From: "Hervé Poussineau" <hpoussin@reactos.org>
To: qemu-devel@nongnu.org
Cc: "Hervé Poussineau" <hpoussin@reactos.org>,
"Aurelien Jarno" <aurelien@aurel32.net>
Subject: [Qemu-devel] [PATCH 2/7] rc4030: create custom DMA address space
Date: Sun, 22 Dec 2013 16:37:25 +0100 [thread overview]
Message-ID: <1387726650-8306-3-git-send-email-hpoussin@reactos.org> (raw)
In-Reply-To: <1387726650-8306-1-git-send-email-hpoussin@reactos.org>
Keep it up to date by catching writes to DMA translation table.
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
---
hw/dma/rc4030.c | 153 ++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 113 insertions(+), 40 deletions(-)
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
index af26632..9b505c5 100644
--- a/hw/dma/rc4030.c
+++ b/hw/dma/rc4030.c
@@ -25,6 +25,7 @@
#include "hw/hw.h"
#include "hw/mips/mips.h"
#include "qemu/timer.h"
+#include "exec/address-spaces.h"
/********************************************************/
/* debug rc4030 */
@@ -47,6 +48,8 @@ do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } whi
/********************************************************/
/* rc4030 emulation */
+#define MAX_TL_ENTRIES 512
+
typedef struct dma_pagetable_entry {
int32_t frame;
int32_t owner;
@@ -96,6 +99,11 @@ typedef struct rc4030State
qemu_irq timer_irq;
qemu_irq jazz_bus_irq;
+ MemoryRegion dma_table; /* translation table */
+ MemoryRegion dma_aliases[MAX_TL_ENTRIES]; /* translation aliases */
+ MemoryRegion dma_region; /* whole DMA memory region */
+ AddressSpace dma_as;
+
MemoryRegion iomem_chipset;
MemoryRegion iomem_jazzio;
} rc4030State;
@@ -265,6 +273,92 @@ static uint32_t rc4030_readb(void *opaque, hwaddr addr)
return (v >> (8 * (addr & 0x3))) & 0xff;
}
+static void rc4030_dma_as_update_one(rc4030State *s, int index,
+ uint32_t new_frame)
+{
+ if (index < MAX_TL_ENTRIES) {
+ memory_region_set_enabled(&s->dma_aliases[index], false);
+ }
+
+ if (!new_frame) {
+ return;
+ }
+
+ if (index >= MAX_TL_ENTRIES) {
+ qemu_log_mask(LOG_UNIMP,
+ "rc4030: trying to use too high "
+ "translation table entry %d (max allowed=%d)",
+ index, MAX_TL_ENTRIES);
+ return;
+ }
+ memory_region_set_alias_offset(&s->dma_aliases[index], new_frame);
+ memory_region_set_enabled(&s->dma_aliases[index], true);
+}
+
+static void rc4030_dma_table_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ rc4030State *s = opaque;
+
+ /* write memory */
+ memcpy(memory_region_get_ram_ptr(&s->dma_table) + addr, &data, size);
+
+ /* update dma address space (only if frame field has been written) */
+ if (addr % sizeof(dma_pagetable_entry) == 0) {
+ int index = addr / sizeof(dma_pagetable_entry);
+ memory_region_transaction_begin();
+ rc4030_dma_as_update_one(s, index, (uint32_t)data);
+ memory_region_transaction_commit();
+ }
+}
+
+static const MemoryRegionOps rc4030_dma_table_ops = {
+ .write = rc4030_dma_table_write,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+};
+
+static void rc4030_dma_table_update(rc4030State *s, uint32_t new_tl_base,
+ uint32_t new_tl_limit)
+{
+ int entries, i;
+ dma_pagetable_entry *dma_tl_contents;
+
+ if (s->dma_tl_limit) {
+ /* write old dma tl table to physical memory */
+ memory_region_del_subregion(get_system_memory(), &s->dma_table);
+ cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff,
+ memory_region_get_ram_ptr(&s->dma_table),
+ s->dma_tl_limit);
+ }
+ memory_region_destroy(&s->dma_table);
+
+ s->dma_tl_base = new_tl_base;
+ s->dma_tl_limit = new_tl_limit;
+ new_tl_base &= 0x7fffffff;
+
+ if (s->dma_tl_limit) {
+ memory_region_init_rom_device(&s->dma_table, NULL,
+ &rc4030_dma_table_ops, s,
+ "dma-translation-table", s->dma_tl_limit);
+ dma_tl_contents = memory_region_get_ram_ptr(&s->dma_table);
+ cpu_physical_memory_read(new_tl_base, dma_tl_contents, s->dma_tl_limit);
+
+ memory_region_transaction_begin();
+ entries = s->dma_tl_limit / sizeof(dma_pagetable_entry);
+ for (i = 0; i < entries; i++) {
+ rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame);
+ }
+ memory_region_add_subregion(get_system_memory(), new_tl_base,
+ &s->dma_table);
+ memory_region_transaction_commit();
+ } else {
+ memory_region_init(&s->dma_table, NULL,
+ "dma-translation-table", 0);
+ }
+}
+
+
static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
{
rc4030State *s = opaque;
@@ -279,11 +373,11 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
break;
/* DMA transl. table base */
case 0x0018:
- s->dma_tl_base = val;
+ rc4030_dma_table_update(s, val, s->dma_tl_limit);
break;
/* DMA transl. table limit */
case 0x0020:
- s->dma_tl_limit = val;
+ rc4030_dma_table_update(s, s->dma_tl_base, val);
break;
/* DMA transl. table invalidated */
case 0x0028:
@@ -590,7 +684,7 @@ static void rc4030_reset(void *opaque)
s->invalid_address_register = 0;
memset(s->dma_regs, 0, sizeof(s->dma_regs));
- s->dma_tl_base = s->dma_tl_limit = 0;
+ rc4030_dma_table_update(s, 0, 0);
s->remote_failed_address = s->memory_failed_address = 0;
s->cache_maint = 0;
@@ -675,39 +769,7 @@ static void rc4030_save(QEMUFile *f, void *opaque)
void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)
{
rc4030State *s = opaque;
- hwaddr entry_addr;
- hwaddr phys_addr;
- dma_pagetable_entry entry;
- int index;
- int ncpy, i;
-
- i = 0;
- for (;;) {
- if (i == len) {
- break;
- }
-
- ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1));
- if (ncpy > len - i)
- ncpy = len - i;
-
- /* Get DMA translation table entry */
- index = addr / DMA_PAGESIZE;
- if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
- break;
- }
- entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
- /* XXX: not sure. should we really use only lowest bits? */
- entry_addr &= 0x7fffffff;
- cpu_physical_memory_read(entry_addr, &entry, sizeof(entry));
-
- /* Read/write data at right place */
- phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
- cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
-
- i += ncpy;
- addr += ncpy;
- }
+ address_space_rw(&s->dma_as, addr, buf, len, is_write);
}
static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
@@ -733,7 +795,7 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri
dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
/* Read/write data at right place */
- rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write);
+ address_space_rw(&s->dma_as, dma_addr, buf, len, is_write);
s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
s->dma_regs[n][DMA_REG_COUNT] -= len;
@@ -800,6 +862,7 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
MemoryRegion *sysmem)
{
rc4030State *s;
+ int i;
s = g_malloc0(sizeof(rc4030State));
@@ -812,14 +875,24 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
qemu_register_reset(rc4030_reset, s);
register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
- rc4030_reset(s);
memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s,
- "rc4030.chipset", 0x300);
+ "rc4030", 0x300);
memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset);
memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s,
- "rc4030.jazzio", 0x00001000);
+ "jazzio", 0x00001000);
memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio);
+ memory_region_init(&s->dma_table, NULL, "dma-translation-table", 0);
+ memory_region_init(&s->dma_region, NULL, "dma-region", INT32_MAX);
+ for (i = 0; i < MAX_TL_ENTRIES; ++i) {
+ memory_region_init_alias(&s->dma_aliases[i], NULL, "dma-alias",
+ get_system_memory(), 0, DMA_PAGESIZE);
+ memory_region_set_enabled(&s->dma_aliases[i], false);
+ memory_region_add_subregion(&s->dma_region, i * DMA_PAGESIZE,
+ &s->dma_aliases[i]);
+ }
+ address_space_init(&s->dma_as, &s->dma_region, "rc4030_dma");
+ rc4030_reset(s);
return s;
}
--
1.7.10.4
next prev parent reply other threads:[~2013-12-22 15:36 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-22 15:37 [Qemu-devel] [PATCH 0/7] rc4030 chipset: misc cleanup Hervé Poussineau
2013-12-22 15:37 ` [Qemu-devel] [PATCH 1/7] mips jazz: compile only in 64 bit little endian Hervé Poussineau
2013-12-22 15:37 ` Hervé Poussineau [this message]
2013-12-22 15:37 ` [Qemu-devel] [PATCH 3/7] rc4030: use AddressSpace and address_space_rw in users Hervé Poussineau
2013-12-22 15:37 ` [Qemu-devel] [PATCH 4/7] rc4030: do not use old_mmio accesses Hervé Poussineau
2013-12-22 15:37 ` [Qemu-devel] [PATCH 5/7] rc4030: document register at offset 0x210 (memory refresh rate) Hervé Poussineau
2013-12-22 15:37 ` [Qemu-devel] [PATCH 6/7] rc4030: use trace events instead of custom logging Hervé Poussineau
2013-12-22 15:37 ` [Qemu-devel] [PATCH 7/7] rc4030: convert to QOM Hervé Poussineau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1387726650-8306-3-git-send-email-hpoussin@reactos.org \
--to=hpoussin@reactos.org \
--cc=aurelien@aurel32.net \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.