diff options
author | Laurent Vivier <lvivier@redhat.com> | 2015-07-24 10:35:13 +0200 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2015-08-13 14:08:29 +0300 |
commit | e402463073ae51d00dc6cf98556e2f5c4b008a31 (patch) | |
tree | 2f1d897da56da6ee0b038c6285378d9ecce88391 /hw/pci | |
parent | c8d163bc9e037ec32b2250b2d7950b1d1bc3fd61 (diff) | |
download | hqemu-e402463073ae51d00dc6cf98556e2f5c4b008a31.zip hqemu-e402463073ae51d00dc6cf98556e2f5c4b008a31.tar.gz |
pci: allow 0 address for PCI IO/MEM regions
Some kernels program a 0 address for io regions. PCI 3.0 spec
section 6.2.5.1 doesn't seem to disallow this.
based on patch by Michael Roth <mdroth@linux.vnet.ibm.com>
Add pci_allow_0_addr in MachineClass to conditionally
allow addr 0 for pseries, as this can break other architectures.
This patch allows to hotplug PCI card in pseries machine, as the first
added card BAR0 is always set to 0 address.
This as a temporary hack, waiting to fix PCI memory priorities for more
machine types...
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/pci')
-rw-r--r-- | hw/pci/pci.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c index a017614..9f57aea 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -38,6 +38,7 @@ #include "hw/pci/msix.h" #include "exec/address-spaces.h" #include "hw/hotplug.h" +#include "hw/boards.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -1065,6 +1066,10 @@ static pcibus_t pci_bar_address(PCIDevice *d, pcibus_t new_addr, last_addr; int bar = pci_bar(d, reg); uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); + Object *machine = qdev_get_machine(); + ObjectClass *oc = object_get_class(machine); + MachineClass *mc = MACHINE_CLASS(oc); + bool allow_0_address = mc->pci_allow_0_address; if (type & PCI_BASE_ADDRESS_SPACE_IO) { if (!(cmd & PCI_COMMAND_IO)) { @@ -1075,7 +1080,8 @@ static pcibus_t pci_bar_address(PCIDevice *d, /* Check if 32 bit BAR wraps around explicitly. * TODO: make priorities correct and remove this work around. */ - if (last_addr <= new_addr || new_addr == 0 || last_addr >= UINT32_MAX) { + if (last_addr <= new_addr || last_addr >= UINT32_MAX || + (!allow_0_address && new_addr == 0)) { return PCI_BAR_UNMAPPED; } return new_addr; @@ -1099,8 +1105,8 @@ static pcibus_t pci_bar_address(PCIDevice *d, /* XXX: as we cannot support really dynamic mappings, we handle specific values as invalid mappings. */ - if (last_addr <= new_addr || new_addr == 0 || - last_addr == PCI_BAR_UNMAPPED) { + if (last_addr <= new_addr || last_addr == PCI_BAR_UNMAPPED || + (!allow_0_address && new_addr == 0)) { return PCI_BAR_UNMAPPED; } |