Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Chunhe Lan and committed by
Borislav Petkov
c92132f5 6ce4eac1

+94 -11
+87 -11
drivers/edac/mpc85xx_edac.c
··· 1 1 /* 2 2 * Freescale MPC85xx Memory Controller kenel module 3 3 * 4 + * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. 5 + * 4 6 * Author: Dave Jiang <djiang@mvista.com> 5 7 * 6 8 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under ··· 198 196 edac_pci_handle_npe(pci, pci->ctl_name); 199 197 } 200 198 199 + static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci) 200 + { 201 + struct mpc85xx_pci_pdata *pdata = pci->pvt_info; 202 + u32 err_detect; 203 + 204 + err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR); 205 + 206 + pr_err("PCIe error(s) detected\n"); 207 + pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect); 208 + pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", 209 + in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR)); 210 + pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n", 211 + in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0)); 212 + pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n", 213 + in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R1)); 214 + pr_err("PCIe ERR_CAP_R2 register: 0x%08x\n", 215 + in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R2)); 216 + pr_err("PCIe ERR_CAP_R3 register: 0x%08x\n", 217 + in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R3)); 218 + 219 + /* clear error bits */ 220 + out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect); 221 + } 222 + 223 + static int mpc85xx_pcie_find_capability(struct device_node *np) 224 + { 225 + struct pci_controller *hose; 226 + 227 + if (!np) 228 + return -EINVAL; 229 + 230 + hose = pci_find_hose_for_OF_device(np); 231 + 232 + return early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP); 233 + } 234 + 201 235 static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id) 202 236 { 203 237 struct edac_pci_ctl_info *pci = dev_id; ··· 245 207 if (!err_detect) 246 208 return IRQ_NONE; 247 209 248 - mpc85xx_pci_check(pci); 210 + if (pdata->is_pcie) 211 + mpc85xx_pcie_check(pci); 212 + else 213 + mpc85xx_pci_check(pci); 249 214 250 215 return IRQ_HANDLED; 251 216 } ··· 280 239 pdata = pci->pvt_info; 281 240 pdata->name = "mpc85xx_pci_err"; 282 241 pdata->irq = NO_IRQ; 242 + 243 + if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0) 244 + pdata->is_pcie = true; 245 + 283 246 dev_set_drvdata(&op->dev, pci); 284 247 pci->dev = &op->dev; 285 248 pci->mod_name = EDAC_MOD_STR; 286 249 pci->ctl_name = pdata->name; 287 250 pci->dev_name = dev_name(&op->dev); 288 251 289 - if (edac_op_state == EDAC_OPSTATE_POLL) 290 - pci->edac_check = mpc85xx_pci_check; 252 + if (edac_op_state == EDAC_OPSTATE_POLL) { 253 + if (pdata->is_pcie) 254 + pci->edac_check = mpc85xx_pcie_check; 255 + else 256 + pci->edac_check = mpc85xx_pci_check; 257 + } 291 258 292 259 pdata->edac_idx = edac_pci_idx++; 293 260 ··· 324 275 goto err; 325 276 } 326 277 327 - orig_pci_err_cap_dr = 328 - in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR); 278 + if (pdata->is_pcie) { 279 + orig_pci_err_cap_dr = 280 + in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR); 281 + out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, ~0); 282 + orig_pci_err_en = 283 + in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN); 284 + out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, 0); 285 + } else { 286 + orig_pci_err_cap_dr = 287 + in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR); 329 288 330 - /* PCI master abort is expected during config cycles */ 331 - out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40); 289 + /* PCI master abort is expected during config cycles */ 290 + out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40); 332 291 333 - orig_pci_err_en = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN); 292 + orig_pci_err_en = 293 + in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN); 334 294 335 - /* disable master abort reporting */ 336 - out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40); 295 + /* disable master abort reporting */ 296 + out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40); 297 + } 337 298 338 299 /* clear error bits */ 339 300 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0); ··· 356 297 if (edac_op_state == EDAC_OPSTATE_INT) { 357 298 pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); 358 299 res = devm_request_irq(&op->dev, pdata->irq, 359 - mpc85xx_pci_isr, IRQF_DISABLED, 300 + mpc85xx_pci_isr, 301 + IRQF_DISABLED | IRQF_SHARED, 360 302 "[EDAC] PCI err", pci); 361 303 if (res < 0) { 362 304 printk(KERN_ERR ··· 370 310 371 311 printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n", 372 312 pdata->irq); 313 + } 314 + 315 + if (pdata->is_pcie) { 316 + /* 317 + * Enable all PCIe error interrupt & error detect except invalid 318 + * PEX_CONFIG_ADDR/PEX_CONFIG_DATA access interrupt generation 319 + * enable bit and invalid PEX_CONFIG_ADDR/PEX_CONFIG_DATA access 320 + * detection enable bit. Because PCIe bus code to initialize and 321 + * configure these PCIe devices on booting will use some invalid 322 + * PEX_CONFIG_ADDR/PEX_CONFIG_DATA, edac driver prints the much 323 + * notice information. So disable this detect to fix ugly print. 324 + */ 325 + out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0 326 + & ~PEX_ERR_ICCAIE_EN_BIT); 327 + out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, 0 328 + | PEX_ERR_ICCAD_DISR_BIT); 373 329 } 374 330 375 331 devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
+7
drivers/edac/mpc85xx_edac.h
··· 134 134 #define MPC85XX_PCI_ERR_DR 0x0000 135 135 #define MPC85XX_PCI_ERR_CAP_DR 0x0004 136 136 #define MPC85XX_PCI_ERR_EN 0x0008 137 + #define PEX_ERR_ICCAIE_EN_BIT 0x00020000 137 138 #define MPC85XX_PCI_ERR_ATTRIB 0x000c 138 139 #define MPC85XX_PCI_ERR_ADDR 0x0010 140 + #define PEX_ERR_ICCAD_DISR_BIT 0x00020000 139 141 #define MPC85XX_PCI_ERR_EXT_ADDR 0x0014 140 142 #define MPC85XX_PCI_ERR_DL 0x0018 141 143 #define MPC85XX_PCI_ERR_DH 0x001c 142 144 #define MPC85XX_PCI_GAS_TIMR 0x0020 143 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 145 151 struct mpc85xx_mc_pdata { 146 152 char *name; ··· 164 158 165 159 struct mpc85xx_pci_pdata { 166 160 char *name; 161 + bool is_pcie; 167 162 int edac_idx; 168 163 void __iomem *pci_vbase; 169 164 int irq;