1 /*
2  * Copyright (c) 2022 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/tc_util.h>
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/random/random.h>
11 
12 #include <zephyr/drivers/pcie/pcie.h>
13 #include <zephyr/drivers/smbus.h>
14 
15 #include "emul.h"
16 
17 #define PERIPH_ADDR	0x10
18 
mock_sys_in8(io_port_t port)19 static uint8_t mock_sys_in8(io_port_t port)
20 {
21 	return emul_in8(port);
22 }
23 
mock_sys_out8(uint8_t data,io_port_t port)24 static void mock_sys_out8(uint8_t data, io_port_t port)
25 {
26 	emul_out8(data, port);
27 }
28 
mock_conf_read(pcie_bdf_t bdf,unsigned int reg)29 static uint32_t mock_conf_read(pcie_bdf_t bdf, unsigned int reg)
30 {
31 	return emul_pci_read(reg);
32 }
33 
34 #if defined(PCIE_CONF_WRITE)
mock_conf_write(pcie_bdf_t bdf,unsigned int reg,uint32_t data)35 static void mock_conf_write(pcie_bdf_t bdf, unsigned int reg, uint32_t data)
36 {
37 	emul_pci_write(bdf, reg, data);
38 }
39 
40 #define pcie_conf_write(bdf, reg, val)	mock_conf_write(bdf, reg, val)
41 #endif /* PCIE_CONF_WRITE */
42 
43 /* Redefine PCIE access */
44 #define pcie_conf_read(bdf, reg)	mock_conf_read(bdf, reg)
45 
46 /* Redefine sys_in function */
47 #define sys_in8(port)			mock_sys_in8(port)
48 #define sys_out8(data, port)		mock_sys_out8(data, port)
49 
50 #define CONFIG_SMBUS_INTEL_PCH_ACCESS_IO
51 #define device_map(a, b, c, d)
52 #define pcie_probe(bdf, id)	1
53 #define pcie_set_cmd(a, b, c)
54 
55 #define SMBUS_EMUL	"smbus_emul"
56 
57 #ifdef PERIPHERAL_INT
58 #define CONFIG_SMBUS_INTEL_PCH_SMBALERT		1
59 #define CONFIG_SMBUS_INTEL_PCH_HOST_NOTIFY	1
60 #endif
61 
62 #include "intel_pch_smbus.c"
63 
run_isr(enum emul_isr_type type)64 void run_isr(enum emul_isr_type type)
65 {
66 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
67 
68 	switch (type) {
69 	case EMUL_SMBUS_INTR:
70 		emul_set_io(emul_get_io(PCH_SMBUS_HSTS) |
71 			    PCH_SMBUS_HSTS_INTERRUPT, PCH_SMBUS_HSTS);
72 		break;
73 	case EMUL_SMBUS_SMBALERT:
74 		emul_set_io(emul_get_io(PCH_SMBUS_HSTS) |
75 			    PCH_SMBUS_HSTS_SMB_ALERT, PCH_SMBUS_HSTS);
76 		break;
77 	case EMUL_SMBUS_HOST_NOTIFY:
78 		emul_set_io(emul_get_io(PCH_SMBUS_SSTS)|
79 			    PCH_SMBUS_SSTS_HNS, PCH_SMBUS_SSTS);
80 		peripheral_handle_host_notify();
81 		break;
82 	default:
83 		break;
84 	}
85 
86 	smbus_isr(dev);
87 }
88 
config_function(const struct device * dev)89 static void config_function(const struct device *dev)
90 {
91 	TC_PRINT("Emulator device configuration\n");
92 }
93 static struct pch_data smbus_data;
94 /* Zero initialized, dummy device does not care about pcie ids */
95 static struct pcie_dev pcie_params;
96 static struct pch_config pch_config_data = {
97 	.config_func = config_function,
98 	.pcie = &pcie_params,
99 };
100 
101 DEVICE_DEFINE(dummy_driver, SMBUS_EMUL, &pch_smbus_init,
102 	      NULL, &smbus_data, &pch_config_data, POST_KERNEL,
103 	      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &funcs);
104 
ZTEST(test_smbus_emul,test_byte)105 ZTEST(test_smbus_emul, test_byte)
106 {
107 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
108 	uint8_t snd_byte, rcv_byte;
109 	int ret;
110 
111 	zassert_not_null(dev, "Device not found");
112 
113 	ret = smbus_quick(dev, PERIPH_ADDR, 1);
114 	zassert_ok(ret, "SMBus Quick failed");
115 
116 	snd_byte = (uint8_t)sys_rand32_get();
117 
118 	ret = smbus_byte_write(dev, PERIPH_ADDR, snd_byte);
119 	zassert_ok(ret, "SMBus Byte Write failed");
120 
121 	ret = smbus_byte_read(dev, PERIPH_ADDR, &rcv_byte);
122 	zassert_ok(ret, "SMBus Byte Read failed");
123 
124 	zassert_equal(snd_byte, rcv_byte, "Data mismatch");
125 
126 	ret = smbus_byte_data_write(dev, PERIPH_ADDR, 0, snd_byte);
127 	zassert_ok(ret, "SMBus Byte Data Write failed");
128 
129 	ret = smbus_byte_data_read(dev, PERIPH_ADDR, 0, &rcv_byte);
130 	zassert_ok(ret, "SMBus Byte Data Read failed");
131 
132 	zassert_equal(snd_byte, rcv_byte, "Data mismatch");
133 }
134 
ZTEST(test_smbus_emul,test_word)135 ZTEST(test_smbus_emul, test_word)
136 {
137 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
138 	uint16_t snd_word, rcv_word;
139 	uint8_t snd_byte;
140 	int ret;
141 
142 	zassert_not_null(dev, "Device not found");
143 
144 	snd_word = (uint16_t)sys_rand32_get();
145 
146 	ret = smbus_word_data_write(dev, PERIPH_ADDR, 0, snd_word);
147 	zassert_ok(ret, "SMBus Word Data Write failed");
148 
149 	ret = smbus_word_data_read(dev, PERIPH_ADDR, 0, &rcv_word);
150 	zassert_ok(ret, "SMBus Byte Data Read failed");
151 
152 	zassert_equal(snd_word, rcv_word, "Data mismatch");
153 
154 	/* Test 2 byte writes following word read */
155 
156 	snd_byte = (uint8_t)sys_rand32_get();
157 
158 	ret = smbus_byte_data_write(dev, PERIPH_ADDR, 0, snd_byte);
159 	zassert_ok(ret, "SMBus Byte Data Write failed");
160 	ret = smbus_byte_data_write(dev, PERIPH_ADDR, 1, snd_byte);
161 	zassert_ok(ret, "SMBus Byte Data Write failed");
162 
163 	ret = smbus_word_data_read(dev, PERIPH_ADDR, 0, &rcv_word);
164 	zassert_ok(ret, "SMBus Byte Data Read failed");
165 
166 	zassert_equal(snd_byte << 8 | snd_byte, rcv_word, "Data mismatch");
167 }
168 
ZTEST(test_smbus_emul,test_proc_call)169 ZTEST(test_smbus_emul, test_proc_call)
170 {
171 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
172 	uint16_t snd_word, rcv_word;
173 	int ret;
174 
175 	zassert_not_null(dev, "Device not found");
176 
177 	snd_word = (uint16_t)sys_rand32_get();
178 	zassert_not_equal(snd_word, 0, "Random number generator misconfgured");
179 
180 	ret = smbus_pcall(dev, PERIPH_ADDR, 0x0, snd_word, &rcv_word);
181 	zassert_ok(ret, "SMBus Proc Call failed");
182 
183 	/* Our emulated Proc Call swaps bytes */
184 	zassert_equal(snd_word, BSWAP_16(rcv_word), "Data mismatch");
185 }
186 
ZTEST(test_smbus_emul,test_block)187 ZTEST(test_smbus_emul, test_block)
188 {
189 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
190 	uint8_t snd_block[SMBUS_BLOCK_BYTES_MAX];
191 	uint8_t rcv_block[SMBUS_BLOCK_BYTES_MAX];
192 	uint8_t snd_count, rcv_count;
193 	int ret;
194 
195 	zassert_not_null(dev, "Device not found");
196 
197 	for (int i = 0; i < sizeof(snd_block); i++) {
198 		snd_block[i] = (uint8_t)sys_rand32_get();
199 	}
200 
201 	snd_count = sizeof(snd_block);
202 
203 	ret = smbus_block_write(dev, PERIPH_ADDR, 0, snd_count, snd_block);
204 	zassert_ok(ret, "SMBUS write block failed, ret %d", ret);
205 
206 	ret = smbus_block_read(dev, PERIPH_ADDR, 0, &rcv_count, rcv_block);
207 	zassert_ok(ret, "SMBUS read block failed, ret %d", ret);
208 
209 	zassert_equal(snd_count, rcv_count, "Block count differs");
210 	zassert_true(!memcmp(snd_block, rcv_block, rcv_count),
211 		     "Data mismatch");
212 }
213 
ZTEST(test_smbus_emul,test_block_pcall)214 ZTEST(test_smbus_emul, test_block_pcall)
215 {
216 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
217 	uint8_t snd_block[SMBUS_BLOCK_BYTES_MAX];
218 	uint8_t rcv_block[SMBUS_BLOCK_BYTES_MAX];
219 	uint8_t snd_count, rcv_count;
220 	int ret;
221 
222 	zassert_not_null(dev, "Device not found");
223 
224 	for (int i = 0; i < sizeof(snd_block); i++) {
225 		snd_block[i] = (uint8_t)sys_rand32_get();
226 	}
227 
228 	snd_count = SMBUS_BLOCK_BYTES_MAX / 2;
229 	ret = smbus_block_pcall(dev, PERIPH_ADDR, 0, snd_count, snd_block,
230 				&rcv_count, rcv_block);
231 	zassert_ok(ret, "SMBUS block pcall failed, ret %d", ret);
232 	zassert_equal(snd_count, rcv_count, "Block count differs");
233 
234 	/**
235 	 * Verify that our emulated peripheral swapped bytes in the block
236 	 * buffer
237 	 */
238 	for (int i = 0; i < rcv_count; i++) {
239 		zassert_equal(snd_block[i], rcv_block[rcv_count - (i + 1)],
240 			      "Data mismatch, not swapped");
241 
242 	}
243 }
244 
245 /* SMBALERT handling */
246 
247 /* False by default */
248 bool smbalert_handled;
249 
smbalert_cb(const struct device * dev,struct smbus_callback * cb,uint8_t addr)250 static void smbalert_cb(const struct device *dev, struct smbus_callback *cb,
251 			uint8_t addr)
252 {
253 	LOG_DBG("SMBALERT callback");
254 
255 	smbalert_handled = true;
256 }
257 
258 struct smbus_callback smbalert_callback = {
259 	.handler = smbalert_cb,
260 	.addr = PERIPH_ADDR,
261 };
262 
263 /* Host Notify handling */
264 
265 /* False by default */
266 bool notify_handled;
267 
notify_cb(const struct device * dev,struct smbus_callback * cb,uint8_t addr)268 static void notify_cb(const struct device *dev, struct smbus_callback *cb,
269 		      uint8_t addr)
270 {
271 	LOG_DBG("Notify callback");
272 
273 	notify_handled = true;
274 }
275 
276 struct smbus_callback notify_callback = {
277 	.handler = notify_cb,
278 	.addr = PERIPH_ADDR,
279 };
280 
281 /* Setup peripheral SMBus device on a bus */
282 
283 struct smbus_peripheral peripheral = {
284 	.addr = PERIPH_ADDR,
285 	.smbalert = true,
286 	.host_notify = true,
287 };
288 
ZTEST(test_smbus_emul,test_alert)289 ZTEST(test_smbus_emul, test_alert)
290 {
291 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
292 	int ret;
293 
294 	Z_TEST_SKIP_IFNDEF(CONFIG_SMBUS_INTEL_PCH_SMBALERT);
295 
296 	zassert_not_null(dev, "Device not found");
297 
298 	/* Try to remove not existing callback */
299 	ret = smbus_smbalert_remove_cb(dev, &smbalert_callback);
300 	zassert_equal(ret, -ENOENT, "Callback remove failed");
301 
302 	/* Set callback */
303 	ret = smbus_smbalert_set_cb(dev, &smbalert_callback);
304 	zassert_ok(ret, "Callback set failed");
305 
306 	/* Emulate SMBus alert from peripheral device */
307 	peripheral_clear_smbalert(&peripheral);
308 	smbalert_handled = false;
309 
310 	/* Run without configure smbalert */
311 	run_isr(EMUL_SMBUS_SMBALERT);
312 
313 	/* Wait for delayed work handled */
314 	k_sleep(K_MSEC(100));
315 
316 	/* Verify that smbalert is NOT handled */
317 	zassert_false(smbalert_handled, "smbalert is not handled");
318 
319 	/* Now enable smbalert */
320 	ret = smbus_configure(dev, SMBUS_MODE_CONTROLLER | SMBUS_MODE_SMBALERT);
321 	zassert_ok(ret, "Configure failed");
322 
323 	/* Emulate SMBus alert again */
324 	run_isr(EMUL_SMBUS_SMBALERT);
325 
326 	/* Wait for delayed work handled */
327 	k_sleep(K_MSEC(100));
328 
329 	/* Verify that smbalert is not handled */
330 	zassert_true(smbalert_handled, "smbalert is not handled");
331 }
332 
ZTEST(test_smbus_emul,test_host_notify)333 ZTEST(test_smbus_emul, test_host_notify)
334 {
335 	const struct device *const dev = device_get_binding(SMBUS_EMUL);
336 	int ret;
337 
338 	Z_TEST_SKIP_IFNDEF(CONFIG_SMBUS_INTEL_PCH_HOST_NOTIFY);
339 
340 	zassert_not_null(dev, "Device not found");
341 
342 	/* Try to remove not existing callback */
343 	ret = smbus_host_notify_remove_cb(dev, &notify_callback);
344 	zassert_equal(ret, -ENOENT, "Callback remove failed");
345 
346 	/* Set callback */
347 	ret = smbus_host_notify_set_cb(dev, &notify_callback);
348 	zassert_ok(ret, "Callback set failed");
349 
350 	/* Emulate SMBus alert from peripheral device */
351 	notify_handled = false;
352 
353 	/* Run without configuring Host Notify */
354 	run_isr(EMUL_SMBUS_HOST_NOTIFY);
355 
356 	/* Wait for delayed work handled */
357 	k_sleep(K_MSEC(100));
358 
359 	/* Verify that smbalert is NOT handled */
360 	zassert_false(notify_handled, "smbalert is not handled");
361 
362 	/* Now enable smbalert */
363 	ret = smbus_configure(dev,
364 			      SMBUS_MODE_CONTROLLER | SMBUS_MODE_HOST_NOTIFY);
365 	zassert_ok(ret, "Configure failed");
366 
367 	/* Emulate SMBus alert again */
368 	run_isr(EMUL_SMBUS_HOST_NOTIFY);
369 
370 	/* Wait for delayed work handled */
371 	k_sleep(K_MSEC(100));
372 
373 	/* Verify that smbalert is handled */
374 	zassert_true(notify_handled, "smbalert is not handled");
375 }
376 
377 /* Test setup function */
smbus_emul_setup(void)378 static void *smbus_emul_setup(void)
379 {
380 	emul_register_smbus_peripheral(&peripheral);
381 
382 	return NULL;
383 }
384 
385 ZTEST_SUITE(test_smbus_emul, NULL, smbus_emul_setup, NULL, NULL, NULL);
386