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