Skip to content

Commit 3fe15c6

Browse files
LorenzoBianconiPaolo Abeni
authored andcommitted
net: airoha: Introduce PPE debugfs support
Similar to PPE support for Mediatek devices, introduce PPE debugfs in order to dump binded and unbinded flows. Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 9cd451d commit 3fe15c6

File tree

4 files changed

+209
-4
lines changed

4 files changed

+209
-4
lines changed

drivers/net/ethernet/airoha/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55

66
obj-$(CONFIG_NET_AIROHA) += airoha-eth.o
77
airoha-eth-y := airoha_eth.o airoha_ppe.o
8+
airoha-eth-$(CONFIG_DEBUG_FS) += airoha_ppe_debugfs.o
89
obj-$(CONFIG_NET_AIROHA_NPU) += airoha_npu.o

drivers/net/ethernet/airoha/airoha_eth.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef AIROHA_ETH_H
88
#define AIROHA_ETH_H
99

10+
#include <linux/debugfs.h>
1011
#include <linux/etherdevice.h>
1112
#include <linux/iopoll.h>
1213
#include <linux/kernel.h>
@@ -480,6 +481,8 @@ struct airoha_ppe {
480481

481482
struct hlist_head *foe_flow;
482483
u16 foe_check_time[PPE_NUM_ENTRIES];
484+
485+
struct dentry *debugfs_dir;
483486
};
484487

485488
struct airoha_eth {
@@ -533,5 +536,16 @@ int airoha_ppe_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
533536
void *cb_priv);
534537
int airoha_ppe_init(struct airoha_eth *eth);
535538
void airoha_ppe_deinit(struct airoha_eth *eth);
539+
struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe,
540+
u32 hash);
541+
542+
#if CONFIG_DEBUG_FS
543+
int airoha_ppe_debugfs_init(struct airoha_ppe *ppe);
544+
#else
545+
static inline int airoha_ppe_debugfs_init(struct airoha_ppe *ppe)
546+
{
547+
return 0;
548+
}
549+
#endif
536550

537551
#endif /* AIROHA_ETH_H */

drivers/net/ethernet/airoha/airoha_ppe.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ static u32 airoha_ppe_foe_get_entry_hash(struct airoha_foe_entry *hwe)
390390
return hash;
391391
}
392392

393-
static struct airoha_foe_entry *
394-
airoha_ppe_foe_get_entry(struct airoha_ppe *ppe, u32 hash)
393+
struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe,
394+
u32 hash)
395395
{
396396
if (hash < PPE_SRAM_NUM_ENTRIES) {
397397
u32 *hwe = ppe->foe + hash * sizeof(struct airoha_foe_entry);
@@ -861,7 +861,7 @@ void airoha_ppe_check_skb(struct airoha_ppe *ppe, u16 hash)
861861
int airoha_ppe_init(struct airoha_eth *eth)
862862
{
863863
struct airoha_ppe *ppe;
864-
int foe_size;
864+
int foe_size, err;
865865

866866
ppe = devm_kzalloc(eth->dev, sizeof(*ppe), GFP_KERNEL);
867867
if (!ppe)
@@ -882,7 +882,15 @@ int airoha_ppe_init(struct airoha_eth *eth)
882882
if (!ppe->foe_flow)
883883
return -ENOMEM;
884884

885-
return rhashtable_init(&eth->flow_table, &airoha_flow_table_params);
885+
err = rhashtable_init(&eth->flow_table, &airoha_flow_table_params);
886+
if (err)
887+
return err;
888+
889+
err = airoha_ppe_debugfs_init(ppe);
890+
if (err)
891+
rhashtable_destroy(&eth->flow_table);
892+
893+
return err;
886894
}
887895

888896
void airoha_ppe_deinit(struct airoha_eth *eth)
@@ -898,4 +906,5 @@ void airoha_ppe_deinit(struct airoha_eth *eth)
898906
rcu_read_unlock();
899907

900908
rhashtable_destroy(&eth->flow_table);
909+
debugfs_remove(eth->ppe->debugfs_dir);
901910
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2025 AIROHA Inc
4+
* Author: Lorenzo Bianconi <[email protected]>
5+
*/
6+
7+
#include "airoha_eth.h"
8+
9+
static void airoha_debugfs_ppe_print_tuple(struct seq_file *m,
10+
void *src_addr, void *dest_addr,
11+
u16 *src_port, u16 *dest_port,
12+
bool ipv6)
13+
{
14+
__be32 n_addr[IPV6_ADDR_WORDS];
15+
16+
if (ipv6) {
17+
ipv6_addr_cpu_to_be32(n_addr, src_addr);
18+
seq_printf(m, "%pI6", n_addr);
19+
} else {
20+
seq_printf(m, "%pI4h", src_addr);
21+
}
22+
if (src_port)
23+
seq_printf(m, ":%d", *src_port);
24+
25+
seq_puts(m, "->");
26+
27+
if (ipv6) {
28+
ipv6_addr_cpu_to_be32(n_addr, dest_addr);
29+
seq_printf(m, "%pI6", n_addr);
30+
} else {
31+
seq_printf(m, "%pI4h", dest_addr);
32+
}
33+
if (dest_port)
34+
seq_printf(m, ":%d", *dest_port);
35+
}
36+
37+
static int airoha_ppe_debugfs_foe_show(struct seq_file *m, void *private,
38+
bool bind)
39+
{
40+
static const char *const ppe_type_str[] = {
41+
[PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
42+
[PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
43+
[PPE_PKT_TYPE_BRIDGE] = "L2B",
44+
[PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
45+
[PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
46+
[PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
47+
[PPE_PKT_TYPE_IPV6_6RD] = "6RD",
48+
};
49+
static const char *const ppe_state_str[] = {
50+
[AIROHA_FOE_STATE_INVALID] = "INV",
51+
[AIROHA_FOE_STATE_UNBIND] = "UNB",
52+
[AIROHA_FOE_STATE_BIND] = "BND",
53+
[AIROHA_FOE_STATE_FIN] = "FIN",
54+
};
55+
struct airoha_ppe *ppe = m->private;
56+
int i;
57+
58+
for (i = 0; i < PPE_NUM_ENTRIES; i++) {
59+
const char *state_str, *type_str = "UNKNOWN";
60+
void *src_addr = NULL, *dest_addr = NULL;
61+
u16 *src_port = NULL, *dest_port = NULL;
62+
struct airoha_foe_mac_info_common *l2;
63+
unsigned char h_source[ETH_ALEN] = {};
64+
unsigned char h_dest[ETH_ALEN];
65+
struct airoha_foe_entry *hwe;
66+
u32 type, state, ib2, data;
67+
bool ipv6 = false;
68+
69+
hwe = airoha_ppe_foe_get_entry(ppe, i);
70+
if (!hwe)
71+
continue;
72+
73+
state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, hwe->ib1);
74+
if (!state)
75+
continue;
76+
77+
if (bind && state != AIROHA_FOE_STATE_BIND)
78+
continue;
79+
80+
state_str = ppe_state_str[state % ARRAY_SIZE(ppe_state_str)];
81+
type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1);
82+
if (type < ARRAY_SIZE(ppe_type_str) && ppe_type_str[type])
83+
type_str = ppe_type_str[type];
84+
85+
seq_printf(m, "%05x %s %7s", i, state_str, type_str);
86+
87+
switch (type) {
88+
case PPE_PKT_TYPE_IPV4_HNAPT:
89+
case PPE_PKT_TYPE_IPV4_DSLITE:
90+
src_port = &hwe->ipv4.orig_tuple.src_port;
91+
dest_port = &hwe->ipv4.orig_tuple.dest_port;
92+
fallthrough;
93+
case PPE_PKT_TYPE_IPV4_ROUTE:
94+
src_addr = &hwe->ipv4.orig_tuple.src_ip;
95+
dest_addr = &hwe->ipv4.orig_tuple.dest_ip;
96+
break;
97+
case PPE_PKT_TYPE_IPV6_ROUTE_5T:
98+
src_port = &hwe->ipv6.src_port;
99+
dest_port = &hwe->ipv6.dest_port;
100+
fallthrough;
101+
case PPE_PKT_TYPE_IPV6_ROUTE_3T:
102+
case PPE_PKT_TYPE_IPV6_6RD:
103+
src_addr = &hwe->ipv6.src_ip;
104+
dest_addr = &hwe->ipv6.dest_ip;
105+
ipv6 = true;
106+
break;
107+
default:
108+
break;
109+
}
110+
111+
if (src_addr && dest_addr) {
112+
seq_puts(m, " orig=");
113+
airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr,
114+
src_port, dest_port, ipv6);
115+
}
116+
117+
switch (type) {
118+
case PPE_PKT_TYPE_IPV4_HNAPT:
119+
case PPE_PKT_TYPE_IPV4_DSLITE:
120+
src_port = &hwe->ipv4.new_tuple.src_port;
121+
dest_port = &hwe->ipv4.new_tuple.dest_port;
122+
fallthrough;
123+
case PPE_PKT_TYPE_IPV4_ROUTE:
124+
src_addr = &hwe->ipv4.new_tuple.src_ip;
125+
dest_addr = &hwe->ipv4.new_tuple.dest_ip;
126+
seq_puts(m, " new=");
127+
airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr,
128+
src_port, dest_port,
129+
ipv6);
130+
break;
131+
default:
132+
break;
133+
}
134+
135+
if (type >= PPE_PKT_TYPE_IPV6_ROUTE_3T) {
136+
data = hwe->ipv6.data;
137+
ib2 = hwe->ipv6.ib2;
138+
l2 = &hwe->ipv6.l2;
139+
} else {
140+
data = hwe->ipv4.data;
141+
ib2 = hwe->ipv4.ib2;
142+
l2 = &hwe->ipv4.l2.common;
143+
*((__be16 *)&h_source[4]) =
144+
cpu_to_be16(hwe->ipv4.l2.src_mac_lo);
145+
}
146+
147+
*((__be32 *)h_dest) = cpu_to_be32(l2->dest_mac_hi);
148+
*((__be16 *)&h_dest[4]) = cpu_to_be16(l2->dest_mac_lo);
149+
*((__be32 *)h_source) = cpu_to_be32(l2->src_mac_hi);
150+
151+
seq_printf(m, " eth=%pM->%pM etype=%04x data=%08x"
152+
" vlan=%d,%d ib1=%08x ib2=%08x\n",
153+
h_source, h_dest, l2->etype, data,
154+
l2->vlan1, l2->vlan2, hwe->ib1, ib2);
155+
}
156+
157+
return 0;
158+
}
159+
160+
static int airoha_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)
161+
{
162+
return airoha_ppe_debugfs_foe_show(m, private, false);
163+
}
164+
DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_all);
165+
166+
static int airoha_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private)
167+
{
168+
return airoha_ppe_debugfs_foe_show(m, private, true);
169+
}
170+
DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_bind);
171+
172+
int airoha_ppe_debugfs_init(struct airoha_ppe *ppe)
173+
{
174+
ppe->debugfs_dir = debugfs_create_dir("ppe", NULL);
175+
debugfs_create_file("entries", 0444, ppe->debugfs_dir, ppe,
176+
&airoha_ppe_debugfs_foe_all_fops);
177+
debugfs_create_file("bind", 0444, ppe->debugfs_dir, ppe,
178+
&airoha_ppe_debugfs_foe_bind_fops);
179+
180+
return 0;
181+
}

0 commit comments

Comments
 (0)