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:
Wei-Ning Huang
2015-07-14 11:23:58 +08:00
committed by ChromeOS Commit Bot
parent 741fd2ba11
commit 33bc892778
8 changed files with 206 additions and 86 deletions

View File

@@ -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

View File

@@ -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

View 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");

View 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 */

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);