⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcibr_intr.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	    if (xtalk_intr == NULL) {		/*		 * This xtalk_intr_alloc is constrained for two reasons:		 * 1) Normal interrupts and error interrupts need to be delivered		 *    through a single xtalk target widget so that there aren't any		 *    ordering problems with DMA, completion interrupts, and error		 *    interrupts. (Use of xconn_vhdl forces this.)		 *		 * 2) On SN1, addressing constraints on SN1 and Bridge force		 *    us to use a single PI number for all interrupts from a		 *    single Bridge. (SN1-specific code forces this).		 */		/*		 * All code dealing with threaded PCI interrupt handlers		 * is located at the pcibr level. Because of this,		 * we always want the lower layers (hub/heart_intr_alloc, 		 * intr_level_connect) to treat us as non-threaded so we		 * don't set up a duplicate threaded environment. We make		 * this happen by calling a special xtalk interface.		 */		xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, 			owner_dev);		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,			    "pcibr_intr_alloc: xtalk_intr=0x%x\n", xtalk_intr));		/* both an assert and a runtime check on this:		 * we need to check in non-DEBUG kernels, and		 * the ASSERT gets us more information when		 * we use DEBUG kernels.		 */		ASSERT(xtalk_intr != NULL);		if (xtalk_intr == NULL) {		    /* it is quite possible that our		     * xtalk_intr_alloc failed because		     * someone else got there first,		     * and we can find their results		     * in xtalk_intr_p.		     */		    if (!*xtalk_intr_p) {#ifdef SUPPORT_PRINTING_V_FORMAT			printk(KERN_ALERT  				"pcibr_intr_alloc %v: unable to get xtalk interrupt resources",				xconn_vhdl);#else			printk(KERN_ALERT  				"pcibr_intr_alloc 0x%p: unable to get xtalk interrupt resources",				(void *)xconn_vhdl);#endif			/* yes, we leak resources here. */			return 0;		    }		} else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) {		    /*		     * now tell the bridge which slot is		     * using this interrupt line.		     */		    int_dev = bridge->b_int_device;		    int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit);		    int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit);		    bridge->b_int_device = int_dev;	/* XXXMP */		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,		    		"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;    vertex_hdl_t	 vhdl;    bridge_t		*bridge;    picreg_t	*int_addr;    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);    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));}/*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,			 *(picreg_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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -