xref: /f-stack/freebsd/sys/interrupt.h (revision 22ce4aff)
1a9643ea8Slogwang /*-
2*22ce4affSfengbojiang  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*22ce4affSfengbojiang  *
4a9643ea8Slogwang  * Copyright (c) 1997, Stefan Esser <[email protected]>
5a9643ea8Slogwang  * All rights reserved.
6a9643ea8Slogwang  *
7a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
8a9643ea8Slogwang  * modification, are permitted provided that the following conditions
9a9643ea8Slogwang  * are met:
10a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
11a9643ea8Slogwang  *    notice unmodified, this list of conditions, and the following
12a9643ea8Slogwang  *    disclaimer.
13a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
14a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
15a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
16a9643ea8Slogwang  *
17a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18a9643ea8Slogwang  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19a9643ea8Slogwang  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20a9643ea8Slogwang  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21a9643ea8Slogwang  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22a9643ea8Slogwang  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a9643ea8Slogwang  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a9643ea8Slogwang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a9643ea8Slogwang  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26a9643ea8Slogwang  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a9643ea8Slogwang  *
28a9643ea8Slogwang  * $FreeBSD$
29a9643ea8Slogwang  */
30a9643ea8Slogwang 
31a9643ea8Slogwang #ifndef _SYS_INTERRUPT_H_
32a9643ea8Slogwang #define _SYS_INTERRUPT_H_
33a9643ea8Slogwang 
34a9643ea8Slogwang #include <sys/_lock.h>
35a9643ea8Slogwang #include <sys/_mutex.h>
36*22ce4affSfengbojiang #include <sys/ck.h>
37a9643ea8Slogwang 
38a9643ea8Slogwang struct intr_event;
39a9643ea8Slogwang struct intr_thread;
40a9643ea8Slogwang struct trapframe;
41a9643ea8Slogwang 
42a9643ea8Slogwang /*
43a9643ea8Slogwang  * Describe a hardware interrupt handler.
44a9643ea8Slogwang  *
45a9643ea8Slogwang  * Multiple interrupt handlers for a specific event can be chained
46a9643ea8Slogwang  * together.
47a9643ea8Slogwang  */
48a9643ea8Slogwang struct intr_handler {
49a9643ea8Slogwang 	driver_filter_t	*ih_filter;	/* Filter handler function. */
50a9643ea8Slogwang 	driver_intr_t	*ih_handler;	/* Threaded handler function. */
51a9643ea8Slogwang 	void		*ih_argument;	/* Argument to pass to handlers. */
52a9643ea8Slogwang 	int		 ih_flags;
53a9643ea8Slogwang 	char		 ih_name[MAXCOMLEN + 1]; /* Name of handler. */
54a9643ea8Slogwang 	struct intr_event *ih_event;	/* Event we are connected to. */
55a9643ea8Slogwang 	int		 ih_need;	/* Needs service. */
56*22ce4affSfengbojiang 	CK_SLIST_ENTRY(intr_handler) ih_next; /* Next handler for this event. */
57a9643ea8Slogwang 	u_char		 ih_pri;	/* Priority of this handler. */
58a9643ea8Slogwang };
59a9643ea8Slogwang 
60a9643ea8Slogwang /* Interrupt handle flags kept in ih_flags */
61*22ce4affSfengbojiang #define	IH_NET		0x00000001	/* Network. */
62a9643ea8Slogwang #define	IH_EXCLUSIVE	0x00000002	/* Exclusive interrupt. */
63a9643ea8Slogwang #define	IH_ENTROPY	0x00000004	/* Device is a good entropy source. */
64a9643ea8Slogwang #define	IH_DEAD		0x00000008	/* Handler should be removed. */
65*22ce4affSfengbojiang #define	IH_SUSP		0x00000010	/* Device is powered down. */
66*22ce4affSfengbojiang #define	IH_CHANGED	0x40000000	/* Handler state is changed. */
67a9643ea8Slogwang #define	IH_MPSAFE	0x80000000	/* Handler does not need Giant. */
68a9643ea8Slogwang 
69a9643ea8Slogwang /*
70a9643ea8Slogwang  * Describe an interrupt event.  An event holds a list of handlers.
71a9643ea8Slogwang  * The 'pre_ithread', 'post_ithread', 'post_filter', and 'assign_cpu'
72a9643ea8Slogwang  * hooks are used to invoke MD code for certain operations.
73a9643ea8Slogwang  *
74a9643ea8Slogwang  * The 'pre_ithread' hook is called when an interrupt thread for
75a9643ea8Slogwang  * handlers without filters is scheduled.  It is responsible for
76a9643ea8Slogwang  * ensuring that 1) the system won't be swamped with an interrupt
77a9643ea8Slogwang  * storm from the associated source while the ithread runs and 2) the
78a9643ea8Slogwang  * current CPU is able to receive interrupts from other interrupt
79a9643ea8Slogwang  * sources.  The first is usually accomplished by disabling
80a9643ea8Slogwang  * level-triggered interrupts until the ithread completes.  The second
81a9643ea8Slogwang  * is accomplished on some platforms by acknowledging the interrupt
82a9643ea8Slogwang  * via an EOI.
83a9643ea8Slogwang  *
84a9643ea8Slogwang  * The 'post_ithread' hook is invoked when an ithread finishes.  It is
85a9643ea8Slogwang  * responsible for ensuring that the associated interrupt source will
86a9643ea8Slogwang  * trigger an interrupt when it is asserted in the future.  Usually
87a9643ea8Slogwang  * this is implemented by enabling a level-triggered interrupt that
88a9643ea8Slogwang  * was previously disabled via the 'pre_ithread' hook.
89a9643ea8Slogwang  *
90a9643ea8Slogwang  * The 'post_filter' hook is invoked when a filter handles an
91a9643ea8Slogwang  * interrupt.  It is responsible for ensuring that the current CPU is
92a9643ea8Slogwang  * able to receive interrupts again.  On some platforms this is done
93a9643ea8Slogwang  * by acknowledging the interrupts via an EOI.
94a9643ea8Slogwang  *
95a9643ea8Slogwang  * The 'assign_cpu' hook is used to bind an interrupt source to a
96a9643ea8Slogwang  * specific CPU.  If the interrupt cannot be bound, this function may
97a9643ea8Slogwang  * return an error.
98a9643ea8Slogwang  *
99a9643ea8Slogwang  * Note that device drivers may also use interrupt events to manage
100a9643ea8Slogwang  * multiplexing interrupt interrupt handler into handlers for child
101a9643ea8Slogwang  * devices.  In that case, the above hooks are not used.  The device
102a9643ea8Slogwang  * can create an event for its interrupt resource and register child
103a9643ea8Slogwang  * event handlers with that event.  It can then use
104a9643ea8Slogwang  * intr_event_execute_handlers() to execute non-filter handlers.
105a9643ea8Slogwang  * Currently filter handlers are not supported by this, but that can
106a9643ea8Slogwang  * be added by splitting out the filter loop from intr_event_handle()
107a9643ea8Slogwang  * if desired.
108a9643ea8Slogwang  */
109a9643ea8Slogwang struct intr_event {
110a9643ea8Slogwang 	TAILQ_ENTRY(intr_event) ie_list;
111*22ce4affSfengbojiang 	CK_SLIST_HEAD(, intr_handler) ie_handlers; /* Interrupt handlers. */
112a9643ea8Slogwang 	char		ie_name[MAXCOMLEN + 1]; /* Individual event name. */
113a9643ea8Slogwang 	char		ie_fullname[MAXCOMLEN + 1];
114a9643ea8Slogwang 	struct mtx	ie_lock;
115a9643ea8Slogwang 	void		*ie_source;	/* Cookie used by MD code. */
116a9643ea8Slogwang 	struct intr_thread *ie_thread;	/* Thread we are connected to. */
117a9643ea8Slogwang 	void		(*ie_pre_ithread)(void *);
118a9643ea8Slogwang 	void		(*ie_post_ithread)(void *);
119a9643ea8Slogwang 	void		(*ie_post_filter)(void *);
120a9643ea8Slogwang 	int		(*ie_assign_cpu)(void *, int);
121a9643ea8Slogwang 	int		ie_flags;
122*22ce4affSfengbojiang 	int		ie_hflags;	/* Cumulative flags of all handlers. */
123a9643ea8Slogwang 	int		ie_count;	/* Loop counter. */
124a9643ea8Slogwang 	int		ie_warncnt;	/* Rate-check interrupt storm warns. */
125a9643ea8Slogwang 	struct timeval	ie_warntm;
126a9643ea8Slogwang 	int		ie_irq;		/* Physical irq number if !SOFT. */
127a9643ea8Slogwang 	int		ie_cpu;		/* CPU this event is bound to. */
128*22ce4affSfengbojiang 	volatile int	ie_phase;	/* Switched to establish a barrier. */
129*22ce4affSfengbojiang 	volatile int	ie_active[2];	/* Filters in ISR context. */
130a9643ea8Slogwang };
131a9643ea8Slogwang 
132a9643ea8Slogwang /* Interrupt event flags kept in ie_flags. */
133a9643ea8Slogwang #define	IE_SOFT		0x000001	/* Software interrupt. */
134a9643ea8Slogwang #define	IE_ADDING_THREAD 0x000004	/* Currently building an ithread. */
135a9643ea8Slogwang 
136*22ce4affSfengbojiang /* Flags to pass to swi_sched. */
137*22ce4affSfengbojiang #define	SWI_FROMNMI	0x1
138a9643ea8Slogwang #define	SWI_DELAY	0x2
139a9643ea8Slogwang 
140a9643ea8Slogwang /*
141a9643ea8Slogwang  * Software interrupt numbers in priority order.  The priority determines
142a9643ea8Slogwang  * the priority of the corresponding interrupt thread.
143a9643ea8Slogwang  */
144a9643ea8Slogwang #define	SWI_TTY		0
145a9643ea8Slogwang #define	SWI_NET		1
146a9643ea8Slogwang #define	SWI_CAMBIO	2
147a9643ea8Slogwang #define	SWI_VM		3
148a9643ea8Slogwang #define	SWI_CLOCK	4
149a9643ea8Slogwang #define	SWI_TQ_FAST	5
150a9643ea8Slogwang #define	SWI_TQ		6
151a9643ea8Slogwang #define	SWI_TQ_GIANT	6
152a9643ea8Slogwang 
153a9643ea8Slogwang struct proc;
154a9643ea8Slogwang 
155a9643ea8Slogwang extern struct	intr_event *clk_intr_event;
156*22ce4affSfengbojiang extern struct	intr_event *tty_intr_event;
157a9643ea8Slogwang extern void	*vm_ih;
158a9643ea8Slogwang 
159a9643ea8Slogwang /* Counts and names for statistics (defined in MD code). */
160*22ce4affSfengbojiang extern u_long 	*intrcnt;	/* counts for for each device and stray */
161*22ce4affSfengbojiang extern char 	*intrnames;	/* string table containing device names */
162a9643ea8Slogwang extern size_t	sintrcnt;	/* size of intrcnt table */
163a9643ea8Slogwang extern size_t	sintrnames;	/* size of intrnames table */
164a9643ea8Slogwang 
165a9643ea8Slogwang #ifdef DDB
166a9643ea8Slogwang void	db_dump_intr_event(struct intr_event *ie, int handlers);
167a9643ea8Slogwang #endif
168a9643ea8Slogwang u_char	intr_priority(enum intr_type flags);
169a9643ea8Slogwang int	intr_event_add_handler(struct intr_event *ie, const char *name,
170a9643ea8Slogwang 	    driver_filter_t filter, driver_intr_t handler, void *arg,
171a9643ea8Slogwang 	    u_char pri, enum intr_type flags, void **cookiep);
172a9643ea8Slogwang int	intr_event_bind(struct intr_event *ie, int cpu);
173*22ce4affSfengbojiang int	intr_event_bind_irqonly(struct intr_event *ie, int cpu);
174*22ce4affSfengbojiang int	intr_event_bind_ithread(struct intr_event *ie, int cpu);
175*22ce4affSfengbojiang struct _cpuset;
176*22ce4affSfengbojiang int	intr_event_bind_ithread_cpuset(struct intr_event *ie,
177*22ce4affSfengbojiang 	    struct _cpuset *mask);
178a9643ea8Slogwang int	intr_event_create(struct intr_event **event, void *source,
179a9643ea8Slogwang 	    int flags, int irq, void (*pre_ithread)(void *),
180a9643ea8Slogwang 	    void (*post_ithread)(void *), void (*post_filter)(void *),
181a9643ea8Slogwang 	    int (*assign_cpu)(void *, int), const char *fmt, ...)
182a9643ea8Slogwang 	    __printflike(9, 10);
183a9643ea8Slogwang int	intr_event_describe_handler(struct intr_event *ie, void *cookie,
184a9643ea8Slogwang 	    const char *descr);
185a9643ea8Slogwang int	intr_event_destroy(struct intr_event *ie);
186a9643ea8Slogwang int	intr_event_handle(struct intr_event *ie, struct trapframe *frame);
187a9643ea8Slogwang int	intr_event_remove_handler(void *cookie);
188*22ce4affSfengbojiang int	intr_event_suspend_handler(void *cookie);
189*22ce4affSfengbojiang int	intr_event_resume_handler(void *cookie);
190*22ce4affSfengbojiang int	intr_getaffinity(int irq, int mode, void *mask);
191a9643ea8Slogwang void	*intr_handler_source(void *cookie);
192*22ce4affSfengbojiang int	intr_setaffinity(int irq, int mode, void *mask);
193a9643ea8Slogwang void	_intr_drain(int irq);  /* Linux compat only. */
194a9643ea8Slogwang int	swi_add(struct intr_event **eventp, const char *name,
195a9643ea8Slogwang 	    driver_intr_t handler, void *arg, int pri, enum intr_type flags,
196a9643ea8Slogwang 	    void **cookiep);
197a9643ea8Slogwang void	swi_sched(void *cookie, int flags);
198a9643ea8Slogwang int	swi_remove(void *cookie);
199a9643ea8Slogwang 
200a9643ea8Slogwang #endif
201