hc
2024-05-10 23fa18eaa71266feff7ba8d83022d9e1cc83c65a
kernel/drivers/nvdimm/core.c
....@@ -1,17 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of version 2 of the GNU General Public License as
6
- * published by the Free Software Foundation.
7
- *
8
- * This program is distributed in the hope that it will be useful, but
9
- * WITHOUT ANY WARRANTY; without even the implied warranty of
10
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
- * General Public License for more details.
124 */
135 #include <linux/libnvdimm.h>
146 #include <linux/badblocks.h>
7
+#include <linux/suspend.h>
158 #include <linux/export.h>
169 #include <linux/module.h>
1710 #include <linux/blkdev.h>
....@@ -254,7 +247,7 @@
254247 *
255248 * Enforce that uuids can only be changed while the device is disabled
256249 * (driver detached)
257
- * LOCKING: expects device_lock() is held on entry
250
+ * LOCKING: expects nd_device_lock() is held on entry
258251 */
259252 int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
260253 size_t len)
....@@ -355,15 +348,15 @@
355348
356349 static int flush_namespaces(struct device *dev, void *data)
357350 {
358
- device_lock(dev);
359
- device_unlock(dev);
351
+ nd_device_lock(dev);
352
+ nd_device_unlock(dev);
360353 return 0;
361354 }
362355
363356 static int flush_regions_dimms(struct device *dev, void *data)
364357 {
365
- device_lock(dev);
366
- device_unlock(dev);
358
+ nd_device_lock(dev);
359
+ nd_device_unlock(dev);
367360 device_for_each_child(dev, NULL, flush_namespaces);
368361 return 0;
369362 }
....@@ -393,10 +386,153 @@
393386 NULL,
394387 };
395388
396
-struct attribute_group nvdimm_bus_attribute_group = {
389
+static const struct attribute_group nvdimm_bus_attribute_group = {
397390 .attrs = nvdimm_bus_attributes,
398391 };
399
-EXPORT_SYMBOL_GPL(nvdimm_bus_attribute_group);
392
+
393
+static ssize_t capability_show(struct device *dev,
394
+ struct device_attribute *attr, char *buf)
395
+{
396
+ struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
397
+ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
398
+ enum nvdimm_fwa_capability cap;
399
+
400
+ if (!nd_desc->fw_ops)
401
+ return -EOPNOTSUPP;
402
+
403
+ cap = nd_desc->fw_ops->capability(nd_desc);
404
+
405
+ switch (cap) {
406
+ case NVDIMM_FWA_CAP_QUIESCE:
407
+ return sprintf(buf, "quiesce\n");
408
+ case NVDIMM_FWA_CAP_LIVE:
409
+ return sprintf(buf, "live\n");
410
+ default:
411
+ return -EOPNOTSUPP;
412
+ }
413
+}
414
+
415
+static DEVICE_ATTR_RO(capability);
416
+
417
+static ssize_t activate_show(struct device *dev,
418
+ struct device_attribute *attr, char *buf)
419
+{
420
+ struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
421
+ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
422
+ enum nvdimm_fwa_capability cap;
423
+ enum nvdimm_fwa_state state;
424
+
425
+ if (!nd_desc->fw_ops)
426
+ return -EOPNOTSUPP;
427
+
428
+ cap = nd_desc->fw_ops->capability(nd_desc);
429
+ state = nd_desc->fw_ops->activate_state(nd_desc);
430
+
431
+ if (cap < NVDIMM_FWA_CAP_QUIESCE)
432
+ return -EOPNOTSUPP;
433
+
434
+ switch (state) {
435
+ case NVDIMM_FWA_IDLE:
436
+ return sprintf(buf, "idle\n");
437
+ case NVDIMM_FWA_BUSY:
438
+ return sprintf(buf, "busy\n");
439
+ case NVDIMM_FWA_ARMED:
440
+ return sprintf(buf, "armed\n");
441
+ case NVDIMM_FWA_ARM_OVERFLOW:
442
+ return sprintf(buf, "overflow\n");
443
+ default:
444
+ return -ENXIO;
445
+ }
446
+}
447
+
448
+static int exec_firmware_activate(void *data)
449
+{
450
+ struct nvdimm_bus_descriptor *nd_desc = data;
451
+
452
+ return nd_desc->fw_ops->activate(nd_desc);
453
+}
454
+
455
+static ssize_t activate_store(struct device *dev,
456
+ struct device_attribute *attr, const char *buf, size_t len)
457
+{
458
+ struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
459
+ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
460
+ enum nvdimm_fwa_state state;
461
+ bool quiesce;
462
+ ssize_t rc;
463
+
464
+ if (!nd_desc->fw_ops)
465
+ return -EOPNOTSUPP;
466
+
467
+ if (sysfs_streq(buf, "live"))
468
+ quiesce = false;
469
+ else if (sysfs_streq(buf, "quiesce"))
470
+ quiesce = true;
471
+ else
472
+ return -EINVAL;
473
+
474
+ state = nd_desc->fw_ops->activate_state(nd_desc);
475
+
476
+ switch (state) {
477
+ case NVDIMM_FWA_BUSY:
478
+ rc = -EBUSY;
479
+ break;
480
+ case NVDIMM_FWA_ARMED:
481
+ case NVDIMM_FWA_ARM_OVERFLOW:
482
+ if (quiesce)
483
+ rc = hibernate_quiet_exec(exec_firmware_activate, nd_desc);
484
+ else
485
+ rc = nd_desc->fw_ops->activate(nd_desc);
486
+ break;
487
+ case NVDIMM_FWA_IDLE:
488
+ default:
489
+ rc = -ENXIO;
490
+ }
491
+
492
+ if (rc == 0)
493
+ rc = len;
494
+ return rc;
495
+}
496
+
497
+static DEVICE_ATTR_ADMIN_RW(activate);
498
+
499
+static umode_t nvdimm_bus_firmware_visible(struct kobject *kobj, struct attribute *a, int n)
500
+{
501
+ struct device *dev = container_of(kobj, typeof(*dev), kobj);
502
+ struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
503
+ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
504
+ enum nvdimm_fwa_capability cap;
505
+
506
+ /*
507
+ * Both 'activate' and 'capability' disappear when no ops
508
+ * detected, or a negative capability is indicated.
509
+ */
510
+ if (!nd_desc->fw_ops)
511
+ return 0;
512
+
513
+ cap = nd_desc->fw_ops->capability(nd_desc);
514
+ if (cap < NVDIMM_FWA_CAP_QUIESCE)
515
+ return 0;
516
+
517
+ return a->mode;
518
+}
519
+static struct attribute *nvdimm_bus_firmware_attributes[] = {
520
+ &dev_attr_activate.attr,
521
+ &dev_attr_capability.attr,
522
+ NULL,
523
+};
524
+
525
+static const struct attribute_group nvdimm_bus_firmware_attribute_group = {
526
+ .name = "firmware",
527
+ .attrs = nvdimm_bus_firmware_attributes,
528
+ .is_visible = nvdimm_bus_firmware_visible,
529
+};
530
+
531
+const struct attribute_group *nvdimm_bus_attribute_groups[] = {
532
+ &nvdimm_bus_attribute_group,
533
+ &nvdimm_bus_firmware_attribute_group,
534
+ NULL,
535
+};
400536
401537 int nvdimm_bus_add_badrange(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
402538 {
....@@ -463,7 +599,6 @@
463599 nd_region_exit();
464600 nvdimm_exit();
465601 nvdimm_bus_exit();
466
- nd_region_devs_exit();
467602 nvdimm_devs_exit();
468603 }
469604