]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/setup.c
x86: use round_jiffies() for the corruption check timer
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / setup.c
index c239b378097395d3270eab23d64a08b92474375f..161f1b33ecec0ccae3cd8dfaf36df52249d9c98e 100644 (file)
@@ -586,22 +586,82 @@ struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
  */
 #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
 #define MAX_SCAN_AREAS 8
+
+static int __read_mostly memory_corruption_check = -1;
+
+static unsigned __read_mostly corruption_check_size = 64*1024;
+static unsigned __read_mostly corruption_check_period = 60; /* seconds */
+
 static struct e820entry scan_areas[MAX_SCAN_AREAS];
 static int num_scan_areas;
 
+
+static int set_corruption_check(char *arg)
+{
+       char *end;
+
+       memory_corruption_check = simple_strtol(arg, &end, 10);
+
+       return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check", set_corruption_check);
+
+static int set_corruption_check_period(char *arg)
+{
+       char *end;
+
+       corruption_check_period = simple_strtoul(arg, &end, 10);
+
+       return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_period", set_corruption_check_period);
+
+static int set_corruption_check_size(char *arg)
+{
+       char *end;
+       unsigned size;
+
+       size = memparse(arg, &end);
+
+       if (*end == '\0')
+               corruption_check_size = size;
+
+       return (size == corruption_check_size) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_size", set_corruption_check_size);
+
+
 static void __init setup_bios_corruption_check(void)
 {
        u64 addr = PAGE_SIZE;   /* assume first page is reserved anyway */
 
-       while(addr < 0x10000 && num_scan_areas < MAX_SCAN_AREAS) {
+       if (memory_corruption_check == -1) {
+               memory_corruption_check =
+#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+                       1
+#else
+                       0
+#endif
+                       ;
+       }
+
+       if (corruption_check_size == 0)
+               memory_corruption_check = 0;
+
+       if (!memory_corruption_check)
+               return;
+
+       corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
+
+       while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
                u64 size;
                addr = find_e820_area_size(addr, &size, PAGE_SIZE);
 
                if (addr == 0)
                        break;
 
-               if ((addr + size) > 0x10000)
-                       size = 0x10000 - addr;
+               if ((addr + size) > corruption_check_size)
+                       size = corruption_check_size - addr;
 
                if (size == 0)
                        break;
@@ -617,12 +677,11 @@ static void __init setup_bios_corruption_check(void)
                addr += size;
        }
 
-       printk(KERN_INFO "scanning %d areas for BIOS corruption\n",
+       printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
               num_scan_areas);
        update_e820();
 }
 
-static int __read_mostly bios_corruption_check = 1;
 static struct timer_list periodic_check_timer;
 
 void check_for_bios_corruption(void)
@@ -630,7 +689,7 @@ void check_for_bios_corruption(void)
        int i;
        int corruption = 0;
 
-       if (!bios_corruption_check)
+       if (!memory_corruption_check)
                return;
 
        for(i = 0; i < num_scan_areas; i++) {
@@ -647,36 +706,60 @@ void check_for_bios_corruption(void)
                }
        }
 
-       if (corruption)
-               dump_stack();
+       WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
 }
 
 static void periodic_check_for_corruption(unsigned long data)
 {
        check_for_bios_corruption();
-       mod_timer(&periodic_check_timer, jiffies + 60*HZ);
+       mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
 }
 
 void start_periodic_check_for_corruption(void)
 {
-       if (!bios_corruption_check)
+       if (!memory_corruption_check || corruption_check_period == 0)
                return;
 
+       printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
+              corruption_check_period);
+
        init_timer(&periodic_check_timer);
        periodic_check_timer.function = &periodic_check_for_corruption;
        periodic_check_for_corruption(0);
 }
+#endif
 
-static int set_bios_corruption_check(char *arg)
+static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
 {
-       char *end;
+       printk(KERN_NOTICE
+               "%s detected: BIOS may corrupt low RAM, working it around.\n",
+               d->ident);
 
-       bios_corruption_check = simple_strtol(arg, &end, 10);
+       reserve_early_overlap_ok(0x0, 0x10000, "BIOS quirk");
 
-       return (*end == 0) ? 0 : -EINVAL;
+       return 0;
 }
-early_param("bios_corruption_check", set_bios_corruption_check);
+
+/* List of systems that have known low memory corruption BIOS problems */
+static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
+#ifdef CONFIG_X86_RESERVE_LOW_64K
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "AMI BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+               },
+       },
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "Phoenix BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+               },
+       },
+       {}
 #endif
+};
 
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
@@ -701,6 +784,8 @@ void __init setup_arch(char **cmdline_p)
        printk(KERN_INFO "Command line: %s\n", boot_command_line);
 #endif
 
+       dmi_check_system(bad_bios_dmi_table);
+
        early_cpu_init();
        early_ioremap_init();
 
@@ -986,3 +1071,5 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
 }
+
+