From c518afec288351347dbe05ea3d49d18fb9a9fff1 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Feb 2022 16:30:05 +0200 Subject: net: mscc: ocelot: consolidate cookie allocation for private VCAP rules Every use case that needed VCAP filters (in order: DSA tag_8021q, MRP, PTP traps) has hardcoded filter identifiers that worked well enough for that use case alone. But when two or more of those use cases would be used together, some of those identifiers would overlap, leading to breakage. Add definitions for each cookie and centralize them in ocelot_vcap.h, such that the overlaps are more obvious. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- include/soc/mscc/ocelot_vcap.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'include/soc/mscc/ocelot_vcap.h') diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index 709cbc198fd2..562bcd972132 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -8,6 +8,22 @@ #include +/* Cookie definitions for private VCAP filters installed by the driver. + * Must be unique per VCAP block. + */ +#define OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port) (port) +#define OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port) (port) +#define OCELOT_VCAP_IS1_TAG_8021Q_PTP_MMIO(ocelot) ((ocelot)->num_phys_ports) +#define OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port) (port) +#define OCELOT_VCAP_IS2_TAG_8021Q_PTP_MMIO(ocelot) ((ocelot)->num_phys_ports) +#define OCELOT_VCAP_IS2_L2_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 1) +#define OCELOT_VCAP_IS2_IPV4_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 2) +#define OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 3) +#define OCELOT_VCAP_IS2_IPV6_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 4) +#define OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 5) +#define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) (port) +#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot, port) ((ocelot)->num_phys_ports + (port)) + /* ================================================================= * VCAP Common * ================================================================= -- cgit v1.2.3 From b9bace6e534d431871a9d69cbd06d3a798f5086d Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Feb 2022 16:30:07 +0200 Subject: net: mscc: ocelot: use a single VCAP filter for all MRP traps The MRP assist code installs a VCAP IS2 trapping rule for each port, but since the key and the action is the same, just the ingress port mask differs, there isn't any need to do this. We can save some space in the TCAM by using a single filter and adjusting the ingress port mask. Reuse the ocelot_trap_add() and ocelot_trap_del() functions for this purpose. Now that the cookies are no longer per port, we need to change the allocation scheme such that MRP traps use a fixed number. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 8 +++--- drivers/net/ethernet/mscc/ocelot.h | 5 ++++ drivers/net/ethernet/mscc/ocelot_mrp.c | 46 ++++++++++++++++------------------ include/soc/mscc/ocelot_vcap.h | 2 +- 4 files changed, 30 insertions(+), 31 deletions(-) (limited to 'include/soc/mscc/ocelot_vcap.h') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 6039c9cb09c7..502e64764cbd 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1468,9 +1468,8 @@ ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap) trap->key.ipv6.dport.mask = 0xffff; } -static int ocelot_trap_add(struct ocelot *ocelot, int port, - unsigned long cookie, - void (*populate)(struct ocelot_vcap_filter *f)) +int ocelot_trap_add(struct ocelot *ocelot, int port, unsigned long cookie, + void (*populate)(struct ocelot_vcap_filter *f)) { struct ocelot_vcap_block *block_vcap_is2; struct ocelot_vcap_filter *trap; @@ -1515,8 +1514,7 @@ static int ocelot_trap_add(struct ocelot *ocelot, int port, return 0; } -static int ocelot_trap_del(struct ocelot *ocelot, int port, - unsigned long cookie) +int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie) { struct ocelot_vcap_block *block_vcap_is2; struct ocelot_vcap_filter *trap; diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index bf4eff6d7086..674043cd9088 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ocelot_rew.h" #include "ocelot_qs.h" @@ -102,6 +103,10 @@ int ocelot_port_devlink_init(struct ocelot *ocelot, int port, enum devlink_port_flavour flavour); void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port); +int ocelot_trap_add(struct ocelot *ocelot, int port, unsigned long cookie, + void (*populate)(struct ocelot_vcap_filter *f)); +int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie); + extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_blocking_nb; diff --git a/drivers/net/ethernet/mscc/ocelot_mrp.c b/drivers/net/ethernet/mscc/ocelot_mrp.c index dc28736e2eb3..68fa833f4aaa 100644 --- a/drivers/net/ethernet/mscc/ocelot_mrp.c +++ b/drivers/net/ethernet/mscc/ocelot_mrp.c @@ -77,37 +77,30 @@ static int ocelot_mrp_redirect_add_vcap(struct ocelot *ocelot, int src_port, return err; } -static int ocelot_mrp_copy_add_vcap(struct ocelot *ocelot, int port, int prio) +static void ocelot_populate_mrp_trap_key(struct ocelot_vcap_filter *filter) { const u8 mrp_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; - struct ocelot_vcap_filter *filter; - int err; - - filter = kzalloc(sizeof(*filter), GFP_KERNEL); - if (!filter) - return -ENOMEM; - filter->key_type = OCELOT_VCAP_KEY_ETYPE; - filter->prio = prio; - filter->id.cookie = OCELOT_VCAP_IS2_MRP_TRAP(ocelot, port); - filter->id.tc_offload = false; - filter->block_id = VCAP_IS2; - filter->type = OCELOT_VCAP_FILTER_OFFLOAD; - filter->ingress_port_mask = BIT(port); /* Here is possible to use control or test dmac because the mask * doesn't cover the LSB */ ether_addr_copy(filter->key.etype.dmac.value, mrp_test_dmac); ether_addr_copy(filter->key.etype.dmac.mask, mrp_mask); - filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; - filter->action.port_mask = 0x0; - filter->action.cpu_copy_ena = true; +} - err = ocelot_vcap_filter_add(ocelot, filter, NULL); - if (err) - kfree(filter); +static int ocelot_mrp_trap_add(struct ocelot *ocelot, int port) +{ + unsigned long cookie = OCELOT_VCAP_IS2_MRP_TRAP(ocelot); - return err; + return ocelot_trap_add(ocelot, port, cookie, + ocelot_populate_mrp_trap_key); +} + +static int ocelot_mrp_trap_del(struct ocelot *ocelot, int port) +{ + unsigned long cookie = OCELOT_VCAP_IS2_MRP_TRAP(ocelot); + + return ocelot_trap_del(ocelot, port, cookie); } static void ocelot_mrp_save_mac(struct ocelot *ocelot, @@ -184,7 +177,7 @@ int ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port, ocelot_mrp_save_mac(ocelot, ocelot_port); if (mrp->ring_role != BR_MRP_RING_ROLE_MRC) - return ocelot_mrp_copy_add_vcap(ocelot, port, 1); + return ocelot_mrp_trap_add(ocelot, port); dst_port = ocelot_mrp_find_partner_port(ocelot, ocelot_port); if (dst_port == -1) @@ -194,7 +187,7 @@ int ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port, if (err) return err; - err = ocelot_mrp_copy_add_vcap(ocelot, port, 2); + err = ocelot_mrp_trap_add(ocelot, port); if (err) { ocelot_mrp_del_vcap(ocelot, OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port)); @@ -209,7 +202,7 @@ int ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port, const struct switchdev_obj_ring_role_mrp *mrp) { struct ocelot_port *ocelot_port = ocelot->ports[port]; - int i; + int err, i; if (!ocelot_port) return -EOPNOTSUPP; @@ -220,8 +213,11 @@ int ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port, if (ocelot_port->mrp_ring_id != mrp->ring_id) return 0; + err = ocelot_mrp_trap_del(ocelot, port); + if (err) + return err; + ocelot_mrp_del_vcap(ocelot, OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port)); - ocelot_mrp_del_vcap(ocelot, OCELOT_VCAP_IS2_MRP_TRAP(ocelot, port)); for (i = 0; i < ocelot->num_phys_ports; ++i) { ocelot_port = ocelot->ports[i]; diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index 562bcd972132..14ada097db0b 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -21,8 +21,8 @@ #define OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 3) #define OCELOT_VCAP_IS2_IPV6_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 4) #define OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 5) +#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports + 6) #define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) (port) -#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot, port) ((ocelot)->num_phys_ports + (port)) /* ================================================================= * VCAP Common -- cgit v1.2.3 From 85ea0daabe5abc6add440f86565b7b9f6aff5535 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Feb 2022 16:30:08 +0200 Subject: net: mscc: ocelot: avoid overlap in VCAP IS2 between PTP and MRP traps OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN overlaps with OCELOT_VCAP_IS2_MRP_REDIRECT. To avoid this, make OCELOT_VCAP_IS2_MRP_REDIRECT take the cookie region from N to 2 * N - 1 (where N is ocelot->num_phys_ports). To avoid any risk that the singleton (not per port) VCAP IS2 filters overlap with per-port VCAP IS2 filters, we must ensure that the number of singleton filters is smaller than the number of physical ports. This is true right now, but may change in the future as switches with less ports get supported, or more singleton filters get added. So to be future-proof, let's move the singleton filters at the end of the range, where they won't overlap with anything to their right. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- include/soc/mscc/ocelot_vcap.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'include/soc/mscc/ocelot_vcap.h') diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index 14ada097db0b..ae0eec7f5dd2 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -15,14 +15,14 @@ #define OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port) (port) #define OCELOT_VCAP_IS1_TAG_8021Q_PTP_MMIO(ocelot) ((ocelot)->num_phys_ports) #define OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port) (port) -#define OCELOT_VCAP_IS2_TAG_8021Q_PTP_MMIO(ocelot) ((ocelot)->num_phys_ports) -#define OCELOT_VCAP_IS2_L2_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 1) -#define OCELOT_VCAP_IS2_IPV4_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 2) -#define OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 3) -#define OCELOT_VCAP_IS2_IPV6_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 4) -#define OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports + 5) -#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports + 6) -#define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) (port) +#define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) ((ocelot)->num_phys_ports + (port)) +#define OCELOT_VCAP_IS2_TAG_8021Q_PTP_MMIO(ocelot) ((ocelot)->num_phys_ports * 2) +#define OCELOT_VCAP_IS2_L2_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 1) +#define OCELOT_VCAP_IS2_IPV4_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 2) +#define OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 3) +#define OCELOT_VCAP_IS2_IPV6_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 4) +#define OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 5) +#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 6) /* ================================================================= * VCAP Common -- cgit v1.2.3 From e42bd4ed09aaf57949f199ae02d20a7108ccf73b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Feb 2022 16:30:10 +0200 Subject: net: mscc: ocelot: keep traps in a list When using the ocelot-8021q tagging protocol, the CPU port isn't configured as an NPI port, but is a regular port. So a "trap to CPU" operation is actually a "redirect" operation. So DSA needs to set up the trapping action one way or another, depending on the tagging protocol in use. To ease DSA's work of modifying the action, keep all currently installed traps in a list, so that DSA can live-patch them when the tagging protocol changes. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 10 ++++++++-- drivers/net/ethernet/mscc/ocelot_flower.c | 3 +++ drivers/net/ethernet/mscc/ocelot_vcap.c | 1 + include/soc/mscc/ocelot.h | 1 + include/soc/mscc/ocelot_vcap.h | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) (limited to 'include/soc/mscc/ocelot_vcap.h') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 502e64764cbd..5356d9316943 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1495,6 +1495,7 @@ int ocelot_trap_add(struct ocelot *ocelot, int port, unsigned long cookie, trap->action.cpu_copy_ena = true; trap->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; trap->action.port_mask = 0; + list_add_tail(&trap->trap_list, &ocelot->traps); new = true; } @@ -1506,8 +1507,10 @@ int ocelot_trap_add(struct ocelot *ocelot, int port, unsigned long cookie, err = ocelot_vcap_filter_replace(ocelot, trap); if (err) { trap->ingress_port_mask &= ~BIT(port); - if (!trap->ingress_port_mask) + if (!trap->ingress_port_mask) { + list_del(&trap->trap_list); kfree(trap); + } return err; } @@ -1527,8 +1530,11 @@ int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie) return 0; trap->ingress_port_mask &= ~BIT(port); - if (!trap->ingress_port_mask) + if (!trap->ingress_port_mask) { + list_del(&trap->trap_list); + return ocelot_vcap_filter_del(ocelot, trap); + } return ocelot_vcap_filter_replace(ocelot, trap); } diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index 949858891973..7106137f98ee 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -279,6 +279,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, filter->action.cpu_copy_ena = true; filter->action.cpu_qu_num = 0; filter->type = OCELOT_VCAP_FILTER_OFFLOAD; + list_add_tail(&filter->trap_list, &ocelot->traps); break; case FLOW_ACTION_POLICE: if (filter->block_id == PSFP_BLOCK_ID) { @@ -840,6 +841,8 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port, ret = ocelot_flower_parse(ocelot, port, ingress, f, filter); if (ret) { + if (!list_empty(&filter->trap_list)) + list_del(&filter->trap_list); kfree(filter); return ret; } diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c index d3544413a8a4..852054da9db9 100644 --- a/drivers/net/ethernet/mscc/ocelot_vcap.c +++ b/drivers/net/ethernet/mscc/ocelot_vcap.c @@ -1401,6 +1401,7 @@ int ocelot_vcap_init(struct ocelot *ocelot) } INIT_LIST_HEAD(&ocelot->dummy_rules); + INIT_LIST_HEAD(&ocelot->traps); INIT_LIST_HEAD(&ocelot->vcap_pol.pol_list); return 0; diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 2d7456c0e77d..78f56502bc09 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -689,6 +689,7 @@ struct ocelot { u8 base_mac[ETH_ALEN]; struct list_head vlans; + struct list_head traps; /* Switches like VSC9959 have flooding per traffic class */ int num_flooding_pgids; diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index ae0eec7f5dd2..69b3d880302d 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -682,6 +682,7 @@ struct ocelot_vcap_id { struct ocelot_vcap_filter { struct list_head list; + struct list_head trap_list; enum ocelot_vcap_filter_type type; int block_id; -- cgit v1.2.3 From 9d75b8818537fe64e6eae033765b9dc1b3107c15 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Feb 2022 16:30:11 +0200 Subject: net: mscc: ocelot: annotate which traps need PTP timestamping The ocelot switch library does not need this information, but the felix DSA driver does. As a reminder, the VSC9959 switch in LS1028A doesn't have an IRQ line for packet extraction, so to be notified that a PTP packet needs to be dequeued, it receives that packet also over Ethernet, by setting up a packet trap. The Felix driver needs to install special kinds of traps for packets in need of RX timestamps, such that the packets are replicated both over Ethernet and over the CPU port module. But the Ocelot switch library sets up more than one trap for PTP event messages; it also traps PTP general messages, MRP control messages etc. Those packets don't need PTP timestamps, so there's no reason for the Felix driver to send them to the CPU port module. By knowing which traps need PTP timestamps, the Felix driver can adjust the traps installed using ocelot_trap_add() such that only those will actually get delivered to the CPU port module. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 14 ++++++++------ drivers/net/ethernet/mscc/ocelot.h | 3 ++- drivers/net/ethernet/mscc/ocelot_mrp.c | 2 +- include/soc/mscc/ocelot_vcap.h | 1 + 4 files changed, 12 insertions(+), 8 deletions(-) (limited to 'include/soc/mscc/ocelot_vcap.h') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 5356d9316943..26f8cf235504 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1468,7 +1468,8 @@ ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap) trap->key.ipv6.dport.mask = 0xffff; } -int ocelot_trap_add(struct ocelot *ocelot, int port, unsigned long cookie, +int ocelot_trap_add(struct ocelot *ocelot, int port, + unsigned long cookie, bool take_ts, void (*populate)(struct ocelot_vcap_filter *f)) { struct ocelot_vcap_block *block_vcap_is2; @@ -1495,6 +1496,7 @@ int ocelot_trap_add(struct ocelot *ocelot, int port, unsigned long cookie, trap->action.cpu_copy_ena = true; trap->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; trap->action.port_mask = 0; + trap->take_ts = take_ts; list_add_tail(&trap->trap_list, &ocelot->traps); new = true; } @@ -1543,7 +1545,7 @@ static int ocelot_l2_ptp_trap_add(struct ocelot *ocelot, int port) { unsigned long l2_cookie = OCELOT_VCAP_IS2_L2_PTP_TRAP(ocelot); - return ocelot_trap_add(ocelot, port, l2_cookie, + return ocelot_trap_add(ocelot, port, l2_cookie, true, ocelot_populate_l2_ptp_trap_key); } @@ -1560,12 +1562,12 @@ static int ocelot_ipv4_ptp_trap_add(struct ocelot *ocelot, int port) unsigned long ipv4_ev_cookie = OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot); int err; - err = ocelot_trap_add(ocelot, port, ipv4_ev_cookie, + err = ocelot_trap_add(ocelot, port, ipv4_ev_cookie, true, ocelot_populate_ipv4_ptp_event_trap_key); if (err) return err; - err = ocelot_trap_add(ocelot, port, ipv4_gen_cookie, + err = ocelot_trap_add(ocelot, port, ipv4_gen_cookie, false, ocelot_populate_ipv4_ptp_general_trap_key); if (err) ocelot_trap_del(ocelot, port, ipv4_ev_cookie); @@ -1590,12 +1592,12 @@ static int ocelot_ipv6_ptp_trap_add(struct ocelot *ocelot, int port) unsigned long ipv6_ev_cookie = OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot); int err; - err = ocelot_trap_add(ocelot, port, ipv6_ev_cookie, + err = ocelot_trap_add(ocelot, port, ipv6_ev_cookie, true, ocelot_populate_ipv6_ptp_event_trap_key); if (err) return err; - err = ocelot_trap_add(ocelot, port, ipv6_gen_cookie, + err = ocelot_trap_add(ocelot, port, ipv6_gen_cookie, false, ocelot_populate_ipv6_ptp_general_trap_key); if (err) ocelot_trap_del(ocelot, port, ipv6_ev_cookie); diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 674043cd9088..5277c4b53af4 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -103,7 +103,8 @@ int ocelot_port_devlink_init(struct ocelot *ocelot, int port, enum devlink_port_flavour flavour); void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port); -int ocelot_trap_add(struct ocelot *ocelot, int port, unsigned long cookie, +int ocelot_trap_add(struct ocelot *ocelot, int port, + unsigned long cookie, bool take_ts, void (*populate)(struct ocelot_vcap_filter *f)); int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie); diff --git a/drivers/net/ethernet/mscc/ocelot_mrp.c b/drivers/net/ethernet/mscc/ocelot_mrp.c index 68fa833f4aaa..142e897ea2af 100644 --- a/drivers/net/ethernet/mscc/ocelot_mrp.c +++ b/drivers/net/ethernet/mscc/ocelot_mrp.c @@ -92,7 +92,7 @@ static int ocelot_mrp_trap_add(struct ocelot *ocelot, int port) { unsigned long cookie = OCELOT_VCAP_IS2_MRP_TRAP(ocelot); - return ocelot_trap_add(ocelot, port, cookie, + return ocelot_trap_add(ocelot, port, cookie, false, ocelot_populate_mrp_trap_key); } diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index 69b3d880302d..50af64e2ca3c 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -695,6 +695,7 @@ struct ocelot_vcap_filter { struct ocelot_vcap_action action; struct ocelot_vcap_stats stats; /* For VCAP IS1 and IS2 */ + bool take_ts; unsigned long ingress_port_mask; /* For VCAP ES0 */ struct ocelot_vcap_port ingress_port; -- cgit v1.2.3 From 9934800436552d2a4af4aaca62d779b33d1f6a63 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Feb 2022 16:30:13 +0200 Subject: net: dsa: felix: update destinations of existing traps with ocelot-8021q Historically, the felix DSA driver has installed special traps such that PTP over L2 works with the ocelot-8021q tagging protocol; commit 0a6f17c6ae21 ("net: dsa: tag_ocelot_8021q: add support for PTP timestamping") has the details. Then the ocelot switch library also gained more comprehensive support for PTP traps through commit 96ca08c05838 ("net: mscc: ocelot: set up traps for PTP packets"). Right now, PTP over L2 works using ocelot-8021q via the traps it has set for itself, but nothing else does. Consolidating the two code blocks would make ocelot-8021q gain support for PTP over L4 and tc-flower traps, and at the same time avoid some code and TCAM duplication. The traps are similar in intent, but different in execution, so some explanation is required. The traps set up by felix_setup_mmio_filtering() are VCAP IS1 filters, which have a PAG that chains them to a VCAP IS2 filter, and the IS2 is where the 'trap' action resides. The traps set up by ocelot_trap_add(), on the other hand, have a single filter, in VCAP IS2. The reason for chaining VCAP IS1 and IS2 in Felix was to ensure that the hardcoded traps take precedence and cannot be overridden by the Ocelot switch library. So in principle, the PTP traps needed for ocelot-8021q in the Felix driver can rely on ocelot_trap_add(), but the filters need to be patched to account for a quirk that LS1028A has: the quirk_no_xtr_irq described in commit 0a6f17c6ae21 ("net: dsa: tag_ocelot_8021q: add support for PTP timestamping"). Live-patching is done by iterating through the trap list every time we know it has been updated, and transforming a trap into a redirect + CPU copy if ocelot-8021q is in use. Making the DSA ocelot-8021q tagger work with the Ocelot traps means we can eliminate the dedicated OCELOT_VCAP_IS1_TAG_8021Q_PTP_MMIO and OCELOT_VCAP_IS2_TAG_8021Q_PTP_MMIO cookies. To minimize the patch delta, OCELOT_VCAP_IS2_MRP_TRAP takes the place of OCELOT_VCAP_IS2_TAG_8021Q_PTP_MMIO (the alternative would have been to left-shift all cookie numbers by 1). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 187 +++++++++++++++++------------------------ include/soc/mscc/ocelot_vcap.h | 4 +- 2 files changed, 77 insertions(+), 114 deletions(-) (limited to 'include/soc/mscc/ocelot_vcap.h') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 7293eff0e90a..9ffd5491bf2d 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -267,30 +267,26 @@ static void felix_8021q_cpu_port_deinit(struct ocelot *ocelot, int port) mutex_unlock(&ocelot->fwd_domain_lock); } -/* Set up a VCAP IS2 rule for delivering PTP frames to the CPU port module. - * If the quirk_no_xtr_irq is in place, then also copy those PTP frames to the - * tag_8021q CPU port. +/* On switches with no extraction IRQ wired, trapped packets need to be + * replicated over Ethernet as well, otherwise we'd get no notification of + * their arrival when using the ocelot-8021q tagging protocol. */ -static int felix_setup_mmio_filtering(struct felix *felix) +static int felix_update_trapping_destinations(struct dsa_switch *ds, + bool using_tag_8021q) { - unsigned long user_ports = dsa_user_ports(felix->ds); - struct ocelot_vcap_filter *redirect_rule; - struct ocelot_vcap_filter *tagging_rule; - struct ocelot *ocelot = &felix->ocelot; - struct dsa_switch *ds = felix->ds; + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + struct ocelot_vcap_filter *trap; + enum ocelot_mask_mode mask_mode; + unsigned long port_mask; struct dsa_port *dp; - int cpu = -1, ret; - - tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); - if (!tagging_rule) - return -ENOMEM; + bool cpu_copy_ena; + int cpu = -1, err; - redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); - if (!redirect_rule) { - kfree(tagging_rule); - return -ENOMEM; - } + if (!felix->info->quirk_no_xtr_irq) + return 0; + /* Figure out the current CPU port */ dsa_switch_for_each_cpu_port(dp, ds) { cpu = dp->index; break; @@ -300,103 +296,46 @@ static int felix_setup_mmio_filtering(struct felix *felix) * dsa_tree_setup_default_cpu() would have failed earlier. */ - tagging_rule->key_type = OCELOT_VCAP_KEY_ETYPE; - *(__be16 *)tagging_rule->key.etype.etype.value = htons(ETH_P_1588); - *(__be16 *)tagging_rule->key.etype.etype.mask = htons(0xffff); - tagging_rule->ingress_port_mask = user_ports; - tagging_rule->prio = 1; - tagging_rule->id.cookie = OCELOT_VCAP_IS1_TAG_8021Q_PTP_MMIO(ocelot); - tagging_rule->id.tc_offload = false; - tagging_rule->block_id = VCAP_IS1; - tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; - tagging_rule->lookup = 0; - tagging_rule->action.pag_override_mask = 0xff; - tagging_rule->action.pag_val = ocelot->num_phys_ports; - - ret = ocelot_vcap_filter_add(ocelot, tagging_rule, NULL); - if (ret) { - kfree(tagging_rule); - kfree(redirect_rule); - return ret; - } + /* Make sure all traps are set up for that destination */ + list_for_each_entry(trap, &ocelot->traps, trap_list) { + /* Figure out the current trapping destination */ + if (using_tag_8021q) { + /* Redirect to the tag_8021q CPU port. If timestamps + * are necessary, also copy trapped packets to the CPU + * port module. + */ + mask_mode = OCELOT_MASK_MODE_REDIRECT; + port_mask = BIT(cpu); + cpu_copy_ena = !!trap->take_ts; + } else { + /* Trap packets only to the CPU port module, which is + * redirected to the NPI port (the DSA CPU port) + */ + mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; + port_mask = 0; + cpu_copy_ena = true; + } - redirect_rule->key_type = OCELOT_VCAP_KEY_ANY; - redirect_rule->ingress_port_mask = user_ports; - redirect_rule->pag = ocelot->num_phys_ports; - redirect_rule->prio = 1; - redirect_rule->id.cookie = OCELOT_VCAP_IS2_TAG_8021Q_PTP_MMIO(ocelot); - redirect_rule->id.tc_offload = false; - redirect_rule->block_id = VCAP_IS2; - redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; - redirect_rule->lookup = 0; - redirect_rule->action.cpu_copy_ena = true; - if (felix->info->quirk_no_xtr_irq) { - /* Redirect to the tag_8021q CPU but also copy PTP packets to - * the CPU port module - */ - redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; - redirect_rule->action.port_mask = BIT(cpu); - } else { - /* Trap PTP packets only to the CPU port module (which is - * redirected to the NPI port) - */ - redirect_rule->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; - redirect_rule->action.port_mask = 0; - } + if (trap->action.mask_mode == mask_mode && + trap->action.port_mask == port_mask && + trap->action.cpu_copy_ena == cpu_copy_ena) + continue; - ret = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL); - if (ret) { - ocelot_vcap_filter_del(ocelot, tagging_rule); - kfree(redirect_rule); - return ret; - } + trap->action.mask_mode = mask_mode; + trap->action.port_mask = port_mask; + trap->action.cpu_copy_ena = cpu_copy_ena; - /* The ownership of the CPU port module's queues might have just been - * transferred to the tag_8021q tagger from the NPI-based tagger. - * So there might still be all sorts of crap in the queues. On the - * other hand, the MMIO-based matching of PTP frames is very brittle, - * so we need to be careful that there are no extra frames to be - * dequeued over MMIO, since we would never know to discard them. - */ - ocelot_drain_cpu_queue(ocelot, 0); + err = ocelot_vcap_filter_replace(ocelot, trap); + if (err) + return err; + } return 0; } -static int felix_teardown_mmio_filtering(struct felix *felix) -{ - struct ocelot_vcap_filter *tagging_rule, *redirect_rule; - struct ocelot_vcap_block *block_vcap_is1; - struct ocelot_vcap_block *block_vcap_is2; - struct ocelot *ocelot = &felix->ocelot; - int err; - - block_vcap_is1 = &ocelot->block[VCAP_IS1]; - block_vcap_is2 = &ocelot->block[VCAP_IS2]; - - tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, - ocelot->num_phys_ports, - false); - if (!tagging_rule) - return -ENOENT; - - err = ocelot_vcap_filter_del(ocelot, tagging_rule); - if (err) - return err; - - redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, - ocelot->num_phys_ports, - false); - if (!redirect_rule) - return -ENOENT; - - return ocelot_vcap_filter_del(ocelot, redirect_rule); -} - static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) { struct ocelot *ocelot = ds->priv; - struct felix *felix = ocelot_to_felix(ocelot); unsigned long cpu_flood; struct dsa_port *dp; int err; @@ -432,10 +371,19 @@ static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) if (err) return err; - err = felix_setup_mmio_filtering(felix); + err = felix_update_trapping_destinations(ds, true); if (err) goto out_tag_8021q_unregister; + /* The ownership of the CPU port module's queues might have just been + * transferred to the tag_8021q tagger from the NPI-based tagger. + * So there might still be all sorts of crap in the queues. On the + * other hand, the MMIO-based matching of PTP frames is very brittle, + * so we need to be careful that there are no extra frames to be + * dequeued over MMIO, since we would never know to discard them. + */ + ocelot_drain_cpu_queue(ocelot, 0); + return 0; out_tag_8021q_unregister: @@ -446,11 +394,10 @@ out_tag_8021q_unregister: static void felix_teardown_tag_8021q(struct dsa_switch *ds, int cpu) { struct ocelot *ocelot = ds->priv; - struct felix *felix = ocelot_to_felix(ocelot); struct dsa_port *dp; int err; - err = felix_teardown_mmio_filtering(felix); + err = felix_update_trapping_destinations(ds, false); if (err) dev_err(ds->dev, "felix_teardown_mmio_filtering returned %d", err); @@ -1279,8 +1226,17 @@ static int felix_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) { struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + bool using_tag_8021q; + int err; - return ocelot_hwstamp_set(ocelot, port, ifr); + err = ocelot_hwstamp_set(ocelot, port, ifr); + if (err) + return err; + + using_tag_8021q = felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q; + + return felix_update_trapping_destinations(ds, using_tag_8021q); } static bool felix_check_xtr_pkt(struct ocelot *ocelot, unsigned int ptp_type) @@ -1407,8 +1363,17 @@ static int felix_cls_flower_add(struct dsa_switch *ds, int port, struct flow_cls_offload *cls, bool ingress) { struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + bool using_tag_8021q; + int err; + + err = ocelot_cls_flower_replace(ocelot, port, cls, ingress); + if (err) + return err; + + using_tag_8021q = felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q; - return ocelot_cls_flower_replace(ocelot, port, cls, ingress); + return felix_update_trapping_destinations(ds, using_tag_8021q); } static int felix_cls_flower_del(struct dsa_switch *ds, int port, diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index 50af64e2ca3c..deb2ad9eb0a5 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -13,16 +13,14 @@ */ #define OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port) (port) #define OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port) (port) -#define OCELOT_VCAP_IS1_TAG_8021Q_PTP_MMIO(ocelot) ((ocelot)->num_phys_ports) #define OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port) (port) #define OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port) ((ocelot)->num_phys_ports + (port)) -#define OCELOT_VCAP_IS2_TAG_8021Q_PTP_MMIO(ocelot) ((ocelot)->num_phys_ports * 2) +#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2) #define OCELOT_VCAP_IS2_L2_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 1) #define OCELOT_VCAP_IS2_IPV4_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 2) #define OCELOT_VCAP_IS2_IPV4_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 3) #define OCELOT_VCAP_IS2_IPV6_GEN_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 4) #define OCELOT_VCAP_IS2_IPV6_EV_PTP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 5) -#define OCELOT_VCAP_IS2_MRP_TRAP(ocelot) ((ocelot)->num_phys_ports * 2 + 6) /* ================================================================= * VCAP Common -- cgit v1.2.3 From f2a0e216bee5d95e2c2d916a8815a659cd3703c2 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Mar 2022 22:41:42 +0200 Subject: net: mscc: ocelot: offload per-flow mirroring using tc-mirred and VCAP IS2 Per-flow mirroring with the VCAP IS2 TCAM (in itself handled as an offload for tc-flower) is done by setting the MIRROR_ENA bit from the action vector of the filter. The packet is mirrored to the port mask configured in the ANA:ANA:MIRRORPORTS register (the same port mask as the destinations for port-based mirroring). Functionality was tested with: tc qdisc add dev swp3 clsact tc filter add dev swp3 ingress protocol ip \ flower skip_sw ip_proto icmp \ action mirred egress mirror dev swp1 and pinging through swp3, while seeing that the ICMP replies are mirrored towards swp1. Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mscc/ocelot.c | 6 +++--- drivers/net/ethernet/mscc/ocelot.h | 4 ++++ drivers/net/ethernet/mscc/ocelot_flower.c | 21 +++++++++++++++++++++ drivers/net/ethernet/mscc/ocelot_vcap.c | 12 ++++++++++++ include/soc/mscc/ocelot_vcap.h | 2 ++ 5 files changed, 42 insertions(+), 3 deletions(-) (limited to 'include/soc/mscc/ocelot_vcap.h') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index d38a9b498490..e443bd8b2d09 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -3023,8 +3023,8 @@ int ocelot_port_del_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio) } EXPORT_SYMBOL_GPL(ocelot_port_del_dscp_prio); -static struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, - struct netlink_ext_ack *extack) +struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, + struct netlink_ext_ack *extack) { struct ocelot_mirror *m = ocelot->mirror; @@ -3053,7 +3053,7 @@ static struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, return m; } -static void ocelot_mirror_put(struct ocelot *ocelot) +void ocelot_mirror_put(struct ocelot *ocelot) { struct ocelot_mirror *m = ocelot->mirror; diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index d5bd525e7ec2..d0fa8ab6cc81 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -112,6 +112,10 @@ int ocelot_trap_add(struct ocelot *ocelot, int port, void (*populate)(struct ocelot_vcap_filter *f)); int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie); +struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, + struct netlink_ext_ack *extack); +void ocelot_mirror_put(struct ocelot *ocelot); + extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_blocking_nb; diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index bd9525867caa..03b5e59d033e 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -359,6 +359,27 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, filter->action.port_mask = BIT(egress_port); filter->type = OCELOT_VCAP_FILTER_OFFLOAD; break; + case FLOW_ACTION_MIRRED: + if (filter->block_id != VCAP_IS2) { + NL_SET_ERR_MSG_MOD(extack, + "Mirror action can only be offloaded to VCAP IS2"); + return -EOPNOTSUPP; + } + if (filter->goto_target != -1) { + NL_SET_ERR_MSG_MOD(extack, + "Last action must be GOTO"); + return -EOPNOTSUPP; + } + egress_port = ocelot->ops->netdev_to_port(a->dev); + if (egress_port < 0) { + NL_SET_ERR_MSG_MOD(extack, + "Destination not an ocelot port"); + return -EOPNOTSUPP; + } + filter->egress_port.value = egress_port; + filter->action.mirror_ena = true; + filter->type = OCELOT_VCAP_FILTER_OFFLOAD; + break; case FLOW_ACTION_VLAN_POP: if (filter->block_id != VCAP_IS1) { NL_SET_ERR_MSG_MOD(extack, diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c index 829fb55ea9dc..c8701ac955a8 100644 --- a/drivers/net/ethernet/mscc/ocelot_vcap.c +++ b/drivers/net/ethernet/mscc/ocelot_vcap.c @@ -335,6 +335,7 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data, vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, a->mask_mode); vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, a->port_mask); + vcap_action_set(vcap, data, VCAP_IS2_ACT_MIRROR_ENA, a->mirror_ena); vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, a->police_ena); vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, a->pol_ix); vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, a->cpu_qu_num); @@ -960,8 +961,16 @@ ocelot_vcap_filter_add_aux_resources(struct ocelot *ocelot, struct ocelot_vcap_filter *filter, struct netlink_ext_ack *extack) { + struct ocelot_mirror *m; int ret; + if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena) { + m = ocelot_mirror_get(ocelot, filter->egress_port.value, + extack); + if (IS_ERR(m)) + return PTR_ERR(m); + } + if (filter->block_id == VCAP_IS2 && filter->action.police_ena) { ret = ocelot_vcap_policer_add(ocelot, filter->action.pol_ix, &filter->action.pol); @@ -978,6 +987,9 @@ ocelot_vcap_filter_del_aux_resources(struct ocelot *ocelot, { if (filter->block_id == VCAP_IS2 && filter->action.police_ena) ocelot_vcap_policer_del(ocelot, filter->action.pol_ix); + + if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena) + ocelot_mirror_put(ocelot); } static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index deb2ad9eb0a5..7b2bf9b1fe69 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -654,6 +654,7 @@ struct ocelot_vcap_action { enum ocelot_mask_mode mask_mode; unsigned long port_mask; bool police_ena; + bool mirror_ena; struct ocelot_policer pol; u32 pol_ix; }; @@ -697,6 +698,7 @@ struct ocelot_vcap_filter { unsigned long ingress_port_mask; /* For VCAP ES0 */ struct ocelot_vcap_port ingress_port; + /* For VCAP IS2 mirrors and ES0 */ struct ocelot_vcap_port egress_port; enum ocelot_vcap_bit dmac_mc; -- cgit v1.2.3