723 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (C) 2019 Chelsio Communications. All rights reserved. */3 4#include "cxgb4.h"5#include "cxgb4_tc_mqprio.h"6#include "sched.h"7 8static int cxgb4_mqprio_validate(struct net_device *dev,9 struct tc_mqprio_qopt_offload *mqprio)10{11 u64 min_rate = 0, max_rate = 0, max_link_rate;12 struct port_info *pi = netdev2pinfo(dev);13 struct adapter *adap = netdev2adap(dev);14 u32 speed, qcount = 0, qoffset = 0;15 u32 start_a, start_b, end_a, end_b;16 int ret;17 u8 i, j;18 19 if (!mqprio->qopt.num_tc)20 return 0;21 22 if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS) {23 netdev_err(dev, "Only full TC hardware offload is supported\n");24 return -EINVAL;25 } else if (mqprio->mode != TC_MQPRIO_MODE_CHANNEL) {26 netdev_err(dev, "Only channel mode offload is supported\n");27 return -EINVAL;28 } else if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE) {29 netdev_err(dev, "Only bandwidth rate shaper supported\n");30 return -EINVAL;31 } else if (mqprio->qopt.num_tc > adap->params.nsched_cls) {32 netdev_err(dev,33 "Only %u traffic classes supported by hardware\n",34 adap->params.nsched_cls);35 return -ERANGE;36 }37 38 ret = t4_get_link_params(pi, NULL, &speed, NULL);39 if (ret) {40 netdev_err(dev, "Failed to get link speed, ret: %d\n", ret);41 return -EINVAL;42 }43 44 /* Convert from Mbps to bps */45 max_link_rate = (u64)speed * 1000 * 1000;46 47 for (i = 0; i < mqprio->qopt.num_tc; i++) {48 qoffset = max_t(u16, mqprio->qopt.offset[i], qoffset);49 qcount += mqprio->qopt.count[i];50 51 start_a = mqprio->qopt.offset[i];52 end_a = start_a + mqprio->qopt.count[i] - 1;53 for (j = i + 1; j < mqprio->qopt.num_tc; j++) {54 start_b = mqprio->qopt.offset[j];55 end_b = start_b + mqprio->qopt.count[j] - 1;56 57 /* If queue count is 0, then the traffic58 * belonging to this class will not use59 * ETHOFLD queues. So, no need to validate60 * further.61 */62 if (!mqprio->qopt.count[i])63 break;64 65 if (!mqprio->qopt.count[j])66 continue;67 68 if (max_t(u32, start_a, start_b) <=69 min_t(u32, end_a, end_b)) {70 netdev_err(dev,71 "Queues can't overlap across tc\n");72 return -EINVAL;73 }74 }75 76 /* Convert byte per second to bits per second */77 min_rate += (mqprio->min_rate[i] * 8);78 max_rate += (mqprio->max_rate[i] * 8);79 }80 81 if (qoffset >= adap->tids.neotids || qcount > adap->tids.neotids)82 return -ENOMEM;83 84 if (min_rate > max_link_rate || max_rate > max_link_rate) {85 netdev_err(dev,86 "Total Min/Max (%llu/%llu) Rate > supported (%llu)\n",87 min_rate, max_rate, max_link_rate);88 return -EINVAL;89 }90 91 return 0;92}93 94static int cxgb4_init_eosw_txq(struct net_device *dev,95 struct sge_eosw_txq *eosw_txq,96 u32 eotid, u32 hwqid)97{98 struct adapter *adap = netdev2adap(dev);99 struct tx_sw_desc *ring;100 101 memset(eosw_txq, 0, sizeof(*eosw_txq));102 103 ring = kcalloc(CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM,104 sizeof(*ring), GFP_KERNEL);105 if (!ring)106 return -ENOMEM;107 108 eosw_txq->desc = ring;109 eosw_txq->ndesc = CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM;110 spin_lock_init(&eosw_txq->lock);111 eosw_txq->state = CXGB4_EO_STATE_CLOSED;112 eosw_txq->eotid = eotid;113 eosw_txq->hwtid = adap->tids.eotid_base + eosw_txq->eotid;114 eosw_txq->cred = adap->params.ofldq_wr_cred;115 eosw_txq->hwqid = hwqid;116 eosw_txq->netdev = dev;117 tasklet_setup(&eosw_txq->qresume_tsk, cxgb4_ethofld_restart);118 return 0;119}120 121static void cxgb4_clean_eosw_txq(struct net_device *dev,122 struct sge_eosw_txq *eosw_txq)123{124 struct adapter *adap = netdev2adap(dev);125 126 cxgb4_eosw_txq_free_desc(adap, eosw_txq, eosw_txq->ndesc);127 eosw_txq->pidx = 0;128 eosw_txq->last_pidx = 0;129 eosw_txq->cidx = 0;130 eosw_txq->last_cidx = 0;131 eosw_txq->flowc_idx = 0;132 eosw_txq->inuse = 0;133 eosw_txq->cred = adap->params.ofldq_wr_cred;134 eosw_txq->ncompl = 0;135 eosw_txq->last_compl = 0;136 eosw_txq->state = CXGB4_EO_STATE_CLOSED;137}138 139static void cxgb4_free_eosw_txq(struct net_device *dev,140 struct sge_eosw_txq *eosw_txq)141{142 spin_lock_bh(&eosw_txq->lock);143 cxgb4_clean_eosw_txq(dev, eosw_txq);144 kfree(eosw_txq->desc);145 spin_unlock_bh(&eosw_txq->lock);146 tasklet_kill(&eosw_txq->qresume_tsk);147}148 149static int cxgb4_mqprio_alloc_hw_resources(struct net_device *dev)150{151 struct port_info *pi = netdev2pinfo(dev);152 struct adapter *adap = netdev2adap(dev);153 struct sge_ofld_rxq *eorxq;154 struct sge_eohw_txq *eotxq;155 int ret, msix = 0;156 u32 i;157 158 /* Allocate ETHOFLD hardware queue structures if not done already */159 if (!refcount_read(&adap->tc_mqprio->refcnt)) {160 adap->sge.eohw_rxq = kcalloc(adap->sge.eoqsets,161 sizeof(struct sge_ofld_rxq),162 GFP_KERNEL);163 if (!adap->sge.eohw_rxq)164 return -ENOMEM;165 166 adap->sge.eohw_txq = kcalloc(adap->sge.eoqsets,167 sizeof(struct sge_eohw_txq),168 GFP_KERNEL);169 if (!adap->sge.eohw_txq) {170 kfree(adap->sge.eohw_rxq);171 return -ENOMEM;172 }173 174 refcount_set(&adap->tc_mqprio->refcnt, 1);175 } else {176 refcount_inc(&adap->tc_mqprio->refcnt);177 }178 179 if (!(adap->flags & CXGB4_USING_MSIX))180 msix = -((int)adap->sge.intrq.abs_id + 1);181 182 for (i = 0; i < pi->nqsets; i++) {183 eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];184 eotxq = &adap->sge.eohw_txq[pi->first_qset + i];185 186 /* Allocate Rxqs for receiving ETHOFLD Tx completions */187 if (msix >= 0) {188 msix = cxgb4_get_msix_idx_from_bmap(adap);189 if (msix < 0) {190 ret = msix;191 goto out_free_queues;192 }193 194 eorxq->msix = &adap->msix_info[msix];195 snprintf(eorxq->msix->desc,196 sizeof(eorxq->msix->desc),197 "%s-eorxq%d", dev->name, i);198 }199 200 init_rspq(adap, &eorxq->rspq,201 CXGB4_EOHW_RXQ_DEFAULT_INTR_USEC,202 CXGB4_EOHW_RXQ_DEFAULT_PKT_CNT,203 CXGB4_EOHW_RXQ_DEFAULT_DESC_NUM,204 CXGB4_EOHW_RXQ_DEFAULT_DESC_SIZE);205 206 eorxq->fl.size = CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM;207 208 ret = t4_sge_alloc_rxq(adap, &eorxq->rspq, false,209 dev, msix, &eorxq->fl,210 cxgb4_ethofld_rx_handler,211 NULL, 0);212 if (ret)213 goto out_free_queues;214 215 /* Allocate ETHOFLD hardware Txqs */216 eotxq->q.size = CXGB4_EOHW_TXQ_DEFAULT_DESC_NUM;217 ret = t4_sge_alloc_ethofld_txq(adap, eotxq, dev,218 eorxq->rspq.cntxt_id);219 if (ret)220 goto out_free_queues;221 222 /* Allocate IRQs, set IRQ affinity, and start Rx */223 if (adap->flags & CXGB4_USING_MSIX) {224 ret = request_irq(eorxq->msix->vec, t4_sge_intr_msix, 0,225 eorxq->msix->desc, &eorxq->rspq);226 if (ret)227 goto out_free_msix;228 229 cxgb4_set_msix_aff(adap, eorxq->msix->vec,230 &eorxq->msix->aff_mask, i);231 }232 233 if (adap->flags & CXGB4_FULL_INIT_DONE)234 cxgb4_enable_rx(adap, &eorxq->rspq);235 }236 237 return 0;238 239out_free_msix:240 while (i-- > 0) {241 eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];242 243 if (adap->flags & CXGB4_FULL_INIT_DONE)244 cxgb4_quiesce_rx(&eorxq->rspq);245 246 if (adap->flags & CXGB4_USING_MSIX) {247 cxgb4_clear_msix_aff(eorxq->msix->vec,248 eorxq->msix->aff_mask);249 free_irq(eorxq->msix->vec, &eorxq->rspq);250 }251 }252 253out_free_queues:254 for (i = 0; i < pi->nqsets; i++) {255 eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];256 eotxq = &adap->sge.eohw_txq[pi->first_qset + i];257 258 if (eorxq->rspq.desc)259 free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl);260 if (eorxq->msix)261 cxgb4_free_msix_idx_in_bmap(adap, eorxq->msix->idx);262 t4_sge_free_ethofld_txq(adap, eotxq);263 }264 265 if (refcount_dec_and_test(&adap->tc_mqprio->refcnt)) {266 kfree(adap->sge.eohw_txq);267 kfree(adap->sge.eohw_rxq);268 }269 return ret;270}271 272static void cxgb4_mqprio_free_hw_resources(struct net_device *dev)273{274 struct port_info *pi = netdev2pinfo(dev);275 struct adapter *adap = netdev2adap(dev);276 struct sge_ofld_rxq *eorxq;277 struct sge_eohw_txq *eotxq;278 u32 i;279 280 /* Return if no ETHOFLD structures have been allocated yet */281 if (!refcount_read(&adap->tc_mqprio->refcnt))282 return;283 284 /* Return if no hardware queues have been allocated */285 if (!adap->sge.eohw_rxq[pi->first_qset].rspq.desc)286 return;287 288 for (i = 0; i < pi->nqsets; i++) {289 eorxq = &adap->sge.eohw_rxq[pi->first_qset + i];290 eotxq = &adap->sge.eohw_txq[pi->first_qset + i];291 292 /* Device removal path will already disable NAPI293 * before unregistering netdevice. So, only disable294 * NAPI if we're not in device removal path295 */296 if (!(adap->flags & CXGB4_SHUTTING_DOWN))297 cxgb4_quiesce_rx(&eorxq->rspq);298 299 if (adap->flags & CXGB4_USING_MSIX) {300 cxgb4_clear_msix_aff(eorxq->msix->vec,301 eorxq->msix->aff_mask);302 free_irq(eorxq->msix->vec, &eorxq->rspq);303 cxgb4_free_msix_idx_in_bmap(adap, eorxq->msix->idx);304 }305 306 free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl);307 t4_sge_free_ethofld_txq(adap, eotxq);308 }309 310 /* Free up ETHOFLD structures if there are no users */311 if (refcount_dec_and_test(&adap->tc_mqprio->refcnt)) {312 kfree(adap->sge.eohw_txq);313 kfree(adap->sge.eohw_rxq);314 }315}316 317static int cxgb4_mqprio_alloc_tc(struct net_device *dev,318 struct tc_mqprio_qopt_offload *mqprio)319{320 struct ch_sched_params p = {321 .type = SCHED_CLASS_TYPE_PACKET,322 .u.params.level = SCHED_CLASS_LEVEL_CL_RL,323 .u.params.mode = SCHED_CLASS_MODE_FLOW,324 .u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS,325 .u.params.ratemode = SCHED_CLASS_RATEMODE_ABS,326 .u.params.class = SCHED_CLS_NONE,327 .u.params.weight = 0,328 .u.params.pktsize = dev->mtu,329 };330 struct cxgb4_tc_port_mqprio *tc_port_mqprio;331 struct port_info *pi = netdev2pinfo(dev);332 struct adapter *adap = netdev2adap(dev);333 struct sched_class *e;334 int ret;335 u8 i;336 337 tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];338 p.u.params.channel = pi->tx_chan;339 for (i = 0; i < mqprio->qopt.num_tc; i++) {340 /* Convert from bytes per second to Kbps */341 p.u.params.minrate = div_u64(mqprio->min_rate[i] * 8, 1000);342 p.u.params.maxrate = div_u64(mqprio->max_rate[i] * 8, 1000);343 344 /* Request larger burst buffer for smaller MTU, so345 * that hardware can work on more data per burst346 * cycle.347 */348 if (dev->mtu <= ETH_DATA_LEN)349 p.u.params.burstsize = 8 * dev->mtu;350 351 e = cxgb4_sched_class_alloc(dev, &p);352 if (!e) {353 ret = -ENOMEM;354 goto out_err;355 }356 357 tc_port_mqprio->tc_hwtc_map[i] = e->idx;358 }359 360 return 0;361 362out_err:363 while (i--)364 cxgb4_sched_class_free(dev, tc_port_mqprio->tc_hwtc_map[i]);365 366 return ret;367}368 369static void cxgb4_mqprio_free_tc(struct net_device *dev)370{371 struct cxgb4_tc_port_mqprio *tc_port_mqprio;372 struct port_info *pi = netdev2pinfo(dev);373 struct adapter *adap = netdev2adap(dev);374 u8 i;375 376 tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];377 for (i = 0; i < tc_port_mqprio->mqprio.qopt.num_tc; i++)378 cxgb4_sched_class_free(dev, tc_port_mqprio->tc_hwtc_map[i]);379}380 381static int cxgb4_mqprio_class_bind(struct net_device *dev,382 struct sge_eosw_txq *eosw_txq,383 u8 tc)384{385 struct ch_sched_flowc fe;386 int ret;387 388 init_completion(&eosw_txq->completion);389 390 fe.tid = eosw_txq->eotid;391 fe.class = tc;392 393 ret = cxgb4_sched_class_bind(dev, &fe, SCHED_FLOWC);394 if (ret)395 return ret;396 397 ret = wait_for_completion_timeout(&eosw_txq->completion,398 CXGB4_FLOWC_WAIT_TIMEOUT);399 if (!ret)400 return -ETIMEDOUT;401 402 return 0;403}404 405static void cxgb4_mqprio_class_unbind(struct net_device *dev,406 struct sge_eosw_txq *eosw_txq,407 u8 tc)408{409 struct adapter *adap = netdev2adap(dev);410 struct ch_sched_flowc fe;411 412 /* If we're shutting down, interrupts are disabled and no completions413 * come back. So, skip waiting for completions in this scenario.414 */415 if (!(adap->flags & CXGB4_SHUTTING_DOWN))416 init_completion(&eosw_txq->completion);417 418 fe.tid = eosw_txq->eotid;419 fe.class = tc;420 cxgb4_sched_class_unbind(dev, &fe, SCHED_FLOWC);421 422 if (!(adap->flags & CXGB4_SHUTTING_DOWN))423 wait_for_completion_timeout(&eosw_txq->completion,424 CXGB4_FLOWC_WAIT_TIMEOUT);425}426 427static int cxgb4_mqprio_enable_offload(struct net_device *dev,428 struct tc_mqprio_qopt_offload *mqprio)429{430 struct cxgb4_tc_port_mqprio *tc_port_mqprio;431 u32 qoffset, qcount, tot_qcount, qid, hwqid;432 struct port_info *pi = netdev2pinfo(dev);433 struct adapter *adap = netdev2adap(dev);434 struct sge_eosw_txq *eosw_txq;435 int eotid, ret;436 u16 i, j;437 u8 hwtc;438 439 ret = cxgb4_mqprio_alloc_hw_resources(dev);440 if (ret)441 return -ENOMEM;442 443 tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];444 for (i = 0; i < mqprio->qopt.num_tc; i++) {445 qoffset = mqprio->qopt.offset[i];446 qcount = mqprio->qopt.count[i];447 for (j = 0; j < qcount; j++) {448 eotid = cxgb4_get_free_eotid(&adap->tids);449 if (eotid < 0) {450 ret = -ENOMEM;451 goto out_free_eotids;452 }453 454 qid = qoffset + j;455 hwqid = pi->first_qset + (eotid % pi->nqsets);456 eosw_txq = &tc_port_mqprio->eosw_txq[qid];457 ret = cxgb4_init_eosw_txq(dev, eosw_txq,458 eotid, hwqid);459 if (ret)460 goto out_free_eotids;461 462 cxgb4_alloc_eotid(&adap->tids, eotid, eosw_txq);463 464 hwtc = tc_port_mqprio->tc_hwtc_map[i];465 ret = cxgb4_mqprio_class_bind(dev, eosw_txq, hwtc);466 if (ret)467 goto out_free_eotids;468 }469 }470 471 memcpy(&tc_port_mqprio->mqprio, mqprio,472 sizeof(struct tc_mqprio_qopt_offload));473 474 /* Inform the stack about the configured tc params.475 *476 * Set the correct queue map. If no queue count has been477 * specified, then send the traffic through default NIC478 * queues; instead of ETHOFLD queues.479 */480 ret = netdev_set_num_tc(dev, mqprio->qopt.num_tc);481 if (ret)482 goto out_free_eotids;483 484 tot_qcount = pi->nqsets;485 for (i = 0; i < mqprio->qopt.num_tc; i++) {486 qcount = mqprio->qopt.count[i];487 if (qcount) {488 qoffset = mqprio->qopt.offset[i] + pi->nqsets;489 } else {490 qcount = pi->nqsets;491 qoffset = 0;492 }493 494 ret = netdev_set_tc_queue(dev, i, qcount, qoffset);495 if (ret)496 goto out_reset_tc;497 498 tot_qcount += mqprio->qopt.count[i];499 }500 501 ret = netif_set_real_num_tx_queues(dev, tot_qcount);502 if (ret)503 goto out_reset_tc;504 505 tc_port_mqprio->state = CXGB4_MQPRIO_STATE_ACTIVE;506 return 0;507 508out_reset_tc:509 netdev_reset_tc(dev);510 i = mqprio->qopt.num_tc;511 512out_free_eotids:513 while (i-- > 0) {514 qoffset = mqprio->qopt.offset[i];515 qcount = mqprio->qopt.count[i];516 for (j = 0; j < qcount; j++) {517 eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j];518 519 hwtc = tc_port_mqprio->tc_hwtc_map[i];520 cxgb4_mqprio_class_unbind(dev, eosw_txq, hwtc);521 522 cxgb4_free_eotid(&adap->tids, eosw_txq->eotid);523 cxgb4_free_eosw_txq(dev, eosw_txq);524 }525 }526 527 cxgb4_mqprio_free_hw_resources(dev);528 return ret;529}530 531static void cxgb4_mqprio_disable_offload(struct net_device *dev)532{533 struct cxgb4_tc_port_mqprio *tc_port_mqprio;534 struct port_info *pi = netdev2pinfo(dev);535 struct adapter *adap = netdev2adap(dev);536 struct sge_eosw_txq *eosw_txq;537 u32 qoffset, qcount;538 u16 i, j;539 u8 hwtc;540 541 tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id];542 if (tc_port_mqprio->state != CXGB4_MQPRIO_STATE_ACTIVE)543 return;544 545 netdev_reset_tc(dev);546 netif_set_real_num_tx_queues(dev, pi->nqsets);547 548 for (i = 0; i < tc_port_mqprio->mqprio.qopt.num_tc; i++) {549 qoffset = tc_port_mqprio->mqprio.qopt.offset[i];550 qcount = tc_port_mqprio->mqprio.qopt.count[i];551 for (j = 0; j < qcount; j++) {552 eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j];553 554 hwtc = tc_port_mqprio->tc_hwtc_map[i];555 cxgb4_mqprio_class_unbind(dev, eosw_txq, hwtc);556 557 cxgb4_free_eotid(&adap->tids, eosw_txq->eotid);558 cxgb4_free_eosw_txq(dev, eosw_txq);559 }560 }561 562 cxgb4_mqprio_free_hw_resources(dev);563 564 /* Free up the traffic classes */565 cxgb4_mqprio_free_tc(dev);566 567 memset(&tc_port_mqprio->mqprio, 0,568 sizeof(struct tc_mqprio_qopt_offload));569 570 tc_port_mqprio->state = CXGB4_MQPRIO_STATE_DISABLED;571}572 573int cxgb4_setup_tc_mqprio(struct net_device *dev,574 struct tc_mqprio_qopt_offload *mqprio)575{576 struct adapter *adap = netdev2adap(dev);577 bool needs_bring_up = false;578 int ret;579 580 ret = cxgb4_mqprio_validate(dev, mqprio);581 if (ret)582 return ret;583 584 mutex_lock(&adap->tc_mqprio->mqprio_mutex);585 586 /* To configure tc params, the current allocated EOTIDs must587 * be freed up. However, they can't be freed up if there's588 * traffic running on the interface. So, ensure interface is589 * down before configuring tc params.590 */591 if (netif_running(dev)) {592 netif_tx_stop_all_queues(dev);593 netif_carrier_off(dev);594 needs_bring_up = true;595 }596 597 cxgb4_mqprio_disable_offload(dev);598 599 /* If requested for clear, then just return since resources are600 * already freed up by now.601 */602 if (!mqprio->qopt.num_tc)603 goto out;604 605 /* Allocate free available traffic classes and configure606 * their rate parameters.607 */608 ret = cxgb4_mqprio_alloc_tc(dev, mqprio);609 if (ret)610 goto out;611 612 ret = cxgb4_mqprio_enable_offload(dev, mqprio);613 if (ret) {614 cxgb4_mqprio_free_tc(dev);615 goto out;616 }617 618out:619 if (needs_bring_up) {620 netif_tx_start_all_queues(dev);621 netif_carrier_on(dev);622 }623 624 mutex_unlock(&adap->tc_mqprio->mqprio_mutex);625 return ret;626}627 628void cxgb4_mqprio_stop_offload(struct adapter *adap)629{630 struct cxgb4_tc_port_mqprio *tc_port_mqprio;631 struct net_device *dev;632 u8 i;633 634 if (!adap->tc_mqprio || !adap->tc_mqprio->port_mqprio)635 return;636 637 mutex_lock(&adap->tc_mqprio->mqprio_mutex);638 for_each_port(adap, i) {639 dev = adap->port[i];640 if (!dev)641 continue;642 643 tc_port_mqprio = &adap->tc_mqprio->port_mqprio[i];644 if (!tc_port_mqprio->mqprio.qopt.num_tc)645 continue;646 647 cxgb4_mqprio_disable_offload(dev);648 }649 mutex_unlock(&adap->tc_mqprio->mqprio_mutex);650}651 652int cxgb4_init_tc_mqprio(struct adapter *adap)653{654 struct cxgb4_tc_port_mqprio *tc_port_mqprio, *port_mqprio;655 struct cxgb4_tc_mqprio *tc_mqprio;656 struct sge_eosw_txq *eosw_txq;657 int ret = 0;658 u8 i;659 660 tc_mqprio = kzalloc(sizeof(*tc_mqprio), GFP_KERNEL);661 if (!tc_mqprio)662 return -ENOMEM;663 664 tc_port_mqprio = kcalloc(adap->params.nports, sizeof(*tc_port_mqprio),665 GFP_KERNEL);666 if (!tc_port_mqprio) {667 ret = -ENOMEM;668 goto out_free_mqprio;669 }670 671 mutex_init(&tc_mqprio->mqprio_mutex);672 673 tc_mqprio->port_mqprio = tc_port_mqprio;674 for (i = 0; i < adap->params.nports; i++) {675 port_mqprio = &tc_mqprio->port_mqprio[i];676 eosw_txq = kcalloc(adap->tids.neotids, sizeof(*eosw_txq),677 GFP_KERNEL);678 if (!eosw_txq) {679 ret = -ENOMEM;680 goto out_free_ports;681 }682 port_mqprio->eosw_txq = eosw_txq;683 }684 685 adap->tc_mqprio = tc_mqprio;686 refcount_set(&adap->tc_mqprio->refcnt, 0);687 return 0;688 689out_free_ports:690 for (i = 0; i < adap->params.nports; i++) {691 port_mqprio = &tc_mqprio->port_mqprio[i];692 kfree(port_mqprio->eosw_txq);693 }694 kfree(tc_port_mqprio);695 696out_free_mqprio:697 kfree(tc_mqprio);698 return ret;699}700 701void cxgb4_cleanup_tc_mqprio(struct adapter *adap)702{703 struct cxgb4_tc_port_mqprio *port_mqprio;704 u8 i;705 706 if (adap->tc_mqprio) {707 mutex_lock(&adap->tc_mqprio->mqprio_mutex);708 if (adap->tc_mqprio->port_mqprio) {709 for (i = 0; i < adap->params.nports; i++) {710 struct net_device *dev = adap->port[i];711 712 if (dev)713 cxgb4_mqprio_disable_offload(dev);714 port_mqprio = &adap->tc_mqprio->port_mqprio[i];715 kfree(port_mqprio->eosw_txq);716 }717 kfree(adap->tc_mqprio->port_mqprio);718 }719 mutex_unlock(&adap->tc_mqprio->mqprio_mutex);720 kfree(adap->tc_mqprio);721 }722}723