// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ #include #include #include "reg.h" #include "core.h" #include "spectrum.h" #include "spectrum_acl_tcam.h" struct mlxsw_sp1_acl_tcam_region { struct mlxsw_sp_acl_ctcam_region cregion; struct mlxsw_sp_acl_tcam_region *region; struct { struct mlxsw_sp_acl_ctcam_chunk cchunk; struct mlxsw_sp_acl_ctcam_entry centry; struct mlxsw_sp_acl_rule_info *rulei; } catchall; }; struct mlxsw_sp1_acl_tcam_chunk { struct mlxsw_sp_acl_ctcam_chunk cchunk; }; struct mlxsw_sp1_acl_tcam_entry { struct mlxsw_sp_acl_ctcam_entry centry; }; static int mlxsw_sp1_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregion, struct mlxsw_sp_acl_ctcam_entry *centry, const char *mask) { return 0; } static void mlxsw_sp1_acl_ctcam_region_entry_remove(struct mlxsw_sp_acl_ctcam_region *cregion, struct mlxsw_sp_acl_ctcam_entry *centry) { } static const struct mlxsw_sp_acl_ctcam_region_ops mlxsw_sp1_acl_ctcam_region_ops = { .entry_insert = mlxsw_sp1_acl_ctcam_region_entry_insert, .entry_remove = mlxsw_sp1_acl_ctcam_region_entry_remove, }; static int mlxsw_sp1_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv, struct mlxsw_sp_acl_tcam *tcam) { return 0; } static void mlxsw_sp1_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv) { } static int mlxsw_sp1_acl_ctcam_region_catchall_add(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp1_acl_tcam_region *region) { struct mlxsw_sp_acl_rule_info *rulei; int err; mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, ®ion->catchall.cchunk, MLXSW_SP_ACL_TCAM_CATCHALL_PRIO); rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl, NULL); if (IS_ERR(rulei)) { err = PTR_ERR(rulei); goto err_rulei_create; } err = mlxsw_sp_acl_rulei_act_continue(rulei); if (WARN_ON(err)) goto err_rulei_act_continue; err = mlxsw_sp_acl_rulei_commit(rulei); if (err) goto err_rulei_commit; err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, ®ion->catchall.cchunk, ®ion->catchall.centry, rulei, false); if (err) goto err_entry_add; region->catchall.rulei = rulei; return 0; err_entry_add: err_rulei_commit: err_rulei_act_continue: mlxsw_sp_acl_rulei_destroy(rulei); err_rulei_create: mlxsw_sp_acl_ctcam_chunk_fini(®ion->catchall.cchunk); return err; } static void mlxsw_sp1_acl_ctcam_region_catchall_del(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp1_acl_tcam_region *region) { struct mlxsw_sp_acl_rule_info *rulei = region->catchall.rulei; mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, ®ion->catchall.cchunk, ®ion->catchall.centry); mlxsw_sp_acl_rulei_destroy(rulei); mlxsw_sp_acl_ctcam_chunk_fini(®ion->catchall.cchunk); } static int mlxsw_sp1_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv, void *tcam_priv, struct mlxsw_sp_acl_tcam_region *_region, void *hints_priv) { struct mlxsw_sp1_acl_tcam_region *region = region_priv; int err; err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, ®ion->cregion, _region, &mlxsw_sp1_acl_ctcam_region_ops); if (err) return err; err = mlxsw_sp1_acl_ctcam_region_catchall_add(mlxsw_sp, region); if (err) goto err_catchall_add; region->region = _region; return 0; err_catchall_add: mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); return err; } static void mlxsw_sp1_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv) { struct mlxsw_sp1_acl_tcam_region *region = region_priv; mlxsw_sp1_acl_ctcam_region_catchall_del(mlxsw_sp, region); mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); } static int mlxsw_sp1_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_region *region) { return 0; } static void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv, unsigned int priority) { struct mlxsw_sp1_acl_tcam_region *region = region_priv; struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, &chunk->cchunk, priority); } static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv) { struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk); } static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp, void *region_priv, void *chunk_priv, void *entry_priv, struct mlxsw_sp_acl_rule_info *rulei) { struct mlxsw_sp1_acl_tcam_region *region = region_priv; struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, &chunk->cchunk, &entry->centry, rulei, false); } static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp, void *region_priv, void *chunk_priv, void *entry_priv) { struct mlxsw_sp1_acl_tcam_region *region = region_priv; struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, &chunk->cchunk, &entry->centry); } static int mlxsw_sp1_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, void *region_priv, void *entry_priv, struct mlxsw_sp_acl_rule_info *rulei) { return -EOPNOTSUPP; } static int mlxsw_sp1_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_region *_region, unsigned int offset, bool *activity) { char ptce2_pl[MLXSW_REG_PTCE2_LEN]; int err; mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ, _region->tcam_region_info, offset, 0); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); if (err) return err; *activity = mlxsw_reg_ptce2_a_get(ptce2_pl); return 0; } static int mlxsw_sp1_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp, void *region_priv, void *entry_priv, bool *activity) { struct mlxsw_sp1_acl_tcam_region *region = region_priv; struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; unsigned int offset; offset = mlxsw_sp_acl_ctcam_entry_offset(&entry->centry); return mlxsw_sp1_acl_tcam_region_entry_activity_get(mlxsw_sp, region->region, offset, activity); } const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = { .key_type = MLXSW_REG_PTAR_KEY_TYPE_FLEX, .priv_size = 0, .init = mlxsw_sp1_acl_tcam_init, .fini = mlxsw_sp1_acl_tcam_fini, .region_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_region), .region_init = mlxsw_sp1_acl_tcam_region_init, .region_fini = mlxsw_sp1_acl_tcam_region_fini, .region_associate = mlxsw_sp1_acl_tcam_region_associate, .chunk_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_chunk), .chunk_init = mlxsw_sp1_acl_tcam_chunk_init, .chunk_fini = mlxsw_sp1_acl_tcam_chunk_fini, .entry_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_entry), .entry_add = mlxsw_sp1_acl_tcam_entry_add, .entry_del = mlxsw_sp1_acl_tcam_entry_del, .entry_action_replace = mlxsw_sp1_acl_tcam_entry_action_replace, .entry_activity_get = mlxsw_sp1_acl_tcam_entry_activity_get, };