0001
0002
0003
0004
0005 #include <linux/kernel.h>
0006 #include <linux/init.h>
0007 #include <linux/linkage.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/smp.h>
0010 #include <linux/spinlock.h>
0011 #include <linux/mm.h>
0012 #include <linux/kernel_stat.h>
0013
0014 #include <asm/errno.h>
0015 #include <asm/irq_regs.h>
0016 #include <asm/signal.h>
0017 #include <asm/io.h>
0018
0019 #include <asm/sibyte/bcm1480_regs.h>
0020 #include <asm/sibyte/bcm1480_int.h>
0021 #include <asm/sibyte/bcm1480_scd.h>
0022
0023 #include <asm/sibyte/sb1250_uart.h>
0024 #include <asm/sibyte/sb1250.h>
0025
0026
0027
0028
0029
0030
0031
0032
0033 #ifdef CONFIG_PCI
0034 extern unsigned long ht_eoi_space;
0035 #endif
0036
0037
0038 int bcm1480_irq_owner[BCM1480_NR_IRQS];
0039
0040 static DEFINE_RAW_SPINLOCK(bcm1480_imr_lock);
0041
0042 void bcm1480_mask_irq(int cpu, int irq)
0043 {
0044 unsigned long flags, hl_spacing;
0045 u64 cur_ints;
0046
0047 raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
0048 hl_spacing = 0;
0049 if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {
0050 hl_spacing = BCM1480_IMR_HL_SPACING;
0051 irq -= BCM1480_NR_IRQS_HALF;
0052 }
0053 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
0054 cur_ints |= (((u64) 1) << irq);
0055 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
0056 raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
0057 }
0058
0059 void bcm1480_unmask_irq(int cpu, int irq)
0060 {
0061 unsigned long flags, hl_spacing;
0062 u64 cur_ints;
0063
0064 raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
0065 hl_spacing = 0;
0066 if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {
0067 hl_spacing = BCM1480_IMR_HL_SPACING;
0068 irq -= BCM1480_NR_IRQS_HALF;
0069 }
0070 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
0071 cur_ints &= ~(((u64) 1) << irq);
0072 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
0073 raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
0074 }
0075
0076 #ifdef CONFIG_SMP
0077 static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask,
0078 bool force)
0079 {
0080 unsigned int irq_dirty, irq = d->irq;
0081 int i = 0, old_cpu, cpu, int_on, k;
0082 u64 cur_ints;
0083 unsigned long flags;
0084
0085 i = cpumask_first_and(mask, cpu_online_mask);
0086
0087
0088 cpu = cpu_logical_map(i);
0089
0090
0091 raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
0092
0093
0094 old_cpu = bcm1480_irq_owner[irq];
0095 irq_dirty = irq;
0096 if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {
0097 irq_dirty -= BCM1480_NR_IRQS_HALF;
0098 }
0099
0100 for (k=0; k<2; k++) {
0101 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
0102 int_on = !(cur_ints & (((u64) 1) << irq_dirty));
0103 if (int_on) {
0104
0105 cur_ints |= (((u64) 1) << irq_dirty);
0106 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
0107 }
0108 bcm1480_irq_owner[irq] = cpu;
0109 if (int_on) {
0110
0111 cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
0112 cur_ints &= ~(((u64) 1) << irq_dirty);
0113 ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
0114 }
0115 }
0116 raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
0117
0118 return 0;
0119 }
0120 #endif
0121
0122
0123
0124
0125 static void disable_bcm1480_irq(struct irq_data *d)
0126 {
0127 unsigned int irq = d->irq;
0128
0129 bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
0130 }
0131
0132 static void enable_bcm1480_irq(struct irq_data *d)
0133 {
0134 unsigned int irq = d->irq;
0135
0136 bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);
0137 }
0138
0139
0140 static void ack_bcm1480_irq(struct irq_data *d)
0141 {
0142 unsigned int irq_dirty, irq = d->irq;
0143 u64 pending;
0144 int k;
0145
0146
0147
0148
0149
0150
0151
0152 irq_dirty = irq;
0153 if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {
0154 irq_dirty -= BCM1480_NR_IRQS_HALF;
0155 }
0156 for (k=0; k<2; k++) {
0157 pending = __raw_readq(IOADDR(A_BCM1480_IMR_REGISTER(bcm1480_irq_owner[irq],
0158 R_BCM1480_IMR_LDT_INTERRUPT_H + (k*BCM1480_IMR_HL_SPACING))));
0159 pending &= ((u64)1 << (irq_dirty));
0160 if (pending) {
0161 #ifdef CONFIG_SMP
0162 int i;
0163 for (i=0; i<NR_CPUS; i++) {
0164
0165
0166
0167
0168 __raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(cpu_logical_map(i),
0169 R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));
0170 }
0171 #else
0172 __raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));
0173 #endif
0174
0175
0176
0177
0178
0179
0180
0181 #ifdef CONFIG_PCI
0182 if (ht_eoi_space)
0183 *(uint32_t *)(ht_eoi_space+(irq<<16)+(7<<2)) = 0;
0184 #endif
0185 }
0186 }
0187 bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
0188 }
0189
0190 static struct irq_chip bcm1480_irq_type = {
0191 .name = "BCM1480-IMR",
0192 .irq_mask_ack = ack_bcm1480_irq,
0193 .irq_mask = disable_bcm1480_irq,
0194 .irq_unmask = enable_bcm1480_irq,
0195 #ifdef CONFIG_SMP
0196 .irq_set_affinity = bcm1480_set_affinity
0197 #endif
0198 };
0199
0200 void __init init_bcm1480_irqs(void)
0201 {
0202 int i;
0203
0204 for (i = 0; i < BCM1480_NR_IRQS; i++) {
0205 irq_set_chip_and_handler(i, &bcm1480_irq_type,
0206 handle_level_irq);
0207 bcm1480_irq_owner[i] = 0;
0208 }
0209 }
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231 #define IMR_IP2_VAL K_BCM1480_INT_MAP_I0
0232 #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1
0233 #define IMR_IP4_VAL K_BCM1480_INT_MAP_I2
0234 #define IMR_IP5_VAL K_BCM1480_INT_MAP_I3
0235 #define IMR_IP6_VAL K_BCM1480_INT_MAP_I4
0236
0237 void __init arch_init_irq(void)
0238 {
0239 unsigned int i, cpu;
0240 u64 tmp;
0241 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
0242 STATUSF_IP1 | STATUSF_IP0;
0243
0244
0245
0246 for (i = 1; i < BCM1480_NR_IRQS_HALF; i++) {
0247 for (cpu = 0; cpu < 4; cpu++) {
0248 __raw_writeq(IMR_IP2_VAL,
0249 IOADDR(A_BCM1480_IMR_REGISTER(cpu,
0250 R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (i << 3)));
0251 }
0252 }
0253
0254
0255 for (i = 0; i < BCM1480_NR_IRQS_HALF; i++) {
0256 for (cpu = 0; cpu < 4; cpu++) {
0257 __raw_writeq(IMR_IP2_VAL,
0258 IOADDR(A_BCM1480_IMR_REGISTER(cpu,
0259 R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) + (i << 3)));
0260 }
0261 }
0262
0263 init_bcm1480_irqs();
0264
0265
0266
0267
0268
0269
0270 for (cpu = 0; cpu < 4; cpu++) {
0271 __raw_writeq(IMR_IP3_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) +
0272 (K_BCM1480_INT_MBOX_0_0 << 3)));
0273 }
0274
0275
0276
0277 for (cpu = 0; cpu < 4; cpu++) {
0278 __raw_writeq(0xffffffffffffffffULL,
0279 IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_0_CLR_CPU)));
0280 __raw_writeq(0xffffffffffffffffULL,
0281 IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_1_CLR_CPU)));
0282 }
0283
0284
0285
0286 tmp = ~((u64) 0) ^ ( (((u64) 1) << K_BCM1480_INT_MBOX_0_0));
0287 for (cpu = 0; cpu < 4; cpu++) {
0288 __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_H)));
0289 }
0290 tmp = ~((u64) 0);
0291 for (cpu = 0; cpu < 4; cpu++) {
0292 __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_L)));
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302 change_c0_status(ST0_IM, imask);
0303 }
0304
0305 extern void bcm1480_mailbox_interrupt(void);
0306
0307 static inline void dispatch_ip2(void)
0308 {
0309 unsigned long long mask_h, mask_l;
0310 unsigned int cpu = smp_processor_id();
0311 unsigned long base;
0312
0313
0314
0315
0316
0317
0318 base = A_BCM1480_IMR_MAPPER(cpu);
0319 mask_h = __raw_readq(
0320 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
0321 mask_l = __raw_readq(
0322 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
0323
0324 if (mask_h) {
0325 if (mask_h ^ 1)
0326 do_IRQ(fls64(mask_h) - 1);
0327 else if (mask_l)
0328 do_IRQ(63 + fls64(mask_l));
0329 }
0330 }
0331
0332 asmlinkage void plat_irq_dispatch(void)
0333 {
0334 unsigned int cpu = smp_processor_id();
0335 unsigned int pending;
0336
0337 pending = read_c0_cause() & read_c0_status();
0338
0339 if (pending & CAUSEF_IP4)
0340 do_IRQ(K_BCM1480_INT_TIMER_0 + cpu);
0341 #ifdef CONFIG_SMP
0342 else if (pending & CAUSEF_IP3)
0343 bcm1480_mailbox_interrupt();
0344 #endif
0345
0346 else if (pending & CAUSEF_IP2)
0347 dispatch_ip2();
0348 }