Received: by 2002:a05:6a10:6d10:0:0:0:0 with SMTP id gq16csp975352pxb; Fri, 15 Apr 2022 17:08:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyN1nL9Foddp7VJws3mM+bIE57MDCxRxI6pn5GWlspEonVm40Xkq9iyVLYnOM8MhB/+oQyY X-Received: by 2002:a17:90a:c58b:b0:1cb:64f5:131c with SMTP id l11-20020a17090ac58b00b001cb64f5131cmr6722098pjt.204.1650067716633; Fri, 15 Apr 2022 17:08:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650067716; cv=none; d=google.com; s=arc-20160816; b=K/brGSHVnQKuq1YqDiRSjRCq8Jv3l2hPCJZguIkrRGRNLkT7USpPwZVmXnvMOkSvtg ObEYka6HuKeyZM/du1sasN0cH38C1Xse0TpXok5uBZ5CkmYuWSxuT5iXqGaDk6WIN3sA s+R2OmJetAQbAzb9GP9O83tuDlBc2uO9QVIXvFzdXex+E/ruT4S3V9Mn/sSpCfMtBonK FjOBnKLQo0uY7Qsm0r9IOmyOG8qENiSUddjmQ+gjR8OpKQG6vqukmJqPdmK3iczfiUvp 8WsBRkzFOdHbfl2Aw3NJrxQYYZI65JQuUWEPm4WQvZXNSlZHgG52VwkCv572C20QxSWw /5xg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=il8wv5OpdYRasu+yrRfjRl9qJvMQm8IUNwTAxprzl8I=; b=ok/tkquaEPmvTuEnoWK0sRpXOGEltSlt7Tl7TmS2BZxoIuGWx+2gF0hqvXWWSmeD52 Yq0JY7BcGKS0KuRbZrvFDa3xR9Bau9GTze1CPut/1GlrUP/x6gxNrt8UzHDrz1TWvAx5 o+Kv1NXnm5yGINHqw9Z+ZiJqyMd6AUTHWtEIGSQXjC4RHkzpVVGUW2F8tOR7w6E8mh9O 9HRIGt72VON6nddW6hr3UyGgC5QEo8ZSfjDm0PBhgaS7T13Sx7DaXXmJcWBquiaghn0q PIUlK7+5qURm8jizRAeoHxzU3MVyim2UrZj6t0BdHFEzauxYIm17O65MPyFenZJ+pqIx ngOA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=F9j6s2yc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id j186-20020a638bc3000000b0039d68b7a689si2801471pge.20.2022.04.15.17.08.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Apr 2022 17:08:36 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=F9j6s2yc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id BEE015D5DD; Fri, 15 Apr 2022 17:08:34 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1351372AbiDOULU (ORCPT + 99 others); Fri, 15 Apr 2022 16:11:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1351188AbiDOULH (ORCPT ); Fri, 15 Apr 2022 16:11:07 -0400 Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3A7AEDB4A9 for ; Fri, 15 Apr 2022 13:08:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1650053318; x=1681589318; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Ia/ynUmgVCZUjj7ocwWn0XIeBDTcxFjHEhyfldeVNlg=; b=F9j6s2ycXDder3befaQjL+7FF66t60PbGSbMORGhXhZNfHrQMsFRBVl0 t/JgB6sLvyIP1O7OZsRwX+XXiuD/WSf91tZMf9FU+R5kJQvV7VaPBUo4o bgGQoSFWrrp4cHRp+k0Ig4nJlVN2m86lNmG/fEG+R3uqyrsKdutPAmdmd wan4Hs10Zo97yDtJhh3XrIdeM8nbD+6kMoJC5XsKPNcpKS9bJHmD2bzn7 JSBQARzV4iJc5uYLcFPtSK8R4cb5igw4vUfyw1X4BU/YPdgmxLqW3JPOP OCJFmnw2vHzfib2cQK0WZBunW/p+NjN6ds+VDO1Qdjj6nmqlzDVt0+vnd Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10318"; a="262078951" X-IronPort-AV: E=Sophos;i="5.90,263,1643702400"; d="scan'208";a="262078951" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Apr 2022 13:08:10 -0700 X-IronPort-AV: E=Sophos;i="5.90,263,1643702400"; d="scan'208";a="574510707" Received: from rhweight-mobl.amr.corp.intel.com (HELO rhweight-mobl.ra.intel.com) ([10.209.98.156]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Apr 2022 13:08:10 -0700 From: Russ Weight To: mcgrof@kernel.org, rafael@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, basheer.ahmed.muddebihal@intel.com, tianfei.zhang@intel.com, Russ Weight Subject: [PATCH v2 5/8] firmware_loader: Add sysfs nodes to monitor fw_upload Date: Fri, 15 Apr 2022 13:08:02 -0700 Message-Id: <20220415200805.610339-6-russell.h.weight@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220415200805.610339-1-russell.h.weight@intel.com> References: <20220415200805.610339-1-russell.h.weight@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RDNS_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add additional sysfs nodes to monitor the transfer of firmware upload data to the target device: cancel: Write 1 to cancel the data transfer error: Display error status for a failed firmware upload remaining_size: Display the remaining amount of data to be transferred status: Display the progress of the firmware upload Signed-off-by: Russ Weight --- v1: - Adapted to enums and filename changes. Otherwise no changes. v2: - Updated documentation Date and KernelVersion fields to July 2022 and 5.19. --- .../ABI/testing/sysfs-class-firmware | 45 +++++++ .../driver-api/firmware/fw_upload.rst | 19 ++- drivers/base/firmware_loader/sysfs.c | 9 ++ drivers/base/firmware_loader/sysfs_upload.c | 121 ++++++++++++++++++ drivers/base/firmware_loader/sysfs_upload.h | 5 + 5 files changed, 198 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-firmware b/Documentation/ABI/testing/sysfs-class-firmware index 18336c23b70d..978d3d500400 100644 --- a/Documentation/ABI/testing/sysfs-class-firmware +++ b/Documentation/ABI/testing/sysfs-class-firmware @@ -10,6 +10,30 @@ Description: The data sysfs file is used for firmware-fallback and for signal the lower-level driver that the firmware data is available. +What: /sys/class/firmware/.../cancel +Date: July 2022 +KernelVersion: 5.19 +Contact: Russ Weight +Description: Write-only. For firmware uploads, write a "1" to this file to + request that the transfer of firmware data to the lower-level + device be canceled. This request will be rejected (EBUSY) if + the update cannot be canceled (e.g. a FLASH write is in + progress) or (ENODEV) if there is no firmware update in progress. + +What: /sys/class/firmware/.../error +Date: July 2022 +KernelVersion: 5.19 +Contact: Russ Weight +Description: Read-only. Returns a string describing a failed firmware + upload. This string will be in the form of :, + where will be one of the status strings described + for the status sysfs file and will be one of the + following: "hw-error", "timeout", "user-abort", "device-busy", + "invalid-file-size", "read-write-error", "flash-wearout". The + error sysfs file is only meaningful when the current firmware + upload status is "idle". If this file is read while a firmware + transfer is in progress, then the read will fail with EBUSY. + What: /sys/class/firmware/.../loading Date: July 2022 KernelVersion: 5.19 @@ -22,6 +46,27 @@ Description: The loading sysfs file is used for both firmware-fallback and uploads, the zero value also triggers the transfer of the firmware data to the lower-level device driver. +What: /sys/class/firmware/.../remaining_size +Date: July 2022 +KernelVersion: 5.19 +Contact: Russ Weight +Description: Read-only. For firmware upload, this file contains the size + of the firmware data that remains to be transferred to the + lower-level device driver. The size value is initialized to + the full size of the firmware image that was previously + written to the data sysfs file. This value is periodically + updated during the "transferring" phase of the firmware + upload. + Format: "%u". + +What: /sys/class/firmware/.../status +Date: July 2022 +KernelVersion: 5.19 +Contact: Russ Weight +Description: Read-only. Returns a string describing the current status of + a firmware upload. The string will be one of the following: + idle, "receiving", "preparing", "transferring", "programming". + What: /sys/class/firmware/.../timeout Date: July 2022 KernelVersion: 5.19 diff --git a/Documentation/driver-api/firmware/fw_upload.rst b/Documentation/driver-api/firmware/fw_upload.rst index 2aaac9c70e41..00c8e19d99b7 100644 --- a/Documentation/driver-api/firmware/fw_upload.rst +++ b/Documentation/driver-api/firmware/fw_upload.rst @@ -9,7 +9,8 @@ persistent sysfs nodes to enable users to initiate firmware updates for that device. It is the responsibility of the device driver and/or the device itself to perform any validation on the data received. Firmware upload uses the same *loading* and *data* sysfs files described in the -documentation for firmware fallback. +documentation for firmware fallback. It also adds additional sysfs files +to provide status on the transfer of the firmware image to the device. Register for firmware upload ============================ @@ -98,3 +99,19 @@ failure: .. kernel-doc:: include/linux/firmware.h :identifiers: fw_upload_err + +Sysfs Attributes +================ + +In addition to the *loading* and *data* sysfs files, there are additional +sysfs files to monitor the status of the data transfer to the target +device and to determine the final pass/fail status of the transfer. +Depending on the device and the size of the firmware image, a firmware +update could take milliseconds or minutes. + +The additional sysfs files are: + +* status - provides an indication of the progress of a firmware update +* error - provides error information for a failed firmware update +* remaining_size - tracks the data transfer portion of an update +* cancel - echo 1 to this file to cancel the update diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c index 4409e33b7f35..9cedba5f5f46 100644 --- a/drivers/base/firmware_loader/sysfs.c +++ b/drivers/base/firmware_loader/sysfs.c @@ -369,6 +369,12 @@ static struct bin_attribute firmware_attr_data = { static struct attribute *fw_dev_attrs[] = { &dev_attr_loading.attr, +#ifdef CONFIG_FW_UPLOAD + &dev_attr_cancel.attr, + &dev_attr_status.attr, + &dev_attr_error.attr, + &dev_attr_remaining_size.attr, +#endif NULL }; @@ -380,6 +386,9 @@ static struct bin_attribute *fw_dev_bin_attrs[] = { static const struct attribute_group fw_dev_attr_group = { .attrs = fw_dev_attrs, .bin_attrs = fw_dev_bin_attrs, +#ifdef CONFIG_FW_UPLOAD + .is_visible = fw_upload_is_visible, +#endif }; static const struct attribute_group *fw_dev_attr_groups[] = { diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c index 0a6450d1974f..c504dae00dbe 100644 --- a/drivers/base/firmware_loader/sysfs_upload.c +++ b/drivers/base/firmware_loader/sysfs_upload.c @@ -11,6 +11,127 @@ * Support for user-space to initiate a firmware upload to a device. */ +static const char * const fw_upload_prog_str[] = { + [FW_UPLOAD_PROG_IDLE] = "idle", + [FW_UPLOAD_PROG_RECEIVING] = "receiving", + [FW_UPLOAD_PROG_PREPARING] = "preparing", + [FW_UPLOAD_PROG_TRANSFERRING] = "transferring", + [FW_UPLOAD_PROG_PROGRAMMING] = "programming" +}; + +static const char * const fw_upload_err_str[] = { + [FW_UPLOAD_ERR_NONE] = "none", + [FW_UPLOAD_ERR_HW_ERROR] = "hw-error", + [FW_UPLOAD_ERR_TIMEOUT] = "timeout", + [FW_UPLOAD_ERR_CANCELED] = "user-abort", + [FW_UPLOAD_ERR_BUSY] = "device-busy", + [FW_UPLOAD_ERR_INVALID_SIZE] = "invalid-file-size", + [FW_UPLOAD_ERR_RW_ERROR] = "read-write-error", + [FW_UPLOAD_ERR_WEAROUT] = "flash-wearout", +}; + +static const char *fw_upload_progress(struct device *dev, + enum fw_upload_prog prog) +{ + const char *status = "unknown-status"; + + if (prog < FW_UPLOAD_PROG_MAX) + status = fw_upload_prog_str[prog]; + else + dev_err(dev, "Invalid status during secure update: %d\n", prog); + + return status; +} + +static const char *fw_upload_error(struct device *dev, + enum fw_upload_err err_code) +{ + const char *error = "unknown-error"; + + if (err_code < FW_UPLOAD_ERR_MAX) + error = fw_upload_err_str[err_code]; + else + dev_err(dev, "Invalid error code during secure update: %d\n", + err_code); + + return error; +} + +static ssize_t +status_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; + + return sysfs_emit(buf, "%s\n", fw_upload_progress(dev, fwlp->progress)); +} +DEVICE_ATTR_RO(status); + +static ssize_t +error_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; + int ret; + + mutex_lock(&fwlp->lock); + + if (fwlp->progress != FW_UPLOAD_PROG_IDLE) + ret = -EBUSY; + else if (!fwlp->err_code) + ret = 0; + else + ret = sysfs_emit(buf, "%s:%s\n", + fw_upload_progress(dev, fwlp->err_progress), + fw_upload_error(dev, fwlp->err_code)); + + mutex_unlock(&fwlp->lock); + + return ret; +} +DEVICE_ATTR_RO(error); + +static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; + int ret = count; + bool cancel; + + if (kstrtobool(buf, &cancel) || !cancel) + return -EINVAL; + + mutex_lock(&fwlp->lock); + if (fwlp->progress == FW_UPLOAD_PROG_IDLE) + ret = -ENODEV; + + fwlp->ops->cancel(fwlp->fw_upload); + mutex_unlock(&fwlp->lock); + + return ret; +} +DEVICE_ATTR_WO(cancel); + +static ssize_t remaining_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; + + return sysfs_emit(buf, "%u\n", fwlp->remaining_size); +} +DEVICE_ATTR_RO(remaining_size); + +umode_t +fw_upload_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + static struct fw_sysfs *fw_sysfs; + + fw_sysfs = to_fw_sysfs(kobj_to_dev(kobj)); + + if (fw_sysfs->fw_upload_priv || attr == &dev_attr_loading.attr) + return attr->mode; + + return 0; +} + static void fw_upload_update_progress(struct fw_upload_priv *fwlp, enum fw_upload_prog new_progress) { diff --git a/drivers/base/firmware_loader/sysfs_upload.h b/drivers/base/firmware_loader/sysfs_upload.h index a72d0e82e107..8e3317d49431 100644 --- a/drivers/base/firmware_loader/sysfs_upload.h +++ b/drivers/base/firmware_loader/sysfs_upload.h @@ -29,6 +29,11 @@ struct fw_upload_priv { }; #ifdef CONFIG_FW_UPLOAD +extern struct device_attribute dev_attr_status; +extern struct device_attribute dev_attr_error; +extern struct device_attribute dev_attr_cancel; +extern struct device_attribute dev_attr_remaining_size; + int fw_upload_start(struct fw_sysfs *fw_sysfs); umode_t fw_upload_is_visible(struct kobject *kobj, struct attribute *attr, int n); #else -- 2.25.1