From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60417) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yzjy6-0005Nf-SV for qemu-devel@nongnu.org; Tue, 02 Jun 2015 07:02:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Yzjy2-0004Sp-5z for qemu-devel@nongnu.org; Tue, 02 Jun 2015 07:02:50 -0400 Received: from hall.aurel32.net ([2001:bc8:30d7:101::1]:59786) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yzjy1-0004Sd-T8 for qemu-devel@nongnu.org; Tue, 02 Jun 2015 07:02:46 -0400 Date: Tue, 2 Jun 2015 13:02:44 +0200 From: Aurelien Jarno Message-ID: <20150602110244.GB26298@aurel32.net> References: <1432729200-5322-1-git-send-email-hpoussin@reactos.org> <1432729200-5322-3-git-send-email-hpoussin@reactos.org> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-15 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable In-Reply-To: <1432729200-5322-3-git-send-email-hpoussin@reactos.org> Sender: Aurelien Jarno Subject: Re: [Qemu-devel] [PATCH v2 02/17] dma/rc4030: create custom DMA address space List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?iso-8859-15?Q?Herv=E9?= Poussineau Cc: Paolo Bonzini , Leon Alrae , qemu-devel@nongnu.org On 2015-05-27 14:19, Herv=E9 Poussineau wrote: > 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. >=20 > Signed-off-by: Herv=E9 Poussineau > --- > Cc: Paolo Bonzini > hw/dma/rc4030.c | 163 +++++++++++++++++++++++++++++++++++++++++++-------= ------ > 1 file changed, 126 insertions(+), 37 deletions(-) >=20 > diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c > index af26632..84039dc 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,16 @@ typedef struct rc4030State > qemu_irq timer_irq; > qemu_irq jazz_bus_irq; > =20 > + /* biggest translation table */ > + MemoryRegion dma_tt; > + /* translation table memory region alias, added to system RAM */ > + MemoryRegion dma_tt_alias; > + /* whole DMA memory region, root of DMA address space */ > + MemoryRegion dma_mr; > + /* translation table entry aliases, added to DMA memory region */ > + MemoryRegion dma_mrs[MAX_TL_ENTRIES]; > + AddressSpace dma_as; > + > MemoryRegion iomem_chipset; > MemoryRegion iomem_jazzio; > } rc4030State; > @@ -265,6 +278,97 @@ 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_alia= s); > + cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff, > + memory_region_get_ram_ptr(&s->dma_tt), > + memory_region_size(&s->dma_tt_alias)); > + } > + object_unparent(OBJECT(&s->dma_tt_alias)); > + > + 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) { > + uint64_t dma_tt_size; > + if (s->dma_tl_limit <=3D memory_region_size(&s->dma_tt)) { > + dma_tt_size =3D s->dma_tl_limit; > + } else { > + dma_tt_size =3D memory_region_size(&s->dma_tt); > + } > + memory_region_init_alias(&s->dma_tt_alias, NULL, > + "dma-table-alias", > + &s->dma_tt, 0, dma_tt_size); > + dma_tl_contents =3D memory_region_get_ram_ptr(&s->dma_tt); > + cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_si= ze); > + > + memory_region_transaction_begin(); > + entries =3D dma_tt_size / 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_alias); > + memory_region_transaction_commit(); > + } else { > + memory_region_init(&s->dma_tt_alias, NULL, > + "dma-table-alias", 0); > + } > +} > + > + > static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) > { > rc4030State *s =3D opaque; > @@ -279,11 +383,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 +694,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 +779,8 @@ 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, MEMTXATTRS_UNSPECIFIED, buf, len, > + is_write); > } > =20 > static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, in= t is_write) > @@ -733,7 +806,8 @@ 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); > + address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED, > + buf, len, is_write); > =20 > s->dma_regs[n][DMA_REG_ENABLE] |=3D DMA_FLAG_TC_INTR; > s->dma_regs[n][DMA_REG_COUNT] -=3D len; > @@ -800,6 +874,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 +896,19 @@ 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_rom_device(&s->dma_tt, NULL, > + &rc4030_dma_tt_ops, s, "dma-table", > + MAX_TL_ENTRIES * sizeof(dma_pagetable_= entry), > + NULL); > + memory_region_init(&s->dma_tt_alias, NULL, "dma-table-alias", 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; > } I don't have a big knowledge of the memory API, but it clearly looks cleaner than the current code. Reviewed-by: Aurelien Jarno --=20 Aurelien Jarno GPG: 4096R/1DDD8C9B aurelien@aurel32.net http://www.aurel32.net