if (!cdev)
                return -ENODEV;
 
-       if (IS_VF(cdev))
-               return 0;
-
        /* The link should be set only once per PF */
        hwfn = &cdev->hwfns[0];
 
+       /* When VF wants to set link, force it to read the bulletin instead.
+        * This mimics the PF behavior, where a noitification [both immediate
+        * and possible later] would be generated when changing properties.
+        */
+       if (IS_VF(cdev)) {
+               qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG);
+               return 0;
+       }
+
        ptt = qed_ptt_acquire(hwfn);
        if (!ptt)
                return -EBUSY;
 
 
        /* Initialize the MFW spinlock */
        spin_lock_init(&p_info->lock);
+       spin_lock_init(&p_info->link_lock);
 
        return 0;
 
        u8 max_bw, min_bw;
        u32 status = 0;
 
+       /* Prevent SW/attentions from doing this at the same time */
+       spin_lock_bh(&p_hwfn->mcp_info->link_lock);
+
        p_link = &p_hwfn->mcp_info->link_output;
        memset(p_link, 0, sizeof(*p_link));
        if (!b_reset) {
        } else {
                DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
                           "Resetting link indications\n");
-               return;
+               goto out;
        }
 
        if (p_hwfn->b_drv_link_init)
        p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT);
 
        qed_link_update(p_hwfn);
+out:
+       spin_unlock_bh(&p_hwfn->mcp_info->link_lock);
 }
 
 int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up)
                return rc;
        }
 
-       /* Reset the link status if needed */
-       if (!b_up)
-               qed_mcp_handle_link_change(p_hwfn, p_ptt, true);
+       /* Mimic link-change attention, done for several reasons:
+        *  - On reset, there's no guarantee MFW would trigger
+        *    an attention.
+        *  - On initialization, older MFWs might not indicate link change
+        *    during LFA, so we'll never get an UP indication.
+        */
+       qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up);
 
        return 0;
 }
 
 #define MFW_PORT(_p_hwfn)       ((_p_hwfn)->abs_pf_id %        \
                                 ((_p_hwfn)->cdev->num_ports_in_engines * 2))
 struct qed_mcp_info {
+       /* Spinlock used for protecting the access to the MFW mailbox */
        spinlock_t                              lock;
+
+       /* Spinlock used for syncing SW link-changes and link-changes
+        * originating from attention context.
+        */
+       spinlock_t                              link_lock;
        bool                                    block_mb_sending;
        u32                                     public_base;
        u32                                     drv_mb_addr;
 
        QED_IOV_WQ_STOP_WQ_FLAG,
        QED_IOV_WQ_FLR_FLAG,
        QED_IOV_WQ_TRUST_FLAG,
+       QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG,
 };
 
 #ifdef CONFIG_QED_SRIOV
 
 
        /* Handle bulletin board changes */
        qed_vf_read_bulletin(hwfn, &change);
+       if (test_and_clear_bit(QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG,
+                              &hwfn->iov_task_flags))
+               change = 1;
        if (change)
                qed_handle_bulletin_change(hwfn);
 
 
                     bool is_locked)
 {
        struct qed_link_params link_params;
-       struct qed_link_output link_output;
        int rc;
 
        DP_INFO(edev, "Starting qede load\n");
        link_params.link_up = true;
        edev->ops->common->set_link(edev->cdev, &link_params);
 
-       /* Query whether link is already-up */
-       memset(&link_output, 0, sizeof(link_output));
-       edev->ops->common->get_link(edev->cdev, &link_output);
        qede_roce_dev_event_open(edev);
-       qede_link_update(edev, &link_output);
 
        qede_ptp_start(edev, (mode == QEDE_LOAD_NORMAL));