mlxsw: spectrum_mr_tcam: Push Spectrum-specific operations into a separate file
authorJiri Pirko <jiri@mellanox.com>
Sun, 8 Jul 2018 20:51:19 +0000 (23:51 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 Jul 2018 23:24:17 +0000 (16:24 -0700)
Since Spectrum-2 has different handling of TCAM, push Spectrum MR TCAM
bits to a separate file accessible by ops which allows to implement
Spectrum-2 specific ops.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/Makefile
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum1_mr_tcam.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c

index 546a13c0974f839d5b8ba5b403f7301c2810843a..cd9a281e0395441d19d7ec827eebaff875988830 100644 (file)
@@ -20,7 +20,8 @@ mlxsw_spectrum-objs           := spectrum.o spectrum_buffers.o \
                                   spectrum_flower.o spectrum_cnt.o \
                                   spectrum_fid.o spectrum_ipip.o \
                                   spectrum_acl_flex_actions.o \
-                                  spectrum_mr.o spectrum_mr_tcam.o \
+                                  spectrum1_mr_tcam.o \
+                                  spectrum_mr_tcam.o spectrum_mr.o \
                                   spectrum_qdisc.o spectrum_span.o
 mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB)    += spectrum_dcb.o
 mlxsw_spectrum-$(CONFIG_NET_DEVLINK) += spectrum_dpipe.o
index bb8ed98d48612246dcf11aac66f6d3b23c779db0..ea72556b9e6a51fa62845c9619227331cbf2298a 100644 (file)
@@ -3623,6 +3623,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
 
        mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops;
        mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops;
+       mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops;
 
        mlxsw_sp->core = mlxsw_core;
        mlxsw_sp->bus_info = mlxsw_bus_info;
index 25ea06dc8bffbea246db30eed9f5070193d9210a..a3fff2ba1ccb9064956fb916c84dcef2b7e47d36 100644 (file)
@@ -146,6 +146,7 @@ struct mlxsw_sp_counter_pool;
 struct mlxsw_sp_fid_core;
 struct mlxsw_sp_kvdl;
 struct mlxsw_sp_kvdl_ops;
+struct mlxsw_sp_mr_tcam_ops;
 
 struct mlxsw_sp {
        struct mlxsw_sp_port **ports;
@@ -171,6 +172,7 @@ struct mlxsw_sp {
        } span;
        const struct mlxsw_sp_kvdl_ops *kvdl_ops;
        const struct mlxsw_afa_ops *afa_ops;
+       const struct mlxsw_sp_mr_tcam_ops *mr_tcam_ops;
 };
 
 static inline struct mlxsw_sp_upper *
@@ -681,4 +683,37 @@ void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port);
 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp);
 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp);
 
+/* spectrum_mr.c */
+enum mlxsw_sp_mr_route_prio {
+       MLXSW_SP_MR_ROUTE_PRIO_SG,
+       MLXSW_SP_MR_ROUTE_PRIO_STARG,
+       MLXSW_SP_MR_ROUTE_PRIO_CATCHALL,
+       __MLXSW_SP_MR_ROUTE_PRIO_MAX
+};
+
+#define MLXSW_SP_MR_ROUTE_PRIO_MAX (__MLXSW_SP_MR_ROUTE_PRIO_MAX - 1)
+
+struct mlxsw_sp_mr_route_key;
+
+struct mlxsw_sp_mr_tcam_ops {
+       size_t priv_size;
+       int (*init)(struct mlxsw_sp *mlxsw_sp, void *priv);
+       void (*fini)(void *priv);
+       size_t route_priv_size;
+       int (*route_create)(struct mlxsw_sp *mlxsw_sp, void *priv,
+                           void *route_priv,
+                           struct mlxsw_sp_mr_route_key *key,
+                           struct mlxsw_afa_block *afa_block,
+                           enum mlxsw_sp_mr_route_prio prio);
+       void (*route_destroy)(struct mlxsw_sp *mlxsw_sp, void *priv,
+                             void *route_priv,
+                             struct mlxsw_sp_mr_route_key *key);
+       int (*route_update)(struct mlxsw_sp *mlxsw_sp, void *route_priv,
+                           struct mlxsw_sp_mr_route_key *key,
+                           struct mlxsw_afa_block *afa_block);
+};
+
+/* spectrum1_mr_tcam.c */
+extern const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops;
+
 #endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum1_mr_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum1_mr_tcam.c
new file mode 100644 (file)
index 0000000..fc649fe
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * drivers/net/ethernet/mellanox/mlxsw/spectrum1_mr_tcam.c
+ * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
+ * Copyright (c) 2018 Jiri Pirko <jiri@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/parman.h>
+
+#include "reg.h"
+#include "spectrum.h"
+#include "core_acl_flex_actions.h"
+#include "spectrum_mr.h"
+
+struct mlxsw_sp1_mr_tcam_region {
+       struct mlxsw_sp *mlxsw_sp;
+       enum mlxsw_reg_rtar_key_type rtar_key_type;
+       struct parman *parman;
+       struct parman_prio *parman_prios;
+};
+
+struct mlxsw_sp1_mr_tcam {
+       struct mlxsw_sp1_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
+};
+
+struct mlxsw_sp1_mr_tcam_route {
+       struct parman_item parman_item;
+       struct parman_prio *parman_prio;
+};
+
+static int mlxsw_sp1_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
+                                          struct parman_item *parman_item,
+                                          struct mlxsw_sp_mr_route_key *key,
+                                          struct mlxsw_afa_block *afa_block)
+{
+       char rmft2_pl[MLXSW_REG_RMFT2_LEN];
+
+       switch (key->proto) {
+       case MLXSW_SP_L3_PROTO_IPV4:
+               mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
+                                         key->vrid,
+                                         MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
+                                         ntohl(key->group.addr4),
+                                         ntohl(key->group_mask.addr4),
+                                         ntohl(key->source.addr4),
+                                         ntohl(key->source_mask.addr4),
+                                         mlxsw_afa_block_first_set(afa_block));
+               break;
+       case MLXSW_SP_L3_PROTO_IPV6:
+               mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
+                                         key->vrid,
+                                         MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
+                                         key->group.addr6,
+                                         key->group_mask.addr6,
+                                         key->source.addr6,
+                                         key->source_mask.addr6,
+                                         mlxsw_afa_block_first_set(afa_block));
+       }
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
+}
+
+static int mlxsw_sp1_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp,
+                                         struct parman_item *parman_item,
+                                         struct mlxsw_sp_mr_route_key *key)
+{
+       struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
+       char rmft2_pl[MLXSW_REG_RMFT2_LEN];
+
+       switch (key->proto) {
+       case MLXSW_SP_L3_PROTO_IPV4:
+               mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
+                                         key->vrid, 0, 0, 0, 0, 0, 0, NULL);
+               break;
+       case MLXSW_SP_L3_PROTO_IPV6:
+               mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
+                                         key->vrid, 0, 0, zero_addr, zero_addr,
+                                         zero_addr, zero_addr, NULL);
+               break;
+       }
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
+}
+
+static struct mlxsw_sp1_mr_tcam_region *
+mlxsw_sp1_mr_tcam_protocol_region(struct mlxsw_sp1_mr_tcam *mr_tcam,
+                                 enum mlxsw_sp_l3proto proto)
+{
+       return &mr_tcam->tcam_regions[proto];
+}
+
+static int
+mlxsw_sp1_mr_tcam_route_parman_item_add(struct mlxsw_sp1_mr_tcam *mr_tcam,
+                                       struct mlxsw_sp1_mr_tcam_route *route,
+                                       struct mlxsw_sp_mr_route_key *key,
+                                       enum mlxsw_sp_mr_route_prio prio)
+{
+       struct mlxsw_sp1_mr_tcam_region *tcam_region;
+       int err;
+
+       tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
+       err = parman_item_add(tcam_region->parman,
+                             &tcam_region->parman_prios[prio],
+                             &route->parman_item);
+       if (err)
+               return err;
+
+       route->parman_prio = &tcam_region->parman_prios[prio];
+       return 0;
+}
+
+static void
+mlxsw_sp1_mr_tcam_route_parman_item_remove(struct mlxsw_sp1_mr_tcam *mr_tcam,
+                                          struct mlxsw_sp1_mr_tcam_route *route,
+                                          struct mlxsw_sp_mr_route_key *key)
+{
+       struct mlxsw_sp1_mr_tcam_region *tcam_region;
+
+       tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
+       parman_item_remove(tcam_region->parman,
+                          route->parman_prio, &route->parman_item);
+}
+
+static int
+mlxsw_sp1_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
+                              void *route_priv,
+                              struct mlxsw_sp_mr_route_key *key,
+                              struct mlxsw_afa_block *afa_block,
+                              enum mlxsw_sp_mr_route_prio prio)
+{
+       struct mlxsw_sp1_mr_tcam_route *route = route_priv;
+       struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
+       int err;
+
+       err = mlxsw_sp1_mr_tcam_route_parman_item_add(mr_tcam, route,
+                                                     key, prio);
+       if (err)
+               return err;
+
+       err = mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
+                                             key, afa_block);
+       if (err)
+               goto err_route_replace;
+       return 0;
+
+err_route_replace:
+       mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
+       return err;
+}
+
+static void
+mlxsw_sp1_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
+                               void *route_priv,
+                               struct mlxsw_sp_mr_route_key *key)
+{
+       struct mlxsw_sp1_mr_tcam_route *route = route_priv;
+       struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
+
+       mlxsw_sp1_mr_tcam_route_remove(mlxsw_sp, &route->parman_item, key);
+       mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
+}
+
+static int
+mlxsw_sp1_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
+                              void *route_priv,
+                              struct mlxsw_sp_mr_route_key *key,
+                              struct mlxsw_afa_block *afa_block)
+{
+       struct mlxsw_sp1_mr_tcam_route *route = route_priv;
+
+       return mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
+                                              key, afa_block);
+}
+
+#define MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT 16
+#define MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP 16
+
+static int
+mlxsw_sp1_mr_tcam_region_alloc(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
+{
+       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
+       char rtar_pl[MLXSW_REG_RTAR_LEN];
+
+       mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
+                           mr_tcam_region->rtar_key_type,
+                           MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
+}
+
+static void
+mlxsw_sp1_mr_tcam_region_free(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
+{
+       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
+       char rtar_pl[MLXSW_REG_RTAR_LEN];
+
+       mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
+                           mr_tcam_region->rtar_key_type, 0);
+       mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
+}
+
+static int mlxsw_sp1_mr_tcam_region_parman_resize(void *priv,
+                                                 unsigned long new_count)
+{
+       struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
+       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
+       char rtar_pl[MLXSW_REG_RTAR_LEN];
+       u64 max_tcam_rules;
+
+       max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
+       if (new_count > max_tcam_rules)
+               return -EINVAL;
+       mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
+                           mr_tcam_region->rtar_key_type, new_count);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
+}
+
+static void mlxsw_sp1_mr_tcam_region_parman_move(void *priv,
+                                                unsigned long from_index,
+                                                unsigned long to_index,
+                                                unsigned long count)
+{
+       struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
+       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
+       char rrcr_pl[MLXSW_REG_RRCR_LEN];
+
+       mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
+                           from_index, count,
+                           mr_tcam_region->rtar_key_type, to_index);
+       mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
+}
+
+static const struct parman_ops mlxsw_sp1_mr_tcam_region_parman_ops = {
+       .base_count     = MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT,
+       .resize_step    = MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP,
+       .resize         = mlxsw_sp1_mr_tcam_region_parman_resize,
+       .move           = mlxsw_sp1_mr_tcam_region_parman_move,
+       .algo           = PARMAN_ALGO_TYPE_LSORT,
+};
+
+static int
+mlxsw_sp1_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
+                             struct mlxsw_sp1_mr_tcam_region *mr_tcam_region,
+                             enum mlxsw_reg_rtar_key_type rtar_key_type)
+{
+       struct parman_prio *parman_prios;
+       struct parman *parman;
+       int err;
+       int i;
+
+       mr_tcam_region->rtar_key_type = rtar_key_type;
+       mr_tcam_region->mlxsw_sp = mlxsw_sp;
+
+       err = mlxsw_sp1_mr_tcam_region_alloc(mr_tcam_region);
+       if (err)
+               return err;
+
+       parman = parman_create(&mlxsw_sp1_mr_tcam_region_parman_ops,
+                              mr_tcam_region);
+       if (!parman) {
+               err = -ENOMEM;
+               goto err_parman_create;
+       }
+       mr_tcam_region->parman = parman;
+
+       parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
+                                    sizeof(*parman_prios), GFP_KERNEL);
+       if (!parman_prios) {
+               err = -ENOMEM;
+               goto err_parman_prios_alloc;
+       }
+       mr_tcam_region->parman_prios = parman_prios;
+
+       for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
+               parman_prio_init(mr_tcam_region->parman,
+                                &mr_tcam_region->parman_prios[i], i);
+       return 0;
+
+err_parman_prios_alloc:
+       parman_destroy(parman);
+err_parman_create:
+       mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
+       return err;
+}
+
+static void
+mlxsw_sp1_mr_tcam_region_fini(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
+{
+       int i;
+
+       for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
+               parman_prio_fini(&mr_tcam_region->parman_prios[i]);
+       kfree(mr_tcam_region->parman_prios);
+       parman_destroy(mr_tcam_region->parman);
+       mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
+}
+
+static int mlxsw_sp1_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
+{
+       struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
+       struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
+       u32 rtar_key;
+       int err;
+
+       if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
+               return -EIO;
+
+       rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
+       err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
+                                           &region[MLXSW_SP_L3_PROTO_IPV4],
+                                           rtar_key);
+       if (err)
+               return err;
+
+       rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
+       err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
+                                           &region[MLXSW_SP_L3_PROTO_IPV6],
+                                           rtar_key);
+       if (err)
+               goto err_ipv6_region_init;
+
+       return 0;
+
+err_ipv6_region_init:
+       mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
+       return err;
+}
+
+static void mlxsw_sp1_mr_tcam_fini(void *priv)
+{
+       struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
+       struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
+
+       mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV6]);
+       mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
+}
+
+const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops = {
+       .priv_size = sizeof(struct mlxsw_sp1_mr_tcam),
+       .init = mlxsw_sp1_mr_tcam_init,
+       .fini = mlxsw_sp1_mr_tcam_fini,
+       .route_priv_size = sizeof(struct mlxsw_sp1_mr_tcam_route),
+       .route_create = mlxsw_sp1_mr_tcam_route_create,
+       .route_destroy = mlxsw_sp1_mr_tcam_route_destroy,
+       .route_update = mlxsw_sp1_mr_tcam_route_update,
+};
index a82539609d492733332c2a6a18eed0952e4615c0..98dcaf78365c2cf8ad5539c1c11809d9e8e089e1 100644 (file)
@@ -1075,6 +1075,6 @@ void mlxsw_sp_mr_fini(struct mlxsw_sp *mlxsw_sp)
        struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 
        cancel_delayed_work_sync(&mr->stats_update_dw);
-       mr->mr_ops->fini(mr->priv);
+       mr->mr_ops->fini(mlxsw_sp, mr->priv);
        kfree(mr);
 }
index 7c864a86811d5321a8f822b438c56d43cdfb8342..c92fa90dca31e4c49f839e96051aef8cc9fd63b7 100644 (file)
@@ -46,15 +46,6 @@ enum mlxsw_sp_mr_route_action {
        MLXSW_SP_MR_ROUTE_ACTION_TRAP_AND_FORWARD,
 };
 
-enum mlxsw_sp_mr_route_prio {
-       MLXSW_SP_MR_ROUTE_PRIO_SG,
-       MLXSW_SP_MR_ROUTE_PRIO_STARG,
-       MLXSW_SP_MR_ROUTE_PRIO_CATCHALL,
-       __MLXSW_SP_MR_ROUTE_PRIO_MAX
-};
-
-#define MLXSW_SP_MR_ROUTE_PRIO_MAX (__MLXSW_SP_MR_ROUTE_PRIO_MAX - 1)
-
 struct mlxsw_sp_mr_route_key {
        int vrid;
        enum mlxsw_sp_l3proto proto;
@@ -101,7 +92,7 @@ struct mlxsw_sp_mr_ops {
                              u16 erif_index);
        void (*route_destroy)(struct mlxsw_sp *mlxsw_sp, void *priv,
                              void *route_priv);
-       void (*fini)(void *priv);
+       void (*fini)(struct mlxsw_sp *mlxsw_sp, void *priv);
 };
 
 struct mlxsw_sp_mr;
index 87d9423dacdc2ac1badc0eb061dda51b1c0d45c5..e9c9f1f45b9da0afaf8fe367293259ba49fe9345 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c
- * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
+ * Copyright (c) 2018 Jiri Pirko <jiri@mellanox.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -35,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
-#include <linux/parman.h>
 
 #include "spectrum_mr_tcam.h"
 #include "reg.h"
 #include "core_acl_flex_actions.h"
 #include "spectrum_mr.h"
 
-struct mlxsw_sp_mr_tcam_region {
-       struct mlxsw_sp *mlxsw_sp;
-       enum mlxsw_reg_rtar_key_type rtar_key_type;
-       struct parman *parman;
-       struct parman_prio *parman_prios;
-};
-
 struct mlxsw_sp_mr_tcam {
-       struct mlxsw_sp_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
+       void *priv;
 };
 
 /* This struct maps to one RIGR2 register entry */
@@ -220,12 +213,11 @@ struct mlxsw_sp_mr_tcam_route {
        struct mlxsw_sp_mr_tcam_erif_list erif_list;
        struct mlxsw_afa_block *afa_block;
        u32 counter_index;
-       struct parman_item parman_item;
-       struct parman_prio *parman_prio;
        enum mlxsw_sp_mr_route_action action;
        struct mlxsw_sp_mr_route_key key;
        u16 irif_index;
        u16 min_mtu;
+       void *priv;
 };
 
 static struct mlxsw_afa_block *
@@ -296,60 +288,6 @@ mlxsw_sp_mr_tcam_afa_block_destroy(struct mlxsw_afa_block *afa_block)
        mlxsw_afa_block_destroy(afa_block);
 }
 
-static int mlxsw_sp_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
-                                         struct parman_item *parman_item,
-                                         struct mlxsw_sp_mr_route_key *key,
-                                         struct mlxsw_afa_block *afa_block)
-{
-       char rmft2_pl[MLXSW_REG_RMFT2_LEN];
-
-       switch (key->proto) {
-       case MLXSW_SP_L3_PROTO_IPV4:
-               mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
-                                         key->vrid,
-                                         MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
-                                         ntohl(key->group.addr4),
-                                         ntohl(key->group_mask.addr4),
-                                         ntohl(key->source.addr4),
-                                         ntohl(key->source_mask.addr4),
-                                         mlxsw_afa_block_first_set(afa_block));
-               break;
-       case MLXSW_SP_L3_PROTO_IPV6:
-               mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
-                                         key->vrid,
-                                         MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
-                                         key->group.addr6,
-                                         key->group_mask.addr6,
-                                         key->source.addr6,
-                                         key->source_mask.addr6,
-                                         mlxsw_afa_block_first_set(afa_block));
-       }
-
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
-}
-
-static int mlxsw_sp_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp, int vrid,
-                                        struct mlxsw_sp_mr_route_key *key,
-                                        struct parman_item *parman_item)
-{
-       struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
-       char rmft2_pl[MLXSW_REG_RMFT2_LEN];
-
-       switch (key->proto) {
-       case MLXSW_SP_L3_PROTO_IPV4:
-               mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
-                                         vrid, 0, 0, 0, 0, 0, 0, NULL);
-               break;
-       case MLXSW_SP_L3_PROTO_IPV6:
-               mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
-                                         vrid, 0, 0, zero_addr, zero_addr,
-                                         zero_addr, zero_addr, NULL);
-               break;
-       }
-
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
-}
-
 static int
 mlxsw_sp_mr_tcam_erif_populate(struct mlxsw_sp *mlxsw_sp,
                               struct mlxsw_sp_mr_tcam_erif_list *erif_list,
@@ -369,51 +307,12 @@ mlxsw_sp_mr_tcam_erif_populate(struct mlxsw_sp *mlxsw_sp,
        return 0;
 }
 
-static struct mlxsw_sp_mr_tcam_region *
-mlxsw_sp_mr_tcam_protocol_region(struct mlxsw_sp_mr_tcam *mr_tcam,
-                                enum mlxsw_sp_l3proto proto)
-{
-       return &mr_tcam->tcam_regions[proto];
-}
-
-static int
-mlxsw_sp_mr_tcam_route_parman_item_add(struct mlxsw_sp_mr_tcam *mr_tcam,
-                                      struct mlxsw_sp_mr_tcam_route *route,
-                                      enum mlxsw_sp_mr_route_prio prio)
-{
-       struct mlxsw_sp_mr_tcam_region *tcam_region;
-       int err;
-
-       tcam_region = mlxsw_sp_mr_tcam_protocol_region(mr_tcam,
-                                                      route->key.proto);
-       err = parman_item_add(tcam_region->parman,
-                             &tcam_region->parman_prios[prio],
-                             &route->parman_item);
-       if (err)
-               return err;
-
-       route->parman_prio = &tcam_region->parman_prios[prio];
-       return 0;
-}
-
-static void
-mlxsw_sp_mr_tcam_route_parman_item_remove(struct mlxsw_sp_mr_tcam *mr_tcam,
-                                         struct mlxsw_sp_mr_tcam_route *route)
-{
-       struct mlxsw_sp_mr_tcam_region *tcam_region;
-
-       tcam_region = mlxsw_sp_mr_tcam_protocol_region(mr_tcam,
-                                                      route->key.proto);
-
-       parman_item_remove(tcam_region->parman,
-                          route->parman_prio, &route->parman_item);
-}
-
 static int
 mlxsw_sp_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
                              void *route_priv,
                              struct mlxsw_sp_mr_route_params *route_params)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam_route *route = route_priv;
        struct mlxsw_sp_mr_tcam *mr_tcam = priv;
        int err;
@@ -447,22 +346,23 @@ mlxsw_sp_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
                goto err_afa_block_create;
        }
 
-       /* Allocate place in the TCAM */
-       err = mlxsw_sp_mr_tcam_route_parman_item_add(mr_tcam, route,
-                                                    route_params->prio);
-       if (err)
-               goto err_parman_item_add;
+       route->priv = kzalloc(ops->route_priv_size, GFP_KERNEL);
+       if (!route->priv) {
+               err = -ENOMEM;
+               goto err_route_priv_alloc;
+       }
 
        /* Write the route to the TCAM */
-       err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
-                                            &route->key, route->afa_block);
+       err = ops->route_create(mlxsw_sp, mr_tcam->priv, route->priv,
+                               &route->key, route->afa_block,
+                               route_params->prio);
        if (err)
-               goto err_route_replace;
+               goto err_route_create;
        return 0;
 
-err_route_replace:
-       mlxsw_sp_mr_tcam_route_parman_item_remove(mr_tcam, route);
-err_parman_item_add:
+err_route_create:
+       kfree(route->priv);
+err_route_priv_alloc:
        mlxsw_sp_mr_tcam_afa_block_destroy(route->afa_block);
 err_afa_block_create:
        mlxsw_sp_flow_counter_free(mlxsw_sp, route->counter_index);
@@ -475,12 +375,12 @@ err_counter_alloc:
 static void mlxsw_sp_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp,
                                           void *priv, void *route_priv)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam_route *route = route_priv;
        struct mlxsw_sp_mr_tcam *mr_tcam = priv;
 
-       mlxsw_sp_mr_tcam_route_remove(mlxsw_sp, route->key.vrid,
-                                     &route->key, &route->parman_item);
-       mlxsw_sp_mr_tcam_route_parman_item_remove(mr_tcam, route);
+       ops->route_destroy(mlxsw_sp, mr_tcam->priv, route->priv, &route->key);
+       kfree(route->priv);
        mlxsw_sp_mr_tcam_afa_block_destroy(route->afa_block);
        mlxsw_sp_flow_counter_free(mlxsw_sp, route->counter_index);
        mlxsw_sp_mr_erif_list_flush(mlxsw_sp, &route->erif_list);
@@ -501,6 +401,7 @@ mlxsw_sp_mr_tcam_route_action_update(struct mlxsw_sp *mlxsw_sp,
                                     void *route_priv,
                                     enum mlxsw_sp_mr_route_action route_action)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam_route *route = route_priv;
        struct mlxsw_afa_block *afa_block;
        int err;
@@ -515,8 +416,7 @@ mlxsw_sp_mr_tcam_route_action_update(struct mlxsw_sp *mlxsw_sp,
                return PTR_ERR(afa_block);
 
        /* Update the TCAM route entry */
-       err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
-                                            &route->key, afa_block);
+       err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
        if (err)
                goto err;
 
@@ -533,6 +433,7 @@ err:
 static int mlxsw_sp_mr_tcam_route_min_mtu_update(struct mlxsw_sp *mlxsw_sp,
                                                 void *route_priv, u16 min_mtu)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam_route *route = route_priv;
        struct mlxsw_afa_block *afa_block;
        int err;
@@ -548,8 +449,7 @@ static int mlxsw_sp_mr_tcam_route_min_mtu_update(struct mlxsw_sp *mlxsw_sp,
                return PTR_ERR(afa_block);
 
        /* Update the TCAM route entry */
-       err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
-                                            &route->key, afa_block);
+       err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
        if (err)
                goto err;
 
@@ -595,6 +495,7 @@ static int mlxsw_sp_mr_tcam_route_erif_add(struct mlxsw_sp *mlxsw_sp,
 static int mlxsw_sp_mr_tcam_route_erif_del(struct mlxsw_sp *mlxsw_sp,
                                           void *route_priv, u16 erif_index)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam_route *route = route_priv;
        struct mlxsw_sp_mr_erif_sublist *erif_sublist;
        struct mlxsw_sp_mr_tcam_erif_list erif_list;
@@ -629,8 +530,7 @@ static int mlxsw_sp_mr_tcam_route_erif_del(struct mlxsw_sp *mlxsw_sp,
        }
 
        /* Update the TCAM route entry */
-       err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
-                                            &route->key, afa_block);
+       err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
        if (err)
                goto err_route_write;
 
@@ -652,6 +552,7 @@ static int
 mlxsw_sp_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp, void *route_priv,
                              struct mlxsw_sp_mr_route_info *route_info)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam_route *route = route_priv;
        struct mlxsw_sp_mr_tcam_erif_list erif_list;
        struct mlxsw_afa_block *afa_block;
@@ -676,8 +577,7 @@ mlxsw_sp_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp, void *route_priv,
        }
 
        /* Update the TCAM route entry */
-       err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
-                                            &route->key, afa_block);
+       err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
        if (err)
                goto err_route_write;
 
@@ -698,167 +598,36 @@ err_erif_populate:
        return err;
 }
 
-#define MLXSW_SP_MR_TCAM_REGION_BASE_COUNT 16
-#define MLXSW_SP_MR_TCAM_REGION_RESIZE_STEP 16
-
-static int
-mlxsw_sp_mr_tcam_region_alloc(struct mlxsw_sp_mr_tcam_region *mr_tcam_region)
-{
-       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
-       char rtar_pl[MLXSW_REG_RTAR_LEN];
-
-       mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
-                           mr_tcam_region->rtar_key_type,
-                           MLXSW_SP_MR_TCAM_REGION_BASE_COUNT);
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
-}
-
-static void
-mlxsw_sp_mr_tcam_region_free(struct mlxsw_sp_mr_tcam_region *mr_tcam_region)
-{
-       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
-       char rtar_pl[MLXSW_REG_RTAR_LEN];
-
-       mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
-                           mr_tcam_region->rtar_key_type, 0);
-       mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
-}
-
-static int mlxsw_sp_mr_tcam_region_parman_resize(void *priv,
-                                                unsigned long new_count)
-{
-       struct mlxsw_sp_mr_tcam_region *mr_tcam_region = priv;
-       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
-       char rtar_pl[MLXSW_REG_RTAR_LEN];
-       u64 max_tcam_rules;
-
-       max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
-       if (new_count > max_tcam_rules)
-               return -EINVAL;
-       mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
-                           mr_tcam_region->rtar_key_type, new_count);
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
-}
-
-static void mlxsw_sp_mr_tcam_region_parman_move(void *priv,
-                                               unsigned long from_index,
-                                               unsigned long to_index,
-                                               unsigned long count)
-{
-       struct mlxsw_sp_mr_tcam_region *mr_tcam_region = priv;
-       struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
-       char rrcr_pl[MLXSW_REG_RRCR_LEN];
-
-       mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
-                           from_index, count,
-                           mr_tcam_region->rtar_key_type, to_index);
-       mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
-}
-
-static const struct parman_ops mlxsw_sp_mr_tcam_region_parman_ops = {
-       .base_count     = MLXSW_SP_MR_TCAM_REGION_BASE_COUNT,
-       .resize_step    = MLXSW_SP_MR_TCAM_REGION_RESIZE_STEP,
-       .resize         = mlxsw_sp_mr_tcam_region_parman_resize,
-       .move           = mlxsw_sp_mr_tcam_region_parman_move,
-       .algo           = PARMAN_ALGO_TYPE_LSORT,
-};
-
-static int
-mlxsw_sp_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
-                            struct mlxsw_sp_mr_tcam_region *mr_tcam_region,
-                            enum mlxsw_reg_rtar_key_type rtar_key_type)
-{
-       struct parman_prio *parman_prios;
-       struct parman *parman;
-       int err;
-       int i;
-
-       mr_tcam_region->rtar_key_type = rtar_key_type;
-       mr_tcam_region->mlxsw_sp = mlxsw_sp;
-
-       err = mlxsw_sp_mr_tcam_region_alloc(mr_tcam_region);
-       if (err)
-               return err;
-
-       parman = parman_create(&mlxsw_sp_mr_tcam_region_parman_ops,
-                              mr_tcam_region);
-       if (!parman) {
-               err = -ENOMEM;
-               goto err_parman_create;
-       }
-       mr_tcam_region->parman = parman;
-
-       parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
-                                    sizeof(*parman_prios), GFP_KERNEL);
-       if (!parman_prios) {
-               err = -ENOMEM;
-               goto err_parman_prios_alloc;
-       }
-       mr_tcam_region->parman_prios = parman_prios;
-
-       for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
-               parman_prio_init(mr_tcam_region->parman,
-                                &mr_tcam_region->parman_prios[i], i);
-       return 0;
-
-err_parman_prios_alloc:
-       parman_destroy(parman);
-err_parman_create:
-       mlxsw_sp_mr_tcam_region_free(mr_tcam_region);
-       return err;
-}
-
-static void
-mlxsw_sp_mr_tcam_region_fini(struct mlxsw_sp_mr_tcam_region *mr_tcam_region)
-{
-       int i;
-
-       for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
-               parman_prio_fini(&mr_tcam_region->parman_prios[i]);
-       kfree(mr_tcam_region->parman_prios);
-       parman_destroy(mr_tcam_region->parman);
-       mlxsw_sp_mr_tcam_region_free(mr_tcam_region);
-}
-
 static int mlxsw_sp_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam *mr_tcam = priv;
-       struct mlxsw_sp_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
-       u32 rtar_key;
        int err;
 
-       if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MC_ERIF_LIST_ENTRIES) ||
-           !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
+       if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MC_ERIF_LIST_ENTRIES))
                return -EIO;
 
-       rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
-       err = mlxsw_sp_mr_tcam_region_init(mlxsw_sp,
-                                          &region[MLXSW_SP_L3_PROTO_IPV4],
-                                          rtar_key);
-       if (err)
-               return err;
+       mr_tcam->priv = kzalloc(ops->priv_size, GFP_KERNEL);
+       if (!mr_tcam->priv)
+               return -ENOMEM;
 
-       rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
-       err = mlxsw_sp_mr_tcam_region_init(mlxsw_sp,
-                                          &region[MLXSW_SP_L3_PROTO_IPV6],
-                                          rtar_key);
+       err = ops->init(mlxsw_sp, mr_tcam->priv);
        if (err)
-               goto err_ipv6_region_init;
-
+               goto err_init;
        return 0;
 
-err_ipv6_region_init:
-       mlxsw_sp_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
+err_init:
+       kfree(mr_tcam->priv);
        return err;
 }
 
-static void mlxsw_sp_mr_tcam_fini(void *priv)
+static void mlxsw_sp_mr_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
 {
+       const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
        struct mlxsw_sp_mr_tcam *mr_tcam = priv;
-       struct mlxsw_sp_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
 
-       mlxsw_sp_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV6]);
-       mlxsw_sp_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
+       ops->fini(mr_tcam->priv);
+       kfree(mr_tcam->priv);
 }
 
 const struct mlxsw_sp_mr_ops mlxsw_sp_mr_tcam_ops = {