x86: qemu: split qfw command interface and qfw core

This patch splits qfw command interface and qfw core function into two
files, and introduces a new Kconfig option (CONFIG_QFW) for qfw core.

Now when qfw command interface is enabled, it will automatically select
qfw core. This patch also makes the ACPI table generation select
CONFIG_QFW.

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
Miao Yan 2016-05-22 19:37:14 -07:00 committed by Bin Meng
parent d3ad062392
commit fcf5c04193
10 changed files with 200 additions and 177 deletions

View File

@ -439,7 +439,7 @@ config GENERATE_MP_TABLE
config GENERATE_ACPI_TABLE config GENERATE_ACPI_TABLE
bool "Generate an ACPI (Advanced Configuration and Power Interface) table" bool "Generate an ACPI (Advanced Configuration and Power Interface) table"
default n default n
select CMD_QEMU_FW_CFG if QEMU select QFW if QEMU
help help
The Advanced Configuration and Power Interface (ACPI) specification The Advanced Configuration and Power Interface (ACPI) specification
provides an open standard for device configuration and management provides an open standard for device configuration and management

View File

@ -420,7 +420,7 @@ static int init_bsp(struct udevice **devp)
return 0; return 0;
} }
#ifdef CONFIG_QEMU #ifdef CONFIG_QFW
static int qemu_cpu_fixup(void) static int qemu_cpu_fixup(void)
{ {
int ret; int ret;
@ -496,7 +496,7 @@ int mp_init(struct mp_params *p)
if (ret) if (ret)
return ret; return ret;
#ifdef CONFIG_QEMU #ifdef CONFIG_QFW
ret = qemu_cpu_fixup(); ret = qemu_cpu_fixup();
if (ret) if (ret)
return ret; return ret;

View File

@ -7,5 +7,6 @@
ifndef CONFIG_EFI_STUB ifndef CONFIG_EFI_STUB
obj-y += car.o dram.o obj-y += car.o dram.o
endif endif
obj-y += cpu.o qemu.o obj-y += qemu.o
obj-$(CONFIG_QFW) += cpu.o
obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o

View File

@ -88,7 +88,9 @@ static void qemu_chipset_init(void)
enable_pm_ich9(); enable_pm_ich9();
} }
#ifdef CONFIG_QFW
qemu_fwcfg_init(); qemu_fwcfg_init();
#endif
} }
int arch_cpu_init(void) int arch_cpu_init(void)

View File

@ -596,6 +596,7 @@ config CMD_SOUND
config CMD_QEMU_FW_CFG config CMD_QEMU_FW_CFG
bool "qfw" bool "qfw"
depends on X86 depends on X86
select QFW
help help
This provides access to the QEMU firmware interface. The main This provides access to the QEMU firmware interface. The main
feature is to allow easy loading of files passed to qemu-system feature is to allow easy loading of files passed to qemu-system

View File

@ -105,7 +105,7 @@ endif
obj-y += pcmcia.o obj-y += pcmcia.o
obj-$(CONFIG_CMD_PORTIO) += portio.o obj-$(CONFIG_CMD_PORTIO) += portio.o
obj-$(CONFIG_CMD_PXE) += pxe.o obj-$(CONFIG_CMD_PXE) += pxe.o
obj-$(CONFIG_CMD_QEMU_FW_CFG) += qemu_fw_cfg.o obj-$(CONFIG_CMD_QEMU_FW_CFG) += qfw.o
obj-$(CONFIG_CMD_READ) += read.o obj-$(CONFIG_CMD_READ) += read.o
obj-$(CONFIG_CMD_REGINFO) += reginfo.o obj-$(CONFIG_CMD_REGINFO) += reginfo.o
obj-$(CONFIG_CMD_REISER) += reiser.o obj-$(CONFIG_CMD_REISER) += reiser.o

View File

@ -7,90 +7,7 @@
#include <common.h> #include <common.h>
#include <command.h> #include <command.h>
#include <errno.h> #include <errno.h>
#include <malloc.h>
#include <qemu_fw_cfg.h> #include <qemu_fw_cfg.h>
#include <asm/io.h>
#include <linux/list.h>
static bool fwcfg_present;
static bool fwcfg_dma_present;
static LIST_HEAD(fw_list);
/* Read configuration item using fw_cfg PIO interface */
static void qemu_fwcfg_read_entry_pio(uint16_t entry,
uint32_t size, void *address)
{
uint32_t i = 0;
uint8_t *data = address;
/*
* writting FW_CFG_INVALID will cause read operation to resume at
* last offset, otherwise read will start at offset 0
*/
if (entry != FW_CFG_INVALID)
outw(entry, FW_CONTROL_PORT);
while (size--)
data[i++] = inb(FW_DATA_PORT);
}
/* Read configuration item using fw_cfg DMA interface */
static void qemu_fwcfg_read_entry_dma(uint16_t entry,
uint32_t size, void *address)
{
struct fw_cfg_dma_access dma;
dma.length = cpu_to_be32(size);
dma.address = cpu_to_be64((uintptr_t)address);
dma.control = cpu_to_be32(FW_CFG_DMA_READ);
/*
* writting FW_CFG_INVALID will cause read operation to resume at
* last offset, otherwise read will start at offset 0
*/
if (entry != FW_CFG_INVALID)
dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16));
barrier();
debug("qemu_fwcfg_dma_read_entry: addr %p, length %u control 0x%x\n",
address, size, be32_to_cpu(dma.control));
outl(cpu_to_be32((uint32_t)&dma), FW_DMA_PORT_HIGH);
while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR)
__asm__ __volatile__ ("pause");
}
bool qemu_fwcfg_present(void)
{
return fwcfg_present;
}
bool qemu_fwcfg_dma_present(void)
{
return fwcfg_dma_present;
}
void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address)
{
if (fwcfg_dma_present)
qemu_fwcfg_read_entry_dma(entry, length, address);
else
qemu_fwcfg_read_entry_pio(entry, length, address);
}
int qemu_fwcfg_online_cpus(void)
{
uint16_t nb_cpus;
if (!fwcfg_present)
return -ENODEV;
qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
return le16_to_cpu(nb_cpus);
}
/* /*
* This function prepares kernel for zboot. It loads kernel data * This function prepares kernel for zboot. It loads kernel data
@ -155,76 +72,6 @@ static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr)
return 0; return 0;
} }
int qemu_fwcfg_read_firmware_list(void)
{
int i;
uint32_t count;
struct fw_file *file;
struct list_head *entry;
/* don't read it twice */
if (!list_empty(&fw_list))
return 0;
qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
if (!count)
return 0;
count = be32_to_cpu(count);
for (i = 0; i < count; i++) {
file = malloc(sizeof(*file));
if (!file) {
printf("error: allocating resource\n");
goto err;
}
qemu_fwcfg_read_entry(FW_CFG_INVALID,
sizeof(struct fw_cfg_file), &file->cfg);
file->addr = 0;
list_add_tail(&file->list, &fw_list);
}
return 0;
err:
list_for_each(entry, &fw_list) {
file = list_entry(entry, struct fw_file, list);
free(file);
}
return -ENOMEM;
}
struct fw_file *qemu_fwcfg_find_file(const char *name)
{
struct list_head *entry;
struct fw_file *file;
list_for_each(entry, &fw_list) {
file = list_entry(entry, struct fw_file, list);
if (!strcmp(file->cfg.name, name))
return file;
}
return NULL;
}
struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter)
{
iter->entry = fw_list.next;
return list_entry(iter->entry, struct fw_file, list);
}
struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter)
{
iter->entry = iter->entry->next;
return list_entry(iter->entry, struct fw_file, list);
}
bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter)
{
return iter->entry == &fw_list;
}
static int qemu_fwcfg_list_firmware(void) static int qemu_fwcfg_list_firmware(void)
{ {
int ret; int ret;
@ -246,25 +93,6 @@ static int qemu_fwcfg_list_firmware(void)
return 0; return 0;
} }
void qemu_fwcfg_init(void)
{
uint32_t qemu;
uint32_t dma_enabled;
fwcfg_present = false;
fwcfg_dma_present = false;
qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
fwcfg_present = true;
if (fwcfg_present) {
qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
if (dma_enabled & FW_CFG_DMA_ENABLED)
fwcfg_dma_present = true;
}
}
static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag, static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[]) int argc, char * const argv[])
{ {

View File

@ -138,4 +138,10 @@ config WINBOND_W83627
legacy UART or other devices in the Winbond Super IO chips legacy UART or other devices in the Winbond Super IO chips
on X86 platforms. on X86 platforms.
config QFW
bool
help
Hidden option to enable QEMU fw_cfg interface. This will be selected by
either CONFIG_CMD_QEMU_FW_CFG or CONFIG_GENERATE_ACPI_TABLE.
endmenu endmenu

View File

@ -43,3 +43,4 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_RESET) += reset-uclass.o obj-$(CONFIG_RESET) += reset-uclass.o
obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
obj-$(CONFIG_QFW) += qemu_fw_cfg.o

184
drivers/misc/qemu_fw_cfg.c Normal file
View File

@ -0,0 +1,184 @@
/*
* (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <errno.h>
#include <malloc.h>
#include <qemu_fw_cfg.h>
#include <asm/io.h>
#include <linux/list.h>
static bool fwcfg_present;
static bool fwcfg_dma_present;
static LIST_HEAD(fw_list);
/* Read configuration item using fw_cfg PIO interface */
static void qemu_fwcfg_read_entry_pio(uint16_t entry,
uint32_t size, void *address)
{
uint32_t i = 0;
uint8_t *data = address;
/*
* writting FW_CFG_INVALID will cause read operation to resume at
* last offset, otherwise read will start at offset 0
*/
if (entry != FW_CFG_INVALID)
outw(entry, FW_CONTROL_PORT);
while (size--)
data[i++] = inb(FW_DATA_PORT);
}
/* Read configuration item using fw_cfg DMA interface */
static void qemu_fwcfg_read_entry_dma(uint16_t entry,
uint32_t size, void *address)
{
struct fw_cfg_dma_access dma;
dma.length = cpu_to_be32(size);
dma.address = cpu_to_be64((uintptr_t)address);
dma.control = cpu_to_be32(FW_CFG_DMA_READ);
/*
* writting FW_CFG_INVALID will cause read operation to resume at
* last offset, otherwise read will start at offset 0
*/
if (entry != FW_CFG_INVALID)
dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16));
barrier();
debug("qemu_fwcfg_dma_read_entry: addr %p, length %u control 0x%x\n",
address, size, be32_to_cpu(dma.control));
outl(cpu_to_be32((uint32_t)&dma), FW_DMA_PORT_HIGH);
while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR)
__asm__ __volatile__ ("pause");
}
bool qemu_fwcfg_present(void)
{
return fwcfg_present;
}
bool qemu_fwcfg_dma_present(void)
{
return fwcfg_dma_present;
}
void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address)
{
if (fwcfg_dma_present)
qemu_fwcfg_read_entry_dma(entry, length, address);
else
qemu_fwcfg_read_entry_pio(entry, length, address);
}
int qemu_fwcfg_online_cpus(void)
{
uint16_t nb_cpus;
if (!fwcfg_present)
return -ENODEV;
qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
return le16_to_cpu(nb_cpus);
}
int qemu_fwcfg_read_firmware_list(void)
{
int i;
uint32_t count;
struct fw_file *file;
struct list_head *entry;
/* don't read it twice */
if (!list_empty(&fw_list))
return 0;
qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
if (!count)
return 0;
count = be32_to_cpu(count);
for (i = 0; i < count; i++) {
file = malloc(sizeof(*file));
if (!file) {
printf("error: allocating resource\n");
goto err;
}
qemu_fwcfg_read_entry(FW_CFG_INVALID,
sizeof(struct fw_cfg_file), &file->cfg);
file->addr = 0;
list_add_tail(&file->list, &fw_list);
}
return 0;
err:
list_for_each(entry, &fw_list) {
file = list_entry(entry, struct fw_file, list);
free(file);
}
return -ENOMEM;
}
struct fw_file *qemu_fwcfg_find_file(const char *name)
{
struct list_head *entry;
struct fw_file *file;
list_for_each(entry, &fw_list) {
file = list_entry(entry, struct fw_file, list);
if (!strcmp(file->cfg.name, name))
return file;
}
return NULL;
}
struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter)
{
iter->entry = fw_list.next;
return list_entry((struct list_head *)iter->entry,
struct fw_file, list);
}
struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter)
{
iter->entry = ((struct list_head *)iter->entry)->next;
return list_entry((struct list_head *)iter->entry,
struct fw_file, list);
}
bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter)
{
return iter->entry == &fw_list;
}
void qemu_fwcfg_init(void)
{
uint32_t qemu;
uint32_t dma_enabled;
fwcfg_present = false;
fwcfg_dma_present = false;
qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
fwcfg_present = true;
if (fwcfg_present) {
qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
if (dma_enabled & FW_CFG_DMA_ENABLED)
fwcfg_dma_present = true;
}
}