summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/apic.c55
-rw-r--r--arch/i386/kernel/i8253.c10
-rw-r--r--arch/ia64/kernel/crash.c2
-rw-r--r--arch/ia64/kernel/setup.c22
-rw-r--r--arch/ia64/mm/contig.c30
-rw-r--r--arch/ia64/mm/discontig.c4
-rw-r--r--arch/ia64/mm/init.c16
-rw-r--r--arch/ia64/sn/kernel/setup.c6
-rw-r--r--arch/powerpc/kernel/process.c9
-rw-r--r--arch/powerpc/platforms/pseries/hvCall.S41
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c2
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h16
12 files changed, 169 insertions, 44 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 5cff7970911..244c3fe9b8c 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -28,6 +28,7 @@
#include <linux/clockchips.h>
#include <linux/acpi_pmtmr.h>
#include <linux/module.h>
+#include <linux/dmi.h>
#include <asm/atomic.h>
#include <asm/smp.h>
@@ -61,6 +62,8 @@ static int enable_local_apic __initdata = 0;
/* Local APIC timer verification ok */
static int local_apic_timer_verify_ok;
+/* Disable local APIC timer from the kernel commandline or via dmi quirk */
+static int local_apic_timer_disabled;
/*
* Debug level, exported for io_apic.c
@@ -266,6 +269,32 @@ static void __devinit setup_APIC_timer(void)
}
/*
+ * Detect systems with known broken BIOS implementations
+ */
+static int __init lapic_check_broken_bios(struct dmi_system_id *d)
+{
+ printk(KERN_NOTICE "%s detected: disabling lapic timer.\n",
+ d->ident);
+ local_apic_timer_disabled = 1;
+ return 0;
+}
+
+static struct dmi_system_id __initdata broken_bios_dmi_table[] = {
+ {
+ /*
+ * BIOS exports only C1 state, but uses deeper power
+ * modes behind the kernels back.
+ */
+ .callback = lapic_check_broken_bios,
+ .ident = "HP nx6325",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
+ },
+ },
+ {}
+};
+
+/*
* In this functions we calibrate APIC bus clocks to the external timer.
*
* We want to do the calibration only once since we want to have local timer
@@ -340,6 +369,22 @@ void __init setup_boot_APIC_clock(void)
long delta, deltapm;
int pm_referenced = 0;
+ /* Detect know broken systems */
+ dmi_check_system(broken_bios_dmi_table);
+
+ /*
+ * The local apic timer can be disabled via the kernel
+ * commandline or from the dmi quirk above. Register the lapic
+ * timer as a dummy clock event source on SMP systems, so the
+ * broadcast mechanism is used. On UP systems simply ignore it.
+ */
+ if (local_apic_timer_disabled) {
+ /* No broadcast on UP ! */
+ if (num_possible_cpus() > 1)
+ setup_APIC_timer();
+ return;
+ }
+
apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
"calibrating APIC timer ...\n");
@@ -461,7 +506,8 @@ void __init setup_boot_APIC_clock(void)
apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
else
local_apic_timer_verify_ok = 0;
- }
+ } else
+ local_irq_enable();
if (!local_apic_timer_verify_ok) {
printk(KERN_WARNING
@@ -1179,6 +1225,13 @@ static int __init parse_nolapic(char *arg)
}
early_param("nolapic", parse_nolapic);
+static int __init parse_disable_lapic_timer(char *arg)
+{
+ local_apic_timer_disabled = 1;
+ return 0;
+}
+early_param("nolapic_timer", parse_disable_lapic_timer);
+
static int __init apic_set_verbosity(char *str)
{
if (strcmp("debug", str) == 0)
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
index 5cbb776b308..10cef5ca8a5 100644
--- a/arch/i386/kernel/i8253.c
+++ b/arch/i386/kernel/i8253.c
@@ -47,9 +47,17 @@ static void init_pit_timer(enum clock_event_mode mode,
outb(LATCH >> 8 , PIT_CH0); /* MSB */
break;
- case CLOCK_EVT_MODE_ONESHOT:
+ /*
+ * Avoid unnecessary state transitions, as it confuses
+ * Geode / Cyrix based boxen.
+ */
case CLOCK_EVT_MODE_SHUTDOWN:
+ if (evt->mode == CLOCK_EVT_MODE_UNUSED)
+ break;
case CLOCK_EVT_MODE_UNUSED:
+ if (evt->mode == CLOCK_EVT_MODE_SHUTDOWN)
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
/* One shot setup */
outb_p(0x38, PIT_MODE);
udelay(10);
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
index 7d1bbb4403b..80a94e70782 100644
--- a/arch/ia64/kernel/crash.c
+++ b/arch/ia64/kernel/crash.c
@@ -164,7 +164,7 @@ kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
nd = (struct ia64_mca_notify_die *)args->err;
/* Reason code 1 means machine check rendezous*/
- if ((val == DIE_INIT_MONARCH_ENTER || DIE_INIT_SLAVE_ENTER) &&
+ if ((val == DIE_INIT_MONARCH_ENTER || val == DIE_INIT_SLAVE_ENTER) &&
nd->sos->rv_rc == 1)
return NOTIFY_DONE;
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 339e8a54c2f..69b9bb3fd7c 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -692,12 +692,15 @@ struct seq_operations cpuinfo_op = {
.show = show_cpuinfo
};
-static char brandname[128];
+#define MAX_BRANDS 8
+static char brandname[MAX_BRANDS][128];
static char * __cpuinit
get_model_name(__u8 family, __u8 model)
{
+ static int overflow;
char brand[128];
+ int i;
memcpy(brand, "Unknown", 8);
if (ia64_pal_get_brand_info(brand)) {
@@ -709,12 +712,17 @@ get_model_name(__u8 family, __u8 model)
case 2: memcpy(brand, "Madison up to 9M cache", 23); break;
}
}
- if (brandname[0] == '\0')
- return strcpy(brandname, brand);
- else if (strcmp(brandname, brand) == 0)
- return brandname;
- else
- return kstrdup(brand, GFP_KERNEL);
+ for (i = 0; i < MAX_BRANDS; i++)
+ if (strcmp(brandname[i], brand) == 0)
+ return brandname[i];
+ for (i = 0; i < MAX_BRANDS; i++)
+ if (brandname[i][0] == '\0')
+ return strcpy(brandname[i], brand);
+ if (overflow++ == 0)
+ printk(KERN_ERR
+ "%s: Table overflow. Some processor model information will be missing\n",
+ __FUNCTION__);
+ return "Unknown";
}
static void __cpuinit
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index fb0f4698f5d..44ce5ed9444 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -97,26 +97,6 @@ void show_mem(void)
unsigned long bootmap_start;
/**
- * find_max_pfn - adjust the maximum page number callback
- * @start: start of range
- * @end: end of range
- * @arg: address of pointer to global max_pfn variable
- *
- * Passed as a callback function to efi_memmap_walk() to determine the highest
- * available page frame number in the system.
- */
-int
-find_max_pfn (unsigned long start, unsigned long end, void *arg)
-{
- unsigned long *max_pfnp = arg, pfn;
-
- pfn = (PAGE_ALIGN(end - 1) - PAGE_OFFSET) >> PAGE_SHIFT;
- if (pfn > *max_pfnp)
- *max_pfnp = pfn;
- return 0;
-}
-
-/**
* find_bootmap_location - callback to find a memory area for the bootmap
* @start: start of region
* @end: end of region
@@ -177,9 +157,10 @@ find_memory (void)
reserve_memory();
/* first find highest page frame number */
- max_pfn = 0;
- efi_memmap_walk(find_max_pfn, &max_pfn);
-
+ min_low_pfn = ~0UL;
+ max_low_pfn = 0;
+ efi_memmap_walk(find_max_min_low_pfn, NULL);
+ max_pfn = max_low_pfn;
/* how many bytes to cover all the pages */
bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT;
@@ -189,7 +170,8 @@ find_memory (void)
if (bootmap_start == ~0UL)
panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
- bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn);
+ bootmap_size = init_bootmem_node(NODE_DATA(0),
+ (bootmap_start >> PAGE_SHIFT), 0, max_pfn);
/* Free all available memory, then mark bootmem-map as being in use. */
efi_memmap_walk(filter_rsvd_memory, free_bootmem);
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 11a2d8825d8..872da7a2acc 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -88,9 +88,6 @@ static int __init build_node_maps(unsigned long start, unsigned long len,
bdp->node_low_pfn = max(epfn, bdp->node_low_pfn);
}
- min_low_pfn = min(min_low_pfn, bdp->node_boot_start>>PAGE_SHIFT);
- max_low_pfn = max(max_low_pfn, bdp->node_low_pfn);
-
return 0;
}
@@ -438,6 +435,7 @@ void __init find_memory(void)
/* These actually end up getting called by call_pernode_memory() */
efi_memmap_walk(filter_rsvd_memory, build_node_maps);
efi_memmap_walk(filter_rsvd_memory, find_pernode_space);
+ efi_memmap_walk(find_max_min_low_pfn, NULL);
for_each_online_node(node)
if (mem_data[node].bootmem_data.node_low_pfn) {
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index f225dd72968..c8da621aab1 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -648,6 +648,22 @@ count_reserved_pages (u64 start, u64 end, void *arg)
return 0;
}
+int
+find_max_min_low_pfn (unsigned long start, unsigned long end, void *arg)
+{
+ unsigned long pfn_start, pfn_end;
+#ifdef CONFIG_FLATMEM
+ pfn_start = (PAGE_ALIGN(__pa(start))) >> PAGE_SHIFT;
+ pfn_end = (PAGE_ALIGN(__pa(end - 1))) >> PAGE_SHIFT;
+#else
+ pfn_start = GRANULEROUNDDOWN(__pa(start)) >> PAGE_SHIFT;
+ pfn_end = GRANULEROUNDUP(__pa(end - 1)) >> PAGE_SHIFT;
+#endif
+ min_low_pfn = min(min_low_pfn, pfn_start);
+ max_low_pfn = max(max_low_pfn, pfn_end);
+ return 0;
+}
+
/*
* Boot command-line option "nolwsys" can be used to disable the use of any light-weight
* system call handler. When this option is in effect, all fsyscalls will end up bubbling
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index bd5373d593e..a9bed5ca2ed 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -348,8 +348,7 @@ sn_scan_pcdp(void)
continue; /* not PCI interconnect */
if (if_pci.translation & PCDP_PCI_TRANS_IOPORT)
- vga_console_iobase =
- if_pci.ioport_tra | __IA64_UNCACHED_OFFSET;
+ vga_console_iobase = if_pci.ioport_tra;
if (if_pci.translation & PCDP_PCI_TRANS_MMIO)
vga_console_membase =
@@ -429,7 +428,8 @@ void __init sn_setup(char **cmdline_p)
* bus containing the VGA console.
*/
if (vga_console_iobase) {
- io_space[0].mmio_base = vga_console_iobase;
+ io_space[0].mmio_base =
+ (unsigned long) ioremap(vga_console_iobase, 0);
io_space[0].sparse = 0;
}
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index f3d4dd580dd..e53b2988d1b 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -465,8 +465,13 @@ void flush_thread(void)
#ifdef CONFIG_PPC64
struct thread_info *t = current_thread_info();
- if (t->flags & _TIF_ABI_PENDING)
- t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
+ if (test_ti_thread_flag(t, TIF_ABI_PENDING)) {
+ clear_ti_thread_flag(t, TIF_ABI_PENDING);
+ if (test_ti_thread_flag(t, TIF_32BIT))
+ clear_ti_thread_flag(t, TIF_32BIT);
+ else
+ set_ti_thread_flag(t, TIF_32BIT);
+ }
#endif
discard_lazy_cpu_state();
diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S
index 5c7e3878989..c1427b3634e 100644
--- a/arch/powerpc/platforms/pseries/hvCall.S
+++ b/arch/powerpc/platforms/pseries/hvCall.S
@@ -30,9 +30,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_PURR);
/*
* postcall is performed immediately before function return which
- * allows liberal use of volatile registers.
+ * allows liberal use of volatile registers. We branch around this
+ * in early init (eg when populating the MMU hashtable) by using an
+ * unconditional cpu feature.
*/
#define HCALL_INST_POSTCALL \
+BEGIN_FTR_SECTION; \
+ b 1f; \
+END_FTR_SECTION(0, 1); \
ld r4,STK_PARM(r3)(r1); /* validate opcode */ \
cmpldi cr7,r4,MAX_HCALL_OPCODE; \
bgt- cr7,1f; \
@@ -123,6 +128,40 @@ _GLOBAL(plpar_hcall)
blr /* return r3 = status */
+/*
+ * plpar_hcall_raw can be called in real mode. kexec/kdump need some
+ * hypervisor calls to be executed in real mode. So plpar_hcall_raw
+ * does not access the per cpu hypervisor call statistics variables,
+ * since these variables may not be present in the RMO region.
+ */
+_GLOBAL(plpar_hcall_raw)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ std r4,STK_PARM(r4)(r1) /* Save ret buffer */
+
+ mr r4,r5
+ mr r5,r6
+ mr r6,r7
+ mr r7,r8
+ mr r8,r9
+ mr r9,r10
+
+ HVSC /* invoke the hypervisor */
+
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+ std r6, 16(r12)
+ std r7, 24(r12)
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
_GLOBAL(plpar_hcall9)
HMT_MEDIUM
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 7496005566e..843ee964321 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -378,7 +378,7 @@ static void pSeries_lpar_hptab_clear(void)
/* TODO: Use bulk call */
for (i = 0; i < hpte_count; i++)
- plpar_pte_remove(0, i, 0, &dummy1, &dummy2);
+ plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2);
}
/*
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index 3eb7b294d92..2e4d10c9eea 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -78,6 +78,22 @@ static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
return rc;
}
+/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */
+static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex,
+ unsigned long avpn, unsigned long *old_pteh_ret,
+ unsigned long *old_ptel_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
+}
+
static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
{