crypto: hisilicon/qm - update reset flow
This patch updates the reset flow based on PF/VF communications. VFs will be stopped after receiving reset message from PF, and wait for reset finish to restart VFs. Signed-off-by: Weili Qian <qianweili@huawei.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
3cd53a27c2
commit
760fe22cf5
@ -201,7 +201,10 @@
|
||||
#define QM_WAIT_DST_ACK 10
|
||||
#define QM_MAX_PF_WAIT_COUNT 10
|
||||
#define QM_MAX_VF_WAIT_COUNT 40
|
||||
|
||||
#define QM_VF_RESET_WAIT_US 20000
|
||||
#define QM_VF_RESET_WAIT_CNT 3000
|
||||
#define QM_VF_RESET_WAIT_TIMEOUT_US \
|
||||
(QM_VF_RESET_WAIT_US * QM_VF_RESET_WAIT_CNT)
|
||||
|
||||
#define QM_DFX_MB_CNT_VF 0x104010
|
||||
#define QM_DFX_DB_CNT_VF 0x104020
|
||||
@ -285,6 +288,16 @@ enum acc_err_result {
|
||||
ACC_ERR_RECOVERED,
|
||||
};
|
||||
|
||||
enum qm_mb_cmd {
|
||||
QM_PF_FLR_PREPARE = 0x01,
|
||||
QM_PF_SRST_PREPARE,
|
||||
QM_PF_RESET_DONE,
|
||||
QM_VF_PREPARE_DONE,
|
||||
QM_VF_PREPARE_FAIL,
|
||||
QM_VF_START_DONE,
|
||||
QM_VF_START_FAIL,
|
||||
};
|
||||
|
||||
struct qm_cqe {
|
||||
__le32 rsvd0;
|
||||
__le16 cmd_id;
|
||||
@ -1890,9 +1903,74 @@ static void qm_clear_cmd_interrupt(struct hisi_qm *qm, u64 vf_mask)
|
||||
writel(val, qm->io_base + QM_IFC_INT_SOURCE_V);
|
||||
}
|
||||
|
||||
static void qm_handle_vf_msg(struct hisi_qm *qm, u32 vf_id)
|
||||
{
|
||||
struct device *dev = &qm->pdev->dev;
|
||||
u32 cmd;
|
||||
u64 msg;
|
||||
int ret;
|
||||
|
||||
ret = qm_get_mb_cmd(qm, &msg, vf_id);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get msg from VF(%u)!\n", vf_id);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = msg & QM_MB_CMD_DATA_MASK;
|
||||
switch (cmd) {
|
||||
case QM_VF_PREPARE_FAIL:
|
||||
dev_err(dev, "failed to stop VF(%u)!\n", vf_id);
|
||||
break;
|
||||
case QM_VF_START_FAIL:
|
||||
dev_err(dev, "failed to start VF(%u)!\n", vf_id);
|
||||
break;
|
||||
case QM_VF_PREPARE_DONE:
|
||||
case QM_VF_START_DONE:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported cmd %u sent by VF(%u)!\n", cmd, vf_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int qm_wait_vf_prepare_finish(struct hisi_qm *qm)
|
||||
{
|
||||
return 0;
|
||||
struct device *dev = &qm->pdev->dev;
|
||||
u32 vfs_num = qm->vfs_num;
|
||||
int cnt = 0;
|
||||
int ret = 0;
|
||||
u64 val;
|
||||
u32 i;
|
||||
|
||||
if (!qm->vfs_num || qm->ver < QM_HW_V3)
|
||||
return 0;
|
||||
|
||||
while (true) {
|
||||
val = readq(qm->io_base + QM_IFC_INT_SOURCE_P);
|
||||
/* All VFs send command to PF, break */
|
||||
if ((val & GENMASK(vfs_num, 1)) == GENMASK(vfs_num, 1))
|
||||
break;
|
||||
|
||||
if (++cnt > QM_MAX_PF_WAIT_COUNT) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
msleep(QM_WAIT_DST_ACK);
|
||||
}
|
||||
|
||||
/* PF check VFs msg */
|
||||
for (i = 1; i <= vfs_num; i++) {
|
||||
if (val & BIT(i))
|
||||
qm_handle_vf_msg(qm, i);
|
||||
else
|
||||
dev_err(dev, "VF(%u) not ping PF!\n", i);
|
||||
}
|
||||
|
||||
/* PF clear interrupt to ack VFs */
|
||||
qm_clear_cmd_interrupt(qm, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qm_trigger_vf_interrupt(struct hisi_qm *qm, u32 fun_num)
|
||||
@ -4038,7 +4116,8 @@ stop_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qm_try_stop_vfs(struct hisi_qm *qm, enum qm_stop_reason stop_reason)
|
||||
static int qm_try_stop_vfs(struct hisi_qm *qm, u64 cmd,
|
||||
enum qm_stop_reason stop_reason)
|
||||
{
|
||||
struct pci_dev *pdev = qm->pdev;
|
||||
int ret;
|
||||
@ -4046,9 +4125,16 @@ static int qm_try_stop_vfs(struct hisi_qm *qm, enum qm_stop_reason stop_reason)
|
||||
if (!qm->vfs_num)
|
||||
return 0;
|
||||
|
||||
ret = qm_vf_reset_prepare(qm, stop_reason);
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to prepare reset, ret = %d.\n", ret);
|
||||
/* Kunpeng930 supports to notify VFs to stop before PF reset */
|
||||
if (qm->ops->ping_all_vfs) {
|
||||
ret = qm->ops->ping_all_vfs(qm, cmd);
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to send cmd to all VFs before PF reset!\n");
|
||||
} else {
|
||||
ret = qm_vf_reset_prepare(qm, stop_reason);
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to prepare reset, ret = %d.\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -4072,7 +4158,14 @@ static int qm_reset_prepare_ready(struct hisi_qm *qm)
|
||||
struct pci_dev *pdev = qm->pdev;
|
||||
struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
|
||||
|
||||
return qm_wait_reset_finish(pf_qm);
|
||||
/*
|
||||
* PF and VF on host doesnot support resetting at the
|
||||
* same time on Kunpeng920.
|
||||
*/
|
||||
if (qm->ver < QM_HW_V3)
|
||||
return qm_wait_reset_finish(pf_qm);
|
||||
|
||||
return qm_wait_reset_finish(qm);
|
||||
}
|
||||
|
||||
static void qm_reset_bit_clear(struct hisi_qm *qm)
|
||||
@ -4080,7 +4173,10 @@ static void qm_reset_bit_clear(struct hisi_qm *qm)
|
||||
struct pci_dev *pdev = qm->pdev;
|
||||
struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
|
||||
|
||||
clear_bit(QM_RESETTING, &pf_qm->misc_ctl);
|
||||
if (qm->ver < QM_HW_V3)
|
||||
clear_bit(QM_RESETTING, &pf_qm->misc_ctl);
|
||||
|
||||
clear_bit(QM_RESETTING, &qm->misc_ctl);
|
||||
}
|
||||
|
||||
static int qm_controller_reset_prepare(struct hisi_qm *qm)
|
||||
@ -4094,7 +4190,11 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qm_try_stop_vfs(qm, QM_SOFT_RESET);
|
||||
/* PF obtains the information of VF by querying the register. */
|
||||
qm_cmd_uninit(qm);
|
||||
|
||||
/* Whether VFs stop successfully, soft reset will continue. */
|
||||
ret = qm_try_stop_vfs(qm, QM_PF_SRST_PREPARE, QM_SOFT_RESET);
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to stop vfs by pf in soft reset.\n");
|
||||
|
||||
@ -4243,7 +4343,7 @@ restart_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qm_try_start_vfs(struct hisi_qm *qm)
|
||||
static int qm_try_start_vfs(struct hisi_qm *qm, enum qm_mb_cmd cmd)
|
||||
{
|
||||
struct pci_dev *pdev = qm->pdev;
|
||||
int ret;
|
||||
@ -4257,9 +4357,16 @@ static int qm_try_start_vfs(struct hisi_qm *qm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qm_vf_reset_done(qm);
|
||||
if (ret)
|
||||
pci_warn(pdev, "failed to start vfs, ret = %d.\n", ret);
|
||||
/* Kunpeng930 supports to notify VFs to start after PF reset. */
|
||||
if (qm->ops->ping_all_vfs) {
|
||||
ret = qm->ops->ping_all_vfs(qm, cmd);
|
||||
if (ret)
|
||||
pci_warn(pdev, "failed to send cmd to all VFs after PF reset!\n");
|
||||
} else {
|
||||
ret = qm_vf_reset_done(qm);
|
||||
if (ret)
|
||||
pci_warn(pdev, "failed to start vfs, ret = %d.\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -4363,7 +4470,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qm_try_start_vfs(qm);
|
||||
ret = qm_try_start_vfs(qm, QM_PF_RESET_DONE);
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to start vfs by pf in soft reset.\n");
|
||||
|
||||
@ -4371,6 +4478,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to start by vfs in soft reset!\n");
|
||||
|
||||
qm_cmd_init(qm);
|
||||
qm_restart_done(qm);
|
||||
|
||||
qm_reset_bit_clear(qm);
|
||||
@ -4462,7 +4570,11 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
|
||||
return;
|
||||
}
|
||||
|
||||
ret = qm_try_stop_vfs(qm, QM_SOFT_RESET);
|
||||
/* PF obtains the information of VF by querying the register. */
|
||||
if (qm->fun_type == QM_HW_PF)
|
||||
qm_cmd_uninit(qm);
|
||||
|
||||
ret = qm_try_stop_vfs(qm, QM_PF_FLR_PREPARE, QM_FLR);
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to stop vfs by pf in FLR.\n");
|
||||
|
||||
@ -4517,7 +4629,7 @@ void hisi_qm_reset_done(struct pci_dev *pdev)
|
||||
goto flr_done;
|
||||
}
|
||||
|
||||
ret = qm_try_start_vfs(qm);
|
||||
ret = qm_try_start_vfs(qm, QM_PF_RESET_DONE);
|
||||
if (ret)
|
||||
pci_err(pdev, "failed to start vfs by pf in FLR.\n");
|
||||
|
||||
@ -4526,6 +4638,9 @@ void hisi_qm_reset_done(struct pci_dev *pdev)
|
||||
pci_err(pdev, "failed to start by vfs in FLR!\n");
|
||||
|
||||
flr_done:
|
||||
if (qm->fun_type == QM_HW_PF)
|
||||
qm_cmd_init(qm);
|
||||
|
||||
if (qm_flr_reset_complete(pdev))
|
||||
pci_info(pdev, "FLR reset complete\n");
|
||||
|
||||
@ -4621,12 +4736,128 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work)
|
||||
|
||||
}
|
||||
|
||||
static void qm_pf_reset_vf_prepare(struct hisi_qm *qm,
|
||||
enum qm_stop_reason stop_reason)
|
||||
{
|
||||
enum qm_mb_cmd cmd = QM_VF_PREPARE_DONE;
|
||||
struct pci_dev *pdev = qm->pdev;
|
||||
int ret;
|
||||
|
||||
ret = qm_reset_prepare_ready(qm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "reset prepare not ready!\n");
|
||||
atomic_set(&qm->status.flags, QM_STOP);
|
||||
cmd = QM_VF_PREPARE_FAIL;
|
||||
goto err_prepare;
|
||||
}
|
||||
|
||||
ret = hisi_qm_stop(qm, stop_reason);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to stop QM, ret = %d.\n", ret);
|
||||
atomic_set(&qm->status.flags, QM_STOP);
|
||||
cmd = QM_VF_PREPARE_FAIL;
|
||||
goto err_prepare;
|
||||
}
|
||||
|
||||
err_prepare:
|
||||
pci_save_state(pdev);
|
||||
ret = qm->ops->ping_pf(qm, cmd);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "PF responds timeout in reset prepare!\n");
|
||||
}
|
||||
|
||||
static void qm_pf_reset_vf_done(struct hisi_qm *qm)
|
||||
{
|
||||
enum qm_mb_cmd cmd = QM_VF_START_DONE;
|
||||
struct pci_dev *pdev = qm->pdev;
|
||||
int ret;
|
||||
|
||||
pci_restore_state(pdev);
|
||||
ret = hisi_qm_start(qm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to start QM, ret = %d.\n", ret);
|
||||
cmd = QM_VF_START_FAIL;
|
||||
}
|
||||
|
||||
ret = qm->ops->ping_pf(qm, cmd);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "PF responds timeout in reset done!\n");
|
||||
|
||||
qm_reset_bit_clear(qm);
|
||||
}
|
||||
|
||||
static int qm_wait_pf_reset_finish(struct hisi_qm *qm)
|
||||
{
|
||||
struct device *dev = &qm->pdev->dev;
|
||||
u32 val, cmd;
|
||||
u64 msg;
|
||||
int ret;
|
||||
|
||||
/* Wait for reset to finish */
|
||||
ret = readl_relaxed_poll_timeout(qm->io_base + QM_IFC_INT_SOURCE_V, val,
|
||||
val == BIT(0), QM_VF_RESET_WAIT_US,
|
||||
QM_VF_RESET_WAIT_TIMEOUT_US);
|
||||
/* hardware completion status should be available by this time */
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't get reset done status from PF, timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether message is got successfully,
|
||||
* VF needs to ack PF by clearing the interrupt.
|
||||
*/
|
||||
ret = qm_get_mb_cmd(qm, &msg, 0);
|
||||
qm_clear_cmd_interrupt(qm, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get msg from PF in reset done!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd = msg & QM_MB_CMD_DATA_MASK;
|
||||
if (cmd != QM_PF_RESET_DONE) {
|
||||
dev_err(dev, "the cmd(%u) is not reset done!\n", cmd);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qm_pf_reset_vf_process(struct hisi_qm *qm,
|
||||
enum qm_stop_reason stop_reason)
|
||||
{
|
||||
struct device *dev = &qm->pdev->dev;
|
||||
int ret;
|
||||
|
||||
dev_info(dev, "device reset start...\n");
|
||||
|
||||
/* The message is obtained by querying the register during resetting */
|
||||
qm_cmd_uninit(qm);
|
||||
qm_pf_reset_vf_prepare(qm, stop_reason);
|
||||
|
||||
ret = qm_wait_pf_reset_finish(qm);
|
||||
if (ret)
|
||||
goto err_get_status;
|
||||
|
||||
qm_pf_reset_vf_done(qm);
|
||||
qm_cmd_init(qm);
|
||||
|
||||
dev_info(dev, "device reset done.\n");
|
||||
|
||||
return;
|
||||
|
||||
err_get_status:
|
||||
qm_cmd_init(qm);
|
||||
qm_reset_bit_clear(qm);
|
||||
}
|
||||
|
||||
static void qm_cmd_process(struct work_struct *cmd_process)
|
||||
{
|
||||
struct hisi_qm *qm = container_of(cmd_process,
|
||||
struct hisi_qm, cmd_process);
|
||||
struct device *dev = &qm->pdev->dev;
|
||||
u64 msg;
|
||||
u32 cmd;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -4635,9 +4866,23 @@ static void qm_cmd_process(struct work_struct *cmd_process)
|
||||
*/
|
||||
ret = qm_get_mb_cmd(qm, &msg, 0);
|
||||
qm_clear_cmd_interrupt(qm, 0);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get msg from source!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = msg & QM_MB_CMD_DATA_MASK;
|
||||
switch (cmd) {
|
||||
case QM_PF_FLR_PREPARE:
|
||||
qm_pf_reset_vf_process(qm, QM_FLR);
|
||||
break;
|
||||
case QM_PF_SRST_PREPARE:
|
||||
qm_pf_reset_vf_process(qm, QM_SOFT_RESET);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported cmd %u sent by PF!\n", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user