linux/arch/powerpc/sysdev/fsl_mpic_err.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Freescale Semiconductor, Inc.
   3 *
   4 * Author: Varun Sethi <varun.sethi@freescale.com>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; version 2 of the
   9 * License.
  10 *
  11 */
  12
  13#include <linux/irq.h>
  14#include <linux/smp.h>
  15#include <linux/interrupt.h>
  16
  17#include <asm/io.h>
  18#include <asm/irq.h>
  19#include <asm/mpic.h>
  20
  21#include "mpic.h"
  22
  23#define MPIC_ERR_INT_BASE       0x3900
  24#define MPIC_ERR_INT_EISR       0x0000
  25#define MPIC_ERR_INT_EIMR       0x0010
  26
  27static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
  28{
  29        return in_be32(base + (err_reg >> 2));
  30}
  31
  32static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
  33{
  34        out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
  35}
  36
  37static void fsl_mpic_mask_err(struct irq_data *d)
  38{
  39        u32 eimr;
  40        struct mpic *mpic = irq_data_get_irq_chip_data(d);
  41        unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
  42
  43        eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
  44        eimr |= (1 << (31 - src));
  45        mpic_fsl_err_write(mpic->err_regs, eimr);
  46}
  47
  48static void fsl_mpic_unmask_err(struct irq_data *d)
  49{
  50        u32 eimr;
  51        struct mpic *mpic = irq_data_get_irq_chip_data(d);
  52        unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
  53
  54        eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
  55        eimr &= ~(1 << (31 - src));
  56        mpic_fsl_err_write(mpic->err_regs, eimr);
  57}
  58
  59static struct irq_chip fsl_mpic_err_chip = {
  60        .irq_disable    = fsl_mpic_mask_err,
  61        .irq_mask       = fsl_mpic_mask_err,
  62        .irq_unmask     = fsl_mpic_unmask_err,
  63};
  64
  65int mpic_setup_error_int(struct mpic *mpic, int intvec)
  66{
  67        int i;
  68
  69        mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
  70        if (!mpic->err_regs) {
  71                pr_err("could not map mpic error registers\n");
  72                return -ENOMEM;
  73        }
  74        mpic->hc_err = fsl_mpic_err_chip;
  75        mpic->hc_err.name = mpic->name;
  76        mpic->flags |= MPIC_FSL_HAS_EIMR;
  77        /* allocate interrupt vectors for error interrupts */
  78        for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
  79                mpic->err_int_vecs[i] = --intvec;
  80
  81        return 0;
  82}
  83
  84int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
  85{
  86        if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
  87            (hw >= mpic->err_int_vecs[0] &&
  88             hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
  89                WARN_ON(mpic->flags & MPIC_SECONDARY);
  90
  91                pr_debug("mpic: mapping as Error Interrupt\n");
  92                irq_set_chip_data(virq, mpic);
  93                irq_set_chip_and_handler(virq, &mpic->hc_err,
  94                                         handle_level_irq);
  95                return 1;
  96        }
  97
  98        return 0;
  99}
 100
 101static irqreturn_t fsl_error_int_handler(int irq, void *data)
 102{
 103        struct mpic *mpic = (struct mpic *) data;
 104        u32 eisr, eimr;
 105        int errint;
 106        unsigned int cascade_irq;
 107
 108        eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
 109        eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
 110
 111        if (!(eisr & ~eimr))
 112                return IRQ_NONE;
 113
 114        while (eisr) {
 115                errint = __builtin_clz(eisr);
 116                cascade_irq = irq_linear_revmap(mpic->irqhost,
 117                                 mpic->err_int_vecs[errint]);
 118                WARN_ON(cascade_irq == NO_IRQ);
 119                if (cascade_irq != NO_IRQ) {
 120                        generic_handle_irq(cascade_irq);
 121                } else {
 122                        eimr |=  1 << (31 - errint);
 123                        mpic_fsl_err_write(mpic->err_regs, eimr);
 124                }
 125                eisr &= ~(1 << (31 - errint));
 126        }
 127
 128        return IRQ_HANDLED;
 129}
 130
 131void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
 132{
 133        unsigned int virq;
 134        int ret;
 135
 136        virq = irq_create_mapping(mpic->irqhost, irqnum);
 137        if (virq == NO_IRQ) {
 138                pr_err("Error interrupt setup failed\n");
 139                return;
 140        }
 141
 142        /* Mask all error interrupts */
 143        mpic_fsl_err_write(mpic->err_regs, ~0);
 144
 145        ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
 146                    "mpic-error-int", mpic);
 147        if (ret)
 148                pr_err("Failed to register error interrupt handler\n");
 149}
 150