Skip to content

Commit b9a5cbf

Browse files
committed
Merge branch 'sfc-tc-offload'
Edward Cree says: ==================== sfc: bare bones TC offload This series begins the work of supporting TC flower offload on EF100 NICs. This is the absolute minimum viable TC implementation to get traffic to VFs and allow them to be tested; it supports no match fields besides ingress port, no actions besides mirred and drop, and no stats. More matches, actions, and counters will be added in subsequent patches. Changed in v2: - Add missing 'static' on declarations (kernel test robot, sparse) ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents c87e4ad + d902e1a commit b9a5cbf

File tree

16 files changed

+980
-3
lines changed

16 files changed

+980
-3
lines changed

drivers/net/ethernet/sfc/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \
99
ef100_ethtool.o ef100_rx.o ef100_tx.o
1010
sfc-$(CONFIG_SFC_MTD) += mtd.o
1111
sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
12-
mae.o tc.o
12+
mae.o tc.o tc_bindings.o
1313

1414
obj-$(CONFIG_SFC) += sfc.o
1515

drivers/net/ethernet/sfc/ef100_ethtool.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const struct ethtool_ops ef100_ethtool_ops = {
4343
.get_pauseparam = efx_ethtool_get_pauseparam,
4444
.set_pauseparam = efx_ethtool_set_pauseparam,
4545
.get_sset_count = efx_ethtool_get_sset_count,
46+
.get_priv_flags = efx_ethtool_get_priv_flags,
47+
.set_priv_flags = efx_ethtool_set_priv_flags,
4648
.self_test = efx_ethtool_self_test,
4749
.get_strings = efx_ethtool_get_strings,
4850
.get_link_ksettings = efx_ethtool_get_link_ksettings,

drivers/net/ethernet/sfc/ef100_netdev.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "mcdi_filters.h"
2424
#include "rx_common.h"
2525
#include "ef100_sriov.h"
26+
#include "tc_bindings.h"
2627

2728
static void ef100_update_name(struct efx_nic *efx)
2829
{
@@ -246,6 +247,9 @@ static const struct net_device_ops ef100_netdev_ops = {
246247
#ifdef CONFIG_RFS_ACCEL
247248
.ndo_rx_flow_steer = efx_filter_rfs,
248249
#endif
250+
#ifdef CONFIG_SFC_SRIOV
251+
.ndo_setup_tc = efx_tc_setup,
252+
#endif
249253
};
250254

251255
/* Netdev registration

drivers/net/ethernet/sfc/ef100_nic.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,9 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
11371137
*/
11381138
netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n",
11391139
rc);
1140+
} else {
1141+
net_dev->features |= NETIF_F_HW_TC;
1142+
efx->fixed_features |= NETIF_F_HW_TC;
11401143
}
11411144
#endif
11421145
return 0;

drivers/net/ethernet/sfc/ef100_rep.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "ef100_nic.h"
1515
#include "mae.h"
1616
#include "rx_common.h"
17+
#include "tc_bindings.h"
1718

1819
#define EFX_EF100_REP_DRIVER "efx_ef100_rep"
1920

@@ -107,6 +108,20 @@ static int efx_ef100_rep_get_phys_port_name(struct net_device *dev,
107108
return 0;
108109
}
109110

111+
static int efx_ef100_rep_setup_tc(struct net_device *net_dev,
112+
enum tc_setup_type type, void *type_data)
113+
{
114+
struct efx_rep *efv = netdev_priv(net_dev);
115+
struct efx_nic *efx = efv->parent;
116+
117+
if (type == TC_SETUP_CLSFLOWER)
118+
return efx_tc_flower(efx, net_dev, type_data, efv);
119+
if (type == TC_SETUP_BLOCK)
120+
return efx_tc_setup_block(net_dev, efx, type_data, efv);
121+
122+
return -EOPNOTSUPP;
123+
}
124+
110125
static void efx_ef100_rep_get_stats64(struct net_device *dev,
111126
struct rtnl_link_stats64 *stats)
112127
{
@@ -120,13 +135,14 @@ static void efx_ef100_rep_get_stats64(struct net_device *dev,
120135
stats->tx_errors = atomic64_read(&efv->stats.tx_errors);
121136
}
122137

123-
static const struct net_device_ops efx_ef100_rep_netdev_ops = {
138+
const struct net_device_ops efx_ef100_rep_netdev_ops = {
124139
.ndo_open = efx_ef100_rep_open,
125140
.ndo_stop = efx_ef100_rep_close,
126141
.ndo_start_xmit = efx_ef100_rep_xmit,
127142
.ndo_get_port_parent_id = efx_ef100_rep_get_port_parent_id,
128143
.ndo_get_phys_port_name = efx_ef100_rep_get_phys_port_name,
129144
.ndo_get_stats64 = efx_ef100_rep_get_stats64,
145+
.ndo_setup_tc = efx_ef100_rep_setup_tc,
130146
};
131147

132148
static void efx_ef100_rep_get_drvinfo(struct net_device *dev,

drivers/net/ethernet/sfc/ef100_rep.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,5 @@ void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf);
6666
* Caller must hold rcu_read_lock().
6767
*/
6868
struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
69+
extern const struct net_device_ops efx_ef100_rep_netdev_ops;
6970
#endif /* EF100_REP_H */

drivers/net/ethernet/sfc/ethtool_common.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = {
101101

102102
#define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc)
103103

104+
static const char efx_ethtool_priv_flags_strings[][ETH_GSTRING_LEN] = {
105+
"log-tc-errors",
106+
};
107+
108+
#define EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS BIT(0)
109+
110+
#define EFX_ETHTOOL_PRIV_FLAGS_COUNT ARRAY_SIZE(efx_ethtool_priv_flags_strings)
111+
104112
void efx_ethtool_get_drvinfo(struct net_device *net_dev,
105113
struct ethtool_drvinfo *info)
106114
{
@@ -452,6 +460,8 @@ int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set)
452460
efx_ptp_describe_stats(efx, NULL);
453461
case ETH_SS_TEST:
454462
return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
463+
case ETH_SS_PRIV_FLAGS:
464+
return EFX_ETHTOOL_PRIV_FLAGS_COUNT;
455465
default:
456466
return -EINVAL;
457467
}
@@ -478,12 +488,39 @@ void efx_ethtool_get_strings(struct net_device *net_dev,
478488
case ETH_SS_TEST:
479489
efx_ethtool_fill_self_tests(efx, NULL, strings, NULL);
480490
break;
491+
case ETH_SS_PRIV_FLAGS:
492+
for (i = 0; i < EFX_ETHTOOL_PRIV_FLAGS_COUNT; i++)
493+
strscpy(strings + i * ETH_GSTRING_LEN,
494+
efx_ethtool_priv_flags_strings[i],
495+
ETH_GSTRING_LEN);
496+
break;
481497
default:
482498
/* No other string sets */
483499
break;
484500
}
485501
}
486502

503+
u32 efx_ethtool_get_priv_flags(struct net_device *net_dev)
504+
{
505+
struct efx_nic *efx = efx_netdev_priv(net_dev);
506+
u32 ret_flags = 0;
507+
508+
if (efx->log_tc_errs)
509+
ret_flags |= EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS;
510+
511+
return ret_flags;
512+
}
513+
514+
int efx_ethtool_set_priv_flags(struct net_device *net_dev, u32 flags)
515+
{
516+
struct efx_nic *efx = efx_netdev_priv(net_dev);
517+
518+
efx->log_tc_errs =
519+
!!(flags & EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS);
520+
521+
return 0;
522+
}
523+
487524
void efx_ethtool_get_stats(struct net_device *net_dev,
488525
struct ethtool_stats *stats,
489526
u64 *data)

drivers/net/ethernet/sfc/ethtool_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ int efx_ethtool_fill_self_tests(struct efx_nic *efx,
2727
int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set);
2828
void efx_ethtool_get_strings(struct net_device *net_dev, u32 string_set,
2929
u8 *strings);
30+
u32 efx_ethtool_get_priv_flags(struct net_device *net_dev);
31+
int efx_ethtool_set_priv_flags(struct net_device *net_dev, u32 flags);
3032
void efx_ethtool_get_stats(struct net_device *net_dev,
3133
struct ethtool_stats *stats __attribute__ ((unused)),
3234
u64 *data);

drivers/net/ethernet/sfc/mae.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,167 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
112112
return 0;
113113
}
114114

115+
static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
116+
{
117+
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
118+
size_t outlen;
119+
int rc;
120+
121+
BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN);
122+
123+
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_GET_CAPS, NULL, 0, outbuf,
124+
sizeof(outbuf), &outlen);
125+
if (rc)
126+
return rc;
127+
if (outlen < sizeof(outbuf))
128+
return -EIO;
129+
caps->match_field_count = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
130+
caps->action_prios = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ACTION_PRIOS);
131+
return 0;
132+
}
133+
134+
static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd,
135+
u8 *field_support)
136+
{
137+
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
138+
MCDI_DECLARE_STRUCT_PTR(caps);
139+
unsigned int count;
140+
size_t outlen;
141+
int rc, i;
142+
143+
BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN);
144+
145+
rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen);
146+
if (rc)
147+
return rc;
148+
count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT);
149+
memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS);
150+
caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS);
151+
/* We're only interested in the support status enum, not any other
152+
* flags, so just extract that from each entry.
153+
*/
154+
for (i = 0; i < count; i++)
155+
if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen)
156+
field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS);
157+
return 0;
158+
}
159+
160+
int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps)
161+
{
162+
int rc;
163+
164+
rc = efx_mae_get_basic_caps(efx, caps);
165+
if (rc)
166+
return rc;
167+
return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS,
168+
caps->action_rule_fields);
169+
}
170+
171+
/* Bit twiddling:
172+
* Prefix: 1...110...0
173+
* ~: 0...001...1
174+
* + 1: 0...010...0 is power of two
175+
* so (~x) & ((~x) + 1) == 0. Converse holds also.
176+
*/
177+
#define is_prefix_byte(_x) !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1))
178+
179+
enum mask_type { MASK_ONES, MASK_ZEROES, MASK_PREFIX, MASK_OTHER };
180+
181+
static const char *mask_type_name(enum mask_type typ)
182+
{
183+
switch (typ) {
184+
case MASK_ONES:
185+
return "all-1s";
186+
case MASK_ZEROES:
187+
return "all-0s";
188+
case MASK_PREFIX:
189+
return "prefix";
190+
case MASK_OTHER:
191+
return "arbitrary";
192+
default: /* can't happen */
193+
return "unknown";
194+
}
195+
}
196+
197+
/* Checks a (big-endian) bytestring is a bit prefix */
198+
static enum mask_type classify_mask(const u8 *mask, size_t len)
199+
{
200+
bool zeroes = true; /* All bits seen so far are zeroes */
201+
bool ones = true; /* All bits seen so far are ones */
202+
bool prefix = true; /* Valid prefix so far */
203+
size_t i;
204+
205+
for (i = 0; i < len; i++) {
206+
if (ones) {
207+
if (!is_prefix_byte(mask[i]))
208+
prefix = false;
209+
} else if (mask[i]) {
210+
prefix = false;
211+
}
212+
if (mask[i] != 0xff)
213+
ones = false;
214+
if (mask[i])
215+
zeroes = false;
216+
}
217+
if (ones)
218+
return MASK_ONES;
219+
if (zeroes)
220+
return MASK_ZEROES;
221+
if (prefix)
222+
return MASK_PREFIX;
223+
return MASK_OTHER;
224+
}
225+
226+
static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ)
227+
{
228+
switch (support) {
229+
case MAE_FIELD_UNSUPPORTED:
230+
case MAE_FIELD_SUPPORTED_MATCH_NEVER:
231+
if (typ == MASK_ZEROES)
232+
return 0;
233+
return -EOPNOTSUPP;
234+
case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
235+
if (typ == MASK_ZEROES)
236+
return 0;
237+
fallthrough;
238+
case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
239+
if (typ == MASK_ONES)
240+
return 0;
241+
return -EINVAL;
242+
case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
243+
if (typ == MASK_OTHER)
244+
return -EOPNOTSUPP;
245+
return 0;
246+
case MAE_FIELD_SUPPORTED_MATCH_MASK:
247+
return 0;
248+
default:
249+
return -EIO;
250+
}
251+
}
252+
253+
int efx_mae_match_check_caps(struct efx_nic *efx,
254+
const struct efx_tc_match_fields *mask,
255+
struct netlink_ext_ack *extack)
256+
{
257+
const u8 *supported_fields = efx->tc->caps->action_rule_fields;
258+
__be32 ingress_port = cpu_to_be32(mask->ingress_port);
259+
enum mask_type ingress_port_mask_type;
260+
int rc;
261+
262+
/* Check for _PREFIX assumes big-endian, so we need to convert */
263+
ingress_port_mask_type = classify_mask((const u8 *)&ingress_port,
264+
sizeof(ingress_port));
265+
rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT],
266+
ingress_port_mask_type);
267+
if (rc) {
268+
efx_tc_err(efx, "No support for %s mask in field ingress_port\n",
269+
mask_type_name(ingress_port_mask_type));
270+
NL_SET_ERR_MSG_MOD(extack, "Unsupported mask type for ingress_port");
271+
return rc;
272+
}
273+
return 0;
274+
}
275+
115276
static bool efx_mae_asl_id(u32 id)
116277
{
117278
return !!(id & BIT(31));
@@ -279,6 +440,10 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
279440
}
280441
MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK,
281442
match->mask.ingress_port);
443+
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID,
444+
match->value.recirc_id);
445+
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK,
446+
match->mask.recirc_id);
282447
return 0;
283448
}
284449

drivers/net/ethernet/sfc/mae.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@ void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
2727

2828
int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
2929

30+
#define MAE_NUM_FIELDS (MAE_FIELD_ENC_VNET_ID + 1)
31+
32+
struct mae_caps {
33+
u32 match_field_count;
34+
u32 action_prios;
35+
u8 action_rule_fields[MAE_NUM_FIELDS];
36+
};
37+
38+
int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps);
39+
40+
int efx_mae_match_check_caps(struct efx_nic *efx,
41+
const struct efx_tc_match_fields *mask,
42+
struct netlink_ext_ack *extack);
43+
3044
int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act);
3145
int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id);
3246

0 commit comments

Comments
 (0)