/*
  * drivers/net/ethernet/mellanox/mlxsw/spectrum.c
- * Copyright (c) 2015-2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2015-2017 Jiri Pirko <jiri@mellanox.com>
  * Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
  * Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
                goto err_afa_init;
        }
 
+       err = mlxsw_sp_span_init(mlxsw_sp);
+       if (err) {
+               dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
+               goto err_span_init;
+       }
+
+       /* Initialize router after SPAN is initialized, so that the FIB and
+        * neighbor event handlers can issue SPAN respin.
+        */
        err = mlxsw_sp_router_init(mlxsw_sp);
        if (err) {
                dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
                goto err_router_init;
        }
 
-       /* Initialize netdevice notifier after router is initialized, so that
-        * the event handler can use router structures.
+       /* Initialize netdevice notifier after router and SPAN is initialized,
+        * so that the event handler can use router structures and call SPAN
+        * respin.
         */
        mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event;
        err = register_netdevice_notifier(&mlxsw_sp->netdevice_nb);
                goto err_netdev_notifier;
        }
 
-       err = mlxsw_sp_span_init(mlxsw_sp);
-       if (err) {
-               dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
-               goto err_span_init;
-       }
-
        err = mlxsw_sp_acl_init(mlxsw_sp);
        if (err) {
                dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
 err_dpipe_init:
        mlxsw_sp_acl_fini(mlxsw_sp);
 err_acl_init:
-       mlxsw_sp_span_fini(mlxsw_sp);
-err_span_init:
        unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
 err_netdev_notifier:
        mlxsw_sp_router_fini(mlxsw_sp);
 err_router_init:
+       mlxsw_sp_span_fini(mlxsw_sp);
+err_span_init:
        mlxsw_sp_afa_fini(mlxsw_sp);
 err_afa_init:
        mlxsw_sp_counter_pool_fini(mlxsw_sp);
        mlxsw_sp_ports_remove(mlxsw_sp);
        mlxsw_sp_dpipe_fini(mlxsw_sp);
        mlxsw_sp_acl_fini(mlxsw_sp);
-       mlxsw_sp_span_fini(mlxsw_sp);
        unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
        mlxsw_sp_router_fini(mlxsw_sp);
+       mlxsw_sp_span_fini(mlxsw_sp);
        mlxsw_sp_afa_fini(mlxsw_sp);
        mlxsw_sp_counter_pool_fini(mlxsw_sp);
        mlxsw_sp_switchdev_fini(mlxsw_sp);
                if (span_entry)
                        mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry);
        }
+       mlxsw_sp_span_respin(mlxsw_sp);
 
        if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev))
                err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev,
 
 #include "spectrum_mr.h"
 #include "spectrum_mr_tcam.h"
 #include "spectrum_router.h"
+#include "spectrum_span.h"
 
 struct mlxsw_sp_fib;
 struct mlxsw_sp_vr;
        read_unlock_bh(&n->lock);
 
        rtnl_lock();
+       mlxsw_sp_span_respin(mlxsw_sp);
+
        entry_connected = nud_state & NUD_VALID && !dead;
        neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
        if (!entry_connected && !neigh_entry)
 
        /* Protect internal structures from changes */
        rtnl_lock();
+       mlxsw_sp_span_respin(mlxsw_sp);
+
        switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE: /* fall through */
        case FIB_EVENT_ENTRY_APPEND: /* fall through */
        int err;
 
        rtnl_lock();
+       mlxsw_sp_span_respin(mlxsw_sp);
+
        switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE: /* fall through */
        case FIB_EVENT_ENTRY_ADD:
 
                   span_entry->id);
        mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind);
 }
+
+void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp)
+{
+       int i;
+       int err;
+
+       ASSERT_RTNL();
+       for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
+               struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
+               struct mlxsw_sp_span_parms sparms = {0};
+
+               if (!curr->ref_count)
+                       continue;
+
+               err = curr->ops->parms(curr->to_dev, &sparms);
+               if (err)
+                       continue;
+
+               if (memcmp(&sparms, &curr->parms, sizeof(sparms))) {
+                       mlxsw_sp_span_entry_deconfigure(curr);
+                       mlxsw_sp_span_entry_configure(mlxsw_sp, curr, sparms);
+               }
+       }
+}