xref: /illumos-gate/usr/src/uts/sun4u/io/pci/pci_ib.c (revision 635216b673cf196ac523ff2a7ab715717e553292)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * PCI Interrupt Block (RISCx) implementation
28  *	initialization
29  *	interrupt enable/disable/clear and mapping register manipulation
30  */
31 
32 #include <sys/types.h>
33 #include <sys/kmem.h>
34 #include <sys/async.h>
35 #include <sys/systm.h>		/* panicstr */
36 #include <sys/spl.h>
37 #include <sys/sunddi.h>
38 #include <sys/machsystm.h>	/* intr_dist_add */
39 #include <sys/ddi_impldefs.h>
40 #include <sys/clock.h>
41 #include <sys/cpuvar.h>
42 #include <sys/pci/pci_obj.h>
43 
44 #ifdef _STARFIRE
45 #include <sys/starfire.h>
46 #endif /* _STARFIRE */
47 
48 /*LINTLIBRARY*/
49 static uint_t ib_intr_reset(void *arg);
50 
51 void
52 ib_create(pci_t *pci_p)
53 {
54 	dev_info_t *dip = pci_p->pci_dip;
55 	ib_t *ib_p;
56 	uintptr_t a;
57 	int i;
58 
59 	/*
60 	 * Allocate interrupt block state structure and link it to
61 	 * the pci state structure.
62 	 */
63 	ib_p = kmem_zalloc(sizeof (ib_t), KM_SLEEP);
64 	pci_p->pci_ib_p = ib_p;
65 	ib_p->ib_pci_p = pci_p;
66 
67 	a = pci_ib_setup(ib_p);
68 
69 	/*
70 	 * Determine virtual addresses of interrupt mapping, clear and diag
71 	 * registers that have common offsets.
72 	 */
73 	ib_p->ib_slot_clear_intr_regs =
74 	    a + COMMON_IB_SLOT_CLEAR_INTR_REG_OFFSET;
75 	ib_p->ib_intr_retry_timer_reg =
76 	    (uint64_t *)(a + COMMON_IB_INTR_RETRY_TIMER_OFFSET);
77 	ib_p->ib_slot_intr_state_diag_reg =
78 	    (uint64_t *)(a + COMMON_IB_SLOT_INTR_STATE_DIAG_REG);
79 	ib_p->ib_obio_intr_state_diag_reg =
80 	    (uint64_t *)(a + COMMON_IB_OBIO_INTR_STATE_DIAG_REG);
81 
82 	if (CHIP_TYPE(pci_p) != PCI_CHIP_XMITS) {
83 		ib_p->ib_upa_imr[0] = (volatile uint64_t *)
84 		    (a + COMMON_IB_UPA0_INTR_MAP_REG_OFFSET);
85 		ib_p->ib_upa_imr[1] = (volatile uint64_t *)
86 		    (a + COMMON_IB_UPA1_INTR_MAP_REG_OFFSET);
87 	}
88 
89 	DEBUG2(DBG_ATTACH, dip, "ib_create: slot_imr=%x, slot_cir=%x\n",
90 	    ib_p->ib_slot_intr_map_regs, ib_p->ib_obio_intr_map_regs);
91 	DEBUG2(DBG_ATTACH, dip, "ib_create: obio_imr=%x, obio_cir=%x\n",
92 	    ib_p->ib_slot_clear_intr_regs, ib_p->ib_obio_clear_intr_regs);
93 	DEBUG2(DBG_ATTACH, dip, "ib_create: upa0_imr=%x, upa1_imr=%x\n",
94 	    ib_p->ib_upa_imr[0], ib_p->ib_upa_imr[1]);
95 	DEBUG3(DBG_ATTACH, dip,
96 	    "ib_create: retry_timer=%x, obio_diag=%x slot_diag=%x\n",
97 	    ib_p->ib_intr_retry_timer_reg,
98 	    ib_p->ib_obio_intr_state_diag_reg,
99 	    ib_p->ib_slot_intr_state_diag_reg);
100 
101 	ib_p->ib_ino_lst = (ib_ino_info_t *)NULL;
102 	mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL);
103 	mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL);
104 
105 	DEBUG1(DBG_ATTACH, dip, "ib_create: numproxy=%x\n",
106 	    pci_p->pci_numproxy);
107 	for (i = 1; i <= pci_p->pci_numproxy; i++) {
108 		set_intr_mapping_reg(pci_p->pci_id,
109 		    (uint64_t *)ib_p->ib_upa_imr[i - 1], i);
110 	}
111 
112 	ib_configure(ib_p);
113 	bus_func_register(BF_TYPE_RESINTR, ib_intr_reset, ib_p);
114 }
115 
116 void
117 ib_destroy(pci_t *pci_p)
118 {
119 	ib_t *ib_p = pci_p->pci_ib_p;
120 	dev_info_t *dip = pci_p->pci_dip;
121 
122 	DEBUG0(DBG_IB, dip, "ib_destroy\n");
123 	bus_func_unregister(BF_TYPE_RESINTR, ib_intr_reset, ib_p);
124 
125 	intr_dist_rem_weighted(ib_intr_dist_all, ib_p);
126 	mutex_destroy(&ib_p->ib_ino_lst_mutex);
127 	mutex_destroy(&ib_p->ib_intr_lock);
128 
129 	ib_free_ino_all(ib_p);
130 
131 	kmem_free(ib_p, sizeof (ib_t));
132 	pci_p->pci_ib_p = NULL;
133 }
134 
135 void
136 ib_configure(ib_t *ib_p)
137 {
138 	/* XXX could be different between psycho and schizo */
139 	*ib_p->ib_intr_retry_timer_reg = pci_intr_retry_intv;
140 }
141 
142 /*
143  * can only used for psycho internal interrupts thermal, power,
144  * ue, ce, pbm
145  */
146 void
147 ib_intr_enable(pci_t *pci_p, ib_ino_t ino)
148 {
149 	ib_t *ib_p = pci_p->pci_ib_p;
150 	ib_mondo_t mondo = IB_INO_TO_MONDO(ib_p, ino);
151 	volatile uint64_t *imr_p = ib_intr_map_reg_addr(ib_p, ino);
152 	uint_t cpu_id;
153 
154 	/*
155 	 * Determine the cpu for the interrupt.
156 	 */
157 	mutex_enter(&ib_p->ib_intr_lock);
158 	cpu_id = intr_dist_cpuid();
159 #ifdef _STARFIRE
160 	cpu_id = pc_translate_tgtid(IB2CB(ib_p)->cb_ittrans_cookie, cpu_id,
161 	    IB_GET_MAPREG_INO(ino));
162 #endif /* _STARFIRE */
163 	DEBUG2(DBG_IB, pci_p->pci_dip,
164 	    "ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id);
165 
166 	*imr_p = ib_get_map_reg(mondo, cpu_id);
167 	IB_INO_INTR_CLEAR(ib_clear_intr_reg_addr(ib_p, ino));
168 	mutex_exit(&ib_p->ib_intr_lock);
169 }
170 
171 /*
172  * Disable the interrupt via its interrupt mapping register.
173  * Can only be used for internal interrupts: thermal, power, ue, ce, pbm.
174  * If called under interrupt context, wait should be set to 0
175  */
176 void
177 ib_intr_disable(ib_t *ib_p, ib_ino_t ino, int wait)
178 {
179 	volatile uint64_t *imr_p = ib_intr_map_reg_addr(ib_p, ino);
180 	volatile uint64_t *state_reg_p = IB_INO_INTR_STATE_REG(ib_p, ino);
181 	hrtime_t start_time;
182 
183 	/* disable the interrupt */
184 	mutex_enter(&ib_p->ib_intr_lock);
185 	IB_INO_INTR_OFF(imr_p);
186 	*imr_p;	/* flush previous write */
187 	mutex_exit(&ib_p->ib_intr_lock);
188 
189 	if (!wait)
190 		goto wait_done;
191 
192 	start_time = gethrtime();
193 	/* busy wait if there is interrupt being processed */
194 	while (IB_INO_INTR_PENDING(state_reg_p, ino) && !panicstr) {
195 		if (gethrtime() - start_time > pci_intrpend_timeout) {
196 			pbm_t *pbm_p = ib_p->ib_pci_p->pci_pbm_p;
197 			cmn_err(CE_WARN, "%s:%s: ib_intr_disable timeout %x",
198 			    pbm_p->pbm_nameinst_str,
199 			    pbm_p->pbm_nameaddr_str, ino);
200 				break;
201 		}
202 	}
203 wait_done:
204 	IB_INO_INTR_PEND(ib_clear_intr_reg_addr(ib_p, ino));
205 #ifdef _STARFIRE
206 	pc_ittrans_cleanup(IB2CB(ib_p)->cb_ittrans_cookie,
207 	    (volatile uint64_t *)(uintptr_t)ino);
208 #endif /* _STARFIRE */
209 }
210 
211 /* can only used for psycho internal interrupts thermal, power, ue, ce, pbm */
212 void
213 ib_nintr_clear(ib_t *ib_p, ib_ino_t ino)
214 {
215 	uint64_t *clr_reg = ib_clear_intr_reg_addr(ib_p, ino);
216 	IB_INO_INTR_CLEAR(clr_reg);
217 }
218 
219 /*
220  * distribute PBM and UPA interrupts. ino is set to 0 by caller if we
221  * are dealing with UPA interrupts (without inos).
222  */
223 void
224 ib_intr_dist_nintr(ib_t *ib_p, ib_ino_t ino, volatile uint64_t *imr_p)
225 {
226 	volatile uint64_t imr = *imr_p;
227 	uint32_t cpu_id;
228 
229 	if (!IB_INO_INTR_ISON(imr))
230 		return;
231 
232 	cpu_id = intr_dist_cpuid();
233 
234 #ifdef _STARFIRE
235 	if (ino) {
236 		cpu_id = pc_translate_tgtid(IB2CB(ib_p)->cb_ittrans_cookie,
237 		    cpu_id, IB_GET_MAPREG_INO(ino));
238 	}
239 #else /* _STARFIRE */
240 	if (ib_map_reg_get_cpu(*imr_p) == cpu_id)
241 		return;
242 #endif /* _STARFIRE */
243 
244 	*imr_p = ib_get_map_reg(IB_IMR2MONDO(imr), cpu_id);
245 	imr = *imr_p;	/* flush previous write */
246 }
247 
248 /*
249  * Converts into nsec, ticks logged with a given CPU.  Adds nsec to ih.
250  */
251 /*ARGSUSED*/
252 void
253 ib_cpu_ticks_to_ih_nsec(ib_t *ib_p, ih_t *ih_p, uint32_t cpu_id)
254 {
255 	extern kmutex_t pciintr_ks_template_lock;
256 	hrtime_t ticks;
257 
258 	/*
259 	 * Because we are updating two fields in ih_t we must lock
260 	 * pciintr_ks_template_lock to prevent someone from reading the
261 	 * kstats after we set ih_ticks to 0 and before we increment
262 	 * ih_nsec to compensate.
263 	 *
264 	 * We must also protect against the interrupt arriving and incrementing
265 	 * ih_ticks between the time we read it and when we reset it to 0.
266 	 * To do this we use atomic_swap.
267 	 */
268 
269 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
270 
271 	mutex_enter(&pciintr_ks_template_lock);
272 	ticks = atomic_swap_64(&ih_p->ih_ticks, 0);
273 	ih_p->ih_nsec += (uint64_t)tick2ns(ticks, cpu_id);
274 	mutex_exit(&pciintr_ks_template_lock);
275 }
276 
277 static void
278 ib_intr_dist(ib_t *ib_p, ib_ino_info_t *ino_p)
279 {
280 	uint32_t cpu_id = ino_p->ino_cpuid;
281 	ib_ino_t ino = ino_p->ino_ino;
282 	volatile uint64_t imr, *imr_p, *state_reg;
283 	hrtime_t start_time;
284 
285 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
286 	imr_p = ib_intr_map_reg_addr(ib_p, ino);
287 	state_reg = IB_INO_INTR_STATE_REG(ib_p, ino);
288 
289 #ifdef _STARFIRE
290 	/*
291 	 * For Starfire it is a pain to check the current target for
292 	 * the mondo since we have to read the PC asics ITTR slot
293 	 * assigned to this mondo. It will be much easier to assume
294 	 * the current target is always different and do the target
295 	 * reprogram all the time.
296 	 */
297 	cpu_id = pc_translate_tgtid(IB2CB(ib_p)->cb_ittrans_cookie, cpu_id,
298 	    IB_GET_MAPREG_INO(ino));
299 #else
300 	if (ib_map_reg_get_cpu(*imr_p) == cpu_id) /* same cpu, no reprog */
301 		return;
302 #endif /* _STARFIRE */
303 
304 	/* disable interrupt, this could disrupt devices sharing our slot */
305 	IB_INO_INTR_OFF(imr_p);
306 	imr = *imr_p;	/* flush previous write */
307 
308 	/* busy wait if there is interrupt being processed */
309 	start_time = gethrtime();
310 	while (IB_INO_INTR_PENDING(state_reg, ino) && !panicstr) {
311 		if (gethrtime() - start_time > pci_intrpend_timeout) {
312 			pbm_t *pbm_p = ib_p->ib_pci_p->pci_pbm_p;
313 			cmn_err(CE_WARN, "%s:%s: ib_intr_dist(%p,%x) timeout",
314 			    pbm_p->pbm_nameinst_str,
315 			    pbm_p->pbm_nameaddr_str,
316 			    imr_p, IB_INO_TO_MONDO(ib_p, ino));
317 			break;
318 		}
319 	}
320 	*imr_p = ib_get_map_reg(IB_IMR2MONDO(imr), cpu_id);
321 	imr = *imr_p;	/* flush previous write */
322 }
323 
324 /*
325  * Redistribute interrupts of the specified weight. The first call has a weight
326  * of weight_max, which can be used to trigger initialization for
327  * redistribution. The inos with weight [weight_max, inf.) should be processed
328  * on the "weight == weight_max" call.  This first call is followed by calls
329  * of decreasing weights, inos of that weight should be processed.  The final
330  * call specifies a weight of zero, this can be used to trigger processing of
331  * stragglers.
332  */
333 void
334 ib_intr_dist_all(void *arg, int32_t weight_max, int32_t weight)
335 {
336 	ib_t *ib_p = (ib_t *)arg;
337 	pci_t *pci_p = ib_p->ib_pci_p;
338 	ib_ino_info_t *ino_p;
339 	ib_ino_pil_t *ipil_p;
340 	ih_t *ih_lst;
341 	int32_t dweight;
342 	int i;
343 
344 	if (weight == 0) {
345 		mutex_enter(&ib_p->ib_intr_lock);
346 		if (CHIP_TYPE(pci_p) != PCI_CHIP_XMITS) {
347 			for (i = 0; i < 2; i++)
348 				ib_intr_dist_nintr(ib_p, 0,
349 				    ib_p->ib_upa_imr[i]);
350 		}
351 		mutex_exit(&ib_p->ib_intr_lock);
352 	}
353 
354 	mutex_enter(&ib_p->ib_ino_lst_mutex);
355 
356 	/* Perform special processing for first call of a redistribution. */
357 	if (weight == weight_max) {
358 		for (ino_p = ib_p->ib_ino_lst; ino_p;
359 		    ino_p = ino_p->ino_next_p) {
360 
361 			/*
362 			 * Clear ino_established of each ino on first call.
363 			 * The ino_established field may be used by a pci
364 			 * nexus driver's pci_intr_dist_cpuid implementation
365 			 * when detection of established pci slot-cpu binding
366 			 * for multi function pci cards.
367 			 */
368 			ino_p->ino_established = 0;
369 
370 			/*
371 			 * recompute the ino_intr_weight based on the device
372 			 * weight of all devinfo nodes sharing the ino (this
373 			 * will allow us to pick up new weights established by
374 			 * i_ddi_set_intr_weight()).
375 			 */
376 			ino_p->ino_intr_weight = 0;
377 
378 			for (ipil_p = ino_p->ino_ipil_p; ipil_p;
379 			    ipil_p = ipil_p->ipil_next_p) {
380 				for (i = 0, ih_lst = ipil_p->ipil_ih_head;
381 				    i < ipil_p->ipil_ih_size; i++,
382 				    ih_lst = ih_lst->ih_next) {
383 					dweight = i_ddi_get_intr_weight
384 					    (ih_lst->ih_dip);
385 					if (dweight > 0)
386 						ino_p->ino_intr_weight +=
387 						    dweight;
388 				}
389 			}
390 		}
391 	}
392 
393 	for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next_p) {
394 		uint32_t orig_cpuid;
395 
396 		/*
397 		 * Get the weight of the ino and determine if we are going to
398 		 * process call.  We wait until an ib_intr_dist_all call of
399 		 * the proper weight occurs to support redistribution of all
400 		 * heavy weighted interrupts first (across all nexus driver
401 		 * instances).  This is done to ensure optimal
402 		 * INTR_WEIGHTED_DIST behavior.
403 		 */
404 		if ((weight == ino_p->ino_intr_weight) ||
405 		    ((weight >= weight_max) &&
406 		    (ino_p->ino_intr_weight >= weight_max))) {
407 			/* select cpuid to target and mark ino established */
408 			orig_cpuid = ino_p->ino_cpuid;
409 			if (cpu[orig_cpuid] == NULL)
410 				orig_cpuid = CPU->cpu_id;
411 			ino_p->ino_cpuid = pci_intr_dist_cpuid(ib_p, ino_p);
412 			ino_p->ino_established = 1;
413 
414 			/* Add device weight of ino devinfos to targeted cpu. */
415 			for (ipil_p = ino_p->ino_ipil_p; ipil_p;
416 			    ipil_p = ipil_p->ipil_next_p) {
417 				for (i = 0, ih_lst = ipil_p->ipil_ih_head;
418 				    i < ipil_p->ipil_ih_size; i++,
419 				    ih_lst = ih_lst->ih_next) {
420 
421 					dweight = i_ddi_get_intr_weight(
422 					    ih_lst->ih_dip);
423 					intr_dist_cpuid_add_device_weight(
424 					    ino_p->ino_cpuid, ih_lst->ih_dip,
425 					    dweight);
426 
427 					/*
428 					 * Different cpus may have different
429 					 * clock speeds. to account for this,
430 					 * whenever an interrupt is moved to a
431 					 * new CPU, we convert the accumulated
432 					 * ticks into nsec, based upon the clock
433 					 * rate of the prior CPU.
434 					 *
435 					 * It is possible that the prior CPU no
436 					 * longer exists. In this case, fall
437 					 * back to using this CPU's clock rate.
438 					 *
439 					 * Note that the value in ih_ticks has
440 					 * already been corrected for any power
441 					 * savings mode which might have been
442 					 * in effect.
443 					 */
444 					ib_cpu_ticks_to_ih_nsec(ib_p, ih_lst,
445 					    orig_cpuid);
446 				}
447 			}
448 
449 			/* program the hardware */
450 			ib_intr_dist(ib_p, ino_p);
451 		}
452 	}
453 	mutex_exit(&ib_p->ib_ino_lst_mutex);
454 }
455 
456 /*
457  * Reset interrupts to IDLE.  This function is called during
458  * panic handling after redistributing interrupts; it's needed to
459  * support dumping to network devices after 'sync' from OBP.
460  *
461  * N.B.  This routine runs in a context where all other threads
462  * are permanently suspended.
463  */
464 static uint_t
465 ib_intr_reset(void *arg)
466 {
467 	ib_t *ib_p = (ib_t *)arg;
468 	ib_ino_t ino;
469 	uint64_t *clr_reg;
470 
471 	/*
472 	 * Note that we only actually care about interrupts that are
473 	 * potentially from network devices.
474 	 */
475 	for (ino = 0; ino <= ib_p->ib_max_ino; ino++) {
476 		clr_reg = ib_clear_intr_reg_addr(ib_p, ino);
477 		IB_INO_INTR_CLEAR(clr_reg);
478 	}
479 
480 	return (BF_NONE);
481 }
482 
483 void
484 ib_suspend(ib_t *ib_p)
485 {
486 	ib_ino_info_t *ip;
487 	pci_t *pci_p = ib_p->ib_pci_p;
488 
489 	/* save ino_lst interrupts' mapping registers content */
490 	mutex_enter(&ib_p->ib_ino_lst_mutex);
491 	for (ip = ib_p->ib_ino_lst; ip; ip = ip->ino_next_p)
492 		ip->ino_map_reg_save = *ip->ino_map_reg;
493 	mutex_exit(&ib_p->ib_ino_lst_mutex);
494 
495 	if (CHIP_TYPE(pci_p) != PCI_CHIP_XMITS) {
496 		ib_p->ib_upa_imr_state[0] = *ib_p->ib_upa_imr[0];
497 		ib_p->ib_upa_imr_state[1] = *ib_p->ib_upa_imr[1];
498 	}
499 }
500 
501 void
502 ib_resume(ib_t *ib_p)
503 {
504 	ib_ino_info_t *ip;
505 	pci_t *pci_p = ib_p->ib_pci_p;
506 
507 	/* restore ino_lst interrupts' mapping registers content */
508 	mutex_enter(&ib_p->ib_ino_lst_mutex);
509 	for (ip = ib_p->ib_ino_lst; ip; ip = ip->ino_next_p) {
510 		IB_INO_INTR_CLEAR(ip->ino_clr_reg);	 /* set intr to idle */
511 		*ip->ino_map_reg = ip->ino_map_reg_save; /* restore IMR */
512 	}
513 	mutex_exit(&ib_p->ib_ino_lst_mutex);
514 
515 	if (CHIP_TYPE(pci_p) != PCI_CHIP_XMITS) {
516 		*ib_p->ib_upa_imr[0] = ib_p->ib_upa_imr_state[0];
517 		*ib_p->ib_upa_imr[1] = ib_p->ib_upa_imr_state[1];
518 	}
519 }
520 
521 /*
522  * locate ino_info structure on ib_p->ib_ino_lst according to ino#
523  * returns NULL if not found.
524  */
525 ib_ino_info_t *
526 ib_locate_ino(ib_t *ib_p, ib_ino_t ino_num)
527 {
528 	ib_ino_info_t *ino_p = ib_p->ib_ino_lst;
529 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
530 
531 	for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next_p)
532 		;
533 	return (ino_p);
534 }
535 
536 #define	IB_INO_TO_SLOT(ino) (IB_IS_OBIO_INO(ino) ? 0xff : ((ino) & 0x1f) >> 2)
537 
538 ib_ino_pil_t *
539 ib_new_ino_pil(ib_t *ib_p, ib_ino_t ino_num, uint_t pil, ih_t *ih_p)
540 {
541 	ib_ino_pil_t	*ipil_p = kmem_zalloc(sizeof (ib_ino_pil_t), KM_SLEEP);
542 	ib_ino_info_t	*ino_p;
543 
544 	if ((ino_p = ib_locate_ino(ib_p, ino_num)) == NULL) {
545 		ino_p = kmem_zalloc(sizeof (ib_ino_info_t), KM_SLEEP);
546 
547 		ino_p->ino_next_p = ib_p->ib_ino_lst;
548 		ib_p->ib_ino_lst = ino_p;
549 
550 		ino_p->ino_ino = ino_num;
551 		ino_p->ino_slot_no = IB_INO_TO_SLOT(ino_num);
552 		ino_p->ino_ib_p = ib_p;
553 		ino_p->ino_clr_reg = ib_clear_intr_reg_addr(ib_p, ino_num);
554 		ino_p->ino_map_reg = ib_intr_map_reg_addr(ib_p, ino_num);
555 		ino_p->ino_unclaimed_intrs = 0;
556 		ino_p->ino_lopil = pil;
557 	}
558 
559 	ih_p->ih_next = ih_p;
560 	ipil_p->ipil_pil = pil;
561 	ipil_p->ipil_ih_head = ih_p;
562 	ipil_p->ipil_ih_tail = ih_p;
563 	ipil_p->ipil_ih_start = ih_p;
564 	ipil_p->ipil_ih_size = 1;
565 	ipil_p->ipil_ino_p = ino_p;
566 
567 	ipil_p->ipil_next_p = ino_p->ino_ipil_p;
568 	ino_p->ino_ipil_p = ipil_p;
569 	ino_p->ino_ipil_size++;
570 
571 	if (ino_p->ino_lopil > pil)
572 		ino_p->ino_lopil = pil;
573 
574 	return (ipil_p);
575 }
576 
577 void
578 ib_delete_ino_pil(ib_t *ib_p, ib_ino_pil_t *ipil_p)
579 {
580 	ib_ino_info_t	*ino_p = ipil_p->ipil_ino_p;
581 	ib_ino_pil_t	*prev, *next;
582 	ushort_t	pil = ipil_p->ipil_pil;
583 
584 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
585 
586 	if (ino_p->ino_ipil_p == ipil_p)
587 		ino_p->ino_ipil_p = ipil_p->ipil_next_p;
588 	else {
589 		for (prev = next = ino_p->ino_ipil_p; next != ipil_p;
590 		    prev = next, next = next->ipil_next_p)
591 			;
592 
593 		if (prev)
594 			prev->ipil_next_p = ipil_p->ipil_next_p;
595 	}
596 
597 	kmem_free(ipil_p, sizeof (ib_ino_pil_t));
598 
599 	if ((--ino_p->ino_ipil_size) && (ino_p->ino_lopil == pil)) {
600 		for (next = ino_p->ino_ipil_p, pil = next->ipil_pil;
601 		    next; next = next->ipil_next_p) {
602 
603 			if (pil > next->ipil_pil)
604 				pil = next->ipil_pil;
605 		}
606 		/*
607 		 * Value stored in pil should be the lowest pil.
608 		 */
609 		ino_p->ino_lopil = pil;
610 	}
611 
612 	if (ino_p->ino_ipil_size)
613 		return;
614 
615 	if (ib_p->ib_ino_lst == ino_p)
616 		ib_p->ib_ino_lst = ino_p->ino_next_p;
617 	else {
618 		ib_ino_info_t	*list = ib_p->ib_ino_lst;
619 
620 		for (; list->ino_next_p != ino_p; list = list->ino_next_p)
621 			;
622 		list->ino_next_p = ino_p->ino_next_p;
623 	}
624 }
625 
626 /* free all ino when we are detaching */
627 void
628 ib_free_ino_all(ib_t *ib_p)
629 {
630 	ib_ino_info_t *ino_p = ib_p->ib_ino_lst;
631 	ib_ino_info_t *next = NULL;
632 
633 	while (ino_p) {
634 		next = ino_p->ino_next_p;
635 		kmem_free(ino_p, sizeof (ib_ino_info_t));
636 		ino_p = next;
637 	}
638 }
639 
640 /*
641  * Locate ib_ino_pil_t structure on ino_p->ino_ipil_p according to ino#
642  * returns NULL if not found.
643  */
644 ib_ino_pil_t *
645 ib_ino_locate_ipil(ib_ino_info_t *ino_p, uint_t pil)
646 {
647 	ib_ino_pil_t	*ipil_p = ino_p->ino_ipil_p;
648 
649 	for (; ipil_p && ipil_p->ipil_pil != pil; ipil_p = ipil_p->ipil_next_p)
650 		;
651 
652 	return (ipil_p);
653 }
654 
655 void
656 ib_ino_add_intr(pci_t *pci_p, ib_ino_pil_t *ipil_p, ih_t *ih_p)
657 {
658 	ib_ino_info_t *ino_p = ipil_p->ipil_ino_p;
659 	ib_ino_t ino = ino_p->ino_ino;
660 	ib_t *ib_p = ino_p->ino_ib_p;
661 	volatile uint64_t *state_reg = IB_INO_INTR_STATE_REG(ib_p, ino);
662 	hrtime_t start_time;
663 
664 	ASSERT(ib_p == pci_p->pci_ib_p);
665 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
666 
667 	/* disable interrupt, this could disrupt devices sharing our slot */
668 	IB_INO_INTR_OFF(ino_p->ino_map_reg);
669 	*ino_p->ino_map_reg;
670 
671 	/* do NOT modify the link list until after the busy wait */
672 
673 	/*
674 	 * busy wait if there is interrupt being processed.
675 	 * either the pending state will be cleared by the interrupt wrapper
676 	 * or the interrupt will be marked as blocked indicating that it was
677 	 * jabbering.
678 	 */
679 	start_time = gethrtime();
680 	while ((ino_p->ino_unclaimed_intrs <= pci_unclaimed_intr_max) &&
681 	    IB_INO_INTR_PENDING(state_reg, ino) && !panicstr) {
682 		if (gethrtime() - start_time > pci_intrpend_timeout) {
683 			pbm_t *pbm_p = pci_p->pci_pbm_p;
684 			cmn_err(CE_WARN, "%s:%s: ib_ino_add_intr %x timeout",
685 			    pbm_p->pbm_nameinst_str,
686 			    pbm_p->pbm_nameaddr_str, ino);
687 			break;
688 		}
689 	}
690 
691 	/* link up ih_t */
692 	ih_p->ih_next = ipil_p->ipil_ih_head;
693 	ipil_p->ipil_ih_tail->ih_next = ih_p;
694 	ipil_p->ipil_ih_tail = ih_p;
695 
696 	ipil_p->ipil_ih_start = ipil_p->ipil_ih_head;
697 	ipil_p->ipil_ih_size++;
698 
699 	/*
700 	 * if the interrupt was previously blocked (left in pending state)
701 	 * because of jabber we need to clear the pending state in case the
702 	 * jabber has gone away.
703 	 */
704 	if (ino_p->ino_unclaimed_intrs > pci_unclaimed_intr_max) {
705 		cmn_err(CE_WARN,
706 		    "%s%d: ib_ino_add_intr: ino 0x%x has been unblocked",
707 		    ddi_driver_name(pci_p->pci_dip),
708 		    ddi_get_instance(pci_p->pci_dip),
709 		    ino_p->ino_ino);
710 		ino_p->ino_unclaimed_intrs = 0;
711 		IB_INO_INTR_CLEAR(ino_p->ino_clr_reg);
712 	}
713 
714 	/* re-enable interrupt */
715 	IB_INO_INTR_ON(ino_p->ino_map_reg);
716 	*ino_p->ino_map_reg;
717 }
718 
719 /*
720  * removes pci_ispec_t from the ino's link list.
721  * uses hardware mutex to lock out interrupt threads.
722  * Side effects: interrupt belongs to that ino is turned off on return.
723  * if we are sharing PCI slot with other inos, the caller needs
724  * to turn it back on.
725  */
726 void
727 ib_ino_rem_intr(pci_t *pci_p, ib_ino_pil_t *ipil_p, ih_t *ih_p)
728 {
729 	ib_ino_info_t *ino_p = ipil_p->ipil_ino_p;
730 	int i;
731 	ib_ino_t ino = ino_p->ino_ino;
732 	ih_t *ih_lst = ipil_p->ipil_ih_head;
733 	volatile uint64_t *state_reg =
734 	    IB_INO_INTR_STATE_REG(ino_p->ino_ib_p, ino);
735 	hrtime_t start_time;
736 
737 	ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex));
738 	/* disable interrupt, this could disrupt devices sharing our slot */
739 	IB_INO_INTR_OFF(ino_p->ino_map_reg);
740 	*ino_p->ino_map_reg;
741 
742 	/* do NOT modify the link list until after the busy wait */
743 
744 	/*
745 	 * busy wait if there is interrupt being processed.
746 	 * either the pending state will be cleared by the interrupt wrapper
747 	 * or the interrupt will be marked as blocked indicating that it was
748 	 * jabbering.
749 	 */
750 	start_time = gethrtime();
751 	while ((ino_p->ino_unclaimed_intrs <= pci_unclaimed_intr_max) &&
752 	    IB_INO_INTR_PENDING(state_reg, ino) && !panicstr) {
753 		if (gethrtime() - start_time > pci_intrpend_timeout) {
754 			pbm_t *pbm_p = pci_p->pci_pbm_p;
755 			cmn_err(CE_WARN, "%s:%s: ib_ino_rem_intr %x timeout",
756 			    pbm_p->pbm_nameinst_str,
757 			    pbm_p->pbm_nameaddr_str, ino);
758 			break;
759 		}
760 	}
761 
762 	if (ipil_p->ipil_ih_size == 1) {
763 		if (ih_lst != ih_p)
764 			goto not_found;
765 		/* no need to set head/tail as ino_p will be freed */
766 		goto reset;
767 	}
768 
769 	/*
770 	 * if the interrupt was previously blocked (left in pending state)
771 	 * because of jabber we need to clear the pending state in case the
772 	 * jabber has gone away.
773 	 */
774 	if (ino_p->ino_unclaimed_intrs > pci_unclaimed_intr_max) {
775 		cmn_err(CE_WARN,
776 		    "%s%d: ib_ino_rem_intr: ino 0x%x has been unblocked",
777 		    ddi_driver_name(pci_p->pci_dip),
778 		    ddi_get_instance(pci_p->pci_dip),
779 		    ino_p->ino_ino);
780 		ino_p->ino_unclaimed_intrs = 0;
781 		IB_INO_INTR_CLEAR(ino_p->ino_clr_reg);
782 	}
783 
784 	/* search the link list for ih_p */
785 	for (i = 0;
786 	    (i < ipil_p->ipil_ih_size) && (ih_lst->ih_next != ih_p);
787 	    i++, ih_lst = ih_lst->ih_next)
788 		;
789 	if (ih_lst->ih_next != ih_p)
790 		goto not_found;
791 
792 	/* remove ih_p from the link list and maintain the head/tail */
793 	ih_lst->ih_next = ih_p->ih_next;
794 	if (ipil_p->ipil_ih_head == ih_p)
795 		ipil_p->ipil_ih_head = ih_p->ih_next;
796 	if (ipil_p->ipil_ih_tail == ih_p)
797 		ipil_p->ipil_ih_tail = ih_lst;
798 	ipil_p->ipil_ih_start = ipil_p->ipil_ih_head;
799 reset:
800 	if (ih_p->ih_config_handle)
801 		pci_config_teardown(&ih_p->ih_config_handle);
802 	if (ih_p->ih_ksp != NULL)
803 		kstat_delete(ih_p->ih_ksp);
804 	kmem_free(ih_p, sizeof (ih_t));
805 	ipil_p->ipil_ih_size--;
806 
807 	return;
808 not_found:
809 	DEBUG2(DBG_R_INTX, ino_p->ino_ib_p->ib_pci_p->pci_dip,
810 	    "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p);
811 }
812 
813 ih_t *
814 ib_intr_locate_ih(ib_ino_pil_t *ipil_p, dev_info_t *rdip, uint32_t inum)
815 {
816 	ih_t *ih_p = ipil_p->ipil_ih_head;
817 	int i;
818 
819 	for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) {
820 		if (ih_p->ih_dip == rdip && ih_p->ih_inum == inum)
821 			return (ih_p);
822 	}
823 
824 	return ((ih_t *)NULL);
825 }
826 
827 ih_t *
828 ib_alloc_ih(dev_info_t *rdip, uint32_t inum,
829 	uint_t (*int_handler)(caddr_t int_handler_arg1,
830 	caddr_t int_handler_arg2),
831 	caddr_t int_handler_arg1,
832 	caddr_t int_handler_arg2)
833 {
834 	ih_t *ih_p;
835 
836 	ih_p = kmem_alloc(sizeof (ih_t), KM_SLEEP);
837 	ih_p->ih_dip = rdip;
838 	ih_p->ih_inum = inum;
839 	ih_p->ih_intr_state = PCI_INTR_STATE_DISABLE;
840 	ih_p->ih_handler = int_handler;
841 	ih_p->ih_handler_arg1 = int_handler_arg1;
842 	ih_p->ih_handler_arg2 = int_handler_arg2;
843 	ih_p->ih_config_handle = NULL;
844 	ih_p->ih_nsec = 0;
845 	ih_p->ih_ticks = 0;
846 	ih_p->ih_ksp = NULL;
847 
848 	return (ih_p);
849 }
850 
851 int
852 ib_update_intr_state(pci_t *pci_p, dev_info_t *rdip,
853 	ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state)
854 {
855 	ib_t		*ib_p = pci_p->pci_ib_p;
856 	ib_ino_info_t	*ino_p;
857 	ib_ino_pil_t	*ipil_p;
858 	ib_mondo_t	mondo;
859 	ih_t		*ih_p;
860 	int		ret = DDI_FAILURE;
861 
862 	/*
863 	 * For PULSE interrupts, pci driver don't allocate
864 	 * ib_ino_info_t and ih_t data structures and also,
865 	 * not maintains any interrupt state information.
866 	 * So, just return success from here.
867 	 */
868 	if (hdlp->ih_vector & PCI_PULSE_INO) {
869 		DEBUG0(DBG_IB, ib_p->ib_pci_p->pci_dip,
870 		    "ib_update_intr_state: PULSE interrupt, return success\n");
871 
872 		return (DDI_SUCCESS);
873 	}
874 
875 	mutex_enter(&ib_p->ib_ino_lst_mutex);
876 
877 	if ((mondo = pci_xlate_intr(pci_p->pci_dip, rdip, pci_p->pci_ib_p,
878 	    IB_MONDO_TO_INO(hdlp->ih_vector))) == 0) {
879 		mutex_exit(&ib_p->ib_ino_lst_mutex);
880 		return (ret);
881 	}
882 
883 	ino_p = ib_locate_ino(ib_p, IB_MONDO_TO_INO(mondo));
884 	if (ino_p && (ipil_p = ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) {
885 		if (ih_p = ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum)) {
886 			ih_p->ih_intr_state = new_intr_state;
887 			ret = DDI_SUCCESS;
888 		}
889 	}
890 
891 	mutex_exit(&ib_p->ib_ino_lst_mutex);
892 	return (ret);
893 }
894 
895 /*
896  * Get interrupt CPU for a given ino.
897  * Return info only for inos which are already mapped to devices.
898  */
899 /*ARGSUSED*/
900 int
901 ib_get_intr_target(pci_t *pci_p, ib_ino_t ino, int *cpu_id_p)
902 {
903 	dev_info_t		*dip = pci_p->pci_dip;
904 	ib_t			*ib_p = pci_p->pci_ib_p;
905 	volatile uint64_t	*imregp;
906 	uint64_t		imregval;
907 
908 	DEBUG1(DBG_IB, dip, "ib_get_intr_target: ino %x\n", ino);
909 
910 	imregp = ib_intr_map_reg_addr(ib_p, ino);
911 	imregval = *imregp;
912 
913 	*cpu_id_p = ib_map_reg_get_cpu(imregval);
914 
915 	DEBUG1(DBG_IB, dip, "ib_get_intr_target: cpu_id %x\n", *cpu_id_p);
916 
917 	return (DDI_SUCCESS);
918 }
919 
920 /*
921  * Associate a new CPU with a given ino.
922  * Operate only on inos which are already mapped to devices.
923  */
924 int
925 ib_set_intr_target(pci_t *pci_p, ib_ino_t ino, int cpu_id)
926 {
927 	dev_info_t		*dip = pci_p->pci_dip;
928 	ib_t			*ib_p = pci_p->pci_ib_p;
929 	int			ret = DDI_SUCCESS;
930 	uint32_t		old_cpu_id;
931 	hrtime_t		start_time;
932 	uint64_t		imregval;
933 	uint64_t		new_imregval;
934 	volatile uint64_t	*imregp;
935 	volatile uint64_t	*idregp;
936 	extern const int	_ncpu;
937 	extern cpu_t		*cpu[];
938 
939 	DEBUG2(DBG_IB, dip, "ib_set_intr_target: ino %x cpu_id %x\n",
940 	    ino, cpu_id);
941 
942 	imregp = (uint64_t *)ib_intr_map_reg_addr(ib_p, ino);
943 	idregp = IB_INO_INTR_STATE_REG(ib_p, ino);
944 
945 	/* Save original mapreg value. */
946 	imregval = *imregp;
947 	DEBUG1(DBG_IB, dip, "ib_set_intr_target: orig mapreg value: 0x%llx\n",
948 	    imregval);
949 
950 	/* Operate only on inos which are already enabled. */
951 	if (!(imregval & COMMON_INTR_MAP_REG_VALID))
952 		return (DDI_FAILURE);
953 
954 	/* Is this request a noop? */
955 	if ((old_cpu_id = ib_map_reg_get_cpu(imregval)) == cpu_id)
956 		return (DDI_SUCCESS);
957 
958 	/* Clear the interrupt valid/enable bit for particular ino. */
959 	DEBUG0(DBG_IB, dip, "Clearing intr_enabled...\n");
960 	*imregp = imregval & ~COMMON_INTR_MAP_REG_VALID;
961 
962 	/* Wait until there are no more pending interrupts. */
963 	start_time = gethrtime();
964 
965 	DEBUG0(DBG_IB, dip, "About to check for pending interrupts...\n");
966 
967 	while (IB_INO_INTR_PENDING(idregp, ino)) {
968 		DEBUG0(DBG_IB, dip, "Waiting for pending ints to clear\n");
969 		if ((gethrtime() - start_time) < pci_intrpend_timeout) {
970 			continue;
971 		} else { /* Timed out waiting. */
972 			DEBUG0(DBG_IB, dip, "Timed out waiting \n");
973 			return (DDI_EPENDING);
974 		}
975 	}
976 
977 	new_imregval = *imregp;
978 
979 	DEBUG1(DBG_IB, dip,
980 	    "after disabling intr, mapreg value: 0x%llx\n", new_imregval);
981 
982 	/*
983 	 * Get lock, validate cpu and write new mapreg value.
984 	 */
985 	mutex_enter(&cpu_lock);
986 	if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) {
987 		/* Prepare new mapreg value with intr enabled and new cpu_id. */
988 		new_imregval &=
989 		    COMMON_INTR_MAP_REG_IGN | COMMON_INTR_MAP_REG_INO;
990 		new_imregval = ib_get_map_reg(new_imregval, cpu_id);
991 
992 		DEBUG1(DBG_IB, dip, "Writing new mapreg value:0x%llx\n",
993 		    new_imregval);
994 
995 		*imregp = new_imregval;
996 
997 		ib_log_new_cpu(ib_p, old_cpu_id, cpu_id, ino);
998 	} else {	/* Invalid cpu.  Restore original register image. */
999 		DEBUG0(DBG_IB, dip,
1000 		    "Invalid cpuid: writing orig mapreg value\n");
1001 
1002 		*imregp = imregval;
1003 		ret = DDI_EINVAL;
1004 	}
1005 	mutex_exit(&cpu_lock);
1006 
1007 	return (ret);
1008 }
1009 
1010 
1011 /*
1012  * Return the dips or number of dips associated with a given interrupt block.
1013  * Size of dips array arg is passed in as dips_ret arg.
1014  * Number of dips returned is returned in dips_ret arg.
1015  * Array of dips gets returned in the dips argument.
1016  * Function returns number of dips existing for the given interrupt block.
1017  *
1018  */
1019 uint8_t
1020 ib_get_ino_devs(
1021 	ib_t *ib_p, uint32_t ino, uint8_t *devs_ret, pcitool_intr_dev_t *devs)
1022 {
1023 	ib_ino_info_t	*ino_p;
1024 	ib_ino_pil_t	*ipil_p;
1025 	ih_t		*ih_p;
1026 	uint32_t	num_devs = 0;
1027 	int		i, j;
1028 
1029 	mutex_enter(&ib_p->ib_ino_lst_mutex);
1030 	ino_p = ib_locate_ino(ib_p, ino);
1031 	if (ino_p != NULL) {
1032 		for (j = 0, ipil_p = ino_p->ino_ipil_p; ipil_p;
1033 		    ipil_p = ipil_p->ipil_next_p) {
1034 			num_devs += ipil_p->ipil_ih_size;
1035 
1036 			for (i = 0, ih_p = ipil_p->ipil_ih_head;
1037 			    ((i < ipil_p->ipil_ih_size) && (i < *devs_ret));
1038 			    i++, j++, ih_p = ih_p->ih_next) {
1039 				(void) strncpy(devs[i].driver_name,
1040 				    ddi_driver_name(ih_p->ih_dip),
1041 				    MAXMODCONFNAME-1);
1042 				devs[i].driver_name[MAXMODCONFNAME] = '\0';
1043 				(void) ddi_pathname(ih_p->ih_dip, devs[i].path);
1044 				devs[i].dev_inst =
1045 				    ddi_get_instance(ih_p->ih_dip);
1046 			}
1047 		}
1048 		*devs_ret = j;
1049 	}
1050 
1051 	mutex_exit(&ib_p->ib_ino_lst_mutex);
1052 
1053 	return (num_devs);
1054 }
1055 
1056 void ib_log_new_cpu(ib_t *ib_p, uint32_t old_cpu_id, uint32_t new_cpu_id,
1057 	uint32_t ino)
1058 {
1059 	ib_ino_info_t	*ino_p;
1060 	ib_ino_pil_t	*ipil_p;
1061 	ih_t		*ih_p;
1062 	int		i;
1063 
1064 	mutex_enter(&ib_p->ib_ino_lst_mutex);
1065 
1066 	/* Log in OS data structures the new CPU. */
1067 	ino_p = ib_locate_ino(ib_p, ino);
1068 	if (ino_p != NULL) {
1069 
1070 		/* Log in OS data structures the new CPU. */
1071 		ino_p->ino_cpuid = new_cpu_id;
1072 
1073 		for (ipil_p = ino_p->ino_ipil_p; ipil_p;
1074 		    ipil_p = ipil_p->ipil_next_p) {
1075 			for (i = 0, ih_p = ipil_p->ipil_ih_head;
1076 			    (i < ipil_p->ipil_ih_size);
1077 			    i++, ih_p = ih_p->ih_next) {
1078 				/*
1079 				 * Account for any residual time
1080 				 * to be logged for old cpu.
1081 				 */
1082 				ib_cpu_ticks_to_ih_nsec(ib_p,
1083 				    ipil_p->ipil_ih_head, old_cpu_id);
1084 			}
1085 		}
1086 	}
1087 
1088 	mutex_exit(&ib_p->ib_ino_lst_mutex);
1089 }
1090