mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
net: bnxt: Add SW GSO completion and teardown support
Update __bnxt_tx_int and bnxt_free_one_tx_ring_skbs to handle SW GSO segments: - MID segments: adjust tx_pkts/tx_bytes accounting and skip skb free (the skb is shared across all segments and freed only once) - LAST segments: call tso_dma_map_complete() to tear down the IOVA mapping if one was used. On the fallback path, payload DMA unmapping is handled by the existing per-BD dma_unmap_len walk. Both MID and LAST completions advance tx_inline_cons to release the segment's inline header slot back to the ring. is_sw_gso is initialized to zero, so the new code paths are not run. Add logic for feature advertisement and guardrails for ring sizing. Suggested-by: Jakub Kicinski <kuba@kernel.org> Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com> Signed-off-by: Joe Damato <joe@dama.to> Link: https://patch.msgid.link/20260408230607.2019402-9-joe@dama.to Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
cc5d90667d
commit
87550ba2dc
|
|
@ -74,6 +74,8 @@
|
|||
#include "bnxt_debugfs.h"
|
||||
#include "bnxt_coredump.h"
|
||||
#include "bnxt_hwmon.h"
|
||||
#include "bnxt_gso.h"
|
||||
#include <net/tso.h>
|
||||
|
||||
#define BNXT_TX_TIMEOUT (5 * HZ)
|
||||
#define BNXT_DEF_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_HW | \
|
||||
|
|
@ -817,12 +819,13 @@ static bool __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
|
|||
bool rc = false;
|
||||
|
||||
while (RING_TX(bp, cons) != hw_cons) {
|
||||
struct bnxt_sw_tx_bd *tx_buf;
|
||||
struct bnxt_sw_tx_bd *tx_buf, *head_buf;
|
||||
struct sk_buff *skb;
|
||||
bool is_ts_pkt;
|
||||
int j, last;
|
||||
|
||||
tx_buf = &txr->tx_buf_ring[RING_TX(bp, cons)];
|
||||
head_buf = tx_buf;
|
||||
skb = tx_buf->skb;
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
|
|
@ -869,6 +872,22 @@ static bool __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
|
|||
DMA_TO_DEVICE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(head_buf->is_sw_gso)) {
|
||||
u16 inline_cons = txr->tx_inline_cons + 1;
|
||||
|
||||
WRITE_ONCE(txr->tx_inline_cons, inline_cons);
|
||||
if (head_buf->is_sw_gso == BNXT_SW_GSO_LAST) {
|
||||
tso_dma_map_complete(&pdev->dev,
|
||||
&head_buf->sw_gso_cstate);
|
||||
} else {
|
||||
tx_pkts--;
|
||||
tx_bytes -= skb->len;
|
||||
skb = NULL;
|
||||
}
|
||||
head_buf->is_sw_gso = 0;
|
||||
}
|
||||
|
||||
if (unlikely(is_ts_pkt)) {
|
||||
if (BNXT_CHIP_P5(bp)) {
|
||||
/* PTP worker takes ownership of the skb */
|
||||
|
|
@ -3412,6 +3431,7 @@ static void bnxt_free_one_tx_ring_skbs(struct bnxt *bp,
|
|||
|
||||
for (i = 0; i < max_idx;) {
|
||||
struct bnxt_sw_tx_bd *tx_buf = &txr->tx_buf_ring[i];
|
||||
struct bnxt_sw_tx_bd *head_buf = tx_buf;
|
||||
struct sk_buff *skb;
|
||||
int j, last;
|
||||
|
||||
|
|
@ -3466,7 +3486,20 @@ static void bnxt_free_one_tx_ring_skbs(struct bnxt *bp,
|
|||
DMA_TO_DEVICE, 0);
|
||||
}
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
if (head_buf->is_sw_gso) {
|
||||
u16 inline_cons = txr->tx_inline_cons + 1;
|
||||
|
||||
WRITE_ONCE(txr->tx_inline_cons, inline_cons);
|
||||
if (head_buf->is_sw_gso == BNXT_SW_GSO_LAST) {
|
||||
tso_dma_map_complete(&pdev->dev,
|
||||
&head_buf->sw_gso_cstate);
|
||||
} else {
|
||||
skb = NULL;
|
||||
}
|
||||
head_buf->is_sw_gso = 0;
|
||||
}
|
||||
if (skb)
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, idx));
|
||||
}
|
||||
|
|
@ -3992,9 +4025,9 @@ static void bnxt_free_tx_inline_buf(struct bnxt_tx_ring_info *txr,
|
|||
txr->tx_inline_size = 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused bnxt_alloc_tx_inline_buf(struct bnxt_tx_ring_info *txr,
|
||||
struct pci_dev *pdev,
|
||||
unsigned int size)
|
||||
static int bnxt_alloc_tx_inline_buf(struct bnxt_tx_ring_info *txr,
|
||||
struct pci_dev *pdev,
|
||||
unsigned int size)
|
||||
{
|
||||
txr->tx_inline_buf = kmalloc(size, GFP_KERNEL);
|
||||
if (!txr->tx_inline_buf)
|
||||
|
|
@ -4097,6 +4130,13 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
|
|||
sizeof(struct tx_push_bd);
|
||||
txr->data_mapping = cpu_to_le64(mapping);
|
||||
}
|
||||
if (!(bp->flags & BNXT_FLAG_UDP_GSO_CAP)) {
|
||||
rc = bnxt_alloc_tx_inline_buf(txr, pdev,
|
||||
BNXT_SW_USO_MAX_SEGS *
|
||||
TSO_HEADER_SIZE);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
qidx = bp->tc_to_qidx[j];
|
||||
ring->queue_id = bp->q_info[qidx].queue_id;
|
||||
spin_lock_init(&txr->xdp_tx_lock);
|
||||
|
|
@ -4635,10 +4675,13 @@ static int bnxt_init_rx_rings(struct bnxt *bp)
|
|||
|
||||
static int bnxt_init_tx_rings(struct bnxt *bp)
|
||||
{
|
||||
netdev_features_t features;
|
||||
u16 i;
|
||||
|
||||
features = bp->dev->features;
|
||||
|
||||
bp->tx_wake_thresh = max_t(int, bp->tx_ring_size / 2,
|
||||
BNXT_MIN_TX_DESC_CNT);
|
||||
bnxt_min_tx_desc_cnt(bp, features));
|
||||
|
||||
for (i = 0; i < bp->tx_nr_rings; i++) {
|
||||
struct bnxt_tx_ring_info *txr = &bp->tx_ring[i];
|
||||
|
|
@ -13837,6 +13880,11 @@ static netdev_features_t bnxt_fix_features(struct net_device *dev,
|
|||
if ((features & NETIF_F_NTUPLE) && !bnxt_rfs_capable(bp, false))
|
||||
features &= ~NETIF_F_NTUPLE;
|
||||
|
||||
if ((features & NETIF_F_GSO_UDP_L4) &&
|
||||
!(bp->flags & BNXT_FLAG_UDP_GSO_CAP) &&
|
||||
bp->tx_ring_size < 2 * BNXT_SW_USO_MAX_DESCS)
|
||||
features &= ~NETIF_F_GSO_UDP_L4;
|
||||
|
||||
if ((bp->flags & BNXT_FLAG_NO_AGG_RINGS) || bp->xdp_prog)
|
||||
features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
|
||||
|
||||
|
|
@ -13882,6 +13930,9 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
|
|||
int rc = 0;
|
||||
bool re_init = false;
|
||||
|
||||
bp->tx_wake_thresh = max_t(int, bp->tx_ring_size / 2,
|
||||
bnxt_min_tx_desc_cnt(bp, features));
|
||||
|
||||
flags &= ~BNXT_FLAG_ALL_CONFIG_FEATS;
|
||||
if (features & NETIF_F_GRO_HW)
|
||||
flags |= BNXT_FLAG_GRO;
|
||||
|
|
@ -16907,8 +16958,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM |
|
||||
NETIF_F_GSO_PARTIAL | NETIF_F_RXHASH |
|
||||
NETIF_F_RXCSUM | NETIF_F_GRO;
|
||||
if (bp->flags & BNXT_FLAG_UDP_GSO_CAP)
|
||||
dev->hw_features |= NETIF_F_GSO_UDP_L4;
|
||||
dev->hw_features |= NETIF_F_GSO_UDP_L4;
|
||||
|
||||
if (BNXT_SUPPORTS_TPA(bp))
|
||||
dev->hw_features |= NETIF_F_LRO;
|
||||
|
|
@ -16941,8 +16991,15 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
dev->priv_flags |= IFF_UNICAST_FLT;
|
||||
|
||||
netif_set_tso_max_size(dev, GSO_MAX_SIZE);
|
||||
if (bp->tso_max_segs)
|
||||
if (!(bp->flags & BNXT_FLAG_UDP_GSO_CAP)) {
|
||||
u16 max_segs = BNXT_SW_USO_MAX_SEGS;
|
||||
|
||||
if (bp->tso_max_segs)
|
||||
max_segs = min_t(u16, max_segs, bp->tso_max_segs);
|
||||
netif_set_tso_max_segs(dev, max_segs);
|
||||
} else if (bp->tso_max_segs) {
|
||||
netif_set_tso_max_segs(dev, bp->tso_max_segs);
|
||||
}
|
||||
|
||||
dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
|
||||
NETDEV_XDP_ACT_RX_SG;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "bnxt_xdp.h"
|
||||
#include "bnxt_ptp.h"
|
||||
#include "bnxt_ethtool.h"
|
||||
#include "bnxt_gso.h"
|
||||
#include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */
|
||||
#include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */
|
||||
#include "bnxt_coredump.h"
|
||||
|
|
@ -852,12 +853,18 @@ static int bnxt_set_ringparam(struct net_device *dev,
|
|||
u8 tcp_data_split = kernel_ering->tcp_data_split;
|
||||
struct bnxt *bp = netdev_priv(dev);
|
||||
u8 hds_config_mod;
|
||||
int rc;
|
||||
|
||||
if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) ||
|
||||
(ering->tx_pending > BNXT_MAX_TX_DESC_CNT) ||
|
||||
(ering->tx_pending < BNXT_MIN_TX_DESC_CNT))
|
||||
return -EINVAL;
|
||||
|
||||
if ((dev->features & NETIF_F_GSO_UDP_L4) &&
|
||||
!(bp->flags & BNXT_FLAG_UDP_GSO_CAP) &&
|
||||
ering->tx_pending < 2 * BNXT_SW_USO_MAX_DESCS)
|
||||
return -EINVAL;
|
||||
|
||||
hds_config_mod = tcp_data_split != dev->cfg->hds_config;
|
||||
if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_DISABLED && hds_config_mod)
|
||||
return -EINVAL;
|
||||
|
|
@ -882,9 +889,17 @@ static int bnxt_set_ringparam(struct net_device *dev,
|
|||
bp->tx_ring_size = ering->tx_pending;
|
||||
bnxt_set_ring_params(bp);
|
||||
|
||||
if (netif_running(dev))
|
||||
return bnxt_open_nic(bp, false, false);
|
||||
if (netif_running(dev)) {
|
||||
rc = bnxt_open_nic(bp, false, false);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* ring size changes may affect features (SW USO requires a minimum
|
||||
* ring size), so recalculate features to ensure the correct features
|
||||
* are blocked/available.
|
||||
*/
|
||||
netdev_update_features(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,15 @@ static inline u16 bnxt_inline_avail(struct bnxt_tx_ring_info *txr)
|
|||
(u16)(txr->tx_inline_prod - READ_ONCE(txr->tx_inline_cons));
|
||||
}
|
||||
|
||||
static inline int bnxt_min_tx_desc_cnt(struct bnxt *bp,
|
||||
netdev_features_t features)
|
||||
{
|
||||
if (!(bp->flags & BNXT_FLAG_UDP_GSO_CAP) &&
|
||||
(features & NETIF_F_GSO_UDP_L4))
|
||||
return BNXT_SW_USO_MAX_DESCS;
|
||||
return BNXT_MIN_TX_DESC_CNT;
|
||||
}
|
||||
|
||||
netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
|
||||
struct bnxt_tx_ring_info *txr,
|
||||
struct netdev_queue *txq,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user