2018-01-25 01:44:11

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 0/5] coreboot table bus and framebuffer driver

On many systems, coreboot[1] firmware can initialize graphics hardware
and set up a high-resolution linear framebuffer. It exports information
about this framebuffer, along with various other information, in a table
discoverable via ACPI or a device tree.

coreboot also supports booting Linux directly from flash as a "payload".
Projects such as Heads[2], u-root[3], and petitboot[4] provide a minimal
userland that can then be used to chainload (via kexec) into a full
Linux system loaded from disk or over the network.

Fitting even a minimal Linux system on an SPI flash chip is challenging.
Reusing the framebuffer setup from coreboot provides an enormous benefit
to these projects by allowing them to omit full graphics drivers from
their kernel builds. It also speeds up boot times by avoiding duplicated
effort, and because coreboot's graphics initialization is often much
faster than the Linux driver.

Patch 1 of this series expands coreboot table support into an enumerable
bus that devices can hang off of. Patches 2-3 convert the existing
drivers to use the new bus structure instead of ad-hoc platform devices,
and patch 4 removes the old coreboot_table_find function.

Finally, patch 5 adds a new driver for the coreboot-initialized
framebuffer. It improves on earlier work[5] by being architecture-
independent and not needing to scan through low memory.

This patchset has been tested on a Lenovo ThinkPad X220, and earlier
versions of these patches have been tested by various members of the
coreboot community on other hardware.

[1]: https://www.coreboot.org/Welcome_to_coreboot
[2]: https://github.com/osresearch/heads
[3]: https://github.com/u-root/u-root
[4]: https://www.kernel.org/pub/linux/kernel/people/geoff/petitboot/petitboot.html
[5]: https://mail.coreboot.org/pipermail/coreboot/2014-September/078551.html

Samuel Holland (5):
firmware: coreboot: Expose the coreboot table as a bus
firmware: memconsole: Probe via coreboot bus
firmware: vpd: Probe via coreboot bus
firmware: coreboot: Remove unused coreboot_table_find
firmware: coreboot: Add coreboot framebuffer driver

drivers/firmware/google/Kconfig | 8 ++
drivers/firmware/google/Makefile | 1 +
drivers/firmware/google/coreboot_table-acpi.c | 2 +-
drivers/firmware/google/coreboot_table-of.c | 2 +-
drivers/firmware/google/coreboot_table.c | 130 ++++++++++++++++++-------
drivers/firmware/google/coreboot_table.h | 72 +++++++++++---
drivers/firmware/google/framebuffer-coreboot.c | 115 ++++++++++++++++++++++
drivers/firmware/google/memconsole-coreboot.c | 49 ++++------
drivers/firmware/google/vpd.c | 43 +++-----
9 files changed, 313 insertions(+), 109 deletions(-)
create mode 100644 drivers/firmware/google/framebuffer-coreboot.c

--
2.13.6



2018-01-25 01:42:16

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 3/5] firmware: vpd: Probe via coreboot bus

Remove the ad-hoc coreboot table search. Now the driver will only be
probed when the necessary coreboot table entry has already been found.
Furthermore, since the coreboot bus takes care of creating the device, a
separate platform device is no longer needed.

Signed-off-by: Samuel Holland <[email protected]>
---
drivers/firmware/google/vpd.c | 43 ++++++++++++-------------------------------
1 file changed, 12 insertions(+), 31 deletions(-)

diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c
index e4b40f2b4627..e9db895916c3 100644
--- a/drivers/firmware/google/vpd.c
+++ b/drivers/firmware/google/vpd.c
@@ -286,20 +286,15 @@ static int vpd_sections_init(phys_addr_t physaddr)
return 0;
}

-static int vpd_probe(struct platform_device *pdev)
+static int vpd_probe(struct coreboot_device *dev)
{
int ret;
- struct lb_cbmem_ref entry;
-
- ret = coreboot_table_find(CB_TAG_VPD, &entry, sizeof(entry));
- if (ret)
- return ret;

vpd_kobj = kobject_create_and_add("vpd", firmware_kobj);
if (!vpd_kobj)
return -ENOMEM;

- ret = vpd_sections_init(entry.cbmem_addr);
+ ret = vpd_sections_init(dev->cbmem_ref.cbmem_addr);
if (ret) {
kobject_put(vpd_kobj);
return ret;
@@ -308,7 +303,7 @@ static int vpd_probe(struct platform_device *pdev)
return 0;
}

-static int vpd_remove(struct platform_device *pdev)
+static int vpd_remove(struct coreboot_device *dev)
{
vpd_section_destroy(&ro_vpd);
vpd_section_destroy(&rw_vpd);
@@ -318,41 +313,27 @@ static int vpd_remove(struct platform_device *pdev)
return 0;
}

-static struct platform_driver vpd_driver = {
+static struct coreboot_driver vpd_driver = {
.probe = vpd_probe,
.remove = vpd_remove,
- .driver = {
+ .drv = {
.name = "vpd",
},
+ .tag = CB_TAG_VPD,
};

-static struct platform_device *vpd_pdev;
-
-static int __init vpd_platform_init(void)
+static int __init coreboot_vpd_init(void)
{
- int ret;
-
- ret = platform_driver_register(&vpd_driver);
- if (ret)
- return ret;
-
- vpd_pdev = platform_device_register_simple("vpd", -1, NULL, 0);
- if (IS_ERR(vpd_pdev)) {
- platform_driver_unregister(&vpd_driver);
- return PTR_ERR(vpd_pdev);
- }
-
- return 0;
+ return coreboot_driver_register(&vpd_driver);
}

-static void __exit vpd_platform_exit(void)
+static void __exit coreboot_vpd_exit(void)
{
- platform_device_unregister(vpd_pdev);
- platform_driver_unregister(&vpd_driver);
+ coreboot_driver_unregister(&vpd_driver);
}

-module_init(vpd_platform_init);
-module_exit(vpd_platform_exit);
+module_init(coreboot_vpd_init);
+module_exit(coreboot_vpd_exit);

MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
--
2.13.6


2018-01-25 01:42:53

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 5/5] firmware: coreboot: Add coreboot framebuffer driver

Register a simplefb framebuffer when the coreboot table contains a
framebuffer entry.

Signed-off-by: Samuel Holland <[email protected]>
---
drivers/firmware/google/Kconfig | 8 ++
drivers/firmware/google/Makefile | 1 +
drivers/firmware/google/coreboot_table.h | 22 +++++
drivers/firmware/google/framebuffer-coreboot.c | 115 +++++++++++++++++++++++++
4 files changed, 146 insertions(+)
create mode 100644 drivers/firmware/google/framebuffer-coreboot.c

diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig
index f16b381a569c..a456a000048b 100644
--- a/drivers/firmware/google/Kconfig
+++ b/drivers/firmware/google/Kconfig
@@ -55,6 +55,14 @@ config GOOGLE_MEMCONSOLE_X86_LEGACY
the EBDA on Google servers. If found, this log is exported to
userland in the file /sys/firmware/log.

+config GOOGLE_FRAMEBUFFER_COREBOOT
+ tristate "Coreboot Framebuffer"
+ depends on FB_SIMPLE
+ depends on GOOGLE_COREBOOT_TABLE
+ help
+ This option enables the kernel to search for a framebuffer in
+ the coreboot table. If found, it is registered with simplefb.
+
config GOOGLE_MEMCONSOLE_COREBOOT
tristate "Firmware Memory Console"
depends on GOOGLE_COREBOOT_TABLE
diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile
index dcd3675efcfc..d0b3fba96194 100644
--- a/drivers/firmware/google/Makefile
+++ b/drivers/firmware/google/Makefile
@@ -4,6 +4,7 @@ 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
obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o
diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h
index 26a3f3f3ac9c..8ad95a94481b 100644
--- a/drivers/firmware/google/coreboot_table.h
+++ b/drivers/firmware/google/coreboot_table.h
@@ -3,6 +3,7 @@
*
* Internal header for coreboot table access.
*
+ * Copyright 2014 Gerd Hoffmann <[email protected]>
* Copyright 2017 Google Inc.
* Copyright 2017 Samuel Holland <[email protected]>
*
@@ -46,12 +47,33 @@ struct lb_cbmem_ref {
u64 cbmem_addr;
};

+/* Describes framebuffer setup by coreboot */
+struct lb_framebuffer {
+ u32 tag;
+ u32 size;
+
+ u64 physical_address;
+ u32 x_resolution;
+ u32 y_resolution;
+ u32 bytes_per_line;
+ u8 bits_per_pixel;
+ u8 red_mask_pos;
+ u8 red_mask_size;
+ u8 green_mask_pos;
+ u8 green_mask_size;
+ u8 blue_mask_pos;
+ u8 blue_mask_size;
+ u8 reserved_mask_pos;
+ u8 reserved_mask_size;
+};
+
/* A device, additionally with information from coreboot. */
struct coreboot_device {
struct device dev;
union {
struct coreboot_table_entry entry;
struct lb_cbmem_ref cbmem_ref;
+ struct lb_framebuffer framebuffer;
};
};

diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c
new file mode 100644
index 000000000000..b8b49c067157
--- /dev/null
+++ b/drivers/firmware/google/framebuffer-coreboot.c
@@ -0,0 +1,115 @@
+/*
+ * framebuffer-coreboot.c
+ *
+ * Memory based framebuffer accessed through coreboot table.
+ *
+ * Copyright 2012-2013 David Herrmann <[email protected]>
+ * Copyright 2017 Google Inc.
+ * Copyright 2017 Samuel Holland <[email protected]>
+ *
+ * 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 <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+
+#include "coreboot_table.h"
+
+#define CB_TAG_FRAMEBUFFER 0x12
+
+static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+
+static int framebuffer_probe(struct coreboot_device *dev)
+{
+ int i;
+ u32 length;
+ struct lb_framebuffer *fb = &dev->framebuffer;
+ struct platform_device *pdev;
+ struct resource res;
+ struct simplefb_platform_data pdata = {
+ .width = fb->x_resolution,
+ .height = fb->y_resolution,
+ .stride = fb->bytes_per_line,
+ .format = NULL,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (fb->bits_per_pixel == formats[i].bits_per_pixel &&
+ fb->red_mask_pos == formats[i].red.offset &&
+ fb->red_mask_size == formats[i].red.length &&
+ fb->green_mask_pos == formats[i].green.offset &&
+ fb->green_mask_size == formats[i].green.length &&
+ fb->blue_mask_pos == formats[i].blue.offset &&
+ fb->blue_mask_size == formats[i].blue.length &&
+ fb->reserved_mask_pos == formats[i].transp.offset &&
+ fb->reserved_mask_size == formats[i].transp.length)
+ pdata.format = formats[i].name;
+ }
+ if (!pdata.format)
+ return -ENODEV;
+
+ memset(&res, 0, sizeof(res));
+ res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ res.name = "Coreboot Framebuffer";
+ res.start = fb->physical_address;
+ length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line);
+ res.end = res.start + length - 1;
+ if (res.end <= res.start)
+ return -EINVAL;
+
+ pdev = platform_device_register_resndata(&dev->dev,
+ "simple-framebuffer", 0,
+ &res, 1, &pdata,
+ sizeof(pdata));
+ if (IS_ERR(pdev))
+ pr_warn("coreboot: could not register framebuffer\n");
+ else
+ dev_set_drvdata(&dev->dev, pdev);
+
+ return PTR_ERR_OR_ZERO(pdev);
+}
+
+static int framebuffer_remove(struct coreboot_device *dev)
+{
+ struct platform_device *pdev = dev_get_drvdata(&dev->dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
+static struct coreboot_driver framebuffer_driver = {
+ .probe = framebuffer_probe,
+ .remove = framebuffer_remove,
+ .drv = {
+ .name = "framebuffer",
+ },
+ .tag = CB_TAG_FRAMEBUFFER,
+};
+
+static int __init coreboot_framebuffer_init(void)
+{
+ return coreboot_driver_register(&framebuffer_driver);
+}
+
+static void coreboot_framebuffer_exit(void)
+{
+ coreboot_driver_unregister(&framebuffer_driver);
+}
+
+module_init(coreboot_framebuffer_init);
+module_exit(coreboot_framebuffer_exit);
+
+MODULE_AUTHOR("Samuel Holland <[email protected]>");
+MODULE_LICENSE("GPL");
--
2.13.6


2018-01-25 01:43:05

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 2/5] firmware: memconsole: Probe via coreboot bus

Remove the ad-hoc coreboot table search. Now the driver will only be
probed when the necessary coreboot table entry has already been found.

Signed-off-by: Samuel Holland <[email protected]>
---
drivers/firmware/google/memconsole-coreboot.c | 49 ++++++++++-----------------
1 file changed, 17 insertions(+), 32 deletions(-)

diff --git a/drivers/firmware/google/memconsole-coreboot.c b/drivers/firmware/google/memconsole-coreboot.c
index 52738887735c..b29e10757bfb 100644
--- a/drivers/firmware/google/memconsole-coreboot.c
+++ b/drivers/firmware/google/memconsole-coreboot.c
@@ -15,9 +15,9 @@
* GNU General Public License for more details.
*/

+#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/platform_device.h>

#include "memconsole.h"
#include "coreboot_table.h"
@@ -73,18 +73,19 @@ static ssize_t memconsole_coreboot_read(char *buf, loff_t pos, size_t count)
return done;
}

-static int memconsole_coreboot_init(phys_addr_t physaddr)
+static int memconsole_probe(struct coreboot_device *dev)
{
struct cbmem_cons __iomem *tmp_cbmc;

- tmp_cbmc = memremap(physaddr, sizeof(*tmp_cbmc), MEMREMAP_WB);
+ tmp_cbmc = memremap(dev->cbmem_ref.cbmem_addr,
+ sizeof(*tmp_cbmc), MEMREMAP_WB);

if (!tmp_cbmc)
return -ENOMEM;

/* Read size only once to prevent overrun attack through /dev/mem. */
cbmem_console_size = tmp_cbmc->size_dont_access_after_boot;
- cbmem_console = memremap(physaddr,
+ cbmem_console = memremap(dev->cbmem_ref.cbmem_addr,
cbmem_console_size + sizeof(*cbmem_console),
MEMREMAP_WB);
memunmap(tmp_cbmc);
@@ -93,26 +94,11 @@ static int memconsole_coreboot_init(phys_addr_t physaddr)
return -ENOMEM;

memconsole_setup(memconsole_coreboot_read);
- return 0;
-}
-
-static int memconsole_probe(struct platform_device *pdev)
-{
- int ret;
- struct lb_cbmem_ref entry;
-
- ret = coreboot_table_find(CB_TAG_CBMEM_CONSOLE, &entry, sizeof(entry));
- if (ret)
- return ret;
-
- ret = memconsole_coreboot_init(entry.cbmem_addr);
- if (ret)
- return ret;

return memconsole_sysfs_init();
}

-static int memconsole_remove(struct platform_device *pdev)
+static int memconsole_remove(struct coreboot_device *dev)
{
memconsole_exit();

@@ -122,28 +108,27 @@ static int memconsole_remove(struct platform_device *pdev)
return 0;
}

-static struct platform_driver memconsole_driver = {
+static struct coreboot_driver memconsole_driver = {
.probe = memconsole_probe,
.remove = memconsole_remove,
- .driver = {
+ .drv = {
.name = "memconsole",
},
+ .tag = CB_TAG_CBMEM_CONSOLE,
};

-static int __init platform_memconsole_init(void)
+static void coreboot_memconsole_exit(void)
{
- struct platform_device *pdev;
-
- pdev = platform_device_register_simple("memconsole", -1, NULL, 0);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
-
- platform_driver_register(&memconsole_driver);
+ coreboot_driver_unregister(&memconsole_driver);
+}

- return 0;
+static int __init coreboot_memconsole_init(void)
+{
+ return coreboot_driver_register(&memconsole_driver);
}

-module_init(platform_memconsole_init);
+module_exit(coreboot_memconsole_exit);
+module_init(coreboot_memconsole_init);

MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
--
2.13.6


2018-01-25 01:43:57

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 4/5] firmware: coreboot: Remove unused coreboot_table_find

Now that all users of the coreboot_table_find function have been updated
to hang off the coreboot table bus instead, remove it.

Signed-off-by: Samuel Holland <[email protected]>
---
drivers/firmware/google/coreboot_table.c | 43 --------------------------------
drivers/firmware/google/coreboot_table.h | 3 ---
2 files changed, 46 deletions(-)

diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c
index 04fc08e81744..19db5709ae28 100644
--- a/drivers/firmware/google/coreboot_table.c
+++ b/drivers/firmware/google/coreboot_table.c
@@ -97,49 +97,6 @@ void coreboot_driver_unregister(struct coreboot_driver *driver)
}
EXPORT_SYMBOL(coreboot_driver_unregister);

-/*
- * This function parses the coreboot table for an entry that contains the base
- * address of the given entry tag. The coreboot table consists of a header
- * directly followed by a number of small, variable-sized entries, which each
- * contain an identifying tag and their length as the first two fields.
- */
-int coreboot_table_find(int tag, void *data, size_t data_size)
-{
- struct coreboot_table_header header;
- struct coreboot_table_entry entry;
- void *ptr_entry;
- int i;
-
- if (!ptr_header)
- return -EPROBE_DEFER;
-
- memcpy_fromio(&header, ptr_header, sizeof(header));
-
- if (strncmp(header.signature, "LBIO", sizeof(header.signature))) {
- pr_warn("coreboot_table: coreboot table missing or corrupt!\n");
- return -ENODEV;
- }
-
- ptr_entry = (void *)ptr_header + header.header_bytes;
-
- for (i = 0; i < header.table_entries; i++) {
- memcpy_fromio(&entry, ptr_entry, sizeof(entry));
- if (entry.tag == tag) {
- if (data_size < entry.size)
- return -EINVAL;
-
- memcpy_fromio(data, ptr_entry, entry.size);
-
- return 0;
- }
-
- ptr_entry += entry.size;
- }
-
- return -ENOENT;
-}
-EXPORT_SYMBOL(coreboot_table_find);
-
int coreboot_table_init(struct device *dev, void __iomem *ptr)
{
int i, ret;
diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h
index 88e6a1c06028..26a3f3f3ac9c 100644
--- a/drivers/firmware/google/coreboot_table.h
+++ b/drivers/firmware/google/coreboot_table.h
@@ -69,9 +69,6 @@ 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);

-/* Retrieve coreboot table entry with tag *tag* and copy it to data */
-int coreboot_table_find(int tag, void *data, size_t data_size);
-
/* Initialize coreboot table module given a pointer to iomem */
int coreboot_table_init(struct device *dev, void __iomem *ptr);

--
2.13.6


2018-01-25 01:44:16

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 1/5] firmware: coreboot: Expose the coreboot table as a bus

This simplifies creating device drivers for hardware or information
described in the coreboot table. It also avoids needing to search
through the table every time a driver is loaded.

Signed-off-by: Samuel Holland <[email protected]>
---
drivers/firmware/google/coreboot_table-acpi.c | 2 +-
drivers/firmware/google/coreboot_table-of.c | 2 +-
drivers/firmware/google/coreboot_table.c | 121 ++++++++++++++++++++++++--
drivers/firmware/google/coreboot_table.h | 49 +++++++++--
4 files changed, 156 insertions(+), 18 deletions(-)

diff --git a/drivers/firmware/google/coreboot_table-acpi.c b/drivers/firmware/google/coreboot_table-acpi.c
index fb98db2d20e2..77197fe3d42f 100644
--- a/drivers/firmware/google/coreboot_table-acpi.c
+++ b/drivers/firmware/google/coreboot_table-acpi.c
@@ -53,7 +53,7 @@ static int coreboot_table_acpi_probe(struct platform_device *pdev)
if (!ptr)
return -ENOMEM;

- return coreboot_table_init(ptr);
+ return coreboot_table_init(&pdev->dev, ptr);
}

static int coreboot_table_acpi_remove(struct platform_device *pdev)
diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c
index 727acdc83e83..f15bf404c579 100644
--- a/drivers/firmware/google/coreboot_table-of.c
+++ b/drivers/firmware/google/coreboot_table-of.c
@@ -34,7 +34,7 @@ static int coreboot_table_of_probe(struct platform_device *pdev)
if (!ptr)
return -ENOMEM;

- return coreboot_table_init(ptr);
+ return coreboot_table_init(&pdev->dev, ptr);
}

static int coreboot_table_of_remove(struct platform_device *pdev)
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c
index 0019d3ec18dd..04fc08e81744 100644
--- a/drivers/firmware/google/coreboot_table.c
+++ b/drivers/firmware/google/coreboot_table.c
@@ -4,6 +4,7 @@
* Module providing coreboot table access.
*
* Copyright 2017 Google Inc.
+ * Copyright 2017 Samuel Holland <[email protected]>
*
* 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
@@ -15,21 +16,87 @@
* GNU General Public License for more details.
*/

+#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>

#include "coreboot_table.h"

-struct coreboot_table_entry {
- u32 tag;
- u32 size;
-};
+#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 int coreboot_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct coreboot_device *device = CB_DEV(dev);
+ struct coreboot_driver *driver = CB_DRV(drv);
+
+ return device->entry.tag == driver->tag;
+}
+
+static int coreboot_bus_probe(struct device *dev)
+{
+ int ret = -ENODEV;
+ struct coreboot_device *device = CB_DEV(dev);
+ struct coreboot_driver *driver = CB_DRV(dev->driver);
+
+ if (driver->probe)
+ ret = driver->probe(device);
+
+ return ret;
+}
+
+static int coreboot_bus_remove(struct device *dev)
+{
+ int ret = 0;
+ struct coreboot_device *device = CB_DEV(dev);
+ struct coreboot_driver *driver = CB_DRV(dev->driver);
+
+ if (driver->remove)
+ ret = driver->remove(device);
+
+ return ret;
+}
+
+static struct bus_type coreboot_bus_type = {
+ .name = "coreboot",
+ .match = coreboot_bus_match,
+ .probe = coreboot_bus_probe,
+ .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);
+
+ kfree(device);
+}
+
+int coreboot_driver_register(struct coreboot_driver *driver)
+{
+ driver->drv.bus = &coreboot_bus_type;
+
+ return driver_register(&driver->drv);
+}
+EXPORT_SYMBOL(coreboot_driver_register);
+
+void coreboot_driver_unregister(struct coreboot_driver *driver)
+{
+ driver_unregister(&driver->drv);
+}
+EXPORT_SYMBOL(coreboot_driver_unregister);
+
/*
* This function parses the coreboot table for an entry that contains the base
* address of the given entry tag. The coreboot table consists of a header
@@ -73,18 +140,58 @@ int coreboot_table_find(int tag, void *data, size_t data_size)
}
EXPORT_SYMBOL(coreboot_table_find);

-int coreboot_table_init(void __iomem *ptr)
+int coreboot_table_init(struct device *dev, void __iomem *ptr)
{
+ int i, ret;
+ void *ptr_entry;
+ struct coreboot_device *device;
+ struct coreboot_table_entry entry;
+ struct coreboot_table_header header;
+
ptr_header = ptr;
+ memcpy_fromio(&header, ptr_header, sizeof(header));

- return 0;
+ if (strncmp(header.signature, "LBIO", sizeof(header.signature))) {
+ pr_warn("coreboot_table: coreboot table missing or corrupt!\n");
+ return -ENODEV;
+ }
+
+ ptr_entry = (void *)ptr_header + header.header_bytes;
+ for (i = 0; i < header.table_entries; i++) {
+ memcpy_fromio(&entry, ptr_entry, sizeof(entry));
+
+ device = kzalloc(sizeof(struct device) + entry.size, GFP_KERNEL);
+ if (!device) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ dev_set_name(&device->dev, "coreboot%d", i);
+ device->dev.parent = dev;
+ device->dev.bus = &coreboot_bus_type;
+ device->dev.release = coreboot_device_release;
+ memcpy_fromio(&device->entry, ptr_entry, entry.size);
+
+ ret = device_register(&device->dev);
+ if (ret) {
+ put_device(&device->dev);
+ break;
+ }
+
+ ptr_entry += entry.size;
+ }
+
+ return ret;
}
EXPORT_SYMBOL(coreboot_table_init);

int coreboot_table_exit(void)
{
- if (ptr_header)
+ if (ptr_header) {
+ bus_unregister(&coreboot_bus_type);
iounmap(ptr_header);
+ ptr_header = NULL;
+ }

return 0;
}
diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h
index 6eff1ae0c5d3..88e6a1c06028 100644
--- a/drivers/firmware/google/coreboot_table.h
+++ b/drivers/firmware/google/coreboot_table.h
@@ -4,6 +4,7 @@
* Internal header for coreboot table access.
*
* Copyright 2017 Google Inc.
+ * Copyright 2017 Samuel Holland <[email protected]>
*
* 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
@@ -20,14 +21,6 @@

#include <linux/io.h>

-/* List of coreboot entry structures that is used */
-struct lb_cbmem_ref {
- uint32_t tag;
- uint32_t size;
-
- uint64_t cbmem_addr;
-};
-
/* Coreboot table header structure */
struct coreboot_table_header {
char signature[4];
@@ -38,11 +31,49 @@ struct coreboot_table_header {
u32 table_entries;
};

+/* List of coreboot entry structures that is used */
+/* Generic */
+struct coreboot_table_entry {
+ u32 tag;
+ u32 size;
+};
+
+/* Points to a CBMEM entry */
+struct lb_cbmem_ref {
+ u32 tag;
+ u32 size;
+
+ u64 cbmem_addr;
+};
+
+/* A device, additionally with information from coreboot. */
+struct coreboot_device {
+ struct device dev;
+ union {
+ struct coreboot_table_entry entry;
+ struct lb_cbmem_ref cbmem_ref;
+ };
+};
+
+/* A driver for handling devices described in coreboot tables. */
+struct coreboot_driver {
+ int (*probe)(struct coreboot_device *);
+ int (*remove)(struct coreboot_device *);
+ struct device_driver drv;
+ u32 tag;
+};
+
+/* Register a driver that uses the data from a coreboot table. */
+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);
+
/* Retrieve coreboot table entry with tag *tag* and copy it to data */
int coreboot_table_find(int tag, void *data, size_t data_size);

/* Initialize coreboot table module given a pointer to iomem */
-int coreboot_table_init(void __iomem *ptr);
+int coreboot_table_init(struct device *dev, void __iomem *ptr);

/* Cleanup coreboot table module */
int coreboot_table_exit(void);
--
2.13.6


2018-03-14 18:12:35

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 0/5] coreboot table bus and framebuffer driver

On Wed, Jan 24, 2018 at 07:41:15PM -0600, Samuel Holland wrote:
> On many systems, coreboot[1] firmware can initialize graphics hardware
> and set up a high-resolution linear framebuffer. It exports information
> about this framebuffer, along with various other information, in a table
> discoverable via ACPI or a device tree.
>
> coreboot also supports booting Linux directly from flash as a "payload".
> Projects such as Heads[2], u-root[3], and petitboot[4] provide a minimal
> userland that can then be used to chainload (via kexec) into a full
> Linux system loaded from disk or over the network.
>
> Fitting even a minimal Linux system on an SPI flash chip is challenging.
> Reusing the framebuffer setup from coreboot provides an enormous benefit
> to these projects by allowing them to omit full graphics drivers from
> their kernel builds. It also speeds up boot times by avoiding duplicated
> effort, and because coreboot's graphics initialization is often much
> faster than the Linux driver.
>
> Patch 1 of this series expands coreboot table support into an enumerable
> bus that devices can hang off of. Patches 2-3 convert the existing
> drivers to use the new bus structure instead of ad-hoc platform devices,
> and patch 4 removes the old coreboot_table_find function.
>
> Finally, patch 5 adds a new driver for the coreboot-initialized
> framebuffer. It improves on earlier work[5] by being architecture-
> independent and not needing to scan through low memory.
>
> This patchset has been tested on a Lenovo ThinkPad X220, and earlier
> versions of these patches have been tested by various members of the
> coreboot community on other hardware.

It would be great to get some of the google developers to ack these, as
this touches their code...

thanks,

greg k-h

2018-03-14 21:24:35

by Julius Werner

[permalink] [raw]
Subject: Re: [PATCH 0/5] coreboot table bus and framebuffer driver

[resend in plain text]

> It would be great to get some of the google developers to ack these, as
> this touches their code...

From the coreboot point of view I guess we're fine with it since it claims
to maintain all of the existing functionality. It's just changing the
kernel-level plumbing for these drivers and I don't really have the
expertise to comment on whether this is better or worse than the old code
(maybe Dmitry or Guenter will?). It seems a little odd to me to call this a
"bus", but if we think that's the most fitting abstraction the kernel has
for it, I'm okay with that. All I care about is that it will work (in all
combinations... e.g. regardless of probe order and even if some parts are
compiled as modules and loaded/unloaded at runtime).

2018-04-23 11:39:51

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 0/5] coreboot table bus and framebuffer driver

On Wed, Mar 14, 2018 at 09:22:04PM +0000, Julius Werner wrote:
> [resend in plain text]
>
> > It would be great to get some of the google developers to ack these, as
> > this touches their code...
>
> From the coreboot point of view I guess we're fine with it since it claims
> to maintain all of the existing functionality. It's just changing the
> kernel-level plumbing for these drivers and I don't really have the
> expertise to comment on whether this is better or worse than the old code
> (maybe Dmitry or Guenter will?). It seems a little odd to me to call this a
> "bus", but if we think that's the most fitting abstraction the kernel has
> for it, I'm okay with that. All I care about is that it will work (in all
> combinations... e.g. regardless of probe order and even if some parts are
> compiled as modules and loaded/unloaded at runtime).

Thanks for the response, patches are all now queued up.

greg k-h