1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
23 * Copyright (c) 2012 Gary Mills
24 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2023 Oxide Computer Company
26 */
27
28 /*
29 * ISA bus nexus driver
30 */
31
32 #include <sys/types.h>
33 #include <sys/cmn_err.h>
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/autoconf.h>
37 #include <sys/errno.h>
38 #include <sys/debug.h>
39 #include <sys/kmem.h>
40 #include <sys/psm.h>
41 #include <sys/ddidmareq.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/ddi_subrdefs.h>
44 #include <sys/dma_engine.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/sunndi.h>
48 #include <sys/acpi/acpi_enum.h>
49 #include <sys/mach_intr.h>
50 #include <sys/pci.h>
51 #include <sys/note.h>
52 #include <sys/boot_console.h>
53 #include <sys/apic.h>
54 #if defined(__xpv)
55 #include <sys/hypervisor.h>
56 #include <sys/evtchn_impl.h>
57
58 extern int console_hypervisor_dev_type(int *);
59 #endif
60
61
62 extern int pseudo_isa;
63 extern int isa_resource_setup(void);
64 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
65 psm_intr_op_t, int *);
66 extern void pci_register_isa_resources(int, uint32_t, uint32_t);
67 static void isa_enumerate(int);
68 static void enumerate_BIOS_serial(dev_info_t *);
69 static void adjust_prtsz(dev_info_t *isa_dip);
70 static void isa_create_ranges_prop(dev_info_t *);
71
72 #define USED_RESOURCES "used-resources"
73
74 /*
75 * The following typedef is used to represent an entry in the "ranges"
76 * property of a pci-isa bridge device node.
77 */
78 typedef struct {
79 uint32_t child_high;
80 uint32_t child_low;
81 uint32_t parent_high;
82 uint32_t parent_mid;
83 uint32_t parent_low;
84 uint32_t size;
85 } pib_ranges_t;
86
87 typedef struct {
88 uint32_t base;
89 uint32_t len;
90 } used_ranges_t;
91
92 #define USED_CELL_SIZE 2 /* 1 byte addr, 1 byte size */
93 #define ISA_ADDR_IO 1 /* IO address space */
94 #define ISA_ADDR_MEM 0 /* memory adress space */
95
96 /*
97 * #define ISA_DEBUG 1
98 */
99
100 #define num_BIOS_serial 4 /* number of BIOS serial ports to look at */
101 #define min_BIOS_serial 2 /* minimum number of BIOS serial ports */
102 #define COM_ISR 2 /* 16550 intr status register */
103 #define COM_SCR 7 /* 16550 scratch register */
104
105 /*
106 * For serial ports not enumerated by ACPI, and parallel ports with
107 * illegal size. Typically, a system can have as many as 4 serial
108 * ports and 3 parallel ports.
109 */
110 #define MAX_EXTRA_RESOURCE 7
111 static struct regspec isa_extra_resource[MAX_EXTRA_RESOURCE];
112 static int isa_extra_count = 0;
113
114 /* Register definitions for COM1 to COM4. */
115 static struct regspec asy_regs[] = {
116 {1, 0x3f8, 0x8},
117 {1, 0x2f8, 0x8},
118 {1, 0x3e8, 0x8},
119 {1, 0x2e8, 0x8}
120 };
121
122 /* Serial port interrupt vectors for COM1 to COM4. */
123 static int asy_intrs[] = {0x4, 0x3, 0x4, 0x3};
124 /* Bitfield indicating which interrupts are overridden by eeprom config */
125 static uchar_t asy_intr_override = 0;
126
127 /*
128 * Local data
129 */
130
131 static ddi_dma_attr_t ISA_dma_attr = {
132 DMA_ATTR_V0,
133 (unsigned long long)0,
134 (unsigned long long)0x00ffffff,
135 0x0000ffff,
136 1,
137 1,
138 1,
139 (unsigned long long)0xffffffff,
140 (unsigned long long)0x0000ffff,
141 1,
142 1,
143 0
144 };
145
146
147 /*
148 * Config information
149 */
150
151 static int
152 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
153 off_t offset, off_t len, caddr_t *vaddrp);
154
155 static int
156 isa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
157 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *);
158
159 static int
160 isa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops,
161 off_t *, size_t *, caddr_t *, uint_t);
162
163 static int
164 isa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
165
166 static int
167 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
168 ddi_intr_handle_impl_t *hdlp, void *result);
169 static int isa_alloc_intr_fixed(dev_info_t *, ddi_intr_handle_impl_t *, void *);
170 static int isa_free_intr_fixed(dev_info_t *, ddi_intr_handle_impl_t *);
171
172 struct bus_ops isa_bus_ops = {
173 BUSO_REV,
174 isa_bus_map,
175 NULL,
176 NULL,
177 NULL,
178 i_ddi_map_fault,
179 NULL,
180 isa_dma_allochdl,
181 ddi_dma_freehdl,
182 ddi_dma_bindhdl,
183 ddi_dma_unbindhdl,
184 ddi_dma_flush,
185 ddi_dma_win,
186 isa_dma_mctl,
187 isa_ctlops,
188 ddi_bus_prop_op,
189 NULL, /* (*bus_get_eventcookie)(); */
190 NULL, /* (*bus_add_eventcall)(); */
191 NULL, /* (*bus_remove_eventcall)(); */
192 NULL, /* (*bus_post_event)(); */
193 NULL, /* (*bus_intr_ctl)(); */
194 NULL, /* (*bus_config)(); */
195 NULL, /* (*bus_unconfig)(); */
196 NULL, /* (*bus_fm_init)(); */
197 NULL, /* (*bus_fm_fini)(); */
198 NULL, /* (*bus_fm_access_enter)(); */
199 NULL, /* (*bus_fm_access_exit)(); */
200 NULL, /* (*bus_power)(); */
201 isa_intr_ops /* (*bus_intr_op)(); */
202 };
203
204
205 static int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
206
207 /*
208 * Internal isa ctlops support routines
209 */
210 static int isa_initchild(dev_info_t *child);
211
212 struct dev_ops isa_ops = {
213 DEVO_REV, /* devo_rev, */
214 0, /* refcnt */
215 ddi_no_info, /* info */
216 nulldev, /* identify */
217 nulldev, /* probe */
218 isa_attach, /* attach */
219 nulldev, /* detach */
220 nodev, /* reset */
221 (struct cb_ops *)0, /* driver operations */
222 &isa_bus_ops, /* bus operations */
223 NULL, /* power */
224 ddi_quiesce_not_needed, /* quiesce */
225 };
226
227 /*
228 * Module linkage information for the kernel.
229 */
230
231 static struct modldrv modldrv = {
232 &mod_driverops, /* Type of module. This is ISA bus driver */
233 "isa nexus driver for 'ISA'",
234 &isa_ops, /* driver ops */
235 };
236
237 static struct modlinkage modlinkage = {
238 MODREV_1,
239 &modldrv,
240 NULL
241 };
242
243 int
_init(void)244 _init(void)
245 {
246 int err;
247 char tty_irq_param[9] = "ttyX-irq";
248 char *tty_irq;
249 int i;
250
251 if ((err = mod_install(&modlinkage)) != 0)
252 return (err);
253
254 /* Check if any tty irqs are overridden by eeprom config */
255 for (i = 0; i < num_BIOS_serial; i++) {
256 tty_irq_param[3] = 'a' + i;
257 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
258 DDI_PROP_DONTPASS, tty_irq_param, &tty_irq)
259 == DDI_PROP_SUCCESS) {
260 long data;
261
262 if (ddi_strtol(tty_irq, NULL, 0, &data) == 0) {
263 asy_intrs[i] = (int)data;
264 asy_intr_override |= 1<<i;
265 }
266
267 ddi_prop_free(tty_irq);
268 }
269 }
270
271 impl_bus_add_probe(isa_enumerate);
272 return (0);
273 }
274
275 int
_fini(void)276 _fini(void)
277 {
278 int err;
279
280 impl_bus_delete_probe(isa_enumerate);
281
282 if ((err = mod_remove(&modlinkage)) != 0)
283 return (err);
284
285 return (0);
286 }
287
288 int
_info(struct modinfo * modinfop)289 _info(struct modinfo *modinfop)
290 {
291 return (mod_info(&modlinkage, modinfop));
292 }
293
294 static int
isa_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)295 isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
296 {
297 int rval;
298
299 #if defined(__xpv)
300 /*
301 * don't allow isa to attach in domU. this can happen if someone sets
302 * the console wrong, etc. ISA devices assume the H/W is there and
303 * will cause the domU to panic.
304 */
305 if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
306 return (DDI_FAILURE);
307 }
308 #endif
309
310 switch (cmd) {
311 case DDI_ATTACH:
312 break;
313 case DDI_RESUME:
314 return (DDI_SUCCESS);
315 default:
316 return (DDI_FAILURE);
317 }
318
319 if ((rval = i_dmae_init(devi)) == DDI_SUCCESS)
320 ddi_report_dev(devi);
321
322 return (rval);
323 }
324
325 #define SET_RNGS(rng_p, used_p, ctyp, ptyp) do { \
326 (rng_p)->child_high = (ctyp); \
327 (rng_p)->child_low = (rng_p)->parent_low = (used_p)->base; \
328 (rng_p)->parent_high = (ptyp); \
329 (rng_p)->parent_mid = 0; \
330 (rng_p)->size = (used_p)->len; \
331 _NOTE(CONSTCOND) } while (0)
332 static uint_t
isa_used_to_ranges(int ctype,int * array,uint_t size,pib_ranges_t * ranges)333 isa_used_to_ranges(int ctype, int *array, uint_t size, pib_ranges_t *ranges)
334 {
335 used_ranges_t *used_p;
336 pib_ranges_t *rng_p = ranges;
337 uint_t i, ptype;
338
339 ptype = (ctype == ISA_ADDR_IO) ? PCI_ADDR_IO : PCI_ADDR_MEM32;
340 ptype |= PCI_REG_REL_M;
341 size /= USED_CELL_SIZE;
342 used_p = (used_ranges_t *)array;
343 SET_RNGS(rng_p, used_p, ctype, ptype);
344 for (i = 1, used_p++; i < size; i++, used_p++) {
345 /* merge ranges record if applicable */
346 if (rng_p->child_low + rng_p->size == used_p->base)
347 rng_p->size += used_p->len;
348 else {
349 rng_p++;
350 SET_RNGS(rng_p, used_p, ctype, ptype);
351 }
352 }
353 return (rng_p - ranges + 1);
354 }
355
356 void
isa_remove_res_from_pci(int type,int * array,uint_t size)357 isa_remove_res_from_pci(int type, int *array, uint_t size)
358 {
359 int i;
360 used_ranges_t *used_p;
361
362 size /= USED_CELL_SIZE;
363 used_p = (used_ranges_t *)array;
364 for (i = 0; i < size; i++, used_p++)
365 pci_register_isa_resources(type, used_p->base, used_p->len);
366 }
367
368 static void
isa_create_ranges_prop(dev_info_t * dip)369 isa_create_ranges_prop(dev_info_t *dip)
370 {
371 dev_info_t *used;
372 int *ioarray, *memarray, status;
373 uint_t nio = 0, nmem = 0, nrng = 0, n;
374 pib_ranges_t *ranges;
375
376 used = ddi_find_devinfo(USED_RESOURCES, -1, 0);
377 if (used == NULL) {
378 cmn_err(CE_WARN, "Failed to find used-resources <%s>\n",
379 ddi_get_name(dip));
380 return;
381 }
382 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
383 DDI_PROP_DONTPASS, "io-space", &ioarray, &nio);
384 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
385 cmn_err(CE_WARN, "io-space property failure for %s (%x)\n",
386 ddi_get_name(used), status);
387 return;
388 }
389 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
390 DDI_PROP_DONTPASS, "device-memory", &memarray, &nmem);
391 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
392 cmn_err(CE_WARN, "device-memory property failure for %s (%x)\n",
393 ddi_get_name(used), status);
394 return;
395 }
396 n = (nio + nmem) / USED_CELL_SIZE;
397 ranges = (pib_ranges_t *)kmem_zalloc(sizeof (pib_ranges_t) * n,
398 KM_SLEEP);
399
400 if (nio != 0) {
401 nrng = isa_used_to_ranges(ISA_ADDR_IO, ioarray, nio, ranges);
402 isa_remove_res_from_pci(ISA_ADDR_IO, ioarray, nio);
403 ddi_prop_free(ioarray);
404 }
405 if (nmem != 0) {
406 nrng += isa_used_to_ranges(ISA_ADDR_MEM, memarray, nmem,
407 ranges + nrng);
408 isa_remove_res_from_pci(ISA_ADDR_MEM, memarray, nmem);
409 ddi_prop_free(memarray);
410 }
411
412 if (!pseudo_isa)
413 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
414 (int *)ranges, nrng * sizeof (pib_ranges_t) / sizeof (int));
415 kmem_free(ranges, sizeof (pib_ranges_t) * n);
416 }
417
418 /*ARGSUSED*/
419 static int
isa_apply_range(dev_info_t * dip,struct regspec * isa_reg_p,pci_regspec_t * pci_reg_p)420 isa_apply_range(dev_info_t *dip, struct regspec *isa_reg_p,
421 pci_regspec_t *pci_reg_p)
422 {
423 pib_ranges_t *ranges, *rng_p;
424 int len, i, offset, nrange;
425
426 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
427 "ranges", (caddr_t)&ranges, &len) != DDI_SUCCESS) {
428 cmn_err(CE_WARN, "Can't get %s ranges property",
429 ddi_get_name(dip));
430 return (DDI_ME_REGSPEC_RANGE);
431 }
432 nrange = len / sizeof (pib_ranges_t);
433 rng_p = ranges;
434 for (i = 0; i < nrange; i++, rng_p++) {
435 /* Check for correct space */
436 if (isa_reg_p->regspec_bustype != rng_p->child_high)
437 continue;
438
439 /* Detect whether request entirely fits within a range */
440 if (isa_reg_p->regspec_addr < rng_p->child_low)
441 continue;
442 if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size - 1) >
443 (rng_p->child_low + rng_p->size - 1))
444 continue;
445
446 offset = isa_reg_p->regspec_addr - rng_p->child_low;
447
448 pci_reg_p->pci_phys_hi = rng_p->parent_high;
449 pci_reg_p->pci_phys_mid = 0;
450 pci_reg_p->pci_phys_low = rng_p->parent_low + offset;
451 pci_reg_p->pci_size_hi = 0;
452 pci_reg_p->pci_size_low = isa_reg_p->regspec_size;
453
454 break;
455 }
456 kmem_free(ranges, len);
457
458 if (i < nrange)
459 return (DDI_SUCCESS);
460
461 /*
462 * Check extra resource range specially for serial and parallel
463 * devices, which are treated differently from all other ISA
464 * devices. On some machines, serial ports are not enumerated
465 * by ACPI but by BIOS, with io base addresses noted in legacy
466 * BIOS data area. Parallel port on some machines comes with
467 * illegal size.
468 */
469 if (isa_reg_p->regspec_bustype != ISA_ADDR_IO) {
470 cmn_err(CE_WARN, "Bus type not ISA I/O\n");
471 return (DDI_ME_REGSPEC_RANGE);
472 }
473
474 for (i = 0; i < isa_extra_count; i++) {
475 struct regspec *reg_p = &isa_extra_resource[i];
476
477 if (isa_reg_p->regspec_addr < reg_p->regspec_addr)
478 continue;
479 if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size) >
480 (reg_p->regspec_addr + reg_p->regspec_size))
481 continue;
482
483 pci_reg_p->pci_phys_hi = PCI_ADDR_IO | PCI_REG_REL_M;
484 pci_reg_p->pci_phys_mid = 0;
485 pci_reg_p->pci_phys_low = isa_reg_p->regspec_addr;
486 pci_reg_p->pci_size_hi = 0;
487 pci_reg_p->pci_size_low = isa_reg_p->regspec_size;
488 break;
489 }
490 if (i < isa_extra_count)
491 return (DDI_SUCCESS);
492
493 cmn_err(CE_WARN, "isa_apply_range: Out of range base <0x%x>, size <%d>",
494 isa_reg_p->regspec_addr, isa_reg_p->regspec_size);
495 return (DDI_ME_REGSPEC_RANGE);
496 }
497
498 static int
isa_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)499 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
500 off_t offset, off_t len, caddr_t *vaddrp)
501 {
502 struct regspec tmp_reg, *rp;
503 pci_regspec_t vreg;
504 ddi_map_req_t mr = *mp; /* Get private copy of request */
505 int error;
506
507 if (pseudo_isa)
508 return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
509
510 mp = &mr;
511
512 /*
513 * First, if given an rnumber, convert it to a regspec...
514 */
515 if (mp->map_type == DDI_MT_RNUMBER) {
516
517 int rnumber = mp->map_obj.rnumber;
518
519 rp = i_ddi_rnumber_to_regspec(rdip, rnumber);
520 if (rp == (struct regspec *)0)
521 return (DDI_ME_RNUMBER_RANGE);
522
523 /*
524 * Convert the given ddi_map_req_t from rnumber to regspec...
525 */
526 mp->map_type = DDI_MT_REGSPEC;
527 mp->map_obj.rp = rp;
528 }
529
530 /*
531 * Adjust offset and length correspnding to called values...
532 * XXX: A non-zero length means override the one in the regspec.
533 * XXX: (Regardless of what's in the parent's range)
534 */
535
536 tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */
537 rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */
538
539 rp->regspec_addr += (uint_t)offset;
540 if (len != 0)
541 rp->regspec_size = (uint_t)len;
542
543 if ((error = isa_apply_range(dip, rp, &vreg)) != 0)
544 return (error);
545 mp->map_obj.rp = (struct regspec *)&vreg;
546
547 /*
548 * Call my parents bus_map function with modified values...
549 */
550
551 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
552 }
553
554 static int
isa_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * dma_attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)555 isa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr,
556 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
557 {
558 ddi_dma_attr_merge(dma_attr, &ISA_dma_attr);
559 return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep));
560 }
561
562 static int
isa_dma_mctl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,enum ddi_dma_ctlops request,off_t * offp,size_t * lenp,caddr_t * objp,uint_t flags)563 isa_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
564 ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
565 off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
566 {
567 int rval;
568 int arg = (int)(uintptr_t)objp;
569
570 switch (request) {
571
572 case DDI_DMA_E_PROG:
573 return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp,
574 (ddi_dma_cookie_t *)lenp, arg));
575
576 case DDI_DMA_E_ACQUIRE:
577 return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp,
578 (caddr_t)lenp));
579
580 case DDI_DMA_E_FREE:
581 return (i_dmae_free(rdip, arg));
582
583 case DDI_DMA_E_STOP:
584 i_dmae_stop(rdip, arg);
585 return (DDI_SUCCESS);
586
587 case DDI_DMA_E_ENABLE:
588 i_dmae_enable(rdip, arg);
589 return (DDI_SUCCESS);
590
591 case DDI_DMA_E_DISABLE:
592 i_dmae_disable(rdip, arg);
593 return (DDI_SUCCESS);
594
595 case DDI_DMA_E_GETCNT:
596 i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp);
597 return (DDI_SUCCESS);
598
599 case DDI_DMA_E_SWSETUP:
600 return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp,
601 (ddi_dma_cookie_t *)lenp, arg));
602
603 case DDI_DMA_E_SWSTART:
604 i_dmae_swstart(rdip, arg);
605 return (DDI_SUCCESS);
606
607 case DDI_DMA_E_GETATTR:
608 bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t));
609 return (DDI_SUCCESS);
610
611 case DDI_DMA_E_1STPTY:
612 {
613 struct ddi_dmae_req req1stpty =
614 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
615 if (arg == 0) {
616 req1stpty.der_command = DMAE_CMD_TRAN;
617 req1stpty.der_trans = DMAE_TRANS_DMND;
618 } else {
619 req1stpty.der_trans = DMAE_TRANS_CSCD;
620 }
621 return (i_dmae_prog(rdip, &req1stpty, NULL, arg));
622 }
623
624 default:
625 /*
626 * We pass to rootnex, but it turns out that rootnex will just
627 * return failure, as we don't use ddi_dma_mctl() except
628 * for DMA engine (ISA) and DVMA (SPARC). Arguably we could
629 * just return an error direclty here, instead.
630 */
631 rval = ddi_dma_mctl(dip, rdip, handle, request, offp,
632 lenp, objp, flags);
633 }
634 return (rval);
635 }
636
637 /*
638 * Check if driver should be treated as an old pre 2.6 driver
639 */
640 static int
old_driver(dev_info_t * dip)641 old_driver(dev_info_t *dip)
642 {
643 extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */
644
645 if (ndi_dev_is_persistent_node(dip)) {
646 if (ignore_hardware_nodes)
647 return (1);
648 if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
649 "ignore-hardware-nodes", -1) != -1)
650 return (1);
651 }
652 return (0);
653 }
654
655 typedef struct {
656 uint32_t phys_hi;
657 uint32_t phys_lo;
658 uint32_t size;
659 } isa_regs_t;
660
661 /*
662 * Return non-zero if device in tree is a PnP isa device
663 */
664 static int
is_pnpisa(dev_info_t * dip)665 is_pnpisa(dev_info_t *dip)
666 {
667 isa_regs_t *isa_regs;
668 int proplen, pnpisa;
669
670 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
671 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) {
672 return (0);
673 }
674 pnpisa = isa_regs[0].phys_hi & 0x80000000;
675 /*
676 * free the memory allocated by ddi_getlongprop().
677 */
678 kmem_free(isa_regs, proplen);
679 if (pnpisa)
680 return (1);
681 else
682 return (0);
683 }
684
685 /*ARGSUSED*/
686 static int
isa_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)687 isa_ctlops(dev_info_t *dip, dev_info_t *rdip,
688 ddi_ctl_enum_t ctlop, void *arg, void *result)
689 {
690 int rn;
691 struct ddi_parent_private_data *pdp;
692
693 switch (ctlop) {
694 case DDI_CTLOPS_REPORTDEV:
695 if (rdip == (dev_info_t *)0)
696 return (DDI_FAILURE);
697 cmn_err(CE_CONT, "?ISA-device: %s%d\n",
698 ddi_driver_name(rdip), ddi_get_instance(rdip));
699 return (DDI_SUCCESS);
700
701 case DDI_CTLOPS_INITCHILD:
702 /*
703 * older drivers aren't expecting the "standard" device
704 * node format used by the hardware nodes. these drivers
705 * only expect their own properties set in their driver.conf
706 * files. so they tell us not to call them with hardware
707 * nodes by setting the property "ignore-hardware-nodes".
708 */
709 if (old_driver((dev_info_t *)arg)) {
710 return (DDI_NOT_WELL_FORMED);
711 }
712
713 return (isa_initchild((dev_info_t *)arg));
714
715 case DDI_CTLOPS_UNINITCHILD:
716 impl_ddi_sunbus_removechild((dev_info_t *)arg);
717 return (DDI_SUCCESS);
718
719 case DDI_CTLOPS_SIDDEV:
720 if (ndi_dev_is_persistent_node(rdip))
721 return (DDI_SUCCESS);
722 /*
723 * All ISA devices need to do confirming probes
724 * unless they are PnP ISA.
725 */
726 if (is_pnpisa(rdip))
727 return (DDI_SUCCESS);
728 else
729 return (DDI_FAILURE);
730
731 case DDI_CTLOPS_REGSIZE:
732 case DDI_CTLOPS_NREGS:
733 if (rdip == (dev_info_t *)0)
734 return (DDI_FAILURE);
735
736 if ((pdp = ddi_get_parent_data(rdip)) == NULL)
737 return (DDI_FAILURE);
738
739 if (ctlop == DDI_CTLOPS_NREGS) {
740 *(int *)result = pdp->par_nreg;
741 } else {
742 rn = *(int *)arg;
743 if (rn >= pdp->par_nreg)
744 return (DDI_FAILURE);
745 *(off_t *)result = (off_t)pdp->par_reg[rn].regspec_size;
746 }
747 return (DDI_SUCCESS);
748
749 case DDI_CTLOPS_ATTACH:
750 case DDI_CTLOPS_DETACH:
751 case DDI_CTLOPS_PEEK:
752 case DDI_CTLOPS_POKE:
753 return (DDI_FAILURE);
754
755 default:
756 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
757 }
758 }
759
760 static struct intrspec *
isa_get_ispec(dev_info_t * rdip,int inum)761 isa_get_ispec(dev_info_t *rdip, int inum)
762 {
763 struct ddi_parent_private_data *pdp = ddi_get_parent_data(rdip);
764
765 /* Validate the interrupt number */
766 if (inum >= pdp->par_nintr)
767 return (NULL);
768
769 /* Get the interrupt structure pointer and return that */
770 return ((struct intrspec *)&pdp->par_intr[inum]);
771 }
772
773 static int
isa_intr_ops(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)774 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
775 ddi_intr_handle_impl_t *hdlp, void *result)
776 {
777 struct intrspec *ispec;
778 #if defined(__xpv)
779 int cons, ttyn;
780
781 cons = console_hypervisor_dev_type(&ttyn);
782 #endif
783 if (pseudo_isa)
784 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
785
786
787 /* Process the interrupt operation */
788 switch (intr_op) {
789 case DDI_INTROP_GETCAP:
790 /* First check with pcplusmp */
791 if (psm_intr_ops == NULL)
792 return (DDI_FAILURE);
793
794 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) {
795 *(int *)result = 0;
796 return (DDI_FAILURE);
797 }
798 break;
799 case DDI_INTROP_SETCAP:
800 if (psm_intr_ops == NULL)
801 return (DDI_FAILURE);
802
803 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result))
804 return (DDI_FAILURE);
805 break;
806 case DDI_INTROP_ALLOC:
807 ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
808 return (isa_alloc_intr_fixed(rdip, hdlp, result));
809 case DDI_INTROP_FREE:
810 ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
811 return (isa_free_intr_fixed(rdip, hdlp));
812 case DDI_INTROP_GETPRI:
813 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
814 return (DDI_FAILURE);
815 *(int *)result = ispec->intrspec_pri;
816 break;
817 case DDI_INTROP_SETPRI:
818 /* Validate the interrupt priority passed to us */
819 if (*(int *)result > LOCK_LEVEL)
820 return (DDI_FAILURE);
821
822 /* Ensure that PSM is all initialized and ispec is ok */
823 if ((psm_intr_ops == NULL) ||
824 ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL))
825 return (DDI_FAILURE);
826
827 /* update the ispec with the new priority */
828 ispec->intrspec_pri = *(int *)result;
829 break;
830 case DDI_INTROP_ADDISR:
831 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
832 return (DDI_FAILURE);
833 ispec->intrspec_func = hdlp->ih_cb_func;
834 break;
835 case DDI_INTROP_REMISR:
836 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
837 return (DDI_FAILURE);
838 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
839 return (DDI_FAILURE);
840 ispec->intrspec_func = (uint_t (*)()) 0;
841 break;
842 case DDI_INTROP_ENABLE:
843 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
844 return (DDI_FAILURE);
845
846 /* Call psmi to translate irq with the dip */
847 if (psm_intr_ops == NULL)
848 return (DDI_FAILURE);
849
850 #if defined(__xpv)
851 /*
852 * if the hypervisor is using an isa serial port for the
853 * console, make sure we don't try to use that interrupt as
854 * it will cause us to panic when xen_bind_pirq() fails.
855 */
856 if (cons == CONS_TTY && ispec->intrspec_vec == asy_intrs[ttyn])
857 return (DDI_FAILURE);
858 #endif
859 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
860 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR,
861 (int *)&hdlp->ih_vector) == PSM_FAILURE)
862 return (DDI_FAILURE);
863
864 /* Add the interrupt handler */
865 if (!add_avintr((void *)hdlp, ispec->intrspec_pri,
866 hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector,
867 hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, NULL, rdip))
868 return (DDI_FAILURE);
869 break;
870 case DDI_INTROP_DISABLE:
871 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
872 return (DDI_FAILURE);
873
874 /* Call psm_ops() to translate irq with the dip */
875 if (psm_intr_ops == NULL)
876 return (DDI_FAILURE);
877
878 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
879 (void) (*psm_intr_ops)(rdip, hdlp,
880 PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector);
881
882 /* Remove the interrupt handler */
883 rem_avintr((void *)hdlp, ispec->intrspec_pri,
884 hdlp->ih_cb_func, hdlp->ih_vector);
885 break;
886 case DDI_INTROP_SETMASK:
887 if (psm_intr_ops == NULL)
888 return (DDI_FAILURE);
889
890 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL))
891 return (DDI_FAILURE);
892 break;
893 case DDI_INTROP_CLRMASK:
894 if (psm_intr_ops == NULL)
895 return (DDI_FAILURE);
896
897 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL))
898 return (DDI_FAILURE);
899 break;
900 case DDI_INTROP_GETPENDING:
901 if (psm_intr_ops == NULL)
902 return (DDI_FAILURE);
903
904 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING,
905 result)) {
906 *(int *)result = 0;
907 return (DDI_FAILURE);
908 }
909 break;
910 case DDI_INTROP_NAVAIL:
911 case DDI_INTROP_NINTRS:
912 *(int *)result = i_ddi_get_intx_nintrs(rdip);
913 if (*(int *)result == 0) {
914 return (DDI_FAILURE);
915 }
916 break;
917 case DDI_INTROP_SUPPORTED_TYPES:
918 *(int *)result = DDI_INTR_TYPE_FIXED; /* Always ... */
919 break;
920 default:
921 return (DDI_FAILURE);
922 }
923
924 return (DDI_SUCCESS);
925 }
926
927 /*
928 * Allocate interrupt vector for FIXED (legacy) type.
929 */
930 static int
isa_alloc_intr_fixed(dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)931 isa_alloc_intr_fixed(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp,
932 void *result)
933 {
934 struct intrspec *ispec;
935 ddi_intr_handle_impl_t info_hdl;
936 int ret;
937 int free_phdl = 0;
938 apic_get_type_t type_info;
939
940 if (psm_intr_ops == NULL)
941 return (DDI_FAILURE);
942
943 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
944 return (DDI_FAILURE);
945
946 /*
947 * If the PSM module is "APIX" then pass the request for it
948 * to allocate the vector now.
949 */
950 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
951 info_hdl.ih_private = &type_info;
952 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
953 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
954 if (hdlp->ih_private == NULL) { /* allocate phdl structure */
955 free_phdl = 1;
956 i_ddi_alloc_intr_phdl(hdlp);
957 }
958 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
959 ret = (*psm_intr_ops)(rdip, hdlp,
960 PSM_INTR_OP_ALLOC_VECTORS, result);
961 if (free_phdl) { /* free up the phdl structure */
962 free_phdl = 0;
963 i_ddi_free_intr_phdl(hdlp);
964 hdlp->ih_private = NULL;
965 }
966 } else {
967 /*
968 * No APIX module; fall back to the old scheme where the
969 * interrupt vector is allocated during ddi_enable_intr() call.
970 */
971 hdlp->ih_pri = ispec->intrspec_pri;
972 *(int *)result = hdlp->ih_scratch1;
973 ret = DDI_SUCCESS;
974 }
975
976 return (ret);
977 }
978
979 /*
980 * Free up interrupt vector for FIXED (legacy) type.
981 */
982 static int
isa_free_intr_fixed(dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)983 isa_free_intr_fixed(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
984 {
985 struct intrspec *ispec;
986 ddi_intr_handle_impl_t info_hdl;
987 int ret;
988 apic_get_type_t type_info;
989
990 if (psm_intr_ops == NULL)
991 return (DDI_FAILURE);
992
993 /*
994 * If the PSM module is "APIX" then pass the request for it
995 * to free up the vector now.
996 */
997 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
998 info_hdl.ih_private = &type_info;
999 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
1000 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
1001 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
1002 return (DDI_FAILURE);
1003 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
1004 ret = (*psm_intr_ops)(rdip, hdlp,
1005 PSM_INTR_OP_FREE_VECTORS, NULL);
1006 } else {
1007 /*
1008 * No APIX module; fall back to the old scheme where
1009 * the interrupt vector was already freed during
1010 * ddi_disable_intr() call.
1011 */
1012 ret = DDI_SUCCESS;
1013 }
1014
1015 return (ret);
1016 }
1017
1018 static void
isa_vendor(uint32_t id,char * vendor)1019 isa_vendor(uint32_t id, char *vendor)
1020 {
1021 vendor[0] = '@' + ((id >> 26) & 0x1f);
1022 vendor[1] = '@' + ((id >> 21) & 0x1f);
1023 vendor[2] = '@' + ((id >> 16) & 0x1f);
1024 vendor[3] = 0;
1025 }
1026
1027 /*
1028 * Name a child
1029 */
1030 static int
isa_name_child(dev_info_t * child,char * name,int namelen)1031 isa_name_child(dev_info_t *child, char *name, int namelen)
1032 {
1033 char vendor[8];
1034 int device;
1035 uint32_t serial;
1036 int func;
1037 int bustype;
1038 uint32_t base;
1039 int proplen;
1040 int pnpisa = 0;
1041 isa_regs_t *isa_regs;
1042
1043 void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **);
1044
1045 /*
1046 * older drivers aren't expecting the "standard" device
1047 * node format used by the hardware nodes. these drivers
1048 * only expect their own properties set in their driver.conf
1049 * files. so they tell us not to call them with hardware
1050 * nodes by setting the property "ignore-hardware-nodes".
1051 */
1052 if (old_driver(child))
1053 return (DDI_FAILURE);
1054
1055 /*
1056 * Fill in parent-private data
1057 */
1058 if (ddi_get_parent_data(child) == NULL) {
1059 struct ddi_parent_private_data *pdptr;
1060 make_ddi_ppd(child, &pdptr);
1061 ddi_set_parent_data(child, pdptr);
1062 }
1063
1064 if (ndi_dev_is_persistent_node(child) == 0) {
1065 /*
1066 * For .conf nodes, generate name from parent private data
1067 */
1068 name[0] = '\0';
1069 if (sparc_pd_getnreg(child) > 0) {
1070 (void) snprintf(name, namelen, "%x,%x",
1071 (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype,
1072 (uint_t)sparc_pd_getreg(child, 0)->regspec_addr);
1073 }
1074 return (DDI_SUCCESS);
1075 }
1076
1077 /*
1078 * For hw nodes, look up "reg" property
1079 */
1080 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1081 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) {
1082 return (DDI_FAILURE);
1083 }
1084
1085 /*
1086 * extract the device identifications
1087 */
1088 pnpisa = isa_regs[0].phys_hi & 0x80000000;
1089 if (pnpisa) {
1090 isa_vendor(isa_regs[0].phys_hi, vendor);
1091 device = isa_regs[0].phys_hi & 0xffff;
1092 serial = isa_regs[0].phys_lo;
1093 func = (isa_regs[0].size >> 24) & 0xff;
1094 if (func != 0)
1095 (void) snprintf(name, namelen, "pnp%s,%04x,%x,%x",
1096 vendor, device, serial, func);
1097 else
1098 (void) snprintf(name, namelen, "pnp%s,%04x,%x",
1099 vendor, device, serial);
1100 } else {
1101 bustype = isa_regs[0].phys_hi;
1102 base = isa_regs[0].phys_lo;
1103 (void) sprintf(name, "%x,%x", bustype, base);
1104 }
1105
1106 /*
1107 * free the memory allocated by ddi_getlongprop().
1108 */
1109 kmem_free(isa_regs, proplen);
1110
1111 return (DDI_SUCCESS);
1112 }
1113
1114 static int
isa_initchild(dev_info_t * child)1115 isa_initchild(dev_info_t *child)
1116 {
1117 char name[80];
1118
1119 if (isa_name_child(child, name, 80) != DDI_SUCCESS)
1120 return (DDI_FAILURE);
1121 ddi_set_name_addr(child, name);
1122
1123 if (ndi_dev_is_persistent_node(child) != 0)
1124 return (DDI_SUCCESS);
1125
1126 /*
1127 * This is a .conf node, try merge properties onto a
1128 * hw node with the same name.
1129 */
1130 if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) {
1131 /*
1132 * Return failure to remove node
1133 */
1134 impl_ddi_sunbus_removechild(child);
1135 return (DDI_FAILURE);
1136 }
1137 /*
1138 * Cannot merge node, permit pseudo children
1139 */
1140 return (DDI_SUCCESS);
1141 }
1142
1143 /*
1144 * called when ACPI enumeration is not used
1145 */
1146 static void
add_known_used_resources(void)1147 add_known_used_resources(void)
1148 {
1149 /* needs to be in increasing order */
1150 int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc};
1151 int dma[] = {0x2};
1152 int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10,
1153 0x778, 0x4};
1154 dev_info_t *usedrdip;
1155
1156 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0);
1157
1158 if (usedrdip == NULL) {
1159 (void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES,
1160 (pnode_t)DEVI_SID_NODEID, &usedrdip);
1161 }
1162
1163 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1164 "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int)));
1165 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1166 "io-space", (int *)io, (int)(sizeof (io) / sizeof (int)));
1167 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1168 "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int)));
1169 (void) ndi_devi_bind_driver(usedrdip, 0);
1170
1171 }
1172
1173 /*
1174 * Return non-zero if UART device exists.
1175 */
1176 static int
uart_exists(ushort_t port)1177 uart_exists(ushort_t port)
1178 {
1179 outb(port + COM_SCR, (char)0x5a);
1180 outb(port + COM_ISR, (char)0x00);
1181 return (inb(port + COM_SCR) == (char)0x5a);
1182 }
1183
1184 static void
isa_enumerate(int reprogram)1185 isa_enumerate(int reprogram)
1186 {
1187 int i;
1188 dev_info_t *xdip;
1189 dev_info_t *isa_dip = ddi_find_devinfo("isa", -1, 0);
1190
1191 struct regspec i8042_regs[] = {
1192 {1, 0x60, 0x1},
1193 {1, 0x64, 0x1}
1194 };
1195 int i8042_intrs[] = {0x1, 0xc};
1196 char *acpi_prop;
1197 int acpi_enum = 1; /* ACPI is default to be on */
1198 #if defined(__xpv)
1199 int cons, ttyn;
1200
1201 cons = console_hypervisor_dev_type(&ttyn);
1202 #endif
1203 if (reprogram || !isa_dip)
1204 return;
1205
1206 bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec));
1207
1208 ndi_devi_enter(isa_dip);
1209
1210 /*
1211 * Check whether ACPI enumeration is disabled.
1212 *
1213 * Note this property may also be set if ACPI ISA enumeration has
1214 * failed, to communicate that to the i8042 nexus.
1215 */
1216 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1217 DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) {
1218 /* 0 == match == false */
1219 acpi_enum = strcmp("off", acpi_prop);
1220 ddi_prop_free(acpi_prop);
1221 }
1222
1223 if (acpi_enum != 0) {
1224 if (acpi_isa_device_enum(isa_dip)) {
1225 ndi_devi_exit(isa_dip);
1226 if (isa_resource_setup() != NDI_SUCCESS) {
1227 cmn_err(CE_WARN, "isa nexus: isa "
1228 "resource setup failed");
1229 }
1230
1231 /* serial ports? */
1232 enumerate_BIOS_serial(isa_dip);
1233
1234 /* adjust parallel port size */
1235 adjust_prtsz(isa_dip);
1236
1237 isa_create_ranges_prop(isa_dip);
1238 return;
1239 }
1240 cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS");
1241 }
1242 cmn_err(CE_NOTE, "!ACPI is off");
1243
1244 /* serial ports */
1245 for (i = 0; i < min_BIOS_serial; i++) {
1246 ushort_t addr = asy_regs[i].regspec_addr;
1247 if (!uart_exists(addr))
1248 continue;
1249 #if defined(__xpv)
1250 if (cons == CONS_TTY && ttyn == i)
1251 continue;
1252 #endif
1253 ndi_devi_alloc_sleep(isa_dip, "asy",
1254 (pnode_t)DEVI_SID_NODEID, &xdip);
1255 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1256 "compatible", "pnpPNP,500");
1257 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1258 "model", "Standard PC COM port");
1259 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1260 "reg", (int *)&asy_regs[i], 3);
1261 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip,
1262 "interrupts", asy_intrs[i]);
1263 (void) ndi_devi_bind_driver(xdip, 0);
1264 /* Adjusting isa_extra here causes a kernel dump later. */
1265 }
1266
1267 /* i8042 node */
1268 ndi_devi_alloc_sleep(isa_dip, "i8042",
1269 (pnode_t)DEVI_SID_NODEID, &xdip);
1270 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1271 "reg", (int *)i8042_regs, 6);
1272 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1273 "interrupts", (int *)i8042_intrs, 2);
1274 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1275 "unit-address", "1,60");
1276 (void) ndi_devi_bind_driver(xdip, 0);
1277
1278 add_known_used_resources();
1279
1280 ndi_devi_exit(isa_dip);
1281
1282 isa_create_ranges_prop(isa_dip);
1283 }
1284
1285 /*
1286 * On some machines, serial port 2 isn't listed in the ACPI table.
1287 * This function goes through the base I/O addresses and makes sure all
1288 * the serial ports there are in the dev_info tree. If any are missing,
1289 * this function will add them.
1290 */
1291 static void
enumerate_BIOS_serial(dev_info_t * isa_dip)1292 enumerate_BIOS_serial(dev_info_t *isa_dip)
1293 {
1294 int i;
1295 dev_info_t *xdip;
1296 int found;
1297 int ret;
1298 struct regspec *tmpregs;
1299 int tmpregs_len;
1300 #if defined(__xpv)
1301 int cons, ttyn;
1302
1303 cons = console_hypervisor_dev_type(&ttyn);
1304 #endif
1305
1306 /*
1307 * Scan the base I/O addresses of the first four serial ports.
1308 */
1309 for (i = 0; i < num_BIOS_serial; i++) {
1310 ushort_t addr = asy_regs[i].regspec_addr;
1311
1312 /* Look for it in the dev_info tree */
1313 found = 0;
1314 for (xdip = ddi_get_child(isa_dip); xdip != NULL;
1315 xdip = ddi_get_next_sibling(xdip)) {
1316 if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) {
1317 /* skip non asy */
1318 continue;
1319 }
1320
1321 /* Match by addr */
1322 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip,
1323 DDI_PROP_DONTPASS, "reg", (int **)&tmpregs,
1324 (uint_t *)&tmpregs_len);
1325 if (ret != DDI_PROP_SUCCESS) {
1326 /* error */
1327 continue;
1328 }
1329
1330 if (tmpregs->regspec_addr == addr)
1331 found = 1;
1332
1333 /*
1334 * Free the memory allocated by
1335 * ddi_prop_lookup_int_array().
1336 */
1337 ddi_prop_free(tmpregs);
1338
1339 if (found) {
1340 if (asy_intr_override & 1<<i) {
1341 (void) ndi_prop_update_int(
1342 DDI_DEV_T_NONE, xdip,
1343 "interrupts", asy_intrs[i]);
1344 }
1345
1346 break;
1347 }
1348 }
1349
1350 /* If not found, then add it */
1351 if (!found && uart_exists(addr)) {
1352 ndi_devi_alloc_sleep(isa_dip, "asy",
1353 (pnode_t)DEVI_SID_NODEID, &xdip);
1354 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1355 "compatible", "pnpPNP,500");
1356 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1357 "model", "Standard PC COM port");
1358 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1359 "reg", (int *)&asy_regs[i], 3);
1360 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip,
1361 "interrupts", asy_intrs[i]);
1362 (void) ndi_devi_bind_driver(xdip, 0);
1363
1364 ASSERT(isa_extra_count < MAX_EXTRA_RESOURCE);
1365 bcopy(&asy_regs[i],
1366 isa_extra_resource + isa_extra_count,
1367 sizeof (struct regspec));
1368 isa_extra_count++;
1369 }
1370 }
1371
1372 /*
1373 * An asy node may have been attached via ACPI enumeration, or
1374 * directly from this file. Check each serial port to see if it
1375 * is in use by the hypervisor. If it is in use, then remove
1376 * the node from the device tree.
1377 */
1378 #if defined(__xpv)
1379 i = 0;
1380
1381 for (xdip = ddi_get_child(isa_dip); xdip != NULL; ) {
1382 dev_info_t *curdip;
1383
1384 curdip = xdip;
1385 xdip = ddi_get_next_sibling(xdip);
1386
1387 if (strncmp(ddi_node_name(curdip), "asy", 3) != 0)
1388 continue;
1389
1390 if (cons == CONS_TTY && ttyn == i) {
1391 ret = ndi_devi_free(curdip);
1392 if (ret != DDI_SUCCESS) {
1393 cmn_err(CE_WARN,
1394 "could not remove asy%d node", i);
1395 }
1396
1397 cmn_err(CE_NOTE, "!asy%d unavailable, reserved"
1398 " to hypervisor", i);
1399 }
1400
1401 i++;
1402 }
1403 #endif
1404
1405 }
1406
1407 /*
1408 * Some machine comes with an illegal parallel port size of 3
1409 * bytes in ACPI, even parallel port mode is ECP.
1410 */
1411 #define DEFAULT_PRT_SIZE 8
1412 static void
adjust_prtsz(dev_info_t * isa_dip)1413 adjust_prtsz(dev_info_t *isa_dip)
1414 {
1415 dev_info_t *cdip;
1416 struct regspec *regs_p, *extreg_p;
1417 int regs_len, nreg, i;
1418 char *name;
1419
1420 for (cdip = ddi_get_child(isa_dip); cdip != NULL;
1421 cdip = ddi_get_next_sibling(cdip)) {
1422 name = ddi_node_name(cdip);
1423 if ((strncmp(name, "lp", 2) != 0) || (strnlen(name, 3) != 2))
1424 continue; /* skip non parallel */
1425
1426 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
1427 DDI_PROP_DONTPASS, "reg", (int **)®s_p,
1428 (uint_t *)®s_len) != DDI_PROP_SUCCESS)
1429 continue;
1430
1431 nreg = regs_len / (sizeof (struct regspec) / sizeof (int));
1432 for (i = 0; i < nreg; i++) {
1433 if (regs_p[i].regspec_size == DEFAULT_PRT_SIZE)
1434 continue;
1435
1436 ASSERT(isa_extra_count < MAX_EXTRA_RESOURCE);
1437 extreg_p = &isa_extra_resource[isa_extra_count++];
1438 extreg_p->regspec_bustype = ISA_ADDR_IO;
1439 extreg_p->regspec_addr = regs_p[i].regspec_addr;
1440 extreg_p->regspec_size = DEFAULT_PRT_SIZE;
1441 }
1442
1443 ddi_prop_free(regs_p);
1444 }
1445 }
1446