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

Merge branch 'Ocelot-Felix-driver-cleanup'

Vladimir Oltean says:

====================
Ocelot/Felix driver cleanup

Some of the code in the mscc felix and ocelot drivers was added while in
a bit of a hurry. Let's take a moment and put things in relative order.

First 3 patches are sparse warning fixes.

Patches 4-9 perform some further splitting between mscc_felix,
mscc_ocelot, and the common hardware library they share. Meaning that
some code is being moved from the library into just the mscc_ocelot
module.

Patches 10-12 refactor the naming conventions in the existing VCAP code
(for tc-flower offload), since we're going to be adding some more code
for VCAP IS1 (previous tentatives already submitted here:
https://patchwork.ozlabs.org/project/netdev/cover/20200602051828.5734-1-xiaoliang.yang_1@nxp.com/),
and that code would be confusing to read and maintain using current
naming conventions.

No functional modification is intended. I checked that the VCAP IS2 code
still works by applying a tc ingress filter with an EtherType key and
'drop' action.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 60cb8d3d c73b0ad3
...@@ -4,7 +4,9 @@ config NET_DSA_MSCC_FELIX ...@@ -4,7 +4,9 @@ config NET_DSA_MSCC_FELIX
depends on NET_DSA && PCI depends on NET_DSA && PCI
depends on NET_VENDOR_MICROSEMI depends on NET_VENDOR_MICROSEMI
depends on NET_VENDOR_FREESCALE depends on NET_VENDOR_FREESCALE
select MSCC_OCELOT_SWITCH depends on HAS_IOMEM
depends on REGMAP_MMIO
select MSCC_OCELOT_SWITCH_LIB
select NET_DSA_TAG_OCELOT select NET_DSA_TAG_OCELOT
select FSL_ENETC_MDIO select FSL_ENETC_MDIO
help help
......
...@@ -557,7 +557,7 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[] = { ...@@ -557,7 +557,7 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
{ .offset = 0x111, .name = "drop_green_prio_7", }, { .offset = 0x111, .name = "drop_green_prio_7", },
}; };
struct vcap_field vsc9959_vcap_is2_keys[] = { static struct vcap_field vsc9959_vcap_is2_keys[] = {
/* Common: 41 bits */ /* Common: 41 bits */
[VCAP_IS2_TYPE] = { 0, 4}, [VCAP_IS2_TYPE] = { 0, 4},
[VCAP_IS2_HK_FIRST] = { 4, 1}, [VCAP_IS2_HK_FIRST] = { 4, 1},
...@@ -637,7 +637,7 @@ struct vcap_field vsc9959_vcap_is2_keys[] = { ...@@ -637,7 +637,7 @@ struct vcap_field vsc9959_vcap_is2_keys[] = {
[VCAP_IS2_HK_OAM_IS_Y1731] = {182, 1}, [VCAP_IS2_HK_OAM_IS_Y1731] = {182, 1},
}; };
struct vcap_field vsc9959_vcap_is2_actions[] = { static struct vcap_field vsc9959_vcap_is2_actions[] = {
[VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1}, [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1},
[VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1}, [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1},
[VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3}, [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3},
......
...@@ -11,22 +11,24 @@ config NET_VENDOR_MICROSEMI ...@@ -11,22 +11,24 @@ config NET_VENDOR_MICROSEMI
if NET_VENDOR_MICROSEMI if NET_VENDOR_MICROSEMI
# Users should depend on NET_SWITCHDEV, HAS_IOMEM, PHYLIB and REGMAP_MMIO
config MSCC_OCELOT_SWITCH_LIB
tristate
help
This is a hardware support library for Ocelot network switches. It is
used by switchdev as well as by DSA drivers.
config MSCC_OCELOT_SWITCH config MSCC_OCELOT_SWITCH
tristate "Ocelot switch driver" tristate "Ocelot switch driver"
depends on NET_SWITCHDEV depends on NET_SWITCHDEV
depends on HAS_IOMEM
select PHYLIB
select REGMAP_MMIO
help
This driver supports the Ocelot network switch device.
config MSCC_OCELOT_SWITCH_OCELOT
tristate "Ocelot switch driver on Ocelot"
depends on MSCC_OCELOT_SWITCH
depends on GENERIC_PHY depends on GENERIC_PHY
depends on REGMAP_MMIO
depends on HAS_IOMEM
depends on PHYLIB
depends on OF_NET depends on OF_NET
select MSCC_OCELOT_SWITCH_LIB
help help
This driver supports the Ocelot network switch device as present on This driver supports the Ocelot network switch device as present on
the Ocelot SoCs. the Ocelot SoCs (VSC7514).
endif # NET_VENDOR_MICROSEMI endif # NET_VENDOR_MICROSEMI
# SPDX-License-Identifier: (GPL-2.0 OR MIT) # SPDX-License-Identifier: (GPL-2.0 OR MIT)
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o obj-$(CONFIG_MSCC_OCELOT_SWITCH_LIB) += mscc_ocelot_switch_lib.o
mscc_ocelot_common-y := ocelot.o ocelot_io.o mscc_ocelot_switch_lib-y := \
mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o ocelot_ptp.o ocelot.o \
obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o ocelot_io.o \
ocelot_police.o \
ocelot_vcap.o \
ocelot_flower.o \
ocelot_ptp.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
mscc_ocelot-y := \
ocelot_vsc7514.o \
ocelot_net.o
This diff is collapsed.
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include "ocelot_rew.h" #include "ocelot_rew.h"
#include "ocelot_qs.h" #include "ocelot_qs.h"
#include "ocelot_tc.h"
#define OCELOT_BUFFER_CELL_SZ 60 #define OCELOT_BUFFER_CELL_SZ 60
...@@ -49,6 +48,13 @@ struct ocelot_multicast { ...@@ -49,6 +48,13 @@ struct ocelot_multicast {
u16 ports; u16 ports;
}; };
struct ocelot_port_tc {
bool block_shared;
unsigned long offload_cnt;
unsigned long police_id;
};
struct ocelot_port_private { struct ocelot_port_private {
struct ocelot_port port; struct ocelot_port port;
struct net_device *dev; struct net_device *dev;
...@@ -60,13 +66,49 @@ struct ocelot_port_private { ...@@ -60,13 +66,49 @@ struct ocelot_port_private {
struct ocelot_port_tc tc; struct ocelot_port_tc tc;
}; };
struct ocelot_dump_ctx {
struct net_device *dev;
struct sk_buff *skb;
struct netlink_callback *cb;
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,
};
int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
bool is_static, void *data);
int ocelot_mact_learn(struct ocelot *ocelot, int port,
const unsigned char mac[ETH_ALEN],
unsigned int vid, enum macaccess_entry_type type);
int ocelot_mact_forget(struct ocelot *ocelot,
const unsigned char mac[ETH_ALEN], unsigned int vid);
int ocelot_port_lag_join(struct ocelot *ocelot, int port,
struct net_device *bond);
void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
struct net_device *bond);
int ocelot_port_obj_del_mdb(struct net_device *dev,
const struct switchdev_obj_port_mdb *mdb);
int ocelot_port_obj_add_mdb(struct net_device *dev,
const struct switchdev_obj_port_mdb *mdb,
struct switchdev_trans *trans);
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg); u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val)) #define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val)) #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops);
int ocelot_probe_port(struct ocelot *ocelot, u8 port, int ocelot_probe_port(struct ocelot *ocelot, u8 port,
void __iomem *regs, void __iomem *regs,
struct phy_device *phy); struct phy_device *phy);
......
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/tc_act/tc_gact.h> #include <net/tc_act/tc_gact.h>
#include "ocelot_ace.h" #include "ocelot_vcap.h"
static int ocelot_flower_parse_action(struct flow_cls_offload *f, static int ocelot_flower_parse_action(struct flow_cls_offload *f,
struct ocelot_ace_rule *ace) struct ocelot_vcap_filter *filter)
{ {
const struct flow_action_entry *a; const struct flow_action_entry *a;
s64 burst; s64 burst;
...@@ -26,17 +26,17 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f, ...@@ -26,17 +26,17 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
flow_action_for_each(i, a, &f->rule->action) { flow_action_for_each(i, a, &f->rule->action) {
switch (a->id) { switch (a->id) {
case FLOW_ACTION_DROP: case FLOW_ACTION_DROP:
ace->action = OCELOT_ACL_ACTION_DROP; filter->action = OCELOT_VCAP_ACTION_DROP;
break; break;
case FLOW_ACTION_TRAP: case FLOW_ACTION_TRAP:
ace->action = OCELOT_ACL_ACTION_TRAP; filter->action = OCELOT_VCAP_ACTION_TRAP;
break; break;
case FLOW_ACTION_POLICE: case FLOW_ACTION_POLICE:
ace->action = OCELOT_ACL_ACTION_POLICE; filter->action = OCELOT_VCAP_ACTION_POLICE;
rate = a->police.rate_bytes_ps; rate = a->police.rate_bytes_ps;
ace->pol.rate = div_u64(rate, 1000) * 8; filter->pol.rate = div_u64(rate, 1000) * 8;
burst = rate * PSCHED_NS2TICKS(a->police.burst); burst = rate * PSCHED_NS2TICKS(a->police.burst);
ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC); filter->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC);
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -47,7 +47,7 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f, ...@@ -47,7 +47,7 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
} }
static int ocelot_flower_parse(struct flow_cls_offload *f, static int ocelot_flower_parse(struct flow_cls_offload *f,
struct ocelot_ace_rule *ace) struct ocelot_vcap_filter *filter)
{ {
struct flow_rule *rule = flow_cls_offload_flow_rule(f); struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector; struct flow_dissector *dissector = rule->match.dissector;
...@@ -88,14 +88,14 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ...@@ -88,14 +88,14 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
return -EOPNOTSUPP; return -EOPNOTSUPP;
flow_rule_match_eth_addrs(rule, &match); flow_rule_match_eth_addrs(rule, &match);
ace->type = OCELOT_ACE_TYPE_ETYPE; filter->key_type = OCELOT_VCAP_KEY_ETYPE;
ether_addr_copy(ace->frame.etype.dmac.value, ether_addr_copy(filter->key.etype.dmac.value,
match.key->dst); match.key->dst);
ether_addr_copy(ace->frame.etype.smac.value, ether_addr_copy(filter->key.etype.smac.value,
match.key->src); match.key->src);
ether_addr_copy(ace->frame.etype.dmac.mask, ether_addr_copy(filter->key.etype.dmac.mask,
match.mask->dst); match.mask->dst);
ether_addr_copy(ace->frame.etype.smac.mask, ether_addr_copy(filter->key.etype.smac.mask,
match.mask->src); match.mask->src);
goto finished_key_parsing; goto finished_key_parsing;
} }
...@@ -105,18 +105,18 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ...@@ -105,18 +105,18 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
flow_rule_match_basic(rule, &match); flow_rule_match_basic(rule, &match);
if (ntohs(match.key->n_proto) == ETH_P_IP) { if (ntohs(match.key->n_proto) == ETH_P_IP) {
ace->type = OCELOT_ACE_TYPE_IPV4; filter->key_type = OCELOT_VCAP_KEY_IPV4;
ace->frame.ipv4.proto.value[0] = filter->key.ipv4.proto.value[0] =
match.key->ip_proto; match.key->ip_proto;
ace->frame.ipv4.proto.mask[0] = filter->key.ipv4.proto.mask[0] =
match.mask->ip_proto; match.mask->ip_proto;
match_protocol = false; match_protocol = false;
} }
if (ntohs(match.key->n_proto) == ETH_P_IPV6) { if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
ace->type = OCELOT_ACE_TYPE_IPV6; filter->key_type = OCELOT_VCAP_KEY_IPV6;
ace->frame.ipv6.proto.value[0] = filter->key.ipv6.proto.value[0] =
match.key->ip_proto; match.key->ip_proto;
ace->frame.ipv6.proto.mask[0] = filter->key.ipv6.proto.mask[0] =
match.mask->ip_proto; match.mask->ip_proto;
match_protocol = false; match_protocol = false;
} }
...@@ -128,16 +128,16 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ...@@ -128,16 +128,16 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
u8 *tmp; u8 *tmp;
flow_rule_match_ipv4_addrs(rule, &match); flow_rule_match_ipv4_addrs(rule, &match);
tmp = &ace->frame.ipv4.sip.value.addr[0]; tmp = &filter->key.ipv4.sip.value.addr[0];
memcpy(tmp, &match.key->src, 4); memcpy(tmp, &match.key->src, 4);
tmp = &ace->frame.ipv4.sip.mask.addr[0]; tmp = &filter->key.ipv4.sip.mask.addr[0];
memcpy(tmp, &match.mask->src, 4); memcpy(tmp, &match.mask->src, 4);
tmp = &ace->frame.ipv4.dip.value.addr[0]; tmp = &filter->key.ipv4.dip.value.addr[0];
memcpy(tmp, &match.key->dst, 4); memcpy(tmp, &match.key->dst, 4);
tmp = &ace->frame.ipv4.dip.mask.addr[0]; tmp = &filter->key.ipv4.dip.mask.addr[0];
memcpy(tmp, &match.mask->dst, 4); memcpy(tmp, &match.mask->dst, 4);
match_protocol = false; match_protocol = false;
} }
...@@ -151,10 +151,10 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ...@@ -151,10 +151,10 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
struct flow_match_ports match; struct flow_match_ports match;
flow_rule_match_ports(rule, &match); flow_rule_match_ports(rule, &match);
ace->frame.ipv4.sport.value = ntohs(match.key->src); filter->key.ipv4.sport.value = ntohs(match.key->src);
ace->frame.ipv4.sport.mask = ntohs(match.mask->src); filter->key.ipv4.sport.mask = ntohs(match.mask->src);
ace->frame.ipv4.dport.value = ntohs(match.key->dst); filter->key.ipv4.dport.value = ntohs(match.key->dst);
ace->frame.ipv4.dport.mask = ntohs(match.mask->dst); filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
match_protocol = false; match_protocol = false;
} }
...@@ -162,11 +162,11 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ...@@ -162,11 +162,11 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
struct flow_match_vlan match; struct flow_match_vlan match;
flow_rule_match_vlan(rule, &match); flow_rule_match_vlan(rule, &match);
ace->type = OCELOT_ACE_TYPE_ANY; filter->key_type = OCELOT_VCAP_KEY_ANY;
ace->vlan.vid.value = match.key->vlan_id; filter->vlan.vid.value = match.key->vlan_id;
ace->vlan.vid.mask = match.mask->vlan_id; filter->vlan.vid.mask = match.mask->vlan_id;
ace->vlan.pcp.value[0] = match.key->vlan_priority; filter->vlan.pcp.value[0] = match.key->vlan_priority;
ace->vlan.pcp.mask[0] = match.mask->vlan_priority; filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
match_protocol = false; match_protocol = false;
} }
...@@ -175,99 +175,77 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ...@@ -175,99 +175,77 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
/* TODO: support SNAP, LLC etc */ /* TODO: support SNAP, LLC etc */
if (proto < ETH_P_802_3_MIN) if (proto < ETH_P_802_3_MIN)
return -EOPNOTSUPP; return -EOPNOTSUPP;
ace->type = OCELOT_ACE_TYPE_ETYPE; filter->key_type = OCELOT_VCAP_KEY_ETYPE;
*(u16 *)ace->frame.etype.etype.value = htons(proto); *(__be16 *)filter->key.etype.etype.value = htons(proto);
*(u16 *)ace->frame.etype.etype.mask = 0xffff; *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
} }
/* else, a rule of type OCELOT_ACE_TYPE_ANY is implicitly added */ /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
ace->prio = f->common.prio; filter->prio = f->common.prio;
ace->id = f->cookie; filter->id = f->cookie;
return ocelot_flower_parse_action(f, ace); return ocelot_flower_parse_action(f, filter);
} }
static static struct ocelot_vcap_filter
struct ocelot_ace_rule *ocelot_ace_rule_create(struct ocelot *ocelot, int port, *ocelot_vcap_filter_create(struct ocelot *ocelot, int port,
struct flow_cls_offload *f) struct flow_cls_offload *f)
{ {
struct ocelot_ace_rule *ace; struct ocelot_vcap_filter *filter;
ace = kzalloc(sizeof(*ace), GFP_KERNEL); filter = kzalloc(sizeof(*filter), GFP_KERNEL);
if (!ace) if (!filter)
return NULL; return NULL;
ace->ingress_port_mask = BIT(port); filter->ingress_port_mask = BIT(port);
return ace; return filter;
} }
int ocelot_cls_flower_replace(struct ocelot *ocelot, int port, int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress) struct flow_cls_offload *f, bool ingress)
{ {
struct ocelot_ace_rule *ace; struct ocelot_vcap_filter *filter;
int ret; int ret;
ace = ocelot_ace_rule_create(ocelot, port, f); filter = ocelot_vcap_filter_create(ocelot, port, f);
if (!ace) if (!filter)
return -ENOMEM; return -ENOMEM;
ret = ocelot_flower_parse(f, ace); ret = ocelot_flower_parse(f, filter);
if (ret) { if (ret) {
kfree(ace); kfree(filter);
return ret; return ret;
} }
return ocelot_ace_rule_offload_add(ocelot, ace, 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);
int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port, int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress) struct flow_cls_offload *f, bool ingress)
{ {
struct ocelot_ace_rule ace; struct ocelot_vcap_filter filter;
ace.prio = f->common.prio; filter.prio = f->common.prio;
ace.id = f->cookie; filter.id = f->cookie;
return ocelot_ace_rule_offload_del(ocelot, &ace); return ocelot_vcap_filter_del(ocelot, &filter);
} }
EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy); EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
int ocelot_cls_flower_stats(struct ocelot *ocelot, int port, int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress) struct flow_cls_offload *f, bool ingress)
{ {
struct ocelot_ace_rule ace; struct ocelot_vcap_filter filter;
int ret; int ret;
ace.prio = f->common.prio; filter.prio = f->common.prio;
ace.id = f->cookie; filter.id = f->cookie;
ret = ocelot_ace_rule_stats_update(ocelot, &ace); ret = ocelot_vcap_filter_stats_update(ocelot, &filter);
if (ret) if (ret)
return ret; return ret;
flow_stats_update(&f->stats, 0x0, ace.stats.pkts, 0, 0x0, flow_stats_update(&f->stats, 0x0, filter.stats.pkts, 0, 0x0,
FLOW_ACTION_HW_STATS_IMMEDIATE); FLOW_ACTION_HW_STATS_IMMEDIATE);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats); EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
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_cls_flower_replace(ocelot, port, f, ingress);
case FLOW_CLS_DESTROY:
return ocelot_cls_flower_destroy(ocelot, port, f, ingress);
case FLOW_CLS_STATS:
return ocelot_cls_flower_stats(ocelot, port, f, ingress);
default:
return -EOPNOTSUPP;
}
}
This diff is collapsed.
...@@ -7,16 +7,6 @@ ...@@ -7,16 +7,6 @@
#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot.h>
#include "ocelot_police.h" #include "ocelot_police.h"
enum mscc_qos_rate_mode {
MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
__MSCC_QOS_RATE_MODE_END,
NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
};
/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */ /* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */ #define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */ #define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
...@@ -30,19 +20,8 @@ enum mscc_qos_rate_mode { ...@@ -30,19 +20,8 @@ enum mscc_qos_rate_mode {
/* Default policer order */ /* Default policer order */
#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */ #define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
struct qos_policer_conf { int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
enum mscc_qos_rate_mode mode; struct qos_policer_conf *conf)
bool dlb; /* Enable DLB (dual leaky bucket mode */
bool cf; /* Coupling flag (ignored in SLB mode) */
u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
u32 pir; /* PIR in kbps/fps */
u32 pbs; /* PBS in bytes/frames */
u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
};
static int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
struct qos_policer_conf *conf)
{ {
u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE; u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
u32 cir = 0, cbs = 0, pir = 0, pbs = 0; u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
...@@ -228,27 +207,3 @@ int ocelot_port_policer_del(struct ocelot *ocelot, int port) ...@@ -228,27 +207,3 @@ int ocelot_port_policer_del(struct ocelot *ocelot, int port)
return 0; return 0;
} }
EXPORT_SYMBOL(ocelot_port_policer_del); EXPORT_SYMBOL(ocelot_port_policer_del);
int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix,
struct ocelot_policer *pol)
{
struct qos_policer_conf pp = { 0 };
if (!pol)
return -EINVAL;
pp.mode = MSCC_QOS_RATE_MODE_DATA;
pp.pir = pol->rate;
pp.pbs = pol->burst;
return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
}
int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix)
{
struct qos_policer_conf pp = { 0 };
pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
}
...@@ -9,9 +9,28 @@ ...@@ -9,9 +9,28 @@
#include "ocelot.h" #include "ocelot.h"
int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix, enum mscc_qos_rate_mode {
struct ocelot_policer *pol); MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
__MSCC_QOS_RATE_MODE_END,
NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
};
int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix); struct qos_policer_conf {
enum mscc_qos_rate_mode mode;
bool dlb; /* Enable DLB (dual leaky bucket mode */
bool cf; /* Coupling flag (ignored in SLB mode) */
u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
u32 pir; /* PIR in kbps/fps */
u32 pbs; /* PBS in bytes/frames */
u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
};
int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
struct qos_policer_conf *conf);
#endif /* _MSCC_OCELOT_POLICE_H_ */ #endif /* _MSCC_OCELOT_POLICE_H_ */
This diff is collapsed.
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Microsemi Ocelot Switch TC driver
*
* Copyright (c) 2019 Microsemi Corporation
*/
#include <soc/mscc/ocelot.h>
#include "ocelot_tc.h"
#include "ocelot_ace.h"
#include <net/pkt_cls.h>
static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
struct tc_cls_matchall_offload *f,
bool ingress)
{
struct netlink_ext_ack *extack = f->common.extack;
struct ocelot *ocelot = priv->port.ocelot;
struct ocelot_policer pol = { 0 };
struct flow_action_entry *action;
int port = priv->chip_port;
int err;
if (!ingress) {
NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported");
return -EOPNOTSUPP;
}
switch (f->command) {
case TC_CLSMATCHALL_REPLACE:
if (!flow_offload_has_one_action(&f->rule->action)) {
NL_SET_ERR_MSG_MOD(extack,
"Only one action is supported");
return -EOPNOTSUPP;
}
if (priv->tc.block_shared) {
NL_SET_ERR_MSG_MOD(extack,
"Rate limit is not supported on shared blocks");
return -EOPNOTSUPP;
}
action = &f->rule->action.entries[0];
if (action->id != FLOW_ACTION_POLICE) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
return -EOPNOTSUPP;
}
if (priv->tc.police_id && priv->tc.police_id != f->cookie) {
NL_SET_ERR_MSG_MOD(extack,
"Only one policer per port is supported");
return -EEXIST;
}
pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
pol.burst = (u32)div_u64(action->police.rate_bytes_ps *
PSCHED_NS2TICKS(action->police.burst),
PSCHED_TICKS_PER_SEC);
err = ocelot_port_policer_add(ocelot, port, &pol);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Could not add policer");
return err;
}
priv->tc.police_id = f->cookie;
priv->tc.offload_cnt++;
return 0;
case TC_CLSMATCHALL_DESTROY:
if (priv->tc.police_id != f->cookie)
return -ENOENT;
err = ocelot_port_policer_del(ocelot, port);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Could not delete policer");
return err;
}
priv->tc.police_id = 0;
priv->tc.offload_cnt--;
return 0;
case TC_CLSMATCHALL_STATS: /* fall through */
default:
return -EOPNOTSUPP;
}
}
static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
void *type_data,
void *cb_priv, bool ingress)
{
struct ocelot_port_private *priv = cb_priv;
if (!tc_cls_can_offload_and_chain0(priv->dev, type_data))
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_CLSMATCHALL:
return ocelot_setup_tc_cls_matchall(priv, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return ocelot_setup_tc_cls_flower(priv, type_data, ingress);
default:
return -EOPNOTSUPP;
}
}
static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type,
void *type_data,
void *cb_priv)
{
return ocelot_setup_tc_block_cb(type, type_data,
cb_priv, true);
}
static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
void *type_data,
void *cb_priv)
{
return ocelot_setup_tc_block_cb(type, type_data,
cb_priv, false);
}
static LIST_HEAD(ocelot_block_cb_list);
static int ocelot_setup_tc_block(struct ocelot_port_private *priv,
struct flow_block_offload *f)
{
struct flow_block_cb *block_cb;
flow_setup_cb_t *cb;
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = ocelot_setup_tc_block_cb_ig;
priv->tc.block_shared = f->block_shared;
} else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = ocelot_setup_tc_block_cb_eg;
} else {
return -EOPNOTSUPP;
}
f->driver_block_list = &ocelot_block_cb_list;
switch (f->command) {
case FLOW_BLOCK_BIND:
if (flow_block_cb_is_busy(cb, priv, &ocelot_block_cb_list))
return -EBUSY;
block_cb = flow_block_cb_alloc(cb, priv, priv, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, f->driver_block_list);
return 0;
case FLOW_BLOCK_UNBIND:
block_cb = flow_block_cb_lookup(f->block, cb, priv);
if (!block_cb)
return -ENOENT;
flow_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
return 0;
default:
return -EOPNOTSUPP;
}
}
int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
struct ocelot_port_private *priv = netdev_priv(dev);
switch (type) {
case TC_SETUP_BLOCK:
return ocelot_setup_tc_block(priv, type_data);
default:
return -EOPNOTSUPP;
}
return 0;
}
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/* Microsemi Ocelot Switch driver
*
* Copyright (c) 2019 Microsemi Corporation
*/
#ifndef _MSCC_OCELOT_TC_H_
#define _MSCC_OCELOT_TC_H_
#include <linux/netdevice.h>
struct ocelot_port_tc {
bool block_shared;
unsigned long offload_cnt;
unsigned long police_id;
};
int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data);
#endif /* _MSCC_OCELOT_TC_H_ */
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* Copyright (c) 2019 Microsemi Corporation * Copyright (c) 2019 Microsemi Corporation
*/ */
#ifndef _MSCC_OCELOT_ACE_H_ #ifndef _MSCC_OCELOT_VCAP_H_
#define _MSCC_OCELOT_ACE_H_ #define _MSCC_OCELOT_VCAP_H_
#include "ocelot.h" #include "ocelot.h"
#include "ocelot_police.h" #include "ocelot_police.h"
...@@ -76,31 +76,31 @@ struct ocelot_vcap_udp_tcp { ...@@ -76,31 +76,31 @@ struct ocelot_vcap_udp_tcp {
u16 mask; u16 mask;
}; };
enum ocelot_ace_type { enum ocelot_vcap_key_type {
OCELOT_ACE_TYPE_ANY, OCELOT_VCAP_KEY_ANY,
OCELOT_ACE_TYPE_ETYPE, OCELOT_VCAP_KEY_ETYPE,
OCELOT_ACE_TYPE_LLC, OCELOT_VCAP_KEY_LLC,
OCELOT_ACE_TYPE_SNAP, OCELOT_VCAP_KEY_SNAP,
OCELOT_ACE_TYPE_ARP, OCELOT_VCAP_KEY_ARP,
OCELOT_ACE_TYPE_IPV4, OCELOT_VCAP_KEY_IPV4,
OCELOT_ACE_TYPE_IPV6 OCELOT_VCAP_KEY_IPV6
}; };
struct ocelot_ace_vlan { struct ocelot_vcap_key_vlan {
struct ocelot_vcap_vid vid; /* VLAN ID (12 bit) */ struct ocelot_vcap_vid vid; /* VLAN ID (12 bit) */
struct ocelot_vcap_u8 pcp; /* PCP (3 bit) */ struct ocelot_vcap_u8 pcp; /* PCP (3 bit) */
enum ocelot_vcap_bit dei; /* DEI */ enum ocelot_vcap_bit dei; /* DEI */
enum ocelot_vcap_bit tagged; /* Tagged/untagged frame */ enum ocelot_vcap_bit tagged; /* Tagged/untagged frame */
}; };
struct ocelot_ace_frame_etype { struct ocelot_vcap_key_etype {
struct ocelot_vcap_u48 dmac; struct ocelot_vcap_u48 dmac;
struct ocelot_vcap_u48 smac; struct ocelot_vcap_u48 smac;
struct ocelot_vcap_u16 etype; struct ocelot_vcap_u16 etype;
struct ocelot_vcap_u16 data; /* MAC data */ struct ocelot_vcap_u16 data; /* MAC data */
}; };
struct ocelot_ace_frame_llc { struct ocelot_vcap_key_llc {
struct ocelot_vcap_u48 dmac; struct ocelot_vcap_u48 dmac;
struct ocelot_vcap_u48 smac; struct ocelot_vcap_u48 smac;
...@@ -108,7 +108,7 @@ struct ocelot_ace_frame_llc { ...@@ -108,7 +108,7 @@ struct ocelot_ace_frame_llc {
struct ocelot_vcap_u32 llc; struct ocelot_vcap_u32 llc;
}; };
struct ocelot_ace_frame_snap { struct ocelot_vcap_key_snap {
struct ocelot_vcap_u48 dmac; struct ocelot_vcap_u48 dmac;
struct ocelot_vcap_u48 smac; struct ocelot_vcap_u48 smac;
...@@ -116,7 +116,7 @@ struct ocelot_ace_frame_snap { ...@@ -116,7 +116,7 @@ struct ocelot_ace_frame_snap {
struct ocelot_vcap_u40 snap; struct ocelot_vcap_u40 snap;
}; };
struct ocelot_ace_frame_arp { struct ocelot_vcap_key_arp {
struct ocelot_vcap_u48 smac; struct ocelot_vcap_u48 smac;
enum ocelot_vcap_bit arp; /* Opcode ARP/RARP */ enum ocelot_vcap_bit arp; /* Opcode ARP/RARP */
enum ocelot_vcap_bit req; /* Opcode request/reply */ enum ocelot_vcap_bit req; /* Opcode request/reply */
...@@ -133,7 +133,7 @@ struct ocelot_ace_frame_arp { ...@@ -133,7 +133,7 @@ struct ocelot_ace_frame_arp {
struct ocelot_vcap_ipv4 dip; /* Target IP address */ struct ocelot_vcap_ipv4 dip; /* Target IP address */
}; };
struct ocelot_ace_frame_ipv4 { struct ocelot_vcap_key_ipv4 {
enum ocelot_vcap_bit ttl; /* TTL zero */ enum ocelot_vcap_bit ttl; /* TTL zero */
enum ocelot_vcap_bit fragment; /* Fragment */ enum ocelot_vcap_bit fragment; /* Fragment */
enum ocelot_vcap_bit options; /* Header options */ enum ocelot_vcap_bit options; /* Header options */
...@@ -155,7 +155,7 @@ struct ocelot_ace_frame_ipv4 { ...@@ -155,7 +155,7 @@ struct ocelot_ace_frame_ipv4 {
enum ocelot_vcap_bit seq_zero; /* TCP sequence number is zero */ enum ocelot_vcap_bit seq_zero; /* TCP sequence number is zero */
}; };
struct ocelot_ace_frame_ipv6 { struct ocelot_vcap_key_ipv6 {
struct ocelot_vcap_u8 proto; /* IPv6 protocol */ struct ocelot_vcap_u8 proto; /* IPv6 protocol */
struct ocelot_vcap_u128 sip; /* IPv6 source (byte 0-7 ignored) */ struct ocelot_vcap_u128 sip; /* IPv6 source (byte 0-7 ignored) */
enum ocelot_vcap_bit ttl; /* TTL zero */ enum ocelot_vcap_bit ttl; /* TTL zero */
...@@ -174,58 +174,58 @@ struct ocelot_ace_frame_ipv6 { ...@@ -174,58 +174,58 @@ struct ocelot_ace_frame_ipv6 {
enum ocelot_vcap_bit seq_zero; /* TCP sequence number is zero */ enum ocelot_vcap_bit seq_zero; /* TCP sequence number is zero */
}; };
enum ocelot_ace_action { enum ocelot_vcap_action {
OCELOT_ACL_ACTION_DROP, OCELOT_VCAP_ACTION_DROP,
OCELOT_ACL_ACTION_TRAP, OCELOT_VCAP_ACTION_TRAP,
OCELOT_ACL_ACTION_POLICE, OCELOT_VCAP_ACTION_POLICE,
}; };
struct ocelot_ace_stats { struct ocelot_vcap_stats {
u64 bytes; u64 bytes;
u64 pkts; u64 pkts;
u64 used; u64 used;
}; };
struct ocelot_ace_rule { struct ocelot_vcap_filter {
struct list_head list; struct list_head list;
u16 prio; u16 prio;
u32 id; u32 id;
enum ocelot_ace_action action; enum ocelot_vcap_action action;
struct ocelot_ace_stats stats; struct ocelot_vcap_stats stats;
unsigned long ingress_port_mask; unsigned long ingress_port_mask;
enum ocelot_vcap_bit dmac_mc; enum ocelot_vcap_bit dmac_mc;
enum ocelot_vcap_bit dmac_bc; enum ocelot_vcap_bit dmac_bc;
struct ocelot_ace_vlan vlan; struct ocelot_vcap_key_vlan vlan;
enum ocelot_ace_type type; enum ocelot_vcap_key_type key_type;
union { union {
/* ocelot_ACE_TYPE_ANY: No specific fields */ /* OCELOT_VCAP_KEY_ANY: No specific fields */
struct ocelot_ace_frame_etype etype; struct ocelot_vcap_key_etype etype;
struct ocelot_ace_frame_llc llc; struct ocelot_vcap_key_llc llc;
struct ocelot_ace_frame_snap snap; struct ocelot_vcap_key_snap snap;
struct ocelot_ace_frame_arp arp; struct ocelot_vcap_key_arp arp;
struct ocelot_ace_frame_ipv4 ipv4; struct ocelot_vcap_key_ipv4 ipv4;
struct ocelot_ace_frame_ipv6 ipv6; struct ocelot_vcap_key_ipv6 ipv6;
} frame; } key;
struct ocelot_policer pol; struct ocelot_policer pol;
u32 pol_ix; u32 pol_ix;
}; };
int ocelot_ace_rule_offload_add(struct ocelot *ocelot, int ocelot_vcap_filter_add(struct ocelot *ocelot,
struct ocelot_ace_rule *rule, struct ocelot_vcap_filter *rule,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int ocelot_ace_rule_offload_del(struct ocelot *ocelot, int ocelot_vcap_filter_del(struct ocelot *ocelot,
struct ocelot_ace_rule *rule); struct ocelot_vcap_filter *rule);
int ocelot_ace_rule_stats_update(struct ocelot *ocelot, int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
struct ocelot_ace_rule *rule); struct ocelot_vcap_filter *rule);
int ocelot_ace_init(struct ocelot *ocelot); int ocelot_vcap_init(struct ocelot *ocelot);
int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv, int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
struct flow_cls_offload *f, struct flow_cls_offload *f,
bool ingress); bool ingress);
#endif /* _MSCC_OCELOT_ACE_H_ */ #endif /* _MSCC_OCELOT_VCAP_H_ */
...@@ -470,7 +470,7 @@ struct ocelot_ops { ...@@ -470,7 +470,7 @@ struct ocelot_ops {
int (*reset)(struct ocelot *ocelot); int (*reset)(struct ocelot *ocelot);
}; };
struct ocelot_acl_block { struct ocelot_vcap_block {
struct list_head rules; struct list_head rules;
int count; int count;
int pol_lpr; int pol_lpr;
...@@ -535,7 +535,7 @@ struct ocelot { ...@@ -535,7 +535,7 @@ struct ocelot {
struct list_head multicast; struct list_head multicast;
struct ocelot_acl_block acl_block; struct ocelot_vcap_block block;
const struct vcap_field *vcap_is2_keys; const struct vcap_field *vcap_is2_keys;
const struct vcap_field *vcap_is2_actions; const struct vcap_field *vcap_is2_actions;
......
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