Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * SS1000/SC2000 interrupt handling.
0004  *
0005  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
0006  *  Heavily based on arch/sparc/kernel/irq.c.
0007  */
0008 
0009 #include <linux/kernel_stat.h>
0010 #include <linux/slab.h>
0011 #include <linux/seq_file.h>
0012 
0013 #include <asm/timer.h>
0014 #include <asm/traps.h>
0015 #include <asm/irq.h>
0016 #include <asm/io.h>
0017 #include <asm/sbi.h>
0018 #include <asm/cacheflush.h>
0019 #include <asm/setup.h>
0020 #include <asm/oplib.h>
0021 
0022 #include "kernel.h"
0023 #include "irq.h"
0024 
0025 /* Sun4d interrupts fall roughly into two categories.  SBUS and
0026  * cpu local.  CPU local interrupts cover the timer interrupts
0027  * and whatnot, and we encode those as normal PILs between
0028  * 0 and 15.
0029  * SBUS interrupts are encodes as a combination of board, level and slot.
0030  */
0031 
0032 struct sun4d_handler_data {
0033     unsigned int cpuid;    /* target cpu */
0034     unsigned int real_irq; /* interrupt level */
0035 };
0036 
0037 
0038 static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
0039 {
0040     return (board + 1) << 5 | (lvl << 2) | slot;
0041 }
0042 
0043 struct sun4d_timer_regs {
0044     u32 l10_timer_limit;
0045     u32 l10_cur_countx;
0046     u32 l10_limit_noclear;
0047     u32 ctrl;
0048     u32 l10_cur_count;
0049 };
0050 
0051 static struct sun4d_timer_regs __iomem *sun4d_timers;
0052 
0053 #define SUN4D_TIMER_IRQ        10
0054 
0055 /* Specify which cpu handle interrupts from which board.
0056  * Index is board - value is cpu.
0057  */
0058 static unsigned char board_to_cpu[32];
0059 
0060 static int pil_to_sbus[] = {
0061     0,
0062     0,
0063     1,
0064     2,
0065     0,
0066     3,
0067     0,
0068     4,
0069     0,
0070     5,
0071     0,
0072     6,
0073     0,
0074     7,
0075     0,
0076     0,
0077 };
0078 
0079 /* Exported for sun4d_smp.c */
0080 DEFINE_SPINLOCK(sun4d_imsk_lock);
0081 
0082 /* SBUS interrupts are encoded integers including the board number
0083  * (plus one), the SBUS level, and the SBUS slot number.  Sun4D
0084  * IRQ dispatch is done by:
0085  *
0086  * 1) Reading the BW local interrupt table in order to get the bus
0087  *    interrupt mask.
0088  *
0089  *    This table is indexed by SBUS interrupt level which can be
0090  *    derived from the PIL we got interrupted on.
0091  *
0092  * 2) For each bus showing interrupt pending from #1, read the
0093  *    SBI interrupt state register.  This will indicate which slots
0094  *    have interrupts pending for that SBUS interrupt level.
0095  *
0096  * 3) Call the genreric IRQ support.
0097  */
0098 static void sun4d_sbus_handler_irq(int sbusl)
0099 {
0100     unsigned int bus_mask;
0101     unsigned int sbino, slot;
0102     unsigned int sbil;
0103 
0104     bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
0105     bw_clear_intr_mask(sbusl, bus_mask);
0106 
0107     sbil = (sbusl << 2);
0108     /* Loop for each pending SBI */
0109     for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
0110         unsigned int idx, mask;
0111 
0112         if (!(bus_mask & 1))
0113             continue;
0114         /* XXX This seems to ACK the irq twice.  acquire_sbi()
0115          * XXX uses swap, therefore this writes 0xf << sbil,
0116          * XXX then later release_sbi() will write the individual
0117          * XXX bits which were set again.
0118          */
0119         mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
0120         mask &= (0xf << sbil);
0121 
0122         /* Loop for each pending SBI slot */
0123         slot = (1 << sbil);
0124         for (idx = 0; mask != 0; idx++, slot <<= 1) {
0125             unsigned int pil;
0126             struct irq_bucket *p;
0127 
0128             if (!(mask & slot))
0129                 continue;
0130 
0131             mask &= ~slot;
0132             pil = sun4d_encode_irq(sbino, sbusl, idx);
0133 
0134             p = irq_map[pil];
0135             while (p) {
0136                 struct irq_bucket *next;
0137 
0138                 next = p->next;
0139                 generic_handle_irq(p->irq);
0140                 p = next;
0141             }
0142             release_sbi(SBI2DEVID(sbino), slot);
0143         }
0144     }
0145 }
0146 
0147 void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs)
0148 {
0149     struct pt_regs *old_regs;
0150     /* SBUS IRQ level (1 - 7) */
0151     int sbusl = pil_to_sbus[pil];
0152 
0153     /* FIXME: Is this necessary?? */
0154     cc_get_ipen();
0155 
0156     cc_set_iclr(1 << pil);
0157 
0158 #ifdef CONFIG_SMP
0159     /*
0160      * Check IPI data structures after IRQ has been cleared. Hard and Soft
0161      * IRQ can happen at the same time, so both cases are always handled.
0162      */
0163     if (pil == SUN4D_IPI_IRQ)
0164         sun4d_ipi_interrupt();
0165 #endif
0166 
0167     old_regs = set_irq_regs(regs);
0168     irq_enter();
0169     if (sbusl == 0) {
0170         /* cpu interrupt */
0171         struct irq_bucket *p;
0172 
0173         p = irq_map[pil];
0174         while (p) {
0175             struct irq_bucket *next;
0176 
0177             next = p->next;
0178             generic_handle_irq(p->irq);
0179             p = next;
0180         }
0181     } else {
0182         /* SBUS interrupt */
0183         sun4d_sbus_handler_irq(sbusl);
0184     }
0185     irq_exit();
0186     set_irq_regs(old_regs);
0187 }
0188 
0189 
0190 static void sun4d_mask_irq(struct irq_data *data)
0191 {
0192     struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data);
0193     unsigned int real_irq;
0194 #ifdef CONFIG_SMP
0195     int cpuid = handler_data->cpuid;
0196     unsigned long flags;
0197 #endif
0198     real_irq = handler_data->real_irq;
0199 #ifdef CONFIG_SMP
0200     spin_lock_irqsave(&sun4d_imsk_lock, flags);
0201     cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
0202     spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
0203 #else
0204     cc_set_imsk(cc_get_imsk() | (1 << real_irq));
0205 #endif
0206 }
0207 
0208 static void sun4d_unmask_irq(struct irq_data *data)
0209 {
0210     struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data);
0211     unsigned int real_irq;
0212 #ifdef CONFIG_SMP
0213     int cpuid = handler_data->cpuid;
0214     unsigned long flags;
0215 #endif
0216     real_irq = handler_data->real_irq;
0217 
0218 #ifdef CONFIG_SMP
0219     spin_lock_irqsave(&sun4d_imsk_lock, flags);
0220     cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
0221     spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
0222 #else
0223     cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
0224 #endif
0225 }
0226 
0227 static unsigned int sun4d_startup_irq(struct irq_data *data)
0228 {
0229     irq_link(data->irq);
0230     sun4d_unmask_irq(data);
0231     return 0;
0232 }
0233 
0234 static void sun4d_shutdown_irq(struct irq_data *data)
0235 {
0236     sun4d_mask_irq(data);
0237     irq_unlink(data->irq);
0238 }
0239 
0240 static struct irq_chip sun4d_irq = {
0241     .name       = "sun4d",
0242     .irq_startup    = sun4d_startup_irq,
0243     .irq_shutdown   = sun4d_shutdown_irq,
0244     .irq_unmask = sun4d_unmask_irq,
0245     .irq_mask   = sun4d_mask_irq,
0246 };
0247 
0248 #ifdef CONFIG_SMP
0249 /* Setup IRQ distribution scheme. */
0250 void __init sun4d_distribute_irqs(void)
0251 {
0252     struct device_node *dp;
0253 
0254     int cpuid = cpu_logical_map(1);
0255 
0256     if (cpuid == -1)
0257         cpuid = cpu_logical_map(0);
0258     for_each_node_by_name(dp, "sbi") {
0259         int devid = of_getintprop_default(dp, "device-id", 0);
0260         int board = of_getintprop_default(dp, "board#", 0);
0261         board_to_cpu[board] = cpuid;
0262         set_sbi_tid(devid, cpuid << 3);
0263     }
0264     printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
0265 }
0266 #endif
0267 
0268 static void sun4d_clear_clock_irq(void)
0269 {
0270     sbus_readl(&sun4d_timers->l10_timer_limit);
0271 }
0272 
0273 static void sun4d_load_profile_irq(int cpu, unsigned int limit)
0274 {
0275     unsigned int value = limit ? timer_value(limit) : 0;
0276     bw_set_prof_limit(cpu, value);
0277 }
0278 
0279 static void __init sun4d_load_profile_irqs(void)
0280 {
0281     int cpu = 0, mid;
0282 
0283     while (!cpu_find_by_instance(cpu, NULL, &mid)) {
0284         sun4d_load_profile_irq(mid >> 3, 0);
0285         cpu++;
0286     }
0287 }
0288 
0289 static unsigned int _sun4d_build_device_irq(unsigned int real_irq,
0290                                             unsigned int pil,
0291                                             unsigned int board)
0292 {
0293     struct sun4d_handler_data *handler_data;
0294     unsigned int irq;
0295 
0296     irq = irq_alloc(real_irq, pil);
0297     if (irq == 0) {
0298         prom_printf("IRQ: allocate for %d %d %d failed\n",
0299             real_irq, pil, board);
0300         goto err_out;
0301     }
0302 
0303     handler_data = irq_get_handler_data(irq);
0304     if (unlikely(handler_data))
0305         goto err_out;
0306 
0307     handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
0308     if (unlikely(!handler_data)) {
0309         prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
0310         prom_halt();
0311     }
0312     handler_data->cpuid    = board_to_cpu[board];
0313     handler_data->real_irq = real_irq;
0314     irq_set_chip_and_handler_name(irq, &sun4d_irq,
0315                                   handle_level_irq, "level");
0316     irq_set_handler_data(irq, handler_data);
0317 
0318 err_out:
0319     return irq;
0320 }
0321 
0322 
0323 
0324 static unsigned int sun4d_build_device_irq(struct platform_device *op,
0325                                            unsigned int real_irq)
0326 {
0327     struct device_node *dp = op->dev.of_node;
0328     struct device_node *board_parent, *bus = dp->parent;
0329     char *bus_connection;
0330     const struct linux_prom_registers *regs;
0331     unsigned int pil;
0332     unsigned int irq;
0333     int board, slot;
0334     int sbusl;
0335 
0336     irq = real_irq;
0337     while (bus) {
0338         if (of_node_name_eq(bus, "sbi")) {
0339             bus_connection = "io-unit";
0340             break;
0341         }
0342 
0343         if (of_node_name_eq(bus, "bootbus")) {
0344             bus_connection = "cpu-unit";
0345             break;
0346         }
0347 
0348         bus = bus->parent;
0349     }
0350     if (!bus)
0351         goto err_out;
0352 
0353     regs = of_get_property(dp, "reg", NULL);
0354     if (!regs)
0355         goto err_out;
0356 
0357     slot = regs->which_io;
0358 
0359     /*
0360      * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
0361      * lacks a "board#" property, something is very wrong.
0362      */
0363     if (!of_node_name_eq(bus->parent, bus_connection)) {
0364         printk(KERN_ERR "%pOF: Error, parent is not %s.\n",
0365             bus, bus_connection);
0366         goto err_out;
0367     }
0368     board_parent = bus->parent;
0369     board = of_getintprop_default(board_parent, "board#", -1);
0370     if (board == -1) {
0371         printk(KERN_ERR "%pOF: Error, lacks board# property.\n",
0372             board_parent);
0373         goto err_out;
0374     }
0375 
0376     sbusl = pil_to_sbus[real_irq];
0377     if (sbusl)
0378         pil = sun4d_encode_irq(board, sbusl, slot);
0379     else
0380         pil = real_irq;
0381 
0382     irq = _sun4d_build_device_irq(real_irq, pil, board);
0383 err_out:
0384     return irq;
0385 }
0386 
0387 static unsigned int sun4d_build_timer_irq(unsigned int board,
0388                                           unsigned int real_irq)
0389 {
0390     return _sun4d_build_device_irq(real_irq, real_irq, board);
0391 }
0392 
0393 
0394 static void __init sun4d_fixup_trap_table(void)
0395 {
0396 #ifdef CONFIG_SMP
0397     unsigned long flags;
0398     struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
0399 
0400     /* Adjust so that we jump directly to smp4d_ticker */
0401     lvl14_save[2] += smp4d_ticker - real_irq_entry;
0402 
0403     /* For SMP we use the level 14 ticker, however the bootup code
0404      * has copied the firmware's level 14 vector into the boot cpu's
0405      * trap table, we must fix this now or we get squashed.
0406      */
0407     local_irq_save(flags);
0408     patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
0409     trap_table->inst_one = lvl14_save[0];
0410     trap_table->inst_two = lvl14_save[1];
0411     trap_table->inst_three = lvl14_save[2];
0412     trap_table->inst_four = lvl14_save[3];
0413     local_ops->cache_all();
0414     local_irq_restore(flags);
0415 #endif
0416 }
0417 
0418 static void __init sun4d_init_timers(void)
0419 {
0420     struct device_node *dp;
0421     struct resource res;
0422     unsigned int irq;
0423     const u32 *reg;
0424     int err;
0425     int board;
0426 
0427     dp = of_find_node_by_name(NULL, "cpu-unit");
0428     if (!dp) {
0429         prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
0430         prom_halt();
0431     }
0432 
0433     /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
0434      * registers via any cpu's mapping.  The first 'reg' property is the
0435      * bootbus.
0436      */
0437     reg = of_get_property(dp, "reg", NULL);
0438     if (!reg) {
0439         prom_printf("sun4d_init_timers: No reg property\n");
0440         prom_halt();
0441     }
0442 
0443     board = of_getintprop_default(dp, "board#", -1);
0444     if (board == -1) {
0445         prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
0446         prom_halt();
0447     }
0448 
0449     of_node_put(dp);
0450 
0451     res.start = reg[1];
0452     res.end = reg[2] - 1;
0453     res.flags = reg[0] & 0xff;
0454     sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
0455                   sizeof(struct sun4d_timer_regs), "user timer");
0456     if (!sun4d_timers) {
0457         prom_printf("sun4d_init_timers: Can't map timer regs\n");
0458         prom_halt();
0459     }
0460 
0461 #ifdef CONFIG_SMP
0462     sparc_config.cs_period = SBUS_CLOCK_RATE * 2;  /* 2 seconds */
0463 #else
0464     sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec  */
0465     sparc_config.features |= FEAT_L10_CLOCKEVENT;
0466 #endif
0467     sparc_config.features |= FEAT_L10_CLOCKSOURCE;
0468     sbus_writel(timer_value(sparc_config.cs_period),
0469             &sun4d_timers->l10_timer_limit);
0470 
0471     master_l10_counter = &sun4d_timers->l10_cur_count;
0472 
0473     irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
0474     err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
0475     if (err) {
0476         prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
0477                      err);
0478         prom_halt();
0479     }
0480     sun4d_load_profile_irqs();
0481     sun4d_fixup_trap_table();
0482 }
0483 
0484 void __init sun4d_init_sbi_irq(void)
0485 {
0486     struct device_node *dp;
0487     int target_cpu;
0488 
0489     target_cpu = boot_cpu_id;
0490     for_each_node_by_name(dp, "sbi") {
0491         int devid = of_getintprop_default(dp, "device-id", 0);
0492         int board = of_getintprop_default(dp, "board#", 0);
0493         unsigned int mask;
0494 
0495         set_sbi_tid(devid, target_cpu << 3);
0496         board_to_cpu[board] = target_cpu;
0497 
0498         /* Get rid of pending irqs from PROM */
0499         mask = acquire_sbi(devid, 0xffffffff);
0500         if (mask) {
0501             printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
0502                    mask, board);
0503             release_sbi(devid, mask);
0504         }
0505     }
0506 }
0507 
0508 void __init sun4d_init_IRQ(void)
0509 {
0510     local_irq_disable();
0511 
0512     sparc_config.init_timers      = sun4d_init_timers;
0513     sparc_config.build_device_irq = sun4d_build_device_irq;
0514     sparc_config.clock_rate       = SBUS_CLOCK_RATE;
0515     sparc_config.clear_clock_irq  = sun4d_clear_clock_irq;
0516     sparc_config.load_profile_irq = sun4d_load_profile_irq;
0517 
0518     /* Cannot enable interrupts until OBP ticker is disabled. */
0519 }