rx.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (C) 2024 Intel Corporation */
  3. #include <net/libeth/rx.h>
  4. /* Rx buffer management */
  5. /**
  6. * libeth_rx_hw_len_mtu - get the actual buffer size to be passed to HW
  7. * @pp: &page_pool_params of the netdev to calculate the size for
  8. * @max_len: maximum buffer size for a single descriptor
  9. *
  10. * Return: HW-writeable length per one buffer to pass it to the HW accounting:
  11. * MTU the @dev has, HW required alignment, minimum and maximum allowed values,
  12. * and system's page size.
  13. */
  14. static u32 libeth_rx_hw_len_mtu(const struct page_pool_params *pp, u32 max_len)
  15. {
  16. u32 len;
  17. len = READ_ONCE(pp->netdev->mtu) + LIBETH_RX_LL_LEN;
  18. len = ALIGN(len, LIBETH_RX_BUF_STRIDE);
  19. len = min3(len, ALIGN_DOWN(max_len ? : U32_MAX, LIBETH_RX_BUF_STRIDE),
  20. pp->max_len);
  21. return len;
  22. }
  23. /**
  24. * libeth_rx_hw_len_truesize - get the short buffer size to be passed to HW
  25. * @pp: &page_pool_params of the netdev to calculate the size for
  26. * @max_len: maximum buffer size for a single descriptor
  27. * @truesize: desired truesize for the buffers
  28. *
  29. * Return: HW-writeable length per one buffer to pass it to the HW ignoring the
  30. * MTU and closest to the passed truesize. Can be used for "short" buffer
  31. * queues to fragment pages more efficiently.
  32. */
  33. static u32 libeth_rx_hw_len_truesize(const struct page_pool_params *pp,
  34. u32 max_len, u32 truesize)
  35. {
  36. u32 min, len;
  37. min = SKB_HEAD_ALIGN(pp->offset + LIBETH_RX_BUF_STRIDE);
  38. truesize = clamp(roundup_pow_of_two(truesize), roundup_pow_of_two(min),
  39. PAGE_SIZE << LIBETH_RX_PAGE_ORDER);
  40. len = SKB_WITH_OVERHEAD(truesize - pp->offset);
  41. len = ALIGN_DOWN(len, LIBETH_RX_BUF_STRIDE) ? : LIBETH_RX_BUF_STRIDE;
  42. len = min3(len, ALIGN_DOWN(max_len ? : U32_MAX, LIBETH_RX_BUF_STRIDE),
  43. pp->max_len);
  44. return len;
  45. }
  46. /**
  47. * libeth_rx_page_pool_params - calculate params with the stack overhead
  48. * @fq: buffer queue to calculate the size for
  49. * @pp: &page_pool_params of the netdev
  50. *
  51. * Set the PP params to will all needed stack overhead (headroom, tailroom) and
  52. * both the HW buffer length and the truesize for all types of buffers. For
  53. * "short" buffers, truesize never exceeds the "wanted" one; for the rest,
  54. * it can be up to the page size.
  55. *
  56. * Return: true on success, false on invalid input params.
  57. */
  58. static bool libeth_rx_page_pool_params(struct libeth_fq *fq,
  59. struct page_pool_params *pp)
  60. {
  61. pp->offset = LIBETH_SKB_HEADROOM;
  62. /* HW-writeable / syncable length per one page */
  63. pp->max_len = LIBETH_RX_PAGE_LEN(pp->offset);
  64. /* HW-writeable length per buffer */
  65. switch (fq->type) {
  66. case LIBETH_FQE_MTU:
  67. fq->buf_len = libeth_rx_hw_len_mtu(pp, fq->buf_len);
  68. break;
  69. case LIBETH_FQE_SHORT:
  70. fq->buf_len = libeth_rx_hw_len_truesize(pp, fq->buf_len,
  71. fq->truesize);
  72. break;
  73. case LIBETH_FQE_HDR:
  74. fq->buf_len = ALIGN(LIBETH_MAX_HEAD, LIBETH_RX_BUF_STRIDE);
  75. break;
  76. default:
  77. return false;
  78. }
  79. /* Buffer size to allocate */
  80. fq->truesize = roundup_pow_of_two(SKB_HEAD_ALIGN(pp->offset +
  81. fq->buf_len));
  82. return true;
  83. }
  84. /**
  85. * libeth_rx_page_pool_params_zc - calculate params without the stack overhead
  86. * @fq: buffer queue to calculate the size for
  87. * @pp: &page_pool_params of the netdev
  88. *
  89. * Set the PP params to exclude the stack overhead and both the buffer length
  90. * and the truesize, which are equal for the data buffers. Note that this
  91. * requires separate header buffers to be always active and account the
  92. * overhead.
  93. * With the MTU == ``PAGE_SIZE``, this allows the kernel to enable the zerocopy
  94. * mode.
  95. *
  96. * Return: true on success, false on invalid input params.
  97. */
  98. static bool libeth_rx_page_pool_params_zc(struct libeth_fq *fq,
  99. struct page_pool_params *pp)
  100. {
  101. u32 mtu, max;
  102. pp->offset = 0;
  103. pp->max_len = PAGE_SIZE << LIBETH_RX_PAGE_ORDER;
  104. switch (fq->type) {
  105. case LIBETH_FQE_MTU:
  106. mtu = READ_ONCE(pp->netdev->mtu);
  107. break;
  108. case LIBETH_FQE_SHORT:
  109. mtu = fq->truesize;
  110. break;
  111. default:
  112. return false;
  113. }
  114. mtu = roundup_pow_of_two(mtu);
  115. max = min(rounddown_pow_of_two(fq->buf_len ? : U32_MAX),
  116. pp->max_len);
  117. fq->buf_len = clamp(mtu, LIBETH_RX_BUF_STRIDE, max);
  118. fq->truesize = fq->buf_len;
  119. return true;
  120. }
  121. /**
  122. * libeth_rx_fq_create - create a PP with the default libeth settings
  123. * @fq: buffer queue struct to fill
  124. * @napi: &napi_struct covering this PP (no usage outside its poll loops)
  125. *
  126. * Return: %0 on success, -%errno on failure.
  127. */
  128. int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi)
  129. {
  130. struct page_pool_params pp = {
  131. .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
  132. .order = LIBETH_RX_PAGE_ORDER,
  133. .pool_size = fq->count,
  134. .nid = fq->nid,
  135. .dev = napi->dev->dev.parent,
  136. .netdev = napi->dev,
  137. .napi = napi,
  138. .dma_dir = DMA_FROM_DEVICE,
  139. };
  140. struct libeth_fqe *fqes;
  141. struct page_pool *pool;
  142. bool ret;
  143. if (!fq->hsplit)
  144. ret = libeth_rx_page_pool_params(fq, &pp);
  145. else
  146. ret = libeth_rx_page_pool_params_zc(fq, &pp);
  147. if (!ret)
  148. return -EINVAL;
  149. pool = page_pool_create(&pp);
  150. if (IS_ERR(pool))
  151. return PTR_ERR(pool);
  152. fqes = kvcalloc_node(fq->count, sizeof(*fqes), GFP_KERNEL, fq->nid);
  153. if (!fqes)
  154. goto err_buf;
  155. fq->fqes = fqes;
  156. fq->pp = pool;
  157. return 0;
  158. err_buf:
  159. page_pool_destroy(pool);
  160. return -ENOMEM;
  161. }
  162. EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_create, LIBETH);
  163. /**
  164. * libeth_rx_fq_destroy - destroy a &page_pool created by libeth
  165. * @fq: buffer queue to process
  166. */
  167. void libeth_rx_fq_destroy(struct libeth_fq *fq)
  168. {
  169. kvfree(fq->fqes);
  170. page_pool_destroy(fq->pp);
  171. }
  172. EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_destroy, LIBETH);
  173. /**
  174. * libeth_rx_recycle_slow - recycle a libeth page from the NAPI context
  175. * @page: page to recycle
  176. *
  177. * To be used on exceptions or rare cases not requiring fast inline recycling.
  178. */
  179. void libeth_rx_recycle_slow(struct page *page)
  180. {
  181. page_pool_recycle_direct(page->pp, page);
  182. }
  183. EXPORT_SYMBOL_NS_GPL(libeth_rx_recycle_slow, LIBETH);
  184. /* Converting abstract packet type numbers into a software structure with
  185. * the packet parameters to do O(1) lookup on Rx.
  186. */
  187. static const u16 libeth_rx_pt_xdp_oip[] = {
  188. [LIBETH_RX_PT_OUTER_L2] = XDP_RSS_TYPE_NONE,
  189. [LIBETH_RX_PT_OUTER_IPV4] = XDP_RSS_L3_IPV4,
  190. [LIBETH_RX_PT_OUTER_IPV6] = XDP_RSS_L3_IPV6,
  191. };
  192. static const u16 libeth_rx_pt_xdp_iprot[] = {
  193. [LIBETH_RX_PT_INNER_NONE] = XDP_RSS_TYPE_NONE,
  194. [LIBETH_RX_PT_INNER_UDP] = XDP_RSS_L4_UDP,
  195. [LIBETH_RX_PT_INNER_TCP] = XDP_RSS_L4_TCP,
  196. [LIBETH_RX_PT_INNER_SCTP] = XDP_RSS_L4_SCTP,
  197. [LIBETH_RX_PT_INNER_ICMP] = XDP_RSS_L4_ICMP,
  198. [LIBETH_RX_PT_INNER_TIMESYNC] = XDP_RSS_TYPE_NONE,
  199. };
  200. static const u16 libeth_rx_pt_xdp_pl[] = {
  201. [LIBETH_RX_PT_PAYLOAD_NONE] = XDP_RSS_TYPE_NONE,
  202. [LIBETH_RX_PT_PAYLOAD_L2] = XDP_RSS_TYPE_NONE,
  203. [LIBETH_RX_PT_PAYLOAD_L3] = XDP_RSS_TYPE_NONE,
  204. [LIBETH_RX_PT_PAYLOAD_L4] = XDP_RSS_L4,
  205. };
  206. /**
  207. * libeth_rx_pt_gen_hash_type - generate an XDP RSS hash type for a PT
  208. * @pt: PT structure to evaluate
  209. *
  210. * Generates ```hash_type``` field with XDP RSS type values from the parsed
  211. * packet parameters if they're obtained dynamically at runtime.
  212. */
  213. void libeth_rx_pt_gen_hash_type(struct libeth_rx_pt *pt)
  214. {
  215. pt->hash_type = 0;
  216. pt->hash_type |= libeth_rx_pt_xdp_oip[pt->outer_ip];
  217. pt->hash_type |= libeth_rx_pt_xdp_iprot[pt->inner_prot];
  218. pt->hash_type |= libeth_rx_pt_xdp_pl[pt->payload_layer];
  219. }
  220. EXPORT_SYMBOL_NS_GPL(libeth_rx_pt_gen_hash_type, LIBETH);
  221. /* Module */
  222. MODULE_DESCRIPTION("Common Ethernet library");
  223. MODULE_LICENSE("GPL");