qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v4 2/2] pci: Teach PCI Bridges about VGA routing


From: Michael S. Tsirkin
Subject: Re: [Qemu-devel] [PATCH v4 2/2] pci: Teach PCI Bridges about VGA routing
Date: Mon, 4 Mar 2013 11:09:37 +0200

On Sun, Mar 03, 2013 at 10:21:32AM -0700, Alex Williamson wrote:
> 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, but we do
> make the bit writable on bridges.  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 <address@hidden>
> ---
>  hw/pci/pci.c        |    4 ++++
>  hw/pci/pci_bridge.c |   45 +++++++++++++++++++++++++++++++++++++++++++--
>  hw/pci/pci_bus.h    |    7 +++++++
>  hw/pci/pcie_port.c  |    2 ++
>  4 files changed, 56 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index ed43111..a881602 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -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 |
> diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
> index 995842a..84e7c19 100644
> --- a/hw/pci/pci_bridge.c
> +++ b/hw/pci/pci_bridge.c
> @@ -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,17 @@ 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 spec we must also implement VGA Palette
> +     * Snooping.  We set this bit writable, but there's not yet
> +     * backing for doing positive decode on the subset of VGA
> +     * registers required for this.
> +     */
> +    pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND,
> +                               PCI_COMMAND_VGA_PALETTE);
> +

I've replaced this one with a comment. Both what this patch does and the
current behaviour are out of spec, but less change seems like a prudent
thing to do.

>      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) |
> diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h
> index f905b9e..aef559a 100644
> --- a/hw/pci/pci_bus.h
> +++ b/hw/pci/pci_bus.h
> @@ -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 {
> diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
> index 33a6b0a..1be107b 100644
> --- a/hw/pci/pcie_port.c
> +++ b/hw/pci/pcie_port.c
> @@ -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);
>  }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]