pcibr_intr.c

来自「Linux Kernel 2.6.9 for OMAP1710」· 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 + -
显示快捷键?