|
|
9ae3a8 |
From 96c218d6936795b087ceb493413221d5058118bc Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Date: Wed, 13 Dec 2017 13:38:36 +0100
|
|
|
9ae3a8 |
Subject: [PATCH 05/41] Implement fw_cfg DMA interface
|
|
|
9ae3a8 |
MIME-Version: 1.0
|
|
|
9ae3a8 |
Content-Type: text/plain; charset=UTF-8
|
|
|
9ae3a8 |
Content-Transfer-Encoding: 8bit
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Message-id: <20171213133912.26176-6-marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: 78358
|
|
|
9ae3a8 |
O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 05/41] Implement fw_cfg DMA interface
|
|
|
9ae3a8 |
Bugzilla: 1411490
|
|
|
9ae3a8 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
From: Marc Marí <markmb@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Based on the specifications on docs/specs/fw_cfg.txt
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
This interface is an addon. The old interface can still be used as usual.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Based on Gerd Hoffman's initial implementation.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Marc Marí <markmb@redhat.com>
|
|
|
9ae3a8 |
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
(cherry picked from commit a4c0d1deb785611c96a455f65ec032976b00b36f)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RHEL: major rewrite due to lack of seperation between the MMIO & IO
|
|
|
9ae3a8 |
introduced in upstream commit
|
|
|
9ae3a8 |
5712db6ae5101db645f71edc393368cd59bfd314 and following commits.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
hw/nvram/fw_cfg.c | 223 ++++++++++++++++++++++++++++++++++++++++++++--
|
|
|
9ae3a8 |
include/hw/nvram/fw_cfg.h | 12 +++
|
|
|
9ae3a8 |
tests/fw_cfg-test.c | 3 +-
|
|
|
9ae3a8 |
3 files changed, 230 insertions(+), 8 deletions(-)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
|
|
|
9ae3a8 |
index 01d4566..85e950c 100644
|
|
|
9ae3a8 |
--- a/hw/nvram/fw_cfg.c
|
|
|
9ae3a8 |
+++ b/hw/nvram/fw_cfg.c
|
|
|
9ae3a8 |
@@ -23,6 +23,7 @@
|
|
|
9ae3a8 |
*/
|
|
|
9ae3a8 |
#include "hw/hw.h"
|
|
|
9ae3a8 |
#include "sysemu/sysemu.h"
|
|
|
9ae3a8 |
+#include "sysemu/dma.h"
|
|
|
9ae3a8 |
#include "hw/isa/isa.h"
|
|
|
9ae3a8 |
#include "hw/nvram/fw_cfg.h"
|
|
|
9ae3a8 |
#include "hw/sysbus.h"
|
|
|
9ae3a8 |
@@ -30,12 +31,22 @@
|
|
|
9ae3a8 |
#include "qemu/error-report.h"
|
|
|
9ae3a8 |
#include "qemu/config-file.h"
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
-#define FW_CFG_SIZE 2
|
|
|
9ae3a8 |
+#define FW_CFG_CTL_SIZE 2
|
|
|
9ae3a8 |
#define FW_CFG_DATA_SIZE 1
|
|
|
9ae3a8 |
#define TYPE_FW_CFG "fw_cfg"
|
|
|
9ae3a8 |
#define FW_CFG_NAME "fw_cfg"
|
|
|
9ae3a8 |
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+/* FW_CFG_VERSION bits */
|
|
|
9ae3a8 |
+#define FW_CFG_VERSION 0x01
|
|
|
9ae3a8 |
+#define FW_CFG_VERSION_DMA 0x02
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+/* FW_CFG_DMA_CONTROL bits */
|
|
|
9ae3a8 |
+#define FW_CFG_DMA_CTL_ERROR 0x01
|
|
|
9ae3a8 |
+#define FW_CFG_DMA_CTL_READ 0x02
|
|
|
9ae3a8 |
+#define FW_CFG_DMA_CTL_SKIP 0x04
|
|
|
9ae3a8 |
+#define FW_CFG_DMA_CTL_SELECT 0x08
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
typedef struct FWCfgEntry {
|
|
|
9ae3a8 |
uint32_t len;
|
|
|
9ae3a8 |
uint8_t *data;
|
|
|
9ae3a8 |
@@ -46,12 +57,17 @@ typedef struct FWCfgEntry {
|
|
|
9ae3a8 |
struct FWCfgState {
|
|
|
9ae3a8 |
SysBusDevice busdev;
|
|
|
9ae3a8 |
MemoryRegion ctl_iomem, data_iomem, comb_iomem;
|
|
|
9ae3a8 |
- uint32_t ctl_iobase, data_iobase;
|
|
|
9ae3a8 |
+ uint32_t ctl_iobase, data_iobase, dma_iobase;
|
|
|
9ae3a8 |
FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
|
|
|
9ae3a8 |
FWCfgFiles *files;
|
|
|
9ae3a8 |
uint16_t cur_entry;
|
|
|
9ae3a8 |
uint32_t cur_offset;
|
|
|
9ae3a8 |
Notifier machine_ready;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ bool dma_enabled;
|
|
|
9ae3a8 |
+ dma_addr_t dma_addr;
|
|
|
9ae3a8 |
+ DMAContext *dma;
|
|
|
9ae3a8 |
+ MemoryRegion dma_iomem;
|
|
|
9ae3a8 |
};
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
#define JPG_FILE 0
|
|
|
9ae3a8 |
@@ -257,6 +273,124 @@ static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
|
|
|
9ae3a8 |
fw_cfg_write(opaque, (uint8_t)value);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+static void fw_cfg_dma_transfer(FWCfgState *s)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ dma_addr_t len;
|
|
|
9ae3a8 |
+ FWCfgDmaAccess dma;
|
|
|
9ae3a8 |
+ int arch;
|
|
|
9ae3a8 |
+ FWCfgEntry *e;
|
|
|
9ae3a8 |
+ int read;
|
|
|
9ae3a8 |
+ dma_addr_t dma_addr;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* Reset the address before the next access */
|
|
|
9ae3a8 |
+ dma_addr = s->dma_addr;
|
|
|
9ae3a8 |
+ s->dma_addr = 0;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (dma_memory_read(s->dma, dma_addr, &dma, sizeof(dma))) {
|
|
|
9ae3a8 |
+ stl_be_dma(s->dma, dma_addr + offsetof(FWCfgDmaAccess, control),
|
|
|
9ae3a8 |
+ FW_CFG_DMA_CTL_ERROR);
|
|
|
9ae3a8 |
+ return;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ dma.address = be64_to_cpu(dma.address);
|
|
|
9ae3a8 |
+ dma.length = be32_to_cpu(dma.length);
|
|
|
9ae3a8 |
+ dma.control = be32_to_cpu(dma.control);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (dma.control & FW_CFG_DMA_CTL_SELECT) {
|
|
|
9ae3a8 |
+ fw_cfg_select(s, dma.control >> 16);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
|
|
|
9ae3a8 |
+ e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (dma.control & FW_CFG_DMA_CTL_READ) {
|
|
|
9ae3a8 |
+ read = 1;
|
|
|
9ae3a8 |
+ } else if (dma.control & FW_CFG_DMA_CTL_SKIP) {
|
|
|
9ae3a8 |
+ read = 0;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ dma.length = 0;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ dma.control = 0;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ while (dma.length > 0 && !(dma.control & FW_CFG_DMA_CTL_ERROR)) {
|
|
|
9ae3a8 |
+ if (s->cur_entry == FW_CFG_INVALID || !e->data ||
|
|
|
9ae3a8 |
+ s->cur_offset >= e->len) {
|
|
|
9ae3a8 |
+ len = dma.length;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* If the access is not a read access, it will be a skip access,
|
|
|
9ae3a8 |
+ * tested before.
|
|
|
9ae3a8 |
+ */
|
|
|
9ae3a8 |
+ if (read) {
|
|
|
9ae3a8 |
+ if (dma_memory_set(s->dma, dma.address, 0, len)) {
|
|
|
9ae3a8 |
+ dma.control |= FW_CFG_DMA_CTL_ERROR;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ if (dma.length <= (e->len - s->cur_offset)) {
|
|
|
9ae3a8 |
+ len = dma.length;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ len = (e->len - s->cur_offset);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (e->read_callback) {
|
|
|
9ae3a8 |
+ e->read_callback(e->callback_opaque, s->cur_offset);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* If the access is not a read access, it will be a skip access,
|
|
|
9ae3a8 |
+ * tested before.
|
|
|
9ae3a8 |
+ */
|
|
|
9ae3a8 |
+ if (read) {
|
|
|
9ae3a8 |
+ if (dma_memory_write(s->dma, dma.address,
|
|
|
9ae3a8 |
+ &e->data[s->cur_offset], len)) {
|
|
|
9ae3a8 |
+ dma.control |= FW_CFG_DMA_CTL_ERROR;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ s->cur_offset += len;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ dma.address += len;
|
|
|
9ae3a8 |
+ dma.length -= len;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ stl_be_dma(s->dma, dma_addr + offsetof(FWCfgDmaAccess, control),
|
|
|
9ae3a8 |
+ dma.control);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ trace_fw_cfg_read(s, 0);
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static void fw_cfg_dma_mem_write(void *opaque, hwaddr addr,
|
|
|
9ae3a8 |
+ uint64_t value, unsigned size)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ FWCfgState *s = opaque;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (size == 4) {
|
|
|
9ae3a8 |
+ value = be32_to_cpu(value);
|
|
|
9ae3a8 |
+ if (addr == 0) {
|
|
|
9ae3a8 |
+ /* FWCfgDmaAccess high address */
|
|
|
9ae3a8 |
+ s->dma_addr = value << 32;
|
|
|
9ae3a8 |
+ } else if (addr == 4) {
|
|
|
9ae3a8 |
+ /* FWCfgDmaAccess low address */
|
|
|
9ae3a8 |
+ s->dma_addr |= value;
|
|
|
9ae3a8 |
+ fw_cfg_dma_transfer(s);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ } else if (size == 8 && addr == 0) {
|
|
|
9ae3a8 |
+ value = be64_to_cpu(value);
|
|
|
9ae3a8 |
+ s->dma_addr = value;
|
|
|
9ae3a8 |
+ fw_cfg_dma_transfer(s);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static bool fw_cfg_dma_mem_valid(void *opaque, hwaddr addr,
|
|
|
9ae3a8 |
+ unsigned size, bool is_write)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ return is_write && ((size == 4 && (addr == 0 || addr == 4)) ||
|
|
|
9ae3a8 |
+ (size == 8 && addr == 0));
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
|
|
|
9ae3a8 |
uint64_t value, unsigned size)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
@@ -317,6 +451,14 @@ static const MemoryRegionOps fw_cfg_comb_mem_ops = {
|
|
|
9ae3a8 |
.valid.accepts = fw_cfg_comb_valid,
|
|
|
9ae3a8 |
};
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+static const MemoryRegionOps fw_cfg_dma_mem_ops = {
|
|
|
9ae3a8 |
+ .write = fw_cfg_dma_mem_write,
|
|
|
9ae3a8 |
+ .endianness = DEVICE_NATIVE_ENDIAN,
|
|
|
9ae3a8 |
+ .valid.accepts = fw_cfg_dma_mem_valid,
|
|
|
9ae3a8 |
+ .valid.max_access_size = 8,
|
|
|
9ae3a8 |
+ .impl.max_access_size = 8,
|
|
|
9ae3a8 |
+};
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static void fw_cfg_reset(DeviceState *d)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d);
|
|
|
9ae3a8 |
@@ -357,6 +499,21 @@ static bool is_version_1(void *opaque, int version_id)
|
|
|
9ae3a8 |
return version_id == 1;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+static bool fw_cfg_dma_enabled(void *opaque)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ FWCfgState *s = opaque;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ return s->dma_enabled;
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static const VMStateDescription vmstate_fw_cfg_dma = {
|
|
|
9ae3a8 |
+ .name = "fw_cfg/dma",
|
|
|
9ae3a8 |
+ .fields = (VMStateField[]) {
|
|
|
9ae3a8 |
+ VMSTATE_UINT64(dma_addr, FWCfgState),
|
|
|
9ae3a8 |
+ VMSTATE_END_OF_LIST()
|
|
|
9ae3a8 |
+ },
|
|
|
9ae3a8 |
+};
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static const VMStateDescription vmstate_fw_cfg = {
|
|
|
9ae3a8 |
.name = "fw_cfg",
|
|
|
9ae3a8 |
.version_id = 2,
|
|
|
9ae3a8 |
@@ -367,6 +524,14 @@ static const VMStateDescription vmstate_fw_cfg = {
|
|
|
9ae3a8 |
VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
|
|
|
9ae3a8 |
VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
|
|
|
9ae3a8 |
VMSTATE_END_OF_LIST()
|
|
|
9ae3a8 |
+ },
|
|
|
9ae3a8 |
+ .subsections = (const VMStateSubsection[]) {
|
|
|
9ae3a8 |
+ {
|
|
|
9ae3a8 |
+ .vmsd = &vmstate_fw_cfg_dma,
|
|
|
9ae3a8 |
+ .needed = fw_cfg_dma_enabled,
|
|
|
9ae3a8 |
+ }, {
|
|
|
9ae3a8 |
+ /* empty */
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
};
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -478,16 +643,24 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
|
|
|
9ae3a8 |
fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
|
|
9ae3a8 |
- hwaddr ctl_addr, hwaddr data_addr)
|
|
|
9ae3a8 |
+static FWCfgState *
|
|
|
9ae3a8 |
+fw_cfg_init_dma(uint32_t ctl_port, uint32_t data_port,
|
|
|
9ae3a8 |
+ uint32_t dma_port,
|
|
|
9ae3a8 |
+ hwaddr ctl_addr, hwaddr data_addr, hwaddr dma_addr,
|
|
|
9ae3a8 |
+ AddressSpace *dma_as)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
DeviceState *dev;
|
|
|
9ae3a8 |
SysBusDevice *d;
|
|
|
9ae3a8 |
FWCfgState *s;
|
|
|
9ae3a8 |
+ uint32_t version = FW_CFG_VERSION;
|
|
|
9ae3a8 |
+ bool dma_enabled = dma_port && dma_as;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
dev = qdev_create(NULL, "fw_cfg");
|
|
|
9ae3a8 |
qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
|
|
|
9ae3a8 |
qdev_prop_set_uint32(dev, "data_iobase", data_port);
|
|
|
9ae3a8 |
+ qdev_prop_set_uint32(dev, "dma_iobase", dma_port);
|
|
|
9ae3a8 |
+ qdev_prop_set_bit(dev, "dma_enabled", dma_enabled);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
d = SYS_BUS_DEVICE(dev);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
s = DO_UPCAST(FWCfgState, busdev.qdev, dev);
|
|
|
9ae3a8 |
@@ -505,8 +678,19 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
|
|
9ae3a8 |
if (data_addr) {
|
|
|
9ae3a8 |
sysbus_mmio_map(d, 1, data_addr);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
+ if (dma_enabled) {
|
|
|
9ae3a8 |
+ /* 64 bits for the address field */
|
|
|
9ae3a8 |
+ s->dma = &dma_context_memory;
|
|
|
9ae3a8 |
+ s->dma_addr = 0;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ version |= FW_CFG_VERSION_DMA;
|
|
|
9ae3a8 |
+ if (dma_addr) {
|
|
|
9ae3a8 |
+ sysbus_mmio_map(d, 2, dma_addr);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
|
|
|
9ae3a8 |
- fw_cfg_add_i32(s, FW_CFG_ID, 1);
|
|
|
9ae3a8 |
+ fw_cfg_add_i32(s, FW_CFG_ID, version);
|
|
|
9ae3a8 |
fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
|
|
|
9ae3a8 |
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
|
|
|
9ae3a8 |
fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
|
|
|
9ae3a8 |
@@ -520,19 +704,37 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
|
|
9ae3a8 |
return s;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
|
|
9ae3a8 |
+ hwaddr ctl_addr, hwaddr data_addr)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ return fw_cfg_init_dma(ctl_port, data_addr, 0, ctl_addr, data_addr, 0, NULL);
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
|
|
|
9ae3a8 |
+ AddressSpace *dma_as)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ return fw_cfg_init_dma(iobase, iobase + 1, dma_iobase, 0, 0, 0, dma_as);
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static int fw_cfg_init1(SysBusDevice *dev)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
FWCfgState *s = FROM_SYSBUS(FWCfgState, dev);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
memory_region_init_io(&s->ctl_iomem, &fw_cfg_ctl_mem_ops, s,
|
|
|
9ae3a8 |
- "fwcfg.ctl", FW_CFG_SIZE);
|
|
|
9ae3a8 |
+ "fwcfg.ctl", FW_CFG_CTL_SIZE);
|
|
|
9ae3a8 |
sysbus_init_mmio(dev, &s->ctl_iomem);
|
|
|
9ae3a8 |
memory_region_init_io(&s->data_iomem, &fw_cfg_data_mem_ops, s,
|
|
|
9ae3a8 |
"fwcfg.data", FW_CFG_DATA_SIZE);
|
|
|
9ae3a8 |
sysbus_init_mmio(dev, &s->data_iomem);
|
|
|
9ae3a8 |
/* In case ctl and data overlap: */
|
|
|
9ae3a8 |
memory_region_init_io(&s->comb_iomem, &fw_cfg_comb_mem_ops, s,
|
|
|
9ae3a8 |
- "fwcfg", FW_CFG_SIZE);
|
|
|
9ae3a8 |
+ "fwcfg", FW_CFG_CTL_SIZE);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (s->dma_enabled) {
|
|
|
9ae3a8 |
+ memory_region_init_io(&s->dma_iomem, &fw_cfg_dma_mem_ops, s,
|
|
|
9ae3a8 |
+ "fwcfg.dma", sizeof(dma_addr_t));
|
|
|
9ae3a8 |
+ sysbus_init_mmio(dev, &s->dma_iomem);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (s->ctl_iobase + 1 == s->data_iobase) {
|
|
|
9ae3a8 |
sysbus_add_io(dev, s->ctl_iobase, &s->comb_iomem);
|
|
|
9ae3a8 |
@@ -544,12 +746,19 @@ static int fw_cfg_init1(SysBusDevice *dev)
|
|
|
9ae3a8 |
sysbus_add_io(dev, s->data_iobase, &s->data_iomem);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (s->dma_iobase) {
|
|
|
9ae3a8 |
+ sysbus_add_io(dev, s->dma_iobase, &s->dma_iomem);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
return 0;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static Property fw_cfg_properties[] = {
|
|
|
9ae3a8 |
DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
|
|
|
9ae3a8 |
DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
|
|
|
9ae3a8 |
+ DEFINE_PROP_HEX32("dma_iobase", FWCfgState, dma_iobase, -1),
|
|
|
9ae3a8 |
+ DEFINE_PROP_BOOL("dma_enabled", FWCfgState, dma_enabled, false),
|
|
|
9ae3a8 |
DEFINE_PROP_END_OF_LIST(),
|
|
|
9ae3a8 |
};
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
|
|
|
9ae3a8 |
index aa5f351..b193e38 100644
|
|
|
9ae3a8 |
--- a/include/hw/nvram/fw_cfg.h
|
|
|
9ae3a8 |
+++ b/include/hw/nvram/fw_cfg.h
|
|
|
9ae3a8 |
@@ -7,6 +7,7 @@
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
#include "exec/hwaddr.h"
|
|
|
9ae3a8 |
#include "qemu/typedefs.h"
|
|
|
9ae3a8 |
+#include "qemu/compiler.h"
|
|
|
9ae3a8 |
#endif
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
#define FW_CFG_SIGNATURE 0x00
|
|
|
9ae3a8 |
@@ -61,6 +62,15 @@ typedef struct FWCfgFiles {
|
|
|
9ae3a8 |
FWCfgFile f[];
|
|
|
9ae3a8 |
} FWCfgFiles;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+/* Control as first field allows for different structures selected by this
|
|
|
9ae3a8 |
+ * field, which might be useful in the future
|
|
|
9ae3a8 |
+ */
|
|
|
9ae3a8 |
+typedef struct FWCfgDmaAccess {
|
|
|
9ae3a8 |
+ uint32_t control;
|
|
|
9ae3a8 |
+ uint32_t length;
|
|
|
9ae3a8 |
+ uint64_t address;
|
|
|
9ae3a8 |
+} QEMU_PACKED FWCfgDmaAccess;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
|
|
|
9ae3a8 |
typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -76,6 +86,8 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
|
|
9ae3a8 |
void *data, size_t len);
|
|
|
9ae3a8 |
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
|
|
9ae3a8 |
hwaddr crl_addr, hwaddr data_addr);
|
|
|
9ae3a8 |
+FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
|
|
|
9ae3a8 |
+ AddressSpace *dma_as);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
FWCfgState *fw_cfg_find(void);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c
|
|
|
9ae3a8 |
index 3428dca..24b8a28 100644
|
|
|
9ae3a8 |
--- a/tests/fw_cfg-test.c
|
|
|
9ae3a8 |
+++ b/tests/fw_cfg-test.c
|
|
|
9ae3a8 |
@@ -38,7 +38,8 @@ static void test_fw_cfg_signature(void)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static void test_fw_cfg_id(void)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
- g_assert_cmpint(qfw_cfg_get_u32(fw_cfg, FW_CFG_ID), ==, 1);
|
|
|
9ae3a8 |
+ uint32_t id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID);
|
|
|
9ae3a8 |
+ g_assert((id == 1) || (id == 3));
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static void test_fw_cfg_uuid(void)
|
|
|
9ae3a8 |
--
|
|
|
9ae3a8 |
1.8.3.1
|
|
|
9ae3a8 |
|