diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt index 73e794f0ff0924e2432e305cb5520345f776160b..debf6813934af05e878863c4a8c53bbf6ae64e62 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/MAINTAINERS b/MAINTAINERS index 2bd34ef58ffa75bb8eb8c642381a344ded56a629..4ccc5fa06d092cf83d8034293050bd3c1973bead 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 2db42b18f53f060a1040ba65cf01114793535ad9..8517c3c3eb3393c8ba539add942342757c117f2b 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 6ff5e3ff6cb57a781a672b631596f924c75f3ee4..3c8cdcfe8d4a9f72c9ffb3762a72b260be85d73c 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -29,6 +29,8 @@ #include #include +#include + #include #include #include @@ -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 042a12982e980c43bb0520e289477df525a50fc2..908915675edcb3f66520c9a3765441d388ef29c0 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "ptrace.h" #include "signal.h" diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 628348c9f6c5f17ded5fa62ec700bdb8666e85a7..9df507d36e0b9b0f0291395da5cecd007b627f0f 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/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index e9b80e9202664bbfa8cd84a6b302b48ae9154560..ccfe6561be240ec65dadbbab2ea56ce0166cd001 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 4bbd85f3ed2a67acd6cc15f45ab3c360dda2e575..2e9469047eb14a0cc22dc4432e7bc0522337c92a 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 diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index d51049522cd0f764bc3f120e64032090f0626024..5f531ea03059d003bab3e86643ed2580a36133cf 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 1018a7486ab76fc717ec2e92096642e54c6b7a05..13ac8a4cd01f6ba7fc070d88a6aa9023ac442f4f 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 aedb0512cb049bac19f8b7616101abf6d9c4302f..a799dd8ef395a94f9a923848ffa6384384eb1efc 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 ca9a602cffd7a2b8ea03c3d7fb0a60c4a1a3acb2..645d440807c229c0e5deba21f3ed3260f0416007 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -8,7 +8,7 @@ #include #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 563792f4f687e6e6dde9f98aaf87d3116b82daff..af227d26e104674e324f99c5f135f3f34e8b4d22 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)