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