Received: by 2002:a05:6a10:6d10:0:0:0:0 with SMTP id gq16csp824110pxb; Fri, 22 Apr 2022 11:59:26 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzZNbCF0jM+Gvkh+i+Bx5Y/wqWzWt3mJNDZhWh51ZlICbaZDTTB5upp1np44uT8Cg8PsJV+ X-Received: by 2002:a17:902:8b88:b0:156:2b14:cb6e with SMTP id ay8-20020a1709028b8800b001562b14cb6emr6045319plb.14.1650653966462; Fri, 22 Apr 2022 11:59:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650653966; cv=none; d=google.com; s=arc-20160816; b=COfW5cdGVzBylvXx47BhFnA1gyPaw82u2tojRHpjdTD5SKc7Hgeed1S8QD2AZXLSQq qOQ8AlhIChEJPO12Ah8l3NGodGUfqXPuVQPQwUyv4P+MWoeaIE8ZkJMgxIykaD18qzx8 +R5szZvH/uui8IJWJeIbUNGDAqEhrSPaV4DWoMbKeXNcOJ2Hf/W5iPOFlhQVZs8CF+jg RelEQIn2REOuGURergiWMOYCV5m0u8yDzqoRuSHh5lsx0TXXaMJNuhrgNEoJcU3XMUbK UT3dm9rA/UblQ5xNUmV/HwE8N2kE0/yjkx5gTLshJLW9dHAIUfzkoR+dgmmqMhRidnaD mw1w== 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=RNpxWDF9xGaklSTaG2/ohHiQGx7TXcBQlu647wDFDD0=; b=D6W7bcC0+YjyckGte5BVQ0BmsavSD/2kqOvt7JLITKDSUaSzSVvr4qRjqPMNQVEevY exl1ScMxRo0zhC2IR05AbeqY9cxGhu4OPPSHepA3bgKVcbTjjoD/WtCBLiIc19JqbFUA zu/pOinkS8cyB4g8lB2p9yt7Net2gLHcXvgNawX0rNZfHoMVUtD5kB7MFBZqkRdrnTMf DIkvdA2352tIS9a1QKDfp4zTrrDZhCdim0CQMakK7H7+guhnA1VB1Z3Yk+/rIceq0IJU he4lKS3GakoC9n3dqFmVLftiJclEA2p31+Q/oZVPcaKlWUXNNPhqJIK7hCPMsbJJucNp 4jyQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b="M/wAe6+V"; 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 23-20020a630d57000000b0039d68b7a67asi9168660pgn.843.2022.04.22.11.59.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Apr 2022 11:59:26 -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="M/wAe6+V"; 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 995F818BC9E; Fri, 22 Apr 2022 11:21:59 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1441977AbiDUVZV (ORCPT + 99 others); Thu, 21 Apr 2022 17:25:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51916 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1441945AbiDUVZG (ORCPT ); Thu, 21 Apr 2022 17:25:06 -0400 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 669A54D255 for ; Thu, 21 Apr 2022 14:22:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1650576135; x=1682112135; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=A3kko49KgvW7vKzlVVL7d6lNSZ6+miNVwAF7TG45IYQ=; b=M/wAe6+VP25Wam7GLxMpYIQZOuv9NjycQUo9yK9xC84DHRfWrx32GS6U 0Bv62Z2LjS8k7EKjgWDddFwsVIRCQGauSfjqtxJy8e/Q4jKFDD/WaS+QZ n+Ej5A25EmurcjfQxwNwxo/b31jhMuEq5LjaxPwKjZ9jOwRZszkrrZh9U HfU8faVv/hEyqacnwVSitjLE7YRwm4njDR2hEBcypLqKp3N56eZ0EImA+ jThtb9t6/E6v53SvkqGXlAJPbv19bjexzX/9DlB77WYCljQM5XZzsZwR4 5Y76HvbWOxMxF+WH8R/vVaKPcYlJfQXzs1c/q5JmqZPnwNEbn/AAJ7bLo A==; X-IronPort-AV: E=McAfee;i="6400,9594,10324"; a="350925005" X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="350925005" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2022 14:22:13 -0700 X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="658704103" Received: from rhweight-mobl.amr.corp.intel.com (HELO rhweight-mobl.ra.intel.com) ([10.209.56.239]) by fmsmga002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2022 14:22:12 -0700 From: Russ Weight To: mcgrof@kernel.org, gregkh@linuxfoundation.org, rafael@kernel.org, linux-kernel@vger.kernel.org Cc: trix@redhat.com, marpagan@redhat.com, lgoncalv@redhat.com, yilun.xu@intel.com, hao.wu@intel.com, matthew.gerlach@linux.intel.com, basheer.ahmed.muddebihal@intel.com, tianfei.zhang@intel.com, Russ Weight Subject: [PATCH v5 7/8] test_firmware: Error injection for firmware upload Date: Thu, 21 Apr 2022 14:22:03 -0700 Message-Id: <20220421212204.36052-8-russell.h.weight@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220421212204.36052-1-russell.h.weight@intel.com> References: <20220421212204.36052-1-russell.h.weight@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.5 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 autolearn=unavailable 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 error injection capability to the test_firmware module specifically for firmware upload testing. Error injection instructions are transferred as the first part of the firmware payload. The format of an error injection string is similar to the error strings that may be read from the error sysfs node. To inject the error "programming:hw-error", one would use the error injection string "inject:programming:hw-error" as the firmware payload: $ echo 1 > loading $ echo inject:programming:hw-error > data $ echo 0 > loading $ cat status idle $ cat error programming:hw-error The first part of the error string is the progress state of the upload at the time of the error. The progress state would be one of the following: "preparing", "transferring", or "programming". The second part of the error string is one of the following: "hw-error", "timeout", "device-busy", "invalid-file-size", "read-write-error", "flash-wearout", and "user-abort". Note that all of the error strings except "user-abort" will fail without delay. The "user-abort" error will cause the firmware upload to stall at the requested progress state for up to 5 minutes to allow you to echo 1 to the cancel sysfs node. It is this cancellation that causes the 'user-abort" error. If the upload is not cancelled within the 5 minute time period, then the upload will complete without an error. Reviewed-by: Luis Chamberlain Reviewed-by: Tianfei zhang Tested-by: Matthew Gerlach Signed-off-by: Russ Weight --- v2: - No changes from v1 v3: - Added Reviewed-by tag v4: - Added Reviewed-by tag v5: - Added Tested-by tag --- lib/test_firmware.c | 127 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 5 deletions(-) diff --git a/lib/test_firmware.c b/lib/test_firmware.c index 2b8c56d7bf37..76115c1a2629 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c @@ -117,12 +117,18 @@ struct test_config { struct device *device); }; +struct upload_inject_err { + const char *prog; + enum fw_upload_err err_code; +}; + struct test_firmware_upload { char *name; struct list_head node; char *buf; size_t size; bool cancel_request; + struct upload_inject_err inject; struct fw_upload *fwl; }; @@ -1067,20 +1073,105 @@ static void upload_release_all(void) test_fw_config->upload_name = NULL; } +/* + * This table is replicated from .../firmware_loader/sysfs_upload.c + * and needs to be kept in sync. + */ +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 void upload_err_inject_error(struct test_firmware_upload *tst, + const u8 *p, const char *prog) +{ + enum fw_upload_err err; + + for (err = FW_UPLOAD_ERR_NONE + 1; err < FW_UPLOAD_ERR_MAX; err++) { + if (strncmp(p, fw_upload_err_str[err], + strlen(fw_upload_err_str[err])) == 0) { + tst->inject.prog = prog; + tst->inject.err_code = err; + return; + } + } +} + +static void upload_err_inject_prog(struct test_firmware_upload *tst, + const u8 *p) +{ + static const char * const progs[] = { + "preparing:", "transferring:", "programming:" + }; + int i; + + for (i = 0; i < ARRAY_SIZE(progs); i++) { + if (strncmp(p, progs[i], strlen(progs[i])) == 0) { + upload_err_inject_error(tst, p + strlen(progs[i]), + progs[i]); + return; + } + } +} + +#define FIVE_MINUTES_MS (5 * 60 * 1000) +static enum fw_upload_err +fw_upload_wait_on_cancel(struct test_firmware_upload *tst) +{ + int ms_delay; + + for (ms_delay = 0; ms_delay < FIVE_MINUTES_MS; ms_delay += 100) { + msleep(100); + if (tst->cancel_request) + return FW_UPLOAD_ERR_CANCELED; + } + return FW_UPLOAD_ERR_NONE; +} + static enum fw_upload_err test_fw_upload_prepare(struct fw_upload *fwl, const u8 *data, u32 size) { struct test_firmware_upload *tst = fwl->dd_handle; + enum fw_upload_err ret = FW_UPLOAD_ERR_NONE; + const char *progress = "preparing:"; tst->cancel_request = false; - if (!size || size > TEST_UPLOAD_MAX_SIZE) - return FW_UPLOAD_ERR_INVALID_SIZE; + if (!size || size > TEST_UPLOAD_MAX_SIZE) { + ret = FW_UPLOAD_ERR_INVALID_SIZE; + goto err_out; + } + + if (strncmp(data, "inject:", strlen("inject:")) == 0) + upload_err_inject_prog(tst, data + strlen("inject:")); memset(tst->buf, 0, TEST_UPLOAD_MAX_SIZE); tst->size = size; - return FW_UPLOAD_ERR_NONE; + if (tst->inject.err_code == FW_UPLOAD_ERR_NONE || + strncmp(tst->inject.prog, progress, strlen(progress)) != 0) + return FW_UPLOAD_ERR_NONE; + + if (tst->inject.err_code == FW_UPLOAD_ERR_CANCELED) + ret = fw_upload_wait_on_cancel(tst); + else + ret = tst->inject.err_code; + +err_out: + /* + * The cleanup op only executes if the prepare op succeeds. + * If the prepare op fails, it must do it's own clean-up. + */ + tst->inject.err_code = FW_UPLOAD_ERR_NONE; + tst->inject.prog = NULL; + + return ret; } static enum fw_upload_err test_fw_upload_write(struct fw_upload *fwl, @@ -1088,6 +1179,7 @@ static enum fw_upload_err test_fw_upload_write(struct fw_upload *fwl, u32 size, u32 *written) { struct test_firmware_upload *tst = fwl->dd_handle; + const char *progress = "transferring:"; u32 blk_size; if (tst->cancel_request) @@ -1097,17 +1189,33 @@ static enum fw_upload_err test_fw_upload_write(struct fw_upload *fwl, memcpy(tst->buf + offset, data + offset, blk_size); *written = blk_size; - return FW_UPLOAD_ERR_NONE; + + if (tst->inject.err_code == FW_UPLOAD_ERR_NONE || + strncmp(tst->inject.prog, progress, strlen(progress)) != 0) + return FW_UPLOAD_ERR_NONE; + + if (tst->inject.err_code == FW_UPLOAD_ERR_CANCELED) + return fw_upload_wait_on_cancel(tst); + + return tst->inject.err_code; } static enum fw_upload_err test_fw_upload_complete(struct fw_upload *fwl) { struct test_firmware_upload *tst = fwl->dd_handle; + const char *progress = "programming:"; if (tst->cancel_request) return FW_UPLOAD_ERR_CANCELED; - return FW_UPLOAD_ERR_NONE; + if (tst->inject.err_code == FW_UPLOAD_ERR_NONE || + strncmp(tst->inject.prog, progress, strlen(progress)) != 0) + return FW_UPLOAD_ERR_NONE; + + if (tst->inject.err_code == FW_UPLOAD_ERR_CANCELED) + return fw_upload_wait_on_cancel(tst); + + return tst->inject.err_code; } static void test_fw_upload_cancel(struct fw_upload *fwl) @@ -1117,11 +1225,20 @@ static void test_fw_upload_cancel(struct fw_upload *fwl) tst->cancel_request = true; } +static void test_fw_cleanup(struct fw_upload *fwl) +{ + struct test_firmware_upload *tst = fwl->dd_handle; + + tst->inject.err_code = FW_UPLOAD_ERR_NONE; + tst->inject.prog = NULL; +} + static const struct fw_upload_ops upload_test_ops = { .prepare = test_fw_upload_prepare, .write = test_fw_upload_write, .poll_complete = test_fw_upload_complete, .cancel = test_fw_upload_cancel, + .cleanup = test_fw_cleanup }; static ssize_t upload_register_store(struct device *dev, -- 2.25.1