From mboxrd@z Thu Jan 1 00:00:00 1970 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 E2C76C3DA61 for ; Mon, 29 Jul 2024 22:19:16 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 6341F6B007B; Mon, 29 Jul 2024 18:19:16 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5E3696B0083; Mon, 29 Jul 2024 18:19:16 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 483FF6B0085; Mon, 29 Jul 2024 18:19:16 -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 24AD86B007B for ; Mon, 29 Jul 2024 18:19:16 -0400 (EDT) Received: from smtpin30.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id A61781A010E for ; Mon, 29 Jul 2024 22:19:15 +0000 (UTC) X-FDA: 82394207070.30.D9BB32B Received: from mail-yb1-f181.google.com (mail-yb1-f181.google.com [209.85.219.181]) by imf25.hostedemail.com (Postfix) with ESMTP id B9FC4A000B for ; Mon, 29 Jul 2024 22:19:13 +0000 (UTC) Authentication-Results: imf25.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=Be29zFJf; spf=pass (imf25.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.219.181 as permitted sender) smtp.mailfrom=nifan.cxl@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1722291499; 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: in-reply-to:in-reply-to:references:references:dkim-signature; bh=5JfC7ZPZMdqfLYpveJCWOsMgU5tD8cPWlNpd7a+EoNE=; b=ZoVqcU8H5iu8vc+6lFOfaX1PXOjo57lu0sn2pY3IHX4h8IX4H2QLYcPWf2N+AR+5r+Jo94 mHvjMEJm6AlHvMEooPAWjvuP4V1RrSnD5yv8r8F/tc/IsVslcnONZEBBFp/Ml8mIvJPWSD Z9a8va7Bn+a2uOgrZ0o4EHeP+hLuTT8= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1722291499; a=rsa-sha256; cv=none; b=i6YzzUFMWbK2wjmsTr1FI3tHLybuDrpB/zVKPMnzGBg4wBsAO0bCLYXrJVgOCnKuBa77fT gg69H43DLojBLxtE6RzcT6FI5Dcp5VrLZDfnTaDH37Bu4Hoq4qd/X5iJHyLMIgEfMGSghT cqr6D78lKlqFimptlq4uBE1wxpH6aCQ= ARC-Authentication-Results: i=1; imf25.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=Be29zFJf; spf=pass (imf25.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.219.181 as permitted sender) smtp.mailfrom=nifan.cxl@gmail.com; dmarc=pass (policy=none) header.from=gmail.com Received: by mail-yb1-f181.google.com with SMTP id 3f1490d57ef6-e04196b7603so2358010276.0 for ; Mon, 29 Jul 2024 15:19:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1722291553; x=1722896353; darn=kvack.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:from:to:cc:subject:date:message-id:reply-to; bh=5JfC7ZPZMdqfLYpveJCWOsMgU5tD8cPWlNpd7a+EoNE=; b=Be29zFJfn/rh85xcpCShuqRfloqef4+1D94WRhTYKdr/S+tjN9W20Ky+a+WnYdJsLy 3TI/zczLLbzgUMqUaFG+jiT5FUOlRNCQ/LvKwUbYvabqzLfBwgWtJenJ5gyorCnmczhq YjoWWPB0e0ghxBImVuxgSRn2vObMM87FoBVfsQ/beeg1wPrE+ntBXdhh81gj9XiTlm68 B5trsS1H2/zawDhjK6GmqKFCMRbW43efPcIEESoUqabcPu2eYpBO9/bxz9NLR7RMuC/M 45nIqyvOgoCKhDDbY1P1ewYHLqqMyqcyoTFmeBTsJf9TrkLvvMW/fw2j+Y6kb29xRcQ9 K0Ag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722291553; x=1722896353; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=5JfC7ZPZMdqfLYpveJCWOsMgU5tD8cPWlNpd7a+EoNE=; b=Gvb7tMIpP2udo0SvfrzQTS5AMkPoVGe6MZGwV21BiXS5QOD+NJMDfo+U71Valg1a38 0Xl7mBxqEGN52ktC5OkIPmq9hp9wqXDMFym/IeXdc2JQ9WZTLpt/O4bQfyFOpPCX5Y2e XNgUz3yLrvExSpVc1KGmv8B7ZFKvZL+N8Niuq1BgoBa/L9iIu4JtisPcrh9wxfSRyIrf C0twXUH2/Kkkk0QVxFklzLsrBMxz4aWv0e8+nOgFjbi0QNrg2XyduhAUwh9xGqbZaxoM matTQR9tA1c/g2EBG7+iUUEIJZP5w6WN8PK5rylM+6fPTfyQF9/VNNH07DN8qxw7dAEO bcGw== X-Forwarded-Encrypted: i=1; AJvYcCXMoma4ck1NLV0QevoLSYDtiBHzuRKDUAD7eGert/ZSMP3PYgbUFK3CwPfMasAkV3XO3vZBaFuXruq/Wxy/UXkeeD0= X-Gm-Message-State: AOJu0Yx2Sxzjr35B1NyOSDk7WVpt+fYPfuOVmexxHZOfdAmTTG7e7S4y uj87ujoNW7om9IUYvIfP9Hiogn5Qgi1veX/MlGgqgkEOK0NtnJIe X-Google-Smtp-Source: AGHT+IHtaey3fRc0kEu5WLGQlebXsg1X2QTUUjfN2ZFUTkeFhhy6BodH0Yp178QMMZlZ2eEhtUgNkw== X-Received: by 2002:a25:68c3:0:b0:e04:e298:3755 with SMTP id 3f1490d57ef6-e0b544b8078mr9052544276.28.1722291552631; Mon, 29 Jul 2024 15:19:12 -0700 (PDT) Received: from debian ([50.205.20.42]) by smtp.gmail.com with ESMTPSA id 3f1490d57ef6-e0b2a969276sm2115300276.61.2024.07.29.15.19.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jul 2024 15:19:12 -0700 (PDT) From: Fan Ni X-Google-Original-From: Fan Ni Date: Mon, 29 Jul 2024 15:18:52 -0700 To: shiju.jose@huawei.com Cc: linux-edac@vger.kernel.org, linux-cxl@vger.kernel.org, linux-acpi@vger.kernel.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org, bp@alien8.de, tony.luck@intel.com, rafael@kernel.org, lenb@kernel.org, mchehab@kernel.org, dan.j.williams@intel.com, dave@stgolabs.net, jonathan.cameron@huawei.com, dave.jiang@intel.com, alison.schofield@intel.com, vishal.l.verma@intel.com, ira.weiny@intel.com, david@redhat.com, Vilas.Sridharan@amd.com, leo.duran@amd.com, Yazen.Ghannam@amd.com, rientjes@google.com, jiaqiyan@google.com, Jon.Grimm@amd.com, dave.hansen@linux.intel.com, naoya.horiguchi@nec.com, james.morse@arm.com, jthoughton@google.com, somasundaram.a@hpe.com, erdemaktas@google.com, pgonda@google.com, duenwen@google.com, mike.malvestuto@intel.com, gthelen@google.com, wschwartz@amperecomputing.com, dferguson@amperecomputing.com, wbs@os.amperecomputing.com, nifan.cxl@gmail.com, tanxiaofei@huawei.com, prime.zeng@hisilicon.com, roberto.sassu@huawei.com, kangkang.shen@futurewei.com, wanghuiqiang@huawei.com, linuxarm@huawei.com Subject: Re: [PATCH v10 11/11] ras: scrub: ACPI RAS2: Add memory ACPI RAS2 driver Message-ID: References: <20240726160556.2079-1-shiju.jose@huawei.com> <20240726160556.2079-12-shiju.jose@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20240726160556.2079-12-shiju.jose@huawei.com> X-Stat-Signature: inbeippa71s6jmt9etem9dtzqc9tj1xh X-Rspamd-Queue-Id: B9FC4A000B X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1722291553-463202 X-HE-Meta: U2FsdGVkX189r277Fcpl+E6ZucwG2/FOtlgic7XYEGNuwi01f+iXTkG/6Qme4XZ4JmiqdvmYs9g1Q8nAOwnHQ6CwP8OxJEO/csPNO2aIMbr/88iPibCZvCsArXL7YtQkxi5BTH1HeKdf0ZZn7elg1is9O/szC+PgCk7FPE7SOJwYwYBQczIVVIecwSGAgJXvjJlEofxL85q9aZrNHrS/weckg8wVqEVN5av4ax8XCtRNT5VMuPOSjdxrP3PNNvZUiCWaLAQpSdAWB7ETI9u7DmNqgILyQUMwlbSkPg8WxPOH+w1bsFdffcekLxt5aM1typd3mAEHgCmZPFrvWBYgTNjIGp57FUmhlJ/vLxEtHRJAC88aKKFLykDlzPEI6BtVlqdSbSXR3EkY0gm6WXGbgK7BryNkfxFsD0A6enArxqZ2m9thQ4ONa9ZRhp6v/zeIdihNYp6j3G3Um4JeJA+vVYDe/4JKaMRm9B8bL1dzECx1ZFYipFDab27ZtlItAIc/a2iCh4qLvzxY4MnJIt04fMMMHBllg0w2V31pDp7KZzUsLvqviJ9wl2AEyPd64OOEw7HlKR7zG4HReWwI3/ajueucQ/dlci87Eq8CbNZ4jpR2HswZLpVGiOrzlMcIMFsa0Q2RI5Pw74xnrVafbP6st/qGYusgxkqhfk2AT58ohnNlUKIyGjCCPy+TWFkN6xkONHd3VtMHx8DTbV3Z5r3RXrWFZ5sVnKujUaHsGzezZJBwt3a7dKj6AJOr0sJ8Yc2ljx+hok2dOKoGRxhJIu9fJACZyWuyDciV3dEJlxXTI7Vk1AOv4x+bCwi16iigRBBnVUyCHCyVpVA1R5cSrNhWQC0cvb8g8wQVXbP7dECvfMnnFDqPWvvOLfBn68Q0z/xIMC7PhIIByljq09JFFGYDH37DxMQC46qI3COr50PPBr6DXl5zQqQ4+jOzPLQNkZrIRcsfBoIhh88GL16IK4m Csunuu/u cDTMNy7ED4MpfIFI9NC7aB2RfrpqhWqoKJPjBKdQaBblZpftPLLs2YeDZumHlgDNZnYov0R2uhbBNn5Sh2alvRCAEcJBxilgFK3ZACoQeIb76qF4ugHJQ9hdX7SXP+prlEg2ES50rxHqfiIRNyaN6T1IxoW4GNPzDO/oc6Z0/Xg6A1OhOzMtUk7e+aJHrDFfSv+OlcQOhfQirLERmhn7XnzMSQx5Ndu55rn9MrjakR0JNgE0zLWWSyq9AO0egSA4KzeJ3GznMny1aWp8EbzCyw7qni8Vd2kDZHYky0RX3YZ/N2v5oq0P+zidjSXeMnskCVHLvHfZoIE1JZBliA8HjXXMftE5KduTPepeC3jQP5s0vQjP1JtstMCtaR2LEaEOqnBkif8OcI+hm1oC8Eb9ABFhY2ldqxAvrezwIuir4D0E8bX8owDpAwmC5ZrisjGSHF5dEgo2FQJSYa8nO6VTNJXeZ/Pey6h244DnkGVVRTAby3McdFgHSGXGjAQ== 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: On Fri, Jul 26, 2024 at 05:05:55PM +0100, shiju.jose@huawei.com wrote: > From: Shiju Jose > > Memory ACPI RAS2 driver binds to the platform device add by the s/add/added/ > 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/scrub/edac-scrub.rst | 41 +++ > drivers/ras/Kconfig | 10 + > drivers/ras/Makefile | 1 + > drivers/ras/acpi_ras2.c | 415 +++++++++++++++++++++++++++++ > 4 files changed, 467 insertions(+) > create mode 100644 drivers/ras/acpi_ras2.c > > diff --git a/Documentation/scrub/edac-scrub.rst b/Documentation/scrub/edac-scrub.rst > index 7815d674f496..348f98091ac1 100644 > --- a/Documentation/scrub/edac-scrub.rst > +++ b/Documentation/scrub/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 > +1 > +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/max_cycle_duration > +24 > +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration > +10 > +root@localhost:~# echo 15 > /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 > +15 > +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 > +1 > +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/max_cycle_duration > +24 > +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/scrub/current_cycle_duration > +10 > +root@localhost:~# cat /sys/bus/edac/devices/acpi_ras2_mem0/enable_background > +0 > +root@localhost:~# echo 3 > /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 > +3 > +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..b2381d5b37d0 > --- /dev/null > +++ b/drivers/ras/acpi_ras2.c > @@ -0,0 +1,415 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * ACPI RAS2 memory driver > + * > + * Copyright (c) 2024 HiSilicon Limited. > + * > + */ > + > +#define pr_fmt(fmt) "MEMORY ACPI RAS2: " fmt > + > +#include > +#include > +#include > + > +#define RAS2_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 > + > +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_secs = 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; > + > + 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; > + > + 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_secs; > + > + return 0; > +} > + > +static int ras2_hw_scrub_cycle_write(struct device *dev, void *drv_data, > + u32 scrub_cycle_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_secs < ras2_ctx->min_scrub_cycle || > + scrub_cycle_secs > ras2_ctx->max_scrub_cycle) > + return -EINVAL; > + > + ras2_ctx->scrub_cycle_secs = scrub_cycle_secs; > + > + 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 enabled; > + 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, &enabled); We have a passed-in argument "enable", we have another local variable "enabled", will "running" be more accurate instead of "enabled"? The same as in ras2_hw_scrub_set_enabled_od() Fan > + if (ret) > + return ret; > + if (enable) { > + if (ras2_ctx->bg || enabled) > + 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_secs); > + ps_sm->params.patrol_scrub_command = RAS2_START_PATROL_SCRUBBER; > + } else { > + if (!ras2_ctx->bg) > + return -EPERM; > + if (!ras2_ctx->bg && enabled) > + 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, "%s: failed to enable(%d) background scrubbing\n", > + __func__, enable); Similar suggestion as below. > + 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 enabled; > + 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, &enabled); > + 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 (enabled) > + 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_secs); > + 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 (!enabled) > + 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 enable(%d) the demand scrubbing\n", enable); Can we improve the messaging as below to make it clearer? dev_err(ras2_ctx->dev, "failed to %s the demand scrubbing\n", enable ? "enable":"disable"); Fan > + 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 int ras2_hw_scrub_get_name(struct device *dev, void *drv_data, char *name) > +{ > + struct ras2_scrub_ctx *ras2_ctx = drv_data; > + > + return sysfs_emit(name, "acpi_ras2_mem%d_scrub\n", ras2_ctx->id); > +} > + > +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, > + .get_name = ras2_hw_scrub_get_name, > + .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_ras_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_ras_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"); > -- > 2.34.1 >