[openwrt/openwrt] kernel: support hw flow-offloading counters on newer MediaTek SoCs

LEDE Commits lede-commits at lists.infradead.org
Wed Nov 2 04:42:17 PDT 2022


dangole pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/9721a42a272aab941ded476a4baa4a85031c3f07

commit 9721a42a272aab941ded476a4baa4a85031c3f07
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Wed Nov 2 11:24:56 2022 +0000

    kernel: support hw flow-offloading counters on newer MediaTek SoCs
    
    The packet processing engine (PPE) found in newer ARM-based MediaTek
    SoCs provides packet and byte counters for offloaded streams.
    Import pending patch reading and using those counters.
    
    Signed-off-by: Daniel Golle <daniel at makrotopia.org>
---
 ...t-mediatek-ppe-add-support-for-flow-accou.patch | 409 +++++++++++++++++++++
 1 file changed, 409 insertions(+)

diff --git a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch
new file mode 100644
index 0000000000..815e0d2337
--- /dev/null
+++ b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch
@@ -0,0 +1,409 @@
+From patchwork Wed Nov  2 00:58:01 2022
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Daniel Golle <daniel at makrotopia.org>
+X-Patchwork-Id: 13027653
+X-Patchwork-Delegate: kuba at kernel.org
+Return-Path: <netdev-owner at kernel.org>
+Date: Wed, 2 Nov 2022 00:58:01 +0000
+From: Daniel Golle <daniel at makrotopia.org>
+To: Felix Fietkau <nbd at nbd.name>, John Crispin <john at phrozen.org>,
+        Sean Wang <sean.wang at mediatek.com>,
+        Mark Lee <Mark-MC.Lee at mediatek.com>,
+        "David S. Miller" <davem at davemloft.net>,
+        Eric Dumazet <edumazet at google.com>,
+        Jakub Kicinski <kuba at kernel.org>,
+        Paolo Abeni <pabeni at redhat.com>,
+        Matthias Brugger <matthias.bgg at gmail.com>,
+        netdev at vger.kernel.org, linux-arm-kernel at lists.infradead.org,
+        linux-mediatek at lists.infradead.org, linux-kernel at vger.kernel.org
+Subject: [PATCH v4] net: ethernet: mediatek: ppe: add support for flow
+ accounting
+Message-ID: <Y2HAmYYPd77dz+K5 at makrotopia.org>
+MIME-Version: 1.0
+Content-Disposition: inline
+Precedence: bulk
+List-ID: <netdev.vger.kernel.org>
+X-Mailing-List: netdev at vger.kernel.org
+X-Patchwork-Delegate: kuba at kernel.org
+
+The PPE units found in MT7622 and newer support packet and byte
+accounting of hw-offloaded flows. Add support for reading those
+counters as found in MediaTek's SDK[1].
+
+[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/bc6a6a375c800dc2b80e1a325a2c732d1737df92
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+v4: declare function mtk_mib_entry_read as static
+v3: don't bother to set 'false' values in any zero-initialized struct
+    use mtk_foe_entry_ib2
+    both changes were requested by Felix Fietkau
+
+v2: fix wrong variable name in return value check spotted by Denis Kirjanov
+
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   |   7 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   |   1 +
+ drivers/net/ethernet/mediatek/mtk_ppe.c       | 110 +++++++++++++++++-
+ drivers/net/ethernet/mediatek/mtk_ppe.h       |  23 +++-
+ .../net/ethernet/mediatek/mtk_ppe_debugfs.c   |   9 +-
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   |   7 ++
+ drivers/net/ethernet/mediatek/mtk_ppe_regs.h  |  14 +++
+ 7 files changed, 166 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -4084,7 +4084,9 @@ static int mtk_probe(struct platform_dev
+ 			u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400;
+ 
+ 			eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr,
+-						   eth->soc->offload_version, i);
++						   eth->soc->offload_version, i,
++						   eth->soc->has_accounting);
++
+ 			if (!eth->ppe[i]) {
+ 				err = -ENOMEM;
+ 				goto err_free_dev;
+@@ -4204,6 +4206,7 @@ static const struct mtk_soc_data mt7622_
+ 	.required_pctl = false,
+ 	.offload_version = 2,
+ 	.hash_offset = 2,
++	.has_accounting = true,
+ 	.foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
+ 	.txrx = {
+ 		.txd_size = sizeof(struct mtk_tx_dma),
+@@ -4241,6 +4244,7 @@ static const struct mtk_soc_data mt7629_
+ 	.hw_features = MTK_HW_FEATURES,
+ 	.required_clks = MT7629_CLKS_BITMAP,
+ 	.required_pctl = false,
++	.has_accounting = true,
+ 	.txrx = {
+ 		.txd_size = sizeof(struct mtk_tx_dma),
+ 		.rxd_size = sizeof(struct mtk_rx_dma),
+@@ -4261,6 +4265,7 @@ static const struct mtk_soc_data mt7986_
+ 	.offload_version = 2,
+ 	.hash_offset = 4,
+ 	.foe_entry_size = sizeof(struct mtk_foe_entry),
++	.has_accounting = true,
+ 	.txrx = {
+ 		.txd_size = sizeof(struct mtk_tx_dma_v2),
+ 		.rxd_size = sizeof(struct mtk_rx_dma_v2),
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -983,6 +983,7 @@ struct mtk_soc_data {
+ 	u8		hash_offset;
+ 	u16		foe_entry_size;
+ 	netdev_features_t hw_features;
++	bool		has_accounting;
+ 	struct {
+ 		u32	txd_size;
+ 		u32	rxd_size;
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -74,6 +74,46 @@ static int mtk_ppe_wait_busy(struct mtk_
+ 	return ret;
+ }
+ 
++static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe)
++{
++	int ret;
++	u32 val;
++
++	ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val,
++				 !(val & MTK_PPE_MIB_SER_CR_ST),
++				 20, MTK_PPE_WAIT_TIMEOUT_US);
++
++	if (ret)
++		dev_err(ppe->dev, "MIB table busy");
++
++	return ret;
++}
++
++static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
++{
++	u32 val, cnt_r0, cnt_r1, cnt_r2;
++	u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high;
++
++	val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST;
++	ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val);
++
++	if (mtk_ppe_mib_wait_busy(ppe))
++		return -ETIMEDOUT;
++
++	cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0);
++	cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1);
++	cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2);
++
++	byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
++	byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
++	pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
++	pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
++	*bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
++	*packets = (pkt_cnt_high << 16) | pkt_cnt_low;
++
++	return 0;
++}
++
+ static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
+ {
+ 	ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
+@@ -444,6 +484,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp
+ 		hwe->ib1 &= ~MTK_FOE_IB1_STATE;
+ 		hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID);
+ 		dma_wmb();
++		if (ppe->accounting) {
++			struct mtk_foe_accounting *acct;
++
++			acct = ppe->acct_table + entry->hash * sizeof(*acct);
++			acct->packets = 0;
++			acct->bytes = 0;
++		}
+ 	}
+ 	entry->hash = 0xffff;
+ 
+@@ -551,6 +598,9 @@ __mtk_foe_entry_commit(struct mtk_ppe *p
+ 	wmb();
+ 	hwe->ib1 = entry->ib1;
+ 
++	if (ppe->accounting)
++		*mtk_foe_entry_ib2(eth, hwe) |= MTK_FOE_IB2_MIB_CNT;
++
+ 	dma_wmb();
+ 
+ 	mtk_ppe_cache_clear(ppe);
+@@ -716,14 +766,42 @@ int mtk_foe_entry_idle_time(struct mtk_p
+ 	return __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
+ }
+ 
++struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
++						 struct mtk_foe_accounting *diff)
++{
++	struct mtk_foe_accounting *acct;
++	int size = sizeof(struct mtk_foe_accounting);
++	u64 bytes, packets;
++
++	if (!ppe->accounting)
++		return NULL;
++
++	if (mtk_mib_entry_read(ppe, index, &bytes, &packets))
++		return NULL;
++
++	acct = ppe->acct_table + index * size;
++
++	acct->bytes += bytes;
++	acct->packets += packets;
++
++	if (diff) {
++		diff->bytes = bytes;
++		diff->packets = packets;
++	}
++
++	return acct;
++}
++
+ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
+-			     int version, int index)
++			     int version, int index, bool accounting)
+ {
+ 	const struct mtk_soc_data *soc = eth->soc;
+ 	struct device *dev = eth->dev;
+ 	struct mtk_ppe *ppe;
+ 	u32 foe_flow_size;
+ 	void *foe;
++	struct mtk_mib_entry *mib;
++	struct mtk_foe_accounting *acct;
+ 
+ 	ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL);
+ 	if (!ppe)
+@@ -738,6 +816,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
+ 	ppe->eth = eth;
+ 	ppe->dev = dev;
+ 	ppe->version = version;
++	ppe->accounting = accounting;
+ 
+ 	foe = dmam_alloc_coherent(ppe->dev,
+ 				  MTK_PPE_ENTRIES * soc->foe_entry_size,
+@@ -753,6 +832,25 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
+ 	if (!ppe->foe_flow)
+ 		return NULL;
+ 
++	if (accounting) {
++		mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib),
++					  &ppe->mib_phys, GFP_KERNEL);
++		if (!mib)
++			return NULL;
++
++		memset(mib, 0, MTK_PPE_ENTRIES * sizeof(*mib));
++
++		ppe->mib_table = mib;
++
++		acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct),
++				    GFP_KERNEL);
++
++		if (!acct)
++			return NULL;
++
++		ppe->acct_table = acct;
++	}
++
+ 	mtk_ppe_debugfs_init(ppe, index);
+ 
+ 	return ppe;
+@@ -867,6 +965,16 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
+ 		ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777);
+ 		ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
+ 	}
++
++	if (ppe->accounting && ppe->mib_phys) {
++		ppe_w32(ppe, MTK_PPE_MIB_TB_BASE, ppe->mib_phys);
++		ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_EN,
++			MTK_PPE_MIB_CFG_EN);
++		ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_RD_CLR,
++			MTK_PPE_MIB_CFG_RD_CLR);
++		ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN,
++			MTK_PPE_MIB_CFG_RD_CLR);
++	}
+ }
+ 
+ int mtk_ppe_stop(struct mtk_ppe *ppe)
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -57,6 +57,7 @@ enum {
+ #define MTK_FOE_IB2_MULTICAST		BIT(8)
+ 
+ #define MTK_FOE_IB2_WDMA_QID2		GENMASK(13, 12)
++#define MTK_FOE_IB2_MIB_CNT		BIT(15)
+ #define MTK_FOE_IB2_WDMA_DEVIDX		BIT(16)
+ #define MTK_FOE_IB2_WDMA_WINFO		BIT(17)
+ 
+@@ -284,16 +285,34 @@ struct mtk_flow_entry {
+ 	unsigned long cookie;
+ };
+ 
++struct mtk_mib_entry {
++	u32	byt_cnt_l;
++	u16	byt_cnt_h;
++	u32	pkt_cnt_l;
++	u8	pkt_cnt_h;
++	u8	_rsv0;
++	u32	_rsv1;
++} __packed;
++
++struct mtk_foe_accounting {
++	u64	bytes;
++	u64	packets;
++};
++
+ struct mtk_ppe {
+ 	struct mtk_eth *eth;
+ 	struct device *dev;
+ 	void __iomem *base;
+ 	int version;
+ 	char dirname[5];
++	bool accounting;
+ 
+ 	void *foe_table;
+ 	dma_addr_t foe_phys;
+ 
++	struct mtk_mib_entry *mib_table;
++	dma_addr_t mib_phys;
++
+ 	u16 foe_check_time[MTK_PPE_ENTRIES];
+ 	struct hlist_head *foe_flow;
+ 
+@@ -303,7 +322,7 @@ struct mtk_ppe {
+ };
+ 
+ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
+-			     int version, int index);
++			     int version, int index, bool accounting);
+ void mtk_ppe_start(struct mtk_ppe *ppe);
+ int mtk_ppe_stop(struct mtk_ppe *ppe);
+ 
+@@ -354,5 +373,7 @@ int mtk_foe_entry_commit(struct mtk_ppe
+ void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index);
++struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
++						 struct mtk_foe_accounting *diff);
+ 
+ #endif
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+@@ -82,6 +82,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file
+ 		struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i);
+ 		struct mtk_foe_mac_info *l2;
+ 		struct mtk_flow_addr_info ai = {};
++		struct mtk_foe_accounting *acct;
+ 		unsigned char h_source[ETH_ALEN];
+ 		unsigned char h_dest[ETH_ALEN];
+ 		int type, state;
+@@ -95,6 +96,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file
+ 		if (bind && state != MTK_FOE_STATE_BIND)
+ 			continue;
+ 
++		acct = mtk_foe_entry_get_mib(ppe, i, NULL);
++
+ 		type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
+ 		seq_printf(m, "%05x %s %7s", i,
+ 			   mtk_foe_entry_state_str(state),
+@@ -153,9 +156,11 @@ mtk_ppe_debugfs_foe_show(struct seq_file
+ 		*((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
+ 
+ 		seq_printf(m, " eth=%pM->%pM etype=%04x"
+-			      " vlan=%d,%d ib1=%08x ib2=%08x\n",
++			      " vlan=%d,%d ib1=%08x ib2=%08x"
++			      " packets=%lld bytes=%lld\n",
+ 			   h_source, h_dest, ntohs(l2->etype),
+-			   l2->vlan1, l2->vlan2, entry->ib1, ib2);
++			   l2->vlan1, l2->vlan2, entry->ib1, ib2,
++			   acct->packets, acct->bytes);
+ 	}
+ 
+ 	return 0;
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -491,6 +491,7 @@ static int
+ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
+ {
+ 	struct mtk_flow_entry *entry;
++	struct mtk_foe_accounting diff;
+ 	u32 idle;
+ 
+ 	entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
+@@ -501,6 +502,12 @@ mtk_flow_offload_stats(struct mtk_eth *e
+ 	idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry);
+ 	f->stats.lastused = jiffies - idle * HZ;
+ 
++	if (entry->hash != 0xFFFF) {
++		mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash, &diff);
++		f->stats.pkts += diff.packets;
++		f->stats.bytes += diff.bytes;
++	}
++
+ 	return 0;
+ }
+ 
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+@@ -143,6 +143,20 @@ enum {
+ 
+ #define MTK_PPE_MIB_TB_BASE			0x338
+ 
++#define MTK_PPE_MIB_SER_CR			0x33C
++#define MTK_PPE_MIB_SER_CR_ST			BIT(16)
++#define MTK_PPE_MIB_SER_CR_ADDR			GENMASK(13, 0)
++
++#define MTK_PPE_MIB_SER_R0			0x340
++#define MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW		GENMASK(31, 0)
++
++#define MTK_PPE_MIB_SER_R1			0x344
++#define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW		GENMASK(31, 16)
++#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH	GENMASK(15, 0)
++
++#define MTK_PPE_MIB_SER_R2			0x348
++#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH		GENMASK(23, 0)
++
+ #define MTK_PPE_MIB_CACHE_CTL			0x350
+ #define MTK_PPE_MIB_CACHE_CTL_EN		BIT(0)
+ #define MTK_PPE_MIB_CACHE_CTL_FLUSH		BIT(2)




More information about the lede-commits mailing list