162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (C) 2018 Netronome Systems, Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/bitops.h>
562306a36Sopenharmony_ci#include <linux/kernel.h>
662306a36Sopenharmony_ci#include <linux/log2.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "../nfpcore/nfp_cpp.h"
962306a36Sopenharmony_ci#include "../nfpcore/nfp_nffw.h"
1062306a36Sopenharmony_ci#include "../nfp_app.h"
1162306a36Sopenharmony_ci#include "../nfp_abi.h"
1262306a36Sopenharmony_ci#include "../nfp_main.h"
1362306a36Sopenharmony_ci#include "../nfp_net.h"
1462306a36Sopenharmony_ci#include "main.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define NFP_NUM_PRIOS_SYM_NAME	"_abi_pci_dscp_num_prio_%u"
1762306a36Sopenharmony_ci#define NFP_NUM_BANDS_SYM_NAME	"_abi_pci_dscp_num_band_%u"
1862306a36Sopenharmony_ci#define NFP_ACT_MASK_SYM_NAME	"_abi_nfd_out_q_actions_%u"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define NFP_RED_SUPPORT_SYM_NAME	"_abi_nfd_out_red_offload_%u"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define NFP_QLVL_SYM_NAME	"_abi_nfd_out_q_lvls_%u%s"
2362306a36Sopenharmony_ci#define NFP_QLVL_STRIDE		16
2462306a36Sopenharmony_ci#define NFP_QLVL_BLOG_BYTES	0
2562306a36Sopenharmony_ci#define NFP_QLVL_BLOG_PKTS	4
2662306a36Sopenharmony_ci#define NFP_QLVL_THRS		8
2762306a36Sopenharmony_ci#define NFP_QLVL_ACT		12
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define NFP_QMSTAT_SYM_NAME	"_abi_nfdqm%u_stats%s"
3062306a36Sopenharmony_ci#define NFP_QMSTAT_STRIDE	32
3162306a36Sopenharmony_ci#define NFP_QMSTAT_NON_STO	0
3262306a36Sopenharmony_ci#define NFP_QMSTAT_STO		8
3362306a36Sopenharmony_ci#define NFP_QMSTAT_DROP		16
3462306a36Sopenharmony_ci#define NFP_QMSTAT_ECN		24
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define NFP_Q_STAT_SYM_NAME	"_abi_nfd_rxq_stats%u%s"
3762306a36Sopenharmony_ci#define NFP_Q_STAT_STRIDE	16
3862306a36Sopenharmony_ci#define NFP_Q_STAT_PKTS		0
3962306a36Sopenharmony_ci#define NFP_Q_STAT_BYTES	8
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define NFP_NET_ABM_MBOX_CMD		NFP_NET_CFG_MBOX_SIMPLE_CMD
4262306a36Sopenharmony_ci#define NFP_NET_ABM_MBOX_RET		NFP_NET_CFG_MBOX_SIMPLE_RET
4362306a36Sopenharmony_ci#define NFP_NET_ABM_MBOX_DATALEN	NFP_NET_CFG_MBOX_SIMPLE_VAL
4462306a36Sopenharmony_ci#define NFP_NET_ABM_MBOX_RESERVED	(NFP_NET_CFG_MBOX_SIMPLE_VAL + 4)
4562306a36Sopenharmony_ci#define NFP_NET_ABM_MBOX_DATA		(NFP_NET_CFG_MBOX_SIMPLE_VAL + 8)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int
4862306a36Sopenharmony_cinfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
4962306a36Sopenharmony_ci		  unsigned int stride, unsigned int offset, unsigned int band,
5062306a36Sopenharmony_ci		  unsigned int queue, bool is_u64, u64 *res)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct nfp_cpp *cpp = alink->abm->app->cpp;
5362306a36Sopenharmony_ci	u64 val, sym_offset;
5462306a36Sopenharmony_ci	unsigned int qid;
5562306a36Sopenharmony_ci	u32 val32;
5662306a36Sopenharmony_ci	int err;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	sym_offset = qid * stride + offset;
6162306a36Sopenharmony_ci	if (is_u64)
6262306a36Sopenharmony_ci		err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val);
6362306a36Sopenharmony_ci	else
6462306a36Sopenharmony_ci		err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32);
6562306a36Sopenharmony_ci	if (err) {
6662306a36Sopenharmony_ci		nfp_err(cpp, "RED offload reading stat failed on vNIC %d band %d queue %d (+ %d)\n",
6762306a36Sopenharmony_ci			alink->id, band, queue, alink->queue_base);
6862306a36Sopenharmony_ci		return err;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	*res = is_u64 ? val : val32;
7262306a36Sopenharmony_ci	return 0;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciint __nfp_abm_ctrl_set_q_lvl(struct nfp_abm *abm, unsigned int id, u32 val)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct nfp_cpp *cpp = abm->app->cpp;
7862306a36Sopenharmony_ci	u64 sym_offset;
7962306a36Sopenharmony_ci	int err;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	__clear_bit(id, abm->threshold_undef);
8262306a36Sopenharmony_ci	if (abm->thresholds[id] == val)
8362306a36Sopenharmony_ci		return 0;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	sym_offset = id * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
8662306a36Sopenharmony_ci	err = __nfp_rtsym_writel(cpp, abm->q_lvls, 4, 0, sym_offset, val);
8762306a36Sopenharmony_ci	if (err) {
8862306a36Sopenharmony_ci		nfp_err(cpp,
8962306a36Sopenharmony_ci			"RED offload setting level failed on subqueue %d\n",
9062306a36Sopenharmony_ci			id);
9162306a36Sopenharmony_ci		return err;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	abm->thresholds[id] = val;
9562306a36Sopenharmony_ci	return 0;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ciint nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band,
9962306a36Sopenharmony_ci			   unsigned int queue, u32 val)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	unsigned int threshold;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	threshold = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	return __nfp_abm_ctrl_set_q_lvl(alink->abm, threshold, val);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciint __nfp_abm_ctrl_set_q_act(struct nfp_abm *abm, unsigned int id,
10962306a36Sopenharmony_ci			     enum nfp_abm_q_action act)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct nfp_cpp *cpp = abm->app->cpp;
11262306a36Sopenharmony_ci	u64 sym_offset;
11362306a36Sopenharmony_ci	int err;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (abm->actions[id] == act)
11662306a36Sopenharmony_ci		return 0;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	sym_offset = id * NFP_QLVL_STRIDE + NFP_QLVL_ACT;
11962306a36Sopenharmony_ci	err = __nfp_rtsym_writel(cpp, abm->q_lvls, 4, 0, sym_offset, act);
12062306a36Sopenharmony_ci	if (err) {
12162306a36Sopenharmony_ci		nfp_err(cpp,
12262306a36Sopenharmony_ci			"RED offload setting action failed on subqueue %d\n",
12362306a36Sopenharmony_ci			id);
12462306a36Sopenharmony_ci		return err;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	abm->actions[id] = act;
12862306a36Sopenharmony_ci	return 0;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciint nfp_abm_ctrl_set_q_act(struct nfp_abm_link *alink, unsigned int band,
13262306a36Sopenharmony_ci			   unsigned int queue, enum nfp_abm_q_action act)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	unsigned int qid;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return __nfp_abm_ctrl_set_q_act(alink->abm, qid, act);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciu64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int queue)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	unsigned int band;
14462306a36Sopenharmony_ci	u64 val, sum = 0;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	for (band = 0; band < alink->abm->num_bands; band++) {
14762306a36Sopenharmony_ci		if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
14862306a36Sopenharmony_ci				      NFP_QMSTAT_STRIDE, NFP_QMSTAT_NON_STO,
14962306a36Sopenharmony_ci				      band, queue, true, &val))
15062306a36Sopenharmony_ci			return 0;
15162306a36Sopenharmony_ci		sum += val;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return sum;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciu64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int queue)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	unsigned int band;
16062306a36Sopenharmony_ci	u64 val, sum = 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	for (band = 0; band < alink->abm->num_bands; band++) {
16362306a36Sopenharmony_ci		if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
16462306a36Sopenharmony_ci				      NFP_QMSTAT_STRIDE, NFP_QMSTAT_STO,
16562306a36Sopenharmony_ci				      band, queue, true, &val))
16662306a36Sopenharmony_ci			return 0;
16762306a36Sopenharmony_ci		sum += val;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return sum;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int
17462306a36Sopenharmony_cinfp_abm_ctrl_stat_basic(struct nfp_abm_link *alink, unsigned int band,
17562306a36Sopenharmony_ci			unsigned int queue, unsigned int off, u64 *val)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	if (!nfp_abm_has_prio(alink->abm)) {
17862306a36Sopenharmony_ci		if (!band) {
17962306a36Sopenharmony_ci			unsigned int id = alink->queue_base + queue;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci			*val = nn_readq(alink->vnic,
18262306a36Sopenharmony_ci					NFP_NET_CFG_RXR_STATS(id) + off);
18362306a36Sopenharmony_ci		} else {
18462306a36Sopenharmony_ci			*val = 0;
18562306a36Sopenharmony_ci		}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		return 0;
18862306a36Sopenharmony_ci	} else {
18962306a36Sopenharmony_ci		return nfp_abm_ctrl_stat(alink, alink->abm->q_stats,
19062306a36Sopenharmony_ci					 NFP_Q_STAT_STRIDE, off, band, queue,
19162306a36Sopenharmony_ci					 true, val);
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ciint nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int band,
19662306a36Sopenharmony_ci			      unsigned int queue, struct nfp_alink_stats *stats)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int err;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_PKTS,
20162306a36Sopenharmony_ci				      &stats->tx_pkts);
20262306a36Sopenharmony_ci	if (err)
20362306a36Sopenharmony_ci		return err;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_BYTES,
20662306a36Sopenharmony_ci				      &stats->tx_bytes);
20762306a36Sopenharmony_ci	if (err)
20862306a36Sopenharmony_ci		return err;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, NFP_QLVL_STRIDE,
21162306a36Sopenharmony_ci				NFP_QLVL_BLOG_BYTES, band, queue, false,
21262306a36Sopenharmony_ci				&stats->backlog_bytes);
21362306a36Sopenharmony_ci	if (err)
21462306a36Sopenharmony_ci		return err;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls,
21762306a36Sopenharmony_ci				NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS,
21862306a36Sopenharmony_ci				band, queue, false, &stats->backlog_pkts);
21962306a36Sopenharmony_ci	if (err)
22062306a36Sopenharmony_ci		return err;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
22362306a36Sopenharmony_ci				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
22462306a36Sopenharmony_ci				band, queue, true, &stats->drops);
22562306a36Sopenharmony_ci	if (err)
22662306a36Sopenharmony_ci		return err;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
22962306a36Sopenharmony_ci				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
23062306a36Sopenharmony_ci				 band, queue, true, &stats->overlimits);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ciint nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink,
23462306a36Sopenharmony_ci			       unsigned int band, unsigned int queue,
23562306a36Sopenharmony_ci			       struct nfp_alink_xstats *xstats)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	int err;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
24062306a36Sopenharmony_ci				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
24162306a36Sopenharmony_ci				band, queue, true, &xstats->pdrop);
24262306a36Sopenharmony_ci	if (err)
24362306a36Sopenharmony_ci		return err;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
24662306a36Sopenharmony_ci				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
24762306a36Sopenharmony_ci				 band, queue, true, &xstats->ecn_marked);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ciint nfp_abm_ctrl_qm_enable(struct nfp_abm *abm)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE,
25362306a36Sopenharmony_ci			    NULL, 0, NULL, 0);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ciint nfp_abm_ctrl_qm_disable(struct nfp_abm *abm)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE,
25962306a36Sopenharmony_ci			    NULL, 0, NULL, 0);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciint nfp_abm_ctrl_prio_map_update(struct nfp_abm_link *alink, u32 *packed)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	const u32 cmd = NFP_NET_CFG_MBOX_CMD_PCI_DSCP_PRIOMAP_SET;
26562306a36Sopenharmony_ci	struct nfp_net *nn = alink->vnic;
26662306a36Sopenharmony_ci	unsigned int i;
26762306a36Sopenharmony_ci	int err;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	err = nfp_net_mbox_lock(nn, alink->abm->prio_map_len);
27062306a36Sopenharmony_ci	if (err)
27162306a36Sopenharmony_ci		return err;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Write data_len and wipe reserved */
27462306a36Sopenharmony_ci	nn_writeq(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATALEN,
27562306a36Sopenharmony_ci		  alink->abm->prio_map_len);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	for (i = 0; i < alink->abm->prio_map_len; i += sizeof(u32))
27862306a36Sopenharmony_ci		nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATA + i,
27962306a36Sopenharmony_ci			  packed[i / sizeof(u32)]);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);
28262306a36Sopenharmony_ci	if (err)
28362306a36Sopenharmony_ci		nfp_err(alink->abm->app->cpp,
28462306a36Sopenharmony_ci			"setting DSCP -> VQ map failed with error %d\n", err);
28562306a36Sopenharmony_ci	return err;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int nfp_abm_ctrl_prio_check_params(struct nfp_abm_link *alink)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct nfp_abm *abm = alink->abm;
29162306a36Sopenharmony_ci	struct nfp_net *nn = alink->vnic;
29262306a36Sopenharmony_ci	unsigned int min_mbox_sz;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (!nfp_abm_has_prio(alink->abm))
29562306a36Sopenharmony_ci		return 0;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	min_mbox_sz = NFP_NET_ABM_MBOX_DATA + alink->abm->prio_map_len;
29862306a36Sopenharmony_ci	if (nn->tlv_caps.mbox_len < min_mbox_sz) {
29962306a36Sopenharmony_ci		nfp_err(abm->app->pf->cpp, "vNIC mailbox too small for prio offload: %u, need: %u\n",
30062306a36Sopenharmony_ci			nn->tlv_caps.mbox_len,  min_mbox_sz);
30162306a36Sopenharmony_ci		return -EINVAL;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	return 0;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ciint nfp_abm_ctrl_read_params(struct nfp_abm_link *alink)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ);
31062306a36Sopenharmony_ci	alink->queue_base /= alink->vnic->stride_rx;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return nfp_abm_ctrl_prio_check_params(alink);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic unsigned int nfp_abm_ctrl_prio_map_size(struct nfp_abm *abm)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	unsigned int size;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	size = roundup_pow_of_two(order_base_2(abm->num_bands));
32062306a36Sopenharmony_ci	size = DIV_ROUND_UP(size * abm->num_prios, BITS_PER_BYTE);
32162306a36Sopenharmony_ci	size = round_up(size, sizeof(u32));
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return size;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic const struct nfp_rtsym *
32762306a36Sopenharmony_cinfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	const struct nfp_rtsym *sym;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	sym = nfp_rtsym_lookup(pf->rtbl, name);
33262306a36Sopenharmony_ci	if (!sym) {
33362306a36Sopenharmony_ci		nfp_err(pf->cpp, "Symbol '%s' not found\n", name);
33462306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci	if (nfp_rtsym_size(sym) != size) {
33762306a36Sopenharmony_ci		nfp_err(pf->cpp,
33862306a36Sopenharmony_ci			"Symbol '%s' wrong size: expected %u got %llu\n",
33962306a36Sopenharmony_ci			name, size, nfp_rtsym_size(sym));
34062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return sym;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic const struct nfp_rtsym *
34762306a36Sopenharmony_cinfp_abm_ctrl_find_q_rtsym(struct nfp_abm *abm, const char *name_fmt,
34862306a36Sopenharmony_ci			  size_t size)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	char pf_symbol[64];
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	size = array3_size(size, abm->num_bands, NFP_NET_MAX_RX_RINGS);
35362306a36Sopenharmony_ci	snprintf(pf_symbol, sizeof(pf_symbol), name_fmt,
35462306a36Sopenharmony_ci		 abm->pf_id, nfp_abm_has_prio(abm) ? "_per_band" : "");
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return nfp_abm_ctrl_find_rtsym(abm->app->pf, pf_symbol, size);
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ciint nfp_abm_ctrl_find_addrs(struct nfp_abm *abm)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct nfp_pf *pf = abm->app->pf;
36262306a36Sopenharmony_ci	const struct nfp_rtsym *sym;
36362306a36Sopenharmony_ci	int res;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	abm->pf_id = nfp_cppcore_pcie_unit(pf->cpp);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* Check if Qdisc offloads are supported */
36862306a36Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_RED_SUPPORT_SYM_NAME, 1);
36962306a36Sopenharmony_ci	if (res < 0)
37062306a36Sopenharmony_ci		return res;
37162306a36Sopenharmony_ci	abm->red_support = res;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Read count of prios and prio bands */
37462306a36Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_BANDS_SYM_NAME, 1);
37562306a36Sopenharmony_ci	if (res < 0)
37662306a36Sopenharmony_ci		return res;
37762306a36Sopenharmony_ci	abm->num_bands = res;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_PRIOS_SYM_NAME, 1);
38062306a36Sopenharmony_ci	if (res < 0)
38162306a36Sopenharmony_ci		return res;
38262306a36Sopenharmony_ci	abm->num_prios = res;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/* Read available actions */
38562306a36Sopenharmony_ci	res = nfp_pf_rtsym_read_optional(pf, NFP_ACT_MASK_SYM_NAME,
38662306a36Sopenharmony_ci					 BIT(NFP_ABM_ACT_MARK_DROP));
38762306a36Sopenharmony_ci	if (res < 0)
38862306a36Sopenharmony_ci		return res;
38962306a36Sopenharmony_ci	abm->action_mask = res;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	abm->prio_map_len = nfp_abm_ctrl_prio_map_size(abm);
39262306a36Sopenharmony_ci	abm->dscp_mask = GENMASK(7, 8 - order_base_2(abm->num_prios));
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/* Check values are sane, U16_MAX is arbitrarily chosen as max */
39562306a36Sopenharmony_ci	if (!is_power_of_2(abm->num_bands) || !is_power_of_2(abm->num_prios) ||
39662306a36Sopenharmony_ci	    abm->num_bands > U16_MAX || abm->num_prios > U16_MAX ||
39762306a36Sopenharmony_ci	    (abm->num_bands == 1) != (abm->num_prios == 1)) {
39862306a36Sopenharmony_ci		nfp_err(pf->cpp,
39962306a36Sopenharmony_ci			"invalid priomap description num bands: %u and num prios: %u\n",
40062306a36Sopenharmony_ci			abm->num_bands, abm->num_prios);
40162306a36Sopenharmony_ci		return -EINVAL;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* Find level and stat symbols */
40562306a36Sopenharmony_ci	if (!abm->red_support)
40662306a36Sopenharmony_ci		return 0;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QLVL_SYM_NAME,
40962306a36Sopenharmony_ci					NFP_QLVL_STRIDE);
41062306a36Sopenharmony_ci	if (IS_ERR(sym))
41162306a36Sopenharmony_ci		return PTR_ERR(sym);
41262306a36Sopenharmony_ci	abm->q_lvls = sym;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QMSTAT_SYM_NAME,
41562306a36Sopenharmony_ci					NFP_QMSTAT_STRIDE);
41662306a36Sopenharmony_ci	if (IS_ERR(sym))
41762306a36Sopenharmony_ci		return PTR_ERR(sym);
41862306a36Sopenharmony_ci	abm->qm_stats = sym;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (nfp_abm_has_prio(abm)) {
42162306a36Sopenharmony_ci		sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_Q_STAT_SYM_NAME,
42262306a36Sopenharmony_ci						NFP_Q_STAT_STRIDE);
42362306a36Sopenharmony_ci		if (IS_ERR(sym))
42462306a36Sopenharmony_ci			return PTR_ERR(sym);
42562306a36Sopenharmony_ci		abm->q_stats = sym;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return 0;
42962306a36Sopenharmony_ci}
430