scatterlist.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef SCATTERLIST_H
  3. #define SCATTERLIST_H
  4. #include <linux/kernel.h>
  5. struct scatterlist {
  6. unsigned long page_link;
  7. unsigned int offset;
  8. unsigned int length;
  9. dma_addr_t dma_address;
  10. };
  11. /* Scatterlist helpers, stolen from linux/scatterlist.h */
  12. #define sg_is_chain(sg) ((sg)->page_link & 0x01)
  13. #define sg_is_last(sg) ((sg)->page_link & 0x02)
  14. #define sg_chain_ptr(sg) \
  15. ((struct scatterlist *) ((sg)->page_link & ~0x03))
  16. /**
  17. * sg_assign_page - Assign a given page to an SG entry
  18. * @sg: SG entry
  19. * @page: The page
  20. *
  21. * Description:
  22. * Assign page to sg entry. Also see sg_set_page(), the most commonly used
  23. * variant.
  24. *
  25. **/
  26. static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
  27. {
  28. unsigned long page_link = sg->page_link & 0x3;
  29. /*
  30. * In order for the low bit stealing approach to work, pages
  31. * must be aligned at a 32-bit boundary as a minimum.
  32. */
  33. BUG_ON((unsigned long) page & 0x03);
  34. #ifdef CONFIG_DEBUG_SG
  35. BUG_ON(sg_is_chain(sg));
  36. #endif
  37. sg->page_link = page_link | (unsigned long) page;
  38. }
  39. /**
  40. * sg_set_page - Set sg entry to point at given page
  41. * @sg: SG entry
  42. * @page: The page
  43. * @len: Length of data
  44. * @offset: Offset into page
  45. *
  46. * Description:
  47. * Use this function to set an sg entry pointing at a page, never assign
  48. * the page directly. We encode sg table information in the lower bits
  49. * of the page pointer. See sg_page() for looking up the page belonging
  50. * to an sg entry.
  51. *
  52. **/
  53. static inline void sg_set_page(struct scatterlist *sg, struct page *page,
  54. unsigned int len, unsigned int offset)
  55. {
  56. sg_assign_page(sg, page);
  57. sg->offset = offset;
  58. sg->length = len;
  59. }
  60. static inline struct page *sg_page(struct scatterlist *sg)
  61. {
  62. #ifdef CONFIG_DEBUG_SG
  63. BUG_ON(sg_is_chain(sg));
  64. #endif
  65. return (struct page *)((sg)->page_link & ~0x3);
  66. }
  67. /*
  68. * Loop over each sg element, following the pointer to a new list if necessary
  69. */
  70. #define for_each_sg(sglist, sg, nr, __i) \
  71. for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
  72. /**
  73. * sg_chain - Chain two sglists together
  74. * @prv: First scatterlist
  75. * @prv_nents: Number of entries in prv
  76. * @sgl: Second scatterlist
  77. *
  78. * Description:
  79. * Links @prv@ and @sgl@ together, to form a longer scatterlist.
  80. *
  81. **/
  82. static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
  83. struct scatterlist *sgl)
  84. {
  85. /*
  86. * offset and length are unused for chain entry. Clear them.
  87. */
  88. prv[prv_nents - 1].offset = 0;
  89. prv[prv_nents - 1].length = 0;
  90. /*
  91. * Set lowest bit to indicate a link pointer, and make sure to clear
  92. * the termination bit if it happens to be set.
  93. */
  94. prv[prv_nents - 1].page_link = ((unsigned long) sgl | 0x01) & ~0x02;
  95. }
  96. /**
  97. * sg_mark_end - Mark the end of the scatterlist
  98. * @sg: SG entryScatterlist
  99. *
  100. * Description:
  101. * Marks the passed in sg entry as the termination point for the sg
  102. * table. A call to sg_next() on this entry will return NULL.
  103. *
  104. **/
  105. static inline void sg_mark_end(struct scatterlist *sg)
  106. {
  107. /*
  108. * Set termination bit, clear potential chain bit
  109. */
  110. sg->page_link |= 0x02;
  111. sg->page_link &= ~0x01;
  112. }
  113. /**
  114. * sg_unmark_end - Undo setting the end of the scatterlist
  115. * @sg: SG entryScatterlist
  116. *
  117. * Description:
  118. * Removes the termination marker from the given entry of the scatterlist.
  119. *
  120. **/
  121. static inline void sg_unmark_end(struct scatterlist *sg)
  122. {
  123. sg->page_link &= ~0x02;
  124. }
  125. static inline struct scatterlist *sg_next(struct scatterlist *sg)
  126. {
  127. if (sg_is_last(sg))
  128. return NULL;
  129. sg++;
  130. if (unlikely(sg_is_chain(sg)))
  131. sg = sg_chain_ptr(sg);
  132. return sg;
  133. }
  134. static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
  135. {
  136. memset(sgl, 0, sizeof(*sgl) * nents);
  137. sg_mark_end(&sgl[nents - 1]);
  138. }
  139. static inline dma_addr_t sg_phys(struct scatterlist *sg)
  140. {
  141. return page_to_phys(sg_page(sg)) + sg->offset;
  142. }
  143. static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
  144. unsigned int buflen)
  145. {
  146. sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
  147. }
  148. static inline void sg_init_one(struct scatterlist *sg,
  149. const void *buf, unsigned int buflen)
  150. {
  151. sg_init_table(sg, 1);
  152. sg_set_buf(sg, buf, buflen);
  153. }
  154. #endif /* SCATTERLIST_H */