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 
87825cf1a30Sjl 	case DDI_CTLOPS_UNINITCHILD:
87925cf1a30Sjl 		return (pcmu_uninit_child(pcmu_p, (dev_info_t *)arg));
88025cf1a30Sjl 
88125cf1a30Sjl 	case DDI_CTLOPS_REPORTDEV:
88225cf1a30Sjl 		return (pcmu_report_dev(rdip));
88325cf1a30Sjl 
88425cf1a30Sjl 	case DDI_CTLOPS_IOMIN:
88525cf1a30Sjl 		/*
88625cf1a30Sjl 		 * If we are using the streaming cache, align at
88725cf1a30Sjl 		 * least on a cache line boundary. Otherwise use
88825cf1a30Sjl 		 * whatever alignment is passed in.
88925cf1a30Sjl 		 */
89025cf1a30Sjl 		return (DDI_SUCCESS);
89125cf1a30Sjl 
89225cf1a30Sjl 	case DDI_CTLOPS_REGSIZE:
89325cf1a30Sjl 		*((off_t *)result) = pcmu_get_reg_set_size(rdip, *((int *)arg));
89425cf1a30Sjl 		return (DDI_SUCCESS);
89525cf1a30Sjl 
89625cf1a30Sjl 	case DDI_CTLOPS_NREGS:
89725cf1a30Sjl 		*((uint_t *)result) = pcmu_get_nreg_set(rdip);
89825cf1a30Sjl 		return (DDI_SUCCESS);
89925cf1a30Sjl 
90025cf1a30Sjl 	case DDI_CTLOPS_DVMAPAGESIZE:
90125cf1a30Sjl 		*((ulong_t *)result) = 0;
90225cf1a30Sjl 		return (DDI_SUCCESS);
90325cf1a30Sjl 
90425cf1a30Sjl 	case DDI_CTLOPS_POKE:
90525cf1a30Sjl 		return (pcmu_ctlops_poke(pcmu_p, (peekpoke_ctlops_t *)arg));
90625cf1a30Sjl 
90725cf1a30Sjl 	case DDI_CTLOPS_PEEK:
90825cf1a30Sjl 		return (pcmu_ctlops_peek(pcmu_p, (peekpoke_ctlops_t *)arg,
90925cf1a30Sjl 		    result));
91025cf1a30Sjl 
91125cf1a30Sjl 	case DDI_CTLOPS_AFFINITY:
91225cf1a30Sjl 		break;
91325cf1a30Sjl 
91425cf1a30Sjl 	case DDI_CTLOPS_QUIESCE:
91525cf1a30Sjl 		return (DDI_FAILURE);
91625cf1a30Sjl 
91725cf1a30Sjl 	case DDI_CTLOPS_UNQUIESCE:
91825cf1a30Sjl 		return (DDI_FAILURE);
91925cf1a30Sjl 
92025cf1a30Sjl 	default:
92125cf1a30Sjl 		break;
92225cf1a30Sjl 	}
92325cf1a30Sjl 
92425cf1a30Sjl 	/*
92525cf1a30Sjl 	 * Now pass the request up to our parent.
92625cf1a30Sjl 	 */
92725cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_CTLOPS, dip,
92825cf1a30Sjl 	    "passing request to parent: rdip=%s%d\n",
92925cf1a30Sjl 	    ddi_driver_name(rdip), ddi_get_instance(rdip));
93025cf1a30Sjl 	return (ddi_ctlops(dip, rdip, op, arg, result));
93125cf1a30Sjl }
93225cf1a30Sjl 
93325cf1a30Sjl 
93425cf1a30Sjl /* ARGSUSED */
93525cf1a30Sjl static int
pcmu_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)93625cf1a30Sjl pcmu_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
93725cf1a30Sjl     ddi_intr_handle_impl_t *hdlp, void *result)
93825cf1a30Sjl {
93925cf1a30Sjl 	pcmu_t		*pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
94025cf1a30Sjl 	int		ret = DDI_SUCCESS;
94125cf1a30Sjl 
94225cf1a30Sjl 	switch (intr_op) {
94325cf1a30Sjl 	case DDI_INTROP_GETCAP:
94425cf1a30Sjl 		/* GetCap will always fail for all non PCI devices */
94525cf1a30Sjl 		(void) pci_intx_get_cap(rdip, (int *)result);
94625cf1a30Sjl 		break;
94725cf1a30Sjl 	case DDI_INTROP_SETCAP:
94825cf1a30Sjl 		ret = DDI_ENOTSUP;
94925cf1a30Sjl 		break;
95025cf1a30Sjl 	case DDI_INTROP_ALLOC:
95125cf1a30Sjl 		*(int *)result = hdlp->ih_scratch1;
95225cf1a30Sjl 		break;
95325cf1a30Sjl 	case DDI_INTROP_FREE:
95425cf1a30Sjl 		break;
95525cf1a30Sjl 	case DDI_INTROP_GETPRI:
95625cf1a30Sjl 		*(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 0;
95725cf1a30Sjl 		break;
95825cf1a30Sjl 	case DDI_INTROP_SETPRI:
95925cf1a30Sjl 		break;
96025cf1a30Sjl 	case DDI_INTROP_ADDISR:
96125cf1a30Sjl 		ret = pcmu_add_intr(dip, rdip, hdlp);
96225cf1a30Sjl 		break;
96325cf1a30Sjl 	case DDI_INTROP_REMISR:
96425cf1a30Sjl 		ret = pcmu_remove_intr(dip, rdip, hdlp);
96525cf1a30Sjl 		break;
96625cf1a30Sjl 	case DDI_INTROP_ENABLE:
96725cf1a30Sjl 		ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp,
96825cf1a30Sjl 		    PCMU_INTR_STATE_ENABLE);
96925cf1a30Sjl 		break;
97025cf1a30Sjl 	case DDI_INTROP_DISABLE:
97125cf1a30Sjl 		ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp,
97225cf1a30Sjl 		    PCMU_INTR_STATE_DISABLE);
97325cf1a30Sjl 		break;
97425cf1a30Sjl 	case DDI_INTROP_SETMASK:
97525cf1a30Sjl 		ret = pci_intx_set_mask(rdip);
97625cf1a30Sjl 		break;
97725cf1a30Sjl 	case DDI_INTROP_CLRMASK:
97825cf1a30Sjl 		ret = pci_intx_clr_mask(rdip);
97925cf1a30Sjl 		break;
98025cf1a30Sjl 	case DDI_INTROP_GETPENDING:
98125cf1a30Sjl 		ret = pci_intx_get_pending(rdip, (int *)result);
98225cf1a30Sjl 		break;
98325cf1a30Sjl 	case DDI_INTROP_NINTRS:
98425cf1a30Sjl 	case DDI_INTROP_NAVAIL:
985a54f81fbSanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
98625cf1a30Sjl 		break;
98725cf1a30Sjl 	case DDI_INTROP_SUPPORTED_TYPES:
98825cf1a30Sjl 		/* PCI nexus driver supports only fixed interrupts */
989a54f81fbSanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
99025cf1a30Sjl 		    DDI_INTR_TYPE_FIXED : 0;
99125cf1a30Sjl 		break;
99225cf1a30Sjl 	default:
99325cf1a30Sjl 		ret = DDI_ENOTSUP;
99425cf1a30Sjl 		break;
99525cf1a30Sjl 	}
99625cf1a30Sjl 
99725cf1a30Sjl 	return (ret);
99825cf1a30Sjl }
99925cf1a30Sjl 
100025cf1a30Sjl /*
100125cf1a30Sjl  * CMU-CH specifics implementation:
100225cf1a30Sjl  *	interrupt mapping register
100325cf1a30Sjl  *	PBM configuration
100425cf1a30Sjl  *	ECC and PBM error handling
100525cf1a30Sjl  */
100625cf1a30Sjl 
100725cf1a30Sjl /* called by pcmu_attach() DDI_ATTACH to initialize pci objects */
100825cf1a30Sjl static int
pcmu_obj_setup(pcmu_t * pcmu_p)100925cf1a30Sjl pcmu_obj_setup(pcmu_t *pcmu_p)
101025cf1a30Sjl {
101125cf1a30Sjl 	int ret;
101225cf1a30Sjl 
101325cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
101425cf1a30Sjl 	pcmu_p->pcmu_rev = ddi_prop_get_int(DDI_DEV_T_ANY, pcmu_p->pcmu_dip,
101525cf1a30Sjl 	    DDI_PROP_DONTPASS, "module-revision#", 0);
101625cf1a30Sjl 
101725cf1a30Sjl 	pcmu_ib_create(pcmu_p);
101825cf1a30Sjl 	pcmu_cb_create(pcmu_p);
101925cf1a30Sjl 	pcmu_ecc_create(pcmu_p);
102025cf1a30Sjl 	pcmu_pbm_create(pcmu_p);
102125cf1a30Sjl 	pcmu_err_create(pcmu_p);
102225cf1a30Sjl 	if ((ret = pcmu_intr_setup(pcmu_p)) != DDI_SUCCESS)
102325cf1a30Sjl 		goto done;
102425cf1a30Sjl 
1025c9b6d37cSfherard 	/*
1026c9b6d37cSfherard 	 * Due to a hardware bug, do not create kstat for DC systems
1027c9b6d37cSfherard 	 * with PCI hw revision less than 5.
1028c9b6d37cSfherard 	 */
1029c9b6d37cSfherard 	if ((strncmp(ddi_binding_name(pcmu_p->pcmu_dip),
1030c9b6d37cSfherard 	    PCICMU_OPL_DC_BINDING_NAME, strlen(PCICMU_OPL_DC_BINDING_NAME))
1031c9b6d37cSfherard 	    != 0) || (pcmu_p->pcmu_rev > 4)) {
1032c9b6d37cSfherard 		pcmu_kstat_create(pcmu_p);
1033c9b6d37cSfherard 	}
103425cf1a30Sjl done:
103525cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
103625cf1a30Sjl 	if (ret != DDI_SUCCESS) {
103725cf1a30Sjl 		cmn_err(CE_NOTE, "Interrupt register failure, returning 0x%x\n",
1038c9b6d37cSfherard 		    ret);
103925cf1a30Sjl 	}
104025cf1a30Sjl 	return (ret);
104125cf1a30Sjl }
104225cf1a30Sjl 
104325cf1a30Sjl /* called by pcmu_detach() DDI_DETACH to destroy pci objects */
104425cf1a30Sjl static void
pcmu_obj_destroy(pcmu_t * pcmu_p)104525cf1a30Sjl pcmu_obj_destroy(pcmu_t *pcmu_p)
104625cf1a30Sjl {
104725cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
104825cf1a30Sjl 
104925cf1a30Sjl 	pcmu_kstat_destroy(pcmu_p);
105025cf1a30Sjl 	pcmu_pbm_destroy(pcmu_p);
105125cf1a30Sjl 	pcmu_err_destroy(pcmu_p);
105225cf1a30Sjl 	pcmu_ecc_destroy(pcmu_p);
105325cf1a30Sjl 	pcmu_cb_destroy(pcmu_p);
105425cf1a30Sjl 	pcmu_ib_destroy(pcmu_p);
105525cf1a30Sjl 	pcmu_intr_teardown(pcmu_p);
105625cf1a30Sjl 
105725cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
105825cf1a30Sjl }
105925cf1a30Sjl 
106025cf1a30Sjl /* called by pcmu_attach() DDI_RESUME to (re)initialize pci objects */
106125cf1a30Sjl static void
pcmu_obj_resume(pcmu_t * pcmu_p)106225cf1a30Sjl pcmu_obj_resume(pcmu_t *pcmu_p)
106325cf1a30Sjl {
106425cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
106525cf1a30Sjl 
106625cf1a30Sjl 	pcmu_ib_configure(pcmu_p->pcmu_ib_p);
106725cf1a30Sjl 	pcmu_ecc_configure(pcmu_p);
106825cf1a30Sjl 	pcmu_ib_resume(pcmu_p->pcmu_ib_p);
106925cf1a30Sjl 	u2u_ittrans_resume((u2u_ittrans_data_t **)
107025cf1a30Sjl 	    &(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie));
107125cf1a30Sjl 
107225cf1a30Sjl 	pcmu_pbm_configure(pcmu_p->pcmu_pcbm_p);
107325cf1a30Sjl 
107425cf1a30Sjl 	pcmu_cb_resume(pcmu_p->pcmu_cb_p);
107525cf1a30Sjl 
107625cf1a30Sjl 	pcmu_pbm_resume(pcmu_p->pcmu_pcbm_p);
107725cf1a30Sjl 
107825cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
107925cf1a30Sjl }
108025cf1a30Sjl 
108125cf1a30Sjl /* called by pcmu_detach() DDI_SUSPEND to suspend pci objects */
108225cf1a30Sjl static void
pcmu_obj_suspend(pcmu_t * pcmu_p)108325cf1a30Sjl pcmu_obj_suspend(pcmu_t *pcmu_p)
108425cf1a30Sjl {
108525cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
108625cf1a30Sjl 
108725cf1a30Sjl 	pcmu_pbm_suspend(pcmu_p->pcmu_pcbm_p);
108825cf1a30Sjl 	pcmu_ib_suspend(pcmu_p->pcmu_ib_p);
108925cf1a30Sjl 	pcmu_cb_suspend(pcmu_p->pcmu_cb_p);
109025cf1a30Sjl 
109125cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
109225cf1a30Sjl }
109325cf1a30Sjl 
109425cf1a30Sjl static int
pcmu_intr_setup(pcmu_t * pcmu_p)109525cf1a30Sjl pcmu_intr_setup(pcmu_t *pcmu_p)
109625cf1a30Sjl {
109725cf1a30Sjl 	dev_info_t *dip = pcmu_p->pcmu_dip;
109825cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
109925cf1a30Sjl 	pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p;
110025cf1a30Sjl 	int i, no_of_intrs;
110125cf1a30Sjl 
110225cf1a30Sjl 	/*
110325cf1a30Sjl 	 * Get the interrupts property.
110425cf1a30Sjl 	 */
110525cf1a30Sjl 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
110625cf1a30Sjl 	    "interrupts", (caddr_t)&pcmu_p->pcmu_inos,
110725cf1a30Sjl 	    &pcmu_p->pcmu_inos_len) != DDI_SUCCESS) {
110825cf1a30Sjl 		cmn_err(CE_PANIC, "%s%d: no interrupts property\n",
1109c9b6d37cSfherard 		    ddi_driver_name(dip), ddi_get_instance(dip));
111025cf1a30Sjl 	}
111125cf1a30Sjl 
111225cf1a30Sjl 	/*
111325cf1a30Sjl 	 * figure out number of interrupts in the "interrupts" property
111425cf1a30Sjl 	 * and convert them all into ino.
111525cf1a30Sjl 	 */
111625cf1a30Sjl 	i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1);
111725cf1a30Sjl 	i = CELLS_1275_TO_BYTES(i);
111825cf1a30Sjl 	no_of_intrs = pcmu_p->pcmu_inos_len / i;
111925cf1a30Sjl 	for (i = 0; i < no_of_intrs; i++) {
112025cf1a30Sjl 		pcmu_p->pcmu_inos[i] =
112125cf1a30Sjl 		    PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[i]);
112225cf1a30Sjl 	}
112325cf1a30Sjl 
112425cf1a30Sjl 	pcb_p->pcb_no_of_inos = no_of_intrs;
112525cf1a30Sjl 	if (i = pcmu_ecc_register_intr(pcmu_p)) {
112625cf1a30Sjl 		goto teardown;
112725cf1a30Sjl 	}
112825cf1a30Sjl 
112925cf1a30Sjl 	intr_dist_add(pcmu_cb_intr_dist, pcb_p);
113025cf1a30Sjl 	pcmu_ecc_enable_intr(pcmu_p);
113125cf1a30Sjl 
113225cf1a30Sjl 	if (i = pcmu_pbm_register_intr(pcbm_p)) {
113325cf1a30Sjl 		intr_dist_rem(pcmu_cb_intr_dist, pcb_p);
113425cf1a30Sjl 		goto teardown;
113525cf1a30Sjl 	}
113625cf1a30Sjl 	intr_dist_add(pcmu_pbm_intr_dist, pcbm_p);
113725cf1a30Sjl 	pcmu_ib_intr_enable(pcmu_p, pcmu_p->pcmu_inos[CBNINTR_PBM]);
113825cf1a30Sjl 
113925cf1a30Sjl 	intr_dist_add_weighted(pcmu_ib_intr_dist_all, pcmu_p->pcmu_ib_p);
114025cf1a30Sjl 	return (DDI_SUCCESS);
114125cf1a30Sjl teardown:
114225cf1a30Sjl 	pcmu_intr_teardown(pcmu_p);
114325cf1a30Sjl 	return (i);
114425cf1a30Sjl }
114525cf1a30Sjl 
114625cf1a30Sjl /*
114725cf1a30Sjl  * pcmu_fix_ranges - fixes the config space entry of the "ranges"
114825cf1a30Sjl  *	property on CMU-CH platforms
114925cf1a30Sjl  */
115025cf1a30Sjl void
pcmu_fix_ranges(pcmu_ranges_t * rng_p,int rng_entries)115125cf1a30Sjl pcmu_fix_ranges(pcmu_ranges_t *rng_p, int rng_entries)
115225cf1a30Sjl {
115325cf1a30Sjl 	int i;
115425cf1a30Sjl 	for (i = 0; i < rng_entries; i++, rng_p++) {
115525cf1a30Sjl 		if ((rng_p->child_high & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG)
115625cf1a30Sjl 			rng_p->parent_low |= rng_p->child_high;
115725cf1a30Sjl 	}
115825cf1a30Sjl }
115925cf1a30Sjl 
116025cf1a30Sjl /*
116125cf1a30Sjl  * map_pcmu_registers
116225cf1a30Sjl  *
116325cf1a30Sjl  * This function is called from the attach routine to map the registers
116425cf1a30Sjl  * accessed by this driver.
116525cf1a30Sjl  *
116625cf1a30Sjl  * used by: pcmu_attach()
116725cf1a30Sjl  *
116825cf1a30Sjl  * return value: DDI_FAILURE on failure
116925cf1a30Sjl  */
117025cf1a30Sjl static int
map_pcmu_registers(pcmu_t * pcmu_p,dev_info_t * dip)117125cf1a30Sjl map_pcmu_registers(pcmu_t *pcmu_p, dev_info_t *dip)
117225cf1a30Sjl {
117325cf1a30Sjl 	ddi_device_acc_attr_t attr;
117425cf1a30Sjl 
117525cf1a30Sjl 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
117625cf1a30Sjl 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
117725cf1a30Sjl 
117825cf1a30Sjl 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
117925cf1a30Sjl 	if (ddi_regs_map_setup(dip, 0, &pcmu_p->pcmu_address[0], 0, 0,
118025cf1a30Sjl 	    &attr, &pcmu_p->pcmu_ac[0]) != DDI_SUCCESS) {
118125cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: unable to map reg entry 0\n",
118225cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
118325cf1a30Sjl 		return (DDI_FAILURE);
118425cf1a30Sjl 	}
118525cf1a30Sjl 
118625cf1a30Sjl 	/*
118725cf1a30Sjl 	 * We still use pcmu_address[2]
118825cf1a30Sjl 	 */
118925cf1a30Sjl 	if (ddi_regs_map_setup(dip, 2, &pcmu_p->pcmu_address[2], 0, 0,
1190c9b6d37cSfherard 	    &attr, &pcmu_p->pcmu_ac[2]) != DDI_SUCCESS) {
119125cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: unable to map reg entry 2\n",
119225cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
119325cf1a30Sjl 		ddi_regs_map_free(&pcmu_p->pcmu_ac[0]);
119425cf1a30Sjl 		return (DDI_FAILURE);
119525cf1a30Sjl 	}
119625cf1a30Sjl 
119725cf1a30Sjl 	/*
119825cf1a30Sjl 	 * The second register set contains the bridge's configuration
119925cf1a30Sjl 	 * header.  This header is at the very beginning of the bridge's
120025cf1a30Sjl 	 * configuration space.  This space has litte-endian byte order.
120125cf1a30Sjl 	 */
120225cf1a30Sjl 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
120325cf1a30Sjl 	if (ddi_regs_map_setup(dip, 1, &pcmu_p->pcmu_address[1], 0,
120425cf1a30Sjl 	    PCI_CONF_HDR_SIZE, &attr, &pcmu_p->pcmu_ac[1]) != DDI_SUCCESS) {
120525cf1a30Sjl 
120625cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: unable to map reg entry 1\n",
120725cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
120825cf1a30Sjl 		ddi_regs_map_free(&pcmu_p->pcmu_ac[0]);
120925cf1a30Sjl 		return (DDI_FAILURE);
121025cf1a30Sjl 	}
121125cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_ATTACH, dip, "address (%p,%p)\n",
121225cf1a30Sjl 	    pcmu_p->pcmu_address[0], pcmu_p->pcmu_address[1]);
121325cf1a30Sjl 	return (DDI_SUCCESS);
121425cf1a30Sjl }
121525cf1a30Sjl 
121625cf1a30Sjl /*
121725cf1a30Sjl  * unmap_pcmu_registers:
121825cf1a30Sjl  *
121925cf1a30Sjl  * This routine unmap the registers mapped by map_pcmu_registers.
122025cf1a30Sjl  *
122125cf1a30Sjl  * used by: pcmu_detach()
122225cf1a30Sjl  *
122325cf1a30Sjl  * return value: none
122425cf1a30Sjl  */
122525cf1a30Sjl static void
unmap_pcmu_registers(pcmu_t * pcmu_p)122625cf1a30Sjl unmap_pcmu_registers(pcmu_t *pcmu_p)
122725cf1a30Sjl {
122825cf1a30Sjl 	ddi_regs_map_free(&pcmu_p->pcmu_ac[0]);
122925cf1a30Sjl 	ddi_regs_map_free(&pcmu_p->pcmu_ac[1]);
123025cf1a30Sjl 	ddi_regs_map_free(&pcmu_p->pcmu_ac[2]);
123125cf1a30Sjl }
123225cf1a30Sjl 
123325cf1a30Sjl /*
123425cf1a30Sjl  * These convenience wrappers relies on map_pcmu_registers() to setup
123525cf1a30Sjl  * pcmu_address[0-2] correctly at first.
123625cf1a30Sjl  */
123725cf1a30Sjl static uintptr_t
get_reg_base(pcmu_t * pcmu_p)123825cf1a30Sjl get_reg_base(pcmu_t *pcmu_p)
123925cf1a30Sjl {
124025cf1a30Sjl 	return ((uintptr_t)pcmu_p->pcmu_address[2]);
124125cf1a30Sjl }
124225cf1a30Sjl 
124325cf1a30Sjl /* The CMU-CH config reg base is always the 2nd reg entry */
124425cf1a30Sjl static uintptr_t
get_config_reg_base(pcmu_t * pcmu_p)124525cf1a30Sjl get_config_reg_base(pcmu_t *pcmu_p)
124625cf1a30Sjl {
124725cf1a30Sjl 	return ((uintptr_t)(pcmu_p->pcmu_address[1]));
124825cf1a30Sjl }
124925cf1a30Sjl 
125025cf1a30Sjl uint64_t
ib_get_map_reg(pcmu_ib_mondo_t mondo,uint32_t cpu_id)125125cf1a30Sjl ib_get_map_reg(pcmu_ib_mondo_t mondo, uint32_t cpu_id)
125225cf1a30Sjl {
125325cf1a30Sjl 	return ((mondo) | (cpu_id << PCMU_INTR_MAP_REG_TID_SHIFT) |
125425cf1a30Sjl 	    PCMU_INTR_MAP_REG_VALID);
125525cf1a30Sjl 
125625cf1a30Sjl }
125725cf1a30Sjl 
125825cf1a30Sjl uint32_t
ib_map_reg_get_cpu(volatile uint64_t reg)125925cf1a30Sjl ib_map_reg_get_cpu(volatile uint64_t reg)
126025cf1a30Sjl {
126125cf1a30Sjl 	return ((reg & PCMU_INTR_MAP_REG_TID) >>
126225cf1a30Sjl 	    PCMU_INTR_MAP_REG_TID_SHIFT);
126325cf1a30Sjl }
126425cf1a30Sjl 
126525cf1a30Sjl uint64_t *
ib_intr_map_reg_addr(pcmu_ib_t * pib_p,pcmu_ib_ino_t ino)126625cf1a30Sjl ib_intr_map_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino)
126725cf1a30Sjl {
126825cf1a30Sjl 	uint64_t *addr;
126925cf1a30Sjl 
127025cf1a30Sjl 	ASSERT(ino & 0x20);
127125cf1a30Sjl 	addr = (uint64_t *)(pib_p->pib_obio_intr_map_regs +
127225cf1a30Sjl 	    (((uint_t)ino & 0x1f) << 3));
127325cf1a30Sjl 	return (addr);
127425cf1a30Sjl }
127525cf1a30Sjl 
127625cf1a30Sjl uint64_t *
ib_clear_intr_reg_addr(pcmu_ib_t * pib_p,pcmu_ib_ino_t ino)127725cf1a30Sjl ib_clear_intr_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino)
127825cf1a30Sjl {
127925cf1a30Sjl 	uint64_t *addr;
128025cf1a30Sjl 
128125cf1a30Sjl 	ASSERT(ino & 0x20);
128225cf1a30Sjl 	addr = (uint64_t *)(pib_p->pib_obio_clear_intr_regs +
128325cf1a30Sjl 	    (((uint_t)ino & 0x1f) << 3));
128425cf1a30Sjl 	return (addr);
128525cf1a30Sjl }
128625cf1a30Sjl 
128725cf1a30Sjl uintptr_t
pcmu_ib_setup(pcmu_ib_t * pib_p)128825cf1a30Sjl pcmu_ib_setup(pcmu_ib_t *pib_p)
128925cf1a30Sjl {
129025cf1a30Sjl 	pcmu_t *pcmu_p = pib_p->pib_pcmu_p;
129125cf1a30Sjl 	uintptr_t a = get_reg_base(pcmu_p);
129225cf1a30Sjl 
129325cf1a30Sjl 	pib_p->pib_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id);
129425cf1a30Sjl 	pib_p->pib_max_ino = PCMU_MAX_INO;
129525cf1a30Sjl 	pib_p->pib_obio_intr_map_regs = a + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET;
129625cf1a30Sjl 	pib_p->pib_obio_clear_intr_regs =
1297c9b6d37cSfherard 	    a + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET;
129825cf1a30Sjl 	return (a);
129925cf1a30Sjl }
130025cf1a30Sjl 
130125cf1a30Sjl /*
130225cf1a30Sjl  * Return the cpuid to to be used for an ino.
130325cf1a30Sjl  *
130425cf1a30Sjl  * On multi-function pci devices, functions have separate devinfo nodes and
130525cf1a30Sjl  * interrupts.
130625cf1a30Sjl  *
130725cf1a30Sjl  * This function determines if there is already an established slot-oriented
130825cf1a30Sjl  * interrupt-to-cpu binding established, if there is then it returns that
130925cf1a30Sjl  * cpu.  Otherwise a new cpu is selected by intr_dist_cpuid().
131025cf1a30Sjl  *
131125cf1a30Sjl  * The devinfo node we are trying to associate a cpu with is
131225cf1a30Sjl  * ino_p->pino_ih_head->ih_dip.
131325cf1a30Sjl  */
131425cf1a30Sjl uint32_t
pcmu_intr_dist_cpuid(pcmu_ib_t * pib_p,pcmu_ib_ino_info_t * ino_p)131525cf1a30Sjl pcmu_intr_dist_cpuid(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p)
131625cf1a30Sjl {
131725cf1a30Sjl 	dev_info_t	*rdip = ino_p->pino_ih_head->ih_dip;
131825cf1a30Sjl 	dev_info_t	*prdip = ddi_get_parent(rdip);
131925cf1a30Sjl 	pcmu_ib_ino_info_t	*sino_p;
132025cf1a30Sjl 	dev_info_t	*sdip;
132125cf1a30Sjl 	dev_info_t	*psdip;
132225cf1a30Sjl 	char		*buf1 = NULL, *buf2 = NULL;
132325cf1a30Sjl 	char		*s1, *s2, *s3;
132425cf1a30Sjl 	int		l2;
132525cf1a30Sjl 	int		cpu_id;
132625cf1a30Sjl 
132725cf1a30Sjl 	/* must be CMU-CH driver parent (not ebus) */
132825cf1a30Sjl 	if (strcmp(ddi_driver_name(prdip), "pcicmu") != 0)
132925cf1a30Sjl 		goto newcpu;
133025cf1a30Sjl 
133125cf1a30Sjl 	/*
133225cf1a30Sjl 	 * From PCI 1275 binding: 2.2.1.3 Unit Address representation:
133325cf1a30Sjl 	 *   Since the "unit-number" is the address that appears in on Open
133425cf1a30Sjl 	 *   Firmware 'device path', it follows that only the DD and DD,FF
133525cf1a30Sjl 	 *   forms of the text representation can appear in a 'device path'.
133625cf1a30Sjl 	 *
133725cf1a30Sjl 	 * The rdip unit address is of the form "DD[,FF]".  Define two
133825cf1a30Sjl 	 * unit address strings that represent same-slot use: "DD" and "DD,".
133925cf1a30Sjl 	 * The first compare uses strcmp, the second uses strncmp.
134025cf1a30Sjl 	 */
134125cf1a30Sjl 	s1 = ddi_get_name_addr(rdip);
134225cf1a30Sjl 	if (s1 == NULL) {
134325cf1a30Sjl 		goto newcpu;
134425cf1a30Sjl 	}
134525cf1a30Sjl 
134625cf1a30Sjl 	buf1 = kmem_alloc(MAXNAMELEN, KM_SLEEP);	/* strcmp */
134725cf1a30Sjl 	buf2 = kmem_alloc(MAXNAMELEN, KM_SLEEP);	/* strncmp */
134825cf1a30Sjl 	s1 = strcpy(buf1, s1);
134925cf1a30Sjl 	s2 = strcpy(buf2, s1);
135025cf1a30Sjl 
135125cf1a30Sjl 	s1 = strrchr(s1, ',');
135225cf1a30Sjl 	if (s1) {
135325cf1a30Sjl 		*s1 = '\0';			/* have "DD,FF" */
135425cf1a30Sjl 		s1 = buf1;			/* search via strcmp "DD" */
135525cf1a30Sjl 
135625cf1a30Sjl 		s2 = strrchr(s2, ',');
135725cf1a30Sjl 		*(s2 + 1) = '\0';
135825cf1a30Sjl 		s2 = buf2;
135925cf1a30Sjl 		l2 = strlen(s2);		/* search via strncmp "DD," */
136025cf1a30Sjl 	} else {
136125cf1a30Sjl 		(void) strcat(s2, ",");		/* have "DD" */
136225cf1a30Sjl 		l2 = strlen(s2);		/* search via strncmp "DD," */
136325cf1a30Sjl 	}
136425cf1a30Sjl 
136525cf1a30Sjl 	/*
136625cf1a30Sjl 	 * Search the established ino list for devinfo nodes bound
136725cf1a30Sjl 	 * to an ino that matches one of the slot use strings.
136825cf1a30Sjl 	 */
136925cf1a30Sjl 	ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex));
137025cf1a30Sjl 	for (sino_p = pib_p->pib_ino_lst; sino_p; sino_p = sino_p->pino_next) {
137125cf1a30Sjl 		/* skip self and non-established */
137225cf1a30Sjl 		if ((sino_p == ino_p) || (sino_p->pino_established == 0))
137325cf1a30Sjl 			continue;
137425cf1a30Sjl 
137525cf1a30Sjl 		/* skip non-siblings */
137625cf1a30Sjl 		sdip = sino_p->pino_ih_head->ih_dip;
137725cf1a30Sjl 		psdip = ddi_get_parent(sdip);
137825cf1a30Sjl 		if (psdip != prdip)
137925cf1a30Sjl 			continue;
138025cf1a30Sjl 
138125cf1a30Sjl 		/* must be CMU-CH driver parent (not ebus) */
138225cf1a30Sjl 		if (strcmp(ddi_driver_name(psdip), "pcicmu") != 0)
138325cf1a30Sjl 			continue;
138425cf1a30Sjl 
138525cf1a30Sjl 		s3 = ddi_get_name_addr(sdip);
138625cf1a30Sjl 		if ((s1 && (strcmp(s1, s3) == 0)) ||
138725cf1a30Sjl 		    (strncmp(s2, s3, l2) == 0)) {
138825cf1a30Sjl 			extern int intr_dist_debug;
138925cf1a30Sjl 
139025cf1a30Sjl 			if (intr_dist_debug) {
139125cf1a30Sjl 				cmn_err(CE_CONT, "intr_dist: "
139225cf1a30Sjl 				    "pcicmu`pcmu_intr_dist_cpuid "
139325cf1a30Sjl 				    "%s#%d %s: cpu %d established "
139425cf1a30Sjl 				    "by %s#%d %s\n", ddi_driver_name(rdip),
139525cf1a30Sjl 				    ddi_get_instance(rdip),
139625cf1a30Sjl 				    ddi_deviname(rdip, buf1),
139725cf1a30Sjl 				    sino_p->pino_cpuid,
139825cf1a30Sjl 				    ddi_driver_name(sdip),
139925cf1a30Sjl 				    ddi_get_instance(sdip),
140025cf1a30Sjl 				    ddi_deviname(sdip, buf2));
140125cf1a30Sjl 			}
140225cf1a30Sjl 			break;
140325cf1a30Sjl 		}
140425cf1a30Sjl 	}
140525cf1a30Sjl 
140625cf1a30Sjl 	/* If a slot use match is found then use established cpu */
140725cf1a30Sjl 	if (sino_p) {
140825cf1a30Sjl 		cpu_id = sino_p->pino_cpuid;	/* target established cpu */
140925cf1a30Sjl 		goto out;
141025cf1a30Sjl 	}
141125cf1a30Sjl 
141225cf1a30Sjl newcpu:	cpu_id = intr_dist_cpuid();		/* target new cpu */
141325cf1a30Sjl 
141425cf1a30Sjl out:	if (buf1)
141525cf1a30Sjl 		kmem_free(buf1, MAXNAMELEN);
141625cf1a30Sjl 	if (buf2)
141725cf1a30Sjl 		kmem_free(buf2, MAXNAMELEN);
141825cf1a30Sjl 	return (cpu_id);
141925cf1a30Sjl }
142025cf1a30Sjl 
142125cf1a30Sjl void
pcmu_cb_teardown(pcmu_t * pcmu_p)142225cf1a30Sjl pcmu_cb_teardown(pcmu_t *pcmu_p)
142325cf1a30Sjl {
142425cf1a30Sjl 	pcmu_cb_t	*pcb_p = pcmu_p->pcmu_cb_p;
142525cf1a30Sjl 
142625cf1a30Sjl 	u2u_ittrans_uninit((u2u_ittrans_data_t *)pcb_p->pcb_ittrans_cookie);
142725cf1a30Sjl }
142825cf1a30Sjl 
142925cf1a30Sjl int
pcmu_ecc_add_intr(pcmu_t * pcmu_p,int inum,pcmu_ecc_intr_info_t * eii_p)143025cf1a30Sjl pcmu_ecc_add_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p)
143125cf1a30Sjl {
143225cf1a30Sjl 	uint32_t mondo;
143325cf1a30Sjl 
143425cf1a30Sjl 	mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) |
143525cf1a30Sjl 	    pcmu_p->pcmu_inos[inum]);
143625cf1a30Sjl 
1437b0fc0e77Sgovinda 	VERIFY(add_ivintr(mondo, pcmu_pil[inum], (intrfunc)pcmu_ecc_intr,
1438b0fc0e77Sgovinda 	    (caddr_t)eii_p, NULL, NULL) == 0);
1439b0fc0e77Sgovinda 
144025cf1a30Sjl 	return (PCMU_ATTACH_RETCODE(PCMU_ECC_OBJ,
144125cf1a30Sjl 	    PCMU_OBJ_INTR_ADD, DDI_SUCCESS));
144225cf1a30Sjl }
144325cf1a30Sjl 
144425cf1a30Sjl /* ARGSUSED */
144525cf1a30Sjl void
pcmu_ecc_rem_intr(pcmu_t * pcmu_p,int inum,pcmu_ecc_intr_info_t * eii_p)144625cf1a30Sjl pcmu_ecc_rem_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p)
144725cf1a30Sjl {
144825cf1a30Sjl 	uint32_t mondo;
144925cf1a30Sjl 
145025cf1a30Sjl 	mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) |
145125cf1a30Sjl 	    pcmu_p->pcmu_inos[inum]);
1452b0fc0e77Sgovinda 
1453b0fc0e77Sgovinda 	VERIFY(rem_ivintr(mondo, pcmu_pil[inum]) == 0);
145425cf1a30Sjl }
145525cf1a30Sjl 
145625cf1a30Sjl void
pcmu_pbm_configure(pcmu_pbm_t * pcbm_p)145725cf1a30Sjl pcmu_pbm_configure(pcmu_pbm_t *pcbm_p)
145825cf1a30Sjl {
145925cf1a30Sjl 	pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
146025cf1a30Sjl 	dev_info_t *dip = pcmu_p->pcmu_dip;
146125cf1a30Sjl 
146225cf1a30Sjl #define	pbm_err	((PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_PE_SHIFT) |	\
146325cf1a30Sjl 		(PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_SE_SHIFT))
146425cf1a30Sjl #define	csr_err	(PCI_STAT_PERROR | PCI_STAT_S_PERROR |		\
146525cf1a30Sjl 		PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB |	\
146625cf1a30Sjl 		PCI_STAT_S_TARG_AB | PCI_STAT_S_PERROR)
146725cf1a30Sjl 
146825cf1a30Sjl 	/*
146925cf1a30Sjl 	 * Clear any PBM errors.
147025cf1a30Sjl 	 */
147125cf1a30Sjl 	*pcbm_p->pcbm_async_flt_status_reg = pbm_err;
147225cf1a30Sjl 
147325cf1a30Sjl 	/*
147425cf1a30Sjl 	 * Clear error bits in configuration status register.
147525cf1a30Sjl 	 */
147625cf1a30Sjl 	PCMU_DBG1(PCMU_DBG_ATTACH, dip,
147725cf1a30Sjl 	    "pcmu_pbm_configure: conf status reg=%x\n", csr_err);
147825cf1a30Sjl 
147925cf1a30Sjl 	pcbm_p->pcbm_config_header->ch_status_reg = csr_err;
148025cf1a30Sjl 
148125cf1a30Sjl 	PCMU_DBG1(PCMU_DBG_ATTACH, dip,
148225cf1a30Sjl 	    "pcmu_pbm_configure: conf status reg==%x\n",
148325cf1a30Sjl 	    pcbm_p->pcbm_config_header->ch_status_reg);
148425cf1a30Sjl 
148525cf1a30Sjl 	(void) ndi_prop_update_int(DDI_DEV_T_ANY, dip, "latency-timer",
1486c9b6d37cSfherard 	    (int)pcbm_p->pcbm_config_header->ch_latency_timer_reg);
148725cf1a30Sjl #undef	pbm_err
148825cf1a30Sjl #undef	csr_err
148925cf1a30Sjl }
149025cf1a30Sjl 
149125cf1a30Sjl uint_t
pcmu_pbm_disable_errors(pcmu_pbm_t * pcbm_p)149225cf1a30Sjl pcmu_pbm_disable_errors(pcmu_pbm_t *pcbm_p)
149325cf1a30Sjl {
149425cf1a30Sjl 	pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
149525cf1a30Sjl 	pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p;
149625cf1a30Sjl 
149725cf1a30Sjl 	/*
149825cf1a30Sjl 	 * Disable error and streaming byte hole interrupts via the
149925cf1a30Sjl 	 * PBM control register.
150025cf1a30Sjl 	 */
150125cf1a30Sjl 	*pcbm_p->pcbm_ctrl_reg &= ~PCMU_PCI_CTRL_ERR_INT_EN;
150225cf1a30Sjl 
150325cf1a30Sjl 	/*
150425cf1a30Sjl 	 * Disable error interrupts via the interrupt mapping register.
150525cf1a30Sjl 	 */
150625cf1a30Sjl 	pcmu_ib_intr_disable(pib_p,
150725cf1a30Sjl 	    pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_NOWAIT);
150825cf1a30Sjl 	return (BF_NONE);
150925cf1a30Sjl }
151025cf1a30Sjl 
151125cf1a30Sjl void
pcmu_cb_setup(pcmu_t * pcmu_p)151225cf1a30Sjl pcmu_cb_setup(pcmu_t *pcmu_p)
151325cf1a30Sjl {
151425cf1a30Sjl 	uint64_t csr, csr_pa, pa;
151525cf1a30Sjl 	pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p;
151625cf1a30Sjl 
151725cf1a30Sjl 	pcb_p->pcb_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id);
151825cf1a30Sjl 	pa = (uint64_t)hat_getpfnum(kas.a_hat, pcmu_p->pcmu_address[0]);
151925cf1a30Sjl 	pcb_p->pcb_base_pa  = pa = pa >> (32 - MMU_PAGESHIFT) << 32;
152025cf1a30Sjl 	pcb_p->pcb_map_pa = pa + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET;
152125cf1a30Sjl 	pcb_p->pcb_clr_pa = pa + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET;
152225cf1a30Sjl 	pcb_p->pcb_obsta_pa = pa + PCMU_IB_OBIO_INTR_STATE_DIAG_REG;
152325cf1a30Sjl 
152425cf1a30Sjl 	csr_pa = pa + PCMU_CB_CONTROL_STATUS_REG_OFFSET;
152525cf1a30Sjl 	csr = lddphysio(csr_pa);
152625cf1a30Sjl 
152725cf1a30Sjl 	/*
152825cf1a30Sjl 	 * Clear any pending address parity errors.
152925cf1a30Sjl 	 */
153025cf1a30Sjl 	if (csr & PCMU_CB_CONTROL_STATUS_APERR) {
153125cf1a30Sjl 		csr |= PCMU_CB_CONTROL_STATUS_APERR;
153225cf1a30Sjl 		cmn_err(CE_WARN, "clearing UPA address parity error\n");
153325cf1a30Sjl 	}
153425cf1a30Sjl 	csr |= PCMU_CB_CONTROL_STATUS_APCKEN;
153525cf1a30Sjl 	csr &= ~PCMU_CB_CONTROL_STATUS_IAP;
153625cf1a30Sjl 	stdphysio(csr_pa, csr);
153725cf1a30Sjl 
153825cf1a30Sjl 	u2u_ittrans_init(pcmu_p,
153925cf1a30Sjl 	    (u2u_ittrans_data_t **)&pcb_p->pcb_ittrans_cookie);
154025cf1a30Sjl }
154125cf1a30Sjl 
154225cf1a30Sjl void
pcmu_ecc_setup(pcmu_ecc_t * pecc_p)154325cf1a30Sjl pcmu_ecc_setup(pcmu_ecc_t *pecc_p)
154425cf1a30Sjl {
154525cf1a30Sjl 	pecc_p->pecc_ue.pecc_errpndg_mask = 0;
154625cf1a30Sjl 	pecc_p->pecc_ue.pecc_offset_mask = PCMU_ECC_UE_AFSR_DW_OFFSET;
154725cf1a30Sjl 	pecc_p->pecc_ue.pecc_offset_shift = PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT;
154825cf1a30Sjl 	pecc_p->pecc_ue.pecc_size_log2 = 3;
154925cf1a30Sjl }
155025cf1a30Sjl 
155125cf1a30Sjl static uintptr_t
get_pbm_reg_base(pcmu_t * pcmu_p)155225cf1a30Sjl get_pbm_reg_base(pcmu_t *pcmu_p)
155325cf1a30Sjl {
155425cf1a30Sjl 	return ((uintptr_t)(pcmu_p->pcmu_address[0]));
155525cf1a30Sjl }
155625cf1a30Sjl 
155725cf1a30Sjl void
pcmu_pbm_setup(pcmu_pbm_t * pcbm_p)155825cf1a30Sjl pcmu_pbm_setup(pcmu_pbm_t *pcbm_p)
155925cf1a30Sjl {
156025cf1a30Sjl 	pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
156125cf1a30Sjl 
156225cf1a30Sjl 	/*
156325cf1a30Sjl 	 * Get the base virtual address for the PBM control block.
156425cf1a30Sjl 	 */
156525cf1a30Sjl 	uintptr_t a = get_pbm_reg_base(pcmu_p);
156625cf1a30Sjl 
156725cf1a30Sjl 	/*
156825cf1a30Sjl 	 * Get the virtual address of the PCI configuration header.
156925cf1a30Sjl 	 * This should be mapped little-endian.
157025cf1a30Sjl 	 */
157125cf1a30Sjl 	pcbm_p->pcbm_config_header =
1572c9b6d37cSfherard 	    (config_header_t *)get_config_reg_base(pcmu_p);
157325cf1a30Sjl 
157425cf1a30Sjl 	/*
157525cf1a30Sjl 	 * Get the virtual addresses for control, error and diag
157625cf1a30Sjl 	 * registers.
157725cf1a30Sjl 	 */
157825cf1a30Sjl 	pcbm_p->pcbm_ctrl_reg = (uint64_t *)(a + PCMU_PCI_CTRL_REG_OFFSET);
157925cf1a30Sjl 	pcbm_p->pcbm_diag_reg = (uint64_t *)(a + PCMU_PCI_DIAG_REG_OFFSET);
158025cf1a30Sjl 	pcbm_p->pcbm_async_flt_status_reg =
158125cf1a30Sjl 	    (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_STATUS_REG_OFFSET);
158225cf1a30Sjl 	pcbm_p->pcbm_async_flt_addr_reg =
158325cf1a30Sjl 	    (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_ADDR_REG_OFFSET);
158425cf1a30Sjl }
158525cf1a30Sjl 
158625cf1a30Sjl /*ARGSUSED*/
158725cf1a30Sjl void
pcmu_pbm_teardown(pcmu_pbm_t * pcbm_p)158825cf1a30Sjl pcmu_pbm_teardown(pcmu_pbm_t *pcbm_p)
158925cf1a30Sjl {
159025cf1a30Sjl }
159125cf1a30Sjl 
159225cf1a30Sjl int
pcmu_get_numproxy(dev_info_t * dip)159325cf1a30Sjl pcmu_get_numproxy(dev_info_t *dip)
159425cf1a30Sjl {
159525cf1a30Sjl 	return (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1596c9b6d37cSfherard 	    "#upa-interrupt-proxies", 1));
159725cf1a30Sjl }
159825cf1a30Sjl 
159925cf1a30Sjl int
pcmu_get_portid(dev_info_t * dip)160025cf1a30Sjl pcmu_get_portid(dev_info_t *dip)
160125cf1a30Sjl {
160225cf1a30Sjl 	return (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
160325cf1a30Sjl 	    "portid", -1));
160425cf1a30Sjl }
160525cf1a30Sjl 
160625cf1a30Sjl /*
160725cf1a30Sjl  * CMU-CH Performance Events.
160825cf1a30Sjl  */
160925cf1a30Sjl static pcmu_kev_mask_t
161025cf1a30Sjl pcicmu_pcmu_events[] = {
161125cf1a30Sjl 	{"pio_cycles_b", 0xf},		{"interrupts", 0x11},
161225cf1a30Sjl 	{"upa_inter_nack", 0x12},	{"pio_reads", 0x13},
161325cf1a30Sjl 	{"pio_writes", 0x14},
161425cf1a30Sjl 	{"clear_pic", 0x1f}
161525cf1a30Sjl };
161625cf1a30Sjl 
161725cf1a30Sjl /*
161825cf1a30Sjl  * Create the picN kstat's.
161925cf1a30Sjl  */
162025cf1a30Sjl void
pcmu_kstat_init()162125cf1a30Sjl pcmu_kstat_init()
162225cf1a30Sjl {
162325cf1a30Sjl 	pcmu_name_kstat = (pcmu_ksinfo_t *)kmem_alloc(sizeof (pcmu_ksinfo_t),
1624c9b6d37cSfherard 	    KM_NOSLEEP);
162525cf1a30Sjl 
162625cf1a30Sjl 	if (pcmu_name_kstat == NULL) {
162725cf1a30Sjl 		cmn_err(CE_WARN, "pcicmu : no space for kstat\n");
162825cf1a30Sjl 	} else {
162925cf1a30Sjl 		pcmu_name_kstat->pic_no_evs =
1630c9b6d37cSfherard 		    sizeof (pcicmu_pcmu_events) / sizeof (pcmu_kev_mask_t);
163125cf1a30Sjl 		pcmu_name_kstat->pic_shift[0] = PCMU_SHIFT_PIC0;
163225cf1a30Sjl 		pcmu_name_kstat->pic_shift[1] = PCMU_SHIFT_PIC1;
163325cf1a30Sjl 		pcmu_create_name_kstat("pcmup",
1634c9b6d37cSfherard 		    pcmu_name_kstat, pcicmu_pcmu_events);
163525cf1a30Sjl 	}
163625cf1a30Sjl }
163725cf1a30Sjl 
163825cf1a30Sjl /*
163925cf1a30Sjl  * Called from _fini()
164025cf1a30Sjl  */
164125cf1a30Sjl void
pcmu_kstat_fini()164225cf1a30Sjl pcmu_kstat_fini()
164325cf1a30Sjl {
164425cf1a30Sjl 	if (pcmu_name_kstat != NULL) {
164525cf1a30Sjl 		pcmu_delete_name_kstat(pcmu_name_kstat);
164625cf1a30Sjl 		kmem_free(pcmu_name_kstat, sizeof (pcmu_ksinfo_t));
164725cf1a30Sjl 		pcmu_name_kstat = NULL;
164825cf1a30Sjl 	}
164925cf1a30Sjl }
165025cf1a30Sjl 
165125cf1a30Sjl /*
165225cf1a30Sjl  * Create the performance 'counters' kstat.
165325cf1a30Sjl  */
165425cf1a30Sjl void
pcmu_add_upstream_kstat(pcmu_t * pcmu_p)165525cf1a30Sjl pcmu_add_upstream_kstat(pcmu_t *pcmu_p)
165625cf1a30Sjl {
165725cf1a30Sjl 	pcmu_cntr_pa_t	*cntr_pa_p = &pcmu_p->pcmu_uks_pa;
165825cf1a30Sjl 	uint64_t regbase = va_to_pa((void *)get_reg_base(pcmu_p));
165925cf1a30Sjl 
166025cf1a30Sjl 	cntr_pa_p->pcr_pa = regbase + PCMU_PERF_PCR_OFFSET;
166125cf1a30Sjl 	cntr_pa_p->pic_pa = regbase + PCMU_PERF_PIC_OFFSET;
166225cf1a30Sjl 	pcmu_p->pcmu_uksp = pcmu_create_cntr_kstat(pcmu_p, "pcmup",
1663c9b6d37cSfherard 	    NUM_OF_PICS, pcmu_cntr_kstat_pa_update, cntr_pa_p);
166425cf1a30Sjl }
166525cf1a30Sjl 
166625cf1a30Sjl /*
166725cf1a30Sjl  * u2u_ittrans_init() is caled from in pci.c's pcmu_cb_setup() per CMU.
166825cf1a30Sjl  * Second argument "ittrans_cookie" is address of pcb_ittrans_cookie in
166925cf1a30Sjl  * pcb_p member. allocated interrupt block is returned in it.
167025cf1a30Sjl  */
167125cf1a30Sjl static void
u2u_ittrans_init(pcmu_t * pcmu_p,u2u_ittrans_data_t ** ittrans_cookie)167225cf1a30Sjl u2u_ittrans_init(pcmu_t *pcmu_p, u2u_ittrans_data_t **ittrans_cookie)
167325cf1a30Sjl {
167425cf1a30Sjl 
167525cf1a30Sjl 	u2u_ittrans_data_t *u2u_trans_p;
167625cf1a30Sjl 	ddi_device_acc_attr_t attr;
167725cf1a30Sjl 	int ret;
167825cf1a30Sjl 	int board;
167925cf1a30Sjl 
168025cf1a30Sjl 	/*
168125cf1a30Sjl 	 * Allocate the data structure to support U2U's
168225cf1a30Sjl 	 * interrupt target translations.
168325cf1a30Sjl 	 */
168425cf1a30Sjl 	u2u_trans_p = (u2u_ittrans_data_t *)
168525cf1a30Sjl 	    kmem_zalloc(sizeof (u2u_ittrans_data_t), KM_SLEEP);
168625cf1a30Sjl 
168725cf1a30Sjl 	/*
168825cf1a30Sjl 	 * Get other properties, "board#"
168925cf1a30Sjl 	 */
169025cf1a30Sjl 	board = ddi_getprop(DDI_DEV_T_ANY, pcmu_p->pcmu_dip,
169125cf1a30Sjl 	    DDI_PROP_DONTPASS, "board#", -1);
169225cf1a30Sjl 
169325cf1a30Sjl 	u2u_trans_p->u2u_board = board;
169425cf1a30Sjl 
169525cf1a30Sjl 	if (board == -1) {
169625cf1a30Sjl 		/* this cannot happen on production systems */
169725cf1a30Sjl 		cmn_err(CE_PANIC, "u2u:Invalid property;board = %d", board);
169825cf1a30Sjl 	}
169925cf1a30Sjl 
170025cf1a30Sjl 	/*
170125cf1a30Sjl 	 * Initialize interrupt target translations mutex.
170225cf1a30Sjl 	 */
170325cf1a30Sjl 	mutex_init(&(u2u_trans_p->u2u_ittrans_lock), "u2u_ittrans_lock",
170425cf1a30Sjl 	    MUTEX_DEFAULT, NULL);
170525cf1a30Sjl 
170625cf1a30Sjl 	/*
170725cf1a30Sjl 	 * Get U2U's registers space by ddi_regs_map_setup(9F)
170825cf1a30Sjl 	 */
170925cf1a30Sjl 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
171025cf1a30Sjl 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
171125cf1a30Sjl 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
171225cf1a30Sjl 
171325cf1a30Sjl 	ret = ddi_regs_map_setup(pcmu_p->pcmu_dip,
171425cf1a30Sjl 	    REGS_INDEX_OF_U2U, (caddr_t *)(&(u2u_trans_p->u2u_regs_base)),
171525cf1a30Sjl 	    0, 0, &attr, &(u2u_trans_p->u2u_acc));
171625cf1a30Sjl 
171725cf1a30Sjl 	/*
171825cf1a30Sjl 	 * check result of ddi_regs_map_setup().
171925cf1a30Sjl 	 */
172025cf1a30Sjl 	if (ret != DDI_SUCCESS) {
172125cf1a30Sjl 		cmn_err(CE_PANIC, "u2u%d: registers map setup failed", board);
172225cf1a30Sjl 	}
172325cf1a30Sjl 
172425cf1a30Sjl 	/*
172525cf1a30Sjl 	 * Read Port-id(1 byte) in u2u
172625cf1a30Sjl 	 */
172725cf1a30Sjl 	u2u_trans_p->u2u_port_id = *(volatile int32_t *)
172825cf1a30Sjl 	    (u2u_trans_p->u2u_regs_base + U2U_PID_REGISTER_OFFSET);
172925cf1a30Sjl 
173025cf1a30Sjl 	if (pcmu_p->pcmu_id != u2u_trans_p->u2u_port_id) {
173125cf1a30Sjl 		cmn_err(CE_PANIC, "u2u%d: Invalid Port-ID", board);
173225cf1a30Sjl 	}
173325cf1a30Sjl 
173425cf1a30Sjl 	*ittrans_cookie = u2u_trans_p;
173525cf1a30Sjl }
173625cf1a30Sjl 
173725cf1a30Sjl /*
173825cf1a30Sjl  * u2u_ittras_resume() is called from pcmu_obj_resume() at DDI_RESUME entry.
173925cf1a30Sjl  */
174025cf1a30Sjl static void
u2u_ittrans_resume(u2u_ittrans_data_t ** ittrans_cookie)174125cf1a30Sjl u2u_ittrans_resume(u2u_ittrans_data_t **ittrans_cookie)
174225cf1a30Sjl {
174325cf1a30Sjl 
174425cf1a30Sjl 	u2u_ittrans_data_t *u2u_trans_p;
174525cf1a30Sjl 	u2u_ittrans_id_t *ittrans_id_p;
174625cf1a30Sjl 	uintptr_t  data_reg_addr;
174725cf1a30Sjl 	int ix;
174825cf1a30Sjl 
174925cf1a30Sjl 	u2u_trans_p = *ittrans_cookie;
175025cf1a30Sjl 
175125cf1a30Sjl 	/*
175225cf1a30Sjl 	 * Set U2U Data Register
175325cf1a30Sjl 	 */
175425cf1a30Sjl 	for (ix = 0; ix < U2U_DATA_NUM; ix++) {
175525cf1a30Sjl 		ittrans_id_p = &(u2u_trans_p->u2u_ittrans_id[ix]);
175625cf1a30Sjl 		data_reg_addr = u2u_trans_p->u2u_regs_base +
175725cf1a30Sjl 		    U2U_DATA_REGISTER_OFFSET + (ix * sizeof (uint64_t));
175825cf1a30Sjl 		if (ittrans_id_p->u2u_ino_map_reg == NULL) {
175925cf1a30Sjl 			/* This index was not set */
176025cf1a30Sjl 			continue;
176125cf1a30Sjl 		}
176225cf1a30Sjl 		*(volatile uint32_t *) (data_reg_addr) =
176325cf1a30Sjl 		    (uint32_t)ittrans_id_p->u2u_tgt_cpu_id;
176425cf1a30Sjl 
176525cf1a30Sjl 	}
176625cf1a30Sjl }
176725cf1a30Sjl 
176825cf1a30Sjl /*
176925cf1a30Sjl  * u2u_ittras_uninit() is called from ib_destroy() at detach,
177025cf1a30Sjl  * or occuring error in attach.
177125cf1a30Sjl  */
177225cf1a30Sjl static void
u2u_ittrans_uninit(u2u_ittrans_data_t * ittrans_cookie)177325cf1a30Sjl u2u_ittrans_uninit(u2u_ittrans_data_t *ittrans_cookie)
177425cf1a30Sjl {
177525cf1a30Sjl 
177625cf1a30Sjl 	if (ittrans_cookie == NULL) {
177725cf1a30Sjl 		return;	/* not support */
177825cf1a30Sjl 	}
177925cf1a30Sjl 
178025cf1a30Sjl 	if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) {
178125cf1a30Sjl 		return;	 /* illeagal case */
178225cf1a30Sjl 	}
178325cf1a30Sjl 
178425cf1a30Sjl 	ddi_regs_map_free(&(ittrans_cookie->u2u_acc));
178525cf1a30Sjl 	mutex_destroy(&(ittrans_cookie->u2u_ittrans_lock));
178625cf1a30Sjl 	kmem_free((void *)ittrans_cookie, sizeof (u2u_ittrans_data_t));
178725cf1a30Sjl }
178825cf1a30Sjl 
178925cf1a30Sjl /*
179025cf1a30Sjl  * This routine,u2u_translate_tgtid(, , cpu_id, pino_map_reg),
179125cf1a30Sjl  * searches index having same value of pino_map_reg, or empty.
179225cf1a30Sjl  * Then, stores cpu_id in a U2U Data Register as this index,
179325cf1a30Sjl  * and return this index.
179425cf1a30Sjl  */
179525cf1a30Sjl int
u2u_translate_tgtid(pcmu_t * pcmu_p,uint_t cpu_id,volatile uint64_t * pino_map_reg)179625cf1a30Sjl u2u_translate_tgtid(pcmu_t *pcmu_p, uint_t cpu_id,
179725cf1a30Sjl     volatile uint64_t *pino_map_reg)
179825cf1a30Sjl {
179925cf1a30Sjl 
180025cf1a30Sjl 	int index = -1;
180125cf1a30Sjl 	int ix;
180225cf1a30Sjl 	int err_level;	/* severity level for cmn_err */
180325cf1a30Sjl 	u2u_ittrans_id_t *ittrans_id_p;
180425cf1a30Sjl 	uintptr_t  data_reg_addr;
180525cf1a30Sjl 	u2u_ittrans_data_t *ittrans_cookie;
180625cf1a30Sjl 
180725cf1a30Sjl 	ittrans_cookie =
1808c9b6d37cSfherard 	    (u2u_ittrans_data_t *)(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie);
180925cf1a30Sjl 
181025cf1a30Sjl 	if (ittrans_cookie == NULL) {
181125cf1a30Sjl 		return (cpu_id);
181225cf1a30Sjl 	}
181325cf1a30Sjl 
181425cf1a30Sjl 	if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) {
181525cf1a30Sjl 		return (-1);	 /* illeagal case */
181625cf1a30Sjl 	}
181725cf1a30Sjl 
181825cf1a30Sjl 	mutex_enter(&(ittrans_cookie->u2u_ittrans_lock));
181925cf1a30Sjl 
182025cf1a30Sjl 	/*
182125cf1a30Sjl 	 * Decide index No. of U2U Data registers in either
182225cf1a30Sjl 	 * already used by same pino_map_reg, or empty.
182325cf1a30Sjl 	 */
182425cf1a30Sjl 	for (ix = 0; ix < U2U_DATA_NUM; ix++) {
182525cf1a30Sjl 		ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]);
182625cf1a30Sjl 		if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) {
182725cf1a30Sjl 			/* already used this pino_map_reg */
182825cf1a30Sjl 			index = ix;
182925cf1a30Sjl 			break;
183025cf1a30Sjl 		}
183125cf1a30Sjl 		if (index == -1 &&
1832c9b6d37cSfherard 		    ittrans_id_p->u2u_ino_map_reg == NULL) {
183325cf1a30Sjl 			index = ix;
183425cf1a30Sjl 		}
183525cf1a30Sjl 	}
183625cf1a30Sjl 
183725cf1a30Sjl 	if (index == -1) {
183825cf1a30Sjl 		if (panicstr) {
183925cf1a30Sjl 			err_level = CE_WARN;
184025cf1a30Sjl 		} else {
184125cf1a30Sjl 			err_level = CE_PANIC;
184225cf1a30Sjl 		}
184325cf1a30Sjl 		cmn_err(err_level, "u2u%d:No more U2U-Data regs!!",
1844c9b6d37cSfherard 		    ittrans_cookie->u2u_board);
184525cf1a30Sjl 		return (cpu_id);
184625cf1a30Sjl 	}
184725cf1a30Sjl 
184825cf1a30Sjl 	/*
184925cf1a30Sjl 	 * For U2U
185025cf1a30Sjl 	 * set cpu_id into u2u_data_reg by index.
185125cf1a30Sjl 	 * ((uint64_t)(u2u_regs_base
185225cf1a30Sjl 	 *	+ U2U_DATA_REGISTER_OFFSET))[index] = cpu_id;
185325cf1a30Sjl 	 */
185425cf1a30Sjl 
185525cf1a30Sjl 	data_reg_addr = ittrans_cookie->u2u_regs_base
1856c9b6d37cSfherard 	    + U2U_DATA_REGISTER_OFFSET
1857c9b6d37cSfherard 	    + (index * sizeof (uint64_t));
185825cf1a30Sjl 
185925cf1a30Sjl 	/*
186025cf1a30Sjl 	 * Set cpu_id into U2U Data register[index]
186125cf1a30Sjl 	 */
186225cf1a30Sjl 	*(volatile uint32_t *) (data_reg_addr) = (uint32_t)cpu_id;
186325cf1a30Sjl 
186425cf1a30Sjl 	/*
186525cf1a30Sjl 	 * Setup for software, excepting at panicing.
186625cf1a30Sjl 	 * and rebooting, etc...?
186725cf1a30Sjl 	 */
186825cf1a30Sjl 	if (!panicstr) {
186925cf1a30Sjl 		ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[index]);
187025cf1a30Sjl 		ittrans_id_p->u2u_tgt_cpu_id = cpu_id;
187125cf1a30Sjl 		ittrans_id_p->u2u_ino_map_reg = pino_map_reg;
187225cf1a30Sjl 	}
187325cf1a30Sjl 
187425cf1a30Sjl 	mutex_exit(&(ittrans_cookie->u2u_ittrans_lock));
187525cf1a30Sjl 
187625cf1a30Sjl 	return (index);
187725cf1a30Sjl }
187825cf1a30Sjl 
187925cf1a30Sjl /*
188025cf1a30Sjl  * u2u_ittrans_cleanup() is called from common_pcmu_ib_intr_disable()
188125cf1a30Sjl  * after called intr_rem_cpu(mondo).
188225cf1a30Sjl  */
188325cf1a30Sjl void
u2u_ittrans_cleanup(u2u_ittrans_data_t * ittrans_cookie,volatile uint64_t * pino_map_reg)188425cf1a30Sjl u2u_ittrans_cleanup(u2u_ittrans_data_t *ittrans_cookie,
188525cf1a30Sjl 			volatile uint64_t *pino_map_reg)
188625cf1a30Sjl {
188725cf1a30Sjl 
188825cf1a30Sjl 	int ix;
188925cf1a30Sjl 	u2u_ittrans_id_t *ittrans_id_p;
189025cf1a30Sjl 
189125cf1a30Sjl 	if (ittrans_cookie == NULL) {
189225cf1a30Sjl 		return;
189325cf1a30Sjl 	}
189425cf1a30Sjl 
189525cf1a30Sjl 	if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) {
189625cf1a30Sjl 		return;	 /* illeagal case */
189725cf1a30Sjl 	}
189825cf1a30Sjl 
189925cf1a30Sjl 	mutex_enter(&(ittrans_cookie->u2u_ittrans_lock));
190025cf1a30Sjl 
190125cf1a30Sjl 	for (ix = 0; ix < U2U_DATA_NUM; ix++) {
190225cf1a30Sjl 		ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]);
190325cf1a30Sjl 		if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) {
190425cf1a30Sjl 			ittrans_id_p->u2u_ino_map_reg = NULL;
190525cf1a30Sjl 			break;
190625cf1a30Sjl 		}
190725cf1a30Sjl 	}
190825cf1a30Sjl 
190925cf1a30Sjl 	mutex_exit(&(ittrans_cookie->u2u_ittrans_lock));
191025cf1a30Sjl }
191125cf1a30Sjl 
191225cf1a30Sjl /*
191325cf1a30Sjl  * pcmu_ecc_classify, called by ecc_handler to classify ecc errors
191425cf1a30Sjl  * and determine if we should panic or not.
191525cf1a30Sjl  */
191625cf1a30Sjl void
pcmu_ecc_classify(uint64_t err,pcmu_ecc_errstate_t * ecc_err_p)191725cf1a30Sjl pcmu_ecc_classify(uint64_t err, pcmu_ecc_errstate_t *ecc_err_p)
191825cf1a30Sjl {
191925cf1a30Sjl 	struct async_flt *ecc = &ecc_err_p->ecc_aflt;
192025cf1a30Sjl 	/* LINTED */
192125cf1a30Sjl 	pcmu_t *pcmu_p = ecc_err_p->ecc_ii_p.pecc_p->pecc_pcmu_p;
192225cf1a30Sjl 
192325cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
192425cf1a30Sjl 
192525cf1a30Sjl 	ecc_err_p->ecc_bridge_type = PCI_OPLCMU;	/* RAGS */
192625cf1a30Sjl 	/*
192725cf1a30Sjl 	 * Get the parent bus id that caused the error.
192825cf1a30Sjl 	 */
192925cf1a30Sjl 	ecc_err_p->ecc_dev_id = (ecc_err_p->ecc_afsr & PCMU_ECC_UE_AFSR_ID)
1930c9b6d37cSfherard 	    >> PCMU_ECC_UE_AFSR_ID_SHIFT;
193125cf1a30Sjl 	/*
193225cf1a30Sjl 	 * Determine the doubleword offset of the error.
193325cf1a30Sjl 	 */
193425cf1a30Sjl 	ecc_err_p->ecc_dw_offset = (ecc_err_p->ecc_afsr &
193525cf1a30Sjl 	    PCMU_ECC_UE_AFSR_DW_OFFSET) >> PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT;
193625cf1a30Sjl 	/*
193725cf1a30Sjl 	 * Determine the primary error type.
193825cf1a30Sjl 	 */
193925cf1a30Sjl 	switch (err) {
194025cf1a30Sjl 	case PCMU_ECC_UE_AFSR_E_PIO:
194125cf1a30Sjl 		if (ecc_err_p->pecc_pri) {
194225cf1a30Sjl 			ecc->flt_erpt_class = PCI_ECC_PIO_UE;
194325cf1a30Sjl 		} else {
194425cf1a30Sjl 			ecc->flt_erpt_class = PCI_ECC_SEC_PIO_UE;
194525cf1a30Sjl 		}
194625cf1a30Sjl 		/* For CMU-CH, a UE is always fatal. */
194725cf1a30Sjl 		ecc->flt_panic = 1;
194825cf1a30Sjl 		break;
194925cf1a30Sjl 
195025cf1a30Sjl 	default:
195125cf1a30Sjl 		return;
195225cf1a30Sjl 	}
195325cf1a30Sjl }
195425cf1a30Sjl 
195525cf1a30Sjl /*
195625cf1a30Sjl  * pcmu_pbm_classify, called by pcmu_pbm_afsr_report to classify piow afsr.
195725cf1a30Sjl  */
195825cf1a30Sjl int
pcmu_pbm_classify(pcmu_pbm_errstate_t * pbm_err_p)195925cf1a30Sjl pcmu_pbm_classify(pcmu_pbm_errstate_t *pbm_err_p)
196025cf1a30Sjl {
196125cf1a30Sjl 	uint32_t e;
196225cf1a30Sjl 	int nerr = 0;
196325cf1a30Sjl 	char **tmp_class;
196425cf1a30Sjl 
196525cf1a30Sjl 	if (pbm_err_p->pcbm_pri) {
196625cf1a30Sjl 		tmp_class = &pbm_err_p->pcbm_pci.pcmu_err_class;
196725cf1a30Sjl 		e = PBM_AFSR_TO_PRIERR(pbm_err_p->pbm_afsr);
196825cf1a30Sjl 		pbm_err_p->pbm_log = FM_LOG_PCI;
196925cf1a30Sjl 	} else {
197025cf1a30Sjl 		tmp_class = &pbm_err_p->pbm_err_class;
197125cf1a30Sjl 		e = PBM_AFSR_TO_SECERR(pbm_err_p->pbm_afsr);
197225cf1a30Sjl 		pbm_err_p->pbm_log = FM_LOG_PBM;
197325cf1a30Sjl 	}
197425cf1a30Sjl 
197525cf1a30Sjl 	if (e & PCMU_PCI_AFSR_E_MA) {
197625cf1a30Sjl 		*tmp_class = pbm_err_p->pcbm_pri ? PCI_MA : PCI_SEC_MA;
197725cf1a30Sjl 		nerr++;
197825cf1a30Sjl 	}
197925cf1a30Sjl 	return (nerr);
198025cf1a30Sjl }
198125cf1a30Sjl 
198225cf1a30Sjl /*
198325cf1a30Sjl  * Function used to clear PBM/PCI/IOMMU error state after error handling
198425cf1a30Sjl  * is complete. Only clearing error bits which have been logged. Called by
198525cf1a30Sjl  * pcmu_pbm_err_handler and pcmu_bus_exit.
198625cf1a30Sjl  */
198725cf1a30Sjl static void
pcmu_clear_error(pcmu_t * pcmu_p,pcmu_pbm_errstate_t * pbm_err_p)198825cf1a30Sjl pcmu_clear_error(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p)
198925cf1a30Sjl {
199025cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
199125cf1a30Sjl 
199225cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcbm_p->pcbm_pcmu_p->pcmu_err_mutex));
199325cf1a30Sjl 
199425cf1a30Sjl 	*pcbm_p->pcbm_ctrl_reg = pbm_err_p->pbm_ctl_stat;
199525cf1a30Sjl 	*pcbm_p->pcbm_async_flt_status_reg = pbm_err_p->pbm_afsr;
199625cf1a30Sjl 	pcbm_p->pcbm_config_header->ch_status_reg =
1997c9b6d37cSfherard 	    pbm_err_p->pcbm_pci.pcmu_cfg_stat;
199825cf1a30Sjl }
199925cf1a30Sjl 
200025cf1a30Sjl /*ARGSUSED*/
200125cf1a30Sjl int
pcmu_pbm_err_handler(dev_info_t * dip,ddi_fm_error_t * derr,const void * impl_data,int caller)200225cf1a30Sjl pcmu_pbm_err_handler(dev_info_t *dip, ddi_fm_error_t *derr,
200325cf1a30Sjl 		const void *impl_data, int caller)
200425cf1a30Sjl {
200525cf1a30Sjl 	int fatal = 0;
200625cf1a30Sjl 	int nonfatal = 0;
200725cf1a30Sjl 	int unknown = 0;
200825cf1a30Sjl 	uint32_t prierr, secerr;
200925cf1a30Sjl 	pcmu_pbm_errstate_t pbm_err;
201025cf1a30Sjl 	pcmu_t *pcmu_p = (pcmu_t *)impl_data;
201125cf1a30Sjl 	int ret = 0;
201225cf1a30Sjl 
201325cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
201425cf1a30Sjl 	pcmu_pbm_errstate_get(pcmu_p, &pbm_err);
201525cf1a30Sjl 
201625cf1a30Sjl 	derr->fme_ena = derr->fme_ena ? derr->fme_ena :
201725cf1a30Sjl 	    fm_ena_generate(0, FM_ENA_FMT1);
201825cf1a30Sjl 
201925cf1a30Sjl 	prierr = PBM_AFSR_TO_PRIERR(pbm_err.pbm_afsr);
202025cf1a30Sjl 	secerr = PBM_AFSR_TO_SECERR(pbm_err.pbm_afsr);
202125cf1a30Sjl 
202225cf1a30Sjl 	if (derr->fme_flag == DDI_FM_ERR_PEEK) {
202325cf1a30Sjl 		/*
202425cf1a30Sjl 		 * For ddi_peek treat all events as nonfatal. We only
202525cf1a30Sjl 		 * really call this function so that pcmu_clear_error()
202625cf1a30Sjl 		 * and ndi_fm_handler_dispatch() will get called.
202725cf1a30Sjl 		 */
202825cf1a30Sjl 		nonfatal++;
202925cf1a30Sjl 		goto done;
203025cf1a30Sjl 	} else if (derr->fme_flag == DDI_FM_ERR_POKE) {
203125cf1a30Sjl 		/*
203225cf1a30Sjl 		 * For ddi_poke we can treat as nonfatal if the
203325cf1a30Sjl 		 * following conditions are met :
203425cf1a30Sjl 		 * 1. Make sure only primary error is MA/TA
203525cf1a30Sjl 		 * 2. Make sure no secondary error
203625cf1a30Sjl 		 * 3. check pci config header stat reg to see MA/TA is
203725cf1a30Sjl 		 *    logged. We cannot verify only MA/TA is recorded
203825cf1a30Sjl 		 *    since it gets much more complicated when a
203925cf1a30Sjl 		 *    PCI-to-PCI bridge is present.
204025cf1a30Sjl 		 */
204125cf1a30Sjl 		if ((prierr == PCMU_PCI_AFSR_E_MA) && !secerr &&
204225cf1a30Sjl 		    (pbm_err.pcbm_pci.pcmu_cfg_stat & PCI_STAT_R_MAST_AB)) {
204325cf1a30Sjl 			nonfatal++;
204425cf1a30Sjl 			goto done;
204525cf1a30Sjl 		}
204625cf1a30Sjl 	}
204725cf1a30Sjl 
204825cf1a30Sjl 	if (prierr || secerr) {
204925cf1a30Sjl 		ret = pcmu_pbm_afsr_report(dip, derr->fme_ena, &pbm_err);
205025cf1a30Sjl 		if (ret == DDI_FM_FATAL) {
205125cf1a30Sjl 			fatal++;
205225cf1a30Sjl 		} else {
205325cf1a30Sjl 			nonfatal++;
205425cf1a30Sjl 		}
205525cf1a30Sjl 	}
205625cf1a30Sjl 
205725cf1a30Sjl 	ret = pcmu_cfg_report(dip, derr, &pbm_err.pcbm_pci, caller, prierr);
205825cf1a30Sjl 	if (ret == DDI_FM_FATAL) {
205925cf1a30Sjl 		fatal++;
206025cf1a30Sjl 	} else if (ret == DDI_FM_NONFATAL) {
206125cf1a30Sjl 		nonfatal++;
206225cf1a30Sjl 	}
206325cf1a30Sjl 
206425cf1a30Sjl done:
206525cf1a30Sjl 	if (ret == DDI_FM_FATAL) {
206625cf1a30Sjl 		fatal++;
206725cf1a30Sjl 	} else if (ret == DDI_FM_NONFATAL) {
206825cf1a30Sjl 		nonfatal++;
206925cf1a30Sjl 	} else if (ret == DDI_FM_UNKNOWN) {
207025cf1a30Sjl 		unknown++;
207125cf1a30Sjl 	}
207225cf1a30Sjl 
207325cf1a30Sjl 	/* Cleanup and reset error bits */
207425cf1a30Sjl 	pcmu_clear_error(pcmu_p, &pbm_err);
207525cf1a30Sjl 
207625cf1a30Sjl 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
207725cf1a30Sjl 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
207825cf1a30Sjl }
207925cf1a30Sjl 
208025cf1a30Sjl int
pcmu_check_error(pcmu_t * pcmu_p)208125cf1a30Sjl pcmu_check_error(pcmu_t *pcmu_p)
208225cf1a30Sjl {
208325cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
208425cf1a30Sjl 	uint16_t pcmu_cfg_stat;
208525cf1a30Sjl 	uint64_t pbm_afsr;
208625cf1a30Sjl 
208725cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
208825cf1a30Sjl 
208925cf1a30Sjl 	pcmu_cfg_stat = pcbm_p->pcbm_config_header->ch_status_reg;
209025cf1a30Sjl 	pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
209125cf1a30Sjl 
209225cf1a30Sjl 	if ((pcmu_cfg_stat & (PCI_STAT_S_PERROR | PCI_STAT_S_TARG_AB |
2093c9b6d37cSfherard 	    PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB |
2094c9b6d37cSfherard 	    PCI_STAT_S_SYSERR | PCI_STAT_PERROR)) ||
2095c9b6d37cSfherard 	    (PBM_AFSR_TO_PRIERR(pbm_afsr))) {
209625cf1a30Sjl 		return (1);
209725cf1a30Sjl 	}
209825cf1a30Sjl 	return (0);
209925cf1a30Sjl 
210025cf1a30Sjl }
210125cf1a30Sjl 
210225cf1a30Sjl /*
210325cf1a30Sjl  * Function used to gather PBM/PCI error state for the
210425cf1a30Sjl  * pcmu_pbm_err_handler. This function must be called while pcmu_err_mutex
210525cf1a30Sjl  * is held.
210625cf1a30Sjl  */
210725cf1a30Sjl static void
pcmu_pbm_errstate_get(pcmu_t * pcmu_p,pcmu_pbm_errstate_t * pbm_err_p)210825cf1a30Sjl pcmu_pbm_errstate_get(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p)
210925cf1a30Sjl {
211025cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
211125cf1a30Sjl 
211225cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
211325cf1a30Sjl 	bzero(pbm_err_p, sizeof (pcmu_pbm_errstate_t));
211425cf1a30Sjl 
211525cf1a30Sjl 	/*
211625cf1a30Sjl 	 * Capture all pbm error state for later logging
211725cf1a30Sjl 	 */
211825cf1a30Sjl 	pbm_err_p->pbm_bridge_type = PCI_OPLCMU;	/* RAGS */
211925cf1a30Sjl 	pbm_err_p->pcbm_pci.pcmu_cfg_stat =
212025cf1a30Sjl 	    pcbm_p->pcbm_config_header->ch_status_reg;
212125cf1a30Sjl 	pbm_err_p->pbm_ctl_stat = *pcbm_p->pcbm_ctrl_reg;
212225cf1a30Sjl 	pbm_err_p->pcbm_pci.pcmu_cfg_comm =
212325cf1a30Sjl 	    pcbm_p->pcbm_config_header->ch_command_reg;
212425cf1a30Sjl 	pbm_err_p->pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
212525cf1a30Sjl 	pbm_err_p->pbm_afar = *pcbm_p->pcbm_async_flt_addr_reg;
212625cf1a30Sjl 	pbm_err_p->pcbm_pci.pcmu_pa = *pcbm_p->pcbm_async_flt_addr_reg;
212725cf1a30Sjl }
212825cf1a30Sjl 
212925cf1a30Sjl static void
pcmu_pbm_clear_error(pcmu_pbm_t * pcbm_p)213025cf1a30Sjl pcmu_pbm_clear_error(pcmu_pbm_t *pcbm_p)
213125cf1a30Sjl {
213225cf1a30Sjl 	uint64_t pbm_afsr;
213325cf1a30Sjl 
213425cf1a30Sjl 	/*
213525cf1a30Sjl 	 * for poke() support - called from POKE_FLUSH. Spin waiting
213625cf1a30Sjl 	 * for MA, TA or SERR to be cleared by a pcmu_pbm_error_intr().
213725cf1a30Sjl 	 * We have to wait for SERR too in case the device is beyond
213825cf1a30Sjl 	 * a pci-pci bridge.
213925cf1a30Sjl 	 */
214025cf1a30Sjl 	pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
214125cf1a30Sjl 	while (((pbm_afsr >> PCMU_PCI_AFSR_PE_SHIFT) &
214225cf1a30Sjl 	    (PCMU_PCI_AFSR_E_MA | PCMU_PCI_AFSR_E_TA))) {
214325cf1a30Sjl 		pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
214425cf1a30Sjl 	}
214525cf1a30Sjl }
214625cf1a30Sjl 
214725cf1a30Sjl void
pcmu_err_create(pcmu_t * pcmu_p)214825cf1a30Sjl pcmu_err_create(pcmu_t *pcmu_p)
214925cf1a30Sjl {
215025cf1a30Sjl 	/*
215125cf1a30Sjl 	 * PCI detected ECC errorq, to schedule async handling
215225cf1a30Sjl 	 * of ECC errors and logging.
215325cf1a30Sjl 	 * The errorq is created here but destroyed when _fini is called
215425cf1a30Sjl 	 * for the pci module.
215525cf1a30Sjl 	 */
215625cf1a30Sjl 	if (pcmu_ecc_queue == NULL) {
215725cf1a30Sjl 		pcmu_ecc_queue = errorq_create("pcmu_ecc_queue",
2158c9b6d37cSfherard 		    (errorq_func_t)pcmu_ecc_err_drain,
2159c9b6d37cSfherard 		    (void *)NULL,
2160c9b6d37cSfherard 		    ECC_MAX_ERRS, sizeof (pcmu_ecc_errstate_t),
2161c9b6d37cSfherard 		    PIL_2, ERRORQ_VITAL);
216225cf1a30Sjl 		if (pcmu_ecc_queue == NULL)
216325cf1a30Sjl 			panic("failed to create required system error queue");
216425cf1a30Sjl 	}
216525cf1a30Sjl 
216625cf1a30Sjl 	/*
216725cf1a30Sjl 	 * Initialize error handling mutex.
216825cf1a30Sjl 	 */
216925cf1a30Sjl 	mutex_init(&pcmu_p->pcmu_err_mutex, NULL, MUTEX_DRIVER,
2170c9b6d37cSfherard 	    (void *)pcmu_p->pcmu_fm_ibc);
217125cf1a30Sjl }
217225cf1a30Sjl 
217325cf1a30Sjl void
pcmu_err_destroy(pcmu_t * pcmu_p)217425cf1a30Sjl pcmu_err_destroy(pcmu_t *pcmu_p)
217525cf1a30Sjl {
217625cf1a30Sjl 	mutex_destroy(&pcmu_p->pcmu_err_mutex);
217725cf1a30Sjl }
217825cf1a30Sjl 
217925cf1a30Sjl /*
218025cf1a30Sjl  * Function used to post PCI block module specific ereports.
218125cf1a30Sjl  */
218225cf1a30Sjl void
pcmu_pbm_ereport_post(dev_info_t * dip,uint64_t ena,pcmu_pbm_errstate_t * pbm_err)218325cf1a30Sjl pcmu_pbm_ereport_post(dev_info_t *dip, uint64_t ena,
218425cf1a30Sjl     pcmu_pbm_errstate_t *pbm_err)
218525cf1a30Sjl {
218625cf1a30Sjl 	char *aux_msg;
218725cf1a30Sjl 	uint32_t prierr, secerr;
218825cf1a30Sjl 	pcmu_t *pcmu_p;
218925cf1a30Sjl 	int instance = ddi_get_instance(dip);
219025cf1a30Sjl 
219125cf1a30Sjl 	ena = ena ? ena : fm_ena_generate(0, FM_ENA_FMT1);
219225cf1a30Sjl 
219325cf1a30Sjl 	pcmu_p = get_pcmu_soft_state(instance);
219425cf1a30Sjl 	prierr = PBM_AFSR_TO_PRIERR(pbm_err->pbm_afsr);
219525cf1a30Sjl 	secerr = PBM_AFSR_TO_SECERR(pbm_err->pbm_afsr);
219625cf1a30Sjl 	if (prierr)
219725cf1a30Sjl 		aux_msg = "PCI primary error: Master Abort";
219825cf1a30Sjl 	else if (secerr)
219925cf1a30Sjl 		aux_msg = "PCI secondary error: Master Abort";
220025cf1a30Sjl 	else
220125cf1a30Sjl 		aux_msg = "";
220225cf1a30Sjl 	cmn_err(CE_WARN, "%s %s: %s %s=0x%lx, %s=0x%lx, %s=0x%lx %s=0x%x",
2203c9b6d37cSfherard 	    (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str,
2204c9b6d37cSfherard 	    (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str,
2205c9b6d37cSfherard 	    aux_msg,
2206c9b6d37cSfherard 	    PCI_PBM_AFAR, pbm_err->pbm_afar,
2207c9b6d37cSfherard 	    PCI_PBM_AFSR, pbm_err->pbm_afsr,
2208c9b6d37cSfherard 	    PCI_PBM_CSR, pbm_err->pbm_ctl_stat,
2209c9b6d37cSfherard 	    "portid", pcmu_p->pcmu_id);
221025cf1a30Sjl }
2211