543 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// Copyright (c) 2022 Nuvoton Technology Corporation3 4#include <linux/debugfs.h>5#include <linux/iopoll.h>6#include <linux/of.h>7#include <linux/platform_device.h>8#include <linux/regmap.h>9#include "edac_module.h"10 11#define EDAC_MOD_NAME "npcm-edac"12#define EDAC_MSG_SIZE 25613 14/* chip serials */15#define NPCM7XX_CHIP BIT(0)16#define NPCM8XX_CHIP BIT(1)17 18/* syndrome values */19#define UE_SYNDROME 0x0320 21/* error injection */22#define ERROR_TYPE_CORRECTABLE 023#define ERROR_TYPE_UNCORRECTABLE 124#define ERROR_LOCATION_DATA 025#define ERROR_LOCATION_CHECKCODE 126#define ERROR_BIT_DATA_MAX 6327#define ERROR_BIT_CHECKCODE_MAX 728 29static char data_synd[] = {30 0xf4, 0xf1, 0xec, 0xea, 0xe9, 0xe6, 0xe5, 0xe3,31 0xdc, 0xda, 0xd9, 0xd6, 0xd5, 0xd3, 0xce, 0xcb,32 0xb5, 0xb0, 0xad, 0xab, 0xa8, 0xa7, 0xa4, 0xa2,33 0x9d, 0x9b, 0x98, 0x97, 0x94, 0x92, 0x8f, 0x8a,34 0x75, 0x70, 0x6d, 0x6b, 0x68, 0x67, 0x64, 0x62,35 0x5e, 0x5b, 0x58, 0x57, 0x54, 0x52, 0x4f, 0x4a,36 0x34, 0x31, 0x2c, 0x2a, 0x29, 0x26, 0x25, 0x23,37 0x1c, 0x1a, 0x19, 0x16, 0x15, 0x13, 0x0e, 0x0b38};39 40static struct regmap *npcm_regmap;41 42struct npcm_platform_data {43 /* chip serials */44 int chip;45 46 /* memory controller registers */47 u32 ctl_ecc_en;48 u32 ctl_int_status;49 u32 ctl_int_ack;50 u32 ctl_int_mask_master;51 u32 ctl_int_mask_ecc;52 u32 ctl_ce_addr_l;53 u32 ctl_ce_addr_h;54 u32 ctl_ce_data_l;55 u32 ctl_ce_data_h;56 u32 ctl_ce_synd;57 u32 ctl_ue_addr_l;58 u32 ctl_ue_addr_h;59 u32 ctl_ue_data_l;60 u32 ctl_ue_data_h;61 u32 ctl_ue_synd;62 u32 ctl_source_id;63 u32 ctl_controller_busy;64 u32 ctl_xor_check_bits;65 66 /* masks and shifts */67 u32 ecc_en_mask;68 u32 int_status_ce_mask;69 u32 int_status_ue_mask;70 u32 int_ack_ce_mask;71 u32 int_ack_ue_mask;72 u32 int_mask_master_non_ecc_mask;73 u32 int_mask_master_global_mask;74 u32 int_mask_ecc_non_event_mask;75 u32 ce_addr_h_mask;76 u32 ce_synd_mask;77 u32 ce_synd_shift;78 u32 ue_addr_h_mask;79 u32 ue_synd_mask;80 u32 ue_synd_shift;81 u32 source_id_ce_mask;82 u32 source_id_ce_shift;83 u32 source_id_ue_mask;84 u32 source_id_ue_shift;85 u32 controller_busy_mask;86 u32 xor_check_bits_mask;87 u32 xor_check_bits_shift;88 u32 writeback_en_mask;89 u32 fwc_mask;90};91 92struct priv_data {93 void __iomem *reg;94 char message[EDAC_MSG_SIZE];95 const struct npcm_platform_data *pdata;96 97 /* error injection */98 struct dentry *debugfs;99 u8 error_type;100 u8 location;101 u8 bit;102};103 104static void handle_ce(struct mem_ctl_info *mci)105{106 struct priv_data *priv = mci->pvt_info;107 const struct npcm_platform_data *pdata;108 u32 val_h = 0, val_l, id, synd;109 u64 addr = 0, data = 0;110 111 pdata = priv->pdata;112 regmap_read(npcm_regmap, pdata->ctl_ce_addr_l, &val_l);113 if (pdata->chip == NPCM8XX_CHIP) {114 regmap_read(npcm_regmap, pdata->ctl_ce_addr_h, &val_h);115 val_h &= pdata->ce_addr_h_mask;116 }117 addr = ((addr | val_h) << 32) | val_l;118 119 regmap_read(npcm_regmap, pdata->ctl_ce_data_l, &val_l);120 if (pdata->chip == NPCM8XX_CHIP)121 regmap_read(npcm_regmap, pdata->ctl_ce_data_h, &val_h);122 data = ((data | val_h) << 32) | val_l;123 124 regmap_read(npcm_regmap, pdata->ctl_source_id, &id);125 id = (id & pdata->source_id_ce_mask) >> pdata->source_id_ce_shift;126 127 regmap_read(npcm_regmap, pdata->ctl_ce_synd, &synd);128 synd = (synd & pdata->ce_synd_mask) >> pdata->ce_synd_shift;129 130 snprintf(priv->message, EDAC_MSG_SIZE,131 "addr = 0x%llx, data = 0x%llx, id = 0x%x", addr, data, id);132 133 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, addr >> PAGE_SHIFT,134 addr & ~PAGE_MASK, synd, 0, 0, -1, priv->message, "");135}136 137static void handle_ue(struct mem_ctl_info *mci)138{139 struct priv_data *priv = mci->pvt_info;140 const struct npcm_platform_data *pdata;141 u32 val_h = 0, val_l, id, synd;142 u64 addr = 0, data = 0;143 144 pdata = priv->pdata;145 regmap_read(npcm_regmap, pdata->ctl_ue_addr_l, &val_l);146 if (pdata->chip == NPCM8XX_CHIP) {147 regmap_read(npcm_regmap, pdata->ctl_ue_addr_h, &val_h);148 val_h &= pdata->ue_addr_h_mask;149 }150 addr = ((addr | val_h) << 32) | val_l;151 152 regmap_read(npcm_regmap, pdata->ctl_ue_data_l, &val_l);153 if (pdata->chip == NPCM8XX_CHIP)154 regmap_read(npcm_regmap, pdata->ctl_ue_data_h, &val_h);155 data = ((data | val_h) << 32) | val_l;156 157 regmap_read(npcm_regmap, pdata->ctl_source_id, &id);158 id = (id & pdata->source_id_ue_mask) >> pdata->source_id_ue_shift;159 160 regmap_read(npcm_regmap, pdata->ctl_ue_synd, &synd);161 synd = (synd & pdata->ue_synd_mask) >> pdata->ue_synd_shift;162 163 snprintf(priv->message, EDAC_MSG_SIZE,164 "addr = 0x%llx, data = 0x%llx, id = 0x%x", addr, data, id);165 166 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, addr >> PAGE_SHIFT,167 addr & ~PAGE_MASK, synd, 0, 0, -1, priv->message, "");168}169 170static irqreturn_t edac_ecc_isr(int irq, void *dev_id)171{172 const struct npcm_platform_data *pdata;173 struct mem_ctl_info *mci = dev_id;174 u32 status;175 176 pdata = ((struct priv_data *)mci->pvt_info)->pdata;177 regmap_read(npcm_regmap, pdata->ctl_int_status, &status);178 if (status & pdata->int_status_ce_mask) {179 handle_ce(mci);180 181 /* acknowledge the CE interrupt */182 regmap_write(npcm_regmap, pdata->ctl_int_ack,183 pdata->int_ack_ce_mask);184 return IRQ_HANDLED;185 } else if (status & pdata->int_status_ue_mask) {186 handle_ue(mci);187 188 /* acknowledge the UE interrupt */189 regmap_write(npcm_regmap, pdata->ctl_int_ack,190 pdata->int_ack_ue_mask);191 return IRQ_HANDLED;192 }193 194 WARN_ON_ONCE(1);195 return IRQ_NONE;196}197 198static ssize_t force_ecc_error(struct file *file, const char __user *data,199 size_t count, loff_t *ppos)200{201 struct device *dev = file->private_data;202 struct mem_ctl_info *mci = to_mci(dev);203 struct priv_data *priv = mci->pvt_info;204 const struct npcm_platform_data *pdata;205 u32 val, syndrome;206 int ret;207 208 pdata = priv->pdata;209 edac_printk(KERN_INFO, EDAC_MOD_NAME,210 "force an ECC error, type = %d, location = %d, bit = %d\n",211 priv->error_type, priv->location, priv->bit);212 213 /* ensure no pending writes */214 ret = regmap_read_poll_timeout(npcm_regmap, pdata->ctl_controller_busy,215 val, !(val & pdata->controller_busy_mask),216 1000, 10000);217 if (ret) {218 edac_printk(KERN_INFO, EDAC_MOD_NAME,219 "wait pending writes timeout\n");220 return count;221 }222 223 regmap_read(npcm_regmap, pdata->ctl_xor_check_bits, &val);224 val &= ~pdata->xor_check_bits_mask;225 226 /* write syndrome to XOR_CHECK_BITS */227 if (priv->error_type == ERROR_TYPE_CORRECTABLE) {228 if (priv->location == ERROR_LOCATION_DATA &&229 priv->bit > ERROR_BIT_DATA_MAX) {230 edac_printk(KERN_INFO, EDAC_MOD_NAME,231 "data bit should not exceed %d (%d)\n",232 ERROR_BIT_DATA_MAX, priv->bit);233 return count;234 }235 236 if (priv->location == ERROR_LOCATION_CHECKCODE &&237 priv->bit > ERROR_BIT_CHECKCODE_MAX) {238 edac_printk(KERN_INFO, EDAC_MOD_NAME,239 "checkcode bit should not exceed %d (%d)\n",240 ERROR_BIT_CHECKCODE_MAX, priv->bit);241 return count;242 }243 244 syndrome = priv->location ? 1 << priv->bit245 : data_synd[priv->bit];246 247 regmap_write(npcm_regmap, pdata->ctl_xor_check_bits,248 val | (syndrome << pdata->xor_check_bits_shift) |249 pdata->writeback_en_mask);250 } else if (priv->error_type == ERROR_TYPE_UNCORRECTABLE) {251 regmap_write(npcm_regmap, pdata->ctl_xor_check_bits,252 val | (UE_SYNDROME << pdata->xor_check_bits_shift));253 }254 255 /* force write check */256 regmap_update_bits(npcm_regmap, pdata->ctl_xor_check_bits,257 pdata->fwc_mask, pdata->fwc_mask);258 259 return count;260}261 262static const struct file_operations force_ecc_error_fops = {263 .open = simple_open,264 .write = force_ecc_error,265 .llseek = generic_file_llseek,266};267 268/*269 * Setup debugfs for error injection.270 *271 * Nodes:272 * error_type - 0: CE, 1: UE273 * location - 0: data, 1: checkcode274 * bit - 0 ~ 63 for data and 0 ~ 7 for checkcode275 * force_ecc_error - trigger276 *277 * Examples:278 * 1. Inject a correctable error (CE) at checkcode bit 7.279 * ~# echo 0 > /sys/kernel/debug/edac/npcm-edac/error_type280 * ~# echo 1 > /sys/kernel/debug/edac/npcm-edac/location281 * ~# echo 7 > /sys/kernel/debug/edac/npcm-edac/bit282 * ~# echo 1 > /sys/kernel/debug/edac/npcm-edac/force_ecc_error283 *284 * 2. Inject an uncorrectable error (UE).285 * ~# echo 1 > /sys/kernel/debug/edac/npcm-edac/error_type286 * ~# echo 1 > /sys/kernel/debug/edac/npcm-edac/force_ecc_error287 */288static void setup_debugfs(struct mem_ctl_info *mci)289{290 struct priv_data *priv = mci->pvt_info;291 292 priv->debugfs = edac_debugfs_create_dir(mci->mod_name);293 if (!priv->debugfs)294 return;295 296 edac_debugfs_create_x8("error_type", 0644, priv->debugfs, &priv->error_type);297 edac_debugfs_create_x8("location", 0644, priv->debugfs, &priv->location);298 edac_debugfs_create_x8("bit", 0644, priv->debugfs, &priv->bit);299 edac_debugfs_create_file("force_ecc_error", 0200, priv->debugfs,300 &mci->dev, &force_ecc_error_fops);301}302 303static int setup_irq(struct mem_ctl_info *mci, struct platform_device *pdev)304{305 const struct npcm_platform_data *pdata;306 int ret, irq;307 308 pdata = ((struct priv_data *)mci->pvt_info)->pdata;309 irq = platform_get_irq(pdev, 0);310 if (irq < 0) {311 edac_printk(KERN_ERR, EDAC_MOD_NAME, "IRQ not defined in DTS\n");312 return irq;313 }314 315 ret = devm_request_irq(&pdev->dev, irq, edac_ecc_isr, 0,316 dev_name(&pdev->dev), mci);317 if (ret < 0) {318 edac_printk(KERN_ERR, EDAC_MOD_NAME, "failed to request IRQ\n");319 return ret;320 }321 322 /* enable the functional group of ECC and mask the others */323 regmap_write(npcm_regmap, pdata->ctl_int_mask_master,324 pdata->int_mask_master_non_ecc_mask);325 326 if (pdata->chip == NPCM8XX_CHIP)327 regmap_write(npcm_regmap, pdata->ctl_int_mask_ecc,328 pdata->int_mask_ecc_non_event_mask);329 330 return 0;331}332 333static const struct regmap_config npcm_regmap_cfg = {334 .reg_bits = 32,335 .reg_stride = 4,336 .val_bits = 32,337};338 339static int edac_probe(struct platform_device *pdev)340{341 const struct npcm_platform_data *pdata;342 struct device *dev = &pdev->dev;343 struct edac_mc_layer layers[1];344 struct mem_ctl_info *mci;345 struct priv_data *priv;346 void __iomem *reg;347 u32 val;348 int rc;349 350 reg = devm_platform_ioremap_resource(pdev, 0);351 if (IS_ERR(reg))352 return PTR_ERR(reg);353 354 npcm_regmap = devm_regmap_init_mmio(dev, reg, &npcm_regmap_cfg);355 if (IS_ERR(npcm_regmap))356 return PTR_ERR(npcm_regmap);357 358 pdata = of_device_get_match_data(dev);359 if (!pdata)360 return -EINVAL;361 362 /* bail out if ECC is not enabled */363 regmap_read(npcm_regmap, pdata->ctl_ecc_en, &val);364 if (!(val & pdata->ecc_en_mask)) {365 edac_printk(KERN_ERR, EDAC_MOD_NAME, "ECC is not enabled\n");366 return -EPERM;367 }368 369 edac_op_state = EDAC_OPSTATE_INT;370 371 layers[0].type = EDAC_MC_LAYER_ALL_MEM;372 layers[0].size = 1;373 374 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,375 sizeof(struct priv_data));376 if (!mci)377 return -ENOMEM;378 379 mci->pdev = &pdev->dev;380 priv = mci->pvt_info;381 priv->reg = reg;382 priv->pdata = pdata;383 platform_set_drvdata(pdev, mci);384 385 mci->mtype_cap = MEM_FLAG_DDR4;386 mci->edac_ctl_cap = EDAC_FLAG_SECDED;387 mci->scrub_cap = SCRUB_FLAG_HW_SRC;388 mci->scrub_mode = SCRUB_HW_SRC;389 mci->edac_cap = EDAC_FLAG_SECDED;390 mci->ctl_name = "npcm_ddr_controller";391 mci->dev_name = dev_name(&pdev->dev);392 mci->mod_name = EDAC_MOD_NAME;393 mci->ctl_page_to_phys = NULL;394 395 rc = setup_irq(mci, pdev);396 if (rc)397 goto free_edac_mc;398 399 rc = edac_mc_add_mc(mci);400 if (rc)401 goto free_edac_mc;402 403 if (IS_ENABLED(CONFIG_EDAC_DEBUG) && pdata->chip == NPCM8XX_CHIP)404 setup_debugfs(mci);405 406 return rc;407 408free_edac_mc:409 edac_mc_free(mci);410 return rc;411}412 413static void edac_remove(struct platform_device *pdev)414{415 struct mem_ctl_info *mci = platform_get_drvdata(pdev);416 struct priv_data *priv = mci->pvt_info;417 const struct npcm_platform_data *pdata;418 419 pdata = priv->pdata;420 if (IS_ENABLED(CONFIG_EDAC_DEBUG) && pdata->chip == NPCM8XX_CHIP)421 edac_debugfs_remove_recursive(priv->debugfs);422 423 edac_mc_del_mc(&pdev->dev);424 edac_mc_free(mci);425 426 regmap_write(npcm_regmap, pdata->ctl_int_mask_master,427 pdata->int_mask_master_global_mask);428 regmap_update_bits(npcm_regmap, pdata->ctl_ecc_en, pdata->ecc_en_mask, 0);429}430 431static const struct npcm_platform_data npcm750_edac = {432 .chip = NPCM7XX_CHIP,433 434 /* memory controller registers */435 .ctl_ecc_en = 0x174,436 .ctl_int_status = 0x1d0,437 .ctl_int_ack = 0x1d4,438 .ctl_int_mask_master = 0x1d8,439 .ctl_ce_addr_l = 0x188,440 .ctl_ce_data_l = 0x190,441 .ctl_ce_synd = 0x18c,442 .ctl_ue_addr_l = 0x17c,443 .ctl_ue_data_l = 0x184,444 .ctl_ue_synd = 0x180,445 .ctl_source_id = 0x194,446 447 /* masks and shifts */448 .ecc_en_mask = BIT(24),449 .int_status_ce_mask = GENMASK(4, 3),450 .int_status_ue_mask = GENMASK(6, 5),451 .int_ack_ce_mask = GENMASK(4, 3),452 .int_ack_ue_mask = GENMASK(6, 5),453 .int_mask_master_non_ecc_mask = GENMASK(30, 7) | GENMASK(2, 0),454 .int_mask_master_global_mask = BIT(31),455 .ce_synd_mask = GENMASK(6, 0),456 .ce_synd_shift = 0,457 .ue_synd_mask = GENMASK(6, 0),458 .ue_synd_shift = 0,459 .source_id_ce_mask = GENMASK(29, 16),460 .source_id_ce_shift = 16,461 .source_id_ue_mask = GENMASK(13, 0),462 .source_id_ue_shift = 0,463};464 465static const struct npcm_platform_data npcm845_edac = {466 .chip = NPCM8XX_CHIP,467 468 /* memory controller registers */469 .ctl_ecc_en = 0x16c,470 .ctl_int_status = 0x228,471 .ctl_int_ack = 0x244,472 .ctl_int_mask_master = 0x220,473 .ctl_int_mask_ecc = 0x260,474 .ctl_ce_addr_l = 0x18c,475 .ctl_ce_addr_h = 0x190,476 .ctl_ce_data_l = 0x194,477 .ctl_ce_data_h = 0x198,478 .ctl_ce_synd = 0x190,479 .ctl_ue_addr_l = 0x17c,480 .ctl_ue_addr_h = 0x180,481 .ctl_ue_data_l = 0x184,482 .ctl_ue_data_h = 0x188,483 .ctl_ue_synd = 0x180,484 .ctl_source_id = 0x19c,485 .ctl_controller_busy = 0x20c,486 .ctl_xor_check_bits = 0x174,487 488 /* masks and shifts */489 .ecc_en_mask = GENMASK(17, 16),490 .int_status_ce_mask = GENMASK(1, 0),491 .int_status_ue_mask = GENMASK(3, 2),492 .int_ack_ce_mask = GENMASK(1, 0),493 .int_ack_ue_mask = GENMASK(3, 2),494 .int_mask_master_non_ecc_mask = GENMASK(30, 3) | GENMASK(1, 0),495 .int_mask_master_global_mask = BIT(31),496 .int_mask_ecc_non_event_mask = GENMASK(8, 4),497 .ce_addr_h_mask = GENMASK(1, 0),498 .ce_synd_mask = GENMASK(15, 8),499 .ce_synd_shift = 8,500 .ue_addr_h_mask = GENMASK(1, 0),501 .ue_synd_mask = GENMASK(15, 8),502 .ue_synd_shift = 8,503 .source_id_ce_mask = GENMASK(29, 16),504 .source_id_ce_shift = 16,505 .source_id_ue_mask = GENMASK(13, 0),506 .source_id_ue_shift = 0,507 .controller_busy_mask = BIT(0),508 .xor_check_bits_mask = GENMASK(23, 16),509 .xor_check_bits_shift = 16,510 .writeback_en_mask = BIT(24),511 .fwc_mask = BIT(8),512};513 514static const struct of_device_id npcm_edac_of_match[] = {515 {516 .compatible = "nuvoton,npcm750-memory-controller",517 .data = &npcm750_edac518 },519 {520 .compatible = "nuvoton,npcm845-memory-controller",521 .data = &npcm845_edac522 },523 {},524};525 526MODULE_DEVICE_TABLE(of, npcm_edac_of_match);527 528static struct platform_driver npcm_edac_driver = {529 .driver = {530 .name = "npcm-edac",531 .of_match_table = npcm_edac_of_match,532 },533 .probe = edac_probe,534 .remove_new = edac_remove,535};536 537module_platform_driver(npcm_edac_driver);538 539MODULE_AUTHOR("Medad CChien <medadyoung@gmail.com>");540MODULE_AUTHOR("Marvin Lin <kflin@nuvoton.com>");541MODULE_DESCRIPTION("Nuvoton NPCM EDAC Driver");542MODULE_LICENSE("GPL");543