]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'hw-breakpoint' of git://git.kernel.org/pub/scm/linux/kernel/git/will...
authorRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 19 Nov 2012 11:23:08 +0000 (11:23 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 19 Nov 2012 11:23:08 +0000 (11:23 +0000)
arch/arm/include/asm/cti.h
arch/arm/include/asm/hw_breakpoint.h
arch/arm/kernel/hw_breakpoint.c

index a0ada3ea4358dfa21c9a08fe36b06897d4a16ff3..f2e5cad3f30655369b57edecf88d5c03c895e5f1 100644 (file)
@@ -146,15 +146,7 @@ static inline void cti_irq_ack(struct cti *cti)
  */
 static inline void cti_unlock(struct cti *cti)
 {
-       void __iomem *base = cti->base;
-       unsigned long val;
-
-       val = __raw_readl(base + LOCKSTATUS);
-
-       if (val & 1) {
-               val = LOCKCODE;
-               __raw_writel(val, base + LOCKACCESS);
-       }
+       __raw_writel(LOCKCODE, cti->base + LOCKACCESS);
 }
 
 /**
@@ -166,14 +158,6 @@ static inline void cti_unlock(struct cti *cti)
  */
 static inline void cti_lock(struct cti *cti)
 {
-       void __iomem *base = cti->base;
-       unsigned long val;
-
-       val = __raw_readl(base + LOCKSTATUS);
-
-       if (!(val & 1)) {
-               val = ~LOCKCODE;
-               __raw_writel(val, base + LOCKACCESS);
-       }
+       __raw_writel(~LOCKCODE, cti->base + LOCKACCESS);
 }
 #endif
index c190bc992f0e6e917d2071c920312c7391beb5e3..01169dd723f12e06f0506c7b8d4d16732170b9aa 100644 (file)
@@ -98,12 +98,12 @@ static inline void decode_ctrl_reg(u32 reg,
 #define ARM_BASE_WCR           112
 
 /* Accessor macros for the debug registers. */
-#define ARM_DBG_READ(M, OP2, VAL) do {\
-       asm volatile("mrc p14, 0, %0, c0," #M ", " #OP2 : "=r" (VAL));\
+#define ARM_DBG_READ(N, M, OP2, VAL) do {\
+       asm volatile("mrc p14, 0, %0, " #N "," #M ", " #OP2 : "=r" (VAL));\
 } while (0)
 
-#define ARM_DBG_WRITE(M, OP2, VAL) do {\
-       asm volatile("mcr p14, 0, %0, c0," #M ", " #OP2 : : "r" (VAL));\
+#define ARM_DBG_WRITE(N, M, OP2, VAL) do {\
+       asm volatile("mcr p14, 0, %0, " #N "," #M ", " #OP2 : : "r" (VAL));\
 } while (0)
 
 struct notifier_block;
index 281bf3301241fba2a1ce1baafeaf3020b7cd57ff..5ff2e77782b185cdcaf18a1636e00ce25b0cf733 100644 (file)
@@ -52,14 +52,14 @@ static u8 debug_arch;
 /* Maximum supported watchpoint length. */
 static u8 max_watchpoint_len;
 
-#define READ_WB_REG_CASE(OP2, M, VAL)          \
-       case ((OP2 << 4) + M):                  \
-               ARM_DBG_READ(c ## M, OP2, VAL); \
+#define READ_WB_REG_CASE(OP2, M, VAL)                  \
+       case ((OP2 << 4) + M):                          \
+               ARM_DBG_READ(c0, c ## M, OP2, VAL);     \
                break
 
-#define WRITE_WB_REG_CASE(OP2, M, VAL)         \
-       case ((OP2 << 4) + M):                  \
-               ARM_DBG_WRITE(c ## M, OP2, VAL);\
+#define WRITE_WB_REG_CASE(OP2, M, VAL)                 \
+       case ((OP2 << 4) + M):                          \
+               ARM_DBG_WRITE(c0, c ## M, OP2, VAL);    \
                break
 
 #define GEN_READ_WB_REG_CASES(OP2, VAL)                \
@@ -136,12 +136,12 @@ static u8 get_debug_arch(void)
 
        /* 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");
+               pr_warn_once("CPUID feature registers not supported. "
+                            "Assuming v6 debug is present.\n");
                return ARM_DEBUG_ARCH_V6;
        }
 
-       ARM_DBG_READ(c0, 0, didr);
+       ARM_DBG_READ(c0, c0, 0, didr);
        return (didr >> 16) & 0xf;
 }
 
@@ -169,7 +169,7 @@ static int debug_exception_updates_fsr(void)
 static int get_num_wrp_resources(void)
 {
        u32 didr;
-       ARM_DBG_READ(c0, 0, didr);
+       ARM_DBG_READ(c0, c0, 0, didr);
        return ((didr >> 28) & 0xf) + 1;
 }
 
@@ -177,7 +177,7 @@ static int get_num_wrp_resources(void)
 static int get_num_brp_resources(void)
 {
        u32 didr;
-       ARM_DBG_READ(c0, 0, didr);
+       ARM_DBG_READ(c0, c0, 0, didr);
        return ((didr >> 24) & 0xf) + 1;
 }
 
@@ -228,19 +228,17 @@ static int get_num_brps(void)
  * be put into halting debug mode at any time by an external debugger
  * but there is nothing we can do to prevent that.
  */
-static int enable_monitor_mode(void)
+static int monitor_mode_enabled(void)
 {
        u32 dscr;
-       int ret = 0;
-
-       ARM_DBG_READ(c1, 0, dscr);
+       ARM_DBG_READ(c0, c1, 0, dscr);
+       return !!(dscr & ARM_DSCR_MDBGEN);
+}
 
-       /* Ensure that halting mode is disabled. */
-       if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN,
-               "halting debug mode enabled. Unable to access hardware resources.\n")) {
-               ret = -EPERM;
-               goto out;
-       }
+static int enable_monitor_mode(void)
+{
+       u32 dscr;
+       ARM_DBG_READ(c0, c1, 0, dscr);
 
        /* If monitor mode is already enabled, just return. */
        if (dscr & ARM_DSCR_MDBGEN)
@@ -250,24 +248,27 @@ static int enable_monitor_mode(void)
        switch (get_debug_arch()) {
        case ARM_DEBUG_ARCH_V6:
        case ARM_DEBUG_ARCH_V6_1:
-               ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN));
+               ARM_DBG_WRITE(c0, c1, 0, (dscr | ARM_DSCR_MDBGEN));
                break;
        case ARM_DEBUG_ARCH_V7_ECP14:
        case ARM_DEBUG_ARCH_V7_1:
-               ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN));
+               ARM_DBG_WRITE(c0, c2, 2, (dscr | ARM_DSCR_MDBGEN));
+               isb();
                break;
        default:
-               ret = -ENODEV;
-               goto out;
+               return -ENODEV;
        }
 
        /* Check that the write made it through. */
-       ARM_DBG_READ(c1, 0, dscr);
-       if (!(dscr & ARM_DSCR_MDBGEN))
-               ret = -EPERM;
+       ARM_DBG_READ(c0, c1, 0, dscr);
+       if (!(dscr & ARM_DSCR_MDBGEN)) {
+               pr_warn_once("Failed to enable monitor mode on CPU %d.\n",
+                               smp_processor_id());
+               return -EPERM;
+       }
 
 out:
-       return ret;
+       return 0;
 }
 
 int hw_breakpoint_slots(int type)
@@ -328,14 +329,9 @@ 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;
+       int i, max_slots, ctrl_base, val_base;
        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;
 
@@ -362,9 +358,9 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
                }
        }
 
-       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) {
-               ret = -EBUSY;
-               goto out;
+       if (i == max_slots) {
+               pr_warning("Can't find any breakpoint slot\n");
+               return -EBUSY;
        }
 
        /* Override the breakpoint data with the step data. */
@@ -383,9 +379,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
 
        /* Setup the control register. */
        write_wb_reg(ctrl_base + i, ctrl);
-
-out:
-       return ret;
+       return 0;
 }
 
 void arch_uninstall_hw_breakpoint(struct perf_event *bp)
@@ -416,8 +410,10 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
                }
        }
 
-       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n"))
+       if (i == max_slots) {
+               pr_warning("Can't find any breakpoint slot\n");
                return;
+       }
 
        /* Ensure that we disable the mismatch breakpoint. */
        if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE &&
@@ -596,6 +592,10 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
        int ret = 0;
        u32 offset, alignment_mask = 0x3;
 
+       /* Ensure that we are in monitor debug mode. */
+       if (!monitor_mode_enabled())
+               return -ENODEV;
+
        /* Build the arch_hw_breakpoint. */
        ret = arch_build_bp_info(bp);
        if (ret)
@@ -858,7 +858,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
                local_irq_enable();
 
        /* We only handle watchpoints and hardware breakpoints. */
-       ARM_DBG_READ(c1, 0, dscr);
+       ARM_DBG_READ(c0, c1, 0, dscr);
 
        /* Perform perf callbacks. */
        switch (ARM_DSCR_MOE(dscr)) {
@@ -906,7 +906,7 @@ static struct undef_hook debug_reg_hook = {
 static void reset_ctrl_regs(void *unused)
 {
        int i, raw_num_brps, err = 0, cpu = smp_processor_id();
-       u32 dbg_power;
+       u32 val;
 
        /*
         * v7 debug contains save and restore registers so that debug state
@@ -919,23 +919,30 @@ static void reset_ctrl_regs(void *unused)
        switch (debug_arch) {
        case ARM_DEBUG_ARCH_V6:
        case ARM_DEBUG_ARCH_V6_1:
-               /* ARMv6 cores just need to reset the registers. */
-               goto reset_regs;
+               /* ARMv6 cores clear the registers out of reset. */
+               goto out_mdbgen;
        case ARM_DEBUG_ARCH_V7_ECP14:
                /*
                 * Ensure sticky power-down is clear (i.e. debug logic is
                 * powered up).
                 */
-               asm volatile("mrc p14, 0, %0, c1, c5, 4" : "=r" (dbg_power));
-               if ((dbg_power & 0x1) == 0)
+               ARM_DBG_READ(c1, c5, 4, val);
+               if ((val & 0x1) == 0)
                        err = -EPERM;
+
+               /*
+                * Check whether we implement OS save and restore.
+                */
+               ARM_DBG_READ(c1, c1, 4, val);
+               if ((val & 0x9) == 0)
+                       goto clear_vcr;
                break;
        case ARM_DEBUG_ARCH_V7_1:
                /*
                 * Ensure the OS double lock is clear.
                 */
-               asm volatile("mrc p14, 0, %0, c1, c3, 4" : "=r" (dbg_power));
-               if ((dbg_power & 0x1) == 1)
+               ARM_DBG_READ(c1, c3, 4, val);
+               if ((val & 0x1) == 1)
                        err = -EPERM;
                break;
        }
@@ -947,24 +954,29 @@ static void reset_ctrl_regs(void *unused)
        }
 
        /*
-        * Unconditionally clear the lock by writing a value
+        * Unconditionally clear the OS lock by writing a value
         * other than 0xC5ACCE55 to the access register.
         */
-       asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0));
+       ARM_DBG_WRITE(c1, c0, 4, 0);
        isb();
 
        /*
         * Clear any configured vector-catch events before
         * enabling monitor mode.
         */
-       asm volatile("mcr p14, 0, %0, c0, c7, 0" : : "r" (0));
+clear_vcr:
+       ARM_DBG_WRITE(c0, c7, 0, 0);
        isb();
 
-reset_regs:
-       if (enable_monitor_mode())
+       if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) {
+               pr_warning("CPU %d failed to disable vector catch\n", cpu);
                return;
+       }
 
-       /* We must also reset any reserved registers. */
+       /*
+        * The control/value register pairs are UNKNOWN out of reset so
+        * clear them to avoid spurious debug events.
+        */
        raw_num_brps = get_num_brp_resources();
        for (i = 0; i < raw_num_brps; ++i) {
                write_wb_reg(ARM_BASE_BCR + i, 0UL);
@@ -975,6 +987,19 @@ reset_regs:
                write_wb_reg(ARM_BASE_WCR + i, 0UL);
                write_wb_reg(ARM_BASE_WVR + i, 0UL);
        }
+
+       if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) {
+               pr_warning("CPU %d failed to clear debug register pairs\n", cpu);
+               return;
+       }
+
+       /*
+        * Have a crack at enabling monitor mode. We don't actually need
+        * it yet, but reporting an error early is useful if it fails.
+        */
+out_mdbgen:
+       if (enable_monitor_mode())
+               cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu));
 }
 
 static int __cpuinit dbg_reset_notify(struct notifier_block *self,
@@ -992,8 +1017,6 @@ static struct notifier_block __cpuinitdata dbg_reset_nb = {
 
 static int __init arch_hw_breakpoint_init(void)
 {
-       u32 dscr;
-
        debug_arch = get_debug_arch();
 
        if (!debug_arch_supported()) {
@@ -1028,17 +1051,10 @@ static int __init arch_hw_breakpoint_init(void)
                core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " :
                "", core_num_wrps);
 
-       ARM_DBG_READ(c1, 0, dscr);
-       if (dscr & ARM_DSCR_HDBGEN) {
-               max_watchpoint_len = 4;
-               pr_warning("halting debug mode enabled. Assuming maximum watchpoint size of %u bytes.\n",
-                          max_watchpoint_len);
-       } 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);
-       }
+       /* 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. */
        hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,