Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c71d4aa7 authored by Russell King's avatar Russell King
Browse files

Merge branch 'hw-breakpoint' of...

Merge branch 'hw-breakpoint' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into devel-stable
parents 667832da f600b9fc
Loading
Loading
Loading
Loading
+2 −18
Original line number Diff line number Diff line
@@ -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
+4 −4
Original line number Diff line number Diff line
@@ -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;
+85 −69
Original line number Diff line number Diff line
@@ -54,12 +54,12 @@ static u8 max_watchpoint_len;

#define READ_WB_REG_CASE(OP2, M, VAL)			\
	case ((OP2 << 4) + M):				\
		ARM_DBG_READ(c ## M, OP2, VAL); \
		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);\
		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. "
		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,20 +228,18 @@ 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);

	/* 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;
	ARM_DBG_READ(c0, c1, 0, dscr);
	return !!(dscr & ARM_DSCR_MDBGEN);
}

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)
		goto out;
@@ -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 @@ static void reset_ctrl_regs(void *unused)
		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);
	}

	/* Register debug fault handler. */
	hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,