consistent.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:4k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/arm/mm/consistent.c
  3.  *
  4.  *  Copyright (C) 2000 Russell King
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License version 2 as
  8.  * published by the Free Software Foundation.
  9.  *
  10.  *  Dynamic DMA mapping support.
  11.  */
  12. #include <linux/config.h>
  13. #include <linux/types.h>
  14. #include <linux/mm.h>
  15. #include <linux/string.h>
  16. #include <linux/vmalloc.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/errno.h>
  19. #include <linux/pci.h>
  20. #include <linux/init.h>
  21. #include <asm/io.h>
  22. #include <asm/pgtable.h>
  23. #include <asm/pgalloc.h>
  24. /*
  25.  * This allocates one page of cache-coherent memory space and returns
  26.  * both the virtual and a "dma" address to that space.  It is not clear
  27.  * whether this could be called from an interrupt context or not.  For
  28.  * now, we expressly forbid it, especially as some of the stuff we do
  29.  * here is not interrupt context safe.
  30.  *
  31.  * Note that this does *not* zero the allocated area!
  32.  */
  33. void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
  34. {
  35. struct page *page, *end, *free;
  36. unsigned long order;
  37. void *ret, *virt;
  38. if (in_interrupt())
  39. BUG();
  40. size = PAGE_ALIGN(size);
  41. order = get_order(size);
  42. page = alloc_pages(gfp, order);
  43. if (!page)
  44. goto no_page;
  45. /*
  46.  * We could do with a page_to_phys and page_to_bus here.
  47.  */
  48. virt = page_address(page);
  49. *dma_handle = virt_to_bus(virt);
  50. ret = __ioremap(virt_to_phys(virt), size, 0);
  51. if (!ret)
  52. goto no_remap;
  53. #if 0 /* ioremap_does_flush_cache_all */
  54. /*
  55.  * we need to ensure that there are no cachelines in use, or
  56.  * worse dirty in this area.  Really, we don't need to do
  57.  * this since __ioremap does a flush_cache_all() anyway. --rmk
  58.  */
  59. invalidate_dcache_range(virt, virt + size);
  60. #endif
  61. /*
  62.  * free wasted pages.  We skip the first page since we know
  63.  * that it will have count = 1 and won't require freeing.
  64.  * We also mark the pages in use as reserved so that
  65.  * remap_page_range works.
  66.  */
  67. page = virt_to_page(virt);
  68. free = page + (size >> PAGE_SHIFT);
  69. end  = page + (1 << order);
  70. for (; page < end; page++) {
  71. set_page_count(page, 1);
  72. if (page >= free)
  73. __free_page(page);
  74. else
  75. SetPageReserved(page);
  76. }
  77. return ret;
  78. no_remap:
  79. __free_pages(page, order);
  80. no_page:
  81. return NULL;
  82. }
  83. void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *handle)
  84. {
  85. void *__ret;
  86. int __gfp = GFP_KERNEL;
  87. #ifdef CONFIG_PCI
  88. if ((hwdev) == NULL ||
  89.     (hwdev)->dma_mask != 0xffffffff)
  90. #endif
  91. __gfp |= GFP_DMA;
  92. __ret = consistent_alloc(__gfp, (size),
  93.  (handle));
  94. return __ret;
  95. }
  96. /*
  97.  * free a page as defined by the above mapping.  We expressly forbid
  98.  * calling this from interrupt context.
  99.  */
  100. void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
  101. {
  102. struct page *page, *end;
  103. void *virt;
  104. if (in_interrupt())
  105. BUG();
  106. virt = bus_to_virt(handle);
  107. /*
  108.  * More messing around with the MM internals.  This is
  109.  * sick, but then so is remap_page_range().
  110.  */
  111. size = PAGE_ALIGN(size);
  112. page = virt_to_page(virt);
  113. end = page + (size >> PAGE_SHIFT);
  114. for (; page < end; page++)
  115. ClearPageReserved(page);
  116. __iounmap(vaddr);
  117. }
  118. /*
  119.  * make an area consistent.
  120.  */
  121. void consistent_sync(void *vaddr, size_t size, int direction)
  122. {
  123. unsigned long start = (unsigned long)vaddr;
  124. unsigned long end   = start + size;
  125. switch (direction) {
  126. case PCI_DMA_NONE:
  127. BUG();
  128. case PCI_DMA_FROMDEVICE: /* invalidate only */
  129. invalidate_dcache_range(start, end);
  130. break;
  131. case PCI_DMA_TODEVICE: /* writeback only */
  132. clean_dcache_range(start, end);
  133. break;
  134. case PCI_DMA_BIDIRECTIONAL: /* writeback and invalidate */
  135. flush_dcache_range(start, end);
  136. break;
  137. }
  138. }