Merge branch 'for-4.6/pfn' into libnvdimm-for-next
authorDan Williams <dan.j.williams@intel.com>
Thu, 10 Mar 2016 01:15:43 +0000 (17:15 -0800)
committerDan Williams <dan.j.williams@intel.com>
Thu, 10 Mar 2016 01:15:43 +0000 (17:15 -0800)
1  2 
drivers/acpi/nfit.c
drivers/nvdimm/pmem.c

@@@ -1658,6 -1571,146 +1658,48 @@@ static int ars_status_process_records(s
        return 0;
  }
  
 -static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
 -              struct nd_region_desc *ndr_desc)
 -{
 -      struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
 -      struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
 -      struct nd_cmd_ars_status *ars_status = NULL;
 -      struct nd_cmd_ars_start *ars_start = NULL;
 -      struct nd_cmd_ars_cap *ars_cap = NULL;
 -      u64 start, len, cur, remaining;
 -      u32 ars_status_size;
 -      int rc;
 -
 -      ars_cap = kzalloc(sizeof(*ars_cap), GFP_KERNEL);
 -      if (!ars_cap)
 -              return -ENOMEM;
 -
 -      start = ndr_desc->res->start;
 -      len = ndr_desc->res->end - ndr_desc->res->start + 1;
 -
 -      rc = ars_get_cap(nd_desc, ars_cap, start, len);
 -      if (rc)
 -              goto out;
 -
 -      /*
 -       * If ARS is unsupported, or if the 'Persistent Memory Scrub' flag in
 -       * extended status is not set, skip this but continue initialization
 -       */
 -      if ((ars_cap->status & 0xffff) ||
 -              !(ars_cap->status >> 16 & ND_ARS_PERSISTENT)) {
 -              dev_warn(acpi_desc->dev,
 -                      "ARS unsupported (status: 0x%x), won't create an error list\n",
 -                      ars_cap->status);
 -              goto out;
 -      }
 -
 -      /*
 -       * Check if a full-range ARS has been run. If so, use those results
 -       * without having to start a new ARS.
 -       */
 -      ars_status_size = ars_cap->max_ars_out;
 -      ars_status = kzalloc(ars_status_size, GFP_KERNEL);
 -      if (!ars_status) {
 -              rc = -ENOMEM;
 -              goto out;
 -      }
 -
 -      rc = ars_get_status(nd_desc, ars_status, ars_status_size);
 -      if (rc)
 -              goto out;
 -
 -      if (ars_status->address <= start &&
 -              (ars_status->address + ars_status->length >= start + len)) {
 -              rc = ars_status_process_records(nvdimm_bus, ars_status, start);
 -              goto out;
 -      }
 -
 -      /*
 -       * ARS_STATUS can overflow if the number of poison entries found is
 -       * greater than the maximum buffer size (ars_cap->max_ars_out)
 -       * To detect overflow, check if the length field of ars_status
 -       * is less than the length we supplied. If so, process the
 -       * error entries we got, adjust the start point, and start again
 -       */
 -      ars_start = kzalloc(sizeof(*ars_start), GFP_KERNEL);
 -      if (!ars_start)
 -              return -ENOMEM;
 -
 -      cur = start;
 -      remaining = len;
 -      do {
 -              u64 done, end;
 -
 -              rc = ars_do_start(nd_desc, ars_start, cur, remaining);
 -              if (rc)
 -                      goto out;
 -
 -              rc = ars_get_status(nd_desc, ars_status, ars_status_size);
 -              if (rc)
 -                      goto out;
 -
 -              rc = ars_status_process_records(nvdimm_bus, ars_status, cur);
 -              if (rc)
 -                      goto out;
 -
 -              end = min(cur + remaining,
 -                      ars_status->address + ars_status->length);
 -              done = end - cur;
 -              cur += done;
 -              remaining -= done;
 -      } while (remaining);
 -
 - out:
 -      kfree(ars_cap);
 -      kfree(ars_start);
 -      kfree(ars_status);
 -      return rc;
 -}
 -
+ static void acpi_nfit_remove_resource(void *data)
+ {
+       struct resource *res = data;
+       remove_resource(res);
+ }
+ static int acpi_nfit_insert_resource(struct acpi_nfit_desc *acpi_desc,
+               struct nd_region_desc *ndr_desc)
+ {
+       struct resource *res, *nd_res = ndr_desc->res;
+       int is_pmem, ret;
+       /* No operation if the region is already registered as PMEM */
+       is_pmem = region_intersects(nd_res->start, resource_size(nd_res),
+                               IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY);
+       if (is_pmem == REGION_INTERSECTS)
+               return 0;
+       res = devm_kzalloc(acpi_desc->dev, sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+       res->name = "Persistent Memory";
+       res->start = nd_res->start;
+       res->end = nd_res->end;
+       res->flags = IORESOURCE_MEM;
+       res->desc = IORES_DESC_PERSISTENT_MEMORY;
+       ret = insert_resource(&iomem_resource, res);
+       if (ret)
+               return ret;
+       ret = devm_add_action(acpi_desc->dev, acpi_nfit_remove_resource, res);
+       if (ret) {
+               remove_resource(res);
+               return ret;
+       }
+       return 0;
+ }
  static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
                struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
                struct acpi_nfit_memory_map *memdev,
@@@ -1773,43 -1823,27 +1815,51 @@@ static int acpi_nfit_register_region(st
  
        nvdimm_bus = acpi_desc->nvdimm_bus;
        if (nfit_spa_type(spa) == NFIT_SPA_PM) {
 -              if (rc)
+               rc = acpi_nfit_insert_resource(acpi_desc, ndr_desc);
 -
 -              rc = acpi_nfit_find_poison(acpi_desc, ndr_desc);
 -              if (rc) {
 -                      dev_err(acpi_desc->dev,
 -                              "error while performing ARS to find poison: %d\n",
 -                              rc);
 -                      return rc;
++              if (rc) {
+                       dev_warn(acpi_desc->dev,
+                               "failed to insert pmem resource to iomem: %d\n",
+                               rc);
 -              if (!nvdimm_pmem_region_create(nvdimm_bus, ndr_desc))
 -                      return -ENOMEM;
++                      goto out;
+               }
++
 +              nfit_spa->nd_region = nvdimm_pmem_region_create(nvdimm_bus,
 +                              ndr_desc);
 +              if (!nfit_spa->nd_region)
 +                      rc = -ENOMEM;
        } else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
 -              if (!nvdimm_volatile_region_create(nvdimm_bus, ndr_desc))
 -                      return -ENOMEM;
 +              nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus,
 +                              ndr_desc);
 +              if (!nfit_spa->nd_region)
 +                      rc = -ENOMEM;
 +      }
 +
 + out:
 +      if (rc)
 +              dev_err(acpi_desc->dev, "failed to register spa range %d\n",
 +                              nfit_spa->spa->range_index);
 +      return rc;
 +}
 +
 +static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc,
 +              u32 max_ars)
 +{
 +      struct device *dev = acpi_desc->dev;
 +      struct nd_cmd_ars_status *ars_status;
 +
 +      if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) {
 +              memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size);
 +              return 0;
        }
  
 -      nfit_spa->is_registered = 1;
 +      if (acpi_desc->ars_status)
 +              devm_kfree(dev, acpi_desc->ars_status);
 +      acpi_desc->ars_status = NULL;
 +      ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL);
 +      if (!ars_status)
 +              return -ENOMEM;
 +      acpi_desc->ars_status = ars_status;
 +      acpi_desc->ars_status_size = max_ars;
        return 0;
  }
  
Simple merge