From patchwork Fri Aug 16 16:42:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766593 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id CFDCEC531DF for ; Fri, 16 Aug 2024 16:43:34 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 3C78C6B0105; Fri, 16 Aug 2024 12:43:33 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 350CD6B0107; Fri, 16 Aug 2024 12:43:33 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 0E46C8D0095; Fri, 16 Aug 2024 12:43:32 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id CC3638D007E for ; Fri, 16 Aug 2024 12:43:32 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 72939160154 for ; Fri, 16 Aug 2024 16:43:32 +0000 (UTC) X-FDA: 82458679464.21.CD26942 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf20.hostedemail.com (Postfix) with ESMTP id 0C5AD1C001B for ; Fri, 16 Aug 2024 16:43:28 +0000 (UTC) Authentication-Results: imf20.hostedemail.com; dkim=none; spf=pass (imf20.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826573; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QgZl+Bmxu5irEkJmBSRuXr/nILpva7a6CA0C6t5FM/I=; b=Tqs1GiVP01Ao2PxdmqeDLoI9kI0HMT60zWGj4Sq0HpzRPJ/kin+2qWvgEqNrGCFnZQLJPN Rc9gKt/OnH8qvnRgkZzPLcwhQKuBTQ1GxE8OwOyc2+gr/r/+7LuGKIT9NL1S60pGTaNAiM 9P/MUzqI5ICQwnjloU10PywHB4mA/Q0= ARC-Authentication-Results: i=1; imf20.hostedemail.com; dkim=none; spf=pass (imf20.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826573; a=rsa-sha256; cv=none; b=WDObE4KuykD3oi5kt1tzdeaqSLnwZ/u81iXWNJ8TCQ9ngWOWmIpGM1vNal3gUtNPb2myI5 Gt95COXCAkJCFKXkghMqb+Xsky3wwYLuaIGNXlquvIFXA7AhOvs9tVc7OvviSCfeGVnwje +8q0XaK+P/TUNtN3hmeVXApUis7oP7A= Received: from mail.maildlp.com (unknown [172.18.186.31]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4WlnmD5Bkzz67Cwc; Sat, 17 Aug 2024 00:40:28 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 02100140A70; Sat, 17 Aug 2024 00:43:27 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:25 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 01/14] EDAC: Add support for EDAC device feature's control Date: Fri, 16 Aug 2024 17:42:24 +0100 Message-ID: <20240816164238.1902-2-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Server: rspam03 X-Rspam-User: X-Rspamd-Queue-Id: 0C5AD1C001B X-Stat-Signature: z353pjqumq4jpzxrr6mrj48kcpcx53hx X-HE-Tag: 1723826608-483122 X-HE-Meta: U2FsdGVkX19Lvm10CoXXm+sW9fTd/qYpm6U+8xPhj4fzw/mjqpw+1RaM1TcPC6Tliw3EqUd66u0pxld8NquW/+1MDm8DRTvCrzt7ZYdSgsqQIRfO6RsySD9VnSsSw186Mn5UPKfD5ijPaZ4XuGdNAztcnyarAwTMofmJZGrzeYt0/clWc5tqcrDIdd29glaLrz+64+RyIAGkV1x8+6PVeNw8tO1tWIGZle2SjiHhQf3M9E+RRjLtKf+x6R2iZ0KUweo+Yq0OTKGPu7HMZ75v4PwToW91s9H5J/z1nKvPpp1XkYwj4VDZCcld1tLRtDxlZpdrrd1MAnNCfjsEkhJhMGt4UUkHKzTxzVpSqBtVC8KROO1Cir6ZHwwgzMUEFYtBhOAJDVoVUrPzGswQ2PK+RjfGWAbmqf3UupX5P5jzMAl437MFYO44ic3Js5QF9rr/DVIlM6MF3J6gMxO0LJqOFurZ2i7KEwQmMC7bhyoIAbVJ4pYuK3Y0/i2zoq8pmJI0VW9Bx2IoPYtazZTvLrywBHj2+ZxoShGSSb7GquhnOkwAZAhCZrqeCYMLGJMGEhk7+/3J/h33F5NrpztE2qS0xCiAw1PmzNUsipJ1uFKkMogAB3AOTPrXnFbdxhsF7hfKxnpqfr5PBLvewpNlIPDBiw/S/j98myxJBYCiPjwqpa7miN7QJj5MbpyZIaWGV1yCA3u4nEPNISHANvQtc/CoRW0unm8w6FrzkZGt2yKJa7n7orr2MXRoKavf5lRMER7BhPYHd0sY9BWMpl9/21pTXw0QF5qUO0ud44ZJmnyfICwKWfpJV++c8EkMi6xhgP7dXwKEbfTdCimk5qNG04wZTAlpmWtEMRCUNcdNjUws8kPbfbnqxVcnk4xAOvSdywUfK77dlQCj51LYSf/lj1Gh6eTq9yAC8uqSliA2TSnEZZfWlF7cOjy61bXtLD126u2VbCX369tJ27cAAssOvtG MtFr+IF6 TkZwu26sJAmXLHB3HKwQlwjTFRH/8QTDZBluHhDkWkukM8wyeawDk5WskbreUj4HTsaYv6PXEc2dbHFo6oWQiNvSutZ3jdIjXdNkTV00mOBVarK/KRqKA5B4J2mo58Hwvnna5HbHl6kBb0g0KSBW01YYU0DXodqbQ00HUIKIz83ngYyD5rBIhudSAyEEynYBN6uOFA3lL10iAF+FGUvCpmZ4IgQ== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Shiju Jose Add generic EDAC device feature's control supports registering RAS features supported in the system. Driver exposes feature's control attributes to the userspace in /sys/bus/edac/devices/// Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- drivers/edac/edac_device.c | 178 +++++++++++++++++++++++++++++++++++++ include/linux/edac.h | 60 +++++++++++++ 2 files changed, 238 insertions(+) diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 621dc2a5d034..635a41db8b5a 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -570,3 +570,181 @@ void edac_device_handle_ue_count(struct edac_device_ctl_info *edac_dev, block ? block->name : "N/A", count, msg); } EXPORT_SYMBOL_GPL(edac_device_handle_ue_count); + +/* EDAC device feature */ +static void edac_dev_release(struct device *dev) +{ + struct edac_dev_feat_ctx *ctx = + container_of(dev, struct edac_dev_feat_ctx, dev); + + kfree(ctx->dev.groups); + kfree(ctx); +} + +const struct device_type edac_dev_type = { + .name = "edac_dev", + .release = edac_dev_release, +}; + +static void edac_dev_unreg(void *data) +{ + device_unregister(data); +} + +/** + * edac_dev_feature_init - Init a ras feature + * @parent: client device. + * @dev_data: pointer to struct edac_dev_data. + * @feat: pointer to struct edac_dev_feature. + * @attr_groups: pointer to attribute group's container. + * + * Returns number of scrub feature's attribute groups on success, + * error otherwise. + */ +static int edac_dev_feat_init(struct device *parent, + struct edac_dev_data *dev_data, + const struct edac_dev_feature *ras_feat, + const struct attribute_group **attr_groups) +{ + int num; + + switch (ras_feat->feat) { + case RAS_FEAT_SCRUB: + dev_data->scrub_ops = ras_feat->scrub_ops; + dev_data->private = ras_feat->scrub_ctx; + return 1; + case RAS_FEAT_ECS: + num = ras_feat->ecs_info.num_media_frus; + dev_data->ecs_ops = ras_feat->ecs_ops; + dev_data->private = ras_feat->ecs_ctx; + return num; + case RAS_FEAT_PPR: + dev_data->ppr_ops = ras_feat->ppr_ops; + dev_data->private = ras_feat->ppr_ctx; + return 1; + default: + return -EINVAL; + } +} + +/** + * edac_dev_register - register device for ras features with edac + * @parent: client device. + * @name: client device's name. + * @private: parent driver's data to store in the context if any. + * @num_features: number of ras features to register. + * @ras_features: list of ras features to register. + * + * Returns 0 on success, error otherwise. + * The new edac_dev_feat_ctx would be freed automatically. + */ +int edac_dev_register(struct device *parent, char *name, + void *private, int num_features, + const struct edac_dev_feature *ras_features) +{ + const struct attribute_group **ras_attr_groups; + struct edac_dev_data *dev_data; + struct edac_dev_feat_ctx *ctx; + int ppr_cnt = 0, ppr_inst = 0; + int attr_gcnt = 0; + int ret, feat; + + if (!parent || !name || !num_features || !ras_features) + return -EINVAL; + + /* Double parse so we can make space for attributes */ + for (feat = 0; feat < num_features; feat++) { + switch (ras_features[feat].feat) { + case RAS_FEAT_SCRUB: + case RAS_FEAT_PPR: + attr_gcnt++; + ppr_cnt++; + break; + case RAS_FEAT_ECS: + attr_gcnt += ras_features[feat].ecs_info.num_media_frus; + break; + default: + return -EINVAL; + } + } + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev.parent = parent; + ctx->private = private; + + ras_attr_groups = kcalloc(attr_gcnt + 1, sizeof(*ras_attr_groups), GFP_KERNEL); + if (!ras_attr_groups) { + ret = -ENOMEM; + goto ctx_free; + } + + if (ppr_cnt) { + ctx->ppr = kcalloc(ppr_cnt, sizeof(*(ctx->ppr)), GFP_KERNEL); + if (!ctx->ppr) { + ret = -ENOMEM; + goto groups_free; + } + } + + attr_gcnt = 0; + for (feat = 0; feat < num_features; feat++, ras_features++) { + switch (ras_features->feat) { + case RAS_FEAT_SCRUB: + if (!ras_features->scrub_ops) + continue; + dev_data = &ctx->scrub; + break; + case RAS_FEAT_ECS: + if (!ras_features->ecs_ops) + continue; + dev_data = &ctx->ecs; + break; + case RAS_FEAT_PPR: + if (!ras_features->ppr_ops) + continue; + dev_data = &ctx->ppr[ppr_inst]; + dev_data->instance = ppr_inst; + ppr_inst++; + break; + default: + ret = -EINVAL; + goto data_mem_free; + } + ret = edac_dev_feat_init(parent, dev_data, ras_features, + &ras_attr_groups[attr_gcnt]); + if (ret < 0) + goto data_mem_free; + + attr_gcnt += ret; + } + ras_attr_groups[attr_gcnt] = NULL; + ctx->dev.bus = edac_get_sysfs_subsys(); + ctx->dev.type = &edac_dev_type; + ctx->dev.groups = ras_attr_groups; + dev_set_drvdata(&ctx->dev, ctx); + ret = dev_set_name(&ctx->dev, name); + if (ret) + goto data_mem_free; + + ret = device_register(&ctx->dev); + if (ret) { + put_device(&ctx->dev); + goto data_mem_free; + return ret; + } + + return devm_add_action_or_reset(parent, edac_dev_unreg, &ctx->dev); + +data_mem_free: + if (ppr_cnt) + kfree(ctx->ppr); +groups_free: + kfree(ras_attr_groups); +ctx_free: + kfree(ctx); + return ret; +} +EXPORT_SYMBOL_GPL(edac_dev_register); diff --git a/include/linux/edac.h b/include/linux/edac.h index b4ee8961e623..cc96f55ac714 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -661,4 +661,64 @@ static inline struct dimm_info *edac_get_dimm(struct mem_ctl_info *mci, return mci->dimms[index]; } + +/* EDAC device features */ + +#define EDAC_FEAT_NAME_LEN 128 + +enum edac_dev_feat { + RAS_FEAT_SCRUB, + RAS_FEAT_ECS, + RAS_FEAT_PPR, + RAS_FEAT_MAX +}; + +struct edac_ecs_ex_info { + u16 num_media_frus; +}; + +/* + * EDAC device feature information structure + */ +struct edac_dev_data { + union { + const struct edac_scrub_ops *scrub_ops; + const struct edac_ecs_ops *ecs_ops; + const struct edac_ppr_ops *ppr_ops; + }; + u8 instance; + void *private; +}; + +struct device; + +struct edac_dev_feat_ctx { + struct device dev; + void *private; + struct edac_dev_data scrub; + struct edac_dev_data ecs; + struct edac_dev_data *ppr; +}; + +struct edac_dev_feature { + enum edac_dev_feat feat; + u8 instance; + union { + const struct edac_scrub_ops *scrub_ops; + const struct edac_ecs_ops *ecs_ops; + const struct edac_ppr_ops *ppr_ops; + }; + union { + void *scrub_ctx; + void *ecs_ctx; + void *ppr_ctx; + }; + union { + struct edac_ecs_ex_info ecs_info; + }; +}; + +int edac_dev_register(struct device *parent, char *dev_name, + void *parent_pvt_data, int num_features, + const struct edac_dev_feature *ras_features); #endif /* _LINUX_EDAC_H_ */ From patchwork Fri Aug 16 16:42:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766595 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 55001C5320D for ; Fri, 16 Aug 2024 16:43:37 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 995E66B0107; Fri, 16 Aug 2024 12:43:33 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 91C776B0108; Fri, 16 Aug 2024 12:43:33 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 796648D007E; Fri, 16 Aug 2024 12:43:33 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id 526BC6B0108 for ; Fri, 16 Aug 2024 12:43:33 -0400 (EDT) Received: from smtpin09.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id F39AEA3F8D for ; Fri, 16 Aug 2024 16:43:32 +0000 (UTC) X-FDA: 82458679464.09.8E97532 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf09.hostedemail.com (Postfix) with ESMTP id 02EF414001C for ; Fri, 16 Aug 2024 16:43:30 +0000 (UTC) Authentication-Results: imf09.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf09.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826538; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=V22ApxHyqCCev7w86iPXIQl/WEWomKq08fExzrwhjPQ=; b=jrVXCTuGOBv3aDLhxLgnYPWrwqRX6O+1wI5KGXxzueZgxugAWtvdEL7iDkATNH7Tl98sBi kmc24nW0ikqNLuJ6/zbXhfJwVmwyER2p99RC3rJV/g1S38zpgZs9p7EarED515VbBgE+au 6fydG8NtWgs1vVKQ32wYyJ2RNLntWqs= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826538; a=rsa-sha256; cv=none; b=RScoAptXUJOKlYnf6ubJEa1yoxCynjfWWCH2s+RYoMEctwfAKAZvPQwDcG+QJJz4iTnAay hHtvAF9UECBsZVbm1iP5GG1e8EWuPOE4DrOIrHmvU4W78JB80QJTUhJkSJ9kqrlh2HeJ6+ StZxUDaDRbYOIejZeKzJCxZkbxMDM8U= ARC-Authentication-Results: i=1; imf09.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf09.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4WlnmX5lTHz6K98p; Sat, 17 Aug 2024 00:40:44 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 21FFA1400C9; Sat, 17 Aug 2024 00:43:29 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:27 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 02/14] EDAC: Add EDAC scrub control driver Date: Fri, 16 Aug 2024 17:42:25 +0100 Message-ID: <20240816164238.1902-3-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Queue-Id: 02EF414001C X-Stat-Signature: 8z97owknt3ngz8iznbtu1bhd9wnek3aj X-Rspamd-Server: rspam09 X-Rspam-User: X-HE-Tag: 1723826610-506434 X-HE-Meta: U2FsdGVkX1+i96DN3pgi06nJtsFjuhpIygT8dg92hTMX/ev7Tefe/8VDlrACMi6ezSkYUm+LcjYvmbndLmlKvuc17mS0SQHez8CAgsn6ukSnIG9UoCV9gR8PinBLWJZTTmsDRuDY3UoHzgVKLwu7xxnPb6LDWLInkk/K0A5bdIDfS7KY2QrBeZpVh4fPlgWz7qbBr3oLipldp4uIBgr1ispjkAAPImZxk4rcjMGW9GTeCcX/Wkg1LtFPAW1OYTqpO7VsHnGbvv2XXpDOMKiiuMQrR00lzYc+CLfAPcMooeVBdTscuBqm/+VARE5FddB4Ni4bk/UkTHoK/x9cyLCXawV5IsC4ZcbXsIAap8y2m2l8xXKGEFiicMJCZTe43qWD1fguC1SFTCURbx4tfvkSKet2IKUylfslWrYAaNqMtwGZUh+rciAWvWfIrmJHjONKuLC5lAeskMf3gHzNUsCkSrFyULik3BENGjZg1sdEzkmC71ujdJ3Olucfm9WgX5ocOhjc6SJVTFf2wO3dt/7Of8Vh8r25mVfyC8yWyucmfaIrkYH4QVVWnkcWcci/ff72p4FdAbHhn1nuvOc5BumLr1Elgsh5ycC6FNWlid/YVHxD7YcTFet4so3Jdg8Rmm5B7SerqxW/VJqkyu4A0sxZislhHe9YKlMkaYll4JodPVzt+DHfeZ7CGVyhsXEi+TNYrXyf39KW6x6eK5I/h9YGTMshNNRJdsL02SLhWA0B5EvaQFOBP2Vi5dOSmvxhvkra9WFfycKLVmC61c8ue++dUumDOfjcTDzelsTWSCK7EIw5n8xD1p4c5t0nHsbFIGpYNxabpk4lW3HDN76Vq5AfHpR8Svd+eYRX+WDH8Ioniw3W59qlXfCmG6n4AMcKaz1hb4vkYyNdp/D9DmoCHgtB8SFub5Oww+nsFxHUq1wSZAlUQ+TvN11ZmYSPzQgVHHSycXzZ91P9vPp7norstoz WcOqda9M 9uzou715pnaBtDBu/kDZX3CuBkoD1rHwdIMgWysVHk9SoWhGQXHbv6sJISbfpULcNc3qkL0AI8epDRcSCdOw/v+rzLVQG96x2puoRYJFtTH+EFsQbTxTqrwOQLj0l+N+ijS+q/0O7UOS5YtfteyKQ2Cu5OW9otFnvoL3ySugDmJVzTVpM9mdLjLtYnnxwwG/j1RlbggFCY8o5KhM0xjA6pVuwKVsbr3CSPMlKxaHMliQz3IA4ASZje418SBAsXDdpShS6c5X7/JFWNmbiu7O9jKex+Ae2woekn3YYYUJORofrmt4= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Shiju Jose Add generic EDAC scrub control driver supports configuring the memory scrubbers in the system. The device with scrub feature, get the scrub descriptor from the EDAC scrub and registers with the EDAC RAS feature driver, which adds the sysfs scrub control interface. The scrub control attributes are available to the userspace in /sys/bus/edac/devices//scrub/. Generic EDAC scrub driver and the common sysfs scrub interface promotes unambiguous access from the userspace irrespective of the underlying scrub devices. The sysfs scrub attribute nodes would be present only if the client driver has implemented the corresponding attribute callback function and pass in ops to the EDAC RAS feature driver during registration. Question: Does EDAC scrub control driver need supporting multiple scrub instances per device like EDAC ECS and EDAC PPR? Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- Documentation/ABI/testing/sysfs-edac-scrub | 69 +++++ drivers/edac/Makefile | 1 + drivers/edac/edac_device.c | 1 + drivers/edac/edac_scrub.c | 315 +++++++++++++++++++++ include/linux/edac.h | 28 ++ 5 files changed, 414 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-edac-scrub create mode 100755 drivers/edac/edac_scrub.c diff --git a/Documentation/ABI/testing/sysfs-edac-scrub b/Documentation/ABI/testing/sysfs-edac-scrub new file mode 100644 index 000000000000..c8b552cfcb17 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-edac-scrub @@ -0,0 +1,69 @@ +What: /sys/bus/edac/devices//scrub +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + The sysfs edac bus devices //scrub subdirectory + belongs to the memory scrub control feature, where + directory corresponds to a device/memory region registered + with the edac scrub driver and thus registered with the + generic edac ras driver too. + The sysfs scrub attr nodes would be present only if the + client driver has implemented the corresponding attr + callback function and pass in ops to the EDAC RAS feature + driver during registration. + +What: /sys/bus/edac/devices//scrub/addr_range_base +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) The base of the address range of the memory region + to be scrubbed (on-demand scrubbing). + +What: /sys/bus/edac/devices//scrub/addr_range_size +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) The size of the address range of the memory region + to be scrubbed (on-demand scrubbing). + +What: /sys/bus/edac/devices//scrub/enable_background +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) Start/Stop background(patrol) scrubbing if supported. + +What: /sys/bus/edac/devices//scrub/enable_on_demand +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) Start/Stop on-demand scrubbing the memory region + if supported. + +What: /sys/bus/edac/devices//scrub/min_cycle_duration +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) Supported minimum scrub cycle duration in seconds + by the memory scrubber. + +What: /sys/bus/edac/devices//scrub/max_cycle_duration +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) Supported maximum scrub cycle duration in seconds + by the memory scrubber. + +What: /sys/bus/edac/devices//scrub/current_cycle_duration +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) The current scrub cycle duration in seconds and must be + within the supported range by the memory scrubber. diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 9c09893695b7..06047c7ba14e 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_EDAC) := edac_core.o edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_core-y += edac_module.o edac_device_sysfs.o wq.o +edac_core-y += edac_scrub.o edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 635a41db8b5a..0363f55e39d1 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -612,6 +612,7 @@ static int edac_dev_feat_init(struct device *parent, case RAS_FEAT_SCRUB: dev_data->scrub_ops = ras_feat->scrub_ops; dev_data->private = ras_feat->scrub_ctx; + attr_groups[0] = edac_scrub_get_desc(); return 1; case RAS_FEAT_ECS: num = ras_feat->ecs_info.num_media_frus; diff --git a/drivers/edac/edac_scrub.c b/drivers/edac/edac_scrub.c new file mode 100755 index 000000000000..1b994933826b --- /dev/null +++ b/drivers/edac/edac_scrub.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic EDAC scrub driver supports controlling the memory + * scrubbers in the system and the common sysfs scrub interface + * promotes unambiguous access from the userspace. + * + * Copyright (c) 2024 HiSilicon Limited. + */ + +#define pr_fmt(fmt) "EDAC SCRUB: " fmt + +#include + +static ssize_t addr_range_base_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + u64 base, size; + int ret; + + ret = ops->read_range(ras_feat_dev->parent, ctx->scrub.private, &base, &size); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%llx\n", base); +} + +static ssize_t addr_range_size_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + u64 base, size; + int ret; + + ret = ops->read_range(ras_feat_dev->parent, ctx->scrub.private, &base, &size); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%llx\n", size); +} + +static ssize_t addr_range_base_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + u64 base, size; + int ret; + + ret = ops->read_range(ras_feat_dev->parent, ctx->scrub.private, &base, &size); + if (ret) + return ret; + + ret = kstrtou64(buf, 0, &base); + if (ret < 0) + return ret; + + ret = ops->write_range(ras_feat_dev->parent, ctx->scrub.private, base, size); + if (ret) + return ret; + + return len; +} + +static ssize_t addr_range_size_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + u64 base, size; + int ret; + + ret = ops->read_range(ras_feat_dev->parent, ctx->scrub.private, &base, &size); + if (ret) + return ret; + + ret = kstrtou64(buf, 0, &size); + if (ret < 0) + return ret; + + ret = ops->write_range(ras_feat_dev->parent, ctx->scrub.private, base, size); + if (ret) + return ret; + + return len; +} + +static ssize_t enable_background_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + ret = ops->set_enabled_bg(ras_feat_dev->parent, ctx->scrub.private, enable); + if (ret) + return ret; + + return len; +} + +static ssize_t enable_background_show(struct device *ras_feat_dev, + struct device_attribute *attr, char *buf) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + bool enable; + int ret; + + ret = ops->get_enabled_bg(ras_feat_dev->parent, ctx->scrub.private, &enable); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", enable); +} + +static ssize_t enable_on_demand_show(struct device *ras_feat_dev, + struct device_attribute *attr, char *buf) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + bool enable; + int ret; + + ret = ops->get_enabled_od(ras_feat_dev->parent, ctx->scrub.private, &enable); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", enable); +} + +static ssize_t enable_on_demand_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + bool enable; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret < 0) + return ret; + + ret = ops->set_enabled_od(ras_feat_dev->parent, ctx->scrub.private, enable); + if (ret) + return ret; + + return len; +} + +static ssize_t min_cycle_duration_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + u32 val; + int ret; + + ret = ops->min_cycle_read(ras_feat_dev->parent, ctx->scrub.private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t max_cycle_duration_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + u32 val; + int ret; + + ret = ops->max_cycle_read(ras_feat_dev->parent, ctx->scrub.private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t current_cycle_duration_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + u32 val; + int ret; + + ret = ops->cycle_duration_read(ras_feat_dev->parent, ctx->scrub.private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t current_cycle_duration_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_scrub_ops *ops = ctx->scrub.scrub_ops; + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + if (ret < 0) + return ret; + + ret = ops->cycle_duration_write(ras_feat_dev->parent, ctx->scrub.private, val); + if (ret) + return ret; + + return len; +} + +static DEVICE_ATTR_RW(addr_range_base); +static DEVICE_ATTR_RW(addr_range_size); +static DEVICE_ATTR_RW(enable_background); +static DEVICE_ATTR_RW(enable_on_demand); +static DEVICE_ATTR_RO(min_cycle_duration); +static DEVICE_ATTR_RO(max_cycle_duration); +static DEVICE_ATTR_RW(current_cycle_duration); + +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_min_cycle_duration.attr, + &dev_attr_max_cycle_duration.attr, + &dev_attr_current_cycle_duration.attr, + NULL +}; + +static umode_t scrub_attr_visible(struct kobject *kobj, + struct attribute *a, int attr_id) +{ + struct device *ras_feat_dev = kobj_to_dev(kobj); + struct edac_dev_feat_ctx *ctx; + const struct edac_scrub_ops *ops; + + ctx = dev_get_drvdata(ras_feat_dev); + if (!ctx) + return 0; + + ops = ctx->scrub.scrub_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; + if (ops->get_enabled_bg) + 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_min_cycle_duration.attr) + return ops->min_cycle_read ? a->mode : 0; + if (a == &dev_attr_max_cycle_duration.attr) + return ops->max_cycle_read ? a->mode : 0; + if (a == &dev_attr_current_cycle_duration.attr) { + if (ops->cycle_duration_read && ops->cycle_duration_write) + return a->mode; + if (ops->cycle_duration_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, +}; + +/** + * edac_scrub_get_desc - get edac scrub's attr descriptor + * + * Returns attribute_group for the scrub feature. + */ +const struct attribute_group *edac_scrub_get_desc(void) +{ + return &scrub_attr_group; +} diff --git a/include/linux/edac.h b/include/linux/edac.h index cc96f55ac714..48e535db19d2 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -673,6 +673,34 @@ enum edac_dev_feat { RAS_FEAT_MAX }; +/** + * 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. + * @min_cycle_read: minimum supported scrub cycle duration in seconds. + * @max_cycle_read: maximum supported scrub cycle duration in seconds. + * @cycle_duration_read: get the scrub cycle duration in seconds. + * @cycle_duration_write: set the scrub cycle duration in seconds. + */ +struct edac_scrub_ops { + int (*read_range)(struct device *dev, void *drv_data, u64 *base, u64 *size); + int (*write_range)(struct device *dev, void *drv_data, u64 base, u64 size); + int (*get_enabled_bg)(struct device *dev, void *drv_data, bool *enable); + int (*set_enabled_bg)(struct device *dev, void *drv_data, bool enable); + int (*get_enabled_od)(struct device *dev, void *drv_data, bool *enable); + int (*set_enabled_od)(struct device *dev, void *drv_data, bool enable); + int (*min_cycle_read)(struct device *dev, void *drv_data, u32 *min); + int (*max_cycle_read)(struct device *dev, void *drv_data, u32 *max); + int (*cycle_duration_read)(struct device *dev, void *drv_data, u32 *cycle); + int (*cycle_duration_write)(struct device *dev, void *drv_data, u32 cycle); +}; + +const struct attribute_group *edac_scrub_get_desc(void); + struct edac_ecs_ex_info { u16 num_media_frus; }; From patchwork Fri Aug 16 16:42:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766597 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 58C1EC3DA4A for ; Fri, 16 Aug 2024 16:43:42 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 4D8E58D0095; Fri, 16 Aug 2024 12:43:39 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 461608D007E; Fri, 16 Aug 2024 12:43:39 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 241708D0095; Fri, 16 Aug 2024 12:43:39 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id E6A6E8D007E for ; Fri, 16 Aug 2024 12:43:38 -0400 (EDT) Received: from smtpin05.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id 3DE2980182 for ; Fri, 16 Aug 2024 16:43:37 +0000 (UTC) X-FDA: 82458679674.05.D924EC9 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf16.hostedemail.com (Postfix) with ESMTP id 1ED3D18000D for ; Fri, 16 Aug 2024 16:43:34 +0000 (UTC) Authentication-Results: imf16.hostedemail.com; dkim=none; spf=pass (imf16.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826541; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kuztfciwcn3Fr3N9b9dhuPBlNZ9q0DqLdtRf5tiJFfs=; b=Zur8YfJpgwUueii3skY5M80Vxeqh7+HfLWwJhdnU0ReY0VQhsglm3bK8bIxwpivB3ERTxD aoCwJp5lwmxKgUp8xlvDnEJhNKh3IwFeMt9koYe2ujS2vBb3GsHGllYcwsonZB0nKMvT5c 6FReoonOlVNLWM/mUf19cYWOcgV/l5M= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826541; a=rsa-sha256; cv=none; b=Mw2NHa5sT7WuR2090JAaAB6sWlz3HtovfA1E1ezmmCX9EP4CtZFQvHehuaz8VKyHpUPDxn w3mIssSm6xh7TomeS2jVmvBw3ipuV6iVhpcqzhXSk3DKINt9/0xrNcnNMc08Jv65uAUK5q qmADMwdXZz4l5v3bD/p/ea7TCVYM2Lo= ARC-Authentication-Results: i=1; imf16.hostedemail.com; dkim=none; spf=pass (imf16.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.216]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4WlnmZ6sGDz6K98x; Sat, 17 Aug 2024 00:40:46 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 487A81400DB; Sat, 17 Aug 2024 00:43:31 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:29 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 03/14] EDAC: Add EDAC ECS control driver Date: Fri, 16 Aug 2024 17:42:26 +0100 Message-ID: <20240816164238.1902-4-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspam-User: X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: 1ED3D18000D X-Stat-Signature: b9ktdkcb78t6wcgnrikksrprik6txcs8 X-HE-Tag: 1723826614-499248 X-HE-Meta: U2FsdGVkX19qAhjUH62zNKPE9wkJlPEPmbAhi3UXyj4ijvxgTmUohwFExsnovOCPnCq1Myp8JW8AO4u2iBI32/m3N38t474VXzm9KD0e9CQHuOOQdFfFg847YtAmoS5XYqoDR2mdsux+34tBT0BnSdRSaoMl2UGN4h2IzpCaNsdtlww7ev3xUidJBcUrkoZL6yx1knhi4Uoxv/QfhcC5BJcDD99pXjK7sojqymBS3/7glylpEkeL6LuuLfqOqr7GQmGSvDpljDoSPJ9TFzcKI6J02eZYVOLfnT5SrauRWLUE9JdNaB052rPtDZqHdH7nEQKZvUvy2U2/EtxjZm6Yi010o+AhNm48QZvf86SIGo9FcZh54Ov+AtkYwi+9li4Yfh2ore0sVDaSrEWdzdkEOg8l7VN4PjsUw8XtTFvgouNPGzw1O7r499y9H1vl2eGqu1IhtEmVFtYBgHV/bgysntBDp7a82VEzvQFGvbmr2Hi1b8Pw2Vkd+0cw/51JAFsWp6BujFSQh74ZCbJr3ySAS9mamsCbGcCduQ9mEjDUv4kt9bNRZakjE6cmAc0nUKWgV5jbTpTk6vFdGVQw+i8Swl+BT0uIuW+heCObnjKSxr+sDhpXdKRy1i8ITlmsUT6UXkWaKCrKZnNvgBs5gRX7cexhMma77alWhpGdgnxzPtVqEmn9fa1i1wIUQ/AgGB8mx6iuLIOm670m7x4rmWu6lLlg/rXoEhuoVS2w2NsQzHaES3+2nEYLyjstZnP8AugH+yWITl9oJWmH1PkJyEEMdzWkZ0zAnKoXrBR9dZCblM94bGlJg5Z2pL6Fg8d7bp+UYjxUWJXi0aoPo1z96oEPAkRrPmUkuHHbEjqxzmIpiQn0r8LvoXP0uWQ0gaVAyDQU/RXFsXtYHRr5t5er6FYWWevU0iejj/2kJDfL8nkfDCc1u3mRl7Jy/U+y+Hwqhb7qPf7/oWc0j6Sd0WxwNPo 2TmIJI08 561uZ4q/kST5d/0Lx0IXN+QhMBO3CinVQU1oasY1WxzdI/s/Dab3G0PnoF4QSwhpDwBn+XQ1twhp5TuaR5+qmSPwP+p9r8rsesqZUvRxxwOrysbXuJWB1Dao89GcJWm5QUgh2ZUcNQ4AJSFzrni0WCnKpjhxHh3ZkiKl6WkPuGdQk5AWrBpUlOhiAA71pVarXhBgv+pXgsTOFTCtO+ASlY6SQCzvXC46YMo2EE8J7hhqwV5nwWSIWVG7zJSSmgKDpPgXWrRsi1pIinT3+wm0RHxI1g1G+Qa09vIVE42iOmDAqEMs= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Shiju Jose Add EDAC ECS (Error Check Scrub) control driver supports configuring the memory device's ECS feature. The Error Check Scrub (ECS) is a feature defined in JEDEC DDR5 SDRAM Specification (JESD79-5) and allows the DRAM to internally read, correct single-bit errors, and write back corrected data bits to the DRAM array while providing transparency to error counts. The DDR5 device contains number of memory media FRUs per device. The DDR5 ECS feature and thus the ECS control driver supports configuring the ECS parameters per FRU. The memory devices support ECS feature register with the EDAC ECS driver and thus with the generic EDAC RAS feature driver, which adds the sysfs ECS control interface. The ECS control attributes are exposed to the userspace in /sys/bus/edac/devices//ecs_fruX/. Generic EDAC ECS driver and the common sysfs ECS interface promotes unambiguous control from the userspace irrespective of the underlying devices, support ECS feature. The support for ECS feature is added separately because the DDR5 ECS feature's control attributes are dissimilar from those of the scrub feature. The sysfs ECS attr nodes would be present only if the client driver has implemented the corresponding attr callback function and pass in ops to the EDAC RAS feature driver during registration. Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- Documentation/ABI/testing/sysfs-edac-ecs | 78 +++++ drivers/edac/Makefile | 2 +- drivers/edac/edac_device.c | 4 + drivers/edac/edac_ecs.c | 376 +++++++++++++++++++++++ include/linux/edac.h | 34 ++ 5 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-edac-ecs create mode 100755 drivers/edac/edac_ecs.c diff --git a/Documentation/ABI/testing/sysfs-edac-ecs b/Documentation/ABI/testing/sysfs-edac-ecs new file mode 100644 index 000000000000..aff6ebcc8a24 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-edac-ecs @@ -0,0 +1,78 @@ +What: /sys/bus/edac/devices//ecs_fru* +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + The sysfs edac bus devices //ecs_fru* subdirectory + belongs to the memory media ECS (Error Check Scrub) control + feature, where directory corresponds to a device + registered with the EDAC ECS driver and thus registered with + the generic edac ras driver too. + /ecs_fru* belongs to the media FRUs (Field replaceable unit) + under the memory device. + The sysfs ECS attr nodes would be present only if the client + driver has implemented the corresponding attr callback + function and pass in ops to the EDAC RAS feature driver + during registration. + +What: /sys/bus/edac/devices//ecs_fru*/log_entry_type +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) The log entry type of how the DDR5 ECS log is reported. + 00b - per DRAM. + 01b - per memory media FRU. + +What: /sys/bus/edac/devices//ecs_fru*/log_entry_type_per_dram +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) True if current log entry type is per DRAM. + +What: /sys/bus/edac/devices//ecs_fru*/log_entry_type_per_memory_media +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) True if current log entry type is per memory media FRU. + +What: /sys/bus/edac/devices//ecs_fru*/mode +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) The mode of how the DDR5 ECS counts the errors. + 0 - ECS counts rows with errors. + 1 - ECS counts codewords with errors. + +What: /sys/bus/edac/devices//ecs_fru*/mode_counts_rows +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) True if current mode is ECS counts rows with errors. + +What: /sys/bus/edac/devices//ecs_fru*/mode_counts_codewords +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) True if current mode is ECS counts codewords with errors. + +What: /sys/bus/edac/devices//ecs_fru*/reset +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (WO) ECS reset ECC counter. + 0 - normal, ECC counter running actively. + 1 - reset ECC counter to the default value. + +What: /sys/bus/edac/devices//ecs_fru*/threshold +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) ECS threshold count per GB of memory cells. diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 06047c7ba14e..4645e4032523 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC) := edac_core.o edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_core-y += edac_module.o edac_device_sysfs.o wq.o -edac_core-y += edac_scrub.o +edac_core-y += edac_scrub.o edac_ecs.o edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 0363f55e39d1..17e7ded01b22 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -606,6 +606,7 @@ static int edac_dev_feat_init(struct device *parent, const struct edac_dev_feature *ras_feat, const struct attribute_group **attr_groups) { + int ret; int num; switch (ras_feat->feat) { @@ -618,6 +619,9 @@ static int edac_dev_feat_init(struct device *parent, num = ras_feat->ecs_info.num_media_frus; dev_data->ecs_ops = ras_feat->ecs_ops; dev_data->private = ras_feat->ecs_ctx; + ret = edac_ecs_get_desc(parent, attr_groups, num); + if (ret) + return ret; return num; case RAS_FEAT_PPR: dev_data->ppr_ops = ras_feat->ppr_ops; diff --git a/drivers/edac/edac_ecs.c b/drivers/edac/edac_ecs.c new file mode 100755 index 000000000000..2de18c3f06ed --- /dev/null +++ b/drivers/edac/edac_ecs.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ECS driver supporting controlling on die error check scrub + * (e.g. DDR5 ECS). The common sysfs ECS interface promotes + * unambiguous access from the userspace. + * + * Copyright (c) 2024 HiSilicon Limited. + */ + +#define pr_fmt(fmt) "EDAC ECS: " fmt + +#include + +#define EDAC_ECS_FRU_NAME "ecs_fru" + +enum edac_ecs_attributes { + ECS_LOG_ENTRY_TYPE, + ECS_LOG_ENTRY_TYPE_PER_DRAM, + ECS_LOG_ENTRY_TYPE_PER_MEMORY_MEDIA, + ECS_MODE, + ECS_MODE_COUNTS_ROWS, + ECS_MODE_COUNTS_CODEWORDS, + ECS_RESET, + ECS_THRESHOLD, + ECS_MAX_ATTRS +}; + +struct edac_ecs_dev_attr { + struct device_attribute dev_attr; + int fru_id; +}; + +struct edac_ecs_fru_context { + char name[EDAC_FEAT_NAME_LEN]; + struct edac_ecs_dev_attr ecs_dev_attr[ECS_MAX_ATTRS]; + struct attribute *ecs_attrs[ECS_MAX_ATTRS + 1]; + struct attribute_group group; +}; + +struct edac_ecs_context { + u16 num_media_frus; + struct edac_ecs_fru_context *fru_ctxs; +}; + +#define to_ecs_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct edac_ecs_dev_attr, dev_attr) + +static ssize_t log_entry_type_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + u32 val; + int ret; + + ret = ops->get_log_entry_type(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t log_entry_type_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + if (ret < 0) + return ret; + + ret = ops->set_log_entry_type(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, val); + if (ret) + return ret; + + return len; +} + +static ssize_t log_entry_type_per_dram_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + u32 val; + int ret; + + ret = ops->get_log_entry_type_per_dram(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t log_entry_type_per_memory_media_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + u32 val; + int ret; + + ret = ops->get_log_entry_type_per_memory_media(ras_feat_dev->parent, + ctx->ecs.private, + ecs_dev_attr->fru_id, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t mode_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + u32 val; + int ret; + + ret = ops->get_mode(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t mode_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + if (ret < 0) + return ret; + + ret = ops->set_mode(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, val); + if (ret) + return ret; + + return len; +} + +static ssize_t mode_counts_rows_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + u32 val; + int ret; + + ret = ops->get_mode_counts_rows(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t mode_counts_codewords_show(struct device *ras_feat_dev, + struct device_attribute *attr, + char *buf) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + u32 val; + int ret; + + ret = ops->get_mode_counts_codewords(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t reset_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + if (ret < 0) + return ret; + + ret = ops->reset(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, val); + if (ret) + return ret; + + return len; +} + +static ssize_t threshold_show(struct device *ras_feat_dev, + struct device_attribute *attr, char *buf) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + int ret; + u32 val; + + ret = ops->get_threshold(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t threshold_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct edac_ecs_dev_attr *ecs_dev_attr = to_ecs_dev_attr(attr); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + if (ret < 0) + return ret; + + ret = ops->set_threshold(ras_feat_dev->parent, ctx->ecs.private, + ecs_dev_attr->fru_id, val); + if (ret) + return ret; + + return len; +} + +static umode_t ecs_attr_visible(struct kobject *kobj, + struct attribute *a, int attr_id) +{ + struct device *ras_feat_dev = kobj_to_dev(kobj); + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ecs_ops *ops = ctx->ecs.ecs_ops; + + switch (attr_id) { + case ECS_LOG_ENTRY_TYPE: + if (ops->get_log_entry_type && ops->set_log_entry_type) + return a->mode; + if (ops->get_log_entry_type) + return 0444; + return 0; + case ECS_LOG_ENTRY_TYPE_PER_DRAM: + return ops->get_log_entry_type_per_dram ? a->mode : 0; + case ECS_LOG_ENTRY_TYPE_PER_MEMORY_MEDIA: + return ops->get_log_entry_type_per_memory_media ? a->mode : 0; + case ECS_MODE: + if (ops->get_mode && ops->set_mode) + return a->mode; + if (ops->get_mode) + return 0444; + return 0; + case ECS_MODE_COUNTS_ROWS: + return ops->get_mode_counts_rows ? a->mode : 0; + case ECS_MODE_COUNTS_CODEWORDS: + return ops->get_mode_counts_codewords ? a->mode : 0; + case ECS_RESET: + return ops->reset ? a->mode : 0; + case ECS_THRESHOLD: + if (ops->get_threshold && ops->set_threshold) + return a->mode; + if (ops->get_threshold) + return 0444; + return 0; + default: + return 0; + } +} + +#define EDAC_ECS_ATTR_RO(_name, _fru_id) \ + ((struct edac_ecs_dev_attr) { .dev_attr = __ATTR_RO(_name), \ + .fru_id = _fru_id }) + +#define EDAC_ECS_ATTR_WO(_name, _fru_id) \ + ((struct edac_ecs_dev_attr) { .dev_attr = __ATTR_WO(_name), \ + .fru_id = _fru_id }) + +#define EDAC_ECS_ATTR_RW(_name, _fru_id) \ + ((struct edac_ecs_dev_attr) { .dev_attr = __ATTR_RW(_name), \ + .fru_id = _fru_id }) + +static int ecs_create_desc(struct device *ecs_dev, + const struct attribute_group **attr_groups, + u16 num_media_frus) +{ + struct edac_ecs_context *ecs_ctx; + u32 fru; + + ecs_ctx = devm_kzalloc(ecs_dev, sizeof(*ecs_ctx), GFP_KERNEL); + if (!ecs_ctx) + return -ENOMEM; + + ecs_ctx->num_media_frus = num_media_frus; + ecs_ctx->fru_ctxs = devm_kcalloc(ecs_dev, num_media_frus, + sizeof(*ecs_ctx->fru_ctxs), + GFP_KERNEL); + if (!ecs_ctx->fru_ctxs) + return -ENOMEM; + + for (fru = 0; fru < num_media_frus; fru++) { + struct edac_ecs_fru_context *fru_ctx = &ecs_ctx->fru_ctxs[fru]; + struct attribute_group *group = &fru_ctx->group; + int i; + + fru_ctx->ecs_dev_attr[0] = EDAC_ECS_ATTR_RW(log_entry_type, fru); + fru_ctx->ecs_dev_attr[1] = EDAC_ECS_ATTR_RO(log_entry_type_per_dram, fru); + fru_ctx->ecs_dev_attr[2] = EDAC_ECS_ATTR_RO(log_entry_type_per_memory_media, fru); + fru_ctx->ecs_dev_attr[3] = EDAC_ECS_ATTR_RW(mode, fru); + fru_ctx->ecs_dev_attr[4] = EDAC_ECS_ATTR_RO(mode_counts_rows, fru); + fru_ctx->ecs_dev_attr[5] = EDAC_ECS_ATTR_RO(mode_counts_codewords, fru); + fru_ctx->ecs_dev_attr[6] = EDAC_ECS_ATTR_WO(reset, fru); + fru_ctx->ecs_dev_attr[7] = EDAC_ECS_ATTR_RW(threshold, fru); + for (i = 0; i < ECS_MAX_ATTRS; i++) + fru_ctx->ecs_attrs[i] = &fru_ctx->ecs_dev_attr[i].dev_attr.attr; + + sprintf(fru_ctx->name, "%s%d", EDAC_ECS_FRU_NAME, fru); + group->name = fru_ctx->name; + group->attrs = fru_ctx->ecs_attrs; + group->is_visible = ecs_attr_visible; + + attr_groups[fru] = group; + } + + return 0; +} + +/** + * edac_ecs_get_desc - get edac ecs descriptors + * @ecs_dev: client ecs device + * @attr_groups: pointer to attrribute group container + * @num_media_frus: number of media FRUs in the device + * + * Returns 0 on success, error otherwise. + */ +int edac_ecs_get_desc(struct device *ecs_dev, + const struct attribute_group **attr_groups, + u16 num_media_frus) +{ + if (!ecs_dev || !attr_groups || !num_media_frus) + return -EINVAL; + + return ecs_create_desc(ecs_dev, attr_groups, num_media_frus); +} diff --git a/include/linux/edac.h b/include/linux/edac.h index 48e535db19d2..86fc4ee97f20 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -701,10 +701,44 @@ struct edac_scrub_ops { const struct attribute_group *edac_scrub_get_desc(void); +/** + * struct ecs_ops - ECS device operations (all elements optional) + * @get_log_entry_type: read the log entry type value. + * @set_log_entry_type: set the log entry type value. + * @get_log_entry_type_per_dram: read the log entry type per dram value. + * @get_log_entry_type_memory_media: read the log entry type per memory media value. + * @get_mode: read the mode value. + * @set_mode: set the mode value. + * @get_mode_counts_rows: read the mode counts rows value. + * @get_mode_counts_codewords: read the mode counts codewords value. + * @reset: reset the ECS counter. + * @get_threshold: read the threshold value. + * @set_threshold: set the threshold value. + */ +struct edac_ecs_ops { + int (*get_log_entry_type)(struct device *dev, void *drv_data, int fru_id, u32 *val); + int (*set_log_entry_type)(struct device *dev, void *drv_data, int fru_id, u32 val); + int (*get_log_entry_type_per_dram)(struct device *dev, void *drv_data, + int fru_id, u32 *val); + int (*get_log_entry_type_per_memory_media)(struct device *dev, void *drv_data, + int fru_id, u32 *val); + int (*get_mode)(struct device *dev, void *drv_data, int fru_id, u32 *val); + int (*set_mode)(struct device *dev, void *drv_data, int fru_id, u32 val); + int (*get_mode_counts_rows)(struct device *dev, void *drv_data, int fru_id, u32 *val); + int (*get_mode_counts_codewords)(struct device *dev, void *drv_data, int fru_id, u32 *val); + int (*reset)(struct device *dev, void *drv_data, int fru_id, u32 val); + int (*get_threshold)(struct device *dev, void *drv_data, int fru_id, u32 *threshold); + int (*set_threshold)(struct device *dev, void *drv_data, int fru_id, u32 threshold); +}; + struct edac_ecs_ex_info { u16 num_media_frus; }; +int edac_ecs_get_desc(struct device *ecs_dev, + const struct attribute_group **attr_groups, + u16 num_media_frus); + /* * EDAC device feature information structure */ From patchwork Fri Aug 16 16:42:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766596 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id EB4CEC531DC for ; Fri, 16 Aug 2024 16:43:39 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2B7068D0093; Fri, 16 Aug 2024 12:43:38 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 1F39F8D007E; Fri, 16 Aug 2024 12:43:38 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id F38668D0093; Fri, 16 Aug 2024 12:43:37 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id C9E8F8D007E for ; Fri, 16 Aug 2024 12:43:37 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 695A9140118 for ; Fri, 16 Aug 2024 16:43:37 +0000 (UTC) X-FDA: 82458679674.27.B7CAB40 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf03.hostedemail.com (Postfix) with ESMTP id 6AB7820004 for ; Fri, 16 Aug 2024 16:43:35 +0000 (UTC) Authentication-Results: imf03.hostedemail.com; dkim=none; spf=pass (imf03.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826579; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0ePB1klFb0vx0WueODFfMsJXNqkz8W5Felq6yt1uZXA=; b=bYOP4WaN7pyngzYzZ5LMmLlrHnMnrApl/co1ohnaXoOOXQk1XeA0btUqisKNb+yFgPbpfM +yrDqD9+5ORhH/eQUYkCrfWAc+2Y08viffp7tFvmGke5R1z1TZKtzs9ZnxjAATeTDW5gly HqJGJLC9m8Vfg08efYTse6bjPFMc+wY= ARC-Authentication-Results: i=1; imf03.hostedemail.com; dkim=none; spf=pass (imf03.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826579; a=rsa-sha256; cv=none; b=zAlCeAI9lcfk5zxBFDifoApMiGQr8EVjMC41pBSDsH139Nm0FEEF8AqB0LxGCZSLSAHsTe fcU15rsRqO9WImn8+86Clz4CEMYZigh4xjiObak5yR9/D0j0J1qSJEKWwjG53EUub/SXD/ AZ9R0vdV6NLk5alZJvSy5s3AISNU7LA= Received: from mail.maildlp.com (unknown [172.18.186.31]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnlt3czQz6K5st; Sat, 17 Aug 2024 00:40:10 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 7B00C1400D3; Sat, 17 Aug 2024 00:43:33 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:32 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 04/14] cxl/mbox: Add GET_SUPPORTED_FEATURES mailbox command Date: Fri, 16 Aug 2024 17:42:27 +0100 Message-ID: <20240816164238.1902-5-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Server: rspam03 X-Rspam-User: X-Rspamd-Queue-Id: 6AB7820004 X-Stat-Signature: ztwbx7ya35tiw1dm53en5kqttnphwgub X-HE-Tag: 1723826615-815775 X-HE-Meta: U2FsdGVkX1/o0hM5dHzsQzCYLDLThxkw71MdSQBgYwezll9o8o9LGULJKXqUf4AS/PftH7qeccVnooqB2DQ4rSQppBwD/0T5ijOlIUpJ660r7uyqQcrMb1qyZbqW3iXdEgxvB69hZuLi5gMx1LoaL6wylEJ812VAtgvlT4Ew/y1+J8b10t2zsImZXyHSuEU1tWF5sXmRBpg5aKRqEPx6u4SrsZc8tRZf3cg0rn4liUmTIHGrDV4IwTlXX1+PQfYJq2eiosLr13k73sg1fsJNiuzt9Lfie9xrjBKM/aa/b1t1rBoebF3767KznT51pOShH58+2llNpRO5bgDArn5FmZMUOyGITcktf3LLN870+26dW8yFB6qteKVMaAGjNEjD89wpPsQzEoDM5NdVeZZbUehI69N4UeeR2mcNBg+1L039Ttm/wT/CnZO3g3zl2wWsSbA8FLuM0Ru27JVtb7mKSYGTeEpeedhoLdzvjEa2rIVLW2tBeu7n6eYH6wKMKy/HO0L+06EsX+lFv1B8/lBBHx2pC8G8LJ3gjpCmiK4KopyR4f++PBPTG8U6gWwYo2QzhiIjV+22RXZrTv2/X/5V9/tgpoZ41/AOODhqMs7jlzm/DdanyLI/DhkloPh+Pq16cLGsy9PmHsZjg05Q8NeanRQwaIhPnltIN0DhXONWSKhYJj7XbNNMNv3jhgqWmcsGLK6yEKZ6VOuwjDue0/WNf3+fCtvLwK1kooOaMopTGN+YThMITo/s44oU9S+mW5we2bmSY3AthdwPvRov0J1MySG0dz9yTjSQDQgGqVZWRku0HfRr+s9Ejc9o4zu9Sd6k399B09UmFxfQYlVaIr0u4vpA/KP1u2p3uaLox0RL7MehhLU7Cn9qahMAX6mDpD10k8OyAW6XEEapXflgRmyQAf8WqY1sHWEu3kwnv+fYGN0nDDolSjyrSKeSWxxB1OlAuNK0FsbIYf4hVBo27IP sydxrFMF sTYBDlc3lwIMQhRCd8DwTk2C3/phQ/mlHO9+v41E+lcM4oyVXRT87GK+/mt91GRXqne/4dxudv4ZOmFps6QQmeSXuqjUgoOVLwGcGY6xc4SUh9KOibhIQCSEdalbSZluDLOUa7Fa8YDqJvnGoOEaZNxH+w66y2CH8IzOFMsT+T/UVJbdH0pBvfd2wNAW07zlpLO73bPV+e6rZktakl8iUCOmSO9ZMsS8Rp2ZuRSwb1uBrxoaYjlnWE0NWoD08HoVsvPYy79cIV9GLkbg= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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 support features with changeable attributes. CXL spec 3.1 section 8.2.9.6.1 describes Get Supported features command. 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 | 68 +++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 63 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 2626f3fff201..760fa3e1075f 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1324,6 +1324,74 @@ 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_get_supported_feature_entry(struct cxl_memdev_state *mds, const uuid_t *feat_uuid, + struct cxl_mbox_supp_feat_entry *feat_entry_out) +{ + struct cxl_mbox_supp_feat_entry *feat_entry; + 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; + } +} +EXPORT_SYMBOL_NS_GPL(cxl_get_supported_feature_entry, 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 af8169ccdbc0..9939c771f642 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -531,6 +531,7 @@ enum cxl_opcode { CXL_MBOX_OP_GET_LOG_CAPS = 0x0402, CXL_MBOX_OP_CLEAR_LOG = 0x0403, CXL_MBOX_OP_GET_SUP_LOG_SUBLIST = 0x0405, + 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, @@ -700,6 +701,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; @@ -831,6 +889,11 @@ 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_get_supported_feature_entry(struct cxl_memdev_state *mds, const uuid_t *feat_uuid, + struct cxl_mbox_supp_feat_entry *feat_entry_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 Aug 16 16:42:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766598 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7921EC531DF for ; Fri, 16 Aug 2024 16:43:45 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 616276B011A; Fri, 16 Aug 2024 12:43:40 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 4FE106B0120; Fri, 16 Aug 2024 12:43:40 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 32B588D007E; Fri, 16 Aug 2024 12:43:40 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 0CA656B011A for ; Fri, 16 Aug 2024 12:43:40 -0400 (EDT) Received: from smtpin10.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id C11F6C012C for ; Fri, 16 Aug 2024 16:43:39 +0000 (UTC) X-FDA: 82458679758.10.EE4D0FE Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf23.hostedemail.com (Postfix) with ESMTP id C2F53140008 for ; Fri, 16 Aug 2024 16:43:37 +0000 (UTC) Authentication-Results: imf23.hostedemail.com; dkim=none; spf=pass (imf23.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826604; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fzdWhbc3IUml8oUVho/VdgdE1Q4izvcl7uFhyDf6MjE=; b=cBnrcMDKFUOQ6ZFsH5E80o0C2Q+mCcNjf5CGDG7DhW0apVKGKG898acI6issuASV3vlxdI r8G+VvdDZk8wbVby1YCiwGYqKB/ArJtujMOajUW1TcrAWc4Mmj7Lk2Tw6RTNb3knujOKAB n61oSFW04Rrb3f0W6EOv0nol3chX47w= ARC-Authentication-Results: i=1; imf23.hostedemail.com; dkim=none; spf=pass (imf23.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826604; a=rsa-sha256; cv=none; b=cVuAq2gEcm1LXXAE7aDzgSE2DQDWsjzV99Mnqd8wADy8YSveSdYLUkBbnHfyJvJ9XAt7ZM Txk6W+ufugBgJu3U5qHQAi+3vqQCVLFC1l9cGb8JjS7Q11cL+P0hQv6izUmo1mROjfSeEr 7oEQWwfj1Qem0CRDdfir8eUvcyzxq2M= Received: from mail.maildlp.com (unknown [172.18.186.216]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnlw6Wphz6K5q1; Sat, 17 Aug 2024 00:40:12 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id DF9D2140A36; Sat, 17 Aug 2024 00:43:35 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:34 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 05/14] cxl/mbox: Add GET_FEATURE mailbox command Date: Fri, 16 Aug 2024 17:42:28 +0100 Message-ID: <20240816164238.1902-6-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspam-User: X-Stat-Signature: 5umpgnok4ha4fkjhbdwet4pr8ew93wxo X-Rspamd-Queue-Id: C2F53140008 X-Rspamd-Server: rspam11 X-HE-Tag: 1723826617-456663 X-HE-Meta: U2FsdGVkX1/N48KcrxUJII4aHoASrIUxQ/SdP598RJlE9p1OdU2g3HKzMa2SspZjtf+NWGGiaKhiSa+12Tk5s4/Xdd5cPVzyNMVARwmK8qPJmcCZ78bJ6nRg0iAssHF1r3yLKZZ/8UHyCeunzUaF0t33DDszGc8ypbhxV7p3Rrour483P0TPPZ16I8HGOZZ7l01/CvOUICeVNoPtrQIAaX5IVUBaWezlywo2yqAq3b3rdduUWZVBOG8PwV1NFWOBpAjlLLNpvIdCG8e2TcloRJqjEEGgY9Z7X8IwJvXbkE9Oq9VGvLyqyqRKLgZKy0a/z+YNMqAoj7Fw9q3LZWr64Xmjsd3pf+4AIzhkvdS/QgIMn9RWj+uuAEN0nVPDg2CjNcZkIGjb98IdgCDf8hTEifH4UmglF0igo7MaTxjIC2NlNzpTWWUuxJB4hWu09FW/nh9VJztiE/nSvgXAi97mQym3wFKFcXiPEwoaAo5CLu4CpfXgKvxM/y6f4rLAjyMrhkZEDafqVu39kebYAz0KU4PF54gdcEFKGIG6cotNYmt4pUJeBjxdz834kW8N3Jh18vvxMcmLj8LcXq2ns31NODSj5hKArh8/teG2n1v+06nbsrLvOaVMCLY/hsoPpFSDHi7di4OMQ0P0Ata2pDSSASCNkkFR0kTE3SnpL1Th/G8WzCeLiAssveHjBCxl6ClKQhQTxx6M9R/yJlBwPSjet/1fjzV0UJLiBK00xekUV354fcK5hMFtWTv5G4BNNWteG56K1xB9nQgFEOumnRBsPSUzQ9rzpW64zKr9dMfOHop8ntSAHXpzaBZAQyAjiemE/ktNZBlTpeEZ1JzZmu4bOX9uaMM0qBz89ttW7g0f7hsGmoepgQB0DP3OhPZxObfsoftLxFzwlNhkYIkLl/bRuZW7mXMQ549X78bfV+wghqw4kB20dMUWgIW3PP15wYID808XPW/snaS2gUxIsLb 5R/ZGrBP vIglkWmasL8xsgk2ZrRIF3YzUs5fX6rI2Ojc7m/a7BNG3xeJgmyFSaVCbMvYj9IACrGsfYBBEmDLXz8zTGsdI6PdKUX4e2Yl5P9CzxR2vXwtMsio/1IFeY61qojZX/dxI3mtM5M1co3m3P0qQiTtfEXYB8SHxDNJy85q+ZIVCGQ9K5WuKSeWF5yG2UMWc6knHnRWnXWljXOnDc5kqmOeBr60fnGK33cMmAc7fgijn44n++sRBWvftiFAqDS2I2gdOqzTRpgb8f9PZbZU= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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. CXL spec 3.1 section 8.2.9.6.2 describes Get Feature command. Signed-off-by: Shiju Jose --- drivers/cxl/core/mbox.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 27 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 760fa3e1075f..c283684e8e73 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1392,6 +1392,46 @@ int cxl_get_supported_feature_entry(struct cxl_memdev_state *mds, const uuid_t * } EXPORT_SYMBOL_NS_GPL(cxl_get_supported_feature_entry, CXL); +size_t cxl_get_feature(struct cxl_memdev_state *mds, + const uuid_t feat_uuid, + enum cxl_get_feat_selection selection, + void *feat_out, size_t feat_out_size) +{ + size_t data_to_rd_size, size_out; + struct cxl_mbox_get_feat_in pi; + struct cxl_mbox_cmd mbox_cmd; + size_t data_rcvd_size = 0; + int rc; + + if (!feat_out || !feat_out_size) + return 0; + + size_out = min(feat_out_size, mds->payload_size); + pi.uuid = feat_uuid; + pi.selection = selection; + do { + data_to_rd_size = min(feat_out_size - data_rcvd_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) + return 0; + data_rcvd_size += mbox_cmd.size_out; + } while (data_rcvd_size < feat_out_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 9939c771f642..608e3ed845a7 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -532,6 +532,7 @@ enum cxl_opcode { CXL_MBOX_OP_CLEAR_LOG = 0x0403, CXL_MBOX_OP_GET_SUP_LOG_SUBLIST = 0x0405, 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, @@ -758,6 +759,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; @@ -894,6 +917,10 @@ int cxl_get_supported_features(struct cxl_memdev_state *mds, struct cxl_mbox_get_supp_feats_out *feats_out); int cxl_get_supported_feature_entry(struct cxl_memdev_state *mds, const uuid_t *feat_uuid, struct cxl_mbox_supp_feat_entry *feat_entry_out); +size_t cxl_get_feature(struct cxl_memdev_state *mds, + const uuid_t feat_uuid, + enum cxl_get_feat_selection selection, + void *feat_out, size_t feat_out_size); 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 Aug 16 16:42:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766599 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id A1DF5C3DA4A for ; Fri, 16 Aug 2024 16:43:48 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 7244A6B0136; Fri, 16 Aug 2024 12:43:43 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 6ABC48D007E; Fri, 16 Aug 2024 12:43:43 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 4DA1C6B013C; Fri, 16 Aug 2024 12:43:43 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 281626B0136 for ; Fri, 16 Aug 2024 12:43:43 -0400 (EDT) Received: from smtpin05.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id B0375A0115 for ; Fri, 16 Aug 2024 16:43:42 +0000 (UTC) X-FDA: 82458679884.05.34A2BD1 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf05.hostedemail.com (Postfix) with ESMTP id A53F0100013 for ; Fri, 16 Aug 2024 16:43:40 +0000 (UTC) Authentication-Results: imf05.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf05.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826560; a=rsa-sha256; cv=none; b=g/FARmP9oniPvtMsT0Zws+6uSoOvGS+DhG6bHzEmcgCPJ9uPihCxzhSJKppYw0OKPPtFCU OFe+cleR27RoGnP+ytb458Jf/gBVA1WKrD6ZcIHwNQFfYxrSiRahXELUlczXpOrkttkGiT EsEgdMYCd13taQEX91YJGjtHt5erK9M= ARC-Authentication-Results: i=1; imf05.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf05.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826560; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qF4jvI2IHufnbtyN/a7COQ8WfrsKyUWPT+X4Iru+o4M=; b=qKhE/KKqsitHYgIapA0QpleaIFceabPygOuK+QZgo7D1xFjHcukLnlwD3FdM3EQ7a/P1pU f/gh3FTIK11Ih43NlR2BJlsNh2m5dErlarsWh1SQj1rKiPXwtQ64lDxSzW6QQv8+hb7pPS vgIlLokqGV8dB6vMB+EiXY+Zlp6Z87g= Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnlz1ghTz6K5t4; Sat, 17 Aug 2024 00:40:15 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 3AA0E140680; Sat, 17 Aug 2024 00:43:38 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:36 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 06/14] cxl/mbox: Add SET_FEATURE mailbox command Date: Fri, 16 Aug 2024 17:42:29 +0100 Message-ID: <20240816164238.1902-7-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: A53F0100013 X-Stat-Signature: b7fu13s1gzyde7ukgbku671gz8itofhu X-Rspam-User: X-HE-Tag: 1723826620-397201 X-HE-Meta: U2FsdGVkX1+vHKPzeUMhPMxdORHE1MRAzaWGRVtM4z8zNCMrNPXKm/fZqpgQALC9qx4Alh9hwlaqb1koav0w7U/EDnL42hjDgLOhvvkJU5oI0/a2BRMCayDqleVorCH2TI7ESDctQ6lqFHAvkZadsHdUTfvWydMxDTyPm/5/VND9fXeKOkD8aB3ll7uniQBOMvta1KUpN+uwvm6CUSpPoSkpKCxlWlU0IV75G267FINLj6TzvJikwdi7OHF+OSnGTWTwe5Qh991LKdqQuRwOx/WTjbDA5gP/9LhbDpmzP+LWY0WRbzy89haTYZissjFfdOdClfRcJ6kex35fZ5Kc4pSzkq6aX8OaMMs7bBZ2FiEm9IH/DkVgoWAgxEtWvXQa8a/WX+JROwu2pYVGrEXZBNomuAkBFDlLHCmHGpCq3emsKRKOkIkI4rNAWgxWCY0VB+lw+pE6/8XV5HvXOljVxdiuNqdghcdZ8AtKINndUDDyhT9sfQirrYdtszjR2HnECJXwF8dfRki9imAwj/GE4UixjWm65ouQiiE+8WkfHJAUbpyY6X1VSQ6LwrXZ+cm3o+QCDjFjmT8lcWM4LW8w2FSOjeBVHNsG3j/wO7uT8onsKvXpE+uzE3gb1bYz5T1L4pNhf/vJhNd1ARG0Ozt/OwYHxks8LFo23WRrhoJnG4Xob18SXFwHLiq+jElU5CBVgVLJE9c7R4O/IU/xjXJKxufnpwTjx5OzKf5fr5yyr0DTYml3XJbcMPDmXcO3eNwY4CaU9oLBSm4/pKrEpuuAbk8uLP9anO5/RFlpNBnO/JvkqbClCm0iIIpBhmtLjluaJniHYXOsOrNcu5Cj5c4/zNr0zblq6DgAgdSQVT+HBn1nuj1+QZzCFmzFXkQvpqT0BsoMGZYatUmyseOye+GJtnz8WD2HjfUvWO0vG3KMFGEhbfmYd5C0oGSSLhtMro75hbyMcvv++XnD3Ya92Bl icaBmD3P GqRsopRQn17lniP3ZYZNw7yaWxA+R7+rw+/UM55VoHruH/+mGIZ90Ul+wbWT2tSgxgqBBlJaTINuPz0ZNvcd2g5ltuQx4GzmX5oCwXI0Jj6XFc5eUSDJFDezWm5a96PrgFDLtb5fJuvDu3+sjEPKUxaRu8hhg4awBI24heSnjrPW6A/LvVD4O8UjbOBhFcozV0xTarNXulZU2QPC54777LGv5iYPIQOgA5nPs1dE9xu6eQXuN5qb5YMsSo6NOOBQJLa0cdXXPkPFL/jhYg+I2N79C77HRRPM+l0u8JwzdV+ktz3g= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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. CXL spec 3.1 section 8.2.9.6.3 describes Set Feature command. Signed-off-by: Shiju Jose --- drivers/cxl/core/mbox.c | 72 +++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 34 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index c283684e8e73..f79269add159 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1432,6 +1432,78 @@ 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; + feat_flag |= CXL_SET_FEAT_FLAG_DATA_SAVED_ACROSS_RESET; + 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); +} +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 608e3ed845a7..a092a14361ec 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -533,6 +533,7 @@ enum cxl_opcode { CXL_MBOX_OP_GET_SUP_LOG_SUBLIST = 0x0405, 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, @@ -781,6 +782,35 @@ 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; @@ -921,6 +951,10 @@ size_t cxl_get_feature(struct cxl_memdev_state *mds, const uuid_t feat_uuid, enum cxl_get_feat_selection selection, void *feat_out, size_t feat_out_size); +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 Aug 16 16:42:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766600 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id D877AC531DC for ; Fri, 16 Aug 2024 16:43:51 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id EC4CA6B013C; Fri, 16 Aug 2024 12:43:45 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id E4CDB6B013F; Fri, 16 Aug 2024 12:43:45 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id C05946B013D; Fri, 16 Aug 2024 12:43:45 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 9485A6B0138 for ; Fri, 16 Aug 2024 12:43:45 -0400 (EDT) Received: from smtpin30.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id E5A0D140170 for ; Fri, 16 Aug 2024 16:43:44 +0000 (UTC) X-FDA: 82458679968.30.514C84D Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf07.hostedemail.com (Postfix) with ESMTP id E189A40023 for ; Fri, 16 Aug 2024 16:43:42 +0000 (UTC) Authentication-Results: imf07.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf07.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826568; a=rsa-sha256; cv=none; b=5AVYOb6PKTuieY3M6vZZGmYn1H+scQ8k60opKjJ4hW/QS+mfWcUb/T1NbRDZYB8ALnJudY FQDUMziXOOjA+V48XWgvZZfzHu5fvZeMhe/WBQaQg/ftZkqUAQwDbitRI1j8JZDIKakjBL PgdNNHQ4gWiJuZd68pzi3YnxxtHgFrY= ARC-Authentication-Results: i=1; imf07.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf07.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826568; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=T0m6hxbwSjWIodYELjD1X+fyO+jaZNps5d8zHneAuqA=; b=yxiMDpmvQbJGuPda2fUOdVKANCqUlWNL18G99n9flgMGxuLPh2QJ6JWGrxJDf+rTNtc1Rh 9cascxaCoCDrcbdZrCzSFxr5TVU2yqVv7rSE5m5h5P6atKUXGoz77tb7rxsc9VwKd4/lEF c1Qpy4ibmd+i/Vq7RYishOL6G9dfwiI= Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4WlnmV1kFQz67Cwc; Sat, 17 Aug 2024 00:40:42 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 80058140680; Sat, 17 Aug 2024 00:43:40 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:38 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 07/14] cxl/memfeature: Add CXL memory device patrol scrub control feature Date: Fri, 16 Aug 2024 17:42:30 +0100 Message-ID: <20240816164238.1902-8-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Queue-Id: E189A40023 X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: y3at1iwa74mg3q3x1njoawitzc1mzu36 X-HE-Tag: 1723826622-27736 X-HE-Meta: U2FsdGVkX19k0s/maodCRFT3hYRjr4Dwd98iYYZJmH8u2SsJjTdaHvtUXI2kF803yPFalvoFmFS4qOW0W+ba7AZWWOHO/H8uugDZYWaExYfgfthEJS5hCDW2F0kJz5p/DqncanjAgL+QLwTxupoiqJZZXMdKANX2NaRhXsYhs/S5KN+CxE+tP5h7+ahkMFq8aEBD/zdrkzEJdE09tBo6Wh7eyB/GrRgAzVb4IBPselmKs5YU5PkWfZYsUmbOfT39xiidLjcu1AJ9OM34L8ryZv59Bo10NhEgFdP3U0efv19rodR9OVPGngv16VmJg2tp0Cjgw4ZHQNkGnbKcNYyo7n/TImFhjb0ag7nIYgRjXnLoMsuXvtjDHgbmibOIcwdR1UIGMp7aMjMT0A8InfbRO7udYVIsNQ4YvjHcNKJwdR5KzPRylxJ4X7pKDjsmYQRKxK2JfQ9N1jfB+6Ro8zLL8z6P7BnrRhYZmzwBJAJBvf0CfQS0Q0qs/Enqj3BKhavJEkt/xIQEMnTselLKTjIEGzvpGTy5NX50SZ3IKpiYtyircLXqY60Y8JWspNojY9WKg3x62vCGbQ2WrisN6rfDdIHmhS8bKeFlzL0z4MPaLPJKTOojrz6a6DN1YCZXQ+kT0CQF8cAsFEupdrQE5VuaewaFb20Tx35cyXeAUF9n0Gf21wtUJ/aNUZYx/JetxVjmHqwsN6PwVFOFKfcwkg/iavGtzfMyNPpP/ubSv8BTH7y3QaHZmZPW/4PaHBP1d336fVgbAI4Nk4nYqHE0R0EF4tweE9p3z3jPRGtUHcqHoqQqaUSI4LWD8mbh2qbJwDCeKiyWA0zVYulrBrgHxHtbzrsz7KRLLCydLa/x5bPSw8ZHvM7hkSvV+O8sFfLu/+2NRJ7wAKLUT1mv5Hkptnag4tUzqM6OI3n796mWzK7msYRvaesUZ5hH4R5aboW7E6ppRCpEDH2948oOZqUgFd5 rx5y8/bp FAo4b9TwVst/IE/4RsoBmWvTyEnL027DatrZDM+XrAX7gXuKd0xCEMhEj5H0BUatMHvkk4F43UpLO7uqYhOYfwOcN/xSGtMhcaHHe+hzyceRg9UjHjrRhD5K+YOx0N5RF+U/Huvja1JoquLb5j5Rft8kINc5EefijenJ57RJaroT6oFp9hgNyXr/NwsUIg3FyP2PHfEbJhjfzKh5quRGxKnuDOA== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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. Add support for CXL memory device based patrol scrub control. Register with EDAC RAS control feature driver, which gets the scrub attr descriptors from the EDAC scrub and expose sysfs scrub control attributes to the userspace. For example CXL device based scrub control for the CXL mem0 device is exposed in /sys/bus/edac/devices/cxl_mem0/scrub/ Also add support for region based CXL memory patrol scrub control. CXL memory region may be interleaved across one or more CXL memory devices. For example region based scrub control for CXL region1 is exposed in /sys/bus/edac/devices/cxl_region1/scrub/ Open Questions: Q1: CXL 3.1 spec defined patrol scrub control feature at CXL memory devices with supporting set scrub cycle and enable/disable scrub. but not based on HPA range. Thus presently scrub control for a region is implemented based on all associated CXL memory devices. What is the exact use case for the CXL region based scrub control? How the HPA range, which Dan asked for region based scrubbing is used? Does spec change is required for patrol scrub control feature with support for setting the HPA range? Q2: Both CXL device based and CXL region based scrub control would be enabled at the same time in a system? Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- Documentation/edac/edac-scrub.rst | 74 ++++++ drivers/cxl/Kconfig | 18 ++ drivers/cxl/core/Makefile | 1 + drivers/cxl/core/memfeature.c | 374 ++++++++++++++++++++++++++++++ drivers/cxl/core/region.c | 6 + drivers/cxl/cxlmem.h | 7 + drivers/cxl/mem.c | 4 + 7 files changed, 484 insertions(+) create mode 100644 Documentation/edac/edac-scrub.rst create mode 100644 drivers/cxl/core/memfeature.c diff --git a/Documentation/edac/edac-scrub.rst b/Documentation/edac/edac-scrub.rst new file mode 100644 index 000000000000..7815d674f496 --- /dev/null +++ b/Documentation/edac/edac-scrub.rst @@ -0,0 +1,74 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================== +EDAC Scrub control +=================== + +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.12 +- Updated for: + +Introduction +------------ +The edac scrub driver provides interfaces for controlling the +memory scrubbers in the system. The scrub device drivers in the +system register with the edac scrub. The 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/bus/edac/devices//scrub/ + +sysfs +----- + +Sysfs files are documented in +`Documentation/ABI/testing/sysfs-edac-scrub-control`. + +Example +------- + +The usage takes the form shown in this example:: + +1. CXL memory device patrol scrubber +1.1 device based +root@localhost:~# cat /sys/bus/edac/devices/cxl_mem0/scrub/min_cycle_duration +3600 +root@localhost:~# cat /sys/bus/edac/devices/cxl_mem0/scrub/max_cycle_duration +918000 +root@localhost:~# cat /sys/bus/edac/devices/cxl_mem0/scrub/current_cycle_duration +43200 +root@localhost:~# echo 54000 > /sys/bus/edac/devices/cxl_mem0/scrub/current_cycle_duration +root@localhost:~# cat /sys/bus/edac/devices/cxl_mem0/scrub/current_cycle_duration +54000 +root@localhost:~# echo 1 > /sys/bus/edac/devices/cxl_mem0/scrub/enable_background +root@localhost:~# cat /sys/bus/edac/devices/cxl_mem0/scrub/enable_background +1 +root@localhost:~# echo 0 > /sys/bus/edac/devices/cxl_mem0/scrub/enable_background +root@localhost:~# cat /sys/bus/edac/devices/cxl_mem0/scrub/enable_background +0 + +1.2. region based +root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/min_cycle_duration +3600 +root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/max_cycle_duration +918000 +root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/current_cycle_duration +43200 +root@localhost:~# echo 54000 > /sys/bus/edac/devices/cxl_region0/scrub/current_cycle_duration +root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/current_cycle_duration +54000 +root@localhost:~# echo 1 > /sys/bus/edac/devices/cxl_region0/scrub/enable_background +root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/enable_background +1 +root@localhost:~# echo 0 > /sys/bus/edac/devices/cxl_region0/scrub/enable_background +root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/enable_background +0 diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig index 99b5c25be079..47b0996d86d3 100644 --- a/drivers/cxl/Kconfig +++ b/drivers/cxl/Kconfig @@ -145,4 +145,22 @@ config CXL_REGION_INVALIDATION_TEST If unsure, or if this kernel is meant for production environments, say N. +config CXL_RAS_FEAT + bool "CXL: Memory RAS features" + depends on CXL_PCI + depends on CXL_MEM + depends on EDAC + help + The CXL memory RAS feature control is optional allows host to control + the RAS feature's configurations of CXL Type 3 devices. + + Registers with the EDAC device subsystem to expose control attributes + of CXL memory device's RAS features to the user. + Provides interface functions to support configuring the CXL memory + device's RAS features. + + Say 'y/n' to enable/disable CXL.mem device'ss RAS feature's control. + See section 8.2.9.9.11 of CXL 3.1 specification for the detailed + information of CXL memory device features. + endif diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index 9259bcc6773c..2a3c7197bc23 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_RAS_FEAT) += memfeature.o diff --git a/drivers/cxl/core/memfeature.c b/drivers/cxl/core/memfeature.c new file mode 100644 index 000000000000..71dd0bd27b8a --- /dev/null +++ b/drivers/cxl/core/memfeature.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * CXL memory RAS feature driver. + * + * Copyright (c) 2024 HiSilicon Limited. + * + * - Supports functions to configure RAS features of the + * CXL memory devices. + * - Registers with the EDAC device subsystem driver to expose + * the feature's sysfs attributes to the user for configuring + * CXL memory RAS feature. + */ + +#define pr_fmt(fmt) "CXL MEM FEAT: " fmt + +#include +#include +#include +#include +#include + +#define CXL_DEV_NUM_RAS_FEATURES 1 +#define CXL_DEV_HOUR_IN_SECS 3600 + +#define CXL_SCRUB_NAME_LEN 128 + +/* CXL memory patrol scrub control definitions */ +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 { + u16 get_feat_size; + u16 set_feat_size; + u8 get_version; + u8 set_version; + u16 set_effects; + struct cxl_memdev *cxlmd; + struct cxl_region *cxlr; +}; + +/** + * 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. + * @scrub_cycle_hrs: [IN] Requested patrol scrub cycle in hours. + * [OUT] Current patrol scrub cycle in hours. + * @min_scrub_cycle_hrs:[OUT] minimum patrol scrub cycle in hours supported. + */ +struct cxl_memdev_ps_params { + bool enable; + bool scrub_cycle_changeable; + u16 scrub_cycle_hrs; + u16 min_scrub_cycle_hrs; +}; + +enum cxl_scrub_param { + CXL_PS_PARAM_ENABLE, + CXL_PS_PARAM_SCRUB_CYCLE, +}; + +#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_hrs; + u8 scrub_flags; +} __packed; + +struct cxl_memdev_ps_wr_attrs { + u8 scrub_cycle_hrs; + u8 scrub_flags; +} __packed; + +static int cxl_mem_ps_get_attrs(struct cxl_memdev_state *mds, + struct cxl_memdev_ps_params *params) +{ + size_t rd_data_size = sizeof(struct cxl_memdev_ps_rd_attrs); + size_t data_size; + 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, + CXL_GET_FEAT_SEL_CURRENT_VALUE, + rd_attrs, rd_data_size); + 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->scrub_cycle_hrs = FIELD_GET(CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_MASK, + rd_attrs->scrub_cycle_hrs); + params->min_scrub_cycle_hrs = FIELD_GET(CXL_MEMDEV_PS_MIN_SCRUB_CYCLE_MASK, + rd_attrs->scrub_cycle_hrs); + + return 0; +} + +static int cxl_ps_get_attrs(struct device *dev, void *drv_data, + struct cxl_memdev_ps_params *params) +{ + struct cxl_patrol_scrub_context *cxl_ps_ctx = drv_data; + struct cxl_memdev *cxlmd; + struct cxl_dev_state *cxlds; + struct cxl_memdev_state *mds; + u16 min_scrub_cycle = 0; + int i, ret; + + if (cxl_ps_ctx->cxlr) { + struct cxl_region *cxlr = cxl_ps_ctx->cxlr; + struct cxl_region_params *p = &cxlr->params; + + for (i = p->interleave_ways - 1; i >= 0; i--) { + struct cxl_endpoint_decoder *cxled = p->targets[i]; + + cxlmd = cxled_to_memdev(cxled); + cxlds = cxlmd->cxlds; + mds = to_cxl_memdev_state(cxlds); + ret = cxl_mem_ps_get_attrs(mds, params); + if (ret) + return ret; + + if (params->min_scrub_cycle_hrs > min_scrub_cycle) + min_scrub_cycle = params->min_scrub_cycle_hrs; + } + params->min_scrub_cycle_hrs = min_scrub_cycle; + return 0; + } + cxlmd = cxl_ps_ctx->cxlmd; + cxlds = cxlmd->cxlds; + mds = to_cxl_memdev_state(cxlds); + + return cxl_mem_ps_get_attrs(mds, params); +} + +static int cxl_mem_ps_set_attrs(struct device *dev, void *drv_data, + struct cxl_memdev_state *mds, + struct cxl_memdev_ps_params *params, + enum cxl_scrub_param param_type) +{ + struct cxl_patrol_scrub_context *cxl_ps_ctx = drv_data; + struct cxl_memdev_ps_wr_attrs wr_attrs; + struct cxl_memdev_ps_params rd_params; + int ret; + + ret = cxl_mem_ps_get_attrs(mds, &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_hrs = FIELD_PREP(CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_MASK, + rd_params.scrub_cycle_hrs); + break; + case CXL_PS_PARAM_SCRUB_CYCLE: + if (params->scrub_cycle_hrs < rd_params.min_scrub_cycle_hrs) { + dev_err(dev, "Invalid CXL patrol scrub cycle(%d) to set\n", + params->scrub_cycle_hrs); + dev_err(dev, "Minimum supported CXL patrol scrub cycle in hour %d\n", + params->min_scrub_cycle_hrs); + return -EINVAL; + } + wr_attrs.scrub_cycle_hrs = FIELD_PREP(CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_MASK, + params->scrub_cycle_hrs); + 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_ps_ctx->set_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; + } + + return 0; +} + +static int cxl_ps_set_attrs(struct device *dev, void *drv_data, + struct cxl_memdev_ps_params *params, + enum cxl_scrub_param param_type) +{ + struct cxl_patrol_scrub_context *cxl_ps_ctx = drv_data; + struct cxl_memdev *cxlmd; + struct cxl_dev_state *cxlds; + struct cxl_memdev_state *mds; + int ret, i; + + if (cxl_ps_ctx->cxlr) { + struct cxl_region *cxlr = cxl_ps_ctx->cxlr; + struct cxl_region_params *p = &cxlr->params; + + for (i = p->interleave_ways - 1; i >= 0; i--) { + struct cxl_endpoint_decoder *cxled = p->targets[i]; + + cxlmd = cxled_to_memdev(cxled); + cxlds = cxlmd->cxlds; + mds = to_cxl_memdev_state(cxlds); + ret = cxl_mem_ps_set_attrs(dev, drv_data, mds, + params, param_type); + if (ret) + return ret; + } + } else { + cxlmd = cxl_ps_ctx->cxlmd; + cxlds = cxlmd->cxlds; + mds = to_cxl_memdev_state(cxlds); + + return cxl_mem_ps_set_attrs(dev, drv_data, mds, params, param_type); + } + + return 0; +} + +static int cxl_patrol_scrub_get_enabled_bg(struct device *dev, void *drv_data, bool *enabled) +{ + struct cxl_memdev_ps_params params; + int ret; + + ret = cxl_ps_get_attrs(dev, drv_data, ¶ms); + if (ret) + return ret; + + *enabled = params.enable; + + return 0; +} + +static int cxl_patrol_scrub_set_enabled_bg(struct device *dev, void *drv_data, bool enable) +{ + struct cxl_memdev_ps_params params = { + .enable = enable, + }; + + return cxl_ps_set_attrs(dev, drv_data, ¶ms, CXL_PS_PARAM_ENABLE); +} + +static int cxl_patrol_scrub_read_min_scrub_cycle(struct device *dev, void *drv_data, + u32 *min) +{ + struct cxl_memdev_ps_params params; + int ret; + + ret = cxl_ps_get_attrs(dev, drv_data, ¶ms); + if (ret) + return ret; + *min = params.min_scrub_cycle_hrs * CXL_DEV_HOUR_IN_SECS; + + return 0; +} + +static int cxl_patrol_scrub_read_max_scrub_cycle(struct device *dev, void *drv_data, + u32 *max) +{ + *max = U8_MAX * CXL_DEV_HOUR_IN_SECS; /* Max set by register size */ + + return 0; +} + +static int cxl_patrol_scrub_read_scrub_cycle(struct device *dev, void *drv_data, + u32 *scrub_cycle_secs) +{ + struct cxl_memdev_ps_params params; + int ret; + + ret = cxl_ps_get_attrs(dev, drv_data, ¶ms); + if (ret) + return ret; + + *scrub_cycle_secs = params.scrub_cycle_hrs * CXL_DEV_HOUR_IN_SECS; + + return 0; +} + +static int cxl_patrol_scrub_write_scrub_cycle(struct device *dev, void *drv_data, + u32 scrub_cycle_secs) +{ + struct cxl_memdev_ps_params params = { + .scrub_cycle_hrs = scrub_cycle_secs / CXL_DEV_HOUR_IN_SECS, + }; + + return cxl_ps_set_attrs(dev, drv_data, ¶ms, CXL_PS_PARAM_SCRUB_CYCLE); +} + +static const struct edac_scrub_ops cxl_ps_scrub_ops = { + .get_enabled_bg = cxl_patrol_scrub_get_enabled_bg, + .set_enabled_bg = cxl_patrol_scrub_set_enabled_bg, + .min_cycle_read = cxl_patrol_scrub_read_min_scrub_cycle, + .max_cycle_read = cxl_patrol_scrub_read_max_scrub_cycle, + .cycle_duration_read = cxl_patrol_scrub_read_scrub_cycle, + .cycle_duration_write = cxl_patrol_scrub_write_scrub_cycle, +}; + +int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) +{ + struct edac_dev_feature ras_features[CXL_DEV_NUM_RAS_FEATURES]; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct cxl_patrol_scrub_context *cxl_ps_ctx; + struct cxl_mbox_supp_feat_entry feat_entry; + char cxl_dev_name[CXL_SCRUB_NAME_LEN]; + int rc, i, num_ras_features = 0; + + if (cxlr) { + struct cxl_region_params *p = &cxlr->params; + + for (i = p->interleave_ways - 1; i >= 0; i--) { + struct cxl_endpoint_decoder *cxled = p->targets[i]; + + cxlmd = cxled_to_memdev(cxled); + memset(&feat_entry, 0, sizeof(feat_entry)); + rc = cxl_get_supported_feature_entry(mds, &cxl_patrol_scrub_uuid, + &feat_entry); + if (rc < 0) + return rc; + if (!(feat_entry.attr_flags & CXL_FEAT_ENTRY_FLAG_CHANGABLE)) + return -EOPNOTSUPP; + } + } else { + rc = cxl_get_supported_feature_entry(mds, &cxl_patrol_scrub_uuid, + &feat_entry); + if (rc < 0) + return rc; + + if (!(feat_entry.attr_flags & CXL_FEAT_ENTRY_FLAG_CHANGABLE)) + return -EOPNOTSUPP; + } + + 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, + .get_version = feat_entry.get_version, + .set_version = feat_entry.set_version, + .set_effects = feat_entry.set_effects, + }; + if (cxlr) { + snprintf(cxl_dev_name, sizeof(cxl_dev_name), + "cxl_region%d", cxlr->id); + cxl_ps_ctx->cxlr = cxlr; + } else { + snprintf(cxl_dev_name, sizeof(cxl_dev_name), + "%s_%s", "cxl", dev_name(&cxlmd->dev)); + cxl_ps_ctx->cxlmd = cxlmd; + } + + ras_features[num_ras_features].feat = RAS_FEAT_SCRUB; + ras_features[num_ras_features].scrub_ops = &cxl_ps_scrub_ops; + ras_features[num_ras_features].scrub_ctx = cxl_ps_ctx; + num_ras_features++; + + return edac_dev_register(&cxlmd->dev, cxl_dev_name, NULL, + num_ras_features, ras_features); +} +EXPORT_SYMBOL_NS_GPL(cxl_mem_ras_features_init, CXL); diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 538ebd5a64fd..4a94a87b9b58 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -3397,6 +3397,12 @@ static int cxl_region_probe(struct device *dev) p->res->start, p->res->end, cxlr, is_system_ram) > 0) return 0; + + rc = cxl_mem_ras_features_init(NULL, cxlr); + if (rc) + dev_warn(&cxlr->dev, "CXL ras features init for region_id=%d failed\n", + cxlr->id); + return devm_cxl_add_dax_region(cxlr); default: dev_dbg(&cxlr->dev, "unsupported region mode: %d\n", diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index a092a14361ec..c6f6e38bdbcb 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -962,6 +962,13 @@ 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); +#ifdef CONFIG_CXL_RAS_FEAT +int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr); +#else +static inline int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) +{ 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 2f1b49bfe162..01691e9feaa1 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -117,6 +117,10 @@ static int cxl_mem_probe(struct device *dev) if (!cxlds->media_ready) return -EBUSY; + rc = cxl_mem_ras_features_init(cxlmd, NULL); + if (rc) + dev_warn(&cxlmd->dev, "CXL ras features init failed\n"); + /* * 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 Aug 16 16:42:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766601 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id E736EC3DA4A for ; Fri, 16 Aug 2024 16:43:54 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 885BD6B00A9; Fri, 16 Aug 2024 12:43:47 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 6FA196B00D4; Fri, 16 Aug 2024 12:43:47 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 4B10B6B00D6; Fri, 16 Aug 2024 12:43:47 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 1E0AB6B00A9 for ; Fri, 16 Aug 2024 12:43:47 -0400 (EDT) Received: from smtpin03.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id AF6851C0591 for ; Fri, 16 Aug 2024 16:43:46 +0000 (UTC) X-FDA: 82458680052.03.5B41451 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf20.hostedemail.com (Postfix) with ESMTP id B479F1C000B for ; Fri, 16 Aug 2024 16:43:44 +0000 (UTC) Authentication-Results: imf20.hostedemail.com; dkim=none; spf=pass (imf20.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826550; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=x3qhDFC/FmACC29R3wGuJSjmoC4V4cD128cT0j19WcY=; b=0gTD9635Mme1eyp1K8goas1q5iIZlnebH5eOegpAybza8uJoqyjC5aZ2kId23OgEyfl2fi 9PNcW7Oz2rNGzn7AVH9GMQ1jWe4eHYtr842+17SwkscIA1zpbhlWOlOKdeBGiOd/SUoOXU boEE+jQ1bk0ijXS+PdQJ+HPcOxNzpv0= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826550; a=rsa-sha256; cv=none; b=l7+t0fiEpn3xhU8cSkBLJ+eysdYWjtnQzuEZH7+ENbXrP4NWINRlJHT5Ec5+G30VNP8iMR 0NAKKxbrtap1GsJ4YHiaLlTTK5NHRyrghqYiaTQIVG2jacI6updqKrRBullqTkRNB0CQuj 1qYMUS5EhQ2a8HlvvLfiQl7li8AlF28= ARC-Authentication-Results: i=1; imf20.hostedemail.com; dkim=none; spf=pass (imf20.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnm35jkWz6K5q4; Sat, 17 Aug 2024 00:40:19 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id BE23C1400C9; Sat, 17 Aug 2024 00:43:42 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:41 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 08/14] cxl/memfeature: Add CXL memory device ECS control feature Date: Fri, 16 Aug 2024 17:42:31 +0100 Message-ID: <20240816164238.1902-9-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspam-User: X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: B479F1C000B X-Stat-Signature: 4j1w7f9xwuew81ddp8ptiax7iztsbzao X-HE-Tag: 1723826624-886018 X-HE-Meta: U2FsdGVkX18lD8CG5lcCwcicLzrWim36hb3GjNg/hlCZ8KnBd0XNmPcmxvzBxgUgvqfKdyDeP11o8GgCdCuu//2KKI0FkIRn09zAsG5rBhs/25Dbxl0wAMZfqbYyfZU8NpvoiGvlaCgVk4Gqui//85Et6CijCv9vzzcYzjCSQJDkuY07vQZX/tkM12h/k5wc2e1sp5JEgS8Dj4DYMuoCyQq95wVsessTbnGVwQbIYCwehBTCeLv9K9XA3RJdfsVwzRled7MGG5xgQAY7S/7MJ30SjQNBJ5/pB1Tn1GqVnlJHnt+I0KRxowgZHp1+WW4TxN84tP2oLRbjWOx6J5hS86JGfAynLsp9KAIPCvF+lSGKppb6YKpT95PxRfTdomMYqf2iTvCaVHPjKw4uGYVDhz5sbT8WvkDag/JOb6w8a6aSAGMWau+y3eFRr6CyWYVJnvJwv8HbSluFs0Z44TjLNlAU1BUlAKtT8iITdsBQl8lmndV35blhIiRcumfdgJEHbMow9q/5kSXwO3JKyw14ZELq1IRST4qcTL8Y52dtAQv1euWLgUVfyRtQ+o91veulE4/dBkAGgjoJ8v3MsUrbNvECwb+uU2FuvYYFFMrYcU6TMv/lGUj0+ih8jdPV1pEZZ4TPpscrgYUCWYjYUwYP436NM8ToxkOnTYzyQode4sQnChU1/dS9IrThcTJmxoN2K1ZiuaRDfPviSs645cHPrU44jvZYDa/JVO3ttoAdhoo7tclpgOn7dC042T9UixF/QAKcuVyWKaalE66F7ZVRlhDBr7UKnE/rpX3AATkAf0HXcqks6wlin5bfKjfQ9qSIJBi7fAUtF7xJAi7GTAhGGNMtnpeppGOc46phz784O8ZCO2uRW+EvpQlvD83byABVPQV2dMsvo1Oo6Mnb9Rmywcytwf/YR6iZrMLq0mybH5nu15u8U6KKRvX7KmROV4sYX9TEM6jUKey9ePOdoiU 1AK5RXQa EjgLJO7jUkiNRV/K1MWpxgxixfzEylBYnmEPtIu/cxxjavZ3+NcXKiM120AFhftq3OVQZRZSWJtlVO/IkPV5R92ZmYIAhiMT9qW5CPsFrKn6QVpojmBf2Ciq4JKsS6aHphe/TdGrihXfbxFpjFSuY6wqo1cjntAAyKfE6j+ySEiZCiY51HNmMr1xKKBjf3KpOM7PdOl5qK3dQPgMYcwijHETlOg== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Shiju Jose CXL spec 3.1 section 8.2.9.9.11.2 describes the DDR5 ECS (Error Check Scrub) control feature. The Error Check Scrub (ECS) is a feature defined in JEDEC DDR5 SDRAM Specification (JESD79-5) and allows the DRAM to internally read, correct single-bit errors, and write back corrected data bits to the DRAM array while providing transparency to error counts. The ECS control allows the requester to change the log entry type, the ECS threshold count provided that the request is within the definition specified in DDR5 mode registers, change mode between codeword mode and row count mode, and reset the ECS counter. Register with EDAC RAS control feature driver, which gets the ECS attr descriptors from the EDAC ECS and expose sysfs ECS control attributes to the userspace. For example ECS control for the memory media FRU 0 in CXL mem0 device is in /sys/bus/edac/devices/cxl_mem0/ecs_fru0/ Signed-off-by: Shiju Jose --- drivers/cxl/core/memfeature.c | 441 +++++++++++++++++++++++++++++++++- 1 file changed, 440 insertions(+), 1 deletion(-) diff --git a/drivers/cxl/core/memfeature.c b/drivers/cxl/core/memfeature.c index 71dd0bd27b8a..ee7fd2f58d01 100644 --- a/drivers/cxl/core/memfeature.c +++ b/drivers/cxl/core/memfeature.c @@ -19,7 +19,7 @@ #include #include -#define CXL_DEV_NUM_RAS_FEATURES 1 +#define CXL_DEV_NUM_RAS_FEATURES 2 #define CXL_DEV_HOUR_IN_SECS 3600 #define CXL_SCRUB_NAME_LEN 128 @@ -307,6 +307,407 @@ static const struct edac_scrub_ops cxl_ps_scrub_ops = { .cycle_duration_write = cxl_patrol_scrub_write_scrub_cycle, }; +/* CXL DDR5 ECS control definitions */ +static const uuid_t cxl_ecs_uuid = + UUID_INIT(0xe5b13f22, 0x2328, 0x4a14, 0xb8, 0xba, 0xb9, 0x69, 0x1e, \ + 0x89, 0x33, 0x86); + +struct cxl_ecs_context { + u16 num_media_frus; + u16 get_feat_size; + u16 set_feat_size; + u8 get_version; + u8 set_version; + u16 set_effects; + struct cxl_memdev *cxlmd; +}; + +enum { + CXL_ECS_PARAM_LOG_ENTRY_TYPE, + CXL_ECS_PARAM_THRESHOLD, + CXL_ECS_PARAM_MODE, + CXL_ECS_PARAM_RESET_COUNTER, +}; + +#define CXL_ECS_LOG_ENTRY_TYPE_MASK GENMASK(1, 0) +#define CXL_ECS_REALTIME_REPORT_CAP_MASK BIT(0) +#define CXL_ECS_THRESHOLD_COUNT_MASK GENMASK(2, 0) +#define CXL_ECS_MODE_MASK BIT(3) +#define CXL_ECS_RESET_COUNTER_MASK BIT(4) + +static const u16 ecs_supp_threshold[] = { 0, 0, 0, 256, 1024, 4096 }; + +enum { + ECS_LOG_ENTRY_TYPE_DRAM = 0x0, + ECS_LOG_ENTRY_TYPE_MEM_MEDIA_FRU = 0x1, +}; + +enum { + ECS_THRESHOLD_256 = 3, + ECS_THRESHOLD_1024 = 4, + ECS_THRESHOLD_4096 = 5, +}; + +enum cxl_ecs_mode { + ECS_MODE_COUNTS_ROWS = 0, + ECS_MODE_COUNTS_CODEWORDS = 1, +}; + +/** + * struct cxl_ecs_params - CXL memory DDR5 ECS parameter data structure. + * @log_entry_type: ECS log entry type, per DRAM or per memory media FRU. + * @threshold: ECS threshold count per GB of memory cells. + * @mode: codeword/row count mode + * 0 : ECS counts rows with errors + * 1 : ECS counts codeword with errors + * @reset_counter: [IN] reset ECC counter to default value. + */ +struct cxl_ecs_params { + u8 log_entry_type; + u16 threshold; + enum cxl_ecs_mode mode; + bool reset_counter; +}; + +struct cxl_ecs_rd_attrs { + u8 ecs_log_cap; + u8 ecs_cap; + __le16 ecs_config; + u8 ecs_flags; +} __packed; + +struct cxl_ecs_wr_attrs { + u8 ecs_log_cap; + __le16 ecs_config; +} __packed; + +/* CXL DDR5 ECS control functions */ +static int cxl_mem_ecs_get_attrs(struct device *dev, void *drv_data, int fru_id, + struct cxl_ecs_params *params) +{ + struct cxl_ecs_context *cxl_ecs_ctx = drv_data; + struct cxl_memdev *cxlmd = cxl_ecs_ctx->cxlmd; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + size_t rd_data_size; + u8 threshold_index; + size_t data_size; + + rd_data_size = cxl_ecs_ctx->get_feat_size; + + struct cxl_ecs_rd_attrs *rd_attrs __free(kfree) = + kmalloc(rd_data_size, GFP_KERNEL); + if (!rd_attrs) + return -ENOMEM; + + params->log_entry_type = 0; + params->threshold = 0; + params->mode = 0; + data_size = cxl_get_feature(mds, cxl_ecs_uuid, + CXL_GET_FEAT_SEL_CURRENT_VALUE, + rd_attrs, rd_data_size); + if (!data_size) + return -EIO; + + params->log_entry_type = FIELD_GET(CXL_ECS_LOG_ENTRY_TYPE_MASK, + rd_attrs[fru_id].ecs_log_cap); + threshold_index = FIELD_GET(CXL_ECS_THRESHOLD_COUNT_MASK, + rd_attrs[fru_id].ecs_config); + params->threshold = ecs_supp_threshold[threshold_index]; + params->mode = FIELD_GET(CXL_ECS_MODE_MASK, + rd_attrs[fru_id].ecs_config); + return 0; +} + +static int cxl_mem_ecs_set_attrs(struct device *dev, void *drv_data, int fru_id, + struct cxl_ecs_params *params, u8 param_type) +{ + struct cxl_ecs_context *cxl_ecs_ctx = drv_data; + struct cxl_memdev *cxlmd = cxl_ecs_ctx->cxlmd; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + size_t rd_data_size, wr_data_size; + u16 num_media_frus, count; + size_t data_size; + int ret; + + num_media_frus = cxl_ecs_ctx->num_media_frus; + rd_data_size = cxl_ecs_ctx->get_feat_size; + wr_data_size = cxl_ecs_ctx->set_feat_size; + struct cxl_ecs_rd_attrs *rd_attrs __free(kfree) = + kmalloc(rd_data_size, GFP_KERNEL); + if (!rd_attrs) + return -ENOMEM; + + data_size = cxl_get_feature(mds, cxl_ecs_uuid, + CXL_GET_FEAT_SEL_CURRENT_VALUE, + rd_attrs, rd_data_size); + if (!data_size) + return -EIO; + struct cxl_ecs_wr_attrs *wr_attrs __free(kfree) = + kmalloc(wr_data_size, GFP_KERNEL); + if (!wr_attrs) + return -ENOMEM; + + /* Fill writable attributes from the current attributes + * read for all the media FRUs. + */ + for (count = 0; count < num_media_frus; count++) { + wr_attrs[count].ecs_log_cap = rd_attrs[count].ecs_log_cap; + wr_attrs[count].ecs_config = rd_attrs[count].ecs_config; + } + + /* Fill attribute to be set for the media FRU */ + switch (param_type) { + case CXL_ECS_PARAM_LOG_ENTRY_TYPE: + if (params->log_entry_type != ECS_LOG_ENTRY_TYPE_DRAM && + params->log_entry_type != ECS_LOG_ENTRY_TYPE_MEM_MEDIA_FRU) { + dev_err(dev, + "Invalid CXL ECS scrub log entry type(%d) to set\n", + params->log_entry_type); + dev_err(dev, + "Log Entry Type 0: per DRAM 1: per Memory Media FRU\n"); + return -EINVAL; + } + wr_attrs[fru_id].ecs_log_cap = FIELD_PREP(CXL_ECS_LOG_ENTRY_TYPE_MASK, + params->log_entry_type); + break; + case CXL_ECS_PARAM_THRESHOLD: + wr_attrs[fru_id].ecs_config &= ~CXL_ECS_THRESHOLD_COUNT_MASK; + switch (params->threshold) { + case 256: + wr_attrs[fru_id].ecs_config |= FIELD_PREP(CXL_ECS_THRESHOLD_COUNT_MASK, + ECS_THRESHOLD_256); + break; + case 1024: + wr_attrs[fru_id].ecs_config |= FIELD_PREP(CXL_ECS_THRESHOLD_COUNT_MASK, + ECS_THRESHOLD_1024); + break; + case 4096: + wr_attrs[fru_id].ecs_config |= FIELD_PREP(CXL_ECS_THRESHOLD_COUNT_MASK, + ECS_THRESHOLD_4096); + break; + default: + dev_err(dev, + "Invalid CXL ECS scrub threshold count(%d) to set\n", + params->threshold); + dev_err(dev, + "Supported scrub threshold count: 256,1024,4096\n"); + return -EINVAL; + } + break; + case CXL_ECS_PARAM_MODE: + if (params->mode != ECS_MODE_COUNTS_ROWS && + params->mode != ECS_MODE_COUNTS_CODEWORDS) { + dev_err(dev, + "Invalid CXL ECS scrub mode(%d) to set\n", + params->mode); + dev_err(dev, + "Mode 0: ECS counts rows with errors" + " 1: ECS counts codewords with errors\n"); + return -EINVAL; + } + wr_attrs[fru_id].ecs_config &= ~CXL_ECS_MODE_MASK; + wr_attrs[fru_id].ecs_config |= FIELD_PREP(CXL_ECS_MODE_MASK, + params->mode); + break; + case CXL_ECS_PARAM_RESET_COUNTER: + wr_attrs[fru_id].ecs_config &= ~CXL_ECS_RESET_COUNTER_MASK; + wr_attrs[fru_id].ecs_config |= FIELD_PREP(CXL_ECS_RESET_COUNTER_MASK, + params->reset_counter); + break; + default: + dev_err(dev, "Invalid CXL ECS parameter to set\n"); + return -EINVAL; + } + + ret = cxl_set_feature(mds, cxl_ecs_uuid, cxl_ecs_ctx->set_version, + wr_attrs, wr_data_size, + CXL_SET_FEAT_FLAG_DATA_SAVED_ACROSS_RESET); + if (ret) { + dev_err(dev, "CXL ECS set feature failed ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int cxl_ecs_get_log_entry_type(struct device *dev, void *drv_data, + int fru_id, u32 *val) +{ + struct cxl_ecs_params params; + int ret; + + ret = cxl_mem_ecs_get_attrs(dev, drv_data, fru_id, ¶ms); + if (ret) + return ret; + + *val = params.log_entry_type; + + return 0; +} + +static int cxl_ecs_set_log_entry_type(struct device *dev, void *drv_data, + int fru_id, u32 val) +{ + struct cxl_ecs_params params = { + .log_entry_type = val, + }; + + return cxl_mem_ecs_set_attrs(dev, drv_data, fru_id, + ¶ms, CXL_ECS_PARAM_LOG_ENTRY_TYPE); +} + +static int cxl_ecs_get_log_entry_type_per_dram(struct device *dev, void *drv_data, + int fru_id, u32 *val) +{ + struct cxl_ecs_params params; + int ret; + + ret = cxl_mem_ecs_get_attrs(dev, drv_data, fru_id, ¶ms); + if (ret) + return ret; + + if (params.log_entry_type == ECS_LOG_ENTRY_TYPE_DRAM) + *val = 1; + else + *val = 0; + + return 0; +} + +static int cxl_ecs_get_log_entry_type_per_memory_media(struct device *dev, + void *drv_data, + int fru_id, u32 *val) +{ + struct cxl_ecs_params params; + int ret; + + ret = cxl_mem_ecs_get_attrs(dev, drv_data, fru_id, ¶ms); + if (ret) + return ret; + + if (params.log_entry_type == ECS_LOG_ENTRY_TYPE_MEM_MEDIA_FRU) + *val = 1; + else + *val = 0; + + return 0; +} + +static int cxl_ecs_get_mode(struct device *dev, void *drv_data, + int fru_id, u32 *val) +{ + struct cxl_ecs_params params; + int ret; + + ret = cxl_mem_ecs_get_attrs(dev, drv_data, fru_id, ¶ms); + if (ret) + return ret; + + *val = params.mode; + + return 0; +} + +static int cxl_ecs_set_mode(struct device *dev, void *drv_data, + int fru_id, u32 val) +{ + struct cxl_ecs_params params = { + .mode = val, + }; + + return cxl_mem_ecs_set_attrs(dev, drv_data, fru_id, + ¶ms, CXL_ECS_PARAM_MODE); +} + +static int cxl_ecs_get_mode_counts_rows(struct device *dev, void *drv_data, + int fru_id, u32 *val) +{ + struct cxl_ecs_params params; + int ret; + + ret = cxl_mem_ecs_get_attrs(dev, drv_data, fru_id, ¶ms); + if (ret) + return ret; + + if (params.mode == ECS_MODE_COUNTS_ROWS) + *val = 1; + else + *val = 0; + + return 0; +} + +static int cxl_ecs_get_mode_counts_codewords(struct device *dev, void *drv_data, + int fru_id, u32 *val) +{ + struct cxl_ecs_params params; + int ret; + + ret = cxl_mem_ecs_get_attrs(dev, drv_data, fru_id, ¶ms); + if (ret) + return ret; + + if (params.mode == ECS_MODE_COUNTS_CODEWORDS) + *val = 1; + else + *val = 0; + + return 0; +} + +static int cxl_ecs_reset(struct device *dev, void *drv_data, int fru_id, u32 val) +{ + struct cxl_ecs_params params = { + .reset_counter = val, + }; + + return cxl_mem_ecs_set_attrs(dev, drv_data, fru_id, + ¶ms, CXL_ECS_PARAM_RESET_COUNTER); +} + +static int cxl_ecs_get_threshold(struct device *dev, void *drv_data, + int fru_id, u32 *val) +{ + struct cxl_ecs_params params; + int ret; + + ret = cxl_mem_ecs_get_attrs(dev, drv_data, fru_id, ¶ms); + if (ret) + return ret; + + *val = params.threshold; + + return 0; +} + +static int cxl_ecs_set_threshold(struct device *dev, void *drv_data, + int fru_id, u32 val) +{ + struct cxl_ecs_params params = { + .threshold = val, + }; + + return cxl_mem_ecs_set_attrs(dev, drv_data, fru_id, + ¶ms, CXL_ECS_PARAM_THRESHOLD); +} + +static const struct edac_ecs_ops cxl_ecs_ops = { + .get_log_entry_type = cxl_ecs_get_log_entry_type, + .set_log_entry_type = cxl_ecs_set_log_entry_type, + .get_log_entry_type_per_dram = cxl_ecs_get_log_entry_type_per_dram, + .get_log_entry_type_per_memory_media = + cxl_ecs_get_log_entry_type_per_memory_media, + .get_mode = cxl_ecs_get_mode, + .set_mode = cxl_ecs_set_mode, + .get_mode_counts_codewords = cxl_ecs_get_mode_counts_codewords, + .get_mode_counts_rows = cxl_ecs_get_mode_counts_rows, + .reset = cxl_ecs_reset, + .get_threshold = cxl_ecs_get_threshold, + .set_threshold = cxl_ecs_set_threshold, +}; + int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) { struct edac_dev_feature ras_features[CXL_DEV_NUM_RAS_FEATURES]; @@ -315,7 +716,9 @@ int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) struct cxl_patrol_scrub_context *cxl_ps_ctx; struct cxl_mbox_supp_feat_entry feat_entry; char cxl_dev_name[CXL_SCRUB_NAME_LEN]; + struct cxl_ecs_context *cxl_ecs_ctx; int rc, i, num_ras_features = 0; + int num_media_frus; if (cxlr) { struct cxl_region_params *p = &cxlr->params; @@ -368,6 +771,42 @@ int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) ras_features[num_ras_features].scrub_ctx = cxl_ps_ctx; num_ras_features++; + if (!cxlr) { + rc = cxl_get_supported_feature_entry(mds, &cxl_ecs_uuid, + &feat_entry); + if (rc < 0) + goto feat_register; + + if (!(feat_entry.attr_flags & CXL_FEAT_ENTRY_FLAG_CHANGABLE)) + goto feat_register; + num_media_frus = feat_entry.get_size / + sizeof(struct cxl_ecs_rd_attrs); + if (!num_media_frus) + goto feat_register; + + cxl_ecs_ctx = devm_kzalloc(&cxlmd->dev, sizeof(*cxl_ecs_ctx), + GFP_KERNEL); + if (!cxl_ecs_ctx) + goto feat_register; + *cxl_ecs_ctx = (struct cxl_ecs_context) { + .get_feat_size = feat_entry.get_size, + .set_feat_size = feat_entry.set_size, + .get_version = feat_entry.get_version, + .set_version = feat_entry.set_version, + .set_effects = feat_entry.set_effects, + .num_media_frus = num_media_frus, + .cxlmd = cxlmd, + }; + + ras_features[num_ras_features].feat = RAS_FEAT_ECS; + ras_features[num_ras_features].ecs_ops = &cxl_ecs_ops; + ras_features[num_ras_features].ecs_ctx = cxl_ecs_ctx; + ras_features[num_ras_features].ecs_info.num_media_frus = + num_media_frus; + num_ras_features++; + } + +feat_register: return edac_dev_register(&cxlmd->dev, cxl_dev_name, NULL, num_ras_features, ras_features); } From patchwork Fri Aug 16 16:42:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766602 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 72D39C3DA4A for ; Fri, 16 Aug 2024 16:43:58 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 661D78D0096; Fri, 16 Aug 2024 12:43:49 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5C37C8D007E; Fri, 16 Aug 2024 12:43:49 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3A5408D0096; Fri, 16 Aug 2024 12:43:49 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 0E54F8D007E for ; Fri, 16 Aug 2024 12:43:49 -0400 (EDT) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id B7CDE120156 for ; Fri, 16 Aug 2024 16:43:48 +0000 (UTC) X-FDA: 82458680136.18.8EFE0B6 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf29.hostedemail.com (Postfix) with ESMTP id CA4B812000B for ; Fri, 16 Aug 2024 16:43:46 +0000 (UTC) Authentication-Results: imf29.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf29.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826572; a=rsa-sha256; cv=none; b=XyEqT32y06CIlMX2dk1HOAQpMXXU+JGMZqyrajoth42CUfoJOCiXOszd3HwEsVqorOYv7k G0cdjUQz0+ngwUoiDmZdaeM7DWIcHpqvBmwjTgVrEoh77c+U0B3ZUoxMyXSsbTEM5DYI34 28BHvBZSwvohMA3RKUaFUE/8SvE41ZM= ARC-Authentication-Results: i=1; imf29.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf29.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826572; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=F93fuiYNl6Q27hD862498JBBQxXlQqyCf924P+Qz0zk=; b=3itDtOQNB2ke3quUvPzApExymgYKls6CV3iEkm8OU+fTsV4zPX1a8+maTmwwMylsH8AVDt Dm5Rj2Yr7WCpfIHwVVkR2e6RnAblqbfv40jj7/2pCYWNKWriQW3qS+4wzyYWiInVjuSSpQ +lfMJaudBVxemDl46g+YKBwx3tOURBI= Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnm56jkfz6K5q1; Sat, 17 Aug 2024 00:40:21 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id E603D1400C9; Sat, 17 Aug 2024 00:43:44 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:43 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 09/14] platform: Add __free() based cleanup function for platform_device_put Date: Fri, 16 Aug 2024 17:42:32 +0100 Message-ID: <20240816164238.1902-10-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Queue-Id: CA4B812000B X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: rb9668h7d3shfajwp4i7h74kj7ctbui6 X-HE-Tag: 1723826626-993697 X-HE-Meta: U2FsdGVkX1/sVVJUTZCQFSHWi7xFoN3whi2cW4Ug/aEiYqU5w0DPCeYVyS7MIKNVW8bATyRUke9RnZyOiZWIzPFR7kaTqBtSDfGHWvKwgCgONUq+K6M5DdE2ipVGOh3bZPoltGCxSwFmNrvQnG9vujlibtRYYfjQHc6iImPnMdv3mWetwfP6C8t22+S+1M6EwMtHn9vcVdyf8/l3t8Z0Wbe+zvvM6GAReYfIm9xmlmiyqRIHC3dj98cFnfFl56ZhHdzIX5vWRc8PdGd4DmAG34xXSLdB5gw1jvVK5Q4h+ad+43ePj7anUzKWJ3IWZd6nmUKXzIkOkLJMlufjsJ2ustDsdhA2/nopPRobU6T62ZbC4J/arJ48ea9vskeW150dZGS/Ekxq6uH5kE8FehxWLhOu9TcfkC+SeIVB7Px0qfNmoRjjDij2t7Tp3OzBkku6Ts3/QEJyMHh16mOw4rxrcV6r46ANGRtimafQngX0XxeHyP6pCOT/XWU54XRN0a+KUNaeTDvgy8MA71YjqFWJijx3VHQBuQVboX5Rv+1Ek3y+XJ9KtJbGsDuv6MGEWJ0QorFeLWUd8WarP6MbxLoXoVyOijEk6vyNXGsK3zd2khoLf+iWRm6ljFpJ/kTdQ93vqlV2ySfOeiD2yrin91fNuVLZz6i3ivwOM6ozCo/TcabWeK+82NnzYKyfjdEb+RZKNQ4rp41kCihJXQ+sleGyg2w5TBp2uPa0kyauU/JCes5nop+BznTcTdjeC39K+ykgQzjDPkHlqXHpf+BxUGF0yisv3AMKpcLlUNO0P/IDsHqG9n7yGFKF061Njt9+6VQdo9+KDZ01j4o06f/EL7dGhhSUEKr00SOyn5g4QuCB22tFkdORNZ9pOVKBHEwA/N2W+Q4/TVTA8k8m6brKvjktdzESOd6loxr9X1jRK7BwzUHJ9/8vDLsYQWwR2uAN7hWyAWaaH6n0pVtWVZ2X0VG gXUneQQP lm7002wS4mI/moOrqX6Bv9hHcsO35kG0UTldeXrEZBAHkUhtoqcrO972/p068ZN6knMu2OTatf0idMMDHmjnudFsYlp/SLcwaeDNuyEhFwdI8y4qWhy0RZoTlB2oj9NcdXdwgoE8A/6agCmK8O/dLcPd7+B/z5As7VYntKJXpFmrIv+EZObogXSLEDc99A+lyWhPd0NRTBg33K6VtSelNoSqy6V15F3w6eO/Vw07dbv0swnb5EwWmbFlI9ajOrSDy0C2WZjM82X6amS7pLBBT3Qx3oujJFyrtEBbTpg2EWhbt24g= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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 Aug 16 16:42:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766603 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id DBBADC531DC for ; Fri, 16 Aug 2024 16:44:00 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id C7D148D0097; Fri, 16 Aug 2024 12:43:51 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id BB6EA8D007E; Fri, 16 Aug 2024 12:43:51 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 9C4158D0097; Fri, 16 Aug 2024 12:43:51 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 69BB18D007E for ; Fri, 16 Aug 2024 12:43:51 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 22AA614012E for ; Fri, 16 Aug 2024 16:43:51 +0000 (UTC) X-FDA: 82458680262.21.A4027A6 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf23.hostedemail.com (Postfix) with ESMTP id 1E6E7140018 for ; Fri, 16 Aug 2024 16:43:48 +0000 (UTC) Authentication-Results: imf23.hostedemail.com; dkim=none; spf=pass (imf23.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826554; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FIHUgkBkho0E/vplg0W5bOaGq0UgBzsEkDeuh4chSOk=; b=MJZqwKXSLbNV3JvDtHL2RRJkiV2DV18ukz81goVqOEPhqNgKnCrDP0g2UKlVDp6QK1EB1t KBSqE6/pDl67nj0jDVJszb8LwLIMC2oy7iMSHvNe3JDn7T/w6ZgPxy8XU3EdNkVV3rm+Jt cW2fEvuRXrWXauNNkVEMYrOmaKVHf10= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826554; a=rsa-sha256; cv=none; b=XFp4nF9Th+r2rKvz4Xgtpd+jfSORcsWftMaW6HELZzAckBELIJuW6N4gs72ZfPUz0sAJsJ AimPy24QJ9WYoqCBNmQc6PdzErzRu15SIEYncjTLKOtSeATnniuMIaPMyfM6IP3XIzgm+g izuELf7JkOIIX5bxquiVsCOWHGYJX8M= ARC-Authentication-Results: i=1; imf23.hostedemail.com; dkim=none; spf=pass (imf23.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.216]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnm818dCz6K5st; Sat, 17 Aug 2024 00:40:24 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 283651400DB; Sat, 17 Aug 2024 00:43:47 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:45 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 10/14] ACPI:RAS2: Add ACPI RAS2 driver Date: Fri, 16 Aug 2024 17:42:33 +0100 Message-ID: <20240816164238.1902-11-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Stat-Signature: fy9dqbstskxhwdm8f3tdzup9nhh6kfiq X-Rspamd-Queue-Id: 1E6E7140018 X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1723826628-276528 X-HE-Meta: U2FsdGVkX19fd1WlL8WbgA83TOPKkGqEVKmshxP3iUvkJX8JLcOFGh934Hwy+d1L/zIhTs55K7rmS3MPskMiJo0ZqBGF+duNkZ4m0iQocHGOntamnrKpy1+fzIcba9oH5JCBaBVa708zZOnx5MAYyAk4Y4Uxg/lWb0HNxjL7yGyRmANzVDMngTHz1noA8xZIJNTNFeUdux7uhDcFmZL5AYGeZ269P+nSGibGx/HoAUvx/YyZYqX1qSgmDGMjZf0xVAGUs5UQljOMszI6liXhZy07Vb481MIlHvwQxQHLctIiw1tbdKPVFULvVocERM/1Xbpqha+eTwmkKaex7wQwZ282mbqoPC7a5FbdSaQaipZuIPzunc3X2Fh/opX+r1Svnn/Bhc5lmyM6wiY90zbt/AOJ2CpHdy1fMaJkFLWZK1kKq6TEjrFR3im0QlXe7JcCNmXWXnFA5sIV6mm17Na5Z+Koo7aZfSa65kaayzn1ovBjTd1or68W+71BZ6Fgp6kKO1NBLVd2Wej1tkmOQ9gwfBs1tRKriwBC3y4rknNzqHPC3foHaPI/rddZoRnLctXdRWkCltIsqHG5RZawzz0Hhw9egL+ink/dtZdrHtCZcYjEUm4tPXK+u3xrYIzhXYOUdgrRbHuNjzzDy0Vqb3nmP/Lz4DCb3qU1L7NqTEfg+DUDiWvsK/+iwKBwI4a6BeL7nMKnBH/B7uEMkCyviOyHgScGlG20rnjxinJtGtELDcOFw89Kkuc53fr15uKEOFYW2Y5VUdZyxNb53i6xU1hLFguxCy6oHBIBaH4V+AaUGJ6BPgcXnGXoijKGffY1Njwiwyi6YdMhLyC15HaPQt3NyUg3LdwoH5bm5SURrbigoRmmlud6CEMN7uEcz/6Xb9TXbg8KNSTY4Zd/FklsdOWytpD7YJYEaQwTewO0IKCL+wJ7/Bf8DSnz9Js7ch7YgoW6eZdqGDJKyA+fEwQsNt1 p9ulR/tM S0zgqi7NCQnzbrKIeelorhul1uhABsgwkdHeL/R45DKCjxeajDpKItjHL5uegZ4QiO0mwREctsmneZ50S/6GJ4lDKdFUZrdhQKxl+hO1QA1SAGnofx1F6PGI6pwF/fGjPA4GHO6bEyfpO2jxSFCkgAc+eXNzo2LbEZabbgk81krO8tw1NF7UqbovbXQ6/l3Z7AN1teJg4MF7/5UkKNSdBpP/myK8bN7oNG5f2NcrjM1XJ3R9Pqv6eKoO5ilSOyRLizfk+nRRro13JjNM= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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 | 391 +++++++++++++++++++++++++++++++++++++++ include/acpi/ras2_acpi.h | 59 ++++++ 4 files changed, 461 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 e3a7c2aedd5f..482080f1f0c5 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 39ea5cfa8326..4d62633ee4c2 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -99,6 +99,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..07fe8ac02d25 --- /dev/null +++ b/drivers/acpi/ras2.c @@ -0,0 +1,391 @@ +// 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_report_cap_error(u32 cap_status) +{ + switch (cap_status) { + case ACPI_RAS2_NOT_VALID: + case ACPI_RAS2_NOT_SUPPORTED: + return -EPERM; + case ACPI_RAS2_BUSY: + return -EBUSY; + case ACPI_RAS2_FAILED: + case ACPI_RAS2_ABORTED: + case ACPI_RAS2_INVALID_DATA: + return -EINVAL; + default: /* 0 or other, Success */ + return 0; + } +} + +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); + u32 cap_status; + u16 status; + u32 ret; + + 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) { + cap_status = readw_relaxed(&generic_comm_base->set_capabilities_status); + ret = ras2_report_cap_error(cap_status); + + status &= ~RAS2_PCC_CMD_ERROR; + writew_relaxed(status, &generic_comm_base->status); + return ret; + } + 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 < 0) + 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 ret >= 0 ? 0 : ret; +} +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 int __init ras2_acpi_init(void) +{ + struct acpi_table_header *pAcpiTable = NULL; + 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; + acpi_status status; + u8 count = 0, i; + int ret; + + status = acpi_get_table("RAS2", 0, &pAcpiTable); + if (ACPI_FAILURE(status) || !pAcpiTable) { + pr_err("ACPI RAS2 driver failed to initialize, get table failed\n"); + return -EINVAL; + } + + ras2_size = pAcpiTable->length; + if (ras2_size < sizeof(struct acpi_table_ras2)) { + pr_err("ACPI RAS2 table present but broken (too short #1)\n"); + ret = -EINVAL; + goto free_ras2_table; + } + + pRas2Table = (struct acpi_table_ras2 *)pAcpiTable; + if (pRas2Table->num_pcc_descs <= 0) { + pr_err("ACPI RAS2 table does not contain PCC descriptors\n"); + ret = -EINVAL; + goto free_ras2_table; + } + + struct platform_device **pdev_list __free(kfree) = + kcalloc(pRas2Table->num_pcc_descs, sizeof(*pdev_list), + GFP_KERNEL); + if (!pdev_list) { + ret = -ENOMEM; + goto free_ras2_table; + } + + 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) { + ret = -ENODEV; + 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; + } + + acpi_put_table(pAcpiTable); + return 0; + +free_ras2_pdev: + for (i = count; i >= 0; i++) + platform_device_put(pdev_list[i]); + +free_ras2_table: + acpi_put_table(pAcpiTable); + + return ret; +} +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..afc1060c714c --- /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 scrub_cycle_hrs, min_scrub_cycle, max_scrub_cycle; + /* 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 Aug 16 16:42:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766604 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1CC21C531DF for ; Fri, 16 Aug 2024 16:44:04 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id CCA368D0098; Fri, 16 Aug 2024 12:43:53 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id C511A8D007E; Fri, 16 Aug 2024 12:43:53 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id AA44B8D0098; Fri, 16 Aug 2024 12:43:53 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 7D1FF8D007E for ; Fri, 16 Aug 2024 12:43:53 -0400 (EDT) Received: from smtpin07.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 4035E140123 for ; Fri, 16 Aug 2024 16:43:53 +0000 (UTC) X-FDA: 82458680346.07.B42167A Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf28.hostedemail.com (Postfix) with ESMTP id 4DEE3C000E for ; Fri, 16 Aug 2024 16:43:51 +0000 (UTC) Authentication-Results: imf28.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf28.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826548; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CpuU+CiVv2kQZHRaKnMQov89bjeIHIzujKEVnG59obg=; b=aDT/F3jpPNUo3P9H/G8HEi8qAoT8D45zwH2E03cyCUGnQ1YK47TXBcKk4n7gONA0L6mLDU a3lsZF3KUh0Rjep+RbxfPX/O/4V/7lKdsM07dwKmfOMzPhTy4Gc4Bj3Sn82sbMuBZ/xU+X 5ut7vJyWbT1Z2MscOKDNt2wNxK6L6E4= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826548; a=rsa-sha256; cv=none; b=lAHlKLImm0PUNd5u2jJSW+MpJB9Hagsed2dkP2M9WlY9+82mpcIRV1zTqI1nj0+w3taWfx uO28hB1MJTKtN2NovoTj61634nG4OQNaxEeH+j7YBXoSm7q3lc3kvRXQq2ETZbXlg3PxPO xSmGd5zWcB6ehpkPqKn1ZmwoX6aTzCk= ARC-Authentication-Results: i=1; imf28.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf28.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnmx0Lw3z6K61T; Sat, 17 Aug 2024 00:41:05 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 5B9ED1400C9; Sat, 17 Aug 2024 00:43:49 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:47 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 11/14] ras: mem: Add memory ACPI RAS2 driver Date: Fri, 16 Aug 2024 17:42:34 +0100 Message-ID: <20240816164238.1902-12-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: 4DEE3C000E X-Stat-Signature: hf4dczpjq1cpd6bxyn8zzewfaf8n1gnh X-Rspam-User: X-HE-Tag: 1723826631-880339 X-HE-Meta: U2FsdGVkX1/H/lO9K7gBCv1DpEWDyijRe6T3tg61kQYQlPrWcQXyXny381Ot/+7J6bnsJPWh/JCtbt5Q5upxGCBOHE2/l/8gLEwYzyv/T1767RmX8JmHU4EUBseDpQ7zgk0KC2nLuNhZbLt2Pk/4SigIUgs/mVU7H8v0uJJ8YkmJpkrWjNNftAinezfvIuyHBPUv5DYH7YHzcWWpwHLI+BlR3Pj173MFrx5/Z/8o5tQQNiqpDdfG+2lNmo2nntGys4NIGsOUqAmVEd+vlfYOjBEwsZ1gCTTdIyEX8NJ5K4dLqwWn1Z7JYe3nS3SdNEDFDxV0C642MHYEdNNlfb1xsBjgqDnNE51ZwRspOYLMEJ7HrGZvRRH3miZBcXRHfmEs1C9qrI0MlF3d94Zm1nsKsFkby8YLqKn5ssNKtF+UEtNLyXU7rM/7hTkOJl8tNX+i4/hvfDLUmcj3aLX9bGcO4PawRE3/HvvGZmkEa9VT6bb2wil4CgbmP/lf5KAbhGp5kl/bTc43t6bw3e9HeXeIkdUR3NqgdQF8iR5hxbHEzd7Z2JSDEXx9i+pFBYsVIUUqVou+yC8v/BAB1eT7rOfOaefvLahNDZtN5hTm4FRqiNVUaqcglfXeJncnaYz291ruf4MFKU8MIbAq/PsmMEY9SR0xkEqcxl69TmYVBZoEcKPp3Vsuq90vI6LhH8fzdjB2IXeoHgu3LBfddHTeYWmq3bhHVL7ZngMcVFdz4mm2RYya7MnJ573+anFUubG2Jm4x0cQkWcPv8WQ6Go55I3JmAo803iJ+dwhTbARha6C6qvI6F097fhPe2b8NiWNDxZepG+SmJvKZFEa2qrjWyiJMxJzMPqsAUqLh51aEHUjrMFLtxImIaxBKiK3udUW3workVClmkev2RNH8i7Uy4WS8x7E5URpvqdgeDePUD5Nwfw3Q8Z6lSuHNFrWh/NkzC8+strrAp5RhlkkxEa8U37E mkQDBPki 5ZSSX6uUucEG7mfdBONR8KHsf1pVnZ/UCC5SIKmfCLs+wi6/+QuO0N58khaTV6IVPUDiUjq982rZIXXIwjTAokz4Rlu6XJ9U8jS2dsBUh4cp3DDNOVu/ixNmrCGDqWGvYz094kK/UrylWSXtyXgG4B+b353KKHV2xNLla8s4AzZvrr7ZLy1vo3T5669fcVAzb0z7vnphzXITWwgwthHIKjJREYA== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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 to the userspace via the edac scrub. Get the scrub attr descriptors from the EDAC scrub and register with EDAC RAS feature driver to expose sysfs scrub control attributes to the userspace. For example scrub control for the RAS2 memory device is exposed in /sys/bus/edac/devices/acpi_ras2_mem0/scrub/ Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- Documentation/edac/edac-scrub.rst | 41 +++ drivers/ras/Kconfig | 10 + drivers/ras/Makefile | 1 + drivers/ras/acpi_ras2.c | 411 ++++++++++++++++++++++++++++++ 4 files changed, 463 insertions(+) create mode 100644 drivers/ras/acpi_ras2.c diff --git a/Documentation/edac/edac-scrub.rst b/Documentation/edac/edac-scrub.rst index 7815d674f496..38456bbff530 100644 --- a/Documentation/edac/edac-scrub.rst +++ b/Documentation/edac/edac-scrub.rst @@ -72,3 +72,44 @@ root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/enable_background root@localhost:~# echo 0 > /sys/bus/edac/devices/cxl_region0/scrub/enable_background root@localhost:~# cat /sys/bus/edac/devices/cxl_region0/scrub/enable_background 0 + +2. RAS2 +2.1 On demand scrubbing for a specific memory region. +root@localhost:~# echo 0x120000 > /sys/bus/edac/devices/acpi_ras2_mem0/scrub/addr_range_base +root@localhost:~# echo 0x150000 > /sys/bus/edac/devices/acpi_ras2_mem0/scrub/addr_range_size +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/min_cycle_duration +3600 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/max_cycle_duration +86400 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration +36000 +root@localhost:~# echo 54000 > /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration +root@localhost:~# echo 1 > /sys/bus/edac/devices/acpi_ras2_mem0/scrub/enable_on_demand +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/enable_on_demand +1 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration +54000 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/addr_range_base +0x120000 +root@localhost:~# cat //sys/bus/edac/devices/acpi_ras2_mem0/scrub/addr_range_size +0x150000 +root@localhost:~# echo 0 > /sys/bus/edac/devices/acpi_ras2_mem0/scrub/enable_on_demand +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/enable_on_demand +0 + +2.2 Background scrubbing the entire memory +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/min_cycle_duration +3600 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/max_cycle_duration +86400 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration +36000 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/enable_background +0 +root@localhost:~# echo 10800 > /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration +root@localhost:~# echo 1 > /sys/bus/edac/devices/acpi_ras2_mem0/enable_background +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/enable_background +1 +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration +10800 +root@localhost:~# echo 0 > /sys/bus/edac/devices/acpi_ras2_mem0/enable_background diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig index fc4f4bb94a4c..a2635017d80d 100644 --- a/drivers/ras/Kconfig +++ b/drivers/ras/Kconfig @@ -46,4 +46,14 @@ config RAS_FMPM Memory will be retired during boot time and run time depending on platform-specific policies. +config MEM_ACPI_RAS2 + tristate "Memory ACPI RAS2 driver" + depends on ACPI_RAS2 + depends on EDAC + 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 to the user via the edac scrub. + endif diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile index 11f95d59d397..a0e6e903d6b0 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_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..f319ad097642 --- /dev/null +++ b/drivers/ras/acpi_ras2.c @@ -0,0 +1,411 @@ +// 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 +#include + +#define RAS2_DEV_NUM_RAS_FEATURES 1 + +#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_SCHRS_IN_MASK GENMASK(15, 8) +#define RAS2_PATROL_SCRUB_EN_BACKGROUND BIT(0) +#define RAS2_PATROL_SCRUB_SCHRS_OUT_MASK GENMASK(7, 0) +#define RAS2_PATROL_SCRUB_MIN_SCHRS_OUT_MASK GENMASK(15, 8) +#define RAS2_PATROL_SCRUB_MAX_SCHRS_OUT_MASK GENMASK(23, 16) +#define RAS2_PATROL_SCRUB_FLAG_SCRUBBER_RUNNING BIT(0) + +#define RAS2_SCRUB_NAME_LEN 128 +#define RAS2_HOUR_IN_SECS 3600 + +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->min_scrub_cycle = FIELD_GET(RAS2_PATROL_SCRUB_MIN_SCHRS_OUT_MASK, + ps_sm->params.scrub_params_out); + ras2_ctx->max_scrub_cycle = FIELD_GET(RAS2_PATROL_SCRUB_MAX_SCHRS_OUT_MASK, + ps_sm->params.scrub_params_out); + if (!ras2_ctx->bg) { + ras2_ctx->base = ps_sm->params.actual_address_range[0]; + ras2_ctx->size = ps_sm->params.actual_address_range[1]; + } + ras2_ctx->scrub_cycle_hrs = FIELD_GET(RAS2_PATROL_SCRUB_SCHRS_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; + + 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_read_min_scrub_cycle(struct device *dev, void *drv_data, + u32 *min) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + + *min = ras2_ctx->min_scrub_cycle * RAS2_HOUR_IN_SECS; + + return 0; +} + +static int ras2_hw_scrub_read_max_scrub_cycle(struct device *dev, void *drv_data, + u32 *max) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + + *max = ras2_ctx->max_scrub_cycle * RAS2_HOUR_IN_SECS; + + return 0; +} + +static int ras2_hw_scrub_cycle_read(struct device *dev, void *drv_data, + u32 *scrub_cycle_secs) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + + *scrub_cycle_secs = ras2_ctx->scrub_cycle_hrs * RAS2_HOUR_IN_SECS; + + return 0; +} + +static int ras2_hw_scrub_cycle_write(struct device *dev, void *drv_data, + u32 scrub_cycle_secs) +{ + u8 scrub_cycle_hrs = scrub_cycle_secs / RAS2_HOUR_IN_SECS; + struct ras2_scrub_ctx *ras2_ctx = drv_data; + 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 (scrub_cycle_hrs < ras2_ctx->min_scrub_cycle || + scrub_cycle_hrs > ras2_ctx->max_scrub_cycle) + return -EINVAL; + + ras2_ctx->scrub_cycle_hrs = scrub_cycle_hrs; + + return 0; +} + +static int ras2_hw_scrub_read_range(struct device *dev, void *drv_data, u64 *base, u64 *size) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + + /* + * When BG scrubbing is enabled the actual address range is not valid. + * Return -EBUSY now unless findout a method to retrieve actual full PA range. + */ + if (ras2_ctx->bg) + return -EBUSY; + + *base = ras2_ctx->base; + *size = ras2_ctx->size; + + return 0; +} + +static int ras2_hw_scrub_write_range(struct device *dev, void *drv_data, u64 base, u64 size) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + 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 (!base || !size) { + dev_warn(dev, "%s: Invalid address range, base=0x%llx size=0x%llx\n", + __func__, base, size); + return -EINVAL; + } + + ras2_ctx->base = base; + ras2_ctx->size = size; + + return 0; +} + +static int ras2_hw_scrub_set_enabled_bg(struct device *dev, void *drv_data, bool enable) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = (void *) + ras2_ctx->pcc_subspace->pcc_comm_addr; + bool running; + int ret; + + guard(mutex)(&ras2_ctx->lock); + ps_sm->common.set_capabilities[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + if (enable) { + if (ras2_ctx->bg || running) + return -EBUSY; + 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_SCHRS_IN_MASK; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PATROL_SCRUB_SCHRS_IN_MASK, + ras2_ctx->scrub_cycle_hrs); + ps_sm->params.patrol_scrub_command = RAS2_START_PATROL_SCRUBBER; + } else { + if (!ras2_ctx->bg) + return -EPERM; + if (!ras2_ctx->bg && running) + return -EBUSY; + 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, "Failed to %s background scrubbing\n", + enable ? "enable" : "disable"); + return ret; + } + if (enable) { + ras2_ctx->bg = true; + /* Update the cache to account for rounding of supplied parameters and similar */ + ret = ras2_update_patrol_scrub_params_cache(ras2_ctx); + } else { + ret = ras2_update_patrol_scrub_params_cache(ras2_ctx); + ras2_ctx->bg = false; + } + + return ret; +} + +static int ras2_hw_scrub_get_enabled_bg(struct device *dev, void *drv_data, bool *enabled) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + + *enabled = ras2_ctx->bg; + + return 0; +} + +static int ras2_hw_scrub_set_enabled_od(struct device *dev, void *drv_data, bool enable) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = (void *) + ras2_ctx->pcc_subspace->pcc_comm_addr; + bool running; + int ret; + + guard(mutex)(&ras2_ctx->lock); + ps_sm->common.set_capabilities[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + if (ras2_ctx->bg) + return -EBUSY; + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + if (enable) { + if (!ras2_ctx->base || !ras2_ctx->size) { + dev_warn(ras2_ctx->dev, + "%s: Invalid address range, base=0x%llx " + "size=0x%llx\n", __func__, + ras2_ctx->base, ras2_ctx->size); + return -ERANGE; + } + if (running) + return -EBUSY; + ps_sm->params.scrub_params_in &= ~RAS2_PATROL_SCRUB_SCHRS_IN_MASK; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PATROL_SCRUB_SCHRS_IN_MASK, + ras2_ctx->scrub_cycle_hrs); + ps_sm->params.requested_address_range[0] = ras2_ctx->base; + ps_sm->params.requested_address_range[1] = ras2_ctx->size; + ps_sm->params.scrub_params_in &= ~RAS2_PATROL_SCRUB_EN_BACKGROUND; + ps_sm->params.patrol_scrub_command = RAS2_START_PATROL_SCRUBBER; + } else { + if (!running) + return 0; + 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 %s demand scrubbing\n", + enable ? "enable" : "disable"); + return ret; + } + + return ras2_update_patrol_scrub_params_cache(ras2_ctx); +} + +static int ras2_hw_scrub_get_enabled_od(struct device *dev, void *drv_data, bool *enabled) +{ + struct ras2_scrub_ctx *ras2_ctx = drv_data; + + guard(mutex)(&ras2_ctx->lock); + if (ras2_ctx->bg) { + *enabled = false; + return 0; + } + + return ras2_get_patrol_scrub_running(ras2_ctx, enabled); +} + +static const struct edac_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, + .min_cycle_read = ras2_hw_scrub_read_min_scrub_cycle, + .max_cycle_read = ras2_hw_scrub_read_max_scrub_cycle, + .cycle_duration_read = ras2_hw_scrub_cycle_read, + .cycle_duration_write = ras2_hw_scrub_cycle_write, +}; + +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 edac_dev_feature ras_features[RAS2_DEV_NUM_RAS_FEATURES]; + char scrub_name[RAS2_SCRUB_NAME_LEN]; + struct ras2_scrub_ctx *ras2_ctx; + int num_ras_features = 0; + 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; + + snprintf(scrub_name, sizeof(scrub_name), "acpi_ras2_mem%d", + ras2_ctx->id); + + ras_features[num_ras_features].feat = RAS_FEAT_SCRUB; + ras_features[num_ras_features].scrub_ops = &ras2_scrub_ops; + ras_features[num_ras_features].scrub_ctx = ras2_ctx; + num_ras_features++; + + return edac_dev_register(&pdev->dev, scrub_name, NULL, + num_ras_features, ras_features); +} + +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"); From patchwork Fri Aug 16 16:42:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766605 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4AB7BC531DC for ; Fri, 16 Aug 2024 16:44:07 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 0E2F98D0099; Fri, 16 Aug 2024 12:43:57 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 01C0F8D007E; Fri, 16 Aug 2024 12:43:56 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id DB0868D0099; Fri, 16 Aug 2024 12:43:56 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id A56178D007E for ; Fri, 16 Aug 2024 12:43:56 -0400 (EDT) Received: from smtpin02.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 420D31A0007 for ; Fri, 16 Aug 2024 16:43:56 +0000 (UTC) X-FDA: 82458680472.02.7256495 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf02.hostedemail.com (Postfix) with ESMTP id 47DCF8001F for ; Fri, 16 Aug 2024 16:43:54 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf02.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826561; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/nJ5CkTG/RUq8b/HW1JiVpmk1yS8NHg1EggSeVYnJZA=; b=2RvAzi6TaZraz+EYthEuBm6kBy19P2p5mHb3upW5tJf4JF+yu+lspRvmkZlrs78Q4WBgOz OKXbvNRmZ9dBqo9tpiVaj4+Ou3721zZqUO/a3qzGG4U2Wen0GLp3U+SZ3QrbYFp+Wt/E+o gtnOQKQZ0tQZmXthtMcOaWP5h0iLlBc= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826561; a=rsa-sha256; cv=none; b=G78Tp4AFEbg9Hci2KZSBx+jhC+DDRXCefNqarawI4cr41iYd2lnImyqdzIJl13JIyx3Pyk Fp4kZBgXmKsHJRakTWtNYHjGqZrJy9gukvxURImiWTQo2mtxnMdVUtSClImFzTegTaTRGA VnI4b83bG0Xu1ltd5jvE09Mj45Hia2U= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf02.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnmj2wm4z6K9P3; Sat, 17 Aug 2024 00:40:53 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id A40081400C9; Sat, 17 Aug 2024 00:43:51 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:50 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 12/14] EDAC: Add EDAC PPR control driver Date: Fri, 16 Aug 2024 17:42:35 +0100 Message-ID: <20240816164238.1902-13-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Queue-Id: 47DCF8001F X-Stat-Signature: yx9q5tas8mirtjurrhtc8kernszrxnjq X-Rspamd-Server: rspam09 X-Rspam-User: X-HE-Tag: 1723826634-423822 X-HE-Meta: U2FsdGVkX19q6g4IYmSBv1H9JtqoGv0pv3ldw1Yf38yVYQb2ZSnpdy6/3kkFWN82cvIMloLEUlkEbEVNWrhk07BYYUENtk89YMwOaNO/aeE5UwfoNht3TlVXKcArbSjBGueDD2bHHrKHbguECXbxxUXIPR6WZX4PcGFDYZgHAxOgLf2Y4//X+roN568tIU19VqB27tQsBXEVWPwk5MWt5uCRM+scJMHLnrUzuqU18YEIXaBmybbDmTFL6RIgC9kMQFccFf3krsw6RXSZprlNMTIWksjgcrMLP3KxFYcr7Ibn1/2HfEa/kFpZep4t6Kj5vQNYGNRB0wkrPtlowU3waJQ5gksSuK5ql2RWvo+mEsRd25Jhrwfolr5f/J0tRoFlQIt/ePkk4V3jaTD4+7feUk9JE6mDsySV7iDfxqjTlsl/K8F/46jA9kZqVRJLcb3hxz0aQVo78Lqrl22xPxMA8IL0lv5iWfZKoF53wJegja01UNr4okFaXpTdDYUWseaXqmiA0c+YbZJLgm/faCNi3haQLd1VoNFnbGuQqolTYBih0bfhgXl9A1etk2j1t0dLwLfqZQ4jAnG0uaEYqFDUgGc0V7I3dxPF8OcMtqzR3+dOqI4fBm9tlRHVHtubcdE/rFT5fXnSpL/pK9z/yiAJOfqj3vTpzj6JxnKd24dUmtrv0DdkNwWsMt2hd6wNCl/d1qRHNcKXmLxHgxEUAEzfpYh5wr+YHdvzDEZ8/idhlJmD1Jh0IOIejxncxYA4byrjnCfyMi1KqLGuZU1UzBysCy7f/XeO16PjdO+E0BJat3CU3zji+hcyZAOEe6ANGBWSU6AYs4elWCArkpjDCG/lOwW1ZYD+SDra8GSp//QQtQRiOBeBob3PEfCvlhe0QG8Cb5Oow6y3QecFYKzb5jCifOQyig20gkCQLVmIwGZRPJNnGk/7iQn9QP7CKL7/dQqyhGOg/0qxlQ4Or5gZ+a5 8rhisIBa nyITpemttSagLFAMKN18swfiI5rzuhCVD+ES6kaYUbHma9XJifF0IWM7gpR/nzO904DbvBvgqeBsfREmrm4aLDMGucHrfdqIJf49m5KwyJN/gjDwcyD07cvuuLNnoru8MeYOgdaA3IaFW6JxsW5rl8oslZVrB5L92qLvm1QDu8m4vshXU3M37hmJ7mrqdyJzl3jUnSxz5BH5oQi/6IIoj7fIyCD/+whkaKWmLIxbmr/aKYvuaM5jfMpOOITYOI4QoWpRBOkCg0Sm9J/krnDhV5UaVN4cgOzIrZYPApipAXerW4no= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Shiju Jose Add generic EDAC PPR(Post Package Repair) control driver supports configuring the memory PPR feature in the system. Supports both sPPR(soft PPR) and hPPR(hard PPR). The device with PPR feature, get the PPR descriptor from the EDAC PPR and registers with the EDAC, which adds the sysfs PPR control attributes. The PPR control attributes are available to the userspace in /sys/bus/edac/devices//pprX/ Generic EDAC PPR driver and the common sysfs PPR interface promotes unambiguous access from the userspace irrespective of the underlying memory devices with PPR feature supported. The sysfs PPR attribute nodes would be present only if the client driver has implemented the corresponding attribute callback functions and pass in ops to the EDAC during registration. Note: There are other PPR drivers to come apart from the CXL PPR in this series. Signed-off-by: Shiju Jose --- Documentation/ABI/testing/sysfs-edac-ppr | 69 ++++++ drivers/edac/Makefile | 2 +- drivers/edac/edac_device.c | 6 + drivers/edac/edac_ppr.c | 255 +++++++++++++++++++++++ include/linux/edac.h | 29 +++ 5 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-edac-ppr create mode 100755 drivers/edac/edac_ppr.c diff --git a/Documentation/ABI/testing/sysfs-edac-ppr b/Documentation/ABI/testing/sysfs-edac-ppr new file mode 100644 index 000000000000..af6ccef9661b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-edac-ppr @@ -0,0 +1,69 @@ +What: /sys/bus/edac/devices//ppr* +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + The sysfs edac bus devices //ppr* subdirectory + belongs to the memory media PPR (Post Package Repair) control + feature, where directory corresponds to a device + registered with the EDAC PPR driver and thus registered with + the generic edac device driver. + /ppr* belongs to either sPPR (Soft PPR) or hPPR (Hard PPR) + feature for the memory device. + The sysfs PPR attr nodes would be only present if PPR is + supported. + +What: /sys/bus/edac/devices//ppr*/persist_mode_avail +Date: Oct 2024 +KernelVersion: 6.12For e.g. HBM, DDR. +Contact: linux-edac@vger.kernel.org +Description: + (RO) persist PPR modes supported in the device. + For e.g. Hard PPR(hPPR) for a permanent row repair, + Soft PPR(sPPR) for a temporary row repair. + +What: /sys/bus/edac/devices//ppr*/persist_mode +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RW) Current persist PPR mode. + +What: /sys/bus/edac/devices//ppr*/dpa_support +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) True if supports DPA for PPR maintenance operation. + +What: /sys/bus/edac/devices//ppr*/ppr_safe_when_in_use +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (RO) True if memory media is accessible and data is retained + during the PPR operation. + +What: /sys/bus/edac/devices//ppr*/repair_hpa +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (WO) Start the PPR operation for the HPA (host physical + address) set. Return failure if resources are not available + to perform repair. + +What: /sys/bus/edac/devices//ppr*/repair_dpa +Date: Oct 2024 +KernelVersion: 6.12 +Contact: linux-edac@vger.kernel.org +Description: + (WO) Starts the PPR operation for the DPA(device physical + address) set. Return failure if resources are not available + to perform repair. + In some states of system configuration (e.g. before address decoders + have been configured), memory devices (e.g. CXL) may not have an + active mapping in the main host address physical address map. + As such, the memory to repair must be identified by a device + specific physical addressing scheme using a DPA. The DPA to use + will be presented in related error records. diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 4645e4032523..4e8e94fbea6a 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC) := edac_core.o edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_core-y += edac_module.o edac_device_sysfs.o wq.o -edac_core-y += edac_scrub.o edac_ecs.o +edac_core-y += edac_scrub.o edac_ecs.o edac_ppr.o edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 17e7ded01b22..6d6599c0659d 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -626,6 +626,12 @@ static int edac_dev_feat_init(struct device *parent, case RAS_FEAT_PPR: dev_data->ppr_ops = ras_feat->ppr_ops; dev_data->private = ras_feat->ppr_ctx; + + ret = edac_ppr_get_desc(parent, attr_groups, + ras_feat->instance); + if (ret) + return ret; + return 1; default: return -EINVAL; diff --git a/drivers/edac/edac_ppr.c b/drivers/edac/edac_ppr.c new file mode 100755 index 000000000000..dab2ba0a8145 --- /dev/null +++ b/drivers/edac/edac_ppr.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic EDAC PPR driver supports controlling the memory + * device with Post Package Repair (PPR) feature in the system + * and the common sysfs PPR control interface promotes unambiguous + * access from the userspace. + * + * Copyright (c) 2024 HiSilicon Limited. + */ + +#define pr_fmt(fmt) "EDAC PPR: " fmt + +#include + +enum edac_ppr_attributes { + PPR_PERSIST_MODE_AVAIL, + PPR_PERSIST_MODE, + PPR_DPA_SUPPORT, + PPR_SAFE_IN_USE, + PPR_HPA, + PPR_DPA, + PPR_MAX_ATTRS +}; + +struct edac_ppr_dev_attr { + struct device_attribute dev_attr; + u8 instance; +}; + +struct edac_ppr_context { + char name[EDAC_FEAT_NAME_LEN]; + struct edac_ppr_dev_attr ppr_dev_attr[PPR_MAX_ATTRS]; + struct attribute *ppr_attrs[PPR_MAX_ATTRS + 1]; + struct attribute_group group; +}; + +#define to_ppr_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct edac_ppr_dev_attr, dev_attr) + +static ssize_t persist_mode_avail_show(struct device *ras_feat_dev, + struct device_attribute *attr, char *buf) +{ + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + + return ops->get_persist_mode_avail(ras_feat_dev->parent, + ctx->ppr[inst].private, buf); +} + +static ssize_t persist_mode_show(struct device *ras_feat_dev, + struct device_attribute *attr, char *buf) +{ + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + u32 mode; + int ret; + + ret = ops->get_persist_mode(ras_feat_dev->parent, ctx->ppr[inst].private, &mode); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", mode); +} + +static ssize_t persist_mode_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + long mode; + int ret; + + ret = kstrtol(buf, 0, &mode); + if (ret < 0) + return ret; + + ret = ops->set_persist_mode(ras_feat_dev->parent, ctx->ppr[inst].private, mode); + if (ret) + return ret; + + return len; +} + +static ssize_t dpa_support_show(struct device *ras_feat_dev, + struct device_attribute *attr, char *buf) +{ + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + int ret; + u32 val; + + ret = ops->get_dpa_support(ras_feat_dev->parent, ctx->ppr[inst].private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t ppr_safe_when_in_use_show(struct device *ras_feat_dev, + struct device_attribute *attr, char *buf) +{ + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + int ret; + u32 val; + + ret = ops->get_ppr_safe_when_in_use(ras_feat_dev->parent, + ctx->ppr[inst].private, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t repair_hpa_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + u64 hpa; + int ret; + + ret = kstrtou64(buf, 0, &hpa); + if (ret < 0) + return ret; + + ret = ops->do_ppr(ras_feat_dev->parent, ctx->ppr[inst].private, true, hpa); + if (ret) + return ret; + + return len; +} + +static ssize_t repair_dpa_store(struct device *ras_feat_dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + u64 dpa; + int ret; + + ret = kstrtou64(buf, 0, &dpa); + if (ret < 0) + return ret; + + ret = ops->do_ppr(ras_feat_dev->parent, ctx->ppr[inst].private, 0, dpa); + if (ret) + return ret; + + return len; +} + +static umode_t ppr_attr_visible(struct kobject *kobj, + struct attribute *a, int attr_id) +{ + struct device *ras_feat_dev = kobj_to_dev(kobj); + struct device_attribute *dev_attr = + container_of(a, struct device_attribute, attr); + u8 inst = ((struct edac_ppr_dev_attr *)to_ppr_dev_attr(dev_attr))->instance; + struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); + const struct edac_ppr_ops *ops = ctx->ppr[inst].ppr_ops; + + switch (attr_id) { + case PPR_PERSIST_MODE_AVAIL: + return ops->get_persist_mode_avail ? a->mode : 0; + case PPR_PERSIST_MODE: + if (ops->get_persist_mode && ops->set_persist_mode) + return a->mode; + if (ops->get_persist_mode) + return 0444; + return 0; + case PPR_DPA_SUPPORT: + return ops->get_dpa_support ? a->mode : 0; + case PPR_SAFE_IN_USE: + return ops->get_ppr_safe_when_in_use ? a->mode : 0; + case PPR_HPA: + case PPR_DPA: + return ops->do_ppr ? a->mode : 0; + default: + return 0; + } +} + +#define EDAC_PPR_ATTR_RO(_name, _instance) \ + ((struct edac_ppr_dev_attr) { .dev_attr = __ATTR_RO(_name), \ + .instance = _instance }) + +#define EDAC_PPR_ATTR_WO(_name, _instance) \ + ((struct edac_ppr_dev_attr) { .dev_attr = __ATTR_WO(_name), \ + .instance = _instance }) + +#define EDAC_PPR_ATTR_RW(_name, _instance) \ + ((struct edac_ppr_dev_attr) { .dev_attr = __ATTR_RW(_name), \ + .instance = _instance }) + +static int ppr_create_desc(struct device *ppr_dev, + const struct attribute_group **attr_groups, + u8 instance) +{ + struct edac_ppr_context *ppr_ctx; + struct attribute_group *group; + int i; + + ppr_ctx = devm_kzalloc(ppr_dev, sizeof(*ppr_ctx), GFP_KERNEL); + if (!ppr_ctx) + return -ENOMEM; + + group = &ppr_ctx->group; + ppr_ctx->ppr_dev_attr[0] = EDAC_PPR_ATTR_RO(persist_mode_avail, instance); + ppr_ctx->ppr_dev_attr[1] = EDAC_PPR_ATTR_RW(persist_mode, instance); + ppr_ctx->ppr_dev_attr[2] = EDAC_PPR_ATTR_RO(dpa_support, instance); + ppr_ctx->ppr_dev_attr[3] = EDAC_PPR_ATTR_RO(ppr_safe_when_in_use, instance); + ppr_ctx->ppr_dev_attr[4] = EDAC_PPR_ATTR_WO(repair_hpa, instance); + ppr_ctx->ppr_dev_attr[5] = EDAC_PPR_ATTR_WO(repair_dpa, instance); + for (i = 0; i < PPR_MAX_ATTRS; i++) + ppr_ctx->ppr_attrs[i] = &ppr_ctx->ppr_dev_attr[i].dev_attr.attr; + + sprintf(ppr_ctx->name, "%s%d", "ppr", instance); + group->name = ppr_ctx->name; + group->attrs = ppr_ctx->ppr_attrs; + group->is_visible = ppr_attr_visible; + + attr_groups[0] = group; + + return 0; +} + +/** + * edac_ppr_get_desc - get edac PPR descriptors + * @ppr_dev: client PPR device + * @attr_groups: pointer to attrribute group container + * @instance: device's PPR instance number. + * + * Returns 0 on success, error otherwise. + */ +int edac_ppr_get_desc(struct device *ppr_dev, + const struct attribute_group **attr_groups, + u8 instance) +{ + if (!ppr_dev || !attr_groups) + return -EINVAL; + + return ppr_create_desc(ppr_dev, attr_groups, instance); +} diff --git a/include/linux/edac.h b/include/linux/edac.h index 86fc4ee97f20..9154fa64eb67 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -739,6 +739,35 @@ int edac_ecs_get_desc(struct device *ecs_dev, const struct attribute_group **attr_groups, u16 num_media_frus); +enum edac_ppr_type { + EDAC_TYPE_SPPR, /* soft PPR */ + EDAC_TYPE_HPPR, /* hard PPR */ +}; + +/** + * struct edac_ppr_ops - PPR(Post Package Repair) device operations + * (all elements optional) + * @get_persist_mode_avail: get the persist modes supported in the device. + * @get_persist_mode: get the persist mode of the PPR instance. + * @set_persist_mode: set the persist mode for the PPR instance. + * @get_dpa_support: get dpa support flag. + * @get_ppr_safe_when_in_use: get whether memory media is accessible and + * data is retained during PPR operation. + * @do_ppr: start PPR operation for the HPA/DPA set. + */ +struct edac_ppr_ops { + int (*get_persist_mode_avail)(struct device *dev, void *drv_data, char *buf); + int (*get_persist_mode)(struct device *dev, void *drv_data, u32 *mode); + int (*set_persist_mode)(struct device *dev, void *drv_data, u32 mode); + int (*get_dpa_support)(struct device *dev, void *drv_data, u32 *val); + int (*get_ppr_safe_when_in_use)(struct device *dev, void *drv_data, u32 *val); + int (*do_ppr)(struct device *dev, void *drv_data, bool hpa, u64 pa); +}; + +int edac_ppr_get_desc(struct device *ppr_dev, + const struct attribute_group **attr_groups, + u8 instance); + /* * EDAC device feature information structure */ From patchwork Fri Aug 16 16:42:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766606 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id C5702C531DC for ; Fri, 16 Aug 2024 16:44:10 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 838158D009A; Fri, 16 Aug 2024 12:43:58 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 796638D007E; Fri, 16 Aug 2024 12:43:58 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 5DD6F8D009A; Fri, 16 Aug 2024 12:43:58 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 308038D007E for ; Fri, 16 Aug 2024 12:43:58 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id E4F0FA0011 for ; Fri, 16 Aug 2024 16:43:57 +0000 (UTC) X-FDA: 82458680514.27.5E0F6DF Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf15.hostedemail.com (Postfix) with ESMTP id EEAEFA001F for ; Fri, 16 Aug 2024 16:43:55 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf15.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826575; a=rsa-sha256; cv=none; b=b4KVCdEa6tYnw4FG0b7wCHgtMm4oVWNPDu7cQ/6moJ3ZFscajS2oe4bM7RCiE6v2sWvS6X 1k5yjzfmVCx9bEosYFrUJiC+OEqdSljGv8ctJzQukXclockhHJLDFUpP8CuV427DpqfiLr KBcxusg7eS5yaTFH+rV3kuefWn6BUGE= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf15.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826575; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wj2GoLc0vZfGtCTkuzUOTZtR6hso48BikQ3190WNIC4=; b=Dw1Mgkxnz8xRh+jm+J6mO56+t3T3qj16f7Ux81t0z/457gEbx4gwWnAnKhDOtu3U342b8E K1NqlZTx5VJVH5ISEWUiT7+ULr1/fmiGByuxyLs1TjpMH4YsO8hQrHakP2EmtmPi1KZrmW deJxnssOiA01IP3bR/C4PeRGJ3dq3TE= Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4Wlnml4kNZz6K95v; Sat, 17 Aug 2024 00:40:55 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id E7E63140680; Sat, 17 Aug 2024 00:43:53 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:52 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 13/14] cxl/mbox: Add support for PERFORM_MAINTENANCE mailbox command Date: Fri, 16 Aug 2024 17:42:36 +0100 Message-ID: <20240816164238.1902-14-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: EEAEFA001F X-Stat-Signature: i58c1xd3rgk51uiy3ki7gs9zzb3sy158 X-Rspam-User: X-HE-Tag: 1723826635-289213 X-HE-Meta: U2FsdGVkX18RZ08NeMPiNH1dHdM9u69m0H27+u7paUMO8qha9Zgqr8aPvteDvLgl5jOFUbDX3ROo4ETbhMqf0bvXHoNQtkLLd3NKa+r3B0oM71lW5+w9CMR8+Djvpi1WHuBGK38ISHQaoZw13CLe56IGUiY4OAWBnHY/5oZrgtdNyEePAb1ebqlmK0DUIrehBzwg0bGGJAfncRPWFSHjSjrONantp7Er9Yej8dBImPM5AhxaPRaxXhS+YWgiT/P3WfIl9WZObuN61vPgNeEpAwKgOuHYG/r+nYxsF0h2CBGPWnhHIHUFFLuK/9vvNfaBCC2FAgIRfACtlLBcjLDHRhwKz0TKCrb6Yo4G0O/FZBPHfCuBx8ATvg0gCmraL2wAlN73ERGjuA4cO/0XrgU53ZPfyzuEqD+VYtF9nVAm+Bb6pwOvg/m8UozvyfbfqLrukGAR0xk6F34LImjdcDvyGYMo4UWjqYjHS8uBPew7XDZWe9cB+O2nPk93IR68LD2pGY64Wtunvr3QEEJ1W3P0frFJNXx6h/2/ZkDksWvAJVjaadM8CpzLxm5qSKdJ+Lz4deaJZaTlrVIKaFe8sqmXMa3PFkU9LuANjZTgwAVKG7NspfbXkh8f+95cLAchq/tITA4MRo7hXlVJYZIzrWxYWLj6DyzOPUvqVlkeQmlIaLA87LqdEF+81R3LtXEHuQSyzCgD6wfi6p8APyMI7iDsVkChk0TAZpyOZ/ECW3RJJt+WxL9qQG/5BvIhTVWrny7V9QspAg0loVW1m+c5qZ+/3Y3MpgLhi7wKbYYbIEIoXF9kpi5F0MWebuBVljgsXt4TL3CD/34+jbqHtGRMslx9l/61Ko9TWYz5MNXLm3H/3j/+10QrvH9ujFXPGwEPHMNEcF9Pe2X1lRsgTdtJ+CnCh+YJ7jgk9HMZe5CmnNfC734iCZMPoRuxPy//gm4612UzfK/enLBkSrxX2v82fvR URUj+883 sjBzbjK+VemYyGoxP7qszJmffv9XjvD708q07XxnxBFcFS/BIKwh2WAb7ET5xlVPnB13SK9nUOtOB1Oq7XUIXyC30NbZA05AupAvLDtJ2OjD2MhxYHSlAuFiOajluQgz67MDljUjIHAXi5MkJBZBbDBP7ScXAojBC0MD+a8Qg1SrClXIQrrprfyh88OvvXOOEDsXf2lT37Bu40EA7HXnWtHQV78aVh+xmqheyv77SMbWIhqUC3rpf4i9Rqk/wxdUtRgdfVWal6Smtpdk= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Shiju Jose Add support for PERFORM_MAINTENANCE mailbox command. CXL spec 3.1 section 8.2.9.7.1 describes the Perform Maintenance command. This command requests the device to execute the maintenance operation specified by the maintenance operation class and the maintenance operation subclass. Signed-off-by: Shiju Jose --- drivers/cxl/core/mbox.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 17 +++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index f79269add159..1665365a1e26 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1504,6 +1504,45 @@ int cxl_set_feature(struct cxl_memdev_state *mds, } EXPORT_SYMBOL_NS_GPL(cxl_set_feature, CXL); +int cxl_do_maintenance(struct cxl_memdev_state *mds, + u8 class, u8 subclass, + void *data_in, size_t data_in_size) +{ + struct cxl_memdev_maintenance_pi { + struct cxl_mbox_do_maintenance_hdr hdr; + u8 data[]; + } __packed; + struct cxl_mbox_cmd mbox_cmd; + size_t hdr_size; + int rc = 0; + + struct cxl_memdev_maintenance_pi *pi __free(kfree) = + kmalloc(mds->payload_size, GFP_KERNEL); + pi->hdr.op_class = class; + pi->hdr.op_subclass = subclass; + hdr_size = sizeof(pi->hdr); + /* + * Check minimum mbox payload size is available for + * the maintenance data transfer. + */ + if (hdr_size + data_in_size > mds->payload_size) + return -ENOMEM; + + memcpy(pi->data, data_in, data_in_size); + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_DO_MAINTENANCE, + .size_in = hdr_size + data_in_size, + .payload_in = pi, + }; + + rc = cxl_internal_send_cmd(mds, &mbox_cmd); + if (rc < 0) + return rc; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_do_maintenance, 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 c6f6e38bdbcb..f525eb330dea 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -534,6 +534,7 @@ enum cxl_opcode { CXL_MBOX_OP_GET_SUPPORTED_FEATURES = 0x0500, CXL_MBOX_OP_GET_FEATURE = 0x0501, CXL_MBOX_OP_SET_FEATURE = 0x0502, + CXL_MBOX_OP_DO_MAINTENANCE = 0x0600, CXL_MBOX_OP_IDENTIFY = 0x4000, CXL_MBOX_OP_GET_PARTITION_INFO = 0x4100, CXL_MBOX_OP_SET_PARTITION_INFO = 0x4101, @@ -811,6 +812,19 @@ struct cxl_mbox_set_feat_hdr { u8 rsvd[9]; } __packed; +/* + * Perform Maintenance CXL 3.1 Spec 8.2.9.7.1 + */ + +/* + * Perform Maintenance input payload + * CXL rev 3.1 section 8.2.9.7.1 Table 8-102 + */ +struct cxl_mbox_do_maintenance_hdr { + u8 op_class; + u8 op_subclass; +} __packed; + /* Get Poison List CXL 3.0 Spec 8.2.9.8.4.1 */ struct cxl_mbox_poison_in { __le64 offset; @@ -955,6 +969,9 @@ 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_do_maintenance(struct cxl_memdev_state *mds, + u8 class, u8 subclass, + void *data_in, size_t data_in_size); 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 Aug 16 16:42:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 13766607 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id F3A62C531DC for ; Fri, 16 Aug 2024 16:44:13 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id C2E948D009B; Fri, 16 Aug 2024 12:44:00 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id B194F8D007E; Fri, 16 Aug 2024 12:44:00 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 91CAF8D009B; Fri, 16 Aug 2024 12:44:00 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 6E9348D007E for ; Fri, 16 Aug 2024 12:44:00 -0400 (EDT) Received: from smtpin05.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 25B2D4017B for ; Fri, 16 Aug 2024 16:44:00 +0000 (UTC) X-FDA: 82458680640.05.1D1BEBB Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf26.hostedemail.com (Postfix) with ESMTP id 11AFA14000A for ; Fri, 16 Aug 2024 16:43:57 +0000 (UTC) Authentication-Results: imf26.hostedemail.com; dkim=none; spf=pass (imf26.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723826624; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NW8Hr1ArFQ5qG9wxysPmp1Yedjexi153IYJ6D7ylWRI=; b=3VcZvh3jGISMS5iLi/R+r6ow3QS0/bMZiOVj/DihXbGKcd5jSk9bGjHsAmilK1tb/vnyzN +fLCVtekTvbDK9OiOGHxZq9ghtDw8AgawNQt293jabtuoBDKCsGOaFDnFmL0k1q0Du5txv nMWxohA6L3VaSgpGO4Dvyu/cP3l7j0g= ARC-Authentication-Results: i=1; imf26.hostedemail.com; dkim=none; spf=pass (imf26.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723826624; a=rsa-sha256; cv=none; b=8f4o4YRtKNFMgTbcvtVC+1aPU7xjmjS+TAFteAjruJ/hPxZcODSAe1qGi7yiDBKm9DyUZM bxKbY1J1v2JwwuRa1xbb0JcW2WbJxsLFufQ6B6/F8ZNdbmdOFqaqs1sprJ6YGzLxvw+Z0W k4lhdRO5snuv+LPBRys41z1iymUxTGI= Received: from mail.maildlp.com (unknown [172.18.186.216]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4WlnmK1D43z6K5rd; Sat, 17 Aug 2024 00:40:33 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id 2A5771400DB; Sat, 17 Aug 2024 00:43:56 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.48.148.43) 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.39; Fri, 16 Aug 2024 17:43:54 +0100 From: To: , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v11 14/14] cxl/memfeature: Add CXL memory device PPR control feature Date: Fri, 16 Aug 2024 17:42:37 +0100 Message-ID: <20240816164238.1902-15-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20240816164238.1902-1-shiju.jose@huawei.com> References: <20240816164238.1902-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.48.148.43] X-ClientProxiedBy: lhrpeml100005.china.huawei.com (7.191.160.25) To lhrpeml500006.china.huawei.com (7.191.161.198) X-Rspam-User: X-Stat-Signature: wonmcr77uq3fwu511m1ugeqf7op6mbsk X-Rspamd-Queue-Id: 11AFA14000A X-Rspamd-Server: rspam11 X-HE-Tag: 1723826637-759320 X-HE-Meta: U2FsdGVkX19NvOALG++rnx7i4c+FX+BBp+NLQS5WBgol5gS6PX+gr6z/bNkd1ujJINw1ae+rLH/gtNiqSvWdPLd2WQU+N0+ej32thUoggxozvLmhg0uvipRY4RqSCu9kFmdUkBLPcpvvhwsAoCZySE3MgeEoLh9nBlnZF8MXq87trBphJ0R+5D9slCHfiMW65D2U4VCaNt59I137VzuUumghbn8WjSxSo/sTbQ0wGIxPKwozMbI1pEU2XmoqFgr7VXf48WrQvpSbICaHhxZjlPfzRoqqgGiTmyN6/ujZWKusxZKvFZP/xQCRoPlTnd4jn8Ta5B4WMNjxsYpLVVWdXdwra4xk4bx2i853V4bPsAweMGwxe3ZLXXHPs157lBP2S/GVyWcKASuKjhnvauibZnmLjNVtjtq7wzhO/oaEtrpmjd2cFOMqv3FmcGkW9HOaiKCGkZtykXBUFedMEAMY0fAAbSm+Q6Pyfir+lIgbM8R952icHtXMdNkSP52az6+8z7Wb+0d7mMX42v4Wpz/JAwfKHEiy951qlUrOGOCuu56IBF/RCuYSrad9RGyvWO8cZmU1OoYK2hFoKw58GgP45rRKK/k/HTcYYUWy7E8XQXIuNE3uDCPZsx8nrSjzE6KdSdtyb+ICtg4mkJ97TT5Nq0SNFU+8qFWFG6T1z1hOQEZU8D/hPwONuztBO5mO3ZJ88E47a0s4rff3C8pxATxQAyryv6c5+NRJQo48VORxszuRW+45BJws3cOMqnr3Qh1+ZQvcjV1L6twBXwi60+hAK4YBsWVAXvWJ9BXg6sr82oS41z4oH/UY1L8FGwrnMGBWMd0jIlImrGttHen12GTy8GhCvL1uMiDGQ6SfE90k/W/L9LN/TWihJWS6Ii6ddZ9vZbyn1EzTSiKnzJ/5CkLf5Z1X8HlTZDZk6SZkFCBkq+UwBM57Z7K3T7hy/loQS5aun+NZoS85M/kTVCUZHmu js4vuZA2 8KuNeuGdQTLhkOe4IBfB3N10UoeMu344FpMK+l91qAQZpObZ2X22w2+UZtFvlUlhaLuR0Iwqi4tbly1DFyrwvdU5EkQFWMXfw2yE72JCsX1bFWaxGeUVWcNVC7QGh5rNiw4v/v3EI0UmhEP1fL+QmLvmGJNxfp7zZ4GjTOtYxU/IT5KGo5hlOCqYWA220IXeWzc1gAIREjwpXeWBGQUQEPXcQVWW6i6u9txAGS0sm7UX/cVf15wGVFulyt0/CCCFk1ZGlf0B3rBnmu/wt10hHQnM5m9bdCWm/JX0eCkgPkPoDiFtrPWYnxq4LvbCNgcwuxzRqh8PRhyjtTw8= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Shiju Jose Post Package Repair (PPR) maintenance operations may be supported by CXL devices that implement CXL.mem protocol. A PPR maintenance operation requests the CXL device to perform a repair operation on its media. For example, a CXL device with DRAM components that support PPR features may implement PPR Maintenance operations. DRAM components may support two types of PPR: Hard PPR (hPPR), for a permanent row repair, and Soft PPR (sPPR), for a temporary row repair. sPPR is much faster than hPPR, but the repair is lost with a power cycle. During the execution of a PPR Maintenance operation, a CXL memory device: - May or may not retain data - May or may not be able to process CXL.mem requests correctly, including the ones that target the DPA involved in the repair. These CXL Memory Device capabilities are specified by Restriction Flags in the sPPR Feature and hPPR Feature. sPPR maintenance operation may be executed at runtime, if data is retained and CXL.mem requests are correctly processed. For CXL devices with DRAM components, hPPR maintenance operation may be executed only at boot because data would not be retained. When a CXL device identifies a failure on a memory component, the device may inform the host about the need for a PPR maintenance operation by using an Event Record, where the Maintenance Needed flag is set. The Event Record specifies the DPA that should be repaired. A CXL device may not keep track of the requests that have already been sent and the information on which DPA should be repaired may be lost upon power cycle. The userspace tool requests for maintenance operation if the number of corrected error reported on a CXL.mem media exceeds error threshold. CXL spec 3.1 section 8.2.9.7.1.2 describes the device's sPPR (soft PPR) maintenance operation and section 8.2.9.7.1.3 describes the device's hPPR (hard PPR) maintenance operation feature. CXL spec 3.1 section 8.2.9.7.2.1 describes the sPPR feature discovery and configuration. CXL spec 3.1 section 8.2.9.7.2.12 describes the hPPR feature discovery and configuration. Add support for CXL memory device PPR control. Register with EDAC driver, which gets the PPR attr descriptors from the EDAC PPR and expose sysfs PPR control attributes to the userspace. For example CXL PPR control for the CXL mem0 device is exposed in /sys/bus/edac/devices/cxl_mem0/pprX/ Tested with QEMU patch for CXL PPR feature. https://lore.kernel.org/all/20240730045722.71482-1-dave@stgolabs.net/ Signed-off-by: Shiju Jose --- drivers/cxl/core/memfeature.c | 279 +++++++++++++++++++++++++++++++++- 1 file changed, 278 insertions(+), 1 deletion(-) diff --git a/drivers/cxl/core/memfeature.c b/drivers/cxl/core/memfeature.c index ee7fd2f58d01..5ce7d7fb9042 100644 --- a/drivers/cxl/core/memfeature.c +++ b/drivers/cxl/core/memfeature.c @@ -18,8 +18,9 @@ #include #include #include +#include "core.h" -#define CXL_DEV_NUM_RAS_FEATURES 2 +#define CXL_DEV_NUM_RAS_FEATURES 3 #define CXL_DEV_HOUR_IN_SECS 3600 #define CXL_SCRUB_NAME_LEN 128 @@ -708,6 +709,249 @@ static const struct edac_ecs_ops cxl_ecs_ops = { .set_threshold = cxl_ecs_set_threshold, }; +/* CXL memory soft PPR & hard PPR control definitions */ +static const uuid_t cxl_sppr_uuid = + UUID_INIT(0x892ba475, 0xfad8, 0x474e, 0x9d, 0x3e, 0x69, 0x2c, 0x91, \ + 0x75, 0x68, 0xbb); + +static const uuid_t cxl_hppr_uuid = + UUID_INIT(0x80ea4521, 0x786f, 0x4127, 0xaf, 0xb1, 0xec, 0x74, 0x59, \ + 0xfb, 0x0e, 0x24); + +struct cxl_ppr_context { + uuid_t ppr_uuid; + u8 instance; + u16 get_feat_size; + u16 set_feat_size; + u8 get_version; + u8 set_version; + u16 set_effects; + struct cxl_memdev *cxlmd; + enum edac_ppr_type ppr_type; + u64 dpa; + u32 nibble_mask; +}; + +/** + * struct cxl_memdev_ppr_params - CXL memory PPR parameter data structure. + * @op_class[OUT]: PPR operation class. + * @op_subclass[OUT]: PPR operation subclass. + * @dpa_support[OUT]: device physical address for PPR support. + * @media_accessible[OUT]: memory media is accessible or not during PPR operation. + * @data_retained[OUT]: data is retained or not during PPR operation. + * @dpa:[IN]: device physical address. + */ +struct cxl_memdev_ppr_params { + u8 op_class; + u8 op_subclass; + bool dpa_support; + bool media_accessible; + bool data_retained; + u64 dpa; +}; + +enum cxl_ppr_param { + CXL_PPR_PARAM_DO_PPR, +}; + +#define CXL_MEMDEV_PPR_QUERY_RESOURCE_FLAG BIT(0) + +#define CXL_MEMDEV_PPR_DEVICE_INITIATED_MASK BIT(0) +#define CXL_MEMDEV_PPR_FLAG_DPA_SUPPORT_MASK BIT(0) +#define CXL_MEMDEV_PPR_FLAG_NIBBLE_SUPPORT_MASK BIT(1) +#define CXL_MEMDEV_PPR_FLAG_MEM_SPARING_EV_REC_SUPPORT_MASK BIT(2) + +#define CXL_MEMDEV_PPR_RESTRICTION_FLAG_MEDIA_ACCESSIBLE_MASK BIT(0) +#define CXL_MEMDEV_PPR_RESTRICTION_FLAG_DATA_RETAINED_MASK BIT(2) + +#define CXL_MEMDEV_PPR_SPARING_EV_REC_EN_MASK BIT(0) + +struct cxl_memdev_ppr_rd_attrs { + u8 max_op_latency; + __le16 op_cap; + __le16 op_mode; + u8 op_class; + u8 op_subclass; + u8 rsvd[9]; + u8 ppr_flags; + __le16 restriction_flags; + u8 ppr_op_mode; +} __packed; + +struct cxl_memdev_ppr_wr_attrs { + __le16 op_mode; + u8 ppr_op_mode; +} __packed; + +struct cxl_memdev_ppr_maintenance_attrs { + u8 flags; + __le64 dpa; + u8 nibble_mask[3]; +} __packed; + +static int cxl_mem_ppr_get_attrs(struct device *dev, void *drv_data, + struct cxl_memdev_ppr_params *params) +{ + struct cxl_ppr_context *cxl_ppr_ctx = drv_data; + struct cxl_memdev *cxlmd = cxl_ppr_ctx->cxlmd; + 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_ppr_rd_attrs); + size_t data_size; + struct cxl_memdev_ppr_rd_attrs *rd_attrs __free(kfree) = + kmalloc(rd_data_size, GFP_KERNEL); + if (!rd_attrs) + return -ENOMEM; + + data_size = cxl_get_feature(mds, cxl_ppr_ctx->ppr_uuid, + CXL_GET_FEAT_SEL_CURRENT_VALUE, + rd_attrs, rd_data_size); + if (!data_size) + return -EIO; + + params->op_class = rd_attrs->op_class; + params->op_subclass = rd_attrs->op_subclass; + params->dpa_support = FIELD_GET(CXL_MEMDEV_PPR_FLAG_DPA_SUPPORT_MASK, + rd_attrs->ppr_flags); + params->media_accessible = FIELD_GET(CXL_MEMDEV_PPR_RESTRICTION_FLAG_MEDIA_ACCESSIBLE_MASK, + rd_attrs->restriction_flags) ^ 1; + params->data_retained = FIELD_GET(CXL_MEMDEV_PPR_RESTRICTION_FLAG_DATA_RETAINED_MASK, + rd_attrs->restriction_flags) ^ 1; + + return 0; +} + +static int cxl_mem_ppr_set_attrs(struct device *dev, void *drv_data, + struct cxl_memdev_ppr_params *params, + enum cxl_ppr_param param_type) +{ + struct cxl_memdev_ppr_maintenance_attrs maintenance_attrs; + struct cxl_ppr_context *cxl_ppr_ctx = drv_data; + struct cxl_memdev *cxlmd = cxl_ppr_ctx->cxlmd; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct cxl_memdev_ppr_params rd_params; + struct cxl_region *cxlr; + int ret; + + ret = cxl_mem_ppr_get_attrs(dev, drv_data, &rd_params); + if (ret) { + dev_err(dev, "Get cxlmemdev PPR params failed ret=%d\n", + ret); + return ret; + } + + switch (param_type) { + case CXL_PPR_PARAM_DO_PPR: + ret = down_read_interruptible(&cxl_region_rwsem); + if (ret) + return ret; + if (!rd_params.media_accessible || !rd_params.data_retained) { + /* Check if DPA is mapped */ + ret = down_read_interruptible(&cxl_dpa_rwsem); + if (ret) { + up_read(&cxl_region_rwsem); + return ret; + } + + cxlr = cxl_dpa_to_region(cxlmd, cxl_ppr_ctx->dpa); + up_read(&cxl_dpa_rwsem); + if (cxlr) { + dev_err(dev, "CXL can't do PPR as DPA is mapped\n"); + up_read(&cxl_region_rwsem); + return -EBUSY; + } + } + maintenance_attrs.flags = CXL_MEMDEV_PPR_QUERY_RESOURCE_FLAG; + maintenance_attrs.dpa = params->dpa; + /* May need to get the nibble mask from the CXL dram error record via + * trace dram event. Presently all nibble masks bits set to 1. + */ + maintenance_attrs.nibble_mask[0] = 0xFF; + maintenance_attrs.nibble_mask[1] = 0xFF; + maintenance_attrs.nibble_mask[2] = 0xFF; + ret = cxl_do_maintenance(mds, rd_params.op_class, rd_params.op_subclass, + &maintenance_attrs, sizeof(maintenance_attrs)); + if (ret) { + dev_err(dev, "CXL do PPR maintenance failed ret=%d\n", ret); + up_read(&cxl_region_rwsem); + return ret; + } + up_read(&cxl_region_rwsem); + return 0; + default: + return -EINVAL; + } +} + +static int cxl_ppr_get_persist_mode_avail(struct device *dev, void *drv_data, + char *buf) +{ + return sysfs_emit(buf, "Soft PPR Hard PPR\n"); +} + +static int cxl_ppr_get_persist_mode(struct device *dev, void *drv_data, + u32 *persist_mode) +{ + struct cxl_ppr_context *cxl_ppr_ctx = drv_data; + + *persist_mode = cxl_ppr_ctx->ppr_type; + + return 0; +} + +static int cxl_ppr_get_dpa_support(struct device *dev, void *drv_data, + u32 *dpa_support) +{ + struct cxl_memdev_ppr_params params; + int ret; + + ret = cxl_mem_ppr_get_attrs(dev, drv_data, ¶ms); + if (ret) + return ret; + + *dpa_support = params.dpa_support; + + return 0; +} + +static int cxl_get_ppr_safe_when_in_use(struct device *dev, void *drv_data, + u32 *safe) +{ + struct cxl_memdev_ppr_params params; + int ret; + + ret = cxl_mem_ppr_get_attrs(dev, drv_data, ¶ms); + if (ret) + return ret; + + *safe = params.media_accessible & params.data_retained; + + return 0; +} + +static int cxl_do_ppr(struct device *dev, void *drv_data, bool hpa, u64 pa) +{ + struct cxl_memdev_ppr_params params = { + .dpa = pa, + }; + + /* CXL mem perform PPR, need support for HPA? */ + if (hpa) + return -EOPNOTSUPP; + + return cxl_mem_ppr_set_attrs(dev, drv_data, ¶ms, + CXL_PPR_PARAM_DO_PPR); +} + +static const struct edac_ppr_ops cxl_sppr_ops = { + .get_persist_mode_avail = cxl_ppr_get_persist_mode_avail, + .get_persist_mode = cxl_ppr_get_persist_mode, + .get_dpa_support = cxl_ppr_get_dpa_support, + .get_ppr_safe_when_in_use = cxl_get_ppr_safe_when_in_use, + .do_ppr = cxl_do_ppr, +}; + int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) { struct edac_dev_feature ras_features[CXL_DEV_NUM_RAS_FEATURES]; @@ -717,8 +961,10 @@ int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) struct cxl_mbox_supp_feat_entry feat_entry; char cxl_dev_name[CXL_SCRUB_NAME_LEN]; struct cxl_ecs_context *cxl_ecs_ctx; + struct cxl_ppr_context *cxl_sppr_ctx; int rc, i, num_ras_features = 0; int num_media_frus; + u8 ppr_inst = 0; if (cxlr) { struct cxl_region_params *p = &cxlr->params; @@ -804,6 +1050,37 @@ int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) ras_features[num_ras_features].ecs_info.num_media_frus = num_media_frus; num_ras_features++; + + /* CXL sPPR */ + rc = cxl_get_supported_feature_entry(mds, &cxl_sppr_uuid, + &feat_entry); + if (rc < 0) + goto feat_register; + + if (!(feat_entry.attr_flags & CXL_FEAT_ENTRY_FLAG_CHANGABLE)) + goto feat_register; + + cxl_sppr_ctx = devm_kzalloc(&cxlmd->dev, sizeof(*cxl_sppr_ctx), + GFP_KERNEL); + if (!cxl_sppr_ctx) + goto feat_register; + *cxl_sppr_ctx = (struct cxl_ppr_context) { + .ppr_uuid = cxl_sppr_uuid, + .get_feat_size = feat_entry.get_size, + .set_feat_size = feat_entry.set_size, + .get_version = feat_entry.get_version, + .set_version = feat_entry.set_version, + .set_effects = feat_entry.set_effects, + .cxlmd = cxlmd, + .ppr_type = EDAC_TYPE_SPPR, + .instance = ppr_inst++, + }; + + ras_features[num_ras_features].feat = RAS_FEAT_PPR; + ras_features[num_ras_features].instance = cxl_sppr_ctx->instance; + ras_features[num_ras_features].ppr_ops = &cxl_sppr_ops; + ras_features[num_ras_features].ppr_ctx = cxl_sppr_ctx; + num_ras_features++; } feat_register: