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