aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/testing/nvdimm/test/nfit.c322
-rw-r--r--tools/testing/nvdimm/test/nfit_test.h66
2 files changed, 360 insertions, 28 deletions
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 2b57254342aa..a043fea4d58d 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -137,6 +137,14 @@ static u32 handle[] = {
137 137
138static unsigned long dimm_fail_cmd_flags[NUM_DCR]; 138static unsigned long dimm_fail_cmd_flags[NUM_DCR];
139 139
140struct nfit_test_fw {
141 enum intel_fw_update_state state;
142 u32 context;
143 u64 version;
144 u32 size_received;
145 u64 end_time;
146};
147
140struct nfit_test { 148struct nfit_test {
141 struct acpi_nfit_desc acpi_desc; 149 struct acpi_nfit_desc acpi_desc;
142 struct platform_device pdev; 150 struct platform_device pdev;
@@ -172,6 +180,7 @@ struct nfit_test {
172 struct nd_intel_smart_threshold *smart_threshold; 180 struct nd_intel_smart_threshold *smart_threshold;
173 struct badrange badrange; 181 struct badrange badrange;
174 struct work_struct work; 182 struct work_struct work;
183 struct nfit_test_fw *fw;
175}; 184};
176 185
177static struct workqueue_struct *nfit_wq; 186static struct workqueue_struct *nfit_wq;
@@ -183,6 +192,226 @@ static struct nfit_test *to_nfit_test(struct device *dev)
183 return container_of(pdev, struct nfit_test, pdev); 192 return container_of(pdev, struct nfit_test, pdev);
184} 193}
185 194
195static int nd_intel_test_get_fw_info(struct nfit_test *t,
196 struct nd_intel_fw_info *nd_cmd, unsigned int buf_len,
197 int idx)
198{
199 struct device *dev = &t->pdev.dev;
200 struct nfit_test_fw *fw = &t->fw[idx];
201
202 dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p, buf_len: %u, idx: %d\n",
203 __func__, t, nd_cmd, buf_len, idx);
204
205 if (buf_len < sizeof(*nd_cmd))
206 return -EINVAL;
207
208 nd_cmd->status = 0;
209 nd_cmd->storage_size = INTEL_FW_STORAGE_SIZE;
210 nd_cmd->max_send_len = INTEL_FW_MAX_SEND_LEN;
211 nd_cmd->query_interval = INTEL_FW_QUERY_INTERVAL;
212 nd_cmd->max_query_time = INTEL_FW_QUERY_MAX_TIME;
213 nd_cmd->update_cap = 0;
214 nd_cmd->fis_version = INTEL_FW_FIS_VERSION;
215 nd_cmd->run_version = 0;
216 nd_cmd->updated_version = fw->version;
217
218 return 0;
219}
220
221static int nd_intel_test_start_update(struct nfit_test *t,
222 struct nd_intel_fw_start *nd_cmd, unsigned int buf_len,
223 int idx)
224{
225 struct device *dev = &t->pdev.dev;
226 struct nfit_test_fw *fw = &t->fw[idx];
227
228 dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n",
229 __func__, t, nd_cmd, buf_len, idx);
230
231 if (buf_len < sizeof(*nd_cmd))
232 return -EINVAL;
233
234 if (fw->state != FW_STATE_NEW) {
235 /* extended status, FW update in progress */
236 nd_cmd->status = 0x10007;
237 return 0;
238 }
239
240 fw->state = FW_STATE_IN_PROGRESS;
241 fw->context++;
242 fw->size_received = 0;
243 nd_cmd->status = 0;
244 nd_cmd->context = fw->context;
245
246 dev_dbg(dev, "%s: context issued: %#x\n", __func__, nd_cmd->context);
247
248 return 0;
249}
250
251static int nd_intel_test_send_data(struct nfit_test *t,
252 struct nd_intel_fw_send_data *nd_cmd, unsigned int buf_len,
253 int idx)
254{
255 struct device *dev = &t->pdev.dev;
256 struct nfit_test_fw *fw = &t->fw[idx];
257 u32 *status = (u32 *)&nd_cmd->data[nd_cmd->length];
258
259 dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n",
260 __func__, t, nd_cmd, buf_len, idx);
261
262 if (buf_len < sizeof(*nd_cmd))
263 return -EINVAL;
264
265
266 dev_dbg(dev, "%s: cmd->status: %#x\n", __func__, *status);
267 dev_dbg(dev, "%s: cmd->data[0]: %#x\n", __func__, nd_cmd->data[0]);
268 dev_dbg(dev, "%s: cmd->data[%u]: %#x\n", __func__, nd_cmd->length-1,
269 nd_cmd->data[nd_cmd->length-1]);
270
271 if (fw->state != FW_STATE_IN_PROGRESS) {
272 dev_dbg(dev, "%s: not in IN_PROGRESS state\n", __func__);
273 *status = 0x5;
274 return 0;
275 }
276
277 if (nd_cmd->context != fw->context) {
278 dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n",
279 __func__, nd_cmd->context, fw->context);
280 *status = 0x10007;
281 return 0;
282 }
283
284 /*
285 * check offset + len > size of fw storage
286 * check length is > max send length
287 */
288 if (nd_cmd->offset + nd_cmd->length > INTEL_FW_STORAGE_SIZE ||
289 nd_cmd->length > INTEL_FW_MAX_SEND_LEN) {
290 *status = 0x3;
291 dev_dbg(dev, "%s: buffer boundary violation\n", __func__);
292 return 0;
293 }
294
295 fw->size_received += nd_cmd->length;
296 dev_dbg(dev, "%s: copying %u bytes, %u bytes so far\n",
297 __func__, nd_cmd->length, fw->size_received);
298 *status = 0;
299 return 0;
300}
301
302static int nd_intel_test_finish_fw(struct nfit_test *t,
303 struct nd_intel_fw_finish_update *nd_cmd,
304 unsigned int buf_len, int idx)
305{
306 struct device *dev = &t->pdev.dev;
307 struct nfit_test_fw *fw = &t->fw[idx];
308
309 dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n",
310 __func__, t, nd_cmd, buf_len, idx);
311
312 if (fw->state == FW_STATE_UPDATED) {
313 /* update already done, need cold boot */
314 nd_cmd->status = 0x20007;
315 return 0;
316 }
317
318 dev_dbg(dev, "%s: context: %#x ctrl_flags: %#x\n",
319 __func__, nd_cmd->context, nd_cmd->ctrl_flags);
320
321 switch (nd_cmd->ctrl_flags) {
322 case 0: /* finish */
323 if (nd_cmd->context != fw->context) {
324 dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n",
325 __func__, nd_cmd->context,
326 fw->context);
327 nd_cmd->status = 0x10007;
328 return 0;
329 }
330 nd_cmd->status = 0;
331 fw->state = FW_STATE_VERIFY;
332 /* set 1 second of time for firmware "update" */
333 fw->end_time = jiffies + HZ;
334 break;
335
336 case 1: /* abort */
337 fw->size_received = 0;
338 /* successfully aborted status */
339 nd_cmd->status = 0x40007;
340 fw->state = FW_STATE_NEW;
341 dev_dbg(dev, "%s: abort successful\n", __func__);
342 break;
343
344 default: /* bad control flag */
345 dev_warn(dev, "%s: unknown control flag: %#x\n",
346 __func__, nd_cmd->ctrl_flags);
347 return -EINVAL;
348 }
349
350 return 0;
351}
352
353static int nd_intel_test_finish_query(struct nfit_test *t,
354 struct nd_intel_fw_finish_query *nd_cmd,
355 unsigned int buf_len, int idx)
356{
357 struct device *dev = &t->pdev.dev;
358 struct nfit_test_fw *fw = &t->fw[idx];
359
360 dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n",
361 __func__, t, nd_cmd, buf_len, idx);
362
363 if (buf_len < sizeof(*nd_cmd))
364 return -EINVAL;
365
366 if (nd_cmd->context != fw->context) {
367 dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n",
368 __func__, nd_cmd->context, fw->context);
369 nd_cmd->status = 0x10007;
370 return 0;
371 }
372
373 dev_dbg(dev, "%s context: %#x\n", __func__, nd_cmd->context);
374
375 switch (fw->state) {
376 case FW_STATE_NEW:
377 nd_cmd->updated_fw_rev = 0;
378 nd_cmd->status = 0;
379 dev_dbg(dev, "%s: new state\n", __func__);
380 break;
381
382 case FW_STATE_IN_PROGRESS:
383 /* sequencing error */
384 nd_cmd->status = 0x40007;
385 nd_cmd->updated_fw_rev = 0;
386 dev_dbg(dev, "%s: sequence error\n", __func__);
387 break;
388
389 case FW_STATE_VERIFY:
390 if (time_is_after_jiffies64(fw->end_time)) {
391 nd_cmd->updated_fw_rev = 0;
392 nd_cmd->status = 0x20007;
393 dev_dbg(dev, "%s: still verifying\n", __func__);
394 break;
395 }
396
397 dev_dbg(dev, "%s: transition out verify\n", __func__);
398 fw->state = FW_STATE_UPDATED;
399 /* we are going to fall through if it's "done" */
400 case FW_STATE_UPDATED:
401 nd_cmd->status = 0;
402 /* bogus test version */
403 fw->version = nd_cmd->updated_fw_rev =
404 INTEL_FW_FAKE_VERSION;
405 dev_dbg(dev, "%s: updated\n", __func__);
406 break;
407
408 default: /* we should never get here */
409 return -EINVAL;
410 }
411
412 return 0;
413}
414
186static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd, 415static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd,
187 unsigned int buf_len) 416 unsigned int buf_len)
188{ 417{
@@ -592,6 +821,23 @@ static int nfit_test_cmd_ars_inject_status(struct nfit_test *t,
592 return 0; 821 return 0;
593} 822}
594 823
824static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func)
825{
826 int i;
827
828 /* lookup per-dimm data */
829 for (i = 0; i < ARRAY_SIZE(handle); i++)
830 if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i])
831 break;
832 if (i >= ARRAY_SIZE(handle))
833 return -ENXIO;
834
835 if ((1 << func) & dimm_fail_cmd_flags[i])
836 return -EIO;
837
838 return i;
839}
840
595static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, 841static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
596 struct nvdimm *nvdimm, unsigned int cmd, void *buf, 842 struct nvdimm *nvdimm, unsigned int cmd, void *buf,
597 unsigned int buf_len, int *cmd_rc) 843 unsigned int buf_len, int *cmd_rc)
@@ -620,22 +866,54 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
620 func = call_pkg->nd_command; 866 func = call_pkg->nd_command;
621 if (call_pkg->nd_family != nfit_mem->family) 867 if (call_pkg->nd_family != nfit_mem->family)
622 return -ENOTTY; 868 return -ENOTTY;
869
870 i = get_dimm(nfit_mem, func);
871 if (i < 0)
872 return i;
873
874 switch (func) {
875 case ND_INTEL_FW_GET_INFO:
876 return nd_intel_test_get_fw_info(t, buf,
877 buf_len, i - t->dcr_idx);
878 case ND_INTEL_FW_START_UPDATE:
879 return nd_intel_test_start_update(t, buf,
880 buf_len, i - t->dcr_idx);
881 case ND_INTEL_FW_SEND_DATA:
882 return nd_intel_test_send_data(t, buf,
883 buf_len, i - t->dcr_idx);
884 case ND_INTEL_FW_FINISH_UPDATE:
885 return nd_intel_test_finish_fw(t, buf,
886 buf_len, i - t->dcr_idx);
887 case ND_INTEL_FW_FINISH_QUERY:
888 return nd_intel_test_finish_query(t, buf,
889 buf_len, i - t->dcr_idx);
890 case ND_INTEL_SMART:
891 return nfit_test_cmd_smart(buf, buf_len,
892 &t->smart[i - t->dcr_idx]);
893 case ND_INTEL_SMART_THRESHOLD:
894 return nfit_test_cmd_smart_threshold(buf,
895 buf_len,
896 &t->smart_threshold[i -
897 t->dcr_idx]);
898 case ND_INTEL_SMART_SET_THRESHOLD:
899 return nfit_test_cmd_smart_set_threshold(buf,
900 buf_len,
901 &t->smart_threshold[i -
902 t->dcr_idx],
903 &t->smart[i - t->dcr_idx],
904 &t->pdev.dev, t->dimm_dev[i]);
905 default:
906 return -ENOTTY;
907 }
623 } 908 }
624 909
625 if (!test_bit(cmd, &cmd_mask) 910 if (!test_bit(cmd, &cmd_mask)
626 || !test_bit(func, &nfit_mem->dsm_mask)) 911 || !test_bit(func, &nfit_mem->dsm_mask))
627 return -ENOTTY; 912 return -ENOTTY;
628 913
629 /* lookup per-dimm data */ 914 i = get_dimm(nfit_mem, func);
630 for (i = 0; i < ARRAY_SIZE(handle); i++) 915 if (i < 0)
631 if (__to_nfit_memdev(nfit_mem)->device_handle == 916 return i;
632 handle[i])
633 break;
634 if (i >= ARRAY_SIZE(handle))
635 return -ENXIO;
636
637 if ((1 << func) & dimm_fail_cmd_flags[i])
638 return -EIO;
639 917
640 switch (func) { 918 switch (func) {
641 case ND_CMD_GET_CONFIG_SIZE: 919 case ND_CMD_GET_CONFIG_SIZE:
@@ -649,20 +927,6 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
649 rc = nfit_test_cmd_set_config_data(buf, buf_len, 927 rc = nfit_test_cmd_set_config_data(buf, buf_len,
650 t->label[i - t->dcr_idx]); 928 t->label[i - t->dcr_idx]);
651 break; 929 break;
652 case ND_INTEL_SMART:
653 rc = nfit_test_cmd_smart(buf, buf_len,
654 &t->smart[i - t->dcr_idx]);
655 break;
656 case ND_INTEL_SMART_THRESHOLD:
657 rc = nfit_test_cmd_smart_threshold(buf, buf_len,
658 &t->smart_threshold[i - t->dcr_idx]);
659 break;
660 case ND_INTEL_SMART_SET_THRESHOLD:
661 rc = nfit_test_cmd_smart_set_threshold(buf, buf_len,
662 &t->smart_threshold[i - t->dcr_idx],
663 &t->smart[i - t->dcr_idx],
664 &t->pdev.dev, t->dimm_dev[i]);
665 break;
666 default: 930 default:
667 return -ENOTTY; 931 return -ENOTTY;
668 } 932 }
@@ -1728,6 +1992,11 @@ static void nfit_test0_setup(struct nfit_test *t)
1728 set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en); 1992 set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en);
1729 set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en); 1993 set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en);
1730 set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc->bus_nfit_cmd_force_en); 1994 set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc->bus_nfit_cmd_force_en);
1995 set_bit(ND_INTEL_FW_GET_INFO, &acpi_desc->dimm_cmd_force_en);
1996 set_bit(ND_INTEL_FW_START_UPDATE, &acpi_desc->dimm_cmd_force_en);
1997 set_bit(ND_INTEL_FW_SEND_DATA, &acpi_desc->dimm_cmd_force_en);
1998 set_bit(ND_INTEL_FW_FINISH_UPDATE, &acpi_desc->dimm_cmd_force_en);
1999 set_bit(ND_INTEL_FW_FINISH_QUERY, &acpi_desc->dimm_cmd_force_en);
1731} 2000}
1732 2001
1733static void nfit_test1_setup(struct nfit_test *t) 2002static void nfit_test1_setup(struct nfit_test *t)
@@ -2134,10 +2403,13 @@ static int nfit_test_probe(struct platform_device *pdev)
2134 nfit_test->smart_threshold = devm_kcalloc(dev, num, 2403 nfit_test->smart_threshold = devm_kcalloc(dev, num,
2135 sizeof(struct nd_intel_smart_threshold), 2404 sizeof(struct nd_intel_smart_threshold),
2136 GFP_KERNEL); 2405 GFP_KERNEL);
2406 nfit_test->fw = devm_kcalloc(dev, num,
2407 sizeof(struct nfit_test_fw), GFP_KERNEL);
2137 if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label 2408 if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label
2138 && nfit_test->label_dma && nfit_test->dcr 2409 && nfit_test->label_dma && nfit_test->dcr
2139 && nfit_test->dcr_dma && nfit_test->flush 2410 && nfit_test->dcr_dma && nfit_test->flush
2140 && nfit_test->flush_dma) 2411 && nfit_test->flush_dma
2412 && nfit_test->fw)
2141 /* pass */; 2413 /* pass */;
2142 else 2414 else
2143 return -ENOMEM; 2415 return -ENOMEM;
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h
index ba230f6f7676..be8fa8ec0615 100644
--- a/tools/testing/nvdimm/test/nfit_test.h
+++ b/tools/testing/nvdimm/test/nfit_test.h
@@ -84,9 +84,14 @@ struct nd_cmd_ars_err_inj_stat {
84 } __packed record[0]; 84 } __packed record[0];
85} __packed; 85} __packed;
86 86
87#define ND_INTEL_SMART 1 87#define ND_INTEL_SMART 1
88#define ND_INTEL_SMART_THRESHOLD 2 88#define ND_INTEL_SMART_THRESHOLD 2
89#define ND_INTEL_SMART_SET_THRESHOLD 17 89#define ND_INTEL_FW_GET_INFO 12
90#define ND_INTEL_FW_START_UPDATE 13
91#define ND_INTEL_FW_SEND_DATA 14
92#define ND_INTEL_FW_FINISH_UPDATE 15
93#define ND_INTEL_FW_FINISH_QUERY 16
94#define ND_INTEL_SMART_SET_THRESHOLD 17
90 95
91#define ND_INTEL_SMART_HEALTH_VALID (1 << 0) 96#define ND_INTEL_SMART_HEALTH_VALID (1 << 0)
92#define ND_INTEL_SMART_SPARES_VALID (1 << 1) 97#define ND_INTEL_SMART_SPARES_VALID (1 << 1)
@@ -152,6 +157,61 @@ struct nd_intel_smart_set_threshold {
152 __u32 status; 157 __u32 status;
153} __packed; 158} __packed;
154 159
160#define INTEL_FW_STORAGE_SIZE 0x100000
161#define INTEL_FW_MAX_SEND_LEN 0xFFEC
162#define INTEL_FW_QUERY_INTERVAL 250000
163#define INTEL_FW_QUERY_MAX_TIME 3000000
164#define INTEL_FW_FIS_VERSION 0x0105
165#define INTEL_FW_FAKE_VERSION 0xffffffffabcd
166
167enum intel_fw_update_state {
168 FW_STATE_NEW = 0,
169 FW_STATE_IN_PROGRESS,
170 FW_STATE_VERIFY,
171 FW_STATE_UPDATED,
172};
173
174struct nd_intel_fw_info {
175 __u32 status;
176 __u32 storage_size;
177 __u32 max_send_len;
178 __u32 query_interval;
179 __u32 max_query_time;
180 __u8 update_cap;
181 __u8 reserved[3];
182 __u32 fis_version;
183 __u64 run_version;
184 __u64 updated_version;
185} __packed;
186
187struct nd_intel_fw_start {
188 __u32 status;
189 __u32 context;
190} __packed;
191
192/* this one has the output first because the variable input data size */
193struct nd_intel_fw_send_data {
194 __u32 context;
195 __u32 offset;
196 __u32 length;
197 __u8 data[0];
198/* this field is not declared due ot variable data from input */
199/* __u32 status; */
200} __packed;
201
202struct nd_intel_fw_finish_update {
203 __u8 ctrl_flags;
204 __u8 reserved[3];
205 __u32 context;
206 __u32 status;
207} __packed;
208
209struct nd_intel_fw_finish_query {
210 __u32 context;
211 __u32 status;
212 __u64 updated_fw_rev;
213} __packed;
214
155union acpi_object; 215union acpi_object;
156typedef void *acpi_handle; 216typedef void *acpi_handle;
157 217