pcibr_dvr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,108 行 · 第 1/5 页
C
2,108 行
unsigned long s; s = pcibr_lock(pcibr_soft); if (pcibr_soft->bs_slot[slot].has_host) { slot = pcibr_soft->bs_slot[slot].host_slot; pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; /* * Special case for dual-slot pci devices such as ioc3 on IP27 * baseio. In these cases, pconn_vhdl should never be for a pci * function on a subordiate PCI bus, so we can safely reset pciio_info * to be the info struct embedded in pcibr_info. Failure to do this * results in using a bogus pciio_info_t for calculations done later * in this routine. */ pciio_info = &pcibr_info->f_c; } if (space == PCIIO_SPACE_NONE) goto done; if (space == PCIIO_SPACE_CFG) { /* * Usually, the first mapping * established to a PCI device * is to its config space. * * In any case, we definitely * do NOT need to worry about * PCI BASE registers, and * MUST NOT attempt to point * the DevIO(x) window at * this access ... */ if (((flags & PCIIO_BYTE_STREAM) == 0) && ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) xio_addr = pci_addr + PCIBR_TYPE0_CFG_DEV(pcibr_soft, slot); goto done; } if (space == PCIIO_SPACE_ROM) { /* PIO to the Expansion Rom. * Driver is responsible for * enabling and disabling * decodes properly. */ wbase = pciio_info->c_rbase; wsize = pciio_info->c_rsize; /* * While the driver should know better * than to attempt to map more space * than the device is decoding, he might * do it; better to bail out here. */ if ((pci_addr + req_size) > wsize) goto done; pci_addr += wbase; space = PCIIO_SPACE_MEM; } /* * reduce window mappings to raw * space mappings (maybe allocating * windows), and try for DevIO(x) * usage (setting it if it is available). */ bar = space - PCIIO_SPACE_WIN0; if (bar < 6) { wspace = pciio_info->c_window[bar].w_space; if (wspace == PCIIO_SPACE_NONE) goto done; /* get PCI base and size */ wbase = pciio_info->c_window[bar].w_base; wsize = pciio_info->c_window[bar].w_size; /* * While the driver should know better * than to attempt to map more space * than the device is decoding, he might * do it; better to bail out here. */ if ((pci_addr + req_size) > wsize) goto done; /* shift from window relative to * decoded space relative. */ pci_addr += wbase; space = wspace; } else bar = -1; /* Scan all the DevIO(x) windows twice looking for one * that can satisfy our request. The first time through, * only look at assigned windows; the second time, also * look at PCIIO_SPACE_NONE windows. Arrange the order * so we always look at our own window first. * * We will not attempt to satisfy a single request * by concatinating multiple windows. */ maxtry = PCIBR_NUM_SLOTS(pcibr_soft) * 2; halftry = PCIBR_NUM_SLOTS(pcibr_soft) - 1; for (try = 0; try < maxtry; ++try) { uint64_t devreg; unsigned offset; /* calculate win based on slot, attempt, and max possible devices on bus */ win = (try + slot) % PCIBR_NUM_SLOTS(pcibr_soft); /* If this DevIO(x) mapping area can provide * a mapping to this address, use it. */ msize = (win < 2) ? 0x200000 : 0x100000; mmask = -msize; if (space != PCIIO_SPACE_IO) mmask &= 0x3FFFFFFF; offset = pci_addr & (msize - 1); /* If this window can't possibly handle that request, * go on to the next window. */ if (((pci_addr & (msize - 1)) + req_size) > msize) continue; devreg = pcibr_soft->bs_slot[win].bss_device; /* Is this window "nailed down"? * If not, maybe we can use it. * (only check this the second time through) */ mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; if ((try > halftry) && (mspace == PCIIO_SPACE_NONE)) { /* If this is the primary DevIO(x) window * for some other device, skip it. */ if ((win != slot) && (PCIIO_VENDOR_ID_NONE != pcibr_soft->bs_slot[win].bss_vendor_id)) continue; /* It's a free window, and we fit in it. * Set up Device(win) to our taste. */ mbase = pci_addr & mmask; /* check that we would really get from * here to there. */ if ((mbase | offset) != pci_addr) continue; devreg &= ~BRIDGE_DEV_OFF_MASK; if (space != PCIIO_SPACE_IO) devreg |= BRIDGE_DEV_DEV_IO_MEM; else devreg &= ~BRIDGE_DEV_DEV_IO_MEM; devreg |= (mbase >> 20) & BRIDGE_DEV_OFF_MASK; /* default is WORD_VALUES. * if you specify both, * operation is undefined. */ if (flags & PCIIO_BYTE_STREAM) devreg |= BRIDGE_DEV_DEV_SWAP; else devreg &= ~BRIDGE_DEV_DEV_SWAP; if (pcibr_soft->bs_slot[win].bss_device != devreg) { pcireg_device_set(pcibr_soft, win, devreg); pcibr_soft->bs_slot[win].bss_device = devreg; pcireg_tflush_get(pcibr_soft); PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, "pcibr_addr_pci_to_xio: Device(%d): 0x%x\n", win, devreg)); } pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase); /* Increment this DevIO's use count */ pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++; /* Save the DevIO register index used to access this BAR */ if (bar != -1) pcibr_info->f_window[bar].w_devio_index = win; PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "pcibr_addr_pci_to_xio: map to space %s [0x%lx..0x%lx] " "for slot %d allocates DevIO(%d) Device(%d) set to %lx\n", pci_space[space], pci_addr, pci_addr + req_size - 1, slot, win, win, devreg)); goto done; } /* endif DevIO(x) not pointed */ mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; /* Now check for request incompat with DevIO(x) */ if ((mspace != space) || (pci_addr < mbase) || ((pci_addr + req_size) > (mbase + msize)) || ((flags & PCIIO_BYTE_STREAM) && !(devreg & BRIDGE_DEV_DEV_SWAP)) || (!(flags & PCIIO_BYTE_STREAM) && (devreg & BRIDGE_DEV_DEV_SWAP))) continue; /* DevIO(x) window is pointed at PCI space * that includes our target. Calculate the * final XIO address, release the lock and * return. */ xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase); /* Increment this DevIO's use count */ pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++; /* Save the DevIO register index used to access this BAR */ if (bar != -1) pcibr_info->f_window[bar].w_devio_index = win; PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "pcibr_addr_pci_to_xio: map to space %s [0x%lx..0x%lx] " "for slot %d uses DevIO(%d)\n", pci_space[space], pci_addr, pci_addr + req_size - 1, slot, win)); goto done; } switch (space) { /* * Accesses to device decode * areas that do a not fit * within the DevIO(x) space are * modified to be accesses via * the direct mapping areas. * * If necessary, drivers can * explicitly ask for mappings * into these address spaces, * but this should never be needed. */ case PCIIO_SPACE_MEM: /* "mem space" */ case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ base = PICBRIDGE0_PCI_MEM32_BASE; limit = PICBRIDGE0_PCI_MEM32_LIMIT; } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ base = PICBRIDGE1_PCI_MEM32_BASE; limit = PICBRIDGE1_PCI_MEM32_LIMIT; } else { printk("pcibr_addr_pci_to_xio(): unknown bridge type"); return (iopaddr_t)0; } if ((pci_addr + base + req_size - 1) <= limit) xio_addr = pci_addr + base; break; case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ base = PICBRIDGE0_PCI_MEM64_BASE; limit = PICBRIDGE0_PCI_MEM64_LIMIT; } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ base = PICBRIDGE1_PCI_MEM64_BASE; limit = PICBRIDGE1_PCI_MEM64_LIMIT; } else { printk("pcibr_addr_pci_to_xio(): unknown bridge type"); return (iopaddr_t)0; } if ((pci_addr + base + req_size - 1) <= limit) xio_addr = pci_addr + base; break; case PCIIO_SPACE_IO: /* "i/o space" */ /* * PIC bridges do not support big-window aliases into PCI I/O space */ xio_addr = XIO_NOWHERE; break; } /* Check that "Direct PIO" byteswapping matches, * try to change it if it does not. */ if (xio_addr != XIO_NOWHERE) { unsigned bst; /* nonzero to set bytestream */ unsigned *bfp; /* addr of record of how swapper is set */ uint64_t swb; /* which control bit to mung */ unsigned bfo; /* current swapper setting */ unsigned bfn; /* desired swapper setting */ bfp = ((space == PCIIO_SPACE_IO) ? (&pcibr_soft->bs_pio_end_io) : (&pcibr_soft->bs_pio_end_mem)); bfo = *bfp; bst = flags & PCIIO_BYTE_STREAM; bfn = bst ? PCIIO_BYTE_STREAM : PCIIO_WORD_VALUES; if (bfn == bfo) { /* we already match. */ ; } else if (bfo != 0) { /* we have a conflict. */ PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "pcibr_addr_pci_to_xio: swap conflict in %s, " "was%s%s, want%s%s\n", pci_space[space], bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "")); xio_addr = XIO_NOWHERE; } else { /* OK to make the change. */ swb = (space == PCIIO_SPACE_IO) ? 0: BRIDGE_CTRL_MEM_SWAP; if (bst) { pcireg_control_bit_set(pcibr_soft, swb); } else { pcireg_control_bit_clr(pcibr_soft, swb); } *bfp = bfn; /* record the assignment */ PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "pcibr_addr_pci_to_xio: swap for %s set to%s%s\n", pci_space[space], bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "")); } } done: pcibr_unlock(pcibr_soft, s); return xio_addr;}/*ARGSUSED6 */pcibr_piomap_tpcibr_piomap_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, size_t req_size, size_t req_size_max, unsigned flags){ pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); pciio_info_t pciio_info = &pcibr_info->f_c; 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; pcibr_piomap_t *mapptr; pcibr_piomap_t maplist; pcibr_piomap_t pcibr_piomap; iopaddr_t xio_addr; xtalk_piomap_t xtalk_piomap; unsigned long s; /* Make sure that the req sizes are non-zero */ if ((req_size < 1) || (req_size_max < 1)) { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "pcibr_piomap_alloc: req_size | req_size_max < 1\n")); return NULL; } /* * Code to translate slot/space/addr * into xio_addr is common between * this routine and pcibr_piotrans_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_PIOMAP, pconn_vhdl, "pcibr_piomap_alloc: xio_addr == XIO_NOWHERE\n")); return NULL; } /* Check the piomap list to see if there is already an allocated * piomap entry but not in use. If so use that one. Otherwise * allocate a new piomap entry and add it to the piomap list */ mapptr = &(pcibr_info->f_piomap); s = pcibr_lock(pcibr_soft); for (pcibr_piomap = *mapptr; pcibr_piomap != NULL; pcibr_piomap = pcibr_piomap->bp_next) { if (pcibr_piomap->bp_mapsz == 0) break; } if (pcibr_piomap) mapptr = NULL; else { pcibr_unlock(pcibr_soft, s); pcibr_piomap = kmalloc(sizeof (*(pcibr_piomap)), GFP_KERNEL); if ( !pcibr_piomap ) { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "pcibr_piomap_alloc: malloc fails\n")); return NULL; } memset(pcibr_piomap, 0, sizeof (*(pcibr_piomap))); } pcibr_piomap->bp_dev = pconn_vhdl; pcibr_piomap->bp_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, pciio_slot); pcibr_piomap->bp_flags = flags; pcibr_piomap->bp_space = space; pcibr_piomap->bp_pciaddr = pci_addr; pcibr_piomap->bp_mapsz = req_size; pcibr_piomap->bp_soft = pcibr_soft; pcibr_piomap->bp_toc = ATOMIC_INIT(0); if (mapptr) { s = pcibr_lock(pcibr_soft);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?