From patchwork Wed Feb 29 11:45:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 143709 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 2643EB6F9D for ; Wed, 29 Feb 2012 22:46:04 +1100 (EST) Received: from localhost ([::1]:51200 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S2hyr-0001Cm-Ug for incoming@patchwork.ozlabs.org; Wed, 29 Feb 2012 06:46:01 -0500 Received: from eggs.gnu.org ([208.118.235.92]:48549) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S2hyc-0001CO-Lc for qemu-devel@nongnu.org; Wed, 29 Feb 2012 06:45:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S2hy7-0002Iu-EG for qemu-devel@nongnu.org; Wed, 29 Feb 2012 06:45:46 -0500 Received: from mx1.redhat.com ([209.132.183.28]:28133) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S2hy7-0002IH-5w for qemu-devel@nongnu.org; Wed, 29 Feb 2012 06:45:15 -0500 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q1TBjDFl012723 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 29 Feb 2012 06:45:13 -0500 Received: from rincewind.home.kraxel.org (ovpn-116-25.ams2.redhat.com [10.36.116.25]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q1TBjCsM010468; Wed, 29 Feb 2012 06:45:12 -0500 Received: by rincewind.home.kraxel.org (Postfix, from userid 500) id A45CA4115B; Wed, 29 Feb 2012 12:45:10 +0100 (CET) From: Gerd Hoffmann To: seabios@seabios.org Date: Wed, 29 Feb 2012 12:45:10 +0100 Message-Id: <1330515910-725-7-git-send-email-kraxel@redhat.com> In-Reply-To: <1330515910-725-1-git-send-email-kraxel@redhat.com> References: <1330515910-725-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: qemu-devel@nongnu.org, Gerd Hoffmann Subject: [Qemu-devel] [PATCH v2 6/6] pci: add prefmem64 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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"); }