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); |
