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