get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1174151,
    "url": "http://patchwork.ozlabs.org/api/patches/1174151/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20191009140953.14087-1-anthony.l.nguyen@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": "<20191009140953.14087-1-anthony.l.nguyen@intel.com>",
    "list_archive_url": null,
    "date": "2019-10-09T14:09:39",
    "name": "[S31,01/15] ice: implement set_eeprom functionality",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "40925e04003480aa4a777564d1be81e9f909c6dc",
    "submitter": {
        "id": 68875,
        "url": "http://patchwork.ozlabs.org/api/people/68875/?format=api",
        "name": "Tony Nguyen",
        "email": "anthony.l.nguyen@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/20191009140953.14087-1-anthony.l.nguyen@intel.com/mbox/",
    "series": [
        {
            "id": 135203,
            "url": "http://patchwork.ozlabs.org/api/series/135203/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=135203",
            "date": "2019-10-09T14:09:45",
            "name": "[S31,01/15] ice: implement set_eeprom functionality",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/135203/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1174151/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1174151/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.136; helo=silver.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 silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\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 46pTgg6lvDz9sP7\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 10 Oct 2019 09:40:15 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 69A6A204C9;\n\tWed,  9 Oct 2019 22:40:14 +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 st2ECjEjgGgB; Wed,  9 Oct 2019 22:40:08 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id DCD6F237C8;\n\tWed,  9 Oct 2019 22:40:08 +0000 (UTC)",
            "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id BA0AC1BF9B5\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed,  9 Oct 2019 22:40:03 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id B510188305\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed,  9 Oct 2019 22:40:03 +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 6rk1Iw3uEeOl for <intel-wired-lan@lists.osuosl.org>;\n\tWed,  9 Oct 2019 22:40:01 +0000 (UTC)",
            "from mga06.intel.com (mga06.intel.com [134.134.136.31])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id D2904882F3\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed,  9 Oct 2019 22:40:00 +0000 (UTC)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t09 Oct 2019 15:40:00 -0700",
            "from unknown (HELO localhost.jf.intel.com) ([10.166.244.174])\n\tby orsmga003.jf.intel.com with ESMTP; 09 Oct 2019 15:40:00 -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.67,277,1566889200\"; d=\"scan'208\";a=\"197052250\"",
        "From": "Tony Nguyen <anthony.l.nguyen@intel.com>",
        "To": "intel-wired-lan@lists.osuosl.org",
        "Date": "Wed,  9 Oct 2019 07:09:39 -0700",
        "Message-Id": "<20191009140953.14087-1-anthony.l.nguyen@intel.com>",
        "X-Mailer": "git-send-email 2.20.1",
        "MIME-Version": "1.0",
        "Subject": "[Intel-wired-lan] [PATCH S31 01/15] ice: implement set_eeprom\n\tfunctionality",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.29",
        "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>",
        "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: Jesse Brandeburg <jesse.brandeburg@intel.com>\n\nThe driver needs set_eeprom to work so that it can\nprogram the onboard NVM using our update application.\n\nAdd functions that are necessary to enable reading the\nNVM image.  They implement basic functionality to lock,\nread, unlock during an NVM read.  Also remove shadow ram\nfunctionality since it is no longer used. In addition\nmove a few function declarations into ice_nvm.h.\n\nSigned-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>\nCo-developed-by: Jacob Keller <jacob.e.keller@intel.com>\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\nSigned-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>\n---\n .../net/ethernet/intel/ice/ice_adminq_cmd.h   |   3 +\n drivers/net/ethernet/intel/ice/ice_common.h   |   4 +-\n drivers/net/ethernet/intel/ice/ice_ethtool.c  | 125 ++++++-\n .../net/ethernet/intel/ice/ice_hw_autogen.h   |   2 +\n drivers/net/ethernet/intel/ice/ice_lib.c      |  24 ++\n drivers/net/ethernet/intel/ice/ice_lib.h      |   2 +\n drivers/net/ethernet/intel/ice/ice_nvm.c      | 341 +++++++++++++-----\n drivers/net/ethernet/intel/ice/ice_nvm.h      |  79 ++++\n 8 files changed, 468 insertions(+), 112 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/ice/ice_nvm.h",
    "diff": "diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex dad9a9efadfa..73c189a794bb 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -1171,6 +1171,8 @@ struct ice_aqc_nvm {\n \t__le32 addr_low;\n };\n \n+#define ICE_AQC_NVM_START_POINT\t\t\t0\n+\n /* NVM Checksum Command (direct, 0x0706) */\n struct ice_aqc_nvm_checksum {\n \tu8 flags;\n@@ -1705,6 +1707,7 @@ enum ice_aq_err {\n \tICE_AQ_RC_ENOMEM\t= 9,  /* Out of memory */\n \tICE_AQ_RC_EBUSY\t\t= 12, /* Device or resource busy */\n \tICE_AQ_RC_EEXIST\t= 13, /* Object already exists */\n+\tICE_AQ_RC_EINVAL\t= 14, /* Invalid argument */\n \tICE_AQ_RC_ENOSPC\t= 16, /* No space left or allocation failure */\n \tICE_AQ_RC_ENOSYS\t= 17, /* Function not implemented */\n \tICE_AQ_RC_ENOSEC\t= 24, /* Missing security manifest */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h\nindex 347077bf8a36..c066f4000582 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.h\n+++ b/drivers/net/ethernet/intel/ice/ice_common.h\n@@ -6,6 +6,7 @@\n \n #include \"ice.h\"\n #include \"ice_type.h\"\n+#include \"ice_nvm.h\"\n #include \"ice_flex_pipe.h\"\n #include \"ice_switch.h\"\n #include <linux/avf/virtchnl.h>\n@@ -32,9 +33,6 @@ enum ice_status\n ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,\n \t\tenum ice_aq_res_access_type access, u32 timeout);\n void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);\n-enum ice_status ice_init_nvm(struct ice_hw *hw);\n-enum ice_status\n-ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data);\n enum ice_status\n ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,\n \t\tstruct ice_aq_desc *desc, void *buf, u16 buf_size,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c\nindex 7e779060069c..c270fbbc25bb 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c\n@@ -226,12 +226,12 @@ static void ice_set_msglevel(struct net_device *netdev, u32 data)\n #endif /* !CONFIG_DYNAMIC_DEBUG */\n }\n \n-static int ice_get_eeprom_len(struct net_device *netdev)\n+static int ice_get_eeprom_len(struct net_device __always_unused *netdev)\n {\n-\tstruct ice_netdev_priv *np = netdev_priv(netdev);\n-\tstruct ice_pf *pf = np->vsi->back;\n-\n-\treturn (int)(pf->hw.nvm.sr_words * sizeof(u16));\n+\t/* currently using a magic number of 0xFFFFFF to allow\n+\t * reads within the 16MB range of the NVM\n+\t */\n+\treturn 0xFFFFFF;\n }\n \n static int\n@@ -239,42 +239,127 @@ ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,\n \t       u8 *bytes)\n {\n \tstruct ice_netdev_priv *np = netdev_priv(netdev);\n-\tu16 first_word, last_word, nwords;\n \tstruct ice_vsi *vsi = np->vsi;\n \tstruct ice_pf *pf = vsi->back;\n \tstruct ice_hw *hw = &pf->hw;\n \tenum ice_status status;\n-\tstruct device *dev;\n \tint ret = 0;\n-\tu16 *buf;\n+\tu32 magic;\n+\tu8 *buf;\n+\n+\tif (!eeprom->len || eeprom->len > ice_get_eeprom_len(netdev))\n+\t\treturn -EINVAL;\n+\n+\tmagic = hw->vendor_id | (hw->device_id << 16);\n+\tif (eeprom->magic && eeprom->magic != magic) {\n+\t\tstruct ice_nvm_access_cmd *nvm;\n+\t\tunion ice_nvm_access_data *data;\n+\n+\t\tnvm = (struct ice_nvm_access_cmd *)eeprom;\n+\t\tdata = (union ice_nvm_access_data *)bytes;\n+\n+\t\tnetdev_dbg(netdev, \"GEEPROM cmd 0x%08x, config 0x%08x, offset 0x%08x, data_size 0x%08x\\n\",\n+\t\t\t   nvm->command, nvm->config, nvm->offset,\n+\t\t\t   nvm->data_size);\n+\n+\t\tstatus = ice_handle_nvm_access(hw, nvm, data);\n \n-\tdev = &pf->pdev->dev;\n+\t\tice_debug_array(hw, ICE_DBG_NVM, 16, 1, (u8 *)data,\n+\t\t\t\tnvm->data_size);\n \n-\teeprom->magic = hw->vendor_id | (hw->device_id << 16);\n+\t\tif (status) {\n+\t\t\tint err = ice_status_to_errno(status);\n \n-\tfirst_word = eeprom->offset >> 1;\n-\tlast_word = (eeprom->offset + eeprom->len - 1) >> 1;\n-\tnwords = last_word - first_word + 1;\n+\t\t\tnetdev_info(netdev, \"NVM read failed with status %d, error %d\\n\",\n+\t\t\t\t    status, err);\n \n-\tbuf = devm_kcalloc(dev, nwords, sizeof(u16), GFP_KERNEL);\n+\t\t\treturn err;\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+\n+\teeprom->magic = magic;\n+\tnetdev_dbg(netdev, \"GEEPROM cmd 0x%08x, offset 0x%08x, len 0x%08x\\n\",\n+\t\t   eeprom->cmd, eeprom->offset, eeprom->len);\n+\n+\tbuf = kzalloc(eeprom->len, GFP_KERNEL);\n \tif (!buf)\n \t\treturn -ENOMEM;\n \n-\tstatus = ice_read_sr_buf(hw, first_word, &nwords, buf);\n+\tstatus = ice_acquire_nvm(hw, ICE_RES_READ);\n \tif (status) {\n-\t\tdev_err(dev, \"ice_read_sr_buf failed, err %d aq_err %d\\n\",\n+\t\tdev_err(&pf->pdev->dev, \"ice_acquire_nvm failed: %d %d\\n\",\n \t\t\tstatus, hw->adminq.sq_last_status);\n-\t\teeprom->len = sizeof(u16) * nwords;\n \t\tret = -EIO;\n \t\tgoto out;\n \t}\n \n-\tmemcpy(bytes, (u8 *)buf + (eeprom->offset & 1), eeprom->len);\n+\t/* kernel only issues 4kB reads so we are good to read 4KB at a time */\n+\tstatus = ice_aq_read_nvm(hw, ICE_AQC_NVM_START_POINT, eeprom->offset,\n+\t\t\t\t eeprom->len, buf, true, false, NULL);\n+\tif (status == ICE_ERR_AQ_ERROR &&\n+\t    hw->adminq.sq_last_status == ICE_AQ_RC_EINVAL) {\n+\t\t/* do nothing, we reached the end */\n+\t\tice_release_nvm(hw);\n+\t\tgoto out;\n+\t} else if (status) {\n+\t\tdev_err(&pf->pdev->dev, \"ice_aq_read_nvm failed: %d %d\\n\",\n+\t\t\tstatus, hw->adminq.sq_last_status);\n+\t\tret = -EIO;\n+\t\tice_release_nvm(hw);\n+\t\tgoto out;\n+\t}\n+\n+\tice_release_nvm(hw);\n+\n+\tmemcpy(bytes, buf + eeprom->offset, eeprom->len);\n out:\n-\tdevm_kfree(dev, buf);\n+\tkfree(buf);\n \treturn ret;\n }\n \n+static int\n+ice_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,\n+\t       u8 *bytes)\n+{\n+\tstruct ice_netdev_priv *np = netdev_priv(netdev);\n+\tstruct ice_hw *hw = &np->vsi->back->hw;\n+\tstruct ice_pf *pf = np->vsi->back;\n+\tunion ice_nvm_access_data *data;\n+\tstruct ice_nvm_access_cmd *nvm;\n+\tenum ice_status status = 0;\n+\tint err = 0;\n+\tu32 magic;\n+\n+\t/* normal ethtool set_eeprom is not supported */\n+\tnvm = (struct ice_nvm_access_cmd *)eeprom;\n+\tdata = (union ice_nvm_access_data *)bytes;\n+\tmagic = hw->vendor_id | (hw->device_id << 16);\n+\n+\tnetdev_dbg(netdev, \"SEEPROM cmd 0x%08x, config 0x%08x, offset 0x%08x, data_size 0x%08x\\n\",\n+\t\t   nvm->command, nvm->config, nvm->offset, nvm->data_size);\n+\tice_debug_array(hw, ICE_DBG_NVM, 16, 1, (u8 *)data, nvm->data_size);\n+\n+\tif (eeprom->magic == magic)\n+\t\terr = -EOPNOTSUPP;\n+\t/* check for NVM access method */\n+\telse if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id)\n+\t\terr = -EINVAL;\n+\telse if (ice_is_reset_in_progress(pf->state))\n+\t\terr = -EBUSY;\n+\telse\n+\t\tstatus = ice_handle_nvm_access(hw, nvm, data);\n+\n+\tif (status) {\n+\t\terr = ice_status_to_errno(status);\n+\t\tnetdev_info(netdev, \"NVM write failed with status %d, error %d\\n\",\n+\t\t\t    status, err);\n+\t}\n+\n+\treturn err;\n+}\n+\n /**\n  * ice_active_vfs - check if there are any active VFs\n  * @pf: board private structure\n@@ -3467,6 +3552,7 @@ static const struct ethtool_ops ice_ethtool_ops = {\n \t.get_link\t\t= ethtool_op_get_link,\n \t.get_eeprom_len\t\t= ice_get_eeprom_len,\n \t.get_eeprom\t\t= ice_get_eeprom,\n+\t.set_eeprom\t\t= ice_set_eeprom,\n \t.get_coalesce\t\t= ice_get_coalesce,\n \t.set_coalesce\t\t= ice_set_coalesce,\n \t.get_strings\t\t= ice_get_strings,\n@@ -3502,6 +3588,7 @@ static const struct ethtool_ops ice_ethtool_safe_mode_ops = {\n \t.set_msglevel\t\t= ice_set_msglevel,\n \t.get_eeprom_len\t\t= ice_get_eeprom_len,\n \t.get_eeprom\t\t= ice_get_eeprom,\n+\t.set_eeprom\t\t= ice_set_eeprom,\n \t.get_strings\t\t= ice_get_strings,\n \t.get_ethtool_stats\t= ice_get_ethtool_stats,\n \t.get_sset_count\t\t= ice_get_sset_count,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\nindex 05a71f223c5d..d541815230de 100644\n--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n@@ -92,6 +92,7 @@\n #define QRXFLXP_CNTXT_RXDID_IDX_M\t\tICE_M(0x3F, 0)\n #define QRXFLXP_CNTXT_RXDID_PRIO_S\t\t8\n #define QRXFLXP_CNTXT_RXDID_PRIO_M\t\tICE_M(0x7, 8)\n+#define GL_FWSTS\t\t\t\t0x00083048\n #define GLGEN_RSTAT\t\t\t\t0x000B8188\n #define GLGEN_RSTAT_DEVSTATE_M\t\t\tICE_M(0x3, 0)\n #define GLGEN_RSTCTL\t\t\t\t0x000B8180\n@@ -268,6 +269,7 @@\n #define VP_MDET_TX_TCLAN_VALID_M\t\tBIT(0)\n #define VP_MDET_TX_TDPU(_VF)\t\t\t(0x00040000 + ((_VF) * 4))\n #define VP_MDET_TX_TDPU_VALID_M\t\t\tBIT(0)\n+#define GL_MNG_FWSM\t\t\t\t0x000B6134\n #define GLNVM_FLA\t\t\t\t0x000B6108\n #define GLNVM_FLA_LOCKED_M\t\t\tBIT(6)\n #define GLNVM_GENS\t\t\t\t0x000B6100\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c\nindex f69a1a59d70e..7a55449d8b87 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.c\n@@ -2653,3 +2653,27 @@ ice_vsi_cfg_mac_fltr(struct ice_vsi *vsi, const u8 *macaddr, bool set)\n \tice_free_fltr_list(&vsi->back->pdev->dev, &tmp_add_list);\n \treturn status;\n }\n+\n+/**\n+ * ice_status_to_errno - convert from enum ice_status to Linux errno\n+ * @err: ice_status value to convert\n+ */\n+int ice_status_to_errno(enum ice_status err)\n+{\n+\tswitch (err) {\n+\tcase ICE_SUCCESS:\n+\t\treturn 0;\n+\tcase ICE_ERR_DOES_NOT_EXIST:\n+\t\treturn -ENOENT;\n+\tcase ICE_ERR_OUT_OF_RANGE:\n+\t\treturn -ENOTTY;\n+\tcase ICE_ERR_PARAM:\n+\t\treturn -EINVAL;\n+\tcase ICE_ERR_NO_MEMORY:\n+\t\treturn -ENOMEM;\n+\tcase ICE_ERR_MAX_LIMIT:\n+\t\treturn -EAGAIN;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h\nindex 12cb89e28631..dc33d98cfded 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.h\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.h\n@@ -91,6 +91,8 @@ void ice_update_rx_ring_stats(struct ice_ring *ring, u64 pkts, u64 bytes);\n \n void ice_vsi_cfg_frame_size(struct ice_vsi *vsi);\n \n+int ice_status_to_errno(enum ice_status err);\n+\n u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran);\n \n char *ice_nvm_version_str(struct ice_hw *hw);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c\nindex bcb431f1bd92..bd19ce9b5bfd 100644\n--- a/drivers/net/ethernet/intel/ice/ice_nvm.c\n+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c\n@@ -11,13 +11,15 @@\n  * @length: length of the section to be read (in bytes from the offset)\n  * @data: command buffer (size [bytes] = length)\n  * @last_command: tells if this is the last command in a series\n+ * @read_shadow_ram: tell if this is a shadow RAM read\n  * @cd: pointer to command details structure or NULL\n  *\n  * Read the NVM using the admin queue commands (0x0701)\n  */\n-static enum ice_status\n+enum ice_status\n ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length,\n-\t\tvoid *data, bool last_command, struct ice_sq_cd *cd)\n+\t\tvoid *data, bool last_command, bool read_shadow_ram,\n+\t\tstruct ice_sq_cd *cd)\n {\n \tstruct ice_aq_desc desc;\n \tstruct ice_aqc_nvm *cmd;\n@@ -30,6 +32,9 @@ ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length,\n \n \tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_read);\n \n+\tif (!read_shadow_ram && module_typeid == ICE_AQC_NVM_START_POINT)\n+\t\tcmd->cmd_flags |= ICE_AQC_NVM_FLASH_ONLY;\n+\n \t/* If this is the last command in a series, set the proper flag. */\n \tif (last_command)\n \t\tcmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD;\n@@ -98,8 +103,9 @@ ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16 *data,\n \t * So do this conversion while calling ice_aq_read_nvm.\n \t */\n \tif (!status)\n-\t\tstatus = ice_aq_read_nvm(hw, 0, 2 * offset, 2 * words, data,\n-\t\t\t\t\t last_command, NULL);\n+\t\tstatus = ice_aq_read_nvm(hw, ICE_AQC_NVM_START_POINT,\n+\t\t\t\t\t 2 * offset, 2 * words, data,\n+\t\t\t\t\t last_command, true, NULL);\n \n \treturn status;\n }\n@@ -124,63 +130,6 @@ ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)\n \treturn status;\n }\n \n-/**\n- * ice_read_sr_buf_aq - Reads Shadow RAM buf via AQ\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 buf) from the SR using the ice_read_sr_aq\n- * method. Ownership of the NVM is taken before reading the buffer and later\n- * released.\n- */\n-static enum ice_status\n-ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)\n-{\n-\tenum ice_status status;\n-\tbool last_cmd = false;\n-\tu16 words_read = 0;\n-\tu16 i = 0;\n-\n-\tdo {\n-\t\tu16 read_size, off_w;\n-\n-\t\t/* Calculate number of bytes we should read in this step.\n-\t\t * It's not allowed to read more than one page at a time or\n-\t\t * to cross page boundaries.\n-\t\t */\n-\t\toff_w = offset % ICE_SR_SECTOR_SIZE_IN_WORDS;\n-\t\tread_size = off_w ?\n-\t\t\tmin_t(u16, *words,\n-\t\t\t      (ICE_SR_SECTOR_SIZE_IN_WORDS - off_w)) :\n-\t\t\tmin_t(u16, (*words - words_read),\n-\t\t\t      ICE_SR_SECTOR_SIZE_IN_WORDS);\n-\n-\t\t/* Check if this is last command, if so set proper flag */\n-\t\tif ((words_read + read_size) >= *words)\n-\t\t\tlast_cmd = true;\n-\n-\t\tstatus = ice_read_sr_aq(hw, offset, read_size,\n-\t\t\t\t\tdata + words_read, last_cmd);\n-\t\tif (status)\n-\t\t\tgoto read_nvm_buf_aq_exit;\n-\n-\t\t/* Increment counter for words already read and move offset to\n-\t\t * new read location\n-\t\t */\n-\t\twords_read += read_size;\n-\t\toffset += read_size;\n-\t} while (words_read < *words);\n-\n-\tfor (i = 0; i < *words; i++)\n-\t\tdata[i] = le16_to_cpu(((__force __le16 *)data)[i]);\n-\n-read_nvm_buf_aq_exit:\n-\t*words = words_read;\n-\treturn status;\n-}\n-\n /**\n  * ice_acquire_nvm - Generic request for acquiring the NVM ownership\n  * @hw: pointer to the HW structure\n@@ -188,7 +137,7 @@ ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)\n  *\n  * This function will request NVM ownership.\n  */\n-static enum ice_status\n+enum ice_status\n ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)\n {\n \tif (hw->nvm.blank_nvm_mode)\n@@ -203,7 +152,7 @@ ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)\n  *\n  * This function will release NVM ownership.\n  */\n-static void ice_release_nvm(struct ice_hw *hw)\n+void ice_release_nvm(struct ice_hw *hw)\n {\n \tif (hw->nvm.blank_nvm_mode)\n \t\treturn;\n@@ -219,8 +168,8 @@ static void ice_release_nvm(struct ice_hw *hw)\n  *\n  * Reads one 16 bit word from the Shadow RAM using the ice_read_sr_word_aq.\n  */\n-static enum ice_status\n-ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)\n+static enum\n+ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)\n {\n \tenum ice_status status;\n \n@@ -292,31 +241,6 @@ enum ice_status ice_init_nvm(struct ice_hw *hw)\n \treturn status;\n }\n \n-/**\n- * ice_read_sr_buf - Reads Shadow RAM buf 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- * @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 buf) from the SR using the ice_read_nvm_buf_aq\n- * method. The buf read is preceded by the NVM ownership take\n- * and followed by the release.\n- */\n-enum ice_status\n-ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)\n-{\n-\tenum ice_status status;\n-\n-\tstatus = ice_acquire_nvm(hw, ICE_RES_READ);\n-\tif (!status) {\n-\t\tstatus = ice_read_sr_buf_aq(hw, offset, words, data);\n-\t\tice_release_nvm(hw);\n-\t}\n-\n-\treturn status;\n-}\n-\n /**\n  * ice_nvm_validate_checksum\n  * @hw: pointer to the HW struct\n@@ -347,3 +271,240 @@ enum ice_status ice_nvm_validate_checksum(struct ice_hw *hw)\n \n \treturn status;\n }\n+\n+/**\n+ * ice_nvm_access_get_features - Return the NVM access features structure\n+ * @cmd: NVM access command to process\n+ * @data: storage for the driver NVM features\n+ *\n+ * Fill in the data section of the NVM access request with a copy of the NVM\n+ * features structure.\n+ */\n+static enum ice_status\n+ice_nvm_access_get_features(struct ice_nvm_access_cmd *cmd,\n+\t\t\t    union ice_nvm_access_data *data)\n+{\n+\t/* The provided data_size must be at least as large as our NVM\n+\t * features structure. A larger size should not be treated as an\n+\t * error, to allow future extensions to to the features structure to\n+\t * work on older drivers.\n+\t */\n+\tif (cmd->data_size < sizeof(struct ice_nvm_features))\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t/* Initialize the data buffer to zeros */\n+\tmemset(data, 0, cmd->data_size);\n+\n+\t/* Fill in the features data */\n+\tdata->drv_features.major = ICE_NVM_ACCESS_MAJOR_VER;\n+\tdata->drv_features.minor = ICE_NVM_ACCESS_MINOR_VER;\n+\tdata->drv_features.size = sizeof(struct ice_nvm_features);\n+\tdata->drv_features.features[0] = ICE_NVM_FEATURES_0_REG_ACCESS;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_nvm_access_get_module - Helper function to read module value\n+ * @cmd: NVM access command structure\n+ *\n+ * Reads the module value out of the NVM access config field.\n+ */\n+static u32 ice_nvm_access_get_module(struct ice_nvm_access_cmd *cmd)\n+{\n+\treturn ((cmd->config & ICE_NVM_CFG_MODULE_M) >> ICE_NVM_CFG_MODULE_S);\n+}\n+\n+/**\n+ * ice_nvm_access_get_flags - Helper function to read flags value\n+ * @cmd: NVM access command structure\n+ *\n+ * Reads the flags value out of the NVM access config field.\n+ */\n+static u32 ice_nvm_access_get_flags(struct ice_nvm_access_cmd *cmd)\n+{\n+\treturn ((cmd->config & ICE_NVM_CFG_FLAGS_M) >> ICE_NVM_CFG_FLAGS_S);\n+}\n+\n+/**\n+ * ice_nvm_access_get_adapter - Helper function to read adapter info\n+ * @cmd: NVM access command structure\n+ *\n+ * Read the adapter info value out of the NVM access config field.\n+ */\n+static u32 ice_nvm_access_get_adapter(struct ice_nvm_access_cmd *cmd)\n+{\n+\treturn ((cmd->config & ICE_NVM_CFG_ADAPTER_INFO_M) >>\n+\t\tICE_NVM_CFG_ADAPTER_INFO_S);\n+}\n+\n+/**\n+ * ice_validate_nvm_rw_reg - Check than an NVM access request is valid\n+ * @cmd: NVM access command structure\n+ *\n+ * Validates that an NVM access structure is request to read or write a valid\n+ * register offset. First validates that the module and flags are correct, and\n+ * then ensures that the register offset is one of the accepted registers.\n+ */\n+static enum ice_status\n+ice_validate_nvm_rw_reg(struct ice_nvm_access_cmd *cmd)\n+{\n+\tu32 module, flags, offset;\n+\tu16 i;\n+\n+\tmodule = ice_nvm_access_get_module(cmd);\n+\tflags = ice_nvm_access_get_flags(cmd);\n+\toffset = cmd->offset;\n+\n+\t/* Make sure the module and flags indicate a read/write request */\n+\tif (module != ICE_NVM_REG_RW_MODULE ||\n+\t    flags != ICE_NVM_REG_RW_FLAGS ||\n+\t    cmd->data_size != FIELD_SIZEOF(union ice_nvm_access_data, regval))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tswitch (offset) {\n+\tcase GL_HICR:\n+\tcase GL_HICR_EN: /* Note, this register is read only */\n+\tcase GL_FWSTS:\n+\tcase GL_MNG_FWSM:\n+\tcase GLGEN_CSR_DEBUG_C:\n+\tcase GLGEN_RSTAT:\n+\tcase GLPCI_LBARCTRL:\n+\tcase GLNVM_GENS:\n+\tcase GLNVM_FLA:\n+\tcase PF_FUNC_RID:\n+\t\treturn 0;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tfor (i = 0; i <= ICE_NVM_ACCESS_GL_HIDA_MAX; i++)\n+\t\tif (offset == (u32)GL_HIDA(i))\n+\t\t\treturn 0;\n+\n+\tfor (i = 0; i <= ICE_NVM_ACCESS_GL_HIBA_MAX; i++)\n+\t\tif (offset == (u32)GL_HIBA(i))\n+\t\t\treturn 0;\n+\n+\t/* All other register offsets are not valid */\n+\treturn ICE_ERR_OUT_OF_RANGE;\n+}\n+\n+/**\n+ * ice_nvm_access_read - Handle an NVM read request\n+ * @hw: pointer to the HW struct\n+ * @cmd: NVM access command to process\n+ * @data: storage for the register value read\n+ *\n+ * Process an NVM access request to read a register.\n+ */\n+static enum ice_status\n+ice_nvm_access_read(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd,\n+\t\t    union ice_nvm_access_data *data)\n+{\n+\tenum ice_status status;\n+\n+\t/* Always initialize the output data, even on failure */\n+\tmemset(data, 0, cmd->data_size);\n+\n+\t/* Make sure this is a valid read/write access request */\n+\tstatus = ice_validate_nvm_rw_reg(cmd);\n+\tif (status)\n+\t\treturn status;\n+\n+\tice_debug(hw, ICE_DBG_NVM, \"NVM access: reading register %08x\\n\",\n+\t\t  cmd->offset);\n+\n+\t/* Read the register and store the contents in the data field */\n+\tdata->regval = rd32(hw, cmd->offset);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_nvm_access_write - Handle an NVM write request\n+ * @hw: pointer to the HW struct\n+ * @cmd: NVM access command to process\n+ * @data: NVM access data to write\n+ *\n+ * Process an NVM access request to write a register.\n+ */\n+static enum ice_status\n+ice_nvm_access_write(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd,\n+\t\t     union ice_nvm_access_data *data)\n+{\n+\tenum ice_status status;\n+\n+\t/* Make sure this is a valid read/write access request */\n+\tstatus = ice_validate_nvm_rw_reg(cmd);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* Reject requests to write to read-only registers */\n+\tswitch (cmd->offset) {\n+\tcase GL_HICR_EN:\n+\tcase GLGEN_RSTAT:\n+\t\treturn ICE_ERR_OUT_OF_RANGE;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tice_debug(hw, ICE_DBG_NVM,\n+\t\t  \"NVM access: writing register %08x with value %08x\\n\",\n+\t\t  cmd->offset, data->regval);\n+\n+\t/* Write the data field to the specified register */\n+\twr32(hw, cmd->offset, data->regval);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_handle_nvm_access - Handle an NVM access request\n+ * @hw: pointer to the HW struct\n+ * @cmd: NVM access command info\n+ * @data: pointer to read or return data\n+ *\n+ * Process an NVM access request. Read the command structure information and\n+ * determine if it is valid. If not, report an error indicating the command\n+ * was invalid.\n+ *\n+ * For valid commands, perform the necessary function, copying the data into\n+ * the provided data buffer.\n+ */\n+enum ice_status\n+ice_handle_nvm_access(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd,\n+\t\t      union ice_nvm_access_data *data)\n+{\n+\tu32 module, flags, adapter_info;\n+\n+\t/* Extended flags are currently reserved and must be zero */\n+\tif ((cmd->config & ICE_NVM_CFG_EXT_FLAGS_M) != 0)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\t/* Adapter info must match the HW device ID */\n+\tadapter_info = ice_nvm_access_get_adapter(cmd);\n+\tif (adapter_info != hw->device_id)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tswitch (cmd->command) {\n+\tcase ICE_NVM_CMD_READ:\n+\t\tmodule = ice_nvm_access_get_module(cmd);\n+\t\tflags = ice_nvm_access_get_flags(cmd);\n+\n+\t\t/* Getting the driver's NVM features structure shares the same\n+\t\t * command type as reading a register. Read the config field\n+\t\t * to determine if this is a request to get features.\n+\t\t */\n+\t\tif (module == ICE_NVM_GET_FEATURES_MODULE &&\n+\t\t    flags == ICE_NVM_GET_FEATURES_FLAGS &&\n+\t\t    cmd->offset == 0)\n+\t\t\treturn ice_nvm_access_get_features(cmd, data);\n+\t\telse\n+\t\t\treturn ice_nvm_access_read(hw, cmd, data);\n+\tcase ICE_NVM_CMD_WRITE:\n+\t\treturn ice_nvm_access_write(hw, cmd, data);\n+\tdefault:\n+\t\treturn ICE_ERR_PARAM;\n+\t}\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_nvm.h b/drivers/net/ethernet/intel/ice/ice_nvm.h\nnew file mode 100644\nindex 000000000000..75d167b7ebe3\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_nvm.h\n@@ -0,0 +1,79 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (c) 2019, Intel Corporation. */\n+\n+#ifndef _ICE_NVM_H_\n+#define _ICE_NVM_H_\n+\n+#define ICE_NVM_CMD_READ\t\t0x0000000B\n+#define ICE_NVM_CMD_WRITE\t\t0x0000000C\n+\n+/* NVM Access config bits */\n+#define ICE_NVM_CFG_MODULE_M\t\tICE_M(0xFF, 0)\n+#define ICE_NVM_CFG_MODULE_S\t\t0\n+#define ICE_NVM_CFG_FLAGS_M\t\tICE_M(0xF, 8)\n+#define ICE_NVM_CFG_FLAGS_S\t\t8\n+#define ICE_NVM_CFG_EXT_FLAGS_M\t\tICE_M(0xF, 12)\n+#define ICE_NVM_CFG_ADAPTER_INFO_M\tICE_M(0xFFFF, 16)\n+#define ICE_NVM_CFG_ADAPTER_INFO_S\t16\n+\n+/* NVM Read Get Driver Features */\n+#define ICE_NVM_GET_FEATURES_MODULE\t0xE\n+#define ICE_NVM_GET_FEATURES_FLAGS\t0xF\n+\n+/* NVM Read/Write Mapped Space */\n+#define ICE_NVM_REG_RW_MODULE\t0x0\n+#define ICE_NVM_REG_RW_FLAGS\t0x1\n+\n+#define ICE_NVM_ACCESS_MAJOR_VER\t0\n+#define ICE_NVM_ACCESS_MINOR_VER\t5\n+\n+/* NVM Access feature flags. Other bits in the features field are reserved and\n+ * should be set to zero when reporting the ice_nvm_features structure.\n+ */\n+#define ICE_NVM_FEATURES_0_REG_ACCESS\tBIT(1)\n+\n+/* NVM Access Features */\n+struct ice_nvm_features {\n+\tu8 major;\t\t/* Major version (informational only) */\n+\tu8 minor;\t\t/* Minor version (informational only) */\n+\tu16 size;\t\t/* size of ice_nvm_features structure */\n+\tu8 features[12];\t/* Array of feature bits */\n+};\n+\n+/* NVM Access command */\n+struct ice_nvm_access_cmd {\n+\tu32 command;\t\t/* NVM command: READ or WRITE */\n+\tu32 config;\t\t/* NVM command configuration */\n+\tu32 offset;\t\t/* offset to read/write, in bytes */\n+\tu32 data_size;\t\t/* size of data field, in bytes */\n+};\n+\n+/* NVM Access data */\n+union ice_nvm_access_data {\n+\tu32 regval;\t/* Storage for register value */\n+\tstruct ice_nvm_features drv_features; /* NVM features */\n+};\n+\n+/* NVM Access registers */\n+#define GL_HIDA(_i)\t\t\t(0x00082000 + ((_i) * 4))\n+#define GL_HIBA(_i)\t\t\t(0x00081000 + ((_i) * 4))\n+#define GL_HICR\t\t\t\t0x00082040\n+#define GL_HICR_EN\t\t\t0x00082044\n+#define GLGEN_CSR_DEBUG_C\t\t0x00075750\n+#define GLPCI_LBARCTRL\t\t\t0x0009DE74\n+\n+#define ICE_NVM_ACCESS_GL_HIDA_MAX\t15\n+#define ICE_NVM_ACCESS_GL_HIBA_MAX\t1023\n+\n+enum ice_status\n+ice_handle_nvm_access(struct ice_hw *hw, struct ice_nvm_access_cmd *cmd,\n+\t\t      union ice_nvm_access_data *data);\n+enum ice_status\n+ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access);\n+void ice_release_nvm(struct ice_hw *hw);\n+enum ice_status\n+ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length,\n+\t\tvoid *data, bool last_command, bool read_shadow_ram,\n+\t\tstruct ice_sq_cd *cd);\n+enum ice_status ice_init_nvm(struct ice_hw *hw);\n+#endif /* _ICE_NVM_H_ */\n",
    "prefixes": [
        "S31",
        "01/15"
    ]
}