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

📄 s3c2510-pcibuf.c

📁 VxWorks BSP for S3C2510A
💻 C
字号:
/* *  linux/arch/arm/mach-s3c2510.c             *  Special pci_map/unmap_single routines for S3C2510  *  * *  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/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/pci.h>//#include "usb_pcipool.h"		// 20030107 remarked by drsohn#include <asm/arch/usb_pcipool.h>		// 20030107 modified by drsohn#include <asm/arch/s3c2510-pcibuf.h>	// 20030107 added by drsohn/* * simple buffer allocator for copying of unsafe to safe buffers * uses __alloc/__free for actual buffers * keeps track of safe buffers we've allocated so we can recover the * unsafe buffers. */#define MAX_SAFE	32#define SIZE_SMALL	1024#define SIZE_LARGE	(16*1024)static long mapped_alloc_size;static char *safe_buffers[MAX_SAFE][2];static struct pci_pool *small_buffer_cache, *large_buffer_cache;static intinit_safe_buffers(struct pci_dev *dev){	small_buffer_cache = usb_pci_pool_create("pci_small_buffer",					    dev,					    SIZE_SMALL,					    0 /* byte alignment */,					    0 /* no page-crossing issues */,					    GFP_KERNEL | GFP_DMA);	if (small_buffer_cache == 0)		return -1;	large_buffer_cache = usb_pci_pool_create("pci_large_buffer",					    dev,					    SIZE_LARGE,					    0 /* byte alignment */,					    0 /* no page-crossing issues */,					    GFP_KERNEL | GFP_DMA);	if (large_buffer_cache == 0)		return -1;	return 0;}/* allocate a 'safe' buffer and keep track of it */static char *alloc_safe_buffer(char *unsafe, int size, dma_addr_t *pbus){	char *safe;	dma_addr_t busptr;	struct pci_pool *pool;	int i;	if (0) printk("alloc_safe_buffer(size=%d)\n", size);	if (size <= SIZE_SMALL)		pool = small_buffer_cache;	else		if (size < SIZE_LARGE)			pool = large_buffer_cache;				else					return 0;	safe = usb_pci_pool_alloc(pool, SLAB_ATOMIC, &busptr);	if (safe == 0)		return 0;	for (i = 0; i < MAX_SAFE; i++)		if (safe_buffers[i][0] == 0) {			break;		}	if (i == MAX_SAFE) {		panic(__FILE__ ": exceeded MAX_SAFE buffers");	}	/* place the size index and the old buffer ptr in the first 8 bytes	 * and return a ptr + 12 to caller	 */	((int *)safe)[0] = i;	((char **)safe)[1] = (char *)pool;	((char **)safe)[2] = unsafe;	busptr += sizeof(int) + sizeof(char *) + sizeof(char *);	safe_buffers[i][0] = (void *)busptr;	safe_buffers[i][1] = (void *)safe;	safe += sizeof(int) + sizeof(char *) + sizeof(char *);	*pbus = busptr;	return safe;}/* determine if a buffer is from our "safe" pool */static char *find_safe_buffer(char *busptr, char **unsafe){	int i;	char *buf;		for (i = 0; i < MAX_SAFE; i++) {		if (safe_buffers[i][0] == busptr) {			if (0) printk("find_safe_buffer(%p) found @ %d\n", busptr, i);			buf = safe_buffers[i][1];			*unsafe = ((char **)buf)[2];			return buf + sizeof(int) + sizeof(char *) + sizeof(char *);		}	}	return (char *)0;}static voidfree_safe_buffer(char *buf){	int index;	struct pci_pool *pool;	char *dma;		if (0) printk("free_safe_buffer(buf=%p)\n", buf);	/* retrieve the buffer size index */	buf -= sizeof(int) + sizeof(char*) + sizeof(char*);	index = ((int *)buf)[0];	pool = (struct pci_pool *)((char **)buf)[1];	if (0) printk("free_safe_buffer(%p) index %d\n",		      buf, index);	if (index < 0 || index >= MAX_SAFE) {		printk(__FILE__ ": free_safe_buffer() corrupt buffer\n");		return;	}	dma = safe_buffers[index][0];	safe_buffers[index][0] = 0;	usb_pci_pool_free(pool, buf, (u32)dma);}/*  NOTE:  replace pci_map/unmap_single with local routines which will  do buffer copies if buffer is above 1mb...*//* * 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_ts3c2510_map_single(struct pci_dev *hwdev, void *virtptr,	       size_t size, int direction){	dma_addr_t busptr;	mapped_alloc_size += size;	if (0) printk("pci_map_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "		      "alloced=%ld\n",		      hwdev, virtptr, size, direction, mapped_alloc_size);	busptr = virt_to_bus(virtptr);	/* we assume here that a buffer will never be >=64k */	if ( (((unsigned long)busptr) & 0x100000) ||	     ((((unsigned long)busptr)+size) & 0x100000) )	{		char *safe;		safe = alloc_safe_buffer(virtptr, size, &busptr);		if (safe == 0) {			printk("unable to map unsafe buffer %p!\n", virtptr);			return 0;		}		if (0) printk("unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",			      virtptr, (void *)virt_to_bus(virtptr),			      safe, (void *)busptr);		memcpy(safe, virtptr, size);		consistent_sync(safe, size, direction);		return busptr;	}	consistent_sync(virtptr, size, direction);	return busptr;}/* * 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) */voids3c2510_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,		 size_t size, int direction){	char *safe, *unsafe;	void *buf;	/* hack; usb-ohci.c never sends hwdev==NULL, all others do */	if (hwdev == NULL) {		return;	}	mapped_alloc_size -= size;	if (0) printk("pci_unmap_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "		      "alloced=%ld\n",		      hwdev, (void *)dma_addr, size, direction,		      mapped_alloc_size);	if ((safe = find_safe_buffer((void *)dma_addr, &unsafe))) {		if (0) printk("copyback unsafe %p, safe %p, size %d\n",			      unsafe, safe, size);		consistent_sync(safe, size, PCI_DMA_FROMDEVICE);		memcpy(unsafe, safe, size);		free_safe_buffer(safe);	} else {		/* assume this is normal memory */		buf = bus_to_virt(dma_addr);		consistent_sync(buf, size, PCI_DMA_FROMDEVICE);	}}EXPORT_SYMBOL(s3c2510_map_single);EXPORT_SYMBOL(s3c2510_unmap_single);static int __init s3c2510_init_safe_buffers(void){	printk("Initializing S3C2510 buffer pool for DMA workaround\n");	init_safe_buffers(NULL);	return 0;}static void free_safe_buffers(void){		usb_pci_pool_destroy(small_buffer_cache);	usb_pci_pool_destroy(large_buffer_cache);}module_init(s3c2510_init_safe_buffers);module_exit(free_safe_buffers);

⌨️ 快捷键说明

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