mirror of
https://github.com/openwrt/openwrt.git
synced 2026-06-17 12:40:16 +04:00
d22ceb8d24
Add hardware TCP Large Receive Offload (LRO) support to the airoha_eth driver, leveraging the EN7581/AN7583 SoC's 8 dedicated LRO hardware queues mapped to RX queues 24–31. LRO hw offloading does not support Scatter-Gather (SG) so it is required to increase the page_pool allocation order to 2 for RX queues 24–31 (LRO queues). Performance comparison between GRO and hw LRO has been carried out using a 10Gbps NIC: GRO: ~2.7 Gbps LRO: ~8.1 Gbps Tested-by: Madhur Agrawal <madhur.agrawal@airoha.com> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Link: https://github.com/openwrt/openwrt/pull/23530 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
247 lines
7.0 KiB
Diff
247 lines
7.0 KiB
Diff
From e928621a0bbd010b75624c77105ce31f2b8d2faf Mon Sep 17 00:00:00 2001
|
|
Message-ID: <e928621a0bbd010b75624c77105ce31f2b8d2faf.1779348625.git.lorenzo@kernel.org>
|
|
In-Reply-To: <e15783f7c987e199ecf80b3d858ed5a86d33c508.1779348625.git.lorenzo@kernel.org>
|
|
References: <e15783f7c987e199ecf80b3d858ed5a86d33c508.1779348625.git.lorenzo@kernel.org>
|
|
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
|
Date: Sat, 13 Dec 2025 09:45:09 +0100
|
|
Subject: [PATCH 12/13] net: airoha: Add ethtool priv_flags callbacks
|
|
|
|
Introduce ethtool priv_flags callbacks in order to allow the user to
|
|
select if the configured device will be used as hw lan or wan and enable
|
|
or disable gdm2 loopback (used for hw QoS).
|
|
|
|
Tested-by: Madhur Agrawal <madhur.agrawal@airoha.com>
|
|
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
|
---
|
|
drivers/net/ethernet/airoha/airoha_eth.c | 173 ++++++++++++++++++++++
|
|
drivers/net/ethernet/airoha/airoha_regs.h | 1 +
|
|
2 files changed, 174 insertions(+)
|
|
|
|
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
|
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
|
@@ -1915,6 +1915,11 @@ static int airoha_dev_open(struct net_de
|
|
u32 cur_len, pse_port = FE_PSE_PORT_PPE1;
|
|
struct airoha_qdma *qdma = dev->qdma;
|
|
|
|
+ if (port->id == AIROHA_GDM2_IDX && airoha_is_lan_gdm_dev(dev)) {
|
|
+ /* GDM2 can be used just as wan */
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
#if defined(CONFIG_PCS_AIROHA)
|
|
if (airhoa_is_phy_external(port)) {
|
|
err = phylink_of_phy_connect(dev->phylink, netdev->dev.of_node, 0);
|
|
@@ -2117,6 +2122,45 @@ static int airoha_enable_gdm2_loopback(s
|
|
return 0;
|
|
}
|
|
|
|
+static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev)
|
|
+{
|
|
+ struct airoha_eth *eth = dev->eth;
|
|
+ int i, src_port;
|
|
+ u32 pse_port;
|
|
+
|
|
+ src_port = eth->soc->ops.get_sport(dev->port, dev->nbq);
|
|
+ if (src_port < 0)
|
|
+ return src_port;
|
|
+
|
|
+ airoha_fe_clear(eth,
|
|
+ REG_SP_DFT_CPORT(src_port >> fls(SP_CPORT_DFT_MASK)),
|
|
+ SP_CPORT_MASK(src_port & SP_CPORT_DFT_MASK));
|
|
+
|
|
+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
|
|
+ FE_PSE_PORT_DROP);
|
|
+ airoha_fe_clear(eth, REG_GDM_LPBK_CFG(AIROHA_GDM2_IDX),
|
|
+ LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK);
|
|
+ pse_port = airoha_ppe_is_enabled(eth, 1) ? FE_PSE_PORT_PPE2
|
|
+ : FE_PSE_PORT_PPE1;
|
|
+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
|
|
+ pse_port);
|
|
+
|
|
+ airoha_fe_rmw(eth, REG_FE_WAN_PORT, WAN0_MASK,
|
|
+ FIELD_PREP(WAN0_MASK, AIROHA_GDM2_IDX));
|
|
+
|
|
+ for (i = 0; i < eth->soc->num_ppe; i++)
|
|
+ airoha_fe_clear(eth, REG_PPE_DFT_CPORT(i, AIROHA_GDM2_IDX),
|
|
+ DFT_CPORT_MASK(AIROHA_GDM2_IDX));
|
|
+
|
|
+ /* Enable VIP and IFC for GDM2 */
|
|
+ airoha_fe_set(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
|
|
+ airoha_fe_set(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));
|
|
+
|
|
+ airoha_fe_wr(eth, REG_SRC_PORT_FC_MAP6, FC_MAP6_DEF_VALUE);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static struct airoha_gdm_dev *
|
|
airoha_get_wan_gdm_dev(struct airoha_eth *eth)
|
|
{
|
|
@@ -2521,6 +2565,80 @@ error:
|
|
return NETDEV_TX_OK;
|
|
}
|
|
|
|
+struct airoha_ethool_priv_flags {
|
|
+ char name[ETH_GSTRING_LEN];
|
|
+ int (*handler)(struct net_device *netdev, u32 flags);
|
|
+};
|
|
+
|
|
+static int airoha_dev_set_wan_flag(struct net_device *netdev, u32 flags)
|
|
+{
|
|
+ struct airoha_gdm_dev *dev = netdev_priv(netdev);
|
|
+ struct airoha_gdm_port *port = dev->port;
|
|
+ struct airoha_eth *eth = dev->eth;
|
|
+
|
|
+ if (!((dev->flags ^ flags) & AIROHA_PRIV_F_WAN))
|
|
+ return 0;
|
|
+
|
|
+ if (netif_running(netdev))
|
|
+ return -EBUSY;
|
|
+
|
|
+ if (flags & AIROHA_PRIV_F_WAN) {
|
|
+ struct airoha_gdm_dev *wan_dev;
|
|
+
|
|
+ /* Verify the wan device is not already configured */
|
|
+ wan_dev = airoha_get_wan_gdm_dev(eth);
|
|
+ if (wan_dev && wan_dev != dev)
|
|
+ return -EBUSY;
|
|
+
|
|
+ switch (port->id) {
|
|
+ case AIROHA_GDM2_IDX:
|
|
+ dev->flags |= AIROHA_PRIV_F_WAN;
|
|
+ airoha_dev_set_qdma(dev);
|
|
+ break;
|
|
+ case AIROHA_GDM3_IDX:
|
|
+ case AIROHA_GDM4_IDX: {
|
|
+ int err;
|
|
+
|
|
+ dev->flags |= AIROHA_PRIV_F_WAN;
|
|
+ airoha_dev_set_qdma(dev);
|
|
+
|
|
+ err = airoha_enable_gdm2_loopback(dev);
|
|
+ if (err) {
|
|
+ dev->flags &= ~AIROHA_PRIV_F_WAN;
|
|
+ return err;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+ } else {
|
|
+ switch (port->id) {
|
|
+ case AIROHA_GDM3_IDX:
|
|
+ case AIROHA_GDM4_IDX: {
|
|
+ int err;
|
|
+
|
|
+ err = airoha_disable_gdm2_loopback(dev);
|
|
+ if (err)
|
|
+ return err;
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ dev->flags &= ~AIROHA_PRIV_F_WAN;
|
|
+ airoha_dev_set_qdma(dev);
|
|
+ }
|
|
+
|
|
+ return airoha_set_macaddr(dev, netdev->dev_addr);
|
|
+}
|
|
+
|
|
+static const struct airoha_ethool_priv_flags airoha_eth_priv_flags[] = {
|
|
+ { "wan", airoha_dev_set_wan_flag },
|
|
+};
|
|
+#define AIROHA_PRIV_FLAGS_STR_LEN ARRAY_SIZE(airoha_eth_priv_flags)
|
|
+
|
|
static void airoha_ethtool_get_drvinfo(struct net_device *netdev,
|
|
struct ethtool_drvinfo *info)
|
|
{
|
|
@@ -2529,6 +2647,7 @@ static void airoha_ethtool_get_drvinfo(s
|
|
|
|
strscpy(info->driver, eth->dev->driver->name, sizeof(info->driver));
|
|
strscpy(info->bus_info, dev_name(eth->dev), sizeof(info->bus_info));
|
|
+ info->n_priv_flags = AIROHA_PRIV_FLAGS_STR_LEN;
|
|
}
|
|
|
|
static void airoha_ethtool_get_mac_stats(struct net_device *netdev,
|
|
@@ -2593,6 +2712,56 @@ airoha_ethtool_get_rmon_stats(struct net
|
|
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
|
|
}
|
|
|
|
+static int airoha_ethtool_set_priv_flags(struct net_device *netdev, u32 flags)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < AIROHA_PRIV_FLAGS_STR_LEN; i++) {
|
|
+ int err;
|
|
+
|
|
+ if (!airoha_eth_priv_flags[i].handler)
|
|
+ continue;
|
|
+
|
|
+ err = airoha_eth_priv_flags[i].handler(netdev, flags);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static u32 airoha_ethtool_get_priv_flags(struct net_device *netdev)
|
|
+{
|
|
+ struct airoha_gdm_dev *dev = netdev_priv(netdev);
|
|
+
|
|
+ return dev->flags;
|
|
+}
|
|
+
|
|
+static int airoha_ethtool_get_sset_count(struct net_device *netdev, int sset)
|
|
+{
|
|
+ switch (sset) {
|
|
+ case ETH_SS_PRIV_FLAGS:
|
|
+ return AIROHA_PRIV_FLAGS_STR_LEN;
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void airoha_ethtool_get_strings(struct net_device *netdev,
|
|
+ u32 stringset, u8 *data)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ switch (stringset) {
|
|
+ case ETH_SS_PRIV_FLAGS:
|
|
+ for (i = 0; i < AIROHA_PRIV_FLAGS_STR_LEN; i++)
|
|
+ ethtool_puts(&data, airoha_eth_priv_flags[i].name);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
|
|
int channel, enum tx_sched_mode mode,
|
|
const u16 *weights, u8 n_weights)
|
|
@@ -3314,6 +3483,10 @@ static const struct ethtool_ops airoha_e
|
|
.get_rmon_stats = airoha_ethtool_get_rmon_stats,
|
|
.get_link_ksettings = phy_ethtool_get_link_ksettings,
|
|
.get_link = ethtool_op_get_link,
|
|
+ .set_priv_flags = airoha_ethtool_set_priv_flags,
|
|
+ .get_priv_flags = airoha_ethtool_get_priv_flags,
|
|
+ .get_sset_count = airoha_ethtool_get_sset_count,
|
|
+ .get_strings = airoha_ethtool_get_strings,
|
|
};
|
|
|
|
static void airoha_mac_config(struct phylink_config *config, unsigned int mode,
|
|
--- a/drivers/net/ethernet/airoha/airoha_regs.h
|
|
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
|
|
@@ -402,6 +402,7 @@
|
|
|
|
#define REG_SRC_PORT_FC_MAP6 0x2298
|
|
#define FC_ID_OF_SRC_PORT_MASK(_n) GENMASK(4 + ((_n) << 3), ((_n) << 3))
|
|
+#define FC_MAP6_DEF_VALUE 0x1b1a1918
|
|
|
|
#define REG_CDM5_RX_OQ1_DROP_CNT 0x29d4
|
|
|