Commit eae340fa authored by David S. Miller's avatar David S. Miller

Merge branch 'Wire-up-Ocelot-tc-flower-to-Felix-DSA'

Vladimir Oltean says:

====================
Wire up Ocelot tc-flower to Felix DSA

This series is a proposal on how to wire up the tc-flower callbacks into
DSA. The example taken is the Microchip Felix switch, whose core
implementation is actually located in drivers/net/ethernet/mscc/.

The proposal is largely a compromise solution. The DSA middle layer
handles just enough to get to the interesting stuff (FLOW_CLS_REPLACE,
FLOW_CLS_DESTROY, FLOW_CLS_STATS), but also thin enough to let drivers
decide what filter keys and actions they support without worrying that
the DSA middle layer will grow exponentially. I am far from being an
expert, so I am asking reviewers to please voice your opinion if you
think it can be done differently, with better results.

The bulk of the work was actually refactoring the ocelot driver enough
to allow the VCAP (Versatile Content-Aware Processor) code for vsc7514
and the vsc9959 switch cores to live together.

Flow block offloads have not been tested yet, only filters attached to a
single port. It might be as simple as replacing ocelot_ace_rule_create
with something smarter, it might be more complicated, I haven't tried
yet.

I should point out that the tc-matchall filter offload is not
implemented in the same manner in current mainline. Florian has already
went all the way down into exposing actual per-action callbacks,
starting with port mirroring. Because currently only mirred is supported
by this DSA mid layer, everything else will return -EOPNOTSUPP. So even
though ocelot supports matchall (aka port-based) policers, we don't have
a call path to call into them.  Personally I think that this is not
going to scale for tc-matchall (there may be policers, traps, drops,
VLAN retagging, etc etc), and that we should consider whether further
matchall filter/action combinations should be just passed on to drivers
with no interpretation instead.
As for the existing mirroring callbacks in DSA, they can either be kept
as-is, or replaced with simple accessors to TC_CLSMATCHALL_REPLACE and
TC_CLSMATCHALL_DESTROY, just like for flower, and drivers which
currently implement the port mirroring callbacks will need to have some
extra "if" conditions now, in order for them to call their port
mirroring implementations.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d6584892 07d985ee
......@@ -2,6 +2,7 @@
/* Copyright 2019 NXP Semiconductors
*/
#include <uapi/linux/if_bridge.h>
#include <soc/mscc/ocelot_vcap.h>
#include <soc/mscc/ocelot_qsys.h>
#include <soc/mscc/ocelot_sys.h>
#include <soc/mscc/ocelot_dev.h>
......@@ -401,6 +402,9 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
ocelot->stats_layout = felix->info->stats_layout;
ocelot->num_stats = felix->info->num_stats;
ocelot->shared_queue_sz = felix->info->shared_queue_sz;
ocelot->vcap_is2_keys = felix->info->vcap_is2_keys;
ocelot->vcap_is2_actions= felix->info->vcap_is2_actions;
ocelot->vcap = felix->info->vcap;
ocelot->ops = felix->info->ops;
port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
......@@ -595,6 +599,30 @@ static bool felix_txtstamp(struct dsa_switch *ds, int port,
return false;
}
static int felix_cls_flower_add(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress)
{
struct ocelot *ocelot = ds->priv;
return ocelot_cls_flower_replace(ocelot, port, cls, ingress);
}
static int felix_cls_flower_del(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress)
{
struct ocelot *ocelot = ds->priv;
return ocelot_cls_flower_destroy(ocelot, port, cls, ingress);
}
static int felix_cls_flower_stats(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress)
{
struct ocelot *ocelot = ds->priv;
return ocelot_cls_flower_stats(ocelot, port, cls, ingress);
}
static const struct dsa_switch_ops felix_switch_ops = {
.get_tag_protocol = felix_get_tag_protocol,
.setup = felix_setup,
......@@ -626,6 +654,9 @@ static const struct dsa_switch_ops felix_switch_ops = {
.port_hwtstamp_set = felix_hwtstamp_set,
.port_rxtstamp = felix_rxtstamp,
.port_txtstamp = felix_txtstamp,
.cls_flower_add = felix_cls_flower_add,
.cls_flower_del = felix_cls_flower_del,
.cls_flower_stats = felix_cls_flower_stats,
};
static struct felix_info *felix_instance_tbl[] = {
......
......@@ -18,6 +18,9 @@ struct felix_info {
const struct ocelot_stat_layout *stats_layout;
unsigned int num_stats;
int num_ports;
struct vcap_field *vcap_is2_keys;
struct vcap_field *vcap_is2_actions;
const struct vcap_props *vcap;
int switch_pci_bar;
int imdio_pci_bar;
int (*mdio_bus_alloc)(struct ocelot *ocelot);
......
......@@ -3,12 +3,17 @@
* Copyright 2018-2019 NXP Semiconductors
*/
#include <linux/fsl/enetc_mdio.h>
#include <soc/mscc/ocelot_vcap.h>
#include <soc/mscc/ocelot_sys.h>
#include <soc/mscc/ocelot.h>
#include <linux/iopoll.h>
#include <linux/pci.h>
#include "felix.h"
#define VSC9959_VCAP_IS2_CNT 1024
#define VSC9959_VCAP_IS2_ENTRY_WIDTH 376
#define VSC9959_VCAP_PORT_CNT 6
/* TODO: should find a better place for these */
#define USXGMII_BMCR_RESET BIT(15)
#define USXGMII_BMCR_AN_EN BIT(12)
......@@ -547,6 +552,129 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
{ .offset = 0x111, .name = "drop_green_prio_7", },
};
struct vcap_field vsc9959_vcap_is2_keys[] = {
/* Common: 41 bits */
[VCAP_IS2_TYPE] = { 0, 4},
[VCAP_IS2_HK_FIRST] = { 4, 1},
[VCAP_IS2_HK_PAG] = { 5, 8},
[VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 7},
[VCAP_IS2_HK_RSV2] = { 20, 1},
[VCAP_IS2_HK_HOST_MATCH] = { 21, 1},
[VCAP_IS2_HK_L2_MC] = { 22, 1},
[VCAP_IS2_HK_L2_BC] = { 23, 1},
[VCAP_IS2_HK_VLAN_TAGGED] = { 24, 1},
[VCAP_IS2_HK_VID] = { 25, 12},
[VCAP_IS2_HK_DEI] = { 37, 1},
[VCAP_IS2_HK_PCP] = { 38, 3},
/* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */
[VCAP_IS2_HK_L2_DMAC] = { 41, 48},
[VCAP_IS2_HK_L2_SMAC] = { 89, 48},
/* MAC_ETYPE (TYPE=000) */
[VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {137, 16},
[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {153, 16},
[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {169, 8},
[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {177, 3},
/* MAC_LLC (TYPE=001) */
[VCAP_IS2_HK_MAC_LLC_L2_LLC] = {137, 40},
/* MAC_SNAP (TYPE=010) */
[VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {137, 40},
/* MAC_ARP (TYPE=011) */
[VCAP_IS2_HK_MAC_ARP_SMAC] = { 41, 48},
[VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 89, 1},
[VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 90, 1},
[VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 91, 1},
[VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 92, 1},
[VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 93, 1},
[VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 94, 1},
[VCAP_IS2_HK_MAC_ARP_OPCODE] = { 95, 2},
[VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = { 97, 32},
[VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {129, 32},
[VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {161, 1},
/* IP4_TCP_UDP / IP4_OTHER common */
[VCAP_IS2_HK_IP4] = { 41, 1},
[VCAP_IS2_HK_L3_FRAGMENT] = { 42, 1},
[VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 43, 1},
[VCAP_IS2_HK_L3_OPTIONS] = { 44, 1},
[VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 45, 1},
[VCAP_IS2_HK_L3_TOS] = { 46, 8},
[VCAP_IS2_HK_L3_IP4_DIP] = { 54, 32},
[VCAP_IS2_HK_L3_IP4_SIP] = { 86, 32},
[VCAP_IS2_HK_DIP_EQ_SIP] = {118, 1},
/* IP4_TCP_UDP (TYPE=100) */
[VCAP_IS2_HK_TCP] = {119, 1},
[VCAP_IS2_HK_L4_SPORT] = {120, 16},
[VCAP_IS2_HK_L4_DPORT] = {136, 16},
[VCAP_IS2_HK_L4_RNG] = {152, 8},
[VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {160, 1},
[VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {161, 1},
[VCAP_IS2_HK_L4_URG] = {162, 1},
[VCAP_IS2_HK_L4_ACK] = {163, 1},
[VCAP_IS2_HK_L4_PSH] = {164, 1},
[VCAP_IS2_HK_L4_RST] = {165, 1},
[VCAP_IS2_HK_L4_SYN] = {166, 1},
[VCAP_IS2_HK_L4_FIN] = {167, 1},
[VCAP_IS2_HK_L4_1588_DOM] = {168, 8},
[VCAP_IS2_HK_L4_1588_VER] = {176, 4},
/* IP4_OTHER (TYPE=101) */
[VCAP_IS2_HK_IP4_L3_PROTO] = {119, 8},
[VCAP_IS2_HK_L3_PAYLOAD] = {127, 56},
/* IP6_STD (TYPE=110) */
[VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 41, 1},
[VCAP_IS2_HK_L3_IP6_SIP] = { 42, 128},
[VCAP_IS2_HK_IP6_L3_PROTO] = {170, 8},
/* OAM (TYPE=111) */
[VCAP_IS2_HK_OAM_MEL_FLAGS] = {137, 7},
[VCAP_IS2_HK_OAM_VER] = {144, 5},
[VCAP_IS2_HK_OAM_OPCODE] = {149, 8},
[VCAP_IS2_HK_OAM_FLAGS] = {157, 8},
[VCAP_IS2_HK_OAM_MEPID] = {165, 16},
[VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {181, 1},
[VCAP_IS2_HK_OAM_IS_Y1731] = {182, 1},
};
struct vcap_field vsc9959_vcap_is2_actions[] = {
[VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1},
[VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1},
[VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3},
[VCAP_IS2_ACT_MASK_MODE] = { 5, 2},
[VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1},
[VCAP_IS2_ACT_LRN_DIS] = { 8, 1},
[VCAP_IS2_ACT_POLICE_ENA] = { 9, 1},
[VCAP_IS2_ACT_POLICE_IDX] = { 10, 9},
[VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1},
[VCAP_IS2_ACT_PORT_MASK] = { 20, 11},
[VCAP_IS2_ACT_REW_OP] = { 31, 9},
[VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 40, 1},
[VCAP_IS2_ACT_RSV] = { 41, 2},
[VCAP_IS2_ACT_ACL_ID] = { 43, 6},
[VCAP_IS2_ACT_HIT_CNT] = { 49, 32},
};
static const struct vcap_props vsc9959_vcap_props[] = {
[VCAP_IS2] = {
.tg_width = 2,
.sw_count = 4,
.entry_count = VSC9959_VCAP_IS2_CNT,
.entry_width = VSC9959_VCAP_IS2_ENTRY_WIDTH,
.action_count = VSC9959_VCAP_IS2_CNT +
VSC9959_VCAP_PORT_CNT + 2,
.action_width = 89,
.action_type_width = 1,
.action_table = {
[IS2_ACTION_TYPE_NORMAL] = {
.width = 44,
.count = 2
},
[IS2_ACTION_TYPE_SMAC_SIP] = {
.width = 6,
.count = 4
},
},
.counter_words = 4,
.counter_width = 32,
},
};
#define VSC9959_INIT_TIMEOUT 50000
#define VSC9959_GCB_RST_SLEEP 100
#define VSC9959_SYS_RAMINIT_SLEEP 80
......@@ -1088,6 +1216,9 @@ struct felix_info felix_info_vsc9959 = {
.ops = &vsc9959_ops,
.stats_layout = vsc9959_stats_layout,
.num_stats = ARRAY_SIZE(vsc9959_stats_layout),
.vcap_is2_keys = vsc9959_vcap_is2_keys,
.vcap_is2_actions = vsc9959_vcap_is2_actions,
.vcap = vsc9959_vcap_props,
.shared_queue_sz = 128 * 1024,
.num_ports = 6,
.switch_pci_bar = 4,
......
......@@ -442,8 +442,23 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port,
ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA |
mode, DEV_MAC_MODE_CFG);
if (ocelot->ops->pcs_init)
ocelot->ops->pcs_init(ocelot, port);
/* Disable HDX fast control */
ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS,
DEV_PORT_MISC);
/* SGMII only for now */
ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA,
PCS1G_MODE_CFG);
ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
/* Enable PCS */
ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
/* No aneg on SGMII */
ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG);
/* No loopback */
ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
/* Enable MAC module */
ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
......@@ -2493,7 +2508,6 @@ void ocelot_deinit(struct ocelot *ocelot)
cancel_delayed_work(&ocelot->stats_work);
destroy_workqueue(ocelot->stats_queue);
mutex_destroy(&ocelot->stats_lock);
ocelot_ace_deinit();
if (ocelot->ptp_clock)
ptp_clock_unregister(ocelot->ptp_clock);
......
......@@ -6,60 +6,12 @@
#include <linux/iopoll.h>
#include <linux/proc_fs.h>
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot_ace.h"
#include "ocelot_vcap.h"
#include "ocelot_s2.h"
#define OCELOT_POLICER_DISCARD 0x17f
static struct ocelot_acl_block *acl_block;
struct vcap_props {
const char *name; /* Symbolic name */
u16 tg_width; /* Type-group width (in bits) */
u16 sw_count; /* Sub word count */
u16 entry_count; /* Entry count */
u16 entry_words; /* Number of entry words */
u16 entry_width; /* Entry width (in bits) */
u16 action_count; /* Action count */
u16 action_words; /* Number of action words */
u16 action_width; /* Action width (in bits) */
u16 action_type_width; /* Action type width (in bits) */
struct {
u16 width; /* Action type width (in bits) */
u16 count; /* Action type sub word count */
} action_table[2];
u16 counter_words; /* Number of counter words */
u16 counter_width; /* Counter width (in bits) */
};
#define ENTRY_WIDTH 32
#define BITS_TO_32BIT(x) (1 + (((x) - 1) / ENTRY_WIDTH))
static const struct vcap_props vcap_is2 = {
.name = "IS2",
.tg_width = 2,
.sw_count = 4,
.entry_count = VCAP_IS2_CNT,
.entry_words = BITS_TO_32BIT(VCAP_IS2_ENTRY_WIDTH),
.entry_width = VCAP_IS2_ENTRY_WIDTH,
.action_count = (VCAP_IS2_CNT + VCAP_PORT_CNT + 2),
.action_words = BITS_TO_32BIT(VCAP_IS2_ACTION_WIDTH),
.action_width = (VCAP_IS2_ACTION_WIDTH),
.action_type_width = 1,
.action_table = {
{
.width = (IS2_AO_ACL_ID + IS2_AL_ACL_ID),
.count = 2
},
{
.width = 6,
.count = 4
},
},
.counter_words = BITS_TO_32BIT(4 * ENTRY_WIDTH),
.counter_width = ENTRY_WIDTH,
};
enum vcap_sel {
VCAP_SEL_ENTRY = 0x1,
......@@ -95,18 +47,20 @@ struct vcap_data {
u32 tg_mask; /* Current type-group mask */
};
static u32 vcap_s2_read_update_ctrl(struct ocelot *oc)
static u32 vcap_s2_read_update_ctrl(struct ocelot *ocelot)
{
return ocelot_read(oc, S2_CORE_UPDATE_CTRL);
return ocelot_read(ocelot, S2_CORE_UPDATE_CTRL);
}
static void vcap_cmd(struct ocelot *oc, u16 ix, int cmd, int sel)
static void vcap_cmd(struct ocelot *ocelot, u16 ix, int cmd, int sel)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 value = (S2_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
S2_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
S2_CORE_UPDATE_CTRL_UPDATE_SHOT);
if ((sel & VCAP_SEL_ENTRY) && ix >= vcap_is2.entry_count)
if ((sel & VCAP_SEL_ENTRY) && ix >= vcap_is2->entry_count)
return;
if (!(sel & VCAP_SEL_ENTRY))
......@@ -118,83 +72,101 @@ static void vcap_cmd(struct ocelot *oc, u16 ix, int cmd, int sel)
if (!(sel & VCAP_SEL_COUNTER))
value |= S2_CORE_UPDATE_CTRL_UPDATE_CNT_DIS;
ocelot_write(oc, value, S2_CORE_UPDATE_CTRL);
readx_poll_timeout(vcap_s2_read_update_ctrl, oc, value,
ocelot_write(ocelot, value, S2_CORE_UPDATE_CTRL);
readx_poll_timeout(vcap_s2_read_update_ctrl, ocelot, value,
(value & S2_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0,
10, 100000);
}
/* Convert from 0-based row to VCAP entry row and run command */
static void vcap_row_cmd(struct ocelot *oc, u32 row, int cmd, int sel)
static void vcap_row_cmd(struct ocelot *ocelot, u32 row, int cmd, int sel)
{
vcap_cmd(oc, vcap_is2.entry_count - row - 1, cmd, sel);
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
vcap_cmd(ocelot, vcap_is2->entry_count - row - 1, cmd, sel);
}
static void vcap_entry2cache(struct ocelot *oc, struct vcap_data *data)
static void vcap_entry2cache(struct ocelot *ocelot, struct vcap_data *data)
{
u32 i;
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 entry_words, i;
for (i = 0; i < vcap_is2.entry_words; i++) {
ocelot_write_rix(oc, data->entry[i], S2_CACHE_ENTRY_DAT, i);
ocelot_write_rix(oc, ~data->mask[i], S2_CACHE_MASK_DAT, i);
entry_words = DIV_ROUND_UP(vcap_is2->entry_width, ENTRY_WIDTH);
for (i = 0; i < entry_words; i++) {
ocelot_write_rix(ocelot, data->entry[i], S2_CACHE_ENTRY_DAT, i);
ocelot_write_rix(ocelot, ~data->mask[i], S2_CACHE_MASK_DAT, i);
}
ocelot_write(oc, data->tg, S2_CACHE_TG_DAT);
ocelot_write(ocelot, data->tg, S2_CACHE_TG_DAT);
}
static void vcap_cache2entry(struct ocelot *oc, struct vcap_data *data)
static void vcap_cache2entry(struct ocelot *ocelot, struct vcap_data *data)
{
u32 i;
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 entry_words, i;
entry_words = DIV_ROUND_UP(vcap_is2->entry_width, ENTRY_WIDTH);
for (i = 0; i < vcap_is2.entry_words; i++) {
data->entry[i] = ocelot_read_rix(oc, S2_CACHE_ENTRY_DAT, i);
for (i = 0; i < entry_words; i++) {
data->entry[i] = ocelot_read_rix(ocelot, S2_CACHE_ENTRY_DAT, i);
// Invert mask
data->mask[i] = ~ocelot_read_rix(oc, S2_CACHE_MASK_DAT, i);
data->mask[i] = ~ocelot_read_rix(ocelot, S2_CACHE_MASK_DAT, i);
}
data->tg = ocelot_read(oc, S2_CACHE_TG_DAT);
data->tg = ocelot_read(ocelot, S2_CACHE_TG_DAT);
}
static void vcap_action2cache(struct ocelot *oc, struct vcap_data *data)
static void vcap_action2cache(struct ocelot *ocelot, struct vcap_data *data)
{
u32 i, width, mask;
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 action_words, i, width, mask;
/* Encode action type */
width = vcap_is2.action_type_width;
width = vcap_is2->action_type_width;
if (width) {
mask = GENMASK(width, 0);
data->action[0] = ((data->action[0] & ~mask) | data->type);
}
for (i = 0; i < vcap_is2.action_words; i++)
ocelot_write_rix(oc, data->action[i], S2_CACHE_ACTION_DAT, i);
action_words = DIV_ROUND_UP(vcap_is2->action_width, ENTRY_WIDTH);
for (i = 0; i < action_words; i++)
ocelot_write_rix(ocelot, data->action[i], S2_CACHE_ACTION_DAT,
i);
for (i = 0; i < vcap_is2.counter_words; i++)
ocelot_write_rix(oc, data->counter[i], S2_CACHE_CNT_DAT, i);
for (i = 0; i < vcap_is2->counter_words; i++)
ocelot_write_rix(ocelot, data->counter[i], S2_CACHE_CNT_DAT, i);
}
static void vcap_cache2action(struct ocelot *oc, struct vcap_data *data)
static void vcap_cache2action(struct ocelot *ocelot, struct vcap_data *data)
{
u32 i, width;
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 action_words, i, width;
for (i = 0; i < vcap_is2.action_words; i++)
data->action[i] = ocelot_read_rix(oc, S2_CACHE_ACTION_DAT, i);
action_words = DIV_ROUND_UP(vcap_is2->action_width, ENTRY_WIDTH);
for (i = 0; i < vcap_is2.counter_words; i++)
data->counter[i] = ocelot_read_rix(oc, S2_CACHE_CNT_DAT, i);
for (i = 0; i < action_words; i++)
data->action[i] = ocelot_read_rix(ocelot, S2_CACHE_ACTION_DAT,
i);
for (i = 0; i < vcap_is2->counter_words; i++)
data->counter[i] = ocelot_read_rix(ocelot, S2_CACHE_CNT_DAT, i);
/* Extract action type */
width = vcap_is2.action_type_width;
width = vcap_is2->action_type_width;
data->type = (width ? (data->action[0] & GENMASK(width, 0)) : 0);
}
/* Calculate offsets for entry */
static void is2_data_get(struct vcap_data *data, int ix)
static void is2_data_get(struct ocelot *ocelot, struct vcap_data *data, int ix)
{
u32 i, col, offset, count, cnt, base, width = vcap_is2.tg_width;
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 i, col, offset, count, cnt, base;
u32 width = vcap_is2->tg_width;
count = (data->tg_sw == VCAP_TG_HALF ? 2 : 4);
col = (ix % 2);
cnt = (vcap_is2.sw_count / count);
base = (vcap_is2.sw_count - col * cnt - cnt);
cnt = (vcap_is2->sw_count / count);
base = (vcap_is2->sw_count - col * cnt - cnt);
data->tg_value = 0;
data->tg_mask = 0;
for (i = 0; i < cnt; i++) {
......@@ -205,13 +177,13 @@ static void is2_data_get(struct vcap_data *data, int ix)
/* Calculate key/action/counter offsets */
col = (count - col - 1);
data->key_offset = (base * vcap_is2.entry_width) / vcap_is2.sw_count;
data->counter_offset = (cnt * col * vcap_is2.counter_width);
data->key_offset = (base * vcap_is2->entry_width) / vcap_is2->sw_count;
data->counter_offset = (cnt * col * vcap_is2->counter_width);
i = data->type;
width = vcap_is2.action_table[i].width;
cnt = vcap_is2.action_table[i].count;
width = vcap_is2->action_table[i].width;
cnt = vcap_is2->action_table[i].count;
data->action_offset =
(((cnt * col * width) / count) + vcap_is2.action_type_width);
(((cnt * col * width) / count) + vcap_is2->action_type_width);
}
static void vcap_data_set(u32 *data, u32 offset, u32 len, u32 value)
......@@ -242,22 +214,39 @@ static u32 vcap_data_get(u32 *data, u32 offset, u32 len)
return value;
}
static void vcap_key_set(struct vcap_data *data, u32 offset, u32 width,
static void vcap_key_field_set(struct vcap_data *data, u32 offset, u32 width,
u32 value, u32 mask)
{
vcap_data_set(data->entry, offset + data->key_offset, width, value);
vcap_data_set(data->mask, offset + data->key_offset, width, mask);
}
static void vcap_key_bytes_set(struct vcap_data *data, u32 offset, u8 *val,
u8 *msk, u32 count)
static void vcap_key_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
u32 value, u32 mask)
{
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 length = ocelot->vcap_is2_keys[field].length;
vcap_key_field_set(data, offset, length, value, mask);
}
static void vcap_key_bytes_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
u8 *val, u8 *msk)
{
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 count = ocelot->vcap_is2_keys[field].length;
u32 i, j, n = 0, value = 0, mask = 0;
WARN_ON(count % 8);
/* Data wider than 32 bits are split up in chunks of maximum 32 bits.
* The 32 LSB of the data are written to the 32 MSB of the TCAM.
*/
offset += (count * 8);
offset += count;
count /= 8;
for (i = 0; i < count; i++) {
j = (count - i - 1);
value += (val[j] << n);
......@@ -265,7 +254,7 @@ static void vcap_key_bytes_set(struct vcap_data *data, u32 offset, u8 *val,
n += 8;
if (n == ENTRY_WIDTH || (i + 1) == count) {
offset -= n;
vcap_key_set(data, offset, n, value, mask);
vcap_key_field_set(data, offset, n, value, mask);
n = 0;
value = 0;
mask = 0;
......@@ -273,55 +262,62 @@ static void vcap_key_bytes_set(struct vcap_data *data, u32 offset, u8 *val,
}
}
static void vcap_key_l4_port_set(struct vcap_data *data, u32 offset,
static void vcap_key_l4_port_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
struct ocelot_vcap_udp_tcp *port)
{
vcap_key_set(data, offset, 16, port->value, port->mask);
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 length = ocelot->vcap_is2_keys[field].length;
WARN_ON(length != 16);
vcap_key_field_set(data, offset, length, port->value, port->mask);
}
static void vcap_key_bit_set(struct vcap_data *data, u32 offset,
static void vcap_key_bit_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
enum ocelot_vcap_bit val)
{
vcap_key_set(data, offset, 1, val == OCELOT_VCAP_BIT_1 ? 1 : 0,
val == OCELOT_VCAP_BIT_ANY ? 0 : 1);
}
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 length = ocelot->vcap_is2_keys[field].length;
u32 value = (val == OCELOT_VCAP_BIT_1 ? 1 : 0);
u32 msk = (val == OCELOT_VCAP_BIT_ANY ? 0 : 1);
#define VCAP_KEY_SET(fld, val, msk) \
vcap_key_set(&data, IS2_HKO_##fld, IS2_HKL_##fld, val, msk)
#define VCAP_KEY_ANY_SET(fld) \
vcap_key_set(&data, IS2_HKO_##fld, IS2_HKL_##fld, 0, 0)
#define VCAP_KEY_BIT_SET(fld, val) vcap_key_bit_set(&data, IS2_HKO_##fld, val)
#define VCAP_KEY_BYTES_SET(fld, val, msk) \
vcap_key_bytes_set(&data, IS2_HKO_##fld, val, msk, IS2_HKL_##fld / 8)
WARN_ON(length != 1);
static void vcap_action_set(struct vcap_data *data, u32 offset, u32 width,
u32 value)
{
vcap_data_set(data->action, offset + data->action_offset, width, value);
vcap_key_field_set(data, offset, length, value, msk);
}
#define VCAP_ACT_SET(fld, val) \
vcap_action_set(data, IS2_AO_##fld, IS2_AL_##fld, val)
static void vcap_action_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_action_field field, u32 value)
{
int offset = ocelot->vcap_is2_actions[field].offset;
int length = ocelot->vcap_is2_actions[field].length;
vcap_data_set(data->action, offset + data->action_offset, length,
value);
}
static void is2_action_set(struct vcap_data *data,
static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
enum ocelot_ace_action action)
{
switch (action) {
case OCELOT_ACL_ACTION_DROP:
VCAP_ACT_SET(PORT_MASK, 0x0);
VCAP_ACT_SET(MASK_MODE, 0x1);
VCAP_ACT_SET(POLICE_ENA, 0x1);
VCAP_ACT_SET(POLICE_IDX, OCELOT_POLICER_DISCARD);
VCAP_ACT_SET(CPU_QU_NUM, 0x0);
VCAP_ACT_SET(CPU_COPY_ENA, 0x0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX,
OCELOT_POLICER_DISCARD);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
break;
case OCELOT_ACL_ACTION_TRAP:
VCAP_ACT_SET(PORT_MASK, 0x0);
VCAP_ACT_SET(MASK_MODE, 0x1);
VCAP_ACT_SET(POLICE_ENA, 0x0);
VCAP_ACT_SET(POLICE_IDX, 0x0);
VCAP_ACT_SET(CPU_QU_NUM, 0x0);
VCAP_ACT_SET(CPU_COPY_ENA, 0x1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
break;
}
}
......@@ -329,6 +325,7 @@ static void is2_action_set(struct vcap_data *data,
static void is2_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_ace_rule *ace)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 val, msk, type, type_mask = 0xf, i, count;
struct ocelot_ace_vlan *tag = &ace->vlan;
struct ocelot_vcap_u64 payload;
......@@ -344,60 +341,76 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
vcap_cache2action(ocelot, &data);
data.tg_sw = VCAP_TG_HALF;
is2_data_get(&data, ix);
is2_data_get(ocelot, &data, ix);
data.tg = (data.tg & ~data.tg_mask);
if (ace->prio != 0)
data.tg |= data.tg_value;
data.type = IS2_ACTION_TYPE_NORMAL;
VCAP_KEY_ANY_SET(PAG);
VCAP_KEY_SET(IGR_PORT_MASK, 0, ~BIT(ace->chip_port));
VCAP_KEY_BIT_SET(FIRST, OCELOT_VCAP_BIT_1);
VCAP_KEY_BIT_SET(HOST_MATCH, OCELOT_VCAP_BIT_ANY);
VCAP_KEY_BIT_SET(L2_MC, ace->dmac_mc);
VCAP_KEY_BIT_SET(L2_BC, ace->dmac_bc);
VCAP_KEY_BIT_SET(VLAN_TAGGED, tag->tagged);
VCAP_KEY_SET(VID, tag->vid.value, tag->vid.mask);
VCAP_KEY_SET(PCP, tag->pcp.value[0], tag->pcp.mask[0]);
VCAP_KEY_BIT_SET(DEI, tag->dei);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_PAG, 0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0,
~ace->ingress_port_mask);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_FIRST, OCELOT_VCAP_BIT_1);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_HOST_MATCH,
OCELOT_VCAP_BIT_ANY);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L2_MC, ace->dmac_mc);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L2_BC, ace->dmac_bc);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_VLAN_TAGGED, tag->tagged);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_VID,
tag->vid.value, tag->vid.mask);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_PCP,
tag->pcp.value[0], tag->pcp.mask[0]);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_DEI, tag->dei);
switch (ace->type) {
case OCELOT_ACE_TYPE_ETYPE: {
struct ocelot_ace_frame_etype *etype = &ace->frame.etype;
type = IS2_TYPE_ETYPE;
VCAP_KEY_BYTES_SET(L2_DMAC, etype->dmac.value,
etype->dmac.mask);
VCAP_KEY_BYTES_SET(L2_SMAC, etype->smac.value,
etype->smac.mask);
VCAP_KEY_BYTES_SET(MAC_ETYPE_ETYPE, etype->etype.value,
etype->etype.mask);
VCAP_KEY_ANY_SET(MAC_ETYPE_L2_PAYLOAD); // Clear unused bits
vcap_key_bytes_set(&data, IS2_HKO_MAC_ETYPE_L2_PAYLOAD,
etype->data.value, etype->data.mask, 2);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
etype->dmac.value, etype->dmac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
etype->smac.value, etype->smac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_ETYPE,
etype->etype.value, etype->etype.mask);
/* Clear unused bits */
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1,
0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2,
0, 0);
vcap_key_bytes_set(ocelot, &data,
VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
etype->data.value, etype->data.mask);
break;
}
case OCELOT_ACE_TYPE_LLC: {
struct ocelot_ace_frame_llc *llc = &ace->frame.llc;
type = IS2_TYPE_LLC;
VCAP_KEY_BYTES_SET(L2_DMAC, llc->dmac.value, llc->dmac.mask);
VCAP_KEY_BYTES_SET(L2_SMAC, llc->smac.value, llc->smac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
llc->dmac.value, llc->dmac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
llc->smac.value, llc->smac.mask);
for (i = 0; i < 4; i++) {
payload.value[i] = llc->llc.value[i];
payload.mask[i] = llc->llc.mask[i];
}
VCAP_KEY_BYTES_SET(MAC_LLC_L2_LLC, payload.value, payload.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_LLC_L2_LLC,
payload.value, payload.mask);
break;
}
case OCELOT_ACE_TYPE_SNAP: {
struct ocelot_ace_frame_snap *snap = &ace->frame.snap;
type = IS2_TYPE_SNAP;
VCAP_KEY_BYTES_SET(L2_DMAC, snap->dmac.value, snap->dmac.mask);
VCAP_KEY_BYTES_SET(L2_SMAC, snap->smac.value, snap->smac.mask);
VCAP_KEY_BYTES_SET(MAC_SNAP_L2_SNAP,
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
snap->dmac.value, snap->dmac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
snap->smac.value, snap->smac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_SNAP_L2_SNAP,
ace->frame.snap.snap.value,
ace->frame.snap.snap.mask);
break;
......@@ -406,26 +419,42 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_ace_frame_arp *arp = &ace->frame.arp;
type = IS2_TYPE_ARP;
VCAP_KEY_BYTES_SET(MAC_ARP_L2_SMAC, arp->smac.value,
arp->smac.mask);
VCAP_KEY_BIT_SET(MAC_ARP_ARP_ADDR_SPACE_OK, arp->ethernet);
VCAP_KEY_BIT_SET(MAC_ARP_ARP_PROTO_SPACE_OK, arp->ip);
VCAP_KEY_BIT_SET(MAC_ARP_ARP_LEN_OK, arp->length);
VCAP_KEY_BIT_SET(MAC_ARP_ARP_TGT_MATCH, arp->dmac_match);
VCAP_KEY_BIT_SET(MAC_ARP_ARP_SENDER_MATCH, arp->smac_match);
VCAP_KEY_BIT_SET(MAC_ARP_ARP_OPCODE_UNKNOWN, arp->unknown);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_SMAC,
arp->smac.value, arp->smac.mask);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK,
arp->ethernet);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK,
arp->ip);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_LEN_OK,
arp->length);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_TARGET_MATCH,
arp->dmac_match);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_SENDER_MATCH,
arp->smac_match);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN,
arp->unknown);
/* OPCODE is inverse, bit 0 is reply flag, bit 1 is RARP flag */
val = ((arp->req == OCELOT_VCAP_BIT_0 ? 1 : 0) |
(arp->arp == OCELOT_VCAP_BIT_0 ? 2 : 0));
msk = ((arp->req == OCELOT_VCAP_BIT_ANY ? 0 : 1) |
(arp->arp == OCELOT_VCAP_BIT_ANY ? 0 : 2));
VCAP_KEY_SET(MAC_ARP_ARP_OPCODE, val, msk);
vcap_key_bytes_set(&data, IS2_HKO_MAC_ARP_L3_IP4_DIP,
arp->dip.value.addr, arp->dip.mask.addr, 4);
vcap_key_bytes_set(&data, IS2_HKO_MAC_ARP_L3_IP4_SIP,
arp->sip.value.addr, arp->sip.mask.addr, 4);
VCAP_KEY_ANY_SET(MAC_ARP_DIP_EQ_SIP);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_OPCODE,
val, msk);
vcap_key_bytes_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP,
arp->dip.value.addr, arp->dip.mask.addr);
vcap_key_bytes_set(ocelot, &data,
VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP,
arp->sip.value.addr, arp->sip.mask.addr);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP,
0, 0);
break;
}
case OCELOT_ACE_TYPE_IPV4:
......@@ -493,18 +522,23 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
seq_zero = ipv6->seq_zero;
}
VCAP_KEY_BIT_SET(IP4,
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_IP4,
ipv4 ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
VCAP_KEY_BIT_SET(L3_FRAGMENT, fragment);
VCAP_KEY_ANY_SET(L3_FRAG_OFS_GT0);
VCAP_KEY_BIT_SET(L3_OPTIONS, options);
VCAP_KEY_BIT_SET(L3_TTL_GT0, ttl);
VCAP_KEY_BYTES_SET(L3_TOS, ds.value, ds.mask);
vcap_key_bytes_set(&data, IS2_HKO_L3_IP4_DIP, dip.value.addr,
dip.mask.addr, 4);
vcap_key_bytes_set(&data, IS2_HKO_L3_IP4_SIP, sip.value.addr,
sip.mask.addr, 4);
VCAP_KEY_BIT_SET(DIP_EQ_SIP, sip_eq_dip);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L3_FRAGMENT,
fragment);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L3_FRAG_OFS_GT0, 0, 0);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L3_OPTIONS,
options);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_IP4_L3_TTL_GT0,
ttl);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_TOS,
ds.value, ds.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_IP4_DIP,
dip.value.addr, dip.mask.addr);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_IP4_SIP,
sip.value.addr, sip.mask.addr);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_DIP_EQ_SIP,
sip_eq_dip);
val = proto.value[0];
msk = proto.mask[0];
type = IS2_TYPE_IP_UDP_TCP;
......@@ -512,25 +546,34 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
/* UDP/TCP protocol match */
tcp = (val == 6 ?
OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_TCP, tcp);
vcap_key_l4_port_set(&data,
IS2_HKO_IP4_TCP_UDP_L4_DPORT,
dport);
vcap_key_l4_port_set(&data,
IS2_HKO_IP4_TCP_UDP_L4_SPORT,
sport);
VCAP_KEY_ANY_SET(IP4_TCP_UDP_L4_RNG);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_SPORT_EQ_DPORT,
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_TCP, tcp);
vcap_key_l4_port_set(ocelot, &data,
VCAP_IS2_HK_L4_DPORT, dport);
vcap_key_l4_port_set(ocelot, &data,
VCAP_IS2_HK_L4_SPORT, sport);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_RNG, 0, 0);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_L4_SPORT_EQ_DPORT,
sport_eq_dport);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_SEQUENCE_EQ0, seq_zero);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_FIN, tcp_fin);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_SYN, tcp_syn);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_RST, tcp_rst);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_PSH, tcp_psh);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_ACK, tcp_ack);
VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_URG, tcp_urg);
VCAP_KEY_ANY_SET(IP4_TCP_UDP_L4_1588_DOM);
VCAP_KEY_ANY_SET(IP4_TCP_UDP_L4_1588_VER);
vcap_key_bit_set(ocelot, &data,
VCAP_IS2_HK_L4_SEQUENCE_EQ0,
seq_zero);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_FIN,
tcp_fin);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_SYN,
tcp_syn);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_RST,
tcp_rst);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_PSH,
tcp_psh);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_ACK,
tcp_ack);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_URG,
tcp_urg);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_1588_DOM,
0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_1588_VER,
0, 0);
} else {
if (msk == 0) {
/* Any IP protocol match */
......@@ -543,10 +586,12 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
payload.mask[i] = ip_data->mask[i];
}
}
VCAP_KEY_BYTES_SET(IP4_OTHER_L3_PROTO, proto.value,
proto.mask);
VCAP_KEY_BYTES_SET(IP4_OTHER_L3_PAYLOAD, payload.value,
payload.mask);
vcap_key_bytes_set(ocelot, &data,
VCAP_IS2_HK_IP4_L3_PROTO,
proto.value, proto.mask);
vcap_key_bytes_set(ocelot, &data,
VCAP_IS2_HK_L3_PAYLOAD,
payload.value, payload.mask);
}
break;
}
......@@ -554,19 +599,21 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
default:
type = 0;
type_mask = 0;
count = (vcap_is2.entry_width / 2);
for (i = (IS2_HKO_PCP + IS2_HKL_PCP); i < count;
i += ENTRY_WIDTH) {
/* Clear entry data */
vcap_key_set(&data, i, min(32u, count - i), 0, 0);
count = vcap_is2->entry_width / 2;
/* Iterate over the non-common part of the key and
* clear entry data
*/
for (i = ocelot->vcap_is2_keys[VCAP_IS2_HK_L2_DMAC].offset;
i < count; i += ENTRY_WIDTH) {
vcap_key_field_set(&data, i, min(32u, count - i), 0, 0);
}
break;
}
VCAP_KEY_SET(TYPE, type, type_mask);
is2_action_set(&data, ace->action);
vcap_data_set(data.counter, data.counter_offset, vcap_is2.counter_width,
ace->stats.pkts);
vcap_key_set(ocelot, &data, VCAP_IS2_TYPE, type, type_mask);
is2_action_set(ocelot, &data, ace->action);
vcap_data_set(data.counter, data.counter_offset,
vcap_is2->counter_width, ace->stats.pkts);
/* Write row */
vcap_entry2cache(ocelot, &data);
......@@ -574,19 +621,20 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
vcap_row_cmd(ocelot, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
}
static void is2_entry_get(struct ocelot_ace_rule *rule, int ix)
static void is2_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
int ix)
{
struct ocelot *op = rule->port->ocelot;
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
struct vcap_data data;
int row = (ix / 2);
u32 cnt;
vcap_row_cmd(op, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
vcap_cache2action(op, &data);
vcap_row_cmd(ocelot, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
vcap_cache2action(ocelot, &data);
data.tg_sw = VCAP_TG_HALF;
is2_data_get(&data, ix);
is2_data_get(ocelot, &data, ix);
cnt = vcap_data_get(data.counter, data.counter_offset,
vcap_is2.counter_width);
vcap_is2->counter_width);
rule->stats.pkts = cnt;
}
......@@ -641,25 +689,27 @@ ocelot_ace_rule_get_rule_index(struct ocelot_acl_block *block, int index)
return NULL;
}
int ocelot_ace_rule_offload_add(struct ocelot_ace_rule *rule)
int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
struct ocelot_ace_rule *rule)
{
struct ocelot_acl_block *block = &ocelot->acl_block;
struct ocelot_ace_rule *ace;
int i, index;
/* Add rule to the linked list */
ocelot_ace_rule_add(acl_block, rule);
ocelot_ace_rule_add(block, rule);
/* Get the index of the inserted rule */
index = ocelot_ace_rule_get_index_id(acl_block, rule);
index = ocelot_ace_rule_get_index_id(block, rule);
/* Move down the rules to make place for the new rule */
for (i = acl_block->count - 1; i > index; i--) {
ace = ocelot_ace_rule_get_rule_index(acl_block, i);
is2_entry_set(rule->port->ocelot, i, ace);
for (i = block->count - 1; i > index; i--) {
ace = ocelot_ace_rule_get_rule_index(block, i);
is2_entry_set(ocelot, i, ace);
}
/* Now insert the new rule */
is2_entry_set(rule->port->ocelot, index, rule);
is2_entry_set(ocelot, index, rule);
return 0;
}
......@@ -680,8 +730,10 @@ static void ocelot_ace_rule_del(struct ocelot_acl_block *block,
block->count--;
}
int ocelot_ace_rule_offload_del(struct ocelot_ace_rule *rule)
int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
struct ocelot_ace_rule *rule)
{
struct ocelot_acl_block *block = &ocelot->acl_block;
struct ocelot_ace_rule del_ace;
struct ocelot_ace_rule *ace;
int i, index;
......@@ -689,70 +741,54 @@ int ocelot_ace_rule_offload_del(struct ocelot_ace_rule *rule)
memset(&del_ace, 0, sizeof(del_ace));
/* Gets index of the rule */
index = ocelot_ace_rule_get_index_id(acl_block, rule);
index = ocelot_ace_rule_get_index_id(block, rule);
/* Delete rule */
ocelot_ace_rule_del(acl_block, rule);
ocelot_ace_rule_del(block, rule);
/* Move up all the blocks over the deleted rule */
for (i = index; i < acl_block->count; i++) {
ace = ocelot_ace_rule_get_rule_index(acl_block, i);
is2_entry_set(rule->port->ocelot, i, ace);
for (i = index; i < block->count; i++) {
ace = ocelot_ace_rule_get_rule_index(block, i);
is2_entry_set(ocelot, i, ace);
}
/* Now delete the last rule, because it is duplicated */
is2_entry_set(rule->port->ocelot, acl_block->count, &del_ace);
is2_entry_set(ocelot, block->count, &del_ace);
return 0;
}
int ocelot_ace_rule_stats_update(struct ocelot_ace_rule *rule)
int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
struct ocelot_ace_rule *rule)
{
struct ocelot_acl_block *block = &ocelot->acl_block;
struct ocelot_ace_rule *tmp;
int index;
index = ocelot_ace_rule_get_index_id(acl_block, rule);
is2_entry_get(rule, index);
index = ocelot_ace_rule_get_index_id(block, rule);
is2_entry_get(ocelot, rule, index);
/* After we get the result we need to clear the counters */
tmp = ocelot_ace_rule_get_rule_index(acl_block, index);
tmp = ocelot_ace_rule_get_rule_index(block, index);
tmp->stats.pkts = 0;
is2_entry_set(rule->port->ocelot, index, tmp);
is2_entry_set(ocelot, index, tmp);
return 0;
}
static struct ocelot_acl_block *ocelot_acl_block_create(struct ocelot *ocelot)
{
struct ocelot_acl_block *block;
block = kzalloc(sizeof(*block), GFP_KERNEL);
if (!block)
return NULL;
INIT_LIST_HEAD(&block->rules);
block->count = 0;
block->ocelot = ocelot;
return block;
}
static void ocelot_acl_block_destroy(struct ocelot_acl_block *block)
{
kfree(block);
}
int ocelot_ace_init(struct ocelot *ocelot)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
struct vcap_data data;
memset(&data, 0, sizeof(data));
vcap_entry2cache(ocelot, &data);
ocelot_write(ocelot, vcap_is2.entry_count, S2_CORE_MV_CFG);
ocelot_write(ocelot, vcap_is2->entry_count, S2_CORE_MV_CFG);
vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY);
vcap_action2cache(ocelot, &data);
ocelot_write(ocelot, vcap_is2.action_count, S2_CORE_MV_CFG);
ocelot_write(ocelot, vcap_is2->action_count, S2_CORE_MV_CFG);
vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE,
VCAP_SEL_ACTION | VCAP_SEL_COUNTER);
......@@ -771,12 +807,7 @@ int ocelot_ace_init(struct ocelot *ocelot)
ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
OCELOT_POLICER_DISCARD);
acl_block = ocelot_acl_block_create(ocelot);
INIT_LIST_HEAD(&ocelot->acl_block.rules);
return 0;
}
void ocelot_ace_deinit(void)
{
ocelot_acl_block_destroy(acl_block);
}
......@@ -186,14 +186,13 @@ struct ocelot_ace_stats {
struct ocelot_ace_rule {
struct list_head list;
struct ocelot_port *port;
u16 prio;
u32 id;
enum ocelot_ace_action action;
struct ocelot_ace_stats stats;
int chip_port;
u16 ingress_port_mask;
enum ocelot_vcap_bit dmac_mc;
enum ocelot_vcap_bit dmac_bc;
......@@ -211,22 +210,17 @@ struct ocelot_ace_rule {
} frame;
};
struct ocelot_acl_block {
struct list_head rules;
struct ocelot *ocelot;
int count;
};
int ocelot_ace_rule_offload_add(struct ocelot_ace_rule *rule);
int ocelot_ace_rule_offload_del(struct ocelot_ace_rule *rule);
int ocelot_ace_rule_stats_update(struct ocelot_ace_rule *rule);
int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
struct ocelot_ace_rule *rule);
int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
struct ocelot_ace_rule *rule);
int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
struct ocelot_ace_rule *rule);
int ocelot_ace_init(struct ocelot *ocelot);
void ocelot_ace_deinit(void);
int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
struct flow_block_offload *f);
void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
struct flow_block_offload *f);
int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
struct flow_cls_offload *f,
bool ingress);
#endif /* _MSCC_OCELOT_ACE_H_ */
......@@ -14,9 +14,14 @@
#include <linux/skbuff.h>
#include <net/switchdev.h>
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot.h"
#define IFH_EXTRACT_BITFIELD64(x, o, w) (((x) >> (o)) & GENMASK_ULL((w) - 1, 0))
#define VSC7514_VCAP_IS2_CNT 64
#define VSC7514_VCAP_IS2_ENTRY_WIDTH 376
#define VSC7514_VCAP_IS2_ACTION_WIDTH 99
#define VSC7514_VCAP_PORT_CNT 11
static int ocelot_parse_ifh(u32 *_ifh, struct frame_info *info)
{
......@@ -211,29 +216,6 @@ static const struct of_device_id mscc_ocelot_match[] = {
};
MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
static void ocelot_port_pcs_init(struct ocelot *ocelot, int port)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
/* Disable HDX fast control */
ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS,
DEV_PORT_MISC);
/* SGMII only for now */
ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA,
PCS1G_MODE_CFG);
ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
/* Enable PCS */
ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
/* No aneg on SGMII */
ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG);
/* No loopback */
ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
}
static int ocelot_reset(struct ocelot *ocelot)
{
int retries = 100;
......@@ -258,10 +240,132 @@ static int ocelot_reset(struct ocelot *ocelot)
}
static const struct ocelot_ops ocelot_ops = {
.pcs_init = ocelot_port_pcs_init,
.reset = ocelot_reset,
};
static const struct vcap_field vsc7514_vcap_is2_keys[] = {
/* Common: 46 bits */
[VCAP_IS2_TYPE] = { 0, 4},
[VCAP_IS2_HK_FIRST] = { 4, 1},
[VCAP_IS2_HK_PAG] = { 5, 8},
[VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 12},
[VCAP_IS2_HK_RSV2] = { 25, 1},
[VCAP_IS2_HK_HOST_MATCH] = { 26, 1},
[VCAP_IS2_HK_L2_MC] = { 27, 1},
[VCAP_IS2_HK_L2_BC] = { 28, 1},
[VCAP_IS2_HK_VLAN_TAGGED] = { 29, 1},
[VCAP_IS2_HK_VID] = { 30, 12},
[VCAP_IS2_HK_DEI] = { 42, 1},
[VCAP_IS2_HK_PCP] = { 43, 3},
/* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */
[VCAP_IS2_HK_L2_DMAC] = { 46, 48},
[VCAP_IS2_HK_L2_SMAC] = { 94, 48},
/* MAC_ETYPE (TYPE=000) */
[VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {142, 16},
[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {158, 16},
[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {174, 8},
[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {182, 3},
/* MAC_LLC (TYPE=001) */
[VCAP_IS2_HK_MAC_LLC_L2_LLC] = {142, 40},
/* MAC_SNAP (TYPE=010) */
[VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {142, 40},
/* MAC_ARP (TYPE=011) */
[VCAP_IS2_HK_MAC_ARP_SMAC] = { 46, 48},
[VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 94, 1},
[VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 95, 1},
[VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 96, 1},
[VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 97, 1},
[VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 98, 1},
[VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 99, 1},
[VCAP_IS2_HK_MAC_ARP_OPCODE] = {100, 2},
[VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = {102, 32},
[VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {134, 32},
[VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {166, 1},
/* IP4_TCP_UDP / IP4_OTHER common */
[VCAP_IS2_HK_IP4] = { 46, 1},
[VCAP_IS2_HK_L3_FRAGMENT] = { 47, 1},
[VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 48, 1},
[VCAP_IS2_HK_L3_OPTIONS] = { 49, 1},
[VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 50, 1},
[VCAP_IS2_HK_L3_TOS] = { 51, 8},
[VCAP_IS2_HK_L3_IP4_DIP] = { 59, 32},
[VCAP_IS2_HK_L3_IP4_SIP] = { 91, 32},
[VCAP_IS2_HK_DIP_EQ_SIP] = {123, 1},
/* IP4_TCP_UDP (TYPE=100) */
[VCAP_IS2_HK_TCP] = {124, 1},
[VCAP_IS2_HK_L4_SPORT] = {125, 16},
[VCAP_IS2_HK_L4_DPORT] = {141, 16},
[VCAP_IS2_HK_L4_RNG] = {157, 8},
[VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {165, 1},
[VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {166, 1},
[VCAP_IS2_HK_L4_URG] = {167, 1},
[VCAP_IS2_HK_L4_ACK] = {168, 1},
[VCAP_IS2_HK_L4_PSH] = {169, 1},
[VCAP_IS2_HK_L4_RST] = {170, 1},
[VCAP_IS2_HK_L4_SYN] = {171, 1},
[VCAP_IS2_HK_L4_FIN] = {172, 1},
[VCAP_IS2_HK_L4_1588_DOM] = {173, 8},
[VCAP_IS2_HK_L4_1588_VER] = {181, 4},
/* IP4_OTHER (TYPE=101) */
[VCAP_IS2_HK_IP4_L3_PROTO] = {124, 8},
[VCAP_IS2_HK_L3_PAYLOAD] = {132, 56},
/* IP6_STD (TYPE=110) */
[VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 46, 1},
[VCAP_IS2_HK_L3_IP6_SIP] = { 47, 128},
[VCAP_IS2_HK_IP6_L3_PROTO] = {175, 8},
/* OAM (TYPE=111) */
[VCAP_IS2_HK_OAM_MEL_FLAGS] = {142, 7},
[VCAP_IS2_HK_OAM_VER] = {149, 5},
[VCAP_IS2_HK_OAM_OPCODE] = {154, 8},
[VCAP_IS2_HK_OAM_FLAGS] = {162, 8},
[VCAP_IS2_HK_OAM_MEPID] = {170, 16},
[VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {186, 1},
[VCAP_IS2_HK_OAM_IS_Y1731] = {187, 1},
};
static const struct vcap_field vsc7514_vcap_is2_actions[] = {
[VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1},
[VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1},
[VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3},
[VCAP_IS2_ACT_MASK_MODE] = { 5, 2},
[VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1},
[VCAP_IS2_ACT_LRN_DIS] = { 8, 1},
[VCAP_IS2_ACT_POLICE_ENA] = { 9, 1},
[VCAP_IS2_ACT_POLICE_IDX] = { 10, 9},
[VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1},
[VCAP_IS2_ACT_PORT_MASK] = { 20, 11},
[VCAP_IS2_ACT_REW_OP] = { 31, 9},
[VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 40, 1},
[VCAP_IS2_ACT_RSV] = { 41, 2},
[VCAP_IS2_ACT_ACL_ID] = { 43, 6},
[VCAP_IS2_ACT_HIT_CNT] = { 49, 32},
};
static const struct vcap_props vsc7514_vcap_props[] = {
[VCAP_IS2] = {
.tg_width = 2,
.sw_count = 4,
.entry_count = VSC7514_VCAP_IS2_CNT,
.entry_width = VSC7514_VCAP_IS2_ENTRY_WIDTH,
.action_count = VSC7514_VCAP_IS2_CNT +
VSC7514_VCAP_PORT_CNT + 2,
.action_width = 99,
.action_type_width = 1,
.action_table = {
[IS2_ACTION_TYPE_NORMAL] = {
.width = 49,
.count = 2
},
[IS2_ACTION_TYPE_SMAC_SIP] = {
.width = 6,
.count = 4
},
},
.counter_words = 4,
.counter_width = 32,
},
};
static int mscc_ocelot_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
......@@ -362,6 +466,10 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
sizeof(struct ocelot_port *), GFP_KERNEL);
ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
ocelot->vcap = vsc7514_vcap_props;
ocelot_init(ocelot);
ocelot_set_cpu_port(ocelot, ocelot->num_phys_ports,
OCELOT_TAG_PREFIX_NONE, OCELOT_TAG_PREFIX_NONE);
......
......@@ -8,13 +8,8 @@
#include "ocelot_ace.h"
struct ocelot_port_block {
struct ocelot_acl_block *block;
struct ocelot_port_private *priv;
};
static int ocelot_flower_parse_action(struct flow_cls_offload *f,
struct ocelot_ace_rule *rule)
struct ocelot_ace_rule *ace)
{
const struct flow_action_entry *a;
int i;
......@@ -25,10 +20,10 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
flow_action_for_each(i, a, &f->rule->action) {
switch (a->id) {
case FLOW_ACTION_DROP:
rule->action = OCELOT_ACL_ACTION_DROP;
ace->action = OCELOT_ACL_ACTION_DROP;
break;
case FLOW_ACTION_TRAP:
rule->action = OCELOT_ACL_ACTION_TRAP;
ace->action = OCELOT_ACL_ACTION_TRAP;
break;
default:
return -EOPNOTSUPP;
......@@ -39,7 +34,7 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
}
static int ocelot_flower_parse(struct flow_cls_offload *f,
struct ocelot_ace_rule *ocelot_rule)
struct ocelot_ace_rule *ace)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
......@@ -84,14 +79,14 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
return -EOPNOTSUPP;
flow_rule_match_eth_addrs(rule, &match);
ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
ace->type = OCELOT_ACE_TYPE_ETYPE;
ether_addr_copy(ace->frame.etype.dmac.value,
match.key->dst);
ether_addr_copy(ocelot_rule->frame.etype.smac.value,
ether_addr_copy(ace->frame.etype.smac.value,
match.key->src);
ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
ether_addr_copy(ace->frame.etype.dmac.mask,
match.mask->dst);
ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
ether_addr_copy(ace->frame.etype.smac.mask,
match.mask->src);
goto finished_key_parsing;
}
......@@ -101,17 +96,17 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
flow_rule_match_basic(rule, &match);
if (ntohs(match.key->n_proto) == ETH_P_IP) {
ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
ocelot_rule->frame.ipv4.proto.value[0] =
ace->type = OCELOT_ACE_TYPE_IPV4;
ace->frame.ipv4.proto.value[0] =
match.key->ip_proto;
ocelot_rule->frame.ipv4.proto.mask[0] =
ace->frame.ipv4.proto.mask[0] =
match.mask->ip_proto;
}
if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
ocelot_rule->frame.ipv6.proto.value[0] =
ace->type = OCELOT_ACE_TYPE_IPV6;
ace->frame.ipv6.proto.value[0] =
match.key->ip_proto;
ocelot_rule->frame.ipv6.proto.mask[0] =
ace->frame.ipv6.proto.mask[0] =
match.mask->ip_proto;
}
}
......@@ -122,16 +117,16 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
u8 *tmp;
flow_rule_match_ipv4_addrs(rule, &match);
tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
tmp = &ace->frame.ipv4.sip.value.addr[0];
memcpy(tmp, &match.key->src, 4);
tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
tmp = &ace->frame.ipv4.sip.mask.addr[0];
memcpy(tmp, &match.mask->src, 4);
tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
tmp = &ace->frame.ipv4.dip.value.addr[0];
memcpy(tmp, &match.key->dst, 4);
tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
tmp = &ace->frame.ipv4.dip.mask.addr[0];
memcpy(tmp, &match.mask->dst, 4);
}
......@@ -144,213 +139,110 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
struct flow_match_ports match;
flow_rule_match_ports(rule, &match);
ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
ace->frame.ipv4.sport.value = ntohs(match.key->src);
ace->frame.ipv4.sport.mask = ntohs(match.mask->src);
ace->frame.ipv4.dport.value = ntohs(match.key->dst);
ace->frame.ipv4.dport.mask = ntohs(match.mask->dst);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match;
flow_rule_match_vlan(rule, &match);
ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
ocelot_rule->vlan.vid.value = match.key->vlan_id;
ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
ace->type = OCELOT_ACE_TYPE_ANY;
ace->vlan.vid.value = match.key->vlan_id;
ace->vlan.vid.mask = match.mask->vlan_id;
ace->vlan.pcp.value[0] = match.key->vlan_priority;
ace->vlan.pcp.mask[0] = match.mask->vlan_priority;
}
finished_key_parsing:
ocelot_rule->prio = f->common.prio;
ocelot_rule->id = f->cookie;
return ocelot_flower_parse_action(f, ocelot_rule);
ace->prio = f->common.prio;
ace->id = f->cookie;
return ocelot_flower_parse_action(f, ace);
}
static
struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
struct ocelot_port_block *block)
struct ocelot_ace_rule *ocelot_ace_rule_create(struct ocelot *ocelot, int port,
struct flow_cls_offload *f)
{
struct ocelot_ace_rule *rule;
struct ocelot_ace_rule *ace;
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
if (!rule)
ace = kzalloc(sizeof(*ace), GFP_KERNEL);
if (!ace)
return NULL;
rule->port = &block->priv->port;
rule->chip_port = block->priv->chip_port;
return rule;
ace->ingress_port_mask = BIT(port);
return ace;
}
static int ocelot_flower_replace(struct flow_cls_offload *f,
struct ocelot_port_block *port_block)
int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress)
{
struct ocelot_ace_rule *rule;
struct ocelot_ace_rule *ace;
int ret;
rule = ocelot_ace_rule_create(f, port_block);
if (!rule)
ace = ocelot_ace_rule_create(ocelot, port, f);
if (!ace)
return -ENOMEM;
ret = ocelot_flower_parse(f, rule);
ret = ocelot_flower_parse(f, ace);
if (ret) {
kfree(rule);
kfree(ace);
return ret;
}
ret = ocelot_ace_rule_offload_add(rule);
if (ret)
return ret;
port_block->priv->tc.offload_cnt++;
return 0;
return ocelot_ace_rule_offload_add(ocelot, ace);
}
EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
static int ocelot_flower_destroy(struct flow_cls_offload *f,
struct ocelot_port_block *port_block)
int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress)
{
struct ocelot_ace_rule rule;
int ret;
struct ocelot_ace_rule ace;
rule.prio = f->common.prio;
rule.port = &port_block->priv->port;
rule.id = f->cookie;
ace.prio = f->common.prio;
ace.id = f->cookie;
ret = ocelot_ace_rule_offload_del(&rule);
if (ret)
return ret;
port_block->priv->tc.offload_cnt--;
return 0;
return ocelot_ace_rule_offload_del(ocelot, &ace);
}
EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
static int ocelot_flower_stats_update(struct flow_cls_offload *f,
struct ocelot_port_block *port_block)
int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress)
{
struct ocelot_ace_rule rule;
struct ocelot_ace_rule ace;
int ret;
rule.prio = f->common.prio;
rule.port = &port_block->priv->port;
rule.id = f->cookie;
ret = ocelot_ace_rule_stats_update(&rule);
ace.prio = f->common.prio;
ace.id = f->cookie;
ret = ocelot_ace_rule_stats_update(ocelot, &ace);
if (ret)
return ret;
flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
flow_stats_update(&f->stats, 0x0, ace.stats.pkts, 0x0);
return 0;
}
EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
struct ocelot_port_block *port_block)
int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
struct flow_cls_offload *f,
bool ingress)
{
struct ocelot *ocelot = priv->port.ocelot;
int port = priv->chip_port;
if (!ingress)
return -EOPNOTSUPP;
switch (f->command) {
case FLOW_CLS_REPLACE:
return ocelot_flower_replace(f, port_block);
return ocelot_cls_flower_replace(ocelot, port, f, ingress);
case FLOW_CLS_DESTROY:
return ocelot_flower_destroy(f, port_block);
return ocelot_cls_flower_destroy(ocelot, port, f, ingress);
case FLOW_CLS_STATS:
return ocelot_flower_stats_update(f, port_block);
default:
return -EOPNOTSUPP;
}
}
static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
struct ocelot_port_block *port_block = cb_priv;
if (!tc_cls_can_offload_and_chain0(port_block->priv->dev, type_data))
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_CLSFLOWER:
return ocelot_setup_tc_cls_flower(type_data, cb_priv);
case TC_SETUP_CLSMATCHALL:
return 0;
return ocelot_cls_flower_stats(ocelot, port, f, ingress);
default:
return -EOPNOTSUPP;
}
}
static struct ocelot_port_block*
ocelot_port_block_create(struct ocelot_port_private *priv)
{
struct ocelot_port_block *port_block;
port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
if (!port_block)
return NULL;
port_block->priv = priv;
return port_block;
}
static void ocelot_port_block_destroy(struct ocelot_port_block *block)
{
kfree(block);
}
static void ocelot_tc_block_unbind(void *cb_priv)
{
struct ocelot_port_block *port_block = cb_priv;
ocelot_port_block_destroy(port_block);
}
int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
struct flow_block_offload *f)
{
struct ocelot_port_block *port_block;
struct flow_block_cb *block_cb;
int ret;
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
return -EOPNOTSUPP;
block_cb = flow_block_cb_lookup(f->block,
ocelot_setup_tc_block_cb_flower, priv);
if (!block_cb) {
port_block = ocelot_port_block_create(priv);
if (!port_block)
return -ENOMEM;
block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
priv, port_block,
ocelot_tc_block_unbind);
if (IS_ERR(block_cb)) {
ret = PTR_ERR(block_cb);
goto err_cb_register;
}
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, f->driver_block_list);
} else {
port_block = flow_block_cb_priv(block_cb);
}
flow_block_cb_incref(block_cb);
return 0;
err_cb_register:
ocelot_port_block_destroy(port_block);
return ret;
}
void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
struct flow_block_offload *f)
{
struct flow_block_cb *block_cb;
block_cb = flow_block_cb_lookup(f->block,
ocelot_setup_tc_block_cb_flower, priv);
if (!block_cb)
return;
if (!flow_block_cb_decref(block_cb)) {
flow_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
}
}
......@@ -20,9 +20,6 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
int port = priv->chip_port;
int err;
netdev_dbg(priv->dev, "%s: port %u command %d cookie %lu\n",
__func__, port, f->command, f->cookie);
if (!ingress) {
NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported");
return -EOPNOTSUPP;
......@@ -99,17 +96,10 @@ static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
switch (type) {
case TC_SETUP_CLSMATCHALL:
netdev_dbg(priv->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
ingress ? "ingress" : "egress");
return ocelot_setup_tc_cls_matchall(priv, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return 0;
return ocelot_setup_tc_cls_flower(priv, type_data, ingress);
default:
netdev_dbg(priv->dev, "tc_block_cb: type %d %s\n",
type,
ingress ? "ingress" : "egress");
return -EOPNOTSUPP;
}
}
......@@ -137,10 +127,6 @@ static int ocelot_setup_tc_block(struct ocelot_port_private *priv,
{
struct flow_block_cb *block_cb;
flow_setup_cb_t *cb;
int err;
netdev_dbg(priv->dev, "tc_block command %d, binder_type %d\n",
f->command, f->binder_type);
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = ocelot_setup_tc_block_cb_ig;
......@@ -162,11 +148,6 @@ static int ocelot_setup_tc_block(struct ocelot_port_private *priv,
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
err = ocelot_setup_tc_block_flower_bind(priv, f);
if (err < 0) {
flow_block_cb_free(block_cb);
return err;
}
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, f->driver_block_list);
return 0;
......@@ -175,7 +156,6 @@ static int ocelot_setup_tc_block(struct ocelot_port_private *priv,
if (!block_cb)
return -ENOENT;
ocelot_setup_tc_block_flower_unbind(priv, f);
flow_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
return 0;
......
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Microsemi Ocelot Switch driver
* Copyright (c) 2019 Microsemi Corporation
*/
#ifndef _OCELOT_VCAP_H_
#define _OCELOT_VCAP_H_
/* =================================================================
* VCAP Common
* =================================================================
*/
/* VCAP Type-Group values */
#define VCAP_TG_NONE 0 /* Entry is invalid */
#define VCAP_TG_FULL 1 /* Full entry */
#define VCAP_TG_HALF 2 /* Half entry */
#define VCAP_TG_QUARTER 3 /* Quarter entry */
/* =================================================================
* VCAP IS2
* =================================================================
*/
#define VCAP_IS2_CNT 64
#define VCAP_IS2_ENTRY_WIDTH 376
#define VCAP_IS2_ACTION_WIDTH 99
#define VCAP_PORT_CNT 11
/* IS2 half key types */
#define IS2_TYPE_ETYPE 0
#define IS2_TYPE_LLC 1
#define IS2_TYPE_SNAP 2
#define IS2_TYPE_ARP 3
#define IS2_TYPE_IP_UDP_TCP 4
#define IS2_TYPE_IP_OTHER 5
#define IS2_TYPE_IPV6 6
#define IS2_TYPE_OAM 7
#define IS2_TYPE_SMAC_SIP6 8
#define IS2_TYPE_ANY 100 /* Pseudo type */
/* IS2 half key type mask for matching any IP */
#define IS2_TYPE_MASK_IP_ANY 0xe
/* IS2 action types */
#define IS2_ACTION_TYPE_NORMAL 0
#define IS2_ACTION_TYPE_SMAC_SIP 1
/* IS2 MASK_MODE values */
#define IS2_ACT_MASK_MODE_NONE 0
#define IS2_ACT_MASK_MODE_FILTER 1
#define IS2_ACT_MASK_MODE_POLICY 2
#define IS2_ACT_MASK_MODE_REDIR 3
/* IS2 REW_OP values */
#define IS2_ACT_REW_OP_NONE 0
#define IS2_ACT_REW_OP_PTP_ONE 2
#define IS2_ACT_REW_OP_PTP_TWO 3
#define IS2_ACT_REW_OP_SPECIAL 8
#define IS2_ACT_REW_OP_PTP_ORG 9
#define IS2_ACT_REW_OP_PTP_ONE_SUB_DELAY_1 (IS2_ACT_REW_OP_PTP_ONE | (1 << 3))
#define IS2_ACT_REW_OP_PTP_ONE_SUB_DELAY_2 (IS2_ACT_REW_OP_PTP_ONE | (2 << 3))
#define IS2_ACT_REW_OP_PTP_ONE_ADD_DELAY (IS2_ACT_REW_OP_PTP_ONE | (1 << 5))
#define IS2_ACT_REW_OP_PTP_ONE_ADD_SUB BIT(7)
#define VCAP_PORT_WIDTH 4
/* IS2 quarter key - SMAC_SIP4 */
#define IS2_QKO_IGR_PORT 0
#define IS2_QKL_IGR_PORT VCAP_PORT_WIDTH
#define IS2_QKO_L2_SMAC (IS2_QKO_IGR_PORT + IS2_QKL_IGR_PORT)
#define IS2_QKL_L2_SMAC 48
#define IS2_QKO_L3_IP4_SIP (IS2_QKO_L2_SMAC + IS2_QKL_L2_SMAC)
#define IS2_QKL_L3_IP4_SIP 32
/* IS2 half key - common */
#define IS2_HKO_TYPE 0
#define IS2_HKL_TYPE 4
#define IS2_HKO_FIRST (IS2_HKO_TYPE + IS2_HKL_TYPE)
#define IS2_HKL_FIRST 1
#define IS2_HKO_PAG (IS2_HKO_FIRST + IS2_HKL_FIRST)
#define IS2_HKL_PAG 8
#define IS2_HKO_IGR_PORT_MASK (IS2_HKO_PAG + IS2_HKL_PAG)
#define IS2_HKL_IGR_PORT_MASK (VCAP_PORT_CNT + 1)
#define IS2_HKO_SERVICE_FRM (IS2_HKO_IGR_PORT_MASK + IS2_HKL_IGR_PORT_MASK)
#define IS2_HKL_SERVICE_FRM 1
#define IS2_HKO_HOST_MATCH (IS2_HKO_SERVICE_FRM + IS2_HKL_SERVICE_FRM)
#define IS2_HKL_HOST_MATCH 1
#define IS2_HKO_L2_MC (IS2_HKO_HOST_MATCH + IS2_HKL_HOST_MATCH)
#define IS2_HKL_L2_MC 1
#define IS2_HKO_L2_BC (IS2_HKO_L2_MC + IS2_HKL_L2_MC)
#define IS2_HKL_L2_BC 1
#define IS2_HKO_VLAN_TAGGED (IS2_HKO_L2_BC + IS2_HKL_L2_BC)
#define IS2_HKL_VLAN_TAGGED 1
#define IS2_HKO_VID (IS2_HKO_VLAN_TAGGED + IS2_HKL_VLAN_TAGGED)
#define IS2_HKL_VID 12
#define IS2_HKO_DEI (IS2_HKO_VID + IS2_HKL_VID)
#define IS2_HKL_DEI 1
#define IS2_HKO_PCP (IS2_HKO_DEI + IS2_HKL_DEI)
#define IS2_HKL_PCP 3
/* IS2 half key - MAC_ETYPE/MAC_LLC/MAC_SNAP/OAM common */
#define IS2_HKO_L2_DMAC (IS2_HKO_PCP + IS2_HKL_PCP)
#define IS2_HKL_L2_DMAC 48
#define IS2_HKO_L2_SMAC (IS2_HKO_L2_DMAC + IS2_HKL_L2_DMAC)
#define IS2_HKL_L2_SMAC 48
/* IS2 half key - MAC_ETYPE */
#define IS2_HKO_MAC_ETYPE_ETYPE (IS2_HKO_L2_SMAC + IS2_HKL_L2_SMAC)
#define IS2_HKL_MAC_ETYPE_ETYPE 16
#define IS2_HKO_MAC_ETYPE_L2_PAYLOAD \
(IS2_HKO_MAC_ETYPE_ETYPE + IS2_HKL_MAC_ETYPE_ETYPE)
#define IS2_HKL_MAC_ETYPE_L2_PAYLOAD 27
/* IS2 half key - MAC_LLC */
#define IS2_HKO_MAC_LLC_L2_LLC IS2_HKO_MAC_ETYPE_ETYPE
#define IS2_HKL_MAC_LLC_L2_LLC 40
/* IS2 half key - MAC_SNAP */
#define IS2_HKO_MAC_SNAP_L2_SNAP IS2_HKO_MAC_ETYPE_ETYPE
#define IS2_HKL_MAC_SNAP_L2_SNAP 40
/* IS2 half key - ARP */
#define IS2_HKO_MAC_ARP_L2_SMAC IS2_HKO_L2_DMAC
#define IS2_HKL_MAC_ARP_L2_SMAC 48
#define IS2_HKO_MAC_ARP_ARP_ADDR_SPACE_OK \
(IS2_HKO_MAC_ARP_L2_SMAC + IS2_HKL_MAC_ARP_L2_SMAC)
#define IS2_HKL_MAC_ARP_ARP_ADDR_SPACE_OK 1
#define IS2_HKO_MAC_ARP_ARP_PROTO_SPACE_OK \
(IS2_HKO_MAC_ARP_ARP_ADDR_SPACE_OK + IS2_HKL_MAC_ARP_ARP_ADDR_SPACE_OK)
#define IS2_HKL_MAC_ARP_ARP_PROTO_SPACE_OK 1
#define IS2_HKO_MAC_ARP_ARP_LEN_OK \
(IS2_HKO_MAC_ARP_ARP_PROTO_SPACE_OK + \
IS2_HKL_MAC_ARP_ARP_PROTO_SPACE_OK)
#define IS2_HKL_MAC_ARP_ARP_LEN_OK 1
#define IS2_HKO_MAC_ARP_ARP_TGT_MATCH \
(IS2_HKO_MAC_ARP_ARP_LEN_OK + IS2_HKL_MAC_ARP_ARP_LEN_OK)
#define IS2_HKL_MAC_ARP_ARP_TGT_MATCH 1
#define IS2_HKO_MAC_ARP_ARP_SENDER_MATCH \
(IS2_HKO_MAC_ARP_ARP_TGT_MATCH + IS2_HKL_MAC_ARP_ARP_TGT_MATCH)
#define IS2_HKL_MAC_ARP_ARP_SENDER_MATCH 1
#define IS2_HKO_MAC_ARP_ARP_OPCODE_UNKNOWN \
(IS2_HKO_MAC_ARP_ARP_SENDER_MATCH + IS2_HKL_MAC_ARP_ARP_SENDER_MATCH)
#define IS2_HKL_MAC_ARP_ARP_OPCODE_UNKNOWN 1
#define IS2_HKO_MAC_ARP_ARP_OPCODE \
(IS2_HKO_MAC_ARP_ARP_OPCODE_UNKNOWN + \
IS2_HKL_MAC_ARP_ARP_OPCODE_UNKNOWN)
#define IS2_HKL_MAC_ARP_ARP_OPCODE 2
#define IS2_HKO_MAC_ARP_L3_IP4_DIP \
(IS2_HKO_MAC_ARP_ARP_OPCODE + IS2_HKL_MAC_ARP_ARP_OPCODE)
#define IS2_HKL_MAC_ARP_L3_IP4_DIP 32
#define IS2_HKO_MAC_ARP_L3_IP4_SIP \
(IS2_HKO_MAC_ARP_L3_IP4_DIP + IS2_HKL_MAC_ARP_L3_IP4_DIP)
#define IS2_HKL_MAC_ARP_L3_IP4_SIP 32
#define IS2_HKO_MAC_ARP_DIP_EQ_SIP \
(IS2_HKO_MAC_ARP_L3_IP4_SIP + IS2_HKL_MAC_ARP_L3_IP4_SIP)
#define IS2_HKL_MAC_ARP_DIP_EQ_SIP 1
/* IS2 half key - IP4_TCP_UDP/IP4_OTHER common */
#define IS2_HKO_IP4 IS2_HKO_L2_DMAC
#define IS2_HKL_IP4 1
#define IS2_HKO_L3_FRAGMENT (IS2_HKO_IP4 + IS2_HKL_IP4)
#define IS2_HKL_L3_FRAGMENT 1
#define IS2_HKO_L3_FRAG_OFS_GT0 (IS2_HKO_L3_FRAGMENT + IS2_HKL_L3_FRAGMENT)
#define IS2_HKL_L3_FRAG_OFS_GT0 1
#define IS2_HKO_L3_OPTIONS (IS2_HKO_L3_FRAG_OFS_GT0 + IS2_HKL_L3_FRAG_OFS_GT0)
#define IS2_HKL_L3_OPTIONS 1
#define IS2_HKO_L3_TTL_GT0 (IS2_HKO_L3_OPTIONS + IS2_HKL_L3_OPTIONS)
#define IS2_HKL_L3_TTL_GT0 1
#define IS2_HKO_L3_TOS (IS2_HKO_L3_TTL_GT0 + IS2_HKL_L3_TTL_GT0)
#define IS2_HKL_L3_TOS 8
#define IS2_HKO_L3_IP4_DIP (IS2_HKO_L3_TOS + IS2_HKL_L3_TOS)
#define IS2_HKL_L3_IP4_DIP 32
#define IS2_HKO_L3_IP4_SIP (IS2_HKO_L3_IP4_DIP + IS2_HKL_L3_IP4_DIP)
#define IS2_HKL_L3_IP4_SIP 32
#define IS2_HKO_DIP_EQ_SIP (IS2_HKO_L3_IP4_SIP + IS2_HKL_L3_IP4_SIP)
#define IS2_HKL_DIP_EQ_SIP 1
/* IS2 half key - IP4_TCP_UDP */
#define IS2_HKO_IP4_TCP_UDP_TCP (IS2_HKO_DIP_EQ_SIP + IS2_HKL_DIP_EQ_SIP)
#define IS2_HKL_IP4_TCP_UDP_TCP 1
#define IS2_HKO_IP4_TCP_UDP_L4_DPORT \
(IS2_HKO_IP4_TCP_UDP_TCP + IS2_HKL_IP4_TCP_UDP_TCP)
#define IS2_HKL_IP4_TCP_UDP_L4_DPORT 16
#define IS2_HKO_IP4_TCP_UDP_L4_SPORT \
(IS2_HKO_IP4_TCP_UDP_L4_DPORT + IS2_HKL_IP4_TCP_UDP_L4_DPORT)
#define IS2_HKL_IP4_TCP_UDP_L4_SPORT 16
#define IS2_HKO_IP4_TCP_UDP_L4_RNG \
(IS2_HKO_IP4_TCP_UDP_L4_SPORT + IS2_HKL_IP4_TCP_UDP_L4_SPORT)
#define IS2_HKL_IP4_TCP_UDP_L4_RNG 8
#define IS2_HKO_IP4_TCP_UDP_SPORT_EQ_DPORT \
(IS2_HKO_IP4_TCP_UDP_L4_RNG + IS2_HKL_IP4_TCP_UDP_L4_RNG)
#define IS2_HKL_IP4_TCP_UDP_SPORT_EQ_DPORT 1
#define IS2_HKO_IP4_TCP_UDP_SEQUENCE_EQ0 \
(IS2_HKO_IP4_TCP_UDP_SPORT_EQ_DPORT + \
IS2_HKL_IP4_TCP_UDP_SPORT_EQ_DPORT)
#define IS2_HKL_IP4_TCP_UDP_SEQUENCE_EQ0 1
#define IS2_HKO_IP4_TCP_UDP_L4_FIN \
(IS2_HKO_IP4_TCP_UDP_SEQUENCE_EQ0 + IS2_HKL_IP4_TCP_UDP_SEQUENCE_EQ0)
#define IS2_HKL_IP4_TCP_UDP_L4_FIN 1
#define IS2_HKO_IP4_TCP_UDP_L4_SYN \
(IS2_HKO_IP4_TCP_UDP_L4_FIN + IS2_HKL_IP4_TCP_UDP_L4_FIN)
#define IS2_HKL_IP4_TCP_UDP_L4_SYN 1
#define IS2_HKO_IP4_TCP_UDP_L4_RST \
(IS2_HKO_IP4_TCP_UDP_L4_SYN + IS2_HKL_IP4_TCP_UDP_L4_SYN)
#define IS2_HKL_IP4_TCP_UDP_L4_RST 1
#define IS2_HKO_IP4_TCP_UDP_L4_PSH \
(IS2_HKO_IP4_TCP_UDP_L4_RST + IS2_HKL_IP4_TCP_UDP_L4_RST)
#define IS2_HKL_IP4_TCP_UDP_L4_PSH 1
#define IS2_HKO_IP4_TCP_UDP_L4_ACK \
(IS2_HKO_IP4_TCP_UDP_L4_PSH + IS2_HKL_IP4_TCP_UDP_L4_PSH)
#define IS2_HKL_IP4_TCP_UDP_L4_ACK 1
#define IS2_HKO_IP4_TCP_UDP_L4_URG \
(IS2_HKO_IP4_TCP_UDP_L4_ACK + IS2_HKL_IP4_TCP_UDP_L4_ACK)
#define IS2_HKL_IP4_TCP_UDP_L4_URG 1
#define IS2_HKO_IP4_TCP_UDP_L4_1588_DOM \
(IS2_HKO_IP4_TCP_UDP_L4_URG + IS2_HKL_IP4_TCP_UDP_L4_URG)
#define IS2_HKL_IP4_TCP_UDP_L4_1588_DOM 8
#define IS2_HKO_IP4_TCP_UDP_L4_1588_VER \
(IS2_HKO_IP4_TCP_UDP_L4_1588_DOM + IS2_HKL_IP4_TCP_UDP_L4_1588_DOM)
#define IS2_HKL_IP4_TCP_UDP_L4_1588_VER 4
/* IS2 half key - IP4_OTHER */
#define IS2_HKO_IP4_OTHER_L3_PROTO IS2_HKO_IP4_TCP_UDP_TCP
#define IS2_HKL_IP4_OTHER_L3_PROTO 8
#define IS2_HKO_IP4_OTHER_L3_PAYLOAD \
(IS2_HKO_IP4_OTHER_L3_PROTO + IS2_HKL_IP4_OTHER_L3_PROTO)
#define IS2_HKL_IP4_OTHER_L3_PAYLOAD 56
/* IS2 half key - IP6_STD */
#define IS2_HKO_IP6_STD_L3_TTL_GT0 IS2_HKO_L2_DMAC
#define IS2_HKL_IP6_STD_L3_TTL_GT0 1
#define IS2_HKO_IP6_STD_L3_IP6_SIP \
(IS2_HKO_IP6_STD_L3_TTL_GT0 + IS2_HKL_IP6_STD_L3_TTL_GT0)
#define IS2_HKL_IP6_STD_L3_IP6_SIP 128
#define IS2_HKO_IP6_STD_L3_PROTO \
(IS2_HKO_IP6_STD_L3_IP6_SIP + IS2_HKL_IP6_STD_L3_IP6_SIP)
#define IS2_HKL_IP6_STD_L3_PROTO 8
/* IS2 half key - OAM */
#define IS2_HKO_OAM_OAM_MEL_FLAGS IS2_HKO_MAC_ETYPE_ETYPE
#define IS2_HKL_OAM_OAM_MEL_FLAGS 7
#define IS2_HKO_OAM_OAM_VER \
(IS2_HKO_OAM_OAM_MEL_FLAGS + IS2_HKL_OAM_OAM_MEL_FLAGS)
#define IS2_HKL_OAM_OAM_VER 5
#define IS2_HKO_OAM_OAM_OPCODE (IS2_HKO_OAM_OAM_VER + IS2_HKL_OAM_OAM_VER)
#define IS2_HKL_OAM_OAM_OPCODE 8
#define IS2_HKO_OAM_OAM_FLAGS (IS2_HKO_OAM_OAM_OPCODE + IS2_HKL_OAM_OAM_OPCODE)
#define IS2_HKL_OAM_OAM_FLAGS 8
#define IS2_HKO_OAM_OAM_MEPID (IS2_HKO_OAM_OAM_FLAGS + IS2_HKL_OAM_OAM_FLAGS)
#define IS2_HKL_OAM_OAM_MEPID 16
#define IS2_HKO_OAM_OAM_CCM_CNTS_EQ0 \
(IS2_HKO_OAM_OAM_MEPID + IS2_HKL_OAM_OAM_MEPID)
#define IS2_HKL_OAM_OAM_CCM_CNTS_EQ0 1
/* IS2 half key - SMAC_SIP6 */
#define IS2_HKO_SMAC_SIP6_IGR_PORT IS2_HKL_TYPE
#define IS2_HKL_SMAC_SIP6_IGR_PORT VCAP_PORT_WIDTH
#define IS2_HKO_SMAC_SIP6_L2_SMAC \
(IS2_HKO_SMAC_SIP6_IGR_PORT + IS2_HKL_SMAC_SIP6_IGR_PORT)
#define IS2_HKL_SMAC_SIP6_L2_SMAC 48
#define IS2_HKO_SMAC_SIP6_L3_IP6_SIP \
(IS2_HKO_SMAC_SIP6_L2_SMAC + IS2_HKL_SMAC_SIP6_L2_SMAC)
#define IS2_HKL_SMAC_SIP6_L3_IP6_SIP 128
/* IS2 full key - common */
#define IS2_FKO_TYPE 0
#define IS2_FKL_TYPE 2
#define IS2_FKO_FIRST (IS2_FKO_TYPE + IS2_FKL_TYPE)
#define IS2_FKL_FIRST 1
#define IS2_FKO_PAG (IS2_FKO_FIRST + IS2_FKL_FIRST)
#define IS2_FKL_PAG 8
#define IS2_FKO_IGR_PORT_MASK (IS2_FKO_PAG + IS2_FKL_PAG)
#define IS2_FKL_IGR_PORT_MASK (VCAP_PORT_CNT + 1)
#define IS2_FKO_SERVICE_FRM (IS2_FKO_IGR_PORT_MASK + IS2_FKL_IGR_PORT_MASK)
#define IS2_FKL_SERVICE_FRM 1
#define IS2_FKO_HOST_MATCH (IS2_FKO_SERVICE_FRM + IS2_FKL_SERVICE_FRM)
#define IS2_FKL_HOST_MATCH 1
#define IS2_FKO_L2_MC (IS2_FKO_HOST_MATCH + IS2_FKL_HOST_MATCH)
#define IS2_FKL_L2_MC 1
#define IS2_FKO_L2_BC (IS2_FKO_L2_MC + IS2_FKL_L2_MC)
#define IS2_FKL_L2_BC 1
#define IS2_FKO_VLAN_TAGGED (IS2_FKO_L2_BC + IS2_FKL_L2_BC)
#define IS2_FKL_VLAN_TAGGED 1
#define IS2_FKO_VID (IS2_FKO_VLAN_TAGGED + IS2_FKL_VLAN_TAGGED)
#define IS2_FKL_VID 12
#define IS2_FKO_DEI (IS2_FKO_VID + IS2_FKL_VID)
#define IS2_FKL_DEI 1
#define IS2_FKO_PCP (IS2_FKO_DEI + IS2_FKL_DEI)
#define IS2_FKL_PCP 3
/* IS2 full key - IP6_TCP_UDP/IP6_OTHER common */
#define IS2_FKO_L3_TTL_GT0 (IS2_FKO_PCP + IS2_FKL_PCP)
#define IS2_FKL_L3_TTL_GT0 1
#define IS2_FKO_L3_TOS (IS2_FKO_L3_TTL_GT0 + IS2_FKL_L3_TTL_GT0)
#define IS2_FKL_L3_TOS 8
#define IS2_FKO_L3_IP6_DIP (IS2_FKO_L3_TOS + IS2_FKL_L3_TOS)
#define IS2_FKL_L3_IP6_DIP 128
#define IS2_FKO_L3_IP6_SIP (IS2_FKO_L3_IP6_DIP + IS2_FKL_L3_IP6_DIP)
#define IS2_FKL_L3_IP6_SIP 128
#define IS2_FKO_DIP_EQ_SIP (IS2_FKO_L3_IP6_SIP + IS2_FKL_L3_IP6_SIP)
#define IS2_FKL_DIP_EQ_SIP 1
/* IS2 full key - IP6_TCP_UDP */
#define IS2_FKO_IP6_TCP_UDP_TCP (IS2_FKO_DIP_EQ_SIP + IS2_FKL_DIP_EQ_SIP)
#define IS2_FKL_IP6_TCP_UDP_TCP 1
#define IS2_FKO_IP6_TCP_UDP_L4_DPORT \
(IS2_FKO_IP6_TCP_UDP_TCP + IS2_FKL_IP6_TCP_UDP_TCP)
#define IS2_FKL_IP6_TCP_UDP_L4_DPORT 16
#define IS2_FKO_IP6_TCP_UDP_L4_SPORT \
(IS2_FKO_IP6_TCP_UDP_L4_DPORT + IS2_FKL_IP6_TCP_UDP_L4_DPORT)
#define IS2_FKL_IP6_TCP_UDP_L4_SPORT 16
#define IS2_FKO_IP6_TCP_UDP_L4_RNG \
(IS2_FKO_IP6_TCP_UDP_L4_SPORT + IS2_FKL_IP6_TCP_UDP_L4_SPORT)
#define IS2_FKL_IP6_TCP_UDP_L4_RNG 8
#define IS2_FKO_IP6_TCP_UDP_SPORT_EQ_DPORT \
(IS2_FKO_IP6_TCP_UDP_L4_RNG + IS2_FKL_IP6_TCP_UDP_L4_RNG)
#define IS2_FKL_IP6_TCP_UDP_SPORT_EQ_DPORT 1
#define IS2_FKO_IP6_TCP_UDP_SEQUENCE_EQ0 \
(IS2_FKO_IP6_TCP_UDP_SPORT_EQ_DPORT + \
IS2_FKL_IP6_TCP_UDP_SPORT_EQ_DPORT)
#define IS2_FKL_IP6_TCP_UDP_SEQUENCE_EQ0 1
#define IS2_FKO_IP6_TCP_UDP_L4_FIN \
(IS2_FKO_IP6_TCP_UDP_SEQUENCE_EQ0 + IS2_FKL_IP6_TCP_UDP_SEQUENCE_EQ0)
#define IS2_FKL_IP6_TCP_UDP_L4_FIN 1
#define IS2_FKO_IP6_TCP_UDP_L4_SYN \
(IS2_FKO_IP6_TCP_UDP_L4_FIN + IS2_FKL_IP6_TCP_UDP_L4_FIN)
#define IS2_FKL_IP6_TCP_UDP_L4_SYN 1
#define IS2_FKO_IP6_TCP_UDP_L4_RST \
(IS2_FKO_IP6_TCP_UDP_L4_SYN + IS2_FKL_IP6_TCP_UDP_L4_SYN)
#define IS2_FKL_IP6_TCP_UDP_L4_RST 1
#define IS2_FKO_IP6_TCP_UDP_L4_PSH \
(IS2_FKO_IP6_TCP_UDP_L4_RST + IS2_FKL_IP6_TCP_UDP_L4_RST)
#define IS2_FKL_IP6_TCP_UDP_L4_PSH 1
#define IS2_FKO_IP6_TCP_UDP_L4_ACK \
(IS2_FKO_IP6_TCP_UDP_L4_PSH + IS2_FKL_IP6_TCP_UDP_L4_PSH)
#define IS2_FKL_IP6_TCP_UDP_L4_ACK 1
#define IS2_FKO_IP6_TCP_UDP_L4_URG \
(IS2_FKO_IP6_TCP_UDP_L4_ACK + IS2_FKL_IP6_TCP_UDP_L4_ACK)
#define IS2_FKL_IP6_TCP_UDP_L4_URG 1
#define IS2_FKO_IP6_TCP_UDP_L4_1588_DOM \
(IS2_FKO_IP6_TCP_UDP_L4_URG + IS2_FKL_IP6_TCP_UDP_L4_URG)
#define IS2_FKL_IP6_TCP_UDP_L4_1588_DOM 8
#define IS2_FKO_IP6_TCP_UDP_L4_1588_VER \
(IS2_FKO_IP6_TCP_UDP_L4_1588_DOM + IS2_FKL_IP6_TCP_UDP_L4_1588_DOM)
#define IS2_FKL_IP6_TCP_UDP_L4_1588_VER 4
/* IS2 full key - IP6_OTHER */
#define IS2_FKO_IP6_OTHER_L3_PROTO IS2_FKO_IP6_TCP_UDP_TCP
#define IS2_FKL_IP6_OTHER_L3_PROTO 8
#define IS2_FKO_IP6_OTHER_L3_PAYLOAD \
(IS2_FKO_IP6_OTHER_L3_PROTO + IS2_FKL_IP6_OTHER_L3_PROTO)
#define IS2_FKL_IP6_OTHER_L3_PAYLOAD 56
/* IS2 full key - CUSTOM */
#define IS2_FKO_CUSTOM_CUSTOM_TYPE IS2_FKO_L3_TTL_GT0
#define IS2_FKL_CUSTOM_CUSTOM_TYPE 1
#define IS2_FKO_CUSTOM_CUSTOM \
(IS2_FKO_CUSTOM_CUSTOM_TYPE + IS2_FKL_CUSTOM_CUSTOM_TYPE)
#define IS2_FKL_CUSTOM_CUSTOM 320
/* IS2 action - BASE_TYPE */
#define IS2_AO_HIT_ME_ONCE 0
#define IS2_AL_HIT_ME_ONCE 1
#define IS2_AO_CPU_COPY_ENA (IS2_AO_HIT_ME_ONCE + IS2_AL_HIT_ME_ONCE)
#define IS2_AL_CPU_COPY_ENA 1
#define IS2_AO_CPU_QU_NUM (IS2_AO_CPU_COPY_ENA + IS2_AL_CPU_COPY_ENA)
#define IS2_AL_CPU_QU_NUM 3
#define IS2_AO_MASK_MODE (IS2_AO_CPU_QU_NUM + IS2_AL_CPU_QU_NUM)
#define IS2_AL_MASK_MODE 2
#define IS2_AO_MIRROR_ENA (IS2_AO_MASK_MODE + IS2_AL_MASK_MODE)
#define IS2_AL_MIRROR_ENA 1
#define IS2_AO_LRN_DIS (IS2_AO_MIRROR_ENA + IS2_AL_MIRROR_ENA)
#define IS2_AL_LRN_DIS 1
#define IS2_AO_POLICE_ENA (IS2_AO_LRN_DIS + IS2_AL_LRN_DIS)
#define IS2_AL_POLICE_ENA 1
#define IS2_AO_POLICE_IDX (IS2_AO_POLICE_ENA + IS2_AL_POLICE_ENA)
#define IS2_AL_POLICE_IDX 9
#define IS2_AO_POLICE_VCAP_ONLY (IS2_AO_POLICE_IDX + IS2_AL_POLICE_IDX)
#define IS2_AL_POLICE_VCAP_ONLY 1
#define IS2_AO_PORT_MASK (IS2_AO_POLICE_VCAP_ONLY + IS2_AL_POLICE_VCAP_ONLY)
#define IS2_AL_PORT_MASK VCAP_PORT_CNT
#define IS2_AO_REW_OP (IS2_AO_PORT_MASK + IS2_AL_PORT_MASK)
#define IS2_AL_REW_OP 9
#define IS2_AO_LM_CNT_DIS (IS2_AO_REW_OP + IS2_AL_REW_OP)
#define IS2_AL_LM_CNT_DIS 1
#define IS2_AO_ISDX_ENA \
(IS2_AO_LM_CNT_DIS + IS2_AL_LM_CNT_DIS + 1) /* Reserved bit */
#define IS2_AL_ISDX_ENA 1
#define IS2_AO_ACL_ID (IS2_AO_ISDX_ENA + IS2_AL_ISDX_ENA)
#define IS2_AL_ACL_ID 6
/* IS2 action - SMAC_SIP */
#define IS2_AO_SMAC_SIP_CPU_COPY_ENA 0
#define IS2_AL_SMAC_SIP_CPU_COPY_ENA 1
#define IS2_AO_SMAC_SIP_CPU_QU_NUM 1
#define IS2_AL_SMAC_SIP_CPU_QU_NUM 3
#define IS2_AO_SMAC_SIP_FWD_KILL_ENA 4
#define IS2_AL_SMAC_SIP_FWD_KILL_ENA 1
#define IS2_AO_SMAC_SIP_HOST_MATCH 5
#define IS2_AL_SMAC_SIP_HOST_MATCH 1
#endif /* _OCELOT_VCAP_H_ */
......@@ -540,6 +540,12 @@ struct dsa_switch_ops {
/*
* TC integration
*/
int (*cls_flower_add)(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress);
int (*cls_flower_del)(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress);
int (*cls_flower_stats)(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress);
int (*port_mirror_add)(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress);
......
......@@ -402,10 +402,14 @@ enum ocelot_tag_prefix {
struct ocelot;
struct ocelot_ops {
void (*pcs_init)(struct ocelot *ocelot, int port);
int (*reset)(struct ocelot *ocelot);
};
struct ocelot_acl_block {
struct list_head rules;
int count;
};
struct ocelot_port {
struct ocelot *ocelot;
......@@ -455,6 +459,12 @@ struct ocelot {
struct list_head multicast;
struct ocelot_acl_block acl_block;
const struct vcap_field *vcap_is2_keys;
const struct vcap_field *vcap_is2_actions;
const struct vcap_props *vcap;
/* Workqueue to check statistics for overflow with its lock */
struct mutex stats_lock;
u64 *stats;
......@@ -469,8 +479,6 @@ struct ocelot {
struct mutex ptp_lock;
/* Protects the PTP clock */
spinlock_t ptp_clock_lock;
void (*port_pcs_init)(struct ocelot_port *port);
};
#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
......@@ -541,5 +549,11 @@ int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
struct sk_buff *skb);
void ocelot_get_txtstamp(struct ocelot *ocelot);
int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress);
int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress);
int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress);
#endif
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Microsemi Ocelot Switch driver
* Copyright (c) 2019 Microsemi Corporation
*/
#ifndef _OCELOT_VCAP_H_
#define _OCELOT_VCAP_H_
/* =================================================================
* VCAP Common
* =================================================================
*/
enum {
/* VCAP_IS1, */
VCAP_IS2,
/* VCAP_ES0, */
};
struct vcap_props {
u16 tg_width; /* Type-group width (in bits) */
u16 sw_count; /* Sub word count */
u16 entry_count; /* Entry count */
u16 entry_words; /* Number of entry words */
u16 entry_width; /* Entry width (in bits) */
u16 action_count; /* Action count */
u16 action_words; /* Number of action words */
u16 action_width; /* Action width (in bits) */
u16 action_type_width; /* Action type width (in bits) */
struct {
u16 width; /* Action type width (in bits) */
u16 count; /* Action type sub word count */
} action_table[2];
u16 counter_words; /* Number of counter words */
u16 counter_width; /* Counter width (in bits) */
};
/* VCAP Type-Group values */
#define VCAP_TG_NONE 0 /* Entry is invalid */
#define VCAP_TG_FULL 1 /* Full entry */
#define VCAP_TG_HALF 2 /* Half entry */
#define VCAP_TG_QUARTER 3 /* Quarter entry */
/* =================================================================
* VCAP IS2
* =================================================================
*/
/* IS2 half key types */
#define IS2_TYPE_ETYPE 0
#define IS2_TYPE_LLC 1
#define IS2_TYPE_SNAP 2
#define IS2_TYPE_ARP 3
#define IS2_TYPE_IP_UDP_TCP 4
#define IS2_TYPE_IP_OTHER 5
#define IS2_TYPE_IPV6 6
#define IS2_TYPE_OAM 7
#define IS2_TYPE_SMAC_SIP6 8
#define IS2_TYPE_ANY 100 /* Pseudo type */
/* IS2 half key type mask for matching any IP */
#define IS2_TYPE_MASK_IP_ANY 0xe
enum {
IS2_ACTION_TYPE_NORMAL,
IS2_ACTION_TYPE_SMAC_SIP,
IS2_ACTION_TYPE_MAX,
};
/* IS2 MASK_MODE values */
#define IS2_ACT_MASK_MODE_NONE 0
#define IS2_ACT_MASK_MODE_FILTER 1
#define IS2_ACT_MASK_MODE_POLICY 2
#define IS2_ACT_MASK_MODE_REDIR 3
/* IS2 REW_OP values */
#define IS2_ACT_REW_OP_NONE 0
#define IS2_ACT_REW_OP_PTP_ONE 2
#define IS2_ACT_REW_OP_PTP_TWO 3
#define IS2_ACT_REW_OP_SPECIAL 8
#define IS2_ACT_REW_OP_PTP_ORG 9
#define IS2_ACT_REW_OP_PTP_ONE_SUB_DELAY_1 (IS2_ACT_REW_OP_PTP_ONE | (1 << 3))
#define IS2_ACT_REW_OP_PTP_ONE_SUB_DELAY_2 (IS2_ACT_REW_OP_PTP_ONE | (2 << 3))
#define IS2_ACT_REW_OP_PTP_ONE_ADD_DELAY (IS2_ACT_REW_OP_PTP_ONE | (1 << 5))
#define IS2_ACT_REW_OP_PTP_ONE_ADD_SUB BIT(7)
#define VCAP_PORT_WIDTH 4
/* IS2 quarter key - SMAC_SIP4 */
#define IS2_QKO_IGR_PORT 0
#define IS2_QKL_IGR_PORT VCAP_PORT_WIDTH
#define IS2_QKO_L2_SMAC (IS2_QKO_IGR_PORT + IS2_QKL_IGR_PORT)
#define IS2_QKL_L2_SMAC 48
#define IS2_QKO_L3_IP4_SIP (IS2_QKO_L2_SMAC + IS2_QKL_L2_SMAC)
#define IS2_QKL_L3_IP4_SIP 32
enum vcap_is2_half_key_field {
/* Common */
VCAP_IS2_TYPE,
VCAP_IS2_HK_FIRST,
VCAP_IS2_HK_PAG,
VCAP_IS2_HK_RSV1,
VCAP_IS2_HK_IGR_PORT_MASK,
VCAP_IS2_HK_RSV2,
VCAP_IS2_HK_HOST_MATCH,
VCAP_IS2_HK_L2_MC,
VCAP_IS2_HK_L2_BC,
VCAP_IS2_HK_VLAN_TAGGED,
VCAP_IS2_HK_VID,
VCAP_IS2_HK_DEI,
VCAP_IS2_HK_PCP,
/* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */
VCAP_IS2_HK_L2_DMAC,
VCAP_IS2_HK_L2_SMAC,
/* MAC_ETYPE (TYPE=000) */
VCAP_IS2_HK_MAC_ETYPE_ETYPE,
VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1,
VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2,
/* MAC_LLC (TYPE=001) */
VCAP_IS2_HK_MAC_LLC_DMAC,
VCAP_IS2_HK_MAC_LLC_SMAC,
VCAP_IS2_HK_MAC_LLC_L2_LLC,
/* MAC_SNAP (TYPE=010) */
VCAP_IS2_HK_MAC_SNAP_SMAC,
VCAP_IS2_HK_MAC_SNAP_DMAC,
VCAP_IS2_HK_MAC_SNAP_L2_SNAP,
/* MAC_ARP (TYPE=011) */
VCAP_IS2_HK_MAC_ARP_SMAC,
VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK,
VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK,
VCAP_IS2_HK_MAC_ARP_LEN_OK,
VCAP_IS2_HK_MAC_ARP_TARGET_MATCH,
VCAP_IS2_HK_MAC_ARP_SENDER_MATCH,
VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN,
VCAP_IS2_HK_MAC_ARP_OPCODE,
VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP,
VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP,
VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP,
/* IP4_TCP_UDP / IP4_OTHER common */
VCAP_IS2_HK_IP4,
VCAP_IS2_HK_L3_FRAGMENT,
VCAP_IS2_HK_L3_FRAG_OFS_GT0,
VCAP_IS2_HK_L3_OPTIONS,
VCAP_IS2_HK_IP4_L3_TTL_GT0,
VCAP_IS2_HK_L3_TOS,
VCAP_IS2_HK_L3_IP4_DIP,
VCAP_IS2_HK_L3_IP4_SIP,
VCAP_IS2_HK_DIP_EQ_SIP,
/* IP4_TCP_UDP (TYPE=100) */
VCAP_IS2_HK_TCP,
VCAP_IS2_HK_L4_SPORT,
VCAP_IS2_HK_L4_DPORT,
VCAP_IS2_HK_L4_RNG,
VCAP_IS2_HK_L4_SPORT_EQ_DPORT,
VCAP_IS2_HK_L4_SEQUENCE_EQ0,
VCAP_IS2_HK_L4_URG,
VCAP_IS2_HK_L4_ACK,
VCAP_IS2_HK_L4_PSH,
VCAP_IS2_HK_L4_RST,
VCAP_IS2_HK_L4_SYN,
VCAP_IS2_HK_L4_FIN,
VCAP_IS2_HK_L4_1588_DOM,
VCAP_IS2_HK_L4_1588_VER,
/* IP4_OTHER (TYPE=101) */
VCAP_IS2_HK_IP4_L3_PROTO,
VCAP_IS2_HK_L3_PAYLOAD,
/* IP6_STD (TYPE=110) */
VCAP_IS2_HK_IP6_L3_TTL_GT0,
VCAP_IS2_HK_IP6_L3_PROTO,
VCAP_IS2_HK_L3_IP6_SIP,
/* OAM (TYPE=111) */
VCAP_IS2_HK_OAM_MEL_FLAGS,
VCAP_IS2_HK_OAM_VER,
VCAP_IS2_HK_OAM_OPCODE,
VCAP_IS2_HK_OAM_FLAGS,
VCAP_IS2_HK_OAM_MEPID,
VCAP_IS2_HK_OAM_CCM_CNTS_EQ0,
VCAP_IS2_HK_OAM_IS_Y1731,
};
struct vcap_field {
int offset;
int length;
};
enum vcap_is2_action_field {
VCAP_IS2_ACT_HIT_ME_ONCE,
VCAP_IS2_ACT_CPU_COPY_ENA,
VCAP_IS2_ACT_CPU_QU_NUM,
VCAP_IS2_ACT_MASK_MODE,
VCAP_IS2_ACT_MIRROR_ENA,
VCAP_IS2_ACT_LRN_DIS,
VCAP_IS2_ACT_POLICE_ENA,
VCAP_IS2_ACT_POLICE_IDX,
VCAP_IS2_ACT_POLICE_VCAP_ONLY,
VCAP_IS2_ACT_PORT_MASK,
VCAP_IS2_ACT_REW_OP,
VCAP_IS2_ACT_SMAC_REPLACE_ENA,
VCAP_IS2_ACT_RSV,
VCAP_IS2_ACT_ACL_ID,
VCAP_IS2_ACT_HIT_CNT,
};
#endif /* _OCELOT_VCAP_H_ */
......@@ -946,6 +946,64 @@ static int dsa_slave_setup_tc_cls_matchall(struct net_device *dev,
}
}
static int dsa_slave_add_cls_flower(struct net_device *dev,
struct flow_cls_offload *cls,
bool ingress)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
int port = dp->index;
if (!ds->ops->cls_flower_add)
return -EOPNOTSUPP;
return ds->ops->cls_flower_add(ds, port, cls, ingress);
}
static int dsa_slave_del_cls_flower(struct net_device *dev,
struct flow_cls_offload *cls,
bool ingress)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
int port = dp->index;
if (!ds->ops->cls_flower_del)
return -EOPNOTSUPP;
return ds->ops->cls_flower_del(ds, port, cls, ingress);
}
static int dsa_slave_stats_cls_flower(struct net_device *dev,
struct flow_cls_offload *cls,
bool ingress)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
int port = dp->index;
if (!ds->ops->cls_flower_stats)
return -EOPNOTSUPP;
return ds->ops->cls_flower_stats(ds, port, cls, ingress);
}
static int dsa_slave_setup_tc_cls_flower(struct net_device *dev,
struct flow_cls_offload *cls,
bool ingress)
{
switch (cls->command) {
case FLOW_CLS_REPLACE:
return dsa_slave_add_cls_flower(dev, cls, ingress);
case FLOW_CLS_DESTROY:
return dsa_slave_del_cls_flower(dev, cls, ingress);
case FLOW_CLS_STATS:
return dsa_slave_stats_cls_flower(dev, cls, ingress);
default:
return -EOPNOTSUPP;
}
}
static int dsa_slave_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv, bool ingress)
{
......@@ -957,6 +1015,8 @@ static int dsa_slave_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
switch (type) {
case TC_SETUP_CLSMATCHALL:
return dsa_slave_setup_tc_cls_matchall(dev, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return dsa_slave_setup_tc_cls_flower(dev, type_data, ingress);
default:
return -EOPNOTSUPP;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment