@@ -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
new file mode 100755
@@ -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)