pcibr_intr.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 701 行 · 第 1/2 页
C
701 行
if ( !intr_entry ) { printk(KERN_ALERT "pcibr_intr_alloc %s: " "unable to get memory", pcibr_soft->bs_name); return 0; } memset(intr_entry, 0, sizeof (*(intr_entry))); intr_entry->il_next = NULL; intr_entry->il_intr = pcibr_intr; intr_entry->il_soft = pcibr_soft; intr_entry->il_slot = pciio_slot; intr_list_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "Bridge bit 0x%x wrap=0x%lx\n", pcibr_int_bit, &(pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap))); if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* we are the first interrupt on this bridge bit. */ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "INT 0x%x (bridge bit %d) allocated [FIRST]\n", pcibr_int_bits, pcibr_int_bit)); continue; } intr_list = *intr_list_p; pcibr_intr_p = &intr_list->il_intr; if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { /* first entry on list was erased, * and we replaced it, so we * don't need our intr_entry. */ kfree(intr_entry); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "INT 0x%x (bridge bit %d) replaces erased first\n", pcibr_int_bits, pcibr_int_bit)); continue; } intr_list_p = &intr_list->il_next; if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* we are the new second interrupt on this bit. */ pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "INT 0x%x (bridge bit %d) is new SECOND\n", pcibr_int_bits, pcibr_int_bit)); continue; } while (1) { pcibr_intr_p = &intr_list->il_intr; if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { /* an entry on list was erased, * and we replaced it, so we * don't need our intr_entry. */ kfree(intr_entry); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "INT 0x%x (bridge bit %d) replaces erase Nth\n", pcibr_int_bits, pcibr_int_bit)); break; } intr_list_p = &intr_list->il_next; if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* entry appended to share list */ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "INT 0x%x (bridge bit %d) is new Nth\n", pcibr_int_bits, pcibr_int_bit)); break; } /* step to next record in chain */ intr_list = *intr_list_p; } } } hub_intr = (hub_intr_t)xtalk_intr; pcibr_intr->bi_irq = hub_intr->i_bit; pcibr_intr->bi_cpu = hub_intr->i_cpuid; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "pcibr_intr_alloc complete: pcibr_intr=0x%lx\n", pcibr_intr)); return pcibr_intr;}/*ARGSUSED */voidpcibr_intr_free(pcibr_intr_t pcibr_intr){ unsigned pcibr_int_bits = pcibr_intr->bi_ibits; pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; unsigned pcibr_int_bit; pcibr_intr_list_t intr_list; int intr_shared; xtalk_intr_t *xtalk_intrp; for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { if (pcibr_int_bits & (1 << pcibr_int_bit)) { for (intr_list = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; intr_list != NULL; intr_list = intr_list->il_next) if (compare_and_swap_ptr((void **) &intr_list->il_intr, pcibr_intr, NULL)) { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_free: cleared hdlr from bit 0x%x\n", pcibr_int_bit)); } /* If this interrupt line is not being shared between multiple * devices release the xtalk interrupt resources. */ intr_shared = pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; if ((!intr_shared) && (*xtalk_intrp)) { xtalk_intr_free(*xtalk_intrp); *xtalk_intrp = 0; /* Clear the PCI device interrupt to bridge interrupt pin * mapping. */ pcireg_intr_device_bit_clr(pcibr_soft, BRIDGE_INT_DEV_MASK(pcibr_int_bit)); } } } kfree(pcibr_intr);}voidpcibr_setpciint(xtalk_intr_t xtalk_intr){ iopaddr_t addr; xtalk_intr_vector_t vect; vertex_hdl_t vhdl; int bus_num; int pcibr_int_bit; void *bridge; addr = xtalk_intr_addr_get(xtalk_intr); vect = xtalk_intr_vector_get(xtalk_intr); vhdl = xtalk_intr_dev_get(xtalk_intr); /* bus and int_bits are stored in sfarg, bus bit3, int_bits bit2:0 */ pcibr_int_bit = *((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x7; bus_num = ((*((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x8) >> 3); bridge = pcibr_bridge_ptr_get(vhdl, bus_num); pcireg_bridge_intr_addr_vect_set(bridge, pcibr_int_bit, vect); pcireg_bridge_intr_addr_addr_set(bridge, pcibr_int_bit, addr);}/*ARGSUSED */intpcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg){ pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; unsigned long s; if (pcibr_intr == NULL) return -1; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_connect: intr_func=0x%lx, intr_arg=0x%lx\n", intr_func, intr_arg)); pcibr_intr->bi_func = intr_func; pcibr_intr->bi_arg = intr_arg; *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; /* * For each PCI interrupt line requested, figure * out which Bridge PCI Interrupt Line it maps * to, and make sure there are xtalk resources * allocated for it. */ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) { pcibr_intr_wrap_t intr_wrap; xtalk_intr_t xtalk_intr; void *int_addr; xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; /* * If this interrupt line is being shared and the connect has * already been done, no need to do it again. */ if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) continue; /* * Use the pcibr wrapper function to handle all Bridge interrupts * regardless of whether the interrupt line is shared or not. */ int_addr = pcireg_intr_addr_addr(pcibr_soft, pcibr_int_bit); pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit = ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit); xtalk_intr_connect(xtalk_intr, NULL, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t) pcibr_setpciint, &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit); pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_setpciint: int_addr=0x%lx, *int_addr=0x%lx, " "pcibr_int_bit=0x%x\n", int_addr, pcireg_intr_addr_get(pcibr_soft, pcibr_int_bit), pcibr_int_bit)); } s = pcibr_lock(pcibr_soft); pcireg_intr_enable_bit_set(pcibr_soft, pcibr_int_bits); pcireg_tflush_get(pcibr_soft); pcibr_unlock(pcibr_soft, s); return 0;}/*ARGSUSED */voidpcibr_intr_disconnect(pcibr_intr_t pcibr_intr){ pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; pcibr_intr_wrap_t intr_wrap; unsigned long s; /* Stop calling the function. Now. */ *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; pcibr_intr->bi_func = 0; pcibr_intr->bi_arg = 0; /* * For each PCI interrupt line requested, figure * out which Bridge PCI Interrupt Line it maps * to, and disconnect the interrupt. */ /* don't disable interrupts for lines that * are shared between devices. */ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if ((pcibr_int_bits & (1 << pcibr_int_bit)) && (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) pcibr_int_bits &= ~(1 << pcibr_int_bit); if (!pcibr_int_bits) return; s = pcibr_lock(pcibr_soft); pcireg_intr_enable_bit_clr(pcibr_soft, pcibr_int_bits); pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ pcibr_unlock(pcibr_soft, s); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_disconnect: disabled int_bits=0x%x\n", pcibr_int_bits)); for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) { /* if the interrupt line is now shared, * do not disconnect it. */ if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_disconnect: disconnect int_bits=0x%x\n", pcibr_int_bits)); /* if we are sharing the interrupt line, * connect us up; this closes the hole * where the another pcibr_intr_alloc() * was in progress as we disconnected. */ intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit = ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit); xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, NULL, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t) pcibr_setpciint, &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n", pcibr_int_bit)); }}/*ARGSUSED */vertex_hdl_tpcibr_intr_cpu_get(pcibr_intr_t pcibr_intr){ pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); return 0;}/* ===================================================================== * INTERRUPT HANDLING */voidpcibr_clearwidint(pcibr_soft_t pcibr_soft){ pcireg_intr_dst_set(pcibr_soft, 0);}voidpcibr_setwidint(xtalk_intr_t intr){ xwidgetnum_t targ = xtalk_intr_target_get(intr); iopaddr_t addr = xtalk_intr_addr_get(intr); xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); pcibr_soft_t bridge = (pcibr_soft_t)xtalk_intr_sfarg_get(intr); pcireg_intr_dst_target_id_set(bridge, targ); pcireg_intr_dst_addr_set(bridge, addr); pcireg_intr_host_err_set(bridge, vect);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?