mlxsw: spectrum_qdisc: Support offloading of ETS Qdisc
authorPetr Machata <petrm@mellanox.com>
Wed, 18 Dec 2019 14:55:19 +0000 (14:55 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 18 Dec 2019 21:32:30 +0000 (13:32 -0800)
Handle TC_SETUP_QDISC_ETS, add a new ops structure for the ETS Qdisc.
Invoke the extended prio handlers implemented in the previous patch. For
stats ops, invoke directly the prio callbacks, which are not sensitive to
differences between PRIO and ETS.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c

index 0d8fce7..ea63204 100644 (file)
@@ -1796,6 +1796,8 @@ static int mlxsw_sp_setup_tc(struct net_device *dev, enum tc_setup_type type,
                return mlxsw_sp_setup_tc_red(mlxsw_sp_port, type_data);
        case TC_SETUP_QDISC_PRIO:
                return mlxsw_sp_setup_tc_prio(mlxsw_sp_port, type_data);
+       case TC_SETUP_QDISC_ETS:
+               return mlxsw_sp_setup_tc_ets(mlxsw_sp_port, type_data);
        default:
                return -EOPNOTSUPP;
        }
index 347bec9..948ef47 100644 (file)
@@ -852,6 +852,8 @@ int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
                          struct tc_red_qopt_offload *p);
 int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
                           struct tc_prio_qopt_offload *p);
+int mlxsw_sp_setup_tc_ets(struct mlxsw_sp_port *mlxsw_sp_port,
+                         struct tc_ets_qopt_offload *p);
 
 /* spectrum_fid.c */
 bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index);
index d513af4..81a2c08 100644 (file)
@@ -18,6 +18,7 @@ enum mlxsw_sp_qdisc_type {
        MLXSW_SP_QDISC_NO_QDISC,
        MLXSW_SP_QDISC_RED,
        MLXSW_SP_QDISC_PRIO,
+       MLXSW_SP_QDISC_ETS,
 };
 
 struct mlxsw_sp_qdisc_ops {
@@ -680,6 +681,55 @@ static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_prio = {
        .clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats,
 };
 
+static int
+mlxsw_sp_qdisc_ets_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
+                               struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
+                               void *params)
+{
+       struct tc_ets_qopt_offload_replace_params *p = params;
+
+       return __mlxsw_sp_qdisc_ets_check_params(p->bands);
+}
+
+static int
+mlxsw_sp_qdisc_ets_replace(struct mlxsw_sp_port *mlxsw_sp_port,
+                          struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
+                          void *params)
+{
+       struct tc_ets_qopt_offload_replace_params *p = params;
+
+       return __mlxsw_sp_qdisc_ets_replace(mlxsw_sp_port, p->bands,
+                                           p->quanta, p->weights, p->priomap);
+}
+
+static void
+mlxsw_sp_qdisc_ets_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
+                            struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
+                            void *params)
+{
+       struct tc_ets_qopt_offload_replace_params *p = params;
+
+       __mlxsw_sp_qdisc_ets_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc,
+                                      p->qstats);
+}
+
+static int
+mlxsw_sp_qdisc_ets_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
+                          struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
+{
+       return __mlxsw_sp_qdisc_ets_destroy(mlxsw_sp_port);
+}
+
+static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_ets = {
+       .type = MLXSW_SP_QDISC_ETS,
+       .check_params = mlxsw_sp_qdisc_ets_check_params,
+       .replace = mlxsw_sp_qdisc_ets_replace,
+       .unoffload = mlxsw_sp_qdisc_ets_unoffload,
+       .destroy = mlxsw_sp_qdisc_ets_destroy,
+       .get_stats = mlxsw_sp_qdisc_get_prio_stats,
+       .clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats,
+};
+
 /* Linux allows linking of Qdiscs to arbitrary classes (so long as the resulting
  * graph is free of cycles). These operations do not change the parent handle
  * though, which means it can be incomplete (if there is more than one class
@@ -772,6 +822,40 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
        }
 }
 
+int mlxsw_sp_setup_tc_ets(struct mlxsw_sp_port *mlxsw_sp_port,
+                         struct tc_ets_qopt_offload *p)
+{
+       struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
+
+       mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, true);
+       if (!mlxsw_sp_qdisc)
+               return -EOPNOTSUPP;
+
+       if (p->command == TC_ETS_REPLACE)
+               return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
+                                             mlxsw_sp_qdisc,
+                                             &mlxsw_sp_qdisc_ops_ets,
+                                             &p->replace_params);
+
+       if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle,
+                                   MLXSW_SP_QDISC_ETS))
+               return -EOPNOTSUPP;
+
+       switch (p->command) {
+       case TC_ETS_DESTROY:
+               return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
+       case TC_ETS_STATS:
+               return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
+                                               &p->stats);
+       case TC_ETS_GRAFT:
+               return __mlxsw_sp_qdisc_ets_graft(mlxsw_sp_port, mlxsw_sp_qdisc,
+                                                 p->graft_params.band,
+                                                 p->graft_params.child_handle);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port)
 {
        struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;