Every devmem dmabuf binding today hands the page_pool PAGE_SIZE niovs. This caps a single RX descriptor at PAGE_SIZE, burning CPU on buffer churn for large flows. Add a bind-time netlink attribute, NETDEV_A_DMABUF_RX_PAGE_SIZE, that lets userspace request a larger niov size. The value must be a power of two >= PAGE_SIZE. The TX path is changed to always pass PAGE_SIZE. Measurements: Setup: kperf in devmem RX/TX cuda mode, 4 flows, 64 MB messages, 60s, dctcp, num-rx-queues=4, dmabuf-rx/tx-size-mb=2048, 10 runs per niov size, mlx5. CPU Util: niov net sirq % net idle % app sys % app idle % ----- ---------------- ---------------- ---------------- ---------------- 4K 62.38 +/- 8.27 33.40 +/- 7.51 54.15 +/- 10.23 43.67 +/- 10.53 16K 58.91 +/- 5.35 35.23 +/- 5.88 41.05 +/- 8.87 56.42 +/- 9.24 32K 64.12 +/- 0.68 31.09 +/- 1.48 44.54 +/- 3.51 52.63 +/- 3.65 64K 54.69 +/- 5.54 39.67 +/- 5.81 35.47 +/- 3.11 61.97 +/- 3.27 RX app sys % drops ~19% from 4K to 64K. Throughput: niov RX dev Gbps RX flow avg Gbps ----- ---------------- ----------------- 4K 300.63 +/- 53.21 75.16 +/- 13.30 16K 321.35 +/- 28.20 80.34 +/- 7.05 32K 347.63 +/- 2.20 86.91 +/- 0.55 64K 332.11 +/- 14.26 83.03 +/- 3.56 Throughput seems to increase, but the stdev is pretty wide so could just be noise. kperf support (not yet merged): https://github.com/facebookexperimental/kperf/commit/8837577f920876bce6986ec18869ac04439ebcd2
Unified · Split
| @@ -6,6 +6,14 @@ doc: >- · 5 unmodified lines | |||
| 6 | netdev configuration over generic netlink. | 6 | netdev configuration over generic netlink. |
| 7 | 7 | ||
| 8 | definitions: | 8 | definitions: |
| 9 | - | ||
| 10 | type: const | ||
| 11 | name: page-size | ||
| 12 | # Dummy value, codegen needs a number. The real value comes from | ||
| 13 | # the PAGE_SIZE macro in the header below. | ||
| 14 | value: 0 | ||
| 15 | header: asm/page.h | ||
| 16 | scope: kernel | ||
| 9 | - | 17 | - |
| 10 | type: flags | 18 | type: flags |
| 11 | name: xdp-act | 19 | name: xdp-act |
| @@ -598,6 +606,16 @@ attribute-sets: · 586 unmodified lines | |||
| 598 | type: u32 | 606 | type: u32 |
| 599 | checks: | 607 | checks: |
| 600 | min: 1 | 608 | min: 1 |
| 609 | - | ||
| 610 | name: rx-page-size | ||
| 611 | doc: | | ||
| 612 | Size in bytes of each device page the NIC writes into from the bound | ||
| 613 | dmabuf. Must be a power of two and >= PAGE_SIZE; defaults to | ||
| 614 | PAGE_SIZE. | ||
| 615 | type: u32 | ||
| 616 | checks: | ||
| 617 | min: page-size | ||
| 618 | max: u32-max | ||
| 601 | 619 | ||
| 602 | operations: | 620 | operations: |
| 603 | list: | 621 | list: |
| @@ -812,6 +830,7 @@ operations: · 208 unmodified lines | |||
| 812 | - ifindex | 830 | - ifindex |
| 813 | - fd | 831 | - fd |
| 814 | - queues | 832 | - queues |
| 833 | - rx-page-size | ||
| 815 | reply: | 834 | reply: |
| 816 | attributes: | 835 | attributes: |
| 817 | - id | 836 | - id |
| @@ -219,6 +219,7 @@ enum { · 218 unmodified lines | |||
| 219 | NETDEV_A_DMABUF_QUEUES, | 219 | NETDEV_A_DMABUF_QUEUES, |
| 220 | NETDEV_A_DMABUF_FD, | 220 | NETDEV_A_DMABUF_FD, |
| 221 | NETDEV_A_DMABUF_ID, | 221 | NETDEV_A_DMABUF_ID, |
| 222 | NETDEV_A_DMABUF_RX_PAGE_SIZE, | ||
| 222 | 223 | ||
| 223 | __NETDEV_A_DMABUF_MAX, | 224 | __NETDEV_A_DMABUF_MAX, |
| 224 | NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1) | 225 | NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1) |
| @@ -46,7 +46,7 @@ static dma_addr_t net_devmem_get_dma_addr(const struct net_iov *niov) · 45 unmodified lines | |||
| 46 | 46 | ||
| 47 | owner = net_devmem_iov_to_chunk_owner(niov); | 47 | owner = net_devmem_iov_to_chunk_owner(niov); |
| 48 | return owner->base_dma_addr + | 48 | return owner->base_dma_addr + |
| 49 | ((dma_addr_t)net_iov_idx(niov) << PAGE_SHIFT); | 49 | ((dma_addr_t)net_iov_idx(niov) << owner->binding->niov_shift); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | static void net_devmem_dmabuf_binding_release(struct percpu_ref *ref) | 52 | static void net_devmem_dmabuf_binding_release(struct percpu_ref *ref) |
| @@ -93,13 +93,14 @@ net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding) · 40 unmodified lines | |||
| 93 | ssize_t offset; | 93 | ssize_t offset; |
| 94 | ssize_t index; | 94 | ssize_t index; |
| 95 | 95 | ||
| 96 | dma_addr = gen_pool_alloc_owner(binding->chunk_pool, PAGE_SIZE, | 96 | dma_addr = gen_pool_alloc_owner(binding->chunk_pool, |
| 97 | 1UL << binding->niov_shift, | ||
| 97 | (void **)&owner); | 98 | (void **)&owner); |
| 98 | if (!dma_addr) | 99 | if (!dma_addr) |
| 99 | return NULL; | 100 | return NULL; |
| 100 | 101 | ||
| 101 | offset = dma_addr - owner->base_dma_addr; | 102 | offset = dma_addr - owner->base_dma_addr; |
| 102 | index = offset / PAGE_SIZE; | 103 | index = offset >> binding->niov_shift; |
| 103 | niov = &owner->area.niovs[index]; | 104 | niov = &owner->area.niovs[index]; |
| 104 | 105 | ||
| 105 | niov->desc.pp_magic = 0; | 106 | niov->desc.pp_magic = 0; |
| @@ -113,12 +114,13 @@ void net_devmem_free_dmabuf(struct net_iov *niov) · 7 unmodified lines | |||
| 113 | { | 114 | { |
| 114 | struct net_devmem_dmabuf_binding *binding = net_devmem_iov_binding(niov); | 115 | struct net_devmem_dmabuf_binding *binding = net_devmem_iov_binding(niov); |
| 115 | unsigned long dma_addr = net_devmem_get_dma_addr(niov); | 116 | unsigned long dma_addr = net_devmem_get_dma_addr(niov); |
| 117 | size_t niov_size = 1UL << binding->niov_shift; | ||
| 116 | 118 | ||
| 117 | if (WARN_ON(!gen_pool_has_addr(binding->chunk_pool, dma_addr, | 119 | if (WARN_ON(!gen_pool_has_addr(binding->chunk_pool, dma_addr, |
| 118 | PAGE_SIZE))) | 120 | niov_size))) |
| 119 | return; | 121 | return; |
| 120 | 122 | ||
| 121 | gen_pool_free(binding->chunk_pool, dma_addr, PAGE_SIZE); | 123 | gen_pool_free(binding->chunk_pool, dma_addr, niov_size); |
| 122 | } | 124 | } |
| 123 | 125 | ||
| 124 | void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding) | 126 | void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding) |
| @@ -163,6 +165,9 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx, · 38 unmodified lines | |||
| 163 | u32 xa_idx; | 165 | u32 xa_idx; |
| 164 | int err; | 166 | int err; |
| 165 | 167 | ||
| 168 | if (binding->niov_shift != PAGE_SHIFT) | ||
| 169 | mp_params.rx_page_size = 1U << binding->niov_shift; | ||
| 170 | |||
| 166 | err = netif_mp_open_rxq(dev, rxq_idx, &mp_params, extack); | 171 | err = netif_mp_open_rxq(dev, rxq_idx, &mp_params, extack); |
| 167 | if (err) | 172 | if (err) |
| 168 | return err; | 173 | return err; |
| @@ -184,10 +189,12 @@ struct net_devmem_dmabuf_binding * · 15 unmodified lines | |||
| 184 | net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, | 189 | net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, |
| 185 | struct device *dma_dev, | 190 | struct device *dma_dev, |
| 186 | enum dma_data_direction direction, | 191 | enum dma_data_direction direction, |
| 187 | unsigned int dmabuf_fd, struct netdev_nl_sock *priv, | 192 | unsigned int dmabuf_fd, unsigned int niov_shift, |
| 193 | struct netdev_nl_sock *priv, | ||
| 188 | struct netlink_ext_ack *extack) | 194 | struct netlink_ext_ack *extack) |
| 189 | { | 195 | { |
| 190 | struct net_devmem_dmabuf_binding *binding; | 196 | struct net_devmem_dmabuf_binding *binding; |
| 197 | size_t niov_size = 1UL << niov_shift; | ||
| 191 | static u32 id_alloc_next; | 198 | static u32 id_alloc_next; |
| 192 | struct scatterlist *sg; | 199 | struct scatterlist *sg; |
| 193 | struct dma_buf *dmabuf; | 200 | struct dma_buf *dmabuf; |
| @@ -213,6 +220,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, · 19 unmodified lines | |||
| 213 | 220 | ||
| 214 | binding->dev = dev; | 221 | binding->dev = dev; |
| 215 | binding->vdev = vdev; | 222 | binding->vdev = vdev; |
| 223 | binding->niov_shift = niov_shift; | ||
| 216 | xa_init_flags(&binding->bound_rxqs, XA_FLAGS_ALLOC); | 224 | xa_init_flags(&binding->bound_rxqs, XA_FLAGS_ALLOC); |
| 217 | 225 | ||
| 218 | err = percpu_ref_init(&binding->ref, | 226 | err = percpu_ref_init(&binding->ref, |
| @@ -255,11 +263,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, · 36 unmodified lines | |||
| 255 | } | 263 | } |
| 256 | } | 264 | } |
| 257 | 265 | ||
| 258 | /* For simplicity we expect to make PAGE_SIZE allocations, but the | 266 | binding->chunk_pool = gen_pool_create(niov_shift, |
| 259 | * binding can be much more flexible than that. We may be able to | ||
| 260 | * allocate MTU sized chunks here. Leave that for future work... | ||
| 261 | */ | ||
| 262 | binding->chunk_pool = gen_pool_create(PAGE_SHIFT, | ||
| 263 | dev_to_node(&dev->dev)); | 267 | dev_to_node(&dev->dev)); |
| 264 | if (!binding->chunk_pool) { | 268 | if (!binding->chunk_pool) { |
| 265 | err = -ENOMEM; | 269 | err = -ENOMEM; |
| @@ -273,9 +277,12 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, · 7 unmodified lines | |||
| 273 | size_t len = sg_dma_len(sg); | 277 | size_t len = sg_dma_len(sg); |
| 274 | struct net_iov *niov; | 278 | struct net_iov *niov; |
| 275 | 279 | ||
| 276 | if (!IS_ALIGNED(len, PAGE_SIZE)) { | 280 | if (!IS_ALIGNED(dma_addr, niov_size) || |
| 281 | !IS_ALIGNED(len, niov_size)) { | ||
| 277 | err = -EINVAL; | 282 | err = -EINVAL; |
| 278 | NL_SET_ERR_MSG(extack, "dma-buf SG length must be PAGE_SIZE aligned"); | 283 | NL_SET_ERR_MSG_FMT(extack, |
| 284 | "dmabuf sg entry (addr=%pad, len=%zu) not aligned to niov size %zu", | ||
| 285 | &dma_addr, len, niov_size); | ||
| 279 | goto err_free_chunks; | 286 | goto err_free_chunks; |
| 280 | } | 287 | } |
| 281 | 288 | ||
| @@ -288,7 +295,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, · 6 unmodified lines | |||
| 288 | 295 | ||
| 289 | owner->area.base_virtual = virtual; | 296 | owner->area.base_virtual = virtual; |
| 290 | owner->base_dma_addr = dma_addr; | 297 | owner->base_dma_addr = dma_addr; |
| 291 | owner->area.num_niovs = len / PAGE_SIZE; | 298 | owner->area.num_niovs = len >> niov_shift; |
| 292 | owner->binding = binding; | 299 | owner->binding = binding; |
| 293 | 300 | ||
| 294 | err = gen_pool_add_owner(binding->chunk_pool, dma_addr, | 301 | err = gen_pool_add_owner(binding->chunk_pool, dma_addr, |
| @@ -454,7 +461,7 @@ int mp_dmabuf_devmem_init(struct page_pool *pool) · 159 unmodified lines | |||
| 454 | pool->dma_sync = false; | 461 | pool->dma_sync = false; |
| 455 | pool->dma_sync_for_cpu = false; | 462 | pool->dma_sync_for_cpu = false; |
| 456 | 463 | ||
| 457 | if (pool->p.order != 0) | 464 | if (pool->p.order != binding->niov_shift - PAGE_SHIFT) |
| 458 | return -E2BIG; | 465 | return -E2BIG; |
| 459 | 466 | ||
| 460 | net_devmem_dmabuf_binding_get(binding); | 467 | net_devmem_dmabuf_binding_get(binding); |
| @@ -71,6 +71,8 @@ struct net_devmem_dmabuf_binding { · 70 unmodified lines | |||
| 71 | */ | 71 | */ |
| 72 | struct net_iov **tx_vec; | 72 | struct net_iov **tx_vec; |
| 73 | 73 | ||
| 74 | unsigned int niov_shift; | ||
| 75 | |||
| 74 | struct work_struct unbind_w; | 76 | struct work_struct unbind_w; |
| 75 | }; | 77 | }; |
| 76 | 78 | ||
| @@ -93,7 +95,8 @@ struct net_devmem_dmabuf_binding * · 16 unmodified lines | |||
| 93 | net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, | 95 | net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, |
| 94 | struct device *dma_dev, | 96 | struct device *dma_dev, |
| 95 | enum dma_data_direction direction, | 97 | enum dma_data_direction direction, |
| 96 | unsigned int dmabuf_fd, struct netdev_nl_sock *priv, | 98 | unsigned int dmabuf_fd, unsigned int niov_shift, |
| 99 | struct netdev_nl_sock *priv, | ||
| 97 | struct netlink_ext_ack *extack); | 100 | struct netlink_ext_ack *extack); |
| 98 | struct net_devmem_dmabuf_binding *net_devmem_lookup_dmabuf(u32 id); | 101 | struct net_devmem_dmabuf_binding *net_devmem_lookup_dmabuf(u32 id); |
| 99 | void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding); | 102 | void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding); |
| @@ -122,10 +125,11 @@ static inline u32 net_devmem_iov_binding_id(const struct net_iov *niov) · 22 unmodified lines | |||
| 122 | 125 | ||
| 123 | static inline unsigned long net_iov_virtual_addr(const struct net_iov *niov) | 126 | static inline unsigned long net_iov_virtual_addr(const struct net_iov *niov) |
| 124 | { | 127 | { |
| 125 | struct net_iov_area *owner = net_iov_owner(niov); | 128 | struct dmabuf_genpool_chunk_owner *co = |
| 129 | net_devmem_iov_to_chunk_owner(niov); | ||
| 126 | 130 | ||
| 127 | return owner->base_virtual + | 131 | return net_iov_owner(niov)->base_virtual + |
| 128 | ((unsigned long)net_iov_idx(niov) << PAGE_SHIFT); | 132 | ((unsigned long)net_iov_idx(niov) << co->binding->niov_shift); |
| 129 | } | 133 | } |
| 130 | 134 | ||
| 131 | static inline bool | 135 | static inline bool |
| @@ -175,6 +179,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, · 43 unmodified lines | |||
| 175 | struct device *dma_dev, | 179 | struct device *dma_dev, |
| 176 | enum dma_data_direction direction, | 180 | enum dma_data_direction direction, |
| 177 | unsigned int dmabuf_fd, | 181 | unsigned int dmabuf_fd, |
| 182 | unsigned int niov_shift, | ||
| 178 | struct netdev_nl_sock *priv, | 183 | struct netdev_nl_sock *priv, |
| 179 | struct netlink_ext_ack *extack) | 184 | struct netlink_ext_ack *extack) |
| 180 | { | 185 | { |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include <uapi/linux/netdev.h> | 12 | #include <uapi/linux/netdev.h> |
| 13 | #include <net/netdev_netlink.h> | 13 | #include <net/netdev_netlink.h> |
| 14 | #include <asm/page.h> | ||
| 14 | 15 | ||
| 15 | /* Integer value ranges */ | 16 | /* Integer value ranges */ |
| 16 | static const struct netlink_range_validation netdev_a_page_pool_id_range = { | 17 | static const struct netlink_range_validation netdev_a_page_pool_id_range = { |
| @@ -27,6 +28,11 @@ static const struct netlink_range_validation netdev_a_napi_defer_hard_irqs_range · 10 unmodified lines | |||
| 27 | .max = S32_MAX, | 28 | .max = S32_MAX, |
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 31 | static const struct netlink_range_validation netdev_a_dmabuf_rx_page_size_range = { | ||
| 32 | .min = PAGE_SIZE, | ||
| 33 | .max = U32_MAX, | ||
| 34 | }; | ||
| 35 | |||
| 30 | /* Common nested types */ | 36 | /* Common nested types */ |
| 31 | const struct nla_policy netdev_lease_nl_policy[NETDEV_A_LEASE_NETNS_ID + 1] = { | 37 | const struct nla_policy netdev_lease_nl_policy[NETDEV_A_LEASE_NETNS_ID + 1] = { |
| 32 | [NETDEV_A_LEASE_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), | 38 | [NETDEV_A_LEASE_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), |
| @@ -106,10 +112,11 @@ static const struct nla_policy netdev_qstats_get_nl_policy[NETDEV_A_QSTATS_SCOPE · 73 unmodified lines | |||
| 106 | }; | 112 | }; |
| 107 | 113 | ||
| 108 | /* NETDEV_CMD_BIND_RX - do */ | 114 | /* NETDEV_CMD_BIND_RX - do */ |
| 109 | static const struct nla_policy netdev_bind_rx_nl_policy[NETDEV_A_DMABUF_FD + 1] = { | 115 | static const struct nla_policy netdev_bind_rx_nl_policy[NETDEV_A_DMABUF_RX_PAGE_SIZE + 1] = { |
| 110 | [NETDEV_A_DMABUF_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), | 116 | [NETDEV_A_DMABUF_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1), |
| 111 | [NETDEV_A_DMABUF_FD] = { .type = NLA_U32, }, | 117 | [NETDEV_A_DMABUF_FD] = { .type = NLA_U32, }, |
| 112 | [NETDEV_A_DMABUF_QUEUES] = NLA_POLICY_NESTED(netdev_queue_id_nl_policy), | 118 | [NETDEV_A_DMABUF_QUEUES] = NLA_POLICY_NESTED(netdev_queue_id_nl_policy), |
| 119 | [NETDEV_A_DMABUF_RX_PAGE_SIZE] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_dmabuf_rx_page_size_range), | ||
| 113 | }; | 120 | }; |
| 114 | 121 | ||
| 115 | /* NETDEV_CMD_NAPI_SET - do */ | 122 | /* NETDEV_CMD_NAPI_SET - do */ |
| @@ -219,7 +226,7 @@ static const struct genl_split_ops netdev_nl_ops[] = { · 103 unmodified lines | |||
| 219 | .cmd = NETDEV_CMD_BIND_RX, | 226 | .cmd = NETDEV_CMD_BIND_RX, |
| 220 | .doit = netdev_nl_bind_rx_doit, | 227 | .doit = netdev_nl_bind_rx_doit, |
| 221 | .policy = netdev_bind_rx_nl_policy, | 228 | .policy = netdev_bind_rx_nl_policy, |
| 222 | .maxattr = NETDEV_A_DMABUF_FD, | 229 | .maxattr = NETDEV_A_DMABUF_RX_PAGE_SIZE, |
| 223 | .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DO, | 230 | .flags = GENL_UNS_ADMIN_PERM | GENL_CMD_CAP_DO, |
| 224 | }, | 231 | }, |
| 225 | { | 232 | { |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | #include <uapi/linux/netdev.h> | 13 | #include <uapi/linux/netdev.h> |
| 14 | #include <net/netdev_netlink.h> | 14 | #include <net/netdev_netlink.h> |
| 15 | #include <asm/page.h> | ||
| 15 | 16 | ||
| 16 | /* Common nested types */ | 17 | /* Common nested types */ |
| 17 | extern const struct nla_policy netdev_lease_nl_policy[NETDEV_A_LEASE_NETNS_ID + 1]; | 18 | extern const struct nla_policy netdev_lease_nl_policy[NETDEV_A_LEASE_NETNS_ID + 1]; |
| @@ -1013,6 +1013,7 @@ netdev_nl_get_dma_dev(struct net_device *netdev, unsigned long *rxq_bitmap, · 1012 unmodified lines | |||
| 1013 | int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) | 1013 | int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) |
| 1014 | { | 1014 | { |
| 1015 | struct net_devmem_dmabuf_binding *binding; | 1015 | struct net_devmem_dmabuf_binding *binding; |
| 1016 | unsigned int niov_shift = PAGE_SHIFT; | ||
| 1016 | u32 ifindex, dmabuf_fd, rxq_idx; | 1017 | u32 ifindex, dmabuf_fd, rxq_idx; |
| 1017 | struct netdev_nl_sock *priv; | 1018 | struct netdev_nl_sock *priv; |
| 1018 | struct net_device *netdev; | 1019 | struct net_device *netdev; |
| @@ -1030,6 +1031,18 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) · 11 unmodified lines | |||
| 1030 | ifindex = nla_get_u32(info->attrs[NETDEV_A_DEV_IFINDEX]); | 1031 | ifindex = nla_get_u32(info->attrs[NETDEV_A_DEV_IFINDEX]); |
| 1031 | dmabuf_fd = nla_get_u32(info->attrs[NETDEV_A_DMABUF_FD]); | 1032 | dmabuf_fd = nla_get_u32(info->attrs[NETDEV_A_DMABUF_FD]); |
| 1032 | 1033 | ||
| 1034 | if (info->attrs[NETDEV_A_DMABUF_RX_PAGE_SIZE]) { | ||
| 1035 | u32 rx_page_size = nla_get_u32(info->attrs[NETDEV_A_DMABUF_RX_PAGE_SIZE]); | ||
| 1036 | |||
| 1037 | if (!is_power_of_2(rx_page_size)) { | ||
| 1038 | NL_SET_ERR_MSG_ATTR(info->extack, | ||
| 1039 | info->attrs[NETDEV_A_DMABUF_RX_PAGE_SIZE], | ||
| 1040 | "rx-page-size must be a power of 2"); | ||
| 1041 | return -EINVAL; | ||
| 1042 | } | ||
| 1043 | niov_shift = ilog2(rx_page_size); | ||
| 1044 | } | ||
| 1045 | |||
| 1033 | priv = genl_sk_priv_get(&netdev_nl_family, NETLINK_CB(skb).sk); | 1046 | priv = genl_sk_priv_get(&netdev_nl_family, NETLINK_CB(skb).sk); |
| 1034 | if (IS_ERR(priv)) | 1047 | if (IS_ERR(priv)) |
| 1035 | return PTR_ERR(priv); | 1048 | return PTR_ERR(priv); |
| @@ -1080,7 +1093,8 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) · 44 unmodified lines | |||
| 1080 | } | 1093 | } |
| 1081 | 1094 | ||
| 1082 | binding = net_devmem_bind_dmabuf(netdev, NULL, dma_dev, DMA_FROM_DEVICE, | 1095 | binding = net_devmem_bind_dmabuf(netdev, NULL, dma_dev, DMA_FROM_DEVICE, |
| 1083 | dmabuf_fd, priv, info->extack); | 1096 | dmabuf_fd, niov_shift, priv, |
| 1097 | info->extack); | ||
| 1084 | if (IS_ERR(binding)) { | 1098 | if (IS_ERR(binding)) { |
| 1085 | err = PTR_ERR(binding); | 1099 | err = PTR_ERR(binding); |
| 1086 | goto err_rxq_bitmap; | 1100 | goto err_rxq_bitmap; |
| @@ -1221,7 +1235,7 @@ int netdev_nl_bind_tx_doit(struct sk_buff *skb, struct genl_info *info) · 134 unmodified lines | |||
| 1221 | binding = net_devmem_bind_dmabuf(bind_dev, | 1235 | binding = net_devmem_bind_dmabuf(bind_dev, |
| 1222 | bind_dev != netdev ? netdev : NULL, | 1236 | bind_dev != netdev ? netdev : NULL, |
| 1223 | dma_dev, DMA_TO_DEVICE, dmabuf_fd, | 1237 | dma_dev, DMA_TO_DEVICE, dmabuf_fd, |
| 1224 | priv, info->extack); | 1238 | PAGE_SHIFT, priv, info->extack); |
| 1225 | if (IS_ERR(binding)) { | 1239 | if (IS_ERR(binding)) { |
| 1226 | err = PTR_ERR(binding); | 1240 | err = PTR_ERR(binding); |
| 1227 | goto err_unlock_bind_dev; | 1241 | goto err_unlock_bind_dev; |
| @@ -219,6 +219,7 @@ enum { · 218 unmodified lines | |||
| 219 | NETDEV_A_DMABUF_QUEUES, | 219 | NETDEV_A_DMABUF_QUEUES, |
| 220 | NETDEV_A_DMABUF_FD, | 220 | NETDEV_A_DMABUF_FD, |
| 221 | NETDEV_A_DMABUF_ID, | 221 | NETDEV_A_DMABUF_ID, |
| 222 | NETDEV_A_DMABUF_RX_PAGE_SIZE, | ||
| 222 | 223 | ||
| 223 | __NETDEV_A_DMABUF_MAX, | 224 | __NETDEV_A_DMABUF_MAX, |
| 224 | NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1) | 225 | NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1) |