get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 17315,
    "url": "http://patches.dpdk.org/api/patches/17315/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1480436367-20749-27-git-send-email-arybchenko@solarflare.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1480436367-20749-27-git-send-email-arybchenko@solarflare.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1480436367-20749-27-git-send-email-arybchenko@solarflare.com",
    "date": "2016-11-29T16:18:58",
    "name": "[dpdk-dev,v2,26/55] net/sfc: import libefx NVRAM support",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "f6d7ae35262a941f49b597a305fabadc94df9ca0",
    "submitter": {
        "id": 607,
        "url": "http://patches.dpdk.org/api/people/607/?format=api",
        "name": "Andrew Rybchenko",
        "email": "arybchenko@solarflare.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1480436367-20749-27-git-send-email-arybchenko@solarflare.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/17315/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/17315/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 51FDD5591;\n\tTue, 29 Nov 2016 17:22:37 +0100 (CET)",
            "from nbfkord-smmo01.seg.att.com (nbfkord-smmo01.seg.att.com\n\t[209.65.160.76]) by dpdk.org (Postfix) with ESMTP id ABAB44A59\n\tfor <dev@dpdk.org>; Tue, 29 Nov 2016 17:20:53 +0100 (CET)",
            "from unknown [12.187.104.26] (EHLO nbfkord-smmo01.seg.att.com)\n\tby nbfkord-smmo01.seg.att.com(mxl_mta-7.2.4-7) with ESMTP id\n\t5eaad385.2b3ec60af940.83589.00-2486.173920.nbfkord-smmo01.seg.att.com\n\t(envelope-from <arybchenko@solarflare.com>); \n\tTue, 29 Nov 2016 16:20:53 +0000 (UTC)",
            "from unknown [12.187.104.26]\n\tby nbfkord-smmo01.seg.att.com(mxl_mta-7.2.4-7) with SMTP id\n\t3eaad385.0.83400.00-2363.173863.nbfkord-smmo01.seg.att.com\n\t(envelope-from <arybchenko@solarflare.com>); \n\tTue, 29 Nov 2016 16:20:52 +0000 (UTC)",
            "from ocex03.SolarFlarecom.com (10.20.40.36) by\n\tocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server\n\t(TLS) id 15.0.1044.25; Tue, 29 Nov 2016 08:20:25 -0800",
            "from opal.uk.solarflarecom.com (10.17.10.1) by\n\tocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server\n\t(TLS) id\n\t15.0.1044.25 via Frontend Transport; Tue, 29 Nov 2016 08:20:25 -0800",
            "from uklogin.uk.solarflarecom.com (uklogin.uk.solarflarecom.com\n\t[10.17.10.10])\n\tby opal.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id\n\tuATGKOQS029967; Tue, 29 Nov 2016 16:20:24 GMT",
            "from uklogin.uk.solarflarecom.com (localhost.localdomain\n\t[127.0.0.1])\n\tby uklogin.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id\n\tuATGKM1Y021233; Tue, 29 Nov 2016 16:20:24 GMT"
        ],
        "X-MXL-Hash": [
            "583daae57dc29260-177a264ed241f246f446e1c6e54e8789fbbeef48",
            "583daae429818b47-c7100a77c96ec3ff81275847e6f29f3369b71039"
        ],
        "From": "Andrew Rybchenko <arybchenko@solarflare.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<ferruh.yigit@intel.com>",
        "Date": "Tue, 29 Nov 2016 16:18:58 +0000",
        "Message-ID": "<1480436367-20749-27-git-send-email-arybchenko@solarflare.com>",
        "X-Mailer": "git-send-email 1.8.2.3",
        "In-Reply-To": "<1480436367-20749-1-git-send-email-arybchenko@solarflare.com>",
        "References": "<1479740470-6723-1-git-send-email-arybchenko@solarflare.com>\n\t<1480436367-20749-1-git-send-email-arybchenko@solarflare.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-AnalysisOut": [
            "[v=2.1 cv=UoJlQrEB c=1 sm=1 tr=0 a=8BlWFWvVlq5taO8ncb8nKg==]",
            "[:17 a=L24OOQBejmoA:10 a=zRKbQ67AAAAA:8 a=LOmOTvbtgsIQUqEBW]",
            "[3cA:9 a=BsjxfoBSgi50ErnD:21 a=u2iUZ8ZlIR1AEXwe:21 a=irRjsw]",
            "[_yJKtvYuIk:21 a=PA03WX8tBzeizutn5_OT:22]"
        ],
        "X-Spam": "[F=0.2000000000; CM=0.500; S=0.200(2015072901)]",
        "X-MAIL-FROM": "<arybchenko@solarflare.com>",
        "X-SOURCE-IP": "[12.187.104.26]",
        "Subject": "[dpdk-dev] [PATCH v2 26/55] net/sfc: import libefx NVRAM support",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Provide API to work with NIC non-volatile memory. It is used\nto update firmware, configure NIC including bootrom parameters,\nmanage licenses, store PCI Vital Product Data etc.\n\nEFSYS_OPT_NVRAM should be enabled to use it.\n\nFrom Solarflare Communications Inc.\n\nSigned-off-by: Andrew Rybchenko <arybchenko@solarflare.com>\n---\n drivers/net/sfc/base/ef10_impl.h   |  222 ++++\n drivers/net/sfc/base/ef10_nvram.c  | 2385 ++++++++++++++++++++++++++++++++++++\n drivers/net/sfc/base/efx.h         |   96 ++\n drivers/net/sfc/base/efx_check.h   |    7 +\n drivers/net/sfc/base/efx_impl.h    |  106 ++\n drivers/net/sfc/base/efx_nvram.c   | 1044 ++++++++++++++++\n drivers/net/sfc/base/siena_impl.h  |   99 ++\n drivers/net/sfc/base/siena_nic.c   |   55 +\n drivers/net/sfc/base/siena_nvram.c |  734 +++++++++++\n 9 files changed, 4748 insertions(+)\n create mode 100644 drivers/net/sfc/base/ef10_nvram.c\n create mode 100644 drivers/net/sfc/base/efx_nvram.c\n create mode 100644 drivers/net/sfc/base/siena_nvram.c",
    "diff": "diff --git a/drivers/net/sfc/base/ef10_impl.h b/drivers/net/sfc/base/ef10_impl.h\nindex 94706dc..e3b2621 100644\n--- a/drivers/net/sfc/base/ef10_impl.h\n+++ b/drivers/net/sfc/base/ef10_impl.h\n@@ -339,6 +339,228 @@ ef10_mcdi_get_timeout(\n \n /* NVRAM */\n \n+#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buf_read_tlv(\n+\t__in\t\t\t\tefx_nic_t *enp,\n+\t__in_bcount(max_seg_size)\tcaddr_t seg_data,\n+\t__in\t\t\t\tsize_t max_seg_size,\n+\t__in\t\t\t\tuint32_t tag,\n+\t__deref_out_bcount_opt(*sizep)\tcaddr_t *datap,\n+\t__out\t\t\t\tsize_t *sizep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buf_write_tlv(\n+\t__inout_bcount(partn_size)\tcaddr_t partn_data,\n+\t__in\t\t\t\tsize_t partn_size,\n+\t__in\t\t\t\tuint32_t tag,\n+\t__in_bcount(tag_size)\t\tcaddr_t tag_data,\n+\t__in\t\t\t\tsize_t tag_size,\n+\t__out\t\t\t\tsize_t *total_lengthp);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_read_tlv(\n+\t__in\t\t\t\tefx_nic_t *enp,\n+\t__in\t\t\t\tuint32_t partn,\n+\t__in\t\t\t\tuint32_t tag,\n+\t__deref_out_bcount_opt(*sizep)\tcaddr_t *datap,\n+\t__out\t\t\t\tsize_t *sizep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_write_tlv(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t tag,\n+\t__in_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_write_segment_tlv(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t tag,\n+\t__in_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__in\t\t\tboolean_t all_segments);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_lock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_unlock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out_opt\t\tuint32_t *resultp);\n+\n+#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */\n+\n+#if EFSYS_OPT_NVRAM\n+\n+#if EFSYS_OPT_DIAG\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp);\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_type_to_partn(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tuint32_t *partnp);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_size(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *sizep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_rw_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *chunk_sizep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_read_mode(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__in\t\t\tuint32_t mode);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_read(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_write(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_rw_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_get_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4]);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_set_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in_ecount(4)\t\tuint16_t version[4]);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_validate(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_create(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint16_t partn_type,\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_find_item_start(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__out\t\t\tuint32_t *startp\n+\t);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_find_end(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__out\t\t\tuint32_t *endp\n+\t);\n+\n+extern\t__checkReturn\t__success(return != B_FALSE)\tboolean_t\n+ef10_nvram_buffer_find_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__out\t\t\tuint32_t *startp,\n+\t__out\t\t\tuint32_t *lengthp\n+\t);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_get_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__in\t\t\tuint32_t length,\n+\t__out_bcount_part(item_max_size, *lengthp)\n+\t\t\t\tcaddr_t itemp,\n+\t__in\t\t\tsize_t item_max_size,\n+\t__out\t\t\tuint32_t *lengthp\n+\t);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_insert_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__in_bcount(length)\tcaddr_t keyp,\n+\t__in\t\t\tuint32_t length,\n+\t__out\t\t\tuint32_t *lengthp\n+\t);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_delete_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__in\t\t\tuint32_t length,\n+\t__in\t\t\tuint32_t end\n+\t);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_finish(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size\n+\t);\n+\n+#endif\t/* EFSYS_OPT_NVRAM */\n+\n \n /* PHY */\n \ndiff --git a/drivers/net/sfc/base/ef10_nvram.c b/drivers/net/sfc/base/ef10_nvram.c\nnew file mode 100644\nindex 0000000..3f9d375\n--- /dev/null\n+++ b/drivers/net/sfc/base/ef10_nvram.c\n@@ -0,0 +1,2385 @@\n+/*\n+ * Copyright (c) 2012-2016 Solarflare Communications Inc.\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ *\n+ * 1. Redistributions of source code must retain the above copyright notice,\n+ *    this list of conditions and the following disclaimer.\n+ * 2. Redistributions in binary form must reproduce the above copyright notice,\n+ *    this list of conditions and the following disclaimer in the documentation\n+ *    and/or other materials provided with the distribution.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ *\n+ * The views and conclusions contained in the software and documentation are\n+ * those of the authors and should not be interpreted as representing official\n+ * policies, either expressed or implied, of the FreeBSD Project.\n+ */\n+\n+#include \"efx.h\"\n+#include \"efx_impl.h\"\n+\n+#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD\n+\n+#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM\n+\n+#include \"ef10_tlv_layout.h\"\n+\n+/* Cursor for TLV partition format */\n+typedef struct tlv_cursor_s {\n+\tuint32_t\t*block;\t\t\t/* Base of data block */\n+\tuint32_t\t*current;\t\t/* Cursor position */\n+\tuint32_t\t*end;\t\t\t/* End tag position */\n+\tuint32_t\t*limit;\t\t\t/* Last dword of data block */\n+} tlv_cursor_t;\n+\n+typedef struct nvram_partition_s {\n+\tuint16_t type;\n+\tuint8_t chip_select;\n+\tuint8_t flags;\n+\t/*\n+\t * The full length of the NVRAM partition.\n+\t * This is different from tlv_partition_header.total_length,\n+\t *  which can be smaller.\n+\t */\n+\tuint32_t length;\n+\tuint32_t erase_size;\n+\tuint32_t *data;\n+\ttlv_cursor_t tlv_cursor;\n+} nvram_partition_t;\n+\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_validate_state(\n+\t__inout\t\t\ttlv_cursor_t *cursor);\n+\n+\n+static\t\t\t\tvoid\n+tlv_init_block(\n+\t__out\tuint32_t\t*block)\n+{\n+\t*block = __CPU_TO_LE_32(TLV_TAG_END);\n+}\n+\n+static\t\t\t\tuint32_t\n+tlv_tag(\n+\t__in\ttlv_cursor_t\t*cursor)\n+{\n+\tuint32_t dword, tag;\n+\n+\tdword = cursor->current[0];\n+\ttag = __LE_TO_CPU_32(dword);\n+\n+\treturn (tag);\n+}\n+\n+static\t\t\t\tsize_t\n+tlv_length(\n+\t__in\ttlv_cursor_t\t*cursor)\n+{\n+\tuint32_t dword, length;\n+\n+\tif (tlv_tag(cursor) == TLV_TAG_END)\n+\t\treturn (0);\n+\n+\tdword = cursor->current[1];\n+\tlength = __LE_TO_CPU_32(dword);\n+\n+\treturn ((size_t)length);\n+}\n+\n+static\t\t\t\tuint8_t *\n+tlv_value(\n+\t__in\ttlv_cursor_t\t*cursor)\n+{\n+\tif (tlv_tag(cursor) == TLV_TAG_END)\n+\t\treturn (NULL);\n+\n+\treturn ((uint8_t *)(&cursor->current[2]));\n+}\n+\n+static\t\t\t\tuint8_t *\n+tlv_item(\n+\t__in\ttlv_cursor_t\t*cursor)\n+{\n+\tif (tlv_tag(cursor) == TLV_TAG_END)\n+\t\treturn (NULL);\n+\n+\treturn ((uint8_t *)cursor->current);\n+}\n+\n+/*\n+ * TLV item DWORD length is tag + length + value (rounded up to DWORD)\n+ * equivalent to tlv_n_words_for_len in mc-comms tlv.c\n+ */\n+#define\tTLV_DWORD_COUNT(length) \\\n+\t(1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t)))\n+\n+\n+static\t\t\t\tuint32_t *\n+tlv_next_item_ptr(\n+\t__in\ttlv_cursor_t\t*cursor)\n+{\n+\tuint32_t length;\n+\n+\tlength = tlv_length(cursor);\n+\n+\treturn (cursor->current + TLV_DWORD_COUNT(length));\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_advance(\n+\t__inout\ttlv_cursor_t\t*cursor)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = tlv_validate_state(cursor)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (cursor->current == cursor->end) {\n+\t\t/* No more tags after END tag */\n+\t\tcursor->current = NULL;\n+\t\trc = ENOENT;\n+\t\tgoto fail2;\n+\t}\n+\n+\t/* Advance to next item and validate */\n+\tcursor->current = tlv_next_item_ptr(cursor);\n+\n+\tif ((rc = tlv_validate_state(cursor)) != 0)\n+\t\tgoto fail3;\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static\t\t\t\tefx_rc_t\n+tlv_rewind(\n+\t__in\ttlv_cursor_t\t*cursor)\n+{\n+\tefx_rc_t rc;\n+\n+\tcursor->current = cursor->block;\n+\n+\tif ((rc = tlv_validate_state(cursor)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static\t\t\t\tefx_rc_t\n+tlv_find(\n+\t__inout\ttlv_cursor_t\t*cursor,\n+\t__in\tuint32_t\ttag)\n+{\n+\tefx_rc_t rc;\n+\n+\trc = tlv_rewind(cursor);\n+\twhile (rc == 0) {\n+\t\tif (tlv_tag(cursor) == tag)\n+\t\t\tbreak;\n+\n+\t\trc = tlv_advance(cursor);\n+\t}\n+\treturn (rc);\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_validate_state(\n+\t__inout\ttlv_cursor_t\t*cursor)\n+{\n+\tefx_rc_t rc;\n+\n+\t/* Check cursor position */\n+\tif (cursor->current < cursor->block) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\tif (cursor->current > cursor->limit) {\n+\t\trc = EINVAL;\n+\t\tgoto fail2;\n+\t}\n+\n+\tif (tlv_tag(cursor) != TLV_TAG_END) {\n+\t\t/* Check current item has space for tag and length */\n+\t\tif (cursor->current > (cursor->limit - 2)) {\n+\t\t\tcursor->current = NULL;\n+\t\t\trc = EFAULT;\n+\t\t\tgoto fail3;\n+\t\t}\n+\n+\t\t/* Check we have value data for current item and another tag */\n+\t\tif (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) {\n+\t\t\tcursor->current = NULL;\n+\t\t\trc = EFAULT;\n+\t\t\tgoto fail4;\n+\t\t}\n+\t}\n+\n+\treturn (0);\n+\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static\t\t\t\tefx_rc_t\n+tlv_init_cursor(\n+\t__out\ttlv_cursor_t\t*cursor,\n+\t__in\tuint32_t\t*block,\n+\t__in\tuint32_t\t*limit,\n+\t__in\tuint32_t\t*current)\n+{\n+\tcursor->block\t= block;\n+\tcursor->limit\t= limit;\n+\n+\tcursor->current\t= current;\n+\tcursor->end\t= NULL;\n+\n+\treturn (tlv_validate_state(cursor));\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_init_cursor_from_size(\n+\t__out\ttlv_cursor_t\t*cursor,\n+\t__in_bcount(size)\n+\t\tuint8_t\t\t*block,\n+\t__in\tsize_t\t\tsize)\n+{\n+\tuint32_t *limit;\n+\tlimit = (uint32_t *)(block + size - sizeof (uint32_t));\n+\treturn (tlv_init_cursor(cursor, (uint32_t *)block,\n+\t\tlimit, (uint32_t *)block));\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_init_cursor_at_offset(\n+\t__out\ttlv_cursor_t\t*cursor,\n+\t__in_bcount(size)\n+\t\tuint8_t\t\t*block,\n+\t__in\tsize_t\t\tsize,\n+\t__in\tsize_t\t\toffset)\n+{\n+\tuint32_t *limit;\n+\tuint32_t *current;\n+\tlimit = (uint32_t *)(block + size - sizeof (uint32_t));\n+\tcurrent = (uint32_t *)(block + offset);\n+\treturn (tlv_init_cursor(cursor, (uint32_t *)block, limit, current));\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_require_end(\n+\t__inout\ttlv_cursor_t\t*cursor)\n+{\n+\tuint32_t *pos;\n+\tefx_rc_t rc;\n+\n+\tif (cursor->end == NULL) {\n+\t\tpos = cursor->current;\n+\t\tif ((rc = tlv_find(cursor, TLV_TAG_END)) != 0)\n+\t\t\tgoto fail1;\n+\n+\t\tcursor->end = cursor->current;\n+\t\tcursor->current = pos;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static\t\t\t\tsize_t\n+tlv_block_length_used(\n+\t__inout\ttlv_cursor_t\t*cursor)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = tlv_validate_state(cursor)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = tlv_require_end(cursor)) != 0)\n+\t\tgoto fail2;\n+\n+\t/* Return space used (including the END tag) */\n+\treturn (cursor->end + 1 - cursor->block) * sizeof (uint32_t);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (0);\n+}\n+\n+static\t\tuint32_t *\n+tlv_last_segment_end(\n+\t__in\ttlv_cursor_t *cursor)\n+{\n+\ttlv_cursor_t segment_cursor;\n+\tuint32_t *last_segment_end = cursor->block;\n+\tuint32_t *segment_start = cursor->block;\n+\n+\t/*\n+\t * Go through each segment and check that it has an end tag. If there\n+\t * is no end tag then the previous segment was the last valid one,\n+\t * so return the pointer to its end tag.\n+\t */\n+\tfor (;;) {\n+\t\tif (tlv_init_cursor(&segment_cursor, segment_start,\n+\t\t    cursor->limit, segment_start) != 0)\n+\t\t\tbreak;\n+\t\tif (tlv_require_end(&segment_cursor) != 0)\n+\t\t\tbreak;\n+\t\tlast_segment_end = segment_cursor.end;\n+\t\tsegment_start = segment_cursor.end + 1;\n+\t}\n+\n+\treturn (last_segment_end);\n+}\n+\n+\n+static\t\t\t\tuint32_t *\n+tlv_write(\n+\t__in\t\t\ttlv_cursor_t *cursor,\n+\t__in\t\t\tuint32_t tag,\n+\t__in_bcount(size)\tuint8_t *data,\n+\t__in\t\t\tsize_t size)\n+{\n+\tuint32_t len = size;\n+\tuint32_t *ptr;\n+\n+\tptr = cursor->current;\n+\n+\t*ptr++ = __CPU_TO_LE_32(tag);\n+\t*ptr++ = __CPU_TO_LE_32(len);\n+\n+\tif (len > 0) {\n+\t\tptr[(len - 1) / sizeof (uint32_t)] = 0;\n+\t\tmemcpy(ptr, data, len);\n+\t\tptr += P2ROUNDUP(len, sizeof (uint32_t)) / sizeof (*ptr);\n+\t}\n+\n+\treturn (ptr);\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_insert(\n+\t__inout\ttlv_cursor_t\t*cursor,\n+\t__in\tuint32_t\ttag,\n+\t__in_bcount(size)\n+\t\tuint8_t\t\t*data,\n+\t__in\tsize_t\t\tsize)\n+{\n+\tunsigned int delta;\n+\tuint32_t *last_segment_end;\n+\tefx_rc_t rc;\n+\n+\tif ((rc = tlv_validate_state(cursor)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = tlv_require_end(cursor)) != 0)\n+\t\tgoto fail2;\n+\n+\tif (tag == TLV_TAG_END) {\n+\t\trc = EINVAL;\n+\t\tgoto fail3;\n+\t}\n+\n+\tlast_segment_end = tlv_last_segment_end(cursor);\n+\n+\tdelta = TLV_DWORD_COUNT(size);\n+\tif (last_segment_end + 1 + delta > cursor->limit) {\n+\t\trc = ENOSPC;\n+\t\tgoto fail4;\n+\t}\n+\n+\t/* Move data up: new space at cursor->current */\n+\tmemmove(cursor->current + delta, cursor->current,\n+\t    (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));\n+\n+\t/* Adjust the end pointer */\n+\tcursor->end += delta;\n+\n+\t/* Write new TLV item */\n+\ttlv_write(cursor, tag, data, size);\n+\n+\treturn (0);\n+\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_delete(\n+\t__inout\ttlv_cursor_t\t*cursor)\n+{\n+\tunsigned int delta;\n+\tuint32_t *last_segment_end;\n+\tefx_rc_t rc;\n+\n+\tif ((rc = tlv_validate_state(cursor)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (tlv_tag(cursor) == TLV_TAG_END) {\n+\t\trc = EINVAL;\n+\t\tgoto fail2;\n+\t}\n+\n+\tdelta = TLV_DWORD_COUNT(tlv_length(cursor));\n+\n+\tif ((rc = tlv_require_end(cursor)) != 0)\n+\t\tgoto fail3;\n+\n+\tlast_segment_end = tlv_last_segment_end(cursor);\n+\n+\t/* Shuffle things down, destroying the item at cursor->current */\n+\tmemmove(cursor->current, cursor->current + delta,\n+\t    (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));\n+\t/* Zero the new space at the end of the TLV chain */\n+\tmemset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t));\n+\t/* Adjust the end pointer */\n+\tcursor->end -= delta;\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_modify(\n+\t__inout\ttlv_cursor_t\t*cursor,\n+\t__in\tuint32_t\ttag,\n+\t__in_bcount(size)\n+\t\tuint8_t\t\t*data,\n+\t__in\tsize_t\t\tsize)\n+{\n+\tuint32_t *pos;\n+\tunsigned int old_ndwords;\n+\tunsigned int new_ndwords;\n+\tunsigned int delta;\n+\tuint32_t *last_segment_end;\n+\tefx_rc_t rc;\n+\n+\tif ((rc = tlv_validate_state(cursor)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (tlv_tag(cursor) == TLV_TAG_END) {\n+\t\trc = EINVAL;\n+\t\tgoto fail2;\n+\t}\n+\tif (tlv_tag(cursor) != tag) {\n+\t\trc = EINVAL;\n+\t\tgoto fail3;\n+\t}\n+\n+\told_ndwords = TLV_DWORD_COUNT(tlv_length(cursor));\n+\tnew_ndwords = TLV_DWORD_COUNT(size);\n+\n+\tif ((rc = tlv_require_end(cursor)) != 0)\n+\t\tgoto fail4;\n+\n+\tlast_segment_end = tlv_last_segment_end(cursor);\n+\n+\tif (new_ndwords > old_ndwords) {\n+\t\t/* Expand space used for TLV item */\n+\t\tdelta = new_ndwords - old_ndwords;\n+\t\tpos = cursor->current + old_ndwords;\n+\n+\t\tif (last_segment_end + 1 + delta > cursor->limit) {\n+\t\t\trc = ENOSPC;\n+\t\t\tgoto fail5;\n+\t\t}\n+\n+\t\t/* Move up: new space at (cursor->current + old_ndwords) */\n+\t\tmemmove(pos + delta, pos,\n+\t\t    (last_segment_end + 1 - pos) * sizeof (uint32_t));\n+\n+\t\t/* Adjust the end pointer */\n+\t\tcursor->end += delta;\n+\n+\t} else if (new_ndwords < old_ndwords) {\n+\t\t/* Shrink space used for TLV item */\n+\t\tdelta = old_ndwords - new_ndwords;\n+\t\tpos = cursor->current + new_ndwords;\n+\n+\t\t/* Move down: remove words at (cursor->current + new_ndwords) */\n+\t\tmemmove(pos, pos + delta,\n+\t\t    (last_segment_end + 1 - pos) * sizeof (uint32_t));\n+\n+\t\t/* Zero the new space at the end of the TLV chain */\n+\t\tmemset(last_segment_end + 1 - delta, 0,\n+\t\t    delta * sizeof (uint32_t));\n+\n+\t\t/* Adjust the end pointer */\n+\t\tcursor->end -= delta;\n+\t}\n+\n+\t/* Write new data */\n+\ttlv_write(cursor, tag, data, size);\n+\n+\treturn (0);\n+\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static uint32_t checksum_tlv_partition(\n+\t__in\tnvram_partition_t *partition)\n+{\n+\ttlv_cursor_t *cursor;\n+\tuint32_t *ptr;\n+\tuint32_t *end;\n+\tuint32_t csum;\n+\tsize_t len;\n+\n+\tcursor = &partition->tlv_cursor;\n+\tlen = tlv_block_length_used(cursor);\n+\tEFSYS_ASSERT3U((len & 3), ==, 0);\n+\n+\tcsum = 0;\n+\tptr = partition->data;\n+\tend = &ptr[len >> 2];\n+\n+\twhile (ptr < end)\n+\t\tcsum += __LE_TO_CPU_32(*ptr++);\n+\n+\treturn (csum);\n+}\n+\n+static\t__checkReturn\t\tefx_rc_t\n+tlv_update_partition_len_and_cks(\n+\t__in\ttlv_cursor_t *cursor)\n+{\n+\tefx_rc_t rc;\n+\tnvram_partition_t partition;\n+\tstruct tlv_partition_header *header;\n+\tstruct tlv_partition_trailer *trailer;\n+\tsize_t new_len;\n+\n+\t/*\n+\t * We just modified the partition, so the total length may not be\n+\t * valid. Don't use tlv_find(), which performs some sanity checks\n+\t * that may fail here.\n+\t */\n+\tpartition.data = cursor->block;\n+\tmemcpy(&partition.tlv_cursor, cursor, sizeof (*cursor));\n+\theader = (struct tlv_partition_header *)partition.data;\n+\t/* Sanity check. */\n+\tif (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) {\n+\t\trc = EFAULT;\n+\t\tgoto fail1;\n+\t}\n+\tnew_len =  tlv_block_length_used(&partition.tlv_cursor);\n+\tif (new_len == 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail2;\n+\t}\n+\theader->total_length = __CPU_TO_LE_32(new_len);\n+\t/* Ensure the modified partition always has a new generation count. */\n+\theader->generation = __CPU_TO_LE_32(\n+\t    __LE_TO_CPU_32(header->generation) + 1);\n+\n+\ttrailer = (struct tlv_partition_trailer *)((uint8_t *)header +\n+\t    new_len - sizeof (*trailer) - sizeof (uint32_t));\n+\ttrailer->generation = header->generation;\n+\ttrailer->checksum = __CPU_TO_LE_32(\n+\t    __LE_TO_CPU_32(trailer->checksum) -\n+\t    checksum_tlv_partition(&partition));\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/* Validate buffer contents (before writing to flash) */\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_validate(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in_bcount(partn_size)\tcaddr_t partn_data,\n+\t__in\t\t\tsize_t partn_size)\n+{\n+\ttlv_cursor_t cursor;\n+\tstruct tlv_partition_header *header;\n+\tstruct tlv_partition_trailer *trailer;\n+\tsize_t total_length;\n+\tuint32_t cksum;\n+\tint pos;\n+\tefx_rc_t rc;\n+\n+\tEFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);\n+\n+\tif ((partn_data == NULL) || (partn_size == 0)) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\n+\t/* The partition header must be the first item (at offset zero) */\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data,\n+\t\t    partn_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail2;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {\n+\t\trc = EINVAL;\n+\t\tgoto fail3;\n+\t}\n+\theader = (struct tlv_partition_header *)tlv_item(&cursor);\n+\n+\t/* Check TLV partition length (includes the END tag) */\n+\ttotal_length = __LE_TO_CPU_32(header->total_length);\n+\tif (total_length > partn_size) {\n+\t\trc = EFBIG;\n+\t\tgoto fail4;\n+\t}\n+\n+\t/* Check partition ends with PARTITION_TRAILER and END tags */\n+\tif ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail5;\n+\t}\n+\ttrailer = (struct tlv_partition_trailer *)tlv_item(&cursor);\n+\n+\tif ((rc = tlv_advance(&cursor)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail6;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_END) {\n+\t\trc = EINVAL;\n+\t\tgoto fail7;\n+\t}\n+\n+\t/* Check generation counts are consistent */\n+\tif (trailer->generation != header->generation) {\n+\t\trc = EINVAL;\n+\t\tgoto fail8;\n+\t}\n+\n+\t/* Verify partition checksum */\n+\tcksum = 0;\n+\tfor (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {\n+\t\tcksum += *((uint32_t *)(partn_data + pos));\n+\t}\n+\tif (cksum != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail9;\n+\t}\n+\n+\treturn (0);\n+\n+fail9:\n+\tEFSYS_PROBE(fail9);\n+fail8:\n+\tEFSYS_PROBE(fail8);\n+fail7:\n+\tEFSYS_PROBE(fail7);\n+fail6:\n+\tEFSYS_PROBE(fail6);\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_create(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint16_t partn_type,\n+\t__in_bcount(partn_size)\tcaddr_t partn_data,\n+\t__in\t\t\tsize_t partn_size)\n+{\n+\tuint32_t *buf = (uint32_t *)partn_data;\n+\tefx_rc_t rc;\n+\ttlv_cursor_t cursor;\n+\tstruct tlv_partition_header header;\n+\tstruct tlv_partition_trailer trailer;\n+\n+\tunsigned int min_buf_size = sizeof (struct tlv_partition_header) +\n+\t    sizeof (struct tlv_partition_trailer);\n+\tif (partn_size < min_buf_size) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\n+\tmemset(buf, 0xff, partn_size);\n+\n+\ttlv_init_block(buf);\n+\tif ((rc = tlv_init_cursor(&cursor, buf,\n+\t    (uint32_t *)((uint8_t *)buf + partn_size),\n+\t    buf)) != 0) {\n+\t\tgoto fail2;\n+\t}\n+\n+\theader.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER);\n+\theader.length = __CPU_TO_LE_32(sizeof (header) - 8);\n+\theader.type_id = __CPU_TO_LE_16(partn_type);\n+\theader.preset = 0;\n+\theader.generation = __CPU_TO_LE_32(1);\n+\theader.total_length = 0;  /* This will be fixed below. */\n+\tif ((rc = tlv_insert(\n+\t    &cursor, TLV_TAG_PARTITION_HEADER,\n+\t    (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0)\n+\t\tgoto fail3;\n+\tif ((rc = tlv_advance(&cursor)) != 0)\n+\t\tgoto fail4;\n+\n+\ttrailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER);\n+\ttrailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8);\n+\ttrailer.generation = header.generation;\n+\ttrailer.checksum = 0;  /* This will be fixed below. */\n+\tif ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER,\n+\t    (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0)\n+\t\tgoto fail5;\n+\n+\tif ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)\n+\t\tgoto fail6;\n+\n+\t/* Check that the partition is valid. */\n+\tif ((rc = ef10_nvram_buffer_validate(enp, partn_type,\n+\t    partn_data, partn_size)) != 0)\n+\t\tgoto fail7;\n+\n+\treturn (0);\n+\n+fail7:\n+\tEFSYS_PROBE(fail7);\n+fail6:\n+\tEFSYS_PROBE(fail6);\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+static\t\t\tuint32_t\n+byte_offset(\n+\t__in\t\tuint32_t *position,\n+\t__in\t\tuint32_t *base)\n+{\n+\treturn (uint32_t)((uint8_t *)position - (uint8_t *)base);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_find_item_start(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__out\t\t\tuint32_t *startp)\n+{\n+\t/* Read past partition header to find start address of the first key */\n+\ttlv_cursor_t cursor;\n+\tefx_rc_t rc;\n+\n+\t/* A PARTITION_HEADER tag must be the first item (at offset zero) */\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,\n+\t\t\tbuffer_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail1;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {\n+\t\trc = EINVAL;\n+\t\tgoto fail2;\n+\t}\n+\n+\tif ((rc = tlv_advance(&cursor)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail3;\n+\t}\n+\t*startp = byte_offset(cursor.current, cursor.block);\n+\n+\tif ((rc = tlv_require_end(&cursor)) != 0)\n+\t\tgoto fail4;\n+\n+\treturn (0);\n+\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_find_end(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__out\t\t\tuint32_t *endp)\n+{\n+\t/* Read to end of partition */\n+\ttlv_cursor_t cursor;\n+\tefx_rc_t rc;\n+\tuint32_t *segment_used;\n+\n+\t_NOTE(ARGUNUSED(offset))\n+\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,\n+\t\t\tbuffer_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail1;\n+\t}\n+\n+\tsegment_used = cursor.block;\n+\n+\t/*\n+\t * Go through each segment and check that it has an end tag. If there\n+\t * is no end tag then the previous segment was the last valid one,\n+\t * so return the used space including that end tag.\n+\t */\n+\twhile (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {\n+\t\tif (tlv_require_end(&cursor) != 0) {\n+\t\t\tif (segment_used == cursor.block) {\n+\t\t\t\t/*\n+\t\t\t\t * First segment is corrupt, so there is\n+\t\t\t\t * no valid data in partition.\n+\t\t\t\t */\n+\t\t\t\trc = EINVAL;\n+\t\t\t\tgoto fail2;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tsegment_used = cursor.end + 1;\n+\n+\t\tcursor.current = segment_used;\n+\t}\n+\t/* Return space used (including the END tag) */\n+\t*endp = (segment_used - cursor.block) * sizeof (uint32_t);\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t__success(return != B_FALSE)\tboolean_t\n+ef10_nvram_buffer_find_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__out\t\t\tuint32_t *startp,\n+\t__out\t\t\tuint32_t *lengthp)\n+{\n+\t/* Find TLV at offset and return key start and length */\n+\ttlv_cursor_t cursor;\n+\tuint8_t *key;\n+\tuint32_t tag;\n+\n+\tif (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,\n+\t\t\tbuffer_size, offset) != 0) {\n+\t\treturn (B_FALSE);\n+\t}\n+\n+\twhile ((key = tlv_item(&cursor)) != NULL) {\n+\t\ttag = tlv_tag(&cursor);\n+\t\tif (tag == TLV_TAG_PARTITION_HEADER ||\n+\t\t    tag == TLV_TAG_PARTITION_TRAILER) {\n+\t\t\tif (tlv_advance(&cursor) != 0) {\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\t*startp = byte_offset(cursor.current, cursor.block);\n+\t\t*lengthp = byte_offset(tlv_next_item_ptr(&cursor),\n+\t\t    cursor.current);\n+\t\treturn (B_TRUE);\n+\t}\n+\n+\treturn (B_FALSE);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_get_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__in\t\t\tuint32_t length,\n+\t__out_bcount_part(item_max_size, *lengthp)\n+\t\t\t\tcaddr_t itemp,\n+\t__in\t\t\tsize_t item_max_size,\n+\t__out\t\t\tuint32_t *lengthp)\n+{\n+\tefx_rc_t rc;\n+\ttlv_cursor_t cursor;\n+\tuint32_t item_length;\n+\n+\tif (item_max_size < length) {\n+\t\trc = ENOSPC;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,\n+\t\t\tbuffer_size, offset)) != 0) {\n+\t\tgoto fail2;\n+\t}\n+\n+\titem_length = tlv_length(&cursor);\n+\tif (length < item_length) {\n+\t\trc = ENOSPC;\n+\t\tgoto fail3;\n+\t}\n+\tmemcpy(itemp, tlv_value(&cursor), item_length);\n+\n+\t*lengthp = item_length;\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_insert_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__in_bcount(length)\tcaddr_t keyp,\n+\t__in\t\t\tuint32_t length,\n+\t__out\t\t\tuint32_t *lengthp)\n+{\n+\tefx_rc_t rc;\n+\ttlv_cursor_t cursor;\n+\n+\tif ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,\n+\t\t\tbuffer_size, offset)) != 0) {\n+\t\tgoto fail1;\n+\t}\n+\n+\trc = tlv_insert(&cursor, TLV_TAG_LICENSE, (uint8_t *)keyp, length);\n+\n+\tif (rc != 0) {\n+\t\tgoto fail2;\n+\t}\n+\n+\t*lengthp = byte_offset(tlv_next_item_ptr(&cursor),\n+\t\t    cursor.current);\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_delete_item(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size,\n+\t__in\t\t\tuint32_t offset,\n+\t__in\t\t\tuint32_t length,\n+\t__in\t\t\tuint32_t end)\n+{\n+\tefx_rc_t rc;\n+\ttlv_cursor_t cursor;\n+\n+\t_NOTE(ARGUNUSED(length, end))\n+\n+\tif ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,\n+\t\t\tbuffer_size, offset)) != 0) {\n+\t\tgoto fail1;\n+\t}\n+\n+\tif ((rc = tlv_delete(&cursor)) != 0)\n+\t\tgoto fail2;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buffer_finish(\n+\t__in_bcount(buffer_size)\n+\t\t\t\tcaddr_t bufferp,\n+\t__in\t\t\tsize_t buffer_size)\n+{\n+\tefx_rc_t rc;\n+\ttlv_cursor_t cursor;\n+\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,\n+\t\t\tbuffer_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif ((rc = tlv_require_end(&cursor)) != 0)\n+\t\tgoto fail2;\n+\n+\tif ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)\n+\t\tgoto fail3;\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\n+\n+/*\n+ * Read and validate a segment from a partition. A segment is a complete\n+ * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may\n+ * be multiple segments in a partition, so seg_offset allows segments\n+ * beyond the first to be read.\n+ */\n+static\t__checkReturn\t\t\tefx_rc_t\n+ef10_nvram_read_tlv_segment(\n+\t__in\t\t\t\tefx_nic_t *enp,\n+\t__in\t\t\t\tuint32_t partn,\n+\t__in\t\t\t\tsize_t seg_offset,\n+\t__in_bcount(max_seg_size)\tcaddr_t seg_data,\n+\t__in\t\t\t\tsize_t max_seg_size)\n+{\n+\ttlv_cursor_t cursor;\n+\tstruct tlv_partition_header *header;\n+\tstruct tlv_partition_trailer *trailer;\n+\tsize_t total_length;\n+\tuint32_t cksum;\n+\tint pos;\n+\tefx_rc_t rc;\n+\n+\tEFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);\n+\n+\tif ((seg_data == NULL) || (max_seg_size == 0)) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\n+\t/* Read initial chunk of the segment, starting at offset */\n+\tif ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data,\n+\t\t    EF10_NVRAM_CHUNK,\n+\t\t    MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) {\n+\t\tgoto fail2;\n+\t}\n+\n+\t/* A PARTITION_HEADER tag must be the first item at the given offset */\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,\n+\t\t    max_seg_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail3;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {\n+\t\trc = EINVAL;\n+\t\tgoto fail4;\n+\t}\n+\theader = (struct tlv_partition_header *)tlv_item(&cursor);\n+\n+\t/* Check TLV segment length (includes the END tag) */\n+\ttotal_length = __LE_TO_CPU_32(header->total_length);\n+\tif (total_length > max_seg_size) {\n+\t\trc = EFBIG;\n+\t\tgoto fail5;\n+\t}\n+\n+\t/* Read the remaining segment content */\n+\tif (total_length > EF10_NVRAM_CHUNK) {\n+\t\tif ((rc = ef10_nvram_partn_read_mode(enp, partn,\n+\t\t\t    seg_offset + EF10_NVRAM_CHUNK,\n+\t\t\t    seg_data + EF10_NVRAM_CHUNK,\n+\t\t\t    total_length - EF10_NVRAM_CHUNK,\n+\t\t\t    MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0)\n+\t\t\tgoto fail6;\n+\t}\n+\n+\t/* Check segment ends with PARTITION_TRAILER and END tags */\n+\tif ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail7;\n+\t}\n+\ttrailer = (struct tlv_partition_trailer *)tlv_item(&cursor);\n+\n+\tif ((rc = tlv_advance(&cursor)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail8;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_END) {\n+\t\trc = EINVAL;\n+\t\tgoto fail9;\n+\t}\n+\n+\t/* Check data read from segment is consistent */\n+\tif (trailer->generation != header->generation) {\n+\t\t/*\n+\t\t * The partition data may have been modified between successive\n+\t\t * MCDI NVRAM_READ requests by the MC or another PCI function.\n+\t\t *\n+\t\t * The caller must retry to obtain consistent partition data.\n+\t\t */\n+\t\trc = EAGAIN;\n+\t\tgoto fail10;\n+\t}\n+\n+\t/* Verify segment checksum */\n+\tcksum = 0;\n+\tfor (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {\n+\t\tcksum += *((uint32_t *)(seg_data + pos));\n+\t}\n+\tif (cksum != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail11;\n+\t}\n+\n+\treturn (0);\n+\n+fail11:\n+\tEFSYS_PROBE(fail11);\n+fail10:\n+\tEFSYS_PROBE(fail10);\n+fail9:\n+\tEFSYS_PROBE(fail9);\n+fail8:\n+\tEFSYS_PROBE(fail8);\n+fail7:\n+\tEFSYS_PROBE(fail7);\n+fail6:\n+\tEFSYS_PROBE(fail6);\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/*\n+ * Read a single TLV item from a host memory\n+ * buffer containing a TLV formatted segment.\n+ */\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_buf_read_tlv(\n+\t__in\t\t\t\tefx_nic_t *enp,\n+\t__in_bcount(max_seg_size)\tcaddr_t seg_data,\n+\t__in\t\t\t\tsize_t max_seg_size,\n+\t__in\t\t\t\tuint32_t tag,\n+\t__deref_out_bcount_opt(*sizep)\tcaddr_t *datap,\n+\t__out\t\t\t\tsize_t *sizep)\n+{\n+\ttlv_cursor_t cursor;\n+\tcaddr_t data;\n+\tsize_t length;\n+\tcaddr_t value;\n+\tefx_rc_t rc;\n+\n+\tif ((seg_data == NULL) || (max_seg_size == 0)) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\n+\t/* Find requested TLV tag in segment data */\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,\n+\t\t    max_seg_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail2;\n+\t}\n+\tif ((rc = tlv_find(&cursor, tag)) != 0) {\n+\t\trc = ENOENT;\n+\t\tgoto fail3;\n+\t}\n+\tvalue = (caddr_t)tlv_value(&cursor);\n+\tlength = tlv_length(&cursor);\n+\n+\tif (length == 0)\n+\t\tdata = NULL;\n+\telse {\n+\t\t/* Copy out data from TLV item */\n+\t\tEFSYS_KMEM_ALLOC(enp->en_esip, length, data);\n+\t\tif (data == NULL) {\n+\t\t\trc = ENOMEM;\n+\t\t\tgoto fail4;\n+\t\t}\n+\t\tmemcpy(data, value, length);\n+\t}\n+\n+\t*datap = data;\n+\t*sizep = length;\n+\n+\treturn (0);\n+\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/* Read a single TLV item from the first segment in a TLV formatted partition */\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_read_tlv(\n+\t__in\t\t\t\t\tefx_nic_t *enp,\n+\t__in\t\t\t\t\tuint32_t partn,\n+\t__in\t\t\t\t\tuint32_t tag,\n+\t__deref_out_bcount_opt(*seg_sizep)\tcaddr_t *seg_datap,\n+\t__out\t\t\t\t\tsize_t *seg_sizep)\n+{\n+\tcaddr_t seg_data = NULL;\n+\tsize_t partn_size = 0;\n+\tsize_t length;\n+\tcaddr_t data;\n+\tint retry;\n+\tefx_rc_t rc;\n+\n+\t/* Allocate sufficient memory for the entire partition */\n+\tif ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (partn_size == 0) {\n+\t\trc = ENOENT;\n+\t\tgoto fail2;\n+\t}\n+\n+\tEFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data);\n+\tif (seg_data == NULL) {\n+\t\trc = ENOMEM;\n+\t\tgoto fail3;\n+\t}\n+\n+\t/*\n+\t * Read the first segment in a TLV partition. Retry until consistent\n+\t * segment contents are returned. Inconsistent data may be read if:\n+\t *  a) the segment contents are invalid\n+\t *  b) the MC has rebooted while we were reading the partition\n+\t *  c) the partition has been modified while we were reading it\n+\t * Limit retry attempts to ensure forward progress.\n+\t */\n+\tretry = 10;\n+\tdo {\n+\t\trc = ef10_nvram_read_tlv_segment(enp, partn, 0,\n+\t\t    seg_data, partn_size);\n+\t} while ((rc == EAGAIN) && (--retry > 0));\n+\n+\tif (rc != 0) {\n+\t\t/* Failed to obtain consistent segment data */\n+\t\tgoto fail4;\n+\t}\n+\n+\tif ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size,\n+\t\t    tag, &data, &length)) != 0)\n+\t\tgoto fail5;\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);\n+\n+\t*seg_datap = data;\n+\t*seg_sizep = length;\n+\n+\treturn (0);\n+\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/* Compute the size of a segment. */\n+\tstatic\t__checkReturn\tefx_rc_t\n+ef10_nvram_buf_segment_size(\n+\t__in\t\t\tcaddr_t seg_data,\n+\t__in\t\t\tsize_t max_seg_size,\n+\t__out\t\t\tsize_t *seg_sizep)\n+{\n+\tefx_rc_t rc;\n+\ttlv_cursor_t cursor;\n+\tstruct tlv_partition_header *header;\n+\tuint32_t cksum;\n+\tint pos;\n+\tuint32_t *end_tag_position;\n+\tuint32_t segment_length;\n+\n+\t/* A PARTITION_HEADER tag must be the first item at the given offset */\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,\n+\t\t    max_seg_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail1;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {\n+\t\trc = EINVAL;\n+\t\tgoto fail2;\n+\t}\n+\theader = (struct tlv_partition_header *)tlv_item(&cursor);\n+\n+\t/* Check TLV segment length (includes the END tag) */\n+\t*seg_sizep = __LE_TO_CPU_32(header->total_length);\n+\tif (*seg_sizep > max_seg_size) {\n+\t\trc = EFBIG;\n+\t\tgoto fail3;\n+\t}\n+\n+\t/* Check segment ends with PARTITION_TRAILER and END tags */\n+\tif ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail4;\n+\t}\n+\n+\tif ((rc = tlv_advance(&cursor)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail5;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_END) {\n+\t\trc = EINVAL;\n+\t\tgoto fail6;\n+\t}\n+\tend_tag_position = cursor.current;\n+\n+\t/* Verify segment checksum */\n+\tcksum = 0;\n+\tfor (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) {\n+\t\tcksum += *((uint32_t *)(seg_data + pos));\n+\t}\n+\tif (cksum != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail7;\n+\t}\n+\n+\t/*\n+\t * Calculate total length from HEADER to END tags and compare to\n+\t * max_seg_size and the total_length field in the HEADER tag.\n+\t */\n+\tsegment_length = tlv_block_length_used(&cursor);\n+\n+\tif (segment_length > max_seg_size) {\n+\t\trc = EINVAL;\n+\t\tgoto fail8;\n+\t}\n+\n+\tif (segment_length != *seg_sizep) {\n+\t\trc = EINVAL;\n+\t\tgoto fail9;\n+\t}\n+\n+\t/* Skip over the first HEADER tag. */\n+\trc = tlv_rewind(&cursor);\n+\trc = tlv_advance(&cursor);\n+\n+\twhile (rc == 0) {\n+\t\tif (tlv_tag(&cursor) == TLV_TAG_END) {\n+\t\t\t/* Check that the END tag is the one found earlier. */\n+\t\t\tif (cursor.current != end_tag_position)\n+\t\t\t\tgoto fail10;\n+\t\t\tbreak;\n+\t\t}\n+\t\t/* Check for duplicate HEADER tags before the END tag. */\n+\t\tif (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {\n+\t\t\trc = EINVAL;\n+\t\t\tgoto fail11;\n+\t\t}\n+\n+\t\trc = tlv_advance(&cursor);\n+\t}\n+\tif (rc != 0)\n+\t\tgoto fail12;\n+\n+\treturn (0);\n+\n+fail12:\n+\tEFSYS_PROBE(fail12);\n+fail11:\n+\tEFSYS_PROBE(fail11);\n+fail10:\n+\tEFSYS_PROBE(fail10);\n+fail9:\n+\tEFSYS_PROBE(fail9);\n+fail8:\n+\tEFSYS_PROBE(fail8);\n+fail7:\n+\tEFSYS_PROBE(fail7);\n+fail6:\n+\tEFSYS_PROBE(fail6);\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/*\n+ * Add or update a single TLV item in a host memory buffer containing a TLV\n+ * formatted segment. Historically partitions consisted of only one segment.\n+ */\n+\t__checkReturn\t\t\tefx_rc_t\n+ef10_nvram_buf_write_tlv(\n+\t__inout_bcount(max_seg_size)\tcaddr_t seg_data,\n+\t__in\t\t\t\tsize_t max_seg_size,\n+\t__in\t\t\t\tuint32_t tag,\n+\t__in_bcount(tag_size)\t\tcaddr_t tag_data,\n+\t__in\t\t\t\tsize_t tag_size,\n+\t__out\t\t\t\tsize_t *total_lengthp)\n+{\n+\ttlv_cursor_t cursor;\n+\tstruct tlv_partition_header *header;\n+\tstruct tlv_partition_trailer *trailer;\n+\tuint32_t generation;\n+\tuint32_t cksum;\n+\tint pos;\n+\tefx_rc_t rc;\n+\n+\t/* A PARTITION_HEADER tag must be the first item (at offset zero) */\n+\tif ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,\n+\t\t\tmax_seg_size)) != 0) {\n+\t\trc = EFAULT;\n+\t\tgoto fail1;\n+\t}\n+\tif (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {\n+\t\trc = EINVAL;\n+\t\tgoto fail2;\n+\t}\n+\theader = (struct tlv_partition_header *)tlv_item(&cursor);\n+\n+\t/* Update the TLV chain to contain the new data */\n+\tif ((rc = tlv_find(&cursor, tag)) == 0) {\n+\t\t/* Modify existing TLV item */\n+\t\tif ((rc = tlv_modify(&cursor, tag,\n+\t\t\t    (uint8_t *)tag_data, tag_size)) != 0)\n+\t\t\tgoto fail3;\n+\t} else {\n+\t\t/* Insert a new TLV item before the PARTITION_TRAILER */\n+\t\trc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER);\n+\t\tif (rc != 0) {\n+\t\t\trc = EINVAL;\n+\t\t\tgoto fail4;\n+\t\t}\n+\t\tif ((rc = tlv_insert(&cursor, tag,\n+\t\t\t    (uint8_t *)tag_data, tag_size)) != 0) {\n+\t\t\trc = EINVAL;\n+\t\t\tgoto fail5;\n+\t\t}\n+\t}\n+\n+\t/* Find the trailer tag */\n+\tif ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail6;\n+\t}\n+\ttrailer = (struct tlv_partition_trailer *)tlv_item(&cursor);\n+\n+\t/* Update PARTITION_HEADER and PARTITION_TRAILER fields */\n+\t*total_lengthp = tlv_block_length_used(&cursor);\n+\tif (*total_lengthp > max_seg_size) {\n+\t\trc = ENOSPC;\n+\t\tgoto fail7;\n+\t}\n+\tgeneration = __LE_TO_CPU_32(header->generation) + 1;\n+\n+\theader->total_length\t= __CPU_TO_LE_32(*total_lengthp);\n+\theader->generation\t= __CPU_TO_LE_32(generation);\n+\ttrailer->generation\t= __CPU_TO_LE_32(generation);\n+\n+\t/* Recompute PARTITION_TRAILER checksum */\n+\ttrailer->checksum = 0;\n+\tcksum = 0;\n+\tfor (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) {\n+\t\tcksum += *((uint32_t *)(seg_data + pos));\n+\t}\n+\ttrailer->checksum = ~cksum + 1;\n+\n+\treturn (0);\n+\n+fail7:\n+\tEFSYS_PROBE(fail7);\n+fail6:\n+\tEFSYS_PROBE(fail6);\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/*\n+ * Add or update a single TLV item in the first segment of a TLV formatted\n+ * dynamic config partition. The first segment is the current active\n+ * configuration.\n+ */\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_write_tlv(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t tag,\n+\t__in_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\treturn ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data,\n+\t    size, B_FALSE);\n+}\n+\n+/*\n+ * Read a segment from nvram at the given offset into a buffer (segment_data)\n+ * and optionally write a new tag to it.\n+ */\n+static\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_segment_write_tlv(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t tag,\n+\t__in_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__inout\t\t\tcaddr_t *seg_datap,\n+\t__inout\t\t\tsize_t *partn_offsetp,\n+\t__inout\t\t\tsize_t *src_remain_lenp,\n+\t__inout\t\t\tsize_t *dest_remain_lenp,\n+\t__in\t\t\tboolean_t write)\n+{\n+\tefx_rc_t rc;\n+\tefx_rc_t status;\n+\tsize_t original_segment_size;\n+\tsize_t modified_segment_size;\n+\n+\t/*\n+\t * Read the segment from NVRAM into the segment_data buffer and validate\n+\t * it, returning if it does not validate. This is not a failure unless\n+\t * this is the first segment in a partition. In this case the caller\n+\t * must propagate the error.\n+\t */\n+\tstatus = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp,\n+\t    *seg_datap, *src_remain_lenp);\n+\tif (status != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\n+\tstatus = ef10_nvram_buf_segment_size(*seg_datap,\n+\t    *src_remain_lenp, &original_segment_size);\n+\tif (status != 0) {\n+\t\trc = EINVAL;\n+\t\tgoto fail2;\n+\t}\n+\n+\tif (write) {\n+\t\t/* Update the contents of the segment in the buffer */\n+\t\tif ((rc = ef10_nvram_buf_write_tlv(*seg_datap,\n+\t\t\t*dest_remain_lenp, tag, data, size,\n+\t\t\t&modified_segment_size)) != 0) {\n+\t\t\tgoto fail3;\n+\t\t}\n+\t\t*dest_remain_lenp -= modified_segment_size;\n+\t\t*seg_datap += modified_segment_size;\n+\t} else {\n+\t\t/*\n+\t\t * We won't modify this segment, but still need to update the\n+\t\t * remaining lengths and pointers.\n+\t\t */\n+\t\t*dest_remain_lenp -= original_segment_size;\n+\t\t*seg_datap += original_segment_size;\n+\t}\n+\n+\t*partn_offsetp += original_segment_size;\n+\t*src_remain_lenp -= original_segment_size;\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/*\n+ * Add or update a single TLV item in either the first segment or in all\n+ * segments in a TLV formatted dynamic config partition. Dynamic config\n+ * partitions on boards that support RFID are divided into a number of segments,\n+ * each formatted like a partition, with header, trailer and end tags. The first\n+ * segment is the current active configuration.\n+ *\n+ * The segments are initialised by manftest and each contain a different\n+ * configuration e.g. firmware variant. The firmware can be instructed\n+ * via RFID to copy a segment to replace the first segment, hence changing the\n+ * active configuration.  This allows ops to change the configuration of a board\n+ * prior to shipment using RFID.\n+ *\n+ * Changes to the dynamic config may need to be written to all segments (e.g.\n+ * firmware versions) or just the first segment (changes to the active\n+ * configuration). See SF-111324-SW \"The use of RFID in Solarflare Products\".\n+ * If only the first segment is written the code still needs to be aware of the\n+ * possible presence of subsequent segments as writing to a segment may cause\n+ * its size to increase, which would overwrite the subsequent segments and\n+ * invalidate them.\n+ */\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_write_segment_tlv(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t tag,\n+\t__in_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__in\t\t\tboolean_t all_segments)\n+{\n+\tsize_t partn_size = 0;\n+\tcaddr_t partn_data;\n+\tsize_t total_length = 0;\n+\tefx_rc_t rc;\n+\tsize_t current_offset = 0;\n+\tsize_t remaining_original_length;\n+\tsize_t remaining_modified_length;\n+\tcaddr_t segment_data;\n+\n+\tEFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG);\n+\n+\t/* Allocate sufficient memory for the entire partition */\n+\tif ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)\n+\t\tgoto fail1;\n+\n+\tEFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data);\n+\tif (partn_data == NULL) {\n+\t\trc = ENOMEM;\n+\t\tgoto fail2;\n+\t}\n+\n+\tremaining_original_length = partn_size;\n+\tremaining_modified_length = partn_size;\n+\tsegment_data = partn_data;\n+\n+\t/* Lock the partition */\n+\tif ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)\n+\t\tgoto fail3;\n+\n+\t/* Iterate over each (potential) segment to update it. */\n+\tdo {\n+\t\tboolean_t write = all_segments || current_offset == 0;\n+\n+\t\trc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size,\n+\t\t    &segment_data, &current_offset, &remaining_original_length,\n+\t\t    &remaining_modified_length, write);\n+\t\tif (rc != 0) {\n+\t\t\tif (current_offset == 0) {\n+\t\t\t\t/*\n+\t\t\t\t * If no data has been read then the first\n+\t\t\t\t * segment is invalid, which is an error.\n+\t\t\t\t */\n+\t\t\t\tgoto fail4;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t} while (current_offset < partn_size);\n+\n+\ttotal_length = segment_data - partn_data;\n+\n+\t/*\n+\t * We've run out of space.  This should actually be dealt with by\n+\t * ef10_nvram_buf_write_tlv returning ENOSPC.\n+\t */\n+\tif (total_length > partn_size) {\n+\t\trc = ENOSPC;\n+\t\tgoto fail5;\n+\t}\n+\n+\t/* Erase the whole partition in NVRAM */\n+\tif ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0)\n+\t\tgoto fail6;\n+\n+\t/* Write new partition contents from the buffer to NVRAM */\n+\tif ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data,\n+\t\t    total_length)) != 0)\n+\t\tgoto fail7;\n+\n+\t/* Unlock the partition */\n+\tef10_nvram_partn_unlock(enp, partn, NULL);\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);\n+\n+\treturn (0);\n+\n+fail7:\n+\tEFSYS_PROBE(fail7);\n+fail6:\n+\tEFSYS_PROBE(fail6);\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+\n+\tef10_nvram_partn_unlock(enp, partn, NULL);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/*\n+ * Get the size of a NVRAM partition. This is the total size allocated in nvram,\n+ * not the data used by the segments in the partition.\n+ */\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_size(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *sizep)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = efx_mcdi_nvram_info(enp, partn, sizep,\n+\t    NULL, NULL, NULL)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_lock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_read_mode(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__in\t\t\tuint32_t mode)\n+{\n+\tsize_t chunk;\n+\tefx_rc_t rc;\n+\n+\twhile (size > 0) {\n+\t\tchunk = MIN(size, EF10_NVRAM_CHUNK);\n+\n+\t\tif ((rc = efx_mcdi_nvram_read(enp, partn, offset,\n+\t\t\t    data, chunk, mode)) != 0) {\n+\t\t\tgoto fail1;\n+\t\t}\n+\n+\t\tsize -= chunk;\n+\t\tdata += chunk;\n+\t\toffset += chunk;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_read(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\t/*\n+\t * Read requests which come in through the EFX API expect to\n+\t * read the current, active partition.\n+\t */\n+\treturn ef10_nvram_partn_read_mode(enp, partn, offset, data, size,\n+\t\t\t    MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__in\t\t\tsize_t size)\n+{\n+\tefx_rc_t rc;\n+\tuint32_t erase_size;\n+\n+\tif ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL,\n+\t    &erase_size, NULL)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (erase_size == 0) {\n+\t\tif ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0)\n+\t\t\tgoto fail2;\n+\t} else {\n+\t\tif (size % erase_size != 0) {\n+\t\t\trc = EINVAL;\n+\t\t\tgoto fail3;\n+\t\t}\n+\t\twhile (size > 0) {\n+\t\t\tif ((rc = efx_mcdi_nvram_erase(enp, partn, offset,\n+\t\t\t    erase_size)) != 0)\n+\t\t\t\tgoto fail4;\n+\t\t\toffset += erase_size;\n+\t\t\tsize -= erase_size;\n+\t\t}\n+\t}\n+\n+\treturn (0);\n+\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_write(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\tsize_t chunk;\n+\tuint32_t write_size;\n+\tefx_rc_t rc;\n+\n+\tif ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL,\n+\t    NULL, &write_size)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (write_size != 0) {\n+\t\t/*\n+\t\t * Check that the size is a multiple of the write chunk size if\n+\t\t * the write chunk size is available.\n+\t\t */\n+\t\tif (size % write_size != 0) {\n+\t\t\trc = EINVAL;\n+\t\t\tgoto fail2;\n+\t\t}\n+\t} else {\n+\t\twrite_size = EF10_NVRAM_CHUNK;\n+\t}\n+\n+\twhile (size > 0) {\n+\t\tchunk = MIN(size, write_size);\n+\n+\t\tif ((rc = efx_mcdi_nvram_write(enp, partn, offset,\n+\t\t\t    data, chunk)) != 0) {\n+\t\t\tgoto fail3;\n+\t\t}\n+\n+\t\tsize -= chunk;\n+\t\tdata += chunk;\n+\t\toffset += chunk;\n+\t}\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_unlock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out_opt\t\tuint32_t *resultp)\n+{\n+\tboolean_t reboot = B_FALSE;\n+\tefx_rc_t rc;\n+\n+\tif (resultp != NULL)\n+\t\t*resultp = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;\n+\n+\trc = efx_mcdi_nvram_update_finish(enp, partn, reboot, resultp);\n+\tif (rc != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_set_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in_ecount(4)\t\tuint16_t version[4])\n+{\n+\tstruct tlv_partition_version partn_version;\n+\tsize_t size;\n+\tefx_rc_t rc;\n+\n+\t/* Add or modify partition version TLV item */\n+\tpartn_version.version_w = __CPU_TO_LE_16(version[0]);\n+\tpartn_version.version_x = __CPU_TO_LE_16(version[1]);\n+\tpartn_version.version_y = __CPU_TO_LE_16(version[2]);\n+\tpartn_version.version_z = __CPU_TO_LE_16(version[3]);\n+\n+\tsize = sizeof (partn_version) - (2 * sizeof (uint32_t));\n+\n+\t/* Write the version number to all segments in the partition */\n+\tif ((rc = ef10_nvram_partn_write_segment_tlv(enp,\n+\t\t    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\n+\t\t    TLV_TAG_PARTITION_VERSION(partn),\n+\t\t    (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */\n+\n+#if EFSYS_OPT_NVRAM\n+\n+typedef struct ef10_parttbl_entry_s {\n+\tunsigned int\t\tpartn;\n+\tunsigned int\t\tport;\n+\tefx_nvram_type_t\tnvtype;\n+} ef10_parttbl_entry_t;\n+\n+/* Translate EFX NVRAM types to firmware partition types */\n+static ef10_parttbl_entry_t hunt_parttbl[] = {\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   1, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   2, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   3, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   4, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  1, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  2, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  3, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  4, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   1, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   2, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   3, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   4, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   1, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   2, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   3, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   4, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   1, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   2, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   3, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   4, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   1, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   2, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   3, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   4, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   1, EFX_NVRAM_LICENSE},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   2, EFX_NVRAM_LICENSE},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   3, EFX_NVRAM_LICENSE},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   4, EFX_NVRAM_LICENSE}\n+};\n+\n+static ef10_parttbl_entry_t medford_parttbl[] = {\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   1, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   2, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   3, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE,\t   4, EFX_NVRAM_MC_FIRMWARE},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  1, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  2, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  3, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  4, EFX_NVRAM_MC_GOLDEN},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   1, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   2, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   3, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_ROM,\t   4, EFX_NVRAM_BOOTROM},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 2, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 3, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 4, EFX_NVRAM_BOOTROM_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   1, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   2, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   3, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,\t   4, EFX_NVRAM_DYNAMIC_CFG},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   1, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   2, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   3, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA,\t\t   4, EFX_NVRAM_FPGA},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   1, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   2, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   3, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_FPGA_BACKUP,\t   4, EFX_NVRAM_FPGA_BACKUP},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   1, EFX_NVRAM_LICENSE},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   2, EFX_NVRAM_LICENSE},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   3, EFX_NVRAM_LICENSE},\n+\t{NVRAM_PARTITION_TYPE_LICENSE,\t\t   4, EFX_NVRAM_LICENSE},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_UEFI,\t   1, EFX_NVRAM_UEFIROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_UEFI,\t   2, EFX_NVRAM_UEFIROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_UEFI,\t   3, EFX_NVRAM_UEFIROM},\n+\t{NVRAM_PARTITION_TYPE_EXPANSION_UEFI,\t   4, EFX_NVRAM_UEFIROM}\n+};\n+\n+static\t__checkReturn\t\tefx_rc_t\n+ef10_parttbl_get(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__out\t\t\tef10_parttbl_entry_t **parttblp,\n+\t__out\t\t\tsize_t *parttbl_rowsp)\n+{\n+\tswitch (enp->en_family) {\n+\tcase EFX_FAMILY_HUNTINGTON:\n+\t\t*parttblp = hunt_parttbl;\n+\t\t*parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl);\n+\t\tbreak;\n+\n+\tcase EFX_FAMILY_MEDFORD:\n+\t\t*parttblp = medford_parttbl;\n+\t\t*parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tEFSYS_ASSERT(B_FALSE);\n+\t\treturn (EINVAL);\n+\t}\n+\treturn (0);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_type_to_partn(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tuint32_t *partnp)\n+{\n+\tefx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);\n+\tef10_parttbl_entry_t *parttbl = NULL;\n+\tsize_t parttbl_rows = 0;\n+\tunsigned int i;\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\tEFSYS_ASSERT(partnp != NULL);\n+\n+\tif (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {\n+\t\tfor (i = 0; i < parttbl_rows; i++) {\n+\t\t\tef10_parttbl_entry_t *entry = &parttbl[i];\n+\n+\t\t\tif (entry->nvtype == type &&\n+\t\t\t    entry->port == emip->emi_port) {\n+\t\t\t\t*partnp = entry->partn;\n+\t\t\t\treturn (0);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn (ENOTSUP);\n+}\n+\n+#if EFSYS_OPT_DIAG\n+\n+static\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_to_type(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tefx_nvram_type_t *typep)\n+{\n+\tefx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);\n+\tef10_parttbl_entry_t *parttbl = NULL;\n+\tsize_t parttbl_rows = 0;\n+\tunsigned int i;\n+\n+\tEFSYS_ASSERT(typep != NULL);\n+\n+\tif (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {\n+\t\tfor (i = 0; i < parttbl_rows; i++) {\n+\t\t\tef10_parttbl_entry_t *entry = &parttbl[i];\n+\n+\t\t\tif (entry->partn == partn &&\n+\t\t\t    entry->port == emip->emi_port) {\n+\t\t\t\t*typep = entry->nvtype;\n+\t\t\t\treturn (0);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn (ENOTSUP);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp)\n+{\n+\tefx_nvram_type_t type;\n+\tunsigned int npartns = 0;\n+\tuint32_t *partns = NULL;\n+\tsize_t size;\n+\tunsigned int i;\n+\tefx_rc_t rc;\n+\n+\t/* Read available partitions from NVRAM partition map */\n+\tsize = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t);\n+\tEFSYS_KMEM_ALLOC(enp->en_esip, size, partns);\n+\tif (partns == NULL) {\n+\t\trc = ENOMEM;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size,\n+\t\t    &npartns)) != 0) {\n+\t\tgoto fail2;\n+\t}\n+\n+\tfor (i = 0; i < npartns; i++) {\n+\t\t/* Check if the partition is supported for this port */\n+\t\tif ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0)\n+\t\t\tcontinue;\n+\n+\t\tif ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0)\n+\t\t\tgoto fail3;\n+\t}\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, size, partns);\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+\tEFSYS_KMEM_FREE(enp->en_esip, size, partns);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\treturn (rc);\n+}\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_get_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4])\n+{\n+\tefx_rc_t rc;\n+\n+\t/* FIXME: get highest partn version from all ports */\n+\t/* FIXME: return partn description if available */\n+\n+\tif ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep,\n+\t\t    version, NULL, 0)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_rw_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *chunk_sizep)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (chunk_sizep != NULL)\n+\t\t*chunk_sizep = EF10_NVRAM_CHUNK;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+ef10_nvram_partn_rw_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = ef10_nvram_partn_unlock(enp, partn, NULL)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif\t/* EFSYS_OPT_NVRAM */\n+\n+#endif\t/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */\ndiff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h\nindex 85fd6f1..6c81d98 100644\n--- a/drivers/net/sfc/base/efx.h\n+++ b/drivers/net/sfc/base/efx.h\n@@ -1243,6 +1243,102 @@ efx_nic_get_vi_pool(\n \n /* NVRAM */\n \n+#if EFSYS_OPT_NVRAM\n+\n+typedef enum efx_nvram_type_e {\n+\tEFX_NVRAM_INVALID = 0,\n+\tEFX_NVRAM_BOOTROM,\n+\tEFX_NVRAM_BOOTROM_CFG,\n+\tEFX_NVRAM_MC_FIRMWARE,\n+\tEFX_NVRAM_MC_GOLDEN,\n+\tEFX_NVRAM_PHY,\n+\tEFX_NVRAM_NULLPHY,\n+\tEFX_NVRAM_FPGA,\n+\tEFX_NVRAM_FCFW,\n+\tEFX_NVRAM_CPLD,\n+\tEFX_NVRAM_FPGA_BACKUP,\n+\tEFX_NVRAM_DYNAMIC_CFG,\n+\tEFX_NVRAM_LICENSE,\n+\tEFX_NVRAM_UEFIROM,\n+\tEFX_NVRAM_NTYPES,\n+} efx_nvram_type_t;\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_init(\n+\t__in\t\t\tefx_nic_t *enp);\n+\n+#if EFSYS_OPT_DIAG\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp);\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_size(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tsize_t *sizep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_rw_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out_opt\t\tsize_t *pref_chunkp);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_rw_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_get_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4]);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_read_chunk(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_set_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in_ecount(4)\t\tuint16_t version[4]);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_validate(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in_bcount(partn_size)\tcaddr_t partn_data,\n+\t__in\t\t\tsize_t partn_size);\n+\n+extern\t __checkReturn\t\tefx_rc_t\n+efx_nvram_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+efx_nvram_write_chunk(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in\t\t\tunsigned int offset,\n+\t__in_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t\t\t\tvoid\n+efx_nvram_fini(\n+\t__in\t\t\tefx_nic_t *enp);\n+\n+#endif\t/* EFSYS_OPT_NVRAM */\n+\n #if EFSYS_OPT_DIAG\n \n typedef enum efx_pattern_type_t {\ndiff --git a/drivers/net/sfc/base/efx_check.h b/drivers/net/sfc/base/efx_check.h\nindex 5522838..e6ef077 100644\n--- a/drivers/net/sfc/base/efx_check.h\n+++ b/drivers/net/sfc/base/efx_check.h\n@@ -181,6 +181,13 @@\n # endif\n #endif /* EFSYS_OPT_NAMES */\n \n+#if EFSYS_OPT_NVRAM\n+/* Support non volatile configuration */\n+# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD)\n+#  error \"NVRAM requires SIENA or HUNTINGTON or MEDFORD\"\n+# endif\n+#endif /* EFSYS_OPT_NVRAM */\n+\n #ifdef EFSYS_OPT_NVRAM_FALCON_BOOTROM\n # error \"NVRAM_FALCON_BOOTROM is obsolete and is not supported.\"\n #endif\ndiff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h\nindex f563eda..6b84f43 100644\n--- a/drivers/net/sfc/base/efx_impl.h\n+++ b/drivers/net/sfc/base/efx_impl.h\n@@ -452,6 +452,105 @@ typedef struct efx_mcdi_s {\n \n #endif /* EFSYS_OPT_MCDI */\n \n+#if EFSYS_OPT_NVRAM\n+typedef struct efx_nvram_ops_s {\n+#if EFSYS_OPT_DIAG\n+\tefx_rc_t\t(*envo_test)(efx_nic_t *);\n+#endif\t/* EFSYS_OPT_DIAG */\n+\tefx_rc_t\t(*envo_type_to_partn)(efx_nic_t *, efx_nvram_type_t,\n+\t\t\t\t\t    uint32_t *);\n+\tefx_rc_t\t(*envo_partn_size)(efx_nic_t *, uint32_t, size_t *);\n+\tefx_rc_t\t(*envo_partn_rw_start)(efx_nic_t *, uint32_t, size_t *);\n+\tefx_rc_t\t(*envo_partn_read)(efx_nic_t *, uint32_t,\n+\t\t\t\t\t    unsigned int, caddr_t, size_t);\n+\tefx_rc_t\t(*envo_partn_erase)(efx_nic_t *, uint32_t,\n+\t\t\t\t\t    unsigned int, size_t);\n+\tefx_rc_t\t(*envo_partn_write)(efx_nic_t *, uint32_t,\n+\t\t\t\t\t    unsigned int, caddr_t, size_t);\n+\tefx_rc_t\t(*envo_partn_rw_finish)(efx_nic_t *, uint32_t);\n+\tefx_rc_t\t(*envo_partn_get_version)(efx_nic_t *, uint32_t,\n+\t\t\t\t\t    uint32_t *, uint16_t *);\n+\tefx_rc_t\t(*envo_partn_set_version)(efx_nic_t *, uint32_t,\n+\t\t\t\t\t    uint16_t *);\n+\tefx_rc_t\t(*envo_buffer_validate)(efx_nic_t *, uint32_t,\n+\t\t\t\t\t    caddr_t, size_t);\n+} efx_nvram_ops_t;\n+#endif /* EFSYS_OPT_NVRAM */\n+\n+#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_partitions(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__out\t\t\tunsigned int *npartnp);\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_metadata(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4],\n+\t__out_bcount_opt(size)\tchar *descp,\n+\t__in\t\t\tsize_t size);\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_info(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out_opt\t\tsize_t *sizep,\n+\t__out_opt\t\tuint32_t *addressp,\n+\t__out_opt\t\tuint32_t *erase_sizep,\n+\t__out_opt\t\tuint32_t *write_sizep);\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_update_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn);\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_read(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__in\t\t\tuint32_t mode);\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t offset,\n+\t__in\t\t\tsize_t size);\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_write(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_update_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tboolean_t reboot,\n+\t__out_opt\t\tuint32_t *resultp);\n+\n+#if EFSYS_OPT_DIAG\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn);\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */\n+\n typedef struct efx_drv_cfg_s {\n \tuint32_t\t\tedc_min_vi_count;\n \tuint32_t\t\tedc_max_vi_count;\n@@ -488,6 +587,10 @@ struct efx_nic_s {\n #if EFSYS_OPT_MCDI\n \tefx_mcdi_t\t\ten_mcdi;\n #endif\t/* EFSYS_OPT_MCDI */\n+#if EFSYS_OPT_NVRAM\n+\tefx_nvram_type_t\ten_nvram_locked;\n+\tconst efx_nvram_ops_t\t*en_envop;\n+#endif\t/* EFSYS_OPT_NVRAM */\n #if EFSYS_OPT_RX_SCALE\n \tefx_rx_hash_support_t\ten_hash_support;\n \tefx_rx_scale_support_t\ten_rss_support;\n@@ -497,6 +600,9 @@ struct efx_nic_s {\n \tunion {\n #if EFSYS_OPT_SIENA\n \t\tstruct {\n+#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD\n+\t\t\tunsigned int\t\tenu_partn_mask;\n+#endif\t/* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */\n \t\t\tint\t\t\tenu_unused;\n \t\t} siena;\n #endif\t/* EFSYS_OPT_SIENA */\ndiff --git a/drivers/net/sfc/base/efx_nvram.c b/drivers/net/sfc/base/efx_nvram.c\nnew file mode 100644\nindex 0000000..6ee2a71\n--- /dev/null\n+++ b/drivers/net/sfc/base/efx_nvram.c\n@@ -0,0 +1,1044 @@\n+/*\n+ * Copyright (c) 2009-2016 Solarflare Communications Inc.\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ *\n+ * 1. Redistributions of source code must retain the above copyright notice,\n+ *    this list of conditions and the following disclaimer.\n+ * 2. Redistributions in binary form must reproduce the above copyright notice,\n+ *    this list of conditions and the following disclaimer in the documentation\n+ *    and/or other materials provided with the distribution.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ *\n+ * The views and conclusions contained in the software and documentation are\n+ * those of the authors and should not be interpreted as representing official\n+ * policies, either expressed or implied, of the FreeBSD Project.\n+ */\n+\n+#include \"efx.h\"\n+#include \"efx_impl.h\"\n+\n+#if EFSYS_OPT_NVRAM\n+\n+#if EFSYS_OPT_SIENA\n+\n+static const efx_nvram_ops_t\t__efx_nvram_siena_ops = {\n+#if EFSYS_OPT_DIAG\n+\tsiena_nvram_test,\t\t/* envo_test */\n+#endif\t/* EFSYS_OPT_DIAG */\n+\tsiena_nvram_type_to_partn,\t/* envo_type_to_partn */\n+\tsiena_nvram_partn_size,\t\t/* envo_partn_size */\n+\tsiena_nvram_partn_rw_start,\t/* envo_partn_rw_start */\n+\tsiena_nvram_partn_read,\t\t/* envo_partn_read */\n+\tsiena_nvram_partn_erase,\t/* envo_partn_erase */\n+\tsiena_nvram_partn_write,\t/* envo_partn_write */\n+\tsiena_nvram_partn_rw_finish,\t/* envo_partn_rw_finish */\n+\tsiena_nvram_partn_get_version,\t/* envo_partn_get_version */\n+\tsiena_nvram_partn_set_version,\t/* envo_partn_set_version */\n+\tNULL,\t\t\t\t/* envo_partn_validate */\n+};\n+\n+#endif\t/* EFSYS_OPT_SIENA */\n+\n+#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD\n+\n+static const efx_nvram_ops_t\t__efx_nvram_ef10_ops = {\n+#if EFSYS_OPT_DIAG\n+\tef10_nvram_test,\t\t/* envo_test */\n+#endif\t/* EFSYS_OPT_DIAG */\n+\tef10_nvram_type_to_partn,\t/* envo_type_to_partn */\n+\tef10_nvram_partn_size,\t\t/* envo_partn_size */\n+\tef10_nvram_partn_rw_start,\t/* envo_partn_rw_start */\n+\tef10_nvram_partn_read,\t\t/* envo_partn_read */\n+\tef10_nvram_partn_erase,\t\t/* envo_partn_erase */\n+\tef10_nvram_partn_write,\t\t/* envo_partn_write */\n+\tef10_nvram_partn_rw_finish,\t/* envo_partn_rw_finish */\n+\tef10_nvram_partn_get_version,\t/* envo_partn_get_version */\n+\tef10_nvram_partn_set_version,\t/* envo_partn_set_version */\n+\tef10_nvram_buffer_validate,\t/* envo_buffer_validate */\n+};\n+\n+#endif\t/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */\n+\n+\t__checkReturn\tefx_rc_t\n+efx_nvram_init(\n+\t__in\t\tefx_nic_t *enp)\n+{\n+\tconst efx_nvram_ops_t *envop;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);\n+\tEFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));\n+\n+\tswitch (enp->en_family) {\n+#if EFSYS_OPT_SIENA\n+\tcase EFX_FAMILY_SIENA:\n+\t\tenvop = &__efx_nvram_siena_ops;\n+\t\tbreak;\n+#endif\t/* EFSYS_OPT_SIENA */\n+\n+#if EFSYS_OPT_HUNTINGTON\n+\tcase EFX_FAMILY_HUNTINGTON:\n+\t\tenvop = &__efx_nvram_ef10_ops;\n+\t\tbreak;\n+#endif\t/* EFSYS_OPT_HUNTINGTON */\n+\n+#if EFSYS_OPT_MEDFORD\n+\tcase EFX_FAMILY_MEDFORD:\n+\t\tenvop = &__efx_nvram_ef10_ops;\n+\t\tbreak;\n+#endif\t/* EFSYS_OPT_MEDFORD */\n+\n+\tdefault:\n+\t\tEFSYS_ASSERT(0);\n+\t\trc = ENOTSUP;\n+\t\tgoto fail1;\n+\t}\n+\n+\tenp->en_envop = envop;\n+\tenp->en_mod_flags |= EFX_MOD_NVRAM;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#if EFSYS_OPT_DIAG\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tif ((rc = envop->envo_test(enp)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_size(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tsize_t *sizep)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0)\n+\t\tgoto fail2;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\t*sizep = 0;\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_get_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4])\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_get_version(enp, partn,\n+\t\t    subtypep, version)) != 0)\n+\t\tgoto fail2;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_rw_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out_opt\t\tsize_t *chunk_sizep)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\tEFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);\n+\n+\tEFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)\n+\t\tgoto fail2;\n+\n+\tenp->en_nvram_locked = type;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_read_chunk(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\tEFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);\n+\n+\tEFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)\n+\t\tgoto fail2;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tunsigned int offset = 0;\n+\tsize_t size = 0;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\tEFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);\n+\n+\tEFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_size(enp, partn, &size)) != 0)\n+\t\tgoto fail2;\n+\n+\tif ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0)\n+\t\tgoto fail3;\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_write_chunk(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in\t\t\tunsigned int offset,\n+\t__in_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\tEFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);\n+\n+\tEFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)\n+\t\tgoto fail2;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_rw_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\tEFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);\n+\n+\tEFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0)\n+\t\tgoto fail2;\n+\n+\tenp->en_nvram_locked = EFX_NVRAM_INVALID;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+\tenp->en_nvram_locked = EFX_NVRAM_INVALID;\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_set_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in_ecount(4)\t\tuint16_t version[4])\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\n+\t/*\n+\t * The Siena implementation of envo_set_version() will attempt to\n+\t * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.\n+\t * Therefore, you can't have already acquired the NVRAM_UPDATE lock.\n+\t */\n+\tEFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)\n+\t\tgoto fail2;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/* Validate buffer contents (before writing to flash) */\n+\t__checkReturn\t\tefx_rc_t\n+efx_nvram_validate(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__in_bcount(partn_size)\tcaddr_t partn_data,\n+\t__in\t\t\tsize_t partn_size)\n+{\n+\tconst efx_nvram_ops_t *envop = enp->en_envop;\n+\tuint32_t partn;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\n+\n+\tif ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (envop->envo_type_to_partn != NULL &&\n+\t    ((rc = envop->envo_buffer_validate(enp, partn,\n+\t    partn_data, partn_size)) != 0))\n+\t\tgoto fail2;\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\n+void\n+efx_nvram_fini(\n+\t__in\t\tefx_nic_t *enp)\n+{\n+\tEFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);\n+\tEFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);\n+\n+\tEFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);\n+\n+\tenp->en_envop = NULL;\n+\tenp->en_mod_flags &= ~EFX_MOD_NVRAM;\n+}\n+\n+#endif\t/* EFSYS_OPT_NVRAM */\n+\n+#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD\n+\n+/*\n+ * Internal MCDI request handling\n+ */\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_partitions(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__out\t\t\tunsigned int *npartnp)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];\n+\tunsigned int npartn;\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_PARTITIONS;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {\n+\t\trc = EMSGSIZE;\n+\t\tgoto fail2;\n+\t}\n+\tnpartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);\n+\n+\tif (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {\n+\t\trc = ENOENT;\n+\t\tgoto fail3;\n+\t}\n+\n+\tif (size < npartn * sizeof (uint32_t)) {\n+\t\trc = ENOSPC;\n+\t\tgoto fail3;\n+\t}\n+\n+\t*npartnp = npartn;\n+\n+\tmemcpy(data,\n+\t    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),\n+\t    (npartn * sizeof (uint32_t)));\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_metadata(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4],\n+\t__out_bcount_opt(size)\tchar *descp,\n+\t__in\t\t\tsize_t size)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_METADATA;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {\n+\t\trc = EMSGSIZE;\n+\t\tgoto fail2;\n+\t}\n+\n+\tif (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,\n+\t\tNVRAM_METADATA_OUT_SUBTYPE_VALID)) {\n+\t\t*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);\n+\t} else {\n+\t\t*subtypep = 0;\n+\t}\n+\n+\tif (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,\n+\t\tNVRAM_METADATA_OUT_VERSION_VALID)) {\n+\t\tversion[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);\n+\t\tversion[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);\n+\t\tversion[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);\n+\t\tversion[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);\n+\t} else {\n+\t\tversion[0] = version[1] = version[2] = version[3] = 0;\n+\t}\n+\n+\tif (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,\n+\t\tNVRAM_METADATA_OUT_DESCRIPTION_VALID)) {\n+\t\t/* Return optional descrition string */\n+\t\tif ((descp != NULL) && (size > 0)) {\n+\t\t\tsize_t desclen;\n+\n+\t\t\tdescp[0] = '\\0';\n+\t\t\tdesclen = (req.emr_out_length_used\n+\t\t\t    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));\n+\n+\t\t\tEFSYS_ASSERT3U(desclen, <=,\n+\t\t\t    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);\n+\n+\t\t\tif (size < desclen) {\n+\t\t\t\trc = ENOSPC;\n+\t\t\t\tgoto fail3;\n+\t\t\t}\n+\n+\t\t\tmemcpy(descp, MCDI_OUT2(req, char,\n+\t\t\t\tNVRAM_METADATA_OUT_DESCRIPTION),\n+\t\t\t    desclen);\n+\n+\t\t\t/* Ensure string is NUL terminated */\n+\t\t\tdescp[desclen] = '\\0';\n+\t\t}\n+\t}\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_info(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out_opt\t\tsize_t *sizep,\n+\t__out_opt\t\tuint32_t *addressp,\n+\t__out_opt\t\tuint32_t *erase_sizep,\n+\t__out_opt\t\tuint32_t *write_sizep)\n+{\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];\n+\tefx_mcdi_req_t req;\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_INFO;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);\n+\n+\tefx_mcdi_execute_quiet(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {\n+\t\trc = EMSGSIZE;\n+\t\tgoto fail2;\n+\t}\n+\n+\tif (sizep)\n+\t\t*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);\n+\n+\tif (addressp)\n+\t\t*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);\n+\n+\tif (erase_sizep)\n+\t\t*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);\n+\n+\tif (write_sizep) {\n+\t\t*write_sizep =\n+\t\t\t(req.emr_out_length_used <\n+\t\t\t    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?\n+\t\t\t0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);\n+\t}\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/*\n+ * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified\n+ * NVRAM updates. Older firmware will ignore the flags field in the request.\n+ */\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_update_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn)\n+{\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];\n+\tefx_mcdi_req_t req;\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_UPDATE_START;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);\n+\n+\tMCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,\n+\t    NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_read(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size,\n+\t__in\t\t\tuint32_t mode)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,\n+\t\t\t    MC_CMD_NVRAM_READ_OUT_LENMAX)];\n+\tefx_rc_t rc;\n+\n+\tif (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_READ;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {\n+\t\trc = EMSGSIZE;\n+\t\tgoto fail2;\n+\t}\n+\n+\tmemcpy(data,\n+\t    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),\n+\t    size);\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t offset,\n+\t__in\t\t\tsize_t size)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_ERASE_OUT_LEN)];\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_ERASE;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+/*\n+ * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both\n+ * Sienna and EF10 based boards.  However EF10 based boards support the use\n+ * of this command with payloads up to the maximum MCDI V2 payload length.\n+ */\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_write(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tuint32_t offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,\n+\t\t\t    MCDI_CTL_SDU_LEN_MAX_V2)];\n+\tefx_rc_t rc;\n+\tsize_t max_data_size;\n+\n+\tmax_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length\n+\t    - MC_CMD_NVRAM_WRITE_IN_LEN(0);\n+\tEFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);\n+\tEFSYS_ASSERT3U(max_data_size, <,\n+\t\t    enp->en_nic_cfg.enc_mcdi_max_payload_length);\n+\n+\tif (size > max_data_size) {\n+\t\trc = EINVAL;\n+\t\tgoto fail1;\n+\t}\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_WRITE;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);\n+\n+\tmemcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),\n+\t    data, size);\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail2;\n+\t}\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\n+/*\n+ * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified\n+ * NVRAM updates. Older firmware will ignore the flags field in the request.\n+ */\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_update_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tboolean_t reboot,\n+\t__out_opt\t\tuint32_t *resultp)\n+{\n+\tconst efx_nic_cfg_t *encp = &enp->en_nic_cfg;\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)];\n+\tuint32_t result = 0; /* FIXME: use MC_CMD_NVRAM_VERIFY_RC_UNKNOWN */\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);\n+\tMCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);\n+\n+\tMCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,\n+\t    NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (encp->enc_fw_verified_nvram_update_required == B_FALSE) {\n+\t\t/* Report success if verified updates are not supported. */\n+\t\tresult = MC_CMD_NVRAM_VERIFY_RC_SUCCESS;\n+\t} else {\n+\t\t/* Firmware-verified NVRAM updates are required */\n+\t\tif (req.emr_out_length_used <\n+\t\t    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {\n+\t\t\trc = EMSGSIZE;\n+\t\t\tgoto fail2;\n+\t\t}\n+\t\tresult =\n+\t\t    MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);\n+\n+\t\tif (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) {\n+\t\t\t/* Mandatory verification failed */\n+\t\t\trc = EINVAL;\n+\t\t\tgoto fail3;\n+\t\t}\n+\t}\n+\n+\tif (resultp != NULL)\n+\t\t*resultp = result;\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\t/* Always report verification result */\n+\tif (resultp != NULL)\n+\t\t*resultp = result;\n+\n+\treturn (rc);\n+}\n+\n+#if EFSYS_OPT_DIAG\n+\n+\t__checkReturn\t\tefx_rc_t\n+efx_mcdi_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_TEST_OUT_LEN)];\n+\tint result;\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_TEST;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;\n+\n+\tMCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {\n+\t\trc = EMSGSIZE;\n+\t\tgoto fail2;\n+\t}\n+\n+\tresult = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);\n+\tif (result == MC_CMD_NVRAM_TEST_FAIL) {\n+\n+\t\tEFSYS_PROBE1(nvram_test_failure, int, partn);\n+\n+\t\trc = (EINVAL);\n+\t\tgoto fail3;\n+\t}\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+\n+#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */\ndiff --git a/drivers/net/sfc/base/siena_impl.h b/drivers/net/sfc/base/siena_impl.h\nindex da03098..6a427b9 100644\n--- a/drivers/net/sfc/base/siena_impl.h\n+++ b/drivers/net/sfc/base/siena_impl.h\n@@ -133,6 +133,105 @@ siena_mcdi_get_timeout(\n \n #endif /* EFSYS_OPT_MCDI */\n \n+#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_lock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_unlock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_get_dynamic_cfg(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tboolean_t vpd,\n+\t__out\t\t\tsiena_mc_dynamic_config_hdr_t **dcfgp,\n+\t__out\t\t\tsize_t *sizep);\n+\n+#endif\t/* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */\n+\n+#if EFSYS_OPT_NVRAM\n+\n+#if EFSYS_OPT_DIAG\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp);\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_get_subtype(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_type_to_partn(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tuint32_t *partnp);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_size(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *sizep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_rw_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *chunk_sizep);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_read(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_write(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_rw_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_get_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4]);\n+\n+extern\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_set_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in_ecount(4)\t\tuint16_t version[4]);\n+\n+#endif\t/* EFSYS_OPT_NVRAM */\n+\n typedef struct siena_link_state_s {\n \tuint32_t\t\tsls_adv_cap_mask;\n \tuint32_t\t\tsls_lp_cap_mask;\ndiff --git a/drivers/net/sfc/base/siena_nic.c b/drivers/net/sfc/base/siena_nic.c\nindex 5d0f6e8..1f8c4e7 100644\n--- a/drivers/net/sfc/base/siena_nic.c\n+++ b/drivers/net/sfc/base/siena_nic.c\n@@ -34,6 +34,51 @@\n \n #if EFSYS_OPT_SIENA\n \n+#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM\n+\n+static\t__checkReturn\t\tefx_rc_t\n+siena_nic_get_partn_mask(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__out\t\t\tunsigned int *maskp)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_NVRAM_TYPES_IN_LEN,\n+\t\t\t    MC_CMD_NVRAM_TYPES_OUT_LEN)];\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_NVRAM_TYPES;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_NVRAM_TYPES_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_NVRAM_TYPES_OUT_LEN;\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (req.emr_out_length_used < MC_CMD_NVRAM_TYPES_OUT_LEN) {\n+\t\trc = EMSGSIZE;\n+\t\tgoto fail2;\n+\t}\n+\n+\t*maskp = MCDI_OUT_DWORD(req, NVRAM_TYPES_OUT_TYPES);\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */\n+\n static\t__checkReturn\tefx_rc_t\n siena_board_cfg(\n \t__in\t\tefx_nic_t *enp)\n@@ -210,6 +255,12 @@ siena_nic_probe(\n \tepp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask;\n \tepp->ep_adv_cap_mask = sls.sls_adv_cap_mask;\n \n+#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM\n+\tif ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0)\n+\t\tgoto fail9;\n+\tenp->en_u.siena.enu_partn_mask = mask;\n+#endif\n+\n #if EFSYS_OPT_MAC_STATS\n \t/* Wipe the MAC statistics */\n \tif ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)\n@@ -242,6 +293,10 @@ siena_nic_probe(\n fail10:\n \tEFSYS_PROBE(fail10);\n #endif\n+#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM\n+fail9:\n+\tEFSYS_PROBE(fail9);\n+#endif\n fail8:\n \tEFSYS_PROBE(fail8);\n fail7:\ndiff --git a/drivers/net/sfc/base/siena_nvram.c b/drivers/net/sfc/base/siena_nvram.c\nnew file mode 100644\nindex 0000000..af4cf17\n--- /dev/null\n+++ b/drivers/net/sfc/base/siena_nvram.c\n@@ -0,0 +1,734 @@\n+/*\n+ * Copyright (c) 2009-2016 Solarflare Communications Inc.\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ *\n+ * 1. Redistributions of source code must retain the above copyright notice,\n+ *    this list of conditions and the following disclaimer.\n+ * 2. Redistributions in binary form must reproduce the above copyright notice,\n+ *    this list of conditions and the following disclaimer in the documentation\n+ *    and/or other materials provided with the distribution.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ *\n+ * The views and conclusions contained in the software and documentation are\n+ * those of the authors and should not be interpreted as representing official\n+ * policies, either expressed or implied, of the FreeBSD Project.\n+ */\n+\n+#include \"efx.h\"\n+#include \"efx_impl.h\"\n+\n+#if EFSYS_OPT_SIENA\n+\n+#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_size(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *sizep)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {\n+\t\trc = ENOTSUP;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif ((rc = efx_mcdi_nvram_info(enp, partn, sizep,\n+\t    NULL, NULL, NULL)) != 0) {\n+\t\tgoto fail2;\n+\t}\n+\n+\treturn (0);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_lock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) {\n+\t\tgoto fail1;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_read(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\tsize_t chunk;\n+\tefx_rc_t rc;\n+\n+\twhile (size > 0) {\n+\t\tchunk = MIN(size, SIENA_NVRAM_CHUNK);\n+\n+\t\tif ((rc = efx_mcdi_nvram_read(enp, partn, offset, data, chunk,\n+\t\t\t    MC_CMD_NVRAM_READ_IN_V2_DEFAULT)) != 0) {\n+\t\t\tgoto fail1;\n+\t\t}\n+\n+\t\tsize -= chunk;\n+\t\tdata += chunk;\n+\t\toffset += chunk;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_erase(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__in\t\t\tsize_t size)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) {\n+\t\tgoto fail1;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_write(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tunsigned int offset,\n+\t__out_bcount(size)\tcaddr_t data,\n+\t__in\t\t\tsize_t size)\n+{\n+\tsize_t chunk;\n+\tefx_rc_t rc;\n+\n+\twhile (size > 0) {\n+\t\tchunk = MIN(size, SIENA_NVRAM_CHUNK);\n+\n+\t\tif ((rc = efx_mcdi_nvram_write(enp, partn, offset,\n+\t\t\t    data, chunk)) != 0) {\n+\t\t\tgoto fail1;\n+\t\t}\n+\n+\t\tsize -= chunk;\n+\t\tdata += chunk;\n+\t\toffset += chunk;\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_unlock(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn)\n+{\n+\tboolean_t reboot;\n+\tefx_rc_t rc;\n+\n+\t/*\n+\t * Reboot into the new image only for PHYs. The driver has to\n+\t * explicitly cope with an MC reboot after a firmware update.\n+\t */\n+\treboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 ||\n+\t\t    partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 ||\n+\t\t    partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO);\n+\n+\trc = efx_mcdi_nvram_update_finish(enp, partn, reboot, NULL);\n+\tif (rc != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif\t/* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */\n+\n+#if EFSYS_OPT_NVRAM\n+\n+typedef struct siena_parttbl_entry_s {\n+\tunsigned int\t\tpartn;\n+\tunsigned int\t\tport;\n+\tefx_nvram_type_t\tnvtype;\n+} siena_parttbl_entry_t;\n+\n+static siena_parttbl_entry_t siena_parttbl[] = {\n+\t{MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,\t1, EFX_NVRAM_NULLPHY},\n+\t{MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,\t2, EFX_NVRAM_NULLPHY},\n+\t{MC_CMD_NVRAM_TYPE_MC_FW,\t\t1, EFX_NVRAM_MC_FIRMWARE},\n+\t{MC_CMD_NVRAM_TYPE_MC_FW,\t\t2, EFX_NVRAM_MC_FIRMWARE},\n+\t{MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,\t1, EFX_NVRAM_MC_GOLDEN},\n+\t{MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,\t2, EFX_NVRAM_MC_GOLDEN},\n+\t{MC_CMD_NVRAM_TYPE_EXP_ROM,\t\t1, EFX_NVRAM_BOOTROM},\n+\t{MC_CMD_NVRAM_TYPE_EXP_ROM,\t\t2, EFX_NVRAM_BOOTROM},\n+\t{MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0,\t1, EFX_NVRAM_BOOTROM_CFG},\n+\t{MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1,\t2, EFX_NVRAM_BOOTROM_CFG},\n+\t{MC_CMD_NVRAM_TYPE_PHY_PORT0,\t\t1, EFX_NVRAM_PHY},\n+\t{MC_CMD_NVRAM_TYPE_PHY_PORT1,\t\t2, EFX_NVRAM_PHY},\n+\t{MC_CMD_NVRAM_TYPE_FPGA,\t\t1, EFX_NVRAM_FPGA},\n+\t{MC_CMD_NVRAM_TYPE_FPGA,\t\t2, EFX_NVRAM_FPGA},\n+\t{MC_CMD_NVRAM_TYPE_FPGA_BACKUP,\t\t1, EFX_NVRAM_FPGA_BACKUP},\n+\t{MC_CMD_NVRAM_TYPE_FPGA_BACKUP,\t\t2, EFX_NVRAM_FPGA_BACKUP},\n+\t{MC_CMD_NVRAM_TYPE_FC_FW,\t\t1, EFX_NVRAM_FCFW},\n+\t{MC_CMD_NVRAM_TYPE_FC_FW,\t\t2, EFX_NVRAM_FCFW},\n+\t{MC_CMD_NVRAM_TYPE_CPLD,\t\t1, EFX_NVRAM_CPLD},\n+\t{MC_CMD_NVRAM_TYPE_CPLD,\t\t2, EFX_NVRAM_CPLD},\n+\t{MC_CMD_NVRAM_TYPE_LICENSE,\t\t1, EFX_NVRAM_LICENSE},\n+\t{MC_CMD_NVRAM_TYPE_LICENSE,\t\t2, EFX_NVRAM_LICENSE}\n+};\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_type_to_partn(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tefx_nvram_type_t type,\n+\t__out\t\t\tuint32_t *partnp)\n+{\n+\tefx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);\n+\tunsigned int i;\n+\n+\tEFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);\n+\tEFSYS_ASSERT(partnp != NULL);\n+\n+\tfor (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {\n+\t\tsiena_parttbl_entry_t *entry = &siena_parttbl[i];\n+\n+\t\tif (entry->port == emip->emi_port && entry->nvtype == type) {\n+\t\t\t*partnp = entry->partn;\n+\t\t\treturn (0);\n+\t\t}\n+\t}\n+\n+\treturn (ENOTSUP);\n+}\n+\n+\n+#if EFSYS_OPT_DIAG\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_test(\n+\t__in\t\t\tefx_nic_t *enp)\n+{\n+\tefx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);\n+\tsiena_parttbl_entry_t *entry;\n+\tunsigned int i;\n+\tefx_rc_t rc;\n+\n+\t/*\n+\t * Iterate over the list of supported partition types\n+\t * applicable to *this* port\n+\t */\n+\tfor (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {\n+\t\tentry = &siena_parttbl[i];\n+\n+\t\tif (entry->port != emip->emi_port ||\n+\t\t    !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn)))\n+\t\t\tcontinue;\n+\n+\t\tif ((rc = efx_mcdi_nvram_test(enp, entry->partn)) != 0) {\n+\t\t\tgoto fail1;\n+\t\t}\n+\t}\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif\t/* EFSYS_OPT_DIAG */\n+\n+\n+#define\tSIENA_DYNAMIC_CFG_SIZE(_nitems)\t\t\t\t\t\\\n+\t(sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) *\t\t\\\n+\tsizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0])))\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_get_dynamic_cfg(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in\t\t\tboolean_t vpd,\n+\t__out\t\t\tsiena_mc_dynamic_config_hdr_t **dcfgp,\n+\t__out\t\t\tsize_t *sizep)\n+{\n+\tsiena_mc_dynamic_config_hdr_t *dcfg = NULL;\n+\tsize_t size;\n+\tuint8_t cksum;\n+\tunsigned int vpd_offset;\n+\tunsigned int vpd_length;\n+\tunsigned int hdr_length;\n+\tunsigned int nversions;\n+\tunsigned int pos;\n+\tunsigned int region;\n+\tefx_rc_t rc;\n+\n+\tEFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 ||\n+\t\t    partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1);\n+\n+\t/*\n+\t * Allocate sufficient memory for the entire dynamiccfg area, even\n+\t * if we're not actually going to read in the VPD.\n+\t */\n+\tif ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)\n+\t\tgoto fail1;\n+\n+\tEFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg);\n+\tif (dcfg == NULL) {\n+\t\trc = ENOMEM;\n+\t\tgoto fail2;\n+\t}\n+\n+\tif ((rc = siena_nvram_partn_read(enp, partn, 0,\n+\t    (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0)\n+\t\tgoto fail3;\n+\n+\t/* Verify the magic */\n+\tif (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0)\n+\t    != SIENA_MC_DYNAMIC_CONFIG_MAGIC)\n+\t\tgoto invalid1;\n+\n+\t/* All future versions of the structure must be backwards compatible */\n+\tEFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0);\n+\n+\thdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);\n+\tnversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);\n+\tvpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);\n+\tvpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);\n+\n+\t/* Verify the hdr doesn't overflow the partn size */\n+\tif (hdr_length > size || vpd_offset > size || vpd_length > size ||\n+\t    vpd_length + vpd_offset > size)\n+\t\tgoto invalid2;\n+\n+\t/* Verify the header has room for all it's versions */\n+\tif (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) ||\n+\t    hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions))\n+\t\tgoto invalid3;\n+\n+\t/*\n+\t * Read the remaining portion of the dcfg, either including\n+\t * the whole of VPD (there is no vpd length in this structure,\n+\t * so we have to parse each tag), or just the dcfg header itself\n+\t */\n+\tregion = vpd ? vpd_offset + vpd_length : hdr_length;\n+\tif (region > SIENA_NVRAM_CHUNK) {\n+\t\tif ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,\n+\t\t    (caddr_t)dcfg + SIENA_NVRAM_CHUNK,\n+\t\t    region - SIENA_NVRAM_CHUNK)) != 0)\n+\t\t\tgoto fail4;\n+\t}\n+\n+\t/* Verify checksum */\n+\tcksum = 0;\n+\tfor (pos = 0; pos < hdr_length; pos++)\n+\t\tcksum += ((uint8_t *)dcfg)[pos];\n+\tif (cksum != 0)\n+\t\tgoto invalid4;\n+\n+\tgoto done;\n+\n+invalid4:\n+\tEFSYS_PROBE(invalid4);\n+invalid3:\n+\tEFSYS_PROBE(invalid3);\n+invalid2:\n+\tEFSYS_PROBE(invalid2);\n+invalid1:\n+\tEFSYS_PROBE(invalid1);\n+\n+\t/*\n+\t * Construct a new \"null\" dcfg, with an empty version vector,\n+\t * and an empty VPD chunk trailing. This has the neat side effect\n+\t * of testing the exception paths in the write path.\n+\t */\n+\tEFX_POPULATE_DWORD_1(dcfg->magic,\n+\t\t\t    EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC);\n+\tEFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg));\n+\tEFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0,\n+\t\t\t    SIENA_MC_DYNAMIC_CONFIG_VERSION);\n+\tEFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,\n+\t\t\t    EFX_DWORD_0, sizeof (*dcfg));\n+\tEFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0);\n+\tEFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0);\n+\n+done:\n+\t*dcfgp = dcfg;\n+\t*sizep = size;\n+\n+\treturn (0);\n+\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, size, dcfg);\n+\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_get_subtype(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep)\n+{\n+\tefx_mcdi_req_t req;\n+\tuint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,\n+\t\t\t    MC_CMD_GET_BOARD_CFG_OUT_LENMAX)];\n+\tefx_word_t *fw_list;\n+\tefx_rc_t rc;\n+\n+\t(void) memset(payload, 0, sizeof (payload));\n+\treq.emr_cmd = MC_CMD_GET_BOARD_CFG;\n+\treq.emr_in_buf = payload;\n+\treq.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;\n+\treq.emr_out_buf = payload;\n+\treq.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMAX;\n+\n+\tefx_mcdi_execute(enp, &req);\n+\n+\tif (req.emr_rc != 0) {\n+\t\trc = req.emr_rc;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {\n+\t\trc = EMSGSIZE;\n+\t\tgoto fail2;\n+\t}\n+\n+\tif (req.emr_out_length_used <\n+\t    MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST +\n+\t    (partn + 1) * sizeof (efx_word_t)) {\n+\t\trc = ENOENT;\n+\t\tgoto fail3;\n+\t}\n+\n+\tfw_list = MCDI_OUT2(req, efx_word_t,\n+\t\t\t    GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);\n+\t*subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0);\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_get_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tuint32_t *subtypep,\n+\t__out_ecount(4)\t\tuint16_t version[4])\n+{\n+\tsiena_mc_dynamic_config_hdr_t *dcfg;\n+\tsiena_parttbl_entry_t *entry;\n+\tuint32_t dcfg_partn;\n+\tunsigned int i;\n+\tefx_rc_t rc;\n+\n+\tif ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {\n+\t\trc = ENOTSUP;\n+\t\tgoto fail1;\n+\t}\n+\n+\tif ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0)\n+\t\tgoto fail2;\n+\n+\t/*\n+\t * Some partitions are accessible from both ports (for instance BOOTROM)\n+\t * Find the highest version reported by all dcfg structures on ports\n+\t * that have access to this partition.\n+\t */\n+\tversion[0] = version[1] = version[2] = version[3] = 0;\n+\tfor (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {\n+\t\tsiena_mc_fw_version_t *verp;\n+\t\tunsigned int nitems;\n+\t\tuint16_t temp[4];\n+\t\tsize_t length;\n+\n+\t\tentry = &siena_parttbl[i];\n+\t\tif (entry->partn != partn)\n+\t\t\tcontinue;\n+\n+\t\tdcfg_partn = (entry->port == 1)\n+\t\t\t? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0\n+\t\t\t: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;\n+\t\t/*\n+\t\t * Ingore missing partitions on port 2, assuming they're due\n+\t\t * to to running on a single port part.\n+\t\t */\n+\t\tif ((1 << dcfg_partn) &  ~enp->en_u.siena.enu_partn_mask) {\n+\t\t\tif (entry->port == 2)\n+\t\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,\n+\t\t    B_FALSE, &dcfg, &length)) != 0)\n+\t\t\tgoto fail3;\n+\n+\t\tnitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items,\n+\t\t\t    EFX_DWORD_0);\n+\t\tif (nitems < entry->partn)\n+\t\t\tgoto done;\n+\n+\t\tverp = &dcfg->fw_version[partn];\n+\t\ttemp[0] = EFX_WORD_FIELD(verp->version_w, EFX_WORD_0);\n+\t\ttemp[1] = EFX_WORD_FIELD(verp->version_x, EFX_WORD_0);\n+\t\ttemp[2] = EFX_WORD_FIELD(verp->version_y, EFX_WORD_0);\n+\t\ttemp[3] = EFX_WORD_FIELD(verp->version_z, EFX_WORD_0);\n+\t\tif (memcmp(version, temp, sizeof (temp)) < 0)\n+\t\t\tmemcpy(version, temp, sizeof (temp));\n+\n+done:\n+\t\tEFSYS_KMEM_FREE(enp->en_esip, length, dcfg);\n+\t}\n+\n+\treturn (0);\n+\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_rw_start(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__out\t\t\tsize_t *chunk_sizep)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = siena_nvram_partn_lock(enp, partn)) != 0)\n+\t\tgoto fail1;\n+\n+\tif (chunk_sizep != NULL)\n+\t\t*chunk_sizep = SIENA_NVRAM_CHUNK;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_rw_finish(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn)\n+{\n+\tefx_rc_t rc;\n+\n+\tif ((rc = siena_nvram_partn_unlock(enp, partn)) != 0)\n+\t\tgoto fail1;\n+\n+\treturn (0);\n+\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+\t__checkReturn\t\tefx_rc_t\n+siena_nvram_partn_set_version(\n+\t__in\t\t\tefx_nic_t *enp,\n+\t__in\t\t\tuint32_t partn,\n+\t__in_ecount(4)\t\tuint16_t version[4])\n+{\n+\tefx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);\n+\tsiena_mc_dynamic_config_hdr_t *dcfg = NULL;\n+\tsiena_mc_fw_version_t *fwverp;\n+\tuint32_t dcfg_partn;\n+\tsize_t dcfg_size;\n+\tunsigned int hdr_length;\n+\tunsigned int vpd_length;\n+\tunsigned int vpd_offset;\n+\tunsigned int nitems;\n+\tunsigned int required_hdr_length;\n+\tunsigned int pos;\n+\tuint8_t cksum;\n+\tuint32_t subtype;\n+\tsize_t length;\n+\tefx_rc_t rc;\n+\n+\tdcfg_partn = (emip->emi_port == 1)\n+\t\t? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0\n+\t\t: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;\n+\n+\tif ((rc = siena_nvram_partn_size(enp, dcfg_partn, &dcfg_size)) != 0)\n+\t\tgoto fail1;\n+\n+\tif ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)\n+\t\tgoto fail2;\n+\n+\tif ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,\n+\t    B_TRUE, &dcfg, &length)) != 0)\n+\t\tgoto fail3;\n+\n+\thdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);\n+\tnitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);\n+\tvpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);\n+\tvpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);\n+\n+\t/*\n+\t * NOTE: This function will blatt any fields trailing the version\n+\t * vector, or the VPD chunk.\n+\t */\n+\trequired_hdr_length = SIENA_DYNAMIC_CFG_SIZE(partn + 1);\n+\tif (required_hdr_length + vpd_length > length) {\n+\t\trc = ENOSPC;\n+\t\tgoto fail4;\n+\t}\n+\n+\tif (vpd_offset < required_hdr_length) {\n+\t\t(void) memmove((caddr_t)dcfg + required_hdr_length,\n+\t\t\t(caddr_t)dcfg + vpd_offset, vpd_length);\n+\t\tvpd_offset = required_hdr_length;\n+\t\tEFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,\n+\t\t\t\t    EFX_DWORD_0, vpd_offset);\n+\t}\n+\n+\tif (hdr_length < required_hdr_length) {\n+\t\t(void) memset((caddr_t)dcfg + hdr_length, 0,\n+\t\t\trequired_hdr_length - hdr_length);\n+\t\thdr_length = required_hdr_length;\n+\t\tEFX_POPULATE_WORD_1(dcfg->length,\n+\t\t\t\t    EFX_WORD_0, hdr_length);\n+\t}\n+\n+\t/* Get the subtype to insert into the fw_subtype array */\n+\tif ((rc = siena_nvram_get_subtype(enp, partn, &subtype)) != 0)\n+\t\tgoto fail5;\n+\n+\t/* Fill out the new version */\n+\tfwverp = &dcfg->fw_version[partn];\n+\tEFX_POPULATE_DWORD_1(fwverp->fw_subtype, EFX_DWORD_0, subtype);\n+\tEFX_POPULATE_WORD_1(fwverp->version_w, EFX_WORD_0, version[0]);\n+\tEFX_POPULATE_WORD_1(fwverp->version_x, EFX_WORD_0, version[1]);\n+\tEFX_POPULATE_WORD_1(fwverp->version_y, EFX_WORD_0, version[2]);\n+\tEFX_POPULATE_WORD_1(fwverp->version_z, EFX_WORD_0, version[3]);\n+\n+\t/* Update the version count */\n+\tif (nitems < partn + 1) {\n+\t\tnitems = partn + 1;\n+\t\tEFX_POPULATE_DWORD_1(dcfg->num_fw_version_items,\n+\t\t\t\t    EFX_DWORD_0, nitems);\n+\t}\n+\n+\t/* Update the checksum */\n+\tcksum = 0;\n+\tfor (pos = 0; pos < hdr_length; pos++)\n+\t\tcksum += ((uint8_t *)dcfg)[pos];\n+\tdcfg->csum.eb_u8[0] -= cksum;\n+\n+\t/* Erase and write the new partition */\n+\tif ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, dcfg_size)) != 0)\n+\t\tgoto fail6;\n+\n+\t/* Write out the new structure to nvram */\n+\tif ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0,\n+\t    (caddr_t)dcfg, vpd_offset + vpd_length)) != 0)\n+\t\tgoto fail7;\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, length, dcfg);\n+\n+\tsiena_nvram_partn_unlock(enp, dcfg_partn);\n+\n+\treturn (0);\n+\n+fail7:\n+\tEFSYS_PROBE(fail7);\n+fail6:\n+\tEFSYS_PROBE(fail6);\n+fail5:\n+\tEFSYS_PROBE(fail5);\n+fail4:\n+\tEFSYS_PROBE(fail4);\n+\n+\tEFSYS_KMEM_FREE(enp->en_esip, length, dcfg);\n+fail3:\n+\tEFSYS_PROBE(fail3);\n+fail2:\n+\tEFSYS_PROBE(fail2);\n+fail1:\n+\tEFSYS_PROBE1(fail1, efx_rc_t, rc);\n+\n+\treturn (rc);\n+}\n+\n+#endif\t/* EFSYS_OPT_NVRAM */\n+\n+#endif\t/* EFSYS_OPT_SIENA */\n",
    "prefixes": [
        "dpdk-dev",
        "v2",
        "26/55"
    ]
}