]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/commitdiff
pci: Teach PCI Bridges about VGA routing
authorAlex Williamson <alex.williamson@redhat.com>
Sun, 3 Mar 2013 17:21:32 +0000 (10:21 -0700)
committerMichael S. Tsirkin <mst@redhat.com>
Tue, 26 Mar 2013 19:02:17 +0000 (21:02 +0200)
Each PCI Bridge has a set of implied VGA regions that are enabled when
the VGA bit is set in the bridge control register.  This allows VGA
devices behind bridges.  Unfortunately with VGA Enable, which we
formerly allowed but didn't back, comes along some required VGA
baggage.  VGA Palette Snooping is required, along with VGA 16-bit
decoding.  We don't yet have support for palette snooping.
We also don't have support for 10-bit VGA aliases, the default mode, but
we enable the register, even on root ports, to avoid confusing guests.
Fortunately there's likely nothing from this century that requires these
features, so the missing bits are noted with TODOs.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
hw/pci/pci.c
hw/pci/pci_bridge.c
hw/pci/pci_bus.h
hw/pci/pcie_port.c

index ed43111bce6afccc9c1d22220afb68d68dea08f7..a88160236e1c132917a4936d62d397ba3479cff6 100644 (file)
@@ -674,6 +674,10 @@ static void pci_init_mask_bridge(PCIDevice *d)
 #define  PCI_BRIDGE_CTL_SEC_DISCARD    0x200   /* Secondary discard timer */
 #define  PCI_BRIDGE_CTL_DISCARD_STATUS 0x400   /* Discard timer status */
 #define  PCI_BRIDGE_CTL_DISCARD_SERR   0x800   /* Discard timer SERR# enable */
+/*
+ * TODO: Bridges default to 10-bit VGA decoding but we currently only
+ * implement 16-bit decoding (no alias support).
+ */
     pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
                  PCI_BRIDGE_CTL_PARITY |
                  PCI_BRIDGE_CTL_SERR |
index 995842a72d04217a358dab01affa37cf7c452a84..edb8c8d9c9eddaf77f3afaef5725db0e5e7a8371 100644 (file)
@@ -151,6 +151,28 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
     memory_region_add_subregion_overlap(parent_space, base, alias, 1);
 }
 
+static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent,
+                                        MemoryRegion *alias_vga)
+{
+    uint16_t brctl = pci_get_word(br->dev.config + PCI_BRIDGE_CONTROL);
+
+    memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_LO],
+                             "pci_bridge_vga_io_lo", &br->address_space_io,
+                             QEMU_PCI_VGA_IO_LO_BASE, QEMU_PCI_VGA_IO_LO_SIZE);
+    memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_HI],
+                             "pci_bridge_vga_io_hi", &br->address_space_io,
+                             QEMU_PCI_VGA_IO_HI_BASE, QEMU_PCI_VGA_IO_HI_SIZE);
+    memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_MEM],
+                             "pci_bridge_vga_mem", &br->address_space_mem,
+                             QEMU_PCI_VGA_MEM_BASE, QEMU_PCI_VGA_MEM_SIZE);
+
+    if (brctl & PCI_BRIDGE_CTL_VGA) {
+        pci_register_vga(&br->dev, &alias_vga[QEMU_PCI_VGA_MEM],
+                         &alias_vga[QEMU_PCI_VGA_IO_LO],
+                         &alias_vga[QEMU_PCI_VGA_IO_HI]);
+    }
+}
+
 static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
 {
     PCIBus *parent = br->dev.bus;
@@ -175,7 +197,8 @@ static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
                           &br->address_space_io,
                           parent->address_space_io,
                           cmd & PCI_COMMAND_IO);
-   /* TODO: optinal VGA and VGA palette snooping support. */
+
+    pci_bridge_init_vga_aliases(br, parent, w->alias_vga);
 
     return w;
 }
@@ -187,6 +210,7 @@ static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w)
     memory_region_del_subregion(parent->address_space_io, &w->alias_io);
     memory_region_del_subregion(parent->address_space_mem, &w->alias_mem);
     memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem);
+    pci_unregister_vga(&br->dev);
 }
 
 static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
@@ -194,6 +218,9 @@ static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
     memory_region_destroy(&w->alias_io);
     memory_region_destroy(&w->alias_mem);
     memory_region_destroy(&w->alias_pref_mem);
+    memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_LO]);
+    memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_HI]);
+    memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_MEM]);
     g_free(w);
 }
 
@@ -227,7 +254,10 @@ void pci_bridge_write_config(PCIDevice *d,
 
         /* memory base/limit, prefetchable base/limit and
            io base/limit upper 16 */
-        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
+        ranges_overlap(address, len, PCI_MEMORY_BASE, 20) ||
+
+        /* vga enable */
+        ranges_overlap(address, len, PCI_BRIDGE_CONTROL, 2)) {
         pci_bridge_update_mappings(s);
     }
 
@@ -306,6 +336,16 @@ int pci_bridge_initfn(PCIDevice *dev)
 
     pci_word_test_and_set_mask(dev->config + PCI_STATUS,
                                PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+
+    /*
+     * TODO: We implement VGA Enable in the Bridge Control Register
+     * therefore per the PCI to PCI bridge spec we must also implement
+     * VGA Palette Snooping.  When done, set this bit writable:
+     *
+     * pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND,
+     *                            PCI_COMMAND_VGA_PALETTE);
+     */
+
     pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
     dev->config[PCI_HEADER_TYPE] =
         (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
index f905b9e11e112d3229995fe17294701dff752733..aef559ae1f1845f1be64ed45319fe82340fc640c 100644 (file)
@@ -47,6 +47,13 @@ struct PCIBridgeWindows {
     MemoryRegion alias_pref_mem;
     MemoryRegion alias_mem;
     MemoryRegion alias_io;
+    /*
+     * When bridge control VGA forwarding is enabled, bridges will
+     * provide positive decode on the PCI VGA defined I/O port and
+     * MMIO ranges.  When enabled forwarding is only qualified on the
+     * I/O and memory enable bits in the bridge command register.
+     */
+    MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS];
 };
 
 struct PCIBridge {
index 33a6b0a08ac07ccd5e8b8eb3ddf7ebb66f80d0eb..1be107b0c97d9a951a2dc00849751be9a8a4cb0f 100644 (file)
@@ -28,10 +28,12 @@ void pcie_port_init_reg(PCIDevice *d)
     pci_set_word(d->config + PCI_SEC_STATUS, 0);
 
     /* Unlike conventional pci bridge, some bits are hardwired to 0. */
+#define  PCI_BRIDGE_CTL_VGA_16BIT       0x10    /* VGA 16-bit decode */
     pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
                  PCI_BRIDGE_CTL_PARITY |
                  PCI_BRIDGE_CTL_ISA |
                  PCI_BRIDGE_CTL_VGA |
+                 PCI_BRIDGE_CTL_VGA_16BIT | /* Req, but no alias support yet */
                  PCI_BRIDGE_CTL_SERR |
                  PCI_BRIDGE_CTL_BUS_RESET);
 }