pcibuf.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/arm/mach-s3c2410/pcibuf.c
  3.  *
  4.  */
  5. #include <linux/module.h>
  6. #include <linux/init.h>
  7. #include <linux/slab.h>
  8. #include <linux/pci.h>
  9. #include "pcipool.h"
  10. //#define PCI_BUF_DEBUG 1
  11. /*
  12.  * simple buffer allocator for copying of unsafe to safe buffers
  13.  * uses __alloc/__free for actual buffers
  14.  * keeps track of safe buffers we've allocated so we can recover the
  15.  * unsafe buffers.
  16.  */
  17. #define MAX_SAFE 32
  18. #define SIZE_SMALL 1024
  19. #define SIZE_LARGE (16*1024)
  20. static long mapped_alloc_size;
  21. static char *safe_buffers[MAX_SAFE][2];
  22. static struct pci_pool *small_buffer_cache, *large_buffer_cache;
  23. static int
  24. init_safe_buffers(struct pci_dev *dev)
  25. {
  26. small_buffer_cache = pci_pool_create("pci_small_buffer",
  27.     dev,
  28.     SIZE_SMALL,
  29.     0 /* byte alignment */,
  30.     0 /* no page-crossing issues */,
  31.     GFP_KERNEL | GFP_DMA);
  32. if (small_buffer_cache == 0)
  33. return -1;
  34. large_buffer_cache = pci_pool_create("pci_large_buffer",
  35.     dev,
  36.     SIZE_LARGE,
  37.     0 /* byte alignment */,
  38.     0 /* no page-crossing issues */,
  39.     GFP_KERNEL | GFP_DMA);
  40. if (large_buffer_cache == 0)
  41. return -1;
  42. return 0;
  43. }
  44. /* allocate a 'safe' buffer and keep track of it */
  45. static char *
  46. alloc_safe_buffer(char *unsafe, int size, dma_addr_t *pbus)
  47. {
  48. char *safe;
  49. dma_addr_t busptr;
  50. struct pci_pool *pool;
  51. int i;
  52. #ifdef PCI_BUF_DEBUG
  53. printk("alloc_safe_buffer(size=%d)n", size);
  54. #endif
  55. if (size <= SIZE_SMALL)
  56. pool = small_buffer_cache;
  57. else
  58. if (size < SIZE_LARGE)
  59. pool = large_buffer_cache;
  60. else
  61. return 0;
  62. safe = pci_pool_alloc(pool, SLAB_ATOMIC, &busptr);
  63. if (safe == 0)
  64. return 0;
  65. for (i = 0; i < MAX_SAFE; i++)
  66. if (safe_buffers[i][0] == 0) {
  67. break;
  68. }
  69. if (i == MAX_SAFE) {
  70. panic(__FILE__ ": exceeded MAX_SAFE buffers");
  71. }
  72. /* place the size index and the old buffer ptr in the first 8 bytes
  73.  * and return a ptr + 12 to caller
  74.  */
  75. ((int *)safe)[0] = i;
  76. ((char **)safe)[1] = (char *)pool;
  77. ((char **)safe)[2] = unsafe;
  78. busptr += sizeof(int) + sizeof(char *) + sizeof(char *);
  79. safe_buffers[i][0] = (void *)busptr;
  80. safe_buffers[i][1] = (void *)safe;
  81. safe += sizeof(int) + sizeof(char *) + sizeof(char *);
  82. *pbus = busptr;
  83. return safe;
  84. }
  85. /* determine if a buffer is from our "safe" pool */
  86. static char *
  87. find_safe_buffer(char *busptr, char **unsafe)
  88. {
  89. int i;
  90. char *buf;
  91. for (i = 0; i < MAX_SAFE; i++) {
  92. if (safe_buffers[i][0] == busptr) {
  93. #ifdef PCI_BUF_DEBUG
  94. printk("find_safe_buffer(%p) found @ %dn", busptr, i);
  95. #endif
  96. buf = safe_buffers[i][1];
  97. *unsafe = ((char **)buf)[2];
  98. return buf + sizeof(int) + sizeof(char *) + sizeof(char *);
  99. }
  100. }
  101. return (char *)0;
  102. }
  103. static void
  104. free_safe_buffer(char *buf)
  105. {
  106. int index;
  107. struct pci_pool *pool;
  108. char *dma;
  109.   
  110. #ifdef PCI_BUF_DEBUG
  111. printk("free_safe_buffer(buf=%p)n", buf);
  112. #endif
  113. /* retrieve the buffer size index */
  114. buf -= sizeof(int) + sizeof(char*) + sizeof(char*);
  115. index = ((int *)buf)[0];
  116. pool = (struct pci_pool *)((char **)buf)[1];
  117. #ifdef PCI_BUF_DEBUG
  118. printk("free_safe_buffer(%p) index %dn", buf, index);
  119. #endif
  120. if (index < 0 || index >= MAX_SAFE) {
  121. printk(__FILE__ ": free_safe_buffer() corrupt buffern");
  122. return;
  123. }
  124. dma = safe_buffers[index][0];
  125. safe_buffers[index][0] = 0;
  126. pci_pool_free(pool, buf, (u32)dma);
  127. }
  128. /*
  129.   NOTE:
  130.   replace pci_map/unmap_single with local routines which will
  131.   do buffer copies if buffer is above 1mb...
  132. */
  133. /*
  134.  * see if a buffer address is in an 'unsafe' range.  if it is
  135.  * allocate a 'safe' buffer and copy the unsafe buffer into it.
  136.  * substitute the safe buffer for the unsafe one.
  137.  * (basically move the buffer from an unsafe area to a safe one)
  138.  *
  139.  * we assume calls to map_single are symmetric with calls to unmap_single...
  140.  */
  141. dma_addr_t
  142. s3c2410_map_single(struct pci_dev *hwdev, void *virtptr,
  143.        size_t size, int direction)
  144. {
  145. dma_addr_t busptr;
  146. mapped_alloc_size += size;
  147. #ifdef PCI_BUF_DEBUG
  148. printk("pci_map_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "
  149.       "alloced=%ldn",
  150.       hwdev, virtptr, size, direction, mapped_alloc_size);
  151. #endif
  152. busptr = virt_to_bus(virtptr);
  153. /* we assume here that a buffer will never be >=64k */
  154. if ( (((unsigned long)busptr) & 0x100000) ||
  155.      ((((unsigned long)busptr)+size) & 0x100000) )
  156. {
  157. char *safe;
  158. safe = alloc_safe_buffer(virtptr, size, &busptr);
  159. if (safe == 0) {
  160. printk("unable to map unsafe buffer %p!n", virtptr);
  161. return 0;
  162. }
  163. #ifdef PCI_BUF_DEBUG
  164. printk("unsafe buffer %p (phy=%p) mapped to %p (phy=%p)n",
  165.       virtptr, (void *)virt_to_bus(virtptr),
  166.       safe, (void *)busptr);
  167. #endif
  168. memcpy(safe, virtptr, size);
  169. consistent_sync(safe, size, direction);
  170. return busptr;
  171. }
  172. consistent_sync(virtptr, size, direction);
  173. return busptr;
  174. }
  175. /*
  176.  * see if a mapped address was really a "safe" buffer and if so,
  177.  * copy the data from the safe buffer back to the unsafe buffer
  178.  * and free up the safe buffer.
  179.  * (basically return things back to the way they should be)
  180.  */
  181. void
  182. s3c2410_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
  183.  size_t size, int direction)
  184. {
  185. char *safe, *unsafe;
  186. void *buf;
  187. /* hack; usb-ohci.c never sends hwdev==NULL, all others do */
  188. if (hwdev == NULL) {
  189. return;
  190. }
  191. mapped_alloc_size -= size;
  192. #ifdef PCI_BUF_DEBUG
  193. printk("pci_unmap_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "
  194.       "alloced=%ldn",
  195.       hwdev, (void *)dma_addr, size, direction,
  196.       mapped_alloc_size);
  197. #endif
  198. if ((safe = find_safe_buffer((void *)dma_addr, &unsafe))) {
  199. #ifdef PCI_BUF_DEBUG
  200. printk("copyback unsafe %p, safe %p, size %dn",
  201.       unsafe, safe, size);
  202. #endif
  203. consistent_sync(safe, size, PCI_DMA_FROMDEVICE);
  204. memcpy(unsafe, safe, size);
  205. free_safe_buffer(safe);
  206. } else {
  207. /* assume this is normal memory */
  208. buf = bus_to_virt(dma_addr);
  209. consistent_sync(buf, size, PCI_DMA_FROMDEVICE);
  210. }
  211. }
  212. EXPORT_SYMBOL(s3c2410_map_single);
  213. EXPORT_SYMBOL(s3c2410_unmap_single);
  214. static int __init s3c2410_init_safe_buffers(void)
  215. {
  216. printk("Initializing S3C2410 buffer pool for DMA workaroundn");
  217. init_safe_buffers(NULL);
  218. return 0;
  219. }
  220. static void free_safe_buffers(void)
  221. {
  222. pci_pool_destroy(small_buffer_cache);
  223. pci_pool_destroy(large_buffer_cache);
  224. }
  225. module_init(s3c2410_init_safe_buffers);
  226. module_exit(free_safe_buffers);