aboutsummaryrefslogtreecommitdiff
path: root/hw/pci
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2013-09-02 11:37:02 +0300
committerMichael S. Tsirkin <mst@redhat.com>2013-09-15 11:49:50 +0300
commit438640695723f33be6d0081ac1e690aa40975c39 (patch)
treec19e421b79b0141f298befb84cb967b6f35efd91 /hw/pci
parentc5a22c4344f17169bb20e122e9d935c62aedc063 (diff)
downloadqemu-438640695723f33be6d0081ac1e690aa40975c39.zip
qemu-438640695723f33be6d0081ac1e690aa40975c39.tar.gz
qemu-438640695723f33be6d0081ac1e690aa40975c39.tar.bz2
pci: add helper to retrieve the 64-bit range
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/pci')
-rw-r--r--hw/pci/pci.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index ad1c1ca..52cbab7 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2257,6 +2257,56 @@ void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque)
bus->iommu_opaque = opaque;
}
+static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
+{
+ Range *range = opaque;
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ uint16_t cmd = pci_get_word(dev->config + PCI_COMMAND);
+ int r;
+
+ if (!(cmd & PCI_COMMAND_MEMORY)) {
+ return;
+ }
+
+ if (pc->is_bridge) {
+ pcibus_t base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+ pcibus_t limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+
+ base = MAX(base, 0x1ULL << 32);
+
+ if (limit >= base) {
+ Range pref_range;
+ pref_range.begin = base;
+ pref_range.end = limit + 1;
+ range_extend(range, &pref_range);
+ }
+ }
+ for (r = 0; r < PCI_NUM_REGIONS; ++r) {
+ PCIIORegion *region = &dev->io_regions[r];
+ Range region_range;
+
+ if (!region->size ||
+ (region->type & PCI_BASE_ADDRESS_SPACE_IO) ||
+ !(region->type & PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ continue;
+ }
+ region_range.begin = pci_get_quad(dev->config + pci_bar(dev, r));
+ region_range.end = region_range.begin + region->size;
+
+ region_range.begin = MAX(region_range.begin, 0x1ULL << 32);
+
+ if (region_range.end - 1 >= region_range.begin) {
+ range_extend(range, &region_range);
+ }
+ }
+}
+
+void pci_bus_get_w64_range(PCIBus *bus, Range *range)
+{
+ range->begin = range->end = 0;
+ pci_for_each_device_under_bus(bus, pci_dev_get_w64, range);
+}
+
static const TypeInfo pci_device_type_info = {
.name = TYPE_PCI_DEVICE,
.parent = TYPE_DEVICE,