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 <cxlmem.h>
11
12 #include "trace.h"
13
14 #define LSA_SIZE SZ_128K
15 #define DEV_SIZE SZ_2G
16 #define EFFECT(x) (1U << x)
17
18 static struct cxl_cel_entry mock_cel[] = {
19 {
20 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_SUPPORTED_LOGS),
21 .effect = cpu_to_le16(0),
22 },
23 {
24 .opcode = cpu_to_le16(CXL_MBOX_OP_IDENTIFY),
25 .effect = cpu_to_le16(0),
26 },
27 {
28 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA),
29 .effect = cpu_to_le16(0),
30 },
31 {
32 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_PARTITION_INFO),
33 .effect = cpu_to_le16(0),
34 },
35 {
36 .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA),
37 .effect = cpu_to_le16(EFFECT(1) | EFFECT(2)),
38 },
39 {
40 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO),
41 .effect = cpu_to_le16(0),
42 },
43 };
44
45 /* See CXL 2.0 Table 181 Get Health Info Output Payload */
46 struct cxl_mbox_health_info {
47 u8 health_status;
48 u8 media_status;
49 u8 ext_status;
50 u8 life_used;
51 __le16 temperature;
52 __le32 dirty_shutdowns;
53 __le32 volatile_errors;
54 __le32 pmem_errors;
55 } __packed;
56
57 static struct {
58 struct cxl_mbox_get_supported_logs gsl;
59 struct cxl_gsl_entry entry;
60 } mock_gsl_payload = {
61 .gsl = {
62 .entries = cpu_to_le16(1),
63 },
64 .entry = {
65 .uuid = DEFINE_CXL_CEL_UUID,
66 .size = cpu_to_le32(sizeof(mock_cel)),
67 },
68 };
69
70 #define PASS_TRY_LIMIT 3
71
72 #define CXL_TEST_EVENT_CNT_MAX 15
73
74 /* Set a number of events to return at a time for simulation. */
75 #define CXL_TEST_EVENT_CNT 3
76
77 struct mock_event_log {
78 u16 clear_idx;
79 u16 cur_idx;
80 u16 nr_events;
81 u16 nr_overflow;
82 u16 overflow_reset;
83 struct cxl_event_record_raw *events[CXL_TEST_EVENT_CNT_MAX];
84 };
85
86 struct mock_event_store {
87 struct cxl_dev_state *cxlds;
88 struct mock_event_log mock_logs[CXL_EVENT_TYPE_MAX];
89 u32 ev_status;
90 };
91
92 struct cxl_mockmem_data {
93 void *lsa;
94 u32 security_state;
95 u8 user_pass[NVDIMM_PASSPHRASE_LEN];
96 u8 master_pass[NVDIMM_PASSPHRASE_LEN];
97 int user_limit;
98 int master_limit;
99 struct mock_event_store mes;
100 u8 event_buf[SZ_4K];
101 };
102
event_find_log(struct device * dev,int log_type)103 static struct mock_event_log *event_find_log(struct device *dev, int log_type)
104 {
105 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
106
107 if (log_type >= CXL_EVENT_TYPE_MAX)
108 return NULL;
109 return &mdata->mes.mock_logs[log_type];
110 }
111
event_get_current(struct mock_event_log * log)112 static struct cxl_event_record_raw *event_get_current(struct mock_event_log *log)
113 {
114 return log->events[log->cur_idx];
115 }
116
event_reset_log(struct mock_event_log * log)117 static void event_reset_log(struct mock_event_log *log)
118 {
119 log->cur_idx = 0;
120 log->clear_idx = 0;
121 log->nr_overflow = log->overflow_reset;
122 }
123
124 /* Handle can never be 0 use 1 based indexing for handle */
event_get_clear_handle(struct mock_event_log * log)125 static u16 event_get_clear_handle(struct mock_event_log *log)
126 {
127 return log->clear_idx + 1;
128 }
129
130 /* Handle can never be 0 use 1 based indexing for handle */
event_get_cur_event_handle(struct mock_event_log * log)131 static __le16 event_get_cur_event_handle(struct mock_event_log *log)
132 {
133 u16 cur_handle = log->cur_idx + 1;
134
135 return cpu_to_le16(cur_handle);
136 }
137
event_log_empty(struct mock_event_log * log)138 static bool event_log_empty(struct mock_event_log *log)
139 {
140 return log->cur_idx == log->nr_events;
141 }
142
mes_add_event(struct mock_event_store * mes,enum cxl_event_log_type log_type,struct cxl_event_record_raw * event)143 static void mes_add_event(struct mock_event_store *mes,
144 enum cxl_event_log_type log_type,
145 struct cxl_event_record_raw *event)
146 {
147 struct mock_event_log *log;
148
149 if (WARN_ON(log_type >= CXL_EVENT_TYPE_MAX))
150 return;
151
152 log = &mes->mock_logs[log_type];
153
154 if ((log->nr_events + 1) > CXL_TEST_EVENT_CNT_MAX) {
155 log->nr_overflow++;
156 log->overflow_reset = log->nr_overflow;
157 return;
158 }
159
160 log->events[log->nr_events] = event;
161 log->nr_events++;
162 }
163
mock_get_event(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)164 static int mock_get_event(struct cxl_dev_state *cxlds,
165 struct cxl_mbox_cmd *cmd)
166 {
167 struct cxl_get_event_payload *pl;
168 struct mock_event_log *log;
169 u16 nr_overflow;
170 u8 log_type;
171 int i;
172
173 if (cmd->size_in != sizeof(log_type))
174 return -EINVAL;
175
176 if (cmd->size_out < struct_size(pl, records, CXL_TEST_EVENT_CNT))
177 return -EINVAL;
178
179 log_type = *((u8 *)cmd->payload_in);
180 if (log_type >= CXL_EVENT_TYPE_MAX)
181 return -EINVAL;
182
183 memset(cmd->payload_out, 0, cmd->size_out);
184
185 log = event_find_log(cxlds->dev, log_type);
186 if (!log || event_log_empty(log))
187 return 0;
188
189 pl = cmd->payload_out;
190
191 for (i = 0; i < CXL_TEST_EVENT_CNT && !event_log_empty(log); i++) {
192 memcpy(&pl->records[i], event_get_current(log),
193 sizeof(pl->records[i]));
194 pl->records[i].hdr.handle = event_get_cur_event_handle(log);
195 log->cur_idx++;
196 }
197
198 pl->record_count = cpu_to_le16(i);
199 if (!event_log_empty(log))
200 pl->flags |= CXL_GET_EVENT_FLAG_MORE_RECORDS;
201
202 if (log->nr_overflow) {
203 u64 ns;
204
205 pl->flags |= CXL_GET_EVENT_FLAG_OVERFLOW;
206 pl->overflow_err_count = cpu_to_le16(nr_overflow);
207 ns = ktime_get_real_ns();
208 ns -= 5000000000; /* 5s ago */
209 pl->first_overflow_timestamp = cpu_to_le64(ns);
210 ns = ktime_get_real_ns();
211 ns -= 1000000000; /* 1s ago */
212 pl->last_overflow_timestamp = cpu_to_le64(ns);
213 }
214
215 return 0;
216 }
217
mock_clear_event(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)218 static int mock_clear_event(struct cxl_dev_state *cxlds,
219 struct cxl_mbox_cmd *cmd)
220 {
221 struct cxl_mbox_clear_event_payload *pl = cmd->payload_in;
222 struct mock_event_log *log;
223 u8 log_type = pl->event_log;
224 u16 handle;
225 int nr;
226
227 if (log_type >= CXL_EVENT_TYPE_MAX)
228 return -EINVAL;
229
230 log = event_find_log(cxlds->dev, log_type);
231 if (!log)
232 return 0; /* No mock data in this log */
233
234 /*
235 * This check is technically not invalid per the specification AFAICS.
236 * (The host could 'guess' handles and clear them in order).
237 * However, this is not good behavior for the host so test it.
238 */
239 if (log->clear_idx + pl->nr_recs > log->cur_idx) {
240 dev_err(cxlds->dev,
241 "Attempting to clear more events than returned!\n");
242 return -EINVAL;
243 }
244
245 /* Check handle order prior to clearing events */
246 for (nr = 0, handle = event_get_clear_handle(log);
247 nr < pl->nr_recs;
248 nr++, handle++) {
249 if (handle != le16_to_cpu(pl->handles[nr])) {
250 dev_err(cxlds->dev, "Clearing events out of order\n");
251 return -EINVAL;
252 }
253 }
254
255 if (log->nr_overflow)
256 log->nr_overflow = 0;
257
258 /* Clear events */
259 log->clear_idx += pl->nr_recs;
260 return 0;
261 }
262
cxl_mock_event_trigger(struct device * dev)263 static void cxl_mock_event_trigger(struct device *dev)
264 {
265 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
266 struct mock_event_store *mes = &mdata->mes;
267 int i;
268
269 for (i = CXL_EVENT_TYPE_INFO; i < CXL_EVENT_TYPE_MAX; i++) {
270 struct mock_event_log *log;
271
272 log = event_find_log(dev, i);
273 if (log)
274 event_reset_log(log);
275 }
276
277 cxl_mem_get_event_records(mes->cxlds, mes->ev_status);
278 }
279
280 struct cxl_event_record_raw maint_needed = {
281 .hdr = {
282 .id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB,
283 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
284 .length = sizeof(struct cxl_event_record_raw),
285 .flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,
286 /* .handle = Set dynamically */
287 .related_handle = cpu_to_le16(0xa5b6),
288 },
289 .data = { 0xDE, 0xAD, 0xBE, 0xEF },
290 };
291
292 struct cxl_event_record_raw hardware_replace = {
293 .hdr = {
294 .id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E,
295 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
296 .length = sizeof(struct cxl_event_record_raw),
297 .flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE,
298 /* .handle = Set dynamically */
299 .related_handle = cpu_to_le16(0xb6a5),
300 },
301 .data = { 0xDE, 0xAD, 0xBE, 0xEF },
302 };
303
304 struct cxl_event_gen_media gen_media = {
305 .hdr = {
306 .id = UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
307 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6),
308 .length = sizeof(struct cxl_event_gen_media),
309 .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT,
310 /* .handle = Set dynamically */
311 .related_handle = cpu_to_le16(0),
312 },
313 .phys_addr = cpu_to_le64(0x2000),
314 .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT,
315 .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR,
316 .transaction_type = CXL_GMER_TRANS_HOST_WRITE,
317 /* .validity_flags = <set below> */
318 .channel = 1,
319 .rank = 30
320 };
321
322 struct cxl_event_dram dram = {
323 .hdr = {
324 .id = UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
325 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24),
326 .length = sizeof(struct cxl_event_dram),
327 .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED,
328 /* .handle = Set dynamically */
329 .related_handle = cpu_to_le16(0),
330 },
331 .phys_addr = cpu_to_le64(0x8000),
332 .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT,
333 .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR,
334 .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB,
335 /* .validity_flags = <set below> */
336 .channel = 1,
337 .bank_group = 5,
338 .bank = 2,
339 .column = {0xDE, 0xAD},
340 };
341
342 struct cxl_event_mem_module mem_module = {
343 .hdr = {
344 .id = UUID_INIT(0xfe927475, 0xdd59, 0x4339,
345 0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74),
346 .length = sizeof(struct cxl_event_mem_module),
347 /* .handle = Set dynamically */
348 .related_handle = cpu_to_le16(0),
349 },
350 .event_type = CXL_MMER_TEMP_CHANGE,
351 .info = {
352 .health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED,
353 .media_status = CXL_DHI_MS_ALL_DATA_LOST,
354 .add_status = (CXL_DHI_AS_CRITICAL << 2) |
355 (CXL_DHI_AS_WARNING << 4) |
356 (CXL_DHI_AS_WARNING << 5),
357 .device_temp = { 0xDE, 0xAD},
358 .dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef },
359 .cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
360 .cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
361 }
362 };
363
cxl_mock_add_event_logs(struct mock_event_store * mes)364 static void cxl_mock_add_event_logs(struct mock_event_store *mes)
365 {
366 put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK,
367 &gen_media.validity_flags);
368
369 put_unaligned_le16(CXL_DER_VALID_CHANNEL | CXL_DER_VALID_BANK_GROUP |
370 CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN,
371 &dram.validity_flags);
372
373 mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed);
374 mes_add_event(mes, CXL_EVENT_TYPE_INFO,
375 (struct cxl_event_record_raw *)&gen_media);
376 mes_add_event(mes, CXL_EVENT_TYPE_INFO,
377 (struct cxl_event_record_raw *)&mem_module);
378 mes->ev_status |= CXLDEV_EVENT_STATUS_INFO;
379
380 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &maint_needed);
381 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
382 mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
383 (struct cxl_event_record_raw *)&dram);
384 mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
385 (struct cxl_event_record_raw *)&gen_media);
386 mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
387 (struct cxl_event_record_raw *)&mem_module);
388 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
389 mes_add_event(mes, CXL_EVENT_TYPE_FAIL,
390 (struct cxl_event_record_raw *)&dram);
391 /* Overflow this log */
392 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
393 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
394 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
395 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
396 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
397 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
398 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
399 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
400 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
401 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace);
402 mes->ev_status |= CXLDEV_EVENT_STATUS_FAIL;
403
404 mes_add_event(mes, CXL_EVENT_TYPE_FATAL, &hardware_replace);
405 mes_add_event(mes, CXL_EVENT_TYPE_FATAL,
406 (struct cxl_event_record_raw *)&dram);
407 mes->ev_status |= CXLDEV_EVENT_STATUS_FATAL;
408 }
409
mock_gsl(struct cxl_mbox_cmd * cmd)410 static int mock_gsl(struct cxl_mbox_cmd *cmd)
411 {
412 if (cmd->size_out < sizeof(mock_gsl_payload))
413 return -EINVAL;
414
415 memcpy(cmd->payload_out, &mock_gsl_payload, sizeof(mock_gsl_payload));
416 cmd->size_out = sizeof(mock_gsl_payload);
417
418 return 0;
419 }
420
mock_get_log(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)421 static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
422 {
423 struct cxl_mbox_get_log *gl = cmd->payload_in;
424 u32 offset = le32_to_cpu(gl->offset);
425 u32 length = le32_to_cpu(gl->length);
426 uuid_t uuid = DEFINE_CXL_CEL_UUID;
427 void *data = &mock_cel;
428
429 if (cmd->size_in < sizeof(*gl))
430 return -EINVAL;
431 if (length > cxlds->payload_size)
432 return -EINVAL;
433 if (offset + length > sizeof(mock_cel))
434 return -EINVAL;
435 if (!uuid_equal(&gl->uuid, &uuid))
436 return -EINVAL;
437 if (length > cmd->size_out)
438 return -EINVAL;
439
440 memcpy(cmd->payload_out, data + offset, length);
441
442 return 0;
443 }
444
mock_rcd_id(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)445 static int mock_rcd_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
446 {
447 struct cxl_mbox_identify id = {
448 .fw_revision = { "mock fw v1 " },
449 .total_capacity =
450 cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
451 .volatile_capacity =
452 cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
453 };
454
455 if (cmd->size_out < sizeof(id))
456 return -EINVAL;
457
458 memcpy(cmd->payload_out, &id, sizeof(id));
459
460 return 0;
461 }
462
mock_id(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)463 static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
464 {
465 struct cxl_mbox_identify id = {
466 .fw_revision = { "mock fw v1 " },
467 .lsa_size = cpu_to_le32(LSA_SIZE),
468 .partition_align =
469 cpu_to_le64(SZ_256M / CXL_CAPACITY_MULTIPLIER),
470 .total_capacity =
471 cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER),
472 };
473
474 if (cmd->size_out < sizeof(id))
475 return -EINVAL;
476
477 memcpy(cmd->payload_out, &id, sizeof(id));
478
479 return 0;
480 }
481
mock_partition_info(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)482 static int mock_partition_info(struct cxl_dev_state *cxlds,
483 struct cxl_mbox_cmd *cmd)
484 {
485 struct cxl_mbox_get_partition_info pi = {
486 .active_volatile_cap =
487 cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
488 .active_persistent_cap =
489 cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER),
490 };
491
492 if (cmd->size_out < sizeof(pi))
493 return -EINVAL;
494
495 memcpy(cmd->payload_out, &pi, sizeof(pi));
496
497 return 0;
498 }
499
mock_get_security_state(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)500 static int mock_get_security_state(struct cxl_dev_state *cxlds,
501 struct cxl_mbox_cmd *cmd)
502 {
503 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
504
505 if (cmd->size_in)
506 return -EINVAL;
507
508 if (cmd->size_out != sizeof(u32))
509 return -EINVAL;
510
511 memcpy(cmd->payload_out, &mdata->security_state, sizeof(u32));
512
513 return 0;
514 }
515
master_plimit_check(struct cxl_mockmem_data * mdata)516 static void master_plimit_check(struct cxl_mockmem_data *mdata)
517 {
518 if (mdata->master_limit == PASS_TRY_LIMIT)
519 return;
520 mdata->master_limit++;
521 if (mdata->master_limit == PASS_TRY_LIMIT)
522 mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PLIMIT;
523 }
524
user_plimit_check(struct cxl_mockmem_data * mdata)525 static void user_plimit_check(struct cxl_mockmem_data *mdata)
526 {
527 if (mdata->user_limit == PASS_TRY_LIMIT)
528 return;
529 mdata->user_limit++;
530 if (mdata->user_limit == PASS_TRY_LIMIT)
531 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT;
532 }
533
mock_set_passphrase(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)534 static int mock_set_passphrase(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
535 {
536 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
537 struct cxl_set_pass *set_pass;
538
539 if (cmd->size_in != sizeof(*set_pass))
540 return -EINVAL;
541
542 if (cmd->size_out != 0)
543 return -EINVAL;
544
545 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
546 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
547 return -ENXIO;
548 }
549
550 set_pass = cmd->payload_in;
551 switch (set_pass->type) {
552 case CXL_PMEM_SEC_PASS_MASTER:
553 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) {
554 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
555 return -ENXIO;
556 }
557 /*
558 * CXL spec rev3.0 8.2.9.8.6.2, The master pasphrase shall only be set in
559 * the security disabled state when the user passphrase is not set.
560 */
561 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
562 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
563 return -ENXIO;
564 }
565 if (memcmp(mdata->master_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) {
566 master_plimit_check(mdata);
567 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
568 return -ENXIO;
569 }
570 memcpy(mdata->master_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN);
571 mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PASS_SET;
572 return 0;
573
574 case CXL_PMEM_SEC_PASS_USER:
575 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
576 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
577 return -ENXIO;
578 }
579 if (memcmp(mdata->user_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) {
580 user_plimit_check(mdata);
581 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
582 return -ENXIO;
583 }
584 memcpy(mdata->user_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN);
585 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PASS_SET;
586 return 0;
587
588 default:
589 cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
590 }
591 return -EINVAL;
592 }
593
mock_disable_passphrase(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)594 static int mock_disable_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_disable_pass *dis_pass;
598
599 if (cmd->size_in != sizeof(*dis_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 dis_pass = cmd->payload_in;
611 switch (dis_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 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)) {
619 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
620 return -ENXIO;
621 }
622
623 if (memcmp(dis_pass->pass, mdata->master_pass, NVDIMM_PASSPHRASE_LEN)) {
624 master_plimit_check(mdata);
625 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
626 return -ENXIO;
627 }
628
629 mdata->master_limit = 0;
630 memset(mdata->master_pass, 0, 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
640 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) {
641 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
642 return -ENXIO;
643 }
644
645 if (memcmp(dis_pass->pass, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) {
646 user_plimit_check(mdata);
647 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
648 return -ENXIO;
649 }
650
651 mdata->user_limit = 0;
652 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
653 mdata->security_state &= ~(CXL_PMEM_SEC_STATE_USER_PASS_SET |
654 CXL_PMEM_SEC_STATE_LOCKED);
655 return 0;
656
657 default:
658 cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
659 return -EINVAL;
660 }
661
662 return 0;
663 }
664
mock_freeze_security(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)665 static int mock_freeze_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
666 {
667 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
668
669 if (cmd->size_in != 0)
670 return -EINVAL;
671
672 if (cmd->size_out != 0)
673 return -EINVAL;
674
675 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN)
676 return 0;
677
678 mdata->security_state |= CXL_PMEM_SEC_STATE_FROZEN;
679 return 0;
680 }
681
mock_unlock_security(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)682 static int mock_unlock_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
683 {
684 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
685
686 if (cmd->size_in != NVDIMM_PASSPHRASE_LEN)
687 return -EINVAL;
688
689 if (cmd->size_out != 0)
690 return -EINVAL;
691
692 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
693 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
694 return -ENXIO;
695 }
696
697 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) {
698 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
699 return -ENXIO;
700 }
701
702 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) {
703 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
704 return -ENXIO;
705 }
706
707 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED)) {
708 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
709 return -ENXIO;
710 }
711
712 if (memcmp(cmd->payload_in, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) {
713 if (++mdata->user_limit == PASS_TRY_LIMIT)
714 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT;
715 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
716 return -ENXIO;
717 }
718
719 mdata->user_limit = 0;
720 mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED;
721 return 0;
722 }
723
mock_passphrase_secure_erase(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)724 static int mock_passphrase_secure_erase(struct cxl_dev_state *cxlds,
725 struct cxl_mbox_cmd *cmd)
726 {
727 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
728 struct cxl_pass_erase *erase;
729
730 if (cmd->size_in != sizeof(*erase))
731 return -EINVAL;
732
733 if (cmd->size_out != 0)
734 return -EINVAL;
735
736 erase = cmd->payload_in;
737 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) {
738 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
739 return -ENXIO;
740 }
741
742 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT &&
743 erase->type == CXL_PMEM_SEC_PASS_USER) {
744 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
745 return -ENXIO;
746 }
747
748 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT &&
749 erase->type == CXL_PMEM_SEC_PASS_MASTER) {
750 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
751 return -ENXIO;
752 }
753
754 switch (erase->type) {
755 case CXL_PMEM_SEC_PASS_MASTER:
756 /*
757 * The spec does not clearly define the behavior of the scenario
758 * where a master passphrase is passed in while the master
759 * passphrase is not set and user passphrase is not set. The
760 * code will take the assumption that it will behave the same
761 * as a CXL secure erase command without passphrase (0x4401).
762 */
763 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET) {
764 if (memcmp(mdata->master_pass, erase->pass,
765 NVDIMM_PASSPHRASE_LEN)) {
766 master_plimit_check(mdata);
767 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
768 return -ENXIO;
769 }
770 mdata->master_limit = 0;
771 mdata->user_limit = 0;
772 mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET;
773 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
774 mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED;
775 } else {
776 /*
777 * CXL rev3 8.2.9.8.6.3 Disable Passphrase
778 * When master passphrase is disabled, the device shall
779 * return Invalid Input for the Passphrase Secure Erase
780 * command with master passphrase.
781 */
782 return -EINVAL;
783 }
784 /* Scramble encryption keys so that data is effectively erased */
785 break;
786 case CXL_PMEM_SEC_PASS_USER:
787 /*
788 * The spec does not clearly define the behavior of the scenario
789 * where a user passphrase is passed in while the user
790 * passphrase is not set. The code will take the assumption that
791 * it will behave the same as a CXL secure erase command without
792 * passphrase (0x4401).
793 */
794 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
795 if (memcmp(mdata->user_pass, erase->pass,
796 NVDIMM_PASSPHRASE_LEN)) {
797 user_plimit_check(mdata);
798 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE;
799 return -ENXIO;
800 }
801 mdata->user_limit = 0;
802 mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET;
803 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN);
804 }
805
806 /*
807 * CXL rev3 Table 8-118
808 * If user passphrase is not set or supported by device, current
809 * passphrase value is ignored. Will make the assumption that
810 * the operation will proceed as secure erase w/o passphrase
811 * since spec is not explicit.
812 */
813
814 /* Scramble encryption keys so that data is effectively erased */
815 break;
816 default:
817 return -EINVAL;
818 }
819
820 return 0;
821 }
822
mock_get_lsa(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)823 static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
824 {
825 struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in;
826 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
827 void *lsa = mdata->lsa;
828 u32 offset, length;
829
830 if (sizeof(*get_lsa) > cmd->size_in)
831 return -EINVAL;
832 offset = le32_to_cpu(get_lsa->offset);
833 length = le32_to_cpu(get_lsa->length);
834 if (offset + length > LSA_SIZE)
835 return -EINVAL;
836 if (length > cmd->size_out)
837 return -EINVAL;
838
839 memcpy(cmd->payload_out, lsa + offset, length);
840 return 0;
841 }
842
mock_set_lsa(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)843 static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
844 {
845 struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in;
846 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
847 void *lsa = mdata->lsa;
848 u32 offset, length;
849
850 if (sizeof(*set_lsa) > cmd->size_in)
851 return -EINVAL;
852 offset = le32_to_cpu(set_lsa->offset);
853 length = cmd->size_in - sizeof(*set_lsa);
854 if (offset + length > LSA_SIZE)
855 return -EINVAL;
856
857 memcpy(lsa + offset, &set_lsa->data[0], length);
858 return 0;
859 }
860
mock_health_info(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)861 static int mock_health_info(struct cxl_dev_state *cxlds,
862 struct cxl_mbox_cmd *cmd)
863 {
864 struct cxl_mbox_health_info health_info = {
865 /* set flags for maint needed, perf degraded, hw replacement */
866 .health_status = 0x7,
867 /* set media status to "All Data Lost" */
868 .media_status = 0x3,
869 /*
870 * set ext_status flags for:
871 * ext_life_used: normal,
872 * ext_temperature: critical,
873 * ext_corrected_volatile: warning,
874 * ext_corrected_persistent: normal,
875 */
876 .ext_status = 0x18,
877 .life_used = 15,
878 .temperature = cpu_to_le16(25),
879 .dirty_shutdowns = cpu_to_le32(10),
880 .volatile_errors = cpu_to_le32(20),
881 .pmem_errors = cpu_to_le32(30),
882 };
883
884 if (cmd->size_out < sizeof(health_info))
885 return -EINVAL;
886
887 memcpy(cmd->payload_out, &health_info, sizeof(health_info));
888 return 0;
889 }
890
cxl_mock_mbox_send(struct cxl_dev_state * cxlds,struct cxl_mbox_cmd * cmd)891 static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
892 {
893 struct device *dev = cxlds->dev;
894 int rc = -EIO;
895
896 switch (cmd->opcode) {
897 case CXL_MBOX_OP_GET_SUPPORTED_LOGS:
898 rc = mock_gsl(cmd);
899 break;
900 case CXL_MBOX_OP_GET_LOG:
901 rc = mock_get_log(cxlds, cmd);
902 break;
903 case CXL_MBOX_OP_IDENTIFY:
904 if (cxlds->rcd)
905 rc = mock_rcd_id(cxlds, cmd);
906 else
907 rc = mock_id(cxlds, cmd);
908 break;
909 case CXL_MBOX_OP_GET_LSA:
910 rc = mock_get_lsa(cxlds, cmd);
911 break;
912 case CXL_MBOX_OP_GET_PARTITION_INFO:
913 rc = mock_partition_info(cxlds, cmd);
914 break;
915 case CXL_MBOX_OP_GET_EVENT_RECORD:
916 rc = mock_get_event(cxlds, cmd);
917 break;
918 case CXL_MBOX_OP_CLEAR_EVENT_RECORD:
919 rc = mock_clear_event(cxlds, cmd);
920 break;
921 case CXL_MBOX_OP_SET_LSA:
922 rc = mock_set_lsa(cxlds, cmd);
923 break;
924 case CXL_MBOX_OP_GET_HEALTH_INFO:
925 rc = mock_health_info(cxlds, cmd);
926 break;
927 case CXL_MBOX_OP_GET_SECURITY_STATE:
928 rc = mock_get_security_state(cxlds, cmd);
929 break;
930 case CXL_MBOX_OP_SET_PASSPHRASE:
931 rc = mock_set_passphrase(cxlds, cmd);
932 break;
933 case CXL_MBOX_OP_DISABLE_PASSPHRASE:
934 rc = mock_disable_passphrase(cxlds, cmd);
935 break;
936 case CXL_MBOX_OP_FREEZE_SECURITY:
937 rc = mock_freeze_security(cxlds, cmd);
938 break;
939 case CXL_MBOX_OP_UNLOCK:
940 rc = mock_unlock_security(cxlds, cmd);
941 break;
942 case CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE:
943 rc = mock_passphrase_secure_erase(cxlds, cmd);
944 break;
945 default:
946 break;
947 }
948
949 dev_dbg(dev, "opcode: %#x sz_in: %zd sz_out: %zd rc: %d\n", cmd->opcode,
950 cmd->size_in, cmd->size_out, rc);
951
952 return rc;
953 }
954
label_area_release(void * lsa)955 static void label_area_release(void *lsa)
956 {
957 vfree(lsa);
958 }
959
is_rcd(struct platform_device * pdev)960 static bool is_rcd(struct platform_device *pdev)
961 {
962 const struct platform_device_id *id = platform_get_device_id(pdev);
963
964 return !!id->driver_data;
965 }
966
event_trigger_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)967 static ssize_t event_trigger_store(struct device *dev,
968 struct device_attribute *attr,
969 const char *buf, size_t count)
970 {
971 cxl_mock_event_trigger(dev);
972 return count;
973 }
974 static DEVICE_ATTR_WO(event_trigger);
975
cxl_mock_mem_probe(struct platform_device * pdev)976 static int cxl_mock_mem_probe(struct platform_device *pdev)
977 {
978 struct device *dev = &pdev->dev;
979 struct cxl_memdev *cxlmd;
980 struct cxl_dev_state *cxlds;
981 struct cxl_mockmem_data *mdata;
982 int rc;
983
984 mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL);
985 if (!mdata)
986 return -ENOMEM;
987 dev_set_drvdata(dev, mdata);
988
989 mdata->lsa = vmalloc(LSA_SIZE);
990 if (!mdata->lsa)
991 return -ENOMEM;
992 rc = devm_add_action_or_reset(dev, label_area_release, mdata->lsa);
993 if (rc)
994 return rc;
995
996 cxlds = cxl_dev_state_create(dev);
997 if (IS_ERR(cxlds))
998 return PTR_ERR(cxlds);
999
1000 cxlds->serial = pdev->id;
1001 cxlds->mbox_send = cxl_mock_mbox_send;
1002 cxlds->payload_size = SZ_4K;
1003 cxlds->event.buf = (struct cxl_get_event_payload *) mdata->event_buf;
1004 if (is_rcd(pdev)) {
1005 cxlds->rcd = true;
1006 cxlds->component_reg_phys = CXL_RESOURCE_NONE;
1007 }
1008
1009 rc = cxl_enumerate_cmds(cxlds);
1010 if (rc)
1011 return rc;
1012
1013 rc = cxl_dev_state_identify(cxlds);
1014 if (rc)
1015 return rc;
1016
1017 rc = cxl_mem_create_range_info(cxlds);
1018 if (rc)
1019 return rc;
1020
1021 mdata->mes.cxlds = cxlds;
1022 cxl_mock_add_event_logs(&mdata->mes);
1023
1024 cxlmd = devm_cxl_add_memdev(cxlds);
1025 if (IS_ERR(cxlmd))
1026 return PTR_ERR(cxlmd);
1027
1028 cxl_mem_get_event_records(cxlds, CXLDEV_EVENT_STATUS_ALL);
1029
1030 return 0;
1031 }
1032
security_lock_show(struct device * dev,struct device_attribute * attr,char * buf)1033 static ssize_t security_lock_show(struct device *dev,
1034 struct device_attribute *attr, char *buf)
1035 {
1036 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
1037
1038 return sysfs_emit(buf, "%u\n",
1039 !!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED));
1040 }
1041
security_lock_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1042 static ssize_t security_lock_store(struct device *dev, struct device_attribute *attr,
1043 const char *buf, size_t count)
1044 {
1045 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
1046 u32 mask = CXL_PMEM_SEC_STATE_FROZEN | CXL_PMEM_SEC_STATE_USER_PLIMIT |
1047 CXL_PMEM_SEC_STATE_MASTER_PLIMIT;
1048 int val;
1049
1050 if (kstrtoint(buf, 0, &val) < 0)
1051 return -EINVAL;
1052
1053 if (val == 1) {
1054 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
1055 return -ENXIO;
1056 mdata->security_state |= CXL_PMEM_SEC_STATE_LOCKED;
1057 mdata->security_state &= ~mask;
1058 } else {
1059 return -EINVAL;
1060 }
1061 return count;
1062 }
1063
1064 static DEVICE_ATTR_RW(security_lock);
1065
1066 static struct attribute *cxl_mock_mem_attrs[] = {
1067 &dev_attr_security_lock.attr,
1068 &dev_attr_event_trigger.attr,
1069 NULL
1070 };
1071 ATTRIBUTE_GROUPS(cxl_mock_mem);
1072
1073 static const struct platform_device_id cxl_mock_mem_ids[] = {
1074 { .name = "cxl_mem", 0 },
1075 { .name = "cxl_rcd", 1 },
1076 { },
1077 };
1078 MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids);
1079
1080 static struct platform_driver cxl_mock_mem_driver = {
1081 .probe = cxl_mock_mem_probe,
1082 .id_table = cxl_mock_mem_ids,
1083 .driver = {
1084 .name = KBUILD_MODNAME,
1085 .dev_groups = cxl_mock_mem_groups,
1086 },
1087 };
1088
1089 module_platform_driver(cxl_mock_mem_driver);
1090 MODULE_LICENSE("GPL v2");
1091 MODULE_IMPORT_NS(CXL);
1092