[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 6/6] pci: add prefmem64
From: |
Gerd Hoffmann |
Subject: |
[Qemu-devel] [PATCH v2 6/6] pci: add prefmem64 |
Date: |
Wed, 29 Feb 2012 12:45:10 +0100 |
This patch adds a prefmem64 region for 64bit pci prefmem bars which
we'll go map above 4G. This will happen when either the device is on
the root bus or it is behind a bridge supporting 64bit memory windows
and all prefmem bars of all devices hooked up using that bridge are
64bit capable.
---
src/acpi-dsdt.dsl | 7 +++++
src/acpi-dsdt.hex | 72 +++++++++++++++++++++++++++++++++++++++++++---------
src/config.h | 2 +
src/pciinit.c | 72 +++++++++++++++++++++++++++++++++++++++++++---------
4 files changed, 127 insertions(+), 26 deletions(-)
diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl
index 7082b65..c17e947 100644
--- a/src/acpi-dsdt.dsl
+++ b/src/acpi-dsdt.dsl
@@ -175,6 +175,13 @@ DefinitionBlock (
0x00000000, // Address Translation Offset
0x1EC00000, // Address Length
,, , AddressRangeMemory, TypeStatic)
+ QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed,
Cacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x8000000000, // Address Range Minimum
+ 0xFFFFFFFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x8000000000, // Address Length
+ ,, , AddressRangeMemory, TypeStatic)
})
}
}
diff --git a/src/acpi-dsdt.hex b/src/acpi-dsdt.hex
index 5dc7bb4..2393827 100644
--- a/src/acpi-dsdt.hex
+++ b/src/acpi-dsdt.hex
@@ -3,12 +3,12 @@ static unsigned char AmlCode[] = {
0x53,
0x44,
0x54,
-0xd3,
-0x10,
+0x1,
+0x11,
0x0,
0x0,
0x1,
-0x2d,
+0x1e,
0x42,
0x58,
0x50,
@@ -31,9 +31,9 @@ static unsigned char AmlCode[] = {
0x4e,
0x54,
0x4c,
-0x28,
-0x5,
-0x10,
+0x23,
+0x1,
+0x9,
0x20,
0x10,
0x49,
@@ -110,16 +110,16 @@ static unsigned char AmlCode[] = {
0x47,
0x42,
0x10,
-0x44,
-0x81,
+0x42,
+0x84,
0x5f,
0x53,
0x42,
0x5f,
0x5b,
0x82,
-0x4c,
-0x80,
+0x4a,
+0x83,
0x50,
0x43,
0x49,
@@ -2064,10 +2064,10 @@ static unsigned char AmlCode[] = {
0x52,
0x53,
0x11,
-0x42,
-0x7,
+0x40,
+0xa,
0xa,
-0x6e,
+0x9c,
0x88,
0xd,
0x0,
@@ -2176,6 +2176,52 @@ static unsigned char AmlCode[] = {
0x0,
0xc0,
0x1e,
+0x8a,
+0x2b,
+0x0,
+0x0,
+0xc,
+0x3,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x80,
+0x0,
+0x0,
+0x0,
+0xff,
+0xff,
+0xff,
+0xff,
+0xff,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x80,
+0x0,
+0x0,
+0x0,
0x79,
0x0,
0x10,
diff --git a/src/config.h b/src/config.h
index b0187a4..5850476 100644
--- a/src/config.h
+++ b/src/config.h
@@ -47,6 +47,8 @@
#define BUILD_PCIMEM_START 0xe0000000
#define BUILD_PCIMEM_END 0xfec00000 /* IOAPIC is mapped at */
+#define BUILD_PCIMEM64_START 0x8000000000ULL
+#define BUILD_PCIMEM64_END 0xFFFFFFFFFFULL
#define BUILD_IOAPIC_ADDR 0xfec00000
#define BUILD_HPET_ADDRESS 0xfed00000
diff --git a/src/pciinit.c b/src/pciinit.c
index a03e17c..b3eaf86 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -22,13 +22,15 @@ enum pci_region_type {
PCI_REGION_TYPE_IO,
PCI_REGION_TYPE_MEM,
PCI_REGION_TYPE_PREFMEM,
+ PCI_REGION_TYPE_PREFMEM64,
PCI_REGION_TYPE_COUNT,
};
static const char *region_type_name[] = {
- [ PCI_REGION_TYPE_IO ] = "io",
- [ PCI_REGION_TYPE_MEM ] = "mem",
- [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
+ [ PCI_REGION_TYPE_IO ] = "io",
+ [ PCI_REGION_TYPE_MEM ] = "mem",
+ [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
+ [ PCI_REGION_TYPE_PREFMEM64 ] = "prefmem64",
};
struct pci_bus {
@@ -42,7 +44,9 @@ struct pci_bus {
u64 bases[32 - PCI_MEM_INDEX_SHIFT];
u64 base;
} r[PCI_REGION_TYPE_COUNT];
+ int use_prefmem64;
struct pci_device *bus_dev;
+ struct pci_bus *parent;
};
static int pci_size_to_index(u32 size, enum pci_region_type type)
@@ -67,11 +71,19 @@ static u32 pci_index_to_size(int index, enum
pci_region_type type)
static enum pci_region_type pci_addr_to_type(struct pci_bus *bus, struct
pci_bar *bar)
{
+ struct pci_bus *b;
+
if (!bar->ismem)
return PCI_REGION_TYPE_IO;
if (!bar->isprefetch)
return PCI_REGION_TYPE_MEM;
- return PCI_REGION_TYPE_PREFMEM;
+ if (!bar->is64)
+ return PCI_REGION_TYPE_PREFMEM;
+ for (b = bus; b != NULL && b->bus_dev != NULL; b = b->parent) {
+ if (!bus->use_prefmem64)
+ return PCI_REGION_TYPE_PREFMEM;
+ }
+ return PCI_REGION_TYPE_PREFMEM64;
}
static u32 pci_bar(struct pci_device *pci, int region_num)
@@ -409,12 +421,26 @@ static void pci_bios_check_devices(struct pci_bus *busses)
if (pci->class != PCI_CLASS_BRIDGE_PCI)
continue;
bus = &busses[pci->secondary_bus];
+ bus->parent = &busses[pci_bdf_to_bus(pci->bdf)];
bus->bus_dev = pci;
+ u32 pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+ if (!pmem) {
+ pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0xfff0fff0);
+ pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+ pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0x0);
+ }
+ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+ dprintf(1, "PCI: bridge bdf=%02x:%02x.%x supports prefmem64\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf));
+ bus->use_prefmem64 = 1;
+ }
}
// discover pci bars
foreachpci(pci) {
num_regions = (pci->class == PCI_CLASS_BRIDGE_PCI) ? 2 :
PCI_NUM_REGIONS;
+ bus = &busses[pci_bdf_to_bus(pci->bdf)];
dprintf(1, "PCI: check device bdf=%02x:%02x.%x\n",
pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
pci_bdf_to_fn(pci->bdf));
@@ -423,6 +449,15 @@ static void pci_bios_check_devices(struct pci_bus *busses)
if (pci->bars[i].addr == 0)
continue;
+ if (pci->bars[i].ismem && pci->bars[i].isprefetch &&
!pci->bars[i].is64) {
+ /* 32bit prefmem bar found -- disable 64bit prefmem
+ * on all bridges all the way up to the root bus */
+ struct pci_bus *b;
+ for (b = bus; b != NULL; b = b->parent) {
+ b->use_prefmem64 = 0;
+ }
+ }
+
if (pci->bars[i].is64)
i++;
}
@@ -466,22 +501,29 @@ static void pci_bios_check_devices(struct pci_bus *busses)
pci_bios_bus_reserve(parent, type, s->r[type].size);
}
dprintf(1, "PCI: secondary bus %d sizes: "
- "io %llx, mem %llx, prefmem %llx\n",
+ "io %llx, mem %llx, prefmem %llx, prefmem64 %llx\n",
secondary_bus,
s->r[PCI_REGION_TYPE_IO].size,
s->r[PCI_REGION_TYPE_MEM].size,
- s->r[PCI_REGION_TYPE_PREFMEM].size);
+ s->r[PCI_REGION_TYPE_PREFMEM].size,
+ s->r[PCI_REGION_TYPE_PREFMEM64].size);
}
}
#define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1)
// Setup region bases (given the regions' size and alignment)
-static int pci_bios_init_root_regions(struct pci_bus *bus, u32 start, u32 end)
+static int pci_bios_init_root_regions(struct pci_bus *bus)
{
+ u32 start = BUILD_PCIMEM_START;
+ u32 end = BUILD_PCIMEM_END;
+ u64 start64 = BUILD_PCIMEM64_START;
+ u64 end64 = BUILD_PCIMEM64_END;
+
bus->r[PCI_REGION_TYPE_IO].base = 0xc000;
int reg1 = PCI_REGION_TYPE_PREFMEM, reg2 = PCI_REGION_TYPE_MEM;
+ int reg3 = PCI_REGION_TYPE_PREFMEM64;
if (bus->r[reg1].sum < bus->r[reg2].sum) {
// Swap regions so larger area is more likely to align well.
reg1 = PCI_REGION_TYPE_MEM;
@@ -493,6 +535,12 @@ static int pci_bios_init_root_regions(struct pci_bus *bus,
u32 start, u32 end)
if (bus->r[reg1].base < start)
// Memory range requested is larger than available.
return -1;
+
+ bus->r[reg3].base = ROOT_BASE(end64, bus->r[reg3].sum, bus->r[reg3].max);
+ if (bus->r[reg3].base < start64)
+ // Memory range requested is larger than available.
+ return -1;
+
return 0;
}
@@ -591,6 +639,9 @@ static void pci_bios_map_devices(struct pci_bus *busses)
if (s->r[PCI_REGION_TYPE_PREFMEM].sum) {
base = s->r[PCI_REGION_TYPE_PREFMEM].base;
limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1;
+ } else if (s->r[PCI_REGION_TYPE_PREFMEM64].sum) {
+ base = s->r[PCI_REGION_TYPE_PREFMEM64].base;
+ limit = base + s->r[PCI_REGION_TYPE_PREFMEM64].size - 1;
} else {
base = PCI_BRIDGE_MEM_MIN;
limit = 0;
@@ -641,11 +692,6 @@ pci_setup(void)
return;
}
- dprintf(3, "pci setup\n");
-
- u32 start = BUILD_PCIMEM_START;
- u32 end = BUILD_PCIMEM_END;
-
dprintf(1, "=== PCI bus & bridge init ===\n");
if (pci_probe_host() != 0) {
return;
@@ -663,7 +709,7 @@ pci_setup(void)
}
memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1));
pci_bios_check_devices(busses);
- if (pci_bios_init_root_regions(&busses[0], start, end) != 0) {
+ if (pci_bios_init_root_regions(&busses[0]) != 0) {
panic("PCI: out of address space\n");
}
--
1.7.1
- [Qemu-devel] [PATCH v2 0/6] pci: 64bit support, Gerd Hoffmann, 2012/02/29
- [Qemu-devel] [PATCH v2 1/6] output: add 64bit hex print support, Gerd Hoffmann, 2012/02/29
- [Qemu-devel] [PATCH v2 6/6] pci: add prefmem64,
Gerd Hoffmann <=
- [Qemu-devel] [PATCH v2 4/6] pci: bridges can have two regions too, Gerd Hoffmann, 2012/02/29
- [Qemu-devel] [PATCH v2 5/6] pci: fix bridge ressource allocation., Gerd Hoffmann, 2012/02/29
- [Qemu-devel] [PATCH v2 2/6] pci: split device discovery into multiple steps, Gerd Hoffmann, 2012/02/29
- [Qemu-devel] [PATCH v2 3/6] pci: 64bit support., Gerd Hoffmann, 2012/02/29