Home | History | Annotate | Line # | Download | only in x86
xen_intr.c revision 1.17.2.1
      1  1.17.2.1  martin /*	$NetBSD: xen_intr.c,v 1.17.2.1 2023/07/31 14:56:19 martin Exp $	*/
      2       1.2  bouyer 
      3       1.2  bouyer /*-
      4       1.2  bouyer  * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
      5       1.2  bouyer  * All rights reserved.
      6       1.2  bouyer  *
      7       1.2  bouyer  * This code is derived from software contributed to The NetBSD Foundation
      8       1.2  bouyer  * by Charles M. Hannum, and by Jason R. Thorpe.
      9       1.2  bouyer  *
     10       1.2  bouyer  * Redistribution and use in source and binary forms, with or without
     11       1.2  bouyer  * modification, are permitted provided that the following conditions
     12       1.2  bouyer  * are met:
     13       1.2  bouyer  * 1. Redistributions of source code must retain the above copyright
     14       1.2  bouyer  *    notice, this list of conditions and the following disclaimer.
     15       1.2  bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.2  bouyer  *    notice, this list of conditions and the following disclaimer in the
     17       1.2  bouyer  *    documentation and/or other materials provided with the distribution.
     18       1.2  bouyer  *
     19       1.2  bouyer  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.2  bouyer  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.2  bouyer  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.2  bouyer  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.2  bouyer  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.2  bouyer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.2  bouyer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.2  bouyer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.2  bouyer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.2  bouyer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.2  bouyer  * POSSIBILITY OF SUCH DAMAGE.
     30       1.2  bouyer  */
     31       1.2  bouyer 
     32       1.2  bouyer #include <sys/cdefs.h>
     33  1.17.2.1  martin __KERNEL_RCSID(0, "$NetBSD: xen_intr.c,v 1.17.2.1 2023/07/31 14:56:19 martin Exp $");
     34       1.2  bouyer 
     35       1.2  bouyer #include <sys/param.h>
     36      1.10  cherry #include <sys/kernel.h>
     37      1.10  cherry #include <sys/kmem.h>
     38      1.10  cherry 
     39      1.11  cherry #include <sys/cpu.h>
     40      1.11  cherry 
     41      1.10  cherry #include <xen/evtchn.h>
     42      1.15  cherry #include <xen/xenfunc.h>
     43       1.2  bouyer 
     44      1.12  cherry #include <uvm/uvm.h>
     45      1.12  cherry 
     46       1.2  bouyer #include <machine/cpu.h>
     47       1.2  bouyer #include <machine/intr.h>
     48       1.2  bouyer 
     49      1.11  cherry #include "acpica.h"
     50      1.11  cherry #include "ioapic.h"
     51      1.11  cherry #include "lapic.h"
     52      1.11  cherry #include "pci.h"
     53      1.11  cherry 
     54      1.11  cherry #if NACPICA > 0
     55      1.11  cherry #include <dev/acpi/acpivar.h>
     56      1.11  cherry #endif
     57      1.11  cherry 
     58      1.11  cherry #if NIOAPIC > 0 || NACPICA > 0
     59      1.11  cherry #include <machine/i82093var.h>
     60      1.11  cherry #endif
     61      1.11  cherry 
     62      1.11  cherry #if NLAPIC > 0
     63      1.11  cherry #include <machine/i82489var.h>
     64      1.11  cherry #endif
     65      1.11  cherry 
     66      1.11  cherry #if NPCI > 0
     67      1.11  cherry #include <dev/pci/ppbreg.h>
     68      1.11  cherry #endif
     69      1.11  cherry 
     70       1.2  bouyer /*
     71       1.2  bouyer  * Restore a value to cpl (unmasking interrupts).  If any unmasked
     72       1.2  bouyer  * interrupts are pending, call Xspllower() to process them.
     73       1.2  bouyer  */
     74      1.14  cherry void xen_spllower(int nlevel);
     75      1.14  cherry 
     76       1.2  bouyer void
     77      1.14  cherry xen_spllower(int nlevel)
     78       1.2  bouyer {
     79       1.2  bouyer 	struct cpu_info *ci = curcpu();
     80      1.11  cherry 	uint32_t xmask;
     81       1.2  bouyer 	u_long psl;
     82       1.2  bouyer 
     83       1.8  bouyer 	if (ci->ci_ilevel <= nlevel)
     84       1.8  bouyer 		return;
     85       1.8  bouyer 
     86       1.2  bouyer 	__insn_barrier();
     87       1.2  bouyer 
     88      1.11  cherry 	xmask = XUNMASK(ci, nlevel);
     89      1.11  cherry 	psl = xen_read_psl();
     90      1.16  bouyer 	x86_disable_intr();
     91      1.11  cherry 	if (ci->ci_xpending & xmask) {
     92       1.7  bouyer 		KASSERT(psl == 0);
     93       1.2  bouyer 		Xspllower(nlevel);
     94       1.2  bouyer 		/* Xspllower does enable_intr() */
     95       1.2  bouyer 	} else {
     96       1.2  bouyer 		ci->ci_ilevel = nlevel;
     97      1.11  cherry 		xen_write_psl(psl);
     98       1.2  bouyer 	}
     99       1.2  bouyer }
    100       1.2  bouyer 
    101      1.16  bouyer 
    102      1.17  cherry #if !defined(XENPVHVM)
    103       1.2  bouyer void
    104      1.16  bouyer x86_disable_intr(void)
    105       1.2  bouyer {
    106  1.17.2.1  martin 
    107  1.17.2.1  martin 	kpreempt_disable();
    108      1.16  bouyer 	curcpu()->ci_vcpu->evtchn_upcall_mask = 1;
    109  1.17.2.1  martin 	kpreempt_enable();
    110  1.17.2.1  martin 
    111  1.17.2.1  martin 	__insn_barrier();
    112       1.2  bouyer }
    113       1.2  bouyer 
    114       1.2  bouyer void
    115      1.16  bouyer x86_enable_intr(void)
    116       1.2  bouyer {
    117  1.17.2.1  martin 	struct cpu_info *ci;
    118  1.17.2.1  martin 
    119  1.17.2.1  martin 	__insn_barrier();
    120  1.17.2.1  martin 
    121  1.17.2.1  martin 	kpreempt_disable();
    122  1.17.2.1  martin 	ci = curcpu();
    123  1.17.2.1  martin 	ci->ci_vcpu->evtchn_upcall_mask = 0;
    124      1.16  bouyer 	__insn_barrier();
    125  1.17.2.1  martin 	if (__predict_false(ci->ci_vcpu->evtchn_upcall_pending))
    126      1.16  bouyer 		hypervisor_force_callback();
    127  1.17.2.1  martin 	kpreempt_enable();
    128       1.2  bouyer }
    129       1.2  bouyer 
    130      1.17  cherry #endif /* !XENPVHVM */
    131      1.17  cherry 
    132       1.2  bouyer u_long
    133      1.11  cherry xen_read_psl(void)
    134       1.2  bouyer {
    135  1.17.2.1  martin 	u_long psl;
    136  1.17.2.1  martin 
    137  1.17.2.1  martin 	kpreempt_disable();
    138  1.17.2.1  martin 	psl = curcpu()->ci_vcpu->evtchn_upcall_mask;
    139  1.17.2.1  martin 	kpreempt_enable();
    140       1.2  bouyer 
    141  1.17.2.1  martin 	return psl;
    142       1.2  bouyer }
    143       1.2  bouyer 
    144       1.2  bouyer void
    145      1.11  cherry xen_write_psl(u_long psl)
    146       1.2  bouyer {
    147  1.17.2.1  martin 	struct cpu_info *ci;
    148       1.2  bouyer 
    149  1.17.2.1  martin 	kpreempt_disable();
    150  1.17.2.1  martin 	ci = curcpu();
    151       1.4  cegger 	ci->ci_vcpu->evtchn_upcall_mask = psl;
    152  1.17.2.1  martin 	__insn_barrier();
    153  1.17.2.1  martin 	if (__predict_false(ci->ci_vcpu->evtchn_upcall_pending) && psl == 0)
    154       1.2  bouyer 	    	hypervisor_force_callback();
    155  1.17.2.1  martin 	kpreempt_enable();
    156       1.2  bouyer }
    157      1.10  cherry 
    158      1.10  cherry void *
    159      1.10  cherry xen_intr_establish(int legacy_irq, struct pic *pic, int pin,
    160      1.10  cherry     int type, int level, int (*handler)(void *), void *arg,
    161      1.10  cherry     bool known_mpsafe)
    162      1.10  cherry {
    163      1.10  cherry 
    164      1.10  cherry 	return xen_intr_establish_xname(legacy_irq, pic, pin, type, level,
    165      1.10  cherry 	    handler, arg, known_mpsafe, "XEN");
    166      1.10  cherry }
    167      1.10  cherry 
    168      1.10  cherry void *
    169      1.10  cherry xen_intr_establish_xname(int legacy_irq, struct pic *pic, int pin,
    170      1.10  cherry     int type, int level, int (*handler)(void *), void *arg,
    171      1.10  cherry     bool known_mpsafe, const char *xname)
    172      1.10  cherry {
    173      1.10  cherry 	const char *intrstr;
    174      1.10  cherry 	char intrstr_buf[INTRIDBUF];
    175      1.10  cherry 
    176      1.10  cherry 	if (pic->pic_type == PIC_XEN) {
    177      1.10  cherry 		struct intrhand *rih;
    178      1.10  cherry 
    179      1.10  cherry 		/*
    180      1.10  cherry 		 * event_set_handler interprets `level != IPL_VM' to
    181      1.10  cherry 		 * mean MP-safe, so we require the caller to match that
    182      1.10  cherry 		 * for the moment.
    183      1.10  cherry 		 */
    184      1.10  cherry 		KASSERT(known_mpsafe == (level != IPL_VM));
    185      1.10  cherry 
    186      1.10  cherry 		intrstr = intr_create_intrid(legacy_irq, pic, pin, intrstr_buf,
    187      1.10  cherry 		    sizeof(intrstr_buf));
    188      1.10  cherry 
    189      1.10  cherry 		event_set_handler(pin, handler, arg, level, intrstr, xname);
    190      1.10  cherry 
    191      1.10  cherry 		rih = kmem_zalloc(sizeof(*rih), cold ? KM_NOSLEEP : KM_SLEEP);
    192      1.10  cherry 		if (rih == NULL) {
    193      1.10  cherry 			printf("%s: can't allocate handler info\n", __func__);
    194      1.10  cherry 			return NULL;
    195      1.10  cherry 		}
    196      1.10  cherry 
    197      1.10  cherry 		/*
    198      1.10  cherry 		 * XXX:
    199      1.10  cherry 		 * This is just a copy for API conformance.
    200      1.10  cherry 		 * The real ih is lost in the innards of
    201      1.10  cherry 		 * event_set_handler(); where the details of
    202      1.10  cherry 		 * biglock_wrapper etc are taken care of.
    203      1.10  cherry 		 * All that goes away when we nuke event_set_handler()
    204      1.10  cherry 		 * et. al. and unify with x86/intr.c
    205      1.10  cherry 		 */
    206      1.10  cherry 		rih->ih_pin = pin; /* port */
    207      1.10  cherry 		rih->ih_fun = rih->ih_realfun = handler;
    208      1.10  cherry 		rih->ih_arg = rih->ih_realarg = arg;
    209      1.10  cherry 		rih->pic_type = pic->pic_type;
    210      1.10  cherry 		return rih;
    211      1.10  cherry 	} 	/* Else we assume pintr */
    212      1.10  cherry 
    213      1.14  cherry #if (NPCI > 0 || NISA > 0) && defined(XENPV) /* XXX: support PVHVM pirq */
    214      1.10  cherry 	struct pintrhand *pih;
    215      1.10  cherry 	int gsi;
    216      1.10  cherry 	int vector, evtchn;
    217      1.10  cherry 
    218      1.10  cherry 	KASSERTMSG(legacy_irq == -1 || (0 <= legacy_irq && legacy_irq < NUM_XEN_IRQS),
    219      1.10  cherry 	    "bad legacy IRQ value: %d", legacy_irq);
    220      1.10  cherry 	KASSERTMSG(!(legacy_irq == -1 && pic == &i8259_pic),
    221      1.10  cherry 	    "non-legacy IRQon i8259 ");
    222      1.10  cherry 
    223      1.10  cherry 	gsi = xen_pic_to_gsi(pic, pin);
    224      1.10  cherry 
    225      1.10  cherry 	intrstr = intr_create_intrid(gsi, pic, pin, intrstr_buf,
    226      1.10  cherry 	    sizeof(intrstr_buf));
    227      1.10  cherry 
    228      1.10  cherry 	vector = xen_vec_alloc(gsi);
    229      1.10  cherry 
    230      1.10  cherry 	if (irq2port[gsi] == 0) {
    231      1.10  cherry 		extern struct cpu_info phycpu_info_primary; /* XXX */
    232      1.10  cherry 		struct cpu_info *ci = &phycpu_info_primary;
    233      1.10  cherry 
    234      1.10  cherry 		pic->pic_addroute(pic, ci, pin, vector, type);
    235      1.10  cherry 
    236      1.10  cherry 		evtchn = bind_pirq_to_evtch(gsi);
    237      1.10  cherry 		KASSERT(evtchn > 0);
    238      1.10  cherry 		KASSERT(evtchn < NR_EVENT_CHANNELS);
    239      1.10  cherry 		irq2port[gsi] = evtchn + 1;
    240      1.10  cherry 		xen_atomic_set_bit(&ci->ci_evtmask[0], evtchn);
    241      1.10  cherry 	} else {
    242      1.10  cherry 		/*
    243      1.10  cherry 		 * Shared interrupt - we can't rebind.
    244      1.10  cherry 		 * The port is shared instead.
    245      1.10  cherry 		 */
    246      1.10  cherry 		evtchn = irq2port[gsi] - 1;
    247      1.10  cherry 	}
    248      1.10  cherry 
    249      1.10  cherry 	pih = pirq_establish(gsi, evtchn, handler, arg, level,
    250      1.10  cherry 			     intrstr, xname);
    251      1.10  cherry 	pih->pic_type = pic->pic_type;
    252      1.10  cherry 	return pih;
    253      1.10  cherry #endif /* NPCI > 0 || NISA > 0 */
    254      1.10  cherry 
    255      1.10  cherry 	/* FALLTHROUGH */
    256      1.10  cherry 	return NULL;
    257      1.10  cherry }
    258      1.10  cherry 
    259      1.10  cherry /*
    260      1.10  cherry  * Deregister an interrupt handler.
    261      1.10  cherry  */
    262      1.10  cherry void
    263      1.10  cherry xen_intr_disestablish(struct intrhand *ih)
    264      1.10  cherry {
    265      1.10  cherry 
    266      1.10  cherry 	if (ih->pic_type == PIC_XEN) {
    267      1.10  cherry 		event_remove_handler(ih->ih_pin, ih->ih_realfun,
    268      1.10  cherry 		    ih->ih_realarg);
    269      1.10  cherry 		kmem_free(ih, sizeof(*ih));
    270      1.10  cherry 		return;
    271      1.10  cherry 	}
    272      1.10  cherry #if defined(DOM0OPS)
    273      1.10  cherry 	/*
    274      1.10  cherry 	 * Cache state, to prevent a use after free situation with
    275      1.10  cherry 	 * ih.
    276      1.10  cherry 	 */
    277      1.10  cherry 
    278      1.10  cherry 	struct pintrhand *pih = (struct pintrhand *)ih;
    279      1.10  cherry 
    280      1.10  cherry 	int pirq = pih->pirq;
    281      1.10  cherry 	int port = pih->evtch;
    282      1.10  cherry 	KASSERT(irq2port[pirq] != 0);
    283      1.10  cherry 
    284      1.10  cherry 	pirq_disestablish(pih);
    285      1.10  cherry 
    286      1.10  cherry 	if (evtsource[port] == NULL) {
    287      1.10  cherry 			/*
    288      1.10  cherry 			 * Last handler was removed by
    289      1.10  cherry 			 * event_remove_handler().
    290      1.10  cherry 			 *
    291      1.10  cherry 			 * We can safely unbind the pirq now.
    292      1.10  cherry 			 */
    293      1.10  cherry 
    294      1.10  cherry 			port = unbind_pirq_from_evtch(pirq);
    295      1.10  cherry 			KASSERT(port == pih->evtch);
    296      1.10  cherry 			irq2port[pirq] = 0;
    297      1.10  cherry 	}
    298      1.10  cherry #endif
    299      1.10  cherry 	return;
    300      1.10  cherry }
    301      1.10  cherry 
    302      1.11  cherry /* MI interface for kern_cpu.c */
    303      1.11  cherry void xen_cpu_intr_redistribute(void);
    304      1.11  cherry 
    305      1.11  cherry void
    306      1.11  cherry xen_cpu_intr_redistribute(void)
    307      1.11  cherry {
    308      1.11  cherry 	KASSERT(mutex_owned(&cpu_lock));
    309      1.11  cherry 	KASSERT(mp_online);
    310      1.11  cherry 
    311      1.11  cherry 	return;
    312      1.11  cherry }
    313      1.11  cherry 
    314      1.11  cherry /* MD - called by x86/cpu.c */
    315      1.12  cherry #if defined(INTRSTACKSIZE)
    316      1.12  cherry static inline bool
    317      1.12  cherry redzone_const_or_false(bool x)
    318      1.12  cherry {
    319      1.12  cherry #ifdef DIAGNOSTIC
    320      1.12  cherry 	return x;
    321      1.12  cherry #else
    322      1.12  cherry 	return false;
    323      1.12  cherry #endif /* !DIAGNOSTIC */
    324      1.12  cherry }
    325      1.12  cherry 
    326      1.12  cherry static inline int
    327      1.12  cherry redzone_const_or_zero(int x)
    328      1.12  cherry {
    329      1.12  cherry 	return redzone_const_or_false(true) ? x : 0;
    330      1.12  cherry }
    331      1.12  cherry #endif
    332      1.12  cherry 
    333      1.14  cherry void xen_cpu_intr_init(struct cpu_info *);
    334      1.11  cherry void
    335      1.14  cherry xen_cpu_intr_init(struct cpu_info *ci)
    336      1.11  cherry {
    337      1.11  cherry 	int i; /* XXX: duplicate */
    338      1.11  cherry 
    339      1.11  cherry 	ci->ci_xunmask[0] = 0xfffffffe;
    340      1.11  cherry 	for (i = 1; i < NIPL; i++)
    341      1.11  cherry 		ci->ci_xunmask[i] = ci->ci_xunmask[i - 1] & ~(1 << i);
    342      1.11  cherry 
    343      1.11  cherry #if defined(INTRSTACKSIZE)
    344      1.11  cherry 	vaddr_t istack;
    345      1.11  cherry 
    346      1.11  cherry 	/*
    347      1.11  cherry 	 * If the red zone is activated, protect both the top and
    348      1.11  cherry 	 * the bottom of the stack with an unmapped page.
    349      1.11  cherry 	 */
    350      1.11  cherry 	istack = uvm_km_alloc(kernel_map,
    351      1.11  cherry 	    INTRSTACKSIZE + redzone_const_or_zero(2 * PAGE_SIZE), 0,
    352      1.11  cherry 	    UVM_KMF_WIRED|UVM_KMF_ZERO);
    353      1.11  cherry 	if (redzone_const_or_false(true)) {
    354      1.11  cherry 		pmap_kremove(istack, PAGE_SIZE);
    355      1.11  cherry 		pmap_kremove(istack + INTRSTACKSIZE + PAGE_SIZE, PAGE_SIZE);
    356      1.11  cherry 		pmap_update(pmap_kernel());
    357      1.11  cherry 	}
    358      1.11  cherry 
    359      1.11  cherry 	/*
    360      1.11  cherry 	 * 33 used to be 1.  Arbitrarily reserve 32 more register_t's
    361      1.11  cherry 	 * of space for ddb(4) to examine some subroutine arguments
    362      1.11  cherry 	 * and to hunt for the next stack frame.
    363      1.11  cherry 	 */
    364      1.11  cherry 	ci->ci_intrstack = (char *)istack + redzone_const_or_zero(PAGE_SIZE) +
    365      1.11  cherry 	    INTRSTACKSIZE - 33 * sizeof(register_t);
    366      1.11  cherry #endif
    367      1.11  cherry 
    368      1.11  cherry 	ci->ci_idepth = -1;
    369      1.11  cherry }
    370      1.11  cherry 
    371      1.11  cherry /*
    372      1.11  cherry  * Everything below from here is duplicated from x86/intr.c
    373      1.11  cherry  * When intr.c and xen_intr.c are unified, these will need to be
    374      1.11  cherry  * merged.
    375      1.11  cherry  */
    376      1.11  cherry 
    377      1.11  cherry u_int xen_cpu_intr_count(struct cpu_info *ci);
    378      1.11  cherry 
    379      1.11  cherry u_int
    380      1.11  cherry xen_cpu_intr_count(struct cpu_info *ci)
    381      1.11  cherry {
    382      1.11  cherry 
    383      1.11  cherry 	KASSERT(ci->ci_nintrhand >= 0);
    384      1.11  cherry 
    385      1.11  cherry 	return ci->ci_nintrhand;
    386      1.11  cherry }
    387      1.11  cherry 
    388      1.11  cherry static const char *
    389      1.11  cherry xen_intr_string(int port, char *buf, size_t len, struct pic *pic)
    390      1.11  cherry {
    391      1.11  cherry 	KASSERT(pic->pic_type == PIC_XEN);
    392      1.11  cherry 
    393      1.11  cherry 	KASSERT(port >= 0);
    394      1.11  cherry 	KASSERT(port < NR_EVENT_CHANNELS);
    395      1.11  cherry 
    396      1.11  cherry 	snprintf(buf, len, "%s channel %d", pic->pic_name, port);
    397      1.11  cherry 
    398      1.11  cherry 	return buf;
    399      1.11  cherry }
    400      1.11  cherry 
    401      1.11  cherry static const char *
    402      1.11  cherry legacy_intr_string(int ih, char *buf, size_t len, struct pic *pic)
    403      1.11  cherry {
    404      1.11  cherry 	int legacy_irq;
    405      1.11  cherry 
    406      1.11  cherry 	KASSERT(pic->pic_type == PIC_I8259);
    407      1.11  cherry #if NLAPIC > 0
    408      1.11  cherry 	KASSERT(APIC_IRQ_ISLEGACY(ih));
    409      1.11  cherry 
    410      1.11  cherry 	legacy_irq = APIC_IRQ_LEGACY_IRQ(ih);
    411      1.11  cherry #else
    412      1.11  cherry 	legacy_irq = ih;
    413      1.11  cherry #endif
    414      1.11  cherry 	KASSERT(legacy_irq >= 0 && legacy_irq < 16);
    415      1.11  cherry 
    416      1.11  cherry 	snprintf(buf, len, "%s pin %d", pic->pic_name, legacy_irq);
    417      1.11  cherry 
    418      1.11  cherry 	return buf;
    419      1.11  cherry }
    420      1.11  cherry 
    421      1.14  cherry const char * xintr_string(intr_handle_t ih, char *buf, size_t len);
    422      1.14  cherry 
    423      1.11  cherry const char *
    424      1.14  cherry xintr_string(intr_handle_t ih, char *buf, size_t len)
    425      1.11  cherry {
    426      1.11  cherry #if NIOAPIC > 0
    427      1.11  cherry 	struct ioapic_softc *pic;
    428      1.11  cherry #endif
    429      1.11  cherry 
    430      1.11  cherry 	if (ih == 0)
    431      1.11  cherry 		panic("%s: bogus handle 0x%" PRIx64, __func__, ih);
    432      1.11  cherry 
    433      1.11  cherry #if NIOAPIC > 0
    434      1.11  cherry 	if (ih & APIC_INT_VIA_APIC) {
    435      1.11  cherry 		pic = ioapic_find(APIC_IRQ_APIC(ih));
    436      1.11  cherry 		if (pic != NULL) {
    437      1.11  cherry 			snprintf(buf, len, "%s pin %d",
    438      1.11  cherry 			    device_xname(pic->sc_dev), APIC_IRQ_PIN(ih));
    439      1.11  cherry 		} else {
    440      1.11  cherry 			snprintf(buf, len,
    441      1.11  cherry 			    "apic %d int %d (irq %d)",
    442      1.11  cherry 			    APIC_IRQ_APIC(ih),
    443      1.11  cherry 			    APIC_IRQ_PIN(ih),
    444      1.11  cherry 			    APIC_IRQ_LEGACY_IRQ(ih));
    445      1.11  cherry 		}
    446      1.11  cherry 	} else
    447      1.11  cherry 		snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih));
    448      1.11  cherry 
    449      1.11  cherry #elif NLAPIC > 0
    450      1.14  cherry 	snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih));
    451      1.11  cherry #else
    452      1.11  cherry 	snprintf(buf, len, "irq %d", (int) ih);
    453      1.11  cherry #endif
    454      1.11  cherry 	return buf;
    455      1.11  cherry 
    456      1.11  cherry }
    457      1.11  cherry 
    458      1.11  cherry /*
    459      1.11  cherry  * Create an interrupt id such as "ioapic0 pin 9". This interrupt id is used
    460      1.11  cherry  * by MI code and intrctl(8).
    461      1.11  cherry  */
    462      1.14  cherry const char * xen_intr_create_intrid(int legacy_irq, struct pic *pic,
    463      1.14  cherry     int pin, char *buf, size_t len);
    464      1.14  cherry 
    465      1.11  cherry const char *
    466      1.14  cherry xen_intr_create_intrid(int legacy_irq, struct pic *pic, int pin, char *buf, size_t len)
    467      1.11  cherry {
    468      1.11  cherry 	int ih = 0;
    469      1.11  cherry 
    470      1.11  cherry #if NPCI > 0
    471      1.11  cherry #if defined(__HAVE_PCI_MSI_MSIX)
    472      1.11  cherry 	if ((pic->pic_type == PIC_MSI) || (pic->pic_type == PIC_MSIX)) {
    473      1.11  cherry 		uint64_t pih;
    474      1.11  cherry 		int dev, vec;
    475      1.11  cherry 
    476      1.11  cherry 		dev = msipic_get_devid(pic);
    477      1.11  cherry 		vec = pin;
    478      1.11  cherry 		pih = __SHIFTIN((uint64_t)dev, MSI_INT_DEV_MASK)
    479      1.11  cherry 			| __SHIFTIN((uint64_t)vec, MSI_INT_VEC_MASK)
    480      1.11  cherry 			| APIC_INT_VIA_MSI;
    481      1.11  cherry 		if (pic->pic_type == PIC_MSI)
    482      1.11  cherry 			MSI_INT_MAKE_MSI(pih);
    483      1.11  cherry 		else if (pic->pic_type == PIC_MSIX)
    484      1.11  cherry 			MSI_INT_MAKE_MSIX(pih);
    485      1.11  cherry 
    486      1.11  cherry 		return x86_pci_msi_string(NULL, pih, buf, len);
    487      1.11  cherry 	}
    488      1.11  cherry #endif /* __HAVE_PCI_MSI_MSIX */
    489      1.11  cherry #endif
    490      1.11  cherry 
    491      1.11  cherry 	if (pic->pic_type == PIC_XEN) {
    492      1.11  cherry 		ih = pin;	/* Port == pin */
    493      1.11  cherry 		return xen_intr_string(pin, buf, len, pic);
    494      1.11  cherry 	}
    495      1.11  cherry 
    496      1.11  cherry 	/*
    497      1.11  cherry 	 * If the device is pci, "legacy_irq" is alway -1. Least 8 bit of "ih"
    498      1.11  cherry 	 * is only used in intr_string() to show the irq number.
    499      1.11  cherry 	 * If the device is "legacy"(such as floppy), it should not use
    500      1.11  cherry 	 * intr_string().
    501      1.11  cherry 	 */
    502      1.11  cherry 	if (pic->pic_type == PIC_I8259) {
    503      1.11  cherry 		ih = legacy_irq;
    504      1.11  cherry 		return legacy_intr_string(ih, buf, len, pic);
    505      1.11  cherry 	}
    506      1.11  cherry 
    507      1.11  cherry #if NIOAPIC > 0 || NACPICA > 0
    508      1.11  cherry 	ih = ((pic->pic_apicid << APIC_INT_APIC_SHIFT) & APIC_INT_APIC_MASK)
    509      1.11  cherry 	    | ((pin << APIC_INT_PIN_SHIFT) & APIC_INT_PIN_MASK);
    510      1.11  cherry 	if (pic->pic_type == PIC_IOAPIC) {
    511      1.11  cherry 		ih |= APIC_INT_VIA_APIC;
    512      1.11  cherry 	}
    513      1.11  cherry 	ih |= pin;
    514      1.11  cherry 	return intr_string(ih, buf, len);
    515      1.11  cherry #endif
    516      1.11  cherry 
    517      1.11  cherry 	return NULL; /* No pic found! */
    518      1.11  cherry }
    519      1.11  cherry 
    520      1.14  cherry #if !defined(XENPVHVM)
    521      1.14  cherry __strong_alias(spllower, xen_spllower);
    522      1.14  cherry __strong_alias(x86_read_psl, xen_read_psl);
    523      1.14  cherry __strong_alias(x86_write_psl, xen_write_psl);
    524      1.14  cherry 
    525      1.14  cherry __strong_alias(intr_string, xintr_string);
    526      1.14  cherry __strong_alias(intr_create_intrid, xen_intr_create_intrid);
    527      1.14  cherry __strong_alias(intr_establish, xen_intr_establish);
    528      1.14  cherry __strong_alias(intr_establish_xname, xen_intr_establish_xname);
    529      1.14  cherry __strong_alias(intr_disestablish, xen_intr_disestablish);
    530      1.14  cherry __strong_alias(cpu_intr_redistribute, xen_cpu_intr_redistribute);
    531      1.14  cherry __strong_alias(cpu_intr_count, xen_cpu_intr_count);
    532      1.14  cherry __strong_alias(cpu_intr_init, xen_cpu_intr_init);
    533      1.14  cherry #endif /* !XENPVHVM */
    534