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 #define LSA_SIZE SZ_128K 13 #define DEV_SIZE SZ_2G 14 #define EFFECT(x) (1U << x) 15 16 static struct cxl_cel_entry mock_cel[] = { 17 { 18 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_SUPPORTED_LOGS), 19 .effect = cpu_to_le16(0), 20 }, 21 { 22 .opcode = cpu_to_le16(CXL_MBOX_OP_IDENTIFY), 23 .effect = cpu_to_le16(0), 24 }, 25 { 26 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA), 27 .effect = cpu_to_le16(0), 28 }, 29 { 30 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_PARTITION_INFO), 31 .effect = cpu_to_le16(0), 32 }, 33 { 34 .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA), 35 .effect = cpu_to_le16(EFFECT(1) | EFFECT(2)), 36 }, 37 { 38 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO), 39 .effect = cpu_to_le16(0), 40 }, 41 }; 42 43 /* See CXL 2.0 Table 181 Get Health Info Output Payload */ 44 struct cxl_mbox_health_info { 45 u8 health_status; 46 u8 media_status; 47 u8 ext_status; 48 u8 life_used; 49 __le16 temperature; 50 __le32 dirty_shutdowns; 51 __le32 volatile_errors; 52 __le32 pmem_errors; 53 } __packed; 54 55 static struct { 56 struct cxl_mbox_get_supported_logs gsl; 57 struct cxl_gsl_entry entry; 58 } mock_gsl_payload = { 59 .gsl = { 60 .entries = cpu_to_le16(1), 61 }, 62 .entry = { 63 .uuid = DEFINE_CXL_CEL_UUID, 64 .size = cpu_to_le32(sizeof(mock_cel)), 65 }, 66 }; 67 68 #define PASS_TRY_LIMIT 3 69 70 struct cxl_mockmem_data { 71 void *lsa; 72 u32 security_state; 73 u8 user_pass[NVDIMM_PASSPHRASE_LEN]; 74 u8 master_pass[NVDIMM_PASSPHRASE_LEN]; 75 int user_limit; 76 int master_limit; 77 78 }; 79 80 static int mock_gsl(struct cxl_mbox_cmd *cmd) 81 { 82 if (cmd->size_out < sizeof(mock_gsl_payload)) 83 return -EINVAL; 84 85 memcpy(cmd->payload_out, &mock_gsl_payload, sizeof(mock_gsl_payload)); 86 cmd->size_out = sizeof(mock_gsl_payload); 87 88 return 0; 89 } 90 91 static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 92 { 93 struct cxl_mbox_get_log *gl = cmd->payload_in; 94 u32 offset = le32_to_cpu(gl->offset); 95 u32 length = le32_to_cpu(gl->length); 96 uuid_t uuid = DEFINE_CXL_CEL_UUID; 97 void *data = &mock_cel; 98 99 if (cmd->size_in < sizeof(*gl)) 100 return -EINVAL; 101 if (length > cxlds->payload_size) 102 return -EINVAL; 103 if (offset + length > sizeof(mock_cel)) 104 return -EINVAL; 105 if (!uuid_equal(&gl->uuid, &uuid)) 106 return -EINVAL; 107 if (length > cmd->size_out) 108 return -EINVAL; 109 110 memcpy(cmd->payload_out, data + offset, length); 111 112 return 0; 113 } 114 115 static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 116 { 117 struct cxl_mbox_identify id = { 118 .fw_revision = { "mock fw v1 " }, 119 .lsa_size = cpu_to_le32(LSA_SIZE), 120 .partition_align = 121 cpu_to_le64(SZ_256M / CXL_CAPACITY_MULTIPLIER), 122 .total_capacity = 123 cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER), 124 }; 125 126 if (cmd->size_out < sizeof(id)) 127 return -EINVAL; 128 129 memcpy(cmd->payload_out, &id, sizeof(id)); 130 131 return 0; 132 } 133 134 static int mock_partition_info(struct cxl_dev_state *cxlds, 135 struct cxl_mbox_cmd *cmd) 136 { 137 struct cxl_mbox_get_partition_info pi = { 138 .active_volatile_cap = 139 cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER), 140 .active_persistent_cap = 141 cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER), 142 }; 143 144 if (cmd->size_out < sizeof(pi)) 145 return -EINVAL; 146 147 memcpy(cmd->payload_out, &pi, sizeof(pi)); 148 149 return 0; 150 } 151 152 static int mock_get_security_state(struct cxl_dev_state *cxlds, 153 struct cxl_mbox_cmd *cmd) 154 { 155 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 156 157 if (cmd->size_in) 158 return -EINVAL; 159 160 if (cmd->size_out != sizeof(u32)) 161 return -EINVAL; 162 163 memcpy(cmd->payload_out, &mdata->security_state, sizeof(u32)); 164 165 return 0; 166 } 167 168 static void master_plimit_check(struct cxl_mockmem_data *mdata) 169 { 170 if (mdata->master_limit == PASS_TRY_LIMIT) 171 return; 172 mdata->master_limit++; 173 if (mdata->master_limit == PASS_TRY_LIMIT) 174 mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PLIMIT; 175 } 176 177 static void user_plimit_check(struct cxl_mockmem_data *mdata) 178 { 179 if (mdata->user_limit == PASS_TRY_LIMIT) 180 return; 181 mdata->user_limit++; 182 if (mdata->user_limit == PASS_TRY_LIMIT) 183 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT; 184 } 185 186 static int mock_set_passphrase(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 187 { 188 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 189 struct cxl_set_pass *set_pass; 190 191 if (cmd->size_in != sizeof(*set_pass)) 192 return -EINVAL; 193 194 if (cmd->size_out != 0) 195 return -EINVAL; 196 197 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 198 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 199 return -ENXIO; 200 } 201 202 set_pass = cmd->payload_in; 203 switch (set_pass->type) { 204 case CXL_PMEM_SEC_PASS_MASTER: 205 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) { 206 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 207 return -ENXIO; 208 } 209 /* 210 * CXL spec rev3.0 8.2.9.8.6.2, The master pasphrase shall only be set in 211 * the security disabled state when the user passphrase is not set. 212 */ 213 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 214 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 215 return -ENXIO; 216 } 217 if (memcmp(mdata->master_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) { 218 master_plimit_check(mdata); 219 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 220 return -ENXIO; 221 } 222 memcpy(mdata->master_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN); 223 mdata->security_state |= CXL_PMEM_SEC_STATE_MASTER_PASS_SET; 224 return 0; 225 226 case CXL_PMEM_SEC_PASS_USER: 227 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) { 228 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 229 return -ENXIO; 230 } 231 if (memcmp(mdata->user_pass, set_pass->old_pass, NVDIMM_PASSPHRASE_LEN)) { 232 user_plimit_check(mdata); 233 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 234 return -ENXIO; 235 } 236 memcpy(mdata->user_pass, set_pass->new_pass, NVDIMM_PASSPHRASE_LEN); 237 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PASS_SET; 238 return 0; 239 240 default: 241 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 242 } 243 return -EINVAL; 244 } 245 246 static int mock_disable_passphrase(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 247 { 248 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 249 struct cxl_disable_pass *dis_pass; 250 251 if (cmd->size_in != sizeof(*dis_pass)) 252 return -EINVAL; 253 254 if (cmd->size_out != 0) 255 return -EINVAL; 256 257 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 258 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 259 return -ENXIO; 260 } 261 262 dis_pass = cmd->payload_in; 263 switch (dis_pass->type) { 264 case CXL_PMEM_SEC_PASS_MASTER: 265 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT) { 266 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 267 return -ENXIO; 268 } 269 270 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)) { 271 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 272 return -ENXIO; 273 } 274 275 if (memcmp(dis_pass->pass, mdata->master_pass, NVDIMM_PASSPHRASE_LEN)) { 276 master_plimit_check(mdata); 277 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 278 return -ENXIO; 279 } 280 281 mdata->master_limit = 0; 282 memset(mdata->master_pass, 0, NVDIMM_PASSPHRASE_LEN); 283 mdata->security_state &= ~CXL_PMEM_SEC_STATE_MASTER_PASS_SET; 284 return 0; 285 286 case CXL_PMEM_SEC_PASS_USER: 287 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) { 288 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 289 return -ENXIO; 290 } 291 292 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) { 293 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 294 return -ENXIO; 295 } 296 297 if (memcmp(dis_pass->pass, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) { 298 user_plimit_check(mdata); 299 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 300 return -ENXIO; 301 } 302 303 mdata->user_limit = 0; 304 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN); 305 mdata->security_state &= ~(CXL_PMEM_SEC_STATE_USER_PASS_SET | 306 CXL_PMEM_SEC_STATE_LOCKED); 307 return 0; 308 309 default: 310 cmd->return_code = CXL_MBOX_CMD_RC_INPUT; 311 return -EINVAL; 312 } 313 314 return 0; 315 } 316 317 static int mock_freeze_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 318 { 319 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 320 321 if (cmd->size_in != 0) 322 return -EINVAL; 323 324 if (cmd->size_out != 0) 325 return -EINVAL; 326 327 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) 328 return 0; 329 330 mdata->security_state |= CXL_PMEM_SEC_STATE_FROZEN; 331 return 0; 332 } 333 334 static int mock_unlock_security(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 335 { 336 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 337 338 if (cmd->size_in != NVDIMM_PASSPHRASE_LEN) 339 return -EINVAL; 340 341 if (cmd->size_out != 0) 342 return -EINVAL; 343 344 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 345 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 346 return -ENXIO; 347 } 348 349 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) { 350 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 351 return -ENXIO; 352 } 353 354 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT) { 355 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 356 return -ENXIO; 357 } 358 359 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED)) { 360 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 361 return -ENXIO; 362 } 363 364 if (memcmp(cmd->payload_in, mdata->user_pass, NVDIMM_PASSPHRASE_LEN)) { 365 if (++mdata->user_limit == PASS_TRY_LIMIT) 366 mdata->security_state |= CXL_PMEM_SEC_STATE_USER_PLIMIT; 367 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 368 return -ENXIO; 369 } 370 371 mdata->user_limit = 0; 372 mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED; 373 return 0; 374 } 375 376 static int mock_passphrase_secure_erase(struct cxl_dev_state *cxlds, 377 struct cxl_mbox_cmd *cmd) 378 { 379 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 380 struct cxl_pass_erase *erase; 381 382 if (cmd->size_in != sizeof(*erase)) 383 return -EINVAL; 384 385 if (cmd->size_out != 0) 386 return -EINVAL; 387 388 erase = cmd->payload_in; 389 if (mdata->security_state & CXL_PMEM_SEC_STATE_FROZEN) { 390 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 391 return -ENXIO; 392 } 393 394 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PLIMIT && 395 erase->type == CXL_PMEM_SEC_PASS_USER) { 396 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 397 return -ENXIO; 398 } 399 400 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT && 401 erase->type == CXL_PMEM_SEC_PASS_MASTER) { 402 cmd->return_code = CXL_MBOX_CMD_RC_SECURITY; 403 return -ENXIO; 404 } 405 406 switch (erase->type) { 407 case CXL_PMEM_SEC_PASS_MASTER: 408 /* 409 * The spec does not clearly define the behavior of the scenario 410 * where a master passphrase is passed in while the master 411 * passphrase is not set and user passphrase is not set. The 412 * code will take the assumption that it will behave the same 413 * as a CXL secure erase command without passphrase (0x4401). 414 */ 415 if (mdata->security_state & CXL_PMEM_SEC_STATE_MASTER_PASS_SET) { 416 if (memcmp(mdata->master_pass, erase->pass, 417 NVDIMM_PASSPHRASE_LEN)) { 418 master_plimit_check(mdata); 419 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 420 return -ENXIO; 421 } 422 mdata->master_limit = 0; 423 mdata->user_limit = 0; 424 mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET; 425 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN); 426 mdata->security_state &= ~CXL_PMEM_SEC_STATE_LOCKED; 427 } else { 428 /* 429 * CXL rev3 8.2.9.8.6.3 Disable Passphrase 430 * When master passphrase is disabled, the device shall 431 * return Invalid Input for the Passphrase Secure Erase 432 * command with master passphrase. 433 */ 434 return -EINVAL; 435 } 436 /* Scramble encryption keys so that data is effectively erased */ 437 break; 438 case CXL_PMEM_SEC_PASS_USER: 439 /* 440 * The spec does not clearly define the behavior of the scenario 441 * where a user passphrase is passed in while the user 442 * passphrase is not set. The code will take the assumption that 443 * it will behave the same as a CXL secure erase command without 444 * passphrase (0x4401). 445 */ 446 if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) { 447 if (memcmp(mdata->user_pass, erase->pass, 448 NVDIMM_PASSPHRASE_LEN)) { 449 user_plimit_check(mdata); 450 cmd->return_code = CXL_MBOX_CMD_RC_PASSPHRASE; 451 return -ENXIO; 452 } 453 mdata->user_limit = 0; 454 mdata->security_state &= ~CXL_PMEM_SEC_STATE_USER_PASS_SET; 455 memset(mdata->user_pass, 0, NVDIMM_PASSPHRASE_LEN); 456 } 457 458 /* 459 * CXL rev3 Table 8-118 460 * If user passphrase is not set or supported by device, current 461 * passphrase value is ignored. Will make the assumption that 462 * the operation will proceed as secure erase w/o passphrase 463 * since spec is not explicit. 464 */ 465 466 /* Scramble encryption keys so that data is effectively erased */ 467 break; 468 default: 469 return -EINVAL; 470 } 471 472 return 0; 473 } 474 475 static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 476 { 477 struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in; 478 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 479 void *lsa = mdata->lsa; 480 u32 offset, length; 481 482 if (sizeof(*get_lsa) > cmd->size_in) 483 return -EINVAL; 484 offset = le32_to_cpu(get_lsa->offset); 485 length = le32_to_cpu(get_lsa->length); 486 if (offset + length > LSA_SIZE) 487 return -EINVAL; 488 if (length > cmd->size_out) 489 return -EINVAL; 490 491 memcpy(cmd->payload_out, lsa + offset, length); 492 return 0; 493 } 494 495 static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 496 { 497 struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in; 498 struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); 499 void *lsa = mdata->lsa; 500 u32 offset, length; 501 502 if (sizeof(*set_lsa) > cmd->size_in) 503 return -EINVAL; 504 offset = le32_to_cpu(set_lsa->offset); 505 length = cmd->size_in - sizeof(*set_lsa); 506 if (offset + length > LSA_SIZE) 507 return -EINVAL; 508 509 memcpy(lsa + offset, &set_lsa->data[0], length); 510 return 0; 511 } 512 513 static int mock_health_info(struct cxl_dev_state *cxlds, 514 struct cxl_mbox_cmd *cmd) 515 { 516 struct cxl_mbox_health_info health_info = { 517 /* set flags for maint needed, perf degraded, hw replacement */ 518 .health_status = 0x7, 519 /* set media status to "All Data Lost" */ 520 .media_status = 0x3, 521 /* 522 * set ext_status flags for: 523 * ext_life_used: normal, 524 * ext_temperature: critical, 525 * ext_corrected_volatile: warning, 526 * ext_corrected_persistent: normal, 527 */ 528 .ext_status = 0x18, 529 .life_used = 15, 530 .temperature = cpu_to_le16(25), 531 .dirty_shutdowns = cpu_to_le32(10), 532 .volatile_errors = cpu_to_le32(20), 533 .pmem_errors = cpu_to_le32(30), 534 }; 535 536 if (cmd->size_out < sizeof(health_info)) 537 return -EINVAL; 538 539 memcpy(cmd->payload_out, &health_info, sizeof(health_info)); 540 return 0; 541 } 542 543 static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 544 { 545 struct device *dev = cxlds->dev; 546 int rc = -EIO; 547 548 switch (cmd->opcode) { 549 case CXL_MBOX_OP_GET_SUPPORTED_LOGS: 550 rc = mock_gsl(cmd); 551 break; 552 case CXL_MBOX_OP_GET_LOG: 553 rc = mock_get_log(cxlds, cmd); 554 break; 555 case CXL_MBOX_OP_IDENTIFY: 556 rc = mock_id(cxlds, cmd); 557 break; 558 case CXL_MBOX_OP_GET_LSA: 559 rc = mock_get_lsa(cxlds, cmd); 560 break; 561 case CXL_MBOX_OP_GET_PARTITION_INFO: 562 rc = mock_partition_info(cxlds, cmd); 563 break; 564 case CXL_MBOX_OP_SET_LSA: 565 rc = mock_set_lsa(cxlds, cmd); 566 break; 567 case CXL_MBOX_OP_GET_HEALTH_INFO: 568 rc = mock_health_info(cxlds, cmd); 569 break; 570 case CXL_MBOX_OP_GET_SECURITY_STATE: 571 rc = mock_get_security_state(cxlds, cmd); 572 break; 573 case CXL_MBOX_OP_SET_PASSPHRASE: 574 rc = mock_set_passphrase(cxlds, cmd); 575 break; 576 case CXL_MBOX_OP_DISABLE_PASSPHRASE: 577 rc = mock_disable_passphrase(cxlds, cmd); 578 break; 579 case CXL_MBOX_OP_FREEZE_SECURITY: 580 rc = mock_freeze_security(cxlds, cmd); 581 break; 582 case CXL_MBOX_OP_UNLOCK: 583 rc = mock_unlock_security(cxlds, cmd); 584 break; 585 case CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE: 586 rc = mock_passphrase_secure_erase(cxlds, cmd); 587 break; 588 default: 589 break; 590 } 591 592 dev_dbg(dev, "opcode: %#x sz_in: %zd sz_out: %zd rc: %d\n", cmd->opcode, 593 cmd->size_in, cmd->size_out, rc); 594 595 return rc; 596 } 597 598 static void label_area_release(void *lsa) 599 { 600 vfree(lsa); 601 } 602 603 static int cxl_mock_mem_probe(struct platform_device *pdev) 604 { 605 struct device *dev = &pdev->dev; 606 struct cxl_memdev *cxlmd; 607 struct cxl_dev_state *cxlds; 608 struct cxl_mockmem_data *mdata; 609 int rc; 610 611 mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL); 612 if (!mdata) 613 return -ENOMEM; 614 dev_set_drvdata(dev, mdata); 615 616 mdata->lsa = vmalloc(LSA_SIZE); 617 if (!mdata->lsa) 618 return -ENOMEM; 619 rc = devm_add_action_or_reset(dev, label_area_release, mdata->lsa); 620 if (rc) 621 return rc; 622 623 cxlds = cxl_dev_state_create(dev); 624 if (IS_ERR(cxlds)) 625 return PTR_ERR(cxlds); 626 627 cxlds->serial = pdev->id; 628 cxlds->mbox_send = cxl_mock_mbox_send; 629 cxlds->payload_size = SZ_4K; 630 631 rc = cxl_enumerate_cmds(cxlds); 632 if (rc) 633 return rc; 634 635 rc = cxl_dev_state_identify(cxlds); 636 if (rc) 637 return rc; 638 639 rc = cxl_mem_create_range_info(cxlds); 640 if (rc) 641 return rc; 642 643 cxlmd = devm_cxl_add_memdev(cxlds); 644 if (IS_ERR(cxlmd)) 645 return PTR_ERR(cxlmd); 646 647 if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) 648 rc = devm_cxl_add_nvdimm(dev, cxlmd); 649 650 return 0; 651 } 652 653 static ssize_t security_lock_show(struct device *dev, 654 struct device_attribute *attr, char *buf) 655 { 656 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 657 658 return sysfs_emit(buf, "%u\n", 659 !!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED)); 660 } 661 662 static ssize_t security_lock_store(struct device *dev, struct device_attribute *attr, 663 const char *buf, size_t count) 664 { 665 struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); 666 u32 mask = CXL_PMEM_SEC_STATE_FROZEN | CXL_PMEM_SEC_STATE_USER_PLIMIT | 667 CXL_PMEM_SEC_STATE_MASTER_PLIMIT; 668 int val; 669 670 if (kstrtoint(buf, 0, &val) < 0) 671 return -EINVAL; 672 673 if (val == 1) { 674 if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) 675 return -ENXIO; 676 mdata->security_state |= CXL_PMEM_SEC_STATE_LOCKED; 677 mdata->security_state &= ~mask; 678 } else { 679 return -EINVAL; 680 } 681 return count; 682 } 683 684 static DEVICE_ATTR_RW(security_lock); 685 686 static struct attribute *cxl_mock_mem_attrs[] = { 687 &dev_attr_security_lock.attr, 688 NULL 689 }; 690 ATTRIBUTE_GROUPS(cxl_mock_mem); 691 692 static const struct platform_device_id cxl_mock_mem_ids[] = { 693 { .name = "cxl_mem", }, 694 { }, 695 }; 696 MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids); 697 698 static struct platform_driver cxl_mock_mem_driver = { 699 .probe = cxl_mock_mem_probe, 700 .id_table = cxl_mock_mem_ids, 701 .driver = { 702 .name = KBUILD_MODNAME, 703 .dev_groups = cxl_mock_mem_groups, 704 }, 705 }; 706 707 module_platform_driver(cxl_mock_mem_driver); 708 MODULE_LICENSE("GPL v2"); 709 MODULE_IMPORT_NS(CXL); 710