blob: b6fe883b1016dd395a21c0ec4c64867c2d208b57 [file] [log] [blame]
Kumar Gala620165f2009-02-12 13:54:53 +00001/*
2 * Author: Kumar Gala <galak@kernel.crashing.org>
3 *
4 * Copyright 2009 Freescale Semiconductor Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12#include <linux/stddef.h>
13#include <linux/kernel.h>
14#include <linux/smp.h>
15#include <linux/threads.h>
Milton Miller23d72bf2011-05-10 19:29:39 +000016#include <linux/hardirq.h>
Kumar Gala620165f2009-02-12 13:54:53 +000017
18#include <asm/dbell.h>
David Gibson0e37d252010-07-09 15:32:30 +100019#include <asm/irq_regs.h>
Paul Mackerras755563b2015-03-19 19:29:01 +110020#include <asm/kvm_ppc.h>
Kumar Gala620165f2009-02-12 13:54:53 +000021
22#ifdef CONFIG_SMP
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100023
Nicholas Pigginb866cc22017-04-13 20:16:21 +100024/*
25 * Doorbells must only be used if CPU_FTR_DBELL is available.
26 * msgsnd is used in HV, and msgsndp is used in !HV.
27 *
28 * These should be used by platform code that is aware of restrictions.
29 * Other arch code should use ->cause_ipi.
30 *
31 * doorbell_global_ipi() sends a dbell to any target CPU.
32 * Must be used only by architectures that address msgsnd target
33 * by PIR/get_hard_smp_processor_id.
34 */
35void doorbell_global_ipi(int cpu)
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100036{
Nicholas Pigginb866cc22017-04-13 20:16:21 +100037 u32 tag = get_hard_smp_processor_id(cpu);
38
39 kvmppc_set_host_ipi(cpu, 1);
Paul Mackerras9fb1b362012-09-04 18:33:08 +000040 /* Order previous accesses vs. msgsnd, which is treated as a store */
Nicholas Pigginb87ac022017-04-13 20:16:22 +100041 ppc_msgsnd_sync();
Nicholas Pigginb866cc22017-04-13 20:16:21 +100042 ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
43}
44
45/*
46 * doorbell_core_ipi() sends a dbell to a target CPU in the same core.
47 * Must be used only by architectures that address msgsnd target
48 * by TIR/cpu_thread_in_core.
49 */
50void doorbell_core_ipi(int cpu)
51{
52 u32 tag = cpu_thread_in_core(cpu);
53
54 kvmppc_set_host_ipi(cpu, 1);
55 /* Order previous accesses vs. msgsnd, which is treated as a store */
Nicholas Pigginb87ac022017-04-13 20:16:22 +100056 ppc_msgsnd_sync();
Nicholas Pigginb866cc22017-04-13 20:16:21 +100057 ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
58}
59
60/*
61 * Attempt to cause a core doorbell if destination is on the same core.
62 * Returns 1 on success, 0 on failure.
63 */
64int doorbell_try_core_ipi(int cpu)
65{
66 int this_cpu = get_cpu();
67 int ret = 0;
68
69 if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) {
70 doorbell_core_ipi(cpu);
71 ret = 1;
72 }
73
74 put_cpu();
75
76 return ret;
Kumar Gala620165f2009-02-12 13:54:53 +000077}
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100078
79void doorbell_exception(struct pt_regs *regs)
80{
David Gibson0e37d252010-07-09 15:32:30 +100081 struct pt_regs *old_regs = set_irq_regs(regs);
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100082
Milton Miller23d72bf2011-05-10 19:29:39 +000083 irq_enter();
Benjamin Herrenschmidtb9f1cd72010-07-09 15:29:53 +100084
Nicholas Pigginb87ac022017-04-13 20:16:22 +100085 ppc_msgsync();
86
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +110087 may_hard_irq_enable();
88
Paul Mackerras755563b2015-03-19 19:29:01 +110089 kvmppc_set_host_ipi(smp_processor_id(), 0);
Christoph Lameter69111ba2014-10-21 15:23:25 -050090 __this_cpu_inc(irq_stat.doorbell_irqs);
Ian Munsiea6a058e2013-03-21 19:22:52 +000091
Nicholas Pigginb87ac022017-04-13 20:16:22 +100092 smp_ipi_demux_relaxed(); /* already performed the barrier */
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100093
Milton Miller23d72bf2011-05-10 19:29:39 +000094 irq_exit();
David Gibson0e37d252010-07-09 15:32:30 +100095 set_irq_regs(old_regs);
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100096}
Benjamin Herrenschmidte3145b32010-07-09 15:25:18 +100097#else /* CONFIG_SMP */
98void doorbell_exception(struct pt_regs *regs)
99{
100 printk(KERN_WARNING "Received doorbell on non-smp system\n");
101}
102#endif /* CONFIG_SMP */
103