1 From patchwork Wed Nov 2 00:58:01 2022
2 Content-Type: text/plain; charset="utf-8"
4 Content-Transfer-Encoding: 7bit
5 X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
6 X-Patchwork-Id: 13027653
7 X-Patchwork-Delegate: kuba@kernel.org
8 Return-Path: <netdev-owner@kernel.org>
9 Date: Wed, 2 Nov 2022 00:58:01 +0000
10 From: Daniel Golle <daniel@makrotopia.org>
11 To: Felix Fietkau <nbd@nbd.name>, John Crispin <john@phrozen.org>,
12 Sean Wang <sean.wang@mediatek.com>,
13 Mark Lee <Mark-MC.Lee@mediatek.com>,
14 "David S. Miller" <davem@davemloft.net>,
15 Eric Dumazet <edumazet@google.com>,
16 Jakub Kicinski <kuba@kernel.org>,
17 Paolo Abeni <pabeni@redhat.com>,
18 Matthias Brugger <matthias.bgg@gmail.com>,
19 netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
20 linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org
21 Subject: [PATCH v4] net: ethernet: mediatek: ppe: add support for flow
23 Message-ID: <Y2HAmYYPd77dz+K5@makrotopia.org>
25 Content-Disposition: inline
27 List-ID: <netdev.vger.kernel.org>
28 X-Mailing-List: netdev@vger.kernel.org
29 X-Patchwork-Delegate: kuba@kernel.org
31 The PPE units found in MT7622 and newer support packet and byte
32 accounting of hw-offloaded flows. Add support for reading those
33 counters as found in MediaTek's SDK[1].
35 [1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/bc6a6a375c800dc2b80e1a325a2c732d1737df92
36 Signed-off-by: Daniel Golle <daniel@makrotopia.org>
38 v4: declare function mtk_mib_entry_read as static
39 v3: don't bother to set 'false' values in any zero-initialized struct
41 both changes were requested by Felix Fietkau
43 v2: fix wrong variable name in return value check spotted by Denis Kirjanov
45 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +-
46 drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
47 drivers/net/ethernet/mediatek/mtk_ppe.c | 110 +++++++++++++++++-
48 drivers/net/ethernet/mediatek/mtk_ppe.h | 23 +++-
49 .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 9 +-
50 .../net/ethernet/mediatek/mtk_ppe_offload.c | 7 ++
51 drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 14 +++
52 7 files changed, 166 insertions(+), 5 deletions(-)
54 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
55 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
56 @@ -4320,7 +4320,9 @@ static int mtk_probe(struct platform_dev
57 u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400;
59 eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr,
60 - eth->soc->offload_version, i);
61 + eth->soc->offload_version, i,
62 + eth->soc->has_accounting);
67 @@ -4445,6 +4447,7 @@ static const struct mtk_soc_data mt7622_
68 .required_pctl = false,
71 + .has_accounting = true,
72 .foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
74 .txd_size = sizeof(struct mtk_tx_dma),
75 @@ -4482,6 +4485,7 @@ static const struct mtk_soc_data mt7629_
76 .hw_features = MTK_HW_FEATURES,
77 .required_clks = MT7629_CLKS_BITMAP,
78 .required_pctl = false,
79 + .has_accounting = true,
81 .txd_size = sizeof(struct mtk_tx_dma),
82 .rxd_size = sizeof(struct mtk_rx_dma),
83 @@ -4502,6 +4506,7 @@ static const struct mtk_soc_data mt7986_
86 .foe_entry_size = sizeof(struct mtk_foe_entry),
87 + .has_accounting = true,
89 .txd_size = sizeof(struct mtk_tx_dma_v2),
90 .rxd_size = sizeof(struct mtk_rx_dma_v2),
91 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
92 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
93 @@ -1007,6 +1007,7 @@ struct mtk_soc_data {
96 netdev_features_t hw_features;
97 + bool has_accounting;
101 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
102 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
103 @@ -74,6 +74,46 @@ static int mtk_ppe_wait_busy(struct mtk_
107 +static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe)
112 + ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val,
113 + !(val & MTK_PPE_MIB_SER_CR_ST),
114 + 20, MTK_PPE_WAIT_TIMEOUT_US);
117 + dev_err(ppe->dev, "MIB table busy");
122 +static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
124 + u32 val, cnt_r0, cnt_r1, cnt_r2;
125 + u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high;
127 + val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST;
128 + ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val);
130 + if (mtk_ppe_mib_wait_busy(ppe))
133 + cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0);
134 + cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1);
135 + cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2);
137 + byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
138 + byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
139 + pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
140 + pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
141 + *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
142 + *packets = (pkt_cnt_high << 16) | pkt_cnt_low;
147 static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
149 ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
150 @@ -444,6 +484,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp
151 hwe->ib1 &= ~MTK_FOE_IB1_STATE;
152 hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID);
154 + if (ppe->accounting) {
155 + struct mtk_foe_accounting *acct;
157 + acct = ppe->acct_table + entry->hash * sizeof(*acct);
162 entry->hash = 0xffff;
164 @@ -551,6 +598,9 @@ __mtk_foe_entry_commit(struct mtk_ppe *p
166 hwe->ib1 = entry->ib1;
168 + if (ppe->accounting)
169 + *mtk_foe_entry_ib2(eth, hwe) |= MTK_FOE_IB2_MIB_CNT;
173 mtk_ppe_cache_clear(ppe);
174 @@ -743,14 +793,42 @@ int mtk_ppe_prepare_reset(struct mtk_ppe
175 return mtk_ppe_wait_busy(ppe);
178 +struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
179 + struct mtk_foe_accounting *diff)
181 + struct mtk_foe_accounting *acct;
182 + int size = sizeof(struct mtk_foe_accounting);
183 + u64 bytes, packets;
185 + if (!ppe->accounting)
188 + if (mtk_mib_entry_read(ppe, index, &bytes, &packets))
191 + acct = ppe->acct_table + index * size;
193 + acct->bytes += bytes;
194 + acct->packets += packets;
197 + diff->bytes = bytes;
198 + diff->packets = packets;
204 struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
205 - int version, int index)
206 + int version, int index, bool accounting)
208 const struct mtk_soc_data *soc = eth->soc;
209 struct device *dev = eth->dev;
213 + struct mtk_mib_entry *mib;
214 + struct mtk_foe_accounting *acct;
216 ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL);
218 @@ -765,6 +843,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
221 ppe->version = version;
222 + ppe->accounting = accounting;
224 foe = dmam_alloc_coherent(ppe->dev,
225 MTK_PPE_ENTRIES * soc->foe_entry_size,
226 @@ -780,6 +859,25 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
231 + mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib),
232 + &ppe->mib_phys, GFP_KERNEL);
236 + memset(mib, 0, MTK_PPE_ENTRIES * sizeof(*mib));
238 + ppe->mib_table = mib;
240 + acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct),
246 + ppe->acct_table = acct;
249 mtk_ppe_debugfs_init(ppe, index);
252 @@ -894,6 +992,16 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
253 ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777);
254 ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
257 + if (ppe->accounting && ppe->mib_phys) {
258 + ppe_w32(ppe, MTK_PPE_MIB_TB_BASE, ppe->mib_phys);
259 + ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_EN,
260 + MTK_PPE_MIB_CFG_EN);
261 + ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_RD_CLR,
262 + MTK_PPE_MIB_CFG_RD_CLR);
263 + ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN,
264 + MTK_PPE_MIB_CFG_RD_CLR);
268 int mtk_ppe_stop(struct mtk_ppe *ppe)
269 --- a/drivers/net/ethernet/mediatek/mtk_ppe.h
270 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
271 @@ -57,6 +57,7 @@ enum {
272 #define MTK_FOE_IB2_MULTICAST BIT(8)
274 #define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12)
275 +#define MTK_FOE_IB2_MIB_CNT BIT(15)
276 #define MTK_FOE_IB2_WDMA_DEVIDX BIT(16)
277 #define MTK_FOE_IB2_WDMA_WINFO BIT(17)
279 @@ -284,16 +285,34 @@ struct mtk_flow_entry {
280 unsigned long cookie;
283 +struct mtk_mib_entry {
292 +struct mtk_foe_accounting {
308 + struct mtk_mib_entry *mib_table;
309 + dma_addr_t mib_phys;
311 u16 foe_check_time[MTK_PPE_ENTRIES];
312 struct hlist_head *foe_flow;
314 @@ -303,7 +322,7 @@ struct mtk_ppe {
317 struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
318 - int version, int index);
319 + int version, int index, bool accounting);
320 void mtk_ppe_start(struct mtk_ppe *ppe);
321 int mtk_ppe_stop(struct mtk_ppe *ppe);
322 int mtk_ppe_prepare_reset(struct mtk_ppe *ppe);
323 @@ -355,5 +374,7 @@ int mtk_foe_entry_commit(struct mtk_ppe
324 void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
325 int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
326 int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index);
327 +struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
328 + struct mtk_foe_accounting *diff);
331 --- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
332 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
333 @@ -82,6 +82,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file
334 struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i);
335 struct mtk_foe_mac_info *l2;
336 struct mtk_flow_addr_info ai = {};
337 + struct mtk_foe_accounting *acct;
338 unsigned char h_source[ETH_ALEN];
339 unsigned char h_dest[ETH_ALEN];
341 @@ -95,6 +96,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file
342 if (bind && state != MTK_FOE_STATE_BIND)
345 + acct = mtk_foe_entry_get_mib(ppe, i, NULL);
347 type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
348 seq_printf(m, "%05x %s %7s", i,
349 mtk_foe_entry_state_str(state),
350 @@ -153,9 +156,11 @@ mtk_ppe_debugfs_foe_show(struct seq_file
351 *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
353 seq_printf(m, " eth=%pM->%pM etype=%04x"
354 - " vlan=%d,%d ib1=%08x ib2=%08x\n",
355 + " vlan=%d,%d ib1=%08x ib2=%08x"
356 + " packets=%lld bytes=%lld\n",
357 h_source, h_dest, ntohs(l2->etype),
358 - l2->vlan1, l2->vlan2, entry->ib1, ib2);
359 + l2->vlan1, l2->vlan2, entry->ib1, ib2,
360 + acct ? acct->packets : 0, acct ? acct->bytes : 0);
364 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
365 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
366 @@ -491,6 +491,7 @@ static int
367 mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
369 struct mtk_flow_entry *entry;
370 + struct mtk_foe_accounting diff;
373 entry = rhashtable_lookup(ð->flow_table, &f->cookie,
374 @@ -501,6 +502,12 @@ mtk_flow_offload_stats(struct mtk_eth *e
375 idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry);
376 f->stats.lastused = jiffies - idle * HZ;
378 + if (entry->hash != 0xFFFF) {
379 + mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash, &diff);
380 + f->stats.pkts += diff.packets;
381 + f->stats.bytes += diff.bytes;
387 --- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
388 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
389 @@ -149,6 +149,20 @@ enum {
391 #define MTK_PPE_MIB_TB_BASE 0x338
393 +#define MTK_PPE_MIB_SER_CR 0x33C
394 +#define MTK_PPE_MIB_SER_CR_ST BIT(16)
395 +#define MTK_PPE_MIB_SER_CR_ADDR GENMASK(13, 0)
397 +#define MTK_PPE_MIB_SER_R0 0x340
398 +#define MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW GENMASK(31, 0)
400 +#define MTK_PPE_MIB_SER_R1 0x344
401 +#define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW GENMASK(31, 16)
402 +#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH GENMASK(15, 0)
404 +#define MTK_PPE_MIB_SER_R2 0x348
405 +#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH GENMASK(23, 0)
407 #define MTK_PPE_MIB_CACHE_CTL 0x350
408 #define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
409 #define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)