pcibr_dvr.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,108 行 · 第 1/5 页

C
2,108
字号
/* * 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/module.h>#include <linux/string.h>#include <linux/interrupt.h>#include <asm/sn/sgi.h>#include <asm/sn/sn_sal.h>#include <asm/sn/iograph.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/sn_private.h>/* * global variables to toggle the different levels of pcibr debugging.   *   -pcibr_debug_mask is the mask of the different types of debugging *    you want to enable.  See sys/PCI/pcibr_private.h  *   -pcibr_debug_module is the module you want to trace.  By default *    all modules are trace.  The format is something like "001c10". *   -pcibr_debug_widget is the widget you want to trace.  For TIO  *    based bricks use the corelet id. *   -pcibr_debug_slot is the pci slot you want to trace. */uint32_t   	  pcibr_debug_mask;			/* 0x00000000 to disable */static char      *pcibr_debug_module = "all";		/* 'all' for all modules */static int	   pcibr_debug_widget = -1;		/* '-1' for all widgets  */static int	   pcibr_debug_slot = -1;		/* '-1' for all slots    */#if PCIBR_SOFT_LISTpcibr_list_p            pcibr_list;#endifextern char *pci_space[];/* ===================================================================== *    Function Table of Contents * *      The order of functions in this file has stopped *      making much sense. We might want to take a look *      at it some time and bring back some sanity, or *      perhaps bust this file into smaller chunks. */extern void		 do_pcibr_rrb_free_all(pcibr_soft_t, pciio_slot_t);extern void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int);extern void		 pcibr_rrb_alloc_more(pcibr_soft_t pcibr_soft, int slot,							int vchan, int more_rrbs);extern int  		 pcibr_wrb_flush(vertex_hdl_t);extern int               pcibr_rrb_alloc(vertex_hdl_t, int *, int *);void            	 pcibr_rrb_alloc_more(pcibr_soft_t, int, int, int);extern void              pcibr_rrb_flush(vertex_hdl_t);static int                pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, uint64_t);void                     pcibr_release_device(pcibr_soft_t, pciio_slot_t, uint64_t);extern iopaddr_t         pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t,                                              pciio_space_t, int, int, int);extern int		 hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, 						 uint buflen);int			 pcibr_detach(vertex_hdl_t);void			 pcibr_directmap_init(pcibr_soft_t);int			 pcibr_pcix_rbars_calc(pcibr_soft_t);extern int               pcibr_ate_alloc(pcibr_soft_t, int, struct resource *);extern void              pcibr_ate_free(pcibr_soft_t, int, int, struct resource *);extern pciio_dmamap_t	 get_free_pciio_dmamap(vertex_hdl_t);extern void		 free_pciio_dmamap(pcibr_dmamap_t);extern int 		 pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl);extern void 		ate_write(pcibr_soft_t, int, int, bridge_ate_t);pcibr_info_t      pcibr_info_get(vertex_hdl_t);static iopaddr_t         pcibr_addr_pci_to_xio(vertex_hdl_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned);pcibr_piomap_t          pcibr_piomap_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);void                    pcibr_piomap_free(pcibr_piomap_t);caddr_t                 pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t);void                    pcibr_piomap_done(pcibr_piomap_t);caddr_t                 pcibr_piotrans_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);iopaddr_t               pcibr_piospace_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, size_t, size_t);void                    pcibr_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t);static iopaddr_t         pcibr_flags_to_d64(unsigned, pcibr_soft_t);extern bridge_ate_t     pcibr_flags_to_ate(pcibr_soft_t, unsigned);pcibr_dmamap_t          pcibr_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned);void                    pcibr_dmamap_free(pcibr_dmamap_t);extern bridge_ate_p     pcibr_ate_addr(pcibr_soft_t, int);static iopaddr_t         pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t);iopaddr_t               pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t);void                    pcibr_dmamap_done(pcibr_dmamap_t);cnodeid_t		pcibr_get_dmatrans_node(vertex_hdl_t);iopaddr_t               pcibr_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned);void                    pcibr_dmamap_drain(pcibr_dmamap_t);void                    pcibr_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t);iopaddr_t               pcibr_dmamap_pciaddr_get(pcibr_dmamap_t);void                    pcibr_provider_startup(vertex_hdl_t);void                    pcibr_provider_shutdown(vertex_hdl_t);int                     pcibr_reset(vertex_hdl_t);pciio_endian_t          pcibr_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t);int                     pcibr_device_flags_set(vertex_hdl_t, pcibr_device_flags_t);extern int		pcibr_slot_info_free(vertex_hdl_t,pciio_slot_t);extern int              pcibr_slot_detach(vertex_hdl_t, pciio_slot_t, int,                                                      char *, int *);pciio_businfo_t		pcibr_businfo_get(vertex_hdl_t);/* ===================================================================== *    Device(x) register management *//* pcibr_try_set_device: attempt to modify Device(x) * for the specified slot on the specified bridge * as requested in flags, limited to the specified * bits. Returns which BRIDGE bits were in conflict, * or ZERO if everything went OK. * * Caller MUST hold pcibr_lock when calling this function. */static intpcibr_try_set_device(pcibr_soft_t pcibr_soft,		     pciio_slot_t slot,		     unsigned flags,		     uint64_t mask){    pcibr_soft_slot_t       slotp;    uint64_t		    old;    uint64_t		    new;    uint64_t		    chg;    uint64_t		    bad;    uint64_t		    badpmu;    uint64_t		    badd32;    uint64_t		    badd64;    uint64_t		    fix;    unsigned long	    s;    slotp = &pcibr_soft->bs_slot[slot];    s = pcibr_lock(pcibr_soft);    old = slotp->bss_device;    /* figure out what the desired     * Device(x) bits are based on     * the flags specified.     */    new = old;    /* Currently, we inherit anything that     * the new caller has not specified in     * one way or another, unless we take     * action here to not inherit.     *     * This is needed for the "swap" stuff,     * since it could have been set via     * pcibr_endian_set -- altho note that     * any explicit PCIBR_BYTE_STREAM or     * PCIBR_WORD_VALUES will freely override     * the effect of that call (and vice     * versa, no protection either way).     *     * I want to get rid of pcibr_endian_set     * in favor of tracking DMA endianness     * using the flags specified when DMA     * channels are created.     */#define	BRIDGE_DEV_WRGA_BITS	(BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN)#define	BRIDGE_DEV_SWAP_BITS	(BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR)    /* Do not use Barrier, Write Gather,     * or Prefetch unless asked.     * Leave everything else as it     * was from the last time.     */    new = new	& ~BRIDGE_DEV_BARRIER	& ~BRIDGE_DEV_WRGA_BITS	& ~BRIDGE_DEV_PREF	;    /* Generic macro flags     */    if (flags & PCIIO_DMA_DATA) {	new = (new            & ~BRIDGE_DEV_BARRIER)      /* barrier off */            | BRIDGE_DEV_PREF;          /* prefetch on */    }    if (flags & PCIIO_DMA_CMD) {        new = ((new            & ~BRIDGE_DEV_PREF)         /* prefetch off */            & ~BRIDGE_DEV_WRGA_BITS)    /* write gather off */            | BRIDGE_DEV_BARRIER;       /* barrier on */    }    /* Generic detail flags     */    if (flags & PCIIO_WRITE_GATHER)	new |= BRIDGE_DEV_WRGA_BITS;    if (flags & PCIIO_NOWRITE_GATHER)	new &= ~BRIDGE_DEV_WRGA_BITS;    if (flags & PCIIO_PREFETCH)	new |= BRIDGE_DEV_PREF;    if (flags & PCIIO_NOPREFETCH)	new &= ~BRIDGE_DEV_PREF;    if (flags & PCIBR_WRITE_GATHER)	new |= BRIDGE_DEV_WRGA_BITS;    if (flags & PCIBR_NOWRITE_GATHER)	new &= ~BRIDGE_DEV_WRGA_BITS;    if (flags & PCIIO_BYTE_STREAM)	new |= BRIDGE_DEV_SWAP_DIR;    if (flags & PCIIO_WORD_VALUES)	new &= ~BRIDGE_DEV_SWAP_DIR;    /* Provider-specific flags     */    if (flags & PCIBR_PREFETCH)	new |= BRIDGE_DEV_PREF;    if (flags & PCIBR_NOPREFETCH)	new &= ~BRIDGE_DEV_PREF;    if (flags & PCIBR_PRECISE)	new |= BRIDGE_DEV_PRECISE;    if (flags & PCIBR_NOPRECISE)	new &= ~BRIDGE_DEV_PRECISE;    if (flags & PCIBR_BARRIER)	new |= BRIDGE_DEV_BARRIER;    if (flags & PCIBR_NOBARRIER)	new &= ~BRIDGE_DEV_BARRIER;    if (flags & PCIBR_64BIT)	new |= BRIDGE_DEV_DEV_SIZE;    if (flags & PCIBR_NO64BIT)	new &= ~BRIDGE_DEV_DEV_SIZE;    /*     * PIC BRINGUP WAR (PV# 855271):     * Allow setting BRIDGE_DEV_VIRTUAL_EN on PIC iff we're a 64-bit     * device.  The bit is only intended for 64-bit devices and, on     * PIC, can cause problems for 32-bit devices.     */    if (mask == BRIDGE_DEV_D64_BITS &&				PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) {	if (flags & PCIBR_VCHAN1) {		new |= BRIDGE_DEV_VIRTUAL_EN;		mask |= BRIDGE_DEV_VIRTUAL_EN;	}    }    /* PIC BRINGUP WAR (PV# 878674):   Don't allow 64bit PIO accesses */    if ((flags & PCIBR_64BIT) &&				PCIBR_WAR_ENABLED(PV878674, pcibr_soft)) {	new &= ~(1ull << 22);    }    chg = old ^ new;				/* what are we changing, */    chg &= mask;				/* of the interesting bits */    if (chg) {	badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0;	badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0;	badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0;	bad = badpmu | badd32 | badd64;	if (bad) {	    /* some conflicts can be resolved by	     * forcing the bit on. this may cause	     * some performance degredation in	     * the stream(s) that want the bit off,	     * but the alternative is not allowing	     * the new stream at all.	     */            if ( (fix = bad & (BRIDGE_DEV_PRECISE |                             BRIDGE_DEV_BARRIER)) ) {		bad &= ~fix;		/* don't change these bits if		 * they are already set in "old"		 */		chg &= ~(fix & old);	    }	    /* some conflicts can be resolved by	     * forcing the bit off. this may cause	     * some performance degredation in	     * the stream(s) that want the bit on,	     * but the alternative is not allowing	     * the new stream at all.	     */	    if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS |			     BRIDGE_DEV_PREF)) ) {		bad &= ~fix;		/* don't change these bits if		 * we wanted to turn them on.		 */		chg &= ~(fix & new);	    }	    /* conflicts in other bits mean	     * we can not establish this DMA	     * channel while the other(s) are	     * still present.	     */	    if (bad) {		pcibr_unlock(pcibr_soft, s);		PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl,			    "pcibr_try_set_device: mod blocked by 0x%x\n", bad));		return bad;	    }	}    }    if (mask == BRIDGE_DEV_PMU_BITS)	slotp->bss_pmu_uctr++;    if (mask == BRIDGE_DEV_D32_BITS)	slotp->bss_d32_uctr++;    if (mask == BRIDGE_DEV_D64_BITS)	slotp->bss_d64_uctr++;    /* the value we want to write is the     * original value, with the bits for     * our selected changes flipped, and     * with any disabled features turned off.     */    new = old ^ chg;			/* only change what we want to change */    if (slotp->bss_device == new) {	pcibr_unlock(pcibr_soft, s);	return 0;    }        pcireg_device_set(pcibr_soft, slot, new);    slotp->bss_device = new;    pcireg_tflush_get(pcibr_soft);	/* wait until Bridge PIO complete */    pcibr_unlock(pcibr_soft, s);    PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl,		"pcibr_try_set_device: Device(%d): 0x%x\n", slot, new));    return 0;}voidpcibr_release_device(pcibr_soft_t pcibr_soft,		     pciio_slot_t slot,		     uint64_t mask){    pcibr_soft_slot_t       slotp;    unsigned long           s;    slotp = &pcibr_soft->bs_slot[slot];    s = pcibr_lock(pcibr_soft);    if (mask == BRIDGE_DEV_PMU_BITS)	slotp->bss_pmu_uctr--;    if (mask == BRIDGE_DEV_D32_BITS)	slotp->bss_d32_uctr--;    if (mask == BRIDGE_DEV_D64_BITS)	slotp->bss_d64_uctr--;    pcibr_unlock(pcibr_soft, s);}/* ===================================================================== *    Bridge (pcibr) "Device Driver" entry points */static intpcibr_mmap(struct file * file, struct vm_area_struct * vma){	vertex_hdl_t		pcibr_vhdl = file->f_dentry->d_fsdata;	pcibr_soft_t            pcibr_soft;	void               *bridge;	unsigned long		phys_addr;	int			error = 0;	pcibr_soft = pcibr_soft_get(pcibr_vhdl);	bridge = pcibr_soft->bs_base;	phys_addr = (unsigned long)bridge & ~0xc000000000000000; /* Mask out the Uncache bits */        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);        vma->vm_flags |= VM_RESERVED | VM_IO;        error = io_remap_page_range(vma, phys_addr, vma->vm_start,				    vma->vm_end - vma->vm_start,				    vma->vm_page_prot);	return error;}/* * This is the file operation table for the pcibr driver. * As each of the functions are implemented, put the * appropriate function name below. */static int pcibr_mmap(struct file * file, struct vm_area_struct * vma);struct file_operations pcibr_fops = {	.owner		= THIS_MODULE,	.mmap		= pcibr_mmap,};/* This is special case code used by grio. There are plans to make * this a bit more general in the future, but till then this should

⌨️ 快捷键说明

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