Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 Freescale Semiconductor, Inc.
0004  *
0005  * Author: Varun Sethi <varun.sethi@freescale.com>
0006  */
0007 
0008 #include <linux/irq.h>
0009 #include <linux/smp.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/irqdomain.h>
0012 
0013 #include <asm/io.h>
0014 #include <asm/irq.h>
0015 #include <asm/mpic.h>
0016 
0017 #include "mpic.h"
0018 
0019 #define MPIC_ERR_INT_BASE   0x3900
0020 #define MPIC_ERR_INT_EISR   0x0000
0021 #define MPIC_ERR_INT_EIMR   0x0010
0022 
0023 static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
0024 {
0025     return in_be32(base + (err_reg >> 2));
0026 }
0027 
0028 static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
0029 {
0030     out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
0031 }
0032 
0033 static void fsl_mpic_mask_err(struct irq_data *d)
0034 {
0035     u32 eimr;
0036     struct mpic *mpic = irq_data_get_irq_chip_data(d);
0037     unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
0038 
0039     eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
0040     eimr |= (1 << (31 - src));
0041     mpic_fsl_err_write(mpic->err_regs, eimr);
0042 }
0043 
0044 static void fsl_mpic_unmask_err(struct irq_data *d)
0045 {
0046     u32 eimr;
0047     struct mpic *mpic = irq_data_get_irq_chip_data(d);
0048     unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
0049 
0050     eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
0051     eimr &= ~(1 << (31 - src));
0052     mpic_fsl_err_write(mpic->err_regs, eimr);
0053 }
0054 
0055 static struct irq_chip fsl_mpic_err_chip = {
0056     .irq_disable    = fsl_mpic_mask_err,
0057     .irq_mask   = fsl_mpic_mask_err,
0058     .irq_unmask = fsl_mpic_unmask_err,
0059 };
0060 
0061 int __init mpic_setup_error_int(struct mpic *mpic, int intvec)
0062 {
0063     int i;
0064 
0065     mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
0066     if (!mpic->err_regs) {
0067         pr_err("could not map mpic error registers\n");
0068         return -ENOMEM;
0069     }
0070     mpic->hc_err = fsl_mpic_err_chip;
0071     mpic->hc_err.name = mpic->name;
0072     mpic->flags |= MPIC_FSL_HAS_EIMR;
0073     /* allocate interrupt vectors for error interrupts */
0074     for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
0075         mpic->err_int_vecs[i] = intvec--;
0076 
0077     return 0;
0078 }
0079 
0080 int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
0081 {
0082     if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
0083         (hw >= mpic->err_int_vecs[0] &&
0084          hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
0085         WARN_ON(mpic->flags & MPIC_SECONDARY);
0086 
0087         pr_debug("mpic: mapping as Error Interrupt\n");
0088         irq_set_chip_data(virq, mpic);
0089         irq_set_chip_and_handler(virq, &mpic->hc_err,
0090                      handle_level_irq);
0091         return 1;
0092     }
0093 
0094     return 0;
0095 }
0096 
0097 static irqreturn_t fsl_error_int_handler(int irq, void *data)
0098 {
0099     struct mpic *mpic = (struct mpic *) data;
0100     u32 eisr, eimr;
0101     int errint;
0102 
0103     eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
0104     eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
0105 
0106     if (!(eisr & ~eimr))
0107         return IRQ_NONE;
0108 
0109     while (eisr) {
0110         int ret;
0111         errint = __builtin_clz(eisr);
0112         ret = generic_handle_domain_irq(mpic->irqhost,
0113                         mpic->err_int_vecs[errint]);
0114         if (WARN_ON(ret)) {
0115             eimr |=  1 << (31 - errint);
0116             mpic_fsl_err_write(mpic->err_regs, eimr);
0117         }
0118         eisr &= ~(1 << (31 - errint));
0119     }
0120 
0121     return IRQ_HANDLED;
0122 }
0123 
0124 void __init mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
0125 {
0126     unsigned int virq;
0127     int ret;
0128 
0129     virq = irq_create_mapping(mpic->irqhost, irqnum);
0130     if (!virq) {
0131         pr_err("Error interrupt setup failed\n");
0132         return;
0133     }
0134 
0135     /* Mask all error interrupts */
0136     mpic_fsl_err_write(mpic->err_regs, ~0);
0137 
0138     ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
0139             "mpic-error-int", mpic);
0140     if (ret)
0141         pr_err("Failed to register error interrupt handler\n");
0142 }