1 /*
2  * Copyright (c) 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/ztest.h>
10 #include <zephyr/tc_util.h>
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(test, CONFIG_LOG_DEFAULT_LEVEL);
14 
15 #include <zephyr/drivers/edac.h>
16 #include <ibecc.h>
17 
18 #define TEST_ADDRESS1		0x1000
19 #define TEST_ADDRESS2		0x2000
20 #define TEST_DATA		0xface
21 #define TEST_ADDRESS_MASK	INJ_ADDR_BASE_MASK_MASK
22 #define DURATION		100
23 
ZTEST(ibecc,test_ibecc_driver_initialized)24 ZTEST(ibecc, test_ibecc_driver_initialized)
25 {
26 	const struct device *dev;
27 
28 	LOG_DBG("Test ibecc driver is initialized");
29 
30 	dev = DEVICE_DT_GET(DT_NODELABEL(ibecc));
31 	zassert_true(device_is_ready(dev), "Device is not ready");
32 }
33 
34 K_APPMEM_PARTITION_DEFINE(default_part);
35 
36 K_APP_BMEM(default_part) static volatile int interrupt;
37 K_APP_BMEM(default_part) static volatile uint32_t error_type;
38 K_APP_BMEM(default_part) static volatile uint64_t error_address;
39 K_APP_BMEM(default_part) static volatile uint16_t error_syndrome;
40 
41 /* Keep track or correctable and uncorrectable errors */
42 static unsigned int errors_correctable, errors_uncorrectable;
43 
callback(const struct device * d,void * data)44 static void callback(const struct device *d, void *data)
45 {
46 	struct ibecc_error *error_data = data;
47 
48 	interrupt++;
49 	error_type = error_data->type;
50 	error_address = error_data->address;
51 	error_syndrome = error_data->syndrome;
52 }
53 
ZTEST(ibecc,test_ibecc_api)54 ZTEST(ibecc, test_ibecc_api)
55 {
56 	const struct device *dev;
57 	uint64_t value;
58 	int ret;
59 
60 	LOG_DBG("Test IBECC API");
61 
62 	/* Error log API */
63 
64 	dev = DEVICE_DT_GET(DT_NODELABEL(ibecc));
65 	zassert_true(device_is_ready(dev), "Device is not ready");
66 
67 	ret = edac_ecc_error_log_get(dev, &value);
68 	zassert_equal(ret, -ENODATA, "edac_ecc_error_log_get failed");
69 
70 	ret = edac_ecc_error_log_clear(dev);
71 	zassert_equal(ret, 0, "edac_ecc_error_log_clear failed");
72 
73 	ret = edac_parity_error_log_get(dev, &value);
74 	zassert_equal(ret, -ENODATA, "edac_parity_error_log_get failed");
75 
76 	ret = edac_parity_error_log_clear(dev);
77 	zassert_equal(ret, 0, "edac_parity_error_log_clear failed");
78 
79 	/* Error stat API */
80 
81 	ret = edac_errors_cor_get(dev);
82 	zassert_equal(ret, errors_correctable,
83 		      "Error correctable count does not match");
84 
85 	ret = edac_errors_uc_get(dev);
86 	zassert_equal(ret, errors_uncorrectable,
87 		      "Error uncorrectable count does mot match");
88 
89 	/* Notification API */
90 
91 	ret = edac_notify_callback_set(dev, callback);
92 	zassert_equal(ret, 0, "Error setting notification callback");
93 }
94 
ZTEST(ibecc,test_ibecc_error_inject_api)95 ZTEST(ibecc, test_ibecc_error_inject_api)
96 {
97 	const struct device *dev;
98 	uint32_t test_value;
99 	uint64_t val;
100 	int ret;
101 
102 	Z_TEST_SKIP_IFNDEF(CONFIG_EDAC_ERROR_INJECT);
103 
104 	LOG_DBG("Test IBECC Inject API");
105 
106 	dev = DEVICE_DT_GET(DT_NODELABEL(ibecc));
107 	zassert_true(device_is_ready(dev), "Device is not ready");
108 
109 	/* Verify default parameters */
110 
111 	ret = edac_inject_get_error_type(dev, &test_value);
112 	zassert_equal(ret, 0, "Error getting error_type");
113 	zassert_equal(test_value, 0, "Error type not zero");
114 
115 	ret = edac_inject_get_param1(dev, &val);
116 	zassert_equal(ret, 0, "Error getting param1");
117 	zassert_equal(val, 0, "Error param1 is not zero");
118 
119 	ret = edac_inject_get_param2(dev, &val);
120 	zassert_equal(ret, 0, "Error getting param2");
121 	zassert_equal(val, 0, "Error param2 is not zero");
122 
123 	/* Verify basic Injection API operations */
124 
125 	/* Set correct value of param1 */
126 	ret = edac_inject_set_param1(dev, TEST_ADDRESS1);
127 	zassert_equal(ret, 0, "Error setting inject address");
128 
129 	/* Try to set incorrect value of param1 with UINT64_MAX */
130 	ret = edac_inject_set_param1(dev, UINT64_MAX);
131 	zassert_not_equal(ret, 0, "Error setting invalid param1");
132 
133 	ret = edac_inject_get_param1(dev, &val);
134 	zassert_equal(ret, 0, "Error getting param1");
135 	zassert_equal(val, TEST_ADDRESS1, "Read back value differs");
136 
137 	/* Set correct value of param2 */
138 	ret = edac_inject_set_param2(dev, TEST_ADDRESS_MASK);
139 	zassert_equal(ret, 0, "Error setting inject address mask");
140 
141 	/* Try to set incorrect value of param2 with UINT64_MAX */
142 	ret = edac_inject_set_param2(dev, UINT64_MAX);
143 	zassert_not_equal(ret, 0, "Error setting invalid param1");
144 
145 	ret = edac_inject_get_param2(dev, &val);
146 	zassert_equal(ret, 0, "Error getting param2");
147 	zassert_equal(val, TEST_ADDRESS_MASK, "Read back value differs");
148 
149 	/* Clearing parameters */
150 
151 	ret = edac_inject_set_param1(dev, 0);
152 	zassert_equal(ret, 0, "Error setting inject address");
153 
154 	ret = edac_inject_get_param1(dev, &val);
155 	zassert_equal(ret, 0, "Error getting param1");
156 	zassert_equal(val, 0, "Read back value differs");
157 
158 	ret = edac_inject_set_param2(dev, 0);
159 	zassert_equal(ret, 0, "Error setting inject address mask");
160 
161 	ret = edac_inject_get_param2(dev, &val);
162 	zassert_equal(ret, 0, "Error getting param2");
163 	zassert_equal(val, 0, "Read back value differs");
164 }
165 
test_inject(const struct device * dev,uint64_t addr,uint64_t mask,uint8_t type)166 static void test_inject(const struct device *dev, uint64_t addr, uint64_t mask,
167 			uint8_t type)
168 {
169 	unsigned int errors_cor, errors_uc;
170 	uint64_t test_addr;
171 	uint32_t test_value;
172 	int ret, num_int;
173 
174 	interrupt = 0;
175 
176 	/* Test error_trigger() for unset error type */
177 	ret = edac_inject_error_trigger(dev);
178 	zassert_equal(ret, 0, "Error setting ctrl");
179 
180 	errors_cor = edac_errors_cor_get(dev);
181 	zassert_not_equal(errors_cor, -ENOSYS, "Not implemented error count");
182 
183 	errors_uc = edac_errors_uc_get(dev);
184 	zassert_not_equal(errors_uc, -ENOSYS, "Not implemented error count");
185 
186 	ret = edac_inject_set_param1(dev, addr);
187 	zassert_equal(ret, 0, "Error setting inject address");
188 
189 	ret = edac_inject_set_param2(dev, mask);
190 	zassert_equal(ret, 0, "Error setting inject address mask");
191 
192 	/* Test correctable error inject */
193 	ret = edac_inject_set_error_type(dev, type);
194 	zassert_equal(ret, 0, "Error setting inject error type");
195 
196 	ret = edac_inject_get_error_type(dev, &test_value);
197 	zassert_equal(ret, 0, "Error getting error_type");
198 	zassert_equal(test_value, type, "Read back value differs");
199 
200 	ret = edac_inject_error_trigger(dev);
201 	zassert_equal(ret, 0, "Error setting ctrl");
202 
203 	device_map((mm_reg_t *)&test_addr, addr, 0x100, K_MEM_CACHE_NONE);
204 	LOG_DBG("Mapped 0x%llx to 0x%llx", addr, test_addr);
205 
206 	test_value = sys_read32(test_addr);
207 	LOG_DBG("Read value 0x%llx: 0x%x", test_addr, test_value);
208 
209 	/* Write to this test address some data */
210 	sys_write32(TEST_DATA, test_addr);
211 	LOG_DBG("Wrote value 0x%x at 0x%llx", TEST_DATA, test_addr);
212 
213 	/* Read back, triggering interrupt and notification */
214 	test_value = sys_read32(test_addr);
215 	LOG_DBG("Read value 0x%llx: 0x%x", test_addr, test_value);
216 
217 	/* Wait for interrupt if needed */
218 	k_busy_wait(USEC_PER_MSEC * DURATION);
219 
220 	/* Load to local variable to avoid using volatile in assert */
221 	num_int = interrupt;
222 
223 	zassert_not_equal(num_int, 0, "Interrupt handler did not execute");
224 	zassert_equal(num_int, 1,
225 		      "Interrupt handler executed more than once! (%d)\n",
226 		      num_int);
227 
228 	LOG_DBG("Interrupt %d", num_int);
229 	LOG_DBG("Error: type %u, address 0x%llx, syndrome %u",
230 		error_type, error_address, error_syndrome);
231 
232 	/* Check statistic information */
233 
234 	ret = edac_errors_cor_get(dev);
235 	zassert_equal(ret, type == EDAC_ERROR_TYPE_DRAM_COR ?
236 		      errors_cor + 1 : errors_cor,
237 		      "Incorrect correctable count");
238 	LOG_DBG("Correctable error count %d", ret);
239 
240 	errors_correctable = ret;
241 
242 	ret = edac_errors_uc_get(dev);
243 	zassert_equal(ret, type == EDAC_ERROR_TYPE_DRAM_UC ?
244 		      errors_uc + 1 : errors_uc,
245 		      "Incorrect uncorrectable count");
246 	LOG_DBG("Uncorrectable error count %d", ret);
247 
248 	errors_uncorrectable = ret;
249 
250 	/* Clear */
251 
252 	ret = edac_inject_set_error_type(dev, 0);
253 	zassert_equal(ret, 0, "Error setting inject error type");
254 
255 	ret = edac_inject_set_param1(dev, 0);
256 	zassert_equal(ret, 0, "Error setting inject address");
257 
258 	ret = edac_inject_set_param2(dev, 0);
259 	zassert_equal(ret, 0, "Error setting inject address mask");
260 
261 	ret = edac_inject_error_trigger(dev);
262 	zassert_equal(ret, 0, "Error setting ctrl");
263 }
264 
check_values(void * p1,void * p2,void * p3)265 static void check_values(void *p1, void *p2, void *p3)
266 {
267 	ARG_UNUSED(p3);
268 
269 	intptr_t address = (intptr_t)p1;
270 	intptr_t type = (intptr_t)p2;
271 	intptr_t addr, errtype;
272 
273 #if defined(CONFIG_USERSPACE)
274 	LOG_DBG("Test communication in user mode thread");
275 	zassert_true(k_is_user_context(), "thread left in kernel mode");
276 #endif
277 
278 	/* Load to local variables to avoid using volatile in assert */
279 	addr = error_address;
280 	errtype = error_type;
281 
282 	/* Verify page address and error type */
283 	zassert_equal(addr, address, "Error address wrong");
284 	zassert_equal(errtype, type, "Error type wrong");
285 }
286 
ibecc_error_inject_test(uint64_t addr,uint64_t mask,uint64_t type)287 static void ibecc_error_inject_test(uint64_t addr, uint64_t mask, uint64_t type)
288 {
289 	const struct device *dev;
290 	int ret;
291 
292 	dev = DEVICE_DT_GET(DT_NODELABEL(ibecc));
293 	zassert_true(device_is_ready(dev), "Device is not ready");
294 
295 	ret = edac_notify_callback_set(dev, callback);
296 	zassert_equal(ret, 0, "Error setting notification callback");
297 
298 	/* Test injecting correctable error at address TEST_ADDRESS1 */
299 	test_inject(dev, addr, mask, type);
300 
301 #if defined(CONFIG_USERSPACE)
302 	k_thread_user_mode_enter(check_values,
303 				 (void *)addr,
304 				 (void *)type,
305 				 NULL);
306 #else
307 	check_values((void *)addr, (void *)type, NULL);
308 #endif
309 }
310 
ZTEST(ibecc,test_ibecc_error_inject_test_cor)311 ZTEST(ibecc, test_ibecc_error_inject_test_cor)
312 {
313 	Z_TEST_SKIP_IFNDEF(CONFIG_EDAC_ERROR_INJECT);
314 
315 	LOG_DBG("Test IBECC injection correctable error");
316 
317 	ibecc_error_inject_test(TEST_ADDRESS1, TEST_ADDRESS_MASK,
318 				EDAC_ERROR_TYPE_DRAM_COR);
319 }
320 
ZTEST(ibecc,test_ibecc_error_inject_test_uc)321 ZTEST(ibecc, test_ibecc_error_inject_test_uc)
322 {
323 	Z_TEST_SKIP_IFNDEF(CONFIG_EDAC_ERROR_INJECT);
324 
325 	LOG_DBG("Test IBECC injection uncorrectable error");
326 
327 	ibecc_error_inject_test(TEST_ADDRESS2, TEST_ADDRESS_MASK,
328 				EDAC_ERROR_TYPE_DRAM_UC);
329 }
330 
setup_ibecc(void)331 static void *setup_ibecc(void)
332 {
333 #if defined(CONFIG_USERSPACE)
334 	int ret = k_mem_domain_add_partition(&k_mem_domain_default,
335 					     &default_part);
336 	if (ret != 0) {
337 		LOG_ERR("Failed to add to mem domain (%d)", ret);
338 		LOG_ERR("Running test setup function second time?");
339 		ztest_test_fail();
340 	}
341 #endif
342 	return NULL;
343 }
344 
345 ZTEST_SUITE(ibecc, NULL, setup_ibecc, NULL, NULL, NULL);
346