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

Commit b866cc21 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc: Change the doorbell IPI calling convention



Change the doorbell callers to know about their msgsnd addressing,
rather than have them set a per-cpu target data tag at boot that gets
sent to the cause_ipi functions. The data is only used for doorbell IPI
functions, no other IPI types, so it makes sense to keep that detail
local to doorbell.

Have the platform code understand doorbell IPIs, rather than the
interrupt controller code understand them. Platform code can look at
capabilities it has available and decide which to use.

Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 9b7ff0c6
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -35,8 +35,6 @@ enum ppc_dbell {
#ifdef CONFIG_PPC_BOOK3S

#define PPC_DBELL_MSGTYPE		PPC_DBELL_SERVER
#define SPRN_DOORBELL_CPUTAG		SPRN_TIR
#define PPC_DBELL_TAG_MASK		0x7f

static inline void _ppc_msgsnd(u32 msg)
{
@@ -49,8 +47,6 @@ static inline void _ppc_msgsnd(u32 msg)
#else /* CONFIG_PPC_BOOK3S */

#define PPC_DBELL_MSGTYPE		PPC_DBELL
#define SPRN_DOORBELL_CPUTAG		SPRN_PIR
#define PPC_DBELL_TAG_MASK		0x3fff

static inline void _ppc_msgsnd(u32 msg)
{
@@ -59,9 +55,10 @@ static inline void _ppc_msgsnd(u32 msg)

#endif /* CONFIG_PPC_BOOK3S */

extern void doorbell_cause_ipi(int cpu, unsigned long data);
extern void doorbell_global_ipi(int cpu);
extern void doorbell_core_ipi(int cpu);
extern int doorbell_try_core_ipi(int cpu);
extern void doorbell_exception(struct pt_regs *regs);
extern void doorbell_setup_this_cpu(void);

static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
{
+1 −2
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ extern int cpu_to_chip_id(int cpu);
struct smp_ops_t {
	void  (*message_pass)(int cpu, int msg);
#ifdef CONFIG_PPC_SMP_MUXED_IPI
	void  (*cause_ipi)(int cpu, unsigned long data);
	void  (*cause_ipi)(int cpu);
#endif
	void  (*probe)(void);
	int   (*kick_cpu)(int nr);
@@ -125,7 +125,6 @@ extern int smp_request_message_ipi(int virq, int message);
extern const char *smp_ipi_name[];

/* for irq controllers with only a single ipi */
extern void smp_muxed_ipi_set_data(int cpu, unsigned long data);
extern void smp_muxed_ipi_message_pass(int cpu, int msg);
extern void smp_muxed_ipi_set_message(int cpu, int msg);
extern irqreturn_t smp_ipi_demux(void);
+1 −1
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ struct icp_ops {
	void (*teardown_cpu)(void);
	void (*flush_ipi)(void);
#ifdef CONFIG_SMP
	void (*cause_ipi)(int cpu, unsigned long data);
	void (*cause_ipi)(int cpu);
	irq_handler_t ipi_action;
#endif
};
+47 −5
Original line number Diff line number Diff line
@@ -20,18 +20,60 @@
#include <asm/kvm_ppc.h>

#ifdef CONFIG_SMP
void doorbell_setup_this_cpu(void)

/*
 * Doorbells must only be used if CPU_FTR_DBELL is available.
 * msgsnd is used in HV, and msgsndp is used in !HV.
 *
 * These should be used by platform code that is aware of restrictions.
 * Other arch code should use ->cause_ipi.
 *
 * doorbell_global_ipi() sends a dbell to any target CPU.
 * Must be used only by architectures that address msgsnd target
 * by PIR/get_hard_smp_processor_id.
 */
void doorbell_global_ipi(int cpu)
{
	unsigned long tag = mfspr(SPRN_DOORBELL_CPUTAG) & PPC_DBELL_TAG_MASK;
	u32 tag = get_hard_smp_processor_id(cpu);

	smp_muxed_ipi_set_data(smp_processor_id(), tag);
	kvmppc_set_host_ipi(cpu, 1);
	/* Order previous accesses vs. msgsnd, which is treated as a store */
	mb();
	ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
}

void doorbell_cause_ipi(int cpu, unsigned long data)
/*
 * doorbell_core_ipi() sends a dbell to a target CPU in the same core.
 * Must be used only by architectures that address msgsnd target
 * by TIR/cpu_thread_in_core.
 */
void doorbell_core_ipi(int cpu)
{
	u32 tag = cpu_thread_in_core(cpu);

	kvmppc_set_host_ipi(cpu, 1);
	/* Order previous accesses vs. msgsnd, which is treated as a store */
	mb();
	ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, data);
	ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
}

/*
 * Attempt to cause a core doorbell if destination is on the same core.
 * Returns 1 on success, 0 on failure.
 */
int doorbell_try_core_ipi(int cpu)
{
	int this_cpu = get_cpu();
	int ret = 0;

	if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) {
		doorbell_core_ipi(cpu);
		ret = 1;
	}

	put_cpu();

	return ret;
}

void doorbell_exception(struct pt_regs *regs)
+5 −12
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <asm/irq.h>
#include <asm/hw_irq.h>
#include <asm/kvm_ppc.h>
#include <asm/dbell.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
@@ -211,17 +212,9 @@ int smp_request_message_ipi(int virq, int msg)
#ifdef CONFIG_PPC_SMP_MUXED_IPI
struct cpu_messages {
	long messages;			/* current messages */
	unsigned long data;		/* data for cause ipi */
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message);

void smp_muxed_ipi_set_data(int cpu, unsigned long data)
{
	struct cpu_messages *info = &per_cpu(ipi_message, cpu);

	info->data = data;
}

void smp_muxed_ipi_set_message(int cpu, int msg)
{
	struct cpu_messages *info = &per_cpu(ipi_message, cpu);
@@ -236,14 +229,13 @@ void smp_muxed_ipi_set_message(int cpu, int msg)

void smp_muxed_ipi_message_pass(int cpu, int msg)
{
	struct cpu_messages *info = &per_cpu(ipi_message, cpu);

	smp_muxed_ipi_set_message(cpu, msg);

	/*
	 * cause_ipi functions are required to include a full barrier
	 * before doing whatever causes the IPI.
	 */
	smp_ops->cause_ipi(cpu, info->data);
	smp_ops->cause_ipi(cpu);
}

#ifdef __BIG_ENDIAN__
@@ -254,11 +246,12 @@ void smp_muxed_ipi_message_pass(int cpu, int msg)

irqreturn_t smp_ipi_demux(void)
{
	struct cpu_messages *info = this_cpu_ptr(&ipi_message);
	struct cpu_messages *info;
	unsigned long all;

	mb();	/* order any irq clear */

	info = this_cpu_ptr(&ipi_message);
	do {
		all = xchg(&info->messages, 0);
#if defined(CONFIG_KVM_XICS) && defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
Loading