📄 pcibr_intr.c
字号:
"bridge intr bit %d clears my wrb\n", pcibr_int_bit)); } else { /* someone else got one allocated first; * free the one we just created, and * retrieve the one they allocated. */ xtalk_intr_free(xtalk_intr); xtalk_intr = *xtalk_intr_p;#if PARANOID /* once xtalk_intr is set, we never clear it, * so if the CAS fails above, this condition * can "never happen" ... */ if (!xtalk_intr) { printk(KERN_ALERT "pcibr_intr_alloc %v: unable to set xtalk interrupt resources", xconn_vhdl); /* yes, we leak resources here. */ return 0; }#endif } } pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; NEW(intr_entry); intr_entry->il_next = NULL; intr_entry->il_intr = pcibr_intr; intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); 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%x\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. */ DEL(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. */ DEL(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; } } }#if DEBUG && INTR_DEBUG printk("%v pcibr_intr_alloc complete\n", pconn_vhdl);#endif hub_intr = (hub_intr_t)xtalk_intr; pcibr_intr->bi_irq = hub_intr->i_bit; pcibr_intr->bi_cpu = hub_intr->i_cpuid; 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)) { bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t int_dev; xtalk_intr_free(*xtalk_intrp); *xtalk_intrp = 0; /* Clear the PCI device interrupt to bridge interrupt pin * mapping. */ int_dev = bridge->b_int_device; int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); bridge->b_int_device = int_dev; } } } DEL(pcibr_intr);}voidpcibr_setpciint(xtalk_intr_t xtalk_intr){ iopaddr_t addr; xtalk_intr_vector_t vect; devfs_handle_t vhdl; bridge_t *bridge; addr = xtalk_intr_addr_get(xtalk_intr); vect = xtalk_intr_vector_get(xtalk_intr); vhdl = xtalk_intr_dev_get(xtalk_intr); bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0); if (is_pic(bridge)) { picreg_t *int_addr; int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr); *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) | (PIC_INT_ADDR_HOST & addr)); } else { bridgereg_t *int_addr; int_addr = (bridgereg_t *)xtalk_intr_sfarg_get(xtalk_intr); *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | (BRIDGE_INT_ADDR_FLD & vect)); }}/*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; bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; uint64_t int_enable; 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%x\n", pcibr_intr)); 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. */ if (IS_PIC_SOFT(pcibr_soft)) int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]); else int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr); xtalk_intr_connect(xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t) pcibr_setpciint, (void *)int_addr); 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%x, *int_addr=0x%x, " "pcibr_int_bit=0x%x\n", int_addr, (is_pic(bridge) ? *(picreg_t *)int_addr : *(bridgereg_t *)int_addr), pcibr_int_bit)); } /* PIC WAR. PV# 854697 * On PIC we must write 64-bit MMRs with 64-bit stores */ s = pcibr_lock(pcibr_soft); if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { int_enable = bridge->p_int_enable_64; int_enable |= pcibr_int_bits; bridge->p_int_enable_64 = int_enable; } else { bridgereg_t int_enable; int_enable = bridge->b_int_enable; int_enable |= pcibr_int_bits; bridge->b_int_enable = int_enable; } bridge->b_wid_tflush; /* wait until Bridge PIO complete */ 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; bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; pcibr_intr_wrap_t intr_wrap; uint64_t int_enable; 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; /* PIC WAR. PV# 854697 * On PIC we must write 64-bit MMRs with 64-bit stores */ s = pcibr_lock(pcibr_soft); if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { int_enable = bridge->p_int_enable_64; int_enable &= ~pcibr_int_bits; bridge->p_int_enable_64 = int_enable; } else { int_enable = (uint64_t)bridge->b_int_enable; int_enable &= ~pcibr_int_bits; bridge->b_int_enable = (bridgereg_t)int_enable; } bridge->b_wid_tflush; /* 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)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -