diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2013-03-03 10:21:26 -0700 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2013-03-26 21:02:16 +0200 |
commit | e01fd687185444944b0b5b0f8c739ae4b33eb029 (patch) | |
tree | 39881a0805e5b76331786b8440515ed6e4037f5d /hw/pci/pci.c | |
parent | a38b2c49bfd3f1cfc2aadd08cd049af16a342b1e (diff) | |
download | qemu-e01fd687185444944b0b5b0f8c739ae4b33eb029.zip qemu-e01fd687185444944b0b5b0f8c739ae4b33eb029.tar.gz qemu-e01fd687185444944b0b5b0f8c739ae4b33eb029.tar.bz2 |
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.c | 61 |
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) |