linux/arch/sparc/kernel/sun4d_irq.c
<<
>>
Prefs
   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
  32struct sun4d_handler_data {
  33        unsigned int cpuid;    /* target cpu */
  34        unsigned int real_irq; /* interrupt level */
  35};
  36
  37
  38static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
  39{
  40        return (board + 1) << 5 | (lvl << 2) | slot;
  41}
  42
  43struct 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
  51static 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 */
  58static unsigned char board_to_cpu[32];
  59
  60static 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 */
  80DEFINE_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 */
  98static 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
 147void 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
 190static 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
 208static 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
 227static 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
 234static void sun4d_shutdown_irq(struct irq_data *data)
 235{
 236        sun4d_mask_irq(data);
 237        irq_unlink(data->irq);
 238}
 239
 240static 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. */
 250void __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
 268static void sun4d_clear_clock_irq(void)
 269{
 270        sbus_readl(&sun4d_timers->l10_timer_limit);
 271}
 272
 273static 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
 279static 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
 289static 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
 318err_out:
 319        return irq;
 320}
 321
 322
 323
 324static 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);
 383err_out:
 384        return irq;
 385}
 386
 387static 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
 394static 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
 418static 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
 484void __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
 508void __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}
 520