xref: /linux/drivers/edac/versalnet_edac.c (revision 03f76ddff5b04a808ae16c06418460151e2fdd4b)
1d5fe2fecSShubhrajyoti Datta // SPDX-License-Identifier: GPL-2.0
2d5fe2fecSShubhrajyoti Datta /*
3d5fe2fecSShubhrajyoti Datta  * AMD Versal NET memory controller driver
4d5fe2fecSShubhrajyoti Datta  * Copyright (C) 2025 Advanced Micro Devices, Inc.
5d5fe2fecSShubhrajyoti Datta  */
6d5fe2fecSShubhrajyoti Datta 
7d5fe2fecSShubhrajyoti Datta #include <linux/cdx/edac_cdx_pcol.h>
8d5fe2fecSShubhrajyoti Datta #include <linux/edac.h>
9d5fe2fecSShubhrajyoti Datta #include <linux/module.h>
10d5fe2fecSShubhrajyoti Datta #include <linux/of_device.h>
11d5fe2fecSShubhrajyoti Datta #include <linux/ras.h>
12d5fe2fecSShubhrajyoti Datta #include <linux/remoteproc.h>
13d5fe2fecSShubhrajyoti Datta #include <linux/rpmsg.h>
14d5fe2fecSShubhrajyoti Datta #include <linux/sizes.h>
15d5fe2fecSShubhrajyoti Datta #include <ras/ras_event.h>
16d5fe2fecSShubhrajyoti Datta 
17d5fe2fecSShubhrajyoti Datta #include "edac_module.h"
18d5fe2fecSShubhrajyoti Datta 
19d5fe2fecSShubhrajyoti Datta /* Granularity of reported error in bytes */
20d5fe2fecSShubhrajyoti Datta #define MC5_ERR_GRAIN			1
21d5fe2fecSShubhrajyoti Datta #define MC_GET_DDR_CONFIG_IN_LEN	4
22d5fe2fecSShubhrajyoti Datta 
23d5fe2fecSShubhrajyoti Datta #define MC5_IRQ_CE_MASK			GENMASK(18, 15)
24d5fe2fecSShubhrajyoti Datta #define MC5_IRQ_UE_MASK			GENMASK(14, 11)
25d5fe2fecSShubhrajyoti Datta 
26d5fe2fecSShubhrajyoti Datta #define MC5_RANK_1_MASK			GENMASK(11, 6)
27d5fe2fecSShubhrajyoti Datta #define MASK_24				GENMASK(29, 24)
28d5fe2fecSShubhrajyoti Datta #define MASK_0				GENMASK(5, 0)
29d5fe2fecSShubhrajyoti Datta 
30d5fe2fecSShubhrajyoti Datta #define MC5_LRANK_1_MASK		GENMASK(11, 6)
31d5fe2fecSShubhrajyoti Datta #define MC5_LRANK_2_MASK		GENMASK(17, 12)
32d5fe2fecSShubhrajyoti Datta #define MC5_BANK1_MASK			GENMASK(11, 6)
33d5fe2fecSShubhrajyoti Datta #define MC5_GRP_0_MASK			GENMASK(17, 12)
34d5fe2fecSShubhrajyoti Datta #define MC5_GRP_1_MASK			GENMASK(23, 18)
35d5fe2fecSShubhrajyoti Datta 
36d5fe2fecSShubhrajyoti Datta #define MC5_REGHI_ROW			7
37d5fe2fecSShubhrajyoti Datta #define MC5_EACHBIT			1
38d5fe2fecSShubhrajyoti Datta #define MC5_ERR_TYPE_CE			0
39d5fe2fecSShubhrajyoti Datta #define MC5_ERR_TYPE_UE			1
40d5fe2fecSShubhrajyoti Datta #define MC5_HIGH_MEM_EN			BIT(20)
41d5fe2fecSShubhrajyoti Datta #define MC5_MEM_MASK			GENMASK(19, 0)
42d5fe2fecSShubhrajyoti Datta #define MC5_X16_BASE			256
43d5fe2fecSShubhrajyoti Datta #define MC5_X16_ECC			32
44d5fe2fecSShubhrajyoti Datta #define MC5_X16_SIZE			(MC5_X16_BASE + MC5_X16_ECC)
45d5fe2fecSShubhrajyoti Datta #define MC5_X32_SIZE			576
46d5fe2fecSShubhrajyoti Datta #define MC5_HIMEM_BASE			(256 * SZ_1M)
47d5fe2fecSShubhrajyoti Datta #define MC5_ILC_HIMEM_EN		BIT(28)
48d5fe2fecSShubhrajyoti Datta #define MC5_ILC_MEM			GENMASK(27, 0)
49d5fe2fecSShubhrajyoti Datta #define MC5_INTERLEAVE_SEL		GENMASK(3, 0)
50d5fe2fecSShubhrajyoti Datta #define MC5_BUS_WIDTH_MASK		GENMASK(19, 18)
51d5fe2fecSShubhrajyoti Datta #define MC5_NUM_CHANS_MASK		BIT(17)
52d5fe2fecSShubhrajyoti Datta #define MC5_RANK_MASK			GENMASK(15, 14)
53d5fe2fecSShubhrajyoti Datta 
54d5fe2fecSShubhrajyoti Datta #define ERROR_LEVEL			2
55d5fe2fecSShubhrajyoti Datta #define ERROR_ID			3
56d5fe2fecSShubhrajyoti Datta #define TOTAL_ERR_LENGTH		5
57d5fe2fecSShubhrajyoti Datta #define MSG_ERR_OFFSET			8
58d5fe2fecSShubhrajyoti Datta #define MSG_ERR_LENGTH			9
59d5fe2fecSShubhrajyoti Datta #define ERROR_DATA			10
60d5fe2fecSShubhrajyoti Datta #define MCDI_RESPONSE			0xFF
61d5fe2fecSShubhrajyoti Datta 
62d5fe2fecSShubhrajyoti Datta #define REG_MAX				152
63d5fe2fecSShubhrajyoti Datta #define ADEC_MAX			152
64d5fe2fecSShubhrajyoti Datta #define NUM_CONTROLLERS			8
65d5fe2fecSShubhrajyoti Datta #define REGS_PER_CONTROLLER		19
66d5fe2fecSShubhrajyoti Datta #define ADEC_NUM			19
67d5fe2fecSShubhrajyoti Datta #define BUFFER_SZ			80
68d5fe2fecSShubhrajyoti Datta 
69d5fe2fecSShubhrajyoti Datta #define XDDR5_BUS_WIDTH_64		0
70d5fe2fecSShubhrajyoti Datta #define XDDR5_BUS_WIDTH_32		1
71d5fe2fecSShubhrajyoti Datta #define XDDR5_BUS_WIDTH_16		2
72d5fe2fecSShubhrajyoti Datta 
73d5fe2fecSShubhrajyoti Datta /**
74d5fe2fecSShubhrajyoti Datta  * struct ecc_error_info - ECC error log information.
75d5fe2fecSShubhrajyoti Datta  * @burstpos:		Burst position.
76d5fe2fecSShubhrajyoti Datta  * @lrank:		Logical Rank number.
77d5fe2fecSShubhrajyoti Datta  * @rank:		Rank number.
78d5fe2fecSShubhrajyoti Datta  * @group:		Group number.
79d5fe2fecSShubhrajyoti Datta  * @bank:		Bank number.
80d5fe2fecSShubhrajyoti Datta  * @col:		Column number.
81d5fe2fecSShubhrajyoti Datta  * @row:		Row number.
82d5fe2fecSShubhrajyoti Datta  * @rowhi:		Row number higher bits.
83d5fe2fecSShubhrajyoti Datta  * @i:			Combined ECC error vector containing encoded values of burst position,
84d5fe2fecSShubhrajyoti Datta  *			rank, bank, column, and row information.
85d5fe2fecSShubhrajyoti Datta  */
86d5fe2fecSShubhrajyoti Datta union ecc_error_info {
87d5fe2fecSShubhrajyoti Datta 	struct {
88d5fe2fecSShubhrajyoti Datta 		u32 burstpos:3;
89d5fe2fecSShubhrajyoti Datta 		u32 lrank:4;
90d5fe2fecSShubhrajyoti Datta 		u32 rank:2;
91d5fe2fecSShubhrajyoti Datta 		u32 group:3;
92d5fe2fecSShubhrajyoti Datta 		u32 bank:2;
93d5fe2fecSShubhrajyoti Datta 		u32 col:11;
94d5fe2fecSShubhrajyoti Datta 		u32 row:7;
95d5fe2fecSShubhrajyoti Datta 		u32 rowhi;
96d5fe2fecSShubhrajyoti Datta 	};
97d5fe2fecSShubhrajyoti Datta 	u64 i;
98d5fe2fecSShubhrajyoti Datta } __packed;
99d5fe2fecSShubhrajyoti Datta 
100d5fe2fecSShubhrajyoti Datta /* Row and column bit positions in the address decoder (ADEC) registers. */
101d5fe2fecSShubhrajyoti Datta union row_col_mapping {
102d5fe2fecSShubhrajyoti Datta 	struct {
103d5fe2fecSShubhrajyoti Datta 		u32 row0:6;
104d5fe2fecSShubhrajyoti Datta 		u32 row1:6;
105d5fe2fecSShubhrajyoti Datta 		u32 row2:6;
106d5fe2fecSShubhrajyoti Datta 		u32 row3:6;
107d5fe2fecSShubhrajyoti Datta 		u32 row4:6;
108d5fe2fecSShubhrajyoti Datta 		u32 reserved:2;
109d5fe2fecSShubhrajyoti Datta 	};
110d5fe2fecSShubhrajyoti Datta 	struct {
111d5fe2fecSShubhrajyoti Datta 		u32 col1:6;
112d5fe2fecSShubhrajyoti Datta 		u32 col2:6;
113d5fe2fecSShubhrajyoti Datta 		u32 col3:6;
114d5fe2fecSShubhrajyoti Datta 		u32 col4:6;
115d5fe2fecSShubhrajyoti Datta 		u32 col5:6;
116d5fe2fecSShubhrajyoti Datta 		u32 reservedcol:2;
117d5fe2fecSShubhrajyoti Datta 	};
118d5fe2fecSShubhrajyoti Datta 	u32 i;
119d5fe2fecSShubhrajyoti Datta } __packed;
120d5fe2fecSShubhrajyoti Datta 
121d5fe2fecSShubhrajyoti Datta /**
122d5fe2fecSShubhrajyoti Datta  * struct ecc_status - ECC status information to report.
123d5fe2fecSShubhrajyoti Datta  * @ceinfo:	Correctable errors.
124d5fe2fecSShubhrajyoti Datta  * @ueinfo:	Uncorrected errors.
125d5fe2fecSShubhrajyoti Datta  * @channel:	Channel number.
126d5fe2fecSShubhrajyoti Datta  * @error_type:	Error type.
127d5fe2fecSShubhrajyoti Datta  */
128d5fe2fecSShubhrajyoti Datta struct ecc_status {
129d5fe2fecSShubhrajyoti Datta 	union ecc_error_info ceinfo[2];
130d5fe2fecSShubhrajyoti Datta 	union ecc_error_info ueinfo[2];
131d5fe2fecSShubhrajyoti Datta 	u8 channel;
132d5fe2fecSShubhrajyoti Datta 	u8 error_type;
133d5fe2fecSShubhrajyoti Datta };
134d5fe2fecSShubhrajyoti Datta 
135d5fe2fecSShubhrajyoti Datta /**
136d5fe2fecSShubhrajyoti Datta  * struct mc_priv - DDR memory controller private instance data.
137d5fe2fecSShubhrajyoti Datta  * @message:		Buffer for framing the event specific info.
138d5fe2fecSShubhrajyoti Datta  * @stat:		ECC status information.
139d5fe2fecSShubhrajyoti Datta  * @error_id:		The error id.
140d5fe2fecSShubhrajyoti Datta  * @error_level:	The error level.
141d5fe2fecSShubhrajyoti Datta  * @dwidth:		Width of data bus excluding ECC bits.
142d5fe2fecSShubhrajyoti Datta  * @part_len:		The support of the message received.
143d5fe2fecSShubhrajyoti Datta  * @regs:		The registers sent on the rpmsg.
144d5fe2fecSShubhrajyoti Datta  * @adec:		Address decode registers.
145d5fe2fecSShubhrajyoti Datta  * @mci:		Memory controller interface.
146d5fe2fecSShubhrajyoti Datta  * @ept:		rpmsg endpoint.
147d5fe2fecSShubhrajyoti Datta  * @mcdi:		The mcdi handle.
148d5fe2fecSShubhrajyoti Datta  */
149d5fe2fecSShubhrajyoti Datta struct mc_priv {
150d5fe2fecSShubhrajyoti Datta 	char message[256];
151d5fe2fecSShubhrajyoti Datta 	struct ecc_status stat;
152d5fe2fecSShubhrajyoti Datta 	u32 error_id;
153d5fe2fecSShubhrajyoti Datta 	u32 error_level;
154d5fe2fecSShubhrajyoti Datta 	u32 dwidth;
155d5fe2fecSShubhrajyoti Datta 	u32 part_len;
156d5fe2fecSShubhrajyoti Datta 	u32 regs[REG_MAX];
157d5fe2fecSShubhrajyoti Datta 	u32 adec[ADEC_MAX];
158d5fe2fecSShubhrajyoti Datta 	struct mem_ctl_info *mci[NUM_CONTROLLERS];
159d5fe2fecSShubhrajyoti Datta 	struct rpmsg_endpoint *ept;
160d5fe2fecSShubhrajyoti Datta 	struct cdx_mcdi *mcdi;
161d5fe2fecSShubhrajyoti Datta };
162d5fe2fecSShubhrajyoti Datta 
163d5fe2fecSShubhrajyoti Datta /*
164d5fe2fecSShubhrajyoti Datta  * Address decoder (ADEC) registers to match the order in which the register
165d5fe2fecSShubhrajyoti Datta  * information is received from the firmware.
166d5fe2fecSShubhrajyoti Datta  */
167d5fe2fecSShubhrajyoti Datta enum adec_info {
168d5fe2fecSShubhrajyoti Datta 	CONF = 0,
169d5fe2fecSShubhrajyoti Datta 	ADEC0,
170d5fe2fecSShubhrajyoti Datta 	ADEC1,
171d5fe2fecSShubhrajyoti Datta 	ADEC2,
172d5fe2fecSShubhrajyoti Datta 	ADEC3,
173d5fe2fecSShubhrajyoti Datta 	ADEC4,
174d5fe2fecSShubhrajyoti Datta 	ADEC5,
175d5fe2fecSShubhrajyoti Datta 	ADEC6,
176d5fe2fecSShubhrajyoti Datta 	ADEC7,
177d5fe2fecSShubhrajyoti Datta 	ADEC8,
178d5fe2fecSShubhrajyoti Datta 	ADEC9,
179d5fe2fecSShubhrajyoti Datta 	ADEC10,
180d5fe2fecSShubhrajyoti Datta 	ADEC11,
181d5fe2fecSShubhrajyoti Datta 	ADEC12,
182d5fe2fecSShubhrajyoti Datta 	ADEC13,
183d5fe2fecSShubhrajyoti Datta 	ADEC14,
184d5fe2fecSShubhrajyoti Datta 	ADEC15,
185d5fe2fecSShubhrajyoti Datta 	ADEC16,
186d5fe2fecSShubhrajyoti Datta 	ADECILC,
187d5fe2fecSShubhrajyoti Datta };
188d5fe2fecSShubhrajyoti Datta 
189d5fe2fecSShubhrajyoti Datta enum reg_info {
190d5fe2fecSShubhrajyoti Datta 	ISR = 0,
191d5fe2fecSShubhrajyoti Datta 	IMR,
192d5fe2fecSShubhrajyoti Datta 	ECCR0_ERR_STATUS,
193d5fe2fecSShubhrajyoti Datta 	ECCR0_ADDR_LO,
194d5fe2fecSShubhrajyoti Datta 	ECCR0_ADDR_HI,
195d5fe2fecSShubhrajyoti Datta 	ECCR0_DATA_LO,
196d5fe2fecSShubhrajyoti Datta 	ECCR0_DATA_HI,
197d5fe2fecSShubhrajyoti Datta 	ECCR0_PAR,
198d5fe2fecSShubhrajyoti Datta 	ECCR1_ERR_STATUS,
199d5fe2fecSShubhrajyoti Datta 	ECCR1_ADDR_LO,
200d5fe2fecSShubhrajyoti Datta 	ECCR1_ADDR_HI,
201d5fe2fecSShubhrajyoti Datta 	ECCR1_DATA_LO,
202d5fe2fecSShubhrajyoti Datta 	ECCR1_DATA_HI,
203d5fe2fecSShubhrajyoti Datta 	ECCR1_PAR,
204d5fe2fecSShubhrajyoti Datta 	XMPU_ERR,
205d5fe2fecSShubhrajyoti Datta 	XMPU_ERR_ADDR_L0,
206d5fe2fecSShubhrajyoti Datta 	XMPU_ERR_ADDR_HI,
207d5fe2fecSShubhrajyoti Datta 	XMPU_ERR_AXI_ID,
208d5fe2fecSShubhrajyoti Datta 	ADEC_CHK_ERR_LOG,
209d5fe2fecSShubhrajyoti Datta };
210d5fe2fecSShubhrajyoti Datta 
get_ddr_info(u32 * error_data,struct mc_priv * priv)211d5fe2fecSShubhrajyoti Datta static bool get_ddr_info(u32 *error_data, struct mc_priv *priv)
212d5fe2fecSShubhrajyoti Datta {
213d5fe2fecSShubhrajyoti Datta 	u32 reglo, reghi, parity, eccr0_val, eccr1_val, isr;
214d5fe2fecSShubhrajyoti Datta 	struct ecc_status *p;
215d5fe2fecSShubhrajyoti Datta 
216d5fe2fecSShubhrajyoti Datta 	isr = error_data[ISR];
217d5fe2fecSShubhrajyoti Datta 
218d5fe2fecSShubhrajyoti Datta 	if (!(isr & (MC5_IRQ_UE_MASK | MC5_IRQ_CE_MASK)))
219d5fe2fecSShubhrajyoti Datta 		return false;
220d5fe2fecSShubhrajyoti Datta 
221d5fe2fecSShubhrajyoti Datta 	eccr0_val = error_data[ECCR0_ERR_STATUS];
222d5fe2fecSShubhrajyoti Datta 	eccr1_val = error_data[ECCR1_ERR_STATUS];
223d5fe2fecSShubhrajyoti Datta 
224d5fe2fecSShubhrajyoti Datta 	if (!eccr0_val && !eccr1_val)
225d5fe2fecSShubhrajyoti Datta 		return false;
226d5fe2fecSShubhrajyoti Datta 
227d5fe2fecSShubhrajyoti Datta 	p = &priv->stat;
228d5fe2fecSShubhrajyoti Datta 
229d5fe2fecSShubhrajyoti Datta 	if (!eccr0_val)
230d5fe2fecSShubhrajyoti Datta 		p->channel = 1;
231d5fe2fecSShubhrajyoti Datta 	else
232d5fe2fecSShubhrajyoti Datta 		p->channel = 0;
233d5fe2fecSShubhrajyoti Datta 
234d5fe2fecSShubhrajyoti Datta 	reglo = error_data[ECCR0_ADDR_LO];
235d5fe2fecSShubhrajyoti Datta 	reghi = error_data[ECCR0_ADDR_HI];
236d5fe2fecSShubhrajyoti Datta 	if (isr & MC5_IRQ_CE_MASK)
237d5fe2fecSShubhrajyoti Datta 		p->ceinfo[0].i = reglo | (u64)reghi << 32;
238d5fe2fecSShubhrajyoti Datta 	else if (isr & MC5_IRQ_UE_MASK)
239d5fe2fecSShubhrajyoti Datta 		p->ueinfo[0].i = reglo | (u64)reghi << 32;
240d5fe2fecSShubhrajyoti Datta 
241d5fe2fecSShubhrajyoti Datta 	parity = error_data[ECCR0_PAR];
242d5fe2fecSShubhrajyoti Datta 	edac_dbg(2, "ERR DATA: 0x%08X%08X PARITY: 0x%08X\n",
243d5fe2fecSShubhrajyoti Datta 		 reghi, reglo, parity);
244d5fe2fecSShubhrajyoti Datta 
245d5fe2fecSShubhrajyoti Datta 	reglo = error_data[ECCR1_ADDR_LO];
246d5fe2fecSShubhrajyoti Datta 	reghi = error_data[ECCR1_ADDR_HI];
247d5fe2fecSShubhrajyoti Datta 	if (isr & MC5_IRQ_CE_MASK)
248d5fe2fecSShubhrajyoti Datta 		p->ceinfo[1].i = reglo | (u64)reghi << 32;
249d5fe2fecSShubhrajyoti Datta 	else if (isr & MC5_IRQ_UE_MASK)
250d5fe2fecSShubhrajyoti Datta 		p->ueinfo[1].i = reglo | (u64)reghi << 32;
251d5fe2fecSShubhrajyoti Datta 
252d5fe2fecSShubhrajyoti Datta 	parity = error_data[ECCR1_PAR];
253d5fe2fecSShubhrajyoti Datta 	edac_dbg(2, "ERR DATA: 0x%08X%08X PARITY: 0x%08X\n",
254d5fe2fecSShubhrajyoti Datta 		 reghi, reglo, parity);
255d5fe2fecSShubhrajyoti Datta 
256d5fe2fecSShubhrajyoti Datta 	return true;
257d5fe2fecSShubhrajyoti Datta }
258d5fe2fecSShubhrajyoti Datta 
259d5fe2fecSShubhrajyoti Datta /**
260d5fe2fecSShubhrajyoti Datta  * convert_to_physical - Convert @error_data to a physical address.
261d5fe2fecSShubhrajyoti Datta  * @priv:	DDR memory controller private instance data.
262d5fe2fecSShubhrajyoti Datta  * @pinf:	ECC error info structure.
263d5fe2fecSShubhrajyoti Datta  * @controller:	Controller number of the MC5
264d5fe2fecSShubhrajyoti Datta  * @error_data:	the DDRMC5 ADEC address decoder register data
265d5fe2fecSShubhrajyoti Datta  *
266d5fe2fecSShubhrajyoti Datta  * Return: physical address of the DDR memory.
267d5fe2fecSShubhrajyoti Datta  */
convert_to_physical(struct mc_priv * priv,union ecc_error_info pinf,int controller,int * error_data)268d5fe2fecSShubhrajyoti Datta static unsigned long convert_to_physical(struct mc_priv *priv,
269d5fe2fecSShubhrajyoti Datta 					 union ecc_error_info pinf,
270d5fe2fecSShubhrajyoti Datta 					 int controller, int *error_data)
271d5fe2fecSShubhrajyoti Datta {
272d5fe2fecSShubhrajyoti Datta 	u32 row, blk, rsh_req_addr, interleave, ilc_base_ctrl_add, ilc_himem_en, reg, offset;
273d5fe2fecSShubhrajyoti Datta 	u64 high_mem_base, high_mem_offset, low_mem_offset, ilcmem_base;
274d5fe2fecSShubhrajyoti Datta 	unsigned long err_addr = 0, addr;
275d5fe2fecSShubhrajyoti Datta 	union row_col_mapping cols;
276d5fe2fecSShubhrajyoti Datta 	union row_col_mapping rows;
277d5fe2fecSShubhrajyoti Datta 	u32 col_bit_0;
278d5fe2fecSShubhrajyoti Datta 
279d5fe2fecSShubhrajyoti Datta 	row = pinf.rowhi << MC5_REGHI_ROW | pinf.row;
280d5fe2fecSShubhrajyoti Datta 	offset = controller * ADEC_NUM;
281d5fe2fecSShubhrajyoti Datta 
282d5fe2fecSShubhrajyoti Datta 	reg = error_data[ADEC6];
283d5fe2fecSShubhrajyoti Datta 	rows.i = reg;
284d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row0;
285d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
286d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row1;
287d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
288d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row2;
289d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
290d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row3;
291d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
292d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row4;
293d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
294d5fe2fecSShubhrajyoti Datta 
295d5fe2fecSShubhrajyoti Datta 	reg = error_data[ADEC7];
296d5fe2fecSShubhrajyoti Datta 	rows.i = reg;
297d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row0;
298d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
299d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row1;
300d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
301d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row2;
302d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
303d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row3;
304d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
305d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row4;
306d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
307d5fe2fecSShubhrajyoti Datta 
308d5fe2fecSShubhrajyoti Datta 	reg = error_data[ADEC8];
309d5fe2fecSShubhrajyoti Datta 	rows.i = reg;
310d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row0;
311d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
312d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row1;
313d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
314d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row2;
315d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
316d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row3;
317d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
318d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row4;
319d5fe2fecSShubhrajyoti Datta 
320d5fe2fecSShubhrajyoti Datta 	reg = error_data[ADEC9];
321d5fe2fecSShubhrajyoti Datta 	rows.i = reg;
322d5fe2fecSShubhrajyoti Datta 
323d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row0;
324d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
325d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row1;
326d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
327d5fe2fecSShubhrajyoti Datta 	err_addr |= (row & BIT(0)) << rows.row2;
328d5fe2fecSShubhrajyoti Datta 	row >>= MC5_EACHBIT;
329d5fe2fecSShubhrajyoti Datta 
330d5fe2fecSShubhrajyoti Datta 	col_bit_0 = FIELD_GET(MASK_24, error_data[ADEC9]);
331d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
332d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << col_bit_0;
333d5fe2fecSShubhrajyoti Datta 
334d5fe2fecSShubhrajyoti Datta 	cols.i = error_data[ADEC10];
335d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col1;
336d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
337d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col2;
338d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
339d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col3;
340d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
341d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col4;
342d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
343d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col5;
344d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
345d5fe2fecSShubhrajyoti Datta 
346d5fe2fecSShubhrajyoti Datta 	cols.i = error_data[ADEC11];
347d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col1;
348d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
349d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col2;
350d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
351d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col3;
352d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
353d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col4;
354d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
355d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.col & 1) << cols.col5;
356d5fe2fecSShubhrajyoti Datta 	pinf.col >>= 1;
357d5fe2fecSShubhrajyoti Datta 
358d5fe2fecSShubhrajyoti Datta 	reg = error_data[ADEC12];
359d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.bank & BIT(0)) << (reg & MASK_0);
360d5fe2fecSShubhrajyoti Datta 	pinf.bank >>= MC5_EACHBIT;
361d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.bank & BIT(0)) << FIELD_GET(MC5_BANK1_MASK, reg);
362d5fe2fecSShubhrajyoti Datta 	pinf.bank >>= MC5_EACHBIT;
363d5fe2fecSShubhrajyoti Datta 
364d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.bank & BIT(0)) << FIELD_GET(MC5_GRP_0_MASK, reg);
365d5fe2fecSShubhrajyoti Datta 	pinf.group >>= MC5_EACHBIT;
366d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.bank & BIT(0)) << FIELD_GET(MC5_GRP_1_MASK, reg);
367d5fe2fecSShubhrajyoti Datta 	pinf.group >>= MC5_EACHBIT;
368d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.bank & BIT(0)) << FIELD_GET(MASK_24, reg);
369d5fe2fecSShubhrajyoti Datta 	pinf.group >>= MC5_EACHBIT;
370d5fe2fecSShubhrajyoti Datta 
371d5fe2fecSShubhrajyoti Datta 	reg = error_data[ADEC4];
372d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.rank & BIT(0)) << (reg & MASK_0);
373d5fe2fecSShubhrajyoti Datta 	pinf.rank >>= MC5_EACHBIT;
374d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.rank & BIT(0)) << FIELD_GET(MC5_RANK_1_MASK, reg);
375d5fe2fecSShubhrajyoti Datta 	pinf.rank >>= MC5_EACHBIT;
376d5fe2fecSShubhrajyoti Datta 
377d5fe2fecSShubhrajyoti Datta 	reg = error_data[ADEC5];
378d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.lrank & BIT(0)) << (reg & MASK_0);
379d5fe2fecSShubhrajyoti Datta 	pinf.lrank >>= MC5_EACHBIT;
380d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.lrank & BIT(0)) << FIELD_GET(MC5_LRANK_1_MASK, reg);
381d5fe2fecSShubhrajyoti Datta 	pinf.lrank >>= MC5_EACHBIT;
382d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.lrank & BIT(0)) << FIELD_GET(MC5_LRANK_2_MASK, reg);
383d5fe2fecSShubhrajyoti Datta 	pinf.lrank >>= MC5_EACHBIT;
384d5fe2fecSShubhrajyoti Datta 	err_addr |= (pinf.lrank & BIT(0)) << FIELD_GET(MASK_24, reg);
385d5fe2fecSShubhrajyoti Datta 	pinf.lrank >>= MC5_EACHBIT;
386d5fe2fecSShubhrajyoti Datta 
387d5fe2fecSShubhrajyoti Datta 	high_mem_base = (priv->adec[ADEC2 + offset] & MC5_MEM_MASK) * MC5_HIMEM_BASE;
388d5fe2fecSShubhrajyoti Datta 	interleave = priv->adec[ADEC13 + offset] & MC5_INTERLEAVE_SEL;
389d5fe2fecSShubhrajyoti Datta 
390d5fe2fecSShubhrajyoti Datta 	high_mem_offset = priv->adec[ADEC3 + offset] & MC5_MEM_MASK;
391d5fe2fecSShubhrajyoti Datta 	low_mem_offset = priv->adec[ADEC1 + offset] & MC5_MEM_MASK;
392d5fe2fecSShubhrajyoti Datta 	reg = priv->adec[ADEC14 + offset];
393d5fe2fecSShubhrajyoti Datta 	ilc_himem_en = !!(reg & MC5_ILC_HIMEM_EN);
394d5fe2fecSShubhrajyoti Datta 	ilcmem_base = (reg & MC5_ILC_MEM) * SZ_1M;
395d5fe2fecSShubhrajyoti Datta 	if (ilc_himem_en)
396d5fe2fecSShubhrajyoti Datta 		ilc_base_ctrl_add = ilcmem_base - high_mem_offset;
397d5fe2fecSShubhrajyoti Datta 	else
398d5fe2fecSShubhrajyoti Datta 		ilc_base_ctrl_add = ilcmem_base - low_mem_offset;
399d5fe2fecSShubhrajyoti Datta 
400d5fe2fecSShubhrajyoti Datta 	if (priv->dwidth == DEV_X16) {
401d5fe2fecSShubhrajyoti Datta 		blk = err_addr / MC5_X16_SIZE;
402d5fe2fecSShubhrajyoti Datta 		rsh_req_addr = (blk << 8) + ilc_base_ctrl_add;
403d5fe2fecSShubhrajyoti Datta 		err_addr = rsh_req_addr * interleave * 2;
404d5fe2fecSShubhrajyoti Datta 	} else {
405d5fe2fecSShubhrajyoti Datta 		blk = err_addr / MC5_X32_SIZE;
406d5fe2fecSShubhrajyoti Datta 		rsh_req_addr = (blk << 9) + ilc_base_ctrl_add;
407d5fe2fecSShubhrajyoti Datta 		err_addr = rsh_req_addr * interleave * 2;
408d5fe2fecSShubhrajyoti Datta 	}
409d5fe2fecSShubhrajyoti Datta 
410d5fe2fecSShubhrajyoti Datta 	if ((priv->adec[ADEC2 + offset] & MC5_HIGH_MEM_EN) && err_addr >= high_mem_base)
411d5fe2fecSShubhrajyoti Datta 		addr = err_addr - high_mem_offset;
412d5fe2fecSShubhrajyoti Datta 	else
413d5fe2fecSShubhrajyoti Datta 		addr = err_addr - low_mem_offset;
414d5fe2fecSShubhrajyoti Datta 
415d5fe2fecSShubhrajyoti Datta 	return addr;
416d5fe2fecSShubhrajyoti Datta }
417d5fe2fecSShubhrajyoti Datta 
418d5fe2fecSShubhrajyoti Datta /**
419d5fe2fecSShubhrajyoti Datta  * handle_error - Handle errors.
420d5fe2fecSShubhrajyoti Datta  * @priv:	DDR memory controller private instance data.
421d5fe2fecSShubhrajyoti Datta  * @stat:	ECC status structure.
422d5fe2fecSShubhrajyoti Datta  * @ctl_num:	Controller number of the MC5
423d5fe2fecSShubhrajyoti Datta  * @error_data:	the MC5 ADEC address decoder register data
424d5fe2fecSShubhrajyoti Datta  *
425d5fe2fecSShubhrajyoti Datta  * Handles ECC correctable and uncorrectable errors.
426d5fe2fecSShubhrajyoti Datta  */
handle_error(struct mc_priv * priv,struct ecc_status * stat,int ctl_num,int * error_data)427d5fe2fecSShubhrajyoti Datta static void handle_error(struct mc_priv  *priv, struct ecc_status *stat,
428d5fe2fecSShubhrajyoti Datta 			 int ctl_num, int *error_data)
429d5fe2fecSShubhrajyoti Datta {
430d5fe2fecSShubhrajyoti Datta 	union ecc_error_info pinf;
431d5fe2fecSShubhrajyoti Datta 	struct mem_ctl_info *mci;
432d5fe2fecSShubhrajyoti Datta 	unsigned long pa;
433d5fe2fecSShubhrajyoti Datta 	phys_addr_t pfn;
434d5fe2fecSShubhrajyoti Datta 	int err;
435d5fe2fecSShubhrajyoti Datta 
436d5fe2fecSShubhrajyoti Datta 	if (WARN_ON_ONCE(ctl_num > NUM_CONTROLLERS))
437d5fe2fecSShubhrajyoti Datta 		return;
438d5fe2fecSShubhrajyoti Datta 
439d5fe2fecSShubhrajyoti Datta 	mci = priv->mci[ctl_num];
440d5fe2fecSShubhrajyoti Datta 
441d5fe2fecSShubhrajyoti Datta 	if (stat->error_type == MC5_ERR_TYPE_CE) {
442d5fe2fecSShubhrajyoti Datta 		pinf = stat->ceinfo[stat->channel];
443d5fe2fecSShubhrajyoti Datta 		snprintf(priv->message, sizeof(priv->message),
444d5fe2fecSShubhrajyoti Datta 			 "Error type:%s Controller %d Addr at %lx\n",
445d5fe2fecSShubhrajyoti Datta 			 "CE", ctl_num, convert_to_physical(priv, pinf, ctl_num, error_data));
446d5fe2fecSShubhrajyoti Datta 
447d5fe2fecSShubhrajyoti Datta 		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
448d5fe2fecSShubhrajyoti Datta 				     1, 0, 0, 0, 0, 0, -1,
449d5fe2fecSShubhrajyoti Datta 				     priv->message, "");
450d5fe2fecSShubhrajyoti Datta 	}
451d5fe2fecSShubhrajyoti Datta 
452d5fe2fecSShubhrajyoti Datta 	if (stat->error_type == MC5_ERR_TYPE_UE) {
453d5fe2fecSShubhrajyoti Datta 		pinf = stat->ueinfo[stat->channel];
454d5fe2fecSShubhrajyoti Datta 		snprintf(priv->message, sizeof(priv->message),
455d5fe2fecSShubhrajyoti Datta 			 "Error type:%s controller %d Addr at %lx\n",
456d5fe2fecSShubhrajyoti Datta 			 "UE", ctl_num, convert_to_physical(priv, pinf, ctl_num, error_data));
457d5fe2fecSShubhrajyoti Datta 
458d5fe2fecSShubhrajyoti Datta 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
459d5fe2fecSShubhrajyoti Datta 				     1, 0, 0, 0, 0, 0, -1,
460d5fe2fecSShubhrajyoti Datta 				     priv->message, "");
461d5fe2fecSShubhrajyoti Datta 		pa = convert_to_physical(priv, pinf, ctl_num, error_data);
462d5fe2fecSShubhrajyoti Datta 		pfn = PHYS_PFN(pa);
463d5fe2fecSShubhrajyoti Datta 
464d5fe2fecSShubhrajyoti Datta 		if (IS_ENABLED(CONFIG_MEMORY_FAILURE)) {
465d5fe2fecSShubhrajyoti Datta 			err = memory_failure(pfn, MF_ACTION_REQUIRED);
466d5fe2fecSShubhrajyoti Datta 			if (err)
467d5fe2fecSShubhrajyoti Datta 				edac_dbg(2, "memory_failure() error: %d", err);
468d5fe2fecSShubhrajyoti Datta 			else
469d5fe2fecSShubhrajyoti Datta 				edac_dbg(2, "Poison page at PA 0x%lx\n", pa);
470d5fe2fecSShubhrajyoti Datta 		}
471d5fe2fecSShubhrajyoti Datta 	}
472d5fe2fecSShubhrajyoti Datta }
473d5fe2fecSShubhrajyoti Datta 
mc_init(struct mem_ctl_info * mci,struct device * dev)474d5fe2fecSShubhrajyoti Datta static void mc_init(struct mem_ctl_info *mci, struct device *dev)
475d5fe2fecSShubhrajyoti Datta {
476d5fe2fecSShubhrajyoti Datta 	struct mc_priv *priv = mci->pvt_info;
477d5fe2fecSShubhrajyoti Datta 	struct csrow_info *csi;
478d5fe2fecSShubhrajyoti Datta 	struct dimm_info *dimm;
479d5fe2fecSShubhrajyoti Datta 	u32 row;
480d5fe2fecSShubhrajyoti Datta 	int ch;
481d5fe2fecSShubhrajyoti Datta 
482d5fe2fecSShubhrajyoti Datta 	/* Initialize controller capabilities and configuration */
483d5fe2fecSShubhrajyoti Datta 	mci->mtype_cap = MEM_FLAG_DDR5;
484d5fe2fecSShubhrajyoti Datta 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
485d5fe2fecSShubhrajyoti Datta 	mci->scrub_cap = SCRUB_HW_SRC;
486d5fe2fecSShubhrajyoti Datta 	mci->scrub_mode = SCRUB_NONE;
487d5fe2fecSShubhrajyoti Datta 
488d5fe2fecSShubhrajyoti Datta 	mci->edac_cap = EDAC_FLAG_SECDED;
489d5fe2fecSShubhrajyoti Datta 	mci->ctl_name = "VersalNET DDR5";
490d5fe2fecSShubhrajyoti Datta 	mci->dev_name = dev_name(dev);
491d5fe2fecSShubhrajyoti Datta 	mci->mod_name = "versalnet_edac";
492d5fe2fecSShubhrajyoti Datta 
493d5fe2fecSShubhrajyoti Datta 	edac_op_state = EDAC_OPSTATE_INT;
494d5fe2fecSShubhrajyoti Datta 
495d5fe2fecSShubhrajyoti Datta 	for (row = 0; row < mci->nr_csrows; row++) {
496d5fe2fecSShubhrajyoti Datta 		csi = mci->csrows[row];
497d5fe2fecSShubhrajyoti Datta 		for (ch = 0; ch < csi->nr_channels; ch++) {
498d5fe2fecSShubhrajyoti Datta 			dimm = csi->channels[ch]->dimm;
499d5fe2fecSShubhrajyoti Datta 			dimm->edac_mode = EDAC_SECDED;
500d5fe2fecSShubhrajyoti Datta 			dimm->mtype = MEM_DDR5;
501d5fe2fecSShubhrajyoti Datta 			dimm->grain = MC5_ERR_GRAIN;
502d5fe2fecSShubhrajyoti Datta 			dimm->dtype = priv->dwidth;
503d5fe2fecSShubhrajyoti Datta 		}
504d5fe2fecSShubhrajyoti Datta 	}
505d5fe2fecSShubhrajyoti Datta }
506d5fe2fecSShubhrajyoti Datta 
507d5fe2fecSShubhrajyoti Datta #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
508d5fe2fecSShubhrajyoti Datta 
mcdi_rpc_timeout(struct cdx_mcdi * cdx,unsigned int cmd)509d5fe2fecSShubhrajyoti Datta static unsigned int mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd)
510d5fe2fecSShubhrajyoti Datta {
511d5fe2fecSShubhrajyoti Datta 	return MCDI_RPC_TIMEOUT;
512d5fe2fecSShubhrajyoti Datta }
513d5fe2fecSShubhrajyoti Datta 
mcdi_request(struct cdx_mcdi * cdx,const struct cdx_dword * hdr,size_t hdr_len,const struct cdx_dword * sdu,size_t sdu_len)514d5fe2fecSShubhrajyoti Datta static void mcdi_request(struct cdx_mcdi *cdx,
515d5fe2fecSShubhrajyoti Datta 			 const struct cdx_dword *hdr, size_t hdr_len,
516d5fe2fecSShubhrajyoti Datta 			 const struct cdx_dword *sdu, size_t sdu_len)
517d5fe2fecSShubhrajyoti Datta {
518d5fe2fecSShubhrajyoti Datta 	void *send_buf;
519d5fe2fecSShubhrajyoti Datta 	int ret;
520d5fe2fecSShubhrajyoti Datta 
521d5fe2fecSShubhrajyoti Datta 	send_buf = kzalloc(hdr_len + sdu_len, GFP_KERNEL);
522d5fe2fecSShubhrajyoti Datta 	if (!send_buf)
523d5fe2fecSShubhrajyoti Datta 		return;
524d5fe2fecSShubhrajyoti Datta 
525d5fe2fecSShubhrajyoti Datta 	memcpy(send_buf, hdr, hdr_len);
526d5fe2fecSShubhrajyoti Datta 	memcpy(send_buf + hdr_len, sdu, sdu_len);
527d5fe2fecSShubhrajyoti Datta 
528d5fe2fecSShubhrajyoti Datta 	ret = rpmsg_send(cdx->ept, send_buf, hdr_len + sdu_len);
529d5fe2fecSShubhrajyoti Datta 	if (ret)
530d5fe2fecSShubhrajyoti Datta 		dev_err(&cdx->rpdev->dev, "Failed to send rpmsg data: %d\n", ret);
531d5fe2fecSShubhrajyoti Datta 
532d5fe2fecSShubhrajyoti Datta 	kfree(send_buf);
533d5fe2fecSShubhrajyoti Datta }
534d5fe2fecSShubhrajyoti Datta 
535d5fe2fecSShubhrajyoti Datta static const struct cdx_mcdi_ops mcdi_ops = {
536d5fe2fecSShubhrajyoti Datta 	.mcdi_rpc_timeout = mcdi_rpc_timeout,
537d5fe2fecSShubhrajyoti Datta 	.mcdi_request = mcdi_request,
538d5fe2fecSShubhrajyoti Datta };
539d5fe2fecSShubhrajyoti Datta 
get_ddr_config(u32 index,u32 * buffer,struct cdx_mcdi * amd_mcdi)540d5fe2fecSShubhrajyoti Datta static void get_ddr_config(u32 index, u32 *buffer, struct cdx_mcdi *amd_mcdi)
541d5fe2fecSShubhrajyoti Datta {
542d5fe2fecSShubhrajyoti Datta 	size_t outlen;
543d5fe2fecSShubhrajyoti Datta 	int ret;
544d5fe2fecSShubhrajyoti Datta 
545d5fe2fecSShubhrajyoti Datta 	MCDI_DECLARE_BUF(inbuf, MC_GET_DDR_CONFIG_IN_LEN);
546d5fe2fecSShubhrajyoti Datta 	MCDI_DECLARE_BUF(outbuf, BUFFER_SZ);
547d5fe2fecSShubhrajyoti Datta 
548d5fe2fecSShubhrajyoti Datta 	MCDI_SET_DWORD(inbuf, EDAC_GET_DDR_CONFIG_IN_CONTROLLER_INDEX, index);
549d5fe2fecSShubhrajyoti Datta 
550d5fe2fecSShubhrajyoti Datta 	ret = cdx_mcdi_rpc(amd_mcdi, MC_CMD_EDAC_GET_DDR_CONFIG, inbuf, sizeof(inbuf),
551d5fe2fecSShubhrajyoti Datta 			   outbuf, sizeof(outbuf), &outlen);
552d5fe2fecSShubhrajyoti Datta 	if (!ret)
553d5fe2fecSShubhrajyoti Datta 		memcpy(buffer, MCDI_PTR(outbuf, GET_DDR_CONFIG),
554d5fe2fecSShubhrajyoti Datta 		       (ADEC_NUM * 4));
555d5fe2fecSShubhrajyoti Datta }
556d5fe2fecSShubhrajyoti Datta 
setup_mcdi(struct mc_priv * mc_priv)557d5fe2fecSShubhrajyoti Datta static int setup_mcdi(struct mc_priv *mc_priv)
558d5fe2fecSShubhrajyoti Datta {
559d5fe2fecSShubhrajyoti Datta 	struct cdx_mcdi *amd_mcdi;
560d5fe2fecSShubhrajyoti Datta 	int ret, i;
561d5fe2fecSShubhrajyoti Datta 
562d5fe2fecSShubhrajyoti Datta 	amd_mcdi = kzalloc(sizeof(*amd_mcdi), GFP_KERNEL);
563d5fe2fecSShubhrajyoti Datta 	if (!amd_mcdi)
564d5fe2fecSShubhrajyoti Datta 		return -ENOMEM;
565d5fe2fecSShubhrajyoti Datta 
566d5fe2fecSShubhrajyoti Datta 	amd_mcdi->mcdi_ops = &mcdi_ops;
567d5fe2fecSShubhrajyoti Datta 	ret = cdx_mcdi_init(amd_mcdi);
568d5fe2fecSShubhrajyoti Datta 	if (ret) {
569d5fe2fecSShubhrajyoti Datta 		kfree(amd_mcdi);
570d5fe2fecSShubhrajyoti Datta 		return ret;
571d5fe2fecSShubhrajyoti Datta 	}
572d5fe2fecSShubhrajyoti Datta 
573d5fe2fecSShubhrajyoti Datta 	amd_mcdi->ept = mc_priv->ept;
574d5fe2fecSShubhrajyoti Datta 	mc_priv->mcdi = amd_mcdi;
575d5fe2fecSShubhrajyoti Datta 
576d5fe2fecSShubhrajyoti Datta 	for (i = 0; i < NUM_CONTROLLERS; i++)
577d5fe2fecSShubhrajyoti Datta 		get_ddr_config(i, &mc_priv->adec[ADEC_NUM * i], amd_mcdi);
578d5fe2fecSShubhrajyoti Datta 
579d5fe2fecSShubhrajyoti Datta 	return 0;
580d5fe2fecSShubhrajyoti Datta }
581d5fe2fecSShubhrajyoti Datta 
582d5fe2fecSShubhrajyoti Datta static const guid_t amd_versalnet_guid = GUID_INIT(0x82678888, 0xa556, 0x44f2,
583d5fe2fecSShubhrajyoti Datta 						 0xb8, 0xb4, 0x45, 0x56, 0x2e,
584d5fe2fecSShubhrajyoti Datta 						 0x8c, 0x5b, 0xec);
585d5fe2fecSShubhrajyoti Datta 
rpmsg_cb(struct rpmsg_device * rpdev,void * data,int len,void * priv,u32 src)586d5fe2fecSShubhrajyoti Datta static int rpmsg_cb(struct rpmsg_device *rpdev, void *data,
587d5fe2fecSShubhrajyoti Datta 		    int len, void *priv, u32 src)
588d5fe2fecSShubhrajyoti Datta {
589d5fe2fecSShubhrajyoti Datta 	struct mc_priv *mc_priv = dev_get_drvdata(&rpdev->dev);
590d5fe2fecSShubhrajyoti Datta 	const guid_t *sec_type = &guid_null;
591d5fe2fecSShubhrajyoti Datta 	u32 length, offset, error_id;
592d5fe2fecSShubhrajyoti Datta 	u32 *result = (u32 *)data;
593d5fe2fecSShubhrajyoti Datta 	struct ecc_status *p;
594d5fe2fecSShubhrajyoti Datta 	int i, j, k, sec_sev;
595d5fe2fecSShubhrajyoti Datta 	const char *err_str;
596d5fe2fecSShubhrajyoti Datta 	u32 *adec_data;
597d5fe2fecSShubhrajyoti Datta 
598d5fe2fecSShubhrajyoti Datta 	if (*(u8 *)data == MCDI_RESPONSE) {
599d5fe2fecSShubhrajyoti Datta 		cdx_mcdi_process_cmd(mc_priv->mcdi, (struct cdx_dword *)data, len);
600d5fe2fecSShubhrajyoti Datta 		return 0;
601d5fe2fecSShubhrajyoti Datta 	}
602d5fe2fecSShubhrajyoti Datta 
603d5fe2fecSShubhrajyoti Datta 	sec_sev = result[ERROR_LEVEL];
604d5fe2fecSShubhrajyoti Datta 	error_id = result[ERROR_ID];
605d5fe2fecSShubhrajyoti Datta 	length = result[MSG_ERR_LENGTH];
606d5fe2fecSShubhrajyoti Datta 	offset = result[MSG_ERR_OFFSET];
607d5fe2fecSShubhrajyoti Datta 
608d5fe2fecSShubhrajyoti Datta 	if (result[TOTAL_ERR_LENGTH] > length) {
609d5fe2fecSShubhrajyoti Datta 		if (!mc_priv->part_len)
610d5fe2fecSShubhrajyoti Datta 			mc_priv->part_len = length;
611d5fe2fecSShubhrajyoti Datta 		else
612d5fe2fecSShubhrajyoti Datta 			mc_priv->part_len += length;
613d5fe2fecSShubhrajyoti Datta 		/*
614d5fe2fecSShubhrajyoti Datta 		 * The data can come in 2 stretches. Construct the regs from 2
615d5fe2fecSShubhrajyoti Datta 		 * messages the offset indicates the offset from which the data is to
616d5fe2fecSShubhrajyoti Datta 		 * be taken
617d5fe2fecSShubhrajyoti Datta 		 */
618d5fe2fecSShubhrajyoti Datta 		for (i = 0 ; i < length; i++) {
619d5fe2fecSShubhrajyoti Datta 			k = offset + i;
620d5fe2fecSShubhrajyoti Datta 			j = ERROR_DATA + i;
621d5fe2fecSShubhrajyoti Datta 			mc_priv->regs[k] = result[j];
622d5fe2fecSShubhrajyoti Datta 		}
623d5fe2fecSShubhrajyoti Datta 		if (mc_priv->part_len < result[TOTAL_ERR_LENGTH])
624d5fe2fecSShubhrajyoti Datta 			return 0;
625d5fe2fecSShubhrajyoti Datta 		mc_priv->part_len = 0;
626d5fe2fecSShubhrajyoti Datta 	}
627d5fe2fecSShubhrajyoti Datta 
628d5fe2fecSShubhrajyoti Datta 	mc_priv->error_id = error_id;
629d5fe2fecSShubhrajyoti Datta 	mc_priv->error_level = result[ERROR_LEVEL];
630d5fe2fecSShubhrajyoti Datta 
631d5fe2fecSShubhrajyoti Datta 	switch (error_id) {
632d5fe2fecSShubhrajyoti Datta 	case 5:		err_str = "General Software Non-Correctable error"; break;
633d5fe2fecSShubhrajyoti Datta 	case 6:		err_str = "CFU error"; break;
634d5fe2fecSShubhrajyoti Datta 	case 7:		err_str = "CFRAME error"; break;
635d5fe2fecSShubhrajyoti Datta 	case 10:	err_str = "DDRMC Microblaze Correctable ECC error"; break;
636d5fe2fecSShubhrajyoti Datta 	case 11:	err_str = "DDRMC Microblaze Non-Correctable ECC error"; break;
637d5fe2fecSShubhrajyoti Datta 	case 15:	err_str = "MMCM error"; break;
638d5fe2fecSShubhrajyoti Datta 	case 16:	err_str = "HNICX Correctable error"; break;
639d5fe2fecSShubhrajyoti Datta 	case 17:	err_str = "HNICX Non-Correctable error"; break;
640d5fe2fecSShubhrajyoti Datta 
641d5fe2fecSShubhrajyoti Datta 	case 18:
642d5fe2fecSShubhrajyoti Datta 		p = &mc_priv->stat;
643d5fe2fecSShubhrajyoti Datta 		memset(p, 0, sizeof(struct ecc_status));
644d5fe2fecSShubhrajyoti Datta 		p->error_type = MC5_ERR_TYPE_CE;
645d5fe2fecSShubhrajyoti Datta 		for (i = 0 ; i < NUM_CONTROLLERS; i++) {
646d5fe2fecSShubhrajyoti Datta 			if (get_ddr_info(&mc_priv->regs[i * REGS_PER_CONTROLLER], mc_priv)) {
647d5fe2fecSShubhrajyoti Datta 				adec_data = mc_priv->adec + ADEC_NUM * i;
648d5fe2fecSShubhrajyoti Datta 				handle_error(mc_priv, &mc_priv->stat, i, adec_data);
649d5fe2fecSShubhrajyoti Datta 			}
650d5fe2fecSShubhrajyoti Datta 		}
651d5fe2fecSShubhrajyoti Datta 		return 0;
652d5fe2fecSShubhrajyoti Datta 	case 19:
653d5fe2fecSShubhrajyoti Datta 		p = &mc_priv->stat;
654d5fe2fecSShubhrajyoti Datta 		memset(p, 0, sizeof(struct ecc_status));
655d5fe2fecSShubhrajyoti Datta 		p->error_type = MC5_ERR_TYPE_UE;
656d5fe2fecSShubhrajyoti Datta 		for (i = 0 ; i < NUM_CONTROLLERS; i++) {
657d5fe2fecSShubhrajyoti Datta 			if (get_ddr_info(&mc_priv->regs[i * REGS_PER_CONTROLLER], mc_priv)) {
658d5fe2fecSShubhrajyoti Datta 				adec_data = mc_priv->adec + ADEC_NUM * i;
659d5fe2fecSShubhrajyoti Datta 				handle_error(mc_priv, &mc_priv->stat, i, adec_data);
660d5fe2fecSShubhrajyoti Datta 			}
661d5fe2fecSShubhrajyoti Datta 		}
662d5fe2fecSShubhrajyoti Datta 		return 0;
663d5fe2fecSShubhrajyoti Datta 
664d5fe2fecSShubhrajyoti Datta 	case 21:	err_str = "GT Non-Correctable error"; break;
665d5fe2fecSShubhrajyoti Datta 	case 22:	err_str = "PL Sysmon Correctable error"; break;
666d5fe2fecSShubhrajyoti Datta 	case 23:	err_str = "PL Sysmon Non-Correctable error"; break;
667d5fe2fecSShubhrajyoti Datta 	case 111:	err_str = "LPX unexpected dfx activation error"; break;
668d5fe2fecSShubhrajyoti Datta 	case 114:	err_str = "INT_LPD Non-Correctable error"; break;
669d5fe2fecSShubhrajyoti Datta 	case 116:	err_str = "INT_OCM Non-Correctable error"; break;
670d5fe2fecSShubhrajyoti Datta 	case 117:	err_str = "INT_FPD Correctable error"; break;
671d5fe2fecSShubhrajyoti Datta 	case 118:	err_str = "INT_FPD Non-Correctable error"; break;
672d5fe2fecSShubhrajyoti Datta 	case 120:	err_str = "INT_IOU Non-Correctable error"; break;
673d5fe2fecSShubhrajyoti Datta 	case 123:	err_str = "err_int_irq from APU GIC Distributor"; break;
674d5fe2fecSShubhrajyoti Datta 	case 124:	err_str = "fault_int_irq from APU GIC Distribute"; break;
675d5fe2fecSShubhrajyoti Datta 	case 132 ... 139: err_str = "FPX SPLITTER error"; break;
676d5fe2fecSShubhrajyoti Datta 	case 140:	err_str = "APU Cluster 0 error"; break;
677d5fe2fecSShubhrajyoti Datta 	case 141:	err_str = "APU Cluster 1 error"; break;
678d5fe2fecSShubhrajyoti Datta 	case 142:	err_str = "APU Cluster 2 error"; break;
679d5fe2fecSShubhrajyoti Datta 	case 143:	err_str = "APU Cluster 3 error"; break;
680d5fe2fecSShubhrajyoti Datta 	case 145:	err_str = "WWDT1 LPX error"; break;
681d5fe2fecSShubhrajyoti Datta 	case 147:	err_str = "IPI error"; break;
682d5fe2fecSShubhrajyoti Datta 	case 152 ... 153: err_str = "AFIFS error"; break;
683d5fe2fecSShubhrajyoti Datta 	case 154 ... 155: err_str = "LPX glitch error"; break;
684d5fe2fecSShubhrajyoti Datta 	case 185 ... 186: err_str = "FPX AFIFS error"; break;
685d5fe2fecSShubhrajyoti Datta 	case 195 ... 199: err_str = "AFIFM error"; break;
686d5fe2fecSShubhrajyoti Datta 	case 108:	err_str = "PSM Correctable error"; break;
687d5fe2fecSShubhrajyoti Datta 	case 59:	err_str = "PMC correctable error"; break;
688d5fe2fecSShubhrajyoti Datta 	case 60:	err_str = "PMC Un correctable error"; break;
689d5fe2fecSShubhrajyoti Datta 	case 43 ... 47:	err_str = "PMC Sysmon error"; break;
690d5fe2fecSShubhrajyoti Datta 	case 163 ... 184: err_str = "RPU error"; break;
691d5fe2fecSShubhrajyoti Datta 	case 148:	err_str = "OCM0 correctable error"; break;
692d5fe2fecSShubhrajyoti Datta 	case 149:	err_str = "OCM1 correctable error"; break;
693d5fe2fecSShubhrajyoti Datta 	case 150:	err_str = "OCM0 Un-correctable error"; break;
694d5fe2fecSShubhrajyoti Datta 	case 151:	err_str = "OCM1 Un-correctable error"; break;
695d5fe2fecSShubhrajyoti Datta 	case 189:	err_str = "PSX_CMN_3 PD block consolidated error"; break;
696d5fe2fecSShubhrajyoti Datta 	case 191:	err_str = "FPD_INT_WRAP PD block consolidated error"; break;
697d5fe2fecSShubhrajyoti Datta 	case 232:	err_str = "CRAM Un-Correctable error"; break;
698d5fe2fecSShubhrajyoti Datta 	default:	err_str = "VERSAL_EDAC_ERR_ID: %d"; break;
699d5fe2fecSShubhrajyoti Datta 	}
700d5fe2fecSShubhrajyoti Datta 
701d5fe2fecSShubhrajyoti Datta 	snprintf(mc_priv->message,
702d5fe2fecSShubhrajyoti Datta 		 sizeof(mc_priv->message),
703d5fe2fecSShubhrajyoti Datta 		 "[VERSAL_EDAC_ERR_ID: %d] Error type: %s", error_id, err_str);
704d5fe2fecSShubhrajyoti Datta 
705d5fe2fecSShubhrajyoti Datta 	/* Convert to bytes */
706d5fe2fecSShubhrajyoti Datta 	length = result[TOTAL_ERR_LENGTH] * 4;
707d5fe2fecSShubhrajyoti Datta 	log_non_standard_event(sec_type, &amd_versalnet_guid, mc_priv->message,
708d5fe2fecSShubhrajyoti Datta 			       sec_sev, (void *)&result[ERROR_DATA], length);
709d5fe2fecSShubhrajyoti Datta 
710d5fe2fecSShubhrajyoti Datta 	return 0;
711d5fe2fecSShubhrajyoti Datta }
712d5fe2fecSShubhrajyoti Datta 
713d5fe2fecSShubhrajyoti Datta static struct rpmsg_device_id amd_rpmsg_id_table[] = {
714d5fe2fecSShubhrajyoti Datta 	{ .name = "error_ipc" },
715d5fe2fecSShubhrajyoti Datta 	{ },
716d5fe2fecSShubhrajyoti Datta };
717d5fe2fecSShubhrajyoti Datta MODULE_DEVICE_TABLE(rpmsg, amd_rpmsg_id_table);
718d5fe2fecSShubhrajyoti Datta 
rpmsg_probe(struct rpmsg_device * rpdev)719d5fe2fecSShubhrajyoti Datta static int rpmsg_probe(struct rpmsg_device *rpdev)
720d5fe2fecSShubhrajyoti Datta {
721d5fe2fecSShubhrajyoti Datta 	struct rpmsg_channel_info chinfo;
722d5fe2fecSShubhrajyoti Datta 	struct mc_priv *pg;
723d5fe2fecSShubhrajyoti Datta 
724d5fe2fecSShubhrajyoti Datta 	pg = (struct mc_priv *)amd_rpmsg_id_table[0].driver_data;
725d5fe2fecSShubhrajyoti Datta 	chinfo.src = RPMSG_ADDR_ANY;
726d5fe2fecSShubhrajyoti Datta 	chinfo.dst = rpdev->dst;
727d5fe2fecSShubhrajyoti Datta 	strscpy(chinfo.name, amd_rpmsg_id_table[0].name,
728d5fe2fecSShubhrajyoti Datta 		strlen(amd_rpmsg_id_table[0].name));
729d5fe2fecSShubhrajyoti Datta 
730d5fe2fecSShubhrajyoti Datta 	pg->ept = rpmsg_create_ept(rpdev, rpmsg_cb, NULL, chinfo);
731d5fe2fecSShubhrajyoti Datta 	if (!pg->ept)
732d5fe2fecSShubhrajyoti Datta 		return dev_err_probe(&rpdev->dev, -ENXIO, "Failed to create ept for channel %s\n",
733d5fe2fecSShubhrajyoti Datta 				     chinfo.name);
734d5fe2fecSShubhrajyoti Datta 
735d5fe2fecSShubhrajyoti Datta 	dev_set_drvdata(&rpdev->dev, pg);
736d5fe2fecSShubhrajyoti Datta 
737d5fe2fecSShubhrajyoti Datta 	return 0;
738d5fe2fecSShubhrajyoti Datta }
739d5fe2fecSShubhrajyoti Datta 
rpmsg_remove(struct rpmsg_device * rpdev)740d5fe2fecSShubhrajyoti Datta static void rpmsg_remove(struct rpmsg_device *rpdev)
741d5fe2fecSShubhrajyoti Datta {
742d5fe2fecSShubhrajyoti Datta 	struct mc_priv *mc_priv = dev_get_drvdata(&rpdev->dev);
743d5fe2fecSShubhrajyoti Datta 
744d5fe2fecSShubhrajyoti Datta 	rpmsg_destroy_ept(mc_priv->ept);
745d5fe2fecSShubhrajyoti Datta 	dev_set_drvdata(&rpdev->dev, NULL);
746d5fe2fecSShubhrajyoti Datta }
747d5fe2fecSShubhrajyoti Datta 
748d5fe2fecSShubhrajyoti Datta static struct rpmsg_driver amd_rpmsg_driver = {
749d5fe2fecSShubhrajyoti Datta 	.drv.name = KBUILD_MODNAME,
750d5fe2fecSShubhrajyoti Datta 	.probe = rpmsg_probe,
751d5fe2fecSShubhrajyoti Datta 	.remove = rpmsg_remove,
752d5fe2fecSShubhrajyoti Datta 	.callback = rpmsg_cb,
753d5fe2fecSShubhrajyoti Datta 	.id_table = amd_rpmsg_id_table,
754d5fe2fecSShubhrajyoti Datta };
755d5fe2fecSShubhrajyoti Datta 
versal_edac_release(struct device * dev)756d5fe2fecSShubhrajyoti Datta static void versal_edac_release(struct device *dev)
757d5fe2fecSShubhrajyoti Datta {
758d5fe2fecSShubhrajyoti Datta 	kfree(dev);
759d5fe2fecSShubhrajyoti Datta }
760d5fe2fecSShubhrajyoti Datta 
init_versalnet(struct mc_priv * priv,struct platform_device * pdev)761d5fe2fecSShubhrajyoti Datta static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev)
762d5fe2fecSShubhrajyoti Datta {
763d5fe2fecSShubhrajyoti Datta 	u32 num_chans, rank, dwidth, config;
764d5fe2fecSShubhrajyoti Datta 	struct edac_mc_layer layers[2];
765d5fe2fecSShubhrajyoti Datta 	struct mem_ctl_info *mci;
766d5fe2fecSShubhrajyoti Datta 	struct device *dev;
767d5fe2fecSShubhrajyoti Datta 	enum dev_type dt;
768d5fe2fecSShubhrajyoti Datta 	char *name;
769d5fe2fecSShubhrajyoti Datta 	int rc, i;
770d5fe2fecSShubhrajyoti Datta 
771d5fe2fecSShubhrajyoti Datta 	for (i = 0; i < NUM_CONTROLLERS; i++) {
772d5fe2fecSShubhrajyoti Datta 		config = priv->adec[CONF + i * ADEC_NUM];
773d5fe2fecSShubhrajyoti Datta 		num_chans = FIELD_GET(MC5_NUM_CHANS_MASK, config);
774d5fe2fecSShubhrajyoti Datta 		rank = 1 << FIELD_GET(MC5_RANK_MASK, config);
775d5fe2fecSShubhrajyoti Datta 		dwidth = FIELD_GET(MC5_BUS_WIDTH_MASK, config);
776d5fe2fecSShubhrajyoti Datta 
777d5fe2fecSShubhrajyoti Datta 		switch (dwidth) {
778d5fe2fecSShubhrajyoti Datta 		case XDDR5_BUS_WIDTH_16:
779d5fe2fecSShubhrajyoti Datta 			dt = DEV_X16;
780d5fe2fecSShubhrajyoti Datta 			break;
781d5fe2fecSShubhrajyoti Datta 		case XDDR5_BUS_WIDTH_32:
782d5fe2fecSShubhrajyoti Datta 			dt = DEV_X32;
783d5fe2fecSShubhrajyoti Datta 			break;
784d5fe2fecSShubhrajyoti Datta 		case XDDR5_BUS_WIDTH_64:
785d5fe2fecSShubhrajyoti Datta 			dt = DEV_X64;
786d5fe2fecSShubhrajyoti Datta 			break;
787d5fe2fecSShubhrajyoti Datta 		default:
788d5fe2fecSShubhrajyoti Datta 			dt = DEV_UNKNOWN;
789d5fe2fecSShubhrajyoti Datta 		}
790d5fe2fecSShubhrajyoti Datta 
791d5fe2fecSShubhrajyoti Datta 		if (dt == DEV_UNKNOWN)
792d5fe2fecSShubhrajyoti Datta 			continue;
793d5fe2fecSShubhrajyoti Datta 
794d5fe2fecSShubhrajyoti Datta 		/* Find the first enabled device and register that one. */
795d5fe2fecSShubhrajyoti Datta 		layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
796d5fe2fecSShubhrajyoti Datta 		layers[0].size = rank;
797d5fe2fecSShubhrajyoti Datta 		layers[0].is_virt_csrow = true;
798d5fe2fecSShubhrajyoti Datta 		layers[1].type = EDAC_MC_LAYER_CHANNEL;
799d5fe2fecSShubhrajyoti Datta 		layers[1].size = num_chans;
800d5fe2fecSShubhrajyoti Datta 		layers[1].is_virt_csrow = false;
801d5fe2fecSShubhrajyoti Datta 
802d5fe2fecSShubhrajyoti Datta 		rc = -ENOMEM;
803d5fe2fecSShubhrajyoti Datta 		mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers,
804d5fe2fecSShubhrajyoti Datta 				    sizeof(struct mc_priv));
805d5fe2fecSShubhrajyoti Datta 		if (!mci) {
806d5fe2fecSShubhrajyoti Datta 			edac_printk(KERN_ERR, EDAC_MC, "Failed memory allocation for MC%d\n", i);
807d5fe2fecSShubhrajyoti Datta 			goto err_alloc;
808d5fe2fecSShubhrajyoti Datta 		}
809d5fe2fecSShubhrajyoti Datta 
810d5fe2fecSShubhrajyoti Datta 		priv->mci[i] = mci;
811d5fe2fecSShubhrajyoti Datta 		priv->dwidth = dt;
812d5fe2fecSShubhrajyoti Datta 
813d5fe2fecSShubhrajyoti Datta 		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
814d5fe2fecSShubhrajyoti Datta 		dev->release = versal_edac_release;
815d5fe2fecSShubhrajyoti Datta 		name = kmalloc(32, GFP_KERNEL);
816d5fe2fecSShubhrajyoti Datta 		sprintf(name, "versal-net-ddrmc5-edac-%d", i);
817d5fe2fecSShubhrajyoti Datta 		dev->init_name = name;
818d5fe2fecSShubhrajyoti Datta 		rc = device_register(dev);
819d5fe2fecSShubhrajyoti Datta 		if (rc)
820d5fe2fecSShubhrajyoti Datta 			goto err_alloc;
821d5fe2fecSShubhrajyoti Datta 
822d5fe2fecSShubhrajyoti Datta 		mci->pdev = dev;
823d5fe2fecSShubhrajyoti Datta 
824d5fe2fecSShubhrajyoti Datta 		platform_set_drvdata(pdev, priv);
825d5fe2fecSShubhrajyoti Datta 
826d5fe2fecSShubhrajyoti Datta 		mc_init(mci, dev);
827d5fe2fecSShubhrajyoti Datta 		rc = edac_mc_add_mc(mci);
828d5fe2fecSShubhrajyoti Datta 		if (rc) {
829d5fe2fecSShubhrajyoti Datta 			edac_printk(KERN_ERR, EDAC_MC, "Failed to register MC%d with EDAC core\n", i);
830d5fe2fecSShubhrajyoti Datta 			goto err_alloc;
831d5fe2fecSShubhrajyoti Datta 		}
832d5fe2fecSShubhrajyoti Datta 	}
833d5fe2fecSShubhrajyoti Datta 	return 0;
834d5fe2fecSShubhrajyoti Datta 
835d5fe2fecSShubhrajyoti Datta err_alloc:
836d5fe2fecSShubhrajyoti Datta 	while (i--) {
837d5fe2fecSShubhrajyoti Datta 		mci = priv->mci[i];
838d5fe2fecSShubhrajyoti Datta 		if (!mci)
839d5fe2fecSShubhrajyoti Datta 			continue;
840d5fe2fecSShubhrajyoti Datta 
841d5fe2fecSShubhrajyoti Datta 		if (mci->pdev) {
842d5fe2fecSShubhrajyoti Datta 			device_unregister(mci->pdev);
843d5fe2fecSShubhrajyoti Datta 			edac_mc_del_mc(mci->pdev);
844d5fe2fecSShubhrajyoti Datta 		}
845d5fe2fecSShubhrajyoti Datta 
846d5fe2fecSShubhrajyoti Datta 		edac_mc_free(mci);
847d5fe2fecSShubhrajyoti Datta 	}
848d5fe2fecSShubhrajyoti Datta 
849d5fe2fecSShubhrajyoti Datta 	return rc;
850d5fe2fecSShubhrajyoti Datta }
851d5fe2fecSShubhrajyoti Datta 
remove_versalnet(struct mc_priv * priv)852d5fe2fecSShubhrajyoti Datta static void remove_versalnet(struct mc_priv *priv)
853d5fe2fecSShubhrajyoti Datta {
854d5fe2fecSShubhrajyoti Datta 	struct mem_ctl_info *mci;
855d5fe2fecSShubhrajyoti Datta 	int i;
856d5fe2fecSShubhrajyoti Datta 
857d5fe2fecSShubhrajyoti Datta 	for (i = 0; i < NUM_CONTROLLERS; i++) {
858d5fe2fecSShubhrajyoti Datta 		device_unregister(priv->mci[i]->pdev);
859d5fe2fecSShubhrajyoti Datta 		mci = edac_mc_del_mc(priv->mci[i]->pdev);
860d5fe2fecSShubhrajyoti Datta 		if (!mci)
861d5fe2fecSShubhrajyoti Datta 			return;
862d5fe2fecSShubhrajyoti Datta 
863d5fe2fecSShubhrajyoti Datta 		edac_mc_free(mci);
864d5fe2fecSShubhrajyoti Datta 	}
865d5fe2fecSShubhrajyoti Datta }
866d5fe2fecSShubhrajyoti Datta 
mc_probe(struct platform_device * pdev)867d5fe2fecSShubhrajyoti Datta static int mc_probe(struct platform_device *pdev)
868d5fe2fecSShubhrajyoti Datta {
869d5fe2fecSShubhrajyoti Datta 	struct device_node *r5_core_node;
870d5fe2fecSShubhrajyoti Datta 	struct mc_priv *priv;
871d5fe2fecSShubhrajyoti Datta 	struct rproc *rp;
872d5fe2fecSShubhrajyoti Datta 	int rc;
873d5fe2fecSShubhrajyoti Datta 
874d5fe2fecSShubhrajyoti Datta 	r5_core_node = of_parse_phandle(pdev->dev.of_node, "amd,rproc", 0);
875d5fe2fecSShubhrajyoti Datta 	if (!r5_core_node) {
876d5fe2fecSShubhrajyoti Datta 		dev_err(&pdev->dev, "amd,rproc: invalid phandle\n");
877d5fe2fecSShubhrajyoti Datta 		return -EINVAL;
878d5fe2fecSShubhrajyoti Datta 	}
879d5fe2fecSShubhrajyoti Datta 
880d5fe2fecSShubhrajyoti Datta 	rp = rproc_get_by_phandle(r5_core_node->phandle);
881d5fe2fecSShubhrajyoti Datta 	if (!rp)
882d5fe2fecSShubhrajyoti Datta 		return -EPROBE_DEFER;
883d5fe2fecSShubhrajyoti Datta 
884d5fe2fecSShubhrajyoti Datta 	rc = rproc_boot(rp);
885d5fe2fecSShubhrajyoti Datta 	if (rc) {
886d5fe2fecSShubhrajyoti Datta 		dev_err(&pdev->dev, "Failed to attach to remote processor\n");
887d5fe2fecSShubhrajyoti Datta 		goto err_rproc_boot;
888d5fe2fecSShubhrajyoti Datta 	}
889d5fe2fecSShubhrajyoti Datta 
890d5fe2fecSShubhrajyoti Datta 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
891*c2fcb2e7SDan Carpenter 	if (!priv) {
892*c2fcb2e7SDan Carpenter 		rc = -ENOMEM;
893d5fe2fecSShubhrajyoti Datta 		goto err_alloc;
894*c2fcb2e7SDan Carpenter 	}
895d5fe2fecSShubhrajyoti Datta 
896d5fe2fecSShubhrajyoti Datta 	amd_rpmsg_id_table[0].driver_data = (kernel_ulong_t)priv;
897d5fe2fecSShubhrajyoti Datta 
898d5fe2fecSShubhrajyoti Datta 	rc = register_rpmsg_driver(&amd_rpmsg_driver);
899d5fe2fecSShubhrajyoti Datta 	if (rc) {
900d5fe2fecSShubhrajyoti Datta 		edac_printk(KERN_ERR, EDAC_MC, "Failed to register RPMsg driver: %d\n", rc);
901d5fe2fecSShubhrajyoti Datta 		goto err_alloc;
902d5fe2fecSShubhrajyoti Datta 	}
903d5fe2fecSShubhrajyoti Datta 
904d5fe2fecSShubhrajyoti Datta 	rc = setup_mcdi(priv);
905d5fe2fecSShubhrajyoti Datta 	if (rc)
906d5fe2fecSShubhrajyoti Datta 		goto err_unreg;
907d5fe2fecSShubhrajyoti Datta 
908d5fe2fecSShubhrajyoti Datta 	priv->mcdi->r5_rproc = rp;
909d5fe2fecSShubhrajyoti Datta 
910d5fe2fecSShubhrajyoti Datta 	rc = init_versalnet(priv, pdev);
911d5fe2fecSShubhrajyoti Datta 	if (rc)
912d5fe2fecSShubhrajyoti Datta 		goto err_init;
913d5fe2fecSShubhrajyoti Datta 
914d5fe2fecSShubhrajyoti Datta 	return 0;
915d5fe2fecSShubhrajyoti Datta 
916d5fe2fecSShubhrajyoti Datta err_init:
917d5fe2fecSShubhrajyoti Datta 	cdx_mcdi_finish(priv->mcdi);
918d5fe2fecSShubhrajyoti Datta 
919d5fe2fecSShubhrajyoti Datta err_unreg:
920d5fe2fecSShubhrajyoti Datta 	unregister_rpmsg_driver(&amd_rpmsg_driver);
921d5fe2fecSShubhrajyoti Datta 
922d5fe2fecSShubhrajyoti Datta err_alloc:
923d5fe2fecSShubhrajyoti Datta 	rproc_shutdown(rp);
924d5fe2fecSShubhrajyoti Datta 
925d5fe2fecSShubhrajyoti Datta err_rproc_boot:
926d5fe2fecSShubhrajyoti Datta 	rproc_put(rp);
927d5fe2fecSShubhrajyoti Datta 
928d5fe2fecSShubhrajyoti Datta 	return rc;
929d5fe2fecSShubhrajyoti Datta }
930d5fe2fecSShubhrajyoti Datta 
mc_remove(struct platform_device * pdev)931d5fe2fecSShubhrajyoti Datta static void mc_remove(struct platform_device *pdev)
932d5fe2fecSShubhrajyoti Datta {
933d5fe2fecSShubhrajyoti Datta 	struct mc_priv *priv = platform_get_drvdata(pdev);
934d5fe2fecSShubhrajyoti Datta 
935d5fe2fecSShubhrajyoti Datta 	unregister_rpmsg_driver(&amd_rpmsg_driver);
936d5fe2fecSShubhrajyoti Datta 	remove_versalnet(priv);
937d5fe2fecSShubhrajyoti Datta 	rproc_shutdown(priv->mcdi->r5_rproc);
938d5fe2fecSShubhrajyoti Datta 	cdx_mcdi_finish(priv->mcdi);
939d5fe2fecSShubhrajyoti Datta }
940d5fe2fecSShubhrajyoti Datta 
941d5fe2fecSShubhrajyoti Datta static const struct of_device_id amd_edac_match[] = {
942d5fe2fecSShubhrajyoti Datta 	{ .compatible = "xlnx,versal-net-ddrmc5", },
943d5fe2fecSShubhrajyoti Datta 	{}
944d5fe2fecSShubhrajyoti Datta };
945d5fe2fecSShubhrajyoti Datta MODULE_DEVICE_TABLE(of, amd_edac_match);
946d5fe2fecSShubhrajyoti Datta 
947d5fe2fecSShubhrajyoti Datta static struct platform_driver amd_ddr_edac_mc_driver = {
948d5fe2fecSShubhrajyoti Datta 	.driver = {
949d5fe2fecSShubhrajyoti Datta 		.name = "versal-net-edac",
950d5fe2fecSShubhrajyoti Datta 		.of_match_table = amd_edac_match,
951d5fe2fecSShubhrajyoti Datta 	},
952d5fe2fecSShubhrajyoti Datta 	.probe = mc_probe,
953d5fe2fecSShubhrajyoti Datta 	.remove = mc_remove,
954d5fe2fecSShubhrajyoti Datta };
955d5fe2fecSShubhrajyoti Datta 
956d5fe2fecSShubhrajyoti Datta module_platform_driver(amd_ddr_edac_mc_driver);
957d5fe2fecSShubhrajyoti Datta 
958d5fe2fecSShubhrajyoti Datta MODULE_AUTHOR("AMD Inc");
959d5fe2fecSShubhrajyoti Datta MODULE_DESCRIPTION("Versal NET EDAC driver");
960d5fe2fecSShubhrajyoti Datta MODULE_LICENSE("GPL");
961