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 D6846C282D1 for ; Fri, 7 Mar 2025 02:46:59 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 1E9BF280002; Thu, 6 Mar 2025 21:46:58 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 199E7280001; Thu, 6 Mar 2025 21:46:58 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 03ACA280002; Thu, 6 Mar 2025 21:46:57 -0500 (EST) 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 D7C2F280001 for ; Thu, 6 Mar 2025 21:46:57 -0500 (EST) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id B06C6A545D for ; Fri, 7 Mar 2025 02:46:58 +0000 (UTC) X-FDA: 83193217716.01.A67EACA Received: from mail-pl1-f177.google.com (mail-pl1-f177.google.com [209.85.214.177]) by imf15.hostedemail.com (Postfix) with ESMTP id BFF15A0006 for ; Fri, 7 Mar 2025 02:46:56 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=PzCbC6i3; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf15.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.214.177 as permitted sender) smtp.mailfrom=nifan.cxl@gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1741315616; 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=e2QEuerNx36Ve8h38j5UuGqNQVWgLdwOZn9+FhlFR/8=; b=MisdS44UTZxU8l+7MkFT19A0I08nbVnAQYtBhEvkW1/w1ZwJAJ2tR1EUGlwQ0SHEvnfN/D N3dQ+8V50LP9FjUE5zxWeYfRnFTQSQy4vFlNONAuu51pT4UFKnAPAXcAfE8UqjOXxHHbpl XSdCjr+5w2bcHD7InXelHk9eHFhuDWs= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=PzCbC6i3; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf15.hostedemail.com: domain of nifan.cxl@gmail.com designates 209.85.214.177 as permitted sender) smtp.mailfrom=nifan.cxl@gmail.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1741315616; a=rsa-sha256; cv=none; b=mOlzW84mBjX/o5ddPlxRoo7EviBrSfrrlI5oT8K24tM06KOisJqq0al+jZXHfZ2/PnQKfN 7Bc1mR9hCiHGYEL/O/EqZY/52i0I5IuyH9OGmOh0NlGkm/RZIk1PA9rBkE1tuwDetMb1vg 51AQueRqL7LiB3/9giG1pzklyxcggV8= Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-223378e2b0dso20191715ad.0 for ; Thu, 06 Mar 2025 18:46:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1741315615; x=1741920415; 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=e2QEuerNx36Ve8h38j5UuGqNQVWgLdwOZn9+FhlFR/8=; b=PzCbC6i3/iGcLSQ3HczeLLEXMyI/1ZVm6QRiZOCt7njNMTWzqThcs0eGIpXGs4Wiff PQ2bvQDcKVH2Joc5xZ3aHv4Y/3meb3BR87TjXuKGGv8ixR1NhP5hZgcOoRSRV1Humhv/ eb3duhN4H/BgbhCjqDWbq5/uAXGJQe0OpVTAjdZzXyf+6g0jGvboqrpdmkCZ6mU/QmxH 6HyOt/ZkEeZjRZGw6ib3HejqtRa+nxQK7ROi/geQvjS5OM1CkxPd7y6u78gk7z6klVWi WFFeDHAZfdgTGY60bvK+f4yzakissNEkvw7t1VgCWNCmHqnXwApdARQYHZN43tVmL9Q4 kThQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741315615; x=1741920415; 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=e2QEuerNx36Ve8h38j5UuGqNQVWgLdwOZn9+FhlFR/8=; b=PcPnyfYcN7Pr4l6PChn6EnB5rM7bDqBy2RbyeaBsFEMgV3JTdE69PsHklflIoyQQMx eKvGPxk172Afc5l9s2r1L3u4X0TSykLiNjH7RnDWhGIG1tBT+7dygm6k95mYjCC3atXQ p/9YoqO91X0JE4QJ8WpQq9SxCse145O6OcDNvpQkepWaX3kOV+ZV2xok/u4Pntc8EAzs mfE3NqB6HbKZ/vItHXLw+kdNLn5xvjGpbpKeQSorWtw7wpAV7A9K0ssTdKH0OZ57HrHH 0lBIA900tz3UiYFtGfTkaAakmmfIGDzsjRz+8/d9P0CRNRZIH4lCEjmYDLyuCWd2tZYO cdHQ== X-Forwarded-Encrypted: i=1; AJvYcCXkdKWeW7OH8E6s2En41x6BxOqzCB0vPRp1W3dLpNbez5tBOi3n8Rl+zIHE/b+Ljia3yUk9gqGI2A==@kvack.org X-Gm-Message-State: AOJu0Yw8CxUnKbzdv1YXRtnY89hZsnElrI+VlXzlhxuPd+YM3nbNjCOi yv5ki+yGVqCJVL6IjZ9jeMpAe40tZKW67KAAo8AshCdCF8w51LTW X-Gm-Gg: ASbGncubL23j0ALP+NMNEk1xI8Gj4h6lrmkaGIHsC76dq3GqlOgAE0Qm8xaQNs7nXti yOeevyI+OGXx0xaic70MChG/6C5MaNGbuP891eKB+CYm4Th9Gi/CNqtAXUdehDdX6KB8XmwDwRH FjZ2QjjOIaQqooW4MHeUFYHyalGmmmEBvYc2H78NQkifSE/hmInHll2UxVcGYzPr84Z+XABOFcX MAAVdrmCxXAp79e3Mfi26V6mnawO8VN9TzUeoypL2sSFfB4Ot6lNMSkK7JGoLnKk4I0cVsb0PDN x+u9r4Y8LNq/gBzLmL14oWPXQMMiuw9lUImvD0I= X-Google-Smtp-Source: AGHT+IGGCWc+C20JLK/YSYbgDhPc0LYuDsVUjJzrJtp+CZGL5bkrHLd/Z6KMIm2ETKyJ3Rm5TOz4rg== X-Received: by 2002:a17:902:da82:b0:224:1eab:97b2 with SMTP id d9443c01a7336-22428c120a4mr23605895ad.53.1741315615452; Thu, 06 Mar 2025 18:46:55 -0800 (PST) Received: from debian ([2601:646:8f03:9fee:e44d:748a:50ed:471f]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22410a91c43sm19629325ad.183.2025.03.06.18.46.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Mar 2025 18:46:54 -0800 (PST) From: Fan Ni X-Google-Original-From: Fan Ni Date: Thu, 6 Mar 2025 18:46:38 -0800 To: shiju.jose@huawei.com Cc: linux-cxl@vger.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, linux-edac@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, 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, 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 3/8] cxl/memfeature: Add CXL memory device ECS control feature Message-ID: References: <20250227223816.2036-1-shiju.jose@huawei.com> <20250227223816.2036-4-shiju.jose@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20250227223816.2036-4-shiju.jose@huawei.com> X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: BFF15A0006 X-Rspam-User: X-Stat-Signature: tq1j5jwn5ifpezynxbph4q7oh1pf8gi7 X-HE-Tag: 1741315616-238852 X-HE-Meta: U2FsdGVkX1/STTO81PauxSlqlrYxTnrOKn85+NzmRMSar+RlkaE+VGELPSYhrBhK/2YVxMsUE6L2l4NomIpXvPc8t7Ih5AM/9N3bqMTVLQTOPsU/dcHTj70C0PC3PKAcKKCqExwM68ONszq8dzG3auKrqZQ+y68d1YQCxo+E2Gwvfcy5REoz4gJTCIQ+eNcDJkCyCfzZ5H5G+Hr7JhEvqnembKJDtSXeQP6h+/FpqJ2q3xEyMG20aWr22gzWIzHi7rd0V6ZZAJN50JxC+uQNwBViiGmGdzm2c6CPg4BFweVj2K61D4CooDF2olSi8/oSGrzjAg7sTG1lI73ClvLua/k01SYM6shwBY3CWE0UUl8CRVAUUhlKSwhMnegbF/Wri0dSSNDMAlwGhG74MtzDIfAL98U/ptYryeo3CqIXXu8EoLtaZqK4hfiG8jUS3S8s8Y8YMl0MaRAvrOn9YKSIFdIxKO+0IcAkIdARRNl9CTIkMg3AFLz7EGB18Mx1x5JDqUNSNr4zL9+Tj93JpAWXmoFhWqdb6R1pPni96VHEcjBpxyU0Sc2gdQyOTuvpry3XLGUf1gd6MAPnEDjiuhpaBEhyaE7MjBJ9gkttXjv24J9+7oxxz3x7zbQ+tpLCftSaJaEuJcvwx7h2g34XkLU42ZPKA46SHhobIKoERjTtO7s9Qok8zvvvDAUF1meFkLiTMzKKf93cmj8COKK2Yx8kPMrqlvUR1dcWUJX0WRRB6vySrf4LtymMwMR/IuduneQCD00ZyMNHd4AfzhbuMGRbi7sKTEQOzMySecFdJn5BG/wU36g+7ojKyrz3Hji/wCtEt33/zVlUR3PZyiGe0kKxf2wsp6ojcyllYpfm9f2YWBjDMM9NzavpL8GaoB4qFe3wDYBVhus+SLaEmaWGZBy5q1+MORH/ODzfRq9CgoHjiImYsPHUcdJ3mtzKTJZtp25HowZIdGHNaWtEgzkTBD+ ql7Z8BNe g8YQXeCrgpHvclAKnsMgJvMgXVoHE/g5XrZ0lkQ16gErSJ09fEQQtJ6vFVWpDXdYTmHEd9VZMCs9tCxm4DOp8+wHIkNOE4Pzg3ZzAvwj+UmjUaaOE/UzfzpincB3FbbwRktjAaYEj7bwv77j8WClcam7/wSgkhIu7eBYf//oRDav7knWOn093qiBkdJUqvP3zt9UsHeFUBB5HkY6T/ctig9mS6vpYeSY8pFm/pLn0yN77QKjj4B/EFrXiVRP4spqDkJc/i/mjG5SQO/OaJ+ggXNtS2gdKV05eAPwAZQruHdShlJwMfjLUCNp7UjHZi08Aoz0I6J2qtcuBNiTL7nhyBeHhd30tue3hedZZGa0OAiNXYN3yqh37FQhpYE4JtI9n9gpLHsJMKWR+8zPS1Gd25v3w4rECck++3aMqqsGjHNxB1DYVTUYao653ZHMTXTEENHlm1kZXz/gIZi/jGdKisyG2+zEq0badfYqn9FUOFrTAgN8FybOk7TzzgqaB8kByoSkCpXLe8pkvaweTRYFmryZPBWw1x0RGHXZQblLy/q1DmdgfCtF47dF3SXptiHROqTIwtL2ZS0CyHlxmbi1yt/ZBfQ== 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 Thu, Feb 27, 2025 at 10:38:10PM +0000, shiju.jose@huawei.com wrote: > From: Shiju Jose > > CXL spec 3.2 section 8.2.10.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 the request falls within the limits specified in > DDR5 mode registers), switch between codeword mode and row count mode, and > reset the ECS counter. > > Register with EDAC device driver, which retrieves the ECS attribute > descriptors from the EDAC ECS and exposes the ECS control attributes to > userspace via sysfs. For example, the ECS control for the memory media FRU0 > in CXL mem0 device is located at /sys/bus/edac/devices/cxl_mem0/ecs_fru0/ > Reviewed-by: Fan Ni > Signed-off-by: Shiju Jose > --- > drivers/cxl/Kconfig | 1 + > drivers/cxl/core/memfeatures.c | 355 ++++++++++++++++++++++++++++++++- > 2 files changed, 355 insertions(+), 1 deletion(-) > > diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig > index b83bdb30b702..94321f5bed77 100644 > --- a/drivers/cxl/Kconfig > +++ b/drivers/cxl/Kconfig > @@ -119,6 +119,7 @@ config CXL_RAS_FEATURES > depends on CXL_FEATURES > depends on EDAC=y || (CXL_BUS=m && EDAC=m) > depends on EDAC_SCRUB > + depends on EDAC_ECS > help > The CXL memory RAS feature control is optional and allows host to > control the RAS features configurations of CXL Type 3 devices. > diff --git a/drivers/cxl/core/memfeatures.c b/drivers/cxl/core/memfeatures.c > index 7a5c0645a07e..253930051e87 100644 > --- a/drivers/cxl/core/memfeatures.c > +++ b/drivers/cxl/core/memfeatures.c > @@ -19,7 +19,7 @@ > #include > #include "core.h" > > -#define CXL_DEV_NUM_RAS_FEATURES 1 > +#define CXL_DEV_NUM_RAS_FEATURES 2 > #define CXL_DEV_HOUR_IN_SECS 3600 > > #define CXL_DEV_NAME_LEN 128 > @@ -428,6 +428,352 @@ static int cxl_region_scrub_init(struct cxl_region *cxlr, > return 0; > } > > +/* > + * CXL DDR5 ECS control definitions. > + */ > +struct cxl_ecs_context { > + u16 num_media_frus; > + u16 get_feat_size; > + u16 set_feat_size; > + u8 get_version; > + u8 set_version; > + u16 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_COUNT_MODE_MASK BIT(3) > +#define CXL_ECS_RESET_COUNTER_MASK BIT(4) > +#define CXL_ECS_RESET_COUNTER 1 > + > +enum { > + ECS_THRESHOLD_256 = 256, > + ECS_THRESHOLD_1024 = 1024, > + ECS_THRESHOLD_4096 = 4096, > +}; > + > +enum { > + ECS_THRESHOLD_IDX_256 = 3, > + ECS_THRESHOLD_IDX_1024 = 4, > + ECS_THRESHOLD_IDX_4096 = 5, > +}; > + > +static const u16 ecs_supp_threshold[] = { > + [ECS_THRESHOLD_IDX_256] = 256, > + [ECS_THRESHOLD_IDX_1024] = 1024, > + [ECS_THRESHOLD_IDX_4096] = 4096, > +}; > + > +enum { > + ECS_LOG_ENTRY_TYPE_DRAM = 0x0, > + ECS_LOG_ENTRY_TYPE_MEM_MEDIA_FRU = 0x1, > +}; > + > +enum cxl_ecs_count_mode { > + ECS_MODE_COUNTS_ROWS = 0, > + ECS_MODE_COUNTS_CODEWORDS = 1, > +}; > + > +/** > + * struct cxl_ecs_params - CXL memory DDR5 ECS parameter data structure. > + * @threshold: ECS threshold count per GB of memory cells. > + * @log_entry_type: ECS log entry type, per DRAM or per memory media FRU. > + * @reset_counter: [IN] reset ECC counter to default value. > + * @count_mode: codeword/row count mode > + * 0 : ECS counts rows with errors > + * 1 : ECS counts codeword with errors > + */ > +struct cxl_ecs_params { > + u16 threshold; > + u8 log_entry_type; > + u8 reset_counter; > + enum cxl_ecs_count_mode count_mode; > +}; > + > +/* > + * See CXL spec rev 3.2 @8.2.10.9.11.2 Table 8-225 DDR5 ECS Control Feature > + * Readable Attributes. > + */ > +struct cxl_ecs_fru_rd_attrs { > + u8 ecs_cap; > + __le16 ecs_config; > + u8 ecs_flags; > +} __packed; > + > +struct cxl_ecs_rd_attrs { > + u8 ecs_log_cap; > + struct cxl_ecs_fru_rd_attrs fru_attrs[]; > +} __packed; > + > +/* > + * See CXL spec rev 3.2 @8.2.10.9.11.2 Table 8-226 DDR5 ECS Control Feature > + * Writable Attributes. > + */ > +struct cxl_ecs_fru_wr_attrs { > + __le16 ecs_config; > +} __packed; > + > +struct cxl_ecs_wr_attrs { > + u8 ecs_log_cap; > + struct cxl_ecs_fru_wr_attrs fru_attrs[]; > +} __packed; > + > +/* > + * CXL DDR5 ECS control functions. > + */ > +static int cxl_mem_ecs_get_attrs(struct device *dev, > + struct cxl_ecs_context *cxl_ecs_ctx, > + int fru_id, struct cxl_ecs_params *params) > +{ > + struct cxl_memdev *cxlmd = cxl_ecs_ctx->cxlmd; > + struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; > + struct cxl_ecs_fru_rd_attrs *fru_rd_attrs; > + size_t rd_data_size; > + u8 threshold_index; > + size_t data_size; > + u16 ecs_config; > + > + rd_data_size = cxl_ecs_ctx->get_feat_size; > + > + struct cxl_ecs_rd_attrs *rd_attrs __free(kvfree) = > + kvzalloc(rd_data_size, GFP_KERNEL); > + if (!rd_attrs) > + return -ENOMEM; > + > + params->log_entry_type = 0; > + params->threshold = 0; > + params->count_mode = 0; > + data_size = cxl_get_feature(cxl_mbox, &CXL_FEAT_ECS_UUID, > + CXL_GET_FEAT_SEL_CURRENT_VALUE, > + rd_attrs, rd_data_size, 0, NULL); > + if (!data_size) > + return -EIO; > + > + fru_rd_attrs = rd_attrs->fru_attrs; > + params->log_entry_type = FIELD_GET(CXL_ECS_LOG_ENTRY_TYPE_MASK, > + rd_attrs->ecs_log_cap); > + ecs_config = le16_to_cpu(fru_rd_attrs[fru_id].ecs_config); > + threshold_index = FIELD_GET(CXL_ECS_THRESHOLD_COUNT_MASK, > + ecs_config); > + params->threshold = ecs_supp_threshold[threshold_index]; > + params->count_mode = FIELD_GET(CXL_ECS_COUNT_MODE_MASK, > + ecs_config); > + return 0; > +} > + > +static int cxl_mem_ecs_set_attrs(struct device *dev, > + struct cxl_ecs_context *cxl_ecs_ctx, > + int fru_id, struct cxl_ecs_params *params, > + u8 param_type) > +{ > + struct cxl_memdev *cxlmd = cxl_ecs_ctx->cxlmd; > + struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; > + struct cxl_ecs_fru_rd_attrs *fru_rd_attrs; > + struct cxl_ecs_fru_wr_attrs *fru_wr_attrs; > + size_t rd_data_size, wr_data_size; > + u16 num_media_frus, count; > + size_t data_size; > + u16 ecs_config; > + > + 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(kvfree) = > + kvzalloc(rd_data_size, GFP_KERNEL); > + if (!rd_attrs) > + return -ENOMEM; > + > + data_size = cxl_get_feature(cxl_mbox, &CXL_FEAT_ECS_UUID, > + CXL_GET_FEAT_SEL_CURRENT_VALUE, > + rd_attrs, rd_data_size, 0, NULL); > + if (!data_size) > + return -EIO; > + > + struct cxl_ecs_wr_attrs *wr_attrs __free(kvfree) = > + kvzalloc(wr_data_size, GFP_KERNEL); > + if (!wr_attrs) > + return -ENOMEM; > + > + /* > + * Fill writable attributes from the current attributes read > + * for all the media FRUs. > + */ > + fru_rd_attrs = rd_attrs->fru_attrs; > + fru_wr_attrs = wr_attrs->fru_attrs; > + wr_attrs->ecs_log_cap = rd_attrs->ecs_log_cap; > + for (count = 0; count < num_media_frus; count++) > + fru_wr_attrs[count].ecs_config = fru_rd_attrs[count].ecs_config; > + > + /* > + * Fill attribute to be set for the media FRU > + */ > + ecs_config = le16_to_cpu(fru_rd_attrs[fru_id].ecs_config); > + 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) > + return -EINVAL; > + > + wr_attrs->ecs_log_cap = FIELD_PREP(CXL_ECS_LOG_ENTRY_TYPE_MASK, > + params->log_entry_type); > + break; > + case CXL_ECS_PARAM_THRESHOLD: > + ecs_config &= ~CXL_ECS_THRESHOLD_COUNT_MASK; > + switch (params->threshold) { > + case ECS_THRESHOLD_256: > + ecs_config |= FIELD_PREP(CXL_ECS_THRESHOLD_COUNT_MASK, > + ECS_THRESHOLD_IDX_256); > + break; > + case ECS_THRESHOLD_1024: > + ecs_config |= FIELD_PREP(CXL_ECS_THRESHOLD_COUNT_MASK, > + ECS_THRESHOLD_IDX_1024); > + break; > + case ECS_THRESHOLD_4096: > + ecs_config |= FIELD_PREP(CXL_ECS_THRESHOLD_COUNT_MASK, > + ECS_THRESHOLD_IDX_4096); > + break; > + default: > + dev_dbg(dev, > + "Invalid CXL ECS scrub threshold count(%d) to set\n", > + params->threshold); > + dev_dbg(dev, > + "Supported scrub threshold counts: %u, %u, %u\n", > + ECS_THRESHOLD_256, ECS_THRESHOLD_1024, ECS_THRESHOLD_4096); > + return -EINVAL; > + } > + break; > + case CXL_ECS_PARAM_MODE: > + if (params->count_mode != ECS_MODE_COUNTS_ROWS && > + params->count_mode != ECS_MODE_COUNTS_CODEWORDS) { > + dev_dbg(dev, > + "Invalid CXL ECS scrub mode(%d) to set\n", > + params->count_mode); > + dev_dbg(dev, > + "Supported ECS Modes: 0: ECS counts rows with errors," > + " 1: ECS counts codewords with errors\n"); > + return -EINVAL; > + } > + ecs_config &= ~CXL_ECS_COUNT_MODE_MASK; > + ecs_config |= FIELD_PREP(CXL_ECS_COUNT_MODE_MASK, params->count_mode); > + break; > + case CXL_ECS_PARAM_RESET_COUNTER: > + if (params->reset_counter != CXL_ECS_RESET_COUNTER) > + return -EINVAL; > + > + ecs_config &= ~CXL_ECS_RESET_COUNTER_MASK; > + ecs_config |= FIELD_PREP(CXL_ECS_RESET_COUNTER_MASK, params->reset_counter); > + break; > + default: > + return -EINVAL; > + } > + fru_wr_attrs[fru_id].ecs_config = cpu_to_le16(ecs_config); > + > + return cxl_set_feature(cxl_mbox, &CXL_FEAT_ECS_UUID, > + cxl_ecs_ctx->set_version, > + wr_attrs, wr_data_size, > + CXL_SET_FEAT_FLAG_DATA_SAVED_ACROSS_RESET, > + 0, NULL); > +} > + > +#define CXL_ECS_GET_ATTR(attrib) \ > +static int cxl_ecs_get_##attrib(struct device *dev, void *drv_data, \ > + int fru_id, u32 *val) \ > +{ \ > + struct cxl_ecs_context *ctx = drv_data; \ > + struct cxl_ecs_params params; \ > + int ret; \ > + \ > + ret = cxl_mem_ecs_get_attrs(dev, ctx, fru_id, ¶ms); \ > + if (ret) \ > + return ret; \ > + \ > + *val = params.attrib; \ > + \ > + return 0; \ > +} > + > +CXL_ECS_GET_ATTR(log_entry_type) > +CXL_ECS_GET_ATTR(count_mode) > +CXL_ECS_GET_ATTR(threshold) > + > +#define CXL_ECS_SET_ATTR(attrib, param_type) \ > +static int cxl_ecs_set_##attrib(struct device *dev, void *drv_data, \ > + int fru_id, u32 val) \ > +{ \ > + struct cxl_ecs_context *ctx = drv_data; \ > + struct cxl_ecs_params params = { \ > + .attrib = val, \ > + }; \ > + \ > + return cxl_mem_ecs_set_attrs(dev, ctx, fru_id, ¶ms, (param_type)); \ > +} > +CXL_ECS_SET_ATTR(log_entry_type, CXL_ECS_PARAM_LOG_ENTRY_TYPE) > +CXL_ECS_SET_ATTR(count_mode, CXL_ECS_PARAM_MODE) > +CXL_ECS_SET_ATTR(reset_counter, CXL_ECS_PARAM_RESET_COUNTER) > +CXL_ECS_SET_ATTR(threshold, 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_mode = cxl_ecs_get_count_mode, > + .set_mode = cxl_ecs_set_count_mode, > + .reset = cxl_ecs_set_reset_counter, > + .get_threshold = cxl_ecs_get_threshold, > + .set_threshold = cxl_ecs_set_threshold, > +}; > + > +static int cxl_memdev_ecs_init(struct cxl_memdev *cxlmd, > + struct edac_dev_feature *ras_feature) > +{ > + struct cxl_ecs_context *cxl_ecs_ctx; > + struct cxl_feat_entry *feat_entry; > + int num_media_frus; > + > + feat_entry = cxl_get_feature_entry(cxlmd->cxlds, &CXL_FEAT_ECS_UUID); > + if (IS_ERR(feat_entry)) > + return -EOPNOTSUPP; > + > + if (!(le32_to_cpu(feat_entry->flags) & CXL_FEATURE_F_CHANGEABLE)) > + return -EOPNOTSUPP; > + > + num_media_frus = (le16_to_cpu(feat_entry->get_feat_size) - > + sizeof(struct cxl_ecs_rd_attrs)) / > + sizeof(struct cxl_ecs_fru_rd_attrs); > + if (!num_media_frus) > + return -EOPNOTSUPP; > + > + cxl_ecs_ctx = devm_kzalloc(&cxlmd->dev, sizeof(*cxl_ecs_ctx), > + GFP_KERNEL); > + if (!cxl_ecs_ctx) > + return -ENOMEM; > + > + *cxl_ecs_ctx = (struct cxl_ecs_context) { > + .get_feat_size = le16_to_cpu(feat_entry->get_feat_size), > + .set_feat_size = le16_to_cpu(feat_entry->set_feat_size), > + .get_version = feat_entry->get_feat_ver, > + .set_version = feat_entry->set_feat_ver, > + .effects = le16_to_cpu(feat_entry->effects), > + .num_media_frus = num_media_frus, > + .cxlmd = cxlmd, > + }; > + > + ras_feature->ft_type = RAS_FEAT_ECS; > + ras_feature->ecs_ops = &cxl_ecs_ops; > + ras_feature->ctx = cxl_ecs_ctx; > + ras_feature->ecs_info.num_media_frus = num_media_frus; > + > + return 0; > +} > + > int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) > { > struct edac_dev_feature ras_features[CXL_DEV_NUM_RAS_FEATURES]; > @@ -444,6 +790,13 @@ int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd) > if (rc != -EOPNOTSUPP) > num_ras_features++; > > + rc = cxl_memdev_ecs_init(cxlmd, &ras_features[num_ras_features]); > + if (rc < 0 && rc != -EOPNOTSUPP) > + return rc; > + > + if (rc != -EOPNOTSUPP) > + num_ras_features++; > + > snprintf(cxl_dev_name, sizeof(cxl_dev_name), "%s_%s", > "cxl", dev_name(&cxlmd->dev)); > > -- > 2.43.0 >