[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 3/8] ioport: register memory regions for I/O port
From: |
Hervé Poussineau |
Subject: |
[Qemu-devel] [PATCH v2 3/8] ioport: register memory regions for I/O port lists |
Date: |
Sun, 9 Jun 2013 01:44:01 +0800 |
As I/O ports are now memory regions, they can be seen in 'info qtree'.
This also removes the last use of MemoryRegionOps.old_portio field.
Some of the code has been extracted from memory.c
Signed-off-by: Hervé Poussineau <address@hidden>
---
include/exec/ioport.h | 3 +-
ioport.c | 132 +++++++++++++++++++++++++++++++++++++++----------
2 files changed, 107 insertions(+), 28 deletions(-)
diff --git a/include/exec/ioport.h b/include/exec/ioport.h
index fc28350..398fe14 100644
--- a/include/exec/ioport.h
+++ b/include/exec/ioport.h
@@ -55,13 +55,14 @@ uint32_t cpu_inl(pio_addr_t addr);
struct MemoryRegion;
struct MemoryRegionPortio;
+struct PortioListState;
typedef struct PortioList {
const struct MemoryRegionPortio *ports;
struct MemoryRegion *address_space;
unsigned nr;
struct MemoryRegion **regions;
- struct MemoryRegion **aliases;
+ struct PortioListState **states;
void *opaque;
const char *name;
} PortioList;
diff --git a/ioport.c b/ioport.c
index a0ac2a0..d26d3e1 100644
--- a/ioport.c
+++ b/ioport.c
@@ -28,6 +28,7 @@
#include "exec/ioport.h"
#include "trace.h"
#include "exec/memory.h"
+#include "qemu/host-utils.h"
/***********************************************************/
/* IO Port */
@@ -330,6 +331,12 @@ uint32_t cpu_inl(pio_addr_t addr)
return val;
}
+typedef struct PortioListState {
+ const MemoryRegionPortio *portio;
+ uint32_t offset;
+ void *opaque;
+} PortioListState;
+
void portio_list_init(PortioList *piolist,
const MemoryRegionPortio *callbacks,
void *opaque, const char *name)
@@ -343,16 +350,95 @@ void portio_list_init(PortioList *piolist,
piolist->ports = callbacks;
piolist->nr = 0;
piolist->regions = g_new0(MemoryRegion *, n);
- piolist->aliases = g_new0(MemoryRegion *, n);
+ piolist->states = g_new0(PortioListState *, n);
piolist->address_space = NULL;
piolist->opaque = opaque;
piolist->name = name;
}
+static const MemoryRegionPortio *portio_find(const MemoryRegionPortio *mrp,
+ uint64_t offset,
+ unsigned int width, bool write)
+{
+ for (; mrp->size; ++mrp) {
+ if (offset >= mrp->offset && offset < mrp->offset + mrp->len
+ && width == mrp->size
+ && (write ? (bool)mrp->write : (bool)mrp->read)) {
+ return mrp;
+ }
+ }
+ return NULL;
+}
+
+static uint64_t portio_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ const PortioListState *s = opaque;
+ const MemoryRegionPortio *mrp;
+ uint16_t data;
+
+ addr += s->portio->offset;
+ mrp = portio_find(s->portio, addr, size, false);
+ if (!mrp && size == 2) {
+ mrp = portio_find(s->portio, addr, 1, false);
+ assert(mrp);
+ data = mrp->read(s->opaque, addr) |
+ (mrp->read(s->opaque, addr + 1) << 8);
+ return data;
+ }
+ assert(mrp);
+ return mrp->read(s->opaque, addr);
+}
+
+static void portio_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ const PortioListState *s = opaque;
+ const MemoryRegionPortio *mrp;
+
+ addr += s->offset;
+ mrp = portio_find(s->portio, addr, size, true);
+ if (!mrp && size == 2) {
+ mrp = portio_find(s->portio, addr, 1, true);
+ assert(mrp);
+ mrp->write(s->opaque, addr, data & 0xff);
+ mrp->write(s->opaque, addr + 1, data >> 8);
+ return;
+ }
+ assert(mrp);
+ mrp->write(s->opaque, addr, data);
+}
+
+static bool portio_accepts(void *opaque, hwaddr addr, unsigned int size,
+ bool is_write)
+{
+ const PortioListState *s = opaque;
+ const MemoryRegionPortio *mrp;
+
+ addr += s->offset;
+ mrp = portio_find(s->portio, addr, size, is_write);
+ if (!mrp && size == 2) {
+ mrp = portio_find(s->portio, addr, 1, is_write);
+ }
+ if (!mrp) {
+ LOG_UNUSED_IOPORT("unused %s%c: port=0x%04" HWADDR_PRIx "\n",
+ is_write ? "out" : "in",
+ size == 1 ? 'b' : size == 2 ? 'w' : 'l',
+ addr);
+ }
+ return mrp;
+}
+
+const MemoryRegionOps portio_ops = {
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .read = portio_read,
+ .write = portio_write,
+ .valid.accepts = portio_accepts,
+};
+
void portio_list_destroy(PortioList *piolist)
{
g_free(piolist->regions);
- g_free(piolist->aliases);
+ g_free(piolist->states);
}
static void portio_list_add_1(PortioList *piolist,
@@ -361,8 +447,8 @@ static void portio_list_add_1(PortioList *piolist,
unsigned off_low, unsigned off_high)
{
MemoryRegionPortio *pio;
- MemoryRegionOps *ops;
- MemoryRegion *region, *alias;
+ MemoryRegion *region = g_new(MemoryRegion, 1);
+ PortioListState *s = g_new(PortioListState, 1);
unsigned i;
/* Copy the sub-list and null-terminate it. */
@@ -370,28 +456,20 @@ static void portio_list_add_1(PortioList *piolist,
memcpy(pio, pio_init, sizeof(MemoryRegionPortio) * count);
memset(pio + count, 0, sizeof(MemoryRegionPortio));
- /* Adjust the offsets to all be zero-based for the region. */
+ /* Adjust the offsets to all be address-based for the region. */
for (i = 0; i < count; ++i) {
- pio[i].offset -= off_low;
+ pio[i].offset += start;
}
- ops = g_new0(MemoryRegionOps, 1);
- ops->old_portio = pio;
-
- region = g_new(MemoryRegion, 1);
- alias = g_new(MemoryRegion, 1);
- /*
- * Use an alias so that the callback is called with an absolute address,
- * rather than an offset relative to to start + off_low.
- */
- memory_region_init_io(region, ops, piolist->opaque, piolist->name,
- INT64_MAX);
- memory_region_init_alias(alias, piolist->name,
- region, start + off_low, off_high - off_low);
+ s->offset = start + off_low;
+ s->portio = pio;
+ s->opaque = piolist->opaque;
+ memory_region_init_io(region, &portio_ops, s, piolist->name,
+ off_high - off_low);
memory_region_add_subregion(piolist->address_space,
- start + off_low, alias);
+ s->offset, region);
piolist->regions[piolist->nr] = region;
- piolist->aliases[piolist->nr] = alias;
+ piolist->states[piolist->nr] = s;
++piolist->nr;
}
@@ -434,19 +512,19 @@ void portio_list_add(PortioList *piolist,
void portio_list_del(PortioList *piolist)
{
- MemoryRegion *mr, *alias;
+ MemoryRegion *mr;
+ PortioListState *s;
unsigned i;
for (i = 0; i < piolist->nr; ++i) {
mr = piolist->regions[i];
- alias = piolist->aliases[i];
- memory_region_del_subregion(piolist->address_space, alias);
- memory_region_destroy(alias);
+ s = piolist->states[i];
+ memory_region_del_subregion(piolist->address_space, mr);
memory_region_destroy(mr);
g_free((MemoryRegionOps *)mr->ops);
g_free(mr);
- g_free(alias);
+ g_free(s);
piolist->regions[i] = NULL;
- piolist->aliases[i] = NULL;
+ piolist->states[i] = NULL;
}
}
--
1.7.10.4
- [Qemu-devel] [PATCH v2 0/8] memory: remove old_portio usage, Hervé Poussineau, 2013/06/08
- [Qemu-devel] [PATCH v2 2/8] memory: handle old_portio accesses in MMIO path, Hervé Poussineau, 2013/06/08
- [Qemu-devel] [PATCH v2 1/8] isa: fix documentation of isa_register_portio_list, Hervé Poussineau, 2013/06/08
- [Qemu-devel] [PATCH v2 3/8] ioport: register memory regions for I/O port lists,
Hervé Poussineau <=
- [Qemu-devel] [PATCH v2 4/8] memory: remove code dealing with old_portio, Hervé Poussineau, 2013/06/08
- [Qemu-devel] [PATCH v2 5/8] ioport: reimplement cpu_in/cpu_out using address_space_rw, Hervé Poussineau, 2013/06/08
- [Qemu-devel] [PATCH v2 6/8] ppc: simplify access to PReP I/O region, Hervé Poussineau, 2013/06/08
- [Qemu-devel] [PATCH v2 7/8] PPC: pseries: Remove hack for PIO window, Hervé Poussineau, 2013/06/08
- [Qemu-devel] [PATCH v2 8/8] isa_mmio: simplify access to system I/O region, Hervé Poussineau, 2013/06/08
- Re: [Qemu-devel] [PATCH v2 0/8] memory: remove old_portio usage, Hervé Poussineau, 2013/06/16