diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 4509281c3c7b..402aa1d33d33 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -1899,36 +1899,81 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev) return 0; } -static int airoha_dev_init(struct net_device *netdev) +static struct airoha_gdm_dev * +airoha_get_wan_gdm_dev(struct airoha_eth *eth) { - struct airoha_gdm_dev *dev = netdev_priv(netdev); - struct airoha_gdm_port *port = dev->port; + int i; + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; + int j; + + if (!port) + continue; + + for (j = 0; j < ARRAY_SIZE(port->devs); j++) { + struct airoha_gdm_dev *dev = port->devs[j]; + + if (dev && !airoha_is_lan_gdm_dev(dev)) + return dev; + } + } + + return NULL; +} + +static void airoha_dev_set_qdma(struct airoha_gdm_dev *dev) +{ + struct net_device *netdev = netdev_from_priv(dev); struct airoha_eth *eth = dev->eth; int ppe_id; /* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */ dev->qdma = ð->qdma[!airoha_is_lan_gdm_dev(dev)]; netdev->irq = dev->qdma->irq_banks[0].irq; - airoha_set_macaddr(dev, netdev->dev_addr); + + ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1); + airoha_ppe_set_cpu_port(dev, ppe_id, airoha_get_fe_port(dev)); +} + +static int airoha_dev_init(struct net_device *netdev) +{ + struct airoha_gdm_dev *dev = netdev_priv(netdev); + struct airoha_gdm_port *port = dev->port; switch (port->id) { case AIROHA_GDM3_IDX: - case AIROHA_GDM4_IDX: - /* If GDM2 is active we can't enable loopback */ - if (!eth->ports[1]) { - int err; + case AIROHA_GDM4_IDX: { + struct airoha_eth *eth = dev->eth; - err = airoha_enable_gdm2_loopback(dev); - if (err) - return err; - } + /* GDM2 supports a single net_device */ + if (eth->ports[1] && eth->ports[1]->devs[0]) + break; + + if (airoha_get_wan_gdm_dev(eth)) + break; + + fallthrough; + } + case AIROHA_GDM2_IDX: + /* GDM2 is always used as wan */ + dev->flags |= AIROHA_PRIV_F_WAN; break; default: break; } - ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1); - airoha_ppe_set_cpu_port(dev, ppe_id, airoha_get_fe_port(dev)); + airoha_dev_set_qdma(dev); + airoha_set_macaddr(dev, netdev->dev_addr); + + if (!airoha_is_lan_gdm_dev(dev) && + (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)) { + int err; + + err = airoha_enable_gdm2_loopback(dev); + if (err) + return err; + } return 0; } diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h index 666e9246e70e..3e8262f583a7 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h @@ -538,6 +538,10 @@ struct airoha_qdma { DECLARE_BITMAP(qos_channel_map, AIROHA_NUM_QOS_CHANNELS); }; +enum airoha_priv_flags { + AIROHA_PRIV_F_WAN = BIT(0), +}; + struct airoha_gdm_dev { struct airoha_gdm_port *port; struct airoha_qdma *qdma; @@ -548,6 +552,7 @@ struct airoha_gdm_dev { u64 cpu_tx_packets; u64 fwd_tx_packets; + u32 flags; int nbq; }; @@ -654,13 +659,7 @@ static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid) static inline bool airoha_is_lan_gdm_dev(struct airoha_gdm_dev *dev) { - struct airoha_gdm_port *port = dev->port; - - /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. - * GDM{2,3,4} can be used as wan port connected to an external - * phy module. - */ - return port->id == 1; + return !(dev->flags & AIROHA_PRIV_F_WAN); } static inline bool airoha_is_7581(struct airoha_eth *eth) diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 96abf451fdac..f54622904733 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -355,7 +355,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, return -EINVAL; port = dev->port; - if (dsa_port >= 0 || eth->ports[1]) + if (dsa_port >= 0 || airoha_is_lan_gdm_dev(dev)) pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id; else