162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2008-2012 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 3562306a36Sopenharmony_ci#include <linux/kernel.h> 3662306a36Sopenharmony_ci#include <linux/string.h> 3762306a36Sopenharmony_ci#include <linux/compiler.h> 3862306a36Sopenharmony_ci#include <linux/slab.h> 3962306a36Sopenharmony_ci#include <asm/page.h> 4062306a36Sopenharmony_ci#include <linux/cache.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "t4_values.h" 4362306a36Sopenharmony_ci#include "csio_hw.h" 4462306a36Sopenharmony_ci#include "csio_wr.h" 4562306a36Sopenharmony_ci#include "csio_mb.h" 4662306a36Sopenharmony_ci#include "csio_defs.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciint csio_intr_coalesce_cnt; /* value:SGE_INGRESS_RX_THRESHOLD[0] */ 4962306a36Sopenharmony_cistatic int csio_sge_thresh_reg; /* SGE_INGRESS_RX_THRESHOLD[0] */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciint csio_intr_coalesce_time = 10; /* value:SGE_TIMER_VALUE_1 */ 5262306a36Sopenharmony_cistatic int csio_sge_timer_reg = 1; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define CSIO_SET_FLBUF_SIZE(_hw, _reg, _val) \ 5562306a36Sopenharmony_ci csio_wr_reg32((_hw), (_val), SGE_FL_BUFFER_SIZE##_reg##_A) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic void 5862306a36Sopenharmony_cicsio_get_flbuf_size(struct csio_hw *hw, struct csio_sge *sge, uint32_t reg) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci sge->sge_fl_buf_size[reg] = csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE0_A + 6162306a36Sopenharmony_ci reg * sizeof(uint32_t)); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Free list buffer size */ 6562306a36Sopenharmony_cistatic inline uint32_t 6662306a36Sopenharmony_cicsio_wr_fl_bufsz(struct csio_sge *sge, struct csio_dma_buf *buf) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return sge->sge_fl_buf_size[buf->paddr & 0xF]; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* Size of the egress queue status page */ 7262306a36Sopenharmony_cistatic inline uint32_t 7362306a36Sopenharmony_cicsio_wr_qstat_pgsz(struct csio_hw *hw) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci return (hw->wrm.sge.sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Ring freelist doorbell */ 7962306a36Sopenharmony_cistatic inline void 8062306a36Sopenharmony_cicsio_wr_ring_fldb(struct csio_hw *hw, struct csio_q *flq) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * Ring the doorbell only when we have atleast CSIO_QCREDIT_SZ 8462306a36Sopenharmony_ci * number of bytes in the freelist queue. This translates to atleast 8562306a36Sopenharmony_ci * 8 freelist buffer pointers (since each pointer is 8 bytes). 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci if (flq->inc_idx >= 8) { 8862306a36Sopenharmony_ci csio_wr_reg32(hw, DBPRIO_F | QID_V(flq->un.fl.flid) | 8962306a36Sopenharmony_ci PIDX_T5_V(flq->inc_idx / 8) | DBTYPE_F, 9062306a36Sopenharmony_ci MYPF_REG(SGE_PF_KDOORBELL_A)); 9162306a36Sopenharmony_ci flq->inc_idx &= 7; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* Write a 0 cidx increment value to enable SGE interrupts for this queue */ 9662306a36Sopenharmony_cistatic void 9762306a36Sopenharmony_cicsio_wr_sge_intr_enable(struct csio_hw *hw, uint16_t iqid) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci csio_wr_reg32(hw, CIDXINC_V(0) | 10062306a36Sopenharmony_ci INGRESSQID_V(iqid) | 10162306a36Sopenharmony_ci TIMERREG_V(X_TIMERREG_RESTART_COUNTER), 10262306a36Sopenharmony_ci MYPF_REG(SGE_PF_GTS_A)); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * csio_wr_fill_fl - Populate the FL buffers of a FL queue. 10762306a36Sopenharmony_ci * @hw: HW module. 10862306a36Sopenharmony_ci * @flq: Freelist queue. 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * Fill up freelist buffer entries with buffers of size specified 11162306a36Sopenharmony_ci * in the size register. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cistatic int 11562306a36Sopenharmony_cicsio_wr_fill_fl(struct csio_hw *hw, struct csio_q *flq) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 11862306a36Sopenharmony_ci struct csio_sge *sge = &wrm->sge; 11962306a36Sopenharmony_ci __be64 *d = (__be64 *)(flq->vstart); 12062306a36Sopenharmony_ci struct csio_dma_buf *buf = &flq->un.fl.bufs[0]; 12162306a36Sopenharmony_ci uint64_t paddr; 12262306a36Sopenharmony_ci int sreg = flq->un.fl.sreg; 12362306a36Sopenharmony_ci int n = flq->credits; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci while (n--) { 12662306a36Sopenharmony_ci buf->len = sge->sge_fl_buf_size[sreg]; 12762306a36Sopenharmony_ci buf->vaddr = dma_alloc_coherent(&hw->pdev->dev, buf->len, 12862306a36Sopenharmony_ci &buf->paddr, GFP_KERNEL); 12962306a36Sopenharmony_ci if (!buf->vaddr) { 13062306a36Sopenharmony_ci csio_err(hw, "Could only fill %d buffers!\n", n + 1); 13162306a36Sopenharmony_ci return -ENOMEM; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci paddr = buf->paddr | (sreg & 0xF); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci *d++ = cpu_to_be64(paddr); 13762306a36Sopenharmony_ci buf++; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * csio_wr_update_fl - 14562306a36Sopenharmony_ci * @hw: HW module. 14662306a36Sopenharmony_ci * @flq: Freelist queue. 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_cistatic inline void 15162306a36Sopenharmony_cicsio_wr_update_fl(struct csio_hw *hw, struct csio_q *flq, uint16_t n) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci flq->inc_idx += n; 15562306a36Sopenharmony_ci flq->pidx += n; 15662306a36Sopenharmony_ci if (unlikely(flq->pidx >= flq->credits)) 15762306a36Sopenharmony_ci flq->pidx -= (uint16_t)flq->credits; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci CSIO_INC_STATS(flq, n_flq_refill); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * csio_wr_alloc_q - Allocate a WR queue and initialize it. 16462306a36Sopenharmony_ci * @hw: HW module 16562306a36Sopenharmony_ci * @qsize: Size of the queue in bytes 16662306a36Sopenharmony_ci * @wrsize: Since of WR in this queue, if fixed. 16762306a36Sopenharmony_ci * @type: Type of queue (Ingress/Egress/Freelist) 16862306a36Sopenharmony_ci * @owner: Module that owns this queue. 16962306a36Sopenharmony_ci * @nflb: Number of freelist buffers for FL. 17062306a36Sopenharmony_ci * @sreg: What is the FL buffer size register? 17162306a36Sopenharmony_ci * @iq_int_handler: Ingress queue handler in INTx mode. 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * This function allocates and sets up a queue for the caller 17462306a36Sopenharmony_ci * of size qsize, aligned at the required boundary. This is subject to 17562306a36Sopenharmony_ci * be free entries being available in the queue array. If one is found, 17662306a36Sopenharmony_ci * it is initialized with the allocated queue, marked as being used (owner), 17762306a36Sopenharmony_ci * and a handle returned to the caller in form of the queue's index 17862306a36Sopenharmony_ci * into the q_arr array. 17962306a36Sopenharmony_ci * If user has indicated a freelist (by specifying nflb > 0), create 18062306a36Sopenharmony_ci * another queue (with its own index into q_arr) for the freelist. Allocate 18162306a36Sopenharmony_ci * memory for DMA buffer metadata (vaddr, len etc). Save off the freelist 18262306a36Sopenharmony_ci * idx in the ingress queue's flq.idx. This is how a Freelist is associated 18362306a36Sopenharmony_ci * with its owning ingress queue. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ciint 18662306a36Sopenharmony_cicsio_wr_alloc_q(struct csio_hw *hw, uint32_t qsize, uint32_t wrsize, 18762306a36Sopenharmony_ci uint16_t type, void *owner, uint32_t nflb, int sreg, 18862306a36Sopenharmony_ci iq_handler_t iq_intx_handler) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 19162306a36Sopenharmony_ci struct csio_q *q, *flq; 19262306a36Sopenharmony_ci int free_idx = wrm->free_qidx; 19362306a36Sopenharmony_ci int ret_idx = free_idx; 19462306a36Sopenharmony_ci uint32_t qsz; 19562306a36Sopenharmony_ci int flq_idx; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (free_idx >= wrm->num_q) { 19862306a36Sopenharmony_ci csio_err(hw, "No more free queues.\n"); 19962306a36Sopenharmony_ci return -1; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci switch (type) { 20362306a36Sopenharmony_ci case CSIO_EGRESS: 20462306a36Sopenharmony_ci qsz = ALIGN(qsize, CSIO_QCREDIT_SZ) + csio_wr_qstat_pgsz(hw); 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci case CSIO_INGRESS: 20762306a36Sopenharmony_ci switch (wrsize) { 20862306a36Sopenharmony_ci case 16: 20962306a36Sopenharmony_ci case 32: 21062306a36Sopenharmony_ci case 64: 21162306a36Sopenharmony_ci case 128: 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci default: 21462306a36Sopenharmony_ci csio_err(hw, "Invalid Ingress queue WR size:%d\n", 21562306a36Sopenharmony_ci wrsize); 21662306a36Sopenharmony_ci return -1; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * Number of elements must be a multiple of 16 22162306a36Sopenharmony_ci * So this includes status page size 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci qsz = ALIGN(qsize/wrsize, 16) * wrsize; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci case CSIO_FREELIST: 22762306a36Sopenharmony_ci qsz = ALIGN(qsize/wrsize, 8) * wrsize + csio_wr_qstat_pgsz(hw); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci default: 23062306a36Sopenharmony_ci csio_err(hw, "Invalid queue type: 0x%x\n", type); 23162306a36Sopenharmony_ci return -1; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci q = wrm->q_arr[free_idx]; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci q->vstart = dma_alloc_coherent(&hw->pdev->dev, qsz, &q->pstart, 23762306a36Sopenharmony_ci GFP_KERNEL); 23862306a36Sopenharmony_ci if (!q->vstart) { 23962306a36Sopenharmony_ci csio_err(hw, 24062306a36Sopenharmony_ci "Failed to allocate DMA memory for " 24162306a36Sopenharmony_ci "queue at id: %d size: %d\n", free_idx, qsize); 24262306a36Sopenharmony_ci return -1; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci q->type = type; 24662306a36Sopenharmony_ci q->owner = owner; 24762306a36Sopenharmony_ci q->pidx = q->cidx = q->inc_idx = 0; 24862306a36Sopenharmony_ci q->size = qsz; 24962306a36Sopenharmony_ci q->wr_sz = wrsize; /* If using fixed size WRs */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci wrm->free_qidx++; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (type == CSIO_INGRESS) { 25462306a36Sopenharmony_ci /* Since queue area is set to zero */ 25562306a36Sopenharmony_ci q->un.iq.genbit = 1; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * Ingress queue status page size is always the size of 25962306a36Sopenharmony_ci * the ingress queue entry. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci q->credits = (qsz - q->wr_sz) / q->wr_sz; 26262306a36Sopenharmony_ci q->vwrap = (void *)((uintptr_t)(q->vstart) + qsz 26362306a36Sopenharmony_ci - q->wr_sz); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* Allocate memory for FL if requested */ 26662306a36Sopenharmony_ci if (nflb > 0) { 26762306a36Sopenharmony_ci flq_idx = csio_wr_alloc_q(hw, nflb * sizeof(__be64), 26862306a36Sopenharmony_ci sizeof(__be64), CSIO_FREELIST, 26962306a36Sopenharmony_ci owner, 0, sreg, NULL); 27062306a36Sopenharmony_ci if (flq_idx == -1) { 27162306a36Sopenharmony_ci csio_err(hw, 27262306a36Sopenharmony_ci "Failed to allocate FL queue" 27362306a36Sopenharmony_ci " for IQ idx:%d\n", free_idx); 27462306a36Sopenharmony_ci return -1; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Associate the new FL with the Ingress quue */ 27862306a36Sopenharmony_ci q->un.iq.flq_idx = flq_idx; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci flq = wrm->q_arr[q->un.iq.flq_idx]; 28162306a36Sopenharmony_ci flq->un.fl.bufs = kcalloc(flq->credits, 28262306a36Sopenharmony_ci sizeof(struct csio_dma_buf), 28362306a36Sopenharmony_ci GFP_KERNEL); 28462306a36Sopenharmony_ci if (!flq->un.fl.bufs) { 28562306a36Sopenharmony_ci csio_err(hw, 28662306a36Sopenharmony_ci "Failed to allocate FL queue bufs" 28762306a36Sopenharmony_ci " for IQ idx:%d\n", free_idx); 28862306a36Sopenharmony_ci return -1; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci flq->un.fl.packen = 0; 29262306a36Sopenharmony_ci flq->un.fl.offset = 0; 29362306a36Sopenharmony_ci flq->un.fl.sreg = sreg; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Fill up the free list buffers */ 29662306a36Sopenharmony_ci if (csio_wr_fill_fl(hw, flq)) 29762306a36Sopenharmony_ci return -1; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* 30062306a36Sopenharmony_ci * Make sure in a FLQ, atleast 1 credit (8 FL buffers) 30162306a36Sopenharmony_ci * remains unpopulated,otherwise HW thinks 30262306a36Sopenharmony_ci * FLQ is empty. 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci flq->pidx = flq->inc_idx = flq->credits - 8; 30562306a36Sopenharmony_ci } else { 30662306a36Sopenharmony_ci q->un.iq.flq_idx = -1; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Associate the IQ INTx handler. */ 31062306a36Sopenharmony_ci q->un.iq.iq_intx_handler = iq_intx_handler; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci csio_q_iqid(hw, ret_idx) = CSIO_MAX_QID; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci } else if (type == CSIO_EGRESS) { 31562306a36Sopenharmony_ci q->credits = (qsz - csio_wr_qstat_pgsz(hw)) / CSIO_QCREDIT_SZ; 31662306a36Sopenharmony_ci q->vwrap = (void *)((uintptr_t)(q->vstart) + qsz 31762306a36Sopenharmony_ci - csio_wr_qstat_pgsz(hw)); 31862306a36Sopenharmony_ci csio_q_eqid(hw, ret_idx) = CSIO_MAX_QID; 31962306a36Sopenharmony_ci } else { /* Freelist */ 32062306a36Sopenharmony_ci q->credits = (qsz - csio_wr_qstat_pgsz(hw)) / sizeof(__be64); 32162306a36Sopenharmony_ci q->vwrap = (void *)((uintptr_t)(q->vstart) + qsz 32262306a36Sopenharmony_ci - csio_wr_qstat_pgsz(hw)); 32362306a36Sopenharmony_ci csio_q_flid(hw, ret_idx) = CSIO_MAX_QID; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return ret_idx; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* 33062306a36Sopenharmony_ci * csio_wr_iq_create_rsp - Response handler for IQ creation. 33162306a36Sopenharmony_ci * @hw: The HW module. 33262306a36Sopenharmony_ci * @mbp: Mailbox. 33362306a36Sopenharmony_ci * @iq_idx: Ingress queue that got created. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * Handle FW_IQ_CMD mailbox completion. Save off the assigned IQ/FL ids. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_cistatic int 33862306a36Sopenharmony_cicsio_wr_iq_create_rsp(struct csio_hw *hw, struct csio_mb *mbp, int iq_idx) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct csio_iq_params iqp; 34162306a36Sopenharmony_ci enum fw_retval retval; 34262306a36Sopenharmony_ci uint32_t iq_id; 34362306a36Sopenharmony_ci int flq_idx; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci memset(&iqp, 0, sizeof(struct csio_iq_params)); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci csio_mb_iq_alloc_write_rsp(hw, mbp, &retval, &iqp); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (retval != FW_SUCCESS) { 35062306a36Sopenharmony_ci csio_err(hw, "IQ cmd returned 0x%x!\n", retval); 35162306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 35262306a36Sopenharmony_ci return -EINVAL; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci csio_q_iqid(hw, iq_idx) = iqp.iqid; 35662306a36Sopenharmony_ci csio_q_physiqid(hw, iq_idx) = iqp.physiqid; 35762306a36Sopenharmony_ci csio_q_pidx(hw, iq_idx) = csio_q_cidx(hw, iq_idx) = 0; 35862306a36Sopenharmony_ci csio_q_inc_idx(hw, iq_idx) = 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Actual iq-id. */ 36162306a36Sopenharmony_ci iq_id = iqp.iqid - hw->wrm.fw_iq_start; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Set the iq-id to iq map table. */ 36462306a36Sopenharmony_ci if (iq_id >= CSIO_MAX_IQ) { 36562306a36Sopenharmony_ci csio_err(hw, 36662306a36Sopenharmony_ci "Exceeding MAX_IQ(%d) supported!" 36762306a36Sopenharmony_ci " iqid:%d rel_iqid:%d FW iq_start:%d\n", 36862306a36Sopenharmony_ci CSIO_MAX_IQ, iq_id, iqp.iqid, hw->wrm.fw_iq_start); 36962306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci csio_q_set_intr_map(hw, iq_idx, iq_id); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * During FW_IQ_CMD, FW sets interrupt_sent bit to 1 in the SGE 37662306a36Sopenharmony_ci * ingress context of this queue. This will block interrupts to 37762306a36Sopenharmony_ci * this queue until the next GTS write. Therefore, we do a 37862306a36Sopenharmony_ci * 0-cidx increment GTS write for this queue just to clear the 37962306a36Sopenharmony_ci * interrupt_sent bit. This will re-enable interrupts to this 38062306a36Sopenharmony_ci * queue. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci csio_wr_sge_intr_enable(hw, iqp.physiqid); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci flq_idx = csio_q_iq_flq_idx(hw, iq_idx); 38562306a36Sopenharmony_ci if (flq_idx != -1) { 38662306a36Sopenharmony_ci struct csio_q *flq = hw->wrm.q_arr[flq_idx]; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci csio_q_flid(hw, flq_idx) = iqp.fl0id; 38962306a36Sopenharmony_ci csio_q_cidx(hw, flq_idx) = 0; 39062306a36Sopenharmony_ci csio_q_pidx(hw, flq_idx) = csio_q_credits(hw, flq_idx) - 8; 39162306a36Sopenharmony_ci csio_q_inc_idx(hw, flq_idx) = csio_q_credits(hw, flq_idx) - 8; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Now update SGE about the buffers allocated during init */ 39462306a36Sopenharmony_ci csio_wr_ring_fldb(hw, flq); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* 40362306a36Sopenharmony_ci * csio_wr_iq_create - Configure an Ingress queue with FW. 40462306a36Sopenharmony_ci * @hw: The HW module. 40562306a36Sopenharmony_ci * @priv: Private data object. 40662306a36Sopenharmony_ci * @iq_idx: Ingress queue index in the WR module. 40762306a36Sopenharmony_ci * @vec: MSIX vector. 40862306a36Sopenharmony_ci * @portid: PCIE Channel to be associated with this queue. 40962306a36Sopenharmony_ci * @async: Is this a FW asynchronous message handling queue? 41062306a36Sopenharmony_ci * @cbfn: Completion callback. 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * This API configures an ingress queue with FW by issuing a FW_IQ_CMD mailbox 41362306a36Sopenharmony_ci * with alloc/write bits set. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ciint 41662306a36Sopenharmony_cicsio_wr_iq_create(struct csio_hw *hw, void *priv, int iq_idx, 41762306a36Sopenharmony_ci uint32_t vec, uint8_t portid, bool async, 41862306a36Sopenharmony_ci void (*cbfn) (struct csio_hw *, struct csio_mb *)) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct csio_mb *mbp; 42162306a36Sopenharmony_ci struct csio_iq_params iqp; 42262306a36Sopenharmony_ci int flq_idx; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci memset(&iqp, 0, sizeof(struct csio_iq_params)); 42562306a36Sopenharmony_ci csio_q_portid(hw, iq_idx) = portid; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 42862306a36Sopenharmony_ci if (!mbp) { 42962306a36Sopenharmony_ci csio_err(hw, "IQ command out of memory!\n"); 43062306a36Sopenharmony_ci return -ENOMEM; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci switch (hw->intr_mode) { 43462306a36Sopenharmony_ci case CSIO_IM_INTX: 43562306a36Sopenharmony_ci case CSIO_IM_MSI: 43662306a36Sopenharmony_ci /* For interrupt forwarding queue only */ 43762306a36Sopenharmony_ci if (hw->intr_iq_idx == iq_idx) 43862306a36Sopenharmony_ci iqp.iqandst = X_INTERRUPTDESTINATION_PCIE; 43962306a36Sopenharmony_ci else 44062306a36Sopenharmony_ci iqp.iqandst = X_INTERRUPTDESTINATION_IQ; 44162306a36Sopenharmony_ci iqp.iqandstindex = 44262306a36Sopenharmony_ci csio_q_physiqid(hw, hw->intr_iq_idx); 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci case CSIO_IM_MSIX: 44562306a36Sopenharmony_ci iqp.iqandst = X_INTERRUPTDESTINATION_PCIE; 44662306a36Sopenharmony_ci iqp.iqandstindex = (uint16_t)vec; 44762306a36Sopenharmony_ci break; 44862306a36Sopenharmony_ci case CSIO_IM_NONE: 44962306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 45062306a36Sopenharmony_ci return -EINVAL; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Pass in the ingress queue cmd parameters */ 45462306a36Sopenharmony_ci iqp.pfn = hw->pfn; 45562306a36Sopenharmony_ci iqp.vfn = 0; 45662306a36Sopenharmony_ci iqp.iq_start = 1; 45762306a36Sopenharmony_ci iqp.viid = 0; 45862306a36Sopenharmony_ci iqp.type = FW_IQ_TYPE_FL_INT_CAP; 45962306a36Sopenharmony_ci iqp.iqasynch = async; 46062306a36Sopenharmony_ci if (csio_intr_coalesce_cnt) 46162306a36Sopenharmony_ci iqp.iqanus = X_UPDATESCHEDULING_COUNTER_OPTTIMER; 46262306a36Sopenharmony_ci else 46362306a36Sopenharmony_ci iqp.iqanus = X_UPDATESCHEDULING_TIMER; 46462306a36Sopenharmony_ci iqp.iqanud = X_UPDATEDELIVERY_INTERRUPT; 46562306a36Sopenharmony_ci iqp.iqpciech = portid; 46662306a36Sopenharmony_ci iqp.iqintcntthresh = (uint8_t)csio_sge_thresh_reg; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci switch (csio_q_wr_sz(hw, iq_idx)) { 46962306a36Sopenharmony_ci case 16: 47062306a36Sopenharmony_ci iqp.iqesize = 0; break; 47162306a36Sopenharmony_ci case 32: 47262306a36Sopenharmony_ci iqp.iqesize = 1; break; 47362306a36Sopenharmony_ci case 64: 47462306a36Sopenharmony_ci iqp.iqesize = 2; break; 47562306a36Sopenharmony_ci case 128: 47662306a36Sopenharmony_ci iqp.iqesize = 3; break; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci iqp.iqsize = csio_q_size(hw, iq_idx) / 48062306a36Sopenharmony_ci csio_q_wr_sz(hw, iq_idx); 48162306a36Sopenharmony_ci iqp.iqaddr = csio_q_pstart(hw, iq_idx); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci flq_idx = csio_q_iq_flq_idx(hw, iq_idx); 48462306a36Sopenharmony_ci if (flq_idx != -1) { 48562306a36Sopenharmony_ci enum chip_type chip = CHELSIO_CHIP_VERSION(hw->chip_id); 48662306a36Sopenharmony_ci struct csio_q *flq = hw->wrm.q_arr[flq_idx]; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci iqp.fl0paden = 1; 48962306a36Sopenharmony_ci iqp.fl0packen = flq->un.fl.packen ? 1 : 0; 49062306a36Sopenharmony_ci iqp.fl0fbmin = X_FETCHBURSTMIN_64B; 49162306a36Sopenharmony_ci iqp.fl0fbmax = ((chip == CHELSIO_T5) ? 49262306a36Sopenharmony_ci X_FETCHBURSTMAX_512B : X_FETCHBURSTMAX_256B); 49362306a36Sopenharmony_ci iqp.fl0size = csio_q_size(hw, flq_idx) / CSIO_QCREDIT_SZ; 49462306a36Sopenharmony_ci iqp.fl0addr = csio_q_pstart(hw, flq_idx); 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci csio_mb_iq_alloc_write(hw, mbp, priv, CSIO_MB_DEFAULT_TMO, &iqp, cbfn); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (csio_mb_issue(hw, mbp)) { 50062306a36Sopenharmony_ci csio_err(hw, "Issue of IQ cmd failed!\n"); 50162306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 50262306a36Sopenharmony_ci return -EINVAL; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (cbfn != NULL) 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return csio_wr_iq_create_rsp(hw, mbp, iq_idx); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/* 51262306a36Sopenharmony_ci * csio_wr_eq_create_rsp - Response handler for EQ creation. 51362306a36Sopenharmony_ci * @hw: The HW module. 51462306a36Sopenharmony_ci * @mbp: Mailbox. 51562306a36Sopenharmony_ci * @eq_idx: Egress queue that got created. 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * Handle FW_EQ_OFLD_CMD mailbox completion. Save off the assigned EQ ids. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_cistatic int 52062306a36Sopenharmony_cicsio_wr_eq_cfg_rsp(struct csio_hw *hw, struct csio_mb *mbp, int eq_idx) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct csio_eq_params eqp; 52362306a36Sopenharmony_ci enum fw_retval retval; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci memset(&eqp, 0, sizeof(struct csio_eq_params)); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci csio_mb_eq_ofld_alloc_write_rsp(hw, mbp, &retval, &eqp); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (retval != FW_SUCCESS) { 53062306a36Sopenharmony_ci csio_err(hw, "EQ OFLD cmd returned 0x%x!\n", retval); 53162306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 53262306a36Sopenharmony_ci return -EINVAL; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci csio_q_eqid(hw, eq_idx) = (uint16_t)eqp.eqid; 53662306a36Sopenharmony_ci csio_q_physeqid(hw, eq_idx) = (uint16_t)eqp.physeqid; 53762306a36Sopenharmony_ci csio_q_pidx(hw, eq_idx) = csio_q_cidx(hw, eq_idx) = 0; 53862306a36Sopenharmony_ci csio_q_inc_idx(hw, eq_idx) = 0; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/* 54662306a36Sopenharmony_ci * csio_wr_eq_create - Configure an Egress queue with FW. 54762306a36Sopenharmony_ci * @hw: HW module. 54862306a36Sopenharmony_ci * @priv: Private data. 54962306a36Sopenharmony_ci * @eq_idx: Egress queue index in the WR module. 55062306a36Sopenharmony_ci * @iq_idx: Associated ingress queue index. 55162306a36Sopenharmony_ci * @cbfn: Completion callback. 55262306a36Sopenharmony_ci * 55362306a36Sopenharmony_ci * This API configures a offload egress queue with FW by issuing a 55462306a36Sopenharmony_ci * FW_EQ_OFLD_CMD (with alloc + write ) mailbox. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_ciint 55762306a36Sopenharmony_cicsio_wr_eq_create(struct csio_hw *hw, void *priv, int eq_idx, 55862306a36Sopenharmony_ci int iq_idx, uint8_t portid, 55962306a36Sopenharmony_ci void (*cbfn) (struct csio_hw *, struct csio_mb *)) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct csio_mb *mbp; 56262306a36Sopenharmony_ci struct csio_eq_params eqp; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci memset(&eqp, 0, sizeof(struct csio_eq_params)); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 56762306a36Sopenharmony_ci if (!mbp) { 56862306a36Sopenharmony_ci csio_err(hw, "EQ command out of memory!\n"); 56962306a36Sopenharmony_ci return -ENOMEM; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci eqp.pfn = hw->pfn; 57362306a36Sopenharmony_ci eqp.vfn = 0; 57462306a36Sopenharmony_ci eqp.eqstart = 1; 57562306a36Sopenharmony_ci eqp.hostfcmode = X_HOSTFCMODE_STATUS_PAGE; 57662306a36Sopenharmony_ci eqp.iqid = csio_q_iqid(hw, iq_idx); 57762306a36Sopenharmony_ci eqp.fbmin = X_FETCHBURSTMIN_64B; 57862306a36Sopenharmony_ci eqp.fbmax = X_FETCHBURSTMAX_512B; 57962306a36Sopenharmony_ci eqp.cidxfthresh = 0; 58062306a36Sopenharmony_ci eqp.pciechn = portid; 58162306a36Sopenharmony_ci eqp.eqsize = csio_q_size(hw, eq_idx) / CSIO_QCREDIT_SZ; 58262306a36Sopenharmony_ci eqp.eqaddr = csio_q_pstart(hw, eq_idx); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci csio_mb_eq_ofld_alloc_write(hw, mbp, priv, CSIO_MB_DEFAULT_TMO, 58562306a36Sopenharmony_ci &eqp, cbfn); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (csio_mb_issue(hw, mbp)) { 58862306a36Sopenharmony_ci csio_err(hw, "Issue of EQ OFLD cmd failed!\n"); 58962306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 59062306a36Sopenharmony_ci return -EINVAL; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (cbfn != NULL) 59462306a36Sopenharmony_ci return 0; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return csio_wr_eq_cfg_rsp(hw, mbp, eq_idx); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci/* 60062306a36Sopenharmony_ci * csio_wr_iq_destroy_rsp - Response handler for IQ removal. 60162306a36Sopenharmony_ci * @hw: The HW module. 60262306a36Sopenharmony_ci * @mbp: Mailbox. 60362306a36Sopenharmony_ci * @iq_idx: Ingress queue that was freed. 60462306a36Sopenharmony_ci * 60562306a36Sopenharmony_ci * Handle FW_IQ_CMD (free) mailbox completion. 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_cistatic int 60862306a36Sopenharmony_cicsio_wr_iq_destroy_rsp(struct csio_hw *hw, struct csio_mb *mbp, int iq_idx) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci enum fw_retval retval = csio_mb_fw_retval(mbp); 61162306a36Sopenharmony_ci int rv = 0; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (retval != FW_SUCCESS) 61462306a36Sopenharmony_ci rv = -EINVAL; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return rv; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci/* 62262306a36Sopenharmony_ci * csio_wr_iq_destroy - Free an ingress queue. 62362306a36Sopenharmony_ci * @hw: The HW module. 62462306a36Sopenharmony_ci * @priv: Private data object. 62562306a36Sopenharmony_ci * @iq_idx: Ingress queue index to destroy 62662306a36Sopenharmony_ci * @cbfn: Completion callback. 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * This API frees an ingress queue by issuing the FW_IQ_CMD 62962306a36Sopenharmony_ci * with the free bit set. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_cistatic int 63262306a36Sopenharmony_cicsio_wr_iq_destroy(struct csio_hw *hw, void *priv, int iq_idx, 63362306a36Sopenharmony_ci void (*cbfn)(struct csio_hw *, struct csio_mb *)) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci int rv = 0; 63662306a36Sopenharmony_ci struct csio_mb *mbp; 63762306a36Sopenharmony_ci struct csio_iq_params iqp; 63862306a36Sopenharmony_ci int flq_idx; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci memset(&iqp, 0, sizeof(struct csio_iq_params)); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 64362306a36Sopenharmony_ci if (!mbp) 64462306a36Sopenharmony_ci return -ENOMEM; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci iqp.pfn = hw->pfn; 64762306a36Sopenharmony_ci iqp.vfn = 0; 64862306a36Sopenharmony_ci iqp.iqid = csio_q_iqid(hw, iq_idx); 64962306a36Sopenharmony_ci iqp.type = FW_IQ_TYPE_FL_INT_CAP; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci flq_idx = csio_q_iq_flq_idx(hw, iq_idx); 65262306a36Sopenharmony_ci if (flq_idx != -1) 65362306a36Sopenharmony_ci iqp.fl0id = csio_q_flid(hw, flq_idx); 65462306a36Sopenharmony_ci else 65562306a36Sopenharmony_ci iqp.fl0id = 0xFFFF; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci iqp.fl1id = 0xFFFF; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci csio_mb_iq_free(hw, mbp, priv, CSIO_MB_DEFAULT_TMO, &iqp, cbfn); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci rv = csio_mb_issue(hw, mbp); 66262306a36Sopenharmony_ci if (rv != 0) { 66362306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 66462306a36Sopenharmony_ci return rv; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (cbfn != NULL) 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return csio_wr_iq_destroy_rsp(hw, mbp, iq_idx); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci/* 67462306a36Sopenharmony_ci * csio_wr_eq_destroy_rsp - Response handler for OFLD EQ creation. 67562306a36Sopenharmony_ci * @hw: The HW module. 67662306a36Sopenharmony_ci * @mbp: Mailbox. 67762306a36Sopenharmony_ci * @eq_idx: Egress queue that was freed. 67862306a36Sopenharmony_ci * 67962306a36Sopenharmony_ci * Handle FW_OFLD_EQ_CMD (free) mailbox completion. 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_cistatic int 68262306a36Sopenharmony_cicsio_wr_eq_destroy_rsp(struct csio_hw *hw, struct csio_mb *mbp, int eq_idx) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci enum fw_retval retval = csio_mb_fw_retval(mbp); 68562306a36Sopenharmony_ci int rv = 0; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (retval != FW_SUCCESS) 68862306a36Sopenharmony_ci rv = -EINVAL; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return rv; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci/* 69662306a36Sopenharmony_ci * csio_wr_eq_destroy - Free an Egress queue. 69762306a36Sopenharmony_ci * @hw: The HW module. 69862306a36Sopenharmony_ci * @priv: Private data object. 69962306a36Sopenharmony_ci * @eq_idx: Egress queue index to destroy 70062306a36Sopenharmony_ci * @cbfn: Completion callback. 70162306a36Sopenharmony_ci * 70262306a36Sopenharmony_ci * This API frees an Egress queue by issuing the FW_EQ_OFLD_CMD 70362306a36Sopenharmony_ci * with the free bit set. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_cistatic int 70662306a36Sopenharmony_cicsio_wr_eq_destroy(struct csio_hw *hw, void *priv, int eq_idx, 70762306a36Sopenharmony_ci void (*cbfn) (struct csio_hw *, struct csio_mb *)) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci int rv = 0; 71062306a36Sopenharmony_ci struct csio_mb *mbp; 71162306a36Sopenharmony_ci struct csio_eq_params eqp; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci memset(&eqp, 0, sizeof(struct csio_eq_params)); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 71662306a36Sopenharmony_ci if (!mbp) 71762306a36Sopenharmony_ci return -ENOMEM; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci eqp.pfn = hw->pfn; 72062306a36Sopenharmony_ci eqp.vfn = 0; 72162306a36Sopenharmony_ci eqp.eqid = csio_q_eqid(hw, eq_idx); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci csio_mb_eq_ofld_free(hw, mbp, priv, CSIO_MB_DEFAULT_TMO, &eqp, cbfn); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci rv = csio_mb_issue(hw, mbp); 72662306a36Sopenharmony_ci if (rv != 0) { 72762306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 72862306a36Sopenharmony_ci return rv; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (cbfn != NULL) 73262306a36Sopenharmony_ci return 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return csio_wr_eq_destroy_rsp(hw, mbp, eq_idx); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci/* 73862306a36Sopenharmony_ci * csio_wr_cleanup_eq_stpg - Cleanup Egress queue status page 73962306a36Sopenharmony_ci * @hw: HW module 74062306a36Sopenharmony_ci * @qidx: Egress queue index 74162306a36Sopenharmony_ci * 74262306a36Sopenharmony_ci * Cleanup the Egress queue status page. 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_cistatic void 74562306a36Sopenharmony_cicsio_wr_cleanup_eq_stpg(struct csio_hw *hw, int qidx) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct csio_q *q = csio_hw_to_wrm(hw)->q_arr[qidx]; 74862306a36Sopenharmony_ci struct csio_qstatus_page *stp = (struct csio_qstatus_page *)q->vwrap; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci memset(stp, 0, sizeof(*stp)); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci/* 75462306a36Sopenharmony_ci * csio_wr_cleanup_iq_ftr - Cleanup Footer entries in IQ 75562306a36Sopenharmony_ci * @hw: HW module 75662306a36Sopenharmony_ci * @qidx: Ingress queue index 75762306a36Sopenharmony_ci * 75862306a36Sopenharmony_ci * Cleanup the footer entries in the given ingress queue, 75962306a36Sopenharmony_ci * set to 1 the internal copy of genbit. 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_cistatic void 76262306a36Sopenharmony_cicsio_wr_cleanup_iq_ftr(struct csio_hw *hw, int qidx) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 76562306a36Sopenharmony_ci struct csio_q *q = wrm->q_arr[qidx]; 76662306a36Sopenharmony_ci void *wr; 76762306a36Sopenharmony_ci struct csio_iqwr_footer *ftr; 76862306a36Sopenharmony_ci uint32_t i = 0; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* set to 1 since we are just about zero out genbit */ 77162306a36Sopenharmony_ci q->un.iq.genbit = 1; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci for (i = 0; i < q->credits; i++) { 77462306a36Sopenharmony_ci /* Get the WR */ 77562306a36Sopenharmony_ci wr = (void *)((uintptr_t)q->vstart + 77662306a36Sopenharmony_ci (i * q->wr_sz)); 77762306a36Sopenharmony_ci /* Get the footer */ 77862306a36Sopenharmony_ci ftr = (struct csio_iqwr_footer *)((uintptr_t)wr + 77962306a36Sopenharmony_ci (q->wr_sz - sizeof(*ftr))); 78062306a36Sopenharmony_ci /* Zero out footer */ 78162306a36Sopenharmony_ci memset(ftr, 0, sizeof(*ftr)); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ciint 78662306a36Sopenharmony_cicsio_wr_destroy_queues(struct csio_hw *hw, bool cmd) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci int i, flq_idx; 78962306a36Sopenharmony_ci struct csio_q *q; 79062306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 79162306a36Sopenharmony_ci int rv; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci for (i = 0; i < wrm->free_qidx; i++) { 79462306a36Sopenharmony_ci q = wrm->q_arr[i]; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci switch (q->type) { 79762306a36Sopenharmony_ci case CSIO_EGRESS: 79862306a36Sopenharmony_ci if (csio_q_eqid(hw, i) != CSIO_MAX_QID) { 79962306a36Sopenharmony_ci csio_wr_cleanup_eq_stpg(hw, i); 80062306a36Sopenharmony_ci if (!cmd) { 80162306a36Sopenharmony_ci csio_q_eqid(hw, i) = CSIO_MAX_QID; 80262306a36Sopenharmony_ci continue; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci rv = csio_wr_eq_destroy(hw, NULL, i, NULL); 80662306a36Sopenharmony_ci if ((rv == -EBUSY) || (rv == -ETIMEDOUT)) 80762306a36Sopenharmony_ci cmd = false; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci csio_q_eqid(hw, i) = CSIO_MAX_QID; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci fallthrough; 81262306a36Sopenharmony_ci case CSIO_INGRESS: 81362306a36Sopenharmony_ci if (csio_q_iqid(hw, i) != CSIO_MAX_QID) { 81462306a36Sopenharmony_ci csio_wr_cleanup_iq_ftr(hw, i); 81562306a36Sopenharmony_ci if (!cmd) { 81662306a36Sopenharmony_ci csio_q_iqid(hw, i) = CSIO_MAX_QID; 81762306a36Sopenharmony_ci flq_idx = csio_q_iq_flq_idx(hw, i); 81862306a36Sopenharmony_ci if (flq_idx != -1) 81962306a36Sopenharmony_ci csio_q_flid(hw, flq_idx) = 82062306a36Sopenharmony_ci CSIO_MAX_QID; 82162306a36Sopenharmony_ci continue; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci rv = csio_wr_iq_destroy(hw, NULL, i, NULL); 82562306a36Sopenharmony_ci if ((rv == -EBUSY) || (rv == -ETIMEDOUT)) 82662306a36Sopenharmony_ci cmd = false; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci csio_q_iqid(hw, i) = CSIO_MAX_QID; 82962306a36Sopenharmony_ci flq_idx = csio_q_iq_flq_idx(hw, i); 83062306a36Sopenharmony_ci if (flq_idx != -1) 83162306a36Sopenharmony_ci csio_q_flid(hw, flq_idx) = CSIO_MAX_QID; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci default: 83562306a36Sopenharmony_ci break; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci hw->flags &= ~CSIO_HWF_Q_FW_ALLOCED; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return 0; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci/* 84562306a36Sopenharmony_ci * csio_wr_get - Get requested size of WR entry/entries from queue. 84662306a36Sopenharmony_ci * @hw: HW module. 84762306a36Sopenharmony_ci * @qidx: Index of queue. 84862306a36Sopenharmony_ci * @size: Cumulative size of Work request(s). 84962306a36Sopenharmony_ci * @wrp: Work request pair. 85062306a36Sopenharmony_ci * 85162306a36Sopenharmony_ci * If requested credits are available, return the start address of the 85262306a36Sopenharmony_ci * work request in the work request pair. Set pidx accordingly and 85362306a36Sopenharmony_ci * return. 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * NOTE about WR pair: 85662306a36Sopenharmony_ci * ================== 85762306a36Sopenharmony_ci * A WR can start towards the end of a queue, and then continue at the 85862306a36Sopenharmony_ci * beginning, since the queue is considered to be circular. This will 85962306a36Sopenharmony_ci * require a pair of address/size to be passed back to the caller - 86062306a36Sopenharmony_ci * hence Work request pair format. 86162306a36Sopenharmony_ci */ 86262306a36Sopenharmony_ciint 86362306a36Sopenharmony_cicsio_wr_get(struct csio_hw *hw, int qidx, uint32_t size, 86462306a36Sopenharmony_ci struct csio_wr_pair *wrp) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 86762306a36Sopenharmony_ci struct csio_q *q = wrm->q_arr[qidx]; 86862306a36Sopenharmony_ci void *cwr = (void *)((uintptr_t)(q->vstart) + 86962306a36Sopenharmony_ci (q->pidx * CSIO_QCREDIT_SZ)); 87062306a36Sopenharmony_ci struct csio_qstatus_page *stp = (struct csio_qstatus_page *)q->vwrap; 87162306a36Sopenharmony_ci uint16_t cidx = q->cidx = ntohs(stp->cidx); 87262306a36Sopenharmony_ci uint16_t pidx = q->pidx; 87362306a36Sopenharmony_ci uint32_t req_sz = ALIGN(size, CSIO_QCREDIT_SZ); 87462306a36Sopenharmony_ci int req_credits = req_sz / CSIO_QCREDIT_SZ; 87562306a36Sopenharmony_ci int credits; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci CSIO_DB_ASSERT(q->owner != NULL); 87862306a36Sopenharmony_ci CSIO_DB_ASSERT((qidx >= 0) && (qidx < wrm->free_qidx)); 87962306a36Sopenharmony_ci CSIO_DB_ASSERT(cidx <= q->credits); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* Calculate credits */ 88262306a36Sopenharmony_ci if (pidx > cidx) { 88362306a36Sopenharmony_ci credits = q->credits - (pidx - cidx) - 1; 88462306a36Sopenharmony_ci } else if (cidx > pidx) { 88562306a36Sopenharmony_ci credits = cidx - pidx - 1; 88662306a36Sopenharmony_ci } else { 88762306a36Sopenharmony_ci /* cidx == pidx, empty queue */ 88862306a36Sopenharmony_ci credits = q->credits; 88962306a36Sopenharmony_ci CSIO_INC_STATS(q, n_qempty); 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci /* 89362306a36Sopenharmony_ci * Check if we have enough credits. 89462306a36Sopenharmony_ci * credits = 1 implies queue is full. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci if (!credits || (req_credits > credits)) { 89762306a36Sopenharmony_ci CSIO_INC_STATS(q, n_qfull); 89862306a36Sopenharmony_ci return -EBUSY; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* 90262306a36Sopenharmony_ci * If we are here, we have enough credits to satisfy the 90362306a36Sopenharmony_ci * request. Check if we are near the end of q, and if WR spills over. 90462306a36Sopenharmony_ci * If it does, use the first addr/size to cover the queue until 90562306a36Sopenharmony_ci * the end. Fit the remainder portion of the request at the top 90662306a36Sopenharmony_ci * of queue and return it in the second addr/len. Set pidx 90762306a36Sopenharmony_ci * accordingly. 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_ci if (unlikely(((uintptr_t)cwr + req_sz) > (uintptr_t)(q->vwrap))) { 91062306a36Sopenharmony_ci wrp->addr1 = cwr; 91162306a36Sopenharmony_ci wrp->size1 = (uint32_t)((uintptr_t)q->vwrap - (uintptr_t)cwr); 91262306a36Sopenharmony_ci wrp->addr2 = q->vstart; 91362306a36Sopenharmony_ci wrp->size2 = req_sz - wrp->size1; 91462306a36Sopenharmony_ci q->pidx = (uint16_t)(ALIGN(wrp->size2, CSIO_QCREDIT_SZ) / 91562306a36Sopenharmony_ci CSIO_QCREDIT_SZ); 91662306a36Sopenharmony_ci CSIO_INC_STATS(q, n_qwrap); 91762306a36Sopenharmony_ci CSIO_INC_STATS(q, n_eq_wr_split); 91862306a36Sopenharmony_ci } else { 91962306a36Sopenharmony_ci wrp->addr1 = cwr; 92062306a36Sopenharmony_ci wrp->size1 = req_sz; 92162306a36Sopenharmony_ci wrp->addr2 = NULL; 92262306a36Sopenharmony_ci wrp->size2 = 0; 92362306a36Sopenharmony_ci q->pidx += (uint16_t)req_credits; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* We are the end of queue, roll back pidx to top of queue */ 92662306a36Sopenharmony_ci if (unlikely(q->pidx == q->credits)) { 92762306a36Sopenharmony_ci q->pidx = 0; 92862306a36Sopenharmony_ci CSIO_INC_STATS(q, n_qwrap); 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci q->inc_idx = (uint16_t)req_credits; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci CSIO_INC_STATS(q, n_tot_reqs); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return 0; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci/* 94062306a36Sopenharmony_ci * csio_wr_copy_to_wrp - Copies given data into WR. 94162306a36Sopenharmony_ci * @data_buf - Data buffer 94262306a36Sopenharmony_ci * @wrp - Work request pair. 94362306a36Sopenharmony_ci * @wr_off - Work request offset. 94462306a36Sopenharmony_ci * @data_len - Data length. 94562306a36Sopenharmony_ci * 94662306a36Sopenharmony_ci * Copies the given data in Work Request. Work request pair(wrp) specifies 94762306a36Sopenharmony_ci * address information of Work request. 94862306a36Sopenharmony_ci * Returns: none 94962306a36Sopenharmony_ci */ 95062306a36Sopenharmony_civoid 95162306a36Sopenharmony_cicsio_wr_copy_to_wrp(void *data_buf, struct csio_wr_pair *wrp, 95262306a36Sopenharmony_ci uint32_t wr_off, uint32_t data_len) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci uint32_t nbytes; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Number of space available in buffer addr1 of WRP */ 95762306a36Sopenharmony_ci nbytes = ((wrp->size1 - wr_off) >= data_len) ? 95862306a36Sopenharmony_ci data_len : (wrp->size1 - wr_off); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci memcpy((uint8_t *) wrp->addr1 + wr_off, data_buf, nbytes); 96162306a36Sopenharmony_ci data_len -= nbytes; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* Write the remaining data from the begining of circular buffer */ 96462306a36Sopenharmony_ci if (data_len) { 96562306a36Sopenharmony_ci CSIO_DB_ASSERT(data_len <= wrp->size2); 96662306a36Sopenharmony_ci CSIO_DB_ASSERT(wrp->addr2 != NULL); 96762306a36Sopenharmony_ci memcpy(wrp->addr2, (uint8_t *) data_buf + nbytes, data_len); 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci/* 97262306a36Sopenharmony_ci * csio_wr_issue - Notify chip of Work request. 97362306a36Sopenharmony_ci * @hw: HW module. 97462306a36Sopenharmony_ci * @qidx: Index of queue. 97562306a36Sopenharmony_ci * @prio: 0: Low priority, 1: High priority 97662306a36Sopenharmony_ci * 97762306a36Sopenharmony_ci * Rings the SGE Doorbell by writing the current producer index of the passed 97862306a36Sopenharmony_ci * in queue into the register. 97962306a36Sopenharmony_ci * 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_ciint 98262306a36Sopenharmony_cicsio_wr_issue(struct csio_hw *hw, int qidx, bool prio) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 98562306a36Sopenharmony_ci struct csio_q *q = wrm->q_arr[qidx]; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci CSIO_DB_ASSERT((qidx >= 0) && (qidx < wrm->free_qidx)); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci wmb(); 99062306a36Sopenharmony_ci /* Ring SGE Doorbell writing q->pidx into it */ 99162306a36Sopenharmony_ci csio_wr_reg32(hw, DBPRIO_V(prio) | QID_V(q->un.eq.physeqid) | 99262306a36Sopenharmony_ci PIDX_T5_V(q->inc_idx) | DBTYPE_F, 99362306a36Sopenharmony_ci MYPF_REG(SGE_PF_KDOORBELL_A)); 99462306a36Sopenharmony_ci q->inc_idx = 0; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return 0; 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic inline uint32_t 100062306a36Sopenharmony_cicsio_wr_avail_qcredits(struct csio_q *q) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci if (q->pidx > q->cidx) 100362306a36Sopenharmony_ci return q->pidx - q->cidx; 100462306a36Sopenharmony_ci else if (q->cidx > q->pidx) 100562306a36Sopenharmony_ci return q->credits - (q->cidx - q->pidx); 100662306a36Sopenharmony_ci else 100762306a36Sopenharmony_ci return 0; /* cidx == pidx, empty queue */ 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci/* 101162306a36Sopenharmony_ci * csio_wr_inval_flq_buf - Invalidate a free list buffer entry. 101262306a36Sopenharmony_ci * @hw: HW module. 101362306a36Sopenharmony_ci * @flq: The freelist queue. 101462306a36Sopenharmony_ci * 101562306a36Sopenharmony_ci * Invalidate the driver's version of a freelist buffer entry, 101662306a36Sopenharmony_ci * without freeing the associated the DMA memory. The entry 101762306a36Sopenharmony_ci * to be invalidated is picked up from the current Free list 101862306a36Sopenharmony_ci * queue cidx. 101962306a36Sopenharmony_ci * 102062306a36Sopenharmony_ci */ 102162306a36Sopenharmony_cistatic inline void 102262306a36Sopenharmony_cicsio_wr_inval_flq_buf(struct csio_hw *hw, struct csio_q *flq) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci flq->cidx++; 102562306a36Sopenharmony_ci if (flq->cidx == flq->credits) { 102662306a36Sopenharmony_ci flq->cidx = 0; 102762306a36Sopenharmony_ci CSIO_INC_STATS(flq, n_qwrap); 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci/* 103262306a36Sopenharmony_ci * csio_wr_process_fl - Process a freelist completion. 103362306a36Sopenharmony_ci * @hw: HW module. 103462306a36Sopenharmony_ci * @q: The ingress queue attached to the Freelist. 103562306a36Sopenharmony_ci * @wr: The freelist completion WR in the ingress queue. 103662306a36Sopenharmony_ci * @len_to_qid: The lower 32-bits of the first flit of the RSP footer 103762306a36Sopenharmony_ci * @iq_handler: Caller's handler for this completion. 103862306a36Sopenharmony_ci * @priv: Private pointer of caller 103962306a36Sopenharmony_ci * 104062306a36Sopenharmony_ci */ 104162306a36Sopenharmony_cistatic inline void 104262306a36Sopenharmony_cicsio_wr_process_fl(struct csio_hw *hw, struct csio_q *q, 104362306a36Sopenharmony_ci void *wr, uint32_t len_to_qid, 104462306a36Sopenharmony_ci void (*iq_handler)(struct csio_hw *, void *, 104562306a36Sopenharmony_ci uint32_t, struct csio_fl_dma_buf *, 104662306a36Sopenharmony_ci void *), 104762306a36Sopenharmony_ci void *priv) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 105062306a36Sopenharmony_ci struct csio_sge *sge = &wrm->sge; 105162306a36Sopenharmony_ci struct csio_fl_dma_buf flb; 105262306a36Sopenharmony_ci struct csio_dma_buf *buf, *fbuf; 105362306a36Sopenharmony_ci uint32_t bufsz, len, lastlen = 0; 105462306a36Sopenharmony_ci struct csio_q *flq = hw->wrm.q_arr[q->un.iq.flq_idx]; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci CSIO_DB_ASSERT(flq != NULL); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci len = len_to_qid; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (len & IQWRF_NEWBUF) { 106162306a36Sopenharmony_ci if (flq->un.fl.offset > 0) { 106262306a36Sopenharmony_ci csio_wr_inval_flq_buf(hw, flq); 106362306a36Sopenharmony_ci flq->un.fl.offset = 0; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci len = IQWRF_LEN_GET(len); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci CSIO_DB_ASSERT(len != 0); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci flb.totlen = len; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* Consume all freelist buffers used for len bytes */ 107362306a36Sopenharmony_ci for (fbuf = flb.flbufs; ; fbuf++) { 107462306a36Sopenharmony_ci buf = &flq->un.fl.bufs[flq->cidx]; 107562306a36Sopenharmony_ci bufsz = csio_wr_fl_bufsz(sge, buf); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci fbuf->paddr = buf->paddr; 107862306a36Sopenharmony_ci fbuf->vaddr = buf->vaddr; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci flb.offset = flq->un.fl.offset; 108162306a36Sopenharmony_ci lastlen = min(bufsz, len); 108262306a36Sopenharmony_ci fbuf->len = lastlen; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci len -= lastlen; 108562306a36Sopenharmony_ci if (!len) 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci csio_wr_inval_flq_buf(hw, flq); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci flb.defer_free = flq->un.fl.packen ? 0 : 1; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci iq_handler(hw, wr, q->wr_sz - sizeof(struct csio_iqwr_footer), 109362306a36Sopenharmony_ci &flb, priv); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (flq->un.fl.packen) 109662306a36Sopenharmony_ci flq->un.fl.offset += ALIGN(lastlen, sge->csio_fl_align); 109762306a36Sopenharmony_ci else 109862306a36Sopenharmony_ci csio_wr_inval_flq_buf(hw, flq); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci/* 110362306a36Sopenharmony_ci * csio_is_new_iqwr - Is this a new Ingress queue entry ? 110462306a36Sopenharmony_ci * @q: Ingress quueue. 110562306a36Sopenharmony_ci * @ftr: Ingress queue WR SGE footer. 110662306a36Sopenharmony_ci * 110762306a36Sopenharmony_ci * The entry is new if our generation bit matches the corresponding 110862306a36Sopenharmony_ci * bit in the footer of the current WR. 110962306a36Sopenharmony_ci */ 111062306a36Sopenharmony_cistatic inline bool 111162306a36Sopenharmony_cicsio_is_new_iqwr(struct csio_q *q, struct csio_iqwr_footer *ftr) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci return (q->un.iq.genbit == (ftr->u.type_gen >> IQWRF_GEN_SHIFT)); 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci/* 111762306a36Sopenharmony_ci * csio_wr_process_iq - Process elements in Ingress queue. 111862306a36Sopenharmony_ci * @hw: HW pointer 111962306a36Sopenharmony_ci * @qidx: Index of queue 112062306a36Sopenharmony_ci * @iq_handler: Handler for this queue 112162306a36Sopenharmony_ci * @priv: Caller's private pointer 112262306a36Sopenharmony_ci * 112362306a36Sopenharmony_ci * This routine walks through every entry of the ingress queue, calling 112462306a36Sopenharmony_ci * the provided iq_handler with the entry, until the generation bit 112562306a36Sopenharmony_ci * flips. 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ciint 112862306a36Sopenharmony_cicsio_wr_process_iq(struct csio_hw *hw, struct csio_q *q, 112962306a36Sopenharmony_ci void (*iq_handler)(struct csio_hw *, void *, 113062306a36Sopenharmony_ci uint32_t, struct csio_fl_dma_buf *, 113162306a36Sopenharmony_ci void *), 113262306a36Sopenharmony_ci void *priv) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 113562306a36Sopenharmony_ci void *wr = (void *)((uintptr_t)q->vstart + (q->cidx * q->wr_sz)); 113662306a36Sopenharmony_ci struct csio_iqwr_footer *ftr; 113762306a36Sopenharmony_ci uint32_t wr_type, fw_qid, qid; 113862306a36Sopenharmony_ci struct csio_q *q_completed; 113962306a36Sopenharmony_ci struct csio_q *flq = csio_iq_has_fl(q) ? 114062306a36Sopenharmony_ci wrm->q_arr[q->un.iq.flq_idx] : NULL; 114162306a36Sopenharmony_ci int rv = 0; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci /* Get the footer */ 114462306a36Sopenharmony_ci ftr = (struct csio_iqwr_footer *)((uintptr_t)wr + 114562306a36Sopenharmony_ci (q->wr_sz - sizeof(*ftr))); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci /* 114862306a36Sopenharmony_ci * When q wrapped around last time, driver should have inverted 114962306a36Sopenharmony_ci * ic.genbit as well. 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_ci while (csio_is_new_iqwr(q, ftr)) { 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci CSIO_DB_ASSERT(((uintptr_t)wr + q->wr_sz) <= 115462306a36Sopenharmony_ci (uintptr_t)q->vwrap); 115562306a36Sopenharmony_ci rmb(); 115662306a36Sopenharmony_ci wr_type = IQWRF_TYPE_GET(ftr->u.type_gen); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci switch (wr_type) { 115962306a36Sopenharmony_ci case X_RSPD_TYPE_CPL: 116062306a36Sopenharmony_ci /* Subtract footer from WR len */ 116162306a36Sopenharmony_ci iq_handler(hw, wr, q->wr_sz - sizeof(*ftr), NULL, priv); 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci case X_RSPD_TYPE_FLBUF: 116462306a36Sopenharmony_ci csio_wr_process_fl(hw, q, wr, 116562306a36Sopenharmony_ci ntohl(ftr->pldbuflen_qid), 116662306a36Sopenharmony_ci iq_handler, priv); 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci case X_RSPD_TYPE_INTR: 116962306a36Sopenharmony_ci fw_qid = ntohl(ftr->pldbuflen_qid); 117062306a36Sopenharmony_ci qid = fw_qid - wrm->fw_iq_start; 117162306a36Sopenharmony_ci q_completed = hw->wrm.intr_map[qid]; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (unlikely(qid == 117462306a36Sopenharmony_ci csio_q_physiqid(hw, hw->intr_iq_idx))) { 117562306a36Sopenharmony_ci /* 117662306a36Sopenharmony_ci * We are already in the Forward Interrupt 117762306a36Sopenharmony_ci * Interrupt Queue Service! Do-not service 117862306a36Sopenharmony_ci * again! 117962306a36Sopenharmony_ci * 118062306a36Sopenharmony_ci */ 118162306a36Sopenharmony_ci } else { 118262306a36Sopenharmony_ci CSIO_DB_ASSERT(q_completed); 118362306a36Sopenharmony_ci CSIO_DB_ASSERT( 118462306a36Sopenharmony_ci q_completed->un.iq.iq_intx_handler); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci /* Call the queue handler. */ 118762306a36Sopenharmony_ci q_completed->un.iq.iq_intx_handler(hw, NULL, 118862306a36Sopenharmony_ci 0, NULL, (void *)q_completed); 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci break; 119162306a36Sopenharmony_ci default: 119262306a36Sopenharmony_ci csio_warn(hw, "Unknown resp type 0x%x received\n", 119362306a36Sopenharmony_ci wr_type); 119462306a36Sopenharmony_ci CSIO_INC_STATS(q, n_rsp_unknown); 119562306a36Sopenharmony_ci break; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci /* 119962306a36Sopenharmony_ci * Ingress *always* has fixed size WR entries. Therefore, 120062306a36Sopenharmony_ci * there should always be complete WRs towards the end of 120162306a36Sopenharmony_ci * queue. 120262306a36Sopenharmony_ci */ 120362306a36Sopenharmony_ci if (((uintptr_t)wr + q->wr_sz) == (uintptr_t)q->vwrap) { 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* Roll over to start of queue */ 120662306a36Sopenharmony_ci q->cidx = 0; 120762306a36Sopenharmony_ci wr = q->vstart; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci /* Toggle genbit */ 121062306a36Sopenharmony_ci q->un.iq.genbit ^= 0x1; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci CSIO_INC_STATS(q, n_qwrap); 121362306a36Sopenharmony_ci } else { 121462306a36Sopenharmony_ci q->cidx++; 121562306a36Sopenharmony_ci wr = (void *)((uintptr_t)(q->vstart) + 121662306a36Sopenharmony_ci (q->cidx * q->wr_sz)); 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci ftr = (struct csio_iqwr_footer *)((uintptr_t)wr + 122062306a36Sopenharmony_ci (q->wr_sz - sizeof(*ftr))); 122162306a36Sopenharmony_ci q->inc_idx++; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci } /* while (q->un.iq.genbit == hdr->genbit) */ 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci /* 122662306a36Sopenharmony_ci * We need to re-arm SGE interrupts in case we got a stray interrupt, 122762306a36Sopenharmony_ci * especially in msix mode. With INTx, this may be a common occurence. 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_ci if (unlikely(!q->inc_idx)) { 123062306a36Sopenharmony_ci CSIO_INC_STATS(q, n_stray_comp); 123162306a36Sopenharmony_ci rv = -EINVAL; 123262306a36Sopenharmony_ci goto restart; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* Replenish free list buffers if pending falls below low water mark */ 123662306a36Sopenharmony_ci if (flq) { 123762306a36Sopenharmony_ci uint32_t avail = csio_wr_avail_qcredits(flq); 123862306a36Sopenharmony_ci if (avail <= 16) { 123962306a36Sopenharmony_ci /* Make sure in FLQ, atleast 1 credit (8 FL buffers) 124062306a36Sopenharmony_ci * remains unpopulated otherwise HW thinks 124162306a36Sopenharmony_ci * FLQ is empty. 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_ci csio_wr_update_fl(hw, flq, (flq->credits - 8) - avail); 124462306a36Sopenharmony_ci csio_wr_ring_fldb(hw, flq); 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cirestart: 124962306a36Sopenharmony_ci /* Now inform SGE about our incremental index value */ 125062306a36Sopenharmony_ci csio_wr_reg32(hw, CIDXINC_V(q->inc_idx) | 125162306a36Sopenharmony_ci INGRESSQID_V(q->un.iq.physiqid) | 125262306a36Sopenharmony_ci TIMERREG_V(csio_sge_timer_reg), 125362306a36Sopenharmony_ci MYPF_REG(SGE_PF_GTS_A)); 125462306a36Sopenharmony_ci q->stats.n_tot_rsps += q->inc_idx; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci q->inc_idx = 0; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci return rv; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ciint 126262306a36Sopenharmony_cicsio_wr_process_iq_idx(struct csio_hw *hw, int qidx, 126362306a36Sopenharmony_ci void (*iq_handler)(struct csio_hw *, void *, 126462306a36Sopenharmony_ci uint32_t, struct csio_fl_dma_buf *, 126562306a36Sopenharmony_ci void *), 126662306a36Sopenharmony_ci void *priv) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 126962306a36Sopenharmony_ci struct csio_q *iq = wrm->q_arr[qidx]; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci return csio_wr_process_iq(hw, iq, iq_handler, priv); 127262306a36Sopenharmony_ci} 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic int 127562306a36Sopenharmony_cicsio_closest_timer(struct csio_sge *s, int time) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci int i, delta, match = 0, min_delta = INT_MAX; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { 128062306a36Sopenharmony_ci delta = time - s->timer_val[i]; 128162306a36Sopenharmony_ci if (delta < 0) 128262306a36Sopenharmony_ci delta = -delta; 128362306a36Sopenharmony_ci if (delta < min_delta) { 128462306a36Sopenharmony_ci min_delta = delta; 128562306a36Sopenharmony_ci match = i; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci return match; 128962306a36Sopenharmony_ci} 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_cistatic int 129262306a36Sopenharmony_cicsio_closest_thresh(struct csio_sge *s, int cnt) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci int i, delta, match = 0, min_delta = INT_MAX; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { 129762306a36Sopenharmony_ci delta = cnt - s->counter_val[i]; 129862306a36Sopenharmony_ci if (delta < 0) 129962306a36Sopenharmony_ci delta = -delta; 130062306a36Sopenharmony_ci if (delta < min_delta) { 130162306a36Sopenharmony_ci min_delta = delta; 130262306a36Sopenharmony_ci match = i; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci return match; 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic void 130962306a36Sopenharmony_cicsio_wr_fixup_host_params(struct csio_hw *hw) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 131262306a36Sopenharmony_ci struct csio_sge *sge = &wrm->sge; 131362306a36Sopenharmony_ci uint32_t clsz = L1_CACHE_BYTES; 131462306a36Sopenharmony_ci uint32_t s_hps = PAGE_SHIFT - 10; 131562306a36Sopenharmony_ci uint32_t stat_len = clsz > 64 ? 128 : 64; 131662306a36Sopenharmony_ci u32 fl_align = clsz < 32 ? 32 : clsz; 131762306a36Sopenharmony_ci u32 pack_align; 131862306a36Sopenharmony_ci u32 ingpad, ingpack; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci csio_wr_reg32(hw, HOSTPAGESIZEPF0_V(s_hps) | HOSTPAGESIZEPF1_V(s_hps) | 132162306a36Sopenharmony_ci HOSTPAGESIZEPF2_V(s_hps) | HOSTPAGESIZEPF3_V(s_hps) | 132262306a36Sopenharmony_ci HOSTPAGESIZEPF4_V(s_hps) | HOSTPAGESIZEPF5_V(s_hps) | 132362306a36Sopenharmony_ci HOSTPAGESIZEPF6_V(s_hps) | HOSTPAGESIZEPF7_V(s_hps), 132462306a36Sopenharmony_ci SGE_HOST_PAGE_SIZE_A); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* T5 introduced the separation of the Free List Padding and 132762306a36Sopenharmony_ci * Packing Boundaries. Thus, we can select a smaller Padding 132862306a36Sopenharmony_ci * Boundary to avoid uselessly chewing up PCIe Link and Memory 132962306a36Sopenharmony_ci * Bandwidth, and use a Packing Boundary which is large enough 133062306a36Sopenharmony_ci * to avoid false sharing between CPUs, etc. 133162306a36Sopenharmony_ci * 133262306a36Sopenharmony_ci * For the PCI Link, the smaller the Padding Boundary the 133362306a36Sopenharmony_ci * better. For the Memory Controller, a smaller Padding 133462306a36Sopenharmony_ci * Boundary is better until we cross under the Memory Line 133562306a36Sopenharmony_ci * Size (the minimum unit of transfer to/from Memory). If we 133662306a36Sopenharmony_ci * have a Padding Boundary which is smaller than the Memory 133762306a36Sopenharmony_ci * Line Size, that'll involve a Read-Modify-Write cycle on the 133862306a36Sopenharmony_ci * Memory Controller which is never good. 133962306a36Sopenharmony_ci */ 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci /* We want the Packing Boundary to be based on the Cache Line 134262306a36Sopenharmony_ci * Size in order to help avoid False Sharing performance 134362306a36Sopenharmony_ci * issues between CPUs, etc. We also want the Packing 134462306a36Sopenharmony_ci * Boundary to incorporate the PCI-E Maximum Payload Size. We 134562306a36Sopenharmony_ci * get best performance when the Packing Boundary is a 134662306a36Sopenharmony_ci * multiple of the Maximum Payload Size. 134762306a36Sopenharmony_ci */ 134862306a36Sopenharmony_ci pack_align = fl_align; 134962306a36Sopenharmony_ci if (pci_is_pcie(hw->pdev)) { 135062306a36Sopenharmony_ci u32 mps, mps_log; 135162306a36Sopenharmony_ci u16 devctl; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci /* The PCIe Device Control Maximum Payload Size field 135462306a36Sopenharmony_ci * [bits 7:5] encodes sizes as powers of 2 starting at 135562306a36Sopenharmony_ci * 128 bytes. 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_ci pcie_capability_read_word(hw->pdev, PCI_EXP_DEVCTL, &devctl); 135862306a36Sopenharmony_ci mps_log = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5) + 7; 135962306a36Sopenharmony_ci mps = 1 << mps_log; 136062306a36Sopenharmony_ci if (mps > pack_align) 136162306a36Sopenharmony_ci pack_align = mps; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci /* T5/T6 have a special interpretation of the "0" 136562306a36Sopenharmony_ci * value for the Packing Boundary. This corresponds to 16 136662306a36Sopenharmony_ci * bytes instead of the expected 32 bytes. 136762306a36Sopenharmony_ci */ 136862306a36Sopenharmony_ci if (pack_align <= 16) { 136962306a36Sopenharmony_ci ingpack = INGPACKBOUNDARY_16B_X; 137062306a36Sopenharmony_ci fl_align = 16; 137162306a36Sopenharmony_ci } else if (pack_align == 32) { 137262306a36Sopenharmony_ci ingpack = INGPACKBOUNDARY_64B_X; 137362306a36Sopenharmony_ci fl_align = 64; 137462306a36Sopenharmony_ci } else { 137562306a36Sopenharmony_ci u32 pack_align_log = fls(pack_align) - 1; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci ingpack = pack_align_log - INGPACKBOUNDARY_SHIFT_X; 137862306a36Sopenharmony_ci fl_align = pack_align; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci /* Use the smallest Ingress Padding which isn't smaller than 138262306a36Sopenharmony_ci * the Memory Controller Read/Write Size. We'll take that as 138362306a36Sopenharmony_ci * being 8 bytes since we don't know of any system with a 138462306a36Sopenharmony_ci * wider Memory Controller Bus Width. 138562306a36Sopenharmony_ci */ 138662306a36Sopenharmony_ci if (csio_is_t5(hw->pdev->device & CSIO_HW_CHIP_MASK)) 138762306a36Sopenharmony_ci ingpad = INGPADBOUNDARY_32B_X; 138862306a36Sopenharmony_ci else 138962306a36Sopenharmony_ci ingpad = T6_INGPADBOUNDARY_8B_X; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci csio_set_reg_field(hw, SGE_CONTROL_A, 139262306a36Sopenharmony_ci INGPADBOUNDARY_V(INGPADBOUNDARY_M) | 139362306a36Sopenharmony_ci EGRSTATUSPAGESIZE_F, 139462306a36Sopenharmony_ci INGPADBOUNDARY_V(ingpad) | 139562306a36Sopenharmony_ci EGRSTATUSPAGESIZE_V(stat_len != 64)); 139662306a36Sopenharmony_ci csio_set_reg_field(hw, SGE_CONTROL2_A, 139762306a36Sopenharmony_ci INGPACKBOUNDARY_V(INGPACKBOUNDARY_M), 139862306a36Sopenharmony_ci INGPACKBOUNDARY_V(ingpack)); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* FL BUFFER SIZE#0 is Page size i,e already aligned to cache line */ 140162306a36Sopenharmony_ci csio_wr_reg32(hw, PAGE_SIZE, SGE_FL_BUFFER_SIZE0_A); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* 140462306a36Sopenharmony_ci * If using hard params, the following will get set correctly 140562306a36Sopenharmony_ci * in csio_wr_set_sge(). 140662306a36Sopenharmony_ci */ 140762306a36Sopenharmony_ci if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS) { 140862306a36Sopenharmony_ci csio_wr_reg32(hw, 140962306a36Sopenharmony_ci (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2_A) + 141062306a36Sopenharmony_ci fl_align - 1) & ~(fl_align - 1), 141162306a36Sopenharmony_ci SGE_FL_BUFFER_SIZE2_A); 141262306a36Sopenharmony_ci csio_wr_reg32(hw, 141362306a36Sopenharmony_ci (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3_A) + 141462306a36Sopenharmony_ci fl_align - 1) & ~(fl_align - 1), 141562306a36Sopenharmony_ci SGE_FL_BUFFER_SIZE3_A); 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci sge->csio_fl_align = fl_align; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci csio_wr_reg32(hw, HPZ0_V(PAGE_SHIFT - 12), ULP_RX_TDDP_PSZ_A); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci /* default value of rx_dma_offset of the NIC driver */ 142362306a36Sopenharmony_ci csio_set_reg_field(hw, SGE_CONTROL_A, 142462306a36Sopenharmony_ci PKTSHIFT_V(PKTSHIFT_M), 142562306a36Sopenharmony_ci PKTSHIFT_V(CSIO_SGE_RX_DMA_OFFSET)); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci csio_hw_tp_wr_bits_indirect(hw, TP_INGRESS_CONFIG_A, 142862306a36Sopenharmony_ci CSUM_HAS_PSEUDO_HDR_F, 0); 142962306a36Sopenharmony_ci} 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_cistatic void 143262306a36Sopenharmony_cicsio_init_intr_coalesce_parms(struct csio_hw *hw) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 143562306a36Sopenharmony_ci struct csio_sge *sge = &wrm->sge; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci csio_sge_thresh_reg = csio_closest_thresh(sge, csio_intr_coalesce_cnt); 143862306a36Sopenharmony_ci if (csio_intr_coalesce_cnt) { 143962306a36Sopenharmony_ci csio_sge_thresh_reg = 0; 144062306a36Sopenharmony_ci csio_sge_timer_reg = X_TIMERREG_RESTART_COUNTER; 144162306a36Sopenharmony_ci return; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci csio_sge_timer_reg = csio_closest_timer(sge, csio_intr_coalesce_time); 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci/* 144862306a36Sopenharmony_ci * csio_wr_get_sge - Get SGE register values. 144962306a36Sopenharmony_ci * @hw: HW module. 145062306a36Sopenharmony_ci * 145162306a36Sopenharmony_ci * Used by non-master functions and by master-functions relying on config file. 145262306a36Sopenharmony_ci */ 145362306a36Sopenharmony_cistatic void 145462306a36Sopenharmony_cicsio_wr_get_sge(struct csio_hw *hw) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 145762306a36Sopenharmony_ci struct csio_sge *sge = &wrm->sge; 145862306a36Sopenharmony_ci uint32_t ingpad; 145962306a36Sopenharmony_ci int i; 146062306a36Sopenharmony_ci u32 timer_value_0_and_1, timer_value_2_and_3, timer_value_4_and_5; 146162306a36Sopenharmony_ci u32 ingress_rx_threshold; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL_A); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci ingpad = INGPADBOUNDARY_G(sge->sge_control); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci switch (ingpad) { 146862306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_32B: 146962306a36Sopenharmony_ci sge->csio_fl_align = 32; break; 147062306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_64B: 147162306a36Sopenharmony_ci sge->csio_fl_align = 64; break; 147262306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_128B: 147362306a36Sopenharmony_ci sge->csio_fl_align = 128; break; 147462306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_256B: 147562306a36Sopenharmony_ci sge->csio_fl_align = 256; break; 147662306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_512B: 147762306a36Sopenharmony_ci sge->csio_fl_align = 512; break; 147862306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_1024B: 147962306a36Sopenharmony_ci sge->csio_fl_align = 1024; break; 148062306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_2048B: 148162306a36Sopenharmony_ci sge->csio_fl_align = 2048; break; 148262306a36Sopenharmony_ci case X_INGPCIEBOUNDARY_4096B: 148362306a36Sopenharmony_ci sge->csio_fl_align = 4096; break; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci for (i = 0; i < CSIO_SGE_FL_SIZE_REGS; i++) 148762306a36Sopenharmony_ci csio_get_flbuf_size(hw, sge, i); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci timer_value_0_and_1 = csio_rd_reg32(hw, SGE_TIMER_VALUE_0_AND_1_A); 149062306a36Sopenharmony_ci timer_value_2_and_3 = csio_rd_reg32(hw, SGE_TIMER_VALUE_2_AND_3_A); 149162306a36Sopenharmony_ci timer_value_4_and_5 = csio_rd_reg32(hw, SGE_TIMER_VALUE_4_AND_5_A); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci sge->timer_val[0] = (uint16_t)csio_core_ticks_to_us(hw, 149462306a36Sopenharmony_ci TIMERVALUE0_G(timer_value_0_and_1)); 149562306a36Sopenharmony_ci sge->timer_val[1] = (uint16_t)csio_core_ticks_to_us(hw, 149662306a36Sopenharmony_ci TIMERVALUE1_G(timer_value_0_and_1)); 149762306a36Sopenharmony_ci sge->timer_val[2] = (uint16_t)csio_core_ticks_to_us(hw, 149862306a36Sopenharmony_ci TIMERVALUE2_G(timer_value_2_and_3)); 149962306a36Sopenharmony_ci sge->timer_val[3] = (uint16_t)csio_core_ticks_to_us(hw, 150062306a36Sopenharmony_ci TIMERVALUE3_G(timer_value_2_and_3)); 150162306a36Sopenharmony_ci sge->timer_val[4] = (uint16_t)csio_core_ticks_to_us(hw, 150262306a36Sopenharmony_ci TIMERVALUE4_G(timer_value_4_and_5)); 150362306a36Sopenharmony_ci sge->timer_val[5] = (uint16_t)csio_core_ticks_to_us(hw, 150462306a36Sopenharmony_ci TIMERVALUE5_G(timer_value_4_and_5)); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci ingress_rx_threshold = csio_rd_reg32(hw, SGE_INGRESS_RX_THRESHOLD_A); 150762306a36Sopenharmony_ci sge->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold); 150862306a36Sopenharmony_ci sge->counter_val[1] = THRESHOLD_1_G(ingress_rx_threshold); 150962306a36Sopenharmony_ci sge->counter_val[2] = THRESHOLD_2_G(ingress_rx_threshold); 151062306a36Sopenharmony_ci sge->counter_val[3] = THRESHOLD_3_G(ingress_rx_threshold); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci csio_init_intr_coalesce_parms(hw); 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci/* 151662306a36Sopenharmony_ci * csio_wr_set_sge - Initialize SGE registers 151762306a36Sopenharmony_ci * @hw: HW module. 151862306a36Sopenharmony_ci * 151962306a36Sopenharmony_ci * Used by Master function to initialize SGE registers in the absence 152062306a36Sopenharmony_ci * of a config file. 152162306a36Sopenharmony_ci */ 152262306a36Sopenharmony_cistatic void 152362306a36Sopenharmony_cicsio_wr_set_sge(struct csio_hw *hw) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 152662306a36Sopenharmony_ci struct csio_sge *sge = &wrm->sge; 152762306a36Sopenharmony_ci int i; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci /* 153062306a36Sopenharmony_ci * Set up our basic SGE mode to deliver CPL messages to our Ingress 153162306a36Sopenharmony_ci * Queue and Packet Date to the Free List. 153262306a36Sopenharmony_ci */ 153362306a36Sopenharmony_ci csio_set_reg_field(hw, SGE_CONTROL_A, RXPKTCPLMODE_F, RXPKTCPLMODE_F); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL_A); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci /* sge->csio_fl_align is set up by csio_wr_fixup_host_params(). */ 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* 154062306a36Sopenharmony_ci * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows 154162306a36Sopenharmony_ci * and generate an interrupt when this occurs so we can recover. 154262306a36Sopenharmony_ci */ 154362306a36Sopenharmony_ci csio_set_reg_field(hw, SGE_DBFIFO_STATUS_A, 154462306a36Sopenharmony_ci LP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M), 154562306a36Sopenharmony_ci LP_INT_THRESH_T5_V(CSIO_SGE_DBFIFO_INT_THRESH)); 154662306a36Sopenharmony_ci csio_set_reg_field(hw, SGE_DBFIFO_STATUS2_A, 154762306a36Sopenharmony_ci HP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M), 154862306a36Sopenharmony_ci HP_INT_THRESH_T5_V(CSIO_SGE_DBFIFO_INT_THRESH)); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci csio_set_reg_field(hw, SGE_DOORBELL_CONTROL_A, ENABLE_DROP_F, 155162306a36Sopenharmony_ci ENABLE_DROP_F); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci /* SGE_FL_BUFFER_SIZE0 is set up by csio_wr_fixup_host_params(). */ 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci CSIO_SET_FLBUF_SIZE(hw, 1, CSIO_SGE_FLBUF_SIZE1); 155662306a36Sopenharmony_ci csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE2 + sge->csio_fl_align - 1) 155762306a36Sopenharmony_ci & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE2_A); 155862306a36Sopenharmony_ci csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE3 + sge->csio_fl_align - 1) 155962306a36Sopenharmony_ci & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE3_A); 156062306a36Sopenharmony_ci CSIO_SET_FLBUF_SIZE(hw, 4, CSIO_SGE_FLBUF_SIZE4); 156162306a36Sopenharmony_ci CSIO_SET_FLBUF_SIZE(hw, 5, CSIO_SGE_FLBUF_SIZE5); 156262306a36Sopenharmony_ci CSIO_SET_FLBUF_SIZE(hw, 6, CSIO_SGE_FLBUF_SIZE6); 156362306a36Sopenharmony_ci CSIO_SET_FLBUF_SIZE(hw, 7, CSIO_SGE_FLBUF_SIZE7); 156462306a36Sopenharmony_ci CSIO_SET_FLBUF_SIZE(hw, 8, CSIO_SGE_FLBUF_SIZE8); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci for (i = 0; i < CSIO_SGE_FL_SIZE_REGS; i++) 156762306a36Sopenharmony_ci csio_get_flbuf_size(hw, sge, i); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* Initialize interrupt coalescing attributes */ 157062306a36Sopenharmony_ci sge->timer_val[0] = CSIO_SGE_TIMER_VAL_0; 157162306a36Sopenharmony_ci sge->timer_val[1] = CSIO_SGE_TIMER_VAL_1; 157262306a36Sopenharmony_ci sge->timer_val[2] = CSIO_SGE_TIMER_VAL_2; 157362306a36Sopenharmony_ci sge->timer_val[3] = CSIO_SGE_TIMER_VAL_3; 157462306a36Sopenharmony_ci sge->timer_val[4] = CSIO_SGE_TIMER_VAL_4; 157562306a36Sopenharmony_ci sge->timer_val[5] = CSIO_SGE_TIMER_VAL_5; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci sge->counter_val[0] = CSIO_SGE_INT_CNT_VAL_0; 157862306a36Sopenharmony_ci sge->counter_val[1] = CSIO_SGE_INT_CNT_VAL_1; 157962306a36Sopenharmony_ci sge->counter_val[2] = CSIO_SGE_INT_CNT_VAL_2; 158062306a36Sopenharmony_ci sge->counter_val[3] = CSIO_SGE_INT_CNT_VAL_3; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci csio_wr_reg32(hw, THRESHOLD_0_V(sge->counter_val[0]) | 158362306a36Sopenharmony_ci THRESHOLD_1_V(sge->counter_val[1]) | 158462306a36Sopenharmony_ci THRESHOLD_2_V(sge->counter_val[2]) | 158562306a36Sopenharmony_ci THRESHOLD_3_V(sge->counter_val[3]), 158662306a36Sopenharmony_ci SGE_INGRESS_RX_THRESHOLD_A); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci csio_wr_reg32(hw, 158962306a36Sopenharmony_ci TIMERVALUE0_V(csio_us_to_core_ticks(hw, sge->timer_val[0])) | 159062306a36Sopenharmony_ci TIMERVALUE1_V(csio_us_to_core_ticks(hw, sge->timer_val[1])), 159162306a36Sopenharmony_ci SGE_TIMER_VALUE_0_AND_1_A); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci csio_wr_reg32(hw, 159462306a36Sopenharmony_ci TIMERVALUE2_V(csio_us_to_core_ticks(hw, sge->timer_val[2])) | 159562306a36Sopenharmony_ci TIMERVALUE3_V(csio_us_to_core_ticks(hw, sge->timer_val[3])), 159662306a36Sopenharmony_ci SGE_TIMER_VALUE_2_AND_3_A); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci csio_wr_reg32(hw, 159962306a36Sopenharmony_ci TIMERVALUE4_V(csio_us_to_core_ticks(hw, sge->timer_val[4])) | 160062306a36Sopenharmony_ci TIMERVALUE5_V(csio_us_to_core_ticks(hw, sge->timer_val[5])), 160162306a36Sopenharmony_ci SGE_TIMER_VALUE_4_AND_5_A); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci csio_init_intr_coalesce_parms(hw); 160462306a36Sopenharmony_ci} 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_civoid 160762306a36Sopenharmony_cicsio_wr_sge_init(struct csio_hw *hw) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci /* 161062306a36Sopenharmony_ci * If we are master and chip is not initialized: 161162306a36Sopenharmony_ci * - If we plan to use the config file, we need to fixup some 161262306a36Sopenharmony_ci * host specific registers, and read the rest of the SGE 161362306a36Sopenharmony_ci * configuration. 161462306a36Sopenharmony_ci * - If we dont plan to use the config file, we need to initialize 161562306a36Sopenharmony_ci * SGE entirely, including fixing the host specific registers. 161662306a36Sopenharmony_ci * If we are master and chip is initialized, just read and work off of 161762306a36Sopenharmony_ci * the already initialized SGE values. 161862306a36Sopenharmony_ci * If we arent the master, we are only allowed to read and work off of 161962306a36Sopenharmony_ci * the already initialized SGE values. 162062306a36Sopenharmony_ci * 162162306a36Sopenharmony_ci * Therefore, before calling this function, we assume that the master- 162262306a36Sopenharmony_ci * ship of the card, state and whether to use config file or not, have 162362306a36Sopenharmony_ci * already been decided. 162462306a36Sopenharmony_ci */ 162562306a36Sopenharmony_ci if (csio_is_hw_master(hw)) { 162662306a36Sopenharmony_ci if (hw->fw_state != CSIO_DEV_STATE_INIT) 162762306a36Sopenharmony_ci csio_wr_fixup_host_params(hw); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS) 163062306a36Sopenharmony_ci csio_wr_get_sge(hw); 163162306a36Sopenharmony_ci else 163262306a36Sopenharmony_ci csio_wr_set_sge(hw); 163362306a36Sopenharmony_ci } else 163462306a36Sopenharmony_ci csio_wr_get_sge(hw); 163562306a36Sopenharmony_ci} 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci/* 163862306a36Sopenharmony_ci * csio_wrm_init - Initialize Work request module. 163962306a36Sopenharmony_ci * @wrm: WR module 164062306a36Sopenharmony_ci * @hw: HW pointer 164162306a36Sopenharmony_ci * 164262306a36Sopenharmony_ci * Allocates memory for an array of queue pointers starting at q_arr. 164362306a36Sopenharmony_ci */ 164462306a36Sopenharmony_ciint 164562306a36Sopenharmony_cicsio_wrm_init(struct csio_wrm *wrm, struct csio_hw *hw) 164662306a36Sopenharmony_ci{ 164762306a36Sopenharmony_ci int i; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci if (!wrm->num_q) { 165062306a36Sopenharmony_ci csio_err(hw, "Num queues is not set\n"); 165162306a36Sopenharmony_ci return -EINVAL; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci wrm->q_arr = kcalloc(wrm->num_q, sizeof(struct csio_q *), GFP_KERNEL); 165562306a36Sopenharmony_ci if (!wrm->q_arr) 165662306a36Sopenharmony_ci goto err; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci for (i = 0; i < wrm->num_q; i++) { 165962306a36Sopenharmony_ci wrm->q_arr[i] = kzalloc(sizeof(struct csio_q), GFP_KERNEL); 166062306a36Sopenharmony_ci if (!wrm->q_arr[i]) { 166162306a36Sopenharmony_ci while (--i >= 0) 166262306a36Sopenharmony_ci kfree(wrm->q_arr[i]); 166362306a36Sopenharmony_ci goto err_free_arr; 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci wrm->free_qidx = 0; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci return 0; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_cierr_free_arr: 167162306a36Sopenharmony_ci kfree(wrm->q_arr); 167262306a36Sopenharmony_cierr: 167362306a36Sopenharmony_ci return -ENOMEM; 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci/* 167762306a36Sopenharmony_ci * csio_wrm_exit - Initialize Work request module. 167862306a36Sopenharmony_ci * @wrm: WR module 167962306a36Sopenharmony_ci * @hw: HW module 168062306a36Sopenharmony_ci * 168162306a36Sopenharmony_ci * Uninitialize WR module. Free q_arr and pointers in it. 168262306a36Sopenharmony_ci * We have the additional job of freeing the DMA memory associated 168362306a36Sopenharmony_ci * with the queues. 168462306a36Sopenharmony_ci */ 168562306a36Sopenharmony_civoid 168662306a36Sopenharmony_cicsio_wrm_exit(struct csio_wrm *wrm, struct csio_hw *hw) 168762306a36Sopenharmony_ci{ 168862306a36Sopenharmony_ci int i; 168962306a36Sopenharmony_ci uint32_t j; 169062306a36Sopenharmony_ci struct csio_q *q; 169162306a36Sopenharmony_ci struct csio_dma_buf *buf; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci for (i = 0; i < wrm->num_q; i++) { 169462306a36Sopenharmony_ci q = wrm->q_arr[i]; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (wrm->free_qidx && (i < wrm->free_qidx)) { 169762306a36Sopenharmony_ci if (q->type == CSIO_FREELIST) { 169862306a36Sopenharmony_ci if (!q->un.fl.bufs) 169962306a36Sopenharmony_ci continue; 170062306a36Sopenharmony_ci for (j = 0; j < q->credits; j++) { 170162306a36Sopenharmony_ci buf = &q->un.fl.bufs[j]; 170262306a36Sopenharmony_ci if (!buf->vaddr) 170362306a36Sopenharmony_ci continue; 170462306a36Sopenharmony_ci dma_free_coherent(&hw->pdev->dev, 170562306a36Sopenharmony_ci buf->len, buf->vaddr, 170662306a36Sopenharmony_ci buf->paddr); 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci kfree(q->un.fl.bufs); 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci dma_free_coherent(&hw->pdev->dev, q->size, 171162306a36Sopenharmony_ci q->vstart, q->pstart); 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci kfree(q); 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci hw->flags &= ~CSIO_HWF_Q_MEM_ALLOCED; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci kfree(wrm->q_arr); 171962306a36Sopenharmony_ci} 1720