diff options
Diffstat (limited to 'drivers/net/ethernet/netronome')
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 42 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/abm/main.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/abm/main.h | 31 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/abm/qdisc.c | 28 |
4 files changed, 109 insertions, 6 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c index 2447e935e2d9..ad6c2a621c7a 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c +++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c @@ -15,12 +15,14 @@ #define NFP_NUM_PRIOS_SYM_NAME "_abi_pci_dscp_num_prio_%u" #define NFP_NUM_BANDS_SYM_NAME "_abi_pci_dscp_num_band_%u" +#define NFP_ACT_MASK_SYM_NAME "_abi_nfd_out_q_actions_%u" #define NFP_QLVL_SYM_NAME "_abi_nfd_out_q_lvls_%u%s" #define NFP_QLVL_STRIDE 16 #define NFP_QLVL_BLOG_BYTES 0 #define NFP_QLVL_BLOG_PKTS 4 #define NFP_QLVL_THRS 8 +#define NFP_QLVL_ACT 12 #define NFP_QMSTAT_SYM_NAME "_abi_nfdqm%u_stats%s" #define NFP_QMSTAT_STRIDE 32 @@ -101,6 +103,39 @@ int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band, return __nfp_abm_ctrl_set_q_lvl(alink->abm, threshold, val); } +int __nfp_abm_ctrl_set_q_act(struct nfp_abm *abm, unsigned int id, + enum nfp_abm_q_action act) +{ + struct nfp_cpp *cpp = abm->app->cpp; + u64 sym_offset; + int err; + + if (abm->actions[id] == act) + return 0; + + sym_offset = id * NFP_QLVL_STRIDE + NFP_QLVL_ACT; + err = __nfp_rtsym_writel(cpp, abm->q_lvls, 4, 0, sym_offset, act); + if (err) { + nfp_err(cpp, + "RED offload setting action failed on subqueue %d\n", + id); + return err; + } + + abm->actions[id] = act; + return 0; +} + +int nfp_abm_ctrl_set_q_act(struct nfp_abm_link *alink, unsigned int band, + unsigned int queue, enum nfp_abm_q_action act) +{ + unsigned int qid; + + qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue; + + return __nfp_abm_ctrl_set_q_act(alink->abm, qid, act); +} + u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int queue) { unsigned int band; @@ -334,6 +369,13 @@ int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm) return res; abm->num_prios = res; + /* Read available actions */ + res = nfp_pf_rtsym_read_optional(pf, NFP_ACT_MASK_SYM_NAME, + BIT(NFP_ABM_ACT_MARK_DROP)); + if (res < 0) + return res; + abm->action_mask = res; + abm->prio_map_len = nfp_abm_ctrl_prio_map_size(abm); abm->dscp_mask = GENMASK(7, 8 - order_base_2(abm->num_prios)); diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.c b/drivers/net/ethernet/netronome/nfp/abm/main.c index ecdef63a20f3..7a4d55f794c2 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/main.c +++ b/drivers/net/ethernet/netronome/nfp/abm/main.c @@ -459,15 +459,22 @@ static int nfp_abm_init(struct nfp_app *app) for (i = 0; i < abm->num_bands * NFP_NET_MAX_RX_RINGS; i++) __nfp_abm_ctrl_set_q_lvl(abm, i, NFP_ABM_LVL_INFINITY); + abm->actions = kvcalloc(abm->num_thresholds, sizeof(*abm->actions), + GFP_KERNEL); + if (!abm->actions) + goto err_free_thresh; + for (i = 0; i < abm->num_bands * NFP_NET_MAX_RX_RINGS; i++) + __nfp_abm_ctrl_set_q_act(abm, i, NFP_ABM_ACT_DROP); + /* We start in legacy mode, make sure advanced queuing is disabled */ err = nfp_abm_ctrl_qm_disable(abm); if (err) - goto err_free_thresh; + goto err_free_act; err = -ENOMEM; reprs = nfp_reprs_alloc(pf->max_data_vnics); if (!reprs) - goto err_free_thresh; + goto err_free_act; RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs); reprs = nfp_reprs_alloc(pf->max_data_vnics); @@ -479,6 +486,8 @@ static int nfp_abm_init(struct nfp_app *app) err_free_phys: nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); +err_free_act: + kvfree(abm->actions); err_free_thresh: kvfree(abm->thresholds); err_free_thresh_umap: @@ -497,6 +506,7 @@ static void nfp_abm_clean(struct nfp_app *app) nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); bitmap_free(abm->threshold_undef); + kvfree(abm->actions); kvfree(abm->thresholds); kfree(abm); app->priv = NULL; diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h index 9352992ab386..4dcf5881fb4b 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/main.h +++ b/drivers/net/ethernet/netronome/nfp/abm/main.h @@ -24,6 +24,17 @@ struct nfp_net; #define NFP_ABM_PORTID_TYPE GENMASK(23, 16) #define NFP_ABM_PORTID_ID GENMASK(7, 0) +/* The possible actions if thresholds are exceeded */ +enum nfp_abm_q_action { + /* mark if ECN capable, otherwise drop */ + NFP_ABM_ACT_MARK_DROP = 0, + /* mark if ECN capable, otherwise goto QM */ + NFP_ABM_ACT_MARK_QUEUE = 1, + NFP_ABM_ACT_DROP = 2, + NFP_ABM_ACT_QUEUE = 3, + NFP_ABM_ACT_NOQUEUE = 4, +}; + /** * struct nfp_abm - ABM NIC app structure * @app: back pointer to nfp_app @@ -31,9 +42,11 @@ struct nfp_net; * * @num_prios: number of supported DSCP priorities * @num_bands: number of supported DSCP priority bands + * @action_mask: bitmask of supported actions * * @thresholds: current threshold configuration * @threshold_undef: bitmap of thresholds which have not been set + * @actions: current FW action configuration * @num_thresholds: number of @thresholds and bits in @threshold_undef * * @prio_map_len: computed length of FW priority map (in bytes) @@ -52,9 +65,11 @@ struct nfp_abm { unsigned int num_prios; unsigned int num_bands; + unsigned int action_mask; u32 *thresholds; unsigned long *threshold_undef; + u8 *actions; size_t num_thresholds; unsigned int prio_map_len; @@ -125,6 +140,7 @@ enum nfp_qdisc_type { * @red: RED Qdisc specific parameters and state * @red.num_bands: Number of valid entries in the @red.band table * @red.band: Per-band array of RED instances + * @red.band.ecn: ECN marking is enabled (rather than drop) * @red.band.threshold: ECN marking threshold * @red.band.stats: current stats of the RED Qdisc * @red.band.prev_stats: previously reported @red.stats @@ -155,6 +171,7 @@ struct nfp_qdisc { unsigned int num_bands; struct { + bool ecn; u32 threshold; struct nfp_alink_stats stats; struct nfp_alink_stats prev_stats; @@ -208,6 +225,16 @@ static inline bool nfp_abm_has_prio(struct nfp_abm *abm) return abm->num_bands > 1; } +static inline bool nfp_abm_has_drop(struct nfp_abm *abm) +{ + return abm->action_mask & BIT(NFP_ABM_ACT_DROP); +} + +static inline bool nfp_abm_has_mark(struct nfp_abm *abm) +{ + return abm->action_mask & BIT(NFP_ABM_ACT_MARK_DROP); +} + void nfp_abm_qdisc_offload_update(struct nfp_abm_link *alink); int nfp_abm_setup_root(struct net_device *netdev, struct nfp_abm_link *alink, struct tc_root_qopt_offload *opt); @@ -225,6 +252,10 @@ int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm); int __nfp_abm_ctrl_set_q_lvl(struct nfp_abm *abm, unsigned int id, u32 val); int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band, unsigned int queue, u32 val); +int __nfp_abm_ctrl_set_q_act(struct nfp_abm *abm, unsigned int id, + enum nfp_abm_q_action act); +int nfp_abm_ctrl_set_q_act(struct nfp_abm_link *alink, unsigned int band, + unsigned int queue, enum nfp_abm_q_action act); int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int band, unsigned int queue, struct nfp_alink_stats *stats); diff --git a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c index 8f6e43667757..2473fb5f75e5 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/qdisc.c +++ b/drivers/net/ethernet/netronome/nfp/abm/qdisc.c @@ -212,9 +212,15 @@ nfp_abm_offload_compile_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc, if (!qdisc->offload_mark) return; - for (i = 0; i < alink->abm->num_bands; i++) + for (i = 0; i < alink->abm->num_bands; i++) { + enum nfp_abm_q_action act; + nfp_abm_ctrl_set_q_lvl(alink, i, queue, qdisc->red.band[i].threshold); + act = qdisc->red.band[i].ecn ? + NFP_ABM_ACT_MARK_DROP : NFP_ABM_ACT_DROP; + nfp_abm_ctrl_set_q_act(alink, i, queue, act); + } } static void @@ -535,11 +541,16 @@ nfp_abm_gred_check_params(struct nfp_abm_link *alink, if (!band->present) return false; - if (!band->is_ecn) { + if (!band->is_ecn && !nfp_abm_has_drop(abm)) { nfp_warn(cpp, "GRED offload failed - drop is not supported (ECN option required) (p:%08x h:%08x vq:%d)\n", opt->parent, opt->handle, i); return false; } + if (band->is_ecn && !nfp_abm_has_mark(abm)) { + nfp_warn(cpp, "GRED offload failed - ECN marking not supported (p:%08x h:%08x vq:%d)\n", + opt->parent, opt->handle, i); + return false; + } if (band->is_harddrop) { nfp_warn(cpp, "GRED offload failed - harddrop is not supported (p:%08x h:%08x vq:%d)\n", opt->parent, opt->handle, i); @@ -577,8 +588,10 @@ nfp_abm_gred_replace(struct net_device *netdev, struct nfp_abm_link *alink, qdisc->params_ok = nfp_abm_gred_check_params(alink, opt); if (qdisc->params_ok) { qdisc->red.num_bands = opt->set.dp_cnt; - for (i = 0; i < qdisc->red.num_bands; i++) + for (i = 0; i < qdisc->red.num_bands; i++) { + qdisc->red.band[i].ecn = opt->set.tab[i].is_ecn; qdisc->red.band[i].threshold = opt->set.tab[i].min; + } } if (qdisc->use_cnt) @@ -649,12 +662,18 @@ nfp_abm_red_check_params(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) { struct nfp_cpp *cpp = alink->abm->app->cpp; + struct nfp_abm *abm = alink->abm; - if (!opt->set.is_ecn) { + if (!opt->set.is_ecn && !nfp_abm_has_drop(abm)) { nfp_warn(cpp, "RED offload failed - drop is not supported (ECN option required) (p:%08x h:%08x)\n", opt->parent, opt->handle); return false; } + if (opt->set.is_ecn && !nfp_abm_has_mark(abm)) { + nfp_warn(cpp, "RED offload failed - ECN marking not supported (p:%08x h:%08x)\n", + opt->parent, opt->handle); + return false; + } if (opt->set.is_harddrop) { nfp_warn(cpp, "RED offload failed - harddrop is not supported (p:%08x h:%08x)\n", opt->parent, opt->handle); @@ -703,6 +722,7 @@ nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink, qdisc->params_ok = nfp_abm_red_check_params(alink, opt); if (qdisc->params_ok) { qdisc->red.num_bands = 1; + qdisc->red.band[0].ecn = opt->set.is_ecn; qdisc->red.band[0].threshold = opt->set.min; } |