⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci-gart.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Dynamic DMA mapping support for AMD Hammer. *  * Use the integrated AGP GART in the Hammer northbridge as an IOMMU for PCI. * This allows to use PCI devices that only support 32bit addresses on systems * with more than 4GB.  * * See Documentation/DMA-mapping.txt for the interface specification. *  * Copyright 2002 Andi Kleen, SuSE Labs. * $Id: pci-gart.c,v 1.18 2002/11/30 03:46:14 ak Exp $ *//*  * Notebook:agpgart_be check if the simple reservation scheme is enough.possible future tuning:  fast path for sg streaming mappings  more intelligent flush strategy - flush only a single NB? flush only when gart area fills up and alloc_iommu wraps.  don't flush on allocation - need to unmap the gart area first to avoid prefetches by the CPU move boundary between IOMMU and AGP in GART dynamically  */ #include <linux/config.h>#include <linux/types.h>#include <linux/ctype.h>#include <linux/agp_backend.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/spinlock.h>#include <linux/pci.h>#include <linux/module.h>#include <asm/io.h>#include <asm/mtrr.h>#include <asm/bitops.h>#include <asm/pgtable.h>#include <asm/proto.h>#include "pci-x86_64.h"unsigned long iommu_bus_base;	/* GART remapping area (physical) */static unsigned long iommu_size; 	/* size of remapping area bytes */static unsigned long iommu_pages;	/* .. and in pages */u32 *iommu_gatt_base; 		/* Remapping table */int no_iommu; static int no_agp; #ifdef CONFIG_IOMMU_DEBUGint force_mmu = 1;#elseint force_mmu = 0;#endifextern int fallback_aper_order;extern int fallback_aper_force;/* Allocation bitmap for the remapping area */ static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED;static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */#define GPTE_VALID    1#define GPTE_COHERENT 2#define GPTE_ENCODE(x) (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT)#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28))#define for_all_nb(dev) \	pci_for_each_dev(dev) \		if (dev->bus->number == 0 && PCI_FUNC(dev->devfn) == 3 && \		    (PCI_SLOT(dev->devfn) >= 24) && (PCI_SLOT(dev->devfn) <= 31))#define EMERGENCY_PAGES 32 /* = 128KB */ #ifdef CONFIG_AGPextern int agp_init(void);#define AGPEXTERN extern#else#define AGPEXTERN#endif/* backdoor interface to AGP driver */AGPEXTERN int agp_memory_reserved;AGPEXTERN __u32 *agp_gatt_table;static unsigned long next_bit;  /* protected by iommu_bitmap_lock */static unsigned long alloc_iommu(int size) { 		unsigned long offset, flags;	spin_lock_irqsave(&iommu_bitmap_lock, flags);		offset = find_next_zero_string(iommu_gart_bitmap,next_bit,iommu_pages,size);	if (offset == -1) 	       	offset = find_next_zero_string(iommu_gart_bitmap,0,next_bit,size);	if (offset != -1) { 		set_bit_string(iommu_gart_bitmap, offset, size); 		next_bit = offset+size; 		if (next_bit >= iommu_pages) 			next_bit = 0;	} 	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);      	return offset;} static void free_iommu(unsigned long offset, int size){ 	unsigned long flags;	spin_lock_irqsave(&iommu_bitmap_lock, flags);	clear_bit_string(iommu_gart_bitmap, offset, size);	next_bit = offset;	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);} static inline void flush_gart(void) { 	struct pci_dev *nb; 	for_all_nb(nb) { 		u32 flag; 		pci_read_config_dword(nb, 0x9c, &flag); /* could cache this */ 		/* could complain for PTE walk errors here (bit 1 of flag) */ 		flag |= 1; 		pci_write_config_dword(nb, 0x9c, flag); 	} } void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,			   dma_addr_t *dma_handle){	void *memory;	int gfp = GFP_ATOMIC;	int i;	unsigned long iommu_page;	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu)		gfp |= GFP_DMA;	/* 	 * First try to allocate continuous and use directly if already 	 * in lowmem. 	 */ 	size = round_up(size, PAGE_SIZE); 	memory = (void *)__get_free_pages(gfp, get_order(size));	if (memory == NULL) {		return NULL; 	} else {		int high = (unsigned long)virt_to_bus(memory) + size			>= 0xffffffff;		int mmu = high;		if (force_mmu) 			mmu = 1;		if (no_iommu) { 			if (high) goto error;			mmu = 0; 		} 			memset(memory, 0, size); 		if (!mmu) { 			*dma_handle = virt_to_bus(memory);			return memory;		}	} 	size >>= PAGE_SHIFT;	iommu_page = alloc_iommu(size);	if (iommu_page == -1)		goto error;    	/* Fill in the GATT, allocating pages as needed. */	for (i = 0; i < size; i++) { 		unsigned long phys_mem; 		void *mem = memory + i*PAGE_SIZE;		if (i > 0) 			atomic_inc(&virt_to_page(mem)->count); 		phys_mem = virt_to_phys(mem); 		BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); 		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); 	} 	flush_gart();	*dma_handle = iommu_bus_base + (iommu_page << PAGE_SHIFT);	return memory; 	 error:	free_pages((unsigned long)memory, get_order(size)); 	return NULL; }/*  * Unmap consistent memory. * The caller must ensure that the device has finished accessing the mapping. */void pci_free_consistent(struct pci_dev *hwdev, size_t size,			 void *vaddr, dma_addr_t bus){	u64 pte;	unsigned long iommu_page;	int i;	size = round_up(size, PAGE_SIZE); 	if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { 		free_pages((unsigned long)vaddr, get_order(size)); 				return;	} 	size >>= PAGE_SHIFT;	iommu_page = (bus - iommu_bus_base) / PAGE_SIZE;	for (i = 0; i < size; i++) {		pte = iommu_gatt_base[iommu_page + i];		BUG_ON((pte & GPTE_VALID) == 0); 		iommu_gatt_base[iommu_page + i] = 0; 				free_page((unsigned long) __va(GPTE_DECODE(pte)));	} 	flush_gart(); 	free_iommu(iommu_page, size);}#ifdef CONFIG_IOMMU_DEBUG/* Debugging aid for drivers that don't free their IOMMU tables */static void **iommu_leak_tab; static int leak_trace;int iommu_leak_pages = 20; extern unsigned long printk_address(unsigned long);void dump_leak(void){	int i;	static int dump; 	if (dump || !iommu_leak_tab) return;	dump = 1;	show_stack(NULL);	/* Very crude. dump some from the end of the table too */ 	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_pages); 	for (i = 0; i < iommu_leak_pages; i+=2) {		printk("%lu: ", iommu_pages-i);		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i]);		printk("%c", (i+1)%2 == 0 ? '\n' : ' '); 	} 	printk("\n");}#endifstatic void iommu_full(struct pci_dev *dev, void *addr, size_t size, int dir){	/* 	 * Ran out of IOMMU space for this operation. This is very bad.	 * Unfortunately the drivers cannot handle this operation properly.	 * Return some non mapped prereserved space in the aperture and 	 * let the Northbridge deal with it. This will result in garbage	 * in the IO operation. When the size exceeds the prereserved space	 * memory corruption will occur or random memory will be DMAed 	 * out. Hopefully no network devices use single mappings that big.	 */ 		printk(KERN_ERR   "PCI-DMA: Error: ran out out IOMMU space for %p size %lu at device %s[%s]\n",	       addr,size, dev ? dev->name : "?", dev ? dev->slot_name : "?");	if (size > PAGE_SIZE*EMERGENCY_PAGES) {		if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)			panic("PCI-DMA: Memory will be corrupted\n");		if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) 			panic("PCI-DMA: Random memory will be DMAed\n"); 	} #ifdef CONFIG_IOMMU_DEBUG	dump_leak(); #endif} static inline int need_iommu(struct pci_dev *dev, unsigned long addr, size_t size){ 	u64 mask = dev ? dev->dma_mask : 0xffffffff;	int high = (~mask & (unsigned long)(addr + size)) != 0;	int mmu = high;	if (force_mmu) 		mmu = 1; 	if (no_iommu) { 		if (high) 			panic("pci_map_single: high address but no IOMMU.\n"); 		mmu = 0; 	} 		return mmu; }dma_addr_t __pci_map_single(struct pci_dev *dev, void *addr, size_t size,			    int dir, int flush){ 	unsigned long iommu_page;

⌨️ 快捷键说明

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