Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2026-03-03 (ice, libie, iavf, igb, igc)

Larysa removes VF restriction for LLDP filters on ice to allow for LLDP
traffic to reach the correct destination.

Jakub adds retry mechanism for AdminQ Read/Write SFF EEPROM call to
follow hardware specification on ice.

Zilin Guan adds cleanup path to free XDP rings on failure in
ice_set_ringparam().

Michal bypasses firmware logging unroll in libie when it isn't supported.

Kohei Enju fixes iavf to take into account hardware MTU support when
setting max MTU values.

Vivek Behera fixes issues on igb and igc using incorrect IRQs when Tx/Rx
queues do not share the same IRQ.

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue:
  igc: Fix trigger of incorrect irq in igc_xsk_wakeup function
  igb: Fix trigger of incorrect irq in igb_xsk_wakeup
  iavf: fix netdev->max_mtu to respect actual hardware limit
  libie: don't unroll if fwlog isn't supported
  ice: Fix memory leak in ice_set_ringparam()
  ice: fix retry for AQ command 0x06EE
  ice: reintroduce retry mechanism for indirect AQ
  ice: fix adding AQ LLDP filter for VF
====================

Link: https://patch.msgid.link/20260303231155.2895065-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-03-04 18:35:35 -08:00
commit 550921c67b
7 changed files with 110 additions and 47 deletions

View File

@ -2793,7 +2793,22 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
netdev->watchdog_timeo = 5 * HZ;
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = LIBIE_MAX_MTU;
/* PF/VF API: vf_res->max_mtu is max frame size (not MTU).
* Convert to MTU.
*/
if (!adapter->vf_res->max_mtu) {
netdev->max_mtu = LIBIE_MAX_MTU;
} else if (adapter->vf_res->max_mtu < LIBETH_RX_LL_LEN + ETH_MIN_MTU ||
adapter->vf_res->max_mtu >
LIBETH_RX_LL_LEN + LIBIE_MAX_MTU) {
netdev_warn_once(adapter->netdev,
"invalid max frame size %d from PF, using default MTU %d",
adapter->vf_res->max_mtu, LIBIE_MAX_MTU);
netdev->max_mtu = LIBIE_MAX_MTU;
} else {
netdev->max_mtu = adapter->vf_res->max_mtu - LIBETH_RX_LL_LEN;
}
if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",

View File

@ -1816,6 +1816,7 @@ static bool ice_should_retry_sq_send_cmd(u16 opcode)
case ice_aqc_opc_lldp_stop:
case ice_aqc_opc_lldp_start:
case ice_aqc_opc_lldp_filter_ctrl:
case ice_aqc_opc_sff_eeprom:
return true;
}
@ -1841,6 +1842,7 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
{
struct libie_aq_desc desc_cpy;
bool is_cmd_for_retry;
u8 *buf_cpy = NULL;
u8 idx = 0;
u16 opcode;
int status;
@ -1850,8 +1852,11 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
memset(&desc_cpy, 0, sizeof(desc_cpy));
if (is_cmd_for_retry) {
/* All retryable cmds are direct, without buf. */
WARN_ON(buf);
if (buf) {
buf_cpy = kmemdup(buf, buf_size, GFP_KERNEL);
if (!buf_cpy)
return -ENOMEM;
}
memcpy(&desc_cpy, desc, sizeof(desc_cpy));
}
@ -1863,12 +1868,14 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
hw->adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
break;
if (buf_cpy)
memcpy(buf, buf_cpy, buf_size);
memcpy(desc, &desc_cpy, sizeof(desc_cpy));
msleep(ICE_SQ_SEND_DELAY_TIME_MS);
} while (++idx < ICE_SQ_SEND_MAX_EXECUTE);
kfree(buf_cpy);
return status;
}
@ -6391,7 +6398,7 @@ int ice_lldp_fltr_add_remove(struct ice_hw *hw, struct ice_vsi *vsi, bool add)
struct ice_aqc_lldp_filter_ctrl *cmd;
struct libie_aq_desc desc;
if (vsi->type != ICE_VSI_PF || !ice_fw_supports_lldp_fltr_ctrl(hw))
if (!ice_fw_supports_lldp_fltr_ctrl(hw))
return -EOPNOTSUPP;
cmd = libie_aq_raw(&desc);

View File

@ -3332,7 +3332,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
rx_rings = kzalloc_objs(*rx_rings, vsi->num_rxq);
if (!rx_rings) {
err = -ENOMEM;
goto done;
goto free_xdp;
}
ice_for_each_rxq(vsi, i) {
@ -3359,7 +3359,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
}
kfree(rx_rings);
err = -ENOMEM;
goto free_tx;
goto free_xdp;
}
}
@ -3411,6 +3411,13 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
}
goto done;
free_xdp:
if (xdp_rings) {
ice_for_each_xdp_txq(vsi, i)
ice_free_tx_ring(&xdp_rings[i]);
kfree(xdp_rings);
}
free_tx:
/* error cleanup if the Rx allocations failed after getting Tx */
if (tx_rings) {
@ -4509,7 +4516,7 @@ ice_get_module_eeprom(struct net_device *netdev,
u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
struct ice_hw *hw = &pf->hw;
bool is_sfp = false;
unsigned int i, j;
unsigned int i;
u16 offset = 0;
u8 page = 0;
int status;
@ -4551,26 +4558,19 @@ ice_get_module_eeprom(struct net_device *netdev,
if (page == 0 || !(data[0x2] & 0x4)) {
u32 copy_len;
/* If i2c bus is busy due to slow page change or
* link management access, call can fail. This is normal.
* So we retry this a few times.
*/
for (j = 0; j < 4; j++) {
status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
!is_sfp, value,
SFF_READ_BLOCK_SIZE,
0, NULL);
netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
addr, offset, page, is_sfp,
value[0], value[1], value[2], value[3],
value[4], value[5], value[6], value[7],
status);
if (status) {
usleep_range(1500, 2500);
memset(value, 0, SFF_READ_BLOCK_SIZE);
continue;
}
break;
status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
!is_sfp, value,
SFF_READ_BLOCK_SIZE,
0, NULL);
netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%pe)\n",
addr, offset, page, is_sfp,
value[0], value[1], value[2], value[3],
value[4], value[5], value[6], value[7],
ERR_PTR(status));
if (status) {
netdev_err(netdev, "%s: error reading module EEPROM: status %pe\n",
__func__, ERR_PTR(status));
return status;
}
/* Make sure we have enough room for the new block */

View File

@ -524,6 +524,16 @@ bool igb_xmit_zc(struct igb_ring *tx_ring, struct xsk_buff_pool *xsk_pool)
return nb_pkts < budget;
}
static u32 igb_sw_irq_prep(struct igb_q_vector *q_vector)
{
u32 eics = 0;
if (!napi_if_scheduled_mark_missed(&q_vector->napi))
eics = q_vector->eims_value;
return eics;
}
int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
{
struct igb_adapter *adapter = netdev_priv(dev);
@ -542,20 +552,32 @@ int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
ring = adapter->tx_ring[qid];
if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
return -ENETDOWN;
if (!READ_ONCE(ring->xsk_pool))
return -EINVAL;
if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) {
if (flags & XDP_WAKEUP_TX) {
if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
return -ENETDOWN;
eics |= igb_sw_irq_prep(ring->q_vector);
}
if (flags & XDP_WAKEUP_RX) {
/* If IGB_FLAG_QUEUE_PAIRS is active, the q_vector
* and NAPI is shared between RX and TX.
* If NAPI is already running it would be marked as missed
* from the TX path, making this RX call a NOP
*/
ring = adapter->rx_ring[qid];
eics |= igb_sw_irq_prep(ring->q_vector);
}
if (eics) {
/* Cause software interrupt */
if (adapter->flags & IGB_FLAG_HAS_MSIX) {
eics |= ring->q_vector->eims_value;
if (adapter->flags & IGB_FLAG_HAS_MSIX)
wr32(E1000_EICS, eics);
} else {
else
wr32(E1000_ICS, E1000_ICS_RXDMT0);
}
}
return 0;

View File

@ -6906,28 +6906,29 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
return nxmit;
}
static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
struct igc_q_vector *q_vector)
static u32 igc_sw_irq_prep(struct igc_q_vector *q_vector)
{
struct igc_hw *hw = &adapter->hw;
u32 eics = 0;
eics |= q_vector->eims_value;
wr32(IGC_EICS, eics);
if (!napi_if_scheduled_mark_missed(&q_vector->napi))
eics = q_vector->eims_value;
return eics;
}
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
{
struct igc_adapter *adapter = netdev_priv(dev);
struct igc_q_vector *q_vector;
struct igc_hw *hw = &adapter->hw;
struct igc_ring *ring;
u32 eics = 0;
if (test_bit(__IGC_DOWN, &adapter->state))
return -ENETDOWN;
if (!igc_xdp_is_enabled(adapter))
return -ENXIO;
/* Check if queue_id is valid. Tx and Rx queue numbers are always same */
if (queue_id >= adapter->num_rx_queues)
return -EINVAL;
@ -6936,9 +6937,22 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
if (!ring->xsk_pool)
return -ENXIO;
q_vector = adapter->q_vector[queue_id];
if (!napi_if_scheduled_mark_missed(&q_vector->napi))
igc_trigger_rxtxq_interrupt(adapter, q_vector);
if (flags & XDP_WAKEUP_RX)
eics |= igc_sw_irq_prep(ring->q_vector);
if (flags & XDP_WAKEUP_TX) {
/* If IGC_FLAG_QUEUE_PAIRS is active, the q_vector
* and NAPI is shared between RX and TX.
* If NAPI is already running it would be marked as missed
* from the RX path, making this TX call a NOP
*/
ring = adapter->tx_ring[queue_id];
eics |= igc_sw_irq_prep(ring->q_vector);
}
if (eics)
/* Cause software interrupt */
wr32(IGC_EICS, eics);
return 0;
}

View File

@ -550,7 +550,8 @@ static void igc_ptp_free_tx_buffer(struct igc_adapter *adapter,
tstamp->buffer_type = 0;
/* Trigger txrx interrupt for transmit completion */
igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index, 0);
igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index,
XDP_WAKEUP_TX);
return;
}

View File

@ -1049,6 +1049,10 @@ void libie_fwlog_deinit(struct libie_fwlog *fwlog)
{
int status;
/* if FW logging isn't supported it means no configuration was done */
if (!libie_fwlog_supported(fwlog))
return;
/* make sure FW logging is disabled to not put the FW in a weird state
* for the next driver load
*/