mirror of
https://github.com/raspberrypi/linux.git
synced 2026-01-04 18:27:36 +00:00
net: airoha: Add wlan flowtable TX offload
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>
This commit is contained in:
committed by
Paolo Abeni
parent
244ada9cb7
commit
a8bdd935d1
@@ -252,6 +252,10 @@ enum {
|
|||||||
#define AIROHA_FOE_MAC_SMAC_ID GENMASK(20, 16)
|
#define AIROHA_FOE_MAC_SMAC_ID GENMASK(20, 16)
|
||||||
#define AIROHA_FOE_MAC_PPPOE_ID GENMASK(15, 0)
|
#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 {
|
struct airoha_foe_mac_info_common {
|
||||||
u16 vlan1;
|
u16 vlan1;
|
||||||
u16 etype;
|
u16 etype;
|
||||||
@@ -481,6 +485,13 @@ struct airoha_flow_table_entry {
|
|||||||
unsigned long cookie;
|
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) */
|
/* RX queue to IRQ mapping: BIT(q) in IRQ(n) */
|
||||||
#define RX_IRQ0_BANK_PIN_MASK 0x839f
|
#define RX_IRQ0_BANK_PIN_MASK 0x839f
|
||||||
#define RX_IRQ1_BANK_PIN_MASK 0x7fe00000
|
#define RX_IRQ1_BANK_PIN_MASK 0x7fe00000
|
||||||
|
|||||||
@@ -190,6 +190,31 @@ static int airoha_ppe_flow_mangle_ipv4(const struct flow_action_entry *act,
|
|||||||
return 0;
|
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)
|
static int airoha_get_dsa_port(struct net_device **dev)
|
||||||
{
|
{
|
||||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
#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,
|
struct airoha_flow_data *data,
|
||||||
int l4proto)
|
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;
|
struct airoha_foe_mac_info_common *l2;
|
||||||
u32 qdata, ports_pad, val;
|
|
||||||
u8 smac_id = 0xf;
|
u8 smac_id = 0xf;
|
||||||
|
|
||||||
memset(hwe, 0, sizeof(*hwe));
|
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;
|
AIROHA_FOE_IB1_BIND_TTL;
|
||||||
hwe->ib1 = val;
|
hwe->ib1 = val;
|
||||||
|
|
||||||
val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f) |
|
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);
|
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
struct airoha_gdm_port *port = netdev_priv(dev);
|
struct airoha_wdma_info info = {};
|
||||||
u8 pse_port;
|
|
||||||
|
|
||||||
if (!airoha_is_valid_gdm_port(eth, port))
|
if (!airoha_ppe_get_wdma_info(dev, data->eth.h_dest, &info)) {
|
||||||
return -EINVAL;
|
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 (dsa_port >= 0)
|
if (!airoha_is_valid_gdm_port(eth, port))
|
||||||
pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
|
return -EINVAL;
|
||||||
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
|
if (dsa_port >= 0)
|
||||||
* descriptors queue.
|
pse_port = port->id == 4 ? FE_PSE_PORT_GDM4
|
||||||
*/
|
: port->id;
|
||||||
if (airhoa_is_lan_gdm_port(port))
|
else
|
||||||
val |= AIROHA_FOE_IB2_FAST_PATH;
|
pse_port = 2; /* uplink relies on GDM2
|
||||||
|
* loopback
|
||||||
|
*/
|
||||||
|
|
||||||
smac_id = port->id;
|
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))
|
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)
|
if (type == PPE_PKT_TYPE_IPV6_ROUTE_3T)
|
||||||
hwe->ipv6.ports = ports_pad;
|
hwe->ipv6.ports = ports_pad;
|
||||||
|
|
||||||
qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f);
|
|
||||||
if (type == PPE_PKT_TYPE_BRIDGE) {
|
if (type == PPE_PKT_TYPE_BRIDGE) {
|
||||||
airoha_ppe_foe_set_bridge_addrs(&hwe->bridge, &data->eth);
|
airoha_ppe_foe_set_bridge_addrs(&hwe->bridge, &data->eth);
|
||||||
hwe->bridge.data = qdata;
|
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;
|
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 = BIT(dsa_port);
|
||||||
l2->etype |= !data->vlan.num ? BIT(15) : 0;
|
l2->etype |= !data->vlan.num ? BIT(15) : 0;
|
||||||
} else if (data->pppoe.num) {
|
} 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;
|
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);
|
airoha_ppe_foe_flow_stat_entry_reset(ppe, npu, index);
|
||||||
|
|
||||||
val = FIELD_GET(AIROHA_FOE_CHANNEL | AIROHA_FOE_QID, *data);
|
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);
|
AIROHA_FOE_IB2_PSE_QOS | AIROHA_FOE_IB2_FAST_PATH);
|
||||||
*meter |= FIELD_PREP(AIROHA_FOE_TUNNEL_MTU, val);
|
*meter |= FIELD_PREP(AIROHA_FOE_TUNNEL_MTU, val);
|
||||||
|
|
||||||
pse_port = FIELD_GET(AIROHA_FOE_IB2_PSE_PORT, *ib2);
|
|
||||||
nbq = pse_port == 1 ? 6 : 5;
|
nbq = pse_port == 1 ? 6 : 5;
|
||||||
*ib2 &= ~(AIROHA_FOE_IB2_NBQ | AIROHA_FOE_IB2_PSE_PORT |
|
*ib2 &= ~(AIROHA_FOE_IB2_NBQ | AIROHA_FOE_IB2_PSE_PORT |
|
||||||
AIROHA_FOE_IB2_PSE_QOS);
|
AIROHA_FOE_IB2_PSE_QOS);
|
||||||
|
|||||||
Reference in New Issue
Block a user