aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-09 06:40:28 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-09 06:40:28 +0200
commitaf32da41b0327b9c6a37856ba82b6760d6c8d10e (patch)
tree1908c1d636394d7ab56ed3e469eb41e9cd357fd6 /drivers/net/ethernet
parent6c377d19d4a5116d9bec5203aa3c6c11523e7898 (diff)
parent37f12441f557468a56c1e27790413aa78c82afa2 (diff)
Merge tag 'net-7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netHEADmaster
Pull networking fixes from Jakub Kicinski: "Including fixes from wireless, wireguard, CAN and Bluetooth. We have one known regression to wrap up in VLAN handling. Current release - regressions: - Bluetooth: RFCOMM: fix deadlock on rfcomm_mutex Previous releases - regressions: - can: fix regression in handling RPS after migrating metadata to skb_ext - eth: - iavf: fix regressions in reconfig impacting bonding - mana: fix packet forwarding performance regression - stmmac: remove buggy VLAN acceleration support Previous releases - always broken: - a few high prio fixes for tun, and af_packet - amt: fix a UaF on tunnel teardown - eth: - bnxt: fix PCIe AER recovery and FLR handling issues - macb: don't modify Tx skbs before taking ownership - axienet: don't leak Tx skbs on interface stop - wifi: - nxpwifi: number of LLM-ish fixes - assorted mt76 fixes" * tag 'net-7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (128 commits) net: macb: copy shared skbs before appending the FCS net: macb: check TX ring before modifying skb vsock: Fix memory leak in vmci_transport_recv_dgram_cb() wireguard: noise: reject response consumption after intermediate initiation wireguard: queueing: preserve tstamp_type when encapsulating packet net: openvswitch: validate transport header presence in set_ipv6_addr net/smc: protect clcsock lifetime in smc_getname ipv6: do not warn on route notification size race ipv4: do not warn on route notification size race ipv4: validate checksum_start before completing checksum ptp: ocp: fix PCIe delay estimation calculation xen/netfront: don't leak the skb when xennet_fill_frags() fails net/packet: call packet_parse_headers after virtio_net_hdr_to_skb xen/netfront: drop RX packets with a short Ethernet header net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits() net: sparx5: free the matchall entry on destroy selftests: mlxsw: Test port range occupancy on template create mlxsw: spectrum_flower: Fix port range register leak in tmplt_create() net: dsa: microchip: fix KSZ8765 fiber detection net/mlx5e: Order ICOSQ cc update after CQ doorbell ...
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.c32
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.h2
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.c5
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c189
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h1
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c11
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c80
-rw-r--r--drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c4
-rw-r--r--drivers/net/ethernet/google/gve/gve_main.c8
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx_dqo.c13
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c22
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c7
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c35
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h11
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c85
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c99
-rw-r--r--drivers/net/ethernet/intel/ice/devlink/port.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.c32
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c79
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vport.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c9
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c28
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c1
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_bpf.c8
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c63
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_ethtool.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c60
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c30
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c65
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h7
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c51
39 files changed, 727 insertions, 394 deletions
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 64619e9a704d..6ca57875b6d6 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2800,14 +2800,34 @@ static int airoha_qdma_set_trtcm_param(struct airoha_qdma *qdma, int channel,
FIELD_PREP(TRTCM_METER_GROUP_MASK, group) |
FIELD_PREP(TRTCM_PARAM_INDEX_MASK, idx) |
FIELD_PREP(TRTCM_PARAM_RATE_TYPE_MASK, mode);
+ int i;
- airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
- airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
+ /*
+ * HW might be in the middle of bucket handling and might
+ * require an additional try to actually apply the new TRTCM
+ * config.
+ */
+ for (i = 0; i < TRTCM_CONFIG_RETRY_MAX; i++) {
+ u32 data = 0;
- return read_poll_timeout(airoha_qdma_rr, val,
- val & TRTCM_PARAM_RW_DONE_MASK,
- USEC_PER_MSEC, 10 * USEC_PER_MSEC, true,
- qdma, REG_TRTCM_CFG_PARAM(addr));
+ airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
+ airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
+
+ if (read_poll_timeout(airoha_qdma_rr, data,
+ data & TRTCM_PARAM_RW_DONE_MASK,
+ USEC_PER_MSEC, 10 * USEC_PER_MSEC,
+ true, qdma, REG_TRTCM_CFG_PARAM(addr)))
+ continue;
+
+ if (airoha_qdma_get_trtcm_param(qdma, channel, addr, param,
+ mode, &data, NULL))
+ continue;
+
+ if (data == val)
+ return 0;
+ }
+
+ return -EBUSY;
}
static int airoha_qdma_set_trtcm_config(struct airoha_qdma *qdma, int channel,
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index 8277c1c87bb3..338fde03a149 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -171,6 +171,8 @@ enum trtcm_param {
#define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
#define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
+#define TRTCM_CONFIG_RETRY_MAX 2
+
enum airoha_dma_map_type {
AIROHA_DMA_UNMAPPED,
AIROHA_DMA_MAP_SINGLE,
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 0ba67a55705d..09b2abdfc9e8 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -300,7 +300,7 @@ static int emac_dma_inblk_32bit(struct emac_board_info *db,
if (!req) {
dev_err(db->dev, "alloc emac dma req error.\n");
ret = -ENOMEM;
- goto alloc_req_err;
+ goto prepare_err;
}
desc->callback_param = req;
@@ -319,9 +319,6 @@ static int emac_dma_inblk_32bit(struct emac_board_info *db,
submit_err:
emac_free_dma_req(req);
-alloc_req_err:
- dmaengine_desc_free(desc);
-
prepare_err:
dma_unmap_single(db->dev, rxbuf, count, DMA_FROM_DEVICE);
return ret;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index d7728d0c5b6e..15a8349ccf7b 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -486,7 +486,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct netdev_queue *txq;
int i;
dma_addr_t mapping;
- unsigned int length, pad = 0;
+ unsigned int length;
u32 len, free_size, vlan_tag_flags, cfa_action, flags;
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
struct pci_dev *pdev = bp->pdev;
@@ -536,6 +536,16 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
return rc < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK;
}
+ /* Pad after the SW USO branch: bnxt_sw_udp_gso_xmit() would
+ * otherwise account the padding as UDP payload.
+ * Must be done before skb_shinfo(skb)->nr_frags is sampled,
+ * because skb_put_padto() might linearize the skb.
+ */
+ if (skb_put_padto(skb, BNXT_MIN_PKT_SIZE)) {
+ /* SKB already freed. */
+ goto tx_kick_pending;
+ }
+
free_size = bnxt_tx_avail(bp, txr);
if (unlikely(free_size < skb_shinfo(skb)->nr_frags + 2)) {
/* We must have raced with NAPI cleanup */
@@ -672,14 +682,6 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
normal_tx:
- if (length < BNXT_MIN_PKT_SIZE) {
- pad = BNXT_MIN_PKT_SIZE - length;
- if (skb_pad(skb, pad))
- /* SKB already freed. */
- goto tx_kick_pending;
- length = BNXT_MIN_PKT_SIZE;
- }
-
mapping = dma_map_single(&pdev->dev, skb->data, len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(&pdev->dev, mapping)))
@@ -759,10 +761,7 @@ normal_tx:
txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
}
- flags &= ~TX_BD_LEN;
- txbd->tx_bd_len_flags_type =
- cpu_to_le32(((len + pad) << TX_BD_LEN_SHIFT) | flags |
- TX_BD_FLAGS_PACKET_END);
+ txbd->tx_bd_len_flags_type |= cpu_to_le32(TX_BD_FLAGS_PACKET_END);
netdev_tx_sent_queue(txq, skb->len);
@@ -15547,7 +15546,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
if (test_and_clear_bit(BNXT_STATE_FW_ACTIVATE_RESET, &bp->state) &&
!test_bit(BNXT_STATE_FW_ACTIVATE, &bp->state))
bnxt_dl_remote_reload(bp);
- if (pci_enable_device(bp->pdev)) {
+ if (!pci_is_enabled(bp->pdev) && pci_enable_device(bp->pdev)) {
netdev_err(bp->dev, "Cannot re-enable PCI device\n");
rc = -ENODEV;
goto fw_reset_abort;
@@ -17111,6 +17110,51 @@ void bnxt_print_device_info(struct bnxt *bp)
pcie_print_link_status(bp->pdev);
}
+static void bnxt_clear_bars(struct pci_dev *pdev)
+{
+ int off;
+
+ for (off = PCI_BASE_ADDRESS_0; off <= PCI_BASE_ADDRESS_5; off += 4)
+ pci_write_config_dword(pdev, off, 0);
+}
+
+/* Clear any pending DMA transactions from crash kernel while loading driver in
+ * capture kernel.
+ */
+static int bnxt_kdump_reset(struct pci_dev *pdev)
+{
+ int rc, i;
+ u16 cmd;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+ if (pci_save_state(pdev))
+ dev_warn(&pdev->dev, "Failed to save PCI state, PCI restore may be incomplete\n");
+
+ rc = pcie_flr(pdev);
+ if (rc)
+ dev_warn(&pdev->dev, "pcie_flr() failed (rc: %d), trying to continue\n",
+ rc);
+
+ /* In case device is not returning CRS, wait 5 seconds longer */
+ for (i = 0; i < 50; i++) {
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (!PCI_POSSIBLE_ERROR(cmd))
+ break;
+ msleep(100);
+ }
+ if (PCI_POSSIBLE_ERROR(cmd)) {
+ dev_err(&pdev->dev, "PCI config space inaccessible after FLR, aborting\n");
+ return -ENODEV;
+ }
+
+ bnxt_clear_bars(pdev);
+ pci_restore_state(pdev);
+ return 0;
+}
+
static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct bnxt_hw_resc *hw_resc;
@@ -17126,12 +17170,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
- /* Clear any pending DMA transactions from crash kernel
- * while loading driver in capture kernel.
- */
if (is_kdump_kernel()) {
- pci_clear_master(pdev);
- pcie_flr(pdev);
+ rc = bnxt_kdump_reset(pdev);
+ if (rc)
+ return rc;
}
max_irqs = bnxt_get_max_irq(pdev);
@@ -17565,10 +17607,8 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
* so we disable bus master to prevent any potential bad DMAs before
* freeing kernel memory.
*/
- if (state == pci_channel_io_frozen) {
- set_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state);
+ if (state == pci_channel_io_frozen)
bnxt_fw_fatal_close(bp);
- }
if (netif_running(netdev))
__bnxt_close_nic(bp, true, true);
@@ -17598,69 +17638,80 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
struct bnxt *bp = netdev_priv(netdev);
int retry = 0;
int err = 0;
- int off;
+ u16 cmd;
netdev_info(bp->dev, "PCI Slot Reset\n");
- if (test_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state)) {
- /* After DPC, the chip should return CRS when the vendor ID
- * config register is read until it is ready. On all chips,
- * this is not happening reliably so add a 5-second delay as a
- * workaround.
- */
- msleep(5000);
- }
+ /* After a PCIe hot reset, the chip should return CRS when the
+ * vendor ID config register is read until it is ready. On all
+ * chips, this is not happening reliably so add a 5-second delay
+ * as a workaround.
+ */
+ msleep(5000);
netdev_lock(netdev);
- if (pci_enable_device(pdev)) {
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (PCI_POSSIBLE_ERROR(cmd)) {
dev_err(&pdev->dev,
- "Cannot re-enable PCI device after reset.\n");
- } else {
- pci_set_master(pdev);
- /* Upon fatal error, our device internal logic that latches to
- * BAR value is getting reset and will restore only upon
- * rewriting the BARs.
- *
- * As pci_restore_state() does not re-write the BARs if the
- * value is same as saved value earlier, driver needs to
- * write the BARs to 0 to force restore, in case of fatal error.
- */
- if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN,
- &bp->state)) {
- for (off = PCI_BASE_ADDRESS_0;
- off <= PCI_BASE_ADDRESS_5; off += 4)
- pci_write_config_dword(bp->pdev, off, 0);
- }
- pci_restore_state(pdev);
+ "PCI config space inaccessible after reset\n");
+ goto reset_exit;
+ }
- bnxt_inv_fw_health_reg(bp);
- bnxt_try_map_fw_health_reg(bp);
+ /* Upon PCIe error, our device internal logic that latches to
+ * BAR value is getting reset and will restore only upon
+ * rewriting the BARs.
+ *
+ * As pci_restore_state() does not re-write the BARs if the
+ * value is same as saved value earlier, driver needs to
+ * write the BARs to 0 to force restore.
+ */
+ pci_clear_master(pdev);
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd &= ~PCI_COMMAND_MEMORY;
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
- /* In some PCIe AER scenarios, firmware may take up to
- * 10 seconds to become ready in the worst case.
- */
- do {
- err = bnxt_try_recover_fw(bp);
- if (!err)
- break;
- retry++;
- } while (retry < BNXT_FW_SLOT_RESET_RETRY);
+ bnxt_clear_bars(pdev);
+ pci_restore_state(pdev);
- if (err) {
- dev_err(&pdev->dev, "Firmware not ready\n");
- goto reset_exit;
+ if (!pci_is_enabled(pdev) && pci_enable_device(pdev)) {
+ dev_err(&pdev->dev,
+ "Cannot re-enable PCI device after reset.\n");
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (!PCI_POSSIBLE_ERROR(cmd)) {
+ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
}
+ goto reset_exit;
+ }
+ pci_set_master(pdev);
- err = bnxt_hwrm_func_reset(bp);
+ bnxt_inv_fw_health_reg(bp);
+ bnxt_try_map_fw_health_reg(bp);
+
+ /* In some PCIe AER scenarios, firmware may take up to
+ * 10 seconds to become ready in the worst case.
+ */
+ do {
+ err = bnxt_try_recover_fw(bp);
if (!err)
- result = PCI_ERS_RESULT_RECOVERED;
+ break;
+ retry++;
+ } while (retry < BNXT_FW_SLOT_RESET_RETRY);
- /* IRQ will be initialized later in bnxt_io_resume */
- bnxt_ulp_irq_stop(bp);
- bnxt_clear_int_mode(bp);
+ if (err) {
+ dev_err(&pdev->dev, "Firmware not ready\n");
+ goto reset_exit;
}
+ err = bnxt_hwrm_func_reset(bp);
+ if (!err)
+ result = PCI_ERS_RESULT_RECOVERED;
+
+ /* IRQ will be initialized later in bnxt_io_resume */
+ bnxt_ulp_irq_stop(bp);
+ bnxt_clear_int_mode(bp);
+
reset_exit:
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
bnxt_clear_reservations(bp, true);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index c673b2ce4a0d..41d05efd6307 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -2468,7 +2468,6 @@ struct bnxt {
#define BNXT_STATE_ABORT_ERR 5
#define BNXT_STATE_FW_FATAL_COND 6
#define BNXT_STATE_DRV_REGISTERED 7
-#define BNXT_STATE_PCI_CHANNEL_IO_FROZEN 8
#define BNXT_STATE_NAPI_DISABLED 9
#define BNXT_STATE_FW_ACTIVATE 11
#define BNXT_STATE_RECOVER 12
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 96d5d4f7f51f..984432952963 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -253,6 +253,17 @@ int bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
reg &= ~CMD_CRC_FWD;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ /*
+ * Mirror wol_power_down_cfg(). If only UMAC_RX
+ * is enabled, then we must place the UMAC back
+ * into SW_RESET.
+ */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ if ((reg & CMD_RX_EN) && !(reg & CMD_TX_EN)) {
+ reg |= CMD_SW_RESET;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ }
spin_unlock_bh(&priv->reg_lock);
/* Resume link status tracking */
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 8e5c034dc3a4..261a7e87520a 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2421,34 +2421,40 @@ static inline int macb_clear_csum(struct sk_buff *skb)
return 0;
}
+static bool macb_needs_sw_fcs(struct sk_buff *skb, struct net_device *netdev)
+{
+ return netdev->features & NETIF_F_HW_CSUM &&
+ skb->ip_summed != CHECKSUM_PARTIAL &&
+ !skb_shinfo(skb)->gso_size && !ptp_one_step_sync(skb);
+}
+
/* Returns a negative errno, or the FCS bytes appended (0 or ETH_FCS_LEN). */
-static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *netdev)
+static int macb_pad_and_fcs(struct sk_buff **skb, bool add_fcs)
{
bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) ||
skb_is_nonlinear(*skb);
int padlen = ETH_ZLEN - (*skb)->len;
int tailroom = skb_tailroom(*skb);
+ bool shared = skb_shared(*skb);
struct sk_buff *nskb;
u32 fcs;
- if (!(netdev->features & NETIF_F_HW_CSUM) ||
- !((*skb)->ip_summed != CHECKSUM_PARTIAL) ||
- skb_shinfo(*skb)->gso_size || ptp_one_step_sync(*skb))
+ if (!add_fcs)
return 0;
if (padlen <= 0) {
- /* FCS could be appeded to tailroom. */
- if (tailroom >= ETH_FCS_LEN)
+ /* FCS could be appended to tailroom. */
+ if (!shared && !skb_is_nonlinear(*skb) &&
+ tailroom >= ETH_FCS_LEN)
goto add_fcs;
- /* No room for FCS, need to reallocate skb. */
- else
- padlen = ETH_FCS_LEN;
+ /* Reallocate with room for the FCS. */
+ padlen = ETH_FCS_LEN;
} else {
/* Add room for FCS. */
padlen += ETH_FCS_LEN;
}
- if (cloned || tailroom < padlen) {
+ if (shared || cloned || tailroom < padlen) {
nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC);
if (!nskb)
return -ENOMEM;
@@ -2481,27 +2487,15 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
unsigned int desc_cnt, nr_frags, frag_size, f;
struct macb_queue *queue = &bp->queues[q];
netdev_tx_t ret = NETDEV_TX_OK;
- unsigned int hdrlen;
+ unsigned int hdrlen, tx_len;
+ bool add_fcs, is_lso;
unsigned long flags;
int fcs_len;
- bool is_lso;
-
- if (macb_clear_csum(skb)) {
- dev_kfree_skb_any(skb);
- return ret;
- }
-
- fcs_len = macb_pad_and_fcs(&skb, netdev);
- if (fcs_len < 0) {
- dev_kfree_skb_any(skb);
- return ret;
- }
-
- if (macb_dma_ptp(bp) &&
- (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ add_fcs = macb_needs_sw_fcs(skb, netdev);
is_lso = (skb_shinfo(skb)->gso_size != 0);
+ tx_len = add_fcs ? max_t(unsigned int, skb->len, ETH_ZLEN) +
+ ETH_FCS_LEN : skb->len;
if (is_lso) {
/* length of headers */
@@ -2515,8 +2509,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
/* if this is required, would need to copy to single buffer */
return NETDEV_TX_BUSY;
}
- } else
+ } else if (add_fcs) {
+ hdrlen = umin(tx_len, bp->max_tx_length);
+ } else {
hdrlen = umin(skb_headlen(skb), bp->max_tx_length);
+ }
#if defined(DEBUG) && defined(VERBOSE_DEBUG)
netdev_vdbg(bp->netdev,
@@ -2531,12 +2528,18 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
* socket buffer: skb fragments of jumbo frames may need to be
* split into many buffer descriptors.
*/
- if (is_lso && (skb_headlen(skb) > hdrlen))
+ if (add_fcs) {
+ /* macb_pad_and_fcs() linearizes the skb before adding the FCS. */
+ desc_cnt = DIV_ROUND_UP(tx_len, bp->max_tx_length);
+ nr_frags = 0;
+ } else if (is_lso && (skb_headlen(skb) > hdrlen)) {
/* extra header descriptor if also payload in first buffer */
desc_cnt = DIV_ROUND_UP((skb_headlen(skb) - hdrlen), bp->max_tx_length) + 1;
- else
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ } else {
desc_cnt = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length);
- nr_frags = skb_shinfo(skb)->nr_frags;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ }
for (f = 0; f < nr_frags; f++) {
frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length);
@@ -2554,6 +2557,21 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
goto unlock;
}
+ if (macb_clear_csum(skb)) {
+ dev_kfree_skb_any(skb);
+ goto unlock;
+ }
+
+ fcs_len = macb_pad_and_fcs(&skb, add_fcs);
+ if (fcs_len < 0) {
+ dev_kfree_skb_any(skb);
+ goto unlock;
+ }
+
+ if (macb_dma_ptp(bp) &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
/* Map socket buffer for DMA transfer */
if (macb_tx_map(bp, queue, skb, hdrlen, fcs_len)) {
dev_kfree_skb_any(skb);
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
index f5acd4be1e69..dbec95b49777 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
+++ b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
@@ -389,7 +389,7 @@ static void chcr_ktls_dev_del(struct net_device *netdev,
cxgb4_remove_tid(&tx_info->adap->tids, tx_info->tx_chan,
tx_info->tid, tx_info->ip_family);
- xa_erase(&u_ctx->tid_list, tx_info->tid);
+ xa_erase_bh(&u_ctx->tid_list, tx_info->tid);
}
port_stats = &tx_info->adap->ch_ktls_stats.ktls_port[tx_info->port_id];
@@ -577,7 +577,7 @@ free_tid:
cxgb4_remove_tid(&tx_info->adap->tids, tx_info->tx_chan,
tx_info->tid, tx_info->ip_family);
- xa_erase(&u_ctx->tid_list, tx_info->tid);
+ xa_erase_bh(&u_ctx->tid_list, tx_info->tid);
put_module:
/* release module refcount */
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
index 9cc343a16271..a6c18e2431cc 100644
--- a/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -1708,17 +1708,17 @@ static int gve_xsk_pool_disable(struct net_device *dev,
}
napi_rx = &priv->ntfy_blocks[priv->rx[qid].ntfy_id].napi;
- napi_disable(napi_rx); /* make sure current rx poll is done */
+ napi_disable_locked(napi_rx); /* make sure current rx poll is done */
tx_qid = gve_xdp_tx_queue_id(priv, qid);
napi_tx = &priv->ntfy_blocks[priv->tx[tx_qid].ntfy_id].napi;
- napi_disable(napi_tx); /* make sure current tx poll is done */
+ napi_disable_locked(napi_tx); /* make sure current tx poll is done */
gve_unreg_xsk_pool(priv, qid);
smp_mb(); /* Make sure it is visible to the workers on datapath */
- napi_enable(napi_rx);
- napi_enable(napi_tx);
+ napi_enable_locked(napi_rx);
+ napi_enable_locked(napi_tx);
if (gve_is_gqi(priv)) {
if (gve_rx_work_pending(&priv->rx[qid]))
napi_schedule(napi_rx);
diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
index 5cf242b28557..82ed5e48b00a 100644
--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -113,6 +113,12 @@ static void gve_rx_reset_ring_dqo(struct gve_priv *priv, int idx)
gve_free_to_page_pool(rx, bs, false);
else
gve_free_qpl_page_dqo(bs);
+
+ if (gve_buf_state_is_allocated(rx, bs) &&
+ bs->xsk_buff) {
+ xsk_buff_free(bs->xsk_buff);
+ bs->xsk_buff = NULL;
+ }
}
}
@@ -836,7 +842,12 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
}
if (unlikely(compl_desc->rx_error)) {
- gve_free_buffer(rx, buf_state);
+ if (buf_state->xsk_buff) {
+ xsk_buff_free(buf_state->xsk_buff);
+ gve_free_buf_state(rx, buf_state);
+ } else {
+ gve_free_buffer(rx, buf_state);
+ }
return -EINVAL;
}
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 73e051d26b9d..abebdb1fc262 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -553,10 +553,15 @@ static int ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
static void ibmveth_free_tx_ltb(struct ibmveth_adapter *adapter, int idx)
{
+ void *ptr = adapter->tx_ltb_ptr[idx];
+
+ if (!ptr)
+ return;
+
+ adapter->tx_ltb_ptr[idx] = NULL;
dma_unmap_single(&adapter->vdev->dev, adapter->tx_ltb_dma[idx],
adapter->tx_ltb_size, DMA_TO_DEVICE);
- kfree(adapter->tx_ltb_ptr[idx]);
- adapter->tx_ltb_ptr[idx] = NULL;
+ kfree(ptr);
}
static int ibmveth_allocate_tx_ltb(struct ibmveth_adapter *adapter, int idx)
@@ -667,7 +672,7 @@ static int ibmveth_open(struct net_device *netdev)
for (i = 0; i < netdev->real_num_tx_queues; i++) {
if (ibmveth_allocate_tx_ltb(adapter, i))
- goto out_free_tx_ltb;
+ goto out_unmap_filter_list;
}
adapter->rx_queue.index = 0;
@@ -718,10 +723,6 @@ static int ibmveth_open(struct net_device *netdev)
if (rc != 0) {
netdev_err(netdev, "unable to request irq 0x%x, rc %d\n",
netdev->irq, rc);
- do {
- lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
- } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
-
goto out_free_buffer_pools;
}
@@ -737,6 +738,9 @@ static int ibmveth_open(struct net_device *netdev)
return 0;
out_free_buffer_pools:
+ do {
+ lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+ } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
while (--i >= 0) {
if (adapter->rx_buff_pool[i].active)
ibmveth_free_buffer_pool(adapter,
@@ -746,10 +750,8 @@ out_unmap_filter_list:
dma_unmap_single(dev, adapter->filter_list_dma, 4096,
DMA_BIDIRECTIONAL);
-out_free_tx_ltb:
- while (--i >= 0) {
+ for (i = netdev->real_num_tx_queues - 1; i >= 0; i--)
ibmveth_free_tx_ltb(adapter, i);
- }
out_unmap_buffer_list:
dma_unmap_single(dev, adapter->buffer_