1 // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2 /* Microsemi Ocelot Switch driver 3 * 4 * Copyright (c) 2017, 2019 Microsemi Corporation 5 * Copyright 2020-2021 NXP 6 */ 7 8 #include <linux/if_bridge.h> 9 #include <linux/mrp_bridge.h> 10 #include <soc/mscc/ocelot_vcap.h> 11 #include <uapi/linux/mrp_bridge.h> 12 #include "ocelot.h" 13 #include "ocelot_vcap.h" 14 15 static const u8 mrp_test_dmac[] = { 0x01, 0x15, 0x4e, 0x00, 0x00, 0x01 }; 16 static const u8 mrp_control_dmac[] = { 0x01, 0x15, 0x4e, 0x00, 0x00, 0x02 }; 17 18 static int ocelot_mrp_find_partner_port(struct ocelot *ocelot, 19 struct ocelot_port *p) 20 { 21 int i; 22 23 for (i = 0; i < ocelot->num_phys_ports; ++i) { 24 struct ocelot_port *ocelot_port = ocelot->ports[i]; 25 26 if (!ocelot_port || p == ocelot_port) 27 continue; 28 29 if (ocelot_port->mrp_ring_id == p->mrp_ring_id) 30 return i; 31 } 32 33 return -1; 34 } 35 36 static int ocelot_mrp_del_vcap(struct ocelot *ocelot, int id) 37 { 38 struct ocelot_vcap_block *block_vcap_is2; 39 struct ocelot_vcap_filter *filter; 40 41 block_vcap_is2 = &ocelot->block[VCAP_IS2]; 42 filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, id, 43 false); 44 if (!filter) 45 return 0; 46 47 return ocelot_vcap_filter_del(ocelot, filter); 48 } 49 50 static int ocelot_mrp_redirect_add_vcap(struct ocelot *ocelot, int src_port, 51 int dst_port) 52 { 53 const u8 mrp_test_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 54 struct ocelot_vcap_filter *filter; 55 int err; 56 57 filter = kzalloc(sizeof(*filter), GFP_KERNEL); 58 if (!filter) 59 return -ENOMEM; 60 61 filter->key_type = OCELOT_VCAP_KEY_ETYPE; 62 filter->prio = 1; 63 filter->id.cookie = OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, src_port); 64 filter->id.tc_offload = false; 65 filter->block_id = VCAP_IS2; 66 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 67 filter->ingress_port_mask = BIT(src_port); 68 ether_addr_copy(filter->key.etype.dmac.value, mrp_test_dmac); 69 ether_addr_copy(filter->key.etype.dmac.mask, mrp_test_mask); 70 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 71 filter->action.port_mask = BIT(dst_port); 72 73 err = ocelot_vcap_filter_add(ocelot, filter, NULL); 74 if (err) 75 kfree(filter); 76 77 return err; 78 } 79 80 static int ocelot_mrp_copy_add_vcap(struct ocelot *ocelot, int port, int prio) 81 { 82 const u8 mrp_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; 83 struct ocelot_vcap_filter *filter; 84 int err; 85 86 filter = kzalloc(sizeof(*filter), GFP_KERNEL); 87 if (!filter) 88 return -ENOMEM; 89 90 filter->key_type = OCELOT_VCAP_KEY_ETYPE; 91 filter->prio = prio; 92 filter->id.cookie = OCELOT_VCAP_IS2_MRP_TRAP(ocelot, port); 93 filter->id.tc_offload = false; 94 filter->block_id = VCAP_IS2; 95 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 96 filter->ingress_port_mask = BIT(port); 97 /* Here is possible to use control or test dmac because the mask 98 * doesn't cover the LSB 99 */ 100 ether_addr_copy(filter->key.etype.dmac.value, mrp_test_dmac); 101 ether_addr_copy(filter->key.etype.dmac.mask, mrp_mask); 102 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; 103 filter->action.port_mask = 0x0; 104 filter->action.cpu_copy_ena = true; 105 filter->action.cpu_qu_num = OCELOT_MRP_CPUQ; 106 107 err = ocelot_vcap_filter_add(ocelot, filter, NULL); 108 if (err) 109 kfree(filter); 110 111 return err; 112 } 113 114 static void ocelot_mrp_save_mac(struct ocelot *ocelot, 115 struct ocelot_port *port) 116 { 117 ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_test_dmac, 118 OCELOT_VLAN_UNAWARE_PVID, ENTRYTYPE_LOCKED); 119 ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_control_dmac, 120 OCELOT_VLAN_UNAWARE_PVID, ENTRYTYPE_LOCKED); 121 } 122 123 static void ocelot_mrp_del_mac(struct ocelot *ocelot, 124 struct ocelot_port *port) 125 { 126 ocelot_mact_forget(ocelot, mrp_test_dmac, OCELOT_VLAN_UNAWARE_PVID); 127 ocelot_mact_forget(ocelot, mrp_control_dmac, OCELOT_VLAN_UNAWARE_PVID); 128 } 129 130 int ocelot_mrp_add(struct ocelot *ocelot, int port, 131 const struct switchdev_obj_mrp *mrp) 132 { 133 struct ocelot_port *ocelot_port = ocelot->ports[port]; 134 struct ocelot_port_private *priv; 135 struct net_device *dev; 136 137 if (!ocelot_port) 138 return -EOPNOTSUPP; 139 140 priv = container_of(ocelot_port, struct ocelot_port_private, port); 141 dev = priv->dev; 142 143 if (mrp->p_port != dev && mrp->s_port != dev) 144 return 0; 145 146 ocelot_port->mrp_ring_id = mrp->ring_id; 147 148 return 0; 149 } 150 EXPORT_SYMBOL(ocelot_mrp_add); 151 152 int ocelot_mrp_del(struct ocelot *ocelot, int port, 153 const struct switchdev_obj_mrp *mrp) 154 { 155 struct ocelot_port *ocelot_port = ocelot->ports[port]; 156 157 if (!ocelot_port) 158 return -EOPNOTSUPP; 159 160 if (ocelot_port->mrp_ring_id != mrp->ring_id) 161 return 0; 162 163 ocelot_port->mrp_ring_id = 0; 164 165 return 0; 166 } 167 EXPORT_SYMBOL(ocelot_mrp_del); 168 169 int ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port, 170 const struct switchdev_obj_ring_role_mrp *mrp) 171 { 172 struct ocelot_port *ocelot_port = ocelot->ports[port]; 173 int dst_port; 174 int err; 175 176 if (!ocelot_port) 177 return -EOPNOTSUPP; 178 179 if (mrp->ring_role != BR_MRP_RING_ROLE_MRC && !mrp->sw_backup) 180 return -EOPNOTSUPP; 181 182 if (ocelot_port->mrp_ring_id != mrp->ring_id) 183 return 0; 184 185 ocelot_mrp_save_mac(ocelot, ocelot_port); 186 187 if (mrp->ring_role != BR_MRP_RING_ROLE_MRC) 188 return ocelot_mrp_copy_add_vcap(ocelot, port, 1); 189 190 dst_port = ocelot_mrp_find_partner_port(ocelot, ocelot_port); 191 if (dst_port == -1) 192 return -EINVAL; 193 194 err = ocelot_mrp_redirect_add_vcap(ocelot, port, dst_port); 195 if (err) 196 return err; 197 198 err = ocelot_mrp_copy_add_vcap(ocelot, port, 2); 199 if (err) { 200 ocelot_mrp_del_vcap(ocelot, 201 OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port)); 202 return err; 203 } 204 205 return 0; 206 } 207 EXPORT_SYMBOL(ocelot_mrp_add_ring_role); 208 209 int ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port, 210 const struct switchdev_obj_ring_role_mrp *mrp) 211 { 212 struct ocelot_port *ocelot_port = ocelot->ports[port]; 213 int i; 214 215 if (!ocelot_port) 216 return -EOPNOTSUPP; 217 218 if (mrp->ring_role != BR_MRP_RING_ROLE_MRC && !mrp->sw_backup) 219 return -EOPNOTSUPP; 220 221 if (ocelot_port->mrp_ring_id != mrp->ring_id) 222 return 0; 223 224 ocelot_mrp_del_vcap(ocelot, OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port)); 225 ocelot_mrp_del_vcap(ocelot, OCELOT_VCAP_IS2_MRP_TRAP(ocelot, port)); 226 227 for (i = 0; i < ocelot->num_phys_ports; ++i) { 228 ocelot_port = ocelot->ports[i]; 229 230 if (!ocelot_port) 231 continue; 232 233 if (ocelot_port->mrp_ring_id != 0) 234 goto out; 235 } 236 237 ocelot_mrp_del_mac(ocelot, ocelot->ports[port]); 238 out: 239 return 0; 240 } 241 EXPORT_SYMBOL(ocelot_mrp_del_ring_role); 242