linux/arch/mips/loongson64/loongson-3/irq.c
<<
>>
Prefs
   1#include <loongson.h>
   2#include <irq.h>
   3#include <linux/interrupt.h>
   4#include <linux/module.h>
   5
   6#include <asm/irq_cpu.h>
   7#include <asm/i8259.h>
   8#include <asm/mipsregs.h>
   9
  10#include "smp.h"
  11
  12unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
  13
  14static void ht_irqdispatch(void)
  15{
  16        unsigned int i, irq;
  17
  18        irq = LOONGSON_HT1_INT_VECTOR(0);
  19        LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
  20
  21        for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
  22                if (irq & (0x1 << ht_irq[i]))
  23                        do_IRQ(ht_irq[i]);
  24        }
  25}
  26
  27#define UNUSED_IPS (CAUSEF_IP5 | CAUSEF_IP4 | CAUSEF_IP1 | CAUSEF_IP0)
  28
  29void mach_irq_dispatch(unsigned int pending)
  30{
  31        if (pending & CAUSEF_IP7)
  32                do_IRQ(LOONGSON_TIMER_IRQ);
  33#if defined(CONFIG_SMP)
  34        if (pending & CAUSEF_IP6)
  35                loongson3_ipi_interrupt(NULL);
  36#endif
  37        if (pending & CAUSEF_IP3)
  38                ht_irqdispatch();
  39        if (pending & CAUSEF_IP2)
  40                do_IRQ(LOONGSON_UART_IRQ);
  41        if (pending & UNUSED_IPS) {
  42                pr_err("%s : spurious interrupt\n", __func__);
  43                spurious_interrupt();
  44        }
  45}
  46
  47static struct irqaction cascade_irqaction = {
  48        .handler = no_action,
  49        .flags = IRQF_NO_SUSPEND,
  50        .name = "cascade",
  51};
  52
  53static inline void mask_loongson_irq(struct irq_data *d)
  54{
  55        clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
  56        irq_disable_hazard();
  57
  58        /* Workaround: UART IRQ may deliver to any core */
  59        if (d->irq == LOONGSON_UART_IRQ) {
  60                int cpu = smp_processor_id();
  61                int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node;
  62                int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node;
  63                u64 intenclr_addr = smp_group[node_id] |
  64                        (u64)(&LOONGSON_INT_ROUTER_INTENCLR);
  65                u64 introuter_lpc_addr = smp_group[node_id] |
  66                        (u64)(&LOONGSON_INT_ROUTER_LPC);
  67
  68                *(volatile u32 *)intenclr_addr = 1 << 10;
  69                *(volatile u8 *)introuter_lpc_addr = 0x10 + (1<<core_id);
  70        }
  71}
  72
  73static inline void unmask_loongson_irq(struct irq_data *d)
  74{
  75        /* Workaround: UART IRQ may deliver to any core */
  76        if (d->irq == LOONGSON_UART_IRQ) {
  77                int cpu = smp_processor_id();
  78                int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node;
  79                int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node;
  80                u64 intenset_addr = smp_group[node_id] |
  81                        (u64)(&LOONGSON_INT_ROUTER_INTENSET);
  82                u64 introuter_lpc_addr = smp_group[node_id] |
  83                        (u64)(&LOONGSON_INT_ROUTER_LPC);
  84
  85                *(volatile u32 *)intenset_addr = 1 << 10;
  86                *(volatile u8 *)introuter_lpc_addr = 0x10 + (1<<core_id);
  87        }
  88
  89        set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
  90        irq_enable_hazard();
  91}
  92
  93 /* For MIPS IRQs which shared by all cores */
  94static struct irq_chip loongson_irq_chip = {
  95        .name           = "Loongson",
  96        .irq_ack        = mask_loongson_irq,
  97        .irq_mask       = mask_loongson_irq,
  98        .irq_mask_ack   = mask_loongson_irq,
  99        .irq_unmask     = unmask_loongson_irq,
 100        .irq_eoi        = unmask_loongson_irq,
 101};
 102
 103void irq_router_init(void)
 104{
 105        int i;
 106
 107        /* route LPC int to cpu core0 int 0 */
 108        LOONGSON_INT_ROUTER_LPC =
 109                LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 0);
 110        /* route HT1 int0 ~ int7 to cpu core0 INT1*/
 111        for (i = 0; i < 8; i++)
 112                LOONGSON_INT_ROUTER_HT1(i) =
 113                        LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 1);
 114        /* enable HT1 interrupt */
 115        LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
 116        /* enable router interrupt intenset */
 117        LOONGSON_INT_ROUTER_INTENSET =
 118                LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
 119}
 120
 121void __init mach_init_irq(void)
 122{
 123        clear_c0_status(ST0_IM | ST0_BEV);
 124
 125        irq_router_init();
 126        mips_cpu_irq_init();
 127        init_i8259_irqs();
 128        irq_set_chip_and_handler(LOONGSON_UART_IRQ,
 129                        &loongson_irq_chip, handle_level_irq);
 130
 131        /* setup HT1 irq */
 132        setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction);
 133
 134        set_c0_status(STATUSF_IP2 | STATUSF_IP6);
 135}
 136
 137#ifdef CONFIG_HOTPLUG_CPU
 138
 139void fixup_irqs(void)
 140{
 141        irq_cpu_offline();
 142        clear_c0_status(ST0_IM);
 143}
 144
 145#endif
 146