1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Handling of a single switch chip, part of a switch fabric 4 * 5 * Copyright (c) 2017 Savoir-faire Linux Inc. 6 * Vivien Didelot <[email protected]> 7 */ 8 9 #include <linux/if_bridge.h> 10 #include <linux/netdevice.h> 11 #include <linux/notifier.h> 12 #include <linux/if_vlan.h> 13 #include <net/switchdev.h> 14 15 #include "dsa_priv.h" 16 17 static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds, 18 unsigned int ageing_time) 19 { 20 int i; 21 22 for (i = 0; i < ds->num_ports; ++i) { 23 struct dsa_port *dp = dsa_to_port(ds, i); 24 25 if (dp->ageing_time && dp->ageing_time < ageing_time) 26 ageing_time = dp->ageing_time; 27 } 28 29 return ageing_time; 30 } 31 32 static int dsa_switch_ageing_time(struct dsa_switch *ds, 33 struct dsa_notifier_ageing_time_info *info) 34 { 35 unsigned int ageing_time = info->ageing_time; 36 struct switchdev_trans *trans = info->trans; 37 38 if (switchdev_trans_ph_prepare(trans)) { 39 if (ds->ageing_time_min && ageing_time < ds->ageing_time_min) 40 return -ERANGE; 41 if (ds->ageing_time_max && ageing_time > ds->ageing_time_max) 42 return -ERANGE; 43 return 0; 44 } 45 46 /* Program the fastest ageing time in case of multiple bridges */ 47 ageing_time = dsa_switch_fastest_ageing_time(ds, ageing_time); 48 49 if (ds->ops->set_ageing_time) 50 return ds->ops->set_ageing_time(ds, ageing_time); 51 52 return 0; 53 } 54 55 static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port, 56 struct dsa_notifier_mtu_info *info) 57 { 58 if (ds->index == info->sw_index) 59 return (port == info->port) || dsa_is_dsa_port(ds, port); 60 61 if (!info->propagate_upstream) 62 return false; 63 64 if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 65 return true; 66 67 return false; 68 } 69 70 static int dsa_switch_mtu(struct dsa_switch *ds, 71 struct dsa_notifier_mtu_info *info) 72 { 73 int port, ret; 74 75 if (!ds->ops->port_change_mtu) 76 return -EOPNOTSUPP; 77 78 for (port = 0; port < ds->num_ports; port++) { 79 if (dsa_switch_mtu_match(ds, port, info)) { 80 ret = ds->ops->port_change_mtu(ds, port, info->mtu); 81 if (ret) 82 return ret; 83 } 84 } 85 86 return 0; 87 } 88 89 static int dsa_switch_bridge_join(struct dsa_switch *ds, 90 struct dsa_notifier_bridge_info *info) 91 { 92 struct dsa_switch_tree *dst = ds->dst; 93 94 if (dst->index == info->tree_index && ds->index == info->sw_index && 95 ds->ops->port_bridge_join) 96 return ds->ops->port_bridge_join(ds, info->port, info->br); 97 98 if ((dst->index != info->tree_index || ds->index != info->sw_index) && 99 ds->ops->crosschip_bridge_join) 100 return ds->ops->crosschip_bridge_join(ds, info->tree_index, 101 info->sw_index, 102 info->port, info->br); 103 104 return 0; 105 } 106 107 static int dsa_switch_bridge_leave(struct dsa_switch *ds, 108 struct dsa_notifier_bridge_info *info) 109 { 110 bool unset_vlan_filtering = br_vlan_enabled(info->br); 111 struct dsa_switch_tree *dst = ds->dst; 112 int err, i; 113 114 if (dst->index == info->tree_index && ds->index == info->sw_index && 115 ds->ops->port_bridge_join) 116 ds->ops->port_bridge_leave(ds, info->port, info->br); 117 118 if ((dst->index != info->tree_index || ds->index != info->sw_index) && 119 ds->ops->crosschip_bridge_join) 120 ds->ops->crosschip_bridge_leave(ds, info->tree_index, 121 info->sw_index, info->port, 122 info->br); 123 124 /* If the bridge was vlan_filtering, the bridge core doesn't trigger an 125 * event for changing vlan_filtering setting upon slave ports leaving 126 * it. That is a good thing, because that lets us handle it and also 127 * handle the case where the switch's vlan_filtering setting is global 128 * (not per port). When that happens, the correct moment to trigger the 129 * vlan_filtering callback is only when the last port left this bridge. 130 */ 131 if (unset_vlan_filtering && ds->vlan_filtering_is_global) { 132 for (i = 0; i < ds->num_ports; i++) { 133 if (i == info->port) 134 continue; 135 if (dsa_to_port(ds, i)->bridge_dev == info->br) { 136 unset_vlan_filtering = false; 137 break; 138 } 139 } 140 } 141 if (unset_vlan_filtering) { 142 struct switchdev_trans trans; 143 144 trans.ph_prepare = true; 145 err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port), 146 false, &trans); 147 if (err && err != EOPNOTSUPP) 148 return err; 149 150 trans.ph_prepare = false; 151 err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port), 152 false, &trans); 153 if (err && err != EOPNOTSUPP) 154 return err; 155 } 156 return 0; 157 } 158 159 static int dsa_switch_fdb_add(struct dsa_switch *ds, 160 struct dsa_notifier_fdb_info *info) 161 { 162 int port = dsa_towards_port(ds, info->sw_index, info->port); 163 164 if (!ds->ops->port_fdb_add) 165 return -EOPNOTSUPP; 166 167 return ds->ops->port_fdb_add(ds, port, info->addr, info->vid); 168 } 169 170 static int dsa_switch_fdb_del(struct dsa_switch *ds, 171 struct dsa_notifier_fdb_info *info) 172 { 173 int port = dsa_towards_port(ds, info->sw_index, info->port); 174 175 if (!ds->ops->port_fdb_del) 176 return -EOPNOTSUPP; 177 178 return ds->ops->port_fdb_del(ds, port, info->addr, info->vid); 179 } 180 181 static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port, 182 struct dsa_notifier_mdb_info *info) 183 { 184 if (ds->index == info->sw_index && port == info->port) 185 return true; 186 187 if (dsa_is_dsa_port(ds, port)) 188 return true; 189 190 return false; 191 } 192 193 static int dsa_switch_mdb_add(struct dsa_switch *ds, 194 struct dsa_notifier_mdb_info *info) 195 { 196 int port, err; 197 198 if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) 199 return -EOPNOTSUPP; 200 201 for (port = 0; port < ds->num_ports; port++) { 202 if (dsa_switch_mdb_match(ds, port, info)) { 203 err = ds->ops->port_mdb_prepare(ds, port, info->mdb); 204 if (err) 205 return err; 206 } 207 } 208 209 for (port = 0; port < ds->num_ports; port++) 210 if (dsa_switch_mdb_match(ds, port, info)) 211 ds->ops->port_mdb_add(ds, port, info->mdb); 212 213 return 0; 214 } 215 216 static int dsa_switch_mdb_del(struct dsa_switch *ds, 217 struct dsa_notifier_mdb_info *info) 218 { 219 if (!ds->ops->port_mdb_del) 220 return -EOPNOTSUPP; 221 222 if (ds->index == info->sw_index) 223 return ds->ops->port_mdb_del(ds, info->port, info->mdb); 224 225 return 0; 226 } 227 228 static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port, 229 struct dsa_notifier_vlan_info *info) 230 { 231 if (ds->index == info->sw_index && port == info->port) 232 return true; 233 234 if (dsa_is_dsa_port(ds, port)) 235 return true; 236 237 return false; 238 } 239 240 static int dsa_switch_vlan_add(struct dsa_switch *ds, 241 struct dsa_notifier_vlan_info *info) 242 { 243 int port, err; 244 245 if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) 246 return -EOPNOTSUPP; 247 248 for (port = 0; port < ds->num_ports; port++) { 249 if (dsa_switch_vlan_match(ds, port, info)) { 250 err = ds->ops->port_vlan_prepare(ds, port, info->vlan); 251 if (err) 252 return err; 253 } 254 } 255 256 for (port = 0; port < ds->num_ports; port++) 257 if (dsa_switch_vlan_match(ds, port, info)) 258 ds->ops->port_vlan_add(ds, port, info->vlan); 259 260 return 0; 261 } 262 263 static int dsa_switch_vlan_del(struct dsa_switch *ds, 264 struct dsa_notifier_vlan_info *info) 265 { 266 if (!ds->ops->port_vlan_del) 267 return -EOPNOTSUPP; 268 269 if (ds->index == info->sw_index) 270 return ds->ops->port_vlan_del(ds, info->port, info->vlan); 271 272 /* Do not deprogram the DSA links as they may be used as conduit 273 * for other VLAN members in the fabric. 274 */ 275 return 0; 276 } 277 278 static int dsa_switch_event(struct notifier_block *nb, 279 unsigned long event, void *info) 280 { 281 struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb); 282 int err; 283 284 switch (event) { 285 case DSA_NOTIFIER_AGEING_TIME: 286 err = dsa_switch_ageing_time(ds, info); 287 break; 288 case DSA_NOTIFIER_BRIDGE_JOIN: 289 err = dsa_switch_bridge_join(ds, info); 290 break; 291 case DSA_NOTIFIER_BRIDGE_LEAVE: 292 err = dsa_switch_bridge_leave(ds, info); 293 break; 294 case DSA_NOTIFIER_FDB_ADD: 295 err = dsa_switch_fdb_add(ds, info); 296 break; 297 case DSA_NOTIFIER_FDB_DEL: 298 err = dsa_switch_fdb_del(ds, info); 299 break; 300 case DSA_NOTIFIER_MDB_ADD: 301 err = dsa_switch_mdb_add(ds, info); 302 break; 303 case DSA_NOTIFIER_MDB_DEL: 304 err = dsa_switch_mdb_del(ds, info); 305 break; 306 case DSA_NOTIFIER_VLAN_ADD: 307 err = dsa_switch_vlan_add(ds, info); 308 break; 309 case DSA_NOTIFIER_VLAN_DEL: 310 err = dsa_switch_vlan_del(ds, info); 311 break; 312 case DSA_NOTIFIER_MTU: 313 err = dsa_switch_mtu(ds, info); 314 break; 315 default: 316 err = -EOPNOTSUPP; 317 break; 318 } 319 320 /* Non-switchdev operations cannot be rolled back. If a DSA driver 321 * returns an error during the chained call, switch chips may be in an 322 * inconsistent state. 323 */ 324 if (err) 325 dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n", 326 event, err); 327 328 return notifier_from_errno(err); 329 } 330 331 int dsa_switch_register_notifier(struct dsa_switch *ds) 332 { 333 ds->nb.notifier_call = dsa_switch_event; 334 335 return raw_notifier_chain_register(&ds->dst->nh, &ds->nb); 336 } 337 338 void dsa_switch_unregister_notifier(struct dsa_switch *ds) 339 { 340 int err; 341 342 err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb); 343 if (err) 344 dev_err(ds->dev, "failed to unregister notifier (%d)\n", err); 345 } 346