xref: /freebsd/sys/x86/xen/xen_apic.c (revision f0cf86c0)
124f7e474SRoger Pau Monné /*
224f7e474SRoger Pau Monné  * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com>
324f7e474SRoger Pau Monné  * All rights reserved.
424f7e474SRoger Pau Monné  *
524f7e474SRoger Pau Monné  * Redistribution and use in source and binary forms, with or without
624f7e474SRoger Pau Monné  * modification, are permitted provided that the following conditions
724f7e474SRoger Pau Monné  * are met:
824f7e474SRoger Pau Monné  * 1. Redistributions of source code must retain the above copyright
924f7e474SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer.
1024f7e474SRoger Pau Monné  * 2. Redistributions in binary form must reproduce the above copyright
1124f7e474SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer in the
1224f7e474SRoger Pau Monné  *    documentation and/or other materials provided with the distribution.
1324f7e474SRoger Pau Monné  *
1424f7e474SRoger Pau Monné  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
1524f7e474SRoger Pau Monné  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1624f7e474SRoger Pau Monné  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1724f7e474SRoger Pau Monné  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1824f7e474SRoger Pau Monné  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1924f7e474SRoger Pau Monné  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2024f7e474SRoger Pau Monné  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2124f7e474SRoger Pau Monné  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2224f7e474SRoger Pau Monné  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2324f7e474SRoger Pau Monné  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2424f7e474SRoger Pau Monné  * SUCH DAMAGE.
2524f7e474SRoger Pau Monné  */
2624f7e474SRoger Pau Monné 
2724f7e474SRoger Pau Monné #include <sys/param.h>
2824f7e474SRoger Pau Monné #include <sys/bus.h>
2924f7e474SRoger Pau Monné #include <sys/kernel.h>
3024f7e474SRoger Pau Monné #include <sys/malloc.h>
3124f7e474SRoger Pau Monné #include <sys/proc.h>
3224f7e474SRoger Pau Monné #include <sys/smp.h>
3324f7e474SRoger Pau Monné #include <sys/systm.h>
3424f7e474SRoger Pau Monné 
3524f7e474SRoger Pau Monné #include <vm/vm.h>
3624f7e474SRoger Pau Monné #include <vm/pmap.h>
3724f7e474SRoger Pau Monné 
3824f7e474SRoger Pau Monné #include <machine/cpufunc.h>
3924f7e474SRoger Pau Monné #include <machine/cpu.h>
40fae92773SJohn Baldwin #include <machine/intr_machdep.h>
4145c228ccSKonstantin Belousov #include <machine/md_var.h>
4224f7e474SRoger Pau Monné #include <machine/smp.h>
4324f7e474SRoger Pau Monné 
4424f7e474SRoger Pau Monné #include <x86/apicreg.h>
45fae92773SJohn Baldwin #include <x86/apicvar.h>
4624f7e474SRoger Pau Monné 
4724f7e474SRoger Pau Monné #include <xen/xen-os.h>
4824f7e474SRoger Pau Monné #include <xen/features.h>
4924f7e474SRoger Pau Monné #include <xen/gnttab.h>
5024f7e474SRoger Pau Monné #include <xen/hypervisor.h>
5124f7e474SRoger Pau Monné #include <xen/hvm.h>
5224f7e474SRoger Pau Monné #include <xen/xen_intr.h>
5324f7e474SRoger Pau Monné 
54ad7dd514SElliott Mitchell #include <contrib/xen/arch-x86/cpuid.h>
55ad7dd514SElliott Mitchell #include <contrib/xen/vcpu.h>
5624f7e474SRoger Pau Monné 
5724f7e474SRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/
5824f7e474SRoger Pau Monné static driver_filter_t xen_smp_rendezvous_action;
59dc43978aSKonstantin Belousov #ifdef __amd64__
60dc43978aSKonstantin Belousov static driver_filter_t xen_invlop;
61dc43978aSKonstantin Belousov #else
6224f7e474SRoger Pau Monné static driver_filter_t xen_invltlb;
6324f7e474SRoger Pau Monné static driver_filter_t xen_invlpg;
6424f7e474SRoger Pau Monné static driver_filter_t xen_invlrng;
6524f7e474SRoger Pau Monné static driver_filter_t xen_invlcache;
66dc43978aSKonstantin Belousov #endif
6724f7e474SRoger Pau Monné static driver_filter_t xen_ipi_bitmap_handler;
6824f7e474SRoger Pau Monné static driver_filter_t xen_cpustop_handler;
6924f7e474SRoger Pau Monné static driver_filter_t xen_cpususpend_handler;
70aba10e13SAlexander Motin static driver_filter_t xen_ipi_swi_handler;
7124f7e474SRoger Pau Monné 
7224f7e474SRoger Pau Monné /*---------------------------------- Macros ----------------------------------*/
7324f7e474SRoger Pau Monné #define	IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
7424f7e474SRoger Pau Monné 
7524f7e474SRoger Pau Monné /*--------------------------------- Xen IPIs ---------------------------------*/
7624f7e474SRoger Pau Monné struct xen_ipi_handler
7724f7e474SRoger Pau Monné {
7824f7e474SRoger Pau Monné 	driver_filter_t	*filter;
7924f7e474SRoger Pau Monné 	const char	*description;
8024f7e474SRoger Pau Monné };
8124f7e474SRoger Pau Monné 
8224f7e474SRoger Pau Monné static struct xen_ipi_handler xen_ipis[] =
8324f7e474SRoger Pau Monné {
8424f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_RENDEZVOUS)]	= { xen_smp_rendezvous_action,	"r"   },
85dc43978aSKonstantin Belousov #ifdef __amd64__
86dc43978aSKonstantin Belousov 	[IPI_TO_IDX(IPI_INVLOP)]	= { xen_invlop,			"itlb"},
87dc43978aSKonstantin Belousov #else
8824f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLTLB)]	= { xen_invltlb,		"itlb"},
8924f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLPG)]	= { xen_invlpg,			"ipg" },
9024f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLRNG)]	= { xen_invlrng,		"irg" },
9124f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLCACHE)]	= { xen_invlcache,		"ic"  },
92dc43978aSKonstantin Belousov #endif
9324f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler,	"b"   },
9424f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_STOP)]		= { xen_cpustop_handler,	"st"  },
9524f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_SUSPEND)]	= { xen_cpususpend_handler,	"sp"  },
96aba10e13SAlexander Motin 	[IPI_TO_IDX(IPI_SWI)]		= { xen_ipi_swi_handler,	"sw"  },
9724f7e474SRoger Pau Monné };
9824f7e474SRoger Pau Monné 
99ad15eeeaSRoger Pau Monné /*
100ad15eeeaSRoger Pau Monné  * Save previous (native) handler as a fallback. Xen < 4.7 doesn't support
101ad15eeeaSRoger Pau Monné  * VCPUOP_send_nmi for HVM guests, and thus we need a fallback in that case:
102ad15eeeaSRoger Pau Monné  *
103ad15eeeaSRoger Pau Monné  * https://lists.freebsd.org/archives/freebsd-xen/2022-January/000032.html
104ad15eeeaSRoger Pau Monné  */
105ad15eeeaSRoger Pau Monné void (*native_ipi_vectored)(u_int, int);
106ad15eeeaSRoger Pau Monné 
10724f7e474SRoger Pau Monné /*------------------------------- Per-CPU Data -------------------------------*/
10824f7e474SRoger Pau Monné DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
10924f7e474SRoger Pau Monné 
11024f7e474SRoger Pau Monné /*------------------------------- Xen PV APIC --------------------------------*/
11124f7e474SRoger Pau Monné 
112b2802351SRoger Pau Monné #define PCPU_ID_GET(id, field) (pcpu_find(id)->pc_##field)
113ad15eeeaSRoger Pau Monné static int
send_nmi(int dest)114b2802351SRoger Pau Monné send_nmi(int dest)
115b2802351SRoger Pau Monné {
116b2802351SRoger Pau Monné 	unsigned int cpu;
117ad15eeeaSRoger Pau Monné 	int rc = 0;
118b2802351SRoger Pau Monné 
119b2802351SRoger Pau Monné 	/*
120b2802351SRoger Pau Monné 	 * NMIs are not routed over event channels, and instead delivered as on
121b2802351SRoger Pau Monné 	 * native using the exception vector (#2). Triggering them can be done
122b2802351SRoger Pau Monné 	 * using the local APIC, or an hypercall as a shortcut like it's done
123b2802351SRoger Pau Monné 	 * below.
124b2802351SRoger Pau Monné 	 */
125b2802351SRoger Pau Monné 	switch(dest) {
126b2802351SRoger Pau Monné 	case APIC_IPI_DEST_SELF:
127ad15eeeaSRoger Pau Monné 		rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi, PCPU_GET(vcpu_id), NULL);
128b2802351SRoger Pau Monné 		break;
129b2802351SRoger Pau Monné 	case APIC_IPI_DEST_ALL:
130ad15eeeaSRoger Pau Monné 		CPU_FOREACH(cpu) {
131ad15eeeaSRoger Pau Monné 			rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
132b2802351SRoger Pau Monné 			    PCPU_ID_GET(cpu, vcpu_id), NULL);
133ad15eeeaSRoger Pau Monné 			if (rc != 0)
134ad15eeeaSRoger Pau Monné 				break;
135ad15eeeaSRoger Pau Monné 		}
136b2802351SRoger Pau Monné 		break;
137b2802351SRoger Pau Monné 	case APIC_IPI_DEST_OTHERS:
138ad15eeeaSRoger Pau Monné 		CPU_FOREACH(cpu) {
139ad15eeeaSRoger Pau Monné 			if (cpu != PCPU_GET(cpuid)) {
140ad15eeeaSRoger Pau Monné 				rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
141b2802351SRoger Pau Monné 				    PCPU_ID_GET(cpu, vcpu_id), NULL);
142ad15eeeaSRoger Pau Monné 				if (rc != 0)
143ad15eeeaSRoger Pau Monné 					break;
144ad15eeeaSRoger Pau Monné 			}
145ad15eeeaSRoger Pau Monné 		}
146b2802351SRoger Pau Monné 		break;
147b2802351SRoger Pau Monné 	default:
148ad15eeeaSRoger Pau Monné 		rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
149b2802351SRoger Pau Monné 		    PCPU_ID_GET(apic_cpuid(dest), vcpu_id), NULL);
150b2802351SRoger Pau Monné 		break;
151b2802351SRoger Pau Monné 	}
152ad15eeeaSRoger Pau Monné 
153ad15eeeaSRoger Pau Monné 	return rc;
154b2802351SRoger Pau Monné }
155b2802351SRoger Pau Monné #undef PCPU_ID_GET
156b2802351SRoger Pau Monné 
15724f7e474SRoger Pau Monné static void
xen_pv_lapic_ipi_vectored(u_int vector,int dest)15824f7e474SRoger Pau Monné xen_pv_lapic_ipi_vectored(u_int vector, int dest)
15924f7e474SRoger Pau Monné {
16024f7e474SRoger Pau Monné 	xen_intr_handle_t *ipi_handle;
16124f7e474SRoger Pau Monné 	int ipi_idx, to_cpu, self;
162ad15eeeaSRoger Pau Monné 	static bool pvnmi = true;
16324f7e474SRoger Pau Monné 
164b2802351SRoger Pau Monné 	if (vector >= IPI_NMI_FIRST) {
165ad15eeeaSRoger Pau Monné 		if (pvnmi) {
166ad15eeeaSRoger Pau Monné 			int rc = send_nmi(dest);
167ad15eeeaSRoger Pau Monné 
168ad15eeeaSRoger Pau Monné 			if (rc != 0) {
169ad15eeeaSRoger Pau Monné 				printf(
170ad15eeeaSRoger Pau Monné     "Sending NMI using hypercall failed (%d) switching to APIC\n", rc);
171ad15eeeaSRoger Pau Monné 				pvnmi = false;
172ad15eeeaSRoger Pau Monné 				native_ipi_vectored(vector, dest);
173ad15eeeaSRoger Pau Monné 			}
174ad15eeeaSRoger Pau Monné 		} else
175ad15eeeaSRoger Pau Monné 			native_ipi_vectored(vector, dest);
176ad15eeeaSRoger Pau Monné 
177b2802351SRoger Pau Monné 		return;
178b2802351SRoger Pau Monné 	}
179b2802351SRoger Pau Monné 
18024f7e474SRoger Pau Monné 	ipi_idx = IPI_TO_IDX(vector);
1818114c8e1SRoger Pau Monné 	if (ipi_idx >= nitems(xen_ipis))
18224f7e474SRoger Pau Monné 		panic("IPI out of range");
18324f7e474SRoger Pau Monné 
18424f7e474SRoger Pau Monné 	switch(dest) {
18524f7e474SRoger Pau Monné 	case APIC_IPI_DEST_SELF:
18624f7e474SRoger Pau Monné 		ipi_handle = DPCPU_GET(ipi_handle);
18724f7e474SRoger Pau Monné 		xen_intr_signal(ipi_handle[ipi_idx]);
18824f7e474SRoger Pau Monné 		break;
18924f7e474SRoger Pau Monné 	case APIC_IPI_DEST_ALL:
19024f7e474SRoger Pau Monné 		CPU_FOREACH(to_cpu) {
19124f7e474SRoger Pau Monné 			ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
19224f7e474SRoger Pau Monné 			xen_intr_signal(ipi_handle[ipi_idx]);
19324f7e474SRoger Pau Monné 		}
19424f7e474SRoger Pau Monné 		break;
19524f7e474SRoger Pau Monné 	case APIC_IPI_DEST_OTHERS:
19624f7e474SRoger Pau Monné 		self = PCPU_GET(cpuid);
19724f7e474SRoger Pau Monné 		CPU_FOREACH(to_cpu) {
19824f7e474SRoger Pau Monné 			if (to_cpu != self) {
19924f7e474SRoger Pau Monné 				ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
20024f7e474SRoger Pau Monné 				xen_intr_signal(ipi_handle[ipi_idx]);
20124f7e474SRoger Pau Monné 			}
20224f7e474SRoger Pau Monné 		}
20324f7e474SRoger Pau Monné 		break;
20424f7e474SRoger Pau Monné 	default:
20524f7e474SRoger Pau Monné 		to_cpu = apic_cpuid(dest);
20624f7e474SRoger Pau Monné 		ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
20724f7e474SRoger Pau Monné 		xen_intr_signal(ipi_handle[ipi_idx]);
20824f7e474SRoger Pau Monné 		break;
20924f7e474SRoger Pau Monné 	}
21024f7e474SRoger Pau Monné }
21124f7e474SRoger Pau Monné 
21224f7e474SRoger Pau Monné /*---------------------------- XEN PV IPI Handlers ---------------------------*/
21324f7e474SRoger Pau Monné /*
21424f7e474SRoger Pau Monné  * These are C clones of the ASM functions found in apic_vector.
21524f7e474SRoger Pau Monné  */
21624f7e474SRoger Pau Monné static int
xen_ipi_bitmap_handler(void * arg)21724f7e474SRoger Pau Monné xen_ipi_bitmap_handler(void *arg)
21824f7e474SRoger Pau Monné {
21924f7e474SRoger Pau Monné 
22054a0b720SElliott Mitchell 	ipi_bitmap_handler(*curthread->td_intr_frame);
22124f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
22224f7e474SRoger Pau Monné }
22324f7e474SRoger Pau Monné 
22424f7e474SRoger Pau Monné static int
xen_smp_rendezvous_action(void * arg)22524f7e474SRoger Pau Monné xen_smp_rendezvous_action(void *arg)
22624f7e474SRoger Pau Monné {
22724f7e474SRoger Pau Monné #ifdef COUNT_IPIS
22824f7e474SRoger Pau Monné 	(*ipi_rendezvous_counts[PCPU_GET(cpuid)])++;
22924f7e474SRoger Pau Monné #endif /* COUNT_IPIS */
23024f7e474SRoger Pau Monné 
23124f7e474SRoger Pau Monné 	smp_rendezvous_action();
23224f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
23324f7e474SRoger Pau Monné }
23424f7e474SRoger Pau Monné 
235dc43978aSKonstantin Belousov #ifdef __amd64__
236dc43978aSKonstantin Belousov static int
xen_invlop(void * arg)237dc43978aSKonstantin Belousov xen_invlop(void *arg)
238dc43978aSKonstantin Belousov {
239dc43978aSKonstantin Belousov 
240dc43978aSKonstantin Belousov 	invlop_handler();
241dc43978aSKonstantin Belousov 	return (FILTER_HANDLED);
242dc43978aSKonstantin Belousov }
243dc43978aSKonstantin Belousov 
244dc43978aSKonstantin Belousov #else /* __i386__ */
245dc43978aSKonstantin Belousov 
24624f7e474SRoger Pau Monné static int
xen_invltlb(void * arg)24724f7e474SRoger Pau Monné xen_invltlb(void *arg)
24824f7e474SRoger Pau Monné {
24924f7e474SRoger Pau Monné 
25024f7e474SRoger Pau Monné 	invltlb_handler();
25124f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
25224f7e474SRoger Pau Monné }
25324f7e474SRoger Pau Monné 
25424f7e474SRoger Pau Monné static int
xen_invlpg(void * arg)25524f7e474SRoger Pau Monné xen_invlpg(void *arg)
25624f7e474SRoger Pau Monné {
25724f7e474SRoger Pau Monné 
25824f7e474SRoger Pau Monné 	invlpg_handler();
25924f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
26024f7e474SRoger Pau Monné }
26124f7e474SRoger Pau Monné 
26224f7e474SRoger Pau Monné static int
xen_invlrng(void * arg)26324f7e474SRoger Pau Monné xen_invlrng(void *arg)
26424f7e474SRoger Pau Monné {
26524f7e474SRoger Pau Monné 
26624f7e474SRoger Pau Monné 	invlrng_handler();
26724f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
26824f7e474SRoger Pau Monné }
26924f7e474SRoger Pau Monné 
27024f7e474SRoger Pau Monné static int
xen_invlcache(void * arg)27124f7e474SRoger Pau Monné xen_invlcache(void *arg)
27224f7e474SRoger Pau Monné {
27324f7e474SRoger Pau Monné 
27424f7e474SRoger Pau Monné 	invlcache_handler();
27524f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
27624f7e474SRoger Pau Monné }
277dc43978aSKonstantin Belousov #endif /* __amd64__ */
27824f7e474SRoger Pau Monné 
27924f7e474SRoger Pau Monné static int
xen_cpustop_handler(void * arg)28024f7e474SRoger Pau Monné xen_cpustop_handler(void *arg)
28124f7e474SRoger Pau Monné {
28224f7e474SRoger Pau Monné 
28324f7e474SRoger Pau Monné 	cpustop_handler();
28424f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
28524f7e474SRoger Pau Monné }
28624f7e474SRoger Pau Monné 
28724f7e474SRoger Pau Monné static int
xen_cpususpend_handler(void * arg)28824f7e474SRoger Pau Monné xen_cpususpend_handler(void *arg)
28924f7e474SRoger Pau Monné {
29024f7e474SRoger Pau Monné 
29124f7e474SRoger Pau Monné 	cpususpend_handler();
29224f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
29324f7e474SRoger Pau Monné }
29424f7e474SRoger Pau Monné 
295aba10e13SAlexander Motin static int
xen_ipi_swi_handler(void * arg)296aba10e13SAlexander Motin xen_ipi_swi_handler(void *arg)
297aba10e13SAlexander Motin {
298aba10e13SAlexander Motin 
29954a0b720SElliott Mitchell 	ipi_swi_handler(*curthread->td_intr_frame);
300aba10e13SAlexander Motin 	return (FILTER_HANDLED);
301aba10e13SAlexander Motin }
302aba10e13SAlexander Motin 
30324f7e474SRoger Pau Monné /*----------------------------- XEN PV IPI setup -----------------------------*/
30424f7e474SRoger Pau Monné /*
30524f7e474SRoger Pau Monné  * Those functions are provided outside of the Xen PV APIC implementation
30624f7e474SRoger Pau Monné  * so PVHVM guests can also use PV IPIs without having an actual Xen PV APIC,
30724f7e474SRoger Pau Monné  * because on PVHVM there's an emulated LAPIC provided by Xen.
30824f7e474SRoger Pau Monné  */
30924f7e474SRoger Pau Monné static void
xen_cpu_ipi_init(int cpu)31024f7e474SRoger Pau Monné xen_cpu_ipi_init(int cpu)
31124f7e474SRoger Pau Monné {
31224f7e474SRoger Pau Monné 	xen_intr_handle_t *ipi_handle;
31324f7e474SRoger Pau Monné 	const struct xen_ipi_handler *ipi;
31424f7e474SRoger Pau Monné 	int idx, rc;
31524f7e474SRoger Pau Monné 
31624f7e474SRoger Pau Monné 	ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
31724f7e474SRoger Pau Monné 
31824f7e474SRoger Pau Monné 	for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
31924f7e474SRoger Pau Monné 		if (ipi->filter == NULL) {
32024f7e474SRoger Pau Monné 			ipi_handle[idx] = NULL;
32124f7e474SRoger Pau Monné 			continue;
32224f7e474SRoger Pau Monné 		}
32324f7e474SRoger Pau Monné 
324ca7af67aSRoger Pau Monné 		rc = xen_intr_alloc_and_bind_ipi(cpu, ipi->filter,
32524f7e474SRoger Pau Monné 		    INTR_TYPE_TTY, &ipi_handle[idx]);
32624f7e474SRoger Pau Monné 		if (rc != 0)
32724f7e474SRoger Pau Monné 			panic("Unable to allocate a XEN IPI port");
32824f7e474SRoger Pau Monné 		xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
32924f7e474SRoger Pau Monné 	}
33024f7e474SRoger Pau Monné }
33124f7e474SRoger Pau Monné 
33224f7e474SRoger Pau Monné static void
xen_setup_cpus(void)33324f7e474SRoger Pau Monné xen_setup_cpus(void)
33424f7e474SRoger Pau Monné {
3352450da67SRoger Pau Monné 	uint32_t regs[4];
33624f7e474SRoger Pau Monné 	int i;
33724f7e474SRoger Pau Monné 
33824f7e474SRoger Pau Monné 	if (!xen_vector_callback_enabled)
33924f7e474SRoger Pau Monné 		return;
34024f7e474SRoger Pau Monné 
3412450da67SRoger Pau Monné 	/*
3422450da67SRoger Pau Monné 	 * Check whether the APIC virtualization is hardware assisted, as
3432450da67SRoger Pau Monné 	 * that's faster than using event channels because it avoids the VM
3442450da67SRoger Pau Monné 	 * exit.
3452450da67SRoger Pau Monné 	 */
346*f0cf86c0SRoger Pau Monné 	KASSERT(hv_base != 0, ("Invalid base Xen CPUID leaf"));
347*f0cf86c0SRoger Pau Monné 	cpuid_count(hv_base + 4, 0, regs);
3482450da67SRoger Pau Monné 	if ((x2apic_mode && (regs[0] & XEN_HVM_CPUID_X2APIC_VIRT)) ||
3492450da67SRoger Pau Monné 	    (!x2apic_mode && (regs[0] & XEN_HVM_CPUID_APIC_ACCESS_VIRT)))
3502450da67SRoger Pau Monné 		return;
3512450da67SRoger Pau Monné 
35224f7e474SRoger Pau Monné 	CPU_FOREACH(i)
35324f7e474SRoger Pau Monné 		xen_cpu_ipi_init(i);
35424f7e474SRoger Pau Monné 
35524f7e474SRoger Pau Monné 	/* Set the xen pv ipi ops to replace the native ones */
356e0516c75SRoger Pau Monné 	ipi_vectored = xen_pv_lapic_ipi_vectored;
357e0516c75SRoger Pau Monné 	native_ipi_vectored = ipi_vectored;
35824f7e474SRoger Pau Monné }
35924f7e474SRoger Pau Monné 
360fae9a0cbSRoger Pau Monné /* Switch to using PV IPIs as soon as the vcpu_id is set. */
361fae9a0cbSRoger Pau Monné SYSINIT(xen_setup_cpus, SI_SUB_SMP, SI_ORDER_SECOND, xen_setup_cpus, NULL);
362