1 // SPDX-License-Identifier: GPL-2.0-only
5 * Module providing coreboot table access.
7 * Copyright 2017 Google Inc.
8 * Copyright 2017 Samuel Holland <samuel@sholland.org>
11 #include <linux/acpi.h>
12 #include <linux/device.h>
13 #include <linux/err.h>
14 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
22 #include "coreboot_table.h"
24 #define CB_DEV(d) container_of(d, struct coreboot_device, dev)
25 #define CB_DRV(d) container_of(d, struct coreboot_driver, drv)
27 static int coreboot_bus_match(struct device
*dev
, struct device_driver
*drv
)
29 struct coreboot_device
*device
= CB_DEV(dev
);
30 struct coreboot_driver
*driver
= CB_DRV(drv
);
32 return device
->entry
.tag
== driver
->tag
;
35 static int coreboot_bus_probe(struct device
*dev
)
38 struct coreboot_device
*device
= CB_DEV(dev
);
39 struct coreboot_driver
*driver
= CB_DRV(dev
->driver
);
42 ret
= driver
->probe(device
);
47 static int coreboot_bus_remove(struct device
*dev
)
50 struct coreboot_device
*device
= CB_DEV(dev
);
51 struct coreboot_driver
*driver
= CB_DRV(dev
->driver
);
54 ret
= driver
->remove(device
);
59 static struct bus_type coreboot_bus_type
= {
61 .match
= coreboot_bus_match
,
62 .probe
= coreboot_bus_probe
,
63 .remove
= coreboot_bus_remove
,
66 static void coreboot_device_release(struct device
*dev
)
68 struct coreboot_device
*device
= CB_DEV(dev
);
73 int coreboot_driver_register(struct coreboot_driver
*driver
)
75 driver
->drv
.bus
= &coreboot_bus_type
;
77 return driver_register(&driver
->drv
);
79 EXPORT_SYMBOL(coreboot_driver_register
);
81 void coreboot_driver_unregister(struct coreboot_driver
*driver
)
83 driver_unregister(&driver
->drv
);
85 EXPORT_SYMBOL(coreboot_driver_unregister
);
87 static int coreboot_table_populate(struct device
*dev
, void *ptr
)
91 struct coreboot_device
*device
;
92 struct coreboot_table_entry
*entry
;
93 struct coreboot_table_header
*header
= ptr
;
95 ptr_entry
= ptr
+ header
->header_bytes
;
96 for (i
= 0; i
< header
->table_entries
; i
++) {
99 device
= kzalloc(sizeof(struct device
) + entry
->size
, GFP_KERNEL
);
103 dev_set_name(&device
->dev
, "coreboot%d", i
);
104 device
->dev
.parent
= dev
;
105 device
->dev
.bus
= &coreboot_bus_type
;
106 device
->dev
.release
= coreboot_device_release
;
107 memcpy(&device
->entry
, ptr_entry
, entry
->size
);
109 ret
= device_register(&device
->dev
);
111 put_device(&device
->dev
);
115 ptr_entry
+= entry
->size
;
121 static int coreboot_table_probe(struct platform_device
*pdev
)
124 struct coreboot_table_header
*header
;
125 struct resource
*res
;
126 struct device
*dev
= &pdev
->dev
;
130 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
134 len
= resource_size(res
);
135 if (!res
->start
|| !len
)
138 /* Check just the header first to make sure things are sane */
139 header
= memremap(res
->start
, sizeof(*header
), MEMREMAP_WB
);
143 len
= header
->header_bytes
+ header
->table_bytes
;
144 ret
= strncmp(header
->signature
, "LBIO", sizeof(header
->signature
));
147 dev_warn(dev
, "coreboot table missing or corrupt!\n");
151 ptr
= memremap(res
->start
, len
, MEMREMAP_WB
);
155 ret
= bus_register(&coreboot_bus_type
);
157 ret
= coreboot_table_populate(dev
, ptr
);
159 bus_unregister(&coreboot_bus_type
);
166 static int __cb_dev_unregister(struct device
*dev
, void *dummy
)
168 device_unregister(dev
);
172 static int coreboot_table_remove(struct platform_device
*pdev
)
174 bus_for_each_dev(&coreboot_bus_type
, NULL
, NULL
, __cb_dev_unregister
);
175 bus_unregister(&coreboot_bus_type
);
180 static const struct acpi_device_id cros_coreboot_acpi_match
[] = {
185 MODULE_DEVICE_TABLE(acpi
, cros_coreboot_acpi_match
);
189 static const struct of_device_id coreboot_of_match
[] = {
190 { .compatible
= "coreboot" },
193 MODULE_DEVICE_TABLE(of
, coreboot_of_match
);
196 static struct platform_driver coreboot_table_driver
= {
197 .probe
= coreboot_table_probe
,
198 .remove
= coreboot_table_remove
,
200 .name
= "coreboot_table",
201 .acpi_match_table
= ACPI_PTR(cros_coreboot_acpi_match
),
202 .of_match_table
= of_match_ptr(coreboot_of_match
),
205 module_platform_driver(coreboot_table_driver
);
206 MODULE_AUTHOR("Google, Inc.");
207 MODULE_LICENSE("GPL");