1*6da67e70SIvan Malov /* SPDX-License-Identifier: BSD-3-Clause 2*6da67e70SIvan Malov * 3*6da67e70SIvan Malov * Copyright(c) 2022 Xilinx, Inc. 4*6da67e70SIvan Malov */ 5*6da67e70SIvan Malov 6*6da67e70SIvan Malov #include <stdbool.h> 7*6da67e70SIvan Malov #include <stdint.h> 8*6da67e70SIvan Malov 9*6da67e70SIvan Malov #include <rte_common.h> 10*6da67e70SIvan Malov #include <rte_flow.h> 11*6da67e70SIvan Malov #include <rte_tailq.h> 12*6da67e70SIvan Malov 13*6da67e70SIvan Malov #include "efx.h" 14*6da67e70SIvan Malov 15*6da67e70SIvan Malov #include "sfc.h" 16*6da67e70SIvan Malov #include "sfc_debug.h" 17*6da67e70SIvan Malov #include "sfc_flow_rss.h" 18*6da67e70SIvan Malov #include "sfc_log.h" 19*6da67e70SIvan Malov #include "sfc_rx.h" 20*6da67e70SIvan Malov 21*6da67e70SIvan Malov int 22*6da67e70SIvan Malov sfc_flow_rss_attach(struct sfc_adapter *sa) 23*6da67e70SIvan Malov { 24*6da67e70SIvan Malov struct sfc_flow_rss *flow_rss = &sa->flow_rss; 25*6da67e70SIvan Malov 26*6da67e70SIvan Malov sfc_log_init(sa, "entry"); 27*6da67e70SIvan Malov 28*6da67e70SIvan Malov TAILQ_INIT(&flow_rss->ctx_list); 29*6da67e70SIvan Malov 30*6da67e70SIvan Malov sfc_log_init(sa, "done"); 31*6da67e70SIvan Malov 32*6da67e70SIvan Malov return 0; 33*6da67e70SIvan Malov } 34*6da67e70SIvan Malov 35*6da67e70SIvan Malov void 36*6da67e70SIvan Malov sfc_flow_rss_detach(struct sfc_adapter *sa) 37*6da67e70SIvan Malov { 38*6da67e70SIvan Malov sfc_log_init(sa, "entry"); 39*6da67e70SIvan Malov 40*6da67e70SIvan Malov sfc_log_init(sa, "done"); 41*6da67e70SIvan Malov } 42*6da67e70SIvan Malov 43*6da67e70SIvan Malov int 44*6da67e70SIvan Malov sfc_flow_rss_parse_conf(struct sfc_adapter *sa, 45*6da67e70SIvan Malov const struct rte_flow_action_rss *in, 46*6da67e70SIvan Malov struct sfc_flow_rss_conf *out, uint16_t *sw_qid_minp) 47*6da67e70SIvan Malov { 48*6da67e70SIvan Malov struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); 49*6da67e70SIvan Malov const struct sfc_rss *ethdev_rss = &sas->rss; 50*6da67e70SIvan Malov uint16_t sw_qid_min; 51*6da67e70SIvan Malov uint16_t sw_qid_max; 52*6da67e70SIvan Malov const uint8_t *key; 53*6da67e70SIvan Malov unsigned int i; 54*6da67e70SIvan Malov int rc; 55*6da67e70SIvan Malov 56*6da67e70SIvan Malov if (in->level) { 57*6da67e70SIvan Malov /* 58*6da67e70SIvan Malov * The caller demands that RSS hash be computed 59*6da67e70SIvan Malov * within the given encapsulation frame / level. 60*6da67e70SIvan Malov * Per flow control for that is not implemented. 61*6da67e70SIvan Malov */ 62*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'level' must be 0"); 63*6da67e70SIvan Malov return EINVAL; 64*6da67e70SIvan Malov } 65*6da67e70SIvan Malov 66*6da67e70SIvan Malov if (in->types != 0) { 67*6da67e70SIvan Malov rc = sfc_rx_hf_rte_to_efx(sa, in->types, 68*6da67e70SIvan Malov &out->efx_hash_types); 69*6da67e70SIvan Malov if (rc != 0) { 70*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: failed to process 'types'"); 71*6da67e70SIvan Malov return rc; 72*6da67e70SIvan Malov } 73*6da67e70SIvan Malov } else { 74*6da67e70SIvan Malov sfc_dbg(sa, "flow-rss: parse: 'types' is 0; proceeding with ethdev setting"); 75*6da67e70SIvan Malov out->efx_hash_types = ethdev_rss->hash_types; 76*6da67e70SIvan Malov } 77*6da67e70SIvan Malov 78*6da67e70SIvan Malov if (in->key_len != 0) { 79*6da67e70SIvan Malov if (in->key_len != sizeof(out->key)) { 80*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'key_len' must be either %zu or 0", 81*6da67e70SIvan Malov sizeof(out->key)); 82*6da67e70SIvan Malov return EINVAL; 83*6da67e70SIvan Malov } 84*6da67e70SIvan Malov 85*6da67e70SIvan Malov if (in->key == NULL) { 86*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'key' is NULL"); 87*6da67e70SIvan Malov return EINVAL; 88*6da67e70SIvan Malov } 89*6da67e70SIvan Malov 90*6da67e70SIvan Malov key = in->key; 91*6da67e70SIvan Malov } else { 92*6da67e70SIvan Malov sfc_dbg(sa, "flow-rss: parse: 'key_len' is 0; proceeding with ethdev key"); 93*6da67e70SIvan Malov key = ethdev_rss->key; 94*6da67e70SIvan Malov } 95*6da67e70SIvan Malov 96*6da67e70SIvan Malov rte_memcpy(out->key, key, sizeof(out->key)); 97*6da67e70SIvan Malov 98*6da67e70SIvan Malov switch (in->func) { 99*6da67e70SIvan Malov case RTE_ETH_HASH_FUNCTION_DEFAULT: 100*6da67e70SIvan Malov /* 101*6da67e70SIvan Malov * DEFAULT means that conformance to a specific 102*6da67e70SIvan Malov * hash algorithm is a don't care to the caller. 103*6da67e70SIvan Malov * The driver can pick the one it deems optimal. 104*6da67e70SIvan Malov */ 105*6da67e70SIvan Malov break; 106*6da67e70SIvan Malov case RTE_ETH_HASH_FUNCTION_TOEPLITZ: 107*6da67e70SIvan Malov if (ethdev_rss->hash_alg != EFX_RX_HASHALG_TOEPLITZ) { 108*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'func' TOEPLITZ is unavailable; use DEFAULT"); 109*6da67e70SIvan Malov return EINVAL; 110*6da67e70SIvan Malov } 111*6da67e70SIvan Malov break; 112*6da67e70SIvan Malov default: 113*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'func' #%d is unsupported", in->func); 114*6da67e70SIvan Malov return EINVAL; 115*6da67e70SIvan Malov } 116*6da67e70SIvan Malov 117*6da67e70SIvan Malov if (in->queue_num == 0) { 118*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'queue_num' is 0; MIN=1"); 119*6da67e70SIvan Malov return EINVAL; 120*6da67e70SIvan Malov } 121*6da67e70SIvan Malov 122*6da67e70SIvan Malov if (in->queue_num > EFX_RSS_TBL_SIZE) { 123*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'queue_num' is too large; MAX=%u", 124*6da67e70SIvan Malov EFX_RSS_TBL_SIZE); 125*6da67e70SIvan Malov return EINVAL; 126*6da67e70SIvan Malov } 127*6da67e70SIvan Malov 128*6da67e70SIvan Malov if (in->queue == NULL) { 129*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: 'queue' is NULL"); 130*6da67e70SIvan Malov return EINVAL; 131*6da67e70SIvan Malov } 132*6da67e70SIvan Malov 133*6da67e70SIvan Malov sw_qid_min = sas->ethdev_rxq_count - 1; 134*6da67e70SIvan Malov sw_qid_max = 0; 135*6da67e70SIvan Malov 136*6da67e70SIvan Malov out->nb_qid_offsets = 0; 137*6da67e70SIvan Malov 138*6da67e70SIvan Malov for (i = 0; i < in->queue_num; ++i) { 139*6da67e70SIvan Malov uint16_t sw_qid = in->queue[i]; 140*6da67e70SIvan Malov 141*6da67e70SIvan Malov if (sw_qid >= sas->ethdev_rxq_count) { 142*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: queue=%u does not exist", 143*6da67e70SIvan Malov sw_qid); 144*6da67e70SIvan Malov return EINVAL; 145*6da67e70SIvan Malov } 146*6da67e70SIvan Malov 147*6da67e70SIvan Malov if (sw_qid < sw_qid_min) 148*6da67e70SIvan Malov sw_qid_min = sw_qid; 149*6da67e70SIvan Malov 150*6da67e70SIvan Malov if (sw_qid > sw_qid_max) 151*6da67e70SIvan Malov sw_qid_max = sw_qid; 152*6da67e70SIvan Malov 153*6da67e70SIvan Malov if (sw_qid != in->queue[0] + i) 154*6da67e70SIvan Malov out->nb_qid_offsets = in->queue_num; 155*6da67e70SIvan Malov } 156*6da67e70SIvan Malov 157*6da67e70SIvan Malov out->qid_span = sw_qid_max - sw_qid_min + 1; 158*6da67e70SIvan Malov 159*6da67e70SIvan Malov if (out->qid_span > EFX_MAXRSS) { 160*6da67e70SIvan Malov sfc_err(sa, "flow-rss: parse: queue ID span %u is too large; MAX=%u", 161*6da67e70SIvan Malov out->qid_span, EFX_MAXRSS); 162*6da67e70SIvan Malov return EINVAL; 163*6da67e70SIvan Malov } 164*6da67e70SIvan Malov 165*6da67e70SIvan Malov if (sw_qid_minp != NULL) 166*6da67e70SIvan Malov *sw_qid_minp = sw_qid_min; 167*6da67e70SIvan Malov 168*6da67e70SIvan Malov return 0; 169*6da67e70SIvan Malov } 170*6da67e70SIvan Malov 171*6da67e70SIvan Malov struct sfc_flow_rss_ctx * 172*6da67e70SIvan Malov sfc_flow_rss_ctx_reuse(struct sfc_adapter *sa, 173*6da67e70SIvan Malov const struct sfc_flow_rss_conf *conf, 174*6da67e70SIvan Malov uint16_t sw_qid_min, const uint16_t *sw_qids) 175*6da67e70SIvan Malov { 176*6da67e70SIvan Malov struct sfc_flow_rss *flow_rss = &sa->flow_rss; 177*6da67e70SIvan Malov static struct sfc_flow_rss_ctx *ctx; 178*6da67e70SIvan Malov 179*6da67e70SIvan Malov SFC_ASSERT(sfc_adapter_is_locked(sa)); 180*6da67e70SIvan Malov 181*6da67e70SIvan Malov TAILQ_FOREACH(ctx, &flow_rss->ctx_list, entries) { 182*6da67e70SIvan Malov if (memcmp(&ctx->conf, conf, sizeof(*conf)) != 0) 183*6da67e70SIvan Malov continue; 184*6da67e70SIvan Malov 185*6da67e70SIvan Malov if (conf->nb_qid_offsets != 0) { 186*6da67e70SIvan Malov bool match_confirmed = true; 187*6da67e70SIvan Malov unsigned int i; 188*6da67e70SIvan Malov 189*6da67e70SIvan Malov for (i = 0; i < conf->nb_qid_offsets; ++i) { 190*6da67e70SIvan Malov uint16_t qid_offset = sw_qids[i] - sw_qid_min; 191*6da67e70SIvan Malov 192*6da67e70SIvan Malov if (ctx->qid_offsets[i] != qid_offset) { 193*6da67e70SIvan Malov match_confirmed = false; 194*6da67e70SIvan Malov break; 195*6da67e70SIvan Malov } 196*6da67e70SIvan Malov } 197*6da67e70SIvan Malov 198*6da67e70SIvan Malov if (!match_confirmed) 199*6da67e70SIvan Malov continue; 200*6da67e70SIvan Malov } 201*6da67e70SIvan Malov 202*6da67e70SIvan Malov sfc_dbg(sa, "flow-rss: reusing ctx=%p", ctx); 203*6da67e70SIvan Malov ++(ctx->refcnt); 204*6da67e70SIvan Malov return ctx; 205*6da67e70SIvan Malov } 206*6da67e70SIvan Malov 207*6da67e70SIvan Malov return NULL; 208*6da67e70SIvan Malov } 209*6da67e70SIvan Malov 210*6da67e70SIvan Malov int 211*6da67e70SIvan Malov sfc_flow_rss_ctx_add(struct sfc_adapter *sa, 212*6da67e70SIvan Malov const struct sfc_flow_rss_conf *conf, uint16_t sw_qid_min, 213*6da67e70SIvan Malov const uint16_t *sw_qids, struct sfc_flow_rss_ctx **ctxp) 214*6da67e70SIvan Malov { 215*6da67e70SIvan Malov struct sfc_flow_rss *flow_rss = &sa->flow_rss; 216*6da67e70SIvan Malov struct sfc_flow_rss_ctx *ctx; 217*6da67e70SIvan Malov 218*6da67e70SIvan Malov SFC_ASSERT(sfc_adapter_is_locked(sa)); 219*6da67e70SIvan Malov 220*6da67e70SIvan Malov ctx = rte_zmalloc("sfc_flow_rss_ctx", sizeof(*ctx), 0); 221*6da67e70SIvan Malov if (ctx == NULL) 222*6da67e70SIvan Malov return ENOMEM; 223*6da67e70SIvan Malov 224*6da67e70SIvan Malov if (conf->nb_qid_offsets != 0) { 225*6da67e70SIvan Malov unsigned int i; 226*6da67e70SIvan Malov 227*6da67e70SIvan Malov ctx->qid_offsets = rte_calloc("sfc_flow_rss_ctx_qid_offsets", 228*6da67e70SIvan Malov conf->nb_qid_offsets, 229*6da67e70SIvan Malov sizeof(*ctx->qid_offsets), 0); 230*6da67e70SIvan Malov if (ctx->qid_offsets == NULL) { 231*6da67e70SIvan Malov rte_free(ctx); 232*6da67e70SIvan Malov return ENOMEM; 233*6da67e70SIvan Malov } 234*6da67e70SIvan Malov 235*6da67e70SIvan Malov for (i = 0; i < conf->nb_qid_offsets; ++i) 236*6da67e70SIvan Malov ctx->qid_offsets[i] = sw_qids[i] - sw_qid_min; 237*6da67e70SIvan Malov } 238*6da67e70SIvan Malov 239*6da67e70SIvan Malov ctx->conf = *conf; 240*6da67e70SIvan Malov ctx->refcnt = 1; 241*6da67e70SIvan Malov 242*6da67e70SIvan Malov TAILQ_INSERT_TAIL(&flow_rss->ctx_list, ctx, entries); 243*6da67e70SIvan Malov 244*6da67e70SIvan Malov *ctxp = ctx; 245*6da67e70SIvan Malov 246*6da67e70SIvan Malov sfc_dbg(sa, "flow-rss: added ctx=%p", ctx); 247*6da67e70SIvan Malov 248*6da67e70SIvan Malov return 0; 249*6da67e70SIvan Malov } 250*6da67e70SIvan Malov 251*6da67e70SIvan Malov void 252*6da67e70SIvan Malov sfc_flow_rss_ctx_del(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx) 253*6da67e70SIvan Malov { 254*6da67e70SIvan Malov struct sfc_flow_rss *flow_rss = &sa->flow_rss; 255*6da67e70SIvan Malov 256*6da67e70SIvan Malov if (ctx == NULL) 257*6da67e70SIvan Malov return; 258*6da67e70SIvan Malov 259*6da67e70SIvan Malov SFC_ASSERT(sfc_adapter_is_locked(sa)); 260*6da67e70SIvan Malov 261*6da67e70SIvan Malov if (ctx->dummy) 262*6da67e70SIvan Malov return; 263*6da67e70SIvan Malov 264*6da67e70SIvan Malov SFC_ASSERT(ctx->refcnt != 0); 265*6da67e70SIvan Malov 266*6da67e70SIvan Malov --(ctx->refcnt); 267*6da67e70SIvan Malov 268*6da67e70SIvan Malov if (ctx->refcnt != 0) 269*6da67e70SIvan Malov return; 270*6da67e70SIvan Malov 271*6da67e70SIvan Malov if (ctx->nic_handle_refcnt != 0) { 272*6da67e70SIvan Malov sfc_err(sa, "flow-rss: deleting ctx=%p abandons its NIC resource: handle=0x%08x, refcnt=%u", 273*6da67e70SIvan Malov ctx, ctx->nic_handle, ctx->nic_handle_refcnt); 274*6da67e70SIvan Malov } 275*6da67e70SIvan Malov 276*6da67e70SIvan Malov TAILQ_REMOVE(&flow_rss->ctx_list, ctx, entries); 277*6da67e70SIvan Malov rte_free(ctx->qid_offsets); 278*6da67e70SIvan Malov rte_free(ctx); 279*6da67e70SIvan Malov 280*6da67e70SIvan Malov sfc_dbg(sa, "flow-rss: deleted ctx=%p", ctx); 281*6da67e70SIvan Malov } 282*6da67e70SIvan Malov 283*6da67e70SIvan Malov static int 284*6da67e70SIvan Malov sfc_flow_rss_ctx_program_tbl(struct sfc_adapter *sa, 285*6da67e70SIvan Malov const struct sfc_flow_rss_ctx *ctx) 286*6da67e70SIvan Malov { 287*6da67e70SIvan Malov const struct sfc_flow_rss_conf *conf = &ctx->conf; 288*6da67e70SIvan Malov unsigned int *tbl = sa->flow_rss.bounce_tbl; 289*6da67e70SIvan Malov unsigned int i; 290*6da67e70SIvan Malov 291*6da67e70SIvan Malov SFC_ASSERT(sfc_adapter_is_locked(sa)); 292*6da67e70SIvan Malov 293*6da67e70SIvan Malov if (conf->nb_qid_offsets != 0) { 294*6da67e70SIvan Malov SFC_ASSERT(ctx->qid_offsets != NULL); 295*6da67e70SIvan Malov 296*6da67e70SIvan Malov for (i = 0; i < EFX_RSS_TBL_SIZE; ++i) 297*6da67e70SIvan Malov tbl[i] = ctx->qid_offsets[i % conf->nb_qid_offsets]; 298*6da67e70SIvan Malov } else { 299*6da67e70SIvan Malov for (i = 0; i < EFX_RSS_TBL_SIZE; ++i) 300*6da67e70SIvan Malov tbl[i] = i % conf->qid_span; 301*6da67e70SIvan Malov } 302*6da67e70SIvan Malov 303*6da67e70SIvan Malov return efx_rx_scale_tbl_set(sa->nic, ctx->nic_handle, 304*6da67e70SIvan Malov tbl, EFX_RSS_TBL_SIZE); 305*6da67e70SIvan Malov } 306*6da67e70SIvan Malov 307*6da67e70SIvan Malov int 308*6da67e70SIvan Malov sfc_flow_rss_ctx_program(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx) 309*6da67e70SIvan Malov { 310*6da67e70SIvan Malov efx_rx_scale_context_type_t ctx_type = EFX_RX_SCALE_EXCLUSIVE; 311*6da67e70SIvan Malov struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); 312*6da67e70SIvan Malov struct sfc_rss *ethdev_rss = &sas->rss; 313*6da67e70SIvan Malov struct sfc_flow_rss_conf *conf; 314*6da67e70SIvan Malov bool allocation_done = B_FALSE; 315*6da67e70SIvan Malov int rc; 316*6da67e70SIvan Malov 317*6da67e70SIvan Malov if (ctx == NULL) 318*6da67e70SIvan Malov return 0; 319*6da67e70SIvan Malov 320*6da67e70SIvan Malov conf = &ctx->conf; 321*6da67e70SIvan Malov 322*6da67e70SIvan Malov SFC_ASSERT(sfc_adapter_is_locked(sa)); 323*6da67e70SIvan Malov 324*6da67e70SIvan Malov if (ctx->nic_handle_refcnt == 0) { 325*6da67e70SIvan Malov rc = efx_rx_scale_context_alloc(sa->nic, ctx_type, 326*6da67e70SIvan Malov conf->qid_span, 327*6da67e70SIvan Malov &ctx->nic_handle); 328*6da67e70SIvan Malov if (rc != 0) { 329*6da67e70SIvan Malov sfc_err(sa, "flow-rss: failed to allocate NIC resource for ctx=%p: type=%d, qid_span=%u, rc=%d", 330*6da67e70SIvan Malov ctx, ctx_type, conf->qid_span, rc); 331*6da67e70SIvan Malov goto fail; 332*6da67e70SIvan Malov } 333*6da67e70SIvan Malov 334*6da67e70SIvan Malov sfc_dbg(sa, "flow-rss: allocated NIC resource for ctx=%p: type=%d, qid_span=%u; handle=0x%08x", 335*6da67e70SIvan Malov ctx, ctx_type, conf->qid_span, 336*6da67e70SIvan Malov ctx->nic_handle); 337*6da67e70SIvan Malov 338*6da67e70SIvan Malov ++(ctx->nic_handle_refcnt); 339*6da67e70SIvan Malov allocation_done = B_TRUE; 340*6da67e70SIvan Malov } else { 341*6da67e70SIvan Malov ++(ctx->nic_handle_refcnt); 342*6da67e70SIvan Malov return 0; 343*6da67e70SIvan Malov } 344*6da67e70SIvan Malov 345*6da67e70SIvan Malov rc = efx_rx_scale_mode_set(sa->nic, ctx->nic_handle, 346*6da67e70SIvan Malov ethdev_rss->hash_alg, 347*6da67e70SIvan Malov (ctx->dummy) ? ethdev_rss->hash_types : 348*6da67e70SIvan Malov conf->efx_hash_types, 349*6da67e70SIvan Malov B_TRUE); 350*6da67e70SIvan Malov if (rc != 0) { 351*6da67e70SIvan Malov sfc_err(sa, "flow-rss: failed to configure hash for ctx=%p: efx_hash_alg=%d, efx_hash_types=0x%08x; rc=%d", 352*6da67e70SIvan Malov ctx, ethdev_rss->hash_alg, 353*6da67e70SIvan Malov (ctx->dummy) ? ethdev_rss->hash_types : 354*6da67e70SIvan Malov conf->efx_hash_types, 355*6da67e70SIvan Malov rc); 356*6da67e70SIvan Malov goto fail; 357*6da67e70SIvan Malov } 358*6da67e70SIvan Malov 359*6da67e70SIvan Malov rc = efx_rx_scale_key_set(sa->nic, ctx->nic_handle, 360*6da67e70SIvan Malov (ctx->dummy) ? ethdev_rss->key : conf->key, 361*6da67e70SIvan Malov RTE_DIM(conf->key)); 362*6da67e70SIvan Malov if (rc != 0) { 363*6da67e70SIvan Malov sfc_err(sa, "flow-rss: failed to set key for ctx=%p; rc=%d", 364*6da67e70SIvan Malov ctx, rc); 365*6da67e70SIvan Malov goto fail; 366*6da67e70SIvan Malov } 367*6da67e70SIvan Malov 368*6da67e70SIvan Malov rc = sfc_flow_rss_ctx_program_tbl(sa, ctx); 369*6da67e70SIvan Malov if (rc != 0) { 370*6da67e70SIvan Malov sfc_err(sa, "flow-rss: failed to program table for ctx=%p; rc=%d", 371*6da67e70SIvan Malov ctx, rc); 372*6da67e70SIvan Malov goto fail; 373*6da67e70SIvan Malov } 374*6da67e70SIvan Malov 375*6da67e70SIvan Malov return 0; 376*6da67e70SIvan Malov 377*6da67e70SIvan Malov fail: 378*6da67e70SIvan Malov if (allocation_done) 379*6da67e70SIvan Malov sfc_flow_rss_ctx_terminate(sa, ctx); 380*6da67e70SIvan Malov 381*6da67e70SIvan Malov return rc; 382*6da67e70SIvan Malov } 383*6da67e70SIvan Malov 384*6da67e70SIvan Malov void 385*6da67e70SIvan Malov sfc_flow_rss_ctx_terminate(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx) 386*6da67e70SIvan Malov { 387*6da67e70SIvan Malov if (ctx == NULL) 388*6da67e70SIvan Malov return; 389*6da67e70SIvan Malov 390*6da67e70SIvan Malov SFC_ASSERT(sfc_adapter_is_locked(sa)); 391*6da67e70SIvan Malov 392*6da67e70SIvan Malov SFC_ASSERT(ctx->nic_handle_refcnt != 0); 393*6da67e70SIvan Malov --(ctx->nic_handle_refcnt); 394*6da67e70SIvan Malov 395*6da67e70SIvan Malov if (ctx->nic_handle_refcnt == 0) { 396*6da67e70SIvan Malov int rc; 397*6da67e70SIvan Malov 398*6da67e70SIvan Malov rc = efx_rx_scale_context_free(sa->nic, ctx->nic_handle); 399*6da67e70SIvan Malov if (rc != 0) { 400*6da67e70SIvan Malov sfc_err(sa, "flow-rss: failed to release NIC resource for ctx=%p: handle=0x%08x; rc=%d", 401*6da67e70SIvan Malov ctx, ctx->nic_handle, rc); 402*6da67e70SIvan Malov 403*6da67e70SIvan Malov sfc_warn(sa, "flow-rss: proceeding despite the prior error"); 404*6da67e70SIvan Malov } 405*6da67e70SIvan Malov 406*6da67e70SIvan Malov sfc_dbg(sa, "flow-rss: released NIC resource for ctx=%p; rc=%d", 407*6da67e70SIvan Malov ctx, rc); 408*6da67e70SIvan Malov } 409*6da67e70SIvan Malov } 410