aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDave Jiang <dave.jiang@intel.com>2018-02-01 19:41:57 -0500
committerDan Williams <dan.j.williams@intel.com>2018-02-01 19:49:18 -0500
commitbfbaa952d1232c6199cdeb4896da67e02a13326d (patch)
tree4df44082a9add16f88f4fa1d29720c93f63e4de5 /tools
parent1c47a645ba48508dd641315ba01a949bea979e8e (diff)
libnvdimm/nfit_test: add firmware download emulation
Adding support in nfit_test for DSM v1.6 firmware update sequence. The test will simulate the flashing of firmware to the DIMM. A bogus version string will be returned as the test has no idea how to parse the firmware binary. Any bogus binary can be used to "update" as the actual binary is not copied into the kernel. Signed-off-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Vishal Verma <vishal.l.verma@intel.com> [ vishal: also move smart calls into the nd_cmd_call block ] Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'tools')
-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