From patchwork Wed Sep 29 23:00:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 12526913 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DFF68C433F5 for ; Wed, 29 Sep 2021 23:00:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C242E61507 for ; Wed, 29 Sep 2021 23:00:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347356AbhI2XCN (ORCPT ); Wed, 29 Sep 2021 19:02:13 -0400 Received: from mga09.intel.com ([134.134.136.24]:47376 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347357AbhI2XCM (ORCPT ); Wed, 29 Sep 2021 19:02:12 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10122"; a="225097212" X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="225097212" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:30 -0700 X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="617768023" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.255.230.76]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:29 -0700 From: Russ Weight To: mdf@kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v17 1/5] fpga: image-load: fpga image load framework Date: Wed, 29 Sep 2021 16:00:21 -0700 Message-Id: <20210929230025.68961-2-russell.h.weight@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210929230025.68961-1-russell.h.weight@intel.com> References: <20210929230025.68961-1-russell.h.weight@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org The FPGA Image Load framework provides an API to transfer update files to an FPGA device. Image files are self-describing. They could contain FPGA images, BMC images, Root Entry Hashes, or other device specific files. It is up to the lower level device driver and the target device to authenticate and disposition the file data. Signed-off-by: Russ Weight --- v17: - No change v16: - Shift from "Driver" terminology to "Framework" in comments and documentation - Rename lops to ops for structure member and local variables - Change device name from "fpga_image%d" to "fpga_image_load%d" v15: - Compare to previous patch: [PATCH v14 1/6] fpga: sec-mgr: fpga security manager class driver - Changed file, symbol, and config names to reflect the new driver name - Rewrote documentation. The documentation will be added to in later patches. - Removed signed-off/reviewed-by tags v14: - Updated copyright to 2021 - Removed the name sysfs entry - Removed MAINTAINERS reference to Documentation/ABI/testing/sysfs-class-fpga-sec-mgr - Use xa_alloc() instead of ida_simple_get() - Rename dev to parent for parent devices - Remove fpga_sec_mgr_create(), devm_fpga_sec_mgr_create(), and fpga_sec_mgr_free() functions and update the fpga_sec_mgr_register() function to both create and register a new security manager. - Populate the fpga_sec_mgr_dev_release() function. v13: - No change v12: - Updated Date and KernelVersion fields in ABI documentation v11: - No change v10: - Rebased to 5.12-rc2 next - Updated Date and KernelVersion in ABI documentation v9: - Updated Date and KernelVersion in ABI documentation v8: - Fixed grammatical error in Documentation/fpga/fpga-sec-mgr.rst v7: - Changed Date in documentation file to December 2020 v6: - Removed sysfs support and documentation for the display of the flash count, root entry hashes, and code-signing-key cancelation vectors. v5: - Added the devm_fpga_sec_mgr_unregister() function, following recent changes to the fpga_manager() implementation. - Changed some *_show() functions to use sysfs_emit() instead of sprintf( v4: - Changed from "Intel FPGA Security Manager" to FPGA Security Manager" and removed unnecessary references to "Intel". - Changed: iops -> sops, imgr -> smgr, IFPGA_ -> FPGA_, ifpga_ to fpga_ v3: - Modified sysfs handler check in check_sysfs_handler() to make it more readable. v2: - Bumped documentation dates and versions - Added Documentation/fpga/ifpga-sec-mgr.rst - Removed references to bmc_flash_count & smbus_flash_count (not supported) - Split ifpga_sec_mgr_register() into create() and register() functions - Added devm_ifpga_sec_mgr_create() - Removed typedefs for imgr ops --- Documentation/fpga/fpga-image-load.rst | 10 ++ Documentation/fpga/index.rst | 1 + MAINTAINERS | 8 ++ drivers/fpga/Kconfig | 10 ++ drivers/fpga/Makefile | 3 + drivers/fpga/fpga-image-load.c | 125 +++++++++++++++++++++++++ include/linux/fpga/fpga-image-load.h | 35 +++++++ 7 files changed, 192 insertions(+) create mode 100644 Documentation/fpga/fpga-image-load.rst create mode 100644 drivers/fpga/fpga-image-load.c create mode 100644 include/linux/fpga/fpga-image-load.h diff --git a/Documentation/fpga/fpga-image-load.rst b/Documentation/fpga/fpga-image-load.rst new file mode 100644 index 000000000000..dda9283ef1c7 --- /dev/null +++ b/Documentation/fpga/fpga-image-load.rst @@ -0,0 +1,10 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================= +FPGA Image Load Framework +========================= + +The FPGA Image Load framework provides a common API for user-space +tools to manage image uploads to FPGA devices. Device drivers that +instantiate the FPGA Image Load framework will interact with the +target device to transfer and authenticate the image data. diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst index f80f95667ca2..85d25fb22c08 100644 --- a/Documentation/fpga/index.rst +++ b/Documentation/fpga/index.rst @@ -8,6 +8,7 @@ fpga :maxdepth: 1 dfl + fpga-image-load .. only:: subproject and html diff --git a/MAINTAINERS b/MAINTAINERS index 437247390737..a99622eebbff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7408,6 +7408,14 @@ F: Documentation/fpga/ F: drivers/fpga/ F: include/linux/fpga/ +FPGA IMAGE UPLOAD DRIVERS +M: Russ Weight +L: linux-fpga@vger.kernel.org +S: Maintained +F: Documentation/fpga/fpga-image-load.rst +F: drivers/fpga/fpga-image-load.c +F: include/linux/fpga/fpga-image-load.h + FPU EMULATOR M: Bill Metzenthen S: Maintained diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 991b3f361ec9..fbd580121661 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -243,4 +243,14 @@ config FPGA_MGR_VERSAL_FPGA configure the programmable logic(PL). To compile this as a module, choose M here. + +config FPGA_IMAGE_LOAD + tristate "FPGA Image Load Framework" + help + The FPGA Image Load framework presents a common user API for + uploading an image file to an FPGA device. The image file is + expected to be self-describing. It is up to the lower level + device driver and/or the device itself to authenticate and + disposition the image data. + endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 0bff783d1b61..adf228ee4f5e 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -22,6 +22,9 @@ obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA) += versal-fpga.o obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o +# FPGA Image Load Framework +obj-$(CONFIG_FPGA_IMAGE_LOAD) += fpga-image-load.o + # FPGA Bridge Drivers obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o diff --git a/drivers/fpga/fpga-image-load.c b/drivers/fpga/fpga-image-load.c new file mode 100644 index 000000000000..799d18444f7c --- /dev/null +++ b/drivers/fpga/fpga-image-load.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FPGA Image Load Framework + * + * Copyright (C) 2019-2021 Intel Corporation, Inc. + */ + +#include +#include +#include +#include + +#define IMAGE_LOAD_XA_LIMIT XA_LIMIT(0, INT_MAX) +static DEFINE_XARRAY_ALLOC(fpga_image_load_xa); + +static struct class *fpga_image_load_class; + +#define to_image_load(d) container_of(d, struct fpga_image_load, dev) + +/** + * fpga_image_load_register - create and register an FPGA Image Load Device + * + * @parent: fpga image load device from pdev + * @ops: pointer to a structure of image load callback functions + * @priv: fpga image load private data + * + * Returns a struct fpga_image_load pointer on success, or ERR_PTR() on + * error. The caller of this function is responsible for calling + * fpga_image_load_unregister(). + */ +struct fpga_image_load * +fpga_image_load_register(struct device *parent, + const struct fpga_image_load_ops *ops, void *priv) +{ + struct fpga_image_load *imgld; + int ret; + + imgld = kzalloc(sizeof(*imgld), GFP_KERNEL); + if (!imgld) + return ERR_PTR(-ENOMEM); + + ret = xa_alloc(&fpga_image_load_xa, &imgld->dev.id, imgld, IMAGE_LOAD_XA_LIMIT, + GFP_KERNEL); + if (ret) + goto error_kfree; + + mutex_init(&imgld->lock); + + imgld->priv = priv; + imgld->ops = ops; + + imgld->dev.class = fpga_image_load_class; + imgld->dev.parent = parent; + + ret = dev_set_name(&imgld->dev, "fpga_image_load%d", imgld->dev.id); + if (ret) { + dev_err(parent, "Failed to set device name: fpga_image_load%d\n", + imgld->dev.id); + goto error_device; + } + + ret = device_register(&imgld->dev); + if (ret) { + put_device(&imgld->dev); + return ERR_PTR(ret); + } + + return imgld; + +error_device: + xa_erase(&fpga_image_load_xa, imgld->dev.id); + +error_kfree: + kfree(imgld); + + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(fpga_image_load_register); + +/** + * fpga_image_load_unregister - unregister an FPGA image load device + * + * @imgld: pointer to struct fpga_image_load + * + * This function is intended for use in the parent driver's remove() + * function. + */ +void fpga_image_load_unregister(struct fpga_image_load *imgld) +{ + device_unregister(&imgld->dev); +} +EXPORT_SYMBOL_GPL(fpga_image_load_unregister); + +static void fpga_image_load_dev_release(struct device *dev) +{ + struct fpga_image_load *imgld = to_image_load(dev); + + xa_erase(&fpga_image_load_xa, imgld->dev.id); + kfree(imgld); +} + +static int __init fpga_image_load_class_init(void) +{ + pr_info("FPGA Image Load Framework\n"); + + fpga_image_load_class = class_create(THIS_MODULE, "fpga_image_load"); + if (IS_ERR(fpga_image_load_class)) + return PTR_ERR(fpga_image_load_class); + + fpga_image_load_class->dev_release = fpga_image_load_dev_release; + + return 0; +} + +static void __exit fpga_image_load_class_exit(void) +{ + class_destroy(fpga_image_load_class); + WARN_ON(!xa_empty(&fpga_image_load_xa)); +} + +MODULE_DESCRIPTION("FPGA Image Load Framework"); +MODULE_LICENSE("GPL v2"); + +subsys_initcall(fpga_image_load_class_init); +module_exit(fpga_image_load_class_exit) diff --git a/include/linux/fpga/fpga-image-load.h b/include/linux/fpga/fpga-image-load.h new file mode 100644 index 000000000000..8b051c82ef5f --- /dev/null +++ b/include/linux/fpga/fpga-image-load.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for FPGA Image Load Framework + * + * Copyright (C) 2019-2021 Intel Corporation, Inc. + */ +#ifndef _LINUX_FPGA_IMAGE_LOAD_H +#define _LINUX_FPGA_IMAGE_LOAD_H + +#include +#include +#include + +struct fpga_image_load; + +/** + * struct fpga_image_load_ops - device specific operations + */ +struct fpga_image_load_ops { +}; + +struct fpga_image_load { + struct device dev; + const struct fpga_image_load_ops *ops; + struct mutex lock; /* protect data structure contents */ + void *priv; +}; + +struct fpga_image_load * +fpga_image_load_register(struct device *dev, + const struct fpga_image_load_ops *ops, void *priv); + +void fpga_image_load_unregister(struct fpga_image_load *imgld); + +#endif From patchwork Wed Sep 29 23:00:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 12526917 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AD58DC433EF for ; Wed, 29 Sep 2021 23:00:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8F79D61507 for ; Wed, 29 Sep 2021 23:00:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347373AbhI2XCQ (ORCPT ); Wed, 29 Sep 2021 19:02:16 -0400 Received: from mga09.intel.com ([134.134.136.24]:47376 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347361AbhI2XCN (ORCPT ); Wed, 29 Sep 2021 19:02:13 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10122"; a="225097216" X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="225097216" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:30 -0700 X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="617768030" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.255.230.76]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:30 -0700 From: Russ Weight To: mdf@kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v17 2/5] fpga: image-load: enable image uploads Date: Wed, 29 Sep 2021 16:00:22 -0700 Message-Id: <20210929230025.68961-3-russell.h.weight@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210929230025.68961-1-russell.h.weight@intel.com> References: <20210929230025.68961-1-russell.h.weight@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org Extend the FPGA Image Load framework to include IOCTL support (FPGA_IMAGE_LOAD_WRITE) for initiating an upload of an image to a device. The IOCTL will return immediately, and the update will begin in the context of a kernel worker thread. Signed-off-by: Russ Weight --- v17: - Minor documentation cleanup and references to cancellation are moved to a later patch. - We no longer send a "just in case" cancel on HW errors. The cleanup() op can and should be used to manage the HW state on an error. - Removed the FPGA_IMAGE_ERR_NONE macro in favor of returning zero. The constant name made sense when we were using enum data types, but is no longer necessary. - Changed the syntax of the write_blk() function and renamed it to write(). It now returns a positive size or a negative error number. - Changed the prepare() and write() ops to pass in elements of the fpga_image_load data structure instead of having the op functions access them directly via imgld. - Removed the default block size. The lower-level driver must choose a block size. - Changed work queue from system_unbound_wq to system_long_wq. - Removed calls to cond_resched(). The lower-level driver must manage any scheduler issues. - Use the cdev_set_parent() macro. v16: - Shift from "Driver" terminology to "Framework" in comments and documentation - Rename lops to ops for structure member and local variables - Change the write_blk() definition to pass in *blk_size (a pointer to a default block size of WRITE_BLOCK_SIZE=0x4000) and max_size (the the maximum block size to stay within the limit of the data buffer). The write_blk() op may use the default *blk_size or modify it to a more optimal number for the given device, subject to the max_size limit. - All enum values for progress and errors are changed to macros, because they are included in the uapi header. This is done to maintain consistency amongst the DFL related IOCTL header files. All references to the enum types are changed to u32. - Bail out early in fpga_image_do_load() if imgld->driver_unload is true. - Add a call to cond_resched() in the write_blk() loop to ensure that we yield to higher priority tasks during long data transfers. - Switch to the system_unbound_wq to enable calls to cond_resched(). - Switch from test_and_set_bit() to atomic_cmpxchg() to manage imgld->opened. - Change fpga_image_load_release() to block until the image upload is complete. - Remove the completion object, imgld->update_done, in favor of calling flush_work(&imgld->work); v15: - Compare to previous patch: [PATCH v14 2/6] fpga: sec-mgr: enable secure updates - Changed file, symbol, and config names to reflect the new driver name - Removed update/filename sysfs file and added the FPGA_IMAGE_LOAD_WRITE IOCTL for writing the image data to the FPGA card. The driver no longer uses the request_firmware framework. - Fixed some error return values in fpga_image_load_register() - Removed signed-off/reviewed-by tags v14: - Added MAINTAINERS reference for Documentation/ABI/testing/sysfs-class-fpga-sec-mgr - Updated ABI documentation date and kernel version - Updated copyright to 2021 v13: - Change "if (count == 0 || " to "if (!count || " - Improve error message: "Attempt to register without all required ops\n" v12: - Updated Date and KernelVersion fields in ABI documentation - Removed size parameter from write_blk() op - it is now up to the lower-level driver to determine the appropriate size and to update smgr->remaining_size accordingly. v11: - Fixed a spelling error in a comment - Initialize smgr->err_code and smgr->progress explicitly in fpga_sec_mgr_create() instead of accepting the default 0 value. v10: - Rebased to 5.12-rc2 next - Updated Date and KernelVersion in ABI documentation v9: - Updated Date and KernelVersion in ABI documentation v8: - No change v7: - Changed Date in documentation file to December 2020 - Changed filename_store() to use kmemdup_nul() instead of kstrndup() and changed the count to not assume a line-return. v6: - Changed "security update" to "secure update" in commit message v5: - When checking the return values for functions of type enum fpga_sec_err err_code, test for FPGA_SEC_ERR_NONE instead of 0 v4: - Changed from "Intel FPGA Security Manager" to FPGA Security Manager" and removed unnecessary references to "Intel". - Changed: iops -> sops, imgr -> smgr, IFPGA_ -> FPGA_, ifpga_ to fpga_ v3: - Removed unnecessary "goto done" - Added a comment to explain imgr->driver_unload in ifpga_sec_mgr_unregister() v2: - Bumped documentation date and version - Removed explicit value assignments in enums - Other minor code cleanup per review comments --- Documentation/fpga/fpga-image-load.rst | 25 ++- MAINTAINERS | 1 + drivers/fpga/fpga-image-load.c | 217 ++++++++++++++++++++++++- include/linux/fpga/fpga-image-load.h | 27 +++ include/uapi/linux/fpga-image-load.h | 53 ++++++ 5 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 include/uapi/linux/fpga-image-load.h diff --git a/Documentation/fpga/fpga-image-load.rst b/Documentation/fpga/fpga-image-load.rst index dda9283ef1c7..f6b0e1624a05 100644 --- a/Documentation/fpga/fpga-image-load.rst +++ b/Documentation/fpga/fpga-image-load.rst @@ -7,4 +7,27 @@ FPGA Image Load Framework The FPGA Image Load framework provides a common API for user-space tools to manage image uploads to FPGA devices. Device drivers that instantiate the FPGA Image Load framework will interact with the -target device to transfer and authenticate the image data. +target device to transfer and authenticate the image data. Image uploads +are processed in the context of a kernel worker thread. + +User API +======== + +open +---- + +An fpga_image_load device is opened exclusively to control an image upload. +The device must remain open throughout the duration of the image upload. +An attempt to close the device while an upload is in progress will block +until the image upload is complete. + +ioctl +----- + +FPGA_IMAGE_LOAD_WRITE: + +Start an image upload with the provided image buffer. This IOCTL returns +immediately after starting a kernel worker thread to process the image +upload which could take as long as 40 minutes depending on the actual +device being updated. This is an exclusive operation; an attempt to start +concurrent image uploads for the same device will fail with EBUSY. diff --git a/MAINTAINERS b/MAINTAINERS index a99622eebbff..e3b5c555ecbd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7415,6 +7415,7 @@ S: Maintained F: Documentation/fpga/fpga-image-load.rst F: drivers/fpga/fpga-image-load.c F: include/linux/fpga/fpga-image-load.h +F: include/uapi/linux/fpga-image-load.h FPU EMULATOR M: Bill Metzenthen diff --git a/drivers/fpga/fpga-image-load.c b/drivers/fpga/fpga-image-load.c index 799d18444f7c..4c2571e3b26f 100644 --- a/drivers/fpga/fpga-image-load.c +++ b/drivers/fpga/fpga-image-load.c @@ -5,18 +5,190 @@ * Copyright (C) 2019-2021 Intel Corporation, Inc. */ +#include #include +#include +#include #include #include +#include #include #define IMAGE_LOAD_XA_LIMIT XA_LIMIT(0, INT_MAX) static DEFINE_XARRAY_ALLOC(fpga_image_load_xa); static struct class *fpga_image_load_class; +static dev_t fpga_image_devt; #define to_image_load(d) container_of(d, struct fpga_image_load, dev) +static void fpga_image_prog_complete(struct fpga_image_load *imgld) +{ + mutex_lock(&imgld->lock); + imgld->progress = FPGA_IMAGE_PROG_IDLE; + mutex_unlock(&imgld->lock); +} + +static void fpga_image_do_load(struct work_struct *work) +{ + struct fpga_image_load *imgld; + s32 ret, offset = 0; + + imgld = container_of(work, struct fpga_image_load, work); + + if (imgld->driver_unload) { + imgld->err_code = FPGA_IMAGE_ERR_CANCELED; + goto idle_exit; + } + + get_device(&imgld->dev); + if (!try_module_get(imgld->dev.parent->driver->owner)) { + imgld->err_code = FPGA_IMAGE_ERR_BUSY; + goto putdev_exit; + } + + imgld->progress = FPGA_IMAGE_PROG_PREPARING; + ret = imgld->ops->prepare(imgld, imgld->data, imgld->remaining_size); + if (ret) { + imgld->err_code = ret; + goto modput_exit; + } + + imgld->progress = FPGA_IMAGE_PROG_WRITING; + while (imgld->remaining_size) { + ret = imgld->ops->write(imgld, imgld->data, offset, + imgld->remaining_size); + if (ret <= 0) { + if (!ret) { + dev_warn(&imgld->dev, + "write-op wrote zero data\n"); + ret = -FPGA_IMAGE_ERR_RW_ERROR; + } + imgld->err_code = -ret; + goto done; + } + + imgld->remaining_size -= ret; + offset += ret; + } + + imgld->progress = FPGA_IMAGE_PROG_PROGRAMMING; + ret = imgld->ops->poll_complete(imgld); + if (ret) + imgld->err_code = ret; + +done: + if (imgld->ops->cleanup) + imgld->ops->cleanup(imgld); + +modput_exit: + module_put(imgld->dev.parent->driver->owner); + +putdev_exit: + put_device(&imgld->dev); + +idle_exit: + /* + * Note: imgld->remaining_size is left unmodified here to provide + * additional information on errors. It will be reinitialized when + * the next image load begins. + */ + vfree(imgld->data); + imgld->data = NULL; + fpga_image_prog_complete(imgld); +} + +static int fpga_image_load_ioctl_write(struct fpga_image_load *imgld, + unsigned long arg) +{ + struct fpga_image_write wb; + unsigned long minsz; + u8 *buf; + + if (imgld->driver_unload || imgld->progress != FPGA_IMAGE_PROG_IDLE) + return -EBUSY; + + minsz = offsetofend(struct fpga_image_write, buf); + if (copy_from_user(&wb, (void __user *)arg, minsz)) + return -EFAULT; + + if (wb.flags) + return -EINVAL; + + buf = vzalloc(wb.size); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, u64_to_user_ptr(wb.buf), wb.size)) { + vfree(buf); + return -EFAULT; + } + + imgld->data = buf; + imgld->remaining_size = wb.size; + imgld->err_code = 0; + imgld->progress = FPGA_IMAGE_PROG_STARTING; + queue_work(system_long_wq, &imgld->work); + + return 0; +} + +static long fpga_image_load_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct fpga_image_load *imgld = filp->private_data; + int ret = -ENOTTY; + + switch (cmd) { + case FPGA_IMAGE_LOAD_WRITE: + mutex_lock(&imgld->lock); + ret = fpga_image_load_ioctl_write(imgld, arg); + mutex_unlock(&imgld->lock); + break; + } + + return ret; +} + +static int fpga_image_load_open(struct inode *inode, struct file *filp) +{ + struct fpga_image_load *imgld = container_of(inode->i_cdev, + struct fpga_image_load, cdev); + + if (atomic_cmpxchg(&imgld->opened, 0, 1)) + return -EBUSY; + + filp->private_data = imgld; + + return 0; +} + +static int fpga_image_load_release(struct inode *inode, struct file *filp) +{ + struct fpga_image_load *imgld = filp->private_data; + + mutex_lock(&imgld->lock); + if (imgld->progress == FPGA_IMAGE_PROG_IDLE) { + mutex_unlock(&imgld->lock); + goto close_exit; + } + + mutex_unlock(&imgld->lock); + flush_work(&imgld->work); + +close_exit: + atomic_set(&imgld->opened, 0); + + return 0; +} + +static const struct file_operations fpga_image_load_fops = { + .owner = THIS_MODULE, + .open = fpga_image_load_open, + .release = fpga_image_load_release, + .unlocked_ioctl = fpga_image_load_ioctl, +}; + /** * fpga_image_load_register - create and register an FPGA Image Load Device * @@ -35,6 +207,11 @@ fpga_image_load_register(struct device *parent, struct fpga_image_load *imgld; int ret; + if (!ops || !ops->prepare || !ops->write || !ops->poll_complete) { + dev_err(parent, "Attempt to register without all required ops\n"); + return ERR_PTR(-ENOMEM); + } + imgld = kzalloc(sizeof(*imgld), GFP_KERNEL); if (!imgld) return ERR_PTR(-ENOMEM); @@ -48,9 +225,13 @@ fpga_image_load_register(struct device *parent, imgld->priv = priv; imgld->ops = ops; + imgld->err_code = 0; + imgld->progress = FPGA_IMAGE_PROG_IDLE; + INIT_WORK(&imgld->work, fpga_image_do_load); imgld->dev.class = fpga_image_load_class; imgld->dev.parent = parent; + imgld->dev.devt = MKDEV(MAJOR(fpga_image_devt), imgld->dev.id); ret = dev_set_name(&imgld->dev, "fpga_image_load%d", imgld->dev.id); if (ret) { @@ -65,6 +246,16 @@ fpga_image_load_register(struct device *parent, return ERR_PTR(ret); } + cdev_init(&imgld->cdev, &fpga_image_load_fops); + imgld->cdev.owner = parent->driver->owner; + cdev_set_parent(&imgld->cdev, &imgld->dev.kobj); + + ret = cdev_add(&imgld->cdev, imgld->dev.devt, 1); + if (ret) { + put_device(&imgld->dev); + return ERR_PTR(ret); + } + return imgld; error_device: @@ -83,10 +274,23 @@ EXPORT_SYMBOL_GPL(fpga_image_load_register); * @imgld: pointer to struct fpga_image_load * * This function is intended for use in the parent driver's remove() - * function. + * function. The driver_unload flag prevents new updates from starting + * once the unregister process has begun. */ void fpga_image_load_unregister(struct fpga_image_load *imgld) { + mutex_lock(&imgld->lock); + imgld->driver_unload = true; + if (imgld->progress == FPGA_IMAGE_PROG_IDLE) { + mutex_unlock(&imgld->lock); + goto unregister; + } + + mutex_unlock(&imgld->lock); + flush_work(&imgld->work); + +unregister: + cdev_del(&imgld->cdev); device_unregister(&imgld->dev); } EXPORT_SYMBOL_GPL(fpga_image_load_unregister); @@ -101,19 +305,30 @@ static void fpga_image_load_dev_release(struct device *dev) static int __init fpga_image_load_class_init(void) { + int ret; pr_info("FPGA Image Load Framework\n"); fpga_image_load_class = class_create(THIS_MODULE, "fpga_image_load"); if (IS_ERR(fpga_image_load_class)) return PTR_ERR(fpga_image_load_class); + ret = alloc_chrdev_region(&fpga_image_devt, 0, MINORMASK, + "fpga_image_load"); + if (ret) + goto exit_destroy_class; + fpga_image_load_class->dev_release = fpga_image_load_dev_release; return 0; + +exit_destroy_class: + class_destroy(fpga_image_load_class); + return ret; } static void __exit fpga_image_load_class_exit(void) { + unregister_chrdev_region(fpga_image_devt, MINORMASK); class_destroy(fpga_image_load_class); WARN_ON(!xa_empty(&fpga_image_load_xa)); } diff --git a/include/linux/fpga/fpga-image-load.h b/include/linux/fpga/fpga-image-load.h index 8b051c82ef5f..7b445f489644 100644 --- a/include/linux/fpga/fpga-image-load.h +++ b/include/linux/fpga/fpga-image-load.h @@ -7,22 +7,49 @@ #ifndef _LINUX_FPGA_IMAGE_LOAD_H #define _LINUX_FPGA_IMAGE_LOAD_H +#include #include #include #include +#include struct fpga_image_load; /** * struct fpga_image_load_ops - device specific operations + * @prepare: Required: Prepare secure update + * @write: Required: The write() op receives the remaining + * size to be written and must return the actual + * size written or a negative error code. The write() + * op will be called repeatedly until all data is + * written. + * @poll_complete: Required: Check for the completion of the + * HW authentication/programming process. + * @cleanup: Optional: Complements the prepare() + * function and is called at the completion + * of the update, whether success or failure, + * if the prepare function succeeded. */ struct fpga_image_load_ops { + u32 (*prepare)(struct fpga_image_load *imgld, const u8 *data, u32 size); + s32 (*write)(struct fpga_image_load *imgld, const u8 *data, + u32 offset, u32 size); + u32 (*poll_complete)(struct fpga_image_load *imgld); + void (*cleanup)(struct fpga_image_load *imgld); }; struct fpga_image_load { struct device dev; + struct cdev cdev; const struct fpga_image_load_ops *ops; struct mutex lock; /* protect data structure contents */ + atomic_t opened; + struct work_struct work; + const u8 *data; /* pointer to update data */ + u32 remaining_size; /* size remaining to transfer */ + u32 progress; + u32 err_code; /* image load error code */ + bool driver_unload; void *priv; }; diff --git a/include/uapi/linux/fpga-image-load.h b/include/uapi/linux/fpga-image-load.h new file mode 100644 index 000000000000..20eae3bb10d8 --- /dev/null +++ b/include/uapi/linux/fpga-image-load.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Header File for FPGA Image Load User API + * + * Copyright (C) 2019-2021 Intel Corporation, Inc. + * + */ + +#ifndef _UAPI_LINUX_FPGA_IMAGE_LOAD_H +#define _UAPI_LINUX_FPGA_IMAGE_LOAD_H + +#include +#include + +#define FPGA_IMAGE_LOAD_MAGIC 0xB9 + +/* Image load progress codes */ +#define FPGA_IMAGE_PROG_IDLE 0 +#define FPGA_IMAGE_PROG_STARTING 1 +#define FPGA_IMAGE_PROG_PREPARING 2 +#define FPGA_IMAGE_PROG_WRITING 3 +#define FPGA_IMAGE_PROG_PROGRAMMING 4 +#define FPGA_IMAGE_PROG_MAX 5 + +/* Image error progress codes */ +#define FPGA_IMAGE_ERR_HW_ERROR 1 +#define FPGA_IMAGE_ERR_TIMEOUT 2 +#define FPGA_IMAGE_ERR_CANCELED 3 +#define FPGA_IMAGE_ERR_BUSY 4 +#define FPGA_IMAGE_ERR_INVALID_SIZE 5 +#define FPGA_IMAGE_ERR_RW_ERROR 6 +#define FPGA_IMAGE_ERR_WEAROUT 7 +#define FPGA_IMAGE_ERR_MAX 8 + +/** + * FPGA_IMAGE_LOAD_WRITE - _IOW(FPGA_IMAGE_LOAD_MAGIC, 0, + * struct fpga_image_write) + * + * Upload a data buffer to the target device. The user must provide the + * data buffer and size. + * + * Return: 0 on success, -errno on failure. + */ +struct fpga_image_write { + /* Input */ + __u32 flags; /* Zero for now */ + __u32 size; /* Data size (in bytes) to be written */ + __u64 buf; /* User space address of source data */ +}; + +#define FPGA_IMAGE_LOAD_WRITE _IOW(FPGA_IMAGE_LOAD_MAGIC, 0, struct fpga_image_write) + +#endif /* _UAPI_LINUX_FPGA_IMAGE_LOAD_H */ From patchwork Wed Sep 29 23:00:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 12526915 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1F151C433FE for ; Wed, 29 Sep 2021 23:00:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 07E4561504 for ; Wed, 29 Sep 2021 23:00:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347156AbhI2XCU (ORCPT ); Wed, 29 Sep 2021 19:02:20 -0400 Received: from mga09.intel.com ([134.134.136.24]:47376 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347367AbhI2XCO (ORCPT ); Wed, 29 Sep 2021 19:02:14 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10122"; a="225097217" X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="225097217" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:31 -0700 X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="617768036" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.255.230.76]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:30 -0700 From: Russ Weight To: mdf@kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v17 3/5] fpga: image-load: signal eventfd when complete Date: Wed, 29 Sep 2021 16:00:23 -0700 Message-Id: <20210929230025.68961-4-russell.h.weight@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210929230025.68961-1-russell.h.weight@intel.com> References: <20210929230025.68961-1-russell.h.weight@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org Amend the FPGA_IMAGE_LOAD_WRITE IOCTL implementation to include an eventfd file descriptor as a parameter. The eventfd will be triggered when the image upload completes. Signed-off-by: Russ Weight --- v17: - More documentation cleanup. v16: - Some cleanup of documentation for the FPGA_IMAGE_LOAD_WRITE IOCTL. v15: - This patch is new to the patch-set, and adds an eventfd to the FPGA_IMAGE_LOAD_WRITE IOCTL. The eventfd is signalled upon completion of an update. --- Documentation/fpga/fpga-image-load.rst | 8 +++++--- drivers/fpga/fpga-image-load.c | 22 ++++++++++++++++++++-- include/linux/fpga/fpga-image-load.h | 2 ++ include/uapi/linux/fpga-image-load.h | 3 ++- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/Documentation/fpga/fpga-image-load.rst b/Documentation/fpga/fpga-image-load.rst index f6b0e1624a05..487b5466f67c 100644 --- a/Documentation/fpga/fpga-image-load.rst +++ b/Documentation/fpga/fpga-image-load.rst @@ -28,6 +28,8 @@ FPGA_IMAGE_LOAD_WRITE: Start an image upload with the provided image buffer. This IOCTL returns immediately after starting a kernel worker thread to process the image -upload which could take as long as 40 minutes depending on the actual -device being updated. This is an exclusive operation; an attempt to start -concurrent image uploads for the same device will fail with EBUSY. +upload which could take as long as 40 minutes depending on the actual device +being updated. This is an exclusive operation; an attempt to start +concurrent image uploads for the same device will fail with EBUSY. An +eventfd file descriptor parameter is provided to this IOCTL. It will be +signalled at the completion of the image upload. diff --git a/drivers/fpga/fpga-image-load.c b/drivers/fpga/fpga-image-load.c index 4c2571e3b26f..f04dfc71c190 100644 --- a/drivers/fpga/fpga-image-load.c +++ b/drivers/fpga/fpga-image-load.c @@ -26,6 +26,7 @@ static void fpga_image_prog_complete(struct fpga_image_load *imgld) { mutex_lock(&imgld->lock); imgld->progress = FPGA_IMAGE_PROG_IDLE; + eventfd_signal(imgld->finished, 1); mutex_unlock(&imgld->lock); } @@ -96,6 +97,8 @@ static void fpga_image_do_load(struct work_struct *work) vfree(imgld->data); imgld->data = NULL; fpga_image_prog_complete(imgld); + eventfd_ctx_put(imgld->finished); + imgld->finished = NULL; } static int fpga_image_load_ioctl_write(struct fpga_image_load *imgld, @@ -103,6 +106,7 @@ static int fpga_image_load_ioctl_write(struct fpga_image_load *imgld, { struct fpga_image_write wb; unsigned long minsz; + int ret; u8 *buf; if (imgld->driver_unload || imgld->progress != FPGA_IMAGE_PROG_IDLE) @@ -115,13 +119,23 @@ static int fpga_image_load_ioctl_write(struct fpga_image_load *imgld, if (wb.flags) return -EINVAL; + if (wb.evtfd < 0) + return -EINVAL; + buf = vzalloc(wb.size); if (!buf) return -ENOMEM; if (copy_from_user(buf, u64_to_user_ptr(wb.buf), wb.size)) { - vfree(buf); - return -EFAULT; + ret = -EFAULT; + goto exit_free; + } + + imgld->finished = eventfd_ctx_fdget(wb.evtfd); + if (IS_ERR(imgld->finished)) { + ret = PTR_ERR(imgld->finished); + imgld->finished = NULL; + goto exit_free; } imgld->data = buf; @@ -131,6 +145,10 @@ static int fpga_image_load_ioctl_write(struct fpga_image_load *imgld, queue_work(system_long_wq, &imgld->work); return 0; + +exit_free: + vfree(buf); + return ret; } static long fpga_image_load_ioctl(struct file *filp, unsigned int cmd, diff --git a/include/linux/fpga/fpga-image-load.h b/include/linux/fpga/fpga-image-load.h index 7b445f489644..77b3c91ce073 100644 --- a/include/linux/fpga/fpga-image-load.h +++ b/include/linux/fpga/fpga-image-load.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,7 @@ struct fpga_image_load { u32 progress; u32 err_code; /* image load error code */ bool driver_unload; + struct eventfd_ctx *finished; void *priv; }; diff --git a/include/uapi/linux/fpga-image-load.h b/include/uapi/linux/fpga-image-load.h index 20eae3bb10d8..8d2d3db92e87 100644 --- a/include/uapi/linux/fpga-image-load.h +++ b/include/uapi/linux/fpga-image-load.h @@ -37,7 +37,7 @@ * struct fpga_image_write) * * Upload a data buffer to the target device. The user must provide the - * data buffer and size. + * data buffer, size, and an eventfd file descriptor. * * Return: 0 on success, -errno on failure. */ @@ -45,6 +45,7 @@ struct fpga_image_write { /* Input */ __u32 flags; /* Zero for now */ __u32 size; /* Data size (in bytes) to be written */ + __s32 evtfd; /* File descriptor for completion signal */ __u64 buf; /* User space address of source data */ }; From patchwork Wed Sep 29 23:00:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 12526921 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 95888C4332F for ; Wed, 29 Sep 2021 23:00:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7A10861507 for ; Wed, 29 Sep 2021 23:00:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347369AbhI2XCV (ORCPT ); Wed, 29 Sep 2021 19:02:21 -0400 Received: from mga09.intel.com ([134.134.136.24]:47379 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347368AbhI2XCO (ORCPT ); Wed, 29 Sep 2021 19:02:14 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10122"; a="225097219" X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="225097219" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:31 -0700 X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="617768040" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.255.230.76]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:31 -0700 From: Russ Weight To: mdf@kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v17 4/5] fpga: image-load: add status ioctl Date: Wed, 29 Sep 2021 16:00:24 -0700 Message-Id: <20210929230025.68961-5-russell.h.weight@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210929230025.68961-1-russell.h.weight@intel.com> References: <20210929230025.68961-1-russell.h.weight@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org Extend the FPGA Image Load framework to include an FPGA_IMAGE_LOAD_STATUS IOCTL that can be used to monitor the progress of an ongoing image upload. The status returned includes how much data remains to be transferred, the progress of the image upload, and error information in the case of a failure. Signed-off-by: Russ Weight --- v17: - Rebased for changes to earlier patches. v16: - Minor changes to adapt in changes in prevoius patches. v15: - This patch is new to the patchset and provides an FPGA_IMAGE_LOAD_STATUS IOCTL to return the current values for: remaining_size, progress, err_progress, and err_code. - This patch has elements of the following three patches from the previous patch-set: [PATCH v14 3/6] fpga: sec-mgr: expose sec-mgr update status [PATCH v14 4/6] fpga: sec-mgr: expose sec-mgr update errors [PATCH v14 5/6] fpga: sec-mgr: expose sec-mgr update size - Changed file, symbol, and config names to reflect the new driver name - There are some minor changes to locking to enable this ioctl to return coherent data. --- Documentation/fpga/fpga-image-load.rst | 6 +++ drivers/fpga/fpga-image-load.c | 58 +++++++++++++++++++++----- include/linux/fpga/fpga-image-load.h | 1 + include/uapi/linux/fpga-image-load.h | 18 ++++++++ 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/Documentation/fpga/fpga-image-load.rst b/Documentation/fpga/fpga-image-load.rst index 487b5466f67c..f64f5ee473b8 100644 --- a/Documentation/fpga/fpga-image-load.rst +++ b/Documentation/fpga/fpga-image-load.rst @@ -33,3 +33,9 @@ being updated. This is an exclusive operation; an attempt to start concurrent image uploads for the same device will fail with EBUSY. An eventfd file descriptor parameter is provided to this IOCTL. It will be signalled at the completion of the image upload. + +FPGA_IMAGE_LOAD_STATUS: + +Collect status for an on-going image upload. The status returned includes +how much data remains to be transferred, the progress of the image upload, +and error information in the case of a failure. diff --git a/drivers/fpga/fpga-image-load.c b/drivers/fpga/fpga-image-load.c index f04dfc71c190..58373b9e8c02 100644 --- a/drivers/fpga/fpga-image-load.c +++ b/drivers/fpga/fpga-image-load.c @@ -22,6 +22,22 @@ static dev_t fpga_image_devt; #define to_image_load(d) container_of(d, struct fpga_image_load, dev) +static void fpga_image_update_progress(struct fpga_image_load *imgld, + u32 new_progress) +{ + mutex_lock(&imgld->lock); + imgld->progress = new_progress; + mutex_unlock(&imgld->lock); +} + +static void fpga_image_set_error(struct fpga_image_load *imgld, u32 err_code) +{ + mutex_lock(&imgld->lock); + imgld->err_progress = imgld->progress; + imgld->err_code = err_code; + mutex_unlock(&imgld->lock); +} + static void fpga_image_prog_complete(struct fpga_image_load *imgld) { mutex_lock(&imgld->lock); @@ -38,24 +54,24 @@ static void fpga_image_do_load(struct work_struct *work) imgld = container_of(work, struct fpga_image_load, work); if (imgld->driver_unload) { - imgld->err_code = FPGA_IMAGE_ERR_CANCELED; + fpga_image_set_error(imgld, FPGA_IMAGE_ERR_CANCELED); goto idle_exit; } get_device(&imgld->dev); if (!try_module_get(imgld->dev.parent->driver->owner)) { - imgld->err_code = FPGA_IMAGE_ERR_BUSY; + fpga_image_set_error(imgld, FPGA_IMAGE_ERR_BUSY); goto putdev_exit; } - imgld->progress = FPGA_IMAGE_PROG_PREPARING; + fpga_image_update_progress(imgld, FPGA_IMAGE_PROG_PREPARING); ret = imgld->ops->prepare(imgld, imgld->data, imgld->remaining_size); if (ret) { - imgld->err_code = ret; + fpga_image_set_error(imgld, ret); goto modput_exit; } - imgld->progress = FPGA_IMAGE_PROG_WRITING; + fpga_image_update_progress(imgld, FPGA_IMAGE_PROG_WRITING); while (imgld->remaining_size) { ret = imgld->ops->write(imgld, imgld->data, offset, imgld->remaining_size); @@ -65,7 +81,7 @@ static void fpga_image_do_load(struct work_struct *work) "write-op wrote zero data\n"); ret = -FPGA_IMAGE_ERR_RW_ERROR; } - imgld->err_code = -ret; + fpga_image_set_error(imgld, -ret); goto done; } @@ -73,10 +89,10 @@ static void fpga_image_do_load(struct work_struct *work) offset += ret; } - imgld->progress = FPGA_IMAGE_PROG_PROGRAMMING; + fpga_image_update_progress(imgld, FPGA_IMAGE_PROG_PROGRAMMING); ret = imgld->ops->poll_complete(imgld); if (ret) - imgld->err_code = ret; + fpga_image_set_error(imgld, ret); done: if (imgld->ops->cleanup) @@ -151,20 +167,42 @@ static int fpga_image_load_ioctl_write(struct fpga_image_load *imgld, return ret; } +static int fpga_image_load_ioctl_status(struct fpga_image_load *imgld, + unsigned long arg) +{ + struct fpga_image_status status; + + memset(&status, 0, sizeof(status)); + status.progress = imgld->progress; + status.remaining_size = imgld->remaining_size; + status.err_progress = imgld->err_progress; + status.err_code = imgld->err_code; + + if (copy_to_user((void __user *)arg, &status, sizeof(status))) + return -EFAULT; + + return 0; +} + static long fpga_image_load_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct fpga_image_load *imgld = filp->private_data; int ret = -ENOTTY; + mutex_lock(&imgld->lock); + switch (cmd) { case FPGA_IMAGE_LOAD_WRITE: - mutex_lock(&imgld->lock); ret = fpga_image_load_ioctl_write(imgld, arg); - mutex_unlock(&imgld->lock); + break; + case FPGA_IMAGE_LOAD_STATUS: + ret = fpga_image_load_ioctl_status(imgld, arg); break; } + mutex_unlock(&imgld->lock); + return ret; } diff --git a/include/linux/fpga/fpga-image-load.h b/include/linux/fpga/fpga-image-load.h index 77b3c91ce073..366111d090fb 100644 --- a/include/linux/fpga/fpga-image-load.h +++ b/include/linux/fpga/fpga-image-load.h @@ -49,6 +49,7 @@ struct fpga_image_load { const u8 *data; /* pointer to update data */ u32 remaining_size; /* size remaining to transfer */ u32 progress; + u32 err_progress; /* progress at time of error */ u32 err_code; /* image load error code */ bool driver_unload; struct eventfd_ctx *finished; diff --git a/include/uapi/linux/fpga-image-load.h b/include/uapi/linux/fpga-image-load.h index 8d2d3db92e87..1b91343961df 100644 --- a/include/uapi/linux/fpga-image-load.h +++ b/include/uapi/linux/fpga-image-load.h @@ -51,4 +51,22 @@ struct fpga_image_write { #define FPGA_IMAGE_LOAD_WRITE _IOW(FPGA_IMAGE_LOAD_MAGIC, 0, struct fpga_image_write) +/** + * FPGA_IMAGE_LOAD_STATUS - _IOR(FPGA_IMAGE_LOAD_MAGIC, 1, + * struct fpga_image_status) + * + * Request status information for an ongoing update. + * + * Return: 0 on success, -errno on failure. + */ +struct fpga_image_status { + /* Output */ + __u32 remaining_size; /* size remaining to transfer */ + __u32 progress; /* current progress of image load */ + __u32 err_progress; /* progress at time of error */ + __u32 err_code; /* error code */ +}; + +#define FPGA_IMAGE_LOAD_STATUS _IOR(FPGA_IMAGE_LOAD_MAGIC, 1, struct fpga_image_status) + #endif /* _UAPI_LINUX_FPGA_IMAGE_LOAD_H */ From patchwork Wed Sep 29 23:00:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Weight X-Patchwork-Id: 12526919 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4558CC43219 for ; Wed, 29 Sep 2021 23:00:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2B5BC61507 for ; Wed, 29 Sep 2021 23:00:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347375AbhI2XCV (ORCPT ); Wed, 29 Sep 2021 19:02:21 -0400 Received: from mga09.intel.com ([134.134.136.24]:47376 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347378AbhI2XCS (ORCPT ); Wed, 29 Sep 2021 19:02:18 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10122"; a="225097220" X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="225097220" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:32 -0700 X-IronPort-AV: E=Sophos;i="5.85,334,1624345200"; d="scan'208";a="617768043" Received: from rhweight-mobl2.amr.corp.intel.com (HELO rhweight-mobl2.ra.intel.com) ([10.255.230.76]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2021 16:00:31 -0700 From: Russ Weight To: mdf@kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@intel.com, Russ Weight Subject: [PATCH v17 5/5] fpga: image-load: enable cancel of image upload Date: Wed, 29 Sep 2021 16:00:25 -0700 Message-Id: <20210929230025.68961-6-russell.h.weight@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210929230025.68961-1-russell.h.weight@intel.com> References: <20210929230025.68961-1-russell.h.weight@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org Extend the FPGA Image Load framework to include a cancel IOCTL that can be used to request that an image upload be canceled. The IOCTL may return EBUSY if it cannot be canceled by software or ENODEV if there is no update in progress. Signed-off-by: Russ Weight --- v17: - Documentation cleanup for cancelling. - Removed the request_cancel flag and handling from the class driver including the fpga_image_prog_transition() function. - The cancel system call now directly calls the cancel() op of the lower-level driver. - Changed the cancel() op to return void. v16: - This was previously patch 6/6 - Amend fpga_image_load_release() to request cancellation of an ongoing update when possible. v15: - Compare to previous patch: [PATCH v14 6/6] fpga: sec-mgr: enable cancel of secure update - Changed file, symbol, and config names to reflect the new driver name - Cancel is now initiated by IOCT instead of sysfs - Removed signed-off/reviewed-by tags v14: - Updated ABI documentation date and kernel version v13: - No change v12: - Updated Date and KernelVersion fields in ABI documentation v11: - No change v10: - Rebased to 5.12-rc2 next - Updated Date and KernelVersion in ABI documentation v9: - Updated Date and KernelVersion in ABI documentation v8: - No change v7: - Changed Date in documentation file to December 2020 v6: - No change v5: - No change v4: - Changed from "Intel FPGA Security Manager" to FPGA Security Manager" and removed unnecessary references to "Intel". - Changed: iops -> sops, imgr -> smgr, IFPGA_ -> FPGA_, ifpga_ to fpga_ v3: - No change v2: - Bumped documentation date and version - Minor code cleanup per review comments --- Documentation/fpga/fpga-image-load.rst | 13 +++++++++++-- drivers/fpga/fpga-image-load.c | 26 +++++++++++++++++++++++--- include/linux/fpga/fpga-image-load.h | 4 ++++ include/uapi/linux/fpga-image-load.h | 2 ++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Documentation/fpga/fpga-image-load.rst b/Documentation/fpga/fpga-image-load.rst index f64f5ee473b8..3997b3bcd7ec 100644 --- a/Documentation/fpga/fpga-image-load.rst +++ b/Documentation/fpga/fpga-image-load.rst @@ -18,8 +18,9 @@ open An fpga_image_load device is opened exclusively to control an image upload. The device must remain open throughout the duration of the image upload. -An attempt to close the device while an upload is in progress will block -until the image upload is complete. +An attempt to close the device while an upload is in progress will cause +the upload to be cancelled. If unable to cancel the image upload, the close +system call will block until the image upload is complete. ioctl ----- @@ -39,3 +40,11 @@ FPGA_IMAGE_LOAD_STATUS: Collect status for an on-going image upload. The status returned includes how much data remains to be transferred, the progress of the image upload, and error information in the case of a failure. + +FPGA_IMAGE_LOAD_CANCEL: + +Request that an on-going image upload be cancelled. This IOCTL will return +ENODEV if there is no update in progress. Depending on the implementation +of the lower-level driver, the cancellation may take affect immediately. +In other cases, the cancellation request may be blocked until a critical +operation such as a FLASH is safely completed. diff --git a/drivers/fpga/fpga-image-load.c b/drivers/fpga/fpga-image-load.c index 58373b9e8c02..239943d7f321 100644 --- a/drivers/fpga/fpga-image-load.c +++ b/drivers/fpga/fpga-image-load.c @@ -159,7 +159,6 @@ static int fpga_image_load_ioctl_write(struct fpga_image_load *imgld, imgld->err_code = 0; imgld->progress = FPGA_IMAGE_PROG_STARTING; queue_work(system_long_wq, &imgld->work); - return 0; exit_free: @@ -184,11 +183,21 @@ static int fpga_image_load_ioctl_status(struct fpga_image_load *imgld, return 0; } +static int fpga_image_load_ioctl_cancel(struct fpga_image_load *imgld, + unsigned long arg) +{ + if (imgld->progress == FPGA_IMAGE_PROG_IDLE) + return -ENODEV; + + imgld->ops->cancel(imgld); + return 0; +} + static long fpga_image_load_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct fpga_image_load *imgld = filp->private_data; - int ret = -ENOTTY; + int ret = 0; mutex_lock(&imgld->lock); @@ -199,6 +208,12 @@ static long fpga_image_load_ioctl(struct file *filp, unsigned int cmd, case FPGA_IMAGE_LOAD_STATUS: ret = fpga_image_load_ioctl_status(imgld, arg); break; + case FPGA_IMAGE_LOAD_CANCEL: + ret = fpga_image_load_ioctl_cancel(imgld, arg); + break; + default: + ret = -ENOTTY; + break; } mutex_unlock(&imgld->lock); @@ -229,6 +244,8 @@ static int fpga_image_load_release(struct inode *inode, struct file *filp) goto close_exit; } + imgld->ops->cancel(imgld); + mutex_unlock(&imgld->lock); flush_work(&imgld->work); @@ -263,7 +280,8 @@ fpga_image_load_register(struct device *parent, struct fpga_image_load *imgld; int ret; - if (!ops || !ops->prepare || !ops->write || !ops->poll_complete) { + if (!ops || !ops->cancel || !ops->prepare || + !ops->write || !ops->poll_complete) { dev_err(parent, "Attempt to register without all required ops\n"); return ERR_PTR(-ENOMEM); } @@ -342,6 +360,8 @@ void fpga_image_load_unregister(struct fpga_image_load *imgld) goto unregister; } + imgld->ops->cancel(imgld); + mutex_unlock(&imgld->lock); flush_work(&imgld->work); diff --git a/include/linux/fpga/fpga-image-load.h b/include/linux/fpga/fpga-image-load.h index 366111d090fb..6baf45072bdb 100644 --- a/include/linux/fpga/fpga-image-load.h +++ b/include/linux/fpga/fpga-image-load.h @@ -26,6 +26,9 @@ struct fpga_image_load; * written. * @poll_complete: Required: Check for the completion of the * HW authentication/programming process. + * @cancel: Required: Request cancellation of update. This op + * is called from the context of a different kernel + * thread, so race conditions need to be considered. * @cleanup: Optional: Complements the prepare() * function and is called at the completion * of the update, whether success or failure, @@ -36,6 +39,7 @@ struct fpga_image_load_ops { s32 (*write)(struct fpga_image_load *imgld, const u8 *data, u32 offset, u32 size); u32 (*poll_complete)(struct fpga_image_load *imgld); + void (*cancel)(struct fpga_image_load *imgld); void (*cleanup)(struct fpga_image_load *imgld); }; diff --git a/include/uapi/linux/fpga-image-load.h b/include/uapi/linux/fpga-image-load.h index 1b91343961df..5bf8a8a57757 100644 --- a/include/uapi/linux/fpga-image-load.h +++ b/include/uapi/linux/fpga-image-load.h @@ -69,4 +69,6 @@ struct fpga_image_status { #define FPGA_IMAGE_LOAD_STATUS _IOR(FPGA_IMAGE_LOAD_MAGIC, 1, struct fpga_image_status) +#define FPGA_IMAGE_LOAD_CANCEL _IO(FPGA_IMAGE_LOAD_MAGIC, 2) + #endif /* _UAPI_LINUX_FPGA_IMAGE_LOAD_H */