* [PATCH net-next v8 5/7] r8169: add support and enable rss
From: javen @ 2026-06-15 3:13 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260615031345.548-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch adds support and enable rss for RTL8127.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
Changes in v2:
- some changes moved from Patch 2/7
Changes in v3:
- add struct rtl8169_rss_data. Allocate it dynamically when needed.
- define rss_key as an u32 array
- replace some magic bit numbers in rtl8169_set_rss_hash_opt() and
rtl8125_set_rx_q_num()
- use union to combine different rx descriptor, refactor struct RxDesc
- remove dead code from rtl8169_double_check_rss_support()
Changes in v4:
- rename macro definition, e.g R8127_MAX_IRQ to R8127_MAX_NUM_IRQVEC
- change hw_supp_indir_tbl_entries type to unsigned int
- change init_rx_desc_type type to enum
- remove rtl_check_rss_support(), add helper function
rtl_hw_support_rss()
- remove hw_curr_isr_ver, use irq_nvecs to judge whether we should
enable vector interrupt mapping, use tp->num_rx_ring to judge whether
we should enable rss
- remove function rtl8169_double_check_rss_support(), use
rtl8169_set_rx_ring_num() to set num_rx_ring according to tp->irq_nvecs
Changes in v5:
- no changes
Changes in v6:
- change rss_queue_num type from u8 to unsigned int
- fix rx desc clear in rtl8169_rx_clear() for different desc type
- clamping num_rx_ring with rounddown_pow_of_two()
Changes in v7:
- remove unused macro
- change unfixed type in rtl8169_store_reta
Changes in v8:
- refill desc->addr when rx_desc reset
- rtl8169_set_channels fixed in patch 7/7
---
drivers/net/ethernet/realtek/r8169_main.c | 394 ++++++++++++++++++++--
1 file changed, 357 insertions(+), 37 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 75f6401fa6cb..29bfac489ca7 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -89,6 +89,19 @@
#define R8127_MAX_TX_QUEUES 8
#define R8169_DEFAULT_RX_QUEUES 1
#define R8169_MAX_TX_QUEUES 1
+#define R8127_MAX_NUM_IRQVEC 32
+#define R8127_MIN_NUM_IRQVEC 30
+#define R8169_IRQ_DEFAULT 1
+#define RTL_RSS_KEY_SIZE 40
+#define RSS_CPU_NUM_MASK GENMASK(18, 16)
+#define RSS_HASH_MASK GENMASK(10, 8)
+#define RTL_MAX_INDIRECTION_TABLE_ENTRIES 128
+#define RXS_RSS_UDP BIT(27)
+#define RXS_RSS_IPV4 BIT(28)
+#define RXS_RSS_IPV6 BIT(29)
+#define RXS_RSS_TCP BIT(30)
+#define RXS_RSS_L3_TYPE_MASK (RXS_RSS_IPV4 | RXS_RSS_IPV6)
+#define RXS_RSS_L4_TYPE_MASK (RXS_RSS_TCP | RXS_RSS_UDP)
#define OCP_STD_PHY_BASE 0xa400
@@ -596,6 +609,20 @@ enum rtl_register_content {
#define ISRIMR_LINKCHG BIT(29)
#define ISRIMR_TOK_Q0 BIT(8)
#define ISRIMR_ROK_Q0 BIT(0)
+#define RTL_DESC_TYPE_CTRL 0xd8
+#define RSS_KEY_REG 0x4600
+#define RSS_INDIRECTION_TBL_REG 0x4700
+#define RSS_CTRL_TCP_IPV4_SUPP BIT(0)
+#define RTL_DESC_TYPE_RSS BIT(1)
+#define RSS_CTRL_IPV4_SUPP BIT(1)
+#define RSS_CTRL_TCP_IPV6_SUPP BIT(2)
+#define RSS_CTRL_IPV6_SUPP BIT(3)
+#define RSS_CTRL_IPV6_EXT_SUPP BIT(4)
+#define RSS_CTRL_TCP_IPV6_EXT_SUPP BIT(5)
+#define RX_RES_RSS BIT(22)
+#define RX_RUNT_RSS BIT(21)
+#define RX_CRC_RSS BIT(20)
+#define RTL_RX_Q_NUM_MASK GENMASK(4, 2)
};
enum rtl_desc_bit {
@@ -653,6 +680,11 @@ enum rtl_rx_desc_bit {
#define RxProtoIP (PID1 | PID0)
#define RxProtoMask RxProtoIP
+#define RX_UDPT_DESC_RSS BIT(19)
+#define RX_TCPT_DESC_RSS BIT(18)
+#define RX_UDPF_DESC_RSS BIT(16) /* UDP/IP checksum failed */
+#define RX_TCPF_DESC_RSS BIT(15) /* TCP/IP checksum failed */
+
IPFail = (1 << 16), /* IP checksum failed */
UDPFail = (1 << 15), /* UDP/IP checksum failed */
TCPFail = (1 << 14), /* TCP/IP checksum failed */
@@ -674,9 +706,27 @@ struct TxDesc {
};
struct RxDesc {
- __le32 opts1;
- __le32 opts2;
- __le64 addr;
+ union {
+ /* RX_DESC_TYPE_DEFAULT */
+ struct {
+ __le32 opts1;
+ __le32 opts2;
+ __le64 addr;
+ };
+
+ /* RX_DESC_TYPE_RSS */
+ struct {
+ union {
+ __le64 rss_addr;
+ struct {
+ __le32 rss_info;
+ __le32 rss_result;
+ } rss_dword;
+ };
+ __le32 rss_opts2;
+ __le32 rss_opts1;
+ };
+ };
};
struct ring_info {
@@ -748,9 +798,9 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
-enum rx_desc_ring_type {
- RX_DESC_RING_TYPE_DEFAULT,
- RX_DESC_RING_TYPE_RSS,
+enum rx_desc_type {
+ RX_DESC_TYPE_DEFAULT,
+ RX_DESC_TYPE_RSS,
};
struct rtl8169_rx_ring {
@@ -763,6 +813,12 @@ struct rtl8169_rx_ring {
struct page *rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
};
+struct rtl8169_rss_data {
+ u32 rss_key[RTL_RSS_KEY_SIZE / sizeof(u32)];
+ u8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES];
+ unsigned int hw_supp_indir_tbl_entries;
+};
+
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev;
@@ -782,7 +838,9 @@ struct rtl8169_private {
u16 tx_lpi_timer;
u32 irq_mask;
unsigned int hw_supp_num_rx_queues;
+ struct rtl8169_rss_data *rss_data;
unsigned int irq_nvecs;
+ enum rx_desc_type init_rx_desc_type;
struct clk *clk;
struct {
@@ -1612,6 +1670,11 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp)
}
}
+static bool rtl_hw_support_rss(struct rtl8169_private *tp)
+{
+ return tp->mac_version == RTL_GIGA_MAC_VER_80;
+}
+
static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
@@ -1913,9 +1976,20 @@ static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb)
TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;
}
-static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
+static void rtl8169_rx_vlan_tag(struct rtl8169_private *tp,
+ struct RxDesc *desc,
+ struct sk_buff *skb)
{
- u32 opts2 = le32_to_cpu(desc->opts2);
+ u32 opts2;
+
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ opts2 = le32_to_cpu(desc->rss_opts2);
+ break;
+ default:
+ opts2 = le32_to_cpu(desc->opts2);
+ break;
+ }
if (opts2 & RxVlanTag)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff));
@@ -2744,17 +2818,27 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
}
+static void rtl8169_init_rss(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->rss_data->hw_supp_indir_tbl_entries; i++)
+ tp->rss_data->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
+
+ netdev_rss_key_fill(tp->rss_data->rss_key, RTL_RSS_KEY_SIZE);
+}
+
static void rtl_setup_rx_params(struct rtl8169_private *tp)
{
tp->num_rx_rings = 1;
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_80:
tp->hw_supp_num_rx_queues = R8127_MAX_RX_QUEUES;
+ tp->rss_data->hw_supp_indir_tbl_entries = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
break;
default:
tp->hw_supp_num_rx_queues = R8169_DEFAULT_RX_QUEUES;
break;
}
+ tp->init_rx_desc_type = RX_DESC_TYPE_DEFAULT;
}
static void rtl_request_firmware(struct rtl8169_private *tp)
@@ -2879,6 +2963,59 @@ static void rtl_set_rx_max_size(struct rtl8169_private *tp)
RTL_W16(tp, RxMaxSize, R8169_RX_BUF_SIZE + 1);
}
+static void rtl8169_store_rss_key(struct rtl8169_private *tp)
+{
+ u32 num_entries = RTL_RSS_KEY_SIZE / sizeof(u32);
+ u32 *rss_key = tp->rss_data->rss_key;
+ const u16 rss_key_reg = RSS_KEY_REG;
+
+ /* Write redirection table to HW */
+ for (int i = 0; i < num_entries; i++)
+ RTL_W32(tp, rss_key_reg + (i * 4), rss_key[i]);
+}
+
+static void rtl8169_store_reta(struct rtl8169_private *tp)
+{
+ u8 *indir_tbl = tp->rss_data->rss_indir_tbl;
+ unsigned int i;
+
+ /* Write redirection table to HW */
+ for (i = 0; i < tp->rss_data->hw_supp_indir_tbl_entries; i += 4) {
+ u32 reta = (u32)indir_tbl[i] |
+ (u32)indir_tbl[i + 1] << 8 |
+ (u32)indir_tbl[i + 2] << 16 |
+ (u32)indir_tbl[i + 3] << 24;
+ RTL_W32(tp, RSS_INDIRECTION_TBL_REG + i, reta);
+ }
+}
+
+static void rtl8169_set_rss_hash_opt(struct rtl8169_private *tp)
+{
+ u32 rss_ctrl;
+
+ rss_ctrl = FIELD_PREP(RSS_CPU_NUM_MASK, ilog2(tp->num_rx_rings));
+
+ /* Perform hash on these packet types */
+ rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
+ | RSS_CTRL_IPV4_SUPP
+ | RSS_CTRL_IPV6_SUPP
+ | RSS_CTRL_IPV6_EXT_SUPP
+ | RSS_CTRL_TCP_IPV6_SUPP
+ | RSS_CTRL_TCP_IPV6_EXT_SUPP;
+
+ rss_ctrl |= FIELD_PREP(RSS_HASH_MASK,
+ ilog2(tp->rss_data->hw_supp_indir_tbl_entries));
+
+ RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
+}
+
+static void rtl_set_rss_config(struct rtl8169_private *tp)
+{
+ rtl8169_set_rss_hash_opt(tp);
+ rtl8169_store_reta(tp);
+ rtl8169_store_rss_key(tp);
+}
+
static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
{
struct rtl8169_rx_ring *ring = &tp->rx_ring[0];
@@ -3945,6 +4082,18 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)
return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13);
}
+static void rtl8125_set_rx_q_num(struct rtl8169_private *tp)
+{
+ u16 rx_q_num;
+ u16 q_ctrl;
+
+ rx_q_num = ilog2(tp->num_rx_rings);
+ q_ctrl = RTL_R16(tp, Q_NUM_CTRL_8125);
+ q_ctrl &= ~RTL_RX_Q_NUM_MASK;
+ q_ctrl |= FIELD_PREP(RTL_RX_Q_NUM_MASK, rx_q_num);
+ RTL_W16(tp, Q_NUM_CTRL_8125, q_ctrl);
+}
+
static void rtl8169_hw_enable_vec_mapping(struct rtl8169_private *tp)
{
u8 tmp;
@@ -3984,6 +4133,13 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
tp->mac_version == RTL_GIGA_MAC_VER_80)
RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
+ /* enable rx descriptor type v4 and set queue num for rss*/
+ if (tp->num_rx_rings > 1) {
+ rtl8125_set_rx_q_num(tp);
+ RTL_W8(tp, RTL_DESC_TYPE_CTRL,
+ RTL_R8(tp, RTL_DESC_TYPE_CTRL) | RTL_DESC_TYPE_RSS);
+ }
+
if (tp->mac_version == RTL_GIGA_MAC_VER_80)
r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00);
else if (tp->mac_version == RTL_GIGA_MAC_VER_70)
@@ -4220,6 +4376,12 @@ static void rtl_hw_start(struct rtl8169_private *tp)
rtl_hw_aspm_clkreq_enable(tp, true);
rtl_set_rx_max_size(tp);
rtl_set_rx_tx_desc_registers(tp);
+ if (rtl_is_8125(tp)) {
+ if (tp->num_rx_rings > 1)
+ rtl_set_rss_config(tp);
+ else
+ RTL_W32(tp, RSS_CTRL_8125, 0x00);
+ }
rtl_lock_config_regs(tp);
rtl_jumbo_config(tp);
@@ -4247,14 +4409,26 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static void rtl8169_mark_to_asic(struct RxDesc *desc)
+static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc *desc)
{
- u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
+ u32 eor;
- desc->opts2 = 0;
- /* Force memory writes to complete before releasing descriptor */
- dma_wmb();
- WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ eor = le32_to_cpu(desc->rss_opts1) & RingEnd;
+ desc->rss_opts2 = cpu_to_le32(0);
+ /* Force memory writes to complete before releasing descriptor */
+ dma_wmb();
+ WRITE_ONCE(desc->rss_opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
+ break;
+ default:
+ eor = le32_to_cpu(desc->opts1) & RingEnd;
+ desc->opts2 = cpu_to_le32(0);
+ /* Force memory writes to complete before releasing descriptor */
+ dma_wmb();
+ WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
+ break;
+ }
}
static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
@@ -4277,9 +4451,12 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
return NULL;
}
- desc->addr = cpu_to_le64(mapping);
ring->rx_desc_phy_addr[index] = mapping;
- rtl8169_mark_to_asic(desc);
+ if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
+ desc->rss_addr = cpu_to_le64(mapping);
+ else
+ desc->addr = cpu_to_le64(mapping);
+ rtl8169_mark_to_asic(tp, desc);
return data;
}
@@ -4295,8 +4472,25 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp, struct rtl8169_rx_ring
__free_pages(ring->rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
ring->rx_databuff[i] = NULL;
ring->rx_desc_phy_addr[i] = 0;
- ring->rx_desc_array[i].addr = 0;
- ring->rx_desc_array[i].opts1 = 0;
+ if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS) {
+ ring->rx_desc_array[i].rss_addr = 0;
+ ring->rx_desc_array[i].rss_opts1 = 0;
+ } else {
+ ring->rx_desc_array[i].addr = 0;
+ ring->rx_desc_array[i].opts1 = 0;
+ }
+ }
+}
+
+static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, struct RxDesc *desc)
+{
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ desc->rss_opts1 |= cpu_to_le32(RingEnd);
+ break;
+ default:
+ desc->opts1 |= cpu_to_le32(RingEnd);
+ break;
}
}
@@ -4316,7 +4510,7 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_ring *r
}
/* mark as last descriptor in the ring */
- ring->rx_desc_array[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd);
+ rtl8169_mark_as_last_descriptor(tp, &ring->rx_desc_array[NUM_RX_DESC - 1]);
return 0;
}
@@ -4466,13 +4660,30 @@ static void rtl8169_cleanup(struct rtl8169_private *tp)
rtl8169_init_ring_indexes(tp);
}
+static void rtl8169_set_desc_dma_addr(struct rtl8169_private *tp,
+ struct RxDesc *desc,
+ dma_addr_t mapping)
+{
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ desc->rss_addr = cpu_to_le64(mapping);
+ break;
+ default:
+ desc->addr = cpu_to_le64(mapping);
+ break;
+ }
+}
+
static void rtl8169_rx_desc_reset(struct rtl8169_private *tp)
{
for (int i = 0; i < tp->num_rx_rings; i++) {
struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
- for (int j = 0; j < NUM_RX_DESC; j++)
- rtl8169_mark_to_asic(ring->rx_desc_array + j);
+ for (int j = 0; j < NUM_RX_DESC; j++) {
+ rtl8169_set_desc_dma_addr(tp, ring->rx_desc_array + j,
+ ring->rx_desc_phy_addr[j]);
+ rtl8169_mark_to_asic(tp, ring->rx_desc_array + j);
+ }
}
}
@@ -4928,27 +5139,88 @@ static inline int rtl8169_fragmented_frame(u32 status)
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
-static inline void rtl8169_rx_csum(struct sk_buff *skb,
+static inline void rtl8169_rx_hash(struct rtl8169_private *tp,
+ struct RxDesc *desc,
+ struct sk_buff *skb)
+{
+ u32 rss_header_info;
+ u32 hash_val;
+
+ if (!(tp->dev->features & NETIF_F_RXHASH))
+ return;
+
+ rss_header_info = le32_to_cpu(desc->rss_dword.rss_info);
+
+ if (!(rss_header_info & RXS_RSS_L3_TYPE_MASK))
+ return;
+
+ hash_val = le32_to_cpu(desc->rss_dword.rss_result);
+
+ skb_set_hash(skb, hash_val,
+ (RXS_RSS_L4_TYPE_MASK & rss_header_info) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
+}
+
+static inline void rtl8169_rx_csum(struct rtl8169_private *tp,
+ struct sk_buff *skb,
struct RxDesc *desc)
{
- u32 status = le32_to_cpu(desc->opts1) & (RxProtoMask | RxCSFailMask);
+ bool csum_ok = false;
+ u32 opts1;
- if (status == RxProtoTCP || status == RxProtoUDP)
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ opts1 = le32_to_cpu(desc->rss_opts1);
+ if (((opts1 & RX_TCPT_DESC_RSS) && !(opts1 & RX_TCPF_DESC_RSS)) ||
+ ((opts1 & RX_UDPT_DESC_RSS) && !(opts1 & RX_UDPF_DESC_RSS)))
+ csum_ok = true;
+ break;
+ default:
+ opts1 = le32_to_cpu(desc->opts1) & (RxProtoMask | RxCSFailMask);
+ if (opts1 == RxProtoTCP || opts1 == RxProtoUDP)
+ csum_ok = true;
+ break;
+ }
+
+ if (csum_ok)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
}
+static __le32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc *desc)
+{
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ return READ_ONCE(desc->rss_opts1);
+ default:
+ return READ_ONCE(desc->opts1);
+ }
+}
+
static bool rtl8169_check_rx_desc_error(struct net_device *dev,
struct rtl8169_private *tp,
u32 status)
{
- if (unlikely(status & RxRES)) {
- if (status & (RxRWT | RxRUNT))
- dev->stats.rx_length_errors++;
- if (status & RxCRC)
- dev->stats.rx_crc_errors++;
- return true;
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ if (unlikely(status & RX_RES_RSS)) {
+ if (status & RX_RUNT_RSS)
+ dev->stats.rx_length_errors++;
+ if (status & RX_CRC_RSS)
+ dev->stats.rx_crc_errors++;
+ return true;
+ }
+ break;
+ default:
+ if (unlikely(status & RxRES)) {
+ if (status & (RxRWT | RxRUNT))
+ dev->stats.rx_length_errors++;
+ if (status & RxCRC)
+ dev->stats.rx_crc_errors++;
+ return true;
+ }
+ break;
}
return false;
}
@@ -4967,7 +5239,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
dma_addr_t addr;
u32 status;
- status = le32_to_cpu(READ_ONCE(desc->opts1));
+ status = le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc));
if (status & DescOwn)
break;
@@ -4985,7 +5257,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
if (!(dev->features & NETIF_F_RXALL))
goto release_descriptor;
- else if (status & RxRWT || !(status & (RxRUNT | RxCRC)))
+ if ((status & RxRWT || !(status & (RxRUNT | RxCRC))) &&
+ tp->init_rx_desc_type == RX_DESC_TYPE_DEFAULT)
goto release_descriptor;
}
@@ -5017,11 +5290,12 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
skb->tail += pkt_size;
skb->len = pkt_size;
dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
-
- rtl8169_rx_csum(skb, desc);
+ if (tp->num_rx_rings > 1)
+ rtl8169_rx_hash(tp, desc, skb);
+ rtl8169_rx_csum(tp, skb, desc);
skb->protocol = eth_type_trans(skb, dev);
- rtl8169_rx_vlan_tag(desc, skb);
+ rtl8169_rx_vlan_tag(tp, desc, skb);
if (skb->pkt_type == PACKET_MULTICAST)
dev->stats.multicast++;
@@ -5030,7 +5304,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
dev_sw_netstats_rx_add(dev, pkt_size);
release_descriptor:
- rtl8169_mark_to_asic(desc);
+ rtl8169_set_desc_dma_addr(tp, desc, ring->rx_desc_phy_addr[entry]);
+ rtl8169_mark_to_asic(tp, desc);
}
return count;
@@ -5601,6 +5876,32 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp)
}
}
+static int get_max_irq_nvecs(struct rtl8169_private *tp)
+{
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
+ return R8127_MAX_NUM_IRQVEC;
+ return R8169_IRQ_DEFAULT;
+}
+
+static int get_min_irq_nvecs(struct rtl8169_private *tp)
+{
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
+ return R8127_MIN_NUM_IRQVEC;
+ return R8169_IRQ_DEFAULT;
+}
+
+static void rtl8169_set_rx_ring_num(struct rtl8169_private *tp)
+{
+ if (tp->irq_nvecs >= get_min_irq_nvecs(tp)) {
+ unsigned int rss_queue_num = netif_get_num_default_rss_queues();
+
+ tp->num_rx_rings = rounddown_pow_of_two(min(rss_queue_num,
+ tp->hw_supp_num_rx_queues));
+ if (tp->num_rx_rings >= 2)
+ tp->init_rx_desc_type = RX_DESC_TYPE_RSS;
+ }
+}
+
static int rtl_alloc_irq(struct rtl8169_private *tp)
{
struct pci_dev *pdev = tp->pci_dev;
@@ -5621,7 +5922,10 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
break;
}
- nvecs = pci_alloc_irq_vectors(pdev, 1, 1, flags);
+ nvecs = pci_alloc_irq_vectors(pdev, get_min_irq_nvecs(tp), get_max_irq_nvecs(tp), flags);
+
+ if (nvecs < 0)
+ nvecs = pci_alloc_irq_vectors(pdev, 1, 1, flags);
if (nvecs < 0)
return nvecs;
@@ -6045,6 +6349,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->dash_type = rtl_get_dash_type(tp);
tp->dash_enabled = rtl_dash_is_enabled(tp);
+ if (rtl_hw_support_rss(tp)) {
+ tp->rss_data = devm_kzalloc(&pdev->dev, sizeof(*tp->rss_data), GFP_KERNEL);
+ if (!tp->rss_data)
+ return -ENOMEM;
+ }
+
tp->cp_cmd = RTL_R16(tp, CPlusCmd) & CPCMD_MASK;
if (sizeof(dma_addr_t) > 4 && tp->mac_version >= RTL_GIGA_MAC_VER_18 &&
@@ -6065,6 +6375,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc < 0)
return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n");
+ rtl8169_set_rx_ring_num(tp);
+
+ if (rtl_hw_support_rss(tp))
+ rtl8169_init_rss(tp);
+
INIT_WORK(&tp->wk.work, rtl_task);
disable_work(&tp->wk.work);
@@ -6077,6 +6392,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ if (rtl_hw_support_rss(tp) && tp->num_rx_rings > 1) {
+ dev->hw_features |= NETIF_F_RXHASH;
+ dev->features |= NETIF_F_RXHASH;
+ }
+
/*
* Pretend we are using VLANs; This bypasses a nasty bug where
* Interrupts stop flowing on high load on 8110SCd controllers.
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v8 6/7] r8169: move struct ethtool_ops
From: javen @ 2026-06-15 3:13 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260615031345.548-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
The patch moves the rtl8169_ethtool_ops definition further down in
r8169_main.c so that subsequent additions of rtl8169_get_channels and
rtl8169_set_channels can be referenced from the ops struct without
needing forward declarations.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
Changes in v2:
- no changes
Changes in v3:
- no changes
Changes in v4:
- no changes
Changes in v5:
- no changes
Changes in v6:
- modify commit message
Changes in v7:
- no changes
Changes in v8:
- no changes
---
drivers/net/ethernet/realtek/r8169_main.c | 56 +++++++++++------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 29bfac489ca7..e43366468101 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -2536,34 +2536,6 @@ static int rtl8169_set_link_ksettings(struct net_device *ndev,
return 0;
}
-static const struct ethtool_ops rtl8169_ethtool_ops = {
- .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
- ETHTOOL_COALESCE_MAX_FRAMES,
- .get_drvinfo = rtl8169_get_drvinfo,
- .get_regs_len = rtl8169_get_regs_len,
- .get_link = ethtool_op_get_link,
- .get_coalesce = rtl_get_coalesce,
- .set_coalesce = rtl_set_coalesce,
- .get_regs = rtl8169_get_regs,
- .get_wol = rtl8169_get_wol,
- .set_wol = rtl8169_set_wol,
- .get_strings = rtl8169_get_strings,
- .get_sset_count = rtl8169_get_sset_count,
- .get_ethtool_stats = rtl8169_get_ethtool_stats,
- .get_ts_info = ethtool_op_get_ts_info,
- .nway_reset = phy_ethtool_nway_reset,
- .get_eee = rtl8169_get_eee,
- .set_eee = rtl8169_set_eee,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = rtl8169_set_link_ksettings,
- .get_ringparam = rtl8169_get_ringparam,
- .get_pause_stats = rtl8169_get_pause_stats,
- .get_pauseparam = rtl8169_get_pauseparam,
- .set_pauseparam = rtl8169_set_pauseparam,
- .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
- .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
-};
-
static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool gmii)
{
/* Chips combining a 1Gbps MAC with a 100Mbps PHY */
@@ -6256,6 +6228,34 @@ static void r8169_init_napi(struct rtl8169_private *tp)
}
}
+static const struct ethtool_ops rtl8169_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_MAX_FRAMES,
+ .get_drvinfo = rtl8169_get_drvinfo,
+ .get_regs_len = rtl8169_get_regs_len,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = rtl_get_coalesce,
+ .set_coalesce = rtl_set_coalesce,
+ .get_regs = rtl8169_get_regs,
+ .get_wol = rtl8169_get_wol,
+ .set_wol = rtl8169_set_wol,
+ .get_strings = rtl8169_get_strings,
+ .get_sset_count = rtl8169_get_sset_count,
+ .get_ethtool_stats = rtl8169_get_ethtool_stats,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .nway_reset = phy_ethtool_nway_reset,
+ .get_eee = rtl8169_get_eee,
+ .set_eee = rtl8169_set_eee,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = rtl8169_set_link_ksettings,
+ .get_ringparam = rtl8169_get_ringparam,
+ .get_pause_stats = rtl8169_get_pause_stats,
+ .get_pauseparam = rtl8169_get_pauseparam,
+ .set_pauseparam = rtl8169_set_pauseparam,
+ .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
+ .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
+};
+
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct rtl_chip_info *chip;
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v8 2/7] r8169: add support for multi rx queues
From: javen @ 2026-06-15 3:13 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260615031345.548-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch adds support for multi rx queues. RSS requires multi rx
queues to receive packets. So we need struct rtl8169_rx_ring for each
queue.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
Changes in v2:
- sort some registers by its number
- remove some unused definitions, like RX_DESC_RING_TYPE_MAX
- change recheck_desc_ownbit type
- remove rdsar_reg in rx_ring struct
- opts1 are different in rx_desc and rx_desc_rss, move the judgement
to Patch 5/7
Changes in v3:
- remove ring->rx_desc_alloc_size, use constant instead
Changes in v4:
- change rdsar_reg type to unsigned int
- follow reverse xmas tree, in rtl_set_rx_tx_desc_registers(),
rtl8169_alloc_rx_data(), rtl8169_alloc_rx_desc(),
rtl8169_free_rx_desc()
- add comments on LED_CTRL, remove helper function
Changes in v5:
- modify rtl8169_init_ring(), do rx clear when failed
- add definition R8169_MAX_TX_QUEUES 1
Changes in v6:
- Restore the secondary Rx error filter when NETIF_F_RXFALL is enabled
in rtl_rx()
Changes in v7:
- remove code associated with recheck_desc_ownbit
Changes in v8:
- remove le64_to_cpu() for addr, rx get addr from rx_desc_phy_addr
---
drivers/net/ethernet/realtek/r8169_main.c | 242 +++++++++++++++++-----
1 file changed, 186 insertions(+), 56 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 8f3a5c50299f..f995a731116a 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -74,9 +74,20 @@
#define NUM_TX_DESC 256 /* Number of Tx descriptor registers */
#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
-#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
+
+/*
+ * Workaround for the hardware DMA prefetcher. The H/W might aggressively
+ * fetch one more descriptor even after hitting the RingEnd mark. We
+ * allocate this extra dummy space as padding to prevent out-of-bounds
+ * access and potential IOMMU faults.
+ */
+#define R8169_RX_RING_BYTES ((NUM_RX_DESC + 1) * sizeof(struct RxDesc))
#define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1)
#define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS)
+#define R8169_MAX_RX_QUEUES 8
+#define R8127_MAX_RX_QUEUES 8
+#define R8169_DEFAULT_RX_QUEUES 1
+#define R8169_MAX_TX_QUEUES 1
#define OCP_STD_PHY_BASE 0xa400
@@ -441,6 +452,7 @@ enum rtl8125_registers {
TxPoll_8125 = 0x90,
LEDSEL3 = 0x96,
MAC0_BKP = 0x19e0,
+ RDSAR_Q1_LOW = 0x4000,
RSS_CTRL_8125 = 0x4500,
Q_NUM_CTRL_8125 = 0x4800,
EEE_TXIDLE_TIMER_8125 = 0x6048,
@@ -728,6 +740,21 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
+enum rx_desc_ring_type {
+ RX_DESC_RING_TYPE_DEFAULT,
+ RX_DESC_RING_TYPE_RSS,
+};
+
+struct rtl8169_rx_ring {
+ u32 index; /* Rx queue index */
+ u32 cur_rx; /* Index of next Rx pkt. */
+ u32 dirty_rx; /* Index for recycling. */
+ struct RxDesc *rx_desc_array; /* array of Rx Desc*/
+ dma_addr_t rx_desc_phy_addr[NUM_RX_DESC]; /* Rx data buffer physical dma address */
+ dma_addr_t rx_phy_addr; /* Rx desc physical address */
+ struct page *rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
+};
+
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev;
@@ -735,20 +762,18 @@ struct rtl8169_private {
struct phy_device *phydev;
enum mac_version mac_version;
enum rtl_dash_type dash_type;
- u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
u32 dirty_tx;
struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
- struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
dma_addr_t TxPhyAddr;
- dma_addr_t RxPhyAddr;
- struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
struct napi_struct *rtl8169_napi;
+ struct rtl8169_rx_ring rx_ring[R8169_MAX_RX_QUEUES];
unsigned int num_rx_rings;
u16 cp_cmd;
u16 tx_lpi_timer;
u32 irq_mask;
+ unsigned int hw_supp_num_rx_queues;
unsigned int irq_nvecs;
struct clk *clk;
@@ -2620,9 +2645,27 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
}
}
+static void rtl8169_rx_desc_init(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ memset(ring->rx_desc_array, 0x0, R8169_RX_RING_BYTES);
+ }
+}
+
static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
{
- tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
+ tp->dirty_tx = 0;
+ tp->cur_tx = 0;
+
+ for (int i = 0; i < tp->hw_supp_num_rx_queues; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ ring->dirty_rx = 0;
+ ring->cur_rx = 0;
+ ring->index = i;
+ }
}
static void rtl_jumbo_config(struct rtl8169_private *tp)
@@ -2684,6 +2727,14 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
static void rtl_setup_rx_params(struct rtl8169_private *tp)
{
tp->num_rx_rings = 1;
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_80:
+ tp->hw_supp_num_rx_queues = R8127_MAX_RX_QUEUES;
+ break;
+ default:
+ tp->hw_supp_num_rx_queues = R8169_DEFAULT_RX_QUEUES;
+ break;
+ }
}
static void rtl_request_firmware(struct rtl8169_private *tp)
@@ -2810,6 +2861,8 @@ static void rtl_set_rx_max_size(struct rtl8169_private *tp)
static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
{
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[0];
+
/*
* Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
* register to be written before TxDescAddrLow to work.
@@ -2817,8 +2870,16 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
*/
RTL_W32(tp, TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
RTL_W32(tp, TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
- RTL_W32(tp, RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
- RTL_W32(tp, RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
+ RTL_W32(tp, RxDescAddrHigh, ((u64) ring->rx_phy_addr) >> 32);
+ RTL_W32(tp, RxDescAddrLow, ((u64) ring->rx_phy_addr) & DMA_BIT_MASK(32));
+
+ for (int i = 1; i < tp->num_rx_rings; i++) {
+ unsigned int rdsar_reg = RDSAR_Q1_LOW + (i - 1) * 8;
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ RTL_W32(tp, rdsar_reg + 4, ((u64)ring->rx_phy_addr >> 32));
+ RTL_W32(tp, rdsar_reg, ((u64)ring->rx_phy_addr) & DMA_BIT_MASK(32));
+ }
}
static void rtl8169_set_magic_reg(struct rtl8169_private *tp)
@@ -4165,8 +4226,9 @@ static void rtl8169_mark_to_asic(struct RxDesc *desc)
}
static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
- struct RxDesc *desc)
+ struct rtl8169_rx_ring *ring, unsigned int index)
{
+ struct RxDesc *desc = ring->rx_desc_array + index;
struct device *d = tp_to_dev(tp);
int node = dev_to_node(d);
dma_addr_t mapping;
@@ -4184,55 +4246,106 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
}
desc->addr = cpu_to_le64(mapping);
+ ring->rx_desc_phy_addr[index] = mapping;
rtl8169_mark_to_asic(desc);
return data;
}
-static void rtl8169_rx_clear(struct rtl8169_private *tp)
+static void rtl8169_rx_clear(struct rtl8169_private *tp, struct rtl8169_rx_ring *ring)
{
int i;
- for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) {
+ for (i = 0; i < NUM_RX_DESC && ring->rx_databuff[i]; i++) {
dma_unmap_page(tp_to_dev(tp),
- le64_to_cpu(tp->RxDescArray[i].addr),
+ ring->rx_desc_phy_addr[i],
R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
- __free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
- tp->Rx_databuff[i] = NULL;
- tp->RxDescArray[i].addr = 0;
- tp->RxDescArray[i].opts1 = 0;
+ __free_pages(ring->rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
+ ring->rx_databuff[i] = NULL;
+ ring->rx_desc_phy_addr[i] = 0;
+ ring->rx_desc_array[i].addr = 0;
+ ring->rx_desc_array[i].opts1 = 0;
}
}
-static int rtl8169_rx_fill(struct rtl8169_private *tp)
+static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_ring *ring)
{
int i;
for (i = 0; i < NUM_RX_DESC; i++) {
struct page *data;
- data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
+ data = rtl8169_alloc_rx_data(tp, ring, i);
if (!data) {
- rtl8169_rx_clear(tp);
+ rtl8169_rx_clear(tp, ring);
return -ENOMEM;
}
- tp->Rx_databuff[i] = data;
+ ring->rx_databuff[i] = data;
}
/* mark as last descriptor in the ring */
- tp->RxDescArray[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd);
+ ring->rx_desc_array[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd);
return 0;
}
+static int rtl8169_alloc_rx_desc(struct rtl8169_private *tp)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ struct rtl8169_rx_ring *ring;
+
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ ring = &tp->rx_ring[i];
+ ring->rx_desc_array = dma_alloc_coherent(&pdev->dev,
+ R8169_RX_RING_BYTES,
+ &ring->rx_phy_addr,
+ GFP_KERNEL);
+ if (!ring->rx_desc_array)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void rtl8169_free_rx_desc(struct rtl8169_private *tp)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ struct rtl8169_rx_ring *ring;
+
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ ring = &tp->rx_ring[i];
+ if (ring->rx_desc_array) {
+ dma_free_coherent(&pdev->dev,
+ R8169_RX_RING_BYTES,
+ ring->rx_desc_array,
+ ring->rx_phy_addr);
+ ring->rx_desc_array = NULL;
+ }
+ }
+}
+
static int rtl8169_init_ring(struct rtl8169_private *tp)
{
+ int i, ret;
+
rtl8169_init_ring_indexes(tp);
+ rtl8169_rx_desc_init(tp);
memset(tp->tx_skb, 0, sizeof(tp->tx_skb));
- memset(tp->Rx_databuff, 0, sizeof(tp->Rx_databuff));
- return rtl8169_rx_fill(tp);
+ for (i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ memset(ring->rx_databuff, 0, sizeof(ring->rx_databuff));
+ ret = rtl8169_rx_fill(tp, ring);
+ if (ret < 0)
+ goto err_clear;
+ }
+ return 0;
+
+err_clear:
+ while (--i >= 0)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
+ return ret;
}
static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int entry)
@@ -4321,16 +4434,23 @@ static void rtl8169_cleanup(struct rtl8169_private *tp)
rtl8169_init_ring_indexes(tp);
}
-static void rtl_reset_work(struct rtl8169_private *tp)
+static void rtl8169_rx_desc_reset(struct rtl8169_private *tp)
{
- int i;
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ for (int j = 0; j < NUM_RX_DESC; j++)
+ rtl8169_mark_to_asic(ring->rx_desc_array + j);
+ }
+}
+static void rtl_reset_work(struct rtl8169_private *tp)
+{
netif_stop_queue(tp->dev);
rtl8169_cleanup(tp);
- for (i = 0; i < NUM_RX_DESC; i++)
- rtl8169_mark_to_asic(tp->RxDescArray + i);
+ rtl8169_rx_desc_reset(tp);
rtl8169_napi_enable(tp);
rtl_hw_start(tp);
@@ -4776,9 +4896,10 @@ static inline int rtl8169_fragmented_frame(u32 status)
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
-static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
+static inline void rtl8169_rx_csum(struct sk_buff *skb,
+ struct RxDesc *desc)
{
- u32 status = opts1 & (RxProtoMask | RxCSFailMask);
+ u32 status = le32_to_cpu(desc->opts1) & (RxProtoMask | RxCSFailMask);
if (status == RxProtoTCP || status == RxProtoUDP)
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -4786,15 +4907,29 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
skb_checksum_none_assert(skb);
}
+static bool rtl8169_check_rx_desc_error(struct net_device *dev,
+ struct rtl8169_private *tp,
+ u32 status)
+{
+ if (unlikely(status & RxRES)) {
+ if (status & (RxRWT | RxRUNT))
+ dev->stats.rx_length_errors++;
+ if (status & RxCRC)
+ dev->stats.rx_crc_errors++;
+ return true;
+ }
+ return false;
+}
+
static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
- int budget, struct napi_struct *napi)
+ struct rtl8169_rx_ring *ring, int budget, struct napi_struct *napi)
{
struct device *d = tp_to_dev(tp);
int count;
- for (count = 0; count < budget; count++, tp->cur_rx++) {
- unsigned int pkt_size, entry = tp->cur_rx % NUM_RX_DESC;
- struct RxDesc *desc = tp->RxDescArray + entry;
+ for (count = 0; count < budget; count++, ring->cur_rx++) {
+ unsigned int pkt_size, entry = ring->cur_rx % NUM_RX_DESC;
+ struct RxDesc *desc = ring->rx_desc_array + entry;
struct sk_buff *skb;
const void *rx_buf;
dma_addr_t addr;
@@ -4810,15 +4945,11 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
*/
dma_rmb();
- if (unlikely(status & RxRES)) {
+ if (rtl8169_check_rx_desc_error(dev, tp, status)) {
if (net_ratelimit())
netdev_warn(dev, "Rx ERROR. status = %08x\n",
status);
dev->stats.rx_errors++;
- if (status & (RxRWT | RxRUNT))
- dev->stats.rx_length_errors++;
- if (status & RxCRC)
- dev->stats.rx_crc_errors++;
if (!(dev->features & NETIF_F_RXALL))
goto release_descriptor;
@@ -4845,8 +4976,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
goto release_descriptor;
}
- addr = le64_to_cpu(desc->addr);
- rx_buf = page_address(tp->Rx_databuff[entry]);
+ addr = ring->rx_desc_phy_addr[entry];
+ rx_buf = page_address(ring->rx_databuff[entry]);
dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
prefetch(rx_buf);
@@ -4855,7 +4986,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
skb->len = pkt_size;
dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
- rtl8169_rx_csum(skb, status);
+ rtl8169_rx_csum(skb, desc);
skb->protocol = eth_type_trans(skb, dev);
rtl8169_rx_vlan_tag(desc, skb);
@@ -4973,7 +5104,8 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
rtl_tx(dev, tp, budget);
- work_done = rtl_rx(dev, tp, budget, napi);
+ /* rtl8169_poll() is used only when there is a single RX ring. */
+ work_done = rtl_rx(dev, tp, &tp->rx_ring[0], budget, napi);
if (work_done < budget && napi_complete_done(napi, work_done))
rtl_irq_enable(tp);
@@ -5104,18 +5236,17 @@ static int rtl8169_close(struct net_device *dev)
netif_stop_queue(dev);
rtl8169_down(tp);
- rtl8169_rx_clear(tp);
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
rtl8169_free_irq(tp);
phy_disconnect(tp->phydev);
- dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
tp->TxPhyAddr);
tp->TxDescArray = NULL;
- tp->RxDescArray = NULL;
+ rtl8169_free_rx_desc(tp);
pm_runtime_put_sync(&pdev->dev);
@@ -5151,10 +5282,8 @@ static int rtl_open(struct net_device *dev)
if (!tp->TxDescArray)
goto out;
- tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
- &tp->RxPhyAddr, GFP_KERNEL);
- if (!tp->RxDescArray)
- goto err_free_tx_0;
+ if (rtl8169_alloc_rx_desc(tp) < 0)
+ goto err_free_rx_1;
retval = rtl8169_init_ring(tp);
if (retval < 0)
@@ -5182,12 +5311,10 @@ static int rtl_open(struct net_device *dev)
rtl8169_free_irq(tp);
err_release_fw_2:
rtl_release_firmware(tp);
- rtl8169_rx_clear(tp);
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
err_free_rx_1:
- dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
- tp->RxDescArray = NULL;
-err_free_tx_0:
+ rtl8169_free_rx_desc(tp);
dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
tp->TxPhyAddr);
tp->TxDescArray = NULL;
@@ -5688,7 +5815,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 txconfig;
u32 xid;
- dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
+ dev = devm_alloc_etherdev_mqs(&pdev->dev, sizeof(*tp),
+ R8169_MAX_TX_QUEUES,
+ R8169_MAX_RX_QUEUES);
+
if (!dev)
return -ENOMEM;
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v8 7/7] r8169: support setting rx queue numbers via ethtool
From: javen @ 2026-06-15 3:13 UTC (permalink / raw)
To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, horms
Cc: netdev, linux-kernel, Javen Xu
In-Reply-To: <20260615031345.548-1-javen_xu@realsil.com.cn>
From: Javen Xu <javen_xu@realsil.com.cn>
This patch add support for changing rx queues by ethtool. We can set rx
1, 2, 4, 8 by ethtool -L eth1 rx num.
Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
Changes in v2:
- no changes
Changes in v3:
- no changes
Changes in v4:
- remove rss_support and rss_enable
- remove some zero-initialized
- use kzalloc_objs instead of kcalloc
Changes in v5:
- no changes
Changes in v6:
- change subject of this patch
- defer the assignment of tp->init_rx_desc_type until after
rtl8169_down()
- call netif_set_real_num_rx_queues() to synchronize the new rx queue
number with networking core
Changes in v7:
- no changes
Changes in v8:
- if dev is not running, updating tp->rss_data->rss_indir_tbl and
calling netif_set_real_num_rx_queue when change rx queue number
- if system does not provide enough irq_nvecs, return -EINVAL
- malloc new_rx before device down
---
drivers/net/ethernet/realtek/r8169_main.c | 146 +++++++++++++++++++++-
1 file changed, 144 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index e43366468101..c893f0e3ecff 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -2790,11 +2790,16 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
}
-static void rtl8169_init_rss(struct rtl8169_private *tp)
+static void rtl8169_set_rss_indir_tbl(struct rtl8169_private *tp,
+ unsigned int num_rx_rings)
{
for (int i = 0; i < tp->rss_data->hw_supp_indir_tbl_entries; i++)
- tp->rss_data->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
+ tp->rss_data->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, num_rx_rings);
+}
+static void rtl8169_init_rss(struct rtl8169_private *tp)
+{
+ rtl8169_set_rss_indir_tbl(tp, tp->num_rx_rings);
netdev_rss_key_fill(tp->rss_data->rss_key, RTL_RSS_KEY_SIZE);
}
@@ -6228,6 +6233,141 @@ static void r8169_init_napi(struct rtl8169_private *tp)
}
}
+static void rtl8169_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ ch->max_rx = tp->hw_supp_num_rx_queues;
+ ch->max_tx = 1;
+
+ ch->rx_count = tp->num_rx_rings;
+ ch->tx_count = 1;
+}
+
+static int rtl8169_realloc_rx(struct rtl8169_private *tp,
+ struct rtl8169_rx_ring *new_rx,
+ int new_count)
+{
+ int i, ret;
+
+ for (i = 0; i < new_count; i++) {
+ struct rtl8169_rx_ring *ring = &new_rx[i];
+
+ ring->rx_desc_array = dma_alloc_coherent(&tp->pci_dev->dev,
+ R8169_RX_RING_BYTES,
+ &ring->rx_phy_addr,
+ GFP_KERNEL);
+ if (!ring->rx_desc_array) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ memset(ring->rx_databuff, 0, sizeof(ring->rx_databuff));
+ ret = rtl8169_rx_fill(tp, ring);
+ if (ret) {
+ dma_free_coherent(&tp->pci_dev->dev, R8169_RX_RING_BYTES,
+ ring->rx_desc_array, ring->rx_phy_addr);
+ goto err_free;
+ }
+ }
+ return 0;
+
+err_free:
+ while (--i >= 0) {
+ rtl8169_rx_clear(tp, &new_rx[i]);
+ dma_free_coherent(&tp->pci_dev->dev, R8169_RX_RING_BYTES,
+ new_rx[i].rx_desc_array, new_rx[i].rx_phy_addr);
+ }
+ return ret;
+}
+
+static int rtl8169_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ bool if_running = netif_running(dev);
+ enum rx_desc_type old_rx_desc_type;
+ enum rx_desc_type new_desc_type;
+ struct rtl8169_rx_ring *new_rx;
+ int i, ret;
+
+ old_rx_desc_type = tp->init_rx_desc_type;
+
+ if (!rtl_hw_support_rss(tp)) {
+ netdev_warn(dev, "This chip does not support multiple channels/RSS.\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (ch->rx_count > R8169_MAX_RX_QUEUES || !is_power_of_2(ch->rx_count) ||
+ tp->irq_nvecs < get_min_irq_nvecs(tp))
+ return -EINVAL;
+
+ if (ch->rx_count == tp->num_rx_rings)
+ return 0;
+
+ new_desc_type = ch->rx_count > 1 ? RX_DESC_TYPE_RSS : RX_DESC_TYPE_DEFAULT;
+
+ if (!if_running) {
+ ret = netif_set_real_num_rx_queues(dev, ch->rx_count);
+ if (ret)
+ return ret;
+
+ tp->num_rx_rings = ch->rx_count;
+ tp->init_rx_desc_type = new_desc_type;
+
+ rtl8169_set_rss_indir_tbl(tp, tp->num_rx_rings);
+ rtl_set_irq_mask(tp);
+ return 0;
+ }
+
+ new_rx = kzalloc_objs(*new_rx, R8169_MAX_RX_QUEUES);
+ if (!new_rx)
+ return -ENOMEM;
+
+ netif_stop_queue(dev);
+ rtl8169_down(tp);
+
+ ret = netif_set_real_num_rx_queues(dev, ch->rx_count);
+ if (ret)
+ goto err_up;
+
+ tp->init_rx_desc_type = new_desc_type;
+
+ ret = rtl8169_realloc_rx(tp, new_rx, ch->rx_count);
+ if (ret)
+ goto err_reset;
+
+ for (i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
+ rtl8169_free_rx_desc(tp);
+
+ tp->num_rx_rings = ch->rx_count;
+
+ memset(tp->rx_ring, 0, sizeof(tp->rx_ring));
+ memcpy(tp->rx_ring, new_rx, sizeof(*new_rx) * ch->rx_count);
+
+ rtl8169_set_rss_indir_tbl(tp, tp->num_rx_rings);
+ rtl_set_irq_mask(tp);
+
+ rtl8169_up(tp);
+ netif_start_queue(dev);
+
+ kfree(new_rx);
+
+ return 0;
+
+err_reset:
+ netif_set_real_num_rx_queues(dev, tp->num_rx_rings);
+ tp->init_rx_desc_type = old_rx_desc_type;
+err_up:
+ rtl8169_up(tp);
+ netif_start_queue(dev);
+ kfree(new_rx);
+
+ return ret;
+}
+
static const struct ethtool_ops rtl8169_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES,
@@ -6246,6 +6386,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.nway_reset = phy_ethtool_nway_reset,
.get_eee = rtl8169_get_eee,
.set_eee = rtl8169_set_eee,
+ .get_channels = rtl8169_get_channels,
+ .set_channels = rtl8169_set_channels,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = rtl8169_set_link_ksettings,
.get_ringparam = rtl8169_get_ringparam,
--
2.43.0
^ permalink raw reply related
* RE: [PATCH net-next v6 4/5] net: wangxun: implement soft quiesce for PCIe error recovery
From: Jiawen Wu @ 2026-06-15 3:06 UTC (permalink / raw)
To: 'Simon Horman'
Cc: netdev, 'Mengyuan Lou', 'Andrew Lunn',
'David S. Miller', 'Eric Dumazet',
'Jakub Kicinski', 'Paolo Abeni',
'Richard Cochran', 'Russell King',
'Jacob Keller', 'Michal Swiatkowski',
'Kees Cook', 'Larysa Zaremba',
'Joe Damato', 'Breno Leitao',
'Aleksandr Loktionov',
'Uwe Kleine-König (The Capable Hub)',
'Fabio Baltieri', 'Thomas Gleixner',
'Greg Kroah-Hartman', netdev, 'Mengyuan Lou',
'Andrew Lunn', 'David S. Miller',
'Eric Dumazet', 'Jakub Kicinski',
'Paolo Abeni', 'Richard Cochran',
'Russell King', 'Jacob Keller',
'Michal Swiatkowski', 'Kees Cook',
'Larysa Zaremba', 'Joe Damato',
'Breno Leitao', 'Aleksandr Loktionov',
'Uwe Kleine-König (The Capable Hub)',
'Fabio Baltieri', 'Thomas Gleixner',
'Greg Kroah-Hartman'
In-Reply-To: <20260612154929.GD671640@horms.kernel.org>
On Fri, Jun 12, 2026 11:49 PM, Simon Horman wrote:
> On Wed, Jun 10, 2026 at 02:09:16PM +0800, Jiawen Wu wrote:
> > Function wx_soft_quiesce() provide a lightweight shutdown path during
> > PCIe error recovery. It avoids MMIO-dependent operations in PCIe error
> > status.
> >
> > Waiting for the service task to complete may unnecessarily delay PCIe
> > error recovery, especially if the work item is already blocked by the
> > hardware failure that triggered AER. So the service task is not
> > explicitly cancelled in quiesce path. As a measure to block the service
> > task, the checking of WX_STATE_DOWN and WX_STATE_RESETTING is added at
> > the entry of every work item.
> >
> > Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> > Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>
> ...
>
> > diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ptp.c b/drivers/net/ethernet/wangxun/libwx/wx_ptp.c
> > index 44f3e6505246..dcc8b3ae1445 100644
> > --- a/drivers/net/ethernet/wangxun/libwx/wx_ptp.c
> > +++ b/drivers/net/ethernet/wangxun/libwx/wx_ptp.c
> > @@ -842,6 +842,27 @@ void wx_ptp_stop(struct wx *wx)
> > }
> > EXPORT_SYMBOL(wx_ptp_stop);
> >
> > +void wx_ptp_quiesce(struct wx *wx)
> > +{
> > + if (!test_and_clear_bit(WX_STATE_PTP_RUNNING, wx->state))
> > + return;
> > +
> > + clear_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags);
> > +
> > + if (wx->ptp_tx_skb) {
> > + dev_kfree_skb_any(wx->ptp_tx_skb);
> > + wx->ptp_tx_skb = NULL;
> > + }
>
> AI-generated review of this patch on sashiko.dev flags a potential UAF here:
>
> "Could freeing wx->ptp_tx_skb here cause a use-after-free or
> double-free?
>
> "Because ptp_clock_unregister() is called after this block, the PTP
> kworker might still be running.
>
> "If wx_ptp_tx_hwtstamp() reads wx->ptp_tx_skb just before this
> free, it will pass the freed skb to skb_tstamp_tx() and call
> dev_kfree_skb_any() on it again.
>
> I'd appreciate it if you could look into that.
I will move ptp_clock_unregister() to be executed before we free wx->ptp_tx_skb.
>
> I believe that the other issues raised in that AI-generated review have
> already been discussed in the context of earlier versions of this
> patch-set.
>
> > + clear_bit_unlock(WX_STATE_PTP_TX_IN_PROGRESS, wx->state);
> > +
> > + if (wx->ptp_clock) {
> > + ptp_clock_unregister(wx->ptp_clock);
> > + wx->ptp_clock = NULL;
> > + dev_info(&wx->pdev->dev, "removed PHC on %s\n", wx->netdev->name);
> > + }
> > +}
>
> ...
>
^ permalink raw reply
* [PATCH net] octeontx2-pf: Fix leak of SQ timestamp buffer on teardown
From: Ratheesh Kannoth @ 2026-06-15 3:07 UTC (permalink / raw)
To: amakarov, davem, jesse.brandeburg, kuba, linux-kernel, netdev,
richardcochran
Cc: andrew+netdev, edumazet, pabeni, sgoutham, Ratheesh Kannoth
The send-queue timestamp ring is allocated with qmem_alloc() when
timestamping is used, but otx2_free_sq_res() never freed sq->timestamps,
leaking that memory across ifdown and device removal. Add the missing
qmem_free() alongside the other SQ companion buffers.
Fixes: c9c12d339d93 ("octeontx2-pf: Add support for PTP clock")
Cc: Aleksey Makarov <amakarov@marvell.com>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index f9fbf0c17648..0c2da974ac6d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1578,6 +1578,7 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
qmem_free(pf->dev, sq->sqe_ring);
qmem_free(pf->dev, sq->cpt_resp);
qmem_free(pf->dev, sq->tso_hdrs);
+ qmem_free(pf->dev, sq->timestamps);
kfree(sq->sg);
kfree(sq->sqb_ptrs);
}
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next v2 1/2] virtio_net: xsk: fix race in rx wake up
From: Xuan Zhuo @ 2026-06-15 2:48 UTC (permalink / raw)
To: menglong8.dong
Cc: mst, jasowang, andrew+netdev, davem, edumazet, kuba, pabeni,
minhquangbui99, kerneljasonxing, netdev, virtualization,
linux-kernel, eperezma
In-Reply-To: <20260611025644.2431148-2-dongml2@chinatelecom.cn>
On Thu, 11 Jun 2026 10:56:43 +0800, menglong8.dong@gmail.com wrote:
> From: Menglong Dong <dongml2@chinatelecom.cn>
>
> During packet receiving in virtio-net, the rq can be empty, which means
> "rq->vq->num_free == virtqueue_get_vring_size(rq->vq)", in
> virtnet_add_recvbuf_xsk(), if we are using xsk. Meanwhile, the fill ring
> can be empty too, which means we can't allocate anything from
> xsk_buff_alloc_batch(). Then, we will set the XDP_RING_NEED_WAKEUP flag.
>
> However, if the user clean all the data in rx ring and fill the
> "fill ring" and check the XDP_RING_NEED_WAKEUP flag after
> xsk_buff_alloc_batch() and before xsk_set_rx_need_wakeup(), then the rx
> napi will never be scheduled: the rx ring is empty, which means we will
> never receive a packet to trigger the further recv fill. The rx ring is
> empty now, so the user will not check the flag too.
>
> Fix this by set the XDP_RING_NEED_WAKEUP flag before
> xsk_buff_alloc_batch() if both rq->vq and fill ring are empty.
>
> Meanwhile, set the XDP_RING_NEED_WAKEUP flag if we have any free entry in
> rq->vq.
>
> Fixes: e3f8800aa243 ("virtio-net: xsk: Support wakeup on RX side")
> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
> ---
> drivers/net/virtio_net.c | 25 ++++++++++++++++++++++---
> 1 file changed, 22 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index f4adcfee7a80..4b5b3fa62008 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -1323,16 +1323,27 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue
> struct xsk_buff_pool *pool, gfp_t gfp)
> {
> struct xdp_buff **xsk_buffs;
> + bool need_wakeup;
> dma_addr_t addr;
> int err = 0;
> u32 len, i;
> int num;
>
> + need_wakeup = xsk_uses_need_wakeup(pool);
> xsk_buffs = rq->xsk_buffs;
>
> + /* If both rq->vq and fill ring are empty, and then the user submit
> + * all the chunks to the fill ring and check the wake up flag
> + * after xsk_buff_alloc_batch() and before xsk_set_rx_need_wakeup(),
> + * we will lose the chance to wake up the rx napi, so we have to
> + * set the need_wakeup flag here.
> + */
> + if (need_wakeup && virtqueue_get_vring_size(rq->vq) == rq->vq->num_free)
> + xsk_set_rx_need_wakeup(pool);
Is Condition A here too strict? We should trigger the wakeup under a wider range
of scenarios.
> +
> num = xsk_buff_alloc_batch(pool, xsk_buffs, rq->vq->num_free);
> if (!num) {
> - if (xsk_uses_need_wakeup(pool)) {
> + if (need_wakeup) {
> xsk_set_rx_need_wakeup(pool);
> /* Return 0 instead of -ENOMEM so that NAPI is
> * descheduled.
> @@ -1341,8 +1352,6 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue
> }
>
> return -ENOMEM;
> - } else {
> - xsk_clear_rx_need_wakeup(pool);
> }
>
> len = xsk_pool_get_rx_frame_size(pool) + vi->hdr_len;
> @@ -1363,6 +1372,16 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue
> goto err;
> }
>
> + if (need_wakeup) {
> + if (rq->vq->num_free)
> + /* We have free buffers, so we'd better wake up the
> + * rx napi as soon as possible.
> + */
> + xsk_set_rx_need_wakeup(pool);
Is the purpose of waking up RX NAPI to invoke try_fill_recv? However,
virtnet_poll does not call try_fill_recv directly. it is done
conditionally.
Thanks.
> + else
> + xsk_clear_rx_need_wakeup(pool);
> + }
> +
> return num;
>
> err:
> --
> 2.54.0
>
^ permalink raw reply
* Re: [net-next v1 2/6] net: stmmac: Checking whether priv->phylink if NULL in NCSI case
From: Minda Chen @ 2026-06-15 1:25 UTC (permalink / raw)
To: Andrew Lunn
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Jose Abreu, Maxime Coquelin, Russell King,
Giuseppe Cavallaro, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
devicetree@vger.kernel.org
In-Reply-To: <f3a32c42-27b2-496f-b236-02c33bee1773@lunn.ch>
>
> > +static inline bool stmmac_phylink_expects_phy(struct phylink *link) {
> > + if (link)
> > + return phylink_expects_phy(link);
> > +
> > + return false;
> > +}
> > +
> > +static inline int stmmac_phylink_pcs_pre_init(struct phylink *link,
> > +struct phylink_pcs *pcs) {
> > + if (link)
> > + return phylink_pcs_pre_init(link, pcs);
> > +
> > + return 0;
> > +}
> > +
> > +static inline void stmmac_phylink_start(struct phylink *link) {
> > + if (link)
> > + phylink_start(link);
> > +}
> > +
> > +static inline void stmmac_phylink_stop(struct phylink *link) {
> > + if (link)
> > + phylink_stop(link);
> > +}
>
> Please take a step back and think about the Linux big picture architecture.
>
> What is stmmac specific here? If you were to add NCSI support to another driver
> which uses phylink, would it need to replicate all this?
>
> When you consider how the MAC is configured, does it need to know it is
> connected to an NCSI? Can the MAC tell the difference between NSCI, fixed-link,
> a PHY or an SFP? Or does the MAC just need to know RGMII, the link is up, send
> frames?
>
> Please look at adding generic support for NSCI in phylink, and see if the existing
> phylink mac ops covers everything needed for configuring the MAC.
>
> Andrew
Thanks. I will try to use fix-PHY link.
^ permalink raw reply
* RE: [PATCH net-next v6 5/5] net: wangxun: add pcie error handler
From: Jiawen Wu @ 2026-06-15 2:13 UTC (permalink / raw)
To: 'Simon Horman'
Cc: netdev, 'Mengyuan Lou', 'Andrew Lunn',
'David S. Miller', 'Eric Dumazet',
'Jakub Kicinski', 'Paolo Abeni',
'Richard Cochran', 'Russell King',
'Jacob Keller', 'Michal Swiatkowski',
'Kees Cook', 'Larysa Zaremba',
'Joe Damato', 'Breno Leitao',
'Aleksandr Loktionov',
'Uwe Kleine-König (The Capable Hub)',
'Fabio Baltieri', 'Thomas Gleixner',
'Greg Kroah-Hartman', netdev, 'Mengyuan Lou',
'Andrew Lunn', 'David S. Miller',
'Eric Dumazet', 'Jakub Kicinski',
'Paolo Abeni', 'Richard Cochran',
'Russell King', 'Jacob Keller',
'Michal Swiatkowski', 'Kees Cook',
'Larysa Zaremba', 'Joe Damato',
'Breno Leitao', 'Aleksandr Loktionov',
'Uwe Kleine-König (The Capable Hub)',
'Fabio Baltieri', 'Thomas Gleixner',
'Greg Kroah-Hartman'
In-Reply-To: <20260612154117.GC671640@horms.kernel.org>
On Fri, Jun 12, 2026 11:41 PM, Simon Horman wrote:
> On Wed, Jun 10, 2026 at 02:09:17PM +0800, Jiawen Wu wrote:
> > Support AER driver to handle the PCIe errors. Sometimes netdev watchdog
> > Tx timeout happens before the AER error report when a PCIe error occurs,
> > CPU blocking would be caused by MMIO during the reset process. To
> > prevent it, check PCIe error status in .ndo_tx_timeout. The current
> > function of ngbe is not yet fully developed, it will be completed in the
> > future.
> >
> > Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
>
> Hi Jiawen,
>
> There is AI-generated review of this patch-set available on both
> https://sashiko.dev and https://netdev-ai.bots.linux.dev/sashiko/
>
> I've tried to filter out only those that seem strictly relevant
> to the progress of this patch and have included them inline.
>
> I'd appreciate it if you could take a look over this.
>
> > diff --git a/drivers/net/ethernet/wangxun/libwx/wx_err.c b/drivers/net/ethernet/wangxun/libwx/wx_err.c
>
> ...
>
> > +/**
> > + * wx_io_slot_reset - called after the pci bus has been reset.
> > + * @pdev: Pointer to PCI device
> > + *
> > + * Return: pci_ers_result_t.
> > + *
> > + * Restart the card from scratch, as if from a cold-boot.
> > + */
> > +static pci_ers_result_t wx_io_slot_reset(struct pci_dev *pdev)
> > +{
> > + struct wx *wx = pci_get_drvdata(pdev);
> > + pci_ers_result_t result;
> > +
> > + if (pci_enable_device_mem(pdev)) {
> > + wx_err(wx, "Cannot re-enable PCI device after reset.\n");
> > + result = PCI_ERS_RESULT_DISCONNECT;
> > + } else {
> > + /* make all memory operations done before clearing the flag */
> > + smp_mb__before_atomic();
> > + clear_bit(WX_STATE_DISABLED, wx->state);
> > + clear_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
> > + pci_set_master(pdev);
> > + pci_restore_state(pdev);
> > + pci_wake_from_d3(pdev, false);
> > +
> > + rtnl_lock();
> > + if (netif_running(wx->netdev) && wx->down_suspend)
> > + wx->down_suspend(wx);
> > + if (wx->do_reset)
> > + wx->do_reset(wx->netdev, false);
>
> The AI-generated review on sashiko.dev flags the following.
>
> "Does this properly initialize the hardware MAC during PCIe AER
> slot reset recovery for the ngbe driver?
>
> "For txgbe, this correctly maps to txgbe_reset(), which calls
> txgbe_reset_hw(). However, for ngbe, wx->do_reset maps to
> ngbe_do_reset() which calls ngbe_reset().
>
> "Looking at ngbe_reset():
>
> "drivers/net/ethernet/wangxun/ngbe/ngbe_main.c:ngbe_reset() {
> if (test_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags))
> return;
> wx_flush_sw_mac_table(wx);
> wx_mac_set_default_filter(wx, wx->mac.addr);
> if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
> wx_ptp_reset(wx);
>
> "This skips ngbe_reset_hw() and fails to fully reset the hardware.
> Since a PCIe slot reset clears the device's internal state, when
> wx_io_resume() subsequently calls ndo_open(), could the device fail
> to function because its hardware registers and PHY state were never
> reset?
As stated in the commit message, ngbe is not yet fully implemented due to some
existing issues with its reset mechanism. These will be refined in a future patch.
> > + rtnl_unlock();
> > + result = PCI_ERS_RESULT_RECOVERED;
> > + }
> > +
> > + pci_aer_clear_nonfatal_status(pdev);
> > +
> > + return result;
> > +}
>
> ...
>
> > +static void wx_tx_timeout_recovery(struct wx *wx)
> > +{
> > + /*
> > + * When a PCIe hardware error occurs, the driver should initiate a PCIe
> > + * recovery mechanism. However, this recovery flow relies on the AER
> > + * driver for current kernel policy. Therefore, a self-contained
> > + * recovery mechanism is not implemented yet.
> > + */
> > + set_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags);
> > + wx_err(wx, "PCIe error detected during tx timeout\n");
> > + queue_work(wx->reset_wq, &wx->reset_task);
> > +}
>
> The AI-generated review on https://netdev-ai.bots.linux.dev/sashiko/ flags:
>
> "What clears WX_FLAG_NEED_PCIE_RECOVERY if AER never follows up?
> wx_tx_timeout_recovery() sets the flag and queues reset_task.
> reset_task only calls wx_soft_quiesce() and does not clear the
> flag:
>
> if (test_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags))
> wx_soft_quiesce(wx);
>
> "The flag is cleared only on the success branch of
> wx_io_slot_reset(). If the PCIe error never escalates to AER (AER
> disabled in firmware or kernel, error not reportable, slot_reset
> returns PCI_ERS_RESULT_DISCONNECT), the flag remains set
> indefinitely.
>
> "Both ngbe_reset() and txgbe_reset() now early-return on this flag:
>
> static void ngbe_reset(struct wx *wx)
> {
> if (test_bit(WX_FLAG_NEED_PCIE_RECOVERY, wx->flags))
> return;
> ...
> }
>
> "so any subsequent reset path (ethtool reset, ndo_set_features
> triggered reset, watchdog timeout reset, FDIR reinit,
> ngbe_reinit_locked / txgbe_reinit_locked) is silently a no-op. The
> hardware reset capability is effectively disabled until the module
> is reloaded.
>
> "Should wx_tx_timeout_recovery() (or reset_task after the quiesce)
> clear the flag once the soft-quiesce completes, so the driver's
> reset machinery remains functional when AER does not follow up?
If a PCIe error happens and AER is unresponsive, the driver currently lacks
alternative recovery mechanisms. This renders the hardware unusable, making
any further reset operations disallowed.
^ permalink raw reply
* [BUG] ptp: vmclock: KASAN slab-use-after-free in vmclock_miscdev_read
From: Shuangpeng Bai @ 2026-06-15 2:15 UTC (permalink / raw)
To: dwmw2, richardcochran, netdev, linux-kernel
Hi,
I hit the following KASAN report while testing current upstream kernel.
The issue was reproduced by opening /dev/vmclock0, unbinding the vmclock
platform device, and then reading from the old fd.
KASAN: slab-use-after-free in vmclock_miscdev_read
I reproduced this on commit: e8c2f9fdadee7cbc75134dc463c1e0d856d6e5c7 (May 25 2026)
The reproducer and .config files are here.
https://gist.github.com/shuangpengbai/7c2d117852611448a80026f8aa4d4bc4
I'm happy to test debug patches or provide additional information.
Reported-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
[ 148.011605][ T8390] BUG: KASAN: slab-use-after-free in vmclock_miscdev_read (drivers/ptp/ptp_vmclock.c:409)
[ 148.015241][ T8390] Read of size 8 at addr ffff88811fdc7478 by task repro_vmclock_o/8390
[ 148.018209][ T8390] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 148.018216][ T8390] Call Trace:
[ 148.018226][ T8390] <TASK>
[ 148.018232][ T8390] dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
[ 148.018248][ T8390] print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
[ 148.018314][ T8390] kasan_report (mm/kasan/report.c:595)
[ 148.018335][ T8390] vmclock_miscdev_read (drivers/ptp/ptp_vmclock.c:409)
[ 148.018384][ T8390] vfs_read (fs/read_write.c:572)
[ 148.018453][ T8390] __x64_sys_pread64 (fs/read_write.c:765 fs/read_write.c:773 fs/read_write.c:770 fs/read_write.c:770)
[ 148.018483][ T8390] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[ 148.018498][ T8390] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[ 148.018604][ T8390] </TASK>
[ 148.042173][ T8390] Freed by task 8390 on cpu 1 at 147.908511s:
[ 148.042791][ T8390] kasan_save_track (mm/kasan/common.c:57 mm/kasan/common.c:78)
[ 148.043265][ T8390] kasan_save_free_info (mm/kasan/generic.c:584)
[ 148.043775][ T8390] __kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285)
[ 148.044256][ T8390] kfree (include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566)
[ 148.044668][ T8390] devres_release_all (drivers/base/devres.c:50 drivers/base/devres.c:547 drivers/base/devres.c:576)
[ 148.045171][ T8390] device_release_driver_internal (drivers/base/dd.c:598 drivers/base/dd.c:1357 drivers/base/dd.c:1375)
[ 148.045791][ T8390] unbind_store (drivers/base/bus.c:244)
[ 148.046252][ T8390] kernfs_fop_write_iter (fs/kernfs/file.c:352)
[ 148.046798][ T8390] vfs_write (fs/read_write.c:595 fs/read_write.c:688)
[ 148.047229][ T8390] ksys_write (fs/read_write.c:740)
[ 148.047678][ T8390] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[ 148.048144][ T8390] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[ 148.048996][ T8390] The buggy address belongs to the object at ffff88811fdc7400
[ 148.048996][ T8390] which belongs to the cache kmalloc-512 of size 512
[ 148.050394][ T8390] The buggy address is located 120 bytes inside of
[ 148.050394][ T8390] freed 512-byte region [ffff88811fdc7400, ffff88811fdc7600)
Best,
Shuangpeng
^ permalink raw reply
* Re: [PATCH net-next v1] e1000: Initialize phy_data to avoid unexpected values
From: Rongguang Wei @ 2026-06-15 1:40 UTC (permalink / raw)
To: Jagielski, Jedrzej, Kitszel, Przemyslaw, Nguyen, Anthony L
Cc: netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
Rongguang Wei
In-Reply-To: <PH0PR11MB590263784927AAB47EE558BAF0182@PH0PR11MB5902.namprd11.prod.outlook.com>
在 2026/6/12 16:58, Jagielski, Jedrzej 写道:
> From: Rongguang Wei <clementwei90@163.com>
> Sent: Friday, June 12, 2026 10:04 AM
>
>> From: Rongguang Wei <weirongguang@kylinos.cn>
>>
>> The phy_data variable is not initialized. If e1000_read_phy_reg
>> returns an error, phy_data will not point to a valid value from
>> the PHY register, which may cause the regs_buff array to be populated
>> with unexpected values.
>
> Hi,
>
> Sounds like a fix, but i believe we would like to have any real
> scenario when the issue occurs and how it can be reproduced.
> If such is provided please target the patch against net tree and
> add fixes tag.
>
Hi,
I was not face a real scenario. I just found out there is no check for
e1000_read_phy_reg return value when I reading the driver code.
Maybe is better to initialized the value or check the return value of e1000_read_phy_reg.
>>
>> Signed-off-by: Rongguang Wei <weirongguang@kylinos.cn>
>> Change-Id: I46071b3b21a566f8da650168d38d6968251b077d
>
>
> i doubt this is a correct kernel commit tag
>
>> ---
>> drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
>> index 4dcbeabb3ad2..f068108c5004 100644
>> --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
>> +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
>> @@ -327,7 +327,7 @@ static void e1000_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
>> struct e1000_adapter *adapter = netdev_priv(netdev);
>> struct e1000_hw *hw = &adapter->hw;
>> u32 *regs_buff = p;
>> - u16 phy_data;
>> + u16 phy_data = 0;
>>
>> memset(p, 0, E1000_REGS_LEN * sizeof(u32));
>>
>> --
>> 2.25.1
>
^ permalink raw reply
* Re: [PATCH net-next v1] e1000: Initialize phy_data to avoid unexpected values
From: Rongguang Wei @ 2026-06-15 1:28 UTC (permalink / raw)
To: Andrew Lunn
Cc: przemyslaw.kitszel, anthony.l.nguyen, netdev, intel-wired-lan,
Rongguang Wei
In-Reply-To: <1578c474-ffbf-46f7-b906-49da4ea48142@lunn.ch>
在 2026/6/13 03:39, Andrew Lunn 写道:
> On Fri, Jun 12, 2026 at 04:03:31PM +0800, Rongguang Wei wrote:
>> From: Rongguang Wei <weirongguang@kylinos.cn>
>>
>> The phy_data variable is not initialized. If e1000_read_phy_reg
>> returns an error, phy_data will not point to a valid value from
>> the PHY register, which may cause the regs_buff array to be populated
>> with unexpected values.
>>
>> Signed-off-by: Rongguang Wei <weirongguang@kylinos.cn>
>> Change-Id: I46071b3b21a566f8da650168d38d6968251b077d
>
> What does this Change-Id mean?
>
Sorry, it just a auto generate id when I push this patch on my own repos.
I forget to delete.
>> ---
>> drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
>> index 4dcbeabb3ad2..f068108c5004 100644
>> --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
>> +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
>> @@ -327,7 +327,7 @@ static void e1000_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
>> struct e1000_adapter *adapter = netdev_priv(netdev);
>> struct e1000_hw *hw = &adapter->hw;
>> u32 *regs_buff = p;
>> - u16 phy_data;
>> + u16 phy_data = 0;
>
> if (hw->phy_type == e1000_phy_igp) {
> e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
> IGP01E1000_PHY_AGC_A);
> e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A &
> IGP01E1000_PHY_PAGE_SELECT, &phy_data);
> regs_buff[13] = (u32)phy_data; /* cable length */
>
> Isn't a cable length of 0 also unexpected?
>
> How does this patch actually make the situation better?
>
Uninitialized variables may be initialized to 0 by the system, explicit initialization
is performed to avoid accidents.
The 0 is from e1000_read_phy_reg_ex in e1000_main.c and e1000_power_down_phy when use
e1000_read_phy_reg function the last paramenters is initialized 0. So I used this value.
There are many other function which use e1000_read_phy_reg also not initialize the last paramenters
eg. e1000_phy_reset_clk_and_crs. I can do it in V2.
>
> Andrew
>
> ---
> pw-bot: cr
^ permalink raw reply
* [BUG] netdevsim: KASAN slab-use-after-free in ref_tracker_free
From: Shuangpeng Bai @ 2026-06-15 1:16 UTC (permalink / raw)
To: netdev
Cc: Jakub Kicinski, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, linux-kernel
Hi netdev maintainers,
I hit the following KASAN report while testing an upstream kernel.
The issue was reproduced with netdevsim. I have not confirmed whether this is
specific to netdevsim or whether other net devices can trigger a similar issue.
The KASAN report shows a slab-use-after-free in ref_tracker_free(), reached from
sysfs_rtnl_lock() while reading phys_port_name.
I reproduced this on commit: e8c2f9fdadee7cbc75134dc463c1e0d856d6e5c7 (May 25 2026)
To help trigger the bug more reliably, we applied a minimal diagnostic patch
that only adds delays and print statements.
The reproducer and .config files are here.
https://gist.github.com/shuangpengbai/b49765d646ec4610917015371aa1c3ca
I'm happy to test debug patches or provide additional information.
Reported-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
[ 3145.449971][T17497] BUG: KASAN: slab-use-after-free in ref_tracker_free (lib/ref_tracker.c:295)
[ 3145.452089][T17497] Read of size 1 at addr ffff888107678598 by task cat/17497
[ 3145.454439][T17497]
[ 3145.454977][T17497] Tainted: [W]=WARN
[ 3145.454980][T17497] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 3145.454985][T17497] Call Trace:
[ 3145.454991][T17497] <TASK>
[ 3145.454994][T17497] dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
[ 3145.455002][T17497] print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
[ 3145.455028][T17497] kasan_report (mm/kasan/report.c:595)
[ 3145.455046][T17497] ref_tracker_free (lib/ref_tracker.c:295)
[ 3145.455083][T17497] sysfs_rtnl_lock (include/linux/netdevice.h:4491 include/linux/netdevice.h:4508 include/linux/netdevice.h:4534 net/core/net-sysfs.c:122)
[ 3145.455091][T17497] phys_port_name_show (net/core/net-sysfs.c:665)
[ 3145.455118][T17497] dev_attr_show (drivers/base/core.c:2421)
[ 3145.455128][T17497] sysfs_kf_seq_show (fs/sysfs/file.c:65)
[ 3145.455135][T17497] seq_read_iter (fs/seq_file.c:231)
[ 3145.455144][T17497] vfs_read (fs/read_write.c:493 fs/read_write.c:574)
[ 3145.455169][T17497] ksys_read (fs/read_write.c:717)
[ 3145.455181][T17497] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[ 3145.455188][T17497] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[ 3145.455193][T17497] RIP: 0033:0x7fcf098c43ce
[ 3145.455200][T17497] Code: c0 e9 b6 fe ff ff 50 48 8d 3d 6e 08 0b 00 e8 69 01 02 00 66 0f 1f 84 00 00 00 00 00 64 8b 04 25 18 00 00 00 85 c0 75 14 0f 05 <48> 3d 00 f0 ff ff 77 5a c3 66 0f 1f 84 00 00 00 00 00 48 83 ec 28
[ 3145.455204][T17497] RSP: 002b:00007ffd05e76b98 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
[ 3145.455211][T17497] RAX: ffffffffffffffda RBX: 0000000000020000 RCX: 00007fcf098c43ce
[ 3145.455214][T17497] RDX: 0000000000020000 RSI: 00007fcf095e4000 RDI: 0000000000000003
[ 3145.455217][T17497] RBP: 00007fcf095e4000 R08: 00007fcf095e3010 R09: 0000000000000000
[ 3145.455219][T17497] R10: fffffffffffffbc5 R11: 0000000000000246 R12: 0000000000000000
[ 3145.455222][T17497] R13: 0000000000000003 R14: 0000000000020000 R15: 0000000000020000
[ 3145.455227][T17497] </TASK>
[ 3145.455229][T17497]
[ 3145.479014][T17497] Freed by task 17497 on cpu 0 at 3145.447575s:
[ 3145.479559][T17497] kasan_save_track (mm/kasan/common.c:57 mm/kasan/common.c:78)
[ 3145.479963][T17497] kasan_save_free_info (mm/kasan/generic.c:584)
[ 3145.480411][T17497] __kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285)
[ 3145.480813][T17497] kfree (include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566)
[ 3145.481148][T17497] device_release (drivers/base/core.c:2542)
[ 3145.481567][T17497] kobject_put (lib/kobject.c:689 lib/kobject.c:720 include/linux/kref.h:65 lib/kobject.c:737)
[ 3145.481951][T17497] sysfs_rtnl_lock (net/core/net-sysfs.c:121)
[ 3145.482351][T17497] phys_port_name_show (net/core/net-sysfs.c:665)
[ 3145.482782][T17497] dev_attr_show (drivers/base/core.c:2421)
[ 3145.483154][T17497] sysfs_kf_seq_show (fs/sysfs/file.c:65)
[ 3145.483586][T17497] seq_read_iter (fs/seq_file.c:231)
[ 3145.483975][T17497] vfs_read (fs/read_write.c:493 fs/read_write.c:574)
[ 3145.484334][T17497] ksys_read (fs/read_write.c:717)
[ 3145.484701][T17497] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[ 3145.485092][T17497] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[ 3145.485592][T17497]
[ 3145.485794][T17497] The buggy address belongs to the object at ffff888107678000
[ 3145.485794][T17497] which belongs to the cache kmalloc-cg-8k of size 8192
[ 3145.486991][T17497] The buggy address is located 1432 bytes inside of
[ 3145.486991][T17497] freed 8192-byte region [ffff888107678000, ffff88810767a000)
[ 3145.488159][T17497]
[ 3145.488367][T17497] The buggy address belongs to the physical page:
Best,
Shuangpeng
^ permalink raw reply
* Re: [PATCH net-next v7 0/4] net: rnpgbe: Add TX/RX and link status support
From: Yibo Dong @ 2026-06-15 0:58 UTC (permalink / raw)
To: Simon Horman
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, danishanwar,
vadim.fedorenko, u.kleine-koenig, linux-kernel, netdev, yaojun
In-Reply-To: <20260612184436.GL671640@horms.kernel.org>
On Fri, Jun 12, 2026 at 07:44:36PM +0100, Simon Horman wrote:
> On Thu, Jun 11, 2026 at 06:00:32PM +0800, Dong Yibo wrote:
> > Hi maintainers,
> >
> > This patch series adds the packet transmission, reception, and link status
> > management features to the RNPGBE driver, building upon the previously
> > introduced mailbox communication and basic driver infrastructure.
> >
> > The series introduces:
> > - Msix/msi interrupt handling with NAPI support
> > - TX path with scatter-gather DMA and completion handling
> > - RX path with page pool buffer management
> > - Link status monitoring and carrier management
> >
> > These changes enable the RNPGBE driver to support basic tx/rx
> > network operations.
> >
> > Changelog:
> > v6 -> v7:
> > [patch 2/4]:
> > 1. Fix 'frag_idx' error in rnpgbe_tx_map. (Sashiko-gemini)
> > [patch 3/4]:
> > 1. Fix skb leak in invalid size path in rnpgbe_clean_rx_irq.
> > (Sashiko-gemini)
> > 2. Fix invalid size range check for rxdesc. (Sashiko-gemini)
> > [patch 4/4]:
> > 1. Fix 'data race on the reply payload'. (Sashiko-gemini)
> > 2. Fix 'asymmetric behaviour' when report up/down. (andrew)
> >
> > links:
> > ---
> > v1: https://lore.kernel.org/netdev/20260325091204.94015-1-dong100@mucse.com/
> > v2: https://lore.kernel.org/netdev/20260403025713.527841-1-dong100@mucse.com/
> > v3: https://lore.kernel.org/netdev/20260507081539.171844-1-dong100@mucse.com/
> > v4: https://lore.kernel.org/netdev/20260526033539.164061-1-dong100@mucse.com/
> > v5: https://lore.kernel.org/netdev/20260528023150.239532-1-dong100@mucse.com/
> > v6: https://lore.kernel.org/netdev/20260604112750.769215-1-dong100@mucse.com/
> >
> > Additional Notes:
>
> Thanks for the update and the notes.
>
> There is another round of AI-generated review of this patch-set available
> on both https://sashiko.dev and https://netdev-ai.bots.linux.dev/sashiko/
>
> I would appreciate it if you could look over that too. With a view to
> addressing any issues that directly affect this patch.
>
Ok, I Will take a look at the AI review results on both sites and fix all
relevant issues pointed out for this patch.
> ...
>
Thanks for your feedback.
^ permalink raw reply
* [PATCH iproute2-next v3] rdma: display resource limits in curr/max format
From: Tao Cui @ 2026-06-15 0:53 UTC (permalink / raw)
To: dsahern, leonro; +Cc: linux-rdma, netdev, Tao Cui
From: Tao Cui <cuitao@kylinos.cn>
Parse the new RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX netlink attribute
to show resource limits alongside current counts in curr/max format:
Before: 0: mlx5_0: qp 123 cq 45 mr 200 pd 10
After: 0: mlx5_0: qp 123/131072 cq 45/65536 mr 200/1000000 pd 10/32768
JSON output provides both current and max fields per resource type
(e.g. "qp": 123, "qp-max": 131072). Backward compatible: no output
change when kernel lacks the new attribute.
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
rdma/include/uapi/rdma/rdma_netlink.h | 5 +++++
rdma/res.c | 21 ++++++++++++++++++++-
rdma/utils.c | 1 +
3 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/rdma/include/uapi/rdma/rdma_netlink.h b/rdma/include/uapi/rdma/rdma_netlink.h
index 4356ec4a..e5b8b065 100644
--- a/rdma/include/uapi/rdma/rdma_netlink.h
+++ b/rdma/include/uapi/rdma/rdma_netlink.h
@@ -604,6 +604,11 @@ enum rdma_nldev_attr {
RDMA_NLDEV_ATTR_FRMR_POOL_PINNED_HANDLES, /* u32 */
RDMA_NLDEV_ATTR_FRMR_POOL_KEY_KERNEL_VENDOR_KEY, /* u64 */
+ /*
+ * Resource summary entry maximum value.
+ */
+ RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX, /* u64 */
+
/*
* Always the end
*/
diff --git a/rdma/res.c b/rdma/res.c
index 062f0007..046935e2 100644
--- a/rdma/res.c
+++ b/rdma/res.c
@@ -55,7 +55,26 @@ static int res_print_summary(struct nlattr **tb)
name = mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]);
curr = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
- res_print_u64(name, curr, nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
+ if (nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX]) {
+ uint64_t max;
+ char max_name[64];
+
+ max = mnl_attr_get_u64(
+ nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX]);
+ snprintf(max_name, sizeof(max_name), "%s-max", name);
+ print_u64(PRINT_JSON, name, NULL, curr);
+ print_u64(PRINT_JSON, max_name, NULL, max);
+ if (!is_json_context()) {
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "%s %" PRIu64 "/%" PRIu64 " ",
+ name, curr, max);
+ pr_out("%s", buf);
+ }
+ } else {
+ res_print_u64(name, curr,
+ nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]);
+ }
}
return 0;
}
diff --git a/rdma/utils.c b/rdma/utils.c
index 87003b2c..90ea1c55 100644
--- a/rdma/utils.c
+++ b/rdma/utils.c
@@ -480,6 +480,7 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
[RDMA_NLDEV_ATTR_EVENT_TYPE] = MNL_TYPE_U8,
[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE] = MNL_TYPE_U8,
[RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED] = MNL_TYPE_U8,
+ [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX] = MNL_TYPE_U64,
};
static int rd_attr_check(const struct nlattr *attr, int *typep)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH bpf-next v4 0/2] bpf: Fix bpf_get/setsockopt to tos for ipv4-mapped ipv6 socket
From: patchwork-bot+netdevbpf @ 2026-06-15 0:50 UTC (permalink / raw)
To: Leon Hwang
Cc: bpf, ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil, john.fastabend, sdf, davem, edumazet,
kuba, pabeni, horms, shuah, ihor.solodrai, netdev, linux-kernel,
linux-kselftest, kernel-patches-bot
In-Reply-To: <20260613162443.60515-1-leon.hwang@linux.dev>
Hello:
This series was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Sun, 14 Jun 2026 00:24:41 +0800 you wrote:
> When TCP over IPv4 via INET6 API, sk->sk_family is AF_INET6, but it is a
> v4 pkt. inet_csk(sk)->icsk_af_ops is ipv6_mapped and use ip_queue_xmit.
> The tos sockopt does not work for bpf [get,set]sockopt() helpers.
>
> Changelog:
> v3 -> v4:
> * Add 'sk->sk_type != SOCK_RAW && !ipv6_only_sock(sk)' check.
> * Re-implement test with LLM assistance.
> * v3: https://lore.kernel.org/all/20240914103226.71109-1-zhoufeng.zf@bytedance.com/
>
> [...]
Here is the summary with links:
- [bpf-next,v4,1/2] bpf: Fix bpf_get/setsockopt to tos for ipv4-mapped ipv6 socket
https://git.kernel.org/bpf/bpf-next/c/ca0f587c029a
- [bpf-next,v4,2/2] selftests/bpf: Add test to verify the fix for bpf_setsockopt() helper
https://git.kernel.org/bpf/bpf-next/c/5cf2c21ab090
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH net-next] i40e: add devlink parameter for Flow Director ATR sample rate
From: kernel test robot @ 2026-06-15 0:42 UTC (permalink / raw)
To: mheib, intel-wired-lan
Cc: llvm, oe-kbuild-all, netdev, jiri, davem, edumazet, kuba, pabeni,
horms, corbet, anthony.l.nguyen, przemyslaw.kitszel,
andrew+netdev, Mohammad Heib
In-Reply-To: <20260614161131.192068-1-mheib@redhat.com>
Hi,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/mheib-redhat-com/i40e-add-devlink-parameter-for-Flow-Director-ATR-sample-rate/20260615-001257
base: net-next/main
patch link: https://lore.kernel.org/r/20260614161131.192068-1-mheib%40redhat.com
patch subject: [Intel-wired-lan] [PATCH net-next] i40e: add devlink parameter for Flow Director ATR sample rate
config: sparc64-allmodconfig (https://download.01.org/0day-ci/archive/20260615/202606150807.u6hUM8VJ-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260615/202606150807.u6hUM8VJ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606150807.u6hUM8VJ-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/net/ethernet/intel/i40e/i40e_devlink.c:106:9: error: incompatible function pointer types initializing 'int (*)(struct devlink *, u32, union devlink_param_value *, struct netlink_ext_ack *)' (aka 'int (*)(struct devlink *, unsigned int, union devlink_param_value *, struct netlink_ext_ack *)') with an expression of type 'int (struct devlink *, u32, union devlink_param_value, struct netlink_ext_ack *)' (aka 'int (struct devlink *, unsigned int, union devlink_param_value, struct netlink_ext_ack *)') [-Wincompatible-function-pointer-types]
106 | i40e_atr_sample_rate_validate),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/net/devlink.h:650:14: note: expanded from macro 'DEVLINK_PARAM_DRIVER'
650 | .validate = _validate, \
| ^~~~~~~~~
1 error generated.
vim +106 drivers/net/ethernet/intel/i40e/i40e_devlink.c
93
94 static const struct devlink_param i40e_dl_params[] = {
95 DEVLINK_PARAM_GENERIC(MAX_MAC_PER_VF,
96 BIT(DEVLINK_PARAM_CMODE_RUNTIME),
97 i40e_max_mac_per_vf_get,
98 i40e_max_mac_per_vf_set,
99 NULL),
100 DEVLINK_PARAM_DRIVER(I40E_DEVLINK_PARAM_ID_ATR_SAMPLE_RATE,
101 "atr_sample_rate",
102 DEVLINK_PARAM_TYPE_U32,
103 BIT(DEVLINK_PARAM_CMODE_RUNTIME),
104 i40e_atr_sample_rate_get,
105 i40e_atr_sample_rate_set,
> 106 i40e_atr_sample_rate_validate),
107 };
108
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [netfilter-nf-next:for-netdev-nf-next-26-06-14 3/11] net/netfilter/nf_conncount.c:502:18: sparse: sparse: incompatible types in comparison expression (different address spaces):
From: Florian Westphal @ 2026-06-15 0:38 UTC (permalink / raw)
To: kernel test robot
Cc: oe-kbuild-all, Pablo Neira Ayuso, netdev, netfilter-devel
In-Reply-To: <202606150616.cpmJToWO-lkp@intel.com>
kernel test robot <lkp@intel.com> wrote:
> tree: https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next.git for-netdev-nf-next-26-06-14
> head: 2354e975932dabb06fad239f07a3b68fd1809737
> commit: 64d7d5abe2160bba369b4a8f06bdf5630573bab0 [3/11] netfilter: nf_conncount: callers must hold rcu read lock
> config: x86_64-randconfig-123-20260614 (https://download.01.org/0day-ci/archive/20260615/202606150616.cpmJToWO-lkp@intel.com/config)
> compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
> sparse: v0.6.5-rc1
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260615/202606150616.cpmJToWO-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202606150616.cpmJToWO-lkp@intel.com/
>
> sparse warnings: (new ones prefixed by >>)
> >> net/netfilter/nf_conncount.c:502:18: sparse: sparse: incompatible types in comparison expression (different address spaces):
> net/netfilter/nf_conncount.c:502:18: sparse: struct rb_node [noderef] __rcu *
> net/netfilter/nf_conncount.c:502:18: sparse: struct rb_node *
> net/netfilter/nf_conncount.c:510:34: sparse: sparse: incompatible types in comparison expression (different address spaces):
> net/netfilter/nf_conncount.c:510:34: sparse: struct rb_node [noderef] __rcu *
> net/netfilter/nf_conncount.c:510:34: sparse: struct rb_node *
> net/netfilter/nf_conncount.c:512:34: sparse: sparse: incompatible types in comparison expression (different address spaces):
> net/netfilter/nf_conncount.c:512:34: sparse: struct rb_node [noderef] __rcu *
> net/netfilter/nf_conncount.c:512:34: sparse: struct rb_node *
Thanks but I have no intent to fix this.
Between rcu_dereference_raw() not giving sparse warnings but also not
providing any hints when callers don't hold rcu read lock and plain
rcu_dereference() that does give runtime coverage but results in above
sparse output I will pick the latter and just ignore these warnings.
^ permalink raw reply
* Re: [PATCH net v2] tipc: fix slab-use-after-free Read in tipc_aead_decrypt_done
From: Doruk Tan Ozturk @ 2026-06-15 0:22 UTC (permalink / raw)
To: tung.quang.nguyen
Cc: jmaloy, aleksander.lobakin, davem, edumazet, kuba, pabeni, horms,
netdev, tipc-discussion, linux-kernel
In-Reply-To: <GV1P189MB1988B2B662DC781F7347EBD4C61B2@GV1P189MB1988.EURP189.PROD.OUTLOOK.COM>
On Tue, Jun 10, 2026, Tung Quang Nguyen wrote:
> Can you decode the stack trace (using linux/scripts/decode_stacktrace.sh)
> for more readable text?
>
> Is the issue reproducible on the latest net branch, or just on the old
> v6.12.92 you mentioned?
Hi Tung,
Thanks for the review. Answers to both questions below.
1) Decoded stack trace
----------------------
Decoded with scripts/decode_stacktrace.sh against the vmlinux that produced
the splat (6.12.92, CONFIG_KASAN_INLINE + CONFIG_TIPC + CONFIG_TIPC_CRYPTO).
The use-after-free read and the allocation/free sites resolve as follows:
BUG: KASAN: slab-use-after-free in tipc_crypto_rcv_complete (net/tipc/crypto.c:1917)
Read of size 8 at addr ffff888104c8c808 by task kworker/3:2/70
Workqueue: cryptd cryptd_queue_worker
Call Trace:
<TASK>
dump_stack_lvl (lib/dump_stack.c:123)
print_report (mm/kasan/report.c:378 mm/kasan/report.c:481)
kasan_report (mm/kasan/report.c:596)
tipc_crypto_rcv_complete (net/tipc/crypto.c:1917)
tipc_aead_decrypt_done (net/tipc/crypto.c:996)
cryptd_aead_crypt (include/crypto/internal/aead.h:85 crypto/cryptd.c:772)
cryptd_queue_worker (crypto/cryptd.c:181)
process_one_work (kernel/workqueue.c:3264)
worker_thread (kernel/workqueue.c:3339 kernel/workqueue.c:3426)
kthread (kernel/kthread.c:389)
ret_from_fork (arch/x86/kernel/process.c:152)
ret_from_fork_asm (arch/x86/entry/entry_64.S:257)
</TASK>
Allocated by task 1550:
kasan_save_stack (mm/kasan/common.c:49)
kasan_save_track (mm/kasan/common.c:61 mm/kasan/common.c:70)
__kasan_kmalloc (mm/kasan/common.c:378 mm/kasan/common.c:395)
tipc_crypto_start (net/tipc/crypto.c:1484)
tipc_init_net (net/tipc/core.c:73)
ops_init (net/core/net_namespace.c:140)
setup_net (net/core/net_namespace.c:357)
copy_net_ns (net/core/net_namespace.c:512)
create_new_namespaces (kernel/nsproxy.c:110)
(The captured report has the KASAN read trace and the Allocated-by track; the
free is on the netns teardown path tipc_crypto_stop() <- tipc_exit_net() <-
cleanup_net(), as described in the changelog.)
So the freed object is the per-netns struct tipc_crypto allocated in
tipc_crypto_start() at netns creation (crypto.c:1484), and the cryptd worker
then reads it from the async completion: tipc_aead_decrypt_done()
(crypto.c:996) -> tipc_crypto_rcv_complete() (crypto.c:1917). Immediately after
the UAF read the worker also faults dereferencing the stale node pointer in
tipc_node_put() (net/tipc/node.c:319), confirming the object is gone.
2) Reproducibility on the latest net branch
--------------------------------------------
The bug is still present on the latest net tree. I checked out v7.1-rc7 and
inspected net/tipc/crypto.c first: the encrypt side already carries the
maybe_get_net() guard from commit e279024617134 ("net/tipc: fix
slab-use-after-free Read in tipc_aead_encrypt"), but tipc_aead_decrypt() still
goes straight from tipc_bearer_hold(b) to crypto_aead_decrypt(req) with no
maybe_get_net(aead->crypto->net) and no matching put_net() -- i.e. the exact
gap this patch closes. So the decrypt path is unguarded on 7.1-rc7 and the UAF
is reachable there in the same way.
I also built v7.1-rc7 (HEAD at v7.1-rc7) with KASAN_INLINE + TIPC + TIPC_CRYPTO
and reproduced the UAF live. The workload is the same as on 6.12.92: a UDP
bearer with a cluster key is flooded with crafted encrypted frames from an
unknown peer, taking the cluster-key (pick_tx) RX decrypt path, while the
bearer's netns is repeatedly torn down. Decoded against the rc7 vmlinux:
BUG: KASAN: slab-use-after-free in tipc_aead_decrypt_done (net/tipc/crypto.c:999)
Read of size 8 at addr ffff8881056258a8 by task kworker/u16:2/51
CPU: 2 UID: 0 PID: 51 Comm: kworker/u16:2 Not tainted 7.1.0-rc7-00020-... #15
Workqueue: events_unbound
Call Trace:
<TASK>
dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
kasan_report (mm/kasan/report.c:595)
tipc_aead_decrypt_done (net/tipc/crypto.c:999)
process_one_work (kernel/workqueue.c:3314)
worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478)
kthread (kernel/kthread.c:436)
ret_from_fork (arch/x86/kernel/process.c:158)
ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
</TASK>
Allocated by task 169:
__kasan_kmalloc (mm/kasan/common.c:398 mm/kasan/common.c:415)
tipc_crypto_start (net/tipc/crypto.c:1502)
tipc_init_net (net/tipc/core.c:72)
ops_init (net/core/net_namespace.c:137)
setup_net (net/core/net_namespace.c:446)
copy_net_ns (net/core/net_namespace.c:579)
create_new_namespaces (kernel/nsproxy.c:132)
unshare_nsproxy_namespaces (kernel/nsproxy.c:234)
ksys_unshare (kernel/fork.c:3242)
__x64_sys_unshare (kernel/fork.c:3316)
do_syscall_64 (arch/x86/entry/syscall_64.c:63)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Freed by task 8:
kfree (mm/slub.c:6566)
tipc_exit_net (net/tipc/core.c:119)
ops_undo_list (net/core/net_namespace.c)
cleanup_net (net/core/net_namespace.c:704)
process_one_work (kernel/workqueue.c:3314)
worker_thread (kernel/workqueue.c)
kthread (kernel/kthread.c:436)
The freed object is the per-netns struct tipc_crypto allocated in
tipc_crypto_start() at netns creation (crypto.c:1502 on rc7); the async decrypt
completion then reads aead->crypto->stats from it (crypto.c:999) after
cleanup_net() -> tipc_exit_net() -> tipc_crypto_stop() has freed it -- the exact
read/alloc/free triple this patch closes, now on 7.1-rc7 rather than 6.12.92.
One note on the harness: on x86 the in-tree gcm(aes) the SIMD aead wrapper used
to register via simd_register_aeads_compat() is, as of the aesni rewrite, now
registered directly with crypto_register_aeads() and decrypts synchronously, so
the cryptd async window the original 6.12.92 splat used does not arise from the
stock aesni path on rc7. To exercise the same async completion the changelog
describes, I forced tipc_aead_decrypt()'s completion onto a workqueue in my test
tree; the unguarded aead->crypto dereference in tipc_aead_decrypt_done() is what
KASAN catches, and that code is byte-for-byte the unpatched upstream path. The
source state is in any case unambiguous: tipc_aead_decrypt() on rc7 still lacks
maybe_get_net(aead->crypto->net), so the completion can outlive the free on any
config where crypto_aead_decrypt() goes async (e.g. cryptd offload).
Reproduced under KASAN on both v6.12.92 and v7.1-rc7; the decrypt path lacks the
guard on the latest net tree.
Thanks,
Doruk
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH net-next] i40e: add devlink parameter for Flow Director ATR sample rate
From: kernel test robot @ 2026-06-14 22:16 UTC (permalink / raw)
To: mheib, intel-wired-lan
Cc: oe-kbuild-all, netdev, jiri, davem, edumazet, kuba, pabeni, horms,
corbet, anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev,
Mohammad Heib
In-Reply-To: <20260614161131.192068-1-mheib@redhat.com>
Hi,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/mheib-redhat-com/i40e-add-devlink-parameter-for-Flow-Director-ATR-sample-rate/20260615-001257
base: net-next/main
patch link: https://lore.kernel.org/r/20260614161131.192068-1-mheib%40redhat.com
patch subject: [Intel-wired-lan] [PATCH net-next] i40e: add devlink parameter for Flow Director ATR sample rate
config: openrisc-allmodconfig (https://download.01.org/0day-ci/archive/20260615/202606150639.gh5uBfAP-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260615/202606150639.gh5uBfAP-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606150639.gh5uBfAP-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/net/ethernet/intel/i40e/i40e_devlink.c:4:
>> drivers/net/ethernet/intel/i40e/i40e_devlink.c:106:30: error: initialization of 'int (*)(struct devlink *, u32, union devlink_param_value *, struct netlink_ext_ack *)' {aka 'int (*)(struct devlink *, unsigned int, union devlink_param_value *, struct netlink_ext_ack *)'} from incompatible pointer type 'int (*)(struct devlink *, u32, union devlink_param_value, struct netlink_ext_ack *)' {aka 'int (*)(struct devlink *, unsigned int, union devlink_param_value, struct netlink_ext_ack *)'} [-Wincompatible-pointer-types]
106 | i40e_atr_sample_rate_validate),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/net/devlink.h:650:21: note: in definition of macro 'DEVLINK_PARAM_DRIVER'
650 | .validate = _validate, \
| ^~~~~~~~~
drivers/net/ethernet/intel/i40e/i40e_devlink.c:106:30: note: (near initialization for 'i40e_dl_params[1].validate')
include/net/devlink.h:650:21: note: in definition of macro 'DEVLINK_PARAM_DRIVER'
650 | .validate = _validate, \
| ^~~~~~~~~
drivers/net/ethernet/intel/i40e/i40e_devlink.c:77:12: note: 'i40e_atr_sample_rate_validate' declared here
77 | static int i40e_atr_sample_rate_validate(struct devlink *devlink, u32 id,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +106 drivers/net/ethernet/intel/i40e/i40e_devlink.c
93
94 static const struct devlink_param i40e_dl_params[] = {
95 DEVLINK_PARAM_GENERIC(MAX_MAC_PER_VF,
96 BIT(DEVLINK_PARAM_CMODE_RUNTIME),
97 i40e_max_mac_per_vf_get,
98 i40e_max_mac_per_vf_set,
99 NULL),
100 DEVLINK_PARAM_DRIVER(I40E_DEVLINK_PARAM_ID_ATR_SAMPLE_RATE,
101 "atr_sample_rate",
102 DEVLINK_PARAM_TYPE_U32,
103 BIT(DEVLINK_PARAM_CMODE_RUNTIME),
104 i40e_atr_sample_rate_get,
105 i40e_atr_sample_rate_set,
> 106 i40e_atr_sample_rate_validate),
107 };
108
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH net-next] r8169: migrate Rx path to page_pool
From: Francois Romieu @ 2026-06-14 22:09 UTC (permalink / raw)
To: atharva-potdar
Cc: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
pabeni, netdev
In-Reply-To: <20260614054137.32181-1-atharvapotdar07@gmail.com>
atharva-potdar <atharvapotdar07@gmail.com> :
> Replace the driver-managed skb+copy Rx model with page_pool
> zero-copy in preparation for XDP support.
>
> Key changes:
> - Allocate order-0 pages via page_pool instead of alloc_pages + dma_map
> - Build skbs directly from pages with napi_build_skb (zero-copy)
> - Add rtl8169_rx_refill() to replenish descriptors after processing
> - Track dirty_rx boundary for efficient refill scheduling
> - Cap max_mtu to R8169_RX_BUF_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN
> (order-0 pages can't support arbitrary jumbo frames)
>
> Tested on RTL8168h with iperf3 (~470 Mbps, 0 retransmits) and
> 1000 pings (0 drops).
You may consider fdd7b4c3302c93f6833e338903ea77245eb510b4 and some related
changes around that time.
--
Ueimor
^ permalink raw reply
* e1000e: Report link down after "Detected Hardware Unit Hang" ?
From: Helge Deller @ 2026-06-14 21:48 UTC (permalink / raw)
To: Tony Nguyen, Przemek Kitszel, intel-wired-lan, netdev
I'm regularily facing the known "eno1: Detected Hardware Unit Hang:"
with my on-board intel e1000e NIC hardware.
Since none of he various tips on the internet helped, I had the idea
to setup a master/slave bond networking to fail over to another NIC when
the Intel chip hangs.
Sadly this doesn't work as intended, because the link of the intel NIC
isn't reported "down", so the failover never happens, unless I manually
start "ifconfig eno1 down".
My question: Shouldn't the intel NIC ideally report Link Down if we know
it hangs? That way a fail-over should at least happen, right?
Below is a completely untested patch.
Does it make sense that I try to test and/or develop such a patch, or
are there things I miss?
Helge
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 7ce0cc8ab8f4..c6edcf4ac032 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1157,6 +1157,10 @@ static void e1000_print_hw_hang(struct work_struct *work)
e1000e_dump(adapter);
+ /* The NIC hangs. Force link down in e1000e_has_link() such that a
+ * failover can happen */
+ hw->phy.media_type = e1000_media_type_unknown;
+
/* Suggest workaround for known h/w issue */
if ((hw->mac.type == e1000_pchlan) && (er32(CTRL) & E1000_CTRL_TFCE))
e_err("Try turning off Tx pause (flow control) via ethtool\n");
^ permalink raw reply related
* Re: [PATCH net-next v4 0/5] ionic: Expose more port stats to ethtool
From: Eric Joyner @ 2026-06-14 20:54 UTC (permalink / raw)
To: Simon Horman
Cc: netdev, Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jacob Keller
In-Reply-To: <20260612091825.GB625020@horms.kernel.org>
On 6/12/2026 2:18 AM, Simon Horman wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> On Tue, Jun 09, 2026 at 11:18:25PM -0700, Eric Joyner wrote:
>> The primary aim of this patchset is to support the reporting of new port
>> statistics (and one old one) that firmware sends to the driver; these
>> include general FEC codeword stats and the FEC histogram. A scheme for
>> these extra stats is introduced in order to prevent devices that don't
>> support these new statistics from unconditionally setting them or
>> reporting them in ethtool.
>
> ...
>
> Hi Eric,
>
> There is AI-generated review of this patch-set available on both
> https://sashiko.dev and https://netdev-ai.bots.linux.dev/sashiko/
> I would appreciate it if you could look over that with a view
> to addressing any issues that directly affect this patch.
Thanks for letting me know; I've submitted a v5 where I hope I've addressed all
of the comments.
- Eric
^ permalink raw reply
* [PATCH net-next v5 5/5] ionic: Add .get_fec_stats ethtool handler
From: Eric Joyner @ 2026-06-14 20:53 UTC (permalink / raw)
To: netdev
Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
Simon Horman
In-Reply-To: <20260614205303.48088-1-eric.joyner@amd.com>
Reports FEC statistics totals and an 802.3ck FEC histogram. Per-lane
counts currently aren't supported.
The reporting of these statistics is gated by DEV_CAP_EXTRA_STATS and
checks for IONIC_STAT_INVALID, since only the newest devices support
reporting all of these stats. Older devices can only report some of the
statistics or not at all, and so the output will properly exclude those
unsupported statistics.
Assisted-by: Claude:claude-4.6-sonnet
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
.../ethernet/pensando/ionic/ionic_ethtool.c | 77 +++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index c4ab4b5caa0a..e88e818667c2 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -441,6 +441,82 @@ static int ionic_get_fecparam(struct net_device *netdev,
return 0;
}
+static const struct ethtool_fec_hist_range ionic_fec_ranges[] = {
+ { 0, 0},
+ { 1, 1},
+ { 2, 2},
+ { 3, 3},
+ { 4, 4},
+ { 5, 5},
+ { 6, 6},
+ { 7, 7},
+ { 8, 8},
+ { 9, 9},
+ { 10, 10},
+ { 11, 11},
+ { 12, 12},
+ { 13, 13},
+ { 14, 14},
+ { 15, 15},
+ { 0, 0},
+};
+
+#define IONIC_FEC_STAT(dst, src) \
+ do { \
+ if ((src) != IONIC_STAT_INVALID) \
+ (dst) = le64_to_cpu((src)); \
+ } while (0)
+
+static void
+ionic_fill_fec_hist(const struct ionic_port_extra_stats *port_extra_stats,
+ struct ethtool_fec_hist *hist)
+{
+ __le64 fec_cw_err_bin;
+ int i;
+
+ if (port_extra_stats->fec_codeword_error_bin[0] == IONIC_STAT_INVALID)
+ return;
+
+ hist->ranges = ionic_fec_ranges;
+ /* All bins in ranges must be set */
+ for (i = 0; i < ARRAY_SIZE(ionic_fec_ranges) - 1; i++) {
+ fec_cw_err_bin = port_extra_stats->fec_codeword_error_bin[i];
+
+ if (fec_cw_err_bin != IONIC_STAT_INVALID)
+ hist->values[i].sum = le64_to_cpu(fec_cw_err_bin);
+ else
+ hist->values[i].sum = 0;
+ }
+}
+
+static void ionic_get_fec_stats(struct net_device *netdev,
+ struct ethtool_fec_stats *fec_stats,
+ struct ethtool_fec_hist *hist)
+{
+ struct ionic_port_extra_stats *port_extra_stats;
+ struct ionic_lif *lif = netdev_priv(netdev);
+
+ if (!(lif->ionic->ident.dev.capabilities &
+ cpu_to_le64(IONIC_DEV_CAP_EXTRA_STATS)))
+ return;
+
+ if (!lif->ionic->idev.port_info) {
+ netdev_err_once(netdev, "port_info not initialized\n");
+ return;
+ }
+
+ port_extra_stats = &lif->ionic->idev.port_info->extra_stats;
+
+ IONIC_FEC_STAT(fec_stats->corrected_blocks.total,
+ port_extra_stats->rsfec_correctable_blocks);
+ IONIC_FEC_STAT(fec_stats->uncorrectable_blocks.total,
+ port_extra_stats->rsfec_uncorrectable_blocks);
+ IONIC_FEC_STAT(fec_stats->corrected_bits.total,
+ port_extra_stats->fec_corrected_bits_total);
+
+ ionic_fill_fec_hist(port_extra_stats, hist);
+}
+
static int ionic_set_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fec)
{
@@ -1177,6 +1253,7 @@ static const struct ethtool_ops ionic_ethtool_ops = {
.get_module_eeprom_by_page = ionic_get_module_eeprom_by_page,
.get_pauseparam = ionic_get_pauseparam,
.set_pauseparam = ionic_set_pauseparam,
+ .get_fec_stats = ionic_get_fec_stats,
.get_fecparam = ionic_get_fecparam,
.set_fecparam = ionic_set_fecparam,
.get_ts_info = ionic_get_ts_info,
--
2.17.1
^ permalink raw reply related
* [PATCH net-next v5 4/5] ionic: Get "link_down_count" ext link stat from firmware
From: Eric Joyner @ 2026-06-14 20:53 UTC (permalink / raw)
To: netdev
Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
Simon Horman
In-Reply-To: <20260614205303.48088-1-eric.joyner@amd.com>
The number of times that link has gone down at the port level is tracked
by the firmware and sent to the driver via regular DMA writes to an
instance of struct ionic_port_status in the driver's memory.
This statistic was never reported in favor of a driver-derived stat, but
doing it in the driver was never necessary since firmware had been
reporting it the whole time. Since it would be more accurate and true to
the description of the statistic to get this count at the PHY level,
replace the driver-calculated statistic with one derived from the
firmware one and remove the driver-calculated one entirely.
The stat reported by the ethtool .get_link_ext_stats() handler is
normalized to 0 on driver load and any device resets that require the
driver to rebuild state while also handling overflows.
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
.../net/ethernet/pensando/ionic/ionic_dev.c | 10 +++++++++
.../net/ethernet/pensando/ionic/ionic_dev.h | 5 +++++
.../ethernet/pensando/ionic/ionic_ethtool.c | 22 ++++++++++++++++---
.../net/ethernet/pensando/ionic/ionic_lif.c | 4 +++-
.../net/ethernet/pensando/ionic/ionic_lif.h | 1 -
.../net/ethernet/pensando/ionic/ionic_main.c | 2 ++
6 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
index 3838c4a70766..648d9d24be85 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
@@ -1076,3 +1076,13 @@ bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos)
return ((pos - tail) & mask) < ((head - tail) & mask);
}
+
+void ionic_reset_link_down_count(struct ionic_dev *idev)
+{
+ if (!READ_ONCE(idev->link_down_count_init)) {
+ idev->link_down_count_total = 0;
+ idev->link_down_count_last =
+ le16_to_cpu(idev->port_info->status.link_down_count);
+ WRITE_ONCE(idev->link_down_count_init, true);
+ }
+}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
index 5f677bcbaf02..db90e39a1442 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
@@ -185,6 +185,9 @@ struct ionic_dev {
struct ionic_port_info *port_info;
dma_addr_t port_info_pa;
struct ionic_port_extra_stats port_extra_stats_cache;
+ bool link_down_count_init;
+ u16 link_down_count_last;
+ u32 link_down_count_total;
struct ionic_devinfo dev_info;
};
@@ -395,4 +398,6 @@ bool ionic_adminq_poke_doorbell(struct ionic_queue *q);
bool ionic_txq_poke_doorbell(struct ionic_queue *q);
bool ionic_rxq_poke_doorbell(struct ionic_queue *q);
+void ionic_reset_link_down_count(struct ionic_dev *idev);
+
#endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index 6069fa460913..c4ab4b5caa0a 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -115,16 +115,32 @@ static void ionic_get_link_ext_stats(struct net_device *netdev,
struct ethtool_link_ext_stats *stats)
{
struct ionic_lif *lif = netdev_priv(netdev);
+ struct ionic *ionic = lif->ionic;
+ u64 link_down_count_total;
+ u16 link_down_count_fw;
- if (lif->ionic->pdev->is_virtfn)
+ if (ionic->pdev->is_virtfn)
return;
- if (!lif->ionic->idev.port_info) {
+ if (!ionic->idev.port_info) {
netdev_err_once(netdev, "port_info not initialized\n");
return;
}
- stats->link_down_events = lif->link_down_count;
+ link_down_count_fw =
+ le16_to_cpu(ionic->idev.port_info->status.link_down_count);
+ link_down_count_total = ionic->idev.link_down_count_total +
+ link_down_count_fw -
+ ionic->idev.link_down_count_last;
+
+ /* The firmware counter is only 16 bits and can wraparound */
+ if (link_down_count_fw < ionic->idev.link_down_count_last)
+ link_down_count_total += BIT(16);
+
+ ionic->idev.link_down_count_last = link_down_count_fw;
+ ionic->idev.link_down_count_total = link_down_count_total;
+
+ stats->link_down_events = link_down_count_total;
}
static int ionic_get_link_ksettings(struct net_device *netdev,
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 637e635bbf03..fd3ee9820531 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -140,6 +140,7 @@ void ionic_lif_deferred_enqueue(struct ionic_lif *lif,
static void ionic_link_status_check(struct ionic_lif *lif)
{
+ struct ionic_dev *idev = &lif->ionic->idev;
struct net_device *netdev = lif->netdev;
u16 link_status;
bool link_up;
@@ -153,6 +154,8 @@ static void ionic_link_status_check(struct ionic_lif *lif)
return;
}
+ ionic_reset_link_down_count(idev);
+
link_status = le16_to_cpu(lif->info->status.link_status);
link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
@@ -179,7 +182,6 @@ static void ionic_link_status_check(struct ionic_lif *lif)
}
} else {
if (netif_carrier_ok(netdev)) {
- lif->link_down_count++;
netdev_info(netdev, "Link down\n");
netif_carrier_off(netdev);
}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index 8e10f66dc50e..d34692462036 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -214,7 +214,6 @@ struct ionic_lif {
bool registered;
bool doorbell_wa;
u16 lif_type;
- unsigned int link_down_count;
unsigned int nmcast;
unsigned int nucast;
unsigned int nvlans;
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
index 306d9d160e17..6e6f3ed07271 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
@@ -737,6 +737,8 @@ int ionic_port_init(struct ionic *ionic)
memset(&idev->port_info->extra_stats, 0xff,
sizeof(idev->port_info->extra_stats));
+ WRITE_ONCE(idev->link_down_count_init, false);
+
sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data));
mutex_lock(&ionic->dev_cmd_lock);
--
2.17.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox