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/vmalloc.h> 6 #include <linux/module.h> 7 #include <linux/delay.h> 8 #include <linux/sizes.h> 9 #include <linux/bits.h> 10 #include <cxl/mailbox.h> 11 #include <linux/unaligned.h> 12 #include <crypto/sha2.h> 13 #include <cxlmem.h> 14 15 #include "trace.h" 16 17 #define LSA_SIZE SZ_128K 18 #define FW_SIZE SZ_64M 19 #define FW_SLOTS 3 20 #define DEV_SIZE SZ_2G 21 #define EFFECT(x) (1U << x) 22 23 #define MOCK_INJECT_DEV_MAX 8 24 #define MOCK_INJECT_TEST_MAX 128 25 26 static unsigned int poison_inject_dev_max = MOCK_INJECT_DEV_MAX; 27 28 enum cxl_command_effects { 29 CONF_CHANGE_COLD_RESET = 0, 30 CONF_CHANGE_IMMEDIATE, 31 DATA_CHANGE_IMMEDIATE, 32 POLICY_CHANGE_IMMEDIATE, 33 LOG_CHANGE_IMMEDIATE, 34 SECURITY_CHANGE_IMMEDIATE, 35 BACKGROUND_OP, 36 SECONDARY_MBOX_SUPPORTED, 37 }; 38 39 #define CXL_CMD_EFFECT_NONE cpu_to_le16(0) 40 41 static struct cxl_cel_entry mock_cel[] = { 42 { 43 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_SUPPORTED_LOGS), 44 .effect = CXL_CMD_EFFECT_NONE, 45 }, 46 { 47 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_SUPPORTED_FEATURES), 48 .effect = CXL_CMD_EFFECT_NONE, 49 }, 50 { 51 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_FEATURE), 52 .effect = CXL_CMD_EFFECT_NONE, 53 }, 54 { 55 .opcode = cpu_to_le16(CXL_MBOX_OP_SET_FEATURE), 56 .effect = cpu_to_le16(EFFECT(CONF_CHANGE_IMMEDIATE)), 57 }, 58 { 59 .opcode = cpu_to_le16(CXL_MBOX_OP_IDENTIFY), 60 .effect = CXL_CMD_EFFECT_NONE, 61 }, 62 { 63 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA), 64 .effect = CXL_CMD_EFFECT_NONE, 65 }, 66 { 67 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_PARTITION_INFO), 68 .effect = CXL_CMD_EFFECT_NONE, 69 }, 70 { 71 .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA), 72 .effect = cpu_to_le16(EFFECT(CONF_CHANGE_IMMEDIATE) | 73 EFFECT(DATA_CHANGE_IMMEDIATE)), 74 }, 75 { 76 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO), 77 .effect = CXL_CMD_EFFECT_NONE, 78 }, 79 { 80 .opcode = cpu_to_le16(CXL_MBOX_OP_SET_SHUTDOWN_STATE), 81 .effect = POLICY_CHANGE_IMMEDIATE, 82 }, 83 { 84 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_POISON), 85 .effect = CXL_CMD_EFFECT_NONE, 86 }, 87 { 88 .opcode = cpu_to_le16(CXL_MBOX_OP_INJECT_POISON), 89 .effect = cpu_to_le16(EFFECT(DATA_CHANGE_IMMEDIATE)), 90 }, 91 { 92 .opcode = cpu_to_le16(CXL_MBOX_OP_CLEAR_POISON), 93 .effect = cpu_to_le16(EFFECT(DATA_CHANGE_IMMEDIATE)), 94 }, 95 { 96 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_FW_INFO), 97 .effect = CXL_CMD_EFFECT_NONE, 98 }, 99 { 100 .opcode = cpu_to_le16(CXL_MBOX_OP_TRANSFER_FW), 101 .effect = cpu_to_le16(EFFECT(CONF_CHANGE_COLD_RESET) | 102 EFFECT(BACKGROUND_OP)), 103 }, 104 { 105 .opcode = cpu_to_le16(CXL_MBOX_OP_ACTIVATE_FW), 106 .effect = cpu_to_le16(EFFECT(CONF_CHANGE_COLD_RESET) | 107 EFFECT(CONF_CHANGE_IMMEDIATE)), 108 }, 109 { 110 .opcode = cpu_to_le16(CXL_MBOX_OP_SANITIZE), 111 .effect = cpu_to_le16(EFFECT(DATA_CHANGE_IMMEDIATE) | 112 EFFECT(SECURITY_CHANGE_IMMEDIATE) | 113 EFFECT(BACKGROUND_OP)), 114 }, 115 }; 116 117 /* See CXL 2.0 Table 181 Get Health Info Output Payload */ 118 struct cxl_mbox_health_info { 119 u8 health_status; 120 u8 media_status; 121 u8 ext_status; 122 u8 life_used; 123 __le16 temperature; 124 __le32 dirty_shutdowns; 125 __le32 volatile_errors; 126 __le32 pmem_errors; 127 } __packed; 128 129 static struct { 130 struct cxl_mbox_get_supported_logs gsl; 131 struct cxl_gsl_entry entry; 132 } mock_gsl_payload = { 133 .gsl = { 134 .entries = cpu_to_le16(1), 135 }, 136 .entry = { 137 .uuid = DEFINE_CXL_CEL_UUID, 138 .size = cpu_to_le32(sizeof(mock_cel)), 139 }, 140 }; 141 142 #define PASS_TRY_LIMIT 3 143 144 #define CXL_TEST_EVENT_CNT_MAX 15 145 146 /* Set a number of events to return at a time for simulation. */ 147 #define CXL_TEST_EVENT_RET_MAX 4 148 149 struct mock_event_log { 150 u16 clear_idx; 151 u16 cur_idx; 152 u16 nr_events; 153 u16 nr_overflow; 154 u16 overflow_reset; 155 struct cxl_event_record_raw *events[CXL_TEST_EVENT_CNT_MAX]; 156 }; 157 158 struct mock_event_store { 159 struct mock_event_log mock_logs[CXL_EVENT_TYPE_MAX]; 160 u32 ev_status; 161 }; 162 163 struct vendor_test_feat { 164 __le32 data; 165 } __packed; 166 167 struct cxl_mockmem_data { 168 void *lsa; 169 void *fw; 170 int fw_slot; 171 int fw_staged; 172 size_t fw_size; 173 u32 security_state; 174 u8 user_pass[NVDIMM_PASSPHRASE_LEN]; 175 u8 master_pass[NVDIMM_PASSPHRASE_LEN]; 176 int user_limit; 177 int master_limit; 178 struct mock_event_store mes; 179 struct cxl_memdev_state *mds; 180 u8 event_buf[SZ_4K]; 181 u64 timestamp; 182 unsigned long sanitize_timeout; 183 struct vendor_test_feat test_feat; 184 u8 shutdown_state; 185 }; 186 187 static struct mock_event_log *event_find_log(struct device *dev, int log_type) 188 { 189 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 190 191 if (log_type >= CXL_EVENT_TYPE_MAX) 192 return NULL; 193 return &mdata->mes.mock_logs[log_type]; 194 } 195 196 static struct cxl_event_record_raw *event_get_current(struct mock_event_log *log) 197 { 198 return log->events[log->cur_idx]; 199 } 200 201 static void event_reset_log(struct mock_event_log *log) 202 { 203 log->cur_idx = 0; 204 log->clear_idx = 0; 205 log->nr_overflow = log->overflow_reset; 206 } 207 208 /* Handle can never be 0 use 1 based indexing for handle */ 209 static u16 event_get_clear_handle(struct mock_event_log *log) 210 { 211 return log->clear_idx + 1; 212 } 213 214 /* Handle can never be 0 use 1 based indexing for handle */ 215 static __le16 event_get_cur_event_handle(struct mock_event_log *log) 216 { 217 u16 cur_handle = log->cur_idx + 1; 218 219 return cpu_to_le16(cur_handle); 220 } 221 222 static bool event_log_empty(struct mock_event_log *log) 223 { 224 return log->cur_idx == log->nr_events; 225 } 226 227 static void mes_add_event(struct mock_event_store *mes, 228 enum cxl_event_log_type log_type, 229 struct cxl_event_record_raw *event) 230 { 231 struct mock_event_log *log; 232 233 if (WARN_ON(log_type >= CXL_EVENT_TYPE_MAX)) 234 return; 235 236 log = &mes->mock_logs[log_type]; 237 238 if ((log->nr_events + 1) > CXL_TEST_EVENT_CNT_MAX) { 239 log->nr_overflow++; 240 log->overflow_reset = log->nr_overflow; 241 return; 242 } 243 244 log->events[log->nr_events] = event; 245 log->nr_events++; 246 } 247 248 /* 249 * Vary the number of events returned to simulate events occuring while the 250 * logs are being read. 251 */ 252 static atomic_t event_counter = ATOMIC_INIT(0); 253 254 static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd) 255 { 256 struct cxl_get_event_payload *pl; 257 struct mock_event_log *log; 258 int ret_limit; 259 u8 log_type; 260 int i; 261 262 if (cmd->size_in != sizeof(log_type)) 263 return -EINVAL; 264 265 /* Vary return limit from 1 to CXL_TEST_EVENT_RET_MAX */ 266 ret_limit = (atomic_inc_return(&event_counter) % CXL_TEST_EVENT_RET_MAX) + 1; 267 268 if (cmd->size_out < struct_size(pl, records, ret_limit)) 269 return -EINVAL; 270 271 log_type = *((u8 *)cmd->payload_in); 272 if (log_type >= CXL_EVENT_TYPE_MAX) 273 return -EINVAL; 274 275 memset(cmd->payload_out, 0, struct_size(pl, records, 0)); 276 277 log = event_find_log(dev, log_type); 278 if (!log || event_log_empty(log)) 279 return 0; 280 281 pl = cmd->payload_out; 282 283 for (i = 0; i < ret_limit && !event_log_empty(log); i++) { 284 memcpy(&pl->records[i], event_get_current(log), 285 sizeof(pl->records[i])); 286 pl->records[i].event.generic.hdr.handle = 287 event_get_cur_event_handle(log); 288 log->cur_idx++; 289 } 290 291 cmd->size_out = struct_size(pl, records, i); 292 pl->record_count = cpu_to_le16(i); 293 if (!event_log_empty(log)) 294 pl->flags |= CXL_GET_EVENT_FLAG_MORE_RECORDS; 295 296 if (log->nr_overflow) { 297 u64 ns; 298 299 pl->flags |= CXL_GET_EVENT_FLAG_OVERFLOW; 300 pl->overflow_err_count = cpu_to_le16(log->nr_overflow); 301 ns = ktime_get_real_ns(); 302 ns -= 5000000000; /* 5s ago */ 303 pl->first_overflow_timestamp = cpu_to_le64(ns); 304 ns = ktime_get_real_ns(); 305 ns -= 1000000000; /* 1s ago */ 306 pl->last_overflow_timestamp = cpu_to_le64(ns); 307 } 308 309 return 0; 310 } 311 312 static int mock_clear_event(struct device *dev, struct cxl_mbox_cmd *cmd) 313 { 314 struct cxl_mbox_clear_event_payload *pl; 315 struct mock_event_log *log; 316 u8 log_type; 317 u16 handle; 318 int nr; 319 320 if (cmd->size_in < sizeof(*pl)) 321 return -EINVAL; 322 323 pl = cmd->payload_in; 324 log_type = pl->event_log; 325 if (log_type >= CXL_EVENT_TYPE_MAX) 326 return -EINVAL; 327 328 log = event_find_log(dev, log_type); 329 if (!log) 330 return 0; /* No mock data in this log */ 331 332 /* 333 * This check is technically not invalid per the specification AFAICS. 334 * (The host could 'guess' handles and clear them in order). 335 * However, this is not good behavior for the host so test it. 336 */ 337 if (log->clear_idx + pl->nr_recs > log->cur_idx) { 338 dev_err(dev, 339 "Attempting to clear more events than returned!\n"); 340 return -EINVAL; 341 } 342 343 /* Check handle order prior to clearing events */ 344 for (nr = 0, handle = event_get_clear_handle(log); 345 nr < pl->nr_recs; 346 nr++, handle++) { 347 if (handle != le16_to_cpu(pl->handles[nr])) { 348 dev_err(dev, "Clearing events out of order\n"); 349 return -EINVAL; 350 } 351 } 352 353 if (log->nr_overflow) 354 log->nr_overflow = 0; 355 356 /* Clear events */ 357 log->clear_idx += pl->nr_recs; 358 return 0; 359 } 360 361 static void cxl_mock_event_trigger(struct device *dev) 362 { 363 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 364 struct mock_event_store *mes = &mdata->mes; 365 int i; 366 367 for (i = CXL_EVENT_TYPE_INFO; i < CXL_EVENT_TYPE_MAX; i++) { 368 struct mock_event_log *log; 369 370 log = event_find_log(dev, i); 371 if (log) 372 event_reset_log(log); 373 } 374 375 cxl_mem_get_event_records(mdata->mds, mes->ev_status); 376 } 377 378 struct cxl_event_record_raw maint_needed = { 379 .id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB, 380 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5), 381 .event.generic = { 382 .hdr = { 383 .length = sizeof(struct cxl_event_record_raw), 384 .flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED, 385 /* .handle = Set dynamically */ 386 .related_handle = cpu_to_le16(0xa5b6), 387 }, 388 .data = { 0xDE, 0xAD, 0xBE, 0xEF }, 389 }, 390 }; 391 392 struct cxl_event_record_raw hardware_replace = { 393 .id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E, 394 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5), 395 .event.generic = { 396 .hdr = { 397 .length = sizeof(struct cxl_event_record_raw), 398 .flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE, 399 /* .handle = Set dynamically */ 400 .related_handle = cpu_to_le16(0xb6a5), 401 }, 402 .data = { 0xDE, 0xAD, 0xBE, 0xEF }, 403 }, 404 }; 405 406 struct cxl_test_gen_media { 407 uuid_t id; 408 struct cxl_event_gen_media rec; 409 } __packed; 410 411 struct cxl_test_gen_media gen_media = { 412 .id = CXL_EVENT_GEN_MEDIA_UUID, 413 .rec = { 414 .media_hdr = { 415 .hdr = { 416 .length = sizeof(struct cxl_test_gen_media), 417 .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT, 418 /* .handle = Set dynamically */ 419 .related_handle = cpu_to_le16(0), 420 }, 421 .phys_addr = cpu_to_le64(0x2000), 422 .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT, 423 .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR, 424 .transaction_type = CXL_GMER_TRANS_HOST_WRITE, 425 /* .validity_flags = <set below> */ 426 .channel = 1, 427 .rank = 30, 428 }, 429 .component_id = { 0x3, 0x74, 0xc5, 0x8, 0x9a, 0x1a, 0xb, 0xfc, 0xd2, 0x7e, 0x2f, 0x31, 0x9b, 0x3c, 0x81, 0x4d }, 430 .cme_threshold_ev_flags = 3, 431 .cme_count = { 33, 0, 0 }, 432 .sub_type = 0x2, 433 }, 434 }; 435 436 struct cxl_test_dram { 437 uuid_t id; 438 struct cxl_event_dram rec; 439 } __packed; 440 441 struct cxl_test_dram dram = { 442 .id = CXL_EVENT_DRAM_UUID, 443 .rec = { 444 .media_hdr = { 445 .hdr = { 446 .length = sizeof(struct cxl_test_dram), 447 .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED, 448 /* .handle = Set dynamically */ 449 .related_handle = cpu_to_le16(0), 450 }, 451 .phys_addr = cpu_to_le64(0x8000), 452 .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT, 453 .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR, 454 .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB, 455 /* .validity_flags = <set below> */ 456 .channel = 1, 457 }, 458 .bank_group = 5, 459 .bank = 2, 460 .column = {0xDE, 0xAD}, 461 .component_id = { 0x1, 0x74, 0xc5, 0x8, 0x9a, 0x1a, 0xb, 0xfc, 0xd2, 0x7e, 0x2f, 0x31, 0x9b, 0x3c, 0x81, 0x4d }, 462 .sub_channel = 8, 463 .cme_threshold_ev_flags = 2, 464 .cvme_count = { 14, 0, 0 }, 465 .sub_type = 0x5, 466 }, 467 }; 468 469 struct cxl_test_mem_module { 470 uuid_t id; 471 struct cxl_event_mem_module rec; 472 } __packed; 473 474 struct cxl_test_mem_module mem_module = { 475 .id = CXL_EVENT_MEM_MODULE_UUID, 476 .rec = { 477 .hdr = { 478 .length = sizeof(struct cxl_test_mem_module), 479 /* .handle = Set dynamically */ 480 .related_handle = cpu_to_le16(0), 481 }, 482 .event_type = CXL_MMER_TEMP_CHANGE, 483 .info = { 484 .health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED, 485 .media_status = CXL_DHI_MS_ALL_DATA_LOST, 486 .add_status = (CXL_DHI_AS_CRITICAL << 2) | 487 (CXL_DHI_AS_WARNING << 4) | 488 (CXL_DHI_AS_WARNING << 5), 489 .device_temp = { 0xDE, 0xAD}, 490 .dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef }, 491 .cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef }, 492 .cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef }, 493 }, 494 /* .validity_flags = <set below> */ 495 .component_id = { 0x2, 0x74, 0xc5, 0x8, 0x9a, 0x1a, 0xb, 0xfc, 0xd2, 0x7e, 0x2f, 0x31, 0x9b, 0x3c, 0x81, 0x4d }, 496 .event_sub_type = 0x3, 497 }, 498 }; 499 500 static int mock_set_timestamp(struct cxl_dev_state *cxlds, 501 struct cxl_mbox_cmd *cmd) 502 { 503 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 504 struct cxl_mbox_set_timestamp_in *ts = cmd->payload_in; 505 506 if (cmd->size_in != sizeof(*ts)) 507 return -EINVAL; 508 509 if (cmd->size_out != 0) 510 return -EINVAL; 511 512 mdata->timestamp = le64_to_cpu(ts->timestamp); 513 return 0; 514 } 515 516 static void cxl_mock_add_event_logs(struct mock_event_store *mes) 517 { 518 put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK | 519 CXL_GMER_VALID_COMPONENT | CXL_GMER_VALID_COMPONENT_ID_FORMAT, 520 &gen_media.rec.media_hdr.validity_flags); 521 522 put_unaligned_le16(CXL_DER_VALID_CHANNEL | CXL_DER_VALID_BANK_GROUP | 523 CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN | CXL_DER_VALID_SUB_CHANNEL | 524 CXL_DER_VALID_COMPONENT | CXL_DER_VALID_COMPONENT_ID_FORMAT, 525 &dram.rec.media_hdr.validity_flags); 526 527 put_unaligned_le16(CXL_MMER_VALID_COMPONENT | CXL_MMER_VALID_COMPONENT_ID_FORMAT, 528 &mem_module.rec.validity_flags); 529 530 mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed); 531 mes_add_event(mes, CXL_EVENT_TYPE_INFO, 532 (struct cxl_event_record_raw *)&gen_media); 533 mes_add_event(mes, CXL_EVENT_TYPE_INFO, 534 (struct cxl_event_record_raw *)&mem_module); 535 mes->ev_status |= CXLDEV_EVENT_STATUS_INFO; 536 537 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &maint_needed); 538 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 539 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, 540 (struct cxl_event_record_raw *)&dram); 541 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, 542 (struct cxl_event_record_raw *)&gen_media); 543 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, 544 (struct cxl_event_record_raw *)&mem_module); 545 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 546 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, 547 (struct cxl_event_record_raw *)&dram); 548 /* Overflow this log */ 549 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 550 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 551 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 552 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 553 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 554 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 555 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 556 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 557 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 558 mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); 559 mes->ev_status |= CXLDEV_EVENT_STATUS_FAIL; 560 561 mes_add_event(mes, CXL_EVENT_TYPE_FATAL, &hardware_replace); 562 mes_add_event(mes, CXL_EVENT_TYPE_FATAL, 563 (struct cxl_event_record_raw *)&dram); 564 mes->ev_status |= CXLDEV_EVENT_STATUS_FATAL; 565 } 566 567 static int mock_gsl(struct cxl_mbox_cmd *cmd) 568 { 569 if (cmd->size_out < sizeof(mock_gsl_payload)) 570 return -EINVAL; 571 572 memcpy(cmd->payload_out, &mock_gsl_payload, sizeof(mock_gsl_payload)); 573 cmd->size_out = sizeof(mock_gsl_payload); 574 575 return 0; 576 } 577 578 static int mock_get_log(struct cxl_memdev_state *mds, struct cxl_mbox_cmd *cmd) 579 { 580 struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 581 uuid_t uuid = DEFINE_CXL_CEL_UUID; 582 struct cxl_mbox_get_log *gl; 583 void *data = &mock_cel; 584 u32 offset; 585 u32 length; 586 587 if (cmd->size_in < sizeof(*gl)) 588 return -EINVAL; 589 590 gl = cmd->payload_in; 591 offset = le32_to_cpu(gl->offset); 592 length = le32_to_cpu(gl->length); 593 594 if (length > cxl_mbox->payload_size) 595 return -EINVAL; 596 if (offset + length > sizeof(mock_cel)) 597 return -EINVAL; 598 if (!uuid_equal(&gl->uuid, &uuid)) 599 return -EINVAL; 600 if (length > cmd->size_out) 601 return -EINVAL; 602 603 memcpy(cmd->payload_out, data + offset, length); 604 605 return 0; 606 } 607 608 static int mock_rcd_id(struct cxl_mbox_cmd *cmd) 609 { 610 struct cxl_mbox_identify id = { 611 .fw_revision = { "mock fw v1 " }, 612 .total_capacity = 613 cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER), 614 .volatile_capacity = 615 cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER), 616 }; 617 618 if (cmd->size_out < sizeof(id)) 619 return -EINVAL; 620 621 memcpy(cmd->payload_out, &id, sizeof(id)); 622 623 return 0; 624 } 625 626 static int mock_id(struct cxl_mbox_cmd *cmd) 627 { 628 struct cxl_mbox_identify id = { 629 .fw_revision = { "mock fw v1 " }, 630 .lsa_size = cpu_to_le32(LSA_SIZE), 631 .partition_align = 632 cpu_to_le64(SZ_256M / CXL_CAPACITY_MULTIPLIER), 633 .total_capacity = 634 cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER), 635 .inject_poison_limit = cpu_to_le16(MOCK_INJECT_TEST_MAX), 636 }; 637 638 put_unaligned_le24(CXL_POISON_LIST_MAX, id.poison_list_max_mer); 639 640 if (cmd->size_out < sizeof(id)) 641 return -EINVAL; 642 643 memcpy(cmd->payload_out, &id, sizeof(id)); 644 645 return 0; 646 } 647 648 static int mock_partition_info(struct cxl_mbox_cmd *cmd) 649 { 650 struct cxl_mbox_get_partition_info pi = { 651 .active_volatile_cap = 652 cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER), 653 .active_persistent_cap = 654 cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER), 655 }; 656 657 if (cmd->size_out < sizeof(pi)) 658 return -EINVAL; 659 660 memcpy(cmd->payload_out, &pi, sizeof(pi)); 661 662 return 0; 663 } 664 665 void cxl_mockmem_sanitize_work(struct work_struct *work) 666 { 667 struct cxl_memdev_state *mds = 668 container_of(work, typeof(*mds), security.poll_dwork.work); 669 struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 670 671 mutex_lock(&cxl_mbox->mbox_mutex); 672 if (mds->security.sanitize_node) 673 sysfs_notify_dirent(mds->security.sanitize_node); 674 mds->security.sanitize_active = false; 675 mutex_unlock(&cxl_mbox->mbox_mutex); 676 677 dev_dbg(mds->cxlds.dev, "sanitize complete\n"); 678 } 679 680 static int mock_sanitize(struct cxl_mockmem_data *mdata, 681 struct cxl_mbox_cmd *cmd) 682 { 683 struct cxl_memdev_state *mds = mdata->mds; 684 struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; 685 int rc = 0; 686 687 if (cmd->size_in != 0) 688 return -EINVAL; 689 690 if (cmd->size_out != 0) 691 return -EINVAL; 692 693 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 694 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 695 return -ENXIO; 696 } 697 if (mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED) { 698 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 699 return -ENXIO; 700 } 701 702 mutex_lock(&cxl_mbox->mbox_mutex); 703 if (schedule_delayed_work(&mds->security.poll_dwork, 704 msecs_to_jiffies(mdata->sanitize_timeout))) { 705 mds->security.sanitize_active = true; 706 dev_dbg(mds->cxlds.dev, "sanitize issued\n"); 707 } else 708 rc = -EBUSY; 709 mutex_unlock(&cxl_mbox->mbox_mutex); 710 711 return rc; 712 } 713 714 static int mock_secure_erase(struct cxl_mockmem_data *mdata, 715 struct cxl_mbox_cmd *cmd) 716 { 717 if (cmd->size_in != 0) 718 return -EINVAL; 719 720 if (cmd->size_out != 0) 721 return -EINVAL; 722 723 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 724 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 725 return -ENXIO; 726 } 727 728 if (mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED) { 729 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 730 return -ENXIO; 731 } 732 733 return 0; 734 } 735 736 static int mock_get_security_state(struct cxl_mockmem_data *mdata, 737 struct cxl_mbox_cmd *cmd) 738 { 739 if (cmd->size_in) 740 return -EINVAL; 741 742 if (cmd->size_out != sizeof(u32)) 743 return -EINVAL; 744 745 memcpy(cmd->payload_out, &mdata->security_state, sizeof(u32)); 746 747 return 0; 748 } 749 750 static void master_plimit_check(struct cxl_mockmem_data *mdata) 751 { 752 if (mdata->master_limit == PASS_TRY_LIMIT) 753 return; 754 mdata->master_limit++; 755 if (mdata->master_limit == PASS_TRY_LIMIT) 756 mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PLIMIT; 757 } 758 759 static void user_plimit_check(struct cxl_mockmem_data *mdata) 760 { 761 if (mdata->user_limit == PASS_TRY_LIMIT) 762 return; 763 mdata->user_limit++; 764 if (mdata->user_limit == PASS_TRY_LIMIT) 765 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT; 766 } 767 768 static int mock_set_passphrase(struct cxl_mockmem_data *mdata, 769 struct cxl_mbox_cmd *cmd) 770 { 771 struct cxl_set_pass *set_pass; 772 773 if (cmd->size_in != sizeof(*set_pass)) 774 return -EINVAL; 775 776 if (cmd->size_out != 0) 777 return -EINVAL; 778 779 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 780 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 781 return -ENXIO; 782 } 783 784 set_pass = cmd->payload_in; 785 switch (set_pass->type) { 786 case CXL_PMEM_SEC_PASS_MASTER: 787 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) { 788 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 789 return -ENXIO; 790 } 791 /* 792 * CXL spec rev3.0 8.2.9.8.6.2, The master pasphrase shall only be set in 793 * the security disabled state when the user passphrase is not set. 794 */ 795 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 796 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 797 return -ENXIO; 798 } 799 if (memcmp(mdata->master_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) { 800 master_plimit_check(mdata); 801 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 802 return -ENXIO; 803 } 804 memcpy(mdata->master_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN); 805 mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PASS_SET; 806 return 0; 807 808 case CXL_PMEM_SEC_PASS_USER: 809 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) { 810 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 811 return -ENXIO; 812 } 813 if (memcmp(mdata->user_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) { 814 user_plimit_check(mdata); 815 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 816 return -ENXIO; 817 } 818 memcpy(mdata->user_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN); 819 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PASS_SET; 820 return 0; 821 822 default: 823 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 824 } 825 return -EINVAL; 826 } 827 828 static int mock_disable_passphrase(struct cxl_mockmem_data *mdata, 829 struct cxl_mbox_cmd *cmd) 830 { 831 struct cxl_disable_pass *dis_pass; 832 833 if (cmd->size_in != sizeof(*dis_pass)) 834 return -EINVAL; 835 836 if (cmd->size_out != 0) 837 return -EINVAL; 838 839 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 840 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 841 return -ENXIO; 842 } 843 844 dis_pass = cmd->payload_in; 845 switch (dis_pass->type) { 846 case CXL_PMEM_SEC_PASS_MASTER: 847 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) { 848 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 849 return -ENXIO; 850 } 851 852 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)) { 853 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 854 return -ENXIO; 855 } 856 857 if (memcmp(dis_pass->pass, mdata->master_pass, NVDIMM_PASSPHRASE_LEN)) { 858 master_plimit_check(mdata); 859 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 860 return -ENXIO; 861 } 862 863 mdata->master_limit = 0; 864 memset(mdata->master_pass, 0, NVDIMM_PASSPHRASE_LEN); 865 mdata->security_state &= ~CXL_PMEM_SEC_STATE_MASTER_PASS_SET; 866 return 0; 867 868 case CXL_PMEM_SEC_PASS_USER: 869 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) { 870 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 871 return -ENXIO; 872 } 873 874 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) { 875 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 876 return -ENXIO; 877 } 878 879 if (memcmp(dis_pass->pass, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) { 880 user_plimit_check(mdata); 881 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 882 return -ENXIO; 883 } 884 885 mdata->user_limit = 0; 886 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN); 887 mdata->security_state &= ~(CXL_PMEM_SEC_STATE_USER_PASS_SET | 888 CXL_PMEM_SEC_STATE_LOCKED); 889 return 0; 890 891 default: 892 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 893 return -EINVAL; 894 } 895 896 return 0; 897 } 898 899 static int mock_freeze_security(struct cxl_mockmem_data *mdata, 900 struct cxl_mbox_cmd *cmd) 901 { 902 if (cmd->size_in != 0) 903 return -EINVAL; 904 905 if (cmd->size_out != 0) 906 return -EINVAL; 907 908 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) 909 return 0; 910 911 mdata->security_state |= CXL_PMEM_SEC_STATE_FROZEN; 912 return 0; 913 } 914 915 static int mock_unlock_security(struct cxl_mockmem_data *mdata, 916 struct cxl_mbox_cmd *cmd) 917 { 918 if (cmd->size_in != NVDIMM_PASSPHRASE_LEN) 919 return -EINVAL; 920 921 if (cmd->size_out != 0) 922 return -EINVAL; 923 924 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 925 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 926 return -ENXIO; 927 } 928 929 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) { 930 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 931 return -ENXIO; 932 } 933 934 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) { 935 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 936 return -ENXIO; 937 } 938 939 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED)) { 940 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 941 return -ENXIO; 942 } 943 944 if (memcmp(cmd->payload_in, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) { 945 if (++mdata->user_limit == PASS_TRY_LIMIT) 946 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT; 947 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 948 return -ENXIO; 949 } 950 951 mdata->user_limit = 0; 952 mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED; 953 return 0; 954 } 955 956 static int mock_passphrase_secure_erase(struct cxl_mockmem_data *mdata, 957 struct cxl_mbox_cmd *cmd) 958 { 959 struct cxl_pass_erase *erase; 960 961 if (cmd->size_in != sizeof(*erase)) 962 return -EINVAL; 963 964 if (cmd->size_out != 0) 965 return -EINVAL; 966 967 erase = cmd->payload_in; 968 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 969 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 970 return -ENXIO; 971 } 972 973 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT && 974 erase->type == CXL_PMEM_SEC_PASS_USER) { 975 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 976 return -ENXIO; 977 } 978 979 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT && 980 erase->type == CXL_PMEM_SEC_PASS_MASTER) { 981 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 982 return -ENXIO; 983 } 984 985 switch (erase->type) { 986 case CXL_PMEM_SEC_PASS_MASTER: 987 /* 988 * The spec does not clearly define the behavior of the scenario 989 * where a master passphrase is passed in while the master 990 * passphrase is not set and user passphrase is not set. The 991 * code will take the assumption that it will behave the same 992 * as a CXL secure erase command without passphrase (0x4401). 993 */ 994 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET) { 995 if (memcmp(mdata->master_pass, erase->pass, 996 NVDIMM_PASSPHRASE_LEN)) { 997 master_plimit_check(mdata); 998 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 999 return -ENXIO; 1000 } 1001 mdata->master_limit = 0; 1002 mdata->user_limit = 0; 1003 mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET; 1004 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN); 1005 mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED; 1006 } else { 1007 /* 1008 * CXL rev3 8.2.9.8.6.3 Disable Passphrase 1009 * When master passphrase is disabled, the device shall 1010 * return Invalid Input for the Passphrase Secure Erase 1011 * command with master passphrase. 1012 */ 1013 return -EINVAL; 1014 } 1015 /* Scramble encryption keys so that data is effectively erased */ 1016 break; 1017 case CXL_PMEM_SEC_PASS_USER: 1018 /* 1019 * The spec does not clearly define the behavior of the scenario 1020 * where a user passphrase is passed in while the user 1021 * passphrase is not set. The code will take the assumption that 1022 * it will behave the same as a CXL secure erase command without 1023 * passphrase (0x4401). 1024 */ 1025 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 1026 if (memcmp(mdata->user_pass, erase->pass, 1027 NVDIMM_PASSPHRASE_LEN)) { 1028 user_plimit_check(mdata); 1029 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 1030 return -ENXIO; 1031 } 1032 mdata->user_limit = 0; 1033 mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET; 1034 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN); 1035 } 1036 1037 /* 1038 * CXL rev3 Table 8-118 1039 * If user passphrase is not set or supported by device, current 1040 * passphrase value is ignored. Will make the assumption that 1041 * the operation will proceed as secure erase w/o passphrase 1042 * since spec is not explicit. 1043 */ 1044 1045 /* Scramble encryption keys so that data is effectively erased */ 1046 break; 1047 default: 1048 return -EINVAL; 1049 } 1050 1051 return 0; 1052 } 1053 1054 static int mock_get_lsa(struct cxl_mockmem_data *mdata, 1055 struct cxl_mbox_cmd *cmd) 1056 { 1057 struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in; 1058 void *lsa = mdata->lsa; 1059 u32 offset, length; 1060 1061 if (sizeof(*get_lsa) > cmd->size_in) 1062 return -EINVAL; 1063 offset = le32_to_cpu(get_lsa->offset); 1064 length = le32_to_cpu(get_lsa->length); 1065 if (offset > LSA_SIZE || length > LSA_SIZE - offset) 1066 return -EINVAL; 1067 if (length > cmd->size_out) 1068 return -EINVAL; 1069 1070 memcpy(cmd->payload_out, lsa + offset, length); 1071 return 0; 1072 } 1073 1074 static int mock_set_lsa(struct cxl_mockmem_data *mdata, 1075 struct cxl_mbox_cmd *cmd) 1076 { 1077 struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in; 1078 void *lsa = mdata->lsa; 1079 u32 offset, length; 1080 1081 if (sizeof(*set_lsa) > cmd->size_in) 1082 return -EINVAL; 1083 offset = le32_to_cpu(set_lsa->offset); 1084 length = cmd->size_in - sizeof(*set_lsa); 1085 if (offset > LSA_SIZE || length > LSA_SIZE - offset) 1086 return -EINVAL; 1087 1088 memcpy(lsa + offset, &set_lsa->data[0], length); 1089 return 0; 1090 } 1091 1092 static int mock_health_info(struct cxl_mbox_cmd *cmd) 1093 { 1094 struct cxl_mbox_health_info health_info = { 1095 /* set flags for maint needed, perf degraded, hw replacement */ 1096 .health_status = 0x7, 1097 /* set media status to "All Data Lost" */ 1098 .media_status = 0x3, 1099 /* 1100 * set ext_status flags for: 1101 * ext_life_used: normal, 1102 * ext_temperature: critical, 1103 * ext_corrected_volatile: warning, 1104 * ext_corrected_persistent: normal, 1105 */ 1106 .ext_status = 0x18, 1107 .life_used = 15, 1108 .temperature = cpu_to_le16(25), 1109 .dirty_shutdowns = cpu_to_le32(10), 1110 .volatile_errors = cpu_to_le32(20), 1111 .pmem_errors = cpu_to_le32(30), 1112 }; 1113 1114 if (cmd->size_out < sizeof(health_info)) 1115 return -EINVAL; 1116 1117 memcpy(cmd->payload_out, &health_info, sizeof(health_info)); 1118 return 0; 1119 } 1120 1121 static int mock_set_shutdown_state(struct cxl_mockmem_data *mdata, 1122 struct cxl_mbox_cmd *cmd) 1123 { 1124 struct cxl_mbox_set_shutdown_state_in *ss = cmd->payload_in; 1125 1126 if (cmd->size_in != sizeof(*ss)) 1127 return -EINVAL; 1128 1129 if (cmd->size_out != 0) 1130 return -EINVAL; 1131 1132 mdata->shutdown_state = ss->state; 1133 return 0; 1134 } 1135 1136 static struct mock_poison { 1137 struct cxl_dev_state *cxlds; 1138 u64 dpa; 1139 } mock_poison_list[MOCK_INJECT_TEST_MAX]; 1140 1141 static struct cxl_mbox_poison_out * 1142 cxl_get_injected_po(struct cxl_dev_state *cxlds, u64 offset, u64 length) 1143 { 1144 struct cxl_mbox_poison_out *po; 1145 int nr_records = 0; 1146 u64 dpa; 1147 1148 po = kzalloc(struct_size(po, record, poison_inject_dev_max), GFP_KERNEL); 1149 if (!po) 1150 return NULL; 1151 1152 for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) { 1153 if (mock_poison_list[i].cxlds != cxlds) 1154 continue; 1155 if (mock_poison_list[i].dpa < offset || 1156 mock_poison_list[i].dpa > offset + length - 1) 1157 continue; 1158 1159 dpa = mock_poison_list[i].dpa + CXL_POISON_SOURCE_INJECTED; 1160 po->record[nr_records].address = cpu_to_le64(dpa); 1161 po->record[nr_records].length = cpu_to_le32(1); 1162 nr_records++; 1163 if (nr_records == poison_inject_dev_max) 1164 break; 1165 } 1166 1167 /* Always return count, even when zero */ 1168 po->count = cpu_to_le16(nr_records); 1169 1170 return po; 1171 } 1172 1173 static int mock_get_poison(struct cxl_dev_state *cxlds, 1174 struct cxl_mbox_cmd *cmd) 1175 { 1176 struct cxl_mbox_poison_in *pi = cmd->payload_in; 1177 struct cxl_mbox_poison_out *po; 1178 u64 offset = le64_to_cpu(pi->offset); 1179 u64 length = le64_to_cpu(pi->length); 1180 int nr_records; 1181 1182 po = cxl_get_injected_po(cxlds, offset, length); 1183 if (!po) 1184 return -ENOMEM; 1185 nr_records = le16_to_cpu(po->count); 1186 memcpy(cmd->payload_out, po, struct_size(po, record, nr_records)); 1187 cmd->size_out = struct_size(po, record, nr_records); 1188 kfree(po); 1189 1190 return 0; 1191 } 1192 1193 static bool mock_poison_dev_max_injected(struct cxl_dev_state *cxlds) 1194 { 1195 int count = 0; 1196 1197 for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) { 1198 if (mock_poison_list[i].cxlds == cxlds) 1199 count++; 1200 } 1201 return (count >= poison_inject_dev_max); 1202 } 1203 1204 static int mock_poison_add(struct cxl_dev_state *cxlds, u64 dpa) 1205 { 1206 /* Return EBUSY to match the CXL driver handling */ 1207 if (mock_poison_dev_max_injected(cxlds)) { 1208 dev_dbg(cxlds->dev, 1209 "Device poison injection limit has been reached: %d\n", 1210 poison_inject_dev_max); 1211 return -EBUSY; 1212 } 1213 1214 for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) { 1215 if (!mock_poison_list[i].cxlds) { 1216 mock_poison_list[i].cxlds = cxlds; 1217 mock_poison_list[i].dpa = dpa; 1218 return 0; 1219 } 1220 } 1221 dev_dbg(cxlds->dev, 1222 "Mock test poison injection limit has been reached: %d\n", 1223 MOCK_INJECT_TEST_MAX); 1224 1225 return -ENXIO; 1226 } 1227 1228 static bool mock_poison_found(struct cxl_dev_state *cxlds, u64 dpa) 1229 { 1230 for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) { 1231 if (mock_poison_list[i].cxlds == cxlds && 1232 mock_poison_list[i].dpa == dpa) 1233 return true; 1234 } 1235 return false; 1236 } 1237 1238 static int mock_inject_poison(struct cxl_dev_state *cxlds, 1239 struct cxl_mbox_cmd *cmd) 1240 { 1241 struct cxl_mbox_inject_poison *pi = cmd->payload_in; 1242 u64 dpa = le64_to_cpu(pi->address); 1243 1244 if (mock_poison_found(cxlds, dpa)) { 1245 /* Not an error to inject poison if already poisoned */ 1246 dev_dbg(cxlds->dev, "DPA: 0x%llx already poisoned\n", dpa); 1247 return 0; 1248 } 1249 1250 return mock_poison_add(cxlds, dpa); 1251 } 1252 1253 static bool mock_poison_del(struct cxl_dev_state *cxlds, u64 dpa) 1254 { 1255 for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) { 1256 if (mock_poison_list[i].cxlds == cxlds && 1257 mock_poison_list[i].dpa == dpa) { 1258 mock_poison_list[i].cxlds = NULL; 1259 return true; 1260 } 1261 } 1262 return false; 1263 } 1264 1265 static int mock_clear_poison(struct cxl_dev_state *cxlds, 1266 struct cxl_mbox_cmd *cmd) 1267 { 1268 struct cxl_mbox_clear_poison *pi = cmd->payload_in; 1269 u64 dpa = le64_to_cpu(pi->address); 1270 1271 /* 1272 * A real CXL device will write pi->write_data to the address 1273 * being cleared. In this mock, just delete this address from 1274 * the mock poison list. 1275 */ 1276 if (!mock_poison_del(cxlds, dpa)) 1277 dev_dbg(cxlds->dev, "DPA: 0x%llx not in poison list\n", dpa); 1278 1279 return 0; 1280 } 1281 1282 static bool mock_poison_list_empty(void) 1283 { 1284 for (int i = 0; i < MOCK_INJECT_TEST_MAX; i++) { 1285 if (mock_poison_list[i].cxlds) 1286 return false; 1287 } 1288 return true; 1289 } 1290 1291 static ssize_t poison_inject_max_show(struct device_driver *drv, char *buf) 1292 { 1293 return sysfs_emit(buf, "%u\n", poison_inject_dev_max); 1294 } 1295 1296 static ssize_t poison_inject_max_store(struct device_driver *drv, 1297 const char *buf, size_t len) 1298 { 1299 int val; 1300 1301 if (kstrtoint(buf, 0, &val) < 0) 1302 return -EINVAL; 1303 1304 if (!mock_poison_list_empty()) 1305 return -EBUSY; 1306 1307 if (val <= MOCK_INJECT_TEST_MAX) 1308 poison_inject_dev_max = val; 1309 else 1310 return -EINVAL; 1311 1312 return len; 1313 } 1314 1315 static DRIVER_ATTR_RW(poison_inject_max); 1316 1317 static struct attribute *cxl_mock_mem_core_attrs[] = { 1318 &driver_attr_poison_inject_max.attr, 1319 NULL 1320 }; 1321 ATTRIBUTE_GROUPS(cxl_mock_mem_core); 1322 1323 static int mock_fw_info(struct cxl_mockmem_data *mdata, 1324 struct cxl_mbox_cmd *cmd) 1325 { 1326 struct cxl_mbox_get_fw_info fw_info = { 1327 .num_slots = FW_SLOTS, 1328 .slot_info = (mdata->fw_slot & 0x7) | 1329 ((mdata->fw_staged & 0x7) << 3), 1330 .activation_cap = 0, 1331 }; 1332 1333 strcpy(fw_info.slot_1_revision, "cxl_test_fw_001"); 1334 strcpy(fw_info.slot_2_revision, "cxl_test_fw_002"); 1335 strcpy(fw_info.slot_3_revision, "cxl_test_fw_003"); 1336 strcpy(fw_info.slot_4_revision, ""); 1337 1338 if (cmd->size_out < sizeof(fw_info)) 1339 return -EINVAL; 1340 1341 memcpy(cmd->payload_out, &fw_info, sizeof(fw_info)); 1342 return 0; 1343 } 1344 1345 static int mock_transfer_fw(struct cxl_mockmem_data *mdata, 1346 struct cxl_mbox_cmd *cmd) 1347 { 1348 struct cxl_mbox_transfer_fw *transfer; 1349 void *fw = mdata->fw; 1350 size_t offset, length; 1351 1352 if (cmd->size_in < sizeof(*transfer)) 1353 return -EINVAL; 1354 1355 transfer = cmd->payload_in; 1356 offset = le32_to_cpu(transfer->offset) * CXL_FW_TRANSFER_ALIGNMENT; 1357 length = cmd->size_in - sizeof(*transfer); 1358 if (offset + length > FW_SIZE) 1359 return -EINVAL; 1360 1361 switch (transfer->action) { 1362 case CXL_FW_TRANSFER_ACTION_FULL: 1363 if (offset != 0) 1364 return -EINVAL; 1365 fallthrough; 1366 case CXL_FW_TRANSFER_ACTION_END: 1367 if (transfer->slot == 0 || transfer->slot > FW_SLOTS) 1368 return -EINVAL; 1369 mdata->fw_size = offset + length; 1370 break; 1371 case CXL_FW_TRANSFER_ACTION_INITIATE: 1372 case CXL_FW_TRANSFER_ACTION_CONTINUE: 1373 break; 1374 case CXL_FW_TRANSFER_ACTION_ABORT: 1375 return 0; 1376 default: 1377 return -EINVAL; 1378 } 1379 1380 memcpy(fw + offset, transfer->data, length); 1381 usleep_range(1500, 2000); 1382 return 0; 1383 } 1384 1385 static int mock_activate_fw(struct cxl_mockmem_data *mdata, 1386 struct cxl_mbox_cmd *cmd) 1387 { 1388 struct cxl_mbox_activate_fw *activate = cmd->payload_in; 1389 1390 if (activate->slot == 0 || activate->slot > FW_SLOTS) 1391 return -EINVAL; 1392 1393 switch (activate->action) { 1394 case CXL_FW_ACTIVATE_ONLINE: 1395 mdata->fw_slot = activate->slot; 1396 mdata->fw_staged = 0; 1397 return 0; 1398 case CXL_FW_ACTIVATE_OFFLINE: 1399 mdata->fw_staged = activate->slot; 1400 return 0; 1401 } 1402 1403 return -EINVAL; 1404 } 1405 1406 #define CXL_VENDOR_FEATURE_TEST \ 1407 UUID_INIT(0xffffffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, \ 1408 0xff, 0xff, 0xff) 1409 1410 static void fill_feature_vendor_test(struct cxl_feat_entry *feat) 1411 { 1412 feat->uuid = CXL_VENDOR_FEATURE_TEST; 1413 feat->id = 0; 1414 feat->get_feat_size = cpu_to_le16(0x4); 1415 feat->set_feat_size = cpu_to_le16(0x4); 1416 feat->flags = cpu_to_le32(CXL_FEATURE_F_CHANGEABLE | 1417 CXL_FEATURE_F_DEFAULT_SEL | 1418 CXL_FEATURE_F_SAVED_SEL); 1419 feat->get_feat_ver = 1; 1420 feat->set_feat_ver = 1; 1421 feat->effects = cpu_to_le16(CXL_CMD_CONFIG_CHANGE_COLD_RESET | 1422 CXL_CMD_EFFECTS_VALID); 1423 } 1424 1425 #define MAX_CXL_TEST_FEATS 1 1426 1427 static int mock_get_test_feature(struct cxl_mockmem_data *mdata, 1428 struct cxl_mbox_cmd *cmd) 1429 { 1430 struct vendor_test_feat *output = cmd->payload_out; 1431 struct cxl_mbox_get_feat_in *input; 1432 u16 offset; 1433 u16 count; 1434 u8 *ptr; 1435 1436 if (cmd->size_in < sizeof(*input)) 1437 return -EINVAL; 1438 1439 input = cmd->payload_in; 1440 offset = le16_to_cpu(input->offset); 1441 count = le16_to_cpu(input->count); 1442 1443 if (offset > sizeof(*output)) { 1444 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 1445 return -EINVAL; 1446 } 1447 1448 if (offset + count > sizeof(*output)) { 1449 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 1450 return -EINVAL; 1451 } 1452 1453 ptr = (u8 *)&mdata->test_feat + offset; 1454 memcpy((u8 *)output + offset, ptr, count); 1455 1456 return 0; 1457 } 1458 1459 static int mock_get_feature(struct cxl_mockmem_data *mdata, 1460 struct cxl_mbox_cmd *cmd) 1461 { 1462 struct cxl_mbox_get_feat_in *input = cmd->payload_in; 1463 1464 if (uuid_equal(&input->uuid, &CXL_VENDOR_FEATURE_TEST)) 1465 return mock_get_test_feature(mdata, cmd); 1466 1467 cmd->return_code = CXL_MBOX_CMD_RC_UNSUPPORTED; 1468 1469 return -EOPNOTSUPP; 1470 } 1471 1472 static int mock_set_test_feature(struct cxl_mockmem_data *mdata, 1473 struct cxl_mbox_cmd *cmd) 1474 { 1475 struct cxl_mbox_set_feat_in *input = cmd->payload_in; 1476 struct vendor_test_feat *test = 1477 (struct vendor_test_feat *)input->feat_data; 1478 u32 action; 1479 1480 action = FIELD_GET(CXL_SET_FEAT_FLAG_DATA_TRANSFER_MASK, 1481 le32_to_cpu(input->hdr.flags)); 1482 /* 1483 * While it is spec compliant to support other set actions, it is not 1484 * necessary to add the complication in the emulation currently. Reject 1485 * anything besides full xfer. 1486 */ 1487 if (action != CXL_SET_FEAT_FLAG_FULL_DATA_TRANSFER) { 1488 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 1489 return -EINVAL; 1490 } 1491 1492 /* Offset should be reserved when doing full transfer */ 1493 if (input->hdr.offset) { 1494 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 1495 return -EINVAL; 1496 } 1497 1498 memcpy(&mdata->test_feat.data, &test->data, sizeof(u32)); 1499 1500 return 0; 1501 } 1502 1503 static int mock_set_feature(struct cxl_mockmem_data *mdata, 1504 struct cxl_mbox_cmd *cmd) 1505 { 1506 struct cxl_mbox_set_feat_in *input = cmd->payload_in; 1507 1508 if (uuid_equal(&input->hdr.uuid, &CXL_VENDOR_FEATURE_TEST)) 1509 return mock_set_test_feature(mdata, cmd); 1510 1511 cmd->return_code = CXL_MBOX_CMD_RC_UNSUPPORTED; 1512 1513 return -EOPNOTSUPP; 1514 } 1515 1516 static int mock_get_supported_features(struct cxl_mockmem_data *mdata, 1517 struct cxl_mbox_cmd *cmd) 1518 { 1519 struct cxl_mbox_get_sup_feats_in *in = cmd->payload_in; 1520 struct cxl_mbox_get_sup_feats_out *out = cmd->payload_out; 1521 struct cxl_feat_entry *feat; 1522 u16 start_idx, count; 1523 1524 if (cmd->size_out < sizeof(*out)) { 1525 cmd->return_code = CXL_MBOX_CMD_RC_PAYLOADLEN; 1526 return -EINVAL; 1527 } 1528 1529 /* 1530 * Current emulation only supports 1 feature 1531 */ 1532 start_idx = le16_to_cpu(in->start_idx); 1533 if (start_idx != 0) { 1534 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 1535 return -EINVAL; 1536 } 1537 1538 count = le16_to_cpu(in->count); 1539 if (count < struct_size(out, ents, 0)) { 1540 cmd->return_code = CXL_MBOX_CMD_RC_PAYLOADLEN; 1541 return -EINVAL; 1542 } 1543 1544 out->supported_feats = cpu_to_le16(MAX_CXL_TEST_FEATS); 1545 cmd->return_code = 0; 1546 if (count < struct_size(out, ents, MAX_CXL_TEST_FEATS)) { 1547 out->num_entries = 0; 1548 return 0; 1549 } 1550 1551 out->num_entries = cpu_to_le16(MAX_CXL_TEST_FEATS); 1552 feat = out->ents; 1553 fill_feature_vendor_test(feat); 1554 1555 return 0; 1556 } 1557 1558 static int cxl_mock_mbox_send(struct cxl_mailbox *cxl_mbox, 1559 struct cxl_mbox_cmd *cmd) 1560 { 1561 struct device *dev = cxl_mbox->host; 1562 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 1563 struct cxl_memdev_state *mds = mdata->mds; 1564 struct cxl_dev_state *cxlds = &mds->cxlds; 1565 int rc = -EIO; 1566 1567 switch (cmd->opcode) { 1568 case CXL_MBOX_OP_SET_TIMESTAMP: 1569 rc = mock_set_timestamp(cxlds, cmd); 1570 break; 1571 case CXL_MBOX_OP_GET_SUPPORTED_LOGS: 1572 rc = mock_gsl(cmd); 1573 break; 1574 case CXL_MBOX_OP_GET_LOG: 1575 rc = mock_get_log(mds, cmd); 1576 break; 1577 case CXL_MBOX_OP_IDENTIFY: 1578 if (cxlds->rcd) 1579 rc = mock_rcd_id(cmd); 1580 else 1581 rc = mock_id(cmd); 1582 break; 1583 case CXL_MBOX_OP_GET_LSA: 1584 rc = mock_get_lsa(mdata, cmd); 1585 break; 1586 case CXL_MBOX_OP_GET_PARTITION_INFO: 1587 rc = mock_partition_info(cmd); 1588 break; 1589 case CXL_MBOX_OP_GET_EVENT_RECORD: 1590 rc = mock_get_event(dev, cmd); 1591 break; 1592 case CXL_MBOX_OP_CLEAR_EVENT_RECORD: 1593 rc = mock_clear_event(dev, cmd); 1594 break; 1595 case CXL_MBOX_OP_SET_LSA: 1596 rc = mock_set_lsa(mdata, cmd); 1597 break; 1598 case CXL_MBOX_OP_GET_HEALTH_INFO: 1599 rc = mock_health_info(cmd); 1600 break; 1601 case CXL_MBOX_OP_SANITIZE: 1602 rc = mock_sanitize(mdata, cmd); 1603 break; 1604 case CXL_MBOX_OP_SECURE_ERASE: 1605 rc = mock_secure_erase(mdata, cmd); 1606 break; 1607 case CXL_MBOX_OP_GET_SECURITY_STATE: 1608 rc = mock_get_security_state(mdata, cmd); 1609 break; 1610 case CXL_MBOX_OP_SET_PASSPHRASE: 1611 rc = mock_set_passphrase(mdata, cmd); 1612 break; 1613 case CXL_MBOX_OP_DISABLE_PASSPHRASE: 1614 rc = mock_disable_passphrase(mdata, cmd); 1615 break; 1616 case CXL_MBOX_OP_FREEZE_SECURITY: 1617 rc = mock_freeze_security(mdata, cmd); 1618 break; 1619 case CXL_MBOX_OP_UNLOCK: 1620 rc = mock_unlock_security(mdata, cmd); 1621 break; 1622 case CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE: 1623 rc = mock_passphrase_secure_erase(mdata, cmd); 1624 break; 1625 case CXL_MBOX_OP_SET_SHUTDOWN_STATE: 1626 rc = mock_set_shutdown_state(mdata, cmd); 1627 break; 1628 case CXL_MBOX_OP_GET_POISON: 1629 rc = mock_get_poison(cxlds, cmd); 1630 break; 1631 case CXL_MBOX_OP_INJECT_POISON: 1632 rc = mock_inject_poison(cxlds, cmd); 1633 break; 1634 case CXL_MBOX_OP_CLEAR_POISON: 1635 rc = mock_clear_poison(cxlds, cmd); 1636 break; 1637 case CXL_MBOX_OP_GET_FW_INFO: 1638 rc = mock_fw_info(mdata, cmd); 1639 break; 1640 case CXL_MBOX_OP_TRANSFER_FW: 1641 rc = mock_transfer_fw(mdata, cmd); 1642 break; 1643 case CXL_MBOX_OP_ACTIVATE_FW: 1644 rc = mock_activate_fw(mdata, cmd); 1645 break; 1646 case CXL_MBOX_OP_GET_SUPPORTED_FEATURES: 1647 rc = mock_get_supported_features(mdata, cmd); 1648 break; 1649 case CXL_MBOX_OP_GET_FEATURE: 1650 rc = mock_get_feature(mdata, cmd); 1651 break; 1652 case CXL_MBOX_OP_SET_FEATURE: 1653 rc = mock_set_feature(mdata, cmd); 1654 break; 1655 default: 1656 break; 1657 } 1658 1659 dev_dbg(dev, "opcode: %#x sz_in: %zd sz_out: %zd rc: %d\n", cmd->opcode, 1660 cmd->size_in, cmd->size_out, rc); 1661 1662 return rc; 1663 } 1664 1665 static void label_area_release(void *lsa) 1666 { 1667 vfree(lsa); 1668 } 1669 1670 static void fw_buf_release(void *buf) 1671 { 1672 vfree(buf); 1673 } 1674 1675 static bool is_rcd(struct platform_device *pdev) 1676 { 1677 const struct platform_device_id *id = platform_get_device_id(pdev); 1678 1679 return !!id->driver_data; 1680 } 1681 1682 static ssize_t event_trigger_store(struct device *dev, 1683 struct device_attribute *attr, 1684 const char *buf, size_t count) 1685 { 1686 cxl_mock_event_trigger(dev); 1687 return count; 1688 } 1689 static DEVICE_ATTR_WO(event_trigger); 1690 1691 static int cxl_mock_mailbox_create(struct cxl_dev_state *cxlds) 1692 { 1693 int rc; 1694 1695 rc = cxl_mailbox_init(&cxlds->cxl_mbox, cxlds->dev); 1696 if (rc) 1697 return rc; 1698 1699 return 0; 1700 } 1701 1702 static void cxl_mock_test_feat_init(struct cxl_mockmem_data *mdata) 1703 { 1704 mdata->test_feat.data = cpu_to_le32(0xdeadbeef); 1705 } 1706 1707 static int cxl_mock_mem_probe(struct platform_device *pdev) 1708 { 1709 struct device *dev = &pdev->dev; 1710 struct cxl_memdev *cxlmd; 1711 struct cxl_memdev_state *mds; 1712 struct cxl_dev_state *cxlds; 1713 struct cxl_mockmem_data *mdata; 1714 struct cxl_mailbox *cxl_mbox; 1715 struct cxl_dpa_info range_info = { 0 }; 1716 int rc; 1717 1718 /* Increase async probe race window */ 1719 usleep_range(500*1000, 1000*1000); 1720 1721 mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL); 1722 if (!mdata) 1723 return -ENOMEM; 1724 dev_set_drvdata(dev, mdata); 1725 1726 mdata->lsa = vzalloc(LSA_SIZE); 1727 if (!mdata->lsa) 1728 return -ENOMEM; 1729 mdata->fw = vmalloc(FW_SIZE); 1730 if (!mdata->fw) 1731 return -ENOMEM; 1732 mdata->fw_slot = 2; 1733 1734 rc = devm_add_action_or_reset(dev, label_area_release, mdata->lsa); 1735 if (rc) 1736 return rc; 1737 1738 rc = devm_add_action_or_reset(dev, fw_buf_release, mdata->fw); 1739 if (rc) 1740 return rc; 1741 1742 mds = cxl_memdev_state_create(dev, pdev->id + 1, 0); 1743 if (IS_ERR(mds)) 1744 return PTR_ERR(mds); 1745 1746 cxlds = &mds->cxlds; 1747 rc = cxl_mock_mailbox_create(cxlds); 1748 if (rc) 1749 return rc; 1750 1751 cxl_mbox = &mds->cxlds.cxl_mbox; 1752 mdata->mds = mds; 1753 cxl_mbox->mbox_send = cxl_mock_mbox_send; 1754 cxl_mbox->payload_size = SZ_4K; 1755 mds->event.buf = (struct cxl_get_event_payload *) mdata->event_buf; 1756 INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mockmem_sanitize_work); 1757 1758 if (is_rcd(pdev)) 1759 cxlds->rcd = true; 1760 1761 rc = cxl_enumerate_cmds(mds); 1762 if (rc) 1763 return rc; 1764 1765 rc = cxl_poison_state_init(mds); 1766 if (rc) 1767 return rc; 1768 1769 rc = cxl_set_timestamp(mds); 1770 if (rc) 1771 return rc; 1772 1773 cxlds->media_ready = true; 1774 rc = cxl_dev_state_identify(mds); 1775 if (rc) 1776 return rc; 1777 1778 rc = cxl_mem_dpa_fetch(mds, &range_info); 1779 if (rc) 1780 return rc; 1781 1782 rc = cxl_dpa_setup(cxlds, &range_info); 1783 if (rc) 1784 return rc; 1785 1786 rc = devm_cxl_setup_features(cxlds); 1787 if (rc) 1788 dev_dbg(dev, "No CXL Features discovered\n"); 1789 1790 cxl_mock_add_event_logs(&mdata->mes); 1791 1792 cxlmd = devm_cxl_add_classdev(cxlds); 1793 if (IS_ERR(cxlmd)) 1794 return PTR_ERR(cxlmd); 1795 1796 rc = devm_cxl_setup_fw_upload(&pdev->dev, mds); 1797 if (rc) 1798 return rc; 1799 1800 rc = devm_cxl_sanitize_setup_notifier(&pdev->dev, cxlmd); 1801 if (rc) 1802 return rc; 1803 1804 rc = devm_cxl_setup_fwctl(&pdev->dev, cxlmd); 1805 if (rc) 1806 dev_dbg(dev, "No CXL FWCTL setup\n"); 1807 1808 cxl_mem_get_event_records(mds, CXLDEV_EVENT_STATUS_ALL); 1809 cxl_mock_test_feat_init(mdata); 1810 1811 return 0; 1812 } 1813 1814 static ssize_t security_lock_show(struct device *dev, 1815 struct device_attribute *attr, char *buf) 1816 { 1817 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 1818 1819 return sysfs_emit(buf, "%u\n", 1820 !!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED)); 1821 } 1822 1823 static ssize_t security_lock_store(struct device *dev, struct device_attribute *attr, 1824 const char *buf, size_t count) 1825 { 1826 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 1827 u32 mask = CXL_PMEM_SEC_STATE_FROZEN | CXL_PMEM_SEC_STATE_USER_PLIMIT | 1828 CXL_PMEM_SEC_STATE_MASTER_PLIMIT; 1829 int val; 1830 1831 if (kstrtoint(buf, 0, &val) < 0) 1832 return -EINVAL; 1833 1834 if (val == 1) { 1835 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) 1836 return -ENXIO; 1837 mdata->security_state |= CXL_PMEM_SEC_STATE_LOCKED; 1838 mdata->security_state &= ~mask; 1839 } else { 1840 return -EINVAL; 1841 } 1842 return count; 1843 } 1844 1845 static DEVICE_ATTR_RW(security_lock); 1846 1847 static ssize_t fw_buf_checksum_show(struct device *dev, 1848 struct device_attribute *attr, char *buf) 1849 { 1850 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 1851 u8 hash[SHA256_DIGEST_SIZE]; 1852 1853 sha256(mdata->fw, mdata->fw_size, hash); 1854 1855 return sysfs_emit(buf, "%*phN\n", SHA256_DIGEST_SIZE, hash); 1856 } 1857 1858 static DEVICE_ATTR_RO(fw_buf_checksum); 1859 1860 static ssize_t sanitize_timeout_show(struct device *dev, 1861 struct device_attribute *attr, char *buf) 1862 { 1863 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 1864 1865 return sysfs_emit(buf, "%lu\n", mdata->sanitize_timeout); 1866 } 1867 1868 static ssize_t sanitize_timeout_store(struct device *dev, 1869 struct device_attribute *attr, 1870 const char *buf, size_t count) 1871 { 1872 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 1873 unsigned long val; 1874 int rc; 1875 1876 rc = kstrtoul(buf, 0, &val); 1877 if (rc) 1878 return rc; 1879 1880 mdata->sanitize_timeout = val; 1881 1882 return count; 1883 } 1884 1885 static DEVICE_ATTR_RW(sanitize_timeout); 1886 1887 static struct attribute *cxl_mock_mem_attrs[] = { 1888 &dev_attr_security_lock.attr, 1889 &dev_attr_event_trigger.attr, 1890 &dev_attr_fw_buf_checksum.attr, 1891 &dev_attr_sanitize_timeout.attr, 1892 NULL 1893 }; 1894 ATTRIBUTE_GROUPS(cxl_mock_mem); 1895 1896 static const struct platform_device_id cxl_mock_mem_ids[] = { 1897 { .name = "cxl_mem", 0 }, 1898 { .name = "cxl_rcd", 1 }, 1899 { }, 1900 }; 1901 MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids); 1902 1903 static struct platform_driver cxl_mock_mem_driver = { 1904 .probe = cxl_mock_mem_probe, 1905 .id_table = cxl_mock_mem_ids, 1906 .driver = { 1907 .name = KBUILD_MODNAME, 1908 .dev_groups = cxl_mock_mem_groups, 1909 .groups = cxl_mock_mem_core_groups, 1910 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1911 }, 1912 }; 1913 1914 module_platform_driver(cxl_mock_mem_driver); 1915 MODULE_LICENSE("GPL v2"); 1916 MODULE_DESCRIPTION("cxl_test: mem device mock module"); 1917 MODULE_IMPORT_NS("CXL"); 1918