]> Git Repo - linux.git/commitdiff
Merge tag 'libnvdimm-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm...
authorLinus Torvalds <[email protected]>
Tue, 11 Aug 2020 17:59:19 +0000 (10:59 -0700)
committerLinus Torvalds <[email protected]>
Tue, 11 Aug 2020 17:59:19 +0000 (10:59 -0700)
Pull libnvdimm updayes from Vishal Verma:
 "You'd normally receive this pull request from Dan Williams, but he's
  busy watching a newborn (Congrats Dan!), so I'm watching libnvdimm
  this cycle.

  This adds a new feature in libnvdimm - 'Runtime Firmware Activation',
  and a few small cleanups and fixes in libnvdimm and DAX. I'd
  originally intended to make separate topic-based pull requests - one
  for libnvdimm, and one for DAX, but some of the DAX material fell out
  since it wasn't quite ready.

  Summary:

   - add 'Runtime Firmware Activation' support for NVDIMMs that
     advertise the relevant capability

   - misc libnvdimm and DAX cleanups"

* tag 'libnvdimm-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
  libnvdimm/security: ensure sysfs poll thread woke up and fetch updated attr
  libnvdimm/security: the 'security' attr never show 'overwrite' state
  libnvdimm/security: fix a typo
  ACPI: NFIT: Fix ARS zero-sized allocation
  dax: Fix incorrect argument passed to xas_set_err()
  ACPI: NFIT: Add runtime firmware activate support
  PM, libnvdimm: Add runtime firmware activation support
  libnvdimm: Convert to DEVICE_ATTR_ADMIN_RO()
  drivers/dax: Expand lock scope to cover the use of addresses
  fs/dax: Remove unused size parameter
  dax: print error message by pr_info() in __generic_fsdax_supported()
  driver-core: Introduce DEVICE_ATTR_ADMIN_{RO,RW}
  tools/testing/nvdimm: Emulate firmware activation commands
  tools/testing/nvdimm: Prepare nfit_ctl_test() for ND_CMD_CALL emulation
  tools/testing/nvdimm: Add command debug messages
  tools/testing/nvdimm: Cleanup dimm index passing
  ACPI: NFIT: Define runtime firmware activation commands
  ACPI: NFIT: Move bus_dsm_mask out of generic nvdimm_bus_descriptor
  libnvdimm: Validate command family indices

1  2 
drivers/acpi/nfit/nfit.h
drivers/dax/super.c
drivers/nvdimm/region_devs.c
drivers/nvdimm/security.c
kernel/power/hibernate.c

diff --combined drivers/acpi/nfit/nfit.h
index a303f01233945f04f4e80676f495764c3e06322f,67b7807ed20098a37387fa4625638a60e77b0b17..c674f3df9be7a0a08776a2a551df73191f5cd8ad
@@@ -16,8 -16,9 +16,9 @@@
  /* ACPI 6.1 */
  #define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
  
 -/* http://pmem.io/documents/NVDIMM_DSM_Interface-V1.6.pdf */
 +/* https://pmem.io/documents/NVDIMM_DSM_Interface-V1.6.pdf */
  #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
+ #define UUID_INTEL_BUS "c7d8acd4-2df8-4b82-9f65-a325335af149"
  
  /* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */
  #define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
@@@ -33,7 -34,6 +34,6 @@@
                | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
                | ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED)
  
- #define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV
  #define NVDIMM_CMD_MAX 31
  
  #define NVDIMM_STANDARD_CMDMASK \
@@@ -66,6 -66,13 +66,13 @@@ enum nvdimm_family_cmds 
        NVDIMM_INTEL_QUERY_OVERWRITE = 26,
        NVDIMM_INTEL_SET_MASTER_PASSPHRASE = 27,
        NVDIMM_INTEL_MASTER_SECURE_ERASE = 28,
+       NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO = 29,
+       NVDIMM_INTEL_FW_ACTIVATE_ARM = 30,
+ };
+ enum nvdimm_bus_family_cmds {
+       NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO = 1,
+       NVDIMM_BUS_INTEL_FW_ACTIVATE = 2,
  };
  
  #define NVDIMM_INTEL_SECURITY_CMDMASK \
  | 1 << NVDIMM_INTEL_SET_MASTER_PASSPHRASE \
  | 1 << NVDIMM_INTEL_MASTER_SECURE_ERASE)
  
+ #define NVDIMM_INTEL_FW_ACTIVATE_CMDMASK \
+ (1 << NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO | 1 << NVDIMM_INTEL_FW_ACTIVATE_ARM)
+ #define NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK \
+ (1 << NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO | 1 << NVDIMM_BUS_INTEL_FW_ACTIVATE)
  #define NVDIMM_INTEL_CMDMASK \
  (NVDIMM_STANDARD_CMDMASK | 1 << NVDIMM_INTEL_GET_MODES \
   | 1 << NVDIMM_INTEL_GET_FWINFO | 1 << NVDIMM_INTEL_START_FWUPDATE \
   | 1 << NVDIMM_INTEL_SEND_FWUPDATE | 1 << NVDIMM_INTEL_FINISH_FWUPDATE \
   | 1 << NVDIMM_INTEL_QUERY_FWUPDATE | 1 << NVDIMM_INTEL_SET_THRESHOLD \
   | 1 << NVDIMM_INTEL_INJECT_ERROR | 1 << NVDIMM_INTEL_LATCH_SHUTDOWN \
-  | NVDIMM_INTEL_SECURITY_CMDMASK)
+  | NVDIMM_INTEL_SECURITY_CMDMASK | NVDIMM_INTEL_FW_ACTIVATE_CMDMASK)
+ #define NVDIMM_INTEL_DENY_CMDMASK \
+ (NVDIMM_INTEL_SECURITY_CMDMASK | NVDIMM_INTEL_FW_ACTIVATE_CMDMASK)
  
  enum nfit_uuids {
        /* for simplicity alias the uuid index with the family id */
        NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
        NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT,
        NFIT_DEV_DIMM_N_HYPERV = NVDIMM_FAMILY_HYPERV,
+       /*
+        * to_nfit_bus_uuid() expects to translate bus uuid family ids
+        * to a UUID index using NVDIMM_FAMILY_MAX as an offset
+        */
+       NFIT_BUS_INTEL = NVDIMM_FAMILY_MAX + NVDIMM_BUS_FAMILY_INTEL,
        NFIT_SPA_VOLATILE,
        NFIT_SPA_PM,
        NFIT_SPA_DCR,
@@@ -199,6 -220,9 +220,9 @@@ struct nfit_mem 
        struct list_head list;
        struct acpi_device *adev;
        struct acpi_nfit_desc *acpi_desc;
+       enum nvdimm_fwa_state fwa_state;
+       enum nvdimm_fwa_result fwa_result;
+       int fwa_count;
        char id[NFIT_DIMM_ID_LEN+1];
        struct resource *flush_wpq;
        unsigned long dsm_mask;
@@@ -238,11 -262,17 +262,17 @@@ struct acpi_nfit_desc 
        unsigned long scrub_flags;
        unsigned long dimm_cmd_force_en;
        unsigned long bus_cmd_force_en;
-       unsigned long bus_nfit_cmd_force_en;
+       unsigned long bus_dsm_mask;
+       unsigned long family_dsm_mask[NVDIMM_BUS_FAMILY_MAX + 1];
        unsigned int platform_cap;
        unsigned int scrub_tmo;
        int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
                        void *iobuf, u64 len, int rw);
+       enum nvdimm_fwa_state fwa_state;
+       enum nvdimm_fwa_capability fwa_cap;
+       int fwa_count;
+       bool fwa_noidle;
+       bool fwa_nosuspend;
  };
  
  enum scrub_mode {
@@@ -345,4 -375,6 +375,6 @@@ void __acpi_nvdimm_notify(struct devic
  int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
                unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc);
  void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
+ bool intel_fwa_supported(struct nvdimm_bus *nvdimm_bus);
+ extern struct device_attribute dev_attr_firmware_activate_noidle;
  #endif /* __NFIT_H__ */
diff --combined drivers/dax/super.c
index f508285263319b8d34dd6942cadbd21b4a2966f4,ec62752215e48d63f8d4db10c238ddfd5f5e840a..c82cbcb6420289f8cf529394ef1138158d32fb4c
@@@ -59,7 -59,7 +59,7 @@@ EXPORT_SYMBOL(bdev_dax_pgoff)
  #if IS_ENABLED(CONFIG_FS_DAX)
  struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev)
  {
 -      if (!blk_queue_dax(bdev->bd_queue))
 +      if (!blk_queue_dax(bdev->bd_disk->queue))
                return NULL;
        return dax_get_by_host(bdev->bd_disk->disk_name);
  }
@@@ -80,14 -80,14 +80,14 @@@ bool __generic_fsdax_supported(struct d
        int err, id;
  
        if (blocksize != PAGE_SIZE) {
-               pr_debug("%s: error: unsupported blocksize for dax\n",
+               pr_info("%s: error: unsupported blocksize for dax\n",
                                bdevname(bdev, buf));
                return false;
        }
  
        err = bdev_dax_pgoff(bdev, start, PAGE_SIZE, &pgoff);
        if (err) {
-               pr_debug("%s: error: unaligned partition for dax\n",
+               pr_info("%s: error: unaligned partition for dax\n",
                                bdevname(bdev, buf));
                return false;
        }
@@@ -95,7 -95,7 +95,7 @@@
        last_page = PFN_DOWN((start + sectors - 1) * 512) * PAGE_SIZE / 512;
        err = bdev_dax_pgoff(bdev, last_page, PAGE_SIZE, &pgoff_end);
        if (err) {
-               pr_debug("%s: error: unaligned partition for dax\n",
+               pr_info("%s: error: unaligned partition for dax\n",
                                bdevname(bdev, buf));
                return false;
        }
        id = dax_read_lock();
        len = dax_direct_access(dax_dev, pgoff, 1, &kaddr, &pfn);
        len2 = dax_direct_access(dax_dev, pgoff_end, 1, &end_kaddr, &end_pfn);
-       dax_read_unlock(id);
  
        if (len < 1 || len2 < 1) {
-               pr_debug("%s: error: dax access failed (%ld)\n",
+               pr_info("%s: error: dax access failed (%ld)\n",
                                bdevname(bdev, buf), len < 1 ? len : len2);
+               dax_read_unlock(id);
                return false;
        }
  
                put_dev_pagemap(end_pgmap);
  
        }
+       dax_read_unlock(id);
  
        if (!dax_enabled) {
-               pr_debug("%s: error: dax support not enabled\n",
+               pr_info("%s: error: dax support not enabled\n",
                                bdevname(bdev, buf));
                return false;
        }
index c3237c2b03a6bffe91eeab8fa4f4613d6cfb33f4,20ff30c2ab935e854b1b36cb9d82263d4bf596fd..ef23119db574663822c64c4cad32be0fa377fb8c
@@@ -605,7 -605,7 +605,7 @@@ static ssize_t resource_show(struct dev
  
        return sprintf(buf, "%#llx\n", nd_region->ndr_start);
  }
- static DEVICE_ATTR(resource, 0400, resource_show, NULL);
+ static DEVICE_ATTR_ADMIN_RO(resource);
  
  static ssize_t persistence_domain_show(struct device *dev,
                struct device_attribute *attr, char *buf)
@@@ -1206,13 -1206,13 +1206,13 @@@ int generic_nvdimm_flush(struct nd_regi
        idx = this_cpu_add_return(flush_idx, hash_32(current->pid + idx, 8));
  
        /*
 -       * The first wmb() is needed to 'sfence' all previous writes
 -       * such that they are architecturally visible for the platform
 -       * buffer flush.  Note that we've already arranged for pmem
 +       * The pmem_wmb() is needed to 'sfence' all
 +       * previous writes such that they are architecturally visible for
 +       * the platform buffer flush. Note that we've already arranged for pmem
         * writes to avoid the cache via memcpy_flushcache().  The final
         * wmb() ensures ordering for the NVDIMM flush write.
         */
 -      wmb();
 +      pmem_wmb();
        for (i = 0; i < nd_region->ndr_mappings; i++)
                if (ndrd_get_flush_wpq(ndrd, i, 0))
                        writeq(1, ndrd_get_flush_wpq(ndrd, i, idx));
index 4cef69bd3c1bd8638c8181ca632d158712a091c0,35d265014e1ec96c193bb302f9c94437e0c63a6e..4b80150e4afa742533400b7e39f9aa8cd5ac88e7
@@@ -95,7 -95,7 +95,7 @@@ static struct key *nvdimm_lookup_user_k
        struct encrypted_key_payload *epayload;
        struct device *dev = &nvdimm->dev;
  
 -      keyref = lookup_user_key(id, 0, 0);
 +      keyref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
        if (IS_ERR(keyref))
                return NULL;
  
@@@ -450,14 -450,19 +450,19 @@@ void __nvdimm_security_overwrite_query(
        else
                dev_dbg(&nvdimm->dev, "overwrite completed\n");
  
-       if (nvdimm->sec.overwrite_state)
-               sysfs_notify_dirent(nvdimm->sec.overwrite_state);
+       /*
+        * Mark the overwrite work done and update dimm security flags,
+        * then send a sysfs event notification to wake up userspace
+        * poll threads to picked up the changed state.
+        */
        nvdimm->sec.overwrite_tmo = 0;
        clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
        clear_bit(NDD_WORK_PENDING, &nvdimm->flags);
-       put_device(&nvdimm->dev);
        nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
-       nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
+       nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
+       if (nvdimm->sec.overwrite_state)
+               sysfs_notify_dirent(nvdimm->sec.overwrite_state);
+       put_device(&nvdimm->dev);
  }
  
  void nvdimm_security_overwrite_query(struct work_struct *work)
diff --combined kernel/power/hibernate.c
index 5714f51ba9f8090e1033736164fd36f6b18625c8,e6fab3f09c98ed1f7d320f0c4b1f66912534bcf6..f33769f97aca59c960d188e24a0a577eaf9c5499
@@@ -795,6 -795,103 +795,103 @@@ int hibernate(void
        return error;
  }
  
+ /**
+  * hibernate_quiet_exec - Execute a function with all devices frozen.
+  * @func: Function to execute.
+  * @data: Data pointer to pass to @func.
+  *
+  * Return the @func return value or an error code if it cannot be executed.
+  */
+ int hibernate_quiet_exec(int (*func)(void *data), void *data)
+ {
+       int error, nr_calls = 0;
+       lock_system_sleep();
+       if (!hibernate_acquire()) {
+               error = -EBUSY;
+               goto unlock;
+       }
+       pm_prepare_console();
+       error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
+       if (error) {
+               nr_calls--;
+               goto exit;
+       }
+       error = freeze_processes();
+       if (error)
+               goto exit;
+       lock_device_hotplug();
+       pm_suspend_clear_flags();
+       error = platform_begin(true);
+       if (error)
+               goto thaw;
+       error = freeze_kernel_threads();
+       if (error)
+               goto thaw;
+       error = dpm_prepare(PMSG_FREEZE);
+       if (error)
+               goto dpm_complete;
+       suspend_console();
+       error = dpm_suspend(PMSG_FREEZE);
+       if (error)
+               goto dpm_resume;
+       error = dpm_suspend_end(PMSG_FREEZE);
+       if (error)
+               goto dpm_resume;
+       error = platform_pre_snapshot(true);
+       if (error)
+               goto skip;
+       error = func(data);
+ skip:
+       platform_finish(true);
+       dpm_resume_start(PMSG_THAW);
+ dpm_resume:
+       dpm_resume(PMSG_THAW);
+       resume_console();
+ dpm_complete:
+       dpm_complete(PMSG_THAW);
+       thaw_kernel_threads();
+ thaw:
+       platform_end(true);
+       unlock_device_hotplug();
+       thaw_processes();
+ exit:
+       __pm_notifier_call_chain(PM_POST_HIBERNATION, nr_calls, NULL);
+       pm_restore_console();
+       hibernate_release();
+ unlock:
+       unlock_system_sleep();
+       return error;
+ }
+ EXPORT_SYMBOL_GPL(hibernate_quiet_exec);
  
  /**
   * software_resume - Resume from a saved hibernation image.
@@@ -1062,7 -1159,7 +1159,7 @@@ power_attr(disk)
  static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
                           char *buf)
  {
 -      return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
 +      return sprintf(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
                       MINOR(swsusp_resume_device));
  }
  
@@@ -1162,7 -1259,7 +1259,7 @@@ static ssize_t reserved_size_store(stru
  
  power_attr(reserved_size);
  
 -static struct attribute * g[] = {
 +static struct attribute *g[] = {
        &disk_attr.attr,
        &resume_offset_attr.attr,
        &resume_attr.attr,
@@@ -1190,7 -1287,7 +1287,7 @@@ static int __init resume_setup(char *st
        if (noresume)
                return 1;
  
 -      strncpy( resume_file, str, 255 );
 +      strncpy(resume_file, str, 255);
        return 1;
  }
  
This page took 0.099675 seconds and 4 git commands to generate.