@@ -1169,6 +1169,14 @@ struct netdev_net_notifier {
* This is always called from the stack with the rtnl lock held and netif
* tx queues stopped. This allows the netdevice to perform queue
* management safely.
+ * int (*ndo_setup_tc_conduit)(struct net_device *dev, int user_port,
+ * enum tc_setup_type type, void *type_data);
+ * Called to setup any 'tc' scheduler, classifier or action on the user
+ * port @user_port via the conduit port @dev. This is useful if the hw
+ * supports improved offloading capability through the conduit port.
+ * This is always called from the stack with the rtnl lock held and netif
+ * tx queues stopped. This allows the netdevice to perform queue
+ * management safely.
*
* Fiber Channel over Ethernet (FCoE) offload functions.
* int (*ndo_fcoe_enable)(struct net_device *dev);
@@ -1475,6 +1483,10 @@ struct net_device_ops {
int (*ndo_setup_tc)(struct net_device *dev,
enum tc_setup_type type,
void *type_data);
+ int (*ndo_setup_tc_conduit)(struct net_device *dev,
+ int user_port,
+ enum tc_setup_type type,
+ void *type_data);
#if IS_ENABLED(CONFIG_FCOE)
int (*ndo_fcoe_enable)(struct net_device *dev);
int (*ndo_fcoe_disable)(struct net_device *dev);
@@ -1725,6 +1725,46 @@ static int dsa_user_setup_ft_block(struct dsa_switch *ds, int port,
return conduit->netdev_ops->ndo_setup_tc(conduit, TC_SETUP_FT, type_data);
}
+static int dsa_user_setup_qdisc(struct net_device *dev,
+ enum tc_setup_type type, void *type_data)
+{
+ struct dsa_port *dp = dsa_user_to_port(dev);
+ struct dsa_switch *ds = dp->ds;
+ struct net_device *conduit;
+ int ret = -EOPNOTSUPP;
+
+ conduit = dsa_port_to_conduit(dsa_to_port(ds, dp->index));
+ if (conduit->netdev_ops->ndo_setup_tc_conduit) {
+ ret = conduit->netdev_ops->ndo_setup_tc_conduit(conduit,
+ dp->index,
+ type,
+ type_data);
+ if (ret && ret != -EOPNOTSUPP) {
+ netdev_err(dev,
+ "qdisc offload failed on conduit %s: %d\n",
+ conduit->name, ret);
+ return ret;
+ }
+ }
+
+ /* Try to offload the requested qdisc via user port. This is necessary
+ * if the traffic is forwarded by the hw dsa switch.
+ */
+ if (ds->ops->port_setup_tc) {
+ int err;
+
+ err = ds->ops->port_setup_tc(ds, dp->index, type, type_data);
+ if (err != -EOPNOTSUPP) {
+ if (err)
+ netdev_err(dev, "qdisc offload failed: %d\n",
+ err);
+ ret = err;
+ }
+ }
+
+ return ret;
+}
+
static int dsa_user_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -1737,13 +1777,8 @@ static int dsa_user_setup_tc(struct net_device *dev, enum tc_setup_type type,
case TC_SETUP_FT:
return dsa_user_setup_ft_block(ds, dp->index, type_data);
default:
- break;
+ return dsa_user_setup_qdisc(dev, type, type_data);
}
-
- if (!ds->ops->port_setup_tc)
- return -EOPNOTSUPP;
-
- return ds->ops->port_setup_tc(ds, dp->index, type, type_data);
}
static int dsa_user_get_rxnfc(struct net_device *dev,
Some DSA hw switches do not support Qdisc offloading or the mac chip has more fine grained QoS capabilities with respect to the hw switch (e.g. Airoha EN7581 mac chip has more hw QoS and buffering capabilities with respect to the mt7530 switch). On the other hand, configuring the switch cpu port via tc does not allow to address all possible use-cases (e.g. shape just tcp traffic with dst port 80 transmitted on lan0). Introduce ndo_setup_tc_conduit callback in order to allow tc to offload Qdisc policies for the specified user ports configuring the hw switch cpu port (mac chip). Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> --- include/linux/netdevice.h | 12 ++++++++++ net/dsa/user.c | 47 ++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 6 deletions(-)