* [PATCH net-next v2] net: airoha: add ethtool priv_flags support for LAN/WAN and GDM2 loopback
@ 2026-06-07 17:19 Lorenzo Bianconi
2026-06-07 17:59 ` Andrew Lunn
0 siblings, 1 reply; 4+ messages in thread
From: Lorenzo Bianconi @ 2026-06-07 17:19 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Lorenzo Bianconi
Cc: linux-arm-kernel, linux-mediatek, netdev, Madhur Agrawal
Introduce ethtool private flags infrastructure for the airoha ethernet
driver, allowing userspace to configure per-device behavior via ethtool.
Implement the "wan" private flag to let the user select whether a GDM
port is used as a hardware LAN or WAN interface. GDM2 is fixed as WAN
only, GDM1 is fixed as LAN only, while GDM3 and GDM4 can be switched
between LAN and WAN at runtime (when the interface is not running).
When a GDM3/GDM4 port is set to WAN mode, enable GDM2 loopback to
support hardware QoS. Conversely, when switching back to LAN mode,
disable the GDM2 loopback and restore the default forwarding
configuration.
Add airoha_disable_gdm2_loopback() as the counterpart of the existing
airoha_enable_gdm2_loopback(), and define FC_MAP6_DEF_VALUE for use
during loopback teardown.
Example usage to configure eth1 (GDM3/GDM4) as WAN:
$ ethtool --show-priv-flags eth1
Private flags for eth1:
wan: off
$ ethtool --set-priv-flags eth1 wan on
$ ethtool --show-priv-flags eth1
Private flags for eth1:
wan: on
To revert back to LAN mode:
$ ethtool --set-priv-flags eth1 wan off
Tested-by: Madhur Agrawal <madhur.agrawal@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
Changes in v2:
- Rework airoha_dev_set_wan_flag routine
- Enable GDM_STRIP_CRC_MASK in airoha_disable_gdm2_loopback()
- Do not always reset REG_SRC_PORT_FC_MAP6 in
airoha_disable_gdm2_loopback() but use the same condition used in
airoha_enable_gdm2_loopback().
- Link to v1: https://lore.kernel.org/r/20260606-airoha-ethtool-priv_flags-v1-1-401b2c9fe9f1@kernel.org
---
drivers/net/ethernet/airoha/airoha_eth.c | 173 ++++++++++++++++++++++++++++++
drivers/net/ethernet/airoha/airoha_regs.h | 1 +
2 files changed, 174 insertions(+)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 5a8e84fa9918..5dd160dbbbc1 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1960,6 +1960,49 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev)
return 0;
}
+static int airoha_disable_gdm2_loopback(struct airoha_gdm_dev *dev)
+{
+ struct airoha_gdm_port *port = dev->port;
+ 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_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
+ GDM_STRIP_CRC_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));
+
+ if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth))
+ 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)
{
@@ -2296,6 +2339,77 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
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;
+ int err;
+
+ if (port->id != AIROHA_GDM3_IDX &&
+ port->id != AIROHA_GDM4_IDX) {
+ /* GDM1 can be used just as LAN while GDM2 can be configured
+ * only as WAN
+ */
+ return -EOPNOTSUPP;
+ }
+
+ 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;
+
+ dev->flags |= AIROHA_PRIV_F_WAN;
+ airoha_dev_set_qdma(dev);
+ err = airoha_enable_gdm2_loopback(dev);
+ if (err)
+ goto error;
+ } else {
+ err = airoha_disable_gdm2_loopback(dev);
+ if (err)
+ return err;
+
+ dev->flags &= ~AIROHA_PRIV_F_WAN;
+ airoha_dev_set_qdma(dev);
+ }
+
+ err = airoha_set_macaddr(dev, netdev->dev_addr);
+ if (err)
+ goto error;
+
+ return 0;
+error:
+ /* Restore previous LAN or WAN configuration */
+ if (flags & AIROHA_PRIV_F_WAN) {
+ airoha_disable_gdm2_loopback(dev);
+ dev->flags &= ~AIROHA_PRIV_F_WAN;
+ airoha_dev_set_qdma(dev);
+ } else {
+ dev->flags |= AIROHA_PRIV_F_WAN;
+ airoha_dev_set_qdma(dev);
+ airoha_enable_gdm2_loopback(dev);
+ }
+
+ return err;
+}
+
+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)
{
@@ -2304,6 +2418,7 @@ static void airoha_ethtool_get_drvinfo(struct net_device *netdev,
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,
@@ -2368,6 +2483,60 @@ airoha_ethtool_get_rmon_stats(struct net_device *netdev,
} while (u64_stats_fetch_retry(&port->stats.syncp, start));
}
+static int airoha_ethtool_set_priv_flags(struct net_device *netdev, u32 flags)
+{
+ struct airoha_gdm_dev *dev = netdev_priv(netdev);
+ int i;
+
+ for (i = 0; i < AIROHA_PRIV_FLAGS_STR_LEN; i++) {
+ int err;
+
+ if (!((dev->flags ^ flags) & BIT(i)))
+ continue;
+
+ 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)
@@ -3094,6 +3263,10 @@ static const struct ethtool_ops airoha_ethtool_ops = {
.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 int airoha_metadata_dst_alloc(struct airoha_gdm_port *port)
diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
index 436f3c8779c1..4e17dfbcf2b8 100644
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -376,6 +376,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
---
base-commit: 903db046d5579bef0ea699eae4b279dd6455fc9f
change-id: 20260606-airoha-ethtool-priv_flags-b6aa70caa780
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH net-next v2] net: airoha: add ethtool priv_flags support for LAN/WAN and GDM2 loopback
2026-06-07 17:19 [PATCH net-next v2] net: airoha: add ethtool priv_flags support for LAN/WAN and GDM2 loopback Lorenzo Bianconi
@ 2026-06-07 17:59 ` Andrew Lunn
2026-06-07 18:07 ` Lorenzo Bianconi
0 siblings, 1 reply; 4+ messages in thread
From: Andrew Lunn @ 2026-06-07 17:59 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev,
Madhur Agrawal
> When a GDM3/GDM4 port is set to WAN mode, enable GDM2 loopback to
> support hardware QoS. Conversely, when switching back to LAN mode,
> disable the GDM2 loopback and restore the default forwarding
> configuration.
Why not just use the presence of an off loadable qdisc as the
indicator to change mode?
Andrew
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net-next v2] net: airoha: add ethtool priv_flags support for LAN/WAN and GDM2 loopback
2026-06-07 17:59 ` Andrew Lunn
@ 2026-06-07 18:07 ` Lorenzo Bianconi
2026-06-07 18:48 ` Andrew Lunn
0 siblings, 1 reply; 4+ messages in thread
From: Lorenzo Bianconi @ 2026-06-07 18:07 UTC (permalink / raw)
To: Andrew Lunn
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev,
Madhur Agrawal
[-- Attachment #1: Type: text/plain, Size: 449 bytes --]
> > When a GDM3/GDM4 port is set to WAN mode, enable GDM2 loopback to
> > support hardware QoS. Conversely, when switching back to LAN mode,
> > disable the GDM2 loopback and restore the default forwarding
> > configuration.
>
> Why not just use the presence of an off loadable qdisc as the
> indicator to change mode?
Hi Andrew,
Interesting, can you please provide more details about you mean?
Regards,
Lorenzo
>
> Andrew
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net-next v2] net: airoha: add ethtool priv_flags support for LAN/WAN and GDM2 loopback
2026-06-07 18:07 ` Lorenzo Bianconi
@ 2026-06-07 18:48 ` Andrew Lunn
0 siblings, 0 replies; 4+ messages in thread
From: Andrew Lunn @ 2026-06-07 18:48 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev,
Madhur Agrawal
On Sun, Jun 07, 2026 at 08:07:37PM +0200, Lorenzo Bianconi wrote:
> > > When a GDM3/GDM4 port is set to WAN mode, enable GDM2 loopback to
> > > support hardware QoS. Conversely, when switching back to LAN mode,
> > > disable the GDM2 loopback and restore the default forwarding
> > > configuration.
> >
> > Why not just use the presence of an off loadable qdisc as the
> > indicator to change mode?
>
> Hi Andrew,
>
> Interesting, can you please provide more details about you mean?
You say you need it to be in loopback mode in order to support
hardware QoS. You configure QoS by using a qdisc, and something like
mqprio, tcf etc. So when the user configures QoS, you can see if the
hardware supports the request QoS. If so, swap to loopback mode and
offload the QoS function to the hardware. If the hardware does not
support the requested QoS, leave it in software and keep with LAN
mode.
Andrew
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-06-07 18:48 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-07 17:19 [PATCH net-next v2] net: airoha: add ethtool priv_flags support for LAN/WAN and GDM2 loopback Lorenzo Bianconi
2026-06-07 17:59 ` Andrew Lunn
2026-06-07 18:07 ` Lorenzo Bianconi
2026-06-07 18:48 ` Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox