diff mbox series

[RFC,v7,11/12] ACPI:RAS2: Add driver for ACPI RAS2 feature table (RAS2)

Message ID 20240223143723.1574-12-shiju.jose@huawei.com (mailing list archive)
State New
Headers show
Series memory: scrub: introduce subsystem + CXL/ACPI-RAS2 drivers | expand

Commit Message

Shiju Jose Feb. 23, 2024, 2:37 p.m. UTC
From: Shiju Jose <shiju.jose@huawei.com>

Add support for ACPI RAS2 feature table (RAS2) defined in the ACPI 6.5
Specification, section 5.2.21.
This driver contains RAS2 Init, which extracts the RAS2 table.
Driver adds platform device, for each memory feature, which binds
to the RAS2 memory driver.

Signed-off-by: Shiju Jose <shiju.jose@huawei.com>
---
 drivers/acpi/Makefile    |  2 +-
 drivers/acpi/ras2_acpi.c | 97 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100755 drivers/acpi/ras2_acpi.c

Comments

Daniel Ferguson March 28, 2024, 11:41 p.m. UTC | #1
> +static int __init ras2_acpi_init(void)
> +{
> +	u8 count;
> +	acpi_status status;
> +	acpi_size ras2_size;
> +	int pcc_subspace_idx;
> +	struct platform_device *pdev;
> +	struct acpi_table_ras2 *pRas2Table;
> +	struct acpi_ras2_pcc_desc *pcc_desc_list;
> +	struct platform_device **pdev_list = NULL;
> +	struct acpi_table_header *pAcpiTable = NULL;
> +
> +	status = acpi_get_table("RAS2", 0, &pAcpiTable);
> +	if (ACPI_FAILURE(status) || !pAcpiTable) {
> +		pr_err("ACPI RAS2 driver failed to initialize, get table failed\n");
> +		return RAS2_FAILURE;
> +	}
> +
> +	ras2_size = pAcpiTable->length;
> +	if (ras2_size < sizeof(struct acpi_table_ras2)) {
> +		pr_err("ACPI RAS2 table present but broken (too short #1)\n");
> +		goto free_ras2_table;
> +	}
> +
> +	pRas2Table = (struct acpi_table_ras2 *)pAcpiTable;
> +
> +	if (pRas2Table->num_pcc_descs <= 0) {
> +		pr_err("ACPI RAS2 table does not contain PCC descriptors\n");
> +		goto free_ras2_table;
> +	}
> +
> +	pdev_list = kzalloc((pRas2Table->num_pcc_descs * sizeof(struct platform_device *)),
> +			     GFP_KERNEL);
> +	if (!pdev_list)
> +		goto free_ras2_table;
> +
> +	pcc_desc_list = (struct acpi_ras2_pcc_desc *)
> +				((void *)pRas2Table + sizeof(struct acpi_table_ras2));
> +	count = 0;
> +	while (count < pRas2Table->num_pcc_descs) {
> +		if (pcc_desc_list->feature_type == RAS2_FEATURE_TYPE_MEMORY) {
> +			pcc_subspace_idx = pcc_desc_list->channel_id;
> +			/* Add the platform device and bind ras2 memory driver */
> +			pdev = ras2_add_platform_device("ras2", &pcc_subspace_idx,
> +							sizeof(pcc_subspace_idx));
> +			if (!pdev)
> +				goto free_ras2_pdev;
> +			pdev_list[count] = pdev;
> +		}
> +		count++;
> +		pcc_desc_list = pcc_desc_list + sizeof(struct acpi_ras2_pcc_desc);

This line needs to be:
pcc_desc_list = pcc_desc_list + 1
because pcc_desc_list is a type larger than a byte.
This bug will crash the module when num_pcc_descs
is greater than 1

> +	}
> +
> +	acpi_put_table(pAcpiTable);
> +	return RAS2_SUCCESS;
> +
> +free_ras2_pdev:
> +	count = 0;
> +	while (count < pRas2Table->num_pcc_descs) {
> +		if (pcc_desc_list->feature_type ==
> +				RAS2_FEATURE_TYPE_MEMORY)
> +			platform_device_put(pdev_list[count++]);
> +	}
> +	kfree(pdev_list);
> +
> +free_ras2_table:
> +	acpi_put_table(pAcpiTable);
> +	return RAS2_FAILURE;
> +}
diff mbox series

Patch

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index b12fba9cff06..e3fd6feb3e54 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -105,7 +105,7 @@  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.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_acpi_common.o
+obj-$(CONFIG_ACPI_RAS2)		+= ras2_acpi_common.o ras2_acpi.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/ras2_acpi.c b/drivers/acpi/ras2_acpi.c
new file mode 100755
index 000000000000..cd2e8f5ad253
--- /dev/null
+++ b/drivers/acpi/ras2_acpi.c
@@ -0,0 +1,97 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ras2_acpi.c - Implementation of ACPI RAS2 feature table processing
+ * functions.
+ *
+ * Copyright (c) 2023 HiSilicon Limited.
+ *
+ * Support for
+ * RAS2 - ACPI 6.5 Specification, section 5.2.21
+ *
+ * Driver contains RAS2 init, which extracts the RAS2 table and
+ * registers the PCC channel for communicating with the ACPI compliant
+ * platform that contains RAS2 command support in hardware.Driver adds
+ * platform device which binds to the RAS2 memory driver.
+ */
+
+#define pr_fmt(fmt)	"ACPI RAS2: " fmt
+
+#include <linux/export.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/platform_device.h>
+#include <acpi/ras2_acpi.h>
+#include <acpi/acpixf.h>
+
+#define RAS2_FEATURE_TYPE_MEMORY        0x00
+
+static int __init ras2_acpi_init(void)
+{
+	u8 count;
+	acpi_status status;
+	acpi_size ras2_size;
+	int pcc_subspace_idx;
+	struct platform_device *pdev;
+	struct acpi_table_ras2 *pRas2Table;
+	struct acpi_ras2_pcc_desc *pcc_desc_list;
+	struct platform_device **pdev_list = NULL;
+	struct acpi_table_header *pAcpiTable = NULL;
+
+	status = acpi_get_table("RAS2", 0, &pAcpiTable);
+	if (ACPI_FAILURE(status) || !pAcpiTable) {
+		pr_err("ACPI RAS2 driver failed to initialize, get table failed\n");
+		return RAS2_FAILURE;
+	}
+
+	ras2_size = pAcpiTable->length;
+	if (ras2_size < sizeof(struct acpi_table_ras2)) {
+		pr_err("ACPI RAS2 table present but broken (too short #1)\n");
+		goto free_ras2_table;
+	}
+
+	pRas2Table = (struct acpi_table_ras2 *)pAcpiTable;
+
+	if (pRas2Table->num_pcc_descs <= 0) {
+		pr_err("ACPI RAS2 table does not contain PCC descriptors\n");
+		goto free_ras2_table;
+	}
+
+	pdev_list = kzalloc((pRas2Table->num_pcc_descs * sizeof(struct platform_device *)),
+			     GFP_KERNEL);
+	if (!pdev_list)
+		goto free_ras2_table;
+
+	pcc_desc_list = (struct acpi_ras2_pcc_desc *)
+				((void *)pRas2Table + sizeof(struct acpi_table_ras2));
+	count = 0;
+	while (count < pRas2Table->num_pcc_descs) {
+		if (pcc_desc_list->feature_type == RAS2_FEATURE_TYPE_MEMORY) {
+			pcc_subspace_idx = pcc_desc_list->channel_id;
+			/* Add the platform device and bind ras2 memory driver */
+			pdev = ras2_add_platform_device("ras2", &pcc_subspace_idx,
+							sizeof(pcc_subspace_idx));
+			if (!pdev)
+				goto free_ras2_pdev;
+			pdev_list[count] = pdev;
+		}
+		count++;
+		pcc_desc_list = pcc_desc_list + sizeof(struct acpi_ras2_pcc_desc);
+	}
+
+	acpi_put_table(pAcpiTable);
+	return RAS2_SUCCESS;
+
+free_ras2_pdev:
+	count = 0;
+	while (count < pRas2Table->num_pcc_descs) {
+		if (pcc_desc_list->feature_type ==
+				RAS2_FEATURE_TYPE_MEMORY)
+			platform_device_put(pdev_list[count++]);
+	}
+	kfree(pdev_list);
+
+free_ras2_table:
+	acpi_put_table(pAcpiTable);
+	return RAS2_FAILURE;
+}
+late_initcall(ras2_acpi_init)