1 /*
2 * CoreNet Coherency Fabric error reporting
3 *
4 * Copyright 2014 Freescale Semiconductor Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12 #include <linux/interrupt.h>
13 #include <linux/io.h>
14 #include <linux/irq.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_address.h>
18 #include <linux/of_device.h>
19 #include <linux/of_irq.h>
20 #include <linux/platform_device.h>
21
22 enum ccf_version {
23 CCF1,
24 CCF2,
25 };
26
27 struct ccf_info {
28 enum ccf_version version;
29 int err_reg_offs;
30 };
31
32 static const struct ccf_info ccf1_info = {
33 .version = CCF1,
34 .err_reg_offs = 0xa00,
35 };
36
37 static const struct ccf_info ccf2_info = {
38 .version = CCF2,
39 .err_reg_offs = 0xe40,
40 };
41
42 static const struct of_device_id ccf_matches[] = {
43 {
44 .compatible = "fsl,corenet1-cf",
45 .data = &ccf1_info,
46 },
47 {
48 .compatible = "fsl,corenet2-cf",
49 .data = &ccf2_info,
50 },
51 {}
52 };
53
54 struct ccf_err_regs {
55 u32 errdet; /* 0x00 Error Detect Register */
56 /* 0x04 Error Enable (ccf1)/Disable (ccf2) Register */
57 u32 errdis;
58 /* 0x08 Error Interrupt Enable Register (ccf2 only) */
59 u32 errinten;
60 u32 cecar; /* 0x0c Error Capture Attribute Register */
61 u32 cecaddrh; /* 0x10 Error Capture Address High */
62 u32 cecaddrl; /* 0x14 Error Capture Address Low */
63 u32 cecar2; /* 0x18 Error Capture Attribute Register 2 */
64 };
65
66 /* LAE/CV also valid for errdis and errinten */
67 #define ERRDET_LAE (1 << 0) /* Local Access Error */
68 #define ERRDET_CV (1 << 1) /* Coherency Violation */
69 #define ERRDET_CTYPE_SHIFT 26 /* Capture Type (ccf2 only) */
70 #define ERRDET_CTYPE_MASK (0x1f << ERRDET_CTYPE_SHIFT)
71 #define ERRDET_CAP (1 << 31) /* Capture Valid (ccf2 only) */
72
73 #define CECAR_VAL (1 << 0) /* Valid (ccf1 only) */
74 #define CECAR_UVT (1 << 15) /* Unavailable target ID (ccf1) */
75 #define CECAR_SRCID_SHIFT_CCF1 24
76 #define CECAR_SRCID_MASK_CCF1 (0xff << CECAR_SRCID_SHIFT_CCF1)
77 #define CECAR_SRCID_SHIFT_CCF2 18
78 #define CECAR_SRCID_MASK_CCF2 (0xff << CECAR_SRCID_SHIFT_CCF2)
79
80 #define CECADDRH_ADDRH 0xff
81
82 struct ccf_private {
83 const struct ccf_info *info;
84 struct device *dev;
85 void __iomem *regs;
86 struct ccf_err_regs __iomem *err_regs;
87 };
88
ccf_irq(int irq,void * dev_id)89 static irqreturn_t ccf_irq(int irq, void *dev_id)
90 {
91 struct ccf_private *ccf = dev_id;
92 static DEFINE_RATELIMIT_STATE(ratelimit, DEFAULT_RATELIMIT_INTERVAL,
93 DEFAULT_RATELIMIT_BURST);
94 u32 errdet, cecar, cecar2;
95 u64 addr;
96 u32 src_id;
97 bool uvt = false;
98 bool cap_valid = false;
99
100 errdet = ioread32be(&ccf->err_regs->errdet);
101 cecar = ioread32be(&ccf->err_regs->cecar);
102 cecar2 = ioread32be(&ccf->err_regs->cecar2);
103 addr = ioread32be(&ccf->err_regs->cecaddrl);
104 addr |= ((u64)(ioread32be(&ccf->err_regs->cecaddrh) &
105 CECADDRH_ADDRH)) << 32;
106
107 if (!__ratelimit(&ratelimit))
108 goto out;
109
110 switch (ccf->info->version) {
111 case CCF1:
112 if (cecar & CECAR_VAL) {
113 if (cecar & CECAR_UVT)
114 uvt = true;
115
116 src_id = (cecar & CECAR_SRCID_MASK_CCF1) >>
117 CECAR_SRCID_SHIFT_CCF1;
118 cap_valid = true;
119 }
120
121 break;
122 case CCF2:
123 if (errdet & ERRDET_CAP) {
124 src_id = (cecar & CECAR_SRCID_MASK_CCF2) >>
125 CECAR_SRCID_SHIFT_CCF2;
126 cap_valid = true;
127 }
128
129 break;
130 }
131
132 dev_crit(ccf->dev, "errdet 0x%08x cecar 0x%08x cecar2 0x%08x\n",
133 errdet, cecar, cecar2);
134
135 if (errdet & ERRDET_LAE) {
136 if (uvt)
137 dev_crit(ccf->dev, "LAW Unavailable Target ID\n");
138 else
139 dev_crit(ccf->dev, "Local Access Window Error\n");
140 }
141
142 if (errdet & ERRDET_CV)
143 dev_crit(ccf->dev, "Coherency Violation\n");
144
145 if (cap_valid) {
146 dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n",
147 addr, src_id);
148 }
149
150 out:
151 iowrite32be(errdet, &ccf->err_regs->errdet);
152 return errdet ? IRQ_HANDLED : IRQ_NONE;
153 }
154
ccf_probe(struct platform_device * pdev)155 static int ccf_probe(struct platform_device *pdev)
156 {
157 struct ccf_private *ccf;
158 struct resource *r;
159 const struct of_device_id *match;
160 int ret, irq;
161
162 match = of_match_device(ccf_matches, &pdev->dev);
163 if (WARN_ON(!match))
164 return -ENODEV;
165
166 ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL);
167 if (!ccf)
168 return -ENOMEM;
169
170 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
171 if (!r) {
172 dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
173 return -ENXIO;
174 }
175
176 ccf->regs = devm_ioremap_resource(&pdev->dev, r);
177 if (IS_ERR(ccf->regs)) {
178 dev_err(&pdev->dev, "%s: can't map mem resource\n", __func__);
179 return PTR_ERR(ccf->regs);
180 }
181
182 ccf->dev = &pdev->dev;
183 ccf->info = match->data;
184 ccf->err_regs = ccf->regs + ccf->info->err_reg_offs;
185
186 dev_set_drvdata(&pdev->dev, ccf);
187
188 irq = platform_get_irq(pdev, 0);
189 if (!irq) {
190 dev_err(&pdev->dev, "%s: no irq\n", __func__);
191 return -ENXIO;
192 }
193
194 ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
195 if (ret) {
196 dev_err(&pdev->dev, "%s: can't request irq\n", __func__);
197 return ret;
198 }
199
200 switch (ccf->info->version) {
201 case CCF1:
202 /* On CCF1 this register enables rather than disables. */
203 iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errdis);
204 break;
205
206 case CCF2:
207 iowrite32be(0, &ccf->err_regs->errdis);
208 iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errinten);
209 break;
210 }
211
212 return 0;
213 }
214
ccf_remove(struct platform_device * pdev)215 static int ccf_remove(struct platform_device *pdev)
216 {
217 struct ccf_private *ccf = dev_get_drvdata(&pdev->dev);
218
219 switch (ccf->info->version) {
220 case CCF1:
221 iowrite32be(0, &ccf->err_regs->errdis);
222 break;
223
224 case CCF2:
225 /*
226 * We clear errdis on ccf1 because that's the only way to
227 * disable interrupts, but on ccf2 there's no need to disable
228 * detection.
229 */
230 iowrite32be(0, &ccf->err_regs->errinten);
231 break;
232 }
233
234 return 0;
235 }
236
237 static struct platform_driver ccf_driver = {
238 .driver = {
239 .name = KBUILD_MODNAME,
240 .owner = THIS_MODULE,
241 .of_match_table = ccf_matches,
242 },
243 .probe = ccf_probe,
244 .remove = ccf_remove,
245 };
246
247 module_platform_driver(ccf_driver);
248
249 MODULE_LICENSE("GPL");
250 MODULE_AUTHOR("Freescale Semiconductor");
251 MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting");
252