summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--arch/x86/kernel/aperture_64.c89
-rw-r--r--arch/x86/kernel/e820_64.c12
-rw-r--r--arch/x86/kernel/setup_64.c3
-rw-r--r--include/asm-x86/e820_64.h1
-rw-r--r--include/asm-x86/gart.h5
6 files changed, 114 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 40db7dd..860a908 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -660,6 +660,10 @@ and is between 256 and 4096 characters. It is defined in the file
gamma= [HW,DRM]
+ gart_fix_e820= [X86_64] disable the fix e820 for K8 GART
+ Format: off | on
+ default: on
+
gdth= [HW,SCSI]
See header of drivers/scsi/gdth.c.
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 52d2bea..bf1b469 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -218,6 +218,95 @@ static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
return 0;
}
+static int gart_fix_e820 __initdata = 1;
+
+static int __init parse_gart_mem(char *p)
+{
+ if (!p)
+ return -EINVAL;
+
+ if (!strncmp(p, "off", 3))
+ gart_fix_e820 = 0;
+ else if (!strncmp(p, "on", 2))
+ gart_fix_e820 = 1;
+
+ return 0;
+}
+early_param("gart_fix_e820", parse_gart_mem);
+
+void __init early_gart_iommu_check(void)
+{
+ /*
+ * in case it is enabled before, esp for kexec/kdump,
+ * previous kernel already enable that. memset called
+ * by allocate_aperture/__alloc_bootmem_nopanic cause restart.
+ * or second kernel have different position for GART hole. and new
+ * kernel could use hole as RAM that is still used by GART set by
+ * first kernel
+ * or BIOS forget to put that in reserved.
+ * try to update e820 to make that region as reserved.
+ */
+ int fix, num;
+ u32 ctl;
+ u32 aper_size = 0, aper_order = 0, last_aper_order = 0;
+ u64 aper_base = 0, last_aper_base = 0;
+ int aper_enabled = 0, last_aper_enabled = 0;
+
+ if (!early_pci_allowed())
+ return;
+
+ fix = 0;
+ for (num = 24; num < 32; num++) {
+ if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
+ continue;
+
+ ctl = read_pci_config(0, num, 3, 0x90);
+ aper_enabled = ctl & 1;
+ aper_order = (ctl >> 1) & 7;
+ aper_size = (32 * 1024 * 1024) << aper_order;
+ aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
+ aper_base <<= 25;
+
+ if ((last_aper_order && aper_order != last_aper_order) ||
+ (last_aper_base && aper_base != last_aper_base) ||
+ (last_aper_enabled && aper_enabled != last_aper_enabled)) {
+ fix = 1;
+ break;
+ }
+ last_aper_order = aper_order;
+ last_aper_base = aper_base;
+ last_aper_enabled = aper_enabled;
+ }
+
+ if (!fix && !aper_enabled)
+ return;
+
+ if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL)
+ fix = 1;
+
+ if (gart_fix_e820 && !fix && aper_enabled) {
+ if (e820_any_mapped(aper_base, aper_base + aper_size,
+ E820_RAM)) {
+ /* reserved it, so we can resuse it in second kernel */
+ printk(KERN_INFO "update e820 for GART\n");
+ add_memory_region(aper_base, aper_size, E820_RESERVED);
+ update_e820();
+ }
+ return;
+ }
+
+ /* different nodes have different setting, disable them all at first*/
+ for (num = 24; num < 32; num++) {
+ if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
+ continue;
+
+ ctl = read_pci_config(0, num, 3, 0x90);
+ ctl &= ~1;
+ write_pci_config(0, num, 3, 0x90, ctl);
+ }
+
+}
+
void __init gart_iommu_hole_init(void)
{
u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
index abc473b..07cfaae 100644
--- a/arch/x86/kernel/e820_64.c
+++ b/arch/x86/kernel/e820_64.c
@@ -728,6 +728,18 @@ void __init finish_e820_parsing(void)
}
}
+void __init update_e820(void)
+{
+ u8 nr_map;
+
+ nr_map = e820.nr_map;
+ if (sanitize_e820_map(e820.map, &nr_map))
+ return;
+ e820.nr_map = nr_map;
+ printk(KERN_INFO "modified physical RAM map:\n");
+ e820_print_map("modified");
+}
+
unsigned long pci_mem_start = 0xaeedbabe;
EXPORT_SYMBOL(pci_mem_start);
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 07547fe..12bad27 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -53,6 +53,7 @@
#include <video/edid.h>
#include <asm/e820.h>
#include <asm/dma.h>
+#include <asm/gart.h>
#include <asm/mpspec.h>
#include <asm/mmu_context.h>
#include <asm/proto.h>
@@ -335,6 +336,8 @@ void __init setup_arch(char **cmdline_p)
finish_e820_parsing();
+ early_gart_iommu_check();
+
e820_register_active_regions(0, 0, -1UL);
/*
* partially used pages are not usable - thus
diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h
index 8cba49d..ff36f43 100644
--- a/include/asm-x86/e820_64.h
+++ b/include/asm-x86/e820_64.h
@@ -39,6 +39,7 @@ extern void e820_register_active_regions(int nid,
extern void finish_e820_parsing(void);
extern struct e820map e820;
+extern void update_e820(void);
extern unsigned ebda_addr, ebda_size;
extern unsigned long nodemap_addr, nodemap_size;
diff --git a/include/asm-x86/gart.h b/include/asm-x86/gart.h
index f704c50..90958ed 100644
--- a/include/asm-x86/gart.h
+++ b/include/asm-x86/gart.h
@@ -9,6 +9,7 @@ extern int iommu_detected;
extern void gart_iommu_init(void);
extern void gart_iommu_shutdown(void);
extern void __init gart_parse_options(char *);
+extern void early_gart_iommu_check(void);
extern void gart_iommu_hole_init(void);
extern int fallback_aper_order;
extern int fallback_aper_force;
@@ -20,6 +21,10 @@ extern int fix_aperture;
#define gart_iommu_aperture 0
#define gart_iommu_aperture_allowed 0
+static inline void early_gart_iommu_check(void)
+{
+}
+
static inline void gart_iommu_shutdown(void)
{
}
OpenPOWER on IntegriCloud