xref: /netbsd-src/sys/arch/x86/include/intr.h (revision ff4bde105648fdd295a51ae5a400c4e26627a7b1)
1*ff4bde10Sknakahara /*	$NetBSD: intr.h,v 1.66 2022/09/07 00:40:18 knakahara Exp $	*/
28375b2d9Sfvdl 
38375b2d9Sfvdl /*-
4b1ae49d2Sthorpej  * Copyright (c) 1998, 2001, 2006, 2007, 2008, 2019 The NetBSD Foundation, Inc.
58375b2d9Sfvdl  * All rights reserved.
68375b2d9Sfvdl  *
78375b2d9Sfvdl  * This code is derived from software contributed to The NetBSD Foundation
88375b2d9Sfvdl  * by Charles M. Hannum, and by Jason R. Thorpe.
98375b2d9Sfvdl  *
108375b2d9Sfvdl  * Redistribution and use in source and binary forms, with or without
118375b2d9Sfvdl  * modification, are permitted provided that the following conditions
128375b2d9Sfvdl  * are met:
138375b2d9Sfvdl  * 1. Redistributions of source code must retain the above copyright
148375b2d9Sfvdl  *    notice, this list of conditions and the following disclaimer.
158375b2d9Sfvdl  * 2. Redistributions in binary form must reproduce the above copyright
168375b2d9Sfvdl  *    notice, this list of conditions and the following disclaimer in the
178375b2d9Sfvdl  *    documentation and/or other materials provided with the distribution.
188375b2d9Sfvdl  *
198375b2d9Sfvdl  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
208375b2d9Sfvdl  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
218375b2d9Sfvdl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
228375b2d9Sfvdl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
238375b2d9Sfvdl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248375b2d9Sfvdl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258375b2d9Sfvdl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268375b2d9Sfvdl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278375b2d9Sfvdl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288375b2d9Sfvdl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298375b2d9Sfvdl  * POSSIBILITY OF SUCH DAMAGE.
308375b2d9Sfvdl  */
318375b2d9Sfvdl 
328375b2d9Sfvdl #ifndef _X86_INTR_H_
338375b2d9Sfvdl #define _X86_INTR_H_
348375b2d9Sfvdl 
354b293a84Sad #define	__HAVE_FAST_SOFTINTS
367eebc91eScherry #if !defined(NO_PREEMPTION)
37104cf0aeSad #define	__HAVE_PREEMPTION
387eebc91eScherry #endif /* !defined(NO_PREEMPTION) */
394b293a84Sad 
40a6cfb08dSdyoung #ifdef _KERNEL
41a6cfb08dSdyoung #include <sys/types.h>
42c24c993fSbouyer #include <sys/kcpuset.h>
43a6cfb08dSdyoung #else
44a6cfb08dSdyoung #include <stdbool.h>
45a6cfb08dSdyoung #endif
46a6cfb08dSdyoung 
4761cf8013Sdyoung #include <sys/evcnt.h>
48c65d622dSknakahara #include <sys/queue.h>
498375b2d9Sfvdl #include <machine/intrdefs.h>
508375b2d9Sfvdl 
51c24c993fSbouyer #ifdef XEN
52c24c993fSbouyer #include <xen/include/public/xen.h>
53c24c993fSbouyer #include <xen/include/public/event_channel.h>
54c24c993fSbouyer #endif /* XEN */
55c24c993fSbouyer 
568375b2d9Sfvdl #ifndef _LOCORE
578375b2d9Sfvdl #include <machine/pic.h>
588375b2d9Sfvdl 
598375b2d9Sfvdl /*
608375b2d9Sfvdl  * Struct describing an interrupt source for a CPU. struct cpu_info
618375b2d9Sfvdl  * has an array of MAX_INTR_SOURCES of these. The index in the array
628375b2d9Sfvdl  * is equal to the stub number of the stubcode as present in vector.s
638375b2d9Sfvdl  *
648375b2d9Sfvdl  * The primary CPU's array of interrupt sources has its first 16
658375b2d9Sfvdl  * entries reserved for legacy ISA irq handlers. This means that
668375b2d9Sfvdl  * they have a 1:1 mapping for arrayindex:irq_num. This is not
678375b2d9Sfvdl  * true for interrupts that come in through IO APICs, to find
688375b2d9Sfvdl  * their source, go through ci->ci_isources[index].is_pic
698375b2d9Sfvdl  *
708375b2d9Sfvdl  * It's possible to always maintain a 1:1 mapping, but that means
718375b2d9Sfvdl  * limiting the total number of interrupt sources to MAX_INTR_SOURCES
728375b2d9Sfvdl  * (32), instead of 32 per CPU. It also would mean that having multiple
738375b2d9Sfvdl  * IO APICs which deliver interrupts from an equal pin number would
748375b2d9Sfvdl  * overlap if they were to be sent to the same CPU.
758375b2d9Sfvdl  */
768375b2d9Sfvdl 
778375b2d9Sfvdl struct intrstub {
788375b2d9Sfvdl 	void *ist_entry;
798375b2d9Sfvdl 	void *ist_recurse;
808375b2d9Sfvdl 	void *ist_resume;
818375b2d9Sfvdl };
828375b2d9Sfvdl 
83c65d622dSknakahara struct percpu_evcnt {
84c65d622dSknakahara 	cpuid_t cpuid;
85c65d622dSknakahara 	uint64_t count;
86c65d622dSknakahara };
87c65d622dSknakahara 
888375b2d9Sfvdl struct intrsource {
898375b2d9Sfvdl 	int is_maxlevel;		/* max. IPL for this source */
900ce8c54dSdrochner 	int is_pin;			/* IRQ for legacy; pin for IO APIC,
910ce8c54dSdrochner 					   -1 for MSI */
928375b2d9Sfvdl 	struct intrhand *is_handlers;	/* handler chain */
938375b2d9Sfvdl 	struct pic *is_pic;		/* originating PIC */
948375b2d9Sfvdl 	void *is_recurse;		/* entry for spllower */
958375b2d9Sfvdl 	void *is_resume;		/* entry for doreti */
964b293a84Sad 	lwp_t *is_lwp;			/* for soft interrupts */
97eb432c68Scherry #if defined(XEN)
98eb432c68Scherry 	u_long ipl_evt_mask1;	/* pending events for this IPL */
99eb432c68Scherry 	u_long ipl_evt_mask2[NR_EVENT_CHANNELS];
100eb432c68Scherry #endif
101a604df28Sknakahara 	struct evcnt is_evcnt;		/* interrupt counter per cpu */
102b1ae49d2Sthorpej 	/*
103e82c4d9bSandvar 	 * is_mask_count requires special handling; it can only be modified
104b1ae49d2Sthorpej 	 * or examined on the CPU that owns the interrupt source, and such
105b1ae49d2Sthorpej 	 * references need to be protected by disabling interrupts.  This
106b1ae49d2Sthorpej 	 * is because intr_mask() can be called from an interrupt handler.
107b1ae49d2Sthorpej 	 * is_distribute_pending does not require such special handling
108b1ae49d2Sthorpej 	 * because intr_unmask() cannot be called from an interrupt handler.
109b1ae49d2Sthorpej 	 */
110b1ae49d2Sthorpej 	u_int is_mask_count;		/* masked? (nested) [see above] */
111b1ae49d2Sthorpej 	int is_distribute_pending;	/* ci<->ci move pending [cpu_lock] */
1128375b2d9Sfvdl 	int is_flags;			/* see below */
1138375b2d9Sfvdl 	int is_type;			/* level, edge */
1148375b2d9Sfvdl 	int is_idtvec;
1158375b2d9Sfvdl 	int is_minlevel;
1164b293a84Sad 	char is_evname[32];		/* event counter name */
117c65d622dSknakahara 	char is_intrid[INTRIDBUF];	/* intrid created by create_intrid() */
118a604df28Sknakahara 	char is_xname[INTRDEVNAMEBUF];	/* device names */
119c65d622dSknakahara 	cpuid_t is_active_cpu;		/* active cpuid */
120c65d622dSknakahara 	struct percpu_evcnt *is_saved_evcnt;	/* interrupt count of deactivated cpus */
121c65d622dSknakahara 	SIMPLEQ_ENTRY(intrsource) is_list;	/* link of intrsources */
1228375b2d9Sfvdl };
1238375b2d9Sfvdl 
1248375b2d9Sfvdl #define IS_LEGACY	0x0001		/* legacy ISA irq source */
1258375b2d9Sfvdl #define IS_IPI		0x0002
1268375b2d9Sfvdl #define IS_LOG		0x0004
1278375b2d9Sfvdl 
1288375b2d9Sfvdl /*
1298375b2d9Sfvdl  * Interrupt handler chains.  *_intr_establish() insert a handler into
1308375b2d9Sfvdl  * the list.  The handler is called with its (single) argument.
1318375b2d9Sfvdl  */
1328375b2d9Sfvdl 
1338375b2d9Sfvdl struct intrhand {
134c24c993fSbouyer 	struct pic *ih_pic;
1358375b2d9Sfvdl 	int	(*ih_fun)(void *);
1368375b2d9Sfvdl 	void	*ih_arg;
1378375b2d9Sfvdl 	int	ih_level;
138fa29ea97Syamt 	int	(*ih_realfun)(void *);
139fa29ea97Syamt 	void	*ih_realarg;
1408375b2d9Sfvdl 	struct	intrhand *ih_next;
1414d8f47aeSad 	struct	intrhand **ih_prevp;
1428375b2d9Sfvdl 	int	ih_pin;
1438375b2d9Sfvdl 	int	ih_slot;
144b1da5714Scherry #if defined(XEN)
14508d9eda9Sbouyer 	int	ih_pending;
146eb432c68Scherry 	struct	intrhand *ih_evt_next;
147eb432c68Scherry #endif
1488375b2d9Sfvdl 	struct cpu_info *ih_cpu;
1498382e30fSriastradh 	char	ih_xname[INTRDEVNAMEBUF];
1508375b2d9Sfvdl };
1518375b2d9Sfvdl 
152b8a6a61fSplunky #ifdef _KERNEL
153b8a6a61fSplunky 
154f0301095Syamt void Xspllower(int);
155f0301095Syamt void spllower(int);
156f0301095Syamt int splraise(int);
157f0301095Syamt void softintr(int);
1588375b2d9Sfvdl 
1598375b2d9Sfvdl /*
1608375b2d9Sfvdl  * Convert spl level to local APIC level
1618375b2d9Sfvdl  */
162f0301095Syamt 
1638375b2d9Sfvdl #define APIC_LEVEL(l)   ((l) << 4)
1648375b2d9Sfvdl 
1658375b2d9Sfvdl /*
1668375b2d9Sfvdl  * Miscellaneous
1678375b2d9Sfvdl  */
168f0301095Syamt 
169f0301095Syamt #define SPL_ASSERT_BELOW(x) KDASSERT(curcpu()->ci_ilevel < (x))
1708375b2d9Sfvdl #define	spl0()		spllower(IPL_NONE)
1718375b2d9Sfvdl #define	splx(x)		spllower(x)
1728375b2d9Sfvdl 
173e96fca78Sad typedef uint8_t ipl_t;
1748bf76628Syamt typedef struct {
1758bf76628Syamt 	ipl_t _ipl;
1768bf76628Syamt } ipl_cookie_t;
1778bf76628Syamt 
1788bf76628Syamt static inline ipl_cookie_t
makeiplcookie(ipl_t ipl)1798bf76628Syamt makeiplcookie(ipl_t ipl)
1808bf76628Syamt {
1818bf76628Syamt 
1828bf76628Syamt 	return (ipl_cookie_t){._ipl = ipl};
1838bf76628Syamt }
1848bf76628Syamt 
1858bf76628Syamt static inline int
splraiseipl(ipl_cookie_t icookie)1868bf76628Syamt splraiseipl(ipl_cookie_t icookie)
1878bf76628Syamt {
1888bf76628Syamt 
1898bf76628Syamt 	return splraise(icookie._ipl);
1908bf76628Syamt }
1918bf76628Syamt 
19206085e8fSyamt #include <sys/spl.h>
19306085e8fSyamt 
1948375b2d9Sfvdl /*
1958375b2d9Sfvdl  * Stub declarations.
1968375b2d9Sfvdl  */
1978375b2d9Sfvdl 
1984b293a84Sad void Xsoftintr(void);
19956c37d10Schristos void Xrecurse_preempt(void);
20056c37d10Schristos void Xresume_preempt(void);
2018375b2d9Sfvdl 
2026e7355e5Smaxv extern struct intrstub legacy_stubs[];
2032cd70f0dSfvdl extern struct intrstub ioapic_edge_stubs[];
2042cd70f0dSfvdl extern struct intrstub ioapic_level_stubs[];
2055c120a76Snonaka extern struct intrstub x2apic_edge_stubs[];
2065c120a76Snonaka extern struct intrstub x2apic_level_stubs[];
2078375b2d9Sfvdl 
2088375b2d9Sfvdl struct cpu_info;
2098375b2d9Sfvdl 
2107d342b58Sfvdl struct pcibus_attach_args;
2117d342b58Sfvdl 
21283fd2fa1Sknakahara typedef uint64_t intr_handle_t;
21383fd2fa1Sknakahara 
2148375b2d9Sfvdl void intr_default_setup(void);
2157b673ebdSdyoung void x86_nmi(void);
216a604df28Sknakahara void *intr_establish_xname(int, struct pic *, int, int, int, int (*)(void *),
217a604df28Sknakahara 			   void *, bool, const char *);
2182839301dSad void *intr_establish(int, struct pic *, int, int, int, int (*)(void *), void *, bool);
219b1ae49d2Sthorpej void intr_mask(struct intrhand *);
220b1ae49d2Sthorpej void intr_unmask(struct intrhand *);
2218375b2d9Sfvdl void intr_disestablish(struct intrhand *);
2227d342b58Sfvdl void intr_add_pcibus(struct pcibus_attach_args *);
22383fd2fa1Sknakahara const char *intr_string(intr_handle_t, char *, size_t);
2248375b2d9Sfvdl void cpu_intr_init(struct cpu_info *);
22583fd2fa1Sknakahara int intr_find_mpmapping(int, int, intr_handle_t *);
22601158ea8Schristos struct pic *intr_findpic(int);
2278375b2d9Sfvdl void intr_printconfig(void);
2288375b2d9Sfvdl 
2290d3459cfSknakahara const char *intr_create_intrid(int, struct pic *, int, char *, size_t);
230c65d622dSknakahara struct intrsource *intr_allocate_io_intrsource(const char *);
231c65d622dSknakahara void intr_free_io_intrsource(const char *);
232c65d622dSknakahara 
233c24c993fSbouyer void x86_init_preempt(struct cpu_info *);
234c24c993fSbouyer void x86_intr_calculatemasks(struct cpu_info *);
235c24c993fSbouyer 
2368375b2d9Sfvdl int x86_send_ipi(struct cpu_info *, int);
2378375b2d9Sfvdl void x86_broadcast_ipi(int);
2388375b2d9Sfvdl void x86_ipi_handler(void);
2398375b2d9Sfvdl 
240c24c993fSbouyer void x86_intr_get_devname(const char *, char *, size_t);
241c24c993fSbouyer void x86_intr_get_assigned(const char *, kcpuset_t *);
242c24c993fSbouyer uint64_t x86_intr_get_count(const char *, u_int);
243c24c993fSbouyer 
244427af037Scherry #ifndef XENPV
2458d26686dSuebayasi extern void (* const ipifunc[X86_NIPI])(struct cpu_info *);
246eb432c68Scherry #endif
2478375b2d9Sfvdl 
248b8a6a61fSplunky #endif /* _KERNEL */
249b8a6a61fSplunky 
2508375b2d9Sfvdl #endif /* !_LOCORE */
2518375b2d9Sfvdl 
2528375b2d9Sfvdl #endif /* !_X86_INTR_H_ */
253