get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/971932/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 971932,
    "url": "http://patchwork.ozlabs.org/api/patches/971932/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180919203459.17064-1-jeffrey.t.kirsher@intel.com/",
    "project": {
        "id": 46,
        "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api",
        "name": "Intel Wired Ethernet development",
        "link_name": "intel-wired-lan",
        "list_id": "intel-wired-lan.osuosl.org",
        "list_email": "intel-wired-lan@osuosl.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20180919203459.17064-1-jeffrey.t.kirsher@intel.com>",
    "list_archive_url": null,
    "date": "2018-09-19T20:34:59",
    "name": "[v3] i40e: Introduce recovery mode support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "e4742cb067ae9783d4b9a5275acf8af65d3cdd2f",
    "submitter": {
        "id": 473,
        "url": "http://patchwork.ozlabs.org/api/people/473/?format=api",
        "name": "Kirsher, Jeffrey T",
        "email": "jeffrey.t.kirsher@intel.com"
    },
    "delegate": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/users/68/?format=api",
        "username": "jtkirshe",
        "first_name": "Jeff",
        "last_name": "Kirsher",
        "email": "jeffrey.t.kirsher@intel.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180919203459.17064-1-jeffrey.t.kirsher@intel.com/mbox/",
    "series": [
        {
            "id": 66491,
            "url": "http://patchwork.ozlabs.org/api/series/66491/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=66491",
            "date": "2018-09-19T20:34:59",
            "name": "[v3] i40e: Introduce recovery mode support",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/66491/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/971932/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/971932/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<intel-wired-lan-bounces@osuosl.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.137; helo=fraxinus.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org;\n\tdmarc=fail (p=none dis=none) header.from=intel.com"
        ],
        "Received": [
            "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 42Fs731cqWz9sCP\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 20 Sep 2018 06:35:10 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id DB773874D4;\n\tWed, 19 Sep 2018 20:35:08 +0000 (UTC)",
            "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id zHyWYsV0xU7a; Wed, 19 Sep 2018 20:35:07 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 5B5B1874BC;\n\tWed, 19 Sep 2018 20:35:07 +0000 (UTC)",
            "from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\tby ash.osuosl.org (Postfix) with ESMTP id 6A4691C11EB\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 19 Sep 2018 20:35:06 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 6664687FDC\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 19 Sep 2018 20:35:06 +0000 (UTC)",
            "from whitealder.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id L1LXmwDQAtf5 for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 19 Sep 2018 20:35:05 +0000 (UTC)",
            "from mga12.intel.com (mga12.intel.com [192.55.52.136])\n\tby whitealder.osuosl.org (Postfix) with ESMTPS id E2F1687FAF\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 19 Sep 2018 20:35:04 +0000 (UTC)",
            "from fmsmga008.fm.intel.com ([10.253.24.58])\n\tby fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t19 Sep 2018 13:35:03 -0700",
            "from jtkirshe-desk1.jf.intel.com ([134.134.177.96])\n\tby fmsmga008.fm.intel.com with ESMTP; 19 Sep 2018 13:35:03 -0700"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6",
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.53,395,1531810800\"; d=\"scan'208\";a=\"72169223\"",
        "From": "Jeff Kirsher <jeffrey.t.kirsher@intel.com>",
        "To": "intel-wired-lan@lists.osuosl.org",
        "Date": "Wed, 19 Sep 2018 13:34:59 -0700",
        "Message-Id": "<20180919203459.17064-1-jeffrey.t.kirsher@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "Subject": "[Intel-wired-lan] [PATCH v3] i40e: Introduce recovery mode support",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.24",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>",
        "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>",
        "List-Post": "<mailto:intel-wired-lan@osuosl.org>",
        "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>",
        "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "intel-wired-lan-bounces@osuosl.org",
        "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"
    },
    "content": "From: Alice Michael <alice.michael@intel.com>\n\nThis patch introduces \"recovery mode\" to the i40e driver. It is\npart of a new Any2Any idea of upgrading the firmware. In this\napproach, it is required for the driver to have support for\n\"transition firmware\", that is used for migrating from structured\nto flat firmware image. In this new, very basic mode, i40e driver\nmust be able to handle particular IOCTL calls from the NVM Update\nTool and run a small set of AQ commands.\n\nSigned-off-by: Alice Michael <alice.michael@intel.com>\n---\nv2: combined all the patches in Series 94 into one patch since all of\nthe patches in the series were either introducing the recovery mode\nsupport or were fixing the recovery mode.  Thanks to  Shannon Nelson\nfor pointing this out.\nAlso fixed where we forgot to set vsi->netdev to NULL after calling\nfree_netdev().\n\nv3: Fixed up code comments and style based on feedback from Shannon\nNelson.  Also fixed up a conflict which occurred due to changes to the\ndriver since this patch was last submitted.\n\n drivers/net/ethernet/intel/i40e/i40e.h        |   1 +\n .../net/ethernet/intel/i40e/i40e_ethtool.c    |  14 +-\n drivers/net/ethernet/intel/i40e/i40e_main.c   | 326 ++++++++++++++++--\n 3 files changed, 308 insertions(+), 33 deletions(-)",
    "diff": "diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\nindex 876cac317e79..11f0987f16c7 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e.h\n@@ -140,6 +140,7 @@ enum i40e_state_t {\n \t__I40E_RESET_FAILED,\n \t__I40E_PORT_SUSPENDED,\n \t__I40E_VF_DISABLE,\n+\t__I40E_RECOVERY_MODE,\n \t__I40E_MACVLAN_SYNC_PENDING,\n \t__I40E_UDP_FILTER_SYNC_PENDING,\n \t__I40E_TEMP_LINK_POLLING,\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c\nindex 9f8464f80783..f35a26c39d7a 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c\n@@ -4904,6 +4904,12 @@ static int i40e_get_module_eeprom(struct net_device *netdev,\n \treturn 0;\n }\n \n+static const struct ethtool_ops i40e_ethtool_recovery_mode_ops = {\n+\t.set_eeprom\t\t= i40e_set_eeprom,\n+\t.get_eeprom_len\t\t= i40e_get_eeprom_len,\n+\t.get_eeprom\t\t= i40e_get_eeprom,\n+};\n+\n static const struct ethtool_ops i40e_ethtool_ops = {\n \t.get_drvinfo\t\t= i40e_get_drvinfo,\n \t.get_regs_len\t\t= i40e_get_regs_len,\n@@ -4949,5 +4955,11 @@ static const struct ethtool_ops i40e_ethtool_ops = {\n \n void i40e_set_ethtool_ops(struct net_device *netdev)\n {\n-\tnetdev->ethtool_ops = &i40e_ethtool_ops;\n+\tstruct i40e_netdev_priv *np = netdev_priv(netdev);\n+\tstruct i40e_pf\t\t*pf = np->vsi->back;\n+\n+\tif (!test_bit(__I40E_RECOVERY_MODE, pf->state))\n+\t\tnetdev->ethtool_ops = &i40e_ethtool_ops;\n+\telse\n+\t\tnetdev->ethtool_ops = &i40e_ethtool_recovery_mode_ops;\n }\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\nindex 330bafe6a689..eb3ea9e630ee 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n@@ -46,6 +46,10 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf);\n static void i40e_prep_for_reset(struct i40e_pf *pf, bool lock_acquired);\n static int i40e_reset(struct i40e_pf *pf);\n static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);\n+static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf);\n+static int i40e_restore_interrupt_scheme(struct i40e_pf *pf);\n+static bool i40e_check_recovery_mode(struct i40e_pf *pf);\n+static int i40e_init_recovery_mode(struct i40e_pf *pf, struct i40e_hw *hw);\n static void i40e_fdir_sb_setup(struct i40e_pf *pf);\n static int i40e_veb_get_bw_info(struct i40e_veb *veb);\n static int i40e_get_capabilities(struct i40e_pf *pf,\n@@ -278,8 +282,9 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id)\n  **/\n void i40e_service_event_schedule(struct i40e_pf *pf)\n {\n-\tif (!test_bit(__I40E_DOWN, pf->state) &&\n-\t    !test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))\n+\tif ((!test_bit(__I40E_DOWN, pf->state) &&\n+\t     !test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) ||\n+\t      test_bit(__I40E_RECOVERY_MODE, pf->state))\n \t\tqueue_work(i40e_wq, &pf->service_task);\n }\n \n@@ -3974,7 +3979,8 @@ static irqreturn_t i40e_intr(int irq, void *data)\n enable_intr:\n \t/* re-enable interrupt causes */\n \twr32(hw, I40E_PFINT_ICR0_ENA, ena_mask);\n-\tif (!test_bit(__I40E_DOWN, pf->state)) {\n+\tif (!test_bit(__I40E_DOWN, pf->state) ||\n+\t    test_bit(__I40E_RECOVERY_MODE, pf->state)) {\n \t\ti40e_service_event_schedule(pf);\n \t\ti40e_irq_dynamic_enable_icr0(pf);\n \t}\n@@ -9393,6 +9399,7 @@ static int i40e_reset(struct i40e_pf *pf)\n  **/\n static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n {\n+\tint old_recovery_mode_bit = test_bit(__I40E_RECOVERY_MODE, pf->state);\n \tstruct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];\n \tstruct i40e_hw *hw = &pf->hw;\n \tu8 set_fc_aq_fail = 0;\n@@ -9400,7 +9407,14 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n \tu32 val;\n \tint v;\n \n-\tif (test_bit(__I40E_DOWN, pf->state))\n+\tif (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&\n+\t    i40e_check_recovery_mode(pf)) {\n+\t\ti40e_set_ethtool_ops(pf->vsi[pf->lan_vsi]->netdev);\n+\t}\n+\n+\tif (test_bit(__I40E_DOWN, pf->state) &&\n+\t    !test_bit(__I40E_RECOVERY_MODE, pf->state) &&\n+\t    !old_recovery_mode_bit)\n \t\tgoto clear_recovery;\n \tdev_dbg(&pf->pdev->dev, \"Rebuilding internal switch\\n\");\n \n@@ -9429,6 +9443,44 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n \tif (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state))\n \t\ti40e_verify_eeprom(pf);\n \n+\t/* if we are going out of or into recovery mode we have to act\n+\t * accordingly with regard to resources initialization\n+\t * and deinitialization\n+\t */\n+\tif (test_bit(__I40E_RECOVERY_MODE, pf->state) ||\n+\t    old_recovery_mode_bit) {\n+\t\tif (i40e_get_capabilities(pf,\n+\t\t\t\t\t  i40e_aqc_opc_list_func_capabilities))\n+\t\t\tgoto end_unlock;\n+\n+\t\tif (test_bit(__I40E_RECOVERY_MODE, pf->state)) {\n+\t\t\t/* we're staying in recovery mode so we'll reinitialize\n+\t\t\t * misc vector here\n+\t\t\t */\n+\t\t\tif (i40e_setup_misc_vector_for_recovery_mode(pf))\n+\t\t\t\tgoto end_unlock;\n+\t\t} else {\n+\t\t\tif (!lock_acquired)\n+\t\t\t\trtnl_lock();\n+\t\t\t/* we're going out of recovery mode so we'll free\n+\t\t\t * the IRQ allocated specifically for recovery mode\n+\t\t\t * and restore the interrupt scheme\n+\t\t\t */\n+\t\t\tfree_irq(pf->pdev->irq, pf);\n+\t\t\ti40e_clear_interrupt_scheme(pf);\n+\t\t\tif (i40e_restore_interrupt_scheme(pf))\n+\t\t\t\tgoto end_unlock;\n+\t\t}\n+\n+\t\t/* tell the firmware that we're starting */\n+\t\ti40e_send_version(pf);\n+\n+\t\t/* bail out in case recovery mode was detected, as there is\n+\t\t * no need for further configuration.\n+\t\t */\n+\t\tgoto end_unlock;\n+\t}\n+\n \ti40e_clear_pxe_mode(hw);\n \tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n \tif (ret)\n@@ -9895,25 +9947,31 @@ static void i40e_service_task(struct work_struct *work)\n \tif (test_and_set_bit(__I40E_SERVICE_SCHED, pf->state))\n \t\treturn;\n \n-\ti40e_detect_recover_hung(pf->vsi[pf->lan_vsi]);\n-\ti40e_sync_filters_subtask(pf);\n-\ti40e_reset_subtask(pf);\n-\ti40e_handle_mdd_event(pf);\n-\ti40e_vc_process_vflr_event(pf);\n-\ti40e_watchdog_subtask(pf);\n-\ti40e_fdir_reinit_subtask(pf);\n-\tif (test_and_clear_bit(__I40E_CLIENT_RESET, pf->state)) {\n-\t\t/* Client subtask will reopen next time through. */\n-\t\ti40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], true);\n-\t} else {\n-\t\ti40e_client_subtask(pf);\n-\t\tif (test_and_clear_bit(__I40E_CLIENT_L2_CHANGE,\n-\t\t\t\t       pf->state))\n-\t\t\ti40e_notify_client_of_l2_param_changes(\n+\tif (!test_bit(__I40E_RECOVERY_MODE, pf->state)) {\n+\t\ti40e_detect_recover_hung(pf->vsi[pf->lan_vsi]);\n+\t\ti40e_sync_filters_subtask(pf);\n+\t\ti40e_reset_subtask(pf);\n+\t\ti40e_handle_mdd_event(pf);\n+\t\ti40e_vc_process_vflr_event(pf);\n+\t\ti40e_watchdog_subtask(pf);\n+\t\ti40e_fdir_reinit_subtask(pf);\n+\t\tif (test_and_clear_bit(__I40E_CLIENT_RESET, pf->state)) {\n+\t\t\t/* Client subtask will reopen next time through. */\n+\t\t\ti40e_notify_client_of_netdev_close(\n+\t\t\t\t\t\tpf->vsi[pf->lan_vsi], true);\n+\t\t} else {\n+\t\t\ti40e_client_subtask(pf);\n+\t\t\tif (test_and_clear_bit(__I40E_CLIENT_L2_CHANGE,\n+\t\t\t\t\t       pf->state))\n+\t\t\t\ti40e_notify_client_of_l2_param_changes(\n \t\t\t\t\t\t\tpf->vsi[pf->lan_vsi]);\n+\t\t}\n+\t\ti40e_sync_udp_filters_subtask(pf);\n+\n+\t} else {\n+\t\ti40e_reset_subtask(pf);\n \t}\n \ti40e_sync_filters_subtask(pf);\n-\ti40e_sync_udp_filters_subtask(pf);\n \ti40e_clean_adminq_subtask(pf);\n \n \t/* flush memory to make sure state is correct before next watchdog */\n@@ -10727,6 +10785,47 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)\n \treturn err;\n }\n \n+/**\n+ * i40e_setup_misc_vector_for_recovery_mode - Setup misc vector in recovery mode\n+ * @pf: board private structure\n+ *\n+ * This sets up the handler for MSIX 0 or MSI/legacy, which is used to manage\n+ * the non-queue interrupts, e.g. AdminQ and errors in recovery mode.\n+ * This is handled differently than in recovery mode since no Tx/Rx resources\n+ * are being allocated.\n+ **/\n+static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf)\n+{\n+\tint err;\n+\n+\tif (pf->flags & I40E_FLAG_MSIX_ENABLED) {\n+\t\terr = i40e_setup_misc_vector(pf);\n+\n+\t\tif (err) {\n+\t\t\tdev_info(&pf->pdev->dev,\n+\t\t\t\t \"MSI-X misc vector request failed, error %d\\n\",\n+\t\t\t\t err);\n+\t\t\treturn err;\n+\t\t}\n+\t} else {\n+\t\tu32 flags = pf->flags & I40E_FLAG_MSI_ENABLED ? 0 : IRQF_SHARED;\n+\n+\t\terr = request_irq(pf->pdev->irq, i40e_intr, flags,\n+\t\t\t\t  pf->int_name, pf);\n+\n+\t\tif (err) {\n+\t\t\tdev_info(&pf->pdev->dev,\n+\t\t\t\t \"MSI/legacy misc vector request failed, error %d\\n\",\n+\t\t\t\t err);\n+\t\t\treturn err;\n+\t\t}\n+\t\ti40e_enable_misc_int_causes(pf);\n+\t\ti40e_irq_dynamic_enable_icr0(pf);\n+\t}\n+\n+\treturn 0;\n+}\n+\n /**\n  * i40e_setup_misc_vector - Setup the misc vector to handle non queue events\n  * @pf: board private structure\n@@ -13848,6 +13947,127 @@ static void i40e_get_platform_mac_addr(struct pci_dev *pdev, struct i40e_pf *pf)\n \t\ti40e_get_mac_addr(&pf->hw, pf->hw.mac.addr);\n }\n \n+/**\n+ * i40e_check_recovery_mode - check if we are running transition firmware\n+ * @pf: board private structure\n+ *\n+ * Check registers indicating the firmware runs in recovery mode. Sets the\n+ * appropriate driver state.\n+ *\n+ * Returns true if the recovery mode was detected, false otherwise\n+ **/\n+static bool i40e_check_recovery_mode(struct i40e_pf *pf)\n+{\n+\tu32 val = rd32(&pf->hw, I40E_GL_FWSTS);\n+\n+\tif (val & I40E_GL_FWSTS_FWS1B_MASK) {\n+\t\tdev_notice(&pf->pdev->dev, \"Firmware recovery mode detected. Limiting functionality.\\n\");\n+\t\tdev_notice(&pf->pdev->dev, \"Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\\n\");\n+\t\tset_bit(__I40E_RECOVERY_MODE, pf->state);\n+\n+\t\treturn true;\n+\t}\n+\tif (test_and_clear_bit(__I40E_RECOVERY_MODE, pf->state))\n+\t\tdev_info(&pf->pdev->dev, \"Reinitializing in normal mode with full functionality.\\n\");\n+\n+\treturn false;\n+}\n+\n+/**\n+ * i40e_init_recovery_mode - initialize subsystems needed in recovery mode\n+ * @pf: board private structure\n+ * @hw: ptr to the hardware info\n+ *\n+ * This function does a minimal setup of all subsystems needed for running\n+ * recovery mode.\n+ *\n+ * Returns 0 on success, negative on failure\n+ **/\n+static int i40e_init_recovery_mode(struct i40e_pf *pf, struct i40e_hw *hw)\n+{\n+\tstruct i40e_vsi *vsi;\n+\tint v_idx;\n+\tint err;\n+\n+\tpci_save_state(pf->pdev);\n+\n+\t/* set up periodic task facility */\n+\ttimer_setup(&pf->service_timer, i40e_service_timer, (unsigned long)pf);\n+\tpf->service_timer_period = HZ;\n+\n+\tINIT_WORK(&pf->service_task, i40e_service_task);\n+\tclear_bit(__I40E_SERVICE_SCHED, pf->state);\n+\n+\terr = i40e_init_interrupt_scheme(pf);\n+\tif (err)\n+\t\tgoto err_switch_setup;\n+\n+\t/* The number of VSIs reported by the FW is the minimum guaranteed\n+\t * to us; HW supports far more and we share the remaining pool with\n+\t * the other PFs. We allocate space for more than the guarantee with\n+\t * the understanding that we might not get them all later.\n+\t */\n+\tif (pf->hw.func_caps.num_vsis < I40E_MIN_VSI_ALLOC)\n+\t\tpf->num_alloc_vsi = I40E_MIN_VSI_ALLOC;\n+\telse\n+\t\tpf->num_alloc_vsi = pf->hw.func_caps.num_vsis;\n+\n+\t/* Set up the vsi struct and our local tracking of the MAIN PF vsi. */\n+\tpf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),\n+\t\t\t  GFP_KERNEL);\n+\tif (!pf->vsi) {\n+\t\terr = -ENOMEM;\n+\t\tgoto err_switch_setup;\n+\t}\n+\n+\t/* We allocate one VSI which is needed as absolute minimum\n+\t * in order to register the netdev\n+\t */\n+\tv_idx = i40e_vsi_mem_alloc(pf, I40E_VSI_MAIN);\n+\tif (v_idx < 0)\n+\t\tgoto err_switch_setup;\n+\tpf->lan_vsi = v_idx;\n+\tvsi = pf->vsi[v_idx];\n+\tif (!vsi)\n+\t\tgoto err_switch_setup;\n+\tvsi->alloc_queue_pairs = 1;\n+\terr = i40e_config_netdev(vsi);\n+\tif (err)\n+\t\tgoto err_switch_setup;\n+\terr = register_netdev(vsi->netdev);\n+\tif (err)\n+\t\tgoto err_switch_setup;\n+\tvsi->netdev_registered = true;\n+\ti40e_dbg_pf_init(pf);\n+\n+\terr = i40e_setup_misc_vector_for_recovery_mode(pf);\n+\tif (err)\n+\t\tgoto err_switch_setup;\n+\n+\t/* tell the firmware that we're starting */\n+\ti40e_send_version(pf);\n+\n+\t/* since everything's happy, start the service_task timer */\n+\tmod_timer(&pf->service_timer,\n+\t\t  round_jiffies(jiffies + pf->service_timer_period));\n+\n+\treturn 0;\n+\n+err_switch_setup:\n+\ti40e_reset_interrupt_capability(pf);\n+\tdel_timer_sync(&pf->service_timer);\n+\ti40e_shutdown_adminq(hw);\n+\tiounmap(hw->hw_addr);\n+\tpci_disable_pcie_error_reporting(pf->pdev);\n+\tpci_release_selected_regions(pf->pdev,\n+\t\t\t\t     pci_select_bars(pf->pdev,\n+\t\t\t\t\t\t     IORESOURCE_MEM));\n+\tpci_disable_device(pf->pdev);\n+\tkfree(pf);\n+\n+\treturn err;\n+}\n+\n /**\n  * i40e_probe - Device initialization routine\n  * @pdev: PCI device information struct\n@@ -13972,12 +14192,15 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \n \t/* Reset here to make sure all is clean and to define PF 'n' */\n \ti40e_clear_hw(hw);\n-\terr = i40e_pf_reset(hw);\n-\tif (err) {\n-\t\tdev_info(&pdev->dev, \"Initial pf_reset failed: %d\\n\", err);\n-\t\tgoto err_pf_reset;\n+\tif (!i40e_check_recovery_mode(pf)) {\n+\t\terr = i40e_pf_reset(hw);\n+\t\tif (err) {\n+\t\t\tdev_info(&pdev->dev, \"Initial pf_reset failed: %d\\n\",\n+\t\t\t\t err);\n+\t\t\tgoto err_pf_reset;\n+\t\t}\n+\t\tpf->pfr_count++;\n \t}\n-\tpf->pfr_count++;\n \n \thw->aq.num_arq_entries = I40E_AQ_LEN;\n \thw->aq.num_asq_entries = I40E_AQ_LEN;\n@@ -14043,6 +14266,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t\tgoto err_sw_init;\n \t}\n \n+\tif (test_bit(__I40E_RECOVERY_MODE, pf->state))\n+\t\treturn i40e_init_recovery_mode(pf, hw);\n+\n \terr = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,\n \t\t\t\thw->func_caps.num_rx_qp, 0, 0);\n \tif (err) {\n@@ -14425,6 +14651,20 @@ static void i40e_remove(struct pci_dev *pdev)\n \tif (pf->service_task.func)\n \t\tcancel_work_sync(&pf->service_task);\n \n+\tif (test_bit(__I40E_RECOVERY_MODE, pf->state)) {\n+\t\tstruct i40e_vsi *vsi = pf->vsi[0];\n+\n+\t\t/* We know that we have allocated only one vsi for this PF,\n+\t\t * it was just for registering netdevice, so the interface\n+\t\t * could be visible in the 'ifconfig' output\n+\t\t */\n+\t\tunregister_netdev(vsi->netdev);\n+\t\tfree_netdev(vsi->netdev);\n+\t\tvsi->netdev = NULL;\n+\n+\t\tgoto unmap;\n+\t}\n+\n \t/* Client close must be called explicitly here because the timer\n \t * has been stopped.\n \t */\n@@ -14474,25 +14714,37 @@ static void i40e_remove(struct pci_dev *pdev)\n \t\t\t\t ret_code);\n \t}\n \n-\t/* shutdown the adminq */\n-\ti40e_shutdown_adminq(hw);\n-\n-\t/* destroy the locks only once, here */\n-\tmutex_destroy(&hw->aq.arq_mutex);\n-\tmutex_destroy(&hw->aq.asq_mutex);\n+unmap:\n+\t/* Free MSI/legacy interrupt 0 when in recovery mode.\n+\t * This is normally done in i40e_vsi_free_irq on\n+\t * VSI close but since recovery mode doesn't allow to up\n+\t * an interface and we do not allocate all Rx/Tx resources\n+\t * for it we'll just do it here\n+\t */\n+\tif (test_bit(__I40E_RECOVERY_MODE, pf->state) &&\n+\t    !(pf->flags & I40E_FLAG_MSIX_ENABLED))\n+\t\tfree_irq(pf->pdev->irq, pf);\n \n \t/* Clear all dynamic memory lists of rings, q_vectors, and VSIs */\n \trtnl_lock();\n \ti40e_clear_interrupt_scheme(pf);\n \tfor (i = 0; i < pf->num_alloc_vsi; i++) {\n \t\tif (pf->vsi[i]) {\n-\t\t\ti40e_vsi_clear_rings(pf->vsi[i]);\n+\t\t\tif (!test_bit(__I40E_RECOVERY_MODE, pf->state))\n+\t\t\t\ti40e_vsi_clear_rings(pf->vsi[i]);\n \t\t\ti40e_vsi_clear(pf->vsi[i]);\n \t\t\tpf->vsi[i] = NULL;\n \t\t}\n \t}\n \trtnl_unlock();\n \n+\t/* shutdown the adminq */\n+\ti40e_shutdown_adminq(hw);\n+\n+\t/* destroy the locks only once, here */\n+\tmutex_destroy(&hw->aq.arq_mutex);\n+\tmutex_destroy(&hw->aq.asq_mutex);\n+\n \tfor (i = 0; i < I40E_MAX_VEB; i++) {\n \t\tkfree(pf->veb[i]);\n \t\tpf->veb[i] = NULL;\n@@ -14703,6 +14955,16 @@ static void i40e_shutdown(struct pci_dev *pdev)\n \twr32(hw, I40E_PFPM_WUFC,\n \t     (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));\n \n+\t/* Free MSI/legacy interrupt 0 when in recovery mode.\n+\t * This is normally done in i40e_vsi_free_irq on\n+\t * VSI close but since recovery mode doesn't allow to up\n+\t * an interface and we do not allocate all Rx/Tx resources\n+\t * for it we'll just do it here\n+\t */\n+\tif (test_bit(__I40E_RECOVERY_MODE, pf->state) &&\n+\t    !(pf->flags & I40E_FLAG_MSIX_ENABLED))\n+\t\tfree_irq(pf->pdev->irq, pf);\n+\n \t/* Since we're going to destroy queues during the\n \t * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this\n \t * whole section\n",
    "prefixes": [
        "v3"
    ]
}