From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35257) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YTe4V-0002Rf-Sh for qemu-devel@nongnu.org; Thu, 05 Mar 2015 17:16:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YTe4Q-0003TA-4C for qemu-devel@nongnu.org; Thu, 05 Mar 2015 17:16:47 -0500 Received: from smtp2-g21.free.fr ([2a01:e0c:1:1599::11]:26158) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YTe4P-0003T6-RJ for qemu-devel@nongnu.org; Thu, 05 Mar 2015 17:16:42 -0500 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Thu, 5 Mar 2015 23:13:19 +0100 Message-Id: <1425593606-5909-2-git-send-email-hpoussin@reactos.org> In-Reply-To: <1425593606-5909-1-git-send-email-hpoussin@reactos.org> References: <1425593606-5909-1-git-send-email-hpoussin@reactos.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 1/8] rc4030: create custom DMA address space List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Herv=C3=A9=20Poussineau?= , Leon Alrae , Laurent@Vivier.EU, Aurelien Jarno Add a new memory region in system address space where DMA address space definition (the 'translation table') belongs, so we can update on the fly the DMA address space. Signed-off-by: Herv=C3=A9 Poussineau --- hw/dma/rc4030.c | 154 ++++++++++++++++++++++++++++++++++++++++++-------= ------ 1 file changed, 117 insertions(+), 37 deletions(-) diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index af26632..93a52f6 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" =20 /********************************************************/ /* debug rc4030 */ @@ -47,6 +48,8 @@ do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__= , ## __VA_ARGS__); } whi /********************************************************/ /* rc4030 emulation */ =20 +#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; =20 + MemoryRegion dma_tt; /* translation table */ + MemoryRegion dma_mrs[MAX_TL_ENTRIES]; /* translation aliases */ + MemoryRegion dma_mr; /* whole DMA memory region */ + AddressSpace dma_as; + MemoryRegion iomem_chipset; MemoryRegion iomem_jazzio; } rc4030State; @@ -265,6 +273,89 @@ static uint32_t rc4030_readb(void *opaque, hwaddr ad= dr) return (v >> (8 * (addr & 0x3))) & 0xff; } =20 +static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t= frame) +{ + if (index < MAX_TL_ENTRIES) { + memory_region_set_enabled(&s->dma_mrs[index], false); + } + + if (!frame) { + return; + } + + if (index >=3D MAX_TL_ENTRIES) { + qemu_log_mask(LOG_UNIMP, + "rc4030: trying to use too high " + "translation table entry %d (max allowed=3D%d)", + index, MAX_TL_ENTRIES); + return; + } + memory_region_set_alias_offset(&s->dma_mrs[index], frame); + memory_region_set_enabled(&s->dma_mrs[index], true); +} + +static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data= , + unsigned int size) +{ + rc4030State *s =3D opaque; + + /* write memory */ + memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size); + + /* update dma address space (only if frame field has been written) *= / + if (addr % sizeof(dma_pagetable_entry) =3D=3D 0) { + int index =3D 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_tt_ops =3D { + .write =3D rc4030_dma_tt_write, + .impl.min_access_size =3D 4, + .impl.max_access_size =3D 4, +}; + +static void rc4030_dma_tt_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_tt); + cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff, + memory_region_get_ram_ptr(&s->dma_tt), + s->dma_tl_limit); + } + + s->dma_tl_base =3D new_tl_base; + s->dma_tl_limit =3D new_tl_limit; + new_tl_base &=3D 0x7fffffff; + + if (s->dma_tl_limit) { + memory_region_init_rom_device(&s->dma_tt, NULL, + &rc4030_dma_tt_ops, s, "dma_tt", + s->dma_tl_limit, NULL); + dma_tl_contents =3D memory_region_get_ram_ptr(&s->dma_tt); + cpu_physical_memory_read(new_tl_base, dma_tl_contents, s->dma_tl= _limit); + + memory_region_transaction_begin(); + entries =3D s->dma_tl_limit / sizeof(dma_pagetable_entry); + for (i =3D 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_tt); + memory_region_transaction_commit(); + } else { + memory_region_init(&s->dma_tt, NULL, "dma_tt", 0); + } +} + + static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) { rc4030State *s =3D opaque; @@ -279,11 +370,11 @@ static void rc4030_writel(void *opaque, hwaddr addr= , uint32_t val) break; /* DMA transl. table base */ case 0x0018: - s->dma_tl_base =3D val; + rc4030_dma_tt_update(s, val, s->dma_tl_limit); break; /* DMA transl. table limit */ case 0x0020: - s->dma_tl_limit =3D val; + rc4030_dma_tt_update(s, s->dma_tl_base, val); break; /* DMA transl. table invalidated */ case 0x0028: @@ -590,7 +681,7 @@ static void rc4030_reset(void *opaque) s->invalid_address_register =3D 0; =20 memset(s->dma_regs, 0, sizeof(s->dma_regs)); - s->dma_tl_base =3D s->dma_tl_limit =3D 0; + rc4030_dma_tt_update(s, 0, 0); =20 s->remote_failed_address =3D s->memory_failed_address =3D 0; s->cache_maint =3D 0; @@ -675,39 +766,7 @@ static void rc4030_save(QEMUFile *f, void *opaque) void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int l= en, int is_write) { rc4030State *s =3D opaque; - hwaddr entry_addr; - hwaddr phys_addr; - dma_pagetable_entry entry; - int index; - int ncpy, i; - - i =3D 0; - for (;;) { - if (i =3D=3D len) { - break; - } - - ncpy =3D DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1)); - if (ncpy > len - i) - ncpy =3D len - i; - - /* Get DMA translation table entry */ - index =3D addr / DMA_PAGESIZE; - if (index >=3D s->dma_tl_limit / sizeof(dma_pagetable_entry)) { - break; - } - entry_addr =3D s->dma_tl_base + index * sizeof(dma_pagetable_ent= ry); - /* XXX: not sure. should we really use only lowest bits? */ - entry_addr &=3D 0x7fffffff; - cpu_physical_memory_read(entry_addr, &entry, sizeof(entry)); - - /* Read/write data at right place */ - phys_addr =3D entry.frame + (addr & (DMA_PAGESIZE - 1)); - cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write); - - i +=3D ncpy; - addr +=3D ncpy; - } + address_space_rw(&s->dma_as, addr, buf, len, is_write); } =20 static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, in= t is_write) @@ -715,6 +774,7 @@ static void rc4030_do_dma(void *opaque, int n, uint8_= t *buf, int len, int is_wri rc4030State *s =3D opaque; hwaddr dma_addr; int dev_to_mem; + int i; =20 s->dma_regs[n][DMA_REG_ENABLE] &=3D ~(DMA_FLAG_TC_INTR | DMA_FLAG_ME= M_INTR | DMA_FLAG_ADDR_INTR); =20 @@ -733,7 +793,16 @@ static void rc4030_do_dma(void *opaque, int n, uint8= _t *buf, int len, int is_wri dma_addr =3D s->dma_regs[n][DMA_REG_ADDRESS]; =20 /* Read/write data at right place */ - rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write); + for (i =3D 0; i < len; ) { + int ncpy =3D DMA_PAGESIZE - (dma_addr & (DMA_PAGESIZE - 1)); + if (ncpy > len - i) { + ncpy =3D len - i; + } + address_space_rw(&s->dma_as, dma_addr, buf + i, ncpy, is_write); + + dma_addr +=3D ncpy; + i +=3D ncpy; + } =20 s->dma_regs[n][DMA_REG_ENABLE] |=3D DMA_FLAG_TC_INTR; s->dma_regs[n][DMA_REG_COUNT] -=3D len; @@ -800,6 +869,7 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, MemoryRegion *sysmem) { rc4030State *s; + int i; =20 s =3D g_malloc0(sizeof(rc4030State)); =20 @@ -821,5 +891,15 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, "rc4030.jazzio", 0x00001000); memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio); =20 + memory_region_init(&s->dma_tt, NULL, "dma_tt", 0); + memory_region_init(&s->dma_mr, NULL, "dma", INT32_MAX); + for (i =3D 0; i < MAX_TL_ENTRIES; ++i) { + memory_region_init_alias(&s->dma_mrs[i], NULL, "dma-alias", + get_system_memory(), 0, DMA_PAGESIZE); + memory_region_set_enabled(&s->dma_mrs[i], false); + memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE, + &s->dma_mrs[i]); + } + address_space_init(&s->dma_as, &s->dma_mr, "rc4030_dma"); return s; } --=20 1.7.10.4