// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Microsemi Ocelot Switch driver
* Copyright (c) 2019 Microsemi Corporation
*/
#include <linux/iopoll.h>
#include <linux/proc_fs.h>
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot_police.h"
#include "ocelot_vcap.h"
#define ENTRY_WIDTH 32
enum vcap_sel {
VCAP_SEL_ENTRY = 0x1,
VCAP_SEL_ACTION = 0x2,
VCAP_SEL_COUNTER = 0x4,
VCAP_SEL_ALL = 0x7,
};
enum vcap_cmd {
VCAP_CMD_WRITE = 0, /* Copy from Cache to TCAM */
VCAP_CMD_READ = 1, /* Copy from TCAM to Cache */
VCAP_CMD_MOVE_UP = 2, /* Move <count> up */
VCAP_CMD_MOVE_DOWN = 3, /* Move <count> down */
VCAP_CMD_INITIALIZE = 4, /* Write all (from cache) */
};
#define VCAP_ENTRY_WIDTH 12 /* Max entry width (32bit words) */
#define VCAP_COUNTER_WIDTH 4 /* Max counter width (32bit words) */
struct vcap_data {
u32 entry[VCAP_ENTRY_WIDTH]; /* ENTRY_DAT */
u32 mask[VCAP_ENTRY_WIDTH]; /* MASK_DAT */
u32 action[VCAP_ENTRY_WIDTH]; /* ACTION_DAT */
u32 counter[VCAP_COUNTER_WIDTH]; /* CNT_DAT */
u32 tg; /* TG_DAT */
u32 type; /* Action type */
u32 tg_sw; /* Current type-group */
u32 cnt; /* Current counter */
u32 key_offset; /* Current entry offset */
u32 action_offset; /* Current action offset */
u32 counter_offset; /* Current counter offset */
u32 tg_value; /* Current type-group value */
u32 tg_mask; /* Current type-group mask */
};
static u32 vcap_read_update_ctrl(struct ocelot *ocelot,
const struct vcap_props *vcap)
{
return ocelot_target_read(ocelot, vcap->target, VCAP_CORE_UPDATE_CTRL);
}
static void vcap_cmd(struct ocelot *ocelot, const struct vcap_props *vcap,
u16 ix, int cmd, int sel)
{
u32 value = (VCAP_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT);
if ((sel & VCAP_SEL_ENTRY) &&