linux/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/* Microchip Sparx5 Switch driver
   3 *
   4 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
   5 */
   6
   7#include <linux/if_bridge.h>
   8#include <net/switchdev.h>
   9
  10#include "sparx5_main_regs.h"
  11#include "sparx5_main.h"
  12
  13static struct workqueue_struct *sparx5_owq;
  14
  15struct sparx5_switchdev_event_work {
  16        struct work_struct work;
  17        struct switchdev_notifier_fdb_info fdb_info;
  18        struct net_device *dev;
  19        unsigned long event;
  20};
  21
  22static void sparx5_port_attr_bridge_flags(struct sparx5_port *port,
  23                                          struct switchdev_brport_flags flags)
  24{
  25        if (flags.mask & BR_MCAST_FLOOD)
  26                sparx5_pgid_update_mask(port, PGID_MC_FLOOD, true);
  27}
  28
  29static void sparx5_attr_stp_state_set(struct sparx5_port *port,
  30                                      u8 state)
  31{
  32        struct sparx5 *sparx5 = port->sparx5;
  33
  34        if (!test_bit(port->portno, sparx5->bridge_mask)) {
  35                netdev_err(port->ndev,
  36                           "Controlling non-bridged port %d?\n", port->portno);
  37                return;
  38        }
  39
  40        switch (state) {
  41        case BR_STATE_FORWARDING:
  42                set_bit(port->portno, sparx5->bridge_fwd_mask);
  43                fallthrough;
  44        case BR_STATE_LEARNING:
  45                set_bit(port->portno, sparx5->bridge_lrn_mask);
  46                break;
  47
  48        default:
  49                /* All other states treated as blocking */
  50                clear_bit(port->portno, sparx5->bridge_fwd_mask);
  51                clear_bit(port->portno, sparx5->bridge_lrn_mask);
  52                break;
  53        }
  54
  55        /* apply the bridge_fwd_mask to all the ports */
  56        sparx5_update_fwd(sparx5);
  57}
  58
  59static void sparx5_port_attr_ageing_set(struct sparx5_port *port,
  60                                        unsigned long ageing_clock_t)
  61{
  62        unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
  63        u32 ageing_time = jiffies_to_msecs(ageing_jiffies);
  64
  65        sparx5_set_ageing(port->sparx5, ageing_time);
  66}
  67
  68static int sparx5_port_attr_set(struct net_device *dev, const void *ctx,
  69                                const struct switchdev_attr *attr,
  70                                struct netlink_ext_ack *extack)
  71{
  72        struct sparx5_port *port = netdev_priv(dev);
  73
  74        switch (attr->id) {
  75        case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
  76                sparx5_port_attr_bridge_flags(port, attr->u.brport_flags);
  77                break;
  78        case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
  79                sparx5_attr_stp_state_set(port, attr->u.stp_state);
  80                break;
  81        case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
  82                sparx5_port_attr_ageing_set(port, attr->u.ageing_time);
  83                break;
  84        case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
  85                port->vlan_aware = attr->u.vlan_filtering;
  86                sparx5_vlan_port_apply(port->sparx5, port);
  87                break;
  88        default:
  89                return -EOPNOTSUPP;
  90        }
  91
  92        return 0;
  93}
  94
  95static int sparx5_port_bridge_join(struct sparx5_port *port,
  96                                   struct net_device *bridge,
  97                                   struct netlink_ext_ack *extack)
  98{
  99        struct sparx5 *sparx5 = port->sparx5;
 100        struct net_device *ndev = port->ndev;
 101        int err;
 102
 103        if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
 104                /* First bridged port */
 105                sparx5->hw_bridge_dev = bridge;
 106        else
 107                if (sparx5->hw_bridge_dev != bridge)
 108                        /* This is adding the port to a second bridge, this is
 109                         * unsupported
 110                         */
 111                        return -ENODEV;
 112
 113        set_bit(port->portno, sparx5->bridge_mask);
 114
 115        err = switchdev_bridge_port_offload(ndev, ndev, NULL, NULL, NULL,
 116                                            false, extack);
 117        if (err)
 118                goto err_switchdev_offload;
 119
 120        /* Port enters in bridge mode therefor don't need to copy to CPU
 121         * frames for multicast in case the bridge is not requesting them
 122         */
 123        __dev_mc_unsync(ndev, sparx5_mc_unsync);
 124
 125        return 0;
 126
 127err_switchdev_offload:
 128        clear_bit(port->portno, sparx5->bridge_mask);
 129        return err;
 130}
 131
 132static void sparx5_port_bridge_leave(struct sparx5_port *port,
 133                                     struct net_device *bridge)
 134{
 135        struct sparx5 *sparx5 = port->sparx5;
 136
 137        switchdev_bridge_port_unoffload(port->ndev, NULL, NULL, NULL);
 138
 139        clear_bit(port->portno, sparx5->bridge_mask);
 140        if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
 141                sparx5->hw_bridge_dev = NULL;
 142
 143        /* Clear bridge vlan settings before updating the port settings */
 144        port->vlan_aware = 0;
 145        port->pvid = NULL_VID;
 146        port->vid = NULL_VID;
 147
 148        /* Port enters in host more therefore restore mc list */
 149        __dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync);
 150}
 151
 152static int sparx5_port_changeupper(struct net_device *dev,
 153                                   struct netdev_notifier_changeupper_info *info)
 154{
 155        struct sparx5_port *port = netdev_priv(dev);
 156        struct netlink_ext_ack *extack;
 157        int err = 0;
 158
 159        extack = netdev_notifier_info_to_extack(&info->info);
 160
 161        if (netif_is_bridge_master(info->upper_dev)) {
 162                if (info->linking)
 163                        err = sparx5_port_bridge_join(port, info->upper_dev,
 164                                                      extack);
 165                else
 166                        sparx5_port_bridge_leave(port, info->upper_dev);
 167
 168                sparx5_vlan_port_apply(port->sparx5, port);
 169        }
 170
 171        return err;
 172}
 173
 174static int sparx5_port_add_addr(struct net_device *dev, bool up)
 175{
 176        struct sparx5_port *port = netdev_priv(dev);
 177        struct sparx5 *sparx5 = port->sparx5;
 178        u16 vid = port->pvid;
 179
 180        if (up)
 181                sparx5_mact_learn(sparx5, PGID_CPU, port->ndev->dev_addr, vid);
 182        else
 183                sparx5_mact_forget(sparx5, port->ndev->dev_addr, vid);
 184
 185        return 0;
 186}
 187
 188static int sparx5_netdevice_port_event(struct net_device *dev,
 189                                       struct notifier_block *nb,
 190                                       unsigned long event, void *ptr)
 191{
 192        int err = 0;
 193
 194        if (!sparx5_netdevice_check(dev))
 195                return 0;
 196
 197        switch (event) {
 198        case NETDEV_CHANGEUPPER:
 199                err = sparx5_port_changeupper(dev, ptr);
 200                break;
 201        case NETDEV_PRE_UP:
 202                err = sparx5_port_add_addr(dev, true);
 203                break;
 204        case NETDEV_DOWN:
 205                err = sparx5_port_add_addr(dev, false);
 206                break;
 207        }
 208
 209        return err;
 210}
 211
 212static int sparx5_netdevice_event(struct notifier_block *nb,
 213                                  unsigned long event, void *ptr)
 214{
 215        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 216        int ret = 0;
 217
 218        ret = sparx5_netdevice_port_event(dev, nb, event, ptr);
 219
 220        return notifier_from_errno(ret);
 221}
 222
 223static void sparx5_switchdev_bridge_fdb_event_work(struct work_struct *work)
 224{
 225        struct sparx5_switchdev_event_work *switchdev_work =
 226                container_of(work, struct sparx5_switchdev_event_work, work);
 227        struct net_device *dev = switchdev_work->dev;
 228        struct switchdev_notifier_fdb_info *fdb_info;
 229        struct sparx5_port *port;
 230        struct sparx5 *sparx5;
 231
 232        rtnl_lock();
 233        if (!sparx5_netdevice_check(dev))
 234                goto out;
 235
 236        port = netdev_priv(dev);
 237        sparx5 = port->sparx5;
 238
 239        fdb_info = &switchdev_work->fdb_info;
 240
 241        switch (switchdev_work->event) {
 242        case SWITCHDEV_FDB_ADD_TO_DEVICE:
 243                if (!fdb_info->added_by_user)
 244                        break;
 245                sparx5_add_mact_entry(sparx5, port, fdb_info->addr,
 246                                      fdb_info->vid);
 247                break;
 248        case SWITCHDEV_FDB_DEL_TO_DEVICE:
 249                if (!fdb_info->added_by_user)
 250                        break;
 251                sparx5_del_mact_entry(sparx5, fdb_info->addr, fdb_info->vid);
 252                break;
 253        }
 254
 255out:
 256        rtnl_unlock();
 257        kfree(switchdev_work->fdb_info.addr);
 258        kfree(switchdev_work);
 259        dev_put(dev);
 260}
 261
 262static void sparx5_schedule_work(struct work_struct *work)
 263{
 264        queue_work(sparx5_owq, work);
 265}
 266
 267static int sparx5_switchdev_event(struct notifier_block *unused,
 268                                  unsigned long event, void *ptr)
 269{
 270        struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
 271        struct sparx5_switchdev_event_work *switchdev_work;
 272        struct switchdev_notifier_fdb_info *fdb_info;
 273        struct switchdev_notifier_info *info = ptr;
 274        int err;
 275
 276        switch (event) {
 277        case SWITCHDEV_PORT_ATTR_SET:
 278                err = switchdev_handle_port_attr_set(dev, ptr,
 279                                                     sparx5_netdevice_check,
 280                                                     sparx5_port_attr_set);
 281                return notifier_from_errno(err);
 282        case SWITCHDEV_FDB_ADD_TO_DEVICE:
 283                fallthrough;
 284        case SWITCHDEV_FDB_DEL_TO_DEVICE:
 285                switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
 286                if (!switchdev_work)
 287                        return NOTIFY_BAD;
 288
 289                switchdev_work->dev = dev;
 290                switchdev_work->event = event;
 291
 292                fdb_info = container_of(info,
 293                                        struct switchdev_notifier_fdb_info,
 294                                        info);
 295                INIT_WORK(&switchdev_work->work,
 296                          sparx5_switchdev_bridge_fdb_event_work);
 297                memcpy(&switchdev_work->fdb_info, ptr,
 298                       sizeof(switchdev_work->fdb_info));
 299                switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
 300                if (!switchdev_work->fdb_info.addr)
 301                        goto err_addr_alloc;
 302
 303                ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
 304                                fdb_info->addr);
 305                dev_hold(dev);
 306
 307                sparx5_schedule_work(&switchdev_work->work);
 308                break;
 309        }
 310
 311        return NOTIFY_DONE;
 312err_addr_alloc:
 313        kfree(switchdev_work);
 314        return NOTIFY_BAD;
 315}
 316
 317static void sparx5_sync_port_dev_addr(struct sparx5 *sparx5,
 318                                      struct sparx5_port *port,
 319                                      u16 vid, bool add)
 320{
 321        if (!port ||
 322            !test_bit(port->portno, sparx5->bridge_mask))
 323                return; /* Skip null/host interfaces */
 324
 325        /* Bridge connects to vid? */
 326        if (add) {
 327                /* Add port MAC address from the VLAN */
 328                sparx5_mact_learn(sparx5, PGID_CPU,
 329                                  port->ndev->dev_addr, vid);
 330        } else {
 331                /* Control port addr visibility depending on
 332                 * port VLAN connectivity.
 333                 */
 334                if (test_bit(port->portno, sparx5->vlan_mask[vid]))
 335                        sparx5_mact_learn(sparx5, PGID_CPU,
 336                                          port->ndev->dev_addr, vid);
 337                else
 338                        sparx5_mact_forget(sparx5,
 339                                           port->ndev->dev_addr, vid);
 340        }
 341}
 342
 343static void sparx5_sync_bridge_dev_addr(struct net_device *dev,
 344                                        struct sparx5 *sparx5,
 345                                        u16 vid, bool add)
 346{
 347        int i;
 348
 349        /* First, handle bridge address'es */
 350        if (add) {
 351                sparx5_mact_learn(sparx5, PGID_CPU, dev->dev_addr,
 352                                  vid);
 353                sparx5_mact_learn(sparx5, PGID_BCAST, dev->broadcast,
 354                                  vid);
 355        } else {
 356                sparx5_mact_forget(sparx5, dev->dev_addr, vid);
 357                sparx5_mact_forget(sparx5, dev->broadcast, vid);
 358        }
 359
 360        /* Now look at bridged ports */
 361        for (i = 0; i < SPX5_PORTS; i++)
 362                sparx5_sync_port_dev_addr(sparx5, sparx5->ports[i], vid, add);
 363}
 364
 365static int sparx5_handle_port_vlan_add(struct net_device *dev,
 366                                       struct notifier_block *nb,
 367                                       const struct switchdev_obj_port_vlan *v)
 368{
 369        struct sparx5_port *port = netdev_priv(dev);
 370
 371        if (netif_is_bridge_master(dev)) {
 372                if (v->flags & BRIDGE_VLAN_INFO_BRENTRY) {
 373                        struct sparx5 *sparx5 =
 374                                container_of(nb, struct sparx5,
 375                                             switchdev_blocking_nb);
 376
 377                        sparx5_sync_bridge_dev_addr(dev, sparx5, v->vid, true);
 378                }
 379                return 0;
 380        }
 381
 382        if (!sparx5_netdevice_check(dev))
 383                return -EOPNOTSUPP;
 384
 385        return sparx5_vlan_vid_add(port, v->vid,
 386                                  v->flags & BRIDGE_VLAN_INFO_PVID,
 387                                  v->flags & BRIDGE_VLAN_INFO_UNTAGGED);
 388}
 389
 390static int sparx5_handle_port_obj_add(struct net_device *dev,
 391                                      struct notifier_block *nb,
 392                                      struct switchdev_notifier_port_obj_info *info)
 393{
 394        const struct switchdev_obj *obj = info->obj;
 395        int err;
 396
 397        switch (obj->id) {
 398        case SWITCHDEV_OBJ_ID_PORT_VLAN:
 399                err = sparx5_handle_port_vlan_add(dev, nb,
 400                                                  SWITCHDEV_OBJ_PORT_VLAN(obj));
 401                break;
 402        default:
 403                err = -EOPNOTSUPP;
 404                break;
 405        }
 406
 407        info->handled = true;
 408        return err;
 409}
 410
 411static int sparx5_handle_port_vlan_del(struct net_device *dev,
 412                                       struct notifier_block *nb,
 413                                       u16 vid)
 414{
 415        struct sparx5_port *port = netdev_priv(dev);
 416        int ret;
 417
 418        /* Master bridge? */
 419        if (netif_is_bridge_master(dev)) {
 420                struct sparx5 *sparx5 =
 421                        container_of(nb, struct sparx5,
 422                                     switchdev_blocking_nb);
 423
 424                sparx5_sync_bridge_dev_addr(dev, sparx5, vid, false);
 425                return 0;
 426        }
 427
 428        if (!sparx5_netdevice_check(dev))
 429                return -EOPNOTSUPP;
 430
 431        ret = sparx5_vlan_vid_del(port, vid);
 432        if (ret)
 433                return ret;
 434
 435        /* Delete the port MAC address with the matching VLAN information */
 436        sparx5_mact_forget(port->sparx5, port->ndev->dev_addr, vid);
 437
 438        return 0;
 439}
 440
 441static int sparx5_handle_port_obj_del(struct net_device *dev,
 442                                      struct notifier_block *nb,
 443                                      struct switchdev_notifier_port_obj_info *info)
 444{
 445        const struct switchdev_obj *obj = info->obj;
 446        int err;
 447
 448        switch (obj->id) {
 449        case SWITCHDEV_OBJ_ID_PORT_VLAN:
 450                err = sparx5_handle_port_vlan_del(dev, nb,
 451                                                  SWITCHDEV_OBJ_PORT_VLAN(obj)->vid);
 452                break;
 453        default:
 454                err = -EOPNOTSUPP;
 455                break;
 456        }
 457
 458        info->handled = true;
 459        return err;
 460}
 461
 462static int sparx5_switchdev_blocking_event(struct notifier_block *nb,
 463                                           unsigned long event,
 464                                           void *ptr)
 465{
 466        struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
 467        int err;
 468
 469        switch (event) {
 470        case SWITCHDEV_PORT_OBJ_ADD:
 471                err = sparx5_handle_port_obj_add(dev, nb, ptr);
 472                return notifier_from_errno(err);
 473        case SWITCHDEV_PORT_OBJ_DEL:
 474                err = sparx5_handle_port_obj_del(dev, nb, ptr);
 475                return notifier_from_errno(err);
 476        case SWITCHDEV_PORT_ATTR_SET:
 477                err = switchdev_handle_port_attr_set(dev, ptr,
 478                                                     sparx5_netdevice_check,
 479                                                     sparx5_port_attr_set);
 480                return notifier_from_errno(err);
 481        }
 482
 483        return NOTIFY_DONE;
 484}
 485
 486int sparx5_register_notifier_blocks(struct sparx5 *s5)
 487{
 488        int err;
 489
 490        s5->netdevice_nb.notifier_call = sparx5_netdevice_event;
 491        err = register_netdevice_notifier(&s5->netdevice_nb);
 492        if (err)
 493                return err;
 494
 495        s5->switchdev_nb.notifier_call = sparx5_switchdev_event;
 496        err = register_switchdev_notifier(&s5->switchdev_nb);
 497        if (err)
 498                goto err_switchdev_nb;
 499
 500        s5->switchdev_blocking_nb.notifier_call = sparx5_switchdev_blocking_event;
 501        err = register_switchdev_blocking_notifier(&s5->switchdev_blocking_nb);
 502        if (err)
 503                goto err_switchdev_blocking_nb;
 504
 505        sparx5_owq = alloc_ordered_workqueue("sparx5_order", 0);
 506        if (!sparx5_owq) {
 507                err = -ENOMEM;
 508                goto err_switchdev_blocking_nb;
 509        }
 510
 511        return 0;
 512
 513err_switchdev_blocking_nb:
 514        unregister_switchdev_notifier(&s5->switchdev_nb);
 515err_switchdev_nb:
 516        unregister_netdevice_notifier(&s5->netdevice_nb);
 517
 518        return err;
 519}
 520
 521void sparx5_unregister_notifier_blocks(struct sparx5 *s5)
 522{
 523        destroy_workqueue(sparx5_owq);
 524
 525        unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb);
 526        unregister_switchdev_notifier(&s5->switchdev_nb);
 527        unregister_netdevice_notifier(&s5->netdevice_nb);
 528}
 529