root/arch/sparc/kernel/sun4d_irq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun4d_encode_irq
  2. sun4d_sbus_handler_irq
  3. sun4d_handler_irq
  4. sun4d_mask_irq
  5. sun4d_unmask_irq
  6. sun4d_startup_irq
  7. sun4d_shutdown_irq
  8. sun4d_distribute_irqs
  9. sun4d_clear_clock_irq
  10. sun4d_load_profile_irq
  11. sun4d_load_profile_irqs
  12. _sun4d_build_device_irq
  13. sun4d_build_device_irq
  14. sun4d_build_timer_irq
  15. sun4d_fixup_trap_table
  16. sun4d_init_timers
  17. sun4d_init_sbi_irq
  18. sun4d_init_IRQ

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * SS1000/SC2000 interrupt handling.
   4  *
   5  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   6  *  Heavily based on arch/sparc/kernel/irq.c.
   7  */
   8 
   9 #include <linux/kernel_stat.h>
  10 #include <linux/slab.h>
  11 #include <linux/seq_file.h>
  12 
  13 #include <asm/timer.h>
  14 #include <asm/traps.h>
  15 #include <asm/irq.h>
  16 #include <asm/io.h>
  17 #include <asm/sbi.h>
  18 #include <asm/cacheflush.h>
  19 #include <asm/setup.h>
  20 #include <asm/oplib.h>
  21 
  22 #include "kernel.h"
  23 #include "irq.h"
  24 
  25 /* Sun4d interrupts fall roughly into two categories.  SBUS and
  26  * cpu local.  CPU local interrupts cover the timer interrupts
  27  * and whatnot, and we encode those as normal PILs between
  28  * 0 and 15.
  29  * SBUS interrupts are encodes as a combination of board, level and slot.
  30  */
  31 
  32 struct sun4d_handler_data {
  33         unsigned int cpuid;    /* target cpu */
  34         unsigned int real_irq; /* interrupt level */
  35 };
  36 
  37 
  38 static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
  39 {
  40         return (board + 1) << 5 | (lvl << 2) | slot;
  41 }
  42 
  43 struct sun4d_timer_regs {
  44         u32     l10_timer_limit;
  45         u32     l10_cur_countx;
  46         u32     l10_limit_noclear;
  47         u32     ctrl;
  48         u32     l10_cur_count;
  49 };
  50 
  51 static struct sun4d_timer_regs __iomem *sun4d_timers;
  52 
  53 #define SUN4D_TIMER_IRQ        10
  54 
  55 /* Specify which cpu handle interrupts from which board.
  56  * Index is board - value is cpu.
  57  */
  58 static unsigned char board_to_cpu[32];
  59 
  60 static int pil_to_sbus[] = {
  61         0,
  62         0,
  63         1,
  64         2,
  65         0,
  66         3,
  67         0,
  68         4,
  69         0,
  70         5,
  71         0,
  72         6,
  73         0,
  74         7,
  75         0,
  76         0,
  77 };
  78 
  79 /* Exported for sun4d_smp.c */
  80 DEFINE_SPINLOCK(sun4d_imsk_lock);
  81 
  82 /* SBUS interrupts are encoded integers including the board number
  83  * (plus one), the SBUS level, and the SBUS slot number.  Sun4D
  84  * IRQ dispatch is done by:
  85  *
  86  * 1) Reading the BW local interrupt table in order to get the bus
  87  *    interrupt mask.
  88  *
  89  *    This table is indexed by SBUS interrupt level which can be
  90  *    derived from the PIL we got interrupted on.
  91  *
  92  * 2) For each bus showing interrupt pending from #1, read the
  93  *    SBI interrupt state register.  This will indicate which slots
  94  *    have interrupts pending for that SBUS interrupt level.
  95  *
  96  * 3) Call the genreric IRQ support.
  97  */
  98 static void sun4d_sbus_handler_irq(int sbusl)
  99 {
 100         unsigned int bus_mask;
 101         unsigned int sbino, slot;
 102         unsigned int sbil;
 103 
 104         bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
 105         bw_clear_intr_mask(sbusl, bus_mask);
 106 
 107         sbil = (sbusl << 2);
 108         /* Loop for each pending SBI */
 109         for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
 110                 unsigned int idx, mask;
 111 
 112                 if (!(bus_mask & 1))
 113                         continue;
 114                 /* XXX This seems to ACK the irq twice.  acquire_sbi()
 115                  * XXX uses swap, therefore this writes 0xf << sbil,
 116                  * XXX then later release_sbi() will write the individual
 117                  * XXX bits which were set again.
 118                  */
 119                 mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
 120                 mask &= (0xf << sbil);
 121 
 122                 /* Loop for each pending SBI slot */
 123                 slot = (1 << sbil);
 124                 for (idx = 0; mask != 0; idx++, slot <<= 1) {
 125                         unsigned int pil;
 126                         struct irq_bucket *p;
 127 
 128                         if (!(mask & slot))
 129                                 continue;
 130 
 131                         mask &= ~slot;
 132                         pil = sun4d_encode_irq(sbino, sbusl, idx);
 133 
 134                         p = irq_map[pil];
 135                         while (p) {
 136                                 struct irq_bucket *next;
 137 
 138                                 next = p->next;
 139                                 generic_handle_irq(p->irq);
 140                                 p = next;
 141                         }
 142                         release_sbi(SBI2DEVID(sbino), slot);
 143                 }
 144         }
 145 }
 146 
 147 void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs)
 148 {
 149         struct pt_regs *old_regs;
 150         /* SBUS IRQ level (1 - 7) */
 151         int sbusl = pil_to_sbus[pil];
 152 
 153         /* FIXME: Is this necessary?? */
 154         cc_get_ipen();
 155 
 156         cc_set_iclr(1 << pil);
 157 
 158 #ifdef CONFIG_SMP
 159         /*
 160          * Check IPI data structures after IRQ has been cleared. Hard and Soft
 161          * IRQ can happen at the same time, so both cases are always handled.
 162          */
 163         if (pil == SUN4D_IPI_IRQ)
 164                 sun4d_ipi_interrupt();
 165 #endif
 166 
 167         old_regs = set_irq_regs(regs);
 168         irq_enter();
 169         if (sbusl == 0) {
 170                 /* cpu interrupt */
 171                 struct irq_bucket *p;
 172 
 173                 p = irq_map[pil];
 174                 while (p) {
 175                         struct irq_bucket *next;
 176 
 177                         next = p->next;
 178                         generic_handle_irq(p->irq);
 179                         p = next;
 180                 }
 181         } else {
 182                 /* SBUS interrupt */
 183                 sun4d_sbus_handler_irq(sbusl);
 184         }
 185         irq_exit();
 186         set_irq_regs(old_regs);
 187 }
 188 
 189 
 190 static void sun4d_mask_irq(struct irq_data *data)
 191 {
 192         struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data);
 193         unsigned int real_irq;
 194 #ifdef CONFIG_SMP
 195         int cpuid = handler_data->cpuid;
 196         unsigned long flags;
 197 #endif
 198         real_irq = handler_data->real_irq;
 199 #ifdef CONFIG_SMP
 200         spin_lock_irqsave(&sun4d_imsk_lock, flags);
 201         cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
 202         spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
 203 #else
 204         cc_set_imsk(cc_get_imsk() | (1 << real_irq));
 205 #endif
 206 }
 207 
 208 static void sun4d_unmask_irq(struct irq_data *data)
 209 {
 210         struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data);
 211         unsigned int real_irq;
 212 #ifdef CONFIG_SMP
 213         int cpuid = handler_data->cpuid;
 214         unsigned long flags;
 215 #endif
 216         real_irq = handler_data->real_irq;
 217 
 218 #ifdef CONFIG_SMP
 219         spin_lock_irqsave(&sun4d_imsk_lock, flags);
 220         cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
 221         spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
 222 #else
 223         cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
 224 #endif
 225 }
 226 
 227 static unsigned int sun4d_startup_irq(struct irq_data *data)
 228 {
 229         irq_link(data->irq);
 230         sun4d_unmask_irq(data);
 231         return 0;
 232 }
 233 
 234 static void sun4d_shutdown_irq(struct irq_data *data)
 235 {
 236         sun4d_mask_irq(data);
 237         irq_unlink(data->irq);
 238 }
 239 
 240 static struct irq_chip sun4d_irq = {
 241         .name           = "sun4d",
 242         .irq_startup    = sun4d_startup_irq,
 243         .irq_shutdown   = sun4d_shutdown_irq,
 244         .irq_unmask     = sun4d_unmask_irq,
 245         .irq_mask       = sun4d_mask_irq,
 246 };
 247 
 248 #ifdef CONFIG_SMP
 249 /* Setup IRQ distribution scheme. */
 250 void __init sun4d_distribute_irqs(void)
 251 {
 252         struct device_node *dp;
 253 
 254         int cpuid = cpu_logical_map(1);
 255 
 256         if (cpuid == -1)
 257                 cpuid = cpu_logical_map(0);
 258         for_each_node_by_name(dp, "sbi") {
 259                 int devid = of_getintprop_default(dp, "device-id", 0);
 260                 int board = of_getintprop_default(dp, "board#", 0);
 261                 board_to_cpu[board] = cpuid;
 262                 set_sbi_tid(devid, cpuid << 3);
 263         }
 264         printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
 265 }
 266 #endif
 267 
 268 static void sun4d_clear_clock_irq(void)
 269 {
 270         sbus_readl(&sun4d_timers->l10_timer_limit);
 271 }
 272 
 273 static void sun4d_load_profile_irq(int cpu, unsigned int limit)
 274 {
 275         unsigned int value = limit ? timer_value(limit) : 0;
 276         bw_set_prof_limit(cpu, value);
 277 }
 278 
 279 static void __init sun4d_load_profile_irqs(void)
 280 {
 281         int cpu = 0, mid;
 282 
 283         while (!cpu_find_by_instance(cpu, NULL, &mid)) {
 284                 sun4d_load_profile_irq(mid >> 3, 0);
 285                 cpu++;
 286         }
 287 }
 288 
 289 static unsigned int _sun4d_build_device_irq(unsigned int real_irq,
 290                                             unsigned int pil,
 291                                             unsigned int board)
 292 {
 293         struct sun4d_handler_data *handler_data;
 294         unsigned int irq;
 295 
 296         irq = irq_alloc(real_irq, pil);
 297         if (irq == 0) {
 298                 prom_printf("IRQ: allocate for %d %d %d failed\n",
 299                         real_irq, pil, board);
 300                 goto err_out;
 301         }
 302 
 303         handler_data = irq_get_handler_data(irq);
 304         if (unlikely(handler_data))
 305                 goto err_out;
 306 
 307         handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
 308         if (unlikely(!handler_data)) {
 309                 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
 310                 prom_halt();
 311         }
 312         handler_data->cpuid    = board_to_cpu[board];
 313         handler_data->real_irq = real_irq;
 314         irq_set_chip_and_handler_name(irq, &sun4d_irq,
 315                                       handle_level_irq, "level");
 316         irq_set_handler_data(irq, handler_data);
 317 
 318 err_out:
 319         return irq;
 320 }
 321 
 322 
 323 
 324 static unsigned int sun4d_build_device_irq(struct platform_device *op,
 325                                            unsigned int real_irq)
 326 {
 327         struct device_node *dp = op->dev.of_node;
 328         struct device_node *board_parent, *bus = dp->parent;
 329         char *bus_connection;
 330         const struct linux_prom_registers *regs;
 331         unsigned int pil;
 332         unsigned int irq;
 333         int board, slot;
 334         int sbusl;
 335 
 336         irq = real_irq;
 337         while (bus) {
 338                 if (of_node_name_eq(bus, "sbi")) {
 339                         bus_connection = "io-unit";
 340                         break;
 341                 }
 342 
 343                 if (of_node_name_eq(bus, "bootbus")) {
 344                         bus_connection = "cpu-unit";
 345                         break;
 346                 }
 347 
 348                 bus = bus->parent;
 349         }
 350         if (!bus)
 351                 goto err_out;
 352 
 353         regs = of_get_property(dp, "reg", NULL);
 354         if (!regs)
 355                 goto err_out;
 356 
 357         slot = regs->which_io;
 358 
 359         /*
 360          * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
 361          * lacks a "board#" property, something is very wrong.
 362          */
 363         if (!of_node_name_eq(bus->parent, bus_connection)) {
 364                 printk(KERN_ERR "%pOF: Error, parent is not %s.\n",
 365                         bus, bus_connection);
 366                 goto err_out;
 367         }
 368         board_parent = bus->parent;
 369         board = of_getintprop_default(board_parent, "board#", -1);
 370         if (board == -1) {
 371                 printk(KERN_ERR "%pOF: Error, lacks board# property.\n",
 372                         board_parent);
 373                 goto err_out;
 374         }
 375 
 376         sbusl = pil_to_sbus[real_irq];
 377         if (sbusl)
 378                 pil = sun4d_encode_irq(board, sbusl, slot);
 379         else
 380                 pil = real_irq;
 381 
 382         irq = _sun4d_build_device_irq(real_irq, pil, board);
 383 err_out:
 384         return irq;
 385 }
 386 
 387 static unsigned int sun4d_build_timer_irq(unsigned int board,
 388                                           unsigned int real_irq)
 389 {
 390         return _sun4d_build_device_irq(real_irq, real_irq, board);
 391 }
 392 
 393 
 394 static void __init sun4d_fixup_trap_table(void)
 395 {
 396 #ifdef CONFIG_SMP
 397         unsigned long flags;
 398         struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
 399 
 400         /* Adjust so that we jump directly to smp4d_ticker */
 401         lvl14_save[2] += smp4d_ticker - real_irq_entry;
 402 
 403         /* For SMP we use the level 14 ticker, however the bootup code
 404          * has copied the firmware's level 14 vector into the boot cpu's
 405          * trap table, we must fix this now or we get squashed.
 406          */
 407         local_irq_save(flags);
 408         patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
 409         trap_table->inst_one = lvl14_save[0];
 410         trap_table->inst_two = lvl14_save[1];
 411         trap_table->inst_three = lvl14_save[2];
 412         trap_table->inst_four = lvl14_save[3];
 413         local_ops->cache_all();
 414         local_irq_restore(flags);
 415 #endif
 416 }
 417 
 418 static void __init sun4d_init_timers(void)
 419 {
 420         struct device_node *dp;
 421         struct resource res;
 422         unsigned int irq;
 423         const u32 *reg;
 424         int err;
 425         int board;
 426 
 427         dp = of_find_node_by_name(NULL, "cpu-unit");
 428         if (!dp) {
 429                 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
 430                 prom_halt();
 431         }
 432 
 433         /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
 434          * registers via any cpu's mapping.  The first 'reg' property is the
 435          * bootbus.
 436          */
 437         reg = of_get_property(dp, "reg", NULL);
 438         if (!reg) {
 439                 prom_printf("sun4d_init_timers: No reg property\n");
 440                 prom_halt();
 441         }
 442 
 443         board = of_getintprop_default(dp, "board#", -1);
 444         if (board == -1) {
 445                 prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
 446                 prom_halt();
 447         }
 448 
 449         of_node_put(dp);
 450 
 451         res.start = reg[1];
 452         res.end = reg[2] - 1;
 453         res.flags = reg[0] & 0xff;
 454         sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
 455                                   sizeof(struct sun4d_timer_regs), "user timer");
 456         if (!sun4d_timers) {
 457                 prom_printf("sun4d_init_timers: Can't map timer regs\n");
 458                 prom_halt();
 459         }
 460 
 461 #ifdef CONFIG_SMP
 462         sparc_config.cs_period = SBUS_CLOCK_RATE * 2;  /* 2 seconds */
 463 #else
 464         sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec  */
 465         sparc_config.features |= FEAT_L10_CLOCKEVENT;
 466 #endif
 467         sparc_config.features |= FEAT_L10_CLOCKSOURCE;
 468         sbus_writel(timer_value(sparc_config.cs_period),
 469                     &sun4d_timers->l10_timer_limit);
 470 
 471         master_l10_counter = &sun4d_timers->l10_cur_count;
 472 
 473         irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
 474         err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
 475         if (err) {
 476                 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
 477                              err);
 478                 prom_halt();
 479         }
 480         sun4d_load_profile_irqs();
 481         sun4d_fixup_trap_table();
 482 }
 483 
 484 void __init sun4d_init_sbi_irq(void)
 485 {
 486         struct device_node *dp;
 487         int target_cpu;
 488 
 489         target_cpu = boot_cpu_id;
 490         for_each_node_by_name(dp, "sbi") {
 491                 int devid = of_getintprop_default(dp, "device-id", 0);
 492                 int board = of_getintprop_default(dp, "board#", 0);
 493                 unsigned int mask;
 494 
 495                 set_sbi_tid(devid, target_cpu << 3);
 496                 board_to_cpu[board] = target_cpu;
 497 
 498                 /* Get rid of pending irqs from PROM */
 499                 mask = acquire_sbi(devid, 0xffffffff);
 500                 if (mask) {
 501                         printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
 502                                mask, board);
 503                         release_sbi(devid, mask);
 504                 }
 505         }
 506 }
 507 
 508 void __init sun4d_init_IRQ(void)
 509 {
 510         local_irq_disable();
 511 
 512         sparc_config.init_timers      = sun4d_init_timers;
 513         sparc_config.build_device_irq = sun4d_build_device_irq;
 514         sparc_config.clock_rate       = SBUS_CLOCK_RATE;
 515         sparc_config.clear_clock_irq  = sun4d_clear_clock_irq;
 516         sparc_config.load_profile_irq = sun4d_load_profile_irq;
 517 
 518         /* Cannot enable interrupts until OBP ticker is disabled. */
 519 }

/* [<][>][^][v][top][bottom][index][help] */