Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <davem@davemloft.net>

+980 -3
+1 -1
drivers/net/ethernet/sfc/Makefile
··· 9 9 ef100_ethtool.o ef100_rx.o ef100_tx.o 10 10 sfc-$(CONFIG_SFC_MTD) += mtd.o 11 11 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 13 13 14 14 obj-$(CONFIG_SFC) += sfc.o 15 15
+2
drivers/net/ethernet/sfc/ef100_ethtool.c
··· 43 43 .get_pauseparam = efx_ethtool_get_pauseparam, 44 44 .set_pauseparam = efx_ethtool_set_pauseparam, 45 45 .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, 46 48 .self_test = efx_ethtool_self_test, 47 49 .get_strings = efx_ethtool_get_strings, 48 50 .get_link_ksettings = efx_ethtool_get_link_ksettings,
+4
drivers/net/ethernet/sfc/ef100_netdev.c
··· 23 23 #include "mcdi_filters.h" 24 24 #include "rx_common.h" 25 25 #include "ef100_sriov.h" 26 + #include "tc_bindings.h" 26 27 27 28 static void ef100_update_name(struct efx_nic *efx) 28 29 { ··· 246 245 .ndo_get_phys_port_name = efx_get_phys_port_name, 247 246 #ifdef CONFIG_RFS_ACCEL 248 247 .ndo_rx_flow_steer = efx_filter_rfs, 248 + #endif 249 + #ifdef CONFIG_SFC_SRIOV 250 + .ndo_setup_tc = efx_tc_setup, 249 251 #endif 250 252 }; 251 253
+3
drivers/net/ethernet/sfc/ef100_nic.c
··· 1137 1137 */ 1138 1138 netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n", 1139 1139 rc); 1140 + } else { 1141 + net_dev->features |= NETIF_F_HW_TC; 1142 + efx->fixed_features |= NETIF_F_HW_TC; 1140 1143 } 1141 1144 #endif 1142 1145 return 0;
+17 -1
drivers/net/ethernet/sfc/ef100_rep.c
··· 14 14 #include "ef100_nic.h" 15 15 #include "mae.h" 16 16 #include "rx_common.h" 17 + #include "tc_bindings.h" 17 18 18 19 #define EFX_EF100_REP_DRIVER "efx_ef100_rep" 19 20 ··· 108 107 return 0; 109 108 } 110 109 110 + static int efx_ef100_rep_setup_tc(struct net_device *net_dev, 111 + enum tc_setup_type type, void *type_data) 112 + { 113 + struct efx_rep *efv = netdev_priv(net_dev); 114 + struct efx_nic *efx = efv->parent; 115 + 116 + if (type == TC_SETUP_CLSFLOWER) 117 + return efx_tc_flower(efx, net_dev, type_data, efv); 118 + if (type == TC_SETUP_BLOCK) 119 + return efx_tc_setup_block(net_dev, efx, type_data, efv); 120 + 121 + return -EOPNOTSUPP; 122 + } 123 + 111 124 static void efx_ef100_rep_get_stats64(struct net_device *dev, 112 125 struct rtnl_link_stats64 *stats) 113 126 { ··· 135 120 stats->tx_errors = atomic64_read(&efv->stats.tx_errors); 136 121 } 137 122 138 - static const struct net_device_ops efx_ef100_rep_netdev_ops = { 123 + const struct net_device_ops efx_ef100_rep_netdev_ops = { 139 124 .ndo_open = efx_ef100_rep_open, 140 125 .ndo_stop = efx_ef100_rep_close, 141 126 .ndo_start_xmit = efx_ef100_rep_xmit, 142 127 .ndo_get_port_parent_id = efx_ef100_rep_get_port_parent_id, 143 128 .ndo_get_phys_port_name = efx_ef100_rep_get_phys_port_name, 144 129 .ndo_get_stats64 = efx_ef100_rep_get_stats64, 130 + .ndo_setup_tc = efx_ef100_rep_setup_tc, 145 131 }; 146 132 147 133 static void efx_ef100_rep_get_drvinfo(struct net_device *dev,
+1
drivers/net/ethernet/sfc/ef100_rep.h
··· 66 66 * Caller must hold rcu_read_lock(). 67 67 */ 68 68 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; 69 70 #endif /* EF100_REP_H */
+37
drivers/net/ethernet/sfc/ethtool_common.c
··· 101 101 102 102 #define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc) 103 103 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 + 104 112 void efx_ethtool_get_drvinfo(struct net_device *net_dev, 105 113 struct ethtool_drvinfo *info) 106 114 { ··· 460 452 efx_ptp_describe_stats(efx, NULL); 461 453 case ETH_SS_TEST: 462 454 return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL); 455 + case ETH_SS_PRIV_FLAGS: 456 + return EFX_ETHTOOL_PRIV_FLAGS_COUNT; 463 457 default: 464 458 return -EINVAL; 465 459 } ··· 488 478 case ETH_SS_TEST: 489 479 efx_ethtool_fill_self_tests(efx, NULL, strings, NULL); 490 480 break; 481 + case ETH_SS_PRIV_FLAGS: 482 + for (i = 0; i < EFX_ETHTOOL_PRIV_FLAGS_COUNT; i++) 483 + strscpy(strings + i * ETH_GSTRING_LEN, 484 + efx_ethtool_priv_flags_strings[i], 485 + ETH_GSTRING_LEN); 486 + break; 491 487 default: 492 488 /* No other string sets */ 493 489 break; 494 490 } 491 + } 492 + 493 + u32 efx_ethtool_get_priv_flags(struct net_device *net_dev) 494 + { 495 + struct efx_nic *efx = efx_netdev_priv(net_dev); 496 + u32 ret_flags = 0; 497 + 498 + if (efx->log_tc_errs) 499 + ret_flags |= EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS; 500 + 501 + return ret_flags; 502 + } 503 + 504 + int efx_ethtool_set_priv_flags(struct net_device *net_dev, u32 flags) 505 + { 506 + struct efx_nic *efx = efx_netdev_priv(net_dev); 507 + 508 + efx->log_tc_errs = 509 + !!(flags & EFX_ETHTOOL_PRIV_FLAGS_LOG_TC_ERRS); 510 + 511 + return 0; 495 512 } 496 513 497 514 void efx_ethtool_get_stats(struct net_device *net_dev,
+2
drivers/net/ethernet/sfc/ethtool_common.h
··· 27 27 int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set); 28 28 void efx_ethtool_get_strings(struct net_device *net_dev, u32 string_set, 29 29 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); 30 32 void efx_ethtool_get_stats(struct net_device *net_dev, 31 33 struct ethtool_stats *stats __attribute__ ((unused)), 32 34 u64 *data);
+165
drivers/net/ethernet/sfc/mae.c
··· 112 112 return 0; 113 113 } 114 114 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 + 115 276 static bool efx_mae_asl_id(u32 id) 116 277 { 117 278 return !!(id & BIT(31)); ··· 440 279 } 441 280 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 442 281 match->mask.ingress_port); 282 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID, 283 + match->value.recirc_id); 284 + MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK, 285 + match->mask.recirc_id); 443 286 return 0; 444 287 } 445 288
+14
drivers/net/ethernet/sfc/mae.h
··· 27 27 28 28 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id); 29 29 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 + 30 44 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act); 31 45 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id); 32 46
+10
drivers/net/ethernet/sfc/mcdi.h
··· 201 201 ((u8 *)(_buf) + (_offset)) 202 202 #define MCDI_PTR(_buf, _field) \ 203 203 _MCDI_PTR(_buf, MC_CMD_ ## _field ## _OFST) 204 + /* Use MCDI_STRUCT_ functions to access members of MCDI structuredefs. 205 + * _buf should point to the start of the structure, typically obtained with 206 + * MCDI_DECLARE_STRUCT_PTR(structure) = _MCDI_DWORD(mcdi_buf, FIELD_WHICH_IS_STRUCT); 207 + */ 208 + #define MCDI_STRUCT_PTR(_buf, _field) \ 209 + _MCDI_PTR(_buf, _field ## _OFST) 204 210 #define _MCDI_CHECK_ALIGN(_ofst, _align) \ 205 211 ((_ofst) + BUILD_BUG_ON_ZERO((_ofst) & (_align - 1))) 206 212 #define _MCDI_DWORD(_buf, _field) \ ··· 214 208 #define _MCDI_STRUCT_DWORD(_buf, _field) \ 215 209 ((_buf) + (_MCDI_CHECK_ALIGN(_field ## _OFST, 4) >> 2)) 216 210 211 + #define MCDI_STRUCT_SET_BYTE(_buf, _field, _value) do { \ 212 + BUILD_BUG_ON(_field ## _LEN != 1); \ 213 + *(u8 *)MCDI_STRUCT_PTR(_buf, _field) = _value; \ 214 + } while (0) 217 215 #define MCDI_BYTE(_buf, _field) \ 218 216 ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \ 219 217 *MCDI_PTR(_buf, _field))
+2
drivers/net/ethernet/sfc/net_driver.h
··· 855 855 * @timer_max_ns: Interrupt timer maximum value, in nanoseconds 856 856 * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues 857 857 * @irqs_hooked: Channel interrupts are hooked 858 + * @log_tc_errs: Error logging for TC filter insertion is enabled 858 859 * @irq_rx_mod_step_us: Step size for IRQ moderation for RX event queues 859 860 * @irq_rx_moderation_us: IRQ moderation time for RX event queues 860 861 * @msg_enable: Log message enable flags ··· 1018 1017 unsigned int timer_max_ns; 1019 1018 bool irq_rx_adaptive; 1020 1019 bool irqs_hooked; 1020 + bool log_tc_errs; 1021 1021 unsigned int irq_mod_step_us; 1022 1022 unsigned int irq_rx_moderation_us; 1023 1023 u32 msg_enable;
+429 -1
drivers/net/ethernet/sfc/tc.c
··· 9 9 * by the Free Software Foundation, incorporated herein by reference. 10 10 */ 11 11 12 + #include <net/pkt_cls.h> 12 13 #include "tc.h" 14 + #include "tc_bindings.h" 13 15 #include "mae.h" 14 16 #include "ef100_rep.h" 15 17 #include "efx.h" 18 + 19 + #define EFX_EFV_PF NULL 20 + /* Look up the representor information (efv) for a device. 21 + * May return NULL for the PF (us), or an error pointer for a device that 22 + * isn't supported as a TC offload endpoint 23 + */ 24 + static struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx, 25 + struct net_device *dev) 26 + { 27 + struct efx_rep *efv; 28 + 29 + if (!dev) 30 + return ERR_PTR(-EOPNOTSUPP); 31 + /* Is it us (the PF)? */ 32 + if (dev == efx->net_dev) 33 + return EFX_EFV_PF; 34 + /* Is it an efx vfrep at all? */ 35 + if (dev->netdev_ops != &efx_ef100_rep_netdev_ops) 36 + return ERR_PTR(-EOPNOTSUPP); 37 + /* Is it ours? We don't support TC rules that include another 38 + * EF100's netdevices (not even on another port of the same NIC). 39 + */ 40 + efv = netdev_priv(dev); 41 + if (efv->parent != efx) 42 + return ERR_PTR(-EOPNOTSUPP); 43 + return efv; 44 + } 45 + 46 + /* Convert a driver-internal vport ID into an external device (wire or VF) */ 47 + static s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv) 48 + { 49 + u32 mport; 50 + 51 + if (IS_ERR(efv)) 52 + return PTR_ERR(efv); 53 + if (!efv) /* device is PF (us) */ 54 + efx_mae_mport_wire(efx, &mport); 55 + else /* device is repr */ 56 + efx_mae_mport_mport(efx, efv->mport, &mport); 57 + return mport; 58 + } 59 + 60 + static const struct rhashtable_params efx_tc_match_action_ht_params = { 61 + .key_len = sizeof(unsigned long), 62 + .key_offset = offsetof(struct efx_tc_flow_rule, cookie), 63 + .head_offset = offsetof(struct efx_tc_flow_rule, linkage), 64 + }; 16 65 17 66 static void efx_tc_free_action_set(struct efx_nic *efx, 18 67 struct efx_tc_action_set *act, bool in_hw) ··· 105 56 /* Release entries in subsidiary tables */ 106 57 efx_tc_free_action_set_list(efx, &rule->acts, true); 107 58 rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 59 + } 60 + 61 + static void efx_tc_flow_free(void *ptr, void *arg) 62 + { 63 + struct efx_tc_flow_rule *rule = ptr; 64 + struct efx_nic *efx = arg; 65 + 66 + netif_err(efx, drv, efx->net_dev, 67 + "tc rule %lx still present at teardown, removing\n", 68 + rule->cookie); 69 + 70 + efx_mae_delete_rule(efx, rule->fw_id); 71 + 72 + /* Release entries in subsidiary tables */ 73 + efx_tc_free_action_set_list(efx, &rule->acts, true); 74 + 75 + kfree(rule); 76 + } 77 + 78 + static int efx_tc_flower_parse_match(struct efx_nic *efx, 79 + struct flow_rule *rule, 80 + struct efx_tc_match *match, 81 + struct netlink_ext_ack *extack) 82 + { 83 + struct flow_dissector *dissector = rule->match.dissector; 84 + 85 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { 86 + struct flow_match_control fm; 87 + 88 + flow_rule_match_control(rule, &fm); 89 + 90 + if (fm.mask->flags) { 91 + efx_tc_err(efx, "Unsupported match on control.flags %#x\n", 92 + fm.mask->flags); 93 + NL_SET_ERR_MSG_MOD(extack, "Unsupported match on control.flags"); 94 + return -EOPNOTSUPP; 95 + } 96 + } 97 + if (dissector->used_keys & 98 + ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 99 + BIT(FLOW_DISSECTOR_KEY_BASIC))) { 100 + efx_tc_err(efx, "Unsupported flower keys %#x\n", dissector->used_keys); 101 + NL_SET_ERR_MSG_MOD(extack, "Unsupported flower keys encountered"); 102 + return -EOPNOTSUPP; 103 + } 104 + 105 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { 106 + struct flow_match_basic fm; 107 + 108 + flow_rule_match_basic(rule, &fm); 109 + if (fm.mask->n_proto) { 110 + EFX_TC_ERR_MSG(efx, extack, "Unsupported eth_proto match\n"); 111 + return -EOPNOTSUPP; 112 + } 113 + if (fm.mask->ip_proto) { 114 + EFX_TC_ERR_MSG(efx, extack, "Unsupported ip_proto match\n"); 115 + return -EOPNOTSUPP; 116 + } 117 + } 118 + 119 + return 0; 120 + } 121 + 122 + static int efx_tc_flower_replace(struct efx_nic *efx, 123 + struct net_device *net_dev, 124 + struct flow_cls_offload *tc, 125 + struct efx_rep *efv) 126 + { 127 + struct flow_rule *fr = flow_cls_offload_flow_rule(tc); 128 + struct netlink_ext_ack *extack = tc->common.extack; 129 + struct efx_tc_flow_rule *rule = NULL, *old; 130 + struct efx_tc_action_set *act = NULL; 131 + const struct flow_action_entry *fa; 132 + struct efx_rep *from_efv, *to_efv; 133 + struct efx_tc_match match; 134 + s64 rc; 135 + int i; 136 + 137 + if (!tc_can_offload_extack(efx->net_dev, extack)) 138 + return -EOPNOTSUPP; 139 + if (WARN_ON(!efx->tc)) 140 + return -ENETDOWN; 141 + if (WARN_ON(!efx->tc->up)) 142 + return -ENETDOWN; 143 + 144 + from_efv = efx_tc_flower_lookup_efv(efx, net_dev); 145 + if (IS_ERR(from_efv)) { 146 + /* Might be a tunnel decap rule from an indirect block. 147 + * Support for those not implemented yet. 148 + */ 149 + return -EOPNOTSUPP; 150 + } 151 + 152 + if (efv != from_efv) { 153 + /* can't happen */ 154 + efx_tc_err(efx, "for %s efv is %snull but from_efv is %snull\n", 155 + netdev_name(net_dev), efv ? "non-" : "", 156 + from_efv ? "non-" : ""); 157 + if (efv) 158 + NL_SET_ERR_MSG_MOD(extack, "vfrep filter has PF net_dev (can't happen)"); 159 + else 160 + NL_SET_ERR_MSG_MOD(extack, "PF filter has vfrep net_dev (can't happen)"); 161 + return -EINVAL; 162 + } 163 + 164 + /* Parse match */ 165 + memset(&match, 0, sizeof(match)); 166 + rc = efx_tc_flower_external_mport(efx, from_efv); 167 + if (rc < 0) { 168 + EFX_TC_ERR_MSG(efx, extack, "Failed to identify ingress m-port"); 169 + return rc; 170 + } 171 + match.value.ingress_port = rc; 172 + match.mask.ingress_port = ~0; 173 + rc = efx_tc_flower_parse_match(efx, fr, &match, extack); 174 + if (rc) 175 + return rc; 176 + 177 + if (tc->common.chain_index) { 178 + EFX_TC_ERR_MSG(efx, extack, "No support for nonzero chain_index"); 179 + return -EOPNOTSUPP; 180 + } 181 + match.mask.recirc_id = 0xff; 182 + 183 + rc = efx_mae_match_check_caps(efx, &match.mask, extack); 184 + if (rc) 185 + return rc; 186 + 187 + rule = kzalloc(sizeof(*rule), GFP_USER); 188 + if (!rule) 189 + return -ENOMEM; 190 + INIT_LIST_HEAD(&rule->acts.list); 191 + rule->cookie = tc->cookie; 192 + old = rhashtable_lookup_get_insert_fast(&efx->tc->match_action_ht, 193 + &rule->linkage, 194 + efx_tc_match_action_ht_params); 195 + if (old) { 196 + netif_dbg(efx, drv, efx->net_dev, 197 + "Already offloaded rule (cookie %lx)\n", tc->cookie); 198 + rc = -EEXIST; 199 + NL_SET_ERR_MSG_MOD(extack, "Rule already offloaded"); 200 + goto release; 201 + } 202 + 203 + /* Parse actions */ 204 + act = kzalloc(sizeof(*act), GFP_USER); 205 + if (!act) { 206 + rc = -ENOMEM; 207 + goto release; 208 + } 209 + 210 + flow_action_for_each(i, fa, &fr->action) { 211 + struct efx_tc_action_set save; 212 + 213 + if (!act) { 214 + /* more actions after a non-pipe action */ 215 + EFX_TC_ERR_MSG(efx, extack, "Action follows non-pipe action"); 216 + rc = -EINVAL; 217 + goto release; 218 + } 219 + 220 + switch (fa->id) { 221 + case FLOW_ACTION_DROP: 222 + rc = efx_mae_alloc_action_set(efx, act); 223 + if (rc) { 224 + EFX_TC_ERR_MSG(efx, extack, "Failed to write action set to hw (drop)"); 225 + goto release; 226 + } 227 + list_add_tail(&act->list, &rule->acts.list); 228 + act = NULL; /* end of the line */ 229 + break; 230 + case FLOW_ACTION_REDIRECT: 231 + case FLOW_ACTION_MIRRED: 232 + save = *act; 233 + to_efv = efx_tc_flower_lookup_efv(efx, fa->dev); 234 + if (IS_ERR(to_efv)) { 235 + EFX_TC_ERR_MSG(efx, extack, "Mirred egress device not on switch"); 236 + rc = PTR_ERR(to_efv); 237 + goto release; 238 + } 239 + rc = efx_tc_flower_external_mport(efx, to_efv); 240 + if (rc < 0) { 241 + EFX_TC_ERR_MSG(efx, extack, "Failed to identify egress m-port"); 242 + goto release; 243 + } 244 + act->dest_mport = rc; 245 + act->deliver = 1; 246 + rc = efx_mae_alloc_action_set(efx, act); 247 + if (rc) { 248 + EFX_TC_ERR_MSG(efx, extack, "Failed to write action set to hw (mirred)"); 249 + goto release; 250 + } 251 + list_add_tail(&act->list, &rule->acts.list); 252 + act = NULL; 253 + if (fa->id == FLOW_ACTION_REDIRECT) 254 + break; /* end of the line */ 255 + /* Mirror, so continue on with saved act */ 256 + act = kzalloc(sizeof(*act), GFP_USER); 257 + if (!act) { 258 + rc = -ENOMEM; 259 + goto release; 260 + } 261 + *act = save; 262 + break; 263 + default: 264 + efx_tc_err(efx, "Unhandled action %u\n", fa->id); 265 + rc = -EOPNOTSUPP; 266 + NL_SET_ERR_MSG_MOD(extack, "Unsupported action"); 267 + goto release; 268 + } 269 + } 270 + 271 + if (act) { 272 + /* Not shot/redirected, so deliver to default dest */ 273 + if (from_efv == EFX_EFV_PF) 274 + /* Rule applies to traffic from the wire, 275 + * and default dest is thus the PF 276 + */ 277 + efx_mae_mport_uplink(efx, &act->dest_mport); 278 + else 279 + /* Representor, so rule applies to traffic from 280 + * representee, and default dest is thus the rep. 281 + * All reps use the same mport for delivery 282 + */ 283 + efx_mae_mport_mport(efx, efx->tc->reps_mport_id, 284 + &act->dest_mport); 285 + act->deliver = 1; 286 + rc = efx_mae_alloc_action_set(efx, act); 287 + if (rc) { 288 + EFX_TC_ERR_MSG(efx, extack, "Failed to write action set to hw (deliver)"); 289 + goto release; 290 + } 291 + list_add_tail(&act->list, &rule->acts.list); 292 + act = NULL; /* Prevent double-free in error path */ 293 + } 294 + 295 + netif_dbg(efx, drv, efx->net_dev, 296 + "Successfully parsed filter (cookie %lx)\n", 297 + tc->cookie); 298 + 299 + rule->match = match; 300 + 301 + rc = efx_mae_alloc_action_set_list(efx, &rule->acts); 302 + if (rc) { 303 + EFX_TC_ERR_MSG(efx, extack, "Failed to write action set list to hw"); 304 + goto release; 305 + } 306 + rc = efx_mae_insert_rule(efx, &rule->match, EFX_TC_PRIO_TC, 307 + rule->acts.fw_id, &rule->fw_id); 308 + if (rc) { 309 + EFX_TC_ERR_MSG(efx, extack, "Failed to insert rule in hw"); 310 + goto release_acts; 311 + } 312 + return 0; 313 + 314 + release_acts: 315 + efx_mae_free_action_set_list(efx, &rule->acts); 316 + release: 317 + /* We failed to insert the rule, so free up any entries we created in 318 + * subsidiary tables. 319 + */ 320 + if (act) 321 + efx_tc_free_action_set(efx, act, false); 322 + if (rule) { 323 + rhashtable_remove_fast(&efx->tc->match_action_ht, 324 + &rule->linkage, 325 + efx_tc_match_action_ht_params); 326 + efx_tc_free_action_set_list(efx, &rule->acts, false); 327 + } 328 + kfree(rule); 329 + return rc; 330 + } 331 + 332 + static int efx_tc_flower_destroy(struct efx_nic *efx, 333 + struct net_device *net_dev, 334 + struct flow_cls_offload *tc) 335 + { 336 + struct netlink_ext_ack *extack = tc->common.extack; 337 + struct efx_tc_flow_rule *rule; 338 + 339 + rule = rhashtable_lookup_fast(&efx->tc->match_action_ht, &tc->cookie, 340 + efx_tc_match_action_ht_params); 341 + if (!rule) { 342 + /* Only log a message if we're the ingress device. Otherwise 343 + * it's a foreign filter and we might just not have been 344 + * interested (e.g. we might not have been the egress device 345 + * either). 346 + */ 347 + if (!IS_ERR(efx_tc_flower_lookup_efv(efx, net_dev))) 348 + netif_warn(efx, drv, efx->net_dev, 349 + "Filter %lx not found to remove\n", tc->cookie); 350 + NL_SET_ERR_MSG_MOD(extack, "Flow cookie not found in offloaded rules"); 351 + return -ENOENT; 352 + } 353 + 354 + /* Remove it from HW */ 355 + efx_tc_delete_rule(efx, rule); 356 + /* Delete it from SW */ 357 + rhashtable_remove_fast(&efx->tc->match_action_ht, &rule->linkage, 358 + efx_tc_match_action_ht_params); 359 + netif_dbg(efx, drv, efx->net_dev, "Removed filter %lx\n", rule->cookie); 360 + kfree(rule); 361 + return 0; 362 + } 363 + 364 + int efx_tc_flower(struct efx_nic *efx, struct net_device *net_dev, 365 + struct flow_cls_offload *tc, struct efx_rep *efv) 366 + { 367 + int rc; 368 + 369 + if (!efx->tc) 370 + return -EOPNOTSUPP; 371 + 372 + mutex_lock(&efx->tc->mutex); 373 + switch (tc->command) { 374 + case FLOW_CLS_REPLACE: 375 + rc = efx_tc_flower_replace(efx, net_dev, tc, efv); 376 + break; 377 + case FLOW_CLS_DESTROY: 378 + rc = efx_tc_flower_destroy(efx, net_dev, tc); 379 + break; 380 + default: 381 + rc = -EOPNOTSUPP; 382 + break; 383 + } 384 + mutex_unlock(&efx->tc->mutex); 385 + return rc; 108 386 } 109 387 110 388 static int efx_tc_configure_default_rule(struct efx_nic *efx, u32 ing_port, ··· 577 201 { 578 202 int rc; 579 203 204 + rc = efx_mae_get_caps(efx, efx->tc->caps); 205 + if (rc) 206 + return rc; 207 + if (efx->tc->caps->match_field_count > MAE_NUM_FIELDS) 208 + /* Firmware supports some match fields the driver doesn't know 209 + * about. Not fatal, unless any of those fields are required 210 + * (MAE_FIELD_SUPPORTED_MATCH_ALWAYS) but if so we don't know. 211 + */ 212 + netif_warn(efx, probe, efx->net_dev, 213 + "FW reports additional match fields %u\n", 214 + efx->tc->caps->match_field_count); 215 + if (efx->tc->caps->action_prios < EFX_TC_PRIO__NUM) { 216 + netif_err(efx, probe, efx->net_dev, 217 + "Too few action prios supported (have %u, need %u)\n", 218 + efx->tc->caps->action_prios, EFX_TC_PRIO__NUM); 219 + return -EIO; 220 + } 580 221 rc = efx_tc_configure_default_rule_pf(efx); 581 222 if (rc) 582 223 return rc; 583 224 rc = efx_tc_configure_default_rule_wire(efx); 584 225 if (rc) 585 226 return rc; 586 - return efx_tc_configure_rep_mport(efx); 227 + rc = efx_tc_configure_rep_mport(efx); 228 + if (rc) 229 + return rc; 230 + efx->tc->up = true; 231 + rc = flow_indr_dev_register(efx_tc_indr_setup_cb, efx); 232 + if (rc) 233 + return rc; 234 + return 0; 587 235 } 588 236 589 237 void efx_fini_tc(struct efx_nic *efx) ··· 615 215 /* We can get called even if efx_init_struct_tc() failed */ 616 216 if (!efx->tc) 617 217 return; 218 + if (efx->tc->up) 219 + flow_indr_dev_unregister(efx_tc_indr_setup_cb, efx, efx_tc_block_unbind); 618 220 efx_tc_deconfigure_rep_mport(efx); 619 221 efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf); 620 222 efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire); 223 + efx->tc->up = false; 621 224 } 622 225 623 226 int efx_init_struct_tc(struct efx_nic *efx) 624 227 { 228 + int rc; 229 + 625 230 if (efx->type->is_vf) 626 231 return 0; 627 232 628 233 efx->tc = kzalloc(sizeof(*efx->tc), GFP_KERNEL); 629 234 if (!efx->tc) 630 235 return -ENOMEM; 236 + efx->tc->caps = kzalloc(sizeof(struct mae_caps), GFP_KERNEL); 237 + if (!efx->tc->caps) { 238 + rc = -ENOMEM; 239 + goto fail_alloc_caps; 240 + } 241 + INIT_LIST_HEAD(&efx->tc->block_list); 631 242 243 + mutex_init(&efx->tc->mutex); 244 + rc = rhashtable_init(&efx->tc->match_action_ht, &efx_tc_match_action_ht_params); 245 + if (rc < 0) 246 + goto fail_match_action_ht; 632 247 efx->tc->reps_filter_uc = -1; 633 248 efx->tc->reps_filter_mc = -1; 634 249 INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list); ··· 651 236 INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list); 652 237 efx->tc->dflt.wire.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 653 238 return 0; 239 + fail_match_action_ht: 240 + mutex_destroy(&efx->tc->mutex); 241 + kfree(efx->tc->caps); 242 + fail_alloc_caps: 243 + kfree(efx->tc); 244 + efx->tc = NULL; 245 + return rc; 654 246 } 655 247 656 248 void efx_fini_struct_tc(struct efx_nic *efx) ··· 665 243 if (!efx->tc) 666 244 return; 667 245 246 + mutex_lock(&efx->tc->mutex); 668 247 EFX_WARN_ON_PARANOID(efx->tc->dflt.pf.fw_id != 669 248 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 670 249 EFX_WARN_ON_PARANOID(efx->tc->dflt.wire.fw_id != 671 250 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 251 + rhashtable_free_and_destroy(&efx->tc->match_action_ht, efx_tc_flow_free, 252 + efx); 253 + mutex_unlock(&efx->tc->mutex); 254 + mutex_destroy(&efx->tc->mutex); 255 + kfree(efx->tc->caps); 672 256 kfree(efx->tc); 673 257 efx->tc = NULL; 674 258 }
+36
drivers/net/ethernet/sfc/tc.h
··· 11 11 12 12 #ifndef EFX_TC_H 13 13 #define EFX_TC_H 14 + #include <net/flow_offload.h> 15 + #include <linux/rhashtable.h> 14 16 #include "net_driver.h" 17 + 18 + /* Error reporting: convenience macros. For indicating why a given filter 19 + * insertion is not supported; errors in internal operation or in the 20 + * hardware should be netif_err()s instead. 21 + */ 22 + /* Used when error message is constant. */ 23 + #define EFX_TC_ERR_MSG(efx, extack, message) do { \ 24 + NL_SET_ERR_MSG_MOD(extack, message); \ 25 + if (efx->log_tc_errs) \ 26 + netif_info(efx, drv, efx->net_dev, "%s\n", message); \ 27 + } while (0) 28 + /* Used when error message is not constant; caller should also supply a 29 + * constant extack message with NL_SET_ERR_MSG_MOD(). 30 + */ 31 + #define efx_tc_err(efx, fmt, args...) do { \ 32 + if (efx->log_tc_errs) \ 33 + netif_info(efx, drv, efx->net_dev, fmt, ##args);\ 34 + } while (0) 15 35 16 36 struct efx_tc_action_set { 17 37 u16 deliver:1; ··· 43 23 struct efx_tc_match_fields { 44 24 /* L1 */ 45 25 u32 ingress_port; 26 + u8 recirc_id; 46 27 }; 47 28 48 29 struct efx_tc_match { ··· 57 36 }; 58 37 59 38 struct efx_tc_flow_rule { 39 + unsigned long cookie; 40 + struct rhash_head linkage; 60 41 struct efx_tc_match match; 61 42 struct efx_tc_action_set_list acts; 62 43 u32 fw_id; 63 44 }; 64 45 65 46 enum efx_tc_rule_prios { 47 + EFX_TC_PRIO_TC, /* Rule inserted by TC */ 66 48 EFX_TC_PRIO_DFLT, /* Default switch rule; one of efx_tc_default_rules */ 67 49 EFX_TC_PRIO__NUM 68 50 }; ··· 73 49 /** 74 50 * struct efx_tc_state - control plane data for TC offload 75 51 * 52 + * @caps: MAE capabilities reported by MCDI 53 + * @block_list: List of &struct efx_tc_block_binding 54 + * @mutex: Used to serialise operations on TC hashtables 55 + * @match_action_ht: Hashtable of TC match-action rules 76 56 * @reps_mport_id: MAE port allocated for representor RX 77 57 * @reps_filter_uc: VNIC filter for representor unicast RX (promisc) 78 58 * @reps_filter_mc: VNIC filter for representor multicast RX (allmulti) ··· 85 57 * %EFX_TC_PRIO_DFLT. Named by *ingress* port 86 58 * @dflt.pf: rule for traffic ingressing from PF (egresses to wire) 87 59 * @dflt.wire: rule for traffic ingressing from wire (egresses to PF) 60 + * @up: have TC datastructures been set up? 88 61 */ 89 62 struct efx_tc_state { 63 + struct mae_caps *caps; 64 + struct list_head block_list; 65 + struct mutex mutex; 66 + struct rhashtable match_action_ht; 90 67 u32 reps_mport_id, reps_mport_vport_id; 91 68 s32 reps_filter_uc, reps_filter_mc; 92 69 struct { 93 70 struct efx_tc_flow_rule pf; 94 71 struct efx_tc_flow_rule wire; 95 72 } dflt; 73 + bool up; 96 74 }; 97 75 98 76 struct efx_rep; ··· 106 72 int efx_tc_configure_default_rule_rep(struct efx_rep *efv); 107 73 void efx_tc_deconfigure_default_rule(struct efx_nic *efx, 108 74 struct efx_tc_flow_rule *rule); 75 + int efx_tc_flower(struct efx_nic *efx, struct net_device *net_dev, 76 + struct flow_cls_offload *tc, struct efx_rep *efv); 109 77 110 78 int efx_tc_insert_rep_filters(struct efx_nic *efx); 111 79 void efx_tc_remove_rep_filters(struct efx_nic *efx);
+228
drivers/net/ethernet/sfc/tc_bindings.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /**************************************************************************** 3 + * Driver for Solarflare network controllers and boards 4 + * Copyright 2022 Xilinx Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License version 2 as published 8 + * by the Free Software Foundation, incorporated herein by reference. 9 + */ 10 + 11 + #include "tc_bindings.h" 12 + #include "tc.h" 13 + 14 + struct efx_tc_block_binding { 15 + struct list_head list; 16 + struct efx_nic *efx; 17 + struct efx_rep *efv; 18 + struct net_device *otherdev; /* may actually be us */ 19 + struct flow_block *block; 20 + }; 21 + 22 + static struct efx_tc_block_binding *efx_tc_find_binding(struct efx_nic *efx, 23 + struct net_device *otherdev) 24 + { 25 + struct efx_tc_block_binding *binding; 26 + 27 + ASSERT_RTNL(); 28 + list_for_each_entry(binding, &efx->tc->block_list, list) 29 + if (binding->otherdev == otherdev) 30 + return binding; 31 + return NULL; 32 + } 33 + 34 + static int efx_tc_block_cb(enum tc_setup_type type, void *type_data, 35 + void *cb_priv) 36 + { 37 + struct efx_tc_block_binding *binding = cb_priv; 38 + struct flow_cls_offload *tcf = type_data; 39 + 40 + switch (type) { 41 + case TC_SETUP_CLSFLOWER: 42 + return efx_tc_flower(binding->efx, binding->otherdev, 43 + tcf, binding->efv); 44 + default: 45 + return -EOPNOTSUPP; 46 + } 47 + } 48 + 49 + void efx_tc_block_unbind(void *cb_priv) 50 + { 51 + struct efx_tc_block_binding *binding = cb_priv; 52 + 53 + list_del(&binding->list); 54 + kfree(binding); 55 + } 56 + 57 + static struct efx_tc_block_binding *efx_tc_create_binding( 58 + struct efx_nic *efx, struct efx_rep *efv, 59 + struct net_device *otherdev, struct flow_block *block) 60 + { 61 + struct efx_tc_block_binding *binding = kmalloc(sizeof(*binding), GFP_KERNEL); 62 + 63 + if (!binding) 64 + return ERR_PTR(-ENOMEM); 65 + binding->efx = efx; 66 + binding->efv = efv; 67 + binding->otherdev = otherdev; 68 + binding->block = block; 69 + list_add(&binding->list, &efx->tc->block_list); 70 + return binding; 71 + } 72 + 73 + int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx, 74 + struct flow_block_offload *tcb, struct efx_rep *efv) 75 + { 76 + struct efx_tc_block_binding *binding; 77 + struct flow_block_cb *block_cb; 78 + int rc; 79 + 80 + if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 81 + return -EOPNOTSUPP; 82 + 83 + if (WARN_ON(!efx->tc)) 84 + return -ENETDOWN; 85 + 86 + switch (tcb->command) { 87 + case FLOW_BLOCK_BIND: 88 + binding = efx_tc_create_binding(efx, efv, net_dev, tcb->block); 89 + if (IS_ERR(binding)) 90 + return PTR_ERR(binding); 91 + block_cb = flow_block_cb_alloc(efx_tc_block_cb, binding, 92 + binding, efx_tc_block_unbind); 93 + rc = PTR_ERR_OR_ZERO(block_cb); 94 + netif_dbg(efx, drv, efx->net_dev, 95 + "bind %sdirect block for device %s, rc %d\n", 96 + net_dev == efx->net_dev ? "" : 97 + efv ? "semi" : "in", 98 + net_dev ? net_dev->name : NULL, rc); 99 + if (rc) { 100 + list_del(&binding->list); 101 + kfree(binding); 102 + } else { 103 + flow_block_cb_add(block_cb, tcb); 104 + } 105 + return rc; 106 + case FLOW_BLOCK_UNBIND: 107 + binding = efx_tc_find_binding(efx, net_dev); 108 + if (binding) { 109 + block_cb = flow_block_cb_lookup(tcb->block, 110 + efx_tc_block_cb, 111 + binding); 112 + if (block_cb) { 113 + flow_block_cb_remove(block_cb, tcb); 114 + netif_dbg(efx, drv, efx->net_dev, 115 + "unbound %sdirect block for device %s\n", 116 + net_dev == efx->net_dev ? "" : 117 + binding->efv ? "semi" : "in", 118 + net_dev ? net_dev->name : NULL); 119 + return 0; 120 + } 121 + } 122 + /* If we're in driver teardown, then we expect to have 123 + * already unbound all our blocks (we did it early while 124 + * we still had MCDI to remove the filters), so getting 125 + * unbind callbacks now isn't a problem. 126 + */ 127 + netif_cond_dbg(efx, drv, efx->net_dev, 128 + !efx->tc->up, warn, 129 + "%sdirect block unbind for device %s, was never bound\n", 130 + net_dev == efx->net_dev ? "" : "in", 131 + net_dev ? net_dev->name : NULL); 132 + return -ENOENT; 133 + default: 134 + return -EOPNOTSUPP; 135 + } 136 + } 137 + 138 + int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch, 139 + void *cb_priv, enum tc_setup_type type, 140 + void *type_data, void *data, 141 + void (*cleanup)(struct flow_block_cb *block_cb)) 142 + { 143 + struct flow_block_offload *tcb = type_data; 144 + struct efx_tc_block_binding *binding; 145 + struct flow_block_cb *block_cb; 146 + struct efx_nic *efx = cb_priv; 147 + bool is_ovs_int_port; 148 + int rc; 149 + 150 + if (!net_dev) 151 + return -EOPNOTSUPP; 152 + 153 + if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS && 154 + tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) 155 + return -EOPNOTSUPP; 156 + 157 + is_ovs_int_port = netif_is_ovs_master(net_dev); 158 + if (tcb->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS && 159 + !is_ovs_int_port) 160 + return -EOPNOTSUPP; 161 + 162 + if (is_ovs_int_port) 163 + return -EOPNOTSUPP; 164 + 165 + switch (type) { 166 + case TC_SETUP_BLOCK: 167 + switch (tcb->command) { 168 + case FLOW_BLOCK_BIND: 169 + binding = efx_tc_create_binding(efx, NULL, net_dev, tcb->block); 170 + if (IS_ERR(binding)) 171 + return PTR_ERR(binding); 172 + block_cb = flow_indr_block_cb_alloc(efx_tc_block_cb, binding, 173 + binding, efx_tc_block_unbind, 174 + tcb, net_dev, sch, data, binding, 175 + cleanup); 176 + rc = PTR_ERR_OR_ZERO(block_cb); 177 + netif_dbg(efx, drv, efx->net_dev, 178 + "bind indr block for device %s, rc %d\n", 179 + net_dev ? net_dev->name : NULL, rc); 180 + if (rc) { 181 + list_del(&binding->list); 182 + kfree(binding); 183 + } else { 184 + flow_block_cb_add(block_cb, tcb); 185 + } 186 + return rc; 187 + case FLOW_BLOCK_UNBIND: 188 + binding = efx_tc_find_binding(efx, net_dev); 189 + if (!binding) 190 + return -ENOENT; 191 + block_cb = flow_block_cb_lookup(tcb->block, 192 + efx_tc_block_cb, 193 + binding); 194 + if (!block_cb) 195 + return -ENOENT; 196 + flow_indr_block_cb_remove(block_cb, tcb); 197 + netif_dbg(efx, drv, efx->net_dev, 198 + "unbind indr block for device %s\n", 199 + net_dev ? net_dev->name : NULL); 200 + return 0; 201 + default: 202 + return -EOPNOTSUPP; 203 + } 204 + default: 205 + return -EOPNOTSUPP; 206 + } 207 + } 208 + 209 + /* .ndo_setup_tc implementation 210 + * Entry point for flower block and filter management. 211 + */ 212 + int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type, 213 + void *type_data) 214 + { 215 + struct efx_nic *efx = efx_netdev_priv(net_dev); 216 + 217 + if (efx->type->is_vf) 218 + return -EOPNOTSUPP; 219 + if (!efx->tc) 220 + return -EOPNOTSUPP; 221 + 222 + if (type == TC_SETUP_CLSFLOWER) 223 + return efx_tc_flower(efx, net_dev, type_data, NULL); 224 + if (type == TC_SETUP_BLOCK) 225 + return efx_tc_setup_block(net_dev, efx, type_data, NULL); 226 + 227 + return -EOPNOTSUPP; 228 + }
+29
drivers/net/ethernet/sfc/tc_bindings.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /**************************************************************************** 3 + * Driver for Solarflare network controllers and boards 4 + * Copyright 2022 Xilinx Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License version 2 as published 8 + * by the Free Software Foundation, incorporated herein by reference. 9 + */ 10 + 11 + #ifndef EFX_TC_BINDINGS_H 12 + #define EFX_TC_BINDINGS_H 13 + #include "net_driver.h" 14 + 15 + #include <net/sch_generic.h> 16 + 17 + struct efx_rep; 18 + 19 + void efx_tc_block_unbind(void *cb_priv); 20 + int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx, 21 + struct flow_block_offload *tcb, struct efx_rep *efv); 22 + int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type, 23 + void *type_data); 24 + 25 + int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch, 26 + void *cb_priv, enum tc_setup_type type, 27 + void *type_data, void *data, 28 + void (*cleanup)(struct flow_block_cb *block_cb)); 29 + #endif /* EFX_TC_BINDINGS_H */