xref: /netbsd-src/sys/arch/xen/x86/xen_intr.c (revision e171a73dc43aac41fc1827e9d3a9f5beac238ee8)
1*e171a73dSriastradh /*	$NetBSD: xen_intr.c,v 1.31 2023/02/25 00:32:13 riastradh Exp $	*/
24e541343Sbouyer 
34e541343Sbouyer /*-
44e541343Sbouyer  * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
54e541343Sbouyer  * All rights reserved.
64e541343Sbouyer  *
74e541343Sbouyer  * This code is derived from software contributed to The NetBSD Foundation
84e541343Sbouyer  * by Charles M. Hannum, and by Jason R. Thorpe.
94e541343Sbouyer  *
104e541343Sbouyer  * Redistribution and use in source and binary forms, with or without
114e541343Sbouyer  * modification, are permitted provided that the following conditions
124e541343Sbouyer  * are met:
134e541343Sbouyer  * 1. Redistributions of source code must retain the above copyright
144e541343Sbouyer  *    notice, this list of conditions and the following disclaimer.
154e541343Sbouyer  * 2. Redistributions in binary form must reproduce the above copyright
164e541343Sbouyer  *    notice, this list of conditions and the following disclaimer in the
174e541343Sbouyer  *    documentation and/or other materials provided with the distribution.
184e541343Sbouyer  *
194e541343Sbouyer  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
204e541343Sbouyer  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214e541343Sbouyer  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
224e541343Sbouyer  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
234e541343Sbouyer  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244e541343Sbouyer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254e541343Sbouyer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264e541343Sbouyer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274e541343Sbouyer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284e541343Sbouyer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294e541343Sbouyer  * POSSIBILITY OF SUCH DAMAGE.
304e541343Sbouyer  */
314e541343Sbouyer 
324e541343Sbouyer #include <sys/cdefs.h>
33*e171a73dSriastradh __KERNEL_RCSID(0, "$NetBSD: xen_intr.c,v 1.31 2023/02/25 00:32:13 riastradh Exp $");
34084208a9Sad 
35084208a9Sad #include "opt_multiprocessor.h"
361947fd1bSjdolecek #include "opt_pci.h"
374e541343Sbouyer 
384e541343Sbouyer #include <sys/param.h>
392465aa9cScherry #include <sys/kernel.h>
402465aa9cScherry #include <sys/kmem.h>
41b20defb9Scherry #include <sys/cpu.h>
42084208a9Sad #include <sys/device.h>
43b20defb9Scherry 
44c24c993fSbouyer #include <xen/intr.h>
452465aa9cScherry #include <xen/evtchn.h>
461e3d30b0Scherry #include <xen/xenfunc.h>
474e541343Sbouyer 
482d1e9ea9Scherry #include <uvm/uvm.h>
492d1e9ea9Scherry 
504e541343Sbouyer #include <machine/cpu.h>
514e541343Sbouyer #include <machine/intr.h>
524e541343Sbouyer 
53b20defb9Scherry #include "acpica.h"
54b20defb9Scherry #include "ioapic.h"
55b20defb9Scherry #include "lapic.h"
56b20defb9Scherry #include "pci.h"
57b20defb9Scherry 
58b20defb9Scherry #if NACPICA > 0
59b20defb9Scherry #include <dev/acpi/acpivar.h>
60b20defb9Scherry #endif
61b20defb9Scherry 
62b20defb9Scherry #if NIOAPIC > 0 || NACPICA > 0
63b20defb9Scherry #include <machine/i82093var.h>
64b20defb9Scherry #endif
65b20defb9Scherry 
66b20defb9Scherry #if NLAPIC > 0
67b20defb9Scherry #include <machine/i82489var.h>
68b20defb9Scherry #endif
69b20defb9Scherry 
70b20defb9Scherry #if NPCI > 0
71b20defb9Scherry #include <dev/pci/ppbreg.h>
72374fa909Sjdolecek #ifdef __HAVE_PCI_MSI_MSIX
73374fa909Sjdolecek #include <x86/pci/msipic.h>
74374fa909Sjdolecek #include <x86/pci/pci_msi_machdep.h>
75374fa909Sjdolecek #endif
76b20defb9Scherry #endif
77b20defb9Scherry 
78084208a9Sad #if defined(MULTIPROCESSOR)
79084208a9Sad static const char *xen_ipi_names[XEN_NIPIS] = XEN_IPI_NAMES;
80084208a9Sad #endif
81084208a9Sad 
825784c3a0Scherry #if !defined(XENPVHVM)
834e541343Sbouyer void
x86_disable_intr(void)843eb5fd5eSbouyer x86_disable_intr(void)
854e541343Sbouyer {
86*e171a73dSriastradh 
87*e171a73dSriastradh 	kpreempt_disable();
883eb5fd5eSbouyer 	curcpu()->ci_vcpu->evtchn_upcall_mask = 1;
89*e171a73dSriastradh 	kpreempt_enable();
90*e171a73dSriastradh 
91*e171a73dSriastradh 	__insn_barrier();
924e541343Sbouyer }
934e541343Sbouyer 
944e541343Sbouyer void
x86_enable_intr(void)953eb5fd5eSbouyer x86_enable_intr(void)
964e541343Sbouyer {
97*e171a73dSriastradh 	struct cpu_info *ci;
98*e171a73dSriastradh 
993eb5fd5eSbouyer 	__insn_barrier();
100*e171a73dSriastradh 
101*e171a73dSriastradh 	kpreempt_disable();
102*e171a73dSriastradh 	ci = curcpu();
103*e171a73dSriastradh 	ci->ci_vcpu->evtchn_upcall_mask = 0;
104*e171a73dSriastradh 	__insn_barrier();
105*e171a73dSriastradh 	if (__predict_false(ci->ci_vcpu->evtchn_upcall_pending))
1063eb5fd5eSbouyer 		hypervisor_force_callback();
107*e171a73dSriastradh 	kpreempt_enable();
1084e541343Sbouyer }
1094e541343Sbouyer 
1105784c3a0Scherry #endif /* !XENPVHVM */
1115784c3a0Scherry 
1124e541343Sbouyer u_long
xen_read_psl(void)113b20defb9Scherry xen_read_psl(void)
1144e541343Sbouyer {
115*e171a73dSriastradh 	u_long psl;
1164e541343Sbouyer 
117*e171a73dSriastradh 	kpreempt_disable();
118*e171a73dSriastradh 	psl = curcpu()->ci_vcpu->evtchn_upcall_mask;
119*e171a73dSriastradh 	kpreempt_enable();
120*e171a73dSriastradh 
121*e171a73dSriastradh 	return psl;
1224e541343Sbouyer }
1234e541343Sbouyer 
1244e541343Sbouyer void
xen_write_psl(u_long psl)125b20defb9Scherry xen_write_psl(u_long psl)
1264e541343Sbouyer {
127*e171a73dSriastradh 	struct cpu_info *ci;
1284e541343Sbouyer 
129*e171a73dSriastradh 	kpreempt_disable();
130*e171a73dSriastradh 	ci = curcpu();
13120161b72Scegger 	ci->ci_vcpu->evtchn_upcall_mask = psl;
132*e171a73dSriastradh 	__insn_barrier();
133*e171a73dSriastradh 	if (__predict_false(ci->ci_vcpu->evtchn_upcall_pending) && psl == 0)
1344e541343Sbouyer 	    	hypervisor_force_callback();
135*e171a73dSriastradh 	kpreempt_enable();
1364e541343Sbouyer }
1372465aa9cScherry 
1382465aa9cScherry void *
xen_intr_establish(int legacy_irq,struct pic * pic,int pin,int type,int level,int (* handler)(void *),void * arg,bool known_mpsafe)1392465aa9cScherry xen_intr_establish(int legacy_irq, struct pic *pic, int pin,
1402465aa9cScherry     int type, int level, int (*handler)(void *), void *arg,
1412465aa9cScherry     bool known_mpsafe)
1422465aa9cScherry {
1432465aa9cScherry 
1442465aa9cScherry 	return xen_intr_establish_xname(legacy_irq, pic, pin, type, level,
1452465aa9cScherry 	    handler, arg, known_mpsafe, "XEN");
1462465aa9cScherry }
1472465aa9cScherry 
1482465aa9cScherry void *
xen_intr_establish_xname(int legacy_irq,struct pic * pic,int pin,int type,int level,int (* handler)(void *),void * arg,bool known_mpsafe,const char * xname)1492465aa9cScherry xen_intr_establish_xname(int legacy_irq, struct pic *pic, int pin,
1502465aa9cScherry     int type, int level, int (*handler)(void *), void *arg,
1512465aa9cScherry     bool known_mpsafe, const char *xname)
1522465aa9cScherry {
1532465aa9cScherry 	const char *intrstr;
1542465aa9cScherry 	char intrstr_buf[INTRIDBUF];
1552465aa9cScherry 
1562465aa9cScherry 	if (pic->pic_type == PIC_XEN) {
1572465aa9cScherry 		struct intrhand *rih;
1582465aa9cScherry 
1592465aa9cScherry 		intrstr = intr_create_intrid(legacy_irq, pic, pin, intrstr_buf,
1602465aa9cScherry 		    sizeof(intrstr_buf));
1612465aa9cScherry 
162c24c993fSbouyer 		rih = event_set_handler(pin, handler, arg, level,
163b914674dSbouyer 		    intrstr, xname, known_mpsafe, NULL);
1642465aa9cScherry 
1652465aa9cScherry 		if (rih == NULL) {
166c24c993fSbouyer 			printf("%s: can't establish interrupt\n", __func__);
1672465aa9cScherry 			return NULL;
1682465aa9cScherry 		}
1692465aa9cScherry 
1702465aa9cScherry 		return rih;
1712465aa9cScherry 	} 	/* Else we assume pintr */
1722465aa9cScherry 
173d9eb2ac8Scherry #if (NPCI > 0 || NISA > 0) && defined(XENPV) /* XXX: support PVHVM pirq */
1742465aa9cScherry 	struct pintrhand *pih;
1752465aa9cScherry 	int gsi;
176d5100c23Sjdolecek 	int evtchn;
177b914674dSbouyer 	/* the hack below is from x86's intr_establish_xname() */
178b914674dSbouyer 	bool mpsafe = (known_mpsafe || level != IPL_VM);
1792465aa9cScherry 
1802465aa9cScherry 	KASSERTMSG(legacy_irq == -1 || (0 <= legacy_irq && legacy_irq < NUM_XEN_IRQS),
1812465aa9cScherry 	    "bad legacy IRQ value: %d", legacy_irq);
1822465aa9cScherry 	KASSERTMSG(!(legacy_irq == -1 && pic == &i8259_pic),
1832465aa9cScherry 	    "non-legacy IRQon i8259 ");
1842465aa9cScherry 
1852465aa9cScherry 	gsi = xen_pic_to_gsi(pic, pin);
186f3af8bcbSbouyer 	if (gsi < 0)
187f3af8bcbSbouyer 		return NULL;
188d5100c23Sjdolecek 	KASSERTMSG(gsi < NR_EVENT_CHANNELS, "gsi %d >= NR_EVENT_CHANNELS %u",
189d5100c23Sjdolecek 	    gsi, (int)NR_EVENT_CHANNELS);
1902465aa9cScherry 
1912465aa9cScherry 	intrstr = intr_create_intrid(gsi, pic, pin, intrstr_buf,
1922465aa9cScherry 	    sizeof(intrstr_buf));
1932465aa9cScherry 
1942465aa9cScherry 	if (irq2port[gsi] == 0) {
1952465aa9cScherry 		extern struct cpu_info phycpu_info_primary; /* XXX */
1962465aa9cScherry 		struct cpu_info *ci = &phycpu_info_primary;
1972465aa9cScherry 
198d5100c23Sjdolecek 		pic->pic_addroute(pic, ci, pin, gsi, type);
1992465aa9cScherry 
2002465aa9cScherry 		evtchn = bind_pirq_to_evtch(gsi);
2012465aa9cScherry 		KASSERT(evtchn > 0);
2022465aa9cScherry 		KASSERT(evtchn < NR_EVENT_CHANNELS);
2032465aa9cScherry 		irq2port[gsi] = evtchn + 1;
2042465aa9cScherry 		xen_atomic_set_bit(&ci->ci_evtmask[0], evtchn);
2052465aa9cScherry 	} else {
2062465aa9cScherry 		/*
2072465aa9cScherry 		 * Shared interrupt - we can't rebind.
2082465aa9cScherry 		 * The port is shared instead.
2092465aa9cScherry 		 */
2102465aa9cScherry 		evtchn = irq2port[gsi] - 1;
2112465aa9cScherry 	}
2122465aa9cScherry 
2132465aa9cScherry 	pih = pirq_establish(gsi, evtchn, handler, arg, level,
214b914674dSbouyer 			     intrstr, xname, mpsafe);
215c24c993fSbouyer 	pih->pic = pic;
216f3af8bcbSbouyer 	if (msipic_is_msi_pic(pic))
217f3af8bcbSbouyer 		pic->pic_hwunmask(pic, pin);
2182465aa9cScherry 	return pih;
2192465aa9cScherry #endif /* NPCI > 0 || NISA > 0 */
2202465aa9cScherry 
2212465aa9cScherry 	/* FALLTHROUGH */
2222465aa9cScherry 	return NULL;
2232465aa9cScherry }
2242465aa9cScherry 
2252465aa9cScherry /*
22634998744Sthorpej  * Mask an interrupt source.
22734998744Sthorpej  */
22834998744Sthorpej void
xen_intr_mask(struct intrhand * ih)22934998744Sthorpej xen_intr_mask(struct intrhand *ih)
23034998744Sthorpej {
23134998744Sthorpej 	/* XXX */
23234998744Sthorpej 	panic("xen_intr_mask: not yet implemented.");
23334998744Sthorpej }
23434998744Sthorpej 
23534998744Sthorpej /*
23634998744Sthorpej  * Unmask an interrupt source.
23734998744Sthorpej  */
23834998744Sthorpej void
xen_intr_unmask(struct intrhand * ih)23934998744Sthorpej xen_intr_unmask(struct intrhand *ih)
24034998744Sthorpej {
24134998744Sthorpej 	/* XXX */
24234998744Sthorpej 	panic("xen_intr_unmask: not yet implemented.");
24334998744Sthorpej }
24434998744Sthorpej 
24534998744Sthorpej /*
2462465aa9cScherry  * Deregister an interrupt handler.
2472465aa9cScherry  */
2482465aa9cScherry void
xen_intr_disestablish(struct intrhand * ih)2492465aa9cScherry xen_intr_disestablish(struct intrhand *ih)
2502465aa9cScherry {
2512465aa9cScherry 
252c24c993fSbouyer 	if (ih->ih_pic->pic_type == PIC_XEN) {
2532465aa9cScherry 		event_remove_handler(ih->ih_pin, ih->ih_realfun,
2542465aa9cScherry 		    ih->ih_realarg);
255c24c993fSbouyer 		/* event_remove_handler frees ih */
2562465aa9cScherry 		return;
2572465aa9cScherry 	}
2584dbd32ceSbouyer #if defined(DOM0OPS) && defined(XENPV)
2592465aa9cScherry 	/*
2602465aa9cScherry 	 * Cache state, to prevent a use after free situation with
2612465aa9cScherry 	 * ih.
2622465aa9cScherry 	 */
2632465aa9cScherry 
2642465aa9cScherry 	struct pintrhand *pih = (struct pintrhand *)ih;
2652465aa9cScherry 
2662465aa9cScherry 	int pirq = pih->pirq;
2672465aa9cScherry 	int port = pih->evtch;
2682465aa9cScherry 	KASSERT(irq2port[pirq] != 0);
2692465aa9cScherry 
2702465aa9cScherry 	pirq_disestablish(pih);
2712465aa9cScherry 
2722465aa9cScherry 	if (evtsource[port] == NULL) {
2732465aa9cScherry 			/*
2742465aa9cScherry 			 * Last handler was removed by
2752465aa9cScherry 			 * event_remove_handler().
2762465aa9cScherry 			 *
2772465aa9cScherry 			 * We can safely unbind the pirq now.
2782465aa9cScherry 			 */
2792465aa9cScherry 
2802465aa9cScherry 			port = unbind_pirq_from_evtch(pirq);
2812465aa9cScherry 			KASSERT(port == pih->evtch);
2822465aa9cScherry 			irq2port[pirq] = 0;
2832465aa9cScherry 	}
2842465aa9cScherry #endif
2852465aa9cScherry 	return;
2862465aa9cScherry }
2872465aa9cScherry 
288b20defb9Scherry /* MI interface for kern_cpu.c */
289b20defb9Scherry void xen_cpu_intr_redistribute(void);
290b20defb9Scherry 
291b20defb9Scherry void
xen_cpu_intr_redistribute(void)292b20defb9Scherry xen_cpu_intr_redistribute(void)
293b20defb9Scherry {
294b20defb9Scherry 	KASSERT(mutex_owned(&cpu_lock));
295b20defb9Scherry 	KASSERT(mp_online);
296b20defb9Scherry 
297b20defb9Scherry 	return;
298b20defb9Scherry }
299b20defb9Scherry 
300b20defb9Scherry /* MD - called by x86/cpu.c */
3012d1e9ea9Scherry #if defined(INTRSTACKSIZE)
3022d1e9ea9Scherry static inline bool
redzone_const_or_false(bool x)3032d1e9ea9Scherry redzone_const_or_false(bool x)
3042d1e9ea9Scherry {
3052d1e9ea9Scherry #ifdef DIAGNOSTIC
3062d1e9ea9Scherry 	return x;
3072d1e9ea9Scherry #else
3082d1e9ea9Scherry 	return false;
3092d1e9ea9Scherry #endif /* !DIAGNOSTIC */
3102d1e9ea9Scherry }
3112d1e9ea9Scherry 
3122d1e9ea9Scherry static inline int
redzone_const_or_zero(int x)3132d1e9ea9Scherry redzone_const_or_zero(int x)
3142d1e9ea9Scherry {
3152d1e9ea9Scherry 	return redzone_const_or_false(true) ? x : 0;
3162d1e9ea9Scherry }
3172d1e9ea9Scherry #endif
3182d1e9ea9Scherry 
319d9eb2ac8Scherry void xen_cpu_intr_init(struct cpu_info *);
320b20defb9Scherry void
xen_cpu_intr_init(struct cpu_info * ci)321d9eb2ac8Scherry xen_cpu_intr_init(struct cpu_info *ci)
322b20defb9Scherry {
323c24c993fSbouyer #if defined(__HAVE_PREEMPTION)
324c24c993fSbouyer 	x86_init_preempt(ci);
325c24c993fSbouyer #endif
326c24c993fSbouyer 	x86_intr_calculatemasks(ci);
327b20defb9Scherry 
328b20defb9Scherry #if defined(INTRSTACKSIZE)
329b20defb9Scherry 	vaddr_t istack;
330b20defb9Scherry 
331b20defb9Scherry 	/*
332b20defb9Scherry 	 * If the red zone is activated, protect both the top and
333b20defb9Scherry 	 * the bottom of the stack with an unmapped page.
334b20defb9Scherry 	 */
335b20defb9Scherry 	istack = uvm_km_alloc(kernel_map,
336b20defb9Scherry 	    INTRSTACKSIZE + redzone_const_or_zero(2 * PAGE_SIZE), 0,
337b20defb9Scherry 	    UVM_KMF_WIRED|UVM_KMF_ZERO);
338b20defb9Scherry 	if (redzone_const_or_false(true)) {
339b20defb9Scherry 		pmap_kremove(istack, PAGE_SIZE);
340b20defb9Scherry 		pmap_kremove(istack + INTRSTACKSIZE + PAGE_SIZE, PAGE_SIZE);
341b20defb9Scherry 		pmap_update(pmap_kernel());
342b20defb9Scherry 	}
343b20defb9Scherry 
344b20defb9Scherry 	/*
345b20defb9Scherry 	 * 33 used to be 1.  Arbitrarily reserve 32 more register_t's
346b20defb9Scherry 	 * of space for ddb(4) to examine some subroutine arguments
347b20defb9Scherry 	 * and to hunt for the next stack frame.
348b20defb9Scherry 	 */
349b20defb9Scherry 	ci->ci_intrstack = (char *)istack + redzone_const_or_zero(PAGE_SIZE) +
350b20defb9Scherry 	    INTRSTACKSIZE - 33 * sizeof(register_t);
351b20defb9Scherry #endif
352b20defb9Scherry 
353084208a9Sad #ifdef MULTIPROCESSOR
354c24c993fSbouyer 	for (int i = 0; i < XEN_NIPIS; i++)
355084208a9Sad 		evcnt_attach_dynamic(&ci->ci_ipi_events[i], EVCNT_TYPE_MISC,
356084208a9Sad 		    NULL, device_xname(ci->ci_dev), xen_ipi_names[i]);
357084208a9Sad #endif
358084208a9Sad 
359b20defb9Scherry 	ci->ci_idepth = -1;
360b20defb9Scherry }
361b20defb9Scherry 
362b20defb9Scherry /*
363b20defb9Scherry  * Everything below from here is duplicated from x86/intr.c
364b20defb9Scherry  * When intr.c and xen_intr.c are unified, these will need to be
365b20defb9Scherry  * merged.
366b20defb9Scherry  */
367b20defb9Scherry 
368b20defb9Scherry u_int xen_cpu_intr_count(struct cpu_info *ci);
369b20defb9Scherry 
370b20defb9Scherry u_int
xen_cpu_intr_count(struct cpu_info * ci)371b20defb9Scherry xen_cpu_intr_count(struct cpu_info *ci)
372b20defb9Scherry {
373b20defb9Scherry 
374b20defb9Scherry 	KASSERT(ci->ci_nintrhand >= 0);
375b20defb9Scherry 
376b20defb9Scherry 	return ci->ci_nintrhand;
377b20defb9Scherry }
378b20defb9Scherry 
379b20defb9Scherry static const char *
xen_intr_string(int port,char * buf,size_t len,struct pic * pic)380b20defb9Scherry xen_intr_string(int port, char *buf, size_t len, struct pic *pic)
381b20defb9Scherry {
382b20defb9Scherry 	KASSERT(pic->pic_type == PIC_XEN);
383b20defb9Scherry 
384b20defb9Scherry 	KASSERT(port >= 0);
385b20defb9Scherry 	KASSERT(port < NR_EVENT_CHANNELS);
386b20defb9Scherry 
387c24c993fSbouyer 	snprintf(buf, len, "%s chan %d", pic->pic_name, port);
388b20defb9Scherry 
389b20defb9Scherry 	return buf;
390b20defb9Scherry }
391b20defb9Scherry 
392b20defb9Scherry static const char *
legacy_intr_string(int ih,char * buf,size_t len,struct pic * pic)393b20defb9Scherry legacy_intr_string(int ih, char *buf, size_t len, struct pic *pic)
394b20defb9Scherry {
395b20defb9Scherry 	int legacy_irq;
396b20defb9Scherry 
397b20defb9Scherry 	KASSERT(pic->pic_type == PIC_I8259);
398b20defb9Scherry #if NLAPIC > 0
399b20defb9Scherry 	KASSERT(APIC_IRQ_ISLEGACY(ih));
400b20defb9Scherry 
401b20defb9Scherry 	legacy_irq = APIC_IRQ_LEGACY_IRQ(ih);
402b20defb9Scherry #else
403b20defb9Scherry 	legacy_irq = ih;
404b20defb9Scherry #endif
405b20defb9Scherry 	KASSERT(legacy_irq >= 0 && legacy_irq < 16);
406b20defb9Scherry 
407b20defb9Scherry 	snprintf(buf, len, "%s pin %d", pic->pic_name, legacy_irq);
408b20defb9Scherry 
409b20defb9Scherry 	return buf;
410b20defb9Scherry }
411b20defb9Scherry 
412d9eb2ac8Scherry const char * xintr_string(intr_handle_t ih, char *buf, size_t len);
413d9eb2ac8Scherry 
414b20defb9Scherry const char *
xintr_string(intr_handle_t ih,char * buf,size_t len)415d9eb2ac8Scherry xintr_string(intr_handle_t ih, char *buf, size_t len)
416b20defb9Scherry {
417b20defb9Scherry #if NIOAPIC > 0
418b20defb9Scherry 	struct ioapic_softc *pic;
419b20defb9Scherry #endif
420b20defb9Scherry 
421b20defb9Scherry 	if (ih == 0)
422b20defb9Scherry 		panic("%s: bogus handle 0x%" PRIx64, __func__, ih);
423b20defb9Scherry 
424b20defb9Scherry #if NIOAPIC > 0
425b20defb9Scherry 	if (ih & APIC_INT_VIA_APIC) {
426b20defb9Scherry 		pic = ioapic_find(APIC_IRQ_APIC(ih));
427b20defb9Scherry 		if (pic != NULL) {
428b20defb9Scherry 			snprintf(buf, len, "%s pin %d",
429b20defb9Scherry 			    device_xname(pic->sc_dev), APIC_IRQ_PIN(ih));
430b20defb9Scherry 		} else {
431b20defb9Scherry 			snprintf(buf, len,
432b20defb9Scherry 			    "apic %d int %d (irq %d)",
433b20defb9Scherry 			    APIC_IRQ_APIC(ih),
434b20defb9Scherry 			    APIC_IRQ_PIN(ih),
435b20defb9Scherry 			    APIC_IRQ_LEGACY_IRQ(ih));
436b20defb9Scherry 		}
437b20defb9Scherry 	} else
438b20defb9Scherry 		snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih));
439b20defb9Scherry 
440b20defb9Scherry #elif NLAPIC > 0
441d9eb2ac8Scherry 	snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih));
442b20defb9Scherry #else
443b20defb9Scherry 	snprintf(buf, len, "irq %d", (int) ih);
444b20defb9Scherry #endif
445b20defb9Scherry 	return buf;
446b20defb9Scherry 
447b20defb9Scherry }
448b20defb9Scherry 
449b20defb9Scherry /*
450b20defb9Scherry  * Create an interrupt id such as "ioapic0 pin 9". This interrupt id is used
451b20defb9Scherry  * by MI code and intrctl(8).
452b20defb9Scherry  */
453d9eb2ac8Scherry const char * xen_intr_create_intrid(int legacy_irq, struct pic *pic,
454d9eb2ac8Scherry     int pin, char *buf, size_t len);
455d9eb2ac8Scherry 
456b20defb9Scherry const char *
xen_intr_create_intrid(int legacy_irq,struct pic * pic,int pin,char * buf,size_t len)457d9eb2ac8Scherry xen_intr_create_intrid(int legacy_irq, struct pic *pic, int pin, char *buf, size_t len)
458b20defb9Scherry {
459b20defb9Scherry 	int ih = 0;
460b20defb9Scherry 
461c24c993fSbouyer #if NPCI > 0 && defined(XENPV)
462b20defb9Scherry #if defined(__HAVE_PCI_MSI_MSIX)
463b20defb9Scherry 	if ((pic->pic_type == PIC_MSI) || (pic->pic_type == PIC_MSIX)) {
464b20defb9Scherry 		uint64_t pih;
465b20defb9Scherry 		int dev, vec;
466b20defb9Scherry 
467b20defb9Scherry 		dev = msipic_get_devid(pic);
468b20defb9Scherry 		vec = pin;
469b20defb9Scherry 		pih = __SHIFTIN((uint64_t)dev, MSI_INT_DEV_MASK)
470b20defb9Scherry 			| __SHIFTIN((uint64_t)vec, MSI_INT_VEC_MASK)
471b20defb9Scherry 			| APIC_INT_VIA_MSI;
472b20defb9Scherry 		if (pic->pic_type == PIC_MSI)
473b20defb9Scherry 			MSI_INT_MAKE_MSI(pih);
474b20defb9Scherry 		else if (pic->pic_type == PIC_MSIX)
475b20defb9Scherry 			MSI_INT_MAKE_MSIX(pih);
476b20defb9Scherry 
477b20defb9Scherry 		return x86_pci_msi_string(NULL, pih, buf, len);
478b20defb9Scherry 	}
479b20defb9Scherry #endif /* __HAVE_PCI_MSI_MSIX */
480b20defb9Scherry #endif
481b20defb9Scherry 
482b20defb9Scherry 	if (pic->pic_type == PIC_XEN) {
483b20defb9Scherry 		ih = pin;	/* Port == pin */
484b20defb9Scherry 		return xen_intr_string(pin, buf, len, pic);
485b20defb9Scherry 	}
486b20defb9Scherry 
487b20defb9Scherry 	/*
4888c146276Sandvar 	 * If the device is pci, "legacy_irq" is always -1. Least 8 bit of "ih"
489b20defb9Scherry 	 * is only used in intr_string() to show the irq number.
490b20defb9Scherry 	 * If the device is "legacy"(such as floppy), it should not use
491b20defb9Scherry 	 * intr_string().
492b20defb9Scherry 	 */
493b20defb9Scherry 	if (pic->pic_type == PIC_I8259) {
494b20defb9Scherry 		ih = legacy_irq;
495b20defb9Scherry 		return legacy_intr_string(ih, buf, len, pic);
496b20defb9Scherry 	}
497b20defb9Scherry 
498b20defb9Scherry #if NIOAPIC > 0 || NACPICA > 0
499b20defb9Scherry 	ih = ((pic->pic_apicid << APIC_INT_APIC_SHIFT) & APIC_INT_APIC_MASK)
500b20defb9Scherry 	    | ((pin << APIC_INT_PIN_SHIFT) & APIC_INT_PIN_MASK);
501b20defb9Scherry 	if (pic->pic_type == PIC_IOAPIC) {
502b20defb9Scherry 		ih |= APIC_INT_VIA_APIC;
503b20defb9Scherry 	}
504b20defb9Scherry 	ih |= pin;
505b20defb9Scherry 	return intr_string(ih, buf, len);
506b20defb9Scherry #endif
507b20defb9Scherry 
508b20defb9Scherry 	return NULL; /* No pic found! */
509b20defb9Scherry }
510b20defb9Scherry 
511374fa909Sjdolecek static struct intrsource xen_dummy_intrsource;
512374fa909Sjdolecek 
513374fa909Sjdolecek struct intrsource *
xen_intr_allocate_io_intrsource(const char * intrid)514374fa909Sjdolecek xen_intr_allocate_io_intrsource(const char *intrid)
515374fa909Sjdolecek {
516374fa909Sjdolecek 	/* Nothing to do, required by MSI code */
517374fa909Sjdolecek 	return &xen_dummy_intrsource;
518374fa909Sjdolecek }
519374fa909Sjdolecek 
520374fa909Sjdolecek void
xen_intr_free_io_intrsource(const char * intrid)521374fa909Sjdolecek xen_intr_free_io_intrsource(const char *intrid)
522374fa909Sjdolecek {
523374fa909Sjdolecek 	/* Nothing to do, required by MSI code */
524374fa909Sjdolecek }
525374fa909Sjdolecek 
526c24c993fSbouyer #if defined(XENPV)
527d9eb2ac8Scherry __strong_alias(x86_read_psl, xen_read_psl);
528d9eb2ac8Scherry __strong_alias(x86_write_psl, xen_write_psl);
529b20defb9Scherry 
530d9eb2ac8Scherry __strong_alias(intr_string, xintr_string);
531d9eb2ac8Scherry __strong_alias(intr_create_intrid, xen_intr_create_intrid);
532d9eb2ac8Scherry __strong_alias(intr_establish, xen_intr_establish);
533d9eb2ac8Scherry __strong_alias(intr_establish_xname, xen_intr_establish_xname);
53434998744Sthorpej __strong_alias(intr_mask, xen_intr_mask);
53534998744Sthorpej __strong_alias(intr_unmask, xen_intr_unmask);
536d9eb2ac8Scherry __strong_alias(intr_disestablish, xen_intr_disestablish);
537d9eb2ac8Scherry __strong_alias(cpu_intr_redistribute, xen_cpu_intr_redistribute);
538d9eb2ac8Scherry __strong_alias(cpu_intr_count, xen_cpu_intr_count);
539d9eb2ac8Scherry __strong_alias(cpu_intr_init, xen_cpu_intr_init);
540374fa909Sjdolecek __strong_alias(intr_allocate_io_intrsource, xen_intr_allocate_io_intrsource);
541374fa909Sjdolecek __strong_alias(intr_free_io_intrsource, xen_intr_free_io_intrsource);
542c24c993fSbouyer #endif /* XENPV */
543