0001
0002
0003 #include <linux/libnvdimm.h>
0004 #include <linux/ndctl.h>
0005 #include <linux/acpi.h>
0006 #include <asm/smp.h>
0007 #include "intel.h"
0008 #include "nfit.h"
0009
0010 static ssize_t firmware_activate_noidle_show(struct device *dev,
0011 struct device_attribute *attr, char *buf)
0012 {
0013 struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
0014 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
0015 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
0016
0017 return sprintf(buf, "%s\n", acpi_desc->fwa_noidle ? "Y" : "N");
0018 }
0019
0020 static ssize_t firmware_activate_noidle_store(struct device *dev,
0021 struct device_attribute *attr, const char *buf, size_t size)
0022 {
0023 struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
0024 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
0025 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
0026 ssize_t rc;
0027 bool val;
0028
0029 rc = kstrtobool(buf, &val);
0030 if (rc)
0031 return rc;
0032 if (val != acpi_desc->fwa_noidle)
0033 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_INVALID;
0034 acpi_desc->fwa_noidle = val;
0035 return size;
0036 }
0037 DEVICE_ATTR_RW(firmware_activate_noidle);
0038
0039 bool intel_fwa_supported(struct nvdimm_bus *nvdimm_bus)
0040 {
0041 struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
0042 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
0043 unsigned long *mask;
0044
0045 if (!test_bit(NVDIMM_BUS_FAMILY_INTEL, &nd_desc->bus_family_mask))
0046 return false;
0047
0048 mask = &acpi_desc->family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL];
0049 return *mask == NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK;
0050 }
0051
0052 static unsigned long intel_security_flags(struct nvdimm *nvdimm,
0053 enum nvdimm_passphrase_type ptype)
0054 {
0055 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0056 unsigned long security_flags = 0;
0057 struct {
0058 struct nd_cmd_pkg pkg;
0059 struct nd_intel_get_security_state cmd;
0060 } nd_cmd = {
0061 .pkg = {
0062 .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,
0063 .nd_family = NVDIMM_FAMILY_INTEL,
0064 .nd_size_out =
0065 sizeof(struct nd_intel_get_security_state),
0066 .nd_fw_size =
0067 sizeof(struct nd_intel_get_security_state),
0068 },
0069 };
0070 int rc;
0071
0072 if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask))
0073 return 0;
0074
0075
0076
0077
0078
0079
0080 if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER)
0081 return BIT(NVDIMM_SECURITY_OVERWRITE);
0082
0083 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0084 if (rc < 0 || nd_cmd.cmd.status) {
0085 pr_err("%s: security state retrieval failed (%d:%#x)\n",
0086 nvdimm_name(nvdimm), rc, nd_cmd.cmd.status);
0087 return 0;
0088 }
0089
0090
0091 if (ptype == NVDIMM_MASTER) {
0092 if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED)
0093 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
0094 else
0095 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
0096 if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_PLIMIT)
0097 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
0098 return security_flags;
0099 }
0100
0101 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED)
0102 return 0;
0103
0104 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
0105 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN ||
0106 nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT)
0107 set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
0108
0109 if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED)
0110 set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
0111 else
0112 set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
0113 } else
0114 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
0115
0116 return security_flags;
0117 }
0118
0119 static int intel_security_freeze(struct nvdimm *nvdimm)
0120 {
0121 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0122 struct {
0123 struct nd_cmd_pkg pkg;
0124 struct nd_intel_freeze_lock cmd;
0125 } nd_cmd = {
0126 .pkg = {
0127 .nd_command = NVDIMM_INTEL_FREEZE_LOCK,
0128 .nd_family = NVDIMM_FAMILY_INTEL,
0129 .nd_size_out = ND_INTEL_STATUS_SIZE,
0130 .nd_fw_size = ND_INTEL_STATUS_SIZE,
0131 },
0132 };
0133 int rc;
0134
0135 if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask))
0136 return -ENOTTY;
0137
0138 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0139 if (rc < 0)
0140 return rc;
0141 if (nd_cmd.cmd.status)
0142 return -EIO;
0143 return 0;
0144 }
0145
0146 static int intel_security_change_key(struct nvdimm *nvdimm,
0147 const struct nvdimm_key_data *old_data,
0148 const struct nvdimm_key_data *new_data,
0149 enum nvdimm_passphrase_type ptype)
0150 {
0151 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0152 unsigned int cmd = ptype == NVDIMM_MASTER ?
0153 NVDIMM_INTEL_SET_MASTER_PASSPHRASE :
0154 NVDIMM_INTEL_SET_PASSPHRASE;
0155 struct {
0156 struct nd_cmd_pkg pkg;
0157 struct nd_intel_set_passphrase cmd;
0158 } nd_cmd = {
0159 .pkg = {
0160 .nd_family = NVDIMM_FAMILY_INTEL,
0161 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2,
0162 .nd_size_out = ND_INTEL_STATUS_SIZE,
0163 .nd_fw_size = ND_INTEL_STATUS_SIZE,
0164 .nd_command = cmd,
0165 },
0166 };
0167 int rc;
0168
0169 if (!test_bit(cmd, &nfit_mem->dsm_mask))
0170 return -ENOTTY;
0171
0172 memcpy(nd_cmd.cmd.old_pass, old_data->data,
0173 sizeof(nd_cmd.cmd.old_pass));
0174 memcpy(nd_cmd.cmd.new_pass, new_data->data,
0175 sizeof(nd_cmd.cmd.new_pass));
0176 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0177 if (rc < 0)
0178 return rc;
0179
0180 switch (nd_cmd.cmd.status) {
0181 case 0:
0182 return 0;
0183 case ND_INTEL_STATUS_INVALID_PASS:
0184 return -EINVAL;
0185 case ND_INTEL_STATUS_NOT_SUPPORTED:
0186 return -EOPNOTSUPP;
0187 case ND_INTEL_STATUS_INVALID_STATE:
0188 default:
0189 return -EIO;
0190 }
0191 }
0192
0193 static void nvdimm_invalidate_cache(void);
0194
0195 static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm,
0196 const struct nvdimm_key_data *key_data)
0197 {
0198 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0199 struct {
0200 struct nd_cmd_pkg pkg;
0201 struct nd_intel_unlock_unit cmd;
0202 } nd_cmd = {
0203 .pkg = {
0204 .nd_command = NVDIMM_INTEL_UNLOCK_UNIT,
0205 .nd_family = NVDIMM_FAMILY_INTEL,
0206 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
0207 .nd_size_out = ND_INTEL_STATUS_SIZE,
0208 .nd_fw_size = ND_INTEL_STATUS_SIZE,
0209 },
0210 };
0211 int rc;
0212
0213 if (!test_bit(NVDIMM_INTEL_UNLOCK_UNIT, &nfit_mem->dsm_mask))
0214 return -ENOTTY;
0215
0216 memcpy(nd_cmd.cmd.passphrase, key_data->data,
0217 sizeof(nd_cmd.cmd.passphrase));
0218 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0219 if (rc < 0)
0220 return rc;
0221 switch (nd_cmd.cmd.status) {
0222 case 0:
0223 break;
0224 case ND_INTEL_STATUS_INVALID_PASS:
0225 return -EINVAL;
0226 default:
0227 return -EIO;
0228 }
0229
0230
0231 nvdimm_invalidate_cache();
0232
0233 return 0;
0234 }
0235
0236 static int intel_security_disable(struct nvdimm *nvdimm,
0237 const struct nvdimm_key_data *key_data)
0238 {
0239 int rc;
0240 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0241 struct {
0242 struct nd_cmd_pkg pkg;
0243 struct nd_intel_disable_passphrase cmd;
0244 } nd_cmd = {
0245 .pkg = {
0246 .nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE,
0247 .nd_family = NVDIMM_FAMILY_INTEL,
0248 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
0249 .nd_size_out = ND_INTEL_STATUS_SIZE,
0250 .nd_fw_size = ND_INTEL_STATUS_SIZE,
0251 },
0252 };
0253
0254 if (!test_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, &nfit_mem->dsm_mask))
0255 return -ENOTTY;
0256
0257 memcpy(nd_cmd.cmd.passphrase, key_data->data,
0258 sizeof(nd_cmd.cmd.passphrase));
0259 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0260 if (rc < 0)
0261 return rc;
0262
0263 switch (nd_cmd.cmd.status) {
0264 case 0:
0265 break;
0266 case ND_INTEL_STATUS_INVALID_PASS:
0267 return -EINVAL;
0268 case ND_INTEL_STATUS_INVALID_STATE:
0269 default:
0270 return -ENXIO;
0271 }
0272
0273 return 0;
0274 }
0275
0276 static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm,
0277 const struct nvdimm_key_data *key,
0278 enum nvdimm_passphrase_type ptype)
0279 {
0280 int rc;
0281 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0282 unsigned int cmd = ptype == NVDIMM_MASTER ?
0283 NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE;
0284 struct {
0285 struct nd_cmd_pkg pkg;
0286 struct nd_intel_secure_erase cmd;
0287 } nd_cmd = {
0288 .pkg = {
0289 .nd_family = NVDIMM_FAMILY_INTEL,
0290 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
0291 .nd_size_out = ND_INTEL_STATUS_SIZE,
0292 .nd_fw_size = ND_INTEL_STATUS_SIZE,
0293 .nd_command = cmd,
0294 },
0295 };
0296
0297 if (!test_bit(cmd, &nfit_mem->dsm_mask))
0298 return -ENOTTY;
0299
0300
0301 nvdimm_invalidate_cache();
0302 memcpy(nd_cmd.cmd.passphrase, key->data,
0303 sizeof(nd_cmd.cmd.passphrase));
0304 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0305 if (rc < 0)
0306 return rc;
0307
0308 switch (nd_cmd.cmd.status) {
0309 case 0:
0310 break;
0311 case ND_INTEL_STATUS_NOT_SUPPORTED:
0312 return -EOPNOTSUPP;
0313 case ND_INTEL_STATUS_INVALID_PASS:
0314 return -EINVAL;
0315 case ND_INTEL_STATUS_INVALID_STATE:
0316 default:
0317 return -ENXIO;
0318 }
0319
0320
0321 nvdimm_invalidate_cache();
0322 return 0;
0323 }
0324
0325 static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm)
0326 {
0327 int rc;
0328 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0329 struct {
0330 struct nd_cmd_pkg pkg;
0331 struct nd_intel_query_overwrite cmd;
0332 } nd_cmd = {
0333 .pkg = {
0334 .nd_command = NVDIMM_INTEL_QUERY_OVERWRITE,
0335 .nd_family = NVDIMM_FAMILY_INTEL,
0336 .nd_size_out = ND_INTEL_STATUS_SIZE,
0337 .nd_fw_size = ND_INTEL_STATUS_SIZE,
0338 },
0339 };
0340
0341 if (!test_bit(NVDIMM_INTEL_QUERY_OVERWRITE, &nfit_mem->dsm_mask))
0342 return -ENOTTY;
0343
0344 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0345 if (rc < 0)
0346 return rc;
0347
0348 switch (nd_cmd.cmd.status) {
0349 case 0:
0350 break;
0351 case ND_INTEL_STATUS_OQUERY_INPROGRESS:
0352 return -EBUSY;
0353 default:
0354 return -ENXIO;
0355 }
0356
0357
0358 nvdimm_invalidate_cache();
0359 return 0;
0360 }
0361
0362 static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm,
0363 const struct nvdimm_key_data *nkey)
0364 {
0365 int rc;
0366 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0367 struct {
0368 struct nd_cmd_pkg pkg;
0369 struct nd_intel_overwrite cmd;
0370 } nd_cmd = {
0371 .pkg = {
0372 .nd_command = NVDIMM_INTEL_OVERWRITE,
0373 .nd_family = NVDIMM_FAMILY_INTEL,
0374 .nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
0375 .nd_size_out = ND_INTEL_STATUS_SIZE,
0376 .nd_fw_size = ND_INTEL_STATUS_SIZE,
0377 },
0378 };
0379
0380 if (!test_bit(NVDIMM_INTEL_OVERWRITE, &nfit_mem->dsm_mask))
0381 return -ENOTTY;
0382
0383
0384 nvdimm_invalidate_cache();
0385 memcpy(nd_cmd.cmd.passphrase, nkey->data,
0386 sizeof(nd_cmd.cmd.passphrase));
0387 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0388 if (rc < 0)
0389 return rc;
0390
0391 switch (nd_cmd.cmd.status) {
0392 case 0:
0393 return 0;
0394 case ND_INTEL_STATUS_OVERWRITE_UNSUPPORTED:
0395 return -ENOTSUPP;
0396 case ND_INTEL_STATUS_INVALID_PASS:
0397 return -EINVAL;
0398 case ND_INTEL_STATUS_INVALID_STATE:
0399 default:
0400 return -ENXIO;
0401 }
0402 }
0403
0404
0405
0406
0407
0408 #ifdef CONFIG_X86
0409 static void nvdimm_invalidate_cache(void)
0410 {
0411 wbinvd_on_all_cpus();
0412 }
0413 #else
0414 static void nvdimm_invalidate_cache(void)
0415 {
0416 WARN_ON_ONCE("cache invalidation required after unlock\n");
0417 }
0418 #endif
0419
0420 static const struct nvdimm_security_ops __intel_security_ops = {
0421 .get_flags = intel_security_flags,
0422 .freeze = intel_security_freeze,
0423 .change_key = intel_security_change_key,
0424 .disable = intel_security_disable,
0425 #ifdef CONFIG_X86
0426 .unlock = intel_security_unlock,
0427 .erase = intel_security_erase,
0428 .overwrite = intel_security_overwrite,
0429 .query_overwrite = intel_security_query_overwrite,
0430 #endif
0431 };
0432
0433 const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;
0434
0435 static int intel_bus_fwa_businfo(struct nvdimm_bus_descriptor *nd_desc,
0436 struct nd_intel_bus_fw_activate_businfo *info)
0437 {
0438 struct {
0439 struct nd_cmd_pkg pkg;
0440 struct nd_intel_bus_fw_activate_businfo cmd;
0441 } nd_cmd = {
0442 .pkg = {
0443 .nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO,
0444 .nd_family = NVDIMM_BUS_FAMILY_INTEL,
0445 .nd_size_out =
0446 sizeof(struct nd_intel_bus_fw_activate_businfo),
0447 .nd_fw_size =
0448 sizeof(struct nd_intel_bus_fw_activate_businfo),
0449 },
0450 };
0451 int rc;
0452
0453 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd),
0454 NULL);
0455 *info = nd_cmd.cmd;
0456 return rc;
0457 }
0458
0459
0460 static enum nvdimm_fwa_state intel_bus_fwa_state(
0461 struct nvdimm_bus_descriptor *nd_desc)
0462 {
0463 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
0464 struct nd_intel_bus_fw_activate_businfo info;
0465 struct device *dev = acpi_desc->dev;
0466 enum nvdimm_fwa_state state;
0467 int rc;
0468
0469
0470
0471
0472
0473
0474 switch (acpi_desc->fwa_state) {
0475 case NVDIMM_FWA_INVALID:
0476 case NVDIMM_FWA_BUSY:
0477 break;
0478 default:
0479
0480 if (acpi_desc->fwa_cap == NVDIMM_FWA_CAP_INVALID)
0481 break;
0482 return acpi_desc->fwa_state;
0483 }
0484
0485
0486 rc = intel_bus_fwa_businfo(nd_desc, &info);
0487 if (rc)
0488 return NVDIMM_FWA_INVALID;
0489
0490 switch (info.state) {
0491 case ND_INTEL_FWA_IDLE:
0492 state = NVDIMM_FWA_IDLE;
0493 break;
0494 case ND_INTEL_FWA_BUSY:
0495 state = NVDIMM_FWA_BUSY;
0496 break;
0497 case ND_INTEL_FWA_ARMED:
0498 if (info.activate_tmo > info.max_quiesce_tmo)
0499 state = NVDIMM_FWA_ARM_OVERFLOW;
0500 else
0501 state = NVDIMM_FWA_ARMED;
0502 break;
0503 default:
0504 dev_err_once(dev, "invalid firmware activate state %d\n",
0505 info.state);
0506 return NVDIMM_FWA_INVALID;
0507 }
0508
0509
0510
0511
0512
0513 if (acpi_desc->fwa_cap == NVDIMM_FWA_CAP_INVALID) {
0514 if (info.capability & ND_INTEL_BUS_FWA_CAP_FWQUIESCE)
0515 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_QUIESCE;
0516 else if (info.capability & ND_INTEL_BUS_FWA_CAP_OSQUIESCE) {
0517
0518
0519
0520
0521
0522 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_LIVE;
0523 } else
0524 acpi_desc->fwa_cap = NVDIMM_FWA_CAP_NONE;
0525 }
0526
0527 acpi_desc->fwa_state = state;
0528
0529 return state;
0530 }
0531
0532 static enum nvdimm_fwa_capability intel_bus_fwa_capability(
0533 struct nvdimm_bus_descriptor *nd_desc)
0534 {
0535 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
0536
0537 if (acpi_desc->fwa_cap > NVDIMM_FWA_CAP_INVALID)
0538 return acpi_desc->fwa_cap;
0539
0540 if (intel_bus_fwa_state(nd_desc) > NVDIMM_FWA_INVALID)
0541 return acpi_desc->fwa_cap;
0542
0543 return NVDIMM_FWA_CAP_INVALID;
0544 }
0545
0546 static int intel_bus_fwa_activate(struct nvdimm_bus_descriptor *nd_desc)
0547 {
0548 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
0549 struct {
0550 struct nd_cmd_pkg pkg;
0551 struct nd_intel_bus_fw_activate cmd;
0552 } nd_cmd = {
0553 .pkg = {
0554 .nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE,
0555 .nd_family = NVDIMM_BUS_FAMILY_INTEL,
0556 .nd_size_in = sizeof(nd_cmd.cmd.iodev_state),
0557 .nd_size_out =
0558 sizeof(struct nd_intel_bus_fw_activate),
0559 .nd_fw_size =
0560 sizeof(struct nd_intel_bus_fw_activate),
0561 },
0562
0563
0564
0565
0566
0567
0568 .cmd = {
0569 .iodev_state = acpi_desc->fwa_noidle
0570 ? ND_INTEL_BUS_FWA_IODEV_OS_IDLE
0571 : ND_INTEL_BUS_FWA_IODEV_FORCE_IDLE,
0572 },
0573 };
0574 int rc;
0575
0576 switch (intel_bus_fwa_state(nd_desc)) {
0577 case NVDIMM_FWA_ARMED:
0578 case NVDIMM_FWA_ARM_OVERFLOW:
0579 break;
0580 default:
0581 return -ENXIO;
0582 }
0583
0584 rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd),
0585 NULL);
0586
0587
0588
0589
0590
0591
0592
0593
0594 acpi_desc->fwa_state = NVDIMM_FWA_INVALID;
0595 acpi_desc->fwa_count++;
0596
0597 dev_dbg(acpi_desc->dev, "result: %d\n", rc);
0598
0599 return rc;
0600 }
0601
0602 static const struct nvdimm_bus_fw_ops __intel_bus_fw_ops = {
0603 .activate_state = intel_bus_fwa_state,
0604 .capability = intel_bus_fwa_capability,
0605 .activate = intel_bus_fwa_activate,
0606 };
0607
0608 const struct nvdimm_bus_fw_ops *intel_bus_fw_ops = &__intel_bus_fw_ops;
0609
0610 static int intel_fwa_dimminfo(struct nvdimm *nvdimm,
0611 struct nd_intel_fw_activate_dimminfo *info)
0612 {
0613 struct {
0614 struct nd_cmd_pkg pkg;
0615 struct nd_intel_fw_activate_dimminfo cmd;
0616 } nd_cmd = {
0617 .pkg = {
0618 .nd_command = NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO,
0619 .nd_family = NVDIMM_FAMILY_INTEL,
0620 .nd_size_out =
0621 sizeof(struct nd_intel_fw_activate_dimminfo),
0622 .nd_fw_size =
0623 sizeof(struct nd_intel_fw_activate_dimminfo),
0624 },
0625 };
0626 int rc;
0627
0628 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0629 *info = nd_cmd.cmd;
0630 return rc;
0631 }
0632
0633 static enum nvdimm_fwa_state intel_fwa_state(struct nvdimm *nvdimm)
0634 {
0635 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0636 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
0637 struct nd_intel_fw_activate_dimminfo info;
0638 int rc;
0639
0640
0641
0642
0643
0644 switch (nfit_mem->fwa_state) {
0645 case NVDIMM_FWA_INVALID:
0646 case NVDIMM_FWA_BUSY:
0647 break;
0648 default:
0649
0650 if (nfit_mem->fwa_count == acpi_desc->fwa_count)
0651 return nfit_mem->fwa_state;
0652 }
0653
0654 rc = intel_fwa_dimminfo(nvdimm, &info);
0655 if (rc)
0656 return NVDIMM_FWA_INVALID;
0657
0658 switch (info.state) {
0659 case ND_INTEL_FWA_IDLE:
0660 nfit_mem->fwa_state = NVDIMM_FWA_IDLE;
0661 break;
0662 case ND_INTEL_FWA_BUSY:
0663 nfit_mem->fwa_state = NVDIMM_FWA_BUSY;
0664 break;
0665 case ND_INTEL_FWA_ARMED:
0666 nfit_mem->fwa_state = NVDIMM_FWA_ARMED;
0667 break;
0668 default:
0669 nfit_mem->fwa_state = NVDIMM_FWA_INVALID;
0670 break;
0671 }
0672
0673 switch (info.result) {
0674 case ND_INTEL_DIMM_FWA_NONE:
0675 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NONE;
0676 break;
0677 case ND_INTEL_DIMM_FWA_SUCCESS:
0678 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_SUCCESS;
0679 break;
0680 case ND_INTEL_DIMM_FWA_NOTSTAGED:
0681 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NOTSTAGED;
0682 break;
0683 case ND_INTEL_DIMM_FWA_NEEDRESET:
0684 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_NEEDRESET;
0685 break;
0686 case ND_INTEL_DIMM_FWA_MEDIAFAILED:
0687 case ND_INTEL_DIMM_FWA_ABORT:
0688 case ND_INTEL_DIMM_FWA_NOTSUPP:
0689 case ND_INTEL_DIMM_FWA_ERROR:
0690 default:
0691 nfit_mem->fwa_result = NVDIMM_FWA_RESULT_FAIL;
0692 break;
0693 }
0694
0695 nfit_mem->fwa_count = acpi_desc->fwa_count;
0696
0697 return nfit_mem->fwa_state;
0698 }
0699
0700 static enum nvdimm_fwa_result intel_fwa_result(struct nvdimm *nvdimm)
0701 {
0702 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0703 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
0704
0705 if (nfit_mem->fwa_count == acpi_desc->fwa_count
0706 && nfit_mem->fwa_result > NVDIMM_FWA_RESULT_INVALID)
0707 return nfit_mem->fwa_result;
0708
0709 if (intel_fwa_state(nvdimm) > NVDIMM_FWA_INVALID)
0710 return nfit_mem->fwa_result;
0711
0712 return NVDIMM_FWA_RESULT_INVALID;
0713 }
0714
0715 static int intel_fwa_arm(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arm)
0716 {
0717 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
0718 struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
0719 struct {
0720 struct nd_cmd_pkg pkg;
0721 struct nd_intel_fw_activate_arm cmd;
0722 } nd_cmd = {
0723 .pkg = {
0724 .nd_command = NVDIMM_INTEL_FW_ACTIVATE_ARM,
0725 .nd_family = NVDIMM_FAMILY_INTEL,
0726 .nd_size_in = sizeof(nd_cmd.cmd.activate_arm),
0727 .nd_size_out =
0728 sizeof(struct nd_intel_fw_activate_arm),
0729 .nd_fw_size =
0730 sizeof(struct nd_intel_fw_activate_arm),
0731 },
0732 .cmd = {
0733 .activate_arm = arm == NVDIMM_FWA_ARM
0734 ? ND_INTEL_DIMM_FWA_ARM
0735 : ND_INTEL_DIMM_FWA_DISARM,
0736 },
0737 };
0738 int rc;
0739
0740 switch (intel_fwa_state(nvdimm)) {
0741 case NVDIMM_FWA_INVALID:
0742 return -ENXIO;
0743 case NVDIMM_FWA_BUSY:
0744 return -EBUSY;
0745 case NVDIMM_FWA_IDLE:
0746 if (arm == NVDIMM_FWA_DISARM)
0747 return 0;
0748 break;
0749 case NVDIMM_FWA_ARMED:
0750 if (arm == NVDIMM_FWA_ARM)
0751 return 0;
0752 break;
0753 default:
0754 return -ENXIO;
0755 }
0756
0757
0758
0759
0760
0761 acpi_desc->fwa_state = NVDIMM_FWA_INVALID;
0762 nfit_mem->fwa_state = NVDIMM_FWA_INVALID;
0763
0764 rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
0765
0766 dev_dbg(acpi_desc->dev, "%s result: %d\n", arm == NVDIMM_FWA_ARM
0767 ? "arm" : "disarm", rc);
0768 return rc;
0769 }
0770
0771 static const struct nvdimm_fw_ops __intel_fw_ops = {
0772 .activate_state = intel_fwa_state,
0773 .activate_result = intel_fwa_result,
0774 .arm = intel_fwa_arm,
0775 };
0776
0777 const struct nvdimm_fw_ops *intel_fw_ops = &__intel_fw_ops;