root/drivers/firmware/google/coreboot_table.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. coreboot_bus_match
  2. coreboot_bus_probe
  3. coreboot_bus_remove
  4. coreboot_device_release
  5. coreboot_driver_register
  6. coreboot_driver_unregister
  7. coreboot_table_populate
  8. coreboot_table_probe
  9. coreboot_table_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * coreboot_table.c
   4  *
   5  * Module providing coreboot table access.
   6  *
   7  * Copyright 2017 Google Inc.
   8  * Copyright 2017 Samuel Holland <samuel@sholland.org>
   9  */
  10 
  11 #include <linux/acpi.h>
  12 #include <linux/device.h>
  13 #include <linux/err.h>
  14 #include <linux/init.h>
  15 #include <linux/io.h>
  16 #include <linux/kernel.h>
  17 #include <linux/module.h>
  18 #include <linux/of.h>
  19 #include <linux/platform_device.h>
  20 #include <linux/slab.h>
  21 
  22 #include "coreboot_table.h"
  23 
  24 #define CB_DEV(d) container_of(d, struct coreboot_device, dev)
  25 #define CB_DRV(d) container_of(d, struct coreboot_driver, drv)
  26 
  27 static int coreboot_bus_match(struct device *dev, struct device_driver *drv)
  28 {
  29         struct coreboot_device *device = CB_DEV(dev);
  30         struct coreboot_driver *driver = CB_DRV(drv);
  31 
  32         return device->entry.tag == driver->tag;
  33 }
  34 
  35 static int coreboot_bus_probe(struct device *dev)
  36 {
  37         int ret = -ENODEV;
  38         struct coreboot_device *device = CB_DEV(dev);
  39         struct coreboot_driver *driver = CB_DRV(dev->driver);
  40 
  41         if (driver->probe)
  42                 ret = driver->probe(device);
  43 
  44         return ret;
  45 }
  46 
  47 static int coreboot_bus_remove(struct device *dev)
  48 {
  49         int ret = 0;
  50         struct coreboot_device *device = CB_DEV(dev);
  51         struct coreboot_driver *driver = CB_DRV(dev->driver);
  52 
  53         if (driver->remove)
  54                 ret = driver->remove(device);
  55 
  56         return ret;
  57 }
  58 
  59 static struct bus_type coreboot_bus_type = {
  60         .name           = "coreboot",
  61         .match          = coreboot_bus_match,
  62         .probe          = coreboot_bus_probe,
  63         .remove         = coreboot_bus_remove,
  64 };
  65 
  66 static void coreboot_device_release(struct device *dev)
  67 {
  68         struct coreboot_device *device = CB_DEV(dev);
  69 
  70         kfree(device);
  71 }
  72 
  73 int coreboot_driver_register(struct coreboot_driver *driver)
  74 {
  75         driver->drv.bus = &coreboot_bus_type;
  76 
  77         return driver_register(&driver->drv);
  78 }
  79 EXPORT_SYMBOL(coreboot_driver_register);
  80 
  81 void coreboot_driver_unregister(struct coreboot_driver *driver)
  82 {
  83         driver_unregister(&driver->drv);
  84 }
  85 EXPORT_SYMBOL(coreboot_driver_unregister);
  86 
  87 static int coreboot_table_populate(struct device *dev, void *ptr)
  88 {
  89         int i, ret;
  90         void *ptr_entry;
  91         struct coreboot_device *device;
  92         struct coreboot_table_entry *entry;
  93         struct coreboot_table_header *header = ptr;
  94 
  95         ptr_entry = ptr + header->header_bytes;
  96         for (i = 0; i < header->table_entries; i++) {
  97                 entry = ptr_entry;
  98 
  99                 device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL);
 100                 if (!device)
 101                         return -ENOMEM;
 102 
 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);
 108 
 109                 ret = device_register(&device->dev);
 110                 if (ret) {
 111                         put_device(&device->dev);
 112                         return ret;
 113                 }
 114 
 115                 ptr_entry += entry->size;
 116         }
 117 
 118         return 0;
 119 }
 120 
 121 static int coreboot_table_probe(struct platform_device *pdev)
 122 {
 123         resource_size_t len;
 124         struct coreboot_table_header *header;
 125         struct resource *res;
 126         struct device *dev = &pdev->dev;
 127         void *ptr;
 128         int ret;
 129 
 130         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 131         if (!res)
 132                 return -EINVAL;
 133 
 134         len = resource_size(res);
 135         if (!res->start || !len)
 136                 return -EINVAL;
 137 
 138         /* Check just the header first to make sure things are sane */
 139         header = memremap(res->start, sizeof(*header), MEMREMAP_WB);
 140         if (!header)
 141                 return -ENOMEM;
 142 
 143         len = header->header_bytes + header->table_bytes;
 144         ret = strncmp(header->signature, "LBIO", sizeof(header->signature));
 145         memunmap(header);
 146         if (ret) {
 147                 dev_warn(dev, "coreboot table missing or corrupt!\n");
 148                 return -ENODEV;
 149         }
 150 
 151         ptr = memremap(res->start, len, MEMREMAP_WB);
 152         if (!ptr)
 153                 return -ENOMEM;
 154 
 155         ret = bus_register(&coreboot_bus_type);
 156         if (!ret) {
 157                 ret = coreboot_table_populate(dev, ptr);
 158                 if (ret)
 159                         bus_unregister(&coreboot_bus_type);
 160         }
 161         memunmap(ptr);
 162 
 163         return ret;
 164 }
 165 
 166 static int coreboot_table_remove(struct platform_device *pdev)
 167 {
 168         bus_unregister(&coreboot_bus_type);
 169         return 0;
 170 }
 171 
 172 #ifdef CONFIG_ACPI
 173 static const struct acpi_device_id cros_coreboot_acpi_match[] = {
 174         { "GOOGCB00", 0 },
 175         { "BOOT0000", 0 },
 176         { }
 177 };
 178 MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match);
 179 #endif
 180 
 181 #ifdef CONFIG_OF
 182 static const struct of_device_id coreboot_of_match[] = {
 183         { .compatible = "coreboot" },
 184         {}
 185 };
 186 MODULE_DEVICE_TABLE(of, coreboot_of_match);
 187 #endif
 188 
 189 static struct platform_driver coreboot_table_driver = {
 190         .probe = coreboot_table_probe,
 191         .remove = coreboot_table_remove,
 192         .driver = {
 193                 .name = "coreboot_table",
 194                 .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match),
 195                 .of_match_table = of_match_ptr(coreboot_of_match),
 196         },
 197 };
 198 module_platform_driver(coreboot_table_driver);
 199 MODULE_AUTHOR("Google, Inc.");
 200 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */