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