mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
7.1 KiB
254 lines
7.1 KiB
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
|
/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ |
|
|
|
#include <linux/kernel.h> |
|
#include <linux/slab.h> |
|
|
|
#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, |
|
};
|
|
|