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

sfc: insert default MAE rules to connect VFs to representors

Default rules are low-priority switching rules which the hardware uses
in the absence of higher-priority rules. Each representor requires a
corresponding rule matching traffic from its representee VF and
delivering to the PF (where a check on INGRESS_MPORT in
__ef100_rx_packet() will direct it to the representor). No rule is
required in the reverse direction, because representor TX uses a TX
override descriptor to bypass the MAE and deliver directly to the VF.
Since inserting any rule into the MAE disables the firmware's own
default rules, also insert a pair of rules to connect the PF to the
physical network port and vice-versa.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Edward Cree and committed by
Jakub Kicinski
67ab160e f50e8fcd

+606 -6
+2 -1
drivers/net/ethernet/sfc/Makefile
··· 8 8 ef100.o ef100_nic.o ef100_netdev.o \ 9 9 ef100_ethtool.o ef100_rx.o ef100_tx.o 10 10 sfc-$(CONFIG_SFC_MTD) += mtd.o 11 - sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o mae.o 11 + sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \ 12 + mae.o tc.o 12 13 13 14 obj-$(CONFIG_SFC) += sfc.o 14 15
+3
drivers/net/ethernet/sfc/ef100.c
··· 431 431 432 432 probe_data = container_of(efx, struct efx_probe_data, efx); 433 433 ef100_remove_netdev(probe_data); 434 + #ifdef CONFIG_SFC_SRIOV 435 + efx_fini_struct_tc(efx); 436 + #endif 434 437 435 438 ef100_remove(efx); 436 439 efx_fini_io(efx);
+4
drivers/net/ethernet/sfc/ef100_netdev.c
··· 329 329 330 330 ef100_unregister_netdev(efx); 331 331 332 + #ifdef CONFIG_SFC_SRIOV 333 + efx_fini_tc(efx); 334 + #endif 335 + 332 336 down_write(&efx->filter_sem); 333 337 efx_mcdi_filter_table_remove(efx); 334 338 up_write(&efx->filter_sem);
+17
drivers/net/ethernet/sfc/ef100_nic.c
··· 1094 1094 return 0; 1095 1095 1096 1096 #ifdef CONFIG_SFC_SRIOV 1097 + rc = efx_init_struct_tc(efx); 1098 + if (rc) 1099 + return rc; 1100 + 1097 1101 rc = efx_ef100_get_base_mport(efx); 1098 1102 if (rc) { 1099 1103 netif_warn(efx, probe, net_dev, 1100 1104 "Failed to probe base mport rc %d; representors will not function\n", 1105 + rc); 1106 + } 1107 + 1108 + rc = efx_init_tc(efx); 1109 + if (rc) { 1110 + /* Either we don't have an MAE at all (i.e. legacy v-switching), 1111 + * or we do but we failed to probe it. In the latter case, we 1112 + * may not have set up default rules, in which case we won't be 1113 + * able to pass any traffic. However, we don't fail the probe, 1114 + * because the user might need to use the netdevice to apply 1115 + * configuration changes to fix whatever's wrong with the MAE. 1116 + */ 1117 + netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n", 1101 1118 rc); 1102 1119 } 1103 1120 #endif
+16 -4
drivers/net/ethernet/sfc/ef100_rep.c
··· 27 27 efv->parent = efx; 28 28 efv->idx = i; 29 29 INIT_LIST_HEAD(&efv->list); 30 + efv->dflt.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 31 + INIT_LIST_HEAD(&efv->dflt.acts.list); 30 32 INIT_LIST_HEAD(&efv->rx_list); 31 33 spin_lock_init(&efv->rx_lock); 32 34 efv->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE | ··· 214 212 /* mport label should fit in 16 bits */ 215 213 WARN_ON(efv->mport >> 16); 216 214 217 - return 0; 215 + return efx_tc_configure_default_rule_rep(efv); 216 + } 217 + 218 + static void efx_ef100_deconfigure_rep(struct efx_rep *efv) 219 + { 220 + struct efx_nic *efx = efv->parent; 221 + 222 + efx_tc_deconfigure_default_rule(efx, &efv->dflt); 218 223 } 219 224 220 225 static void efx_ef100_rep_destroy_netdev(struct efx_rep *efv) ··· 255 246 pci_err(efx->pci_dev, 256 247 "Failed to configure representor for VF %d, rc %d\n", 257 248 i, rc); 258 - goto fail; 249 + goto fail1; 259 250 } 260 251 rc = register_netdev(efv->net_dev); 261 252 if (rc) { 262 253 pci_err(efx->pci_dev, 263 254 "Failed to register representor for VF %d, rc %d\n", 264 255 i, rc); 265 - goto fail; 256 + goto fail2; 266 257 } 267 258 pci_dbg(efx->pci_dev, "Representor for VF %d is %s\n", i, 268 259 efv->net_dev->name); 269 260 return 0; 270 - fail: 261 + fail2: 262 + efx_ef100_deconfigure_rep(efv); 263 + fail1: 271 264 efx_ef100_rep_destroy_netdev(efv); 272 265 return rc; 273 266 } ··· 283 272 return; 284 273 netif_dbg(efx, drv, rep_dev, "Removing VF representor\n"); 285 274 unregister_netdev(rep_dev); 275 + efx_ef100_deconfigure_rep(efv); 286 276 efx_ef100_rep_destroy_netdev(efv); 287 277 } 288 278
+3
drivers/net/ethernet/sfc/ef100_rep.h
··· 14 14 #define EF100_REP_H 15 15 16 16 #include "net_driver.h" 17 + #include "tc.h" 17 18 18 19 struct efx_rep_sw_stats { 19 20 atomic64_t rx_packets, tx_packets; ··· 33 32 * @write_index: number of packets enqueued to @rx_list 34 33 * @read_index: number of packets consumed from @rx_list 35 34 * @rx_pring_size: max length of RX list 35 + * @dflt: default-rule for MAE switching 36 36 * @list: entry on efx->vf_reps 37 37 * @rx_list: list of SKBs queued for receive in NAPI poll 38 38 * @rx_lock: protects @rx_list ··· 48 46 unsigned int idx; 49 47 unsigned int write_index, read_index; 50 48 unsigned int rx_pring_size; 49 + struct efx_tc_flow_rule dflt; 51 50 struct list_head list; 52 51 struct list_head rx_list; 53 52 spinlock_t rx_lock;
+256 -1
drivers/net/ethernet/sfc/mae.c
··· 11 11 12 12 #include "mae.h" 13 13 #include "mcdi.h" 14 - #include "mcdi_pcol.h" 14 + #include "mcdi_pcol_mae.h" 15 15 16 16 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out) 17 17 { ··· 23 23 *out = EFX_DWORD_VAL(mport); 24 24 } 25 25 26 + void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out) 27 + { 28 + efx_dword_t mport; 29 + 30 + EFX_POPULATE_DWORD_3(mport, 31 + MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, 32 + MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER, 33 + MAE_MPORT_SELECTOR_FUNC_VF_ID, MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL); 34 + *out = EFX_DWORD_VAL(mport); 35 + } 36 + 26 37 void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out) 27 38 { 28 39 efx_dword_t mport; ··· 42 31 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, 43 32 MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER, 44 33 MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id); 34 + *out = EFX_DWORD_VAL(mport); 35 + } 36 + 37 + /* Constructs an mport selector from an mport ID, because they're not the same */ 38 + void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out) 39 + { 40 + efx_dword_t mport; 41 + 42 + EFX_POPULATE_DWORD_2(mport, 43 + MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID, 44 + MAE_MPORT_SELECTOR_MPORT_ID, mport_id); 45 45 *out = EFX_DWORD_VAL(mport); 46 46 } 47 47 ··· 72 50 if (outlen < sizeof(outbuf)) 73 51 return -EIO; 74 52 *id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID); 53 + return 0; 54 + } 55 + 56 + static bool efx_mae_asl_id(u32 id) 57 + { 58 + return !!(id & BIT(31)); 59 + } 60 + 61 + int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) 62 + { 63 + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 64 + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN); 65 + size_t outlen; 66 + int rc; 67 + 68 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 69 + MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 70 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 71 + MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 72 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 73 + MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 74 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, 75 + MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL); 76 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 77 + MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 78 + if (act->deliver) 79 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER, 80 + act->dest_mport); 81 + BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL); 82 + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf), 83 + outbuf, sizeof(outbuf), &outlen); 84 + if (rc) 85 + return rc; 86 + if (outlen < sizeof(outbuf)) 87 + return -EIO; 88 + act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 89 + /* We rely on the high bit of AS IDs always being clear. 90 + * The firmware API guarantees this, but let's check it ourselves. 91 + */ 92 + if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) { 93 + efx_mae_free_action_set(efx, act->fw_id); 94 + return -EIO; 95 + } 96 + return 0; 97 + } 98 + 99 + int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id) 100 + { 101 + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 102 + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1)); 103 + size_t outlen; 104 + int rc; 105 + 106 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id); 107 + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf), 108 + outbuf, sizeof(outbuf), &outlen); 109 + if (rc) 110 + return rc; 111 + if (outlen < sizeof(outbuf)) 112 + return -EIO; 113 + /* FW freed a different ID than we asked for, should never happen. 114 + * Warn because it means we've now got a different idea to the FW of 115 + * what action-sets exist, which could cause mayhem later. 116 + */ 117 + if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id)) 118 + return -EIO; 119 + return 0; 120 + } 121 + 122 + int efx_mae_alloc_action_set_list(struct efx_nic *efx, 123 + struct efx_tc_action_set_list *acts) 124 + { 125 + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN); 126 + struct efx_tc_action_set *act; 127 + size_t inlen, outlen, i = 0; 128 + efx_dword_t *inbuf; 129 + int rc; 130 + 131 + list_for_each_entry(act, &acts->list, list) 132 + i++; 133 + if (i == 0) 134 + return -EINVAL; 135 + if (i == 1) { 136 + /* Don't wrap an ASL around a single AS, just use the AS_ID 137 + * directly. ASLs are a more limited resource. 138 + */ 139 + act = list_first_entry(&acts->list, struct efx_tc_action_set, list); 140 + acts->fw_id = act->fw_id; 141 + return 0; 142 + } 143 + if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2) 144 + return -EOPNOTSUPP; /* Too many actions */ 145 + inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i); 146 + inbuf = kzalloc(inlen, GFP_KERNEL); 147 + if (!inbuf) 148 + return -ENOMEM; 149 + i = 0; 150 + list_for_each_entry(act, &acts->list, list) { 151 + MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS, 152 + i, act->fw_id); 153 + i++; 154 + } 155 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i); 156 + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen, 157 + outbuf, sizeof(outbuf), &outlen); 158 + if (rc) 159 + goto out_free; 160 + if (outlen < sizeof(outbuf)) { 161 + rc = -EIO; 162 + goto out_free; 163 + } 164 + acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID); 165 + /* We rely on the high bit of ASL IDs always being set. 166 + * The firmware API guarantees this, but let's check it ourselves. 167 + */ 168 + if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) { 169 + efx_mae_free_action_set_list(efx, acts); 170 + rc = -EIO; 171 + } 172 + out_free: 173 + kfree(inbuf); 174 + return rc; 175 + } 176 + 177 + int efx_mae_free_action_set_list(struct efx_nic *efx, 178 + struct efx_tc_action_set_list *acts) 179 + { 180 + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1)); 181 + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1)); 182 + size_t outlen; 183 + int rc; 184 + 185 + /* If this is just an AS_ID with no ASL wrapper, then there is 186 + * nothing for us to free. (The AS will be freed later.) 187 + */ 188 + if (efx_mae_asl_id(acts->fw_id)) { 189 + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID, 190 + acts->fw_id); 191 + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf, 192 + sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 193 + if (rc) 194 + return rc; 195 + if (outlen < sizeof(outbuf)) 196 + return -EIO; 197 + /* FW freed a different ID than we asked for, should never happen. 198 + * Warn because it means we've now got a different idea to the FW of 199 + * what action-set-lists exist, which could cause mayhem later. 200 + */ 201 + if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id)) 202 + return -EIO; 203 + } 204 + /* We're probably about to free @acts, but let's just make sure its 205 + * fw_id is blatted so that it won't look valid if it leaks out. 206 + */ 207 + acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL; 208 + return 0; 209 + } 210 + 211 + static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 212 + const struct efx_tc_match *match) 213 + { 214 + if (match->mask.ingress_port) { 215 + if (~match->mask.ingress_port) 216 + return -EOPNOTSUPP; 217 + MCDI_STRUCT_SET_DWORD(match_crit, 218 + MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR, 219 + match->value.ingress_port); 220 + } 221 + MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 222 + match->mask.ingress_port); 223 + return 0; 224 + } 225 + 226 + int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, 227 + u32 prio, u32 acts_id, u32 *id) 228 + { 229 + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN)); 230 + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 231 + MCDI_DECLARE_STRUCT_PTR(match_crit); 232 + MCDI_DECLARE_STRUCT_PTR(response); 233 + size_t outlen; 234 + int rc; 235 + 236 + if (!id) 237 + return -EINVAL; 238 + 239 + match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA); 240 + response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE); 241 + if (efx_mae_asl_id(acts_id)) { 242 + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 243 + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 244 + MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 245 + } else { 246 + /* We only had one AS, so we didn't wrap it in an ASL */ 247 + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 248 + MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 249 + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 250 + } 251 + MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio); 252 + rc = efx_mae_populate_match_criteria(match_crit, match); 253 + if (rc) 254 + return rc; 255 + 256 + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf), 257 + outbuf, sizeof(outbuf), &outlen); 258 + if (rc) 259 + return rc; 260 + if (outlen < sizeof(outbuf)) 261 + return -EIO; 262 + *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 263 + return 0; 264 + } 265 + 266 + int efx_mae_delete_rule(struct efx_nic *efx, u32 id) 267 + { 268 + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 269 + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1)); 270 + size_t outlen; 271 + int rc; 272 + 273 + MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id); 274 + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf), 275 + outbuf, sizeof(outbuf), &outlen); 276 + if (rc) 277 + return rc; 278 + if (outlen < sizeof(outbuf)) 279 + return -EIO; 280 + /* FW freed a different ID than we asked for, should also never happen. 281 + * Warn because it means we've now got a different idea to the FW of 282 + * what rules exist, which could cause mayhem later. 283 + */ 284 + if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id)) 285 + return -EIO; 75 286 return 0; 76 287 }
+16
drivers/net/ethernet/sfc/mae.h
··· 14 14 /* MCDI interface for the ef100 Match-Action Engine */ 15 15 16 16 #include "net_driver.h" 17 + #include "tc.h" 18 + #include "mcdi_pcol.h" /* needed for various MC_CMD_MAE_*_NULL defines */ 17 19 18 20 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out); 21 + void efx_mae_mport_uplink(struct efx_nic *efx, u32 *out); 19 22 void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out); 23 + void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out); 20 24 21 25 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id); 26 + 27 + int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act); 28 + int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id); 29 + 30 + int efx_mae_alloc_action_set_list(struct efx_nic *efx, 31 + struct efx_tc_action_set_list *acts); 32 + int efx_mae_free_action_set_list(struct efx_nic *efx, 33 + struct efx_tc_action_set_list *acts); 34 + 35 + int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, 36 + u32 prio, u32 acts_id, u32 *id); 37 + int efx_mae_delete_rule(struct efx_nic *efx, u32 id); 22 38 23 39 #endif /* EF100_MAE_H */
+4
drivers/net/ethernet/sfc/mcdi.h
··· 205 205 ((_ofst) + BUILD_BUG_ON_ZERO((_ofst) & (_align - 1))) 206 206 #define _MCDI_DWORD(_buf, _field) \ 207 207 ((_buf) + (_MCDI_CHECK_ALIGN(MC_CMD_ ## _field ## _OFST, 4) >> 2)) 208 + #define _MCDI_STRUCT_DWORD(_buf, _field) \ 209 + ((_buf) + (_MCDI_CHECK_ALIGN(_field ## _OFST, 4) >> 2)) 208 210 209 211 #define MCDI_BYTE(_buf, _field) \ 210 212 ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \ ··· 216 214 le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field))) 217 215 #define MCDI_SET_DWORD(_buf, _field, _value) \ 218 216 EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0, _value) 217 + #define MCDI_STRUCT_SET_DWORD(_buf, _field, _value) \ 218 + EFX_POPULATE_DWORD_1(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0, _value) 219 219 #define MCDI_DWORD(_buf, _field) \ 220 220 EFX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0) 221 221 #define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1) \
+24
drivers/net/ethernet/sfc/mcdi_pcol_mae.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /**************************************************************************** 3 + * Driver for Solarflare network controllers and boards 4 + * Copyright 2019 Solarflare Communications Inc. 5 + * Copyright 2019-2022 Xilinx, Inc. 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License version 2 as published 9 + * by the Free Software Foundation, incorporated herein by reference. 10 + */ 11 + 12 + #ifndef MCDI_PCOL_MAE_H 13 + #define MCDI_PCOL_MAE_H 14 + /* MCDI definitions for Match-Action Engine functionality, that are 15 + * missing from the main mcdi_pcol.h 16 + */ 17 + 18 + /* MC_CMD_MAE_COUNTER_LIST_ALLOC is not (yet) a released API, but the 19 + * following value is needed as an argument to MC_CMD_MAE_ACTION_SET_ALLOC. 20 + */ 21 + /* enum: A counter ID that is guaranteed never to represent a real counter */ 22 + #define MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL 0xffffffff 23 + 24 + #endif /* MCDI_PCOL_MAE_H */
+2
drivers/net/ethernet/sfc/net_driver.h
··· 978 978 * @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their 979 979 * xdp_rxq_info structures? 980 980 * @netdev_notifier: Netdevice notifier. 981 + * @tc: state for TC offload (EF100). 981 982 * @mem_bar: The BAR that is mapped into membase. 982 983 * @reg_base: Offset from the start of the bar to the function control window. 983 984 * @monitor_work: Hardware monitor workitem ··· 1162 1161 bool xdp_rxq_info_failed; 1163 1162 1164 1163 struct notifier_block netdev_notifier; 1164 + struct efx_tc_state *tc; 1165 1165 1166 1166 unsigned int mem_bar; 1167 1167 u32 reg_base;
+183
drivers/net/ethernet/sfc/tc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /**************************************************************************** 3 + * Driver for Solarflare network controllers and boards 4 + * Copyright 2019 Solarflare Communications Inc. 5 + * Copyright 2020-2022 Xilinx Inc. 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License version 2 as published 9 + * by the Free Software Foundation, incorporated herein by reference. 10 + */ 11 + 12 + #include "tc.h" 13 + #include "mae.h" 14 + #include "ef100_rep.h" 15 + 16 + static void efx_tc_free_action_set(struct efx_nic *efx, 17 + struct efx_tc_action_set *act, bool in_hw) 18 + { 19 + /* Failure paths calling this on the 'running action' set in_hw=false, 20 + * because if the alloc had succeeded we'd've put it in acts.list and 21 + * not still have it in act. 22 + */ 23 + if (in_hw) { 24 + efx_mae_free_action_set(efx, act->fw_id); 25 + /* in_hw is true iff we are on an acts.list; make sure to 26 + * remove ourselves from that list before we are freed. 27 + */ 28 + list_del(&act->list); 29 + } 30 + kfree(act); 31 + } 32 + 33 + static void efx_tc_free_action_set_list(struct efx_nic *efx, 34 + struct efx_tc_action_set_list *acts, 35 + bool in_hw) 36 + { 37 + struct efx_tc_action_set *act, *next; 38 + 39 + /* Failure paths set in_hw=false, because usually the acts didn't get 40 + * to efx_mae_alloc_action_set_list(); if they did, the failure tree 41 + * has a separate efx_mae_free_action_set_list() before calling us. 42 + */ 43 + if (in_hw) 44 + efx_mae_free_action_set_list(efx, acts); 45 + /* Any act that's on the list will be in_hw even if the list isn't */ 46 + list_for_each_entry_safe(act, next, &acts->list, list) 47 + efx_tc_free_action_set(efx, act, true); 48 + /* Don't kfree, as acts is embedded inside a struct efx_tc_flow_rule */ 49 + } 50 + 51 + static void efx_tc_delete_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rule) 52 + { 53 + efx_mae_delete_rule(efx, rule->fw_id); 54 + 55 + /* Release entries in subsidiary tables */ 56 + efx_tc_free_action_set_list(efx, &rule->acts, true); 57 + rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 58 + } 59 + 60 + static int efx_tc_configure_default_rule(struct efx_nic *efx, u32 ing_port, 61 + u32 eg_port, struct efx_tc_flow_rule *rule) 62 + { 63 + struct efx_tc_action_set_list *acts = &rule->acts; 64 + struct efx_tc_match *match = &rule->match; 65 + struct efx_tc_action_set *act; 66 + int rc; 67 + 68 + match->value.ingress_port = ing_port; 69 + match->mask.ingress_port = ~0; 70 + act = kzalloc(sizeof(*act), GFP_KERNEL); 71 + if (!act) 72 + return -ENOMEM; 73 + act->deliver = 1; 74 + act->dest_mport = eg_port; 75 + rc = efx_mae_alloc_action_set(efx, act); 76 + if (rc) 77 + goto fail1; 78 + EFX_WARN_ON_PARANOID(!list_empty(&acts->list)); 79 + list_add_tail(&act->list, &acts->list); 80 + rc = efx_mae_alloc_action_set_list(efx, acts); 81 + if (rc) 82 + goto fail2; 83 + rc = efx_mae_insert_rule(efx, match, EFX_TC_PRIO_DFLT, 84 + acts->fw_id, &rule->fw_id); 85 + if (rc) 86 + goto fail3; 87 + return 0; 88 + fail3: 89 + efx_mae_free_action_set_list(efx, acts); 90 + fail2: 91 + list_del(&act->list); 92 + efx_mae_free_action_set(efx, act->fw_id); 93 + fail1: 94 + kfree(act); 95 + return rc; 96 + } 97 + 98 + static int efx_tc_configure_default_rule_pf(struct efx_nic *efx) 99 + { 100 + struct efx_tc_flow_rule *rule = &efx->tc->dflt.pf; 101 + u32 ing_port, eg_port; 102 + 103 + efx_mae_mport_uplink(efx, &ing_port); 104 + efx_mae_mport_wire(efx, &eg_port); 105 + return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule); 106 + } 107 + 108 + static int efx_tc_configure_default_rule_wire(struct efx_nic *efx) 109 + { 110 + struct efx_tc_flow_rule *rule = &efx->tc->dflt.wire; 111 + u32 ing_port, eg_port; 112 + 113 + efx_mae_mport_wire(efx, &ing_port); 114 + efx_mae_mport_uplink(efx, &eg_port); 115 + return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule); 116 + } 117 + 118 + int efx_tc_configure_default_rule_rep(struct efx_rep *efv) 119 + { 120 + struct efx_tc_flow_rule *rule = &efv->dflt; 121 + struct efx_nic *efx = efv->parent; 122 + u32 ing_port, eg_port; 123 + 124 + efx_mae_mport_mport(efx, efv->mport, &ing_port); 125 + efx_mae_mport_uplink(efx, &eg_port); 126 + return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule); 127 + } 128 + 129 + void efx_tc_deconfigure_default_rule(struct efx_nic *efx, 130 + struct efx_tc_flow_rule *rule) 131 + { 132 + if (rule->fw_id != MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL) 133 + efx_tc_delete_rule(efx, rule); 134 + rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 135 + } 136 + 137 + int efx_init_tc(struct efx_nic *efx) 138 + { 139 + int rc; 140 + 141 + rc = efx_tc_configure_default_rule_pf(efx); 142 + if (rc) 143 + return rc; 144 + return efx_tc_configure_default_rule_wire(efx); 145 + } 146 + 147 + void efx_fini_tc(struct efx_nic *efx) 148 + { 149 + /* We can get called even if efx_init_struct_tc() failed */ 150 + if (!efx->tc) 151 + return; 152 + efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf); 153 + efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire); 154 + } 155 + 156 + int efx_init_struct_tc(struct efx_nic *efx) 157 + { 158 + if (efx->type->is_vf) 159 + return 0; 160 + 161 + efx->tc = kzalloc(sizeof(*efx->tc), GFP_KERNEL); 162 + if (!efx->tc) 163 + return -ENOMEM; 164 + 165 + INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list); 166 + efx->tc->dflt.pf.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 167 + INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list); 168 + efx->tc->dflt.wire.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 169 + return 0; 170 + } 171 + 172 + void efx_fini_struct_tc(struct efx_nic *efx) 173 + { 174 + if (!efx->tc) 175 + return; 176 + 177 + EFX_WARN_ON_PARANOID(efx->tc->dflt.pf.fw_id != 178 + MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 179 + EFX_WARN_ON_PARANOID(efx->tc->dflt.wire.fw_id != 180 + MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 181 + kfree(efx->tc); 182 + efx->tc = NULL; 183 + }
+76
drivers/net/ethernet/sfc/tc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /**************************************************************************** 3 + * Driver for Solarflare network controllers and boards 4 + * Copyright 2019 Solarflare Communications Inc. 5 + * Copyright 2020-2022 Xilinx Inc. 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License version 2 as published 9 + * by the Free Software Foundation, incorporated herein by reference. 10 + */ 11 + 12 + #ifndef EFX_TC_H 13 + #define EFX_TC_H 14 + #include "net_driver.h" 15 + 16 + struct efx_tc_action_set { 17 + u16 deliver:1; 18 + u32 dest_mport; 19 + u32 fw_id; /* index of this entry in firmware actions table */ 20 + struct list_head list; 21 + }; 22 + 23 + struct efx_tc_match_fields { 24 + /* L1 */ 25 + u32 ingress_port; 26 + }; 27 + 28 + struct efx_tc_match { 29 + struct efx_tc_match_fields value; 30 + struct efx_tc_match_fields mask; 31 + }; 32 + 33 + struct efx_tc_action_set_list { 34 + struct list_head list; 35 + u32 fw_id; 36 + }; 37 + 38 + struct efx_tc_flow_rule { 39 + struct efx_tc_match match; 40 + struct efx_tc_action_set_list acts; 41 + u32 fw_id; 42 + }; 43 + 44 + enum efx_tc_rule_prios { 45 + EFX_TC_PRIO_DFLT, /* Default switch rule; one of efx_tc_default_rules */ 46 + EFX_TC_PRIO__NUM 47 + }; 48 + 49 + /** 50 + * struct efx_tc_state - control plane data for TC offload 51 + * 52 + * @dflt: Match-action rules for default switching; at priority 53 + * %EFX_TC_PRIO_DFLT. Named by *ingress* port 54 + * @dflt.pf: rule for traffic ingressing from PF (egresses to wire) 55 + * @dflt.wire: rule for traffic ingressing from wire (egresses to PF) 56 + */ 57 + struct efx_tc_state { 58 + struct { 59 + struct efx_tc_flow_rule pf; 60 + struct efx_tc_flow_rule wire; 61 + } dflt; 62 + }; 63 + 64 + struct efx_rep; 65 + 66 + int efx_tc_configure_default_rule_rep(struct efx_rep *efv); 67 + void efx_tc_deconfigure_default_rule(struct efx_nic *efx, 68 + struct efx_tc_flow_rule *rule); 69 + 70 + int efx_init_tc(struct efx_nic *efx); 71 + void efx_fini_tc(struct efx_nic *efx); 72 + 73 + int efx_init_struct_tc(struct efx_nic *efx); 74 + void efx_fini_struct_tc(struct efx_nic *efx); 75 + 76 + #endif /* EFX_TC_H */