Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / sys / kern / irq.c @ 03e9c04a

History | View | Annotate | Download (6.29 KB)

1
/*-
2
 * Copyright (c) 2005-2007, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29

    
30
/*
31
 * irq.c - interrupt request management routines.
32
 */
33

    
34
/**
35
 * We define the following two different types of interrupt services
36
 * in order to improve real-time performance.
37
 *
38
 * - Interrupt Service Routine (ISR)
39
 *
40
 *  ISR is started by an actual hardware interrupt. The associated
41
 *  interrupt is disabled in Interrupt Control Unit (ICU), and CPU
42
 *  interrupt is enabled while ISR runs.
43
 *  If ISR determines that the corresponding device generated the
44
 *  interrupt, ISR must program the device to stop that interrupt.
45
 *  Then, ISR should do minimum I/O operation and return control as
46
 *  quickly as possible. ISR will run within a context of the thread
47
 *  running when interrupt occurs. So, only few kernel services are
48
 *  available within ISR.
49
 *
50
 * - Interrupt Service Thread (IST)
51
 *
52
 *  IST is automatically activated if ISR returns INT_CONTINUE. It
53
 *  will be called when the system enters safer condition than ISR.
54
 *  A device driver should use IST to do heavy I/O operation as much
55
 *  as possible. Since ISR for the same IRQ line may be invoked during
56
 *  IST, the shared data, resources, and device registers must be
57
 *  synchronized by disabling interrupts. IST does not have to be
58
 *  reentrant because it is not interrupted by same IST itself.
59
 */
60

    
61
#include <kernel.h>
62
#include <event.h>
63
#include <kmem.h>
64
#include <sched.h>
65
#include <thread.h>
66
#include <irq.h>
67
#include <hal.h>
68

    
69
/* forward declarations */
70
static void        irq_thread(void *);
71

    
72
static struct irq        *irq_table[MAXIRQS];        /* IRQ descriptor table */
73

    
74
/*
75
 * irq_attach - attach ISR and IST to the specified interrupt.
76
 *
77
 * Returns irq handle, or panic on failure.  The interrupt of
78
 * attached irq will be unmasked (enabled) in this routine.
79
 * TODO: Interrupt sharing is not supported, for now.
80
 */
81
irq_t
82
irq_attach(int vector, int pri, int shared,
83
           int (*isr)(void *), void (*ist)(void *), void *data)
84
{
85
        struct irq *irq;
86
        int mode;
87

    
88
        ASSERT(isr != NULL);
89

    
90
        sched_lock();
91
        if ((irq = kmem_alloc(sizeof(*irq))) == NULL)
92
                panic("irq_attach");
93

    
94
        memset(irq, 0, sizeof(*irq));
95
        irq->vector = vector;
96
        irq->priority = pri;
97
        irq->isr = isr;
98
        irq->ist = ist;
99
        irq->data = data;
100

    
101
        if (ist != IST_NONE) {
102
                /*
103
                 * Create a new thread for IST.
104
                 */
105
                irq->thread = kthread_create(&irq_thread, irq, ISTPRI(pri));
106
                if (irq->thread == NULL)
107
                        panic("irq_attach");
108

    
109
                event_init(&irq->istevt, "interrupt");
110
        }
111
        irq_table[vector] = irq;
112
        mode = shared ? IMODE_LEVEL : IMODE_EDGE;
113
        interrupt_setup(vector, mode);
114
        interrupt_unmask(vector, pri);
115

    
116
        sched_unlock();
117
        DPRINTF(("IRQ%d attached priority=%d\n", vector, pri));
118
        return irq;
119
}
120

    
121
/*
122
 * Detach an interrupt handler from the interrupt chain.
123
 * The detached interrupt will be masked off if nobody
124
 * attaches to it, anymore.
125
 */
126
void
127
irq_detach(irq_t irq)
128
{
129
        ASSERT(irq != NULL);
130
        ASSERT(irq->vector < MAXIRQS);
131

    
132
        interrupt_mask(irq->vector);
133
        irq_table[irq->vector] = NULL;
134
        if (irq->thread != NULL)
135
                kthread_terminate(irq->thread);
136

    
137
        kmem_free(irq);
138
}
139

    
140
/*
141
 * Interrupt service thread.
142
 * This is a common dispatcher to all interrupt threads.
143
 */
144
static void
145
irq_thread(void *arg)
146
{
147
        void (*fn)(void *);
148
        void *data;
149
        struct irq *irq;
150

    
151
        splhigh();
152

    
153
        irq = (struct irq *)arg;
154
        fn = irq->ist;
155
        data = irq->data;
156

    
157
        for (;;) {
158
                if (irq->istreq <= 0) {
159
                        /*
160
                         * Since the interrupt is disabled above,
161
                         * an interrupt for this vector keeps
162
                         * pending until this thread enters sleep
163
                         * state. Thus, we don't lose any IST
164
                         * requests even if the interrupt is fired
165
                         * here.
166
                         */
167
                        sched_sleep(&irq->istevt);
168
                }
169
                irq->istreq--;
170
                ASSERT(irq->istreq >= 0);
171

    
172
                /*
173
                 * Call IST
174
                 */
175
                spl0();
176
                (*fn)(data);
177
                splhigh();
178
        }
179
        /* NOTREACHED */
180
}
181

    
182
/*
183
 * Interrupt handler.
184
 *
185
 * This routine will call the corresponding ISR for the
186
 * requested interrupt vector. HAL code must call this
187
 * routine with scheduler locked.
188
 */
189
void
190
irq_handler(int vector)
191
{
192
        struct irq *irq;
193
        int rc;
194

    
195
        irq = irq_table[vector];
196
        if (irq == NULL) {
197
                DPRINTF(("Random interrupt ignored\n"));
198
                return;
199
        }
200
        ASSERT(irq->isr != NULL);
201

    
202
        /* Profile */
203
        irq->count++;
204

    
205
        /*
206
         * Call ISR
207
         */
208
        rc = (*irq->isr)(irq->data);
209

    
210
        if (rc == INT_CONTINUE) {
211
                /*
212
                 * Kick IST
213
                 */
214
                ASSERT(irq->ist != IST_NONE);
215
                irq->istreq++;
216
                sched_wakeup(&irq->istevt);
217
                ASSERT(irq->istreq != 0);
218
        }
219
}
220

    
221
/*
222
 * Return irq information.
223
 */
224
int
225
irq_info(struct irqinfo *info)
226
{
227
        int vec = info->cookie;
228
        int found = 0;
229
        struct irq *irq;
230

    
231
        while (vec < MAXIRQS) {
232
                if (irq_table[vec]) {
233
                        found = 1;
234
                        break;
235
                }
236
                vec++;
237
        }
238
        if (!found)
239
                return ESRCH;
240

    
241
        irq = irq_table[vec];
242
        info->vector = irq->vector;
243
        info->count = irq->count;
244
        info->priority = irq->priority;
245
        info->istreq = irq->istreq;
246
        info->thread = irq->thread;
247
        info->cookie = vec + 1;
248
        return 0;
249
}
250

    
251
/*
252
 * Start interrupt processing.
253
 */
254
void
255
irq_init(void)
256
{
257

    
258
        interrupt_init();
259

    
260
        /* Enable interrupts */
261
        spl0();
262
}