aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/nfit/core.c48
-rw-r--r--drivers/nvdimm/core.c8
-rw-r--r--drivers/nvdimm/nd.h22
-rw-r--r--drivers/nvdimm/region_devs.c22
-rw-r--r--tools/testing/nvdimm/test/nfit.c3
5 files changed, 70 insertions, 33 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 80cc7c089a15..e1d5ea6d5e40 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -94,54 +94,50 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
94 return to_acpi_device(acpi_desc->dev); 94 return to_acpi_device(acpi_desc->dev);
95} 95}
96 96
97static int xlat_status(void *buf, unsigned int cmd) 97static int xlat_status(void *buf, unsigned int cmd, u32 status)
98{ 98{
99 struct nd_cmd_clear_error *clear_err; 99 struct nd_cmd_clear_error *clear_err;
100 struct nd_cmd_ars_status *ars_status; 100 struct nd_cmd_ars_status *ars_status;
101 struct nd_cmd_ars_start *ars_start;
102 struct nd_cmd_ars_cap *ars_cap;
103 u16 flags; 101 u16 flags;
104 102
105 switch (cmd) { 103 switch (cmd) {
106 case ND_CMD_ARS_CAP: 104 case ND_CMD_ARS_CAP:
107 ars_cap = buf; 105 if ((status & 0xffff) == NFIT_ARS_CAP_NONE)
108 if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
109 return -ENOTTY; 106 return -ENOTTY;
110 107
111 /* Command failed */ 108 /* Command failed */
112 if (ars_cap->status & 0xffff) 109 if (status & 0xffff)
113 return -EIO; 110 return -EIO;
114 111
115 /* No supported scan types for this range */ 112 /* No supported scan types for this range */
116 flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE; 113 flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
117 if ((ars_cap->status >> 16 & flags) == 0) 114 if ((status >> 16 & flags) == 0)
118 return -ENOTTY; 115 return -ENOTTY;
119 break; 116 break;
120 case ND_CMD_ARS_START: 117 case ND_CMD_ARS_START:
121 ars_start = buf;
122 /* ARS is in progress */ 118 /* ARS is in progress */
123 if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY) 119 if ((status & 0xffff) == NFIT_ARS_START_BUSY)
124 return -EBUSY; 120 return -EBUSY;
125 121
126 /* Command failed */ 122 /* Command failed */
127 if (ars_start->status & 0xffff) 123 if (status & 0xffff)
128 return -EIO; 124 return -EIO;
129 break; 125 break;
130 case ND_CMD_ARS_STATUS: 126 case ND_CMD_ARS_STATUS:
131 ars_status = buf; 127 ars_status = buf;
132 /* Command failed */ 128 /* Command failed */
133 if (ars_status->status & 0xffff) 129 if (status & 0xffff)
134 return -EIO; 130 return -EIO;
135 /* Check extended status (Upper two bytes) */ 131 /* Check extended status (Upper two bytes) */
136 if (ars_status->status == NFIT_ARS_STATUS_DONE) 132 if (status == NFIT_ARS_STATUS_DONE)
137 return 0; 133 return 0;
138 134
139 /* ARS is in progress */ 135 /* ARS is in progress */
140 if (ars_status->status == NFIT_ARS_STATUS_BUSY) 136 if (status == NFIT_ARS_STATUS_BUSY)
141 return -EBUSY; 137 return -EBUSY;
142 138
143 /* No ARS performed for the current boot */ 139 /* No ARS performed for the current boot */
144 if (ars_status->status == NFIT_ARS_STATUS_NONE) 140 if (status == NFIT_ARS_STATUS_NONE)
145 return -EAGAIN; 141 return -EAGAIN;
146 142
147 /* 143 /*
@@ -149,19 +145,19 @@ static int xlat_status(void *buf, unsigned int cmd)
149 * agent wants the scan to stop. If we didn't overflow 145 * agent wants the scan to stop. If we didn't overflow
150 * then just continue with the returned results. 146 * then just continue with the returned results.
151 */ 147 */
152 if (ars_status->status == NFIT_ARS_STATUS_INTR) { 148 if (status == NFIT_ARS_STATUS_INTR) {
153 if (ars_status->flags & NFIT_ARS_F_OVERFLOW) 149 if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
154 return -ENOSPC; 150 return -ENOSPC;
155 return 0; 151 return 0;
156 } 152 }
157 153
158 /* Unknown status */ 154 /* Unknown status */
159 if (ars_status->status >> 16) 155 if (status >> 16)
160 return -EIO; 156 return -EIO;
161 break; 157 break;
162 case ND_CMD_CLEAR_ERROR: 158 case ND_CMD_CLEAR_ERROR:
163 clear_err = buf; 159 clear_err = buf;
164 if (clear_err->status & 0xffff) 160 if (status & 0xffff)
165 return -EIO; 161 return -EIO;
166 if (!clear_err->cleared) 162 if (!clear_err->cleared)
167 return -EIO; 163 return -EIO;
@@ -172,6 +168,9 @@ static int xlat_status(void *buf, unsigned int cmd)
172 break; 168 break;
173 } 169 }
174 170
171 /* all other non-zero status results in an error */
172 if (status)
173 return -EIO;
175 return 0; 174 return 0;
176} 175}
177 176
@@ -186,10 +185,10 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
186 struct nd_cmd_pkg *call_pkg = NULL; 185 struct nd_cmd_pkg *call_pkg = NULL;
187 const char *cmd_name, *dimm_name; 186 const char *cmd_name, *dimm_name;
188 unsigned long cmd_mask, dsm_mask; 187 unsigned long cmd_mask, dsm_mask;
188 u32 offset, fw_status = 0;
189 acpi_handle handle; 189 acpi_handle handle;
190 unsigned int func; 190 unsigned int func;
191 const u8 *uuid; 191 const u8 *uuid;
192 u32 offset;
193 int rc, i; 192 int rc, i;
194 193
195 func = cmd; 194 func = cmd;
@@ -317,6 +316,15 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
317 out_obj->buffer.pointer + offset, out_size); 316 out_obj->buffer.pointer + offset, out_size);
318 offset += out_size; 317 offset += out_size;
319 } 318 }
319
320 /*
321 * Set fw_status for all the commands with a known format to be
322 * later interpreted by xlat_status().
323 */
324 if (i >= 1 && ((cmd >= ND_CMD_ARS_CAP && cmd <= ND_CMD_CLEAR_ERROR)
325 || (cmd >= ND_CMD_SMART && cmd <= ND_CMD_VENDOR)))
326 fw_status = *(u32 *) out_obj->buffer.pointer;
327
320 if (offset + in_buf.buffer.length < buf_len) { 328 if (offset + in_buf.buffer.length < buf_len) {
321 if (i >= 1) { 329 if (i >= 1) {
322 /* 330 /*
@@ -325,7 +333,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
325 */ 333 */
326 rc = buf_len - offset - in_buf.buffer.length; 334 rc = buf_len - offset - in_buf.buffer.length;
327 if (cmd_rc) 335 if (cmd_rc)
328 *cmd_rc = xlat_status(buf, cmd); 336 *cmd_rc = xlat_status(buf, cmd, fw_status);
329 } else { 337 } else {
330 dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n", 338 dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
331 __func__, dimm_name, cmd_name, buf_len, 339 __func__, dimm_name, cmd_name, buf_len,
@@ -335,7 +343,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
335 } else { 343 } else {
336 rc = 0; 344 rc = 0;
337 if (cmd_rc) 345 if (cmd_rc)
338 *cmd_rc = xlat_status(buf, cmd); 346 *cmd_rc = xlat_status(buf, cmd, fw_status);
339 } 347 }
340 348
341 out: 349 out:
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 715583f69d28..4d7bbd2df5c0 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -99,8 +99,11 @@ static struct nvdimm_map *alloc_nvdimm_map(struct device *dev,
99 nvdimm_map->size = size; 99 nvdimm_map->size = size;
100 kref_init(&nvdimm_map->kref); 100 kref_init(&nvdimm_map->kref);
101 101
102 if (!request_mem_region(offset, size, dev_name(&nvdimm_bus->dev))) 102 if (!request_mem_region(offset, size, dev_name(&nvdimm_bus->dev))) {
103 dev_err(&nvdimm_bus->dev, "failed to request %pa + %zd for %s\n",
104 &offset, size, dev_name(dev));
103 goto err_request_region; 105 goto err_request_region;
106 }
104 107
105 if (flags) 108 if (flags)
106 nvdimm_map->mem = memremap(offset, size, flags); 109 nvdimm_map->mem = memremap(offset, size, flags);
@@ -171,6 +174,9 @@ void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset,
171 kref_get(&nvdimm_map->kref); 174 kref_get(&nvdimm_map->kref);
172 nvdimm_bus_unlock(dev); 175 nvdimm_bus_unlock(dev);
173 176
177 if (!nvdimm_map)
178 return NULL;
179
174 if (devm_add_action_or_reset(dev, nvdimm_map_put, nvdimm_map)) 180 if (devm_add_action_or_reset(dev, nvdimm_map_put, nvdimm_map))
175 return NULL; 181 return NULL;
176 182
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 8024a0ef86d3..0b78a8211f4a 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -52,10 +52,28 @@ struct nvdimm_drvdata {
52struct nd_region_data { 52struct nd_region_data {
53 int ns_count; 53 int ns_count;
54 int ns_active; 54 int ns_active;
55 unsigned int flush_mask; 55 unsigned int hints_shift;
56 void __iomem *flush_wpq[0][0]; 56 void __iomem *flush_wpq[0];
57}; 57};
58 58
59static inline void __iomem *ndrd_get_flush_wpq(struct nd_region_data *ndrd,
60 int dimm, int hint)
61{
62 unsigned int num = 1 << ndrd->hints_shift;
63 unsigned int mask = num - 1;
64
65 return ndrd->flush_wpq[dimm * num + (hint & mask)];
66}
67
68static inline void ndrd_set_flush_wpq(struct nd_region_data *ndrd, int dimm,
69 int hint, void __iomem *flush)
70{
71 unsigned int num = 1 << ndrd->hints_shift;
72 unsigned int mask = num - 1;
73
74 ndrd->flush_wpq[dimm * num + (hint & mask)] = flush;
75}
76
59static inline struct nd_namespace_index *to_namespace_index( 77static inline struct nd_namespace_index *to_namespace_index(
60 struct nvdimm_drvdata *ndd, int i) 78 struct nvdimm_drvdata *ndd, int i)
61{ 79{
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index e8d5ba7b29af..4c0ac4abb629 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -38,7 +38,7 @@ static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
38 38
39 dev_dbg(dev, "%s: map %d flush address%s\n", nvdimm_name(nvdimm), 39 dev_dbg(dev, "%s: map %d flush address%s\n", nvdimm_name(nvdimm),
40 nvdimm->num_flush, nvdimm->num_flush == 1 ? "" : "es"); 40 nvdimm->num_flush, nvdimm->num_flush == 1 ? "" : "es");
41 for (i = 0; i < nvdimm->num_flush; i++) { 41 for (i = 0; i < (1 << ndrd->hints_shift); i++) {
42 struct resource *res = &nvdimm->flush_wpq[i]; 42 struct resource *res = &nvdimm->flush_wpq[i];
43 unsigned long pfn = PHYS_PFN(res->start); 43 unsigned long pfn = PHYS_PFN(res->start);
44 void __iomem *flush_page; 44 void __iomem *flush_page;
@@ -54,14 +54,15 @@ static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
54 54
55 if (j < i) 55 if (j < i)
56 flush_page = (void __iomem *) ((unsigned long) 56 flush_page = (void __iomem *) ((unsigned long)
57 ndrd->flush_wpq[dimm][j] & PAGE_MASK); 57 ndrd_get_flush_wpq(ndrd, dimm, j)
58 & PAGE_MASK);
58 else 59 else
59 flush_page = devm_nvdimm_ioremap(dev, 60 flush_page = devm_nvdimm_ioremap(dev,
60 PHYS_PFN(pfn), PAGE_SIZE); 61 PFN_PHYS(pfn), PAGE_SIZE);
61 if (!flush_page) 62 if (!flush_page)
62 return -ENXIO; 63 return -ENXIO;
63 ndrd->flush_wpq[dimm][i] = flush_page 64 ndrd_set_flush_wpq(ndrd, dimm, i, flush_page
64 + (res->start & ~PAGE_MASK); 65 + (res->start & ~PAGE_MASK));
65 } 66 }
66 67
67 return 0; 68 return 0;
@@ -93,7 +94,10 @@ int nd_region_activate(struct nd_region *nd_region)
93 return -ENOMEM; 94 return -ENOMEM;
94 dev_set_drvdata(dev, ndrd); 95 dev_set_drvdata(dev, ndrd);
95 96
96 ndrd->flush_mask = (1 << ilog2(num_flush)) - 1; 97 if (!num_flush)
98 return 0;
99
100 ndrd->hints_shift = ilog2(num_flush);
97 for (i = 0; i < nd_region->ndr_mappings; i++) { 101 for (i = 0; i < nd_region->ndr_mappings; i++) {
98 struct nd_mapping *nd_mapping = &nd_region->mapping[i]; 102 struct nd_mapping *nd_mapping = &nd_region->mapping[i];
99 struct nvdimm *nvdimm = nd_mapping->nvdimm; 103 struct nvdimm *nvdimm = nd_mapping->nvdimm;
@@ -900,8 +904,8 @@ void nvdimm_flush(struct nd_region *nd_region)
900 */ 904 */
901 wmb(); 905 wmb();
902 for (i = 0; i < nd_region->ndr_mappings; i++) 906 for (i = 0; i < nd_region->ndr_mappings; i++)
903 if (ndrd->flush_wpq[i][0]) 907 if (ndrd_get_flush_wpq(ndrd, i, 0))
904 writeq(1, ndrd->flush_wpq[i][idx & ndrd->flush_mask]); 908 writeq(1, ndrd_get_flush_wpq(ndrd, i, idx));
905 wmb(); 909 wmb();
906} 910}
907EXPORT_SYMBOL_GPL(nvdimm_flush); 911EXPORT_SYMBOL_GPL(nvdimm_flush);
@@ -925,7 +929,7 @@ int nvdimm_has_flush(struct nd_region *nd_region)
925 929
926 for (i = 0; i < nd_region->ndr_mappings; i++) 930 for (i = 0; i < nd_region->ndr_mappings; i++)
927 /* flush hints present, flushing required */ 931 /* flush hints present, flushing required */
928 if (ndrd->flush_wpq[i][0]) 932 if (ndrd_get_flush_wpq(ndrd, i, 0))
929 return 1; 933 return 1;
930 934
931 /* 935 /*
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index dd48f421844c..f64c57bf1d4b 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -603,7 +603,8 @@ static int nfit_test0_alloc(struct nfit_test *t)
603 return -ENOMEM; 603 return -ENOMEM;
604 sprintf(t->label[i], "label%d", i); 604 sprintf(t->label[i], "label%d", i);
605 605
606 t->flush[i] = test_alloc(t, sizeof(u64) * NUM_HINTS, 606 t->flush[i] = test_alloc(t, max(PAGE_SIZE,
607 sizeof(u64) * NUM_HINTS),
607 &t->flush_dma[i]); 608 &t->flush_dma[i]);
608 if (!t->flush[i]) 609 if (!t->flush[i])
609 return -ENOMEM; 610 return -ENOMEM;