Commit 97b9c3e1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'fixes' of master.kernel.org:/home/rmk/linux-2.6-arm

* 'fixes' of master.kernel.org:/home/rmk/linux-2.6-arm:
  ARM: 6745/1: kprobes insn decoding fix
  ARM: tlb: move noMMU tlb_flush() to asm/tlb.h
  ARM: tlb: delay page freeing for SMP and ARMv7 CPUs
  ARM: Keep exit text/data around for SMP_ON_UP
  ARM: Ensure predictable endian state on signal handler entry
  ARM: 6740/1: Place correctly notes section in the linker script
  ARM: 6700/1: SPEAr: Correct SOC config base address for spear320
  ARM: 6722/1: SPEAr: sp810: switch to slow mode before reset
  ARM: 6712/1: SPEAr: replace readl(), writel() with relaxed versions in uncompress.h
  ARM: 6720/1: SPEAr: Append UL to VMALLOC_END
  ARM: 6676/1: Correct the cpu_architecture() function for ARMv7
  ARM: 6739/1: update .gitignore for boot/compressed
  ARM: 6743/1: errata: interrupted ICALLUIS may prevent completion of broadcasted operation
  ARM: 6742/1: pmu: avoid setting IRQ affinity on UP systems
  ARM: 6741/1: errata: pl310 cache sync operation may be faulty
parents f85cca6b 5a5af730
...@@ -1177,6 +1177,31 @@ config ARM_ERRATA_743622 ...@@ -1177,6 +1177,31 @@ config ARM_ERRATA_743622
visible impact on the overall performance or power consumption of the visible impact on the overall performance or power consumption of the
processor. processor.
config ARM_ERRATA_751472
bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation"
depends on CPU_V7 && SMP
help
This option enables the workaround for the 751472 Cortex-A9 (prior
to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the
completion of a following broadcasted operation if the second
operation is received by a CPU before the ICIALLUIS has completed,
potentially leading to corrupted entries in the cache or TLB.
config ARM_ERRATA_753970
bool "ARM errata: cache sync operation may be faulty"
depends on CACHE_PL310
help
This option enables the workaround for the 753970 PL310 (r3p0) erratum.
Under some condition the effect of cache sync operation on
the store buffer still remains when the operation completes.
This means that the store buffer is always asked to drain and
this prevents it from merging any further writes. The workaround
is to replace the normal offset of cache sync operation (0x730)
by another offset targeting an unmapped PL310 register 0x740.
This has the same effect as the cache sync operation: store buffer
drain and waiting for all buffers empty.
endmenu endmenu
source "arch/arm/common/Kconfig" source "arch/arm/common/Kconfig"
......
...@@ -15,7 +15,7 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) ...@@ -15,7 +15,7 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
LDFLAGS_vmlinux += --be8 LDFLAGS_vmlinux += --be8
endif endif
OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S OBJCOPYFLAGS :=-O binary -R .comment -S
GZFLAGS :=-9 GZFLAGS :=-9
#KBUILD_CFLAGS +=-pipe #KBUILD_CFLAGS +=-pipe
# Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
......
font.c font.c
piggy.gz lib1funcs.S
piggy.gzip
piggy.lzo
piggy.lzma
vmlinux
vmlinux.lds vmlinux.lds
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define L2X0_RAW_INTR_STAT 0x21C #define L2X0_RAW_INTR_STAT 0x21C
#define L2X0_INTR_CLEAR 0x220 #define L2X0_INTR_CLEAR 0x220
#define L2X0_CACHE_SYNC 0x730 #define L2X0_CACHE_SYNC 0x730
#define L2X0_DUMMY_REG 0x740
#define L2X0_INV_LINE_PA 0x770 #define L2X0_INV_LINE_PA 0x770
#define L2X0_INV_WAY 0x77C #define L2X0_INV_WAY 0x77C
#define L2X0_CLEAN_LINE_PA 0x7B0 #define L2X0_CLEAN_LINE_PA 0x7B0
......
...@@ -58,6 +58,9 @@ ...@@ -58,6 +58,9 @@
static inline void sysctl_soft_reset(void __iomem *base) static inline void sysctl_soft_reset(void __iomem *base)
{ {
/* switch to slow mode */
writel(0x2, base + SCCTRL);
/* writing any value to SCSYSSTAT reg will reset system */ /* writing any value to SCSYSSTAT reg will reset system */
writel(0, base + SCSYSSTAT); writel(0, base + SCSYSSTAT);
} }
......
...@@ -18,16 +18,34 @@ ...@@ -18,16 +18,34 @@
#define __ASMARM_TLB_H #define __ASMARM_TLB_H
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#ifndef CONFIG_MMU #ifndef CONFIG_MMU
#include <linux/pagemap.h> #include <linux/pagemap.h>
#define tlb_flush(tlb) ((void) tlb)
#include <asm-generic/tlb.h> #include <asm-generic/tlb.h>
#else /* !CONFIG_MMU */ #else /* !CONFIG_MMU */
#include <linux/swap.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/tlbflush.h>
/*
* We need to delay page freeing for SMP as other CPUs can access pages
* which have been removed but not yet had their TLB entries invalidated.
* Also, as ARMv7 speculative prefetch can drag new entries into the TLB,
* we need to apply this same delaying tactic to ensure correct operation.
*/
#if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7)
#define tlb_fast_mode(tlb) 0
#define FREE_PTE_NR 500
#else
#define tlb_fast_mode(tlb) 1
#define FREE_PTE_NR 0
#endif
/* /*
* TLB handling. This allows us to remove pages from the page * TLB handling. This allows us to remove pages from the page
...@@ -36,12 +54,58 @@ ...@@ -36,12 +54,58 @@
struct mmu_gather { struct mmu_gather {
struct mm_struct *mm; struct mm_struct *mm;
unsigned int fullmm; unsigned int fullmm;
struct vm_area_struct *vma;
unsigned long range_start; unsigned long range_start;
unsigned long range_end; unsigned long range_end;
unsigned int nr;
struct page *pages[FREE_PTE_NR];
}; };
DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
/*
* This is unnecessarily complex. There's three ways the TLB shootdown
* code is used:
* 1. Unmapping a range of vmas. See zap_page_range(), unmap_region().
* tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
* tlb->vma will be non-NULL.
* 2. Unmapping all vmas. See exit_mmap().
* tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
* tlb->vma will be non-NULL. Additionally, page tables will be freed.
* 3. Unmapping argument pages. See shift_arg_pages().
* tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
* tlb->vma will be NULL.
*/
static inline void tlb_flush(struct mmu_gather *tlb)
{
if (tlb->fullmm || !tlb->vma)
flush_tlb_mm(tlb->mm);
else if (tlb->range_end > 0) {
flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
tlb->range_start = TASK_SIZE;
tlb->range_end = 0;
}
}
static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
{
if (!tlb->fullmm) {
if (addr < tlb->range_start)
tlb->range_start = addr;
if (addr + PAGE_SIZE > tlb->range_end)
tlb->range_end = addr + PAGE_SIZE;
}
}
static inline void tlb_flush_mmu(struct mmu_gather *tlb)
{
tlb_flush(tlb);
if (!tlb_fast_mode(tlb)) {
free_pages_and_swap_cache(tlb->pages, tlb->nr);
tlb->nr = 0;
}
}
static inline struct mmu_gather * static inline struct mmu_gather *
tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
{ {
...@@ -49,6 +113,8 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) ...@@ -49,6 +113,8 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
tlb->mm = mm; tlb->mm = mm;
tlb->fullmm = full_mm_flush; tlb->fullmm = full_mm_flush;
tlb->vma = NULL;
tlb->nr = 0;
return tlb; return tlb;
} }
...@@ -56,8 +122,7 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) ...@@ -56,8 +122,7 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
static inline void static inline void
tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
{ {
if (tlb->fullmm) tlb_flush_mmu(tlb);
flush_tlb_mm(tlb->mm);
/* keep the page table cache within bounds */ /* keep the page table cache within bounds */
check_pgt_cache(); check_pgt_cache();
...@@ -71,12 +136,7 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) ...@@ -71,12 +136,7 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
static inline void static inline void
tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr) tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
{ {
if (!tlb->fullmm) { tlb_add_flush(tlb, addr);
if (addr < tlb->range_start)
tlb->range_start = addr;
if (addr + PAGE_SIZE > tlb->range_end)
tlb->range_end = addr + PAGE_SIZE;
}
} }
/* /*
...@@ -89,6 +149,7 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) ...@@ -89,6 +149,7 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
{ {
if (!tlb->fullmm) { if (!tlb->fullmm) {
flush_cache_range(vma, vma->vm_start, vma->vm_end); flush_cache_range(vma, vma->vm_start, vma->vm_end);
tlb->vma = vma;
tlb->range_start = TASK_SIZE; tlb->range_start = TASK_SIZE;
tlb->range_end = 0; tlb->range_end = 0;
} }
...@@ -97,12 +158,30 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) ...@@ -97,12 +158,30 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
static inline void static inline void
tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
{ {
if (!tlb->fullmm && tlb->range_end > 0) if (!tlb->fullmm)
flush_tlb_range(vma, tlb->range_start, tlb->range_end); tlb_flush(tlb);
}
static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
{
if (tlb_fast_mode(tlb)) {
free_page_and_swap_cache(page);
} else {
tlb->pages[tlb->nr++] = page;
if (tlb->nr >= FREE_PTE_NR)
tlb_flush_mmu(tlb);
}
}
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
unsigned long addr)
{
pgtable_page_dtor(pte);
tlb_add_flush(tlb, addr);
tlb_remove_page(tlb, pte);
} }
#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page) #define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
#define pte_free_tlb(tlb, ptep, addr) pte_free((tlb)->mm, ptep)
#define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp) #define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp)
#define tlb_migrate_finish(mm) do { } while (0) #define tlb_migrate_finish(mm) do { } while (0)
......
...@@ -10,12 +10,7 @@ ...@@ -10,12 +10,7 @@
#ifndef _ASMARM_TLBFLUSH_H #ifndef _ASMARM_TLBFLUSH_H
#define _ASMARM_TLBFLUSH_H #define _ASMARM_TLBFLUSH_H
#ifdef CONFIG_MMU
#ifndef CONFIG_MMU
#define tlb_flush(tlb) ((void) tlb)
#else /* CONFIG_MMU */
#include <asm/glue.h> #include <asm/glue.h>
......
...@@ -1437,7 +1437,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) ...@@ -1437,7 +1437,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
return space_cccc_1100_010x(insn, asi); return space_cccc_1100_010x(insn, asi);
} else if ((insn & 0x0e000000) == 0x0c400000) { } else if ((insn & 0x0e000000) == 0x0c000000) {
return space_cccc_110x(insn, asi); return space_cccc_110x(insn, asi);
......
...@@ -97,28 +97,34 @@ set_irq_affinity(int irq, ...@@ -97,28 +97,34 @@ set_irq_affinity(int irq,
irq, cpu); irq, cpu);
return err; return err;
#else #else
return 0; return -EINVAL;
#endif #endif
} }
static int static int
init_cpu_pmu(void) init_cpu_pmu(void)
{ {
int i, err = 0; int i, irqs, err = 0;
struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
if (!pdev) { if (!pdev)
err = -ENODEV; return -ENODEV;
goto out;
} irqs = pdev->num_resources;
/*
* If we have a single PMU interrupt that we can't shift, assume that
* we're running on a uniprocessor machine and continue.
*/
if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
return 0;
for (i = 0; i < pdev->num_resources; ++i) { for (i = 0; i < irqs; ++i) {
err = set_irq_affinity(platform_get_irq(pdev, i), i); err = set_irq_affinity(platform_get_irq(pdev, i), i);
if (err) if (err)
break; break;
} }
out:
return err; return err;
} }
......
...@@ -226,8 +226,8 @@ int cpu_architecture(void) ...@@ -226,8 +226,8 @@ int cpu_architecture(void)
* Register 0 and check for VMSAv7 or PMSAv7 */ * Register 0 and check for VMSAv7 or PMSAv7 */
asm("mrc p15, 0, %0, c0, c1, 4" asm("mrc p15, 0, %0, c0, c1, 4"
: "=r" (mmfr0)); : "=r" (mmfr0));
if ((mmfr0 & 0x0000000f) == 0x00000003 || if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
(mmfr0 & 0x000000f0) == 0x00000030) (mmfr0 & 0x000000f0) >= 0x00000030)
cpu_arch = CPU_ARCH_ARMv7; cpu_arch = CPU_ARCH_ARMv7;
else if ((mmfr0 & 0x0000000f) == 0x00000002 || else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
(mmfr0 & 0x000000f0) == 0x00000020) (mmfr0 & 0x000000f0) == 0x00000020)
......
...@@ -474,7 +474,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, ...@@ -474,7 +474,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
unsigned long handler = (unsigned long)ka->sa.sa_handler; unsigned long handler = (unsigned long)ka->sa.sa_handler;
unsigned long retcode; unsigned long retcode;
int thumb = 0; int thumb = 0;
unsigned long cpsr = regs->ARM_cpsr & ~PSR_f; unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT);
cpsr |= PSR_ENDSTATE;
/* /*
* Maybe we need to deliver a 32-bit signal to a 26-bit task. * Maybe we need to deliver a 32-bit signal to a 26-bit task.
......
...@@ -21,6 +21,12 @@ ...@@ -21,6 +21,12 @@
#define ARM_CPU_KEEP(x) #define ARM_CPU_KEEP(x)
#endif #endif
#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
#define ARM_EXIT_KEEP(x) x
#else
#define ARM_EXIT_KEEP(x)
#endif
OUTPUT_ARCH(arm) OUTPUT_ARCH(arm)
ENTRY(stext) ENTRY(stext)
...@@ -43,6 +49,7 @@ SECTIONS ...@@ -43,6 +49,7 @@ SECTIONS
_sinittext = .; _sinittext = .;
HEAD_TEXT HEAD_TEXT
INIT_TEXT INIT_TEXT
ARM_EXIT_KEEP(EXIT_TEXT)
_einittext = .; _einittext = .;
ARM_CPU_DISCARD(PROC_INFO) ARM_CPU_DISCARD(PROC_INFO)
__arch_info_begin = .; __arch_info_begin = .;
...@@ -67,6 +74,7 @@ SECTIONS ...@@ -67,6 +74,7 @@ SECTIONS
#ifndef CONFIG_XIP_KERNEL #ifndef CONFIG_XIP_KERNEL
__init_begin = _stext; __init_begin = _stext;
INIT_DATA INIT_DATA
ARM_EXIT_KEEP(EXIT_DATA)
#endif #endif
} }
...@@ -162,6 +170,7 @@ SECTIONS ...@@ -162,6 +170,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE); . = ALIGN(PAGE_SIZE);
__init_begin = .; __init_begin = .;
INIT_DATA INIT_DATA
ARM_EXIT_KEEP(EXIT_DATA)
. = ALIGN(PAGE_SIZE); . = ALIGN(PAGE_SIZE);
__init_end = .; __init_end = .;
#endif #endif
...@@ -247,6 +256,8 @@ SECTIONS ...@@ -247,6 +256,8 @@ SECTIONS
} }
#endif #endif
NOTES
BSS_SECTION(0, 0, 0) BSS_SECTION(0, 0, 0)
_end = .; _end = .;
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#define SPEAR320_SMII1_BASE 0xAB000000 #define SPEAR320_SMII1_BASE 0xAB000000
#define SPEAR320_SMII1_SIZE 0x01000000 #define SPEAR320_SMII1_SIZE 0x01000000
#define SPEAR320_SOC_CONFIG_BASE 0xB4000000 #define SPEAR320_SOC_CONFIG_BASE 0xB3000000
#define SPEAR320_SOC_CONFIG_SIZE 0x00000070 #define SPEAR320_SOC_CONFIG_SIZE 0x00000070
/* Interrupt registers offsets and masks */ /* Interrupt registers offsets and masks */
#define INT_STS_MASK_REG 0x04 #define INT_STS_MASK_REG 0x04
......
...@@ -49,7 +49,13 @@ static inline void cache_wait(void __iomem *reg, unsigned long mask) ...@@ -49,7 +49,13 @@ static inline void cache_wait(void __iomem *reg, unsigned long mask)
static inline void cache_sync(void) static inline void cache_sync(void)
{ {
void __iomem *base = l2x0_base; void __iomem *base = l2x0_base;
#ifdef CONFIG_ARM_ERRATA_753970
/* write to an unmmapped register */
writel_relaxed(0, base + L2X0_DUMMY_REG);
#else
writel_relaxed(0, base + L2X0_CACHE_SYNC); writel_relaxed(0, base + L2X0_CACHE_SYNC);
#endif
cache_wait(base + L2X0_CACHE_SYNC, 1); cache_wait(base + L2X0_CACHE_SYNC, 1);
} }
......
...@@ -264,6 +264,12 @@ __v7_setup: ...@@ -264,6 +264,12 @@ __v7_setup:
orreq r10, r10, #1 << 6 @ set bit #6 orreq r10, r10, #1 << 6 @ set bit #6
mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
#endif #endif
#ifdef CONFIG_ARM_ERRATA_751472
cmp r6, #0x30 @ present prior to r3p0
mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register
orrlt r10, r10, #1 << 11 @ set bit #11
mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register
#endif
3: mov r10, #0 3: mov r10, #0
#ifdef HARVARD_CACHE #ifdef HARVARD_CACHE
......
...@@ -24,10 +24,10 @@ static inline void putc(int c) ...@@ -24,10 +24,10 @@ static inline void putc(int c)
{ {
void __iomem *base = (void __iomem *)SPEAR_DBG_UART_BASE; void __iomem *base = (void __iomem *)SPEAR_DBG_UART_BASE;
while (readl(base + UART01x_FR) & UART01x_FR_TXFF) while (readl_relaxed(base + UART01x_FR) & UART01x_FR_TXFF)
barrier(); barrier();
writel(c, base + UART01x_DR); writel_relaxed(c, base + UART01x_DR);
} }
static inline void flush(void) static inline void flush(void)
......
...@@ -14,6 +14,6 @@ ...@@ -14,6 +14,6 @@
#ifndef __PLAT_VMALLOC_H #ifndef __PLAT_VMALLOC_H
#define __PLAT_VMALLOC_H #define __PLAT_VMALLOC_H
#define VMALLOC_END 0xF0000000 #define VMALLOC_END 0xF0000000UL
#endif /* __PLAT_VMALLOC_H */ #endif /* __PLAT_VMALLOC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment