Received: by 2002:a05:7208:3188:b0:7e:5202:c8b4 with SMTP id r8csp885386rbd; Fri, 23 Feb 2024 06:39:58 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCXGRNqKM7IKeUM8D8VyRoJc/WHrn09YVDyBxr7iUOlhGU+BZZVI3x7PUBgTEAZBPjFXers1BFm7oz5URZE3QrWQnjL5+RQvLqXczi6i/w== X-Google-Smtp-Source: AGHT+IHXO+ztlnXJ2nk4V1s4gtW2/A9q9BqewHTQKZUlJiPcIpNBWsFSH8sKEc+KZqrNTw8BJ3IP X-Received: by 2002:a05:622a:1054:b0:42e:606e:8002 with SMTP id f20-20020a05622a105400b0042e606e8002mr8703qte.36.1708699198534; Fri, 23 Feb 2024 06:39:58 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1708699198; cv=pass; d=google.com; s=arc-20160816; b=Pubf4vRVVCNnRgQHLIZBxAXr4TslSJ14LiklbcEhAVqwfSLJ05IaRgN5D2QNCRLY4W hkBkEULUsSV2PEER4m3DCzCVUW7spho7udTgxVmKuB6uUgPDY/vfwaCc+spcQM3ZD2vf IqS1A9na+wi4VgHV3fr0DoVx6+WVOnfEsGvBPxPdcVL+45HeTE0ZOQoO4nMbCd0TT3aq rVjPtdl5EkLBJO69wPaURZ1dN6HllgVNkODNpjzd/DC3eN2PPYKCJi0J2bWsPvH3BxD3 5c1ESetUSPPdp589us0etlwnw2+c475VS0zBevgZOsr8MGwxlkEuJA20yKU2H8eDxyG8 WkEw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from; bh=vLKdBp0Khy68JR8jcxgLPQGogE31zNHEEhxO16Ef/I8=; fh=HSG1GuUk1qrw7ZagzQBYl1ym3Aq+DwkDC5iYsmK8j3I=; b=pt6vg+Jc4A5Y748aGB1rZdp/dpS7TYl1r6lkP7piMTCRvFctt9ihLP7+kWhCUpParH 0yTzDNFygYsMwD/ifh8I0Pz0oI4CwZl4dg7Ic0w6yzOlFoJ9GoV4ho8nEZsHbphgvXdF Bed9fZsJS4ZIfO8Uag8cdfFPdxSv4d2CiRkA8B++YWHwI5n15WjvBNtMoYW6Wf3eplRM gCf+rrgJEx+x6RyPTeayABY05Ezr3V4c8aphfO4BSKypbB6e7QEaLbp45GYBsothgBVD csavmXElofaHH0AZVaU+P/xQ/OcKTphCYe1/EtV4FCd03lOC8vnFuLcQCtWGwmElcVJZ IzQQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; arc=pass (i=1 spf=pass spfdomain=huawei.com dmarc=pass fromdomain=huawei.com); spf=pass (google.com: domain of linux-kernel+bounces-78497-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-78497-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id e7-20020a0562141d0700b0068ef89a53bfsi16148796qvd.321.2024.02.23.06.39.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 23 Feb 2024 06:39:58 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-78497-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; arc=pass (i=1 spf=pass spfdomain=huawei.com dmarc=pass fromdomain=huawei.com); spf=pass (google.com: domain of linux-kernel+bounces-78497-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-78497-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 3B3961C22B6C for ; Fri, 23 Feb 2024 14:39:58 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 410998288C; Fri, 23 Feb 2024 14:37:51 +0000 (UTC) Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E2C2F80C0E; Fri, 23 Feb 2024 14:37:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708699070; cv=none; b=XLEzDCsMD+xz2kZEjFxv9BzHZ6O1X5QlNQ1Kzo0h1/p+DnITgeI3fcfqGhesoWaB1Mc+yPKJTXf/gIPI/YoLigieOTQC8mSB/UwlCw1evCPhxsIbHyZbfkmlW+nonhH6GdDKUdtjjK+XiGLNRKM99xZO+GJsUYJNxOHORu2gj10= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708699070; c=relaxed/simple; bh=HjRjQJjpaGOU/Bd4AZEvaexaL9/hGrjKwCHKesdEaNM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=erdQyr8EtObNdY0tFZbh4BPvOgI80x5H8whhA3CzuxRcC8p2xDE+jI0Ytj+HzYcBVj4SLWBEmgGMTszK3Tq9q8pMnZ+i8voxTTzdcipf2DRO9b1ELGBiNKXPibpT3bOvQLK9M3GJ8pc6Ktf8eAlBs8dW4FTlpQwwG2I/iX04pIE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4ThCDc2NQZz6K5p5; Fri, 23 Feb 2024 22:33:36 +0800 (CST) Received: from lhrpeml500006.china.huawei.com (unknown [7.191.161.198]) by mail.maildlp.com (Postfix) with ESMTPS id A657C140B33; Fri, 23 Feb 2024 22:37:45 +0800 (CST) Received: from SecurePC30232.china.huawei.com (10.122.247.234) 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.35; Fri, 23 Feb 2024 14:37:44 +0000 From: To: , , , , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH v7 08/12] cxl/memscrub: Register CXL device ECS with scrub subsystem driver Date: Fri, 23 Feb 2024 22:37:19 +0800 Message-ID: <20240223143723.1574-9-shiju.jose@huawei.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20240223143723.1574-1-shiju.jose@huawei.com> References: <20240223143723.1574-1-shiju.jose@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: lhrpeml500003.china.huawei.com (7.191.162.67) To lhrpeml500006.china.huawei.com (7.191.161.198) From: Shiju Jose Register with the scrub subsystem driver to expose the sysfs attributes to the user for configuring the CXL memory device's ECS feature. Add the static CXL ECS specific attributes to support configuring the CXL memory device ECS feature. Signed-off-by: Shiju Jose --- .../ABI/testing/sysfs-class-cxl-ecs-configure | 79 ++++++ drivers/cxl/core/memscrub.c | 251 +++++++++++++++++- 2 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-cxl-ecs-configure diff --git a/Documentation/ABI/testing/sysfs-class-cxl-ecs-configure b/Documentation/ABI/testing/sysfs-class-cxl-ecs-configure new file mode 100644 index 000000000000..541b150db71c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-cxl-ecs-configure @@ -0,0 +1,79 @@ +See `Documentation/ABI/testing/sysfs-class-scrub-configure` for the +documentation of common scrub configure directory layout (/sys/class/scrub/), +including the attributes used for configuring the CXL patrol scrub. +Following are the attributes defined for configuring the CXL ECS. + +What: /sys/class/scrub/scrubX/regionN/ecs_log_entry_type +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@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/class/scrub/scrubX/regionN/ecs_log_entry_type_per_dram +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) Returns true if current log entry type of DDR5 ECS + region is per DRAM. + +What: /sys/class/scrub/scrubX/regionN/ecs_log_entry_type_per_memory_media +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) Returns true if current log entry type of DDR5 ECS + region is per memory media FRU. + +What: /sys/class/scrub/scrubX/regionN/mode +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@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/class/scrub/scrubX/regionN/mode_counts_rows +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) Returns true if current mode of DDR5 ECS region + is counts rows with errors. + +What: /sys/class/scrub/scrubX/regionN/mode_counts_codewords +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) Returns true if current mode of DDR5 ECS region + is counts codewords with errors. + +What: /sys/class/scrub/scrubX/regionN/reset_counter +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@vger.kernel.org +Description: + (WO) DDR5 ECS reset ECC counter. + 0 - normal, ECC counter running actively. + 1 - reset ECC counter to the default value. + +What: /sys/class/scrub/scrubX/regionN/threshold +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@vger.kernel.org +Description: + (RW) DDR5 ECS threshold count per GB of memory cells. + +What: /sys/class/scrub/scrubX/regionN/threshold_available +Date: February 2024 +KernelVersion: 6.8 +Contact: linux-kernel@vger.kernel.org +Description: + (RO) Supported list of DDR5 ECS threshold count per GB of + memory cells. diff --git a/drivers/cxl/core/memscrub.c b/drivers/cxl/core/memscrub.c index b053dcb9197e..e227ea2f1508 100644 --- a/drivers/cxl/core/memscrub.c +++ b/drivers/cxl/core/memscrub.c @@ -558,9 +558,9 @@ cxl_mem_ecs_get_attrs(struct device *scrub_dev, int fru_id, return 0; } -static int __maybe_unused -cxl_mem_ecs_set_attrs(struct device *scrub_dev, int fru_id, - struct cxl_memdev_ecs_params *params, u8 param_type) +static int cxl_mem_ecs_set_attrs(struct device *scrub_dev, int fru_id, + struct cxl_memdev_ecs_params *params, + u8 param_type) { struct cxl_memdev *cxlmd = to_cxl_memdev(scrub_dev->parent); struct cxl_dev_state *cxlds = cxlmd->cxlds; @@ -677,8 +677,243 @@ cxl_mem_ecs_set_attrs(struct device *scrub_dev, int fru_id, return 0; } +static int cxl_mem_ecs_log_entry_type_write(struct device *dev, int region_id, long val) +{ + struct cxl_memdev_ecs_params params; + int ret; + + params.log_entry_type = val; + ret = cxl_mem_ecs_set_attrs(dev, region_id, ¶ms, + CXL_MEMDEV_ECS_PARAM_LOG_ENTRY_TYPE); + if (ret) { + dev_err(dev->parent, "Set CXL ECS params for log entry type failed ret=%d\n", + ret); + return ret; + } + + return 0; +} + +static int cxl_mem_ecs_threshold_write(struct device *dev, int region_id, long val) +{ + struct cxl_memdev_ecs_params params; + int ret; + + params.threshold = val; + ret = cxl_mem_ecs_set_attrs(dev, region_id, ¶ms, + CXL_MEMDEV_ECS_PARAM_THRESHOLD); + if (ret) { + dev_err(dev->parent, "Set CXL ECS params for threshold failed ret=%d\n", + ret); + return ret; + } + + return 0; +} + +static int cxl_mem_ecs_mode_write(struct device *dev, int region_id, long val) +{ + struct cxl_memdev_ecs_params params; + int ret; + + params.mode = val; + ret = cxl_mem_ecs_set_attrs(dev, region_id, ¶ms, + CXL_MEMDEV_ECS_PARAM_MODE); + if (ret) { + dev_err(dev->parent, "Set CXL ECS params for mode failed ret=%d\n", + ret); + return ret; + } + + return 0; +} + +static int cxl_mem_ecs_reset_counter_write(struct device *dev, int region_id, long val) +{ + struct cxl_memdev_ecs_params params; + int ret; + + params.reset_counter = val; + ret = cxl_mem_ecs_set_attrs(dev, region_id, ¶ms, + CXL_MEMDEV_ECS_PARAM_RESET_COUNTER); + if (ret) { + dev_err(dev->parent, "Set CXL ECS params for reset ECC counter failed ret=%d\n", + ret); + return ret; + } + + return 0; +} + +enum cxl_mem_ecs_scrub_attributes { + cxl_ecs_log_entry_type, + cxl_ecs_log_entry_type_per_dram, + cxl_ecs_log_entry_type_per_memory_media, + cxl_ecs_mode, + cxl_ecs_mode_counts_codewords, + cxl_ecs_mode_counts_rows, + cxl_ecs_reset, + cxl_ecs_threshold, + cxl_ecs_threshold_available, + cxl_ecs_max_attrs +}; + +static ssize_t cxl_mem_ecs_show_scrub_attr(struct device *dev, char *buf, + int attr_id) +{ + struct cxl_ecs_context *cxl_ecs_ctx = dev_get_drvdata(dev); + int region_id = cxl_ecs_ctx->region_id; + struct cxl_memdev_ecs_params params; + int ret; + + if (attr_id == cxl_ecs_log_entry_type || + attr_id == cxl_ecs_log_entry_type_per_dram || + attr_id == cxl_ecs_log_entry_type_per_memory_media || + attr_id == cxl_ecs_mode || + attr_id == cxl_ecs_mode_counts_codewords || + attr_id == cxl_ecs_mode_counts_rows || + attr_id == cxl_ecs_threshold) { + ret = cxl_mem_ecs_get_attrs(dev, region_id, ¶ms); + if (ret) { + dev_err(dev->parent, "Get CXL ECS params failed ret=%d\n", ret); + return ret; + } + } + switch (attr_id) { + case cxl_ecs_log_entry_type: + return sprintf(buf, "%d\n", params.log_entry_type); + case cxl_ecs_log_entry_type_per_dram: + if (params.log_entry_type == ECS_LOG_ENTRY_TYPE_DRAM) + return sysfs_emit(buf, "1\n"); + else + return sysfs_emit(buf, "0\n"); + case cxl_ecs_log_entry_type_per_memory_media: + if (params.log_entry_type == ECS_LOG_ENTRY_TYPE_MEM_MEDIA_FRU) + return sysfs_emit(buf, "1\n"); + else + return sysfs_emit(buf, "0\n"); + case cxl_ecs_mode: + return sprintf(buf, "%d\n", params.mode); + case cxl_ecs_mode_counts_codewords: + if (params.mode == ECS_MODE_COUNTS_CODEWORDS) + return sysfs_emit(buf, "1\n"); + else + return sysfs_emit(buf, "0\n"); + case cxl_ecs_mode_counts_rows: + if (params.mode == ECS_MODE_COUNTS_ROWS) + return sysfs_emit(buf, "1\n"); + else + return sysfs_emit(buf, "0\n"); + case cxl_ecs_threshold: + return sprintf(buf, "%d\n", params.threshold); + case cxl_ecs_threshold_available: + return sysfs_emit(buf, "256,1024,4096\n"); + } + + return -EOPNOTSUPP; +} + +static ssize_t cxl_mem_ecs_store_scrub_attr(struct device *dev, const char *buf, + size_t count, int attr_id) +{ + struct cxl_ecs_context *cxl_ecs_ctx = dev_get_drvdata(dev); + int region_id = cxl_ecs_ctx->region_id; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + switch (attr_id) { + case cxl_ecs_log_entry_type: + ret = cxl_mem_ecs_log_entry_type_write(dev, region_id, val); + if (ret) + return -EOPNOTSUPP; + break; + case cxl_ecs_mode: + ret = cxl_mem_ecs_mode_write(dev, region_id, val); + if (ret) + return -EOPNOTSUPP; + break; + case cxl_ecs_reset: + ret = cxl_mem_ecs_reset_counter_write(dev, region_id, val); + if (ret) + return -EOPNOTSUPP; + break; + case cxl_ecs_threshold: + ret = cxl_mem_ecs_threshold_write(dev, region_id, val); + if (ret) + return -EOPNOTSUPP; + break; + default: + return -EOPNOTSUPP; + } + + return count; +} + +#define CXL_ECS_SCRUB_ATTR_RW(attr) \ +static ssize_t attr##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + return cxl_mem_ecs_show_scrub_attr(dev, buf, (cxl_ecs_##attr)); \ +} \ +static ssize_t attr##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return cxl_mem_ecs_store_scrub_attr(dev, buf, count, (cxl_ecs_##attr));\ +} \ +static DEVICE_ATTR_RW(attr) + +#define CXL_ECS_SCRUB_ATTR_RO(attr) \ +static ssize_t attr##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + return cxl_mem_ecs_show_scrub_attr(dev, buf, (cxl_ecs_##attr)); \ +} \ +static DEVICE_ATTR_RO(attr) + +#define CXL_ECS_SCRUB_ATTR_WO(attr) \ +static ssize_t attr##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return cxl_mem_ecs_store_scrub_attr(dev, buf, count, (cxl_ecs_##attr));\ +} \ +static DEVICE_ATTR_WO(attr) + +CXL_ECS_SCRUB_ATTR_RW(log_entry_type); +CXL_ECS_SCRUB_ATTR_RO(log_entry_type_per_dram); +CXL_ECS_SCRUB_ATTR_RO(log_entry_type_per_memory_media); +CXL_ECS_SCRUB_ATTR_RW(mode); +CXL_ECS_SCRUB_ATTR_RO(mode_counts_codewords); +CXL_ECS_SCRUB_ATTR_RO(mode_counts_rows); +CXL_ECS_SCRUB_ATTR_WO(reset); +CXL_ECS_SCRUB_ATTR_RW(threshold); +CXL_ECS_SCRUB_ATTR_RO(threshold_available); + +static struct attribute *cxl_mem_ecs_scrub_attrs[] = { + &dev_attr_log_entry_type.attr, + &dev_attr_log_entry_type_per_dram.attr, + &dev_attr_log_entry_type_per_memory_media.attr, + &dev_attr_mode.attr, + &dev_attr_mode_counts_codewords.attr, + &dev_attr_mode_counts_rows.attr, + &dev_attr_reset.attr, + &dev_attr_threshold.attr, + &dev_attr_threshold_available.attr, + NULL +}; + +static struct attribute_group cxl_mem_ecs_attr_group = { + .attrs = cxl_mem_ecs_scrub_attrs +}; + int cxl_mem_ecs_init(struct cxl_memdev *cxlmd, int region_id) { + char scrub_name[CXL_MEMDEV_MAX_NAME_LENGTH]; struct cxl_mbox_supp_feat_entry feat_entry; struct cxl_ecs_context *cxl_ecs_ctx; int nr_media_frus; @@ -704,6 +939,16 @@ int cxl_mem_ecs_init(struct cxl_memdev *cxlmd, int region_id) cxl_ecs_ctx->set_feat_size = feat_entry.set_size; cxl_ecs_ctx->region_id = region_id; + snprintf(scrub_name, sizeof(scrub_name), "%s_%s_region%d", + "cxl_ecs", dev_name(&cxlmd->dev), cxl_ecs_ctx->region_id); + struct device *cxl_scrub_dev = devm_scrub_device_register(&cxlmd->dev, + scrub_name, + cxl_ecs_ctx, NULL, + cxl_ecs_ctx->region_id, + &cxl_mem_ecs_attr_group); + if (IS_ERR(cxl_scrub_dev)) + return PTR_ERR(cxl_scrub_dev); + return 0; } EXPORT_SYMBOL_NS_GPL(cxl_mem_ecs_init, CXL); -- 2.34.1