if (err)
                goto err_egress_flood;
 
+       err = switchdev_bridge_port_offload(netdev, netdev, extack);
+       if (err)
+               goto err_switchdev_offload;
+
        return 0;
 
+err_switchdev_offload:
 err_egress_flood:
        dpaa2_switch_port_set_fdb(port_priv, NULL);
        return err;
        return dpaa2_switch_port_vlan_add(arg, vlan_proto, vid);
 }
 
+static void dpaa2_switch_port_pre_bridge_leave(struct net_device *netdev)
+{
+       switchdev_bridge_port_unoffload(netdev);
+}
+
 static int dpaa2_switch_port_bridge_leave(struct net_device *netdev)
 {
        struct ethsw_port_priv *port_priv = netdev_priv(netdev);
                if (err)
                        goto out;
 
+               if (!info->linking)
+                       dpaa2_switch_port_pre_bridge_leave(netdev);
+
                break;
        case NETDEV_CHANGEUPPER:
                upper_dev = info->upper_dev;
 
        case NETDEV_CHANGEUPPER:
                if (netif_is_bridge_master(upper)) {
                        if (info->linking)
-                               return prestera_bridge_port_join(upper, port);
+                               return prestera_bridge_port_join(upper, port,
+                                                                extack);
                        else
                                prestera_bridge_port_leave(upper, port);
                } else if (netif_is_lag_master(upper)) {
 
 }
 
 int prestera_bridge_port_join(struct net_device *br_dev,
-                             struct prestera_port *port)
+                             struct prestera_port *port,
+                             struct netlink_ext_ack *extack)
 {
        struct prestera_switchdev *swdev = port->sw->swdev;
        struct prestera_bridge_port *br_port;
                goto err_brport_create;
        }
 
+       err = switchdev_bridge_port_offload(br_port->dev, port->dev, extack);
+       if (err)
+               goto err_switchdev_offload;
+
        if (bridge->vlan_enabled)
                return 0;
 
        return 0;
 
 err_port_join:
+       switchdev_bridge_port_unoffload(br_port->dev);
+err_switchdev_offload:
        prestera_bridge_port_put(br_port);
 err_brport_create:
        prestera_bridge_put(bridge);
        else
                prestera_bridge_1d_port_leave(br_port);
 
+       switchdev_bridge_port_unoffload(br_port->dev);
+
        prestera_hw_port_learning_set(port, false);
        prestera_hw_port_flood_set(port, BR_FLOOD | BR_MCAST_FLOOD, 0);
        prestera_port_vid_stp_set(port, PRESTERA_VID_ALL, BR_STATE_FORWARDING);
 
 void prestera_switchdev_fini(struct prestera_switch *sw);
 
 int prestera_bridge_port_join(struct net_device *br_dev,
-                             struct prestera_port *port);
+                             struct prestera_port *port,
+                             struct netlink_ext_ack *extack);
 
 void prestera_bridge_port_leave(struct net_device *br_dev,
                                struct prestera_port *port);
 
 
 static struct mlxsw_sp_bridge_port *
 mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device,
-                           struct net_device *brport_dev)
+                           struct net_device *brport_dev,
+                           struct netlink_ext_ack *extack)
 {
        struct mlxsw_sp_bridge_port *bridge_port;
        struct mlxsw_sp_port *mlxsw_sp_port;
+       int err;
 
        bridge_port = kzalloc(sizeof(*bridge_port), GFP_KERNEL);
        if (!bridge_port)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(brport_dev);
        bridge_port->lagged = mlxsw_sp_port->lagged;
        list_add(&bridge_port->list, &bridge_device->ports_list);
        bridge_port->ref_count = 1;
 
+       err = switchdev_bridge_port_offload(brport_dev, mlxsw_sp_port->dev,
+                                           extack);
+       if (err)
+               goto err_switchdev_offload;
+
        return bridge_port;
+
+err_switchdev_offload:
+       list_del(&bridge_port->list);
+       kfree(bridge_port);
+       return ERR_PTR(err);
 }
 
 static void
 mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port)
 {
+       switchdev_bridge_port_unoffload(bridge_port->dev);
        list_del(&bridge_port->list);
        WARN_ON(!list_empty(&bridge_port->vlans_list));
        kfree(bridge_port);
        if (IS_ERR(bridge_device))
                return ERR_CAST(bridge_device);
 
-       bridge_port = mlxsw_sp_bridge_port_create(bridge_device, brport_dev);
-       if (!bridge_port) {
-               err = -ENOMEM;
+       bridge_port = mlxsw_sp_bridge_port_create(bridge_device, brport_dev,
+                                                 extack);
+       if (IS_ERR(bridge_port)) {
+               err = PTR_ERR(bridge_port);
                goto err_bridge_port_create;
        }
 
 
 }
 
 static int sparx5_port_bridge_join(struct sparx5_port *port,
-                                  struct net_device *bridge)
+                                  struct net_device *bridge,
+                                  struct netlink_ext_ack *extack)
 {
        struct sparx5 *sparx5 = port->sparx5;
+       struct net_device *ndev = port->ndev;
+       int err;
 
        if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
                /* First bridged port */
 
        set_bit(port->portno, sparx5->bridge_mask);
 
+       err = switchdev_bridge_port_offload(ndev, ndev, extack);
+       if (err)
+               goto err_switchdev_offload;
+
        /* Port enters in bridge mode therefor don't need to copy to CPU
         * frames for multicast in case the bridge is not requesting them
         */
-       __dev_mc_unsync(port->ndev, sparx5_mc_unsync);
+       __dev_mc_unsync(ndev, sparx5_mc_unsync);
 
        return 0;
+
+err_switchdev_offload:
+       clear_bit(port->portno, sparx5->bridge_mask);
+       return err;
 }
 
 static void sparx5_port_bridge_leave(struct sparx5_port *port,
 {
        struct sparx5 *sparx5 = port->sparx5;
 
+       switchdev_bridge_port_unoffload(port->ndev);
+
        clear_bit(port->portno, sparx5->bridge_mask);
        if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
                sparx5->hw_bridge_dev = NULL;
                                   struct netdev_notifier_changeupper_info *info)
 {
        struct sparx5_port *port = netdev_priv(dev);
+       struct netlink_ext_ack *extack;
        int err = 0;
 
+       extack = netdev_notifier_info_to_extack(&info->info);
+
        if (netif_is_bridge_master(info->upper_dev)) {
                if (info->linking)
-                       err = sparx5_port_bridge_join(port, info->upper_dev);
+                       err = sparx5_port_bridge_join(port, info->upper_dev,
+                                                     extack);
                else
                        sparx5_port_bridge_leave(port, info->upper_dev);
 
 
 
        ocelot_port_bridge_join(ocelot, port, bridge);
 
+       err = switchdev_bridge_port_offload(brport_dev, dev, extack);
+       if (err)
+               goto err_switchdev_offload;
+
        err = ocelot_switchdev_sync(ocelot, port, brport_dev, bridge, extack);
        if (err)
                goto err_switchdev_sync;
        return 0;
 
 err_switchdev_sync:
+       switchdev_bridge_port_unoffload(brport_dev);
+err_switchdev_offload:
        ocelot_port_bridge_leave(ocelot, port, bridge);
        return err;
 }
 
+static void ocelot_netdevice_pre_bridge_leave(struct net_device *brport_dev)
+{
+       switchdev_bridge_port_unoffload(brport_dev);
+}
+
 static int ocelot_netdevice_bridge_leave(struct net_device *dev,
                                         struct net_device *brport_dev,
                                         struct net_device *bridge)
        return err;
 }
 
+static void ocelot_netdevice_pre_lag_leave(struct net_device *dev,
+                                          struct net_device *bond)
+{
+       struct net_device *bridge_dev;
+
+       bridge_dev = netdev_master_upper_dev_get(bond);
+       if (!bridge_dev || !netif_is_bridge_master(bridge_dev))
+               return;
+
+       ocelot_netdevice_pre_bridge_leave(bond);
+}
+
 static int ocelot_netdevice_lag_leave(struct net_device *dev,
                                      struct net_device *bond)
 {
        return NOTIFY_DONE;
 }
 
+static int
+ocelot_netdevice_prechangeupper(struct net_device *dev,
+                               struct net_device *brport_dev,
+                               struct netdev_notifier_changeupper_info *info)
+{
+       if (netif_is_bridge_master(info->upper_dev) && !info->linking)
+               ocelot_netdevice_pre_bridge_leave(brport_dev);
+
+       if (netif_is_lag_master(info->upper_dev) && !info->linking)
+               ocelot_netdevice_pre_lag_leave(dev, info->upper_dev);
+
+       return NOTIFY_DONE;
+}
+
+static int
+ocelot_netdevice_lag_prechangeupper(struct net_device *dev,
+                                   struct netdev_notifier_changeupper_info *info)
+{
+       struct net_device *lower;
+       struct list_head *iter;
+       int err = NOTIFY_DONE;
+
+       netdev_for_each_lower_dev(dev, lower, iter) {
+               struct ocelot_port_private *priv = netdev_priv(lower);
+               struct ocelot_port *ocelot_port = &priv->port;
+
+               if (ocelot_port->bond != dev)
+                       return NOTIFY_OK;
+
+               err = ocelot_netdevice_prechangeupper(dev, lower, info);
+               if (err)
+                       return err;
+       }
+
+       return NOTIFY_DONE;
+}
+
 static int
 ocelot_netdevice_changelowerstate(struct net_device *dev,
                                  struct netdev_lag_lower_state_info *info)
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 
        switch (event) {
+       case NETDEV_PRECHANGEUPPER: {
+               struct netdev_notifier_changeupper_info *info = ptr;
+
+               if (ocelot_netdevice_dev_check(dev))
+                       return ocelot_netdevice_prechangeupper(dev, dev, info);
+
+               if (netif_is_lag_master(dev))
+                       return ocelot_netdevice_lag_prechangeupper(dev, info);
+
+               break;
+       }
        case NETDEV_CHANGEUPPER: {
                struct netdev_notifier_changeupper_info *info = ptr;
 
 
        int (*port_obj_fdb_del)(struct rocker_port *rocker_port,
                                u16 vid, const unsigned char *addr);
        int (*port_master_linked)(struct rocker_port *rocker_port,
-                                 struct net_device *master);
+                                 struct net_device *master,
+                                 struct netlink_ext_ack *extack);
        int (*port_master_unlinked)(struct rocker_port *rocker_port,
                                    struct net_device *master);
        int (*port_neigh_update)(struct rocker_port *rocker_port,
 
 }
 
 static int rocker_world_port_master_linked(struct rocker_port *rocker_port,
-                                          struct net_device *master)
+                                          struct net_device *master,
+                                          struct netlink_ext_ack *extack)
 {
        struct rocker_world_ops *wops = rocker_port->rocker->wops;
 
        if (!wops->port_master_linked)
                return -EOPNOTSUPP;
-       return wops->port_master_linked(rocker_port, master);
+       return wops->port_master_linked(rocker_port, master, extack);
 }
 
 static int rocker_world_port_master_unlinked(struct rocker_port *rocker_port,
 static int rocker_netdevice_event(struct notifier_block *unused,
                                  unsigned long event, void *ptr)
 {
+       struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct netdev_notifier_changeupper_info *info;
        struct rocker_port *rocker_port;
                rocker_port = netdev_priv(dev);
                if (info->linking) {
                        err = rocker_world_port_master_linked(rocker_port,
-                                                             info->upper_dev);
+                                                             info->upper_dev,
+                                                             extack);
                        if (err)
                                netdev_warn(dev, "failed to reflect master linked (err %d)\n",
                                            err);
 
 }
 
 static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port,
-                                 struct net_device *bridge)
+                                 struct net_device *bridge,
+                                 struct netlink_ext_ack *extack)
 {
+       struct net_device *dev = ofdpa_port->dev;
        int err;
 
        /* Port is joining bridge, so the internal VLAN for the
 
        ofdpa_port->bridge_dev = bridge;
 
-       return ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
+       err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
+       if (err)
+               return err;
+
+       return switchdev_bridge_port_offload(dev, dev, extack);
 }
 
 static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port)
 {
+       struct net_device *dev = ofdpa_port->dev;
        int err;
 
+       switchdev_bridge_port_unoffload(dev);
+
        err = ofdpa_port_vlan_del(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
        if (err)
                return err;
 }
 
 static int ofdpa_port_master_linked(struct rocker_port *rocker_port,
-                                   struct net_device *master)
+                                   struct net_device *master,
+                                   struct netlink_ext_ack *extack)
 {
        struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
        int err = 0;
 
        if (netif_is_bridge_master(master))
-               err = ofdpa_port_bridge_join(ofdpa_port, master);
+               err = ofdpa_port_bridge_join(ofdpa_port, master, extack);
        else if (netif_is_ovs_master(master))
                err = ofdpa_port_ovs_changed(ofdpa_port, master);
        return err;
 
 
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
 #include <linux/if_vlan.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
        return false;
 }
 
-static int am65_cpsw_netdevice_port_link(struct net_device *ndev, struct net_device *br_ndev)
+static int am65_cpsw_netdevice_port_link(struct net_device *ndev,
+                                        struct net_device *br_ndev,
+                                        struct netlink_ext_ack *extack)
 {
        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
        struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
+       int err;
 
        if (!common->br_members) {
                common->hw_bridge_dev = br_ndev;
                        return -EOPNOTSUPP;
        }
 
+       err = switchdev_bridge_port_offload(ndev, ndev, extack);
+       if (err)
+               return err;
+
        common->br_members |= BIT(priv->port->port_id);
 
        am65_cpsw_port_offload_fwd_mark_update(common);
        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
        struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
 
+       switchdev_bridge_port_unoffload(ndev);
+
        common->br_members &= ~BIT(priv->port->port_id);
 
        am65_cpsw_port_offload_fwd_mark_update(common);
 static int am65_cpsw_netdevice_event(struct notifier_block *unused,
                                     unsigned long event, void *ptr)
 {
+       struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
        struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
        struct netdev_notifier_changeupper_info *info;
        int ret = NOTIFY_DONE;
 
                if (netif_is_bridge_master(info->upper_dev)) {
                        if (info->linking)
-                               ret = am65_cpsw_netdevice_port_link(ndev, info->upper_dev);
+                               ret = am65_cpsw_netdevice_port_link(ndev,
+                                                                   info->upper_dev,
+                                                                   extack);
                        else
                                am65_cpsw_netdevice_port_unlink(ndev);
                }
 
 #include <linux/module.h>
 #include <linux/irqreturn.h>
 #include <linux/interrupt.h>
+#include <linux/if_bridge.h>
 #include <linux/if_ether.h>
 #include <linux/etherdevice.h>
 #include <linux/net_tstamp.h>
 }
 
 static int cpsw_netdevice_port_link(struct net_device *ndev,
-                                   struct net_device *br_ndev)
+                                   struct net_device *br_ndev,
+                                   struct netlink_ext_ack *extack)
 {
        struct cpsw_priv *priv = netdev_priv(ndev);
        struct cpsw_common *cpsw = priv->cpsw;
+       int err;
 
        if (!cpsw->br_members) {
                cpsw->hw_bridge_dev = br_ndev;
                        return -EOPNOTSUPP;
        }
 
+       err = switchdev_bridge_port_offload(ndev, ndev, extack);
+       if (err)
+               return err;
+
        cpsw->br_members |= BIT(priv->emac_port);
 
        cpsw_port_offload_fwd_mark_update(cpsw);
        struct cpsw_priv *priv = netdev_priv(ndev);
        struct cpsw_common *cpsw = priv->cpsw;
 
+       switchdev_bridge_port_unoffload(ndev);
+
        cpsw->br_members &= ~BIT(priv->emac_port);
 
        cpsw_port_offload_fwd_mark_update(cpsw);
 static int cpsw_netdevice_event(struct notifier_block *unused,
                                unsigned long event, void *ptr)
 {
+       struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
        struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
        struct netdev_notifier_changeupper_info *info;
        int ret = NOTIFY_DONE;
                if (netif_is_bridge_master(info->upper_dev)) {
                        if (info->linking)
                                ret = cpsw_netdevice_port_link(ndev,
-                                                              info->upper_dev);
+                                                              info->upper_dev,
+                                                              extack);
                        else
                                cpsw_netdevice_port_unlink(ndev);
                }
 
 }
 #endif
 
+#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_NET_SWITCHDEV)
+
+int switchdev_bridge_port_offload(struct net_device *brport_dev,
+                                 struct net_device *dev,
+                                 struct netlink_ext_ack *extack);
+void switchdev_bridge_port_unoffload(struct net_device *brport_dev);
+
+#else
+
+static inline int switchdev_bridge_port_offload(struct net_device *brport_dev,
+                                               struct net_device *dev,
+                                               struct netlink_ext_ack *extack)
+{
+       return -EINVAL;
+}
+
+static inline void switchdev_bridge_port_unoffload(struct net_device *brport_dev)
+{
+}
+#endif
+
 #endif
 
        nbp_backup_clear(p);
 
        nbp_update_port_count(br);
-       nbp_switchdev_del(p);
 
        netdev_upper_dev_unlink(dev, br->dev);
 
        if (err)
                goto err5;
 
-       err = nbp_switchdev_add(p);
-       if (err)
-               goto err6;
-
        dev_disable_lro(dev);
 
        list_add_rcu(&p->list, &br->port_list);
                 */
                err = dev_pre_changeaddr_notify(br->dev, dev->dev_addr, extack);
                if (err)
-                       goto err7;
+                       goto err6;
        }
 
        err = nbp_vlan_init(p, extack);
        if (err) {
                netdev_err(dev, "failed to initialize vlan filtering on this port\n");
-               goto err7;
+               goto err6;
        }
 
        spin_lock_bh(&br->lock);
 
        return 0;
 
-err7:
+err6:
        if (fdb_synced)
                br_fdb_unsync_static(br, p);
        list_del_rcu(&p->list);
        br_fdb_delete_by_port(br, p, 0, 1);
        nbp_update_port_count(br);
-       nbp_switchdev_del(p);
-err6:
        netdev_upper_dev_unlink(dev, br->dev);
 err5:
        dev->priv_flags &= ~IFF_BRIDGE_PORT;
 
         * hardware domain.
         */
        int                             hwdom;
+       int                             offload_count;
+       struct netdev_phys_item_id      ppid;
 #endif
        u16                             group_fwd_mask;
        u16                             backup_redirected_cnt;
 int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
                               struct netlink_ext_ack *extack);
 int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid);
-int nbp_switchdev_add(struct net_bridge_port *p);
-void nbp_switchdev_del(struct net_bridge_port *p);
 void br_switchdev_init(struct net_bridge *br);
 
 static inline void br_switchdev_frame_unmark(struct sk_buff *skb)
 {
 }
 
-static inline int nbp_switchdev_add(struct net_bridge_port *p)
-{
-       return 0;
-}
-
-static inline void nbp_switchdev_del(struct net_bridge_port *p)
-{
-}
-
 static inline void br_switchdev_init(struct net_bridge *br)
 {
 }
 
 
        /* joining is yet to be added to the port list. */
        list_for_each_entry(p, &br->port_list, list) {
-               if (netdev_port_same_parent_id(joining->dev, p->dev)) {
+               if (netdev_phys_item_id_same(&joining->ppid, &p->ppid)) {
                        joining->hwdom = p->hwdom;
                        return 0;
                }
        clear_bit(leaving->hwdom, &br->busy_hwdoms);
 }
 
-int nbp_switchdev_add(struct net_bridge_port *p)
+static int nbp_switchdev_add(struct net_bridge_port *p,
+                            struct netdev_phys_item_id ppid,
+                            struct netlink_ext_ack *extack)
 {
-       struct netdev_phys_item_id ppid = { };
-       int err;
+       if (p->offload_count) {
+               /* Prevent unsupported configurations such as a bridge port
+                * which is a bonding interface, and the member ports are from
+                * different hardware switches.
+                */
+               if (!netdev_phys_item_id_same(&p->ppid, &ppid)) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Same bridge port cannot be offloaded by two physical switches");
+                       return -EBUSY;
+               }
 
-       ASSERT_RTNL();
+               /* Tolerate drivers that call switchdev_bridge_port_offload()
+                * more than once for the same bridge port, such as when the
+                * bridge port is an offloaded bonding/team interface.
+                */
+               p->offload_count++;
 
-       err = dev_get_port_parent_id(p->dev, &ppid, true);
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       return 0;
-               return err;
+               return 0;
        }
 
+       p->ppid = ppid;
+       p->offload_count = 1;
+
        return nbp_switchdev_hwdom_set(p);
 }
 
-void nbp_switchdev_del(struct net_bridge_port *p)
+static void nbp_switchdev_del(struct net_bridge_port *p)
 {
-       ASSERT_RTNL();
+       if (WARN_ON(!p->offload_count))
+               return;
+
+       p->offload_count--;
+
+       if (p->offload_count)
+               return;
 
        if (p->hwdom)
                nbp_switchdev_hwdom_put(p);
 }
+
+/* Let the bridge know that this port is offloaded, so that it can assign a
+ * switchdev hardware domain to it.
+ */
+int switchdev_bridge_port_offload(struct net_device *brport_dev,
+                                 struct net_device *dev,
+                                 struct netlink_ext_ack *extack)
+{
+       struct netdev_phys_item_id ppid;
+       struct net_bridge_port *p;
+       int err;
+
+       ASSERT_RTNL();
+
+       p = br_port_get_rtnl(brport_dev);
+       if (!p)
+               return -ENODEV;
+
+       err = dev_get_port_parent_id(dev, &ppid, false);
+       if (err)
+               return err;
+
+       return nbp_switchdev_add(p, ppid, extack);
+}
+EXPORT_SYMBOL_GPL(switchdev_bridge_port_offload);
+
+void switchdev_bridge_port_unoffload(struct net_device *brport_dev)
+{
+       struct net_bridge_port *p;
+
+       ASSERT_RTNL();
+
+       p = br_port_get_rtnl(brport_dev);
+       if (!p)
+               return;
+
+       nbp_switchdev_del(p);
+}
+EXPORT_SYMBOL_GPL(switchdev_bridge_port_unoffload);
 
                .port = dp->index,
                .br = br,
        };
+       struct net_device *dev = dp->slave;
+       struct net_device *brport_dev;
        int err;
 
        /* Here the interface is already bridged. Reflect the current
         */
        dp->bridge_dev = br;
 
+       brport_dev = dsa_port_to_bridge_port(dp);
+
        err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_JOIN, &info);
        if (err)
                goto out_rollback;
 
-       err = dsa_port_switchdev_sync(dp, extack);
+       err = switchdev_bridge_port_offload(brport_dev, dev, extack);
        if (err)
                goto out_rollback_unbridge;
 
+       err = dsa_port_switchdev_sync(dp, extack);
+       if (err)
+               goto out_rollback_unoffload;
+
        return 0;
 
+out_rollback_unoffload:
+       switchdev_bridge_port_unoffload(brport_dev);
 out_rollback_unbridge:
        dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
 out_rollback:
 int dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br,
                              struct netlink_ext_ack *extack)
 {
+       struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
+
+       switchdev_bridge_port_unoffload(brport_dev);
+
        return dsa_port_switchdev_unsync_objs(dp, br, extack);
 }