712 lines · c
1/*2 * Freescale MPC85xx Memory Controller kernel module3 *4 * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.5 *6 * Author: Dave Jiang <djiang@mvista.com>7 *8 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under9 * the terms of the GNU General Public License version 2. This program10 * is licensed "as is" without any warranty of any kind, whether express11 * or implied.12 *13 */14#include <linux/module.h>15#include <linux/init.h>16#include <linux/interrupt.h>17#include <linux/ctype.h>18#include <linux/io.h>19#include <linux/mod_devicetable.h>20#include <linux/edac.h>21#include <linux/smp.h>22#include <linux/gfp.h>23#include <linux/fsl/edac.h>24 25#include <linux/of.h>26#include <linux/of_address.h>27#include <linux/of_irq.h>28#include "edac_module.h"29#include "mpc85xx_edac.h"30#include "fsl_ddr_edac.h"31 32static int edac_dev_idx;33#ifdef CONFIG_PCI34static int edac_pci_idx;35#endif36 37/*38 * PCI Err defines39 */40#ifdef CONFIG_PCI41static u32 orig_pci_err_cap_dr;42static u32 orig_pci_err_en;43#endif44 45static u32 orig_l2_err_disable;46 47/**************************** PCI Err device ***************************/48#ifdef CONFIG_PCI49 50static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci)51{52 struct mpc85xx_pci_pdata *pdata = pci->pvt_info;53 u32 err_detect;54 55 err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);56 57 /* master aborts can happen during PCI config cycles */58 if (!(err_detect & ~(PCI_EDE_MULTI_ERR | PCI_EDE_MST_ABRT))) {59 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);60 return;61 }62 63 pr_err("PCI error(s) detected\n");64 pr_err("PCI/X ERR_DR register: %#08x\n", err_detect);65 66 pr_err("PCI/X ERR_ATTRIB register: %#08x\n",67 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB));68 pr_err("PCI/X ERR_ADDR register: %#08x\n",69 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR));70 pr_err("PCI/X ERR_EXT_ADDR register: %#08x\n",71 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR));72 pr_err("PCI/X ERR_DL register: %#08x\n",73 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL));74 pr_err("PCI/X ERR_DH register: %#08x\n",75 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH));76 77 /* clear error bits */78 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);79 80 if (err_detect & PCI_EDE_PERR_MASK)81 edac_pci_handle_pe(pci, pci->ctl_name);82 83 if ((err_detect & ~PCI_EDE_MULTI_ERR) & ~PCI_EDE_PERR_MASK)84 edac_pci_handle_npe(pci, pci->ctl_name);85}86 87static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci)88{89 struct mpc85xx_pci_pdata *pdata = pci->pvt_info;90 u32 err_detect, err_cap_stat;91 92 err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);93 err_cap_stat = in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR);94 95 pr_err("PCIe error(s) detected\n");96 pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect);97 pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", err_cap_stat);98 pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n",99 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0));100 pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n",101 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R1));102 pr_err("PCIe ERR_CAP_R2 register: 0x%08x\n",103 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R2));104 pr_err("PCIe ERR_CAP_R3 register: 0x%08x\n",105 in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R3));106 107 /* clear error bits */108 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect);109 110 /* reset error capture */111 out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, err_cap_stat | 0x1);112}113 114static int mpc85xx_pcie_find_capability(struct device_node *np)115{116 struct pci_controller *hose;117 118 if (!np)119 return -EINVAL;120 121 hose = pci_find_hose_for_OF_device(np);122 123 return early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);124}125 126static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)127{128 struct edac_pci_ctl_info *pci = dev_id;129 struct mpc85xx_pci_pdata *pdata = pci->pvt_info;130 u32 err_detect;131 132 err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR);133 134 if (!err_detect)135 return IRQ_NONE;136 137 if (pdata->is_pcie)138 mpc85xx_pcie_check(pci);139 else140 mpc85xx_pci_check(pci);141 142 return IRQ_HANDLED;143}144 145static int mpc85xx_pci_err_probe(struct platform_device *op)146{147 struct edac_pci_ctl_info *pci;148 struct mpc85xx_pci_pdata *pdata;149 struct mpc85xx_edac_pci_plat_data *plat_data;150 struct device_node *of_node;151 struct resource r;152 int res = 0;153 154 if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL))155 return -ENOMEM;156 157 pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mpc85xx_pci_err");158 if (!pci)159 return -ENOMEM;160 161 /* make sure error reporting method is sane */162 switch (edac_op_state) {163 case EDAC_OPSTATE_POLL:164 case EDAC_OPSTATE_INT:165 break;166 default:167 edac_op_state = EDAC_OPSTATE_INT;168 break;169 }170 171 pdata = pci->pvt_info;172 pdata->name = "mpc85xx_pci_err";173 174 plat_data = op->dev.platform_data;175 if (!plat_data) {176 dev_err(&op->dev, "no platform data");177 res = -ENXIO;178 goto err;179 }180 of_node = plat_data->of_node;181 182 if (mpc85xx_pcie_find_capability(of_node) > 0)183 pdata->is_pcie = true;184 185 dev_set_drvdata(&op->dev, pci);186 pci->dev = &op->dev;187 pci->mod_name = EDAC_MOD_STR;188 pci->ctl_name = pdata->name;189 pci->dev_name = dev_name(&op->dev);190 191 if (edac_op_state == EDAC_OPSTATE_POLL) {192 if (pdata->is_pcie)193 pci->edac_check = mpc85xx_pcie_check;194 else195 pci->edac_check = mpc85xx_pci_check;196 }197 198 pdata->edac_idx = edac_pci_idx++;199 200 res = of_address_to_resource(of_node, 0, &r);201 if (res) {202 pr_err("%s: Unable to get resource for PCI err regs\n", __func__);203 goto err;204 }205 206 /* we only need the error registers */207 r.start += 0xe00;208 209 if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),210 pdata->name)) {211 pr_err("%s: Error while requesting mem region\n", __func__);212 res = -EBUSY;213 goto err;214 }215 216 pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));217 if (!pdata->pci_vbase) {218 pr_err("%s: Unable to setup PCI err regs\n", __func__);219 res = -ENOMEM;220 goto err;221 }222 223 if (pdata->is_pcie) {224 orig_pci_err_cap_dr =225 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR);226 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, ~0);227 orig_pci_err_en =228 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);229 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, 0);230 } else {231 orig_pci_err_cap_dr =232 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR);233 234 /* PCI master abort is expected during config cycles */235 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR, 0x40);236 237 orig_pci_err_en =238 in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN);239 240 /* disable master abort reporting */241 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0x40);242 }243 244 /* clear error bits */245 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);246 247 /* reset error capture */248 out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, 0x1);249 250 if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {251 edac_dbg(3, "failed edac_pci_add_device()\n");252 goto err;253 }254 255 if (edac_op_state == EDAC_OPSTATE_INT) {256 pdata->irq = irq_of_parse_and_map(of_node, 0);257 res = devm_request_irq(&op->dev, pdata->irq,258 mpc85xx_pci_isr,259 IRQF_SHARED,260 "[EDAC] PCI err", pci);261 if (res < 0) {262 pr_err("%s: Unable to request irq %d for MPC85xx PCI err\n",263 __func__, pdata->irq);264 irq_dispose_mapping(pdata->irq);265 res = -ENODEV;266 goto err2;267 }268 269 pr_info(EDAC_MOD_STR " acquired irq %d for PCI Err\n",270 pdata->irq);271 }272 273 if (pdata->is_pcie) {274 /*275 * Enable all PCIe error interrupt & error detect except invalid276 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA access interrupt generation277 * enable bit and invalid PEX_CONFIG_ADDR/PEX_CONFIG_DATA access278 * detection enable bit. Because PCIe bus code to initialize and279 * configure these PCIe devices on booting will use some invalid280 * PEX_CONFIG_ADDR/PEX_CONFIG_DATA, edac driver prints the much281 * notice information. So disable this detect to fix ugly print.282 */283 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, ~0284 & ~PEX_ERR_ICCAIE_EN_BIT);285 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, 0286 | PEX_ERR_ICCAD_DISR_BIT);287 }288 289 devres_remove_group(&op->dev, mpc85xx_pci_err_probe);290 edac_dbg(3, "success\n");291 pr_info(EDAC_MOD_STR " PCI err registered\n");292 293 return 0;294 295err2:296 edac_pci_del_device(&op->dev);297err:298 edac_pci_free_ctl_info(pci);299 devres_release_group(&op->dev, mpc85xx_pci_err_probe);300 return res;301}302 303static void mpc85xx_pci_err_remove(struct platform_device *op)304{305 struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev);306 struct mpc85xx_pci_pdata *pdata = pci->pvt_info;307 308 edac_dbg(0, "\n");309 310 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR, orig_pci_err_cap_dr);311 out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EN, orig_pci_err_en);312 313 edac_pci_del_device(&op->dev);314 edac_pci_free_ctl_info(pci);315}316 317static const struct platform_device_id mpc85xx_pci_err_match[] = {318 {319 .name = "mpc85xx-pci-edac"320 },321 {}322};323 324static struct platform_driver mpc85xx_pci_err_driver = {325 .probe = mpc85xx_pci_err_probe,326 .remove_new = mpc85xx_pci_err_remove,327 .id_table = mpc85xx_pci_err_match,328 .driver = {329 .name = "mpc85xx_pci_err",330 .suppress_bind_attrs = true,331 },332};333#endif /* CONFIG_PCI */334 335/**************************** L2 Err device ***************************/336 337/************************ L2 SYSFS parts ***********************************/338 339static ssize_t mpc85xx_l2_inject_data_hi_show(struct edac_device_ctl_info340 *edac_dev, char *data)341{342 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;343 return sprintf(data, "0x%08x",344 in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJHI));345}346 347static ssize_t mpc85xx_l2_inject_data_lo_show(struct edac_device_ctl_info348 *edac_dev, char *data)349{350 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;351 return sprintf(data, "0x%08x",352 in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJLO));353}354 355static ssize_t mpc85xx_l2_inject_ctrl_show(struct edac_device_ctl_info356 *edac_dev, char *data)357{358 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;359 return sprintf(data, "0x%08x",360 in_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJCTL));361}362 363static ssize_t mpc85xx_l2_inject_data_hi_store(struct edac_device_ctl_info364 *edac_dev, const char *data,365 size_t count)366{367 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;368 if (isdigit(*data)) {369 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJHI,370 simple_strtoul(data, NULL, 0));371 return count;372 }373 return 0;374}375 376static ssize_t mpc85xx_l2_inject_data_lo_store(struct edac_device_ctl_info377 *edac_dev, const char *data,378 size_t count)379{380 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;381 if (isdigit(*data)) {382 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJLO,383 simple_strtoul(data, NULL, 0));384 return count;385 }386 return 0;387}388 389static ssize_t mpc85xx_l2_inject_ctrl_store(struct edac_device_ctl_info390 *edac_dev, const char *data,391 size_t count)392{393 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;394 if (isdigit(*data)) {395 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINJCTL,396 simple_strtoul(data, NULL, 0));397 return count;398 }399 return 0;400}401 402static struct edac_dev_sysfs_attribute mpc85xx_l2_sysfs_attributes[] = {403 {404 .attr = {405 .name = "inject_data_hi",406 .mode = (S_IRUGO | S_IWUSR)407 },408 .show = mpc85xx_l2_inject_data_hi_show,409 .store = mpc85xx_l2_inject_data_hi_store},410 {411 .attr = {412 .name = "inject_data_lo",413 .mode = (S_IRUGO | S_IWUSR)414 },415 .show = mpc85xx_l2_inject_data_lo_show,416 .store = mpc85xx_l2_inject_data_lo_store},417 {418 .attr = {419 .name = "inject_ctrl",420 .mode = (S_IRUGO | S_IWUSR)421 },422 .show = mpc85xx_l2_inject_ctrl_show,423 .store = mpc85xx_l2_inject_ctrl_store},424 425 /* End of list */426 {427 .attr = {.name = NULL}428 }429};430 431static void mpc85xx_set_l2_sysfs_attributes(struct edac_device_ctl_info432 *edac_dev)433{434 edac_dev->sysfs_attributes = mpc85xx_l2_sysfs_attributes;435}436 437/***************************** L2 ops ***********************************/438 439static void mpc85xx_l2_check(struct edac_device_ctl_info *edac_dev)440{441 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;442 u32 err_detect;443 444 err_detect = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET);445 446 if (!(err_detect & L2_EDE_MASK))447 return;448 449 pr_err("ECC Error in CPU L2 cache\n");450 pr_err("L2 Error Detect Register: 0x%08x\n", err_detect);451 pr_err("L2 Error Capture Data High Register: 0x%08x\n",452 in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATAHI));453 pr_err("L2 Error Capture Data Lo Register: 0x%08x\n",454 in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATALO));455 pr_err("L2 Error Syndrome Register: 0x%08x\n",456 in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTECC));457 pr_err("L2 Error Attributes Capture Register: 0x%08x\n",458 in_be32(pdata->l2_vbase + MPC85XX_L2_ERRATTR));459 pr_err("L2 Error Address Capture Register: 0x%08x\n",460 in_be32(pdata->l2_vbase + MPC85XX_L2_ERRADDR));461 462 /* clear error detect register */463 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET, err_detect);464 465 if (err_detect & L2_EDE_CE_MASK)466 edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);467 468 if (err_detect & L2_EDE_UE_MASK)469 edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);470}471 472static irqreturn_t mpc85xx_l2_isr(int irq, void *dev_id)473{474 struct edac_device_ctl_info *edac_dev = dev_id;475 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;476 u32 err_detect;477 478 err_detect = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET);479 480 if (!(err_detect & L2_EDE_MASK))481 return IRQ_NONE;482 483 mpc85xx_l2_check(edac_dev);484 485 return IRQ_HANDLED;486}487 488static int mpc85xx_l2_err_probe(struct platform_device *op)489{490 struct edac_device_ctl_info *edac_dev;491 struct mpc85xx_l2_pdata *pdata;492 struct resource r;493 int res;494 495 if (!devres_open_group(&op->dev, mpc85xx_l2_err_probe, GFP_KERNEL))496 return -ENOMEM;497 498 edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),499 "cpu", 1, "L", 1, 2,500 edac_dev_idx);501 if (!edac_dev) {502 devres_release_group(&op->dev, mpc85xx_l2_err_probe);503 return -ENOMEM;504 }505 506 pdata = edac_dev->pvt_info;507 pdata->name = "mpc85xx_l2_err";508 edac_dev->dev = &op->dev;509 dev_set_drvdata(edac_dev->dev, edac_dev);510 edac_dev->ctl_name = pdata->name;511 edac_dev->dev_name = pdata->name;512 513 res = of_address_to_resource(op->dev.of_node, 0, &r);514 if (res) {515 pr_err("%s: Unable to get resource for L2 err regs\n", __func__);516 goto err;517 }518 519 /* we only need the error registers */520 r.start += 0xe00;521 522 if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),523 pdata->name)) {524 pr_err("%s: Error while requesting mem region\n", __func__);525 res = -EBUSY;526 goto err;527 }528 529 pdata->l2_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));530 if (!pdata->l2_vbase) {531 pr_err("%s: Unable to setup L2 err regs\n", __func__);532 res = -ENOMEM;533 goto err;534 }535 536 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDET, ~0);537 538 orig_l2_err_disable = in_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS);539 540 /* clear the err_dis */541 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS, 0);542 543 edac_dev->mod_name = EDAC_MOD_STR;544 545 if (edac_op_state == EDAC_OPSTATE_POLL)546 edac_dev->edac_check = mpc85xx_l2_check;547 548 mpc85xx_set_l2_sysfs_attributes(edac_dev);549 550 pdata->edac_idx = edac_dev_idx++;551 552 if (edac_device_add_device(edac_dev) > 0) {553 edac_dbg(3, "failed edac_device_add_device()\n");554 goto err;555 }556 557 if (edac_op_state == EDAC_OPSTATE_INT) {558 pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);559 res = devm_request_irq(&op->dev, pdata->irq,560 mpc85xx_l2_isr, IRQF_SHARED,561 "[EDAC] L2 err", edac_dev);562 if (res < 0) {563 pr_err("%s: Unable to request irq %d for MPC85xx L2 err\n",564 __func__, pdata->irq);565 irq_dispose_mapping(pdata->irq);566 res = -ENODEV;567 goto err2;568 }569 570 pr_info(EDAC_MOD_STR " acquired irq %d for L2 Err\n", pdata->irq);571 572 edac_dev->op_state = OP_RUNNING_INTERRUPT;573 574 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, L2_EIE_MASK);575 }576 577 devres_remove_group(&op->dev, mpc85xx_l2_err_probe);578 579 edac_dbg(3, "success\n");580 pr_info(EDAC_MOD_STR " L2 err registered\n");581 582 return 0;583 584err2:585 edac_device_del_device(&op->dev);586err:587 devres_release_group(&op->dev, mpc85xx_l2_err_probe);588 edac_device_free_ctl_info(edac_dev);589 return res;590}591 592static void mpc85xx_l2_err_remove(struct platform_device *op)593{594 struct edac_device_ctl_info *edac_dev = dev_get_drvdata(&op->dev);595 struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;596 597 edac_dbg(0, "\n");598 599 if (edac_op_state == EDAC_OPSTATE_INT) {600 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, 0);601 irq_dispose_mapping(pdata->irq);602 }603 604 out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS, orig_l2_err_disable);605 edac_device_del_device(&op->dev);606 edac_device_free_ctl_info(edac_dev);607}608 609static const struct of_device_id mpc85xx_l2_err_of_match[] = {610 { .compatible = "fsl,mpc8536-l2-cache-controller", },611 { .compatible = "fsl,mpc8540-l2-cache-controller", },612 { .compatible = "fsl,mpc8541-l2-cache-controller", },613 { .compatible = "fsl,mpc8544-l2-cache-controller", },614 { .compatible = "fsl,mpc8548-l2-cache-controller", },615 { .compatible = "fsl,mpc8555-l2-cache-controller", },616 { .compatible = "fsl,mpc8560-l2-cache-controller", },617 { .compatible = "fsl,mpc8568-l2-cache-controller", },618 { .compatible = "fsl,mpc8569-l2-cache-controller", },619 { .compatible = "fsl,mpc8572-l2-cache-controller", },620 { .compatible = "fsl,p1020-l2-cache-controller", },621 { .compatible = "fsl,p1021-l2-cache-controller", },622 { .compatible = "fsl,p2020-l2-cache-controller", },623 { .compatible = "fsl,t2080-l2-cache-controller", },624 {},625};626MODULE_DEVICE_TABLE(of, mpc85xx_l2_err_of_match);627 628static struct platform_driver mpc85xx_l2_err_driver = {629 .probe = mpc85xx_l2_err_probe,630 .remove_new = mpc85xx_l2_err_remove,631 .driver = {632 .name = "mpc85xx_l2_err",633 .of_match_table = mpc85xx_l2_err_of_match,634 },635};636 637static const struct of_device_id mpc85xx_mc_err_of_match[] = {638 { .compatible = "fsl,mpc8536-memory-controller", },639 { .compatible = "fsl,mpc8540-memory-controller", },640 { .compatible = "fsl,mpc8541-memory-controller", },641 { .compatible = "fsl,mpc8544-memory-controller", },642 { .compatible = "fsl,mpc8548-memory-controller", },643 { .compatible = "fsl,mpc8555-memory-controller", },644 { .compatible = "fsl,mpc8560-memory-controller", },645 { .compatible = "fsl,mpc8568-memory-controller", },646 { .compatible = "fsl,mpc8569-memory-controller", },647 { .compatible = "fsl,mpc8572-memory-controller", },648 { .compatible = "fsl,mpc8349-memory-controller", },649 { .compatible = "fsl,p1020-memory-controller", },650 { .compatible = "fsl,p1021-memory-controller", },651 { .compatible = "fsl,p2020-memory-controller", },652 { .compatible = "fsl,qoriq-memory-controller", },653 {},654};655MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match);656 657static struct platform_driver mpc85xx_mc_err_driver = {658 .probe = fsl_mc_err_probe,659 .remove_new = fsl_mc_err_remove,660 .driver = {661 .name = "mpc85xx_mc_err",662 .of_match_table = mpc85xx_mc_err_of_match,663 },664};665 666static struct platform_driver * const drivers[] = {667 &mpc85xx_mc_err_driver,668 &mpc85xx_l2_err_driver,669#ifdef CONFIG_PCI670 &mpc85xx_pci_err_driver,671#endif672};673 674static int __init mpc85xx_mc_init(void)675{676 int res = 0;677 u32 __maybe_unused pvr = 0;678 679 pr_info("Freescale(R) MPC85xx EDAC driver, (C) 2006 Montavista Software\n");680 681 /* make sure error reporting method is sane */682 switch (edac_op_state) {683 case EDAC_OPSTATE_POLL:684 case EDAC_OPSTATE_INT:685 break;686 default:687 edac_op_state = EDAC_OPSTATE_INT;688 break;689 }690 691 res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));692 if (res)693 pr_warn(EDAC_MOD_STR "drivers fail to register\n");694 695 return 0;696}697 698module_init(mpc85xx_mc_init);699 700static void __exit mpc85xx_mc_exit(void)701{702 platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));703}704 705module_exit(mpc85xx_mc_exit);706 707MODULE_DESCRIPTION("Freescale MPC85xx Memory Controller EDAC driver");708MODULE_LICENSE("GPL");709MODULE_AUTHOR("Montavista Software, Inc.");710module_param(edac_op_state, int, 0444);711MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll, 2=Interrupt");712