]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arc/kernel/irq.c
ARC: Interrupt Handling
[karo-tx-linux.git] / arch / arc / kernel / irq.c
1 /*
2  * Copyright (C) 2011-12 Synopsys, Inc. (www.synopsys.com)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  */
9
10 #include <linux/interrupt.h>
11 #include <linux/module.h>
12 #include <asm/sections.h>
13 #include <asm/irq.h>
14
15 /*
16  * Early Hardware specific Interrupt setup
17  * -Called very early (start_kernel -> setup_arch -> setup_processor)
18  * -Platform Independent (must for any ARC700)
19  * -Needed for each CPU (hence not foldable into init_IRQ)
20  *
21  * what it does ?
22  * -setup Vector Table Base Reg - in case Linux not linked at 0x8000_0000
23  * -Disable all IRQs (on CPU side)
24  */
25 void __init arc_init_IRQ(void)
26 {
27         int level_mask = level_mask;
28
29         write_aux_reg(AUX_INTR_VEC_BASE, _int_vec_base_lds);
30
31         /* Disable all IRQs: enable them as devices request */
32         write_aux_reg(AUX_IENABLE, 0);
33 }
34
35 /*
36  * ARC700 core includes a simple on-chip intc supporting
37  * -per IRQ enable/disable
38  * -2 levels of interrupts (high/low)
39  * -all interrupts being level triggered
40  *
41  * To reduce platform code, we assume all IRQs directly hooked-up into intc.
42  * Platforms with external intc, hence cascaded IRQs, are free to over-ride
43  * below, per IRQ.
44  */
45
46 static void arc_mask_irq(struct irq_data *data)
47 {
48         arch_mask_irq(data->irq);
49 }
50
51 static void arc_unmask_irq(struct irq_data *data)
52 {
53         arch_unmask_irq(data->irq);
54 }
55
56 static struct irq_chip onchip_intc = {
57         .name           = "ARC In-core Intc",
58         .irq_mask       = arc_mask_irq,
59         .irq_unmask     = arc_unmask_irq,
60 };
61
62 void __init init_onchip_IRQ(void)
63 {
64         int i;
65
66         for (i = 0; i < NR_IRQS; i++)
67                 irq_set_chip_and_handler(i, &onchip_intc, handle_level_irq);
68
69 #ifdef CONFIG_SMP
70         irq_set_chip_and_handler(TIMER0_IRQ, &onchip_intc, handle_percpu_irq);
71 #endif
72 }
73
74 /*
75  * Late Interrupt system init called from start_kernel for Boot CPU only
76  *
77  * Since slab must already be initialized, platforms can start doing any
78  * needed request_irq( )s
79  */
80 void __init init_IRQ(void)
81 {
82         init_onchip_IRQ();
83         plat_init_IRQ();
84 }
85
86 /*
87  * "C" Entry point for any ARC ISR, called from low level vector handler
88  * @irq is the vector number read from ICAUSE reg of on-chip intc
89  */
90 void arch_do_IRQ(unsigned int irq, struct pt_regs *regs)
91 {
92         struct pt_regs *old_regs = set_irq_regs(regs);
93
94         irq_enter();
95         generic_handle_irq(irq);
96         irq_exit();
97         set_irq_regs(old_regs);
98 }
99
100 int __init get_hw_config_num_irq(void)
101 {
102         uint32_t val = read_aux_reg(ARC_REG_VECBASE_BCR);
103
104         switch (val & 0x03) {
105         case 0:
106                 return 16;
107         case 1:
108                 return 32;
109         case 2:
110                 return 8;
111         default:
112                 return 0;
113         }
114
115         return 0;
116 }
117
118 void arch_local_irq_enable(void)
119 {
120         unsigned long flags;
121
122         /*
123          * ARC IDE Drivers tries to re-enable interrupts from hard-isr
124          * context which is simply wrong
125          */
126         if (in_irq()) {
127                 WARN_ONCE(1, "IRQ enabled from hard-isr");
128                 return;
129         }
130
131         flags = arch_local_save_flags();
132         flags |= (STATUS_E1_MASK | STATUS_E2_MASK);
133         arch_local_irq_restore(flags);
134 }
135 EXPORT_SYMBOL(arch_local_irq_enable);