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 D69F1C4345F for ; Wed, 24 Apr 2024 20:26:13 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 3A8F88D002D; Wed, 24 Apr 2024 16:26:13 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 358058D002C; Wed, 24 Apr 2024 16:26:13 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 1AB868D002D; Wed, 24 Apr 2024 16:26:13 -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 E7B768D002C for ; Wed, 24 Apr 2024 16:26:12 -0400 (EDT) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 4E67F1C16D3 for ; Wed, 24 Apr 2024 20:26:12 +0000 (UTC) X-FDA: 82045557384.18.77C828B Received: from mail-oa1-f50.google.com (mail-oa1-f50.google.com [209.85.160.50]) by imf20.hostedemail.com (Postfix) with ESMTP id 6F67C1C0006 for ; Wed, 24 Apr 2024 20:26:10 +0000 (UTC) Authentication-Results: imf20.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=jivegFvQ; spf=pass (imf20.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.160.50 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=1713990370; 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=incol+l1cttU80jXk2nqyGIlECdYg5DlgRh3ZAraHcI=; b=s8EV+ZXSBEvDt+JFUtx7gxJJjogu4HsdHYRL41tqyKvk1vrRhS642eVAmu3CNSoHD9MB6X 9SifZ+5wQs63VvWaiioBV6oewL/uhuGfxrml1MgkJ5xJgCh8a8MrZTCBm4Pm+Y4NG8yV58 LbtbbqQM3hpMMGfJemR/HucpLk9i0hE= ARC-Authentication-Results: i=1; imf20.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=jivegFvQ; spf=pass (imf20.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.160.50 as permitted sender) smtp.mailfrom=nifan.cxl@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1713990370; a=rsa-sha256; cv=none; b=I9SzuN/aRQP89jibQyfKtBb8eWxBSBaX/9Dmd0CZUNT0mPaahsde9YdkyXkRIpOV4gtlK1 DPrxkDESO5wo6m3KV4amz1wsl4qkohSt76aMEjvgMYq2k/GG1VHPcJfG2C1fsYA/YlwWz2 vwjndKAlFCH3WEQRrR1pIwLh1DW4yIs= Received: by mail-oa1-f50.google.com with SMTP id 586e51a60fabf-23333dddd8aso228915fac.1 for ; Wed, 24 Apr 2024 13:26:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1713990369; x=1714595169; 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=incol+l1cttU80jXk2nqyGIlECdYg5DlgRh3ZAraHcI=; b=jivegFvQ8x7GREmTttjV4yOIbM3q64gIWmMyw8CTL8HH1K+YWCdMSbc3llDAsr5jJx o64hUJRRcPBeoKZOjIWwy5BBWh6yd3H4xJF2khKkluyFxvo3ifSvfLnMQtCxogWp812t 5ojMVrde9bgFRaGXyAidRcKLS8/G9pPdCVDle3EpKECws24RuDdK3gjfu0JLswGnNnSC LnH0RTFhJGgGj5GRMRJx9PKw5uK0KxJr51cUtqhMl1+7rdEO0RokU2L3U0B89PdyWQDd sAoSISk88lWB/n/SsDLfdF9Z5ZDCBy8UGfPaJfFW+uS1hl+KnfWKS8anRHDlodGHCdjC KvBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1713990369; x=1714595169; 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=incol+l1cttU80jXk2nqyGIlECdYg5DlgRh3ZAraHcI=; b=NrkH5rAf6YvMLOgvj4xsmRxm18mR6dntTgmZa7yObFel5XrV0AWNwgaTYZK0/Ha+SP cx3PCGVb36Z4PPc78LAfTigllGXx25OsGXS+nJlSI7zfE9BIbmAU6s26JZZhoVyFhzIr Ddo9Rc7bi/2ay0re6+mDoEeUt6/qUyBivXYSvECVtvd6NB4sVPDXEd6sIriisvB/LhyE 8ymQX3ynjlXEyCke1YrJ92APPwDCTASXh7f010a9KAPUvb4AQLqDxZxEt4k2MNV/83BK /ZeYkXMT9rooJJKzL9ZSrmmhvkykEvs7drHzt5ukssw6PCEkZHZZYRbZTIunoKJXnsfH traQ== X-Forwarded-Encrypted: i=1; AJvYcCUNWEzA3v2ily8B7GHNG9GpN+94HG6a1YRwLkXt1tNS1I3FIPYuqqdZ/1YYRUii+o+s4A75TtImaXQtBUyIhuEdS90= X-Gm-Message-State: AOJu0YzS01wv9/ThMj66M9fKXfi5CKOmUUX0F/LBJ2vJZyRgWA5EfUJK xx9T/JETDY1sgPq4r5/Y4p3GLTzb9GdabsZCzvRPlLiLXSuoT32S X-Google-Smtp-Source: AGHT+IFhXCtEEypDPb+KRK/ZNKaDwjojMo4l1m6xexhGZqfv+stKhOGdYK5rdm1vBXBnystoX42XUQ== X-Received: by 2002:a05:6870:e245:b0:233:b5dd:471c with SMTP id d5-20020a056870e24500b00233b5dd471cmr3861498oac.51.1713990369274; Wed, 24 Apr 2024 13:26:09 -0700 (PDT) Received: from debian ([2601:641:300:14de:b318:9476:706a:e82a]) by smtp.gmail.com with ESMTPSA id p5-20020a634f45000000b005f05c88c149sm11622926pgl.71.2024.04.24.13.25.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Apr 2024 13:26:08 -0700 (PDT) From: fan X-Google-Original-From: fan Date: Wed, 24 Apr 2024 13:25:52 -0700 To: shiju.jose@huawei.com Cc: linux-cxl@vger.kernel.org, linux-acpi@vger.kernel.org, linux-mm@kvack.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, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, david@redhat.com, Vilas.Sridharan@amd.com, leo.duran@amd.com, Yazen.Ghannam@amd.com, rientjes@google.com, jiaqiyan@google.com, tony.luck@intel.com, Jon.Grimm@amd.com, dave.hansen@linux.intel.com, rafael@kernel.org, lenb@kernel.org, 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, kangkang.shen@futurewei.com, wanghuiqiang@huawei.com, linuxarm@huawei.com Subject: Re: [RFC PATCH v8 01/10] ras: scrub: Add scrub subsystem Message-ID: References: <20240419164720.1765-1-shiju.jose@huawei.com> <20240419164720.1765-2-shiju.jose@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20240419164720.1765-2-shiju.jose@huawei.com> X-Stat-Signature: 3o8o9huwy3pmnak1gx7fj5zjnotdjmiw X-Rspamd-Queue-Id: 6F67C1C0006 X-Rspamd-Server: rspam10 X-Rspam-User: X-HE-Tag: 1713990370-777339 X-HE-Meta: U2FsdGVkX19aAuK2TNJxiJaTOesqsUEz9jbzSyv8lQ8l1+i4IIbU6wFbKakiUAy8Wu0eYZoLHxSWPIymq8GhbS1ZmCXDVFPYbJVDjZefQxswZk6MRCtFiXQEjYUnog+dks3iaYsl/otWH2Uzv98/0LQ/8ByGvBEV+/fVHi5nyLrVLFxxcEXqO66lmsVBnM2LigEyRHq9SQcki8YVnsHtYTmJYoncj+8GkiYs7SStSLbeecak6InUrYQfFAVDZngzFEtZXI3KQyk1Oxz1o2SOkzUVFmQntDa1LCtsO8NqucHmkq/seCXwbeMSv51CPC5Dgh1ZEcZ6WcY6MzRDmorBBJdosJefLNGqeCI7iak2sjMvr5kjiV8AQSlEhjGVrRCiHTH3rLsSgaLfmgwagqNpJpBhcgPEt8BqRQ5etO/QJiisn0dmFmJCl9kAbourpSad6kDvCvki/bCMIKgfrbrOzrMeOvFLc6BXfkI8TYA3hBXvTuMQ4ox5Kc+2lkTdHaWQloJcQ6ukQYta1ZSubsvBAlyZNTBJa+LMClGhxt96ApxzvnVSwxSUFDC+0bZcL+/6M7RjfOtagh8Os6oiRC0Ii7Cbw2gNj7K0iXKtctizRnkKLe+F1AePQ69gixwprfu1SPPNbSAPQoELJN8f/nu7H6lp+5WQTThlJPOpyNKcY20GQelq89va0WBLlFyEbMvkKzgb6Te3XoMA57yS4OdGwmicW4s3clpK8edDog52zJH0Hsrwb3TwrLtk68+d6FbyTGk93z8bb7fbhCJCM3GEswiIetChc+Li4umW0Nm0o+cA/NL+/B8yvC4WETlPvdQYoGh5FmZfrEVmH13lg9PN7WAhnPJa63Opa3bOghgab9KRyU5kY+T1VvAIRI4DXY+CipDu8hJUII0eMsa5R8Yd8K6LhSnvqyaCXHT5JrQQAX6wtzyqF/Dg/pBcDCndxXip9UtpHEMrk85DuJfLNMj A6a0Nu7e 2EyTVU6TGV+vM+mdSFdCeLlh4EYexX85t2BGHV5k2cZ0D+Ht02NKiV2+FTGfwaZsECqRV3lTQed+gd1N9Wd6zMA+eAfEYdp4AfNANT4UjrTyAd+taEF2JuCGSeiB/seLKrT7QSF4vqNQN4/mpdk1v9e1xoiAzU/rxhkK8A8u/uDsyoKU7t7N2HFM6MOyrjwqhL5ckGafGwlbQCWNwHZkMAoh1lNUBsVaiL8bGpuZWCk4lqaVbTi/eNDvJZAXBnTvM4yI4x4mdKcCD+R+BMGRI3SwZwoMXhjeLTNrO9sifuckZSAvp+6qvDpEU5CYaQCoynA1vzlHDlC6e3zRBFTzQAwYSDkcJUp0W3Tn/ZReyq+grjGEeeY8UkcNpMrCezBUQh65LtJ7K4O8nmlIAu0PLPlsw47AMuGejc1JKuy6LpYAHu3I5G7mDht0Ca+X9PivbXV1nQJ1nRz4jMvVqKp1xC9ChG14ZJXdX9nwMfu16ZdWmvMtl6vCBjfL98TDHgL8nqxJJZSzmMh1EKJBvUbderKp8YDR+/XpfIfU3g+WRX0Ca+KDl+pwaT86n+vfgD6D8VEEl47QJv0XveW9hoMmScDZhO1IPFjrQmB30Dvmu67vxfrjl1OH7up68hqAzp9X0B2YJ32SgqYNbCZQfUWiQs7l3eQ== 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 Sat, Apr 20, 2024 at 12:47:10AM +0800, shiju.jose@huawei.com wrote: > From: Shiju Jose > > Add scrub subsystem supports configuring the memory scrubbers > in the system. The scrub subsystem provides the interface for > registering the scrub devices. The scrub control attributes > are provided to the user in /sys/class/ras/rasX/scrub > > Co-developed-by: Jonathan Cameron > Signed-off-by: Jonathan Cameron > Signed-off-by: Shiju Jose > --- > .../ABI/testing/sysfs-class-scrub-configure | 47 +++ > drivers/ras/Kconfig | 7 + > drivers/ras/Makefile | 1 + > drivers/ras/memory_scrub.c | 271 ++++++++++++++++++ > include/linux/memory_scrub.h | 37 +++ > 5 files changed, 363 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-class-scrub-configure > create mode 100755 drivers/ras/memory_scrub.c > create mode 100755 include/linux/memory_scrub.h > > diff --git a/Documentation/ABI/testing/sysfs-class-scrub-configure b/Documentation/ABI/testing/sysfs-class-scrub-configure > new file mode 100644 > index 000000000000..3ed77dbb00ad > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-scrub-configure > @@ -0,0 +1,47 @@ > +What: /sys/class/ras/ > +Date: March 2024 > +KernelVersion: 6.9 > +Contact: linux-kernel@vger.kernel.org > +Description: > + The ras/ class subdirectory belongs to the > + common ras features such as scrub subsystem. > + > +What: /sys/class/ras/rasX/scrub/ > +Date: March 2024 > +KernelVersion: 6.9 > +Contact: linux-kernel@vger.kernel.org > +Description: > + The /sys/class/ras/ras{0,1,2,3,...}/scrub directories > + correspond to each scrub device registered with the > + scrub subsystem. > + > +What: /sys/class/ras/rasX/scrub/name > +Date: March 2024 > +KernelVersion: 6.9 > +Contact: linux-kernel@vger.kernel.org > +Description: > + (RO) name of the memory scrubber > + > +What: /sys/class/ras/rasX/scrub/enable_background > +Date: March 2024 > +KernelVersion: 6.9 > +Contact: linux-kernel@vger.kernel.org > +Description: > + (RW) Enable/Disable background(patrol) scrubbing if supported. > + > +What: /sys/class/ras/rasX/scrub/rate_available > +Date: March 2024 > +KernelVersion: 6.9 > +Contact: linux-kernel@vger.kernel.org > +Description: > + (RO) Supported range for the scrub rate by the scrubber. > + The scrub rate represents in hours. > + > +What: /sys/class/ras/rasX/scrub/rate > +Date: March 2024 > +KernelVersion: 6.9 > +Contact: linux-kernel@vger.kernel.org > +Description: > + (RW) The scrub rate specified and it must be with in the > + supported range by the scrubber. > + The scrub rate represents in hours. > diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig > index fc4f4bb94a4c..181701479564 100644 > --- a/drivers/ras/Kconfig > +++ b/drivers/ras/Kconfig > @@ -46,4 +46,11 @@ config RAS_FMPM > Memory will be retired during boot time and run time depending on > platform-specific policies. > > +config SCRUB > + tristate "Memory scrub driver" > + help > + This option selects the memory scrub subsystem, supports > + configuring the parameters of underlying scrubbers in the > + system for the DRAM memories. > + > endif > diff --git a/drivers/ras/Makefile b/drivers/ras/Makefile > index 11f95d59d397..89bcf0d84355 100644 > --- a/drivers/ras/Makefile > +++ b/drivers/ras/Makefile > @@ -2,6 +2,7 @@ > obj-$(CONFIG_RAS) += ras.o > obj-$(CONFIG_DEBUG_FS) += debugfs.o > obj-$(CONFIG_RAS_CEC) += cec.o > +obj-$(CONFIG_SCRUB) += memory_scrub.o > > obj-$(CONFIG_RAS_FMPM) += amd/fmpm.o > obj-y += amd/atl/ > diff --git a/drivers/ras/memory_scrub.c b/drivers/ras/memory_scrub.c > new file mode 100755 > index 000000000000..7e995380ec3a > --- /dev/null > +++ b/drivers/ras/memory_scrub.c > @@ -0,0 +1,271 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Memory scrub subsystem supports configuring the registered > + * memory scrubbers. > + * > + * Copyright (c) 2024 HiSilicon Limited. > + */ > + > +#define pr_fmt(fmt) "MEM SCRUB: " fmt > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* memory scrubber config definitions */ > +#define SCRUB_ID_PREFIX "ras" > +#define SCRUB_ID_FORMAT SCRUB_ID_PREFIX "%d" > + > +static DEFINE_IDA(scrub_ida); > + > +struct scrub_device { > + int id; > + struct device dev; > + const struct scrub_ops *ops; > +}; > + > +#define to_scrub_device(d) container_of(d, struct scrub_device, dev) > +static ssize_t enable_background_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + bool enable; > + int ret; > + > + ret = kstrtobool(buf, &enable); > + if (ret < 0) > + return ret; > + > + ret = scrub_dev->ops->set_enabled_bg(dev, enable); > + if (ret) > + return ret; > + > + return len; > +} > + > +static ssize_t enable_background_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + bool enable; > + int ret; > + > + ret = scrub_dev->ops->get_enabled_bg(dev, &enable); > + if (ret) > + return ret; > + > + return sysfs_emit(buf, "%d\n", enable); > +} > + > +static ssize_t name_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + int ret; > + > + ret = scrub_dev->ops->get_name(dev, buf); > + if (ret) > + return ret; > + > + return strlen(buf); > +} > + > +static ssize_t rate_show(struct device *dev, struct device_attribute *attr, > + char *buf) > +{ > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + u64 val; > + int ret; > + > + ret = scrub_dev->ops->rate_read(dev, &val); > + if (ret) > + return ret; > + > + return sysfs_emit(buf, "0x%llx\n", val); > +} > + > +static ssize_t rate_store(struct device *dev, struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + long val; > + int ret; > + > + ret = kstrtol(buf, 10, &val); > + if (ret < 0) > + return ret; > + > + ret = scrub_dev->ops->rate_write(dev, val); > + if (ret) > + return ret; > + > + return len; > +} > + > +static ssize_t rate_available_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + u64 min_sr, max_sr; > + int ret; > + > + ret = scrub_dev->ops->rate_avail_range(dev, &min_sr, &max_sr); > + if (ret) > + return ret; > + > + return sysfs_emit(buf, "0x%llx-0x%llx\n", min_sr, max_sr); > +} > + > +DEVICE_ATTR_RW(enable_background); > +DEVICE_ATTR_RO(name); > +DEVICE_ATTR_RW(rate); > +DEVICE_ATTR_RO(rate_available); > + > +static struct attribute *scrub_attrs[] = { > + &dev_attr_enable_background.attr, > + &dev_attr_name.attr, > + &dev_attr_rate.attr, > + &dev_attr_rate_available.attr, > + NULL > +}; > + > +static umode_t scrub_attr_visible(struct kobject *kobj, > + struct attribute *a, int attr_id) > +{ > + struct device *dev = kobj_to_dev(kobj); > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + const struct scrub_ops *ops = scrub_dev->ops; > + > + if (a == &dev_attr_enable_background.attr) { > + if (ops->set_enabled_bg && ops->get_enabled_bg) > + return a->mode; > + if (ops->get_enabled_bg) > + return 0444; > + return 0; > + } > + if (a == &dev_attr_name.attr) > + return ops->get_name ? a->mode : 0; > + if (a == &dev_attr_rate_available.attr) > + return ops->rate_avail_range ? a->mode : 0; > + if (a == &dev_attr_rate.attr) { /* Write only makes little sense */ > + if (ops->rate_read && ops->rate_write) > + return a->mode; > + if (ops->rate_read) > + return 0444; > + return 0; > + } > + > + return 0; > +} > + > +static const struct attribute_group scrub_attr_group = { > + .name = "scrub", > + .attrs = scrub_attrs, > + .is_visible = scrub_attr_visible, > +}; > + > +static const struct attribute_group *scrub_attr_groups[] = { > + &scrub_attr_group, > + NULL > +}; > + > +static void scrub_dev_release(struct device *dev) > +{ > + struct scrub_device *scrub_dev = to_scrub_device(dev); > + > + ida_free(&scrub_ida, scrub_dev->id); > + kfree(scrub_dev); > +} > + > +static struct class scrub_class = { > + .name = "ras", > + .dev_groups = scrub_attr_groups, > + .dev_release = scrub_dev_release, > +}; > + > +static struct device * > +scrub_device_register(struct device *parent, void *drvdata, > + const struct scrub_ops *ops) > +{ > + struct scrub_device *scrub_dev; > + struct device *hdev; > + int err; > + > + scrub_dev = kzalloc(sizeof(*scrub_dev), GFP_KERNEL); > + if (!scrub_dev) > + return ERR_PTR(-ENOMEM); > + hdev = &scrub_dev->dev; > + > + scrub_dev->id = ida_alloc(&scrub_ida, GFP_KERNEL); > + if (scrub_dev->id < 0) { > + kfree(scrub_dev); > + return ERR_PTR(-ENOMEM); > + } > + > + scrub_dev->ops = ops; > + hdev->class = &scrub_class; > + hdev->parent = parent; > + dev_set_drvdata(hdev, drvdata); > + dev_set_name(hdev, SCRUB_ID_FORMAT, scrub_dev->id); Need to check the return value of dev_set_name? fan > + err = device_register(hdev); > + if (err) { > + put_device(hdev); > + return ERR_PTR(err); > + } > + > + return hdev; > +} > + > +static void devm_scrub_release(void *dev) > +{ > + device_unregister(dev); > +} > + > +/** > + * devm_scrub_device_register - register scrubber device > + * @dev: the parent device > + * @drvdata: driver data to attach to the scrub device > + * @ops: pointer to scrub_ops structure (optional) > + * > + * Returns the pointer to the new device on success, ERR_PTR() otherwise. > + * The new device would be automatically unregistered with the parent device. > + */ > +struct device * > +devm_scrub_device_register(struct device *dev, void *drvdata, > + const struct scrub_ops *ops) > +{ > + struct device *hdev; > + int ret; > + > + if (!dev) > + return ERR_PTR(-EINVAL); > + > + hdev = scrub_device_register(dev, drvdata, ops); > + if (IS_ERR(hdev)) > + return hdev; > + > + ret = devm_add_action_or_reset(dev, devm_scrub_release, hdev); > + if (ret) > + return ERR_PTR(ret); > + > + return hdev; > +} > +EXPORT_SYMBOL_GPL(devm_scrub_device_register); > + > +static int __init memory_scrub_control_init(void) > +{ > + return class_register(&scrub_class); > +} > +subsys_initcall(memory_scrub_control_init); > + > +static void memory_scrub_control_exit(void) > +{ > + class_unregister(&scrub_class); > +} > +module_exit(memory_scrub_control_exit); > diff --git a/include/linux/memory_scrub.h b/include/linux/memory_scrub.h > new file mode 100755 > index 000000000000..f0e1657a5072 > --- /dev/null > +++ b/include/linux/memory_scrub.h > @@ -0,0 +1,37 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Memory scrub subsystem driver supports controlling > + * the memory scrubbers in the system. > + * > + * Copyright (c) 2024 HiSilicon Limited. > + */ > + > +#ifndef __MEMORY_SCRUB_H > +#define __MEMORY_SCRUB_H > + > +#include > + > +struct device; > + > +/** > + * struct scrub_ops - scrub device operations (all elements optional) > + * @get_enabled_bg: check if currently performing background scrub. > + * @set_enabled_bg: start or stop a bg-scrub. > + * @get_name: get the memory scrubber name. > + * @rate_avail_range: retrieve limits on supported rates. > + * @rate_read: read the scrub rate > + * @rate_write: set the scrub rate > + */ > +struct scrub_ops { > + int (*get_enabled_bg)(struct device *dev, bool *enable); > + int (*set_enabled_bg)(struct device *dev, bool enable); > + int (*get_name)(struct device *dev, char *buf); > + int (*rate_avail_range)(struct device *dev, u64 *min, u64 *max); > + int (*rate_read)(struct device *dev, u64 *rate); > + int (*rate_write)(struct device *dev, u64 rate); > +}; > + > +struct device * > +devm_scrub_device_register(struct device *dev, void *drvdata, > + const struct scrub_ops *ops); > +#endif /* __MEMORY_SCRUB_H */ > -- > 2.34.1 >