xref: /illumos-gate/usr/src/uts/sun4u/opl/io/pcicmu/pcicmu.c (revision 25cf1a30)
1*25cf1a30Sjl /*
2*25cf1a30Sjl  * CDDL HEADER START
3*25cf1a30Sjl  *
4*25cf1a30Sjl  * The contents of this file are subject to the terms of the
5*25cf1a30Sjl  * Common Development and Distribution License (the "License").
6*25cf1a30Sjl  * You may not use this file except in compliance with the License.
7*25cf1a30Sjl  *
8*25cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
10*25cf1a30Sjl  * See the License for the specific language governing permissions
11*25cf1a30Sjl  * and limitations under the License.
12*25cf1a30Sjl  *
13*25cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
14*25cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
16*25cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*25cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*25cf1a30Sjl  *
19*25cf1a30Sjl  * CDDL HEADER END
20*25cf1a30Sjl  */
21*25cf1a30Sjl /*
22*25cf1a30Sjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*25cf1a30Sjl  * Use is subject to license terms.
24*25cf1a30Sjl  */
25*25cf1a30Sjl 
26*25cf1a30Sjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*25cf1a30Sjl 
28*25cf1a30Sjl /*
29*25cf1a30Sjl  * OPL CMU-CH PCI nexus driver.
30*25cf1a30Sjl  *
31*25cf1a30Sjl  */
32*25cf1a30Sjl 
33*25cf1a30Sjl #include <sys/types.h>
34*25cf1a30Sjl #include <sys/sysmacros.h>
35*25cf1a30Sjl #include <sys/systm.h>
36*25cf1a30Sjl #include <sys/intreg.h>
37*25cf1a30Sjl #include <sys/intr.h>
38*25cf1a30Sjl #include <sys/machsystm.h>
39*25cf1a30Sjl #include <sys/conf.h>
40*25cf1a30Sjl #include <sys/stat.h>
41*25cf1a30Sjl #include <sys/kmem.h>
42*25cf1a30Sjl #include <sys/async.h>
43*25cf1a30Sjl #include <sys/ivintr.h>
44*25cf1a30Sjl #include <sys/sunddi.h>
45*25cf1a30Sjl #include <sys/sunndi.h>
46*25cf1a30Sjl #include <sys/ndifm.h>
47*25cf1a30Sjl #include <sys/ontrap.h>
48*25cf1a30Sjl #include <sys/ddi_impldefs.h>
49*25cf1a30Sjl #include <sys/ddi_subrdefs.h>
50*25cf1a30Sjl #include <sys/epm.h>
51*25cf1a30Sjl #include <sys/spl.h>
52*25cf1a30Sjl #include <sys/fm/util.h>
53*25cf1a30Sjl #include <sys/fm/util.h>
54*25cf1a30Sjl #include <sys/fm/protocol.h>
55*25cf1a30Sjl #include <sys/fm/io/pci.h>
56*25cf1a30Sjl #include <sys/fm/io/sun4upci.h>
57*25cf1a30Sjl #include <sys/pcicmu/pcicmu.h>
58*25cf1a30Sjl 
59*25cf1a30Sjl #include <sys/cmn_err.h>
60*25cf1a30Sjl #include <sys/time.h>
61*25cf1a30Sjl #include <sys/pci.h>
62*25cf1a30Sjl #include <sys/modctl.h>
63*25cf1a30Sjl #include <sys/open.h>
64*25cf1a30Sjl #include <sys/errno.h>
65*25cf1a30Sjl #include <sys/file.h>
66*25cf1a30Sjl 
67*25cf1a30Sjl 
68*25cf1a30Sjl uint32_t pcmu_spurintr_duration = 60000000; /* One minute */
69*25cf1a30Sjl 
70*25cf1a30Sjl /*
71*25cf1a30Sjl  * The variable controls the default setting of the command register
72*25cf1a30Sjl  * for pci devices.  See pcmu_init_child() for details.
73*25cf1a30Sjl  *
74*25cf1a30Sjl  * This flags also controls the setting of bits in the bridge control
75*25cf1a30Sjl  * register pci to pci bridges.  See pcmu_init_child() for details.
76*25cf1a30Sjl  */
77*25cf1a30Sjl ushort_t pcmu_command_default = PCI_COMM_SERR_ENABLE |
78*25cf1a30Sjl 				PCI_COMM_WAIT_CYC_ENAB |
79*25cf1a30Sjl 				PCI_COMM_PARITY_DETECT |
80*25cf1a30Sjl 				PCI_COMM_ME |
81*25cf1a30Sjl 				PCI_COMM_MAE |
82*25cf1a30Sjl 				PCI_COMM_IO;
83*25cf1a30Sjl /*
84*25cf1a30Sjl  * The following driver parameters are defined as variables to allow
85*25cf1a30Sjl  * patching for debugging and tuning.  Flags that can be set on a per
86*25cf1a30Sjl  * PBM basis are bit fields where the PBM device instance number maps
87*25cf1a30Sjl  * to the bit position.
88*25cf1a30Sjl  */
89*25cf1a30Sjl #ifdef DEBUG
90*25cf1a30Sjl uint64_t pcmu_debug_flags = 0;
91*25cf1a30Sjl #endif
92*25cf1a30Sjl uint_t ecc_error_intr_enable = 1;
93*25cf1a30Sjl 
94*25cf1a30Sjl uint_t pcmu_ecc_afsr_retries = 100;	/* XXX - what's a good value? */
95*25cf1a30Sjl 
96*25cf1a30Sjl uint_t pcmu_intr_retry_intv = 5;	/* for interrupt retry reg */
97*25cf1a30Sjl uint_t pcmu_panic_on_fatal_errors = 1;	/* should be 1 at beta */
98*25cf1a30Sjl 
99*25cf1a30Sjl hrtime_t pcmu_intrpend_timeout = 5ll * NANOSEC;	/* 5 seconds in nanoseconds */
100*25cf1a30Sjl 
101*25cf1a30Sjl uint64_t pcmu_errtrig_pa = 0x0;
102*25cf1a30Sjl 
103*25cf1a30Sjl 
104*25cf1a30Sjl /*
105*25cf1a30Sjl  * The following value is the number of consecutive unclaimed interrupts that
106*25cf1a30Sjl  * will be tolerated for a particular ino_p before the interrupt is deemed to
107*25cf1a30Sjl  * be jabbering and is blocked.
108*25cf1a30Sjl  */
109*25cf1a30Sjl uint_t pcmu_unclaimed_intr_max = 20;
110*25cf1a30Sjl 
111*25cf1a30Sjl /*
112*25cf1a30Sjl  * function prototypes for dev ops routines:
113*25cf1a30Sjl  */
114*25cf1a30Sjl static int pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
115*25cf1a30Sjl static int pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
116*25cf1a30Sjl static int pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
117*25cf1a30Sjl     void *arg, void **result);
118*25cf1a30Sjl static int pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp);
119*25cf1a30Sjl static int pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp);
120*25cf1a30Sjl static int pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
121*25cf1a30Sjl 						cred_t *credp, int *rvalp);
122*25cf1a30Sjl static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
123*25cf1a30Sjl     int flags, char *name, caddr_t valuep, int *lengthp);
124*25cf1a30Sjl static int pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args);
125*25cf1a30Sjl static int pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args,
126*25cf1a30Sjl     void *result);
127*25cf1a30Sjl 
128*25cf1a30Sjl static int map_pcmu_registers(pcmu_t *, dev_info_t *);
129*25cf1a30Sjl static void unmap_pcmu_registers(pcmu_t *);
130*25cf1a30Sjl static void pcmu_pbm_clear_error(pcmu_pbm_t *);
131*25cf1a30Sjl 
132*25cf1a30Sjl static int pcmu_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
133*25cf1a30Sjl     void *, void *);
134*25cf1a30Sjl static int pcmu_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
135*25cf1a30Sjl     off_t, off_t, caddr_t *);
136*25cf1a30Sjl static int pcmu_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
137*25cf1a30Sjl     ddi_intr_handle_impl_t *, void *);
138*25cf1a30Sjl 
139*25cf1a30Sjl static uint32_t pcmu_identity_init(pcmu_t *pcmu_p);
140*25cf1a30Sjl static int pcmu_intr_setup(pcmu_t *pcmu_p);
141*25cf1a30Sjl static void pcmu_pbm_errstate_get(pcmu_t *pcmu_p,
142*25cf1a30Sjl     pcmu_pbm_errstate_t *pbm_err_p);
143*25cf1a30Sjl static int pcmu_obj_setup(pcmu_t *pcmu_p);
144*25cf1a30Sjl static void pcmu_obj_destroy(pcmu_t *pcmu_p);
145*25cf1a30Sjl static void pcmu_obj_resume(pcmu_t *pcmu_p);
146*25cf1a30Sjl static void pcmu_obj_suspend(pcmu_t *pcmu_p);
147*25cf1a30Sjl 
148*25cf1a30Sjl static void u2u_ittrans_init(pcmu_t *, u2u_ittrans_data_t **);
149*25cf1a30Sjl static void u2u_ittrans_resume(u2u_ittrans_data_t **);
150*25cf1a30Sjl static void u2u_ittrans_uninit(u2u_ittrans_data_t *);
151*25cf1a30Sjl 
152*25cf1a30Sjl static pcmu_ksinfo_t	*pcmu_name_kstat;
153*25cf1a30Sjl 
154*25cf1a30Sjl /*
155*25cf1a30Sjl  * bus ops and dev ops structures:
156*25cf1a30Sjl  */
157*25cf1a30Sjl static struct bus_ops pcmu_bus_ops = {
158*25cf1a30Sjl 	BUSO_REV,
159*25cf1a30Sjl 	pcmu_map,
160*25cf1a30Sjl 	0,
161*25cf1a30Sjl 	0,
162*25cf1a30Sjl 	0,
163*25cf1a30Sjl 	i_ddi_map_fault,
164*25cf1a30Sjl 	0,
165*25cf1a30Sjl 	0,
166*25cf1a30Sjl 	0,
167*25cf1a30Sjl 	0,
168*25cf1a30Sjl 	0,
169*25cf1a30Sjl 	0,
170*25cf1a30Sjl 	0,
171*25cf1a30Sjl 	0,
172*25cf1a30Sjl 	pcmu_ctlops,
173*25cf1a30Sjl 	ddi_bus_prop_op,
174*25cf1a30Sjl 	ndi_busop_get_eventcookie,	/* (*bus_get_eventcookie)(); */
175*25cf1a30Sjl 	ndi_busop_add_eventcall,	/* (*bus_add_eventcall)(); */
176*25cf1a30Sjl 	ndi_busop_remove_eventcall,	/* (*bus_remove_eventcall)(); */
177*25cf1a30Sjl 	ndi_post_event,			/* (*bus_post_event)(); */
178*25cf1a30Sjl 	NULL,				/* (*bus_intr_ctl)(); */
179*25cf1a30Sjl 	NULL,				/* (*bus_config)(); */
180*25cf1a30Sjl 	NULL,				/* (*bus_unconfig)(); */
181*25cf1a30Sjl 	NULL,				/* (*bus_fm_init)(); */
182*25cf1a30Sjl 	NULL,				/* (*bus_fm_fini)(); */
183*25cf1a30Sjl 	NULL,				/* (*bus_fm_access_enter)(); */
184*25cf1a30Sjl 	NULL,				/* (*bus_fm_access_fini)(); */
185*25cf1a30Sjl 	NULL,				/* (*bus_power)(); */
186*25cf1a30Sjl 	pcmu_intr_ops			/* (*bus_intr_op)(); */
187*25cf1a30Sjl };
188*25cf1a30Sjl 
189*25cf1a30Sjl struct cb_ops pcmu_cb_ops = {
190*25cf1a30Sjl 	pcmu_open,			/* open */
191*25cf1a30Sjl 	pcmu_close,			/* close */
192*25cf1a30Sjl 	nodev,				/* strategy */
193*25cf1a30Sjl 	nodev,				/* print */
194*25cf1a30Sjl 	nodev,				/* dump */
195*25cf1a30Sjl 	nodev,				/* read */
196*25cf1a30Sjl 	nodev,				/* write */
197*25cf1a30Sjl 	pcmu_ioctl,			/* ioctl */
198*25cf1a30Sjl 	nodev,				/* devmap */
199*25cf1a30Sjl 	nodev,				/* mmap */
200*25cf1a30Sjl 	nodev,				/* segmap */
201*25cf1a30Sjl 	nochpoll,			/* poll */
202*25cf1a30Sjl 	pcmu_prop_op,			/* cb_prop_op */
203*25cf1a30Sjl 	NULL,				/* streamtab */
204*25cf1a30Sjl 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
205*25cf1a30Sjl 	CB_REV,				/* rev */
206*25cf1a30Sjl 	nodev,				/* int (*cb_aread)() */
207*25cf1a30Sjl 	nodev				/* int (*cb_awrite)() */
208*25cf1a30Sjl };
209*25cf1a30Sjl 
210*25cf1a30Sjl static struct dev_ops pcmu_ops = {
211*25cf1a30Sjl 	DEVO_REV,
212*25cf1a30Sjl 	0,
213*25cf1a30Sjl 	pcmu_info,
214*25cf1a30Sjl 	nulldev,
215*25cf1a30Sjl 	0,
216*25cf1a30Sjl 	pcmu_attach,
217*25cf1a30Sjl 	pcmu_detach,
218*25cf1a30Sjl 	nodev,
219*25cf1a30Sjl 	&pcmu_cb_ops,
220*25cf1a30Sjl 	&pcmu_bus_ops,
221*25cf1a30Sjl 	0
222*25cf1a30Sjl };
223*25cf1a30Sjl 
224*25cf1a30Sjl /*
225*25cf1a30Sjl  * module definitions:
226*25cf1a30Sjl  */
227*25cf1a30Sjl extern struct mod_ops mod_driverops;
228*25cf1a30Sjl 
229*25cf1a30Sjl static struct modldrv modldrv = {
230*25cf1a30Sjl 	&mod_driverops,				/* Type of module - driver */
231*25cf1a30Sjl 	"OPL CMU-CH PCI Nexus driver %I%",	/* Name of module. */
232*25cf1a30Sjl 	&pcmu_ops,				/* driver ops */
233*25cf1a30Sjl };
234*25cf1a30Sjl 
235*25cf1a30Sjl static struct modlinkage modlinkage = {
236*25cf1a30Sjl 	MODREV_1, (void *)&modldrv, NULL
237*25cf1a30Sjl };
238*25cf1a30Sjl 
239*25cf1a30Sjl /*
240*25cf1a30Sjl  * driver global data:
241*25cf1a30Sjl  */
242*25cf1a30Sjl void *per_pcmu_state;			/* per-pbm soft state pointer */
243*25cf1a30Sjl kmutex_t pcmu_global_mutex;		/* attach/detach common struct lock */
244*25cf1a30Sjl errorq_t *pcmu_ecc_queue = NULL;	/* per-system ecc handling queue */
245*25cf1a30Sjl 
246*25cf1a30Sjl extern void pcmu_child_cfg_save(dev_info_t *dip);
247*25cf1a30Sjl extern void pcmu_child_cfg_restore(dev_info_t *dip);
248*25cf1a30Sjl 
249*25cf1a30Sjl int
250*25cf1a30Sjl _init(void)
251*25cf1a30Sjl {
252*25cf1a30Sjl 	int e;
253*25cf1a30Sjl 
254*25cf1a30Sjl 	/*
255*25cf1a30Sjl 	 * Initialize per-pci bus soft state pointer.
256*25cf1a30Sjl 	 */
257*25cf1a30Sjl 	e = ddi_soft_state_init(&per_pcmu_state, sizeof (pcmu_t), 1);
258*25cf1a30Sjl 	if (e != 0)
259*25cf1a30Sjl 		return (e);
260*25cf1a30Sjl 
261*25cf1a30Sjl 	/*
262*25cf1a30Sjl 	 * Initialize global mutexes.
263*25cf1a30Sjl 	 */
264*25cf1a30Sjl 	mutex_init(&pcmu_global_mutex, NULL, MUTEX_DRIVER, NULL);
265*25cf1a30Sjl 
266*25cf1a30Sjl 	/*
267*25cf1a30Sjl 	 * Create the performance kstats.
268*25cf1a30Sjl 	 */
269*25cf1a30Sjl 	pcmu_kstat_init();
270*25cf1a30Sjl 
271*25cf1a30Sjl 	/*
272*25cf1a30Sjl 	 * Install the module.
273*25cf1a30Sjl 	 */
274*25cf1a30Sjl 	e = mod_install(&modlinkage);
275*25cf1a30Sjl 	if (e != 0) {
276*25cf1a30Sjl 		ddi_soft_state_fini(&per_pcmu_state);
277*25cf1a30Sjl 		mutex_destroy(&pcmu_global_mutex);
278*25cf1a30Sjl 	}
279*25cf1a30Sjl 	return (e);
280*25cf1a30Sjl }
281*25cf1a30Sjl 
282*25cf1a30Sjl int
283*25cf1a30Sjl _fini(void)
284*25cf1a30Sjl {
285*25cf1a30Sjl 	int e;
286*25cf1a30Sjl 
287*25cf1a30Sjl 	/*
288*25cf1a30Sjl 	 * Remove the module.
289*25cf1a30Sjl 	 */
290*25cf1a30Sjl 	e = mod_remove(&modlinkage);
291*25cf1a30Sjl 	if (e != 0) {
292*25cf1a30Sjl 		return (e);
293*25cf1a30Sjl 	}
294*25cf1a30Sjl 
295*25cf1a30Sjl 	/*
296*25cf1a30Sjl 	 * Destroy pcmu_ecc_queue, and set it to NULL.
297*25cf1a30Sjl 	 */
298*25cf1a30Sjl 	if (pcmu_ecc_queue) {
299*25cf1a30Sjl 		errorq_destroy(pcmu_ecc_queue);
300*25cf1a30Sjl 		pcmu_ecc_queue = NULL;
301*25cf1a30Sjl 	}
302*25cf1a30Sjl 
303*25cf1a30Sjl 	/*
304*25cf1a30Sjl 	 * Destroy the performance kstats.
305*25cf1a30Sjl 	 */
306*25cf1a30Sjl 	pcmu_kstat_fini();
307*25cf1a30Sjl 
308*25cf1a30Sjl 	/*
309*25cf1a30Sjl 	 * Free the per-pci and per-CMU-CH soft state info and destroy
310*25cf1a30Sjl 	 * mutex for per-CMU-CH soft state.
311*25cf1a30Sjl 	 */
312*25cf1a30Sjl 	ddi_soft_state_fini(&per_pcmu_state);
313*25cf1a30Sjl 	mutex_destroy(&pcmu_global_mutex);
314*25cf1a30Sjl 	return (e);
315*25cf1a30Sjl }
316*25cf1a30Sjl 
317*25cf1a30Sjl int
318*25cf1a30Sjl _info(struct modinfo *modinfop)
319*25cf1a30Sjl {
320*25cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
321*25cf1a30Sjl }
322*25cf1a30Sjl 
323*25cf1a30Sjl /*ARGSUSED*/
324*25cf1a30Sjl static int
325*25cf1a30Sjl pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
326*25cf1a30Sjl {
327*25cf1a30Sjl 	int	instance = getminor((dev_t)arg) >> 8;
328*25cf1a30Sjl 	pcmu_t	*pcmu_p = get_pcmu_soft_state(instance);
329*25cf1a30Sjl 
330*25cf1a30Sjl 	switch (infocmd) {
331*25cf1a30Sjl 	case DDI_INFO_DEVT2INSTANCE:
332*25cf1a30Sjl 		*result = (void *)(uintptr_t)instance;
333*25cf1a30Sjl 		return (DDI_SUCCESS);
334*25cf1a30Sjl 
335*25cf1a30Sjl 	case DDI_INFO_DEVT2DEVINFO:
336*25cf1a30Sjl 		if (pcmu_p == NULL)
337*25cf1a30Sjl 			return (DDI_FAILURE);
338*25cf1a30Sjl 		*result = (void *)pcmu_p->pcmu_dip;
339*25cf1a30Sjl 		return (DDI_SUCCESS);
340*25cf1a30Sjl 
341*25cf1a30Sjl 	default:
342*25cf1a30Sjl 		return (DDI_FAILURE);
343*25cf1a30Sjl 	}
344*25cf1a30Sjl }
345*25cf1a30Sjl 
346*25cf1a30Sjl 
347*25cf1a30Sjl /* device driver entry points */
348*25cf1a30Sjl /*
349*25cf1a30Sjl  * attach entry point:
350*25cf1a30Sjl  */
351*25cf1a30Sjl static int
352*25cf1a30Sjl pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
353*25cf1a30Sjl {
354*25cf1a30Sjl 	pcmu_t *pcmu_p;
355*25cf1a30Sjl 	int instance = ddi_get_instance(dip);
356*25cf1a30Sjl 
357*25cf1a30Sjl 	switch (cmd) {
358*25cf1a30Sjl 	case DDI_ATTACH:
359*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_ATTACH\n");
360*25cf1a30Sjl 
361*25cf1a30Sjl 		/*
362*25cf1a30Sjl 		 * Allocate and get the per-pci soft state structure.
363*25cf1a30Sjl 		 */
364*25cf1a30Sjl 		if (alloc_pcmu_soft_state(instance) != DDI_SUCCESS) {
365*25cf1a30Sjl 			cmn_err(CE_WARN, "%s%d: can't allocate pci state",
366*25cf1a30Sjl 			    ddi_driver_name(dip), instance);
367*25cf1a30Sjl 			goto err_bad_pcmu_softstate;
368*25cf1a30Sjl 		}
369*25cf1a30Sjl 		pcmu_p = get_pcmu_soft_state(instance);
370*25cf1a30Sjl 		pcmu_p->pcmu_dip = dip;
371*25cf1a30Sjl 		mutex_init(&pcmu_p->pcmu_mutex, NULL, MUTEX_DRIVER, NULL);
372*25cf1a30Sjl 		pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED;
373*25cf1a30Sjl 		pcmu_p->pcmu_open_count = 0;
374*25cf1a30Sjl 
375*25cf1a30Sjl 		/*
376*25cf1a30Sjl 		 * Get key properties of the pci bridge node.
377*25cf1a30Sjl 		 */
378*25cf1a30Sjl 		if (get_pcmu_properties(pcmu_p, dip) == DDI_FAILURE) {
379*25cf1a30Sjl 			goto err_bad_pcmu_prop;
380*25cf1a30Sjl 		}
381*25cf1a30Sjl 
382*25cf1a30Sjl 		/*
383*25cf1a30Sjl 		 * Map in the registers.
384*25cf1a30Sjl 		 */
385*25cf1a30Sjl 		if (map_pcmu_registers(pcmu_p, dip) == DDI_FAILURE) {
386*25cf1a30Sjl 			goto err_bad_reg_prop;
387*25cf1a30Sjl 		}
388*25cf1a30Sjl 		if (pcmu_obj_setup(pcmu_p) != DDI_SUCCESS) {
389*25cf1a30Sjl 			goto err_bad_objs;
390*25cf1a30Sjl 		}
391*25cf1a30Sjl 
392*25cf1a30Sjl 		if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
393*25cf1a30Sjl 		    (uint_t)instance<<8 | 0xff,
394*25cf1a30Sjl 		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
395*25cf1a30Sjl 			goto err_bad_devctl_node;
396*25cf1a30Sjl 		}
397*25cf1a30Sjl 
398*25cf1a30Sjl 		/*
399*25cf1a30Sjl 		 * Due to unresolved hardware issues, disable PCIPM until
400*25cf1a30Sjl 		 * the problem is fully understood.
401*25cf1a30Sjl 		 *
402*25cf1a30Sjl 		 * pcmu_pwr_setup(pcmu_p, dip);
403*25cf1a30Sjl 		 */
404*25cf1a30Sjl 
405*25cf1a30Sjl 		ddi_report_dev(dip);
406*25cf1a30Sjl 
407*25cf1a30Sjl 		pcmu_p->pcmu_state = PCMU_ATTACHED;
408*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "attach success\n");
409*25cf1a30Sjl 		break;
410*25cf1a30Sjl 
411*25cf1a30Sjl err_bad_objs:
412*25cf1a30Sjl 		ddi_remove_minor_node(dip, "devctl");
413*25cf1a30Sjl err_bad_devctl_node:
414*25cf1a30Sjl 		unmap_pcmu_registers(pcmu_p);
415*25cf1a30Sjl err_bad_reg_prop:
416*25cf1a30Sjl 		free_pcmu_properties(pcmu_p);
417*25cf1a30Sjl err_bad_pcmu_prop:
418*25cf1a30Sjl 		mutex_destroy(&pcmu_p->pcmu_mutex);
419*25cf1a30Sjl 		free_pcmu_soft_state(instance);
420*25cf1a30Sjl err_bad_pcmu_softstate:
421*25cf1a30Sjl 		return (DDI_FAILURE);
422*25cf1a30Sjl 
423*25cf1a30Sjl 	case DDI_RESUME:
424*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_RESUME\n");
425*25cf1a30Sjl 
426*25cf1a30Sjl 		/*
427*25cf1a30Sjl 		 * Make sure the CMU-CH control registers
428*25cf1a30Sjl 		 * are configured properly.
429*25cf1a30Sjl 		 */
430*25cf1a30Sjl 		pcmu_p = get_pcmu_soft_state(instance);
431*25cf1a30Sjl 		mutex_enter(&pcmu_p->pcmu_mutex);
432*25cf1a30Sjl 
433*25cf1a30Sjl 		/*
434*25cf1a30Sjl 		 * Make sure this instance has been suspended.
435*25cf1a30Sjl 		 */
436*25cf1a30Sjl 		if (pcmu_p->pcmu_state != PCMU_SUSPENDED) {
437*25cf1a30Sjl 			PCMU_DBG0(PCMU_DBG_ATTACH, dip,
438*25cf1a30Sjl 			    "instance NOT suspended\n");
439*25cf1a30Sjl 			mutex_exit(&pcmu_p->pcmu_mutex);
440*25cf1a30Sjl 			return (DDI_FAILURE);
441*25cf1a30Sjl 		}
442*25cf1a30Sjl 		pcmu_obj_resume(pcmu_p);
443*25cf1a30Sjl 		pcmu_p->pcmu_state = PCMU_ATTACHED;
444*25cf1a30Sjl 
445*25cf1a30Sjl 		pcmu_child_cfg_restore(dip);
446*25cf1a30Sjl 
447*25cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
448*25cf1a30Sjl 		break;
449*25cf1a30Sjl 
450*25cf1a30Sjl 	default:
451*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip, "unsupported attach op\n");
452*25cf1a30Sjl 		return (DDI_FAILURE);
453*25cf1a30Sjl 	}
454*25cf1a30Sjl 
455*25cf1a30Sjl 	return (DDI_SUCCESS);
456*25cf1a30Sjl }
457*25cf1a30Sjl 
458*25cf1a30Sjl /*
459*25cf1a30Sjl  * detach entry point:
460*25cf1a30Sjl  */
461*25cf1a30Sjl static int
462*25cf1a30Sjl pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
463*25cf1a30Sjl {
464*25cf1a30Sjl 	int instance = ddi_get_instance(dip);
465*25cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(instance);
466*25cf1a30Sjl 	int len;
467*25cf1a30Sjl 
468*25cf1a30Sjl 	/*
469*25cf1a30Sjl 	 * Make sure we are currently attached
470*25cf1a30Sjl 	 */
471*25cf1a30Sjl 	if (pcmu_p->pcmu_state != PCMU_ATTACHED) {
472*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_ATTACH, dip,
473*25cf1a30Sjl 		    "failed - instance not attached\n");
474*25cf1a30Sjl 		return (DDI_FAILURE);
475*25cf1a30Sjl 	}
476*25cf1a30Sjl 
477*25cf1a30Sjl 	mutex_enter(&pcmu_p->pcmu_mutex);
478*25cf1a30Sjl 
479*25cf1a30Sjl 	switch (cmd) {
480*25cf1a30Sjl 	case DDI_DETACH:
481*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_DETACH, dip, "DDI_DETACH\n");
482*25cf1a30Sjl 		pcmu_obj_destroy(pcmu_p);
483*25cf1a30Sjl 
484*25cf1a30Sjl 		/*
485*25cf1a30Sjl 		 * Free the pci soft state structure and the rest of the
486*25cf1a30Sjl 		 * resources it's using.
487*25cf1a30Sjl 		 */
488*25cf1a30Sjl 		free_pcmu_properties(pcmu_p);
489*25cf1a30Sjl 		unmap_pcmu_registers(pcmu_p);
490*25cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
491*25cf1a30Sjl 		mutex_destroy(&pcmu_p->pcmu_mutex);
492*25cf1a30Sjl 		free_pcmu_soft_state(instance);
493*25cf1a30Sjl 
494*25cf1a30Sjl 		/* Free the interrupt-priorities prop if we created it. */
495*25cf1a30Sjl 		if (ddi_getproplen(DDI_DEV_T_ANY, dip,
496*25cf1a30Sjl 		    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
497*25cf1a30Sjl 		    "interrupt-priorities", &len) == DDI_PROP_SUCCESS) {
498*25cf1a30Sjl 			(void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
499*25cf1a30Sjl 			    "interrupt-priorities");
500*25cf1a30Sjl 		}
501*25cf1a30Sjl 		return (DDI_SUCCESS);
502*25cf1a30Sjl 
503*25cf1a30Sjl 	case DDI_SUSPEND:
504*25cf1a30Sjl 		pcmu_child_cfg_save(dip);
505*25cf1a30Sjl 		pcmu_obj_suspend(pcmu_p);
506*25cf1a30Sjl 		pcmu_p->pcmu_state = PCMU_SUSPENDED;
507*25cf1a30Sjl 
508*25cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
509*25cf1a30Sjl 		return (DDI_SUCCESS);
510*25cf1a30Sjl 
511*25cf1a30Sjl 	default:
512*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_DETACH, dip, "unsupported detach op\n");
513*25cf1a30Sjl 		mutex_exit(&pcmu_p->pcmu_mutex);
514*25cf1a30Sjl 		return (DDI_FAILURE);
515*25cf1a30Sjl 	}
516*25cf1a30Sjl }
517*25cf1a30Sjl 
518*25cf1a30Sjl 
519*25cf1a30Sjl /*LINTLIBRARY*/
520*25cf1a30Sjl 
521*25cf1a30Sjl /* ARGSUSED3 */
522*25cf1a30Sjl static int
523*25cf1a30Sjl pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp)
524*25cf1a30Sjl {
525*25cf1a30Sjl 	pcmu_t *pcmu_p;
526*25cf1a30Sjl 
527*25cf1a30Sjl 	if (otyp != OTYP_CHR) {
528*25cf1a30Sjl 		return (EINVAL);
529*25cf1a30Sjl 	}
530*25cf1a30Sjl 
531*25cf1a30Sjl 	/*
532*25cf1a30Sjl 	 * Get the soft state structure for the device.
533*25cf1a30Sjl 	 */
534*25cf1a30Sjl 	pcmu_p = DEV_TO_SOFTSTATE(*devp);
535*25cf1a30Sjl 	if (pcmu_p == NULL) {
536*25cf1a30Sjl 		return (ENXIO);
537*25cf1a30Sjl 	}
538*25cf1a30Sjl 
539*25cf1a30Sjl 	/*
540*25cf1a30Sjl 	 * Handle the open by tracking the device state.
541*25cf1a30Sjl 	 */
542*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_OPEN, pcmu_p->pcmu_dip,
543*25cf1a30Sjl 	    "devp=%x: flags=%x\n", devp, flags);
544*25cf1a30Sjl 	mutex_enter(&pcmu_p->pcmu_mutex);
545*25cf1a30Sjl 	if (flags & FEXCL) {
546*25cf1a30Sjl 		if (pcmu_p->pcmu_soft_state != PCMU_SOFT_STATE_CLOSED) {
547*25cf1a30Sjl 			mutex_exit(&pcmu_p->pcmu_mutex);
548*25cf1a30Sjl 			PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n");
549*25cf1a30Sjl 			return (EBUSY);
550*25cf1a30Sjl 		}
551*25cf1a30Sjl 		pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN_EXCL;
552*25cf1a30Sjl 	} else {
553*25cf1a30Sjl 		if (pcmu_p->pcmu_soft_state == PCMU_SOFT_STATE_OPEN_EXCL) {
554*25cf1a30Sjl 			mutex_exit(&pcmu_p->pcmu_mutex);
555*25cf1a30Sjl 			PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n");
556*25cf1a30Sjl 			return (EBUSY);
557*25cf1a30Sjl 		}
558*25cf1a30Sjl 		pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN;
559*25cf1a30Sjl 	}
560*25cf1a30Sjl 	pcmu_p->pcmu_open_count++;
561*25cf1a30Sjl 	mutex_exit(&pcmu_p->pcmu_mutex);
562*25cf1a30Sjl 	return (0);
563*25cf1a30Sjl }
564*25cf1a30Sjl 
565*25cf1a30Sjl 
566*25cf1a30Sjl /* ARGSUSED */
567*25cf1a30Sjl static int
568*25cf1a30Sjl pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp)
569*25cf1a30Sjl {
570*25cf1a30Sjl 	pcmu_t *pcmu_p;
571*25cf1a30Sjl 
572*25cf1a30Sjl 	if (otyp != OTYP_CHR) {
573*25cf1a30Sjl 		return (EINVAL);
574*25cf1a30Sjl 	}
575*25cf1a30Sjl 
576*25cf1a30Sjl 	pcmu_p = DEV_TO_SOFTSTATE(dev);
577*25cf1a30Sjl 	if (pcmu_p == NULL) {
578*25cf1a30Sjl 		return (ENXIO);
579*25cf1a30Sjl 	}
580*25cf1a30Sjl 
581*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_CLOSE, pcmu_p->pcmu_dip,
582*25cf1a30Sjl 	    "dev=%x: flags=%x\n", dev, flags);
583*25cf1a30Sjl 	mutex_enter(&pcmu_p->pcmu_mutex);
584*25cf1a30Sjl 	pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED;
585*25cf1a30Sjl 	pcmu_p->pcmu_open_count = 0;
586*25cf1a30Sjl 	mutex_exit(&pcmu_p->pcmu_mutex);
587*25cf1a30Sjl 	return (0);
588*25cf1a30Sjl }
589*25cf1a30Sjl 
590*25cf1a30Sjl /* ARGSUSED */
591*25cf1a30Sjl static int
592*25cf1a30Sjl pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
593*25cf1a30Sjl     cred_t *credp, int *rvalp)
594*25cf1a30Sjl {
595*25cf1a30Sjl 	pcmu_t *pcmu_p;
596*25cf1a30Sjl 	dev_info_t *dip;
597*25cf1a30Sjl 	struct devctl_iocdata *dcp;
598*25cf1a30Sjl 	uint_t bus_state;
599*25cf1a30Sjl 	int rv = 0;
600*25cf1a30Sjl 
601*25cf1a30Sjl 	pcmu_p = DEV_TO_SOFTSTATE(dev);
602*25cf1a30Sjl 	if (pcmu_p == NULL) {
603*25cf1a30Sjl 		return (ENXIO);
604*25cf1a30Sjl 	}
605*25cf1a30Sjl 
606*25cf1a30Sjl 	dip = pcmu_p->pcmu_dip;
607*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
608*25cf1a30Sjl 
609*25cf1a30Sjl 	/*
610*25cf1a30Sjl 	 * We can use the generic implementation for these ioctls
611*25cf1a30Sjl 	 */
612*25cf1a30Sjl 	switch (cmd) {
613*25cf1a30Sjl 	case DEVCTL_DEVICE_GETSTATE:
614*25cf1a30Sjl 	case DEVCTL_DEVICE_ONLINE:
615*25cf1a30Sjl 	case DEVCTL_DEVICE_OFFLINE:
616*25cf1a30Sjl 	case DEVCTL_BUS_GETSTATE:
617*25cf1a30Sjl 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
618*25cf1a30Sjl 	}
619*25cf1a30Sjl 
620*25cf1a30Sjl 	/*
621*25cf1a30Sjl 	 * read devctl ioctl data
622*25cf1a30Sjl 	 */
623*25cf1a30Sjl 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
624*25cf1a30Sjl 		return (EFAULT);
625*25cf1a30Sjl 
626*25cf1a30Sjl 	switch (cmd) {
627*25cf1a30Sjl 
628*25cf1a30Sjl 	case DEVCTL_DEVICE_RESET:
629*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n");
630*25cf1a30Sjl 		rv = ENOTSUP;
631*25cf1a30Sjl 		break;
632*25cf1a30Sjl 
633*25cf1a30Sjl 
634*25cf1a30Sjl 	case DEVCTL_BUS_QUIESCE:
635*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n");
636*25cf1a30Sjl 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) {
637*25cf1a30Sjl 			if (bus_state == BUS_QUIESCED) {
638*25cf1a30Sjl 				break;
639*25cf1a30Sjl 			}
640*25cf1a30Sjl 		}
641*25cf1a30Sjl 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
642*25cf1a30Sjl 		break;
643*25cf1a30Sjl 
644*25cf1a30Sjl 	case DEVCTL_BUS_UNQUIESCE:
645*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n");
646*25cf1a30Sjl 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) {
647*25cf1a30Sjl 			if (bus_state == BUS_ACTIVE) {
648*25cf1a30Sjl 				break;
649*25cf1a30Sjl 			}
650*25cf1a30Sjl 		}
651*25cf1a30Sjl 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
652*25cf1a30Sjl 		break;
653*25cf1a30Sjl 
654*25cf1a30Sjl 	case DEVCTL_BUS_RESET:
655*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n");
656*25cf1a30Sjl 		rv = ENOTSUP;
657*25cf1a30Sjl 		break;
658*25cf1a30Sjl 
659*25cf1a30Sjl 	case DEVCTL_BUS_RESETALL:
660*25cf1a30Sjl 		PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n");
661*25cf1a30Sjl 		rv = ENOTSUP;
662*25cf1a30Sjl 		break;
663*25cf1a30Sjl 
664*25cf1a30Sjl 	default:
665*25cf1a30Sjl 		rv = ENOTTY;
666*25cf1a30Sjl 	}
667*25cf1a30Sjl 
668*25cf1a30Sjl 	ndi_dc_freehdl(dcp);
669*25cf1a30Sjl 	return (rv);
670*25cf1a30Sjl }
671*25cf1a30Sjl 
672*25cf1a30Sjl static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
673*25cf1a30Sjl     int flags, char *name, caddr_t valuep, int *lengthp)
674*25cf1a30Sjl {
675*25cf1a30Sjl 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
676*25cf1a30Sjl }
677*25cf1a30Sjl /* bus driver entry points */
678*25cf1a30Sjl 
679*25cf1a30Sjl /*
680*25cf1a30Sjl  * bus map entry point:
681*25cf1a30Sjl  *
682*25cf1a30Sjl  *	if map request is for an rnumber
683*25cf1a30Sjl  *		get the corresponding regspec from device node
684*25cf1a30Sjl  *	build a new regspec in our parent's format
685*25cf1a30Sjl  *	build a new map_req with the new regspec
686*25cf1a30Sjl  *	call up the tree to complete the mapping
687*25cf1a30Sjl  */
688*25cf1a30Sjl static int
689*25cf1a30Sjl pcmu_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
690*25cf1a30Sjl 	off_t off, off_t len, caddr_t *addrp)
691*25cf1a30Sjl {
692*25cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
693*25cf1a30Sjl 	struct regspec p_regspec;
694*25cf1a30Sjl 	ddi_map_req_t p_mapreq;
695*25cf1a30Sjl 	int reglen, rval, r_no;
696*25cf1a30Sjl 	pci_regspec_t reloc_reg, *rp = &reloc_reg;
697*25cf1a30Sjl 
698*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_MAP, dip, "rdip=%s%d:",
699*25cf1a30Sjl 	    ddi_driver_name(rdip), ddi_get_instance(rdip));
700*25cf1a30Sjl 
701*25cf1a30Sjl 	if (mp->map_flags & DDI_MF_USER_MAPPING) {
702*25cf1a30Sjl 		return (DDI_ME_UNIMPLEMENTED);
703*25cf1a30Sjl 	}
704*25cf1a30Sjl 
705*25cf1a30Sjl 	switch (mp->map_type) {
706*25cf1a30Sjl 	case DDI_MT_REGSPEC:
707*25cf1a30Sjl 		reloc_reg = *(pci_regspec_t *)mp->map_obj.rp;	/* dup whole */
708*25cf1a30Sjl 		break;
709*25cf1a30Sjl 
710*25cf1a30Sjl 	case DDI_MT_RNUMBER:
711*25cf1a30Sjl 		r_no = mp->map_obj.rnumber;
712*25cf1a30Sjl 		PCMU_DBG1(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, " r#=%x", r_no);
713*25cf1a30Sjl 
714*25cf1a30Sjl 		if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS,
715*25cf1a30Sjl 		    "reg", (caddr_t)&rp, &reglen) != DDI_SUCCESS) {
716*25cf1a30Sjl 			return (DDI_ME_RNUMBER_RANGE);
717*25cf1a30Sjl 		}
718*25cf1a30Sjl 
719*25cf1a30Sjl 		if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) {
720*25cf1a30Sjl 			kmem_free(rp, reglen);
721*25cf1a30Sjl 			return (DDI_ME_RNUMBER_RANGE);
722*25cf1a30Sjl 		}
723*25cf1a30Sjl 		rp += r_no;
724*25cf1a30Sjl 		break;
725*25cf1a30Sjl 
726*25cf1a30Sjl 	default:
727*25cf1a30Sjl 		return (DDI_ME_INVAL);
728*25cf1a30Sjl 	}
729*25cf1a30Sjl 	PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, "\n");
730*25cf1a30Sjl 
731*25cf1a30Sjl 	/* use "assigned-addresses" to relocate regspec within pci space */
732*25cf1a30Sjl 	if (rval = pcmu_reloc_reg(dip, rdip, pcmu_p, rp)) {
733*25cf1a30Sjl 		goto done;
734*25cf1a30Sjl 	}
735*25cf1a30Sjl 
736*25cf1a30Sjl 	/* adjust regspec according to mapping request */
737*25cf1a30Sjl 	if (len) {
738*25cf1a30Sjl 		rp->pci_size_low = (uint_t)len;
739*25cf1a30Sjl 	}
740*25cf1a30Sjl 	rp->pci_phys_low += off;
741*25cf1a30Sjl 
742*25cf1a30Sjl 	/* use "ranges" to translate relocated pci regspec into parent space */
743*25cf1a30Sjl 	if (rval = pcmu_xlate_reg(pcmu_p, rp, &p_regspec)) {
744*25cf1a30Sjl 		goto done;
745*25cf1a30Sjl 	}
746*25cf1a30Sjl 
747*25cf1a30Sjl 	p_mapreq = *mp;		/* dup the whole structure */
748*25cf1a30Sjl 	p_mapreq.map_type = DDI_MT_REGSPEC;
749*25cf1a30Sjl 	p_mapreq.map_obj.rp = &p_regspec;
750*25cf1a30Sjl 	rval = ddi_map(dip, &p_mapreq, 0, 0, addrp);
751*25cf1a30Sjl 
752*25cf1a30Sjl done:
753*25cf1a30Sjl 	if (mp->map_type == DDI_MT_RNUMBER) {
754*25cf1a30Sjl 		kmem_free(rp - r_no, reglen);
755*25cf1a30Sjl 	}
756*25cf1a30Sjl 	return (rval);
757*25cf1a30Sjl }
758*25cf1a30Sjl 
759*25cf1a30Sjl #ifdef  DEBUG
760*25cf1a30Sjl int	pcmu_peekfault_cnt = 0;
761*25cf1a30Sjl int	pcmu_pokefault_cnt = 0;
762*25cf1a30Sjl #endif  /* DEBUG */
763*25cf1a30Sjl 
764*25cf1a30Sjl static int
765*25cf1a30Sjl pcmu_do_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args)
766*25cf1a30Sjl {
767*25cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
768*25cf1a30Sjl 	int err = DDI_SUCCESS;
769*25cf1a30Sjl 	on_trap_data_t otd;
770*25cf1a30Sjl 
771*25cf1a30Sjl 	mutex_enter(&pcbm_p->pcbm_pokeflt_mutex);
772*25cf1a30Sjl 	pcbm_p->pcbm_ontrap_data = &otd;
773*25cf1a30Sjl 
774*25cf1a30Sjl 	/* Set up protected environment. */
775*25cf1a30Sjl 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
776*25cf1a30Sjl 		uintptr_t tramp = otd.ot_trampoline;
777*25cf1a30Sjl 
778*25cf1a30Sjl 		otd.ot_trampoline = (uintptr_t)&poke_fault;
779*25cf1a30Sjl 		err = do_poke(in_args->size, (void *)in_args->dev_addr,
780*25cf1a30Sjl 		    (void *)in_args->host_addr);
781*25cf1a30Sjl 		otd.ot_trampoline = tramp;
782*25cf1a30Sjl 	} else {
783*25cf1a30Sjl 		err = DDI_FAILURE;
784*25cf1a30Sjl 	}
785*25cf1a30Sjl 
786*25cf1a30Sjl 	/*
787*25cf1a30Sjl 	 * Read the async fault register for the PBM to see it sees
788*25cf1a30Sjl 	 * a master-abort.
789*25cf1a30Sjl 	 */
790*25cf1a30Sjl 	pcmu_pbm_clear_error(pcbm_p);
791*25cf1a30Sjl 
792*25cf1a30Sjl 	if (otd.ot_trap & OT_DATA_ACCESS) {
793*25cf1a30Sjl 		err = DDI_FAILURE;
794*25cf1a30Sjl 	}
795*25cf1a30Sjl 
796*25cf1a30Sjl 	/* Take down protected environment. */
797*25cf1a30Sjl 	no_trap();
798*25cf1a30Sjl 
799*25cf1a30Sjl 	pcbm_p->pcbm_ontrap_data = NULL;
800*25cf1a30Sjl 	mutex_exit(&pcbm_p->pcbm_pokeflt_mutex);
801*25cf1a30Sjl 
802*25cf1a30Sjl #ifdef  DEBUG
803*25cf1a30Sjl 	if (err == DDI_FAILURE)
804*25cf1a30Sjl 		pcmu_pokefault_cnt++;
805*25cf1a30Sjl #endif
806*25cf1a30Sjl 	return (err);
807*25cf1a30Sjl }
808*25cf1a30Sjl 
809*25cf1a30Sjl 
810*25cf1a30Sjl static int
811*25cf1a30Sjl pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args)
812*25cf1a30Sjl {
813*25cf1a30Sjl 	return (pcmu_do_poke(pcmu_p, in_args));
814*25cf1a30Sjl }
815*25cf1a30Sjl 
816*25cf1a30Sjl /* ARGSUSED */
817*25cf1a30Sjl static int
818*25cf1a30Sjl pcmu_do_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args)
819*25cf1a30Sjl {
820*25cf1a30Sjl 	int err = DDI_SUCCESS;
821*25cf1a30Sjl 	on_trap_data_t otd;
822*25cf1a30Sjl 
823*25cf1a30Sjl 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
824*25cf1a30Sjl 		uintptr_t tramp = otd.ot_trampoline;
825*25cf1a30Sjl 
826*25cf1a30Sjl 		otd.ot_trampoline = (uintptr_t)&peek_fault;
827*25cf1a30Sjl 		err = do_peek(in_args->size, (void *)in_args->dev_addr,
828*25cf1a30Sjl 		    (void *)in_args->host_addr);
829*25cf1a30Sjl 		otd.ot_trampoline = tramp;
830*25cf1a30Sjl 	} else
831*25cf1a30Sjl 		err = DDI_FAILURE;
832*25cf1a30Sjl 
833*25cf1a30Sjl 	no_trap();
834*25cf1a30Sjl 
835*25cf1a30Sjl #ifdef  DEBUG
836*25cf1a30Sjl 	if (err == DDI_FAILURE)
837*25cf1a30Sjl 		pcmu_peekfault_cnt++;
838*25cf1a30Sjl #endif
839*25cf1a30Sjl 	return (err);
840*25cf1a30Sjl }
841*25cf1a30Sjl 
842*25cf1a30Sjl 
843*25cf1a30Sjl static int
844*25cf1a30Sjl pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, void *result)
845*25cf1a30Sjl {
846*25cf1a30Sjl 	result = (void *)in_args->host_addr;
847*25cf1a30Sjl 	return (pcmu_do_peek(pcmu_p, in_args));
848*25cf1a30Sjl }
849*25cf1a30Sjl 
850*25cf1a30Sjl /*
851*25cf1a30Sjl  * control ops entry point:
852*25cf1a30Sjl  *
853*25cf1a30Sjl  * Requests handled completely:
854*25cf1a30Sjl  *	DDI_CTLOPS_INITCHILD	see pcmu_init_child() for details
855*25cf1a30Sjl  *	DDI_CTLOPS_UNINITCHILD
856*25cf1a30Sjl  *	DDI_CTLOPS_REPORTDEV	see report_dev() for details
857*25cf1a30Sjl  *	DDI_CTLOPS_XLATE_INTRS	nothing to do
858*25cf1a30Sjl  *	DDI_CTLOPS_IOMIN	cache line size if streaming otherwise 1
859*25cf1a30Sjl  *	DDI_CTLOPS_REGSIZE
860*25cf1a30Sjl  *	DDI_CTLOPS_NREGS
861*25cf1a30Sjl  *	DDI_CTLOPS_NINTRS
862*25cf1a30Sjl  *	DDI_CTLOPS_DVMAPAGESIZE
863*25cf1a30Sjl  *	DDI_CTLOPS_POKE
864*25cf1a30Sjl  *	DDI_CTLOPS_PEEK
865*25cf1a30Sjl  *	DDI_CTLOPS_QUIESCE
866*25cf1a30Sjl  *	DDI_CTLOPS_UNQUIESCE
867*25cf1a30Sjl  *
868*25cf1a30Sjl  * All others passed to parent.
869*25cf1a30Sjl  */
870*25cf1a30Sjl static int
871*25cf1a30Sjl pcmu_ctlops(dev_info_t *dip, dev_info_t *rdip,
872*25cf1a30Sjl 	ddi_ctl_enum_t op, void *arg, void *result)
873*25cf1a30Sjl {
874*25cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
875*25cf1a30Sjl 
876*25cf1a30Sjl 	switch (op) {
877*25cf1a30Sjl 	case DDI_CTLOPS_INITCHILD:
878*25cf1a30Sjl 		return (pcmu_init_child(pcmu_p, (dev_info_t *)arg));
879*25cf1a30Sjl 
880*25cf1a30Sjl 	case DDI_CTLOPS_UNINITCHILD:
881*25cf1a30Sjl 		return (pcmu_uninit_child(pcmu_p, (dev_info_t *)arg));
882*25cf1a30Sjl 
883*25cf1a30Sjl 	case DDI_CTLOPS_REPORTDEV:
884*25cf1a30Sjl 		return (pcmu_report_dev(rdip));
885*25cf1a30Sjl 
886*25cf1a30Sjl 	case DDI_CTLOPS_IOMIN:
887*25cf1a30Sjl 		/*
888*25cf1a30Sjl 		 * If we are using the streaming cache, align at
889*25cf1a30Sjl 		 * least on a cache line boundary. Otherwise use
890*25cf1a30Sjl 		 * whatever alignment is passed in.
891*25cf1a30Sjl 		 */
892*25cf1a30Sjl 		return (DDI_SUCCESS);
893*25cf1a30Sjl 
894*25cf1a30Sjl 	case DDI_CTLOPS_REGSIZE:
895*25cf1a30Sjl 		*((off_t *)result) = pcmu_get_reg_set_size(rdip, *((int *)arg));
896*25cf1a30Sjl 		return (DDI_SUCCESS);
897*25cf1a30Sjl 
898*25cf1a30Sjl 	case DDI_CTLOPS_NREGS:
899*25cf1a30Sjl 		*((uint_t *)result) = pcmu_get_nreg_set(rdip);
900*25cf1a30Sjl 		return (DDI_SUCCESS);
901*25cf1a30Sjl 
902*25cf1a30Sjl 	case DDI_CTLOPS_DVMAPAGESIZE:
903*25cf1a30Sjl 		*((ulong_t *)result) = 0;
904*25cf1a30Sjl 		return (DDI_SUCCESS);
905*25cf1a30Sjl 
906*25cf1a30Sjl 	case DDI_CTLOPS_POKE:
907*25cf1a30Sjl 		return (pcmu_ctlops_poke(pcmu_p, (peekpoke_ctlops_t *)arg));
908*25cf1a30Sjl 
909*25cf1a30Sjl 	case DDI_CTLOPS_PEEK:
910*25cf1a30Sjl 		return (pcmu_ctlops_peek(pcmu_p, (peekpoke_ctlops_t *)arg,
911*25cf1a30Sjl 		    result));
912*25cf1a30Sjl 
913*25cf1a30Sjl 	case DDI_CTLOPS_AFFINITY:
914*25cf1a30Sjl 		break;
915*25cf1a30Sjl 
916*25cf1a30Sjl 	case DDI_CTLOPS_QUIESCE:
917*25cf1a30Sjl 		return (DDI_FAILURE);
918*25cf1a30Sjl 
919*25cf1a30Sjl 	case DDI_CTLOPS_UNQUIESCE:
920*25cf1a30Sjl 		return (DDI_FAILURE);
921*25cf1a30Sjl 
922*25cf1a30Sjl 	default:
923*25cf1a30Sjl 		break;
924*25cf1a30Sjl 	}
925*25cf1a30Sjl 
926*25cf1a30Sjl 	/*
927*25cf1a30Sjl 	 * Now pass the request up to our parent.
928*25cf1a30Sjl 	 */
929*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_CTLOPS, dip,
930*25cf1a30Sjl 	    "passing request to parent: rdip=%s%d\n",
931*25cf1a30Sjl 	    ddi_driver_name(rdip), ddi_get_instance(rdip));
932*25cf1a30Sjl 	return (ddi_ctlops(dip, rdip, op, arg, result));
933*25cf1a30Sjl }
934*25cf1a30Sjl 
935*25cf1a30Sjl 
936*25cf1a30Sjl /* ARGSUSED */
937*25cf1a30Sjl static int
938*25cf1a30Sjl pcmu_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
939*25cf1a30Sjl     ddi_intr_handle_impl_t *hdlp, void *result)
940*25cf1a30Sjl {
941*25cf1a30Sjl 	pcmu_t		*pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
942*25cf1a30Sjl 	int		ret = DDI_SUCCESS;
943*25cf1a30Sjl 
944*25cf1a30Sjl 	switch (intr_op) {
945*25cf1a30Sjl 	case DDI_INTROP_GETCAP:
946*25cf1a30Sjl 		/* GetCap will always fail for all non PCI devices */
947*25cf1a30Sjl 		(void) pci_intx_get_cap(rdip, (int *)result);
948*25cf1a30Sjl 		break;
949*25cf1a30Sjl 	case DDI_INTROP_SETCAP:
950*25cf1a30Sjl 		ret = DDI_ENOTSUP;
951*25cf1a30Sjl 		break;
952*25cf1a30Sjl 	case DDI_INTROP_ALLOC:
953*25cf1a30Sjl 		*(int *)result = hdlp->ih_scratch1;
954*25cf1a30Sjl 		break;
955*25cf1a30Sjl 	case DDI_INTROP_FREE:
956*25cf1a30Sjl 		break;
957*25cf1a30Sjl 	case DDI_INTROP_GETPRI:
958*25cf1a30Sjl 		*(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 0;
959*25cf1a30Sjl 		break;
960*25cf1a30Sjl 	case DDI_INTROP_SETPRI:
961*25cf1a30Sjl 		break;
962*25cf1a30Sjl 	case DDI_INTROP_ADDISR:
963*25cf1a30Sjl 		ret = pcmu_add_intr(dip, rdip, hdlp);
964*25cf1a30Sjl 		break;
965*25cf1a30Sjl 	case DDI_INTROP_REMISR:
966*25cf1a30Sjl 		ret = pcmu_remove_intr(dip, rdip, hdlp);
967*25cf1a30Sjl 		break;
968*25cf1a30Sjl 	case DDI_INTROP_ENABLE:
969*25cf1a30Sjl 		ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp,
970*25cf1a30Sjl 		    PCMU_INTR_STATE_ENABLE);
971*25cf1a30Sjl 		break;
972*25cf1a30Sjl 	case DDI_INTROP_DISABLE:
973*25cf1a30Sjl 		ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp,
974*25cf1a30Sjl 		    PCMU_INTR_STATE_DISABLE);
975*25cf1a30Sjl 		break;
976*25cf1a30Sjl 	case DDI_INTROP_SETMASK:
977*25cf1a30Sjl 		ret = pci_intx_set_mask(rdip);
978*25cf1a30Sjl 		break;
979*25cf1a30Sjl 	case DDI_INTROP_CLRMASK:
980*25cf1a30Sjl 		ret = pci_intx_clr_mask(rdip);
981*25cf1a30Sjl 		break;
982*25cf1a30Sjl 	case DDI_INTROP_GETPENDING:
983*25cf1a30Sjl 		ret = pci_intx_get_pending(rdip, (int *)result);
984*25cf1a30Sjl 		break;
985*25cf1a30Sjl 	case DDI_INTROP_NINTRS:
986*25cf1a30Sjl 	case DDI_INTROP_NAVAIL:
987*25cf1a30Sjl 		*(int *)result = i_ddi_get_nintrs(rdip);
988*25cf1a30Sjl 		break;
989*25cf1a30Sjl 	case DDI_INTROP_SUPPORTED_TYPES:
990*25cf1a30Sjl 		/* PCI nexus driver supports only fixed interrupts */
991*25cf1a30Sjl 		*(int *)result = i_ddi_get_nintrs(rdip) ?
992*25cf1a30Sjl 		    DDI_INTR_TYPE_FIXED : 0;
993*25cf1a30Sjl 		break;
994*25cf1a30Sjl 	default:
995*25cf1a30Sjl 		ret = DDI_ENOTSUP;
996*25cf1a30Sjl 		break;
997*25cf1a30Sjl 	}
998*25cf1a30Sjl 
999*25cf1a30Sjl 	return (ret);
1000*25cf1a30Sjl }
1001*25cf1a30Sjl 
1002*25cf1a30Sjl /*
1003*25cf1a30Sjl  * CMU-CH specifics implementation:
1004*25cf1a30Sjl  *	interrupt mapping register
1005*25cf1a30Sjl  *	PBM configuration
1006*25cf1a30Sjl  *	ECC and PBM error handling
1007*25cf1a30Sjl  */
1008*25cf1a30Sjl 
1009*25cf1a30Sjl /* called by pcmu_attach() DDI_ATTACH to initialize pci objects */
1010*25cf1a30Sjl static int
1011*25cf1a30Sjl pcmu_obj_setup(pcmu_t *pcmu_p)
1012*25cf1a30Sjl {
1013*25cf1a30Sjl 	int ret;
1014*25cf1a30Sjl 
1015*25cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
1016*25cf1a30Sjl 	pcmu_p->pcmu_rev = ddi_prop_get_int(DDI_DEV_T_ANY, pcmu_p->pcmu_dip,
1017*25cf1a30Sjl 	    DDI_PROP_DONTPASS, "module-revision#", 0);
1018*25cf1a30Sjl 
1019*25cf1a30Sjl 	pcmu_ib_create(pcmu_p);
1020*25cf1a30Sjl 	pcmu_cb_create(pcmu_p);
1021*25cf1a30Sjl 	pcmu_ecc_create(pcmu_p);
1022*25cf1a30Sjl 	pcmu_pbm_create(pcmu_p);
1023*25cf1a30Sjl 	pcmu_err_create(pcmu_p);
1024*25cf1a30Sjl 	if ((ret = pcmu_intr_setup(pcmu_p)) != DDI_SUCCESS)
1025*25cf1a30Sjl 		goto done;
1026*25cf1a30Sjl 
1027*25cf1a30Sjl 	pcmu_kstat_create(pcmu_p);
1028*25cf1a30Sjl done:
1029*25cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
1030*25cf1a30Sjl 	if (ret != DDI_SUCCESS) {
1031*25cf1a30Sjl 		cmn_err(CE_NOTE, "Interrupt register failure, returning 0x%x\n",
1032*25cf1a30Sjl 			ret);
1033*25cf1a30Sjl 	}
1034*25cf1a30Sjl 	return (ret);
1035*25cf1a30Sjl }
1036*25cf1a30Sjl 
1037*25cf1a30Sjl /* called by pcmu_detach() DDI_DETACH to destroy pci objects */
1038*25cf1a30Sjl static void
1039*25cf1a30Sjl pcmu_obj_destroy(pcmu_t *pcmu_p)
1040*25cf1a30Sjl {
1041*25cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
1042*25cf1a30Sjl 
1043*25cf1a30Sjl 	pcmu_kstat_destroy(pcmu_p);
1044*25cf1a30Sjl 	pcmu_pbm_destroy(pcmu_p);
1045*25cf1a30Sjl 	pcmu_err_destroy(pcmu_p);
1046*25cf1a30Sjl 	pcmu_ecc_destroy(pcmu_p);
1047*25cf1a30Sjl 	pcmu_cb_destroy(pcmu_p);
1048*25cf1a30Sjl 	pcmu_ib_destroy(pcmu_p);
1049*25cf1a30Sjl 	pcmu_intr_teardown(pcmu_p);
1050*25cf1a30Sjl 
1051*25cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
1052*25cf1a30Sjl }
1053*25cf1a30Sjl 
1054*25cf1a30Sjl /* called by pcmu_attach() DDI_RESUME to (re)initialize pci objects */
1055*25cf1a30Sjl static void
1056*25cf1a30Sjl pcmu_obj_resume(pcmu_t *pcmu_p)
1057*25cf1a30Sjl {
1058*25cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
1059*25cf1a30Sjl 
1060*25cf1a30Sjl 	pcmu_ib_configure(pcmu_p->pcmu_ib_p);
1061*25cf1a30Sjl 	pcmu_ecc_configure(pcmu_p);
1062*25cf1a30Sjl 	pcmu_ib_resume(pcmu_p->pcmu_ib_p);
1063*25cf1a30Sjl 	u2u_ittrans_resume((u2u_ittrans_data_t **)
1064*25cf1a30Sjl 	    &(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie));
1065*25cf1a30Sjl 
1066*25cf1a30Sjl 	pcmu_pbm_configure(pcmu_p->pcmu_pcbm_p);
1067*25cf1a30Sjl 
1068*25cf1a30Sjl 	pcmu_cb_resume(pcmu_p->pcmu_cb_p);
1069*25cf1a30Sjl 
1070*25cf1a30Sjl 	pcmu_pbm_resume(pcmu_p->pcmu_pcbm_p);
1071*25cf1a30Sjl 
1072*25cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
1073*25cf1a30Sjl }
1074*25cf1a30Sjl 
1075*25cf1a30Sjl /* called by pcmu_detach() DDI_SUSPEND to suspend pci objects */
1076*25cf1a30Sjl static void
1077*25cf1a30Sjl pcmu_obj_suspend(pcmu_t *pcmu_p)
1078*25cf1a30Sjl {
1079*25cf1a30Sjl 	mutex_enter(&pcmu_global_mutex);
1080*25cf1a30Sjl 
1081*25cf1a30Sjl 	pcmu_pbm_suspend(pcmu_p->pcmu_pcbm_p);
1082*25cf1a30Sjl 	pcmu_ib_suspend(pcmu_p->pcmu_ib_p);
1083*25cf1a30Sjl 	pcmu_cb_suspend(pcmu_p->pcmu_cb_p);
1084*25cf1a30Sjl 
1085*25cf1a30Sjl 	mutex_exit(&pcmu_global_mutex);
1086*25cf1a30Sjl }
1087*25cf1a30Sjl 
1088*25cf1a30Sjl static int
1089*25cf1a30Sjl pcmu_intr_setup(pcmu_t *pcmu_p)
1090*25cf1a30Sjl {
1091*25cf1a30Sjl 	dev_info_t *dip = pcmu_p->pcmu_dip;
1092*25cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
1093*25cf1a30Sjl 	pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p;
1094*25cf1a30Sjl 	int i, no_of_intrs;
1095*25cf1a30Sjl 
1096*25cf1a30Sjl 	/*
1097*25cf1a30Sjl 	 * Get the interrupts property.
1098*25cf1a30Sjl 	 */
1099*25cf1a30Sjl 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1100*25cf1a30Sjl 	    "interrupts", (caddr_t)&pcmu_p->pcmu_inos,
1101*25cf1a30Sjl 	    &pcmu_p->pcmu_inos_len) != DDI_SUCCESS) {
1102*25cf1a30Sjl 		cmn_err(CE_PANIC, "%s%d: no interrupts property\n",
1103*25cf1a30Sjl 			ddi_driver_name(dip), ddi_get_instance(dip));
1104*25cf1a30Sjl 	}
1105*25cf1a30Sjl 
1106*25cf1a30Sjl 	/*
1107*25cf1a30Sjl 	 * figure out number of interrupts in the "interrupts" property
1108*25cf1a30Sjl 	 * and convert them all into ino.
1109*25cf1a30Sjl 	 */
1110*25cf1a30Sjl 	i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1);
1111*25cf1a30Sjl 	i = CELLS_1275_TO_BYTES(i);
1112*25cf1a30Sjl 	no_of_intrs = pcmu_p->pcmu_inos_len / i;
1113*25cf1a30Sjl 	for (i = 0; i < no_of_intrs; i++) {
1114*25cf1a30Sjl 		pcmu_p->pcmu_inos[i] =
1115*25cf1a30Sjl 		    PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[i]);
1116*25cf1a30Sjl 	}
1117*25cf1a30Sjl 
1118*25cf1a30Sjl 	pcb_p->pcb_no_of_inos = no_of_intrs;
1119*25cf1a30Sjl 	if (i = pcmu_ecc_register_intr(pcmu_p)) {
1120*25cf1a30Sjl 		goto teardown;
1121*25cf1a30Sjl 	}
1122*25cf1a30Sjl 
1123*25cf1a30Sjl 	intr_dist_add(pcmu_cb_intr_dist, pcb_p);
1124*25cf1a30Sjl 	pcmu_ecc_enable_intr(pcmu_p);
1125*25cf1a30Sjl 
1126*25cf1a30Sjl 	if (i = pcmu_pbm_register_intr(pcbm_p)) {
1127*25cf1a30Sjl 		intr_dist_rem(pcmu_cb_intr_dist, pcb_p);
1128*25cf1a30Sjl 		goto teardown;
1129*25cf1a30Sjl 	}
1130*25cf1a30Sjl 	intr_dist_add(pcmu_pbm_intr_dist, pcbm_p);
1131*25cf1a30Sjl 	pcmu_ib_intr_enable(pcmu_p, pcmu_p->pcmu_inos[CBNINTR_PBM]);
1132*25cf1a30Sjl 
1133*25cf1a30Sjl 	intr_dist_add_weighted(pcmu_ib_intr_dist_all, pcmu_p->pcmu_ib_p);
1134*25cf1a30Sjl 	return (DDI_SUCCESS);
1135*25cf1a30Sjl teardown:
1136*25cf1a30Sjl 	pcmu_intr_teardown(pcmu_p);
1137*25cf1a30Sjl 	return (i);
1138*25cf1a30Sjl }
1139*25cf1a30Sjl 
1140*25cf1a30Sjl /*
1141*25cf1a30Sjl  * pcmu_fix_ranges - fixes the config space entry of the "ranges"
1142*25cf1a30Sjl  *	property on CMU-CH platforms
1143*25cf1a30Sjl  */
1144*25cf1a30Sjl void
1145*25cf1a30Sjl pcmu_fix_ranges(pcmu_ranges_t *rng_p, int rng_entries)
1146*25cf1a30Sjl {
1147*25cf1a30Sjl 	int i;
1148*25cf1a30Sjl 	for (i = 0; i < rng_entries; i++, rng_p++) {
1149*25cf1a30Sjl 		if ((rng_p->child_high & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG)
1150*25cf1a30Sjl 			rng_p->parent_low |= rng_p->child_high;
1151*25cf1a30Sjl 	}
1152*25cf1a30Sjl }
1153*25cf1a30Sjl 
1154*25cf1a30Sjl /*
1155*25cf1a30Sjl  * map_pcmu_registers
1156*25cf1a30Sjl  *
1157*25cf1a30Sjl  * This function is called from the attach routine to map the registers
1158*25cf1a30Sjl  * accessed by this driver.
1159*25cf1a30Sjl  *
1160*25cf1a30Sjl  * used by: pcmu_attach()
1161*25cf1a30Sjl  *
1162*25cf1a30Sjl  * return value: DDI_FAILURE on failure
1163*25cf1a30Sjl  */
1164*25cf1a30Sjl static int
1165*25cf1a30Sjl map_pcmu_registers(pcmu_t *pcmu_p, dev_info_t *dip)
1166*25cf1a30Sjl {
1167*25cf1a30Sjl 	ddi_device_acc_attr_t attr;
1168*25cf1a30Sjl 
1169*25cf1a30Sjl 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1170*25cf1a30Sjl 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1171*25cf1a30Sjl 
1172*25cf1a30Sjl 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
1173*25cf1a30Sjl 	if (ddi_regs_map_setup(dip, 0, &pcmu_p->pcmu_address[0], 0, 0,
1174*25cf1a30Sjl 	    &attr, &pcmu_p->pcmu_ac[0]) != DDI_SUCCESS) {
1175*25cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: unable to map reg entry 0\n",
1176*25cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
1177*25cf1a30Sjl 		return (DDI_FAILURE);
1178*25cf1a30Sjl 	}
1179*25cf1a30Sjl 
1180*25cf1a30Sjl 	/*
1181*25cf1a30Sjl 	 * We still use pcmu_address[2]
1182*25cf1a30Sjl 	 */
1183*25cf1a30Sjl 	if (ddi_regs_map_setup(dip, 2, &pcmu_p->pcmu_address[2], 0, 0,
1184*25cf1a30Sjl 		&attr, &pcmu_p->pcmu_ac[2]) != DDI_SUCCESS) {
1185*25cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: unable to map reg entry 2\n",
1186*25cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
1187*25cf1a30Sjl 		ddi_regs_map_free(&pcmu_p->pcmu_ac[0]);
1188*25cf1a30Sjl 		return (DDI_FAILURE);
1189*25cf1a30Sjl 	}
1190*25cf1a30Sjl 
1191*25cf1a30Sjl 	/*
1192*25cf1a30Sjl 	 * The second register set contains the bridge's configuration
1193*25cf1a30Sjl 	 * header.  This header is at the very beginning of the bridge's
1194*25cf1a30Sjl 	 * configuration space.  This space has litte-endian byte order.
1195*25cf1a30Sjl 	 */
1196*25cf1a30Sjl 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1197*25cf1a30Sjl 	if (ddi_regs_map_setup(dip, 1, &pcmu_p->pcmu_address[1], 0,
1198*25cf1a30Sjl 	    PCI_CONF_HDR_SIZE, &attr, &pcmu_p->pcmu_ac[1]) != DDI_SUCCESS) {
1199*25cf1a30Sjl 
1200*25cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: unable to map reg entry 1\n",
1201*25cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
1202*25cf1a30Sjl 		ddi_regs_map_free(&pcmu_p->pcmu_ac[0]);
1203*25cf1a30Sjl 		return (DDI_FAILURE);
1204*25cf1a30Sjl 	}
1205*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_ATTACH, dip, "address (%p,%p)\n",
1206*25cf1a30Sjl 	    pcmu_p->pcmu_address[0], pcmu_p->pcmu_address[1]);
1207*25cf1a30Sjl 	return (DDI_SUCCESS);
1208*25cf1a30Sjl }
1209*25cf1a30Sjl 
1210*25cf1a30Sjl /*
1211*25cf1a30Sjl  * unmap_pcmu_registers:
1212*25cf1a30Sjl  *
1213*25cf1a30Sjl  * This routine unmap the registers mapped by map_pcmu_registers.
1214*25cf1a30Sjl  *
1215*25cf1a30Sjl  * used by: pcmu_detach()
1216*25cf1a30Sjl  *
1217*25cf1a30Sjl  * return value: none
1218*25cf1a30Sjl  */
1219*25cf1a30Sjl static void
1220*25cf1a30Sjl unmap_pcmu_registers(pcmu_t *pcmu_p)
1221*25cf1a30Sjl {
1222*25cf1a30Sjl 	ddi_regs_map_free(&pcmu_p->pcmu_ac[0]);
1223*25cf1a30Sjl 	ddi_regs_map_free(&pcmu_p->pcmu_ac[1]);
1224*25cf1a30Sjl 	ddi_regs_map_free(&pcmu_p->pcmu_ac[2]);
1225*25cf1a30Sjl }
1226*25cf1a30Sjl 
1227*25cf1a30Sjl /*
1228*25cf1a30Sjl  * These convenience wrappers relies on map_pcmu_registers() to setup
1229*25cf1a30Sjl  * pcmu_address[0-2] correctly at first.
1230*25cf1a30Sjl  */
1231*25cf1a30Sjl static uintptr_t
1232*25cf1a30Sjl get_reg_base(pcmu_t *pcmu_p)
1233*25cf1a30Sjl {
1234*25cf1a30Sjl 	return ((uintptr_t)pcmu_p->pcmu_address[2]);
1235*25cf1a30Sjl }
1236*25cf1a30Sjl 
1237*25cf1a30Sjl /* The CMU-CH config reg base is always the 2nd reg entry */
1238*25cf1a30Sjl static uintptr_t
1239*25cf1a30Sjl get_config_reg_base(pcmu_t *pcmu_p)
1240*25cf1a30Sjl {
1241*25cf1a30Sjl 	return ((uintptr_t)(pcmu_p->pcmu_address[1]));
1242*25cf1a30Sjl }
1243*25cf1a30Sjl 
1244*25cf1a30Sjl uint64_t
1245*25cf1a30Sjl ib_get_map_reg(pcmu_ib_mondo_t mondo, uint32_t cpu_id)
1246*25cf1a30Sjl {
1247*25cf1a30Sjl 	return ((mondo) | (cpu_id << PCMU_INTR_MAP_REG_TID_SHIFT) |
1248*25cf1a30Sjl 	    PCMU_INTR_MAP_REG_VALID);
1249*25cf1a30Sjl 
1250*25cf1a30Sjl }
1251*25cf1a30Sjl 
1252*25cf1a30Sjl uint32_t
1253*25cf1a30Sjl ib_map_reg_get_cpu(volatile uint64_t reg)
1254*25cf1a30Sjl {
1255*25cf1a30Sjl 	return ((reg & PCMU_INTR_MAP_REG_TID) >>
1256*25cf1a30Sjl 	    PCMU_INTR_MAP_REG_TID_SHIFT);
1257*25cf1a30Sjl }
1258*25cf1a30Sjl 
1259*25cf1a30Sjl uint64_t *
1260*25cf1a30Sjl ib_intr_map_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino)
1261*25cf1a30Sjl {
1262*25cf1a30Sjl 	uint64_t *addr;
1263*25cf1a30Sjl 
1264*25cf1a30Sjl 	ASSERT(ino & 0x20);
1265*25cf1a30Sjl 	addr = (uint64_t *)(pib_p->pib_obio_intr_map_regs +
1266*25cf1a30Sjl 	    (((uint_t)ino & 0x1f) << 3));
1267*25cf1a30Sjl 	return (addr);
1268*25cf1a30Sjl }
1269*25cf1a30Sjl 
1270*25cf1a30Sjl uint64_t *
1271*25cf1a30Sjl ib_clear_intr_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino)
1272*25cf1a30Sjl {
1273*25cf1a30Sjl 	uint64_t *addr;
1274*25cf1a30Sjl 
1275*25cf1a30Sjl 	ASSERT(ino & 0x20);
1276*25cf1a30Sjl 	addr = (uint64_t *)(pib_p->pib_obio_clear_intr_regs +
1277*25cf1a30Sjl 	    (((uint_t)ino & 0x1f) << 3));
1278*25cf1a30Sjl 	return (addr);
1279*25cf1a30Sjl }
1280*25cf1a30Sjl 
1281*25cf1a30Sjl uintptr_t
1282*25cf1a30Sjl pcmu_ib_setup(pcmu_ib_t *pib_p)
1283*25cf1a30Sjl {
1284*25cf1a30Sjl 	pcmu_t *pcmu_p = pib_p->pib_pcmu_p;
1285*25cf1a30Sjl 	uintptr_t a = get_reg_base(pcmu_p);
1286*25cf1a30Sjl 
1287*25cf1a30Sjl 	pib_p->pib_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id);
1288*25cf1a30Sjl 	pib_p->pib_max_ino = PCMU_MAX_INO;
1289*25cf1a30Sjl 	pib_p->pib_obio_intr_map_regs = a + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET;
1290*25cf1a30Sjl 	pib_p->pib_obio_clear_intr_regs =
1291*25cf1a30Sjl 		a + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET;
1292*25cf1a30Sjl 	return (a);
1293*25cf1a30Sjl }
1294*25cf1a30Sjl 
1295*25cf1a30Sjl /*
1296*25cf1a30Sjl  * Return the cpuid to to be used for an ino.
1297*25cf1a30Sjl  *
1298*25cf1a30Sjl  * On multi-function pci devices, functions have separate devinfo nodes and
1299*25cf1a30Sjl  * interrupts.
1300*25cf1a30Sjl  *
1301*25cf1a30Sjl  * This function determines if there is already an established slot-oriented
1302*25cf1a30Sjl  * interrupt-to-cpu binding established, if there is then it returns that
1303*25cf1a30Sjl  * cpu.  Otherwise a new cpu is selected by intr_dist_cpuid().
1304*25cf1a30Sjl  *
1305*25cf1a30Sjl  * The devinfo node we are trying to associate a cpu with is
1306*25cf1a30Sjl  * ino_p->pino_ih_head->ih_dip.
1307*25cf1a30Sjl  */
1308*25cf1a30Sjl uint32_t
1309*25cf1a30Sjl pcmu_intr_dist_cpuid(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p)
1310*25cf1a30Sjl {
1311*25cf1a30Sjl 	dev_info_t	*rdip = ino_p->pino_ih_head->ih_dip;
1312*25cf1a30Sjl 	dev_info_t	*prdip = ddi_get_parent(rdip);
1313*25cf1a30Sjl 	pcmu_ib_ino_info_t	*sino_p;
1314*25cf1a30Sjl 	dev_info_t	*sdip;
1315*25cf1a30Sjl 	dev_info_t	*psdip;
1316*25cf1a30Sjl 	char		*buf1 = NULL, *buf2 = NULL;
1317*25cf1a30Sjl 	char		*s1, *s2, *s3;
1318*25cf1a30Sjl 	int		l2;
1319*25cf1a30Sjl 	int		cpu_id;
1320*25cf1a30Sjl 
1321*25cf1a30Sjl 	/* must be CMU-CH driver parent (not ebus) */
1322*25cf1a30Sjl 	if (strcmp(ddi_driver_name(prdip), "pcicmu") != 0)
1323*25cf1a30Sjl 		goto newcpu;
1324*25cf1a30Sjl 
1325*25cf1a30Sjl 	/*
1326*25cf1a30Sjl 	 * From PCI 1275 binding: 2.2.1.3 Unit Address representation:
1327*25cf1a30Sjl 	 *   Since the "unit-number" is the address that appears in on Open
1328*25cf1a30Sjl 	 *   Firmware 'device path', it follows that only the DD and DD,FF
1329*25cf1a30Sjl 	 *   forms of the text representation can appear in a 'device path'.
1330*25cf1a30Sjl 	 *
1331*25cf1a30Sjl 	 * The rdip unit address is of the form "DD[,FF]".  Define two
1332*25cf1a30Sjl 	 * unit address strings that represent same-slot use: "DD" and "DD,".
1333*25cf1a30Sjl 	 * The first compare uses strcmp, the second uses strncmp.
1334*25cf1a30Sjl 	 */
1335*25cf1a30Sjl 	s1 = ddi_get_name_addr(rdip);
1336*25cf1a30Sjl 	if (s1 == NULL) {
1337*25cf1a30Sjl 		goto newcpu;
1338*25cf1a30Sjl 	}
1339*25cf1a30Sjl 
1340*25cf1a30Sjl 	buf1 = kmem_alloc(MAXNAMELEN, KM_SLEEP);	/* strcmp */
1341*25cf1a30Sjl 	buf2 = kmem_alloc(MAXNAMELEN, KM_SLEEP);	/* strncmp */
1342*25cf1a30Sjl 	s1 = strcpy(buf1, s1);
1343*25cf1a30Sjl 	s2 = strcpy(buf2, s1);
1344*25cf1a30Sjl 
1345*25cf1a30Sjl 	s1 = strrchr(s1, ',');
1346*25cf1a30Sjl 	if (s1) {
1347*25cf1a30Sjl 		*s1 = '\0';			/* have "DD,FF" */
1348*25cf1a30Sjl 		s1 = buf1;			/* search via strcmp "DD" */
1349*25cf1a30Sjl 
1350*25cf1a30Sjl 		s2 = strrchr(s2, ',');
1351*25cf1a30Sjl 		*(s2 + 1) = '\0';
1352*25cf1a30Sjl 		s2 = buf2;
1353*25cf1a30Sjl 		l2 = strlen(s2);		/* search via strncmp "DD," */
1354*25cf1a30Sjl 	} else {
1355*25cf1a30Sjl 		(void) strcat(s2, ",");		/* have "DD" */
1356*25cf1a30Sjl 		l2 = strlen(s2);		/* search via strncmp "DD," */
1357*25cf1a30Sjl 	}
1358*25cf1a30Sjl 
1359*25cf1a30Sjl 	/*
1360*25cf1a30Sjl 	 * Search the established ino list for devinfo nodes bound
1361*25cf1a30Sjl 	 * to an ino that matches one of the slot use strings.
1362*25cf1a30Sjl 	 */
1363*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex));
1364*25cf1a30Sjl 	for (sino_p = pib_p->pib_ino_lst; sino_p; sino_p = sino_p->pino_next) {
1365*25cf1a30Sjl 		/* skip self and non-established */
1366*25cf1a30Sjl 		if ((sino_p == ino_p) || (sino_p->pino_established == 0))
1367*25cf1a30Sjl 			continue;
1368*25cf1a30Sjl 
1369*25cf1a30Sjl 		/* skip non-siblings */
1370*25cf1a30Sjl 		sdip = sino_p->pino_ih_head->ih_dip;
1371*25cf1a30Sjl 		psdip = ddi_get_parent(sdip);
1372*25cf1a30Sjl 		if (psdip != prdip)
1373*25cf1a30Sjl 			continue;
1374*25cf1a30Sjl 
1375*25cf1a30Sjl 		/* must be CMU-CH driver parent (not ebus) */
1376*25cf1a30Sjl 		if (strcmp(ddi_driver_name(psdip), "pcicmu") != 0)
1377*25cf1a30Sjl 			continue;
1378*25cf1a30Sjl 
1379*25cf1a30Sjl 		s3 = ddi_get_name_addr(sdip);
1380*25cf1a30Sjl 		if ((s1 && (strcmp(s1, s3) == 0)) ||
1381*25cf1a30Sjl 		    (strncmp(s2, s3, l2) == 0)) {
1382*25cf1a30Sjl 			extern int intr_dist_debug;
1383*25cf1a30Sjl 
1384*25cf1a30Sjl 			if (intr_dist_debug) {
1385*25cf1a30Sjl 				cmn_err(CE_CONT, "intr_dist: "
1386*25cf1a30Sjl 				    "pcicmu`pcmu_intr_dist_cpuid "
1387*25cf1a30Sjl 				    "%s#%d %s: cpu %d established "
1388*25cf1a30Sjl 				    "by %s#%d %s\n", ddi_driver_name(rdip),
1389*25cf1a30Sjl 				    ddi_get_instance(rdip),
1390*25cf1a30Sjl 				    ddi_deviname(rdip, buf1),
1391*25cf1a30Sjl 				    sino_p->pino_cpuid,
1392*25cf1a30Sjl 				    ddi_driver_name(sdip),
1393*25cf1a30Sjl 				    ddi_get_instance(sdip),
1394*25cf1a30Sjl 				    ddi_deviname(sdip, buf2));
1395*25cf1a30Sjl 			}
1396*25cf1a30Sjl 			break;
1397*25cf1a30Sjl 		}
1398*25cf1a30Sjl 	}
1399*25cf1a30Sjl 
1400*25cf1a30Sjl 	/* If a slot use match is found then use established cpu */
1401*25cf1a30Sjl 	if (sino_p) {
1402*25cf1a30Sjl 		cpu_id = sino_p->pino_cpuid;	/* target established cpu */
1403*25cf1a30Sjl 		goto out;
1404*25cf1a30Sjl 	}
1405*25cf1a30Sjl 
1406*25cf1a30Sjl newcpu:	cpu_id = intr_dist_cpuid();		/* target new cpu */
1407*25cf1a30Sjl 
1408*25cf1a30Sjl out:	if (buf1)
1409*25cf1a30Sjl 		kmem_free(buf1, MAXNAMELEN);
1410*25cf1a30Sjl 	if (buf2)
1411*25cf1a30Sjl 		kmem_free(buf2, MAXNAMELEN);
1412*25cf1a30Sjl 	return (cpu_id);
1413*25cf1a30Sjl }
1414*25cf1a30Sjl 
1415*25cf1a30Sjl void
1416*25cf1a30Sjl pcmu_cb_teardown(pcmu_t *pcmu_p)
1417*25cf1a30Sjl {
1418*25cf1a30Sjl 	pcmu_cb_t	*pcb_p = pcmu_p->pcmu_cb_p;
1419*25cf1a30Sjl 
1420*25cf1a30Sjl 	u2u_ittrans_uninit((u2u_ittrans_data_t *)pcb_p->pcb_ittrans_cookie);
1421*25cf1a30Sjl }
1422*25cf1a30Sjl 
1423*25cf1a30Sjl int
1424*25cf1a30Sjl pcmu_ecc_add_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p)
1425*25cf1a30Sjl {
1426*25cf1a30Sjl 	uint32_t mondo;
1427*25cf1a30Sjl 
1428*25cf1a30Sjl 	mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) |
1429*25cf1a30Sjl 	    pcmu_p->pcmu_inos[inum]);
1430*25cf1a30Sjl 
1431*25cf1a30Sjl 	VERIFY(add_ivintr(mondo, pcmu_pil[inum], pcmu_ecc_intr,
1432*25cf1a30Sjl 	    (caddr_t)eii_p, NULL) == 0);
1433*25cf1a30Sjl 	return (PCMU_ATTACH_RETCODE(PCMU_ECC_OBJ,
1434*25cf1a30Sjl 	    PCMU_OBJ_INTR_ADD, DDI_SUCCESS));
1435*25cf1a30Sjl }
1436*25cf1a30Sjl 
1437*25cf1a30Sjl /* ARGSUSED */
1438*25cf1a30Sjl void
1439*25cf1a30Sjl pcmu_ecc_rem_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p)
1440*25cf1a30Sjl {
1441*25cf1a30Sjl 	uint32_t mondo;
1442*25cf1a30Sjl 
1443*25cf1a30Sjl 	mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) |
1444*25cf1a30Sjl 	    pcmu_p->pcmu_inos[inum]);
1445*25cf1a30Sjl 	rem_ivintr(mondo, NULL);
1446*25cf1a30Sjl }
1447*25cf1a30Sjl 
1448*25cf1a30Sjl void
1449*25cf1a30Sjl pcmu_pbm_configure(pcmu_pbm_t *pcbm_p)
1450*25cf1a30Sjl {
1451*25cf1a30Sjl 	pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
1452*25cf1a30Sjl 	dev_info_t *dip = pcmu_p->pcmu_dip;
1453*25cf1a30Sjl 
1454*25cf1a30Sjl #define	pbm_err	((PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_PE_SHIFT) |	\
1455*25cf1a30Sjl 		(PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_SE_SHIFT))
1456*25cf1a30Sjl #define	csr_err	(PCI_STAT_PERROR | PCI_STAT_S_PERROR |		\
1457*25cf1a30Sjl 		PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB |	\
1458*25cf1a30Sjl 		PCI_STAT_S_TARG_AB | PCI_STAT_S_PERROR)
1459*25cf1a30Sjl 
1460*25cf1a30Sjl 	/*
1461*25cf1a30Sjl 	 * Clear any PBM errors.
1462*25cf1a30Sjl 	 */
1463*25cf1a30Sjl 	*pcbm_p->pcbm_async_flt_status_reg = pbm_err;
1464*25cf1a30Sjl 
1465*25cf1a30Sjl 	/*
1466*25cf1a30Sjl 	 * Clear error bits in configuration status register.
1467*25cf1a30Sjl 	 */
1468*25cf1a30Sjl 	PCMU_DBG1(PCMU_DBG_ATTACH, dip,
1469*25cf1a30Sjl 	    "pcmu_pbm_configure: conf status reg=%x\n", csr_err);
1470*25cf1a30Sjl 
1471*25cf1a30Sjl 	pcbm_p->pcbm_config_header->ch_status_reg = csr_err;
1472*25cf1a30Sjl 
1473*25cf1a30Sjl 	PCMU_DBG1(PCMU_DBG_ATTACH, dip,
1474*25cf1a30Sjl 	    "pcmu_pbm_configure: conf status reg==%x\n",
1475*25cf1a30Sjl 	    pcbm_p->pcbm_config_header->ch_status_reg);
1476*25cf1a30Sjl 
1477*25cf1a30Sjl 	(void) ndi_prop_update_int(DDI_DEV_T_ANY, dip, "latency-timer",
1478*25cf1a30Sjl 		(int)pcbm_p->pcbm_config_header->ch_latency_timer_reg);
1479*25cf1a30Sjl #undef	pbm_err
1480*25cf1a30Sjl #undef	csr_err
1481*25cf1a30Sjl }
1482*25cf1a30Sjl 
1483*25cf1a30Sjl uint_t
1484*25cf1a30Sjl pcmu_pbm_disable_errors(pcmu_pbm_t *pcbm_p)
1485*25cf1a30Sjl {
1486*25cf1a30Sjl 	pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
1487*25cf1a30Sjl 	pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p;
1488*25cf1a30Sjl 
1489*25cf1a30Sjl 	/*
1490*25cf1a30Sjl 	 * Disable error and streaming byte hole interrupts via the
1491*25cf1a30Sjl 	 * PBM control register.
1492*25cf1a30Sjl 	 */
1493*25cf1a30Sjl 	*pcbm_p->pcbm_ctrl_reg &= ~PCMU_PCI_CTRL_ERR_INT_EN;
1494*25cf1a30Sjl 
1495*25cf1a30Sjl 	/*
1496*25cf1a30Sjl 	 * Disable error interrupts via the interrupt mapping register.
1497*25cf1a30Sjl 	 */
1498*25cf1a30Sjl 	pcmu_ib_intr_disable(pib_p,
1499*25cf1a30Sjl 	    pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_NOWAIT);
1500*25cf1a30Sjl 	return (BF_NONE);
1501*25cf1a30Sjl }
1502*25cf1a30Sjl 
1503*25cf1a30Sjl void
1504*25cf1a30Sjl pcmu_cb_setup(pcmu_t *pcmu_p)
1505*25cf1a30Sjl {
1506*25cf1a30Sjl 	uint64_t csr, csr_pa, pa;
1507*25cf1a30Sjl 	pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p;
1508*25cf1a30Sjl 
1509*25cf1a30Sjl 	pcb_p->pcb_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id);
1510*25cf1a30Sjl 	pa = (uint64_t)hat_getpfnum(kas.a_hat, pcmu_p->pcmu_address[0]);
1511*25cf1a30Sjl 	pcb_p->pcb_base_pa  = pa = pa >> (32 - MMU_PAGESHIFT) << 32;
1512*25cf1a30Sjl 	pcb_p->pcb_map_pa = pa + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET;
1513*25cf1a30Sjl 	pcb_p->pcb_clr_pa = pa + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET;
1514*25cf1a30Sjl 	pcb_p->pcb_obsta_pa = pa + PCMU_IB_OBIO_INTR_STATE_DIAG_REG;
1515*25cf1a30Sjl 
1516*25cf1a30Sjl 	csr_pa = pa + PCMU_CB_CONTROL_STATUS_REG_OFFSET;
1517*25cf1a30Sjl 	csr = lddphysio(csr_pa);
1518*25cf1a30Sjl 
1519*25cf1a30Sjl 	/*
1520*25cf1a30Sjl 	 * Clear any pending address parity errors.
1521*25cf1a30Sjl 	 */
1522*25cf1a30Sjl 	if (csr & PCMU_CB_CONTROL_STATUS_APERR) {
1523*25cf1a30Sjl 		csr |= PCMU_CB_CONTROL_STATUS_APERR;
1524*25cf1a30Sjl 		cmn_err(CE_WARN, "clearing UPA address parity error\n");
1525*25cf1a30Sjl 	}
1526*25cf1a30Sjl 	csr |= PCMU_CB_CONTROL_STATUS_APCKEN;
1527*25cf1a30Sjl 	csr &= ~PCMU_CB_CONTROL_STATUS_IAP;
1528*25cf1a30Sjl 	stdphysio(csr_pa, csr);
1529*25cf1a30Sjl 
1530*25cf1a30Sjl 	u2u_ittrans_init(pcmu_p,
1531*25cf1a30Sjl 	    (u2u_ittrans_data_t **)&pcb_p->pcb_ittrans_cookie);
1532*25cf1a30Sjl }
1533*25cf1a30Sjl 
1534*25cf1a30Sjl void
1535*25cf1a30Sjl pcmu_ecc_setup(pcmu_ecc_t *pecc_p)
1536*25cf1a30Sjl {
1537*25cf1a30Sjl 	pecc_p->pecc_ue.pecc_errpndg_mask = 0;
1538*25cf1a30Sjl 	pecc_p->pecc_ue.pecc_offset_mask = PCMU_ECC_UE_AFSR_DW_OFFSET;
1539*25cf1a30Sjl 	pecc_p->pecc_ue.pecc_offset_shift = PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT;
1540*25cf1a30Sjl 	pecc_p->pecc_ue.pecc_size_log2 = 3;
1541*25cf1a30Sjl }
1542*25cf1a30Sjl 
1543*25cf1a30Sjl static uintptr_t
1544*25cf1a30Sjl get_pbm_reg_base(pcmu_t *pcmu_p)
1545*25cf1a30Sjl {
1546*25cf1a30Sjl 	return ((uintptr_t)(pcmu_p->pcmu_address[0]));
1547*25cf1a30Sjl }
1548*25cf1a30Sjl 
1549*25cf1a30Sjl void
1550*25cf1a30Sjl pcmu_pbm_setup(pcmu_pbm_t *pcbm_p)
1551*25cf1a30Sjl {
1552*25cf1a30Sjl 	pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
1553*25cf1a30Sjl 
1554*25cf1a30Sjl 	/*
1555*25cf1a30Sjl 	 * Get the base virtual address for the PBM control block.
1556*25cf1a30Sjl 	 */
1557*25cf1a30Sjl 	uintptr_t a = get_pbm_reg_base(pcmu_p);
1558*25cf1a30Sjl 
1559*25cf1a30Sjl 	/*
1560*25cf1a30Sjl 	 * Get the virtual address of the PCI configuration header.
1561*25cf1a30Sjl 	 * This should be mapped little-endian.
1562*25cf1a30Sjl 	 */
1563*25cf1a30Sjl 	pcbm_p->pcbm_config_header =
1564*25cf1a30Sjl 		(config_header_t *)get_config_reg_base(pcmu_p);
1565*25cf1a30Sjl 
1566*25cf1a30Sjl 	/*
1567*25cf1a30Sjl 	 * Get the virtual addresses for control, error and diag
1568*25cf1a30Sjl 	 * registers.
1569*25cf1a30Sjl 	 */
1570*25cf1a30Sjl 	pcbm_p->pcbm_ctrl_reg = (uint64_t *)(a + PCMU_PCI_CTRL_REG_OFFSET);
1571*25cf1a30Sjl 	pcbm_p->pcbm_diag_reg = (uint64_t *)(a + PCMU_PCI_DIAG_REG_OFFSET);
1572*25cf1a30Sjl 	pcbm_p->pcbm_async_flt_status_reg =
1573*25cf1a30Sjl 	    (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_STATUS_REG_OFFSET);
1574*25cf1a30Sjl 	pcbm_p->pcbm_async_flt_addr_reg =
1575*25cf1a30Sjl 	    (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_ADDR_REG_OFFSET);
1576*25cf1a30Sjl }
1577*25cf1a30Sjl 
1578*25cf1a30Sjl /*ARGSUSED*/
1579*25cf1a30Sjl void
1580*25cf1a30Sjl pcmu_pbm_teardown(pcmu_pbm_t *pcbm_p)
1581*25cf1a30Sjl {
1582*25cf1a30Sjl }
1583*25cf1a30Sjl 
1584*25cf1a30Sjl int
1585*25cf1a30Sjl pcmu_get_numproxy(dev_info_t *dip)
1586*25cf1a30Sjl {
1587*25cf1a30Sjl 	return (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1588*25cf1a30Sjl 		"#upa-interrupt-proxies", 1));
1589*25cf1a30Sjl }
1590*25cf1a30Sjl 
1591*25cf1a30Sjl int
1592*25cf1a30Sjl pcmu_get_portid(dev_info_t *dip)
1593*25cf1a30Sjl {
1594*25cf1a30Sjl 	return (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1595*25cf1a30Sjl 	    "portid", -1));
1596*25cf1a30Sjl }
1597*25cf1a30Sjl 
1598*25cf1a30Sjl /*
1599*25cf1a30Sjl  * CMU-CH Performance Events.
1600*25cf1a30Sjl  */
1601*25cf1a30Sjl static pcmu_kev_mask_t
1602*25cf1a30Sjl pcicmu_pcmu_events[] = {
1603*25cf1a30Sjl 	{"pio_cycles_b", 0xf},		{"interrupts", 0x11},
1604*25cf1a30Sjl 	{"upa_inter_nack", 0x12},	{"pio_reads", 0x13},
1605*25cf1a30Sjl 	{"pio_writes", 0x14},
1606*25cf1a30Sjl 	{"clear_pic", 0x1f}
1607*25cf1a30Sjl };
1608*25cf1a30Sjl 
1609*25cf1a30Sjl /*
1610*25cf1a30Sjl  * Create the picN kstat's.
1611*25cf1a30Sjl  */
1612*25cf1a30Sjl void
1613*25cf1a30Sjl pcmu_kstat_init()
1614*25cf1a30Sjl {
1615*25cf1a30Sjl 	pcmu_name_kstat = (pcmu_ksinfo_t *)kmem_alloc(sizeof (pcmu_ksinfo_t),
1616*25cf1a30Sjl 		KM_NOSLEEP);
1617*25cf1a30Sjl 
1618*25cf1a30Sjl 	if (pcmu_name_kstat == NULL) {
1619*25cf1a30Sjl 		cmn_err(CE_WARN, "pcicmu : no space for kstat\n");
1620*25cf1a30Sjl 	} else {
1621*25cf1a30Sjl 		pcmu_name_kstat->pic_no_evs =
1622*25cf1a30Sjl 			sizeof (pcicmu_pcmu_events) / sizeof (pcmu_kev_mask_t);
1623*25cf1a30Sjl 		pcmu_name_kstat->pic_shift[0] = PCMU_SHIFT_PIC0;
1624*25cf1a30Sjl 		pcmu_name_kstat->pic_shift[1] = PCMU_SHIFT_PIC1;
1625*25cf1a30Sjl 		pcmu_create_name_kstat("pcmup",
1626*25cf1a30Sjl 			pcmu_name_kstat, pcicmu_pcmu_events);
1627*25cf1a30Sjl 	}
1628*25cf1a30Sjl }
1629*25cf1a30Sjl 
1630*25cf1a30Sjl /*
1631*25cf1a30Sjl  * Called from _fini()
1632*25cf1a30Sjl  */
1633*25cf1a30Sjl void
1634*25cf1a30Sjl pcmu_kstat_fini()
1635*25cf1a30Sjl {
1636*25cf1a30Sjl 	if (pcmu_name_kstat != NULL) {
1637*25cf1a30Sjl 		pcmu_delete_name_kstat(pcmu_name_kstat);
1638*25cf1a30Sjl 		kmem_free(pcmu_name_kstat, sizeof (pcmu_ksinfo_t));
1639*25cf1a30Sjl 		pcmu_name_kstat = NULL;
1640*25cf1a30Sjl 	}
1641*25cf1a30Sjl }
1642*25cf1a30Sjl 
1643*25cf1a30Sjl /*
1644*25cf1a30Sjl  * Create the performance 'counters' kstat.
1645*25cf1a30Sjl  */
1646*25cf1a30Sjl void
1647*25cf1a30Sjl pcmu_add_upstream_kstat(pcmu_t *pcmu_p)
1648*25cf1a30Sjl {
1649*25cf1a30Sjl 	pcmu_cntr_pa_t	*cntr_pa_p = &pcmu_p->pcmu_uks_pa;
1650*25cf1a30Sjl 	uint64_t regbase = va_to_pa((void *)get_reg_base(pcmu_p));
1651*25cf1a30Sjl 
1652*25cf1a30Sjl 	cntr_pa_p->pcr_pa = regbase + PCMU_PERF_PCR_OFFSET;
1653*25cf1a30Sjl 	cntr_pa_p->pic_pa = regbase + PCMU_PERF_PIC_OFFSET;
1654*25cf1a30Sjl 	pcmu_p->pcmu_uksp = pcmu_create_cntr_kstat(pcmu_p, "pcmup",
1655*25cf1a30Sjl 		NUM_OF_PICS, pcmu_cntr_kstat_pa_update, cntr_pa_p);
1656*25cf1a30Sjl }
1657*25cf1a30Sjl 
1658*25cf1a30Sjl /*
1659*25cf1a30Sjl  * u2u_ittrans_init() is caled from in pci.c's pcmu_cb_setup() per CMU.
1660*25cf1a30Sjl  * Second argument "ittrans_cookie" is address of pcb_ittrans_cookie in
1661*25cf1a30Sjl  * pcb_p member. allocated interrupt block is returned in it.
1662*25cf1a30Sjl  */
1663*25cf1a30Sjl static void
1664*25cf1a30Sjl u2u_ittrans_init(pcmu_t *pcmu_p, u2u_ittrans_data_t **ittrans_cookie)
1665*25cf1a30Sjl {
1666*25cf1a30Sjl 
1667*25cf1a30Sjl 	u2u_ittrans_data_t *u2u_trans_p;
1668*25cf1a30Sjl 	ddi_device_acc_attr_t attr;
1669*25cf1a30Sjl 	int ret;
1670*25cf1a30Sjl 	int board;
1671*25cf1a30Sjl 
1672*25cf1a30Sjl 	/*
1673*25cf1a30Sjl 	 * Allocate the data structure to support U2U's
1674*25cf1a30Sjl 	 * interrupt target translations.
1675*25cf1a30Sjl 	 */
1676*25cf1a30Sjl 	u2u_trans_p = (u2u_ittrans_data_t *)
1677*25cf1a30Sjl 	    kmem_zalloc(sizeof (u2u_ittrans_data_t), KM_SLEEP);
1678*25cf1a30Sjl 
1679*25cf1a30Sjl 	/*
1680*25cf1a30Sjl 	 * Get other properties, "board#"
1681*25cf1a30Sjl 	 */
1682*25cf1a30Sjl 	board = ddi_getprop(DDI_DEV_T_ANY, pcmu_p->pcmu_dip,
1683*25cf1a30Sjl 	    DDI_PROP_DONTPASS, "board#", -1);
1684*25cf1a30Sjl 
1685*25cf1a30Sjl 	u2u_trans_p->u2u_board = board;
1686*25cf1a30Sjl 
1687*25cf1a30Sjl 	if (board == -1) {
1688*25cf1a30Sjl 		/* this cannot happen on production systems */
1689*25cf1a30Sjl 		cmn_err(CE_PANIC, "u2u:Invalid property;board = %d", board);
1690*25cf1a30Sjl 	}
1691*25cf1a30Sjl 
1692*25cf1a30Sjl 	/*
1693*25cf1a30Sjl 	 * Initialize interrupt target translations mutex.
1694*25cf1a30Sjl 	 */
1695*25cf1a30Sjl 	mutex_init(&(u2u_trans_p->u2u_ittrans_lock), "u2u_ittrans_lock",
1696*25cf1a30Sjl 	    MUTEX_DEFAULT, NULL);
1697*25cf1a30Sjl 
1698*25cf1a30Sjl 	/*
1699*25cf1a30Sjl 	 * Get U2U's registers space by ddi_regs_map_setup(9F)
1700*25cf1a30Sjl 	 */
1701*25cf1a30Sjl 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1702*25cf1a30Sjl 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1703*25cf1a30Sjl 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
1704*25cf1a30Sjl 
1705*25cf1a30Sjl 	ret = ddi_regs_map_setup(pcmu_p->pcmu_dip,
1706*25cf1a30Sjl 	    REGS_INDEX_OF_U2U, (caddr_t *)(&(u2u_trans_p->u2u_regs_base)),
1707*25cf1a30Sjl 	    0, 0, &attr, &(u2u_trans_p->u2u_acc));
1708*25cf1a30Sjl 
1709*25cf1a30Sjl 	/*
1710*25cf1a30Sjl 	 * check result of ddi_regs_map_setup().
1711*25cf1a30Sjl 	 */
1712*25cf1a30Sjl 	if (ret != DDI_SUCCESS) {
1713*25cf1a30Sjl 		cmn_err(CE_PANIC, "u2u%d: registers map setup failed", board);
1714*25cf1a30Sjl 	}
1715*25cf1a30Sjl 
1716*25cf1a30Sjl 	/*
1717*25cf1a30Sjl 	 * Read Port-id(1 byte) in u2u
1718*25cf1a30Sjl 	 */
1719*25cf1a30Sjl 	u2u_trans_p->u2u_port_id = *(volatile int32_t *)
1720*25cf1a30Sjl 	    (u2u_trans_p->u2u_regs_base + U2U_PID_REGISTER_OFFSET);
1721*25cf1a30Sjl 
1722*25cf1a30Sjl 	if (pcmu_p->pcmu_id != u2u_trans_p->u2u_port_id) {
1723*25cf1a30Sjl 		cmn_err(CE_PANIC, "u2u%d: Invalid Port-ID", board);
1724*25cf1a30Sjl 	}
1725*25cf1a30Sjl 
1726*25cf1a30Sjl 	*ittrans_cookie = u2u_trans_p;
1727*25cf1a30Sjl }
1728*25cf1a30Sjl 
1729*25cf1a30Sjl /*
1730*25cf1a30Sjl  * u2u_ittras_resume() is called from pcmu_obj_resume() at DDI_RESUME entry.
1731*25cf1a30Sjl  */
1732*25cf1a30Sjl static void
1733*25cf1a30Sjl u2u_ittrans_resume(u2u_ittrans_data_t **ittrans_cookie)
1734*25cf1a30Sjl {
1735*25cf1a30Sjl 
1736*25cf1a30Sjl 	u2u_ittrans_data_t *u2u_trans_p;
1737*25cf1a30Sjl 	u2u_ittrans_id_t *ittrans_id_p;
1738*25cf1a30Sjl 	uintptr_t  data_reg_addr;
1739*25cf1a30Sjl 	int ix;
1740*25cf1a30Sjl 
1741*25cf1a30Sjl 	u2u_trans_p = *ittrans_cookie;
1742*25cf1a30Sjl 
1743*25cf1a30Sjl 	/*
1744*25cf1a30Sjl 	 * Set U2U Data Register
1745*25cf1a30Sjl 	 */
1746*25cf1a30Sjl 	for (ix = 0; ix < U2U_DATA_NUM; ix++) {
1747*25cf1a30Sjl 		ittrans_id_p = &(u2u_trans_p->u2u_ittrans_id[ix]);
1748*25cf1a30Sjl 		data_reg_addr = u2u_trans_p->u2u_regs_base +
1749*25cf1a30Sjl 		    U2U_DATA_REGISTER_OFFSET + (ix * sizeof (uint64_t));
1750*25cf1a30Sjl 		if (ittrans_id_p->u2u_ino_map_reg == NULL) {
1751*25cf1a30Sjl 			/* This index was not set */
1752*25cf1a30Sjl 			continue;
1753*25cf1a30Sjl 		}
1754*25cf1a30Sjl 		*(volatile uint32_t *) (data_reg_addr) =
1755*25cf1a30Sjl 		    (uint32_t)ittrans_id_p->u2u_tgt_cpu_id;
1756*25cf1a30Sjl 
1757*25cf1a30Sjl 	}
1758*25cf1a30Sjl }
1759*25cf1a30Sjl 
1760*25cf1a30Sjl /*
1761*25cf1a30Sjl  * u2u_ittras_uninit() is called from ib_destroy() at detach,
1762*25cf1a30Sjl  * or occuring error in attach.
1763*25cf1a30Sjl  */
1764*25cf1a30Sjl static void
1765*25cf1a30Sjl u2u_ittrans_uninit(u2u_ittrans_data_t *ittrans_cookie)
1766*25cf1a30Sjl {
1767*25cf1a30Sjl 
1768*25cf1a30Sjl 	if (ittrans_cookie == NULL) {
1769*25cf1a30Sjl 		return;	/* not support */
1770*25cf1a30Sjl 	}
1771*25cf1a30Sjl 
1772*25cf1a30Sjl 	if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) {
1773*25cf1a30Sjl 		return;	 /* illeagal case */
1774*25cf1a30Sjl 	}
1775*25cf1a30Sjl 
1776*25cf1a30Sjl 	ddi_regs_map_free(&(ittrans_cookie->u2u_acc));
1777*25cf1a30Sjl 	mutex_destroy(&(ittrans_cookie->u2u_ittrans_lock));
1778*25cf1a30Sjl 	kmem_free((void *)ittrans_cookie, sizeof (u2u_ittrans_data_t));
1779*25cf1a30Sjl }
1780*25cf1a30Sjl 
1781*25cf1a30Sjl /*
1782*25cf1a30Sjl  * This routine,u2u_translate_tgtid(, , cpu_id, pino_map_reg),
1783*25cf1a30Sjl  * searches index having same value of pino_map_reg, or empty.
1784*25cf1a30Sjl  * Then, stores cpu_id in a U2U Data Register as this index,
1785*25cf1a30Sjl  * and return this index.
1786*25cf1a30Sjl  */
1787*25cf1a30Sjl int
1788*25cf1a30Sjl u2u_translate_tgtid(pcmu_t *pcmu_p, uint_t cpu_id,
1789*25cf1a30Sjl     volatile uint64_t *pino_map_reg)
1790*25cf1a30Sjl {
1791*25cf1a30Sjl 
1792*25cf1a30Sjl 	int index = -1;
1793*25cf1a30Sjl 	int ix;
1794*25cf1a30Sjl 	int err_level;	/* severity level for cmn_err */
1795*25cf1a30Sjl 	u2u_ittrans_id_t *ittrans_id_p;
1796*25cf1a30Sjl 	uintptr_t  data_reg_addr;
1797*25cf1a30Sjl 	u2u_ittrans_data_t *ittrans_cookie;
1798*25cf1a30Sjl 
1799*25cf1a30Sjl 	ittrans_cookie =
1800*25cf1a30Sjl 		(u2u_ittrans_data_t *)(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie);
1801*25cf1a30Sjl 
1802*25cf1a30Sjl 	if (ittrans_cookie == NULL) {
1803*25cf1a30Sjl 		return (cpu_id);
1804*25cf1a30Sjl 	}
1805*25cf1a30Sjl 
1806*25cf1a30Sjl 	if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) {
1807*25cf1a30Sjl 		return (-1);	 /* illeagal case */
1808*25cf1a30Sjl 	}
1809*25cf1a30Sjl 
1810*25cf1a30Sjl 	mutex_enter(&(ittrans_cookie->u2u_ittrans_lock));
1811*25cf1a30Sjl 
1812*25cf1a30Sjl 	/*
1813*25cf1a30Sjl 	 * Decide index No. of U2U Data registers in either
1814*25cf1a30Sjl 	 * already used by same pino_map_reg, or empty.
1815*25cf1a30Sjl 	 */
1816*25cf1a30Sjl 	for (ix = 0; ix < U2U_DATA_NUM; ix++) {
1817*25cf1a30Sjl 		ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]);
1818*25cf1a30Sjl 		if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) {
1819*25cf1a30Sjl 			/* already used this pino_map_reg */
1820*25cf1a30Sjl 			index = ix;
1821*25cf1a30Sjl 			break;
1822*25cf1a30Sjl 		}
1823*25cf1a30Sjl 		if (index == -1 &&
1824*25cf1a30Sjl 			ittrans_id_p->u2u_ino_map_reg == NULL) {
1825*25cf1a30Sjl 			index = ix;
1826*25cf1a30Sjl 		}
1827*25cf1a30Sjl 	}
1828*25cf1a30Sjl 
1829*25cf1a30Sjl 	if (index == -1) {
1830*25cf1a30Sjl 		if (panicstr) {
1831*25cf1a30Sjl 			err_level = CE_WARN;
1832*25cf1a30Sjl 		} else {
1833*25cf1a30Sjl 			err_level = CE_PANIC;
1834*25cf1a30Sjl 		}
1835*25cf1a30Sjl 		cmn_err(err_level, "u2u%d:No more U2U-Data regs!!",
1836*25cf1a30Sjl 			ittrans_cookie->u2u_board);
1837*25cf1a30Sjl 		return (cpu_id);
1838*25cf1a30Sjl 	}
1839*25cf1a30Sjl 
1840*25cf1a30Sjl 	/*
1841*25cf1a30Sjl 	 * For U2U
1842*25cf1a30Sjl 	 * set cpu_id into u2u_data_reg by index.
1843*25cf1a30Sjl 	 * ((uint64_t)(u2u_regs_base
1844*25cf1a30Sjl 	 *	+ U2U_DATA_REGISTER_OFFSET))[index] = cpu_id;
1845*25cf1a30Sjl 	 */
1846*25cf1a30Sjl 
1847*25cf1a30Sjl 	data_reg_addr = ittrans_cookie->u2u_regs_base
1848*25cf1a30Sjl 			+ U2U_DATA_REGISTER_OFFSET
1849*25cf1a30Sjl 			+ (index * sizeof (uint64_t));
1850*25cf1a30Sjl 
1851*25cf1a30Sjl 	/*
1852*25cf1a30Sjl 	 * Set cpu_id into U2U Data register[index]
1853*25cf1a30Sjl 	 */
1854*25cf1a30Sjl 	*(volatile uint32_t *) (data_reg_addr) = (uint32_t)cpu_id;
1855*25cf1a30Sjl 
1856*25cf1a30Sjl 	/*
1857*25cf1a30Sjl 	 * Setup for software, excepting at panicing.
1858*25cf1a30Sjl 	 * and rebooting, etc...?
1859*25cf1a30Sjl 	 */
1860*25cf1a30Sjl 	if (!panicstr) {
1861*25cf1a30Sjl 		ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[index]);
1862*25cf1a30Sjl 		ittrans_id_p->u2u_tgt_cpu_id = cpu_id;
1863*25cf1a30Sjl 		ittrans_id_p->u2u_ino_map_reg = pino_map_reg;
1864*25cf1a30Sjl 	}
1865*25cf1a30Sjl 
1866*25cf1a30Sjl 	mutex_exit(&(ittrans_cookie->u2u_ittrans_lock));
1867*25cf1a30Sjl 
1868*25cf1a30Sjl 	return (index);
1869*25cf1a30Sjl }
1870*25cf1a30Sjl 
1871*25cf1a30Sjl /*
1872*25cf1a30Sjl  * u2u_ittrans_cleanup() is called from common_pcmu_ib_intr_disable()
1873*25cf1a30Sjl  * after called intr_rem_cpu(mondo).
1874*25cf1a30Sjl  */
1875*25cf1a30Sjl void
1876*25cf1a30Sjl u2u_ittrans_cleanup(u2u_ittrans_data_t *ittrans_cookie,
1877*25cf1a30Sjl 			volatile uint64_t *pino_map_reg)
1878*25cf1a30Sjl {
1879*25cf1a30Sjl 
1880*25cf1a30Sjl 	int ix;
1881*25cf1a30Sjl 	u2u_ittrans_id_t *ittrans_id_p;
1882*25cf1a30Sjl 
1883*25cf1a30Sjl 	if (ittrans_cookie == NULL) {
1884*25cf1a30Sjl 		return;
1885*25cf1a30Sjl 	}
1886*25cf1a30Sjl 
1887*25cf1a30Sjl 	if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) {
1888*25cf1a30Sjl 		return;	 /* illeagal case */
1889*25cf1a30Sjl 	}
1890*25cf1a30Sjl 
1891*25cf1a30Sjl 	mutex_enter(&(ittrans_cookie->u2u_ittrans_lock));
1892*25cf1a30Sjl 
1893*25cf1a30Sjl 	for (ix = 0; ix < U2U_DATA_NUM; ix++) {
1894*25cf1a30Sjl 		ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]);
1895*25cf1a30Sjl 		if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) {
1896*25cf1a30Sjl 			ittrans_id_p->u2u_ino_map_reg = NULL;
1897*25cf1a30Sjl 			break;
1898*25cf1a30Sjl 		}
1899*25cf1a30Sjl 	}
1900*25cf1a30Sjl 
1901*25cf1a30Sjl 	mutex_exit(&(ittrans_cookie->u2u_ittrans_lock));
1902*25cf1a30Sjl }
1903*25cf1a30Sjl 
1904*25cf1a30Sjl /*
1905*25cf1a30Sjl  * pcmu_ecc_classify, called by ecc_handler to classify ecc errors
1906*25cf1a30Sjl  * and determine if we should panic or not.
1907*25cf1a30Sjl  */
1908*25cf1a30Sjl void
1909*25cf1a30Sjl pcmu_ecc_classify(uint64_t err, pcmu_ecc_errstate_t *ecc_err_p)
1910*25cf1a30Sjl {
1911*25cf1a30Sjl 	struct async_flt *ecc = &ecc_err_p->ecc_aflt;
1912*25cf1a30Sjl 	/* LINTED */
1913*25cf1a30Sjl 	pcmu_t *pcmu_p = ecc_err_p->ecc_ii_p.pecc_p->pecc_pcmu_p;
1914*25cf1a30Sjl 
1915*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
1916*25cf1a30Sjl 
1917*25cf1a30Sjl 	ecc_err_p->ecc_bridge_type = PCI_OPLCMU;	/* RAGS */
1918*25cf1a30Sjl 	/*
1919*25cf1a30Sjl 	 * Get the parent bus id that caused the error.
1920*25cf1a30Sjl 	 */
1921*25cf1a30Sjl 	ecc_err_p->ecc_dev_id = (ecc_err_p->ecc_afsr & PCMU_ECC_UE_AFSR_ID)
1922*25cf1a30Sjl 			>> PCMU_ECC_UE_AFSR_ID_SHIFT;
1923*25cf1a30Sjl 	/*
1924*25cf1a30Sjl 	 * Determine the doubleword offset of the error.
1925*25cf1a30Sjl 	 */
1926*25cf1a30Sjl 	ecc_err_p->ecc_dw_offset = (ecc_err_p->ecc_afsr &
1927*25cf1a30Sjl 	    PCMU_ECC_UE_AFSR_DW_OFFSET) >> PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT;
1928*25cf1a30Sjl 	/*
1929*25cf1a30Sjl 	 * Determine the primary error type.
1930*25cf1a30Sjl 	 */
1931*25cf1a30Sjl 	switch (err) {
1932*25cf1a30Sjl 	case PCMU_ECC_UE_AFSR_E_PIO:
1933*25cf1a30Sjl 		if (ecc_err_p->pecc_pri) {
1934*25cf1a30Sjl 			ecc->flt_erpt_class = PCI_ECC_PIO_UE;
1935*25cf1a30Sjl 		} else {
1936*25cf1a30Sjl 			ecc->flt_erpt_class = PCI_ECC_SEC_PIO_UE;
1937*25cf1a30Sjl 		}
1938*25cf1a30Sjl 		/* For CMU-CH, a UE is always fatal. */
1939*25cf1a30Sjl 		ecc->flt_panic = 1;
1940*25cf1a30Sjl 		break;
1941*25cf1a30Sjl 
1942*25cf1a30Sjl 	default:
1943*25cf1a30Sjl 		return;
1944*25cf1a30Sjl 	}
1945*25cf1a30Sjl }
1946*25cf1a30Sjl 
1947*25cf1a30Sjl /*
1948*25cf1a30Sjl  * pcmu_pbm_classify, called by pcmu_pbm_afsr_report to classify piow afsr.
1949*25cf1a30Sjl  */
1950*25cf1a30Sjl int
1951*25cf1a30Sjl pcmu_pbm_classify(pcmu_pbm_errstate_t *pbm_err_p)
1952*25cf1a30Sjl {
1953*25cf1a30Sjl 	uint32_t e;
1954*25cf1a30Sjl 	int nerr = 0;
1955*25cf1a30Sjl 	char **tmp_class;
1956*25cf1a30Sjl 
1957*25cf1a30Sjl 	if (pbm_err_p->pcbm_pri) {
1958*25cf1a30Sjl 		tmp_class = &pbm_err_p->pcbm_pci.pcmu_err_class;
1959*25cf1a30Sjl 		e = PBM_AFSR_TO_PRIERR(pbm_err_p->pbm_afsr);
1960*25cf1a30Sjl 		pbm_err_p->pbm_log = FM_LOG_PCI;
1961*25cf1a30Sjl 	} else {
1962*25cf1a30Sjl 		tmp_class = &pbm_err_p->pbm_err_class;
1963*25cf1a30Sjl 		e = PBM_AFSR_TO_SECERR(pbm_err_p->pbm_afsr);
1964*25cf1a30Sjl 		pbm_err_p->pbm_log = FM_LOG_PBM;
1965*25cf1a30Sjl 	}
1966*25cf1a30Sjl 
1967*25cf1a30Sjl 	if (e & PCMU_PCI_AFSR_E_MA) {
1968*25cf1a30Sjl 		*tmp_class = pbm_err_p->pcbm_pri ? PCI_MA : PCI_SEC_MA;
1969*25cf1a30Sjl 		nerr++;
1970*25cf1a30Sjl 	}
1971*25cf1a30Sjl 	return (nerr);
1972*25cf1a30Sjl }
1973*25cf1a30Sjl 
1974*25cf1a30Sjl /*
1975*25cf1a30Sjl  * Function used to clear PBM/PCI/IOMMU error state after error handling
1976*25cf1a30Sjl  * is complete. Only clearing error bits which have been logged. Called by
1977*25cf1a30Sjl  * pcmu_pbm_err_handler and pcmu_bus_exit.
1978*25cf1a30Sjl  */
1979*25cf1a30Sjl static void
1980*25cf1a30Sjl pcmu_clear_error(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p)
1981*25cf1a30Sjl {
1982*25cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
1983*25cf1a30Sjl 
1984*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcbm_p->pcbm_pcmu_p->pcmu_err_mutex));
1985*25cf1a30Sjl 
1986*25cf1a30Sjl 	*pcbm_p->pcbm_ctrl_reg = pbm_err_p->pbm_ctl_stat;
1987*25cf1a30Sjl 	*pcbm_p->pcbm_async_flt_status_reg = pbm_err_p->pbm_afsr;
1988*25cf1a30Sjl 	pcbm_p->pcbm_config_header->ch_status_reg =
1989*25cf1a30Sjl 		pbm_err_p->pcbm_pci.pcmu_cfg_stat;
1990*25cf1a30Sjl }
1991*25cf1a30Sjl 
1992*25cf1a30Sjl /*ARGSUSED*/
1993*25cf1a30Sjl int
1994*25cf1a30Sjl pcmu_pbm_err_handler(dev_info_t *dip, ddi_fm_error_t *derr,
1995*25cf1a30Sjl 		const void *impl_data, int caller)
1996*25cf1a30Sjl {
1997*25cf1a30Sjl 	int fatal = 0;
1998*25cf1a30Sjl 	int nonfatal = 0;
1999*25cf1a30Sjl 	int unknown = 0;
2000*25cf1a30Sjl 	uint32_t prierr, secerr;
2001*25cf1a30Sjl 	pcmu_pbm_errstate_t pbm_err;
2002*25cf1a30Sjl 	pcmu_t *pcmu_p = (pcmu_t *)impl_data;
2003*25cf1a30Sjl 	int ret = 0;
2004*25cf1a30Sjl 
2005*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
2006*25cf1a30Sjl 	pcmu_pbm_errstate_get(pcmu_p, &pbm_err);
2007*25cf1a30Sjl 
2008*25cf1a30Sjl 	derr->fme_ena = derr->fme_ena ? derr->fme_ena :
2009*25cf1a30Sjl 	    fm_ena_generate(0, FM_ENA_FMT1);
2010*25cf1a30Sjl 
2011*25cf1a30Sjl 	prierr = PBM_AFSR_TO_PRIERR(pbm_err.pbm_afsr);
2012*25cf1a30Sjl 	secerr = PBM_AFSR_TO_SECERR(pbm_err.pbm_afsr);
2013*25cf1a30Sjl 
2014*25cf1a30Sjl 	if (derr->fme_flag == DDI_FM_ERR_PEEK) {
2015*25cf1a30Sjl 		/*
2016*25cf1a30Sjl 		 * For ddi_peek treat all events as nonfatal. We only
2017*25cf1a30Sjl 		 * really call this function so that pcmu_clear_error()
2018*25cf1a30Sjl 		 * and ndi_fm_handler_dispatch() will get called.
2019*25cf1a30Sjl 		 */
2020*25cf1a30Sjl 		nonfatal++;
2021*25cf1a30Sjl 		goto done;
2022*25cf1a30Sjl 	} else if (derr->fme_flag == DDI_FM_ERR_POKE) {
2023*25cf1a30Sjl 		/*
2024*25cf1a30Sjl 		 * For ddi_poke we can treat as nonfatal if the
2025*25cf1a30Sjl 		 * following conditions are met :
2026*25cf1a30Sjl 		 * 1. Make sure only primary error is MA/TA
2027*25cf1a30Sjl 		 * 2. Make sure no secondary error
2028*25cf1a30Sjl 		 * 3. check pci config header stat reg to see MA/TA is
2029*25cf1a30Sjl 		 *    logged. We cannot verify only MA/TA is recorded
2030*25cf1a30Sjl 		 *    since it gets much more complicated when a
2031*25cf1a30Sjl 		 *    PCI-to-PCI bridge is present.
2032*25cf1a30Sjl 		 */
2033*25cf1a30Sjl 		if ((prierr == PCMU_PCI_AFSR_E_MA) && !secerr &&
2034*25cf1a30Sjl 		    (pbm_err.pcbm_pci.pcmu_cfg_stat & PCI_STAT_R_MAST_AB)) {
2035*25cf1a30Sjl 			nonfatal++;
2036*25cf1a30Sjl 			goto done;
2037*25cf1a30Sjl 		}
2038*25cf1a30Sjl 	}
2039*25cf1a30Sjl 
2040*25cf1a30Sjl 	if (prierr || secerr) {
2041*25cf1a30Sjl 		ret = pcmu_pbm_afsr_report(dip, derr->fme_ena, &pbm_err);
2042*25cf1a30Sjl 		if (ret == DDI_FM_FATAL) {
2043*25cf1a30Sjl 			fatal++;
2044*25cf1a30Sjl 		} else {
2045*25cf1a30Sjl 			nonfatal++;
2046*25cf1a30Sjl 		}
2047*25cf1a30Sjl 	}
2048*25cf1a30Sjl 
2049*25cf1a30Sjl 	ret = pcmu_cfg_report(dip, derr, &pbm_err.pcbm_pci, caller, prierr);
2050*25cf1a30Sjl 	if (ret == DDI_FM_FATAL) {
2051*25cf1a30Sjl 		fatal++;
2052*25cf1a30Sjl 	} else if (ret == DDI_FM_NONFATAL) {
2053*25cf1a30Sjl 		nonfatal++;
2054*25cf1a30Sjl 	}
2055*25cf1a30Sjl 
2056*25cf1a30Sjl done:
2057*25cf1a30Sjl 	if (ret == DDI_FM_FATAL) {
2058*25cf1a30Sjl 		fatal++;
2059*25cf1a30Sjl 	} else if (ret == DDI_FM_NONFATAL) {
2060*25cf1a30Sjl 		nonfatal++;
2061*25cf1a30Sjl 	} else if (ret == DDI_FM_UNKNOWN) {
2062*25cf1a30Sjl 		unknown++;
2063*25cf1a30Sjl 	}
2064*25cf1a30Sjl 
2065*25cf1a30Sjl 	/* Cleanup and reset error bits */
2066*25cf1a30Sjl 	pcmu_clear_error(pcmu_p, &pbm_err);
2067*25cf1a30Sjl 
2068*25cf1a30Sjl 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
2069*25cf1a30Sjl 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
2070*25cf1a30Sjl }
2071*25cf1a30Sjl 
2072*25cf1a30Sjl int
2073*25cf1a30Sjl pcmu_check_error(pcmu_t *pcmu_p)
2074*25cf1a30Sjl {
2075*25cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
2076*25cf1a30Sjl 	uint16_t pcmu_cfg_stat;
2077*25cf1a30Sjl 	uint64_t pbm_afsr;
2078*25cf1a30Sjl 
2079*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
2080*25cf1a30Sjl 
2081*25cf1a30Sjl 	pcmu_cfg_stat = pcbm_p->pcbm_config_header->ch_status_reg;
2082*25cf1a30Sjl 	pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
2083*25cf1a30Sjl 
2084*25cf1a30Sjl 	if ((pcmu_cfg_stat & (PCI_STAT_S_PERROR | PCI_STAT_S_TARG_AB |
2085*25cf1a30Sjl 				PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB |
2086*25cf1a30Sjl 				PCI_STAT_S_SYSERR | PCI_STAT_PERROR)) ||
2087*25cf1a30Sjl 			(PBM_AFSR_TO_PRIERR(pbm_afsr))) {
2088*25cf1a30Sjl 		return (1);
2089*25cf1a30Sjl 	}
2090*25cf1a30Sjl 	return (0);
2091*25cf1a30Sjl 
2092*25cf1a30Sjl }
2093*25cf1a30Sjl 
2094*25cf1a30Sjl /*
2095*25cf1a30Sjl  * Function used to gather PBM/PCI error state for the
2096*25cf1a30Sjl  * pcmu_pbm_err_handler. This function must be called while pcmu_err_mutex
2097*25cf1a30Sjl  * is held.
2098*25cf1a30Sjl  */
2099*25cf1a30Sjl static void
2100*25cf1a30Sjl pcmu_pbm_errstate_get(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p)
2101*25cf1a30Sjl {
2102*25cf1a30Sjl 	pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
2103*25cf1a30Sjl 
2104*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
2105*25cf1a30Sjl 	bzero(pbm_err_p, sizeof (pcmu_pbm_errstate_t));
2106*25cf1a30Sjl 
2107*25cf1a30Sjl 	/*
2108*25cf1a30Sjl 	 * Capture all pbm error state for later logging
2109*25cf1a30Sjl 	 */
2110*25cf1a30Sjl 	pbm_err_p->pbm_bridge_type = PCI_OPLCMU;	/* RAGS */
2111*25cf1a30Sjl 	pbm_err_p->pcbm_pci.pcmu_cfg_stat =
2112*25cf1a30Sjl 	    pcbm_p->pcbm_config_header->ch_status_reg;
2113*25cf1a30Sjl 	pbm_err_p->pbm_ctl_stat = *pcbm_p->pcbm_ctrl_reg;
2114*25cf1a30Sjl 	pbm_err_p->pcbm_pci.pcmu_cfg_comm =
2115*25cf1a30Sjl 	    pcbm_p->pcbm_config_header->ch_command_reg;
2116*25cf1a30Sjl 	pbm_err_p->pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
2117*25cf1a30Sjl 	pbm_err_p->pbm_afar = *pcbm_p->pcbm_async_flt_addr_reg;
2118*25cf1a30Sjl 	pbm_err_p->pcbm_pci.pcmu_pa = *pcbm_p->pcbm_async_flt_addr_reg;
2119*25cf1a30Sjl }
2120*25cf1a30Sjl 
2121*25cf1a30Sjl static void
2122*25cf1a30Sjl pcmu_pbm_clear_error(pcmu_pbm_t *pcbm_p)
2123*25cf1a30Sjl {
2124*25cf1a30Sjl 	uint64_t pbm_afsr;
2125*25cf1a30Sjl 
2126*25cf1a30Sjl 	/*
2127*25cf1a30Sjl 	 * for poke() support - called from POKE_FLUSH. Spin waiting
2128*25cf1a30Sjl 	 * for MA, TA or SERR to be cleared by a pcmu_pbm_error_intr().
2129*25cf1a30Sjl 	 * We have to wait for SERR too in case the device is beyond
2130*25cf1a30Sjl 	 * a pci-pci bridge.
2131*25cf1a30Sjl 	 */
2132*25cf1a30Sjl 	pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
2133*25cf1a30Sjl 	while (((pbm_afsr >> PCMU_PCI_AFSR_PE_SHIFT) &
2134*25cf1a30Sjl 	    (PCMU_PCI_AFSR_E_MA | PCMU_PCI_AFSR_E_TA))) {
2135*25cf1a30Sjl 		pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg;
2136*25cf1a30Sjl 	}
2137*25cf1a30Sjl }
2138*25cf1a30Sjl 
2139*25cf1a30Sjl void
2140*25cf1a30Sjl pcmu_err_create(pcmu_t *pcmu_p)
2141*25cf1a30Sjl {
2142*25cf1a30Sjl 	/*
2143*25cf1a30Sjl 	 * PCI detected ECC errorq, to schedule async handling
2144*25cf1a30Sjl 	 * of ECC errors and logging.
2145*25cf1a30Sjl 	 * The errorq is created here but destroyed when _fini is called
2146*25cf1a30Sjl 	 * for the pci module.
2147*25cf1a30Sjl 	 */
2148*25cf1a30Sjl 	if (pcmu_ecc_queue == NULL) {
2149*25cf1a30Sjl 		pcmu_ecc_queue = errorq_create("pcmu_ecc_queue",
2150*25cf1a30Sjl 				(errorq_func_t)pcmu_ecc_err_drain,
2151*25cf1a30Sjl 				(void *)NULL,
2152*25cf1a30Sjl 				ECC_MAX_ERRS, sizeof (pcmu_ecc_errstate_t),
2153*25cf1a30Sjl 				PIL_2, ERRORQ_VITAL);
2154*25cf1a30Sjl 		if (pcmu_ecc_queue == NULL)
2155*25cf1a30Sjl 			panic("failed to create required system error queue");
2156*25cf1a30Sjl 	}
2157*25cf1a30Sjl 
2158*25cf1a30Sjl 	/*
2159*25cf1a30Sjl 	 * Initialize error handling mutex.
2160*25cf1a30Sjl 	 */
2161*25cf1a30Sjl 	mutex_init(&pcmu_p->pcmu_err_mutex, NULL, MUTEX_DRIVER,
2162*25cf1a30Sjl 			(void *)pcmu_p->pcmu_fm_ibc);
2163*25cf1a30Sjl }
2164*25cf1a30Sjl 
2165*25cf1a30Sjl void
2166*25cf1a30Sjl pcmu_err_destroy(pcmu_t *pcmu_p)
2167*25cf1a30Sjl {
2168*25cf1a30Sjl 	mutex_destroy(&pcmu_p->pcmu_err_mutex);
2169*25cf1a30Sjl }
2170*25cf1a30Sjl 
2171*25cf1a30Sjl /*
2172*25cf1a30Sjl  * Function used to post PCI block module specific ereports.
2173*25cf1a30Sjl  */
2174*25cf1a30Sjl void
2175*25cf1a30Sjl pcmu_pbm_ereport_post(dev_info_t *dip, uint64_t ena,
2176*25cf1a30Sjl     pcmu_pbm_errstate_t *pbm_err)
2177*25cf1a30Sjl {
2178*25cf1a30Sjl 	char *aux_msg;
2179*25cf1a30Sjl 	uint32_t prierr, secerr;
2180*25cf1a30Sjl 	pcmu_t *pcmu_p;
2181*25cf1a30Sjl 	int instance = ddi_get_instance(dip);
2182*25cf1a30Sjl 
2183*25cf1a30Sjl 	ena = ena ? ena : fm_ena_generate(0, FM_ENA_FMT1);
2184*25cf1a30Sjl 
2185*25cf1a30Sjl 	pcmu_p = get_pcmu_soft_state(instance);
2186*25cf1a30Sjl 	prierr = PBM_AFSR_TO_PRIERR(pbm_err->pbm_afsr);
2187*25cf1a30Sjl 	secerr = PBM_AFSR_TO_SECERR(pbm_err->pbm_afsr);
2188*25cf1a30Sjl 	if (prierr)
2189*25cf1a30Sjl 		aux_msg = "PCI primary error: Master Abort";
2190*25cf1a30Sjl 	else if (secerr)
2191*25cf1a30Sjl 		aux_msg = "PCI secondary error: Master Abort";
2192*25cf1a30Sjl 	else
2193*25cf1a30Sjl 		aux_msg = "";
2194*25cf1a30Sjl 	cmn_err(CE_WARN, "%s %s: %s %s=0x%lx, %s=0x%lx, %s=0x%lx %s=0x%x",
2195*25cf1a30Sjl 		(pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str,
2196*25cf1a30Sjl 		(pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str,
2197*25cf1a30Sjl 		aux_msg,
2198*25cf1a30Sjl 		PCI_PBM_AFAR, pbm_err->pbm_afar,
2199*25cf1a30Sjl 		PCI_PBM_AFSR, pbm_err->pbm_afsr,
2200*25cf1a30Sjl 		PCI_PBM_CSR, pbm_err->pbm_ctl_stat,
2201*25cf1a30Sjl 		"portid", pcmu_p->pcmu_id);
2202*25cf1a30Sjl }
2203