| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* Interface for implementing AF_XDP zero-copy support in drivers. | |
| * Copyright(c) 2020 Intel Corporation. | |
| */ | |
| #ifndef _LINUX_XDP_SOCK_DRV_H | |
| #define _LINUX_XDP_SOCK_DRV_H | |
| #include <net/xdp_sock.h> | |
| #include <net/xsk_buff_pool.h> | |
| #define XDP_UMEM_MIN_CHUNK_SHIFT 11 | |
| #define XDP_UMEM_MIN_CHUNK_SIZE (1 << XDP_UMEM_MIN_CHUNK_SHIFT) | |
| #define NETDEV_XDP_ACT_XSK (NETDEV_XDP_ACT_BASIC | \ | |
| NETDEV_XDP_ACT_REDIRECT | \ | |
| NETDEV_XDP_ACT_XSK_ZEROCOPY) | |
| struct xsk_cb_desc { | |
| void *src; | |
| u8 off; | |
| u8 bytes; | |
| }; | |
| #ifdef CONFIG_XDP_SOCKETS | |
| void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries); | |
| bool xsk_tx_peek_desc(struct xsk_buff_pool *pool, struct xdp_desc *desc); | |
| u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 max); | |
| void xsk_tx_release(struct xsk_buff_pool *pool); | |
| struct xsk_buff_pool *xsk_get_pool_from_qid(struct net_device *dev, | |
| u16 queue_id); | |
| void xsk_set_rx_need_wakeup(struct xsk_buff_pool *pool); | |
| void xsk_set_tx_need_wakeup(struct xsk_buff_pool *pool); | |
| void xsk_clear_rx_need_wakeup(struct xsk_buff_pool *pool); | |
| void xsk_clear_tx_need_wakeup(struct xsk_buff_pool *pool); | |
| bool xsk_uses_need_wakeup(struct xsk_buff_pool *pool); | |
| static inline u32 xsk_pool_get_headroom(struct xsk_buff_pool *pool) | |
| { | |
| return XDP_PACKET_HEADROOM + pool->headroom; | |
| } | |
| static inline u32 xsk_pool_get_tailroom(bool mbuf) | |
| { | |
| return mbuf ? SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : 0; | |
| } | |
| static inline u32 xsk_pool_get_chunk_size(struct xsk_buff_pool *pool) | |
| { | |
| return pool->chunk_size; | |
| } | |
| static inline u32 __xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool) | |
| { | |
| return xsk_pool_get_chunk_size(pool) - xsk_pool_get_headroom(pool); | |
| } | |
| static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool) | |
| { | |
| u32 frame_size = __xsk_pool_get_rx_frame_size(pool); | |
| struct xdp_umem *umem = pool->umem; | |
| bool mbuf; | |
| /* Reserve tailroom only for zero-copy pools that opted into | |
| * multi-buffer. The reserved area is used for skb_shared_info, | |
| * matching the XDP core's xdp_data_hard_end() layout. | |
| */ | |
| mbuf = pool->dev && (umem->flags & XDP_UMEM_SG_FLAG); | |
| frame_size -= xsk_pool_get_tailroom(mbuf); | |
| return ALIGN_DOWN(frame_size, 128); | |
| } | |
| static inline u32 xsk_pool_get_rx_frag_step(struct xsk_buff_pool *pool) | |
| { | |
| return pool->unaligned ? 0 : xsk_pool_get_chunk_size(pool); | |
| } | |
| static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool, | |
| struct xdp_rxq_info *rxq) | |
| { | |
| xp_set_rxq_info(pool, rxq); | |
| } | |
| static inline void xsk_pool_fill_cb(struct xsk_buff_pool *pool, | |
| struct xsk_cb_desc *desc) | |
| { | |
| xp_fill_cb(pool, desc); | |
| } | |
| static inline void xsk_pool_dma_unmap(struct xsk_buff_pool *pool, | |
| unsigned long attrs) | |
| { | |
| xp_dma_unmap(pool, attrs); | |
| } | |
| static inline int xsk_pool_dma_map(struct xsk_buff_pool *pool, | |
| struct device *dev, unsigned long attrs) | |
| { | |
| struct xdp_umem *umem = pool->umem; | |
| return xp_dma_map(pool, dev, attrs, umem->pgs, umem->npgs); | |
| } | |
| static inline dma_addr_t xsk_buff_xdp_get_dma(struct xdp_buff *xdp) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); | |
| return xp_get_dma(xskb); | |
| } | |
| static inline dma_addr_t xsk_buff_xdp_get_frame_dma(struct xdp_buff *xdp) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); | |
| return xp_get_frame_dma(xskb); | |
| } | |
| static inline struct xdp_buff *xsk_buff_alloc(struct xsk_buff_pool *pool) | |
| { | |
| return xp_alloc(pool); | |
| } | |
| static inline bool xsk_is_eop_desc(const struct xdp_desc *desc) | |
| { | |
| return !xp_mb_desc(desc); | |
| } | |
| /* Returns as many entries as possible up to max. 0 <= N <= max. */ | |
| static inline u32 xsk_buff_alloc_batch(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max) | |
| { | |
| return xp_alloc_batch(pool, xdp, max); | |
| } | |
| static inline bool xsk_buff_can_alloc(struct xsk_buff_pool *pool, u32 count) | |
| { | |
| return xp_can_alloc(pool, count); | |
| } | |
| static inline void xsk_buff_free(struct xdp_buff *xdp) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); | |
| struct list_head *xskb_list = &xskb->pool->xskb_list; | |
| struct xdp_buff_xsk *pos, *tmp; | |
| if (likely(!xdp_buff_has_frags(xdp))) | |
| goto out; | |
| list_for_each_entry_safe(pos, tmp, xskb_list, list_node) { | |
| list_del_init(&pos->list_node); | |
| xp_free(pos); | |
| } | |
| xdp_get_shared_info_from_buff(xdp)->nr_frags = 0; | |
| out: | |
| xp_free(xskb); | |
| } | |
| static inline bool xsk_buff_add_frag(struct xdp_buff *head, | |
| struct xdp_buff *xdp) | |
| { | |
| const void *data = xdp->data; | |
| struct xdp_buff_xsk *frag; | |
| if (!__xdp_buff_add_frag(head, virt_to_netmem(data), | |
| offset_in_page(data), xdp->data_end - data, | |
| xdp->frame_sz, false)) | |
| return false; | |
| frag = container_of(xdp, struct xdp_buff_xsk, xdp); | |
| list_add_tail(&frag->list_node, &frag->pool->xskb_list); | |
| return true; | |
| } | |
| static inline struct xdp_buff *xsk_buff_get_frag(const struct xdp_buff *first) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(first, struct xdp_buff_xsk, xdp); | |
| struct xdp_buff *ret = NULL; | |
| struct xdp_buff_xsk *frag; | |
| frag = list_first_entry_or_null(&xskb->pool->xskb_list, | |
| struct xdp_buff_xsk, list_node); | |
| if (frag) { | |
| list_del_init(&frag->list_node); | |
| ret = &frag->xdp; | |
| } | |
| return ret; | |
| } | |
| static inline void xsk_buff_del_frag(struct xdp_buff *xdp) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); | |
| list_del_init(&xskb->list_node); | |
| } | |
| static inline struct xdp_buff *xsk_buff_get_head(struct xdp_buff *first) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(first, struct xdp_buff_xsk, xdp); | |
| struct xdp_buff_xsk *frag; | |
| frag = list_first_entry(&xskb->pool->xskb_list, struct xdp_buff_xsk, | |
| list_node); | |
| return &frag->xdp; | |
| } | |
| static inline struct xdp_buff *xsk_buff_get_tail(struct xdp_buff *first) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(first, struct xdp_buff_xsk, xdp); | |
| struct xdp_buff_xsk *frag; | |
| frag = list_last_entry(&xskb->pool->xskb_list, struct xdp_buff_xsk, | |
| list_node); | |
| return &frag->xdp; | |
| } | |
| static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) | |
| { | |
| xdp->data = xdp->data_hard_start + XDP_PACKET_HEADROOM; | |
| xdp->data_meta = xdp->data; | |
| xdp->data_end = xdp->data + size; | |
| xdp->flags = 0; | |
| } | |
| static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool, | |
| u64 addr) | |
| { | |
| return xp_raw_get_dma(pool, addr); | |
| } | |
| static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr) | |
| { | |
| return xp_raw_get_data(pool, addr); | |
| } | |
| /** | |
| * xsk_buff_raw_get_ctx - get &xdp_desc context | |
| * @pool: XSk buff pool desc address belongs to | |
| * @addr: desc address (from userspace) | |
| * @options: desc options (from userspace) | |
| * | |
| * Wrapper for xp_raw_get_ctx() to be used in drivers, see its kdoc for | |
| * details. | |
| * | |
| * Return: new &xdp_desc_ctx struct containing desc's DMA address and metadata | |
| * pointer, if it is present (initialized to %NULL otherwise). | |
| */ | |
| static inline struct xdp_desc_ctx | |
| xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr, u32 options) | |
| { | |
| return xp_raw_get_ctx(pool, addr, options); | |
| } | |
| #define XDP_TXMD_FLAGS_VALID ( \ | |
| XDP_TXMD_FLAGS_TIMESTAMP | \ | |
| XDP_TXMD_FLAGS_CHECKSUM | \ | |
| XDP_TXMD_FLAGS_LAUNCH_TIME | \ | |
| 0) | |
| static inline bool | |
| xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool, | |
| const struct xsk_tx_metadata *meta, u64 *flags) | |
| { | |
| *flags = READ_ONCE(meta->flags); | |
| if (*flags & XDP_TXMD_FLAGS_LAUNCH_TIME) | |
| if (pool->tx_metadata_len < | |
| offsetofend(struct xsk_tx_metadata, request.launch_time)) | |
| return false; | |
| return !(*flags & ~XDP_TXMD_FLAGS_VALID); | |
| } | |
| /** | |
| * xsk_tx_metadata_request - Evaluate AF_XDP TX metadata at submission | |
| * and call appropriate xsk_tx_metadata_ops operation. | |
| * @pool: pointer to AF_XDP buffer pool, used to validate the metadata | |
| * @pmeta: pointer to pointer to AF_XDP metadata area | |
| * @ops: pointer to struct xsk_tx_metadata_ops | |
| * @priv: pointer to driver-private area | |
| * | |
| * This function should be called by the networking device when | |
| * it prepares AF_XDP egress packet. | |
| */ | |
| static inline void | |
| xsk_tx_metadata_request(const struct xsk_buff_pool *pool, | |
| struct xsk_tx_metadata **pmeta, | |
| const struct xsk_tx_metadata_ops *ops, void *priv) | |
| { | |
| const struct xsk_tx_metadata *meta = *pmeta; | |
| u64 flags; | |
| if (!meta) | |
| return; | |
| if (unlikely(!xsk_buff_valid_tx_metadata(pool, meta, &flags))) { | |
| *pmeta = NULL; | |
| return; /* no way to signal the error to the user */ | |
| } | |
| if (ops->tmo_request_launch_time) | |
| if (flags & XDP_TXMD_FLAGS_LAUNCH_TIME) | |
| ops->tmo_request_launch_time( | |
| READ_ONCE(meta->request.launch_time), priv); | |
| if (ops->tmo_request_timestamp) | |
| if (flags & XDP_TXMD_FLAGS_TIMESTAMP) | |
| ops->tmo_request_timestamp(priv); | |
| if (ops->tmo_request_checksum) | |
| if (flags & XDP_TXMD_FLAGS_CHECKSUM) | |
| ops->tmo_request_checksum( | |
| READ_ONCE(meta->request.csum_start), | |
| READ_ONCE(meta->request.csum_offset), priv); | |
| if (!(flags & XDP_TXMD_FLAGS_TIMESTAMP)) | |
| *pmeta = NULL; | |
| } | |
| static inline struct xsk_tx_metadata * | |
| __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data, | |
| unsigned int options) | |
| { | |
| if (!pool->tx_metadata_len || !(options & XDP_TX_METADATA)) | |
| return NULL; | |
| return data - pool->tx_metadata_len; | |
| } | |
| static inline struct xsk_tx_metadata * | |
| xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr, u32 options) | |
| { | |
| return __xsk_buff_get_metadata(pool, xp_raw_get_data(pool, addr), | |
| options); | |
| } | |
| static inline void xsk_buff_dma_sync_for_cpu(struct xdp_buff *xdp) | |
| { | |
| struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); | |
| xp_dma_sync_for_cpu(xskb); | |
| } | |
| static inline void xsk_buff_raw_dma_sync_for_device(struct xsk_buff_pool *pool, | |
| dma_addr_t dma, | |
| size_t size) | |
| { | |
| xp_dma_sync_for_device(pool, dma, size); | |
| } | |
| #else | |
| static inline void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries) | |
| { | |
| } | |
| static inline bool xsk_tx_peek_desc(struct xsk_buff_pool *pool, | |
| struct xdp_desc *desc) | |
| { | |
| return false; | |
| } | |
| static inline u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 max) | |
| { | |
| return 0; | |
| } | |
| static inline void xsk_tx_release(struct xsk_buff_pool *pool) | |
| { | |
| } | |
| static inline struct xsk_buff_pool * | |
| xsk_get_pool_from_qid(struct net_device *dev, u16 queue_id) | |
| { | |
| return NULL; | |
| } | |
| static inline void xsk_set_rx_need_wakeup(struct xsk_buff_pool *pool) | |
| { | |
| } | |
| static inline void xsk_set_tx_need_wakeup(struct xsk_buff_pool *pool) | |
| { | |
| } | |
| static inline void xsk_clear_rx_need_wakeup(struct xsk_buff_pool *pool) | |
| { | |
| } | |
| static inline void xsk_clear_tx_need_wakeup(struct xsk_buff_pool *pool) | |
| { | |
| } | |
| static inline bool xsk_uses_need_wakeup(struct xsk_buff_pool *pool) | |
| { | |
| return false; | |
| } | |
| static inline u32 xsk_pool_get_headroom(struct xsk_buff_pool *pool) | |
| { | |
| return 0; | |
| } | |
| static inline u32 xsk_pool_get_chunk_size(struct xsk_buff_pool *pool) | |
| { | |
| return 0; | |
| } | |
| static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool) | |
| { | |
| return 0; | |
| } | |
| static inline u32 xsk_pool_get_rx_frag_step(struct xsk_buff_pool *pool) | |
| { | |
| return 0; | |
| } | |
| static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool, | |
| struct xdp_rxq_info *rxq) | |
| { | |
| } | |
| static inline void xsk_pool_fill_cb(struct xsk_buff_pool *pool, | |
| struct xsk_cb_desc *desc) | |
| { | |
| } | |
| static inline void xsk_pool_dma_unmap(struct xsk_buff_pool *pool, | |
| unsigned long attrs) | |
| { | |
| } | |
| static inline int xsk_pool_dma_map(struct xsk_buff_pool *pool, | |
| struct device *dev, unsigned long attrs) | |
| { | |
| return 0; | |
| } | |
| static inline dma_addr_t xsk_buff_xdp_get_dma(struct xdp_buff *xdp) | |
| { | |
| return 0; | |
| } | |
| static inline dma_addr_t xsk_buff_xdp_get_frame_dma(struct xdp_buff *xdp) | |
| { | |
| return 0; | |
| } | |
| static inline struct xdp_buff *xsk_buff_alloc(struct xsk_buff_pool *pool) | |
| { | |
| return NULL; | |
| } | |
| static inline bool xsk_is_eop_desc(const struct xdp_desc *desc) | |
| { | |
| return false; | |
| } | |
| static inline u32 xsk_buff_alloc_batch(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max) | |
| { | |
| return 0; | |
| } | |
| static inline bool xsk_buff_can_alloc(struct xsk_buff_pool *pool, u32 count) | |
| { | |
| return false; | |
| } | |
| static inline void xsk_buff_free(struct xdp_buff *xdp) | |
| { | |
| } | |
| static inline bool xsk_buff_add_frag(struct xdp_buff *head, | |
| struct xdp_buff *xdp) | |
| { | |
| return false; | |
| } | |
| static inline struct xdp_buff *xsk_buff_get_frag(const struct xdp_buff *first) | |
| { | |
| return NULL; | |
| } | |
| static inline void xsk_buff_del_frag(struct xdp_buff *xdp) | |
| { | |
| } | |
| static inline struct xdp_buff *xsk_buff_get_head(struct xdp_buff *first) | |
| { | |
| return NULL; | |
| } | |
| static inline struct xdp_buff *xsk_buff_get_tail(struct xdp_buff *first) | |
| { | |
| return NULL; | |
| } | |
| static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) | |
| { | |
| } | |
| static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool, | |
| u64 addr) | |
| { | |
| return 0; | |
| } | |
| static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr) | |
| { | |
| return NULL; | |
| } | |
| static inline struct xdp_desc_ctx | |
| xsk_buff_raw_get_ctx(const struct xsk_buff_pool *pool, u64 addr, u32 options) | |
| { | |
| return (struct xdp_desc_ctx){ }; | |
| } | |
| static inline bool | |
| xsk_buff_valid_tx_metadata(const struct xsk_buff_pool *pool, | |
| const struct xsk_tx_metadata *meta, u64 *flags) | |
| { | |
| return false; | |
| } | |
| static inline void | |
| xsk_tx_metadata_request(const struct xsk_buff_pool *pool, | |
| struct xsk_tx_metadata **pmeta, | |
| const struct xsk_tx_metadata_ops *ops, void *priv) | |
| { | |
| } | |
| static inline struct xsk_tx_metadata * | |
| __xsk_buff_get_metadata(const struct xsk_buff_pool *pool, void *data, | |
| unsigned int options) | |
| { | |
| return NULL; | |
| } | |
| static inline struct xsk_tx_metadata * | |
| xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr, u32 options) | |
| { | |
| return NULL; | |
| } | |
| static inline void xsk_buff_dma_sync_for_cpu(struct xdp_buff *xdp) | |
| { | |
| } | |
| static inline void xsk_buff_raw_dma_sync_for_device(struct xsk_buff_pool *pool, | |
| dma_addr_t dma, | |
| size_t size) | |
| { | |
| } | |
| #endif /* CONFIG_XDP_SOCKETS */ | |
| #endif /* _LINUX_XDP_SOCK_DRV_H */ |