diff options
author | Chunhe Lan <Chunhe.Lan@freescale.com> | 2013-11-25 05:28:41 -0500 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2013-11-25 05:29:15 -0500 |
commit | c92132f5980666c7a52ecb53d98226c9986d32cd (patch) | |
tree | dd658f56a9f520850f6cb75a8f907359b9f740e5 /drivers/edac/mpc85xx_edac.c | |
parent | 6ce4eac1f600b34f2f7f58f9cd8f0503d79e42ae (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/mpc85xx_edac.c')
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 98 |
1 files changed, 87 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 | ||
201 | static 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 | |||
225 | static 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 | |||
199 | static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id) | 237 | static 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"); |