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