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 + -
显示快捷键?