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 <vivien.didelot@savoirfairelinux.com> 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_prepare(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 return 0; 210 } 211 212 static int dsa_switch_mdb_add(struct dsa_switch *ds, 213 struct dsa_notifier_mdb_info *info) 214 { 215 int port; 216 217 if (switchdev_trans_ph_prepare(info->trans)) 218 return dsa_switch_mdb_prepare(ds, info); 219 220 if (!ds->ops->port_mdb_add) 221 return 0; 222 223 for (port = 0; port < ds->num_ports; port++) 224 if (dsa_switch_mdb_match(ds, port, info)) 225 ds->ops->port_mdb_add(ds, port, info->mdb); 226 227 return 0; 228 } 229 230 static int dsa_switch_mdb_del(struct dsa_switch *ds, 231 struct dsa_notifier_mdb_info *info) 232 { 233 if (!ds->ops->port_mdb_del) 234 return -EOPNOTSUPP; 235 236 if (ds->index == info->sw_index) 237 return ds->ops->port_mdb_del(ds, info->port, info->mdb); 238 239 return 0; 240 } 241 242 static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port, 243 struct dsa_notifier_vlan_info *info) 244 { 245 if (ds->index == info->sw_index && port == info->port) 246 return true; 247 248 if (dsa_is_dsa_port(ds, port)) 249 return true; 250 251 return false; 252 } 253 254 static int dsa_switch_vlan_prepare(struct dsa_switch *ds, 255 struct dsa_notifier_vlan_info *info) 256 { 257 int port, err; 258 259 if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) 260 return -EOPNOTSUPP; 261 262 for (port = 0; port < ds->num_ports; port++) { 263 if (dsa_switch_vlan_match(ds, port, info)) { 264 err = ds->ops->port_vlan_prepare(ds, port, info->vlan); 265 if (err) 266 return err; 267 } 268 } 269 270 return 0; 271 } 272 273 static int dsa_switch_vlan_add(struct dsa_switch *ds, 274 struct dsa_notifier_vlan_info *info) 275 { 276 int port; 277 278 if (switchdev_trans_ph_prepare(info->trans)) 279 return dsa_switch_vlan_prepare(ds, info); 280 281 if (!ds->ops->port_vlan_add) 282 return 0; 283 284 for (port = 0; port < ds->num_ports; port++) 285 if (dsa_switch_vlan_match(ds, port, info)) 286 ds->ops->port_vlan_add(ds, port, info->vlan); 287 288 return 0; 289 } 290 291 static int dsa_switch_vlan_del(struct dsa_switch *ds, 292 struct dsa_notifier_vlan_info *info) 293 { 294 if (!ds->ops->port_vlan_del) 295 return -EOPNOTSUPP; 296 297 if (ds->index == info->sw_index) 298 return ds->ops->port_vlan_del(ds, info->port, info->vlan); 299 300 /* Do not deprogram the DSA links as they may be used as conduit 301 * for other VLAN members in the fabric. 302 */ 303 return 0; 304 } 305 306 static int dsa_switch_event(struct notifier_block *nb, 307 unsigned long event, void *info) 308 { 309 struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb); 310 int err; 311 312 switch (event) { 313 case DSA_NOTIFIER_AGEING_TIME: 314 err = dsa_switch_ageing_time(ds, info); 315 break; 316 case DSA_NOTIFIER_BRIDGE_JOIN: 317 err = dsa_switch_bridge_join(ds, info); 318 break; 319 case DSA_NOTIFIER_BRIDGE_LEAVE: 320 err = dsa_switch_bridge_leave(ds, info); 321 break; 322 case DSA_NOTIFIER_FDB_ADD: 323 err = dsa_switch_fdb_add(ds, info); 324 break; 325 case DSA_NOTIFIER_FDB_DEL: 326 err = dsa_switch_fdb_del(ds, info); 327 break; 328 case DSA_NOTIFIER_MDB_ADD: 329 err = dsa_switch_mdb_add(ds, info); 330 break; 331 case DSA_NOTIFIER_MDB_DEL: 332 err = dsa_switch_mdb_del(ds, info); 333 break; 334 case DSA_NOTIFIER_VLAN_ADD: 335 err = dsa_switch_vlan_add(ds, info); 336 break; 337 case DSA_NOTIFIER_VLAN_DEL: 338 err = dsa_switch_vlan_del(ds, info); 339 break; 340 case DSA_NOTIFIER_MTU: 341 err = dsa_switch_mtu(ds, info); 342 break; 343 default: 344 err = -EOPNOTSUPP; 345 break; 346 } 347 348 /* Non-switchdev operations cannot be rolled back. If a DSA driver 349 * returns an error during the chained call, switch chips may be in an 350 * inconsistent state. 351 */ 352 if (err) 353 dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n", 354 event, err); 355 356 return notifier_from_errno(err); 357 } 358 359 int dsa_switch_register_notifier(struct dsa_switch *ds) 360 { 361 ds->nb.notifier_call = dsa_switch_event; 362 363 return raw_notifier_chain_register(&ds->dst->nh, &ds->nb); 364 } 365 366 void dsa_switch_unregister_notifier(struct dsa_switch *ds) 367 { 368 int err; 369 370 err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb); 371 if (err) 372 dev_err(ds->dev, "failed to unregister notifier (%d)\n", err); 373 } 374