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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: iommu_common.c,v 1.6.2.1 2001/12/11 22:47:27 davem Exp $
  2.  * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
  3.  *
  4.  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  5.  */
  6. #include "iommu_common.h"
  7. /* You are _strongly_ advised to enable the following debugging code
  8.  * any time you make changes to the sg code below, run it for a while
  9.  * with filesystems mounted read-only before buying the farm... -DaveM
  10.  */
  11. #ifdef VERIFY_SG
  12. static int verify_lengths(struct scatterlist *sg, int nents, int npages)
  13. {
  14. int sg_len, dma_len;
  15. int i, pgcount;
  16. sg_len = 0;
  17. for (i = 0; i < nents; i++)
  18. sg_len += sg[i].length;
  19. dma_len = 0;
  20. for (i = 0; i < nents && sg[i].dma_length; i++)
  21. dma_len += sg[i].dma_length;
  22. if (sg_len != dma_len) {
  23. printk("verify_lengths: Error, different, sg[%d] dma[%d]n",
  24.        sg_len, dma_len);
  25. return -1;
  26. }
  27. pgcount = 0;
  28. for (i = 0; i < nents && sg[i].dma_length; i++) {
  29. unsigned long start, end;
  30. start = sg[i].dma_address;
  31. start = start & IO_PAGE_MASK;
  32. end = sg[i].dma_address + sg[i].dma_length;
  33. end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK;
  34. pgcount += ((end - start) >> IO_PAGE_SHIFT);
  35. }
  36. if (pgcount != npages) {
  37. printk("verify_lengths: Error, page count wrong, "
  38.        "npages[%d] pgcount[%d]n",
  39.        npages, pgcount);
  40. return -1;
  41. }
  42. /* This test passes... */
  43. return 0;
  44. }
  45. static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
  46. {
  47. struct scatterlist *sg = *__sg;
  48. iopte_t *iopte = *__iopte;
  49. u32 dlen = dma_sg->dma_length;
  50. u32 daddr;
  51. unsigned int sglen;
  52. unsigned long sgaddr;
  53. daddr = dma_sg->dma_address;
  54. sglen = sg->length;
  55. sgaddr = (unsigned long) (sg->address ?
  56.   sg->address :
  57.   page_address(sg->page) + sg->offset);
  58. while (dlen > 0) {
  59. unsigned long paddr;
  60. /* SG and DMA_SG must begin at the same sub-page boundary. */
  61. if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) {
  62. printk("verify_one_map: Wrong start offset "
  63.        "sg[%08lx] dma[%08x]n",
  64.        sgaddr, daddr);
  65. nents = -1;
  66. goto out;
  67. }
  68. /* Verify the IOPTE points to the right page. */
  69. paddr = iopte_val(*iopte) & IOPTE_PAGE;
  70. if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) {
  71. printk("verify_one_map: IOPTE[%08lx] maps the "
  72.        "wrong page, should be [%08lx]n",
  73.        iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET);
  74. nents = -1;
  75. goto out;
  76. }
  77. /* If this SG crosses a page, adjust to that next page
  78.  * boundary and loop.
  79.  */
  80. if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) {
  81. unsigned long next_page, diff;
  82. next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK;
  83. diff = next_page - sgaddr;
  84. sgaddr += diff;
  85. daddr += diff;
  86. sglen -= diff;
  87. dlen -= diff;
  88. if (dlen > 0)
  89. iopte++;
  90. continue;
  91. }
  92. /* SG wholly consumed within this page. */
  93. daddr += sglen;
  94. dlen -= sglen;
  95. if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0))
  96. iopte++;
  97. sg++;
  98. if (--nents <= 0)
  99. break;
  100. sgaddr = (unsigned long) (sg->address ?
  101.   sg->address :
  102.   page_address(sg->page) + sg->offset);
  103. sglen = sg->length;
  104. }
  105. if (dlen < 0) {
  106. /* Transfer overrun, big problems. */
  107. printk("verify_one_map: Transfer overrun by %d bytes.n",
  108.        -dlen);
  109. nents = -1;
  110. } else {
  111. /* Advance to next dma_sg implies that the next iopte will
  112.  * begin it.
  113.  */
  114. iopte++;
  115. }
  116. out:
  117. *__sg = sg;
  118. *__iopte = iopte;
  119. return nents;
  120. }
  121. static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
  122. {
  123. struct scatterlist *dma_sg = sg;
  124. struct scatterlist *orig_dma_sg = dma_sg;
  125. int orig_nents = nents;
  126. for (;;) {
  127. nents = verify_one_map(dma_sg, &sg, nents, &iopte);
  128. if (nents <= 0)
  129. break;
  130. dma_sg++;
  131. if (dma_sg->dma_length == 0)
  132. break;
  133. }
  134. if (nents > 0) {
  135. printk("verify_maps: dma maps consumed by some sgs remain (%d)n",
  136.        nents);
  137. return -1;
  138. }
  139. if (nents < 0) {
  140. printk("verify_maps: Error, messed up mappings, "
  141.        "at sg %d dma_sg %dn",
  142.        (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg));
  143. return -1;
  144. }
  145. /* This test passes... */
  146. return 0;
  147. }
  148. void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages)
  149. {
  150. if (verify_lengths(sg, nents, npages) < 0 ||
  151.     verify_maps(sg, nents, iopte) < 0) {
  152. int i;
  153. printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
  154. printk("%016lx.n", sg->dma_address & IO_PAGE_MASK);
  155. for (i = 0; i < nents; i++) {
  156. printk("sg(%d): address(%p) length(%x) "
  157.        "dma_address[%016lx] dma_length[%016lx]n",
  158.        i,
  159.        sg[i].address, sg[i].length,
  160.        sg[i].dma_address, sg[i].dma_length);
  161. }
  162. }
  163. /* Seems to be ok */
  164. }
  165. #endif
  166. unsigned long prepare_sg(struct scatterlist *sg, int nents)
  167. {
  168. struct scatterlist *dma_sg = sg;
  169. unsigned long prev;
  170. u32 dent_addr, dent_len;
  171. prev  = (unsigned long) (sg->address ?
  172.  sg->address :
  173.  page_address(sg->page) + sg->offset);
  174. prev += (unsigned long) (dent_len = sg->length);
  175. dent_addr = (u32) ((unsigned long)(sg->address ?
  176.    sg->address :
  177.    page_address(sg->page) + sg->offset)
  178.    & (IO_PAGE_SIZE - 1UL));
  179. while (--nents) {
  180. unsigned long addr;
  181. sg++;
  182. addr = (unsigned long) (sg->address ?
  183. sg->address :
  184. page_address(sg->page) + sg->offset);
  185. if (! VCONTIG(prev, addr)) {
  186. dma_sg->dma_address = dent_addr;
  187. dma_sg->dma_length = dent_len;
  188. dma_sg++;
  189. dent_addr = ((dent_addr +
  190.       dent_len +
  191.       (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT);
  192. dent_addr <<= IO_PAGE_SHIFT;
  193. dent_addr += addr & (IO_PAGE_SIZE - 1UL);
  194. dent_len = 0;
  195. }
  196. dent_len += sg->length;
  197. prev = addr + sg->length;
  198. }
  199. dma_sg->dma_address = dent_addr;
  200. dma_sg->dma_length = dent_len;
  201. return ((unsigned long) dent_addr +
  202. (unsigned long) dent_len +
  203. (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
  204. }