brintos

brintos / linux-shallow public Read only

0
0
Text · 14.7 KiB · 2e2133b Raw
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