From patchwork Fri Apr 19 16:47:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790708 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5FBE6130A5B; Fri, 19 Apr 2024 16:47:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545266; cv=none; b=AiB4Me3VbGzxRAGwb6CUWk0nwUAxSbQ7uvrv3tN7ewkluHFncvbDNGhJLR6HeEbkk2wJFPVaAtt62GfEaVBZI/huUsxqO3/4EiAuA3JSQRscslb3BV8QTNMJmJSlI6uSBUUlJzSilENwrMkZ89WWGdMbAQGtjRPpS8N12yicyNs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545266; c=relaxed/simple; bh=FLmy9nGhpeQpzNEGELd6fb1fl1kbOZbYo1/FiZ5frWc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MBj/tJeq2NCNK6RbCfR7UWlCXCZ6M5JzSyfhe0DNQPLj4r59NBlTJZmAQTBSQIlmDsK4czrsZwx+0vVLiuXffGK27wh5MvjePBjzJZiLwwd0voIN8qUKcD0Z0lhWZyFTjC/i4Lnf/NO1MT/iQLFH0cPwKk2G8BnKUCfvLkuTizA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.31]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgW31Gl2z6K626; Sat, 20 Apr 2024 00:45:35 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 0DB10140A70; Sat, 20 Apr 2024 00:47:42 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:41 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 01/10] ras: scrub: Add scrub subsystem Date: Sat, 20 Apr 2024 00:47:10 +0800 Message-ID: <20240419164720.1765-2-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Add scrub subsystem supports configuring the memory scrubbers in the system. The scrub subsystem provides the interface for registering the scrub devices. The scrub control attributes are provided to the user in /sys/class/ras/rasX/scrub Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- .../ABI/testing/sysfs-class-scrub-configure | 47 +++ drivers/ras/Kconfig | 7 + drivers/ras/Makefile | 1 + drivers/ras/memory_scrub.c | 271 ++++++++++++++++++ include/linux/memory_scrub.h | 37 +++ 5 files changed, 363 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-scrub-configure create mode 100755 drivers/ras/memory_scrub.c create mode 100755 include/linux/memory_scrub.h diff --git a/Documentation/ABI/testing/sysfs-class-scrub-configure b/Documentation/ABI/testing/sysfs-class-scrub-configure new file mode 100644 index 000000000000..3ed77dbb00ad --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-scrub-configure @@ -0,0 +1,47 @@ +What: /sys/class/ras/ +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + The ras/ class subdirectory belongs to the + common ras features such as scrub subsystem. + +What: /sys/class/ras/rasX/scrub/ +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + The /sys/class/ras/ras{0,1,2,3,...}/scrub directories + correspond to each scrub device registered with the + scrub subsystem. + +What: /sys/class/ras/rasX/scrub/name +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) name of the memory scrubber + +What: /sys/class/ras/rasX/scrub/enable_background +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + (RW) Enable/Disable background(patrol) scrubbing if supported. + +What: /sys/class/ras/rasX/scrub/rate_available +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) Supported range for the scrub rate by the scrubber. + The scrub rate represents in hours. + +What: /sys/class/ras/rasX/scrub/rate +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + (RW) The scrub rate specified and it must be with in the + supported range by the scrubber. + The scrub rate represents in hours. diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig index fc4f4bb94a4c..181701479564 100644 --- a/drivers/ras/Kconfig +++ b/drivers/ras/Kconfig @@ -46,4 +46,11 @@ config RAS_FMPM Memory will be retired during boot time and run time depending on platform-specific policies. +config SCRUB + tristate "Memory scrub driver" + help + This option selects the memory scrub subsystem, supports + configuring the parameters of underlying scrubbers in the + system for the DRAM memories. + endif diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile index 11f95d59d397..89bcf0d84355 100644 --- a/drivers/ras/Makefile +++ b/drivers/ras/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_RAS) += ras.o obj-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_RAS_CEC) += cec.o +obj-$(CONFIG_SCRUB) += memory_scrub.o obj-$(CONFIG_RAS_FMPM) += amd/fmpm.o obj-y += amd/atl/ diff --git a/drivers/ras/memory_scrub.c b/drivers/ras/memory_scrub.c new file mode 100755 index 000000000000..7e995380ec3a --- /dev/null +++ b/drivers/ras/memory_scrub.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Memory scrub subsystem supports configuring the registered + * memory scrubbers. + * + * Copyright (c) 2024 HiSilicon Limited. + */ + +#define pr_fmt(fmt) "MEM SCRUB: " fmt + +#include +#include +#include +#include +#include +#include +#include + +/* memory scrubber config definitions */ +#define SCRUB_ID_PREFIX "ras" +#define SCRUB_ID_FORMAT SCRUB_ID_PREFIX "%d" + +static DEFINE_IDA(scrub_ida); + +struct scrub_device { + int id; + struct device dev; + const struct scrub_ops *ops; +}; + +#define to_scrub_device(d) container_of(d, struct scrub_device, dev) +static ssize_t enable_background_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + ret = scrub_dev->ops->set_enabled_bg(dev, enable); + if (ret) + return ret; + + return len; +} + +static ssize_t enable_background_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + bool enable; + int ret; + + ret = scrub_dev->ops->get_enabled_bg(dev, &enable); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", enable); +} + +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + int ret; + + ret = scrub_dev->ops->get_name(dev, buf); + if (ret) + return ret; + + return strlen(buf); +} + +static ssize_t rate_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + u64 val; + int ret; + + ret = scrub_dev->ops->rate_read(dev, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%llx\n", val); +} + +static ssize_t rate_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + ret = scrub_dev->ops->rate_write(dev, val); + if (ret) + return ret; + + return len; +} + +static ssize_t rate_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + u64 min_sr, max_sr; + int ret; + + ret = scrub_dev->ops->rate_avail_range(dev, &min_sr, &max_sr); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%llx-0x%llx\n", min_sr, max_sr); +} + +DEVICE_ATTR_RW(enable_background); +DEVICE_ATTR_RO(name); +DEVICE_ATTR_RW(rate); +DEVICE_ATTR_RO(rate_available); + +static struct attribute *scrub_attrs[] = { + &dev_attr_enable_background.attr, + &dev_attr_name.attr, + &dev_attr_rate.attr, + &dev_attr_rate_available.attr, + NULL +}; + +static umode_t scrub_attr_visible(struct kobject *kobj, + struct attribute *a, int attr_id) +{ + struct device *dev = kobj_to_dev(kobj); + struct scrub_device *scrub_dev = to_scrub_device(dev); + const struct scrub_ops *ops = scrub_dev->ops; + + if (a == &dev_attr_enable_background.attr) { + if (ops->set_enabled_bg && ops->get_enabled_bg) + return a->mode; + if (ops->get_enabled_bg) + return 0444; + return 0; + } + if (a == &dev_attr_name.attr) + return ops->get_name ? a->mode : 0; + if (a == &dev_attr_rate_available.attr) + return ops->rate_avail_range ? a->mode : 0; + if (a == &dev_attr_rate.attr) { /* Write only makes little sense */ + if (ops->rate_read && ops->rate_write) + return a->mode; + if (ops->rate_read) + return 0444; + return 0; + } + + return 0; +} + +static const struct attribute_group scrub_attr_group = { + .name = "scrub", + .attrs = scrub_attrs, + .is_visible = scrub_attr_visible, +}; + +static const struct attribute_group *scrub_attr_groups[] = { + &scrub_attr_group, + NULL +}; + +static void scrub_dev_release(struct device *dev) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + + ida_free(&scrub_ida, scrub_dev->id); + kfree(scrub_dev); +} + +static struct class scrub_class = { + .name = "ras", + .dev_groups = scrub_attr_groups, + .dev_release = scrub_dev_release, +}; + +static struct device * +scrub_device_register(struct device *parent, void *drvdata, + const struct scrub_ops *ops) +{ + struct scrub_device *scrub_dev; + struct device *hdev; + int err; + + scrub_dev = kzalloc(sizeof(*scrub_dev), GFP_KERNEL); + if (!scrub_dev) + return ERR_PTR(-ENOMEM); + hdev = &scrub_dev->dev; + + scrub_dev->id = ida_alloc(&scrub_ida, GFP_KERNEL); + if (scrub_dev->id < 0) { + kfree(scrub_dev); + return ERR_PTR(-ENOMEM); + } + + scrub_dev->ops = ops; + hdev->class = &scrub_class; + hdev->parent = parent; + dev_set_drvdata(hdev, drvdata); + dev_set_name(hdev, SCRUB_ID_FORMAT, scrub_dev->id); + err = device_register(hdev); + if (err) { + put_device(hdev); + return ERR_PTR(err); + } + + return hdev; +} + +static void devm_scrub_release(void *dev) +{ + device_unregister(dev); +} + +/** + * devm_scrub_device_register - register scrubber device + * @dev: the parent device + * @drvdata: driver data to attach to the scrub device + * @ops: pointer to scrub_ops structure (optional) + * + * Returns the pointer to the new device on success, ERR_PTR() otherwise. + * The new device would be automatically unregistered with the parent device. + */ +struct device * +devm_scrub_device_register(struct device *dev, void *drvdata, + const struct scrub_ops *ops) +{ + struct device *hdev; + int ret; + + if (!dev) + return ERR_PTR(-EINVAL); + + hdev = scrub_device_register(dev, drvdata, ops); + if (IS_ERR(hdev)) + return hdev; + + ret = devm_add_action_or_reset(dev, devm_scrub_release, hdev); + if (ret) + return ERR_PTR(ret); + + return hdev; +} +EXPORT_SYMBOL_GPL(devm_scrub_device_register); + +static int __init memory_scrub_control_init(void) +{ + return class_register(&scrub_class); +} +subsys_initcall(memory_scrub_control_init); + +static void memory_scrub_control_exit(void) +{ + class_unregister(&scrub_class); +} +module_exit(memory_scrub_control_exit); diff --git a/include/linux/memory_scrub.h b/include/linux/memory_scrub.h new file mode 100755 index 000000000000..f0e1657a5072 --- /dev/null +++ b/include/linux/memory_scrub.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Memory scrub subsystem driver supports controlling + * the memory scrubbers in the system. + * + * Copyright (c) 2024 HiSilicon Limited. + */ + +#ifndef __MEMORY_SCRUB_H +#define __MEMORY_SCRUB_H + +#include + +struct device; + +/** + * struct scrub_ops - scrub device operations (all elements optional) + * @get_enabled_bg: check if currently performing background scrub. + * @set_enabled_bg: start or stop a bg-scrub. + * @get_name: get the memory scrubber name. + * @rate_avail_range: retrieve limits on supported rates. + * @rate_read: read the scrub rate + * @rate_write: set the scrub rate + */ +struct scrub_ops { + int (*get_enabled_bg)(struct device *dev, bool *enable); + int (*set_enabled_bg)(struct device *dev, bool enable); + int (*get_name)(struct device *dev, char *buf); + int (*rate_avail_range)(struct device *dev, u64 *min, u64 *max); + int (*rate_read)(struct device *dev, u64 *rate); + int (*rate_write)(struct device *dev, u64 rate); +}; + +struct device * +devm_scrub_device_register(struct device *dev, void *drvdata, + const struct scrub_ops *ops); +#endif /* __MEMORY_SCRUB_H */ From patchwork Fri Apr 19 16:47:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790707 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9D13C136678; Fri, 19 Apr 2024 16:47:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545267; cv=none; b=WAp7k6KUKxfF0iG2LvIpEhayPWmTMiBh22/OnSA7PKlwoeUy0VdwaS77wGjn8a7xUGmto8BEAeMWSPa3zWgTZZJJ2/7xQGrakkSs/KE5+hJ2TMQMzzrIow7twUPb5XUMvL+fKEvc5BXFgCIOcIjOUNy98aGJf/gDOhAGqqqzTgc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545267; c=relaxed/simple; bh=vxeDJBGJmcE4zin4YPrW480rqgvwsh0z7OcUlNEIshA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=n98xeEWtuOQY5HMA2IF5nVQAP/8e30S34oagUIIVmXAG2X4y6vR+6sDs59XKaI5aRd9LyFgE51znS3yY2wXf/Jd1zwlURLhhOt7M4QKg0uliT6rvDm20Wd8njIDO5lSRXH6xErD8DZQbqpKGnC3i5tEGV8UqKZBTGFoYJ/9sfao= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.216]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgYT6Q5zz6K8xt; Sat, 20 Apr 2024 00:47:41 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 45AEA140447; Sat, 20 Apr 2024 00:47:43 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:42 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 02/10] cxl/mbox: Add GET_SUPPORTED_FEATURES mailbox command Date: Sat, 20 Apr 2024 00:47:11 +0800 Message-ID: <20240419164720.1765-3-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Add support for GET_SUPPORTED_FEATURES mailbox command. CXL spec 3.1 section 8.2.9.6 describes optional device specific features. CXL devices supports features with changeable attributes. Get Supported Features retrieves the list of supported device specific features. The settings of a feature can be retrieved using Get Feature and optionally modified using Set Feature. Signed-off-by: Shiju Jose --- drivers/cxl/core/mbox.c | 27 ++++++++++++++++++ drivers/cxl/cxlmem.h | 61 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index f0f54aeccc87..82e279b821e2 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1291,6 +1291,33 @@ int cxl_set_timestamp(struct cxl_memdev_state *mds) } EXPORT_SYMBOL_NS_GPL(cxl_set_timestamp, CXL); +int cxl_get_supported_features(struct cxl_memdev_state *mds, + u32 count, u16 start_index, + struct cxl_mbox_get_supp_feats_out *feats_out) +{ + struct cxl_mbox_get_supp_feats_in pi; + struct cxl_mbox_cmd mbox_cmd; + int rc; + + pi.count = cpu_to_le32(count); + pi.start_index = cpu_to_le16(start_index); + + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_GET_SUPPORTED_FEATURES, + .size_in = sizeof(pi), + .payload_in = &pi, + .size_out = count, + .payload_out = feats_out, + .min_out = sizeof(*feats_out), + }; + rc = cxl_internal_send_cmd(mds, &mbox_cmd); + if (rc < 0) + return rc; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_get_supported_features, CXL); + int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, struct cxl_region *cxlr) { diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 36cee9c30ceb..06231e63373e 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -527,6 +527,7 @@ enum cxl_opcode { CXL_MBOX_OP_SET_TIMESTAMP = 0x0301, CXL_MBOX_OP_GET_SUPPORTED_LOGS = 0x0400, CXL_MBOX_OP_GET_LOG = 0x0401, + CXL_MBOX_OP_GET_SUPPORTED_FEATURES = 0x0500, CXL_MBOX_OP_IDENTIFY = 0x4000, CXL_MBOX_OP_GET_PARTITION_INFO = 0x4100, CXL_MBOX_OP_SET_PARTITION_INFO = 0x4101, @@ -696,6 +697,63 @@ struct cxl_mbox_set_timestamp_in { } __packed; +/* + * Get Supported Features CXL 3.1 Spec 8.2.9.6.1 + */ + +/* + * Get Supported Features input payload + * CXL rev 3.1 section 8.2.9.6.1 Table 8-95 + */ +struct cxl_mbox_get_supp_feats_in { + __le32 count; + __le16 start_index; + u8 rsvd[2]; +} __packed; + +/* + * Get Supported Features Supported Feature Entry + * CXL rev 3.1 section 8.2.9.6.1 Table 8-97 + */ +/* Supported Feature Entry : Payload out attribute flags */ +#define CXL_FEAT_ENTRY_FLAG_CHANGABLE BIT(0) +#define CXL_FEAT_ENTRY_FLAG_DEEPEST_RESET_PERSISTENCE_MASK GENMASK(3, 1) +#define CXL_FEAT_ENTRY_FLAG_PERSIST_ACROSS_FIRMWARE_UPDATE BIT(4) +#define CXL_FEAT_ENTRY_FLAG_SUPPORT_DEFAULT_SELECTION BIT(5) +#define CXL_FEAT_ENTRY_FLAG_SUPPORT_SAVED_SELECTION BIT(6) + +enum cxl_feat_attr_value_persistence { + CXL_FEAT_ATTR_VALUE_PERSISTENCE_NONE, + CXL_FEAT_ATTR_VALUE_PERSISTENCE_CXL_RESET, + CXL_FEAT_ATTR_VALUE_PERSISTENCE_HOT_RESET, + CXL_FEAT_ATTR_VALUE_PERSISTENCE_WARM_RESET, + CXL_FEAT_ATTR_VALUE_PERSISTENCE_COLD_RESET, + CXL_FEAT_ATTR_VALUE_PERSISTENCE_MAX +}; + +struct cxl_mbox_supp_feat_entry { + uuid_t uuid; + __le16 index; + __le16 get_size; + __le16 set_size; + __le32 attr_flags; + u8 get_version; + u8 set_version; + __le16 set_effects; + u8 rsvd[18]; +} __packed; + +/* + * Get Supported Features output payload + * CXL rev 3.1 section 8.2.9.6.1 Table 8-96 + */ +struct cxl_mbox_get_supp_feats_out { + __le16 nr_entries; + __le16 nr_supported; + u8 rsvd[4]; + struct cxl_mbox_supp_feat_entry feat_entries[]; +} __packed; + /* Get Poison List CXL 3.0 Spec 8.2.9.8.4.1 */ struct cxl_mbox_poison_in { __le64 offset; @@ -827,6 +885,9 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_type event_type, const uuid_t *uuid, union cxl_event *evt); int cxl_set_timestamp(struct cxl_memdev_state *mds); +int cxl_get_supported_features(struct cxl_memdev_state *mds, + u32 count, u16 start_index, + struct cxl_mbox_get_supp_feats_out *feats_out); int cxl_poison_state_init(struct cxl_memdev_state *mds); int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, struct cxl_region *cxlr); From patchwork Fri Apr 19 16:47:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790264 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E1E05136E1C; Fri, 19 Apr 2024 16:47:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545268; cv=none; b=YkNHTPuHrv3feeLoThnTac1OZbWCONsa9qLoMrEVeampwlfdc3y0riyLHuwAoG3OKY1mOHZf/jdnBrKh8VY9zinUWtfMVLJs0gMoAHovmmgE+2q4iFWQVQkKhLS62w6dvUASEuhCsdUX69AbFL+85aFbGwNFatWGAxn+9KznWRo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545268; c=relaxed/simple; bh=reI3SeEHSCKIoQsRob7GvElPx06URHqGNZxJaNYoxFY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YynhxsZi0HBh8rVoikk3RU5vBr00al10c/WmFzX4FqOugAI8zNW7E1GxTgJ8p/ZmnA9iCgROJR7fdfH13Qwhup9feEQ1Z57XzUR+U8ECiFV5ioyyICkmf6gD77R+8KujxTwtiYrpNeSJHXECQyDPDlrXhM+qrXVeqTauFuRTwPM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgW536scz6K62B; Sat, 20 Apr 2024 00:45:37 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 54086140AB8; Sat, 20 Apr 2024 00:47:44 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:43 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 03/10] cxl/mbox: Add GET_FEATURE mailbox command Date: Sat, 20 Apr 2024 00:47:12 +0800 Message-ID: <20240419164720.1765-4-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Add support for GET_FEATURE mailbox command. CXL spec 3.1 section 8.2.9.6 describes optional device specific features. The settings of a feature can be retrieved using Get Feature command. Signed-off-by: Shiju Jose --- drivers/cxl/core/mbox.c | 53 +++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 28 ++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 82e279b821e2..999965871048 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1318,6 +1318,59 @@ int cxl_get_supported_features(struct cxl_memdev_state *mds, } EXPORT_SYMBOL_NS_GPL(cxl_get_supported_features, CXL); +size_t cxl_get_feature(struct cxl_memdev_state *mds, + const uuid_t feat_uuid, void *feat_out, + size_t feat_out_size, + size_t feat_out_min_size, + enum cxl_get_feat_selection selection) +{ + struct cxl_dev_state *cxlds = &mds->cxlds; + struct cxl_mbox_get_feat_in pi; + struct cxl_mbox_cmd mbox_cmd; + size_t data_rcvd_size = 0; + size_t data_to_rd_size, size_out; + int rc; + + if (feat_out_size < feat_out_min_size) { + dev_err(cxlds->dev, + "%s: feature out buffer size(%lu) is not big enough\n", + __func__, feat_out_size); + return 0; + } + + if (feat_out_size <= mds->payload_size) + size_out = feat_out_size; + else + size_out = mds->payload_size; + pi.uuid = feat_uuid; + pi.selection = selection; + do { + if ((feat_out_min_size - data_rcvd_size) <= mds->payload_size) + data_to_rd_size = feat_out_min_size - data_rcvd_size; + else + data_to_rd_size = mds->payload_size; + + pi.offset = cpu_to_le16(data_rcvd_size); + pi.count = cpu_to_le16(data_to_rd_size); + + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_GET_FEATURE, + .size_in = sizeof(pi), + .payload_in = &pi, + .size_out = size_out, + .payload_out = feat_out + data_rcvd_size, + .min_out = data_to_rd_size, + }; + rc = cxl_internal_send_cmd(mds, &mbox_cmd); + if (rc < 0 || mbox_cmd.size_out == 0) + return 0; + data_rcvd_size += mbox_cmd.size_out; + } while (data_rcvd_size < feat_out_min_size); + + return data_rcvd_size; +} +EXPORT_SYMBOL_NS_GPL(cxl_get_feature, CXL); + int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, struct cxl_region *cxlr) { diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 06231e63373e..c822eb30e6d1 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -528,6 +528,7 @@ enum cxl_opcode { CXL_MBOX_OP_GET_SUPPORTED_LOGS = 0x0400, CXL_MBOX_OP_GET_LOG = 0x0401, CXL_MBOX_OP_GET_SUPPORTED_FEATURES = 0x0500, + CXL_MBOX_OP_GET_FEATURE = 0x0501, CXL_MBOX_OP_IDENTIFY = 0x4000, CXL_MBOX_OP_GET_PARTITION_INFO = 0x4100, CXL_MBOX_OP_SET_PARTITION_INFO = 0x4101, @@ -754,6 +755,28 @@ struct cxl_mbox_get_supp_feats_out { struct cxl_mbox_supp_feat_entry feat_entries[]; } __packed; +/* + * Get Feature CXL 3.1 Spec 8.2.9.6.2 + */ + +/* + * Get Feature input payload + * CXL rev 3.1 section 8.2.9.6.2 Table 8-99 + */ +enum cxl_get_feat_selection { + CXL_GET_FEAT_SEL_CURRENT_VALUE, + CXL_GET_FEAT_SEL_DEFAULT_VALUE, + CXL_GET_FEAT_SEL_SAVED_VALUE, + CXL_GET_FEAT_SEL_MAX +}; + +struct cxl_mbox_get_feat_in { + uuid_t uuid; + __le16 offset; + __le16 count; + u8 selection; +} __packed; + /* Get Poison List CXL 3.0 Spec 8.2.9.8.4.1 */ struct cxl_mbox_poison_in { __le64 offset; @@ -888,6 +911,11 @@ int cxl_set_timestamp(struct cxl_memdev_state *mds); int cxl_get_supported_features(struct cxl_memdev_state *mds, u32 count, u16 start_index, struct cxl_mbox_get_supp_feats_out *feats_out); +size_t cxl_get_feature(struct cxl_memdev_state *mds, + const uuid_t feat_uuid, void *feat_out, + size_t feat_out_size, + size_t feat_out_min_size, + enum cxl_get_feat_selection selection); int cxl_poison_state_init(struct cxl_memdev_state *mds); int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, struct cxl_region *cxlr); From patchwork Fri Apr 19 16:47:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790263 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0043213AD1E; Fri, 19 Apr 2024 16:47:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545271; cv=none; b=lSsD97NEcHTWtaS7IsNF4qgKqaf9H32Z4e7Z01yGtt7TNa7ZkB8cbEBKXrvDDBZKWJce6PcIJZQwp9H9xpRe7Q1DequWcv5eNoq2zsvADjhgxvw8ghpJvkv9NFGBq7rqcuDaAXUX/bJYFcjN+1BpnoVTRO9VoGOVUHU2AOnLd9A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545271; c=relaxed/simple; bh=aXgDUKRqY8QAqkzAHeRiKxyCzJOiL8X4c8Y7aaDhP/A=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QlP2EBY78e+KiDhjY7rEXE8hV/oAq70FfKLvCrtU26PquBAhAWPN8Sj9RoOgnpRCUQCxSSoD0QW5abFr5p8I0N1yxi+FXcpN2oDcHrmeridXq5TjxueB27Uny3huqMO63ezhdBAqk4g+eqEJasi2UIu7Q4a9/jYUoM0VLnYSmXs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgW90KVRz6K62N; Sat, 20 Apr 2024 00:45:41 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id DAB6A140B55; Sat, 20 Apr 2024 00:47:47 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:44 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 04/10] cxl/mbox: Add SET_FEATURE mailbox command Date: Sat, 20 Apr 2024 00:47:13 +0800 Message-ID: <20240419164720.1765-5-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Add support for SET_FEATURE mailbox command. CXL spec 3.1 section 8.2.9.6 describes optional device specific features. CXL devices supports features with changeable attributes. The settings of a feature can be optionally modified using Set Feature command. Signed-off-by: Shiju Jose --- drivers/cxl/core/mbox.c | 73 +++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 33 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 999965871048..4ca1238e8fec 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1371,6 +1371,79 @@ size_t cxl_get_feature(struct cxl_memdev_state *mds, } EXPORT_SYMBOL_NS_GPL(cxl_get_feature, CXL); +/* + * FEAT_DATA_MIN_PAYLOAD_SIZE - min extra number of bytes should be + * available in the mailbox for storing the actual feature data so that + * the feature data transfer would work as expected. + */ +#define FEAT_DATA_MIN_PAYLOAD_SIZE 10 +int cxl_set_feature(struct cxl_memdev_state *mds, + const uuid_t feat_uuid, u8 feat_version, + void *feat_data, size_t feat_data_size, + u8 feat_flag) +{ + struct cxl_memdev_set_feat_pi { + struct cxl_mbox_set_feat_hdr hdr; + u8 feat_data[]; + } __packed; + size_t data_in_size, data_sent_size = 0; + struct cxl_mbox_cmd mbox_cmd; + size_t hdr_size; + int rc = 0; + + struct cxl_memdev_set_feat_pi *pi __free(kfree) = + kmalloc(mds->payload_size, GFP_KERNEL); + pi->hdr.uuid = feat_uuid; + pi->hdr.version = feat_version; + feat_flag &= ~CXL_SET_FEAT_FLAG_DATA_TRANSFER_MASK; + hdr_size = sizeof(pi->hdr); + /* + * Check minimum mbox payload size is available for + * the feature data transfer. + */ + if (hdr_size + FEAT_DATA_MIN_PAYLOAD_SIZE > mds->payload_size) + return -ENOMEM; + + if ((hdr_size + feat_data_size) <= mds->payload_size) { + pi->hdr.flags = cpu_to_le32(feat_flag | + CXL_SET_FEAT_FLAG_FULL_DATA_TRANSFER); + data_in_size = feat_data_size; + } else { + pi->hdr.flags = cpu_to_le32(feat_flag | + CXL_SET_FEAT_FLAG_INITIATE_DATA_TRANSFER); + data_in_size = mds->payload_size - hdr_size; + } + + do { + pi->hdr.offset = cpu_to_le16(data_sent_size); + memcpy(pi->feat_data, feat_data + data_sent_size, data_in_size); + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_SET_FEATURE, + .size_in = hdr_size + data_in_size, + .payload_in = pi, + }; + rc = cxl_internal_send_cmd(mds, &mbox_cmd); + if (rc < 0) + return rc; + + data_sent_size += data_in_size; + if (data_sent_size >= feat_data_size) + return 0; + + if ((feat_data_size - data_sent_size) <= (mds->payload_size - hdr_size)) { + data_in_size = feat_data_size - data_sent_size; + pi->hdr.flags = cpu_to_le32(feat_flag | + CXL_SET_FEAT_FLAG_FINISH_DATA_TRANSFER); + } else { + pi->hdr.flags = cpu_to_le32(feat_flag | + CXL_SET_FEAT_FLAG_CONTINUE_DATA_TRANSFER); + } + } while (true); + + return rc; +} +EXPORT_SYMBOL_NS_GPL(cxl_set_feature, CXL); + int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, struct cxl_region *cxlr) { diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index c822eb30e6d1..1c50a3e2eced 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -529,6 +529,7 @@ enum cxl_opcode { CXL_MBOX_OP_GET_LOG = 0x0401, CXL_MBOX_OP_GET_SUPPORTED_FEATURES = 0x0500, CXL_MBOX_OP_GET_FEATURE = 0x0501, + CXL_MBOX_OP_SET_FEATURE = 0x0502, CXL_MBOX_OP_IDENTIFY = 0x4000, CXL_MBOX_OP_GET_PARTITION_INFO = 0x4100, CXL_MBOX_OP_SET_PARTITION_INFO = 0x4101, @@ -777,6 +778,34 @@ struct cxl_mbox_get_feat_in { u8 selection; } __packed; +/* + * Set Feature CXL 3.1 Spec 8.2.9.6.3 + */ + +/* + * Set Feature input payload + * CXL rev 3.1 section 8.2.9.6.3 Table 8-101 + */ +/* Set Feature : Payload in flags */ +#define CXL_SET_FEAT_FLAG_DATA_TRANSFER_MASK GENMASK(2, 0) +enum cxl_set_feat_flag_data_transfer { + CXL_SET_FEAT_FLAG_FULL_DATA_TRANSFER, + CXL_SET_FEAT_FLAG_INITIATE_DATA_TRANSFER, + CXL_SET_FEAT_FLAG_CONTINUE_DATA_TRANSFER, + CXL_SET_FEAT_FLAG_FINISH_DATA_TRANSFER, + CXL_SET_FEAT_FLAG_ABORT_DATA_TRANSFER, + CXL_SET_FEAT_FLAG_DATA_TRANSFER_MAX +}; +#define CXL_SET_FEAT_FLAG_DATA_SAVED_ACROSS_RESET BIT(3) + +struct cxl_mbox_set_feat_hdr { + uuid_t uuid; + __le32 flags; + __le16 offset; + u8 version; + u8 rsvd[9]; +} __packed; + /* Get Poison List CXL 3.0 Spec 8.2.9.8.4.1 */ struct cxl_mbox_poison_in { __le64 offset; @@ -916,6 +945,10 @@ size_t cxl_get_feature(struct cxl_memdev_state *mds, size_t feat_out_size, size_t feat_out_min_size, enum cxl_get_feat_selection selection); +int cxl_set_feature(struct cxl_memdev_state *mds, + const uuid_t feat_uuid, u8 feat_version, + void *feat_data, size_t feat_data_size, + u8 feat_flag); int cxl_poison_state_init(struct cxl_memdev_state *mds); int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, struct cxl_region *cxlr); From patchwork Fri Apr 19 16:47:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790262 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 003C113AD1B; Fri, 19 Apr 2024 16:47:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545272; cv=none; b=Y86V9H1+X8MJ1vj0t1JcJ9e5clqHElC/HAcf+MPZ1XWHm8N4lesBgfEOuJvuiwAZvqTE/nXProXmssdL2YysP6YqcSw4vidQbja7y2H3z8390gJ73IIKT9hnTk4jwqCqCN7BNivZtQUUi9JtQOMnot+k+31Ye0nBg6CynbMhL10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545272; c=relaxed/simple; bh=/CinCs2Fq+4HX9AWVODe8ElHHF3SMTDntQaPjQydwyY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=R1Rv1LCiBxXjhIwxjEBoBKbPdJeSfo/pqg3En0w201YIrqaVL0+Z24BtJ2ZqYqbcx3NxIqgdSlzXgovf5VMdtW8cvEHAlRah5e+wP6+am1fzrL7IaQQpNigvLjV9+B0faDbvdTX0eR+EYExXRomdcSnV7hJZUDqt3MCQAjyTNJM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgYZ3xc9z6K8xv; Sat, 20 Apr 2024 00:47:46 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id E9E25140B63; Sat, 20 Apr 2024 00:47:47 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:45 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 05/10] cxl/memscrub: Add CXL device patrol scrub control feature Date: Sat, 20 Apr 2024 00:47:14 +0800 Message-ID: <20240419164720.1765-6-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose CXL spec 3.1 section 8.2.9.9.11.1 describes the device patrol scrub control feature. The device patrol scrub proactively locates and makes corrections to errors in regular cycle. Allow specifying the number of hours within which the patrol scrub must be completed, subject to minimum and maximum limits reported by the device. Also allow disabling scrub allowing trade-off error rates against performance. Register with scrub subsystem to provide scrub control attributes to the user. Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- Documentation/scrub/scrub-configure.rst | 52 ++++ drivers/cxl/Kconfig | 19 ++ drivers/cxl/core/Makefile | 1 + drivers/cxl/core/memscrub.c | 314 ++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 8 + drivers/cxl/mem.c | 6 + 6 files changed, 400 insertions(+) create mode 100644 Documentation/scrub/scrub-configure.rst create mode 100644 drivers/cxl/core/memscrub.c diff --git a/Documentation/scrub/scrub-configure.rst b/Documentation/scrub/scrub-configure.rst new file mode 100644 index 000000000000..2275366b60d3 --- /dev/null +++ b/Documentation/scrub/scrub-configure.rst @@ -0,0 +1,52 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================ +Scrub subsystem +================ + +Copyright (c) 2024 HiSilicon Limited. + +:Author: Shiju Jose +:License: The GNU Free Documentation License, Version 1.2 + (dual licensed under the GPL v2) +:Original Reviewers: + +- Written for: 6.9 +- Updated for: + +Introduction +------------ +The scrub subsystem provides interface for controlling attributes +of memory scrubbers in the system. The scrub device drivers +in the system register with the scrub subsystem.The scrub subsystem +driver exposes the scrub controls to the user in the sysfs. + +The File System +--------------- + +The control attributes of the registered scrubbers could be +accessed in the /sys/class/ras/rasX/scrub/ + +sysfs +----- + +Sysfs files are documented in +`Documentation/ABI/testing/sysfs-class-scrub-configure`. + +Example +------- + +The usage takes the form shown in this example:: + +1. CXL patrol scrubber + # cat /sys/class/ras/ras0/scrub/rate_available + # 0x1-0xff + # echo 30 > /sys/class/ras/ras0/scrub/rate + # cat /sys/class/ras/ras0/scrub/rate + # 0x1e + # echo 1 > /sys/class/ras/ras0/scrub/enable_background + # cat /sys/class/ras/ras0/scrub/enable_background + # 1 + # echo 0 > /sys/class/ras/ras0/scrub/enable_background + # cat /sys/class/ras/ras0/scrub/enable_background + # 0 diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig index 5f3c9c5529b9..3621b9f27e80 100644 --- a/drivers/cxl/Kconfig +++ b/drivers/cxl/Kconfig @@ -144,4 +144,23 @@ config CXL_REGION_INVALIDATION_TEST If unsure, or if this kernel is meant for production environments, say N. +config CXL_SCRUB + bool "CXL: Memory scrub feature" + depends on CXL_PCI + depends on CXL_MEM + depends on SCRUB + help + The CXL memory scrub control is an optional feature allows host to + control the scrub configurations of CXL Type 3 devices, which + supports patrol scrubbing. + + Registers with the scrub subsystem to provide control attributes + of CXL memory device scrubber to the user. + Provides interface functions to support configuring the CXL memory + device patrol scrubber. + + Say 'y/n' to enable/disable control of memory scrub parameters for + CXL.mem devices. See section 8.2.9.9.11.1 of CXL 3.1 specification + for detailed description of CXL memory patrol scrub control feature. + endif diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index 9259bcc6773c..e0fc814c3983 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -16,3 +16,4 @@ cxl_core-y += pmu.o cxl_core-y += cdat.o cxl_core-$(CONFIG_TRACING) += trace.o cxl_core-$(CONFIG_CXL_REGION) += region.o +cxl_core-$(CONFIG_CXL_SCRUB) += memscrub.o diff --git a/drivers/cxl/core/memscrub.c b/drivers/cxl/core/memscrub.c new file mode 100644 index 000000000000..a50f6e384394 --- /dev/null +++ b/drivers/cxl/core/memscrub.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * CXL memory scrub driver. + * + * Copyright (c) 2024 HiSilicon Limited. + * + * - Provides functions to configure patrol scrub feature of the + * CXL memory devices. + * - Registers with the scrub subsystem driver to expose the sysfs attributes + * to the user for configuring the CXL memory patrol scrub feature. + */ + +#define pr_fmt(fmt) "CXL_MEM_SCRUB: " fmt + +#include +#include +#include +#include + +static int cxl_mem_get_supported_feature_entry(struct cxl_memdev *cxlmd, const uuid_t *feat_uuid, + struct cxl_mbox_supp_feat_entry *feat_entry_out) +{ + struct cxl_mbox_supp_feat_entry *feat_entry; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + int feat_index, feats_out_size; + int nentries, count; + int ret; + + feat_index = 0; + feats_out_size = sizeof(struct cxl_mbox_get_supp_feats_out) + + sizeof(struct cxl_mbox_supp_feat_entry); + struct cxl_mbox_get_supp_feats_out *feats_out __free(kfree) = + kmalloc(feats_out_size, GFP_KERNEL); + if (!feats_out) + return -ENOMEM; + + while (true) { + memset(feats_out, 0, feats_out_size); + ret = cxl_get_supported_features(mds, feats_out_size, + feat_index, feats_out); + if (ret) + return ret; + + nentries = feats_out->nr_entries; + if (!nentries) + return -EOPNOTSUPP; + + /* Check CXL memdev supports the feature */ + feat_entry = feats_out->feat_entries; + for (count = 0; count < nentries; count++, feat_entry++) { + if (uuid_equal(&feat_entry->uuid, feat_uuid)) { + memcpy(feat_entry_out, feat_entry, + sizeof(*feat_entry_out)); + return 0; + } + } + feat_index += nentries; + } +} + +/* CXL memory patrol scrub control definitions */ +#define CXL_MEMDEV_PS_GET_FEAT_VERSION 0x01 +#define CXL_MEMDEV_PS_SET_FEAT_VERSION 0x01 + +static const uuid_t cxl_patrol_scrub_uuid = + UUID_INIT(0x96dad7d6, 0xfde8, 0x482b, 0xa7, 0x33, 0x75, 0x77, 0x4e, \ + 0x06, 0xdb, 0x8a); + +/* CXL memory patrol scrub control functions */ +struct cxl_patrol_scrub_context { + struct device *dev; + u16 get_feat_size; + u16 set_feat_size; + bool scrub_cycle_changeable; +}; + +/** + * struct cxl_memdev_ps_params - CXL memory patrol scrub parameter data structure. + * @enable: [IN & OUT] enable(1)/disable(0) patrol scrub. + * @scrub_cycle_changeable: [OUT] scrub cycle attribute of patrol scrub is changeable. + * @rate: [IN] Requested patrol scrub cycle in hours. + * [OUT] Current patrol scrub cycle in hours. + * @min_rate:[OUT] minimum patrol scrub cycle, in hours, supported. + */ +struct cxl_memdev_ps_params { + bool enable; + bool scrub_cycle_changeable; + u16 rate; + u16 min_rate; +}; + +enum cxl_scrub_param { + cxl_ps_param_enable, + cxl_ps_param_rate, +}; + +#define CXL_MEMDEV_PS_SCRUB_CYCLE_CHANGE_CAP_MASK BIT(0) +#define CXL_MEMDEV_PS_SCRUB_CYCLE_REALTIME_REPORT_CAP_MASK BIT(1) +#define CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_MASK GENMASK(7, 0) +#define CXL_MEMDEV_PS_MIN_SCRUB_CYCLE_MASK GENMASK(15, 8) +#define CXL_MEMDEV_PS_FLAG_ENABLED_MASK BIT(0) + +struct cxl_memdev_ps_rd_attrs { + u8 scrub_cycle_cap; + __le16 scrub_cycle; + u8 scrub_flags; +} __packed; + +struct cxl_memdev_ps_wr_attrs { + u8 scrub_cycle_hr; + u8 scrub_flags; +} __packed; + +static int cxl_mem_ps_get_attrs(struct device *dev, + struct cxl_memdev_ps_params *params) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + size_t rd_data_size = sizeof(struct cxl_memdev_ps_rd_attrs); + size_t data_size; + + if (!mds) + return -EFAULT; + + struct cxl_memdev_ps_rd_attrs *rd_attrs __free(kfree) = + kmalloc(rd_data_size, GFP_KERNEL); + if (!rd_attrs) + return -ENOMEM; + + data_size = cxl_get_feature(mds, cxl_patrol_scrub_uuid, rd_attrs, + rd_data_size, rd_data_size, + CXL_GET_FEAT_SEL_CURRENT_VALUE); + if (!data_size) + return -EIO; + + params->scrub_cycle_changeable = FIELD_GET(CXL_MEMDEV_PS_SCRUB_CYCLE_CHANGE_CAP_MASK, + rd_attrs->scrub_cycle_cap); + params->enable = FIELD_GET(CXL_MEMDEV_PS_FLAG_ENABLED_MASK, + rd_attrs->scrub_flags); + params->rate = FIELD_GET(CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_MASK, + rd_attrs->scrub_cycle); + params->min_rate = FIELD_GET(CXL_MEMDEV_PS_MIN_SCRUB_CYCLE_MASK, + rd_attrs->scrub_cycle); + + return 0; +} + +static int cxl_mem_ps_set_attrs(struct device *dev, struct cxl_memdev_ps_params *params, + enum cxl_scrub_param param_type) +{ + struct cxl_memdev_ps_wr_attrs wr_attrs; + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct cxl_memdev_ps_params rd_params; + int ret; + + ret = cxl_mem_ps_get_attrs(dev, &rd_params); + if (ret) { + dev_err(dev, "Get cxlmemdev patrol scrub params failed ret=%d\n", + ret); + return ret; + } + + switch (param_type) { + case cxl_ps_param_enable: + wr_attrs.scrub_flags = FIELD_PREP(CXL_MEMDEV_PS_FLAG_ENABLED_MASK, + params->enable); + wr_attrs.scrub_cycle_hr = FIELD_PREP(CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_MASK, + rd_params.rate); + break; + case cxl_ps_param_rate: + if (params->rate < rd_params.min_rate) { + dev_err(dev, "Invalid CXL patrol scrub cycle(%d) to set\n", + params->rate); + dev_err(dev, "Minimum supported CXL patrol scrub cycle in hour %d\n", + params->min_rate); + return -EINVAL; + } + wr_attrs.scrub_cycle_hr = FIELD_PREP(CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_MASK, + params->rate); + wr_attrs.scrub_flags = FIELD_PREP(CXL_MEMDEV_PS_FLAG_ENABLED_MASK, + rd_params.enable); + break; + } + + ret = cxl_set_feature(mds, cxl_patrol_scrub_uuid, CXL_MEMDEV_PS_SET_FEAT_VERSION, + &wr_attrs, sizeof(wr_attrs), + CXL_SET_FEAT_FLAG_DATA_SAVED_ACROSS_RESET); + if (ret) + dev_err(dev, "CXL patrol scrub set feature failed ret=%d\n", + ret); + + return ret; +} + +static int cxl_patrol_scrub_get_enabled_bg(struct device *dev, bool *enabled) +{ + struct cxl_memdev_ps_params params; + int ret; + + ret = cxl_mem_ps_get_attrs(dev->parent, ¶ms); + if (ret) + return ret; + + *enabled = params.enable; + + return 0; +} + +static int cxl_patrol_scrub_set_enabled_bg(struct device *dev, bool enable) +{ + struct cxl_memdev_ps_params params = { + .enable = enable, + }; + + return cxl_mem_ps_set_attrs(dev->parent, ¶ms, cxl_ps_param_enable); +} + +static int cxl_patrol_scrub_get_name(struct device *dev, char *name) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev->parent); + + return sysfs_emit(name, "%s_%s\n", "cxl_patrol_scrub", + dev_name(&cxlmd->dev)); +} + +static int cxl_patrol_scrub_write_rate(struct device *dev, u64 rate) +{ + struct cxl_memdev_ps_params params = { + .rate = rate, + }; + + return cxl_mem_ps_set_attrs(dev->parent, ¶ms, cxl_ps_param_rate); +} + +static int cxl_patrol_scrub_read_rate(struct device *dev, u64 *rate) +{ + struct cxl_memdev_ps_params params; + int ret; + + ret = cxl_mem_ps_get_attrs(dev->parent, ¶ms); + if (ret) + return ret; + + *rate = params.rate; + + return 0; +} + +static int cxl_patrol_scrub_read_rate_avail(struct device *dev, u64 *min, u64 *max) +{ + struct cxl_memdev_ps_params params; + int ret; + + ret = cxl_mem_ps_get_attrs(dev->parent, ¶ms); + if (ret) + return ret; + *min = params.min_rate; + *max = U8_MAX; /* Max set by register size */ + + return 0; +} + +static const struct scrub_ops cxl_ps_scrub_ops = { + .get_enabled_bg = cxl_patrol_scrub_get_enabled_bg, + .set_enabled_bg = cxl_patrol_scrub_set_enabled_bg, + .get_name = cxl_patrol_scrub_get_name, + .rate_read = cxl_patrol_scrub_read_rate, + .rate_write = cxl_patrol_scrub_write_rate, + .rate_avail_range = cxl_patrol_scrub_read_rate_avail, +}; + +int cxl_mem_patrol_scrub_init(struct cxl_memdev *cxlmd) +{ + struct cxl_patrol_scrub_context *cxl_ps_ctx; + struct cxl_mbox_supp_feat_entry feat_entry; + struct cxl_memdev_ps_params params; + struct device *cxl_scrub_dev; + int ret; + + ret = cxl_mem_get_supported_feature_entry(cxlmd, &cxl_patrol_scrub_uuid, + &feat_entry); + if (ret < 0) + return ret; + + if (!(feat_entry.attr_flags & CXL_FEAT_ENTRY_FLAG_CHANGABLE)) + return -EOPNOTSUPP; + + ret = cxl_mem_ps_get_attrs(&cxlmd->dev, ¶ms); + if (ret) + return dev_err_probe(&cxlmd->dev, ret, + "Get CXL patrol scrub params failed\n"); + + cxl_ps_ctx = devm_kzalloc(&cxlmd->dev, sizeof(*cxl_ps_ctx), GFP_KERNEL); + if (!cxl_ps_ctx) + return -ENOMEM; + + *cxl_ps_ctx = (struct cxl_patrol_scrub_context) { + .get_feat_size = feat_entry.get_size, + .set_feat_size = feat_entry.set_size, + .scrub_cycle_changeable = params.scrub_cycle_changeable, + }; + + cxl_scrub_dev = devm_scrub_device_register(&cxlmd->dev, cxl_ps_ctx, + &cxl_ps_scrub_ops); + if (IS_ERR(cxl_scrub_dev)) + return PTR_ERR(cxl_scrub_dev); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_mem_patrol_scrub_init, CXL); diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 1c50a3e2eced..f95e39febd73 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -956,6 +956,14 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd); int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa); int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa); +/* cxl memory scrub functions */ +#ifdef CONFIG_CXL_SCRUB +int cxl_mem_patrol_scrub_init(struct cxl_memdev *cxlmd); +#else +static inline int cxl_mem_patrol_scrub_init(struct cxl_memdev *cxlmd) +{ return 0; } +#endif + #ifdef CONFIG_CXL_SUSPEND void cxl_mem_active_inc(void); void cxl_mem_active_dec(void); diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index 0c79d9ce877c..399e43463626 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -117,6 +117,12 @@ static int cxl_mem_probe(struct device *dev) if (!cxlds->media_ready) return -EBUSY; + rc = cxl_mem_patrol_scrub_init(cxlmd); + if (rc) { + dev_dbg(&cxlmd->dev, "CXL patrol scrub init failed\n"); + return rc; + } + /* * Someone is trying to reattach this device after it lost its port * connection (an endpoint port previously registered by this memdev was From patchwork Fri Apr 19 16:47:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790706 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 362A913AD39; Fri, 19 Apr 2024 16:47:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545271; cv=none; b=hDOIs3RH6vxxJcCl4OvJ9/F7zMvi4KkvGqpAMWhGcVjBJSQBsizfcMhSElqAH5f0/Kma31kJb9uSPl0AE4mlYhlXVy7+7q88lo1Ks954JHK0Lbxt2e/e7wQtPaAvR2FCTAXiu9DlmBsIS6Pf+aYchjCDnMvEkcR7xhhnYwKq1JE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545271; c=relaxed/simple; bh=N/KbKABNeanEm1VOOHMlDsmLILPdeTsV4rqskWWMfv8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GHqcOdE1zc4inKDTU5ygLpVrEtS4uGYmqTmHpMx1faYCn6RABJT5niTiOniHM8TdgAMUpncFNv03MuD0TCh2+tZ8gjJAG4iAsaTFzy9wjpatvSS9+r3XKChN2AqIkwwdhqEZETDvZCnrsrKi4q65UFkxIJPEJ1ypxD/q0v4qkGU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgWB0pdKz6JBJF; Sat, 20 Apr 2024 00:45:42 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 17014140D1D; Sat, 20 Apr 2024 00:47:48 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:46 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 06/10] ACPICA: Add __free() based cleanup function for acpi_put_table Date: Sat, 20 Apr 2024 00:47:15 +0800 Message-ID: <20240419164720.1765-7-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Jonathan Cameron Add __free() based cleanup function for acpi_put_table. Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- include/acpi/acpixf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 3d90716f9522..fc64d903a703 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -492,6 +492,8 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status **out_table)) ACPI_EXTERNAL_RETURN_VOID(void acpi_put_table(struct acpi_table_header *table)) +DEFINE_FREE(acpi_put_table, struct acpi_table_header *, if (!IS_ERR_OR_NULL(_T)) acpi_put_table(_T)) + ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_get_table_by_index(u32 table_index, struct acpi_table_header From patchwork Fri Apr 19 16:47:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790705 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D32013B297; Fri, 19 Apr 2024 16:47:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545271; cv=none; b=m+VoK57D3OrSpYo8sYcMaQHiC+JY0cvrz34uA2Bc3bBOI8gbycU/iGHrHB6uQnXQSALuf7QPiqBkFrd4VrxnFFwKI8Z8nLhfkKWKXQr+T/xER6F1X48BOnTyfMCe946qxqDJ8MeEvIHVFB2ihGivOfZwLDry7c4ZJ9MHfTvyl4A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545271; c=relaxed/simple; bh=IHhctoOcFaOxLkAqUw+9q5ii2zp+YdRGoQ4RmBmfHf0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=a3RqJDjnzklfbNivZvJdqW82oi2Mc0s/U4mBZsLxoGvWUIVMJ9JcNfnaznKmP9mg0K+y9OkaI7dKv3ecen3p5Els+NoqLt4UbB59UWH0Htt4DF/4l03mwA/jC8O909eIVadj634cb9klYETl2m1sfs1W5ESvvyUU3HElW0elgqU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgW94RMZz6K63v; Sat, 20 Apr 2024 00:45:41 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 68F0C140DAF; Sat, 20 Apr 2024 00:47:48 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:47 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 07/10] platform: Add __free() based cleanup function for platform_device_put Date: Sat, 20 Apr 2024 00:47:16 +0800 Message-ID: <20240419164720.1765-8-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Jonathan Cameron Add __free() based cleanup function for platform_device_put(). Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- include/linux/platform_device.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 7a41c72c1959..1ddc35623b4c 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -232,6 +232,7 @@ extern int platform_device_add_data(struct platform_device *pdev, extern int platform_device_add(struct platform_device *pdev); extern void platform_device_del(struct platform_device *pdev); extern void platform_device_put(struct platform_device *pdev); +DEFINE_FREE(platform_device_put, struct platform_device *, if (_T) platform_device_put(_T)) struct platform_driver { int (*probe)(struct platform_device *); From patchwork Fri Apr 19 16:47:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790704 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB56813BC07; Fri, 19 Apr 2024 16:47:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545274; cv=none; b=oOlgfq4/Ofrov/rOU7i0BI5KsMQhKAUEnflyX2N1FCBOSUz2243qfYqqzofNtNAYVIm4ZeLZfKISDrJ3KrAVl6dY12RA1zFli30t3nKs8Z7NqTcToKBKIUEYMYgXHbC0pglS5lci8SQQe+koVBGF+kA+eCWTGug0N2R4CpW9syw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545274; c=relaxed/simple; bh=NcR+bYaf8Mx3cz6CkDdlXpQDZaAt7PQmrLfmx7E3u+g=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cHz6a7+cq+KQpiL7Ok90Bv0hjgX4dn/9SCB6VSnuekdKXvpMt7r8la2TyX09NnQMZbZAwXeGuHq8QusXN/Xn/N1FbNznPAoMluC3U6moK6Lsup9hjqr9uECYi6q9FO6OnngXWFyrxAjQUN4b60nQb/p+DjKj/vF5PpPTcU0u2pA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.31]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgYc1bsvz6K8xt; Sat, 20 Apr 2024 00:47:48 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 913BD140A35; Sat, 20 Apr 2024 00:47:49 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:48 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 08/10] ACPI:RAS2: Add ACPI RAS2 driver Date: Sat, 20 Apr 2024 00:47:17 +0800 Message-ID: <20240419164720.1765-9-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Add support for ACPI RAS2 feature table (RAS2) defined in the ACPI 6.5 Specification, section 5.2.21. Driver contains RAS2 Init, which extracts the RAS2 table and driver adds platform device for each memory features which binds to the RAS2 memory driver. Driver uses PCC mailbox to communicate with the ACPI HW and the driver adds OSPM interfaces to send RAS2 commands. Co-developed-by: A Somasundaram Signed-off-by: A Somasundaram Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- drivers/acpi/Kconfig | 10 ++ drivers/acpi/Makefile | 1 + drivers/acpi/ras2.c | 366 +++++++++++++++++++++++++++++++++++++++ include/acpi/ras2_acpi.h | 59 +++++++ 4 files changed, 436 insertions(+) create mode 100755 drivers/acpi/ras2.c create mode 100644 include/acpi/ras2_acpi.h diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ff1689bb3124..638f1e38f961 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -284,6 +284,16 @@ config ACPI_CPPC_LIB If your platform does not support CPPC in firmware, leave this option disabled. +config ACPI_RAS2 + bool "ACPI RAS2 driver" + select MAILBOX + select PCC + help + The driver adds support for ACPI RAS2 feature table(extracts RAS2 + table from OS system table) and OSPM interfaces to send RAS2 + commands via PCC mailbox subspace. Driver adds platform device for + the RAS2 memory features which binds to the RAS2 memory driver. + config ACPI_PROCESSOR tristate "Processor" depends on X86 || ARM64 || LOONGARCH || RISCV diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8cc8c0d9c873..1df9de524c62 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -104,6 +104,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o +obj-$(CONFIG_ACPI_RAS2) += ras2.o obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o obj-$(CONFIG_ACPI_PPTT) += pptt.o obj-$(CONFIG_ACPI_PFRUT) += pfr_update.o pfr_telemetry.o diff --git a/drivers/acpi/ras2.c b/drivers/acpi/ras2.c new file mode 100755 index 000000000000..f4282aad5174 --- /dev/null +++ b/drivers/acpi/ras2.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of ACPI RAS2 driver. + * + * Copyright (c) 2024 HiSilicon Limited. + * + * Support for RAS2 - ACPI 6.5 Specification, section 5.2.21 + * + * Driver contains ACPI RAS2 init, which extracts the ACPI RAS2 table and + * get the PCC channel subspace for communicating with the ACPI compliant + * HW platform which supports ACPI RAS2. Driver adds platform devices + * for each RAS2 memory feature which binds to the memory ACPI RAS2 driver. + */ + +#define pr_fmt(fmt) "ACPI RAS2: " fmt + +#include +#include +#include +#include +#include +#include + +/* + * Arbitrary Retries for PCC commands because the + * remote processor could be much slower to reply. + */ +#define RAS2_NUM_RETRIES 600 + +#define RAS2_FEATURE_TYPE_MEMORY 0x00 + +/* global variables for the RAS2 PCC subspaces */ +static DEFINE_MUTEX(ras2_pcc_subspace_lock); +static LIST_HEAD(ras2_pcc_subspaces); + +static int ras2_check_pcc_chan(struct ras2_pcc_subspace *pcc_subspace) +{ + struct acpi_ras2_shared_memory __iomem *generic_comm_base = pcc_subspace->pcc_comm_addr; + ktime_t next_deadline = ktime_add(ktime_get(), pcc_subspace->deadline); + u16 status; + + while (!ktime_after(ktime_get(), next_deadline)) { + /* + * As per ACPI spec, the PCC space will be initialized by + * platform and should have set the command completion bit when + * PCC can be used by OSPM + */ + status = readw_relaxed(&generic_comm_base->status); + if (status & RAS2_PCC_CMD_ERROR) + return -EIO; + if (status & RAS2_PCC_CMD_COMPLETE) + return 0; + /* + * Reducing the bus traffic in case this loop takes longer than + * a few retries. + */ + msleep(10); + } + + return -EIO; +} + +/** + * ras2_send_pcc_cmd() - Send RAS2 command via PCC channel + * @ras2_ctx: pointer to the ras2 context structure + * @cmd: command to send + * + * Returns: 0 on success, an error otherwise + */ +int ras2_send_pcc_cmd(struct ras2_scrub_ctx *ras2_ctx, u16 cmd) +{ + struct ras2_pcc_subspace *pcc_subspace = ras2_ctx->pcc_subspace; + struct acpi_ras2_shared_memory *generic_comm_base = pcc_subspace->pcc_comm_addr; + static ktime_t last_cmd_cmpl_time, last_mpar_reset; + struct mbox_chan *pcc_channel; + unsigned int time_delta; + static int mpar_count; + int ret; + + guard(mutex)(&ras2_pcc_subspace_lock); + ret = ras2_check_pcc_chan(pcc_subspace); + if (ret) + return ret; + pcc_channel = pcc_subspace->pcc_chan->mchan; + + /* + * Handle the Minimum Request Turnaround Time(MRTT) + * "The minimum amount of time that OSPM must wait after the completion + * of a command before issuing the next command, in microseconds" + */ + if (pcc_subspace->pcc_mrtt) { + time_delta = ktime_us_delta(ktime_get(), last_cmd_cmpl_time); + if (pcc_subspace->pcc_mrtt > time_delta) + udelay(pcc_subspace->pcc_mrtt - time_delta); + } + + /* + * Handle the non-zero Maximum Periodic Access Rate(MPAR) + * "The maximum number of periodic requests that the subspace channel can + * support, reported in commands per minute. 0 indicates no limitation." + * + * This parameter should be ideally zero or large enough so that it can + * handle maximum number of requests that all the cores in the system can + * collectively generate. If it is not, we will follow the spec and just + * not send the request to the platform after hitting the MPAR limit in + * any 60s window + */ + if (pcc_subspace->pcc_mpar) { + if (mpar_count == 0) { + time_delta = ktime_ms_delta(ktime_get(), last_mpar_reset); + if (time_delta < 60 * MSEC_PER_SEC) { + dev_dbg(ras2_ctx->dev, + "PCC cmd not sent due to MPAR limit"); + return -EIO; + } + last_mpar_reset = ktime_get(); + mpar_count = pcc_subspace->pcc_mpar; + } + mpar_count--; + } + + /* Write to the shared comm region. */ + writew_relaxed(cmd, &generic_comm_base->command); + + /* Flip CMD COMPLETE bit */ + writew_relaxed(0, &generic_comm_base->status); + + /* Ring doorbell */ + ret = mbox_send_message(pcc_channel, &cmd); + if (ret < 0) { + dev_err(ras2_ctx->dev, + "Err sending PCC mbox message. cmd:%d, ret:%d\n", + cmd, ret); + return ret; + } + + /* + * If Minimum Request Turnaround Time is non-zero, we need + * to record the completion time of both READ and WRITE + * command for proper handling of MRTT, so we need to check + * for pcc_mrtt in addition to CMD_READ + */ + if (cmd == RAS2_PCC_CMD_EXEC || pcc_subspace->pcc_mrtt) { + ret = ras2_check_pcc_chan(pcc_subspace); + if (pcc_subspace->pcc_mrtt) + last_cmd_cmpl_time = ktime_get(); + } + + if (pcc_channel->mbox->txdone_irq) + mbox_chan_txdone(pcc_channel, ret); + else + mbox_client_txdone(pcc_channel, ret); + + return 0; +} +EXPORT_SYMBOL_GPL(ras2_send_pcc_cmd); + +static int ras2_register_pcc_channel(struct device *dev, struct ras2_scrub_ctx *ras2_ctx, + int pcc_subspace_id) +{ + struct acpi_pcct_hw_reduced *ras2_ss; + struct mbox_client *ras2_mbox_cl; + struct pcc_mbox_chan *pcc_chan; + struct ras2_pcc_subspace *pcc_subspace; + + if (pcc_subspace_id < 0) + return -EINVAL; + + mutex_lock(&ras2_pcc_subspace_lock); + list_for_each_entry(pcc_subspace, &ras2_pcc_subspaces, elem) { + if (pcc_subspace->pcc_subspace_id == pcc_subspace_id) { + ras2_ctx->pcc_subspace = pcc_subspace; + pcc_subspace->ref_count++; + mutex_unlock(&ras2_pcc_subspace_lock); + return 0; + } + } + mutex_unlock(&ras2_pcc_subspace_lock); + + pcc_subspace = kcalloc(1, sizeof(*pcc_subspace), GFP_KERNEL); + if (!pcc_subspace) + return -ENOMEM; + pcc_subspace->pcc_subspace_id = pcc_subspace_id; + ras2_mbox_cl = &pcc_subspace->mbox_client; + ras2_mbox_cl->dev = dev; + ras2_mbox_cl->knows_txdone = true; + + pcc_chan = pcc_mbox_request_channel(ras2_mbox_cl, pcc_subspace_id); + if (IS_ERR(pcc_chan)) { + kfree(pcc_subspace); + return PTR_ERR(pcc_chan); + } + pcc_subspace->pcc_chan = pcc_chan; + ras2_ss = pcc_chan->mchan->con_priv; + pcc_subspace->comm_base_addr = ras2_ss->base_address; + + /* + * ras2_ss->latency is just a Nominal value. In reality + * the remote processor could be much slower to reply. + * So add an arbitrary amount of wait on top of Nominal. + */ + pcc_subspace->deadline = ns_to_ktime(RAS2_NUM_RETRIES * ras2_ss->latency * + NSEC_PER_USEC); + pcc_subspace->pcc_mrtt = ras2_ss->min_turnaround_time; + pcc_subspace->pcc_mpar = ras2_ss->max_access_rate; + pcc_subspace->pcc_comm_addr = acpi_os_ioremap(pcc_subspace->comm_base_addr, + ras2_ss->length); + /* Set flag so that we dont come here for each CPU. */ + pcc_subspace->pcc_channel_acquired = true; + + mutex_lock(&ras2_pcc_subspace_lock); + list_add(&pcc_subspace->elem, &ras2_pcc_subspaces); + pcc_subspace->ref_count++; + mutex_unlock(&ras2_pcc_subspace_lock); + ras2_ctx->pcc_subspace = pcc_subspace; + + return 0; +} + +static void ras2_unregister_pcc_channel(void *ctx) +{ + struct ras2_scrub_ctx *ras2_ctx = ctx; + struct ras2_pcc_subspace *pcc_subspace = ras2_ctx->pcc_subspace; + + if (!pcc_subspace || !pcc_subspace->pcc_chan) + return; + + guard(mutex)(&ras2_pcc_subspace_lock); + if (pcc_subspace->ref_count > 0) + pcc_subspace->ref_count--; + if (!pcc_subspace->ref_count) { + list_del(&pcc_subspace->elem); + pcc_mbox_free_channel(pcc_subspace->pcc_chan); + kfree(pcc_subspace); + } +} + +/** + * devm_ras2_register_pcc_channel() - Register RAS2 PCC channel + * @dev: pointer to the ras2 device + * @ras2_ctx: pointer to the ras2 context structure + * @pcc_subspace_id: identifier of the RAS2 PCC channel. + * + * Returns: 0 on success, an error otherwise + */ +int devm_ras2_register_pcc_channel(struct device *dev, struct ras2_scrub_ctx *ras2_ctx, + int pcc_subspace_id) +{ + int ret; + + ret = ras2_register_pcc_channel(dev, ras2_ctx, pcc_subspace_id); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, ras2_unregister_pcc_channel, ras2_ctx); +} +EXPORT_SYMBOL_NS_GPL(devm_ras2_register_pcc_channel, ACPI_RAS2); + +static struct platform_device *ras2_add_platform_device(char *name, int channel) +{ + int ret; + struct platform_device *pdev __free(platform_device_put) = + platform_device_alloc(name, PLATFORM_DEVID_AUTO); + if (!pdev) + return ERR_PTR(-ENOMEM); + + ret = platform_device_add_data(pdev, &channel, sizeof(channel)); + if (ret) + return ERR_PTR(ret); + + ret = platform_device_add(pdev); + if (ret) + return ERR_PTR(ret); + + return_ptr(pdev); +} + +static struct acpi_table_header *acpi_get_table2(acpi_string signature, + u32 instance) +{ + struct acpi_table_header *header = NULL; + acpi_status status = acpi_get_table(signature, instance, &header); + + if (ACPI_FAILURE(status)) + return ERR_PTR(-EINVAL); + + return header; +} + +static int __init ras2_acpi_init(void) +{ + struct acpi_ras2_pcc_desc *pcc_desc_list; + struct acpi_table_ras2 *pRas2Table; + struct platform_device *pdev; + int pcc_subspace_id; + acpi_size ras2_size; + u8 count = 0, i; + + struct acpi_table_header *pAcpiTable __free(acpi_put_table) = + acpi_get_table2("RAS2", 0); + if (IS_ERR_OR_NULL(pAcpiTable)) { + pr_err("ACPI RAS2 driver failed to initialize, get table failed\n"); + return -ENODEV; + } + + ras2_size = pAcpiTable->length; + if (ras2_size < sizeof(struct acpi_table_ras2)) { + pr_err("ACPI RAS2 table present but broken (too short #1)\n"); + return -EINVAL; + } + + pRas2Table = (struct acpi_table_ras2 *)pAcpiTable; + if (pRas2Table->num_pcc_descs <= 0) { + pr_err("ACPI RAS2 table does not contain PCC descriptors\n"); + return -EINVAL; + } + + struct platform_device **pdev_list __free(kfree) = + kcalloc(pRas2Table->num_pcc_descs, sizeof(*pdev_list), + GFP_KERNEL); + if (!pdev_list) + return -ENOMEM; + + pcc_desc_list = (struct acpi_ras2_pcc_desc *)(pRas2Table + 1); + /* Double scan for the case of only one actual controller */ + pcc_subspace_id = -1; + count = 0; + for (i = 0; i < pRas2Table->num_pcc_descs; i++, pcc_desc_list++) { + if (pcc_desc_list->feature_type != RAS2_FEATURE_TYPE_MEMORY) + continue; + if (pcc_subspace_id == -1) { + pcc_subspace_id = pcc_desc_list->channel_id; + count++; + } + if (pcc_desc_list->channel_id != pcc_subspace_id) + count++; + } + if (count == 1) { + pdev = ras2_add_platform_device("acpi_ras2", pcc_subspace_id); + if (!pdev) + goto free_ras2_pdev; + pdev_list[0] = pdev; + return 0; + } + + count = 0; + for (i = 0; i < pRas2Table->num_pcc_descs; i++, pcc_desc_list++) { + if (pcc_desc_list->feature_type != RAS2_FEATURE_TYPE_MEMORY) + continue; + pcc_subspace_id = pcc_desc_list->channel_id; + /* Add the platform device and bind ACPI RAS2 memory driver */ + pdev = ras2_add_platform_device("acpi_ras2", pcc_subspace_id); + if (!pdev) + goto free_ras2_pdev; + pdev_list[count++] = pdev; + } + + return 0; + +free_ras2_pdev: + for (i = count; i >= 0; i++) + platform_device_put(pdev_list[i]); + + return -ENODEV; +} +late_initcall(ras2_acpi_init) diff --git a/include/acpi/ras2_acpi.h b/include/acpi/ras2_acpi.h new file mode 100644 index 000000000000..8c9430e6383e --- /dev/null +++ b/include/acpi/ras2_acpi.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * RAS2 ACPI driver header file + * + * (C) Copyright 2014, 2015 Hewlett-Packard Enterprises + * + * Copyright (c) 2024 HiSilicon Limited + */ + +#ifndef _RAS2_ACPI_H +#define _RAS2_ACPI_H + +#include +#include +#include +#include + +#define RAS2_PCC_CMD_COMPLETE BIT(0) +#define RAS2_PCC_CMD_ERROR BIT(2) + +/* RAS2 specific PCC commands */ +#define RAS2_PCC_CMD_EXEC 0x01 + +struct device; + +/* Data structures for PCC communication and RAS2 table */ +struct pcc_mbox_chan; + +struct ras2_pcc_subspace { + int pcc_subspace_id; + struct mbox_client mbox_client; + struct pcc_mbox_chan *pcc_chan; + struct acpi_ras2_shared_memory __iomem *pcc_comm_addr; + u64 comm_base_addr; + bool pcc_channel_acquired; + ktime_t deadline; + unsigned int pcc_mpar; + unsigned int pcc_mrtt; + struct list_head elem; + u16 ref_count; +}; + +struct ras2_scrub_ctx { + struct device *dev; + struct ras2_pcc_subspace *pcc_subspace; + int id; + struct device *scrub_dev; + bool bg; + u64 base, size; + u8 rate, rate_min, rate_max; + /* Lock to provide mutually exclusive access to PCC channel */ + struct mutex lock; +}; + +int ras2_send_pcc_cmd(struct ras2_scrub_ctx *ras2_ctx, u16 cmd); +int devm_ras2_register_pcc_channel(struct device *dev, struct ras2_scrub_ctx *ras2_ctx, + int pcc_subspace_id); + +#endif /* _RAS2_ACPI_H */ From patchwork Fri Apr 19 16:47:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790261 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F352413C9C8; Fri, 19 Apr 2024 16:47:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545274; cv=none; b=iZOChKCd32U7k06wOfjL9s9ftbXdXrAyC/g61G7ICJe6CRxyaRfF042WNGaPf5LLU86dyMpZ3EUnaHcCrPutN5HW1YFhlUTC0m8fS2JM3UrFWcqpI2SO75m1vjjcSKff4w1MvL3VCxkWCHa43F0Nm7EwMQ20nHkvYtkPCjEPwac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545274; c=relaxed/simple; bh=tDSifUiE4U4D1GwvzyJbNw4EOl+iDD7KH4clCnPWrcQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aiXSK0SPi+x87/mMaU4I2+m/qnShzEikIm9RU/pIodCGi1Drd3aist0x/0qVXdW+o76K8u9YTTDtFrfZ2Y6m6UaQI9OFP4DGK+nZrqREkVJfwG3Z/rkRmeKMZWczDCNPZvfs0sFtsyowR5Pm7DM/qiTO0sjzdgcLiwCLZTXzb0o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.31]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgWC65WBz6K626; Sat, 20 Apr 2024 00:45:43 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id A9B64140A35; Sat, 20 Apr 2024 00:47:50 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:49 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 09/10] ras: scrub: Add scrub control attributes for ACPI RAS2 Date: Sat, 20 Apr 2024 00:47:18 +0800 Message-ID: <20240419164720.1765-10-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Add scrub control attributes for ACPI RAS2 patrol scrub feature. Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- .../ABI/testing/sysfs-class-scrub-configure | 28 +++- drivers/ras/memory_scrub.c | 131 ++++++++++++++++++ include/linux/memory_scrub.h | 8 ++ 3 files changed, 165 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-scrub-configure b/Documentation/ABI/testing/sysfs-class-scrub-configure index 3ed77dbb00ad..7178776249f8 100644 --- a/Documentation/ABI/testing/sysfs-class-scrub-configure +++ b/Documentation/ABI/testing/sysfs-class-scrub-configure @@ -15,12 +15,21 @@ Description: correspond to each scrub device registered with the scrub subsystem. -What: /sys/class/ras/rasX/scrub/name +What: /sys/class/ras/rasX/scrub/addr_range_base Date: March 2024 KernelVersion: 6.9 Contact: linux-kernel@vger.kernel.org Description: - (RO) name of the memory scrubber + (RW) The base of the address range of the memory region + to be scrubbed (on-demand scrubbing). + +What: /sys/class/ras/rasX/scrub/addr_range_size +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + (RW) The size of the address range of the memory region + to be scrubbed (on-demand scrubbing). What: /sys/class/ras/rasX/scrub/enable_background Date: March 2024 @@ -29,6 +38,21 @@ Contact: linux-kernel@vger.kernel.org Description: (RW) Enable/Disable background(patrol) scrubbing if supported. +What: /sys/class/ras/rasX/scrub/enable_on_demand +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + (RW) Enable/Disable on-demand scrubbing the memory region + if supported. + +What: /sys/class/ras/rasX/scrub/name +Date: March 2024 +KernelVersion: 6.9 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) name of the memory scrubber + What: /sys/class/ras/rasX/scrub/rate_available Date: March 2024 KernelVersion: 6.9 diff --git a/drivers/ras/memory_scrub.c b/drivers/ras/memory_scrub.c index 7e995380ec3a..ace6c59b8993 100755 --- a/drivers/ras/memory_scrub.c +++ b/drivers/ras/memory_scrub.c @@ -29,6 +29,83 @@ struct scrub_device { }; #define to_scrub_device(d) container_of(d, struct scrub_device, dev) +static ssize_t addr_range_base_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + u64 base, size; + int ret; + + ret = scrub_dev->ops->read_range(dev, &base, &size); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%llx\n", base); +} + +static ssize_t addr_range_size_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + u64 base, size; + int ret; + + ret = scrub_dev->ops->read_range(dev, &base, &size); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%llx\n", size); +} + +static ssize_t addr_range_base_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + u64 base, size; + int ret; + + ret = scrub_dev->ops->read_range(dev, &base, &size); + if (ret) + return ret; + + ret = kstrtou64(buf, 16, &base); + if (ret < 0) + return ret; + + ret = scrub_dev->ops->write_range(dev, base, size); + if (ret) + return ret; + + return len; +} + +static ssize_t addr_range_size_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + u64 base, size; + int ret; + + ret = scrub_dev->ops->read_range(dev, &base, &size); + if (ret) + return ret; + + ret = kstrtou64(buf, 16, &size); + if (ret < 0) + return ret; + + ret = scrub_dev->ops->write_range(dev, base, size); + if (ret) + return ret; + + return len; +} + static ssize_t enable_background_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -62,6 +139,39 @@ static ssize_t enable_background_show(struct device *dev, return sysfs_emit(buf, "%d\n", enable); } +static ssize_t enable_on_demand_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + bool enable; + int ret; + + ret = scrub_dev->ops->get_enabled_od(dev, &enable); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", enable); +} + +static ssize_t enable_on_demand_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct scrub_device *scrub_dev = to_scrub_device(dev); + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + ret = scrub_dev->ops->set_enabled_od(dev, enable); + if (ret) + return ret; + + return len; +} + static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -122,13 +232,19 @@ static ssize_t rate_available_show(struct device *dev, return sysfs_emit(buf, "0x%llx-0x%llx\n", min_sr, max_sr); } +DEVICE_ATTR_RW(addr_range_base); +DEVICE_ATTR_RW(addr_range_size); DEVICE_ATTR_RW(enable_background); +DEVICE_ATTR_RW(enable_on_demand); DEVICE_ATTR_RO(name); DEVICE_ATTR_RW(rate); DEVICE_ATTR_RO(rate_available); static struct attribute *scrub_attrs[] = { + &dev_attr_addr_range_base.attr, + &dev_attr_addr_range_size.attr, &dev_attr_enable_background.attr, + &dev_attr_enable_on_demand.attr, &dev_attr_name.attr, &dev_attr_rate.attr, &dev_attr_rate_available.attr, @@ -142,6 +258,14 @@ static umode_t scrub_attr_visible(struct kobject *kobj, struct scrub_device *scrub_dev = to_scrub_device(dev); const struct scrub_ops *ops = scrub_dev->ops; + if (a == &dev_attr_addr_range_base.attr || + a == &dev_attr_addr_range_size.attr) { + if (ops->read_range && ops->write_range) + return a->mode; + if (ops->read_range) + return 0444; + return 0; + } if (a == &dev_attr_enable_background.attr) { if (ops->set_enabled_bg && ops->get_enabled_bg) return a->mode; @@ -149,6 +273,13 @@ static umode_t scrub_attr_visible(struct kobject *kobj, return 0444; return 0; } + if (a == &dev_attr_enable_on_demand.attr) { + if (ops->set_enabled_od && ops->get_enabled_od) + return a->mode; + if (ops->get_enabled_od) + return 0444; + return 0; + } if (a == &dev_attr_name.attr) return ops->get_name ? a->mode : 0; if (a == &dev_attr_rate_available.attr) diff --git a/include/linux/memory_scrub.h b/include/linux/memory_scrub.h index f0e1657a5072..d8edb48677c9 100755 --- a/include/linux/memory_scrub.h +++ b/include/linux/memory_scrub.h @@ -15,16 +15,24 @@ struct device; /** * struct scrub_ops - scrub device operations (all elements optional) + * @read_range: read base and offset of scrubbing range. + * @write_range: set the base and offset of the scrubbing range. * @get_enabled_bg: check if currently performing background scrub. * @set_enabled_bg: start or stop a bg-scrub. + * @get_enabled_od: check if currently performing on-demand scrub. + * @set_enabled_od: start or stop an on-demand scrub. * @get_name: get the memory scrubber name. * @rate_avail_range: retrieve limits on supported rates. * @rate_read: read the scrub rate * @rate_write: set the scrub rate */ struct scrub_ops { + int (*read_range)(struct device *dev, u64 *base, u64 *size); + int (*write_range)(struct device *dev, u64 base, u64 size); int (*get_enabled_bg)(struct device *dev, bool *enable); int (*set_enabled_bg)(struct device *dev, bool enable); + int (*get_enabled_od)(struct device *dev, bool *enable); + int (*set_enabled_od)(struct device *dev, bool enable); int (*get_name)(struct device *dev, char *buf); int (*rate_avail_range)(struct device *dev, u64 *min, u64 *max); int (*rate_read)(struct device *dev, u64 *rate); From patchwork Fri Apr 19 16:47:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 790703 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9ED213D24A; Fri, 19 Apr 2024 16:47:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545276; cv=none; b=s/8DbQqMh2bmr9fvIWFYy1z8h4EcYBS3tVI3zUrdVPOC73ygL1B1p9TlFaAHWH4N3K6ELcgIfJzO3Ieu9CQWRlmQLMu4Mt+o3NZszEvHQ/GMcXjnKRJB3dUCnoLVVbrWROt7HJpT/KlI8oZbrpMiwvM/wPiuJfsBx4T7Ho5H39c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713545276; c=relaxed/simple; bh=/g4f7qp6hur4avI/RS/oiYOYgMpH/1YNdrDGuVqvUUg=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=o1Feqq6BXWrtSIuYmpjBZxXNy1HR79xnifwbukWqcS17i2/gbV4a4ohWaTMOj7klMmqaCYtmDyoAvTLRM1O0ZQPsAHCVslLmPWQPQSluXK8DPX9kAxm858BvDmulmUR21i227EOW6zxCilpJM9bnGn+ere8SNp1x2dxmGyhkT9E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4VLgYf2Cfyz6K8x1; Sat, 20 Apr 2024 00:47:50 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id AC42F140B55; Sat, 20 Apr 2024 00:47:51 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) by lhrpeml500006.china.huawei.com (7.191.161.198) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 19 Apr 2024 17:47:50 +0100 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v8 10/10] ras: scrub: ACPI RAS2: Add memory ACPI RAS2 driver Date: Sat, 20 Apr 2024 00:47:19 +0800 Message-ID: <20240419164720.1765-11-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240419164720.1765-1-shiju.jose@huawei.com> References: <20240419164720.1765-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-acpi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: lhrpeml500006.china.huawei.com (7.191.161.198) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Memory ACPI RAS2 driver binds to the platform device add by the ACPI RAS2 table parser. Driver uses a PCC subspace for communicating with the ACPI compliant platform to provide control of memory scrub parameters via the scrub subsystem. Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- Documentation/scrub/scrub-configure.rst | 33 +++ drivers/ras/Kconfig | 10 + drivers/ras/Makefile | 1 + drivers/ras/acpi_ras2.c | 358 ++++++++++++++++++++++++ 4 files changed, 402 insertions(+) create mode 100644 drivers/ras/acpi_ras2.c diff --git a/Documentation/scrub/scrub-configure.rst b/Documentation/scrub/scrub-configure.rst index 2275366b60d3..7a1bf87bc6d7 100644 --- a/Documentation/scrub/scrub-configure.rst +++ b/Documentation/scrub/scrub-configure.rst @@ -50,3 +50,36 @@ The usage takes the form shown in this example:: # echo 0 > /sys/class/ras/ras0/scrub/enable_background # cat /sys/class/ras/ras0/scrub/enable_background # 0 + +2. RAS2 +2.1 On demand scrubbing for a specific memory region. + # echo 0x120000 > /sys/class/ras/ras1/scrub/addr_range_base + # echo 0x150000 > /sys/class/ras/ras1/scrub/addr_range_size + # cat /sys/class/ras/ras1/scrub/rate_available + # 0x1-0x18 + # echo 20 > /sys/class/ras/ras1/scrub/rate + # echo 1 > /sys/class/ras/ras1/scrub/enable_on_demand + # cat /sys/class/ras/ras1/scrub/enable_on_demand + # 1 + # cat /sys/class/ras/ras1/scrub/rate + # 0x14 + # cat /sys/class/ras/ras1/scrub/addr_range_base + # 0x120000 + # cat /sys/class/ras/ras1/scrub/addr_range_size + # 0x150000 + # echo 0 > /sys/class/ras/ras1/scrub/enable_on_demand + # cat /sys/class/ras/ras1/scrub/enable_on_demand + # 0 + +2.2 Background scrubbing the entire memory + # cat /sys/class/ras/ras1/scrub/rate_available + # 0x1-0x18 + # echo 3 > /sys/class/ras/ras1/scrub/rate + # echo 1 > /sys/class/ras/ras1/scrub/enable_background + # cat /sys/class/ras/ras1/scrub/enable_background + # 1 + # cat /sys/class/ras/ras1/scrub/rate + # 0x3 + # echo 0 > /sys/class/ras/ras1/scrub/enable_background + # cat /sys/class/ras/ras1/scrub/enable_background + # 0 diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig index 181701479564..57c346dfc01f 100644 --- a/drivers/ras/Kconfig +++ b/drivers/ras/Kconfig @@ -53,4 +53,14 @@ config SCRUB configuring the parameters of underlying scrubbers in the system for the DRAM memories. +config MEM_ACPI_RAS2 + tristate "Memory ACPI RAS2 driver" + depends on ACPI_RAS2 + depends on SCRUB + help + The driver binds to the platform device added by the ACPI RAS2 + table parser. Use a PCC channel subspace for communicating with + the ACPI compliant platform to provide control of memory scrub + parameters via the scrub subsystem. + endif diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile index 89bcf0d84355..48339fee1cb3 100644 --- a/drivers/ras/Makefile +++ b/drivers/ras/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_RAS) += ras.o obj-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_RAS_CEC) += cec.o obj-$(CONFIG_SCRUB) += memory_scrub.o +obj-$(CONFIG_MEM_ACPI_RAS2) += acpi_ras2.o obj-$(CONFIG_RAS_FMPM) += amd/fmpm.o obj-y += amd/atl/ diff --git a/drivers/ras/acpi_ras2.c b/drivers/ras/acpi_ras2.c new file mode 100644 index 000000000000..b3e9b61367bb --- /dev/null +++ b/drivers/ras/acpi_ras2.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ACPI RAS2 memory driver + * + * Copyright (c) 2024 HiSilicon Limited. + * + */ + +#define pr_fmt(fmt) "MEMORY ACPI RAS2: " fmt + +#include +#include +#include + +#define RAS2_SUPPORT_HW_PARTOL_SCRUB BIT(0) +#define RAS2_TYPE_PATROL_SCRUB 0x0000 + +#define RAS2_GET_PATROL_PARAMETERS 0x01 +#define RAS2_START_PATROL_SCRUBBER 0x02 +#define RAS2_STOP_PATROL_SCRUBBER 0x03 + +#define RAS2_PATROL_SCRUB_RATE_IN_MASK GENMASK(15, 8) +#define RAS2_PATROL_SCRUB_EN_BACKGROUND BIT(0) +#define RAS2_PATROL_SCRUB_RATE_OUT_MASK GENMASK(7, 0) +#define RAS2_PATROL_SCRUB_MIN_RATE_OUT_MASK GENMASK(15, 8) +#define RAS2_PATROL_SCRUB_MAX_RATE_OUT_MASK GENMASK(23, 16) +#define RAS2_PATROL_SCRUB_FLAG_SCRUBBER_RUNNING BIT(0) + +struct acpi_ras2_ps_shared_mem { + struct acpi_ras2_shared_memory common; + struct acpi_ras2_patrol_scrub_parameter params; +}; + +static int ras2_is_patrol_scrub_support(struct ras2_scrub_ctx *ras2_ctx) +{ + struct acpi_ras2_shared_memory __iomem *common = (void *) + ras2_ctx->pcc_subspace->pcc_comm_addr; + + guard(mutex)(&ras2_ctx->lock); + common->set_capabilities[0] = 0; + + return common->features[0] & RAS2_SUPPORT_HW_PARTOL_SCRUB; +} + +static int ras2_update_patrol_scrub_params_cache(struct ras2_scrub_ctx *ras2_ctx) +{ + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = (void *) + ras2_ctx->pcc_subspace->pcc_comm_addr; + int ret; + + ps_sm->common.set_capabilities[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + ps_sm->params.patrol_scrub_command = RAS2_GET_PATROL_PARAMETERS; + + ret = ras2_send_pcc_cmd(ras2_ctx, RAS2_PCC_CMD_EXEC); + if (ret) { + dev_err(ras2_ctx->dev, "failed to read parameters\n"); + return ret; + } + + ras2_ctx->rate_min = FIELD_GET(RAS2_PATROL_SCRUB_MIN_RATE_OUT_MASK, + ps_sm->params.scrub_params_out); + ras2_ctx->rate_max = FIELD_GET(RAS2_PATROL_SCRUB_MAX_RATE_OUT_MASK, + ps_sm->params.scrub_params_out); + ras2_ctx->base = ps_sm->params.actual_address_range[0]; + ras2_ctx->size = ps_sm->params.actual_address_range[1]; + ras2_ctx->rate = FIELD_GET(RAS2_PATROL_SCRUB_RATE_OUT_MASK, + ps_sm->params.scrub_params_out); + return 0; +} + +/* Context - lock must be held */ +static int ras2_get_patrol_scrub_running(struct ras2_scrub_ctx *ras2_ctx, + bool *running) +{ + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = (void *) + ras2_ctx->pcc_subspace->pcc_comm_addr; + int ret; + + if (ras2_ctx->bg) + *running = true; + + ps_sm->common.set_capabilities[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + ps_sm->params.patrol_scrub_command = RAS2_GET_PATROL_PARAMETERS; + + ret = ras2_send_pcc_cmd(ras2_ctx, RAS2_PCC_CMD_EXEC); + if (ret) { + dev_err(ras2_ctx->dev, "failed to read parameters\n"); + return ret; + } + + *running = ps_sm->params.flags & RAS2_PATROL_SCRUB_FLAG_SCRUBBER_RUNNING; + + return 0; +} + +static int ras2_hw_scrub_write_rate(struct device *dev, u64 rate) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + bool running; + int ret; + + guard(mutex)(&ras2_ctx->lock); + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + + if (running) + return -EBUSY; + + if (rate < ras2_ctx->rate_min || rate > ras2_ctx->rate_max) + return -EINVAL; + + ras2_ctx->rate = rate; + + return 0; +} + +static int ras2_hw_scrub_read_rate(struct device *dev, u64 *rate) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + + *rate = ras2_ctx->rate; + + return 0; +} + +static int ras2_hw_scrub_read_rate_avail(struct device *dev, u64 *min, u64 *max) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + + *min = ras2_ctx->rate_min; + *max = ras2_ctx->rate_max; + + return 0; +} + +static int ras2_hw_scrub_read_range(struct device *dev, u64 *base, u64 *size) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + + *base = ras2_ctx->base; + *size = ras2_ctx->size; + + return 0; +} + +static int ras2_hw_scrub_write_range(struct device *dev, u64 base, u64 size) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + bool running; + int ret; + + guard(mutex)(&ras2_ctx->lock); + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + + if (running) + return -EBUSY; + + ras2_ctx->base = base; + ras2_ctx->size = size; + + return 0; +} + +static int ras2_hw_scrub_set_enabled_bg(struct device *dev, bool enable) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = (void *) + ras2_ctx->pcc_subspace->pcc_comm_addr; + int ret; + + guard(mutex)(&ras2_ctx->lock); + ps_sm->common.set_capabilities[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + if (enable) { + ps_sm->params.requested_address_range[0] = 0; + ps_sm->params.requested_address_range[1] = 0; + ps_sm->params.scrub_params_in &= ~RAS2_PATROL_SCRUB_RATE_IN_MASK; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PATROL_SCRUB_RATE_IN_MASK, + ras2_ctx->rate); + ps_sm->params.patrol_scrub_command = RAS2_START_PATROL_SCRUBBER; + } else { + ps_sm->params.patrol_scrub_command = RAS2_STOP_PATROL_SCRUBBER; + } + ps_sm->params.scrub_params_in &= ~RAS2_PATROL_SCRUB_EN_BACKGROUND; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PATROL_SCRUB_EN_BACKGROUND, + enable); + + ret = ras2_send_pcc_cmd(ras2_ctx, RAS2_PCC_CMD_EXEC); + if (ret) { + dev_err(ras2_ctx->dev, "%s: failed to enable(%d) background scrubbing\n", + __func__, enable); + return ret; + } + ras2_ctx->bg = true; + + /* Update the cache to account for rounding of supplied parameters and similar */ + return ras2_update_patrol_scrub_params_cache(ras2_ctx); +} + +static int ras2_hw_scrub_get_enabled_bg(struct device *dev, bool *enabled) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + + *enabled = ras2_ctx->bg; + + return 0; +} + +static int ras2_hw_scrub_set_enabled_od(struct device *dev, bool enable) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = (void *) + ras2_ctx->pcc_subspace->pcc_comm_addr; + bool enabled; + int ret; + + guard(mutex)(&ras2_ctx->lock); + ps_sm->common.set_capabilities[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + if (enable) { + if (!ras2_ctx->size) { + dev_warn(ras2_ctx->dev, + "%s: Invalid requested address range, requested_address_range[0]=0x%llx " + "requested_address_range[1]=0x%llx\n", __func__, + ps_sm->params.requested_address_range[0], + ps_sm->params.requested_address_range[1]); + return -ERANGE; + } + ret = ras2_get_patrol_scrub_running(ras2_ctx, &enabled); + if (ret) + return ret; + + if (enabled) + return 0; + + ps_sm->params.scrub_params_in &= ~RAS2_PATROL_SCRUB_RATE_IN_MASK; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PATROL_SCRUB_RATE_IN_MASK, + ras2_ctx->rate); + ps_sm->params.requested_address_range[0] = ras2_ctx->base; + ps_sm->params.requested_address_range[1] = ras2_ctx->size; + ps_sm->params.patrol_scrub_command = RAS2_START_PATROL_SCRUBBER; + } else { + ps_sm->params.patrol_scrub_command = RAS2_STOP_PATROL_SCRUBBER; + } + + ret = ras2_send_pcc_cmd(ras2_ctx, RAS2_PCC_CMD_EXEC); + if (ret) { + dev_err(ras2_ctx->dev, "failed to enable(%d) the demand scrubbing\n", enable); + return ret; + } + ras2_ctx->bg = false; + + return ras2_update_patrol_scrub_params_cache(ras2_ctx); +} + +static int ras2_hw_scrub_get_enabled_od(struct device *dev, bool *enabled) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + + guard(mutex)(&ras2_ctx->lock); + if (ras2_ctx->bg) { + *enabled = false; + return 0; + } + + return ras2_get_patrol_scrub_running(ras2_ctx, enabled); +} + +static int ras2_hw_scrub_get_name(struct device *dev, char *name) +{ + struct ras2_scrub_ctx *ras2_ctx = dev_get_drvdata(dev); + + return sysfs_emit(name, "ras2_scrub%d\n", ras2_ctx->id); +} + +static const struct scrub_ops ras2_scrub_ops = { + .read_range = ras2_hw_scrub_read_range, + .write_range = ras2_hw_scrub_write_range, + .get_enabled_bg = ras2_hw_scrub_get_enabled_bg, + .set_enabled_bg = ras2_hw_scrub_set_enabled_bg, + .get_enabled_od = ras2_hw_scrub_get_enabled_od, + .set_enabled_od = ras2_hw_scrub_set_enabled_od, + .get_name = ras2_hw_scrub_get_name, + .rate_avail_range = ras2_hw_scrub_read_rate_avail, + .rate_read = ras2_hw_scrub_read_rate, + .rate_write = ras2_hw_scrub_write_rate, +}; + +static DEFINE_IDA(ras2_ida); + +static void ida_release(void *ctx) +{ + struct ras2_scrub_ctx *ras2_ctx = ctx; + + ida_free(&ras2_ida, ras2_ctx->id); +} + +static int ras2_probe(struct platform_device *pdev) +{ + struct ras2_scrub_ctx *ras2_ctx; + struct device *hw_scrub_dev; + int ret, id; + + /* RAS2 PCC Channel and Scrub specific context */ + ras2_ctx = devm_kzalloc(&pdev->dev, sizeof(*ras2_ctx), GFP_KERNEL); + if (!ras2_ctx) + return -ENOMEM; + + ras2_ctx->dev = &pdev->dev; + mutex_init(&ras2_ctx->lock); + + ret = devm_ras2_register_pcc_channel(&pdev->dev, ras2_ctx, + *((int *)dev_get_platdata(&pdev->dev))); + if (ret < 0) { + dev_dbg(ras2_ctx->dev, + "failed to register pcc channel ret=%d\n", ret); + return ret; + } + if (!ras2_is_patrol_scrub_support(ras2_ctx)) + return -EOPNOTSUPP; + + ret = ras2_update_patrol_scrub_params_cache(ras2_ctx); + if (ret) + return ret; + + id = ida_alloc(&ras2_ida, GFP_KERNEL); + if (id < 0) + return id; + + ras2_ctx->id = id; + + ret = devm_add_action_or_reset(&pdev->dev, ida_release, ras2_ctx); + if (ret < 0) + return ret; + + hw_scrub_dev = devm_scrub_device_register(&pdev->dev, ras2_ctx, &ras2_scrub_ops); + if (IS_ERR(hw_scrub_dev)) + return PTR_ERR(hw_scrub_dev); + + ras2_ctx->scrub_dev = hw_scrub_dev; + + return 0; +} + +static const struct platform_device_id ras2_id_table[] = { + { .name = "acpi_ras2", }, + { } +}; +MODULE_DEVICE_TABLE(platform, ras2_id_table); + +static struct platform_driver ras2_driver = { + .probe = ras2_probe, + .driver = { + .name = "acpi_ras2", + }, + .id_table = ras2_id_table, +}; +module_driver(ras2_driver, platform_driver_register, platform_driver_unregister); + +MODULE_IMPORT_NS(ACPI_RAS2); +MODULE_DESCRIPTION("ACPI RAS2 memory driver"); +MODULE_LICENSE("GPL");