Merge branch 'for-4.7/dsm' into libnvdimm-for-next
[linux-2.6-block.git] / drivers / acpi / nfit.c
index bf2d7a20d9d725265748d0ee51fab279f9d61f6c..2564f330a93e44c1eff3a7435572df78c639a1a7 100644 (file)
@@ -328,8 +328,11 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
                                        offset);
                        rc = -ENXIO;
                }
-       } else
+       } else {
                rc = 0;
+               if (cmd_rc)
+                       *cmd_rc = xlat_status(buf, cmd);
+       }
 
  out:
        ACPI_FREE(out_obj);
@@ -696,6 +699,7 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
                        if (!nfit_mem)
                                return -ENOMEM;
                        INIT_LIST_HEAD(&nfit_mem->list);
+                       nfit_mem->acpi_desc = acpi_desc;
                        list_add(&nfit_mem->list, &acpi_desc->dimms);
                }
 
@@ -879,6 +883,18 @@ static ssize_t device_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(device);
 
+static int num_nvdimm_formats(struct nvdimm *nvdimm)
+{
+       struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+       int formats = 0;
+
+       if (nfit_mem->memdev_pmem)
+               formats++;
+       if (nfit_mem->memdev_bdw)
+               formats++;
+       return formats;
+}
+
 static ssize_t format_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -888,6 +904,55 @@ static ssize_t format_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(format);
 
+static ssize_t format1_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       u32 handle;
+       ssize_t rc = -ENXIO;
+       struct nfit_mem *nfit_mem;
+       struct nfit_memdev *nfit_memdev;
+       struct acpi_nfit_desc *acpi_desc;
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+       struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
+
+       nfit_mem = nvdimm_provider_data(nvdimm);
+       acpi_desc = nfit_mem->acpi_desc;
+       handle = to_nfit_memdev(dev)->device_handle;
+
+       /* assumes DIMMs have at most 2 published interface codes */
+       mutex_lock(&acpi_desc->init_mutex);
+       list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+               struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
+               struct nfit_dcr *nfit_dcr;
+
+               if (memdev->device_handle != handle)
+                       continue;
+
+               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+                       if (nfit_dcr->dcr->region_index != memdev->region_index)
+                               continue;
+                       if (nfit_dcr->dcr->code == dcr->code)
+                               continue;
+                       rc = sprintf(buf, "%#x\n", nfit_dcr->dcr->code);
+                       break;
+               }
+               if (rc != ENXIO)
+                       break;
+       }
+       mutex_unlock(&acpi_desc->init_mutex);
+       return rc;
+}
+static DEVICE_ATTR_RO(format1);
+
+static ssize_t formats_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+
+       return sprintf(buf, "%d\n", num_nvdimm_formats(nvdimm));
+}
+static DEVICE_ATTR_RO(formats);
+
 static ssize_t serial_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -941,6 +1006,8 @@ static struct attribute *acpi_nfit_dimm_attributes[] = {
        &dev_attr_vendor.attr,
        &dev_attr_device.attr,
        &dev_attr_format.attr,
+       &dev_attr_formats.attr,
+       &dev_attr_format1.attr,
        &dev_attr_serial.attr,
        &dev_attr_rev_id.attr,
        &dev_attr_flags.attr,
@@ -953,11 +1020,13 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
                struct attribute *a, int n)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
+       struct nvdimm *nvdimm = to_nvdimm(dev);
 
-       if (to_nfit_dcr(dev))
-               return a->mode;
-       else
+       if (!to_nfit_dcr(dev))
+               return 0;
+       if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1)
                return 0;
+       return a->mode;
 }
 
 static struct attribute_group acpi_nfit_dimm_attribute_group = {
@@ -2413,7 +2482,7 @@ static int acpi_nfit_add(struct acpi_device *adev)
        acpi_size sz;
        int rc;
 
-       status = acpi_get_table_with_size("NFIT", 0, &tbl, &sz);
+       status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz);
        if (ACPI_FAILURE(status)) {
                /* This is ok, we could have an nvdimm hotplugged later */
                dev_dbg(dev, "failed to find NFIT at startup\n");