Commit 7cf6f56d authored by David S. Miller's avatar David S. Miller

Merge branch 'hns3-error-handling'

Guangbin Huang says:

====================
net: hns3: refactors and decouples the error handling logic

This patchset refactors and decouples the error handling logic from reset
logic, it is the preset patch of the RAS feature. It mainly implements the
function that reset logic remains independent of the error handling logic,
this will ensure that common misellaneous MSI-X interrupt are re-enabled
quickly.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ca4e2b94 e0fe0a38
......@@ -243,7 +243,6 @@ enum hnae3_reset_type {
HNAE3_FUNC_RESET,
HNAE3_GLOBAL_RESET,
HNAE3_IMP_RESET,
HNAE3_UNKNOWN_RESET,
HNAE3_NONE_RESET,
HNAE3_MAX_RESET,
};
......
......@@ -1940,8 +1940,8 @@ int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
if (!test_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state)) {
dev_err(dev,
"Can't handle - MSIx error reported during dev init\n");
return 0;
"failed to handle msix error during dev init\n");
return -EAGAIN;
}
return hclge_handle_all_hw_msix_error(hdev, reset_requests);
......
......@@ -2843,6 +2843,14 @@ static void hclge_reset_task_schedule(struct hclge_dev *hdev)
hclge_wq, &hdev->service_task, 0);
}
static void hclge_errhand_task_schedule(struct hclge_dev *hdev)
{
if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
!test_and_set_bit(HCLGE_STATE_ERR_SERVICE_SCHED, &hdev->state))
mod_delayed_work_on(cpumask_first(&hdev->affinity_mask),
hclge_wq, &hdev->service_task, 0);
}
void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time)
{
if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
......@@ -3394,18 +3402,8 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
/* vector 0 interrupt is shared with reset and mailbox source events.*/
switch (event_cause) {
case HCLGE_VECTOR0_EVENT_ERR:
/* we do not know what type of reset is required now. This could
* only be decided after we fetch the type of errors which
* caused this event. Therefore, we will do below for now:
* 1. Assert HNAE3_UNKNOWN_RESET type of reset. This means we
* have defered type of reset to be used.
* 2. Schedule the reset service task.
* 3. When service task receives HNAE3_UNKNOWN_RESET type it
* will fetch the correct type of reset. This would be done
* by first decoding the types of errors.
*/
set_bit(HNAE3_UNKNOWN_RESET, &hdev->reset_request);
fallthrough;
hclge_errhand_task_schedule(hdev);
break;
case HCLGE_VECTOR0_EVENT_RST:
hclge_reset_task_schedule(hdev);
break;
......@@ -3794,28 +3792,6 @@ static enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev,
enum hnae3_reset_type rst_level = HNAE3_NONE_RESET;
struct hclge_dev *hdev = ae_dev->priv;
/* first, resolve any unknown reset type to the known type(s) */
if (test_bit(HNAE3_UNKNOWN_RESET, addr)) {
u32 msix_sts_reg = hclge_read_dev(&hdev->hw,
HCLGE_MISC_VECTOR_INT_STS);
/* we will intentionally ignore any errors from this function
* as we will end up in *some* reset request in any case
*/
if (hclge_handle_hw_msix_error(hdev, addr))
dev_info(&hdev->pdev->dev, "received msix interrupt 0x%x\n",
msix_sts_reg);
clear_bit(HNAE3_UNKNOWN_RESET, addr);
/* We defered the clearing of the error event which caused
* interrupt since it was not posssible to do that in
* interrupt context (and this is the reason we introduced
* new UNKNOWN reset type). Now, the errors have been
* handled and cleared in hardware we can safely enable
* interrupts. This is an exception to the norm.
*/
hclge_enable_vector(&hdev->misc_vector, true);
}
/* return the highest priority reset level amongst all */
if (test_bit(HNAE3_IMP_RESET, addr)) {
rst_level = HNAE3_IMP_RESET;
......@@ -4264,6 +4240,36 @@ static void hclge_reset_subtask(struct hclge_dev *hdev)
hdev->reset_type = HNAE3_NONE_RESET;
}
static void hclge_misc_err_recovery(struct hclge_dev *hdev)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
struct device *dev = &hdev->pdev->dev;
u32 msix_sts_reg;
msix_sts_reg = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS);
if (msix_sts_reg & HCLGE_VECTOR0_REG_MSIX_MASK) {
if (hclge_handle_hw_msix_error(hdev,
&hdev->default_reset_request))
dev_info(dev, "received msix interrupt 0x%x\n",
msix_sts_reg);
if (hdev->default_reset_request)
if (ae_dev->ops->reset_event)
ae_dev->ops->reset_event(hdev->pdev, NULL);
}
hclge_enable_vector(&hdev->misc_vector, true);
}
static void hclge_errhand_service_task(struct hclge_dev *hdev)
{
if (!test_and_clear_bit(HCLGE_STATE_ERR_SERVICE_SCHED, &hdev->state))
return;
hclge_misc_err_recovery(hdev);
}
static void hclge_reset_service_task(struct hclge_dev *hdev)
{
if (!test_and_clear_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
......@@ -4347,14 +4353,16 @@ static void hclge_service_task(struct work_struct *work)
struct hclge_dev *hdev =
container_of(work, struct hclge_dev, service_task.work);
hclge_errhand_service_task(hdev);
hclge_reset_service_task(hdev);
hclge_mailbox_service_task(hdev);
hclge_periodic_service_task(hdev);
/* Handle reset and mbx again in case periodical task delays the
* handling by calling hclge_task_schedule() in
/* Handle error recovery, reset and mbx again in case periodical task
* delays the handling by calling hclge_task_schedule() in
* hclge_periodic_service_task().
*/
hclge_errhand_service_task(hdev);
hclge_reset_service_task(hdev);
hclge_mailbox_service_task(hdev);
}
......
......@@ -221,6 +221,7 @@ enum HCLGE_DEV_STATE {
HCLGE_STATE_RST_HANDLING,
HCLGE_STATE_MBX_SERVICE_SCHED,
HCLGE_STATE_MBX_HANDLING,
HCLGE_STATE_ERR_SERVICE_SCHED,
HCLGE_STATE_STATISTICS_UPDATING,
HCLGE_STATE_CMD_DISABLE,
HCLGE_STATE_LINK_UPDATING,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment