Merge branch 'devel-stable' into devel

Conflicts:
	arch/arm/mach-pxa/clock.c
	arch/arm/mach-pxa/clock.h
This commit is contained in:
Russell King
2011-01-06 22:33:32 +00:00
413 changed files with 23376 additions and 6825 deletions
+1
View File
@@ -54,6 +54,7 @@ AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o
obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o
obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o
obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o
obj-$(CONFIG_IWMMXT) += iwmmxt.o
obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
+4
View File
@@ -178,6 +178,7 @@ __dabt_svc:
@
@ set desired IRQ state, then call main handler
@
debug_entry r1
msr cpsr_c, r9
mov r2, sp
bl do_DataAbort
@@ -304,6 +305,7 @@ __pabt_svc:
#else
bl CPU_PABORT_HANDLER
#endif
debug_entry r1
msr cpsr_c, r9 @ Maybe enable interrupts
mov r2, sp @ regs
bl do_PrefetchAbort @ call abort handler
@@ -419,6 +421,7 @@ __dabt_usr:
@
@ IRQs on, then call the main handler
@
debug_entry r1
enable_irq
mov r2, sp
adr lr, BSYM(ret_from_exception)
@@ -683,6 +686,7 @@ __pabt_usr:
#else
bl CPU_PABORT_HANDLER
#endif
debug_entry r1
enable_irq @ Enable interrupts
mov r2, sp @ regs
bl do_PrefetchAbort @ call abort handler
+19
View File
@@ -165,6 +165,25 @@
.endm
#endif /* !CONFIG_THUMB2_KERNEL */
@
@ Debug exceptions are taken as prefetch or data aborts.
@ We must disable preemption during the handler so that
@ we can access the debug registers safely.
@
.macro debug_entry, fsr
#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT)
ldr r4, =0x40f @ mask out fsr.fs
and r5, r4, \fsr
cmp r5, #2 @ debug exception
bne 1f
get_thread_info r10
ldr r6, [r10, #TI_PREEMPT] @ get preempt count
add r11, r6, #1 @ increment it
str r11, [r10, #TI_PREEMPT]
1:
#endif
.endm
/*
* These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - r0 to r6.
+319 -224
View File
@@ -24,6 +24,7 @@
#define pr_fmt(fmt) "hw-breakpoint: " fmt
#include <linux/errno.h>
#include <linux/hardirq.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/smp.h>
@@ -44,6 +45,7 @@ static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]);
/* Number of BRP/WRP registers on this CPU. */
static int core_num_brps;
static int core_num_reserved_brps;
static int core_num_wrps;
/* Debug architecture version. */
@@ -52,87 +54,6 @@ static u8 debug_arch;
/* Maximum supported watchpoint length. */
static u8 max_watchpoint_len;
/* Determine number of BRP registers available. */
static int get_num_brps(void)
{
u32 didr;
ARM_DBG_READ(c0, 0, didr);
return ((didr >> 24) & 0xf) + 1;
}
/* Determine number of WRP registers available. */
static int get_num_wrps(void)
{
/*
* FIXME: When a watchpoint fires, the only way to work out which
* watchpoint it was is by disassembling the faulting instruction
* and working out the address of the memory access.
*
* Furthermore, we can only do this if the watchpoint was precise
* since imprecise watchpoints prevent us from calculating register
* based addresses.
*
* For the time being, we only report 1 watchpoint register so we
* always know which watchpoint fired. In the future we can either
* add a disassembler and address generation emulator, or we can
* insert a check to see if the DFAR is set on watchpoint exception
* entry [the ARM ARM states that the DFAR is UNKNOWN, but
* experience shows that it is set on some implementations].
*/
#if 0
u32 didr, wrps;
ARM_DBG_READ(c0, 0, didr);
return ((didr >> 28) & 0xf) + 1;
#endif
return 1;
}
int hw_breakpoint_slots(int type)
{
/*
* We can be called early, so don't rely on
* our static variables being initialised.
*/
switch (type) {
case TYPE_INST:
return get_num_brps();
case TYPE_DATA:
return get_num_wrps();
default:
pr_warning("unknown slot type: %d\n", type);
return 0;
}
}
/* Determine debug architecture. */
static u8 get_debug_arch(void)
{
u32 didr;
/* Do we implement the extended CPUID interface? */
if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
pr_warning("CPUID feature registers not supported. "
"Assuming v6 debug is present.\n");
return ARM_DEBUG_ARCH_V6;
}
ARM_DBG_READ(c0, 0, didr);
return (didr >> 16) & 0xf;
}
/* Does this core support mismatch breakpoints? */
static int core_has_mismatch_bps(void)
{
return debug_arch >= ARM_DEBUG_ARCH_V7_ECP14 && core_num_brps > 1;
}
u8 arch_get_debug_arch(void)
{
return debug_arch;
}
#define READ_WB_REG_CASE(OP2, M, VAL) \
case ((OP2 << 4) + M): \
ARM_DBG_READ(c ## M, OP2, VAL); \
@@ -210,6 +131,94 @@ static void write_wb_reg(int n, u32 val)
isb();
}
/* Determine debug architecture. */
static u8 get_debug_arch(void)
{
u32 didr;
/* Do we implement the extended CPUID interface? */
if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
pr_warning("CPUID feature registers not supported. "
"Assuming v6 debug is present.\n");
return ARM_DEBUG_ARCH_V6;
}
ARM_DBG_READ(c0, 0, didr);
return (didr >> 16) & 0xf;
}
u8 arch_get_debug_arch(void)
{
return debug_arch;
}
/* Determine number of BRP register available. */
static int get_num_brp_resources(void)
{
u32 didr;
ARM_DBG_READ(c0, 0, didr);
return ((didr >> 24) & 0xf) + 1;
}
/* Does this core support mismatch breakpoints? */
static int core_has_mismatch_brps(void)
{
return (get_debug_arch() >= ARM_DEBUG_ARCH_V7_ECP14 &&
get_num_brp_resources() > 1);
}
/* Determine number of usable WRPs available. */
static int get_num_wrps(void)
{
/*
* FIXME: When a watchpoint fires, the only way to work out which
* watchpoint it was is by disassembling the faulting instruction
* and working out the address of the memory access.
*
* Furthermore, we can only do this if the watchpoint was precise
* since imprecise watchpoints prevent us from calculating register
* based addresses.
*
* Providing we have more than 1 breakpoint register, we only report
* a single watchpoint register for the time being. This way, we always
* know which watchpoint fired. In the future we can either add a
* disassembler and address generation emulator, or we can insert a
* check to see if the DFAR is set on watchpoint exception entry
* [the ARM ARM states that the DFAR is UNKNOWN, but experience shows
* that it is set on some implementations].
*/
#if 0
int wrps;
u32 didr;
ARM_DBG_READ(c0, 0, didr);
wrps = ((didr >> 28) & 0xf) + 1;
#endif
int wrps = 1;
if (core_has_mismatch_brps() && wrps >= get_num_brp_resources())
wrps = get_num_brp_resources() - 1;
return wrps;
}
/* We reserve one breakpoint for each watchpoint. */
static int get_num_reserved_brps(void)
{
if (core_has_mismatch_brps())
return get_num_wrps();
return 0;
}
/* Determine number of usable BRPs available. */
static int get_num_brps(void)
{
int brps = get_num_brp_resources();
if (core_has_mismatch_brps())
brps -= get_num_reserved_brps();
return brps;
}
/*
* In order to access the breakpoint/watchpoint control registers,
* we must be running in debug monitor mode. Unfortunately, we can
@@ -230,8 +239,12 @@ static int enable_monitor_mode(void)
goto out;
}
/* If monitor mode is already enabled, just return. */
if (dscr & ARM_DSCR_MDBGEN)
goto out;
/* Write to the corresponding DSCR. */
switch (debug_arch) {
switch (get_debug_arch()) {
case ARM_DEBUG_ARCH_V6:
case ARM_DEBUG_ARCH_V6_1:
ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN));
@@ -246,15 +259,30 @@ static int enable_monitor_mode(void)
/* Check that the write made it through. */
ARM_DBG_READ(c1, 0, dscr);
if (WARN_ONCE(!(dscr & ARM_DSCR_MDBGEN),
"failed to enable monitor mode.")) {
if (!(dscr & ARM_DSCR_MDBGEN))
ret = -EPERM;
}
out:
return ret;
}
int hw_breakpoint_slots(int type)
{
/*
* We can be called early, so don't rely on
* our static variables being initialised.
*/
switch (type) {
case TYPE_INST:
return get_num_brps();
case TYPE_DATA:
return get_num_wrps();
default:
pr_warning("unknown slot type: %d\n", type);
return 0;
}
}
/*
* Check if 8-bit byte-address select is available.
* This clobbers WRP 0.
@@ -268,9 +296,6 @@ static u8 get_max_wp_len(void)
if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14)
goto out;
if (enable_monitor_mode())
goto out;
memset(&ctrl, 0, sizeof(ctrl));
ctrl.len = ARM_BREAKPOINT_LEN_8;
ctrl_reg = encode_ctrl_reg(ctrl);
@@ -289,23 +314,6 @@ u8 arch_get_max_wp_len(void)
return max_watchpoint_len;
}
/*
* Handler for reactivating a suspended watchpoint when the single
* step `mismatch' breakpoint is triggered.
*/
static void wp_single_step_handler(struct perf_event *bp, int unused,
struct perf_sample_data *data,
struct pt_regs *regs)
{
perf_event_enable(counter_arch_bp(bp)->suspended_wp);
unregister_hw_breakpoint(bp);
}
static int bp_is_single_step(struct perf_event *bp)
{
return bp->overflow_handler == wp_single_step_handler;
}
/*
* Install a perf counter breakpoint.
*/
@@ -314,30 +322,41 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
struct perf_event **slot, **slots;
int i, max_slots, ctrl_base, val_base, ret = 0;
u32 addr, ctrl;
/* Ensure that we are in monitor mode and halting mode is disabled. */
ret = enable_monitor_mode();
if (ret)
goto out;
addr = info->address;
ctrl = encode_ctrl_reg(info->ctrl) | 0x1;
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
/* Breakpoint */
ctrl_base = ARM_BASE_BCR;
val_base = ARM_BASE_BVR;
slots = __get_cpu_var(bp_on_reg);
max_slots = core_num_brps - 1;
if (bp_is_single_step(bp)) {
info->ctrl.mismatch = 1;
i = max_slots;
slots[i] = bp;
goto setup;
slots = (struct perf_event **)__get_cpu_var(bp_on_reg);
max_slots = core_num_brps;
if (info->step_ctrl.enabled) {
/* Override the breakpoint data with the step data. */
addr = info->trigger & ~0x3;
ctrl = encode_ctrl_reg(info->step_ctrl);
}
} else {
/* Watchpoint */
ctrl_base = ARM_BASE_WCR;
val_base = ARM_BASE_WVR;
slots = __get_cpu_var(wp_on_reg);
if (info->step_ctrl.enabled) {
/* Install into the reserved breakpoint region. */
ctrl_base = ARM_BASE_BCR + core_num_brps;
val_base = ARM_BASE_BVR + core_num_brps;
/* Override the watchpoint data with the step data. */
addr = info->trigger & ~0x3;
ctrl = encode_ctrl_reg(info->step_ctrl);
} else {
ctrl_base = ARM_BASE_WCR;
val_base = ARM_BASE_WVR;
}
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
max_slots = core_num_wrps;
}
@@ -355,12 +374,11 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
goto out;
}
setup:
/* Setup the address register. */
write_wb_reg(val_base + i, info->address);
write_wb_reg(val_base + i, addr);
/* Setup the control register. */
write_wb_reg(ctrl_base + i, encode_ctrl_reg(info->ctrl) | 0x1);
write_wb_reg(ctrl_base + i, ctrl);
out:
return ret;
@@ -375,18 +393,15 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
/* Breakpoint */
base = ARM_BASE_BCR;
slots = __get_cpu_var(bp_on_reg);
max_slots = core_num_brps - 1;
if (bp_is_single_step(bp)) {
i = max_slots;
slots[i] = NULL;
goto reset;
}
slots = (struct perf_event **)__get_cpu_var(bp_on_reg);
max_slots = core_num_brps;
} else {
/* Watchpoint */
base = ARM_BASE_WCR;
slots = __get_cpu_var(wp_on_reg);
if (info->step_ctrl.enabled)
base = ARM_BASE_BCR + core_num_brps;
else
base = ARM_BASE_WCR;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
max_slots = core_num_wrps;
}
@@ -403,7 +418,6 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
return;
reset:
/* Reset the control register. */
write_wb_reg(base + i, 0);
}
@@ -537,12 +551,23 @@ static int arch_build_bp_info(struct perf_event *bp)
return -EINVAL;
}
/*
* Breakpoints must be of length 2 (thumb) or 4 (ARM) bytes.
* Watchpoints can be of length 1, 2, 4 or 8 bytes if supported
* by the hardware and must be aligned to the appropriate number of
* bytes.
*/
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE &&
info->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
info->ctrl.len != ARM_BREAKPOINT_LEN_4)
return -EINVAL;
/* Address */
info->address = bp->attr.bp_addr;
/* Privilege */
info->ctrl.privilege = ARM_BREAKPOINT_USER;
if (arch_check_bp_in_kernelspace(bp) && !bp_is_single_step(bp))
if (arch_check_bp_in_kernelspace(bp))
info->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
/* Enabled? */
@@ -561,7 +586,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
int ret = 0;
u32 bytelen, max_len, offset, alignment_mask = 0x3;
u32 offset, alignment_mask = 0x3;
/* Build the arch_hw_breakpoint. */
ret = arch_build_bp_info(bp);
@@ -571,84 +596,85 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
/* Check address alignment. */
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
alignment_mask = 0x7;
if (info->address & alignment_mask) {
/*
* Try to fix the alignment. This may result in a length
* that is too large, so we must check for that.
*/
bytelen = get_hbp_len(info->ctrl.len);
max_len = info->ctrl.type == ARM_BREAKPOINT_EXECUTE ? 4 :
max_watchpoint_len;
if (max_len >= 8)
offset = info->address & 0x7;
else
offset = info->address & 0x3;
if (bytelen > (1 << ((max_len - (offset + 1)) >> 1))) {
ret = -EFBIG;
goto out;
}
info->ctrl.len <<= offset;
info->address &= ~offset;
pr_debug("breakpoint alignment fixup: length = 0x%x, "
"address = 0x%x\n", info->ctrl.len, info->address);
offset = info->address & alignment_mask;
switch (offset) {
case 0:
/* Aligned */
break;
case 1:
/* Allow single byte watchpoint. */
if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
break;
case 2:
/* Allow halfword watchpoints and breakpoints. */
if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
break;
default:
ret = -EINVAL;
goto out;
}
info->address &= ~alignment_mask;
info->ctrl.len <<= offset;
/*
* Currently we rely on an overflow handler to take
* care of single-stepping the breakpoint when it fires.
* In the case of userspace breakpoints on a core with V7 debug,
* we can use the mismatch feature as a poor-man's hardware single-step.
* we can use the mismatch feature as a poor-man's hardware
* single-step, but this only works for per-task breakpoints.
*/
if (WARN_ONCE(!bp->overflow_handler &&
(arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()),
(arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_brps()
|| !bp->hw.bp_target),
"overflow handler required but none found")) {
ret = -EINVAL;
goto out;
}
out:
return ret;
}
static void update_mismatch_flag(int idx, int flag)
/*
* Enable/disable single-stepping over the breakpoint bp at address addr.
*/
static void enable_single_step(struct perf_event *bp, u32 addr)
{
struct perf_event *bp = __get_cpu_var(bp_on_reg[idx]);
struct arch_hw_breakpoint *info;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
if (bp == NULL)
return;
arch_uninstall_hw_breakpoint(bp);
info->step_ctrl.mismatch = 1;
info->step_ctrl.len = ARM_BREAKPOINT_LEN_4;
info->step_ctrl.type = ARM_BREAKPOINT_EXECUTE;
info->step_ctrl.privilege = info->ctrl.privilege;
info->step_ctrl.enabled = 1;
info->trigger = addr;
arch_install_hw_breakpoint(bp);
}
info = counter_arch_bp(bp);
/* Update the mismatch field to enter/exit `single-step' mode */
if (!bp->overflow_handler && info->ctrl.mismatch != flag) {
info->ctrl.mismatch = flag;
write_wb_reg(ARM_BASE_BCR + idx, encode_ctrl_reg(info->ctrl) | 0x1);
}
static void disable_single_step(struct perf_event *bp)
{
arch_uninstall_hw_breakpoint(bp);
counter_arch_bp(bp)->step_ctrl.enabled = 0;
arch_install_hw_breakpoint(bp);
}
static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
{
int i;
struct perf_event *bp, **slots = __get_cpu_var(wp_on_reg);
struct perf_event *wp, **slots;
struct arch_hw_breakpoint *info;
struct perf_event_attr attr;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
/* Without a disassembler, we can only handle 1 watchpoint. */
BUG_ON(core_num_wrps > 1);
hw_breakpoint_init(&attr);
attr.bp_addr = regs->ARM_pc & ~0x3;
attr.bp_len = HW_BREAKPOINT_LEN_4;
attr.bp_type = HW_BREAKPOINT_X;
for (i = 0; i < core_num_wrps; ++i) {
rcu_read_lock();
if (slots[i] == NULL) {
wp = slots[i];
if (wp == NULL) {
rcu_read_unlock();
continue;
}
@@ -658,87 +684,121 @@ static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
* single watchpoint, we can set the trigger to the lowest
* possible faulting address.
*/
info = counter_arch_bp(slots[i]);
info->trigger = slots[i]->attr.bp_addr;
info = counter_arch_bp(wp);
info->trigger = wp->attr.bp_addr;
pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
perf_bp_event(slots[i], regs);
perf_bp_event(wp, regs);
/*
* If no overflow handler is present, insert a temporary
* mismatch breakpoint so we can single-step over the
* watchpoint trigger.
*/
if (!slots[i]->overflow_handler) {
bp = register_user_hw_breakpoint(&attr,
wp_single_step_handler,
current);
counter_arch_bp(bp)->suspended_wp = slots[i];
perf_event_disable(slots[i]);
}
if (!wp->overflow_handler)
enable_single_step(wp, instruction_pointer(regs));
rcu_read_unlock();
}
}
static void watchpoint_single_step_handler(unsigned long pc)
{
int i;
struct perf_event *wp, **slots;
struct arch_hw_breakpoint *info;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
for (i = 0; i < core_num_reserved_brps; ++i) {
rcu_read_lock();
wp = slots[i];
if (wp == NULL)
goto unlock;
info = counter_arch_bp(wp);
if (!info->step_ctrl.enabled)
goto unlock;
/*
* Restore the original watchpoint if we've completed the
* single-step.
*/
if (info->trigger != pc)
disable_single_step(wp);
unlock:
rcu_read_unlock();
}
}
static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
{
int i;
int mismatch;
u32 ctrl_reg, val, addr;
struct perf_event *bp, **slots = __get_cpu_var(bp_on_reg);
struct perf_event *bp, **slots;
struct arch_hw_breakpoint *info;
struct arch_hw_breakpoint_ctrl ctrl;
slots = (struct perf_event **)__get_cpu_var(bp_on_reg);
/* The exception entry code places the amended lr in the PC. */
addr = regs->ARM_pc;
/* Check the currently installed breakpoints first. */
for (i = 0; i < core_num_brps; ++i) {
rcu_read_lock();
bp = slots[i];
if (bp == NULL) {
rcu_read_unlock();
continue;
}
if (bp == NULL)
goto unlock;
mismatch = 0;
info = counter_arch_bp(bp);
/* Check if the breakpoint value matches. */
val = read_wb_reg(ARM_BASE_BVR + i);
if (val != (addr & ~0x3))
goto unlock;
goto mismatch;
/* Possible match, check the byte address select to confirm. */
ctrl_reg = read_wb_reg(ARM_BASE_BCR + i);
decode_ctrl_reg(ctrl_reg, &ctrl);
if ((1 << (addr & 0x3)) & ctrl.len) {
mismatch = 1;
info = counter_arch_bp(bp);
info->trigger = addr;
}
unlock:
if ((mismatch && !info->ctrl.mismatch) || bp_is_single_step(bp)) {
pr_debug("breakpoint fired: address = 0x%x\n", addr);
perf_bp_event(bp, regs);
if (!bp->overflow_handler)
enable_single_step(bp, addr);
goto unlock;
}
update_mismatch_flag(i, mismatch);
mismatch:
/* If we're stepping a breakpoint, it can now be restored. */
if (info->step_ctrl.enabled)
disable_single_step(bp);
unlock:
rcu_read_unlock();
}
/* Handle any pending watchpoint single-step breakpoints. */
watchpoint_single_step_handler(addr);
}
/*
* Called from either the Data Abort Handler [watchpoint] or the
* Prefetch Abort Handler [breakpoint].
* Prefetch Abort Handler [breakpoint] with preemption disabled.
*/
static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
int ret = 1; /* Unhandled fault. */
int ret = 0;
u32 dscr;
/* We must be called with preemption disabled. */
WARN_ON(preemptible());
/* We only handle watchpoints and hardware breakpoints. */
ARM_DBG_READ(c1, 0, dscr);
@@ -753,25 +813,47 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
watchpoint_handler(addr, regs);
break;
default:
goto out;
ret = 1; /* Unhandled fault. */
}
ret = 0;
out:
/*
* Re-enable preemption after it was disabled in the
* low-level exception handling code.
*/
preempt_enable();
return ret;
}
/*
* One-time initialisation.
*/
static void __init reset_ctrl_regs(void *unused)
static void reset_ctrl_regs(void *unused)
{
int i;
/*
* v7 debug contains save and restore registers so that debug state
* can be maintained across low-power modes without leaving
* the debug logic powered up. It is IMPLEMENTATION DEFINED whether
* we can write to the debug registers out of reset, so we must
* unlock the OS Lock Access Register to avoid taking undefined
* instruction exceptions later on.
*/
if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) {
/*
* Unconditionally clear the lock by writing a value
* other than 0xC5ACCE55 to the access register.
*/
asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0));
isb();
}
if (enable_monitor_mode())
return;
for (i = 0; i < core_num_brps; ++i) {
/* We must also reset any reserved registers. */
for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) {
write_wb_reg(ARM_BASE_BCR + i, 0UL);
write_wb_reg(ARM_BASE_BVR + i, 0UL);
}
@@ -782,45 +864,57 @@ static void __init reset_ctrl_regs(void *unused)
}
}
static int __cpuinit dbg_reset_notify(struct notifier_block *self,
unsigned long action, void *cpu)
{
if (action == CPU_ONLINE)
smp_call_function_single((int)cpu, reset_ctrl_regs, NULL, 1);
return NOTIFY_OK;
}
static struct notifier_block __cpuinitdata dbg_reset_nb = {
.notifier_call = dbg_reset_notify,
};
static int __init arch_hw_breakpoint_init(void)
{
int ret = 0;
u32 dscr;
debug_arch = get_debug_arch();
if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) {
pr_info("debug architecture 0x%x unsupported.\n", debug_arch);
ret = -ENODEV;
goto out;
return 0;
}
/* Determine how many BRPs/WRPs are available. */
core_num_brps = get_num_brps();
core_num_reserved_brps = get_num_reserved_brps();
core_num_wrps = get_num_wrps();
pr_info("found %d breakpoint and %d watchpoint registers.\n",
core_num_brps, core_num_wrps);
core_num_brps + core_num_reserved_brps, core_num_wrps);
if (core_has_mismatch_bps())
pr_info("1 breakpoint reserved for watchpoint single-step.\n");
if (core_num_reserved_brps)
pr_info("%d breakpoint(s) reserved for watchpoint "
"single-step.\n", core_num_reserved_brps);
ARM_DBG_READ(c1, 0, dscr);
if (dscr & ARM_DSCR_HDBGEN) {
pr_warning("halting debug mode enabled. Assuming maximum "
"watchpoint size of 4 bytes.");
} else {
/* Work out the maximum supported watchpoint length. */
max_watchpoint_len = get_max_wp_len();
pr_info("maximum watchpoint size is %u bytes.\n",
max_watchpoint_len);
/*
* Reset the breakpoint resources. We assume that a halting
* debugger will leave the world in a nice state for us.
*/
smp_call_function(reset_ctrl_regs, NULL, 1);
reset_ctrl_regs(NULL);
/* Work out the maximum supported watchpoint length. */
max_watchpoint_len = get_max_wp_len();
pr_info("maximum watchpoint size is %u bytes.\n",
max_watchpoint_len);
}
/* Register debug fault handler. */
@@ -829,8 +923,9 @@ static int __init arch_hw_breakpoint_init(void)
hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
"breakpoint debug exception");
out:
return ret;
/* Register hotplug notifier. */
register_cpu_notifier(&dbg_reset_nb);
return 0;
}
arch_initcall(arch_hw_breakpoint_init);
+42 -13
View File
@@ -19,6 +19,14 @@
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
#if defined(CONFIG_CPU_PJ4)
#define PJ4(code...) code
#define XSC(code...)
#else
#define PJ4(code...)
#define XSC(code...) code
#endif
#define MMX_WR0 (0x00)
#define MMX_WR1 (0x08)
#define MMX_WR2 (0x10)
@@ -58,11 +66,17 @@
ENTRY(iwmmxt_task_enable)
mrc p15, 0, r2, c15, c1, 0
tst r2, #0x3 @ CP0 and CP1 accessible?
XSC(mrc p15, 0, r2, c15, c1, 0)
PJ4(mrc p15, 0, r2, c1, c0, 2)
@ CP0 and CP1 accessible?
XSC(tst r2, #0x3)
PJ4(tst r2, #0xf)
movne pc, lr @ if so no business here
orr r2, r2, #0x3 @ enable access to CP0 and CP1
mcr p15, 0, r2, c15, c1, 0
@ enable access to CP0 and CP1
XSC(orr r2, r2, #0x3)
XSC(mcr p15, 0, r2, c15, c1, 0)
PJ4(orr r2, r2, #0xf)
PJ4(mcr p15, 0, r2, c1, c0, 2)
ldr r3, =concan_owner
add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area
@@ -179,17 +193,26 @@ ENTRY(iwmmxt_task_disable)
teqne r1, r2 @ or specified one?
bne 1f @ no: quit
mrc p15, 0, r4, c15, c1, 0
orr r4, r4, #0x3 @ enable access to CP0 and CP1
mcr p15, 0, r4, c15, c1, 0
@ enable access to CP0 and CP1
XSC(mrc p15, 0, r4, c15, c1, 0)
XSC(orr r4, r4, #0xf)
XSC(mcr p15, 0, r4, c15, c1, 0)
PJ4(mrc p15, 0, r4, c1, c0, 2)
PJ4(orr r4, r4, #0x3)
PJ4(mcr p15, 0, r4, c1, c0, 2)
mov r0, #0 @ nothing to load
str r0, [r3] @ no more current owner
mrc p15, 0, r2, c2, c0, 0
mov r2, r2 @ cpwait
bl concan_save
bic r4, r4, #0x3 @ disable access to CP0 and CP1
mcr p15, 0, r4, c15, c1, 0
@ disable access to CP0 and CP1
XSC(bic r4, r4, #0x3)
XSC(mcr p15, 0, r4, c15, c1, 0)
PJ4(bic r4, r4, #0xf)
PJ4(mcr p15, 0, r4, c1, c0, 2)
mrc p15, 0, r2, c2, c0, 0
mov r2, r2 @ cpwait
@@ -277,8 +300,11 @@ ENTRY(iwmmxt_task_restore)
*/
ENTRY(iwmmxt_task_switch)
mrc p15, 0, r1, c15, c1, 0
tst r1, #0x3 @ CP0 and CP1 accessible?
XSC(mrc p15, 0, r1, c15, c1, 0)
PJ4(mrc p15, 0, r1, c1, c0, 2)
@ CP0 and CP1 accessible?
XSC(tst r1, #0x3)
PJ4(tst r1, #0xf)
bne 1f @ yes: block them for next task
ldr r2, =concan_owner
@@ -287,8 +313,11 @@ ENTRY(iwmmxt_task_switch)
teq r2, r3 @ next task owns it?
movne pc, lr @ no: leave Concan disabled
1: eor r1, r1, #3 @ flip Concan access
mcr p15, 0, r1, c15, c1, 0
1: @ flip Conan access
XSC(eor r1, r1, #0x3)
XSC(mcr p15, 0, r1, c15, c1, 0)
PJ4(eor r1, r1, #0xf)
PJ4(mcr p15, 0, r1, c1, c0, 2)
mrc p15, 0, r1, c2, c0, 0
sub pc, lr, r1, lsr #32 @ cpwait and return
+9 -9
View File
@@ -32,7 +32,7 @@ static struct platform_device *pmu_device;
* Hardware lock to serialize accesses to PMU registers. Needed for the
* read/modify/write sequences.
*/
DEFINE_SPINLOCK(pmu_lock);
static DEFINE_RAW_SPINLOCK(pmu_lock);
/*
* ARMv6 supports a maximum of 3 events, starting from index 1. If we add
@@ -65,7 +65,7 @@ struct cpu_hw_events {
*/
unsigned long active_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];
};
DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
struct arm_pmu {
enum arm_perf_pmu_ids id;
@@ -673,17 +673,17 @@ arch_initcall(init_hw_perf_events);
* This code has been adapted from the ARM OProfile support.
*/
struct frame_tail {
struct frame_tail *fp;
unsigned long sp;
unsigned long lr;
struct frame_tail __user *fp;
unsigned long sp;
unsigned long lr;
} __attribute__((packed));
/*
* Get the return address for a single stackframe and return a pointer to the
* next frame tail.
*/
static struct frame_tail *
user_backtrace(struct frame_tail *tail,
static struct frame_tail __user *
user_backtrace(struct frame_tail __user *tail,
struct perf_callchain_entry *entry)
{
struct frame_tail buftail;
@@ -709,10 +709,10 @@ user_backtrace(struct frame_tail *tail,
void
perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
{
struct frame_tail *tail;
struct frame_tail __user *tail;
tail = (struct frame_tail *)regs->ARM_fp - 1;
tail = (struct frame_tail __user *)regs->ARM_fp - 1;
while (tail && !((unsigned long)tail & 0x3))
tail = user_backtrace(tail, entry);
+15 -15
View File
@@ -400,7 +400,7 @@ armv6pmu_write_counter(int counter,
WARN_ONCE(1, "invalid counter number (%d)\n", counter);
}
void
static void
armv6pmu_enable_event(struct hw_perf_event *hwc,
int idx)
{
@@ -426,12 +426,12 @@ armv6pmu_enable_event(struct hw_perf_event *hwc,
* Mask out the current event and set the counter to count the event
* that we're interested in.
*/
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~mask;
val |= evt;
armv6_pmcr_write(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static irqreturn_t
@@ -500,11 +500,11 @@ armv6pmu_start(void)
{
unsigned long flags, val;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = armv6_pmcr_read();
val |= ARMV6_PMCR_ENABLE;
armv6_pmcr_write(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void
@@ -512,11 +512,11 @@ armv6pmu_stop(void)
{
unsigned long flags, val;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~ARMV6_PMCR_ENABLE;
armv6_pmcr_write(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static int
@@ -570,12 +570,12 @@ armv6pmu_disable_event(struct hw_perf_event *hwc,
* of ETM bus signal assertion cycles. The external reporting should
* be disabled and so this should never increment.
*/
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~mask;
val |= evt;
armv6_pmcr_write(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void
@@ -599,12 +599,12 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
* Unlike UP ARMv6, we don't have a way of stopping the counters. We
* simply disable the interrupt reporting.
*/
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~mask;
val |= evt;
armv6_pmcr_write(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static const struct arm_pmu armv6pmu = {
@@ -625,7 +625,7 @@ static const struct arm_pmu armv6pmu = {
.max_period = (1LLU << 32) - 1,
};
const struct arm_pmu *__init armv6pmu_init(void)
static const struct arm_pmu *__init armv6pmu_init(void)
{
return &armv6pmu;
}
@@ -655,17 +655,17 @@ static const struct arm_pmu armv6mpcore_pmu = {
.max_period = (1LLU << 32) - 1,
};
const struct arm_pmu *__init armv6mpcore_pmu_init(void)
static const struct arm_pmu *__init armv6mpcore_pmu_init(void)
{
return &armv6mpcore_pmu;
}
#else
const struct arm_pmu *__init armv6pmu_init(void)
static const struct arm_pmu *__init armv6pmu_init(void)
{
return NULL;
}
const struct arm_pmu *__init armv6mpcore_pmu_init(void)
static const struct arm_pmu *__init armv6mpcore_pmu_init(void)
{
return NULL;
}
+13 -13
View File
@@ -681,7 +681,7 @@ static void armv7_pmnc_dump_regs(void)
}
#endif
void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
{
unsigned long flags;
@@ -689,7 +689,7 @@ void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
* Enable counter and interrupt, and set the counter to count
* the event that we're interested in.
*/
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
/*
* Disable counter
@@ -713,7 +713,7 @@ void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
*/
armv7_pmnc_enable_counter(idx);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
@@ -723,7 +723,7 @@ static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
/*
* Disable counter and interrupt
*/
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
/*
* Disable counter
@@ -735,7 +735,7 @@ static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
*/
armv7_pmnc_disable_intens(idx);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
@@ -805,20 +805,20 @@ static void armv7pmu_start(void)
{
unsigned long flags;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
/* Enable all counters */
armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void armv7pmu_stop(void)
{
unsigned long flags;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
/* Disable all counters */
armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,
@@ -874,7 +874,7 @@ static u32 __init armv7_reset_read_pmnc(void)
return nb_cnt + 1;
}
const struct arm_pmu *__init armv7_a8_pmu_init(void)
static const struct arm_pmu *__init armv7_a8_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA8;
armv7pmu.name = "ARMv7 Cortex-A8";
@@ -884,7 +884,7 @@ const struct arm_pmu *__init armv7_a8_pmu_init(void)
return &armv7pmu;
}
const struct arm_pmu *__init armv7_a9_pmu_init(void)
static const struct arm_pmu *__init armv7_a9_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA9;
armv7pmu.name = "ARMv7 Cortex-A9";
@@ -894,12 +894,12 @@ const struct arm_pmu *__init armv7_a9_pmu_init(void)
return &armv7pmu;
}
#else
const struct arm_pmu *__init armv7_a8_pmu_init(void)
static const struct arm_pmu *__init armv7_a8_pmu_init(void)
{
return NULL;
}
const struct arm_pmu *__init armv7_a9_pmu_init(void)
static const struct arm_pmu *__init armv7_a9_pmu_init(void)
{
return NULL;
}
+20 -20
View File
@@ -291,12 +291,12 @@ xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
return;
}
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val &= ~mask;
val |= evt;
xscale1pmu_write_pmnc(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void
@@ -322,12 +322,12 @@ xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
return;
}
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val &= ~mask;
val |= evt;
xscale1pmu_write_pmnc(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static int
@@ -355,11 +355,11 @@ xscale1pmu_start(void)
{
unsigned long flags, val;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val |= XSCALE_PMU_ENABLE;
xscale1pmu_write_pmnc(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void
@@ -367,11 +367,11 @@ xscale1pmu_stop(void)
{
unsigned long flags, val;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val &= ~XSCALE_PMU_ENABLE;
xscale1pmu_write_pmnc(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static inline u32
@@ -428,7 +428,7 @@ static const struct arm_pmu xscale1pmu = {
.max_period = (1LLU << 32) - 1,
};
const struct arm_pmu *__init xscale1pmu_init(void)
static const struct arm_pmu *__init xscale1pmu_init(void)
{
return &xscale1pmu;
}
@@ -635,10 +635,10 @@ xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
return;
}
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
xscale2pmu_write_event_select(evtsel);
xscale2pmu_write_int_enable(ien);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void
@@ -678,10 +678,10 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
return;
}
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
xscale2pmu_write_event_select(evtsel);
xscale2pmu_write_int_enable(ien);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static int
@@ -705,11 +705,11 @@ xscale2pmu_start(void)
{
unsigned long flags, val;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
val |= XSCALE_PMU_ENABLE;
xscale2pmu_write_pmnc(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void
@@ -717,11 +717,11 @@ xscale2pmu_stop(void)
{
unsigned long flags, val;
spin_lock_irqsave(&pmu_lock, flags);
raw_spin_lock_irqsave(&pmu_lock, flags);
val = xscale2pmu_read_pmnc();
val &= ~XSCALE_PMU_ENABLE;
xscale2pmu_write_pmnc(val);
spin_unlock_irqrestore(&pmu_lock, flags);
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static inline u32
@@ -790,17 +790,17 @@ static const struct arm_pmu xscale2pmu = {
.max_period = (1LLU << 32) - 1,
};
const struct arm_pmu *__init xscale2pmu_init(void)
static const struct arm_pmu *__init xscale2pmu_init(void)
{
return &xscale2pmu;
}
#else
const struct arm_pmu *__init xscale1pmu_init(void)
static const struct arm_pmu *__init xscale1pmu_init(void)
{
return NULL;
}
const struct arm_pmu *__init xscale2pmu_init(void)
static const struct arm_pmu *__init xscale2pmu_init(void)
{
return NULL;
}
+94
View File
@@ -0,0 +1,94 @@
/*
* linux/arch/arm/kernel/pj4-cp0.c
*
* PJ4 iWMMXt coprocessor context switching and handling
*
* Copyright (c) 2010 Marvell International Inc.
*
* 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 <linux/types.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/io.h>
#include <asm/thread_notify.h>
static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
{
struct thread_info *thread = t;
switch (cmd) {
case THREAD_NOTIFY_FLUSH:
/*
* flush_thread() zeroes thread->fpstate, so no need
* to do anything here.
*
* FALLTHROUGH: Ensure we don't try to overwrite our newly
* initialised state information on the first fault.
*/
case THREAD_NOTIFY_EXIT:
iwmmxt_task_release(thread);
break;
case THREAD_NOTIFY_SWITCH:
iwmmxt_task_switch(thread);
break;
}
return NOTIFY_DONE;
}
static struct notifier_block iwmmxt_notifier_block = {
.notifier_call = iwmmxt_do,
};
static u32 __init pj4_cp_access_read(void)
{
u32 value;
__asm__ __volatile__ (
"mrc p15, 0, %0, c1, c0, 2\n\t"
: "=r" (value));
return value;
}
static void __init pj4_cp_access_write(u32 value)
{
u32 temp;
__asm__ __volatile__ (
"mcr p15, 0, %1, c1, c0, 2\n\t"
"mrc p15, 0, %0, c1, c0, 2\n\t"
"mov %0, %0\n\t"
"sub pc, pc, #4\n\t"
: "=r" (temp) : "r" (value));
}
/*
* Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
* switch code handle iWMMXt context switching.
*/
static int __init pj4_cp0_init(void)
{
u32 cp_access;
cp_access = pj4_cp_access_read() & ~0xf;
pj4_cp_access_write(cp_access);
printk(KERN_INFO "PJ4 iWMMXt coprocessor enabled.\n");
elf_hwcap |= HWCAP_IWMMXT;
thread_register_notifier(&iwmmxt_notifier_block);
return 0;
}
late_initcall(pj4_cp0_init);
+2 -2
View File
@@ -1060,8 +1060,8 @@ static int ptrace_sethbpregs(struct task_struct *tsk, long num,
goto out;
if ((gen_type & implied_type) != gen_type) {
ret = -EINVAL;
goto out;
ret = -EINVAL;
goto out;
}
attr.bp_len = gen_len;