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