Commit 2fba7dc5 authored by Maciej Fijalkowski's avatar Maciej Fijalkowski Committed by Daniel Borkmann

ice: Add support for XDP multi-buffer on Rx side

Ice driver needs to be a bit reworked on Rx data path in order to
support multi-buffer XDP. For skb path, it currently works in a way that
Rx ring carries pointer to skb so if driver didn't manage to combine
fragmented frame at current NAPI instance, it can restore the state on
next instance and keep looking for last fragment (so descriptor with EOP
bit set). What needs to be achieved is that xdp_buff needs to be
combined in such way (linear + frags part) in the first place. Then skb
will be ready to go in case of XDP_PASS or BPF program being not present
on interface. If BPF program is there, it would work on multi-buffer
XDP. At this point xdp_buff resides directly on Rx ring, so given the
fact that skb will be built straight from xdp_buff, there will be no
further need to carry skb on Rx ring.

Besides removing skb pointer from Rx ring, lots of members have been
moved around within ice_rx_ring. First and foremost reason was to place
rx_buf with xdp_buff on the same cacheline. This means that once we
touch rx_buf (which is a preceding step before touching xdp_buff),
xdp_buff will already be hot in cache. Second thing was that xdp_rxq is
used rather rarely and it occupies a separate cacheline, so maybe it is
better to have it at the end of ice_rx_ring.

Other change that affects ice_rx_ring is the introduction of
ice_rx_ring::first_desc. Its purpose is twofold - first is to propagate
rx_buf->act to all the parts of current xdp_buff after running XDP
program, so that ice_put_rx_buf() that got moved out of the main Rx
processing loop will be able to tak an appriopriate action on each
buffer. Second is for ice_construct_skb().

ice_construct_skb() has a copybreak mechanism which had an explicit
impact on xdp_buff->skb conversion in the new approach when legacy Rx
flag is toggled. It works in a way that linear part is 256 bytes long,
if frame is bigger than that, remaining bytes are going as a frag to
skb_shared_info.

This means while memcpying frags from xdp_buff to newly allocated skb,
care needs to be taken when picking the destination frag array entry.
Upon the time ice_construct_skb() is called, when dealing with
fragmented frame, current rx_buf points to the *last* fragment, but
copybreak needs to be done against the first one.  That's where
ice_rx_ring::first_desc helps.

When frame building spans across NAPI polls (DD bit is not set on
current descriptor and xdp->data is not NULL) with current Rx buffer
handling state there might be some problems.
Since calls to ice_put_rx_buf() were pulled out of the main Rx
processing loop and were scoped from cached_ntc to current ntc, remember
that now mentioned function relies on rx_buf->act, which is set within
ice_run_xdp(). ice_run_xdp() is called when EOP bit was found, so
currently we could put Rx buffer with rx_buf->act being *uninitialized*.
To address this, change scoping to rely on first_desc on both boundaries
instead.

This also implies that cleaned_count which is used as an input to
ice_alloc_rx_buffers() and tells how many new buffers should be refilled
has to be adjusted. If it stayed as is, what could happen is a case
where ntc would go over ntu.

Therefore, remove cleaned_count altogether and use against allocing
routine newly introduced ICE_RX_DESC_UNUSED() macro which is an
equivalent of ICE_DESC_UNUSED() dedicated for Rx side and based on
struct ice_rx_ring::first_desc instead of next_to_clean.
Signed-off-by: default avatarMaciej Fijalkowski <maciej.fijalkowski@intel.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Reviewed-by: default avatarAlexander Lobakin <alexandr.lobakin@intel.com>
Link: https://lore.kernel.org/bpf/20230131204506.219292-11-maciej.fijalkowski@intel.com
parent 8a11b334
...@@ -492,7 +492,7 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring) ...@@ -492,7 +492,7 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
{ {
struct device *dev = ice_pf_to_dev(ring->vsi->back); struct device *dev = ice_pf_to_dev(ring->vsi->back);
u16 num_bufs = ICE_DESC_UNUSED(ring); u32 num_bufs = ICE_RX_DESC_UNUSED(ring);
int err; int err;
ring->rx_buf_len = ring->vsi->rx_buf_len; ring->rx_buf_len = ring->vsi->rx_buf_len;
...@@ -500,8 +500,10 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) ...@@ -500,8 +500,10 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
if (ring->vsi->type == ICE_VSI_PF) { if (ring->vsi->type == ICE_VSI_PF) {
if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
/* coverity[check_return] */ /* coverity[check_return] */
xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev, __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index, ring->q_vector->napi.napi_id); ring->q_index,
ring->q_vector->napi.napi_id,
ring->vsi->rx_buf_len);
ring->xsk_pool = ice_xsk_pool(ring); ring->xsk_pool = ice_xsk_pool(ring);
if (ring->xsk_pool) { if (ring->xsk_pool) {
...@@ -521,9 +523,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) ...@@ -521,9 +523,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
} else { } else {
if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
/* coverity[check_return] */ /* coverity[check_return] */
xdp_rxq_info_reg(&ring->xdp_rxq, __xdp_rxq_info_reg(&ring->xdp_rxq,
ring->netdev, ring->netdev,
ring->q_index, ring->q_vector->napi.napi_id); ring->q_index,
ring->q_vector->napi.napi_id,
ring->vsi->rx_buf_len);
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED, MEM_TYPE_PAGE_SHARED,
...@@ -534,6 +538,7 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) ...@@ -534,6 +538,7 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
} }
xdp_init_buff(&ring->xdp, ice_rx_pg_size(ring) / 2, &ring->xdp_rxq); xdp_init_buff(&ring->xdp, ice_rx_pg_size(ring) / 2, &ring->xdp_rxq);
ring->xdp.data = NULL;
err = ice_setup_rx_ctx(ring); err = ice_setup_rx_ctx(ring);
if (err) { if (err) {
dev_err(dev, "ice_setup_rx_ctx failed for RxQ %d, err %d\n", dev_err(dev, "ice_setup_rx_ctx failed for RxQ %d, err %d\n",
......
...@@ -3092,7 +3092,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, ...@@ -3092,7 +3092,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
/* allocate Rx buffers */ /* allocate Rx buffers */
err = ice_alloc_rx_bufs(&rx_rings[i], err = ice_alloc_rx_bufs(&rx_rings[i],
ICE_DESC_UNUSED(&rx_rings[i])); ICE_RX_DESC_UNUSED(&rx_rings[i]));
rx_unwind: rx_unwind:
if (err) { if (err) {
while (i) { while (i) {
......
...@@ -2888,9 +2888,12 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, ...@@ -2888,9 +2888,12 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog,
bool if_running = netif_running(vsi->netdev); bool if_running = netif_running(vsi->netdev);
int ret = 0, xdp_ring_err = 0; int ret = 0, xdp_ring_err = 0;
if (frame_size > ice_max_xdp_frame_size(vsi)) { if (prog && !prog->aux->xdp_has_frags) {
NL_SET_ERR_MSG_MOD(extack, "MTU too large for loading XDP"); if (frame_size > ice_max_xdp_frame_size(vsi)) {
return -EOPNOTSUPP; NL_SET_ERR_MSG_MOD(extack,
"MTU is too large for linear frames and XDP prog does not support frags");
return -EOPNOTSUPP;
}
} }
/* need to stop netdev while setting up the program for Rx rings */ /* need to stop netdev while setting up the program for Rx rings */
...@@ -7354,6 +7357,7 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -7354,6 +7357,7 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi; struct ice_vsi *vsi = np->vsi;
struct ice_pf *pf = vsi->back; struct ice_pf *pf = vsi->back;
struct bpf_prog *prog;
u8 count = 0; u8 count = 0;
int err = 0; int err = 0;
...@@ -7362,7 +7366,8 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -7362,7 +7366,8 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
return 0; return 0;
} }
if (ice_is_xdp_ena_vsi(vsi)) { prog = vsi->xdp_prog;
if (prog && !prog->aux->xdp_has_frags) {
int frame_size = ice_max_xdp_frame_size(vsi); int frame_size = ice_max_xdp_frame_size(vsi);
if (new_mtu + ICE_ETH_PKT_HDR_PAD > frame_size) { if (new_mtu + ICE_ETH_PKT_HDR_PAD > frame_size) {
......
This diff is collapsed.
...@@ -112,6 +112,10 @@ static inline int ice_skb_pad(void) ...@@ -112,6 +112,10 @@ static inline int ice_skb_pad(void)
(u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ (u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
(R)->next_to_clean - (R)->next_to_use - 1) (R)->next_to_clean - (R)->next_to_use - 1)
#define ICE_RX_DESC_UNUSED(R) \
((((R)->first_desc > (R)->next_to_use) ? 0 : (R)->count) + \
(R)->first_desc - (R)->next_to_use - 1)
#define ICE_RING_QUARTER(R) ((R)->count >> 2) #define ICE_RING_QUARTER(R) ((R)->count >> 2)
#define ICE_TX_FLAGS_TSO BIT(0) #define ICE_TX_FLAGS_TSO BIT(0)
...@@ -136,6 +140,7 @@ static inline int ice_skb_pad(void) ...@@ -136,6 +140,7 @@ static inline int ice_skb_pad(void)
#define ICE_XDP_TX BIT(1) #define ICE_XDP_TX BIT(1)
#define ICE_XDP_REDIR BIT(2) #define ICE_XDP_REDIR BIT(2)
#define ICE_XDP_EXIT BIT(3) #define ICE_XDP_EXIT BIT(3)
#define ICE_SKB_CONSUMED ICE_XDP_CONSUMED
#define ICE_RX_DMA_ATTR \ #define ICE_RX_DMA_ATTR \
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING) (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
...@@ -277,43 +282,44 @@ struct ice_rx_ring { ...@@ -277,43 +282,44 @@ struct ice_rx_ring {
struct ice_vsi *vsi; /* Backreference to associated VSI */ struct ice_vsi *vsi; /* Backreference to associated VSI */
struct ice_q_vector *q_vector; /* Backreference to associated vector */ struct ice_q_vector *q_vector; /* Backreference to associated vector */
u8 __iomem *tail; u8 __iomem *tail;
u16 q_index; /* Queue number of ring */
u16 count; /* Number of descriptors */
u16 reg_idx; /* HW register index of the ring */
u16 next_to_alloc;
/* CL2 - 2nd cacheline starts here */
union { union {
struct ice_rx_buf *rx_buf; struct ice_rx_buf *rx_buf;
struct xdp_buff **xdp_buf; struct xdp_buff **xdp_buf;
}; };
/* CL2 - 2nd cacheline starts here */ struct xdp_buff xdp;
struct xdp_rxq_info xdp_rxq;
/* CL3 - 3rd cacheline starts here */ /* CL3 - 3rd cacheline starts here */
u16 q_index; /* Queue number of ring */ struct bpf_prog *xdp_prog;
u16 rx_offset;
u16 count; /* Number of descriptors */
u16 reg_idx; /* HW register index of the ring */
/* used in interrupt processing */ /* used in interrupt processing */
u16 next_to_use; u16 next_to_use;
u16 next_to_clean; u16 next_to_clean;
u16 next_to_alloc; u16 first_desc;
u16 rx_offset;
u16 rx_buf_len;
/* stats structs */ /* stats structs */
struct ice_ring_stats *ring_stats; struct ice_ring_stats *ring_stats;
struct rcu_head rcu; /* to avoid race on free */ struct rcu_head rcu; /* to avoid race on free */
/* CL4 - 3rd cacheline starts here */ /* CL4 - 4th cacheline starts here */
struct ice_channel *ch; struct ice_channel *ch;
struct bpf_prog *xdp_prog;
struct ice_tx_ring *xdp_ring; struct ice_tx_ring *xdp_ring;
struct xsk_buff_pool *xsk_pool; struct xsk_buff_pool *xsk_pool;
struct xdp_buff xdp;
struct sk_buff *skb;
dma_addr_t dma; /* physical address of ring */ dma_addr_t dma; /* physical address of ring */
u64 cached_phctime; u64 cached_phctime;
u16 rx_buf_len;
u8 dcb_tc; /* Traffic class of ring */ u8 dcb_tc; /* Traffic class of ring */
u8 ptp_rx; u8 ptp_rx;
#define ICE_RX_FLAGS_RING_BUILD_SKB BIT(1) #define ICE_RX_FLAGS_RING_BUILD_SKB BIT(1)
#define ICE_RX_FLAGS_CRC_STRIP_DIS BIT(2) #define ICE_RX_FLAGS_CRC_STRIP_DIS BIT(2)
u8 flags; u8 flags;
/* CL5 - 5th cacheline starts here */
struct xdp_rxq_info xdp_rxq;
} ____cacheline_internodealigned_in_smp; } ____cacheline_internodealigned_in_smp;
struct ice_tx_ring { struct ice_tx_ring {
...@@ -436,7 +442,7 @@ static inline unsigned int ice_rx_pg_order(struct ice_rx_ring *ring) ...@@ -436,7 +442,7 @@ static inline unsigned int ice_rx_pg_order(struct ice_rx_ring *ring)
union ice_32b_rx_flex_desc; union ice_32b_rx_flex_desc;
bool ice_alloc_rx_bufs(struct ice_rx_ring *rxr, u16 cleaned_count); bool ice_alloc_rx_bufs(struct ice_rx_ring *rxr, unsigned int cleaned_count);
netdev_tx_t ice_start_xmit(struct sk_buff *skb, struct net_device *netdev); netdev_tx_t ice_start_xmit(struct sk_buff *skb, struct net_device *netdev);
u16 u16
ice_select_queue(struct net_device *dev, struct sk_buff *skb, ice_select_queue(struct net_device *dev, struct sk_buff *skb,
......
...@@ -5,6 +5,36 @@ ...@@ -5,6 +5,36 @@
#define _ICE_TXRX_LIB_H_ #define _ICE_TXRX_LIB_H_
#include "ice.h" #include "ice.h"
/**
* ice_set_rx_bufs_act - propagate Rx buffer action to frags
* @xdp: XDP buffer representing frame (linear and frags part)
* @rx_ring: Rx ring struct
* act: action to store onto Rx buffers related to XDP buffer parts
*
* Set action that should be taken before putting Rx buffer from first frag
* to one before last. Last one is handled by caller of this function as it
* is the EOP frag that is currently being processed. This function is
* supposed to be called only when XDP buffer contains frags.
*/
static inline void
ice_set_rx_bufs_act(struct xdp_buff *xdp, const struct ice_rx_ring *rx_ring,
const unsigned int act)
{
const struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
u32 first = rx_ring->first_desc;
u32 nr_frags = sinfo->nr_frags;
u32 cnt = rx_ring->count;
struct ice_rx_buf *buf;
for (int i = 0; i < nr_frags; i++) {
buf = &rx_ring->rx_buf[first];
buf->act = act;
if (++first == cnt)
first = 0;
}
}
/** /**
* ice_test_staterr - tests bits in Rx descriptor status and error fields * ice_test_staterr - tests bits in Rx descriptor status and error fields
* @status_err_n: Rx descriptor status_error0 or status_error1 bits * @status_err_n: Rx descriptor status_error0 or status_error1 bits
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment