398 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright 2018, 2019 Cisco Systems4 */5 6#include <linux/edac.h>7#include <linux/module.h>8#include <linux/init.h>9#include <linux/interrupt.h>10#include <linux/platform_device.h>11#include <linux/stop_machine.h>12#include <linux/io.h>13#include <linux/of_address.h>14#include <linux/regmap.h>15#include "edac_module.h"16 17 18#define DRV_NAME "aspeed-edac"19 20 21#define ASPEED_MCR_PROT 0x00 /* protection key register */22#define ASPEED_MCR_CONF 0x04 /* configuration register */23#define ASPEED_MCR_INTR_CTRL 0x50 /* interrupt control/status register */24#define ASPEED_MCR_ADDR_UNREC 0x58 /* address of first un-recoverable error */25#define ASPEED_MCR_ADDR_REC 0x5c /* address of last recoverable error */26#define ASPEED_MCR_LAST ASPEED_MCR_ADDR_REC27 28 29#define ASPEED_MCR_PROT_PASSWD 0xfc60030930#define ASPEED_MCR_CONF_DRAM_TYPE BIT(4)31#define ASPEED_MCR_CONF_ECC BIT(7)32#define ASPEED_MCR_INTR_CTRL_CLEAR BIT(31)33#define ASPEED_MCR_INTR_CTRL_CNT_REC GENMASK(23, 16)34#define ASPEED_MCR_INTR_CTRL_CNT_UNREC GENMASK(15, 12)35#define ASPEED_MCR_INTR_CTRL_ENABLE (BIT(0) | BIT(1))36 37 38static struct regmap *aspeed_regmap;39 40 41static int regmap_reg_write(void *context, unsigned int reg, unsigned int val)42{43 void __iomem *regs = (void __iomem *)context;44 45 /* enable write to MCR register set */46 writel(ASPEED_MCR_PROT_PASSWD, regs + ASPEED_MCR_PROT);47 48 writel(val, regs + reg);49 50 /* disable write to MCR register set */51 writel(~ASPEED_MCR_PROT_PASSWD, regs + ASPEED_MCR_PROT);52 53 return 0;54}55 56 57static int regmap_reg_read(void *context, unsigned int reg, unsigned int *val)58{59 void __iomem *regs = (void __iomem *)context;60 61 *val = readl(regs + reg);62 63 return 0;64}65 66static bool regmap_is_volatile(struct device *dev, unsigned int reg)67{68 switch (reg) {69 case ASPEED_MCR_PROT:70 case ASPEED_MCR_INTR_CTRL:71 case ASPEED_MCR_ADDR_UNREC:72 case ASPEED_MCR_ADDR_REC:73 return true;74 default:75 return false;76 }77}78 79 80static const struct regmap_config aspeed_regmap_config = {81 .reg_bits = 32,82 .val_bits = 32,83 .reg_stride = 4,84 .max_register = ASPEED_MCR_LAST,85 .reg_write = regmap_reg_write,86 .reg_read = regmap_reg_read,87 .volatile_reg = regmap_is_volatile,88 .fast_io = true,89};90 91 92static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr)93{94 struct csrow_info *csrow = mci->csrows[0];95 u32 page, offset, syndrome;96 97 if (!rec_cnt)98 return;99 100 /* report first few errors (if there are) */101 /* note: no addresses are recorded */102 if (rec_cnt > 1) {103 /* page, offset and syndrome are not available */104 page = 0;105 offset = 0;106 syndrome = 0;107 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, rec_cnt-1,108 page, offset, syndrome, 0, 0, -1,109 "address(es) not available", "");110 }111 112 /* report last error */113 /* note: rec_addr is the last recoverable error addr */114 page = rec_addr >> PAGE_SHIFT;115 offset = rec_addr & ~PAGE_MASK;116 /* syndrome is not available */117 syndrome = 0;118 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,119 csrow->first_page + page, offset, syndrome,120 0, 0, -1, "", "");121}122 123 124static void count_un_rec(struct mem_ctl_info *mci, u8 un_rec_cnt,125 u32 un_rec_addr)126{127 struct csrow_info *csrow = mci->csrows[0];128 u32 page, offset, syndrome;129 130 if (!un_rec_cnt)131 return;132 133 /* report 1. error */134 /* note: un_rec_addr is the first unrecoverable error addr */135 page = un_rec_addr >> PAGE_SHIFT;136 offset = un_rec_addr & ~PAGE_MASK;137 /* syndrome is not available */138 syndrome = 0;139 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,140 csrow->first_page + page, offset, syndrome,141 0, 0, -1, "", "");142 143 /* report further errors (if there are) */144 /* note: no addresses are recorded */145 if (un_rec_cnt > 1) {146 /* page, offset and syndrome are not available */147 page = 0;148 offset = 0;149 syndrome = 0;150 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, un_rec_cnt-1,151 page, offset, syndrome, 0, 0, -1,152 "address(es) not available", "");153 }154}155 156 157static irqreturn_t mcr_isr(int irq, void *arg)158{159 struct mem_ctl_info *mci = arg;160 u32 rec_addr, un_rec_addr;161 u32 reg50, reg5c, reg58;162 u8 rec_cnt, un_rec_cnt;163 164 regmap_read(aspeed_regmap, ASPEED_MCR_INTR_CTRL, ®50);165 dev_dbg(mci->pdev, "received edac interrupt w/ mcr register 50: 0x%x\n",166 reg50);167 168 /* collect data about recoverable and unrecoverable errors */169 rec_cnt = (reg50 & ASPEED_MCR_INTR_CTRL_CNT_REC) >> 16;170 un_rec_cnt = (reg50 & ASPEED_MCR_INTR_CTRL_CNT_UNREC) >> 12;171 172 dev_dbg(mci->pdev, "%d recoverable interrupts and %d unrecoverable interrupts\n",173 rec_cnt, un_rec_cnt);174 175 regmap_read(aspeed_regmap, ASPEED_MCR_ADDR_UNREC, ®58);176 un_rec_addr = reg58;177 178 regmap_read(aspeed_regmap, ASPEED_MCR_ADDR_REC, ®5c);179 rec_addr = reg5c;180 181 /* clear interrupt flags and error counters: */182 regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL,183 ASPEED_MCR_INTR_CTRL_CLEAR,184 ASPEED_MCR_INTR_CTRL_CLEAR);185 186 regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL,187 ASPEED_MCR_INTR_CTRL_CLEAR, 0);188 189 /* process recoverable and unrecoverable errors */190 count_rec(mci, rec_cnt, rec_addr);191 count_un_rec(mci, un_rec_cnt, un_rec_addr);192 193 if (!rec_cnt && !un_rec_cnt)194 dev_dbg(mci->pdev, "received edac interrupt, but did not find any ECC counters\n");195 196 regmap_read(aspeed_regmap, ASPEED_MCR_INTR_CTRL, ®50);197 dev_dbg(mci->pdev, "edac interrupt handled. mcr reg 50 is now: 0x%x\n",198 reg50);199 200 return IRQ_HANDLED;201}202 203 204static int config_irq(void *ctx, struct platform_device *pdev)205{206 int irq;207 int rc;208 209 /* register interrupt handler */210 irq = platform_get_irq(pdev, 0);211 dev_dbg(&pdev->dev, "got irq %d\n", irq);212 if (irq < 0)213 return irq;214 215 rc = devm_request_irq(&pdev->dev, irq, mcr_isr, IRQF_TRIGGER_HIGH,216 DRV_NAME, ctx);217 if (rc) {218 dev_err(&pdev->dev, "unable to request irq %d\n", irq);219 return rc;220 }221 222 /* enable interrupts */223 regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL,224 ASPEED_MCR_INTR_CTRL_ENABLE,225 ASPEED_MCR_INTR_CTRL_ENABLE);226 227 return 0;228}229 230 231static int init_csrows(struct mem_ctl_info *mci)232{233 struct csrow_info *csrow = mci->csrows[0];234 u32 nr_pages, dram_type;235 struct dimm_info *dimm;236 struct device_node *np;237 struct resource r;238 u32 reg04;239 int rc;240 241 /* retrieve info about physical memory from device tree */242 np = of_find_node_by_name(NULL, "memory");243 if (!np) {244 dev_err(mci->pdev, "dt: missing /memory node\n");245 return -ENODEV;246 }247 248 rc = of_address_to_resource(np, 0, &r);249 250 of_node_put(np);251 252 if (rc) {253 dev_err(mci->pdev, "dt: failed requesting resource for /memory node\n");254 return rc;255 }256 257 dev_dbg(mci->pdev, "dt: /memory node resources: first page %pR, PAGE_SHIFT macro=0x%x\n",258 &r, PAGE_SHIFT);259 260 csrow->first_page = r.start >> PAGE_SHIFT;261 nr_pages = resource_size(&r) >> PAGE_SHIFT;262 csrow->last_page = csrow->first_page + nr_pages - 1;263 264 regmap_read(aspeed_regmap, ASPEED_MCR_CONF, ®04);265 dram_type = (reg04 & ASPEED_MCR_CONF_DRAM_TYPE) ? MEM_DDR4 : MEM_DDR3;266 267 dimm = csrow->channels[0]->dimm;268 dimm->mtype = dram_type;269 dimm->edac_mode = EDAC_SECDED;270 dimm->nr_pages = nr_pages / csrow->nr_channels;271 272 dev_dbg(mci->pdev, "initialized dimm with first_page=0x%lx and nr_pages=0x%x\n",273 csrow->first_page, nr_pages);274 275 return 0;276}277 278 279static int aspeed_probe(struct platform_device *pdev)280{281 struct device *dev = &pdev->dev;282 struct edac_mc_layer layers[2];283 struct mem_ctl_info *mci;284 void __iomem *regs;285 u32 reg04;286 int rc;287 288 regs = devm_platform_ioremap_resource(pdev, 0);289 if (IS_ERR(regs))290 return PTR_ERR(regs);291 292 aspeed_regmap = devm_regmap_init(dev, NULL, (__force void *)regs,293 &aspeed_regmap_config);294 if (IS_ERR(aspeed_regmap))295 return PTR_ERR(aspeed_regmap);296 297 /* bail out if ECC mode is not configured */298 regmap_read(aspeed_regmap, ASPEED_MCR_CONF, ®04);299 if (!(reg04 & ASPEED_MCR_CONF_ECC)) {300 dev_err(&pdev->dev, "ECC mode is not configured in u-boot\n");301 return -EPERM;302 }303 304 edac_op_state = EDAC_OPSTATE_INT;305 306 /* allocate & init EDAC MC data structure */307 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;308 layers[0].size = 1;309 layers[0].is_virt_csrow = true;310 layers[1].type = EDAC_MC_LAYER_CHANNEL;311 layers[1].size = 1;312 layers[1].is_virt_csrow = false;313 314 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);315 if (!mci)316 return -ENOMEM;317 318 mci->pdev = &pdev->dev;319 mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4;320 mci->edac_ctl_cap = EDAC_FLAG_SECDED;321 mci->edac_cap = EDAC_FLAG_SECDED;322 mci->scrub_cap = SCRUB_FLAG_HW_SRC;323 mci->scrub_mode = SCRUB_HW_SRC;324 mci->mod_name = DRV_NAME;325 mci->ctl_name = "MIC";326 mci->dev_name = dev_name(&pdev->dev);327 328 rc = init_csrows(mci);329 if (rc) {330 dev_err(&pdev->dev, "failed to init csrows\n");331 goto probe_exit02;332 }333 334 platform_set_drvdata(pdev, mci);335 336 /* register with edac core */337 rc = edac_mc_add_mc(mci);338 if (rc) {339 dev_err(&pdev->dev, "failed to register with EDAC core\n");340 goto probe_exit02;341 }342 343 /* register interrupt handler and enable interrupts */344 rc = config_irq(mci, pdev);345 if (rc) {346 dev_err(&pdev->dev, "failed setting up irq\n");347 goto probe_exit01;348 }349 350 return 0;351 352probe_exit01:353 edac_mc_del_mc(&pdev->dev);354probe_exit02:355 edac_mc_free(mci);356 return rc;357}358 359 360static void aspeed_remove(struct platform_device *pdev)361{362 struct mem_ctl_info *mci;363 364 /* disable interrupts */365 regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL,366 ASPEED_MCR_INTR_CTRL_ENABLE, 0);367 368 /* free resources */369 mci = edac_mc_del_mc(&pdev->dev);370 if (mci)371 edac_mc_free(mci);372}373 374 375static const struct of_device_id aspeed_of_match[] = {376 { .compatible = "aspeed,ast2400-sdram-edac" },377 { .compatible = "aspeed,ast2500-sdram-edac" },378 { .compatible = "aspeed,ast2600-sdram-edac" },379 {},380};381 382MODULE_DEVICE_TABLE(of, aspeed_of_match);383 384static struct platform_driver aspeed_driver = {385 .driver = {386 .name = DRV_NAME,387 .of_match_table = aspeed_of_match388 },389 .probe = aspeed_probe,390 .remove_new = aspeed_remove391};392module_platform_driver(aspeed_driver);393 394MODULE_LICENSE("GPL");395MODULE_AUTHOR("Stefan Schaeckeler <sschaeck@cisco.com>");396MODULE_DESCRIPTION("Aspeed BMC SoC EDAC driver");397MODULE_VERSION("1.0");398