Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/948159/?format=api
{ "id": 948159, "url": "http://patchwork.ozlabs.org/api/patches/948159/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180723231348.14838-7-anirudh.venkataramanan@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": "<20180723231348.14838-7-anirudh.venkataramanan@intel.com>", "list_archive_url": null, "date": "2018-07-23T23:13:41", "name": "[06/13] ice: Refactor VSI allocation, deletion and rebuild flow", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "92b6fcc3b2520bb091b132d0d66c8c9d182bb424", "submitter": { "id": 73601, "url": "http://patchwork.ozlabs.org/api/people/73601/?format=api", "name": "Anirudh Venkataramanan", "email": "anirudh.venkataramanan@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/20180723231348.14838-7-anirudh.venkataramanan@intel.com/mbox/", "series": [ { "id": 57159, "url": "http://patchwork.ozlabs.org/api/series/57159/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=57159", "date": "2018-07-23T23:13:35", "name": "Feature updates for ice", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/57159/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/948159/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/948159/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.133; helo=hemlock.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 hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 41ZHP54szSz9s29\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 24 Jul 2018 09:14:01 +1000 (AEST)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 5293F822DA;\n\tMon, 23 Jul 2018 23:14:00 +0000 (UTC)", "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id B2tFzAzOl5OL; Mon, 23 Jul 2018 23:13:56 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 98CBA8344C;\n\tMon, 23 Jul 2018 23:13:56 +0000 (UTC)", "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\tby ash.osuosl.org (Postfix) with ESMTP id E0EB01CF309\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 23 Jul 2018 23:13:52 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id DE81B21FFB\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 23 Jul 2018 23:13:52 +0000 (UTC)", "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id qatd0usCVVCe for <intel-wired-lan@lists.osuosl.org>;\n\tMon, 23 Jul 2018 23:13:50 +0000 (UTC)", "from mga06.intel.com (mga06.intel.com [134.134.136.31])\n\tby silver.osuosl.org (Postfix) with ESMTPS id 5C76620778\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 23 Jul 2018 23:13:50 +0000 (UTC)", "from fmsmga006.fm.intel.com ([10.253.24.20])\n\tby orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t23 Jul 2018 16:13:49 -0700", "from shasta.jf.intel.com ([10.166.241.10])\n\tby fmsmga006.fm.intel.com with ESMTP; 23 Jul 2018 16:13:49 -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.51,394,1526367600\"; d=\"scan'208\";a=\"248252729\"", "From": "Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Mon, 23 Jul 2018 16:13:41 -0700", "Message-Id": "<20180723231348.14838-7-anirudh.venkataramanan@intel.com>", "X-Mailer": "git-send-email 2.14.3", "In-Reply-To": "<20180723231348.14838-1-anirudh.venkataramanan@intel.com>", "References": "<20180723231348.14838-1-anirudh.venkataramanan@intel.com>", "Subject": "[Intel-wired-lan] [PATCH 06/13] ice: Refactor VSI allocation,\n\tdeletion and rebuild flow", "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": "This patch refactors aspects of the VSI allocation, deletion and rebuild\nflow. Some of the more noteworthy changes are described below.\n\n1) On reset, all switch filters applied in the hardware are lost. In\n the rebuild flow, only MAC and broadcast filters are being restored.\n Instead, use a new function ice_replay_all_fltr to restore all the\n filters that were previously added. To do this, remove calls to\n ice_remove_vsi_fltr to prevent cleaning out the internal bookkeeping\n structures that ice_replay_all_fltr uses to replay filters.\n\n2) Introduce a new state bit __ICE_PREPARED_FOR_RESET to distinguish the\n PF that requested the reset (and consequently prepared for it) from\n the rest of the PFs. These other PFs will prepare for reset only\n when they receive an interrupt from the firmware.\n\n3) Use new functions ice_add_vsi and ice_free_vsi to create and destroy\n VSIs respectively. These functions accept a handle to uniquely\n identify a VSI. This same handle is required to rebuild the VSI post\n reset. To prevent confusion, the existing ice_vsi_add was renamed to\n ice_vsi_init.\n\n4) Enhance ice_vsi_setup for the upcoming SR-IOV changes and expose a\n new wrapper function ice_pf_vsi_setup to create PF VSIs. Rework the\n error handling path in ice_setup_pf_sw.\n\n5) Introduce a new function ice_vsi_release_all to release all PF VSIs.\n\nSigned-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>\n---\n drivers/net/ethernet/intel/ice/ice.h | 2 +\n drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 1 +\n drivers/net/ethernet/intel/ice/ice_common.c | 2 +\n drivers/net/ethernet/intel/ice/ice_main.c | 371 +++++++++++++++---------\n drivers/net/ethernet/intel/ice/ice_switch.c | 353 ++++++++++++++++++++--\n drivers/net/ethernet/intel/ice/ice_switch.h | 14 +-\n drivers/net/ethernet/intel/ice/ice_type.h | 8 +-\n 7 files changed, 580 insertions(+), 171 deletions(-)", "diff": "diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex 868f4a1d0f72..e17030db0bee 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -62,6 +62,7 @@ extern const char ice_drv_ver[];\n #define ICE_RES_VALID_BIT\t0x8000\n #define ICE_RES_MISC_VEC_ID\t(ICE_RES_VALID_BIT - 1)\n #define ICE_INVAL_Q_INDEX\t0xffff\n+#define ICE_INVAL_VFID\t\t256\n \n #define ICE_VSIQF_HKEY_ARRAY_SIZE\t((VSIQF_HKEY_MAX_INDEX + 1) *\t4)\n \n@@ -122,6 +123,7 @@ struct ice_sw {\n enum ice_state {\n \t__ICE_DOWN,\n \t__ICE_NEEDS_RESTART,\n+\t__ICE_PREPARED_FOR_RESET,\t/* set by driver when prepared */\n \t__ICE_RESET_RECOVERY_PENDING,\t/* set by driver when reset starts */\n \t__ICE_PFR_REQ,\t\t\t/* set by driver and peers */\n \t__ICE_CORER_REQ,\t\t/* set by driver and peers */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 8bb97d6c632d..a49b890941ec 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -1254,6 +1254,7 @@ struct ice_aq_desc {\n \t\tstruct ice_aqc_add_txqs add_txqs;\n \t\tstruct ice_aqc_dis_txqs dis_txqs;\n \t\tstruct ice_aqc_add_get_update_free_vsi vsi_cmd;\n+\t\tstruct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;\n \t\tstruct ice_aqc_alloc_free_res_cmd sw_res_ctrl;\n \t\tstruct ice_aqc_set_event_mask set_event_mask;\n \t\tstruct ice_aqc_get_link_status get_link_status;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex ba15788c2012..6466936b1610 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -645,6 +645,8 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req)\n \t\tice_debug(hw, ICE_DBG_INIT, \"GlobalR requested\\n\");\n \t\tval = GLGEN_RTRIG_GLOBR_M;\n \t\tbreak;\n+\tdefault:\n+\t\treturn ICE_ERR_PARAM;\n \t}\n \n \tval |= rd32(hw, GLGEN_RTRIG);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex be80aac9230a..689a4cd3bbef 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -32,6 +32,7 @@ static const struct net_device_ops ice_netdev_ops;\n static void ice_pf_dis_all_vsi(struct ice_pf *pf);\n static void ice_rebuild(struct ice_pf *pf);\n static int ice_vsi_release(struct ice_vsi *vsi);\n+static void ice_vsi_release_all(struct ice_pf *pf);\n static void ice_update_vsi_stats(struct ice_vsi *vsi);\n static void ice_update_pf_stats(struct ice_pf *pf);\n \n@@ -456,23 +457,13 @@ static void\n ice_prepare_for_reset(struct ice_pf *pf)\n {\n \tstruct ice_hw *hw = &pf->hw;\n-\tu32 v;\n-\n-\tice_for_each_vsi(pf, v)\n-\t\tif (pf->vsi[v])\n-\t\t\tice_remove_vsi_fltr(hw, pf->vsi[v]->vsi_num);\n-\n-\tdev_dbg(&pf->pdev->dev, \"Tearing down internal switch for reset\\n\");\n \n \t/* disable the VSIs and their queues that are not already DOWN */\n-\t/* pf_dis_all_vsi modifies netdev structures -rtnl_lock needed */\n \tice_pf_dis_all_vsi(pf);\n \n-\tice_for_each_vsi(pf, v)\n-\t\tif (pf->vsi[v])\n-\t\t\tpf->vsi[v]->vsi_num = 0;\n-\n \tice_shutdown_all_ctrlq(hw);\n+\n+\tset_bit(__ICE_PREPARED_FOR_RESET, pf->state);\n }\n \n /**\n@@ -490,26 +481,32 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)\n \tWARN_ON(in_interrupt());\n \n \t/* PFR is a bit of a special case because it doesn't result in an OICR\n-\t * interrupt. So for PFR, we prepare for reset, issue the reset and\n-\t * rebuild sequentially.\n+\t * interrupt. Set pending bit here which otherwise gets set in the\n+\t * OICR handler.\n \t */\n-\tif (reset_type == ICE_RESET_PFR) {\n+\tif (reset_type == ICE_RESET_PFR)\n \t\tset_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);\n-\t\tice_prepare_for_reset(pf);\n-\t}\n+\n+\tice_prepare_for_reset(pf);\n \n \t/* trigger the reset */\n \tif (ice_reset(hw, reset_type)) {\n \t\tdev_err(dev, \"reset %d failed\\n\", reset_type);\n \t\tset_bit(__ICE_RESET_FAILED, pf->state);\n \t\tclear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);\n+\t\tclear_bit(__ICE_PREPARED_FOR_RESET, pf->state);\n \t\treturn;\n \t}\n \n+\t/* PFR is a bit of a special case because it doesn't result in an OICR\n+\t * interrupt. So for PFR, rebuild after the reset and clear the reset-\n+\t * associated state bits.\n+\t */\n \tif (reset_type == ICE_RESET_PFR) {\n \t\tpf->pfr_count++;\n \t\tice_rebuild(pf);\n \t\tclear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);\n+\t\tclear_bit(__ICE_PREPARED_FOR_RESET, pf->state);\n \t}\n }\n \n@@ -519,20 +516,23 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)\n */\n static void ice_reset_subtask(struct ice_pf *pf)\n {\n-\tenum ice_reset_req reset_type;\n-\n-\trtnl_lock();\n+\tenum ice_reset_req reset_type = ICE_RESET_INVAL;\n \n \t/* When a CORER/GLOBR/EMPR is about to happen, the hardware triggers an\n-\t * OICR interrupt. The OICR handler (ice_misc_intr) determines what\n-\t * type of reset happened and sets __ICE_RESET_RECOVERY_PENDING bit in\n-\t * pf->state. So if reset/recovery is pending (as indicated by this bit)\n-\t * we do a rebuild and return.\n+\t * OICR interrupt. The OICR handler (ice_misc_intr) determines what type\n+\t * of reset is pending and sets bits in pf->state indicating the reset\n+\t * type and __ICE_RESET_RECOVERY_PENDING. So, if the latter bit is set\n+\t * prepare for pending reset if not already (for PF software-initiated\n+\t * global resets the software should already be prepared for it as\n+\t * indicated by __ICE_PREPARED_FOR_RESET; for global resets initiated\n+\t * by firmware or software on other PFs, that bit is not set so prepare\n+\t * for the reset now), poll for reset done, rebuild and return.\n \t */\n \tif (ice_is_reset_recovery_pending(pf->state)) {\n \t\tclear_bit(__ICE_GLOBR_RECV, pf->state);\n \t\tclear_bit(__ICE_CORER_RECV, pf->state);\n-\t\tice_prepare_for_reset(pf);\n+\t\tif (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state))\n+\t\t\tice_prepare_for_reset(pf);\n \n \t\t/* make sure we are ready to rebuild */\n \t\tif (ice_check_reset(&pf->hw)) {\n@@ -541,29 +541,32 @@ static void ice_reset_subtask(struct ice_pf *pf)\n \t\t\t/* done with reset. start rebuild */\n \t\t\tpf->hw.reset_ongoing = false;\n \t\t\tice_rebuild(pf);\n+\t\t\t/* clear bit to resume normal operations, but\n+\t\t\t * ICE_NEEDS_RESTART bit is set incase rebuild failed\n+\t\t\t */\n+\t\t\tclear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);\n+\t\t\tclear_bit(__ICE_PREPARED_FOR_RESET, pf->state);\n \t\t}\n-\t\tclear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);\n-\t\tgoto unlock;\n+\n+\t\treturn;\n \t}\n \n \t/* No pending resets to finish processing. Check for new resets */\n+\tif (test_and_clear_bit(__ICE_PFR_REQ, pf->state))\n+\t\treset_type = ICE_RESET_PFR;\n+\tif (test_and_clear_bit(__ICE_CORER_REQ, pf->state))\n+\t\treset_type = ICE_RESET_CORER;\n \tif (test_and_clear_bit(__ICE_GLOBR_REQ, pf->state))\n \t\treset_type = ICE_RESET_GLOBR;\n-\telse if (test_and_clear_bit(__ICE_CORER_REQ, pf->state))\n-\t\treset_type = ICE_RESET_CORER;\n-\telse if (test_and_clear_bit(__ICE_PFR_REQ, pf->state))\n-\t\treset_type = ICE_RESET_PFR;\n-\telse\n-\t\tgoto unlock;\n+\t/* If no valid reset type requested just return */\n+\tif (reset_type == ICE_RESET_INVAL)\n+\t\treturn;\n \n-\t/* reset if not already down or resetting */\n+\t/* reset if not already down or busy */\n \tif (!test_bit(__ICE_DOWN, pf->state) &&\n \t !test_bit(__ICE_CFG_BUSY, pf->state)) {\n \t\tice_do_reset(pf, reset_type);\n \t}\n-\n-unlock:\n-\trtnl_unlock();\n }\n \n /**\n@@ -970,7 +973,8 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf)\n static void ice_service_task_schedule(struct ice_pf *pf)\n {\n \tif (!test_bit(__ICE_DOWN, pf->state) &&\n-\t !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state))\n+\t !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state) &&\n+\t !test_bit(__ICE_NEEDS_RESTART, pf->state))\n \t\tqueue_work(ice_wq, &pf->serv_task);\n }\n \n@@ -1013,9 +1017,10 @@ static void ice_service_task(struct work_struct *work)\n \t/* process reset requests first */\n \tice_reset_subtask(pf);\n \n-\t/* bail if a reset/recovery cycle is pending */\n+\t/* bail if a reset/recovery cycle is pending or rebuild failed */\n \tif (ice_is_reset_recovery_pending(pf->state) ||\n-\t test_bit(__ICE_SUSPENDED, pf->state)) {\n+\t test_bit(__ICE_SUSPENDED, pf->state) ||\n+\t test_bit(__ICE_NEEDS_RESTART, pf->state)) {\n \t\tice_service_task_complete(pf);\n \t\treturn;\n \t}\n@@ -1160,7 +1165,7 @@ static void ice_vsi_delete(struct ice_vsi *vsi)\n \n \tmemcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props));\n \n-\tstatus = ice_aq_free_vsi(&pf->hw, &ctxt, false, NULL);\n+\tstatus = ice_free_vsi(&pf->hw, vsi->idx, &ctxt, false, NULL);\n \tif (status)\n \t\tdev_err(&pf->pdev->dev, \"Failed to delete VSI %i in FW\\n\",\n \t\t\tvsi->vsi_num);\n@@ -1421,13 +1426,13 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)\n }\n \n /**\n- * ice_vsi_add - Create a new VSI or fetch preallocated VSI\n+ * ice_vsi_init - Create and initialize a VSI\n * @vsi: the VSI being configured\n *\n * This initializes a VSI context depending on the VSI type to be added and\n * passes it down to the add_vsi aq command to create a new VSI.\n */\n-static int ice_vsi_add(struct ice_vsi *vsi)\n+static int ice_vsi_init(struct ice_vsi *vsi)\n {\n \tstruct ice_vsi_ctx ctxt = { 0 };\n \tstruct ice_pf *pf = vsi->back;\n@@ -1454,13 +1459,17 @@ static int ice_vsi_add(struct ice_vsi *vsi)\n \tctxt.info.sw_id = vsi->port_info->sw_id;\n \tice_vsi_setup_q_map(vsi, &ctxt);\n \n-\tret = ice_aq_add_vsi(hw, &ctxt, NULL);\n+\tret = ice_add_vsi(hw, vsi->idx, &ctxt, NULL);\n \tif (ret) {\n-\t\tdev_err(&vsi->back->pdev->dev,\n-\t\t\t\"Add VSI AQ call failed, err %d\\n\", ret);\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"Add VSI failed, err %d\\n\", ret);\n \t\treturn -EIO;\n \t}\n+\n+\t/* keep context for update VSI operations */\n \tvsi->info = ctxt.info;\n+\n+\t/* record VSI number returned */\n \tvsi->vsi_num = ctxt.vsi_num;\n \n \treturn ret;\n@@ -2654,14 +2663,12 @@ static int ice_vsi_cfg_rss(struct ice_vsi *vsi)\n }\n \n /**\n- * ice_vsi_reinit_setup - return resource and reallocate resource for a VSI\n- * @vsi: pointer to the ice_vsi\n- *\n- * This reallocates the VSIs queue resources\n+ * ice_vsi_rebuild - Rebuild VSI after reset\n+ * @vsi: vsi to be rebuild\n *\n * Returns 0 on success and negative value on failure\n */\n-static int ice_vsi_reinit_setup(struct ice_vsi *vsi)\n+static int ice_vsi_rebuild(struct ice_vsi *vsi)\n {\n \tu16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };\n \tint ret, i;\n@@ -2677,7 +2684,7 @@ static int ice_vsi_reinit_setup(struct ice_vsi *vsi)\n \tice_vsi_set_num_qs(vsi);\n \n \t/* Initialize VSI struct elements and create VSI in FW */\n-\tret = ice_vsi_add(vsi);\n+\tret = ice_vsi_init(vsi);\n \tif (ret < 0)\n \t\tgoto err_vsi;\n \n@@ -2687,19 +2694,7 @@ static int ice_vsi_reinit_setup(struct ice_vsi *vsi)\n \n \tswitch (vsi->type) {\n \tcase ICE_VSI_PF:\n-\t\tif (!vsi->netdev) {\n-\t\t\tret = ice_cfg_netdev(vsi);\n-\t\t\tif (ret)\n-\t\t\t\tgoto err_rings;\n-\n-\t\t\tret = register_netdev(vsi->netdev);\n-\t\t\tif (ret)\n-\t\t\t\tgoto err_rings;\n-\n-\t\t\tnetif_carrier_off(vsi->netdev);\n-\t\t\tnetif_tx_stop_all_queues(vsi->netdev);\n-\t\t}\n-\n+\t\t/* fall through */\n \t\tret = ice_vsi_alloc_q_vectors(vsi);\n \t\tif (ret)\n \t\t\tgoto err_rings;\n@@ -2751,21 +2746,23 @@ static int ice_vsi_reinit_setup(struct ice_vsi *vsi)\n /**\n * ice_vsi_setup - Set up a VSI by a given type\n * @pf: board private structure\n- * @type: VSI type\n * @pi: pointer to the port_info instance\n+ * @type: VSI type\n+ * @vf_id: defines VF id to which this VSI connects. This field is meant to be\n+ * used only for ICE_VSI_VF VSI type. For other VSI types, should\n+ * fill-in ICE_INVAL_VFID as input.\n *\n * This allocates the sw VSI structure and its queue resources.\n *\n- * Returns pointer to the successfully allocated and configure VSI sw struct on\n- * success, otherwise returns NULL on failure.\n+ * Returns pointer to the successfully allocated and configured VSI sw struct on\n+ * success, NULL on failure.\n */\n static struct ice_vsi *\n-ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n-\t struct ice_port_info *pi)\n+ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,\n+\t enum ice_vsi_type type, u16 __always_unused vf_id)\n {\n \tu16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };\n \tstruct device *dev = &pf->pdev->dev;\n-\tstruct ice_vsi_ctx ctxt = { 0 };\n \tstruct ice_vsi *vsi;\n \tint ret, i;\n \n@@ -2788,12 +2785,10 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \tice_vsi_set_rss_params(vsi);\n \n \t/* create the VSI */\n-\tret = ice_vsi_add(vsi);\n+\tret = ice_vsi_init(vsi);\n \tif (ret)\n \t\tgoto err_vsi;\n \n-\tctxt.vsi_num = vsi->vsi_num;\n-\n \tswitch (vsi->type) {\n \tcase ICE_VSI_PF:\n \t\tret = ice_cfg_netdev(vsi);\n@@ -2862,10 +2857,7 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \t\tvsi->netdev = NULL;\n \t}\n err_cfg_netdev:\n-\tret = ice_aq_free_vsi(&pf->hw, &ctxt, false, NULL);\n-\tif (ret)\n-\t\tdev_err(&vsi->back->pdev->dev,\n-\t\t\t\"Free VSI AQ call failed, err %d\\n\", ret);\n+\tice_vsi_delete(vsi);\n err_vsi:\n \tice_vsi_put_qs(vsi);\n err_get_qs:\n@@ -2876,6 +2868,20 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \treturn NULL;\n }\n \n+/**\n+ * ice_pf_vsi_setup - Set up a PF VSI\n+ * @pf: board private structure\n+ * @pi: pointer to the port_info instance\n+ *\n+ * Returns pointer to the successfully allocated VSI sw struct on success,\n+ * otherwise returns NULL on failure.\n+ */\n+static struct ice_vsi *\n+ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)\n+{\n+\treturn ice_vsi_setup(pf, pi, ICE_VSI_PF, ICE_INVAL_VFID);\n+}\n+\n /**\n * ice_vsi_add_vlan - Add vsi membership for given vlan\n * @vsi: the vsi being configured\n@@ -3023,50 +3029,48 @@ static int ice_setup_pf_sw(struct ice_pf *pf)\n \tstruct ice_vsi *vsi;\n \tint status = 0;\n \n-\tif (!ice_is_reset_recovery_pending(pf->state)) {\n-\t\tvsi = ice_vsi_setup(pf, ICE_VSI_PF, pf->hw.port_info);\n-\t\tif (!vsi) {\n-\t\t\tstatus = -ENOMEM;\n-\t\t\tgoto error_exit;\n-\t\t}\n-\t} else {\n-\t\tvsi = pf->vsi[0];\n-\t\tstatus = ice_vsi_reinit_setup(vsi);\n-\t\tif (status < 0)\n-\t\t\treturn -EIO;\n+\tif (ice_is_reset_recovery_pending(pf->state))\n+\t\treturn -EBUSY;\n+\n+\tvsi = ice_pf_vsi_setup(pf, pf->hw.port_info);\n+\tif (!vsi) {\n+\t\tstatus = -ENOMEM;\n+\t\tgoto unroll_vsi_setup;\n \t}\n \n-\t/* tmp_add_list contains a list of MAC addresses for which MAC\n-\t * filters need to be programmed. Add the VSI's unicast MAC to\n-\t * this list\n+\t/* To add a MAC filter, first add the MAC to a list and then\n+\t * pass the list to ice_add_mac.\n \t */\n+\n+\t /* Add a unicast MAC filter so the VSI can get its packets */\n \tstatus = ice_add_mac_to_list(vsi, &tmp_add_list,\n \t\t\t\t vsi->port_info->mac.perm_addr);\n \tif (status)\n-\t\tgoto error_exit;\n+\t\tgoto unroll_vsi_setup;\n \n \t/* VSI needs to receive broadcast traffic, so add the broadcast\n-\t * MAC address to the list.\n+\t * MAC address to the list as well.\n \t */\n \teth_broadcast_addr(broadcast);\n \tstatus = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);\n \tif (status)\n-\t\tgoto error_exit;\n+\t\tgoto free_mac_list;\n \n \t/* program MAC filters for entries in tmp_add_list */\n \tstatus = ice_add_mac(&pf->hw, &tmp_add_list);\n \tif (status) {\n \t\tdev_err(&pf->pdev->dev, \"Could not add MAC filters\\n\");\n \t\tstatus = -ENOMEM;\n-\t\tgoto error_exit;\n+\t\tgoto free_mac_list;\n \t}\n \n \tice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);\n \treturn status;\n \n-error_exit:\n+free_mac_list:\n \tice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);\n \n+unroll_vsi_setup:\n \tif (vsi) {\n \t\tice_vsi_free_q_vectors(vsi);\n \t\tif (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED)\n@@ -3455,24 +3459,13 @@ static int ice_probe(struct pci_dev *pdev,\n static void ice_remove(struct pci_dev *pdev)\n {\n \tstruct ice_pf *pf = pci_get_drvdata(pdev);\n-\tint i = 0;\n-\tint err;\n \n \tif (!pf)\n \t\treturn;\n \n \tset_bit(__ICE_DOWN, pf->state);\n \n-\tfor (i = 0; i < pf->num_alloc_vsi; i++) {\n-\t\tif (!pf->vsi[i])\n-\t\t\tcontinue;\n-\n-\t\terr = ice_vsi_release(pf->vsi[i]);\n-\t\tif (err)\n-\t\t\tdev_dbg(&pf->pdev->dev, \"Failed to release VSI index %d (err %d)\\n\",\n-\t\t\t\ti, err);\n-\t}\n-\n+\tice_vsi_release_all(pf);\n \tice_free_irq_msix_misc(pf);\n \tice_clear_interrupt_scheme(pf);\n \tice_deinit_pf(pf);\n@@ -3519,7 +3512,7 @@ static int __init ice_module_init(void)\n \tpr_info(\"%s - version %s\\n\", ice_driver_string, ice_drv_ver);\n \tpr_info(\"%s\\n\", ice_copyright);\n \n-\tice_wq = alloc_ordered_workqueue(\"%s\", WQ_MEM_RECLAIM, KBUILD_MODNAME);\n+\tice_wq = alloc_workqueue(\"%s\", WQ_MEM_RECLAIM, 0, KBUILD_MODNAME);\n \tif (!ice_wq) {\n \t\tpr_err(\"Failed to create workqueue\\n\");\n \t\treturn -ENOMEM;\n@@ -5106,8 +5099,14 @@ static int ice_vsi_release(struct ice_vsi *vsi)\n \tif (!vsi->back)\n \t\treturn -ENODEV;\n \tpf = vsi->back;\n-\n-\tif (vsi->netdev) {\n+\t/* do not unregister and free netdevs while driver is in the reset\n+\t * recovery pending state. Since reset/rebuild happens through PF\n+\t * service task workqueue, its not a good idea to unregister netdev\n+\t * that is associated to the PF that is running the work queue items\n+\t * currently. This is done to avoid check_flush_dependency() warning\n+\t * on this wq\n+\t */\n+\tif (vsi->netdev && !ice_is_reset_recovery_pending(pf->state)) {\n \t\tunregister_netdev(vsi->netdev);\n \t\tfree_netdev(vsi->netdev);\n \t\tvsi->netdev = NULL;\n@@ -5133,11 +5132,39 @@ static int ice_vsi_release(struct ice_vsi *vsi)\n \tpf->q_left_tx += vsi->alloc_txq;\n \tpf->q_left_rx += vsi->alloc_rxq;\n \n-\tice_vsi_clear(vsi);\n+\t/* retain SW VSI data structure since it is needed to unregister and\n+\t * free VSI netdev when PF is not in reset recovery pending state,\\\n+\t * for ex: during rmmod.\n+\t */\n+\tif (!ice_is_reset_recovery_pending(pf->state))\n+\t\tice_vsi_clear(vsi);\n \n \treturn 0;\n }\n \n+/**\n+ * ice_vsi_release_all - Delete all VSIs\n+ * @pf: PF from which all VSIs are being removed\n+ */\n+static void ice_vsi_release_all(struct ice_pf *pf)\n+{\n+\tint err, i;\n+\n+\tif (!pf->vsi)\n+\t\treturn;\n+\n+\tfor (i = 0; i < pf->num_alloc_vsi; i++) {\n+\t\tif (!pf->vsi[i])\n+\t\t\tcontinue;\n+\n+\t\terr = ice_vsi_release(pf->vsi[i]);\n+\t\tif (err)\n+\t\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\t\"Failed to release pf->vsi[%d], err %d, vsi_num = %d\\n\",\n+\t\t\t\ti, err, pf->vsi[i]->vsi_num);\n+\t}\n+}\n+\n /**\n * ice_dis_vsi - pause a VSI\n * @vsi: the VSI being paused\n@@ -5150,27 +5177,31 @@ static void ice_dis_vsi(struct ice_vsi *vsi)\n \tset_bit(__ICE_NEEDS_RESTART, vsi->state);\n \n \tif (vsi->netdev && netif_running(vsi->netdev) &&\n-\t vsi->type == ICE_VSI_PF)\n+\t vsi->type == ICE_VSI_PF) {\n+\t\trtnl_lock();\n \t\tvsi->netdev->netdev_ops->ndo_stop(vsi->netdev);\n-\n-\tice_vsi_close(vsi);\n+\t\trtnl_unlock();\n+\t} else {\n+\t\tice_vsi_close(vsi);\n+\t}\n }\n \n /**\n * ice_ena_vsi - resume a VSI\n * @vsi: the VSI being resume\n */\n-static void ice_ena_vsi(struct ice_vsi *vsi)\n+static int ice_ena_vsi(struct ice_vsi *vsi)\n {\n-\tif (!test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state))\n-\t\treturn;\n+\tint err = 0;\n+\n+\tif (test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state))\n+\t\tif (vsi->netdev && netif_running(vsi->netdev)) {\n+\t\t\trtnl_lock();\n+\t\t\terr = vsi->netdev->netdev_ops->ndo_open(vsi->netdev);\n+\t\t\trtnl_unlock();\n+\t\t}\n \n-\tif (vsi->netdev && netif_running(vsi->netdev))\n-\t\tvsi->netdev->netdev_ops->ndo_open(vsi->netdev);\n-\telse if (ice_vsi_open(vsi))\n-\t\t/* this clears the DOWN bit */\n-\t\tdev_dbg(&vsi->back->pdev->dev, \"Failed open VSI 0x%04X on switch 0x%04X\\n\",\n-\t\t\tvsi->vsi_num, vsi->vsw->sw_id);\n+\treturn err;\n }\n \n /**\n@@ -5190,13 +5221,47 @@ static void ice_pf_dis_all_vsi(struct ice_pf *pf)\n * ice_pf_ena_all_vsi - Resume all VSIs on a PF\n * @pf: the PF\n */\n-static void ice_pf_ena_all_vsi(struct ice_pf *pf)\n+static int ice_pf_ena_all_vsi(struct ice_pf *pf)\n {\n \tint v;\n \n \tice_for_each_vsi(pf, v)\n \t\tif (pf->vsi[v])\n-\t\t\tice_ena_vsi(pf->vsi[v]);\n+\t\t\tif (ice_ena_vsi(pf->vsi[v]))\n+\t\t\t\treturn -EIO;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_vsi_rebuild_all - rebuild all VSIs in pf\n+ * @pf: the PF\n+ */\n+static int ice_vsi_rebuild_all(struct ice_pf *pf)\n+{\n+\tint i;\n+\n+\t/* loop through pf->vsi array and reinit the VSI if found */\n+\tfor (i = 0; i < pf->num_alloc_vsi; i++) {\n+\t\tint err;\n+\n+\t\tif (!pf->vsi[i])\n+\t\t\tcontinue;\n+\n+\t\terr = ice_vsi_rebuild(pf->vsi[i]);\n+\t\tif (err) {\n+\t\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\t\"VSI at index %d rebuild failed\\n\",\n+\t\t\t\tpf->vsi[i]->idx);\n+\t\t\treturn err;\n+\t\t}\n+\n+\t\tdev_info(&pf->pdev->dev,\n+\t\t\t \"VSI at index %d rebuilt. vsi_num = 0x%x\\n\",\n+\t\t\t pf->vsi[i]->idx, pf->vsi[i]->vsi_num);\n+\t}\n+\n+\treturn 0;\n }\n \n /**\n@@ -5218,13 +5283,13 @@ static void ice_rebuild(struct ice_pf *pf)\n \tret = ice_init_all_ctrlq(hw);\n \tif (ret) {\n \t\tdev_err(dev, \"control queues init failed %d\\n\", ret);\n-\t\tgoto fail_reset;\n+\t\tgoto err_init_ctrlq;\n \t}\n \n \tret = ice_clear_pf_cfg(hw);\n \tif (ret) {\n \t\tdev_err(dev, \"clear PF configuration failed %d\\n\", ret);\n-\t\tgoto fail_reset;\n+\t\tgoto err_init_ctrlq;\n \t}\n \n \tice_clear_pxe_mode(hw);\n@@ -5232,14 +5297,24 @@ static void ice_rebuild(struct ice_pf *pf)\n \tret = ice_get_caps(hw);\n \tif (ret) {\n \t\tdev_err(dev, \"ice_get_caps failed %d\\n\", ret);\n-\t\tgoto fail_reset;\n+\t\tgoto err_init_ctrlq;\n \t}\n \n-\t/* basic nic switch setup */\n-\terr = ice_setup_pf_sw(pf);\n+\terr = ice_sched_init_port(hw->port_info);\n+\tif (err)\n+\t\tgoto err_sched_init_port;\n+\n+\terr = ice_vsi_rebuild_all(pf);\n \tif (err) {\n-\t\tdev_err(dev, \"ice_setup_pf_sw failed\\n\");\n-\t\tgoto fail_reset;\n+\t\tdev_err(dev, \"ice_vsi_rebuild_all failed\\n\");\n+\t\tgoto err_vsi_rebuild;\n+\t}\n+\n+\tret = ice_replay_all_fltr(&pf->hw);\n+\tif (ret) {\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"error replaying switch filter rules\\n\");\n+\t\tgoto err_vsi_rebuild;\n \t}\n \n \t/* start misc vector */\n@@ -5247,20 +5322,35 @@ static void ice_rebuild(struct ice_pf *pf)\n \t\terr = ice_req_irq_msix_misc(pf);\n \t\tif (err) {\n \t\t\tdev_err(dev, \"misc vector setup failed: %d\\n\", err);\n-\t\t\tgoto fail_reset;\n+\t\t\tgoto err_vsi_rebuild;\n \t\t}\n \t}\n \n \t/* restart the VSIs that were rebuilt and running before the reset */\n-\tice_pf_ena_all_vsi(pf);\n+\terr = ice_pf_ena_all_vsi(pf);\n+\tif (err) {\n+\t\tdev_err(&pf->pdev->dev, \"error enabling VSIs\\n\");\n+\t\t/* no need to disable VSIs in tear down path in ice_rebuild()\n+\t\t * since its already taken care in ice_vsi_open()\n+\t\t */\n+\t\tgoto err_vsi_rebuild;\n+\t}\n \n+\t/* if we get here, reset flow is successful */\n+\tclear_bit(__ICE_RESET_FAILED, pf->state);\n \treturn;\n \n-fail_reset:\n+err_vsi_rebuild:\n+\tice_vsi_release_all(pf);\n+err_sched_init_port:\n+\tice_sched_cleanup_all(hw);\n+err_init_ctrlq:\n \tice_shutdown_all_ctrlq(hw);\n \tset_bit(__ICE_RESET_FAILED, pf->state);\n clear_recovery:\n-\tset_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);\n+\t/* set this bit in PF state to control service task scheduling */\n+\tset_bit(__ICE_NEEDS_RESTART, pf->state);\n+\tdev_err(dev, \"Rebuild failed, unload and reload driver\\n\");\n }\n \n /**\n@@ -5433,6 +5523,11 @@ static int ice_open(struct net_device *netdev)\n \tstruct ice_vsi *vsi = np->vsi;\n \tint err;\n \n+\tif (test_bit(__ICE_NEEDS_RESTART, vsi->back->state)) {\n+\t\tnetdev_err(netdev, \"driver needs to be unloaded and reloaded\\n\");\n+\t\treturn -EIO;\n+\t}\n+\n \tnetif_carrier_off(netdev);\n \n \terr = ice_vsi_open(vsi);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c\nindex 2e5b523d1e4e..40e069edd59f 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.c\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.c\n@@ -167,17 +167,17 @@ ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp *buf,\n *\n * Add a VSI context to the hardware (0x0210)\n */\n-enum ice_status\n+static enum ice_status\n ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n \t struct ice_sq_cd *cd)\n {\n \tstruct ice_aqc_add_update_free_vsi_resp *res;\n \tstruct ice_aqc_add_get_update_free_vsi *cmd;\n-\tenum ice_status status;\n \tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n \n \tcmd = &desc.params.vsi_cmd;\n-\tres = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw;\n+\tres = &desc.params.add_update_free_vsi_res;\n \n \tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);\n \n@@ -201,6 +201,42 @@ ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n \treturn status;\n }\n \n+/**\n+ * ice_aq_free_vsi\n+ * @hw: pointer to the hw struct\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Free VSI context info from hardware (0x0213)\n+ */\n+static enum ice_status\n+ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n+\t\tbool keep_vsi_alloc, struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_add_update_free_vsi_resp *resp;\n+\tstruct ice_aqc_add_get_update_free_vsi *cmd;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\n+\tcmd = &desc.params.vsi_cmd;\n+\tresp = &desc.params.add_update_free_vsi_res;\n+\n+\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);\n+\n+\tcmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);\n+\tif (keep_vsi_alloc)\n+\t\tcmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);\n+\n+\tstatus = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);\n+\tif (!status) {\n+\t\tvsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);\n+\t\tvsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);\n+\t}\n+\n+\treturn status;\n+}\n+\n /**\n * ice_aq_update_vsi\n * @hw: pointer to the hw struct\n@@ -219,7 +255,7 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n \tenum ice_status status;\n \n \tcmd = &desc.params.vsi_cmd;\n-\tresp = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw;\n+\tresp = &desc.params.add_update_free_vsi_res;\n \n \tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);\n \n@@ -239,38 +275,202 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n }\n \n /**\n- * ice_aq_free_vsi\n+ * ice_update_fltr_vsi_map - update given filter VSI map\n+ * @list_head: list for which filters needs to be updated\n+ * @list_lock: filter lock which needs to be updated\n+ * @old_vsi_num: old VSI HW id\n+ * @new_vsi_num: new VSI HW id\n+ *\n+ * update the VSI map for a given filter list\n+ */\n+static void\n+ice_update_fltr_vsi_map(struct list_head *list_head,\n+\t\t\tstruct mutex *list_lock, u16 old_vsi_num,\n+\t\t\tu16 new_vsi_num)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *itr;\n+\n+\tmutex_lock(list_lock);\n+\tif (list_empty(list_head))\n+\t\tgoto exit_update_map;\n+\n+\tlist_for_each_entry(itr, list_head, list_entry) {\n+\t\tif (itr->vsi_list_info &&\n+\t\t test_bit(old_vsi_num, itr->vsi_list_info->vsi_map)) {\n+\t\t\tclear_bit(old_vsi_num, itr->vsi_list_info->vsi_map);\n+\t\t\tset_bit(new_vsi_num, itr->vsi_list_info->vsi_map);\n+\t\t} else if (itr->fltr_info.fltr_act == ICE_FWD_TO_VSI &&\n+\t\t\t itr->fltr_info.fwd_id.vsi_id == old_vsi_num) {\n+\t\t\titr->fltr_info.fwd_id.vsi_id = new_vsi_num;\n+\t\t\titr->fltr_info.src = new_vsi_num;\n+\t\t}\n+\t}\n+exit_update_map:\n+\tmutex_unlock(list_lock);\n+}\n+\n+/**\n+ * ice_update_all_fltr_vsi_map - update all filters VSI map\n+ * @hw: pointer to the hardware structure\n+ * @old_vsi_num: old VSI HW id\n+ * @new_vsi_num: new VSI HW id\n+ *\n+ * update all filters VSI map\n+ */\n+static void\n+ice_update_all_fltr_vsi_map(struct ice_hw *hw, u16 old_vsi_num, u16 new_vsi_num)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tu8 i;\n+\n+\tfor (i = 0; i < ICE_SW_LKUP_LAST; i++) {\n+\t\tstruct list_head *head = &sw->recp_list[i].filt_rules;\n+\t\tstruct mutex *lock; /* Lock to protect filter rule list */\n+\n+\t\tlock = &sw->recp_list[i].filt_rule_lock;\n+\t\tice_update_fltr_vsi_map(head, lock, old_vsi_num,\n+\t\t\t\t\tnew_vsi_num);\n+\t}\n+}\n+\n+/**\n+ * ice_is_vsi_valid - check whether the VSI is valid or not\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * check whether the VSI is valid or not\n+ */\n+static bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\treturn vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];\n+}\n+\n+/**\n+ * ice_get_hw_vsi_num - return the hw VSI number\n * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * return the hw VSI number\n+ * Caution: call this function only if VSI is valid (ice_is_vsi_valid)\n+ */\n+static u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\treturn hw->vsi_ctx[vsi_handle]->vsi_num;\n+}\n+\n+/**\n+ * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * return the VSI context entry for a given VSI handle\n+ */\n+static struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\treturn (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];\n+}\n+\n+/**\n+ * ice_save_vsi_ctx - save the VSI context for a given VSI handle\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ * @vsi: VSI context pointer\n+ *\n+ * save the VSI context entry for a given VSI handle\n+ */\n+static void ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle,\n+\t\t\t struct ice_vsi_ctx *vsi)\n+{\n+\thw->vsi_ctx[vsi_handle] = vsi;\n+}\n+\n+/**\n+ * ice_clear_vsi_ctx - clear the VSI context entry\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: VSI handle\n+ *\n+ * clear the VSI context entry\n+ */\n+static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)\n+{\n+\tstruct ice_vsi_ctx *vsi;\n+\n+\tvsi = ice_get_vsi_ctx(hw, vsi_handle);\n+\tif (vsi) {\n+\t\tdevm_kfree(ice_hw_to_dev(hw), vsi);\n+\t\thw->vsi_ctx[vsi_handle] = NULL;\n+\t}\n+}\n+\n+/**\n+ * ice_add_vsi - add VSI context to the hardware and VSI handle list\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: unique VSI handle provided by drivers\n * @vsi_ctx: pointer to a VSI context struct\n- * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources\n * @cd: pointer to command details structure or NULL\n *\n- * Get VSI context info from hardware (0x0213)\n+ * Add a VSI context to the hardware also add it into the VSI handle list.\n+ * If this function gets called after reset for exisiting VSIs then update\n+ * with the new HW VSI number in the corresponding VSI handle list entry.\n */\n enum ice_status\n-ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n-\t\tbool keep_vsi_alloc, struct ice_sq_cd *cd)\n+ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t struct ice_sq_cd *cd)\n {\n-\tstruct ice_aqc_add_update_free_vsi_resp *resp;\n-\tstruct ice_aqc_add_get_update_free_vsi *cmd;\n-\tstruct ice_aq_desc desc;\n+\tstruct ice_vsi_ctx *tmp_vsi_ctx;\n \tenum ice_status status;\n \n-\tcmd = &desc.params.vsi_cmd;\n-\tresp = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw;\n-\n-\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);\n+\tif (vsi_handle >= ICE_MAX_VSI)\n+\t\treturn ICE_ERR_PARAM;\n+\tstatus = ice_aq_add_vsi(hw, vsi_ctx, cd);\n+\tif (status)\n+\t\treturn status;\n+\ttmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);\n+\tif (!tmp_vsi_ctx) {\n+\t\t/* Create a new vsi context */\n+\t\ttmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw),\n+\t\t\t\t\t sizeof(*tmp_vsi_ctx), GFP_KERNEL);\n+\t\tif (!tmp_vsi_ctx) {\n+\t\t\tice_aq_free_vsi(hw, vsi_ctx, false, cd);\n+\t\t\treturn ICE_ERR_NO_MEMORY;\n+\t\t}\n+\t\t*tmp_vsi_ctx = *vsi_ctx;\n+\t\tice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);\n+\t} else {\n+\t\t/* update with new HW VSI num */\n+\t\tif (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num) {\n+\t\t\t/* update all filter lists with new HW VSI num */\n+\t\t\tice_update_all_fltr_vsi_map(hw, tmp_vsi_ctx->vsi_num,\n+\t\t\t\t\t\t vsi_ctx->vsi_num);\n+\t\t\ttmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;\n+\t\t}\n+\t}\n \n-\tcmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);\n-\tif (keep_vsi_alloc)\n-\t\tcmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);\n+\treturn status;\n+}\n \n-\tstatus = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);\n-\tif (!status) {\n-\t\tvsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);\n-\t\tvsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);\n-\t}\n+/**\n+ * ice_free_vsi- free VSI context from hardware and VSI handle list\n+ * @hw: pointer to the hw struct\n+ * @vsi_handle: unique VSI handle\n+ * @vsi_ctx: pointer to a VSI context struct\n+ * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Free VSI context info from hardware as well as from VSI handle list\n+ */\n+enum ice_status\n+ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t bool keep_vsi_alloc, struct ice_sq_cd *cd)\n+{\n+\tenum ice_status status;\n \n+\tif (!ice_is_vsi_valid(hw, vsi_handle))\n+\t\treturn ICE_ERR_PARAM;\n+\tvsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);\n+\tstatus = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);\n+\tif (!status)\n+\t\tice_clear_vsi_ctx(hw, vsi_handle);\n \treturn status;\n }\n \n@@ -1516,6 +1716,25 @@ ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)\n \treturn 0;\n }\n \n+/**\n+ * ice_rem_sw_rule_info\n+ * @hw: pointer to the hardware structure\n+ * @rule_head: pointer to the switch list structure that we want to delete\n+ */\n+static void\n+ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head)\n+{\n+\tif (!list_empty(rule_head)) {\n+\t\tstruct ice_fltr_mgmt_list_entry *entry;\n+\t\tstruct ice_fltr_mgmt_list_entry *tmp;\n+\n+\t\tlist_for_each_entry_safe(entry, tmp, rule_head, list_entry) {\n+\t\t\tlist_del(&entry->list_entry);\n+\t\t\tdevm_kfree(ice_hw_to_dev(hw), entry);\n+\t\t}\n+\t}\n+}\n+\n /**\n * ice_cfg_dflt_vsi - change state of VSI to set/clear default\n * @hw: pointer to the hardware structure\n@@ -1822,3 +2041,89 @@ void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id)\n \tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE_MAC);\n \tice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC_VLAN);\n }\n+\n+/**\n+ * ice_replay_fltr - Replay all the filters stored by a specific list head\n+ * @hw: pointer to the hardware structure\n+ * @list_head: list for which filters needs to be replayed\n+ * @recp_id: Recipe id for which rules need to be replayed\n+ */\n+static enum ice_status\n+ice_replay_fltr(struct ice_hw *hw, u8 recp_id, struct list_head *list_head)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *itr;\n+\tstruct list_head l_head;\n+\tenum ice_status status = 0;\n+\n+\tif (list_empty(list_head))\n+\t\treturn status;\n+\n+\t/* Move entries from the given list_head to a temporary l_head so that\n+\t * they can be replayed. Otherwise when trying to re-add the same\n+\t * filter, the function will return already exists\n+\t */\n+\tlist_replace_init(list_head, &l_head);\n+\n+\t/* Mark the given list_head empty by reinitializing it so filters\n+\t * could be added again by *handler\n+\t */\n+\tlist_for_each_entry(itr, &l_head, list_entry) {\n+\t\tstruct ice_fltr_list_entry f_entry;\n+\n+\t\tf_entry.fltr_info = itr->fltr_info;\n+\t\tif (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN) {\n+\t\t\tstatus = ice_add_rule_internal(hw, recp_id, &f_entry);\n+\t\t\tif (status)\n+\t\t\t\tgoto end;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* Add a filter per vsi separately */\n+\t\twhile (1) {\n+\t\t\tu16 vsi;\n+\n+\t\t\tvsi = find_first_bit(itr->vsi_list_info->vsi_map,\n+\t\t\t\t\t ICE_MAX_VSI);\n+\t\t\tif (vsi == ICE_MAX_VSI)\n+\t\t\t\tbreak;\n+\n+\t\t\tclear_bit(vsi, itr->vsi_list_info->vsi_map);\n+\t\t\tf_entry.fltr_info.fwd_id.vsi_id = vsi;\n+\t\t\tf_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\t\t\tif (recp_id == ICE_SW_LKUP_VLAN)\n+\t\t\t\tstatus = ice_add_vlan_internal(hw, &f_entry);\n+\t\t\telse\n+\t\t\t\tstatus = ice_add_rule_internal(hw, recp_id,\n+\t\t\t\t\t\t\t &f_entry);\n+\t\t\tif (status)\n+\t\t\t\tgoto end;\n+\t\t}\n+\t}\n+end:\n+\t/* Clear the filter management list */\n+\tice_rem_sw_rule_info(hw, &l_head);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_replay_all_fltr - replay all filters stored in bookkeeping lists\n+ * @hw: pointer to the hardware structure\n+ *\n+ * NOTE: This function does not clean up partially added filters on error.\n+ * It is up to caller of the function to issue a reset or fail early.\n+ */\n+enum ice_status ice_replay_all_fltr(struct ice_hw *hw)\n+{\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\tenum ice_status status = 0;\n+\tu8 i;\n+\n+\tfor (i = 0; i < ICE_SW_LKUP_LAST; i++) {\n+\t\tstruct list_head *head = &sw->recp_list[i].filt_rules;\n+\n+\t\tstatus = ice_replay_fltr(hw, i, head);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\treturn status;\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h\nindex 09a3b6d6541a..11a481644dac 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.h\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.h\n@@ -158,15 +158,14 @@ struct ice_fltr_mgmt_list_entry {\n \n /* VSI related commands */\n enum ice_status\n-ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n-\t struct ice_sq_cd *cd);\n-enum ice_status\n ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n \t\t struct ice_sq_cd *cd);\n enum ice_status\n-ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,\n-\t\tbool keep_vsi_alloc, struct ice_sq_cd *cd);\n-\n+ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t struct ice_sq_cd *cd);\n+enum ice_status\n+ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,\n+\t bool keep_vsi_alloc, struct ice_sq_cd *cd);\n enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);\n \n /* Switch/bridge related commands */\n@@ -177,6 +176,9 @@ enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list);\n enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list);\n enum ice_status\n ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction);\n+\n+enum ice_status ice_replay_all_fltr(struct ice_hw *hw);\n+\n enum ice_status ice_init_def_sw_recp(struct ice_hw *hw);\n \n #endif /* _ICE_SWITCH_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h\nindex 15458b034ed1..75457afc912c 100644\n--- a/drivers/net/ethernet/intel/ice/ice_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_type.h\n@@ -144,9 +144,10 @@ struct ice_mac_info {\n \n /* Various RESET request, These are not tied with HW reset types */\n enum ice_reset_req {\n-\tICE_RESET_PFR\t= 0,\n-\tICE_RESET_CORER\t= 1,\n-\tICE_RESET_GLOBR\t= 2,\n+\tICE_RESET_INVAL = 0,\n+\tICE_RESET_PFR\t= 1,\n+\tICE_RESET_CORER\t= 2,\n+\tICE_RESET_GLOBR\t= 3,\n };\n \n /* Bus parameters */\n@@ -277,6 +278,7 @@ struct ice_hw {\n \tu8 max_cgds;\n \tu8 sw_entry_point_layer;\n \n+\tstruct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI];\n \tu8 evb_veb;\t\t/* true for VEB, false for VEPA */\n \tu8 reset_ongoing;\t/* true if hw is in reset, false otherwise */\n \tstruct ice_bus_info bus;\n", "prefixes": [ "06/13" ] }