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