From 162aa53b1840612b231b992776acb50528ab2de4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 3 Sep 2018 09:34:02 +0200 Subject: firmware: google: make structure gsmi_dev static The structure gsmi_dev is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warning: symbol 'gsmi_dev' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index c8f169bf2e27..734146eec1b9 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -84,7 +84,7 @@ struct gsmi_buf { u32 address; /* physical address of buffer */ }; -struct gsmi_device { +static struct gsmi_device { struct platform_device *pdev; /* platform device */ struct gsmi_buf *name_buf; /* variable name buffer */ struct gsmi_buf *data_buf; /* generic data buffer */ -- cgit v1.2.3 From 09ed061a4f56d50758851ca3997510f27115f81b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:03 -0700 Subject: firmware: coreboot: Let OF core populate platform device Now that the /firmware/coreboot node in DT is populated by the core DT platform code with commit 3aa0582fdb82 ("of: platform: populate /firmware/ node from of_platform_default_populate_init()") we should and can remove the platform device creation here. Otherwise, the of_platform_device_create() call will fail, the coreboot of driver won't be registered, and this driver will never bind. At the same time, we should move this driver to use MODULE_DEVICE_TABLE so that module auto-load works properly when the coreboot device is auto-populated and we should drop the of_node handling that was presumably placed here to hold a reference to the DT node created during module init that no longer happens. Cc: Wei-Ning Huang Cc: Julius Werner Reviewed-by: Brian Norris Cc: Samuel Holland Reviewed-by: Sudeep Holla Fixes: 3aa0582fdb82 ("of: platform: populate /firmware/ node from of_platform_default_populate_init()") Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table-of.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c index f15bf404c579..9b90c0fa4a0b 100644 --- a/drivers/firmware/google/coreboot_table-of.c +++ b/drivers/firmware/google/coreboot_table-of.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "coreboot_table.h" @@ -30,7 +29,6 @@ static int coreboot_table_of_probe(struct platform_device *pdev) void __iomem *ptr; ptr = of_iomap(fw_dn, 0); - of_node_put(fw_dn); if (!ptr) return -ENOMEM; @@ -44,8 +42,9 @@ static int coreboot_table_of_remove(struct platform_device *pdev) static const struct of_device_id coreboot_of_match[] = { { .compatible = "coreboot" }, - {}, + {} }; +MODULE_DEVICE_TABLE(of, coreboot_of_match); static struct platform_driver coreboot_table_of_driver = { .probe = coreboot_table_of_probe, @@ -55,28 +54,7 @@ static struct platform_driver coreboot_table_of_driver = { .of_match_table = coreboot_of_match, }, }; - -static int __init platform_coreboot_table_of_init(void) -{ - struct platform_device *pdev; - struct device_node *of_node; - - /* Limit device creation to the presence of /firmware/coreboot node */ - of_node = of_find_node_by_path("/firmware/coreboot"); - if (!of_node) - return -ENODEV; - - if (!of_match_node(coreboot_of_match, of_node)) - return -ENODEV; - - pdev = of_platform_device_create(of_node, "coreboot_table_of", NULL); - if (!pdev) - return -ENODEV; - - return platform_driver_register(&coreboot_table_of_driver); -} - -module_init(platform_coreboot_table_of_init); +module_platform_driver(coreboot_table_of_driver); MODULE_AUTHOR("Google, Inc."); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 20edec388277b62ddfddb8b2b376a937a2cd6d1b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:04 -0700 Subject: firmware: coreboot: Unmap ioregion after device population Both callers of coreboot_table_init() ioremap the pointer that comes in but they don't unmap the memory on failure. Both of them also fail probe immediately with the return value of coreboot_table_init(), leaking a mapping when it fails. The mapping isn't necessary at all after devices are populated either, so we can just drop the mapping here when we exit the function. Let's do that to simplify the code a bit and plug the leak. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Fixes: 570d30c2823f ("firmware: coreboot: Expose the coreboot table as a bus") Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 19db5709ae28..898bb9abc41f 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -110,7 +110,8 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) if (strncmp(header.signature, "LBIO", sizeof(header.signature))) { pr_warn("coreboot_table: coreboot table missing or corrupt!\n"); - return -ENODEV; + ret = -ENODEV; + goto out; } ptr_entry = (void *)ptr_header + header.header_bytes; @@ -137,7 +138,8 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) ptr_entry += entry.size; } - +out: + iounmap(ptr); return ret; } EXPORT_SYMBOL(coreboot_table_init); @@ -146,7 +148,6 @@ int coreboot_table_exit(void) { if (ptr_header) { bus_unregister(&coreboot_bus_type); - iounmap(ptr_header); ptr_header = NULL; } -- cgit v1.2.3 From b81e3140e4128921f25119a2b5ae0049f8373d1a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:05 -0700 Subject: firmware: coreboot: Make bus registration symmetric The bus is registered in module_init() but is unregistered when the platform driver remove() function calls coreboot_table_exit(). That isn't symmetric and it causes the bus to appear on systems that compile this code in, even when there isn't any coreboot firmware on the device. Let's move the registration to the coreboot_table_init() function so that it matches the exit path. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 898bb9abc41f..f417170f83ea 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -70,12 +70,6 @@ static struct bus_type coreboot_bus_type = { .remove = coreboot_bus_remove, }; -static int __init coreboot_bus_init(void) -{ - return bus_register(&coreboot_bus_type); -} -module_init(coreboot_bus_init); - static void coreboot_device_release(struct device *dev) { struct coreboot_device *device = CB_DEV(dev); @@ -114,6 +108,10 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) goto out; } + ret = bus_register(&coreboot_bus_type); + if (ret) + goto out; + ptr_entry = (void *)ptr_header + header.header_bytes; for (i = 0; i < header.table_entries; i++) { memcpy_fromio(&entry, ptr_entry, sizeof(entry)); @@ -138,6 +136,10 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) ptr_entry += entry.size; } + + if (ret) + bus_unregister(&coreboot_bus_type); + out: iounmap(ptr); return ret; -- cgit v1.2.3 From a28aad66da8bd19b249670d003bb9a698bdda397 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:06 -0700 Subject: firmware: coreboot: Collapse platform drivers into bus core The DT based and ACPI based platform drivers here do the same thing; map some memory and hand it over to the coreboot bus to populate devices. The only major difference is that the DT based driver doesn't map the coreboot table header to figure out how large of a region to map for the whole coreboot table and it uses of_iomap() instead of ioremap_cache(). A cached or non-cached mapping shouldn't matter here and mapping some smaller region first before mapping the whole table is just more work but should be OK. In the end, we can remove two files and combine the code all in one place making it easier to reason about things. We leave the old Kconfigs in place for a little while longer but make them hidden and select the previously hidden config option. This way users can upgrade without having to know to reselect this config in the future. Later on we can remove the old hidden configs. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/Kconfig | 26 +++----- drivers/firmware/google/Makefile | 2 - drivers/firmware/google/coreboot_table-acpi.c | 88 --------------------------- drivers/firmware/google/coreboot_table-of.c | 60 ------------------ drivers/firmware/google/coreboot_table.c | 66 ++++++++++++++++++-- drivers/firmware/google/coreboot_table.h | 6 -- 6 files changed, 72 insertions(+), 176 deletions(-) delete mode 100644 drivers/firmware/google/coreboot_table-acpi.c delete mode 100644 drivers/firmware/google/coreboot_table-of.c (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index a456a000048b..16564cfa47ef 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -19,28 +19,22 @@ config GOOGLE_SMI variables. config GOOGLE_COREBOOT_TABLE - tristate - depends on GOOGLE_COREBOOT_TABLE_ACPI || GOOGLE_COREBOOT_TABLE_OF - -config GOOGLE_COREBOOT_TABLE_ACPI - tristate "Coreboot Table Access - ACPI" - depends on ACPI - select GOOGLE_COREBOOT_TABLE + tristate "Coreboot Table Access" + depends on ACPI || OF help This option enables the coreboot_table module, which provides other - firmware modules to access to the coreboot table. The coreboot table - pointer is accessed through the ACPI "GOOGCB00" object. + firmware modules access to the coreboot table. The coreboot table + pointer is accessed through the ACPI "GOOGCB00" object or the + device tree node /firmware/coreboot. If unsure say N. +config GOOGLE_COREBOOT_TABLE_ACPI + tristate + select GOOGLE_COREBOOT_TABLE + config GOOGLE_COREBOOT_TABLE_OF - tristate "Coreboot Table Access - Device Tree" - depends on OF + tristate select GOOGLE_COREBOOT_TABLE - help - This option enable the coreboot_table module, which provide other - firmware modules to access coreboot table. The coreboot table pointer - is accessed through the device tree node /firmware/coreboot. - If unsure say N. config GOOGLE_MEMCONSOLE tristate diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile index d0b3fba96194..d17caded5d88 100644 --- a/drivers/firmware/google/Makefile +++ b/drivers/firmware/google/Makefile @@ -2,8 +2,6 @@ obj-$(CONFIG_GOOGLE_SMI) += gsmi.o obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o -obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI) += coreboot_table-acpi.o -obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF) += coreboot_table-of.o obj-$(CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT) += framebuffer-coreboot.o obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o diff --git a/drivers/firmware/google/coreboot_table-acpi.c b/drivers/firmware/google/coreboot_table-acpi.c deleted file mode 100644 index 77197fe3d42f..000000000000 --- a/drivers/firmware/google/coreboot_table-acpi.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * coreboot_table-acpi.c - * - * Using ACPI to locate Coreboot table and provide coreboot table access. - * - * Copyright 2017 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "coreboot_table.h" - -static int coreboot_table_acpi_probe(struct platform_device *pdev) -{ - phys_addr_t phyaddr; - resource_size_t len; - struct coreboot_table_header __iomem *header = NULL; - struct resource *res; - void __iomem *ptr = NULL; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - - len = resource_size(res); - if (!res->start || !len) - return -EINVAL; - - phyaddr = res->start; - header = ioremap_cache(phyaddr, sizeof(*header)); - if (header == NULL) - return -ENOMEM; - - ptr = ioremap_cache(phyaddr, - header->header_bytes + header->table_bytes); - iounmap(header); - if (!ptr) - return -ENOMEM; - - return coreboot_table_init(&pdev->dev, ptr); -} - -static int coreboot_table_acpi_remove(struct platform_device *pdev) -{ - return coreboot_table_exit(); -} - -static const struct acpi_device_id cros_coreboot_acpi_match[] = { - { "GOOGCB00", 0 }, - { "BOOT0000", 0 }, - { } -}; -MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match); - -static struct platform_driver coreboot_table_acpi_driver = { - .probe = coreboot_table_acpi_probe, - .remove = coreboot_table_acpi_remove, - .driver = { - .name = "coreboot_table_acpi", - .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match), - }, -}; - -static int __init coreboot_table_acpi_init(void) -{ - return platform_driver_register(&coreboot_table_acpi_driver); -} - -module_init(coreboot_table_acpi_init); - -MODULE_AUTHOR("Google, Inc."); -MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c deleted file mode 100644 index 9b90c0fa4a0b..000000000000 --- a/drivers/firmware/google/coreboot_table-of.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * coreboot_table-of.c - * - * Coreboot table access through open firmware. - * - * Copyright 2017 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include "coreboot_table.h" - -static int coreboot_table_of_probe(struct platform_device *pdev) -{ - struct device_node *fw_dn = pdev->dev.of_node; - void __iomem *ptr; - - ptr = of_iomap(fw_dn, 0); - if (!ptr) - return -ENOMEM; - - return coreboot_table_init(&pdev->dev, ptr); -} - -static int coreboot_table_of_remove(struct platform_device *pdev) -{ - return coreboot_table_exit(); -} - -static const struct of_device_id coreboot_of_match[] = { - { .compatible = "coreboot" }, - {} -}; -MODULE_DEVICE_TABLE(of, coreboot_of_match); - -static struct platform_driver coreboot_table_of_driver = { - .probe = coreboot_table_of_probe, - .remove = coreboot_table_of_remove, - .driver = { - .name = "coreboot_table_of", - .of_match_table = coreboot_of_match, - }, -}; -module_platform_driver(coreboot_table_of_driver); - -MODULE_AUTHOR("Google, Inc."); -MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index f417170f83ea..e9cd4da61404 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -16,12 +16,15 @@ * GNU General Public License for more details. */ +#include #include #include #include #include #include #include +#include +#include #include #include "coreboot_table.h" @@ -91,7 +94,7 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) } EXPORT_SYMBOL(coreboot_driver_unregister); -int coreboot_table_init(struct device *dev, void __iomem *ptr) +static int coreboot_table_init(struct device *dev, void __iomem *ptr) { int i, ret; void *ptr_entry; @@ -144,9 +147,38 @@ out: iounmap(ptr); return ret; } -EXPORT_SYMBOL(coreboot_table_init); -int coreboot_table_exit(void) +static int coreboot_table_probe(struct platform_device *pdev) +{ + phys_addr_t phyaddr; + resource_size_t len; + struct coreboot_table_header __iomem *header = NULL; + struct resource *res; + void __iomem *ptr = NULL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + len = resource_size(res); + if (!res->start || !len) + return -EINVAL; + + phyaddr = res->start; + header = ioremap_cache(phyaddr, sizeof(*header)); + if (header == NULL) + return -ENOMEM; + + ptr = ioremap_cache(phyaddr, + header->header_bytes + header->table_bytes); + iounmap(header); + if (!ptr) + return -ENOMEM; + + return coreboot_table_init(&pdev->dev, ptr); +} + +static int coreboot_table_remove(struct platform_device *pdev) { if (ptr_header) { bus_unregister(&coreboot_bus_type); @@ -155,7 +187,33 @@ int coreboot_table_exit(void) return 0; } -EXPORT_SYMBOL(coreboot_table_exit); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cros_coreboot_acpi_match[] = { + { "GOOGCB00", 0 }, + { "BOOT0000", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id coreboot_of_match[] = { + { .compatible = "coreboot" }, + {} +}; +MODULE_DEVICE_TABLE(of, coreboot_of_match); +#endif + +static struct platform_driver coreboot_table_driver = { + .probe = coreboot_table_probe, + .remove = coreboot_table_remove, + .driver = { + .name = "coreboot_table", + .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match), + .of_match_table = of_match_ptr(coreboot_of_match), + }, +}; +module_platform_driver(coreboot_table_driver); MODULE_AUTHOR("Google, Inc."); MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h index 8ad95a94481b..71a9de6b15fa 100644 --- a/drivers/firmware/google/coreboot_table.h +++ b/drivers/firmware/google/coreboot_table.h @@ -91,10 +91,4 @@ int coreboot_driver_register(struct coreboot_driver *driver); /* Unregister a driver that uses the data from a coreboot table. */ void coreboot_driver_unregister(struct coreboot_driver *driver); -/* Initialize coreboot table module given a pointer to iomem */ -int coreboot_table_init(struct device *dev, void __iomem *ptr); - -/* Cleanup coreboot table module */ -int coreboot_table_exit(void); - #endif /* __COREBOOT_TABLE_H */ -- cgit v1.2.3 From a7d9b5f0120eea9f0f58c2ed2b98d2fc86389af3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:07 -0700 Subject: firmware: coreboot: Remap RAM with memremap() instead of ioremap() This is all system memory, so we shouldn't be mapping this all with ioremap() as these aren't I/O regions. Instead, they're memory regions so we should use memremap(). Pick MEMREMAP_WB so we can map memory from RAM directly if that's possible, otherwise it falls back to ioremap_cache() like is being done here already. This also nicely silences the sparse warnings in this code and reduces the need to copy anything around anymore. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 40 +++++++++++++++----------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index e9cd4da61404..2c6c35f0da32 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -32,7 +32,7 @@ #define CB_DEV(d) container_of(d, struct coreboot_device, dev) #define CB_DRV(d) container_of(d, struct coreboot_driver, drv) -static struct coreboot_table_header __iomem *ptr_header; +static struct coreboot_table_header *ptr_header; static int coreboot_bus_match(struct device *dev, struct device_driver *drv) { @@ -94,18 +94,18 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) } EXPORT_SYMBOL(coreboot_driver_unregister); -static int coreboot_table_init(struct device *dev, void __iomem *ptr) +static int coreboot_table_init(struct device *dev, void *ptr) { int i, ret; void *ptr_entry; struct coreboot_device *device; - struct coreboot_table_entry entry; - struct coreboot_table_header header; + struct coreboot_table_entry *entry; + struct coreboot_table_header *header; ptr_header = ptr; - memcpy_fromio(&header, ptr_header, sizeof(header)); + header = ptr; - if (strncmp(header.signature, "LBIO", sizeof(header.signature))) { + if (strncmp(header->signature, "LBIO", sizeof(header->signature))) { pr_warn("coreboot_table: coreboot table missing or corrupt!\n"); ret = -ENODEV; goto out; @@ -115,11 +115,11 @@ static int coreboot_table_init(struct device *dev, void __iomem *ptr) if (ret) goto out; - ptr_entry = (void *)ptr_header + header.header_bytes; - for (i = 0; i < header.table_entries; i++) { - memcpy_fromio(&entry, ptr_entry, sizeof(entry)); + ptr_entry = ptr_header + header->header_bytes; + for (i = 0; i < header->table_entries; i++) { + entry = ptr_entry; - device = kzalloc(sizeof(struct device) + entry.size, GFP_KERNEL); + device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL); if (!device) { ret = -ENOMEM; break; @@ -129,7 +129,7 @@ static int coreboot_table_init(struct device *dev, void __iomem *ptr) device->dev.parent = dev; device->dev.bus = &coreboot_bus_type; device->dev.release = coreboot_device_release; - memcpy_fromio(&device->entry, ptr_entry, entry.size); + memcpy(&device->entry, ptr_entry, entry->size); ret = device_register(&device->dev); if (ret) { @@ -137,24 +137,23 @@ static int coreboot_table_init(struct device *dev, void __iomem *ptr) break; } - ptr_entry += entry.size; + ptr_entry += entry->size; } if (ret) bus_unregister(&coreboot_bus_type); out: - iounmap(ptr); + memunmap(ptr); return ret; } static int coreboot_table_probe(struct platform_device *pdev) { - phys_addr_t phyaddr; resource_size_t len; - struct coreboot_table_header __iomem *header = NULL; + struct coreboot_table_header *header; struct resource *res; - void __iomem *ptr = NULL; + void *ptr; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -164,14 +163,13 @@ static int coreboot_table_probe(struct platform_device *pdev) if (!res->start || !len) return -EINVAL; - phyaddr = res->start; - header = ioremap_cache(phyaddr, sizeof(*header)); + header = memremap(res->start, sizeof(*header), MEMREMAP_WB); if (header == NULL) return -ENOMEM; - ptr = ioremap_cache(phyaddr, - header->header_bytes + header->table_bytes); - iounmap(header); + ptr = memremap(res->start, header->header_bytes + header->table_bytes, + MEMREMAP_WB); + memunmap(header); if (!ptr) return -ENOMEM; -- cgit v1.2.3 From 7adb05bb813d1ba4863c8914eead6139d3d5f8ff Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:08 -0700 Subject: firmware: coreboot: Only populate devices in coreboot_table_init() This function checks the header for sanity, registers a bus, and populates devices for each coreboot table entry. Let's just populate devices here and pull the other bits up into the caller so that this function can be repurposed for pure device creation and registration. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Suggested-by: Julius Werner Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 67 ++++++++++++++------------------ 1 file changed, 29 insertions(+), 38 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 2c6c35f0da32..078d3bbe632f 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -32,8 +32,6 @@ #define CB_DEV(d) container_of(d, struct coreboot_device, dev) #define CB_DRV(d) container_of(d, struct coreboot_driver, drv) -static struct coreboot_table_header *ptr_header; - static int coreboot_bus_match(struct device *dev, struct device_driver *drv) { struct coreboot_device *device = CB_DEV(dev); @@ -94,36 +92,21 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) } EXPORT_SYMBOL(coreboot_driver_unregister); -static int coreboot_table_init(struct device *dev, void *ptr) +static int coreboot_table_populate(struct device *dev, void *ptr) { int i, ret; void *ptr_entry; struct coreboot_device *device; struct coreboot_table_entry *entry; - struct coreboot_table_header *header; - - ptr_header = ptr; - header = ptr; + struct coreboot_table_header *header = ptr; - if (strncmp(header->signature, "LBIO", sizeof(header->signature))) { - pr_warn("coreboot_table: coreboot table missing or corrupt!\n"); - ret = -ENODEV; - goto out; - } - - ret = bus_register(&coreboot_bus_type); - if (ret) - goto out; - - ptr_entry = ptr_header + header->header_bytes; + ptr_entry = ptr + header->header_bytes; for (i = 0; i < header->table_entries; i++) { entry = ptr_entry; device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL); - if (!device) { - ret = -ENOMEM; - break; - } + if (!device) + return -ENOMEM; dev_set_name(&device->dev, "coreboot%d", i); device->dev.parent = dev; @@ -134,18 +117,13 @@ static int coreboot_table_init(struct device *dev, void *ptr) ret = device_register(&device->dev); if (ret) { put_device(&device->dev); - break; + return ret; } ptr_entry += entry->size; } - if (ret) - bus_unregister(&coreboot_bus_type); - -out: - memunmap(ptr); - return ret; + return 0; } static int coreboot_table_probe(struct platform_device *pdev) @@ -153,7 +131,9 @@ static int coreboot_table_probe(struct platform_device *pdev) resource_size_t len; struct coreboot_table_header *header; struct resource *res; + struct device *dev = &pdev->dev; void *ptr; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -163,26 +143,37 @@ static int coreboot_table_probe(struct platform_device *pdev) if (!res->start || !len) return -EINVAL; + /* Check just the header first to make sure things are sane */ header = memremap(res->start, sizeof(*header), MEMREMAP_WB); - if (header == NULL) + if (!header) return -ENOMEM; - ptr = memremap(res->start, header->header_bytes + header->table_bytes, - MEMREMAP_WB); + len = header->header_bytes + header->table_bytes; + ret = strncmp(header->signature, "LBIO", sizeof(header->signature)); memunmap(header); + if (ret) { + dev_warn(dev, "coreboot table missing or corrupt!\n"); + return -ENODEV; + } + + ptr = memremap(res->start, len, MEMREMAP_WB); if (!ptr) return -ENOMEM; - return coreboot_table_init(&pdev->dev, ptr); + ret = bus_register(&coreboot_bus_type); + if (!ret) { + ret = coreboot_table_populate(dev, ptr); + if (ret) + bus_unregister(&coreboot_bus_type); + } + memunmap(ptr); + + return ret; } static int coreboot_table_remove(struct platform_device *pdev) { - if (ptr_header) { - bus_unregister(&coreboot_bus_type); - ptr_header = NULL; - } - + bus_unregister(&coreboot_bus_type); return 0; } -- cgit v1.2.3 From 7153d9afdbd52805f99c28f51e81ee65f5dabbf8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 11 Sep 2018 17:58:58 +0100 Subject: firmware: vpd: fix spelling mistake "partion" -> "partition" Trivial fix to spelling mistake in comment Signed-off-by: Colin Ian King Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/vpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index 1aa67bb5d8c0..c0c0b4e4e281 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -198,7 +198,7 @@ static int vpd_section_init(const char *name, struct vpd_section *sec, sec->name = name; - /* We want to export the raw partion with name ${name}_raw */ + /* We want to export the raw partition with name ${name}_raw */ sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name); if (!sec->raw_name) { err = -ENOMEM; -- cgit v1.2.3 From 655603de68469adaff16842ac17a5aec9c9ce89b Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 12 Oct 2018 10:04:45 -0600 Subject: gsmi: Fix bug in append_to_eventlog sysfs handler The sysfs handler should return the number of bytes consumed, which in the case of a successful write is the entire buffer. Also fix a bug where param.data_len was being set to (count - (2 * sizeof(u32))) instead of just (count - sizeof(u32)). The latter is correct because we skip over the leading u32 which is our param.type, but we were also incorrectly subtracting sizeof(u32) on the line where we were actually setting param.data_len: param.data_len = count - sizeof(u32); This meant that for our example event.kernel_software_watchdog with total length 10 bytes, param.data_len was just 2 prior to this change. To test, successfully append an event to the log with gsmi sysfs. This sample event is for a "Kernel Software Watchdog" > xxd -g 1 event.kernel_software_watchdog 0000000: 01 00 00 00 ad de 06 00 00 00 > cat event.kernel_software_watchdog > /sys/firmware/gsmi/append_to_eventlog > mosys eventlog list | tail -1 14 | 2012-06-25 10:14:14 | Kernl Event | Software Watchdog Signed-off-by: Duncan Laurie Reviewed-by: Vadim Bendebury Reviewed-by: Stefan Reinauer Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin Reviewed-by: Justin TerAvest [zwisler: updated changelog for 2nd bug fix and upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 734146eec1b9..3677d511f4c4 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -480,11 +480,10 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, if (count < sizeof(u32)) return -EINVAL; param.type = *(u32 *)buf; - count -= sizeof(u32); buf += sizeof(u32); /* The remaining buffer is the data payload */ - if (count > gsmi_dev.data_buf->length) + if ((count - sizeof(u32)) > gsmi_dev.data_buf->length) return -EINVAL; param.data_len = count - sizeof(u32); @@ -504,7 +503,7 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, spin_unlock_irqrestore(&gsmi_dev.lock, flags); - return rc; + return (rc == 0) ? count : rc; } -- cgit v1.2.3 From 255d7447cf92821ded63079ffe4019d9f0fa0a6c Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 12 Oct 2018 10:04:46 -0600 Subject: gsmi: Add coreboot to list of matching BIOS vendors In order to use this coreboot needs board support for: CONFIG_ELOG=y CONFIG_ELOG_GSMI=y And the kernel driver needs enabled: CONFIG_GOOGLE_GSMI=y To test, verify that clean shutdown event is added to the log: > mosys eventlog list | grep 'Clean Shutdown' 11 | 2012-06-25 09:49:24 | Kernl Event | Clean Shutdown Signed-off-by: Duncan Laurie Reviewed-by: Vadim Bendebury Reviewed-by: Stefan Reinauer Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin Reviewed-by: Justin TerAvest [zwisler: update changelog for upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 3677d511f4c4..bf86d3c9bbb9 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -715,6 +715,12 @@ static const struct dmi_system_id gsmi_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), }, }, + { + .ident = "Coreboot Firmware", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), + }, + }, {} }; MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table); -- cgit v1.2.3 From d31655ba89575a2d1559a345642338eecd49c96d Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 12 Oct 2018 10:04:47 -0600 Subject: gsmi: Remove autoselected dependency on EFI and EFI_VARS Instead of selecting EFI and EFI_VARS automatically when GSMI is enabled let that portion of the driver be conditionally compiled if EFI and EFI_VARS are enabled. This allows the rest of the driver (specifically event log) to be used if EFI_VARS is not enabled. To test: 1) verify that EFI_VARS is not automatically selected when CONFIG_GOOGLE_GSMI is enabled 2) verify that the kernel boots on Link and that GSMI event log is still available and functional 3) specifically boot the kernel on Alex to ensure it does not try to load efivars and that gsmi also does not load because it is not in the supported DMI table Signed-off-by: Duncan Laurie Reviewed-by: Olof Johansson Signed-off-by: Benson Leung Signed-off-by: Ben Zhang Signed-off-by: Filipe Brandenburger Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin [zwisler: update changelog for upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/Kconfig | 6 +++--- drivers/firmware/google/gsmi.c | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 16564cfa47ef..91a0404affe2 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -10,12 +10,12 @@ if GOOGLE_FIRMWARE config GOOGLE_SMI tristate "SMI interface for Google platforms" - depends on X86 && ACPI && DMI && EFI - select EFI_VARS + depends on X86 && ACPI && DMI help Say Y here if you want to enable SMI callbacks for Google platforms. This provides an interface for writing to and - clearing the EFI event log and reading and writing NVRAM + clearing the event log. If EFI_VARS is also enabled this + driver provides an interface for reading and writing NVRAM variables. config GOOGLE_COREBOOT_TABLE diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index bf86d3c9bbb9..170996764edd 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -289,6 +289,10 @@ static int gsmi_exec(u8 func, u8 sub) return rc; } +#ifdef CONFIG_EFI_VARS + +static struct efivars efivars; + static efi_status_t gsmi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr, unsigned long *data_size, @@ -466,6 +470,8 @@ static const struct efivar_operations efivar_ops = { .get_next_variable = gsmi_get_next_variable, }; +#endif /* CONFIG_EFI_VARS */ + static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) @@ -767,7 +773,6 @@ static __init int gsmi_system_valid(void) } static struct kobject *gsmi_kobj; -static struct efivars efivars; static const struct platform_device_info gsmi_dev_info = { .name = "gsmi", @@ -891,11 +896,14 @@ static __init int gsmi_init(void) goto out_remove_bin_file; } +#ifdef CONFIG_EFI_VARS ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj); if (ret) { printk(KERN_INFO "gsmi: Failed to register efivars\n"); - goto out_remove_sysfs_files; + sysfs_remove_files(gsmi_kobj, gsmi_attrs); + goto out_remove_bin_file; } +#endif register_reboot_notifier(&gsmi_reboot_notifier); register_die_notifier(&gsmi_die_notifier); @@ -906,8 +914,6 @@ static __init int gsmi_init(void) return 0; -out_remove_sysfs_files: - sysfs_remove_files(gsmi_kobj, gsmi_attrs); out_remove_bin_file: sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); out_err: @@ -927,7 +933,9 @@ static void __exit gsmi_exit(void) unregister_die_notifier(&gsmi_die_notifier); atomic_notifier_chain_unregister(&panic_notifier_list, &gsmi_panic_notifier); +#ifdef CONFIG_EFI_VARS efivars_unregister(&efivars); +#endif sysfs_remove_files(gsmi_kobj, gsmi_attrs); sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); -- cgit v1.2.3 From 8942b2d5094b01e4509f0118a7940bb07350e128 Mon Sep 17 00:00:00 2001 From: Furquan Shaikh Date: Fri, 12 Oct 2018 10:04:48 -0600 Subject: gsmi: Add GSMI commands to log S0ix info Add new GSMI commands (GSMI_CMD_LOG_S0IX_SUSPEND = 0xa, GSMI_CMD_LOG_S0IX_RESUME = 0xb) that allow firmware to log any information during S0ix suspend/resume paths. Traditional ACPI suspend S3 involves BIOS both during the suspend and the resume paths. However, modern suspend type like S0ix does not involve firmware on either of the paths. This command gives the firmware an opportunity to log any required information about the suspend and resume operations e.g. wake sources. Additionally, this change adds a module parameter to allow platforms to specifically enable S0ix logging if required. This prevents any other platforms from unnecessarily making a GSMI call which could have any side-effects. Tested by verifying that wake sources are correctly logged in eventlog. Signed-off-by: Furquan Shaikh Reviewed-by: Aaron Durbin Reviewed-by: Rajat Jain Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin [zwisler: update changelog for upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 93 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 170996764edd..82ce1e6d261e 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -29,6 +29,7 @@ #include #include #include +#include #define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */ /* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */ @@ -70,6 +71,8 @@ #define GSMI_CMD_SET_NVRAM_VAR 0x03 #define GSMI_CMD_SET_EVENT_LOG 0x08 #define GSMI_CMD_CLEAR_EVENT_LOG 0x09 +#define GSMI_CMD_LOG_S0IX_SUSPEND 0x0a +#define GSMI_CMD_LOG_S0IX_RESUME 0x0b #define GSMI_CMD_CLEAR_CONFIG 0x20 #define GSMI_CMD_HANDSHAKE_TYPE 0xC1 @@ -122,7 +125,6 @@ struct gsmi_log_entry_type_1 { u32 instance; } __packed; - /* * Some platforms don't have explicit SMI handshake * and need to wait for SMI to complete. @@ -133,6 +135,15 @@ module_param(spincount, uint, 0600); MODULE_PARM_DESC(spincount, "The number of loop iterations to use when using the spin handshake."); +/* + * Platforms might not support S0ix logging in their GSMI handlers. In order to + * avoid any side-effects of generating an SMI for S0ix logging, use the S0ix + * related GSMI commands only for those platforms that explicitly enable this + * option. + */ +static bool s0ix_logging_enable; +module_param(s0ix_logging_enable, bool, 0600); + static struct gsmi_buf *gsmi_buf_alloc(void) { struct gsmi_buf *smibuf; @@ -781,6 +792,78 @@ static const struct platform_device_info gsmi_dev_info = { .dma_mask = DMA_BIT_MASK(32), }; +#ifdef CONFIG_PM +static void gsmi_log_s0ix_info(u8 cmd) +{ + unsigned long flags; + + /* + * If platform has not enabled S0ix logging, then no action is + * necessary. + */ + if (!s0ix_logging_enable) + return; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + + gsmi_exec(GSMI_CALLBACK, cmd); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); +} + +static int gsmi_log_s0ix_suspend(struct device *dev) +{ + /* + * If system is not suspending via firmware using the standard ACPI Sx + * types, then make a GSMI call to log the suspend info. + */ + if (!pm_suspend_via_firmware()) + gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_SUSPEND); + + /* + * Always return success, since we do not want suspend + * to fail just because of logging failure. + */ + return 0; +} + +static int gsmi_log_s0ix_resume(struct device *dev) +{ + /* + * If system did not resume via firmware, then make a GSMI call to log + * the resume info and wake source. + */ + if (!pm_resume_via_firmware()) + gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_RESUME); + + /* + * Always return success, since we do not want resume + * to fail just because of logging failure. + */ + return 0; +} + +static const struct dev_pm_ops gsmi_pm_ops = { + .suspend_noirq = gsmi_log_s0ix_suspend, + .resume_noirq = gsmi_log_s0ix_resume, +}; + +static int gsmi_platform_driver_probe(struct platform_device *dev) +{ + return 0; +} + +static struct platform_driver gsmi_driver_info = { + .driver = { + .name = "gsmi", + .pm = &gsmi_pm_ops, + }, + .probe = gsmi_platform_driver_probe, +}; +#endif + static __init int gsmi_init(void) { unsigned long flags; @@ -792,6 +875,14 @@ static __init int gsmi_init(void) gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command; +#ifdef CONFIG_PM + ret = platform_driver_register(&gsmi_driver_info); + if (unlikely(ret)) { + printk(KERN_ERR "gsmi: unable to register platform driver\n"); + return ret; + } +#endif + /* register device */ gsmi_dev.pdev = platform_device_register_full(&gsmi_dev_info); if (IS_ERR(gsmi_dev.pdev)) { -- cgit v1.2.3