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 547EBC3DA59 for ; Fri, 19 Jul 2024 18:43:31 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id AB27D6B0082; Fri, 19 Jul 2024 14:43:30 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id A62526B0083; Fri, 19 Jul 2024 14:43:30 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 902976B0088; Fri, 19 Jul 2024 14:43:30 -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 6D1246B0082 for ; Fri, 19 Jul 2024 14:43:30 -0400 (EDT) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id AFE811208CC for ; Fri, 19 Jul 2024 18:43:29 +0000 (UTC) X-FDA: 82357375338.01.A449657 Received: from mail-pf1-f175.google.com (mail-pf1-f175.google.com [209.85.210.175]) by imf30.hostedemail.com (Postfix) with ESMTP id C25A580005 for ; Fri, 19 Jul 2024 18:43:26 +0000 (UTC) Authentication-Results: imf30.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=nPCAS42s; spf=pass (imf30.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.210.175 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=1721414564; 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=9ksl0r9CZ72zWVwuRHRRlhsOPiNmz7I0PeyEzWPG0ok=; b=yXvjZV/Lr+fLibQAhVu0qbL/ywEkO1JAQZfkt2NLhiyrVhfVxnUTY3gK3d9KMxjj01Hnl7 YhwIzZqvY9+scCXVBp6XnzRX2YkeDHVyomgofoNXfroLPUgvqRMmmyrTn2GrirmQtQfBlM +1wi6H5FyJKmSjtKG6h39i57oyV2zDw= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1721414564; a=rsa-sha256; cv=none; b=4EWUW1spowLOfBp70NHUebjz1kStOIBe0dTBaU+6zcF9+e1U8gBwakahxlHKePkK3usqnc osPFmhkxL6lWdtp2aye6JvUG3u7DAjIZcSft44zvlDGRBnclbaVp3Dejvdf5tLQ2bQ+PXV HayW1iRPQ9sRDRgEAHr035Xizee6EME= ARC-Authentication-Results: i=1; imf30.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=nPCAS42s; spf=pass (imf30.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.210.175 as permitted sender) smtp.mailfrom=nifan.cxl@gmail.com; dmarc=pass (policy=none) header.from=gmail.com Received: by mail-pf1-f175.google.com with SMTP id d2e1a72fcca58-70b4267ccfcso911641b3a.3 for ; Fri, 19 Jul 2024 11:43:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1721414605; x=1722019405; 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=9ksl0r9CZ72zWVwuRHRRlhsOPiNmz7I0PeyEzWPG0ok=; b=nPCAS42sKgfcBVyjDcuTMrOU/4TTna/jb7VFKuDnvoJFiYUheFvV4sbgqz7aTctV7T 1BPMvN0/VBlh8ijRiYuBhz40/AaQm/PUrUlOIjYihuTl1N2b3Xr0GqHa/HlbIta0Y4Ge NVCeuu7w66eAA6zDYaVrfCh6WO1UbLxBSMUfb3w1bA2inHNz06meGA5jxYLc/0c6iQGO XGpXa4AWS6XUQFeXSz4hxhsINr+9I7h978CiPoCek8h9jp4H7Wn7hZbBl0m0ZPnqMjmK sHfMwGNHyDyRTX6hx/SLbdSghbIy/rPLI30NtjghZclsBAHSS7jcAl1kIIdAv6h8BSH+ e2Cw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721414605; x=1722019405; 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=9ksl0r9CZ72zWVwuRHRRlhsOPiNmz7I0PeyEzWPG0ok=; b=jzm/+sMXmwdEL0Q6gktqPYIV5PmH0Br1hrI0xQQiYJTFHKoxP82wzQ3R8vRDPy0CFL dydEgVYPXaxhP1rDd37NWpWtHJntFziY+TP8Pm5dpDj9OeT3ldwArbmuFro1P0EU/KHj LVbaaWhn9+Tbxzr1zg8QMirktLdAkHGeW3t2C3FJ4E0lYJ+zIp1xv7/9DVb/aUYJip1j IieQtqUTTbhLsXYIci07eWVAsb1SpawM4PNzpNjtWUgbgIj1+NEeAXfICkhJS8HfJrVT pFQJVOztnKSHFiK3zjNXHIEOHS4MOApoELgYjLa1Jj5mgCUGqSTk+wxwEr9P5FoLq4g5 JXpQ== X-Forwarded-Encrypted: i=1; AJvYcCUwkT6fQ10Bxe/DwLPB03l7eNxGLvtJi4K6jF5x/nEynjdrdsZdtuNl31ezQcynyi7HbfedvnmW6FTk1BPhcoIMvq0= X-Gm-Message-State: AOJu0Yw6vcb6EQRpEyztk51JXuMrwCexB3X5Drbd2YamVERcWELr0wUo Mab79FTtYrPkhBFLyQZcHnmh3Ctt2cDS7pH++ZKtqPYSb9AsgN3T X-Google-Smtp-Source: AGHT+IF4jBurPQ43jlcuXJ1lkHKfqgHilWGPcN1XXaq1uTTlU2xKFSddeNcpR+3dxoUPoTYOQnTopw== X-Received: by 2002:a05:6a20:a11e:b0:1bd:253e:28e with SMTP id adf61e73a8af0-1c3fdc962c8mr11541516637.16.1721414605167; Fri, 19 Jul 2024 11:43:25 -0700 (PDT) Received: from gpd ([2601:646:8f03:9fee:d888:5d2b:51bf:885e]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1fd6f31bd9bsm7932015ad.157.2024.07.19.11.43.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 19 Jul 2024 11:43:24 -0700 (PDT) From: fan X-Google-Original-From: fan Date: Fri, 19 Jul 2024 11:43:02 -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: [RFC PATCH v9 08/11] cxl/memscrub: Add CXL memory device ECS control feature Message-ID: References: <20240716150336.2042-1-shiju.jose@huawei.com> <20240716150336.2042-9-shiju.jose@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20240716150336.2042-9-shiju.jose@huawei.com> X-Rspam-User: X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: C25A580005 X-Stat-Signature: 99f9eiffqgdc4ncix57tyd4tiyp6goor X-HE-Tag: 1721414606-594719 X-HE-Meta: U2FsdGVkX1/if0sp1uL0M6ocyOn9IzrWW/epK7jefaX8VWJoejaVD9Pl6c+mvjd2EFJKwRAJqNvAaHbzcLFvQNW/Ms9BCMWh0PYYTiuupqx2AY0hn6g88swYxaSqcOiCKv5nHQuqVi0WdcGwsJ9KmbzaURgJAzMfixrxUWRnPvaWGJ55RJBftZUhyTNXjXMLngn/wCwVTzkvd1j3SPSLHfYb9iAgnMiAHl0aNH/22qMYHLpLLdupDIR80xHDGHhYfbSr4aY09R1Dx5xPbyPGXyoeO+yeEH6L+3OM+dJ6XyEaUOY67X/wdwPZcwkfS7mzMW+/BaJp+bvwkKu/LaxCvbzdWvOG6+pfJVq5dilZqz1H8ICmbIWTQs0+aL88cLvf6SNFepnmeVNLYYrZyAjOYYooW0sJyl/i2UB0SPjyfzePQuXjnTMpN6yDHbS3or/sYyEGjfyVQMGi25yBCVd3O/QWa918FzqZWL38oEFicabrwUAMn4y297uG9bPjSwKFcZgRYI/XHtnnnm3joJx4b/DUZWIGNh+SUvT4vYlCmX2AoFoyV1KbiNCElcJww6BH2fR+Zo1RmmqJNbpdO/w7qFGWN25E/Rag6SEHh0K30Cxjsex0EQ6nOeFpSLIFvKmsPRmFMR9AuB8MUOuui505G6kuPOlUr0iCo/4q0uHHYRuyuAnk6kxf3hQM1YQN5QqbbHzWoQa7u0UtYRhaKduTl26kInLnxMrLmhOSMfTJETaWSKr7m/ZBJwmGIR0mRiKt0f5qFTsq4ty+L5BK9RNqwwIki1JzkoTxdPz2cxVDrUMAczS0usqWPLTBJR9IRsZQcYZlcbcHooxY3C/FmUZ590Y7GBDgj7mRUWgjDcq9hi5ZFEM2QT0LWyZtyiWyDcU2AsUm3p/iK9/WpzCko+nAE4YMuO2aK2WBOxVr6rRMj37VkdxFeZpgqo4h8PQAi3DZnO2Rv1xHsii7xWbnlt9 faE3b2rD GdX1GQOkbx5YPndQpmIFZ94S5WYbxK93HG2+ZXokZSrDvSnr54UP8UkafD+KYdruO0SxUq66BD/a0D2XkV/bDXS6x3V8zTM5pRWpHmoJ87o2/TbMPjEZkXByqVMfrNPSvyh9fRKSuytwDpoJNZUtIpWI2xXgghZ++naV3/1kbuJNLxxzXq7ml0+fr/Ge2b4JFel0cazSrji5JC6KgcHgsGd1OaTW1EwNn+mNVgRXTJFF6PRhWrKXKO9GJykVGWvPJ8FKkwihT0y1yDdgHVhyPbDcjY9CktXoQfMfo5up7Vrme3GRfQbs+HSY56CVkYHM9MAmyoPUCiGBpYhd+cO3Cxexuer+s9oNF3l5PRrWUlXneXwBWBEKrENmL4NnMEhynwo61JI2W9v3BFZoI4ZjZSiuEN5+oPYxJr3yKqEwqsC1Ghj9t2EhJ2S5FDvoLWHvUAwMxKE2B1wo/8DOhXmkipoWX7H3PpQTmioUB1K3JZVJOgHtMy9mC4qOWL1o8nTc7GAx3ImP1cj43OV13sYqqr6uBKXzYd2FQIhuQ 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 Tue, Jul 16, 2024 at 04:03:32PM +0100, shiju.jose@huawei.com wrote: > From: Shiju Jose > > CXL spec 3.1 section 8.2.9.9.11.2 describes the DDR5 Error Check > Scrub (ECS) 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/ > > Note: The documentation can be added if necessary. > > Signed-off-by: Shiju Jose > --- Some lines are too long. And some other comments inline. > drivers/cxl/core/memscrub.c | 429 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 429 insertions(+) > > diff --git a/drivers/cxl/core/memscrub.c b/drivers/cxl/core/memscrub.c > index 430f85b01f6c..9be230ea989a 100644 > --- a/drivers/cxl/core/memscrub.c > +++ b/drivers/cxl/core/memscrub.c > @@ -351,13 +351,411 @@ static const struct edac_scrub_ops cxl_ps_scrub_ops = { > .cycle_in_hours_range = cxl_patrol_scrub_read_scrub_cycle_hrs_range, > }; > > +/* CXL DDR5 ECS control definitions */ > +#define CXL_MEMDEV_ECS_GET_FEAT_VERSION 0x01 > +#define CXL_MEMDEV_ECS_SET_FEAT_VERSION 0x01 > + > +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; > + struct cxl_memdev *cxlmd; > +}; > + > +/** > + * 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; > + u8 mode; An enum is defined below, why not directly use enum type here? > + bool reset_counter; > +}; > + > +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 { > + ECS_MODE_COUNTS_ROWS = 0, > + ECS_MODE_COUNTS_CODEWORDS = 1, > +}; > + > +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, rd_attrs, > + rd_data_size, CXL_GET_FEAT_SEL_CURRENT_VALUE); > + 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, rd_attrs, > + rd_data_size, CXL_GET_FEAT_SEL_CURRENT_VALUE); > + 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_MEMDEV_ECS_SET_FEAT_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, u64 *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, u64 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, u64 *val) I may have missed something. We have cxl_ecs_get_log_entry_type, and what is cxl_ecs_get_log_entry_type_per_memory_media and cxl_ecs_get_log_entry_type_per_dram for? > +{ > + 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, u64 *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, u64 *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, u64 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, u64 *val) As above, what is cxl_ecs_get_mode_counts_codewords and cxl_ecs_get_mode_counts_rows for? Fan > +{ > + 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, u64 *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, u64 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, u64 *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, u64 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 int cxl_ecs_get_name(struct device *dev, void *drv_data, int fru_id, char *name) > +{ > + struct cxl_ecs_context *cxl_ecs_ctx = drv_data; > + struct cxl_memdev *cxlmd = cxl_ecs_ctx->cxlmd; > + > + return sysfs_emit(name, "cxl_%s_ecs_fru%d\n", dev_name(&cxlmd->dev), fru_id); > +} > + > +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, > + .get_name = cxl_ecs_get_name, > +}; > + > int cxl_mem_ras_features_init(struct cxl_memdev *cxlmd, struct cxl_region *cxlr) > { > struct edac_ras_feature ras_features[CXL_DEV_NUM_RAS_FEATURES]; > 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; > @@ -407,6 +805,37 @@ 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_mem_get_supported_feature_entry(cxlmd, &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, > + .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_ras_dev_register(&cxlmd->dev, cxl_dev_name, NULL, > num_ras_features, ras_features); > } > -- > 2.34.1 >