Patchwork [RFC,1/3] sysbus: Add support for resizing and unmapping MMIOs

login
register
mail settings
Submitter Peter Maydell
Date June 8, 2011, 11:33 a.m.
Message ID <1307532813-27175-2-git-send-email-peter.maydell@linaro.org>
Download mbox | patch
Permalink /patch/99416/
State New
Headers show

Comments

Peter Maydell - June 8, 2011, 11:33 a.m.
From: Juha Riihimäki <juha.riihimaki@nokia.com>

Add new functions sysbus_mmio_unmap() and sysbus_mmio_resize()
which allow a sysbus device user to trim the size of the
device's mmio region and also to unmap it.

The rationale here is twofold:
 * Some generic qdev devices might have an mmio region that
   doesn't match the specific implementation. For example
   usb-ohci creates an 0x1000 byte mmio for its registers,
   but the instantiation of the OHCI controller on OMAP3
   has only an 0x400 byte space in the memory map. Using
   resize lets us not worry about how overlapping mapped
   regions are resolved.
 * The OMAP GPMC (general purpose memory controller) has
   a set of registers which allow the guest to control
   whether and at what size various of its subdevices are
   mapped. At the moment QEMU's omap_gpmc model isn't
   qdevified, but when it and its children are this will
   be necessary.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/sysbus.c |   37 +++++++++++++++++++++++++++++++++++++
 hw/sysbus.h |    2 ++
 2 files changed, 39 insertions(+), 0 deletions(-)

Patch

diff --git a/hw/sysbus.c b/hw/sysbus.c
index 2e22be7..01ebe47 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -39,6 +39,23 @@  void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
     }
 }
 
+void sysbus_mmio_unmap(SysBusDevice *dev, int n)
+{
+    assert(n >= 0 && n < dev->num_mmio);
+
+    if (dev->mmio[n].addr == (target_phys_addr_t)-1) {
+        /* region already unmapped */
+        return;
+    }
+    if (dev->mmio[n].cb) {
+        dev->mmio[n].cb(dev, (target_phys_addr_t)-1);
+    } else {
+        cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
+                                     IO_MEM_UNASSIGNED);
+    }
+    dev->mmio[n].addr = (target_phys_addr_t)-1;
+}
+
 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
 {
     assert(n >= 0 && n < dev->num_mmio);
@@ -61,6 +78,26 @@  void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
     }
 }
 
+void sysbus_mmio_resize(SysBusDevice *dev, int n, target_phys_addr_t newsize)
+{
+    target_phys_addr_t addr;
+    assert(n >= 0 && n < dev->num_mmio);
+
+    if (newsize != dev->mmio[n].size) {
+        addr = dev->mmio[n].addr;
+        if (addr != (target_phys_addr_t)-1) {
+            /* The expected use case is that resizes will only happen
+             * on unmapped regions, but we handle the already-mapped
+             * case by temporarily unmapping and remapping.
+             */
+            sysbus_mmio_unmap(dev, n);
+        }
+        dev->mmio[n].size = newsize;
+        if (addr != (target_phys_addr_t)-1) {
+            sysbus_mmio_map(dev, n, addr);
+        }
+    }
+}
 
 /* Request an IRQ source.  The actual IRQ object may be populated later.  */
 void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 4e8cb16..70e2488 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -53,6 +53,8 @@  void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
 
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
+void sysbus_mmio_unmap(SysBusDevice *dev, int n);
+void sysbus_mmio_resize(SysBusDevice *dev, int n, target_phys_addr_t newsize);
 
 /* Legacy helper function for creating devices.  */
 DeviceState *sysbus_create_varargs(const char *name,