Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/808992/?format=api
{ "id": 808992, "url": "http://patchwork.ozlabs.org/api/patches/808992/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20170901204249.3835-1-jacob.e.keller@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": "<20170901204249.3835-1-jacob.e.keller@intel.com>", "list_archive_url": null, "date": "2017-09-01T20:42:49", "name": "i40e: avoid NVM acquire deadlock during NVM update", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "38495d41a1931ab1828aa7aad38c407e2e720c7b", "submitter": { "id": 9784, "url": "http://patchwork.ozlabs.org/api/people/9784/?format=api", "name": "Jacob Keller", "email": "jacob.e.keller@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/20170901204249.3835-1-jacob.e.keller@intel.com/mbox/", "series": [ { "id": 1111, "url": "http://patchwork.ozlabs.org/api/series/1111/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=1111", "date": "2017-09-01T20:42:49", "name": "i40e: avoid NVM acquire deadlock during NVM update", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/1111/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/808992/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/808992/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.138; helo=whitealder.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\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 3xkWQp4QhCz9sMN\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 2 Sep 2017 06:42:57 +1000 (AEST)", "from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 6187188F11;\n\tFri, 1 Sep 2017 20:42:56 +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 3g96WLp-gqFF; Fri, 1 Sep 2017 20:42:54 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id DE23B88ED4;\n\tFri, 1 Sep 2017 20:42:54 +0000 (UTC)", "from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\tby ash.osuosl.org (Postfix) with ESMTP id A878A1C40B6\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 1 Sep 2017 20:42:53 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id A117C88ED4\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 1 Sep 2017 20:42:53 +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 2P7j1TjE3XG2 for <intel-wired-lan@lists.osuosl.org>;\n\tFri, 1 Sep 2017 20:42:52 +0000 (UTC)", "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n\tby whitealder.osuosl.org (Postfix) with ESMTPS id 9449C88E37\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 1 Sep 2017 20:42:52 +0000 (UTC)", "from fmsmga001.fm.intel.com ([10.253.24.23])\n\tby orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t01 Sep 2017 13:42:51 -0700", "from jekeller-desk.amr.corp.intel.com ([134.134.177.230])\n\tby fmsmga001.fm.intel.com with ESMTP; 01 Sep 2017 13:42:51 -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-ExtLoop1": "1", "X-IronPort-AV": "E=Sophos; i=\"5.41,459,1498546800\"; d=\"scan'208\";\n\ta=\"1190695286\"", "From": "Jacob Keller <jacob.e.keller@intel.com>", "To": "Intel Wired LAN <intel-wired-lan@lists.osuosl.org>", "Date": "Fri, 1 Sep 2017 13:42:49 -0700", "Message-Id": "<20170901204249.3835-1-jacob.e.keller@intel.com>", "X-Mailer": "git-send-email 2.14.1.436.g33e61a4f0239", "Cc": "Stefan Assmann <sassmann@kpanic.de>", "Subject": "[Intel-wired-lan] [PATCH] i40e: avoid NVM acquire deadlock during\n\tNVM update", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.18-1", "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: Anjali Singhai Jain <anjali.singhai@intel.com>\n\nX722 devices use the AdminQ to access the NVM, and this requires taking\nthe AdminQ lock. Because of this, we lock the AdminQ during\ni40e_read_nvm(), which is also called in places where the lock is\nalready held, such as the firmware update path which wants to lock once\nand then unlock when finished after performing several tasks.\n\nAlthough this should have only affected X722 devices, commit\n96a39aed25e6 (\"i40e: Acquire NVM lock before reads on all devices\",\n2016-12-02) added locking for all NVM reads, regardless of device\nfamily.\n\nThis resulted in us accidentally causing NVM acquire timeouts on all\ndevices, causing failed firmware updates which left the eeprom in\na corrupt state.\n\nCreate unsafe non-locked variants of i40e_read_nvm_word and\ni40e_read_nvm_buffer, __i40e_read_nvm_word and __i40e_read_nvm_buffer\nrespectively. These variants will not take the NVM lock and are expected\nto only be called in places where the NVM lock is already held if\nneeded.\n\nSince the only caller of i40e_read_nvm_buffer() was in such a path,\nremove it entirely in favor of the unsafe version. If necessary we can\nalways add it back in the future.\n\nAdditionally, we now need to hold the NVM lock in i40e_validate_checksum\nbecause the call to i40e_calc_nvm_checksum now assumes that the NVM lock\nis held. We can further move the call to read I40E_SR_SW_CHECKSUM_WORD\nup a bit so that we do not need to acquire the NVM lock twice.\n\nThis should resolve firmware updates and also fix potential raise that\ncould have caused the driver to report an invalid NVM checksum upon\ndriver load.\n\nReported-by: Stefan Assmann <sassmann@kpanic.de>\nFixes: 96a39aed25e6 (\"i40e: Acquire NVM lock before reads on all devices\", 2016-12-02)\nSigned-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\n---\n\nThis is a more complete version of the patch suggested by Stefan, found\nat https://patchwork.ozlabs.org/patch/808699/ and it should be able to\navoid needing the 2nd patch in his series, which reverted a workqueue\nchange. The code is slightly refactored from what he suggested, and also\nincludes the i40e_nvm_read_buffer() function, as well as fixing up the\nissues in i40e_validate_checksum().\n\nStefan, can you let me know if this works for you? I didn't have any\nissues, but I'd like to confirm this fix is acceptable to you.\n\n drivers/net/ethernet/intel/i40e/i40e_nvm.c | 102 ++++++++++++++---------\n drivers/net/ethernet/intel/i40e/i40e_prototype.h | 2 -\n 2 files changed, 62 insertions(+), 42 deletions(-)", "diff": "diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c\nindex 96afef98a08f..d92aedc278aa 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c\n@@ -283,7 +283,7 @@ static i40e_status i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer,\n * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)\n * @data: word read from the Shadow RAM\n *\n- * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.\n+ * Reads one 16 bit word from the Shadow RAM using the AdminQ\n **/\n static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,\n \t\t\t\t\t u16 *data)\n@@ -297,27 +297,49 @@ static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,\n }\n \n /**\n- * i40e_read_nvm_word - Reads Shadow RAM\n+ * __i40e_read_nvm_word - Reads nvm word, assumes called does the locking\n * @hw: pointer to the HW structure\n * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)\n * @data: word read from the Shadow RAM\n *\n- * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.\n+ * Reads one 16 bit word from the Shadow RAM.\n+ *\n+ * Do not use this function except in cases where the nvm lock is already\n+ * taken via i40e_acquire_nvm().\n+ **/\n+static i40e_status __i40e_read_nvm_word(struct i40e_hw *hw,\n+\t\t\t\t\t\t u16 offset, u16 *data)\n+{\n+\ti40e_status ret_code = 0;\n+\n+\tif (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)\n+\t\tret_code = i40e_read_nvm_word_aq(hw, offset, data);\n+\telse\n+\t\tret_code = i40e_read_nvm_word_srctl(hw, offset, data);\n+\treturn ret_code;\n+}\n+\n+/**\n+ * i40e_read_nvm_word - Reads nvm word and acquire lock if necessary\n+ * @hw: pointer to the HW structure\n+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)\n+ * @data: word read from the Shadow RAM\n+ *\n+ * Reads one 16 bit word from the Shadow RAM.\n **/\n i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,\n-\t\t\t u16 *data)\n+\t\t\t\t\t u16 *data)\n {\n-\tenum i40e_status_code ret_code = 0;\n+\ti40e_status ret_code = 0;\n \n \tret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);\n-\tif (!ret_code) {\n-\t\tif (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {\n-\t\t\tret_code = i40e_read_nvm_word_aq(hw, offset, data);\n-\t\t} else {\n-\t\t\tret_code = i40e_read_nvm_word_srctl(hw, offset, data);\n-\t\t}\n-\t\ti40e_release_nvm(hw);\n-\t}\n+\tif (ret_code)\n+\t\treturn ret_code;\n+\n+\tret_code = __i40e_read_nvm_word(hw, offset, data);\n+\n+\ti40e_release_nvm(hw);\n+\n \treturn ret_code;\n }\n \n@@ -410,31 +432,25 @@ static i40e_status i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,\n }\n \n /**\n- * i40e_read_nvm_buffer - Reads Shadow RAM buffer\n+ * __i40e_read_nvm_buffer - Reads nvm buffer, caller must acquire lock\n * @hw: pointer to the HW structure\n * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).\n * @words: (in) number of words to read; (out) number of words actually read\n * @data: words read from the Shadow RAM\n *\n * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()\n- * method. The buffer read is preceded by the NVM ownership take\n- * and followed by the release.\n+ * method.\n **/\n-i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,\n-\t\t\t\t u16 *words, u16 *data)\n+static i40e_status __i40e_read_nvm_buffer(struct i40e_hw *hw,\n+\t\t\t\t\t\t u16 offset, u16 *words,\n+\t\t\t\t\t\t u16 *data)\n {\n-\tenum i40e_status_code ret_code = 0;\n+\ti40e_status ret_code = 0;\n \n-\tif (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {\n-\t\tret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);\n-\t\tif (!ret_code) {\n-\t\t\tret_code = i40e_read_nvm_buffer_aq(hw, offset, words,\n-\t\t\t\t\t\t\t data);\n-\t\t\ti40e_release_nvm(hw);\n-\t\t}\n-\t} else {\n+\tif (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)\n+\t\tret_code = i40e_read_nvm_buffer_aq(hw, offset, words, data);\n+\telse\n \t\tret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data);\n-\t}\n \treturn ret_code;\n }\n \n@@ -516,15 +532,15 @@ static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,\n \tdata = (u16 *)vmem.va;\n \n \t/* read pointer to VPD area */\n-\tret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);\n+\tret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);\n \tif (ret_code) {\n \t\tret_code = I40E_ERR_NVM_CHECKSUM;\n \t\tgoto i40e_calc_nvm_checksum_exit;\n \t}\n \n \t/* read pointer to PCIe Alt Auto-load module */\n-\tret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,\n-\t\t\t\t &pcie_alt_module);\n+\tret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,\n+\t\t\t\t\t&pcie_alt_module);\n \tif (ret_code) {\n \t\tret_code = I40E_ERR_NVM_CHECKSUM;\n \t\tgoto i40e_calc_nvm_checksum_exit;\n@@ -538,7 +554,7 @@ static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,\n \t\tif ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {\n \t\t\tu16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;\n \n-\t\t\tret_code = i40e_read_nvm_buffer(hw, i, &words, data);\n+\t\t\tret_code = __i40e_read_nvm_buffer(hw, i, &words, data);\n \t\t\tif (ret_code) {\n \t\t\t\tret_code = I40E_ERR_NVM_CHECKSUM;\n \t\t\t\tgoto i40e_calc_nvm_checksum_exit;\n@@ -610,14 +626,19 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,\n \tu16 checksum_sr = 0;\n \tu16 checksum_local = 0;\n \n-\tret_code = i40e_calc_nvm_checksum(hw, &checksum_local);\n-\tif (ret_code)\n-\t\tgoto i40e_validate_nvm_checksum_exit;\n-\n-\t/* Do not use i40e_read_nvm_word() because we do not want to take\n-\t * the synchronization semaphores twice here.\n+\t/* We must acquire the NVM lock in order to correctly synchronize the\n+\t * NVM accesses across multiple PFs. Without doing so it is possible\n+\t * for one of the PFs to read invalid data potentially indicating that\n+\t * the checksum is invalid.\n \t */\n-\ti40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);\n+\tret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);\n+\tif (ret_code)\n+\t\treturn ret_code;\n+\tret_code = i40e_calc_nvm_checksum(hw, &checksum_local);\n+\t__i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);\n+\ti40e_release_nvm(hw);\n+\tif (ret_code)\n+\t\treturn ret_code;\n \n \t/* Verify read checksum from EEPROM is the same as\n \t * calculated checksum\n@@ -629,7 +650,6 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,\n \tif (checksum)\n \t\t*checksum = checksum_local;\n \n-i40e_validate_nvm_checksum_exit:\n \treturn ret_code;\n }\n \n@@ -1026,6 +1046,7 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,\n \t\tbreak;\n \n \tcase I40E_NVMUPD_CSUM_CON:\n+\t\t/* Assumes the caller has acquired the nvm */\n \t\tstatus = i40e_update_nvm_checksum(hw);\n \t\tif (status) {\n \t\t\t*perrno = hw->aq.asq_last_status ?\n@@ -1040,6 +1061,7 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,\n \t\tbreak;\n \n \tcase I40E_NVMUPD_CSUM_LCB:\n+\t\t/* Assumes the caller has acquired the nvm */\n \t\tstatus = i40e_update_nvm_checksum(hw);\n \t\tif (status) {\n \t\t\t*perrno = hw->aq.asq_last_status ?\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\nindex 6254ad5167eb..01502561035c 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n@@ -311,8 +311,6 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw,\n void i40e_release_nvm(struct i40e_hw *hw);\n i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,\n \t\t\t\t\t u16 *data);\n-i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,\n-\t\t\t\t\t u16 *words, u16 *data);\n i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw);\n i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,\n \t\t\t\t\t\t u16 *checksum);\n", "prefixes": [] }