CHROMIUM: google memconsole: separate coreboot related functions
Separate coreboot related functions to coreboot_table.c to provide common methods for other firmware drivers. BUG=chrome-os-partner:39945 TEST=`emerge-oak chromeos-kernel-3_18` Signed-off-by: Wei-Ning Huang <wnhuang@google.com> Reviewed-on: https://chromium-review.googlesource.com/285380 Reviewed-by: Daniel Kurtz <djkurtz@chromium.org> Commit-Queue: Wei-Ning Huang <wnhuang@chromium.org> Tested-by: Wei-Ning Huang <wnhuang@chromium.org> (cherry picked from commit cc27c869c48c80ec7d89629f6cf112ef89818c78) Change-Id: Ie71f246d958c77b0721918167933de026d161bcb Reviewed-on: https://chromium-review.googlesource.com/294777 Reviewed-by: Yuji Sasaki <sasakiy@google.com> Reviewed-by: Wei-Ning Huang <wnhuang@chromium.org> Commit-Queue: Yuji Sasaki <sasakiy@google.com> Tested-by: Yuji Sasaki <sasakiy@google.com>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
741fd2ba11
commit
33bc892778
@@ -19,6 +19,13 @@ config GOOGLE_SMI
|
||||
driver provides an interface for reading and writing NVRAM
|
||||
variables.
|
||||
|
||||
config GOOGLE_COREBOOT_TABLE
|
||||
tristate "Coreboot Table Access"
|
||||
depends on OF
|
||||
help
|
||||
This option enable the coreboot_table module, which provide other
|
||||
firmware modules to access coreboot table.
|
||||
|
||||
config GOOGLE_MEMCONSOLE_X86
|
||||
tristate "Firmware Memory Console - X86"
|
||||
depends on X86 && ACPI && DMI
|
||||
@@ -29,7 +36,7 @@ config GOOGLE_MEMCONSOLE_X86
|
||||
|
||||
config GOOGLE_MEMCONSOLE_OF
|
||||
tristate "Firmware Memory Console - OF"
|
||||
depends on OF
|
||||
depends on GOOGLE_COREBOOT_TABLE
|
||||
help
|
||||
This option enables the kernel to search for a firmware log on
|
||||
coreboot platforms using device tree. If found, this log is exported
|
||||
|
||||
@@ -3,6 +3,7 @@ memc-x86-y := memconsole-x86.o memconsole.o
|
||||
vpd-sysfs-y := vpd.o vpd_decode.o
|
||||
|
||||
obj-$(CONFIG_GOOGLE_SMI) += gsmi.o
|
||||
obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o
|
||||
obj-$(CONFIG_GOOGLE_MEMCONSOLE_OF) += memc-of.o
|
||||
obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86) += memc-x86.o
|
||||
obj-$(CONFIG_GOOGLE_VPD) += vpd-sysfs.o
|
||||
|
||||
145
drivers/firmware/google/coreboot_table.c
Normal file
145
drivers/firmware/google/coreboot_table.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* coreboot_table.c: module providing coreboot table access.
|
||||
*
|
||||
* Copyright 2015 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 <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct coreboot_table_header {
|
||||
char signature[4];
|
||||
u32 header_bytes;
|
||||
u32 header_checksum;
|
||||
u32 table_bytes;
|
||||
u32 table_checksum;
|
||||
u32 table_entries;
|
||||
};
|
||||
|
||||
struct coreboot_table_entry {
|
||||
u32 tag;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
static struct coreboot_table_header __iomem *ptr_header =
|
||||
(void*)(-EPROBE_DEFER);
|
||||
|
||||
/*
|
||||
* 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 (IS_ERR(ptr_header))
|
||||
return PTR_ERR(ptr_header);
|
||||
|
||||
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 0;
|
||||
}
|
||||
EXPORT_SYMBOL(coreboot_table_find);
|
||||
|
||||
static int coreboot_table_of_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct device_node* fw_dn;
|
||||
|
||||
fw_dn = of_find_compatible_node(NULL, NULL, "coreboot");
|
||||
if (!fw_dn) {
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ptr_header = of_iomap(fw_dn, 0);
|
||||
of_node_put(fw_dn);
|
||||
|
||||
if (!ptr_header) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
ptr_header = ERR_PTR(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coreboot_table_of_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (!IS_ERR(ptr_header))
|
||||
iounmap(ptr_header);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver coreboot_table_driver = {
|
||||
.probe = coreboot_table_of_probe,
|
||||
.remove = coreboot_table_of_remove,
|
||||
.driver = {
|
||||
.name = "coreboot_table",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init platform_coreboot_table_init(void)
|
||||
{
|
||||
struct platform_device* pdev;
|
||||
int ret = 0;
|
||||
|
||||
pdev = platform_device_register_simple("coreboot_table", -1, NULL, 0);
|
||||
if (pdev == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&coreboot_table_driver);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
ptr_header = ERR_PTR(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
module_init(platform_coreboot_table_init);
|
||||
|
||||
MODULE_AUTHOR("Google, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
32
drivers/firmware/google/coreboot_table.h
Normal file
32
drivers/firmware/google/coreboot_table.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* coreboot_table.c: Internal header for coreboot table access.
|
||||
*
|
||||
* Copyright 2015 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.
|
||||
*/
|
||||
|
||||
#ifndef __COREBOOT_TABLE_H
|
||||
#define __COREBOOT_TABLE_H
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* List of coreboot entry structures that is used */
|
||||
struct lb_cbmem_ref {
|
||||
uint32_t tag;
|
||||
uint32_t size;
|
||||
|
||||
uint64_t cbmem_addr;
|
||||
};
|
||||
|
||||
/* Retrieve coreboot table entry with tag *tag* and copy it to data */
|
||||
int coreboot_table_find(int tag, void *data, size_t data_size);
|
||||
|
||||
#endif /* __COREBOOT_TABLE_H */
|
||||
@@ -11,79 +11,22 @@
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "memconsole.h"
|
||||
#include "coreboot_table.h"
|
||||
|
||||
#define CB_TAG_CBMEM_CONSOLE 0x17
|
||||
|
||||
struct coreboot_table_header {
|
||||
char signature[4];
|
||||
u32 header_bytes;
|
||||
u32 header_checksum;
|
||||
u32 table_bytes;
|
||||
u32 table_checksum;
|
||||
u32 table_entries;
|
||||
};
|
||||
|
||||
struct coreboot_table_entry {
|
||||
u32 tag;
|
||||
u32 size;
|
||||
u64 physaddr;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function parses the coreboot table for an entry that contains the base
|
||||
* address of the firmware console. 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.
|
||||
*/
|
||||
static bool memconsole_find(struct platform_device *pdev)
|
||||
{
|
||||
bool ret = false;
|
||||
struct coreboot_table_header __iomem header;
|
||||
struct coreboot_table_header *ptr_header;
|
||||
struct coreboot_table_entry __iomem entry;
|
||||
struct coreboot_table_entry *ptr_entry;
|
||||
int i;
|
||||
struct device_node *coreboot_node = pdev->dev.of_node;
|
||||
|
||||
if (!coreboot_node)
|
||||
return false;
|
||||
|
||||
ptr_header = of_iomap(coreboot_node, 0);
|
||||
if (!ptr_header)
|
||||
goto out_node;
|
||||
|
||||
memcpy_fromio(&header, ptr_header, sizeof(header));
|
||||
|
||||
if (strncmp(header.signature, "LBIO", sizeof(header.signature))) {
|
||||
|
||||
pr_warn("memconsole: coreboot table missing or corrupt!\n");
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
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 == CB_TAG_CBMEM_CONSOLE) {
|
||||
ret = memconsole_coreboot_init(entry.physaddr);
|
||||
break;
|
||||
}
|
||||
|
||||
ptr_entry = (void *)ptr_entry + entry.size;
|
||||
}
|
||||
|
||||
out_unmap:
|
||||
iounmap(ptr_header);
|
||||
out_node:
|
||||
of_node_put(coreboot_node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int memconsole_of_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (!memconsole_find(pdev))
|
||||
return -ENODEV;
|
||||
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();
|
||||
}
|
||||
@@ -104,19 +47,11 @@ static struct platform_driver memconsole_driver = {
|
||||
|
||||
static int __init platform_memconsole_init(void)
|
||||
{
|
||||
struct device_node *fw_dn;
|
||||
struct platform_device *pdev;
|
||||
|
||||
/*
|
||||
* Coreboot systems with OF support might have memconsole.
|
||||
* memconsole_find checks to see if CB_TAG_CBMEM_CONSOLE entry is found.
|
||||
*/
|
||||
fw_dn = of_find_compatible_node(NULL, NULL, "coreboot");
|
||||
if (!fw_dn)
|
||||
return -ENODEV;
|
||||
|
||||
pdev = platform_device_register_simple("memconsole", -1, NULL, 0);
|
||||
pdev->dev.of_node = fw_dn;
|
||||
if (pdev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
platform_driver_register(&memconsole_driver);
|
||||
|
||||
|
||||
@@ -243,11 +243,11 @@ static bool __init memconsole_find(void)
|
||||
|
||||
if (coreboot_system) {
|
||||
physaddr = get_address_from_acpi(CBMEM_CONSOLE_ACPI_NAME);
|
||||
if (physaddr && memconsole_coreboot_init(physaddr))
|
||||
if (physaddr && memconsole_coreboot_init(physaddr) == 0)
|
||||
return true;
|
||||
|
||||
physaddr = check_cbmem();
|
||||
if (physaddr && memconsole_coreboot_init(physaddr))
|
||||
if (physaddr && memconsole_coreboot_init(physaddr) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,14 +44,14 @@ void memconsole_setup(void *baseaddr, size_t length)
|
||||
}
|
||||
EXPORT_SYMBOL(memconsole_setup);
|
||||
|
||||
bool memconsole_coreboot_init(phys_addr_t physaddr)
|
||||
int memconsole_coreboot_init(phys_addr_t physaddr)
|
||||
{
|
||||
struct cbmem_cons __iomem *tmp_cbmc;
|
||||
|
||||
tmp_cbmc = ioremap_cache(physaddr, sizeof(*tmp_cbmc));
|
||||
|
||||
if (tmp_cbmc == NULL)
|
||||
return false;
|
||||
return -ENOMEM;
|
||||
|
||||
cbmem_console = ioremap_cache(physaddr, tmp_cbmc->buffer_size +
|
||||
sizeof(*cbmem_console)); /* Don't forget counting the header. */
|
||||
@@ -59,11 +59,11 @@ bool memconsole_coreboot_init(phys_addr_t physaddr)
|
||||
iounmap(tmp_cbmc);
|
||||
|
||||
if (cbmem_console == NULL)
|
||||
return false;
|
||||
return -ENOMEM;
|
||||
|
||||
memconsole_setup(cbmem_console->buffer_body,
|
||||
min(cbmem_console->buffer_cursor, cbmem_console->buffer_size));
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(memconsole_coreboot_init);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Initialize the memory console given physical address of console buffer */
|
||||
bool memconsole_coreboot_init(phys_addr_t physaddr);
|
||||
int memconsole_coreboot_init(phys_addr_t physaddr);
|
||||
|
||||
/* Initialize the memory console from raw (virtual) base address and length. */
|
||||
void memconsole_setup(void *baseaddr, size_t length);
|
||||
|
||||
Reference in New Issue
Block a user