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 = {0}; 143 144 err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port), 145 false, &trans); 146 if (err && err != EOPNOTSUPP) 147 return err; 148 } 149 return 0; 150 } 151 152 static int dsa_switch_fdb_add(struct dsa_switch *ds, 153 struct dsa_notifier_fdb_info *info) 154 { 155 int port = dsa_towards_port(ds, info->sw_index, info->port); 156 157 if (!ds->ops->port_fdb_add) 158 return -EOPNOTSUPP; 159 160 return ds->ops->port_fdb_add(ds, port, info->addr, info->vid); 161 } 162 163 static int dsa_switch_fdb_del(struct dsa_switch *ds, 164 struct dsa_notifier_fdb_info *info) 165 { 166 int port = dsa_towards_port(ds, info->sw_index, info->port); 167 168 if (!ds->ops->port_fdb_del) 169 return -EOPNOTSUPP; 170 171 return ds->ops->port_fdb_del(ds, port, info->addr, info->vid); 172 } 173 174 static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port, 175 struct dsa_notifier_mdb_info *info) 176 { 177 if (ds->index == info->sw_index && port == info->port) 178 return true; 179 180 if (dsa_is_dsa_port(ds, port)) 181 return true; 182 183 return false; 184 } 185 186 static int dsa_switch_mdb_prepare(struct dsa_switch *ds, 187 struct dsa_notifier_mdb_info *info) 188 { 189 int port, err; 190 191 if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) 192 return -EOPNOTSUPP; 193 194 for (port = 0; port < ds->num_ports; port++) { 195 if (dsa_switch_mdb_match(ds, port, info)) { 196 err = ds->ops->port_mdb_prepare(ds, port, info->mdb); 197 if (err) 198 return err; 199 } 200 } 201 202 return 0; 203 } 204 205 static int dsa_switch_mdb_add(struct dsa_switch *ds, 206 struct dsa_notifier_mdb_info *info) 207 { 208 int port; 209 210 if (switchdev_trans_ph_prepare(info->trans)) 211 return dsa_switch_mdb_prepare(ds, info); 212 213 if (!ds->ops->port_mdb_add) 214 return 0; 215 216 for (port = 0; port < ds->num_ports; port++) 217 if (dsa_switch_mdb_match(ds, port, info)) 218 ds->ops->port_mdb_add(ds, port, info->mdb); 219 220 return 0; 221 } 222 223 static int dsa_switch_mdb_del(struct dsa_switch *ds, 224 struct dsa_notifier_mdb_info *info) 225 { 226 if (!ds->ops->port_mdb_del) 227 return -EOPNOTSUPP; 228 229 if (ds->index == info->sw_index) 230 return ds->ops->port_mdb_del(ds, info->port, info->mdb); 231 232 return 0; 233 } 234 235 static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port, 236 struct dsa_notifier_vlan_info *info) 237 { 238 if (ds->index == info->sw_index && port == info->port) 239 return true; 240 241 if (dsa_is_dsa_port(ds, port)) 242 return true; 243 244 return false; 245 } 246 247 static int dsa_switch_vlan_prepare(struct dsa_switch *ds, 248 struct dsa_notifier_vlan_info *info) 249 { 250 int port, err; 251 252 if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) 253 return -EOPNOTSUPP; 254 255 for (port = 0; port < ds->num_ports; port++) { 256 if (dsa_switch_vlan_match(ds, port, info)) { 257 err = ds->ops->port_vlan_prepare(ds, port, info->vlan); 258 if (err) 259 return err; 260 } 261 } 262 263 return 0; 264 } 265 266 static int dsa_switch_vlan_add(struct dsa_switch *ds, 267 struct dsa_notifier_vlan_info *info) 268 { 269 int port; 270 271 if (switchdev_trans_ph_prepare(info->trans)) 272 return dsa_switch_vlan_prepare(ds, info); 273 274 if (!ds->ops->port_vlan_add) 275 return 0; 276 277 for (port = 0; port < ds->num_ports; port++) 278 if (dsa_switch_vlan_match(ds, port, info)) 279 ds->ops->port_vlan_add(ds, port, info->vlan); 280 281 return 0; 282 } 283 284 static int dsa_switch_vlan_del(struct dsa_switch *ds, 285 struct dsa_notifier_vlan_info *info) 286 { 287 if (!ds->ops->port_vlan_del) 288 return -EOPNOTSUPP; 289 290 if (ds->index == info->sw_index) 291 return ds->ops->port_vlan_del(ds, info->port, info->vlan); 292 293 /* Do not deprogram the DSA links as they may be used as conduit 294 * for other VLAN members in the fabric. 295 */ 296 return 0; 297 } 298 299 static int dsa_switch_event(struct notifier_block *nb, 300 unsigned long event, void *info) 301 { 302 struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb); 303 int err; 304 305 switch (event) { 306 case DSA_NOTIFIER_AGEING_TIME: 307 err = dsa_switch_ageing_time(ds, info); 308 break; 309 case DSA_NOTIFIER_BRIDGE_JOIN: 310 err = dsa_switch_bridge_join(ds, info); 311 break; 312 case DSA_NOTIFIER_BRIDGE_LEAVE: 313 err = dsa_switch_bridge_leave(ds, info); 314 break; 315 case DSA_NOTIFIER_FDB_ADD: 316 err = dsa_switch_fdb_add(ds, info); 317 break; 318 case DSA_NOTIFIER_FDB_DEL: 319 err = dsa_switch_fdb_del(ds, info); 320 break; 321 case DSA_NOTIFIER_MDB_ADD: 322 err = dsa_switch_mdb_add(ds, info); 323 break; 324 case DSA_NOTIFIER_MDB_DEL: 325 err = dsa_switch_mdb_del(ds, info); 326 break; 327 case DSA_NOTIFIER_VLAN_ADD: 328 err = dsa_switch_vlan_add(ds, info); 329 break; 330 case DSA_NOTIFIER_VLAN_DEL: 331 err = dsa_switch_vlan_del(ds, info); 332 break; 333 case DSA_NOTIFIER_MTU: 334 err = dsa_switch_mtu(ds, info); 335 break; 336 default: 337 err = -EOPNOTSUPP; 338 break; 339 } 340 341 /* Non-switchdev operations cannot be rolled back. If a DSA driver 342 * returns an error during the chained call, switch chips may be in an 343 * inconsistent state. 344 */ 345 if (err) 346 dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n", 347 event, err); 348 349 return notifier_from_errno(err); 350 } 351 352 int dsa_switch_register_notifier(struct dsa_switch *ds) 353 { 354 ds->nb.notifier_call = dsa_switch_event; 355 356 return raw_notifier_chain_register(&ds->dst->nh, &ds->nb); 357 } 358 359 void dsa_switch_unregister_notifier(struct dsa_switch *ds) 360 { 361 int err; 362 363 err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb); 364 if (err) 365 dev_err(ds->dev, "failed to unregister notifier (%d)\n", err); 366 } 367