qboot: enable mmconfig

Need to enable mmconfig in qboot and also need to reserve
mmconfig space in bios.

Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <1490869973-4562-1-git-send-email-yang.zhong@intel.com>
[Do not affect e820 memory map on i440FX chipset. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/hwsetup.c b/hwsetup.c
index 0e186eb..e8a452e 100644
--- a/hwsetup.c
+++ b/hwsetup.c
@@ -127,3 +127,31 @@
 
 	setup_pic();
 }
+
+#define Q35_HOST_BRIDGE_PCIEXBAREN      1
+#define Q35_HOST_BRIDGE_PCIEXBAR        0x60
+
+static void setup_q35_mmconfig(void)
+{
+	const int bdf = 0;
+	uint64_t addr = PCIE_MMCONFIG_BASE;
+	uint32_t upper = addr >> 32;
+	uint32_t lower = (addr & 0xffffffff) | Q35_HOST_BRIDGE_PCIEXBAREN;
+
+	pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0);
+	pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper);
+	pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
+}
+
+bool setup_mmconfig(void)
+{
+	const int bdf = 0;
+	uint32_t id = pci_config_readl(bdf, 0);
+
+	if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35_MCH << 16))) {
+		setup_q35_mmconfig();
+		return true;
+	}
+
+	return false;
+}
diff --git a/include/bios.h b/include/bios.h
index bc96f87..df60c5a 100644
--- a/include/bios.h
+++ b/include/bios.h
@@ -40,6 +40,7 @@
 
 extern void setup_pci(void);
 extern void setup_hw(void);
+extern bool setup_mmconfig(void);
 extern void extract_acpi(void);
 extern void boot_from_fwcfg(void);
 extern bool boot_from_cbfs(void *base, size_t sz);
diff --git a/include/pci.h b/include/pci.h
index bb37b86..7f40f38 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -72,4 +72,7 @@
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
 #define PCI_DEVICE_ID_INTEL_82371AB	0x7111
 
+#define PCIE_MMCONFIG_BASE 0xb0000000
+#define PCIE_MMCONFIG_SIZE (256 * 1024 * 1024)
+
 #endif
diff --git a/main.c b/main.c
index 1913b37..f092289 100644
--- a/main.c
+++ b/main.c
@@ -6,6 +6,7 @@
 #include "segment.h"
 #include "fw_cfg.h"
 #include "pflash.h"
+#include "pci.h"
 
 static void set_realmode_int(int vec, void *p)
 {
@@ -30,6 +31,7 @@
 /* Top of memory below 4GB.  */
 uint32_t lowmem;
 struct e820map *e820;
+static bool have_mmconfig;
 
 static void extract_e820(void)
 {
@@ -42,7 +44,7 @@
 		panic();
 
 	size = fw_cfg_file_size(id);
-	nr_map = size / sizeof(e820->map[0]) + 4;
+	nr_map = size / sizeof(e820->map[0]) + 5;
 
 	e820 = malloc(offsetof(struct e820map, map[nr_map]));
 	e820->nr_map = nr_map;
@@ -54,8 +56,16 @@
 		{ .addr = 0xd0000, .size = 128 * 1024, .type = E820_NVS }; /* ACPI tables */
 	e820->map[3] = (struct e820entry)
 		{ .addr = 0xf0000, .size = 64 * 1024, .type = E820_RESERVED }; /* firmware */
-	fw_cfg_read_file(id, &e820->map[4], size);
-	for (i = 4; i < e820->nr_map; i++)
+
+	i = 4;
+	if (have_mmconfig)
+		e820->map[i++] = (struct e820entry)
+			{ .addr = PCIE_MMCONFIG_BASE, .size = PCIE_MMCONFIG_SIZE, .type = E820_RESERVED };
+	else
+		nr_map--;
+
+	fw_cfg_read_file(id, &e820->map[i], size);
+	for (; i < e820->nr_map; i++)
 		if (e820->map[i].addr == 0) {
 			lowmem = e820->map[i].size;
 			e820->map[i].addr = 1024 * 1024;
@@ -85,6 +95,7 @@
 	// in order to probe CBFS!
 	asm("ljmp $0x8, $1f; 1:");
 
+	have_mmconfig = setup_mmconfig();
 	setup_pci();
 	setup_idt();
 	fw_cfg_setup();