brintos

brintos / linux-shallow public Read only

0
0
Text · 9.9 KiB · 157a480 Raw
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, &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 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