source: rtems/bsps/sparc/shared/irq/genirq.c @ d60d303c

5
Last change on this file since d60d303c was d60d303c, checked in by Sebastian Huber <sebastian.huber@…>, on 04/20/18 at 11:33:24

bsps/sparc: Move shared files to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 * Generic interrupt helpers mainly for GRLIB PCI peripherals
3 *
4 * COPYRIGHT (c) 2008.
5 * Cobham Gaisler AB.
6 *
7 * The license and distribution terms for this file may be
8 * found in the file LICENSE in this distribution or at
9 * http://www.rtems.org/license/LICENSE.
10 */
11
12#include <rtems.h>
13#include <rtems/bspIo.h>
14#include <stdlib.h>
15#include <string.h>
16#include <bsp/genirq.h>
17
18struct genirq_handler_entry {
19        struct genirq_handler_entry     *next;          /* Next ISR entry for this IRQ number */
20        genirq_handler                  isr;            /* ISR function called upon IRQ */
21        void                            *arg;           /* custom argument to ISR */
22        int                             enabled;        /* Inidicates if IRQ is enabled */
23};
24
25struct genirq_irq_entry {
26        struct genirq_handler_entry     *head;
27        struct genirq_stats             stats;
28};
29
30struct genirq_priv {
31        /* Maximum number of interrupt */
32        int                             genirq_max;
33        /* IRQ Table index N reflect IRQ number N */
34        struct genirq_irq_entry         genirq_table[1]; /* Length depends on */
35};
36
37genirq_t genirq_init(int number_of_irqs)
38{
39        int size;
40        struct genirq_priv *priv;
41
42        size = sizeof(int) +
43               number_of_irqs * sizeof(struct genirq_irq_entry);
44
45        priv = (struct genirq_priv *)malloc(size);
46        if ( !priv )
47                return NULL;
48        memset(priv, 0, size);
49        priv->genirq_max = number_of_irqs - 1;
50
51        return priv;
52}
53
54void genirq_destroy(genirq_t d)
55{
56        struct genirq_priv *priv = d;
57        struct genirq_irq_entry *irqentry;
58        struct genirq_handler_entry *isrentry, *tmp;
59        int i;
60
61        /* Free all registered interrupts */
62        for ( i=0; i<priv->genirq_max; i++) {
63                irqentry = &priv->genirq_table[i];
64                isrentry = irqentry->head;
65                while ( isrentry ) {
66                        tmp = isrentry;
67                        isrentry = isrentry->next;
68                        genirq_free_handler(tmp);
69                }
70        }
71
72        free(priv);
73}
74
75int genirq_check(genirq_t d, int irq)
76{
77        struct genirq_priv *priv = d;
78
79        if ( (irq <= 0) || (irq > priv->genirq_max) )
80                return -1;
81        else
82                return 0;
83}
84
85void *genirq_alloc_handler(genirq_handler isr, void *arg)
86{
87        struct genirq_handler_entry *newentry;
88
89        newentry = malloc(sizeof(struct genirq_handler_entry));
90        if ( newentry ) {
91                /* Initialize ISR entry */
92                newentry->isr     = isr;
93                newentry->arg     = arg;
94                newentry->enabled = 0;
95        }
96        return newentry;
97}
98
99int genirq_register(genirq_t d, int irq, void *handler)
100{
101        struct genirq_priv *priv = d;
102        struct genirq_irq_entry *irqentry;
103        struct genirq_handler_entry *isrentry, *newentry = handler;
104
105        if ( genirq_check(d, irq) )
106                return -1;
107
108        /* Insert new ISR entry first into table */
109        irqentry = &priv->genirq_table[irq];
110        isrentry = irqentry->head;
111        irqentry->head = newentry;
112        newentry->next = isrentry;
113
114        if ( isrentry )
115                return 1; /* This is the first handler on this IRQ */
116        return 0;
117}
118
119void *genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
120{
121        struct genirq_priv *priv = d;
122        struct genirq_irq_entry *irqentry;
123        struct genirq_handler_entry *isrentry, **prev;
124        void *ret;
125
126        if ( genirq_check(d, irq) )
127                return NULL;
128
129        /* Remove isr[arg] from ISR list */
130        irqentry = &priv->genirq_table[irq];
131        ret = NULL;
132
133        prev = &irqentry->head;
134        isrentry = irqentry->head;
135        while ( isrentry ) {
136                if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
137                        /* Found ISR, remove it from list */
138                        if ( isrentry->enabled ) {
139                                /* Can not remove enabled ISRs, disable first */
140                                ret = NULL;
141                                break;
142                        }
143                        *prev = isrentry->next;
144                        ret = isrentry;
145                        break;
146                }
147                prev = &isrentry->next;
148                isrentry = isrentry->next;
149        }
150
151        return ret;
152}
153
154/* Enables or Disables ISR handler. Internal function to reduce footprint
155 * of enable/disable functions.
156 *
157 * \param action 1=enable, 0=disable ISR
158 */
159static int genirq_set_active(
160        struct genirq_priv *priv,
161        int irq,
162        genirq_handler isr,
163        void *arg,
164        int action)
165{
166        struct genirq_irq_entry *irqentry;
167        struct genirq_handler_entry *isrentry, *e = NULL;
168        int enabled;
169
170        if ( genirq_check(priv, irq) )
171                return -1;
172
173        /* Find isr[arg] in ISR list */
174        irqentry = &priv->genirq_table[irq];
175        enabled = 0;
176
177        isrentry = irqentry->head;
178        while ( isrentry ) {
179                if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
180                        /* Found ISR */
181                        if ( isrentry->enabled == action ) {
182                                /* The ISR is already enabled or disabled
183                                 * depending on request, neccessary actions
184                                 * were taken last time the same action was
185                                 * requested.
186                                 */
187                                return 1;
188                        }
189                        e = isrentry;
190                } else {
191                        enabled += isrentry->enabled;
192                }
193                isrentry = isrentry->next;
194        }
195
196        if ( !e )
197                return -1;
198
199        e->enabled = action;
200
201        return enabled;
202}
203
204int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg)
205{
206        struct genirq_priv *priv = d;
207        return genirq_set_active(priv, irq, isr, arg, 1);
208}
209
210int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg)
211{
212        struct genirq_priv *priv = d;
213        return genirq_set_active(priv, irq, isr, arg, 0);
214}
215
216void genirq_doirq(genirq_t d, int irq)
217{
218        struct genirq_priv *priv = d;
219        struct genirq_irq_entry *irqentry;
220        struct genirq_handler_entry *isrentry;
221        int enabled;
222
223        irqentry = &priv->genirq_table[irq];
224        irqentry->stats.irq_cnt++;
225
226        enabled = 0;
227
228        isrentry = irqentry->head;
229        while ( isrentry ) {
230                if ( isrentry->enabled ) {
231                        enabled = 1;
232                        /* Call the ISR */
233                        isrentry->isr(isrentry->arg);
234                }
235                isrentry = isrentry->next;
236        }
237
238        /* Was the IRQ an IRQ without source? */
239        if ( enabled == 0 ) {
240                /* This should not happen */
241                printk("Spurious IRQ happened on IRQ %d\n", irq);
242        }
243}
Note: See TracBrowser for help on using the repository browser.