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 #include "efx.h" 16 17 static void efx_tc_free_action_set(struct efx_nic *efx, 18 struct efx_tc_action_set *act, bool in_hw) 19 { 20 /* Failure paths calling this on the 'running action' set in_hw=false, 21 * because if the alloc had succeeded we'd've put it in acts.list and 22 * not still have it in act. 23 */ 24 if (in_hw) { 25 efx_mae_free_action_set(efx, act->fw_id); 26 /* in_hw is true iff we are on an acts.list; make sure to 27 * remove ourselves from that list before we are freed. 28 */ 29 list_del(&act->list); 30 } 31 kfree(act); 32 } 33 34 static void efx_tc_free_action_set_list(struct efx_nic *efx, 35 struct efx_tc_action_set_list *acts, 36 bool in_hw) 37 { 38 struct efx_tc_action_set *act, *next; 39 40 /* Failure paths set in_hw=false, because usually the acts didn't get 41 * to efx_mae_alloc_action_set_list(); if they did, the failure tree 42 * has a separate efx_mae_free_action_set_list() before calling us. 43 */ 44 if (in_hw) 45 efx_mae_free_action_set_list(efx, acts); 46 /* Any act that's on the list will be in_hw even if the list isn't */ 47 list_for_each_entry_safe(act, next, &acts->list, list) 48 efx_tc_free_action_set(efx, act, true); 49 /* Don't kfree, as acts is embedded inside a struct efx_tc_flow_rule */ 50 } 51 52 static void efx_tc_delete_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rule) 53 { 54 efx_mae_delete_rule(efx, rule->fw_id); 55 56 /* Release entries in subsidiary tables */ 57 efx_tc_free_action_set_list(efx, &rule->acts, true); 58 rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 59 } 60 61 static int efx_tc_configure_default_rule(struct efx_nic *efx, u32 ing_port, 62 u32 eg_port, struct efx_tc_flow_rule *rule) 63 { 64 struct efx_tc_action_set_list *acts = &rule->acts; 65 struct efx_tc_match *match = &rule->match; 66 struct efx_tc_action_set *act; 67 int rc; 68 69 match->value.ingress_port = ing_port; 70 match->mask.ingress_port = ~0; 71 act = kzalloc(sizeof(*act), GFP_KERNEL); 72 if (!act) 73 return -ENOMEM; 74 act->deliver = 1; 75 act->dest_mport = eg_port; 76 rc = efx_mae_alloc_action_set(efx, act); 77 if (rc) 78 goto fail1; 79 EFX_WARN_ON_PARANOID(!list_empty(&acts->list)); 80 list_add_tail(&act->list, &acts->list); 81 rc = efx_mae_alloc_action_set_list(efx, acts); 82 if (rc) 83 goto fail2; 84 rc = efx_mae_insert_rule(efx, match, EFX_TC_PRIO_DFLT, 85 acts->fw_id, &rule->fw_id); 86 if (rc) 87 goto fail3; 88 return 0; 89 fail3: 90 efx_mae_free_action_set_list(efx, acts); 91 fail2: 92 list_del(&act->list); 93 efx_mae_free_action_set(efx, act->fw_id); 94 fail1: 95 kfree(act); 96 return rc; 97 } 98 99 static int efx_tc_configure_default_rule_pf(struct efx_nic *efx) 100 { 101 struct efx_tc_flow_rule *rule = &efx->tc->dflt.pf; 102 u32 ing_port, eg_port; 103 104 efx_mae_mport_uplink(efx, &ing_port); 105 efx_mae_mport_wire(efx, &eg_port); 106 return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule); 107 } 108 109 static int efx_tc_configure_default_rule_wire(struct efx_nic *efx) 110 { 111 struct efx_tc_flow_rule *rule = &efx->tc->dflt.wire; 112 u32 ing_port, eg_port; 113 114 efx_mae_mport_wire(efx, &ing_port); 115 efx_mae_mport_uplink(efx, &eg_port); 116 return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule); 117 } 118 119 int efx_tc_configure_default_rule_rep(struct efx_rep *efv) 120 { 121 struct efx_tc_flow_rule *rule = &efv->dflt; 122 struct efx_nic *efx = efv->parent; 123 u32 ing_port, eg_port; 124 125 efx_mae_mport_mport(efx, efv->mport, &ing_port); 126 efx_mae_mport_mport(efx, efx->tc->reps_mport_id, &eg_port); 127 return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule); 128 } 129 130 void efx_tc_deconfigure_default_rule(struct efx_nic *efx, 131 struct efx_tc_flow_rule *rule) 132 { 133 if (rule->fw_id != MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL) 134 efx_tc_delete_rule(efx, rule); 135 rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 136 } 137 138 static int efx_tc_configure_rep_mport(struct efx_nic *efx) 139 { 140 u32 rep_mport_label; 141 int rc; 142 143 rc = efx_mae_allocate_mport(efx, &efx->tc->reps_mport_id, &rep_mport_label); 144 if (rc) 145 return rc; 146 pci_dbg(efx->pci_dev, "created rep mport 0x%08x (0x%04x)\n", 147 efx->tc->reps_mport_id, rep_mport_label); 148 /* Use mport *selector* as vport ID */ 149 efx_mae_mport_mport(efx, efx->tc->reps_mport_id, 150 &efx->tc->reps_mport_vport_id); 151 return 0; 152 } 153 154 static void efx_tc_deconfigure_rep_mport(struct efx_nic *efx) 155 { 156 efx_mae_free_mport(efx, efx->tc->reps_mport_id); 157 efx->tc->reps_mport_id = MAE_MPORT_SELECTOR_NULL; 158 } 159 160 int efx_tc_insert_rep_filters(struct efx_nic *efx) 161 { 162 struct efx_filter_spec promisc, allmulti; 163 int rc; 164 165 if (efx->type->is_vf) 166 return 0; 167 if (!efx->tc) 168 return 0; 169 efx_filter_init_rx(&promisc, EFX_FILTER_PRI_REQUIRED, 0, 0); 170 efx_filter_set_uc_def(&promisc); 171 efx_filter_set_vport_id(&promisc, efx->tc->reps_mport_vport_id); 172 rc = efx_filter_insert_filter(efx, &promisc, false); 173 if (rc < 0) 174 return rc; 175 efx->tc->reps_filter_uc = rc; 176 efx_filter_init_rx(&allmulti, EFX_FILTER_PRI_REQUIRED, 0, 0); 177 efx_filter_set_mc_def(&allmulti); 178 efx_filter_set_vport_id(&allmulti, efx->tc->reps_mport_vport_id); 179 rc = efx_filter_insert_filter(efx, &allmulti, false); 180 if (rc < 0) 181 return rc; 182 efx->tc->reps_filter_mc = rc; 183 return 0; 184 } 185 186 void efx_tc_remove_rep_filters(struct efx_nic *efx) 187 { 188 if (efx->type->is_vf) 189 return; 190 if (!efx->tc) 191 return; 192 if (efx->tc->reps_filter_mc >= 0) 193 efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, efx->tc->reps_filter_mc); 194 efx->tc->reps_filter_mc = -1; 195 if (efx->tc->reps_filter_uc >= 0) 196 efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, efx->tc->reps_filter_uc); 197 efx->tc->reps_filter_uc = -1; 198 } 199 200 int efx_init_tc(struct efx_nic *efx) 201 { 202 int rc; 203 204 rc = efx_tc_configure_default_rule_pf(efx); 205 if (rc) 206 return rc; 207 rc = efx_tc_configure_default_rule_wire(efx); 208 if (rc) 209 return rc; 210 return efx_tc_configure_rep_mport(efx); 211 } 212 213 void efx_fini_tc(struct efx_nic *efx) 214 { 215 /* We can get called even if efx_init_struct_tc() failed */ 216 if (!efx->tc) 217 return; 218 efx_tc_deconfigure_rep_mport(efx); 219 efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf); 220 efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire); 221 } 222 223 int efx_init_struct_tc(struct efx_nic *efx) 224 { 225 if (efx->type->is_vf) 226 return 0; 227 228 efx->tc = kzalloc(sizeof(*efx->tc), GFP_KERNEL); 229 if (!efx->tc) 230 return -ENOMEM; 231 232 efx->tc->reps_filter_uc = -1; 233 efx->tc->reps_filter_mc = -1; 234 INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list); 235 efx->tc->dflt.pf.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 236 INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list); 237 efx->tc->dflt.wire.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; 238 return 0; 239 } 240 241 void efx_fini_struct_tc(struct efx_nic *efx) 242 { 243 if (!efx->tc) 244 return; 245 246 EFX_WARN_ON_PARANOID(efx->tc->dflt.pf.fw_id != 247 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 248 EFX_WARN_ON_PARANOID(efx->tc->dflt.wire.fw_id != 249 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 250 kfree(efx->tc); 251 efx->tc = NULL; 252 } 253