pcibr_dvr.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,108 行 · 第 1/5 页

C
2,108
字号
	maplist = *mapptr;	pcibr_piomap->bp_next = maplist;	*mapptr = pcibr_piomap;    }    pcibr_unlock(pcibr_soft, s);    if (pcibr_piomap) {	xtalk_piomap =	    xtalk_piomap_alloc(xconn_vhdl, 0,			       xio_addr,			       req_size, req_size_max,			       flags & PIOMAP_FLAGS);	if (xtalk_piomap) {	    pcibr_piomap->bp_xtalk_addr = xio_addr;	    pcibr_piomap->bp_xtalk_pio = xtalk_piomap;	} else {	    pcibr_piomap->bp_mapsz = 0;	    pcibr_piomap = 0;	}    }        PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,		"pcibr_piomap_alloc: map=0x%lx\n", pcibr_piomap));    return pcibr_piomap;}/*ARGSUSED */voidpcibr_piomap_free(pcibr_piomap_t pcibr_piomap){    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,		"pcibr_piomap_free: map=0x%lx\n", pcibr_piomap));    xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio);    pcibr_piomap->bp_xtalk_pio = 0;    pcibr_piomap->bp_mapsz = 0;}/*ARGSUSED */caddr_tpcibr_piomap_addr(pcibr_piomap_t pcibr_piomap,		  iopaddr_t pci_addr,		  size_t req_size){    caddr_t	addr;    addr = xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio,			     pcibr_piomap->bp_xtalk_addr +			     pci_addr - pcibr_piomap->bp_pciaddr,			     req_size);    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,                "pcibr_piomap_addr: map=0x%lx, addr=0x%lx\n", 		pcibr_piomap, addr));    return addr;}/*ARGSUSED */voidpcibr_piomap_done(pcibr_piomap_t pcibr_piomap){    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,		"pcibr_piomap_done: map=0x%lx\n", pcibr_piomap));    xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio);}/*ARGSUSED */caddr_tpcibr_piotrans_addr(vertex_hdl_t pconn_vhdl,		    device_desc_t dev_desc,		    pciio_space_t space,		    iopaddr_t pci_addr,		    size_t req_size,		    unsigned flags){    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);    vertex_hdl_t            xconn_vhdl = pcibr_soft->bs_conn;    iopaddr_t               xio_addr;    caddr_t		    addr;    xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags);    if (xio_addr == XIO_NOWHERE) {	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIODIR, pconn_vhdl,		    "pcibr_piotrans_addr: xio_addr == XIO_NOWHERE\n"));	return NULL;    }    addr = xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS);    PCIBR_DEBUG((PCIBR_DEBUG_PIODIR, pconn_vhdl,		"pcibr_piotrans_addr: xio_addr=0x%lx, addr=0x%lx\n",		xio_addr, addr));    return addr;}/* * PIO Space allocation and management. *      Allocate and Manage the PCI PIO space (mem and io space) *      This routine is pretty simplistic at this time, and *      does pretty trivial management of allocation and freeing. *      The current scheme is prone for fragmentation. *      Change the scheme to use bitmaps. *//*ARGSUSED */iopaddr_tpcibr_piospace_alloc(vertex_hdl_t pconn_vhdl,		     device_desc_t dev_desc,		     pciio_space_t space,		     size_t req_size,		     size_t alignment){    pcibr_info_t            pcibr_info = pcibr_info_get(pconn_vhdl);    pciio_info_t            pciio_info = &pcibr_info->f_c;    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);    pciio_piospace_t        piosp;    unsigned long           s;    iopaddr_t               start_addr;    size_t                  align_mask;    /*     * Check for proper alignment     */    ASSERT(alignment >= PAGE_SIZE);    ASSERT((alignment & (alignment - 1)) == 0);    align_mask = alignment - 1;    s = pcibr_lock(pcibr_soft);    /*     * First look if a previously allocated chunk exists.     */    piosp = pcibr_info->f_piospace;    if (piosp) {	/*	 * Look through the list for a right sized free chunk.	 */	do {	    if (piosp->free &&		(piosp->space == space) &&		(piosp->count >= req_size) &&		!(piosp->start & align_mask)) {		piosp->free = 0;		pcibr_unlock(pcibr_soft, s);		return piosp->start;	    }	    piosp = piosp->next;	} while (piosp);    }    ASSERT(!piosp);    /*     * Allocate PCI bus address, usually for the Universe chip driver;     * do not pass window info since the actual PCI bus address     * space will never be freed.  The space may be reused after it     * is logically released by pcibr_piospace_free().     */    switch (space) {    case PCIIO_SPACE_IO:        start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL,                                          PCIIO_SPACE_IO,                                          0, req_size, alignment);	break;    case PCIIO_SPACE_MEM:    case PCIIO_SPACE_MEM32:        start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL,                                          PCIIO_SPACE_MEM32,                                          0, req_size, alignment);	break;    default:	ASSERT(0);	pcibr_unlock(pcibr_soft, s);	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,		    "pcibr_piospace_alloc: unknown space %d\n", space));	return 0;    }    /*     * If too big a request, reject it.     */    if (!start_addr) {	pcibr_unlock(pcibr_soft, s);	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,		    "pcibr_piospace_alloc: request 0x%lx to big\n", req_size));	return 0;    }    piosp = kmalloc(sizeof (*(piosp)), GFP_KERNEL);    if ( !piosp ) {	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,		    "pcibr_piospace_alloc: malloc fails\n"));	return 0;    }    memset(piosp, 0, sizeof (*(piosp)));    piosp->free = 0;    piosp->space = space;    piosp->start = start_addr;    piosp->count = req_size;    piosp->next = pcibr_info->f_piospace;    pcibr_info->f_piospace = piosp;    pcibr_unlock(pcibr_soft, s);    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,		"pcibr_piospace_alloc: piosp=0x%lx\n", piosp));    return start_addr;}#define ERR_MSG "!Device %s freeing size (0x%lx) different than allocated (0x%lx)"/*ARGSUSED */voidpcibr_piospace_free(vertex_hdl_t pconn_vhdl,		    pciio_space_t space,		    iopaddr_t pciaddr,		    size_t req_size){    pcibr_info_t            pcibr_info = pcibr_info_get(pconn_vhdl);    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;    pciio_piospace_t        piosp;    unsigned long           s;    char                    name[1024];    /*     * Look through the bridge data structures for the pciio_piospace_t     * structure corresponding to  'pciaddr'     */    s = pcibr_lock(pcibr_soft);    piosp = pcibr_info->f_piospace;    while (piosp) {	/*	 * Piospace free can only be for the complete	 * chunk and not parts of it..	 */	if (piosp->start == pciaddr) {	    if (piosp->count == req_size)		break;	    /*	     * Improper size passed for freeing..	     * Print a message and break;	     */	    hwgraph_vertex_name_get(pconn_vhdl, name, 1024);	    printk(KERN_WARNING  "pcibr_piospace_free: error");	    printk(KERN_WARNING  "Device %s freeing size (0x%lx) different than allocated (0x%lx)",					name, req_size, piosp->count);	    printk(KERN_WARNING  "Freeing 0x%lx instead", piosp->count);	    break;	}	piosp = piosp->next;    }    if (!piosp) {	printk(KERN_WARNING  		"pcibr_piospace_free: Address 0x%lx size 0x%lx - No match\n",		pciaddr, req_size);	pcibr_unlock(pcibr_soft, s);	return;    }    piosp->free = 1;    pcibr_unlock(pcibr_soft, s);    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,		"pcibr_piospace_free: piosp=0x%lx\n", piosp));    return;}/* ===================================================================== *    DMA MANAGEMENT * *      The Bridge ASIC provides three methods of doing *      DMA: via a "direct map" register available in *      32-bit PCI space (which selects a contiguous 2G *      address space on some other widget), via *      "direct" addressing via 64-bit PCI space (all *      destination information comes from the PCI *      address, including transfer attributes), and via *      a "mapped" region that allows a bunch of *      different small mappings to be established with *      the PMU. * *      For efficiency, we most prefer to use the 32-bit *      direct mapping facility, since it requires no *      resource allocations. The advantage of using the *      PMU over the 64-bit direct is that single-cycle *      PCI addressing can be used; the advantage of *      using 64-bit direct over PMU addressing is that *      we do not have to allocate entries in the PMU. *//* * Convert PCI-generic software flags and Bridge-specific software flags * into Bridge-specific Direct Map attribute bits. */static iopaddr_tpcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft){    iopaddr_t               attributes = 0;    /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */#ifdef LATER    ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64));#endif    /* Generic macro flags     */    if (flags & PCIIO_DMA_DATA) {	/* standard data channel */	attributes &= ~PCI64_ATTR_BAR;	/* no barrier bit */	attributes |= PCI64_ATTR_PREF;	/* prefetch on */    }    if (flags & PCIIO_DMA_CMD) {	/* standard command channel */	attributes |= PCI64_ATTR_BAR;	/* barrier bit on */	attributes &= ~PCI64_ATTR_PREF;	/* disable prefetch */    }    /* Generic detail flags     */    if (flags & PCIIO_PREFETCH)	attributes |= PCI64_ATTR_PREF;    if (flags & PCIIO_NOPREFETCH)	attributes &= ~PCI64_ATTR_PREF;    /* the swap bit is in the address attributes for xbridge */    if (flags & PCIIO_BYTE_STREAM)       	attributes |= PCI64_ATTR_SWAP;    if (flags & PCIIO_WORD_VALUES)       	attributes &= ~PCI64_ATTR_SWAP;    /* Provider-specific flags     */    if (flags & PCIBR_BARRIER)	attributes |= PCI64_ATTR_BAR;    if (flags & PCIBR_NOBARRIER)	attributes &= ~PCI64_ATTR_BAR;    if (flags & PCIBR_PREFETCH)	attributes |= PCI64_ATTR_PREF;    if (flags & PCIBR_NOPREFETCH)	attributes &= ~PCI64_ATTR_PREF;    if (flags & PCIBR_PRECISE)	attributes |= PCI64_ATTR_PREC;    if (flags & PCIBR_NOPRECISE)	attributes &= ~PCI64_ATTR_PREC;    if (flags & PCIBR_VCHAN1)	attributes |= PCI64_ATTR_VIRTUAL;    if (flags & PCIBR_VCHAN0)	attributes &= ~PCI64_ATTR_VIRTUAL;    /* PIC in PCI-X mode only supports barrier & swap */    if (IS_PCIX(pcibr_soft)) {	attributes &= (PCI64_ATTR_BAR | PCI64_ATTR_SWAP);    }    return attributes;}/*ARGSUSED */pcibr_dmamap_tpcibr_dmamap_alloc(vertex_hdl_t pconn_vhdl,		   device_desc_t dev_desc,		   size_t req_size_max,		   unsigned flags){    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);    vertex_hdl_t            xconn_vhdl = pcibr_soft->bs_conn;    pciio_slot_t            slot;    xwidgetnum_t            xio_port;    xtalk_dmamap_t          xtalk_dmamap;    pcibr_dmamap_t          pcibr_dmamap;    int                     ate_count;    int                     ate_index;    int			    vchan = VCHAN0;    unsigned long	    s;    /* merge in forced flags */    flags |= pcibr_soft->bs_dma_flags;    /*     * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc()     * can be called within an interrupt thread.     */    s = pcibr_lock(pcibr_soft);    pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl);    pcibr_unlock(pcibr_soft, s);    if (!pcibr_dmamap)	return 0;    xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max,				      flags & DMAMAP_FLAGS);    if (!xtalk_dmamap) {	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl,		    "pcibr_dmamap_alloc: xtalk_dmamap_alloc failed\n"));	free_pciio_dmamap(pcibr_dmamap);	return 0;    }    xio_port = pcibr_soft->bs_mxid;    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);    pcibr_dmamap->bd_dev = pconn_vhdl;    pcibr_dmamap->bd_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot);    pcibr_dmamap->bd_soft = pcibr_soft;    pcibr_dmamap->bd_xtalk = xtalk_dmamap;    pcibr_dmamap->bd_max_size = req_size_max;    pcibr_dmamap->bd_xio_port = xio_port;    if (flags & PCIIO_DMA_A64) {	if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D64_BITS)) {	    iopaddr_t               pci_addr;	    int                     have_rrbs;	    int                     min_rrbs;

⌨️ 快捷键说明

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