1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2018 Intel Corporation. All rights reserved. */ 3 #include <linux/libnvdimm.h> 4 #include <linux/ndctl.h> 5 #include <linux/acpi.h> 6 #include <linux/memregion.h> 7 #include <asm/smp.h> 8 #include "intel.h" 9 #include "nfit.h" 10 11 static ssize_t firmware_activate_noidle_show(struct device *dev, 12 struct device_attribute *attr, char *buf) 13 { 14 struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev); 15 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); 16 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); 17 18 return sprintf(buf, "%s\n", acpi_desc->fwa_noidle ? "Y" : "N"); 19 } 20 21 static ssize_t firmware_activate_noidle_store(struct device *dev, 22 struct device_attribute *attr, const char *buf, size_t size) 23 { 24 struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev); 25 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); 26 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); 27 ssize_t rc; 28 bool val; 29 30 rc = kstrtobool(buf, &val); 31 if (rc) 32 return rc; 33 if (val != acpi_desc->fwa_noidle) 34 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_INVALID; 35 acpi_desc->fwa_noidle = val; 36 return size; 37 } 38 DEVICE_ATTR_RW(firmware_activate_noidle); 39 40 bool intel_fwa_supported(struct nvdimm_bus *nvdimm_bus) 41 { 42 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); 43 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); 44 unsigned long *mask; 45 46 if (!test_bit(NVDIMM_BUS_FAMILY_INTEL, &nd_desc->bus_family_mask)) 47 return false; 48 49 mask = &acpi_desc->family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL]; 50 return *mask == NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK; 51 } 52 53 static unsigned long intel_security_flags(struct nvdimm *nvdimm, 54 enum nvdimm_passphrase_type ptype) 55 { 56 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 57 unsigned long security_flags = 0; 58 struct { 59 struct nd_cmd_pkg pkg; 60 struct nd_intel_get_security_state cmd; 61 } nd_cmd = { 62 .pkg = { 63 .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE, 64 .nd_family = NVDIMM_FAMILY_INTEL, 65 .nd_size_out = 66 sizeof(struct nd_intel_get_security_state), 67 .nd_fw_size = 68 sizeof(struct nd_intel_get_security_state), 69 }, 70 }; 71 int rc; 72 73 if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) 74 return 0; 75 76 /* 77 * Short circuit the state retrieval while we are doing overwrite. 78 * The DSM spec states that the security state is indeterminate 79 * until the overwrite DSM completes. 80 */ 81 if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER) 82 return BIT(NVDIMM_SECURITY_OVERWRITE); 83 84 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 85 if (rc < 0 || nd_cmd.cmd.status) { 86 pr_err("%s: security state retrieval failed (%d:%#x)\n", 87 nvdimm_name(nvdimm), rc, nd_cmd.cmd.status); 88 return 0; 89 } 90 91 /* check and see if security is enabled and locked */ 92 if (ptype == NVDIMM_MASTER) { 93 if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED) 94 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); 95 else 96 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); 97 if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_PLIMIT) 98 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); 99 return security_flags; 100 } 101 102 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) 103 return 0; 104 105 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { 106 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN || 107 nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT) 108 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); 109 110 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) 111 set_bit(NVDIMM_SECURITY_LOCKED, &security_flags); 112 else 113 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); 114 } else 115 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); 116 117 return security_flags; 118 } 119 120 static int intel_security_freeze(struct nvdimm *nvdimm) 121 { 122 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 123 struct { 124 struct nd_cmd_pkg pkg; 125 struct nd_intel_freeze_lock cmd; 126 } nd_cmd = { 127 .pkg = { 128 .nd_command = NVDIMM_INTEL_FREEZE_LOCK, 129 .nd_family = NVDIMM_FAMILY_INTEL, 130 .nd_size_out = ND_INTEL_STATUS_SIZE, 131 .nd_fw_size = ND_INTEL_STATUS_SIZE, 132 }, 133 }; 134 int rc; 135 136 if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask)) 137 return -ENOTTY; 138 139 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 140 if (rc < 0) 141 return rc; 142 if (nd_cmd.cmd.status) 143 return -EIO; 144 return 0; 145 } 146 147 static int intel_security_change_key(struct nvdimm *nvdimm, 148 const struct nvdimm_key_data *old_data, 149 const struct nvdimm_key_data *new_data, 150 enum nvdimm_passphrase_type ptype) 151 { 152 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 153 unsigned int cmd = ptype == NVDIMM_MASTER ? 154 NVDIMM_INTEL_SET_MASTER_PASSPHRASE : 155 NVDIMM_INTEL_SET_PASSPHRASE; 156 struct { 157 struct nd_cmd_pkg pkg; 158 struct nd_intel_set_passphrase cmd; 159 } nd_cmd = { 160 .pkg = { 161 .nd_family = NVDIMM_FAMILY_INTEL, 162 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2, 163 .nd_size_out = ND_INTEL_STATUS_SIZE, 164 .nd_fw_size = ND_INTEL_STATUS_SIZE, 165 .nd_command = cmd, 166 }, 167 }; 168 int rc; 169 170 if (!test_bit(cmd, &nfit_mem->dsm_mask)) 171 return -ENOTTY; 172 173 memcpy(nd_cmd.cmd.old_pass, old_data->data, 174 sizeof(nd_cmd.cmd.old_pass)); 175 memcpy(nd_cmd.cmd.new_pass, new_data->data, 176 sizeof(nd_cmd.cmd.new_pass)); 177 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 178 if (rc < 0) 179 return rc; 180 181 switch (nd_cmd.cmd.status) { 182 case 0: 183 return 0; 184 case ND_INTEL_STATUS_INVALID_PASS: 185 return -EINVAL; 186 case ND_INTEL_STATUS_NOT_SUPPORTED: 187 return -EOPNOTSUPP; 188 case ND_INTEL_STATUS_INVALID_STATE: 189 default: 190 return -EIO; 191 } 192 } 193 194 static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm, 195 const struct nvdimm_key_data *key_data) 196 { 197 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 198 struct { 199 struct nd_cmd_pkg pkg; 200 struct nd_intel_unlock_unit cmd; 201 } nd_cmd = { 202 .pkg = { 203 .nd_command = NVDIMM_INTEL_UNLOCK_UNIT, 204 .nd_family = NVDIMM_FAMILY_INTEL, 205 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, 206 .nd_size_out = ND_INTEL_STATUS_SIZE, 207 .nd_fw_size = ND_INTEL_STATUS_SIZE, 208 }, 209 }; 210 int rc; 211 212 if (!test_bit(NVDIMM_INTEL_UNLOCK_UNIT, &nfit_mem->dsm_mask)) 213 return -ENOTTY; 214 215 memcpy(nd_cmd.cmd.passphrase, key_data->data, 216 sizeof(nd_cmd.cmd.passphrase)); 217 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 218 if (rc < 0) 219 return rc; 220 switch (nd_cmd.cmd.status) { 221 case 0: 222 break; 223 case ND_INTEL_STATUS_INVALID_PASS: 224 return -EINVAL; 225 default: 226 return -EIO; 227 } 228 229 return 0; 230 } 231 232 static int intel_security_disable(struct nvdimm *nvdimm, 233 const struct nvdimm_key_data *key_data) 234 { 235 int rc; 236 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 237 struct { 238 struct nd_cmd_pkg pkg; 239 struct nd_intel_disable_passphrase cmd; 240 } nd_cmd = { 241 .pkg = { 242 .nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE, 243 .nd_family = NVDIMM_FAMILY_INTEL, 244 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, 245 .nd_size_out = ND_INTEL_STATUS_SIZE, 246 .nd_fw_size = ND_INTEL_STATUS_SIZE, 247 }, 248 }; 249 250 if (!test_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, &nfit_mem->dsm_mask)) 251 return -ENOTTY; 252 253 memcpy(nd_cmd.cmd.passphrase, key_data->data, 254 sizeof(nd_cmd.cmd.passphrase)); 255 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 256 if (rc < 0) 257 return rc; 258 259 switch (nd_cmd.cmd.status) { 260 case 0: 261 break; 262 case ND_INTEL_STATUS_INVALID_PASS: 263 return -EINVAL; 264 case ND_INTEL_STATUS_INVALID_STATE: 265 default: 266 return -ENXIO; 267 } 268 269 return 0; 270 } 271 272 static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm, 273 const struct nvdimm_key_data *key, 274 enum nvdimm_passphrase_type ptype) 275 { 276 int rc; 277 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 278 unsigned int cmd = ptype == NVDIMM_MASTER ? 279 NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE; 280 struct { 281 struct nd_cmd_pkg pkg; 282 struct nd_intel_secure_erase cmd; 283 } nd_cmd = { 284 .pkg = { 285 .nd_family = NVDIMM_FAMILY_INTEL, 286 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, 287 .nd_size_out = ND_INTEL_STATUS_SIZE, 288 .nd_fw_size = ND_INTEL_STATUS_SIZE, 289 .nd_command = cmd, 290 }, 291 }; 292 293 if (!test_bit(cmd, &nfit_mem->dsm_mask)) 294 return -ENOTTY; 295 296 memcpy(nd_cmd.cmd.passphrase, key->data, 297 sizeof(nd_cmd.cmd.passphrase)); 298 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 299 if (rc < 0) 300 return rc; 301 302 switch (nd_cmd.cmd.status) { 303 case 0: 304 break; 305 case ND_INTEL_STATUS_NOT_SUPPORTED: 306 return -EOPNOTSUPP; 307 case ND_INTEL_STATUS_INVALID_PASS: 308 return -EINVAL; 309 case ND_INTEL_STATUS_INVALID_STATE: 310 default: 311 return -ENXIO; 312 } 313 314 return 0; 315 } 316 317 static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm) 318 { 319 int rc; 320 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 321 struct { 322 struct nd_cmd_pkg pkg; 323 struct nd_intel_query_overwrite cmd; 324 } nd_cmd = { 325 .pkg = { 326 .nd_command = NVDIMM_INTEL_QUERY_OVERWRITE, 327 .nd_family = NVDIMM_FAMILY_INTEL, 328 .nd_size_out = ND_INTEL_STATUS_SIZE, 329 .nd_fw_size = ND_INTEL_STATUS_SIZE, 330 }, 331 }; 332 333 if (!test_bit(NVDIMM_INTEL_QUERY_OVERWRITE, &nfit_mem->dsm_mask)) 334 return -ENOTTY; 335 336 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 337 if (rc < 0) 338 return rc; 339 340 switch (nd_cmd.cmd.status) { 341 case 0: 342 break; 343 case ND_INTEL_STATUS_OQUERY_INPROGRESS: 344 return -EBUSY; 345 default: 346 return -ENXIO; 347 } 348 349 return 0; 350 } 351 352 static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm, 353 const struct nvdimm_key_data *nkey) 354 { 355 int rc; 356 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 357 struct { 358 struct nd_cmd_pkg pkg; 359 struct nd_intel_overwrite cmd; 360 } nd_cmd = { 361 .pkg = { 362 .nd_command = NVDIMM_INTEL_OVERWRITE, 363 .nd_family = NVDIMM_FAMILY_INTEL, 364 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, 365 .nd_size_out = ND_INTEL_STATUS_SIZE, 366 .nd_fw_size = ND_INTEL_STATUS_SIZE, 367 }, 368 }; 369 370 if (!test_bit(NVDIMM_INTEL_OVERWRITE, &nfit_mem->dsm_mask)) 371 return -ENOTTY; 372 373 memcpy(nd_cmd.cmd.passphrase, nkey->data, 374 sizeof(nd_cmd.cmd.passphrase)); 375 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 376 if (rc < 0) 377 return rc; 378 379 switch (nd_cmd.cmd.status) { 380 case 0: 381 return 0; 382 case ND_INTEL_STATUS_OVERWRITE_UNSUPPORTED: 383 return -ENOTSUPP; 384 case ND_INTEL_STATUS_INVALID_PASS: 385 return -EINVAL; 386 case ND_INTEL_STATUS_INVALID_STATE: 387 default: 388 return -ENXIO; 389 } 390 } 391 392 static const struct nvdimm_security_ops __intel_security_ops = { 393 .get_flags = intel_security_flags, 394 .freeze = intel_security_freeze, 395 .change_key = intel_security_change_key, 396 .disable = intel_security_disable, 397 #ifdef CONFIG_X86 398 .unlock = intel_security_unlock, 399 .erase = intel_security_erase, 400 .overwrite = intel_security_overwrite, 401 .query_overwrite = intel_security_query_overwrite, 402 #endif 403 }; 404 405 const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops; 406 407 static int intel_bus_fwa_businfo(struct nvdimm_bus_descriptor *nd_desc, 408 struct nd_intel_bus_fw_activate_businfo *info) 409 { 410 struct { 411 struct nd_cmd_pkg pkg; 412 struct nd_intel_bus_fw_activate_businfo cmd; 413 } nd_cmd = { 414 .pkg = { 415 .nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO, 416 .nd_family = NVDIMM_BUS_FAMILY_INTEL, 417 .nd_size_out = 418 sizeof(struct nd_intel_bus_fw_activate_businfo), 419 .nd_fw_size = 420 sizeof(struct nd_intel_bus_fw_activate_businfo), 421 }, 422 }; 423 int rc; 424 425 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), 426 NULL); 427 *info = nd_cmd.cmd; 428 return rc; 429 } 430 431 /* The fw_ops expect to be called with the nvdimm_bus_lock() held */ 432 static enum nvdimm_fwa_state intel_bus_fwa_state( 433 struct nvdimm_bus_descriptor *nd_desc) 434 { 435 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); 436 struct nd_intel_bus_fw_activate_businfo info; 437 struct device *dev = acpi_desc->dev; 438 enum nvdimm_fwa_state state; 439 int rc; 440 441 /* 442 * It should not be possible for platform firmware to return 443 * busy because activate is a synchronous operation. Treat it 444 * similar to invalid, i.e. always refresh / poll the status. 445 */ 446 switch (acpi_desc->fwa_state) { 447 case NVDIMM_FWA_INVALID: 448 case NVDIMM_FWA_BUSY: 449 break; 450 default: 451 /* check if capability needs to be refreshed */ 452 if (acpi_desc->fwa_cap == NVDIMM_FWA_CAP_INVALID) 453 break; 454 return acpi_desc->fwa_state; 455 } 456 457 /* Refresh with platform firmware */ 458 rc = intel_bus_fwa_businfo(nd_desc, &info); 459 if (rc) 460 return NVDIMM_FWA_INVALID; 461 462 switch (info.state) { 463 case ND_INTEL_FWA_IDLE: 464 state = NVDIMM_FWA_IDLE; 465 break; 466 case ND_INTEL_FWA_BUSY: 467 state = NVDIMM_FWA_BUSY; 468 break; 469 case ND_INTEL_FWA_ARMED: 470 if (info.activate_tmo > info.max_quiesce_tmo) 471 state = NVDIMM_FWA_ARM_OVERFLOW; 472 else 473 state = NVDIMM_FWA_ARMED; 474 break; 475 default: 476 dev_err_once(dev, "invalid firmware activate state %d\n", 477 info.state); 478 return NVDIMM_FWA_INVALID; 479 } 480 481 /* 482 * Capability data is available in the same payload as state. It 483 * is expected to be static. 484 */ 485 if (acpi_desc->fwa_cap == NVDIMM_FWA_CAP_INVALID) { 486 if (info.capability & ND_INTEL_BUS_FWA_CAP_FWQUIESCE) 487 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_QUIESCE; 488 else if (info.capability & ND_INTEL_BUS_FWA_CAP_OSQUIESCE) { 489 /* 490 * Skip hibernate cycle by default if platform 491 * indicates that it does not need devices to be 492 * quiesced. 493 */ 494 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_LIVE; 495 } else 496 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_NONE; 497 } 498 499 acpi_desc->fwa_state = state; 500 501 return state; 502 } 503 504 static enum nvdimm_fwa_capability intel_bus_fwa_capability( 505 struct nvdimm_bus_descriptor *nd_desc) 506 { 507 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); 508 509 if (acpi_desc->fwa_cap > NVDIMM_FWA_CAP_INVALID) 510 return acpi_desc->fwa_cap; 511 512 if (intel_bus_fwa_state(nd_desc) > NVDIMM_FWA_INVALID) 513 return acpi_desc->fwa_cap; 514 515 return NVDIMM_FWA_CAP_INVALID; 516 } 517 518 static int intel_bus_fwa_activate(struct nvdimm_bus_descriptor *nd_desc) 519 { 520 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); 521 struct { 522 struct nd_cmd_pkg pkg; 523 struct nd_intel_bus_fw_activate cmd; 524 } nd_cmd = { 525 .pkg = { 526 .nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE, 527 .nd_family = NVDIMM_BUS_FAMILY_INTEL, 528 .nd_size_in = sizeof(nd_cmd.cmd.iodev_state), 529 .nd_size_out = 530 sizeof(struct nd_intel_bus_fw_activate), 531 .nd_fw_size = 532 sizeof(struct nd_intel_bus_fw_activate), 533 }, 534 /* 535 * Even though activate is run from a suspended context, 536 * for safety, still ask platform firmware to force 537 * quiesce devices by default. Let a module 538 * parameter override that policy. 539 */ 540 .cmd = { 541 .iodev_state = acpi_desc->fwa_noidle 542 ? ND_INTEL_BUS_FWA_IODEV_OS_IDLE 543 : ND_INTEL_BUS_FWA_IODEV_FORCE_IDLE, 544 }, 545 }; 546 int rc; 547 548 switch (intel_bus_fwa_state(nd_desc)) { 549 case NVDIMM_FWA_ARMED: 550 case NVDIMM_FWA_ARM_OVERFLOW: 551 break; 552 default: 553 return -ENXIO; 554 } 555 556 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), 557 NULL); 558 559 /* 560 * Whether the command succeeded, or failed, the agent checking 561 * for the result needs to query the DIMMs individually. 562 * Increment the activation count to invalidate all the DIMM 563 * states at once (it's otherwise not possible to take 564 * acpi_desc->init_mutex in this context) 565 */ 566 acpi_desc->fwa_state = NVDIMM_FWA_INVALID; 567 acpi_desc->fwa_count++; 568 569 dev_dbg(acpi_desc->dev, "result: %d\n", rc); 570 571 return rc; 572 } 573 574 static const struct nvdimm_bus_fw_ops __intel_bus_fw_ops = { 575 .activate_state = intel_bus_fwa_state, 576 .capability = intel_bus_fwa_capability, 577 .activate = intel_bus_fwa_activate, 578 }; 579 580 const struct nvdimm_bus_fw_ops *intel_bus_fw_ops = &__intel_bus_fw_ops; 581 582 static int intel_fwa_dimminfo(struct nvdimm *nvdimm, 583 struct nd_intel_fw_activate_dimminfo *info) 584 { 585 struct { 586 struct nd_cmd_pkg pkg; 587 struct nd_intel_fw_activate_dimminfo cmd; 588 } nd_cmd = { 589 .pkg = { 590 .nd_command = NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO, 591 .nd_family = NVDIMM_FAMILY_INTEL, 592 .nd_size_out = 593 sizeof(struct nd_intel_fw_activate_dimminfo), 594 .nd_fw_size = 595 sizeof(struct nd_intel_fw_activate_dimminfo), 596 }, 597 }; 598 int rc; 599 600 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 601 *info = nd_cmd.cmd; 602 return rc; 603 } 604 605 static enum nvdimm_fwa_state intel_fwa_state(struct nvdimm *nvdimm) 606 { 607 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 608 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc; 609 struct nd_intel_fw_activate_dimminfo info; 610 int rc; 611 612 /* 613 * Similar to the bus state, since activate is synchronous the 614 * busy state should resolve within the context of 'activate'. 615 */ 616 switch (nfit_mem->fwa_state) { 617 case NVDIMM_FWA_INVALID: 618 case NVDIMM_FWA_BUSY: 619 break; 620 default: 621 /* If no activations occurred the old state is still valid */ 622 if (nfit_mem->fwa_count == acpi_desc->fwa_count) 623 return nfit_mem->fwa_state; 624 } 625 626 rc = intel_fwa_dimminfo(nvdimm, &info); 627 if (rc) 628 return NVDIMM_FWA_INVALID; 629 630 switch (info.state) { 631 case ND_INTEL_FWA_IDLE: 632 nfit_mem->fwa_state = NVDIMM_FWA_IDLE; 633 break; 634 case ND_INTEL_FWA_BUSY: 635 nfit_mem->fwa_state = NVDIMM_FWA_BUSY; 636 break; 637 case ND_INTEL_FWA_ARMED: 638 nfit_mem->fwa_state = NVDIMM_FWA_ARMED; 639 break; 640 default: 641 nfit_mem->fwa_state = NVDIMM_FWA_INVALID; 642 break; 643 } 644 645 switch (info.result) { 646 case ND_INTEL_DIMM_FWA_NONE: 647 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NONE; 648 break; 649 case ND_INTEL_DIMM_FWA_SUCCESS: 650 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_SUCCESS; 651 break; 652 case ND_INTEL_DIMM_FWA_NOTSTAGED: 653 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NOTSTAGED; 654 break; 655 case ND_INTEL_DIMM_FWA_NEEDRESET: 656 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NEEDRESET; 657 break; 658 case ND_INTEL_DIMM_FWA_MEDIAFAILED: 659 case ND_INTEL_DIMM_FWA_ABORT: 660 case ND_INTEL_DIMM_FWA_NOTSUPP: 661 case ND_INTEL_DIMM_FWA_ERROR: 662 default: 663 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_FAIL; 664 break; 665 } 666 667 nfit_mem->fwa_count = acpi_desc->fwa_count; 668 669 return nfit_mem->fwa_state; 670 } 671 672 static enum nvdimm_fwa_result intel_fwa_result(struct nvdimm *nvdimm) 673 { 674 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 675 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc; 676 677 if (nfit_mem->fwa_count == acpi_desc->fwa_count 678 && nfit_mem->fwa_result > NVDIMM_FWA_RESULT_INVALID) 679 return nfit_mem->fwa_result; 680 681 if (intel_fwa_state(nvdimm) > NVDIMM_FWA_INVALID) 682 return nfit_mem->fwa_result; 683 684 return NVDIMM_FWA_RESULT_INVALID; 685 } 686 687 static int intel_fwa_arm(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arm) 688 { 689 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 690 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc; 691 struct { 692 struct nd_cmd_pkg pkg; 693 struct nd_intel_fw_activate_arm cmd; 694 } nd_cmd = { 695 .pkg = { 696 .nd_command = NVDIMM_INTEL_FW_ACTIVATE_ARM, 697 .nd_family = NVDIMM_FAMILY_INTEL, 698 .nd_size_in = sizeof(nd_cmd.cmd.activate_arm), 699 .nd_size_out = 700 sizeof(struct nd_intel_fw_activate_arm), 701 .nd_fw_size = 702 sizeof(struct nd_intel_fw_activate_arm), 703 }, 704 .cmd = { 705 .activate_arm = arm == NVDIMM_FWA_ARM 706 ? ND_INTEL_DIMM_FWA_ARM 707 : ND_INTEL_DIMM_FWA_DISARM, 708 }, 709 }; 710 int rc; 711 712 switch (intel_fwa_state(nvdimm)) { 713 case NVDIMM_FWA_INVALID: 714 return -ENXIO; 715 case NVDIMM_FWA_BUSY: 716 return -EBUSY; 717 case NVDIMM_FWA_IDLE: 718 if (arm == NVDIMM_FWA_DISARM) 719 return 0; 720 break; 721 case NVDIMM_FWA_ARMED: 722 if (arm == NVDIMM_FWA_ARM) 723 return 0; 724 break; 725 default: 726 return -ENXIO; 727 } 728 729 /* 730 * Invalidate the bus-level state, now that we're committed to 731 * changing the 'arm' state. 732 */ 733 acpi_desc->fwa_state = NVDIMM_FWA_INVALID; 734 nfit_mem->fwa_state = NVDIMM_FWA_INVALID; 735 736 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); 737 738 dev_dbg(acpi_desc->dev, "%s result: %d\n", arm == NVDIMM_FWA_ARM 739 ? "arm" : "disarm", rc); 740 return rc; 741 } 742 743 static const struct nvdimm_fw_ops __intel_fw_ops = { 744 .activate_state = intel_fwa_state, 745 .activate_result = intel_fwa_result, 746 .arm = intel_fwa_arm, 747 }; 748 749 const struct nvdimm_fw_ops *intel_fw_ops = &__intel_fw_ops; 750