xref: /openbmc/linux/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
1b1396c2bSRahul Lakkireddy // SPDX-License-Identifier: GPL-2.0-only
2b1396c2bSRahul Lakkireddy /* Copyright (C) 2019 Chelsio Communications.  All rights reserved. */
3b1396c2bSRahul Lakkireddy 
4b1396c2bSRahul Lakkireddy #include "cxgb4.h"
5b1396c2bSRahul Lakkireddy #include "cxgb4_tc_mqprio.h"
60e395b3cSRahul Lakkireddy #include "sched.h"
7b1396c2bSRahul Lakkireddy 
cxgb4_mqprio_validate(struct net_device * dev,struct tc_mqprio_qopt_offload * mqprio)8b1396c2bSRahul Lakkireddy static int cxgb4_mqprio_validate(struct net_device *dev,
9b1396c2bSRahul Lakkireddy 				 struct tc_mqprio_qopt_offload *mqprio)
10b1396c2bSRahul Lakkireddy {
11b1396c2bSRahul Lakkireddy 	u64 min_rate = 0, max_rate = 0, max_link_rate;
12b1396c2bSRahul Lakkireddy 	struct port_info *pi = netdev2pinfo(dev);
13b1396c2bSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
144ec4762dSRahul Lakkireddy 	u32 speed, qcount = 0, qoffset = 0;
15b2383ad9SRahul Lakkireddy 	u32 start_a, start_b, end_a, end_b;
16b1396c2bSRahul Lakkireddy 	int ret;
17b2383ad9SRahul Lakkireddy 	u8 i, j;
18b1396c2bSRahul Lakkireddy 
19b1396c2bSRahul Lakkireddy 	if (!mqprio->qopt.num_tc)
20b1396c2bSRahul Lakkireddy 		return 0;
21b1396c2bSRahul Lakkireddy 
22b1396c2bSRahul Lakkireddy 	if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS) {
23b1396c2bSRahul Lakkireddy 		netdev_err(dev, "Only full TC hardware offload is supported\n");
24b1396c2bSRahul Lakkireddy 		return -EINVAL;
25b1396c2bSRahul Lakkireddy 	} else if (mqprio->mode != TC_MQPRIO_MODE_CHANNEL) {
26b1396c2bSRahul Lakkireddy 		netdev_err(dev, "Only channel mode offload is supported\n");
27b1396c2bSRahul Lakkireddy 		return -EINVAL;
28b1396c2bSRahul Lakkireddy 	} else if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE) {
29b1396c2bSRahul Lakkireddy 		netdev_err(dev,	"Only bandwidth rate shaper supported\n");
30b1396c2bSRahul Lakkireddy 		return -EINVAL;
31b1396c2bSRahul Lakkireddy 	} else if (mqprio->qopt.num_tc > adap->params.nsched_cls) {
32b1396c2bSRahul Lakkireddy 		netdev_err(dev,
33b1396c2bSRahul Lakkireddy 			   "Only %u traffic classes supported by hardware\n",
34b1396c2bSRahul Lakkireddy 			   adap->params.nsched_cls);
35b1396c2bSRahul Lakkireddy 		return -ERANGE;
36b1396c2bSRahul Lakkireddy 	}
37b1396c2bSRahul Lakkireddy 
384ec4762dSRahul Lakkireddy 	ret = t4_get_link_params(pi, NULL, &speed, NULL);
39b1396c2bSRahul Lakkireddy 	if (ret) {
40b1396c2bSRahul Lakkireddy 		netdev_err(dev, "Failed to get link speed, ret: %d\n", ret);
41b1396c2bSRahul Lakkireddy 		return -EINVAL;
42b1396c2bSRahul Lakkireddy 	}
43b1396c2bSRahul Lakkireddy 
44b1396c2bSRahul Lakkireddy 	/* Convert from Mbps to bps */
45b1396c2bSRahul Lakkireddy 	max_link_rate = (u64)speed * 1000 * 1000;
46b1396c2bSRahul Lakkireddy 
47b1396c2bSRahul Lakkireddy 	for (i = 0; i < mqprio->qopt.num_tc; i++) {
48b1396c2bSRahul Lakkireddy 		qoffset = max_t(u16, mqprio->qopt.offset[i], qoffset);
49b1396c2bSRahul Lakkireddy 		qcount += mqprio->qopt.count[i];
50b1396c2bSRahul Lakkireddy 
51b2383ad9SRahul Lakkireddy 		start_a = mqprio->qopt.offset[i];
52b2383ad9SRahul Lakkireddy 		end_a = start_a + mqprio->qopt.count[i] - 1;
53b2383ad9SRahul Lakkireddy 		for (j = i + 1; j < mqprio->qopt.num_tc; j++) {
54b2383ad9SRahul Lakkireddy 			start_b = mqprio->qopt.offset[j];
55b2383ad9SRahul Lakkireddy 			end_b = start_b + mqprio->qopt.count[j] - 1;
56b2383ad9SRahul Lakkireddy 
57b2383ad9SRahul Lakkireddy 			/* If queue count is 0, then the traffic
58b2383ad9SRahul Lakkireddy 			 * belonging to this class will not use
59b2383ad9SRahul Lakkireddy 			 * ETHOFLD queues. So, no need to validate
60b2383ad9SRahul Lakkireddy 			 * further.
61b2383ad9SRahul Lakkireddy 			 */
62b2383ad9SRahul Lakkireddy 			if (!mqprio->qopt.count[i])
63b2383ad9SRahul Lakkireddy 				break;
64b2383ad9SRahul Lakkireddy 
65b2383ad9SRahul Lakkireddy 			if (!mqprio->qopt.count[j])
66b2383ad9SRahul Lakkireddy 				continue;
67b2383ad9SRahul Lakkireddy 
68b2383ad9SRahul Lakkireddy 			if (max_t(u32, start_a, start_b) <=
69b2383ad9SRahul Lakkireddy 			    min_t(u32, end_a, end_b)) {
70b2383ad9SRahul Lakkireddy 				netdev_err(dev,
71b2383ad9SRahul Lakkireddy 					   "Queues can't overlap across tc\n");
72b2383ad9SRahul Lakkireddy 				return -EINVAL;
73b2383ad9SRahul Lakkireddy 			}
74b2383ad9SRahul Lakkireddy 		}
75b2383ad9SRahul Lakkireddy 
76b1396c2bSRahul Lakkireddy 		/* Convert byte per second to bits per second */
77b1396c2bSRahul Lakkireddy 		min_rate += (mqprio->min_rate[i] * 8);
78b1396c2bSRahul Lakkireddy 		max_rate += (mqprio->max_rate[i] * 8);
79b1396c2bSRahul Lakkireddy 	}
80b1396c2bSRahul Lakkireddy 
81b1396c2bSRahul Lakkireddy 	if (qoffset >= adap->tids.neotids || qcount > adap->tids.neotids)
82b1396c2bSRahul Lakkireddy 		return -ENOMEM;
83b1396c2bSRahul Lakkireddy 
84b1396c2bSRahul Lakkireddy 	if (min_rate > max_link_rate || max_rate > max_link_rate) {
85b1396c2bSRahul Lakkireddy 		netdev_err(dev,
86b1396c2bSRahul Lakkireddy 			   "Total Min/Max (%llu/%llu) Rate > supported (%llu)\n",
87b1396c2bSRahul Lakkireddy 			   min_rate, max_rate, max_link_rate);
88b1396c2bSRahul Lakkireddy 		return -EINVAL;
89b1396c2bSRahul Lakkireddy 	}
90b1396c2bSRahul Lakkireddy 
91b1396c2bSRahul Lakkireddy 	return 0;
92b1396c2bSRahul Lakkireddy }
93b1396c2bSRahul Lakkireddy 
cxgb4_init_eosw_txq(struct net_device * dev,struct sge_eosw_txq * eosw_txq,u32 eotid,u32 hwqid)94b1396c2bSRahul Lakkireddy static int cxgb4_init_eosw_txq(struct net_device *dev,
95b1396c2bSRahul Lakkireddy 			       struct sge_eosw_txq *eosw_txq,
96b1396c2bSRahul Lakkireddy 			       u32 eotid, u32 hwqid)
97b1396c2bSRahul Lakkireddy {
98b1396c2bSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
990ed96b46SRahul Lakkireddy 	struct tx_sw_desc *ring;
100b1396c2bSRahul Lakkireddy 
101b1396c2bSRahul Lakkireddy 	memset(eosw_txq, 0, sizeof(*eosw_txq));
102b1396c2bSRahul Lakkireddy 
103b1396c2bSRahul Lakkireddy 	ring = kcalloc(CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM,
104b1396c2bSRahul Lakkireddy 		       sizeof(*ring), GFP_KERNEL);
105b1396c2bSRahul Lakkireddy 	if (!ring)
106b1396c2bSRahul Lakkireddy 		return -ENOMEM;
107b1396c2bSRahul Lakkireddy 
108b1396c2bSRahul Lakkireddy 	eosw_txq->desc = ring;
109b1396c2bSRahul Lakkireddy 	eosw_txq->ndesc = CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM;
110b1396c2bSRahul Lakkireddy 	spin_lock_init(&eosw_txq->lock);
111b1396c2bSRahul Lakkireddy 	eosw_txq->state = CXGB4_EO_STATE_CLOSED;
112b1396c2bSRahul Lakkireddy 	eosw_txq->eotid = eotid;
113b1396c2bSRahul Lakkireddy 	eosw_txq->hwtid = adap->tids.eotid_base + eosw_txq->eotid;
114b1396c2bSRahul Lakkireddy 	eosw_txq->cred = adap->params.ofldq_wr_cred;
115b1396c2bSRahul Lakkireddy 	eosw_txq->hwqid = hwqid;
116b1396c2bSRahul Lakkireddy 	eosw_txq->netdev = dev;
1170eb484eeSAllen Pais 	tasklet_setup(&eosw_txq->qresume_tsk, cxgb4_ethofld_restart);
118b1396c2bSRahul Lakkireddy 	return 0;
119b1396c2bSRahul Lakkireddy }
120b1396c2bSRahul Lakkireddy 
cxgb4_clean_eosw_txq(struct net_device * dev,struct sge_eosw_txq * eosw_txq)121b1396c2bSRahul Lakkireddy static void cxgb4_clean_eosw_txq(struct net_device *dev,
122b1396c2bSRahul Lakkireddy 				 struct sge_eosw_txq *eosw_txq)
123b1396c2bSRahul Lakkireddy {
124b1396c2bSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
125b1396c2bSRahul Lakkireddy 
126b1396c2bSRahul Lakkireddy 	cxgb4_eosw_txq_free_desc(adap, eosw_txq, eosw_txq->ndesc);
127b1396c2bSRahul Lakkireddy 	eosw_txq->pidx = 0;
128b1396c2bSRahul Lakkireddy 	eosw_txq->last_pidx = 0;
129b1396c2bSRahul Lakkireddy 	eosw_txq->cidx = 0;
130b1396c2bSRahul Lakkireddy 	eosw_txq->last_cidx = 0;
1310e395b3cSRahul Lakkireddy 	eosw_txq->flowc_idx = 0;
132b1396c2bSRahul Lakkireddy 	eosw_txq->inuse = 0;
133b1396c2bSRahul Lakkireddy 	eosw_txq->cred = adap->params.ofldq_wr_cred;
134b1396c2bSRahul Lakkireddy 	eosw_txq->ncompl = 0;
135b1396c2bSRahul Lakkireddy 	eosw_txq->last_compl = 0;
136b1396c2bSRahul Lakkireddy 	eosw_txq->state = CXGB4_EO_STATE_CLOSED;
137b1396c2bSRahul Lakkireddy }
138b1396c2bSRahul Lakkireddy 
cxgb4_free_eosw_txq(struct net_device * dev,struct sge_eosw_txq * eosw_txq)139b1396c2bSRahul Lakkireddy static void cxgb4_free_eosw_txq(struct net_device *dev,
140b1396c2bSRahul Lakkireddy 				struct sge_eosw_txq *eosw_txq)
141b1396c2bSRahul Lakkireddy {
142b1396c2bSRahul Lakkireddy 	spin_lock_bh(&eosw_txq->lock);
143b1396c2bSRahul Lakkireddy 	cxgb4_clean_eosw_txq(dev, eosw_txq);
144b1396c2bSRahul Lakkireddy 	kfree(eosw_txq->desc);
145b1396c2bSRahul Lakkireddy 	spin_unlock_bh(&eosw_txq->lock);
146b1396c2bSRahul Lakkireddy 	tasklet_kill(&eosw_txq->qresume_tsk);
147b1396c2bSRahul Lakkireddy }
148b1396c2bSRahul Lakkireddy 
cxgb4_mqprio_alloc_hw_resources(struct net_device * dev)1492d0cb84dSRahul Lakkireddy static int cxgb4_mqprio_alloc_hw_resources(struct net_device *dev)
1502d0cb84dSRahul Lakkireddy {
1512d0cb84dSRahul Lakkireddy 	struct port_info *pi = netdev2pinfo(dev);
1522d0cb84dSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
1532d0cb84dSRahul Lakkireddy 	struct sge_ofld_rxq *eorxq;
1542d0cb84dSRahul Lakkireddy 	struct sge_eohw_txq *eotxq;
1552d0cb84dSRahul Lakkireddy 	int ret, msix = 0;
1562d0cb84dSRahul Lakkireddy 	u32 i;
1572d0cb84dSRahul Lakkireddy 
1582d0cb84dSRahul Lakkireddy 	/* Allocate ETHOFLD hardware queue structures if not done already */
1592d0cb84dSRahul Lakkireddy 	if (!refcount_read(&adap->tc_mqprio->refcnt)) {
1602d0cb84dSRahul Lakkireddy 		adap->sge.eohw_rxq = kcalloc(adap->sge.eoqsets,
1612d0cb84dSRahul Lakkireddy 					     sizeof(struct sge_ofld_rxq),
1622d0cb84dSRahul Lakkireddy 					     GFP_KERNEL);
1632d0cb84dSRahul Lakkireddy 		if (!adap->sge.eohw_rxq)
1642d0cb84dSRahul Lakkireddy 			return -ENOMEM;
1652d0cb84dSRahul Lakkireddy 
1662d0cb84dSRahul Lakkireddy 		adap->sge.eohw_txq = kcalloc(adap->sge.eoqsets,
1672d0cb84dSRahul Lakkireddy 					     sizeof(struct sge_eohw_txq),
1682d0cb84dSRahul Lakkireddy 					     GFP_KERNEL);
1692d0cb84dSRahul Lakkireddy 		if (!adap->sge.eohw_txq) {
1702d0cb84dSRahul Lakkireddy 			kfree(adap->sge.eohw_rxq);
1712d0cb84dSRahul Lakkireddy 			return -ENOMEM;
1722d0cb84dSRahul Lakkireddy 		}
173ea8608d4SRahul Lakkireddy 
174ea8608d4SRahul Lakkireddy 		refcount_set(&adap->tc_mqprio->refcnt, 1);
175ea8608d4SRahul Lakkireddy 	} else {
176ea8608d4SRahul Lakkireddy 		refcount_inc(&adap->tc_mqprio->refcnt);
1772d0cb84dSRahul Lakkireddy 	}
1782d0cb84dSRahul Lakkireddy 
1792d0cb84dSRahul Lakkireddy 	if (!(adap->flags & CXGB4_USING_MSIX))
1802d0cb84dSRahul Lakkireddy 		msix = -((int)adap->sge.intrq.abs_id + 1);
1812d0cb84dSRahul Lakkireddy 
1822d0cb84dSRahul Lakkireddy 	for (i = 0; i < pi->nqsets; i++) {
1832d0cb84dSRahul Lakkireddy 		eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];
1842d0cb84dSRahul Lakkireddy 		eotxq = &adap->sge.eohw_txq[pi->first_qset + i];
1852d0cb84dSRahul Lakkireddy 
1862d0cb84dSRahul Lakkireddy 		/* Allocate Rxqs for receiving ETHOFLD Tx completions */
1872d0cb84dSRahul Lakkireddy 		if (msix >= 0) {
1882d0cb84dSRahul Lakkireddy 			msix = cxgb4_get_msix_idx_from_bmap(adap);
18972c99609SDan Carpenter 			if (msix < 0) {
19072c99609SDan Carpenter 				ret = msix;
1912d0cb84dSRahul Lakkireddy 				goto out_free_queues;
19272c99609SDan Carpenter 			}
1932d0cb84dSRahul Lakkireddy 
1942d0cb84dSRahul Lakkireddy 			eorxq->msix = &adap->msix_info[msix];
1952d0cb84dSRahul Lakkireddy 			snprintf(eorxq->msix->desc,
1962d0cb84dSRahul Lakkireddy 				 sizeof(eorxq->msix->desc),
1972d0cb84dSRahul Lakkireddy 				 "%s-eorxq%d", dev->name, i);
1982d0cb84dSRahul Lakkireddy 		}
1992d0cb84dSRahul Lakkireddy 
2002d0cb84dSRahul Lakkireddy 		init_rspq(adap, &eorxq->rspq,
2012d0cb84dSRahul Lakkireddy 			  CXGB4_EOHW_RXQ_DEFAULT_INTR_USEC,
2022d0cb84dSRahul Lakkireddy 			  CXGB4_EOHW_RXQ_DEFAULT_PKT_CNT,
2032d0cb84dSRahul Lakkireddy 			  CXGB4_EOHW_RXQ_DEFAULT_DESC_NUM,
2042d0cb84dSRahul Lakkireddy 			  CXGB4_EOHW_RXQ_DEFAULT_DESC_SIZE);
2052d0cb84dSRahul Lakkireddy 
2062d0cb84dSRahul Lakkireddy 		eorxq->fl.size = CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM;
2072d0cb84dSRahul Lakkireddy 
2082d0cb84dSRahul Lakkireddy 		ret = t4_sge_alloc_rxq(adap, &eorxq->rspq, false,
2094846d533SRahul Lakkireddy 				       dev, msix, &eorxq->fl,
2104846d533SRahul Lakkireddy 				       cxgb4_ethofld_rx_handler,
2112d0cb84dSRahul Lakkireddy 				       NULL, 0);
2122d0cb84dSRahul Lakkireddy 		if (ret)
2132d0cb84dSRahul Lakkireddy 			goto out_free_queues;
2142d0cb84dSRahul Lakkireddy 
2152d0cb84dSRahul Lakkireddy 		/* Allocate ETHOFLD hardware Txqs */
2162d0cb84dSRahul Lakkireddy 		eotxq->q.size = CXGB4_EOHW_TXQ_DEFAULT_DESC_NUM;
2172d0cb84dSRahul Lakkireddy 		ret = t4_sge_alloc_ethofld_txq(adap, eotxq, dev,
2182d0cb84dSRahul Lakkireddy 					       eorxq->rspq.cntxt_id);
2192d0cb84dSRahul Lakkireddy 		if (ret)
2202d0cb84dSRahul Lakkireddy 			goto out_free_queues;
2212d0cb84dSRahul Lakkireddy 
2222d0cb84dSRahul Lakkireddy 		/* Allocate IRQs, set IRQ affinity, and start Rx */
2232d0cb84dSRahul Lakkireddy 		if (adap->flags & CXGB4_USING_MSIX) {
2242d0cb84dSRahul Lakkireddy 			ret = request_irq(eorxq->msix->vec, t4_sge_intr_msix, 0,
2252d0cb84dSRahul Lakkireddy 					  eorxq->msix->desc, &eorxq->rspq);
2262d0cb84dSRahul Lakkireddy 			if (ret)
2272d0cb84dSRahul Lakkireddy 				goto out_free_msix;
2282d0cb84dSRahul Lakkireddy 
2292d0cb84dSRahul Lakkireddy 			cxgb4_set_msix_aff(adap, eorxq->msix->vec,
2302d0cb84dSRahul Lakkireddy 					   &eorxq->msix->aff_mask, i);
2312d0cb84dSRahul Lakkireddy 		}
2322d0cb84dSRahul Lakkireddy 
2332d0cb84dSRahul Lakkireddy 		if (adap->flags & CXGB4_FULL_INIT_DONE)
2342d0cb84dSRahul Lakkireddy 			cxgb4_enable_rx(adap, &eorxq->rspq);
2352d0cb84dSRahul Lakkireddy 	}
2362d0cb84dSRahul Lakkireddy 
2372d0cb84dSRahul Lakkireddy 	return 0;
2382d0cb84dSRahul Lakkireddy 
2392d0cb84dSRahul Lakkireddy out_free_msix:
2402d0cb84dSRahul Lakkireddy 	while (i-- > 0) {
2412d0cb84dSRahul Lakkireddy 		eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];
2422d0cb84dSRahul Lakkireddy 
2432d0cb84dSRahul Lakkireddy 		if (adap->flags & CXGB4_FULL_INIT_DONE)
2442d0cb84dSRahul Lakkireddy 			cxgb4_quiesce_rx(&eorxq->rspq);
2452d0cb84dSRahul Lakkireddy 
2462d0cb84dSRahul Lakkireddy 		if (adap->flags & CXGB4_USING_MSIX) {
2472d0cb84dSRahul Lakkireddy 			cxgb4_clear_msix_aff(eorxq->msix->vec,
2482d0cb84dSRahul Lakkireddy 					     eorxq->msix->aff_mask);
2492d0cb84dSRahul Lakkireddy 			free_irq(eorxq->msix->vec, &eorxq->rspq);
2502d0cb84dSRahul Lakkireddy 		}
2512d0cb84dSRahul Lakkireddy 	}
2522d0cb84dSRahul Lakkireddy 
2532d0cb84dSRahul Lakkireddy out_free_queues:
2542d0cb84dSRahul Lakkireddy 	for (i = 0; i < pi->nqsets; i++) {
2552d0cb84dSRahul Lakkireddy 		eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];
2562d0cb84dSRahul Lakkireddy 		eotxq = &adap->sge.eohw_txq[pi->first_qset + i];
2572d0cb84dSRahul Lakkireddy 
2582d0cb84dSRahul Lakkireddy 		if (eorxq->rspq.desc)
2592d0cb84dSRahul Lakkireddy 			free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl);
2602d0cb84dSRahul Lakkireddy 		if (eorxq->msix)
2612d0cb84dSRahul Lakkireddy 			cxgb4_free_msix_idx_in_bmap(adap, eorxq->msix->idx);
2622d0cb84dSRahul Lakkireddy 		t4_sge_free_ethofld_txq(adap, eotxq);
2632d0cb84dSRahul Lakkireddy 	}
2642d0cb84dSRahul Lakkireddy 
265ea8608d4SRahul Lakkireddy 	if (refcount_dec_and_test(&adap->tc_mqprio->refcnt)) {
2662d0cb84dSRahul Lakkireddy 		kfree(adap->sge.eohw_txq);
2672d0cb84dSRahul Lakkireddy 		kfree(adap->sge.eohw_rxq);
268ea8608d4SRahul Lakkireddy 	}
2692d0cb84dSRahul Lakkireddy 	return ret;
2702d0cb84dSRahul Lakkireddy }
2712d0cb84dSRahul Lakkireddy 
cxgb4_mqprio_free_hw_resources(struct net_device * dev)2728b8371b5Szhengbin static void cxgb4_mqprio_free_hw_resources(struct net_device *dev)
2732d0cb84dSRahul Lakkireddy {
2742d0cb84dSRahul Lakkireddy 	struct port_info *pi = netdev2pinfo(dev);
2752d0cb84dSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
2762d0cb84dSRahul Lakkireddy 	struct sge_ofld_rxq *eorxq;
2772d0cb84dSRahul Lakkireddy 	struct sge_eohw_txq *eotxq;
2782d0cb84dSRahul Lakkireddy 	u32 i;
2792d0cb84dSRahul Lakkireddy 
2802d0cb84dSRahul Lakkireddy 	/* Return if no ETHOFLD structures have been allocated yet */
2812d0cb84dSRahul Lakkireddy 	if (!refcount_read(&adap->tc_mqprio->refcnt))
2822d0cb84dSRahul Lakkireddy 		return;
2832d0cb84dSRahul Lakkireddy 
2842d0cb84dSRahul Lakkireddy 	/* Return if no hardware queues have been allocated */
2852d0cb84dSRahul Lakkireddy 	if (!adap->sge.eohw_rxq[pi->first_qset].rspq.desc)
2862d0cb84dSRahul Lakkireddy 		return;
2872d0cb84dSRahul Lakkireddy 
2882d0cb84dSRahul Lakkireddy 	for (i = 0; i < pi->nqsets; i++) {
2892d0cb84dSRahul Lakkireddy 		eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];
2902d0cb84dSRahul Lakkireddy 		eotxq = &adap->sge.eohw_txq[pi->first_qset + i];
2912d0cb84dSRahul Lakkireddy 
2922d0cb84dSRahul Lakkireddy 		/* Device removal path will already disable NAPI
2932d0cb84dSRahul Lakkireddy 		 * before unregistering netdevice. So, only disable
2942d0cb84dSRahul Lakkireddy 		 * NAPI if we're not in device removal path
2952d0cb84dSRahul Lakkireddy 		 */
2962d0cb84dSRahul Lakkireddy 		if (!(adap->flags & CXGB4_SHUTTING_DOWN))
2972d0cb84dSRahul Lakkireddy 			cxgb4_quiesce_rx(&eorxq->rspq);
2982d0cb84dSRahul Lakkireddy 
2992d0cb84dSRahul Lakkireddy 		if (adap->flags & CXGB4_USING_MSIX) {
3002d0cb84dSRahul Lakkireddy 			cxgb4_clear_msix_aff(eorxq->msix->vec,
3012d0cb84dSRahul Lakkireddy 					     eorxq->msix->aff_mask);
3022d0cb84dSRahul Lakkireddy 			free_irq(eorxq->msix->vec, &eorxq->rspq);
303cef8dac9SRahul Lakkireddy 			cxgb4_free_msix_idx_in_bmap(adap, eorxq->msix->idx);
3042d0cb84dSRahul Lakkireddy 		}
3052d0cb84dSRahul Lakkireddy 
3062d0cb84dSRahul Lakkireddy 		free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl);
3072d0cb84dSRahul Lakkireddy 		t4_sge_free_ethofld_txq(adap, eotxq);
3082d0cb84dSRahul Lakkireddy 	}
3092d0cb84dSRahul Lakkireddy 
3102d0cb84dSRahul Lakkireddy 	/* Free up ETHOFLD structures if there are no users */
3112d0cb84dSRahul Lakkireddy 	if (refcount_dec_and_test(&adap->tc_mqprio->refcnt)) {
3122d0cb84dSRahul Lakkireddy 		kfree(adap->sge.eohw_txq);
3132d0cb84dSRahul Lakkireddy 		kfree(adap->sge.eohw_rxq);
3142d0cb84dSRahul Lakkireddy 	}
3152d0cb84dSRahul Lakkireddy }
3162d0cb84dSRahul Lakkireddy 
cxgb4_mqprio_alloc_tc(struct net_device * dev,struct tc_mqprio_qopt_offload * mqprio)3170e395b3cSRahul Lakkireddy static int cxgb4_mqprio_alloc_tc(struct net_device *dev,
3180e395b3cSRahul Lakkireddy 				 struct tc_mqprio_qopt_offload *mqprio)
3190e395b3cSRahul Lakkireddy {
3200e395b3cSRahul Lakkireddy 	struct ch_sched_params p = {
3210e395b3cSRahul Lakkireddy 		.type = SCHED_CLASS_TYPE_PACKET,
3220e395b3cSRahul Lakkireddy 		.u.params.level = SCHED_CLASS_LEVEL_CL_RL,
3230e395b3cSRahul Lakkireddy 		.u.params.mode = SCHED_CLASS_MODE_FLOW,
3240e395b3cSRahul Lakkireddy 		.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS,
3250e395b3cSRahul Lakkireddy 		.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS,
3260e395b3cSRahul Lakkireddy 		.u.params.class = SCHED_CLS_NONE,
3270e395b3cSRahul Lakkireddy 		.u.params.weight = 0,
3280e395b3cSRahul Lakkireddy 		.u.params.pktsize = dev->mtu,
3290e395b3cSRahul Lakkireddy 	};
3300e395b3cSRahul Lakkireddy 	struct cxgb4_tc_port_mqprio *tc_port_mqprio;
3310e395b3cSRahul Lakkireddy 	struct port_info *pi = netdev2pinfo(dev);
3320e395b3cSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
3330e395b3cSRahul Lakkireddy 	struct sched_class *e;
3340e395b3cSRahul Lakkireddy 	int ret;
3350e395b3cSRahul Lakkireddy 	u8 i;
3360e395b3cSRahul Lakkireddy 
3370e395b3cSRahul Lakkireddy 	tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];
3380e395b3cSRahul Lakkireddy 	p.u.params.channel = pi->tx_chan;
3390e395b3cSRahul Lakkireddy 	for (i = 0; i < mqprio->qopt.num_tc; i++) {
3400e395b3cSRahul Lakkireddy 		/* Convert from bytes per second to Kbps */
34197c20ea8SRahul Lakkireddy 		p.u.params.minrate = div_u64(mqprio->min_rate[i] * 8, 1000);
34297c20ea8SRahul Lakkireddy 		p.u.params.maxrate = div_u64(mqprio->max_rate[i] * 8, 1000);
3430e395b3cSRahul Lakkireddy 
3444bccfc03SRahul Lakkireddy 		/* Request larger burst buffer for smaller MTU, so
3454bccfc03SRahul Lakkireddy 		 * that hardware can work on more data per burst
3464bccfc03SRahul Lakkireddy 		 * cycle.
3474bccfc03SRahul Lakkireddy 		 */
3484bccfc03SRahul Lakkireddy 		if (dev->mtu <= ETH_DATA_LEN)
3494bccfc03SRahul Lakkireddy 			p.u.params.burstsize = 8 * dev->mtu;
3504bccfc03SRahul Lakkireddy 
3510e395b3cSRahul Lakkireddy 		e = cxgb4_sched_class_alloc(dev, &p);
3520e395b3cSRahul Lakkireddy 		if (!e) {
3530e395b3cSRahul Lakkireddy 			ret = -ENOMEM;
3540e395b3cSRahul Lakkireddy 			goto out_err;
3550e395b3cSRahul Lakkireddy 		}
3560e395b3cSRahul Lakkireddy 
3570e395b3cSRahul Lakkireddy 		tc_port_mqprio->tc_hwtc_map[i] = e->idx;
3580e395b3cSRahul Lakkireddy 	}
3590e395b3cSRahul Lakkireddy 
3600e395b3cSRahul Lakkireddy 	return 0;
3610e395b3cSRahul Lakkireddy 
3620e395b3cSRahul Lakkireddy out_err:
3630e395b3cSRahul Lakkireddy 	while (i--)
3640e395b3cSRahul Lakkireddy 		cxgb4_sched_class_free(dev, tc_port_mqprio->tc_hwtc_map[i]);
3650e395b3cSRahul Lakkireddy 
3660e395b3cSRahul Lakkireddy 	return ret;
3670e395b3cSRahul Lakkireddy }
3680e395b3cSRahul Lakkireddy 
cxgb4_mqprio_free_tc(struct net_device * dev)3690e395b3cSRahul Lakkireddy static void cxgb4_mqprio_free_tc(struct net_device *dev)
3700e395b3cSRahul Lakkireddy {
3710e395b3cSRahul Lakkireddy 	struct cxgb4_tc_port_mqprio *tc_port_mqprio;
3720e395b3cSRahul Lakkireddy 	struct port_info *pi = netdev2pinfo(dev);
3730e395b3cSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
3740e395b3cSRahul Lakkireddy 	u8 i;
3750e395b3cSRahul Lakkireddy 
3760e395b3cSRahul Lakkireddy 	tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];
3770e395b3cSRahul Lakkireddy 	for (i = 0; i < tc_port_mqprio->mqprio.qopt.num_tc; i++)
3780e395b3cSRahul Lakkireddy 		cxgb4_sched_class_free(dev, tc_port_mqprio->tc_hwtc_map[i]);
3790e395b3cSRahul Lakkireddy }
3800e395b3cSRahul Lakkireddy 
cxgb4_mqprio_class_bind(struct net_device * dev,struct sge_eosw_txq * eosw_txq,u8 tc)3810e395b3cSRahul Lakkireddy static int cxgb4_mqprio_class_bind(struct net_device *dev,
3820e395b3cSRahul Lakkireddy 				   struct sge_eosw_txq *eosw_txq,
3830e395b3cSRahul Lakkireddy 				   u8 tc)
3840e395b3cSRahul Lakkireddy {
3850e395b3cSRahul Lakkireddy 	struct ch_sched_flowc fe;
3860e395b3cSRahul Lakkireddy 	int ret;
3870e395b3cSRahul Lakkireddy 
3880e395b3cSRahul Lakkireddy 	init_completion(&eosw_txq->completion);
3890e395b3cSRahul Lakkireddy 
3900e395b3cSRahul Lakkireddy 	fe.tid = eosw_txq->eotid;
3910e395b3cSRahul Lakkireddy 	fe.class = tc;
3920e395b3cSRahul Lakkireddy 
3930e395b3cSRahul Lakkireddy 	ret = cxgb4_sched_class_bind(dev, &fe, SCHED_FLOWC);
3940e395b3cSRahul Lakkireddy 	if (ret)
3950e395b3cSRahul Lakkireddy 		return ret;
3960e395b3cSRahul Lakkireddy 
3970e395b3cSRahul Lakkireddy 	ret = wait_for_completion_timeout(&eosw_txq->completion,
3980e395b3cSRahul Lakkireddy 					  CXGB4_FLOWC_WAIT_TIMEOUT);
3990e395b3cSRahul Lakkireddy 	if (!ret)
4000e395b3cSRahul Lakkireddy 		return -ETIMEDOUT;
4010e395b3cSRahul Lakkireddy 
4020e395b3cSRahul Lakkireddy 	return 0;
4030e395b3cSRahul Lakkireddy }
4040e395b3cSRahul Lakkireddy 
cxgb4_mqprio_class_unbind(struct net_device * dev,struct sge_eosw_txq * eosw_txq,u8 tc)4050e395b3cSRahul Lakkireddy static void cxgb4_mqprio_class_unbind(struct net_device *dev,
4060e395b3cSRahul Lakkireddy 				      struct sge_eosw_txq *eosw_txq,
4070e395b3cSRahul Lakkireddy 				      u8 tc)
4080e395b3cSRahul Lakkireddy {
4090e395b3cSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
4100e395b3cSRahul Lakkireddy 	struct ch_sched_flowc fe;
4110e395b3cSRahul Lakkireddy 
4120e395b3cSRahul Lakkireddy 	/* If we're shutting down, interrupts are disabled and no completions
4130e395b3cSRahul Lakkireddy 	 * come back. So, skip waiting for completions in this scenario.
4140e395b3cSRahul Lakkireddy 	 */
4150e395b3cSRahul Lakkireddy 	if (!(adap->flags & CXGB4_SHUTTING_DOWN))
4160e395b3cSRahul Lakkireddy 		init_completion(&eosw_txq->completion);
4170e395b3cSRahul Lakkireddy 
4180e395b3cSRahul Lakkireddy 	fe.tid = eosw_txq->eotid;
4190e395b3cSRahul Lakkireddy 	fe.class = tc;
4200e395b3cSRahul Lakkireddy 	cxgb4_sched_class_unbind(dev, &fe, SCHED_FLOWC);
4210e395b3cSRahul Lakkireddy 
4220e395b3cSRahul Lakkireddy 	if (!(adap->flags & CXGB4_SHUTTING_DOWN))
4230e395b3cSRahul Lakkireddy 		wait_for_completion_timeout(&eosw_txq->completion,
4240e395b3cSRahul Lakkireddy 					    CXGB4_FLOWC_WAIT_TIMEOUT);
4250e395b3cSRahul Lakkireddy }
4260e395b3cSRahul Lakkireddy 
cxgb4_mqprio_enable_offload(struct net_device * dev,struct tc_mqprio_qopt_offload * mqprio)427b1396c2bSRahul Lakkireddy static int cxgb4_mqprio_enable_offload(struct net_device *dev,
428b1396c2bSRahul Lakkireddy 				       struct tc_mqprio_qopt_offload *mqprio)
429b1396c2bSRahul Lakkireddy {
430b1396c2bSRahul Lakkireddy 	struct cxgb4_tc_port_mqprio *tc_port_mqprio;
431b1396c2bSRahul Lakkireddy 	u32 qoffset, qcount, tot_qcount, qid, hwqid;
432b1396c2bSRahul Lakkireddy 	struct port_info *pi = netdev2pinfo(dev);
433b1396c2bSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
434b1396c2bSRahul Lakkireddy 	struct sge_eosw_txq *eosw_txq;
435b1396c2bSRahul Lakkireddy 	int eotid, ret;
436b1396c2bSRahul Lakkireddy 	u16 i, j;
4370e395b3cSRahul Lakkireddy 	u8 hwtc;
438b1396c2bSRahul Lakkireddy 
4392d0cb84dSRahul Lakkireddy 	ret = cxgb4_mqprio_alloc_hw_resources(dev);
4402d0cb84dSRahul Lakkireddy 	if (ret)
4412d0cb84dSRahul Lakkireddy 		return -ENOMEM;
4422d0cb84dSRahul Lakkireddy 
443b1396c2bSRahul Lakkireddy 	tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];
444b1396c2bSRahul Lakkireddy 	for (i = 0; i < mqprio->qopt.num_tc; i++) {
445b1396c2bSRahul Lakkireddy 		qoffset = mqprio->qopt.offset[i];
446b1396c2bSRahul Lakkireddy 		qcount = mqprio->qopt.count[i];
447b1396c2bSRahul Lakkireddy 		for (j = 0; j < qcount; j++) {
448b1396c2bSRahul Lakkireddy 			eotid = cxgb4_get_free_eotid(&adap->tids);
449b1396c2bSRahul Lakkireddy 			if (eotid < 0) {
450b1396c2bSRahul Lakkireddy 				ret = -ENOMEM;
451b1396c2bSRahul Lakkireddy 				goto out_free_eotids;
452b1396c2bSRahul Lakkireddy 			}
453b1396c2bSRahul Lakkireddy 
454b1396c2bSRahul Lakkireddy 			qid = qoffset + j;
455b1396c2bSRahul Lakkireddy 			hwqid = pi->first_qset + (eotid % pi->nqsets);
456b1396c2bSRahul Lakkireddy 			eosw_txq = &tc_port_mqprio->eosw_txq[qid];
457b1396c2bSRahul Lakkireddy 			ret = cxgb4_init_eosw_txq(dev, eosw_txq,
458b1396c2bSRahul Lakkireddy 						  eotid, hwqid);
459b1396c2bSRahul Lakkireddy 			if (ret)
460b1396c2bSRahul Lakkireddy 				goto out_free_eotids;
461b1396c2bSRahul Lakkireddy 
462b1396c2bSRahul Lakkireddy 			cxgb4_alloc_eotid(&adap->tids, eotid, eosw_txq);
4630e395b3cSRahul Lakkireddy 
4640e395b3cSRahul Lakkireddy 			hwtc = tc_port_mqprio->tc_hwtc_map[i];
4650e395b3cSRahul Lakkireddy 			ret = cxgb4_mqprio_class_bind(dev, eosw_txq, hwtc);
4660e395b3cSRahul Lakkireddy 			if (ret)
4670e395b3cSRahul Lakkireddy 				goto out_free_eotids;
468b1396c2bSRahul Lakkireddy 		}
469b1396c2bSRahul Lakkireddy 	}
470b1396c2bSRahul Lakkireddy 
471b1396c2bSRahul Lakkireddy 	memcpy(&tc_port_mqprio->mqprio, mqprio,
472b1396c2bSRahul Lakkireddy 	       sizeof(struct tc_mqprio_qopt_offload));
473b1396c2bSRahul Lakkireddy 
474b1396c2bSRahul Lakkireddy 	/* Inform the stack about the configured tc params.
475b1396c2bSRahul Lakkireddy 	 *
476b1396c2bSRahul Lakkireddy 	 * Set the correct queue map. If no queue count has been
477b1396c2bSRahul Lakkireddy 	 * specified, then send the traffic through default NIC
478b1396c2bSRahul Lakkireddy 	 * queues; instead of ETHOFLD queues.
479b1396c2bSRahul Lakkireddy 	 */
480b1396c2bSRahul Lakkireddy 	ret = netdev_set_num_tc(dev, mqprio->qopt.num_tc);
481b1396c2bSRahul Lakkireddy 	if (ret)
482b1396c2bSRahul Lakkireddy 		goto out_free_eotids;
483b1396c2bSRahul Lakkireddy 
484b1396c2bSRahul Lakkireddy 	tot_qcount = pi->nqsets;
485b1396c2bSRahul Lakkireddy 	for (i = 0; i < mqprio->qopt.num_tc; i++) {
486b1396c2bSRahul Lakkireddy 		qcount = mqprio->qopt.count[i];
487b1396c2bSRahul Lakkireddy 		if (qcount) {
488b1396c2bSRahul Lakkireddy 			qoffset = mqprio->qopt.offset[i] + pi->nqsets;
489b1396c2bSRahul Lakkireddy 		} else {
490b1396c2bSRahul Lakkireddy 			qcount = pi->nqsets;
491b1396c2bSRahul Lakkireddy 			qoffset = 0;
492b1396c2bSRahul Lakkireddy 		}
493b1396c2bSRahul Lakkireddy 
494b1396c2bSRahul Lakkireddy 		ret = netdev_set_tc_queue(dev, i, qcount, qoffset);
495b1396c2bSRahul Lakkireddy 		if (ret)
496b1396c2bSRahul Lakkireddy 			goto out_reset_tc;
497b1396c2bSRahul Lakkireddy 
498b1396c2bSRahul Lakkireddy 		tot_qcount += mqprio->qopt.count[i];
499b1396c2bSRahul Lakkireddy 	}
500b1396c2bSRahul Lakkireddy 
501b1396c2bSRahul Lakkireddy 	ret = netif_set_real_num_tx_queues(dev, tot_qcount);
502b1396c2bSRahul Lakkireddy 	if (ret)
503b1396c2bSRahul Lakkireddy 		goto out_reset_tc;
504b1396c2bSRahul Lakkireddy 
505b1396c2bSRahul Lakkireddy 	tc_port_mqprio->state = CXGB4_MQPRIO_STATE_ACTIVE;
506b1396c2bSRahul Lakkireddy 	return 0;
507b1396c2bSRahul Lakkireddy 
508b1396c2bSRahul Lakkireddy out_reset_tc:
509b1396c2bSRahul Lakkireddy 	netdev_reset_tc(dev);
510b1396c2bSRahul Lakkireddy 	i = mqprio->qopt.num_tc;
511b1396c2bSRahul Lakkireddy 
512b1396c2bSRahul Lakkireddy out_free_eotids:
513b1396c2bSRahul Lakkireddy 	while (i-- > 0) {
514b1396c2bSRahul Lakkireddy 		qoffset = mqprio->qopt.offset[i];
515b1396c2bSRahul Lakkireddy 		qcount = mqprio->qopt.count[i];
516b1396c2bSRahul Lakkireddy 		for (j = 0; j < qcount; j++) {
517b1396c2bSRahul Lakkireddy 			eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j];
5180e395b3cSRahul Lakkireddy 
5190e395b3cSRahul Lakkireddy 			hwtc = tc_port_mqprio->tc_hwtc_map[i];
5200e395b3cSRahul Lakkireddy 			cxgb4_mqprio_class_unbind(dev, eosw_txq, hwtc);
5210e395b3cSRahul Lakkireddy 
522b1396c2bSRahul Lakkireddy 			cxgb4_free_eotid(&adap->tids, eosw_txq->eotid);
523b1396c2bSRahul Lakkireddy 			cxgb4_free_eosw_txq(dev, eosw_txq);
524b1396c2bSRahul Lakkireddy 		}
525b1396c2bSRahul Lakkireddy 	}
526b1396c2bSRahul Lakkireddy 
5272d0cb84dSRahul Lakkireddy 	cxgb4_mqprio_free_hw_resources(dev);
528b1396c2bSRahul Lakkireddy 	return ret;
529b1396c2bSRahul Lakkireddy }
530b1396c2bSRahul Lakkireddy 
cxgb4_mqprio_disable_offload(struct net_device * dev)531b1396c2bSRahul Lakkireddy static void cxgb4_mqprio_disable_offload(struct net_device *dev)
532b1396c2bSRahul Lakkireddy {
533b1396c2bSRahul Lakkireddy 	struct cxgb4_tc_port_mqprio *tc_port_mqprio;
534b1396c2bSRahul Lakkireddy 	struct port_info *pi = netdev2pinfo(dev);
535b1396c2bSRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
536b1396c2bSRahul Lakkireddy 	struct sge_eosw_txq *eosw_txq;
537b1396c2bSRahul Lakkireddy 	u32 qoffset, qcount;
538b1396c2bSRahul Lakkireddy 	u16 i, j;
5390e395b3cSRahul Lakkireddy 	u8 hwtc;
540b1396c2bSRahul Lakkireddy 
541b1396c2bSRahul Lakkireddy 	tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];
542b1396c2bSRahul Lakkireddy 	if (tc_port_mqprio->state != CXGB4_MQPRIO_STATE_ACTIVE)
543b1396c2bSRahul Lakkireddy 		return;
544b1396c2bSRahul Lakkireddy 
545b1396c2bSRahul Lakkireddy 	netdev_reset_tc(dev);
546b1396c2bSRahul Lakkireddy 	netif_set_real_num_tx_queues(dev, pi->nqsets);
547b1396c2bSRahul Lakkireddy 
548b1396c2bSRahul Lakkireddy 	for (i = 0; i < tc_port_mqprio->mqprio.qopt.num_tc; i++) {
549b1396c2bSRahul Lakkireddy 		qoffset = tc_port_mqprio->mqprio.qopt.offset[i];
550b1396c2bSRahul Lakkireddy 		qcount = tc_port_mqprio->mqprio.qopt.count[i];
551b1396c2bSRahul Lakkireddy 		for (j = 0; j < qcount; j++) {
552b1396c2bSRahul Lakkireddy 			eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j];
5530e395b3cSRahul Lakkireddy 
5540e395b3cSRahul Lakkireddy 			hwtc = tc_port_mqprio->tc_hwtc_map[i];
5550e395b3cSRahul Lakkireddy 			cxgb4_mqprio_class_unbind(dev, eosw_txq, hwtc);
5560e395b3cSRahul Lakkireddy 
557b1396c2bSRahul Lakkireddy 			cxgb4_free_eotid(&adap->tids, eosw_txq->eotid);
558b1396c2bSRahul Lakkireddy 			cxgb4_free_eosw_txq(dev, eosw_txq);
559b1396c2bSRahul Lakkireddy 		}
560b1396c2bSRahul Lakkireddy 	}
561b1396c2bSRahul Lakkireddy 
5622d0cb84dSRahul Lakkireddy 	cxgb4_mqprio_free_hw_resources(dev);
5632d0cb84dSRahul Lakkireddy 
5640e395b3cSRahul Lakkireddy 	/* Free up the traffic classes */
5650e395b3cSRahul Lakkireddy 	cxgb4_mqprio_free_tc(dev);
5660e395b3cSRahul Lakkireddy 
567b1396c2bSRahul Lakkireddy 	memset(&tc_port_mqprio->mqprio, 0,
568b1396c2bSRahul Lakkireddy 	       sizeof(struct tc_mqprio_qopt_offload));
569b1396c2bSRahul Lakkireddy 
570b1396c2bSRahul Lakkireddy 	tc_port_mqprio->state = CXGB4_MQPRIO_STATE_DISABLED;
571b1396c2bSRahul Lakkireddy }
572b1396c2bSRahul Lakkireddy 
cxgb4_setup_tc_mqprio(struct net_device * dev,struct tc_mqprio_qopt_offload * mqprio)573b1396c2bSRahul Lakkireddy int cxgb4_setup_tc_mqprio(struct net_device *dev,
574b1396c2bSRahul Lakkireddy 			  struct tc_mqprio_qopt_offload *mqprio)
575b1396c2bSRahul Lakkireddy {
5765148e595SRahul Lakkireddy 	struct adapter *adap = netdev2adap(dev);
577b1396c2bSRahul Lakkireddy 	bool needs_bring_up = false;
578b1396c2bSRahul Lakkireddy 	int ret;
579b1396c2bSRahul Lakkireddy 
580b1396c2bSRahul Lakkireddy 	ret = cxgb4_mqprio_validate(dev, mqprio);
581b1396c2bSRahul Lakkireddy 	if (ret)
582b1396c2bSRahul Lakkireddy 		return ret;
583b1396c2bSRahul Lakkireddy 
5845148e595SRahul Lakkireddy 	mutex_lock(&adap->tc_mqprio->mqprio_mutex);
5855148e595SRahul Lakkireddy 
586b1396c2bSRahul Lakkireddy 	/* To configure tc params, the current allocated EOTIDs must
587b1396c2bSRahul Lakkireddy 	 * be freed up. However, they can't be freed up if there's
588b1396c2bSRahul Lakkireddy 	 * traffic running on the interface. So, ensure interface is
589b1396c2bSRahul Lakkireddy 	 * down before configuring tc params.
590b1396c2bSRahul Lakkireddy 	 */
591b1396c2bSRahul Lakkireddy 	if (netif_running(dev)) {
592*3822d067SRahul Lakkireddy 		netif_tx_stop_all_queues(dev);
593*3822d067SRahul Lakkireddy 		netif_carrier_off(dev);
594b1396c2bSRahul Lakkireddy 		needs_bring_up = true;
595b1396c2bSRahul Lakkireddy 	}
596b1396c2bSRahul Lakkireddy 
597b1396c2bSRahul Lakkireddy 	cxgb4_mqprio_disable_offload(dev);
598b1396c2bSRahul Lakkireddy 
599b1396c2bSRahul Lakkireddy 	/* If requested for clear, then just return since resources are
600b1396c2bSRahul Lakkireddy 	 * already freed up by now.
601b1396c2bSRahul Lakkireddy 	 */
602b1396c2bSRahul Lakkireddy 	if (!mqprio->qopt.num_tc)
603b1396c2bSRahul Lakkireddy 		goto out;
604b1396c2bSRahul Lakkireddy 
6050e395b3cSRahul Lakkireddy 	/* Allocate free available traffic classes and configure
6060e395b3cSRahul Lakkireddy 	 * their rate parameters.
6070e395b3cSRahul Lakkireddy 	 */
6080e395b3cSRahul Lakkireddy 	ret = cxgb4_mqprio_alloc_tc(dev, mqprio);
6090e395b3cSRahul Lakkireddy 	if (ret)
6100e395b3cSRahul Lakkireddy 		goto out;
6110e395b3cSRahul Lakkireddy 
612b1396c2bSRahul Lakkireddy 	ret = cxgb4_mqprio_enable_offload(dev, mqprio);
6130e395b3cSRahul Lakkireddy 	if (ret) {
6140e395b3cSRahul Lakkireddy 		cxgb4_mqprio_free_tc(dev);
6150e395b3cSRahul Lakkireddy 		goto out;
6160e395b3cSRahul Lakkireddy 	}
617b1396c2bSRahul Lakkireddy 
618b1396c2bSRahul Lakkireddy out:
619*3822d067SRahul Lakkireddy 	if (needs_bring_up) {
620*3822d067SRahul Lakkireddy 		netif_tx_start_all_queues(dev);
621*3822d067SRahul Lakkireddy 		netif_carrier_on(dev);
622*3822d067SRahul Lakkireddy 	}
623b1396c2bSRahul Lakkireddy 
6245148e595SRahul Lakkireddy 	mutex_unlock(&adap->tc_mqprio->mqprio_mutex);
625b1396c2bSRahul Lakkireddy 	return ret;
626b1396c2bSRahul Lakkireddy }
627b1396c2bSRahul Lakkireddy 
cxgb4_mqprio_stop_offload(struct adapter * adap)628cef8dac9SRahul Lakkireddy void cxgb4_mqprio_stop_offload(struct adapter *adap)
629cef8dac9SRahul Lakkireddy {
630cef8dac9SRahul Lakkireddy 	struct cxgb4_tc_port_mqprio *tc_port_mqprio;
631cef8dac9SRahul Lakkireddy 	struct net_device *dev;
632cef8dac9SRahul Lakkireddy 	u8 i;
633cef8dac9SRahul Lakkireddy 
634cef8dac9SRahul Lakkireddy 	if (!adap->tc_mqprio || !adap->tc_mqprio->port_mqprio)
635cef8dac9SRahul Lakkireddy 		return;
636cef8dac9SRahul Lakkireddy 
6375148e595SRahul Lakkireddy 	mutex_lock(&adap->tc_mqprio->mqprio_mutex);
638cef8dac9SRahul Lakkireddy 	for_each_port(adap, i) {
639cef8dac9SRahul Lakkireddy 		dev = adap->port[i];
640cef8dac9SRahul Lakkireddy 		if (!dev)
641cef8dac9SRahul Lakkireddy 			continue;
642cef8dac9SRahul Lakkireddy 
643cef8dac9SRahul Lakkireddy 		tc_port_mqprio = &adap->tc_mqprio->port_mqprio[i];
644cef8dac9SRahul Lakkireddy 		if (!tc_port_mqprio->mqprio.qopt.num_tc)
645cef8dac9SRahul Lakkireddy 			continue;
646cef8dac9SRahul Lakkireddy 
647cef8dac9SRahul Lakkireddy 		cxgb4_mqprio_disable_offload(dev);
648cef8dac9SRahul Lakkireddy 	}
6495148e595SRahul Lakkireddy 	mutex_unlock(&adap->tc_mqprio->mqprio_mutex);
650cef8dac9SRahul Lakkireddy }
651cef8dac9SRahul Lakkireddy 
cxgb4_init_tc_mqprio(struct adapter * adap)652b1396c2bSRahul Lakkireddy int cxgb4_init_tc_mqprio(struct adapter *adap)
653b1396c2bSRahul Lakkireddy {
654b1396c2bSRahul Lakkireddy 	struct cxgb4_tc_port_mqprio *tc_port_mqprio, *port_mqprio;
655b1396c2bSRahul Lakkireddy 	struct cxgb4_tc_mqprio *tc_mqprio;
656b1396c2bSRahul Lakkireddy 	struct sge_eosw_txq *eosw_txq;
657b1396c2bSRahul Lakkireddy 	int ret = 0;
658b1396c2bSRahul Lakkireddy 	u8 i;
659b1396c2bSRahul Lakkireddy 
660b1396c2bSRahul Lakkireddy 	tc_mqprio = kzalloc(sizeof(*tc_mqprio), GFP_KERNEL);
661b1396c2bSRahul Lakkireddy 	if (!tc_mqprio)
662b1396c2bSRahul Lakkireddy 		return -ENOMEM;
663b1396c2bSRahul Lakkireddy 
664b1396c2bSRahul Lakkireddy 	tc_port_mqprio = kcalloc(adap->params.nports, sizeof(*tc_port_mqprio),
665b1396c2bSRahul Lakkireddy 				 GFP_KERNEL);
666b1396c2bSRahul Lakkireddy 	if (!tc_port_mqprio) {
667b1396c2bSRahul Lakkireddy 		ret = -ENOMEM;
668b1396c2bSRahul Lakkireddy 		goto out_free_mqprio;
669b1396c2bSRahul Lakkireddy 	}
670b1396c2bSRahul Lakkireddy 
6715148e595SRahul Lakkireddy 	mutex_init(&tc_mqprio->mqprio_mutex);
6725148e595SRahul Lakkireddy 
673b1396c2bSRahul Lakkireddy 	tc_mqprio->port_mqprio = tc_port_mqprio;
674b1396c2bSRahul Lakkireddy 	for (i = 0; i < adap->params.nports; i++) {
675b1396c2bSRahul Lakkireddy 		port_mqprio = &tc_mqprio->port_mqprio[i];
676b1396c2bSRahul Lakkireddy 		eosw_txq = kcalloc(adap->tids.neotids, sizeof(*eosw_txq),
677b1396c2bSRahul Lakkireddy 				   GFP_KERNEL);
678b1396c2bSRahul Lakkireddy 		if (!eosw_txq) {
679b1396c2bSRahul Lakkireddy 			ret = -ENOMEM;
680b1396c2bSRahul Lakkireddy 			goto out_free_ports;
681b1396c2bSRahul Lakkireddy 		}
682b1396c2bSRahul Lakkireddy 		port_mqprio->eosw_txq = eosw_txq;
683b1396c2bSRahul Lakkireddy 	}
684b1396c2bSRahul Lakkireddy 
685b1396c2bSRahul Lakkireddy 	adap->tc_mqprio = tc_mqprio;
6862d0cb84dSRahul Lakkireddy 	refcount_set(&adap->tc_mqprio->refcnt, 0);
687b1396c2bSRahul Lakkireddy 	return 0;
688b1396c2bSRahul Lakkireddy 
689b1396c2bSRahul Lakkireddy out_free_ports:
690b1396c2bSRahul Lakkireddy 	for (i = 0; i < adap->params.nports; i++) {
691b1396c2bSRahul Lakkireddy 		port_mqprio = &tc_mqprio->port_mqprio[i];
692b1396c2bSRahul Lakkireddy 		kfree(port_mqprio->eosw_txq);
693b1396c2bSRahul Lakkireddy 	}
694b1396c2bSRahul Lakkireddy 	kfree(tc_port_mqprio);
695b1396c2bSRahul Lakkireddy 
696b1396c2bSRahul Lakkireddy out_free_mqprio:
697b1396c2bSRahul Lakkireddy 	kfree(tc_mqprio);
698b1396c2bSRahul Lakkireddy 	return ret;
699b1396c2bSRahul Lakkireddy }
700b1396c2bSRahul Lakkireddy 
cxgb4_cleanup_tc_mqprio(struct adapter * adap)701b1396c2bSRahul Lakkireddy void cxgb4_cleanup_tc_mqprio(struct adapter *adap)
702b1396c2bSRahul Lakkireddy {
703b1396c2bSRahul Lakkireddy 	struct cxgb4_tc_port_mqprio *port_mqprio;
704b1396c2bSRahul Lakkireddy 	u8 i;
705b1396c2bSRahul Lakkireddy 
706b1396c2bSRahul Lakkireddy 	if (adap->tc_mqprio) {
7075148e595SRahul Lakkireddy 		mutex_lock(&adap->tc_mqprio->mqprio_mutex);
708b1396c2bSRahul Lakkireddy 		if (adap->tc_mqprio->port_mqprio) {
709b1396c2bSRahul Lakkireddy 			for (i = 0; i < adap->params.nports; i++) {
710b1396c2bSRahul Lakkireddy 				struct net_device *dev = adap->port[i];
711b1396c2bSRahul Lakkireddy 
712b1396c2bSRahul Lakkireddy 				if (dev)
713b1396c2bSRahul Lakkireddy 					cxgb4_mqprio_disable_offload(dev);
714b1396c2bSRahul Lakkireddy 				port_mqprio = &adap->tc_mqprio->port_mqprio[i];
715b1396c2bSRahul Lakkireddy 				kfree(port_mqprio->eosw_txq);
716b1396c2bSRahul Lakkireddy 			}
717b1396c2bSRahul Lakkireddy 			kfree(adap->tc_mqprio->port_mqprio);
718b1396c2bSRahul Lakkireddy 		}
7195148e595SRahul Lakkireddy 		mutex_unlock(&adap->tc_mqprio->mqprio_mutex);
720b1396c2bSRahul Lakkireddy 		kfree(adap->tc_mqprio);
721b1396c2bSRahul Lakkireddy 	}
722b1396c2bSRahul Lakkireddy }
723