1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Xilinx ZynqMP OCM ECC Driver
4 *
5 * Copyright (C) 2022 Advanced Micro Devices, Inc.
6 */
7
8#include <linux/edac.h>
9#include <linux/interrupt.h>
10#include <linux/module.h>
11#include <linux/of.h>
12#include <linux/of_platform.h>
13#include <linux/platform_device.h>
14
15#include "edac_module.h"
16
17#define ZYNQMP_OCM_EDAC_MSG_SIZE	256
18
19#define ZYNQMP_OCM_EDAC_STRING	"zynqmp_ocm"
20
21/* Error/Interrupt registers */
22#define ERR_CTRL_OFST		0x0
23#define OCM_ISR_OFST		0x04
24#define OCM_IMR_OFST		0x08
25#define OCM_IEN_OFST		0x0C
26#define OCM_IDS_OFST		0x10
27
28/* ECC control register */
29#define ECC_CTRL_OFST		0x14
30
31/* Correctable error info registers */
32#define CE_FFA_OFST		0x1C
33#define CE_FFD0_OFST		0x20
34#define CE_FFD1_OFST		0x24
35#define CE_FFD2_OFST		0x28
36#define CE_FFD3_OFST		0x2C
37#define CE_FFE_OFST		0x30
38
39/* Uncorrectable error info registers */
40#define UE_FFA_OFST		0x34
41#define UE_FFD0_OFST		0x38
42#define UE_FFD1_OFST		0x3C
43#define UE_FFD2_OFST		0x40
44#define UE_FFD3_OFST		0x44
45#define UE_FFE_OFST		0x48
46
47/* ECC control register bit field definitions */
48#define ECC_CTRL_CLR_CE_ERR	0x40
49#define ECC_CTRL_CLR_UE_ERR	0x80
50
51/* Fault injection data and count registers */
52#define OCM_FID0_OFST		0x4C
53#define OCM_FID1_OFST		0x50
54#define OCM_FID2_OFST		0x54
55#define OCM_FID3_OFST		0x58
56#define OCM_FIC_OFST		0x74
57
58#define UE_MAX_BITPOS_LOWER	31
59#define UE_MIN_BITPOS_UPPER	32
60#define UE_MAX_BITPOS_UPPER	63
61
62/* Interrupt masks */
63#define OCM_CEINTR_MASK		BIT(6)
64#define OCM_UEINTR_MASK		BIT(7)
65#define OCM_ECC_ENABLE_MASK	BIT(0)
66
67#define OCM_FICOUNT_MASK	GENMASK(23, 0)
68#define OCM_NUM_UE_BITPOS	2
69#define OCM_BASEVAL		0xFFFC0000
70#define EDAC_DEVICE		"ZynqMP-OCM"
71
72/**
73 * struct ecc_error_info - ECC error log information
74 * @addr:	Fault generated at this address
75 * @fault_lo:	Generated fault data (lower 32-bit)
76 * @fault_hi:	Generated fault data (upper 32-bit)
77 */
78struct ecc_error_info {
79	u32 addr;
80	u32 fault_lo;
81	u32 fault_hi;
82};
83
84/**
85 * struct ecc_status - ECC status information to report
86 * @ce_cnt:	Correctable error count
87 * @ue_cnt:	Uncorrectable error count
88 * @ceinfo:	Correctable error log information
89 * @ueinfo:	Uncorrectable error log information
90 */
91struct ecc_status {
92	u32 ce_cnt;
93	u32 ue_cnt;
94	struct ecc_error_info ceinfo;
95	struct ecc_error_info ueinfo;
96};
97
98/**
99 * struct edac_priv - OCM private instance data
100 * @baseaddr:	Base address of the OCM
101 * @message:	Buffer for framing the event specific info
102 * @stat:	ECC status information
103 * @ce_cnt:	Correctable Error count
104 * @ue_cnt:	Uncorrectable Error count
105 * @debugfs_dir:	Directory entry for debugfs
106 * @ce_bitpos:	Bit position for Correctable Error
107 * @ue_bitpos:	Array to store UnCorrectable Error bit positions
108 * @fault_injection_cnt: Fault Injection Counter value
109 */
110struct edac_priv {
111	void __iomem *baseaddr;
112	char message[ZYNQMP_OCM_EDAC_MSG_SIZE];
113	struct ecc_status stat;
114	u32 ce_cnt;
115	u32 ue_cnt;
116#ifdef CONFIG_EDAC_DEBUG
117	struct dentry *debugfs_dir;
118	u8 ce_bitpos;
119	u8 ue_bitpos[OCM_NUM_UE_BITPOS];
120	u32 fault_injection_cnt;
121#endif
122};
123
124/**
125 * get_error_info - Get the current ECC error info
126 * @base:	Pointer to the base address of the OCM
127 * @p:		Pointer to the OCM ECC status structure
128 * @mask:	Status register mask value
129 *
130 * Determines there is any ECC error or not
131 *
132 */
133static void get_error_info(void __iomem *base, struct ecc_status *p, int mask)
134{
135	if (mask & OCM_CEINTR_MASK) {
136		p->ce_cnt++;
137		p->ceinfo.fault_lo = readl(base + CE_FFD0_OFST);
138		p->ceinfo.fault_hi = readl(base + CE_FFD1_OFST);
139		p->ceinfo.addr = (OCM_BASEVAL | readl(base + CE_FFA_OFST));
140		writel(ECC_CTRL_CLR_CE_ERR, base + OCM_ISR_OFST);
141	} else if (mask & OCM_UEINTR_MASK) {
142		p->ue_cnt++;
143		p->ueinfo.fault_lo = readl(base + UE_FFD0_OFST);
144		p->ueinfo.fault_hi = readl(base + UE_FFD1_OFST);
145		p->ueinfo.addr = (OCM_BASEVAL | readl(base + UE_FFA_OFST));
146		writel(ECC_CTRL_CLR_UE_ERR, base + OCM_ISR_OFST);
147	}
148}
149
150/**
151 * handle_error - Handle error types CE and UE
152 * @dci:	Pointer to the EDAC device instance
153 * @p:		Pointer to the OCM ECC status structure
154 *
155 * Handles correctable and uncorrectable errors.
156 */
157static void handle_error(struct edac_device_ctl_info *dci, struct ecc_status *p)
158{
159	struct edac_priv *priv = dci->pvt_info;
160	struct ecc_error_info *pinf;
161
162	if (p->ce_cnt) {
163		pinf = &p->ceinfo;
164		snprintf(priv->message, ZYNQMP_OCM_EDAC_MSG_SIZE,
165			 "\nOCM ECC error type :%s\nAddr: [0x%x]\nFault Data[0x%08x%08x]",
166			 "CE", pinf->addr, pinf->fault_hi, pinf->fault_lo);
167		edac_device_handle_ce(dci, 0, 0, priv->message);
168	}
169
170	if (p->ue_cnt) {
171		pinf = &p->ueinfo;
172		snprintf(priv->message, ZYNQMP_OCM_EDAC_MSG_SIZE,
173			 "\nOCM ECC error type :%s\nAddr: [0x%x]\nFault Data[0x%08x%08x]",
174			 "UE", pinf->addr, pinf->fault_hi, pinf->fault_lo);
175		edac_device_handle_ue(dci, 0, 0, priv->message);
176	}
177
178	memset(p, 0, sizeof(*p));
179}
180
181/**
182 * intr_handler - ISR routine
183 * @irq:        irq number
184 * @dev_id:     device id pointer
185 *
186 * Return: IRQ_NONE, if CE/UE interrupt not set or IRQ_HANDLED otherwise
187 */
188static irqreturn_t intr_handler(int irq, void *dev_id)
189{
190	struct edac_device_ctl_info *dci = dev_id;
191	struct edac_priv *priv = dci->pvt_info;
192	int regval;
193
194	regval = readl(priv->baseaddr + OCM_ISR_OFST);
195	if (!(regval & (OCM_CEINTR_MASK | OCM_UEINTR_MASK))) {
196		WARN_ONCE(1, "Unhandled IRQ%d, ISR: 0x%x", irq, regval);
197		return IRQ_NONE;
198	}
199
200	get_error_info(priv->baseaddr, &priv->stat, regval);
201
202	priv->ce_cnt += priv->stat.ce_cnt;
203	priv->ue_cnt += priv->stat.ue_cnt;
204	handle_error(dci, &priv->stat);
205
206	return IRQ_HANDLED;
207}
208
209/**
210 * get_eccstate - Return the ECC status
211 * @base:	Pointer to the OCM base address
212 *
213 * Get the ECC enable/disable status
214 *
215 * Return: ECC status 0/1.
216 */
217static bool get_eccstate(void __iomem *base)
218{
219	return readl(base + ECC_CTRL_OFST) & OCM_ECC_ENABLE_MASK;
220}
221
222#ifdef CONFIG_EDAC_DEBUG
223/**
224 * write_fault_count - write fault injection count
225 * @priv:	Pointer to the EDAC private struct
226 *
227 * Update the fault injection count register, once the counter reaches
228 * zero, it injects errors
229 */
230static void write_fault_count(struct edac_priv *priv)
231{
232	u32 ficount = priv->fault_injection_cnt;
233
234	if (ficount & ~OCM_FICOUNT_MASK) {
235		ficount &= OCM_FICOUNT_MASK;
236		edac_printk(KERN_INFO, EDAC_DEVICE,
237			    "Fault injection count value truncated to %d\n", ficount);
238	}
239
240	writel(ficount, priv->baseaddr + OCM_FIC_OFST);
241}
242
243/*
244 * To get the Correctable Error injected, the following steps are needed:
245 * - Setup the optional Fault Injection Count:
246 *	echo <fault_count val> > /sys/kernel/debug/edac/ocm/inject_fault_count
247 * - Write the Correctable Error bit position value:
248 *	echo <bit_pos val> > /sys/kernel/debug/edac/ocm/inject_ce_bitpos
249 */
250static ssize_t inject_ce_write(struct file *file, const char __user *data,
251			       size_t count, loff_t *ppos)
252{
253	struct edac_device_ctl_info *edac_dev = file->private_data;
254	struct edac_priv *priv = edac_dev->pvt_info;
255	int ret;
256
257	if (!data)
258		return -EFAULT;
259
260	ret = kstrtou8_from_user(data, count, 0, &priv->ce_bitpos);
261	if (ret)
262		return ret;
263
264	if (priv->ce_bitpos > UE_MAX_BITPOS_UPPER)
265		return -EINVAL;
266
267	if (priv->ce_bitpos <= UE_MAX_BITPOS_LOWER) {
268		writel(BIT(priv->ce_bitpos), priv->baseaddr + OCM_FID0_OFST);
269		writel(0, priv->baseaddr + OCM_FID1_OFST);
270	} else {
271		writel(BIT(priv->ce_bitpos - UE_MIN_BITPOS_UPPER),
272		       priv->baseaddr + OCM_FID1_OFST);
273		writel(0, priv->baseaddr + OCM_FID0_OFST);
274	}
275
276	write_fault_count(priv);
277
278	return count;
279}
280
281static const struct file_operations inject_ce_fops = {
282	.open = simple_open,
283	.write = inject_ce_write,
284	.llseek = generic_file_llseek,
285};
286
287/*
288 * To get the Uncorrectable Error injected, the following steps are needed:
289 * - Setup the optional Fault Injection Count:
290 *      echo <fault_count val> > /sys/kernel/debug/edac/ocm/inject_fault_count
291 * - Write the Uncorrectable Error bit position values:
292 *      echo <bit_pos0 val>,<bit_pos1 val> > /sys/kernel/debug/edac/ocm/inject_ue_bitpos
293 */
294static ssize_t inject_ue_write(struct file *file, const char __user *data,
295			       size_t count, loff_t *ppos)
296{
297	struct edac_device_ctl_info *edac_dev = file->private_data;
298	struct edac_priv *priv = edac_dev->pvt_info;
299	char buf[6], *pbuf, *token[2];
300	u64 ue_bitpos;
301	int i, ret;
302	u8 len;
303
304	if (!data)
305		return -EFAULT;
306
307	len = min_t(size_t, count, sizeof(buf));
308	if (copy_from_user(buf, data, len))
309		return -EFAULT;
310
311	buf[len] = '\0';
312	pbuf = &buf[0];
313	for (i = 0; i < OCM_NUM_UE_BITPOS; i++)
314		token[i] = strsep(&pbuf, ",");
315
316	ret = kstrtou8(token[0], 0, &priv->ue_bitpos[0]);
317	if (ret)
318		return ret;
319
320	ret = kstrtou8(token[1], 0, &priv->ue_bitpos[1]);
321	if (ret)
322		return ret;
323
324	if (priv->ue_bitpos[0] > UE_MAX_BITPOS_UPPER ||
325	    priv->ue_bitpos[1] > UE_MAX_BITPOS_UPPER)
326		return -EINVAL;
327
328	if (priv->ue_bitpos[0] == priv->ue_bitpos[1]) {
329		edac_printk(KERN_ERR, EDAC_DEVICE, "Bit positions should not be equal\n");
330		return -EINVAL;
331	}
332
333	ue_bitpos = BIT(priv->ue_bitpos[0]) | BIT(priv->ue_bitpos[1]);
334
335	writel((u32)ue_bitpos, priv->baseaddr + OCM_FID0_OFST);
336	writel((u32)(ue_bitpos >> 32), priv->baseaddr + OCM_FID1_OFST);
337
338	write_fault_count(priv);
339
340	return count;
341}
342
343static const struct file_operations inject_ue_fops = {
344	.open = simple_open,
345	.write = inject_ue_write,
346	.llseek = generic_file_llseek,
347};
348
349static void setup_debugfs(struct edac_device_ctl_info *edac_dev)
350{
351	struct edac_priv *priv = edac_dev->pvt_info;
352
353	priv->debugfs_dir = edac_debugfs_create_dir("ocm");
354	if (!priv->debugfs_dir)
355		return;
356
357	edac_debugfs_create_x32("inject_fault_count", 0644, priv->debugfs_dir,
358				&priv->fault_injection_cnt);
359	edac_debugfs_create_file("inject_ue_bitpos", 0644, priv->debugfs_dir,
360				 edac_dev, &inject_ue_fops);
361	edac_debugfs_create_file("inject_ce_bitpos", 0644, priv->debugfs_dir,
362				 edac_dev, &inject_ce_fops);
363}
364#endif
365
366static int edac_probe(struct platform_device *pdev)
367{
368	struct edac_device_ctl_info *dci;
369	struct edac_priv *priv;
370	void __iomem *baseaddr;
371	struct resource *res;
372	int irq, ret;
373
374	baseaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
375	if (IS_ERR(baseaddr))
376		return PTR_ERR(baseaddr);
377
378	if (!get_eccstate(baseaddr)) {
379		edac_printk(KERN_INFO, EDAC_DEVICE, "ECC not enabled\n");
380		return -ENXIO;
381	}
382
383	dci = edac_device_alloc_ctl_info(sizeof(*priv), ZYNQMP_OCM_EDAC_STRING,
384					 1, ZYNQMP_OCM_EDAC_STRING, 1, 0,
385					 edac_device_alloc_index());
386	if (!dci)
387		return -ENOMEM;
388
389	priv = dci->pvt_info;
390	platform_set_drvdata(pdev, dci);
391	dci->dev = &pdev->dev;
392	priv->baseaddr = baseaddr;
393	dci->mod_name = pdev->dev.driver->name;
394	dci->ctl_name = ZYNQMP_OCM_EDAC_STRING;
395	dci->dev_name = dev_name(&pdev->dev);
396
397	irq = platform_get_irq(pdev, 0);
398	if (irq < 0) {
399		ret = irq;
400		goto free_dev_ctl;
401	}
402
403	ret = devm_request_irq(&pdev->dev, irq, intr_handler, 0,
404			       dev_name(&pdev->dev), dci);
405	if (ret) {
406		edac_printk(KERN_ERR, EDAC_DEVICE, "Failed to request Irq\n");
407		goto free_dev_ctl;
408	}
409
410	/* Enable UE, CE interrupts */
411	writel((OCM_CEINTR_MASK | OCM_UEINTR_MASK), priv->baseaddr + OCM_IEN_OFST);
412
413#ifdef CONFIG_EDAC_DEBUG
414	setup_debugfs(dci);
415#endif
416
417	ret = edac_device_add_device(dci);
418	if (ret)
419		goto free_dev_ctl;
420
421	return 0;
422
423free_dev_ctl:
424	edac_device_free_ctl_info(dci);
425
426	return ret;
427}
428
429static void edac_remove(struct platform_device *pdev)
430{
431	struct edac_device_ctl_info *dci = platform_get_drvdata(pdev);
432	struct edac_priv *priv = dci->pvt_info;
433
434	/* Disable UE, CE interrupts */
435	writel((OCM_CEINTR_MASK | OCM_UEINTR_MASK), priv->baseaddr + OCM_IDS_OFST);
436
437#ifdef CONFIG_EDAC_DEBUG
438	debugfs_remove_recursive(priv->debugfs_dir);
439#endif
440
441	edac_device_del_device(&pdev->dev);
442	edac_device_free_ctl_info(dci);
443}
444
445static const struct of_device_id zynqmp_ocm_edac_match[] = {
446	{ .compatible = "xlnx,zynqmp-ocmc-1.0"},
447	{ /* end of table */ }
448};
449
450MODULE_DEVICE_TABLE(of, zynqmp_ocm_edac_match);
451
452static struct platform_driver zynqmp_ocm_edac_driver = {
453	.driver = {
454		   .name = "zynqmp-ocm-edac",
455		   .of_match_table = zynqmp_ocm_edac_match,
456		   },
457	.probe = edac_probe,
458	.remove_new = edac_remove,
459};
460
461module_platform_driver(zynqmp_ocm_edac_driver);
462
463MODULE_AUTHOR("Advanced Micro Devices, Inc");
464MODULE_DESCRIPTION("Xilinx ZynqMP OCM ECC driver");
465MODULE_LICENSE("GPL");
466