summaryrefslogtreecommitdiff
path: root/drivers/acpi/apei/hest.c
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2010-08-02 15:48:24 +0800
committerLen Brown <len.brown@intel.com>2010-08-08 14:55:52 -0400
commit7ad6e9435596f692ff65f399da12816c94960185 (patch)
tree85786993b961b240f2c95fa320b5eeff859dae2c /drivers/acpi/apei/hest.c
parentad4ecef2f13c790f95b55320f2925c205d8f971f (diff)
ACPI, APEI, Manage GHES as platform devices
Register GHES during HEST initialization as platform devices. And make GHES driver into platform device driver. So that the GHES driver module can be loaded automatically when there are GHES available. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/apei/hest.c')
-rw-r--r--drivers/acpi/apei/hest.c76
1 files changed, 70 insertions, 6 deletions
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index e7f40d362cb3..343168d18266 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -34,6 +34,7 @@
#include <linux/kdebug.h>
#include <linux/highmem.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
#include <acpi/apei.h>
#include "apei-internal.h"
@@ -47,11 +48,6 @@ EXPORT_SYMBOL_GPL(hest_disable);
static struct acpi_table_hest *hest_tab;
-static int hest_void_parse(struct acpi_hest_header *hest_hdr, void *data)
-{
- return 0;
-}
-
static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
[ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */
[ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
@@ -125,6 +121,69 @@ int apei_hest_parse(apei_hest_func_t func, void *data)
}
EXPORT_SYMBOL_GPL(apei_hest_parse);
+struct ghes_arr {
+ struct platform_device **ghes_devs;
+ unsigned int count;
+};
+
+static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
+{
+ int *count = data;
+
+ if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR)
+ (*count)++;
+ return 0;
+}
+
+static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
+{
+ struct acpi_hest_generic *generic;
+ struct platform_device *ghes_dev;
+ struct ghes_arr *ghes_arr = data;
+ int rc;
+
+ if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
+ return 0;
+ generic = (struct acpi_hest_generic *)hest_hdr;
+ if (!generic->enabled)
+ return 0;
+ ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id);
+ if (!ghes_dev)
+ return -ENOMEM;
+ ghes_dev->dev.platform_data = generic;
+ rc = platform_device_add(ghes_dev);
+ if (rc)
+ goto err;
+ ghes_arr->ghes_devs[ghes_arr->count++] = ghes_dev;
+
+ return 0;
+err:
+ platform_device_put(ghes_dev);
+ return rc;
+}
+
+static int hest_ghes_dev_register(unsigned int ghes_count)
+{
+ int rc, i;
+ struct ghes_arr ghes_arr;
+
+ ghes_arr.count = 0;
+ ghes_arr.ghes_devs = kmalloc(sizeof(void *) * ghes_count, GFP_KERNEL);
+ if (!ghes_arr.ghes_devs)
+ return -ENOMEM;
+
+ rc = apei_hest_parse(hest_parse_ghes, &ghes_arr);
+ if (rc)
+ goto err;
+out:
+ kfree(ghes_arr.ghes_devs);
+ return rc;
+err:
+ for (i = 0; i < ghes_arr.count; i++)
+ platform_device_unregister(ghes_arr.ghes_devs[i]);
+ goto out;
+}
+
static int __init setup_hest_disable(char *str)
{
hest_disable = 1;
@@ -137,6 +196,7 @@ static int __init hest_init(void)
{
acpi_status status;
int rc = -ENODEV;
+ unsigned int ghes_count = 0;
if (acpi_disabled)
goto err;
@@ -158,7 +218,11 @@ static int __init hest_init(void)
goto err;
}
- rc = apei_hest_parse(hest_void_parse, NULL);
+ rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);
+ if (rc)
+ goto err;
+
+ rc = hest_ghes_dev_register(ghes_count);
if (rc)
goto err;