aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/memory
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-07-02 19:52:11 -0400
committerScott Wood <scottwood@freescale.com>2014-07-29 20:26:30 -0400
commit54afbec0d57f322127e3886b04fe4fd860519bfb (patch)
tree0878b64dfd44ec4b933660b3b2051db6b09147c1 /drivers/memory
parent48cd9b5d590aee1664170968a9eae068e36761eb (diff)
memory: Freescale CoreNet Coherency Fabric error reporting driver
The CoreNet Coherency Fabric is part of the memory subsystem on some Freescale QorIQ chips. It can report coherency violations (e.g. due to misusing memory that is mapped noncoherent) as well as transactions that do not hit any local access window, or which hit a local access window with an invalid target ID. Signed-off-by: Scott Wood <scottwood@freescale.com> Reviewed-by: Bharat Bhushan <bharat.bhushan@freescale.com>
Diffstat (limited to 'drivers/memory')
-rw-r--r--drivers/memory/Kconfig10
-rw-r--r--drivers/memory/Makefile1
-rw-r--r--drivers/memory/fsl-corenet-cf.c251
3 files changed, 262 insertions, 0 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c59e9c96e86d..fab81a143bd7 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -61,6 +61,16 @@ config TEGRA30_MC
61 analysis, especially for IOMMU/SMMU(System Memory Management 61 analysis, especially for IOMMU/SMMU(System Memory Management
62 Unit) module. 62 Unit) module.
63 63
64config FSL_CORENET_CF
65 tristate "Freescale CoreNet Error Reporting"
66 depends on FSL_SOC_BOOKE
67 help
68 Say Y for reporting of errors from the Freescale CoreNet
69 Coherency Fabric. Errors reported include accesses to
70 physical addresses that mapped by no local access window
71 (LAW) or an invalid LAW, as well as bad cache state that
72 represents a coherency violation.
73
64config FSL_IFC 74config FSL_IFC
65 bool 75 bool
66 depends on FSL_SOC 76 depends on FSL_SOC
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 71160a2b7313..4055c47f45ab 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF) += of_memory.o
7endif 7endif
8obj-$(CONFIG_TI_AEMIF) += ti-aemif.o 8obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
9obj-$(CONFIG_TI_EMIF) += emif.o 9obj-$(CONFIG_TI_EMIF) += emif.o
10obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o
10obj-$(CONFIG_FSL_IFC) += fsl_ifc.o 11obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
11obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o 12obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
12obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o 13obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c
new file mode 100644
index 000000000000..c9443fc136db
--- /dev/null
+++ b/drivers/memory/fsl-corenet-cf.c
@@ -0,0 +1,251 @@
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
22enum ccf_version {
23 CCF1,
24 CCF2,
25};
26
27struct ccf_info {
28 enum ccf_version version;
29 int err_reg_offs;
30};
31
32static const struct ccf_info ccf1_info = {
33 .version = CCF1,
34 .err_reg_offs = 0xa00,
35};
36
37static const struct ccf_info ccf2_info = {
38 .version = CCF2,
39 .err_reg_offs = 0xe40,
40};
41
42static 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
54struct 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
82struct 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
89static 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
150out:
151 iowrite32be(errdet, &ccf->err_regs->errdet);
152 return errdet ? IRQ_HANDLED : IRQ_NONE;
153}
154
155static 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
215static 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
237static 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
247module_platform_driver(ccf_driver);
248
249MODULE_LICENSE("GPL");
250MODULE_AUTHOR("Freescale Semiconductor");
251MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting");