162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * cxgb4_uld.c:Chelsio Upper Layer Driver Interface for T4/T5/T6 SGE management 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Written by: Atul Gupta (atul.gupta@chelsio.com) 3562306a36Sopenharmony_ci * Written by: Hariprasad Shenai (hariprasad@chelsio.com) 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <linux/kernel.h> 3962306a36Sopenharmony_ci#include <linux/module.h> 4062306a36Sopenharmony_ci#include <linux/errno.h> 4162306a36Sopenharmony_ci#include <linux/types.h> 4262306a36Sopenharmony_ci#include <linux/debugfs.h> 4362306a36Sopenharmony_ci#include <linux/export.h> 4462306a36Sopenharmony_ci#include <linux/list.h> 4562306a36Sopenharmony_ci#include <linux/skbuff.h> 4662306a36Sopenharmony_ci#include <linux/pci.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include "cxgb4.h" 4962306a36Sopenharmony_ci#include "cxgb4_uld.h" 5062306a36Sopenharmony_ci#include "t4_regs.h" 5162306a36Sopenharmony_ci#include "t4fw_api.h" 5262306a36Sopenharmony_ci#include "t4_msg.h" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define for_each_uldrxq(m, i) for (i = 0; i < ((m)->nrxq + (m)->nciq); i++) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* Flush the aggregated lro sessions */ 5762306a36Sopenharmony_cistatic void uldrx_flush_handler(struct sge_rspq *q) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct adapter *adap = q->adap; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (adap->uld[q->uld].lro_flush) 6262306a36Sopenharmony_ci adap->uld[q->uld].lro_flush(&q->lro_mgr); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/** 6662306a36Sopenharmony_ci * uldrx_handler - response queue handler for ULD queues 6762306a36Sopenharmony_ci * @q: the response queue that received the packet 6862306a36Sopenharmony_ci * @rsp: the response queue descriptor holding the offload message 6962306a36Sopenharmony_ci * @gl: the gather list of packet fragments 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Deliver an ingress offload packet to a ULD. All processing is done by 7262306a36Sopenharmony_ci * the ULD, we just maintain statistics. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistatic int uldrx_handler(struct sge_rspq *q, const __be64 *rsp, 7562306a36Sopenharmony_ci const struct pkt_gl *gl) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct adapter *adap = q->adap; 7862306a36Sopenharmony_ci struct sge_ofld_rxq *rxq = container_of(q, struct sge_ofld_rxq, rspq); 7962306a36Sopenharmony_ci int ret; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* FW can send CPLs encapsulated in a CPL_FW4_MSG */ 8262306a36Sopenharmony_ci if (((const struct rss_header *)rsp)->opcode == CPL_FW4_MSG && 8362306a36Sopenharmony_ci ((const struct cpl_fw4_msg *)(rsp + 1))->type == FW_TYPE_RSSCPL) 8462306a36Sopenharmony_ci rsp += 2; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (q->flush_handler) 8762306a36Sopenharmony_ci ret = adap->uld[q->uld].lro_rx_handler(adap->uld[q->uld].handle, 8862306a36Sopenharmony_ci rsp, gl, &q->lro_mgr, 8962306a36Sopenharmony_ci &q->napi); 9062306a36Sopenharmony_ci else 9162306a36Sopenharmony_ci ret = adap->uld[q->uld].rx_handler(adap->uld[q->uld].handle, 9262306a36Sopenharmony_ci rsp, gl); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (ret) { 9562306a36Sopenharmony_ci rxq->stats.nomem++; 9662306a36Sopenharmony_ci return -1; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!gl) 10062306a36Sopenharmony_ci rxq->stats.imm++; 10162306a36Sopenharmony_ci else if (gl == CXGB4_MSG_AN) 10262306a36Sopenharmony_ci rxq->stats.an++; 10362306a36Sopenharmony_ci else 10462306a36Sopenharmony_ci rxq->stats.pkts++; 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int alloc_uld_rxqs(struct adapter *adap, 10962306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info, bool lro) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci unsigned int nq = rxq_info->nrxq + rxq_info->nciq; 11262306a36Sopenharmony_ci struct sge_ofld_rxq *q = rxq_info->uldrxq; 11362306a36Sopenharmony_ci unsigned short *ids = rxq_info->rspq_id; 11462306a36Sopenharmony_ci int i, err, msi_idx, que_idx = 0; 11562306a36Sopenharmony_ci struct sge *s = &adap->sge; 11662306a36Sopenharmony_ci unsigned int per_chan; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci per_chan = rxq_info->nrxq / adap->params.nports; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) 12162306a36Sopenharmony_ci msi_idx = 1; 12262306a36Sopenharmony_ci else 12362306a36Sopenharmony_ci msi_idx = -((int)s->intrq.abs_id + 1); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci for (i = 0; i < nq; i++, q++) { 12662306a36Sopenharmony_ci if (i == rxq_info->nrxq) { 12762306a36Sopenharmony_ci /* start allocation of concentrator queues */ 12862306a36Sopenharmony_ci per_chan = rxq_info->nciq / adap->params.nports; 12962306a36Sopenharmony_ci que_idx = 0; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (msi_idx >= 0) { 13362306a36Sopenharmony_ci msi_idx = cxgb4_get_msix_idx_from_bmap(adap); 13462306a36Sopenharmony_ci if (msi_idx < 0) { 13562306a36Sopenharmony_ci err = -ENOSPC; 13662306a36Sopenharmony_ci goto freeout; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci snprintf(adap->msix_info[msi_idx].desc, 14062306a36Sopenharmony_ci sizeof(adap->msix_info[msi_idx].desc), 14162306a36Sopenharmony_ci "%s-%s%d", 14262306a36Sopenharmony_ci adap->port[0]->name, rxq_info->name, i); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci q->msix = &adap->msix_info[msi_idx]; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci err = t4_sge_alloc_rxq(adap, &q->rspq, false, 14762306a36Sopenharmony_ci adap->port[que_idx++ / per_chan], 14862306a36Sopenharmony_ci msi_idx, 14962306a36Sopenharmony_ci q->fl.size ? &q->fl : NULL, 15062306a36Sopenharmony_ci uldrx_handler, 15162306a36Sopenharmony_ci lro ? uldrx_flush_handler : NULL, 15262306a36Sopenharmony_ci 0); 15362306a36Sopenharmony_ci if (err) 15462306a36Sopenharmony_ci goto freeout; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci memset(&q->stats, 0, sizeof(q->stats)); 15762306a36Sopenharmony_ci if (ids) 15862306a36Sopenharmony_ci ids[i] = q->rspq.abs_id; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_cifreeout: 16262306a36Sopenharmony_ci q = rxq_info->uldrxq; 16362306a36Sopenharmony_ci for ( ; i; i--, q++) { 16462306a36Sopenharmony_ci if (q->rspq.desc) 16562306a36Sopenharmony_ci free_rspq_fl(adap, &q->rspq, 16662306a36Sopenharmony_ci q->fl.size ? &q->fl : NULL); 16762306a36Sopenharmony_ci if (q->msix) 16862306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, q->msix->idx); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci return err; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int 17462306a36Sopenharmony_cisetup_sge_queues_uld(struct adapter *adap, unsigned int uld_type, bool lro) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 17762306a36Sopenharmony_ci int i, ret; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci ret = alloc_uld_rxqs(adap, rxq_info, lro); 18062306a36Sopenharmony_ci if (ret) 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Tell uP to route control queue completions to rdma rspq */ 18462306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE && uld_type == CXGB4_ULD_RDMA) { 18562306a36Sopenharmony_ci struct sge *s = &adap->sge; 18662306a36Sopenharmony_ci unsigned int cmplqid; 18762306a36Sopenharmony_ci u32 param, cmdop; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci cmdop = FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL; 19062306a36Sopenharmony_ci for_each_port(adap, i) { 19162306a36Sopenharmony_ci cmplqid = rxq_info->uldrxq[i].rspq.cntxt_id; 19262306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 19362306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(cmdop) | 19462306a36Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(s->ctrlq[i].q.cntxt_id)); 19562306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 19662306a36Sopenharmony_ci 0, 1, ¶m, &cmplqid); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void t4_free_uld_rxqs(struct adapter *adap, int n, 20362306a36Sopenharmony_ci struct sge_ofld_rxq *q) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci for ( ; n; n--, q++) { 20662306a36Sopenharmony_ci if (q->rspq.desc) 20762306a36Sopenharmony_ci free_rspq_fl(adap, &q->rspq, 20862306a36Sopenharmony_ci q->fl.size ? &q->fl : NULL); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void free_sge_queues_uld(struct adapter *adap, unsigned int uld_type) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE && uld_type == CXGB4_ULD_RDMA) { 21762306a36Sopenharmony_ci struct sge *s = &adap->sge; 21862306a36Sopenharmony_ci u32 param, cmdop, cmplqid = 0; 21962306a36Sopenharmony_ci int i; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci cmdop = FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL; 22262306a36Sopenharmony_ci for_each_port(adap, i) { 22362306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 22462306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(cmdop) | 22562306a36Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(s->ctrlq[i].q.cntxt_id)); 22662306a36Sopenharmony_ci t4_set_params(adap, adap->mbox, adap->pf, 22762306a36Sopenharmony_ci 0, 1, ¶m, &cmplqid); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (rxq_info->nciq) 23262306a36Sopenharmony_ci t4_free_uld_rxqs(adap, rxq_info->nciq, 23362306a36Sopenharmony_ci rxq_info->uldrxq + rxq_info->nrxq); 23462306a36Sopenharmony_ci t4_free_uld_rxqs(adap, rxq_info->nrxq, rxq_info->uldrxq); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int cfg_queues_uld(struct adapter *adap, unsigned int uld_type, 23862306a36Sopenharmony_ci const struct cxgb4_uld_info *uld_info) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct sge *s = &adap->sge; 24162306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info; 24262306a36Sopenharmony_ci int i, nrxq, ciq_size; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci rxq_info = kzalloc(sizeof(*rxq_info), GFP_KERNEL); 24562306a36Sopenharmony_ci if (!rxq_info) 24662306a36Sopenharmony_ci return -ENOMEM; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX && uld_info->nrxq > s->nqs_per_uld) { 24962306a36Sopenharmony_ci i = s->nqs_per_uld; 25062306a36Sopenharmony_ci rxq_info->nrxq = roundup(i, adap->params.nports); 25162306a36Sopenharmony_ci } else { 25262306a36Sopenharmony_ci i = min_t(int, uld_info->nrxq, 25362306a36Sopenharmony_ci num_online_cpus()); 25462306a36Sopenharmony_ci rxq_info->nrxq = roundup(i, adap->params.nports); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci if (!uld_info->ciq) { 25762306a36Sopenharmony_ci rxq_info->nciq = 0; 25862306a36Sopenharmony_ci } else { 25962306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) 26062306a36Sopenharmony_ci rxq_info->nciq = min_t(int, s->nqs_per_uld, 26162306a36Sopenharmony_ci num_online_cpus()); 26262306a36Sopenharmony_ci else 26362306a36Sopenharmony_ci rxq_info->nciq = min_t(int, MAX_OFLD_QSETS, 26462306a36Sopenharmony_ci num_online_cpus()); 26562306a36Sopenharmony_ci rxq_info->nciq = ((rxq_info->nciq / adap->params.nports) * 26662306a36Sopenharmony_ci adap->params.nports); 26762306a36Sopenharmony_ci rxq_info->nciq = max_t(int, rxq_info->nciq, 26862306a36Sopenharmony_ci adap->params.nports); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci nrxq = rxq_info->nrxq + rxq_info->nciq; /* total rxq's */ 27262306a36Sopenharmony_ci rxq_info->uldrxq = kcalloc(nrxq, sizeof(struct sge_ofld_rxq), 27362306a36Sopenharmony_ci GFP_KERNEL); 27462306a36Sopenharmony_ci if (!rxq_info->uldrxq) { 27562306a36Sopenharmony_ci kfree(rxq_info); 27662306a36Sopenharmony_ci return -ENOMEM; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci rxq_info->rspq_id = kcalloc(nrxq, sizeof(unsigned short), GFP_KERNEL); 28062306a36Sopenharmony_ci if (!rxq_info->rspq_id) { 28162306a36Sopenharmony_ci kfree(rxq_info->uldrxq); 28262306a36Sopenharmony_ci kfree(rxq_info); 28362306a36Sopenharmony_ci return -ENOMEM; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci for (i = 0; i < rxq_info->nrxq; i++) { 28762306a36Sopenharmony_ci struct sge_ofld_rxq *r = &rxq_info->uldrxq[i]; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci init_rspq(adap, &r->rspq, 5, 1, uld_info->rxq_size, 64); 29062306a36Sopenharmony_ci r->rspq.uld = uld_type; 29162306a36Sopenharmony_ci r->fl.size = 72; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ciq_size = 64 + adap->vres.cq.size + adap->tids.nftids; 29562306a36Sopenharmony_ci if (ciq_size > SGE_MAX_IQ_SIZE) { 29662306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "CIQ size too small for available IQs\n"); 29762306a36Sopenharmony_ci ciq_size = SGE_MAX_IQ_SIZE; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci for (i = rxq_info->nrxq; i < nrxq; i++) { 30162306a36Sopenharmony_ci struct sge_ofld_rxq *r = &rxq_info->uldrxq[i]; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci init_rspq(adap, &r->rspq, 5, 1, ciq_size, 64); 30462306a36Sopenharmony_ci r->rspq.uld = uld_type; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci memcpy(rxq_info->name, uld_info->name, IFNAMSIZ); 30862306a36Sopenharmony_ci adap->sge.uld_rxq_info[uld_type] = rxq_info; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void free_queues_uld(struct adapter *adap, unsigned int uld_type) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci adap->sge.uld_rxq_info[uld_type] = NULL; 31862306a36Sopenharmony_ci kfree(rxq_info->rspq_id); 31962306a36Sopenharmony_ci kfree(rxq_info->uldrxq); 32062306a36Sopenharmony_ci kfree(rxq_info); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int 32462306a36Sopenharmony_cirequest_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 32762306a36Sopenharmony_ci struct msix_info *minfo; 32862306a36Sopenharmony_ci unsigned int idx; 32962306a36Sopenharmony_ci int err = 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci for_each_uldrxq(rxq_info, idx) { 33262306a36Sopenharmony_ci minfo = rxq_info->uldrxq[idx].msix; 33362306a36Sopenharmony_ci err = request_irq(minfo->vec, 33462306a36Sopenharmony_ci t4_sge_intr_msix, 0, 33562306a36Sopenharmony_ci minfo->desc, 33662306a36Sopenharmony_ci &rxq_info->uldrxq[idx].rspq); 33762306a36Sopenharmony_ci if (err) 33862306a36Sopenharmony_ci goto unwind; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci cxgb4_set_msix_aff(adap, minfo->vec, 34162306a36Sopenharmony_ci &minfo->aff_mask, idx); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ciunwind: 34662306a36Sopenharmony_ci while (idx-- > 0) { 34762306a36Sopenharmony_ci minfo = rxq_info->uldrxq[idx].msix; 34862306a36Sopenharmony_ci cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); 34962306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, minfo->idx); 35062306a36Sopenharmony_ci free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci return err; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void 35662306a36Sopenharmony_cifree_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 35962306a36Sopenharmony_ci struct msix_info *minfo; 36062306a36Sopenharmony_ci unsigned int idx; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for_each_uldrxq(rxq_info, idx) { 36362306a36Sopenharmony_ci minfo = rxq_info->uldrxq[idx].msix; 36462306a36Sopenharmony_ci cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); 36562306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, minfo->idx); 36662306a36Sopenharmony_ci free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void enable_rx_uld(struct adapter *adap, unsigned int uld_type) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 37362306a36Sopenharmony_ci int idx; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for_each_uldrxq(rxq_info, idx) { 37662306a36Sopenharmony_ci struct sge_rspq *q = &rxq_info->uldrxq[idx].rspq; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!q) 37962306a36Sopenharmony_ci continue; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci cxgb4_enable_rx(adap, q); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic void quiesce_rx_uld(struct adapter *adap, unsigned int uld_type) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 38862306a36Sopenharmony_ci int idx; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci for_each_uldrxq(rxq_info, idx) { 39162306a36Sopenharmony_ci struct sge_rspq *q = &rxq_info->uldrxq[idx].rspq; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (!q) 39462306a36Sopenharmony_ci continue; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci cxgb4_quiesce_rx(q); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void 40162306a36Sopenharmony_cifree_sge_txq_uld(struct adapter *adap, struct sge_uld_txq_info *txq_info) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci int nq = txq_info->ntxq; 40462306a36Sopenharmony_ci int i; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci for (i = 0; i < nq; i++) { 40762306a36Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (txq && txq->q.desc) { 41062306a36Sopenharmony_ci tasklet_kill(&txq->qresume_tsk); 41162306a36Sopenharmony_ci t4_ofld_eq_free(adap, adap->mbox, adap->pf, 0, 41262306a36Sopenharmony_ci txq->q.cntxt_id); 41362306a36Sopenharmony_ci free_tx_desc(adap, &txq->q, txq->q.in_use, false); 41462306a36Sopenharmony_ci kfree(txq->q.sdesc); 41562306a36Sopenharmony_ci __skb_queue_purge(&txq->sendq); 41662306a36Sopenharmony_ci free_txq(adap, &txq->q); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int 42262306a36Sopenharmony_cialloc_sge_txq_uld(struct adapter *adap, struct sge_uld_txq_info *txq_info, 42362306a36Sopenharmony_ci unsigned int uld_type) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct sge *s = &adap->sge; 42662306a36Sopenharmony_ci int nq = txq_info->ntxq; 42762306a36Sopenharmony_ci int i, j, err; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci j = nq / adap->params.nports; 43062306a36Sopenharmony_ci for (i = 0; i < nq; i++) { 43162306a36Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci txq->q.size = 1024; 43462306a36Sopenharmony_ci err = t4_sge_alloc_uld_txq(adap, txq, adap->port[i / j], 43562306a36Sopenharmony_ci s->fw_evtq.cntxt_id, uld_type); 43662306a36Sopenharmony_ci if (err) 43762306a36Sopenharmony_ci goto freeout; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_cifreeout: 44162306a36Sopenharmony_ci free_sge_txq_uld(adap, txq_info); 44262306a36Sopenharmony_ci return err; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic void 44662306a36Sopenharmony_cirelease_sge_txq_uld(struct adapter *adap, unsigned int uld_type) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info = NULL; 44962306a36Sopenharmony_ci int tx_uld_type = TX_ULD(uld_type); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci txq_info = adap->sge.uld_txq_info[tx_uld_type]; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (txq_info && atomic_dec_and_test(&txq_info->users)) { 45462306a36Sopenharmony_ci free_sge_txq_uld(adap, txq_info); 45562306a36Sopenharmony_ci kfree(txq_info->uldtxq); 45662306a36Sopenharmony_ci kfree(txq_info); 45762306a36Sopenharmony_ci adap->sge.uld_txq_info[tx_uld_type] = NULL; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int 46262306a36Sopenharmony_cisetup_sge_txq_uld(struct adapter *adap, unsigned int uld_type, 46362306a36Sopenharmony_ci const struct cxgb4_uld_info *uld_info) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info = NULL; 46662306a36Sopenharmony_ci int tx_uld_type, i; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci tx_uld_type = TX_ULD(uld_type); 46962306a36Sopenharmony_ci txq_info = adap->sge.uld_txq_info[tx_uld_type]; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if ((tx_uld_type == CXGB4_TX_OFLD) && txq_info && 47262306a36Sopenharmony_ci (atomic_inc_return(&txq_info->users) > 1)) 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci txq_info = kzalloc(sizeof(*txq_info), GFP_KERNEL); 47662306a36Sopenharmony_ci if (!txq_info) 47762306a36Sopenharmony_ci return -ENOMEM; 47862306a36Sopenharmony_ci if (uld_type == CXGB4_ULD_CRYPTO) { 47962306a36Sopenharmony_ci i = min_t(int, adap->vres.ncrypto_fc, 48062306a36Sopenharmony_ci num_online_cpus()); 48162306a36Sopenharmony_ci txq_info->ntxq = rounddown(i, adap->params.nports); 48262306a36Sopenharmony_ci if (txq_info->ntxq <= 0) { 48362306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "Crypto Tx Queues can't be zero\n"); 48462306a36Sopenharmony_ci kfree(txq_info); 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci } else { 48962306a36Sopenharmony_ci i = min_t(int, uld_info->ntxq, num_online_cpus()); 49062306a36Sopenharmony_ci txq_info->ntxq = roundup(i, adap->params.nports); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci txq_info->uldtxq = kcalloc(txq_info->ntxq, sizeof(struct sge_uld_txq), 49362306a36Sopenharmony_ci GFP_KERNEL); 49462306a36Sopenharmony_ci if (!txq_info->uldtxq) { 49562306a36Sopenharmony_ci kfree(txq_info); 49662306a36Sopenharmony_ci return -ENOMEM; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (alloc_sge_txq_uld(adap, txq_info, tx_uld_type)) { 50062306a36Sopenharmony_ci kfree(txq_info->uldtxq); 50162306a36Sopenharmony_ci kfree(txq_info); 50262306a36Sopenharmony_ci return -ENOMEM; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci atomic_inc(&txq_info->users); 50662306a36Sopenharmony_ci adap->sge.uld_txq_info[tx_uld_type] = txq_info; 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void uld_queue_init(struct adapter *adap, unsigned int uld_type, 51162306a36Sopenharmony_ci struct cxgb4_lld_info *lli) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; 51462306a36Sopenharmony_ci int tx_uld_type = TX_ULD(uld_type); 51562306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info = adap->sge.uld_txq_info[tx_uld_type]; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci lli->rxq_ids = rxq_info->rspq_id; 51862306a36Sopenharmony_ci lli->nrxq = rxq_info->nrxq; 51962306a36Sopenharmony_ci lli->ciq_ids = rxq_info->rspq_id + rxq_info->nrxq; 52062306a36Sopenharmony_ci lli->nciq = rxq_info->nciq; 52162306a36Sopenharmony_ci lli->ntxq = txq_info->ntxq; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ciint t4_uld_mem_alloc(struct adapter *adap) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct sge *s = &adap->sge; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci adap->uld = kcalloc(CXGB4_ULD_MAX, sizeof(*adap->uld), GFP_KERNEL); 52962306a36Sopenharmony_ci if (!adap->uld) 53062306a36Sopenharmony_ci return -ENOMEM; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci s->uld_rxq_info = kcalloc(CXGB4_ULD_MAX, 53362306a36Sopenharmony_ci sizeof(struct sge_uld_rxq_info *), 53462306a36Sopenharmony_ci GFP_KERNEL); 53562306a36Sopenharmony_ci if (!s->uld_rxq_info) 53662306a36Sopenharmony_ci goto err_uld; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci s->uld_txq_info = kcalloc(CXGB4_TX_MAX, 53962306a36Sopenharmony_ci sizeof(struct sge_uld_txq_info *), 54062306a36Sopenharmony_ci GFP_KERNEL); 54162306a36Sopenharmony_ci if (!s->uld_txq_info) 54262306a36Sopenharmony_ci goto err_uld_rx; 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cierr_uld_rx: 54662306a36Sopenharmony_ci kfree(s->uld_rxq_info); 54762306a36Sopenharmony_cierr_uld: 54862306a36Sopenharmony_ci kfree(adap->uld); 54962306a36Sopenharmony_ci return -ENOMEM; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_civoid t4_uld_mem_free(struct adapter *adap) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct sge *s = &adap->sge; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci kfree(s->uld_txq_info); 55762306a36Sopenharmony_ci kfree(s->uld_rxq_info); 55862306a36Sopenharmony_ci kfree(adap->uld); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* This function should be called with uld_mutex taken. */ 56262306a36Sopenharmony_cistatic void cxgb4_shutdown_uld_adapter(struct adapter *adap, enum cxgb4_uld type) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci if (adap->uld[type].handle) { 56562306a36Sopenharmony_ci adap->uld[type].handle = NULL; 56662306a36Sopenharmony_ci adap->uld[type].add = NULL; 56762306a36Sopenharmony_ci release_sge_txq_uld(adap, type); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) 57062306a36Sopenharmony_ci quiesce_rx_uld(adap, type); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) 57362306a36Sopenharmony_ci free_msix_queue_irqs_uld(adap, type); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci free_sge_queues_uld(adap, type); 57662306a36Sopenharmony_ci free_queues_uld(adap, type); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_civoid t4_uld_clean_up(struct adapter *adap) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci unsigned int i; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (!is_uld(adap)) 58562306a36Sopenharmony_ci return; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci mutex_lock(&uld_mutex); 58862306a36Sopenharmony_ci for (i = 0; i < CXGB4_ULD_MAX; i++) { 58962306a36Sopenharmony_ci if (!adap->uld[i].handle) 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci cxgb4_shutdown_uld_adapter(adap, i); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic void uld_init(struct adapter *adap, struct cxgb4_lld_info *lld) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci int i; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci lld->pdev = adap->pdev; 60262306a36Sopenharmony_ci lld->pf = adap->pf; 60362306a36Sopenharmony_ci lld->l2t = adap->l2t; 60462306a36Sopenharmony_ci lld->tids = &adap->tids; 60562306a36Sopenharmony_ci lld->ports = adap->port; 60662306a36Sopenharmony_ci lld->vr = &adap->vres; 60762306a36Sopenharmony_ci lld->mtus = adap->params.mtus; 60862306a36Sopenharmony_ci lld->nchan = adap->params.nports; 60962306a36Sopenharmony_ci lld->nports = adap->params.nports; 61062306a36Sopenharmony_ci lld->wr_cred = adap->params.ofldq_wr_cred; 61162306a36Sopenharmony_ci lld->crypto = adap->params.crypto; 61262306a36Sopenharmony_ci lld->iscsi_iolen = MAXRXDATA_G(t4_read_reg(adap, TP_PARA_REG2_A)); 61362306a36Sopenharmony_ci lld->iscsi_tagmask = t4_read_reg(adap, ULP_RX_ISCSI_TAGMASK_A); 61462306a36Sopenharmony_ci lld->iscsi_pgsz_order = t4_read_reg(adap, ULP_RX_ISCSI_PSZ_A); 61562306a36Sopenharmony_ci lld->iscsi_llimit = t4_read_reg(adap, ULP_RX_ISCSI_LLIMIT_A); 61662306a36Sopenharmony_ci lld->iscsi_ppm = &adap->iscsi_ppm; 61762306a36Sopenharmony_ci lld->adapter_type = adap->params.chip; 61862306a36Sopenharmony_ci lld->cclk_ps = 1000000000 / adap->params.vpd.cclk; 61962306a36Sopenharmony_ci lld->udb_density = 1 << adap->params.sge.eq_qpp; 62062306a36Sopenharmony_ci lld->ucq_density = 1 << adap->params.sge.iq_qpp; 62162306a36Sopenharmony_ci lld->sge_host_page_size = 1 << (adap->params.sge.hps + 10); 62262306a36Sopenharmony_ci lld->filt_mode = adap->params.tp.vlan_pri_map; 62362306a36Sopenharmony_ci /* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */ 62462306a36Sopenharmony_ci for (i = 0; i < NCHAN; i++) 62562306a36Sopenharmony_ci lld->tx_modq[i] = i; 62662306a36Sopenharmony_ci lld->gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS_A); 62762306a36Sopenharmony_ci lld->db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL_A); 62862306a36Sopenharmony_ci lld->fw_vers = adap->params.fw_vers; 62962306a36Sopenharmony_ci lld->dbfifo_int_thresh = dbfifo_int_thresh; 63062306a36Sopenharmony_ci lld->sge_ingpadboundary = adap->sge.fl_align; 63162306a36Sopenharmony_ci lld->sge_egrstatuspagesize = adap->sge.stat_len; 63262306a36Sopenharmony_ci lld->sge_pktshift = adap->sge.pktshift; 63362306a36Sopenharmony_ci lld->ulp_crypto = adap->params.crypto; 63462306a36Sopenharmony_ci lld->enable_fw_ofld_conn = adap->flags & CXGB4_FW_OFLD_CONN; 63562306a36Sopenharmony_ci lld->max_ordird_qp = adap->params.max_ordird_qp; 63662306a36Sopenharmony_ci lld->max_ird_adapter = adap->params.max_ird_adapter; 63762306a36Sopenharmony_ci lld->ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl; 63862306a36Sopenharmony_ci lld->nodeid = dev_to_node(adap->pdev_dev); 63962306a36Sopenharmony_ci lld->fr_nsmr_tpte_wr_support = adap->params.fr_nsmr_tpte_wr_support; 64062306a36Sopenharmony_ci lld->write_w_imm_support = adap->params.write_w_imm_support; 64162306a36Sopenharmony_ci lld->write_cmpl_support = adap->params.write_cmpl_support; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int uld_attach(struct adapter *adap, unsigned int uld) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct cxgb4_lld_info lli; 64762306a36Sopenharmony_ci void *handle; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci uld_init(adap, &lli); 65062306a36Sopenharmony_ci uld_queue_init(adap, uld, &lli); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci handle = adap->uld[uld].add(&lli); 65362306a36Sopenharmony_ci if (IS_ERR(handle)) { 65462306a36Sopenharmony_ci dev_warn(adap->pdev_dev, 65562306a36Sopenharmony_ci "could not attach to the %s driver, error %ld\n", 65662306a36Sopenharmony_ci adap->uld[uld].name, PTR_ERR(handle)); 65762306a36Sopenharmony_ci return PTR_ERR(handle); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci adap->uld[uld].handle = handle; 66162306a36Sopenharmony_ci t4_register_netevent_notifier(); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) 66462306a36Sopenharmony_ci adap->uld[uld].state_change(handle, CXGB4_STATE_UP); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci return 0; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 67062306a36Sopenharmony_cistatic bool cxgb4_uld_in_use(struct adapter *adap) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci const struct tid_info *t = &adap->tids; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return (atomic_read(&t->conns_in_use) || t->stids_in_use); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci/* cxgb4_set_ktls_feature: request FW to enable/disable ktls settings. 67862306a36Sopenharmony_ci * @adap: adapter info 67962306a36Sopenharmony_ci * @enable: 1 to enable / 0 to disable ktls settings. 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_ciint cxgb4_set_ktls_feature(struct adapter *adap, bool enable) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci int ret = 0; 68462306a36Sopenharmony_ci u32 params = 68562306a36Sopenharmony_ci FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 68662306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_KTLS_HW) | 68762306a36Sopenharmony_ci FW_PARAMS_PARAM_Y_V(enable) | 68862306a36Sopenharmony_ci FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_KTLS_HW_USER_ENABLE); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (enable) { 69162306a36Sopenharmony_ci if (!refcount_read(&adap->chcr_ktls.ktls_refcount)) { 69262306a36Sopenharmony_ci /* At this moment if ULD connection are up means, other 69362306a36Sopenharmony_ci * ULD is/are already active, return failure. 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_ci if (cxgb4_uld_in_use(adap)) { 69662306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 69762306a36Sopenharmony_ci "ULD connections (tid/stid) active. Can't enable kTLS\n"); 69862306a36Sopenharmony_ci return -EINVAL; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 70162306a36Sopenharmony_ci 0, 1, ¶ms, ¶ms); 70262306a36Sopenharmony_ci if (ret) 70362306a36Sopenharmony_ci return ret; 70462306a36Sopenharmony_ci refcount_set(&adap->chcr_ktls.ktls_refcount, 1); 70562306a36Sopenharmony_ci pr_debug("kTLS has been enabled. Restrictions placed on ULD support\n"); 70662306a36Sopenharmony_ci } else { 70762306a36Sopenharmony_ci /* ktls settings already up, just increment refcount. */ 70862306a36Sopenharmony_ci refcount_inc(&adap->chcr_ktls.ktls_refcount); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci } else { 71162306a36Sopenharmony_ci /* return failure if refcount is already 0. */ 71262306a36Sopenharmony_ci if (!refcount_read(&adap->chcr_ktls.ktls_refcount)) 71362306a36Sopenharmony_ci return -EINVAL; 71462306a36Sopenharmony_ci /* decrement refcount and test, if 0, disable ktls feature, 71562306a36Sopenharmony_ci * else return command success. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci if (refcount_dec_and_test(&adap->chcr_ktls.ktls_refcount)) { 71862306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 71962306a36Sopenharmony_ci 0, 1, ¶ms, ¶ms); 72062306a36Sopenharmony_ci if (ret) 72162306a36Sopenharmony_ci return ret; 72262306a36Sopenharmony_ci pr_debug("kTLS is disabled. Restrictions on ULD support removed\n"); 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return ret; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci#endif 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic void cxgb4_uld_alloc_resources(struct adapter *adap, 73162306a36Sopenharmony_ci enum cxgb4_uld type, 73262306a36Sopenharmony_ci const struct cxgb4_uld_info *p) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci int ret = 0; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if ((type == CXGB4_ULD_CRYPTO && !is_pci_uld(adap)) || 73762306a36Sopenharmony_ci (type != CXGB4_ULD_CRYPTO && !is_offload(adap))) 73862306a36Sopenharmony_ci return; 73962306a36Sopenharmony_ci if (type == CXGB4_ULD_ISCSIT && is_t4(adap->params.chip)) 74062306a36Sopenharmony_ci return; 74162306a36Sopenharmony_ci ret = cfg_queues_uld(adap, type, p); 74262306a36Sopenharmony_ci if (ret) 74362306a36Sopenharmony_ci goto out; 74462306a36Sopenharmony_ci ret = setup_sge_queues_uld(adap, type, p->lro); 74562306a36Sopenharmony_ci if (ret) 74662306a36Sopenharmony_ci goto free_queues; 74762306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 74862306a36Sopenharmony_ci ret = request_msix_queue_irqs_uld(adap, type); 74962306a36Sopenharmony_ci if (ret) 75062306a36Sopenharmony_ci goto free_rxq; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) 75362306a36Sopenharmony_ci enable_rx_uld(adap, type); 75462306a36Sopenharmony_ci if (adap->uld[type].add) 75562306a36Sopenharmony_ci goto free_irq; 75662306a36Sopenharmony_ci ret = setup_sge_txq_uld(adap, type, p); 75762306a36Sopenharmony_ci if (ret) 75862306a36Sopenharmony_ci goto free_irq; 75962306a36Sopenharmony_ci adap->uld[type] = *p; 76062306a36Sopenharmony_ci ret = uld_attach(adap, type); 76162306a36Sopenharmony_ci if (ret) 76262306a36Sopenharmony_ci goto free_txq; 76362306a36Sopenharmony_ci return; 76462306a36Sopenharmony_cifree_txq: 76562306a36Sopenharmony_ci release_sge_txq_uld(adap, type); 76662306a36Sopenharmony_cifree_irq: 76762306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) 76862306a36Sopenharmony_ci quiesce_rx_uld(adap, type); 76962306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) 77062306a36Sopenharmony_ci free_msix_queue_irqs_uld(adap, type); 77162306a36Sopenharmony_cifree_rxq: 77262306a36Sopenharmony_ci free_sge_queues_uld(adap, type); 77362306a36Sopenharmony_cifree_queues: 77462306a36Sopenharmony_ci free_queues_uld(adap, type); 77562306a36Sopenharmony_ciout: 77662306a36Sopenharmony_ci dev_warn(adap->pdev_dev, 77762306a36Sopenharmony_ci "ULD registration failed for uld type %d\n", type); 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_civoid cxgb4_uld_enable(struct adapter *adap) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci struct cxgb4_uld_list *uld_entry; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci mutex_lock(&uld_mutex); 78562306a36Sopenharmony_ci list_add_tail(&adap->list_node, &adapter_list); 78662306a36Sopenharmony_ci list_for_each_entry(uld_entry, &uld_list, list_node) 78762306a36Sopenharmony_ci cxgb4_uld_alloc_resources(adap, uld_entry->uld_type, 78862306a36Sopenharmony_ci &uld_entry->uld_info); 78962306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci/* cxgb4_register_uld - register an upper-layer driver 79362306a36Sopenharmony_ci * @type: the ULD type 79462306a36Sopenharmony_ci * @p: the ULD methods 79562306a36Sopenharmony_ci * 79662306a36Sopenharmony_ci * Registers an upper-layer driver with this driver and notifies the ULD 79762306a36Sopenharmony_ci * about any presently available devices that support its type. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_civoid cxgb4_register_uld(enum cxgb4_uld type, 80062306a36Sopenharmony_ci const struct cxgb4_uld_info *p) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct cxgb4_uld_list *uld_entry; 80362306a36Sopenharmony_ci struct adapter *adap; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (type >= CXGB4_ULD_MAX) 80662306a36Sopenharmony_ci return; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci uld_entry = kzalloc(sizeof(*uld_entry), GFP_KERNEL); 80962306a36Sopenharmony_ci if (!uld_entry) 81062306a36Sopenharmony_ci return; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci memcpy(&uld_entry->uld_info, p, sizeof(struct cxgb4_uld_info)); 81362306a36Sopenharmony_ci mutex_lock(&uld_mutex); 81462306a36Sopenharmony_ci list_for_each_entry(adap, &adapter_list, list_node) 81562306a36Sopenharmony_ci cxgb4_uld_alloc_resources(adap, type, p); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci uld_entry->uld_type = type; 81862306a36Sopenharmony_ci list_add_tail(&uld_entry->list_node, &uld_list); 81962306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 82062306a36Sopenharmony_ci return; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_register_uld); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci/** 82562306a36Sopenharmony_ci * cxgb4_unregister_uld - unregister an upper-layer driver 82662306a36Sopenharmony_ci * @type: the ULD type 82762306a36Sopenharmony_ci * 82862306a36Sopenharmony_ci * Unregisters an existing upper-layer driver. 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_ciint cxgb4_unregister_uld(enum cxgb4_uld type) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct cxgb4_uld_list *uld_entry, *tmp; 83362306a36Sopenharmony_ci struct adapter *adap; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (type >= CXGB4_ULD_MAX) 83662306a36Sopenharmony_ci return -EINVAL; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci mutex_lock(&uld_mutex); 83962306a36Sopenharmony_ci list_for_each_entry(adap, &adapter_list, list_node) { 84062306a36Sopenharmony_ci if ((type == CXGB4_ULD_CRYPTO && !is_pci_uld(adap)) || 84162306a36Sopenharmony_ci (type != CXGB4_ULD_CRYPTO && !is_offload(adap))) 84262306a36Sopenharmony_ci continue; 84362306a36Sopenharmony_ci if (type == CXGB4_ULD_ISCSIT && is_t4(adap->params.chip)) 84462306a36Sopenharmony_ci continue; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci cxgb4_shutdown_uld_adapter(adap, type); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci list_for_each_entry_safe(uld_entry, tmp, &uld_list, list_node) { 85062306a36Sopenharmony_ci if (uld_entry->uld_type == type) { 85162306a36Sopenharmony_ci list_del(&uld_entry->list_node); 85262306a36Sopenharmony_ci kfree(uld_entry); 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_unregister_uld); 860