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