Commit a8bdd935 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Paolo Abeni
Browse files

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: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250814-airoha-en7581-wlan-tx-offload-v1-1-72e0a312003e@kernel.org


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 244ada9c
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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
+74 −29
Original line number Diff line number Diff line
@@ -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,12 +261,20 @@ 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_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;

@@ -249,19 +282,27 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
				return -EINVAL;

			if (dsa_port >= 0)
			pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
				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);
				pse_port = 2; /* uplink relies on GDM2
					       * loopback
					       */

		/* For downlink traffic consume SRAM memory for hw forwarding
		 * descriptors queue.
			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))
		val |= AIROHA_FOE_IB2_MULTICAST;
@@ -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);