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

Merge branch 'dsa-felix-psfp'

Xiaoliang Yang says:

====================
net: dsa: felix: psfp support on vsc9959

VSC9959 hardware supports Per-Stream Filtering and Policing(PSFP).
This patch series add PSFP support on tc flower offload of ocelot
driver. Use chain 30000 to distinguish PSFP from VCAP blocks. Add gate
and police set to support PSFP in VSC9959 driver.

v6-v7 changes:
 - Add a patch to restrict psfp rules on ingress port.
 - Using stats.drops to show the packet count discarded by the rule.

v5->v6 changes:
 - Modify ocelot_mact_lookup() parameters.
 - Use parameters ssid and sfid instead of streamdata in
   ocelot_mact_learn_streamdata() function.
 - Serialize STREAMDATA and MAC table write.

v4->v5 changes:
 - Add MAC table lock patch, and move stream data write in
   ocelot_mact_learn_streamdata().
 - Add two sections of VCAP policers to Seville platform.

v3->v4 changes:
 - Introduce vsc9959_psfp_sfi_table_get() function in patch where it is
   used to fix compile warning.

v2->v3 changes:
 - Reorder first two patches. Export struct ocelot_mact_entry, then add
   ocelot_mact_lookup() and ocelot_mact_write() functions.
 - Add PSFP list to struct ocelot, and init it by using
   ocelot->ops->psfp_init().

v1->v2 changes:
 - Use tc flower offload of ocelot driver to support PSFP add and delete.
 - Add PSFP tables add/del functions in felix_vsc9959.c.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f6ef47e5 a7e13edf
...@@ -989,6 +989,10 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ...@@ -989,6 +989,10 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
ocelot->num_stats = felix->info->num_stats; ocelot->num_stats = felix->info->num_stats;
ocelot->num_mact_rows = felix->info->num_mact_rows; ocelot->num_mact_rows = felix->info->num_mact_rows;
ocelot->vcap = felix->info->vcap; ocelot->vcap = felix->info->vcap;
ocelot->vcap_pol.base = felix->info->vcap_pol_base;
ocelot->vcap_pol.max = felix->info->vcap_pol_max;
ocelot->vcap_pol.base2 = felix->info->vcap_pol_base2;
ocelot->vcap_pol.max2 = felix->info->vcap_pol_max2;
ocelot->ops = felix->info->ops; ocelot->ops = felix->info->ops;
ocelot->npi_inj_prefix = OCELOT_TAG_PREFIX_SHORT; ocelot->npi_inj_prefix = OCELOT_TAG_PREFIX_SHORT;
ocelot->npi_xtr_prefix = OCELOT_TAG_PREFIX_SHORT; ocelot->npi_xtr_prefix = OCELOT_TAG_PREFIX_SHORT;
......
...@@ -21,6 +21,10 @@ struct felix_info { ...@@ -21,6 +21,10 @@ struct felix_info {
int num_ports; int num_ports;
int num_tx_queues; int num_tx_queues;
struct vcap_props *vcap; struct vcap_props *vcap;
u16 vcap_pol_base;
u16 vcap_pol_max;
u16 vcap_pol_base2;
u16 vcap_pol_max2;
int switch_pci_bar; int switch_pci_bar;
int imdio_pci_bar; int imdio_pci_bar;
const struct ptp_clock_info *ptp_caps; const struct ptp_clock_info *ptp_caps;
......
This diff is collapsed.
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
#define MSCC_MIIM_CMD_REGAD_SHIFT 20 #define MSCC_MIIM_CMD_REGAD_SHIFT 20
#define MSCC_MIIM_CMD_PHYAD_SHIFT 25 #define MSCC_MIIM_CMD_PHYAD_SHIFT 25
#define MSCC_MIIM_CMD_VLD BIT(31) #define MSCC_MIIM_CMD_VLD BIT(31)
#define VSC9953_VCAP_POLICER_BASE 11
#define VSC9953_VCAP_POLICER_MAX 31
#define VSC9953_VCAP_POLICER_BASE2 120
#define VSC9953_VCAP_POLICER_MAX2 161
static const u32 vsc9953_ana_regmap[] = { static const u32 vsc9953_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x00b500), REG(ANA_ADVLEARN, 0x00b500),
...@@ -1172,6 +1176,10 @@ static const struct felix_info seville_info_vsc9953 = { ...@@ -1172,6 +1176,10 @@ static const struct felix_info seville_info_vsc9953 = {
.stats_layout = vsc9953_stats_layout, .stats_layout = vsc9953_stats_layout,
.num_stats = ARRAY_SIZE(vsc9953_stats_layout), .num_stats = ARRAY_SIZE(vsc9953_stats_layout),
.vcap = vsc9953_vcap_props, .vcap = vsc9953_vcap_props,
.vcap_pol_base = VSC9953_VCAP_POLICER_BASE,
.vcap_pol_max = VSC9953_VCAP_POLICER_MAX,
.vcap_pol_base2 = VSC9953_VCAP_POLICER_BASE2,
.vcap_pol_max2 = VSC9953_VCAP_POLICER_MAX2,
.num_mact_rows = 2048, .num_mact_rows = 2048,
.num_ports = 10, .num_ports = 10,
.num_tx_queues = OCELOT_NUM_TC, .num_tx_queues = OCELOT_NUM_TC,
......
...@@ -61,7 +61,7 @@ static void ocelot_mact_select(struct ocelot *ocelot, ...@@ -61,7 +61,7 @@ static void ocelot_mact_select(struct ocelot *ocelot,
} }
int ocelot_mact_learn(struct ocelot *ocelot, int port, static int __ocelot_mact_learn(struct ocelot *ocelot, int port,
const unsigned char mac[ETH_ALEN], const unsigned char mac[ETH_ALEN],
unsigned int vid, enum macaccess_entry_type type) unsigned int vid, enum macaccess_entry_type type)
{ {
...@@ -83,8 +83,6 @@ int ocelot_mact_learn(struct ocelot *ocelot, int port, ...@@ -83,8 +83,6 @@ int ocelot_mact_learn(struct ocelot *ocelot, int port,
if (mc_ports & BIT(ocelot->num_phys_ports)) if (mc_ports & BIT(ocelot->num_phys_ports))
cmd |= ANA_TABLES_MACACCESS_MAC_CPU_COPY; cmd |= ANA_TABLES_MACACCESS_MAC_CPU_COPY;
mutex_lock(&ocelot->mact_lock);
ocelot_mact_select(ocelot, mac, vid); ocelot_mact_select(ocelot, mac, vid);
/* Issue a write command */ /* Issue a write command */
...@@ -92,9 +90,20 @@ int ocelot_mact_learn(struct ocelot *ocelot, int port, ...@@ -92,9 +90,20 @@ int ocelot_mact_learn(struct ocelot *ocelot, int port,
err = ocelot_mact_wait_for_completion(ocelot); err = ocelot_mact_wait_for_completion(ocelot);
return err;
}
int ocelot_mact_learn(struct ocelot *ocelot, int port,
const unsigned char mac[ETH_ALEN],
unsigned int vid, enum macaccess_entry_type type)
{
int ret;
mutex_lock(&ocelot->mact_lock);
ret = __ocelot_mact_learn(ocelot, port, mac, vid, type);
mutex_unlock(&ocelot->mact_lock); mutex_unlock(&ocelot->mact_lock);
return err; return ret;
} }
EXPORT_SYMBOL(ocelot_mact_learn); EXPORT_SYMBOL(ocelot_mact_learn);
...@@ -120,6 +129,66 @@ int ocelot_mact_forget(struct ocelot *ocelot, ...@@ -120,6 +129,66 @@ int ocelot_mact_forget(struct ocelot *ocelot,
} }
EXPORT_SYMBOL(ocelot_mact_forget); EXPORT_SYMBOL(ocelot_mact_forget);
int ocelot_mact_lookup(struct ocelot *ocelot, int *dst_idx,
const unsigned char mac[ETH_ALEN],
unsigned int vid, enum macaccess_entry_type *type)
{
int val;
mutex_lock(&ocelot->mact_lock);
ocelot_mact_select(ocelot, mac, vid);
/* Issue a read command with MACACCESS_VALID=1. */
ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
ANA_TABLES_MACACCESS);
if (ocelot_mact_wait_for_completion(ocelot)) {
mutex_unlock(&ocelot->mact_lock);
return -ETIMEDOUT;
}
/* Read back the entry flags */
val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
mutex_unlock(&ocelot->mact_lock);
if (!(val & ANA_TABLES_MACACCESS_VALID))
return -ENOENT;
*dst_idx = ANA_TABLES_MACACCESS_DEST_IDX_X(val);
*type = ANA_TABLES_MACACCESS_ENTRYTYPE_X(val);
return 0;
}
EXPORT_SYMBOL(ocelot_mact_lookup);
int ocelot_mact_learn_streamdata(struct ocelot *ocelot, int dst_idx,
const unsigned char mac[ETH_ALEN],
unsigned int vid,
enum macaccess_entry_type type,
int sfid, int ssid)
{
int ret;
mutex_lock(&ocelot->mact_lock);
ocelot_write(ocelot,
(sfid < 0 ? 0 : ANA_TABLES_STREAMDATA_SFID_VALID) |
ANA_TABLES_STREAMDATA_SFID(sfid) |
(ssid < 0 ? 0 : ANA_TABLES_STREAMDATA_SSID_VALID) |
ANA_TABLES_STREAMDATA_SSID(ssid),
ANA_TABLES_STREAMDATA);
ret = __ocelot_mact_learn(ocelot, dst_idx, mac, vid, type);
mutex_unlock(&ocelot->mact_lock);
return ret;
}
EXPORT_SYMBOL(ocelot_mact_learn_streamdata);
static void ocelot_mact_init(struct ocelot *ocelot) static void ocelot_mact_init(struct ocelot *ocelot)
{ {
/* Configure the learning mode entries attributes: /* Configure the learning mode entries attributes:
...@@ -2283,6 +2352,9 @@ int ocelot_init(struct ocelot *ocelot) ...@@ -2283,6 +2352,9 @@ int ocelot_init(struct ocelot *ocelot)
ocelot_vcap_init(ocelot); ocelot_vcap_init(ocelot);
ocelot_cpu_port_init(ocelot); ocelot_cpu_port_init(ocelot);
if (ocelot->ops->psfp_init)
ocelot->ops->psfp_init(ocelot);
for (port = 0; port < ocelot->num_phys_ports; port++) { for (port = 0; port < ocelot->num_phys_ports; port++) {
/* Clear all counters (5 groups) */ /* Clear all counters (5 groups) */
ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port) | ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port) |
......
...@@ -55,19 +55,6 @@ struct ocelot_dump_ctx { ...@@ -55,19 +55,6 @@ struct ocelot_dump_ctx {
int idx; int idx;
}; };
/* MAC table entry types.
* ENTRYTYPE_NORMAL is subject to aging.
* ENTRYTYPE_LOCKED is not subject to aging.
* ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
* ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
*/
enum macaccess_entry_type {
ENTRYTYPE_NORMAL = 0,
ENTRYTYPE_LOCKED,
ENTRYTYPE_MACv4,
ENTRYTYPE_MACv6,
};
/* A (PGID) port mask structure, encoding the 2^ocelot->num_phys_ports /* A (PGID) port mask structure, encoding the 2^ocelot->num_phys_ports
* possibilities of egress port masks for L2 multicast traffic. * possibilities of egress port masks for L2 multicast traffic.
* For a switch with 9 user ports, there are 512 possible port masks, but the * For a switch with 9 user ports, there are 512 possible port masks, but the
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
(1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP) (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
#define VCAP_IS2_CHAIN(lookup, pag) \ #define VCAP_IS2_CHAIN(lookup, pag) \
(2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag)) (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
/* PSFP chain and block ID */
#define PSFP_BLOCK_ID OCELOT_NUM_VCAP_BLOCKS
#define OCELOT_PSFP_CHAIN (3 * VCAP_BLOCK)
static int ocelot_chain_to_block(int chain, bool ingress) static int ocelot_chain_to_block(int chain, bool ingress)
{ {
...@@ -46,6 +49,9 @@ static int ocelot_chain_to_block(int chain, bool ingress) ...@@ -46,6 +49,9 @@ static int ocelot_chain_to_block(int chain, bool ingress)
if (chain == VCAP_IS2_CHAIN(lookup, pag)) if (chain == VCAP_IS2_CHAIN(lookup, pag))
return VCAP_IS2; return VCAP_IS2;
if (chain == OCELOT_PSFP_CHAIN)
return PSFP_BLOCK_ID;
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -84,7 +90,8 @@ static bool ocelot_is_goto_target_valid(int goto_target, int chain, ...@@ -84,7 +90,8 @@ static bool ocelot_is_goto_target_valid(int goto_target, int chain,
goto_target == VCAP_IS1_CHAIN(1) || goto_target == VCAP_IS1_CHAIN(1) ||
goto_target == VCAP_IS1_CHAIN(2) || goto_target == VCAP_IS1_CHAIN(2) ||
goto_target == VCAP_IS2_CHAIN(0, 0) || goto_target == VCAP_IS2_CHAIN(0, 0) ||
goto_target == VCAP_IS2_CHAIN(1, 0)); goto_target == VCAP_IS2_CHAIN(1, 0) ||
goto_target == OCELOT_PSFP_CHAIN);
if (chain == VCAP_IS1_CHAIN(0)) if (chain == VCAP_IS1_CHAIN(0))
return (goto_target == VCAP_IS1_CHAIN(1)); return (goto_target == VCAP_IS1_CHAIN(1));
...@@ -111,7 +118,11 @@ static bool ocelot_is_goto_target_valid(int goto_target, int chain, ...@@ -111,7 +118,11 @@ static bool ocelot_is_goto_target_valid(int goto_target, int chain,
if (chain == VCAP_IS2_CHAIN(0, pag)) if (chain == VCAP_IS2_CHAIN(0, pag))
return (goto_target == VCAP_IS2_CHAIN(1, pag)); return (goto_target == VCAP_IS2_CHAIN(1, pag));
/* VCAP IS2 lookup 1 cannot jump anywhere */ /* VCAP IS2 lookup 1 can goto to PSFP block if hardware support */
for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
if (chain == VCAP_IS2_CHAIN(1, pag))
return (goto_target == OCELOT_PSFP_CHAIN);
return false; return false;
} }
...@@ -211,6 +222,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -211,6 +222,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
const struct flow_action_entry *a; const struct flow_action_entry *a;
enum ocelot_tag_tpid_sel tpid; enum ocelot_tag_tpid_sel tpid;
int i, chain, egress_port; int i, chain, egress_port;
u32 pol_ix, pol_max;
u64 rate; u64 rate;
int err; int err;
...@@ -269,10 +281,14 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -269,10 +281,14 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
filter->type = OCELOT_VCAP_FILTER_OFFLOAD; filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
break; break;
case FLOW_ACTION_POLICE: case FLOW_ACTION_POLICE:
if (filter->block_id == PSFP_BLOCK_ID) {
filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
break;
}
if (filter->block_id != VCAP_IS2 || if (filter->block_id != VCAP_IS2 ||
filter->lookup != 0) { filter->lookup != 0) {
NL_SET_ERR_MSG_MOD(extack, NL_SET_ERR_MSG_MOD(extack,
"Police action can only be offloaded to VCAP IS2 lookup 0"); "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (filter->goto_target != -1) { if (filter->goto_target != -1) {
...@@ -286,6 +302,20 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -286,6 +302,20 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
filter->action.police_ena = true; filter->action.police_ena = true;
pol_ix = a->police.index + ocelot->vcap_pol.base;
pol_max = ocelot->vcap_pol.max;
if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
pol_ix += ocelot->vcap_pol.base2 - pol_max - 1;
pol_max = ocelot->vcap_pol.max2;
}
if (pol_ix >= pol_max)
return -EINVAL;
filter->action.pol_ix = pol_ix;
rate = a->police.rate_bytes_ps; rate = a->police.rate_bytes_ps;
filter->action.pol.rate = div_u64(rate, 1000) * 8; filter->action.pol.rate = div_u64(rate, 1000) * 8;
filter->action.pol.burst = a->police.burst; filter->action.pol.burst = a->police.burst;
...@@ -399,6 +429,14 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -399,6 +429,14 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
filter->action.pcp_a_val = a->vlan.prio; filter->action.pcp_a_val = a->vlan.prio;
filter->type = OCELOT_VCAP_FILTER_OFFLOAD; filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
break; break;
case FLOW_ACTION_GATE:
if (filter->block_id != PSFP_BLOCK_ID) {
NL_SET_ERR_MSG_MOD(extack,
"Gate action can only be offloaded to PSFP chain");
return -EOPNOTSUPP;
}
filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
break;
default: default:
NL_SET_ERR_MSG_MOD(extack, "Cannot offload action"); NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -407,7 +445,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -407,7 +445,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
if (filter->goto_target == -1) { if (filter->goto_target == -1) {
if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) || if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
chain == 0) { chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
allow_missing_goto_target = true; allow_missing_goto_target = true;
} else { } else {
NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action"); NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
...@@ -689,6 +727,10 @@ static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress, ...@@ -689,6 +727,10 @@ static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
if (ret) if (ret)
return ret; return ret;
/* PSFP filter need to parse key by stream identification function. */
if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
return 0;
return ocelot_flower_parse_key(ocelot, port, ingress, f, filter); return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
} }
...@@ -792,6 +834,15 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port, ...@@ -792,6 +834,15 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
if (filter->type == OCELOT_VCAP_FILTER_DUMMY) if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
return ocelot_vcap_dummy_filter_add(ocelot, filter); return ocelot_vcap_dummy_filter_add(ocelot, filter);
if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
kfree(filter);
if (ocelot->ops->psfp_filter_add)
return ocelot->ops->psfp_filter_add(ocelot, port, f);
NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
return -EOPNOTSUPP;
}
return ocelot_vcap_filter_add(ocelot, filter, f->common.extack); return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
} }
EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace); EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
...@@ -807,6 +858,13 @@ int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port, ...@@ -807,6 +858,13 @@ int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
if (block_id < 0) if (block_id < 0)
return 0; return 0;
if (block_id == PSFP_BLOCK_ID) {
if (ocelot->ops->psfp_filter_del)
return ocelot->ops->psfp_filter_del(ocelot, f);
return -EOPNOTSUPP;
}
block = &ocelot->block[block_id]; block = &ocelot->block[block_id];
filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true); filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
...@@ -825,12 +883,25 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port, ...@@ -825,12 +883,25 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
{ {
struct ocelot_vcap_filter *filter; struct ocelot_vcap_filter *filter;
struct ocelot_vcap_block *block; struct ocelot_vcap_block *block;
struct flow_stats stats = {0};
int block_id, ret; int block_id, ret;
block_id = ocelot_chain_to_block(f->common.chain_index, ingress); block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
if (block_id < 0) if (block_id < 0)
return 0; return 0;
if (block_id == PSFP_BLOCK_ID) {
if (ocelot->ops->psfp_stats_get) {
ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
if (ret)
return ret;
goto stats_update;
}
return -EOPNOTSUPP;
}
block = &ocelot->block[block_id]; block = &ocelot->block[block_id];
filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true); filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
...@@ -841,7 +912,10 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port, ...@@ -841,7 +912,10 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
if (ret) if (ret)
return ret; return ret;
flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0, stats.pkts = filter->stats.pkts;
stats_update:
flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
FLOW_ACTION_HW_STATS_IMMEDIATE); FLOW_ACTION_HW_STATS_IMMEDIATE);
return 0; return 0;
} }
......
...@@ -887,10 +887,18 @@ static void vcap_entry_set(struct ocelot *ocelot, int ix, ...@@ -887,10 +887,18 @@ static void vcap_entry_set(struct ocelot *ocelot, int ix,
return es0_entry_set(ocelot, ix, filter); return es0_entry_set(ocelot, ix, filter);
} }
static int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix, struct vcap_policer_entry {
struct list_head list;
refcount_t refcount;
u32 pol_ix;
};
int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix,
struct ocelot_policer *pol) struct ocelot_policer *pol)
{ {
struct qos_policer_conf pp = { 0 }; struct qos_policer_conf pp = { 0 };
struct vcap_policer_entry *tmp;
int ret;
if (!pol) if (!pol)
return -EINVAL; return -EINVAL;
...@@ -899,57 +907,74 @@ static int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix, ...@@ -899,57 +907,74 @@ static int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix,
pp.pir = pol->rate; pp.pir = pol->rate;
pp.pbs = pol->burst; pp.pbs = pol->burst;
return qos_policer_conf_set(ocelot, 0, pol_ix, &pp); list_for_each_entry(tmp, &ocelot->vcap_pol.pol_list, list)
if (tmp->pol_ix == pol_ix) {
refcount_inc(&tmp->refcount);
return 0;
}
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
ret = qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
if (ret) {
kfree(tmp);
return ret;
}
tmp->pol_ix = pol_ix;
refcount_set(&tmp->refcount, 1);
list_add_tail(&tmp->list, &ocelot->vcap_pol.pol_list);
return 0;
} }
EXPORT_SYMBOL(ocelot_vcap_policer_add);
static void ocelot_vcap_policer_del(struct ocelot *ocelot, int ocelot_vcap_policer_del(struct ocelot *ocelot, u32 pol_ix)
struct ocelot_vcap_block *block,
u32 pol_ix)
{ {
struct ocelot_vcap_filter *filter;
struct qos_policer_conf pp = {0}; struct qos_policer_conf pp = {0};
int index = -1; struct vcap_policer_entry *tmp, *n;
u8 z = 0;
if (pol_ix < block->pol_lpr)
return; list_for_each_entry_safe(tmp, n, &ocelot->vcap_pol.pol_list, list)
if (tmp->pol_ix == pol_ix) {
list_for_each_entry(filter, &block->rules, list) { z = refcount_dec_and_test(&tmp->refcount);
index++; if (z) {
if (filter->block_id == VCAP_IS2 && list_del(&tmp->list);
filter->action.police_ena && kfree(tmp);
filter->action.pol_ix < pol_ix) {
filter->action.pol_ix += 1;
ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
&filter->action.pol);
is2_entry_set(ocelot, index, filter);
} }
} }
if (z) {
pp.mode = MSCC_QOS_RATE_MODE_DISABLED; pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
qos_policer_conf_set(ocelot, 0, pol_ix, &pp); return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
}
block->pol_lpr++; return 0;
} }
EXPORT_SYMBOL(ocelot_vcap_policer_del);
static void ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
struct ocelot_vcap_block *block, struct ocelot_vcap_block *block,
struct ocelot_vcap_filter *filter) struct ocelot_vcap_filter *filter)
{ {
struct ocelot_vcap_filter *tmp; struct ocelot_vcap_filter *tmp;
struct list_head *pos, *n; struct list_head *pos, *n;
int ret;
if (filter->block_id == VCAP_IS2 && filter->action.police_ena) { if (filter->block_id == VCAP_IS2 && filter->action.police_ena) {
block->pol_lpr--; ret = ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
filter->action.pol_ix = block->pol_lpr;
ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
&filter->action.pol); &filter->action.pol);
if (ret)
return ret;
} }
block->count++; block->count++;
if (list_empty(&block->rules)) { if (list_empty(&block->rules)) {
list_add(&filter->list, &block->rules); list_add(&filter->list, &block->rules);
return; return 0;
} }
list_for_each_safe(pos, n, &block->rules) { list_for_each_safe(pos, n, &block->rules) {
...@@ -958,6 +983,8 @@ static void ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, ...@@ -958,6 +983,8 @@ static void ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
break; break;
} }
list_add(&filter->list, pos->prev); list_add(&filter->list, pos->prev);
return 0;
} }
static bool ocelot_vcap_filter_equal(const struct ocelot_vcap_filter *a, static bool ocelot_vcap_filter_equal(const struct ocelot_vcap_filter *a,
...@@ -1132,7 +1159,7 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot, ...@@ -1132,7 +1159,7 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct ocelot_vcap_block *block = &ocelot->block[filter->block_id]; struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
int i, index; int i, index, ret;
if (!ocelot_exclusive_mac_etype_filter_rules(ocelot, filter)) { if (!ocelot_exclusive_mac_etype_filter_rules(ocelot, filter)) {
NL_SET_ERR_MSG_MOD(extack, NL_SET_ERR_MSG_MOD(extack,
...@@ -1141,7 +1168,9 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot, ...@@ -1141,7 +1168,9 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
} }
/* Add filter to the linked list */ /* Add filter to the linked list */
ocelot_vcap_filter_add_to_block(ocelot, block, filter); ret = ocelot_vcap_filter_add_to_block(ocelot, block, filter);
if (ret)
return ret;
/* Get the index of the inserted filter */ /* Get the index of the inserted filter */
index = ocelot_vcap_block_get_filter_index(block, filter); index = ocelot_vcap_block_get_filter_index(block, filter);
...@@ -1174,7 +1203,7 @@ static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot, ...@@ -1174,7 +1203,7 @@ static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot,
if (ocelot_vcap_filter_equal(filter, tmp)) { if (ocelot_vcap_filter_equal(filter, tmp)) {
if (tmp->block_id == VCAP_IS2 && if (tmp->block_id == VCAP_IS2 &&
tmp->action.police_ena) tmp->action.police_ena)
ocelot_vcap_policer_del(ocelot, block, ocelot_vcap_policer_del(ocelot,
tmp->action.pol_ix); tmp->action.pol_ix);
list_del(pos); list_del(pos);
...@@ -1350,13 +1379,13 @@ int ocelot_vcap_init(struct ocelot *ocelot) ...@@ -1350,13 +1379,13 @@ int ocelot_vcap_init(struct ocelot *ocelot)
struct vcap_props *vcap = &ocelot->vcap[i]; struct vcap_props *vcap = &ocelot->vcap[i];
INIT_LIST_HEAD(&block->rules); INIT_LIST_HEAD(&block->rules);
block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
ocelot_vcap_detect_constants(ocelot, vcap); ocelot_vcap_detect_constants(ocelot, vcap);
ocelot_vcap_init_one(ocelot, vcap); ocelot_vcap_init_one(ocelot, vcap);
} }
INIT_LIST_HEAD(&ocelot->dummy_rules); INIT_LIST_HEAD(&ocelot->dummy_rules);
INIT_LIST_HEAD(&ocelot->vcap_pol.pol_list);
return 0; return 0;
} }
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <soc/mscc/ocelot_hsio.h> #include <soc/mscc/ocelot_hsio.h>
#include "ocelot.h" #include "ocelot.h"
#define VSC7514_VCAP_POLICER_BASE 128
#define VSC7514_VCAP_POLICER_MAX 191
static const u32 ocelot_ana_regmap[] = { static const u32 ocelot_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x009000), REG(ANA_ADVLEARN, 0x009000),
REG(ANA_VLANMASK, 0x009004), REG(ANA_VLANMASK, 0x009004),
...@@ -1129,6 +1132,10 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -1129,6 +1132,10 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->num_flooding_pgids = 1; ocelot->num_flooding_pgids = 1;
ocelot->vcap = vsc7514_vcap_props; ocelot->vcap = vsc7514_vcap_props;
ocelot->vcap_pol.base = VSC7514_VCAP_POLICER_BASE;
ocelot->vcap_pol.max = VSC7514_VCAP_POLICER_MAX;
ocelot->npi = -1; ocelot->npi = -1;
err = ocelot_init(ocelot); err = ocelot_init(ocelot);
......
...@@ -555,12 +555,25 @@ struct ocelot_ops { ...@@ -555,12 +555,25 @@ struct ocelot_ops {
u16 (*wm_enc)(u16 value); u16 (*wm_enc)(u16 value);
u16 (*wm_dec)(u16 value); u16 (*wm_dec)(u16 value);
void (*wm_stat)(u32 val, u32 *inuse, u32 *maxuse); void (*wm_stat)(u32 val, u32 *inuse, u32 *maxuse);
void (*psfp_init)(struct ocelot *ocelot);
int (*psfp_filter_add)(struct ocelot *ocelot, int port,
struct flow_cls_offload *f);
int (*psfp_filter_del)(struct ocelot *ocelot, struct flow_cls_offload *f);
int (*psfp_stats_get)(struct ocelot *ocelot, struct flow_cls_offload *f,
struct flow_stats *stats);
};
struct ocelot_vcap_policer {
struct list_head pol_list;
u16 base;
u16 max;
u16 base2;
u16 max2;
}; };
struct ocelot_vcap_block { struct ocelot_vcap_block {
struct list_head rules; struct list_head rules;
int count; int count;
int pol_lpr;
}; };
struct ocelot_bridge_vlan { struct ocelot_bridge_vlan {
...@@ -581,6 +594,12 @@ enum ocelot_port_tag_config { ...@@ -581,6 +594,12 @@ enum ocelot_port_tag_config {
OCELOT_PORT_TAG_TRUNK = 3, OCELOT_PORT_TAG_TRUNK = 3,
}; };
struct ocelot_psfp_list {
struct list_head stream_list;
struct list_head sfi_list;
struct list_head sgi_list;
};
enum ocelot_sb { enum ocelot_sb {
OCELOT_SB_BUF, OCELOT_SB_BUF,
OCELOT_SB_REF, OCELOT_SB_REF,
...@@ -593,6 +612,19 @@ enum ocelot_sb_pool { ...@@ -593,6 +612,19 @@ enum ocelot_sb_pool {
OCELOT_SB_POOL_NUM, OCELOT_SB_POOL_NUM,
}; };
/* MAC table entry types.
* ENTRYTYPE_NORMAL is subject to aging.
* ENTRYTYPE_LOCKED is not subject to aging.
* ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
* ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
*/
enum macaccess_entry_type {
ENTRYTYPE_NORMAL = 0,
ENTRYTYPE_LOCKED,
ENTRYTYPE_MACv4,
ENTRYTYPE_MACv6,
};
#define OCELOT_QUIRK_PCS_PERFORMS_RATE_ADAPTATION BIT(0) #define OCELOT_QUIRK_PCS_PERFORMS_RATE_ADAPTATION BIT(0)
#define OCELOT_QUIRK_QSGMII_PORTS_MUST_BE_UP BIT(1) #define OCELOT_QUIRK_QSGMII_PORTS_MUST_BE_UP BIT(1)
...@@ -667,8 +699,11 @@ struct ocelot { ...@@ -667,8 +699,11 @@ struct ocelot {
struct list_head dummy_rules; struct list_head dummy_rules;
struct ocelot_vcap_block block[3]; struct ocelot_vcap_block block[3];
struct ocelot_vcap_policer vcap_pol;
struct vcap_props *vcap; struct vcap_props *vcap;
struct ocelot_psfp_list psfp;
/* Workqueue to check statistics for overflow with its lock */ /* Workqueue to check statistics for overflow with its lock */
struct mutex stats_lock; struct mutex stats_lock;
u64 *stats; u64 *stats;
...@@ -870,6 +905,19 @@ void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port, ...@@ -870,6 +905,19 @@ void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port,
bool tx_pause, bool rx_pause, bool tx_pause, bool rx_pause,
unsigned long quirks); unsigned long quirks);
int ocelot_mact_lookup(struct ocelot *ocelot, int *dst_idx,
const unsigned char mac[ETH_ALEN],
unsigned int vid, enum macaccess_entry_type *type);
int ocelot_mact_learn_streamdata(struct ocelot *ocelot, int dst_idx,
const unsigned char mac[ETH_ALEN],
unsigned int vid,
enum macaccess_entry_type type,
int sfid, int ssid);
int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix,
struct ocelot_policer *pol);
int ocelot_vcap_policer_del(struct ocelot *ocelot, u32 pol_ix);
#if IS_ENABLED(CONFIG_BRIDGE_MRP) #if IS_ENABLED(CONFIG_BRIDGE_MRP)
int ocelot_mrp_add(struct ocelot *ocelot, int port, int ocelot_mrp_add(struct ocelot *ocelot, int port,
const struct switchdev_obj_mrp *mrp); const struct switchdev_obj_mrp *mrp);
......
...@@ -227,6 +227,11 @@ ...@@ -227,6 +227,11 @@
#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x) ((x) & GENMASK(1, 0)) #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x) ((x) & GENMASK(1, 0))
#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M GENMASK(1, 0) #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M GENMASK(1, 0)
#define SFIDACCESS_CMD_IDLE 0
#define SFIDACCESS_CMD_READ 1
#define SFIDACCESS_CMD_WRITE 2
#define SFIDACCESS_CMD_INIT 3
#define ANA_TABLES_SFIDTIDX_SGID_VALID BIT(26) #define ANA_TABLES_SFIDTIDX_SGID_VALID BIT(26)
#define ANA_TABLES_SFIDTIDX_SGID(x) (((x) << 18) & GENMASK(25, 18)) #define ANA_TABLES_SFIDTIDX_SGID(x) (((x) << 18) & GENMASK(25, 18))
#define ANA_TABLES_SFIDTIDX_SGID_M GENMASK(25, 18) #define ANA_TABLES_SFIDTIDX_SGID_M GENMASK(25, 18)
...@@ -255,6 +260,11 @@ ...@@ -255,6 +260,11 @@
#define ANA_SG_CONFIG_REG_3_INIT_IPS(x) (((x) << 21) & GENMASK(24, 21)) #define ANA_SG_CONFIG_REG_3_INIT_IPS(x) (((x) << 21) & GENMASK(24, 21))
#define ANA_SG_CONFIG_REG_3_INIT_IPS_M GENMASK(24, 21) #define ANA_SG_CONFIG_REG_3_INIT_IPS_M GENMASK(24, 21)
#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x) (((x) & GENMASK(24, 21)) >> 21) #define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x) (((x) & GENMASK(24, 21)) >> 21)
#define ANA_SG_CONFIG_REG_3_IPV_VALID BIT(24)
#define ANA_SG_CONFIG_REG_3_IPV_INVALID(x) (((x) << 24) & GENMASK(24, 24))
#define ANA_SG_CONFIG_REG_3_INIT_IPV(x) (((x) << 21) & GENMASK(23, 21))
#define ANA_SG_CONFIG_REG_3_INIT_IPV_M GENMASK(23, 21)
#define ANA_SG_CONFIG_REG_3_INIT_IPV_X(x) (((x) & GENMASK(23, 21)) >> 21)
#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE BIT(25) #define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE BIT(25)
#define ANA_SG_GCL_GS_CONFIG_RSZ 0x4 #define ANA_SG_GCL_GS_CONFIG_RSZ 0x4
......
...@@ -656,6 +656,7 @@ enum ocelot_vcap_filter_type { ...@@ -656,6 +656,7 @@ enum ocelot_vcap_filter_type {
OCELOT_VCAP_FILTER_DUMMY, OCELOT_VCAP_FILTER_DUMMY,
OCELOT_VCAP_FILTER_PAG, OCELOT_VCAP_FILTER_PAG,
OCELOT_VCAP_FILTER_OFFLOAD, OCELOT_VCAP_FILTER_OFFLOAD,
OCELOT_PSFP_FILTER_OFFLOAD,
}; };
struct ocelot_vcap_id { struct ocelot_vcap_id {
......
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