RE: [PATCH net-next v10 5/7] r8169: add support and enable rss
Javen <[email protected]>
| Newsgroups | org.kernel.vger.netdev,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
> >On Mon, 3 Aug 2026 10:13:03 +0800 javen wrote: >> From: Javen Xu <[email protected]> >> >> This patch adds support and enable rss for RTL8127. >> >> Signed-off-by: Javen Xu <[email protected]> >> --- >> 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 >> >> Changes in v9: >> - remove rtl8169_set_desc_dma_addr, only set desc dma addr for >> RX_DESC_TYPE_RSS desc >> >> Changes in v10: >> - Change rss_key to u8 array and write rss_key_reg as u32 values. >> Use get_unaligned_le32() to keep behavior consistent on big-endian >> and little-endian >> --- >> drivers/net/ethernet/realtek/r8169_main.c | 379 >> ++++++++++++++++++++-- >> 1 file changed, 346 insertions(+), 33 deletions(-) >> >> diff --git a/drivers/net/ethernet/realtek/r8169_main.c >> b/drivers/net/ethernet/realtek/r8169_main.c >> index 31f6d0c2e3d1..4e571fcea092 100644 >> --- a/drivers/net/ethernet/realtek/r8169_main.c >> +++ b/drivers/net/ethernet/realtek/r8169_main.c >> @@ -88,6 +88,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 >> >> @@ -595,6 +608,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 { >> @@ -652,6 +679,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 */ >> @@ -673,9 +705,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 { >> @@ -747,6 +797,11 @@ enum rtl_dash_type { >> RTL_DASH_25_BP, >> }; >> >> +enum rx_desc_type { >> + RX_DESC_TYPE_DEFAULT, >> + RX_DESC_TYPE_RSS, >> +}; >> + >> struct rtl8169_rx_ring { >> u32 cur_rx; /* Index of next Rx pkt. */ >> u32 dirty_rx; /* Index for recycling. */ >> @@ -756,6 +811,12 @@ struct rtl8169_rx_ring { >> struct page *rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ >> }; >> >> +struct rtl8169_rss_data { >> + u8 rss_key[RTL_RSS_KEY_SIZE]; >> + 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; >> @@ -775,7 +836,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 { >> @@ -1605,6 +1668,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) { >> @@ -1906,9 +1974,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)); @@ -2736,17 +2815,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 = R8169_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) @@ >> -2871,6 +2960,58 @@ 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) { >> + u8 *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 < RTL_RSS_KEY_SIZE; i += sizeof(u32)) >> + RTL_W32(tp, rss_key_reg + i, get_unaligned_le32(rss_key >> + + i)); > >you fetched packed word of the key with get_unaligned_le32().. > >> +} >> + >> +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; > >.. but the indir table you pack manually, why? > >> + 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; > >| should be at the end of the lines > >> + 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); >> +} > >> + /* enable rx descriptor type v4 and set queue num for rss*/ > >nit: missing space at the end of the comment > > >> - 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); > >Why the two calls to pci_alloc_irq_vectors() ? >It should select the best number of IRQs it can, so why not just call > > pci_alloc_irq_vectors(pdev, 1, get_max_irq_nvecs(tp), flags); > Hardware limitation. When we try to enable rss, we should use new interrupt mapping. New interrupt 0-7 is used for rx, 8-15 is used for tx, and linkchg interrupt is fixed at 29. So the min irq number for RTL8127 to enable rss is 30, not 1. I will add this explanation in the code. Thanks, Javen >note: please review the submission for unnecessarily going over 80 chars, we >still prefer <=80 lines in netdev > >> if (nvecs < 0) >> return nvecs;