Files
openwrt/target/linux/airoha/patches-6.12/920-12-net-airoha-Add-ethtool-priv_flags-callbacks.patch
T
Lorenzo Bianconi d22ceb8d24 airoha: Improve LRO performances
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>
2026-05-27 09:17:12 +02:00

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