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));