linux/drivers/edac/aspeed_edac.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2018, 2019 Cisco Systems
   4 */
   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_REC
  27
  28
  29#define ASPEED_MCR_PROT_PASSWD              0xfc600309
  30#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, &reg50);
 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, &reg58);
 176        un_rec_addr = reg58;
 177
 178        regmap_read(aspeed_regmap, ASPEED_MCR_ADDR_REC, &reg5c);
 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, &reg50);
 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, &reg04);
 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, &reg04);
 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 int 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        return 0;
 374}
 375
 376
 377static const struct of_device_id aspeed_of_match[] = {
 378        { .compatible = "aspeed,ast2400-sdram-edac" },
 379        { .compatible = "aspeed,ast2500-sdram-edac" },
 380        { .compatible = "aspeed,ast2600-sdram-edac" },
 381        {},
 382};
 383
 384MODULE_DEVICE_TABLE(of, aspeed_of_match);
 385
 386static struct platform_driver aspeed_driver = {
 387        .driver         = {
 388                .name   = DRV_NAME,
 389                .of_match_table = aspeed_of_match
 390        },
 391        .probe          = aspeed_probe,
 392        .remove         = aspeed_remove
 393};
 394module_platform_driver(aspeed_driver);
 395
 396MODULE_LICENSE("GPL");
 397MODULE_AUTHOR("Stefan Schaeckeler <sschaeck@cisco.com>");
 398MODULE_DESCRIPTION("Aspeed BMC SoC EDAC driver");
 399MODULE_VERSION("1.0");
 400