iommu_common.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 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) (page_address(sg->page) + sg->offset);
  56. while (dlen > 0) {
  57. unsigned long paddr;
  58. /* SG and DMA_SG must begin at the same sub-page boundary. */
  59. if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) {
  60. printk("verify_one_map: Wrong start offset "
  61. "sg[%08lx] dma[%08x]\n",
  62. sgaddr, daddr);
  63. nents = -1;
  64. goto out;
  65. }
  66. /* Verify the IOPTE points to the right page. */
  67. paddr = iopte_val(*iopte) & IOPTE_PAGE;
  68. if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) {
  69. printk("verify_one_map: IOPTE[%08lx] maps the "
  70. "wrong page, should be [%08lx]\n",
  71. iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET);
  72. nents = -1;
  73. goto out;
  74. }
  75. /* If this SG crosses a page, adjust to that next page
  76. * boundary and loop.
  77. */
  78. if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) {
  79. unsigned long next_page, diff;
  80. next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK;
  81. diff = next_page - sgaddr;
  82. sgaddr += diff;
  83. daddr += diff;
  84. sglen -= diff;
  85. dlen -= diff;
  86. if (dlen > 0)
  87. iopte++;
  88. continue;
  89. }
  90. /* SG wholly consumed within this page. */
  91. daddr += sglen;
  92. dlen -= sglen;
  93. if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0))
  94. iopte++;
  95. sg++;
  96. if (--nents <= 0)
  97. break;
  98. sgaddr = (unsigned long) (page_address(sg->page) + sg->offset);
  99. sglen = sg->length;
  100. }
  101. if (dlen < 0) {
  102. /* Transfer overrun, big problems. */
  103. printk("verify_one_map: Transfer overrun by %d bytes.\n",
  104. -dlen);
  105. nents = -1;
  106. } else {
  107. /* Advance to next dma_sg implies that the next iopte will
  108. * begin it.
  109. */
  110. iopte++;
  111. }
  112. out:
  113. *__sg = sg;
  114. *__iopte = iopte;
  115. return nents;
  116. }
  117. static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
  118. {
  119. struct scatterlist *dma_sg = sg;
  120. struct scatterlist *orig_dma_sg = dma_sg;
  121. int orig_nents = nents;
  122. for (;;) {
  123. nents = verify_one_map(dma_sg, &sg, nents, &iopte);
  124. if (nents <= 0)
  125. break;
  126. dma_sg++;
  127. if (dma_sg->dma_length == 0)
  128. break;
  129. }
  130. if (nents > 0) {
  131. printk("verify_maps: dma maps consumed by some sgs remain (%d)\n",
  132. nents);
  133. return -1;
  134. }
  135. if (nents < 0) {
  136. printk("verify_maps: Error, messed up mappings, "
  137. "at sg %d dma_sg %d\n",
  138. (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg));
  139. return -1;
  140. }
  141. /* This test passes... */
  142. return 0;
  143. }
  144. void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages)
  145. {
  146. if (verify_lengths(sg, nents, npages) < 0 ||
  147. verify_maps(sg, nents, iopte) < 0) {
  148. int i;
  149. printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
  150. printk("%016lx.\n", sg->dma_address & IO_PAGE_MASK);
  151. for (i = 0; i < nents; i++) {
  152. printk("sg(%d): page_addr(%p) off(%x) length(%x) "
  153. "dma_address[%016lx] dma_length[%016lx]\n",
  154. i,
  155. page_address(sg[i].page), sg[i].offset,
  156. sg[i].length,
  157. sg[i].dma_address, sg[i].dma_length);
  158. }
  159. }
  160. /* Seems to be ok */
  161. }
  162. #endif
  163. unsigned long prepare_sg(struct scatterlist *sg, int nents)
  164. {
  165. struct scatterlist *dma_sg = sg;
  166. unsigned long prev;
  167. u32 dent_addr, dent_len;
  168. prev = (unsigned long) (page_address(sg->page) + sg->offset);
  169. prev += (unsigned long) (dent_len = sg->length);
  170. dent_addr = (u32) ((unsigned long)(page_address(sg->page) + sg->offset)
  171. & (IO_PAGE_SIZE - 1UL));
  172. while (--nents) {
  173. unsigned long addr;
  174. sg++;
  175. addr = (unsigned long) (page_address(sg->page) + sg->offset);
  176. if (! VCONTIG(prev, addr)) {
  177. dma_sg->dma_address = dent_addr;
  178. dma_sg->dma_length = dent_len;
  179. dma_sg++;
  180. dent_addr = ((dent_addr +
  181. dent_len +
  182. (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT);
  183. dent_addr <<= IO_PAGE_SHIFT;
  184. dent_addr += addr & (IO_PAGE_SIZE - 1UL);
  185. dent_len = 0;
  186. }
  187. dent_len += sg->length;
  188. prev = addr + sg->length;
  189. }
  190. dma_sg->dma_address = dent_addr;
  191. dma_sg->dma_length = dent_len;
  192. return ((unsigned long) dent_addr +
  193. (unsigned long) dent_len +
  194. (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
  195. }