From owner-dev-commits-src-main@freebsd.org Mon Jun 28 12:15:47 2021 Return-Path: Delivered-To: dev-commits-src-main@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id AED736553DD; Mon, 28 Jun 2021 12:15:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4GD65H4Symz4tkv; Mon, 28 Jun 2021 12:15:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 819DD25314; Mon, 28 Jun 2021 12:15:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 15SCFlnp036786; Mon, 28 Jun 2021 12:15:47 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 15SCFlOD036785; Mon, 28 Jun 2021 12:15:47 GMT (envelope-from git) Date: Mon, 28 Jun 2021 12:15:47 GMT Message-Id: <202106281215.15SCFlOD036785@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Bjoern A. Zeeb" Subject: git: 399da52fff81 - main - LinuxKPI: firmware, implement deferred loading for "nowait" MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bz X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 399da52fff81a33b1f2c0cee3e8574bc3c63166f Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-main@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for the main branch of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Jun 2021 12:15:47 -0000 The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=399da52fff81a33b1f2c0cee3e8574bc3c63166f commit 399da52fff81a33b1f2c0cee3e8574bc3c63166f Author: Bjoern A. Zeeb AuthorDate: 2021-06-20 13:49:46 +0000 Commit: Bjoern A. Zeeb CommitDate: 2021-06-28 12:13:43 +0000 LinuxKPI: firmware, implement deferred loading for "nowait" Change linuxkpi_request_firmware_nowait() to deferred firmware loading scheduling a task. This changes behaviour in some cases that we return from loading the driver before the driver is finished initialising if the driver does not deal with it (wait). This brings the behaviour one would expect from when this function is called and I implemented it to see if it would help a specific case. Sponsored by: The FreeBSD Foundation MFC after: 12 days Reviewed by: hselasky, imp (earlier version) Differential Revision: https://reviews.freebsd.org/D30830 --- sys/compat/linuxkpi/common/src/linux_firmware.c | 74 +++++++++++++++++++------ 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/sys/compat/linuxkpi/common/src/linux_firmware.c b/sys/compat/linuxkpi/common/src/linux_firmware.c index 289779c5246c..d779b509105e 100644 --- a/sys/compat/linuxkpi/common/src/linux_firmware.c +++ b/sys/compat/linuxkpi/common/src/linux_firmware.c @@ -30,9 +30,13 @@ * $FreeBSD$ */ +#include +#include #include #include #include +#include +#include #include #include @@ -42,6 +46,16 @@ MALLOC_DEFINE(M_LKPI_FW, "lkpifw", "LinuxKPI firmware"); +struct lkpi_fw_task { + /* Task and arguments for the "nowait" callback. */ + struct task fw_task; + gfp_t gfp; + const char *fw_name; + struct device *dev; + void *drv; + void(*cont)(const struct linuxkpi_firmware *, void *); +}; + static int _linuxkpi_request_firmware(const char *fw_name, const struct linuxkpi_firmware **fw, struct device *dev, gfp_t gfp __unused, bool enoentok, bool warn) @@ -52,8 +66,10 @@ _linuxkpi_request_firmware(const char *fw_name, const struct linuxkpi_firmware * char *p; uint32_t flags; - if (fw_name == NULL || fw == NULL || dev == NULL) + if (fw_name == NULL || fw == NULL || dev == NULL) { + *fw = NULL; return (-EINVAL); + } /* Set independent on "warn". To debug, bootverbose is avail. */ flags = FIRMWARE_GET_NOWARN; @@ -129,28 +145,54 @@ _linuxkpi_request_firmware(const char *fw_name, const struct linuxkpi_firmware * return (0); } -int -linuxkpi_request_firmware_nowait(struct module *mod __unused, bool _t __unused, - const char *fw_name, struct device *dev, gfp_t gfp, void *drv, - void(*cont)(const struct linuxkpi_firmware *, void *)) +static void +lkpi_fw_task(void *ctx, int pending) { - const struct linuxkpi_firmware *lfw; + struct lkpi_fw_task *lfwt; + const struct linuxkpi_firmware *fw; int error; + KASSERT(ctx != NULL && pending == 1, ("%s: lfwt %p, pending %d\n", + __func__, ctx, pending)); + + lfwt = ctx; + if (lfwt->cont == NULL) + goto out; + + error = _linuxkpi_request_firmware(lfwt->fw_name, &fw, lfwt->dev, + lfwt->gfp, true, true); + /* * Linux seems to run the callback if it cannot find the firmware. - * The fact that this is "_nowait()" and has a callback seems to - * imply that this is run in a deferred conext which we currently - * do not do. Should it become necessary (a driver actually requiring - * it) we would need to implement it here. + * We call it in all cases as it is the only feedback to the requester. */ - error = _linuxkpi_request_firmware(fw_name, &lfw, dev, gfp, true, true); - if (error == -ENOENT) - error = 0; - if (error == 0) - cont(lfw, drv); + lfwt->cont(fw, lfwt->drv); + /* Do not assume fw is still valid! */ - return (error); +out: + free(lfwt, M_LKPI_FW); +} + +int +linuxkpi_request_firmware_nowait(struct module *mod __unused, bool _t __unused, + const char *fw_name, struct device *dev, gfp_t gfp, void *drv, + void(*cont)(const struct linuxkpi_firmware *, void *)) +{ + struct lkpi_fw_task *lfwt; + int error; + + lfwt = malloc(sizeof(*lfwt), M_LKPI_FW, M_WAITOK | M_ZERO); + lfwt->gfp = gfp; + lfwt->fw_name = fw_name; + lfwt->dev = dev; + lfwt->drv = drv; + lfwt->cont = cont; + TASK_INIT(&lfwt->fw_task, 0, lkpi_fw_task, lfwt); + error = taskqueue_enqueue(taskqueue_thread, &lfwt->fw_task); + + if (error) + return (-error); + return (0); } int