Commit a32737e1 authored by Russell King's avatar Russell King

Merge branches 'fixes' and 'misc' into for-linus

parents 27edacac a3c2b511
......@@ -258,6 +258,7 @@ config ARCH_INTEGRATOR
select ARCH_HAS_CPUFREQ
select CLKDEV_LOOKUP
select HAVE_MACH_CLKDEV
select HAVE_TCM
select ICST
select GENERIC_CLOCKEVENTS
select PLAT_VERSATILE
......@@ -1126,6 +1127,11 @@ config ARM_TIMER_SP804
source arch/arm/mm/Kconfig
config ARM_NR_BANKS
int
default 16 if ARCH_EP93XX
default 8
config IWMMXT
bool "Enable iWMMXt support"
depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4
......@@ -1560,6 +1566,16 @@ config LOCAL_TIMERS
accounting to be spread across the timer interval, preventing a
"thundering herd" at every timer tick.
config ARCH_NR_GPIO
int
default 1024 if ARCH_SHMOBILE || ARCH_TEGRA
default 350 if ARCH_U8500
default 0
help
Maximum number of GPIOs in the system.
If unsure, leave the default value.
source kernel/Kconfig.preempt
config HZ
......
......@@ -143,7 +143,6 @@ static int sp804_set_next_event(unsigned long next,
}
static struct clock_event_device sp804_clockevent = {
.shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = sp804_set_mode,
.set_next_event = sp804_set_next_event,
......@@ -169,13 +168,9 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
clkevt_base = base;
clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
evt->name = name;
evt->irq = irq;
evt->mult = div_sc(rate, NSEC_PER_SEC, evt->shift);
evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt);
evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
setup_irq(irq, &sp804_timer_irq);
clockevents_register_device(evt);
clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
}
/*
* Copyright 2011 Calxeda, Inc.
* Based on PPC version Copyright 2007 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ASM_EDAC_H
#define ASM_EDAC_H
/*
* ECC atomic, DMA, SMP and interrupt safe scrub function.
* Implements the per arch atomic_scrub() that EDAC use for software
* ECC scrubbing. It reads memory and then writes back the original
* value, allowing the hardware to detect and correct memory errors.
*/
static inline void atomic_scrub(void *va, u32 size)
{
#if __LINUX_ARM_ARCH__ >= 6
unsigned int *virt_addr = va;
unsigned int temp, temp2;
unsigned int i;
for (i = 0; i < size / sizeof(*virt_addr); i++, virt_addr++) {
/* Very carefully read and write to memory atomically
* so we are interrupt, DMA and SMP safe.
*/
__asm__ __volatile__("\n"
"1: ldrex %0, [%2]\n"
" strex %1, %0, [%2]\n"
" teq %1, #0\n"
" bne 1b\n"
: "=&r"(temp), "=&r"(temp2)
: "r"(virt_addr)
: "cc");
}
#endif
}
#endif
#ifndef _ARCH_ARM_GPIO_H
#define _ARCH_ARM_GPIO_H
#if CONFIG_ARCH_NR_GPIO > 0
#define ARCH_NR_GPIO CONFIG_ARCH_NR_GPIO
#endif
/* not all ARM platforms necessarily support this API ... */
#include <mach/gpio.h>
......
......@@ -27,23 +27,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu);
#define arch_irq_stat_cpu smp_irq_stat_cpu
#if NR_IRQS > 512
#define HARDIRQ_BITS 10
#elif NR_IRQS > 256
#define HARDIRQ_BITS 9
#else
#define HARDIRQ_BITS 8
#endif
/*
* The hardirq mask has to be large enough to have space
* for potentially all IRQ sources in the system nesting
* on a single CPU:
*/
#if (1 << HARDIRQ_BITS) < NR_IRQS
# error HARDIRQ_BITS is too low!
#endif
#define __ARCH_IRQ_EXIT_IRQS_DISABLED 1
#endif /* __ASM_HARDIRQ_H */
/*
* arch/arm/include/asm/opcodes.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARM_OPCODES_H
#define __ASM_ARM_OPCODES_H
#ifndef __ASSEMBLY__
extern asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr);
#endif
#define ARM_OPCODE_CONDTEST_FAIL 0
#define ARM_OPCODE_CONDTEST_PASS 1
#define ARM_OPCODE_CONDTEST_UNCOND 2
#endif /* __ASM_ARM_OPCODES_H */
......@@ -336,6 +336,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
* We provide our own arch_get_unmapped_area to cope with VIPT caches.
*/
#define HAVE_ARCH_UNMAPPED_AREA
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
/*
* remap a physical page `pfn' of size `size' with page protection `prot'
......
......@@ -123,6 +123,8 @@ static inline void prefetch(const void *ptr)
#endif
#define HAVE_ARCH_PICK_MMAP_LAYOUT
#endif
#endif /* __ASM_ARM_PROCESSOR_H */
......@@ -192,11 +192,7 @@ static const struct tagtable __tagtable_##fn __tag = { tag, fn }
/*
* Memory map description
*/
#ifdef CONFIG_ARCH_EP93XX
# define NR_BANKS 16
#else
# define NR_BANKS 8
#endif
#define NR_BANKS CONFIG_ARM_NR_BANKS
struct membank {
phys_addr_t start;
......
......@@ -24,12 +24,13 @@
#if defined(__KERNEL__) && __LINUX_ARM_ARCH__ >= 6
static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
static inline __attribute_const__ __u32 __arch_swahb32(__u32 x)
{
__asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
return x;
}
#define __arch_swab16 __arch_swab16
#define __arch_swahb32 __arch_swahb32
#define __arch_swab16(x) ((__u16)__arch_swahb32(x))
static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
{
......
......@@ -13,7 +13,7 @@ CFLAGS_REMOVE_return_address.o = -pg
# Object file lists.
obj-y := elf.o entry-armv.o entry-common.o irq.o \
obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \
process.o ptrace.o return_address.o setup.o signal.o \
sys_arm.o stacktrace.o time.o traps.o
......
......@@ -202,6 +202,8 @@
#include <linux/slab.h>
#include <linux/kprobes.h>
#include <asm/opcodes.h>
#include "kprobes.h"
#include "kprobes-test.h"
......@@ -1050,65 +1052,9 @@ static int test_instance;
static unsigned long test_check_cc(int cc, unsigned long cpsr)
{
unsigned long temp;
switch (cc) {
case 0x0: /* eq */
return cpsr & PSR_Z_BIT;
case 0x1: /* ne */
return (~cpsr) & PSR_Z_BIT;
case 0x2: /* cs */
return cpsr & PSR_C_BIT;
case 0x3: /* cc */
return (~cpsr) & PSR_C_BIT;
case 0x4: /* mi */
return cpsr & PSR_N_BIT;
case 0x5: /* pl */
return (~cpsr) & PSR_N_BIT;
case 0x6: /* vs */
return cpsr & PSR_V_BIT;
case 0x7: /* vc */
return (~cpsr) & PSR_V_BIT;
int ret = arm_check_condition(cc << 28, cpsr);
case 0x8: /* hi */
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
return cpsr & PSR_C_BIT;
case 0x9: /* ls */
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
return (~cpsr) & PSR_C_BIT;
case 0xa: /* ge */
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
return (~cpsr) & PSR_N_BIT;
case 0xb: /* lt */
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
return cpsr & PSR_N_BIT;
case 0xc: /* gt */
temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
return (~temp) & PSR_N_BIT;
case 0xd: /* le */
temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
return temp & PSR_N_BIT;
case 0xe: /* al */
case 0xf: /* unconditional */
return true;
}
BUG();
return false;
return (ret != ARM_OPCODE_CONDTEST_FAIL);
}
static int is_last_scenario;
......@@ -1128,7 +1074,9 @@ static unsigned long test_context_cpsr(int scenario)
if (!test_case_is_thumb) {
/* Testing ARM code */
probe_should_run = test_check_cc(current_instruction >> 28, cpsr) != 0;
int cc = current_instruction >> 28;
probe_should_run = test_check_cc(cc, cpsr) != 0;
if (scenario == 15)
is_last_scenario = true;
......
/*
* linux/arch/arm/kernel/opcodes.c
*
* A32 condition code lookup feature moved from nwfpe/fpopcode.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <asm/opcodes.h>
#define ARM_OPCODE_CONDITION_UNCOND 0xf
/*
* condition code lookup table
* index into the table is test code: EQ, NE, ... LT, GT, AL, NV
*
* bit position in short is condition code: NZCV
*/
static const unsigned short cc_map[16] = {
0xF0F0, /* EQ == Z set */
0x0F0F, /* NE */
0xCCCC, /* CS == C set */
0x3333, /* CC */
0xFF00, /* MI == N set */
0x00FF, /* PL */
0xAAAA, /* VS == V set */
0x5555, /* VC */
0x0C0C, /* HI == C set && Z clear */
0xF3F3, /* LS == C clear || Z set */
0xAA55, /* GE == (N==V) */
0x55AA, /* LT == (N!=V) */
0x0A05, /* GT == (!Z && (N==V)) */
0xF5FA, /* LE == (Z || (N!=V)) */
0xFFFF, /* AL always */
0 /* NV */
};
/*
* Returns:
* ARM_OPCODE_CONDTEST_FAIL - if condition fails
* ARM_OPCODE_CONDTEST_PASS - if condition passes (including AL)
* ARM_OPCODE_CONDTEST_UNCOND - if NV condition, or separate unconditional
* opcode space from v5 onwards
*
* Code that tests whether a conditional instruction would pass its condition
* check should check that return value == ARM_OPCODE_CONDTEST_PASS.
*
* Code that tests if a condition means that the instruction would be executed
* (regardless of conditional or unconditional) should instead check that the
* return value != ARM_OPCODE_CONDTEST_FAIL.
*/
asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr)
{
u32 cc_bits = opcode >> 28;
u32 psr_cond = psr >> 28;
unsigned int ret;
if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) {
if ((cc_map[cc_bits] >> (psr_cond)) & 1)
ret = ARM_OPCODE_CONDTEST_PASS;
else
ret = ARM_OPCODE_CONDTEST_FAIL;
} else {
ret = ARM_OPCODE_CONDTEST_UNCOND;
}
return ret;
}
EXPORT_SYMBOL_GPL(arm_check_condition);
......@@ -10,8 +10,11 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
#include <linux/clockchips.h>
......@@ -25,6 +28,7 @@
/* set up by the platform code */
void __iomem *twd_base;
static struct clk *twd_clk;
static unsigned long twd_timer_rate;
static struct clock_event_device __percpu **twd_evt;
......@@ -89,6 +93,52 @@ void twd_timer_stop(struct clock_event_device *clk)
disable_percpu_irq(clk->irq);
}
#ifdef CONFIG_CPU_FREQ
/*
* Updates clockevent frequency when the cpu frequency changes.
* Called on the cpu that is changing frequency with interrupts disabled.
*/
static void twd_update_frequency(void *data)
{
twd_timer_rate = clk_get_rate(twd_clk);
clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
}
static int twd_cpufreq_transition(struct notifier_block *nb,
unsigned long state, void *data)
{
struct cpufreq_freqs *freqs = data;
/*
* The twd clock events must be reprogrammed to account for the new
* frequency. The timer is local to a cpu, so cross-call to the
* changing cpu.
*/
if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
smp_call_function_single(freqs->cpu, twd_update_frequency,
NULL, 1);
return NOTIFY_OK;
}
static struct notifier_block twd_cpufreq_nb = {
.notifier_call = twd_cpufreq_transition,
};
static int twd_cpufreq_init(void)
{
if (!IS_ERR(twd_clk))
return cpufreq_register_notifier(&twd_cpufreq_nb,
CPUFREQ_TRANSITION_NOTIFIER);
return 0;
}
core_initcall(twd_cpufreq_init);
#endif
static void __cpuinit twd_calibrate_rate(void)
{
unsigned long count;
......@@ -140,6 +190,35 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
return IRQ_NONE;
}
static struct clk *twd_get_clock(void)
{
struct clk *clk;
int err;
clk = clk_get_sys("smp_twd", NULL);
if (IS_ERR(clk)) {
pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
return clk;
}
err = clk_prepare(clk);
if (err) {
pr_err("smp_twd: clock failed to prepare: %d\n", err);
clk_put(clk);
return ERR_PTR(err);
}
err = clk_enable(clk);
if (err) {
pr_err("smp_twd: clock failed to enable: %d\n", err);
clk_unprepare(clk);
clk_put(clk);
return ERR_PTR(err);
}
return clk;
}
/*
* Setup the local clock events for a CPU.
*/
......@@ -165,7 +244,13 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
}
}
twd_calibrate_rate();
if (!twd_clk)
twd_clk = twd_get_clock();
if (!IS_ERR_OR_NULL(twd_clk))
twd_timer_rate = clk_get_rate(twd_clk);
else
twd_calibrate_rate();
clk->name = "local_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
......@@ -173,15 +258,11 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
clk->rating = 350;
clk->set_mode = twd_set_mode;
clk->set_next_event = twd_set_next_event;
clk->shift = 20;
clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
this_cpu_clk = __this_cpu_ptr(twd_evt);
*this_cpu_clk = clk;
clockevents_register_device(clk);
clockevents_config_and_register(clk, twd_timer_rate,
0xf, 0xffffffff);
enable_percpu_irq(clk->irq, 0);
}
......@@ -25,6 +25,7 @@
#include <linux/syscalls.h>
#include <linux/perf_event.h>
#include <asm/opcodes.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
......@@ -185,6 +186,21 @@ static int swp_handler(struct pt_regs *regs, unsigned int instr)
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc);
res = arm_check_condition(instr, regs->ARM_cpsr);
switch (res) {
case ARM_OPCODE_CONDTEST_PASS:
break;
case ARM_OPCODE_CONDTEST_FAIL:
/* Condition failed - return to next instruction */
regs->ARM_pc += 4;
return 0;
case ARM_OPCODE_CONDTEST_UNCOND:
/* If unconditional encoding - not a SWP, undef */
return -EFAULT;
default:
return -EINVAL;
}
if (current->pid != previous_pid) {
pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n",
current->comm, (unsigned long)current->pid);
......
......@@ -180,9 +180,9 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks,
*/
void __init tcm_init(void)
{
u32 tcm_status = read_cpuid_tcmstatus();
u8 dtcm_banks = (tcm_status >> 16) & 0x03;
u8 itcm_banks = (tcm_status & 0x03);
u32 tcm_status;
u8 dtcm_banks;
u8 itcm_banks;
size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data;
size_t itcm_code_sz = &__eitcm_text - &__sitcm_text;
char *start;
......@@ -191,6 +191,22 @@ void __init tcm_init(void)
int ret;
int i;
/*
* Prior to ARMv5 there is no TCM, and trying to read the status
* register will hang the processor.
*/
if (cpu_architecture() < CPU_ARCH_ARMv5) {
if (dtcm_code_sz || itcm_code_sz)
pr_info("CPU TCM: %u bytes of DTCM and %u bytes of "
"ITCM code compiled in, but no TCM present "
"in pre-v5 CPU\n", dtcm_code_sz, itcm_code_sz);
return;
}
tcm_status = read_cpuid_tcmstatus();
dtcm_banks = (tcm_status >> 16) & 0x03;
itcm_banks = (tcm_status & 0x03);
/* Values greater than 2 for D/ITCM banks are "reserved" */
if (dtcm_banks > 2)
dtcm_banks = 0;
......
......@@ -6,6 +6,8 @@ config ARCH_INTEGRATOR_AP
bool "Support Integrator/AP and Integrator/PP2 platforms"
select CLKSRC_MMIO
select MIGHT_HAVE_PCI
select SERIAL_AMBA_PL010
select SERIAL_AMBA_PL010_CONSOLE
help
Include support for the ARM(R) Integrator/AP and
Integrator/PP2 platforms.
......@@ -15,6 +17,8 @@ config ARCH_INTEGRATOR_CP
select ARCH_CINTEGRATOR
select ARM_TIMER_SP804
select PLAT_VERSATILE_CLCD
select SERIAL_AMBA_PL011
select SERIAL_AMBA_PL011_CONSOLE
help
Include support for the ARM(R) Integrator CP platform.
......
......@@ -29,6 +29,7 @@
#include <mach/cm.h>
#include <asm/system.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/mach/time.h>
#include <asm/pgtable.h>
......@@ -44,7 +45,6 @@ static struct amba_device rtc_device = {
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_RTCINT, NO_IRQ },
.periphid = 0x00041030,
};
static struct amba_device uart0_device = {
......@@ -58,7 +58,6 @@ static struct amba_device uart0_device = {
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_UARTINT0, NO_IRQ },
.periphid = 0x0041010,
};
static struct amba_device uart1_device = {
......@@ -72,7 +71,6 @@ static struct amba_device uart1_device = {
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_UARTINT1, NO_IRQ },
.periphid = 0x0041010,
};
static struct amba_device kmi0_device = {
......@@ -85,7 +83,6 @@ static struct amba_device kmi0_device = {
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_KMIINT0, NO_IRQ },
.periphid = 0x00041050,
};
static struct amba_device kmi1_device = {
......@@ -98,7 +95,6 @@ static struct amba_device kmi1_device = {
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_KMIINT1, NO_IRQ },
.periphid = 0x00041050,
};
static struct amba_device *amba_devs[] __initdata = {
......@@ -157,6 +153,19 @@ static int __init integrator_init(void)
{
int i;
/*
* The Integrator/AP lacks necessary AMBA PrimeCell IDs, so we need to
* hard-code them. The Integator/CP and forward have proper cell IDs.
* Else we leave them undefined to the bus driver can autoprobe them.
*/
if (machine_is_integrator()) {
rtc_device.periphid = 0x00041030;
uart0_device.periphid = 0x00041010;
uart1_device.periphid = 0x00041010;
kmi0_device.periphid = 0x00041050;
kmi1_device.periphid = 0x00041050;
}
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
......
......@@ -107,7 +107,7 @@ static void __init sheevaplug_init(void)
kirkwood_init();
/* setup gpio pin select */
if (machine_is_sheeva_esata())
if (machine_is_esata_sheevaplug())
kirkwood_mpp_conf(sheeva_esata_mpp_config);
else
kirkwood_mpp_conf(sheevaplug_mpp_config);
......@@ -123,11 +123,11 @@ static void __init sheevaplug_init(void)
kirkwood_ge00_init(&sheevaplug_ge00_data);
/* honor lower power consumption for plugs with out eSATA */
if (machine_is_sheeva_esata())
if (machine_is_esata_sheevaplug())
kirkwood_sata_init(&sheeva_esata_sata_data);
/* enable sd wp and sd cd on plugs with esata */
if (machine_is_sheeva_esata())
if (machine_is_esata_sheevaplug())
kirkwood_sdio_init(&sheeva_esata_mvsdio_data);
else
kirkwood_sdio_init(&sheevaplug_mvsdio_data);
......
......@@ -178,7 +178,7 @@ static struct hw_pci qnap_ts209_pci __initdata = {
static int __init qnap_ts209_pci_init(void)
{
if (machine_is_ts_x09())
if (machine_is_ts209())
pci_common_init(&qnap_ts209_pci);
return 0;
......
......@@ -12,8 +12,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#define ARCH_NR_GPIOS 1024
#include <linux/sh_pfc.h>
#ifdef CONFIG_GPIOLIB
......
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H
/*
* 288 (#267 is the highest one actually hooked up) onchip GPIOs, plus enough
* room for a couple of GPIO expanders.
*/
#define ARCH_NR_GPIOS 350
#endif /* __ASM_ARCH_GPIO_H */
......@@ -231,7 +231,7 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
static int __kprobes
__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
struct task_struct *tsk)
unsigned int flags, struct task_struct *tsk)
{
struct vm_area_struct *vma;
int fault;
......@@ -253,18 +253,7 @@ __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
goto out;
}
/*
* If for any reason at all we couldn't handle the fault, make
* sure we exit gracefully rather than endlessly redo the fault.
*/
fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, (fsr & FSR_WRITE) ? FAULT_FLAG_WRITE : 0);
if (unlikely(fault & VM_FAULT_ERROR))
return fault;
if (fault & VM_FAULT_MAJOR)
tsk->maj_flt++;
else
tsk->min_flt++;
return fault;
return handle_mm_fault(mm, vma, addr & PAGE_MASK, flags);
check_stack:
if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
......@@ -279,6 +268,9 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
struct task_struct *tsk;
struct mm_struct *mm;
int fault, sig, code;
int write = fsr & FSR_WRITE;
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
(write ? FAULT_FLAG_WRITE : 0);
if (notify_page_fault(regs, fsr))
return 0;
......@@ -305,6 +297,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if (!down_read_trylock(&mm->mmap_sem)) {
if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc))
goto no_context;
retry:
down_read(&mm->mmap_sem);
} else {
/*
......@@ -320,14 +313,41 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
#endif
}
fault = __do_page_fault(mm, addr, fsr, tsk);
up_read(&mm->mmap_sem);
fault = __do_page_fault(mm, addr, fsr, flags, tsk);
/* If we need to retry but a fatal signal is pending, handle the
* signal first. We do not need to release the mmap_sem because
* it would already be released in __lock_page_or_retry in
* mm/filemap.c. */
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
return 0;
/*
* Major/minor page fault accounting is only done on the
* initial attempt. If we go through a retry, it is extremely
* likely that the page will be found in page cache at that point.
*/
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
if (fault & VM_FAULT_MAJOR)
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, addr);
else if (fault & VM_FAULT_MINOR)
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, addr);
if (flags & FAULT_FLAG_ALLOW_RETRY) {
if (fault & VM_FAULT_MAJOR) {
tsk->maj_flt++;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
regs, addr);
} else {
tsk->min_flt++;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
regs, addr);
}
if (fault & VM_FAULT_RETRY) {
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
flags &= ~FAULT_FLAG_ALLOW_RETRY;
goto retry;
}
}
up_read(&mm->mmap_sem);
/*
* Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
......
......@@ -11,10 +11,49 @@
#include <linux/random.h>
#include <asm/cachetype.h>
static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
unsigned long pgoff)
{
unsigned long base = addr & ~(SHMLBA-1);
unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1);
if (base + off <= addr)
return base + off;
return base - off;
}
#define COLOUR_ALIGN(addr,pgoff) \
((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
(((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
/* gap between mmap and stack */
#define MIN_GAP (128*1024*1024UL)
#define MAX_GAP ((TASK_SIZE)/6*5)
static int mmap_is_legacy(void)
{
if (current->personality & ADDR_COMPAT_LAYOUT)
return 1;
if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
return 1;
return sysctl_legacy_va_layout;
}
static unsigned long mmap_base(unsigned long rnd)
{
unsigned long gap = rlimit(RLIMIT_STACK);
if (gap < MIN_GAP)
gap = MIN_GAP;
else if (gap > MAX_GAP)
gap = MAX_GAP;
return PAGE_ALIGN(TASK_SIZE - gap - rnd);
}
/*
* We need to ensure that shared mappings are correctly aligned to
* avoid aliasing issues with VIPT caches. We need to ensure that
......@@ -68,13 +107,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (len > mm->cached_hole_size) {
start_addr = addr = mm->free_area_cache;
} else {
start_addr = addr = TASK_UNMAPPED_BASE;
start_addr = addr = mm->mmap_base;
mm->cached_hole_size = 0;
}
/* 8 bits of randomness in 20 address space bits */
if ((current->flags & PF_RANDOMIZE) &&
!(current->personality & ADDR_NO_RANDOMIZE))
addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
full_search:
if (do_align)
......@@ -111,6 +146,134 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
}
}
unsigned long
arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
const unsigned long len, const unsigned long pgoff,
const unsigned long flags)
{
struct vm_area_struct *vma;
struct mm_struct *mm = current->mm;
unsigned long addr = addr0;
int do_align = 0;
int aliasing = cache_is_vipt_aliasing();
/*
* We only need to do colour alignment if either the I or D
* caches alias.
*/
if (aliasing)
do_align = filp || (flags & MAP_SHARED);
/* requested length too big for entire address space */
if (len > TASK_SIZE)
return -ENOMEM;
if (flags & MAP_FIXED) {
if (aliasing && flags & MAP_SHARED &&
(addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
return -EINVAL;
return addr;
}
/* requesting a specific address */
if (addr) {
if (do_align)
addr = COLOUR_ALIGN(addr, pgoff);
else
addr = PAGE_ALIGN(addr);
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
(!vma || addr + len <= vma->vm_start))
return addr;
}
/* check if free_area_cache is useful for us */
if (len <= mm->cached_hole_size) {
mm->cached_hole_size = 0;
mm->free_area_cache = mm->mmap_base;
}
/* either no address requested or can't fit in requested address hole */
addr = mm->free_area_cache;
if (do_align) {
unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff);
addr = base + len;
}
/* make sure it can fit in the remaining address space */
if (addr > len) {
vma = find_vma(mm, addr-len);
if (!vma || addr <= vma->vm_start)
/* remember the address as a hint for next time */
return (mm->free_area_cache = addr-len);
}
if (mm->mmap_base < len)
goto bottomup;
addr = mm->mmap_base - len;
if (do_align)
addr = COLOUR_ALIGN_DOWN(addr, pgoff);
do {
/*
* Lookup failure means no vma is above this address,
* else if new region fits below vma->vm_start,
* return with success:
*/
vma = find_vma(mm, addr);
if (!vma || addr+len <= vma->vm_start)
/* remember the address as a hint for next time */
return (mm->free_area_cache = addr);
/* remember the largest hole we saw so far */
if (addr + mm->cached_hole_size < vma->vm_start)
mm->cached_hole_size = vma->vm_start - addr;
/* try just below the current vma->vm_start */
addr = vma->vm_start - len;
if (do_align)
addr = COLOUR_ALIGN_DOWN(addr, pgoff);
} while (len < vma->vm_start);
bottomup:
/*
* A failed mmap() very likely causes application failure,
* so fall back to the bottom-up function here. This scenario
* can happen with large stack limits and large mmap()
* allocations.
*/
mm->cached_hole_size = ~0UL;
mm->free_area_cache = TASK_UNMAPPED_BASE;
addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
/*
* Restore the topdown base:
*/
mm->free_area_cache = mm->mmap_base;
mm->cached_hole_size = ~0UL;
return addr;
}
void arch_pick_mmap_layout(struct mm_struct *mm)
{
unsigned long random_factor = 0UL;
/* 8 bits of randomness in 20 address space bits */
if ((current->flags & PF_RANDOMIZE) &&
!(current->personality & ADDR_NO_RANDOMIZE))
random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
if (mmap_is_legacy()) {
mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
mm->get_unmapped_area = arch_get_unmapped_area;
mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base(random_factor);
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
mm->unmap_area = arch_unmap_area_topdown;
}
}
/*
* You really shouldn't be using read() or write() on /dev/mem. This
......
......@@ -284,6 +284,7 @@ __v7_ca5mp_setup:
__v7_ca9mp_setup:
mov r10, #(1 << 0) @ TLB ops broadcasting
b 1f
__v7_ca7mp_setup:
__v7_ca15mp_setup:
mov r10, #0
1:
......@@ -464,6 +465,16 @@ __v7_ca5mp_proc_info:
__v7_proc __v7_ca5mp_setup
.size __v7_ca5mp_proc_info, . - __v7_ca5mp_proc_info
/*
* ARM Ltd. Cortex A7 processor.
*/
.type __v7_ca7mp_proc_info, #object
__v7_ca7mp_proc_info:
.long 0x410fc070
.long 0xff0ffff0
__v7_proc __v7_ca7mp_setup, hwcaps = HWCAP_IDIV
.size __v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info
/*
* ARM Ltd. Cortex A9 processor.
*/
......
......@@ -20,6 +20,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <asm/opcodes.h>
/* This is the kernel's entry point into the floating point emulator.
It is called from the kernel with code similar to this:
......@@ -81,11 +83,11 @@ nwfpe_enter:
mov r6, r0 @ save the opcode
emulate:
ldr r1, [sp, #S_PSR] @ fetch the PSR
bl checkCondition @ check the condition
cmp r0, #0 @ r0 = 0 ==> condition failed
bl arm_check_condition @ check the condition
cmp r0, #ARM_OPCODE_CONDTEST_PASS @ condition passed?
@ if condition code failed to match, next insn
beq next @ get the next instruction;
bne next @ get the next instruction;
mov r0, r6 @ prepare for EmulateAll()
bl EmulateAll @ emulate the instruction
......
......@@ -61,29 +61,3 @@ const float32 float32Constant[] = {
0x41200000 /* single 10.0 */
};
/* condition code lookup table
index into the table is test code: EQ, NE, ... LT, GT, AL, NV
bit position in short is condition code: NZCV */
static const unsigned short aCC[16] = {
0xF0F0, // EQ == Z set
0x0F0F, // NE
0xCCCC, // CS == C set
0x3333, // CC
0xFF00, // MI == N set
0x00FF, // PL
0xAAAA, // VS == V set
0x5555, // VC
0x0C0C, // HI == C set && Z clear
0xF3F3, // LS == C clear || Z set
0xAA55, // GE == (N==V)
0x55AA, // LT == (N!=V)
0x0A05, // GT == (!Z && (N==V))
0xF5FA, // LE == (Z || (N!=V))
0xFFFF, // AL always
0 // NV
};
unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes)
{
return (aCC[opcode >> 28] >> (ccodes >> 28)) & 1;
}
......@@ -475,9 +475,6 @@ static inline unsigned int getDestinationSize(const unsigned int opcode)
return (nRc);
}
extern unsigned int checkCondition(const unsigned int opcode,
const unsigned int ccodes);
extern const float64 float64Constant[];
extern const float32 float32Constant[];
......
This diff is collapsed.
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