linux/arch/mips/sgi-ip30/ip30-irq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ip30-irq.c: Highlevel interrupt handling for IP30 architecture.
   4 */
   5#include <linux/errno.h>
   6#include <linux/init.h>
   7#include <linux/interrupt.h>
   8#include <linux/irq.h>
   9#include <linux/percpu.h>
  10#include <linux/spinlock.h>
  11#include <linux/tick.h>
  12#include <linux/types.h>
  13
  14#include <asm/irq_cpu.h>
  15#include <asm/sgi/heart.h>
  16
  17struct heart_irq_data {
  18        u64     *irq_mask;
  19        int     cpu;
  20};
  21
  22static DECLARE_BITMAP(heart_irq_map, HEART_NUM_IRQS);
  23
  24static DEFINE_PER_CPU(unsigned long, irq_enable_mask);
  25
  26static inline int heart_alloc_int(void)
  27{
  28        int bit;
  29
  30again:
  31        bit = find_first_zero_bit(heart_irq_map, HEART_NUM_IRQS);
  32        if (bit >= HEART_NUM_IRQS)
  33                return -ENOSPC;
  34
  35        if (test_and_set_bit(bit, heart_irq_map))
  36                goto again;
  37
  38        return bit;
  39}
  40
  41static void ip30_error_irq(struct irq_desc *desc)
  42{
  43        u64 pending, mask, cause, error_irqs, err_reg;
  44        int cpu = smp_processor_id();
  45        int i;
  46
  47        pending = heart_read(&heart_regs->isr);
  48        mask = heart_read(&heart_regs->imr[cpu]);
  49        cause = heart_read(&heart_regs->cause);
  50        error_irqs = (pending & HEART_L4_INT_MASK & mask);
  51
  52        /* Bail if there's nothing to process (how did we get here, then?) */
  53        if (unlikely(!error_irqs))
  54                return;
  55
  56        /* Prevent any of the error IRQs from firing again. */
  57        heart_write(mask & ~(pending), &heart_regs->imr[cpu]);
  58
  59        /* Ack all error IRQs. */
  60        heart_write(HEART_L4_INT_MASK, &heart_regs->clear_isr);
  61
  62        /*
  63         * If we also have a cause value, then something happened, so loop
  64         * through the error IRQs and report a "heart attack" for each one
  65         * and print the value of the HEART cause register.  This is really
  66         * primitive right now, but it should hopefully work until a more
  67         * robust error handling routine can be put together.
  68         *
  69         * Refer to heart.h for the HC_* macros to work out the cause
  70         * that got us here.
  71         */
  72        if (cause) {
  73                pr_alert("IP30: CPU%d: HEART ATTACK! ISR = 0x%.16llx, IMR = 0x%.16llx, CAUSE = 0x%.16llx\n",
  74                         cpu, pending, mask, cause);
  75
  76                if (cause & HC_COR_MEM_ERR) {
  77                        err_reg = heart_read(&heart_regs->mem_err_addr);
  78                        pr_alert("  HEART_MEMERR_ADDR = 0x%.16llx\n", err_reg);
  79                }
  80
  81                /* i = 63; i >= 51; i-- */
  82                for (i = HEART_ERR_MASK_END; i >= HEART_ERR_MASK_START; i--)
  83                        if ((pending >> i) & 1)
  84                                pr_alert("  HEART Error IRQ #%d\n", i);
  85
  86                /* XXX: Seems possible to loop forever here, so panic(). */
  87                panic("IP30: Fatal Error !\n");
  88        }
  89
  90        /* Unmask the error IRQs. */
  91        heart_write(mask, &heart_regs->imr[cpu]);
  92}
  93
  94static void ip30_normal_irq(struct irq_desc *desc)
  95{
  96        int cpu = smp_processor_id();
  97        struct irq_domain *domain;
  98        u64 pend, mask;
  99        int irq;
 100
 101        pend = heart_read(&heart_regs->isr);
 102        mask = (heart_read(&heart_regs->imr[cpu]) &
 103                (HEART_L0_INT_MASK | HEART_L1_INT_MASK | HEART_L2_INT_MASK));
 104
 105        pend &= mask;
 106        if (unlikely(!pend))
 107                return;
 108
 109#ifdef CONFIG_SMP
 110        if (pend & BIT_ULL(HEART_L2_INT_RESCHED_CPU_0)) {
 111                heart_write(BIT_ULL(HEART_L2_INT_RESCHED_CPU_0),
 112                            &heart_regs->clear_isr);
 113                scheduler_ipi();
 114        } else if (pend & BIT_ULL(HEART_L2_INT_RESCHED_CPU_1)) {
 115                heart_write(BIT_ULL(HEART_L2_INT_RESCHED_CPU_1),
 116                            &heart_regs->clear_isr);
 117                scheduler_ipi();
 118        } else if (pend & BIT_ULL(HEART_L2_INT_CALL_CPU_0)) {
 119                heart_write(BIT_ULL(HEART_L2_INT_CALL_CPU_0),
 120                            &heart_regs->clear_isr);
 121                generic_smp_call_function_interrupt();
 122        } else if (pend & BIT_ULL(HEART_L2_INT_CALL_CPU_1)) {
 123                heart_write(BIT_ULL(HEART_L2_INT_CALL_CPU_1),
 124                            &heart_regs->clear_isr);
 125                generic_smp_call_function_interrupt();
 126        } else
 127#endif
 128        {
 129                domain = irq_desc_get_handler_data(desc);
 130                irq = irq_linear_revmap(domain, __ffs(pend));
 131                if (irq)
 132                        generic_handle_irq(irq);
 133                else
 134                        spurious_interrupt();
 135        }
 136}
 137
 138static void ip30_ack_heart_irq(struct irq_data *d)
 139{
 140        heart_write(BIT_ULL(d->hwirq), &heart_regs->clear_isr);
 141}
 142
 143static void ip30_mask_heart_irq(struct irq_data *d)
 144{
 145        struct heart_irq_data *hd = irq_data_get_irq_chip_data(d);
 146        unsigned long *mask = &per_cpu(irq_enable_mask, hd->cpu);
 147
 148        clear_bit(d->hwirq, mask);
 149        heart_write(*mask, &heart_regs->imr[hd->cpu]);
 150}
 151
 152static void ip30_mask_and_ack_heart_irq(struct irq_data *d)
 153{
 154        struct heart_irq_data *hd = irq_data_get_irq_chip_data(d);
 155        unsigned long *mask = &per_cpu(irq_enable_mask, hd->cpu);
 156
 157        clear_bit(d->hwirq, mask);
 158        heart_write(*mask, &heart_regs->imr[hd->cpu]);
 159        heart_write(BIT_ULL(d->hwirq), &heart_regs->clear_isr);
 160}
 161
 162static void ip30_unmask_heart_irq(struct irq_data *d)
 163{
 164        struct heart_irq_data *hd = irq_data_get_irq_chip_data(d);
 165        unsigned long *mask = &per_cpu(irq_enable_mask, hd->cpu);
 166
 167        set_bit(d->hwirq, mask);
 168        heart_write(*mask, &heart_regs->imr[hd->cpu]);
 169}
 170
 171static int ip30_set_heart_irq_affinity(struct irq_data *d,
 172                                       const struct cpumask *mask, bool force)
 173{
 174        struct heart_irq_data *hd = irq_data_get_irq_chip_data(d);
 175
 176        if (!hd)
 177                return -EINVAL;
 178
 179        if (irqd_is_started(d))
 180                ip30_mask_and_ack_heart_irq(d);
 181
 182        hd->cpu = cpumask_first_and(mask, cpu_online_mask);
 183
 184        if (irqd_is_started(d))
 185                ip30_unmask_heart_irq(d);
 186
 187        irq_data_update_effective_affinity(d, cpumask_of(hd->cpu));
 188
 189        return 0;
 190}
 191
 192static struct irq_chip heart_irq_chip = {
 193        .name                   = "HEART",
 194        .irq_ack                = ip30_ack_heart_irq,
 195        .irq_mask               = ip30_mask_heart_irq,
 196        .irq_mask_ack           = ip30_mask_and_ack_heart_irq,
 197        .irq_unmask             = ip30_unmask_heart_irq,
 198        .irq_set_affinity       = ip30_set_heart_irq_affinity,
 199};
 200
 201static int heart_domain_alloc(struct irq_domain *domain, unsigned int virq,
 202                              unsigned int nr_irqs, void *arg)
 203{
 204        struct irq_alloc_info *info = arg;
 205        struct heart_irq_data *hd;
 206        int hwirq;
 207
 208        if (nr_irqs > 1 || !info)
 209                return -EINVAL;
 210
 211        hd = kzalloc(sizeof(*hd), GFP_KERNEL);
 212        if (!hd)
 213                return -ENOMEM;
 214
 215        hwirq = heart_alloc_int();
 216        if (hwirq < 0) {
 217                kfree(hd);
 218                return -EAGAIN;
 219        }
 220        irq_domain_set_info(domain, virq, hwirq, &heart_irq_chip, hd,
 221                            handle_level_irq, NULL, NULL);
 222
 223        return 0;
 224}
 225
 226static void heart_domain_free(struct irq_domain *domain,
 227                              unsigned int virq, unsigned int nr_irqs)
 228{
 229        struct irq_data *irqd;
 230
 231        if (nr_irqs > 1)
 232                return;
 233
 234        irqd = irq_domain_get_irq_data(domain, virq);
 235        clear_bit(irqd->hwirq, heart_irq_map);
 236        if (irqd && irqd->chip_data)
 237                kfree(irqd->chip_data);
 238}
 239
 240static const struct irq_domain_ops heart_domain_ops = {
 241        .alloc = heart_domain_alloc,
 242        .free  = heart_domain_free,
 243};
 244
 245void __init ip30_install_ipi(void)
 246{
 247        int cpu = smp_processor_id();
 248        unsigned long *mask = &per_cpu(irq_enable_mask, cpu);
 249
 250        set_bit(HEART_L2_INT_RESCHED_CPU_0 + cpu, mask);
 251        heart_write(BIT_ULL(HEART_L2_INT_RESCHED_CPU_0 + cpu),
 252                    &heart_regs->clear_isr);
 253        set_bit(HEART_L2_INT_CALL_CPU_0 + cpu, mask);
 254        heart_write(BIT_ULL(HEART_L2_INT_CALL_CPU_0 + cpu),
 255                    &heart_regs->clear_isr);
 256
 257        heart_write(*mask, &heart_regs->imr[cpu]);
 258}
 259
 260void __init arch_init_irq(void)
 261{
 262        struct irq_domain *domain;
 263        struct fwnode_handle *fn;
 264        unsigned long *mask;
 265        int i;
 266
 267        mips_cpu_irq_init();
 268
 269        /* Mask all IRQs. */
 270        heart_write(HEART_CLR_ALL_MASK, &heart_regs->imr[0]);
 271        heart_write(HEART_CLR_ALL_MASK, &heart_regs->imr[1]);
 272        heart_write(HEART_CLR_ALL_MASK, &heart_regs->imr[2]);
 273        heart_write(HEART_CLR_ALL_MASK, &heart_regs->imr[3]);
 274
 275        /* Ack everything. */
 276        heart_write(HEART_ACK_ALL_MASK, &heart_regs->clear_isr);
 277
 278        /* Enable specific HEART error IRQs for each CPU. */
 279        mask = &per_cpu(irq_enable_mask, 0);
 280        *mask |= HEART_CPU0_ERR_MASK;
 281        heart_write(*mask, &heart_regs->imr[0]);
 282        mask = &per_cpu(irq_enable_mask, 1);
 283        *mask |= HEART_CPU1_ERR_MASK;
 284        heart_write(*mask, &heart_regs->imr[1]);
 285
 286        /*
 287         * Some HEART bits are reserved by hardware or by software convention.
 288         * Mark these as reserved right away so they won't be accidentally
 289         * used later.
 290         */
 291        set_bit(HEART_L0_INT_GENERIC, heart_irq_map);
 292        set_bit(HEART_L0_INT_FLOW_CTRL_HWTR_0, heart_irq_map);
 293        set_bit(HEART_L0_INT_FLOW_CTRL_HWTR_1, heart_irq_map);
 294        set_bit(HEART_L2_INT_RESCHED_CPU_0, heart_irq_map);
 295        set_bit(HEART_L2_INT_RESCHED_CPU_1, heart_irq_map);
 296        set_bit(HEART_L2_INT_CALL_CPU_0, heart_irq_map);
 297        set_bit(HEART_L2_INT_CALL_CPU_1, heart_irq_map);
 298        set_bit(HEART_L3_INT_TIMER, heart_irq_map);
 299
 300        /* Reserve the error interrupts (#51 to #63). */
 301        for (i = HEART_L4_INT_XWID_ERR_9; i <= HEART_L4_INT_HEART_EXCP; i++)
 302                set_bit(i, heart_irq_map);
 303
 304        fn = irq_domain_alloc_named_fwnode("HEART");
 305        WARN_ON(fn == NULL);
 306        if (!fn)
 307                return;
 308        domain = irq_domain_create_linear(fn, HEART_NUM_IRQS,
 309                                          &heart_domain_ops, NULL);
 310        WARN_ON(domain == NULL);
 311        if (!domain)
 312                return;
 313
 314        irq_set_default_host(domain);
 315
 316        irq_set_percpu_devid(IP30_HEART_L0_IRQ);
 317        irq_set_chained_handler_and_data(IP30_HEART_L0_IRQ, ip30_normal_irq,
 318                                         domain);
 319        irq_set_percpu_devid(IP30_HEART_L1_IRQ);
 320        irq_set_chained_handler_and_data(IP30_HEART_L1_IRQ, ip30_normal_irq,
 321                                         domain);
 322        irq_set_percpu_devid(IP30_HEART_L2_IRQ);
 323        irq_set_chained_handler_and_data(IP30_HEART_L2_IRQ, ip30_normal_irq,
 324                                         domain);
 325        irq_set_percpu_devid(IP30_HEART_ERR_IRQ);
 326        irq_set_chained_handler_and_data(IP30_HEART_ERR_IRQ, ip30_error_irq,
 327                                         domain);
 328}
 329