xref: /onnv-gate/usr/src/uts/i86pc/io/pci/pci.c (revision 881:e6bc7f4b8a33)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  *	Host to PCI local bus driver
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/conf.h>
340Sstevel@tonic-gate #include <sys/modctl.h>
350Sstevel@tonic-gate #include <sys/pci.h>
360Sstevel@tonic-gate #include <sys/pci_impl.h>
37*881Sjohnny #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/sunndi.h>
390Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h>
400Sstevel@tonic-gate #include <sys/pci_cfgspace.h>
41*881Sjohnny #include <io/pci/pci_common.h>
42*881Sjohnny #include <io/pci/pci_tools_ext.h>
43*881Sjohnny #include <io/pci/pci_var.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /* Save minimal state. */
460Sstevel@tonic-gate void *pci_statep;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate  * Bus Operation functions
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate static int	pci_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
520Sstevel@tonic-gate 		    off_t, off_t, caddr_t *);
530Sstevel@tonic-gate static int	pci_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
540Sstevel@tonic-gate 		    void *, void *);
550Sstevel@tonic-gate static int	pci_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
560Sstevel@tonic-gate 		    ddi_intr_handle_impl_t *, void *);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate struct bus_ops pci_bus_ops = {
590Sstevel@tonic-gate 	BUSO_REV,
600Sstevel@tonic-gate 	pci_bus_map,
610Sstevel@tonic-gate 	NULL,
620Sstevel@tonic-gate 	NULL,
630Sstevel@tonic-gate 	NULL,
640Sstevel@tonic-gate 	i_ddi_map_fault,
650Sstevel@tonic-gate 	ddi_dma_map,
660Sstevel@tonic-gate 	ddi_dma_allochdl,
670Sstevel@tonic-gate 	ddi_dma_freehdl,
680Sstevel@tonic-gate 	ddi_dma_bindhdl,
690Sstevel@tonic-gate 	ddi_dma_unbindhdl,
700Sstevel@tonic-gate 	ddi_dma_flush,
710Sstevel@tonic-gate 	ddi_dma_win,
720Sstevel@tonic-gate 	ddi_dma_mctl,
730Sstevel@tonic-gate 	pci_ctlops,
740Sstevel@tonic-gate 	ddi_bus_prop_op,
750Sstevel@tonic-gate 	0,		/* (*bus_get_eventcookie)();	*/
760Sstevel@tonic-gate 	0,		/* (*bus_add_eventcall)();	*/
770Sstevel@tonic-gate 	0,		/* (*bus_remove_eventcall)();	*/
780Sstevel@tonic-gate 	0,		/* (*bus_post_event)();		*/
790Sstevel@tonic-gate 	0,		/* (*bus_intr_ctl)(); */
800Sstevel@tonic-gate 	0,		/* (*bus_config)(); */
810Sstevel@tonic-gate 	0,		/* (*bus_unconfig)(); */
820Sstevel@tonic-gate 	NULL,		/* (*bus_fm_init)(); */
830Sstevel@tonic-gate 	NULL,		/* (*bus_fm_fini)(); */
840Sstevel@tonic-gate 	NULL,		/* (*bus_fm_access_enter)(); */
850Sstevel@tonic-gate 	NULL,		/* (*bus_fm_access_exit)(); */
860Sstevel@tonic-gate 	NULL,		/* (*bus_power)(); */
870Sstevel@tonic-gate 	pci_intr_ops	/* (*bus_intr_op)(); */
880Sstevel@tonic-gate };
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * One goal here is to leverage off of the pcihp.c source without making
920Sstevel@tonic-gate  * changes to it.  Call into it's cb_ops directly if needed, piggybacking
930Sstevel@tonic-gate  * anything else needed by the pci_tools.c module.  Only pci_tools and pcihp
94117Sschwartz  * will be opening PCI nexus driver file descriptors.
950Sstevel@tonic-gate  */
96*881Sjohnny static int	pci_open(dev_t *, int, int, cred_t *);
97*881Sjohnny static int	pci_close(dev_t, int, int, cred_t *);
98*881Sjohnny static int	pci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
99*881Sjohnny static int	pci_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
100*881Sjohnny 		    caddr_t, int *);
101*881Sjohnny static int	pci_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate struct cb_ops pci_cb_ops = {
1040Sstevel@tonic-gate 	pci_open,			/* open */
1050Sstevel@tonic-gate 	pci_close,			/* close */
1060Sstevel@tonic-gate 	nodev,				/* strategy */
1070Sstevel@tonic-gate 	nodev,				/* print */
1080Sstevel@tonic-gate 	nodev,				/* dump */
1090Sstevel@tonic-gate 	nodev,				/* read */
1100Sstevel@tonic-gate 	nodev,				/* write */
1110Sstevel@tonic-gate 	pci_ioctl,			/* ioctl */
1120Sstevel@tonic-gate 	nodev,				/* devmap */
1130Sstevel@tonic-gate 	nodev,				/* mmap */
1140Sstevel@tonic-gate 	nodev,				/* segmap */
1150Sstevel@tonic-gate 	nochpoll,			/* poll */
1160Sstevel@tonic-gate 	pci_prop_op,			/* cb_prop_op */
1170Sstevel@tonic-gate 	NULL,				/* streamtab */
1180Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
1190Sstevel@tonic-gate 	CB_REV,				/* rev */
1200Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
1210Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
1220Sstevel@tonic-gate };
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * Device Node Operation functions
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
1280Sstevel@tonic-gate static int pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate struct dev_ops pci_ops = {
1310Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
1320Sstevel@tonic-gate 	0,			/* refcnt  */
1330Sstevel@tonic-gate 	pci_info,		/* info */
1340Sstevel@tonic-gate 	nulldev,		/* identify */
1350Sstevel@tonic-gate 	nulldev,		/* probe */
1360Sstevel@tonic-gate 	pci_attach,		/* attach */
1370Sstevel@tonic-gate 	pci_detach,		/* detach */
1380Sstevel@tonic-gate 	nulldev,		/* reset */
1390Sstevel@tonic-gate 	&pci_cb_ops,		/* driver operations */
1400Sstevel@tonic-gate 	&pci_bus_ops		/* bus operations */
1410Sstevel@tonic-gate };
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /*
144354Smyers  * This variable controls the default setting of the command register
145354Smyers  * for pci devices.  See pci_initchild() for details.
146354Smyers  */
147354Smyers static ushort_t pci_command_default = PCI_COMM_ME |
148354Smyers 					PCI_COMM_MAE |
149354Smyers 					PCI_COMM_IO;
150354Smyers 
151354Smyers /*
1520Sstevel@tonic-gate  * Internal routines in support of particular pci_ctlops.
1530Sstevel@tonic-gate  */
1540Sstevel@tonic-gate static int pci_removechild(dev_info_t *child);
1550Sstevel@tonic-gate static int pci_initchild(dev_info_t *child);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * These are the access routines.  The pci_bus_map sets the handle
1590Sstevel@tonic-gate  * to point to these.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate static uint8_t pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr);
1620Sstevel@tonic-gate static uint16_t pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr);
1630Sstevel@tonic-gate static uint32_t pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr);
1640Sstevel@tonic-gate static uint64_t pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate static void pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr,
1670Sstevel@tonic-gate 				uint8_t value);
1680Sstevel@tonic-gate static void pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr,
1690Sstevel@tonic-gate 				uint16_t value);
1700Sstevel@tonic-gate static void pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr,
1710Sstevel@tonic-gate 				uint32_t value);
1720Sstevel@tonic-gate static void pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr,
1730Sstevel@tonic-gate 				uint64_t value);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate static void pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1760Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags);
1770Sstevel@tonic-gate static void pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1780Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags);
1790Sstevel@tonic-gate static void pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1800Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags);
1810Sstevel@tonic-gate static void pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1820Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate static void pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1850Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags);
1860Sstevel@tonic-gate static void pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1870Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags);
1880Sstevel@tonic-gate static void pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1890Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags);
1900Sstevel@tonic-gate static void pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1910Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate  * Module linkage information for the kernel.
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate static struct modldrv modldrv = {
1980Sstevel@tonic-gate 	&mod_driverops, /* Type of module */
1990Sstevel@tonic-gate 	"host to PCI nexus driver %I%",
2000Sstevel@tonic-gate 	&pci_ops,	/* driver ops */
2010Sstevel@tonic-gate };
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate static struct modlinkage modlinkage = {
2040Sstevel@tonic-gate 	MODREV_1,
2050Sstevel@tonic-gate 	(void *)&modldrv,
2060Sstevel@tonic-gate 	NULL
2070Sstevel@tonic-gate };
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate int
2100Sstevel@tonic-gate _init(void)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	int e;
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	/*
2150Sstevel@tonic-gate 	 * Initialize per-pci bus soft state pointer.
2160Sstevel@tonic-gate 	 */
2170Sstevel@tonic-gate 	e = ddi_soft_state_init(&pci_statep, sizeof (pci_state_t), 1);
2180Sstevel@tonic-gate 	if (e != 0)
2190Sstevel@tonic-gate 		return (e);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0)
2220Sstevel@tonic-gate 		ddi_soft_state_fini(&pci_statep);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	return (e);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate int
2280Sstevel@tonic-gate _fini(void)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate 	int rc;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	rc = mod_remove(&modlinkage);
2330Sstevel@tonic-gate 	if (rc != 0)
2340Sstevel@tonic-gate 		return (rc);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	ddi_soft_state_fini(&pci_statep);
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	return (rc);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate int
2420Sstevel@tonic-gate _info(struct modinfo *modinfop)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate /*ARGSUSED*/
2480Sstevel@tonic-gate static int
2490Sstevel@tonic-gate pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2500Sstevel@tonic-gate {
2510Sstevel@tonic-gate 	/*
2520Sstevel@tonic-gate 	 * Use the minor number as constructed by pcihp, as the index value to
2530Sstevel@tonic-gate 	 * ddi_soft_state_zalloc.
2540Sstevel@tonic-gate 	 */
255117Sschwartz 	int instance = ddi_get_instance(devi);
2560Sstevel@tonic-gate 	pci_state_t *pcip = NULL;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci")
2590Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
2600Sstevel@tonic-gate 		cmn_err(CE_WARN, "pci:  'device_type' prop create failed");
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 
263117Sschwartz 	if (ddi_soft_state_zalloc(pci_statep, instance) == DDI_SUCCESS) {
264117Sschwartz 		pcip = ddi_get_soft_state(pci_statep, instance);
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if (pcip == NULL) {
268117Sschwartz 		goto bad_soft_state;
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	pcip->pci_dip = devi;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	/*
2740Sstevel@tonic-gate 	 * Initialize hotplug support on this bus. At minimum
2750Sstevel@tonic-gate 	 * (for non hotplug bus) this would create ":devctl" minor
2760Sstevel@tonic-gate 	 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
2770Sstevel@tonic-gate 	 * to this bus.
2780Sstevel@tonic-gate 	 */
2790Sstevel@tonic-gate 	if (pcihp_init(devi) != DDI_SUCCESS) {
2800Sstevel@tonic-gate 		cmn_err(CE_WARN, "pci: Failed to setup hotplug framework");
281117Sschwartz 		goto bad_pcihp_init;
282117Sschwartz 	}
283117Sschwartz 
284777Sschwartz 	/* Second arg: initialize for pci, not pci_express */
285777Sschwartz 	if (pcitool_init(devi, B_FALSE) != DDI_SUCCESS) {
286117Sschwartz 		goto bad_pcitool_init;
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	ddi_report_dev(devi);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	return (DDI_SUCCESS);
292117Sschwartz 
293117Sschwartz bad_pcitool_init:
294117Sschwartz 	(void) pcihp_uninit(devi);
295117Sschwartz bad_pcihp_init:
296117Sschwartz 	ddi_soft_state_free(pci_statep, instance);
297117Sschwartz bad_soft_state:
298117Sschwartz 	return (DDI_FAILURE);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate /*ARGSUSED*/
3020Sstevel@tonic-gate static int
3030Sstevel@tonic-gate pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
3040Sstevel@tonic-gate {
305117Sschwartz 	/* Uninitialize pcitool support. */
306117Sschwartz 	pcitool_uninit(devi);
307117Sschwartz 
308117Sschwartz 	/* Uninitialize hotplug support on this bus. */
3090Sstevel@tonic-gate 	(void) pcihp_uninit(devi);
310117Sschwartz 
3110Sstevel@tonic-gate 	ddi_soft_state_free(pci_statep, DIP_TO_MINOR(devi));
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	return (DDI_SUCCESS);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate static int
3170Sstevel@tonic-gate pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
3180Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	struct regspec reg;
3210Sstevel@tonic-gate 	ddi_map_req_t mr;
3220Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
3230Sstevel@tonic-gate 	ddi_acc_impl_t *ap;
3240Sstevel@tonic-gate 	pci_regspec_t pci_reg;
3250Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
3260Sstevel@tonic-gate 	int 	rnumber;
3270Sstevel@tonic-gate 	int	length;
3280Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
3290Sstevel@tonic-gate 	int	space;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	mr = *mp; /* Get private copy of request */
3330Sstevel@tonic-gate 	mp = &mr;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	/*
3360Sstevel@tonic-gate 	 * check for register number
3370Sstevel@tonic-gate 	 */
3380Sstevel@tonic-gate 	switch (mp->map_type) {
3390Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
3400Sstevel@tonic-gate 		pci_reg = *(pci_regspec_t *)(mp->map_obj.rp);
3410Sstevel@tonic-gate 		pci_rp = &pci_reg;
342*881Sjohnny 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
3430Sstevel@tonic-gate 			return (DDI_FAILURE);
3440Sstevel@tonic-gate 		break;
3450Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
3460Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
3470Sstevel@tonic-gate 		/*
3480Sstevel@tonic-gate 		 * get ALL "reg" properties for dip, select the one of
3490Sstevel@tonic-gate 		 * of interest. In x86, "assigned-addresses" property
3500Sstevel@tonic-gate 		 * is identical to the "reg" property, so there is no
3510Sstevel@tonic-gate 		 * need to cross check the two to determine the physical
3520Sstevel@tonic-gate 		 * address of the registers.
3530Sstevel@tonic-gate 		 * This routine still performs some validity checks to
3540Sstevel@tonic-gate 		 * make sure that everything is okay.
3550Sstevel@tonic-gate 		 */
356*881Sjohnny 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
357*881Sjohnny 		    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
358*881Sjohnny 		    (uint_t *)&length) != DDI_PROP_SUCCESS)
3590Sstevel@tonic-gate 			return (DDI_FAILURE);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 		/*
3620Sstevel@tonic-gate 		 * validate the register number.
3630Sstevel@tonic-gate 		 */
3640Sstevel@tonic-gate 		length /= (sizeof (pci_regspec_t) / sizeof (int));
3650Sstevel@tonic-gate 		if (rnumber >= length) {
3660Sstevel@tonic-gate 			ddi_prop_free(pci_rp);
3670Sstevel@tonic-gate 			return (DDI_FAILURE);
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		/*
3710Sstevel@tonic-gate 		 * copy the required entry.
3720Sstevel@tonic-gate 		 */
3730Sstevel@tonic-gate 		pci_reg = pci_rp[rnumber];
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 		/*
3760Sstevel@tonic-gate 		 * free the memory allocated by ddi_prop_lookup_int_array
3770Sstevel@tonic-gate 		 */
3780Sstevel@tonic-gate 		ddi_prop_free(pci_rp);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 		pci_rp = &pci_reg;
381*881Sjohnny 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
3820Sstevel@tonic-gate 			return (DDI_FAILURE);
3830Sstevel@tonic-gate 		mp->map_type = DDI_MT_REGSPEC;
3840Sstevel@tonic-gate 		break;
3850Sstevel@tonic-gate 	default:
3860Sstevel@tonic-gate 		return (DDI_ME_INVAL);
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	/*
3920Sstevel@tonic-gate 	 * check for unmap and unlock of address space
3930Sstevel@tonic-gate 	 */
3940Sstevel@tonic-gate 	if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
3950Sstevel@tonic-gate 		/*
3960Sstevel@tonic-gate 		 * Adjust offset and length
3970Sstevel@tonic-gate 		 * A non-zero length means override the one in the regspec.
3980Sstevel@tonic-gate 		 */
3990Sstevel@tonic-gate 		pci_rp->pci_phys_low += (uint_t)offset;
4000Sstevel@tonic-gate 		if (len != 0)
4010Sstevel@tonic-gate 			pci_rp->pci_size_low = len;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		switch (space) {
4040Sstevel@tonic-gate 		case PCI_ADDR_CONFIG:
4050Sstevel@tonic-gate 			/* No work required on unmap of Config space */
4060Sstevel@tonic-gate 			return (DDI_SUCCESS);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		case PCI_ADDR_IO:
4090Sstevel@tonic-gate 			reg.regspec_bustype = 1;
4100Sstevel@tonic-gate 			break;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 		case PCI_ADDR_MEM64:
4130Sstevel@tonic-gate 			/*
4140Sstevel@tonic-gate 			 * MEM64 requires special treatment on map, to check
4150Sstevel@tonic-gate 			 * that the device is below 4G.  On unmap, however,
4160Sstevel@tonic-gate 			 * we can assume that everything is OK... the map
4170Sstevel@tonic-gate 			 * must have succeeded.
4180Sstevel@tonic-gate 			 */
4190Sstevel@tonic-gate 			/* FALLTHROUGH */
4200Sstevel@tonic-gate 		case PCI_ADDR_MEM32:
4210Sstevel@tonic-gate 			reg.regspec_bustype = 0;
4220Sstevel@tonic-gate 			break;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 		default:
4250Sstevel@tonic-gate 			return (DDI_FAILURE);
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 		reg.regspec_addr = pci_rp->pci_phys_low;
4280Sstevel@tonic-gate 		reg.regspec_size = pci_rp->pci_size_low;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		mp->map_obj.rp = &reg;
4310Sstevel@tonic-gate 		return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	/* check for user mapping request - not legal for Config */
4360Sstevel@tonic-gate 	if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) {
4370Sstevel@tonic-gate 		return (DDI_FAILURE);
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	/*
4410Sstevel@tonic-gate 	 * check for config space
4420Sstevel@tonic-gate 	 * On x86, CONFIG is not mapped via MMU and there is
4430Sstevel@tonic-gate 	 * no endian-ness issues. Set the attr field in the handle to
4440Sstevel@tonic-gate 	 * indicate that the common routines to call the nexus driver.
4450Sstevel@tonic-gate 	 */
4460Sstevel@tonic-gate 	if (space == PCI_ADDR_CONFIG) {
4470Sstevel@tonic-gate 		hp = (ddi_acc_hdl_t *)mp->map_handlep;
4480Sstevel@tonic-gate 
449*881Sjohnny 		/* Can't map config space without a handle */
450*881Sjohnny 		if (hp == NULL)
4510Sstevel@tonic-gate 			return (DDI_FAILURE);
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 		ap = (ddi_acc_impl_t *)hp->ah_platform_private;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		/* endian-ness check */
4560Sstevel@tonic-gate 		if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
4570Sstevel@tonic-gate 			return (DDI_FAILURE);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 		/*
4600Sstevel@tonic-gate 		 * range check
4610Sstevel@tonic-gate 		 */
4620Sstevel@tonic-gate 		if ((offset >= 256) || (len > 256) || (offset + len > 256))
4630Sstevel@tonic-gate 			return (DDI_FAILURE);
4640Sstevel@tonic-gate 		*vaddrp = (caddr_t)offset;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
4670Sstevel@tonic-gate 		ap->ahi_put8 = pci_config_wr8;
4680Sstevel@tonic-gate 		ap->ahi_get8 = pci_config_rd8;
4690Sstevel@tonic-gate 		ap->ahi_put64 = pci_config_wr64;
4700Sstevel@tonic-gate 		ap->ahi_get64 = pci_config_rd64;
4710Sstevel@tonic-gate 		ap->ahi_rep_put8 = pci_config_rep_wr8;
4720Sstevel@tonic-gate 		ap->ahi_rep_get8 = pci_config_rep_rd8;
4730Sstevel@tonic-gate 		ap->ahi_rep_put64 = pci_config_rep_wr64;
4740Sstevel@tonic-gate 		ap->ahi_rep_get64 = pci_config_rep_rd64;
4750Sstevel@tonic-gate 		ap->ahi_get16 = pci_config_rd16;
4760Sstevel@tonic-gate 		ap->ahi_get32 = pci_config_rd32;
4770Sstevel@tonic-gate 		ap->ahi_put16 = pci_config_wr16;
4780Sstevel@tonic-gate 		ap->ahi_put32 = pci_config_wr32;
4790Sstevel@tonic-gate 		ap->ahi_rep_get16 = pci_config_rep_rd16;
4800Sstevel@tonic-gate 		ap->ahi_rep_get32 = pci_config_rep_rd32;
4810Sstevel@tonic-gate 		ap->ahi_rep_put16 = pci_config_rep_wr16;
4820Sstevel@tonic-gate 		ap->ahi_rep_put32 = pci_config_rep_wr32;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 		/* Initialize to default check/notify functions */
4850Sstevel@tonic-gate 		ap->ahi_fault_check = i_ddi_acc_fault_check;
4860Sstevel@tonic-gate 		ap->ahi_fault_notify = i_ddi_acc_fault_notify;
4870Sstevel@tonic-gate 		ap->ahi_fault = 0;
4880Sstevel@tonic-gate 		impl_acc_err_init(hp);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		/* record the device address for future reference */
4910Sstevel@tonic-gate 		cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private;
4920Sstevel@tonic-gate 		cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
4930Sstevel@tonic-gate 		cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
4940Sstevel@tonic-gate 		cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		return (DDI_SUCCESS);
4970Sstevel@tonic-gate 	}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	/*
5000Sstevel@tonic-gate 	 * range check
5010Sstevel@tonic-gate 	 */
5020Sstevel@tonic-gate 	if ((offset >= pci_rp->pci_size_low) ||
5030Sstevel@tonic-gate 	    (len > pci_rp->pci_size_low) ||
5040Sstevel@tonic-gate 	    (offset + len > pci_rp->pci_size_low)) {
5050Sstevel@tonic-gate 		return (DDI_FAILURE);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	/*
5090Sstevel@tonic-gate 	 * Adjust offset and length
5100Sstevel@tonic-gate 	 * A non-zero length means override the one in the regspec.
5110Sstevel@tonic-gate 	 */
5120Sstevel@tonic-gate 	pci_rp->pci_phys_low += (uint_t)offset;
5130Sstevel@tonic-gate 	if (len != 0)
5140Sstevel@tonic-gate 		pci_rp->pci_size_low = len;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/*
5170Sstevel@tonic-gate 	 * convert the pci regsec into the generic regspec used by the
5180Sstevel@tonic-gate 	 * parent root nexus driver.
5190Sstevel@tonic-gate 	 */
5200Sstevel@tonic-gate 	switch (space) {
5210Sstevel@tonic-gate 	case PCI_ADDR_IO:
5220Sstevel@tonic-gate 		reg.regspec_bustype = 1;
5230Sstevel@tonic-gate 		break;
5240Sstevel@tonic-gate 	case PCI_ADDR_MEM64:
5250Sstevel@tonic-gate 		/*
5260Sstevel@tonic-gate 		 * We can't handle 64-bit devices that are mapped above
5270Sstevel@tonic-gate 		 * 4G or that are larger than 4G.
5280Sstevel@tonic-gate 		 */
5290Sstevel@tonic-gate 		if (pci_rp->pci_phys_mid != 0 ||
5300Sstevel@tonic-gate 		    pci_rp->pci_size_hi != 0)
5310Sstevel@tonic-gate 			return (DDI_FAILURE);
5320Sstevel@tonic-gate 		/*
5330Sstevel@tonic-gate 		 * Other than that, we can treat them as 32-bit mappings
5340Sstevel@tonic-gate 		 */
5350Sstevel@tonic-gate 		/* FALLTHROUGH */
5360Sstevel@tonic-gate 	case PCI_ADDR_MEM32:
5370Sstevel@tonic-gate 		reg.regspec_bustype = 0;
5380Sstevel@tonic-gate 		break;
5390Sstevel@tonic-gate 	default:
5400Sstevel@tonic-gate 		return (DDI_FAILURE);
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 	reg.regspec_addr = pci_rp->pci_phys_low;
5430Sstevel@tonic-gate 	reg.regspec_size = pci_rp->pci_size_low;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	mp->map_obj.rp = &reg;
5460Sstevel@tonic-gate 	return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*ARGSUSED*/
5510Sstevel@tonic-gate static int
5520Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
5530Sstevel@tonic-gate 	ddi_ctl_enum_t ctlop, void *arg, void *result)
5540Sstevel@tonic-gate {
5550Sstevel@tonic-gate 	pci_regspec_t *drv_regp;
5560Sstevel@tonic-gate 	uint_t	reglen;
5570Sstevel@tonic-gate 	int	rn;
5580Sstevel@tonic-gate 	int	totreg;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	switch (ctlop) {
5610Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
5620Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
5630Sstevel@tonic-gate 			return (DDI_FAILURE);
5640Sstevel@tonic-gate 		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
5650Sstevel@tonic-gate 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
5660Sstevel@tonic-gate 		    ddi_driver_name(rdip),
5670Sstevel@tonic-gate 		    ddi_get_instance(rdip));
5680Sstevel@tonic-gate 		return (DDI_SUCCESS);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
5710Sstevel@tonic-gate 		return (pci_initchild((dev_info_t *)arg));
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
5740Sstevel@tonic-gate 		return (pci_removechild((dev_info_t *)arg));
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
5770Sstevel@tonic-gate 		return (DDI_SUCCESS);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
5800Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
5810Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
5820Sstevel@tonic-gate 			return (DDI_FAILURE);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 		*(int *)result = 0;
5850Sstevel@tonic-gate 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
5860Sstevel@tonic-gate 				DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
5870Sstevel@tonic-gate 				&reglen) != DDI_PROP_SUCCESS) {
5880Sstevel@tonic-gate 			return (DDI_FAILURE);
5890Sstevel@tonic-gate 		}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 		totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t);
5920Sstevel@tonic-gate 		if (ctlop == DDI_CTLOPS_NREGS)
5930Sstevel@tonic-gate 			*(int *)result = totreg;
5940Sstevel@tonic-gate 		else if (ctlop == DDI_CTLOPS_REGSIZE) {
5950Sstevel@tonic-gate 			rn = *(int *)arg;
5960Sstevel@tonic-gate 			if (rn >= totreg) {
5970Sstevel@tonic-gate 				ddi_prop_free(drv_regp);
5980Sstevel@tonic-gate 				return (DDI_FAILURE);
5990Sstevel@tonic-gate 			}
6000Sstevel@tonic-gate 			*(off_t *)result = drv_regp[rn].pci_size_low;
6010Sstevel@tonic-gate 		}
6020Sstevel@tonic-gate 		ddi_prop_free(drv_regp);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 		return (DDI_SUCCESS);
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	case DDI_CTLOPS_POWER: {
6070Sstevel@tonic-gate 		power_req_t	*reqp = (power_req_t *)arg;
6080Sstevel@tonic-gate 		/*
6090Sstevel@tonic-gate 		 * We currently understand reporting of PCI_PM_IDLESPEED
6100Sstevel@tonic-gate 		 * capability. Everything else is passed up.
6110Sstevel@tonic-gate 		 */
6120Sstevel@tonic-gate 		if ((reqp->request_type == PMR_REPORT_PMCAP) &&
6130Sstevel@tonic-gate 		    (reqp->req.report_pmcap_req.cap ==  PCI_PM_IDLESPEED)) {
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 			return (DDI_SUCCESS);
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	default:
6210Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/* NOTREACHED */
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate /*
629*881Sjohnny  * pci_intr_ops
6300Sstevel@tonic-gate  */
6310Sstevel@tonic-gate static int
632*881Sjohnny pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
633*881Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
6340Sstevel@tonic-gate {
635*881Sjohnny 	return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result));
636*881Sjohnny }
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate static int
6400Sstevel@tonic-gate pci_initchild(dev_info_t *child)
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate 	char name[80];
643354Smyers 	ddi_acc_handle_t config_handle;
644354Smyers 	ushort_t command_preserve, command;
6450Sstevel@tonic-gate 
646*881Sjohnny 	if (pci_common_name_child(child, name, 80) != DDI_SUCCESS) {
6470Sstevel@tonic-gate 		return (DDI_FAILURE);
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/*
6520Sstevel@tonic-gate 	 * Pseudo nodes indicate a prototype node with per-instance
6530Sstevel@tonic-gate 	 * properties to be merged into the real h/w device node.
6540Sstevel@tonic-gate 	 * The interpretation of the unit-address is DD[,F]
6550Sstevel@tonic-gate 	 * where DD is the device id and F is the function.
6560Sstevel@tonic-gate 	 */
6570Sstevel@tonic-gate 	if (ndi_dev_is_persistent_node(child) == 0) {
6580Sstevel@tonic-gate 		extern int pci_allow_pseudo_children;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 		/*
6630Sstevel@tonic-gate 		 * Try to merge the properties from this prototype
6640Sstevel@tonic-gate 		 * node into real h/w nodes.
6650Sstevel@tonic-gate 		 */
666*881Sjohnny 		if (ndi_merge_node(child, pci_common_name_child) ==
667*881Sjohnny 		    DDI_SUCCESS) {
6680Sstevel@tonic-gate 			/*
6690Sstevel@tonic-gate 			 * Merged ok - return failure to remove the node.
6700Sstevel@tonic-gate 			 */
6710Sstevel@tonic-gate 			ddi_set_name_addr(child, NULL);
6720Sstevel@tonic-gate 			return (DDI_FAILURE);
6730Sstevel@tonic-gate 		}
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 		/* workaround for ddivs to run under PCI */
6760Sstevel@tonic-gate 		if (pci_allow_pseudo_children) {
6770Sstevel@tonic-gate 			/*
6780Sstevel@tonic-gate 			 * If the "interrupts" property doesn't exist,
6790Sstevel@tonic-gate 			 * this must be the ddivs no-intr case, and it returns
6800Sstevel@tonic-gate 			 * DDI_SUCCESS instead of DDI_FAILURE.
6810Sstevel@tonic-gate 			 */
6820Sstevel@tonic-gate 			if (ddi_prop_get_int(DDI_DEV_T_ANY, child,
6830Sstevel@tonic-gate 			    DDI_PROP_DONTPASS, "interrupts", -1) == -1)
6840Sstevel@tonic-gate 				return (DDI_SUCCESS);
6850Sstevel@tonic-gate 			/*
6860Sstevel@tonic-gate 			 * Create the ddi_parent_private_data for a pseudo
6870Sstevel@tonic-gate 			 * child.
6880Sstevel@tonic-gate 			 */
689*881Sjohnny 			pci_common_set_parent_private_data(child);
6900Sstevel@tonic-gate 			return (DDI_SUCCESS);
6910Sstevel@tonic-gate 		}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 		/*
6940Sstevel@tonic-gate 		 * The child was not merged into a h/w node,
6950Sstevel@tonic-gate 		 * but there's not much we can do with it other
6960Sstevel@tonic-gate 		 * than return failure to cause the node to be removed.
6970Sstevel@tonic-gate 		 */
6980Sstevel@tonic-gate 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
6990Sstevel@tonic-gate 		    ddi_get_name(child), ddi_get_name_addr(child),
7000Sstevel@tonic-gate 		    ddi_get_name(child));
7010Sstevel@tonic-gate 		ddi_set_name_addr(child, NULL);
7020Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
706*881Sjohnny 	    "interrupts", -1) != -1)
707*881Sjohnny 		pci_common_set_parent_private_data(child);
708*881Sjohnny 	else
7090Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
7100Sstevel@tonic-gate 
711354Smyers 	/*
712354Smyers 	 * initialize command register
713354Smyers 	 */
714354Smyers 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
715354Smyers 		return (DDI_FAILURE);
716354Smyers 
717354Smyers 	/*
718354Smyers 	 * Support for the "command-preserve" property.
719354Smyers 	 */
720354Smyers 	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
721354Smyers 						DDI_PROP_DONTPASS,
722354Smyers 						"command-preserve", 0);
723354Smyers 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
724354Smyers 	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
725354Smyers 	command |= (pci_command_default & ~command_preserve);
726354Smyers 	pci_config_put16(config_handle, PCI_CONF_COMM, command);
727354Smyers 
728354Smyers 	pci_config_teardown(&config_handle);
7290Sstevel@tonic-gate 	return (DDI_SUCCESS);
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate static int
7330Sstevel@tonic-gate pci_removechild(dev_info_t *dip)
7340Sstevel@tonic-gate {
7350Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
7380Sstevel@tonic-gate 		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
7390Sstevel@tonic-gate 		ddi_set_parent_data(dip, NULL);
7400Sstevel@tonic-gate 	}
7410Sstevel@tonic-gate 	ddi_set_name_addr(dip, NULL);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	/*
7440Sstevel@tonic-gate 	 * Strip the node to properly convert it back to prototype form
7450Sstevel@tonic-gate 	 */
7460Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	impl_rem_dev_props(dip);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	return (DDI_SUCCESS);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate /*
7550Sstevel@tonic-gate  * These are the get and put functions to be shared with drivers. The
7560Sstevel@tonic-gate  * mutex locking is done inside the functions referenced, rather than
7570Sstevel@tonic-gate  * here, and is thus shared across PCI child drivers and any other
7580Sstevel@tonic-gate  * consumers of PCI config space (such as the ACPI subsystem).
7590Sstevel@tonic-gate  *
7600Sstevel@tonic-gate  * The configuration space addresses come in as pointers.  This is fine on
7610Sstevel@tonic-gate  * a 32-bit system, where the VM space and configuration space are the same
7620Sstevel@tonic-gate  * size.  It's not such a good idea on a 64-bit system, where memory
7630Sstevel@tonic-gate  * addresses are twice as large as configuration space addresses.  At some
7640Sstevel@tonic-gate  * point in the call tree we need to take a stand and say "you are 32-bit
7650Sstevel@tonic-gate  * from this time forth", and this seems like a nice self-contained place.
7660Sstevel@tonic-gate  */
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate static uint8_t
7690Sstevel@tonic-gate pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
7720Sstevel@tonic-gate 	uint8_t	rval;
7730Sstevel@tonic-gate 	int reg;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
7820Sstevel@tonic-gate 	    reg);
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	return (rval);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate static void
7880Sstevel@tonic-gate pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
7890Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags)
7900Sstevel@tonic-gate {
7910Sstevel@tonic-gate 	uint8_t *h, *d;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	h = host_addr;
7940Sstevel@tonic-gate 	d = dev_addr;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
7970Sstevel@tonic-gate 		for (; repcount; repcount--)
7980Sstevel@tonic-gate 			*h++ = pci_config_rd8(hdlp, d++);
7990Sstevel@tonic-gate 	else
8000Sstevel@tonic-gate 		for (; repcount; repcount--)
8010Sstevel@tonic-gate 			*h++ = pci_config_rd8(hdlp, d);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate static uint16_t
8050Sstevel@tonic-gate pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
8080Sstevel@tonic-gate 	uint16_t rval;
8090Sstevel@tonic-gate 	int reg;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
8180Sstevel@tonic-gate 	    reg);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	return (rval);
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate static void
8240Sstevel@tonic-gate pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
8250Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags)
8260Sstevel@tonic-gate {
8270Sstevel@tonic-gate 	uint16_t *h, *d;
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	h = host_addr;
8300Sstevel@tonic-gate 	d = dev_addr;
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
8330Sstevel@tonic-gate 		for (; repcount; repcount--)
8340Sstevel@tonic-gate 			*h++ = pci_config_rd16(hdlp, d++);
8350Sstevel@tonic-gate 	else
8360Sstevel@tonic-gate 		for (; repcount; repcount--)
8370Sstevel@tonic-gate 			*h++ = pci_config_rd16(hdlp, d);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate static uint32_t
8410Sstevel@tonic-gate pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
8420Sstevel@tonic-gate {
8430Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
8440Sstevel@tonic-gate 	uint32_t rval;
8450Sstevel@tonic-gate 	int reg;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
8540Sstevel@tonic-gate 	    cfp->c_funcnum, reg);
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	return (rval);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate static void
8600Sstevel@tonic-gate pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
8610Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate 	uint32_t *h, *d;
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	h = host_addr;
8660Sstevel@tonic-gate 	d = dev_addr;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
8690Sstevel@tonic-gate 		for (; repcount; repcount--)
8700Sstevel@tonic-gate 			*h++ = pci_config_rd32(hdlp, d++);
8710Sstevel@tonic-gate 	else
8720Sstevel@tonic-gate 		for (; repcount; repcount--)
8730Sstevel@tonic-gate 			*h++ = pci_config_rd32(hdlp, d);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate static void
8780Sstevel@tonic-gate pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
8810Sstevel@tonic-gate 	int reg;
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
8900Sstevel@tonic-gate 	    cfp->c_funcnum, reg, value);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate static void
8940Sstevel@tonic-gate pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
8950Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate 	uint8_t *h, *d;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	h = host_addr;
9000Sstevel@tonic-gate 	d = dev_addr;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
9030Sstevel@tonic-gate 		for (; repcount; repcount--)
9040Sstevel@tonic-gate 			pci_config_wr8(hdlp, d++, *h++);
9050Sstevel@tonic-gate 	else
9060Sstevel@tonic-gate 		for (; repcount; repcount--)
9070Sstevel@tonic-gate 			pci_config_wr8(hdlp, d, *h++);
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate static void
9110Sstevel@tonic-gate pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
9140Sstevel@tonic-gate 	int reg;
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
9230Sstevel@tonic-gate 	    cfp->c_funcnum, reg, value);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate static void
9270Sstevel@tonic-gate pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
9280Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags)
9290Sstevel@tonic-gate {
9300Sstevel@tonic-gate 	uint16_t *h, *d;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	h = host_addr;
9330Sstevel@tonic-gate 	d = dev_addr;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
9360Sstevel@tonic-gate 		for (; repcount; repcount--)
9370Sstevel@tonic-gate 			pci_config_wr16(hdlp, d++, *h++);
9380Sstevel@tonic-gate 	else
9390Sstevel@tonic-gate 		for (; repcount; repcount--)
9400Sstevel@tonic-gate 			pci_config_wr16(hdlp, d, *h++);
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate static void
9440Sstevel@tonic-gate pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
9470Sstevel@tonic-gate 	int reg;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
9560Sstevel@tonic-gate 	    cfp->c_funcnum, reg, value);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate static void
9600Sstevel@tonic-gate pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
9610Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags)
9620Sstevel@tonic-gate {
9630Sstevel@tonic-gate 	uint32_t *h, *d;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	h = host_addr;
9660Sstevel@tonic-gate 	d = dev_addr;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
9690Sstevel@tonic-gate 		for (; repcount; repcount--)
9700Sstevel@tonic-gate 			pci_config_wr32(hdlp, d++, *h++);
9710Sstevel@tonic-gate 	else
9720Sstevel@tonic-gate 		for (; repcount; repcount--)
9730Sstevel@tonic-gate 			pci_config_wr32(hdlp, d, *h++);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate static uint64_t
9770Sstevel@tonic-gate pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
9780Sstevel@tonic-gate {
9790Sstevel@tonic-gate 	uint32_t lw_val;
9800Sstevel@tonic-gate 	uint32_t hi_val;
9810Sstevel@tonic-gate 	uint32_t *dp;
9820Sstevel@tonic-gate 	uint64_t val;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	dp = (uint32_t *)addr;
9850Sstevel@tonic-gate 	lw_val = pci_config_rd32(hdlp, dp);
9860Sstevel@tonic-gate 	dp++;
9870Sstevel@tonic-gate 	hi_val = pci_config_rd32(hdlp, dp);
9880Sstevel@tonic-gate 	val = ((uint64_t)hi_val << 32) | lw_val;
9890Sstevel@tonic-gate 	return (val);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate static void
9930Sstevel@tonic-gate pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	uint32_t lw_val;
9960Sstevel@tonic-gate 	uint32_t hi_val;
9970Sstevel@tonic-gate 	uint32_t *dp;
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	dp = (uint32_t *)addr;
10000Sstevel@tonic-gate 	lw_val = (uint32_t)(value & 0xffffffff);
10010Sstevel@tonic-gate 	hi_val = (uint32_t)(value >> 32);
10020Sstevel@tonic-gate 	pci_config_wr32(hdlp, dp, lw_val);
10030Sstevel@tonic-gate 	dp++;
10040Sstevel@tonic-gate 	pci_config_wr32(hdlp, dp, hi_val);
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate static void
10080Sstevel@tonic-gate pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
10090Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags)
10100Sstevel@tonic-gate {
10110Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR) {
10120Sstevel@tonic-gate 		for (; repcount; repcount--)
10130Sstevel@tonic-gate 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
10140Sstevel@tonic-gate 	} else {
10150Sstevel@tonic-gate 		for (; repcount; repcount--)
10160Sstevel@tonic-gate 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate static void
10210Sstevel@tonic-gate pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
10220Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags)
10230Sstevel@tonic-gate {
10240Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR) {
10250Sstevel@tonic-gate 		for (; repcount; repcount--)
10260Sstevel@tonic-gate 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
10270Sstevel@tonic-gate 	} else {
10280Sstevel@tonic-gate 		for (; repcount; repcount--)
10290Sstevel@tonic-gate 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate 
1033*881Sjohnny 
10340Sstevel@tonic-gate /*
10350Sstevel@tonic-gate  * When retrofitting this module for pci_tools, functions such as open, close,
10360Sstevel@tonic-gate  * and ioctl are now pulled into this module.  Before this, the functions in
10370Sstevel@tonic-gate  * the pcihp module were referenced directly.  Now they are called or
10380Sstevel@tonic-gate  * referenced through the pcihp cb_ops structure from functions in this module.
10390Sstevel@tonic-gate  */
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate static int
10420Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
10430Sstevel@tonic-gate {
1044*881Sjohnny 	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate static int
10480Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp)
10490Sstevel@tonic-gate {
1050*881Sjohnny 	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate static int
1054*881Sjohnny pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
10550Sstevel@tonic-gate {
1056777Sschwartz 	minor_t		minor = getminor(dev);
1057777Sschwartz 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
1058777Sschwartz 	pci_state_t	*pci_p = ddi_get_soft_state(pci_statep, instance);
10590Sstevel@tonic-gate 
1060*881Sjohnny 	if (pci_p == NULL)
1061*881Sjohnny 		return (ENXIO);
1062117Sschwartz 
1063*881Sjohnny 	return (pci_common_ioctl(pci_p->pci_dip,
1064*881Sjohnny 	    dev, cmd, arg, mode, credp, rvalp));
1065*881Sjohnny }
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate static int
10690Sstevel@tonic-gate pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1070117Sschwartz 	int flags, char *name, caddr_t valuep, int *lengthp)
10710Sstevel@tonic-gate {
1072*881Sjohnny 	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
10730Sstevel@tonic-gate 	    name, valuep, lengthp));
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate static int
10770Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
10780Sstevel@tonic-gate {
10790Sstevel@tonic-gate 	return (pcihp_info(dip, cmd, arg, result));
10800Sstevel@tonic-gate }
1081