2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
9 #include <linux/types.h>
10 #include <linux/module.h>
11 #include <asm/sn/sgi.h>
12 #include <asm/sn/arch.h>
13 #include <asm/sn/pci/pciio.h>
14 #include <asm/sn/pci/pcibr.h>
15 #include <asm/sn/pci/pcibr_private.h>
16 #include <asm/sn/pci/pci_defs.h>
17 #include <asm/sn/io.h>
18 #include <asm/sn/sn_private.h>
22 compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr)
24 /* FIXME - compare_and_swap_ptr NOT ATOMIC */
25 if (*location == old_ptr) {
34 unsigned int pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots);
35 pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t);
36 void pcibr_intr_free(pcibr_intr_t);
37 void pcibr_setpciint(xtalk_intr_t);
38 int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t);
39 void pcibr_intr_disconnect(pcibr_intr_t);
41 vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t);
43 extern pcibr_info_t pcibr_info_get(vertex_hdl_t);
45 /* =====================================================================
46 * INTERRUPT MANAGEMENT
50 pcibr_intr_bits(pciio_info_t info,
51 pciio_intr_line_t lines, int nslots)
53 pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(info);
57 * Currently favored mapping from PCI
58 * slot number and INTA/B/C/D to Bridge
59 * PCI Interrupt Bit Number:
73 if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C))
75 if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D))
76 bbits |= 1 << (slot ^ 4);
83 * On SN systems there is a race condition between a PIO read response
84 * and DMA's. In rare cases, the read response may beat the DMA, causing
85 * the driver to think that data in memory is complete and meaningful.
86 * This code eliminates that race.
87 * This routine is called by the PIO read routines after doing the read.
88 * This routine then forces a fake interrupt on another line, which
89 * is logically associated with the slot that the PIO is addressed to.
90 * (see sn_dma_flush_init() )
91 * It then spins while watching the memory location that the interrupt
92 * is targetted to. When the interrupt response arrives, we are sure
93 * that the DMA has landed in memory and it is safe for the driver
97 extern struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS];
100 sn_dma_flush(unsigned long addr)
104 struct sn_flush_device_list *p;
109 nasid = NASID_GET(addr);
110 wid_num = SWIN_WIDGETNUM(addr);
111 bwin = BWIN_WINDOWNUM(addr);
113 if (flush_nasid_list[nasid].widget_p == NULL) return;
115 unsigned long itte = flush_nasid_list[nasid].iio_itte[bwin];
117 wid_num = (itte >> IIO_ITTE_WIDGET_SHIFT) &
118 IIO_ITTE_WIDGET_MASK;
120 if (flush_nasid_list[nasid].widget_p == NULL) return;
121 if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) return;
122 p = &flush_nasid_list[nasid].widget_p[wid_num][0];
124 /* find a matching BAR */
126 for (i=0; i<DEV_PER_WIDGET;i++) {
127 for (j=0; j<PCI_ROM_RESOURCE;j++) {
128 if (p->bar_list[j].start == 0) break;
129 if (addr >= p->bar_list[j].start && addr <= p->bar_list[j].end) break;
131 if (j < PCI_ROM_RESOURCE && p->bar_list[j].start != 0) break;
135 /* if no matching BAR, return without doing anything. */
137 if (i == DEV_PER_WIDGET) return;
139 spin_lock_irqsave(&p->flush_lock, flags);
143 /* force an interrupt. */
145 *(volatile uint32_t *)(p->force_int_addr) = 1;
147 /* wait for the interrupt to come back. */
149 while (p->flush_addr != 0x10f);
151 /* okay, everything is synched up. */
152 spin_unlock_irqrestore(&p->flush_lock, flags);
155 EXPORT_SYMBOL(sn_dma_flush);
158 * There are end cases where a deadlock can occur if interrupt
159 * processing completes and the Bridge b_int_status bit is still set.
161 * One scenerio is if a second PCI interrupt occurs within 60ns of
162 * the previous interrupt being cleared. In this case the Bridge
163 * does not detect the transition, the Bridge b_int_status bit
164 * remains set, and because no transition was detected no interrupt
165 * packet is sent to the Hub/Heart.
167 * A second scenerio is possible when a b_int_status bit is being
168 * shared by multiple devices:
169 * Device #1 generates interrupt
170 * Bridge b_int_status bit set
171 * Device #2 generates interrupt
172 * interrupt processing begins
173 * ISR for device #1 runs and
175 * Device #1 generates interrupt
176 * ISR for device #2 runs and
178 * (b_int_status bit still set)
179 * interrupt processing completes
181 * Interrupt processing is now complete, but an interrupt is still
182 * outstanding for Device #1. But because there was no transition of
183 * the b_int_status bit, no interrupt packet will be generated and
184 * a deadlock will occur.
186 * To avoid these deadlock situations, this function is used
187 * to check if a specific Bridge b_int_status bit is set, and if so,
188 * cause the setting of the corresponding interrupt bit.
190 * On a XBridge (SN1) and PIC (SN2), we do this by writing the appropriate Bridge Force
191 * Interrupt register.
194 pcibr_force_interrupt(pcibr_intr_t intr)
198 pcibr_soft_t pcibr_soft = intr->bi_soft;
200 bits = intr->bi_ibits;
201 for (bit = 0; bit < 8; bit++) {
202 if (bits & (1 << bit)) {
204 PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl,
205 "pcibr_force_interrupt: bit=0x%x\n", bit));
207 pcireg_force_intr_set(pcibr_soft, bit);
214 pcibr_intr_alloc(vertex_hdl_t pconn_vhdl,
215 device_desc_t dev_desc,
216 pciio_intr_line_t lines,
217 vertex_hdl_t owner_dev)
219 pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl);
220 pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
221 pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
222 vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn;
225 xtalk_intr_t *xtalk_intr_p;
226 pcibr_intr_t *pcibr_intr_p;
227 pcibr_intr_list_t *intr_list_p;
229 unsigned pcibr_int_bits;
230 unsigned pcibr_int_bit;
231 xtalk_intr_t xtalk_intr = (xtalk_intr_t)0;
233 pcibr_intr_t pcibr_intr;
234 pcibr_intr_list_t intr_entry;
235 pcibr_intr_list_t intr_list;
237 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
238 "pcibr_intr_alloc: %s%s%s%s%s\n",
239 !(lines & 15) ? " No INTs?" : "",
240 lines & 1 ? " INTA" : "",
241 lines & 2 ? " INTB" : "",
242 lines & 4 ? " INTC" : "",
243 lines & 8 ? " INTD" : ""));
245 pcibr_intr = kmalloc(sizeof (*(pcibr_intr)), GFP_KERNEL);
248 memset(pcibr_intr, 0, sizeof (*(pcibr_intr)));
250 pcibr_intr->bi_dev = pconn_vhdl;
251 pcibr_intr->bi_lines = lines;
252 pcibr_intr->bi_soft = pcibr_soft;
253 pcibr_intr->bi_ibits = 0; /* bits will be added below */
254 pcibr_intr->bi_func = 0; /* unset until connect */
255 pcibr_intr->bi_arg = 0; /* unset until connect */
256 pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD;
257 pcibr_intr->bi_mustruncpu = CPU_NONE;
258 pcibr_intr->bi_ibuf.ib_in = 0;
259 pcibr_intr->bi_ibuf.ib_out = 0;
260 spin_lock_init(&pcibr_intr->bi_ibuf.ib_lock);
262 pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info,
263 lines, PCIBR_NUM_SLOTS(pcibr_soft));
266 * For each PCI interrupt line requested, figure
267 * out which Bridge PCI Interrupt Line it maps
268 * to, and make sure there are xtalk resources
271 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
272 "pcibr_intr_alloc: pcibr_int_bits: 0x%x\n", pcibr_int_bits));
273 for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) {
274 if (pcibr_int_bits & (1 << pcibr_int_bit)) {
275 xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
277 xtalk_intr = *xtalk_intr_p;
279 if (xtalk_intr == NULL) {
281 * This xtalk_intr_alloc is constrained for two reasons:
282 * 1) Normal interrupts and error interrupts need to be delivered
283 * through a single xtalk target widget so that there aren't any
284 * ordering problems with DMA, completion interrupts, and error
285 * interrupts. (Use of xconn_vhdl forces this.)
287 * 2) On SN1, addressing constraints on SN1 and Bridge force
288 * us to use a single PI number for all interrupts from a
289 * single Bridge. (SN1-specific code forces this).
293 * All code dealing with threaded PCI interrupt handlers
294 * is located at the pcibr level. Because of this,
295 * we always want the lower layers (hub/heart_intr_alloc,
296 * intr_level_connect) to treat us as non-threaded so we
297 * don't set up a duplicate threaded environment. We make
298 * this happen by calling a special xtalk interface.
300 xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc,
303 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
304 "pcibr_intr_alloc: xtalk_intr=0x%lx\n", xtalk_intr));
306 /* both an assert and a runtime check on this:
307 * we need to check in non-DEBUG kernels, and
308 * the ASSERT gets us more information when
309 * we use DEBUG kernels.
311 ASSERT(xtalk_intr != NULL);
312 if (xtalk_intr == NULL) {
313 /* it is quite possible that our
314 * xtalk_intr_alloc failed because
315 * someone else got there first,
316 * and we can find their results
319 if (!*xtalk_intr_p) {
320 printk(KERN_ALERT "pcibr_intr_alloc %s: "
321 "unable to get xtalk interrupt resources",
322 pcibr_soft->bs_name);
323 /* yes, we leak resources here. */
326 } else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) {
328 * now tell the bridge which slot is
329 * using this interrupt line.
331 pcireg_intr_device_bit_clr(pcibr_soft,
332 BRIDGE_INT_DEV_MASK(pcibr_int_bit));
333 pcireg_intr_device_bit_set(pcibr_soft,
334 (pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit)));
336 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
337 "bridge intr bit %d clears my wrb\n",
340 /* someone else got one allocated first;
341 * free the one we just created, and
342 * retrieve the one they allocated.
344 xtalk_intr_free(xtalk_intr);
345 xtalk_intr = *xtalk_intr_p;
349 pcibr_intr->bi_ibits |= 1 << pcibr_int_bit;
351 intr_entry = kmalloc(sizeof (*(intr_entry)), GFP_KERNEL);
353 printk(KERN_ALERT "pcibr_intr_alloc %s: "
354 "unable to get memory",
355 pcibr_soft->bs_name);
358 memset(intr_entry, 0, sizeof (*(intr_entry)));
360 intr_entry->il_next = NULL;
361 intr_entry->il_intr = pcibr_intr;
362 intr_entry->il_soft = pcibr_soft;
363 intr_entry->il_slot = pciio_slot;
365 &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list;
367 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
368 "Bridge bit 0x%x wrap=0x%lx\n", pcibr_int_bit,
369 &(pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap)));
371 if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
372 /* we are the first interrupt on this bridge bit.
374 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
375 "INT 0x%x (bridge bit %d) allocated [FIRST]\n",
376 pcibr_int_bits, pcibr_int_bit));
379 intr_list = *intr_list_p;
380 pcibr_intr_p = &intr_list->il_intr;
381 if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) {
382 /* first entry on list was erased,
383 * and we replaced it, so we
384 * don't need our intr_entry.
387 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
388 "INT 0x%x (bridge bit %d) replaces erased first\n",
389 pcibr_int_bits, pcibr_int_bit));
392 intr_list_p = &intr_list->il_next;
393 if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
394 /* we are the new second interrupt on this bit.
396 pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1;
397 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
398 "INT 0x%x (bridge bit %d) is new SECOND\n",
399 pcibr_int_bits, pcibr_int_bit));
403 pcibr_intr_p = &intr_list->il_intr;
404 if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) {
405 /* an entry on list was erased,
406 * and we replaced it, so we
407 * don't need our intr_entry.
411 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
412 "INT 0x%x (bridge bit %d) replaces erase Nth\n",
413 pcibr_int_bits, pcibr_int_bit));
416 intr_list_p = &intr_list->il_next;
417 if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
418 /* entry appended to share list
420 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
421 "INT 0x%x (bridge bit %d) is new Nth\n",
422 pcibr_int_bits, pcibr_int_bit));
425 /* step to next record in chain
427 intr_list = *intr_list_p;
432 hub_intr = (hub_intr_t)xtalk_intr;
433 pcibr_intr->bi_irq = hub_intr->i_bit;
434 pcibr_intr->bi_cpu = hub_intr->i_cpuid;
435 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
436 "pcibr_intr_alloc complete: pcibr_intr=0x%lx\n", pcibr_intr));
442 pcibr_intr_free(pcibr_intr_t pcibr_intr)
444 unsigned pcibr_int_bits = pcibr_intr->bi_ibits;
445 pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft;
446 unsigned pcibr_int_bit;
447 pcibr_intr_list_t intr_list;
449 xtalk_intr_t *xtalk_intrp;
451 for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) {
452 if (pcibr_int_bits & (1 << pcibr_int_bit)) {
454 pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list;
456 intr_list = intr_list->il_next)
457 if (compare_and_swap_ptr((void **) &intr_list->il_intr,
461 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC,
463 "pcibr_intr_free: cleared hdlr from bit 0x%x\n",
466 /* If this interrupt line is not being shared between multiple
467 * devices release the xtalk interrupt resources.
470 pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared;
471 xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
473 if ((!intr_shared) && (*xtalk_intrp)) {
475 xtalk_intr_free(*xtalk_intrp);
478 /* Clear the PCI device interrupt to bridge interrupt pin
481 pcireg_intr_device_bit_clr(pcibr_soft,
482 BRIDGE_INT_DEV_MASK(pcibr_int_bit));
490 pcibr_setpciint(xtalk_intr_t xtalk_intr)
493 xtalk_intr_vector_t vect;
499 addr = xtalk_intr_addr_get(xtalk_intr);
500 vect = xtalk_intr_vector_get(xtalk_intr);
501 vhdl = xtalk_intr_dev_get(xtalk_intr);
503 /* bus and int_bits are stored in sfarg, bus bit3, int_bits bit2:0 */
504 pcibr_int_bit = *((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x7;
505 bus_num = ((*((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x8) >> 3);
507 bridge = pcibr_bridge_ptr_get(vhdl, bus_num);
508 pcireg_bridge_intr_addr_vect_set(bridge, pcibr_int_bit, vect);
509 pcireg_bridge_intr_addr_addr_set(bridge, pcibr_int_bit, addr);
514 pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg)
516 pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft;
517 unsigned pcibr_int_bits = pcibr_intr->bi_ibits;
518 unsigned pcibr_int_bit;
521 if (pcibr_intr == NULL)
524 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
525 "pcibr_intr_connect: intr_func=0x%lx, intr_arg=0x%lx\n",
526 intr_func, intr_arg));
528 pcibr_intr->bi_func = intr_func;
529 pcibr_intr->bi_arg = intr_arg;
530 *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED;
533 * For each PCI interrupt line requested, figure
534 * out which Bridge PCI Interrupt Line it maps
535 * to, and make sure there are xtalk resources
538 for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
539 if (pcibr_int_bits & (1 << pcibr_int_bit)) {
540 pcibr_intr_wrap_t intr_wrap;
541 xtalk_intr_t xtalk_intr;
544 xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
545 intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
548 * If this interrupt line is being shared and the connect has
549 * already been done, no need to do it again.
551 if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected)
556 * Use the pcibr wrapper function to handle all Bridge interrupts
557 * regardless of whether the interrupt line is shared or not.
559 int_addr = pcireg_intr_addr_addr(pcibr_soft, pcibr_int_bit);
560 pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit =
561 ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit);
562 xtalk_intr_connect(xtalk_intr,
564 (intr_arg_t) intr_wrap,
565 (xtalk_intr_setfunc_t) pcibr_setpciint,
566 &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit);
568 pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1;
570 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
571 "pcibr_setpciint: int_addr=0x%lx, *int_addr=0x%lx, "
572 "pcibr_int_bit=0x%x\n", int_addr,
573 pcireg_intr_addr_get(pcibr_soft, pcibr_int_bit),
577 s = pcibr_lock(pcibr_soft);
578 pcireg_intr_enable_bit_set(pcibr_soft, pcibr_int_bits);
579 pcireg_tflush_get(pcibr_soft);
580 pcibr_unlock(pcibr_soft, s);
587 pcibr_intr_disconnect(pcibr_intr_t pcibr_intr)
589 pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft;
590 unsigned pcibr_int_bits = pcibr_intr->bi_ibits;
591 unsigned pcibr_int_bit;
592 pcibr_intr_wrap_t intr_wrap;
595 /* Stop calling the function. Now.
597 *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED;
598 pcibr_intr->bi_func = 0;
599 pcibr_intr->bi_arg = 0;
601 * For each PCI interrupt line requested, figure
602 * out which Bridge PCI Interrupt Line it maps
603 * to, and disconnect the interrupt.
606 /* don't disable interrupts for lines that
607 * are shared between devices.
609 for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
610 if ((pcibr_int_bits & (1 << pcibr_int_bit)) &&
611 (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared))
612 pcibr_int_bits &= ~(1 << pcibr_int_bit);
616 s = pcibr_lock(pcibr_soft);
617 pcireg_intr_enable_bit_clr(pcibr_soft, pcibr_int_bits);
618 pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */
619 pcibr_unlock(pcibr_soft, s);
621 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
622 "pcibr_intr_disconnect: disabled int_bits=0x%x\n",
625 for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
626 if (pcibr_int_bits & (1 << pcibr_int_bit)) {
628 /* if the interrupt line is now shared,
629 * do not disconnect it.
631 if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
634 xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr);
635 pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0;
637 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
638 "pcibr_intr_disconnect: disconnect int_bits=0x%x\n",
641 /* if we are sharing the interrupt line,
642 * connect us up; this closes the hole
643 * where the another pcibr_intr_alloc()
644 * was in progress as we disconnected.
646 intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
647 if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
650 pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit =
651 ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit);
652 xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr,
654 (intr_arg_t) intr_wrap,
655 (xtalk_intr_setfunc_t) pcibr_setpciint,
656 &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit);
658 PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
659 "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n",
666 pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr)
668 pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft;
669 unsigned pcibr_int_bits = pcibr_intr->bi_ibits;
670 unsigned pcibr_int_bit;
672 for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
673 if (pcibr_int_bits & (1 << pcibr_int_bit))
674 return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr);
678 /* =====================================================================
682 pcibr_clearwidint(pcibr_soft_t pcibr_soft)
684 pcireg_intr_dst_set(pcibr_soft, 0);
689 pcibr_setwidint(xtalk_intr_t intr)
691 xwidgetnum_t targ = xtalk_intr_target_get(intr);
692 iopaddr_t addr = xtalk_intr_addr_get(intr);
693 xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr);
695 pcibr_soft_t bridge = (pcibr_soft_t)xtalk_intr_sfarg_get(intr);
697 pcireg_intr_dst_target_id_set(bridge, targ);
698 pcireg_intr_dst_addr_set(bridge, addr);
699 pcireg_intr_host_err_set(bridge, vect);