brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · 9d887bf Raw
297 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell RVU Physical Function ethernet driver3 *4 * Copyright (C) 2023 Marvell.5 *6 */7 8#include <linux/netdevice.h>9#include <net/tso.h>10 11#include "cn10k.h"12#include "otx2_reg.h"13#include "otx2_common.h"14#include "otx2_txrx.h"15#include "otx2_struct.h"16 17#define OTX2_QOS_MAX_LEAF_NODES 1618 19static void otx2_qos_aura_pool_free(struct otx2_nic *pfvf, int pool_id)20{21	struct otx2_pool *pool;22 23	if (!pfvf->qset.pool)24		return;25 26	pool = &pfvf->qset.pool[pool_id];27	qmem_free(pfvf->dev, pool->stack);28	qmem_free(pfvf->dev, pool->fc_addr);29	pool->stack = NULL;30	pool->fc_addr = NULL;31}32 33static int otx2_qos_sq_aura_pool_init(struct otx2_nic *pfvf, int qidx)34{35	struct otx2_qset *qset = &pfvf->qset;36	int pool_id, stack_pages, num_sqbs;37	struct otx2_hw *hw = &pfvf->hw;38	struct otx2_snd_queue *sq;39	struct otx2_pool *pool;40	dma_addr_t bufptr;41	int err, ptr;42	u64 iova, pa;43 44	/* Calculate number of SQBs needed.45	 *46	 * For a 128byte SQE, and 4K size SQB, 31 SQEs will fit in one SQB.47	 * Last SQE is used for pointing to next SQB.48	 */49	num_sqbs = (hw->sqb_size / 128) - 1;50	num_sqbs = (qset->sqe_cnt + num_sqbs) / num_sqbs;51 52	/* Get no of stack pages needed */53	stack_pages =54		(num_sqbs + hw->stack_pg_ptrs - 1) / hw->stack_pg_ptrs;55 56	pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, qidx);57	pool = &pfvf->qset.pool[pool_id];58 59	/* Initialize aura context */60	err = otx2_aura_init(pfvf, pool_id, pool_id, num_sqbs);61	if (err)62		return err;63 64	/* Initialize pool context */65	err = otx2_pool_init(pfvf, pool_id, stack_pages,66			     num_sqbs, hw->sqb_size, AURA_NIX_SQ);67	if (err)68		goto aura_free;69 70	/* Flush accumulated messages */71	err = otx2_sync_mbox_msg(&pfvf->mbox);72	if (err)73		goto pool_free;74 75	/* Allocate pointers and free them to aura/pool */76	sq = &qset->sq[qidx];77	sq->sqb_count = 0;78	sq->sqb_ptrs = kcalloc(num_sqbs, sizeof(*sq->sqb_ptrs), GFP_KERNEL);79	if (!sq->sqb_ptrs) {80		err = -ENOMEM;81		goto pool_free;82	}83 84	for (ptr = 0; ptr < num_sqbs; ptr++) {85		err = otx2_alloc_rbuf(pfvf, pool, &bufptr);86		if (err)87			goto sqb_free;88		pfvf->hw_ops->aura_freeptr(pfvf, pool_id, bufptr);89		sq->sqb_ptrs[sq->sqb_count++] = (u64)bufptr;90	}91 92	return 0;93 94sqb_free:95	while (ptr--) {96		if (!sq->sqb_ptrs[ptr])97			continue;98		iova = sq->sqb_ptrs[ptr];99		pa = otx2_iova_to_phys(pfvf->iommu_domain, iova);100		dma_unmap_page_attrs(pfvf->dev, iova, hw->sqb_size,101				     DMA_FROM_DEVICE,102				     DMA_ATTR_SKIP_CPU_SYNC);103		put_page(virt_to_page(phys_to_virt(pa)));104		otx2_aura_allocptr(pfvf, pool_id);105	}106	sq->sqb_count = 0;107	kfree(sq->sqb_ptrs);108pool_free:109	qmem_free(pfvf->dev, pool->stack);110aura_free:111	qmem_free(pfvf->dev, pool->fc_addr);112	otx2_mbox_reset(&pfvf->mbox.mbox, 0);113	return err;114}115 116static void otx2_qos_sq_free_sqbs(struct otx2_nic *pfvf, int qidx)117{118	struct otx2_qset *qset = &pfvf->qset;119	struct otx2_hw *hw = &pfvf->hw;120	struct otx2_snd_queue *sq;121	u64 iova, pa;122	int sqb;123 124	sq = &qset->sq[qidx];125	if (!sq->sqb_ptrs)126		return;127	for (sqb = 0; sqb < sq->sqb_count; sqb++) {128		if (!sq->sqb_ptrs[sqb])129			continue;130		iova = sq->sqb_ptrs[sqb];131		pa = otx2_iova_to_phys(pfvf->iommu_domain, iova);132		dma_unmap_page_attrs(pfvf->dev, iova, hw->sqb_size,133				     DMA_FROM_DEVICE,134				     DMA_ATTR_SKIP_CPU_SYNC);135		put_page(virt_to_page(phys_to_virt(pa)));136	}137 138	sq->sqb_count = 0;139 140	sq = &qset->sq[qidx];141	qmem_free(pfvf->dev, sq->sqe);142	qmem_free(pfvf->dev, sq->tso_hdrs);143	kfree(sq->sg);144	kfree(sq->sqb_ptrs);145	qmem_free(pfvf->dev, sq->timestamps);146 147	memset((void *)sq, 0, sizeof(*sq));148}149 150/* send queue id */151static void otx2_qos_sqb_flush(struct otx2_nic *pfvf, int qidx)152{153	int sqe_tail, sqe_head;154	u64 incr, *ptr, val;155 156	ptr = (__force u64 *)otx2_get_regaddr(pfvf, NIX_LF_SQ_OP_STATUS);157	incr = (u64)qidx << 32;158	val = otx2_atomic64_add(incr, ptr);159	sqe_head = (val >> 20) & 0x3F;160	sqe_tail = (val >> 28) & 0x3F;161	if (sqe_head != sqe_tail)162		usleep_range(50, 60);163}164 165static int otx2_qos_ctx_disable(struct otx2_nic *pfvf, u16 qidx, int aura_id)166{167	struct nix_cn10k_aq_enq_req *cn10k_sq_aq;168	struct npa_aq_enq_req *aura_aq;169	struct npa_aq_enq_req *pool_aq;170	struct nix_aq_enq_req *sq_aq;171 172	if (test_bit(CN10K_LMTST, &pfvf->hw.cap_flag)) {173		cn10k_sq_aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox);174		if (!cn10k_sq_aq)175			return -ENOMEM;176		cn10k_sq_aq->qidx = qidx;177		cn10k_sq_aq->sq.ena = 0;178		cn10k_sq_aq->sq_mask.ena = 1;179		cn10k_sq_aq->ctype = NIX_AQ_CTYPE_SQ;180		cn10k_sq_aq->op = NIX_AQ_INSTOP_WRITE;181	} else {182		sq_aq = otx2_mbox_alloc_msg_nix_aq_enq(&pfvf->mbox);183		if (!sq_aq)184			return -ENOMEM;185		sq_aq->qidx = qidx;186		sq_aq->sq.ena = 0;187		sq_aq->sq_mask.ena = 1;188		sq_aq->ctype = NIX_AQ_CTYPE_SQ;189		sq_aq->op = NIX_AQ_INSTOP_WRITE;190	}191 192	aura_aq = otx2_mbox_alloc_msg_npa_aq_enq(&pfvf->mbox);193	if (!aura_aq) {194		otx2_mbox_reset(&pfvf->mbox.mbox, 0);195		return -ENOMEM;196	}197 198	aura_aq->aura_id = aura_id;199	aura_aq->aura.ena = 0;200	aura_aq->aura_mask.ena = 1;201	aura_aq->ctype = NPA_AQ_CTYPE_AURA;202	aura_aq->op = NPA_AQ_INSTOP_WRITE;203 204	pool_aq = otx2_mbox_alloc_msg_npa_aq_enq(&pfvf->mbox);205	if (!pool_aq) {206		otx2_mbox_reset(&pfvf->mbox.mbox, 0);207		return -ENOMEM;208	}209 210	pool_aq->aura_id = aura_id;211	pool_aq->pool.ena = 0;212	pool_aq->pool_mask.ena = 1;213 214	pool_aq->ctype = NPA_AQ_CTYPE_POOL;215	pool_aq->op = NPA_AQ_INSTOP_WRITE;216 217	return otx2_sync_mbox_msg(&pfvf->mbox);218}219 220int otx2_qos_get_qid(struct otx2_nic *pfvf)221{222	int qidx;223 224	qidx = find_first_zero_bit(pfvf->qos.qos_sq_bmap,225				   pfvf->hw.tc_tx_queues);226 227	return qidx == pfvf->hw.tc_tx_queues ? -ENOSPC : qidx;228}229 230void otx2_qos_free_qid(struct otx2_nic *pfvf, int qidx)231{232	clear_bit(qidx, pfvf->qos.qos_sq_bmap);233}234 235int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx)236{237	struct otx2_hw *hw = &pfvf->hw;238	int pool_id, sq_idx, err;239 240	if (pfvf->flags & OTX2_FLAG_INTF_DOWN)241		return -EPERM;242 243	sq_idx = hw->non_qos_queues + qidx;244 245	mutex_lock(&pfvf->mbox.lock);246	err = otx2_qos_sq_aura_pool_init(pfvf, sq_idx);247	if (err)248		goto out;249 250	pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, sq_idx);251	err = otx2_sq_init(pfvf, sq_idx, pool_id);252	if (err)253		goto out;254out:255	mutex_unlock(&pfvf->mbox.lock);256	return err;257}258 259void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx)260{261	struct otx2_qset *qset = &pfvf->qset;262	struct otx2_hw *hw = &pfvf->hw;263	struct otx2_snd_queue *sq;264	struct otx2_cq_queue *cq;265	int pool_id, sq_idx;266 267	sq_idx = hw->non_qos_queues + qidx;268 269	/* If the DOWN flag is set SQs are already freed */270	if (pfvf->flags & OTX2_FLAG_INTF_DOWN)271		return;272 273	sq = &pfvf->qset.sq[sq_idx];274	if (!sq->sqb_ptrs)275		return;276 277	if (sq_idx < hw->non_qos_queues ||278	    sq_idx >= otx2_get_total_tx_queues(pfvf)) {279		netdev_err(pfvf->netdev, "Send Queue is not a QoS queue\n");280		return;281	}282 283	cq = &qset->cq[pfvf->hw.rx_queues + sq_idx];284	pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, sq_idx);285 286	otx2_qos_sqb_flush(pfvf, sq_idx);287	otx2_smq_flush(pfvf, otx2_get_smq_idx(pfvf, sq_idx));288	otx2_cleanup_tx_cqes(pfvf, cq);289 290	mutex_lock(&pfvf->mbox.lock);291	otx2_qos_ctx_disable(pfvf, sq_idx, pool_id);292	mutex_unlock(&pfvf->mbox.lock);293 294	otx2_qos_sq_free_sqbs(pfvf, sq_idx);295	otx2_qos_aura_pool_free(pfvf, pool_id);296}297