1 // SPDX-License-Identifier: GPL-2.0 2 3 /* Texas Instruments K3 ICSSG Ethernet Switchdev Driver 4 * 5 * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/ 6 * 7 */ 8 9 #include <linux/etherdevice.h> 10 #include <linux/if_bridge.h> 11 #include <linux/netdevice.h> 12 #include <linux/workqueue.h> 13 #include <net/switchdev.h> 14 15 #include "icssg_prueth.h" 16 #include "icssg_switchdev.h" 17 #include "icssg_mii_rt.h" 18 19 struct prueth_switchdev_event_work { 20 struct work_struct work; 21 struct switchdev_notifier_fdb_info fdb_info; 22 struct prueth_emac *emac; 23 unsigned long event; 24 }; 25 26 static int prueth_switchdev_stp_state_set(struct prueth_emac *emac, 27 u8 state) 28 { 29 enum icssg_port_state_cmd emac_state; 30 int ret = 0; 31 32 switch (state) { 33 case BR_STATE_FORWARDING: 34 emac_state = ICSSG_EMAC_PORT_FORWARD; 35 break; 36 case BR_STATE_DISABLED: 37 emac_state = ICSSG_EMAC_PORT_DISABLE; 38 break; 39 case BR_STATE_LISTENING: 40 case BR_STATE_BLOCKING: 41 emac_state = ICSSG_EMAC_PORT_BLOCK; 42 break; 43 default: 44 return -EOPNOTSUPP; 45 } 46 47 icssg_set_port_state(emac, emac_state); 48 netdev_dbg(emac->ndev, "STP state: %u\n", emac_state); 49 50 return ret; 51 } 52 53 static int prueth_switchdev_attr_br_flags_set(struct prueth_emac *emac, 54 struct net_device *orig_dev, 55 struct switchdev_brport_flags brport_flags) 56 { 57 enum icssg_port_state_cmd emac_state; 58 59 if (brport_flags.mask & BR_MCAST_FLOOD) 60 emac_state = ICSSG_EMAC_PORT_MC_FLOODING_ENABLE; 61 else 62 emac_state = ICSSG_EMAC_PORT_MC_FLOODING_DISABLE; 63 64 netdev_dbg(emac->ndev, "BR_MCAST_FLOOD: %d port %u\n", 65 emac_state, emac->port_id); 66 67 icssg_set_port_state(emac, emac_state); 68 69 return 0; 70 } 71 72 static int prueth_switchdev_attr_br_flags_pre_set(struct net_device *netdev, 73 struct switchdev_brport_flags brport_flags) 74 { 75 if (brport_flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD)) 76 return -EINVAL; 77 78 return 0; 79 } 80 81 static int prueth_switchdev_attr_set(struct net_device *ndev, const void *ctx, 82 const struct switchdev_attr *attr, 83 struct netlink_ext_ack *extack) 84 { 85 struct prueth_emac *emac = netdev_priv(ndev); 86 int ret; 87 88 netdev_dbg(ndev, "attr: id %u port: %u\n", attr->id, emac->port_id); 89 90 switch (attr->id) { 91 case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: 92 ret = prueth_switchdev_attr_br_flags_pre_set(ndev, 93 attr->u.brport_flags); 94 break; 95 case SWITCHDEV_ATTR_ID_PORT_STP_STATE: 96 ret = prueth_switchdev_stp_state_set(emac, 97 attr->u.stp_state); 98 netdev_dbg(ndev, "stp state: %u\n", attr->u.stp_state); 99 break; 100 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: 101 ret = prueth_switchdev_attr_br_flags_set(emac, attr->orig_dev, 102 attr->u.brport_flags); 103 break; 104 default: 105 ret = -EOPNOTSUPP; 106 break; 107 } 108 109 return ret; 110 } 111 112 static void prueth_switchdev_fdb_offload_notify(struct net_device *ndev, 113 struct switchdev_notifier_fdb_info *rcv) 114 { 115 struct switchdev_notifier_fdb_info info; 116 117 memset(&info, 0, sizeof(info)); 118 info.addr = rcv->addr; 119 info.vid = rcv->vid; 120 info.offloaded = true; 121 call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, 122 ndev, &info.info, NULL); 123 } 124 125 static void prueth_switchdev_event_work(struct work_struct *work) 126 { 127 struct prueth_switchdev_event_work *switchdev_work = 128 container_of(work, struct prueth_switchdev_event_work, work); 129 struct prueth_emac *emac = switchdev_work->emac; 130 struct switchdev_notifier_fdb_info *fdb; 131 int port_id = emac->port_id; 132 int ret; 133 134 rtnl_lock(); 135 switch (switchdev_work->event) { 136 case SWITCHDEV_FDB_ADD_TO_DEVICE: 137 fdb = &switchdev_work->fdb_info; 138 139 netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n", 140 fdb->addr, fdb->vid, fdb->added_by_user, 141 fdb->offloaded, port_id); 142 143 if (!fdb->added_by_user) 144 break; 145 if (!ether_addr_equal(emac->mac_addr, fdb->addr)) 146 break; 147 148 ret = icssg_fdb_add_del(emac, fdb->addr, fdb->vid, 149 BIT(port_id), true); 150 if (!ret) 151 prueth_switchdev_fdb_offload_notify(emac->ndev, fdb); 152 break; 153 case SWITCHDEV_FDB_DEL_TO_DEVICE: 154 fdb = &switchdev_work->fdb_info; 155 156 netdev_dbg(emac->ndev, "prueth_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n", 157 fdb->addr, fdb->vid, fdb->added_by_user, 158 fdb->offloaded, port_id); 159 160 if (!fdb->added_by_user) 161 break; 162 if (!ether_addr_equal(emac->mac_addr, fdb->addr)) 163 break; 164 icssg_fdb_add_del(emac, fdb->addr, fdb->vid, 165 BIT(port_id), false); 166 break; 167 default: 168 break; 169 } 170 rtnl_unlock(); 171 172 kfree(switchdev_work->fdb_info.addr); 173 kfree(switchdev_work); 174 dev_put(emac->ndev); 175 } 176 177 static int prueth_switchdev_event(struct notifier_block *unused, 178 unsigned long event, void *ptr) 179 { 180 struct net_device *ndev = switchdev_notifier_info_to_dev(ptr); 181 struct prueth_switchdev_event_work *switchdev_work; 182 struct switchdev_notifier_fdb_info *fdb_info = ptr; 183 struct prueth_emac *emac = netdev_priv(ndev); 184 int err; 185 186 if (!prueth_dev_check(ndev)) 187 return NOTIFY_DONE; 188 189 if (event == SWITCHDEV_PORT_ATTR_SET) { 190 err = switchdev_handle_port_attr_set(ndev, ptr, 191 prueth_dev_check, 192 prueth_switchdev_attr_set); 193 return notifier_from_errno(err); 194 } 195 196 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); 197 if (WARN_ON(!switchdev_work)) 198 return NOTIFY_BAD; 199 200 INIT_WORK(&switchdev_work->work, prueth_switchdev_event_work); 201 switchdev_work->emac = emac; 202 switchdev_work->event = event; 203 204 switch (event) { 205 case SWITCHDEV_FDB_ADD_TO_DEVICE: 206 case SWITCHDEV_FDB_DEL_TO_DEVICE: 207 memcpy(&switchdev_work->fdb_info, ptr, 208 sizeof(switchdev_work->fdb_info)); 209 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); 210 if (!switchdev_work->fdb_info.addr) 211 goto err_addr_alloc; 212 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, 213 fdb_info->addr); 214 dev_hold(ndev); 215 break; 216 default: 217 kfree(switchdev_work); 218 return NOTIFY_DONE; 219 } 220 221 queue_work(system_long_wq, &switchdev_work->work); 222 223 return NOTIFY_DONE; 224 225 err_addr_alloc: 226 kfree(switchdev_work); 227 return NOTIFY_BAD; 228 } 229 230 static int prueth_switchdev_vlan_add(struct prueth_emac *emac, bool untag, bool pvid, 231 u8 vid, struct net_device *orig_dev) 232 { 233 bool cpu_port = netif_is_bridge_master(orig_dev); 234 int untag_mask = 0; 235 int port_mask; 236 int ret = 0; 237 238 if (cpu_port) 239 port_mask = BIT(PRUETH_PORT_HOST); 240 else 241 port_mask = BIT(emac->port_id); 242 243 if (untag) 244 untag_mask = port_mask; 245 246 icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true); 247 248 netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X PVID %d\n", 249 vid, port_mask, untag_mask, pvid); 250 251 if (!pvid) 252 return ret; 253 254 icssg_set_pvid(emac->prueth, vid, emac->port_id); 255 256 return ret; 257 } 258 259 static int prueth_switchdev_vlan_del(struct prueth_emac *emac, u16 vid, 260 struct net_device *orig_dev) 261 { 262 bool cpu_port = netif_is_bridge_master(orig_dev); 263 int port_mask; 264 int ret = 0; 265 266 if (cpu_port) 267 port_mask = BIT(PRUETH_PORT_HOST); 268 else 269 port_mask = BIT(emac->port_id); 270 271 icssg_vtbl_modify(emac, vid, port_mask, 0, false); 272 273 if (cpu_port) 274 icssg_fdb_add_del(emac, emac->mac_addr, vid, 275 BIT(PRUETH_PORT_HOST), false); 276 277 if (vid == icssg_get_pvid(emac)) 278 icssg_set_pvid(emac->prueth, 0, emac->port_id); 279 280 netdev_dbg(emac->ndev, "VID del vid:%u port_mask:%X\n", 281 vid, port_mask); 282 283 return ret; 284 } 285 286 static int prueth_switchdev_vlans_add(struct prueth_emac *emac, 287 const struct switchdev_obj_port_vlan *vlan) 288 { 289 bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 290 struct net_device *orig_dev = vlan->obj.orig_dev; 291 bool cpu_port = netif_is_bridge_master(orig_dev); 292 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 293 294 netdev_dbg(emac->ndev, "VID add vid:%u flags:%X\n", 295 vlan->vid, vlan->flags); 296 297 if (cpu_port && !(vlan->flags & BRIDGE_VLAN_INFO_BRENTRY)) 298 return 0; 299 300 if (vlan->vid > 0xff) 301 return 0; 302 303 return prueth_switchdev_vlan_add(emac, untag, pvid, vlan->vid, 304 orig_dev); 305 } 306 307 static int prueth_switchdev_vlans_del(struct prueth_emac *emac, 308 const struct switchdev_obj_port_vlan *vlan) 309 { 310 if (vlan->vid > 0xff) 311 return 0; 312 313 return prueth_switchdev_vlan_del(emac, vlan->vid, 314 vlan->obj.orig_dev); 315 } 316 317 static int prueth_switchdev_mdb_add(struct prueth_emac *emac, 318 struct switchdev_obj_port_mdb *mdb) 319 { 320 struct net_device *orig_dev = mdb->obj.orig_dev; 321 u8 port_mask, fid_c2; 322 bool cpu_port; 323 int err; 324 325 cpu_port = netif_is_bridge_master(orig_dev); 326 327 if (cpu_port) 328 port_mask = BIT(PRUETH_PORT_HOST); 329 else 330 port_mask = BIT(emac->port_id); 331 332 fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid); 333 334 err = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 | port_mask, true); 335 netdev_dbg(emac->ndev, "MDB add vid %u:%pM ports: %X\n", 336 mdb->vid, mdb->addr, port_mask); 337 338 return err; 339 } 340 341 static int prueth_switchdev_mdb_del(struct prueth_emac *emac, 342 struct switchdev_obj_port_mdb *mdb) 343 { 344 struct net_device *orig_dev = mdb->obj.orig_dev; 345 int del_mask, ret, fid_c2; 346 bool cpu_port; 347 348 cpu_port = netif_is_bridge_master(orig_dev); 349 350 if (cpu_port) 351 del_mask = BIT(PRUETH_PORT_HOST); 352 else 353 del_mask = BIT(emac->port_id); 354 355 fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid); 356 357 if (fid_c2 & ~del_mask) 358 ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 & ~del_mask, true); 359 else 360 ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, 0, false); 361 362 netdev_dbg(emac->ndev, "MDB del vid %u:%pM ports: %X\n", 363 mdb->vid, mdb->addr, del_mask); 364 365 return ret; 366 } 367 368 static int prueth_switchdev_obj_add(struct net_device *ndev, const void *ctx, 369 const struct switchdev_obj *obj, 370 struct netlink_ext_ack *extack) 371 { 372 struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 373 struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); 374 struct prueth_emac *emac = netdev_priv(ndev); 375 int err = 0; 376 377 netdev_dbg(ndev, "obj_add: id %u port: %u\n", obj->id, emac->port_id); 378 379 switch (obj->id) { 380 case SWITCHDEV_OBJ_ID_PORT_VLAN: 381 err = prueth_switchdev_vlans_add(emac, vlan); 382 break; 383 case SWITCHDEV_OBJ_ID_PORT_MDB: 384 case SWITCHDEV_OBJ_ID_HOST_MDB: 385 err = prueth_switchdev_mdb_add(emac, mdb); 386 break; 387 default: 388 err = -EOPNOTSUPP; 389 break; 390 } 391 392 return err; 393 } 394 395 static int prueth_switchdev_obj_del(struct net_device *ndev, const void *ctx, 396 const struct switchdev_obj *obj) 397 { 398 struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 399 struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); 400 struct prueth_emac *emac = netdev_priv(ndev); 401 int err = 0; 402 403 netdev_dbg(ndev, "obj_del: id %u port: %u\n", obj->id, emac->port_id); 404 405 switch (obj->id) { 406 case SWITCHDEV_OBJ_ID_PORT_VLAN: 407 err = prueth_switchdev_vlans_del(emac, vlan); 408 break; 409 case SWITCHDEV_OBJ_ID_PORT_MDB: 410 case SWITCHDEV_OBJ_ID_HOST_MDB: 411 err = prueth_switchdev_mdb_del(emac, mdb); 412 break; 413 default: 414 err = -EOPNOTSUPP; 415 break; 416 } 417 418 return err; 419 } 420 421 static int prueth_switchdev_blocking_event(struct notifier_block *unused, 422 unsigned long event, void *ptr) 423 { 424 struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 425 int err; 426 427 switch (event) { 428 case SWITCHDEV_PORT_OBJ_ADD: 429 err = switchdev_handle_port_obj_add(dev, ptr, 430 prueth_dev_check, 431 prueth_switchdev_obj_add); 432 return notifier_from_errno(err); 433 case SWITCHDEV_PORT_OBJ_DEL: 434 err = switchdev_handle_port_obj_del(dev, ptr, 435 prueth_dev_check, 436 prueth_switchdev_obj_del); 437 return notifier_from_errno(err); 438 case SWITCHDEV_PORT_ATTR_SET: 439 err = switchdev_handle_port_attr_set(dev, ptr, 440 prueth_dev_check, 441 prueth_switchdev_attr_set); 442 return notifier_from_errno(err); 443 default: 444 break; 445 } 446 447 return NOTIFY_DONE; 448 } 449 450 int prueth_switchdev_register_notifiers(struct prueth *prueth) 451 { 452 int ret = 0; 453 454 prueth->prueth_switchdev_nb.notifier_call = &prueth_switchdev_event; 455 ret = register_switchdev_notifier(&prueth->prueth_switchdev_nb); 456 if (ret) { 457 dev_err(prueth->dev, "register switchdev notifier fail ret:%d\n", 458 ret); 459 return ret; 460 } 461 462 prueth->prueth_switchdev_bl_nb.notifier_call = &prueth_switchdev_blocking_event; 463 ret = register_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb); 464 if (ret) { 465 dev_err(prueth->dev, "register switchdev blocking notifier ret:%d\n", 466 ret); 467 unregister_switchdev_notifier(&prueth->prueth_switchdev_nb); 468 } 469 470 return ret; 471 } 472 473 void prueth_switchdev_unregister_notifiers(struct prueth *prueth) 474 { 475 unregister_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb); 476 unregister_switchdev_notifier(&prueth->prueth_switchdev_nb); 477 } 478