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