Skip to content

Commit 425eabd

Browse files
joabreudavem330
authored andcommitted
net: stmmac: Implement L3/L4 Filters using TC Flower
Implement filters for Layer 3 and Layer 4 using TC Flower API. Add the corresponding callbacks in XGMAC core. Signed-off-by: Jose Abreu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c104891 commit 425eabd

File tree

8 files changed

+488
-2
lines changed

8 files changed

+488
-2
lines changed

drivers/net/ethernet/stmicro/stmmac/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ struct dma_features {
360360
unsigned int sphen;
361361
unsigned int vlins;
362362
unsigned int dvlan;
363+
unsigned int l3l4fnum;
363364
};
364365

365366
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */

drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#define XGMAC_CORE_INIT_RX 0
4848
#define XGMAC_PACKET_FILTER 0x00000008
4949
#define XGMAC_FILTER_RA BIT(31)
50+
#define XGMAC_FILTER_IPFE BIT(20)
5051
#define XGMAC_FILTER_VTFE BIT(16)
5152
#define XGMAC_FILTER_HPF BIT(10)
5253
#define XGMAC_FILTER_PCF BIT(7)
@@ -119,6 +120,7 @@
119120
#define XGMAC_HWFEAT_VLHASH BIT(4)
120121
#define XGMAC_HWFEAT_GMIISEL BIT(1)
121122
#define XGMAC_HW_FEATURE1 0x00000120
123+
#define XGMAC_HWFEAT_L3L4FNUM GENMASK(30, 27)
122124
#define XGMAC_HWFEAT_RSSEN BIT(20)
123125
#define XGMAC_HWFEAT_TSOEN BIT(18)
124126
#define XGMAC_HWFEAT_SPHEN BIT(17)
@@ -150,6 +152,34 @@
150152
#define XGMAC_DCS GENMASK(19, 16)
151153
#define XGMAC_DCS_SHIFT 16
152154
#define XGMAC_ADDRx_LOW(x) (0x00000304 + (x) * 0x8)
155+
#define XGMAC_L3L4_ADDR_CTRL 0x00000c00
156+
#define XGMAC_IDDR GENMASK(15, 8)
157+
#define XGMAC_IDDR_SHIFT 8
158+
#define XGMAC_IDDR_FNUM 4
159+
#define XGMAC_TT BIT(1)
160+
#define XGMAC_XB BIT(0)
161+
#define XGMAC_L3L4_DATA 0x00000c04
162+
#define XGMAC_L3L4_CTRL 0x0
163+
#define XGMAC_L4DPIM0 BIT(21)
164+
#define XGMAC_L4DPM0 BIT(20)
165+
#define XGMAC_L4SPIM0 BIT(19)
166+
#define XGMAC_L4SPM0 BIT(18)
167+
#define XGMAC_L4PEN0 BIT(16)
168+
#define XGMAC_L3HDBM0 GENMASK(15, 11)
169+
#define XGMAC_L3HSBM0 GENMASK(10, 6)
170+
#define XGMAC_L3DAIM0 BIT(5)
171+
#define XGMAC_L3DAM0 BIT(4)
172+
#define XGMAC_L3SAIM0 BIT(3)
173+
#define XGMAC_L3SAM0 BIT(2)
174+
#define XGMAC_L3PEN0 BIT(0)
175+
#define XGMAC_L4_ADDR 0x1
176+
#define XGMAC_L4DP0 GENMASK(31, 16)
177+
#define XGMAC_L4DP0_SHIFT 16
178+
#define XGMAC_L4SP0 GENMASK(15, 0)
179+
#define XGMAC_L3_ADDR0 0x4
180+
#define XGMAC_L3_ADDR1 0x5
181+
#define XGMAC_L3_ADDR2 0x6
182+
#define XMGAC_L3_ADDR3 0x7
153183
#define XGMAC_ARP_ADDR 0x00000c10
154184
#define XGMAC_RSS_CTRL 0x00000c80
155185
#define XGMAC_UDP4TE BIT(3)

drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,181 @@ static void dwxgmac2_enable_vlan(struct mac_device_info *hw, u32 type)
11631163
writel(value, ioaddr + XGMAC_VLAN_INCL);
11641164
}
11651165

1166+
static int dwxgmac2_filter_wait(struct mac_device_info *hw)
1167+
{
1168+
void __iomem *ioaddr = hw->pcsr;
1169+
u32 value;
1170+
1171+
if (readl_poll_timeout(ioaddr + XGMAC_L3L4_ADDR_CTRL, value,
1172+
!(value & XGMAC_XB), 100, 10000))
1173+
return -EBUSY;
1174+
return 0;
1175+
}
1176+
1177+
static int dwxgmac2_filter_read(struct mac_device_info *hw, u32 filter_no,
1178+
u8 reg, u32 *data)
1179+
{
1180+
void __iomem *ioaddr = hw->pcsr;
1181+
u32 value;
1182+
int ret;
1183+
1184+
ret = dwxgmac2_filter_wait(hw);
1185+
if (ret)
1186+
return ret;
1187+
1188+
value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT;
1189+
value |= XGMAC_TT | XGMAC_XB;
1190+
writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL);
1191+
1192+
ret = dwxgmac2_filter_wait(hw);
1193+
if (ret)
1194+
return ret;
1195+
1196+
*data = readl(ioaddr + XGMAC_L3L4_DATA);
1197+
return 0;
1198+
}
1199+
1200+
static int dwxgmac2_filter_write(struct mac_device_info *hw, u32 filter_no,
1201+
u8 reg, u32 data)
1202+
{
1203+
void __iomem *ioaddr = hw->pcsr;
1204+
u32 value;
1205+
int ret;
1206+
1207+
ret = dwxgmac2_filter_wait(hw);
1208+
if (ret)
1209+
return ret;
1210+
1211+
writel(data, ioaddr + XGMAC_L3L4_DATA);
1212+
1213+
value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT;
1214+
value |= XGMAC_XB;
1215+
writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL);
1216+
1217+
return dwxgmac2_filter_wait(hw);
1218+
}
1219+
1220+
static int dwxgmac2_config_l3_filter(struct mac_device_info *hw, u32 filter_no,
1221+
bool en, bool ipv6, bool sa, bool inv,
1222+
u32 match)
1223+
{
1224+
void __iomem *ioaddr = hw->pcsr;
1225+
u32 value;
1226+
int ret;
1227+
1228+
value = readl(ioaddr + XGMAC_PACKET_FILTER);
1229+
value |= XGMAC_FILTER_IPFE;
1230+
writel(value, ioaddr + XGMAC_PACKET_FILTER);
1231+
1232+
ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L3L4_CTRL, &value);
1233+
if (ret)
1234+
return ret;
1235+
1236+
/* For IPv6 not both SA/DA filters can be active */
1237+
if (ipv6) {
1238+
value |= XGMAC_L3PEN0;
1239+
value &= ~(XGMAC_L3SAM0 | XGMAC_L3SAIM0);
1240+
value &= ~(XGMAC_L3DAM0 | XGMAC_L3DAIM0);
1241+
if (sa) {
1242+
value |= XGMAC_L3SAM0;
1243+
if (inv)
1244+
value |= XGMAC_L3SAIM0;
1245+
} else {
1246+
value |= XGMAC_L3DAM0;
1247+
if (inv)
1248+
value |= XGMAC_L3DAIM0;
1249+
}
1250+
} else {
1251+
value &= ~XGMAC_L3PEN0;
1252+
if (sa) {
1253+
value |= XGMAC_L3SAM0;
1254+
if (inv)
1255+
value |= XGMAC_L3SAIM0;
1256+
} else {
1257+
value |= XGMAC_L3DAM0;
1258+
if (inv)
1259+
value |= XGMAC_L3DAIM0;
1260+
}
1261+
}
1262+
1263+
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
1264+
if (ret)
1265+
return ret;
1266+
1267+
if (sa) {
1268+
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3_ADDR0, match);
1269+
if (ret)
1270+
return ret;
1271+
} else {
1272+
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3_ADDR1, match);
1273+
if (ret)
1274+
return ret;
1275+
}
1276+
1277+
if (!en)
1278+
return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);
1279+
1280+
return 0;
1281+
}
1282+
1283+
static int dwxgmac2_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
1284+
bool en, bool udp, bool sa, bool inv,
1285+
u32 match)
1286+
{
1287+
void __iomem *ioaddr = hw->pcsr;
1288+
u32 value;
1289+
int ret;
1290+
1291+
value = readl(ioaddr + XGMAC_PACKET_FILTER);
1292+
value |= XGMAC_FILTER_IPFE;
1293+
writel(value, ioaddr + XGMAC_PACKET_FILTER);
1294+
1295+
ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L3L4_CTRL, &value);
1296+
if (ret)
1297+
return ret;
1298+
1299+
if (udp) {
1300+
value |= XGMAC_L4PEN0;
1301+
} else {
1302+
value &= ~XGMAC_L4PEN0;
1303+
}
1304+
1305+
value &= ~(XGMAC_L4SPM0 | XGMAC_L4SPIM0);
1306+
value &= ~(XGMAC_L4DPM0 | XGMAC_L4DPIM0);
1307+
if (sa) {
1308+
value |= XGMAC_L4SPM0;
1309+
if (inv)
1310+
value |= XGMAC_L4SPIM0;
1311+
} else {
1312+
value |= XGMAC_L4DPM0;
1313+
if (inv)
1314+
value |= XGMAC_L4DPIM0;
1315+
}
1316+
1317+
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
1318+
if (ret)
1319+
return ret;
1320+
1321+
if (sa) {
1322+
value = match & XGMAC_L4SP0;
1323+
1324+
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
1325+
if (ret)
1326+
return ret;
1327+
} else {
1328+
value = (match << XGMAC_L4DP0_SHIFT) & XGMAC_L4DP0;
1329+
1330+
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
1331+
if (ret)
1332+
return ret;
1333+
}
1334+
1335+
if (!en)
1336+
return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);
1337+
1338+
return 0;
1339+
}
1340+
11661341
const struct stmmac_ops dwxgmac210_ops = {
11671342
.core_init = dwxgmac2_core_init,
11681343
.set_mac = dwxgmac2_set_mac,
@@ -1203,6 +1378,8 @@ const struct stmmac_ops dwxgmac210_ops = {
12031378
.flex_pps_config = dwxgmac2_flex_pps_config,
12041379
.sarc_configure = dwxgmac2_sarc_configure,
12051380
.enable_vlan = dwxgmac2_enable_vlan,
1381+
.config_l3_filter = dwxgmac2_config_l3_filter,
1382+
.config_l4_filter = dwxgmac2_config_l4_filter,
12061383
};
12071384

12081385
int dwxgmac2_setup(struct stmmac_priv *priv)

drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
378378

379379
/* MAC HW feature 1 */
380380
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
381+
dma_cap->l3l4fnum = (hw_cap & XGMAC_HWFEAT_L3L4FNUM) >> 27;
381382
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
382383
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
383384
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;

drivers/net/ethernet/stmicro/stmmac/hwif.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,13 @@ struct stmmac_ops {
363363
int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts);
364364
/* Source Address Insertion / Replacement */
365365
void (*sarc_configure)(void __iomem *ioaddr, int val);
366+
/* Filtering */
367+
int (*config_l3_filter)(struct mac_device_info *hw, u32 filter_no,
368+
bool en, bool ipv6, bool sa, bool inv,
369+
u32 match);
370+
int (*config_l4_filter)(struct mac_device_info *hw, u32 filter_no,
371+
bool en, bool udp, bool sa, bool inv,
372+
u32 match);
366373
};
367374

368375
#define stmmac_core_init(__priv, __args...) \
@@ -443,6 +450,10 @@ struct stmmac_ops {
443450
stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args)
444451
#define stmmac_sarc_configure(__priv, __args...) \
445452
stmmac_do_void_callback(__priv, mac, sarc_configure, __args)
453+
#define stmmac_config_l3_filter(__priv, __args...) \
454+
stmmac_do_callback(__priv, mac, config_l3_filter, __args)
455+
#define stmmac_config_l4_filter(__priv, __args...) \
456+
stmmac_do_callback(__priv, mac, config_l4_filter, __args)
446457

447458
/* PTP and HW Timer helpers */
448459
struct stmmac_hwtimestamp {
@@ -499,13 +510,16 @@ struct stmmac_mode_ops {
499510
struct stmmac_priv;
500511
struct tc_cls_u32_offload;
501512
struct tc_cbs_qopt_offload;
513+
struct flow_cls_offload;
502514

503515
struct stmmac_tc_ops {
504516
int (*init)(struct stmmac_priv *priv);
505517
int (*setup_cls_u32)(struct stmmac_priv *priv,
506518
struct tc_cls_u32_offload *cls);
507519
int (*setup_cbs)(struct stmmac_priv *priv,
508520
struct tc_cbs_qopt_offload *qopt);
521+
int (*setup_cls)(struct stmmac_priv *priv,
522+
struct flow_cls_offload *cls);
509523
};
510524

511525
#define stmmac_tc_init(__priv, __args...) \
@@ -514,6 +528,8 @@ struct stmmac_tc_ops {
514528
stmmac_do_callback(__priv, tc, setup_cls_u32, __args)
515529
#define stmmac_tc_setup_cbs(__priv, __args...) \
516530
stmmac_do_callback(__priv, tc, setup_cbs, __args)
531+
#define stmmac_tc_setup_cls(__priv, __args...) \
532+
stmmac_do_callback(__priv, tc, setup_cls, __args)
517533

518534
struct stmmac_counters;
519535

drivers/net/ethernet/stmicro/stmmac/stmmac.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ struct stmmac_rss {
128128
u32 table[STMMAC_RSS_MAX_TABLE_SIZE];
129129
};
130130

131+
#define STMMAC_FLOW_ACTION_DROP BIT(0)
132+
struct stmmac_flow_entry {
133+
unsigned long cookie;
134+
unsigned long action;
135+
u8 ip_proto;
136+
int in_use;
137+
int idx;
138+
int is_l4;
139+
};
140+
131141
struct stmmac_priv {
132142
/* Frequently used values are kept adjacent for cache effect */
133143
u32 tx_coal_frames;
@@ -216,6 +226,8 @@ struct stmmac_priv {
216226
unsigned int tc_entries_max;
217227
unsigned int tc_off_max;
218228
struct stmmac_tc_entry *tc_entries;
229+
unsigned int flow_entries_max;
230+
struct stmmac_flow_entry *flow_entries;
219231

220232
/* Pulse Per Second output */
221233
struct stmmac_pps_cfg pps[STMMAC_PPS_MAX];

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3931,12 +3931,17 @@ static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
39313931
struct stmmac_priv *priv = cb_priv;
39323932
int ret = -EOPNOTSUPP;
39333933

3934+
if (!tc_cls_can_offload_and_chain0(priv->dev, type_data))
3935+
return ret;
3936+
39343937
stmmac_disable_all_queues(priv);
39353938

39363939
switch (type) {
39373940
case TC_SETUP_CLSU32:
3938-
if (tc_cls_can_offload_and_chain0(priv->dev, type_data))
3939-
ret = stmmac_tc_setup_cls_u32(priv, priv, type_data);
3941+
ret = stmmac_tc_setup_cls_u32(priv, priv, type_data);
3942+
break;
3943+
case TC_SETUP_CLSFLOWER:
3944+
ret = stmmac_tc_setup_cls(priv, priv, type_data);
39403945
break;
39413946
default:
39423947
break;

0 commit comments

Comments
 (0)