Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ocelot-mrp'

Horatiu Vultur says:

====================
net: ocelot: Extend MRP

This patch series extends the current support of MRP in Ocelot driver.
Currently the forwarding of the frames happened in SW because all frames
were trapped to CPU. With this patch the MRP frames will be forward in HW.

v1 -> v2:
- create a patch series instead of single patch
- rename ocelot_mrp_find_port to ocelot_mrp_find_partner_port
- rename PGID_MRP to PGID_BLACKHOLE
- use GFP_KERNEL instead of GFP_ATOMIC
- fix other whitespace issues
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+167 -103
+4 -8
drivers/net/ethernet/mscc/ocelot.c
··· 687 687 int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb) 688 688 { 689 689 struct skb_shared_hwtstamps *shhwtstamps; 690 - u64 tod_in_ns, full_ts_in_ns, cpuq; 690 + u64 tod_in_ns, full_ts_in_ns; 691 691 u64 timestamp, src_port, len; 692 692 u32 xfh[OCELOT_TAG_LEN / 4]; 693 693 struct net_device *dev; ··· 704 704 ocelot_xfh_get_src_port(xfh, &src_port); 705 705 ocelot_xfh_get_len(xfh, &len); 706 706 ocelot_xfh_get_rew_val(xfh, &timestamp); 707 - ocelot_xfh_get_cpuq(xfh, &cpuq); 708 707 709 708 if (WARN_ON(src_port >= ocelot->num_phys_ports)) 710 709 return -EINVAL; ··· 770 771 skb->offload_fwd_mark = 1; 771 772 772 773 skb->protocol = eth_type_trans(skb, dev); 773 - 774 - #if IS_ENABLED(CONFIG_BRIDGE_MRP) 775 - if (skb->protocol == cpu_to_be16(ETH_P_MRP) && 776 - cpuq & BIT(OCELOT_MRP_CPUQ)) 777 - skb->offload_fwd_mark = 0; 778 - #endif 779 774 780 775 *nskb = skb; 781 776 ··· 2044 2051 2045 2052 ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i); 2046 2053 } 2054 + 2055 + ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_BLACKHOLE); 2056 + 2047 2057 /* Allow broadcast and unknown L2 multicast to the CPU. */ 2048 2058 ocelot_rmw_rix(ocelot, ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)), 2049 2059 ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
+158 -75
drivers/net/ethernet/mscc/ocelot_mrp.c
··· 1 1 // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2 2 /* Microsemi Ocelot Switch driver 3 3 * 4 - * This contains glue logic between the switchdev driver operations and the 5 - * mscc_ocelot_switch_lib. 6 - * 7 4 * Copyright (c) 2017, 2019 Microsemi Corporation 8 5 * Copyright 2020-2021 NXP Semiconductors 9 6 */ ··· 12 15 #include "ocelot.h" 13 16 #include "ocelot_vcap.h" 14 17 15 - static int ocelot_mrp_del_vcap(struct ocelot *ocelot, int port) 18 + static const u8 mrp_test_dmac[] = { 0x01, 0x15, 0x4e, 0x00, 0x00, 0x01 }; 19 + static const u8 mrp_control_dmac[] = { 0x01, 0x15, 0x4e, 0x00, 0x00, 0x02 }; 20 + 21 + static int ocelot_mrp_find_partner_port(struct ocelot *ocelot, 22 + struct ocelot_port *p) 23 + { 24 + int i; 25 + 26 + for (i = 0; i < ocelot->num_phys_ports; ++i) { 27 + struct ocelot_port *ocelot_port = ocelot->ports[i]; 28 + 29 + if (!ocelot_port || p == ocelot_port) 30 + continue; 31 + 32 + if (ocelot_port->mrp_ring_id == p->mrp_ring_id) 33 + return i; 34 + } 35 + 36 + return -1; 37 + } 38 + 39 + static int ocelot_mrp_del_vcap(struct ocelot *ocelot, int id) 16 40 { 17 41 struct ocelot_vcap_block *block_vcap_is2; 18 42 struct ocelot_vcap_filter *filter; 19 43 20 44 block_vcap_is2 = &ocelot->block[VCAP_IS2]; 21 - filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, port, 45 + filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, id, 22 46 false); 23 47 if (!filter) 24 48 return 0; 25 49 26 50 return ocelot_vcap_filter_del(ocelot, filter); 51 + } 52 + 53 + static int ocelot_mrp_redirect_add_vcap(struct ocelot *ocelot, int src_port, 54 + int dst_port) 55 + { 56 + const u8 mrp_test_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 57 + struct ocelot_vcap_filter *filter; 58 + int err; 59 + 60 + filter = kzalloc(sizeof(*filter), GFP_KERNEL); 61 + if (!filter) 62 + return -ENOMEM; 63 + 64 + filter->key_type = OCELOT_VCAP_KEY_ETYPE; 65 + filter->prio = 1; 66 + filter->id.cookie = src_port; 67 + filter->id.tc_offload = false; 68 + filter->block_id = VCAP_IS2; 69 + filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 70 + filter->ingress_port_mask = BIT(src_port); 71 + ether_addr_copy(filter->key.etype.dmac.value, mrp_test_dmac); 72 + ether_addr_copy(filter->key.etype.dmac.mask, mrp_test_mask); 73 + filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 74 + filter->action.port_mask = BIT(dst_port); 75 + 76 + err = ocelot_vcap_filter_add(ocelot, filter, NULL); 77 + if (err) 78 + kfree(filter); 79 + 80 + return err; 81 + } 82 + 83 + static int ocelot_mrp_copy_add_vcap(struct ocelot *ocelot, int port, 84 + int prio, unsigned long cookie) 85 + { 86 + const u8 mrp_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; 87 + struct ocelot_vcap_filter *filter; 88 + int err; 89 + 90 + filter = kzalloc(sizeof(*filter), GFP_KERNEL); 91 + if (!filter) 92 + return -ENOMEM; 93 + 94 + filter->key_type = OCELOT_VCAP_KEY_ETYPE; 95 + filter->prio = prio; 96 + filter->id.cookie = cookie; 97 + filter->id.tc_offload = false; 98 + filter->block_id = VCAP_IS2; 99 + filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 100 + filter->ingress_port_mask = BIT(port); 101 + /* Here is possible to use control or test dmac because the mask 102 + * doesn't cover the LSB 103 + */ 104 + ether_addr_copy(filter->key.etype.dmac.value, mrp_test_dmac); 105 + ether_addr_copy(filter->key.etype.dmac.mask, mrp_mask); 106 + filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; 107 + filter->action.port_mask = 0x0; 108 + filter->action.cpu_copy_ena = true; 109 + filter->action.cpu_qu_num = OCELOT_MRP_CPUQ; 110 + 111 + err = ocelot_vcap_filter_add(ocelot, filter, NULL); 112 + if (err) 113 + kfree(filter); 114 + 115 + return err; 116 + } 117 + 118 + static void ocelot_mrp_save_mac(struct ocelot *ocelot, 119 + struct ocelot_port *port) 120 + { 121 + ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_test_dmac, 122 + port->pvid_vlan.vid, ENTRYTYPE_LOCKED); 123 + ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_control_dmac, 124 + port->pvid_vlan.vid, ENTRYTYPE_LOCKED); 125 + } 126 + 127 + static void ocelot_mrp_del_mac(struct ocelot *ocelot, 128 + struct ocelot_port *port) 129 + { 130 + ocelot_mact_forget(ocelot, mrp_test_dmac, port->pvid_vlan.vid); 131 + ocelot_mact_forget(ocelot, mrp_control_dmac, port->pvid_vlan.vid); 27 132 } 28 133 29 134 int ocelot_mrp_add(struct ocelot *ocelot, int port, ··· 144 45 if (mrp->p_port != dev && mrp->s_port != dev) 145 46 return 0; 146 47 147 - if (ocelot->mrp_ring_id != 0 && 148 - ocelot->mrp_s_port && 149 - ocelot->mrp_p_port) 150 - return -EINVAL; 151 - 152 - if (mrp->p_port == dev) 153 - ocelot->mrp_p_port = dev; 154 - 155 - if (mrp->s_port == dev) 156 - ocelot->mrp_s_port = dev; 157 - 158 - ocelot->mrp_ring_id = mrp->ring_id; 48 + ocelot_port->mrp_ring_id = mrp->ring_id; 159 49 160 50 return 0; 161 51 } ··· 154 66 const struct switchdev_obj_mrp *mrp) 155 67 { 156 68 struct ocelot_port *ocelot_port = ocelot->ports[port]; 157 - struct ocelot_port_private *priv; 158 - struct net_device *dev; 69 + int i; 159 70 160 71 if (!ocelot_port) 161 72 return -EOPNOTSUPP; 162 73 163 - priv = container_of(ocelot_port, struct ocelot_port_private, port); 164 - dev = priv->dev; 165 - 166 - if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev) 74 + if (ocelot_port->mrp_ring_id != mrp->ring_id) 167 75 return 0; 168 76 169 - if (ocelot->mrp_ring_id == 0 && 170 - !ocelot->mrp_s_port && 171 - !ocelot->mrp_p_port) 172 - return -EINVAL; 77 + ocelot_mrp_del_vcap(ocelot, port); 78 + ocelot_mrp_del_vcap(ocelot, port + ocelot->num_phys_ports); 173 79 174 - if (ocelot_mrp_del_vcap(ocelot, priv->chip_port)) 175 - return -EINVAL; 80 + ocelot_port->mrp_ring_id = 0; 176 81 177 - if (ocelot->mrp_p_port == dev) 178 - ocelot->mrp_p_port = NULL; 82 + for (i = 0; i < ocelot->num_phys_ports; ++i) { 83 + ocelot_port = ocelot->ports[i]; 179 84 180 - if (ocelot->mrp_s_port == dev) 181 - ocelot->mrp_s_port = NULL; 85 + if (!ocelot_port) 86 + continue; 182 87 183 - ocelot->mrp_ring_id = 0; 88 + if (ocelot_port->mrp_ring_id != 0) 89 + goto out; 90 + } 184 91 92 + ocelot_mrp_del_mac(ocelot, ocelot_port); 93 + out: 185 94 return 0; 186 95 } 187 96 EXPORT_SYMBOL(ocelot_mrp_del); ··· 187 102 const struct switchdev_obj_ring_role_mrp *mrp) 188 103 { 189 104 struct ocelot_port *ocelot_port = ocelot->ports[port]; 190 - struct ocelot_vcap_filter *filter; 191 - struct ocelot_port_private *priv; 192 - struct net_device *dev; 105 + int dst_port; 193 106 int err; 194 107 195 108 if (!ocelot_port) 196 109 return -EOPNOTSUPP; 197 110 198 - priv = container_of(ocelot_port, struct ocelot_port_private, port); 199 - dev = priv->dev; 200 - 201 - if (ocelot->mrp_ring_id != mrp->ring_id) 202 - return -EINVAL; 203 - 204 - if (!mrp->sw_backup) 111 + if (mrp->ring_role != BR_MRP_RING_ROLE_MRC && !mrp->sw_backup) 205 112 return -EOPNOTSUPP; 206 113 207 - if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev) 114 + if (ocelot_port->mrp_ring_id != mrp->ring_id) 208 115 return 0; 209 116 210 - filter = kzalloc(sizeof(*filter), GFP_ATOMIC); 211 - if (!filter) 212 - return -ENOMEM; 117 + ocelot_mrp_save_mac(ocelot, ocelot_port); 213 118 214 - filter->key_type = OCELOT_VCAP_KEY_ETYPE; 215 - filter->prio = 1; 216 - filter->id.cookie = priv->chip_port; 217 - filter->id.tc_offload = false; 218 - filter->block_id = VCAP_IS2; 219 - filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 220 - filter->ingress_port_mask = BIT(priv->chip_port); 221 - *(__be16 *)filter->key.etype.etype.value = htons(ETH_P_MRP); 222 - *(__be16 *)filter->key.etype.etype.mask = htons(0xffff); 223 - filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; 224 - filter->action.port_mask = 0x0; 225 - filter->action.cpu_copy_ena = true; 226 - filter->action.cpu_qu_num = OCELOT_MRP_CPUQ; 119 + if (mrp->ring_role != BR_MRP_RING_ROLE_MRC) 120 + return ocelot_mrp_copy_add_vcap(ocelot, port, 1, port); 227 121 228 - err = ocelot_vcap_filter_add(ocelot, filter, NULL); 122 + dst_port = ocelot_mrp_find_partner_port(ocelot, ocelot_port); 123 + if (dst_port == -1) 124 + return -EINVAL; 125 + 126 + err = ocelot_mrp_redirect_add_vcap(ocelot, port, dst_port); 229 127 if (err) 230 - kfree(filter); 128 + return err; 231 129 232 - return err; 130 + err = ocelot_mrp_copy_add_vcap(ocelot, port, 2, 131 + port + ocelot->num_phys_ports); 132 + if (err) { 133 + ocelot_mrp_del_vcap(ocelot, port); 134 + return err; 135 + } 136 + 137 + return 0; 233 138 } 234 139 EXPORT_SYMBOL(ocelot_mrp_add_ring_role); 235 140 ··· 227 152 const struct switchdev_obj_ring_role_mrp *mrp) 228 153 { 229 154 struct ocelot_port *ocelot_port = ocelot->ports[port]; 230 - struct ocelot_port_private *priv; 231 - struct net_device *dev; 155 + int i; 232 156 233 157 if (!ocelot_port) 234 158 return -EOPNOTSUPP; 235 159 236 - priv = container_of(ocelot_port, struct ocelot_port_private, port); 237 - dev = priv->dev; 238 - 239 - if (ocelot->mrp_ring_id != mrp->ring_id) 240 - return -EINVAL; 241 - 242 - if (!mrp->sw_backup) 160 + if (mrp->ring_role != BR_MRP_RING_ROLE_MRC && !mrp->sw_backup) 243 161 return -EOPNOTSUPP; 244 162 245 - if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev) 163 + if (ocelot_port->mrp_ring_id != mrp->ring_id) 246 164 return 0; 247 165 248 - return ocelot_mrp_del_vcap(ocelot, priv->chip_port); 166 + ocelot_mrp_del_vcap(ocelot, port); 167 + ocelot_mrp_del_vcap(ocelot, port + ocelot->num_phys_ports); 168 + 169 + for (i = 0; i < ocelot->num_phys_ports; ++i) { 170 + ocelot_port = ocelot->ports[i]; 171 + 172 + if (!ocelot_port) 173 + continue; 174 + 175 + if (ocelot_port->mrp_ring_id != 0) 176 + goto out; 177 + } 178 + 179 + ocelot_mrp_del_mac(ocelot, ocelot_port); 180 + out: 181 + return 0; 249 182 } 250 183 EXPORT_SYMBOL(ocelot_mrp_del_ring_role);
-5
include/linux/dsa/ocelot.h
··· 160 160 packing(extraction, src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0); 161 161 } 162 162 163 - static inline void ocelot_xfh_get_cpuq(void *extraction, u64 *cpuq) 164 - { 165 - packing(extraction, cpuq, 28, 20, OCELOT_TAG_LEN, UNPACK, 0); 166 - } 167 - 168 163 static inline void ocelot_xfh_get_qos_class(void *extraction, u64 *qos_class) 169 164 { 170 165 packing(extraction, qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
+5 -7
include/soc/mscc/ocelot.h
··· 51 51 */ 52 52 53 53 /* Reserve some destination PGIDs at the end of the range: 54 + * PGID_BLACKHOLE: used for not forwarding the frames 54 55 * PGID_CPU: used for whitelisting certain MAC addresses, such as the addresses 55 56 * of the switch port net devices, towards the CPU port module. 56 57 * PGID_UC: the flooding destinations for unknown unicast traffic. ··· 60 59 * PGID_MCIPV6: the flooding destinations for IPv6 multicast traffic. 61 60 * PGID_BC: the flooding destinations for broadcast traffic. 62 61 */ 62 + #define PGID_BLACKHOLE 57 63 63 #define PGID_CPU 58 64 64 #define PGID_UC 59 65 65 #define PGID_MC 60 ··· 75 73 76 74 #define for_each_nonreserved_multicast_dest_pgid(ocelot, pgid) \ 77 75 for ((pgid) = (ocelot)->num_phys_ports + 1; \ 78 - (pgid) < PGID_CPU; \ 76 + (pgid) < PGID_BLACKHOLE; \ 79 77 (pgid)++) 80 78 81 79 #define for_each_aggr_pgid(ocelot, pgid) \ ··· 613 611 614 612 struct net_device *bond; 615 613 bool lag_tx_active; 614 + 615 + u16 mrp_ring_id; 616 616 }; 617 617 618 618 struct ocelot { ··· 683 679 /* Protects the PTP clock */ 684 680 spinlock_t ptp_clock_lock; 685 681 struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM]; 686 - 687 - #if IS_ENABLED(CONFIG_BRIDGE_MRP) 688 - u16 mrp_ring_id; 689 - struct net_device *mrp_p_port; 690 - struct net_device *mrp_s_port; 691 - #endif 692 682 }; 693 683 694 684 struct ocelot_policer {
-8
net/dsa/tag_ocelot.c
··· 83 83 struct dsa_port *dp; 84 84 u8 *extraction; 85 85 u16 vlan_tpid; 86 - u64 cpuq; 87 86 88 87 /* Revert skb->data by the amount consumed by the DSA master, 89 88 * so it points to the beginning of the frame. ··· 112 113 ocelot_xfh_get_qos_class(extraction, &qos_class); 113 114 ocelot_xfh_get_tag_type(extraction, &tag_type); 114 115 ocelot_xfh_get_vlan_tci(extraction, &vlan_tci); 115 - ocelot_xfh_get_cpuq(extraction, &cpuq); 116 116 117 117 skb->dev = dsa_master_find_slave(netdev, 0, src_port); 118 118 if (!skb->dev) ··· 125 127 126 128 skb->offload_fwd_mark = 1; 127 129 skb->priority = qos_class; 128 - 129 - #if IS_ENABLED(CONFIG_BRIDGE_MRP) 130 - if (eth_hdr(skb)->h_proto == cpu_to_be16(ETH_P_MRP) && 131 - cpuq & BIT(OCELOT_MRP_CPUQ)) 132 - skb->offload_fwd_mark = 0; 133 - #endif 134 130 135 131 /* Ocelot switches copy frames unmodified to the CPU. However, it is 136 132 * possible for the user to request a VLAN modification through