int nfp_abm_ctrl_prio_map_update(struct nfp_abm_link *alink, u32 *packed)
 {
+       const u32 cmd = NFP_NET_CFG_MBOX_CMD_PCI_DSCP_PRIOMAP_SET;
        struct nfp_net *nn = alink->vnic;
        unsigned int i;
        int err;
 
+       err = nfp_net_mbox_lock(nn, alink->abm->prio_map_len);
+       if (err)
+               return err;
+
        /* Write data_len and wipe reserved */
        nn_writeq(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATALEN,
                  alink->abm->prio_map_len);
                nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATA + i,
                          packed[i / sizeof(u32)]);
 
-       err = nfp_net_reconfig_mbox(nn,
-                                   NFP_NET_CFG_MBOX_CMD_PCI_DSCP_PRIOMAP_SET);
+       err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);
        if (err)
                nfp_err(alink->abm->app->cpp,
                        "setting DSCP -> VQ map failed with error %d\n", err);
 
  * @shared_handler:     Handler for shared interrupts
  * @shared_name:        Name for shared interrupt
  * @me_freq_mhz:        ME clock_freq (MHz)
- * @reconfig_lock:     Protects HW reconfiguration request regs/machinery
+ * @reconfig_lock:     Protects @reconfig_posted, @reconfig_timer_active,
+ *                     @reconfig_sync_present and HW reconfiguration request
+ *                     regs/machinery from async requests (sync must take
+ *                     @bar_lock)
  * @reconfig_posted:   Pending reconfig bits coming from async sources
  * @reconfig_timer_active:  Timer for reading reconfiguration results is pending
  * @reconfig_sync_present:  Some thread is performing synchronous reconfig
  * @reconfig_timer:    Timer for async reading of reconfig results
  * @reconfig_in_progress_update:       Update FW is processing now (debug only)
+ * @bar_lock:          vNIC config BAR access lock, protects: update,
+ *                     mailbox area
  * @link_up:            Is the link up?
  * @link_status_lock:  Protects @link_* and ensures atomicity with BAR reading
  * @rx_coalesce_usecs:      RX interrupt moderation usecs delay parameter
        struct timer_list reconfig_timer;
        u32 reconfig_in_progress_update;
 
+       struct mutex bar_lock;
+
        u32 rx_coalesce_usecs;
        u32 rx_coalesce_max_frames;
        u32 tx_coalesce_usecs;
        spin_unlock_bh(&nn->r_vecs[0].lock);
 }
 
+static inline void nn_ctrl_bar_lock(struct nfp_net *nn)
+{
+       mutex_lock(&nn->bar_lock);
+}
+
+static inline void nn_ctrl_bar_unlock(struct nfp_net *nn)
+{
+       mutex_unlock(&nn->bar_lock);
+}
+
 /* Globals */
 extern const char nfp_driver_version[];
 
 void nfp_net_rss_write_itbl(struct nfp_net *nn);
 void nfp_net_rss_write_key(struct nfp_net *nn);
 void nfp_net_coalesce_write_cfg(struct nfp_net *nn);
-int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd);
+int nfp_net_mbox_lock(struct nfp_net *nn, unsigned int data_size);
+int nfp_net_mbox_reconfig(struct nfp_net *nn, u32 mbox_cmd);
+int nfp_net_mbox_reconfig_and_unlock(struct nfp_net *nn, u32 mbox_cmd);
 
 unsigned int
 nfp_net_irqs_alloc(struct pci_dev *pdev, struct msix_entry *irq_entries,
 
 #include <linux/interrupt.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/lockdep.h>
 #include <linux/mm.h>
 #include <linux/overflow.h>
 #include <linux/page_ref.h>
 }
 
 /**
- * nfp_net_reconfig() - Reconfigure the firmware
+ * __nfp_net_reconfig() - Reconfigure the firmware
  * @nn:      NFP Net device to reconfigure
  * @update:  The value for the update field in the BAR config
  *
  *
  * Return: Negative errno on error, 0 on success
  */
-int nfp_net_reconfig(struct nfp_net *nn, u32 update)
+static int __nfp_net_reconfig(struct nfp_net *nn, u32 update)
 {
        int ret;
 
+       lockdep_assert_held(&nn->bar_lock);
+
        nfp_net_reconfig_sync_enter(nn);
 
        nfp_net_reconfig_start(nn, update);
        return ret;
 }
 
+int nfp_net_reconfig(struct nfp_net *nn, u32 update)
+{
+       int ret;
+
+       nn_ctrl_bar_lock(nn);
+       ret = __nfp_net_reconfig(nn, update);
+       nn_ctrl_bar_unlock(nn);
+
+       return ret;
+}
+
+int nfp_net_mbox_lock(struct nfp_net *nn, unsigned int data_size)
+{
+       if (nn->tlv_caps.mbox_len < NFP_NET_CFG_MBOX_SIMPLE_VAL + data_size) {
+               nn_err(nn, "mailbox too small for %u of data (%u)\n",
+                      data_size, nn->tlv_caps.mbox_len);
+               return -EIO;
+       }
+
+       nn_ctrl_bar_lock(nn);
+       return 0;
+}
+
 /**
- * nfp_net_reconfig_mbox() - Reconfigure the firmware via the mailbox
+ * nfp_net_mbox_reconfig() - Reconfigure the firmware via the mailbox
  * @nn:        NFP Net device to reconfigure
  * @mbox_cmd:  The value for the mailbox command
  *
  *
  * Return: Negative errno on error, 0 on success
  */
-int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd)
+int nfp_net_mbox_reconfig(struct nfp_net *nn, u32 mbox_cmd)
 {
        u32 mbox = nn->tlv_caps.mbox_off;
        int ret;
 
-       if (!nfp_net_has_mbox(&nn->tlv_caps)) {
-               nn_err(nn, "no mailbox present, command: %u\n", mbox_cmd);
-               return -EIO;
-       }
-
+       lockdep_assert_held(&nn->bar_lock);
        nn_writeq(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_CMD, mbox_cmd);
 
-       ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MBOX);
+       ret = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MBOX);
        if (ret) {
                nn_err(nn, "Mailbox update error\n");
                return ret;
        return -nn_readl(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_RET);
 }
 
+int nfp_net_mbox_reconfig_and_unlock(struct nfp_net *nn, u32 mbox_cmd)
+{
+       int ret;
+
+       ret = nfp_net_mbox_reconfig(nn, mbox_cmd);
+       nn_ctrl_bar_unlock(nn);
+       return ret;
+}
+
 /* Interrupt configuration and handling
  */
 
 static int
 nfp_net_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
 {
+       const u32 cmd = NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD;
        struct nfp_net *nn = netdev_priv(netdev);
+       int err;
 
        /* Priority tagged packets with vlan id 0 are processed by the
         * NFP as untagged packets
        if (!vid)
                return 0;
 
+       err = nfp_net_mbox_lock(nn, NFP_NET_CFG_VLAN_FILTER_SZ);
+       if (err)
+               return err;
+
        nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_VID, vid);
        nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_PROTO,
                  ETH_P_8021Q);
 
-       return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD);
+       return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
 }
 
 static int
 nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
 {
+       const u32 cmd = NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL;
        struct nfp_net *nn = netdev_priv(netdev);
+       int err;
 
        /* Priority tagged packets with vlan id 0 are processed by the
         * NFP as untagged packets
        if (!vid)
                return 0;
 
+       err = nfp_net_mbox_lock(nn, NFP_NET_CFG_VLAN_FILTER_SZ);
+       if (err)
+               return err;
+
        nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_VID, vid);
        nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_PROTO,
                  ETH_P_8021Q);
 
-       return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL);
+       return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
 }
 
 static void nfp_net_stat64(struct net_device *netdev,
        nn->dp.txd_cnt = NFP_NET_TX_DESCS_DEFAULT;
        nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT;
 
+       mutex_init(&nn->bar_lock);
+
        spin_lock_init(&nn->reconfig_lock);
        spin_lock_init(&nn->link_status_lock);
 
 void nfp_net_free(struct nfp_net *nn)
 {
        WARN_ON(timer_pending(&nn->reconfig_timer) || nn->reconfig_posted);
+
+       mutex_destroy(&nn->bar_lock);
+
        if (nn->dp.netdev)
                free_netdev(nn->dp.netdev);
        else