1139825Simp/*-
226156Sse * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
326156Sse * All rights reserved.
426156Sse *
526156Sse * Redistribution and use in source and binary forms, with or without
626156Sse * modification, are permitted provided that the following conditions
726156Sse * are met:
826156Sse * 1. Redistributions of source code must retain the above copyright
926156Sse *    notice unmodified, this list of conditions, and the following
1026156Sse *    disclaimer.
1126156Sse * 2. Redistributions in binary form must reproduce the above copyright
1226156Sse *    notice, this list of conditions and the following disclaimer in the
1326156Sse *    documentation and/or other materials provided with the distribution.
1426156Sse *
1526156Sse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1626156Sse * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1726156Sse * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1826156Sse * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1926156Sse * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2026156Sse * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2126156Sse * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2226156Sse * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2326156Sse * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2426156Sse * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2526156Sse *
2650477Speter * $FreeBSD$
2726156Sse */
2826156Sse
2945897Speter#ifndef _SYS_INTERRUPT_H_
3045897Speter#define _SYS_INTERRUPT_H_
3126380Sdfr
3276771Sjhb#include <sys/_lock.h>
3376771Sjhb#include <sys/_mutex.h>
3476771Sjhb
35151658Sjhbstruct intr_event;
36151658Sjhbstruct intr_thread;
37166901Spisostruct trapframe;
38151658Sjhb
3965822Sjhb/*
4065822Sjhb * Describe a hardware interrupt handler.
4165822Sjhb *
42151658Sjhb * Multiple interrupt handlers for a specific event can be chained
4372237Sjhb * together.
4465822Sjhb */
45151658Sjhbstruct intr_handler {
46192451Sjhb	driver_filter_t	*ih_filter;	/* Filter handler function. */
47192451Sjhb	driver_intr_t	*ih_handler;	/* Threaded handler function. */
48192451Sjhb	void		*ih_argument;	/* Argument to pass to handlers. */
4972237Sjhb	int		 ih_flags;
50198411Sjhb	char		 ih_name[MAXCOMLEN + 1]; /* Name of handler. */
51151658Sjhb	struct intr_event *ih_event;	/* Event we are connected to. */
5272237Sjhb	int		 ih_need;	/* Needs service. */
53151658Sjhb	TAILQ_ENTRY(intr_handler) ih_next; /* Next handler for this event. */
5472237Sjhb	u_char		 ih_pri;	/* Priority of this handler. */
55169320Spiso	struct intr_thread *ih_thread;	/* Ithread for filtered handler. */
5672237Sjhb};
5765822Sjhb
5872237Sjhb/* Interrupt handle flags kept in ih_flags */
5972237Sjhb#define	IH_EXCLUSIVE	0x00000002	/* Exclusive interrupt. */
6072237Sjhb#define	IH_ENTROPY	0x00000004	/* Device is a good entropy source. */
6172839Sjhb#define	IH_DEAD		0x00000008	/* Handler should be removed. */
6272237Sjhb#define	IH_MPSAFE	0x80000000	/* Handler does not need Giant. */
6372237Sjhb
6472237Sjhb/*
65151658Sjhb * Describe an interrupt event.  An event holds a list of handlers.
66177940Sjhb * The 'pre_ithread', 'post_ithread', 'post_filter', and 'assign_cpu'
67177940Sjhb * hooks are used to invoke MD code for certain operations.
68177940Sjhb *
69177940Sjhb * The 'pre_ithread' hook is called when an interrupt thread for
70177940Sjhb * handlers without filters is scheduled.  It is responsible for
71177940Sjhb * ensuring that 1) the system won't be swamped with an interrupt
72177940Sjhb * storm from the associated source while the ithread runs and 2) the
73177940Sjhb * current CPU is able to receive interrupts from other interrupt
74177940Sjhb * sources.  The first is usually accomplished by disabling
75177940Sjhb * level-triggered interrupts until the ithread completes.  The second
76177940Sjhb * is accomplished on some platforms by acknowledging the interrupt
77177940Sjhb * via an EOI.
78177940Sjhb *
79177940Sjhb * The 'post_ithread' hook is invoked when an ithread finishes.  It is
80177940Sjhb * responsible for ensuring that the associated interrupt source will
81177940Sjhb * trigger an interrupt when it is asserted in the future.  Usually
82177940Sjhb * this is implemented by enabling a level-triggered interrupt that
83177940Sjhb * was previously disabled via the 'pre_ithread' hook.
84177940Sjhb *
85177940Sjhb * The 'post_filter' hook is invoked when a filter handles an
86177940Sjhb * interrupt.  It is responsible for ensuring that the current CPU is
87177940Sjhb * able to receive interrupts again.  On some platforms this is done
88177940Sjhb * by acknowledging the interrupts via an EOI.
89177940Sjhb *
90177940Sjhb * The 'assign_cpu' hook is used to bind an interrupt source to a
91177940Sjhb * specific CPU.  If the interrupt cannot be bound, this function may
92177940Sjhb * return an error.
93183052Sjhb *
94183052Sjhb * Note that device drivers may also use interrupt events to manage
95183052Sjhb * multiplexing interrupt interrupt handler into handlers for child
96183052Sjhb * devices.  In that case, the above hooks are not used.  The device
97183052Sjhb * can create an event for its interrupt resource and register child
98183052Sjhb * event handlers with that event.  It can then use
99183052Sjhb * intr_event_execute_handlers() to execute non-filter handlers.
100183052Sjhb * Currently filter handlers are not supported by this, but that can
101183052Sjhb * be added by splitting out the filter loop from intr_event_handle()
102183052Sjhb * if desired.
10372237Sjhb */
104151658Sjhbstruct intr_event {
105151658Sjhb	TAILQ_ENTRY(intr_event) ie_list;
106151658Sjhb	TAILQ_HEAD(, intr_handler) ie_handlers; /* Interrupt handlers. */
107198411Sjhb	char		ie_name[MAXCOMLEN + 1]; /* Individual event name. */
108198411Sjhb	char		ie_fullname[MAXCOMLEN + 1];
109151658Sjhb	struct mtx	ie_lock;
110151658Sjhb	void		*ie_source;	/* Cookie used by MD code. */
111151658Sjhb	struct intr_thread *ie_thread;	/* Thread we are connected to. */
112177940Sjhb	void		(*ie_pre_ithread)(void *);
113177940Sjhb	void		(*ie_post_ithread)(void *);
114177940Sjhb	void		(*ie_post_filter)(void *);
115177181Sjhb	int		(*ie_assign_cpu)(void *, u_char);
116151658Sjhb	int		ie_flags;
117151658Sjhb	int		ie_count;	/* Loop counter. */
118168850Snjl	int		ie_warncnt;	/* Rate-check interrupt storm warns. */
119168850Snjl	struct timeval	ie_warntm;
120178092Sjeff	int		ie_irq;		/* Physical irq number if !SOFT. */
121177181Sjhb	u_char		ie_cpu;		/* CPU this event is bound to. */
12265822Sjhb};
12365822Sjhb
124151658Sjhb/* Interrupt event flags kept in ie_flags. */
125151658Sjhb#define	IE_SOFT		0x000001	/* Software interrupt. */
126151658Sjhb#define	IE_ENTROPY	0x000002	/* Interrupt is an entropy source. */
127151658Sjhb#define	IE_ADDING_THREAD 0x000004	/* Currently building an ithread. */
12872237Sjhb
12972237Sjhb/* Flags to pass to sched_swi. */
13088900Sjhb#define	SWI_DELAY	0x2
13138244Sbde
13276057Sjhb/*
133131244Sjhb * Software interrupt numbers in priority order.  The priority determines
134131244Sjhb * the priority of the corresponding interrupt thread.
13576057Sjhb */
13676057Sjhb#define	SWI_TTY		0
13776057Sjhb#define	SWI_NET		1
138136134Sscottl#define	SWI_CAMBIO	2
139136134Sscottl#define	SWI_VM		3
140136134Sscottl#define	SWI_CLOCK	4
141136134Sscottl#define	SWI_TQ_FAST	5
142131244Sjhb#define	SWI_TQ		6
143119789Ssam#define	SWI_TQ_GIANT	6
14476057Sjhb
145183052Sjhbstruct proc;
146183052Sjhb
147151658Sjhbextern struct	intr_event *tty_intr_event;
148151658Sjhbextern struct	intr_event *clk_intr_event;
14972237Sjhbextern void	*vm_ih;
15066698Sjhb
15177582Stmm/* Counts and names for statistics (defined in MD code). */
15277582Stmmextern u_long 	intrcnt[];	/* counts for for each device and stray */
15377582Stmmextern char 	intrnames[];	/* string table containing device names */
154224187Sattilioextern size_t	sintrcnt;	/* size of intrcnt table */
155224187Sattilioextern size_t	sintrnames;	/* size of intrnames table */
15677582Stmm
157121482Sjhb#ifdef DDB
158151658Sjhbvoid	db_dump_intr_event(struct intr_event *ie, int handlers);
159121482Sjhb#endif
160151658Sjhbu_char	intr_priority(enum intr_type flags);
161151658Sjhbint	intr_event_add_handler(struct intr_event *ie, const char *name,
162166901Spiso	    driver_filter_t filter, driver_intr_t handler, void *arg,
163166901Spiso	    u_char pri, enum intr_type flags, void **cookiep);
164177181Sjhbint	intr_event_bind(struct intr_event *ie, u_char cpu);
165151658Sjhbint	intr_event_create(struct intr_event **event, void *source,
166178092Sjeff	    int flags, int irq, void (*pre_ithread)(void *),
167177940Sjhb	    void (*post_ithread)(void *), void (*post_filter)(void *),
168177940Sjhb	    int (*assign_cpu)(void *, u_char), const char *fmt, ...)
169178092Sjeff	    __printflike(9, 10);
170198391Sjhbint	intr_event_describe_handler(struct intr_event *ie, void *cookie,
171198391Sjhb	    const char *descr);
172151658Sjhbint	intr_event_destroy(struct intr_event *ie);
173183052Sjhbvoid	intr_event_execute_handlers(struct proc *p, struct intr_event *ie);
174177940Sjhbint	intr_event_handle(struct intr_event *ie, struct trapframe *frame);
175151658Sjhbint	intr_event_remove_handler(void *cookie);
176178092Sjeffint	intr_getaffinity(int irq, void *mask);
177165125Sjhbvoid	*intr_handler_source(void *cookie);
178178092Sjeffint	intr_setaffinity(int irq, void *mask);
179219819Sjeffvoid	_intr_drain(int irq);  /* Linux compat only. */
180151658Sjhbint	swi_add(struct intr_event **eventp, const char *name,
18172237Sjhb	    driver_intr_t handler, void *arg, int pri, enum intr_type flags,
18292719Salfred	    void **cookiep);
18392719Salfredvoid	swi_sched(void *cookie, int flags);
184151699Sjhbint	swi_remove(void *cookie);
18538244Sbde
18638244Sbde#endif
187