From patchwork Mon Oct 10 14:59:39 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Avi Kivity X-Patchwork-Id: 118782 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 466F9B71AD for ; Tue, 11 Oct 2011 03:40:45 +1100 (EST) Received: from localhost ([::1]:33928 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RDHLi-0006mw-FI for incoming@patchwork.ozlabs.org; Mon, 10 Oct 2011 11:01:02 -0400 Received: from eggs.gnu.org ([140.186.70.92]:37760) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RDHLB-0005f1-BE for qemu-devel@nongnu.org; Mon, 10 Oct 2011 11:00:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RDHL2-00028F-KT for qemu-devel@nongnu.org; Mon, 10 Oct 2011 11:00:29 -0400 Received: from mx1.redhat.com ([209.132.183.28]:14631) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RDHL1-00027b-V7 for qemu-devel@nongnu.org; Mon, 10 Oct 2011 11:00:20 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p9AF0H52004391 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 10 Oct 2011 11:00:18 -0400 Received: from cleopatra.tlv.redhat.com (cleopatra.tlv.redhat.com [10.35.255.11]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p9AF0EGL019800; Mon, 10 Oct 2011 11:00:17 -0400 Received: from s01.tlv.redhat.com (s01.tlv.redhat.com [10.35.255.8]) by cleopatra.tlv.redhat.com (Postfix) with ESMTP id 51E95B06BD; Mon, 10 Oct 2011 17:00:01 +0200 (IST) From: Avi Kivity To: Anthony Liguori , qemu-devel@nongnu.org Date: Mon, 10 Oct 2011 16:59:39 +0200 Message-Id: <1318258793-10576-11-git-send-email-avi@redhat.com> In-Reply-To: <1318258793-10576-1-git-send-email-avi@redhat.com> References: <1318258793-10576-1-git-send-email-avi@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 10/24] Introduce PortioList X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add a type and methods for manipulating a list of disjoint I/O ports, used in some older hardware devices. Based on original patch by Richard Henderson. Signed-off-by: Richard Henderson Signed-off-by: Avi Kivity --- Makefile.objs | 2 +- Makefile.target | 2 +- ioport.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ioport.h | 21 +++++++++++ memory.c | 8 ++-- 5 files changed, 135 insertions(+), 6 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index c849e51..9e70253 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -82,7 +82,7 @@ common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o common-obj-y += tcg-runtime.o host-utils.o -common-obj-y += irq.o ioport.o input.o +common-obj-y += irq.o input.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_MAX7310) += max7310.o common-obj-$(CONFIG_WM8750) += wm8750.o diff --git a/Makefile.target b/Makefile.target index 1aa6fce..f24d0aa 100644 --- a/Makefile.target +++ b/Makefile.target @@ -183,7 +183,7 @@ endif #CONFIG_BSD_USER # System emulator target ifdef CONFIG_SOFTMMU -obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o +obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly obj-$(CONFIG_NO_PCI) += pci-stub.o diff --git a/ioport.c b/ioport.c index a32483b..36fa3a4 100644 --- a/ioport.c +++ b/ioport.c @@ -27,6 +27,7 @@ #include "ioport.h" #include "trace.h" +#include "memory.h" /***********************************************************/ /* IO Port */ @@ -313,3 +314,110 @@ uint32_t cpu_inl(pio_addr_t addr) LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val); return val; } + +void portio_list_init(PortioList *piolist, + const MemoryRegionPortio *callbacks, + void *opaque, const char *name) +{ + unsigned n = 0; + + while (callbacks[n].size) { + ++n; + } + + piolist->ports = callbacks; + piolist->nr = 0; + piolist->regions = g_new0(MemoryRegion *, n); + piolist->address_space = NULL; + piolist->opaque = opaque; + piolist->name = name; +} + +void portio_list_destroy(PortioList *piolist) +{ + g_free(piolist->regions); +} + +static void portio_list_add_1(PortioList *piolist, + const MemoryRegionPortio *pio_init, + unsigned count, unsigned start, + unsigned off_low, unsigned off_high) +{ + MemoryRegionPortio *pio; + MemoryRegionOps *ops; + MemoryRegion *region; + unsigned i; + + /* Copy the sub-list and null-terminate it. */ + pio = g_new(MemoryRegionPortio, count + 1); + memcpy(pio, pio_init, sizeof(MemoryRegionPortio) * count); + memset(pio + count, 0, sizeof(MemoryRegionPortio)); + + /* Adjust the offsets to all be zero-based for the region. */ + for (i = 0; i < count; ++i) { + pio[i].offset -= off_low; + } + + ops = g_new0(MemoryRegionOps, 1); + ops->old_portio = pio; + + region = g_new(MemoryRegion, 1); + memory_region_init_io(region, ops, piolist->opaque, piolist->name, + off_high - off_low); + memory_region_set_offset(region, start + off_low); + memory_region_add_subregion(piolist->address_space, + start + off_low, region); + piolist->regions[piolist->nr++] = region; +} + +void portio_list_add(PortioList *piolist, + MemoryRegion *address_space, + uint32_t start) +{ + const MemoryRegionPortio *pio, *pio_start = piolist->ports; + unsigned int off_low, off_high, off_last, count; + + piolist->address_space = address_space; + + /* Handle the first entry specially. */ + off_last = off_low = pio_start->offset; + off_high = off_low + pio_start->len; + count = 1; + + for (pio = pio_start + 1; pio->size != 0; pio++, count++) { + /* All entries must be sorted by offset. */ + assert(pio->offset >= off_last); + off_last = pio->offset; + + /* If we see a hole, break the region. */ + if (off_last > off_high) { + portio_list_add_1(piolist, pio_start, count, start, off_low, + off_high); + /* ... and start collecting anew. */ + pio_start = pio; + off_low = off_last; + off_high = off_low + pio->len; + count = 0; + } else if (off_last + pio->len > off_high) { + off_high = off_last + pio->len; + } + } + + /* There will always be an open sub-list. */ + portio_list_add_1(piolist, pio_start, count, start, off_low, off_high); +} + +void portio_list_del(PortioList *piolist) +{ + MemoryRegion *mr; + unsigned i; + + for (i = 0; i < piolist->nr; ++i) { + mr = piolist->regions[i]; + memory_region_del_subregion(piolist->address_space, mr); + memory_region_destroy(mr); + g_free((MemoryRegionOps *)mr->ops); + g_free(mr); + piolist->regions[i] = NULL; + } +} diff --git a/ioport.h b/ioport.h index 82ffd9d..968cc23 100644 --- a/ioport.h +++ b/ioport.h @@ -52,4 +52,25 @@ uint8_t cpu_inb(pio_addr_t addr); uint16_t cpu_inw(pio_addr_t addr); uint32_t cpu_inl(pio_addr_t addr); +typedef struct MemoryRegion MemoryRegion; +typedef struct MemoryRegionPortio MemoryRegionPortio; + +typedef struct PortioList { + const MemoryRegionPortio *ports; + MemoryRegion *address_space; + unsigned nr; + MemoryRegion **regions; + void *opaque; + const char *name; +} PortioList; + +void portio_list_init(PortioList *piolist, + const MemoryRegionPortio *callbacks, + void *opaque, const char *name); +void portio_list_destroy(PortioList *piolist); +void portio_list_add(PortioList *piolist, + MemoryRegion *address_space, + uint32_t addr); +void portio_list_del(PortioList *piolist); + #endif /* IOPORT_H */ diff --git a/memory.c b/memory.c index f46e626..27abd3e 100644 --- a/memory.c +++ b/memory.c @@ -403,12 +403,12 @@ static void memory_region_iorange_read(IORange *iorange, *data = ((uint64_t)1 << (width * 8)) - 1; if (mrp) { - *data = mrp->read(mr->opaque, offset); + *data = mrp->read(mr->opaque, offset + mr->offset); } return; } *data = 0; - access_with_adjusted_size(offset, data, width, + access_with_adjusted_size(offset + mr->offset, data, width, mr->ops->impl.min_access_size, mr->ops->impl.max_access_size, memory_region_read_accessor, mr); @@ -425,11 +425,11 @@ static void memory_region_iorange_write(IORange *iorange, const MemoryRegionPortio *mrp = find_portio(mr, offset, width, true); if (mrp) { - mrp->write(mr->opaque, offset, data); + mrp->write(mr->opaque, offset + mr->offset, data); } return; } - access_with_adjusted_size(offset, &data, width, + access_with_adjusted_size(offset + mr->offset, &data, width, mr->ops->impl.min_access_size, mr->ops->impl.max_access_size, memory_region_write_accessor, mr);