Commit e6ebe6c1 authored by David S. Miller's avatar David S. Miller

Merge branch 'taprio-auto-qmaxsdu-new-tx'

Vladimir Oltean says:

====================
taprio automatic queueMaxSDU and new TXQ selection procedure

This patch set addresses 2 design limitations in the taprio software scheduler:

1. Software scheduling fundamentally prioritizes traffic incorrectly,
   in a way which was inspired from Intel igb/igc drivers and does not
   follow the inputs user space gives (traffic classes and TC to TXQ
   mapping). Patch 05/15 handles this, 01/15 - 04/15 are preparations
   for this work.

2. Software scheduling assumes that the gate for a traffic class closes
   as soon as the next interval begins. But this isn't true.
   If consecutive schedule entries have that traffic class gate open,
   there is no "gate close" event and taprio should keep dequeuing from
   that TC without interruptions. Patches 06/15 - 15/15 handle this.
   Patch 10/15 is a generic Qdisc change required for this to work.

Future development directions which depend on this patch set are:

- Propagating the automatic queueMaxSDU calculation down to offloading
  device drivers, instead of letting them calculate this, as
  vsc9959_tas_guard_bands_update() does today.

- A software data path for tc-taprio with preemptible traffic and
  Hold/Release events.

v1 at:
https://patchwork.kernel.org/project/netdevbpf/cover/20230128010719.2182346-1-vladimir.oltean@nxp.com/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6da13bf9 39b02d6d
...@@ -2810,6 +2810,22 @@ static int igb_offload_txtime(struct igb_adapter *adapter, ...@@ -2810,6 +2810,22 @@ static int igb_offload_txtime(struct igb_adapter *adapter,
return 0; return 0;
} }
static int igb_tc_query_caps(struct igb_adapter *adapter,
struct tc_query_caps_base *base)
{
switch (base->type) {
case TC_SETUP_QDISC_TAPRIO: {
struct tc_taprio_caps *caps = base->caps;
caps->broken_mqprio = true;
return 0;
}
default:
return -EOPNOTSUPP;
}
}
static LIST_HEAD(igb_block_cb_list); static LIST_HEAD(igb_block_cb_list);
static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type, static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
...@@ -2818,6 +2834,8 @@ static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type, ...@@ -2818,6 +2834,8 @@ static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
struct igb_adapter *adapter = netdev_priv(dev); struct igb_adapter *adapter = netdev_priv(dev);
switch (type) { switch (type) {
case TC_QUERY_CAPS:
return igb_tc_query_caps(adapter, type_data);
case TC_SETUP_QDISC_CBS: case TC_SETUP_QDISC_CBS:
return igb_offload_cbs(adapter, type_data); return igb_offload_cbs(adapter, type_data);
case TC_SETUP_BLOCK: case TC_SETUP_BLOCK:
......
...@@ -6214,10 +6214,10 @@ static int igc_tc_query_caps(struct igc_adapter *adapter, ...@@ -6214,10 +6214,10 @@ static int igc_tc_query_caps(struct igc_adapter *adapter,
case TC_SETUP_QDISC_TAPRIO: { case TC_SETUP_QDISC_TAPRIO: {
struct tc_taprio_caps *caps = base->caps; struct tc_taprio_caps *caps = base->caps;
if (hw->mac.type != igc_i225) caps->broken_mqprio = true;
return -EOPNOTSUPP;
caps->gate_mask_per_txq = true; if (hw->mac.type == igc_i225)
caps->gate_mask_per_txq = true;
return 0; return 0;
} }
......
...@@ -177,6 +177,11 @@ struct tc_mqprio_qopt_offload { ...@@ -177,6 +177,11 @@ struct tc_mqprio_qopt_offload {
struct tc_taprio_caps { struct tc_taprio_caps {
bool supports_queue_max_sdu:1; bool supports_queue_max_sdu:1;
bool gate_mask_per_txq:1; bool gate_mask_per_txq:1;
/* Device expects lower TXQ numbers to have higher priority over higher
* TXQs, regardless of their TC mapping. DO NOT USE FOR NEW DRIVERS,
* INSTEAD ENFORCE A PROPER TC:TXQ MAPPING COMING FROM USER SPACE.
*/
bool broken_mqprio:1;
}; };
struct tc_taprio_sched_entry { struct tc_taprio_sched_entry {
......
...@@ -1282,12 +1282,6 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1282,12 +1282,6 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
if (err) if (err)
goto err_out3; goto err_out3;
if (ops->init) {
err = ops->init(sch, tca[TCA_OPTIONS], extack);
if (err != 0)
goto err_out5;
}
if (tca[TCA_STAB]) { if (tca[TCA_STAB]) {
stab = qdisc_get_stab(tca[TCA_STAB], extack); stab = qdisc_get_stab(tca[TCA_STAB], extack);
if (IS_ERR(stab)) { if (IS_ERR(stab)) {
...@@ -1296,11 +1290,18 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1296,11 +1290,18 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
} }
rcu_assign_pointer(sch->stab, stab); rcu_assign_pointer(sch->stab, stab);
} }
if (ops->init) {
err = ops->init(sch, tca[TCA_OPTIONS], extack);
if (err != 0)
goto err_out5;
}
if (tca[TCA_RATE]) { if (tca[TCA_RATE]) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (sch->flags & TCQ_F_MQROOT) { if (sch->flags & TCQ_F_MQROOT) {
NL_SET_ERR_MSG(extack, "Cannot attach rate estimator to a multi-queue root qdisc"); NL_SET_ERR_MSG(extack, "Cannot attach rate estimator to a multi-queue root qdisc");
goto err_out4; goto err_out5;
} }
err = gen_new_estimator(&sch->bstats, err = gen_new_estimator(&sch->bstats,
...@@ -1311,7 +1312,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1311,7 +1312,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
tca[TCA_RATE]); tca[TCA_RATE]);
if (err) { if (err) {
NL_SET_ERR_MSG(extack, "Failed to generate new estimator"); NL_SET_ERR_MSG(extack, "Failed to generate new estimator");
goto err_out4; goto err_out5;
} }
} }
...@@ -1321,6 +1322,8 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1321,6 +1322,8 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
return sch; return sch;
err_out5: err_out5:
qdisc_put_stab(rtnl_dereference(sch->stab));
err_out4:
/* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */ /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */
if (ops->destroy) if (ops->destroy)
ops->destroy(sch); ops->destroy(sch);
...@@ -1332,16 +1335,6 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1332,16 +1335,6 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
err_out: err_out:
*errp = err; *errp = err;
return NULL; return NULL;
err_out4:
/*
* Any broken qdiscs that would require a ops->reset() here?
* The qdisc was never in action so it shouldn't be necessary.
*/
qdisc_put_stab(rtnl_dereference(sch->stab));
if (ops->destroy)
ops->destroy(sch);
goto err_out3;
} }
static int qdisc_change(struct Qdisc *sch, struct nlattr **tca, static int qdisc_change(struct Qdisc *sch, struct nlattr **tca,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment