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