aboutsummaryrefslogtreecommitdiff
path: root/sys/sys/interrupt.h
blob: f1770fe64b0b22016f8027c63c4e9ee3d3a0a38b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*-
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
 *
 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#ifndef _SYS_INTERRUPT_H_
#define _SYS_INTERRUPT_H_

#include <sys/_lock.h>
#include <sys/_mutex.h>
#include <sys/ck.h>

struct intr_event;
struct intr_thread;
struct trapframe;

/*
 * Describe a hardware interrupt handler.
 *
 * Multiple interrupt handlers for a specific event can be chained
 * together.
 */
struct intr_handler {
	driver_filter_t	*ih_filter;	/* Filter handler function. */
	driver_intr_t	*ih_handler;	/* Threaded handler function. */
	void		*ih_argument;	/* Argument to pass to handlers. */
	int		 ih_flags;
	char		 ih_name[MAXCOMLEN + 1]; /* Name of handler. */
	struct intr_event *ih_event;	/* Event we are connected to. */
	int		 ih_need;	/* Needs service. */
	CK_SLIST_ENTRY(intr_handler) ih_next; /* Next handler for this event. */
	u_char		 ih_pri;	/* Priority of this handler. */
};

/* Interrupt handle flags kept in ih_flags */
#define	IH_NET		0x00000001	/* Network. */
#define	IH_EXCLUSIVE	0x00000002	/* Exclusive interrupt. */
#define	IH_ENTROPY	0x00000004	/* Device is a good entropy source. */
#define	IH_DEAD		0x00000008	/* Handler should be removed. */
#define	IH_SUSP		0x00000010	/* Device is powered down. */
#define	IH_CHANGED	0x40000000	/* Handler state is changed. */
#define	IH_MPSAFE	0x80000000	/* Handler does not need Giant. */

/*
 * Describe an interrupt event.  An event holds a list of handlers.
 * The 'pre_ithread', 'post_ithread', 'post_filter', and 'assign_cpu'
 * hooks are used to invoke MD code for certain operations.
 *
 * The 'pre_ithread' hook is called when an interrupt thread for
 * handlers without filters is scheduled.  It is responsible for
 * ensuring that 1) the system won't be swamped with an interrupt
 * storm from the associated source while the ithread runs and 2) the
 * current CPU is able to receive interrupts from other interrupt
 * sources.  The first is usually accomplished by disabling
 * level-triggered interrupts until the ithread completes.  The second
 * is accomplished on some platforms by acknowledging the interrupt
 * via an EOI.
 *
 * The 'post_ithread' hook is invoked when an ithread finishes.  It is
 * responsible for ensuring that the associated interrupt source will
 * trigger an interrupt when it is asserted in the future.  Usually
 * this is implemented by enabling a level-triggered interrupt that
 * was previously disabled via the 'pre_ithread' hook.
 *
 * The 'post_filter' hook is invoked when a filter handles an
 * interrupt.  It is responsible for ensuring that the current CPU is
 * able to receive interrupts again.  On some platforms this is done
 * by acknowledging the interrupts via an EOI.
 *
 * The 'assign_cpu' hook is used to bind an interrupt source to a
 * specific CPU.  If the interrupt cannot be bound, this function may
 * return an error.
 *
 * Note that device drivers may also use interrupt events to manage
 * multiplexing interrupt interrupt handler into handlers for child
 * devices.  In that case, the above hooks are not used.  The device
 * can create an event for its interrupt resource and register child
 * event handlers with that event.  It can then use
 * intr_event_execute_handlers() to execute non-filter handlers.
 * Currently filter handlers are not supported by this, but that can
 * be added by splitting out the filter loop from intr_event_handle()
 * if desired.
 */
struct intr_event {
	TAILQ_ENTRY(intr_event) ie_list;
	CK_SLIST_HEAD(, intr_handler) ie_handlers; /* Interrupt handlers. */
	char		ie_name[MAXCOMLEN + 1]; /* Individual event name. */
	char		ie_fullname[MAXCOMLEN + 1];
	struct mtx	ie_lock;
	void		*ie_source;	/* Cookie used by MD code. */
	struct intr_thread *ie_thread;	/* Thread we are connected to. */
	void		(*ie_pre_ithread)(void *);
	void		(*ie_post_ithread)(void *);
	void		(*ie_post_filter)(void *);
	int		(*ie_assign_cpu)(void *, int);
	int		ie_flags;
	int		ie_hflags;	/* Cumulative flags of all handlers. */
	int		ie_count;	/* Loop counter. */
	int		ie_warncnt;	/* Rate-check interrupt storm warns. */
	struct timeval	ie_warntm;
	int		ie_irq;		/* Physical irq number if !SOFT. */
	int		ie_cpu;		/* CPU this event is bound to. */
	volatile int	ie_phase;	/* Switched to establish a barrier. */
	volatile int	ie_active[2];	/* Filters in ISR context. */
};

/* Interrupt event flags kept in ie_flags. */
#define	IE_SOFT		0x000001	/* Software interrupt. */
#define	IE_ADDING_THREAD 0x000004	/* Currently building an ithread. */

/* Flags to pass to swi_sched. */
#define	SWI_FROMNMI	0x1
#define	SWI_DELAY	0x2

/*
 * Software interrupt numbers in priority order.  The priority determines
 * the priority of the corresponding interrupt thread.
 */
#define	SWI_TTY		0
#define	SWI_NET		1
#define	SWI_CAMBIO	2
#define	SWI_VM		3
#define	SWI_CLOCK	4
#define	SWI_TQ_FAST	5
#define	SWI_TQ		6
#define	SWI_TQ_GIANT	6

struct proc;

extern struct	intr_event *clk_intr_event;
extern struct	intr_event *tty_intr_event;
extern void	*vm_ih;

/* Counts and names for statistics (defined in MD code). */
extern u_long 	*intrcnt;	/* counts for for each device and stray */
extern char 	*intrnames;	/* string table containing device names */
extern size_t	sintrcnt;	/* size of intrcnt table */
extern size_t	sintrnames;	/* size of intrnames table */

#ifdef DDB
void	db_dump_intr_event(struct intr_event *ie, int handlers);
#endif
u_char	intr_priority(enum intr_type flags);
int	intr_event_add_handler(struct intr_event *ie, const char *name,
	    driver_filter_t filter, driver_intr_t handler, void *arg, 
	    u_char pri, enum intr_type flags, void **cookiep);	    
int	intr_event_bind(struct intr_event *ie, int cpu);
int	intr_event_bind_irqonly(struct intr_event *ie, int cpu);
int	intr_event_bind_ithread(struct intr_event *ie, int cpu);
struct _cpuset;
int	intr_event_bind_ithread_cpuset(struct intr_event *ie,
	    struct _cpuset *mask);
int	intr_event_create(struct intr_event **event, void *source,
	    int flags, int irq, void (*pre_ithread)(void *),
	    void (*post_ithread)(void *), void (*post_filter)(void *),
	    int (*assign_cpu)(void *, int), const char *fmt, ...)
	    __printflike(9, 10);
int	intr_event_describe_handler(struct intr_event *ie, void *cookie,
	    const char *descr);
int	intr_event_destroy(struct intr_event *ie);
int	intr_event_handle(struct intr_event *ie, struct trapframe *frame);
int	intr_event_remove_handler(void *cookie);
int	intr_event_suspend_handler(void *cookie);
int	intr_event_resume_handler(void *cookie);
int	intr_getaffinity(int irq, int mode, void *mask);
void	*intr_handler_source(void *cookie);
int	intr_setaffinity(int irq, int mode, void *mask);
void	_intr_drain(int irq);  /* Linux compat only. */
int	swi_add(struct intr_event **eventp, const char *name,
	    driver_intr_t handler, void *arg, int pri, enum intr_type flags,
	    void **cookiep);
void	swi_sched(void *cookie, int flags);
int	swi_remove(void *cookie);

#endif