return NOTIFY_DONE;
 }
 
-struct dsa_switchdev_event_work {
-       struct work_struct work;
-       struct switchdev_notifier_fdb_info fdb_info;
-       struct net_device *dev;
-       unsigned long event;
-};
+static void
+dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work)
+{
+       struct dsa_switch *ds = switchdev_work->ds;
+       struct switchdev_notifier_fdb_info info;
+       struct dsa_port *dp;
+
+       if (!dsa_is_user_port(ds, switchdev_work->port))
+               return;
+
+       info.addr = switchdev_work->addr;
+       info.vid = switchdev_work->vid;
+       info.offloaded = true;
+       dp = dsa_to_port(ds, switchdev_work->port);
+       call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
+                                dp->slave, &info.info, NULL);
+}
 
 static void dsa_slave_switchdev_event_work(struct work_struct *work)
 {
        struct dsa_switchdev_event_work *switchdev_work =
                container_of(work, struct dsa_switchdev_event_work, work);
-       struct net_device *dev = switchdev_work->dev;
-       struct switchdev_notifier_fdb_info *fdb_info;
-       struct dsa_port *dp = dsa_slave_to_port(dev);
+       struct dsa_switch *ds = switchdev_work->ds;
+       struct dsa_port *dp;
        int err;
 
+       dp = dsa_to_port(ds, switchdev_work->port);
+
        rtnl_lock();
        switch (switchdev_work->event) {
        case SWITCHDEV_FDB_ADD_TO_DEVICE:
-               fdb_info = &switchdev_work->fdb_info;
-               if (!fdb_info->added_by_user)
-                       break;
-
-               err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
+               err = dsa_port_fdb_add(dp, switchdev_work->addr,
+                                      switchdev_work->vid);
                if (err) {
-                       netdev_err(dev,
-                                  "failed to add %pM vid %d to fdb: %d\n",
-                                  fdb_info->addr, fdb_info->vid, err);
+                       dev_err(ds->dev,
+                               "port %d failed to add %pM vid %d to fdb: %d\n",
+                               dp->index, switchdev_work->addr,
+                               switchdev_work->vid, err);
                        break;
                }
-               fdb_info->offloaded = true;
-               call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev,
-                                        &fdb_info->info, NULL);
+               dsa_fdb_offload_notify(switchdev_work);
                break;
 
        case SWITCHDEV_FDB_DEL_TO_DEVICE:
-               fdb_info = &switchdev_work->fdb_info;
-               if (!fdb_info->added_by_user)
-                       break;
-
-               err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
+               err = dsa_port_fdb_del(dp, switchdev_work->addr,
+                                      switchdev_work->vid);
                if (err) {
-                       netdev_err(dev,
-                                  "failed to delete %pM vid %d from fdb: %d\n",
-                                  fdb_info->addr, fdb_info->vid, err);
+                       dev_err(ds->dev,
+                               "port %d failed to delete %pM vid %d from fdb: %d\n",
+                               dp->index, switchdev_work->addr,
+                               switchdev_work->vid, err);
                }
 
                break;
        }
        rtnl_unlock();
 
-       kfree(switchdev_work->fdb_info.addr);
        kfree(switchdev_work);
-       dev_put(dev);
-}
-
-static int
-dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work *
-                                 switchdev_work,
-                                 const struct switchdev_notifier_fdb_info *
-                                 fdb_info)
-{
-       memcpy(&switchdev_work->fdb_info, fdb_info,
-              sizeof(switchdev_work->fdb_info));
-       switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
-       if (!switchdev_work->fdb_info.addr)
-               return -ENOMEM;
-       ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
-                       fdb_info->addr);
-       return 0;
+       if (dsa_is_user_port(ds, dp->index))
+               dev_put(dp->slave);
 }
 
 /* Called under rcu_read_lock() */
                                     unsigned long event, void *ptr)
 {
        struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+       const struct switchdev_notifier_fdb_info *fdb_info;
        struct dsa_switchdev_event_work *switchdev_work;
+       struct dsa_port *dp;
        int err;
 
        if (event == SWITCHDEV_PORT_ATTR_SET) {
        if (!dsa_slave_dev_check(dev))
                return NOTIFY_DONE;
 
+       dp = dsa_slave_to_port(dev);
+
        switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
        if (!switchdev_work)
                return NOTIFY_BAD;
 
        INIT_WORK(&switchdev_work->work,
                  dsa_slave_switchdev_event_work);
-       switchdev_work->dev = dev;
+       switchdev_work->ds = dp->ds;
+       switchdev_work->port = dp->index;
        switchdev_work->event = event;
 
        switch (event) {
        case SWITCHDEV_FDB_ADD_TO_DEVICE:
        case SWITCHDEV_FDB_DEL_TO_DEVICE:
-               if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr))
-                       goto err_fdb_work_init;
+               fdb_info = ptr;
+
+               if (!fdb_info->added_by_user) {
+                       kfree(switchdev_work);
+                       return NOTIFY_OK;
+               }
+
+               ether_addr_copy(switchdev_work->addr,
+                               fdb_info->addr);
+               switchdev_work->vid = fdb_info->vid;
+
                dev_hold(dev);
                break;
        default:
 
        dsa_schedule_work(&switchdev_work->work);
        return NOTIFY_OK;
-
-err_fdb_work_init:
-       kfree(switchdev_work);
-       return NOTIFY_BAD;
 }
 
 static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused,