sba_iommu.c

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

C
2,079
字号
 * See Documentation/DMA-mapping.txt */static void *sba_alloc_consistent(struct device *hwdev, size_t size,					dma_addr_t *dma_handle, int gfp){	void *ret;	if (!hwdev) {		/* only support PCI */		*dma_handle = 0;		return 0;	}        ret = (void *) __get_free_pages(gfp, get_order(size));	if (ret) {		memset(ret, 0, size);		*dma_handle = sba_map_single(hwdev, ret, size, 0);	}	return ret;}/** * sba_free_consistent - free/unmap shared mem for DMA * @hwdev: instance of PCI owned by the driver that's asking. * @size:  number of bytes mapped in driver buffer. * @vaddr:  virtual address IOVA of "consistent" buffer. * @dma_handler:  IO virtual address of "consistent" buffer. * * See Documentation/DMA-mapping.txt */static voidsba_free_consistent(struct device *hwdev, size_t size, void *vaddr,		    dma_addr_t dma_handle){	sba_unmap_single(hwdev, dma_handle, size, 0);	free_pages((unsigned long) vaddr, get_order(size));}/*** Since 0 is a valid pdir_base index value, can't use that** to determine if a value is valid or not. Use a flag to indicate** the SG list entry contains a valid pdir index.*/#define PIDE_FLAG 0x80000000UL#ifdef SBA_COLLECT_STATS#define IOMMU_MAP_STATS#endif#include "iommu-helpers.h"#ifdef DEBUG_LARGE_SG_ENTRIESint dump_run_sg = 0;#endif/** * sba_map_sg - map Scatter/Gather list * @dev: instance of PCI owned by the driver that's asking. * @sglist:  array of buffer/length pairs * @nents:  number of entries in list * @direction:  R/W or both. * * See Documentation/DMA-mapping.txt */static intsba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,	   enum dma_data_direction direction){	struct ioc *ioc;	int coalesced, filled = 0;	unsigned long flags;	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);	ioc = GET_IOC(dev);	ASSERT(ioc);	/* Fast path single entry scatterlists. */	if (nents == 1) {		sg_dma_address(sglist) = sba_map_single(dev,						(void *)sg_virt_addr(sglist),						sglist->length, direction);		sg_dma_len(sglist)     = sglist->length;		return 1;	}	spin_lock_irqsave(&ioc->res_lock, flags);#ifdef ASSERT_PDIR_SANITY	if (sba_check_pdir(ioc,"Check before sba_map_sg()"))	{		sba_dump_sg(ioc, sglist, nents);		panic("Check before sba_map_sg()");	}#endif#ifdef SBA_COLLECT_STATS	ioc->msg_calls++;#endif	/*	** First coalesce the chunks and allocate I/O pdir space	**	** If this is one DMA stream, we can properly map using the	** correct virtual address associated with each DMA page.	** w/o this association, we wouldn't have coherent DMA!	** Access to the virtual address is what forces a two pass algorithm.	*/	coalesced = iommu_coalesce_chunks(ioc, sglist, nents, sba_alloc_range);	/*	** Program the I/O Pdir	**	** map the virtual addresses to the I/O Pdir	** o dma_address will contain the pdir index	** o dma_len will contain the number of bytes to map 	** o address contains the virtual address.	*/	filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry);#ifdef ASSERT_PDIR_SANITY	if (sba_check_pdir(ioc,"Check after sba_map_sg()"))	{		sba_dump_sg(ioc, sglist, nents);		panic("Check after sba_map_sg()\n");	}#endif	spin_unlock_irqrestore(&ioc->res_lock, flags);	ASSERT(coalesced == filled);	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);	return filled;}/** * sba_unmap_sg - unmap Scatter/Gather list * @dev: instance of PCI owned by the driver that's asking. * @sglist:  array of buffer/length pairs * @nents:  number of entries in list * @direction:  R/W or both. * * See Documentation/DMA-mapping.txt */static void sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,	     enum dma_data_direction direction){	struct ioc *ioc;#ifdef ASSERT_PDIR_SANITY	unsigned long flags;#endif	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",		__FUNCTION__, nents, sg_virt_addr(sglist), sglist->length);	ioc = GET_IOC(dev);	ASSERT(ioc);#ifdef SBA_COLLECT_STATS	ioc->usg_calls++;#endif#ifdef ASSERT_PDIR_SANITY	spin_lock_irqsave(&ioc->res_lock, flags);	sba_check_pdir(ioc,"Check before sba_unmap_sg()");	spin_unlock_irqrestore(&ioc->res_lock, flags);#endif	while (sg_dma_len(sglist) && nents--) {		sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);#ifdef SBA_COLLECT_STATS		ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;		ioc->usingle_calls--;	/* kluge since call is unmap_sg() */#endif		++sglist;	}	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);#ifdef ASSERT_PDIR_SANITY	spin_lock_irqsave(&ioc->res_lock, flags);	sba_check_pdir(ioc,"Check after sba_unmap_sg()");	spin_unlock_irqrestore(&ioc->res_lock, flags);#endif}static struct hppa_dma_ops sba_ops = {	.dma_supported =	sba_dma_supported,	.alloc_consistent =	sba_alloc_consistent,	.alloc_noncoherent =	sba_alloc_consistent,	.free_consistent =	sba_free_consistent,	.map_single =		sba_map_single,	.unmap_single =		sba_unmap_single,	.map_sg =		sba_map_sg,	.unmap_sg =		sba_unmap_sg,	.dma_sync_single_for_cpu =	NULL,	.dma_sync_single_for_device =	NULL,	.dma_sync_sg_for_cpu =		NULL,	.dma_sync_sg_for_device =	NULL,};/******************************************************************************   SBA PAT PDC support****   o call pdc_pat_cell_module()**   o store ranges in PCI "resource" structures****************************************************************************/static voidsba_get_pat_resources(struct sba_device *sba_dev){#if 0/*** TODO/REVISIT/FIXME: support for directed ranges requires calls to**      PAT PDC to program the SBA/LBA directed range registers...this**      burden may fall on the LBA code since it directly supports the**      PCI subsystem. It's not clear yet. - ggg*/PAT_MOD(mod)->mod_info.mod_pages   = PAT_GET_MOD_PAGES(temp);	FIXME : ???PAT_MOD(mod)->mod_info.dvi         = PAT_GET_DVI(temp);	Tells where the dvi bits are located in the address.PAT_MOD(mod)->mod_info.ioc         = PAT_GET_IOC(temp);	FIXME : ???#endif}/****************************************************************   Initialization and claim****************************************************************/#define PIRANHA_ADDR_MASK	0x00160000UL /* bit 17,18,20 */#define PIRANHA_ADDR_VAL	0x00060000UL /* bit 17,18 on */static void *sba_alloc_pdir(unsigned int pdir_size){        unsigned long pdir_base;	unsigned long pdir_order = get_order(pdir_size);	pdir_base = __get_free_pages(GFP_KERNEL, pdir_order);	if (NULL == (void *) pdir_base)		panic("sba_ioc_init() could not allocate I/O Page Table\n");	/* If this is not PA8700 (PCX-W2)	**	OR newer than ver 2.2	**	OR in a system that doesn't need VINDEX bits from SBA,	**	** then we aren't exposed to the HW bug.	*/	if ( ((boot_cpu_data.pdc.cpuid >> 5) & 0x7f) != 0x13			|| (boot_cpu_data.pdc.versions > 0x202)			|| (boot_cpu_data.pdc.capabilities & 0x08L) )		return (void *) pdir_base;	/*	 * PA8700 (PCX-W2, aka piranha) silent data corruption fix	 *	 * An interaction between PA8700 CPU (Ver 2.2 or older) and	 * Ike/Astro can cause silent data corruption. This is only	 * a problem if the I/O PDIR is located in memory such that	 * (little-endian)  bits 17 and 18 are on and bit 20 is off.	 *	 * Since the max IO Pdir size is 2MB, by cleverly allocating the	 * right physical address, we can either avoid (IOPDIR <= 1MB)	 * or minimize (2MB IO Pdir) the problem if we restrict the	 * IO Pdir to a maximum size of 2MB-128K (1902K).	 *	 * Because we always allocate 2^N sized IO pdirs, either of the	 * "bad" regions will be the last 128K if at all. That's easy	 * to test for.	 * 	 */	if (pdir_order <= (19-12)) {		if (((virt_to_phys(pdir_base)+pdir_size-1) & PIRANHA_ADDR_MASK) == PIRANHA_ADDR_VAL) {			/* allocate a new one on 512k alignment */			unsigned long new_pdir = __get_free_pages(GFP_KERNEL, (19-12));			/* release original */			free_pages(pdir_base, pdir_order);			pdir_base = new_pdir;			/* release excess */			while (pdir_order < (19-12)) {				new_pdir += pdir_size;				free_pages(new_pdir, pdir_order);				pdir_order +=1;				pdir_size <<=1;			}		}	} else {		/*		** 1MB or 2MB Pdir		** Needs to be aligned on an "odd" 1MB boundary.		*/		unsigned long new_pdir = __get_free_pages(GFP_KERNEL, pdir_order+1); /* 2 or 4MB */		/* release original */		free_pages( pdir_base, pdir_order);		/* release first 1MB */		free_pages(new_pdir, 20-12);		pdir_base = new_pdir + 1024*1024;		if (pdir_order > (20-12)) {			/*			** 2MB Pdir.			**			** Flag tells init_bitmap() to mark bad 128k as used			** and to reduce the size by 128k.			*/			piranha_bad_128k = 1;			new_pdir += 3*1024*1024;			/* release last 1MB */			free_pages(new_pdir, 20-12);			/* release unusable 128KB */			free_pages(new_pdir - 128*1024 , 17-12);			pdir_size -= 128*1024;		}	}	memset((void *) pdir_base, 0, pdir_size);	return (void *) pdir_base;}static voidsba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num){        /* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */        extern void lba_set_iregs(struct parisc_device *, u32, u32);	u32 iova_space_mask;	u32 iova_space_size;	int iov_order, tcnfg;	struct parisc_device *lba;#if SBA_AGP_SUPPORT	int agp_found = 0;#endif	/*	** Firmware programs the base and size of a "safe IOVA space"	** (one that doesn't overlap memory or LMMIO space) in the	** IBASE and IMASK registers.	*/	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE);	iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;	if ((ioc->ibase < 0xfed00000UL) && ((ioc->ibase + iova_space_size) > 0xfee00000UL)) {		printk("WARNING: IOV space overlaps local config and interrupt message, truncating\n");		iova_space_size /= 2;	}	/*	** iov_order is always based on a 1GB IOVA space since we want to	** turn on the other half for AGP GART.	*/	iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);	DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n",		__FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,		iov_order + PAGE_SHIFT);	ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL,						   get_order(ioc->pdir_size));	if (!ioc->pdir_base)		panic("Couldn't allocate I/O Page Table\n");	memset(ioc->pdir_base, 0, ioc->pdir_size);	DBG_INIT("%s() pdir %p size %x\n",			__FUNCTION__, ioc->pdir_base, ioc->pdir_size);#if SBA_HINT_SUPPORT	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));	DBG_INIT("	hint_shift_pdir %x hint_mask_pdir %lx\n",		ioc->hint_shift_pdir, ioc->hint_mask_pdir);#endif	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);	WRITE_REG(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);	/* build IMASK for IOC and Elroy */	iova_space_mask =  0xffffffff;	iova_space_mask <<= (iov_order + PAGE_SHIFT);	ioc->imask = iova_space_mask;#ifdef ZX1_SUPPORT	ioc->iovp_mask = ~(iova_space_mask + PAGE_SIZE - 1);#endif	sba_dump_tlb(ioc->ioc_hpa);	/*	** setup Mercury IBASE/IMASK registers as well.	*/	for (lba = sba->child; lba; lba = lba->sibling) {		int rope_num = (lba->hpa >> 13) & 0xf;		if (rope_num >> 3 == ioc_num)			lba_set_iregs(lba, ioc->ibase, ioc->imask);	}	WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK);#ifdef __LP64__	/*	** Setting the upper bits makes checking for bypass addresses	** a little faster later on.	*/	ioc->imask |= 0xFFFFFFFF00000000UL;#endif	/* Set I/O PDIR Page size to system page size */	switch (PAGE_SHIFT) {		case 12: tcnfg = 0; break;	/*  4K */		case 13: tcnfg = 1; break;	/*  8K */		case 14: tcnfg = 2; break;	/* 16K */		case 16: tcnfg = 3; break;	/* 64K */		default:			panic(__FILE__ "Unsupported system page size %d",				1 << PAGE_SHIFT);			break;	}	WRITE_REG(tcnfg, ioc->ioc_hpa + IOC_TCNFG);	/*	** Program the IOC's ibase and enable IOVA translation	** Bit zero == enable bit.	*/	WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE);	/*	** Clear I/O TLB of any possible entries.	** (Yes. This is a bit paranoid...but so what)	*/	WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);#if SBA_AGP_SUPPORT	/*	** If an AGP device is present, only use half of the IOV space	** for PCI DMA.  Unfortunately we can't know ahead of time	** whether GART support will actually be used, for now we	** can just key on any AGP device found in the system.	** We program the next pdir index after we stop w/ a key for	** the GART code to handshake on.	*/	device=NULL;	for (lba = sba->child; lba; lba = lba->sibling) {		if (IS_QUICKSILVER(lba))			break;	}	if (lba) {		DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);		ioc->pdir_size /= 2;		((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;	} else {		DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);	}#endif /* 0 */}static voidsba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num){	/* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */	extern void lba_set_iregs(struct parisc_device *, u32, u32);	u32 iova_space_size, iova_space_mask;	int pdir_size, iov_order;	unsigned long physmem;	struct parisc_device *lba;	/*	** Determine IOVA Space size from memory size.	**	** Ideally, PCI drivers would register the maximum number	** of DMA they can have outstanding for each device they	** own.  Next best thing would be to guess how much DMA	** can be outstanding based on PCI Class/sub-class. Both	** methods still require some "extra" to support PCI	** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).	**	** While we have 32-bits "IOVA" space, top two 2 bits are used	** for DMA hints - ergo only 30 bits max.	*/	physmem = num_physpages << PAGE_SHIFT;	iova_space_size = (u32) (physmem/(sba_mem_ratio*global_ioc_cnt));	/* limit IOVA space size to 1MB-1GB */	if (iova_space_size < 1024*1024) {		iova_space_size = 1024*1024;	}#ifdef __LP64__	else if (iova_space_size > 512*1024*1024) {		iova_space_size = 512*1024*1024;	}#endif	/*	** iova space must be log2() in size.	** thus, pdir/res_map will also be log2().

⌨️ 快捷键说明

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