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