aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorChunhe Lan <Chunhe.Lan@freescale.com>2013-11-25 05:28:41 -0500
committerBorislav Petkov <bp@suse.de>2013-11-25 05:29:15 -0500
commitc92132f5980666c7a52ecb53d98226c9986d32cd (patch)
treedd658f56a9f520850f6cb75a8f907359b9f740e5 /drivers/edac
parent6ce4eac1f600b34f2f7f58f9cd8f0503d79e42ae (diff)
edac/85xx: Add PCIe error interrupt edac support
Add pcie error interrupt edac support for mpc85xx, p3041, p4080, and p5020. The mpc85xx uses the legacy interrupt report mechanism - the error interrupts are reported directly to mpic. While the p3041/ p4080/p5020 attaches the most of error interrupts to interrupt zero. And report error interrupts to mpic via interrupt 0. This patch can handle both of them. Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com> Link: http://lkml.kernel.org/r/1384712714-8826-3-git-send-email-morbidrsa@gmail.com Cc: Doug Thompson <dougthompson@xmission.com> Cc: Dave Jiang <dave.jiang@gmail.com> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@men.de> Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/mpc85xx_edac.c98
-rw-r--r--drivers/edac/mpc85xx_edac.h7
2 files changed, 94 insertions, 11 deletions
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index fd46b0bd5f2a..8f9182179a7c 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -1,6 +1,8 @@
1/* 1/*
2 * Freescale MPC85xx Memory Controller kenel module 2 * Freescale MPC85xx Memory Controller kenel module
3 * 3 *
4 * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.
5 *
4 * Author: Dave Jiang <djiang@mvista.com> 6 * Author: Dave Jiang <djiang@mvista.com>
5 * 7 *
6 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under 8 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
@@ -196,6 +198,42 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)
196 edac_pci_handle_npe(pci, pci->ctl_name); 198 edac_pci_handle_npe(pci, pci->ctl_name);
197} 199}
198 200
201static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci)
202{
203 struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
204 u32 err_detect;
205
206 err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);
207
208 pr_err("PCIe error(s) detected\n");
209 pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect);
210 pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n",
211 in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR));
212 pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n",
213 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0));
214 pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n",
215 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R1));
216 pr_err("PCIe ERR_CAP_R2 register: 0x%08x\n",
217 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R2));
218 pr_err("PCIe ERR_CAP_R3 register: 0x%08x\n",
219 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R3));
220
221 /* clear error bits */
222 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);
223}
224
225static int mpc85xx_pcie_find_capability(struct device_node *np)
226{
227 struct pci_controller *hose;
228
229 if (!np)
230 return -EINVAL;
231
232 hose = pci_find_hose_for_OF_device(np);
233
234 return early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
235}
236
199static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id) 237static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
200{ 238{
201 struct edac_pci_ctl_info *pci = dev_id; 239 struct edac_pci_ctl_info *pci = dev_id;
@@ -207,7 +245,10 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
207 if (!err_detect) 245 if (!err_detect)
208 return IRQ_NONE; 246 return IRQ_NONE;
209 247
210 mpc85xx_pci_check(pci); 248 if (pdata->is_pcie)
249 mpc85xx_pcie_check(pci);
250 else
251 mpc85xx_pci_check(pci);
211 252
212 return IRQ_HANDLED; 253 return IRQ_HANDLED;
213} 254}
@@ -239,14 +280,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
239 pdata = pci->pvt_info; 280 pdata = pci->pvt_info;
240 pdata->name = "mpc85xx_pci_err"; 281 pdata->name = "mpc85xx_pci_err";
241 pdata->irq = NO_IRQ; 282 pdata->irq = NO_IRQ;
283
284 if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
285 pdata->is_pcie = true;
286
242 dev_set_drvdata(&op->dev, pci); 287 dev_set_drvdata(&op->dev, pci);
243 pci->dev = &op->dev; 288 pci->dev = &op->dev;
244 pci->mod_name = EDAC_MOD_STR; 289 pci->mod_name = EDAC_MOD_STR;
245 pci->ctl_name = pdata->name; 290 pci->ctl_name = pdata->name;
246 pci->dev_name = dev_name(&op->dev); 291 pci->dev_name = dev_name(&op->dev);
247 292
248 if (edac_op_state == EDAC_OPSTATE_POLL) 293 if (edac_op_state == EDAC_OPSTATE_POLL) {
249 pci->edac_check = mpc85xx_pci_check; 294 if (pdata->is_pcie)
295 pci->edac_check = mpc85xx_pcie_check;
296 else
297 pci->edac_check = mpc85xx_pci_check;
298 }
250 299
251 pdata->edac_idx = edac_pci_idx++; 300 pdata->edac_idx = edac_pci_idx++;
252 301
@@ -275,16 +324,26 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
275 goto err; 324 goto err;
276 } 325 }
277 326
278 orig_pci_err_cap_dr = 327 if (pdata->is_pcie) {
279 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR); 328 orig_pci_err_cap_dr =
329 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR);
330 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, ~0);
331 orig_pci_err_en =
332 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
333 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, 0);
334 } else {
335 orig_pci_err_cap_dr =
336 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);
280 337
281 /* PCI master abort is expected during config cycles */ 338 /* PCI master abort is expected during config cycles */
282 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40); 339 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);
283 340
284 orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN); 341 orig_pci_err_en =
342 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);
285 343
286 /* disable master abort reporting */ 344 /* disable master abort reporting */
287 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40); 345 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);
346 }
288 347
289 /* clear error bits */ 348 /* clear error bits */
290 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0); 349 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
@@ -297,7 +356,8 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
297 if (edac_op_state == EDAC_OPSTATE_INT) { 356 if (edac_op_state == EDAC_OPSTATE_INT) {
298 pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); 357 pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
299 res = devm_request_irq(&op->dev, pdata->irq, 358 res = devm_request_irq(&op->dev, pdata->irq,
300 mpc85xx_pci_isr, IRQF_DISABLED, 359 mpc85xx_pci_isr,
360 IRQF_DISABLED | IRQF_SHARED,
301 "[EDAC] PCI err", pci); 361 "[EDAC] PCI err", pci);
302 if (res < 0) { 362 if (res < 0) {
303 printk(KERN_ERR 363 printk(KERN_ERR
@@ -312,6 +372,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
312 pdata->irq); 372 pdata->irq);
313 } 373 }
314 374
375 if (pdata->is_pcie) {
376 /*
377 * Enable all PCIe error interrupt & error detect except invalid
378 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA access interrupt generation
379 * enable bit and invalid PEX_CONFIG_ADDR/PEX_CONFIG_DATA access
380 * detection enable bit. Because PCIe bus code to initialize and
381 * configure these PCIe devices on booting will use some invalid
382 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA, edac driver prints the much
383 * notice information. So disable this detect to fix ugly print.
384 */
385 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0
386 & ~PEX_ERR_ICCAIE_EN_BIT);
387 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, 0
388 | PEX_ERR_ICCAD_DISR_BIT);
389 }
390
315 devres_remove_group(&op->dev, mpc85xx_pci_err_probe); 391 devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
316 edac_dbg(3, "success\n"); 392 edac_dbg(3, "success\n");
317 printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n"); 393 printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 932016f2cf06..8c6256436227 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -134,13 +134,19 @@
134#define MPC85XX_PCI_ERR_DR 0x0000 134#define MPC85XX_PCI_ERR_DR 0x0000
135#define MPC85XX_PCI_ERR_CAP_DR 0x0004 135#define MPC85XX_PCI_ERR_CAP_DR 0x0004
136#define MPC85XX_PCI_ERR_EN 0x0008 136#define MPC85XX_PCI_ERR_EN 0x0008
137#define PEX_ERR_ICCAIE_EN_BIT 0x00020000
137#define MPC85XX_PCI_ERR_ATTRIB 0x000c 138#define MPC85XX_PCI_ERR_ATTRIB 0x000c
138#define MPC85XX_PCI_ERR_ADDR 0x0010 139#define MPC85XX_PCI_ERR_ADDR 0x0010
140#define PEX_ERR_ICCAD_DISR_BIT 0x00020000
139#define MPC85XX_PCI_ERR_EXT_ADDR 0x0014 141#define MPC85XX_PCI_ERR_EXT_ADDR 0x0014
140#define MPC85XX_PCI_ERR_DL 0x0018 142#define MPC85XX_PCI_ERR_DL 0x0018
141#define MPC85XX_PCI_ERR_DH 0x001c 143#define MPC85XX_PCI_ERR_DH 0x001c
142#define MPC85XX_PCI_GAS_TIMR 0x0020 144#define MPC85XX_PCI_GAS_TIMR 0x0020
143#define MPC85XX_PCI_PCIX_TIMR 0x0024 145#define MPC85XX_PCI_PCIX_TIMR 0x0024
146#define MPC85XX_PCIE_ERR_CAP_R0 0x0028
147#define MPC85XX_PCIE_ERR_CAP_R1 0x002c
148#define MPC85XX_PCIE_ERR_CAP_R2 0x0030
149#define MPC85XX_PCIE_ERR_CAP_R3 0x0034
144 150
145struct mpc85xx_mc_pdata { 151struct mpc85xx_mc_pdata {
146 char *name; 152 char *name;
@@ -158,6 +164,7 @@ struct mpc85xx_l2_pdata {
158 164
159struct mpc85xx_pci_pdata { 165struct mpc85xx_pci_pdata {
160 char *name; 166 char *name;
167 bool is_pcie;
161 int edac_idx; 168 int edac_idx;
162 void __iomem *pci_vbase; 169 void __iomem *pci_vbase;
163 int irq; 170 int irq;