#define MPIC_MAX_CPUS          32
 #define MPIC_MAX_ISU           32
 
+#define MPIC_MAX_ERR      32
+#define MPIC_FSL_ERR_INT  16
+
 /*
  * Tsi108 implementation of MPIC has many differences from the original one
  */
        struct irq_chip         hc_ipi;
 #endif
        struct irq_chip         hc_tm;
+       struct irq_chip         hc_err;
        const char              *name;
        /* Flags */
        unsigned int            flags;
        /* vector numbers used for internal sources (ipi/timers) */
        unsigned int            ipi_vecs[4];
        unsigned int            timer_vecs[8];
+       /* vector numbers used for FSL MPIC error interrupts */
+       unsigned int            err_int_vecs[MPIC_MAX_ERR];
 
        /* Spurious vector to program into unused sources */
        unsigned int            spurious_vec;
        struct mpic_reg_bank    cpuregs[MPIC_MAX_CPUS];
        struct mpic_reg_bank    isus[MPIC_MAX_ISU];
 
+       /* ioremap'ed base for error interrupt registers */
+       u32 __iomem     *err_regs;
+
        /* Protected sources */
        unsigned long           *protected;
 
 #define MPIC_NO_RESET                  0x00004000
 /* Freescale MPIC (compatible includes "fsl,mpic") */
 #define MPIC_FSL                       0x00008000
+/* Freescale MPIC supports EIMR (error interrupt mask register).
+ * This flag is set for MPIC version >= 4.1 (version determined
+ * from the BRR1 register).
+*/
+#define MPIC_FSL_HAS_EIMR              0x00010000
 
 /* MPIC HW modification ID */
 #define MPIC_REGSET_MASK               0xf0000000
 
 obj-$(CONFIG_PPC_PMI)          += pmi.o
 obj-$(CONFIG_U3_DART)          += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
-obj-$(CONFIG_FSL_SOC)          += fsl_soc.o
+obj-$(CONFIG_FSL_SOC)          += fsl_soc.o fsl_mpic_err.o
 obj-$(CONFIG_FSL_PCI)          += fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)          += fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)          += fsl_lbc.o
 
--- /dev/null
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Varun Sethi <varun.sethi@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mpic.h>
+
+#include "mpic.h"
+
+#define MPIC_ERR_INT_BASE      0x3900
+#define MPIC_ERR_INT_EISR      0x0000
+#define MPIC_ERR_INT_EIMR      0x0010
+
+static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
+{
+       return in_be32(base + (err_reg >> 2));
+}
+
+static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
+{
+       out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
+}
+
+static void fsl_mpic_mask_err(struct irq_data *d)
+{
+       u32 eimr;
+       struct mpic *mpic = irq_data_get_irq_chip_data(d);
+       unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
+
+       eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+       eimr |= (1 << (31 - src));
+       mpic_fsl_err_write(mpic->err_regs, eimr);
+}
+
+static void fsl_mpic_unmask_err(struct irq_data *d)
+{
+       u32 eimr;
+       struct mpic *mpic = irq_data_get_irq_chip_data(d);
+       unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
+
+       eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+       eimr &= ~(1 << (31 - src));
+       mpic_fsl_err_write(mpic->err_regs, eimr);
+}
+
+static struct irq_chip fsl_mpic_err_chip = {
+       .irq_disable    = fsl_mpic_mask_err,
+       .irq_mask       = fsl_mpic_mask_err,
+       .irq_unmask     = fsl_mpic_unmask_err,
+};
+
+int mpic_setup_error_int(struct mpic *mpic, int intvec)
+{
+       int i;
+
+       mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
+       if (!mpic->err_regs) {
+               pr_err("could not map mpic error registers\n");
+               return -ENOMEM;
+       }
+       mpic->hc_err = fsl_mpic_err_chip;
+       mpic->hc_err.name = mpic->name;
+       mpic->flags |= MPIC_FSL_HAS_EIMR;
+       /* allocate interrupt vectors for error interrupts */
+       for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
+               mpic->err_int_vecs[i] = --intvec;
+
+       return 0;
+}
+
+int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
+{
+       if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
+           (hw >= mpic->err_int_vecs[0] &&
+            hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
+               WARN_ON(mpic->flags & MPIC_SECONDARY);
+
+               pr_debug("mpic: mapping as Error Interrupt\n");
+               irq_set_chip_data(virq, mpic);
+               irq_set_chip_and_handler(virq, &mpic->hc_err,
+                                        handle_level_irq);
+               return 1;
+       }
+
+       return 0;
+}
+
+static irqreturn_t fsl_error_int_handler(int irq, void *data)
+{
+       struct mpic *mpic = (struct mpic *) data;
+       u32 eisr, eimr;
+       int errint;
+       unsigned int cascade_irq;
+
+       eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
+       eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+
+       if (!(eisr & ~eimr))
+               return IRQ_NONE;
+
+       while (eisr) {
+               errint = __builtin_clz(eisr);
+               cascade_irq = irq_linear_revmap(mpic->irqhost,
+                                mpic->err_int_vecs[errint]);
+               WARN_ON(cascade_irq == NO_IRQ);
+               if (cascade_irq != NO_IRQ) {
+                       generic_handle_irq(cascade_irq);
+               } else {
+                       eimr |=  1 << (31 - errint);
+                       mpic_fsl_err_write(mpic->err_regs, eimr);
+               }
+               eisr &= ~(1 << (31 - errint));
+       }
+
+       return IRQ_HANDLED;
+}
+
+void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
+{
+       unsigned int virq;
+       int ret;
+
+       virq = irq_create_mapping(mpic->irqhost, irqnum);
+       if (virq == NO_IRQ) {
+               pr_err("Error interrupt setup failed\n");
+               return;
+       }
+
+       /* Mask all error interrupts */
+       mpic_fsl_err_write(mpic->err_regs, ~0);
+
+       ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
+                   "mpic-error-int", mpic);
+       if (ret)
+               pr_err("Failed to register error interrupt handler\n");
+}
 
                return 0;
        }
 
+       if (mpic_map_error_int(mpic, virq, hw))
+               return 0;
+
        if (hw >= mpic->num_sources)
                return -EINVAL;
 
                 */
                switch (intspec[2]) {
                case 0:
-               case 1: /* no EISR/EIMR support for now, treat as shared IRQ */
+                       break;
+               case 1:
+                       if (!(mpic->flags & MPIC_FSL_HAS_EIMR))
+                               break;
+
+                       if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs))
+                               return -EINVAL;
+
+                       *out_hwirq = mpic->err_int_vecs[intspec[3]];
+
                        break;
                case 2:
                        if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
        mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
        if (mpic->flags & MPIC_FSL) {
+               u32 brr1, version;
+               int ret;
+
                /*
                 * Yes, Freescale really did put global registers in the
                 * magic per-cpu area -- and they don't even show up in the
                 */
                mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
                         MPIC_CPU_THISBASE, 0x1000);
+
+               brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+                               MPIC_FSL_BRR1);
+               version = brr1 & MPIC_FSL_BRR1_VER;
+
+               /* Error interrupt mask register (EIMR) is required for
+                * handling individual device error interrupts. EIMR
+                * was added in MPIC version 4.1.
+                *
+                * Over here we reserve vector number space for error
+                * interrupt vectors. This space is stolen from the
+                * global vector number space, as in case of ipis
+                * and timer interrupts.
+                *
+                * Available vector space = intvec_top - 12, where 12
+                * is the number of vectors which have been consumed by
+                * ipis and timer interrupts.
+                */
+               if (version >= 0x401) {
+                       ret = mpic_setup_error_int(mpic, intvec_top - 12);
+                       if (ret)
+                               return NULL;
+               }
        }
 
        /* Reset */
                        num_timers = 8;
        }
 
+       /* FSL mpic error interrupt intialization */
+       if (mpic->flags & MPIC_FSL_HAS_EIMR)
+               mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);
+
        /* Initialize timers to our reserved vectors and mask them for now */
        for (i = 0; i < num_timers; i++) {
                unsigned int offset = mpic_tm_offset(mpic, i);
 
                             const struct cpumask *cpumask, bool force);
 extern void mpic_reset_core(int cpu);
 
+#ifdef CONFIG_FSL_SOC
+extern int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw);
+extern void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum);
+extern int mpic_setup_error_int(struct mpic *mpic, int intvec);
+#else
+static inline int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
+{
+       return 0;
+}
+
+
+static inline void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
+{
+       return;
+}
+
+static inline int mpic_setup_error_int(struct mpic *mpic, int intvec)
+{
+       return -1;
+}
+#endif
+
 #endif /* _POWERPC_SYSDEV_MPIC_H */