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