get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 94969,
    "url": "http://patchwork.dpdk.org/api/patches/94969/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20210629080632.30964-3-david.marchand@redhat.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.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": "<20210629080632.30964-3-david.marchand@redhat.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210629080632.30964-3-david.marchand@redhat.com",
    "date": "2021-06-29T08:06:32",
    "name": "[v3,2/2] eal: handle compressed firmwares",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "082a06374a59ba98344e128d52f38435659d16be",
    "submitter": {
        "id": 1173,
        "url": "http://patchwork.dpdk.org/api/people/1173/?format=api",
        "name": "David Marchand",
        "email": "david.marchand@redhat.com"
    },
    "delegate": {
        "id": 24651,
        "url": "http://patchwork.dpdk.org/api/users/24651/?format=api",
        "username": "dmarchand",
        "first_name": "David",
        "last_name": "Marchand",
        "email": "david.marchand@redhat.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20210629080632.30964-3-david.marchand@redhat.com/mbox/",
    "series": [
        {
            "id": 17515,
            "url": "http://patchwork.dpdk.org/api/series/17515/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=17515",
            "date": "2021-06-29T08:06:30",
            "name": "Support compressed firmwares",
            "version": 3,
            "mbox": "http://patchwork.dpdk.org/series/17515/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/94969/comments/",
    "check": "fail",
    "checks": "http://patchwork.dpdk.org/api/patches/94969/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id CAC22A0A0C;\n\tTue, 29 Jun 2021 10:07:04 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id BC5544118D;\n\tTue, 29 Jun 2021 10:07:04 +0200 (CEST)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by mails.dpdk.org (Postfix) with ESMTP id 6549E4118D\n for <dev@dpdk.org>; Tue, 29 Jun 2021 10:07:03 +0200 (CEST)",
            "from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com\n [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id\n us-mta-380-Z5jFpn3uMlu4whlwv7L0Xw-1; Tue, 29 Jun 2021 04:06:57 -0400",
            "from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com\n [10.5.11.12])\n (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n (No client certificate requested)\n by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 365FD801F97;\n Tue, 29 Jun 2021 08:06:55 +0000 (UTC)",
            "from dmarchan.remote.csb (unknown [10.40.192.189])\n by smtp.corp.redhat.com (Postfix) with ESMTP id 720D260C0F;\n Tue, 29 Jun 2021 08:06:49 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1624954022;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=4yYGhts3dPY1eXJTn0NLJJVtRHbLMnoGzzay171oU0w=;\n b=HJ8eegGJssMcDkFn1hB3vf+WLH4LrNVwsVTCEXW1wCZyUHZFycHVwlZgQDYHhf8V3Nu+6o\n 9K6yn4E0lbqsCqlApHiGc7aP2twVX/jzTxxTMURhrNDN00vhzjTuqtYdG1tuJ2baQykRiQ\n 63gVqW08TPslg/kyBSswzMmn8h9eq0c=",
        "X-MC-Unique": "Z5jFpn3uMlu4whlwv7L0Xw-1",
        "From": "David Marchand <david.marchand@redhat.com>",
        "To": "dev@dpdk.org",
        "Cc": "Igor Russkikh <irusskikh@marvell.com>, Aaron Conole <aconole@redhat.com>,\n Michael Santana <maicolgabriel@hotmail.com>,\n Bruce Richardson <bruce.richardson@intel.com>,\n Rasesh Mody <rmody@marvell.com>, Shahed Shaikh <shshaikh@marvell.com>,\n Qiming Yang <qiming.yang@intel.com>, Qi Zhang <qi.z.zhang@intel.com>,\n Heinrich Kuhn <heinrich.kuhn@netronome.com>,\n Devendra Singh Rawat <dsinghrawat@marvell.com>,\n Ray Kinsella <mdr@ashroe.eu>, Neil Horman <nhorman@tuxdriver.com>,\n Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>,\n Narcisa Ana Maria Vasile <navasile@linux.microsoft.com>,\n Dmitry Malloy <dmitrym@microsoft.com>,\n Pallavi Kadam <pallavi.kadam@intel.com>",
        "Date": "Tue, 29 Jun 2021 10:06:32 +0200",
        "Message-Id": "<20210629080632.30964-3-david.marchand@redhat.com>",
        "In-Reply-To": "<20210629080632.30964-1-david.marchand@redhat.com>",
        "References": "<20210602095836.24901-1-david.marchand@redhat.com>\n <20210629080632.30964-1-david.marchand@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.12",
        "Authentication-Results": "relay.mimecast.com;\n auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=david.marchand@redhat.com",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain; charset=\"US-ASCII\"",
        "Subject": "[dpdk-dev] [PATCH v3 2/2] eal: handle compressed firmwares",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Introduce an internal firmware loading helper to remove code duplication\nin our drivers and handle xz compressed firmwares by calling libarchive.\n\nThis helper tries to look for .xz suffixes so that drivers are not aware\nthe firmwares have been compressed.\n\nlibarchive is set as an optional dependency: without libarchive, a\nruntime warning is emitted so that users know there is a compressed\nfirmware.\n\nWindows implementation is left as an empty stub.\n\nSigned-off-by: David Marchand <david.marchand@redhat.com>\nReviewed-by: Igor Russkikh <irusskikh@marvell.com>\n---\nChanges since v2:\n- added a comment on libarchive link dependency,\n\nChanges since v1:\n- used pkg-config for libarchive detection,\n- updated doxygen annotations,\n- added internal helpers in eal_firmware.c to enhance readability,\n- dropped whitespace damage in version.map,\n\n---\n .github/workflows/build.yml    |   1 +\n .travis.yml                    |   1 +\n config/meson.build             |  10 +++\n drivers/net/bnx2x/bnx2x.c      |  35 +++-----\n drivers/net/ice/ice_ethdev.c   |  60 +++----------\n drivers/net/nfp/nfp_net.c      |  57 +++----------\n drivers/net/qede/qede_main.c   |  45 ++++------\n lib/eal/include/rte_firmware.h |  32 +++++++\n lib/eal/unix/eal_firmware.c    | 149 +++++++++++++++++++++++++++++++++\n lib/eal/unix/meson.build       |   1 +\n lib/eal/version.map            |   1 +\n lib/eal/windows/eal.c          |   9 ++\n 12 files changed, 259 insertions(+), 142 deletions(-)\n create mode 100644 lib/eal/include/rte_firmware.h\n create mode 100644 lib/eal/unix/eal_firmware.c",
    "diff": "diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml\nindex 7c4d6dcdbf..7dac20ddeb 100644\n--- a/.github/workflows/build.yml\n+++ b/.github/workflows/build.yml\n@@ -93,6 +93,7 @@ jobs:\n       run: sudo apt install -y ccache libnuma-dev python3-setuptools\n         python3-wheel python3-pip python3-pyelftools ninja-build libbsd-dev\n         libpcap-dev libibverbs-dev libcrypto++-dev libfdt-dev libjansson-dev\n+        libarchive-dev\n     - name: Install libabigail build dependencies if no cache is available\n       if: env.ABI_CHECKS == 'true' && steps.libabigail-cache.outputs.cache-hit != 'true'\n       run: sudo apt install -y autoconf automake libtool pkg-config libxml2-dev\ndiff --git a/.travis.yml b/.travis.yml\nindex 5b702cc9bb..23067d9e3c 100644\n--- a/.travis.yml\n+++ b/.travis.yml\n@@ -16,6 +16,7 @@ addons:\n     packages: &required_packages\n       - [libnuma-dev, python3-setuptools, python3-wheel, python3-pip, python3-pyelftools, ninja-build]\n       - [libbsd-dev, libpcap-dev, libibverbs-dev, libcrypto++-dev, libfdt-dev, libjansson-dev]\n+      - [libarchive-dev]\n \n _aarch64_packages: &aarch64_packages\n   - *required_packages\ndiff --git a/config/meson.build b/config/meson.build\nindex 017bb2efbb..639aa74e12 100644\n--- a/config/meson.build\n+++ b/config/meson.build\n@@ -172,6 +172,16 @@ if libexecinfo.found() and cc.has_header('execinfo.h')\n     dpdk_extra_ldflags += '-lexecinfo'\n endif\n \n+libarchive = dependency('libarchive', required: false, method: 'pkg-config')\n+if libarchive.found()\n+    dpdk_conf.set('RTE_HAS_LIBARCHIVE', 1)\n+    # Push libarchive link dependency at the project level to support\n+    # statically linking dpdk apps. Details at:\n+    # https://inbox.dpdk.org/dev/20210605004024.660267a1@sovereign/\n+    add_project_link_arguments('-larchive', language: 'c')\n+    dpdk_extra_ldflags += '-larchive'\n+endif\n+\n # check for libbsd\n libbsd = dependency('libbsd', required: false, method: 'pkg-config')\n if libbsd.found()\ndiff --git a/drivers/net/bnx2x/bnx2x.c b/drivers/net/bnx2x/bnx2x.c\nindex 654878d9de..60292753e2 100644\n--- a/drivers/net/bnx2x/bnx2x.c\n+++ b/drivers/net/bnx2x/bnx2x.c\n@@ -26,7 +26,9 @@\n #include <arpa/inet.h>\n #include <fcntl.h>\n #include <zlib.h>\n+\n #include <rte_bitops.h>\n+#include <rte_firmware.h>\n #include <rte_string_fns.h>\n \n #define BNX2X_PMD_VER_PREFIX \"BNX2X PMD\"\n@@ -9655,44 +9657,33 @@ static void bnx2x_init_rte(struct bnx2x_softc *sc)\n void bnx2x_load_firmware(struct bnx2x_softc *sc)\n {\n \tconst char *fwname;\n-\tint f;\n-\tstruct stat st;\n+\tvoid *buf;\n+\tsize_t bufsz;\n \n \tfwname = sc->devinfo.device_id == CHIP_NUM_57711\n \t\t? FW_NAME_57711 : FW_NAME_57810;\n-\tf = open(fwname, O_RDONLY);\n-\tif (f < 0) {\n+\tif (rte_firmware_read(fwname, &buf, &bufsz) != 0) {\n \t\tPMD_DRV_LOG(NOTICE, sc, \"Can't open firmware file\");\n \t\treturn;\n \t}\n \n-\tif (fstat(f, &st) < 0) {\n-\t\tPMD_DRV_LOG(NOTICE, sc, \"Can't stat firmware file\");\n-\t\tclose(f);\n-\t\treturn;\n-\t}\n-\n-\tsc->firmware = rte_zmalloc(\"bnx2x_fw\", st.st_size, RTE_CACHE_LINE_SIZE);\n+\tsc->firmware = rte_zmalloc(\"bnx2x_fw\", bufsz, RTE_CACHE_LINE_SIZE);\n \tif (!sc->firmware) {\n \t\tPMD_DRV_LOG(NOTICE, sc, \"Can't allocate memory for firmware\");\n-\t\tclose(f);\n-\t\treturn;\n+\t\tgoto out;\n \t}\n \n-\tif (read(f, sc->firmware, st.st_size) != st.st_size) {\n-\t\tPMD_DRV_LOG(NOTICE, sc, \"Can't read firmware data\");\n-\t\tclose(f);\n-\t\treturn;\n-\t}\n-\tclose(f);\n-\n-\tsc->fw_len = st.st_size;\n+\tsc->fw_len = bufsz;\n \tif (sc->fw_len < FW_HEADER_LEN) {\n \t\tPMD_DRV_LOG(NOTICE, sc,\n \t\t\t    \"Invalid fw size: %\" PRIu64, sc->fw_len);\n-\t\treturn;\n+\t\tgoto out;\n \t}\n+\n+\tmemcpy(sc->firmware, buf, sc->fw_len);\n \tPMD_DRV_LOG(DEBUG, sc, \"fw_len = %\" PRIu64, sc->fw_len);\n+out:\n+\tfree(buf);\n }\n \n static void\ndiff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c\nindex d180b73c32..06da1bbd94 100644\n--- a/drivers/net/ice/ice_ethdev.c\n+++ b/drivers/net/ice/ice_ethdev.c\n@@ -10,6 +10,7 @@\n #include <sys/stat.h>\n #include <unistd.h>\n \n+#include <rte_firmware.h>\n #include <rte_tailq.h>\n \n #include \"base/ice_sched.h\"\n@@ -1673,22 +1674,14 @@ ice_load_pkg_type(struct ice_hw *hw)\n \treturn package_type;\n }\n \n-#ifdef RTE_EXEC_ENV_WINDOWS\n-#define ice_access _access\n-#else\n-#define ice_access access\n-#endif\n-\n int ice_load_pkg(struct ice_adapter *adapter, bool use_dsn, uint64_t dsn)\n {\n \tstruct ice_hw *hw = &adapter->hw;\n \tchar pkg_file[ICE_MAX_PKG_FILENAME_SIZE];\n \tchar opt_ddp_filename[ICE_MAX_PKG_FILENAME_SIZE];\n+\tvoid *buf;\n+\tsize_t bufsz;\n \tint err;\n-\tuint8_t *buf = NULL;\n-\tint buf_len;\n-\tFILE *file;\n-\tstruct stat fstat;\n \n \tif (!use_dsn)\n \t\tgoto no_dsn;\n@@ -1698,57 +1691,31 @@ int ice_load_pkg(struct ice_adapter *adapter, bool use_dsn, uint64_t dsn)\n \t\t\"ice-%016\" PRIx64 \".pkg\", dsn);\n \tstrncpy(pkg_file, ICE_PKG_FILE_SEARCH_PATH_UPDATES,\n \t\tICE_MAX_PKG_FILENAME_SIZE);\n-\tif (!ice_access(strcat(pkg_file, opt_ddp_filename), 0))\n+\tstrcat(pkg_file, opt_ddp_filename);\n+\tif (rte_firmware_read(pkg_file, &buf, &bufsz) == 0)\n \t\tgoto load_fw;\n \n \tstrncpy(pkg_file, ICE_PKG_FILE_SEARCH_PATH_DEFAULT,\n \t\tICE_MAX_PKG_FILENAME_SIZE);\n-\tif (!ice_access(strcat(pkg_file, opt_ddp_filename), 0))\n+\tstrcat(pkg_file, opt_ddp_filename);\n+\tif (rte_firmware_read(pkg_file, &buf, &bufsz) == 0)\n \t\tgoto load_fw;\n \n no_dsn:\n \tstrncpy(pkg_file, ICE_PKG_FILE_UPDATES, ICE_MAX_PKG_FILENAME_SIZE);\n-\tif (!ice_access(pkg_file, 0))\n+\tif (rte_firmware_read(pkg_file, &buf, &bufsz) == 0)\n \t\tgoto load_fw;\n+\n \tstrncpy(pkg_file, ICE_PKG_FILE_DEFAULT, ICE_MAX_PKG_FILENAME_SIZE);\n-\tif (ice_access(pkg_file, 0)) {\n+\tif (rte_firmware_read(pkg_file, &buf, &bufsz) < 0) {\n \t\tPMD_INIT_LOG(ERR, \"failed to search file path\\n\");\n \t\treturn -1;\n \t}\n \n load_fw:\n-\tfile = fopen(pkg_file, \"rb\");\n-\tif (!file)  {\n-\t\tPMD_INIT_LOG(ERR, \"failed to open file: %s\\n\", pkg_file);\n-\t\treturn -1;\n-\t}\n-\n \tPMD_INIT_LOG(DEBUG, \"DDP package name: %s\", pkg_file);\n \n-\terr = stat(pkg_file, &fstat);\n-\tif (err) {\n-\t\tPMD_INIT_LOG(ERR, \"failed to get file stats\\n\");\n-\t\tgoto out;\n-\t}\n-\n-\tbuf_len = fstat.st_size;\n-\tbuf = rte_malloc(NULL, buf_len, 0);\n-\n-\tif (!buf) {\n-\t\tPMD_INIT_LOG(ERR, \"failed to allocate buf of size %d for package\\n\",\n-\t\t\t\tbuf_len);\n-\t\terr = -1;\n-\t\tgoto out;\n-\t}\n-\n-\terr = fread(buf, buf_len, 1, file);\n-\tif (err != 1) {\n-\t\tPMD_INIT_LOG(ERR, \"failed to read package data\\n\");\n-\t\terr = -1;\n-\t\tgoto out;\n-\t}\n-\n-\terr = ice_copy_and_init_pkg(hw, buf, buf_len);\n+\terr = ice_copy_and_init_pkg(hw, buf, bufsz);\n \tif (err) {\n \t\tPMD_INIT_LOG(ERR, \"ice_copy_and_init_hw failed: %d\\n\", err);\n \t\tgoto out;\n@@ -1758,13 +1725,10 @@ int ice_load_pkg(struct ice_adapter *adapter, bool use_dsn, uint64_t dsn)\n \tadapter->active_pkg_type = ice_load_pkg_type(hw);\n \n out:\n-\tfclose(file);\n-\trte_free(buf);\n+\tfree(buf);\n \treturn err;\n }\n \n-#undef ice_access\n-\n static void\n ice_base_queue_get(struct ice_pf *pf)\n {\ndiff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c\nindex 2ee88fbfc7..879da7ef59 100644\n--- a/drivers/net/nfp/nfp_net.c\n+++ b/drivers/net/nfp/nfp_net.c\n@@ -29,6 +29,7 @@\n #include <rte_alarm.h>\n #include <rte_spinlock.h>\n #include <rte_service_component.h>\n+#include <rte_firmware.h>\n \n #include \"nfpcore/nfp_cpp.h\"\n #include \"nfpcore/nfp_nffw.h\"\n@@ -3366,12 +3367,10 @@ static int\n nfp_fw_upload(struct rte_pci_device *dev, struct nfp_nsp *nsp, char *card)\n {\n \tstruct nfp_cpp *cpp = nsp->cpp;\n-\tint fw_f;\n-\tchar *fw_buf;\n+\tvoid *fw_buf;\n \tchar fw_name[125];\n \tchar serial[40];\n-\tstruct stat file_stat;\n-\toff_t fsize, bytes;\n+\tsize_t fsize;\n \n \t/* Looking for firmware file in order of priority */\n \n@@ -3384,66 +3383,34 @@ nfp_fw_upload(struct rte_pci_device *dev, struct nfp_nsp *nsp, char *card)\n \n \tsnprintf(fw_name, sizeof(fw_name), \"%s/%s.nffw\", DEFAULT_FW_PATH,\n \t\t\tserial);\n-\n \tPMD_DRV_LOG(DEBUG, \"Trying with fw file: %s\", fw_name);\n-\tfw_f = open(fw_name, O_RDONLY);\n-\tif (fw_f >= 0)\n-\t\tgoto read_fw;\n+\tif (rte_firmware_read(fw_name, &fw_buf, &fsize) == 0)\n+\t\tgoto load_fw;\n \n \t/* Then try the PCI name */\n \tsnprintf(fw_name, sizeof(fw_name), \"%s/pci-%s.nffw\", DEFAULT_FW_PATH,\n \t\t\tdev->device.name);\n-\n \tPMD_DRV_LOG(DEBUG, \"Trying with fw file: %s\", fw_name);\n-\tfw_f = open(fw_name, O_RDONLY);\n-\tif (fw_f >= 0)\n-\t\tgoto read_fw;\n+\tif (rte_firmware_read(fw_name, &fw_buf, &fsize) == 0)\n+\t\tgoto load_fw;\n \n \t/* Finally try the card type and media */\n \tsnprintf(fw_name, sizeof(fw_name), \"%s/%s\", DEFAULT_FW_PATH, card);\n \tPMD_DRV_LOG(DEBUG, \"Trying with fw file: %s\", fw_name);\n-\tfw_f = open(fw_name, O_RDONLY);\n-\tif (fw_f < 0) {\n+\tif (rte_firmware_read(fw_name, &fw_buf, &fsize) < 0) {\n \t\tPMD_DRV_LOG(INFO, \"Firmware file %s not found.\", fw_name);\n \t\treturn -ENOENT;\n \t}\n \n-read_fw:\n-\tif (fstat(fw_f, &file_stat) < 0) {\n-\t\tPMD_DRV_LOG(INFO, \"Firmware file %s size is unknown\", fw_name);\n-\t\tclose(fw_f);\n-\t\treturn -ENOENT;\n-\t}\n-\n-\tfsize = file_stat.st_size;\n-\tPMD_DRV_LOG(INFO, \"Firmware file found at %s with size: %\" PRIu64 \"\",\n-\t\t\t    fw_name, (uint64_t)fsize);\n-\n-\tfw_buf = malloc((size_t)fsize);\n-\tif (!fw_buf) {\n-\t\tPMD_DRV_LOG(INFO, \"malloc failed for fw buffer\");\n-\t\tclose(fw_f);\n-\t\treturn -ENOMEM;\n-\t}\n-\tmemset(fw_buf, 0, fsize);\n-\n-\tbytes = read(fw_f, fw_buf, fsize);\n-\tif (bytes != fsize) {\n-\t\tPMD_DRV_LOG(INFO, \"Reading fw to buffer failed.\"\n-\t\t\t\t   \"Just %\" PRIu64 \" of %\" PRIu64 \" bytes read\",\n-\t\t\t\t   (uint64_t)bytes, (uint64_t)fsize);\n-\t\tfree(fw_buf);\n-\t\tclose(fw_f);\n-\t\treturn -EIO;\n-\t}\n+load_fw:\n+\tPMD_DRV_LOG(INFO, \"Firmware file found at %s with size: %zu\",\n+\t\tfw_name, fsize);\n \n \tPMD_DRV_LOG(INFO, \"Uploading the firmware ...\");\n-\tnfp_nsp_load_fw(nsp, fw_buf, bytes);\n+\tnfp_nsp_load_fw(nsp, fw_buf, fsize);\n \tPMD_DRV_LOG(INFO, \"Done\");\n \n \tfree(fw_buf);\n-\tclose(fw_f);\n-\n \treturn 0;\n }\n \ndiff --git a/drivers/net/qede/qede_main.c b/drivers/net/qede/qede_main.c\nindex caa9d1d4f6..504e2c66a0 100644\n--- a/drivers/net/qede/qede_main.c\n+++ b/drivers/net/qede/qede_main.c\n@@ -5,7 +5,9 @@\n  */\n \n #include <limits.h>\n+\n #include <rte_alarm.h>\n+#include <rte_firmware.h>\n #include <rte_string_fns.h>\n \n #include \"qede_ethdev.h\"\n@@ -127,51 +129,40 @@ static void qed_free_stream_mem(struct ecore_dev *edev)\n #ifdef CONFIG_ECORE_BINARY_FW\n static int qed_load_firmware_data(struct ecore_dev *edev)\n {\n-\tint fd;\n-\tstruct stat st;\n \tconst char *fw = RTE_LIBRTE_QEDE_FW;\n+\tvoid *buf;\n+\tsize_t bufsz;\n+\tint ret;\n \n \tif (strcmp(fw, \"\") == 0)\n \t\tstrcpy(qede_fw_file, QEDE_DEFAULT_FIRMWARE);\n \telse\n \t\tstrcpy(qede_fw_file, fw);\n \n-\tfd = open(qede_fw_file, O_RDONLY);\n-\tif (fd < 0) {\n-\t\tDP_ERR(edev, \"Can't open firmware file\\n\");\n-\t\treturn -ENOENT;\n-\t}\n-\n-\tif (fstat(fd, &st) < 0) {\n-\t\tDP_ERR(edev, \"Can't stat firmware file\\n\");\n-\t\tclose(fd);\n+\tif (rte_firmware_read(qede_fw_file, &buf, &bufsz) < 0) {\n+\t\tDP_ERR(edev, \"Can't read firmware data: %s\\n\", qede_fw_file);\n \t\treturn -1;\n \t}\n \n-\tedev->firmware = rte_zmalloc(\"qede_fw\", st.st_size,\n-\t\t\t\t    RTE_CACHE_LINE_SIZE);\n+\tedev->firmware = rte_zmalloc(\"qede_fw\", bufsz, RTE_CACHE_LINE_SIZE);\n \tif (!edev->firmware) {\n \t\tDP_ERR(edev, \"Can't allocate memory for firmware\\n\");\n-\t\tclose(fd);\n-\t\treturn -ENOMEM;\n+\t\tret = -ENOMEM;\n+\t\tgoto out;\n \t}\n \n-\tif (read(fd, edev->firmware, st.st_size) != st.st_size) {\n-\t\tDP_ERR(edev, \"Can't read firmware data\\n\");\n-\t\tclose(fd);\n-\t\treturn -1;\n-\t}\n-\n-\tedev->fw_len = st.st_size;\n+\tmemcpy(edev->firmware, buf, bufsz);\n+\tedev->fw_len = bufsz;\n \tif (edev->fw_len < 104) {\n \t\tDP_ERR(edev, \"Invalid fw size: %\" PRIu64 \"\\n\",\n \t\t\t  edev->fw_len);\n-\t\tclose(fd);\n-\t\treturn -EINVAL;\n+\t\tret = -EINVAL;\n+\t\tgoto out;\n \t}\n-\n-\tclose(fd);\n-\treturn 0;\n+\tret = 0;\n+out:\n+\tfree(buf);\n+\treturn ret;\n }\n #endif\n \ndiff --git a/lib/eal/include/rte_firmware.h b/lib/eal/include/rte_firmware.h\nnew file mode 100644\nindex 0000000000..3389e60ca0\n--- /dev/null\n+++ b/lib/eal/include/rte_firmware.h\n@@ -0,0 +1,32 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Red Hat, Inc.\n+ */\n+\n+#ifndef __RTE_FIRMWARE_H__\n+#define __RTE_FIRMWARE_H__\n+\n+#include <sys/types.h>\n+\n+#include <rte_compat.h>\n+\n+/**\n+ * Load a firmware in a dynamically allocated buffer, dealing with compressed\n+ * files if libarchive is available.\n+ *\n+ * @param[in] name\n+ *      Firmware filename to load.\n+ * @param[out] buf\n+ *      Buffer allocated by this function. If this function succeeds, the\n+ *      caller is responsible for calling free() on this buffer.\n+ * @param[out] bufsz\n+ *      Size of the data in the buffer.\n+ *\n+ * @return\n+ *      0 if successful.\n+ *      Negative otherwise, buf and bufsize contents are invalid.\n+ */\n+__rte_internal\n+int\n+rte_firmware_read(const char *name, void **buf, size_t *bufsz);\n+\n+#endif\ndiff --git a/lib/eal/unix/eal_firmware.c b/lib/eal/unix/eal_firmware.c\nnew file mode 100644\nindex 0000000000..494cd5f058\n--- /dev/null\n+++ b/lib/eal/unix/eal_firmware.c\n@@ -0,0 +1,149 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Red Hat, Inc.\n+ */\n+\n+#ifdef RTE_HAS_LIBARCHIVE\n+#include <archive.h>\n+#endif\n+#include <fcntl.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <unistd.h>\n+\n+#include <rte_common.h>\n+#include <rte_firmware.h>\n+#include <rte_log.h>\n+\n+#ifdef RTE_HAS_LIBARCHIVE\n+\n+struct firmware_read_ctx {\n+\tstruct archive *a;\n+};\n+\n+static int\n+firmware_open(struct firmware_read_ctx *ctx, const char *name, size_t blocksize)\n+{\n+\tstruct archive_entry *e;\n+\n+\tctx->a = archive_read_new();\n+\tif (ctx->a == NULL)\n+\t\treturn -1;\n+\tif (archive_read_support_format_raw(ctx->a) != ARCHIVE_OK ||\n+\t\t\tarchive_read_support_filter_xz(ctx->a) != ARCHIVE_OK ||\n+\t\t\tarchive_read_open_filename(ctx->a, name, blocksize) != ARCHIVE_OK ||\n+\t\t\tarchive_read_next_header(ctx->a, &e) != ARCHIVE_OK) {\n+\t\tarchive_read_free(ctx->a);\n+\t\tctx->a = NULL;\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+static ssize_t\n+firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count)\n+{\n+\treturn archive_read_data(ctx->a, buf, count);\n+}\n+\n+static void\n+firmware_close(struct firmware_read_ctx *ctx)\n+{\n+\tarchive_read_free(ctx->a);\n+\tctx->a = NULL;\n+}\n+\n+#else /* !RTE_HAS_LIBARCHIVE */\n+\n+struct firmware_read_ctx {\n+\tint fd;\n+};\n+\n+static int\n+firmware_open(struct firmware_read_ctx *ctx, const char *name,\n+\t__rte_unused size_t blocksize)\n+{\n+\tctx->fd = open(name, O_RDONLY);\n+\tif (ctx->fd < 0)\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n+static ssize_t\n+firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count)\n+{\n+\treturn read(ctx->fd, buf, count);\n+}\n+\n+static void\n+firmware_close(struct firmware_read_ctx *ctx)\n+{\n+\tclose(ctx->fd);\n+\tctx->fd = -1;\n+}\n+\n+#endif /* !RTE_HAS_LIBARCHIVE */\n+\n+static int\n+firmware_read(const char *name, void **buf, size_t *bufsz)\n+{\n+\tconst size_t blocksize = 4096;\n+\tstruct firmware_read_ctx ctx;\n+\tint ret = -1;\n+\tint err;\n+\n+\t*buf = NULL;\n+\t*bufsz = 0;\n+\n+\tif (firmware_open(&ctx, name, blocksize) < 0)\n+\t\treturn -1;\n+\n+\tdo {\n+\t\tvoid *tmp;\n+\n+\t\ttmp = realloc(*buf, *bufsz + blocksize);\n+\t\tif (tmp == NULL) {\n+\t\t\tfree(*buf);\n+\t\t\t*buf = NULL;\n+\t\t\t*bufsz = 0;\n+\t\t\tgoto out;\n+\t\t}\n+\t\t*buf = tmp;\n+\n+\t\terr = firmware_read_block(&ctx, RTE_PTR_ADD(*buf, *bufsz), blocksize);\n+\t\tif (err < 0) {\n+\t\t\tfree(*buf);\n+\t\t\t*buf = NULL;\n+\t\t\t*bufsz = 0;\n+\t\t\tgoto out;\n+\t\t}\n+\t\t*bufsz += err;\n+\n+\t} while (err != 0);\n+\n+\tret = 0;\n+out:\n+\tfirmware_close(&ctx);\n+\treturn ret;\n+}\n+\n+int\n+rte_firmware_read(const char *name, void **buf, size_t *bufsz)\n+{\n+\tchar path[PATH_MAX];\n+\tint ret;\n+\n+\tret = firmware_read(name, buf, bufsz);\n+\tif (ret < 0) {\n+\t\tsnprintf(path, sizeof(path), \"%s.xz\", name);\n+\t\tpath[PATH_MAX - 1] = '\\0';\n+#ifndef RTE_HAS_LIBARCHIVE\n+\t\tif (access(path, F_OK) == 0) {\n+\t\t\tRTE_LOG(WARNING, EAL, \"libarchive not available, %s cannot be decompressed\\n\",\n+\t\t\t\tpath);\n+\t\t}\n+#else\n+\t\tret = firmware_read(path, buf, bufsz);\n+#endif\n+\t}\n+\treturn ret;\n+}\ndiff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build\nindex dc711b4240..e3ecd3e956 100644\n--- a/lib/eal/unix/meson.build\n+++ b/lib/eal/unix/meson.build\n@@ -5,5 +5,6 @@ sources += files(\n         'eal_file.c',\n         'eal_unix_memory.c',\n         'eal_unix_timer.c',\n+        'eal_firmware.c',\n         'rte_thread.c',\n )\ndiff --git a/lib/eal/version.map b/lib/eal/version.map\nindex fe5c3dac98..2df65c6903 100644\n--- a/lib/eal/version.map\n+++ b/lib/eal/version.map\n@@ -428,6 +428,7 @@ EXPERIMENTAL {\n INTERNAL {\n \tglobal:\n \n+\trte_firmware_read;\n \trte_mem_lock;\n \trte_mem_map;\n \trte_mem_page_size;\ndiff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c\nindex 8483f6b02c..6fe2bdd282 100644\n--- a/lib/eal/windows/eal.c\n+++ b/lib/eal/windows/eal.c\n@@ -21,6 +21,7 @@\n #include <eal_private.h>\n #include <rte_service_component.h>\n #include <rte_vfio.h>\n+#include <rte_firmware.h>\n \n #include \"eal_hugepages.h\"\n #include \"eal_trace.h\"\n@@ -465,3 +466,11 @@ rte_vfio_container_dma_unmap(__rte_unused int container_fd,\n {\n \treturn -1;\n }\n+\n+int\n+rte_firmware_read(__rte_unused const char *name,\n+\t\t\t__rte_unused void **buf,\n+\t\t\t__rte_unused size_t *bufsz)\n+{\n+\treturn -1;\n+}\n",
    "prefixes": [
        "v3",
        "2/2"
    ]
}