diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2013-04-19 11:15:20 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2013-04-19 11:15:20 +0100 |
commit | 89a32d32fb573b32bbe129421602c2b3c3c247ec (patch) | |
tree | 848a0f17c4f74fca1489839556742c93e2ccada1 /hw | |
parent | a2bff788d2316c037ce5ab72468b3fda1a0527a1 (diff) | |
download | qemu-89a32d32fb573b32bbe129421602c2b3c3c247ec.zip qemu-89a32d32fb573b32bbe129421602c2b3c3c247ec.tar.gz qemu-89a32d32fb573b32bbe129421602c2b3c3c247ec.tar.bz2 |
versatile_pci: Expose PCI memory space to system
The VersatilePB's PCI controller exposes the PCI memory space to the
system via three regions controlled by the mapping control registers.
Implement this so that guests can actually use MMIO-BAR PCI cards.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Acked-by: Paul Brook <paul@codesourcery.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/realview.c | 3 | ||||
-rw-r--r-- | hw/arm/versatilepb.c | 3 | ||||
-rw-r--r-- | hw/pci-host/versatile.c | 72 |
3 files changed, 77 insertions, 1 deletions
diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 8f561c2..d6f47bf 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -221,6 +221,9 @@ static void realview_init(QEMUMachineInitArgs *args, sysbus_mmio_map(busdev, 1, 0x60000000); /* PCI self-config */ sysbus_mmio_map(busdev, 2, 0x61000000); /* PCI config */ sysbus_mmio_map(busdev, 3, 0x62000000); /* PCI I/O */ + sysbus_mmio_map(busdev, 4, 0x63000000); /* PCI memory window 1 */ + sysbus_mmio_map(busdev, 5, 0x64000000); /* PCI memory window 2 */ + sysbus_mmio_map(busdev, 6, 0x68000000); /* PCI memory window 3 */ sysbus_connect_irq(busdev, 0, pic[48]); sysbus_connect_irq(busdev, 1, pic[49]); sysbus_connect_irq(busdev, 2, pic[50]); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 8128fcd..753757e 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -228,6 +228,9 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) sysbus_mmio_map(busdev, 1, 0x41000000); /* PCI self-config */ sysbus_mmio_map(busdev, 2, 0x42000000); /* PCI config */ sysbus_mmio_map(busdev, 3, 0x43000000); /* PCI I/O */ + sysbus_mmio_map(busdev, 4, 0x44000000); /* PCI memory window 1 */ + sysbus_mmio_map(busdev, 5, 0x50000000); /* PCI memory window 2 */ + sysbus_mmio_map(busdev, 6, 0x60000000); /* PCI memory window 3 */ sysbus_connect_irq(busdev, 0, sic[27]); sysbus_connect_irq(busdev, 1, sic[28]); sysbus_connect_irq(busdev, 2, sic[29]); diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index b0132e6..e99f35f 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -42,13 +42,20 @@ typedef struct { MemoryRegion controlregs; MemoryRegion mem_config; MemoryRegion mem_config2; + /* Containers representing the PCI address spaces */ MemoryRegion pci_io_space; + MemoryRegion pci_mem_space; + /* Alias regions into PCI address spaces which we expose as sysbus regions. + * The offsets into pci_mem_space are controlled by the imap registers. + */ MemoryRegion pci_io_window; + MemoryRegion pci_mem_window[3]; PCIBus pci_bus; PCIDevice pci_dev; /* Constant for life of device: */ int realview; + uint32_t mem_win_size[3]; /* Variable state: */ uint32_t imap[3]; @@ -58,10 +65,49 @@ typedef struct { uint8_t irq_mapping; } PCIVPBState; +static void pci_vpb_update_window(PCIVPBState *s, int i) +{ + /* Adjust the offset of the alias region we use for + * the memory window i to account for a change in the + * value of the corresponding IMAP register. + * Note that the semantics of the IMAP register differ + * for realview and versatile variants of the controller. + */ + hwaddr offset; + if (s->realview) { + /* Top bits of register (masked according to window size) provide + * top bits of PCI address. + */ + offset = s->imap[i] & ~(s->mem_win_size[i] - 1); + } else { + /* Bottom 4 bits of register provide top 4 bits of PCI address */ + offset = s->imap[i] << 28; + } + memory_region_set_alias_offset(&s->pci_mem_window[i], offset); +} + +static void pci_vpb_update_all_windows(PCIVPBState *s) +{ + /* Update all alias windows based on the current register state */ + int i; + + for (i = 0; i < 3; i++) { + pci_vpb_update_window(s, i); + } +} + +static int pci_vpb_post_load(void *opaque, int version_id) +{ + PCIVPBState *s = opaque; + pci_vpb_update_all_windows(s); + return 0; +} + static const VMStateDescription pci_vpb_vmstate = { .name = "versatile-pci", .version_id = 1, .minimum_version_id = 1, + .post_load = pci_vpb_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(imap, PCIVPBState, 3), VMSTATE_UINT32_ARRAY(smap, PCIVPBState, 3), @@ -103,6 +149,7 @@ static void pci_vpb_reg_write(void *opaque, hwaddr addr, { int win = (addr - PCI_IMAP0) >> 2; s->imap[win] = val; + pci_vpb_update_window(s, win); break; } case PCI_SELFID: @@ -270,6 +317,8 @@ static void pci_vpb_reset(DeviceState *d) s->selfid = 0; s->flags = 0; s->irq_mapping = PCI_VPB_IRQMAP_ASSUME_OK; + + pci_vpb_update_all_windows(s); } static void pci_vpb_init(Object *obj) @@ -278,9 +327,10 @@ static void pci_vpb_init(Object *obj) PCIVPBState *s = PCI_VPB(obj); memory_region_init(&s->pci_io_space, "pci_io", 1ULL << 32); + memory_region_init(&s->pci_mem_space, "pci_mem", 1ULL << 32); pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), "pci", - get_system_memory(), &s->pci_io_space, + &s->pci_mem_space, &s->pci_io_space, PCI_DEVFN(11, 0), TYPE_PCI_BUS); h->bus = &s->pci_bus; @@ -288,6 +338,11 @@ static void pci_vpb_init(Object *obj) qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus)); object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(29, 0), "addr", NULL); + + /* Window sizes for VersatilePB; realview_pci's init will override */ + s->mem_win_size[0] = 0x0c000000; + s->mem_win_size[1] = 0x10000000; + s->mem_win_size[2] = 0x10000000; } static void pci_vpb_realize(DeviceState *dev, Error **errp) @@ -314,6 +369,7 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) * 1 : PCI self config window * 2 : PCI config window * 3 : PCI IO window + * 4..6 : PCI memory windows */ memory_region_init_io(&s->controlregs, &pci_vpb_reg_ops, s, "pci-vpb-regs", 0x1000); @@ -333,6 +389,16 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->pci_io_space); + /* Create the alias regions corresponding to our three windows onto + * PCI memory space. The sizes vary from board to board; the base + * offsets are guest controllable via the IMAP registers. + */ + for (i = 0; i < 3; i++) { + memory_region_init_alias(&s->pci_mem_window[i], "pci-vbp-window", + &s->pci_mem_space, 0, s->mem_win_size[i]); + sysbus_init_mmio(sbd, &s->pci_mem_window[i]); + } + /* TODO Remove once realize propagates to child devices. */ object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); } @@ -384,6 +450,10 @@ static void pci_realview_init(Object *obj) PCIVPBState *s = PCI_VPB(obj); s->realview = 1; + /* The PCI window sizes are different on Realview boards */ + s->mem_win_size[0] = 0x01000000; + s->mem_win_size[1] = 0x04000000; + s->mem_win_size[2] = 0x08000000; } static const TypeInfo pci_realview_info = { |