Commit a278e7ea authored by Michael Neuling's avatar Michael Neuling Committed by Michael Ellerman
Browse files

powerpc: Fix compile issue with force DAWR



If you compile with KVM but without CONFIG_HAVE_HW_BREAKPOINT you fail
at linking with:
  arch/powerpc/kvm/book3s_hv_rmhandlers.o:(.text+0x708): undefined reference to `dawr_force_enable'

This was caused by commit c1fe190c ("powerpc: Add force enable of
DAWR on P9 option").

This moves a bunch of code around to fix this. It moves a lot of the
DAWR code in a new file and creates a new CONFIG_PPC_DAWR to enable
compiling it.

Fixes: c1fe190c ("powerpc: Add force enable of DAWR on P9 option")
Signed-off-by: default avatarMichael Neuling <mikey@neuling.org>
[mpe: Minor formatting in set_dawr()]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 548c54ac
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -236,6 +236,7 @@ config PPC
	select OLD_SIGSUSPEND
	select PCI_DOMAINS			if PCI
	select PCI_SYSCALL			if PCI
	select PPC_DAWR				if PPC64
	select RTC_LIB
	select SPARSE_IRQ
	select SYSCTL_EXCEPTION_TRACE
@@ -372,6 +373,9 @@ config PPC_ADV_DEBUG_DAC_RANGE
	depends on PPC_ADV_DEBUG_REGS && 44x
	default y

config PPC_DAWR
	bool

config ZONE_DMA
	bool
	default y if PPC_BOOK3E_64
+14 −7
Original line number Diff line number Diff line
@@ -90,18 +90,25 @@ static inline void hw_breakpoint_disable(void)
extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
int hw_breakpoint_handler(struct die_args *args);

extern int set_dawr(struct arch_hw_breakpoint *brk);
#else	/* CONFIG_HAVE_HW_BREAKPOINT */
static inline void hw_breakpoint_disable(void) { }
static inline void thread_change_pc(struct task_struct *tsk,
					struct pt_regs *regs) { }

#endif	/* CONFIG_HAVE_HW_BREAKPOINT */


#ifdef CONFIG_PPC_DAWR
extern bool dawr_force_enable;
static inline bool dawr_enabled(void)
{
	return dawr_force_enable;
}

#else	/* CONFIG_HAVE_HW_BREAKPOINT */
static inline void hw_breakpoint_disable(void) { }
static inline void thread_change_pc(struct task_struct *tsk,
					struct pt_regs *regs) { }
int set_dawr(struct arch_hw_breakpoint *brk);
#else
static inline bool dawr_enabled(void) { return false; }
#endif	/* CONFIG_HAVE_HW_BREAKPOINT */
static inline int set_dawr(struct arch_hw_breakpoint *brk) { return -1; }
#endif

#endif	/* __KERNEL__ */
#endif	/* _PPC_BOOK3S_64_HW_BREAKPOINT_H */
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
obj-$(CONFIG_VDSO32)		+= vdso32/
obj-$(CONFIG_PPC_WATCHDOG)	+= watchdog.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
obj-$(CONFIG_PPC_DAWR)		+= dawr.o
obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_ppc970.o cpu_setup_pa6t.o
obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_power.o
obj-$(CONFIG_PPC_BOOK3S_64)	+= mce.o mce_power.o
+101 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+
/*
 * DAWR infrastructure
 *
 * Copyright 2019, Michael Neuling, IBM Corporation.
 */

#include <linux/types.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <asm/debugfs.h>
#include <asm/machdep.h>
#include <asm/hvcall.h>

bool dawr_force_enable;
EXPORT_SYMBOL_GPL(dawr_force_enable);

int set_dawr(struct arch_hw_breakpoint *brk)
{
	unsigned long dawr, dawrx, mrd;

	dawr = brk->address;

	dawrx  = (brk->type & (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE))
		<< (63 - 58);
	dawrx |= ((brk->type & (HW_BRK_TYPE_TRANSLATE)) >> 2) << (63 - 59);
	dawrx |= (brk->type & (HW_BRK_TYPE_PRIV_ALL)) >> 3;
	/*
	 * DAWR length is stored in field MDR bits 48:53.  Matches range in
	 * doublewords (64 bits) baised by -1 eg. 0b000000=1DW and
	 * 0b111111=64DW.
	 * brk->len is in bytes.
	 * This aligns up to double word size, shifts and does the bias.
	 */
	mrd = ((brk->len + 7) >> 3) - 1;
	dawrx |= (mrd & 0x3f) << (63 - 53);

	if (ppc_md.set_dawr)
		return ppc_md.set_dawr(dawr, dawrx);

	mtspr(SPRN_DAWR, dawr);
	mtspr(SPRN_DAWRX, dawrx);

	return 0;
}

static void set_dawr_cb(void *info)
{
	set_dawr(info);
}

static ssize_t dawr_write_file_bool(struct file *file,
				    const char __user *user_buf,
				    size_t count, loff_t *ppos)
{
	struct arch_hw_breakpoint null_brk = {0, 0, 0};
	size_t rc;

	/* Send error to user if they hypervisor won't allow us to write DAWR */
	if (!dawr_force_enable &&
	    firmware_has_feature(FW_FEATURE_LPAR) &&
	    set_dawr(&null_brk) != H_SUCCESS)
		return -ENODEV;

	rc = debugfs_write_file_bool(file, user_buf, count, ppos);
	if (rc)
		return rc;

	/* If we are clearing, make sure all CPUs have the DAWR cleared */
	if (!dawr_force_enable)
		smp_call_function(set_dawr_cb, &null_brk, 0);

	return rc;
}

static const struct file_operations dawr_enable_fops = {
	.read =		debugfs_read_file_bool,
	.write =	dawr_write_file_bool,
	.open =		simple_open,
	.llseek =	default_llseek,
};

static int __init dawr_force_setup(void)
{
	if (cpu_has_feature(CPU_FTR_DAWR)) {
		/* Don't setup sysfs file for user control on P8 */
		dawr_force_enable = true;
		return 0;
	}

	if (PVR_VER(mfspr(SPRN_PVR)) == PVR_POWER9) {
		/* Turn DAWR off by default, but allow admin to turn it on */
		debugfs_create_file_unsafe("dawr_enable_dangerous", 0600,
					   powerpc_debugfs_root,
					   &dawr_force_enable,
					   &dawr_enable_fops);
	}
	return 0;
}
arch_initcall(dawr_force_setup);
+0 −61
Original line number Diff line number Diff line
@@ -380,64 +380,3 @@ void hw_breakpoint_pmu_read(struct perf_event *bp)
{
	/* TODO */
}

bool dawr_force_enable;
EXPORT_SYMBOL_GPL(dawr_force_enable);

static void set_dawr_cb(void *info)
{
	set_dawr(info);
}

static ssize_t dawr_write_file_bool(struct file *file,
				    const char __user *user_buf,
				    size_t count, loff_t *ppos)
{
	struct arch_hw_breakpoint null_brk = {0, 0, 0};
	size_t rc;

	/* Send error to user if they hypervisor won't allow us to write DAWR */
	if ((!dawr_force_enable) &&
	    (firmware_has_feature(FW_FEATURE_LPAR)) &&
	    (set_dawr(&null_brk) != H_SUCCESS))
		return -1;

	rc = debugfs_write_file_bool(file, user_buf, count, ppos);
	if (rc)
		return rc;

	/* If we are clearing, make sure all CPUs have the DAWR cleared */
	if (!dawr_force_enable)
		smp_call_function(set_dawr_cb, &null_brk, 0);

	return rc;
}

static const struct file_operations dawr_enable_fops = {
	.read =		debugfs_read_file_bool,
	.write =	dawr_write_file_bool,
	.open =		simple_open,
	.llseek =	default_llseek,
};

static int __init dawr_force_setup(void)
{
	dawr_force_enable = false;

	if (cpu_has_feature(CPU_FTR_DAWR)) {
		/* Don't setup sysfs file for user control on P8 */
		dawr_force_enable = true;
		return 0;
	}

	if (PVR_VER(mfspr(SPRN_PVR)) == PVR_POWER9) {
		/* Turn DAWR off by default, but allow admin to turn it on */
		dawr_force_enable = false;
		debugfs_create_file_unsafe("dawr_enable_dangerous", 0600,
					   powerpc_debugfs_root,
					   &dawr_force_enable,
					   &dawr_enable_fops);
	}
	return 0;
}
arch_initcall(dawr_force_setup);
Loading