OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [src/] [generic/] [irq.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Generic kernel irq handling.
3
 *
4
 * Copyright (C) 2007 - 2010 Bahadir Balban
5
 */
6
#include <l4/config.h>
7
#include <l4/macros.h>
8
#include <l4/generic/scheduler.h>
9
#include <l4/generic/debug.h>
10
#include <l4/generic/platform.h>
11
#include <l4/generic/tcb.h>
12
#include <l4/generic/irq.h>
13
#include <l4/lib/mutex.h>
14
#include <l4/lib/printk.h>
15
#include <l4/api/errno.h>
16
#include INC_PLAT(irq.h)
17
#include INC_ARCH(exception.h)
18
 
19
/*
20
 * Registers a userspace thread as an irq handler.
21
 *
22
 * A userspace irq thread should have a low-level, device-specific
23
 * irq handler as an in-kernel counterpart. This and its irq chip
24
 * must have been set up at compile-time. These handlers should
25
 * also know how to notify their userspace threads.
26
 *
27
 * If the irq does not have these set up, we cannot allow
28
 * the irq registry.
29
 */
30
int irq_register(struct ktcb *task, int notify_slot, l4id_t irq_index)
31
{
32
        struct irq_desc *this_desc = irq_desc_array + irq_index;
33
 
34
        /* Kernel counterpart not set up, don't allow */
35
        if (!this_desc->handler || !this_desc->chip)
36
                return -ENOIRQ;
37
 
38
        /* Index must be valid */
39
        if (irq_index > IRQS_MAX || irq_index < 0)
40
                return -ENOIRQ;
41
 
42
        /* Setup the task and notify slot */
43
        this_desc->task = task;
44
        this_desc->task_notify_slot = notify_slot;
45
 
46
        /* Setup irq desc waitqueue */
47
        waitqueue_head_init(&this_desc->wqh_irq);
48
 
49
        /* Enable the irq */
50
        irq_enable(irq_index);
51
 
52
        return 0;
53
}
54
 
55
 
56
/* If there is cascading, enable it. */
57
static inline void cascade_irq_chip(struct irq_chip *this_chip)
58
{
59
        if (this_chip->cascade >= 0) {
60
                BUG_ON(IRQ_CHIPS_MAX == 1);
61
                if(this_chip->ops.unmask)
62
                        this_chip->ops.unmask(this_chip->cascade);
63
        }
64
}
65
 
66
void irq_controllers_init(void)
67
{
68
        struct irq_chip *this_chip;
69
 
70
        for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
71
                this_chip = irq_chip_array + i;
72
 
73
                /* Initialise the irq chip (e.g. reset all registers) */
74
                if (this_chip->ops.init)
75
                        this_chip->ops.init();
76
 
77
                /* Enable cascaded irq on this chip if it exists */
78
                cascade_irq_chip(this_chip);
79
        }
80
}
81
 
82
 
83
/*
84
 * Finds the global irq number by looping over irq chips.
85
 *
86
 * Global irq number =
87
 *      Unique irq chip_offset defined by us + irq number local to chip
88
 */
89
l4id_t global_irq_index(void)
90
{
91
        struct irq_chip *this_chip;
92
        l4id_t irq_index = 0;
93
 
94
        /*
95
         * Loop over all chips, starting from the top
96
         * (i.e. nearest to the cpu)
97
         */
98
        for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
99
 
100
                /* Get the chip */
101
                this_chip = irq_chip_array + i;
102
 
103
                /* Find local irq that is triggered on this chip */
104
                if (this_chip->ops.read_irq) {
105
                        irq_index = this_chip->ops.read_irq(this_chip->data);
106
                        BUG_ON(irq_index == IRQ_NIL);
107
                }
108
 
109
                /* See if this irq is a cascaded irq */
110
                if (irq_index == this_chip->cascade)
111
                        continue; /* Yes, continue to next chip */
112
 
113
                /*
114
                 * Irq was initiated from this chip. Add this chip's
115
                 * global irq offset and return it
116
                 */
117
                irq_index += this_chip->start;
118
                return irq_index;
119
        }
120
 
121
        /*
122
         * Cascaded irq detected, but no lower chips
123
         * left to process. This should not happen
124
         */
125
        BUG();
126
 
127
        return IRQ_NIL;
128
}
129
 
130
#include <l4/drivers/irq/gic/gic.h>
131
 
132
void do_irq(void)
133
{
134
        l4id_t irq_index = global_irq_index();
135
        struct irq_desc *this_irq;
136
 
137
        if (irq_index == IRQ_SPURIOUS) {
138
                printk("CPU%d: FATAL: Spurious irq\n", smp_get_cpuid());
139
                BUG();
140
        }
141
 
142
        // printk("CPU%d: Received irq %d\n", smp_get_cpuid(), irq_index);
143
 
144
        this_irq = irq_desc_array + irq_index;
145
 
146
        system_account_irq();
147
 
148
        /*
149
         * Note, this can be easily done a few instructions
150
         * quicker by some immediate read/disable/enable_all().
151
         *
152
         * We currently stick with it as it is clearer.
153
         */
154
        irq_disable(irq_index);
155
 
156
        /* Re-enable all irqs */
157
        enable_irqs();
158
 
159
        /* Handle the irq */
160
        BUG_ON(!this_irq->handler);
161
        if (this_irq->handler(this_irq) != IRQ_HANDLED) {
162
                printk("CPU%d: FATAL: Spurious or broken irq\n",
163
                       smp_get_cpuid());
164
                BUG();
165
        }
166
 
167
        irq_enable(irq_index);
168
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.