From patchwork Wed Apr 2 12:02:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 14035855 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 71CEBC28B20 for ; Wed, 2 Apr 2025 12:03:03 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id EA74F280004; Wed, 2 Apr 2025 08:02:59 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id E347B280001; Wed, 2 Apr 2025 08:02:59 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B7205280004; Wed, 2 Apr 2025 08:02:59 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 81586280004 for ; Wed, 2 Apr 2025 08:02:59 -0400 (EDT) Received: from smtpin17.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 33AEEBB3A9 for ; Wed, 2 Apr 2025 12:03:01 +0000 (UTC) X-FDA: 83288967762.17.2B1AC96 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf03.hostedemail.com (Postfix) with ESMTP id F23E620021 for ; Wed, 2 Apr 2025 12:02:58 +0000 (UTC) Authentication-Results: imf03.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf03.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1743595379; a=rsa-sha256; cv=none; b=ASKs8ksxuuegczceL68ciKC8965mllGyAYWFjePnqxpLbCTCZ+rcVacajf6wfmMsiA/RxB dCnbkALRz6rJNM44JxetMngfk5JD57J8+UNEUDcLCtadYWoF/IzjvE7o0XXlx1/i/f+TVQ M3XS8RbKXMAT7Qk2uN5yAVSGBiRNtuo= ARC-Authentication-Results: i=1; imf03.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf03.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1743595379; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=D/PMQaVC/1aXnj+XoAqZqi7Lm30Yp1bdXpF9qbP2Frc=; b=h90x6nwp4fohtEOxCEoTFy7yGjDQaop4CLWJTixVIdYNLpu7iZeWAaGF5i1fLTh6J9b97v gW4MlsJ2Kb9NBxTuWybCpDw9dNbKfHqyTxHkZFV4q9YjYtKuUTScs22kS3OiRV4BUNleND YIXfCuzgz8uUA4iUX+6gnK7gcDIn05g= Received: from mail.maildlp.com (unknown [172.18.186.216]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4ZSNh46pmNz6M4fR; Wed, 2 Apr 2025 19:59:16 +0800 (CST) Received: from frapeml500007.china.huawei.com (unknown [7.182.85.172]) by mail.maildlp.com (Postfix) with ESMTPS id B55B314067A; Wed, 2 Apr 2025 20:02:55 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.126.171.80) by frapeml500007.china.huawei.com (7.182.85.172) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.39; Wed, 2 Apr 2025 14:02:54 +0200 From: To: , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [NOT FOR MERGING PATCH v3 1/3] ACPI: ACPI 6.5: RAS2: Rename RAS2 table structure and field names Date: Wed, 2 Apr 2025 13:02:27 +0100 Message-ID: <20250402120230.596-2-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20250402120230.596-1-shiju.jose@huawei.com> References: <20250402120230.596-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.126.171.80] X-ClientProxiedBy: lhrpeml100009.china.huawei.com (7.191.174.83) To frapeml500007.china.huawei.com (7.182.85.172) X-Rspamd-Queue-Id: F23E620021 X-Stat-Signature: oxub6ggct5m51sgbojtttkhy4zxxebpd X-Rspam-User: X-Rspamd-Server: rspam06 X-HE-Tag: 1743595378-505232 X-HE-Meta: U2FsdGVkX1+10SskKB4Nv1za4bnkSpRIQy3cMwfhqfOSnyJGHRDT0+0GCYVpuk9lDbSrhjxXiYR3RtGHsKpgCkJa9GWYBh7lKMDf1IVf/C66yeUfO9pv3Hz02kLBXbVD6xGiiA9eG5AlMs5ggaVMKB0Si8+i8fm+tmmoNb+n4UFBqB8t3F2GluH9MoYdo8EzQtQnjvLttqaxxrkhKwM5F8yQ/MiuzpONJaMEcgllK76RKMdrUvDxZn/PuU6v/S1MCJX0Z+ztKYA1bG2L+iYkvtQF7td9Drcf2/XK59ZwcDJ3gM3xqKn1u+hAqYkPzt+5JOrs41ohotuqe0ADUGZqMkHxJdW0W+UfGRicakBkmX+vOpkaexnfFh5caysOtpHHwZRP66UiadjvNRRejeAT/FeQ2SOl5omj1t+lBfkD7yHo96e3oN/o6/x9Do2Lifk0A8y96Dd4sU+PuZqthaBNr8cTUs2LJhYGaxo3sb/9xiW++8ZrtVoRfLzO2nKgRqrFno299oGK6lOAivwlVGjoHe8mLoGlMHz6sl1mIt5muqCRrRq8w8/iMmEBnvWMFDAmQ9te7pCTmxT3aSB/DhRtvLaVz5YqUGvNdfnffsQG8pGm/21inCB4HorVpfrd8faqYOsremLrvzydjG0zR1M7WQl6Kz30bPO98ULCyahbC4G67LdeR1UbllhDCY0s6euTWHac4/0ztvBxcgoneH1RbrGlz5Pok1XI0ywLEYTVZ+CEb/+sU3pECzmVZkx05ROMu1ToOopKkh71B/V5VyRGkqqjrtNGad6aeJGuXGAzpirSoYfmhGeJcEOYxFLUVL0JRdlfX4XvSlIveCfZWnb0PBwvyLtxy/eGtGjZ0AICYJOXZqZTBdAkVqmNXbg2mPD6mZfdjHBR7EqzOSZUkPTHstoXZiVDdg89oObCgsu591sF0iSG8jGgwg0+2w+T6xdkIsApIIcqqb4R+TxMwbR G+mg1BUM k1wyF6R0M+onXAxqLF62w02Sarxy4fW9piFCjyrpbMFJqA/FG89b43fyGGScsbaXR2Ue8Y4ZzN9Fd8q+g3Hi226oSz3o/HbFVq3xogthjaQhNc2SMwWjKfuFYBEr5LvDfVddOKSxl5eoX3VSotzmH6MIP8tDdv5BQGWuNtqBdBeZJSjSjcArMbM5bTlu3F69zbO/T6dJXp8TLltyEeXyHNYLBj36eLCZ7wzoHI78sRt/r6HA= 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: From: Shiju Jose Rename the RAS2 table structure and field names to shorten them and avoid long lines in the ACPI RAS2 drivers. 1. struct acpi_ras2_shared_memory to struct acpi_ras2_shmem 2. In struct acpi_ras2_shared_memory: fields, - set_capabilities[16] to set_caps[16] - num_parameter_blocks to num_param_blks - set_capabilities_status to set_caps_status 3. struct acpi_ras2_patrol_scrub_parameter to struct acpi_ras2_patrol_scrub_param 4. In struct acpi_ras2_patrol_scrub_parameter: fields, - patrol_scrub_command to command - requested_address_range to req_addr_range - actual_address_range to actl_addr_range Signed-off-by: Shiju Jose --- Corresponding changes are merged in the acpica: https://github.com/acpica/acpica/commit/2c8a38f747de9d977491a494faf0dfaf799b777b --- include/acpi/actbl2.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 2e917a8f8bca..493174ca87f6 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -2802,15 +2802,15 @@ struct acpi_ras2_pcc_desc { /* RAS2 Platform Communication Channel Shared Memory Region */ -struct acpi_ras2_shared_memory { +struct acpi_ras2_shmem { u32 signature; u16 command; u16 status; u16 version; u8 features[16]; - u8 set_capabilities[16]; - u16 num_parameter_blocks; - u32 set_capabilities_status; + u8 set_caps[16]; + u16 num_param_blks; + u32 set_caps_status; }; /* RAS2 Parameter Block Structure for PATROL_SCRUB */ @@ -2823,11 +2823,11 @@ struct acpi_ras2_parameter_block { /* RAS2 Parameter Block Structure for PATROL_SCRUB */ -struct acpi_ras2_patrol_scrub_parameter { +struct acpi_ras2_patrol_scrub_param { struct acpi_ras2_parameter_block header; - u16 patrol_scrub_command; - u64 requested_address_range[2]; - u64 actual_address_range[2]; + u16 command; + u64 req_addr_range[2]; + u64 actl_addr_range[2]; u32 flags; u32 scrub_params_out; u32 scrub_params_in; From patchwork Wed Apr 2 12:02:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 14035865 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 1A806C28B20 for ; Wed, 2 Apr 2025 12:03:09 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 6D215280007; Wed, 2 Apr 2025 08:03:03 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5DAA6280001; Wed, 2 Apr 2025 08:03:03 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 2F55A280007; Wed, 2 Apr 2025 08:03:03 -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 EEFFD280001 for ; Wed, 2 Apr 2025 08:03:02 -0400 (EDT) Received: from smtpin15.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id 8AAA21217D3 for ; Wed, 2 Apr 2025 12:03:04 +0000 (UTC) X-FDA: 83288967888.15.51C0EDC Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf15.hostedemail.com (Postfix) with ESMTP id 942BEA0008 for ; Wed, 2 Apr 2025 12:03:02 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf15.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1743595382; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+YMjMTQMEgF/r4gs3sEOSYwvML9OXCdjn4GcciduEcQ=; b=yKyhrG7EUFf2GxB0vziwCaDBArBzfJil1mWSoQYb9bvfGyCw6mk3UONSFE+56HD/WwKokH mrtswxJJqUtK9EOnFUrazbxJMs/LaeVclfPaIlM/Hrcx02gp0d9LkI9ezAGptpHvjpKIeG RU5A1hg6whef8CpM/JafR+y+vnZcLM4= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1743595382; a=rsa-sha256; cv=none; b=H3OmyYMrPDNM80o1YiRo0lnRy0uosKYRucnMFxsSDmhTtneXC+Dwt6iMXwexuVmh4r4ths WYebt+fmhaohrDgh73B+k9KlckUdtNQnnqZSPo5qn1IluiOmIQv61r2WNcpF9txYI6lLxD ulkT/C0xZVdxQ3wVYx2WqxbrTZ4Q8gs= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf15.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4ZSNhC1RLBz6K9LL; Wed, 2 Apr 2025 19:59:23 +0800 (CST) Received: from frapeml500007.china.huawei.com (unknown [7.182.85.172]) by mail.maildlp.com (Postfix) with ESMTPS id F06F11400D9; Wed, 2 Apr 2025 20:02:57 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.126.171.80) by frapeml500007.china.huawei.com (7.182.85.172) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.39; Wed, 2 Apr 2025 14:02:56 +0200 From: To: , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v3 2/3] ACPI:RAS2: Add ACPI RAS2 driver Date: Wed, 2 Apr 2025 13:02:28 +0100 Message-ID: <20250402120230.596-3-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20250402120230.596-1-shiju.jose@huawei.com> References: <20250402120230.596-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.126.171.80] X-ClientProxiedBy: lhrpeml100009.china.huawei.com (7.191.174.83) To frapeml500007.china.huawei.com (7.182.85.172) X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: 942BEA0008 X-Stat-Signature: 6hft5texinttf3a3ba36gz1yf6tf6s4w X-Rspam-User: X-HE-Tag: 1743595382-615274 X-HE-Meta: U2FsdGVkX1+f5uMo5WyQ/Azf7SpmWid1EkIueORL/RwcPMeMTF1rQgLPuuQOfuMObA04ljZrddaMi3ims/9XfdgK2yuDAV9zwndcAAiRXbI2tIV9pfhVUx/rovChPEZ0Z4Is8LAw1S+fB5Ovkt3C8sQ6Sy66gAj5TpONdliGlFfamEGP8x3IDE73iNmRLgyX9Vi3AQv6935GjX7aPEXnXlEmOeymlOybtn9pWv/gMknuqIjUQHs0hSoLxP/UZciST4YM5Q4uGLYiChI0NME/zioi96wZZo+s9cjmsDZU2AA2/D00JxCnDU/6tSLByX6qKa+50U3zqJem3a5N/SCAFxBdjiGCOkTUf+VGhjxzT7DrMrtYTSUjbhdFRfypX6r8nXJmQdjaEGT4be0AgioWrX2JEXP1bYUl2HX/DvgOpOnfAHqYwFrnXlztB4gIUGXA6F80IJ7zaVvTDhacIFlHTR6dJ6MXofowTDbQp7mO13MGQPt1aZ4CAWaJoMUwHAeMsFEYlnRhtRCZB8HvsQctijhza576pFQPHWJMgmHI0FI2oQ6CA49dIicajn/or5mHQTn4DY/tVWKwqA5JZdBVUtaEcCQER2JLrTCksiXa2oNW3BbeM5h8EKakR37gIPgV0tPLCPm9DAW4vgx6JRF1wLPXSSd/XRcieMeuEq+WWS1LclvsEqK5gpb56IXU7rY8hTbLsQAK38lAVgdiEeuZElS8OUjX36qK0uvFzQ84ql93feFEwl9q/3sxo27o2yIZg4+kQ9KOxLW0JxENrX9SVmuXv+IiI9Y0WKKZysiLSg1TU5Luvf9uiBx3u58PranFAaHt3TFtzifhNodMPwn9sG8X7DUXxTvb0aiub1fJHPrCnnyHiosiC7OIvKP/94xn63BQiaY3tENIAcAYC6EUNbA23+4SDhw8i7c++xRgIDcQKgC9LWYvhy2RnjwSJgaRRfcsEwWSFuCBeD+zFhr w+yPvEhq bAOwLM+N4SBo6tQ3Dvtxf1snVMtZRtTRROAlt63vFeIWE+nyg7LuAr3SOe2I48RKlYY7uWVj/rgxYiSK11gDKdPpzoAR5hPsBB/IkTty4IVKs5B11Yces3a8odnUxKAcClctfyBJPJoDbNMPxMbG4CrM2TzseVWpFgHaOxFJRJrePJimWQtzKOOKkDQyIaUedGggxUX+iGmnNGznE9jtEnx2LAWxh+LUkIUmY8ScTd6MYmg9h913tiNhPSLAXellbUrRMeYrSwW8A8v7U9VaRvNiIlCywDtosxZf1qsevEHlbXuoms1RMjSx7a21vz9Prqv6y 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: From: Shiju Jose Add support for ACPI RAS2 feature table (RAS2) defined in the ACPI 6.5 Specification, section 5.2.21. Driver defines RAS2 Init, which extracts the RAS2 table and driver adds auxiliary device for each memory feature which binds to the RAS2 memory driver. Driver uses PCC mailbox to communicate with the ACPI HW and the driver adds OSPM interfaces to send RAS2 commands. Acked-by: Rafael J. Wysocki Co-developed-by: A Somasundaram Signed-off-by: A Somasundaram Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Tested-by: Daniel Ferguson Signed-off-by: Shiju Jose --- drivers/acpi/Kconfig | 11 ++ drivers/acpi/Makefile | 1 + drivers/acpi/bus.c | 3 + drivers/acpi/ras2.c | 420 ++++++++++++++++++++++++++++++++++++++++++ include/acpi/ras2.h | 44 +++++ 5 files changed, 479 insertions(+) create mode 100644 drivers/acpi/ras2.c create mode 100644 include/acpi/ras2.h diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index d81b55f5068c..bae9a47c829d 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -293,6 +293,17 @@ config ACPI_CPPC_LIB If your platform does not support CPPC in firmware, leave this option disabled. +config ACPI_RAS2 + bool "ACPI RAS2 driver" + select AUXILIARY_BUS + select MAILBOX + select PCC + help + The driver adds support for ACPI RAS2 feature table(extracts RAS2 + table from OS system table) and OSPM interfaces to send RAS2 + commands via PCC mailbox subspace. Driver adds platform device for + the RAS2 memory features which binds to the RAS2 memory driver. + config ACPI_PROCESSOR tristate "Processor" depends on X86 || ARM64 || LOONGARCH || RISCV diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 40208a0f5dfb..797b38cdc2f3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o +obj-$(CONFIG_ACPI_RAS2) += ras2.o obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o obj-$(CONFIG_ACPI_PPTT) += pptt.o obj-$(CONFIG_ACPI_PFRUT) += pfr_update.o pfr_telemetry.o diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 058910af82bc..9a0a1582b8c3 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1472,6 +1473,8 @@ static int __init acpi_init(void) acpi_debugger_init(); acpi_setup_sb_notify_handler(); acpi_viot_init(); + acpi_ras2_init(); + return 0; } diff --git a/drivers/acpi/ras2.c b/drivers/acpi/ras2.c new file mode 100644 index 000000000000..69d8afe99b6e --- /dev/null +++ b/drivers/acpi/ras2.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of ACPI RAS2 driver. + * + * Copyright (c) 2024-2025 HiSilicon Limited. + * + * Support for RAS2 - ACPI 6.5 Specification, section 5.2.21 + * + * Driver contains ACPI RAS2 init, which extracts the ACPI RAS2 table and + * get the PCC channel subspace for communicating with the ACPI compliant + * HW platform which supports ACPI RAS2. Driver adds platform devices + * for each RAS2 memory feature which binds to the memory ACPI RAS2 driver. + */ + +#define pr_fmt(fmt) "ACPI RAS2: " fmt + +#include +#include +#include +#include +#include +#include + +static struct acpi_table_ras2 *__read_mostly ras2_tab; + +/* Data structure for PCC communication */ +struct ras2_pcc_subspace { + struct mbox_client mbox_client; + struct pcc_mbox_chan *pcc_chan; + struct acpi_ras2_shmem __iomem *comm_addr; + struct list_head elem; + /* Lock to provide mutually exclusive access to PCC channel */ + struct mutex pcc_lock; + unsigned int deadline_us; + unsigned int pcc_mpar; + unsigned int pcc_mrtt; + ktime_t last_cmd_cmpl_time; + ktime_t last_mpar_reset; + int mpar_count; + int pcc_id; + u16 ref_count; + bool pcc_chnl_acq; +}; + +/* + * Arbitrary retries for PCC commands because the remote processor + * could be much slower to reply. Keeping it high enough to cover + * emulators where the processors run painfully slow. + */ +#define RAS2_NUM_RETRIES 600ULL + +#define RAS2_FEAT_TYPE_MEMORY 0x00 + +/* Static variables for the RAS2 PCC subspaces */ +static DEFINE_MUTEX(ras2_pcc_list_lock); +static LIST_HEAD(ras2_pcc_subspaces); + +static int ras2_report_cap_error(u32 cap_status) +{ + switch (cap_status) { + case ACPI_RAS2_NOT_VALID: + case ACPI_RAS2_NOT_SUPPORTED: + return -EPERM; + case ACPI_RAS2_BUSY: + return -EBUSY; + case ACPI_RAS2_FAILED: + case ACPI_RAS2_ABORTED: + case ACPI_RAS2_INVALID_DATA: + return -EINVAL; + default: /* 0 or other, Success */ + return 0; + } +} + +static int ras2_check_pcc_chan(struct ras2_pcc_subspace *pcc_subspace) +{ + struct acpi_ras2_shmem __iomem *gen_comm_base = pcc_subspace->comm_addr; + u32 cap_status; + u16 status; + u32 rc; + + /* + * As per ACPI spec, the PCC space will be initialized by + * platform and should have set the command completion bit when + * PCC can be used by OSPM + * + * Poll PCC status register every 3us(delay_us) for maximum of + * deadline_us(timeout_us) until PCC command complete bit is set(cond) + */ + rc = readw_relaxed_poll_timeout(&gen_comm_base->status, status, + status & PCC_STATUS_CMD_COMPLETE, 3, + pcc_subspace->deadline_us); + if (rc) { + pr_warn("PCC check channel failed for : %d rc=%d\n", + pcc_subspace->pcc_id, rc); + return rc; + } + + if (status & PCC_STATUS_ERROR) { + cap_status = readw_relaxed(&gen_comm_base->set_caps_status); + ras2_report_cap_error(cap_status); + + status &= ~PCC_STATUS_ERROR; + writew_relaxed(status, &gen_comm_base->status); + return -EIO; + } + + if (status & PCC_STATUS_CMD_COMPLETE) + return 0; + + return -EIO; +} + +/** + * ras2_send_pcc_cmd() - Send RAS2 command via PCC channel + * @ras2_ctx: pointer to the RAS2 context structure + * @cmd: command to send + * + * Returns: 0 on success, an error otherwise + */ +int ras2_send_pcc_cmd(struct ras2_mem_ctx *ras2_ctx, u16 cmd) +{ + struct ras2_pcc_subspace *pcc_subspace = ras2_ctx->pcc_subspace; + struct acpi_ras2_shmem *gen_comm_base = pcc_subspace->comm_addr; + struct mbox_chan *pcc_channel; + unsigned int time_delta; + int rc; + + rc = ras2_check_pcc_chan(pcc_subspace); + if (rc < 0) + return rc; + + pcc_channel = pcc_subspace->pcc_chan->mchan; + + /* + * Handle the Minimum Request Turnaround Time(MRTT) + * "The minimum amount of time that OSPM must wait after the completion + * of a command before issuing the next command, in microseconds" + */ + if (pcc_subspace->pcc_mrtt) { + time_delta = ktime_us_delta(ktime_get(), + pcc_subspace->last_cmd_cmpl_time); + if (pcc_subspace->pcc_mrtt > time_delta) + udelay(pcc_subspace->pcc_mrtt - time_delta); + } + + /* + * Handle the non-zero Maximum Periodic Access Rate(MPAR) + * "The maximum number of periodic requests that the subspace channel can + * support, reported in commands per minute. 0 indicates no limitation." + * + * This parameter should be ideally zero or large enough so that it can + * handle maximum number of requests that all the cores in the system can + * collectively generate. If it is not, we will follow the spec and just + * not send the request to the platform after hitting the MPAR limit in + * any 60s window + */ + if (pcc_subspace->pcc_mpar) { + if (pcc_subspace->mpar_count == 0) { + time_delta = ktime_ms_delta(ktime_get(), + pcc_subspace->last_mpar_reset); + if (time_delta < 60 * MSEC_PER_SEC) { + dev_dbg(ras2_ctx->dev, + "PCC cmd not sent due to MPAR limit"); + return -EIO; + } + pcc_subspace->last_mpar_reset = ktime_get(); + pcc_subspace->mpar_count = pcc_subspace->pcc_mpar; + } + pcc_subspace->mpar_count--; + } + + /* Write to the shared comm region. */ + writew_relaxed(cmd, &gen_comm_base->command); + + /* Flip CMD COMPLETE bit */ + writew_relaxed(0, &gen_comm_base->status); + + /* Ring doorbell */ + rc = mbox_send_message(pcc_channel, &cmd); + if (rc < 0) { + dev_warn(ras2_ctx->dev, + "Err sending PCC mbox message. cmd:%d, rc:%d\n", cmd, rc); + return rc; + } + + /* + * If Minimum Request Turnaround Time is non-zero, we need + * to record the completion time of both READ and WRITE + * command for proper handling of MRTT, so we need to check + * for pcc_mrtt in addition to CMD_READ + */ + if (cmd == PCC_CMD_EXEC_RAS2 || pcc_subspace->pcc_mrtt) { + rc = ras2_check_pcc_chan(pcc_subspace); + if (pcc_subspace->pcc_mrtt) + pcc_subspace->last_cmd_cmpl_time = ktime_get(); + } + + if (pcc_channel->mbox->txdone_irq) + mbox_chan_txdone(pcc_channel, rc); + else + mbox_client_txdone(pcc_channel, rc); + + return rc >= 0 ? 0 : rc; +} +EXPORT_SYMBOL_GPL(ras2_send_pcc_cmd); + +static int ras2_register_pcc_channel(struct ras2_mem_ctx *ras2_ctx, int pcc_id) +{ + struct ras2_pcc_subspace *pcc_subspace; + struct pcc_mbox_chan *pcc_chan; + struct mbox_client *mbox_cl; + + if (pcc_id < 0) + return -EINVAL; + + mutex_lock(&ras2_pcc_list_lock); + list_for_each_entry(pcc_subspace, &ras2_pcc_subspaces, elem) { + if (pcc_subspace->pcc_id != pcc_id) + continue; + ras2_ctx->pcc_subspace = pcc_subspace; + ras2_ctx->comm_addr = pcc_subspace->comm_addr; + ras2_ctx->dev = pcc_subspace->pcc_chan->mchan->mbox->dev; + ras2_ctx->pcc_lock = &pcc_subspace->pcc_lock; + pcc_subspace->ref_count++; + mutex_unlock(&ras2_pcc_list_lock); + return 0; + } + mutex_unlock(&ras2_pcc_list_lock); + + pcc_subspace = kzalloc(sizeof(*pcc_subspace), GFP_KERNEL); + if (!pcc_subspace) + return -ENOMEM; + + mbox_cl = &pcc_subspace->mbox_client; + mbox_cl->knows_txdone = true; + + pcc_chan = pcc_mbox_request_channel(mbox_cl, pcc_id); + if (IS_ERR(pcc_chan)) { + kfree(pcc_subspace); + return PTR_ERR(pcc_chan); + } + + *pcc_subspace = (struct ras2_pcc_subspace) { + .pcc_id = pcc_id, + .pcc_chan = pcc_chan, + .comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr, + pcc_chan->shmem_size), + .deadline_us = RAS2_NUM_RETRIES * pcc_chan->latency, + .pcc_mrtt = pcc_chan->min_turnaround_time, + .pcc_mpar = pcc_chan->max_access_rate, + .mbox_client = { + .knows_txdone = true, + }, + .pcc_chnl_acq = true, + }; + + mutex_lock(&ras2_pcc_list_lock); + list_add(&pcc_subspace->elem, &ras2_pcc_subspaces); + pcc_subspace->ref_count++; + mutex_unlock(&ras2_pcc_list_lock); + ras2_ctx->pcc_subspace = pcc_subspace; + ras2_ctx->comm_addr = pcc_subspace->comm_addr; + ras2_ctx->dev = pcc_chan->mchan->mbox->dev; + mutex_init(&pcc_subspace->pcc_lock); + ras2_ctx->pcc_lock = &pcc_subspace->pcc_lock; + + return 0; +} + +static DEFINE_IDA(ras2_ida); +static void ras2_remove_pcc(struct ras2_mem_ctx *ras2_ctx) +{ + struct ras2_pcc_subspace *pcc_subspace = ras2_ctx->pcc_subspace; + + guard(mutex)(&ras2_pcc_list_lock); + if (pcc_subspace->ref_count > 0) + pcc_subspace->ref_count--; + + if (!pcc_subspace->ref_count) { + list_del(&pcc_subspace->elem); + pcc_mbox_free_channel(pcc_subspace->pcc_chan); + kfree(pcc_subspace); + } +} + +static void ras2_release(struct device *device) +{ + struct auxiliary_device *auxdev = container_of(device, struct auxiliary_device, dev); + struct ras2_mem_ctx *ras2_ctx = container_of(auxdev, struct ras2_mem_ctx, adev); + + ida_free(&ras2_ida, auxdev->id); + ras2_remove_pcc(ras2_ctx); + kfree(ras2_ctx); +} + +static int ras2_add_aux_device(char *name, int channel) +{ + struct ras2_mem_ctx *ras2_ctx; + int id, rc; + + ras2_ctx = kzalloc(sizeof(*ras2_ctx), GFP_KERNEL); + if (!ras2_ctx) + return -ENOMEM; + + rc = ras2_register_pcc_channel(ras2_ctx, channel); + if (rc < 0) { + pr_debug("failed to register pcc channel rc=%d\n", rc); + goto ctx_free; + } + + id = ida_alloc(&ras2_ida, GFP_KERNEL); + if (id < 0) { + rc = id; + goto pcc_free; + } + + ras2_ctx->id = id; + ras2_ctx->adev.id = id; + ras2_ctx->adev.name = RAS2_MEM_DEV_ID_NAME; + ras2_ctx->adev.dev.release = ras2_release; + ras2_ctx->adev.dev.parent = ras2_ctx->dev; + + rc = auxiliary_device_init(&ras2_ctx->adev); + if (rc) + goto ida_free; + + rc = auxiliary_device_add(&ras2_ctx->adev); + if (rc) { + auxiliary_device_uninit(&ras2_ctx->adev); + return rc; + } + + return 0; + +ida_free: + ida_free(&ras2_ida, id); +pcc_free: + ras2_remove_pcc(ras2_ctx); +ctx_free: + kfree(ras2_ctx); + + return rc; +} + +static int acpi_ras2_parse(void) +{ + struct acpi_ras2_pcc_desc *pcc_desc_list; + u16 i, count; + int pcc_id; + int rc; + + if (ras2_tab->header.length < sizeof(*ras2_tab)) { + pr_warn(FW_WARN "ACPI RAS2 table present but broken (too short #1)\n"); + return -EINVAL; + } + + if (!ras2_tab->num_pcc_descs) { + pr_warn(FW_WARN "No PCC descs in ACPI RAS2 table\n"); + return -EINVAL; + } + + pcc_desc_list = (struct acpi_ras2_pcc_desc *)(ras2_tab + 1); + /* Double scan for the case of only one actual controller */ + pcc_id = -1; + for (i = 0, count = 0; i < ras2_tab->num_pcc_descs; i++, pcc_desc_list++) { + if (pcc_desc_list->feature_type != RAS2_FEAT_TYPE_MEMORY) + continue; + if (pcc_id == -1) { + pcc_id = pcc_desc_list->channel_id; + count++; + } + if (pcc_desc_list->channel_id != pcc_id) + count++; + } + + /* + * Workaround for the client platform with multiple scrub devices + * but uses single PCC subspace for communication. + */ + if (count == 1) { + /* Add auxiliary device and bind ACPI RAS2 memory driver */ + rc = ras2_add_aux_device(RAS2_MEM_DEV_ID_NAME, pcc_id); + if (rc) + return rc; + + return 0; + } + + pcc_desc_list = (struct acpi_ras2_pcc_desc *)(ras2_tab + 1); + for (i = 0; i < ras2_tab->num_pcc_descs; i++, pcc_desc_list++) { + if (pcc_desc_list->feature_type != RAS2_FEAT_TYPE_MEMORY) + continue; + + rc = ras2_add_aux_device(RAS2_MEM_DEV_ID_NAME, pcc_desc_list->channel_id); + if (rc) + return rc; + } + + return 0; +} + +void __init acpi_ras2_init(void) +{ + acpi_status status; + int rc; + + status = acpi_get_table(ACPI_SIG_RAS2, 0, + (struct acpi_table_header **)&ras2_tab); + if (ACPI_FAILURE(status) || !ras2_tab) { + pr_err("Failed to get table, %s\n", acpi_format_exception(status)); + return; + } + + rc = acpi_ras2_parse(); + if (rc) { + acpi_put_table((struct acpi_table_header *)ras2_tab); + pr_err("Failed to parse RAS2 table\n"); + } +} diff --git a/include/acpi/ras2.h b/include/acpi/ras2.h new file mode 100644 index 000000000000..50530b7cbca2 --- /dev/null +++ b/include/acpi/ras2.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * ACPI RAS2 driver header file + * + * Copyright (c) 2024-2025 HiSilicon Limited + */ + +#ifndef _ACPI_RAS2_H +#define _ACPI_RAS2_H + +#include +#include +#include +#include +#include + +struct device; + +/* ACPI spec 6.5 Table 5.82: PCC command codes used by + * RAS2 platform communication channel. + */ +#define PCC_CMD_EXEC_RAS2 0x01 + +#define RAS2_AUX_DEV_NAME "ras2" +#define RAS2_MEM_DEV_ID_NAME "acpi_ras2_mem" + +/* Data structure RAS2 table */ +struct ras2_mem_ctx { + struct auxiliary_device adev; + /* Lock to provide mutually exclusive access to PCC channel */ + struct mutex *pcc_lock; + struct device *dev; + struct acpi_ras2_shmem __iomem *comm_addr; + void *pcc_subspace; + int id; +}; + +#ifdef CONFIG_ACPI_RAS2 +void __init acpi_ras2_init(void); +int ras2_send_pcc_cmd(struct ras2_mem_ctx *ras2_ctx, u16 cmd); +#else +static inline void acpi_ras2_init(void) { } +#endif +#endif /* _ACPI_RAS2_H */ From patchwork Wed Apr 2 12:02:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiju Jose X-Patchwork-Id: 14035856 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 20D55C36017 for ; Wed, 2 Apr 2025 12:03:06 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 53947280006; Wed, 2 Apr 2025 08:03:02 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 4EC2A280001; Wed, 2 Apr 2025 08:03:02 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 33E1B280006; Wed, 2 Apr 2025 08:03:02 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 0C49E280001 for ; Wed, 2 Apr 2025 08:03:02 -0400 (EDT) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id B8FCB1CD4E6 for ; Wed, 2 Apr 2025 12:03:03 +0000 (UTC) X-FDA: 83288967846.18.0CF5281 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by imf11.hostedemail.com (Postfix) with ESMTP id BAD1C40019 for ; Wed, 2 Apr 2025 12:03:01 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf11.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1743595382; a=rsa-sha256; cv=none; b=ghy9QZL44Y0h5XW+EWno1/ZIphVxq1ZZ5UnMa3P+tb26E9JWdCisc1T+klGCjg+YKHXvyL NYa0167uw+5OzQCjOi9CNhJ9OkdP4Doocl/x7l5qcSbOyd9wJeT9lYiRYaQ9jsnnnO5LgA ppT2TVJdNtOzjk3VIZO2rTlq7SdLPps= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf11.hostedemail.com: domain of shiju.jose@huawei.com designates 185.176.79.56 as permitted sender) smtp.mailfrom=shiju.jose@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1743595382; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SsXthTLmAtK2DAtnMC9Iyb9ZX/XPpWDKWs2BGksaVoc=; b=5m9MOiNsHNtmus0HRw3vfe2oMlu1QPp/rn4mwhLwd57KWfKuPHDEjd/Rpe8EiJE1crILY1 PZtHqW8AKAE1Fxld5R/l4h1ELOG/YLMkFP9u3t8vcG/9nu63/T8Lvagmv5urmpdzbHS8fN z6HzgTeZ25mnjLMNnYIS/oz+JFjZXxY= Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4ZSNh9370Lz6M4p2; Wed, 2 Apr 2025 19:59:21 +0800 (CST) Received: from frapeml500007.china.huawei.com (unknown [7.182.85.172]) by mail.maildlp.com (Postfix) with ESMTPS id 35DFB1400D9; Wed, 2 Apr 2025 20:03:00 +0800 (CST) Received: from P_UKIT01-A7bmah.china.huawei.com (10.126.171.80) by frapeml500007.china.huawei.com (7.182.85.172) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.39; Wed, 2 Apr 2025 14:02:58 +0200 From: To: , , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH v3 3/3] ras: mem: Add memory ACPI RAS2 driver Date: Wed, 2 Apr 2025 13:02:29 +0100 Message-ID: <20250402120230.596-4-shiju.jose@huawei.com> X-Mailer: git-send-email 2.43.0.windows.1 In-Reply-To: <20250402120230.596-1-shiju.jose@huawei.com> References: <20250402120230.596-1-shiju.jose@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.126.171.80] X-ClientProxiedBy: lhrpeml100009.china.huawei.com (7.191.174.83) To frapeml500007.china.huawei.com (7.182.85.172) X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: BAD1C40019 X-Stat-Signature: uqzfa9cxe4uja9e3gyygqt1kcurcuurh X-Rspam-User: X-HE-Tag: 1743595381-344496 X-HE-Meta: U2FsdGVkX18gUE6nj8+u2MSRHrVGouyeAflqxbTtrI/fPgCwynDjO9UMMB+GYPxi7MMLhQBXNJeIDkiOsqaa360weZX6GoYeX/yiPR6HkDJxhljGXUY15bRSYGFVG29hM0YOBHLHupfzgY5Uy9StM3nqI3J3NJdh4iOrWBLvlDCdnDBu3W+uAgPTCCUlE6V1Hg5Rmq4mz4fImqoOgwxzHnjles3iLGhI1/0N7BzEuIXeQEPABbsrTctUI+0H1I5eXFcSbb+4go8tF+oeKFdFmxRXG9jZoD1oZrWjS5nTHknJIliQe+tdPrQceKnTOlJPZlFLl2cmf573VDX/MKvWeSsYy9fPTxW7pGtznfNJUckWpw7Dud5gelQX7YyLEL7ZIrxLHLhOhR7brIdOoy44cV7osg7j2L42fXgk3lpmabXio8sWzHen/ym5Xyd18RpyeYytA6wDTYU0mr230QY2/YPkAT7/UEXMM/E+6CabBD8kk4jFraSkmOaC0zCUSUgY/Wyt1PlAfZdrVzMNjhuWDz4qEFn84UxsFIgSaMOyZZ3ACACfKhMutvwW8sWVBlp6BIraP0xcwf0gX1muCBBpick1eqIsdQd7QVsNK0HmqTZt+RKTDhnADDZeUVRJI8PJoYd0y2rZej4qC96wEE5Dh7YU+lDv3u8IbHLVvUrTy+tueRZmawGH5u4NJXmK/FqN/qMDiKUJrfo2UYdJltJMZOIwt2SlNYGdKVcxqs0Ciiu1U6B2h2md8I/QODS2s4vnQoJxpZhZDT6YloijQrNGnZYhMbpVrLHV5DD1uzNY8JoM1Yej4PEYi6WQx2OEnD+sdt2lkK+GvRXShXLFh12XiLiweNCpleNlPrFuoL3towFMGUb/NX7i29zQYvQwpKse/hXiBKKVPeulJj7/Ha8cFSWxzG4eXGMXk7IN2E9htwkim2fLFXBSC7I2HW1yt7wIol9ui0dQhmY3GsIYfPI 5UE7irhC dIQ1/vJ6ltseKDhB3ItrJqedA84W9Uym3IaEZ3roAsGId1HKJb6FHAyVtWrrnWqxt8yoTnwXvvw5B2IU2H8qMG/K6fQi6OMRpxL9NPn+VwySonUJN2jJFPagkp1d+oWg0/rCtHcKNo66MuhT7bTMiUUCIpEF1RWffHkM7cV+FDpcArxL6GL68GrbpdZz57PTNejNm0SbTu0EqmW7wsbmkdRjK85pflGil5dmC/yVeTr5hbxW3K+TU1mTDLB++9N8kE6MMGEKck5JGWTw= 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: From: Shiju Jose Memory ACPI RAS2 auxiliary driver binds to the auxiliary device add by the ACPI RAS2 table parser. Driver uses a PCC subspace for communicating with the ACPI compliant platform. Device with ACPI RAS2 scrub feature registers with EDAC device driver, which retrieves the scrub descriptor from EDAC scrub and exposes the scrub control attributes for RAS2 scrub instance to userspace in /sys/bus/edac/devices/acpi_ras_mem0/scrubX/. Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Tested-by: Daniel Ferguson Signed-off-by: Shiju Jose --- Documentation/edac/scrub.rst | 76 +++++++ drivers/ras/Kconfig | 11 + drivers/ras/Makefile | 1 + drivers/ras/acpi_ras2.c | 406 +++++++++++++++++++++++++++++++++++ include/acpi/ras2.h | 7 + 5 files changed, 501 insertions(+) create mode 100644 drivers/ras/acpi_ras2.c diff --git a/Documentation/edac/scrub.rst b/Documentation/edac/scrub.rst index daab929cdba1..171d70bff731 100644 --- a/Documentation/edac/scrub.rst +++ b/Documentation/edac/scrub.rst @@ -264,3 +264,79 @@ Sysfs files are documented in `Documentation/ABI/testing/sysfs-edac-scrub` `Documentation/ABI/testing/sysfs-edac-ecs` + +Examples +-------- + +The usage takes the form shown in these examples: + +1. ACPI RAS2 + +1.1 On demand scrubbing for a specific memory region. + +1.1.1. Query what is device default/current scrub cycle setting. + + Applicable to both on-demand and background scrubbing. + +# cat /sys/bus/edac/devices/acpi_ras_mem0/scrub0/current_cycle_duration + +36000 + +1.1.2 Query the range of device supported scrub cycle for a memory region. + +# cat /sys/bus/edac/devices/acpi_ras_mem0/scrub0/min_cycle_duration + +3600 + +# cat /sys/bus/edac/devices/acpi_ras_mem0/scrub0/max_cycle_duration + +86400 + +1.1.3. Program scrubbing for the memory region in RAS2 device to repeat every +43200 seconds (half a day). + +# echo 43200 > /sys/bus/edac/devices/acpi_ras_mem0/scrub0/current_cycle_duration + +1.1.4. Program address and size of the memory region to scrub + +Readback 'addr', non-zero - demand scrub is in progress, zero - scrub is finished. + +# cat /sys/bus/edac/devices/acpi_ras_mem0/scrub0/addr + +0 + +Write 'size' of the memory region to scrub. + +# echo 0x300000 > /sys/bus/edac/devices/acpi_ras_mem0/scrub0/size + +Write 'addr' starts demand scrubbing, please make sure other attributes are +set prior to that. + +# echo 0x200000 > /sys/bus/edac/devices/acpi_ras_mem0/scrub0/addr + +Readback 'addr', non-zero - demand scrub is in progress, zero - scrub is finished. + +# cat /sys/bus/edac/devices/acpi_ras_mem0/scrub0/addr + +0x200000 + +# cat /sys/bus/edac/devices/acpi_ras_mem0/scrub0/addr + +0 + +1.2 Background scrubbing the entire memory + +1.2.3 Query the status of background scrubbing. + +# cat /sys/bus/edac/devices/acpi_ras_mem0/scrub0/enable_background + +0 + +1.2.4. Program background scrubbing for RAS2 device to repeat in every 21600 +seconds (quarter of a day). + +# echo 21600 > /sys/bus/edac/devices/acpi_ras_mem0/scrub0/current_cycle_duration + +1.2.5. Start 'background scrubbing'. + +# echo 1 > /sys/bus/edac/devices/acpi_ras_mem0/scrub0/enable_background diff --git a/drivers/ras/Kconfig b/drivers/ras/Kconfig index fc4f4bb94a4c..a88002f1f462 100644 --- a/drivers/ras/Kconfig +++ b/drivers/ras/Kconfig @@ -46,4 +46,15 @@ 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 + depends on EDAC_SCRUB + 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..dbf0f51772e6 --- /dev/null +++ b/drivers/ras/acpi_ras2.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ACPI RAS2 memory driver + * + * Copyright (c) 2024-2025 HiSilicon Limited. + * + */ + +#define pr_fmt(fmt) "ACPI RAS2 MEMORY: " fmt + +#include +#include +#include +#include + +#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 + +/* + * RAS2 patrol scrub + */ +#define RAS2_PS_SC_HRS_IN_MASK GENMASK(15, 8) +#define RAS2_PS_EN_BACKGROUND BIT(0) +#define RAS2_PS_SC_HRS_OUT_MASK GENMASK(7, 0) +#define RAS2_PS_MIN_SC_HRS_OUT_MASK GENMASK(15, 8) +#define RAS2_PS_MAX_SC_HRS_OUT_MASK GENMASK(23, 16) +#define RAS2_PS_FLAG_SCRUB_RUNNING BIT(0) + +#define RAS2_SCRUB_NAME_LEN 128 +#define RAS2_HOUR_IN_SECS 3600 + +enum ras2_od_scrub_status { + OD_SCRUB_STS_IDLE, + OD_SCRUB_STS_INIT, + OD_SCRUB_STS_ACTIVE, +}; + +struct acpi_ras2_ps_shared_mem { + struct acpi_ras2_shmem common; + struct acpi_ras2_patrol_scrub_param params; +}; + +#define TO_ACPI_RAS2_PS_SHMEM(_addr) \ + container_of(_addr, struct acpi_ras2_ps_shared_mem, common) + +static int ras2_is_patrol_scrub_support(struct ras2_mem_ctx *ras2_ctx) +{ + struct acpi_ras2_shmem __iomem *common = (void *)ras2_ctx->comm_addr; + + guard(mutex)(ras2_ctx->pcc_lock); + common->set_caps[0] = 0; + + return common->features[0] & RAS2_SUPPORT_HW_PARTOL_SCRUB; +} + +static int ras2_update_patrol_scrub_params_cache(struct ras2_mem_ctx *ras2_ctx) +{ + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = + TO_ACPI_RAS2_PS_SHMEM(ras2_ctx->comm_addr); + int ret; + + ps_sm->common.set_caps[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + ps_sm->params.command = RAS2_GET_PATROL_PARAMETERS; + + ret = ras2_send_pcc_cmd(ras2_ctx, PCC_CMD_EXEC_RAS2); + if (ret) { + dev_err(ras2_ctx->dev, "failed to read parameters\n"); + return ret; + } + + ras2_ctx->min_scrub_cycle = FIELD_GET(RAS2_PS_MIN_SC_HRS_OUT_MASK, + ps_sm->params.scrub_params_out); + ras2_ctx->max_scrub_cycle = FIELD_GET(RAS2_PS_MAX_SC_HRS_OUT_MASK, + ps_sm->params.scrub_params_out); + ras2_ctx->scrub_cycle_hrs = FIELD_GET(RAS2_PS_SC_HRS_OUT_MASK, + ps_sm->params.scrub_params_out); + if (ras2_ctx->bg_scrub) { + ras2_ctx->base = 0; + ras2_ctx->size = 0; + ras2_ctx->od_scrub_sts = OD_SCRUB_STS_IDLE; + return 0; + } + + if (ps_sm->params.flags & RAS2_PS_FLAG_SCRUB_RUNNING) { + ras2_ctx->base = ps_sm->params.actl_addr_range[0]; + ras2_ctx->size = ps_sm->params.actl_addr_range[1]; + } else if (ras2_ctx->od_scrub_sts != OD_SCRUB_STS_INIT) { + /* + * When demand scrubbing is finished driver resets actual + * address range to 0 when readback. Otherwise userspace + * assumes demand scrubbing is in progress. + */ + ras2_ctx->base = 0; + ras2_ctx->size = 0; + ras2_ctx->od_scrub_sts = OD_SCRUB_STS_IDLE; + } + + return 0; +} + +/* Context - PCC lock must be held */ +static int ras2_get_patrol_scrub_running(struct ras2_mem_ctx *ras2_ctx, + bool *running) +{ + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = + TO_ACPI_RAS2_PS_SHMEM(ras2_ctx->comm_addr); + int ret; + + ps_sm->common.set_caps[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + ps_sm->params.command = RAS2_GET_PATROL_PARAMETERS; + + ret = ras2_send_pcc_cmd(ras2_ctx, PCC_CMD_EXEC_RAS2); + if (ret) { + dev_err(ras2_ctx->dev, "failed to read parameters\n"); + return ret; + } + + *running = ps_sm->params.flags & RAS2_PS_FLAG_SCRUB_RUNNING; + + return 0; +} + +static int ras2_hw_scrub_read_min_scrub_cycle(struct device *dev, void *drv_data, + u32 *min) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + + *min = ras2_ctx->min_scrub_cycle * RAS2_HOUR_IN_SECS; + + return 0; +} + +static int ras2_hw_scrub_read_max_scrub_cycle(struct device *dev, void *drv_data, + u32 *max) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + + *max = ras2_ctx->max_scrub_cycle * RAS2_HOUR_IN_SECS; + + return 0; +} + +static int ras2_hw_scrub_cycle_read(struct device *dev, void *drv_data, + u32 *scrub_cycle_secs) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + + *scrub_cycle_secs = ras2_ctx->scrub_cycle_hrs * RAS2_HOUR_IN_SECS; + + return 0; +} + +static int ras2_hw_scrub_cycle_write(struct device *dev, void *drv_data, + u32 scrub_cycle_secs) +{ + u8 scrub_cycle_hrs = scrub_cycle_secs / RAS2_HOUR_IN_SECS; + struct ras2_mem_ctx *ras2_ctx = drv_data; + bool running; + int ret; + + guard(mutex)(ras2_ctx->pcc_lock); + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + + if (running) + return -EBUSY; + + if (scrub_cycle_hrs < ras2_ctx->min_scrub_cycle || + scrub_cycle_hrs > ras2_ctx->max_scrub_cycle) + return -EINVAL; + + ras2_ctx->scrub_cycle_hrs = scrub_cycle_hrs; + + return 0; +} + +static int ras2_hw_scrub_read_addr(struct device *dev, void *drv_data, u64 *base) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + int ret; + + /* + * When BG scrubbing is enabled the actual address range is not valid. + * Return -EBUSY now unless find out a method to retrieve actual full PA range. + */ + if (ras2_ctx->bg_scrub) + return -EBUSY; + + ret = ras2_update_patrol_scrub_params_cache(ras2_ctx); + if (ret) + return ret; + + *base = ras2_ctx->base; + + return 0; +} + +static int ras2_hw_scrub_read_size(struct device *dev, void *drv_data, u64 *size) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + int ret; + + if (ras2_ctx->bg_scrub) + return -EBUSY; + + ret = ras2_update_patrol_scrub_params_cache(ras2_ctx); + if (ret) + return ret; + + *size = ras2_ctx->size; + + return 0; +} + +static int ras2_hw_scrub_write_addr(struct device *dev, void *drv_data, u64 base) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = + TO_ACPI_RAS2_PS_SHMEM(ras2_ctx->comm_addr); + bool running; + int ret; + + guard(mutex)(ras2_ctx->pcc_lock); + ps_sm->common.set_caps[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + if (ras2_ctx->bg_scrub) + return -EBUSY; + + if (!base || !ras2_ctx->size) { + dev_warn(ras2_ctx->dev, + "%s: Invalid address range, base=0x%llx size=0x%llx\n", + __func__, base, ras2_ctx->size); + return -ERANGE; + } + + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + + if (running) + return -EBUSY; + + ps_sm->params.scrub_params_in &= ~RAS2_PS_SC_HRS_IN_MASK; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PS_SC_HRS_IN_MASK, + ras2_ctx->scrub_cycle_hrs); + ps_sm->params.req_addr_range[0] = base; + ps_sm->params.req_addr_range[1] = ras2_ctx->size; + ps_sm->params.scrub_params_in &= ~RAS2_PS_EN_BACKGROUND; + ps_sm->params.command = RAS2_START_PATROL_SCRUBBER; + + ret = ras2_send_pcc_cmd(ras2_ctx, PCC_CMD_EXEC_RAS2); + if (ret) { + dev_err(ras2_ctx->dev, "Failed to start demand scrubbing\n"); + return ret; + } + ras2_ctx->od_scrub_sts = OD_SCRUB_STS_ACTIVE; + + return ras2_update_patrol_scrub_params_cache(ras2_ctx); +} + +static int ras2_hw_scrub_write_size(struct device *dev, void *drv_data, u64 size) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + bool running; + int ret; + + guard(mutex)(ras2_ctx->pcc_lock); + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + + if (running) + return -EBUSY; + + if (!size) { + dev_warn(dev, "%s: Invalid address range size=0x%llx\n", + __func__, size); + return -EINVAL; + } + + ras2_ctx->size = size; + ras2_ctx->od_scrub_sts = OD_SCRUB_STS_INIT; + + return 0; +} + +static int ras2_hw_scrub_set_enabled_bg(struct device *dev, void *drv_data, bool enable) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + struct acpi_ras2_ps_shared_mem __iomem *ps_sm = + TO_ACPI_RAS2_PS_SHMEM(ras2_ctx->comm_addr); + bool running; + int ret; + + guard(mutex)(ras2_ctx->pcc_lock); + ps_sm->common.set_caps[0] = RAS2_SUPPORT_HW_PARTOL_SCRUB; + ret = ras2_get_patrol_scrub_running(ras2_ctx, &running); + if (ret) + return ret; + + if (enable) { + if (ras2_ctx->bg_scrub || running) + return -EBUSY; + ps_sm->params.req_addr_range[0] = 0; + ps_sm->params.req_addr_range[1] = 0; + ps_sm->params.scrub_params_in &= ~RAS2_PS_SC_HRS_IN_MASK; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PS_SC_HRS_IN_MASK, + ras2_ctx->scrub_cycle_hrs); + ps_sm->params.command = RAS2_START_PATROL_SCRUBBER; + } else { + if (!ras2_ctx->bg_scrub) + return -EPERM; + ps_sm->params.command = RAS2_STOP_PATROL_SCRUBBER; + } + + ps_sm->params.scrub_params_in &= ~RAS2_PS_EN_BACKGROUND; + ps_sm->params.scrub_params_in |= FIELD_PREP(RAS2_PS_EN_BACKGROUND, + enable); + ret = ras2_send_pcc_cmd(ras2_ctx, PCC_CMD_EXEC_RAS2); + if (ret) { + dev_err(ras2_ctx->dev, "Failed to %s background scrubbing\n", + str_enable_disable(enable)); + return ret; + } + + if (enable) { + ras2_ctx->bg_scrub = 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_scrub = false; + } + + return ret; +} + +static int ras2_hw_scrub_get_enabled_bg(struct device *dev, void *drv_data, bool *enabled) +{ + struct ras2_mem_ctx *ras2_ctx = drv_data; + + *enabled = ras2_ctx->bg_scrub; + + return 0; +} + +static const struct edac_scrub_ops ras2_scrub_ops = { + .read_addr = ras2_hw_scrub_read_addr, + .read_size = ras2_hw_scrub_read_size, + .write_addr = ras2_hw_scrub_write_addr, + .write_size = ras2_hw_scrub_write_size, + .get_enabled_bg = ras2_hw_scrub_get_enabled_bg, + .set_enabled_bg = ras2_hw_scrub_set_enabled_bg, + .get_min_cycle = ras2_hw_scrub_read_min_scrub_cycle, + .get_max_cycle = ras2_hw_scrub_read_max_scrub_cycle, + .get_cycle_duration = ras2_hw_scrub_cycle_read, + .set_cycle_duration = ras2_hw_scrub_cycle_write, +}; + +static int ras2_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct ras2_mem_ctx *ras2_ctx = container_of(auxdev, struct ras2_mem_ctx, adev); + struct edac_dev_feature ras_features; + char scrub_name[RAS2_SCRUB_NAME_LEN]; + int ret; + + if (!ras2_is_patrol_scrub_support(ras2_ctx)) + return -EOPNOTSUPP; + + ret = ras2_update_patrol_scrub_params_cache(ras2_ctx); + if (ret) + return ret; + + sprintf(scrub_name, "acpi_ras_mem%d", ras2_ctx->id); + + ras_features.ft_type = RAS_FEAT_SCRUB; + ras_features.instance = ras2_ctx->instance; + ras_features.scrub_ops = &ras2_scrub_ops; + ras_features.ctx = ras2_ctx; + + return edac_dev_register(&auxdev->dev, scrub_name, NULL, 1, + &ras_features); +} + +static const struct auxiliary_device_id ras2_mem_dev_id_table[] = { + { .name = RAS2_AUX_DEV_NAME "." RAS2_MEM_DEV_ID_NAME, }, + { } +}; + +MODULE_DEVICE_TABLE(auxiliary, ras2_mem_dev_id_table); + +static struct auxiliary_driver ras2_mem_driver = { + .name = RAS2_MEM_DEV_ID_NAME, + .probe = ras2_probe, + .id_table = ras2_mem_dev_id_table, +}; +module_auxiliary_driver(ras2_mem_driver); + +MODULE_IMPORT_NS("ACPI_RAS2"); +MODULE_DESCRIPTION("ACPI RAS2 memory driver"); +MODULE_LICENSE("GPL"); diff --git a/include/acpi/ras2.h b/include/acpi/ras2.h index 50530b7cbca2..841539a430d6 100644 --- a/include/acpi/ras2.h +++ b/include/acpi/ras2.h @@ -32,7 +32,14 @@ struct ras2_mem_ctx { struct device *dev; struct acpi_ras2_shmem __iomem *comm_addr; void *pcc_subspace; + u64 base, size; int id; + u8 instance; + u8 scrub_cycle_hrs; + u8 min_scrub_cycle; + u8 max_scrub_cycle; + u8 od_scrub_sts; + bool bg_scrub; }; #ifdef CONFIG_ACPI_RAS2