18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
28c2ecf20Sopenharmony_ci/* Copyright (C) 2018 Netronome Systems, Inc. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/bitops.h>
58c2ecf20Sopenharmony_ci#include <linux/kernel.h>
68c2ecf20Sopenharmony_ci#include <linux/log2.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "../nfpcore/nfp_cpp.h"
98c2ecf20Sopenharmony_ci#include "../nfpcore/nfp_nffw.h"
108c2ecf20Sopenharmony_ci#include "../nfp_app.h"
118c2ecf20Sopenharmony_ci#include "../nfp_abi.h"
128c2ecf20Sopenharmony_ci#include "../nfp_main.h"
138c2ecf20Sopenharmony_ci#include "../nfp_net.h"
148c2ecf20Sopenharmony_ci#include "main.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define NFP_NUM_PRIOS_SYM_NAME	"_abi_pci_dscp_num_prio_%u"
178c2ecf20Sopenharmony_ci#define NFP_NUM_BANDS_SYM_NAME	"_abi_pci_dscp_num_band_%u"
188c2ecf20Sopenharmony_ci#define NFP_ACT_MASK_SYM_NAME	"_abi_nfd_out_q_actions_%u"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define NFP_RED_SUPPORT_SYM_NAME	"_abi_nfd_out_red_offload_%u"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define NFP_QLVL_SYM_NAME	"_abi_nfd_out_q_lvls_%u%s"
238c2ecf20Sopenharmony_ci#define NFP_QLVL_STRIDE		16
248c2ecf20Sopenharmony_ci#define NFP_QLVL_BLOG_BYTES	0
258c2ecf20Sopenharmony_ci#define NFP_QLVL_BLOG_PKTS	4
268c2ecf20Sopenharmony_ci#define NFP_QLVL_THRS		8
278c2ecf20Sopenharmony_ci#define NFP_QLVL_ACT		12
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define NFP_QMSTAT_SYM_NAME	"_abi_nfdqm%u_stats%s"
308c2ecf20Sopenharmony_ci#define NFP_QMSTAT_STRIDE	32
318c2ecf20Sopenharmony_ci#define NFP_QMSTAT_NON_STO	0
328c2ecf20Sopenharmony_ci#define NFP_QMSTAT_STO		8
338c2ecf20Sopenharmony_ci#define NFP_QMSTAT_DROP		16
348c2ecf20Sopenharmony_ci#define NFP_QMSTAT_ECN		24
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define NFP_Q_STAT_SYM_NAME	"_abi_nfd_rxq_stats%u%s"
378c2ecf20Sopenharmony_ci#define NFP_Q_STAT_STRIDE	16
388c2ecf20Sopenharmony_ci#define NFP_Q_STAT_PKTS		0
398c2ecf20Sopenharmony_ci#define NFP_Q_STAT_BYTES	8
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define NFP_NET_ABM_MBOX_CMD		NFP_NET_CFG_MBOX_SIMPLE_CMD
428c2ecf20Sopenharmony_ci#define NFP_NET_ABM_MBOX_RET		NFP_NET_CFG_MBOX_SIMPLE_RET
438c2ecf20Sopenharmony_ci#define NFP_NET_ABM_MBOX_DATALEN	NFP_NET_CFG_MBOX_SIMPLE_VAL
448c2ecf20Sopenharmony_ci#define NFP_NET_ABM_MBOX_RESERVED	(NFP_NET_CFG_MBOX_SIMPLE_VAL + 4)
458c2ecf20Sopenharmony_ci#define NFP_NET_ABM_MBOX_DATA		(NFP_NET_CFG_MBOX_SIMPLE_VAL + 8)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int
488c2ecf20Sopenharmony_cinfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
498c2ecf20Sopenharmony_ci		  unsigned int stride, unsigned int offset, unsigned int band,
508c2ecf20Sopenharmony_ci		  unsigned int queue, bool is_u64, u64 *res)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct nfp_cpp *cpp = alink->abm->app->cpp;
538c2ecf20Sopenharmony_ci	u64 val, sym_offset;
548c2ecf20Sopenharmony_ci	unsigned int qid;
558c2ecf20Sopenharmony_ci	u32 val32;
568c2ecf20Sopenharmony_ci	int err;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	sym_offset = qid * stride + offset;
618c2ecf20Sopenharmony_ci	if (is_u64)
628c2ecf20Sopenharmony_ci		err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val);
638c2ecf20Sopenharmony_ci	else
648c2ecf20Sopenharmony_ci		err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32);
658c2ecf20Sopenharmony_ci	if (err) {
668c2ecf20Sopenharmony_ci		nfp_err(cpp, "RED offload reading stat failed on vNIC %d band %d queue %d (+ %d)\n",
678c2ecf20Sopenharmony_ci			alink->id, band, queue, alink->queue_base);
688c2ecf20Sopenharmony_ci		return err;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	*res = is_u64 ? val : val32;
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint __nfp_abm_ctrl_set_q_lvl(struct nfp_abm *abm, unsigned int id, u32 val)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct nfp_cpp *cpp = abm->app->cpp;
788c2ecf20Sopenharmony_ci	u64 sym_offset;
798c2ecf20Sopenharmony_ci	int err;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	__clear_bit(id, abm->threshold_undef);
828c2ecf20Sopenharmony_ci	if (abm->thresholds[id] == val)
838c2ecf20Sopenharmony_ci		return 0;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	sym_offset = id * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
868c2ecf20Sopenharmony_ci	err = __nfp_rtsym_writel(cpp, abm->q_lvls, 4, 0, sym_offset, val);
878c2ecf20Sopenharmony_ci	if (err) {
888c2ecf20Sopenharmony_ci		nfp_err(cpp,
898c2ecf20Sopenharmony_ci			"RED offload setting level failed on subqueue %d\n",
908c2ecf20Sopenharmony_ci			id);
918c2ecf20Sopenharmony_ci		return err;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	abm->thresholds[id] = val;
958c2ecf20Sopenharmony_ci	return 0;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciint nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band,
998c2ecf20Sopenharmony_ci			   unsigned int queue, u32 val)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	unsigned int threshold;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	threshold = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return __nfp_abm_ctrl_set_q_lvl(alink->abm, threshold, val);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ciint __nfp_abm_ctrl_set_q_act(struct nfp_abm *abm, unsigned int id,
1098c2ecf20Sopenharmony_ci			     enum nfp_abm_q_action act)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct nfp_cpp *cpp = abm->app->cpp;
1128c2ecf20Sopenharmony_ci	u64 sym_offset;
1138c2ecf20Sopenharmony_ci	int err;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (abm->actions[id] == act)
1168c2ecf20Sopenharmony_ci		return 0;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	sym_offset = id * NFP_QLVL_STRIDE + NFP_QLVL_ACT;
1198c2ecf20Sopenharmony_ci	err = __nfp_rtsym_writel(cpp, abm->q_lvls, 4, 0, sym_offset, act);
1208c2ecf20Sopenharmony_ci	if (err) {
1218c2ecf20Sopenharmony_ci		nfp_err(cpp,
1228c2ecf20Sopenharmony_ci			"RED offload setting action failed on subqueue %d\n",
1238c2ecf20Sopenharmony_ci			id);
1248c2ecf20Sopenharmony_ci		return err;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	abm->actions[id] = act;
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciint nfp_abm_ctrl_set_q_act(struct nfp_abm_link *alink, unsigned int band,
1328c2ecf20Sopenharmony_ci			   unsigned int queue, enum nfp_abm_q_action act)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	unsigned int qid;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return __nfp_abm_ctrl_set_q_act(alink->abm, qid, act);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciu64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int queue)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	unsigned int band;
1448c2ecf20Sopenharmony_ci	u64 val, sum = 0;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	for (band = 0; band < alink->abm->num_bands; band++) {
1478c2ecf20Sopenharmony_ci		if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
1488c2ecf20Sopenharmony_ci				      NFP_QMSTAT_STRIDE, NFP_QMSTAT_NON_STO,
1498c2ecf20Sopenharmony_ci				      band, queue, true, &val))
1508c2ecf20Sopenharmony_ci			return 0;
1518c2ecf20Sopenharmony_ci		sum += val;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	return sum;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ciu64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int queue)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	unsigned int band;
1608c2ecf20Sopenharmony_ci	u64 val, sum = 0;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	for (band = 0; band < alink->abm->num_bands; band++) {
1638c2ecf20Sopenharmony_ci		if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
1648c2ecf20Sopenharmony_ci				      NFP_QMSTAT_STRIDE, NFP_QMSTAT_STO,
1658c2ecf20Sopenharmony_ci				      band, queue, true, &val))
1668c2ecf20Sopenharmony_ci			return 0;
1678c2ecf20Sopenharmony_ci		sum += val;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return sum;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int
1748c2ecf20Sopenharmony_cinfp_abm_ctrl_stat_basic(struct nfp_abm_link *alink, unsigned int band,
1758c2ecf20Sopenharmony_ci			unsigned int queue, unsigned int off, u64 *val)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	if (!nfp_abm_has_prio(alink->abm)) {
1788c2ecf20Sopenharmony_ci		if (!band) {
1798c2ecf20Sopenharmony_ci			unsigned int id = alink->queue_base + queue;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci			*val = nn_readq(alink->vnic,
1828c2ecf20Sopenharmony_ci					NFP_NET_CFG_RXR_STATS(id) + off);
1838c2ecf20Sopenharmony_ci		} else {
1848c2ecf20Sopenharmony_ci			*val = 0;
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		return 0;
1888c2ecf20Sopenharmony_ci	} else {
1898c2ecf20Sopenharmony_ci		return nfp_abm_ctrl_stat(alink, alink->abm->q_stats,
1908c2ecf20Sopenharmony_ci					 NFP_Q_STAT_STRIDE, off, band, queue,
1918c2ecf20Sopenharmony_ci					 true, val);
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciint nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int band,
1968c2ecf20Sopenharmony_ci			      unsigned int queue, struct nfp_alink_stats *stats)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	int err;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_PKTS,
2018c2ecf20Sopenharmony_ci				      &stats->tx_pkts);
2028c2ecf20Sopenharmony_ci	if (err)
2038c2ecf20Sopenharmony_ci		return err;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_BYTES,
2068c2ecf20Sopenharmony_ci				      &stats->tx_bytes);
2078c2ecf20Sopenharmony_ci	if (err)
2088c2ecf20Sopenharmony_ci		return err;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, NFP_QLVL_STRIDE,
2118c2ecf20Sopenharmony_ci				NFP_QLVL_BLOG_BYTES, band, queue, false,
2128c2ecf20Sopenharmony_ci				&stats->backlog_bytes);
2138c2ecf20Sopenharmony_ci	if (err)
2148c2ecf20Sopenharmony_ci		return err;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls,
2178c2ecf20Sopenharmony_ci				NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS,
2188c2ecf20Sopenharmony_ci				band, queue, false, &stats->backlog_pkts);
2198c2ecf20Sopenharmony_ci	if (err)
2208c2ecf20Sopenharmony_ci		return err;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
2238c2ecf20Sopenharmony_ci				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
2248c2ecf20Sopenharmony_ci				band, queue, true, &stats->drops);
2258c2ecf20Sopenharmony_ci	if (err)
2268c2ecf20Sopenharmony_ci		return err;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
2298c2ecf20Sopenharmony_ci				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
2308c2ecf20Sopenharmony_ci				 band, queue, true, &stats->overlimits);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ciint nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink,
2348c2ecf20Sopenharmony_ci			       unsigned int band, unsigned int queue,
2358c2ecf20Sopenharmony_ci			       struct nfp_alink_xstats *xstats)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	int err;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
2408c2ecf20Sopenharmony_ci				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
2418c2ecf20Sopenharmony_ci				band, queue, true, &xstats->pdrop);
2428c2ecf20Sopenharmony_ci	if (err)
2438c2ecf20Sopenharmony_ci		return err;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
2468c2ecf20Sopenharmony_ci				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
2478c2ecf20Sopenharmony_ci				 band, queue, true, &xstats->ecn_marked);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ciint nfp_abm_ctrl_qm_enable(struct nfp_abm *abm)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE,
2538c2ecf20Sopenharmony_ci			    NULL, 0, NULL, 0);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciint nfp_abm_ctrl_qm_disable(struct nfp_abm *abm)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE,
2598c2ecf20Sopenharmony_ci			    NULL, 0, NULL, 0);
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ciint nfp_abm_ctrl_prio_map_update(struct nfp_abm_link *alink, u32 *packed)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	const u32 cmd = NFP_NET_CFG_MBOX_CMD_PCI_DSCP_PRIOMAP_SET;
2658c2ecf20Sopenharmony_ci	struct nfp_net *nn = alink->vnic;
2668c2ecf20Sopenharmony_ci	unsigned int i;
2678c2ecf20Sopenharmony_ci	int err;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	err = nfp_net_mbox_lock(nn, alink->abm->prio_map_len);
2708c2ecf20Sopenharmony_ci	if (err)
2718c2ecf20Sopenharmony_ci		return err;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* Write data_len and wipe reserved */
2748c2ecf20Sopenharmony_ci	nn_writeq(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATALEN,
2758c2ecf20Sopenharmony_ci		  alink->abm->prio_map_len);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	for (i = 0; i < alink->abm->prio_map_len; i += sizeof(u32))
2788c2ecf20Sopenharmony_ci		nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATA + i,
2798c2ecf20Sopenharmony_ci			  packed[i / sizeof(u32)]);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);
2828c2ecf20Sopenharmony_ci	if (err)
2838c2ecf20Sopenharmony_ci		nfp_err(alink->abm->app->cpp,
2848c2ecf20Sopenharmony_ci			"setting DSCP -> VQ map failed with error %d\n", err);
2858c2ecf20Sopenharmony_ci	return err;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic int nfp_abm_ctrl_prio_check_params(struct nfp_abm_link *alink)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct nfp_abm *abm = alink->abm;
2918c2ecf20Sopenharmony_ci	struct nfp_net *nn = alink->vnic;
2928c2ecf20Sopenharmony_ci	unsigned int min_mbox_sz;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (!nfp_abm_has_prio(alink->abm))
2958c2ecf20Sopenharmony_ci		return 0;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	min_mbox_sz = NFP_NET_ABM_MBOX_DATA + alink->abm->prio_map_len;
2988c2ecf20Sopenharmony_ci	if (nn->tlv_caps.mbox_len < min_mbox_sz) {
2998c2ecf20Sopenharmony_ci		nfp_err(abm->app->pf->cpp, "vNIC mailbox too small for prio offload: %u, need: %u\n",
3008c2ecf20Sopenharmony_ci			nn->tlv_caps.mbox_len,  min_mbox_sz);
3018c2ecf20Sopenharmony_ci		return -EINVAL;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	return 0;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ciint nfp_abm_ctrl_read_params(struct nfp_abm_link *alink)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ);
3108c2ecf20Sopenharmony_ci	alink->queue_base /= alink->vnic->stride_rx;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return nfp_abm_ctrl_prio_check_params(alink);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic unsigned int nfp_abm_ctrl_prio_map_size(struct nfp_abm *abm)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	unsigned int size;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	size = roundup_pow_of_two(order_base_2(abm->num_bands));
3208c2ecf20Sopenharmony_ci	size = DIV_ROUND_UP(size * abm->num_prios, BITS_PER_BYTE);
3218c2ecf20Sopenharmony_ci	size = round_up(size, sizeof(u32));
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return size;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic const struct nfp_rtsym *
3278c2ecf20Sopenharmony_cinfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	const struct nfp_rtsym *sym;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	sym = nfp_rtsym_lookup(pf->rtbl, name);
3328c2ecf20Sopenharmony_ci	if (!sym) {
3338c2ecf20Sopenharmony_ci		nfp_err(pf->cpp, "Symbol '%s' not found\n", name);
3348c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOENT);
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci	if (nfp_rtsym_size(sym) != size) {
3378c2ecf20Sopenharmony_ci		nfp_err(pf->cpp,
3388c2ecf20Sopenharmony_ci			"Symbol '%s' wrong size: expected %u got %llu\n",
3398c2ecf20Sopenharmony_ci			name, size, nfp_rtsym_size(sym));
3408c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return sym;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic const struct nfp_rtsym *
3478c2ecf20Sopenharmony_cinfp_abm_ctrl_find_q_rtsym(struct nfp_abm *abm, const char *name_fmt,
3488c2ecf20Sopenharmony_ci			  size_t size)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	char pf_symbol[64];
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	size = array3_size(size, abm->num_bands, NFP_NET_MAX_RX_RINGS);
3538c2ecf20Sopenharmony_ci	snprintf(pf_symbol, sizeof(pf_symbol), name_fmt,
3548c2ecf20Sopenharmony_ci		 abm->pf_id, nfp_abm_has_prio(abm) ? "_per_band" : "");
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return nfp_abm_ctrl_find_rtsym(abm->app->pf, pf_symbol, size);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ciint nfp_abm_ctrl_find_addrs(struct nfp_abm *abm)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct nfp_pf *pf = abm->app->pf;
3628c2ecf20Sopenharmony_ci	const struct nfp_rtsym *sym;
3638c2ecf20Sopenharmony_ci	int res;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	abm->pf_id = nfp_cppcore_pcie_unit(pf->cpp);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* Check if Qdisc offloads are supported */
3688c2ecf20Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_RED_SUPPORT_SYM_NAME, 1);
3698c2ecf20Sopenharmony_ci	if (res < 0)
3708c2ecf20Sopenharmony_ci		return res;
3718c2ecf20Sopenharmony_ci	abm->red_support = res;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* Read count of prios and prio bands */
3748c2ecf20Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_BANDS_SYM_NAME, 1);
3758c2ecf20Sopenharmony_ci	if (res < 0)
3768c2ecf20Sopenharmony_ci		return res;
3778c2ecf20Sopenharmony_ci	abm->num_bands = res;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_PRIOS_SYM_NAME, 1);
3808c2ecf20Sopenharmony_ci	if (res < 0)
3818c2ecf20Sopenharmony_ci		return res;
3828c2ecf20Sopenharmony_ci	abm->num_prios = res;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/* Read available actions */
3858c2ecf20Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_ACT_MASK_SYM_NAME,
3868c2ecf20Sopenharmony_ci					 BIT(NFP_ABM_ACT_MARK_DROP));
3878c2ecf20Sopenharmony_ci	if (res < 0)
3888c2ecf20Sopenharmony_ci		return res;
3898c2ecf20Sopenharmony_ci	abm->action_mask = res;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	abm->prio_map_len = nfp_abm_ctrl_prio_map_size(abm);
3928c2ecf20Sopenharmony_ci	abm->dscp_mask = GENMASK(7, 8 - order_base_2(abm->num_prios));
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/* Check values are sane, U16_MAX is arbitrarily chosen as max */
3958c2ecf20Sopenharmony_ci	if (!is_power_of_2(abm->num_bands) || !is_power_of_2(abm->num_prios) ||
3968c2ecf20Sopenharmony_ci	    abm->num_bands > U16_MAX || abm->num_prios > U16_MAX ||
3978c2ecf20Sopenharmony_ci	    (abm->num_bands == 1) != (abm->num_prios == 1)) {
3988c2ecf20Sopenharmony_ci		nfp_err(pf->cpp,
3998c2ecf20Sopenharmony_ci			"invalid priomap description num bands: %u and num prios: %u\n",
4008c2ecf20Sopenharmony_ci			abm->num_bands, abm->num_prios);
4018c2ecf20Sopenharmony_ci		return -EINVAL;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* Find level and stat symbols */
4058c2ecf20Sopenharmony_ci	if (!abm->red_support)
4068c2ecf20Sopenharmony_ci		return 0;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QLVL_SYM_NAME,
4098c2ecf20Sopenharmony_ci					NFP_QLVL_STRIDE);
4108c2ecf20Sopenharmony_ci	if (IS_ERR(sym))
4118c2ecf20Sopenharmony_ci		return PTR_ERR(sym);
4128c2ecf20Sopenharmony_ci	abm->q_lvls = sym;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QMSTAT_SYM_NAME,
4158c2ecf20Sopenharmony_ci					NFP_QMSTAT_STRIDE);
4168c2ecf20Sopenharmony_ci	if (IS_ERR(sym))
4178c2ecf20Sopenharmony_ci		return PTR_ERR(sym);
4188c2ecf20Sopenharmony_ci	abm->qm_stats = sym;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (nfp_abm_has_prio(abm)) {
4218c2ecf20Sopenharmony_ci		sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_Q_STAT_SYM_NAME,
4228c2ecf20Sopenharmony_ci						NFP_Q_STAT_STRIDE);
4238c2ecf20Sopenharmony_ci		if (IS_ERR(sym))
4248c2ecf20Sopenharmony_ci			return PTR_ERR(sym);
4258c2ecf20Sopenharmony_ci		abm->q_stats = sym;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	return 0;
4298c2ecf20Sopenharmony_ci}
430