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

📄 pcibuf.c.new

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 NEW
字号:
/* *  linux/arch/arm/mach-s3c2410/pcibuf.c * *  Special pci_{map/unmap/dma_sync}_* routines for S3C2410. * *  These functions utilize bouncer buffers to compensate for a bug in *  the S3C2410 hardware which don't allow DMA to/from addresses *  certain addresses above 1MB. * *  Re-written by kingmonkey <kangdazhi@163.com> *  Re-written by Christopher Hoover <ch@murgatroid.com> *  Original version by Brad Parker (brad@heeltoe.com) * *  Copyright (C) 2002 Hewlett Packard Company. * *  This program is free software; you can redistribute it and/or *  modify it under the terms of the GNU General Public License *  version 2 as published by the Free Software Foundation. * */#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/list.h>#include "pcipool.h"//#define PCI_BUF_DEBUG 1/* * 26 bits of the S3C2410 address bus are available to the S3C2410. * Use these when feeding target addresses to the DMA engines. */#define S3C2410_ADDR_WIDTH	(26)#define S3C2410_ADDR_MASK		((1<<S3C2410_ADDR_WIDTH)-1)#define S3C2410_DMA_ADDR(x)	((x)&S3C2410_ADDR_MASK)struct safe_buffer {	struct list_head node;	/* original request */	void		*ptr;	size_t		size;	int		direction;	/* safe buffer info */	struct pci_pool *pool;	void		*safe;	dma_addr_t	safe_dma_addr;};LIST_HEAD(safe_buffers);#define SIZE_SMALL	1024#define SIZE_LARGE	(16*1024)static struct pci_pool *small_buffer_pool, *large_buffer_pool;static intinit_safe_buffers(){	small_buffer_pool = pci_pool_create("pci_small_buffer",					    S3C2410_FAKE_PCIDEV,					    SIZE_SMALL,					    0 /* byte alignment */,					    0 /* no page-crossing issues */,					    GFP_KERNEL | GFP_DMA);	if (small_buffer_pool == 0){		printk(KERN_ERR"%s: could not allocate small pci pool\n", __func__);		return -1;	}	large_buffer_pool = pci_pool_create("pci_large_buffer",					    S3C2410_FAKE_PCIDEV,					    SIZE_LARGE,					    0 /* byte alignment */,					    0 /* no page-crossing issues */,					    GFP_KERNEL | GFP_DMA);	if (large_buffer_pool == 0){		printk(KERN_ERR"%s: could not allocate large pci pool\n", __func__);		pci_pool_destroy(small_buffer_pool);				small_buffer_pool = 0;		return -1;	}	return 0;}static void __exitdestroy_safe_buffer_pools(void){	if (small_buffer_pool)		pci_pool_destroy(small_buffer_pool);	if (large_buffer_pool)		pci_pool_destroy(large_buffer_pool);	small_buffer_pool = large_buffer_pool = 0;}/* allocate a 'safe' buffer and keep track of it */static struct safe_buffer *alloc_safe_buffer(void *ptr, size_t size, int direction){	struct safe_buffer *buf;	struct pci_pool *pool;	void *safe;	dma_addr_t safe_dma_addr;#ifdef PCI_BUF_DEBUG	printk("%s: alloc_safe_buffer(size=%d)\n", __func__, size);#endif	buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);	if (buf == 0) {		printk(KERN_WARNING "%s: kmalloc failed\n", __func__);		return 0;	}	if (size <= SIZE_SMALL) {		pool = small_buffer_pool;		safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);	} else if (size <= SIZE_LARGE) {		pool = large_buffer_pool;		safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);	} else {#ifdef PCI_BUF_DEBUG		printk(KERN_DEBUG "%s: resorting to pci_alloc_consistent\n"__func__);#endif		pool = 0;		safe = pci_alloc_consistent(S3C2410_FAKE_PCIDEV, size,&safe_dma_addr);	}	if (safe == 0) {		printk(KERN_WARNING"%s: could not alloc dma memory (size=%d)\n",__func__, size);		kfree(buf);		return 0;	}	buf->ptr = ptr;	buf->size = size;	buf->direction = direction;	buf->pool = pool;	buf->safe = safe;	buf->safe_dma_addr = safe_dma_addr;	MOD_INC_USE_COUNT;	list_add(&buf->node, &safe_buffers);	return buf;}/* determine if a buffer is from our "safe" pool */static struct safe_buffer *find_safe_buffer(dma_addr_t safe_dma_addr){	struct list_head *entry;	list_for_each(entry, &safe_buffers) {		struct safe_buffer *b =	list_entry(entry, struct safe_buffer, node);		if (b->safe_dma_addr == safe_dma_addr) {			return b;		}	}	return 0;}static voidfree_safe_buffer(struct safe_buffer *buf){#ifdef PCI_BUF_DEBUG	printk("%s: free_safe_buffer(buf=%p)\n", __func__,buf);#endif		list_del(&buf->node);	if (buf->pool)		pci_pool_free(buf->pool, buf->safe, buf->safe_dma_addr);	else		pci_free_consistent(S3C2410_FAKE_PCIDEV, buf->size, buf->safe,				    buf->safe_dma_addr);	kfree(buf);	MOD_DEC_USE_COUNT;}static inline intdma_range_is_safe(dma_addr_t addr, size_t size){	unsigned int physaddr = S3C2410_DMA_ADDR((unsigned int) addr );	/* Any address within one megabyte of the start of the target         * bank will be OK.  This is an overly conservative test:         * other addresses can be OK depending on the dram         * configuration.  	 *	 * We take care to ensure the entire dma region is within	 * the safe range.	 */		return ((physaddr + size - 1) < (1<<20));}/* * see if a buffer address is in an 'unsafe' range.  if it is * allocate a 'safe' buffer and copy the unsafe buffer into it. * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) * * we assume calls to map_single are symmetric with calls to unmap_single... */dma_addr_ts3c2410_map_single(struct pci_dev *hwdev, void *virtptr,	       size_t size, int direction){	unsigned long flags;	dma_addr_t dma_addr;#ifdef PCI_BUF_DEBUG	printk("%s: pci_map_single(hwdev=%p,ptr=%p,size=%d,dir=%x)  \n",		      __func__,hwdev, virtptr, size, direction);#endif	local_irq_save(flags);	dma_addr = virt_to_bus(virtptr);	/* we assume here that a buffer will never be >=64k *///	if ( (((unsigned long)dma_addr) & 0x100000) ||//	     ((((unsigned long)dma_addr)+size) & 0x100000) )	if(!dma_range_is_safe(dma_addr, size))	{		struct safe_buffer *buf;		buf = alloc_safe_buffer(virtptr, size, direction);		if (buf == 0) {			printk(KERN_ERR			       "%s: unable to map unsafe buffer %p!\n",			       __func__, virtptr);			local_irq_restore(flags);			return 0;		}#ifdef PCI_BUF_DEBUG		printk("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",			__func__,			buf->ptr, (void *) virt_to_bus(buf->ptr),			buf->safe, (void *) buf->safe_dma_addr);#endif		if ((direction == PCI_DMA_TODEVICE) ||(direction == PCI_DMA_BIDIRECTIONAL)) {#ifdef PCI_BUF_DEBUG	 			printk("%s: copy out from unsafe %p, to safe %p, size %d\n",__func__, virtptr, buf->safe, size);#endif			memcpy(buf->safe, virtptr, size);		}		consistent_sync(buf->safe, size, direction);	} else {		consistent_sync(virtptr, size, direction);	}	local_irq_restore(flags);	return dma_addr;}/* * see if a mapped address was really a "safe" buffer and if so, * copy the data from the safe buffer back to the unsafe buffer * and free up the safe buffer. * (basically return things back to the way they should be) */voids3c2410_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,		 size_t size, int direction){	unsigned long flags;	struct safe_buffer *buf;	void *tmp;#ifdef PCI_BUF_DEBUG	printk("%s(ptr=%p,size=%d,dir=%x)\n",		__func__, (void *) dma_addr, size, direction);#endif	if(direction == PCI_DMA_NONE)		BUG();	local_irq_save(flags);	buf = find_safe_buffer(dma_addr);	if (buf) {		if(buf->size != size)			BUG();		if(buf->direction != direction)			BUG();#ifdef PCI_BUF_DEBUG		printk("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",			__func__,			buf->ptr, (void *) virt_to_bus(buf->ptr),			buf->safe, (void *) buf->safe_dma_addr);#endif		if ((direction == PCI_DMA_FROMDEVICE) ||		    (direction == PCI_DMA_BIDIRECTIONAL)) {#ifdef PCI_BUF_DEBUG		    			printk("%s: copy back from safe %p, to unsafe %p size %d\n",				__func__, buf->safe, buf->ptr, size);#endif			memcpy(buf->ptr, buf->safe, size);			free_safe_buffer(buf);		}	}else	{		/* assume this is normal memory */		tmp = bus_to_virt(dma_addr);		consistent_sync(tmp, size, PCI_DMA_FROMDEVICE);	}	local_irq_restore(flags);}EXPORT_SYMBOL(s3c2410_map_single);EXPORT_SYMBOL(s3c2410_unmap_single);static int __init s3c2410_init_safe_buffers(void){	int ret;	printk("Initializing S3C2410 buffer pool for DMA workaround\n");		ret=init_safe_buffers();	return ret;}static void __exit s3c2410_free_safe_buffers(void){	if(!list_empty(&safe_buffers))		BUG();	destroy_safe_buffer_pools();}module_init(s3c2410_init_safe_buffers);module_exit(s3c2410_free_safe_buffers);MODULE_AUTHOR("kingmonkey <kangdazhi@163.com>");MODULE_DESCRIPTION("Special pci_{map/unmap/dma_sync}_* routines for S3C2410	.");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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