net/cxgbe: rework queue allocation between ports
authorRahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Fri, 11 Sep 2020 23:52:08 +0000 (05:22 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 18 Sep 2020 16:55:12 +0000 (18:55 +0200)
Firmware returns the max queues that can be allocated on the entire
PF. The driver evenly distributes them across all the ports belonging
to the PF. However, some ports may need more queues than others and
this equal distribution scheme prevents accessing these other ports
unused queues. So, remove the equal distribution scheme and allow the
ports to allocate as many queues as they need.

Also remove the hardcoded 64 max limit on queue allocation. Instead,
use the max limit given by firmware.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
drivers/net/cxgbe/base/adapter.h
drivers/net/cxgbe/base/common.h
drivers/net/cxgbe/base/t4_hw.c
drivers/net/cxgbe/cxgbe.h
drivers/net/cxgbe/cxgbe_ethdev.c
drivers/net/cxgbe/cxgbe_filter.c
drivers/net/cxgbe/cxgbe_main.c
drivers/net/cxgbe/cxgbevf_ethdev.c
drivers/net/cxgbe/cxgbevf_main.c
drivers/net/cxgbe/sge.c

index 3e74177..f9c4cde 100644 (file)
@@ -19,7 +19,6 @@
 #include "t4_regs_values.h"
 
 enum {
-       MAX_ETH_QSETS = 64,           /* # of Ethernet Tx/Rx queue sets */
        MAX_CTRL_QUEUES = NCHAN,      /* # of control Tx queues */
 };
 
@@ -47,9 +46,10 @@ struct port_info {
        u8     pidx;                    /* port index for this PF */
        u8     tx_chan;                 /* associated channel */
 
-       u8     n_rx_qsets;              /* # of rx qsets */
-       u8     n_tx_qsets;              /* # of tx qsets */
-       u8     first_qset;              /* index of first qset */
+       u16    n_rx_qsets;              /* # of rx qsets */
+       u16    n_tx_qsets;              /* # of tx qsets */
+       u16    first_rxqset;            /* index of first rxqset */
+       u16    first_txqset;            /* index of first txqset */
 
        u16    *rss;                    /* rss table */
        u8     rss_mode;                /* rss mode */
@@ -274,8 +274,8 @@ struct sge_ctrl_txq {                /* State for an SGE control Tx queue */
 } __rte_cache_aligned;
 
 struct sge {
-       struct sge_eth_txq ethtxq[MAX_ETH_QSETS];
-       struct sge_eth_rxq ethrxq[MAX_ETH_QSETS];
+       struct sge_eth_txq *ethtxq;
+       struct sge_eth_rxq *ethrxq;
        struct sge_rspq fw_evtq __rte_cache_aligned;
        struct sge_ctrl_txq ctrlq[MAX_CTRL_QUEUES];
 
index 79c8fcb..07508a1 100644 (file)
@@ -218,6 +218,7 @@ struct rss_params {
  */
 struct pf_resources {
        unsigned int neq;      /* N egress Qs */
+       unsigned int nethctrl; /* N egress ETH or CTRL Qs */
        unsigned int niqflint; /* N ingress Qs/w free list(s) & intr */
 };
 
index c8514c9..943d94f 100644 (file)
@@ -2517,6 +2517,10 @@ int t4_get_pfres(struct adapter *adapter)
 
        word = be32_to_cpu(rpl.type_to_neq);
        pfres->neq = G_FW_PFVF_CMD_NEQ(word);
+
+       word = be32_to_cpu(rpl.r_caps_to_nethctrl);
+       pfres->nethctrl = G_FW_PFVF_CMD_NETHCTRL(word);
+
        return 0;
 }
 
index 0bf6061..ef62af1 100644 (file)
@@ -98,7 +98,8 @@ int cxgbe_poll_for_completion(struct sge_rspq *q, unsigned int us,
 int cxgbe_link_start(struct port_info *pi);
 int cxgbe_setup_sge_fwevtq(struct adapter *adapter);
 int cxgbe_setup_sge_ctrl_txq(struct adapter *adapter);
-void cxgbe_cfg_queues(struct rte_eth_dev *eth_dev);
+int cxgbe_cfg_queues(struct rte_eth_dev *eth_dev);
+void cxgbe_cfg_queues_free(struct adapter *adapter);
 int cxgbe_cfg_queue_count(struct rte_eth_dev *eth_dev);
 int cxgbe_init_rss(struct adapter *adap);
 int cxgbe_setup_rss(struct port_info *pi);
index 38b4377..329b7cb 100644 (file)
@@ -116,7 +116,6 @@ int cxgbe_dev_info_get(struct rte_eth_dev *eth_dev,
 {
        struct port_info *pi = eth_dev->data->dev_private;
        struct adapter *adapter = pi->adapter;
-       int max_queues = adapter->sge.max_ethqsets / adapter->params.nports;
 
        static const struct rte_eth_desc_lim cxgbe_desc_lim = {
                .nb_max = CXGBE_MAX_RING_DESC_SIZE,
@@ -126,8 +125,8 @@ int cxgbe_dev_info_get(struct rte_eth_dev *eth_dev,
 
        device_info->min_rx_bufsize = CXGBE_MIN_RX_BUFSIZE;
        device_info->max_rx_pktlen = CXGBE_MAX_RX_PKTLEN;
-       device_info->max_rx_queues = max_queues;
-       device_info->max_tx_queues = max_queues;
+       device_info->max_rx_queues = adapter->sge.max_ethqsets;
+       device_info->max_tx_queues = adapter->sge.max_ethqsets;
        device_info->max_mac_addrs = 1;
        /* XXX: For now we support one MAC/port */
        device_info->max_vfs = adapter->params.arch.vfcount;
@@ -501,13 +500,14 @@ int cxgbe_dev_tx_queue_setup(struct rte_eth_dev *eth_dev,
        struct port_info *pi = eth_dev->data->dev_private;
        struct adapter *adapter = pi->adapter;
        struct sge *s = &adapter->sge;
-       struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset + queue_idx];
-       int err = 0;
        unsigned int temp_nb_desc;
+       struct sge_eth_txq *txq;
+       int err = 0;
 
+       txq = &s->ethtxq[pi->first_txqset + queue_idx];
        dev_debug(adapter, "%s: eth_dev->data->nb_tx_queues = %d; queue_idx = %d; nb_desc = %d; socket_id = %d; pi->first_qset = %u\n",
                  __func__, eth_dev->data->nb_tx_queues, queue_idx, nb_desc,
-                 socket_id, pi->first_qset);
+                 socket_id, pi->first_txqset);
 
        /*  Free up the existing queue  */
        if (eth_dev->data->tx_queues[queue_idx]) {
@@ -603,16 +603,16 @@ int cxgbe_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
                             const struct rte_eth_rxconf *rx_conf __rte_unused,
                             struct rte_mempool *mp)
 {
+       unsigned int pkt_len = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
        struct port_info *pi = eth_dev->data->dev_private;
        struct adapter *adapter = pi->adapter;
+       struct rte_eth_dev_info dev_info;
        struct sge *s = &adapter->sge;
-       struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset + queue_idx];
-       int err = 0;
-       int msi_idx = 0;
        unsigned int temp_nb_desc;
-       struct rte_eth_dev_info dev_info;
-       unsigned int pkt_len = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+       int err = 0, msi_idx = 0;
+       struct sge_eth_rxq *rxq;
 
+       rxq = &s->ethrxq[pi->first_rxqset + queue_idx];
        dev_debug(adapter, "%s: eth_dev->data->nb_rx_queues = %d; queue_idx = %d; nb_desc = %d; socket_id = %d; mp = %p\n",
                  __func__, eth_dev->data->nb_rx_queues, queue_idx, nb_desc,
                  socket_id, mp);
@@ -685,11 +685,10 @@ int cxgbe_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
 void cxgbe_dev_rx_queue_release(void *q)
 {
        struct sge_eth_rxq *rxq = (struct sge_eth_rxq *)q;
-       struct sge_rspq *rq = &rxq->rspq;
 
-       if (rq) {
+       if (rxq) {
                struct port_info *pi = (struct port_info *)
-                                      (rq->eth_dev->data->dev_private);
+                                      (rxq->rspq.eth_dev->data->dev_private);
                struct adapter *adap = pi->adapter;
 
                dev_debug(adapter, "%s: pi->port_id = %d; rx_queue_id = %d\n",
@@ -729,7 +728,7 @@ static int cxgbe_dev_stats_get(struct rte_eth_dev *eth_dev,
 
        for (i = 0; i < pi->n_rx_qsets; i++) {
                struct sge_eth_rxq *rxq =
-                       &s->ethrxq[pi->first_qset + i];
+                       &s->ethrxq[pi->first_rxqset + i];
 
                eth_stats->q_ipackets[i] = rxq->stats.pkts;
                eth_stats->q_ibytes[i] = rxq->stats.rx_bytes;
@@ -739,7 +738,7 @@ static int cxgbe_dev_stats_get(struct rte_eth_dev *eth_dev,
 
        for (i = 0; i < pi->n_tx_qsets; i++) {
                struct sge_eth_txq *txq =
-                       &s->ethtxq[pi->first_qset + i];
+                       &s->ethtxq[pi->first_txqset + i];
 
                eth_stats->q_opackets[i] = txq->stats.pkts;
                eth_stats->q_obytes[i] = txq->stats.tx_bytes;
@@ -760,14 +759,14 @@ static int cxgbe_dev_stats_reset(struct rte_eth_dev *eth_dev)
        cxgbe_stats_reset(pi);
        for (i = 0; i < pi->n_rx_qsets; i++) {
                struct sge_eth_rxq *rxq =
-                       &s->ethrxq[pi->first_qset + i];
+                       &s->ethrxq[pi->first_rxqset + i];
 
                rxq->stats.pkts = 0;
                rxq->stats.rx_bytes = 0;
        }
        for (i = 0; i < pi->n_tx_qsets; i++) {
                struct sge_eth_txq *txq =
-                       &s->ethtxq[pi->first_qset + i];
+                       &s->ethtxq[pi->first_txqset + i];
 
                txq->stats.pkts = 0;
                txq->stats.tx_bytes = 0;
index 384dde3..5a7efe7 100644 (file)
@@ -145,7 +145,7 @@ static unsigned int get_filter_steerq(struct rte_eth_dev *dev,
                 * then assume it is an absolute qid.
                 */
                if (fs->iq < pi->n_rx_qsets)
-                       iq = adapter->sge.ethrxq[pi->first_qset +
+                       iq = adapter->sge.ethrxq[pi->first_rxqset +
                                                 fs->iq].rspq.abs_id;
                else
                        iq = fs->iq;
index d0a6422..da4ae25 100644 (file)
@@ -526,22 +526,6 @@ static int tid_init(struct tid_info *t)
        return 0;
 }
 
-static inline bool is_x_1g_port(const struct link_config *lc)
-{
-       return (lc->pcaps & FW_PORT_CAP32_SPEED_1G) != 0;
-}
-
-static inline bool is_x_10g_port(const struct link_config *lc)
-{
-       unsigned int speeds, high_speeds;
-
-       speeds = V_FW_PORT_CAP32_SPEED(G_FW_PORT_CAP32_SPEED(lc->pcaps));
-       high_speeds = speeds &
-                     ~(FW_PORT_CAP32_SPEED_100M | FW_PORT_CAP32_SPEED_1G);
-
-       return high_speeds != 0;
-}
-
 static inline void init_rspq(struct adapter *adap, struct sge_rspq *q,
                      unsigned int us, unsigned int cnt,
                      unsigned int size, unsigned int iqe_size)
@@ -554,20 +538,35 @@ static inline void init_rspq(struct adapter *adap, struct sge_rspq *q,
 
 int cxgbe_cfg_queue_count(struct rte_eth_dev *eth_dev)
 {
-       struct port_info *pi = eth_dev->data->dev_private;
+       struct port_info *temp_pi, *pi = eth_dev->data->dev_private;
        struct adapter *adap = pi->adapter;
+       u16 first_txq = 0, first_rxq = 0;
        struct sge *s = &adap->sge;
-       unsigned int max_queues = s->max_ethqsets / adap->params.nports;
+       u16 i, max_rxqs, max_txqs;
+
+       max_rxqs = s->max_ethqsets;
+       max_txqs = s->max_ethqsets;
+       for_each_port(adap, i) {
+               temp_pi = adap2pinfo(adap, i);
+               if (i == pi->port_id)
+                       break;
+
+               if (max_rxqs <= temp_pi->n_rx_qsets ||
+                   max_txqs <= temp_pi->n_tx_qsets)
+                       return -ENOMEM;
+
+               first_rxq += temp_pi->n_rx_qsets;
+               first_txq += temp_pi->n_tx_qsets;
+               max_rxqs -= temp_pi->n_rx_qsets;
+               max_txqs -= temp_pi->n_tx_qsets;
+       }
 
        if ((eth_dev->data->nb_rx_queues < 1) ||
            (eth_dev->data->nb_tx_queues < 1))
                return -EINVAL;
 
-       if ((eth_dev->data->nb_rx_queues > max_queues) ||
-           (eth_dev->data->nb_tx_queues > max_queues))
-               return -EINVAL;
-
-       if (eth_dev->data->nb_rx_queues > pi->rss_size)
+       if (eth_dev->data->nb_rx_queues > max_rxqs ||
+           eth_dev->data->nb_tx_queues > max_txqs)
                return -EINVAL;
 
        /* We must configure RSS, since config has changed*/
@@ -575,68 +574,66 @@ int cxgbe_cfg_queue_count(struct rte_eth_dev *eth_dev)
 
        pi->n_rx_qsets = eth_dev->data->nb_rx_queues;
        pi->n_tx_qsets = eth_dev->data->nb_tx_queues;
+       pi->first_rxqset = first_rxq;
+       pi->first_txqset = first_txq;
 
        return 0;
 }
 
-void cxgbe_cfg_queues(struct rte_eth_dev *eth_dev)
+void cxgbe_cfg_queues_free(struct adapter *adap)
+{
+       if (adap->sge.ethtxq) {
+               rte_free(adap->sge.ethtxq);
+               adap->sge.ethtxq = NULL;
+       }
+
+       if (adap->sge.ethrxq) {
+               rte_free(adap->sge.ethrxq);
+               adap->sge.ethrxq = NULL;
+       }
+
+       adap->flags &= ~CFG_QUEUES;
+}
+
+int cxgbe_cfg_queues(struct rte_eth_dev *eth_dev)
 {
        struct port_info *pi = eth_dev->data->dev_private;
        struct adapter *adap = pi->adapter;
        struct sge *s = &adap->sge;
-       unsigned int i, nb_ports = 0, qidx = 0;
-       unsigned int q_per_port = 0;
+       u16 i;
 
        if (!(adap->flags & CFG_QUEUES)) {
-               for_each_port(adap, i) {
-                       struct port_info *tpi = adap2pinfo(adap, i);
-
-                       nb_ports += (is_x_10g_port(&tpi->link_cfg)) ||
-                                    is_x_1g_port(&tpi->link_cfg) ? 1 : 0;
-               }
-
-               /*
-                * We default up to # of cores queues per 1G/10G port.
-                */
-               if (nb_ports)
-                       q_per_port = (s->max_ethqsets -
-                                    (adap->params.nports - nb_ports)) /
-                                    nb_ports;
-
-               if (q_per_port > rte_lcore_count())
-                       q_per_port = rte_lcore_count();
-
-               for_each_port(adap, i) {
-                       struct port_info *pi = adap2pinfo(adap, i);
-
-                       pi->first_qset = qidx;
-
-                       /* Initially n_rx_qsets == n_tx_qsets */
-                       pi->n_rx_qsets = (is_x_10g_port(&pi->link_cfg) ||
-                                         is_x_1g_port(&pi->link_cfg)) ?
-                                         q_per_port : 1;
-                       pi->n_tx_qsets = pi->n_rx_qsets;
-
-                       if (pi->n_rx_qsets > pi->rss_size)
-                               pi->n_rx_qsets = pi->rss_size;
+               s->ethrxq = rte_calloc_socket(NULL, s->max_ethqsets,
+                                             sizeof(struct sge_eth_rxq), 0,
+                                             rte_socket_id());
+               if (!s->ethrxq)
+                       return -ENOMEM;
 
-                       qidx += pi->n_rx_qsets;
+               s->ethtxq = rte_calloc_socket(NULL, s->max_ethqsets,
+                                             sizeof(struct sge_eth_txq), 0,
+                                             rte_socket_id());
+               if (!s->ethtxq) {
+                       rte_free(s->ethrxq);
+                       s->ethrxq = NULL;
+                       return -ENOMEM;
                }
 
-               for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) {
+               for (i = 0; i < s->max_ethqsets; i++) {
                        struct sge_eth_rxq *r = &s->ethrxq[i];
+                       struct sge_eth_txq *t = &s->ethtxq[i];
 
                        init_rspq(adap, &r->rspq, 5, 32, 1024, 64);
                        r->usembufs = 1;
                        r->fl.size = (r->usembufs ? 1024 : 72);
-               }
 
-               for (i = 0; i < ARRAY_SIZE(s->ethtxq); i++)
-                       s->ethtxq[i].q.size = 1024;
+                       t->q.size = 1024;
+               }
 
                init_rspq(adap, &adap->sge.fw_evtq, 0, 0, 1024, 64);
                adap->flags |= CFG_QUEUES;
        }
+
+       return 0;
 }
 
 void cxgbe_stats_get(struct port_info *pi, struct port_stats *stats)
@@ -1043,34 +1040,31 @@ static void configure_pcie_ext_tag(struct adapter *adapter)
 /* Figure out how many Queue Sets we can support */
 void cxgbe_configure_max_ethqsets(struct adapter *adapter)
 {
-       unsigned int ethqsets;
+       unsigned int ethqsets, reserved;
 
-       /*
-        * We need to reserve an Ingress Queue for the Asynchronous Firmware
-        * Event Queue.
+       /* We need to reserve an Ingress Queue for the Asynchronous Firmware
+        * Event Queue and 1 Control Queue per port.
         *
         * For each Queue Set, we'll need the ability to allocate two Egress
         * Contexts -- one for the Ingress Queue Free List and one for the TX
         * Ethernet Queue.
         */
+       reserved = max(adapter->params.nports, 1);
        if (is_pf4(adapter)) {
                struct pf_resources *pfres = &adapter->params.pfres;
 
-               ethqsets = pfres->niqflint - 1;
-               if (pfres->neq < ethqsets * 2)
+               ethqsets = min(pfres->niqflint, pfres->nethctrl);
+               if (ethqsets > (pfres->neq / 2))
                        ethqsets = pfres->neq / 2;
        } else {
                struct vf_resources *vfres = &adapter->params.vfres;
 
-               ethqsets = vfres->niqflint - 1;
-               if (vfres->nethctrl != ethqsets)
-                       ethqsets = min(vfres->nethctrl, ethqsets);
-               if (vfres->neq < ethqsets * 2)
+               ethqsets = min(vfres->niqflint, vfres->nethctrl);
+               if (ethqsets > (vfres->neq / 2))
                        ethqsets = vfres->neq / 2;
        }
 
-       if (ethqsets > MAX_ETH_QSETS)
-               ethqsets = MAX_ETH_QSETS;
+       ethqsets -= reserved;
        adapter->sge.max_ethqsets = ethqsets;
 }
 
@@ -1707,7 +1701,7 @@ int cxgbe_write_rss_conf(const struct port_info *pi, uint64_t rss_hf)
                         F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN |
                         F_FW_RSS_VI_CONFIG_CMD_UDPEN;
 
-       rxq = &adapter->sge.ethrxq[pi->first_qset];
+       rxq = &adapter->sge.ethrxq[pi->first_rxqset];
        rss = rxq[0].rspq.abs_id;
 
        /* If Tunnel All Lookup isn't specified in the global RSS
@@ -1738,7 +1732,7 @@ int cxgbe_write_rss(const struct port_info *pi, const u16 *queues)
        /*  Should never be called before setting up sge eth rx queues */
        BUG_ON(!(adapter->flags & FULL_INIT_DONE));
 
-       rxq = &adapter->sge.ethrxq[pi->first_qset];
+       rxq = &adapter->sge.ethrxq[pi->first_rxqset];
        rss = rte_zmalloc(NULL, pi->rss_size * sizeof(u16), 0);
        if (!rss)
                return -ENOMEM;
@@ -1810,7 +1804,7 @@ void cxgbe_enable_rx_queues(struct port_info *pi)
        unsigned int i;
 
        for (i = 0; i < pi->n_rx_qsets; i++)
-               enable_rx(adap, &s->ethrxq[pi->first_qset + i].rspq);
+               enable_rx(adap, &s->ethrxq[pi->first_rxqset + i].rspq);
 }
 
 /**
@@ -1988,6 +1982,8 @@ void cxgbe_close(struct adapter *adapter)
                adapter->flags &= ~FULL_INIT_DONE;
        }
 
+       cxgbe_cfg_queues_free(adapter);
+
        if (is_pf4(adapter) && (adapter->flags & FW_OK))
                t4_fw_bye(adapter, adapter->mbox);
 }
@@ -2163,7 +2159,9 @@ allocate_mac:
                }
        }
 
-       cxgbe_cfg_queues(adapter->eth_dev);
+       err = cxgbe_cfg_queues(adapter->eth_dev);
+       if (err)
+               goto out_free;
 
        cxgbe_print_adapter_info(adapter);
        cxgbe_print_port_info(adapter);
@@ -2222,6 +2220,8 @@ allocate_mac:
        return 0;
 
 out_free:
+       cxgbe_cfg_queues_free(adapter);
+
        for_each_port(adapter, i) {
                pi = adap2pinfo(adapter, i);
                if (pi->viid != 0)
index b3c885d..947fcdd 100644 (file)
@@ -55,7 +55,7 @@ static int cxgbevf_dev_stats_get(struct rte_eth_dev *eth_dev,
 
        for (i = 0; i < pi->n_rx_qsets; i++) {
                struct sge_eth_rxq *rxq =
-                       &s->ethrxq[pi->first_qset + i];
+                       &s->ethrxq[pi->first_rxqset + i];
 
                eth_stats->q_ipackets[i] = rxq->stats.pkts;
                eth_stats->q_ibytes[i] = rxq->stats.rx_bytes;
@@ -65,7 +65,7 @@ static int cxgbevf_dev_stats_get(struct rte_eth_dev *eth_dev,
 
        for (i = 0; i < pi->n_tx_qsets; i++) {
                struct sge_eth_txq *txq =
-                       &s->ethtxq[pi->first_qset + i];
+                       &s->ethtxq[pi->first_txqset + i];
 
                eth_stats->q_opackets[i] = txq->stats.pkts;
                eth_stats->q_obytes[i] = txq->stats.tx_bytes;
index 9fe0ec6..35d8734 100644 (file)
@@ -278,7 +278,10 @@ allocate_mac:
                }
        }
 
-       cxgbe_cfg_queues(adapter->eth_dev);
+       err = cxgbe_cfg_queues(adapter->eth_dev);
+       if (err)
+               goto out_free;
+
        cxgbe_print_adapter_info(adapter);
        cxgbe_print_port_info(adapter);
 
@@ -293,6 +296,8 @@ allocate_mac:
        return 0;
 
 out_free:
+       cxgbe_cfg_queues_free(adapter);
+
        for_each_port(adapter, i) {
                pi = adap2pinfo(adapter, i);
                if (pi->viid != 0)
index 34e4857..3aeef2e 100644 (file)
@@ -2193,15 +2193,18 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
  */
 void t4_sge_eth_clear_queues(struct port_info *pi)
 {
-       int i;
        struct adapter *adap = pi->adapter;
-       struct sge_eth_rxq *rxq = &adap->sge.ethrxq[pi->first_qset];
-       struct sge_eth_txq *txq = &adap->sge.ethtxq[pi->first_qset];
+       struct sge_eth_rxq *rxq;
+       struct sge_eth_txq *txq;
+       int i;
 
+       rxq = &adap->sge.ethrxq[pi->first_rxqset];
        for (i = 0; i < pi->n_rx_qsets; i++, rxq++) {
                if (rxq->rspq.desc)
                        t4_sge_eth_rxq_stop(adap, &rxq->rspq);
        }
+
+       txq = &adap->sge.ethtxq[pi->first_txqset];
        for (i = 0; i < pi->n_tx_qsets; i++, txq++) {
                if (txq->q.desc) {
                        struct sge_txq *q = &txq->q;
@@ -2241,7 +2244,7 @@ void t4_sge_eth_release_queues(struct port_info *pi)
        struct sge_eth_txq *txq;
        unsigned int i;
 
-       rxq = &adap->sge.ethrxq[pi->first_qset];
+       rxq = &adap->sge.ethrxq[pi->first_rxqset];
        /* clean up Ethernet Tx/Rx queues */
        for (i = 0; i < pi->n_rx_qsets; i++, rxq++) {
                /* Free only the queues allocated */
@@ -2253,7 +2256,7 @@ void t4_sge_eth_release_queues(struct port_info *pi)
                }
        }
 
-       txq = &adap->sge.ethtxq[pi->first_qset];
+       txq = &adap->sge.ethtxq[pi->first_txqset];
        for (i = 0; i < pi->n_tx_qsets; i++, txq++) {
                /* Free only the queues allocated */
                if (txq->q.desc) {