]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge branch 'for-5.1/nfit/ars' into libnvdimm-for-next
authorDan Williams <dan.j.williams@intel.com>
Mon, 11 Mar 2019 19:37:55 +0000 (12:37 -0700)
committerDan Williams <dan.j.williams@intel.com>
Mon, 11 Mar 2019 19:37:55 +0000 (12:37 -0700)
Merge several updates to the ARS implementation. Highlights include:

* Support retrieval of short-ARS results if the ARS state is "requires
  continuation", and even if the "no_init_ars" module parameter is
  specified.
* Allow busy-polling of the kernel ARS state by allowing root to reset
  the exponential back-off timer.
* Filter potentially stale ARS results by tracking query-ARS relative to
  the previous start-ARS.

1  2 
MAINTAINERS
drivers/acpi/nfit/core.c
drivers/acpi/nfit/nfit.h

diff --combined MAINTAINERS
index d20cf119ec1dfcf6362d16012e084ae2854d0311,9919840d54cde80896e5f6f18bc03a0b9b8f8ffc..e870684b058df51a09fbf2741c751feecc7360a9
@@@ -2848,6 -2848,9 +2848,9 @@@ F:      include/uapi/linux/if_bonding.
  BPF (Safe dynamic programs and tools)
  M:    Alexei Starovoitov <ast@kernel.org>
  M:    Daniel Borkmann <daniel@iogearbox.net>
+ R:    Martin KaFai Lau <kafai@fb.com>
+ R:    Song Liu <songliubraving@fb.com>
+ R:    Yonghong Song <yhs@fb.com>
  L:    netdev@vger.kernel.org
  L:    linux-kernel@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
@@@ -2873,6 -2876,8 +2876,8 @@@ F:      samples/bpf
  F:    tools/bpf/
  F:    tools/lib/bpf/
  F:    tools/testing/selftests/bpf/
+ K:    bpf
+ N:    bpf
  
  BPF JIT for ARM
  M:    Shubham Bansal <illusionist.neo@gmail.com>
@@@ -4536,11 -4541,10 +4541,11 @@@ S:   Maintaine
  F:    drivers/i2c/busses/i2c-diolan-u2c.c
  
  FILESYSTEM DIRECT ACCESS (DAX)
 -M:    Matthew Wilcox <willy@infradead.org>
 -M:    Ross Zwisler <zwisler@kernel.org>
 -M:    Jan Kara <jack@suse.cz>
 +M:    Dan Williams <dan.j.williams@intel.com>
 +R:    Matthew Wilcox <willy@infradead.org>
 +R:    Jan Kara <jack@suse.cz>
  L:    linux-fsdevel@vger.kernel.org
 +L:    linux-nvdimm@lists.01.org
  S:    Supported
  F:    fs/dax.c
  F:    include/linux/dax.h
@@@ -4548,9 -4552,9 +4553,9 @@@ F:      include/trace/events/fs_dax.
  
  DEVICE DIRECT ACCESS (DAX)
  M:    Dan Williams <dan.j.williams@intel.com>
 -M:    Dave Jiang <dave.jiang@intel.com>
 -M:    Ross Zwisler <zwisler@kernel.org>
  M:    Vishal Verma <vishal.l.verma@intel.com>
 +M:    Keith Busch <keith.busch@intel.com>
 +M:    Dave Jiang <dave.jiang@intel.com>
  L:    linux-nvdimm@lists.01.org
  S:    Supported
  F:    drivers/dax/
@@@ -5182,7 -5186,7 +5187,7 @@@ DRM DRIVERS FOR XE
  M:    Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
  T:    git git://anongit.freedesktop.org/drm/drm-misc
  L:    dri-devel@lists.freedesktop.org
- L:    xen-devel@lists.xen.org
+ L:    xen-devel@lists.xenproject.org (moderated for non-subscribers)
  S:    Supported
  F:    drivers/gpu/drm/xen/
  F:    Documentation/gpu/xen-front.rst
@@@ -8644,6 -8648,7 +8649,6 @@@ S:      Maintaine
  F:    tools/lib/lockdep/
  
  LIBNVDIMM BLK: MMIO-APERTURE DRIVER
 -M:    Ross Zwisler <zwisler@kernel.org>
  M:    Dan Williams <dan.j.williams@intel.com>
  M:    Vishal Verma <vishal.l.verma@intel.com>
  M:    Dave Jiang <dave.jiang@intel.com>
@@@ -8656,6 -8661,7 +8661,6 @@@ F:      drivers/nvdimm/region_devs.
  LIBNVDIMM BTT: BLOCK TRANSLATION TABLE
  M:    Vishal Verma <vishal.l.verma@intel.com>
  M:    Dan Williams <dan.j.williams@intel.com>
 -M:    Ross Zwisler <zwisler@kernel.org>
  M:    Dave Jiang <dave.jiang@intel.com>
  L:    linux-nvdimm@lists.01.org
  Q:    https://patchwork.kernel.org/project/linux-nvdimm/list/
@@@ -8663,6 -8669,7 +8668,6 @@@ S:      Supporte
  F:    drivers/nvdimm/btt*
  
  LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER
 -M:    Ross Zwisler <zwisler@kernel.org>
  M:    Dan Williams <dan.j.williams@intel.com>
  M:    Vishal Verma <vishal.l.verma@intel.com>
  M:    Dave Jiang <dave.jiang@intel.com>
@@@ -8681,10 -8688,9 +8686,10 @@@ F:    Documentation/devicetree/bindings/pm
  
  LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
  M:    Dan Williams <dan.j.williams@intel.com>
 -M:    Ross Zwisler <zwisler@kernel.org>
  M:    Vishal Verma <vishal.l.verma@intel.com>
  M:    Dave Jiang <dave.jiang@intel.com>
 +M:    Keith Busch <keith.busch@intel.com>
 +M:    Ira Weiny <ira.weiny@intel.com>
  L:    linux-nvdimm@lists.01.org
  Q:    https://patchwork.kernel.org/project/linux-nvdimm/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
@@@ -11306,10 -11312,12 +11311,12 @@@ F:        include/dt-bindings
  
  OPENCORES I2C BUS DRIVER
  M:    Peter Korsgaard <peter@korsgaard.com>
+ M:    Andrew Lunn <andrew@lunn.ch>
  L:    linux-i2c@vger.kernel.org
  S:    Maintained
  F:    Documentation/i2c/busses/i2c-ocores
  F:    drivers/i2c/busses/i2c-ocores.c
+ F:    include/linux/platform_data/i2c-ocores.h
  
  OPENRISC ARCHITECTURE
  M:    Jonas Bonn <jonas@southpole.se>
@@@ -12867,6 -12875,13 +12874,13 @@@ F: Documentation/devicetree/bindings/ne
  F:    drivers/net/dsa/realtek-smi*
  F:    drivers/net/dsa/rtl83*
  
+ REDPINE WIRELESS DRIVER
+ M:    Amitkumar Karwar <amitkarwar@gmail.com>
+ M:    Siva Rebbagondla <siva8118@gmail.com>
+ L:    linux-wireless@vger.kernel.org
+ S:    Maintained
+ F:    drivers/net/wireless/rsi/
  REGISTER MAP ABSTRACTION
  M:    Mark Brown <broonie@kernel.org>
  L:    linux-kernel@vger.kernel.org
@@@ -13695,6 -13710,15 +13709,15 @@@ L: netdev@vger.kernel.or
  S:    Supported
  F:    drivers/net/ethernet/sfc/
  
+ SFF/SFP/SFP+ MODULE SUPPORT
+ M:    Russell King <linux@armlinux.org.uk>
+ L:    netdev@vger.kernel.org
+ S:    Maintained
+ F:    drivers/net/phy/phylink.c
+ F:    drivers/net/phy/sfp*
+ F:    include/linux/phylink.h
+ F:    include/linux/sfp.h
  SGI GRU DRIVER
  M:    Dimitri Sivanich <sivanich@sgi.com>
  S:    Maintained
@@@ -16640,6 -16664,15 +16663,15 @@@ S: Maintaine
  F:    drivers/platform/x86/
  F:    drivers/platform/olpc/
  
+ X86 PLATFORM DRIVERS - ARCH
+ R:    Darren Hart <dvhart@infradead.org>
+ R:    Andy Shevchenko <andy@infradead.org>
+ L:    platform-driver-x86@vger.kernel.org
+ L:    x86@kernel.org
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
+ S:    Maintained
+ F:    arch/x86/platform
  X86 VDSO
  M:    Andy Lutomirski <luto@kernel.org>
  L:    linux-kernel@vger.kernel.org
@@@ -16672,6 -16705,24 +16704,24 @@@ T: git git://linuxtv.org/media_tree.gi
  S:    Maintained
  F:    drivers/media/tuners/tuner-xc2028.*
  
+ XDP (eXpress Data Path)
+ M:    Alexei Starovoitov <ast@kernel.org>
+ M:    Daniel Borkmann <daniel@iogearbox.net>
+ M:    David S. Miller <davem@davemloft.net>
+ M:    Jakub Kicinski <jakub.kicinski@netronome.com>
+ M:    Jesper Dangaard Brouer <hawk@kernel.org>
+ M:    John Fastabend <john.fastabend@gmail.com>
+ L:    netdev@vger.kernel.org
+ L:    xdp-newbies@vger.kernel.org
+ S:    Supported
+ F:    net/core/xdp.c
+ F:    include/net/xdp.h
+ F:    kernel/bpf/devmap.c
+ F:    kernel/bpf/cpumap.c
+ F:    include/trace/events/xdp.h
+ K:    xdp
+ N:    xdp
  XDP SOCKETS (AF_XDP)
  M:    Björn Töpel <bjorn.topel@intel.com>
  M:    Magnus Karlsson <magnus.karlsson@intel.com>
diff --combined drivers/acpi/nfit/core.c
index c7afb1f223f75853b7319ef4cae25c701e814e4a,5c9eb8d700d339ed9695662df45f45ce7eb2fc60..df8979008dd4ec6496c1e5600ec856a300dec08f
@@@ -55,10 -55,6 +55,10 @@@ static bool no_init_ars
  module_param(no_init_ars, bool, 0644);
  MODULE_PARM_DESC(no_init_ars, "Skip ARS run at nfit init time");
  
 +static bool force_labels;
 +module_param(force_labels, bool, 0444);
 +MODULE_PARM_DESC(force_labels, "Opt-in to labels despite missing methods");
 +
  LIST_HEAD(acpi_descs);
  DEFINE_MUTEX(acpi_desc_lock);
  
@@@ -419,7 -415,7 +419,7 @@@ static int cmd_to_func(struct nfit_mem 
        if (call_pkg) {
                int i;
  
 -              if (nfit_mem->family != call_pkg->nd_family)
 +              if (nfit_mem && nfit_mem->family != call_pkg->nd_family)
                        return -ENOTTY;
  
                for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++)
                return call_pkg->nd_command;
        }
  
 +      /* In the !call_pkg case, bus commands == bus functions */
 +      if (!nfit_mem)
 +              return cmd;
 +
        /* Linux ND commands == NVDIMM_FAMILY_INTEL function numbers */
        if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
                return cmd;
@@@ -462,18 -454,17 +462,18 @@@ int acpi_nfit_ctl(struct nvdimm_bus_des
        if (cmd_rc)
                *cmd_rc = -EINVAL;
  
 +      if (cmd == ND_CMD_CALL)
 +              call_pkg = buf;
 +      func = cmd_to_func(nfit_mem, cmd, call_pkg);
 +      if (func < 0)
 +              return func;
 +
        if (nvdimm) {
                struct acpi_device *adev = nfit_mem->adev;
  
                if (!adev)
                        return -ENOTTY;
  
 -              if (cmd == ND_CMD_CALL)
 -                      call_pkg = buf;
 -              func = cmd_to_func(nfit_mem, cmd, call_pkg);
 -              if (func < 0)
 -                      return func;
                dimm_name = nvdimm_name(nvdimm);
                cmd_name = nvdimm_cmd_name(cmd);
                cmd_mask = nvdimm_cmd_mask(nvdimm);
        } else {
                struct acpi_device *adev = to_acpi_dev(acpi_desc);
  
 -              func = cmd;
                cmd_name = nvdimm_bus_cmd_name(cmd);
                cmd_mask = nd_desc->cmd_mask;
 -              dsm_mask = cmd_mask;
 -              if (cmd == ND_CMD_CALL)
 -                      dsm_mask = nd_desc->bus_dsm_mask;
 +              dsm_mask = nd_desc->bus_dsm_mask;
                desc = nd_cmd_bus_desc(cmd);
                guid = to_nfit_uuid(NFIT_DEV_BUS);
                handle = adev->handle;
                return -EINVAL;
        }
  
 +      if (out_obj->type != ACPI_TYPE_BUFFER) {
 +              dev_dbg(dev, "%s unexpected output object type cmd: %s type: %d\n",
 +                              dimm_name, cmd_name, out_obj->type);
 +              rc = -EINVAL;
 +              goto out;
 +      }
 +
        if (call_pkg) {
                call_pkg->nd_fw_size = out_obj->buffer.length;
                memcpy(call_pkg->nd_payload + call_pkg->nd_size_in,
                return 0;
        }
  
 -      if (out_obj->package.type != ACPI_TYPE_BUFFER) {
 -              dev_dbg(dev, "%s unexpected output object type cmd: %s type: %d\n",
 -                              dimm_name, cmd_name, out_obj->type);
 -              rc = -EINVAL;
 -              goto out;
 -      }
 -
        dev_dbg(dev, "%s cmd: %s output length: %d\n", dimm_name,
                        cmd_name, out_obj->buffer.length);
        print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, 4,
@@@ -1323,19 -1317,30 +1323,30 @@@ static ssize_t scrub_show(struct devic
                struct device_attribute *attr, char *buf)
  {
        struct nvdimm_bus_descriptor *nd_desc;
+       struct acpi_nfit_desc *acpi_desc;
        ssize_t rc = -ENXIO;
+       bool busy;
  
        device_lock(dev);
        nd_desc = dev_get_drvdata(dev);
-       if (nd_desc) {
-               struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+       if (!nd_desc) {
+               device_unlock(dev);
+               return rc;
+       }
+       acpi_desc = to_acpi_desc(nd_desc);
  
-               mutex_lock(&acpi_desc->init_mutex);
-               rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
-                               acpi_desc->scrub_busy
-                               && !acpi_desc->cancel ? "+\n" : "\n");
-               mutex_unlock(&acpi_desc->init_mutex);
+       mutex_lock(&acpi_desc->init_mutex);
+       busy = test_bit(ARS_BUSY, &acpi_desc->scrub_flags)
+               && !test_bit(ARS_CANCEL, &acpi_desc->scrub_flags);
+       rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, busy ? "+\n" : "\n");
+       /* Allow an admin to poll the busy state at a higher rate */
+       if (busy && capable(CAP_SYS_RAWIO) && !test_and_set_bit(ARS_POLL,
+                               &acpi_desc->scrub_flags)) {
+               acpi_desc->scrub_tmo = 1;
+               mod_delayed_work(nfit_wq, &acpi_desc->dwork, HZ);
        }
+       mutex_unlock(&acpi_desc->init_mutex);
        device_unlock(dev);
        return rc;
  }
@@@ -1765,14 -1770,14 +1776,14 @@@ static bool acpi_nvdimm_has_method(stru
  
  __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem)
  {
 +      struct device *dev = &nfit_mem->adev->dev;
        struct nd_intel_smart smart = { 0 };
        union acpi_object in_buf = {
 -              .type = ACPI_TYPE_BUFFER,
 -              .buffer.pointer = (char *) &smart,
 -              .buffer.length = sizeof(smart),
 +              .buffer.type = ACPI_TYPE_BUFFER,
 +              .buffer.length = 0,
        };
        union acpi_object in_obj = {
 -              .type = ACPI_TYPE_PACKAGE,
 +              .package.type = ACPI_TYPE_PACKAGE,
                .package.count = 1,
                .package.elements = &in_buf,
        };
                return;
  
        out_obj = acpi_evaluate_dsm(handle, guid, revid, func, &in_obj);
 -      if (!out_obj)
 +      if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER
 +                      || out_obj->buffer.length < sizeof(smart)) {
 +              dev_dbg(dev->parent, "%s: failed to retrieve initial health\n",
 +                              dev_name(dev));
 +              ACPI_FREE(out_obj);
                return;
 +      }
 +      memcpy(&smart, out_obj->buffer.pointer, sizeof(smart));
 +      ACPI_FREE(out_obj);
  
        if (smart.flags & ND_INTEL_SMART_SHUTDOWN_VALID) {
                if (smart.shutdown_state)
                set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags);
                nfit_mem->dirty_shutdown = smart.shutdown_count;
        }
 -      ACPI_FREE(out_obj);
  }
  
  static void populate_shutdown_status(struct nfit_mem *nfit_mem)
@@@ -1873,17 -1872,9 +1884,17 @@@ static int acpi_nfit_add_dimm(struct ac
        dev_set_drvdata(&adev_dimm->dev, nfit_mem);
  
        /*
 -       * Until standardization materializes we need to consider 4
 -       * different command sets.  Note, that checking for function0 (bit0)
 -       * tells us if any commands are reachable through this GUID.
 +       * There are 4 "legacy" NVDIMM command sets
 +       * (NVDIMM_FAMILY_{INTEL,MSFT,HPE1,HPE2}) that were created before
 +       * an EFI working group was established to constrain this
 +       * proliferation. The nfit driver probes for the supported command
 +       * set by GUID. Note, if you're a platform developer looking to add
 +       * a new command set to this probe, consider using an existing set,
 +       * or otherwise seek approval to publish the command set at
 +       * http://www.uefi.org/RFIC_LIST.
 +       *
 +       * Note, that checking for function0 (bit0) tells us if any commands
 +       * are reachable through this GUID.
         */
        for (i = 0; i <= NVDIMM_FAMILY_MAX; i++)
                if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
                        dsm_mask &= ~(1 << 8);
        } else if (nfit_mem->family == NVDIMM_FAMILY_MSFT) {
                dsm_mask = 0xffffffff;
 +      } else if (nfit_mem->family == NVDIMM_FAMILY_HYPERV) {
 +              dsm_mask = 0x1f;
        } else {
                dev_dbg(dev, "unknown dimm command family\n");
                nfit_mem->family = -1;
                | 1 << ND_CMD_SET_CONFIG_DATA;
        if (family == NVDIMM_FAMILY_INTEL
                        && (dsm_mask & label_mask) == label_mask)
 -              return 0;
 +              /* skip _LS{I,R,W} enabling */;
 +      else {
 +              if (acpi_nvdimm_has_method(adev_dimm, "_LSI")
 +                              && acpi_nvdimm_has_method(adev_dimm, "_LSR")) {
 +                      dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev));
 +                      set_bit(NFIT_MEM_LSR, &nfit_mem->flags);
 +              }
  
 -      if (acpi_nvdimm_has_method(adev_dimm, "_LSI")
 -                      && acpi_nvdimm_has_method(adev_dimm, "_LSR")) {
 -              dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev));
 -              set_bit(NFIT_MEM_LSR, &nfit_mem->flags);
 -      }
 +              if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)
 +                              && acpi_nvdimm_has_method(adev_dimm, "_LSW")) {
 +                      dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev));
 +                      set_bit(NFIT_MEM_LSW, &nfit_mem->flags);
 +              }
  
 -      if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)
 -                      && acpi_nvdimm_has_method(adev_dimm, "_LSW")) {
 -              dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev));
 -              set_bit(NFIT_MEM_LSW, &nfit_mem->flags);
 +              /*
 +               * Quirk read-only label configurations to preserve
 +               * access to label-less namespaces by default.
 +               */
 +              if (!test_bit(NFIT_MEM_LSW, &nfit_mem->flags)
 +                              && !force_labels) {
 +                      dev_dbg(dev, "%s: No _LSW, disable labels\n",
 +                                      dev_name(&adev_dimm->dev));
 +                      clear_bit(NFIT_MEM_LSR, &nfit_mem->flags);
 +              } else
 +                      dev_dbg(dev, "%s: Force enable labels\n",
 +                                      dev_name(&adev_dimm->dev));
        }
  
        populate_shutdown_status(nfit_mem);
@@@ -2063,10 -2038,6 +2074,10 @@@ static int acpi_nfit_register_dimms(str
                        cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK;
                }
  
 +              /* Quirk to ignore LOCAL for labels on HYPERV DIMMs */
 +              if (nfit_mem->family == NVDIMM_FAMILY_HYPERV)
 +                      set_bit(NDD_NOBLK, &flags);
 +
                if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) {
                        set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
                        set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
                if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0)
                        continue;
  
 -              dev_info(acpi_desc->dev, "%s flags:%s%s%s%s%s\n",
 +              dev_err(acpi_desc->dev, "Error found in NVDIMM %s flags:%s%s%s%s%s\n",
                                nvdimm_name(nvdimm),
                  mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
                  mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
@@@ -2681,7 -2652,10 +2692,10 @@@ static int ars_start(struct acpi_nfit_d
  
        if (rc < 0)
                return rc;
-       return cmd_rc;
+       if (cmd_rc < 0)
+               return cmd_rc;
+       set_bit(ARS_VALID, &acpi_desc->scrub_flags);
+       return 0;
  }
  
  static int ars_continue(struct acpi_nfit_desc *acpi_desc)
        struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
        struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status;
  
-       memset(&ars_start, 0, sizeof(ars_start));
-       ars_start.address = ars_status->restart_address;
-       ars_start.length = ars_status->restart_length;
-       ars_start.type = ars_status->type;
-       ars_start.flags = acpi_desc->ars_start_flags;
+       ars_start = (struct nd_cmd_ars_start) {
+               .address = ars_status->restart_address,
+               .length = ars_status->restart_length,
+               .type = ars_status->type,
+       };
        rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start,
                        sizeof(ars_start), &cmd_rc);
        if (rc < 0)
@@@ -2774,6 -2748,17 +2788,17 @@@ static int ars_status_process_records(s
         */
        if (ars_status->out_length < 44)
                return 0;
+       /*
+        * Ignore potentially stale results that are only refreshed
+        * after a start-ARS event.
+        */
+       if (!test_and_clear_bit(ARS_VALID, &acpi_desc->scrub_flags)) {
+               dev_dbg(acpi_desc->dev, "skip %d stale records\n",
+                               ars_status->num_records);
+               return 0;
+       }
        for (i = 0; i < ars_status->num_records; i++) {
                /* only process full records */
                if (ars_status->out_length
@@@ -3044,14 -3029,16 +3069,16 @@@ static int ars_register(struct acpi_nfi
  {
        int rc;
  
-       if (no_init_ars || test_bit(ARS_FAILED, &nfit_spa->ars_state))
+       if (test_bit(ARS_FAILED, &nfit_spa->ars_state))
                return acpi_nfit_register_region(acpi_desc, nfit_spa);
  
        set_bit(ARS_REQ_SHORT, &nfit_spa->ars_state);
-       set_bit(ARS_REQ_LONG, &nfit_spa->ars_state);
+       if (!no_init_ars)
+               set_bit(ARS_REQ_LONG, &nfit_spa->ars_state);
  
        switch (acpi_nfit_query_poison(acpi_desc)) {
        case 0:
+       case -ENOSPC:
        case -EAGAIN:
                rc = ars_start(acpi_desc, nfit_spa, ARS_REQ_SHORT);
                /* shouldn't happen, try again later */
                break;
        case -EBUSY:
        case -ENOMEM:
-       case -ENOSPC:
                /*
                 * BIOS was using ARS, wait for it to complete (or
                 * resources to become available) and then perform our
@@@ -3111,7 -3097,7 +3137,7 @@@ static unsigned int __acpi_nfit_scrub(s
  
        lockdep_assert_held(&acpi_desc->init_mutex);
  
-       if (acpi_desc->cancel)
+       if (test_bit(ARS_CANCEL, &acpi_desc->scrub_flags))
                return 0;
  
        if (query_rc == -EBUSY) {
@@@ -3185,7 -3171,7 +3211,7 @@@ static void __sched_ars(struct acpi_nfi
  {
        lockdep_assert_held(&acpi_desc->init_mutex);
  
-       acpi_desc->scrub_busy = 1;
+       set_bit(ARS_BUSY, &acpi_desc->scrub_flags);
        /* note this should only be set from within the workqueue */
        if (tmo)
                acpi_desc->scrub_tmo = tmo;
@@@ -3201,7 -3187,7 +3227,7 @@@ static void notify_ars_done(struct acpi
  {
        lockdep_assert_held(&acpi_desc->init_mutex);
  
-       acpi_desc->scrub_busy = 0;
+       clear_bit(ARS_BUSY, &acpi_desc->scrub_flags);
        acpi_desc->scrub_count++;
        if (acpi_desc->scrub_count_state)
                sysfs_notify_dirent(acpi_desc->scrub_count_state);
@@@ -3222,6 -3208,7 +3248,7 @@@ static void acpi_nfit_scrub(struct work
        else
                notify_ars_done(acpi_desc);
        memset(acpi_desc->ars_status, 0, acpi_desc->max_ars);
+       clear_bit(ARS_POLL, &acpi_desc->scrub_flags);
        mutex_unlock(&acpi_desc->init_mutex);
  }
  
@@@ -3256,6 -3243,7 +3283,7 @@@ static int acpi_nfit_register_regions(s
        struct nfit_spa *nfit_spa;
        int rc;
  
+       set_bit(ARS_VALID, &acpi_desc->scrub_flags);
        list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
                switch (nfit_spa_type(nfit_spa->spa)) {
                case NFIT_SPA_VOLATILE:
@@@ -3490,7 -3478,7 +3518,7 @@@ int acpi_nfit_ars_rescan(struct acpi_nf
        struct nfit_spa *nfit_spa;
  
        mutex_lock(&acpi_desc->init_mutex);
-       if (acpi_desc->cancel) {
+       if (test_bit(ARS_CANCEL, &acpi_desc->scrub_flags)) {
                mutex_unlock(&acpi_desc->init_mutex);
                return 0;
        }
@@@ -3569,7 -3557,7 +3597,7 @@@ void acpi_nfit_shutdown(void *data
        mutex_unlock(&acpi_desc_lock);
  
        mutex_lock(&acpi_desc->init_mutex);
-       acpi_desc->cancel = 1;
+       set_bit(ARS_CANCEL, &acpi_desc->scrub_flags);
        cancel_delayed_work_sync(&acpi_desc->dwork);
        mutex_unlock(&acpi_desc->init_mutex);
  
@@@ -3769,7 -3757,6 +3797,7 @@@ static __init int nfit_init(void
        guid_parse(UUID_NFIT_DIMM_N_HPE1, &nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
        guid_parse(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
        guid_parse(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
 +      guid_parse(UUID_NFIT_DIMM_N_HYPERV, &nfit_uuid[NFIT_DEV_DIMM_N_HYPERV]);
  
        nfit_wq = create_singlethread_workqueue("nfit");
        if (!nfit_wq)
diff --combined drivers/acpi/nfit/nfit.h
index 4de167b4f76f4e7a9038a868a23e5c5936f46e41,0cbe5009eb2c4e9dc2c04b85ca1b7821f704daa4..2f8cf2a11e3bf0ecae57507fb325bdf429d11d6e
  /* https://msdn.microsoft.com/library/windows/hardware/mt604741 */
  #define UUID_NFIT_DIMM_N_MSFT "1ee68b36-d4bd-4a1a-9a16-4f8e53d46e05"
  
 +/* http://www.uefi.org/RFIC_LIST (see "Virtual NVDIMM 0x1901") */
 +#define UUID_NFIT_DIMM_N_HYPERV "5746c5f2-a9a2-4264-ad0e-e4ddc9e09e80"
 +
  #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
                | 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_MSFT
 +#define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV
  
  #define NVDIMM_STANDARD_CMDMASK \
  (1 << ND_CMD_SMART | 1 << ND_CMD_SMART_THRESHOLD | 1 << ND_CMD_DIMM_FLAGS \
@@@ -97,7 -94,6 +97,7 @@@ enum nfit_uuids 
        NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,
        NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
        NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT,
 +      NFIT_DEV_DIMM_N_HYPERV = NVDIMM_FAMILY_HYPERV,
        NFIT_SPA_VOLATILE,
        NFIT_SPA_PM,
        NFIT_SPA_DCR,
@@@ -214,6 -210,13 +214,13 @@@ struct nfit_mem 
        int family;
  };
  
+ enum scrub_flags {
+       ARS_BUSY,
+       ARS_CANCEL,
+       ARS_VALID,
+       ARS_POLL,
+ };
  struct acpi_nfit_desc {
        struct nvdimm_bus_descriptor nd_desc;
        struct acpi_table_header acpi_header;
        struct list_head idts;
        struct nvdimm_bus *nvdimm_bus;
        struct device *dev;
-       u8 ars_start_flags;
        struct nd_cmd_ars_status *ars_status;
        struct nfit_spa *scrub_spa;
        struct delayed_work dwork;
        unsigned int max_ars;
        unsigned int scrub_count;
        unsigned int scrub_mode;
-       unsigned int scrub_busy:1;
-       unsigned int cancel:1;
+       unsigned long scrub_flags;
        unsigned long dimm_cmd_force_en;
        unsigned long bus_cmd_force_en;
        unsigned long bus_nfit_cmd_force_en;