diff mbox series

[net-next/mlxsw,internal,preRFC,3/3] mlxsw: spectrum: acl: Implement delta for ERP

Message ID 20180805130133.6812-4-jiri@resnulli.us (mailing list archive)
State RFC
Headers show
Series mlxsw: Introduce ERP sharing by multiple masks - static approach | expand

Commit Message

Jiri Pirko Aug. 5, 2018, 1:01 p.m. UTC
From: Jiri Pirko <jiri@mellanox.com>

Allow ERP sharing for multiple mask. Do it by properly implementing
delta_create() objagg object. Use the computed delta info for inserting
rules in A-TCAM.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlxsw/reg.h          |  8 +-
 .../ethernet/mellanox/mlxsw/spectrum_acl_atcam.c   | 15 +++-
 .../net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c | 91 +++++++++++++++++++++-
 .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.h    | 14 ++++
 4 files changed, 122 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 6e8b619b769b..35b2bb5bc0fa 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -2765,8 +2765,9 @@  static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid,
 					u32 priority,
 					const char *tcam_region_info,
 					const char *key, u8 erp_id,
-					bool large_exists, u32 lkey_id,
-					u32 action_pointer)
+					u16 delta_start, u8 delta_mask,
+					u8 delta_value, bool large_exists,
+					u32 lkey_id, u32 action_pointer)
 {
 	MLXSW_REG_ZERO(ptce3, payload);
 	mlxsw_reg_ptce3_v_set(payload, valid);
@@ -2775,6 +2776,9 @@  static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid,
 	mlxsw_reg_ptce3_tcam_region_info_memcpy_to(payload, tcam_region_info);
 	mlxsw_reg_ptce3_flex2_key_blocks_memcpy_to(payload, key);
 	mlxsw_reg_ptce3_erp_id_set(payload, erp_id);
+	mlxsw_reg_ptce3_delta_start_set(payload, delta_start);
+	mlxsw_reg_ptce3_delta_mask_set(payload, delta_mask);
+	mlxsw_reg_ptce3_delta_value_set(payload, delta_value);
 	mlxsw_reg_ptce3_large_exists_set(payload, large_exists);
 	mlxsw_reg_ptce3_large_entry_key_id_set(payload, lkey_id);
 	mlxsw_reg_ptce3_action_pointer_set(payload, action_pointer);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c
index 5a0b88707269..5500f7b1a137 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c
@@ -378,9 +378,12 @@  mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
 				       struct mlxsw_sp_acl_atcam_entry *aentry,
 				       struct mlxsw_sp_acl_rule_info *rulei)
 {
+	const struct mlxsw_sp_acl_erp_mask_delta *delta =
+			mlxsw_sp_acl_erp_mask_delta(aentry->erp_mask);
 	struct mlxsw_sp_acl_tcam_region *region = aregion->region;
 	u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
 	struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
+	char *enc_key = aentry->ht_key.enc_key;
 	char ptce3_pl[MLXSW_REG_PTCE3_LEN];
 	u32 kvdl_index, priority;
 	int err;
@@ -397,7 +400,8 @@  mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
 	kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block);
 	mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE,
 			     priority, region->tcam_region_info,
-			     aentry->ht_key.enc_key, erp_id,
+			     enc_key, erp_id, delta->start, delta->mask,
+			     mlxsw_sp_acl_erp_mask_delta_value(delta, enc_key),
 			     refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
 			     kvdl_index);
 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
@@ -416,14 +420,19 @@  mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
 				       struct mlxsw_sp_acl_atcam_region *aregion,
 				       struct mlxsw_sp_acl_atcam_entry *aentry)
 {
+	const struct mlxsw_sp_acl_erp_mask_delta *delta =
+			mlxsw_sp_acl_erp_mask_delta(aentry->erp_mask);
 	struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id;
 	struct mlxsw_sp_acl_tcam_region *region = aregion->region;
 	u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
+	char *enc_key = aentry->ht_key.enc_key;
 	char ptce3_pl[MLXSW_REG_PTCE3_LEN];
 
 	mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0,
-			     region->tcam_region_info, aentry->ht_key.enc_key,
-			     erp_id, refcount_read(&lkey_id->refcnt) != 1,
+			     region->tcam_region_info, enc_key,
+			     erp_id, delta->start, delta->mask,
+			     mlxsw_sp_acl_erp_mask_delta_value(delta, enc_key),
+			     refcount_read(&lkey_id->refcnt) != 1,
 			     lkey_id->id, 0);
 	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
 	aregion->ops->lkey_id_put(aregion, lkey_id);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
index f11a50b36927..ac57bf6d3026 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
@@ -978,14 +978,103 @@  u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
 	return erp->id;
 }
 
+static const struct mlxsw_sp_acl_erp_mask_delta
+mlxsw_sp_acl_erp_mask_delta_default = {};
+
+const struct mlxsw_sp_acl_erp_mask_delta *
+mlxsw_sp_acl_erp_mask_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask)
+{
+	struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
+	const struct mlxsw_sp_acl_erp_mask_delta *delta;
+
+	delta = objagg_obj_delta_priv(objagg_obj);
+	if (!delta)
+		delta = &mlxsw_sp_acl_erp_mask_delta_default;
+	return delta;
+}
+
+static int mlxsw_sp_acl_erp_delta_get(struct mlxsw_sp_acl_erp_key *parent_key,
+				      struct mlxsw_sp_acl_erp_key *key,
+				      u16 *delta_start, u8 *delta_mask)
+{
+	size_t len = sizeof(key->mask);
+	int index_start = -1;
+	int offset = 0;
+	u16 pmask;
+	u16 mask;
+	int i;
+
+	/* The difference between 2 masks can be up to 8 consecutive bits. */
+	for (i = 0; i < len; i++) {
+		if (parent_key->mask[i] == key->mask[i])
+			continue;
+		if (index_start == -1)
+			index_start = i;
+		else if (index_start != i - 1)
+			return -EINVAL;
+	}
+	if (index_start == -1) {
+		/* The masks are the same, this cannot happen.
+		 * That means the caller is broken.
+		 */
+		WARN_ON(1);
+		*delta_start = 0;
+		*delta_mask = 0;
+		return 0;
+	}
+	pmask = parent_key->mask[index_start] << 8;
+	mask = key->mask[index_start] << 8;
+	if (index_start + 1 < len) {
+		pmask |= (unsigned char) parent_key->mask[index_start + 1];
+		mask |= (unsigned char) key->mask[index_start + 1];
+	}
+
+	if ((pmask ^ mask) & pmask)
+		return -EINVAL;
+	mask &= ~pmask;
+	while (!(mask & (1 << (15 - offset))))
+		offset++;
+	while (!(mask & 1))
+		mask >>= 1;
+	if (mask & 0xff00)
+		return -EINVAL;
+
+	*delta_start = index_start * 8 + offset;
+	*delta_mask = mask;
+
+	return 0;
+}
+
 static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
 					   void *obj)
 {
-	return NULL;
+	struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
+	struct mlxsw_sp_acl_erp_mask_delta *delta;
+	struct mlxsw_sp_acl_erp_key *key = obj;
+	u16 delta_start;
+	u8 delta_mask;
+	int err;
+
+	if (parent_key->ctcam || key->ctcam)
+		return ERR_PTR(-EINVAL);
+	err = mlxsw_sp_acl_erp_delta_get(parent_key, obj,
+					 &delta_start, &delta_mask);
+	if (err)
+		return ERR_PTR(-EINVAL);
+
+	delta = kzalloc(sizeof(*delta), GFP_KERNEL);
+	if (!delta)
+		return ERR_PTR(-ENOMEM);
+	delta->start = delta_start;
+	delta->mask = delta_mask;
+	return 0;
 }
 
 static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
 {
+	struct mlxsw_sp_acl_erp_mask_delta *delta = delta_priv;
+
+	kfree(delta);
 }
 
 static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h
index 08b7368ffafd..b904658c9651 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h
@@ -213,9 +213,23 @@  void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
 
 struct mlxsw_sp_acl_erp_mask;
 
+struct mlxsw_sp_acl_erp_mask_delta {
+	u16 start;
+	u8 mask;
+};
+
+static inline u8
+mlxsw_sp_acl_erp_mask_delta_value(const struct mlxsw_sp_acl_erp_mask_delta *delta,
+				  const char *enc_key)
+{
+	return (enc_key[delta->start / 8] << (delta->start % 8)) & delta->mask;
+}
+
 bool
 mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask);
 u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask);
+const struct mlxsw_sp_acl_erp_mask_delta *
+mlxsw_sp_acl_erp_mask_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask);
 struct mlxsw_sp_acl_erp_mask *
 mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion,
 			  const char *mask, bool ctcam);