162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2021 Broadcom. All Rights Reserved. The term 462306a36Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "efct_driver.h" 862306a36Sopenharmony_ci#include "efct_hw.h" 962306a36Sopenharmony_ci#include "efct_unsol.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciint 1262306a36Sopenharmony_ciefct_hw_init_queues(struct efct_hw *hw) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci struct hw_eq *eq = NULL; 1562306a36Sopenharmony_ci struct hw_cq *cq = NULL; 1662306a36Sopenharmony_ci struct hw_wq *wq = NULL; 1762306a36Sopenharmony_ci struct hw_mq *mq = NULL; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci struct hw_eq *eqs[EFCT_HW_MAX_NUM_EQ]; 2062306a36Sopenharmony_ci struct hw_cq *cqs[EFCT_HW_MAX_NUM_EQ]; 2162306a36Sopenharmony_ci struct hw_rq *rqs[EFCT_HW_MAX_NUM_EQ]; 2262306a36Sopenharmony_ci u32 i = 0, j; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci hw->eq_count = 0; 2562306a36Sopenharmony_ci hw->cq_count = 0; 2662306a36Sopenharmony_ci hw->mq_count = 0; 2762306a36Sopenharmony_ci hw->wq_count = 0; 2862306a36Sopenharmony_ci hw->rq_count = 0; 2962306a36Sopenharmony_ci hw->hw_rq_count = 0; 3062306a36Sopenharmony_ci INIT_LIST_HEAD(&hw->eq_list); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci for (i = 0; i < hw->config.n_eq; i++) { 3362306a36Sopenharmony_ci /* Create EQ */ 3462306a36Sopenharmony_ci eq = efct_hw_new_eq(hw, EFCT_HW_EQ_DEPTH); 3562306a36Sopenharmony_ci if (!eq) { 3662306a36Sopenharmony_ci efct_hw_queue_teardown(hw); 3762306a36Sopenharmony_ci return -ENOMEM; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci eqs[i] = eq; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* Create one MQ */ 4362306a36Sopenharmony_ci if (!i) { 4462306a36Sopenharmony_ci cq = efct_hw_new_cq(eq, 4562306a36Sopenharmony_ci hw->num_qentries[SLI4_QTYPE_CQ]); 4662306a36Sopenharmony_ci if (!cq) { 4762306a36Sopenharmony_ci efct_hw_queue_teardown(hw); 4862306a36Sopenharmony_ci return -ENOMEM; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci mq = efct_hw_new_mq(cq, EFCT_HW_MQ_DEPTH); 5262306a36Sopenharmony_ci if (!mq) { 5362306a36Sopenharmony_ci efct_hw_queue_teardown(hw); 5462306a36Sopenharmony_ci return -ENOMEM; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Create WQ */ 5962306a36Sopenharmony_ci cq = efct_hw_new_cq(eq, hw->num_qentries[SLI4_QTYPE_CQ]); 6062306a36Sopenharmony_ci if (!cq) { 6162306a36Sopenharmony_ci efct_hw_queue_teardown(hw); 6262306a36Sopenharmony_ci return -ENOMEM; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci wq = efct_hw_new_wq(cq, hw->num_qentries[SLI4_QTYPE_WQ]); 6662306a36Sopenharmony_ci if (!wq) { 6762306a36Sopenharmony_ci efct_hw_queue_teardown(hw); 6862306a36Sopenharmony_ci return -ENOMEM; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* Create CQ set */ 7362306a36Sopenharmony_ci if (efct_hw_new_cq_set(eqs, cqs, i, hw->num_qentries[SLI4_QTYPE_CQ])) { 7462306a36Sopenharmony_ci efct_hw_queue_teardown(hw); 7562306a36Sopenharmony_ci return -EIO; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Create RQ set */ 7962306a36Sopenharmony_ci if (efct_hw_new_rq_set(cqs, rqs, i, EFCT_HW_RQ_ENTRIES_DEF)) { 8062306a36Sopenharmony_ci efct_hw_queue_teardown(hw); 8162306a36Sopenharmony_ci return -EIO; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci for (j = 0; j < i ; j++) { 8562306a36Sopenharmony_ci rqs[j]->filter_mask = 0; 8662306a36Sopenharmony_ci rqs[j]->is_mrq = true; 8762306a36Sopenharmony_ci rqs[j]->base_mrq_id = rqs[0]->hdr->id; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci hw->hw_mrq_count = i; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciint 9662306a36Sopenharmony_ciefct_hw_map_wq_cpu(struct efct_hw *hw) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct efct *efct = hw->os; 9962306a36Sopenharmony_ci u32 cpu = 0, i; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Init cpu_map array */ 10262306a36Sopenharmony_ci hw->wq_cpu_array = kcalloc(num_possible_cpus(), sizeof(void *), 10362306a36Sopenharmony_ci GFP_KERNEL); 10462306a36Sopenharmony_ci if (!hw->wq_cpu_array) 10562306a36Sopenharmony_ci return -ENOMEM; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci for (i = 0; i < hw->config.n_eq; i++) { 10862306a36Sopenharmony_ci const struct cpumask *maskp; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Get a CPU mask for all CPUs affinitized to this vector */ 11162306a36Sopenharmony_ci maskp = pci_irq_get_affinity(efct->pci, i); 11262306a36Sopenharmony_ci if (!maskp) { 11362306a36Sopenharmony_ci efc_log_debug(efct, "maskp null for vector:%d\n", i); 11462306a36Sopenharmony_ci continue; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Loop through all CPUs associated with vector idx */ 11862306a36Sopenharmony_ci for_each_cpu_and(cpu, maskp, cpu_present_mask) { 11962306a36Sopenharmony_ci efc_log_debug(efct, "CPU:%d irq vector:%d\n", cpu, i); 12062306a36Sopenharmony_ci hw->wq_cpu_array[cpu] = hw->hw_wq[i]; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct hw_eq * 12862306a36Sopenharmony_ciefct_hw_new_eq(struct efct_hw *hw, u32 entry_count) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct hw_eq *eq = kzalloc(sizeof(*eq), GFP_KERNEL); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (!eq) 13362306a36Sopenharmony_ci return NULL; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci eq->type = SLI4_QTYPE_EQ; 13662306a36Sopenharmony_ci eq->hw = hw; 13762306a36Sopenharmony_ci eq->entry_count = entry_count; 13862306a36Sopenharmony_ci eq->instance = hw->eq_count++; 13962306a36Sopenharmony_ci eq->queue = &hw->eq[eq->instance]; 14062306a36Sopenharmony_ci INIT_LIST_HEAD(&eq->cq_list); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_EQ, eq->queue, entry_count, 14362306a36Sopenharmony_ci NULL)) { 14462306a36Sopenharmony_ci efc_log_err(hw->os, "EQ[%d] alloc failure\n", eq->instance); 14562306a36Sopenharmony_ci kfree(eq); 14662306a36Sopenharmony_ci return NULL; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci sli_eq_modify_delay(&hw->sli, eq->queue, 1, 0, 8); 15062306a36Sopenharmony_ci hw->hw_eq[eq->instance] = eq; 15162306a36Sopenharmony_ci INIT_LIST_HEAD(&eq->list_entry); 15262306a36Sopenharmony_ci list_add_tail(&eq->list_entry, &hw->eq_list); 15362306a36Sopenharmony_ci efc_log_debug(hw->os, "create eq[%2d] id %3d len %4d\n", eq->instance, 15462306a36Sopenharmony_ci eq->queue->id, eq->entry_count); 15562306a36Sopenharmony_ci return eq; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistruct hw_cq * 15962306a36Sopenharmony_ciefct_hw_new_cq(struct hw_eq *eq, u32 entry_count) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct efct_hw *hw = eq->hw; 16262306a36Sopenharmony_ci struct hw_cq *cq = kzalloc(sizeof(*cq), GFP_KERNEL); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!cq) 16562306a36Sopenharmony_ci return NULL; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci cq->eq = eq; 16862306a36Sopenharmony_ci cq->type = SLI4_QTYPE_CQ; 16962306a36Sopenharmony_ci cq->instance = eq->hw->cq_count++; 17062306a36Sopenharmony_ci cq->entry_count = entry_count; 17162306a36Sopenharmony_ci cq->queue = &hw->cq[cq->instance]; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci INIT_LIST_HEAD(&cq->q_list); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_CQ, cq->queue, 17662306a36Sopenharmony_ci cq->entry_count, eq->queue)) { 17762306a36Sopenharmony_ci efc_log_err(hw->os, "CQ[%d] allocation failure len=%d\n", 17862306a36Sopenharmony_ci eq->instance, eq->entry_count); 17962306a36Sopenharmony_ci kfree(cq); 18062306a36Sopenharmony_ci return NULL; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci hw->hw_cq[cq->instance] = cq; 18462306a36Sopenharmony_ci INIT_LIST_HEAD(&cq->list_entry); 18562306a36Sopenharmony_ci list_add_tail(&cq->list_entry, &eq->cq_list); 18662306a36Sopenharmony_ci efc_log_debug(hw->os, "create cq[%2d] id %3d len %4d\n", cq->instance, 18762306a36Sopenharmony_ci cq->queue->id, cq->entry_count); 18862306a36Sopenharmony_ci return cq; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ciu32 19262306a36Sopenharmony_ciefct_hw_new_cq_set(struct hw_eq *eqs[], struct hw_cq *cqs[], 19362306a36Sopenharmony_ci u32 num_cqs, u32 entry_count) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci u32 i; 19662306a36Sopenharmony_ci struct efct_hw *hw = eqs[0]->hw; 19762306a36Sopenharmony_ci struct sli4 *sli4 = &hw->sli; 19862306a36Sopenharmony_ci struct hw_cq *cq = NULL; 19962306a36Sopenharmony_ci struct sli4_queue *qs[SLI4_MAX_CQ_SET_COUNT]; 20062306a36Sopenharmony_ci struct sli4_queue *assefct[SLI4_MAX_CQ_SET_COUNT]; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Initialise CQS pointers to NULL */ 20362306a36Sopenharmony_ci for (i = 0; i < num_cqs; i++) 20462306a36Sopenharmony_ci cqs[i] = NULL; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci for (i = 0; i < num_cqs; i++) { 20762306a36Sopenharmony_ci cq = kzalloc(sizeof(*cq), GFP_KERNEL); 20862306a36Sopenharmony_ci if (!cq) 20962306a36Sopenharmony_ci goto error; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci cqs[i] = cq; 21262306a36Sopenharmony_ci cq->eq = eqs[i]; 21362306a36Sopenharmony_ci cq->type = SLI4_QTYPE_CQ; 21462306a36Sopenharmony_ci cq->instance = hw->cq_count++; 21562306a36Sopenharmony_ci cq->entry_count = entry_count; 21662306a36Sopenharmony_ci cq->queue = &hw->cq[cq->instance]; 21762306a36Sopenharmony_ci qs[i] = cq->queue; 21862306a36Sopenharmony_ci assefct[i] = eqs[i]->queue; 21962306a36Sopenharmony_ci INIT_LIST_HEAD(&cq->q_list); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (sli_cq_alloc_set(sli4, qs, num_cqs, entry_count, assefct)) { 22362306a36Sopenharmony_ci efc_log_err(hw->os, "Failed to create CQ Set.\n"); 22462306a36Sopenharmony_ci goto error; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci for (i = 0; i < num_cqs; i++) { 22862306a36Sopenharmony_ci hw->hw_cq[cqs[i]->instance] = cqs[i]; 22962306a36Sopenharmony_ci INIT_LIST_HEAD(&cqs[i]->list_entry); 23062306a36Sopenharmony_ci list_add_tail(&cqs[i]->list_entry, &cqs[i]->eq->cq_list); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cierror: 23662306a36Sopenharmony_ci for (i = 0; i < num_cqs; i++) { 23762306a36Sopenharmony_ci kfree(cqs[i]); 23862306a36Sopenharmony_ci cqs[i] = NULL; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci return -EIO; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistruct hw_mq * 24462306a36Sopenharmony_ciefct_hw_new_mq(struct hw_cq *cq, u32 entry_count) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct efct_hw *hw = cq->eq->hw; 24762306a36Sopenharmony_ci struct hw_mq *mq = kzalloc(sizeof(*mq), GFP_KERNEL); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!mq) 25062306a36Sopenharmony_ci return NULL; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci mq->cq = cq; 25362306a36Sopenharmony_ci mq->type = SLI4_QTYPE_MQ; 25462306a36Sopenharmony_ci mq->instance = cq->eq->hw->mq_count++; 25562306a36Sopenharmony_ci mq->entry_count = entry_count; 25662306a36Sopenharmony_ci mq->entry_size = EFCT_HW_MQ_DEPTH; 25762306a36Sopenharmony_ci mq->queue = &hw->mq[mq->instance]; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_MQ, mq->queue, mq->entry_size, 26062306a36Sopenharmony_ci cq->queue)) { 26162306a36Sopenharmony_ci efc_log_err(hw->os, "MQ allocation failure\n"); 26262306a36Sopenharmony_ci kfree(mq); 26362306a36Sopenharmony_ci return NULL; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci hw->hw_mq[mq->instance] = mq; 26762306a36Sopenharmony_ci INIT_LIST_HEAD(&mq->list_entry); 26862306a36Sopenharmony_ci list_add_tail(&mq->list_entry, &cq->q_list); 26962306a36Sopenharmony_ci efc_log_debug(hw->os, "create mq[%2d] id %3d len %4d\n", mq->instance, 27062306a36Sopenharmony_ci mq->queue->id, mq->entry_count); 27162306a36Sopenharmony_ci return mq; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistruct hw_wq * 27562306a36Sopenharmony_ciefct_hw_new_wq(struct hw_cq *cq, u32 entry_count) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct efct_hw *hw = cq->eq->hw; 27862306a36Sopenharmony_ci struct hw_wq *wq = kzalloc(sizeof(*wq), GFP_KERNEL); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (!wq) 28162306a36Sopenharmony_ci return NULL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci wq->hw = cq->eq->hw; 28462306a36Sopenharmony_ci wq->cq = cq; 28562306a36Sopenharmony_ci wq->type = SLI4_QTYPE_WQ; 28662306a36Sopenharmony_ci wq->instance = cq->eq->hw->wq_count++; 28762306a36Sopenharmony_ci wq->entry_count = entry_count; 28862306a36Sopenharmony_ci wq->queue = &hw->wq[wq->instance]; 28962306a36Sopenharmony_ci wq->wqec_set_count = EFCT_HW_WQEC_SET_COUNT; 29062306a36Sopenharmony_ci wq->wqec_count = wq->wqec_set_count; 29162306a36Sopenharmony_ci wq->free_count = wq->entry_count - 1; 29262306a36Sopenharmony_ci INIT_LIST_HEAD(&wq->pending_list); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_WQ, wq->queue, 29562306a36Sopenharmony_ci wq->entry_count, cq->queue)) { 29662306a36Sopenharmony_ci efc_log_err(hw->os, "WQ allocation failure\n"); 29762306a36Sopenharmony_ci kfree(wq); 29862306a36Sopenharmony_ci return NULL; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci hw->hw_wq[wq->instance] = wq; 30262306a36Sopenharmony_ci INIT_LIST_HEAD(&wq->list_entry); 30362306a36Sopenharmony_ci list_add_tail(&wq->list_entry, &cq->q_list); 30462306a36Sopenharmony_ci efc_log_debug(hw->os, "create wq[%2d] id %3d len %4d cls %d\n", 30562306a36Sopenharmony_ci wq->instance, wq->queue->id, wq->entry_count, wq->class); 30662306a36Sopenharmony_ci return wq; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ciu32 31062306a36Sopenharmony_ciefct_hw_new_rq_set(struct hw_cq *cqs[], struct hw_rq *rqs[], 31162306a36Sopenharmony_ci u32 num_rq_pairs, u32 entry_count) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct efct_hw *hw = cqs[0]->eq->hw; 31462306a36Sopenharmony_ci struct hw_rq *rq = NULL; 31562306a36Sopenharmony_ci struct sli4_queue *qs[SLI4_MAX_RQ_SET_COUNT * 2] = { NULL }; 31662306a36Sopenharmony_ci u32 i, q_count, size; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Initialise RQS pointers */ 31962306a36Sopenharmony_ci for (i = 0; i < num_rq_pairs; i++) 32062306a36Sopenharmony_ci rqs[i] = NULL; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* 32362306a36Sopenharmony_ci * Allocate an RQ object SET, where each element in set 32462306a36Sopenharmony_ci * encapsulates 2 SLI queues (for rq pair) 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci for (i = 0, q_count = 0; i < num_rq_pairs; i++, q_count += 2) { 32762306a36Sopenharmony_ci rq = kzalloc(sizeof(*rq), GFP_KERNEL); 32862306a36Sopenharmony_ci if (!rq) 32962306a36Sopenharmony_ci goto error; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci rqs[i] = rq; 33262306a36Sopenharmony_ci rq->instance = hw->hw_rq_count++; 33362306a36Sopenharmony_ci rq->cq = cqs[i]; 33462306a36Sopenharmony_ci rq->type = SLI4_QTYPE_RQ; 33562306a36Sopenharmony_ci rq->entry_count = entry_count; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Header RQ */ 33862306a36Sopenharmony_ci rq->hdr = &hw->rq[hw->rq_count]; 33962306a36Sopenharmony_ci rq->hdr_entry_size = EFCT_HW_RQ_HEADER_SIZE; 34062306a36Sopenharmony_ci hw->hw_rq_lookup[hw->rq_count] = rq->instance; 34162306a36Sopenharmony_ci hw->rq_count++; 34262306a36Sopenharmony_ci qs[q_count] = rq->hdr; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Data RQ */ 34562306a36Sopenharmony_ci rq->data = &hw->rq[hw->rq_count]; 34662306a36Sopenharmony_ci rq->data_entry_size = hw->config.rq_default_buffer_size; 34762306a36Sopenharmony_ci hw->hw_rq_lookup[hw->rq_count] = rq->instance; 34862306a36Sopenharmony_ci hw->rq_count++; 34962306a36Sopenharmony_ci qs[q_count + 1] = rq->data; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci rq->rq_tracker = NULL; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (sli_fc_rq_set_alloc(&hw->sli, num_rq_pairs, qs, 35562306a36Sopenharmony_ci cqs[0]->queue->id, 35662306a36Sopenharmony_ci rqs[0]->entry_count, 35762306a36Sopenharmony_ci rqs[0]->hdr_entry_size, 35862306a36Sopenharmony_ci rqs[0]->data_entry_size)) { 35962306a36Sopenharmony_ci efc_log_err(hw->os, "RQ Set alloc failure for base CQ=%d\n", 36062306a36Sopenharmony_ci cqs[0]->queue->id); 36162306a36Sopenharmony_ci goto error; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci for (i = 0; i < num_rq_pairs; i++) { 36562306a36Sopenharmony_ci hw->hw_rq[rqs[i]->instance] = rqs[i]; 36662306a36Sopenharmony_ci INIT_LIST_HEAD(&rqs[i]->list_entry); 36762306a36Sopenharmony_ci list_add_tail(&rqs[i]->list_entry, &cqs[i]->q_list); 36862306a36Sopenharmony_ci size = sizeof(struct efc_hw_sequence *) * rqs[i]->entry_count; 36962306a36Sopenharmony_ci rqs[i]->rq_tracker = kzalloc(size, GFP_KERNEL); 37062306a36Sopenharmony_ci if (!rqs[i]->rq_tracker) 37162306a36Sopenharmony_ci goto error; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cierror: 37762306a36Sopenharmony_ci for (i = 0; i < num_rq_pairs; i++) { 37862306a36Sopenharmony_ci if (rqs[i]) { 37962306a36Sopenharmony_ci kfree(rqs[i]->rq_tracker); 38062306a36Sopenharmony_ci kfree(rqs[i]); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return -EIO; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_civoid 38862306a36Sopenharmony_ciefct_hw_del_eq(struct hw_eq *eq) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct hw_cq *cq; 39162306a36Sopenharmony_ci struct hw_cq *cq_next; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (!eq) 39462306a36Sopenharmony_ci return; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci list_for_each_entry_safe(cq, cq_next, &eq->cq_list, list_entry) 39762306a36Sopenharmony_ci efct_hw_del_cq(cq); 39862306a36Sopenharmony_ci list_del(&eq->list_entry); 39962306a36Sopenharmony_ci eq->hw->hw_eq[eq->instance] = NULL; 40062306a36Sopenharmony_ci kfree(eq); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_civoid 40462306a36Sopenharmony_ciefct_hw_del_cq(struct hw_cq *cq) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct hw_q *q; 40762306a36Sopenharmony_ci struct hw_q *q_next; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (!cq) 41062306a36Sopenharmony_ci return; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci list_for_each_entry_safe(q, q_next, &cq->q_list, list_entry) { 41362306a36Sopenharmony_ci switch (q->type) { 41462306a36Sopenharmony_ci case SLI4_QTYPE_MQ: 41562306a36Sopenharmony_ci efct_hw_del_mq((struct hw_mq *)q); 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci case SLI4_QTYPE_WQ: 41862306a36Sopenharmony_ci efct_hw_del_wq((struct hw_wq *)q); 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci case SLI4_QTYPE_RQ: 42162306a36Sopenharmony_ci efct_hw_del_rq((struct hw_rq *)q); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci default: 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci list_del(&cq->list_entry); 42862306a36Sopenharmony_ci cq->eq->hw->hw_cq[cq->instance] = NULL; 42962306a36Sopenharmony_ci kfree(cq); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_civoid 43362306a36Sopenharmony_ciefct_hw_del_mq(struct hw_mq *mq) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci if (!mq) 43662306a36Sopenharmony_ci return; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci list_del(&mq->list_entry); 43962306a36Sopenharmony_ci mq->cq->eq->hw->hw_mq[mq->instance] = NULL; 44062306a36Sopenharmony_ci kfree(mq); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_civoid 44462306a36Sopenharmony_ciefct_hw_del_wq(struct hw_wq *wq) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci if (!wq) 44762306a36Sopenharmony_ci return; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci list_del(&wq->list_entry); 45062306a36Sopenharmony_ci wq->cq->eq->hw->hw_wq[wq->instance] = NULL; 45162306a36Sopenharmony_ci kfree(wq); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_civoid 45562306a36Sopenharmony_ciefct_hw_del_rq(struct hw_rq *rq) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct efct_hw *hw = NULL; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (!rq) 46062306a36Sopenharmony_ci return; 46162306a36Sopenharmony_ci /* Free RQ tracker */ 46262306a36Sopenharmony_ci kfree(rq->rq_tracker); 46362306a36Sopenharmony_ci rq->rq_tracker = NULL; 46462306a36Sopenharmony_ci list_del(&rq->list_entry); 46562306a36Sopenharmony_ci hw = rq->cq->eq->hw; 46662306a36Sopenharmony_ci hw->hw_rq[rq->instance] = NULL; 46762306a36Sopenharmony_ci kfree(rq); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_civoid 47162306a36Sopenharmony_ciefct_hw_queue_teardown(struct efct_hw *hw) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct hw_eq *eq; 47462306a36Sopenharmony_ci struct hw_eq *eq_next; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (!hw->eq_list.next) 47762306a36Sopenharmony_ci return; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci list_for_each_entry_safe(eq, eq_next, &hw->eq_list, list_entry) 48062306a36Sopenharmony_ci efct_hw_del_eq(eq); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic inline int 48462306a36Sopenharmony_ciefct_hw_rqpair_find(struct efct_hw *hw, u16 rq_id) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci return efct_hw_queue_hash_find(hw->rq_hash, rq_id); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic struct efc_hw_sequence * 49062306a36Sopenharmony_ciefct_hw_rqpair_get(struct efct_hw *hw, u16 rqindex, u16 bufindex) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct sli4_queue *rq_hdr = &hw->rq[rqindex]; 49362306a36Sopenharmony_ci struct efc_hw_sequence *seq = NULL; 49462306a36Sopenharmony_ci struct hw_rq *rq = hw->hw_rq[hw->hw_rq_lookup[rqindex]]; 49562306a36Sopenharmony_ci unsigned long flags = 0; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (bufindex >= rq_hdr->length) { 49862306a36Sopenharmony_ci efc_log_err(hw->os, 49962306a36Sopenharmony_ci "RQidx %d bufidx %d exceed ring len %d for id %d\n", 50062306a36Sopenharmony_ci rqindex, bufindex, rq_hdr->length, rq_hdr->id); 50162306a36Sopenharmony_ci return NULL; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* rq_hdr lock also covers rqindex+1 queue */ 50562306a36Sopenharmony_ci spin_lock_irqsave(&rq_hdr->lock, flags); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci seq = rq->rq_tracker[bufindex]; 50862306a36Sopenharmony_ci rq->rq_tracker[bufindex] = NULL; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (!seq) { 51162306a36Sopenharmony_ci efc_log_err(hw->os, 51262306a36Sopenharmony_ci "RQbuf NULL, rqidx %d, bufidx %d, cur q idx = %d\n", 51362306a36Sopenharmony_ci rqindex, bufindex, rq_hdr->index); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci spin_unlock_irqrestore(&rq_hdr->lock, flags); 51762306a36Sopenharmony_ci return seq; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ciint 52162306a36Sopenharmony_ciefct_hw_rqpair_process_rq(struct efct_hw *hw, struct hw_cq *cq, 52262306a36Sopenharmony_ci u8 *cqe) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci u16 rq_id; 52562306a36Sopenharmony_ci u32 index; 52662306a36Sopenharmony_ci int rqindex; 52762306a36Sopenharmony_ci int rq_status; 52862306a36Sopenharmony_ci u32 h_len; 52962306a36Sopenharmony_ci u32 p_len; 53062306a36Sopenharmony_ci struct efc_hw_sequence *seq; 53162306a36Sopenharmony_ci struct hw_rq *rq; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci rq_status = sli_fc_rqe_rqid_and_index(&hw->sli, cqe, 53462306a36Sopenharmony_ci &rq_id, &index); 53562306a36Sopenharmony_ci if (rq_status != 0) { 53662306a36Sopenharmony_ci switch (rq_status) { 53762306a36Sopenharmony_ci case SLI4_FC_ASYNC_RQ_BUF_LEN_EXCEEDED: 53862306a36Sopenharmony_ci case SLI4_FC_ASYNC_RQ_DMA_FAILURE: 53962306a36Sopenharmony_ci /* just get RQ buffer then return to chip */ 54062306a36Sopenharmony_ci rqindex = efct_hw_rqpair_find(hw, rq_id); 54162306a36Sopenharmony_ci if (rqindex < 0) { 54262306a36Sopenharmony_ci efc_log_debug(hw->os, 54362306a36Sopenharmony_ci "status=%#x: lookup fail id=%#x\n", 54462306a36Sopenharmony_ci rq_status, rq_id); 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* get RQ buffer */ 54962306a36Sopenharmony_ci seq = efct_hw_rqpair_get(hw, rqindex, index); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* return to chip */ 55262306a36Sopenharmony_ci if (efct_hw_rqpair_sequence_free(hw, seq)) { 55362306a36Sopenharmony_ci efc_log_debug(hw->os, 55462306a36Sopenharmony_ci "status=%#x,fail rtrn buf to RQ\n", 55562306a36Sopenharmony_ci rq_status); 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci case SLI4_FC_ASYNC_RQ_INSUFF_BUF_NEEDED: 56062306a36Sopenharmony_ci case SLI4_FC_ASYNC_RQ_INSUFF_BUF_FRM_DISC: 56162306a36Sopenharmony_ci /* 56262306a36Sopenharmony_ci * since RQ buffers were not consumed, cannot return 56362306a36Sopenharmony_ci * them to chip 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci efc_log_debug(hw->os, "Warning: RCQE status=%#x,\n", 56662306a36Sopenharmony_ci rq_status); 56762306a36Sopenharmony_ci fallthrough; 56862306a36Sopenharmony_ci default: 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci return -EIO; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci rqindex = efct_hw_rqpair_find(hw, rq_id); 57562306a36Sopenharmony_ci if (rqindex < 0) { 57662306a36Sopenharmony_ci efc_log_debug(hw->os, "Error: rq_id lookup failed for id=%#x\n", 57762306a36Sopenharmony_ci rq_id); 57862306a36Sopenharmony_ci return -EIO; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci rq = hw->hw_rq[hw->hw_rq_lookup[rqindex]]; 58262306a36Sopenharmony_ci rq->use_count++; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci seq = efct_hw_rqpair_get(hw, rqindex, index); 58562306a36Sopenharmony_ci if (WARN_ON(!seq)) 58662306a36Sopenharmony_ci return -EIO; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci seq->hw = hw; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci sli_fc_rqe_length(&hw->sli, cqe, &h_len, &p_len); 59162306a36Sopenharmony_ci seq->header->dma.len = h_len; 59262306a36Sopenharmony_ci seq->payload->dma.len = p_len; 59362306a36Sopenharmony_ci seq->fcfi = sli_fc_rqe_fcfi(&hw->sli, cqe); 59462306a36Sopenharmony_ci seq->hw_priv = cq->eq; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci efct_unsolicited_cb(hw->os, seq); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int 60262306a36Sopenharmony_ciefct_hw_rqpair_put(struct efct_hw *hw, struct efc_hw_sequence *seq) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct sli4_queue *rq_hdr = &hw->rq[seq->header->rqindex]; 60562306a36Sopenharmony_ci struct sli4_queue *rq_payload = &hw->rq[seq->payload->rqindex]; 60662306a36Sopenharmony_ci u32 hw_rq_index = hw->hw_rq_lookup[seq->header->rqindex]; 60762306a36Sopenharmony_ci struct hw_rq *rq = hw->hw_rq[hw_rq_index]; 60862306a36Sopenharmony_ci u32 phys_hdr[2]; 60962306a36Sopenharmony_ci u32 phys_payload[2]; 61062306a36Sopenharmony_ci int qindex_hdr; 61162306a36Sopenharmony_ci int qindex_payload; 61262306a36Sopenharmony_ci unsigned long flags = 0; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* Update the RQ verification lookup tables */ 61562306a36Sopenharmony_ci phys_hdr[0] = upper_32_bits(seq->header->dma.phys); 61662306a36Sopenharmony_ci phys_hdr[1] = lower_32_bits(seq->header->dma.phys); 61762306a36Sopenharmony_ci phys_payload[0] = upper_32_bits(seq->payload->dma.phys); 61862306a36Sopenharmony_ci phys_payload[1] = lower_32_bits(seq->payload->dma.phys); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* rq_hdr lock also covers payload / header->rqindex+1 queue */ 62162306a36Sopenharmony_ci spin_lock_irqsave(&rq_hdr->lock, flags); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * Note: The header must be posted last for buffer pair mode because 62562306a36Sopenharmony_ci * posting on the header queue posts the payload queue as well. 62662306a36Sopenharmony_ci * We do not ring the payload queue independently in RQ pair mode. 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_ci qindex_payload = sli_rq_write(&hw->sli, rq_payload, 62962306a36Sopenharmony_ci (void *)phys_payload); 63062306a36Sopenharmony_ci qindex_hdr = sli_rq_write(&hw->sli, rq_hdr, (void *)phys_hdr); 63162306a36Sopenharmony_ci if (qindex_hdr < 0 || 63262306a36Sopenharmony_ci qindex_payload < 0) { 63362306a36Sopenharmony_ci efc_log_err(hw->os, "RQ_ID=%#x write failed\n", rq_hdr->id); 63462306a36Sopenharmony_ci spin_unlock_irqrestore(&rq_hdr->lock, flags); 63562306a36Sopenharmony_ci return -EIO; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* ensure the indexes are the same */ 63962306a36Sopenharmony_ci WARN_ON(qindex_hdr != qindex_payload); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* Update the lookup table */ 64262306a36Sopenharmony_ci if (!rq->rq_tracker[qindex_hdr]) { 64362306a36Sopenharmony_ci rq->rq_tracker[qindex_hdr] = seq; 64462306a36Sopenharmony_ci } else { 64562306a36Sopenharmony_ci efc_log_debug(hw->os, 64662306a36Sopenharmony_ci "expected rq_tracker[%d][%d] buffer to be NULL\n", 64762306a36Sopenharmony_ci hw_rq_index, qindex_hdr); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci spin_unlock_irqrestore(&rq_hdr->lock, flags); 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ciint 65562306a36Sopenharmony_ciefct_hw_rqpair_sequence_free(struct efct_hw *hw, struct efc_hw_sequence *seq) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci int rc = 0; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* 66062306a36Sopenharmony_ci * Post the data buffer first. Because in RQ pair mode, ringing the 66162306a36Sopenharmony_ci * doorbell of the header ring will post the data buffer as well. 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci if (efct_hw_rqpair_put(hw, seq)) { 66462306a36Sopenharmony_ci efc_log_err(hw->os, "error writing buffers\n"); 66562306a36Sopenharmony_ci return -EIO; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return rc; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ciint 67262306a36Sopenharmony_ciefct_efc_hw_sequence_free(struct efc *efc, struct efc_hw_sequence *seq) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct efct *efct = efc->base; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return efct_hw_rqpair_sequence_free(&efct->hw, seq); 67762306a36Sopenharmony_ci} 678