summaryrefslogtreecommitdiffstats
path: root/hw/pci/pci.c
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2013-03-03 10:21:26 -0700
committerMichael S. Tsirkin <mst@redhat.com>2013-03-26 21:02:16 +0200
commite01fd687185444944b0b5b0f8c739ae4b33eb029 (patch)
tree39881a0805e5b76331786b8440515ed6e4037f5d /hw/pci/pci.c
parenta38b2c49bfd3f1cfc2aadd08cd049af16a342b1e (diff)
downloadhqemu-e01fd687185444944b0b5b0f8c739ae4b33eb029.zip
hqemu-e01fd687185444944b0b5b0f8c739ae4b33eb029.tar.gz
pci: Add PCI VGA helpers
Allow devices to register VGA memory regions for handling PCI spec defined VGA I/O port and MMIO areas. PCI will attach these to the bus address spaces and enable them according to the device command register value. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/pci/pci.c')
-rw-r--r--hw/pci/pci.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 2f45c8f..ed43111 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -875,6 +875,8 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
continue;
memory_region_del_subregion(r->address_space, r->memory);
}
+
+ pci_unregister_vga(pci_dev);
}
static int pci_unregister_device(DeviceState *dev)
@@ -937,6 +939,63 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
: pci_dev->bus->address_space_mem;
}
+static void pci_update_vga(PCIDevice *pci_dev)
+{
+ uint16_t cmd;
+
+ if (!pci_dev->has_vga) {
+ return;
+ }
+
+ cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
+
+ memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_MEM],
+ cmd & PCI_COMMAND_MEMORY);
+ memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO],
+ cmd & PCI_COMMAND_IO);
+ memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI],
+ cmd & PCI_COMMAND_IO);
+}
+
+void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
+ MemoryRegion *io_lo, MemoryRegion *io_hi)
+{
+ assert(!pci_dev->has_vga);
+
+ assert(memory_region_size(mem) == QEMU_PCI_VGA_MEM_SIZE);
+ pci_dev->vga_regions[QEMU_PCI_VGA_MEM] = mem;
+ memory_region_add_subregion_overlap(pci_dev->bus->address_space_mem,
+ QEMU_PCI_VGA_MEM_BASE, mem, 1);
+
+ assert(memory_region_size(io_lo) == QEMU_PCI_VGA_IO_LO_SIZE);
+ pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO] = io_lo;
+ memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
+ QEMU_PCI_VGA_IO_LO_BASE, io_lo, 1);
+
+ assert(memory_region_size(io_hi) == QEMU_PCI_VGA_IO_HI_SIZE);
+ pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI] = io_hi;
+ memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
+ QEMU_PCI_VGA_IO_HI_BASE, io_hi, 1);
+ pci_dev->has_vga = true;
+
+ pci_update_vga(pci_dev);
+}
+
+void pci_unregister_vga(PCIDevice *pci_dev)
+{
+ if (!pci_dev->has_vga) {
+ return;
+ }
+
+ memory_region_del_subregion(pci_dev->bus->address_space_mem,
+ pci_dev->vga_regions[QEMU_PCI_VGA_MEM]);
+ memory_region_del_subregion(pci_dev->bus->address_space_io,
+ pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO]);
+ memory_region_del_subregion(pci_dev->bus->address_space_io,
+ pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI]);
+ pci_dev->has_vga = false;
+}
+
pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
{
return pci_dev->io_regions[region_num].addr;
@@ -1036,6 +1095,8 @@ static void pci_update_mappings(PCIDevice *d)
r->addr, r->memory, 1);
}
}
+
+ pci_update_vga(d);
}
static inline int pci_irq_disabled(PCIDevice *d)
OpenPOWER on IntegriCloud