1895ae5beSAppana Durga Kedareswara rao // SPDX-License-Identifier: GPL-2.0
2895ae5beSAppana Durga Kedareswara rao /*
3895ae5beSAppana Durga Kedareswara rao * Driver for Xilinx TMR Inject IP.
4895ae5beSAppana Durga Kedareswara rao *
5895ae5beSAppana Durga Kedareswara rao * Copyright (C) 2022 Advanced Micro Devices, Inc.
6895ae5beSAppana Durga Kedareswara rao *
7895ae5beSAppana Durga Kedareswara rao * Description:
8895ae5beSAppana Durga Kedareswara rao * This driver is developed for TMR Inject IP,The Triple Modular Redundancy(TMR)
9895ae5beSAppana Durga Kedareswara rao * Inject provides fault injection.
10895ae5beSAppana Durga Kedareswara rao */
11895ae5beSAppana Durga Kedareswara rao
12895ae5beSAppana Durga Kedareswara rao #include <asm/xilinx_mb_manager.h>
13895ae5beSAppana Durga Kedareswara rao #include <linux/module.h>
14*d9c58aebSRob Herring #include <linux/of.h>
15*d9c58aebSRob Herring #include <linux/platform_device.h>
16895ae5beSAppana Durga Kedareswara rao #include <linux/fault-inject.h>
17895ae5beSAppana Durga Kedareswara rao
18895ae5beSAppana Durga Kedareswara rao /* TMR Inject Register offsets */
19895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_CR_OFFSET 0x0
20895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_AIR_OFFSET 0x4
21895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_IIR_OFFSET 0xC
22895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_EAIR_OFFSET 0x10
23895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_ERR_OFFSET 0x204
24895ae5beSAppana Durga Kedareswara rao
25895ae5beSAppana Durga Kedareswara rao /* Register Bitmasks/shifts */
26895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_CR_CPUID_SHIFT 8
27895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_CR_IE_SHIFT 10
28895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_IIR_ADDR_MASK GENMASK(31, 16)
29895ae5beSAppana Durga Kedareswara rao
30895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_MAGIC_MAX_VAL 255
31895ae5beSAppana Durga Kedareswara rao
32895ae5beSAppana Durga Kedareswara rao /**
33895ae5beSAppana Durga Kedareswara rao * struct xtmr_inject_dev - Driver data for TMR Inject
34895ae5beSAppana Durga Kedareswara rao * @regs: device physical base address
35895ae5beSAppana Durga Kedareswara rao * @magic: Magic hardware configuration value
36895ae5beSAppana Durga Kedareswara rao */
37895ae5beSAppana Durga Kedareswara rao struct xtmr_inject_dev {
38895ae5beSAppana Durga Kedareswara rao void __iomem *regs;
39895ae5beSAppana Durga Kedareswara rao u32 magic;
40895ae5beSAppana Durga Kedareswara rao };
41895ae5beSAppana Durga Kedareswara rao
42895ae5beSAppana Durga Kedareswara rao static DECLARE_FAULT_ATTR(inject_fault);
43895ae5beSAppana Durga Kedareswara rao static char *inject_request;
44895ae5beSAppana Durga Kedareswara rao module_param(inject_request, charp, 0);
45895ae5beSAppana Durga Kedareswara rao MODULE_PARM_DESC(inject_request, "default fault injection attributes");
46895ae5beSAppana Durga Kedareswara rao static struct dentry *dbgfs_root;
47895ae5beSAppana Durga Kedareswara rao
48895ae5beSAppana Durga Kedareswara rao /* IO accessors */
xtmr_inject_write(struct xtmr_inject_dev * xtmr_inject,u32 addr,u32 value)49895ae5beSAppana Durga Kedareswara rao static inline void xtmr_inject_write(struct xtmr_inject_dev *xtmr_inject,
50895ae5beSAppana Durga Kedareswara rao u32 addr, u32 value)
51895ae5beSAppana Durga Kedareswara rao {
52895ae5beSAppana Durga Kedareswara rao iowrite32(value, xtmr_inject->regs + addr);
53895ae5beSAppana Durga Kedareswara rao }
54895ae5beSAppana Durga Kedareswara rao
xtmr_inject_read(struct xtmr_inject_dev * xtmr_inject,u32 addr)55895ae5beSAppana Durga Kedareswara rao static inline u32 xtmr_inject_read(struct xtmr_inject_dev *xtmr_inject,
56895ae5beSAppana Durga Kedareswara rao u32 addr)
57895ae5beSAppana Durga Kedareswara rao {
58895ae5beSAppana Durga Kedareswara rao return ioread32(xtmr_inject->regs + addr);
59895ae5beSAppana Durga Kedareswara rao }
60895ae5beSAppana Durga Kedareswara rao
xtmr_inject_set(void * data,u64 val)61895ae5beSAppana Durga Kedareswara rao static int xtmr_inject_set(void *data, u64 val)
62895ae5beSAppana Durga Kedareswara rao {
63895ae5beSAppana Durga Kedareswara rao if (val != 1)
64895ae5beSAppana Durga Kedareswara rao return -EINVAL;
65895ae5beSAppana Durga Kedareswara rao
66895ae5beSAppana Durga Kedareswara rao xmb_inject_err();
67895ae5beSAppana Durga Kedareswara rao return 0;
68895ae5beSAppana Durga Kedareswara rao }
69895ae5beSAppana Durga Kedareswara rao DEFINE_DEBUGFS_ATTRIBUTE(xtmr_inject_fops, NULL, xtmr_inject_set, "%llu\n");
70895ae5beSAppana Durga Kedareswara rao
xtmr_init_debugfs(struct xtmr_inject_dev * xtmr_inject)71895ae5beSAppana Durga Kedareswara rao static void xtmr_init_debugfs(struct xtmr_inject_dev *xtmr_inject)
72895ae5beSAppana Durga Kedareswara rao {
73895ae5beSAppana Durga Kedareswara rao struct dentry *dir;
74895ae5beSAppana Durga Kedareswara rao
75895ae5beSAppana Durga Kedareswara rao dbgfs_root = debugfs_create_dir("xtmr_inject", NULL);
76895ae5beSAppana Durga Kedareswara rao dir = fault_create_debugfs_attr("inject_fault", dbgfs_root,
77895ae5beSAppana Durga Kedareswara rao &inject_fault);
78895ae5beSAppana Durga Kedareswara rao debugfs_create_file("inject_fault", 0200, dir, NULL,
79895ae5beSAppana Durga Kedareswara rao &xtmr_inject_fops);
80895ae5beSAppana Durga Kedareswara rao }
81895ae5beSAppana Durga Kedareswara rao
xtmr_inject_init(struct xtmr_inject_dev * xtmr_inject)82895ae5beSAppana Durga Kedareswara rao static void xtmr_inject_init(struct xtmr_inject_dev *xtmr_inject)
83895ae5beSAppana Durga Kedareswara rao {
84895ae5beSAppana Durga Kedareswara rao u32 cr_val;
85895ae5beSAppana Durga Kedareswara rao
86895ae5beSAppana Durga Kedareswara rao if (inject_request)
87895ae5beSAppana Durga Kedareswara rao setup_fault_attr(&inject_fault, inject_request);
88895ae5beSAppana Durga Kedareswara rao /* Allow fault injection */
89895ae5beSAppana Durga Kedareswara rao cr_val = xtmr_inject->magic |
90895ae5beSAppana Durga Kedareswara rao (1 << XTMR_INJECT_CR_IE_SHIFT) |
91895ae5beSAppana Durga Kedareswara rao (1 << XTMR_INJECT_CR_CPUID_SHIFT);
92895ae5beSAppana Durga Kedareswara rao xtmr_inject_write(xtmr_inject, XTMR_INJECT_CR_OFFSET,
93895ae5beSAppana Durga Kedareswara rao cr_val);
94895ae5beSAppana Durga Kedareswara rao /* Initialize the address inject and instruction inject registers */
95895ae5beSAppana Durga Kedareswara rao xtmr_inject_write(xtmr_inject, XTMR_INJECT_AIR_OFFSET,
96895ae5beSAppana Durga Kedareswara rao XMB_INJECT_ERR_OFFSET);
97895ae5beSAppana Durga Kedareswara rao xtmr_inject_write(xtmr_inject, XTMR_INJECT_IIR_OFFSET,
98895ae5beSAppana Durga Kedareswara rao XMB_INJECT_ERR_OFFSET & XTMR_INJECT_IIR_ADDR_MASK);
99895ae5beSAppana Durga Kedareswara rao }
100895ae5beSAppana Durga Kedareswara rao
101895ae5beSAppana Durga Kedareswara rao /**
102895ae5beSAppana Durga Kedareswara rao * xtmr_inject_probe - Driver probe function
103895ae5beSAppana Durga Kedareswara rao * @pdev: Pointer to the platform_device structure
104895ae5beSAppana Durga Kedareswara rao *
105895ae5beSAppana Durga Kedareswara rao * This is the driver probe routine. It does all the memory
106895ae5beSAppana Durga Kedareswara rao * allocation for the device.
107895ae5beSAppana Durga Kedareswara rao *
108895ae5beSAppana Durga Kedareswara rao * Return: 0 on success and failure value on error
109895ae5beSAppana Durga Kedareswara rao */
xtmr_inject_probe(struct platform_device * pdev)110895ae5beSAppana Durga Kedareswara rao static int xtmr_inject_probe(struct platform_device *pdev)
111895ae5beSAppana Durga Kedareswara rao {
112895ae5beSAppana Durga Kedareswara rao struct xtmr_inject_dev *xtmr_inject;
113895ae5beSAppana Durga Kedareswara rao int err;
114895ae5beSAppana Durga Kedareswara rao
115895ae5beSAppana Durga Kedareswara rao xtmr_inject = devm_kzalloc(&pdev->dev, sizeof(*xtmr_inject),
116895ae5beSAppana Durga Kedareswara rao GFP_KERNEL);
117895ae5beSAppana Durga Kedareswara rao if (!xtmr_inject)
118895ae5beSAppana Durga Kedareswara rao return -ENOMEM;
119895ae5beSAppana Durga Kedareswara rao
120895ae5beSAppana Durga Kedareswara rao xtmr_inject->regs = devm_platform_ioremap_resource(pdev, 0);
121895ae5beSAppana Durga Kedareswara rao if (IS_ERR(xtmr_inject->regs))
122895ae5beSAppana Durga Kedareswara rao return PTR_ERR(xtmr_inject->regs);
123895ae5beSAppana Durga Kedareswara rao
124895ae5beSAppana Durga Kedareswara rao err = of_property_read_u32(pdev->dev.of_node, "xlnx,magic",
125895ae5beSAppana Durga Kedareswara rao &xtmr_inject->magic);
126895ae5beSAppana Durga Kedareswara rao if (err < 0) {
127895ae5beSAppana Durga Kedareswara rao dev_err(&pdev->dev, "unable to read xlnx,magic property");
128895ae5beSAppana Durga Kedareswara rao return err;
129895ae5beSAppana Durga Kedareswara rao }
130895ae5beSAppana Durga Kedareswara rao
131895ae5beSAppana Durga Kedareswara rao if (xtmr_inject->magic > XTMR_INJECT_MAGIC_MAX_VAL) {
132895ae5beSAppana Durga Kedareswara rao dev_err(&pdev->dev, "invalid xlnx,magic property value");
133895ae5beSAppana Durga Kedareswara rao return -EINVAL;
134895ae5beSAppana Durga Kedareswara rao }
135895ae5beSAppana Durga Kedareswara rao
136895ae5beSAppana Durga Kedareswara rao /* Initialize TMR Inject */
137895ae5beSAppana Durga Kedareswara rao xtmr_inject_init(xtmr_inject);
138895ae5beSAppana Durga Kedareswara rao
139895ae5beSAppana Durga Kedareswara rao xtmr_init_debugfs(xtmr_inject);
140895ae5beSAppana Durga Kedareswara rao
141895ae5beSAppana Durga Kedareswara rao platform_set_drvdata(pdev, xtmr_inject);
142895ae5beSAppana Durga Kedareswara rao
143895ae5beSAppana Durga Kedareswara rao return 0;
144895ae5beSAppana Durga Kedareswara rao }
145895ae5beSAppana Durga Kedareswara rao
xtmr_inject_remove(struct platform_device * pdev)146895ae5beSAppana Durga Kedareswara rao static int xtmr_inject_remove(struct platform_device *pdev)
147895ae5beSAppana Durga Kedareswara rao {
148895ae5beSAppana Durga Kedareswara rao debugfs_remove_recursive(dbgfs_root);
149895ae5beSAppana Durga Kedareswara rao dbgfs_root = NULL;
150895ae5beSAppana Durga Kedareswara rao return 0;
151895ae5beSAppana Durga Kedareswara rao }
152895ae5beSAppana Durga Kedareswara rao
153895ae5beSAppana Durga Kedareswara rao static const struct of_device_id xtmr_inject_of_match[] = {
154895ae5beSAppana Durga Kedareswara rao {
155895ae5beSAppana Durga Kedareswara rao .compatible = "xlnx,tmr-inject-1.0",
156895ae5beSAppana Durga Kedareswara rao },
157895ae5beSAppana Durga Kedareswara rao { /* end of table */ }
158895ae5beSAppana Durga Kedareswara rao };
159895ae5beSAppana Durga Kedareswara rao MODULE_DEVICE_TABLE(of, xtmr_inject_of_match);
160895ae5beSAppana Durga Kedareswara rao
161895ae5beSAppana Durga Kedareswara rao static struct platform_driver xtmr_inject_driver = {
162895ae5beSAppana Durga Kedareswara rao .driver = {
163895ae5beSAppana Durga Kedareswara rao .name = "xilinx-tmr_inject",
164895ae5beSAppana Durga Kedareswara rao .of_match_table = xtmr_inject_of_match,
165895ae5beSAppana Durga Kedareswara rao },
166895ae5beSAppana Durga Kedareswara rao .probe = xtmr_inject_probe,
167895ae5beSAppana Durga Kedareswara rao .remove = xtmr_inject_remove,
168895ae5beSAppana Durga Kedareswara rao };
169895ae5beSAppana Durga Kedareswara rao module_platform_driver(xtmr_inject_driver);
170895ae5beSAppana Durga Kedareswara rao MODULE_AUTHOR("Advanced Micro Devices, Inc");
171895ae5beSAppana Durga Kedareswara rao MODULE_DESCRIPTION("Xilinx TMR Inject Driver");
172895ae5beSAppana Durga Kedareswara rao MODULE_LICENSE("GPL");
173