diff options
Diffstat (limited to 'arch/sparc/kernel/sun4c_irq.c')
-rw-r--r-- | arch/sparc/kernel/sun4c_irq.c | 150 |
1 files changed, 90 insertions, 60 deletions
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 90eea38ad66f..f6bf25a2ff80 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c | |||
@@ -65,62 +65,94 @@ | |||
65 | */ | 65 | */ |
66 | unsigned char __iomem *interrupt_enable; | 66 | unsigned char __iomem *interrupt_enable; |
67 | 67 | ||
68 | static void sun4c_disable_irq(unsigned int irq_nr) | 68 | static void sun4c_mask_irq(struct irq_data *data) |
69 | { | 69 | { |
70 | unsigned long flags; | 70 | unsigned long mask = (unsigned long)data->chip_data; |
71 | unsigned char current_mask, new_mask; | 71 | |
72 | 72 | if (mask) { | |
73 | local_irq_save(flags); | 73 | unsigned long flags; |
74 | irq_nr &= (NR_IRQS - 1); | 74 | |
75 | current_mask = sbus_readb(interrupt_enable); | 75 | local_irq_save(flags); |
76 | switch (irq_nr) { | 76 | mask = sbus_readb(interrupt_enable) & ~mask; |
77 | case 1: | 77 | sbus_writeb(mask, interrupt_enable); |
78 | new_mask = ((current_mask) & (~(SUN4C_INT_E1))); | ||
79 | break; | ||
80 | case 8: | ||
81 | new_mask = ((current_mask) & (~(SUN4C_INT_E8))); | ||
82 | break; | ||
83 | case 10: | ||
84 | new_mask = ((current_mask) & (~(SUN4C_INT_E10))); | ||
85 | break; | ||
86 | case 14: | ||
87 | new_mask = ((current_mask) & (~(SUN4C_INT_E14))); | ||
88 | break; | ||
89 | default: | ||
90 | local_irq_restore(flags); | 78 | local_irq_restore(flags); |
91 | return; | ||
92 | } | 79 | } |
93 | sbus_writeb(new_mask, interrupt_enable); | ||
94 | local_irq_restore(flags); | ||
95 | } | 80 | } |
96 | 81 | ||
97 | static void sun4c_enable_irq(unsigned int irq_nr) | 82 | static void sun4c_unmask_irq(struct irq_data *data) |
98 | { | 83 | { |
99 | unsigned long flags; | 84 | unsigned long mask = (unsigned long)data->chip_data; |
100 | unsigned char current_mask, new_mask; | 85 | |
101 | 86 | if (mask) { | |
102 | local_irq_save(flags); | 87 | unsigned long flags; |
103 | irq_nr &= (NR_IRQS - 1); | 88 | |
104 | current_mask = sbus_readb(interrupt_enable); | 89 | local_irq_save(flags); |
105 | switch (irq_nr) { | 90 | mask = sbus_readb(interrupt_enable) | mask; |
106 | case 1: | 91 | sbus_writeb(mask, interrupt_enable); |
107 | new_mask = ((current_mask) | SUN4C_INT_E1); | ||
108 | break; | ||
109 | case 8: | ||
110 | new_mask = ((current_mask) | SUN4C_INT_E8); | ||
111 | break; | ||
112 | case 10: | ||
113 | new_mask = ((current_mask) | SUN4C_INT_E10); | ||
114 | break; | ||
115 | case 14: | ||
116 | new_mask = ((current_mask) | SUN4C_INT_E14); | ||
117 | break; | ||
118 | default: | ||
119 | local_irq_restore(flags); | 92 | local_irq_restore(flags); |
120 | return; | ||
121 | } | 93 | } |
122 | sbus_writeb(new_mask, interrupt_enable); | 94 | } |
123 | local_irq_restore(flags); | 95 | |
96 | static unsigned int sun4c_startup_irq(struct irq_data *data) | ||
97 | { | ||
98 | irq_link(data->irq); | ||
99 | sun4c_unmask_irq(data); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void sun4c_shutdown_irq(struct irq_data *data) | ||
105 | { | ||
106 | sun4c_mask_irq(data); | ||
107 | irq_unlink(data->irq); | ||
108 | } | ||
109 | |||
110 | static struct irq_chip sun4c_irq = { | ||
111 | .name = "sun4c", | ||
112 | .irq_startup = sun4c_startup_irq, | ||
113 | .irq_shutdown = sun4c_shutdown_irq, | ||
114 | .irq_mask = sun4c_mask_irq, | ||
115 | .irq_unmask = sun4c_unmask_irq, | ||
116 | }; | ||
117 | |||
118 | static unsigned int sun4c_build_device_irq(struct platform_device *op, | ||
119 | unsigned int real_irq) | ||
120 | { | ||
121 | unsigned int irq; | ||
122 | |||
123 | if (real_irq >= 16) { | ||
124 | prom_printf("Bogus sun4c IRQ %u\n", real_irq); | ||
125 | prom_halt(); | ||
126 | } | ||
127 | |||
128 | irq = irq_alloc(real_irq, real_irq); | ||
129 | if (irq) { | ||
130 | unsigned long mask = 0UL; | ||
131 | |||
132 | switch (real_irq) { | ||
133 | case 1: | ||
134 | mask = SUN4C_INT_E1; | ||
135 | break; | ||
136 | case 8: | ||
137 | mask = SUN4C_INT_E8; | ||
138 | break; | ||
139 | case 10: | ||
140 | mask = SUN4C_INT_E10; | ||
141 | break; | ||
142 | case 14: | ||
143 | mask = SUN4C_INT_E14; | ||
144 | break; | ||
145 | default: | ||
146 | /* All the rest are either always enabled, | ||
147 | * or are for signalling software interrupts. | ||
148 | */ | ||
149 | break; | ||
150 | } | ||
151 | irq_set_chip_and_handler_name(irq, &sun4c_irq, | ||
152 | handle_level_irq, "level"); | ||
153 | irq_set_chip_data(irq, (void *)mask); | ||
154 | } | ||
155 | return irq; | ||
124 | } | 156 | } |
125 | 157 | ||
126 | struct sun4c_timer_info { | 158 | struct sun4c_timer_info { |
@@ -144,8 +176,9 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) | |||
144 | 176 | ||
145 | static void __init sun4c_init_timers(irq_handler_t counter_fn) | 177 | static void __init sun4c_init_timers(irq_handler_t counter_fn) |
146 | { | 178 | { |
147 | const struct linux_prom_irqs *irq; | 179 | const struct linux_prom_irqs *prom_irqs; |
148 | struct device_node *dp; | 180 | struct device_node *dp; |
181 | unsigned int irq; | ||
149 | const u32 *addr; | 182 | const u32 *addr; |
150 | int err; | 183 | int err; |
151 | 184 | ||
@@ -163,9 +196,9 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn) | |||
163 | 196 | ||
164 | sun4c_timers = (void __iomem *) (unsigned long) addr[0]; | 197 | sun4c_timers = (void __iomem *) (unsigned long) addr[0]; |
165 | 198 | ||
166 | irq = of_get_property(dp, "intr", NULL); | 199 | prom_irqs = of_get_property(dp, "intr", NULL); |
167 | of_node_put(dp); | 200 | of_node_put(dp); |
168 | if (!irq) { | 201 | if (!prom_irqs) { |
169 | prom_printf("sun4c_init_timers: No intr property\n"); | 202 | prom_printf("sun4c_init_timers: No intr property\n"); |
170 | prom_halt(); | 203 | prom_halt(); |
171 | } | 204 | } |
@@ -178,15 +211,15 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn) | |||
178 | 211 | ||
179 | master_l10_counter = &sun4c_timers->l10_count; | 212 | master_l10_counter = &sun4c_timers->l10_count; |
180 | 213 | ||
181 | err = request_irq(irq[0].pri, counter_fn, | 214 | irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri); |
182 | (IRQF_DISABLED | SA_STATIC_ALLOC), | 215 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); |
183 | "timer", NULL); | ||
184 | if (err) { | 216 | if (err) { |
185 | prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); | 217 | prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); |
186 | prom_halt(); | 218 | prom_halt(); |
187 | } | 219 | } |
188 | 220 | ||
189 | sun4c_disable_irq(irq[1].pri); | 221 | /* disable timer interrupt */ |
222 | sun4c_mask_irq(irq_get_irq_data(irq)); | ||
190 | } | 223 | } |
191 | 224 | ||
192 | #ifdef CONFIG_SMP | 225 | #ifdef CONFIG_SMP |
@@ -215,14 +248,11 @@ void __init sun4c_init_IRQ(void) | |||
215 | 248 | ||
216 | interrupt_enable = (void __iomem *) (unsigned long) addr[0]; | 249 | interrupt_enable = (void __iomem *) (unsigned long) addr[0]; |
217 | 250 | ||
218 | BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | ||
219 | BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | ||
220 | BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | ||
221 | BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | ||
222 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); | 251 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); |
223 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); | 252 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); |
224 | 253 | ||
225 | sparc_irq_config.init_timers = sun4c_init_timers; | 254 | sparc_irq_config.init_timers = sun4c_init_timers; |
255 | sparc_irq_config.build_device_irq = sun4c_build_device_irq; | ||
226 | 256 | ||
227 | #ifdef CONFIG_SMP | 257 | #ifdef CONFIG_SMP |
228 | BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); | 258 | BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); |