3c2283b8c6ddd363dcd68383691cdce9566b136d
[dpdk.git] / drivers / net / bnxt / bnxt_rxq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2021 Broadcom
3  * All rights reserved.
4  */
5
6 #include <inttypes.h>
7
8 #include <rte_malloc.h>
9
10 #include "bnxt.h"
11 #include "bnxt_filter.h"
12 #include "bnxt_hwrm.h"
13 #include "bnxt_ring.h"
14 #include "bnxt_rxq.h"
15 #include "bnxt_rxr.h"
16 #include "bnxt_vnic.h"
17 #include "hsi_struct_def_dpdk.h"
18
19 /*
20  * RX Queues
21  */
22
23 uint64_t bnxt_get_rx_port_offloads(struct bnxt *bp)
24 {
25         uint64_t rx_offload_capa;
26
27         rx_offload_capa = RTE_ETH_RX_OFFLOAD_IPV4_CKSUM  |
28                           RTE_ETH_RX_OFFLOAD_UDP_CKSUM   |
29                           RTE_ETH_RX_OFFLOAD_TCP_CKSUM   |
30                           RTE_ETH_RX_OFFLOAD_KEEP_CRC    |
31                           RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
32                           RTE_ETH_RX_OFFLOAD_VLAN_EXTEND |
33                           RTE_ETH_RX_OFFLOAD_TCP_LRO |
34                           RTE_ETH_RX_OFFLOAD_SCATTER |
35                           RTE_ETH_RX_OFFLOAD_RSS_HASH;
36
37         rx_offload_capa |= RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
38                            RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM;
39
40         if (bp->flags & BNXT_FLAG_PTP_SUPPORTED)
41                 rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
42         if (bp->vnic_cap_flags & BNXT_VNIC_CAP_VLAN_RX_STRIP)
43                 rx_offload_capa |= RTE_ETH_RX_OFFLOAD_VLAN_STRIP;
44
45         return rx_offload_capa;
46 }
47
48 /* Determine whether the current configuration needs aggregation ring in HW. */
49 int bnxt_need_agg_ring(struct rte_eth_dev *eth_dev)
50 {
51         /* scattered_rx will be true if OFFLOAD_SCATTER is enabled,
52          * if LRO is enabled, or if the max packet len is greater than the
53          * mbuf data size. So AGG ring will be needed whenever scattered_rx
54          * is set.
55          */
56         return eth_dev->data->scattered_rx ? 1 : 0;
57 }
58
59 void bnxt_free_rxq_stats(struct bnxt_rx_queue *rxq)
60 {
61         if (rxq && rxq->cp_ring && rxq->cp_ring->hw_stats)
62                 rxq->cp_ring->hw_stats = NULL;
63 }
64
65 int bnxt_mq_rx_configure(struct bnxt *bp)
66 {
67         struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf;
68         const struct rte_eth_vmdq_rx_conf *conf =
69                     &dev_conf->rx_adv_conf.vmdq_rx_conf;
70         unsigned int i, j, nb_q_per_grp = 1, ring_idx = 0;
71         int start_grp_id, end_grp_id = 1, rc = 0;
72         struct bnxt_vnic_info *vnic;
73         struct bnxt_filter_info *filter;
74         enum rte_eth_nb_pools pools = 1, max_pools = 0;
75         struct bnxt_rx_queue *rxq;
76
77         bp->nr_vnics = 0;
78
79         /* Multi-queue mode */
80         if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_VMDQ_DCB_RSS) {
81                 /* VMDq ONLY, VMDq+RSS, VMDq+DCB, VMDq+DCB+RSS */
82
83                 switch (dev_conf->rxmode.mq_mode) {
84                 case RTE_ETH_MQ_RX_VMDQ_RSS:
85                 case RTE_ETH_MQ_RX_VMDQ_ONLY:
86                 case RTE_ETH_MQ_RX_VMDQ_DCB_RSS:
87                         /* FALLTHROUGH */
88                         /* ETH_8/64_POOLs */
89                         pools = conf->nb_queue_pools;
90                         /* For each pool, allocate MACVLAN CFA rule & VNIC */
91                         max_pools = RTE_MIN(bp->max_vnics,
92                                             RTE_MIN(bp->max_l2_ctx,
93                                             RTE_MIN(bp->max_rsscos_ctx,
94                                                     RTE_ETH_64_POOLS)));
95                         PMD_DRV_LOG(DEBUG,
96                                     "pools = %u max_pools = %u\n",
97                                     pools, max_pools);
98                         if (pools > max_pools)
99                                 pools = max_pools;
100                         break;
101                 case RTE_ETH_MQ_RX_RSS:
102                         pools = bp->rx_cosq_cnt ? bp->rx_cosq_cnt : 1;
103                         break;
104                 default:
105                         PMD_DRV_LOG(ERR, "Unsupported mq_mod %d\n",
106                                 dev_conf->rxmode.mq_mode);
107                         rc = -EINVAL;
108                         goto err_out;
109                 }
110         } else if (!dev_conf->rxmode.mq_mode) {
111                 pools = bp->rx_cosq_cnt ? bp->rx_cosq_cnt : pools;
112         }
113
114         pools = RTE_MIN(pools, bp->rx_cp_nr_rings);
115         nb_q_per_grp = bp->rx_cp_nr_rings / pools;
116         PMD_DRV_LOG(DEBUG, "pools = %u nb_q_per_grp = %u\n",
117                     pools, nb_q_per_grp);
118         start_grp_id = 0;
119         end_grp_id = nb_q_per_grp;
120
121         for (i = 0; i < pools; i++) {
122                 vnic = &bp->vnic_info[i];
123                 if (!vnic) {
124                         PMD_DRV_LOG(ERR, "VNIC alloc failed\n");
125                         rc = -ENOMEM;
126                         goto err_out;
127                 }
128                 vnic->flags |= BNXT_VNIC_INFO_BCAST;
129                 bp->nr_vnics++;
130
131                 for (j = 0; j < nb_q_per_grp; j++, ring_idx++) {
132                         rxq = bp->eth_dev->data->rx_queues[ring_idx];
133                         rxq->vnic = vnic;
134                         PMD_DRV_LOG(DEBUG,
135                                     "rxq[%d] = %p vnic[%d] = %p\n",
136                                     ring_idx, rxq, i, vnic);
137                 }
138                 if (i == 0) {
139                         if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_VMDQ_DCB) {
140                                 bp->eth_dev->data->promiscuous = 1;
141                                 vnic->flags |= BNXT_VNIC_INFO_PROMISC;
142                         }
143                         vnic->func_default = true;
144                 }
145                 vnic->start_grp_id = start_grp_id;
146                 vnic->end_grp_id = end_grp_id;
147
148                 if (i) {
149                         if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_VMDQ_DCB ||
150                             !(dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_RSS))
151                                 vnic->rss_dflt_cr = true;
152                         goto skip_filter_allocation;
153                 }
154                 filter = bnxt_alloc_filter(bp);
155                 if (!filter) {
156                         PMD_DRV_LOG(ERR, "L2 filter alloc failed\n");
157                         rc = -ENOMEM;
158                         goto err_out;
159                 }
160                 filter->mac_index = 0;
161                 filter->flags |= HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_OUTERMOST;
162                 /*
163                  * TODO: Configure & associate CFA rule for
164                  * each VNIC for each VMDq with MACVLAN, MACVLAN+TC
165                  */
166                 STAILQ_INSERT_TAIL(&vnic->filter, filter, next);
167
168 skip_filter_allocation:
169                 start_grp_id = end_grp_id;
170                 end_grp_id += nb_q_per_grp;
171         }
172
173         bp->rx_num_qs_per_vnic = nb_q_per_grp;
174
175         if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) {
176                 struct rte_eth_rss_conf *rss = &bp->rss_conf;
177
178                 for (i = 0; i < bp->nr_vnics; i++) {
179                         uint32_t lvl = RTE_ETH_RSS_LEVEL(rss->rss_hf);
180
181                         vnic = &bp->vnic_info[i];
182                         vnic->hash_type =
183                                 bnxt_rte_to_hwrm_hash_types(rss->rss_hf);
184                         vnic->hash_mode =
185                                 bnxt_rte_to_hwrm_hash_level(bp,
186                                                             rss->rss_hf,
187                                                             lvl);
188
189                         /*
190                          * Use the supplied key if the key length is
191                          * acceptable and the rss_key is not NULL
192                          */
193                         if (rss->rss_key &&
194                             rss->rss_key_len <= HW_HASH_KEY_SIZE)
195                                 memcpy(vnic->rss_hash_key,
196                                        rss->rss_key, rss->rss_key_len);
197                 }
198         }
199
200         return rc;
201
202 err_out:
203         /* Free allocated vnic/filters */
204
205         return rc;
206 }
207
208 void bnxt_rx_queue_release_mbufs(struct bnxt_rx_queue *rxq)
209 {
210         struct rte_mbuf **sw_ring;
211         struct bnxt_tpa_info *tpa_info;
212         uint16_t i;
213
214         if (!rxq || !rxq->rx_ring)
215                 return;
216
217         sw_ring = rxq->rx_ring->rx_buf_ring;
218         if (sw_ring) {
219 #if defined(RTE_ARCH_X86) || defined(RTE_ARCH_ARM64)
220                 /*
221                  * The vector receive burst function does not set used
222                  * mbuf pointers to NULL, do that here to simplify
223                  * cleanup logic.
224                  */
225                 for (i = 0; i < rxq->rxrearm_nb; i++)
226                         sw_ring[rxq->rxrearm_start + i] = NULL;
227                 rxq->rxrearm_nb = 0;
228 #endif
229                 for (i = 0;
230                      i < rxq->rx_ring->rx_ring_struct->ring_size; i++) {
231                         if (sw_ring[i]) {
232                                 if (sw_ring[i] != &rxq->fake_mbuf)
233                                         rte_pktmbuf_free_seg(sw_ring[i]);
234                                 sw_ring[i] = NULL;
235                         }
236                 }
237         }
238         /* Free up mbufs in Agg ring */
239         if (rxq->bp == NULL ||
240             rxq->bp->eth_dev == NULL ||
241             !bnxt_need_agg_ring(rxq->bp->eth_dev))
242                 return;
243
244         sw_ring = rxq->rx_ring->ag_buf_ring;
245         if (sw_ring) {
246                 for (i = 0;
247                      i < rxq->rx_ring->ag_ring_struct->ring_size; i++) {
248                         if (sw_ring[i]) {
249                                 rte_pktmbuf_free_seg(sw_ring[i]);
250                                 sw_ring[i] = NULL;
251                         }
252                 }
253         }
254
255         /* Free up mbufs in TPA */
256         tpa_info = rxq->rx_ring->tpa_info;
257         if (tpa_info) {
258                 int max_aggs = BNXT_TPA_MAX_AGGS(rxq->bp);
259
260                 for (i = 0; i < max_aggs; i++) {
261                         if (tpa_info[i].mbuf) {
262                                 rte_pktmbuf_free_seg(tpa_info[i].mbuf);
263                                 tpa_info[i].mbuf = NULL;
264                         }
265                 }
266         }
267
268 }
269
270 void bnxt_free_rx_mbufs(struct bnxt *bp)
271 {
272         struct bnxt_rx_queue *rxq;
273         int i;
274
275         for (i = 0; i < (int)bp->rx_nr_rings; i++) {
276                 rxq = bp->rx_queues[i];
277                 bnxt_rx_queue_release_mbufs(rxq);
278         }
279 }
280
281 void bnxt_free_rxq_mem(struct bnxt_rx_queue *rxq)
282 {
283         bnxt_rx_queue_release_mbufs(rxq);
284
285         /* Free RX, AGG ring hardware descriptors */
286         if (rxq->rx_ring) {
287                 bnxt_free_ring(rxq->rx_ring->rx_ring_struct);
288                 rte_free(rxq->rx_ring->rx_ring_struct);
289                 rxq->rx_ring->rx_ring_struct = NULL;
290                 /* Free RX Agg ring hardware descriptors */
291                 bnxt_free_ring(rxq->rx_ring->ag_ring_struct);
292                 rte_free(rxq->rx_ring->ag_ring_struct);
293                 rxq->rx_ring->ag_ring_struct = NULL;
294
295                 rte_free(rxq->rx_ring);
296                 rxq->rx_ring = NULL;
297         }
298         /* Free RX completion ring hardware descriptors */
299         if (rxq->cp_ring) {
300                 bnxt_free_ring(rxq->cp_ring->cp_ring_struct);
301                 rte_free(rxq->cp_ring->cp_ring_struct);
302                 rxq->cp_ring->cp_ring_struct = NULL;
303                 rte_free(rxq->cp_ring);
304                 rxq->cp_ring = NULL;
305         }
306
307         bnxt_free_rxq_stats(rxq);
308         rte_memzone_free(rxq->mz);
309         rxq->mz = NULL;
310 }
311
312 void bnxt_rx_queue_release_op(struct rte_eth_dev *dev, uint16_t queue_idx)
313 {
314         struct bnxt_rx_queue *rxq = dev->data->rx_queues[queue_idx];
315
316         if (rxq != NULL) {
317                 if (is_bnxt_in_error(rxq->bp))
318                         return;
319
320                 bnxt_free_hwrm_rx_ring(rxq->bp, rxq->queue_id);
321                 bnxt_free_rxq_mem(rxq);
322                 rte_free(rxq);
323         }
324 }
325
326 int bnxt_rx_queue_setup_op(struct rte_eth_dev *eth_dev,
327                                uint16_t queue_idx,
328                                uint16_t nb_desc,
329                                unsigned int socket_id,
330                                const struct rte_eth_rxconf *rx_conf,
331                                struct rte_mempool *mp)
332 {
333         struct bnxt *bp = eth_dev->data->dev_private;
334         uint64_t rx_offloads = eth_dev->data->dev_conf.rxmode.offloads;
335         struct bnxt_rx_queue *rxq;
336         int rc = 0;
337
338         rc = is_bnxt_in_error(bp);
339         if (rc)
340                 return rc;
341
342         if (queue_idx >= bnxt_max_rings(bp)) {
343                 PMD_DRV_LOG(ERR,
344                         "Cannot create Rx ring %d. Only %d rings available\n",
345                         queue_idx, bp->max_rx_rings);
346                 return -EINVAL;
347         }
348
349         if (nb_desc < BNXT_MIN_RING_DESC || nb_desc > MAX_RX_DESC_CNT) {
350                 PMD_DRV_LOG(ERR, "nb_desc %d is invalid\n", nb_desc);
351                 return -EINVAL;
352         }
353
354         if (eth_dev->data->rx_queues) {
355                 rxq = eth_dev->data->rx_queues[queue_idx];
356                 if (rxq)
357                         bnxt_rx_queue_release_op(eth_dev, queue_idx);
358         }
359         rxq = rte_zmalloc_socket("bnxt_rx_queue", sizeof(struct bnxt_rx_queue),
360                                  RTE_CACHE_LINE_SIZE, socket_id);
361         if (!rxq) {
362                 PMD_DRV_LOG(ERR, "bnxt_rx_queue allocation failed!\n");
363                 return -ENOMEM;
364         }
365         rxq->bp = bp;
366         rxq->mb_pool = mp;
367         rxq->nb_rx_desc = nb_desc;
368         rxq->rx_free_thresh =
369                 RTE_MIN(rte_align32pow2(nb_desc) / 4, RTE_BNXT_MAX_RX_BURST);
370
371         if (rx_conf->rx_drop_en != BNXT_DEFAULT_RX_DROP_EN)
372                 PMD_DRV_LOG(NOTICE,
373                             "Per-queue config of drop-en is not supported.\n");
374         rxq->drop_en = BNXT_DEFAULT_RX_DROP_EN;
375
376         PMD_DRV_LOG(DEBUG, "RX Buf MTU %d\n", eth_dev->data->mtu);
377
378         eth_dev->data->rx_queues[queue_idx] = rxq;
379
380         rc = bnxt_init_rx_ring_struct(rxq, socket_id);
381         if (rc) {
382                 PMD_DRV_LOG(ERR,
383                             "init_rx_ring_struct failed!\n");
384                 goto err;
385         }
386
387         PMD_DRV_LOG(DEBUG, "RX Buf size is %d\n", rxq->rx_buf_size);
388         rxq->queue_id = queue_idx;
389         rxq->port_id = eth_dev->data->port_id;
390         if (rx_offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC)
391                 rxq->crc_len = RTE_ETHER_CRC_LEN;
392         else
393                 rxq->crc_len = 0;
394
395         /* Allocate RX ring hardware descriptors */
396         rc = bnxt_alloc_rings(bp, socket_id, queue_idx, NULL, rxq, rxq->cp_ring,
397                               NULL, "rxr");
398         if (rc) {
399                 PMD_DRV_LOG(ERR,
400                             "ring_dma_zone_reserve for rx_ring failed!\n");
401                 goto err;
402         }
403         rte_atomic64_init(&rxq->rx_mbuf_alloc_fail);
404
405         /* rxq 0 must not be stopped when used as async CPR */
406         if (!BNXT_NUM_ASYNC_CPR(bp) && queue_idx == 0)
407                 rxq->rx_deferred_start = false;
408         else
409                 rxq->rx_deferred_start = rx_conf->rx_deferred_start;
410
411         rxq->rx_started = rxq->rx_deferred_start ? false : true;
412         rxq->vnic = BNXT_GET_DEFAULT_VNIC(bp);
413
414         /* Configure mtu if it is different from what was configured before */
415         if (!queue_idx)
416                 bnxt_mtu_set_op(eth_dev, eth_dev->data->mtu);
417
418         return 0;
419 err:
420         bnxt_rx_queue_release_op(eth_dev, queue_idx);
421         return rc;
422 }
423
424 int
425 bnxt_rx_queue_intr_enable_op(struct rte_eth_dev *eth_dev, uint16_t queue_id)
426 {
427         struct bnxt *bp = eth_dev->data->dev_private;
428         struct bnxt_rx_queue *rxq;
429         struct bnxt_cp_ring_info *cpr;
430         int rc = 0;
431
432         rc = is_bnxt_in_error(bp);
433         if (rc)
434                 return rc;
435
436         if (eth_dev->data->rx_queues) {
437                 rxq = eth_dev->data->rx_queues[queue_id];
438                 if (!rxq)
439                         return -EINVAL;
440
441                 cpr = rxq->cp_ring;
442                 B_CP_DB_REARM(cpr, cpr->cp_raw_cons);
443         }
444         return rc;
445 }
446
447 int
448 bnxt_rx_queue_intr_disable_op(struct rte_eth_dev *eth_dev, uint16_t queue_id)
449 {
450         struct bnxt *bp = eth_dev->data->dev_private;
451         struct bnxt_rx_queue *rxq;
452         struct bnxt_cp_ring_info *cpr;
453         int rc = 0;
454
455         rc = is_bnxt_in_error(bp);
456         if (rc)
457                 return rc;
458
459         if (eth_dev->data->rx_queues) {
460                 rxq = eth_dev->data->rx_queues[queue_id];
461                 if (!rxq)
462                         return -EINVAL;
463
464                 cpr = rxq->cp_ring;
465                 B_CP_DB_DISARM(cpr);
466         }
467         return rc;
468 }
469
470 int bnxt_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id)
471 {
472         struct bnxt *bp = dev->data->dev_private;
473         struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf;
474         struct bnxt_rx_queue *rxq = bp->rx_queues[rx_queue_id];
475         struct bnxt_vnic_info *vnic = NULL;
476         int rc = 0;
477
478         rc = is_bnxt_in_error(bp);
479         if (rc)
480                 return rc;
481
482         if (rxq == NULL) {
483                 PMD_DRV_LOG(ERR, "Invalid Rx queue %d\n", rx_queue_id);
484                 return -EINVAL;
485         }
486
487         /* Set the queue state to started here.
488          * We check the status of the queue while posting buffer.
489          * If queue is it started, we do not post buffers for Rx.
490          */
491         rxq->rx_started = true;
492         dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
493
494         bnxt_free_hwrm_rx_ring(bp, rx_queue_id);
495         rc = bnxt_alloc_hwrm_rx_ring(bp, rx_queue_id);
496         if (rc)
497                 return rc;
498
499         if (BNXT_CHIP_P5(bp)) {
500                 /* Reconfigure default receive ring and MRU. */
501                 bnxt_hwrm_vnic_cfg(bp, rxq->vnic);
502         }
503         PMD_DRV_LOG(INFO, "Rx queue started %d\n", rx_queue_id);
504
505         if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) {
506                 vnic = rxq->vnic;
507
508                 if (BNXT_HAS_RING_GRPS(bp)) {
509                         if (vnic->fw_grp_ids[rx_queue_id] != INVALID_HW_RING_ID)
510                                 return 0;
511
512                         vnic->fw_grp_ids[rx_queue_id] =
513                                         bp->grp_info[rx_queue_id].fw_grp_id;
514                         PMD_DRV_LOG(DEBUG,
515                                     "vnic = %p fw_grp_id = %d\n",
516                                     vnic, bp->grp_info[rx_queue_id].fw_grp_id);
517                 }
518
519                 PMD_DRV_LOG(DEBUG, "Rx Queue Count %d\n", vnic->rx_queue_cnt);
520                 rc = bnxt_vnic_rss_configure(bp, vnic);
521         }
522
523         if (rc != 0) {
524                 dev->data->rx_queue_state[rx_queue_id] =
525                                 RTE_ETH_QUEUE_STATE_STOPPED;
526                 rxq->rx_started = false;
527         }
528
529         PMD_DRV_LOG(INFO,
530                     "queue %d, rx_deferred_start %d, state %d!\n",
531                     rx_queue_id, rxq->rx_deferred_start,
532                     bp->eth_dev->data->rx_queue_state[rx_queue_id]);
533
534         return rc;
535 }
536
537 int bnxt_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id)
538 {
539         struct bnxt *bp = dev->data->dev_private;
540         struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf;
541         struct bnxt_vnic_info *vnic = NULL;
542         struct bnxt_rx_queue *rxq = NULL;
543         int active_queue_cnt = 0;
544         int i, rc = 0;
545
546         rc = is_bnxt_in_error(bp);
547         if (rc)
548                 return rc;
549
550         /* For the stingray platform and other platforms needing tighter
551          * control of resource utilization, Rx CQ 0 also works as
552          * Default CQ for async notifications
553          */
554         if (!BNXT_NUM_ASYNC_CPR(bp) && !rx_queue_id) {
555                 PMD_DRV_LOG(ERR, "Cannot stop Rx queue id %d\n", rx_queue_id);
556                 return -EINVAL;
557         }
558
559         rxq = bp->rx_queues[rx_queue_id];
560         if (!rxq) {
561                 PMD_DRV_LOG(ERR, "Invalid Rx queue %d\n", rx_queue_id);
562                 return -EINVAL;
563         }
564
565         vnic = rxq->vnic;
566         if (!vnic) {
567                 PMD_DRV_LOG(ERR, "VNIC not initialized for RxQ %d\n",
568                             rx_queue_id);
569                 return -EINVAL;
570         }
571
572         dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
573         rxq->rx_started = false;
574         PMD_DRV_LOG(DEBUG, "Rx queue stopped\n");
575
576         if (dev_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) {
577                 if (BNXT_HAS_RING_GRPS(bp))
578                         vnic->fw_grp_ids[rx_queue_id] = INVALID_HW_RING_ID;
579
580                 PMD_DRV_LOG(DEBUG, "Rx Queue Count %d\n", vnic->rx_queue_cnt);
581                 rc = bnxt_vnic_rss_configure(bp, vnic);
582         }
583
584         /* Compute current number of active receive queues. */
585         for (i = vnic->start_grp_id; i < vnic->end_grp_id; i++)
586                 if (bp->rx_queues[i]->rx_started)
587                         active_queue_cnt++;
588
589         if (BNXT_CHIP_P5(bp)) {
590                 /*
591                  * For Thor, we need to ensure that the VNIC default receive
592                  * ring corresponds to an active receive queue. When no queue
593                  * is active, we need to temporarily set the MRU to zero so
594                  * that packets are dropped early in the receive pipeline in
595                  * order to prevent the VNIC default receive ring from being
596                  * accessed.
597                  */
598                 if (active_queue_cnt == 0) {
599                         uint16_t saved_mru = vnic->mru;
600
601                         /* clear RSS setting on vnic. */
602                         bnxt_vnic_rss_clear_p5(bp, vnic);
603
604                         vnic->mru = 0;
605                         /* Reconfigure default receive ring and MRU. */
606                         bnxt_hwrm_vnic_cfg(bp, vnic);
607                         vnic->mru = saved_mru;
608                 } else {
609                         /* Reconfigure default receive ring. */
610                         bnxt_hwrm_vnic_cfg(bp, vnic);
611                 }
612         } else if (active_queue_cnt) {
613                 /*
614                  * If the queue being stopped is the current default queue and
615                  * there are other active queues, pick one of them as the
616                  * default and reconfigure the vnic.
617                  */
618                 if (vnic->dflt_ring_grp == bp->grp_info[rx_queue_id].fw_grp_id) {
619                         for (i = vnic->start_grp_id; i < vnic->end_grp_id; i++) {
620                                 if (bp->rx_queues[i]->rx_started) {
621                                         vnic->dflt_ring_grp =
622                                                 bp->grp_info[i].fw_grp_id;
623                                         bnxt_hwrm_vnic_cfg(bp, vnic);
624                                         break;
625                                 }
626                         }
627                 }
628         }
629
630         if (rc == 0)
631                 bnxt_rx_queue_release_mbufs(rxq);
632
633         return rc;
634 }