xref: /illumos-gate/usr/src/uts/sun4u/opl/io/pcicmu/pcicmu.c (revision 19397407)
125cf1a30Sjl /*
225cf1a30Sjl  * CDDL HEADER START
325cf1a30Sjl  *
425cf1a30Sjl  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
725cf1a30Sjl  *
825cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl  * See the License for the specific language governing permissions
1125cf1a30Sjl  * and limitations under the License.
1225cf1a30Sjl  *
1325cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl  *
1925cf1a30Sjl  * CDDL HEADER END
2025cf1a30Sjl  */
2125cf1a30Sjl /*
22*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2325cf1a30Sjl  * Use is subject to license terms.
2425cf1a30Sjl  */
2525cf1a30Sjl 
2625cf1a30Sjl 
2725cf1a30Sjl /*
2825cf1a30Sjl  * OPL CMU-CH PCI nexus driver.
2925cf1a30Sjl  *
3025cf1a30Sjl  */
3125cf1a30Sjl 
3225cf1a30Sjl #include <sys/types.h>
3325cf1a30Sjl #include <sys/sysmacros.h>
3425cf1a30Sjl #include <sys/systm.h>
3525cf1a30Sjl #include <sys/intreg.h>
3625cf1a30Sjl #include <sys/intr.h>
3725cf1a30Sjl #include <sys/machsystm.h>
3825cf1a30Sjl #include <sys/conf.h>
3925cf1a30Sjl #include <sys/stat.h>
4025cf1a30Sjl #include <sys/kmem.h>
4125cf1a30Sjl #include <sys/async.h>
4225cf1a30Sjl #include <sys/ivintr.h>
4325cf1a30Sjl #include <sys/sunddi.h>
4425cf1a30Sjl #include <sys/sunndi.h>
4525cf1a30Sjl #include <sys/ndifm.h>
4625cf1a30Sjl #include <sys/ontrap.h>
4725cf1a30Sjl #include <sys/ddi_impldefs.h>
4825cf1a30Sjl #include <sys/ddi_subrdefs.h>
4925cf1a30Sjl #include <sys/epm.h>
5025cf1a30Sjl #include <sys/spl.h>
5125cf1a30Sjl #include <sys/fm/util.h>
5225cf1a30Sjl #include <sys/fm/util.h>
5325cf1a30Sjl #include <sys/fm/protocol.h>
5425cf1a30Sjl #include <sys/fm/io/pci.h>
5525cf1a30Sjl #include <sys/fm/io/sun4upci.h>
5625cf1a30Sjl #include <sys/pcicmu/pcicmu.h>
5725cf1a30Sjl 
5825cf1a30Sjl #include <sys/cmn_err.h>
5925cf1a30Sjl #include <sys/time.h>
6025cf1a30Sjl #include <sys/pci.h>
6125cf1a30Sjl #include <sys/modctl.h>
6225cf1a30Sjl #include <sys/open.h>
6325cf1a30Sjl #include <sys/errno.h>
6425cf1a30Sjl #include <sys/file.h>
6525cf1a30Sjl 
6625cf1a30Sjl 
6725cf1a30Sjl uint32_t pcmu_spurintr_duration = 60000000; /* One minute */
6825cf1a30Sjl 
6925cf1a30Sjl /*
7025cf1a30Sjl  * The variable controls the default setting of the command register
7125cf1a30Sjl  * for pci devices.  See pcmu_init_child() for details.
7225cf1a30Sjl  *
7325cf1a30Sjl  * This flags also controls the setting of bits in the bridge control
7425cf1a30Sjl  * register pci to pci bridges.  See pcmu_init_child() for details.
7525cf1a30Sjl  */
7625cf1a30Sjl ushort_t pcmu_command_default = PCI_COMM_SERR_ENABLE |
7725cf1a30Sjl 				PCI_COMM_WAIT_CYC_ENAB |
7825cf1a30Sjl 				PCI_COMM_PARITY_DETECT |
7925cf1a30Sjl 				PCI_COMM_ME |
8025cf1a30Sjl 				PCI_COMM_MAE |
8125cf1a30Sjl 				PCI_COMM_IO;
8225cf1a30Sjl /*
8325cf1a30Sjl  * The following driver parameters are defined as variables to allow
8425cf1a30Sjl  * patching for debugging and tuning.  Flags that can be set on a per
8525cf1a30Sjl  * PBM basis are bit fields where the PBM device instance number maps
8625cf1a30Sjl  * to the bit position.
8725cf1a30Sjl  */
8825cf1a30Sjl #ifdef DEBUG
8925cf1a30Sjl uint64_t pcmu_debug_flags = 0;
9025cf1a30Sjl #endif
9125cf1a30Sjl uint_t ecc_error_intr_enable = 1;
9225cf1a30Sjl 
9325cf1a30Sjl uint_t pcmu_ecc_afsr_retries = 100;	/* XXX - what's a good value? */
9425cf1a30Sjl 
9525cf1a30Sjl uint_t pcmu_intr_retry_intv = 5;	/* for interrupt retry reg */
9625cf1a30Sjl uint_t pcmu_panic_on_fatal_errors = 1;	/* should be 1 at beta */
9725cf1a30Sjl 
9825cf1a30Sjl hrtime_t pcmu_intrpend_timeout = 5ll * NANOSEC;	/* 5 seconds in nanoseconds */
9925cf1a30Sjl 
10025cf1a30Sjl uint64_t pcmu_errtrig_pa = 0x0;
10125cf1a30Sjl 
10225cf1a30Sjl 
10325cf1a30Sjl /*
10425cf1a30Sjl  * The following value is the number of consecutive unclaimed interrupts that
10525cf1a30Sjl  * will be tolerated for a particular ino_p before the interrupt is deemed to
10625cf1a30Sjl  * be jabbering and is blocked.
10725cf1a30Sjl  */
10825cf1a30Sjl uint_t pcmu_unclaimed_intr_max = 20;
10925cf1a30Sjl 
11025cf1a30Sjl /*
11125cf1a30Sjl  * function prototypes for dev ops routines:
11225cf1a30Sjl  */
11325cf1a30Sjl static int pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
11425cf1a30Sjl static int pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
11525cf1a30Sjl static int pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
11625cf1a30Sjl     void *arg, void **result);
11725cf1a30Sjl static int pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp);
11825cf1a30Sjl static int pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp);
11925cf1a30Sjl static int pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
12025cf1a30Sjl 						cred_t *credp, int *rvalp);
12125cf1a30Sjl static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
12225cf1a30Sjl     int flags, char *name, caddr_t valuep, int *lengthp);
12325cf1a30Sjl static int pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args);
12425cf1a30Sjl static int pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args,
12525cf1a30Sjl     void *result);
12625cf1a30Sjl 
12725cf1a30Sjl static int map_pcmu_registers(pcmu_t *, dev_info_t *);
12825cf1a30Sjl static void unmap_pcmu_registers(pcmu_t *);
12925cf1a30Sjl static void pcmu_pbm_clear_error(pcmu_pbm_t *);
13025cf1a30Sjl 
13125cf1a30Sjl static int pcmu_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
13225cf1a30Sjl     void *, void *);
13325cf1a30Sjl static int pcmu_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
13425cf1a30Sjl     off_t, off_t, caddr_t *);
13525cf1a30Sjl static int pcmu_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
13625cf1a30Sjl     ddi_intr_handle_impl_t *, void *);
13725cf1a30Sjl 
13825cf1a30Sjl static uint32_t pcmu_identity_init(pcmu_t *pcmu_p);
13925cf1a30Sjl static int pcmu_intr_setup(pcmu_t *pcmu_p);
14025cf1a30Sjl static void pcmu_pbm_errstate_get(pcmu_t *pcmu_p,
14125cf1a30Sjl     pcmu_pbm_errstate_t *pbm_err_p);
14225cf1a30Sjl static int pcmu_obj_setup(pcmu_t *pcmu_p);
14325cf1a30Sjl static void pcmu_obj_destroy(pcmu_t *pcmu_p);
14425cf1a30Sjl static void pcmu_obj_resume(pcmu_t *pcmu_p);
14525cf1a30Sjl static void pcmu_obj_suspend(pcmu_t *pcmu_p);
14625cf1a30Sjl 
14725cf1a30Sjl static void u2u_ittrans_init(pcmu_t *, u2u_ittrans_data_t **);
14825cf1a30Sjl static void u2u_ittrans_resume(u2u_ittrans_data_t **);
14925cf1a30Sjl static void u2u_ittrans_uninit(u2u_ittrans_data_t *);
15025cf1a30Sjl 
15125cf1a30Sjl static pcmu_ksinfo_t	*pcmu_name_kstat;
15225cf1a30Sjl 
15325cf1a30Sjl /*
15425cf1a30Sjl  * bus ops and dev ops structures:
15525cf1a30Sjl  */
15625cf1a30Sjl static struct bus_ops pcmu_bus_ops = {
15725cf1a30Sjl 	BUSO_REV,
15825cf1a30Sjl 	pcmu_map,
15925cf1a30Sjl 	0,
16025cf1a30Sjl 	0,
16125cf1a30Sjl 	0,
16225cf1a30Sjl 	i_ddi_map_fault,
16325cf1a30Sjl 	0,
16425cf1a30Sjl 	0,
16525cf1a30Sjl 	0,
16625cf1a30Sjl 	0,
16725cf1a30Sjl 	0,
16825cf1a30Sjl 	0,
16925cf1a30Sjl 	0,
17025cf1a30Sjl 	0,
17125cf1a30Sjl 	pcmu_ctlops,
17225cf1a30Sjl 	ddi_bus_prop_op,
17325cf1a30Sjl 	ndi_busop_get_eventcookie,	/* (*bus_get_eventcookie)(); */
17425cf1a30Sjl 	ndi_busop_add_eventcall,	/* (*bus_add_eventcall)(); */
17525cf1a30Sjl 	ndi_busop_remove_eventcall,	/* (*bus_remove_eventcall)(); */
17625cf1a30Sjl 	ndi_post_event,			/* (*bus_post_event)(); */
17725cf1a30Sjl 	NULL,				/* (*bus_intr_ctl)(); */
17825cf1a30Sjl 	NULL,				/* (*bus_config)(); */
17925cf1a30Sjl 	NULL,				/* (*bus_unconfig)(); */
18025cf1a30Sjl 	NULL,				/* (*bus_fm_init)(); */
18125cf1a30Sjl 	NULL,				/* (*bus_fm_fini)(); */
18225cf1a30Sjl 	NULL,				/* (*bus_fm_access_enter)(); */
18325cf1a30Sjl 	NULL,				/* (*bus_fm_access_fini)(); */
18425cf1a30Sjl 	NULL,				/* (*bus_power)(); */
18525cf1a30Sjl 	pcmu_intr_ops			/* (*bus_intr_op)(); */
18625cf1a30Sjl };
18725cf1a30Sjl 
18825cf1a30Sjl struct cb_ops pcmu_cb_ops = {
18925cf1a30Sjl 	pcmu_open,			/* open */
19025cf1a30Sjl 	pcmu_close,			/* close */
19125cf1a30Sjl 	nodev,				/* strategy */
19225cf1a30Sjl 	nodev,				/* print */
19325cf1a30Sjl 	nodev,				/* dump */
19425cf1a30Sjl 	nodev,				/* read */
19525cf1a30Sjl 	nodev,				/* write */
19625cf1a30Sjl 	pcmu_ioctl,			/* ioctl */
19725cf1a30Sjl 	nodev,				/* devmap */
19825cf1a30Sjl 	nodev,				/* mmap */
19925cf1a30Sjl 	nodev,				/* segmap */
20025cf1a30Sjl 	nochpoll,			/* poll */
20125cf1a30Sjl 	pcmu_prop_op,			/* cb_prop_op */
20225cf1a30Sjl 	NULL,				/* streamtab */
20325cf1a30Sjl 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
20425cf1a30Sjl 	CB_REV,				/* rev */
20525cf1a30Sjl 	nodev,				/* int (*cb_aread)() */
20625cf1a30Sjl 	nodev				/* int (*cb_awrite)() */
20725cf1a30Sjl };
20825cf1a30Sjl 
20925cf1a30Sjl static struct dev_ops pcmu_ops = {
21025cf1a30Sjl 	DEVO_REV,
21125cf1a30Sjl 	0,
21225cf1a30Sjl 	pcmu_info,
21325cf1a30Sjl 	nulldev,
21425cf1a30Sjl 	0,
21525cf1a30Sjl 	pcmu_attach,
21625cf1a30Sjl 	pcmu_detach,
21725cf1a30Sjl 	nodev,
21825cf1a30Sjl 	&pcmu_cb_ops,
21925cf1a30Sjl 	&pcmu_bus_ops,
220*19397407SSherry Moore 	0,
221*19397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
222*19397407SSherry Moore 
22325cf1a30Sjl };
22425cf1a30Sjl 
22525cf1a30Sjl /*
22625cf1a30Sjl  * module definitions:
22725cf1a30Sjl  */
22825cf1a30Sjl extern struct mod_ops mod_driverops;
22925cf1a30Sjl 
23025cf1a30Sjl static struct modldrv modldrv = {
23125cf1a30Sjl 	&mod_driverops,				/* Type of module - driver */
232*19397407SSherry Moore 	"OPL CMU-CH PCI Nexus driver",	/* Name of module. */
23325cf1a30Sjl 	&pcmu_ops,				/* driver ops */
23425cf1a30Sjl };
23525cf1a30Sjl 
23625cf1a30Sjl static struct modlinkage modlinkage = {
23725cf1a30Sjl 	MODREV_1, (void *)&modldrv, NULL
23825cf1a30Sjl };
23925cf1a30Sjl 
24025cf1a30Sjl /*
24125cf1a30Sjl  * driver global data:
24225cf1a30Sjl  */
24325cf1a30Sjl void *per_pcmu_state;			/* per-pbm soft state pointer */
24425cf1a30Sjl kmutex_t pcmu_global_mutex;		/* attach/detach common struct lock */
24525cf1a30Sjl errorq_t *pcmu_ecc_queue = NULL;	/* per-system ecc handling queue */
24625cf1a30Sjl 
24725cf1a30Sjl extern void pcmu_child_cfg_save(dev_info_t *dip);
24825cf1a30Sjl extern void pcmu_child_cfg_restore(dev_info_t *dip);
24925cf1a30Sjl 
25025cf1a30Sjl int
_init(void)25125cf1a30Sjl _init(void)
25225cf1a30Sjl {
25325cf1a30Sjl 	int e;
25425cf1a30Sjl 
25525cf1a30Sjl 	/*
25625cf1a30Sjl 	 * Initialize per-pci bus soft state pointer.
25725cf1a30Sjl 	 */
25825cf1a30Sjl 	e = ddi_soft_state_init(&per_pcmu_state, sizeof (pcmu_t), 1);
25925cf1a30Sjl 	if (e != 0)
26025cf1a30Sjl 		return (e);
26125cf1a30Sjl 
26225cf1a30Sjl 	/*
26325cf1a30Sjl 	 * Initialize global mutexes.
26425cf1a30Sjl 	 */
26525cf1a30Sjl 	mutex_init(&pcmu_global_mutex, NULL, MUTEX_DRIVER, NULL);
26625cf1a30Sjl 
26725cf1a30Sjl 	/*
26825cf1a30Sjl 	 * Create the performance kstats.
26925cf1a30Sjl 	 */
27025cf1a30Sjl 	pcmu_kstat_init();
27125cf1a30Sjl 
27225cf1a30Sjl 	/*
27325cf1a30Sjl 	 * Install the module.
27425cf1a30Sjl 	 */
27525cf1a30Sjl 	e = mod_install(&modlinkage);
27625cf1a30Sjl 	if (e != 0) {
27725cf1a30Sjl 		ddi_soft_state_fini(&per_pcmu_state);
27825cf1a30Sjl 		mutex_destroy(&pcmu_global_mutex);
27925cf1a30Sjl 	}
28025cf1a30Sjl 	return (e);
28125cf1a30Sjl }
28225cf1a30Sjl 
28325cf1a30Sjl int
_fini(void)28425cf1a30Sjl _fini(void)
28525cf1a30Sjl {
28625cf1a30Sjl 	int e;
28725cf1a30Sjl 
28825cf1a30Sjl 	/*
28925cf1a30Sjl 	 * Remove the module.
29025cf1a30Sjl 	 */
29125cf1a30Sjl 	e = mod_remove(&modlinkage);
29225cf1a30Sjl 	if (e != 0) {
29325cf1a30Sjl 		return (e);
29425cf1a30Sjl 	}
29525cf1a30Sjl 
29625cf1a30Sjl 	/*
29725cf1a30Sjl 	 * Destroy pcmu_ecc_queue, and set it to NULL.
29825cf1a30Sjl 	 */
29925cf1a30Sjl 	if (pcmu_ecc_queue) {
30025cf1a30Sjl 		errorq_destroy(pcmu_ecc_queue);
30125cf1a30Sjl 		pcmu_ecc_queue = NULL;
30225cf1a30Sjl 	}
30325cf1a30Sjl 
30425cf1a30Sjl 	/*
30525cf1a30Sjl 	 * Destroy the performance kstats.
30625cf1a30Sjl 	 */
30725cf1a30Sjl 	pcmu_kstat_fini();
30825cf1a30Sjl 
30925cf1a30Sjl 	/*
31025cf1a30Sjl 	 * Free the per-pci and per-CMU-CH soft state info and destroy
31125cf1a30Sjl 	 * mutex for per-CMU-CH soft state.
31225cf1a30Sjl 	 */
31325cf1a30Sjl 	ddi_soft_state_fini(&per_pcmu_state);
31425cf1a30Sjl 	mutex_destroy(&pcmu_global_mutex);
31525cf1a30Sjl 	return (e);
31625cf1a30Sjl }
31725cf1a30Sjl 
31825cf1a30Sjl int
_info(struct modinfo * modinfop)31925cf1a30Sjl _info(struct modinfo *modinfop)
32025cf1a30Sjl {
32125cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
32225cf1a30Sjl }
32325cf1a30Sjl 
32425cf1a30Sjl /*ARGSUSED*/
32525cf1a30Sjl static int
pcmu_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)32625cf1a30Sjl pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
32725cf1a30Sjl {
32825cf1a30Sjl 	int	instance = getminor((dev_t)arg) >> 8;
32925cf1a30Sjl 	pcmu_t	*pcmu_p = get_pcmu_soft_state(instance);
33025cf1a30Sjl 
33125cf1a30Sjl 	switch (infocmd) {
33225cf1a30Sjl 	case DDI_INFO_DEVT2INSTANCE:
33325cf1a30Sjl 		*result = (void *)(uintptr_t)instance;
33425cf1a30Sjl 		return (DDI_SUCCESS);
33525cf1a30Sjl 
33625cf1a30Sjl 	case DDI_INFO_DEVT2DEVINFO:
33725cf1a30Sjl 		if (pcmu_p == NULL)
33825cf1a30Sjl 			return (DDI_FAILURE);
33925cf1a30Sjl 		*result = (void *)pcmu_p->pcmu_dip;
34025cf1a30Sjl 		return (DDI_SUCCESS);
34125cf1a30Sjl 
34225cf1a30Sjl 	default:
34325cf1a30Sjl 		return (DDI_FAILURE);
34425cf1a30Sjl 	}
34525cf1a30Sjl }
34625cf1a30Sjl 
34725cf1a30Sjl 
34825cf1a30Sjl /* device driver entry points */
34925cf1a30Sjl /*
35025cf1a30Sjl  * attach entry point:
35125cf1a30Sjl  */
35225cf1a30Sjl static int
pcmu_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)35325cf1a30Sjl pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
35425cf1a30Sjl {
35525cf1a30Sjl 	pcmu_t *pcmu_p;
35625cf1a30Sjl 	int instance = ddi_get_instance(dip);
35725cf1a30Sjl 
35825cf1a30Sjl 	switch (cmd) {
35925cf1a30Sjl 	case DDI_ATTACH:
36025cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_ATTACH\n");
36125cf1a30Sjl 
36225cf1a30Sjl 		/*
36325cf1a30Sjl 		 * Allocate and get the per-pci soft state structure.
36425cf1a30Sjl 		 */
36525cf1a30Sjl 		if (alloc_pcmu_soft_state(instance) != DDI_SUCCESS) {
36625cf1a30Sjl 			cmn_err(CE_WARN, "%s%d: can't allocate pci state",
36725cf1a30Sjl 			    ddi_driver_name(dip), instance);
36825cf1a30Sjl 			goto err_bad_pcmu_softstate;
36925cf1a30Sjl 		}
37025cf1a30Sjl 		pcmu_p = get_pcmu_soft_state(instance);
37125cf1a30Sjl 		pcmu_p->pcmu_dip = dip;
37225cf1a30Sjl 		mutex_init(&pcmu_p->pcmu_mutex, NULL, MUTEX_DRIVER, NULL);
37325cf1a30Sjl 		pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED;
37425cf1a30Sjl 		pcmu_p->pcmu_open_count = 0;
37525cf1a30Sjl 
37625cf1a30Sjl 		/*
37725cf1a30Sjl 		 * Get key properties of the pci bridge node.
37825cf1a30Sjl 		 */
37925cf1a30Sjl 		if (get_pcmu_properties(pcmu_p, dip) == DDI_FAILURE) {
38025cf1a30Sjl 			goto err_bad_pcmu_prop;
38125cf1a30Sjl 		}
38225cf1a30Sjl 
38325cf1a30Sjl 		/*
38425cf1a30Sjl 		 * Map in the registers.
38525cf1a30Sjl 		 */
38625cf1a30Sjl 		if (map_pcmu_registers(pcmu_p, dip) == DDI_FAILURE) {
38725cf1a30Sjl 			goto err_bad_reg_prop;
38825cf1a30Sjl 		}
38925cf1a30Sjl 		if (pcmu_obj_setup(pcmu_p) != DDI_SUCCESS) {
39025cf1a30Sjl 			goto err_bad_objs;
39125cf1a30Sjl 		}
39225cf1a30Sjl 
39325cf1a30Sjl 		if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
39425cf1a30Sjl 		    (uint_t)instance<<8 | 0xff,
39525cf1a30Sjl 		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
39625cf1a30Sjl 			goto err_bad_devctl_node;
39725cf1a30Sjl 		}
39825cf1a30Sjl 
39925cf1a30Sjl 		/*
40025cf1a30Sjl 		 * Due to unresolved hardware issues, disable PCIPM until
40125cf1a30Sjl 		 * the problem is fully understood.
40225cf1a30Sjl 		 *
40325cf1a30Sjl 		 * pcmu_pwr_setup(pcmu_p, dip);
40425cf1a30Sjl 		 */
40525cf1a30Sjl 
40625cf1a30Sjl 		ddi_report_dev(dip);
40725cf1a30Sjl 
40825cf1a30Sjl 		pcmu_p->pcmu_state = PCMU_ATTACHED;
40925cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "attach success\n");
41025cf1a30Sjl 		break;
41125cf1a30Sjl 
41225cf1a30Sjl err_bad_objs:
41325cf1a30Sjl 		ddi_remove_minor_node(dip, "devctl");
41425cf1a30Sjl err_bad_devctl_node:
41525cf1a30Sjl 		unmap_pcmu_registers(pcmu_p);
41625cf1a30Sjl err_bad_reg_prop:
41725cf1a30Sjl 		free_pcmu_properties(pcmu_p);
41825cf1a30Sjl err_bad_pcmu_prop:
41925cf1a30Sjl 		mutex_destroy(&pcmu_p->pcmu_mutex);
42025cf1a30Sjl 		free_pcmu_soft_state(instance);
42125cf1a30Sjl err_bad_pcmu_softstate:
42225cf1a30Sjl 		return (DDI_FAILURE);
42325cf1a30Sjl 
42425cf1a30Sjl 	case DDI_RESUME:
42525cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_RESUME\n");
42625cf1a30Sjl 
42725cf1a30Sjl 		/*
42825cf1a30Sjl 		 * Make sure the CMU-CH control registers
42925cf1a30Sjl 		 * are configured properly.
43025cf1a30Sjl 		 */
43125cf1a30Sjl 		pcmu_p = get_pcmu_soft_state(instance);
43225cf1a30Sjl 		mutex_enter(&pcmu_p->pcmu_mutex);
43325cf1a30Sjl 
43425cf1a30Sjl 		/*
43525cf1a30Sjl 		 * Make sure this instance has been suspended.
43625cf1a30Sjl 		 */
43725cf1a30Sjl 		if (pcmu_p->pcmu_state != PCMU_SUSPENDED) {
43825cf1a30Sjl 			PCMU_DBG0(PCMU_DBG_ATTACH, dip,
43925cf1a30Sjl 			    "instance NOT suspended\n");
44025cf1a30Sjl 			mutex_exit(&pcmu_p->pcmu_mutex);
44125cf1a30Sjl 			return (DDI_FAILURE);
44225cf1a30Sjl 		}
44325cf1a30Sjl 		pcmu_obj_resume(pcmu_p);
44425cf1a30Sjl 		pcmu_p->pcmu_state = PCMU_ATTACHED;
44525cf1a30Sjl 
44625cf1a30Sjl 		pcmu_child_cfg_restore(dip);
44725cf1a30Sjl 
44825cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
44925cf1a30Sjl 		break;
45025cf1a30Sjl 
45125cf1a30Sjl 	default:
45225cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "unsupported attach op\n");
45325cf1a30Sjl 		return (DDI_FAILURE);
45425cf1a30Sjl 	}
45525cf1a30Sjl 
45625cf1a30Sjl 	return (DDI_SUCCESS);
45725cf1a30Sjl }
45825cf1a30Sjl 
45925cf1a30Sjl /*
46025cf1a30Sjl  * detach entry point:
46125cf1a30Sjl  */
46225cf1a30Sjl static int
pcmu_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)46325cf1a30Sjl pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
46425cf1a30Sjl {
46525cf1a30Sjl 	int instance = ddi_get_instance(dip);
46625cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(instance);
46725cf1a30Sjl 	int len;
46825cf1a30Sjl 
46925cf1a30Sjl 	/*
47025cf1a30Sjl 	 * Make sure we are currently attached
47125cf1a30Sjl 	 */
47225cf1a30Sjl 	if (pcmu_p->pcmu_state != PCMU_ATTACHED) {
47325cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip,
47425cf1a30Sjl 		    "failed - instance not attached\n");
47525cf1a30Sjl 		return (DDI_FAILURE);
47625cf1a30Sjl 	}
47725cf1a30Sjl 
47825cf1a30Sjl 	mutex_enter(&pcmu_p->pcmu_mutex);
47925cf1a30Sjl 
48025cf1a30Sjl 	switch (cmd) {
48125cf1a30Sjl 	case DDI_DETACH:
48225cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_DETACH, dip, "DDI_DETACH\n");
48325cf1a30Sjl 		pcmu_obj_destroy(pcmu_p);
48425cf1a30Sjl 
48525cf1a30Sjl 		/*
48625cf1a30Sjl 		 * Free the pci soft state structure and the rest of the
48725cf1a30Sjl 		 * resources it's using.
48825cf1a30Sjl 		 */
48925cf1a30Sjl 		free_pcmu_properties(pcmu_p);
49025cf1a30Sjl 		unmap_pcmu_registers(pcmu_p);
49125cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
49225cf1a30Sjl 		mutex_destroy(&pcmu_p->pcmu_mutex);
49325cf1a30Sjl 		free_pcmu_soft_state(instance);
49425cf1a30Sjl 
49525cf1a30Sjl 		/* Free the interrupt-priorities prop if we created it. */
49625cf1a30Sjl 		if (ddi_getproplen(DDI_DEV_T_ANY, dip,
49725cf1a30Sjl 		    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
49825cf1a30Sjl 		    "interrupt-priorities", &len) == DDI_PROP_SUCCESS) {
49925cf1a30Sjl 			(void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
50025cf1a30Sjl 			    "interrupt-priorities");
50125cf1a30Sjl 		}
50225cf1a30Sjl 		return (DDI_SUCCESS);
50325cf1a30Sjl 
50425cf1a30Sjl 	case DDI_SUSPEND:
50525cf1a30Sjl 		pcmu_child_cfg_save(dip);
50625cf1a30Sjl 		pcmu_obj_suspend(pcmu_p);
50725cf1a30Sjl 		pcmu_p->pcmu_state = PCMU_SUSPENDED;
50825cf1a30Sjl 
50925cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
51025cf1a30Sjl 		return (DDI_SUCCESS);
51125cf1a30Sjl 
51225cf1a30Sjl 	default:
51325cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_DETACH, dip, "unsupported detach op\n");
51425cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
51525cf1a30Sjl 		return (DDI_FAILURE);
51625cf1a30Sjl 	}
51725cf1a30Sjl }
51825cf1a30Sjl 
51925cf1a30Sjl /* ARGSUSED3 */
52025cf1a30Sjl static int
pcmu_open(dev_t * devp,int flags,int otyp,cred_t * credp)52125cf1a30Sjl pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp)
52225cf1a30Sjl {
52325cf1a30Sjl 	pcmu_t *pcmu_p;
52425cf1a30Sjl 
52525cf1a30Sjl 	if (otyp != OTYP_CHR) {
52625cf1a30Sjl 		return (EINVAL);
52725cf1a30Sjl 	}
52825cf1a30Sjl 
52925cf1a30Sjl 	/*
53025cf1a30Sjl 	 * Get the soft state structure for the device.
53125cf1a30Sjl 	 */
53225cf1a30Sjl 	pcmu_p = DEV_TO_SOFTSTATE(*devp);
53325cf1a30Sjl 	if (pcmu_p == NULL) {
53425cf1a30Sjl 		return (ENXIO);
53525cf1a30Sjl 	}
53625cf1a30Sjl 
53725cf1a30Sjl 	/*
53825cf1a30Sjl 	 * Handle the open by tracking the device state.
53925cf1a30Sjl 	 */
54025cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_OPEN, pcmu_p->pcmu_dip,
54125cf1a30Sjl 	    "devp=%x: flags=%x\n", devp, flags);
54225cf1a30Sjl 	mutex_enter(&pcmu_p->pcmu_mutex);
54325cf1a30Sjl 	if (flags & FEXCL) {
54425cf1a30Sjl 		if (pcmu_p->pcmu_soft_state != PCMU_SOFT_STATE_CLOSED) {
54525cf1a30Sjl 			mutex_exit(&pcmu_p->pcmu_mutex);
54625cf1a30Sjl 			PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n");
54725cf1a30Sjl 			return (EBUSY);
54825cf1a30Sjl 		}
54925cf1a30Sjl 		pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN_EXCL;
55025cf1a30Sjl 	} else {
55125cf1a30Sjl 		if (pcmu_p->pcmu_soft_state == PCMU_SOFT_STATE_OPEN_EXCL) {
55225cf1a30Sjl 			mutex_exit(&pcmu_p->pcmu_mutex);
55325cf1a30Sjl 			PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n");
55425cf1a30Sjl 			return (EBUSY);
55525cf1a30Sjl 		}
55625cf1a30Sjl 		pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN;
55725cf1a30Sjl 	}
55825cf1a30Sjl 	pcmu_p->pcmu_open_count++;
55925cf1a30Sjl 	mutex_exit(&pcmu_p->pcmu_mutex);
56025cf1a30Sjl 	return (0);
56125cf1a30Sjl }
56225cf1a30Sjl 
56325cf1a30Sjl 
56425cf1a30Sjl /* ARGSUSED */
56525cf1a30Sjl static int
pcmu_close(dev_t dev,int flags,int otyp,cred_t * credp)56625cf1a30Sjl pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp)
56725cf1a30Sjl {
56825cf1a30Sjl 	pcmu_t *pcmu_p;
56925cf1a30Sjl 
57025cf1a30Sjl 	if (otyp != OTYP_CHR) {
57125cf1a30Sjl 		return (EINVAL);
57225cf1a30Sjl 	}
57325cf1a30Sjl 
57425cf1a30Sjl 	pcmu_p = DEV_TO_SOFTSTATE(dev);
57525cf1a30Sjl 	if (pcmu_p == NULL) {
57625cf1a30Sjl 		return (ENXIO);
57725cf1a30Sjl 	}
57825cf1a30Sjl 
57925cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_CLOSE, pcmu_p->pcmu_dip,
58025cf1a30Sjl 	    "dev=%x: flags=%x\n", dev, flags);
58125cf1a30Sjl 	mutex_enter(&pcmu_p->pcmu_mutex);
58225cf1a30Sjl 	pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED;
58325cf1a30Sjl 	pcmu_p->pcmu_open_count = 0;
58425cf1a30Sjl 	mutex_exit(&pcmu_p->pcmu_mutex);
58525cf1a30Sjl 	return (0);
58625cf1a30Sjl }
58725cf1a30Sjl 
58825cf1a30Sjl /* ARGSUSED */
58925cf1a30Sjl static int
pcmu_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)59025cf1a30Sjl pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
59125cf1a30Sjl     cred_t *credp, int *rvalp)
59225cf1a30Sjl {
59325cf1a30Sjl 	pcmu_t *pcmu_p;
59425cf1a30Sjl 	dev_info_t *dip;
59525cf1a30Sjl 	struct devctl_iocdata *dcp;
59625cf1a30Sjl 	uint_t bus_state;
59725cf1a30Sjl 	int rv = 0;
59825cf1a30Sjl 
59925cf1a30Sjl 	pcmu_p = DEV_TO_SOFTSTATE(dev);
60025cf1a30Sjl 	if (pcmu_p == NULL) {
60125cf1a30Sjl 		return (ENXIO);
60225cf1a30Sjl 	}
60325cf1a30Sjl 
60425cf1a30Sjl 	dip = pcmu_p->pcmu_dip;
60525cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
60625cf1a30Sjl 
60725cf1a30Sjl 	/*
60825cf1a30Sjl 	 * We can use the generic implementation for these ioctls
60925cf1a30Sjl 	 */
61025cf1a30Sjl 	switch (cmd) {
61125cf1a30Sjl 	case DEVCTL_DEVICE_GETSTATE:
61225cf1a30Sjl 	case DEVCTL_DEVICE_ONLINE:
61325cf1a30Sjl 	case DEVCTL_DEVICE_OFFLINE:
61425cf1a30Sjl 	case DEVCTL_BUS_GETSTATE:
61525cf1a30Sjl 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
61625cf1a30Sjl 	}
61725cf1a30Sjl 
61825cf1a30Sjl 	/*
61925cf1a30Sjl 	 * read devctl ioctl data
62025cf1a30Sjl 	 */
62125cf1a30Sjl 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
62225cf1a30Sjl 		return (EFAULT);
62325cf1a30Sjl 
62425cf1a30Sjl 	switch (cmd) {
62525cf1a30Sjl 
62625cf1a30Sjl 	case DEVCTL_DEVICE_RESET:
62725cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n");
62825cf1a30Sjl 		rv = ENOTSUP;
62925cf1a30Sjl 		break;
63025cf1a30Sjl 
63125cf1a30Sjl 
63225cf1a30Sjl 	case DEVCTL_BUS_QUIESCE:
63325cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n");
63425cf1a30Sjl 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) {
63525cf1a30Sjl 			if (bus_state == BUS_QUIESCED) {
63625cf1a30Sjl 				break;
63725cf1a30Sjl 			}
63825cf1a30Sjl 		}
63925cf1a30Sjl 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
64025cf1a30Sjl 		break;
64125cf1a30Sjl 
64225cf1a30Sjl 	case DEVCTL_BUS_UNQUIESCE:
64325cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n");
64425cf1a30Sjl 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) {
64525cf1a30Sjl 			if (bus_state == BUS_ACTIVE) {
64625cf1a30Sjl 				break;
64725cf1a30Sjl 			}
64825cf1a30Sjl 		}
64925cf1a30Sjl 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
65025cf1a30Sjl 		break;
65125cf1a30Sjl 
65225cf1a30Sjl 	case DEVCTL_BUS_RESET:
65325cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n");
65425cf1a30Sjl 		rv = ENOTSUP;
65525cf1a30Sjl 		break;
65625cf1a30Sjl 
65725cf1a30Sjl 	case DEVCTL_BUS_RESETALL:
65825cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n");
65925cf1a30Sjl 		rv = ENOTSUP;
66025cf1a30Sjl 		break;
66125cf1a30Sjl 
66225cf1a30Sjl 	default:
66325cf1a30Sjl 		rv = ENOTTY;
66425cf1a30Sjl 	}
66525cf1a30Sjl 
66625cf1a30Sjl 	ndi_dc_freehdl(dcp);
66725cf1a30Sjl 	return (rv);
66825cf1a30Sjl }
66925cf1a30Sjl 
pcmu_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)67025cf1a30Sjl static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
67125cf1a30Sjl     int flags, char *name, caddr_t valuep, int *lengthp)
67225cf1a30Sjl {
67325cf1a30Sjl 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
67425cf1a30Sjl }
67525cf1a30Sjl /* bus driver entry points */
67625cf1a30Sjl 
67725cf1a30Sjl /*
67825cf1a30Sjl  * bus map entry point:
67925cf1a30Sjl  *
68025cf1a30Sjl  *	if map request is for an rnumber
68125cf1a30Sjl  *		get the corresponding regspec from device node
68225cf1a30Sjl  *	build a new regspec in our parent's format
68325cf1a30Sjl  *	build a new map_req with the new regspec
68425cf1a30Sjl  *	call up the tree to complete the mapping
68525cf1a30Sjl  */
68625cf1a30Sjl static int
pcmu_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t off,off_t len,caddr_t * addrp)68725cf1a30Sjl pcmu_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
68825cf1a30Sjl 	off_t off, off_t len, caddr_t *addrp)
68925cf1a30Sjl {
69025cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
69125cf1a30Sjl 	struct regspec p_regspec;
69225cf1a30Sjl 	ddi_map_req_t p_mapreq;
69325cf1a30Sjl 	int reglen, rval, r_no;
69425cf1a30Sjl 	pci_regspec_t reloc_reg, *rp = &reloc_reg;
69525cf1a30Sjl 
69625cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_MAP, dip, "rdip=%s%d:",
69725cf1a30Sjl 	    ddi_driver_name(rdip), ddi_get_instance(rdip));
69825cf1a30Sjl 
69925cf1a30Sjl 	if (mp->map_flags & DDI_MF_USER_MAPPING) {
70025cf1a30Sjl 		return (DDI_ME_UNIMPLEMENTED);
70125cf1a30Sjl 	}
70225cf1a30Sjl 
70325cf1a30Sjl 	switch (mp->map_type) {
70425cf1a30Sjl 	case DDI_MT_REGSPEC:
70525cf1a30Sjl 		reloc_reg = *(pci_regspec_t *)mp->map_obj.rp;	/* dup whole */
70625cf1a30Sjl 		break;
70725cf1a30Sjl 
70825cf1a30Sjl 	case DDI_MT_RNUMBER:
70925cf1a30Sjl 		r_no = mp->map_obj.rnumber;
71025cf1a30Sjl 		PCMU_DBG1(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, " r#=%x", r_no);
71125cf1a30Sjl 
71225cf1a30Sjl 		if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS,
71325cf1a30Sjl 		    "reg", (caddr_t)&rp, &reglen) != DDI_SUCCESS) {
71425cf1a30Sjl 			return (DDI_ME_RNUMBER_RANGE);
71525cf1a30Sjl 		}
71625cf1a30Sjl 
71725cf1a30Sjl 		if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) {
71825cf1a30Sjl 			kmem_free(rp, reglen);
71925cf1a30Sjl 			return (DDI_ME_RNUMBER_RANGE);
72025cf1a30Sjl 		}
72125cf1a30Sjl 		rp += r_no;
72225cf1a30Sjl 		break;
72325cf1a30Sjl 
72425cf1a30Sjl 	default:
72525cf1a30Sjl 		return (DDI_ME_INVAL);
72625cf1a30Sjl 	}
72725cf1a30Sjl 	PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, "\n");
72825cf1a30Sjl 
72925cf1a30Sjl 	/* use "assigned-addresses" to relocate regspec within pci space */
73025cf1a30Sjl 	if (rval = pcmu_reloc_reg(dip, rdip, pcmu_p, rp)) {
73125cf1a30Sjl 		goto done;
73225cf1a30Sjl 	}
73325cf1a30Sjl 
73425cf1a30Sjl 	/* adjust regspec according to mapping request */
73525cf1a30Sjl 	if (len) {
73625cf1a30Sjl 		rp->pci_size_low = (uint_t)len;
73725cf1a30Sjl 	}
73825cf1a30Sjl 	rp->pci_phys_low += off;
73925cf1a30Sjl 
74025cf1a30Sjl 	/* use "ranges" to translate relocated pci regspec into parent space */
74125cf1a30Sjl 	if (rval = pcmu_xlate_reg(pcmu_p, rp, &p_regspec)) {
74225cf1a30Sjl 		goto done;
74325cf1a30Sjl 	}
74425cf1a30Sjl 
74525cf1a30Sjl 	p_mapreq = *mp;		/* dup the whole structure */
74625cf1a30Sjl 	p_mapreq.map_type = DDI_MT_REGSPEC;
74725cf1a30Sjl 	p_mapreq.map_obj.rp = &p_regspec;
74825cf1a30Sjl 	rval = ddi_map(dip, &p_mapreq, 0, 0, addrp);
74925cf1a30Sjl 
75025cf1a30Sjl done:
75125cf1a30Sjl 	if (mp->map_type == DDI_MT_RNUMBER) {
75225cf1a30Sjl 		kmem_free(rp - r_no, reglen);
75325cf1a30Sjl 	}
75425cf1a30Sjl 	return (rval);
75525cf1a30Sjl }
75625cf1a30Sjl 
75725cf1a30Sjl #ifdef  DEBUG
75825cf1a30Sjl int	pcmu_peekfault_cnt = 0;
75925cf1a30Sjl int	pcmu_pokefault_cnt = 0;
76025cf1a30Sjl #endif  /* DEBUG */
76125cf1a30Sjl 
76225cf1a30Sjl static int
pcmu_do_poke(pcmu_t * pcmu_p,peekpoke_ctlops_t * in_args)76325cf1a30Sjl pcmu_do_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args)
76425cf1a30Sjl {
76525cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
76625cf1a30Sjl 	int err = DDI_SUCCESS;
76725cf1a30Sjl 	on_trap_data_t otd;
76825cf1a30Sjl 
76925cf1a30Sjl 	mutex_enter(&pcbm_p->pcbm_pokeflt_mutex);
77025cf1a30Sjl 	pcbm_p->pcbm_ontrap_data = &otd;
77125cf1a30Sjl 
77225cf1a30Sjl 	/* Set up protected environment. */
77325cf1a30Sjl 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
77425cf1a30Sjl 		uintptr_t tramp = otd.ot_trampoline;
77525cf1a30Sjl 
77625cf1a30Sjl 		otd.ot_trampoline = (uintptr_t)&poke_fault;
77725cf1a30Sjl 		err = do_poke(in_args->size, (void *)in_args->dev_addr,
77825cf1a30Sjl 		    (void *)in_args->host_addr);
77925cf1a30Sjl 		otd.ot_trampoline = tramp;
78025cf1a30Sjl 	} else {
78125cf1a30Sjl 		err = DDI_FAILURE;
78225cf1a30Sjl 	}
78325cf1a30Sjl 
78425cf1a30Sjl 	/*
78525cf1a30Sjl 	 * Read the async fault register for the PBM to see it sees
78625cf1a30Sjl 	 * a master-abort.
78725cf1a30Sjl 	 */
78825cf1a30Sjl 	pcmu_pbm_clear_error(pcbm_p);
78925cf1a30Sjl 
79025cf1a30Sjl 	if (otd.ot_trap & OT_DATA_ACCESS) {
79125cf1a30Sjl 		err = DDI_FAILURE;
79225cf1a30Sjl 	}
79325cf1a30Sjl 
79425cf1a30Sjl 	/* Take down protected environment. */
79525cf1a30Sjl 	no_trap();
79625cf1a30Sjl 
79725cf1a30Sjl 	pcbm_p->pcbm_ontrap_data = NULL;
79825cf1a30Sjl 	mutex_exit(&pcbm_p->pcbm_pokeflt_mutex);
79925cf1a30Sjl 
80025cf1a30Sjl #ifdef  DEBUG
80125cf1a30Sjl 	if (err == DDI_FAILURE)
80225cf1a30Sjl 		pcmu_pokefault_cnt++;
80325cf1a30Sjl #endif
80425cf1a30Sjl 	return (err);
80525cf1a30Sjl }
80625cf1a30Sjl 
80725cf1a30Sjl 
80825cf1a30Sjl static int
pcmu_ctlops_poke(pcmu_t * pcmu_p,peekpoke_ctlops_t * in_args)80925cf1a30Sjl pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args)
81025cf1a30Sjl {
81125cf1a30Sjl 	return (pcmu_do_poke(pcmu_p, in_args));
81225cf1a30Sjl }
81325cf1a30Sjl 
81425cf1a30Sjl /* ARGSUSED */
81525cf1a30Sjl static int
pcmu_do_peek(pcmu_t * pcmu_p,peekpoke_ctlops_t * in_args)81625cf1a30Sjl pcmu_do_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args)
81725cf1a30Sjl {
81825cf1a30Sjl 	int err = DDI_SUCCESS;
81925cf1a30Sjl 	on_trap_data_t otd;
82025cf1a30Sjl 
82125cf1a30Sjl 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
82225cf1a30Sjl 		uintptr_t tramp = otd.ot_trampoline;
82325cf1a30Sjl 
82425cf1a30Sjl 		otd.ot_trampoline = (uintptr_t)&peek_fault;
82525cf1a30Sjl 		err = do_peek(in_args->size, (void *)in_args->dev_addr,
82625cf1a30Sjl 		    (void *)in_args->host_addr);
82725cf1a30Sjl 		otd.ot_trampoline = tramp;
82825cf1a30Sjl 	} else
82925cf1a30Sjl 		err = DDI_FAILURE;
83025cf1a30Sjl 
83125cf1a30Sjl 	no_trap();
83225cf1a30Sjl 
83325cf1a30Sjl #ifdef  DEBUG
83425cf1a30Sjl 	if (err == DDI_FAILURE)
83525cf1a30Sjl 		pcmu_peekfault_cnt++;
83625cf1a30Sjl #endif
83725cf1a30Sjl 	return (err);
83825cf1a30Sjl }
83925cf1a30Sjl 
84025cf1a30Sjl 
84125cf1a30Sjl static int
pcmu_ctlops_peek(pcmu_t * pcmu_p,peekpoke_ctlops_t * in_args,void * result)84225cf1a30Sjl pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, void *result)
84325cf1a30Sjl {
84425cf1a30Sjl 	result = (void *)in_args->host_addr;
84525cf1a30Sjl 	return (pcmu_do_peek(pcmu_p, in_args));
84625cf1a30Sjl }
84725cf1a30Sjl 
84825cf1a30Sjl /*
84925cf1a30Sjl  * control ops entry point:
85025cf1a30Sjl  *
85125cf1a30Sjl  * Requests handled completely:
85225cf1a30Sjl  *	DDI_CTLOPS_INITCHILD	see pcmu_init_child() for details
85325cf1a30Sjl  *	DDI_CTLOPS_UNINITCHILD
85425cf1a30Sjl  *	DDI_CTLOPS_REPORTDEV	see report_dev() for details
85525cf1a30Sjl  *	DDI_CTLOPS_XLATE_INTRS	nothing to do
85625cf1a30Sjl  *	DDI_CTLOPS_IOMIN	cache line size if streaming otherwise 1
85725cf1a30Sjl  *	DDI_CTLOPS_REGSIZE
85825cf1a30Sjl  *	DDI_CTLOPS_NREGS
85925cf1a30Sjl  *	DDI_CTLOPS_NINTRS
86025cf1a30Sjl  *	DDI_CTLOPS_DVMAPAGESIZE
86125cf1a30Sjl  *	DDI_CTLOPS_POKE
86225cf1a30Sjl  *	DDI_CTLOPS_PEEK
86325cf1a30Sjl  *	DDI_CTLOPS_QUIESCE
86425cf1a30Sjl  *	DDI_CTLOPS_UNQUIESCE
86525cf1a30Sjl  *
86625cf1a30Sjl  * All others passed to parent.
86725cf1a30Sjl  */
86825cf1a30Sjl static int
pcmu_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)86925cf1a30Sjl pcmu_ctlops(dev_info_t *dip, dev_info_t *rdip,
87025cf1a30Sjl 	ddi_ctl_enum_t op, void *arg, void *result)
87125cf1a30Sjl {
87225cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
87325cf1a30Sjl 
87425cf1a30Sjl 	switch (op) {
87525cf1a30Sjl 	case DDI_CTLOPS_INITCHILD:
87625cf1a30Sjl 		return (pcmu_init_child(pcmu_p, (dev_info_t *)arg));
87725cf1a30Sjl 
878