aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2018-11-19 15:21:50 -0800
committerDavid S. Miller <davem@davemloft.net>2018-11-19 18:53:46 -0800
commit340a4864d538ab718b0e888a1d5933bc13e6a372 (patch)
treeb8279d8df85a64ea2c50859459ae4670663e601a
parentnfp: abm: add cls_u32 offload for simple band classification (diff)
downloadlinux-dev-340a4864d538ab718b0e888a1d5933bc13e6a372.tar.xz
linux-dev-340a4864d538ab718b0e888a1d5933bc13e6a372.zip
nfp: abm: add support for more threshold actions
Original FW only allowed us to perform ECN marking. Newer releases also support plain old drop. Add the ability to configure drop policy. This is particularly useful in combination with GRED, because different bands can have different ECN marking setting. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: John Hurley <john.hurley@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/ctrl.c42
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/main.c14
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/main.h31
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/qdisc.c28
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;
}