27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5dcd3dacszhou * Common Development and Distribution License (the "License").
6dcd3dacszhou * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
22b89e420Garrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org>
230d92875Gary Mills * Copyright (c) 2012 Gary Mills
245cd376eJimmy Vetayases * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
257c478bdstevel@tonic-gate */
287c478bdstevel@tonic-gate *	ISA bus nexus driver
297c478bdstevel@tonic-gate */
317c478bdstevel@tonic-gate#include <sys/types.h>
327c478bdstevel@tonic-gate#include <sys/cmn_err.h>
337c478bdstevel@tonic-gate#include <sys/conf.h>
347c478bdstevel@tonic-gate#include <sys/modctl.h>
357c478bdstevel@tonic-gate#include <sys/autoconf.h>
367c478bdstevel@tonic-gate#include <sys/errno.h>
377c478bdstevel@tonic-gate#include <sys/debug.h>
387c478bdstevel@tonic-gate#include <sys/kmem.h>
39dffe9acml#include <sys/psm.h>
407c478bdstevel@tonic-gate#include <sys/ddidmareq.h>
417c478bdstevel@tonic-gate#include <sys/ddi_impldefs.h>
4237d6e24lipeng sang - Sun Microsystems - Beijing China#include <sys/ddi_subrdefs.h>
437c478bdstevel@tonic-gate#include <sys/dma_engine.h>
447c478bdstevel@tonic-gate#include <sys/ddi.h>
457c478bdstevel@tonic-gate#include <sys/sunddi.h>
467c478bdstevel@tonic-gate#include <sys/sunndi.h>
477c478bdstevel@tonic-gate#include <sys/acpi/acpi_enum.h>
487832385Judy Chen#include <sys/mach_intr.h>
497832385Judy Chen#include <sys/pci.h>
507832385Judy Chen#include <sys/note.h>
51349b53dStuart Maybee#include <sys/boot_console.h>
527ff178cJimmy Vetayases#include <sys/apic.h>
53843e198johnlev#if defined(__xpv)
54843e198johnlev#include <sys/hypervisor.h>
55843e198johnlev#include <sys/evtchn_impl.h>
56349b53dStuart Maybee
570d92875Gary Millsextern int console_hypervisor_dev_type(int *);
607ff178cJimmy Vetayases
617832385Judy Chenextern int pseudo_isa;
627c478bdstevel@tonic-gateextern int isa_resource_setup(void);
637832385Judy Chenextern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
647832385Judy Chen    psm_intr_op_t, int *);
651d6b7b3Judy Chenextern void pci_register_isa_resources(int, uint32_t, uint32_t);
6637d6e24lipeng sang - Sun Microsystems - Beijing Chinastatic void isa_enumerate(int);
67dffe9acmlstatic void enumerate_BIOS_serial(dev_info_t *);
681d6b7b3Judy Chenstatic void adjust_prtsz(dev_info_t *isa_dip);
6937d6e24lipeng sang - Sun Microsystems - Beijing Chinastatic void isa_create_ranges_prop(dev_info_t *);
710d92875Gary Mills#define	USED_RESOURCES	"used-resources"
720d92875Gary Mills
737832385Judy Chen/*
747832385Judy Chen * The following typedef is used to represent an entry in the "ranges"
757832385Judy Chen * property of a pci-isa bridge device node.
767832385Judy Chen */
777832385Judy Chentypedef struct {
787832385Judy Chen	uint32_t child_high;
797832385Judy Chen	uint32_t child_low;
807832385Judy Chen	uint32_t parent_high;
817832385Judy Chen	uint32_t parent_mid;
827832385Judy Chen	uint32_t parent_low;
837832385Judy Chen	uint32_t size;
847832385Judy Chen} pib_ranges_t;
857832385Judy Chen
867832385Judy Chentypedef struct {
877832385Judy Chen	uint32_t base;
887832385Judy Chen	uint32_t len;
897832385Judy Chen} used_ranges_t;
907832385Judy Chen
917832385Judy Chen#define	USED_CELL_SIZE	2	/* 1 byte addr, 1 byte size */
927832385Judy Chen#define	ISA_ADDR_IO	1	/* IO address space */
937832385Judy Chen#define	ISA_ADDR_MEM	0	/* memory adress space */
940d92875Gary Mills
967c478bdstevel@tonic-gate * #define ISA_DEBUG 1
977c478bdstevel@tonic-gate */
990d92875Gary Mills#define	num_BIOS_serial	4	/* number of BIOS serial ports to look at */
1000d92875Gary Mills#define	min_BIOS_serial	2	/* minimum number of BIOS serial ports */
1010d92875Gary Mills#define	COM_ISR		2	/* 16550 intr status register */
1020d92875Gary Mills#define	COM_SCR		7	/* 16550 scratch register */
1030d92875Gary Mills
1051d6b7b3Judy Chen * For serial ports not enumerated by ACPI, and parallel ports with
1061d6b7b3Judy Chen * illegal size. Typically, a system can have as many as 4 serial
1071d6b7b3Judy Chen * ports and 3 parallel ports.
1081d6b7b3Judy Chen */
1091d6b7b3Judy Chen#define	MAX_EXTRA_RESOURCE	7
1101d6b7b3Judy Chenstatic struct regspec isa_extra_resource[MAX_EXTRA_RESOURCE];
1111d6b7b3Judy Chenstatic int isa_extra_count = 0;
1121d6b7b3Judy Chen
1130d92875Gary Mills/* Register definitions for COM1 to COM4. */
1140d92875Gary Millsstatic struct regspec asy_regs[] = {
1150d92875Gary Mills	{1, 0x3f8, 0x8},
1160d92875Gary Mills	{1, 0x2f8, 0x8},
1170d92875Gary Mills	{1, 0x3e8, 0x8},
1180d92875Gary Mills	{1, 0x2e8, 0x8}
1190d92875Gary Mills};
1200d92875Gary Mills
1210d92875Gary Mills/* Serial port interrupt vectors for COM1 to COM4. */
1220d92875Gary Millsstatic int asy_intrs[] = {0x4, 0x3, 0x4, 0x3};
123709ee7cPaul B. Henson/* Bitfield indicating which interrupts are overridden by eeprom config */
124709ee7cPaul B. Hensonstatic uchar_t asy_intr_override = 0;
1250d92875Gary Mills
1261d6b7b3Judy Chen/*
1277c478bdstevel@tonic-gate *      Local data
1287c478bdstevel@tonic-gate */
1307c478bdstevel@tonic-gatestatic ddi_dma_attr_t ISA_dma_attr = {
1317c478bdstevel@tonic-gate	DMA_ATTR_V0,
1327c478bdstevel@tonic-gate	(unsigned long long)0,
1337c478bdstevel@tonic-gate	(unsigned long long)0x00ffffff,
1347c478bdstevel@tonic-gate	0x0000ffff,
1357c478bdstevel@tonic-gate	1,
1367c478bdstevel@tonic-gate	1,
1377c478bdstevel@tonic-gate	1,
1387c478bdstevel@tonic-gate	(unsigned long long)0xffffffff,
1397c478bdstevel@tonic-gate	(unsigned long long)0x0000ffff,
1407c478bdstevel@tonic-gate	1,
1417c478bdstevel@tonic-gate	1,
1427c478bdstevel@tonic-gate	0
1477c478bdstevel@tonic-gate * Config information
1487c478bdstevel@tonic-gate */
1507c478bdstevel@tonic-gatestatic int
1517832385Judy Chenisa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
1527832385Judy Chen    off_t offset, off_t len, caddr_t *vaddrp);
1537832385Judy Chen
1547832385Judy Chenstatic int
1557c478bdstevel@tonic-gateisa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
1567c478bdstevel@tonic-gate    int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *);
1587c478bdstevel@tonic-gatestatic int
1597c478bdstevel@tonic-gateisa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops,
1607c478bdstevel@tonic-gate    off_t *, size_t *, caddr_t *, uint_t);
1627c478bdstevel@tonic-gatestatic int
1637c478bdstevel@tonic-gateisa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
1657832385Judy Chenstatic int
1667832385Judy Chenisa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1677832385Judy Chen    ddi_intr_handle_impl_t *hdlp, void *result);
1687ff178cJimmy Vetayasesstatic int isa_alloc_intr_fixed(dev_info_t *, ddi_intr_handle_impl_t *, void *);
1697ff178cJimmy Vetayasesstatic int isa_free_intr_fixed(dev_info_t *, ddi_intr_handle_impl_t *);
1707832385Judy Chen
1717c478bdstevel@tonic-gatestruct bus_ops isa_bus_ops = {
1727c478bdstevel@tonic-gate	BUSO_REV,
1737832385Judy Chen	isa_bus_map,
1747c478bdstevel@tonic-gate	NULL,
1757c478bdstevel@tonic-gate	NULL,
1767c478bdstevel@tonic-gate	NULL,
1777c478bdstevel@tonic-gate	i_ddi_map_fault,
178cd21e7cGarrett D'Amore	NULL,
1797c478bdstevel@tonic-gate	isa_dma_allochdl,
1807c478bdstevel@tonic-gate	ddi_dma_freehdl,
1817c478bdstevel@tonic-gate	ddi_dma_bindhdl,
1827c478bdstevel@tonic-gate	ddi_dma_unbindhdl,
1837c478bdstevel@tonic-gate	ddi_dma_flush,
1847c478bdstevel@tonic-gate	ddi_dma_win,
1857c478bdstevel@tonic-gate	isa_dma_mctl,
1867c478bdstevel@tonic-gate	isa_ctlops,
1877c478bdstevel@tonic-gate	ddi_bus_prop_op,
1887c478bdstevel@tonic-gate	NULL,		/* (*bus_get_eventcookie)();	*/
1897c478bdstevel@tonic-gate	NULL,		/* (*bus_add_eventcall)();	*/
1907c478bdstevel@tonic-gate	NULL,		/* (*bus_remove_eventcall)();	*/
1917c478bdstevel@tonic-gate	NULL,		/* (*bus_post_event)();		*/
1927c478bdstevel@tonic-gate	NULL,		/* (*bus_intr_ctl)(); */
1937c478bdstevel@tonic-gate	NULL,		/* (*bus_config)(); */
1947c478bdstevel@tonic-gate	NULL,		/* (*bus_unconfig)(); */
1957c478bdstevel@tonic-gate	NULL,		/* (*bus_fm_init)(); */
1967c478bdstevel@tonic-gate	NULL,		/* (*bus_fm_fini)(); */
1977c478bdstevel@tonic-gate	NULL,		/* (*bus_fm_access_enter)(); */
1987c478bdstevel@tonic-gate	NULL,		/* (*bus_fm_access_exit)(); */
1997c478bdstevel@tonic-gate	NULL,		/* (*bus_power)(); */
2007832385Judy Chen	isa_intr_ops	/* (*bus_intr_op)(); */
2047c478bdstevel@tonic-gatestatic int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
2077c478bdstevel@tonic-gate * Internal isa ctlops support routines
2087c478bdstevel@tonic-gate */
2097c478bdstevel@tonic-gatestatic int isa_initchild(dev_info_t *child);
2117c478bdstevel@tonic-gatestruct dev_ops isa_ops = {
2127c478bdstevel@tonic-gate	DEVO_REV,		/* devo_rev, */
2137c478bdstevel@tonic-gate	0,			/* refcnt  */
2147c478bdstevel@tonic-gate	ddi_no_info,		/* info */
2157c478bdstevel@tonic-gate	nulldev,		/* identify */
2167c478bdstevel@tonic-gate	nulldev,		/* probe */
2177c478bdstevel@tonic-gate	isa_attach,		/* attach */
2187832385Judy Chen	nulldev,		/* detach */
2197c478bdstevel@tonic-gate	nodev,			/* reset */
2207c478bdstevel@tonic-gate	(struct cb_ops *)0,	/* driver operations */
2211939740Sherry Moore	&isa_bus_ops,		/* bus operations */
2221939740Sherry Moore	NULL,			/* power */
2231939740Sherry Moore	ddi_quiesce_not_needed,		/* quiesce */
2277c478bdstevel@tonic-gate * Module linkage information for the kernel.
2287c478bdstevel@tonic-gate */
2307c478bdstevel@tonic-gatestatic struct modldrv modldrv = {
2317c478bdstevel@tonic-gate	&mod_driverops, /* Type of module.  This is ISA bus driver */
232613b287Richard Bean	"isa nexus driver for 'ISA'",
2337c478bdstevel@tonic-gate	&isa_ops,	/* driver ops */
2367c478bdstevel@tonic-gatestatic struct modlinkage modlinkage = {
2377c478bdstevel@tonic-gate	MODREV_1,
2387c478bdstevel@tonic-gate	&modldrv,
2397c478bdstevel@tonic-gate	NULL
24537d6e24lipeng sang - Sun Microsystems - Beijing China	int	err;
246709ee7cPaul B. Henson	char tty_irq_param[9] = "ttyX-irq";
247709ee7cPaul B. Henson	char *tty_irq;
248709ee7cPaul B. Henson	int i;
24937d6e24lipeng sang - Sun Microsystems - Beijing China
25037d6e24lipeng sang - Sun Microsystems - Beijing China	if ((err = mod_install(&modlinkage)) != 0)
25137d6e24lipeng sang - Sun Microsystems - Beijing China		return (err);
25237d6e24lipeng sang - Sun Microsystems - Beijing China
253709ee7cPaul B. Henson	/* Check if any tty irqs are overridden by eeprom config */
254709ee7cPaul B. Henson	for (i = 0; i < num_BIOS_serial; i++) {
255709ee7cPaul B. Henson		tty_irq_param[3] = 'a' + i;
256709ee7cPaul B. Henson		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
257709ee7cPaul B. Henson		    DDI_PROP_DONTPASS, tty_irq_param, &tty_irq)
258709ee7cPaul B. Henson		    == DDI_PROP_SUCCESS) {
259709ee7cPaul B. Henson			long data;
260709ee7cPaul B. Henson
261709ee7cPaul B. Henson			if (ddi_strtol(tty_irq, NULL, 0, &data) == 0) {
262709ee7cPaul B. Henson				asy_intrs[i] = (int)data;
263709ee7cPaul B. Henson				asy_intr_override |= 1<<i;
264709ee7cPaul B. Henson			}
265709ee7cPaul B. Henson
266709ee7cPaul B. Henson			ddi_prop_free(tty_irq);
267709ee7cPaul B. Henson		}
268709ee7cPaul B. Henson	}
269709ee7cPaul B. Henson
27037d6e24lipeng sang - Sun Microsystems - Beijing China	impl_bus_add_probe(isa_enumerate);
27137d6e24lipeng sang - Sun Microsystems - Beijing China	return (0);
27737d6e24lipeng sang - Sun Microsystems - Beijing China	int	err;
27837d6e24lipeng sang - Sun Microsystems - Beijing China
27937d6e24lipeng sang - Sun Microsystems - Beijing China	impl_bus_delete_probe(isa_enumerate);
28037d6e24lipeng sang - Sun Microsystems - Beijing China
28137d6e24lipeng sang - Sun Microsystems - Beijing China	if ((err = mod_remove(&modlinkage)) != 0)
28237d6e24lipeng sang - Sun Microsystems - Beijing China		return (err);
28337d6e24lipeng sang - Sun Microsystems - Beijing China
28437d6e24lipeng sang - Sun Microsystems - Beijing China	return (0);
2887c478bdstevel@tonic-gate_info(struct modinfo *modinfop)
2907c478bdstevel@tonic-gate	return (mod_info(&modlinkage, modinfop));
2937c478bdstevel@tonic-gatestatic int
2947c478bdstevel@tonic-gateisa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2967c478bdstevel@tonic-gate	int rval;
298843e198johnlev#if defined(__xpv)
299843e198johnlev	/*
300843e198johnlev	 * don't allow isa to attach in domU. this can happen if someone sets
301843e198johnlev	 * the console wrong, etc. ISA devices assume the H/W is there and
302843e198johnlev	 * will cause the domU to panic.
303843e198johnlev	 */
304843e198johnlev	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
305843e198johnlev		return (DDI_FAILURE);
306843e198johnlev	}
3097832385Judy Chen	switch (cmd) {
3107832385Judy Chen	case DDI_ATTACH:
3117832385Judy Chen		break;
3127832385Judy Chen	case DDI_RESUME:
3137832385Judy Chen		return (DDI_SUCCESS);
3147832385Judy Chen	default:
3157c478bdstevel@tonic-gate		return (DDI_FAILURE);
3167832385Judy Chen	}
31837d6e24lipeng sang - Sun Microsystems - Beijing China	if ((rval = i_dmae_init(devi)) == DDI_SUCCESS)
3197c478bdstevel@tonic-gate		ddi_report_dev(devi);
3207832385Judy Chen
3217c478bdstevel@tonic-gate	return (rval);
3247832385Judy Chen#define	SET_RNGS(rng_p, used_p, ctyp, ptyp) do {			\
3257832385Judy Chen		(rng_p)->child_high = (ctyp);				\
3267832385Judy Chen		(rng_p)->child_low = (rng_p)->parent_low = (used_p)->base; \
3277832385Judy Chen		(rng_p)->parent_high = (ptyp);				\
3287832385Judy Chen		(rng_p)->parent_mid = 0;				\
3297832385Judy Chen		(rng_p)->size = (used_p)->len;				\
3307832385Judy Chen		_NOTE(CONSTCOND) } while (0)
3317832385Judy Chenstatic uint_t
3327832385Judy Chenisa_used_to_ranges(int ctype, int *array, uint_t size, pib_ranges_t *ranges)
3337832385Judy Chen{
3347832385Judy Chen	used_ranges_t *used_p;
3357832385Judy Chen	pib_ranges_t *rng_p = ranges;
3367832385Judy Chen	uint_t	i, ptype;
3377832385Judy Chen
3387832385Judy Chen	ptype = (ctype == ISA_ADDR_IO) ? PCI_ADDR_IO : PCI_ADDR_MEM32;
3397832385Judy Chen	ptype |= PCI_REG_REL_M;
3407832385Judy Chen	size /= USED_CELL_SIZE;
3417832385Judy Chen	used_p = (used_ranges_t *)array;
3427832385Judy Chen	SET_RNGS(rng_p, used_p, ctype, ptype);
3437832385Judy Chen	for (i = 1, used_p++; i < size; i++, used_p++) {
3447832385Judy Chen		/* merge ranges record if applicable */
3457832385Judy Chen		if (rng_p->child_low + rng_p->size == used_p->base)
3467832385Judy Chen			rng_p->size += used_p->len;
3477832385Judy Chen		else {
3487832385Judy Chen			rng_p++;
3497832385Judy Chen			SET_RNGS(rng_p, used_p, ctype, ptype);
3507832385Judy Chen		}
3517832385Judy Chen	}
3527832385Judy Chen	return (rng_p - ranges + 1);
3537832385Judy Chen}
3547832385Judy Chen
3557832385Judy Chenvoid
3567832385Judy Chenisa_remove_res_from_pci(int type, int *array, uint_t size)
3577832385Judy Chen{
3587832385Judy Chen	int i;
3597832385Judy Chen	used_ranges_t *used_p;
3607832385Judy Chen
3617832385Judy Chen	size /= USED_CELL_SIZE;
3627832385Judy Chen	used_p = (used_ranges_t *)array;
3637832385Judy Chen	for (i = 0; i < size; i++, used_p++)
3641d6b7b3Judy Chen		pci_register_isa_resources(type, used_p->base, used_p->len);
3657832385Judy Chen}
3667832385Judy Chen
3677832385Judy Chenstatic void
36837d6e24lipeng sang - Sun Microsystems - Beijing Chinaisa_create_ranges_prop(dev_info_t *dip)
3697832385Judy Chen{
3707832385Judy Chen	dev_info_t *used;
3717832385Judy Chen	int *ioarray, *memarray, status;
3727832385Judy Chen	uint_t nio = 0, nmem = 0, nrng = 0, n;
3737832385Judy Chen	pib_ranges_t *ranges;
3747832385Judy Chen
3750d92875Gary Mills	used = ddi_find_devinfo(USED_RESOURCES, -1, 0);
3767832385Judy Chen	if (used == NULL) {
3777832385Judy Chen		cmn_err(CE_WARN, "Failed to find used-resources <%s>\n",
3787832385Judy Chen		    ddi_get_name(dip));
3797832385Judy Chen		return;
3807832385Judy Chen	}
3817832385Judy Chen	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
3827832385Judy Chen	    DDI_PROP_DONTPASS, "io-space", &ioarray, &nio);
3837832385Judy Chen	if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
3847832385Judy Chen		cmn_err(CE_WARN, "io-space property failure for %s (%x)\n",
3857832385Judy Chen		    ddi_get_name(used), status);
3867832385Judy Chen		return;
3877832385Judy Chen	}
3887832385Judy Chen	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
3897832385Judy Chen	    DDI_PROP_DONTPASS, "device-memory", &memarray, &nmem);
3907832385Judy Chen	if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
3917832385Judy Chen		cmn_err(CE_WARN, "device-memory property failure for %s (%x)\n",
3927832385Judy Chen		    ddi_get_name(used), status);
3937832385Judy Chen		return;
3947832385Judy Chen	}
3957832385Judy Chen	n = (nio + nmem) / USED_CELL_SIZE;
3967832385Judy Chen	ranges =  (pib_ranges_t *)kmem_zalloc(sizeof (pib_ranges_t) * n,
3977832385Judy Chen	    KM_SLEEP);
3987832385Judy Chen
3997832385Judy Chen	if (nio != 0) {
4007832385Judy Chen		nrng = isa_used_to_ranges(ISA_ADDR_IO, ioarray, nio, ranges);
4017832385Judy Chen		isa_remove_res_from_pci(ISA_ADDR_IO, ioarray, nio);
4027832385Judy Chen		ddi_prop_free(ioarray);
4037832385Judy Chen	}
4047832385Judy Chen	if (nmem != 0) {
4057832385Judy Chen		nrng += isa_used_to_ranges(ISA_ADDR_MEM, memarray, nmem,
4067832385Judy Chen		    ranges + nrng);
4077832385Judy Chen		isa_remove_res_from_pci(ISA_ADDR_MEM, memarray, nmem);
4087832385Judy Chen		ddi_prop_free(memarray);
4097832385Judy Chen	}
4107832385Judy Chen
4111d6b7b3Judy Chen	if (!pseudo_isa)
4121d6b7b3Judy Chen		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
4131d6b7b3Judy Chen		    (int *)ranges, nrng * sizeof (pib_ranges_t) / sizeof (int));
4147832385Judy Chen	kmem_free(ranges, sizeof (pib_ranges_t) * n);
4157832385Judy Chen}
4167832385Judy Chen
4177832385Judy Chen/*ARGSUSED*/
4187832385Judy Chenstatic int
4197832385Judy Chenisa_apply_range(dev_info_t *dip, struct regspec *isa_reg_p,
4207832385Judy Chen    pci_regspec_t *pci_reg_p)
4217832385Judy Chen{
4227832385Judy Chen	pib_ranges_t *ranges, *rng_p;
4237832385Judy Chen	int len, i, offset, nrange;
4247832385Judy Chen
4257832385Judy Chen	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4267832385Judy Chen	    "ranges", (caddr_t)&ranges, &len) != DDI_SUCCESS) {
4277832385Judy Chen		cmn_err(CE_WARN, "Can't get %s ranges property",
4287832385Judy Chen		    ddi_get_name(dip));
4297832385Judy Chen		return (DDI_ME_REGSPEC_RANGE);
4307832385Judy Chen	}
4317832385Judy Chen	nrange = len / sizeof (pib_ranges_t);
4327832385Judy Chen	rng_p = ranges;
4337832385Judy Chen	for (i = 0; i < nrange; i++, rng_p++) {
4347832385Judy Chen		/* Check for correct space */
4357832385Judy Chen		if (isa_reg_p->regspec_bustype != rng_p->child_high)
4367832385Judy Chen			continue;
4377832385Judy Chen
4387832385Judy Chen		/* Detect whether request entirely fits within a range */
4397832385Judy Chen		if (isa_reg_p->regspec_addr < rng_p->child_low)
4407832385Judy Chen			continue;
4412273e7cJudy Chen		if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size - 1) >
4422273e7cJudy Chen		    (rng_p->child_low + rng_p->size - 1))
4437832385Judy Chen			continue;
4447832385Judy Chen
4457832385Judy Chen		offset = isa_reg_p->regspec_addr - rng_p->child_low;
4467832385Judy Chen
4477832385Judy Chen		pci_reg_p->pci_phys_hi = rng_p->parent_high;
4487832385Judy Chen		pci_reg_p->pci_phys_mid = 0;
4497832385Judy Chen		pci_reg_p->pci_phys_low = rng_p->parent_low + offset;
4507832385Judy Chen		pci_reg_p->pci_size_hi = 0;
4517832385Judy Chen		pci_reg_p->pci_size_low = isa_reg_p->regspec_size;
4527832385Judy Chen
4537832385Judy Chen		break;
4547832385Judy Chen	}
4557832385Judy Chen	kmem_free(ranges, len);
4561d6b7b3Judy Chen
4571d6b7b3Judy Chen	if (i < nrange)
4581d6b7b3Judy Chen		return (DDI_SUCCESS);
4591d6b7b3Judy Chen
4601d6b7b3Judy Chen	/*
4611d6b7b3Judy Chen	 * Check extra resource range specially for serial and parallel
4621d6b7b3Judy Chen	 * devices, which are treated differently from all other ISA
4631d6b7b3Judy Chen	 * devices. On some machines, serial ports are not enumerated
4641d6b7b3Judy Chen	 * by ACPI but by BIOS, with io base addresses noted in legacy
4651d6b7b3Judy Chen	 * BIOS data area. Parallel port on some machines comes with
4661d6b7b3Judy Chen	 * illegal size.
4671d6b7b3Judy Chen	 */
4680d92875Gary Mills	if (isa_reg_p->regspec_bustype != ISA_ADDR_IO) {
4690d92875Gary Mills		cmn_err(CE_WARN, "Bus type not ISA I/O\n");
4700d92875Gary Mills		return (DDI_ME_REGSPEC_RANGE);
4710d92875Gary Mills	}
4721d6b7b3Judy Chen
4731d6b7b3Judy Chen	for (i = 0; i < isa_extra_count; i++) {
4741d6b7b3Judy Chen		struct regspec *reg_p = &isa_extra_resource[i];
4751d6b7b3Judy Chen
4761d6b7b3Judy Chen		if (isa_reg_p->regspec_addr < reg_p->regspec_addr)
4771d6b7b3Judy Chen			continue;
4781d6b7b3Judy Chen		if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size) >
4791d6b7b3Judy Chen		    (reg_p->regspec_addr + reg_p->regspec_size))
4801d6b7b3Judy Chen			continue;
4811d6b7b3Judy Chen
4821d6b7b3Judy Chen		pci_reg_p->pci_phys_hi = PCI_ADDR_IO | PCI_REG_REL_M;
4831d6b7b3Judy Chen		pci_reg_p->pci_phys_mid = 0;
4841d6b7b3Judy Chen		pci_reg_p->pci_phys_low = isa_reg_p->regspec_addr;
4851d6b7b3Judy Chen		pci_reg_p->pci_size_hi = 0;
4861d6b7b3Judy Chen		pci_reg_p->pci_size_low = isa_reg_p->regspec_size;
4871d6b7b3Judy Chen		break;
4887832385Judy Chen	}
4891d6b7b3Judy Chen	if (i < isa_extra_count)
4901d6b7b3Judy Chen		return (DDI_SUCCESS);
4917832385Judy Chen
4921d6b7b3Judy Chen	cmn_err(CE_WARN, "isa_apply_range: Out of range base <0x%x>, size <%d>",
4931d6b7b3Judy Chen	    isa_reg_p->regspec_addr, isa_reg_p->regspec_size);
4941d6b7b3Judy Chen	return (DDI_ME_REGSPEC_RANGE);
4957832385Judy Chen}
4967832385Judy Chen
4977832385Judy Chenstatic int
4987832385Judy Chenisa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
4997832385Judy Chen    off_t offset, off_t len, caddr_t *vaddrp)
5007832385Judy Chen{
5017832385Judy Chen	struct regspec tmp_reg, *rp;
5027832385Judy Chen	pci_regspec_t vreg;
5037832385Judy Chen	ddi_map_req_t mr = *mp;		/* Get private copy of request */
5047832385Judy Chen	int error;
5057832385Judy Chen
5067832385Judy Chen	if (pseudo_isa)
5077832385Judy Chen		return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
5087832385Judy Chen
5097832385Judy Chen	mp = &mr;
5107832385Judy Chen
5117832385Judy Chen	/*
5127832385Judy Chen	 * First, if given an rnumber, convert it to a regspec...
5137832385Judy Chen	 */
5147832385Judy Chen	if (mp->map_type == DDI_MT_RNUMBER)  {
5157832385Judy Chen
5167832385Judy Chen		int rnumber = mp->map_obj.rnumber;
5177832385Judy Chen
5187832385Judy Chen		rp = i_ddi_rnumber_to_regspec(rdip, rnumber);
5197832385Judy Chen		if (rp == (struct regspec *)0)
5207832385Judy Chen			return (DDI_ME_RNUMBER_RANGE);
5217832385Judy Chen
5227832385Judy Chen		/*
5237832385Judy Chen		 * Convert the given ddi_map_req_t from rnumber to regspec...
5247832385Judy Chen		 */
5257832385Judy Chen		mp->map_type = DDI_MT_REGSPEC;
5267832385Judy Chen		mp->map_obj.rp = rp;
5277832385Judy Chen	}
5287832385Judy Chen
5297832385Judy Chen	/*
5307832385Judy Chen	 * Adjust offset and length correspnding to called values...
5317832385Judy Chen	 * XXX: A non-zero length means override the one in the regspec.
5327832385Judy Chen	 * XXX: (Regardless of what's in the parent's range)
5337832385Judy Chen	 */
5347832385Judy Chen
5357832385Judy Chen	tmp_reg = *(mp->map_obj.rp);		/* Preserve underlying data */
5367832385Judy Chen	rp = mp->map_obj.rp = &tmp_reg;		/* Use tmp_reg in request */
5377832385Judy Chen
5387832385Judy Chen	rp->regspec_addr += (uint_t)offset;
5397832385Judy Chen	if (len != 0)
5407832385Judy Chen		rp->regspec_size = (uint_t)len;
5417832385Judy Chen
5427832385Judy Chen	if ((error = isa_apply_range(dip, rp, &vreg)) != 0)
5437832385Judy Chen		return (error);
5447832385Judy Chen	mp->map_obj.rp = (struct regspec *)&vreg;
5457832385Judy Chen
5467832385Judy Chen	/*
5477832385Judy Chen	 * Call my parents bus_map function with modified values...
5487832385Judy Chen	 */
5497832385Judy Chen
5507832385Judy Chen	return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
5517832385Judy Chen}
5527832385Judy Chen
5537c478bdstevel@tonic-gatestatic int
5547c478bdstevel@tonic-gateisa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr,
5557c478bdstevel@tonic-gate    int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
5577c478bdstevel@tonic-gate	ddi_dma_attr_merge(dma_attr, &ISA_dma_attr);
5587c478bdstevel@tonic-gate	return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep));
5617c478bdstevel@tonic-gatestatic int
5627c478bdstevel@tonic-gateisa_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
5637c478bdstevel@tonic-gate    ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
5647c478bdstevel@tonic-gate    off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
5667c478bdstevel@tonic-gate	int rval;
5677c478bdstevel@tonic-gate	int arg = (int)(uintptr_t)objp;
5697c478bdstevel@tonic-gate	switch (request) {
5717c478bdstevel@tonic-gate	case DDI_DMA_E_PROG:
5727c478bdstevel@tonic-gate		return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp,
5737c478bdstevel@tonic-gate		    (ddi_dma_cookie_t *)lenp, arg));
5757c478bdstevel@tonic-gate	case DDI_DMA_E_ACQUIRE:
5767c478bdstevel@tonic-gate		return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp,
5777c478bdstevel@tonic-gate		    (caddr_t)lenp));
5797c478bdstevel@tonic-gate	case DDI_DMA_E_FREE:
5807c478bdstevel@tonic-gate		return (i_dmae_free(rdip, arg));
5827c478bdstevel@tonic-gate	case DDI_DMA_E_STOP:
5837c478bdstevel@tonic-gate		i_dmae_stop(rdip, arg);
5847c478bdstevel@tonic-gate		return (DDI_SUCCESS);
5867c478bdstevel@tonic-gate	case DDI_DMA_E_ENABLE:
5877c478bdstevel@tonic-gate		i_dmae_enable(rdip, arg);
5887c478bdstevel@tonic-gate		return (DDI_SUCCESS);
5907c478bdstevel@tonic-gate	case DDI_DMA_E_DISABLE:
5917c478bdstevel@tonic-gate		i_dmae_disable(rdip, arg);
5927c478bdstevel@tonic-gate		return (DDI_SUCCESS);
5947c478bdstevel@tonic-gate	case DDI_DMA_E_GETCNT:
5957c478bdstevel@tonic-gate		i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp);
5967c478bdstevel@tonic-gate		return (DDI_SUCCESS);
5987c478bdstevel@tonic-gate	case DDI_DMA_E_SWSETUP:
5997c478bdstevel@tonic-gate		return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp,
6007c478bdstevel@tonic-gate		    (ddi_dma_cookie_t *)lenp, arg));
6027c478bdstevel@tonic-gate	case DDI_DMA_E_SWSTART:
6037c478bdstevel@tonic-gate		i_dmae_swstart(rdip, arg);
6047c478bdstevel@tonic-gate		return (DDI_SUCCESS);
6067c478bdstevel@tonic-gate	case DDI_DMA_E_GETATTR:
6077c478bdstevel@tonic-gate		bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t));
6087c478bdstevel@tonic-gate		return (DDI_SUCCESS);
6107c478bdstevel@tonic-gate	case DDI_DMA_E_1STPTY:
6117c478bdstevel@tonic-gate		{
6127c478bdstevel@tonic-gate			struct ddi_dmae_req req1stpty =
6137c478bdstevel@tonic-gate			    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
6147c478bdstevel@tonic-gate			if (arg == 0) {
6157c478bdstevel@tonic-gate				req1stpty.der_command = DMAE_CMD_TRAN;
6167c478bdstevel@tonic-gate				req1stpty.der_trans = DMAE_TRANS_DMND;
6177c478bdstevel@tonic-gate			} else {
6187c478bdstevel@tonic-gate				req1stpty.der_trans = DMAE_TRANS_CSCD;
6197c478bdstevel@tonic-gate			}
6207c478bdstevel@tonic-gate			return (i_dmae_prog(rdip, &req1stpty, NULL, arg));
6217c478bdstevel@tonic-gate		}
6237c478bdstevel@tonic-gate	default:
624b89e420Garrett D'Amore		/*
625b89e420Garrett D'Amore		 * We pass to rootnex, but it turns out that rootnex will just
626b89e420Garrett D'Amore		 * return failure, as we don't use ddi_dma_mctl() except
627b89e420Garrett D'Amore		 * for DMA engine (ISA) and DVMA (SPARC).  Arguably we could
628b89e420Garrett D'Amore		 * just return an error direclty here, instead.
629b89e420Garrett D'Amore		 */
6307c478bdstevel@tonic-gate		rval = ddi_dma_mctl(dip, rdip, handle, request, offp,
6317c478bdstevel@tonic-gate		    lenp, objp, flags);
6327c478bdstevel@tonic-gate	}
6337c478bdstevel@tonic-gate	return (rval);
6377c478bdstevel@tonic-gate * Check if driver should be treated as an old pre 2.6 driver
6387c478bdstevel@tonic-gate */
6397c478bdstevel@tonic-gatestatic int
6407c478bdstevel@tonic-gateold_driver(dev_info_t *dip)
6427c478bdstevel@tonic-gate	extern int ignore_hardware_nodes;	/* force flag from ddi_impl.c */
6447c478bdstevel@tonic-gate	if (ndi_dev_is_persistent_node(dip)) {
6457c478bdstevel@tonic-gate		if (ignore_hardware_nodes)
6467c478bdstevel@tonic-gate			return (1);
6477c478bdstevel@tonic-gate		if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
6487c478bdstevel@tonic-gate		    "ignore-hardware-nodes", -1) != -1)
6497c478bdstevel@tonic-gate			return (1);
6507c478bdstevel@tonic-gate	}
6517c478bdstevel@tonic-gate	return (0);
6547c478bdstevel@tonic-gatetypedef struct {
6557c478bdstevel@tonic-gate	uint32_t phys_hi;
6567c478bdstevel@tonic-gate	uint32_t phys_lo;
6577c478bdstevel@tonic-gate	uint32_t size;
6587c478bdstevel@tonic-gate} isa_regs_t;
6617c478bdstevel@tonic-gate * Return non-zero if device in tree is a PnP isa device
6627c478bdstevel@tonic-gate */
6637c478bdstevel@tonic-gatestatic int
6647c478bdstevel@tonic-gateis_pnpisa(dev_info_t *dip)
6667c478bdstevel@tonic-gate	isa_regs_t *isa_regs;
6677c478bdstevel@tonic-gate	int proplen, pnpisa;
6697c478bdstevel@tonic-gate	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
670843e198johnlev	    (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) {
6717c478bdstevel@tonic-gate		return (0);
6727c478bdstevel@tonic-gate	}
6737c478bdstevel@tonic-gate	pnpisa = isa_regs[0].phys_hi & 0x80000000;
6747c478bdstevel@tonic-gate	/*
6757c478bdstevel@tonic-gate	 * free the memory allocated by ddi_getlongprop().
6767c478bdstevel@tonic-gate	 */
6777c478bdstevel@tonic-gate	kmem_free(isa_regs, proplen);
6787c478bdstevel@tonic-gate	if (pnpisa)
6797c478bdstevel@tonic-gate		return (1);
6807c478bdstevel@tonic-gate	else
6817c478bdstevel@tonic-gate		return (0);
6857c478bdstevel@tonic-gatestatic int
6867c478bdstevel@tonic-gateisa_ctlops(dev_info_t *dip, dev_info_t *rdip,
6877c478bdstevel@tonic-gate	ddi_ctl_enum_t ctlop, void *arg, void *result)
6897832385Judy Chen	int rn;
6907832385Judy Chen	struct ddi_parent_private_data *pdp;
6917832385Judy Chen
6927c478bdstevel@tonic-gate	switch (ctlop) {
6937c478bdstevel@tonic-gate	case DDI_CTLOPS_REPORTDEV:
6947c478bdstevel@tonic-gate		if (rdip == (dev_info_t *)0)
6957c478bdstevel@tonic-gate			return (DDI_FAILURE);
6967c478bdstevel@tonic-gate		cmn_err(CE_CONT, "?ISA-device: %s%d\n",
6977c478bdstevel@tonic-gate		    ddi_driver_name(rdip), ddi_get_instance(rdip));
6987c478bdstevel@tonic-gate		return (DDI_SUCCESS);
7007c478bdstevel@tonic-gate	case DDI_CTLOPS_INITCHILD:
7017c478bdstevel@tonic-gate		/*
7027c478bdstevel@tonic-gate		 * older drivers aren't expecting the "standard" device
7037c478bdstevel@tonic-gate		 * node format used by the hardware nodes.  these drivers
7047c478bdstevel@tonic-gate		 * only expect their own properties set in their driver.conf
7057c478bdstevel@tonic-gate		 * files.  so they tell us not to call them with hardware
7067c478bdstevel@tonic-gate		 * nodes by setting the property "ignore-hardware-nodes".
7077c478bdstevel@tonic-gate		 */
7087c478bdstevel@tonic-gate		if (old_driver((dev_info_t *)arg)) {
7097c478bdstevel@tonic-gate			return (DDI_NOT_WELL_FORMED);
7107c478bdstevel@tonic-gate		}
7127c478bdstevel@tonic-gate		return (isa_initchild((dev_info_t *)arg));
7147c478bdstevel@tonic-gate	case DDI_CTLOPS_UNINITCHILD:
7157c478bdstevel@tonic-gate		impl_ddi_sunbus_removechild((dev_info_t *)arg);
7167c478bdstevel@tonic-gate		return (DDI_SUCCESS);
7187c478bdstevel@tonic-gate	case DDI_CTLOPS_SIDDEV:
71997caaa3Guoli Shu<Kerry.Shu@Sun.COM>		if (ndi_dev_is_persistent_node(rdip))
72097caaa3Guoli Shu<Kerry.Shu@Sun.COM>			return (DDI_SUCCESS);
7217c478bdstevel@tonic-gate		/*
7227c478bdstevel@tonic-gate		 * All ISA devices need to do confirming probes
7237c478bdstevel@tonic-gate		 * unless they are PnP ISA.
7247c478bdstevel@tonic-gate		 */
72597caaa3Guoli Shu<Kerry.Shu@Sun.COM>		if (is_pnpisa(rdip))
7267c478bdstevel@tonic-gate			return (DDI_SUCCESS);
7277c478bdstevel@tonic-gate		else
7287c478bdstevel@tonic-gate			return (DDI_FAILURE);
7307832385Judy Chen	case DDI_CTLOPS_REGSIZE:
7317832385Judy Chen	case DDI_CTLOPS_NREGS:
7327832385Judy Chen		if (rdip == (dev_info_t *)0)
7337832385Judy Chen			return (DDI_FAILURE);
7347832385Judy Chen
7357832385Judy Chen		if ((pdp = ddi_get_parent_data(rdip)) == NULL)
7367832385Judy Chen			return (DDI_FAILURE);
7377832385Judy Chen
7387832385Judy Chen		if (ctlop == DDI_CTLOPS_NREGS) {
7397832385Judy Chen			*(int *)result = pdp->par_nreg;
7407832385Judy Chen		} else {
7417832385Judy Chen			rn = *(int *)arg;
7427832385Judy Chen			if (rn >= pdp->par_nreg)
7437832385Judy Chen				return (DDI_FAILURE);
7447832385Judy Chen			*(off_t *)result = (off_t)pdp->par_reg[rn].regspec_size;
7457832385Judy Chen		}
7467832385Judy Chen		return (DDI_SUCCESS);
7477832385Judy Chen
7487832385Judy Chen	case DDI_CTLOPS_ATTACH:
7497832385Judy Chen	case DDI_CTLOPS_DETACH:
7507832385Judy Chen	case DDI_CTLOPS_PEEK:
7517832385Judy Chen	case DDI_CTLOPS_POKE:
7527832385Judy Chen		return (DDI_FAILURE);
7537832385Judy Chen
7547c478bdstevel@tonic-gate	default:
7557c478bdstevel@tonic-gate		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
7567c478bdstevel@tonic-gate	}
7597832385Judy Chenstatic struct intrspec *
7607832385Judy Chenisa_get_ispec(dev_info_t *rdip, int inum)
7617832385Judy Chen{
7627832385Judy Chen	struct ddi_parent_private_data *pdp = ddi_get_parent_data(rdip);
7637832385Judy Chen
7647832385Judy Chen	/* Validate the interrupt number */
7657832385Judy Chen	if (inum >= pdp->par_nintr)
7667832385Judy Chen		return (NULL);
7677832385Judy Chen
7687832385Judy Chen	/* Get the interrupt structure pointer and return that */
7697832385Judy Chen	return ((struct intrspec *)&pdp->par_intr[inum]);
7707832385Judy Chen}
7717832385Judy Chen
7727832385Judy Chenstatic int
7737832385Judy Chenisa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
7747832385Judy Chen    ddi_intr_handle_impl_t *hdlp, void *result)
7757832385Judy Chen{
7767832385Judy Chen	struct intrspec *ispec;
7770d92875Gary Mills#if defined(__xpv)
7780d92875Gary Mills	int cons, ttyn;
7797832385Judy Chen
7800d92875Gary Mills	cons = console_hypervisor_dev_type(&ttyn);
7810d92875Gary Mills#endif
7827832385Judy Chen	if (pseudo_isa)
7837832385Judy Chen		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
7847832385Judy Chen
7857832385Judy Chen
7867832385Judy Chen	/* Process the interrupt operation */
7877832385Judy Chen	switch (intr_op) {
7887832385Judy Chen	case DDI_INTROP_GETCAP:
7897832385Judy Chen		/* First check with pcplusmp */
7907832385Judy Chen		if (psm_intr_ops == NULL)
7917832385Judy Chen			return (DDI_FAILURE);
7927832385Judy Chen
7937832385Judy Chen		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) {
7947832385Judy Chen			*(int *)result = 0;
7957832385Judy Chen			return (DDI_FAILURE);
7967832385Judy Chen		}
7977832385Judy Chen		break;
7987832385Judy Chen	case DDI_INTROP_SETCAP:
7997832385Judy Chen		if (psm_intr_ops == NULL)
8007832385Judy Chen			return (DDI_FAILURE);
8017832385Judy Chen
8027832385Judy Chen		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result))
8037832385Judy Chen			return (DDI_FAILURE);
8047832385Judy Chen		break;
8057832385Judy Chen	case DDI_INTROP_ALLOC:
8067ff178cJimmy Vetayases		ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
8077ff178cJimmy Vetayases		return (isa_alloc_intr_fixed(rdip, hdlp, result));
8087832385Judy Chen	case DDI_INTROP_FREE:
8097ff178cJimmy Vetayases		ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
8107ff178cJimmy Vetayases		return (isa_free_intr_fixed(rdip, hdlp));
8117832385Judy Chen	case DDI_INTROP_GETPRI:
8127832385Judy Chen		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
8137832385Judy Chen			return (DDI_FAILURE);
8147832385Judy Chen		*(int *)result = ispec->intrspec_pri;
8157832385Judy Chen		break;
8167832385Judy Chen	case DDI_INTROP_SETPRI:
8177832385Judy Chen		/* Validate the interrupt priority passed to us */
8187832385Judy Chen		if (*(int *)result > LOCK_LEVEL)
8197832385Judy Chen			return (DDI_FAILURE);
8207832385Judy Chen
8217832385Judy Chen		/* Ensure that PSM is all initialized and ispec is ok */
8227832385Judy Chen		if ((psm_intr_ops == NULL) ||
8237832385Judy Chen		    ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL))
8247832385Judy Chen			return (DDI_FAILURE);
8257832385Judy Chen
8267832385Judy Chen		/* update the ispec with the new priority */
8277832385Judy Chen		ispec->intrspec_pri =  *(int *)result;
8287832385Judy Chen		break;
8297832385Judy Chen	case DDI_INTROP_ADDISR:
8307832385Judy Chen		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
8317832385Judy Chen			return (DDI_FAILURE);
8327832385Judy Chen		ispec->intrspec_func = hdlp->ih_cb_func;
8337832385Judy Chen		break;
8347832385Judy Chen	case DDI_INTROP_REMISR:
8357832385Judy Chen		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
8367832385Judy Chen			return (DDI_FAILURE);
8377832385Judy Chen		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
8387832385Judy Chen			return (DDI_FAILURE);
8397832385Judy Chen		ispec->intrspec_func = (uint_t (*)()) 0;
8407832385Judy Chen		break;
8417832385Judy Chen	case DDI_INTROP_ENABLE:
8427832385Judy Chen		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
8437832385Judy Chen			return (DDI_FAILURE);
8447832385Judy Chen
8457832385Judy Chen		/* Call psmi to translate irq with the dip */
8467832385Judy Chen		if (psm_intr_ops == NULL)
8477832385Judy Chen			return (DDI_FAILURE);
8487832385Judy Chen
849349b53dStuart Maybee#if defined(__xpv)
850349b53dStuart Maybee		/*
851349b53dStuart Maybee		 * if the hypervisor is using an isa serial port for the
852349b53dStuart Maybee		 * console, make sure we don't try to use that interrupt as
853349b53dStuart Maybee		 * it will cause us to panic when xen_bind_pirq() fails.
854349b53dStuart Maybee		 */
8550d92875Gary Mills		if (cons == CONS_TTY && ispec->intrspec_vec == asy_intrs[ttyn])
856349b53dStuart Maybee			return (DDI_FAILURE);
857349b53dStuart Maybee#endif
8587832385Judy Chen		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
85986a9c50Guoli Shu<Kerry.Shu@Sun.COM>		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR,
86086a9c50Guoli Shu<Kerry.Shu@Sun.COM>		    (int *)&hdlp->ih_vector) == PSM_FAILURE)
86186a9c50Guoli Shu<Kerry.Shu@Sun.COM>			return (DDI_FAILURE);
8627832385Judy Chen
8637832385Judy Chen		/* Add the interrupt handler */
8647832385Judy Chen		if (!add_avintr((void *)hdlp, ispec->intrspec_pri,
8657832385Judy Chen		    hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector,
8667832385Judy Chen		    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, NULL, rdip))
8677832385Judy Chen			return (DDI_FAILURE);
8687832385Judy Chen		break;
8697832385Judy Chen	case DDI_INTROP_DISABLE:
8707832385Judy Chen		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
8717832385Judy Chen			return (DDI_FAILURE);
8727832385Judy Chen
8737832385Judy Chen		/* Call psm_ops() to translate irq with the dip */
8747832385Judy Chen		if (psm_intr_ops == NULL)
8757832385Judy Chen			return (DDI_FAILURE);
8767832385Judy Chen
8777832385Judy Chen		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
8787832385Judy Chen		(void) (*psm_intr_ops)(rdip, hdlp,
8797832385Judy Chen		    PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector);
8807832385Judy Chen
8817832385Judy Chen		/* Remove the interrupt handler */
8827832385Judy Chen		rem_avintr((void *)hdlp, ispec->intrspec_pri,
8837832385Judy Chen		    hdlp->ih_cb_func, hdlp->ih_vector);
8847832385Judy Chen		break;
8857832385Judy Chen	case DDI_INTROP_SETMASK:
8867832385Judy Chen		if (psm_intr_ops == NULL)
8877832385Judy Chen			return (DDI_FAILURE);
8887832385Judy Chen
8897832385Judy Chen		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL))
8907832385Judy Chen			return (DDI_FAILURE);
8917832385Judy Chen		break;
8927832385Judy Chen	case DDI_INTROP_CLRMASK:
8937832385Judy Chen		if (psm_intr_ops == NULL)
8947832385Judy Chen			return (DDI_FAILURE);
8957832385Judy Chen
8967832385Judy Chen		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL))
8977832385Judy Chen			return (DDI_FAILURE);
8987832385Judy Chen		break;
8997832385Judy Chen	case DDI_INTROP_GETPENDING:
9007832385Judy Chen		if (psm_intr_ops == NULL)
9017832385Judy Chen			return (DDI_FAILURE);
9027832385Judy Chen
9037832385Judy Chen		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING,
9047832385Judy Chen		    result)) {
9057832385Judy Chen			*(int *)result = 0;
9067832385Judy Chen			return (DDI_FAILURE);
9077832385Judy Chen		}
9087832385Judy Chen		break;
9097832385Judy Chen	case DDI_INTROP_NAVAIL:
9107832385Judy Chen	case DDI_INTROP_NINTRS:
9117832385Judy Chen		*(int *)result = i_ddi_get_intx_nintrs(rdip);
9127832385Judy Chen		if (*(int *)result == 0) {
9137832385Judy Chen			return (DDI_FAILURE);
9147832385Judy Chen		}
9157832385Judy Chen		break;
9167832385Judy Chen	case DDI_INTROP_SUPPORTED_TYPES:
9177832385Judy Chen		*(int *)result = DDI_INTR_TYPE_FIXED;	/* Always ... */
9187832385Judy Chen		break;
9197832385Judy Chen	default:
9207832385Judy Chen		return (DDI_FAILURE);
9217832385Judy Chen	}
9227832385Judy Chen
9237832385Judy Chen	return (DDI_SUCCESS);
9247832385Judy Chen}
9257832385Judy Chen
9267ff178cJimmy Vetayases/*
9277ff178cJimmy Vetayases * Allocate interrupt vector for FIXED (legacy) type.
9287ff178cJimmy Vetayases */
9297ff178cJimmy Vetayasesstatic int
9307ff178cJimmy Vetayasesisa_alloc_intr_fixed(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp,
9317ff178cJimmy Vetayases    void *result)
9327ff178cJimmy Vetayases{
9337ff178cJimmy Vetayases	struct intrspec		*ispec;
9347ff178cJimmy Vetayases	ddi_intr_handle_impl_t	info_hdl;
9357ff178cJimmy Vetayases	int			ret;
9367ff178cJimmy Vetayases	int			free_phdl = 0;
9377ff178cJimmy Vetayases	apic_get_type_t		type_info;
9387ff178cJimmy Vetayases
9397ff178cJimmy Vetayases	if (psm_intr_ops == NULL)
9407ff178cJimmy Vetayases		return (DDI_FAILURE);
9417ff178cJimmy Vetayases
9427ff178cJimmy Vetayases	if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
9437ff178cJimmy Vetayases		return (DDI_FAILURE);
9447ff178cJimmy Vetayases
9457ff178cJimmy Vetayases	/*
9467ff178cJimmy Vetayases	 * If the PSM module is "APIX" then pass the request for it
9477ff178cJimmy Vetayases	 * to allocate the vector now.
9487ff178cJimmy Vetayases	 */
9497ff178cJimmy Vetayases	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
9507ff178cJimmy Vetayases	info_hdl.ih_private = &type_info;
9517ff178cJimmy Vetayases	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
9527ff178cJimmy Vetayases	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
9537ff178cJimmy Vetayases		if (hdlp->ih_private == NULL) { /* allocate phdl structure */
9547ff178cJimmy Vetayases			free_phdl = 1;
9557ff178cJimmy Vetayases			i_ddi_alloc_intr_phdl(hdlp);
9567ff178cJimmy Vetayases		}
9577ff178cJimmy Vetayases		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
9587ff178cJimmy Vetayases		ret = (*psm_intr_ops)(rdip, hdlp,
9597ff178cJimmy Vetayases		    PSM_INTR_OP_ALLOC_VECTORS, result);
9607ff178cJimmy Vetayases		if (free_phdl) { /* free up the phdl structure */
9617ff178cJimmy Vetayases			free_phdl = 0;
9627ff178cJimmy Vetayases			i_ddi_free_intr_phdl(hdlp);
9637ff178cJimmy Vetayases			hdlp->ih_private = NULL;
9647ff178cJimmy Vetayases		}
9657ff178cJimmy Vetayases	} else {
9667ff178cJimmy Vetayases		/*
9677ff178cJimmy Vetayases		 * No APIX module; fall back to the old scheme where the
9687ff178cJimmy Vetayases		 * interrupt vector is allocated during ddi_enable_intr() call.
9697ff178cJimmy Vetayases		 */
9707ff178cJimmy Vetayases		hdlp->ih_pri = ispec->intrspec_pri;
9717ff178cJimmy Vetayases		*(int *)result = hdlp->ih_scratch1;
9727ff178cJimmy Vetayases		ret = DDI_SUCCESS;
9737ff178cJimmy Vetayases	}
9747ff178cJimmy Vetayases
9757ff178cJimmy Vetayases	return (ret);
9767ff178cJimmy Vetayases}
9777ff178cJimmy Vetayases
9787ff178cJimmy Vetayases/*
9797ff178cJimmy Vetayases * Free up interrupt vector for FIXED (legacy) type.
9807ff178cJimmy Vetayases */
9817ff178cJimmy Vetayasesstatic int
9827ff178cJimmy Vetayasesisa_free_intr_fixed(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
9837ff178cJimmy Vetayases{
9847ff178cJimmy Vetayases	struct intrspec			*ispec;
9857ff178cJimmy Vetayases	ddi_intr_handle_impl_t		info_hdl;
9867ff178cJimmy Vetayases	int				ret;
9877ff178cJimmy Vetayases	apic_get_type_t			type_info;
9887ff178cJimmy Vetayases
9897ff178cJimmy Vetayases	if (psm_intr_ops == NULL)
9907ff178cJimmy Vetayases		return (DDI_FAILURE);
9917ff178cJimmy Vetayases
9927ff178cJimmy Vetayases	/*
9937ff178cJimmy Vetayases	 * If the PSM module is "APIX" then pass the request for it
9947ff178cJimmy Vetayases	 * to free up the vector now.
9957ff178cJimmy Vetayases	 */
9967ff178cJimmy Vetayases	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
9977ff178cJimmy Vetayases	info_hdl.ih_private = &type_info;
9987ff178cJimmy Vetayases	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
9997ff178cJimmy Vetayases	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
10007ff178cJimmy Vetayases		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
10017ff178cJimmy Vetayases			return (DDI_FAILURE);
10027ff178cJimmy Vetayases		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
10037ff178cJimmy Vetayases		ret = (*psm_intr_ops)(rdip, hdlp,
10047ff178cJimmy Vetayases		    PSM_INTR_OP_FREE_VECTORS, NULL);
10057ff178cJimmy Vetayases	} else {
10067ff178cJimmy Vetayases		/*
10077ff178cJimmy Vetayases		 * No APIX module; fall back to the old scheme where
10087ff178cJimmy Vetayases		 * the interrupt vector was already freed during
10097ff178cJimmy Vetayases		 * ddi_disable_intr() call.
10107ff178cJimmy Vetayases		 */
10117ff178cJimmy Vetayases		ret = DDI_SUCCESS;
10127ff178cJimmy Vetayases	}
10137ff178cJimmy Vetayases
10147ff178cJimmy Vetayases	return (ret);
10157ff178cJimmy Vetayases}
10167ff178cJimmy Vetayases
10177c478bdstevel@tonic-gatestatic void
10187c478bdstevel@tonic-gateisa_vendor(uint32_t id, char *vendor)
10207c478bdstevel@tonic-gate	vendor[0] = '@' + ((id >> 26) & 0x1f);
10217c478bdstevel@tonic-gate	vendor[1] = '@' + ((id >> 21) & 0x1f);
10227c478bdstevel@tonic-gate	vendor[2] = '@' + ((id >> 16) & 0x1f);
10237c478bdstevel@tonic-gate	vendor[3] = 0;
10277c478bdstevel@tonic-gate * Name a child
10287c478bdstevel@tonic-gate */
10297c478bdstevel@tonic-gatestatic int
10307c478bdstevel@tonic-gateisa_name_child(dev_info_t *child, char *name, int namelen)
10327c478bdstevel@tonic-gate	char vendor[8];
10337c478bdstevel@tonic-gate	int device;
10347c478bdstevel@tonic-gate	uint32_t serial;
10357c478bdstevel@tonic-gate	int func;
10367c478bdstevel@tonic-gate	int bustype;
10377c478bdstevel@tonic-gate	uint32_t base;
10387c478bdstevel@tonic-gate	int proplen;
10397c478bdstevel@tonic-gate	int pnpisa = 0;
10407c478bdstevel@tonic-gate	isa_regs_t *isa_regs;
10427c478bdstevel@tonic-gate	void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **);
10447c478bdstevel@tonic-gate	/*
10457c478bdstevel@tonic-gate	 * older drivers aren't expecting the "standard" device
10467c478bdstevel@tonic-gate	 * node format used by the hardware nodes.  these drivers
10477c478bdstevel@tonic-gate	 * only expect their own properties set in their driver.conf
10487c478bdstevel@tonic-gate	 * files.  so they tell us not to call them with hardware
10497c478bdstevel@tonic-gate	 * nodes by setting the property "ignore-hardware-nodes".
10507c478bdstevel@tonic-gate	 */
10517c478bdstevel@tonic-gate	if (old_driver(child))
10527c478bdstevel@tonic-gate		return (DDI_FAILURE);
10547c478bdstevel@tonic-gate	/*
10557c478bdstevel@tonic-gate	 * Fill in parent-private data
10567c478bdstevel@tonic-gate	 */
10577c478bdstevel@tonic-gate	if (ddi_get_parent_data(child) == NULL) {
10587c478bdstevel@tonic-gate		struct ddi_parent_private_data *pdptr;
10597c478bdstevel@tonic-gate		make_ddi_ppd(child, &pdptr);
10607c478bdstevel@tonic-gate		ddi_set_parent_data(child, pdptr);
10617c478bdstevel@tonic-gate	}
10637c478bdstevel@tonic-gate	if (ndi_dev_is_persistent_node(child) == 0) {
10647c478bdstevel@tonic-gate		/*
10657c478bdstevel@tonic-gate		 * For .conf nodes, generate name from parent private data
10667c478bdstevel@tonic-gate		 */
10677c478bdstevel@tonic-gate		name[0] = '\0';
10687c478bdstevel@tonic-gate		if (sparc_pd_getnreg(child) > 0) {
10697c478bdstevel@tonic-gate			(void) snprintf(name, namelen, "%x,%x",
10707c478bdstevel@tonic-gate			    (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype,
10717c478bdstevel@tonic-gate			    (uint_t)sparc_pd_getreg(child, 0)->regspec_addr);
10727c478bdstevel@tonic-gate		}
10737c478bdstevel@tonic-gate		return (DDI_SUCCESS);
10747c478bdstevel@tonic-gate	}
10767c478bdstevel@tonic-gate	/*
10777c478bdstevel@tonic-gate	 * For hw nodes, look up "reg" property
10787c478bdstevel@tonic-gate	 */
10797c478bdstevel@tonic-gate	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
10807c478bdstevel@tonic-gate	    (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) {
10817c478bdstevel@tonic-gate		return (DDI_FAILURE);
10827c478bdstevel@tonic-gate	}
10847c478bdstevel@tonic-gate	/*
10857c478bdstevel@tonic-gate	 * extract the device identifications
10867c478bdstevel@tonic-gate	 */
10877c478bdstevel@tonic-gate	pnpisa = isa_regs[0].phys_hi & 0x80000000;
10887c478bdstevel@tonic-gate	if (pnpisa) {
10897c478bdstevel@tonic-gate		isa_vendor(isa_regs[0].phys_hi, vendor);
10907c478bdstevel@tonic-gate		device = isa_regs[0].phys_hi & 0xffff;
10917c478bdstevel@tonic-gate		serial = isa_regs[0].phys_lo;
10927c478bdstevel@tonic-gate		func = (isa_regs[0].size >> 24) & 0xff;
10937c478bdstevel@tonic-gate		if (func != 0)
10947c478bdstevel@tonic-gate			(void) snprintf(name, namelen, "pnp%s,%04x,%x,%x",
10957c478bdstevel@tonic-gate			    vendor, device, serial, func);
10967c478bdstevel@tonic-gate		else
10977c478bdstevel@tonic-gate			(void) snprintf(name, namelen, "pnp%s,%04x,%x",
10987c478bdstevel@tonic-gate			    vendor, device, serial);
10997c478bdstevel@tonic-gate	} else {
11007c478bdstevel@tonic-gate		bustype = isa_regs[0].phys_hi;
11017c478bdstevel@tonic-gate		base = isa_regs[0].phys_lo;
11027c478bdstevel@tonic-gate		(void) sprintf(name, "%x,%x", bustype, base);
11037c478bdstevel@tonic-gate	}
11057c478bdstevel@tonic-gate	/*
11067c478bdstevel@tonic-gate	 * free the memory allocated by ddi_getlongprop().
11077c478bdstevel@tonic-gate	 */
11087c478bdstevel@tonic-gate	kmem_free(isa_regs, proplen);
11107c478bdstevel@tonic-gate	return (DDI_SUCCESS);
11137c478bdstevel@tonic-gatestatic int
11147c478bdstevel@tonic-gateisa_initchild(dev_info_t *child)
11167c478bdstevel@tonic-gate	char name[80];
11187c478bdstevel@tonic-gate	if (isa_name_child(child, name, 80) != DDI_SUCCESS)
11197c478bdstevel@tonic-gate		return (DDI_FAILURE);
11207c478bdstevel@tonic-gate	ddi_set_name_addr(child, name);
11227c478bdstevel@tonic-gate	if (ndi_dev_is_persistent_node(child) != 0)
11237c478bdstevel@tonic-gate		return (DDI_SUCCESS);
11257c478bdstevel@tonic-gate	/*
11267c478bdstevel@tonic-gate	 * This is a .conf node, try merge properties onto a
11277c478bdstevel@tonic-gate	 * hw node with the same name.
11287c478bdstevel@tonic-gate	 */
11297c478bdstevel@tonic-gate	if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) {
11307c478bdstevel@tonic-gate		/*
11317c478bdstevel@tonic-gate		 * Return failure to remove node
11327c478bdstevel@tonic-gate		 */
11337c478bdstevel@tonic-gate		impl_ddi_sunbus_removechild(child);
11347c478bdstevel@tonic-gate		return (DDI_FAILURE);
11357c478bdstevel@tonic-gate	}
11367c478bdstevel@tonic-gate	/*
11377c478bdstevel@tonic-gate	 * Cannot merge node, permit pseudo children
11387c478bdstevel@tonic-gate	 */
11397c478bdstevel@tonic-gate	return (DDI_SUCCESS);
11437c478bdstevel@tonic-gate * called when ACPI enumeration is not used
11447c478bdstevel@tonic-gate */
11457c478bdstevel@tonic-gatestatic void
11487c478bdstevel@tonic-gate	/* needs to be in increasing order */
11497c478bdstevel@tonic-gate	int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc};
11507c478bdstevel@tonic-gate	int dma[] = {0x2};
11517c478bdstevel@tonic-gate	int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10,
11527c478bdstevel@tonic-gate	    0x778, 0x4};
11537c478bdstevel@tonic-gate	dev_info_t *usedrdip;
11557c478bdstevel@tonic-gate	usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0);
11577c478bdstevel@tonic-gate	if (usedrdip == NULL) {
11587c478bdstevel@tonic-gate		(void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES,
1159fa9e406ahrens		    (pnode_t)DEVI_SID_NODEID, &usedrdip);
11607c478bdstevel@tonic-gate	}
11627c478bdstevel@tonic-gate	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
11637c478bdstevel@tonic-gate	    "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int)));
11647c478bdstevel@tonic-gate	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
11657c478bdstevel@tonic-gate	    "io-space", (int *)io, (int)(sizeof (io) / sizeof (int)));
11667c478bdstevel@tonic-gate	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
11677c478bdstevel@tonic-gate	    "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int)));
11687c478bdstevel@tonic-gate	(void) ndi_devi_bind_driver(usedrdip, 0);
11720d92875Gary Mills/*
11730d92875Gary Mills * Return non-zero if UART device exists.
11740d92875Gary Mills */
11750d92875Gary Millsstatic int
11760d92875Gary Millsuart_exists(ushort_t port)
11770d92875Gary Mills{
11780d92875Gary Mills	outb(port + COM_SCR, (char)0x5a);
11790d92875Gary Mills	outb(port + COM_ISR, (char)0x00);
11800d92875Gary Mills	return (inb(port + COM_SCR) == (char)0x5a);
11810d92875Gary Mills}
11820d92875Gary Mills
11837c478bdstevel@tonic-gatestatic void
118437d6e24lipeng sang - Sun Microsystems - Beijing Chinaisa_enumerate(int reprogram)
11867c478bdstevel@tonic-gate	int circ, i;
11877c478bdstevel@tonic-gate	dev_info_t *xdip;
118837d6e24lipeng sang - Sun Microsystems - Beijing China	dev_info_t *isa_dip = ddi_find_devinfo("isa", -1, 0);
11907c478bdstevel@tonic-gate	struct regspec i8042_regs[] = {
11917c478bdstevel@tonic-gate		{1, 0x60, 0x1},
11927c478bdstevel@tonic-gate		{1, 0x64, 0x1}
11937c478bdstevel@tonic-gate	};
11947c478bdstevel@tonic-gate	int i8042_intrs[] = {0x1, 0xc};
11957c478bdstevel@tonic-gate	char *acpi_prop;
11967c478bdstevel@tonic-gate	int acpi_enum = 1; /* ACPI is default to be on */
11970d92875Gary Mills#if defined(__xpv)
11980d92875Gary Mills	int cons, ttyn;
12000d92875Gary Mills	cons = console_hypervisor_dev_type(&ttyn);
12010d92875Gary Mills#endif
120237d6e24lipeng sang - Sun Microsystems - Beijing China	if (reprogram || !isa_dip)
12037c478bdstevel@tonic-gate		return;
120537d6e24lipeng sang - Sun Microsystems - Beijing China	bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec));
120637d6e24lipeng sang - Sun Microsystems - Beijing China
12077c478bdstevel@tonic-gate	ndi_devi_enter(isa_dip, &circ);
12097c478bdstevel@tonic-gate	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
12107c478bdstevel@tonic-gate	    DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) {
12117c478bdstevel@tonic-gate		acpi_enum = strcmp("off", acpi_prop);
12127c478bdstevel@tonic-gate		ddi_prop_free(acpi_prop);
12137c478bdstevel@tonic-gate	}
12157c478bdstevel@tonic-gate	if (acpi_enum) {
12167c478bdstevel@tonic-gate		if (acpi_isa_device_enum(isa_dip)) {
12177c478bdstevel@tonic-gate			ndi_devi_exit(isa_dip, circ);
12187c478bdstevel@tonic-gate			if (isa_resource_setup() != NDI_SUCCESS) {
12197c478bdstevel@tonic-gate				cmn_err(CE_WARN, "isa nexus: isa "
12207c478bdstevel@tonic-gate				    "resource setup failed");
12217c478bdstevel@tonic-gate			}
1223dffe9acml			/* serial ports? */
1224dffe9acml			enumerate_BIOS_serial(isa_dip);
12251d6b7b3Judy Chen
12261d6b7b3Judy Chen			/* adjust parallel port size  */
12271d6b7b3Judy Chen			adjust_prtsz(isa_dip);
122837d6e24lipeng sang - Sun Microsystems - Beijing China
122937d6e24lipeng sang - Sun Microsystems - Beijing China			isa_create_ranges_prop(isa_dip);
12307c478bdstevel@tonic-gate			return;
12317c478bdstevel@tonic-gate		}
12327c478bdstevel@tonic-gate		cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS");
12337c478bdstevel@tonic-gate	}
12347c478bdstevel@tonic-gate	cmn_err(CE_NOTE, "!ACPI is off");
12367c478bdstevel@tonic-gate	/* serial ports */
12370d92875Gary Mills	for (i = 0; i < min_BIOS_serial; i++) {
12380d92875Gary Mills		ushort_t addr = asy_regs[i].regspec_addr;
12390d92875Gary Mills		if (!uart_exists(addr))
12400d92875Gary Mills			continue;
1241843e198johnlev#if defined(__xpv)
12420d92875Gary Mills		if (cons == CONS_TTY && ttyn == i)
1243349b53dStuart Maybee			continue;
12457c478bdstevel@tonic-gate		ndi_devi_alloc_sleep(isa_dip, "asy",
1246fa9e406ahrens		    (pnode_t)DEVI_SID_NODEID, &xdip);
12470d92875Gary Mills		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
12480d92875Gary Mills		    "compatible", "PNP0500");
12490d92875Gary Mills		/* This should be gotten from master file: */
12500d92875Gary Mills		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
12510d92875Gary Mills		    "model", "Standard PC COM port");
12527c478bdstevel@tonic-gate		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
12537c478bdstevel@tonic-gate		    "reg", (int *)&asy_regs[i], 3);
12547c478bdstevel@tonic-gate		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip,
12557c478bdstevel@tonic-gate		    "interrupts", asy_intrs[i]);
12567c478bdstevel@tonic-gate		(void) ndi_devi_bind_driver(xdip, 0);
12570d92875Gary Mills		/* Adjusting isa_extra here causes a kernel dump later. */
12587c478bdstevel@tonic-gate	}
12607c478bdstevel@tonic-gate	/* i8042 node */
12617c478bdstevel@tonic-gate	ndi_devi_alloc_sleep(isa_dip, "i8042",
1262fa9e406ahrens	    (pnode_t)DEVI_SID_NODEID, &xdip);
12637c478bdstevel@tonic-gate	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
12647c478bdstevel@tonic-gate	    "reg", (int *)i8042_regs, 6);
12657c478bdstevel@tonic-gate	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
12667c478bdstevel@tonic-gate	    "interrupts", (int *)i8042_intrs, 2);
12677c478bdstevel@tonic-gate	(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
12687c478bdstevel@tonic-gate	    "unit-address", "1,60");
12697c478bdstevel@tonic-gate	(void) ndi_devi_bind_driver(xdip, 0);
12717c478bdstevel@tonic-gate	add_known_used_resources();
12737c478bdstevel@tonic-gate	ndi_devi_exit(isa_dip, circ);
127537d6e24lipeng sang - Sun Microsystems - Beijing China	isa_create_ranges_prop(isa_dip);
1279dffe9acml * On some machines, serial port 2 isn't listed in the ACPI table.
12800d92875Gary Mills * This function goes through the base I/O addresses and makes sure all
1281dffe9acml * the serial ports there are in the dev_info tree.  If any are missing,
1282dffe9acml * this function will add them.
1283dffe9acml */
1285dffe9acmlstatic void
1286dffe9acmlenumerate_BIOS_serial(dev_info_t *isa_dip)
1288dffe9acml	int i;
1289dffe9acml	dev_info_t *xdip;
1290dffe9acml	int found;
1291dffe9acml	int ret;
1292dffe9acml	struct regspec *tmpregs;
1293dffe9acml	int tmpregs_len;
12940d92875Gary Mills#if defined(__xpv)
12950d92875Gary Mills	int cons, ttyn;
12960d92875Gary Mills
12970d92875Gary Mills	cons = console_hypervisor_dev_type(&ttyn);
12980d92875Gary Mills#endif
1300dffe9acml	/*
13010d92875Gary Mills	 * Scan the base I/O addresses of the first four serial ports.
1302dffe9acml	 */
1303dffe9acml	for (i = 0; i < num_BIOS_serial; i++) {
13040d92875Gary Mills		ushort_t addr = asy_regs[i].regspec_addr;
1306dffe9acml		/* Look for it in the dev_info tree */
1307dffe9acml		found = 0;
1308dffe9acml		for (xdip = ddi_get_child(isa_dip); xdip != NULL;
1309dffe9acml		    xdip = ddi_get_next_sibling(xdip)) {
1310dffe9acml			if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) {
1311dffe9acml				/* skip non asy */
1312dffe9acml				continue;
1313dffe9acml			}
1315dffe9acml			/* Match by addr */
1316dffe9acml			ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip,
1317843e198johnlev			    DDI_PROP_DONTPASS, "reg", (int **)&tmpregs,
1318843e198johnlev			    (uint_t *)&tmpregs_len);
1319dffe9acml			if (ret != DDI_PROP_SUCCESS) {
1320dffe9acml				/* error */
1321dffe9acml				continue;
1322dffe9acml			}
13240d92875Gary Mills			if (tmpregs->regspec_addr == addr)
1325dffe9acml				found = 1;
13260d92875Gary Mills
1327dffe9acml			/*
1328dffe9acml			 * Free the memory allocated by
1329dffe9acml			 * ddi_prop_lookup_int_array().
1330dffe9acml			 */
1331dffe9acml			ddi_prop_free(tmpregs);
1333709ee7cPaul B. Henson			if (found) {
1334709ee7cPaul B. Henson				if (asy_intr_override & 1<<i) {
1335709ee7cPaul B. Henson					(void) ndi_prop_update_int(
1336709ee7cPaul B. Henson					    DDI_DEV_T_NONE, xdip,
1337709ee7cPaul B. Henson					    "interrupts", asy_intrs[i]);
1338709ee7cPaul B. Henson				}
1339709ee7cPaul B. Henson
13400d92875Gary Mills				break;