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

📄 pcibr_intr.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */#include <linux/types.h>#include <linux/slab.h>#include <linux/module.h>#include <asm/sn/sgi.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/addrs.h>#include <asm/sn/arch.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.h>#include <asm/sn/xtalk/xwidget.h>#include <asm/sn/pci/bridge.h>#include <asm/sn/pci/pciio.h>#include <asm/sn/pci/pcibr.h>#include <asm/sn/pci/pcibr_private.h>#include <asm/sn/pci/pci_defs.h>#include <asm/sn/prio.h>#include <asm/sn/xtalk/xbow.h>#include <asm/sn/ioc3.h>#include <asm/sn/io.h>#include <asm/sn/sn_private.h>#ifdef __ia64inline intcompare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr){	/* FIXME - compare_and_swap_ptr NOT ATOMIC */	if (*location == old_ptr) {		*location = new_ptr;		return(1);	}	else		return(0);}#endifunsigned		pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots);pcibr_intr_t            pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t);void                    pcibr_intr_free(pcibr_intr_t);void              pcibr_setpciint(xtalk_intr_t);int                     pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t);void                    pcibr_intr_disconnect(pcibr_intr_t);vertex_hdl_t            pcibr_intr_cpu_get(pcibr_intr_t);void                    pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);void                    pcibr_intr_func(intr_arg_t);extern pcibr_info_t      pcibr_info_get(vertex_hdl_t);/* ===================================================================== *    INTERRUPT MANAGEMENT */unsignedpcibr_intr_bits(pciio_info_t info,		pciio_intr_line_t lines, int nslots){    pciio_slot_t            slot = PCIBR_INFO_SLOT_GET_INT(info);    unsigned		    bbits = 0;    /*     * Currently favored mapping from PCI     * slot number and INTA/B/C/D to Bridge     * PCI Interrupt Bit Number:     *     *     SLOT     A B C D     *      0       0 4 0 4     *      1       1 5 1 5     *      2       2 6 2 6     *      3       3 7 3 7     *      4       4 0 4 0     *      5       5 1 5 1     *      6       6 2 6 2     *      7       7 3 7 3     */    if (slot < nslots) {	if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C))	    bbits |= 1 << slot;	if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D))	    bbits |= 1 << (slot ^ 4);    }    return bbits;}/* *	Get the next wrapper pointer queued in the interrupt circular buffer. */pcibr_intr_wrap_tpcibr_wrap_get(pcibr_intr_cbuf_t cbuf){    pcibr_intr_wrap_t	wrap;	if (cbuf->ib_in == cbuf->ib_out)	    panic( "pcibr intr circular buffer empty, cbuf=0x%p, ib_in=ib_out=%d\n",		(void *)cbuf, cbuf->ib_out);	wrap = cbuf->ib_cbuf[cbuf->ib_out++];	cbuf->ib_out = cbuf->ib_out % IBUFSIZE;	return(wrap);}/*  *	Queue a wrapper pointer in the interrupt circular buffer. */voidpcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf){	int	in;	/*	 * Multiple CPUs could be executing this code simultaneously	 * if a handler has registered multiple interrupt lines and	 * the interrupts are directed to different CPUs.	 */	spin_lock(&cbuf->ib_lock);	in = (cbuf->ib_in + 1) % IBUFSIZE;	if (in == cbuf->ib_out) 	    panic( "pcibr intr circular buffer full, cbuf=0x%p, ib_in=%d\n",		(void *)cbuf, cbuf->ib_in);	cbuf->ib_cbuf[cbuf->ib_in] = wrap;	cbuf->ib_in = in;	spin_unlock(&cbuf->ib_lock);	return;}/* *	On SN systems there is a race condition between a PIO read response *	and DMA's.  In rare cases, the read response may beat the DMA, causing *	the driver to think that data in memory is complete and meaningful. *	This code eliminates that race. *	This routine is called by the PIO read routines after doing the read. *	This routine then forces a fake interrupt on another line, which *	is logically associated with the slot that the PIO is addressed to. *	(see sn_dma_flush_init() ) *	It then spins while watching the memory location that the interrupt *	is targetted to.  When the interrupt response arrives, we are sure *	that the DMA has landed in memory and it is safe for the driver *	to proceed. */extern struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS];voidsn_dma_flush(unsigned long addr) {	nasid_t nasid;	int wid_num;	volatile struct sn_flush_device_list *p;	int i,j;	int bwin;	unsigned long flags;	nasid = NASID_GET(addr);	wid_num = SWIN_WIDGETNUM(addr);	bwin = BWIN_WINDOWNUM(addr);	if (flush_nasid_list[nasid].widget_p == NULL) return;	if (bwin > 0) {		bwin--;		switch (bwin) {			case 0:				wid_num = ((flush_nasid_list[nasid].iio_itte1) >> 8) & 0xf;				break;			case 1:				wid_num = ((flush_nasid_list[nasid].iio_itte2) >> 8) & 0xf;				break;			case 2: 				wid_num = ((flush_nasid_list[nasid].iio_itte3) >> 8) & 0xf;				break;			case 3: 				wid_num = ((flush_nasid_list[nasid].iio_itte4) >> 8) & 0xf;				break;			case 4: 				wid_num = ((flush_nasid_list[nasid].iio_itte5) >> 8) & 0xf;				break;			case 5: 				wid_num = ((flush_nasid_list[nasid].iio_itte6) >> 8) & 0xf;				break;			case 6: 				wid_num = ((flush_nasid_list[nasid].iio_itte7) >> 8) & 0xf;				break;		}	}	if (flush_nasid_list[nasid].widget_p == NULL) return;	if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) return;	p = &flush_nasid_list[nasid].widget_p[wid_num][0];	// find a matching BAR	for (i=0; i<DEV_PER_WIDGET;i++) {		for (j=0; j<PCI_ROM_RESOURCE;j++) {			if (p->bar_list[j].start == 0) break;			if (addr >= p->bar_list[j].start && addr <= p->bar_list[j].end) break;		}		if (j < PCI_ROM_RESOURCE && p->bar_list[j].start != 0) break;		p++;	}	// if no matching BAR, return without doing anything.	if (i == DEV_PER_WIDGET) return;	spin_lock_irqsave(&p->flush_lock, flags);	p->flush_addr = 0;	// force an interrupt.	*(bridgereg_t *)(p->force_int_addr) = 1;	// wait for the interrupt to come back.	while (p->flush_addr != 0x10f);	// okay, everything is synched up.	spin_unlock_irqrestore(&p->flush_lock, flags);	return;}EXPORT_SYMBOL(sn_dma_flush);/* *	There are end cases where a deadlock can occur if interrupt  *	processing completes and the Bridge b_int_status bit is still set. * *	One scenerio is if a second PCI interrupt occurs within 60ns of *	the previous interrupt being cleared. In this case the Bridge *	does not detect the transition, the Bridge b_int_status bit *	remains set, and because no transition was detected no interrupt *	packet is sent to the Hub/Heart. * *	A second scenerio is possible when a b_int_status bit is being *	shared by multiple devices: *						Device #1 generates interrupt *						Bridge b_int_status bit set *						Device #2 generates interrupt *		interrupt processing begins *		  ISR for device #1 runs and *			clears interrupt *						Device #1 generates interrupt *		  ISR for device #2 runs and *			clears interrupt *						(b_int_status bit still set) *		interrupt processing completes *		   *	Interrupt processing is now complete, but an interrupt is still *	outstanding for Device #1. But because there was no transition of *	the b_int_status bit, no interrupt packet will be generated and *	a deadlock will occur. * *	To avoid these deadlock situations, this function is used *	to check if a specific Bridge b_int_status bit is set, and if so, *	cause the setting of the corresponding interrupt bit. * *	On a XBridge (SN1) and PIC (SN2), we do this by writing the appropriate Bridge Force  *	Interrupt register. */voidpcibr_force_interrupt(pcibr_intr_t intr){	unsigned	bit;	unsigned	bits;	pcibr_soft_t    pcibr_soft = intr->bi_soft;	bridge_t       *bridge = pcibr_soft->bs_base;	bits = intr->bi_ibits;	for (bit = 0; bit < 8; bit++) {		if (bits & (1 << bit)) {			PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl,		    		"pcibr_force_interrupt: bit=0x%x\n", bit));			if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {	    			bridge->b_force_pin[bit].intr = 1;			}		}	}}/*ARGSUSED */pcibr_intr_tpcibr_intr_alloc(vertex_hdl_t pconn_vhdl,		 device_desc_t dev_desc,		 pciio_intr_line_t lines,		 vertex_hdl_t owner_dev){    pcibr_info_t            pcibr_info = pcibr_info_get(pconn_vhdl);    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;    vertex_hdl_t            xconn_vhdl = pcibr_soft->bs_conn;    bridge_t               *bridge = pcibr_soft->bs_base;    int                     is_threaded = 0;    xtalk_intr_t           *xtalk_intr_p;    pcibr_intr_t           *pcibr_intr_p;    pcibr_intr_list_t      *intr_list_p;    unsigned                pcibr_int_bits;    unsigned                pcibr_int_bit;    xtalk_intr_t            xtalk_intr = (xtalk_intr_t)0;    hub_intr_t		    hub_intr;    pcibr_intr_t            pcibr_intr;    pcibr_intr_list_t       intr_entry;    pcibr_intr_list_t       intr_list;    bridgereg_t             int_dev;    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,    		"pcibr_intr_alloc: %s%s%s%s%s\n",		!(lines & 15) ? " No INTs?" : "",		lines & 1 ? " INTA" : "",		lines & 2 ? " INTB" : "",		lines & 4 ? " INTC" : "",		lines & 8 ? " INTD" : ""));    NEW(pcibr_intr);    if (!pcibr_intr)	return NULL;    pcibr_intr->bi_dev = pconn_vhdl;    pcibr_intr->bi_lines = lines;    pcibr_intr->bi_soft = pcibr_soft;    pcibr_intr->bi_ibits = 0;		/* bits will be added below */    pcibr_intr->bi_func = 0;            /* unset until connect */    pcibr_intr->bi_arg = 0;             /* unset until connect */    pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD;    pcibr_intr->bi_mustruncpu = CPU_NONE;    pcibr_intr->bi_ibuf.ib_in = 0;    pcibr_intr->bi_ibuf.ib_out = 0;    spin_lock_init(&pcibr_intr->bi_ibuf.ib_lock);    pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines, 		PCIBR_NUM_SLOTS(pcibr_soft));    /*     * 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.     */    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,		"pcibr_intr_alloc: pcibr_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)) {	    xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;	    xtalk_intr = *xtalk_intr_p;

⌨️ 快捷键说明

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