xref: /openbmc/linux/tools/testing/cxl/test/mem.c (revision c5c39217ff49ffb8494a671c9521c43006f87f1a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2021 Intel Corporation. All rights reserved.
3 
4 #include <linux/platform_device.h>
5 #include <linux/mod_devicetable.h>
6 #include <linux/module.h>
7 #include <linux/delay.h>
8 #include <linux/sizes.h>
9 #include <linux/bits.h>
10 #include <asm/unaligned.h>
11 #include <cxlmem.h>
12 
13 #include "trace.h"
14 
15 #define LSA_SIZE SZ_128K
16 #define DEV_SIZE SZ_2G
17 #define EFFECT(x) (1U << x)
18 
19 #define MOCK_INJECT_DEV_MAX 8
20 #define MOCK_INJECT_TEST_MAX 128
21 
22 static unsigned int poison_inject_dev_max = MOCK_INJECT_DEV_MAX;
23 
24 static struct cxl_cel_entry mock_cel[] = {
25 	{
26 		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_SUPPORTED_LOGS),
27 		.effect = cpu_to_le16(0),
28 	},
29 	{
30 		.opcode = cpu_to_le16(CXL_MBOX_OP_IDENTIFY),
31 		.effect = cpu_to_le16(0),
32 	},
33 	{
34 		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA),
35 		.effect = cpu_to_le16(0),
36 	},
37 	{
38 		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_PARTITION_INFO),
39 		.effect = cpu_to_le16(0),
40 	},
41 	{
42 		.opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA),
43 		.effect = cpu_to_le16(EFFECT(1) | EFFECT(2)),
44 	},
45 	{
46 		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO),
47 		.effect = cpu_to_le16(0),
48 	},
49 	{
50 		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_POISON),
51 		.effect = cpu_to_le16(0),
52 	},
53 	{
54 		.opcode = cpu_to_le16(CXL_MBOX_OP_INJECT_POISON),
55 		.effect = cpu_to_le16(0),
56 	},
57 	{
58 		.opcode = cpu_to_le16(CXL_MBOX_OP_CLEAR_POISON),
59 		.effect = cpu_to_le16(0),
60 	},
61 };
62 
63 /* See CXL 2.0 Table 181 Get Health Info Output Payload */
64 struct cxl_mbox_health_info {
65 	u8 health_status;
66 	u8 media_status;
67 	u8 ext_status;
68 	u8 life_used;
69 	__le16 temperature;
70 	__le32 dirty_shutdowns;
71 	__le32 volatile_errors;
72 	__le32 pmem_errors;
73 } __packed;
74 
75 static struct {
76 	struct cxl_mbox_get_supported_logs gsl;
77 	struct cxl_gsl_entry entry;
78 } mock_gsl_payload = {
79 	.gsl = {
80 		.entries = cpu_to_le16(1),
81 	},
82 	.entry = {
83 		.uuid = DEFINE_CXL_CEL_UUID,
84 		.size = cpu_to_le32(sizeof(mock_cel)),
85 	},
86 };
87 
88 #define PASS_TRY_LIMIT 3
89 
90 #define CXL_TEST_EVENT_CNT_MAX 15
91 
92 /* Set a number of events to return at a time for simulation.  */
93 #define CXL_TEST_EVENT_CNT 3
94 
95 struct mock_event_log {
96 	u16 clear_idx;
97 	u16 cur_idx;
98 	u16 nr_events;
99 	u16 nr_overflow;
100 	u16 overflow_reset;
101 	struct cxl_event_record_raw *events[CXL_TEST_EVENT_CNT_MAX];
102 };
103 
104 struct mock_event_store {
105 	struct cxl_dev_state *cxlds;
106 	struct mock_event_log mock_logs[CXL_EVENT_TYPE_MAX];
107 	u32 ev_status;
108 };
109 
110 struct cxl_mockmem_data {
111 	void *lsa;
112 	u32 security_state;
113 	u8 user_pass[NVDIMM_PASSPHRASE_LEN];
114 	u8 master_pass[NVDIMM_PASSPHRASE_LEN];
115 	int user_limit;
116 	int master_limit;
117 	struct mock_event_store mes;
118 	u8 event_buf[SZ_4K];
119 	u64 timestamp;
120 };
121 
122 static struct mock_event_log *event_find_log(struct device *dev, int log_type)
123 {
124 	struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
125 
126 	if (log_type >= CXL_EVENT_TYPE_MAX)
127 		return NULL;
128 	return &mdata->mes.mock_logs[log_type];
129 }
130 
131 static struct cxl_event_record_raw *event_get_current(struct mock_event_log *log)
132 {
133 	return log->events[log->cur_idx];
134 }
135 
136 static void event_reset_log(struct mock_event_log *log)
137 {
138 	log->cur_idx = 0;
139 	log->clear_idx = 0;
140 	log->nr_overflow = log->overflow_reset;
141 }
142 
143 /* Handle can never be 0 use 1 based indexing for handle */
144 static u16 event_get_clear_handle(struct mock_event_log *log)
145 {
146 	return log->clear_idx + 1;
147 }
148 
149 /* Handle can never be 0 use 1 based indexing for handle */
150 static __le16 event_get_cur_event_handle(struct mock_event_log *log)
151 {
152 	u16 cur_handle = log->cur_idx + 1;
153 
154 	return cpu_to_le16(cur_handle);
155 }
156 
157 static bool event_log_empty(struct mock_event_log *log)
158 {
159 	return log->cur_idx == log->nr_events;
160 }
161 
162 static void mes_add_event(struct mock_event_store *mes,
163 			  enum cxl_event_log_type log_type,
164 			  struct cxl_event_record_raw *event)
165 {
166 	struct mock_event_log *log;
167 
168 	if (WARN_ON(log_type >= CXL_EVENT_TYPE_MAX))
169 		return;
170 
171 	log = &mes->mock_logs[log_type];
172 
173 	if ((log->nr_events + 1) > CXL_TEST_EVENT_CNT_MAX) {
174 		log->nr_overflow++;
175 		log->overflow_reset = log->nr_overflow;
176 		return;
177 	}
178 
179 	log->events[log->nr_events] = event;
180 	log->nr_events++;
181 }
182 
183 static int mock_get_event(struct cxl_dev_state *cxlds,
184 			  struct cxl_mbox_cmd *cmd)
185 {
186 	struct cxl_get_event_payload *pl;
187 	struct mock_event_log *log;
188 	u16 nr_overflow;
189 	u8 log_type;
190 	int i;
191 
192 	if (cmd->size_in != sizeof(log_type))
193 		return -EINVAL;
194 
195 	if (cmd->size_out < struct_size(pl, records, CXL_TEST_EVENT_CNT))
196 		return -EINVAL;
197 
198 	log_type = *((u8 *)cmd->payload_in);
199 	if (log_type >= CXL_EVENT_TYPE_MAX)
200 		return -EINVAL;
201 
202 	memset(cmd->payload_out, 0, cmd->size_out);
203 
204 	log = event_find_log(cxlds->dev, log_type);
205 	if (!log || event_log_empty(log))
206 		return 0;
207 
208 	pl = cmd->payload_out;
209 
210 	for (i = 0; i < CXL_TEST_EVENT_CNT && !event_log_empty(log); i++) {
211 		memcpy(&pl->records[i], event_get_current(log),
212 		       sizeof(pl->records[i]));
213 		pl->records[i].hdr.handle = event_get_cur_event_handle(log);
214 		log->cur_idx++;
215 	}
216 
217 	pl->record_count = cpu_to_le16(i);
218 	if (!event_log_empty(log))
219 		pl->flags |= CXL_GET_EVENT_FLAG_MORE_RECORDS;
220 
221 	if (log->nr_overflow) {
222 		u64 ns;
223 
224 		pl->flags |= CXL_GET_EVENT_FLAG_OVERFLOW;
225 		pl->overflow_err_count = cpu_to_le16(nr_overflow);
226 		ns = ktime_get_real_ns();
227 		ns -= 5000000000; /* 5s ago */
228 		pl->first_overflow_timestamp = cpu_to_le64(ns);
229 		ns = ktime_get_real_ns();
230 		ns -= 1000000000; /* 1s ago */
231 		pl->last_overflow_timestamp = cpu_to_le64(ns);
232 	}
233 
234 	return 0;
235 }
236 
237 static int mock_clear_event(struct cxl_dev_state *cxlds,
238 			    struct cxl_mbox_cmd *cmd)
239 {
240 	struct cxl_mbox_clear_event_payload *pl = cmd->payload_in;
241 	struct mock_event_log *log;
242 	u8 log_type = pl->event_log;
243 	u16 handle;
244 	int nr;
245 
246 	if (log_type >= CXL_EVENT_TYPE_MAX)
247 		return -EINVAL;
248 
249 	log = event_find_log(cxlds->dev, log_type);
250 	if (!log)
251 		return 0; /* No mock data in this log */
252 
253 	/*
254 	 * This check is technically not invalid per the specification AFAICS.
255 	 * (The host could 'guess' handles and clear them in order).
256 	 * However, this is not good behavior for the host so test it.
257 	 */
258 	if (log->clear_idx + pl->nr_recs > log->cur_idx) {
259 		dev_err(cxlds->dev,
260 			"Attempting to clear more events than returned!\n");
261 		return -EINVAL;
262 	}
263 
264 	/* Check handle order prior to clearing events */
265 	for (nr = 0, handle = event_get_clear_handle(log);
266 	     nr < pl->nr_recs;
267 	     nr++, handle++) {
268 		if (handle != le16_to_cpu(pl->handles[nr])) {
269 			dev_err(cxlds->dev, "Clearing events out of order\n");
270 			return -EINVAL;
271 		}
272 	}
273 
274 	if (log->nr_overflow)
275 		log->nr_overflow = 0;
276 
277 	/* Clear events */
278 	log->clear_idx += pl->nr_recs;
279 	return 0;
280 }
281 
282 static void cxl_mock_event_trigger(struct device *dev)
283 {
284 	struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
285 	struct mock_event_store *mes = &mdata->mes;
286 	int i;
287 
288 	for (i = CXL_EVENT_TYPE_INFO; i < CXL_EVENT_TYPE_MAX; i++) {
289 		struct mock_event_log *log;
290 
291 		log = event_find_log(dev, i);
292 		if (log)
293 			event_reset_log(log);
294 	}
295 
296 	cxl_mem_get_event_records(mes->cxlds, mes->ev_status);
297 }
298 
299 struct cxl_event_record_raw maint_needed = {
300 	.hdr = {
301 		.id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB,
302 				0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
303 		.length = sizeof(struct cxl_event_record_raw),
304 		.flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,
305 		/* .handle = Set dynamically */
306 		.related_handle = cpu_to_le16(0xa5b6),
307 	},
308 	.data = { 0xDE, 0xAD, 0xBE, 0xEF },
309 };
310 
311 struct cxl_event_record_raw hardware_replace = {
312 	.hdr = {
313 		.id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E,
314 				0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
315 		.length = sizeof(struct cxl_event_record_raw),
316 		.flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE,
317 		/* .handle = Set dynamically */
318 		.related_handle = cpu_to_le16(0xb6a5),
319 	},
320 	.data = { 0xDE, 0xAD, 0xBE, 0xEF },
321 };
322 
323 struct cxl_event_gen_media gen_media = {
324 	.hdr = {
325 		.id = UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
326 				0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6),
327 		.length = sizeof(struct cxl_event_gen_media),
328 		.flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT,
329 		/* .handle = Set dynamically */
330 		.related_handle = cpu_to_le16(0),
331 	},
332 	.phys_addr = cpu_to_le64(0x2000),
333 	.descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT,
334 	.type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR,
335 	.transaction_type = CXL_GMER_TRANS_HOST_WRITE,
336 	/* .validity_flags = <set below> */
337 	.channel = 1,
338 	.rank = 30
339 };
340 
341 struct cxl_event_dram dram = {
342 	.hdr = {
343 		.id = UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
344 				0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24),
345 		.length = sizeof(struct cxl_event_dram),
346 		.flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED,
347 		/* .handle = Set dynamically */
348 		.related_handle = cpu_to_le16(0),
349 	},
350 	.phys_addr = cpu_to_le64(0x8000),
351 	.descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT,
352 	.type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR,
353 	.transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB,
354 	/* .validity_flags = <set below> */
355 	.channel = 1,
356 	.bank_group = 5,
357 	.bank = 2,
358 	.column = {0xDE, 0xAD},
359 };
360 
361 struct cxl_event_mem_module mem_module = {
362 	.hdr = {
363 		.id = UUID_INIT(0xfe927475, 0xdd59, 0x4339,
364 				0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74),
365 		.length = sizeof(struct cxl_event_mem_module),
366 		/* .handle = Set dynamically */
367 		.related_handle = cpu_to_le16(0),
368 	},
369 	.event_type = CXL_MMER_TEMP_CHANGE,
370 	.info = {
371 		.health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED,
372 		.media_status = CXL_DHI_MS_ALL_DATA_LOST,
373 		.add_status = (CXL_DHI_AS_CRITICAL << 2) |
374 			      (CXL_DHI_AS_WARNING << 4) |
375 			      (CXL_DHI_AS_WARNING << 5),
376 		.device_temp = { 0xDE, 0xAD},
377 		.dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef },
378 		.cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
379 		.cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
380 	}
381 };
382 
383 static int mock_set_timestamp(struct cxl_dev_state *cxlds,
384 			      struct cxl_mbox_cmd *cmd)
385 {
386 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
387 	struct cxl_mbox_set_timestamp_in *ts = cmd->payload_in;
388 
389 	if (cmd->size_in != sizeof(*ts))
390 		return -EINVAL;
391 
392 	if (cmd->size_out != 0)
393 		return -EINVAL;
394 
395 	mdata->timestamp = le64_to_cpu(ts->timestamp);
396 	return 0;
397 }
398 
399 static void cxl_mock_add_event_logs(struct mock_event_store *mes)
400 {
401 	put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK,
402 			   &gen_media.validity_flags);
403 
404 	put_unaligned_le16(CXL_DER_VALID_CHANNEL | CXL_DER_VALID_BANK_GROUP |
405 			   CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN,
406 			   &dram.validity_flags);
407 
408 	mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed);
409 	mes_add_event(mes, CXL_EVENT_TYPE_INFO,
410 		      (struct cxl_event_record_raw *)&gen_media);
411 	mes_add_event(mes, CXL_EVENT_TYPE_INFO,
412 		      (struct cxl_event_record_raw *)&mem_module);
413 	mes->ev_status |= CXLDEV_EVENT_STATUS_INFO;
414 
415 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &maint_needed);
416 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
417 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
418 		      (struct cxl_event_record_raw *)&dram);
419 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
420 		      (struct cxl_event_record_raw *)&gen_media);
421 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
422 		      (struct cxl_event_record_raw *)&mem_module);
423 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
424 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
425 		      (struct cxl_event_record_raw *)&dram);
426 	/* Overflow this log */
427 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
428 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
429 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
430 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
431 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
432 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
433 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
434 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
435 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
436 	mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
437 	mes->ev_status |= CXLDEV_EVENT_STATUS_FAIL;
438 
439 	mes_add_event(mes, CXL_EVENT_TYPE_FATAL, &hardware_replace);
440 	mes_add_event(mes, CXL_EVENT_TYPE_FATAL,
441 		      (struct cxl_event_record_raw *)&dram);
442 	mes->ev_status |= CXLDEV_EVENT_STATUS_FATAL;
443 }
444 
445 static int mock_gsl(struct cxl_mbox_cmd *cmd)
446 {
447 	if (cmd->size_out < sizeof(mock_gsl_payload))
448 		return -EINVAL;
449 
450 	memcpy(cmd->payload_out, &mock_gsl_payload, sizeof(mock_gsl_payload));
451 	cmd->size_out = sizeof(mock_gsl_payload);
452 
453 	return 0;
454 }
455 
456 static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
457 {
458 	struct cxl_mbox_get_log *gl = cmd->payload_in;
459 	u32 offset = le32_to_cpu(gl->offset);
460 	u32 length = le32_to_cpu(gl->length);
461 	uuid_t uuid = DEFINE_CXL_CEL_UUID;
462 	void *data = &mock_cel;
463 
464 	if (cmd->size_in < sizeof(*gl))
465 		return -EINVAL;
466 	if (length > cxlds->payload_size)
467 		return -EINVAL;
468 	if (offset + length > sizeof(mock_cel))
469 		return -EINVAL;
470 	if (!uuid_equal(&gl->uuid, &uuid))
471 		return -EINVAL;
472 	if (length > cmd->size_out)
473 		return -EINVAL;
474 
475 	memcpy(cmd->payload_out, data + offset, length);
476 
477 	return 0;
478 }
479 
480 static int mock_rcd_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
481 {
482 	struct cxl_mbox_identify id = {
483 		.fw_revision = { "mock fw v1 " },
484 		.total_capacity =
485 			cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
486 		.volatile_capacity =
487 			cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
488 	};
489 
490 	if (cmd->size_out < sizeof(id))
491 		return -EINVAL;
492 
493 	memcpy(cmd->payload_out, &id, sizeof(id));
494 
495 	return 0;
496 }
497 
498 static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
499 {
500 	struct cxl_mbox_identify id = {
501 		.fw_revision = { "mock fw v1 " },
502 		.lsa_size = cpu_to_le32(LSA_SIZE),
503 		.partition_align =
504 			cpu_to_le64(SZ_256M / CXL_CAPACITY_MULTIPLIER),
505 		.total_capacity =
506 			cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
507 		.inject_poison_limit = cpu_to_le16(MOCK_INJECT_TEST_MAX),
508 	};
509 
510 	put_unaligned_le24(CXL_POISON_LIST_MAX, id.poison_list_max_mer);
511 
512 	if (cmd->size_out < sizeof(id))
513 		return -EINVAL;
514 
515 	memcpy(cmd->payload_out, &id, sizeof(id));
516 
517 	return 0;
518 }
519 
520 static int mock_partition_info(struct cxl_dev_state *cxlds,
521 			       struct cxl_mbox_cmd *cmd)
522 {
523 	struct cxl_mbox_get_partition_info pi = {
524 		.active_volatile_cap =
525 			cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
526 		.active_persistent_cap =
527 			cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
528 	};
529 
530 	if (cmd->size_out < sizeof(pi))
531 		return -EINVAL;
532 
533 	memcpy(cmd->payload_out, &pi, sizeof(pi));
534 
535 	return 0;
536 }
537 
538 static int mock_sanitize(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
539 {
540 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
541 
542 	if (cmd->size_in != 0)
543 		return -EINVAL;
544 
545 	if (cmd->size_out != 0)
546 		return -EINVAL;
547 
548 	if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
549 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
550 		return -ENXIO;
551 	}
552 	if (mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED) {
553 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
554 		return -ENXIO;
555 	}
556 
557 	return 0; /* assume less than 2 secs, no bg */
558 }
559 
560 static int mock_get_security_state(struct cxl_dev_state *cxlds,
561 				   struct cxl_mbox_cmd *cmd)
562 {
563 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
564 
565 	if (cmd->size_in)
566 		return -EINVAL;
567 
568 	if (cmd->size_out != sizeof(u32))
569 		return -EINVAL;
570 
571 	memcpy(cmd->payload_out, &mdata->security_state, sizeof(u32));
572 
573 	return 0;
574 }
575 
576 static void master_plimit_check(struct cxl_mockmem_data *mdata)
577 {
578 	if (mdata->master_limit == PASS_TRY_LIMIT)
579 		return;
580 	mdata->master_limit++;
581 	if (mdata->master_limit == PASS_TRY_LIMIT)
582 		mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PLIMIT;
583 }
584 
585 static void user_plimit_check(struct cxl_mockmem_data *mdata)
586 {
587 	if (mdata->user_limit == PASS_TRY_LIMIT)
588 		return;
589 	mdata->user_limit++;
590 	if (mdata->user_limit == PASS_TRY_LIMIT)
591 		mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT;
592 }
593 
594 static int mock_set_passphrase(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
595 {
596 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
597 	struct cxl_set_pass *set_pass;
598 
599 	if (cmd->size_in != sizeof(*set_pass))
600 		return -EINVAL;
601 
602 	if (cmd->size_out != 0)
603 		return -EINVAL;
604 
605 	if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
606 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
607 		return -ENXIO;
608 	}
609 
610 	set_pass = cmd->payload_in;
611 	switch (set_pass->type) {
612 	case CXL_PMEM_SEC_PASS_MASTER:
613 		if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) {
614 			cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
615 			return -ENXIO;
616 		}
617 		/*
618 		 * CXL spec rev3.0 8.2.9.8.6.2, The master pasphrase shall only be set in
619 		 * the security disabled state when the user passphrase is not set.
620 		 */
621 		if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
622 			cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
623 			return -ENXIO;
624 		}
625 		if (memcmp(mdata->master_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) {
626 			master_plimit_check(mdata);
627 			cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
628 			return -ENXIO;
629 		}
630 		memcpy(mdata->master_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN);
631 		mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PASS_SET;
632 		return 0;
633 
634 	case CXL_PMEM_SEC_PASS_USER:
635 		if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
636 			cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
637 			return -ENXIO;
638 		}
639 		if (memcmp(mdata->user_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) {
640 			user_plimit_check(mdata);
641 			cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
642 			return -ENXIO;
643 		}
644 		memcpy(mdata->user_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN);
645 		mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PASS_SET;
646 		return 0;
647 
648 	default:
649 		cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
650 	}
651 	return -EINVAL;
652 }
653 
654 static int mock_disable_passphrase(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
655 {
656 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
657 	struct cxl_disable_pass *dis_pass;
658 
659 	if (cmd->size_in != sizeof(*dis_pass))
660 		return -EINVAL;
661 
662 	if (cmd->size_out != 0)
663 		return -EINVAL;
664 
665 	if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
666 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
667 		return -ENXIO;
668 	}
669 
670 	dis_pass = cmd->payload_in;
671 	switch (dis_pass->type) {
672 	case CXL_PMEM_SEC_PASS_MASTER:
673 		if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) {
674 			cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
675 			return -ENXIO;
676 		}
677 
678 		if (!(mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)) {
679 			cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
680 			return -ENXIO;
681 		}
682 
683 		if (memcmp(dis_pass->pass, mdata->master_pass, NVDIMM_PASSPHRASE_LEN)) {
684 			master_plimit_check(mdata);
685 			cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
686 			return -ENXIO;
687 		}
688 
689 		mdata->master_limit = 0;
690 		memset(mdata->master_pass, 0, NVDIMM_PASSPHRASE_LEN);
691 		mdata->security_state &= ~CXL_PMEM_SEC_STATE_MASTER_PASS_SET;
692 		return 0;
693 
694 	case CXL_PMEM_SEC_PASS_USER:
695 		if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
696 			cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
697 			return -ENXIO;
698 		}
699 
700 		if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) {
701 			cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
702 			return -ENXIO;
703 		}
704 
705 		if (memcmp(dis_pass->pass, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) {
706 			user_plimit_check(mdata);
707 			cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
708 			return -ENXIO;
709 		}
710 
711 		mdata->user_limit = 0;
712 		memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
713 		mdata->security_state &= ~(CXL_PMEM_SEC_STATE_USER_PASS_SET |
714 					   CXL_PMEM_SEC_STATE_LOCKED);
715 		return 0;
716 
717 	default:
718 		cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
719 		return -EINVAL;
720 	}
721 
722 	return 0;
723 }
724 
725 static int mock_freeze_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
726 {
727 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
728 
729 	if (cmd->size_in != 0)
730 		return -EINVAL;
731 
732 	if (cmd->size_out != 0)
733 		return -EINVAL;
734 
735 	if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN)
736 		return 0;
737 
738 	mdata->security_state |= CXL_PMEM_SEC_STATE_FROZEN;
739 	return 0;
740 }
741 
742 static int mock_unlock_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
743 {
744 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
745 
746 	if (cmd->size_in != NVDIMM_PASSPHRASE_LEN)
747 		return -EINVAL;
748 
749 	if (cmd->size_out != 0)
750 		return -EINVAL;
751 
752 	if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
753 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
754 		return -ENXIO;
755 	}
756 
757 	if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) {
758 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
759 		return -ENXIO;
760 	}
761 
762 	if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
763 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
764 		return -ENXIO;
765 	}
766 
767 	if (!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED)) {
768 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
769 		return -ENXIO;
770 	}
771 
772 	if (memcmp(cmd->payload_in, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) {
773 		if (++mdata->user_limit == PASS_TRY_LIMIT)
774 			mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT;
775 		cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
776 		return -ENXIO;
777 	}
778 
779 	mdata->user_limit = 0;
780 	mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED;
781 	return 0;
782 }
783 
784 static int mock_passphrase_secure_erase(struct cxl_dev_state *cxlds,
785 					struct cxl_mbox_cmd *cmd)
786 {
787 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
788 	struct cxl_pass_erase *erase;
789 
790 	if (cmd->size_in != sizeof(*erase))
791 		return -EINVAL;
792 
793 	if (cmd->size_out != 0)
794 		return -EINVAL;
795 
796 	erase = cmd->payload_in;
797 	if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
798 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
799 		return -ENXIO;
800 	}
801 
802 	if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT &&
803 	    erase->type == CXL_PMEM_SEC_PASS_USER) {
804 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
805 		return -ENXIO;
806 	}
807 
808 	if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT &&
809 	    erase->type == CXL_PMEM_SEC_PASS_MASTER) {
810 		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
811 		return -ENXIO;
812 	}
813 
814 	switch (erase->type) {
815 	case CXL_PMEM_SEC_PASS_MASTER:
816 		/*
817 		 * The spec does not clearly define the behavior of the scenario
818 		 * where a master passphrase is passed in while the master
819 		 * passphrase is not set and user passphrase is not set. The
820 		 * code will take the assumption that it will behave the same
821 		 * as a CXL secure erase command without passphrase (0x4401).
822 		 */
823 		if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET) {
824 			if (memcmp(mdata->master_pass, erase->pass,
825 				   NVDIMM_PASSPHRASE_LEN)) {
826 				master_plimit_check(mdata);
827 				cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
828 				return -ENXIO;
829 			}
830 			mdata->master_limit = 0;
831 			mdata->user_limit = 0;
832 			mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET;
833 			memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
834 			mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED;
835 		} else {
836 			/*
837 			 * CXL rev3 8.2.9.8.6.3 Disable Passphrase
838 			 * When master passphrase is disabled, the device shall
839 			 * return Invalid Input for the Passphrase Secure Erase
840 			 * command with master passphrase.
841 			 */
842 			return -EINVAL;
843 		}
844 		/* Scramble encryption keys so that data is effectively erased */
845 		break;
846 	case CXL_PMEM_SEC_PASS_USER:
847 		/*
848 		 * The spec does not clearly define the behavior of the scenario
849 		 * where a user passphrase is passed in while the user
850 		 * passphrase is not set. The code will take the assumption that
851 		 * it will behave the same as a CXL secure erase command without
852 		 * passphrase (0x4401).
853 		 */
854 		if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
855 			if (memcmp(mdata->user_pass, erase->pass,
856 				   NVDIMM_PASSPHRASE_LEN)) {
857 				user_plimit_check(mdata);
858 				cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
859 				return -ENXIO;
860 			}
861 			mdata->user_limit = 0;
862 			mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET;
863 			memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
864 		}
865 
866 		/*
867 		 * CXL rev3 Table 8-118
868 		 * If user passphrase is not set or supported by device, current
869 		 * passphrase value is ignored. Will make the assumption that
870 		 * the operation will proceed as secure erase w/o passphrase
871 		 * since spec is not explicit.
872 		 */
873 
874 		/* Scramble encryption keys so that data is effectively erased */
875 		break;
876 	default:
877 		return -EINVAL;
878 	}
879 
880 	return 0;
881 }
882 
883 static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
884 {
885 	struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in;
886 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
887 	void *lsa = mdata->lsa;
888 	u32 offset, length;
889 
890 	if (sizeof(*get_lsa) > cmd->size_in)
891 		return -EINVAL;
892 	offset = le32_to_cpu(get_lsa->offset);
893 	length = le32_to_cpu(get_lsa->length);
894 	if (offset + length > LSA_SIZE)
895 		return -EINVAL;
896 	if (length > cmd->size_out)
897 		return -EINVAL;
898 
899 	memcpy(cmd->payload_out, lsa + offset, length);
900 	return 0;
901 }
902 
903 static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
904 {
905 	struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in;
906 	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
907 	void *lsa = mdata->lsa;
908 	u32 offset, length;
909 
910 	if (sizeof(*set_lsa) > cmd->size_in)
911 		return -EINVAL;
912 	offset = le32_to_cpu(set_lsa->offset);
913 	length = cmd->size_in - sizeof(*set_lsa);
914 	if (offset + length > LSA_SIZE)
915 		return -EINVAL;
916 
917 	memcpy(lsa + offset, &set_lsa->data[0], length);
918 	return 0;
919 }
920 
921 static int mock_health_info(struct cxl_dev_state *cxlds,
922 			    struct cxl_mbox_cmd *cmd)
923 {
924 	struct cxl_mbox_health_info health_info = {
925 		/* set flags for maint needed, perf degraded, hw replacement */
926 		.health_status = 0x7,
927 		/* set media status to "All Data Lost" */
928 		.media_status = 0x3,
929 		/*
930 		 * set ext_status flags for:
931 		 *  ext_life_used: normal,
932 		 *  ext_temperature: critical,
933 		 *  ext_corrected_volatile: warning,
934 		 *  ext_corrected_persistent: normal,
935 		 */
936 		.ext_status = 0x18,
937 		.life_used = 15,
938 		.temperature = cpu_to_le16(25),
939 		.dirty_shutdowns = cpu_to_le32(10),
940 		.volatile_errors = cpu_to_le32(20),
941 		.pmem_errors = cpu_to_le32(30),
942 	};
943 
944 	if (cmd->size_out < sizeof(health_info))
945 		return -EINVAL;
946 
947 	memcpy(cmd->payload_out, &health_info, sizeof(health_info));
948 	return 0;
949 }
950 
951 static struct mock_poison {
952 	struct cxl_dev_state *cxlds;
953 	u64 dpa;
954 } mock_poison_list[MOCK_INJECT_TEST_MAX];
955 
956 static struct cxl_mbox_poison_out *
957 cxl_get_injected_po(struct cxl_dev_state *cxlds, u64 offset, u64 length)
958 {
959 	struct cxl_mbox_poison_out *po;
960 	int nr_records = 0;
961 	u64 dpa;
962 
963 	po = kzalloc(struct_size(po, record, poison_inject_dev_max), GFP_KERNEL);
964 	if (!po)
965 		return NULL;
966 
967 	for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) {
968 		if (mock_poison_list[i].cxlds != cxlds)
969 			continue;
970 		if (mock_poison_list[i].dpa < offset ||
971 		    mock_poison_list[i].dpa > offset + length - 1)
972 			continue;
973 
974 		dpa = mock_poison_list[i].dpa + CXL_POISON_SOURCE_INJECTED;
975 		po->record[nr_records].address = cpu_to_le64(dpa);
976 		po->record[nr_records].length = cpu_to_le32(1);
977 		nr_records++;
978 		if (nr_records == poison_inject_dev_max)
979 			break;
980 	}
981 
982 	/* Always return count, even when zero */
983 	po->count = cpu_to_le16(nr_records);
984 
985 	return po;
986 }
987 
988 static int mock_get_poison(struct cxl_dev_state *cxlds,
989 			   struct cxl_mbox_cmd *cmd)
990 {
991 	struct cxl_mbox_poison_in *pi = cmd->payload_in;
992 	struct cxl_mbox_poison_out *po;
993 	u64 offset = le64_to_cpu(pi->offset);
994 	u64 length = le64_to_cpu(pi->length);
995 	int nr_records;
996 
997 	po = cxl_get_injected_po(cxlds, offset, length);
998 	if (!po)
999 		return -ENOMEM;
1000 	nr_records = le16_to_cpu(po->count);
1001 	memcpy(cmd->payload_out, po, struct_size(po, record, nr_records));
1002 	cmd->size_out = struct_size(po, record, nr_records);
1003 	kfree(po);
1004 
1005 	return 0;
1006 }
1007 
1008 static bool mock_poison_dev_max_injected(struct cxl_dev_state *cxlds)
1009 {
1010 	int count = 0;
1011 
1012 	for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) {
1013 		if (mock_poison_list[i].cxlds == cxlds)
1014 			count++;
1015 	}
1016 	return (count >= poison_inject_dev_max);
1017 }
1018 
1019 static bool mock_poison_add(struct cxl_dev_state *cxlds, u64 dpa)
1020 {
1021 	if (mock_poison_dev_max_injected(cxlds)) {
1022 		dev_dbg(cxlds->dev,
1023 			"Device poison injection limit has been reached: %d\n",
1024 			MOCK_INJECT_DEV_MAX);
1025 		return false;
1026 	}
1027 
1028 	for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) {
1029 		if (!mock_poison_list[i].cxlds) {
1030 			mock_poison_list[i].cxlds = cxlds;
1031 			mock_poison_list[i].dpa = dpa;
1032 			return true;
1033 		}
1034 	}
1035 	dev_dbg(cxlds->dev,
1036 		"Mock test poison injection limit has been reached: %d\n",
1037 		MOCK_INJECT_TEST_MAX);
1038 
1039 	return false;
1040 }
1041 
1042 static bool mock_poison_found(struct cxl_dev_state *cxlds, u64 dpa)
1043 {
1044 	for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) {
1045 		if (mock_poison_list[i].cxlds == cxlds &&
1046 		    mock_poison_list[i].dpa == dpa)
1047 			return true;
1048 	}
1049 	return false;
1050 }
1051 
1052 static int mock_inject_poison(struct cxl_dev_state *cxlds,
1053 			      struct cxl_mbox_cmd *cmd)
1054 {
1055 	struct cxl_mbox_inject_poison *pi = cmd->payload_in;
1056 	u64 dpa = le64_to_cpu(pi->address);
1057 
1058 	if (mock_poison_found(cxlds, dpa)) {
1059 		/* Not an error to inject poison if already poisoned */
1060 		dev_dbg(cxlds->dev, "DPA: 0x%llx already poisoned\n", dpa);
1061 		return 0;
1062 	}
1063 	if (!mock_poison_add(cxlds, dpa))
1064 		return -ENXIO;
1065 
1066 	return 0;
1067 }
1068 
1069 static bool mock_poison_del(struct cxl_dev_state *cxlds, u64 dpa)
1070 {
1071 	for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) {
1072 		if (mock_poison_list[i].cxlds == cxlds &&
1073 		    mock_poison_list[i].dpa == dpa) {
1074 			mock_poison_list[i].cxlds = NULL;
1075 			return true;
1076 		}
1077 	}
1078 	return false;
1079 }
1080 
1081 static int mock_clear_poison(struct cxl_dev_state *cxlds,
1082 			     struct cxl_mbox_cmd *cmd)
1083 {
1084 	struct cxl_mbox_clear_poison *pi = cmd->payload_in;
1085 	u64 dpa = le64_to_cpu(pi->address);
1086 
1087 	/*
1088 	 * A real CXL device will write pi->write_data to the address
1089 	 * being cleared. In this mock, just delete this address from
1090 	 * the mock poison list.
1091 	 */
1092 	if (!mock_poison_del(cxlds, dpa))
1093 		dev_dbg(cxlds->dev, "DPA: 0x%llx not in poison list\n", dpa);
1094 
1095 	return 0;
1096 }
1097 
1098 static bool mock_poison_list_empty(void)
1099 {
1100 	for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) {
1101 		if (mock_poison_list[i].cxlds)
1102 			return false;
1103 	}
1104 	return true;
1105 }
1106 
1107 static ssize_t poison_inject_max_show(struct device_driver *drv, char *buf)
1108 {
1109 	return sysfs_emit(buf, "%u\n", poison_inject_dev_max);
1110 }
1111 
1112 static ssize_t poison_inject_max_store(struct device_driver *drv,
1113 				       const char *buf, size_t len)
1114 {
1115 	int val;
1116 
1117 	if (kstrtoint(buf, 0, &val) < 0)
1118 		return -EINVAL;
1119 
1120 	if (!mock_poison_list_empty())
1121 		return -EBUSY;
1122 
1123 	if (val <= MOCK_INJECT_TEST_MAX)
1124 		poison_inject_dev_max = val;
1125 	else
1126 		return -EINVAL;
1127 
1128 	return len;
1129 }
1130 
1131 static DRIVER_ATTR_RW(poison_inject_max);
1132 
1133 static struct attribute *cxl_mock_mem_core_attrs[] = {
1134 	&driver_attr_poison_inject_max.attr,
1135 	NULL
1136 };
1137 ATTRIBUTE_GROUPS(cxl_mock_mem_core);
1138 
1139 static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
1140 {
1141 	struct device *dev = cxlds->dev;
1142 	int rc = -EIO;
1143 
1144 	switch (cmd->opcode) {
1145 	case CXL_MBOX_OP_SET_TIMESTAMP:
1146 		rc = mock_set_timestamp(cxlds, cmd);
1147 		break;
1148 	case CXL_MBOX_OP_GET_SUPPORTED_LOGS:
1149 		rc = mock_gsl(cmd);
1150 		break;
1151 	case CXL_MBOX_OP_GET_LOG:
1152 		rc = mock_get_log(cxlds, cmd);
1153 		break;
1154 	case CXL_MBOX_OP_IDENTIFY:
1155 		if (cxlds->rcd)
1156 			rc = mock_rcd_id(cxlds, cmd);
1157 		else
1158 			rc = mock_id(cxlds, cmd);
1159 		break;
1160 	case CXL_MBOX_OP_GET_LSA:
1161 		rc = mock_get_lsa(cxlds, cmd);
1162 		break;
1163 	case CXL_MBOX_OP_GET_PARTITION_INFO:
1164 		rc = mock_partition_info(cxlds, cmd);
1165 		break;
1166 	case CXL_MBOX_OP_GET_EVENT_RECORD:
1167 		rc = mock_get_event(cxlds, cmd);
1168 		break;
1169 	case CXL_MBOX_OP_CLEAR_EVENT_RECORD:
1170 		rc = mock_clear_event(cxlds, cmd);
1171 		break;
1172 	case CXL_MBOX_OP_SET_LSA:
1173 		rc = mock_set_lsa(cxlds, cmd);
1174 		break;
1175 	case CXL_MBOX_OP_GET_HEALTH_INFO:
1176 		rc = mock_health_info(cxlds, cmd);
1177 		break;
1178 	case CXL_MBOX_OP_SANITIZE:
1179 		rc = mock_sanitize(cxlds, cmd);
1180 		break;
1181 	case CXL_MBOX_OP_GET_SECURITY_STATE:
1182 		rc = mock_get_security_state(cxlds, cmd);
1183 		break;
1184 	case CXL_MBOX_OP_SET_PASSPHRASE:
1185 		rc = mock_set_passphrase(cxlds, cmd);
1186 		break;
1187 	case CXL_MBOX_OP_DISABLE_PASSPHRASE:
1188 		rc = mock_disable_passphrase(cxlds, cmd);
1189 		break;
1190 	case CXL_MBOX_OP_FREEZE_SECURITY:
1191 		rc = mock_freeze_security(cxlds, cmd);
1192 		break;
1193 	case CXL_MBOX_OP_UNLOCK:
1194 		rc = mock_unlock_security(cxlds, cmd);
1195 		break;
1196 	case CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE:
1197 		rc = mock_passphrase_secure_erase(cxlds, cmd);
1198 		break;
1199 	case CXL_MBOX_OP_GET_POISON:
1200 		rc = mock_get_poison(cxlds, cmd);
1201 		break;
1202 	case CXL_MBOX_OP_INJECT_POISON:
1203 		rc = mock_inject_poison(cxlds, cmd);
1204 		break;
1205 	case CXL_MBOX_OP_CLEAR_POISON:
1206 		rc = mock_clear_poison(cxlds, cmd);
1207 		break;
1208 	default:
1209 		break;
1210 	}
1211 
1212 	dev_dbg(dev, "opcode: %#x sz_in: %zd sz_out: %zd rc: %d\n", cmd->opcode,
1213 		cmd->size_in, cmd->size_out, rc);
1214 
1215 	return rc;
1216 }
1217 
1218 static void label_area_release(void *lsa)
1219 {
1220 	vfree(lsa);
1221 }
1222 
1223 static bool is_rcd(struct platform_device *pdev)
1224 {
1225 	const struct platform_device_id *id = platform_get_device_id(pdev);
1226 
1227 	return !!id->driver_data;
1228 }
1229 
1230 static ssize_t event_trigger_store(struct device *dev,
1231 				   struct device_attribute *attr,
1232 				   const char *buf, size_t count)
1233 {
1234 	cxl_mock_event_trigger(dev);
1235 	return count;
1236 }
1237 static DEVICE_ATTR_WO(event_trigger);
1238 
1239 static int cxl_mock_mem_probe(struct platform_device *pdev)
1240 {
1241 	struct device *dev = &pdev->dev;
1242 	struct cxl_memdev *cxlmd;
1243 	struct cxl_dev_state *cxlds;
1244 	struct cxl_mockmem_data *mdata;
1245 	int rc;
1246 
1247 	mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL);
1248 	if (!mdata)
1249 		return -ENOMEM;
1250 	dev_set_drvdata(dev, mdata);
1251 
1252 	mdata->lsa = vmalloc(LSA_SIZE);
1253 	if (!mdata->lsa)
1254 		return -ENOMEM;
1255 	rc = devm_add_action_or_reset(dev, label_area_release, mdata->lsa);
1256 	if (rc)
1257 		return rc;
1258 
1259 	cxlds = cxl_dev_state_create(dev);
1260 	if (IS_ERR(cxlds))
1261 		return PTR_ERR(cxlds);
1262 
1263 	cxlds->serial = pdev->id;
1264 	cxlds->mbox_send = cxl_mock_mbox_send;
1265 	cxlds->payload_size = SZ_4K;
1266 	cxlds->event.buf = (struct cxl_get_event_payload *) mdata->event_buf;
1267 	if (is_rcd(pdev)) {
1268 		cxlds->rcd = true;
1269 		cxlds->component_reg_phys = CXL_RESOURCE_NONE;
1270 	}
1271 
1272 	rc = cxl_enumerate_cmds(cxlds);
1273 	if (rc)
1274 		return rc;
1275 
1276 	rc = cxl_poison_state_init(cxlds);
1277 	if (rc)
1278 		return rc;
1279 
1280 	rc = cxl_set_timestamp(cxlds);
1281 	if (rc)
1282 		return rc;
1283 
1284 	cxlds->media_ready = true;
1285 	rc = cxl_dev_state_identify(cxlds);
1286 	if (rc)
1287 		return rc;
1288 
1289 	rc = cxl_mem_create_range_info(cxlds);
1290 	if (rc)
1291 		return rc;
1292 
1293 	mdata->mes.cxlds = cxlds;
1294 	cxl_mock_add_event_logs(&mdata->mes);
1295 
1296 	cxlmd = devm_cxl_add_memdev(cxlds);
1297 	if (IS_ERR(cxlmd))
1298 		return PTR_ERR(cxlmd);
1299 
1300 	cxl_mem_get_event_records(cxlds, CXLDEV_EVENT_STATUS_ALL);
1301 
1302 	return 0;
1303 }
1304 
1305 static ssize_t security_lock_show(struct device *dev,
1306 				  struct device_attribute *attr, char *buf)
1307 {
1308 	struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
1309 
1310 	return sysfs_emit(buf, "%u\n",
1311 			  !!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED));
1312 }
1313 
1314 static ssize_t security_lock_store(struct device *dev, struct device_attribute *attr,
1315 				   const char *buf, size_t count)
1316 {
1317 	struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
1318 	u32 mask = CXL_PMEM_SEC_STATE_FROZEN | CXL_PMEM_SEC_STATE_USER_PLIMIT |
1319 		   CXL_PMEM_SEC_STATE_MASTER_PLIMIT;
1320 	int val;
1321 
1322 	if (kstrtoint(buf, 0, &val) < 0)
1323 		return -EINVAL;
1324 
1325 	if (val == 1) {
1326 		if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
1327 			return -ENXIO;
1328 		mdata->security_state |= CXL_PMEM_SEC_STATE_LOCKED;
1329 		mdata->security_state &= ~mask;
1330 	} else {
1331 		return -EINVAL;
1332 	}
1333 	return count;
1334 }
1335 
1336 static DEVICE_ATTR_RW(security_lock);
1337 
1338 static struct attribute *cxl_mock_mem_attrs[] = {
1339 	&dev_attr_security_lock.attr,
1340 	&dev_attr_event_trigger.attr,
1341 	NULL
1342 };
1343 ATTRIBUTE_GROUPS(cxl_mock_mem);
1344 
1345 static const struct platform_device_id cxl_mock_mem_ids[] = {
1346 	{ .name = "cxl_mem", 0 },
1347 	{ .name = "cxl_rcd", 1 },
1348 	{ },
1349 };
1350 MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids);
1351 
1352 static struct platform_driver cxl_mock_mem_driver = {
1353 	.probe = cxl_mock_mem_probe,
1354 	.id_table = cxl_mock_mem_ids,
1355 	.driver = {
1356 		.name = KBUILD_MODNAME,
1357 		.dev_groups = cxl_mock_mem_groups,
1358 		.groups = cxl_mock_mem_core_groups,
1359 	},
1360 };
1361 
1362 module_platform_driver(cxl_mock_mem_driver);
1363 MODULE_LICENSE("GPL v2");
1364 MODULE_IMPORT_NS(CXL);
1365