From patchwork Sun Feb 27 20:56:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 12762142 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2B4B3C433EF for ; Sun, 27 Feb 2022 21:00:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ZxITepvjlpHNHf8rEWVlNavo5KUgoVNca5N+whQdhBc=; b=xpcXiAo/0sXQNZ Yw2q+3ax1RiArKN/SxRfiz7sKjygpEBRc7GzkGABfgUycgpSE/SBaqsvpgUlyk5+ihdG/YeOxFw5r B84iSAgC7Z2nxrd2maJ/VDr/0xBk3paTftYWp8MWGj0ynfsZM8CwfA8RJqyty7OlBMo9Czewv4Wmc +LDFf82mSHUh5T5xJZfn16UdwfyEf8h21XD/uUFjUJDEQReiPfTCvef5LogtB0fS9VINiTKt7qbvI 25Ja4dSqWHbGs1Rm8HVWYmJNzuUtgPx56zgjectUDQnG1IQEjOtTGULGX821CuQzYCI2eus3MErrC ZOoZH5sp0caMxumCnfgQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nOQdJ-00A8Z6-5K; Sun, 27 Feb 2022 20:59:09 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nOQar-00A7Cu-K5 for linux-arm-kernel@lists.infradead.org; Sun, 27 Feb 2022 20:56:40 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id EA12C11FB; Sun, 27 Feb 2022 12:56:36 -0800 (PST) Received: from e120937-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8D0713F66F; Sun, 27 Feb 2022 12:56:35 -0800 (PST) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, Jonathan.Cameron@Huawei.com, f.fainelli@gmail.com, vincent.guittot@linaro.org, souvik.chakravarty@arm.com, peter.hilber@opensynergy.com, cristian.marussi@arm.com Subject: [RFC PATCH 09/16] firmware: arm_scmi: testing: Add Clock protocol full support Date: Sun, 27 Feb 2022 20:56:01 +0000 Message-Id: <20220227205608.30812-10-cristian.marussi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220227205608.30812-1-cristian.marussi@arm.com> References: <20220227205608.30812-1-cristian.marussi@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220227_125637_830131_D6F70FD0 X-CRM114-Status: GOOD ( 20.31 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add SCMI Clock protocol testing support exposing SCMI Clock protocol operations under debugfs /sys/kernel/debug/scmi/protocol_0x14//, where the subdirectories represents each a distinct clock resource with ID equal . Signed-off-by: Cristian Marussi --- Documentation/ABI/testing/debugfs-scmi | 56 +++++++ .../arm_scmi/scmi_test_driver/test_clocks.c | 150 +++++++++++++++++- .../arm_scmi/scmi_test_driver/test_common.c | 48 ++++++ .../arm_scmi/scmi_test_driver/test_common.h | 1 + 4 files changed, 254 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/debugfs-scmi b/Documentation/ABI/testing/debugfs-scmi index 85177f3723c8..e91c19e7a323 100644 --- a/Documentation/ABI/testing/debugfs-scmi +++ b/Documentation/ABI/testing/debugfs-scmi @@ -99,3 +99,59 @@ Description: SCMI Clock Protocol informational RO data for clock resource named field of struct scmi_clock_info as documented in include/scmi/protocol.h Users: KSelftest, Debugging + +What: /sys/kernel/debug/scmi/protocol_0x14//rate_get_set +Date: Feb 2022 +KernelVersion: 5.19 +Contact: cristian.marussi@arm.com +Description: SCMI Clock Protocol rate get/set operation for clock resource + with id ; a read returns the currently set clock rate value + as a base-10 integer while the write of a base-10 integer sets a + new clock rate value. + Each R/W access invokes the corresponding SCMI Clock protocol + operations and issuing of needed SCMI commands. +Users: KSelftest, Debugging + +What: /sys/kernel/debug/scmi/protocol_0x14//enable +Date: Feb 2022 +KernelVersion: 5.19 +Contact: cristian.marussi@arm.com +Description: SCMI Clock Protocol enable operation for clock resource with id + ; writing a boolean value causes that specific clock to be + enabled or disabled. + No reference counting is kept: each write access invokes the + corresponding SCMI Clock protocol operations and issuing of + needed SCMI commands. +Users: KSelftest, Debugging + +What: /sys/kernel/debug/scmi/protocol_0x14//enable_atomic_irqs_on +Date: Feb 2022 +KernelVersion: 5.19 +Contact: cristian.marussi@arm.com +Description: SCMI Clock Protocol enable atomic operation for clock resource + with id ; writing a boolean value causes that specific + clock to be enabled or disabled using SCMI transport in polling + mode, if allowed by the underlying SCMI transport. + No reference counting is kept: each write access invokes the + corresponding SCMI Clock protocol operations and issuing of + needed SCMI commands. + Available only if the underlying SCMI transport is atomic + capable (/sys/kernel/debug/scmi/transport/is_atomic is True). +Users: KSelftest, Debugging + +What: /sys/kernel/debug/scmi/protocol_0x14//enable_atomic_irqs_off +Date: Feb 2022 +KernelVersion: 5.19 +Contact: cristian.marussi@arm.com +Description: SCMI Clock Protocol enable atomic operation for clock resource + with id ; writing a boolean value causes that specific + clock to be enabled or disabled using SCMI transport in polling + mode, if allowed by the underlying SCMI transport. + Local IRQs are disabled while the SCMI command transaction is + executed. + No reference counting is kept: each write access invokes the + corresponding SCMI Clock protocol operations and issuing of + needed SCMI commands. + Available only if the underlying SCMI transport is atomic + capable (/sys/kernel/debug/scmi/transport/is_atomic is True). +Users: KSelftest, Debugging diff --git a/drivers/firmware/arm_scmi/scmi_test_driver/test_clocks.c b/drivers/firmware/arm_scmi/scmi_test_driver/test_clocks.c index 3b9e92baa509..ae5b1af88f60 100644 --- a/drivers/firmware/arm_scmi/scmi_test_driver/test_clocks.c +++ b/drivers/firmware/arm_scmi/scmi_test_driver/test_clocks.c @@ -24,6 +24,139 @@ struct scmi_clock_data { const struct scmi_clock_info **clk_info; }; +static ssize_t scmi_test_clk_rate_get_read(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + int ret; + struct scmi_test_buffer *data = filp->private_data; + + if (!data) + return 0; + + if (!data->used) { + u64 rate; + struct scmi_test_setup *tsp = filp->f_inode->i_private; + const struct scmi_clk_proto_ops *clock_ops = tsp->ops; + + ret = clock_ops->rate_get(tsp->ph, data->id, &rate); + if (ret) + return ret; + + data->used = scnprintf(data->buf, data->len, "%lld\n", rate); + } + + return simple_read_from_buffer(buf, count, ppos, data->buf, data->used); +} + +static ssize_t scmi_test_clk_rate_get_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + int ret; + u64 rate; + struct scmi_test_setup *tsp = filp->f_inode->i_private; + const struct scmi_clk_proto_ops *clock_ops = tsp->ops; + struct scmi_test_buffer *data = filp->private_data; + + if (!data) + return 0; + + ret = kstrtou64_from_user(buf, count, 10, &rate); + if (ret < 0) + return ret; + + ret = clock_ops->rate_set(tsp->ph, data->id, rate); + if (ret) + return ret; + + return count; +} + +static const struct file_operations test_clk_rate_get_set_fops = { + .open = scmi_test_setup_open, + .release = scmi_test_release, + .read = scmi_test_clk_rate_get_read, + .write = scmi_test_clk_rate_get_write, +}; + +static ssize_t scmi_test_clk_enable_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + bool enabled, irqs_off; + int ret; + unsigned long flags; + struct scmi_test_setup *tsp = filp->f_inode->i_private; + const struct scmi_clk_proto_ops *clock_ops = tsp->ops; + struct scmi_test_buffer *data = filp->private_data; + + if (!data) + return 0; + + ret = kstrtobool_from_user(buf, count, &enabled); + if (ret) + return ret; + + irqs_off = !strncmp(filp->f_path.dentry->d_name.name, + "enable_atomic_irqs_off", + strlen("enable_atomic_irqs_off")); + if (irqs_off) + local_irq_save(flags); + + if (enabled) + ret = clock_ops->enable_atomic(tsp->ph, data->id); + else + ret = clock_ops->disable_atomic(tsp->ph, data->id); + + if (irqs_off) + local_irq_restore(flags); + + if (ret) + return ret; + + return count; +} + +static const struct file_operations test_clk_enable_fops = { + .open = scmi_test_setup_open, + .release = scmi_test_release, + .write = scmi_test_clk_enable_write, +}; + +static ssize_t scmi_test_clk_prepare_enable_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + bool enabled; + int ret; + struct scmi_test_setup *tsp = filp->f_inode->i_private; + const struct scmi_clk_proto_ops *clock_ops = tsp->ops; + struct scmi_test_buffer *data = filp->private_data; + + if (!data) + return 0; + + ret = kstrtobool_from_user(buf, count, &enabled); + if (ret) + return ret; + + if (enabled) + ret = clock_ops->enable(tsp->ph, data->id); + else + ret = clock_ops->disable(tsp->ph, data->id); + + if (ret) + return ret; + + return count; +} + +static const struct file_operations test_clk_prepare_enable_fops = { + .open = scmi_test_setup_open, + .release = scmi_test_release, + .write = scmi_test_clk_prepare_enable_write, +}; + static ssize_t scmi_test_clock_rates_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -130,9 +263,24 @@ int scmi_test_clock_init(struct scmi_test_setup *tsp) snprintf(clock_dir, 16, "%03d", i); clock_dentry = debugfs_create_dir(clock_dir, tsp->parent); - if (!IS_ERR(clock_dentry)) + if (!IS_ERR(clock_dentry)) { scmi_test_debugfs_clock_info_create(cdata->clk_info[i], clock_dentry); + debugfs_create_file("rate_get_set", 0600, + clock_dentry, tsp, + &test_clk_rate_get_set_fops); + if (tsp->sdev->handle->transport->is_atomic) { + debugfs_create_file("enable_atomic_irqs_off", + 0200, clock_dentry, tsp, + &test_clk_enable_fops); + debugfs_create_file("enable_atomic_irqs_on", + 0200, clock_dentry, tsp, + &test_clk_enable_fops); + } + debugfs_create_file("enable", 0200, + clock_dentry, tsp, + &test_clk_prepare_enable_fops); + } } return 0; diff --git a/drivers/firmware/arm_scmi/scmi_test_driver/test_common.c b/drivers/firmware/arm_scmi/scmi_test_driver/test_common.c index 1a4b6aa35095..cbe2eec4f2ac 100644 --- a/drivers/firmware/arm_scmi/scmi_test_driver/test_common.c +++ b/drivers/firmware/arm_scmi/scmi_test_driver/test_common.c @@ -15,6 +15,54 @@ #include "test_common.h" /* Common File operations */ + +/** + * scmi_test_setup_open - A common open helper + * @ino: Related inode reference + * @filp: Related file pointer reference + * + * Expects to receive a struct scmi_test_setup via inode i_private reference and + * then allocate a properly sized buffer; it also tries to parse the parent + * directory name in search for a base10 integer and, if found, stores it into + * the buffer descriptor @id field: this comes handy since most of the SCMI + * protocol operations and data are bound to some specific SCMI resource id and + * the SCMI debugfs directory tree is structured to mirror this layout, so that, + * as an example, protocol would expose about its resource + * with id as: + * + * /sys/kernel/debug/scmi/protocol_0x// + * + * As as result this open would allocate a data buffer, parse the dentry and + * set data->id = + * + * Return: 0 on Success + */ +int scmi_test_setup_open(struct inode *ino, struct file *filp) +{ + unsigned int id; + size_t blen; + struct scmi_test_buffer *data; + struct scmi_test_setup *tsp = filp->f_inode->i_private; + const char *id_str = filp->f_path.dentry->d_parent->d_name.name; + + if (!tsp) + return -EINVAL; + + blen = tsp->blen ?: SCMI_TEST_DEFAULT_BUF_SZ; + data = kzalloc(sizeof(*data) + blen, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->len = blen; + /* Grab clk ID from debugfs entry naming if any */ + if (!kstrtouint(id_str, 10, &id)) + data->id = id; + + filp->private_data = data; + + return 0; +} + int scmi_test_release(struct inode *ino, struct file *filp) { kfree(filp->private_data); diff --git a/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h b/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h index 1ff5bbc32ae3..3c64cae9fae9 100644 --- a/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h +++ b/drivers/firmware/arm_scmi/scmi_test_driver/test_common.h @@ -68,6 +68,7 @@ struct scmi_test_buffer { extern const struct file_operations scmi_test_string_file_fops; +int scmi_test_setup_open(struct inode *ino, struct file *filp); int scmi_test_fixed_buffer_open(struct inode *ino, struct file *filp); int scmi_test_release(struct inode *ino, struct file *filp);