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

drivers-edac: add marvell mv64x60 driver

Marvell mv64x60 SoC support for EDAC. Used on PPC and MIPS platforms.
Development and testing done on PPC Motorola prpmc2800 ATCA board.

[akpm@linux-foundation.org: make mv64x60_ctl_name static]
Signed-off-by: Dave Jiang <djiang@mvista.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk
Signed-off-by: Douglas Thompson <dougthompson@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dave Jiang and committed by
Linus Torvalds
4f4aeeab a9a753d5

+977
+7
drivers/edac/Kconfig
··· 130 130 Support for error detection and correction on the Freescale 131 131 MPC8560, MPC8540, MPC8548 132 132 133 + config EDAC_MV64X60 134 + tristate "Marvell MV64x60" 135 + depends on EDAC_MM_EDAC && MV64X60 136 + help 137 + Support for error detection and correction on the Marvell 138 + MV64360 and MV64460 chipsets. 139 + 133 140 config EDAC_PASEMI 134 141 tristate "PA Semi PWRficient" 135 142 depends on EDAC_MM_EDAC && PCI
+1
drivers/edac/Makefile
··· 29 29 obj-$(CONFIG_EDAC_R82600) += r82600_edac.o 30 30 obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o 31 31 obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o 32 + obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o 32 33 obj-$(CONFIG_EDAC_CELL) += cell_edac.o 33 34
+855
drivers/edac/mv64x60_edac.c
··· 1 + /* 2 + * Marvell MV64x60 Memory Controller kernel module for PPC platforms 3 + * 4 + * Author: Dave Jiang <djiang@mvista.com> 5 + * 6 + * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under 7 + * the terms of the GNU General Public License version 2. This program 8 + * is licensed "as is" without any warranty of any kind, whether express 9 + * or implied. 10 + * 11 + */ 12 + 13 + #include <linux/module.h> 14 + #include <linux/init.h> 15 + #include <linux/slab.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/io.h> 18 + #include <linux/edac.h> 19 + 20 + #include "edac_core.h" 21 + #include "edac_module.h" 22 + #include "mv64x60_edac.h" 23 + 24 + static const char *mv64x60_ctl_name = "MV64x60"; 25 + static int edac_dev_idx; 26 + static int edac_pci_idx; 27 + static int edac_mc_idx; 28 + 29 + /*********************** PCI err device **********************************/ 30 + #ifdef CONFIG_PCI 31 + static void mv64x60_pci_check(struct edac_pci_ctl_info *pci) 32 + { 33 + struct mv64x60_pci_pdata *pdata = pci->pvt_info; 34 + u32 cause; 35 + 36 + cause = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE); 37 + if (!cause) 38 + return; 39 + 40 + printk(KERN_ERR "Error in PCI %d Interface\n", pdata->pci_hose); 41 + printk(KERN_ERR "Cause register: 0x%08x\n", cause); 42 + printk(KERN_ERR "Address Low: 0x%08x\n", 43 + in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_LO)); 44 + printk(KERN_ERR "Address High: 0x%08x\n", 45 + in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_HI)); 46 + printk(KERN_ERR "Attribute: 0x%08x\n", 47 + in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ATTR)); 48 + printk(KERN_ERR "Command: 0x%08x\n", 49 + in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CMD)); 50 + out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, ~cause); 51 + 52 + if (cause & MV64X60_PCI_PE_MASK) 53 + edac_pci_handle_pe(pci, pci->ctl_name); 54 + 55 + if (!(cause & MV64X60_PCI_PE_MASK)) 56 + edac_pci_handle_npe(pci, pci->ctl_name); 57 + } 58 + 59 + static irqreturn_t mv64x60_pci_isr(int irq, void *dev_id) 60 + { 61 + struct edac_pci_ctl_info *pci = dev_id; 62 + struct mv64x60_pci_pdata *pdata = pci->pvt_info; 63 + u32 val; 64 + 65 + val = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE); 66 + if (!val) 67 + return IRQ_NONE; 68 + 69 + mv64x60_pci_check(pci); 70 + 71 + return IRQ_HANDLED; 72 + } 73 + 74 + static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev) 75 + { 76 + struct edac_pci_ctl_info *pci; 77 + struct mv64x60_pci_pdata *pdata; 78 + struct resource *r; 79 + int res = 0; 80 + 81 + if (!devres_open_group(&pdev->dev, mv64x60_pci_err_probe, GFP_KERNEL)) 82 + return -ENOMEM; 83 + 84 + pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mv64x60_pci_err"); 85 + if (!pci) 86 + return -ENOMEM; 87 + 88 + pdata = pci->pvt_info; 89 + 90 + pdata->pci_hose = pdev->id; 91 + pdata->name = "mpc85xx_pci_err"; 92 + pdata->irq = NO_IRQ; 93 + platform_set_drvdata(pdev, pci); 94 + pci->dev = &pdev->dev; 95 + pci->dev_name = pdev->dev.bus_id; 96 + pci->mod_name = EDAC_MOD_STR; 97 + pci->ctl_name = pdata->name; 98 + 99 + if (edac_op_state == EDAC_OPSTATE_POLL) 100 + pci->edac_check = mv64x60_pci_check; 101 + 102 + pdata->edac_idx = edac_pci_idx++; 103 + 104 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 105 + if (!r) { 106 + printk(KERN_ERR "%s: Unable to get resource for " 107 + "PCI err regs\n", __func__); 108 + res = -ENOENT; 109 + goto err; 110 + } 111 + 112 + if (!devm_request_mem_region(&pdev->dev, 113 + r->start, 114 + r->end - r->start + 1, 115 + pdata->name)) { 116 + printk(KERN_ERR "%s: Error while requesting mem region\n", 117 + __func__); 118 + res = -EBUSY; 119 + goto err; 120 + } 121 + 122 + pdata->pci_vbase = devm_ioremap(&pdev->dev, 123 + r->start, 124 + r->end - r->start + 1); 125 + if (!pdata->pci_vbase) { 126 + printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__); 127 + res = -ENOMEM; 128 + goto err; 129 + } 130 + 131 + out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, 0); 132 + out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK, 0); 133 + out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK, 134 + MV64X60_PCIx_ERR_MASK_VAL); 135 + 136 + if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { 137 + debugf3("%s(): failed edac_pci_add_device()\n", __func__); 138 + goto err; 139 + } 140 + 141 + if (edac_op_state == EDAC_OPSTATE_INT) { 142 + pdata->irq = platform_get_irq(pdev, 0); 143 + res = devm_request_irq(&pdev->dev, 144 + pdata->irq, 145 + mv64x60_pci_isr, 146 + IRQF_DISABLED, 147 + "[EDAC] PCI err", 148 + pci); 149 + if (res < 0) { 150 + printk(KERN_ERR "%s: Unable to request irq %d for " 151 + "MV64x60 PCI ERR\n", __func__, pdata->irq); 152 + res = -ENODEV; 153 + goto err2; 154 + } 155 + printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n", 156 + pdata->irq); 157 + } 158 + 159 + devres_remove_group(&pdev->dev, mv64x60_pci_err_probe); 160 + 161 + /* get this far and it's successful */ 162 + debugf3("%s(): success\n", __func__); 163 + 164 + return 0; 165 + 166 + err2: 167 + edac_pci_del_device(&pdev->dev); 168 + err: 169 + edac_pci_free_ctl_info(pci); 170 + devres_release_group(&pdev->dev, mv64x60_pci_err_probe); 171 + return res; 172 + } 173 + 174 + static int mv64x60_pci_err_remove(struct platform_device *pdev) 175 + { 176 + struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev); 177 + 178 + debugf0("%s()\n", __func__); 179 + 180 + edac_pci_del_device(&pdev->dev); 181 + 182 + edac_pci_free_ctl_info(pci); 183 + 184 + return 0; 185 + } 186 + 187 + static struct platform_driver mv64x60_pci_err_driver = { 188 + .probe = mv64x60_pci_err_probe, 189 + .remove = __devexit_p(mv64x60_pci_err_remove), 190 + .driver = { 191 + .name = "mv64x60_pci_err", 192 + } 193 + }; 194 + 195 + #endif /* CONFIG_PCI */ 196 + 197 + /*********************** SRAM err device **********************************/ 198 + static void mv64x60_sram_check(struct edac_device_ctl_info *edac_dev) 199 + { 200 + struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info; 201 + u32 cause; 202 + 203 + cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE); 204 + if (!cause) 205 + return; 206 + 207 + printk(KERN_ERR "Error in internal SRAM\n"); 208 + printk(KERN_ERR "Cause register: 0x%08x\n", cause); 209 + printk(KERN_ERR "Address Low: 0x%08x\n", 210 + in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_LO)); 211 + printk(KERN_ERR "Address High: 0x%08x\n", 212 + in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_HI)); 213 + printk(KERN_ERR "Data Low: 0x%08x\n", 214 + in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_LO)); 215 + printk(KERN_ERR "Data High: 0x%08x\n", 216 + in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_HI)); 217 + printk(KERN_ERR "Parity: 0x%08x\n", 218 + in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_PARITY)); 219 + out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0); 220 + 221 + edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); 222 + } 223 + 224 + static irqreturn_t mv64x60_sram_isr(int irq, void *dev_id) 225 + { 226 + struct edac_device_ctl_info *edac_dev = dev_id; 227 + struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info; 228 + u32 cause; 229 + 230 + cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE); 231 + if (!cause) 232 + return IRQ_NONE; 233 + 234 + mv64x60_sram_check(edac_dev); 235 + 236 + return IRQ_HANDLED; 237 + } 238 + 239 + static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev) 240 + { 241 + struct edac_device_ctl_info *edac_dev; 242 + struct mv64x60_sram_pdata *pdata; 243 + struct resource *r; 244 + int res = 0; 245 + 246 + if (!devres_open_group(&pdev->dev, mv64x60_sram_err_probe, GFP_KERNEL)) 247 + return -ENOMEM; 248 + 249 + edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata), 250 + "sram", 1, NULL, 0, 0, NULL, 0, 251 + edac_dev_idx); 252 + if (!edac_dev) { 253 + devres_release_group(&pdev->dev, mv64x60_sram_err_probe); 254 + return -ENOMEM; 255 + } 256 + 257 + pdata = edac_dev->pvt_info; 258 + pdata->name = "mv64x60_sram_err"; 259 + pdata->irq = NO_IRQ; 260 + edac_dev->dev = &pdev->dev; 261 + platform_set_drvdata(pdev, edac_dev); 262 + edac_dev->dev_name = pdev->dev.bus_id; 263 + 264 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 265 + if (!r) { 266 + printk(KERN_ERR "%s: Unable to get resource for " 267 + "SRAM err regs\n", __func__); 268 + res = -ENOENT; 269 + goto err; 270 + } 271 + 272 + if (!devm_request_mem_region(&pdev->dev, 273 + r->start, 274 + r->end - r->start + 1, 275 + pdata->name)) { 276 + printk(KERN_ERR "%s: Error while request mem region\n", 277 + __func__); 278 + res = -EBUSY; 279 + goto err; 280 + } 281 + 282 + pdata->sram_vbase = devm_ioremap(&pdev->dev, 283 + r->start, 284 + r->end - r->start + 1); 285 + if (!pdata->sram_vbase) { 286 + printk(KERN_ERR "%s: Unable to setup SRAM err regs\n", 287 + __func__); 288 + res = -ENOMEM; 289 + goto err; 290 + } 291 + 292 + /* setup SRAM err registers */ 293 + out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0); 294 + 295 + edac_dev->mod_name = EDAC_MOD_STR; 296 + edac_dev->ctl_name = pdata->name; 297 + 298 + if (edac_op_state == EDAC_OPSTATE_POLL) 299 + edac_dev->edac_check = mv64x60_sram_check; 300 + 301 + pdata->edac_idx = edac_dev_idx++; 302 + 303 + if (edac_device_add_device(edac_dev) > 0) { 304 + debugf3("%s(): failed edac_device_add_device()\n", __func__); 305 + goto err; 306 + } 307 + 308 + if (edac_op_state == EDAC_OPSTATE_INT) { 309 + pdata->irq = platform_get_irq(pdev, 0); 310 + res = devm_request_irq(&pdev->dev, 311 + pdata->irq, 312 + mv64x60_sram_isr, 313 + IRQF_DISABLED, 314 + "[EDAC] SRAM err", 315 + edac_dev); 316 + if (res < 0) { 317 + printk(KERN_ERR 318 + "%s: Unable to request irq %d for " 319 + "MV64x60 SRAM ERR\n", __func__, pdata->irq); 320 + res = -ENODEV; 321 + goto err2; 322 + } 323 + 324 + printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for SRAM Err\n", 325 + pdata->irq); 326 + } 327 + 328 + devres_remove_group(&pdev->dev, mv64x60_sram_err_probe); 329 + 330 + /* get this far and it's successful */ 331 + debugf3("%s(): success\n", __func__); 332 + 333 + return 0; 334 + 335 + err2: 336 + edac_device_del_device(&pdev->dev); 337 + err: 338 + devres_release_group(&pdev->dev, mv64x60_sram_err_probe); 339 + edac_device_free_ctl_info(edac_dev); 340 + return res; 341 + } 342 + 343 + static int mv64x60_sram_err_remove(struct platform_device *pdev) 344 + { 345 + struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev); 346 + 347 + debugf0("%s()\n", __func__); 348 + 349 + edac_device_del_device(&pdev->dev); 350 + edac_device_free_ctl_info(edac_dev); 351 + 352 + return 0; 353 + } 354 + 355 + static struct platform_driver mv64x60_sram_err_driver = { 356 + .probe = mv64x60_sram_err_probe, 357 + .remove = mv64x60_sram_err_remove, 358 + .driver = { 359 + .name = "mv64x60_sram_err", 360 + } 361 + }; 362 + 363 + /*********************** CPU err device **********************************/ 364 + static void mv64x60_cpu_check(struct edac_device_ctl_info *edac_dev) 365 + { 366 + struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info; 367 + u32 cause; 368 + 369 + cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) & 370 + MV64x60_CPU_CAUSE_MASK; 371 + if (!cause) 372 + return; 373 + 374 + printk(KERN_ERR "Error on CPU interface\n"); 375 + printk(KERN_ERR "Cause register: 0x%08x\n", cause); 376 + printk(KERN_ERR "Address Low: 0x%08x\n", 377 + in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_LO)); 378 + printk(KERN_ERR "Address High: 0x%08x\n", 379 + in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_HI)); 380 + printk(KERN_ERR "Data Low: 0x%08x\n", 381 + in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_LO)); 382 + printk(KERN_ERR "Data High: 0x%08x\n", 383 + in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_HI)); 384 + printk(KERN_ERR "Parity: 0x%08x\n", 385 + in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_PARITY)); 386 + out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0); 387 + 388 + edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); 389 + } 390 + 391 + static irqreturn_t mv64x60_cpu_isr(int irq, void *dev_id) 392 + { 393 + struct edac_device_ctl_info *edac_dev = dev_id; 394 + struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info; 395 + u32 cause; 396 + 397 + cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) & 398 + MV64x60_CPU_CAUSE_MASK; 399 + if (!cause) 400 + return IRQ_NONE; 401 + 402 + mv64x60_cpu_check(edac_dev); 403 + 404 + return IRQ_HANDLED; 405 + } 406 + 407 + static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev) 408 + { 409 + struct edac_device_ctl_info *edac_dev; 410 + struct resource *r; 411 + struct mv64x60_cpu_pdata *pdata; 412 + int res = 0; 413 + 414 + if (!devres_open_group(&pdev->dev, mv64x60_cpu_err_probe, GFP_KERNEL)) 415 + return -ENOMEM; 416 + 417 + edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata), 418 + "cpu", 1, NULL, 0, 0, NULL, 0, 419 + edac_dev_idx); 420 + if (!edac_dev) { 421 + devres_release_group(&pdev->dev, mv64x60_cpu_err_probe); 422 + return -ENOMEM; 423 + } 424 + 425 + pdata = edac_dev->pvt_info; 426 + pdata->name = "mv64x60_cpu_err"; 427 + pdata->irq = NO_IRQ; 428 + edac_dev->dev = &pdev->dev; 429 + platform_set_drvdata(pdev, edac_dev); 430 + edac_dev->dev_name = pdev->dev.bus_id; 431 + 432 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 433 + if (!r) { 434 + printk(KERN_ERR "%s: Unable to get resource for " 435 + "CPU err regs\n", __func__); 436 + res = -ENOENT; 437 + goto err; 438 + } 439 + 440 + if (!devm_request_mem_region(&pdev->dev, 441 + r->start, 442 + r->end - r->start + 1, 443 + pdata->name)) { 444 + printk(KERN_ERR "%s: Error while requesting mem region\n", 445 + __func__); 446 + res = -EBUSY; 447 + goto err; 448 + } 449 + 450 + pdata->cpu_vbase[0] = devm_ioremap(&pdev->dev, 451 + r->start, 452 + r->end - r->start + 1); 453 + if (!pdata->cpu_vbase[0]) { 454 + printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__); 455 + res = -ENOMEM; 456 + goto err; 457 + } 458 + 459 + r = platform_get_resource(pdev, IORESOURCE_MEM, 1); 460 + if (!r) { 461 + printk(KERN_ERR "%s: Unable to get resource for " 462 + "CPU err regs\n", __func__); 463 + res = -ENOENT; 464 + goto err; 465 + } 466 + 467 + if (!devm_request_mem_region(&pdev->dev, 468 + r->start, 469 + r->end - r->start + 1, 470 + pdata->name)) { 471 + printk(KERN_ERR "%s: Error while requesting mem region\n", 472 + __func__); 473 + res = -EBUSY; 474 + goto err; 475 + } 476 + 477 + pdata->cpu_vbase[1] = devm_ioremap(&pdev->dev, 478 + r->start, 479 + r->end - r->start + 1); 480 + if (!pdata->cpu_vbase[1]) { 481 + printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__); 482 + res = -ENOMEM; 483 + goto err; 484 + } 485 + 486 + /* setup CPU err registers */ 487 + out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0); 488 + out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0); 489 + out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0x000000ff); 490 + 491 + edac_dev->mod_name = EDAC_MOD_STR; 492 + edac_dev->ctl_name = pdata->name; 493 + if (edac_op_state == EDAC_OPSTATE_POLL) 494 + edac_dev->edac_check = mv64x60_cpu_check; 495 + 496 + pdata->edac_idx = edac_dev_idx++; 497 + 498 + if (edac_device_add_device(edac_dev) > 0) { 499 + debugf3("%s(): failed edac_device_add_device()\n", __func__); 500 + goto err; 501 + } 502 + 503 + if (edac_op_state == EDAC_OPSTATE_INT) { 504 + pdata->irq = platform_get_irq(pdev, 0); 505 + res = devm_request_irq(&pdev->dev, 506 + pdata->irq, 507 + mv64x60_cpu_isr, 508 + IRQF_DISABLED, 509 + "[EDAC] CPU err", 510 + edac_dev); 511 + if (res < 0) { 512 + printk(KERN_ERR 513 + "%s: Unable to request irq %d for MV64x60 " 514 + "CPU ERR\n", __func__, pdata->irq); 515 + res = -ENODEV; 516 + goto err2; 517 + } 518 + 519 + printk(KERN_INFO EDAC_MOD_STR 520 + " acquired irq %d for CPU Err\n", pdata->irq); 521 + } 522 + 523 + devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe); 524 + 525 + /* get this far and it's successful */ 526 + debugf3("%s(): success\n", __func__); 527 + 528 + return 0; 529 + 530 + err2: 531 + edac_device_del_device(&pdev->dev); 532 + err: 533 + devres_release_group(&pdev->dev, mv64x60_cpu_err_probe); 534 + edac_device_free_ctl_info(edac_dev); 535 + return res; 536 + } 537 + 538 + static int mv64x60_cpu_err_remove(struct platform_device *pdev) 539 + { 540 + struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev); 541 + 542 + debugf0("%s()\n", __func__); 543 + 544 + edac_device_del_device(&pdev->dev); 545 + edac_device_free_ctl_info(edac_dev); 546 + return 0; 547 + } 548 + 549 + static struct platform_driver mv64x60_cpu_err_driver = { 550 + .probe = mv64x60_cpu_err_probe, 551 + .remove = mv64x60_cpu_err_remove, 552 + .driver = { 553 + .name = "mv64x60_cpu_err", 554 + } 555 + }; 556 + 557 + /*********************** DRAM err device **********************************/ 558 + 559 + static void mv64x60_mc_check(struct mem_ctl_info *mci) 560 + { 561 + struct mv64x60_mc_pdata *pdata = mci->pvt_info; 562 + u32 reg; 563 + u32 err_addr; 564 + u32 sdram_ecc; 565 + u32 comp_ecc; 566 + u32 syndrome; 567 + 568 + reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR); 569 + if (!reg) 570 + return; 571 + 572 + err_addr = reg & ~0x3; 573 + sdram_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_RCVD); 574 + comp_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CALC); 575 + syndrome = sdram_ecc ^ comp_ecc; 576 + 577 + /* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */ 578 + if (!(reg & 0x1)) 579 + edac_mc_handle_ce(mci, err_addr >> PAGE_SHIFT, 580 + err_addr & PAGE_MASK, syndrome, 0, 0, 581 + mci->ctl_name); 582 + else /* 2 bit error, UE */ 583 + edac_mc_handle_ue(mci, err_addr >> PAGE_SHIFT, 584 + err_addr & PAGE_MASK, 0, mci->ctl_name); 585 + 586 + /* clear the error */ 587 + out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0); 588 + } 589 + 590 + static irqreturn_t mv64x60_mc_isr(int irq, void *dev_id) 591 + { 592 + struct mem_ctl_info *mci = dev_id; 593 + struct mv64x60_mc_pdata *pdata = mci->pvt_info; 594 + u32 reg; 595 + 596 + reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR); 597 + if (!reg) 598 + return IRQ_NONE; 599 + 600 + /* writing 0's to the ECC err addr in check function clears irq */ 601 + mv64x60_mc_check(mci); 602 + 603 + return IRQ_HANDLED; 604 + } 605 + 606 + static void get_total_mem(struct mv64x60_mc_pdata *pdata) 607 + { 608 + struct device_node *np = NULL; 609 + const unsigned int *reg; 610 + 611 + np = of_find_node_by_type(NULL, "memory"); 612 + if (!np) 613 + return; 614 + 615 + reg = get_property(np, "reg", NULL); 616 + 617 + pdata->total_mem = reg[1]; 618 + } 619 + 620 + static void mv64x60_init_csrows(struct mem_ctl_info *mci, 621 + struct mv64x60_mc_pdata *pdata) 622 + { 623 + struct csrow_info *csrow; 624 + u32 devtype; 625 + u32 ctl; 626 + 627 + get_total_mem(pdata); 628 + 629 + ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG); 630 + 631 + csrow = &mci->csrows[0]; 632 + csrow->first_page = 0; 633 + csrow->nr_pages = pdata->total_mem >> PAGE_SHIFT; 634 + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; 635 + csrow->grain = 8; 636 + 637 + csrow->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR; 638 + 639 + devtype = (ctl >> 20) & 0x3; 640 + switch (devtype) { 641 + case 0x0: 642 + csrow->dtype = DEV_X32; 643 + break; 644 + case 0x2: /* could be X8 too, but no way to tell */ 645 + csrow->dtype = DEV_X16; 646 + break; 647 + case 0x3: 648 + csrow->dtype = DEV_X4; 649 + break; 650 + default: 651 + csrow->dtype = DEV_UNKNOWN; 652 + break; 653 + } 654 + 655 + csrow->edac_mode = EDAC_SECDED; 656 + } 657 + 658 + static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev) 659 + { 660 + struct mem_ctl_info *mci; 661 + struct mv64x60_mc_pdata *pdata; 662 + struct resource *r; 663 + u32 ctl; 664 + int res = 0; 665 + 666 + if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL)) 667 + return -ENOMEM; 668 + 669 + mci = edac_mc_alloc(sizeof(struct mv64x60_mc_pdata), 1, 1, edac_mc_idx); 670 + if (!mci) { 671 + printk(KERN_ERR "%s: No memory for CPU err\n", __func__); 672 + devres_release_group(&pdev->dev, mv64x60_mc_err_probe); 673 + return -ENOMEM; 674 + } 675 + 676 + pdata = mci->pvt_info; 677 + mci->dev = &pdev->dev; 678 + platform_set_drvdata(pdev, mci); 679 + pdata->name = "mv64x60_mc_err"; 680 + pdata->irq = NO_IRQ; 681 + mci->dev_name = pdev->dev.bus_id; 682 + pdata->edac_idx = edac_mc_idx++; 683 + 684 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 685 + if (!r) { 686 + printk(KERN_ERR "%s: Unable to get resource for " 687 + "MC err regs\n", __func__); 688 + res = -ENOENT; 689 + goto err; 690 + } 691 + 692 + if (!devm_request_mem_region(&pdev->dev, 693 + r->start, 694 + r->end - r->start + 1, 695 + pdata->name)) { 696 + printk(KERN_ERR "%s: Error while requesting mem region\n", 697 + __func__); 698 + res = -EBUSY; 699 + goto err; 700 + } 701 + 702 + pdata->mc_vbase = devm_ioremap(&pdev->dev, 703 + r->start, 704 + r->end - r->start + 1); 705 + if (!pdata->mc_vbase) { 706 + printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__); 707 + res = -ENOMEM; 708 + goto err; 709 + } 710 + 711 + ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG); 712 + if (!(ctl & MV64X60_SDRAM_ECC)) { 713 + /* Non-ECC RAM? */ 714 + printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); 715 + res = -ENODEV; 716 + goto err2; 717 + } 718 + 719 + debugf3("%s(): init mci\n", __func__); 720 + mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; 721 + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; 722 + mci->edac_cap = EDAC_FLAG_SECDED; 723 + mci->mod_name = EDAC_MOD_STR; 724 + mci->mod_ver = MV64x60_REVISION; 725 + mci->ctl_name = mv64x60_ctl_name; 726 + 727 + if (edac_op_state == EDAC_OPSTATE_POLL) 728 + mci->edac_check = mv64x60_mc_check; 729 + 730 + mci->ctl_page_to_phys = NULL; 731 + 732 + mci->scrub_mode = SCRUB_SW_SRC; 733 + 734 + mv64x60_init_csrows(mci, pdata); 735 + 736 + /* setup MC registers */ 737 + out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0); 738 + ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL); 739 + ctl = (ctl & 0xff00ffff) | 0x10000; 740 + out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl); 741 + 742 + if (edac_mc_add_mc(mci)) { 743 + debugf3("%s(): failed edac_mc_add_mc()\n", __func__); 744 + goto err; 745 + } 746 + 747 + if (edac_op_state == EDAC_OPSTATE_INT) { 748 + /* acquire interrupt that reports errors */ 749 + pdata->irq = platform_get_irq(pdev, 0); 750 + res = devm_request_irq(&pdev->dev, 751 + pdata->irq, 752 + mv64x60_mc_isr, 753 + IRQF_DISABLED, 754 + "[EDAC] MC err", 755 + mci); 756 + if (res < 0) { 757 + printk(KERN_ERR "%s: Unable to request irq %d for " 758 + "MV64x60 DRAM ERR\n", __func__, pdata->irq); 759 + res = -ENODEV; 760 + goto err2; 761 + } 762 + 763 + printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC Err\n", 764 + pdata->irq); 765 + } 766 + 767 + /* get this far and it's successful */ 768 + debugf3("%s(): success\n", __func__); 769 + 770 + return 0; 771 + 772 + err2: 773 + edac_mc_del_mc(&pdev->dev); 774 + err: 775 + devres_release_group(&pdev->dev, mv64x60_mc_err_probe); 776 + edac_mc_free(mci); 777 + return res; 778 + } 779 + 780 + static int mv64x60_mc_err_remove(struct platform_device *pdev) 781 + { 782 + struct mem_ctl_info *mci = platform_get_drvdata(pdev); 783 + 784 + debugf0("%s()\n", __func__); 785 + 786 + edac_mc_del_mc(&pdev->dev); 787 + edac_mc_free(mci); 788 + return 0; 789 + } 790 + 791 + static struct platform_driver mv64x60_mc_err_driver = { 792 + .probe = mv64x60_mc_err_probe, 793 + .remove = mv64x60_mc_err_remove, 794 + .driver = { 795 + .name = "mv64x60_mc_err", 796 + } 797 + }; 798 + 799 + static int __init mv64x60_edac_init(void) 800 + { 801 + int ret = 0; 802 + 803 + printk(KERN_INFO "Marvell MV64x60 EDAC driver " MV64x60_REVISION "\n"); 804 + printk(KERN_INFO "\t(C) 2006-2007 MontaVista Software\n"); 805 + /* make sure error reporting method is sane */ 806 + switch (edac_op_state) { 807 + case EDAC_OPSTATE_POLL: 808 + case EDAC_OPSTATE_INT: 809 + break; 810 + default: 811 + edac_op_state = EDAC_OPSTATE_INT; 812 + break; 813 + } 814 + 815 + ret = platform_driver_register(&mv64x60_mc_err_driver); 816 + if (ret) 817 + printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n"); 818 + 819 + ret = platform_driver_register(&mv64x60_cpu_err_driver); 820 + if (ret) 821 + printk(KERN_WARNING EDAC_MOD_STR 822 + "CPU err failed to register\n"); 823 + 824 + ret = platform_driver_register(&mv64x60_sram_err_driver); 825 + if (ret) 826 + printk(KERN_WARNING EDAC_MOD_STR 827 + "SRAM err failed to register\n"); 828 + 829 + #ifdef CONFIG_PCI 830 + ret = platform_driver_register(&mv64x60_pci_err_driver); 831 + if (ret) 832 + printk(KERN_WARNING EDAC_MOD_STR 833 + "PCI err failed to register\n"); 834 + #endif 835 + 836 + return ret; 837 + } 838 + module_init(mv64x60_edac_init); 839 + 840 + static void __exit mv64x60_edac_exit(void) 841 + { 842 + #ifdef CONFIG_PCI 843 + platform_driver_unregister(&mv64x60_pci_err_driver); 844 + #endif 845 + platform_driver_unregister(&mv64x60_sram_err_driver); 846 + platform_driver_unregister(&mv64x60_cpu_err_driver); 847 + platform_driver_unregister(&mv64x60_mc_err_driver); 848 + } 849 + module_exit(mv64x60_edac_exit); 850 + 851 + MODULE_LICENSE("GPL"); 852 + MODULE_AUTHOR("Montavista Software, Inc."); 853 + module_param(edac_op_state, int, 0444); 854 + MODULE_PARM_DESC(edac_op_state, 855 + "EDAC Error Reporting state: 0=Poll, 2=Interrupt");
+114
drivers/edac/mv64x60_edac.h
··· 1 + /* 2 + * EDAC defs for Marvell MV64x60 bridge chip 3 + * 4 + * Author: Dave Jiang <djiang@mvista.com> 5 + * 6 + * 2007 (c) MontaVista Software, Inc. This file is licensed under 7 + * the terms of the GNU General Public License version 2. This program 8 + * is licensed "as is" without any warranty of any kind, whether express 9 + * or implied. 10 + * 11 + */ 12 + #ifndef _MV64X60_EDAC_H_ 13 + #define _MV64X60_EDAC_H_ 14 + 15 + #define MV64x60_REVISION " Ver: 2.0.0 " __DATE__ 16 + #define EDAC_MOD_STR "MV64x60_edac" 17 + 18 + #define mv64x60_printk(level, fmt, arg...) \ 19 + edac_printk(level, "MV64x60", fmt, ##arg) 20 + 21 + #define mv64x60_mc_printk(mci, level, fmt, arg...) \ 22 + edac_mc_chipset_printk(mci, level, "MV64x60", fmt, ##arg) 23 + 24 + /* CPU Error Report Registers */ 25 + #define MV64x60_CPU_ERR_ADDR_LO 0x00 /* 0x0070 */ 26 + #define MV64x60_CPU_ERR_ADDR_HI 0x08 /* 0x0078 */ 27 + #define MV64x60_CPU_ERR_DATA_LO 0x00 /* 0x0128 */ 28 + #define MV64x60_CPU_ERR_DATA_HI 0x08 /* 0x0130 */ 29 + #define MV64x60_CPU_ERR_PARITY 0x10 /* 0x0138 */ 30 + #define MV64x60_CPU_ERR_CAUSE 0x18 /* 0x0140 */ 31 + #define MV64x60_CPU_ERR_MASK 0x20 /* 0x0148 */ 32 + 33 + #define MV64x60_CPU_CAUSE_MASK 0x07ffffff 34 + 35 + /* SRAM Error Report Registers */ 36 + #define MV64X60_SRAM_ERR_CAUSE 0x08 /* 0x0388 */ 37 + #define MV64X60_SRAM_ERR_ADDR_LO 0x10 /* 0x0390 */ 38 + #define MV64X60_SRAM_ERR_ADDR_HI 0x78 /* 0x03f8 */ 39 + #define MV64X60_SRAM_ERR_DATA_LO 0x18 /* 0x0398 */ 40 + #define MV64X60_SRAM_ERR_DATA_HI 0x20 /* 0x03a0 */ 41 + #define MV64X60_SRAM_ERR_PARITY 0x28 /* 0x03a8 */ 42 + 43 + /* SDRAM Controller Registers */ 44 + #define MV64X60_SDRAM_CONFIG 0x00 /* 0x1400 */ 45 + #define MV64X60_SDRAM_ERR_DATA_HI 0x40 /* 0x1440 */ 46 + #define MV64X60_SDRAM_ERR_DATA_LO 0x44 /* 0x1444 */ 47 + #define MV64X60_SDRAM_ERR_ECC_RCVD 0x48 /* 0x1448 */ 48 + #define MV64X60_SDRAM_ERR_ECC_CALC 0x4c /* 0x144c */ 49 + #define MV64X60_SDRAM_ERR_ADDR 0x50 /* 0x1450 */ 50 + #define MV64X60_SDRAM_ERR_ECC_CNTL 0x54 /* 0x1454 */ 51 + #define MV64X60_SDRAM_ERR_ECC_ERR_CNT 0x58 /* 0x1458 */ 52 + 53 + #define MV64X60_SDRAM_REGISTERED 0x20000 54 + #define MV64X60_SDRAM_ECC 0x40000 55 + 56 + #ifdef CONFIG_PCI 57 + /* 58 + * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of 59 + * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as 60 + * well. IOW, don't set bit 0. 61 + */ 62 + #define MV64X60_PCIx_ERR_MASK_VAL 0x00a50c24 63 + 64 + /* Register offsets from PCIx error address low register */ 65 + #define MV64X60_PCI_ERROR_ADDR_LO 0x00 66 + #define MV64X60_PCI_ERROR_ADDR_HI 0x04 67 + #define MV64X60_PCI_ERROR_ATTR 0x08 68 + #define MV64X60_PCI_ERROR_CMD 0x10 69 + #define MV64X60_PCI_ERROR_CAUSE 0x18 70 + #define MV64X60_PCI_ERROR_MASK 0x1c 71 + 72 + #define MV64X60_PCI_ERR_SWrPerr 0x0002 73 + #define MV64X60_PCI_ERR_SRdPerr 0x0004 74 + #define MV64X60_PCI_ERR_MWrPerr 0x0020 75 + #define MV64X60_PCI_ERR_MRdPerr 0x0040 76 + 77 + #define MV64X60_PCI_PE_MASK (MV64X60_PCI_ERR_SWrPerr | \ 78 + MV64X60_PCI_ERR_SRdPerr | \ 79 + MV64X60_PCI_ERR_MWrPerr | \ 80 + MV64X60_PCI_ERR_MRdPerr) 81 + 82 + struct mv64x60_pci_pdata { 83 + int pci_hose; 84 + void __iomem *pci_vbase; 85 + char *name; 86 + int irq; 87 + int edac_idx; 88 + }; 89 + 90 + #endif /* CONFIG_PCI */ 91 + 92 + struct mv64x60_mc_pdata { 93 + void __iomem *mc_vbase; 94 + int total_mem; 95 + char *name; 96 + int irq; 97 + int edac_idx; 98 + }; 99 + 100 + struct mv64x60_cpu_pdata { 101 + void __iomem *cpu_vbase[2]; 102 + char *name; 103 + int irq; 104 + int edac_idx; 105 + }; 106 + 107 + struct mv64x60_sram_pdata { 108 + void __iomem *sram_vbase; 109 + char *name; 110 + int irq; 111 + int edac_idx; 112 + }; 113 + 114 + #endif