xref: /kernel/linux/linux-6.6/arch/x86/xen/irq.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/hardirq.h>
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <asm/x86_init.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <xen/interface/xen.h>
762306a36Sopenharmony_ci#include <xen/interface/sched.h>
862306a36Sopenharmony_ci#include <xen/interface/vcpu.h>
962306a36Sopenharmony_ci#include <xen/features.h>
1062306a36Sopenharmony_ci#include <xen/events.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <asm/xen/hypercall.h>
1362306a36Sopenharmony_ci#include <asm/xen/hypervisor.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "xen-ops.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Force a proper event-channel callback from Xen after clearing the
1962306a36Sopenharmony_ci * callback mask. We do this in a very simple manner, by making a call
2062306a36Sopenharmony_ci * down into Xen. The pending flag will be checked by Xen on return.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_cinoinstr void xen_force_evtchn_callback(void)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	(void)HYPERVISOR_xen_version(0, NULL);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic noinstr void xen_safe_halt(void)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	/* Blocking includes an implicit local_irq_enable(). */
3062306a36Sopenharmony_ci	if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
3162306a36Sopenharmony_ci		BUG();
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void xen_halt(void)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	if (irqs_disabled())
3762306a36Sopenharmony_ci		HYPERVISOR_vcpu_op(VCPUOP_down,
3862306a36Sopenharmony_ci				   xen_vcpu_nr(smp_processor_id()), NULL);
3962306a36Sopenharmony_ci	else
4062306a36Sopenharmony_ci		xen_safe_halt();
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic const typeof(pv_ops) xen_irq_ops __initconst = {
4462306a36Sopenharmony_ci	.irq = {
4562306a36Sopenharmony_ci		/* Initial interrupt flag handling only called while interrupts off. */
4662306a36Sopenharmony_ci		.save_fl = __PV_IS_CALLEE_SAVE(paravirt_ret0),
4762306a36Sopenharmony_ci		.irq_disable = __PV_IS_CALLEE_SAVE(paravirt_nop),
4862306a36Sopenharmony_ci		.irq_enable = __PV_IS_CALLEE_SAVE(paravirt_BUG),
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci		.safe_halt = xen_safe_halt,
5162306a36Sopenharmony_ci		.halt = xen_halt,
5262306a36Sopenharmony_ci	},
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_civoid __init xen_init_irq_ops(void)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	pv_ops.irq = xen_irq_ops.irq;
5862306a36Sopenharmony_ci	x86_init.irqs.intr_init = xen_init_IRQ;
5962306a36Sopenharmony_ci}
60