]> www.infradead.org Git - users/willy/linux.git/commitdiff
net: airoha: Add wlan flowtable TX offload
authorLorenzo Bianconi <lorenzo@kernel.org>
Thu, 14 Aug 2025 07:51:16 +0000 (09:51 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 19 Aug 2025 10:22:24 +0000 (12:22 +0200)
Introduce support to offload the traffic received on the ethernet NIC
and forwarded to the wireless one using HW Packet Processor Engine (PPE)
capabilities.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250814-airoha-en7581-wlan-tx-offload-v1-1-72e0a312003e@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/airoha/airoha_eth.h
drivers/net/ethernet/airoha/airoha_ppe.c

index a970b789cf232c316e5ea27b0146493bf91c3767..9f721e2b972f0e547978419701caf532df664910 100644 (file)
@@ -252,6 +252,10 @@ enum {
 #define AIROHA_FOE_MAC_SMAC_ID         GENMASK(20, 16)
 #define AIROHA_FOE_MAC_PPPOE_ID                GENMASK(15, 0)
 
+#define AIROHA_FOE_MAC_WDMA_QOS                GENMASK(15, 12)
+#define AIROHA_FOE_MAC_WDMA_BAND       BIT(11)
+#define AIROHA_FOE_MAC_WDMA_WCID       GENMASK(10, 0)
+
 struct airoha_foe_mac_info_common {
        u16 vlan1;
        u16 etype;
@@ -481,6 +485,13 @@ struct airoha_flow_table_entry {
        unsigned long cookie;
 };
 
+struct airoha_wdma_info {
+       u8 idx;
+       u8 queue;
+       u16 wcid;
+       u8 bss;
+};
+
 /* RX queue to IRQ mapping: BIT(q) in IRQ(n) */
 #define RX_IRQ0_BANK_PIN_MASK                  0x839f
 #define RX_IRQ1_BANK_PIN_MASK                  0x7fe00000
index 82163392332c92d3bf50a976ffd473ae7a31a344..2bf1c584ba7b7217549ce79df86f7a123199b5e1 100644 (file)
@@ -190,6 +190,31 @@ static int airoha_ppe_flow_mangle_ipv4(const struct flow_action_entry *act,
        return 0;
 }
 
+static int airoha_ppe_get_wdma_info(struct net_device *dev, const u8 *addr,
+                                   struct airoha_wdma_info *info)
+{
+       struct net_device_path_stack stack;
+       struct net_device_path *path;
+       int err;
+
+       if (!dev)
+               return -ENODEV;
+
+       err = dev_fill_forward_path(dev, addr, &stack);
+       if (err)
+               return err;
+
+       path = &stack.path[stack.num_paths - 1];
+       if (path->type != DEV_PATH_MTK_WDMA)
+               return -1;
+
+       info->idx = path->mtk_wdma.wdma_idx;
+       info->bss = path->mtk_wdma.bss;
+       info->wcid = path->mtk_wdma.wcid;
+
+       return 0;
+}
+
 static int airoha_get_dsa_port(struct net_device **dev)
 {
 #if IS_ENABLED(CONFIG_NET_DSA)
@@ -220,9 +245,9 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
                                        struct airoha_flow_data *data,
                                        int l4proto)
 {
-       int dsa_port = airoha_get_dsa_port(&dev);
+       u32 qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f), ports_pad, val;
+       int wlan_etype = -EINVAL, dsa_port = airoha_get_dsa_port(&dev);
        struct airoha_foe_mac_info_common *l2;
-       u32 qdata, ports_pad, val;
        u8 smac_id = 0xf;
 
        memset(hwe, 0, sizeof(*hwe));
@@ -236,31 +261,47 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
              AIROHA_FOE_IB1_BIND_TTL;
        hwe->ib1 = val;
 
-       val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f) |
-             AIROHA_FOE_IB2_PSE_QOS;
-       if (dsa_port >= 0)
-               val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, dsa_port);
-
+       val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f);
        if (dev) {
-               struct airoha_gdm_port *port = netdev_priv(dev);
-               u8 pse_port;
-
-               if (!airoha_is_valid_gdm_port(eth, port))
-                       return -EINVAL;
-
-               if (dsa_port >= 0)
-                       pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
-               else
-                       pse_port = 2; /* uplink relies on GDM2 loopback */
-               val |= FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, pse_port);
-
-               /* For downlink traffic consume SRAM memory for hw forwarding
-                * descriptors queue.
-                */
-               if (airhoa_is_lan_gdm_port(port))
-                       val |= AIROHA_FOE_IB2_FAST_PATH;
-
-               smac_id = port->id;
+               struct airoha_wdma_info info = {};
+
+               if (!airoha_ppe_get_wdma_info(dev, data->eth.h_dest, &info)) {
+                       val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, info.idx) |
+                              FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT,
+                                         FE_PSE_PORT_CDM4);
+                       qdata |= FIELD_PREP(AIROHA_FOE_ACTDP, info.bss);
+                       wlan_etype = FIELD_PREP(AIROHA_FOE_MAC_WDMA_BAND,
+                                               info.idx) |
+                                    FIELD_PREP(AIROHA_FOE_MAC_WDMA_WCID,
+                                               info.wcid);
+               } else {
+                       struct airoha_gdm_port *port = netdev_priv(dev);
+                       u8 pse_port;
+
+                       if (!airoha_is_valid_gdm_port(eth, port))
+                               return -EINVAL;
+
+                       if (dsa_port >= 0)
+                               pse_port = port->id == 4 ? FE_PSE_PORT_GDM4
+                                                        : port->id;
+                       else
+                               pse_port = 2; /* uplink relies on GDM2
+                                              * loopback
+                                              */
+
+                       val |= FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, pse_port) |
+                              AIROHA_FOE_IB2_PSE_QOS;
+                       /* For downlink traffic consume SRAM memory for hw
+                        * forwarding descriptors queue.
+                        */
+                       if (airhoa_is_lan_gdm_port(port))
+                               val |= AIROHA_FOE_IB2_FAST_PATH;
+                       if (dsa_port >= 0)
+                               val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ,
+                                                 dsa_port);
+
+                       smac_id = port->id;
+               }
        }
 
        if (is_multicast_ether_addr(data->eth.h_dest))
@@ -272,7 +313,6 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
        if (type == PPE_PKT_TYPE_IPV6_ROUTE_3T)
                hwe->ipv6.ports = ports_pad;
 
-       qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f);
        if (type == PPE_PKT_TYPE_BRIDGE) {
                airoha_ppe_foe_set_bridge_addrs(&hwe->bridge, &data->eth);
                hwe->bridge.data = qdata;
@@ -313,7 +353,9 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
                        l2->vlan2 = data->vlan.hdr[1].id;
        }
 
-       if (dsa_port >= 0) {
+       if (wlan_etype >= 0) {
+               l2->etype = wlan_etype;
+       } else if (dsa_port >= 0) {
                l2->etype = BIT(dsa_port);
                l2->etype |= !data->vlan.num ? BIT(15) : 0;
        } else if (data->pppoe.num) {
@@ -490,6 +532,10 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe,
                meter = &hwe->ipv4.l2.meter;
        }
 
+       pse_port = FIELD_GET(AIROHA_FOE_IB2_PSE_PORT, *ib2);
+       if (pse_port == FE_PSE_PORT_CDM4)
+               return;
+
        airoha_ppe_foe_flow_stat_entry_reset(ppe, npu, index);
 
        val = FIELD_GET(AIROHA_FOE_CHANNEL | AIROHA_FOE_QID, *data);
@@ -500,7 +546,6 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe,
                      AIROHA_FOE_IB2_PSE_QOS | AIROHA_FOE_IB2_FAST_PATH);
        *meter |= FIELD_PREP(AIROHA_FOE_TUNNEL_MTU, val);
 
-       pse_port = FIELD_GET(AIROHA_FOE_IB2_PSE_PORT, *ib2);
        nbq = pse_port == 1 ? 6 : 5;
        *ib2 &= ~(AIROHA_FOE_IB2_NBQ | AIROHA_FOE_IB2_PSE_PORT |
                  AIROHA_FOE_IB2_PSE_QOS);