diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 12 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 13 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 1 | ||||
-rw-r--r-- | arch/arm/mm/flush.c | 39 | ||||
-rw-r--r-- | arch/x86_64/kernel/early-quirks.c | 5 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 124 |
6 files changed, 139 insertions, 55 deletions
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 2db42b18f53..8517c3c3eb3 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -436,7 +436,7 @@ __und_usr: usr_entry tst r3, #PSR_T_BIT @ Thumb mode? - bne fpundefinstr @ ignore FP + bne __und_usr_unknown @ ignore FP sub r4, r2, #4 @ @@ -448,7 +448,7 @@ __und_usr: @ 1: ldrt r0, [r4] adr r9, ret_from_exception - adr lr, fpundefinstr + adr lr, __und_usr_unknown @ @ fallthrough to call_fpe @ @@ -476,7 +476,9 @@ __und_usr: * Emulators may wish to make use of the following registers: * r0 = instruction opcode. * r2 = PC+4 + * r9 = normal "successful" return address * r10 = this threads thread_info structure. + * lr = unrecognised instruction return address */ call_fpe: tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 @@ -545,10 +547,12 @@ do_fpe: .data ENTRY(fp_enter) - .word fpundefinstr + .word no_fp .text -fpundefinstr: +no_fp: mov pc, lr + +__und_usr_unknown: mov r0, sp adr lr, ret_from_exception b do_undefinstr diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 6ff5e3ff6cb..3c8cdcfe8d4 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -29,6 +29,8 @@ #include <linux/timer.h> #include <linux/irq.h> +#include <linux/mc146818rtc.h> + #include <asm/leds.h> #include <asm/thread_info.h> #include <asm/mach/time.h> @@ -85,6 +87,17 @@ unsigned long long __attribute__((weak)) sched_clock(void) return (unsigned long long)jiffies * (1000000000 / HZ); } +/* + * An implementation of printk_clock() independent from + * sched_clock(). This avoids non-bootable kernels when + * printk_clock is enabled. + */ +unsigned long long printk_clock(void) +{ + return (unsigned long long)(jiffies - INITIAL_JIFFIES) * + (1000000000 / HZ); +} + static unsigned long next_rtc_update; /* diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 042a12982e9..908915675ed 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -27,6 +27,7 @@ #include <asm/uaccess.h> #include <asm/unistd.h> #include <asm/traps.h> +#include <asm/io.h> #include "ptrace.h" #include "signal.h" diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 628348c9f6c..9df507d36e0 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -202,3 +202,42 @@ void flush_dcache_page(struct page *page) } } EXPORT_SYMBOL(flush_dcache_page); + +/* + * Flush an anonymous page so that users of get_user_pages() + * can safely access the data. The expected sequence is: + * + * get_user_pages() + * -> flush_anon_page + * memcpy() to/from page + * if written to page, flush_dcache_page() + */ +void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) +{ + unsigned long pfn; + + /* VIPT non-aliasing caches need do nothing */ + if (cache_is_vipt_nonaliasing()) + return; + + /* + * Write back and invalidate userspace mapping. + */ + pfn = page_to_pfn(page); + if (cache_is_vivt()) { + flush_cache_page(vma, vmaddr, pfn); + } else { + /* + * For aliasing VIPT, we can flush an alias of the + * userspace address only. + */ + flush_pfn_alias(pfn, vmaddr); + } + + /* + * Invalidate kernel mapping. No data should be contained + * in this mapping of the page. FIXME: this is overkill + * since we actually ask for a write-back and invalidate. + */ + __cpuc_flush_dcache_page(page_address(page)); +} diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c index 829698f6d04..49802f1bee9 100644 --- a/arch/x86_64/kernel/early-quirks.c +++ b/arch/x86_64/kernel/early-quirks.c @@ -69,6 +69,11 @@ static void nvidia_bugs(void) static void ati_bugs(void) { + if (timer_over_8254 == 1) { + timer_over_8254 = 0; + printk(KERN_INFO + "ATI board detected. Disabling timer routing over 8254.\n"); + } } static void intel_bugs(void) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 2a1dcd5f69c..d7bad90a5ad 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -55,6 +55,10 @@ int sis_apic_bug; /* not actually supported, dummy for compile */ static int no_timer_check; +static int disable_timer_pin_1 __initdata; + +int timer_over_8254 __initdata = 1; + /* Where if anywhere is the i8259 connect in external int mode */ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; @@ -350,6 +354,29 @@ static int __init disable_ioapic_setup(char *str) } early_param("noapic", disable_ioapic_setup); +/* Actually the next is obsolete, but keep it for paranoid reasons -AK */ +static int __init disable_timer_pin_setup(char *arg) +{ + disable_timer_pin_1 = 1; + return 1; +} +__setup("disable_timer_pin_1", disable_timer_pin_setup); + +static int __init setup_disable_8254_timer(char *s) +{ + timer_over_8254 = -1; + return 1; +} +static int __init setup_enable_8254_timer(char *s) +{ + timer_over_8254 = 2; + return 1; +} + +__setup("disable_8254_timer", setup_disable_8254_timer); +__setup("enable_8254_timer", setup_enable_8254_timer); + + /* * Find the IRQ entry number of a certain pin. */ @@ -1568,33 +1595,10 @@ static inline void unlock_ExtINT_logic(void) * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast * fanatically on his truly buggy board. + * + * FIXME: really need to revamp this for modern platforms only. */ - -static int try_apic_pin(int apic, int pin, char *msg) -{ - apic_printk(APIC_VERBOSE, KERN_INFO - "..TIMER: trying IO-APIC=%d PIN=%d %s", - apic, pin, msg); - - /* - * Ok, does IRQ0 through the IOAPIC work? - */ - if (!no_timer_check && timer_irq_works()) { - nmi_watchdog_default(); - if (nmi_watchdog == NMI_IO_APIC) { - disable_8259A_irq(0); - setup_nmi(); - enable_8259A_irq(0); - } - return 1; - } - clear_IO_APIC_pin(apic, pin); - apic_printk(APIC_QUIET, KERN_ERR " .. failed\n"); - return 0; -} - -/* The function from hell */ -static void check_timer(void) +static inline void check_timer(void) { int apic1, pin1, apic2, pin2; int vector; @@ -1615,43 +1619,61 @@ static void check_timer(void) */ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); init_8259A(1); + if (timer_over_8254 > 0) + enable_8259A_irq(0); pin1 = find_isa_irq_pin(0, mp_INT); apic1 = find_isa_irq_apic(0, mp_INT); pin2 = ioapic_i8259.pin; apic2 = ioapic_i8259.apic; - /* Do this first, otherwise we get double interrupts on ATI boards */ - if ((pin1 != -1) && try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled")) - return; + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", + vector, apic1, pin1, apic2, pin2); - /* Now try again with IRQ0 8259A enabled. - Assumes timer is on IO-APIC 0 ?!? */ - enable_8259A_irq(0); - unmask_IO_APIC_irq(0); - if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled")) - return; - disable_8259A_irq(0); - - /* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides - on Nvidia boards */ - if (!(apic1 == 0 && pin1 == 0) && - try_apic_pin(0, 0, "fallback with 8259 IRQ0 disabled")) - return; - if (!(apic1 == 0 && pin1 == 2) && - try_apic_pin(0, 2, "fallback with 8259 IRQ0 disabled")) - return; + if (pin1 != -1) { + /* + * Ok, does IRQ0 through the IOAPIC work? + */ + unmask_IO_APIC_irq(0); + if (!no_timer_check && timer_irq_works()) { + nmi_watchdog_default(); + if (nmi_watchdog == NMI_IO_APIC) { + disable_8259A_irq(0); + setup_nmi(); + enable_8259A_irq(0); + } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); + return; + } + clear_IO_APIC_pin(apic1, pin1); + apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not " + "connected to IO-APIC\n"); + } - /* Then try pure 8259A routing on the 8259 as reported by BIOS*/ - enable_8259A_irq(0); + apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) " + "through the 8259A ... "); if (pin2 != -1) { + apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...", + apic2, pin2); + /* + * legacy devices should be connected to IO APIC #0 + */ setup_ExtINT_IRQ0_pin(apic2, pin2, vector); - if (try_apic_pin(apic2,pin2,"8259A broadcast ExtINT from BIOS")) + if (timer_irq_works()) { + apic_printk(APIC_VERBOSE," works.\n"); + nmi_watchdog_default(); + if (nmi_watchdog == NMI_IO_APIC) { + setup_nmi(); + } return; + } + /* + * Cleanup, just in case ... + */ + clear_IO_APIC_pin(apic2, pin2); } - - /* Tried all possibilities to go through the IO-APIC. Now come the - really cheesy fallbacks. */ + apic_printk(APIC_VERBOSE," failed.\n"); if (nmi_watchdog == NMI_IO_APIC) { printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); |