1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
29702785aSThomas Gleixner #include <linux/smp.h>
3ae039001SAnkur Arora #include <linux/cpu.h>
483b96794SVitaly Kuznetsov #include <linux/slab.h>
583b96794SVitaly Kuznetsov #include <linux/cpumask.h>
683b96794SVitaly Kuznetsov #include <linux/percpu.h>
79702785aSThomas Gleixner
89702785aSThomas Gleixner #include <xen/events.h>
99702785aSThomas Gleixner
10ed467e69SKonrad Rzeszutek Wilk #include <xen/hvc-console.h>
119702785aSThomas Gleixner #include "xen-ops.h"
12a2ef5dc2SMukesh Rathor #include "smp.h"
139702785aSThomas Gleixner
14ee336e10SKonrad Rzeszutek Wilk static DEFINE_PER_CPU(struct xen_common_irq, xen_resched_irq) = { .irq = -1 };
15ee336e10SKonrad Rzeszutek Wilk static DEFINE_PER_CPU(struct xen_common_irq, xen_callfunc_irq) = { .irq = -1 };
16ee336e10SKonrad Rzeszutek Wilk static DEFINE_PER_CPU(struct xen_common_irq, xen_callfuncsingle_irq) = { .irq = -1 };
179547689fSKonrad Rzeszutek Wilk static DEFINE_PER_CPU(struct xen_common_irq, xen_debug_irq) = { .irq = -1 };
189702785aSThomas Gleixner
199702785aSThomas Gleixner static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
203b16cf87SJens Axboe static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
219702785aSThomas Gleixner
229702785aSThomas Gleixner /*
23184748ccSPeter Zijlstra * Reschedule call back.
249702785aSThomas Gleixner */
xen_reschedule_interrupt(int irq,void * dev_id)259702785aSThomas Gleixner static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
269702785aSThomas Gleixner {
271b437c8cSBrian Gerst inc_irq_stat(irq_resched_count);
28184748ccSPeter Zijlstra scheduler_ipi();
2938bb5ab4SJeremy Fitzhardinge
309702785aSThomas Gleixner return IRQ_HANDLED;
319702785aSThomas Gleixner }
329702785aSThomas Gleixner
xen_smp_intr_free(unsigned int cpu)335fc509bcSBoris Ostrovsky void xen_smp_intr_free(unsigned int cpu)
3453b94fdcSKonrad Rzeszutek Wilk {
3569143f60SXiu Jianfeng kfree(per_cpu(xen_resched_irq, cpu).name);
3669143f60SXiu Jianfeng per_cpu(xen_resched_irq, cpu).name = NULL;
37ee336e10SKonrad Rzeszutek Wilk if (per_cpu(xen_resched_irq, cpu).irq >= 0) {
389547689fSKonrad Rzeszutek Wilk unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
39ee336e10SKonrad Rzeszutek Wilk per_cpu(xen_resched_irq, cpu).irq = -1;
40ee336e10SKonrad Rzeszutek Wilk }
4169143f60SXiu Jianfeng kfree(per_cpu(xen_callfunc_irq, cpu).name);
4269143f60SXiu Jianfeng per_cpu(xen_callfunc_irq, cpu).name = NULL;
43ee336e10SKonrad Rzeszutek Wilk if (per_cpu(xen_callfunc_irq, cpu).irq >= 0) {
449547689fSKonrad Rzeszutek Wilk unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
45ee336e10SKonrad Rzeszutek Wilk per_cpu(xen_callfunc_irq, cpu).irq = -1;
46ee336e10SKonrad Rzeszutek Wilk }
4769143f60SXiu Jianfeng kfree(per_cpu(xen_debug_irq, cpu).name);
4869143f60SXiu Jianfeng per_cpu(xen_debug_irq, cpu).name = NULL;
49ee336e10SKonrad Rzeszutek Wilk if (per_cpu(xen_debug_irq, cpu).irq >= 0) {
509547689fSKonrad Rzeszutek Wilk unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
51ee336e10SKonrad Rzeszutek Wilk per_cpu(xen_debug_irq, cpu).irq = -1;
52ee336e10SKonrad Rzeszutek Wilk }
5369143f60SXiu Jianfeng kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
5469143f60SXiu Jianfeng per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
55ee336e10SKonrad Rzeszutek Wilk if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0) {
569547689fSKonrad Rzeszutek Wilk unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
5753b94fdcSKonrad Rzeszutek Wilk NULL);
58ee336e10SKonrad Rzeszutek Wilk per_cpu(xen_callfuncsingle_irq, cpu).irq = -1;
59ee336e10SKonrad Rzeszutek Wilk }
6004e95761SVitaly Kuznetsov }
6153b94fdcSKonrad Rzeszutek Wilk
xen_smp_intr_init(unsigned int cpu)625fc509bcSBoris Ostrovsky int xen_smp_intr_init(unsigned int cpu)
639702785aSThomas Gleixner {
649702785aSThomas Gleixner int rc;
6504e95761SVitaly Kuznetsov char *resched_name, *callfunc_name, *debug_name;
669702785aSThomas Gleixner
679702785aSThomas Gleixner resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
68*a9bbb05cSKunwu Chan if (!resched_name)
69*a9bbb05cSKunwu Chan goto fail_mem;
7069143f60SXiu Jianfeng per_cpu(xen_resched_irq, cpu).name = resched_name;
719702785aSThomas Gleixner rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
729702785aSThomas Gleixner cpu,
739702785aSThomas Gleixner xen_reschedule_interrupt,
749d71cee6SMichael Opdenacker IRQF_PERCPU|IRQF_NOBALANCING,
759702785aSThomas Gleixner resched_name,
769702785aSThomas Gleixner NULL);
779702785aSThomas Gleixner if (rc < 0)
789702785aSThomas Gleixner goto fail;
799547689fSKonrad Rzeszutek Wilk per_cpu(xen_resched_irq, cpu).irq = rc;
809702785aSThomas Gleixner
819702785aSThomas Gleixner callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
82*a9bbb05cSKunwu Chan if (!callfunc_name)
83*a9bbb05cSKunwu Chan goto fail_mem;
8469143f60SXiu Jianfeng per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
859702785aSThomas Gleixner rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
869702785aSThomas Gleixner cpu,
879702785aSThomas Gleixner xen_call_function_interrupt,
889d71cee6SMichael Opdenacker IRQF_PERCPU|IRQF_NOBALANCING,
899702785aSThomas Gleixner callfunc_name,
909702785aSThomas Gleixner NULL);
919702785aSThomas Gleixner if (rc < 0)
929702785aSThomas Gleixner goto fail;
939547689fSKonrad Rzeszutek Wilk per_cpu(xen_callfunc_irq, cpu).irq = rc;
949702785aSThomas Gleixner
95d04b1ae5SJuergen Gross if (!xen_fifo_events) {
96ee523ca1SJeremy Fitzhardinge debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
97*a9bbb05cSKunwu Chan if (!debug_name)
98*a9bbb05cSKunwu Chan goto fail_mem;
99*a9bbb05cSKunwu Chan
10069143f60SXiu Jianfeng per_cpu(xen_debug_irq, cpu).name = debug_name;
101d04b1ae5SJuergen Gross rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu,
102d04b1ae5SJuergen Gross xen_debug_interrupt,
1039d71cee6SMichael Opdenacker IRQF_PERCPU | IRQF_NOBALANCING,
104ee523ca1SJeremy Fitzhardinge debug_name, NULL);
105ee523ca1SJeremy Fitzhardinge if (rc < 0)
106ee523ca1SJeremy Fitzhardinge goto fail;
1079547689fSKonrad Rzeszutek Wilk per_cpu(xen_debug_irq, cpu).irq = rc;
108d04b1ae5SJuergen Gross }
109ee523ca1SJeremy Fitzhardinge
1103b16cf87SJens Axboe callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
111*a9bbb05cSKunwu Chan if (!callfunc_name)
112*a9bbb05cSKunwu Chan goto fail_mem;
113*a9bbb05cSKunwu Chan
11469143f60SXiu Jianfeng per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
1153b16cf87SJens Axboe rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
1163b16cf87SJens Axboe cpu,
1173b16cf87SJens Axboe xen_call_function_single_interrupt,
1189d71cee6SMichael Opdenacker IRQF_PERCPU|IRQF_NOBALANCING,
1193b16cf87SJens Axboe callfunc_name,
1203b16cf87SJens Axboe NULL);
1213b16cf87SJens Axboe if (rc < 0)
1223b16cf87SJens Axboe goto fail;
1239547689fSKonrad Rzeszutek Wilk per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
1243b16cf87SJens Axboe
12527d8b207SKonrad Rzeszutek Wilk return 0;
12627d8b207SKonrad Rzeszutek Wilk
127*a9bbb05cSKunwu Chan fail_mem:
128*a9bbb05cSKunwu Chan rc = -ENOMEM;
12904e95761SVitaly Kuznetsov fail:
13004e95761SVitaly Kuznetsov xen_smp_intr_free(cpu);
13104e95761SVitaly Kuznetsov return rc;
13204e95761SVitaly Kuznetsov }
13304e95761SVitaly Kuznetsov
xen_smp_cpus_done(unsigned int max_cpus)134ae039001SAnkur Arora void __init xen_smp_cpus_done(unsigned int max_cpus)
135ae039001SAnkur Arora {
136ae039001SAnkur Arora if (xen_hvm_domain())
137ae039001SAnkur Arora native_smp_cpus_done(max_cpus);
13863e708f8SPrarit Bhargava else
13963e708f8SPrarit Bhargava calculate_max_logical_packages();
140ae039001SAnkur Arora }
141ae039001SAnkur Arora
xen_smp_send_reschedule(int cpu)142a52482d9SVitaly Kuznetsov void xen_smp_send_reschedule(int cpu)
1439702785aSThomas Gleixner {
1449702785aSThomas Gleixner xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
1459702785aSThomas Gleixner }
1469702785aSThomas Gleixner
__xen_send_IPI_mask(const struct cpumask * mask,int vector)147f447d56dSBen Guthro static void __xen_send_IPI_mask(const struct cpumask *mask,
148f447d56dSBen Guthro int vector)
1499702785aSThomas Gleixner {
1509702785aSThomas Gleixner unsigned cpu;
1519702785aSThomas Gleixner
152bcda016eSMike Travis for_each_cpu_and(cpu, mask, cpu_online_mask)
1539702785aSThomas Gleixner xen_send_IPI_one(cpu, vector);
1549702785aSThomas Gleixner }
1559702785aSThomas Gleixner
xen_smp_send_call_function_ipi(const struct cpumask * mask)156a52482d9SVitaly Kuznetsov void xen_smp_send_call_function_ipi(const struct cpumask *mask)
1573b16cf87SJens Axboe {
1583b16cf87SJens Axboe int cpu;
1593b16cf87SJens Axboe
160f447d56dSBen Guthro __xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
1613b16cf87SJens Axboe
1623b16cf87SJens Axboe /* Make sure other vcpus get a chance to run if they need to. */
163bcda016eSMike Travis for_each_cpu(cpu, mask) {
1643b16cf87SJens Axboe if (xen_vcpu_stolen(cpu)) {
1651207cf8eSHannes Eder HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
1663b16cf87SJens Axboe break;
1673b16cf87SJens Axboe }
1683b16cf87SJens Axboe }
1693b16cf87SJens Axboe }
1703b16cf87SJens Axboe
xen_smp_send_call_function_single_ipi(int cpu)171a52482d9SVitaly Kuznetsov void xen_smp_send_call_function_single_ipi(int cpu)
1723b16cf87SJens Axboe {
173f447d56dSBen Guthro __xen_send_IPI_mask(cpumask_of(cpu),
174e7986739SMike Travis XEN_CALL_FUNCTION_SINGLE_VECTOR);
1753b16cf87SJens Axboe }
1763b16cf87SJens Axboe
xen_map_vector(int vector)177f447d56dSBen Guthro static inline int xen_map_vector(int vector)
178f447d56dSBen Guthro {
179f447d56dSBen Guthro int xen_vector;
180f447d56dSBen Guthro
181f447d56dSBen Guthro switch (vector) {
182f447d56dSBen Guthro case RESCHEDULE_VECTOR:
183f447d56dSBen Guthro xen_vector = XEN_RESCHEDULE_VECTOR;
184f447d56dSBen Guthro break;
185f447d56dSBen Guthro case CALL_FUNCTION_VECTOR:
186f447d56dSBen Guthro xen_vector = XEN_CALL_FUNCTION_VECTOR;
187f447d56dSBen Guthro break;
188f447d56dSBen Guthro case CALL_FUNCTION_SINGLE_VECTOR:
189f447d56dSBen Guthro xen_vector = XEN_CALL_FUNCTION_SINGLE_VECTOR;
190f447d56dSBen Guthro break;
1911ff2b0c3SLin Ming case IRQ_WORK_VECTOR:
1921ff2b0c3SLin Ming xen_vector = XEN_IRQ_WORK_VECTOR;
1931ff2b0c3SLin Ming break;
1946efa20e4SKonrad Rzeszutek Wilk #ifdef CONFIG_X86_64
1956efa20e4SKonrad Rzeszutek Wilk case NMI_VECTOR:
1966efa20e4SKonrad Rzeszutek Wilk case APIC_DM_NMI: /* Some use that instead of NMI_VECTOR */
1976efa20e4SKonrad Rzeszutek Wilk xen_vector = XEN_NMI_VECTOR;
1986efa20e4SKonrad Rzeszutek Wilk break;
1996efa20e4SKonrad Rzeszutek Wilk #endif
200f447d56dSBen Guthro default:
201f447d56dSBen Guthro xen_vector = -1;
202f447d56dSBen Guthro printk(KERN_ERR "xen: vector 0x%x is not implemented\n",
203f447d56dSBen Guthro vector);
204f447d56dSBen Guthro }
205f447d56dSBen Guthro
206f447d56dSBen Guthro return xen_vector;
207f447d56dSBen Guthro }
208f447d56dSBen Guthro
xen_send_IPI_mask(const struct cpumask * mask,int vector)209f447d56dSBen Guthro void xen_send_IPI_mask(const struct cpumask *mask,
210f447d56dSBen Guthro int vector)
211f447d56dSBen Guthro {
212f447d56dSBen Guthro int xen_vector = xen_map_vector(vector);
213f447d56dSBen Guthro
214f447d56dSBen Guthro if (xen_vector >= 0)
215f447d56dSBen Guthro __xen_send_IPI_mask(mask, xen_vector);
216f447d56dSBen Guthro }
217f447d56dSBen Guthro
xen_send_IPI_all(int vector)218f447d56dSBen Guthro void xen_send_IPI_all(int vector)
219f447d56dSBen Guthro {
220f447d56dSBen Guthro int xen_vector = xen_map_vector(vector);
221f447d56dSBen Guthro
222f447d56dSBen Guthro if (xen_vector >= 0)
223f447d56dSBen Guthro __xen_send_IPI_mask(cpu_online_mask, xen_vector);
224f447d56dSBen Guthro }
225f447d56dSBen Guthro
xen_send_IPI_self(int vector)226f447d56dSBen Guthro void xen_send_IPI_self(int vector)
227f447d56dSBen Guthro {
228f447d56dSBen Guthro int xen_vector = xen_map_vector(vector);
229f447d56dSBen Guthro
230f447d56dSBen Guthro if (xen_vector >= 0)
231f447d56dSBen Guthro xen_send_IPI_one(smp_processor_id(), xen_vector);
232f447d56dSBen Guthro }
233f447d56dSBen Guthro
xen_send_IPI_mask_allbutself(const struct cpumask * mask,int vector)234f447d56dSBen Guthro void xen_send_IPI_mask_allbutself(const struct cpumask *mask,
235f447d56dSBen Guthro int vector)
236f447d56dSBen Guthro {
237f447d56dSBen Guthro unsigned cpu;
238f447d56dSBen Guthro unsigned int this_cpu = smp_processor_id();
2391db01b49SStefan Bader int xen_vector = xen_map_vector(vector);
240f447d56dSBen Guthro
2411db01b49SStefan Bader if (!(num_online_cpus() > 1) || (xen_vector < 0))
242f447d56dSBen Guthro return;
243f447d56dSBen Guthro
244f447d56dSBen Guthro for_each_cpu_and(cpu, mask, cpu_online_mask) {
245f447d56dSBen Guthro if (this_cpu == cpu)
246f447d56dSBen Guthro continue;
247f447d56dSBen Guthro
2481db01b49SStefan Bader xen_send_IPI_one(cpu, xen_vector);
249f447d56dSBen Guthro }
250f447d56dSBen Guthro }
251f447d56dSBen Guthro
xen_send_IPI_allbutself(int vector)252f447d56dSBen Guthro void xen_send_IPI_allbutself(int vector)
253f447d56dSBen Guthro {
2541db01b49SStefan Bader xen_send_IPI_mask_allbutself(cpu_online_mask, vector);
255f447d56dSBen Guthro }
256f447d56dSBen Guthro
xen_call_function_interrupt(int irq,void * dev_id)2579702785aSThomas Gleixner static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
2589702785aSThomas Gleixner {
2593b16cf87SJens Axboe generic_smp_call_function_interrupt();
2601b437c8cSBrian Gerst inc_irq_stat(irq_call_count);
2619702785aSThomas Gleixner
2629702785aSThomas Gleixner return IRQ_HANDLED;
2639702785aSThomas Gleixner }
2649702785aSThomas Gleixner
xen_call_function_single_interrupt(int irq,void * dev_id)2653b16cf87SJens Axboe static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
2669702785aSThomas Gleixner {
2673b16cf87SJens Axboe generic_smp_call_function_single_interrupt();
2681b437c8cSBrian Gerst inc_irq_stat(irq_call_count);
2699702785aSThomas Gleixner
2703b16cf87SJens Axboe return IRQ_HANDLED;
2719702785aSThomas Gleixner }
272