xref: /onnv-gate/usr/src/uts/sun4/io/px/px_ib.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PX Interrupt Block implementation
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/kmem.h>
35*0Sstevel@tonic-gate #include <sys/async.h>
36*0Sstevel@tonic-gate #include <sys/systm.h>		/* panicstr */
37*0Sstevel@tonic-gate #include <sys/spl.h>
38*0Sstevel@tonic-gate #include <sys/sunddi.h>
39*0Sstevel@tonic-gate #include <sys/machsystm.h>	/* intr_dist_add */
40*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
41*0Sstevel@tonic-gate #include <sys/cpuvar.h>
42*0Sstevel@tonic-gate #include "px_obj.h"
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate /*LINTLIBRARY*/
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate static void px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight);
47*0Sstevel@tonic-gate static void px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino,
48*0Sstevel@tonic-gate     boolean_t wait_flag);
49*0Sstevel@tonic-gate static uint_t px_ib_intr_reset(void *arg);
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate int
52*0Sstevel@tonic-gate px_ib_attach(px_t *px_p)
53*0Sstevel@tonic-gate {
54*0Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
55*0Sstevel@tonic-gate 	px_ib_t		*ib_p;
56*0Sstevel@tonic-gate 	sysino_t	sysino;
57*0Sstevel@tonic-gate 	px_fault_t	*fault_p = &px_p->px_fault;
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate 	DBG(DBG_IB, dip, "px_ib_attach\n");
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	if (px_lib_intr_devino_to_sysino(px_p->px_dip,
62*0Sstevel@tonic-gate 	    px_p->px_inos[PX_FAULT_PEC], &sysino) != DDI_SUCCESS)
63*0Sstevel@tonic-gate 		return (DDI_FAILURE);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 	/*
66*0Sstevel@tonic-gate 	 * Allocate interrupt block state structure and link it to
67*0Sstevel@tonic-gate 	 * the px state structure.
68*0Sstevel@tonic-gate 	 */
69*0Sstevel@tonic-gate 	ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP);
70*0Sstevel@tonic-gate 	px_p->px_ib_p = ib_p;
71*0Sstevel@tonic-gate 	ib_p->ib_px_p = px_p;
72*0Sstevel@tonic-gate 	ib_p->ib_ino_lst = (px_ib_ino_info_t *)NULL;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL);
75*0Sstevel@tonic-gate 	mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL);
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	intr_dist_add_weighted(px_ib_intr_redist, ib_p);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	/*
82*0Sstevel@tonic-gate 	 * Initialize PEC fault data structure
83*0Sstevel@tonic-gate 	 */
84*0Sstevel@tonic-gate 	fault_p->px_fh_dip = dip;
85*0Sstevel@tonic-gate 	fault_p->px_fh_sysino = sysino;
86*0Sstevel@tonic-gate 	fault_p->px_fh_lst = NULL;
87*0Sstevel@tonic-gate 	mutex_init(&fault_p->px_fh_lock, NULL, MUTEX_DRIVER, NULL);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	/* Register IMU error */
90*0Sstevel@tonic-gate 	px_err_add_fh(fault_p, PX_ERR_IMU,
91*0Sstevel@tonic-gate 	    (caddr_t)px_p->px_address[PX_REG_CSR]);
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
94*0Sstevel@tonic-gate }
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate void
97*0Sstevel@tonic-gate px_ib_detach(px_t *px_p)
98*0Sstevel@tonic-gate {
99*0Sstevel@tonic-gate 	px_ib_t		*ib_p = px_p->px_ib_p;
100*0Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	DBG(DBG_IB, dip, "px_ib_detach\n");
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	px_err_rem(&px_p->px_fault, PX_FAULT_PEC);
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p);
107*0Sstevel@tonic-gate 	intr_dist_rem_weighted(px_ib_intr_redist, ib_p);
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	mutex_destroy(&ib_p->ib_ino_lst_mutex);
110*0Sstevel@tonic-gate 	mutex_destroy(&ib_p->ib_intr_lock);
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	px_ib_free_ino_all(ib_p);
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	px_p->px_ib_p = NULL;
115*0Sstevel@tonic-gate 	kmem_free(ib_p, sizeof (px_ib_t));
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate static struct {
119*0Sstevel@tonic-gate 	kstat_named_t ihks_name;
120*0Sstevel@tonic-gate 	kstat_named_t ihks_type;
121*0Sstevel@tonic-gate 	kstat_named_t ihks_cpu;
122*0Sstevel@tonic-gate 	kstat_named_t ihks_pil;
123*0Sstevel@tonic-gate 	kstat_named_t ihks_time;
124*0Sstevel@tonic-gate 	kstat_named_t ihks_ino;
125*0Sstevel@tonic-gate 	kstat_named_t ihks_cookie;
126*0Sstevel@tonic-gate 	kstat_named_t ihks_devpath;
127*0Sstevel@tonic-gate 	kstat_named_t ihks_buspath;
128*0Sstevel@tonic-gate } px_ih_ks_template = {
129*0Sstevel@tonic-gate 	{ "name",	KSTAT_DATA_CHAR },
130*0Sstevel@tonic-gate 	{ "type",	KSTAT_DATA_CHAR },
131*0Sstevel@tonic-gate 	{ "cpu",	KSTAT_DATA_UINT64 },
132*0Sstevel@tonic-gate 	{ "pil",	KSTAT_DATA_UINT64 },
133*0Sstevel@tonic-gate 	{ "time",	KSTAT_DATA_UINT64 },
134*0Sstevel@tonic-gate 	{ "ino",	KSTAT_DATA_UINT64 },
135*0Sstevel@tonic-gate 	{ "cookie",	KSTAT_DATA_UINT64 },
136*0Sstevel@tonic-gate 	{ "devpath",	KSTAT_DATA_STRING },
137*0Sstevel@tonic-gate 	{ "buspath",	KSTAT_DATA_STRING },
138*0Sstevel@tonic-gate };
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate static uint32_t ih_instance;
141*0Sstevel@tonic-gate static kmutex_t ih_ks_template_lock;
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate int
144*0Sstevel@tonic-gate ih_ks_update(kstat_t *ksp, int rw)
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate 	px_ih_t *ih_p = ksp->ks_private;
147*0Sstevel@tonic-gate 	int maxlen = sizeof (px_ih_ks_template.ihks_name.value.c);
148*0Sstevel@tonic-gate 	px_ib_t *ib_p = ih_p->ih_ino_p->ino_ib_p;
149*0Sstevel@tonic-gate 	px_t *px_p = ib_p->ib_px_p;
150*0Sstevel@tonic-gate 	devino_t ino;
151*0Sstevel@tonic-gate 	sysino_t sysino;
152*0Sstevel@tonic-gate 	char ih_devpath[MAXPATHLEN];
153*0Sstevel@tonic-gate 	char ih_buspath[MAXPATHLEN];
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	ino = ih_p->ih_ino_p->ino_ino;
156*0Sstevel@tonic-gate 	(void) px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino);
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	(void) snprintf(px_ih_ks_template.ihks_name.value.c, maxlen, "%s%d",
159*0Sstevel@tonic-gate 	    ddi_driver_name(ih_p->ih_dip),
160*0Sstevel@tonic-gate 	    ddi_get_instance(ih_p->ih_dip));
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	(void) strcpy(px_ih_ks_template.ihks_type.value.c,
163*0Sstevel@tonic-gate 	    (ih_p->ih_rec_type == 0) ? "fixed" : "msi");
164*0Sstevel@tonic-gate 	px_ih_ks_template.ihks_cpu.value.ui64 = ih_p->ih_ino_p->ino_cpuid;
165*0Sstevel@tonic-gate 	px_ih_ks_template.ihks_pil.value.ui64 = ih_p->ih_ino_p->ino_pil;
166*0Sstevel@tonic-gate 	px_ih_ks_template.ihks_time.value.ui64 = ih_p->ih_nsec + (uint64_t)
167*0Sstevel@tonic-gate 	    tick2ns((hrtime_t)ih_p->ih_ticks, ih_p->ih_ino_p->ino_cpuid);
168*0Sstevel@tonic-gate 	px_ih_ks_template.ihks_ino.value.ui64 = ino;
169*0Sstevel@tonic-gate 	px_ih_ks_template.ihks_cookie.value.ui64 = sysino;
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	(void) ddi_pathname(ih_p->ih_dip, ih_devpath);
172*0Sstevel@tonic-gate 	(void) ddi_pathname(px_p->px_dip, ih_buspath);
173*0Sstevel@tonic-gate 	kstat_named_setstr(&px_ih_ks_template.ihks_devpath, ih_devpath);
174*0Sstevel@tonic-gate 	kstat_named_setstr(&px_ih_ks_template.ihks_buspath, ih_buspath);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	return (0);
177*0Sstevel@tonic-gate }
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate void
180*0Sstevel@tonic-gate px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate 	px_ib_t		*ib_p = px_p->px_ib_p;
183*0Sstevel@tonic-gate 	sysino_t	sysino;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	/*
186*0Sstevel@tonic-gate 	 * Determine the cpu for the interrupt
187*0Sstevel@tonic-gate 	 */
188*0Sstevel@tonic-gate 	mutex_enter(&ib_p->ib_intr_lock);
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	DBG(DBG_IB, px_p->px_dip,
191*0Sstevel@tonic-gate 	    "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino,
194*0Sstevel@tonic-gate 	    &sysino) != DDI_SUCCESS) {
195*0Sstevel@tonic-gate 		DBG(DBG_IB, px_p->px_dip,
196*0Sstevel@tonic-gate 		    "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n");
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 		mutex_exit(&ib_p->ib_intr_lock);
199*0Sstevel@tonic-gate 		return;
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id);
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	mutex_exit(&ib_p->ib_intr_lock);
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate /*ARGSUSED*/
208*0Sstevel@tonic-gate void
209*0Sstevel@tonic-gate px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait)
210*0Sstevel@tonic-gate {
211*0Sstevel@tonic-gate 	sysino_t	sysino;
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	mutex_enter(&ib_p->ib_intr_lock);
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino);
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	/* Disable the interrupt */
218*0Sstevel@tonic-gate 	if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino,
219*0Sstevel@tonic-gate 	    &sysino) != DDI_SUCCESS) {
220*0Sstevel@tonic-gate 		DBG(DBG_IB, ib_p->ib_px_p->px_dip,
221*0Sstevel@tonic-gate 		    "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n");
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 		mutex_exit(&ib_p->ib_intr_lock);
224*0Sstevel@tonic-gate 		return;
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino);
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	mutex_exit(&ib_p->ib_intr_lock);
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate static void
234*0Sstevel@tonic-gate px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino,
235*0Sstevel@tonic-gate     boolean_t wait_flag)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	uint32_t	old_cpu_id;
238*0Sstevel@tonic-gate 	sysino_t	sysino;
239*0Sstevel@tonic-gate 	intr_valid_state_t	enabled = 0;
240*0Sstevel@tonic-gate 	hrtime_t	start_time;
241*0Sstevel@tonic-gate 	intr_state_t	intr_state;
242*0Sstevel@tonic-gate 	int		e;
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino);
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) {
247*0Sstevel@tonic-gate 		DBG(DBG_IB, dip, "px_ib_intr_dist_en: "
248*0Sstevel@tonic-gate 		    "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino);
249*0Sstevel@tonic-gate 		return;
250*0Sstevel@tonic-gate 	}
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	/* Skip enabling disabled interrupts */
253*0Sstevel@tonic-gate 	if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) {
254*0Sstevel@tonic-gate 		DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() "
255*0Sstevel@tonic-gate 		    "failed, sysino 0x%x\n", sysino);
256*0Sstevel@tonic-gate 		return;
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 	if (!enabled)
259*0Sstevel@tonic-gate 		return;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/* Done if redistributed onto the same cpuid */
262*0Sstevel@tonic-gate 	if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) {
263*0Sstevel@tonic-gate 		DBG(DBG_IB, dip, "px_ib_intr_dist_en: "
264*0Sstevel@tonic-gate 		    "px_intr_gettarget() failed\n");
265*0Sstevel@tonic-gate 		return;
266*0Sstevel@tonic-gate 	}
267*0Sstevel@tonic-gate 	if (cpu_id == old_cpu_id)
268*0Sstevel@tonic-gate 		return;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	if (!wait_flag)
271*0Sstevel@tonic-gate 		goto done;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	/* Busy wait on pending interrupts */
274*0Sstevel@tonic-gate 	PX_INTR_DISABLE(dip, sysino);
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	for (start_time = gethrtime(); !panicstr &&
277*0Sstevel@tonic-gate 	    ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) ==
278*0Sstevel@tonic-gate 		DDI_SUCCESS) &&
279*0Sstevel@tonic-gate 	    (intr_state == INTR_DELIVERED_STATE); /* */) {
280*0Sstevel@tonic-gate 		if (gethrtime() - start_time > px_intrpend_timeout) {
281*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
282*0Sstevel@tonic-gate 			    "%s%d: px_ib_intr_dist_en: sysino 0x%x(ino 0x%x) "
283*0Sstevel@tonic-gate 			    "from cpu id 0x%x to 0x%x timeout",
284*0Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
285*0Sstevel@tonic-gate 			    sysino, ino, old_cpu_id, cpu_id);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 			e = DDI_FAILURE;
288*0Sstevel@tonic-gate 			break;
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 	}
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	if (e != DDI_SUCCESS)
293*0Sstevel@tonic-gate 		DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, "
294*0Sstevel@tonic-gate 		    "ino 0x%x sysino 0x%x\n", ino, sysino);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate done:
297*0Sstevel@tonic-gate 	PX_INTR_ENABLE(dip, sysino, cpu_id);
298*0Sstevel@tonic-gate }
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate /*
302*0Sstevel@tonic-gate  * Redistribute interrupts of the specified weight. The first call has a weight
303*0Sstevel@tonic-gate  * of weight_max, which can be used to trigger initialization for
304*0Sstevel@tonic-gate  * redistribution. The inos with weight [weight_max, inf.) should be processed
305*0Sstevel@tonic-gate  * on the "weight == weight_max" call.  This first call is followed by calls
306*0Sstevel@tonic-gate  * of decreasing weights, inos of that weight should be processed.  The final
307*0Sstevel@tonic-gate  * call specifies a weight of zero, this can be used to trigger processing of
308*0Sstevel@tonic-gate  * stragglers.
309*0Sstevel@tonic-gate  */
310*0Sstevel@tonic-gate static void
311*0Sstevel@tonic-gate px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight)
312*0Sstevel@tonic-gate {
313*0Sstevel@tonic-gate 	px_ib_t		*ib_p = (px_ib_t *)arg;
314*0Sstevel@tonic-gate 	px_t		*px_p = ib_p->ib_px_p;
315*0Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
316*0Sstevel@tonic-gate 	px_ib_ino_info_t *ino_p;
317*0Sstevel@tonic-gate 	px_ih_t		*ih_lst;
318*0Sstevel@tonic-gate 	int32_t		dweight = 0;
319*0Sstevel@tonic-gate 	int		i;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	/* Redistribute internal interrupts */
322*0Sstevel@tonic-gate 	if (weight == 0) {
323*0Sstevel@tonic-gate 		devino_t	ino_pec = px_p->px_inos[PX_INTR_PEC];
324*0Sstevel@tonic-gate 		mutex_enter(&ib_p->ib_intr_lock);
325*0Sstevel@tonic-gate 		px_ib_intr_dist_en(dip, intr_dist_cpuid(), ino_pec, B_FALSE);
326*0Sstevel@tonic-gate 		mutex_exit(&ib_p->ib_intr_lock);
327*0Sstevel@tonic-gate 	}
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	/* Redistribute device interrupts */
330*0Sstevel@tonic-gate 	mutex_enter(&ib_p->ib_ino_lst_mutex);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next) {
333*0Sstevel@tonic-gate 		uint32_t orig_cpuid;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 		/*
336*0Sstevel@tonic-gate 		 * Recomputes the sum of interrupt weights of devices that
337*0Sstevel@tonic-gate 		 * share the same ino upon first call marked by
338*0Sstevel@tonic-gate 		 * (weight == weight_max).
339*0Sstevel@tonic-gate 		 */
340*0Sstevel@tonic-gate 		if (weight == weight_max) {
341*0Sstevel@tonic-gate 			ino_p->ino_intr_weight = 0;
342*0Sstevel@tonic-gate 			for (i = 0, ih_lst = ino_p->ino_ih_head;
343*0Sstevel@tonic-gate 			    i < ino_p->ino_ih_size;
344*0Sstevel@tonic-gate 			    i++, ih_lst = ih_lst->ih_next) {
345*0Sstevel@tonic-gate 				dweight = i_ddi_get_intr_weight(ih_lst->ih_dip);
346*0Sstevel@tonic-gate 				if (dweight > 0)
347*0Sstevel@tonic-gate 					ino_p->ino_intr_weight += dweight;
348*0Sstevel@tonic-gate 			}
349*0Sstevel@tonic-gate 		}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 		/*
352*0Sstevel@tonic-gate 		 * As part of redistributing weighted interrupts over cpus,
353*0Sstevel@tonic-gate 		 * nexus redistributes device interrupts and updates
354*0Sstevel@tonic-gate 		 * cpu weight. The purpose is for the most light weighted
355*0Sstevel@tonic-gate 		 * cpu to take the next interrupt and gain weight, therefore
356*0Sstevel@tonic-gate 		 * attention demanding device gains more cpu attention by
357*0Sstevel@tonic-gate 		 * making itself heavy.
358*0Sstevel@tonic-gate 		 */
359*0Sstevel@tonic-gate 		if ((weight == ino_p->ino_intr_weight) ||
360*0Sstevel@tonic-gate 		    ((weight >= weight_max) &&
361*0Sstevel@tonic-gate 		    (ino_p->ino_intr_weight >= weight_max))) {
362*0Sstevel@tonic-gate 			orig_cpuid = ino_p->ino_cpuid;
363*0Sstevel@tonic-gate 			if (cpu[orig_cpuid] == NULL)
364*0Sstevel@tonic-gate 				orig_cpuid = CPU->cpu_id;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 			/* select cpuid to target and mark ino established */
367*0Sstevel@tonic-gate 			ino_p->ino_cpuid = intr_dist_cpuid();
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 			/* Add device weight to targeted cpu. */
370*0Sstevel@tonic-gate 			for (i = 0, ih_lst = ino_p->ino_ih_head;
371*0Sstevel@tonic-gate 			    i < ino_p->ino_ih_size;
372*0Sstevel@tonic-gate 			    i++, ih_lst = ih_lst->ih_next) {
373*0Sstevel@tonic-gate 				hrtime_t ticks;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 				dweight = i_ddi_get_intr_weight(ih_lst->ih_dip);
376*0Sstevel@tonic-gate 				intr_dist_cpuid_add_device_weight(
377*0Sstevel@tonic-gate 				    ino_p->ino_cpuid, ih_lst->ih_dip, dweight);
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 				/*
380*0Sstevel@tonic-gate 				 * different cpus may have different clock
381*0Sstevel@tonic-gate 				 * speeds. to account for this, whenever an
382*0Sstevel@tonic-gate 				 * interrupt is moved to a new CPU, we
383*0Sstevel@tonic-gate 				 * convert the accumulated ticks into nsec,
384*0Sstevel@tonic-gate 				 * based upon the clock rate of the prior
385*0Sstevel@tonic-gate 				 * CPU.
386*0Sstevel@tonic-gate 				 *
387*0Sstevel@tonic-gate 				 * It is possible that the prior CPU no longer
388*0Sstevel@tonic-gate 				 * exists. In this case, fall back to using
389*0Sstevel@tonic-gate 				 * this CPU's clock rate.
390*0Sstevel@tonic-gate 				 *
391*0Sstevel@tonic-gate 				 * Note that the value in ih_ticks has already
392*0Sstevel@tonic-gate 				 * been corrected for any power savings mode
393*0Sstevel@tonic-gate 				 * which might have been in effect.
394*0Sstevel@tonic-gate 				 *
395*0Sstevel@tonic-gate 				 * because we are updating two fields in
396*0Sstevel@tonic-gate 				 * ih_t we must lock ih_ks_template_lock to
397*0Sstevel@tonic-gate 				 * prevent someone from reading the kstats
398*0Sstevel@tonic-gate 				 * after we set ih_ticks to 0 and before we
399*0Sstevel@tonic-gate 				 * increment ih_nsec to compensate.
400*0Sstevel@tonic-gate 				 *
401*0Sstevel@tonic-gate 				 * we must also protect against the interrupt
402*0Sstevel@tonic-gate 				 * arriving and incrementing ih_ticks between
403*0Sstevel@tonic-gate 				 * the time we read it and when we reset it
404*0Sstevel@tonic-gate 				 * to 0. To do this we use atomic_swap.
405*0Sstevel@tonic-gate 				 */
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 				mutex_enter(&ih_ks_template_lock);
408*0Sstevel@tonic-gate 				ticks = atomic_swap_64(&ih_lst->ih_ticks, 0);
409*0Sstevel@tonic-gate 				ih_lst->ih_nsec += (uint64_t)
410*0Sstevel@tonic-gate 				    tick2ns(ticks, orig_cpuid);
411*0Sstevel@tonic-gate 				mutex_exit(&ih_ks_template_lock);
412*0Sstevel@tonic-gate 			}
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 			/* enable interrupt on new targeted cpu */
415*0Sstevel@tonic-gate 			px_ib_intr_dist_en(dip, ino_p->ino_cpuid,
416*0Sstevel@tonic-gate 			    ino_p->ino_ino, B_TRUE);
417*0Sstevel@tonic-gate 		}
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 	mutex_exit(&ib_p->ib_ino_lst_mutex);
420*0Sstevel@tonic-gate }
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate /*
423*0Sstevel@tonic-gate  * Reset interrupts to IDLE.  This function is called during
424*0Sstevel@tonic-gate  * panic handling after redistributing interrupts; it's needed to
425*0Sstevel@tonic-gate  * support dumping to network devices after 'sync' from OBP.
426*0Sstevel@tonic-gate  *
427*0Sstevel@tonic-gate  * N.B.  This routine runs in a context where all other threads
428*0Sstevel@tonic-gate  * are permanently suspended.
429*0Sstevel@tonic-gate  */
430*0Sstevel@tonic-gate static uint_t
431*0Sstevel@tonic-gate px_ib_intr_reset(void *arg)
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate 	px_ib_t		*ib_p = (px_ib_t *)arg;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n");
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS)
438*0Sstevel@tonic-gate 		return (BF_FATAL);
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	return (BF_NONE);
441*0Sstevel@tonic-gate }
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate /*
444*0Sstevel@tonic-gate  * Locate ino_info structure on ib_p->ib_ino_lst according to ino#
445*0Sstevel@tonic-gate  * returns NULL if not found.
446*0Sstevel@tonic-gate  */
447*0Sstevel@tonic-gate px_ib_ino_info_t *
448*0Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num)
449*0Sstevel@tonic-gate {
450*0Sstevel@tonic-gate 	px_ib_ino_info_t	*ino_p = ib_p->ib_ino_lst;
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next);
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	return (ino_p);
457*0Sstevel@tonic-gate }
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate px_ib_ino_info_t *
460*0Sstevel@tonic-gate px_ib_new_ino(px_ib_t *ib_p, devino_t ino_num, px_ih_t *ih_p)
461*0Sstevel@tonic-gate {
462*0Sstevel@tonic-gate 	px_ib_ino_info_t	*ino_p = kmem_alloc(sizeof (px_ib_ino_info_t),
463*0Sstevel@tonic-gate 	    KM_SLEEP);
464*0Sstevel@tonic-gate 	sysino_t	sysino;
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	ino_p->ino_ino = ino_num;
467*0Sstevel@tonic-gate 	ino_p->ino_ib_p = ib_p;
468*0Sstevel@tonic-gate 	ino_p->ino_unclaimed = 0;
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino_p->ino_ino,
471*0Sstevel@tonic-gate 	    &sysino) != DDI_SUCCESS)
472*0Sstevel@tonic-gate 		return (NULL);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	ino_p->ino_sysino = sysino;
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	/*
477*0Sstevel@tonic-gate 	 * Cannot disable interrupt since we might share slot
478*0Sstevel@tonic-gate 	 */
479*0Sstevel@tonic-gate 	ih_p->ih_next = ih_p;
480*0Sstevel@tonic-gate 	ino_p->ino_ih_head = ih_p;
481*0Sstevel@tonic-gate 	ino_p->ino_ih_tail = ih_p;
482*0Sstevel@tonic-gate 	ino_p->ino_ih_start = ih_p;
483*0Sstevel@tonic-gate 	ino_p->ino_ih_size = 1;
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	ino_p->ino_next = ib_p->ib_ino_lst;
486*0Sstevel@tonic-gate 	ib_p->ib_ino_lst = ino_p;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	return (ino_p);
489*0Sstevel@tonic-gate }
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate /*
492*0Sstevel@tonic-gate  * The ino_p is retrieved by previous call to px_ib_locate_ino().
493*0Sstevel@tonic-gate  */
494*0Sstevel@tonic-gate void
495*0Sstevel@tonic-gate px_ib_delete_ino(px_ib_t *ib_p, px_ib_ino_info_t *ino_p)
496*0Sstevel@tonic-gate {
497*0Sstevel@tonic-gate 	px_ib_ino_info_t	*list = ib_p->ib_ino_lst;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	if (list == ino_p)
502*0Sstevel@tonic-gate 		ib_p->ib_ino_lst = list->ino_next;
503*0Sstevel@tonic-gate 	else {
504*0Sstevel@tonic-gate 		for (; list->ino_next != ino_p; list = list->ino_next);
505*0Sstevel@tonic-gate 		list->ino_next = ino_p->ino_next;
506*0Sstevel@tonic-gate 	}
507*0Sstevel@tonic-gate }
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate /*
510*0Sstevel@tonic-gate  * Free all ino when we are detaching.
511*0Sstevel@tonic-gate  */
512*0Sstevel@tonic-gate void
513*0Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p)
514*0Sstevel@tonic-gate {
515*0Sstevel@tonic-gate 	px_ib_ino_info_t	*tmp = ib_p->ib_ino_lst;
516*0Sstevel@tonic-gate 	px_ib_ino_info_t	*next = NULL;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	while (tmp) {
519*0Sstevel@tonic-gate 		next = tmp->ino_next;
520*0Sstevel@tonic-gate 		kmem_free(tmp, sizeof (px_ib_ino_info_t));
521*0Sstevel@tonic-gate 		tmp = next;
522*0Sstevel@tonic-gate 	}
523*0Sstevel@tonic-gate }
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate int
526*0Sstevel@tonic-gate px_ib_ino_add_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p)
527*0Sstevel@tonic-gate {
528*0Sstevel@tonic-gate 	px_ib_t		*ib_p = ino_p->ino_ib_p;
529*0Sstevel@tonic-gate 	devino_t	ino = ino_p->ino_ino;
530*0Sstevel@tonic-gate 	sysino_t	sysino = ino_p->ino_sysino;
531*0Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
532*0Sstevel@tonic-gate 	cpuid_t		curr_cpu;
533*0Sstevel@tonic-gate 	hrtime_t	start_time;
534*0Sstevel@tonic-gate 	intr_state_t	intr_state;
535*0Sstevel@tonic-gate 	int		ret = DDI_SUCCESS;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
538*0Sstevel@tonic-gate 	ASSERT(ib_p == px_p->px_ib_p);
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino);
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	/* Disable the interrupt */
543*0Sstevel@tonic-gate 	if ((ret = px_lib_intr_gettarget(dip, sysino,
544*0Sstevel@tonic-gate 	    &curr_cpu)) != DDI_SUCCESS) {
545*0Sstevel@tonic-gate 		DBG(DBG_IB, dip,
546*0Sstevel@tonic-gate 		    "px_ib_ino_add_intr px_intr_gettarget() failed\n");
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 		return (ret);
549*0Sstevel@tonic-gate 	}
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	PX_INTR_DISABLE(dip, sysino);
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	/* Busy wait on pending interrupt */
554*0Sstevel@tonic-gate 	for (start_time = gethrtime(); !panicstr &&
555*0Sstevel@tonic-gate 	    ((ret = px_lib_intr_getstate(dip, sysino, &intr_state))
556*0Sstevel@tonic-gate 	    == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) {
557*0Sstevel@tonic-gate 		if (gethrtime() - start_time > px_intrpend_timeout) {
558*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending "
559*0Sstevel@tonic-gate 			    "sysino 0x%x(ino 0x%x) timeout",
560*0Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
561*0Sstevel@tonic-gate 			    sysino, ino);
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 			ret = DDI_FAILURE;
564*0Sstevel@tonic-gate 			break;
565*0Sstevel@tonic-gate 		}
566*0Sstevel@tonic-gate 	}
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
569*0Sstevel@tonic-gate 		DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, "
570*0Sstevel@tonic-gate 		    "ino 0x%x sysino 0x%x\n", ino, sysino);
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 		return (ret);
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	/* Link up px_ispec_t portion of the ppd */
576*0Sstevel@tonic-gate 	ih_p->ih_next = ino_p->ino_ih_head;
577*0Sstevel@tonic-gate 	ino_p->ino_ih_tail->ih_next = ih_p;
578*0Sstevel@tonic-gate 	ino_p->ino_ih_tail = ih_p;
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	ino_p->ino_ih_start = ino_p->ino_ih_head;
581*0Sstevel@tonic-gate 	ino_p->ino_ih_size++;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	/*
584*0Sstevel@tonic-gate 	 * If the interrupt was previously blocked (left in pending state)
585*0Sstevel@tonic-gate 	 * because of jabber we need to clear the pending state in case the
586*0Sstevel@tonic-gate 	 * jabber has gone away.
587*0Sstevel@tonic-gate 	 */
588*0Sstevel@tonic-gate 	if (ino_p->ino_unclaimed > px_unclaimed_intr_max) {
589*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
590*0Sstevel@tonic-gate 		    "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked",
591*0Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip), ino);
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 		ino_p->ino_unclaimed = 0;
594*0Sstevel@tonic-gate 		if ((ret = px_lib_intr_setstate(dip, sysino,
595*0Sstevel@tonic-gate 		    INTR_IDLE_STATE)) != DDI_SUCCESS) {
596*0Sstevel@tonic-gate 			DBG(DBG_IB, px_p->px_dip,
597*0Sstevel@tonic-gate 			    "px_ib_ino_add_intr px_intr_setstate failed\n");
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 			return (ret);
600*0Sstevel@tonic-gate 		}
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/* Re-enable interrupt */
604*0Sstevel@tonic-gate 	PX_INTR_ENABLE(dip, sysino, curr_cpu);
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	return (ret);
607*0Sstevel@tonic-gate }
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate /*
610*0Sstevel@tonic-gate  * Removes px_ispec_t from the ino's link list.
611*0Sstevel@tonic-gate  * uses hardware mutex to lock out interrupt threads.
612*0Sstevel@tonic-gate  * Side effects: interrupt belongs to that ino is turned off on return.
613*0Sstevel@tonic-gate  * if we are sharing PX slot with other inos, the caller needs
614*0Sstevel@tonic-gate  * to turn it back on.
615*0Sstevel@tonic-gate  */
616*0Sstevel@tonic-gate int
617*0Sstevel@tonic-gate px_ib_ino_rem_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p)
618*0Sstevel@tonic-gate {
619*0Sstevel@tonic-gate 	devino_t	ino = ino_p->ino_ino;
620*0Sstevel@tonic-gate 	sysino_t	sysino = ino_p->ino_sysino;
621*0Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
622*0Sstevel@tonic-gate 	px_ih_t		*ih_lst = ino_p->ino_ih_head;
623*0Sstevel@tonic-gate 	hrtime_t	start_time;
624*0Sstevel@tonic-gate 	intr_state_t	intr_state;
625*0Sstevel@tonic-gate 	int		i, ret = DDI_SUCCESS;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex));
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n",
630*0Sstevel@tonic-gate 	    ino_p->ino_ino);
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	/* Disable the interrupt */
633*0Sstevel@tonic-gate 	PX_INTR_DISABLE(px_p->px_dip, sysino);
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	if (ino_p->ino_ih_size == 1) {
636*0Sstevel@tonic-gate 		if (ih_lst != ih_p)
637*0Sstevel@tonic-gate 			goto not_found;
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 		/* No need to set head/tail as ino_p will be freed */
640*0Sstevel@tonic-gate 		goto reset;
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	/* Busy wait on pending interrupt */
644*0Sstevel@tonic-gate 	for (start_time = gethrtime(); !panicstr &&
645*0Sstevel@tonic-gate 	    ((ret = px_lib_intr_getstate(dip, sysino, &intr_state))
646*0Sstevel@tonic-gate 	    == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) {
647*0Sstevel@tonic-gate 		if (gethrtime() - start_time > px_intrpend_timeout) {
648*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending "
649*0Sstevel@tonic-gate 			    "sysino 0x%x(ino 0x%x) timeout",
650*0Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
651*0Sstevel@tonic-gate 			    sysino, ino);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 			ret = DDI_FAILURE;
654*0Sstevel@tonic-gate 			break;
655*0Sstevel@tonic-gate 		}
656*0Sstevel@tonic-gate 	}
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
659*0Sstevel@tonic-gate 		DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, "
660*0Sstevel@tonic-gate 		    "ino 0x%x sysino 0x%x\n", ino, sysino);
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 		return (ret);
663*0Sstevel@tonic-gate 	}
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	/*
666*0Sstevel@tonic-gate 	 * If the interrupt was previously blocked (left in pending state)
667*0Sstevel@tonic-gate 	 * because of jabber we need to clear the pending state in case the
668*0Sstevel@tonic-gate 	 * jabber has gone away.
669*0Sstevel@tonic-gate 	 */
670*0Sstevel@tonic-gate 	if (ino_p->ino_unclaimed > px_unclaimed_intr_max) {
671*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: "
672*0Sstevel@tonic-gate 		    "ino 0x%x has been unblocked",
673*0Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip), ino);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 		ino_p->ino_unclaimed = 0;
676*0Sstevel@tonic-gate 		if ((ret = px_lib_intr_setstate(dip, sysino,
677*0Sstevel@tonic-gate 		    INTR_IDLE_STATE)) != DDI_SUCCESS) {
678*0Sstevel@tonic-gate 			DBG(DBG_IB, px_p->px_dip,
679*0Sstevel@tonic-gate 			    "px_ib_ino_rem_intr px_intr_setstate failed\n");
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 			return (ret);
682*0Sstevel@tonic-gate 		}
683*0Sstevel@tonic-gate 	}
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	/* Search the link list for ih_p */
686*0Sstevel@tonic-gate 	for (i = 0; (i < ino_p->ino_ih_size) &&
687*0Sstevel@tonic-gate 	    (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next);
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 	if (ih_lst->ih_next != ih_p)
690*0Sstevel@tonic-gate 		goto not_found;
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	/* Remove ih_p from the link list and maintain the head/tail */
693*0Sstevel@tonic-gate 	ih_lst->ih_next = ih_p->ih_next;
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	if (ino_p->ino_ih_head == ih_p)
696*0Sstevel@tonic-gate 		ino_p->ino_ih_head = ih_p->ih_next;
697*0Sstevel@tonic-gate 	if (ino_p->ino_ih_tail == ih_p)
698*0Sstevel@tonic-gate 		ino_p->ino_ih_tail = ih_lst;
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 	ino_p->ino_ih_start = ino_p->ino_ih_head;
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate reset:
703*0Sstevel@tonic-gate 	if (ih_p->ih_config_handle)
704*0Sstevel@tonic-gate 		pci_config_teardown(&ih_p->ih_config_handle);
705*0Sstevel@tonic-gate 	if (ih_p->ih_ksp != NULL)
706*0Sstevel@tonic-gate 		kstat_delete(ih_p->ih_ksp);
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	kmem_free(ih_p, sizeof (px_ih_t));
709*0Sstevel@tonic-gate 	ino_p->ino_ih_size--;
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	return (ret);
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate not_found:
714*0Sstevel@tonic-gate 	DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip,
715*0Sstevel@tonic-gate 		"ino_p=%x does not have ih_p=%x\n", ino_p, ih_p);
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	return (DDI_FAILURE);
718*0Sstevel@tonic-gate }
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate px_ih_t *
721*0Sstevel@tonic-gate px_ib_ino_locate_intr(px_ib_ino_info_t *ino_p, dev_info_t *rdip,
722*0Sstevel@tonic-gate     uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code)
723*0Sstevel@tonic-gate {
724*0Sstevel@tonic-gate 	px_ih_t	*ih_lst = ino_p->ino_ih_head;
725*0Sstevel@tonic-gate 	int	i;
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 	for (i = 0; i < ino_p->ino_ih_size; i++, ih_lst = ih_lst->ih_next) {
728*0Sstevel@tonic-gate 		if ((ih_lst->ih_dip == rdip) && (ih_lst->ih_inum == inum) &&
729*0Sstevel@tonic-gate 		    (ih_lst->ih_rec_type == rec_type) &&
730*0Sstevel@tonic-gate 		    (ih_lst->ih_msg_code == msg_code))
731*0Sstevel@tonic-gate 			return (ih_lst);
732*0Sstevel@tonic-gate 	}
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	return ((px_ih_t *)NULL);
735*0Sstevel@tonic-gate }
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate px_ih_t *
738*0Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum,
739*0Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2),
740*0Sstevel@tonic-gate     caddr_t int_handler_arg1, caddr_t int_handler_arg2,
741*0Sstevel@tonic-gate     msiq_rec_type_t rec_type, msgcode_t msg_code)
742*0Sstevel@tonic-gate {
743*0Sstevel@tonic-gate 	px_ih_t	*ih_p;
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP);
746*0Sstevel@tonic-gate 	ih_p->ih_dip = rdip;
747*0Sstevel@tonic-gate 	ih_p->ih_inum = inum;
748*0Sstevel@tonic-gate 	ih_p->ih_intr_state = PX_INTR_STATE_DISABLE;
749*0Sstevel@tonic-gate 	ih_p->ih_handler = int_handler;
750*0Sstevel@tonic-gate 	ih_p->ih_handler_arg1 = int_handler_arg1;
751*0Sstevel@tonic-gate 	ih_p->ih_handler_arg2 = int_handler_arg2;
752*0Sstevel@tonic-gate 	ih_p->ih_config_handle = NULL;
753*0Sstevel@tonic-gate 	ih_p->ih_rec_type = rec_type;
754*0Sstevel@tonic-gate 	ih_p->ih_msg_code = msg_code;
755*0Sstevel@tonic-gate 	ih_p->ih_nsec = 0;
756*0Sstevel@tonic-gate 	ih_p->ih_ticks = 0;
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	/*
759*0Sstevel@tonic-gate 	 * Create pci_intrs::: kstats for all ih types except messages,
760*0Sstevel@tonic-gate 	 * which represent unusual conditions and don't need to be tracked.
761*0Sstevel@tonic-gate 	 */
762*0Sstevel@tonic-gate 	ih_p->ih_ksp = NULL;
763*0Sstevel@tonic-gate 	if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) {
764*0Sstevel@tonic-gate 		ih_p->ih_ksp = kstat_create("pci_intrs",
765*0Sstevel@tonic-gate 		    atomic_inc_32_nv(&ih_instance), "config", "interrupts",
766*0Sstevel@tonic-gate 		    KSTAT_TYPE_NAMED,
767*0Sstevel@tonic-gate 		    sizeof (px_ih_ks_template) / sizeof (kstat_named_t),
768*0Sstevel@tonic-gate 		    KSTAT_FLAG_VIRTUAL);
769*0Sstevel@tonic-gate 	}
770*0Sstevel@tonic-gate 	if (ih_p->ih_ksp != NULL) {
771*0Sstevel@tonic-gate 		ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2;
772*0Sstevel@tonic-gate 		ih_p->ih_ksp->ks_lock = &ih_ks_template_lock;
773*0Sstevel@tonic-gate 		ih_p->ih_ksp->ks_data = &px_ih_ks_template;
774*0Sstevel@tonic-gate 		ih_p->ih_ksp->ks_private = ih_p;
775*0Sstevel@tonic-gate 		ih_p->ih_ksp->ks_update = ih_ks_update;
776*0Sstevel@tonic-gate 	}
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	return (ih_p);
779*0Sstevel@tonic-gate }
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate /*
782*0Sstevel@tonic-gate  * Only used for fixed or legacy interrupts.
783*0Sstevel@tonic-gate  */
784*0Sstevel@tonic-gate int
785*0Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip,
786*0Sstevel@tonic-gate     uint_t inum, devino_t ino, uint_t new_intr_state)
787*0Sstevel@tonic-gate {
788*0Sstevel@tonic-gate 	px_ib_t		*ib_p = px_p->px_ib_p;
789*0Sstevel@tonic-gate 	px_ib_ino_info_t *ino_p;
790*0Sstevel@tonic-gate 	px_ih_t		*ih_p;
791*0Sstevel@tonic-gate 	int		ret = DDI_FAILURE;
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	DBG(DBG_IB, px_p->px_dip, "ib_update_intr_state: %s%d "
794*0Sstevel@tonic-gate 	    "inum %x devino %x state %x\n", ddi_driver_name(rdip),
795*0Sstevel@tonic-gate 	    ddi_get_instance(rdip), inum, ino, new_intr_state);
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	mutex_enter(&ib_p->ib_ino_lst_mutex);
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	if (ino_p = px_ib_locate_ino(ib_p, ino)) {
800*0Sstevel@tonic-gate 		if (ih_p = px_ib_ino_locate_intr(ino_p, rdip, inum, 0, 0)) {
801*0Sstevel@tonic-gate 			ih_p->ih_intr_state = new_intr_state;
802*0Sstevel@tonic-gate 			ret = DDI_SUCCESS;
803*0Sstevel@tonic-gate 		}
804*0Sstevel@tonic-gate 	}
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	mutex_exit(&ib_p->ib_ino_lst_mutex);
807*0Sstevel@tonic-gate 	return (ret);
808*0Sstevel@tonic-gate }
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate int
811*0Sstevel@tonic-gate px_imu_intr(dev_info_t *dip, px_fh_t *fh_p)
812*0Sstevel@tonic-gate {
813*0Sstevel@tonic-gate 	uint32_t offset = px_fhd_tbl[fh_p->fh_err_id].fhd_st;
814*0Sstevel@tonic-gate 	uint64_t stat = fh_p->fh_stat;
815*0Sstevel@tonic-gate 	if (stat)
816*0Sstevel@tonic-gate 		LOG(DBG_ERR_INTR, dip, "[%x]=%16llx imu stat\n", offset, stat);
817*0Sstevel@tonic-gate 	return (stat ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED);
818*0Sstevel@tonic-gate }
819