aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/cachetlb.txt5
-rw-r--r--Documentation/x86_64/boot-options.txt4
-rw-r--r--MAINTAINERS22
-rw-r--r--arch/arm/kernel/entry-armv.S12
-rw-r--r--arch/arm/kernel/time.c13
-rw-r--r--arch/arm/kernel/traps.c1
-rw-r--r--arch/arm/mm/flush.c39
-rw-r--r--arch/x86_64/kernel/early-quirks.c5
-rw-r--r--arch/x86_64/kernel/io_apic.c124
-rw-r--r--drivers/mmc/mmci.c4
-rw-r--r--include/asm-arm/arch-iop32x/iop32x.h2
-rw-r--r--include/asm-arm/cacheflush.h10
-rw-r--r--include/asm-arm/hardware/iop3xx.h6
-rw-r--r--include/asm-parisc/cacheflush.h2
-rw-r--r--include/linux/highmem.h2
-rw-r--r--mm/memory.c2
16 files changed, 185 insertions, 68 deletions
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
index 73e794f0ff0..debf6813934 100644
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -373,14 +373,15 @@ maps this page at its virtual address.
likely that you will need to flush the instruction cache
for copy_to_user_page().
- void flush_anon_page(struct page *page, unsigned long vmaddr)
+ void flush_anon_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vmaddr)
When the kernel needs to access the contents of an anonymous
page, it calls this function (currently only
get_user_pages()). Note: flush_dcache_page() deliberately
doesn't work for an anonymous page. The default
implementation is a nop (and should remain so for all coherent
architectures). For incoherent architectures, it should flush
- the cache of the page at vmaddr in the current user process.
+ the cache of the page at vmaddr.
void flush_kernel_dcache_page(struct page *page)
When the kernel needs to modify a user page is has obtained
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index dbdcaf68e3e..5c86ed6f044 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -52,6 +52,10 @@ APICs
apicmaintimer. Useful when your PIT timer is totally
broken.
+ disable_8254_timer / enable_8254_timer
+ Enable interrupt 0 timer routing over the 8254 in addition to over
+ the IO-APIC. The kernel tries to set a sensible default.
+
Early Console
syntax: earlyprintk=vga
diff --git a/MAINTAINERS b/MAINTAINERS
index 2bd34ef58ff..4ccc5fa06d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -412,20 +412,32 @@ S: Maintained
ARM/INTEL IOP32X ARM ARCHITECTURE
P: Lennert Buytenhek
M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-S: Maintained
+S: Supported
+
+ARM/INTEL IOP33X ARM ARCHITECTURE
+P: Dan Williams
+M: dan.j.williams@intel.com
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Supported
ARM/INTEL IOP13XX ARM ARCHITECTURE
P: Lennert Buytenhek
M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-S: Maintained
+S: Supported
ARM/INTEL IQ81342EX MACHINE SUPPORT
P: Lennert Buytenhek
M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-S: Maintained
+S: Supported
ARM/INTEL IXP2000 ARM ARCHITECTURE
P: Lennert Buytenhek
@@ -448,8 +460,10 @@ S: Maintained
ARM/INTEL XSC3 (MANZANO) ARM CORE
P: Lennert Buytenhek
M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-S: Maintained
+S: Supported
ARM/IP FABRICS DOUBLE ESPRESSO MACHINE SUPPORT
P: Lennert Buytenhek
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");
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index e9b80e92026..ccfe6561be2 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -42,6 +42,8 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
{
writel(0, host->base + MMCICOMMAND);
+ BUG_ON(host->data);
+
host->mrq = NULL;
host->cmd = NULL;
@@ -198,6 +200,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
}
if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+ if (host->data)
+ mmci_stop_data(host);
mmci_request_end(host, cmd->mrq);
} else if (!(cmd->data->flags & MMC_DATA_READ)) {
mmci_start_data(host, cmd->data);
diff --git a/include/asm-arm/arch-iop32x/iop32x.h b/include/asm-arm/arch-iop32x/iop32x.h
index 4bbd85f3ed2..2e9469047eb 100644
--- a/include/asm-arm/arch-iop32x/iop32x.h
+++ b/include/asm-arm/arch-iop32x/iop32x.h
@@ -19,7 +19,7 @@
* Peripherals that are shared between the iop32x and iop33x but
* located at different addresses.
*/
-#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07c0 + (reg))
+#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07c4 + (reg))
#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg))
#include <asm/hardware/iop3xx.h>
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
index d51049522cd..5f531ea0305 100644
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -357,6 +357,16 @@ extern void flush_dcache_page(struct page *);
extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
+#define ARCH_HAS_FLUSH_ANON_PAGE
+static inline void flush_anon_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vmaddr)
+{
+ extern void __flush_anon_page(struct vm_area_struct *vma,
+ struct page *, unsigned long);
+ if (PageAnon(page))
+ __flush_anon_page(vma, page, vmaddr);
+}
+
#define flush_dcache_mmap_lock(mapping) \
write_lock_irq(&(mapping)->tree_lock)
#define flush_dcache_mmap_unlock(mapping) \
diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h
index 1018a7486ab..13ac8a4cd01 100644
--- a/include/asm-arm/hardware/iop3xx.h
+++ b/include/asm-arm/hardware/iop3xx.h
@@ -168,9 +168,9 @@ extern void gpio_line_set(int line, int value);
#define IOP3XX_PERCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0710)
/* General Purpose I/O */
-#define IOP3XX_GPOE (volatile u32 *)IOP3XX_GPIO_REG(0x0004)
-#define IOP3XX_GPID (volatile u32 *)IOP3XX_GPIO_REG(0x0008)
-#define IOP3XX_GPOD (volatile u32 *)IOP3XX_GPIO_REG(0x000c)
+#define IOP3XX_GPOE (volatile u32 *)IOP3XX_GPIO_REG(0x0000)
+#define IOP3XX_GPID (volatile u32 *)IOP3XX_GPIO_REG(0x0004)
+#define IOP3XX_GPOD (volatile u32 *)IOP3XX_GPIO_REG(0x0008)
/* Timers */
#define IOP3XX_TU_TMR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0000)
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
index aedb0512cb0..a799dd8ef39 100644
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -186,7 +186,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
}
static inline void
-flush_anon_page(struct page *page, unsigned long vmaddr)
+flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
{
if (PageAnon(page))
flush_user_dcache_page(vmaddr);
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index ca9a602cffd..645d440807c 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -8,7 +8,7 @@
#include <asm/cacheflush.h>
#ifndef ARCH_HAS_FLUSH_ANON_PAGE
-static inline void flush_anon_page(struct page *page, unsigned long vmaddr)
+static inline void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
{
}
#endif
diff --git a/mm/memory.c b/mm/memory.c
index 563792f4f68..af227d26e10 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1091,7 +1091,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
if (pages) {
pages[i] = page;
- flush_anon_page(page, start);
+ flush_anon_page(vma, page, start);
flush_dcache_page(page);
}
if (vmas)