xref: /illumos-gate/usr/src/uts/i86pc/io/pci/pci.c (revision 1f0c5e61)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
500d0963fSdilpreet  * Common Development and Distribution License (the "License").
600d0963fSdilpreet  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
229757e35cSStephen Hanson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
25cd21e7c5SGarrett D'Amore /*
26cd21e7c5SGarrett D'Amore  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
27*1f0c5e61SRobert Mustacchi  * Copyright 2016 Joyent, Inc.
28cd21e7c5SGarrett D'Amore  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  *	Host to PCI local bus driver
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/conf.h>
357c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
367c478bd9Sstevel@tonic-gate #include <sys/pci.h>
377c478bd9Sstevel@tonic-gate #include <sys/pci_impl.h>
3870025d76Sjohnny #include <sys/sysmacros.h>
397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
4000d0963fSdilpreet #include <sys/ddifm.h>
4100d0963fSdilpreet #include <sys/ndifm.h>
4200d0963fSdilpreet #include <sys/fm/protocol.h>
437c478bd9Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h>
4470025d76Sjohnny #include <io/pci/pci_common.h>
4570025d76Sjohnny #include <io/pci/pci_tools_ext.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* Save minimal state. */
487c478bd9Sstevel@tonic-gate void *pci_statep;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Bus Operation functions
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate static int	pci_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
547c478bd9Sstevel@tonic-gate 		    off_t, off_t, caddr_t *);
557c478bd9Sstevel@tonic-gate static int	pci_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
567c478bd9Sstevel@tonic-gate 		    void *, void *);
577c478bd9Sstevel@tonic-gate static int	pci_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
587c478bd9Sstevel@tonic-gate 		    ddi_intr_handle_impl_t *, void *);
5900d0963fSdilpreet static int	pci_fm_init(dev_info_t *, dev_info_t *, int,
6000d0963fSdilpreet 		    ddi_iblock_cookie_t *);
6100d0963fSdilpreet static int	pci_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate struct bus_ops pci_bus_ops = {
647c478bd9Sstevel@tonic-gate 	BUSO_REV,
657c478bd9Sstevel@tonic-gate 	pci_bus_map,
667c478bd9Sstevel@tonic-gate 	NULL,
677c478bd9Sstevel@tonic-gate 	NULL,
687c478bd9Sstevel@tonic-gate 	NULL,
697c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,
70cd21e7c5SGarrett D'Amore 	NULL,
717c478bd9Sstevel@tonic-gate 	ddi_dma_allochdl,
727c478bd9Sstevel@tonic-gate 	ddi_dma_freehdl,
737c478bd9Sstevel@tonic-gate 	ddi_dma_bindhdl,
747c478bd9Sstevel@tonic-gate 	ddi_dma_unbindhdl,
757c478bd9Sstevel@tonic-gate 	ddi_dma_flush,
767c478bd9Sstevel@tonic-gate 	ddi_dma_win,
777c478bd9Sstevel@tonic-gate 	ddi_dma_mctl,
787c478bd9Sstevel@tonic-gate 	pci_ctlops,
797c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
807c478bd9Sstevel@tonic-gate 	0,		/* (*bus_get_eventcookie)();	*/
817c478bd9Sstevel@tonic-gate 	0,		/* (*bus_add_eventcall)();	*/
827c478bd9Sstevel@tonic-gate 	0,		/* (*bus_remove_eventcall)();	*/
837c478bd9Sstevel@tonic-gate 	0,		/* (*bus_post_event)();		*/
847c478bd9Sstevel@tonic-gate 	0,		/* (*bus_intr_ctl)(); */
857c478bd9Sstevel@tonic-gate 	0,		/* (*bus_config)(); */
867c478bd9Sstevel@tonic-gate 	0,		/* (*bus_unconfig)(); */
8700d0963fSdilpreet 	pci_fm_init,	/* (*bus_fm_init)(); */
887c478bd9Sstevel@tonic-gate 	NULL,		/* (*bus_fm_fini)(); */
897c478bd9Sstevel@tonic-gate 	NULL,		/* (*bus_fm_access_enter)(); */
907c478bd9Sstevel@tonic-gate 	NULL,		/* (*bus_fm_access_exit)(); */
917c478bd9Sstevel@tonic-gate 	NULL,		/* (*bus_power)(); */
927c478bd9Sstevel@tonic-gate 	pci_intr_ops	/* (*bus_intr_op)(); */
937c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * One goal here is to leverage off of the pcihp.c source without making
977c478bd9Sstevel@tonic-gate  * changes to it.  Call into it's cb_ops directly if needed, piggybacking
987c478bd9Sstevel@tonic-gate  * anything else needed by the pci_tools.c module.  Only pci_tools and pcihp
997851eb82Sschwartz  * will be opening PCI nexus driver file descriptors.
1007c478bd9Sstevel@tonic-gate  */
10170025d76Sjohnny static int	pci_open(dev_t *, int, int, cred_t *);
10270025d76Sjohnny static int	pci_close(dev_t, int, int, cred_t *);
10370025d76Sjohnny static int	pci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
10470025d76Sjohnny static int	pci_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
10570025d76Sjohnny 		    caddr_t, int *);
10670025d76Sjohnny static int	pci_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
107eae2e508Skrishnae static void	pci_peekpoke_cb(dev_info_t *, ddi_fm_error_t *);
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate struct cb_ops pci_cb_ops = {
1107c478bd9Sstevel@tonic-gate 	pci_open,			/* open */
1117c478bd9Sstevel@tonic-gate 	pci_close,			/* close */
1127c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
1137c478bd9Sstevel@tonic-gate 	nodev,				/* print */
1147c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
1157c478bd9Sstevel@tonic-gate 	nodev,				/* read */
1167c478bd9Sstevel@tonic-gate 	nodev,				/* write */
1177c478bd9Sstevel@tonic-gate 	pci_ioctl,			/* ioctl */
1187c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
1197c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
1207c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
1217c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
1227c478bd9Sstevel@tonic-gate 	pci_prop_op,			/* cb_prop_op */
1237c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
1247c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
1257c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
1267c478bd9Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
1277c478bd9Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
1287c478bd9Sstevel@tonic-gate };
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * Device Node Operation functions
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
1347c478bd9Sstevel@tonic-gate static int pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate struct dev_ops pci_ops = {
1377c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
1387c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
1397c478bd9Sstevel@tonic-gate 	pci_info,		/* info */
1407c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
1417c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
1427c478bd9Sstevel@tonic-gate 	pci_attach,		/* attach */
1437c478bd9Sstevel@tonic-gate 	pci_detach,		/* detach */
1447c478bd9Sstevel@tonic-gate 	nulldev,		/* reset */
1457c478bd9Sstevel@tonic-gate 	&pci_cb_ops,		/* driver operations */
14619397407SSherry Moore 	&pci_bus_ops,		/* bus operations */
14719397407SSherry Moore 	NULL,			/* power */
14819397407SSherry Moore 	ddi_quiesce_not_needed		/* quiesce */
1497c478bd9Sstevel@tonic-gate };
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
152c11e1991Smyers  * This variable controls the default setting of the command register
153c11e1991Smyers  * for pci devices.  See pci_initchild() for details.
154c11e1991Smyers  */
155c11e1991Smyers static ushort_t pci_command_default = PCI_COMM_ME |
156c11e1991Smyers 					PCI_COMM_MAE |
157c11e1991Smyers 					PCI_COMM_IO;
158c11e1991Smyers 
159c11e1991Smyers /*
1607c478bd9Sstevel@tonic-gate  * Internal routines in support of particular pci_ctlops.
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate static int pci_removechild(dev_info_t *child);
1637c478bd9Sstevel@tonic-gate static int pci_initchild(dev_info_t *child);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1707c478bd9Sstevel@tonic-gate 	&mod_driverops, 			/* Type of module */
17126947304SEvan Yan 	"x86 Host to PCI nexus driver",		/* Name of module */
1727c478bd9Sstevel@tonic-gate 	&pci_ops,				/* driver ops */
1737c478bd9Sstevel@tonic-gate };
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1767c478bd9Sstevel@tonic-gate 	MODREV_1,
1777c478bd9Sstevel@tonic-gate 	(void *)&modldrv,
1787c478bd9Sstevel@tonic-gate 	NULL
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate int
_init(void)1827c478bd9Sstevel@tonic-gate _init(void)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	int e;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	/*
1877c478bd9Sstevel@tonic-gate 	 * Initialize per-pci bus soft state pointer.
1887c478bd9Sstevel@tonic-gate 	 */
1897c478bd9Sstevel@tonic-gate 	e = ddi_soft_state_init(&pci_statep, sizeof (pci_state_t), 1);
1907c478bd9Sstevel@tonic-gate 	if (e != 0)
1917c478bd9Sstevel@tonic-gate 		return (e);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0)
1947c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&pci_statep);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	return (e);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate int
_fini(void)2007c478bd9Sstevel@tonic-gate _fini(void)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	int rc;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	rc = mod_remove(&modlinkage);
2057c478bd9Sstevel@tonic-gate 	if (rc != 0)
2067c478bd9Sstevel@tonic-gate 		return (rc);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&pci_statep);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	return (rc);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2147c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2207c478bd9Sstevel@tonic-gate static int
pci_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2217c478bd9Sstevel@tonic-gate pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	/*
2247c478bd9Sstevel@tonic-gate 	 * Use the minor number as constructed by pcihp, as the index value to
2257c478bd9Sstevel@tonic-gate 	 * ddi_soft_state_zalloc.
2267c478bd9Sstevel@tonic-gate 	 */
2277851eb82Sschwartz 	int instance = ddi_get_instance(devi);
2287c478bd9Sstevel@tonic-gate 	pci_state_t *pcip = NULL;
2292df1fe9cSrandyf 	switch (cmd) {
2302df1fe9cSrandyf 	case DDI_ATTACH:
2312df1fe9cSrandyf 		break;
2322df1fe9cSrandyf 
2332df1fe9cSrandyf 	case DDI_RESUME:
2342df1fe9cSrandyf 		return (DDI_SUCCESS);
2352df1fe9cSrandyf 
2362df1fe9cSrandyf 	default:
2372df1fe9cSrandyf 		return (DDI_FAILURE);
2382df1fe9cSrandyf 	}
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci")
2417c478bd9Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
2427c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pci:  'device_type' prop create failed");
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457851eb82Sschwartz 	if (ddi_soft_state_zalloc(pci_statep, instance) == DDI_SUCCESS) {
2467851eb82Sschwartz 		pcip = ddi_get_soft_state(pci_statep, instance);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (pcip == NULL) {
2507851eb82Sschwartz 		goto bad_soft_state;
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	pcip->pci_dip = devi;
25426947304SEvan Yan 	pcip->pci_soft_state = PCI_SOFT_STATE_CLOSED;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/*
2577c478bd9Sstevel@tonic-gate 	 * Initialize hotplug support on this bus. At minimum
2587c478bd9Sstevel@tonic-gate 	 * (for non hotplug bus) this would create ":devctl" minor
2597c478bd9Sstevel@tonic-gate 	 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
2607c478bd9Sstevel@tonic-gate 	 * to this bus.
2617c478bd9Sstevel@tonic-gate 	 */
2627c478bd9Sstevel@tonic-gate 	if (pcihp_init(devi) != DDI_SUCCESS) {
2637c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pci: Failed to setup hotplug framework");
2647851eb82Sschwartz 		goto bad_pcihp_init;
2657851eb82Sschwartz 	}
2667851eb82Sschwartz 
267d4476ccbSschwartz 	/* Second arg: initialize for pci, not pci_express */
268d4476ccbSschwartz 	if (pcitool_init(devi, B_FALSE) != DDI_SUCCESS) {
2697851eb82Sschwartz 		goto bad_pcitool_init;
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
27200d0963fSdilpreet 	pcip->pci_fmcap = DDI_FM_ERRCB_CAPABLE |
27300d0963fSdilpreet 	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
27400d0963fSdilpreet 	ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc);
27526947304SEvan Yan 	mutex_init(&pcip->pci_mutex, NULL, MUTEX_DRIVER, NULL);
27600d0963fSdilpreet 	mutex_init(&pcip->pci_err_mutex, NULL, MUTEX_DRIVER,
27700d0963fSdilpreet 	    (void *)pcip->pci_fm_ibc);
27800d0963fSdilpreet 	mutex_init(&pcip->pci_peek_poke_mutex, NULL, MUTEX_DRIVER,
27900d0963fSdilpreet 	    (void *)pcip->pci_fm_ibc);
28000d0963fSdilpreet 	if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) {
28100d0963fSdilpreet 		pci_ereport_setup(devi);
28200d0963fSdilpreet 		ddi_fm_handler_register(devi, pci_fm_callback, NULL);
28300d0963fSdilpreet 	}
28400d0963fSdilpreet 
2857c478bd9Sstevel@tonic-gate 	ddi_report_dev(devi);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2887851eb82Sschwartz 
2897851eb82Sschwartz bad_pcitool_init:
2907851eb82Sschwartz 	(void) pcihp_uninit(devi);
2917851eb82Sschwartz bad_pcihp_init:
2927851eb82Sschwartz 	ddi_soft_state_free(pci_statep, instance);
2937851eb82Sschwartz bad_soft_state:
2947851eb82Sschwartz 	return (DDI_FAILURE);
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2987c478bd9Sstevel@tonic-gate static int
pci_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)2997c478bd9Sstevel@tonic-gate pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
3007c478bd9Sstevel@tonic-gate {
3017a364d25Sschwartz 	int instance = ddi_get_instance(devi);
30200d0963fSdilpreet 	pci_state_t *pcip;
30300d0963fSdilpreet 
30400d0963fSdilpreet 	pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(devi));
3052df1fe9cSrandyf 
3062df1fe9cSrandyf 
3072df1fe9cSrandyf 	switch (cmd) {
3082df1fe9cSrandyf 	case DDI_DETACH:
30900d0963fSdilpreet 		if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) {
31000d0963fSdilpreet 			ddi_fm_handler_unregister(devi);
31100d0963fSdilpreet 			pci_ereport_teardown(devi);
31200d0963fSdilpreet 		}
31300d0963fSdilpreet 		mutex_destroy(&pcip->pci_peek_poke_mutex);
31400d0963fSdilpreet 		mutex_destroy(&pcip->pci_err_mutex);
31526947304SEvan Yan 		mutex_destroy(&pcip->pci_mutex);
3162df1fe9cSrandyf 		ddi_fm_fini(devi);	/* Uninitialize pcitool support. */
3177851eb82Sschwartz 		pcitool_uninit(devi);
3187851eb82Sschwartz 
3197851eb82Sschwartz 		/* Uninitialize hotplug support on this bus. */
3207c478bd9Sstevel@tonic-gate 		(void) pcihp_uninit(devi);
3217851eb82Sschwartz 
3227a364d25Sschwartz 		ddi_soft_state_free(pci_statep, instance);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3252df1fe9cSrandyf 	case DDI_SUSPEND:
3262df1fe9cSrandyf 		return (DDI_SUCCESS);
3272df1fe9cSrandyf 	default:
3282df1fe9cSrandyf 		return (DDI_FAILURE);
3292df1fe9cSrandyf 	}
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate static int
pci_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)3337c478bd9Sstevel@tonic-gate pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
3347c478bd9Sstevel@tonic-gate     off_t offset, off_t len, caddr_t *vaddrp)
3357c478bd9Sstevel@tonic-gate {
336*1f0c5e61SRobert Mustacchi 	struct regspec64 reg;
3377c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr;
3387c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
339837c1ac4SStephen Hanson 	ddi_acc_impl_t *hdlp;
3407c478bd9Sstevel@tonic-gate 	pci_regspec_t pci_reg;
3417c478bd9Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
3427c478bd9Sstevel@tonic-gate 	int 	rnumber;
343*1f0c5e61SRobert Mustacchi 	uint64_t pci_rlength;
344*1f0c5e61SRobert Mustacchi 	uint_t	nelems;
3457c478bd9Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
3467c478bd9Sstevel@tonic-gate 	int	space;
347837c1ac4SStephen Hanson 	pci_state_t *pcip;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	mr = *mp; /* Get private copy of request */
3507c478bd9Sstevel@tonic-gate 	mp = &mr;
3517c478bd9Sstevel@tonic-gate 
3529757e35cSStephen Hanson 	if (mp->map_handlep != NULL) {
353837c1ac4SStephen Hanson 		pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip));
354837c1ac4SStephen Hanson 		hdlp = (ddi_acc_impl_t *)(mp->map_handlep)->ah_platform_private;
355837c1ac4SStephen Hanson 		hdlp->ahi_err_mutexp = &pcip->pci_err_mutex;
356837c1ac4SStephen Hanson 		hdlp->ahi_peekpoke_mutexp = &pcip->pci_peek_poke_mutex;
357837c1ac4SStephen Hanson 		hdlp->ahi_scan_dip = dip;
358837c1ac4SStephen Hanson 		hdlp->ahi_scan = pci_peekpoke_cb;
3599757e35cSStephen Hanson 	}
360837c1ac4SStephen Hanson 
3617c478bd9Sstevel@tonic-gate 	/*
3627c478bd9Sstevel@tonic-gate 	 * check for register number
3637c478bd9Sstevel@tonic-gate 	 */
3647c478bd9Sstevel@tonic-gate 	switch (mp->map_type) {
3657c478bd9Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
3667c478bd9Sstevel@tonic-gate 		pci_reg = *(pci_regspec_t *)(mp->map_obj.rp);
3677c478bd9Sstevel@tonic-gate 		pci_rp = &pci_reg;
36870025d76Sjohnny 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
3697c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3707c478bd9Sstevel@tonic-gate 		break;
3717c478bd9Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
3727c478bd9Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
3737c478bd9Sstevel@tonic-gate 		/*
3747c478bd9Sstevel@tonic-gate 		 * get ALL "reg" properties for dip, select the one of
3757c478bd9Sstevel@tonic-gate 		 * of interest. In x86, "assigned-addresses" property
3767c478bd9Sstevel@tonic-gate 		 * is identical to the "reg" property, so there is no
3777c478bd9Sstevel@tonic-gate 		 * need to cross check the two to determine the physical
3787c478bd9Sstevel@tonic-gate 		 * address of the registers.
3797c478bd9Sstevel@tonic-gate 		 * This routine still performs some validity checks to
3807c478bd9Sstevel@tonic-gate 		 * make sure that everything is okay.
3817c478bd9Sstevel@tonic-gate 		 */
38270025d76Sjohnny 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
383*1f0c5e61SRobert Mustacchi 		    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &nelems) !=
384*1f0c5e61SRobert Mustacchi 		    DDI_PROP_SUCCESS)
3857c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 		/*
3887c478bd9Sstevel@tonic-gate 		 * validate the register number.
3897c478bd9Sstevel@tonic-gate 		 */
390*1f0c5e61SRobert Mustacchi 		nelems /= (sizeof (pci_regspec_t) / sizeof (int));
391*1f0c5e61SRobert Mustacchi 		if (rnumber >= nelems) {
3927c478bd9Sstevel@tonic-gate 			ddi_prop_free(pci_rp);
3937c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3947c478bd9Sstevel@tonic-gate 		}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		/*
3977c478bd9Sstevel@tonic-gate 		 * copy the required entry.
3987c478bd9Sstevel@tonic-gate 		 */
3997c478bd9Sstevel@tonic-gate 		pci_reg = pci_rp[rnumber];
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 		/*
4027c478bd9Sstevel@tonic-gate 		 * free the memory allocated by ddi_prop_lookup_int_array
4037c478bd9Sstevel@tonic-gate 		 */
4047c478bd9Sstevel@tonic-gate 		ddi_prop_free(pci_rp);
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		pci_rp = &pci_reg;
40770025d76Sjohnny 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
4087c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4097c478bd9Sstevel@tonic-gate 		mp->map_type = DDI_MT_REGSPEC;
4107c478bd9Sstevel@tonic-gate 		break;
4117c478bd9Sstevel@tonic-gate 	default:
4127c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/*
4187c478bd9Sstevel@tonic-gate 	 * check for unmap and unlock of address space
4197c478bd9Sstevel@tonic-gate 	 */
4207c478bd9Sstevel@tonic-gate 	if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
4217c478bd9Sstevel@tonic-gate 		switch (space) {
4227c478bd9Sstevel@tonic-gate 		case PCI_ADDR_CONFIG:
4237c478bd9Sstevel@tonic-gate 			/* No work required on unmap of Config space */
4247c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		case PCI_ADDR_IO:
4277c478bd9Sstevel@tonic-gate 			reg.regspec_bustype = 1;
4287c478bd9Sstevel@tonic-gate 			break;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 		case PCI_ADDR_MEM64:
4317c478bd9Sstevel@tonic-gate 		case PCI_ADDR_MEM32:
4327c478bd9Sstevel@tonic-gate 			reg.regspec_bustype = 0;
4337c478bd9Sstevel@tonic-gate 			break;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		default:
4367c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 
439*1f0c5e61SRobert Mustacchi 		reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 |
440*1f0c5e61SRobert Mustacchi 		    (uint64_t)pci_rp->pci_phys_low;
441*1f0c5e61SRobert Mustacchi 		reg.regspec_size = (uint64_t)pci_rp->pci_size_hi << 32 |
442*1f0c5e61SRobert Mustacchi 		    (uint64_t)pci_rp->pci_size_low;
443*1f0c5e61SRobert Mustacchi 
444*1f0c5e61SRobert Mustacchi 		/*
445*1f0c5e61SRobert Mustacchi 		 * Adjust offset and length
446*1f0c5e61SRobert Mustacchi 		 * A non-zero length means override the one in the regspec.
447*1f0c5e61SRobert Mustacchi 		 */
448*1f0c5e61SRobert Mustacchi 		if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset))
449*1f0c5e61SRobert Mustacchi 			return (DDI_FAILURE);
450*1f0c5e61SRobert Mustacchi 		reg.regspec_addr += offset;
451*1f0c5e61SRobert Mustacchi 		if (len != 0)
452*1f0c5e61SRobert Mustacchi 			reg.regspec_size = len;
453*1f0c5e61SRobert Mustacchi 
454*1f0c5e61SRobert Mustacchi 		mp->map_obj.rp = (struct regspec *)&reg;
455*1f0c5e61SRobert Mustacchi 		mp->map_flags |= DDI_MF_EXT_REGSPEC;
4567c478bd9Sstevel@tonic-gate 		return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/* check for user mapping request - not legal for Config */
4617c478bd9Sstevel@tonic-gate 	if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) {
4627c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/*
4667c478bd9Sstevel@tonic-gate 	 * check for config space
4677c478bd9Sstevel@tonic-gate 	 * On x86, CONFIG is not mapped via MMU and there is
4687c478bd9Sstevel@tonic-gate 	 * no endian-ness issues. Set the attr field in the handle to
4697c478bd9Sstevel@tonic-gate 	 * indicate that the common routines to call the nexus driver.
4707c478bd9Sstevel@tonic-gate 	 */
4717c478bd9Sstevel@tonic-gate 	if (space == PCI_ADDR_CONFIG) {
4727c478bd9Sstevel@tonic-gate 		/* Can't map config space without a handle */
47300d0963fSdilpreet 		hp = (ddi_acc_hdl_t *)mp->map_handlep;
47470025d76Sjohnny 		if (hp == NULL)
4757c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		/* record the device address for future reference */
4787c478bd9Sstevel@tonic-gate 		cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private;
4797c478bd9Sstevel@tonic-gate 		cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
4807c478bd9Sstevel@tonic-gate 		cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
4817c478bd9Sstevel@tonic-gate 		cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
4827c478bd9Sstevel@tonic-gate 
48300d0963fSdilpreet 		*vaddrp = (caddr_t)offset;
48400d0963fSdilpreet 		return (pci_fm_acc_setup(hp, offset, len));
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/*
4887c478bd9Sstevel@tonic-gate 	 * range check
4897c478bd9Sstevel@tonic-gate 	 */
490*1f0c5e61SRobert Mustacchi 	pci_rlength = (uint64_t)pci_rp->pci_size_low |
491*1f0c5e61SRobert Mustacchi 	    (uint64_t)pci_rp->pci_size_hi << 32;
492*1f0c5e61SRobert Mustacchi 	if ((offset >= pci_rlength) || (len > pci_rlength) ||
493*1f0c5e61SRobert Mustacchi 	    (offset + len > pci_rlength) || (offset + len < MAX(offset, len))) {
4947c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	 * convert the pci regsec into the generic regspec used by the
4997c478bd9Sstevel@tonic-gate 	 * parent root nexus driver.
5007c478bd9Sstevel@tonic-gate 	 */
5017c478bd9Sstevel@tonic-gate 	switch (space) {
5027c478bd9Sstevel@tonic-gate 	case PCI_ADDR_IO:
5037c478bd9Sstevel@tonic-gate 		reg.regspec_bustype = 1;
5047c478bd9Sstevel@tonic-gate 		break;
5057c478bd9Sstevel@tonic-gate 	case PCI_ADDR_MEM64:
5067c478bd9Sstevel@tonic-gate 	case PCI_ADDR_MEM32:
5077c478bd9Sstevel@tonic-gate 		reg.regspec_bustype = 0;
5087c478bd9Sstevel@tonic-gate 		break;
5097c478bd9Sstevel@tonic-gate 	default:
5107c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
513*1f0c5e61SRobert Mustacchi 	reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 |
514*1f0c5e61SRobert Mustacchi 	    (uint64_t)pci_rp->pci_phys_low;
515*1f0c5e61SRobert Mustacchi 	reg.regspec_size = pci_rlength;
516*1f0c5e61SRobert Mustacchi 
517*1f0c5e61SRobert Mustacchi 	/*
518*1f0c5e61SRobert Mustacchi 	 * Adjust offset and length
519*1f0c5e61SRobert Mustacchi 	 * A non-zero length means override the one in the regspec.
520*1f0c5e61SRobert Mustacchi 	 */
521*1f0c5e61SRobert Mustacchi 	if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset))
522*1f0c5e61SRobert Mustacchi 		return (DDI_FAILURE);
523*1f0c5e61SRobert Mustacchi 	reg.regspec_addr += offset;
524*1f0c5e61SRobert Mustacchi 	if (len != 0)
525*1f0c5e61SRobert Mustacchi 		reg.regspec_size = len;
526*1f0c5e61SRobert Mustacchi 
527*1f0c5e61SRobert Mustacchi 	mp->map_obj.rp = (struct regspec *)&reg;
528*1f0c5e61SRobert Mustacchi 	mp->map_flags |= DDI_MF_EXT_REGSPEC;
5297c478bd9Sstevel@tonic-gate 	return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5347c478bd9Sstevel@tonic-gate static int
pci_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)5357c478bd9Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
5367c478bd9Sstevel@tonic-gate     ddi_ctl_enum_t ctlop, void *arg, void *result)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	pci_regspec_t *drv_regp;
5397c478bd9Sstevel@tonic-gate 	uint_t	reglen;
5407c478bd9Sstevel@tonic-gate 	int	totreg;
54100d0963fSdilpreet 	pci_state_t *pcip;
5422df1fe9cSrandyf 	struct  attachspec *asp;
5432c2d21e9SRichard Lowe 	struct  detachspec *dsp;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	switch (ctlop) {
5467c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
5477c478bd9Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
5487c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5497c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
5507c478bd9Sstevel@tonic-gate 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
5517c478bd9Sstevel@tonic-gate 		    ddi_driver_name(rdip),
5527c478bd9Sstevel@tonic-gate 		    ddi_get_instance(rdip));
5537c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
5567c478bd9Sstevel@tonic-gate 		return (pci_initchild((dev_info_t *)arg));
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
5597c478bd9Sstevel@tonic-gate 		return (pci_removechild((dev_info_t *)arg));
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
5627c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
5657c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
5667c478bd9Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
5677c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		*(int *)result = 0;
5707c478bd9Sstevel@tonic-gate 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
5717c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
5727c478bd9Sstevel@tonic-gate 		    &reglen) != DDI_PROP_SUCCESS) {
5737c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5747c478bd9Sstevel@tonic-gate 		}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t);
5777c478bd9Sstevel@tonic-gate 		if (ctlop == DDI_CTLOPS_NREGS)
5787c478bd9Sstevel@tonic-gate 			*(int *)result = totreg;
5797c478bd9Sstevel@tonic-gate 		else if (ctlop == DDI_CTLOPS_REGSIZE) {
580*1f0c5e61SRobert Mustacchi 			uint64_t val;
581*1f0c5e61SRobert Mustacchi 			int rn;
582*1f0c5e61SRobert Mustacchi 
5837c478bd9Sstevel@tonic-gate 			rn = *(int *)arg;
5847c478bd9Sstevel@tonic-gate 			if (rn >= totreg) {
5857c478bd9Sstevel@tonic-gate 				ddi_prop_free(drv_regp);
5867c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
5877c478bd9Sstevel@tonic-gate 			}
588*1f0c5e61SRobert Mustacchi 			val = drv_regp[rn].pci_size_low |
589*1f0c5e61SRobert Mustacchi 			    (uint64_t)drv_regp[rn].pci_size_hi << 32;
590*1f0c5e61SRobert Mustacchi 			if (val > OFF_MAX) {
591*1f0c5e61SRobert Mustacchi 				int ce = CE_NOTE;
592*1f0c5e61SRobert Mustacchi #ifdef DEBUG
593*1f0c5e61SRobert Mustacchi 				ce = CE_WARN;
594*1f0c5e61SRobert Mustacchi #endif
595*1f0c5e61SRobert Mustacchi 				dev_err(rdip, ce, "failed to get register "
596*1f0c5e61SRobert Mustacchi 				    "size, value larger than OFF_MAX: 0x%"
597*1f0c5e61SRobert Mustacchi 				    PRIx64 "\n", val);
598*1f0c5e61SRobert Mustacchi 				return (DDI_FAILURE);
599*1f0c5e61SRobert Mustacchi 			}
600*1f0c5e61SRobert Mustacchi 			*(off_t *)result = (off_t)val;
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 		ddi_prop_free(drv_regp);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POWER: {
6077c478bd9Sstevel@tonic-gate 		power_req_t	*reqp = (power_req_t *)arg;
6087c478bd9Sstevel@tonic-gate 		/*
6097c478bd9Sstevel@tonic-gate 		 * We currently understand reporting of PCI_PM_IDLESPEED
6107c478bd9Sstevel@tonic-gate 		 * capability. Everything else is passed up.
6117c478bd9Sstevel@tonic-gate 		 */
6127c478bd9Sstevel@tonic-gate 		if ((reqp->request_type == PMR_REPORT_PMCAP) &&
6137c478bd9Sstevel@tonic-gate 		    (reqp->req.report_pmcap_req.cap ==  PCI_PM_IDLESPEED)) {
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
62000d0963fSdilpreet 	case DDI_CTLOPS_PEEK:
62100d0963fSdilpreet 	case DDI_CTLOPS_POKE:
62200d0963fSdilpreet 		pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip));
62300d0963fSdilpreet 		return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
62400d0963fSdilpreet 		    pci_common_peekpoke, &pcip->pci_err_mutex,
625eae2e508Skrishnae 		    &pcip->pci_peek_poke_mutex, pci_peekpoke_cb));
62600d0963fSdilpreet 
6272df1fe9cSrandyf 	/* for now only X86 systems support PME wakeup from suspended state */
6282df1fe9cSrandyf 	case DDI_CTLOPS_ATTACH:
6292df1fe9cSrandyf 		asp = (struct attachspec *)arg;
6302df1fe9cSrandyf 		if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE)
6312df1fe9cSrandyf 			if (pci_pre_resume(rdip) != DDI_SUCCESS)
6322df1fe9cSrandyf 				return (DDI_FAILURE);
6332df1fe9cSrandyf 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
6342df1fe9cSrandyf 
6352df1fe9cSrandyf 	case DDI_CTLOPS_DETACH:
6362c2d21e9SRichard Lowe 		dsp = (struct detachspec *)arg;
6372c2d21e9SRichard Lowe 		if (dsp->cmd == DDI_SUSPEND && dsp->when == DDI_POST)
6382df1fe9cSrandyf 			if (pci_post_suspend(rdip) != DDI_SUCCESS)
6392df1fe9cSrandyf 				return (DDI_FAILURE);
6402df1fe9cSrandyf 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
6412df1fe9cSrandyf 
6427c478bd9Sstevel@tonic-gate 	default:
6437c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate /*
65170025d76Sjohnny  * pci_intr_ops
6527c478bd9Sstevel@tonic-gate  */
6537c478bd9Sstevel@tonic-gate static int
pci_intr_ops(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)65470025d76Sjohnny pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
65570025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
6567c478bd9Sstevel@tonic-gate {
65770025d76Sjohnny 	return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result));
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate static int
pci_initchild(dev_info_t * child)6627c478bd9Sstevel@tonic-gate pci_initchild(dev_info_t *child)
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate 	char name[80];
665c11e1991Smyers 	ddi_acc_handle_t config_handle;
666c11e1991Smyers 	ushort_t command_preserve, command;
6677c478bd9Sstevel@tonic-gate 
66870025d76Sjohnny 	if (pci_common_name_child(child, name, 80) != DDI_SUCCESS) {
6697c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * Pseudo nodes indicate a prototype node with per-instance
6757c478bd9Sstevel@tonic-gate 	 * properties to be merged into the real h/w device node.
6767c478bd9Sstevel@tonic-gate 	 * The interpretation of the unit-address is DD[,F]
6777c478bd9Sstevel@tonic-gate 	 * where DD is the device id and F is the function.
6787c478bd9Sstevel@tonic-gate 	 */
6797c478bd9Sstevel@tonic-gate 	if (ndi_dev_is_persistent_node(child) == 0) {
6807c478bd9Sstevel@tonic-gate 		extern int pci_allow_pseudo_children;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 		/*
6857c478bd9Sstevel@tonic-gate 		 * Try to merge the properties from this prototype
6867c478bd9Sstevel@tonic-gate 		 * node into real h/w nodes.
6877c478bd9Sstevel@tonic-gate 		 */
68870025d76Sjohnny 		if (ndi_merge_node(child, pci_common_name_child) ==
68970025d76Sjohnny 		    DDI_SUCCESS) {
6907c478bd9Sstevel@tonic-gate 			/*
6917c478bd9Sstevel@tonic-gate 			 * Merged ok - return failure to remove the node.
6927c478bd9Sstevel@tonic-gate 			 */
6937c478bd9Sstevel@tonic-gate 			ddi_set_name_addr(child, NULL);
6947c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6957c478bd9Sstevel@tonic-gate 		}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 		/* workaround for ddivs to run under PCI */
6987c478bd9Sstevel@tonic-gate 		if (pci_allow_pseudo_children) {
6997c478bd9Sstevel@tonic-gate 			/*
7007c478bd9Sstevel@tonic-gate 			 * If the "interrupts" property doesn't exist,
7017c478bd9Sstevel@tonic-gate 			 * this must be the ddivs no-intr case, and it returns
7027c478bd9Sstevel@tonic-gate 			 * DDI_SUCCESS instead of DDI_FAILURE.
7037c478bd9Sstevel@tonic-gate 			 */
7047c478bd9Sstevel@tonic-gate 			if (ddi_prop_get_int(DDI_DEV_T_ANY, child,
7057c478bd9Sstevel@tonic-gate 			    DDI_PROP_DONTPASS, "interrupts", -1) == -1)
7067c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
7077c478bd9Sstevel@tonic-gate 			/*
7087c478bd9Sstevel@tonic-gate 			 * Create the ddi_parent_private_data for a pseudo
7097c478bd9Sstevel@tonic-gate 			 * child.
7107c478bd9Sstevel@tonic-gate 			 */
71170025d76Sjohnny 			pci_common_set_parent_private_data(child);
7127c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
7137c478bd9Sstevel@tonic-gate 		}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 		/*
7167c478bd9Sstevel@tonic-gate 		 * The child was not merged into a h/w node,
7177c478bd9Sstevel@tonic-gate 		 * but there's not much we can do with it other
7187c478bd9Sstevel@tonic-gate 		 * than return failure to cause the node to be removed.
7197c478bd9Sstevel@tonic-gate 		 */
7207c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
7217c478bd9Sstevel@tonic-gate 		    ddi_get_name(child), ddi_get_name_addr(child),
7227c478bd9Sstevel@tonic-gate 		    ddi_get_name(child));
7237c478bd9Sstevel@tonic-gate 		ddi_set_name_addr(child, NULL);
7247c478bd9Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
7257c478bd9Sstevel@tonic-gate 	}
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
72870025d76Sjohnny 	    "interrupts", -1) != -1)
72970025d76Sjohnny 		pci_common_set_parent_private_data(child);
73070025d76Sjohnny 	else
7317c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
7327c478bd9Sstevel@tonic-gate 
733c11e1991Smyers 	/*
734c11e1991Smyers 	 * initialize command register
735c11e1991Smyers 	 */
736c11e1991Smyers 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
737c11e1991Smyers 		return (DDI_FAILURE);
738c11e1991Smyers 
739c11e1991Smyers 	/*
740c11e1991Smyers 	 * Support for the "command-preserve" property.
741c11e1991Smyers 	 */
742c11e1991Smyers 	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
7432df1fe9cSrandyf 	    DDI_PROP_DONTPASS, "command-preserve", 0);
744c11e1991Smyers 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
745c11e1991Smyers 	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
746c11e1991Smyers 	command |= (pci_command_default & ~command_preserve);
747c11e1991Smyers 	pci_config_put16(config_handle, PCI_CONF_COMM, command);
748c11e1991Smyers 
749c11e1991Smyers 	pci_config_teardown(&config_handle);
7507c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7517c478bd9Sstevel@tonic-gate }
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate static int
pci_removechild(dev_info_t * dip)7547c478bd9Sstevel@tonic-gate pci_removechild(dev_info_t *dip)
7557c478bd9Sstevel@tonic-gate {
7567c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
7597c478bd9Sstevel@tonic-gate 		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
7607c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(dip, NULL);
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(dip, NULL);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	/*
7657c478bd9Sstevel@tonic-gate 	 * Strip the node to properly convert it back to prototype form
7667c478bd9Sstevel@tonic-gate 	 */
7677c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	impl_rem_dev_props(dip);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate  * When retrofitting this module for pci_tools, functions such as open, close,
7777c478bd9Sstevel@tonic-gate  * and ioctl are now pulled into this module.  Before this, the functions in
7787c478bd9Sstevel@tonic-gate  * the pcihp module were referenced directly.  Now they are called or
7797c478bd9Sstevel@tonic-gate  * referenced through the pcihp cb_ops structure from functions in this module.
7807c478bd9Sstevel@tonic-gate  */
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate static int
pci_open(dev_t * devp,int flags,int otyp,cred_t * credp)7837c478bd9Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
7847c478bd9Sstevel@tonic-gate {
78570025d76Sjohnny 	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate static int
pci_close(dev_t dev,int flags,int otyp,cred_t * credp)7897c478bd9Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp)
7907c478bd9Sstevel@tonic-gate {
79170025d76Sjohnny 	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate static int
pci_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)79570025d76Sjohnny pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
7967c478bd9Sstevel@tonic-gate {
7977851eb82Sschwartz 	minor_t		minor = getminor(dev);
79826947304SEvan Yan 	int		instance = PCI_MINOR_NUM_TO_INSTANCE(minor);
799d4476ccbSschwartz 	pci_state_t	*pci_p = ddi_get_soft_state(pci_statep, instance);
80026947304SEvan Yan 	int		ret = ENOTTY;
8017c478bd9Sstevel@tonic-gate 
80270025d76Sjohnny 	if (pci_p == NULL)
80370025d76Sjohnny 		return (ENXIO);
8047851eb82Sschwartz 
80526947304SEvan Yan 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
80626947304SEvan Yan 	case PCI_TOOL_REG_MINOR_NUM:
80726947304SEvan Yan 	case PCI_TOOL_INTR_MINOR_NUM:
80826947304SEvan Yan 		/* To handle pcitool related ioctls */
80926947304SEvan Yan 		ret =  pci_common_ioctl(pci_p->pci_dip, dev, cmd, arg, mode,
81026947304SEvan Yan 		    credp, rvalp);
81126947304SEvan Yan 		break;
81226947304SEvan Yan 	default:
81326947304SEvan Yan 		/* To handle devctl and hotplug related ioctls */
81426947304SEvan Yan 		ret = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
81526947304SEvan Yan 		    credp, rvalp);
81626947304SEvan Yan 		break;
81726947304SEvan Yan 	}
81826947304SEvan Yan 
81926947304SEvan Yan 	return (ret);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static int
pci_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)8247c478bd9Sstevel@tonic-gate pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
8257c478bd9Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp)
8267c478bd9Sstevel@tonic-gate {
82770025d76Sjohnny 	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
8287c478bd9Sstevel@tonic-gate 	    name, valuep, lengthp));
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate static int
pci_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)8327c478bd9Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	return (pcihp_info(dip, cmd, arg, result));
8357c478bd9Sstevel@tonic-gate }
83600d0963fSdilpreet 
pci_peekpoke_cb(dev_info_t * dip,ddi_fm_error_t * derr)837eae2e508Skrishnae void pci_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
838eae2e508Skrishnae 	(void) pci_ereport_post(dip, derr, NULL);
839eae2e508Skrishnae }
840eae2e508Skrishnae 
84100d0963fSdilpreet /*ARGSUSED*/
84200d0963fSdilpreet static int
pci_fm_init(dev_info_t * dip,dev_info_t * tdip,int cap,ddi_iblock_cookie_t * ibc)84300d0963fSdilpreet pci_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
84400d0963fSdilpreet     ddi_iblock_cookie_t *ibc)
84500d0963fSdilpreet {
84600d0963fSdilpreet 	pci_state_t  *pcip = ddi_get_soft_state(pci_statep,
84700d0963fSdilpreet 	    ddi_get_instance(dip));
84800d0963fSdilpreet 
84900d0963fSdilpreet 	ASSERT(ibc != NULL);
85000d0963fSdilpreet 	*ibc = pcip->pci_fm_ibc;
85100d0963fSdilpreet 
85200d0963fSdilpreet 	return (pcip->pci_fmcap);
85300d0963fSdilpreet }
85400d0963fSdilpreet 
85500d0963fSdilpreet /*ARGSUSED*/
85600d0963fSdilpreet static int
pci_fm_callback(dev_info_t * dip,ddi_fm_error_t * derr,const void * no_used)85700d0963fSdilpreet pci_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
85800d0963fSdilpreet {
85900d0963fSdilpreet 	pci_state_t  *pcip = ddi_get_soft_state(pci_statep,
86000d0963fSdilpreet 	    ddi_get_instance(dip));
86100d0963fSdilpreet 
86200d0963fSdilpreet 	mutex_enter(&pcip->pci_err_mutex);
86300d0963fSdilpreet 	pci_ereport_post(dip, derr, NULL);
86400d0963fSdilpreet 	mutex_exit(&pcip->pci_err_mutex);
86500d0963fSdilpreet 	return (derr->fme_status);
86600d0963fSdilpreet }
867