mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 08:28:13 +00:00
12ad6cfc09
The flag xen_have_vcpu_info_placement was needed to support Xen hypervisors older than version 3.4, which didn't support the VCPUOP_register_vcpu_info hypercall. Today the Linux kernel requires at least Xen 4.0 to be able to run, so xen_have_vcpu_info_placement can be dropped (in theory the flag was used to ensure a working kernel even in case of the VCPUOP_register_vcpu_info hypercall failing for other reasons than the hypercall not being supported, but the only cases covered by the flag would be parameter errors, which ought not to be made anyway). This allows to let some functions return void now, as they can never fail. Signed-off-by: Juergen Gross <jgross@suse.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Link: https://lore.kernel.org/r/20211028072748.29862-2-jgross@suse.com Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
259 lines
6.3 KiB
C
259 lines
6.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/smp.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/percpu.h>
|
|
|
|
#include <xen/events.h>
|
|
|
|
#include <xen/hvc-console.h>
|
|
#include "xen-ops.h"
|
|
#include "smp.h"
|
|
|
|
static DEFINE_PER_CPU(struct xen_common_irq, xen_resched_irq) = { .irq = -1 };
|
|
static DEFINE_PER_CPU(struct xen_common_irq, xen_callfunc_irq) = { .irq = -1 };
|
|
static DEFINE_PER_CPU(struct xen_common_irq, xen_callfuncsingle_irq) = { .irq = -1 };
|
|
static DEFINE_PER_CPU(struct xen_common_irq, xen_debug_irq) = { .irq = -1 };
|
|
|
|
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
|
|
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
|
|
|
|
/*
|
|
* Reschedule call back.
|
|
*/
|
|
static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
|
|
{
|
|
inc_irq_stat(irq_resched_count);
|
|
scheduler_ipi();
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
void xen_smp_intr_free(unsigned int cpu)
|
|
{
|
|
if (per_cpu(xen_resched_irq, cpu).irq >= 0) {
|
|
unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
|
|
per_cpu(xen_resched_irq, cpu).irq = -1;
|
|
kfree(per_cpu(xen_resched_irq, cpu).name);
|
|
per_cpu(xen_resched_irq, cpu).name = NULL;
|
|
}
|
|
if (per_cpu(xen_callfunc_irq, cpu).irq >= 0) {
|
|
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
|
|
per_cpu(xen_callfunc_irq, cpu).irq = -1;
|
|
kfree(per_cpu(xen_callfunc_irq, cpu).name);
|
|
per_cpu(xen_callfunc_irq, cpu).name = NULL;
|
|
}
|
|
if (per_cpu(xen_debug_irq, cpu).irq >= 0) {
|
|
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
|
|
per_cpu(xen_debug_irq, cpu).irq = -1;
|
|
kfree(per_cpu(xen_debug_irq, cpu).name);
|
|
per_cpu(xen_debug_irq, cpu).name = NULL;
|
|
}
|
|
if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0) {
|
|
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
|
|
NULL);
|
|
per_cpu(xen_callfuncsingle_irq, cpu).irq = -1;
|
|
kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
|
|
per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
|
|
}
|
|
}
|
|
|
|
int xen_smp_intr_init(unsigned int cpu)
|
|
{
|
|
int rc;
|
|
char *resched_name, *callfunc_name, *debug_name;
|
|
|
|
resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
|
|
rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
|
|
cpu,
|
|
xen_reschedule_interrupt,
|
|
IRQF_PERCPU|IRQF_NOBALANCING,
|
|
resched_name,
|
|
NULL);
|
|
if (rc < 0)
|
|
goto fail;
|
|
per_cpu(xen_resched_irq, cpu).irq = rc;
|
|
per_cpu(xen_resched_irq, cpu).name = resched_name;
|
|
|
|
callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
|
|
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
|
|
cpu,
|
|
xen_call_function_interrupt,
|
|
IRQF_PERCPU|IRQF_NOBALANCING,
|
|
callfunc_name,
|
|
NULL);
|
|
if (rc < 0)
|
|
goto fail;
|
|
per_cpu(xen_callfunc_irq, cpu).irq = rc;
|
|
per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
|
|
|
|
if (!xen_fifo_events) {
|
|
debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
|
|
rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu,
|
|
xen_debug_interrupt,
|
|
IRQF_PERCPU | IRQF_NOBALANCING,
|
|
debug_name, NULL);
|
|
if (rc < 0)
|
|
goto fail;
|
|
per_cpu(xen_debug_irq, cpu).irq = rc;
|
|
per_cpu(xen_debug_irq, cpu).name = debug_name;
|
|
}
|
|
|
|
callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
|
|
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
|
|
cpu,
|
|
xen_call_function_single_interrupt,
|
|
IRQF_PERCPU|IRQF_NOBALANCING,
|
|
callfunc_name,
|
|
NULL);
|
|
if (rc < 0)
|
|
goto fail;
|
|
per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
|
|
per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
xen_smp_intr_free(cpu);
|
|
return rc;
|
|
}
|
|
|
|
void __init xen_smp_cpus_done(unsigned int max_cpus)
|
|
{
|
|
if (xen_hvm_domain())
|
|
native_smp_cpus_done(max_cpus);
|
|
else
|
|
calculate_max_logical_packages();
|
|
}
|
|
|
|
void xen_smp_send_reschedule(int cpu)
|
|
{
|
|
xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
|
|
}
|
|
|
|
static void __xen_send_IPI_mask(const struct cpumask *mask,
|
|
int vector)
|
|
{
|
|
unsigned cpu;
|
|
|
|
for_each_cpu_and(cpu, mask, cpu_online_mask)
|
|
xen_send_IPI_one(cpu, vector);
|
|
}
|
|
|
|
void xen_smp_send_call_function_ipi(const struct cpumask *mask)
|
|
{
|
|
int cpu;
|
|
|
|
__xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
|
|
|
|
/* Make sure other vcpus get a chance to run if they need to. */
|
|
for_each_cpu(cpu, mask) {
|
|
if (xen_vcpu_stolen(cpu)) {
|
|
HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void xen_smp_send_call_function_single_ipi(int cpu)
|
|
{
|
|
__xen_send_IPI_mask(cpumask_of(cpu),
|
|
XEN_CALL_FUNCTION_SINGLE_VECTOR);
|
|
}
|
|
|
|
static inline int xen_map_vector(int vector)
|
|
{
|
|
int xen_vector;
|
|
|
|
switch (vector) {
|
|
case RESCHEDULE_VECTOR:
|
|
xen_vector = XEN_RESCHEDULE_VECTOR;
|
|
break;
|
|
case CALL_FUNCTION_VECTOR:
|
|
xen_vector = XEN_CALL_FUNCTION_VECTOR;
|
|
break;
|
|
case CALL_FUNCTION_SINGLE_VECTOR:
|
|
xen_vector = XEN_CALL_FUNCTION_SINGLE_VECTOR;
|
|
break;
|
|
case IRQ_WORK_VECTOR:
|
|
xen_vector = XEN_IRQ_WORK_VECTOR;
|
|
break;
|
|
#ifdef CONFIG_X86_64
|
|
case NMI_VECTOR:
|
|
case APIC_DM_NMI: /* Some use that instead of NMI_VECTOR */
|
|
xen_vector = XEN_NMI_VECTOR;
|
|
break;
|
|
#endif
|
|
default:
|
|
xen_vector = -1;
|
|
printk(KERN_ERR "xen: vector 0x%x is not implemented\n",
|
|
vector);
|
|
}
|
|
|
|
return xen_vector;
|
|
}
|
|
|
|
void xen_send_IPI_mask(const struct cpumask *mask,
|
|
int vector)
|
|
{
|
|
int xen_vector = xen_map_vector(vector);
|
|
|
|
if (xen_vector >= 0)
|
|
__xen_send_IPI_mask(mask, xen_vector);
|
|
}
|
|
|
|
void xen_send_IPI_all(int vector)
|
|
{
|
|
int xen_vector = xen_map_vector(vector);
|
|
|
|
if (xen_vector >= 0)
|
|
__xen_send_IPI_mask(cpu_online_mask, xen_vector);
|
|
}
|
|
|
|
void xen_send_IPI_self(int vector)
|
|
{
|
|
int xen_vector = xen_map_vector(vector);
|
|
|
|
if (xen_vector >= 0)
|
|
xen_send_IPI_one(smp_processor_id(), xen_vector);
|
|
}
|
|
|
|
void xen_send_IPI_mask_allbutself(const struct cpumask *mask,
|
|
int vector)
|
|
{
|
|
unsigned cpu;
|
|
unsigned int this_cpu = smp_processor_id();
|
|
int xen_vector = xen_map_vector(vector);
|
|
|
|
if (!(num_online_cpus() > 1) || (xen_vector < 0))
|
|
return;
|
|
|
|
for_each_cpu_and(cpu, mask, cpu_online_mask) {
|
|
if (this_cpu == cpu)
|
|
continue;
|
|
|
|
xen_send_IPI_one(cpu, xen_vector);
|
|
}
|
|
}
|
|
|
|
void xen_send_IPI_allbutself(int vector)
|
|
{
|
|
xen_send_IPI_mask_allbutself(cpu_online_mask, vector);
|
|
}
|
|
|
|
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
|
|
{
|
|
generic_smp_call_function_interrupt();
|
|
inc_irq_stat(irq_call_count);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
|
|
{
|
|
generic_smp_call_function_single_interrupt();
|
|
inc_irq_stat(irq_call_count);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|