Merge branch 'for-5.1/libnvdimm' into libnvdimm-for-next
[platform/kernel/linux-rpi.git] / drivers / acpi / nfit / core.c
index c34c595..c7afb1f 100644 (file)
@@ -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);
 
@@ -556,6 +560,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
                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,
@@ -574,13 +585,6 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
                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,
@@ -1761,14 +1765,14 @@ static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method)
 
 __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,
        };
@@ -1783,8 +1787,15 @@ __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem)
                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)
@@ -1795,7 +1806,6 @@ __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem)
                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)
@@ -1863,9 +1873,17 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
        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))
@@ -1888,6 +1906,8 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
                        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;
@@ -1917,18 +1937,32 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
                | 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);
@@ -2029,6 +2063,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
                        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);
@@ -2052,7 +2090,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
                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":"",
@@ -3731,6 +3769,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)