Add support for flush hints and use them in the nd_blk I/O path instead
of the global persistent_sync() whenever we can.

Signed-off-by: Ross Zwisler <[email protected]>
Cc: Dan Williams <[email protected]>
Cc: "Rafael J. Wysocki" <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
 drivers/acpi/nfit.c | 49 +++++++++++++++++++++++++++++++++++++++++++++----
 drivers/acpi/nfit.h | 22 ++++++++++++++++++++++
 2 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index 22df61968c1c..6cca50d1c690 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -286,9 +286,20 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, 
void *table, const void
                                idt->interleave_index, idt->line_count);
                break;
        }
-       case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
-               dev_dbg(dev, "%s: flush\n", __func__);
+       case ACPI_NFIT_TYPE_FLUSH_ADDRESS: {
+               struct nfit_flush *nfit_flush = devm_kzalloc(dev,
+                               sizeof(*nfit_flush), GFP_KERNEL);
+               struct acpi_nfit_flush_address *flush = table;
+
+               if (!nfit_flush)
+                       return err;
+               INIT_LIST_HEAD(&nfit_flush->list);
+               nfit_flush->flush = flush;
+               list_add_tail(&nfit_flush->list, &acpi_desc->flushes);
+               dev_dbg(dev, "%s: flush_hint handle: %d hint_count: %d\n",
+                       __func__, flush->device_handle, flush->hint_count);
                break;
+       }
        case ACPI_NFIT_TYPE_SMBIOS:
                dev_dbg(dev, "%s: smbios\n", __func__);
                break;
@@ -338,6 +349,7 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
 {
        u16 dcr_index = __to_nfit_memdev(nfit_mem)->region_index;
        struct nfit_memdev *nfit_memdev;
+       struct nfit_flush *nfit_flush;
        struct nfit_dcr *nfit_dcr;
        struct nfit_bdw *nfit_bdw;
        struct nfit_idt *nfit_idt;
@@ -384,6 +396,7 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
                                nfit_memdev->memdev->region_index != dcr_index)
                        continue;
                nfit_mem->memdev_bdw = nfit_memdev->memdev;
+
                idt_index = nfit_memdev->memdev->interleave_index;
                list_for_each_entry(nfit_idt, &acpi_desc->idts, list) {
                        if (nfit_idt->idt->interleave_index != idt_index)
@@ -391,6 +404,14 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
                        nfit_mem->idt_bdw = nfit_idt->idt;
                        break;
                }
+
+               list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) {
+                       if (nfit_flush->flush->device_handle !=
+                                       nfit_memdev->memdev->device_handle)
+                               continue;
+                       nfit_mem->nfit_flush = nfit_flush;
+                       break;
+               }
                break;
        }
 
@@ -929,7 +950,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, 
unsigned int bw,
 
        /* mmio->base must be mapped uncacheable */
        writeq(cmd, mmio->base + offset);
-       persistent_sync();
+       nfit_blk->psync(nfit_blk);
        /* FIXME: conditionally perform read-back if mandated by firmware */
 }
 
@@ -970,7 +991,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk 
*nfit_blk, void *iobuf,
        }
 
        if (write)
-               persistent_sync();
+               nfit_blk->psync(nfit_blk);
 
        rc = read_blk_stat(nfit_blk, bw) ? -EIO : 0;
        return rc;
@@ -1130,6 +1151,7 @@ static int acpi_nfit_blk_region_enable(struct nd_bus 
*nd_bus, struct device *dev
        struct nd_bus_descriptor *nd_desc = to_nd_desc(nd_bus);
        struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
        struct nd_blk_region *ndbr = to_nd_blk_region(dev);
+       struct nfit_flush *nfit_flush;
        struct nfit_blk_mmio *mmio;
        struct nfit_blk *nfit_blk;
        struct nfit_mem *nfit_mem;
@@ -1195,6 +1217,24 @@ static int acpi_nfit_blk_region_enable(struct nd_bus 
*nd_bus, struct device *dev
                return rc;
        }
 
+       nfit_flush = nfit_mem->nfit_flush;
+       if (nfit_flush && nfit_flush->flush->hint_count != 0) {
+               struct acpi_nfit_flush_address *flush = nfit_flush->flush;
+               struct resource res;
+
+               res.start = flush->hint_address[0];
+               res.end = flush->hint_address[0] + sizeof(u64) - 1;
+               res.name = dev_name(dev);
+               res.flags = IORESOURCE_MEM;
+
+               /* only need a single hint address.  map uncacheable */
+               nfit_blk->flush_hint = devm_ioremap_resource(dev, &res);
+               if (IS_ERR(nfit_blk->flush_hint))
+                       return -ENOMEM;
+               nfit_blk->psync = directed_psync;
+       } else
+               nfit_blk->psync = global_psync;
+
        if (mmio->line_size == 0)
                return 0;
 
@@ -1349,6 +1389,7 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, 
acpi_size sz)
        INIT_LIST_HEAD(&acpi_desc->dcrs);
        INIT_LIST_HEAD(&acpi_desc->bdws);
        INIT_LIST_HEAD(&acpi_desc->idts);
+       INIT_LIST_HEAD(&acpi_desc->flushes);
        INIT_LIST_HEAD(&acpi_desc->memdevs);
        INIT_LIST_HEAD(&acpi_desc->dimms);
        mutex_init(&acpi_desc->spa_map_mutex);
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
index b882a22ee7bb..858719017bef 100644
--- a/drivers/acpi/nfit.h
+++ b/drivers/acpi/nfit.h
@@ -18,6 +18,7 @@
 #include <linux/libnd.h>
 #include <linux/uuid.h>
 #include <linux/acpi.h>
+#include <linux/pmem.h>
 #include <acpi/acuuid.h>
 
 #define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
@@ -66,6 +67,11 @@ struct nfit_idt {
        struct list_head list;
 };
 
+struct nfit_flush {
+       struct acpi_nfit_flush_address *flush;
+       struct list_head list;
+};
+
 struct nfit_memdev {
        struct acpi_nfit_memory_map *memdev;
        struct list_head list;
@@ -83,6 +89,7 @@ struct nfit_mem {
        struct acpi_nfit_system_address *spa_bdw;
        struct acpi_nfit_interleave *idt_dcr;
        struct acpi_nfit_interleave *idt_bdw;
+       struct nfit_flush *nfit_flush;
        struct list_head list;
        struct acpi_device *adev;
        unsigned long dsm_mask;
@@ -94,6 +101,7 @@ struct acpi_nfit_desc {
        struct mutex spa_map_mutex;
        struct list_head spa_maps;
        struct list_head memdevs;
+       struct list_head flushes;
        struct list_head dimms;
        struct list_head spas;
        struct list_head dcrs;
@@ -131,6 +139,8 @@ struct nfit_blk {
        u64 bdw_offset; /* post interleave offset */
        u64 stat_offset;
        u64 cmd_offset;
+       void __iomem *flush_hint;
+       void (*psync)(struct nfit_blk *nfit_blk);
 };
 
 struct nfit_spa_mapping {
@@ -158,6 +168,18 @@ static inline struct acpi_nfit_desc *to_acpi_desc(struct 
nd_bus_descriptor *nd_d
        return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
 }
 
+static inline void directed_psync(struct nfit_blk *nfit_blk)
+{
+       wmb(); /* order previous writes */
+       writeq(1, nfit_blk->flush_hint); /* flush_hint must be mapped UC */
+       wmb(); /* order the write to the flush_hint */
+}
+
+static inline void global_psync(struct nfit_blk *nfit_blk)
+{
+       persistent_sync();
+}
+
 const u8 *to_nfit_uuid(enum nfit_uuids id);
 int acpi_nfit_init(struct acpi_nfit_desc *nfit, acpi_size sz);
 #endif /* __NFIT_H__ */
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to