From 398d1e37f960f3dc688fd1887276efbe18c17329 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 24 Jan 2022 10:53:01 -0800 Subject: ionic: add FW_STOPPING state Between fw running and fw actually stopped into reset, we need a fw_stopping concept to catch and block some actions while we're transitioning to FW_RESET state. This will help to be sure the fw_up task is not scheduled until after the fw_down task has completed. On some rare occasion timing, it is possible for the fw_up task to try to run before the fw_down task, then not get run after the fw_down task has run, leaving the device in a down state. This is possible if the watchdog goes off in between finding the down transition and starting the fw_down task, where the later watchdog sees the FW is back up and schedules a fw_up task. Fixes: c672412f6172 ("ionic: remove lifs on fw reset") Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_dev.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/net/ethernet/pensando/ionic/ionic_dev.c') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 86791e0f2d72..8edbd7c30ccc 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -197,21 +197,24 @@ do_check_time: struct ionic_lif *lif = ionic->lif; bool trigger = false; - idev->fw_status_ready = fw_status_ready; - - if (!fw_status_ready) { - dev_info(ionic->dev, "FW stopped %u\n", fw_status); - if (lif && !test_bit(IONIC_LIF_F_FW_RESET, lif->state)) - trigger = true; - } else { - dev_info(ionic->dev, "FW running %u\n", fw_status); - if (lif && test_bit(IONIC_LIF_F_FW_RESET, lif->state)) - trigger = true; + if (!fw_status_ready && lif && + !test_bit(IONIC_LIF_F_FW_RESET, lif->state) && + !test_and_set_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) { + dev_info(ionic->dev, "FW stopped 0x%02x\n", fw_status); + trigger = true; + + } else if (fw_status_ready && lif && + test_bit(IONIC_LIF_F_FW_RESET, lif->state) && + !test_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) { + dev_info(ionic->dev, "FW running 0x%02x\n", fw_status); + trigger = true; } if (trigger) { struct ionic_deferred_work *work; + idev->fw_status_ready = fw_status_ready; + work = kzalloc(sizeof(*work), GFP_ATOMIC); if (work) { work->type = IONIC_DW_TYPE_LIF_RESET; @@ -221,7 +224,7 @@ do_check_time: } } - if (!fw_status_ready) + if (!idev->fw_status_ready) return -ENXIO; /* wait at least one watchdog period since the last heartbeat */ -- cgit v1.2.3