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

📄 pcibr_intr.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#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)) {#if DEBUG && INTR_DEBUG		    printk("%s: cleared a handler from bit %d\n",			    pcibr_soft->bs_name, pcibr_int_bit);#endif		}	    /* 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_addr_get(xtalk_intr);    xtalk_intr_vector_t     vect = xtalk_intr_vector_get(xtalk_intr);    bridgereg_t            *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){    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;    bridgereg_t             b_int_enable;    unsigned long           s;    if (pcibr_intr == NULL)	return -1;#if DEBUG && INTR_DEBUG    printk("%v: pcibr_intr_connect\n",	    pcibr_intr->bi_dev);#endif    *((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)) {	    xtalk_intr_t            xtalk_intr;	    xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;	    /*	     * 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.	     */	    xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint,			       (void *)&(bridge->b_int_addr[pcibr_int_bit].addr));	    pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1;#if DEBUG && INTR_DEBUG	    printk("%v bridge bit %d wrapper connected\n",		    pcibr_intr->bi_dev, pcibr_int_bit);#endif	}    s = pcibr_lock(pcibr_soft);    b_int_enable = bridge->b_int_enable;    b_int_enable |= pcibr_int_bits;    bridge->b_int_enable = b_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;    bridgereg_t             b_int_enable;    unsigned long           s;    /* Stop calling the function. Now.     */    *((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 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);    b_int_enable = bridge->b_int_enable;    b_int_enable &= ~pcibr_int_bits;    bridge->b_int_enable = b_int_enable;    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */    pcibr_unlock(pcibr_soft, s);    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;#if DEBUG && INTR_DEBUG	    printk("%s: xtalk disconnect done for Bridge bit %d\n",		pcibr_soft->bs_name, pcibr_int_bit);#endif	    /* 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.	     */	    if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)		continue;	    xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr,			       (xtalk_intr_setfunc_t)pcibr_setpciint,			       (void *) &(bridge->b_int_addr[pcibr_int_bit].addr));	}}/*ARGSUSED */devfs_handle_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(bridge_t *bridge){    bridge->b_wid_int_upper = 0;    bridge->b_wid_int_lower = 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);    widgetreg_t		    NEW_b_wid_int_upper, NEW_b_wid_int_lower;    widgetreg_t		    OLD_b_wid_int_upper, OLD_b_wid_int_lower;    bridge_t               *bridge = (bridge_t *)xtalk_intr_sfarg_get(intr);    NEW_b_wid_int_upper = ( (0x000F0000 & (targ << 16)) |			       XTALK_ADDR_TO_UPPER(addr));    NEW_b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);    OLD_b_wid_int_upper = bridge->b_wid_int_upper;    OLD_b_wid_int_lower = bridge->b_wid_int_lower;    /* Verify that all interrupts from this Bridge are using a single PI */    if ((OLD_b_wid_int_upper != 0) && (OLD_b_wid_int_lower != 0)) {	/*	 * Once set, these registers shouldn't change; they should	 * be set multiple times with the same values.	 *	 * If we're attempting to change these registers, it means	 * that our heuristics for allocating interrupts in a way	 * appropriate for IP35 have failed, and the admin needs to	 * explicitly direct some interrupts (or we need to make the	 * heuristics more clever).	 *	 * In practice, we hope this doesn't happen very often, if	 * at all.	 */	if ((OLD_b_wid_int_upper != NEW_b_wid_int_upper) ||	    (OLD_b_wid_int_lower != NEW_b_wid_int_lower)) {		printk(KERN_WARNING  "Interrupt allocation is too complex.\n");		printk(KERN_WARNING  "Use explicit administrative interrupt targetting.\n");		printk(KERN_WARNING  "bridge=0x%lx targ=0x%x\n", (unsigned long)bridge, targ);		printk(KERN_WARNING  "NEW=0x%x/0x%x  OLD=0x%x/0x%x\n",			NEW_b_wid_int_upper, NEW_b_wid_int_lower,			OLD_b_wid_int_upper, OLD_b_wid_int_lower);		PRINT_PANIC("PCI Bridge interrupt targetting error\n");	}    }    bridge->b_wid_int_upper = NEW_b_wid_int_upper;    bridge->b_wid_int_lower = NEW_b_wid_int_lower;    bridge->b_int_host_err = vect;}/* * pcibr_intr_preset: called during mlreset time * if the platform specific code needs to route * one of the Bridge's xtalk interrupts before the * xtalk infrastructure is available. */voidpcibr_xintr_preset(void *which_widget,		   int which_widget_intr,		   xwidgetnum_t targ,		   iopaddr_t addr,		   xtalk_intr_vector_t vect){    bridge_t               *bridge = (bridge_t *) which_widget;    if (which_widget_intr == -1) {	/* bridge widget error interrupt */	bridge->b_wid_int_upper = ( (0x000F0000 & (targ << 16)) |				   XTALK_ADDR_TO_UPPER(addr));	bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);	bridge->b_int_host_err = vect;	/* turn on all interrupts except	 * the PCI interrupt requests,	 * at least at heart.	 */	bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK;    } else {	/* routing a PCI device interrupt.	 * targ and low 38 bits of addr must	 * be the same as the already set	 * value for the widget error interrupt.	 */	bridge->b_int_addr[which_widget_intr].addr =	    ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |	     (BRIDGE_INT_ADDR_FLD & vect));	/*	 * now bridge can let it through;	 * NB: still should be blocked at	 * xtalk provider end, until the service	 * function is set.	 */	bridge->b_int_enable |= 1 << vect;    }    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */}/* * pcibr_intr_func() * * This is the pcibr interrupt "wrapper" function that is called, * in interrupt context, to initiate the interrupt handler(s) registered * (via pcibr_intr_alloc/connect) for the occuring interrupt. Non-threaded  * handlers will be called directly, and threaded handlers will have their  * thread woken up. */voidpcibr_intr_func(intr_arg_t arg){    pcibr_intr_wrap_t       wrap = (pcibr_intr_wrap_t) arg;    reg_p                   wrbf;    pcibr_intr_t            intr;    pcibr_intr_list_t       list;    int                     clearit;    int			    do_nonthreaded = 1;    int			    is_threaded = 0;    int			    x = 0;	/*	 * If any handler is still running from a previous interrupt	 * just return. If there's a need to call the handler(s) again,	 * another interrupt will be generated either by the device or by	 * pcibr_force_interrupt().	 */	if (wrap->iw_hdlrcnt) {		return;	}    /*     * Call all interrupt handlers registered.     * First, the pcibr_intrd threads for any threaded handlers will be     * awoken, then any non-threaded handlers will be called sequentially.     */		clearit = 1;	while (do_nonthreaded) {	    for (list = wrap->iw_list; list != NULL; list = list->il_next) {		if ((intr = list->il_intr) &&		    (intr->bi_flags & PCIIO_INTR_CONNECTED)) {		/*		 * This device may have initiated write		 * requests since the bridge last saw		 * an edge on this interrupt input; flushing		 * the buffer prior to invoking the handler		 * should help but may not be sufficient if we 		 * get more requests after the flush, followed		 * by the card deciding it wants service, before		 * the interrupt handler checks to see if things need		 * to be done.		 *		 * There is a similar race condition if		 * an interrupt handler loops around and		 * notices further service is required.		 * Perhaps we need to have an explicit		 * call that interrupt handlers need to		 * do between noticing that DMA to memory		 * has completed, but before observing the		 * contents of memory?		 */			if ((do_nonthreaded) && (!is_threaded)) {			/* Non-threaded. 			 * Call the interrupt handler at interrupt level			 */			/* Only need to flush write buffers if sharing */			if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) {			    if ((x = *wrbf))	/* write request buffer flush */#ifdef SUPPORT_PRINTING_V_FORMAT				printk(KERN_ALERT  "pcibr_intr_func %v: \n"				    "write buffer flush failed, wrbf=0x%x\n", 				    list->il_intr->bi_dev, wrbf);#else				printk(KERN_ALERT  "pcibr_intr_func %p: \n"				    "write buffer flush failed, wrbf=0x%lx\n", 				    (void *)list->il_intr->bi_dev, (long) wrbf);#endif			}		    }		    clearit = 0;		}	    }		do_nonthreaded = 0;		/*		 * If the non-threaded handler was the last to complete,		 * (i.e., no threaded handlers still running) force an		 * interrupt to avoid a potential deadlock situation.		 */		if (wrap->iw_hdlrcnt == 0) {			pcibr_force_interrupt(wrap);		}	}	/* If there were no handlers,	 * disable the interrupt and return.	 * It will get enabled again after	 * a handler is connected.	 * If we don't do this, we would	 * sit here and spin through the	 * list forever.	 */	if (clearit) {	    pcibr_soft_t            pcibr_soft = wrap->iw_soft;	    bridge_t               *bridge = pcibr_soft->bs_base;	    bridgereg_t             b_int_enable;	    bridgereg_t		    mask = 1 << wrap->iw_intr;	    unsigned long           s;	    s = pcibr_lock(pcibr_soft);	    b_int_enable = bridge->b_int_enable;	    b_int_enable &= ~mask;	    bridge->b_int_enable = b_int_enable;	    bridge->b_wid_tflush;	/* wait until Bridge PIO complete */	    pcibr_unlock(pcibr_soft, s);	    return;	}}

⌨️ 快捷键说明

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