From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 168B12239364C for ; Wed, 31 Jan 2018 13:26:30 -0800 (PST) From: "Verma, Vishal L" Subject: Re: [PATCH 1/2] libnvdimm/nfit_test: add firmware download emulation Date: Wed, 31 Jan 2018 21:32:04 +0000 Message-ID: <1517434323.8128.8.camel@intel.com> References: <151698930627.35603.14847307775995809534.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <151698930627.35603.14847307775995809534.stgit@djiang5-desk3.ch.intel.com> Content-Language: en-US Content-ID: <3A8895488FF0CC4C8F3785F10016233B@intel.com> MIME-Version: 1.0 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" To: "Jiang, Dave" , "linux-nvdimm@lists.01.org" List-ID: On Fri, 2018-01-26 at 10:55 -0700, Dave Jiang wrote: > 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 > --- > tools/testing/nvdimm/test/nfit.c | 293 > ++++++++++++++++++++++++++++++++- > tools/testing/nvdimm/test/nfit_test.h | 66 +++++++ > 2 files changed, 345 insertions(+), 14 deletions(-) > For both of these, Reviewed-by: Vishal Verma > diff --git a/tools/testing/nvdimm/test/nfit.c > b/tools/testing/nvdimm/test/nfit.c > index 2b57254342aa..3d999f193471 100644 > --- a/tools/testing/nvdimm/test/nfit.c > +++ b/tools/testing/nvdimm/test/nfit.c > @@ -137,6 +137,14 @@ static u32 handle[] = { > > static unsigned long dimm_fail_cmd_flags[NUM_DCR]; > > +struct nfit_test_fw { > + enum intel_fw_update_state state; > + u32 context; > + u64 version; > + u32 size_received; > + u64 end_time; > +}; > + > struct nfit_test { > struct acpi_nfit_desc acpi_desc; > struct platform_device pdev; > @@ -172,6 +180,7 @@ struct nfit_test { > struct nd_intel_smart_threshold *smart_threshold; > struct badrange badrange; > struct work_struct work; > + struct nfit_test_fw *fw; > }; > > static struct workqueue_struct *nfit_wq; > @@ -183,6 +192,226 @@ static struct nfit_test *to_nfit_test(struct > device *dev) > return container_of(pdev, struct nfit_test, pdev); > } > > +static int nd_intel_test_get_fw_info(struct nfit_test *t, > + struct nd_intel_fw_info *nd_cmd, unsigned int > buf_len, > + int idx) > +{ > + struct device *dev = &t->pdev.dev; > + struct nfit_test_fw *fw = &t->fw[idx]; > + > + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p, buf_len: %u, idx: > %d\n", > + __func__, t, nd_cmd, buf_len, idx); > + > + if (buf_len < sizeof(*nd_cmd)) > + return -EINVAL; > + > + nd_cmd->status = 0; > + nd_cmd->storage_size = INTEL_FW_STORAGE_SIZE; > + nd_cmd->max_send_len = INTEL_FW_MAX_SEND_LEN; > + nd_cmd->query_interval = INTEL_FW_QUERY_INTERVAL; > + nd_cmd->max_query_time = INTEL_FW_QUERY_MAX_TIME; > + nd_cmd->update_cap = 0; > + nd_cmd->fis_version = INTEL_FW_FIS_VERSION; > + nd_cmd->run_version = 0; > + nd_cmd->updated_version = fw->version; > + > + return 0; > +} > + > +static int nd_intel_test_start_update(struct nfit_test *t, > + struct nd_intel_fw_start *nd_cmd, unsigned int > buf_len, > + int idx) > +{ > + struct device *dev = &t->pdev.dev; > + struct nfit_test_fw *fw = &t->fw[idx]; > + > + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: > %d)\n", > + __func__, t, nd_cmd, buf_len, idx); > + > + if (buf_len < sizeof(*nd_cmd)) > + return -EINVAL; > + > + if (fw->state != FW_STATE_NEW) { > + /* extended status, FW update in progress */ > + nd_cmd->status = 0x10007; > + return 0; > + } > + > + fw->state = FW_STATE_IN_PROGRESS; > + fw->context++; > + fw->size_received = 0; > + nd_cmd->status = 0; > + nd_cmd->context = fw->context; > + > + dev_dbg(dev, "%s: context issued: %#x\n", __func__, nd_cmd- > >context); > + > + return 0; > +} > + > +static int nd_intel_test_send_data(struct nfit_test *t, > + struct nd_intel_fw_send_data *nd_cmd, unsigned int > buf_len, > + int idx) > +{ > + struct device *dev = &t->pdev.dev; > + struct nfit_test_fw *fw = &t->fw[idx]; > + u32 *status = (u32 *)&nd_cmd->data[nd_cmd->length]; > + > + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: > %d)\n", > + __func__, t, nd_cmd, buf_len, idx); > + > + if (buf_len < sizeof(*nd_cmd)) > + return -EINVAL; > + > + > + dev_dbg(dev, "%s: cmd->status: %#x\n", __func__, *status); > + dev_dbg(dev, "%s: cmd->data[0]: %#x\n", __func__, nd_cmd- > >data[0]); > + dev_dbg(dev, "%s: cmd->data[%u]: %#x\n", __func__, nd_cmd- > >length-1, > + nd_cmd->data[nd_cmd->length-1]); > + > + if (fw->state != FW_STATE_IN_PROGRESS) { > + dev_dbg(dev, "%s: not in IN_PROGRESS state\n", > __func__); > + *status = 0x5; > + return 0; > + } > + > + if (nd_cmd->context != fw->context) { > + dev_dbg(dev, "%s: incorrect context: in: %#x > correct: %#x\n", > + __func__, nd_cmd->context, fw- > >context); > + *status = 0x10007; > + return 0; > + } > + > + /* > + * check offset + len > size of fw storage > + * check length is > max send length > + */ > + if (nd_cmd->offset + nd_cmd->length > INTEL_FW_STORAGE_SIZE > || > + nd_cmd->length > INTEL_FW_MAX_SEND_LEN) { > + *status = 0x3; > + dev_dbg(dev, "%s: buffer boundary violation\n", > __func__); > + return 0; > + } > + > + fw->size_received += nd_cmd->length; > + dev_dbg(dev, "%s: copying %u bytes, %u bytes so far\n", > + __func__, nd_cmd->length, fw- > >size_received); > + *status = 0; > + return 0; > +} > + > +static int nd_intel_test_finish_fw(struct nfit_test *t, > + struct nd_intel_fw_finish_update *nd_cmd, > + unsigned int buf_len, int idx) > +{ > + struct device *dev = &t->pdev.dev; > + struct nfit_test_fw *fw = &t->fw[idx]; > + > + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: > %d)\n", > + __func__, t, nd_cmd, buf_len, idx); > + > + if (fw->state == FW_STATE_UPDATED) { > + /* update already done, need cold boot */ > + nd_cmd->status = 0x20007; > + return 0; > + } > + > + dev_dbg(dev, "%s: context: %#x ctrl_flags: %#x\n", > + __func__, nd_cmd->context, nd_cmd- > >ctrl_flags); > + > + switch (nd_cmd->ctrl_flags) { > + case 0: /* finish */ > + if (nd_cmd->context != fw->context) { > + dev_dbg(dev, "%s: incorrect context: in: %#x > correct: %#x\n", > + __func__, nd_cmd->context, > + fw->context); > + nd_cmd->status = 0x10007; > + return 0; > + } > + nd_cmd->status = 0; > + fw->state = FW_STATE_VERIFY; > + /* set 1 second of time for firmware "update" */ > + fw->end_time = jiffies + HZ; > + break; > + > + case 1: /* abort */ > + fw->size_received = 0; > + /* successfully aborted status */ > + nd_cmd->status = 0x40007; > + fw->state = FW_STATE_NEW; > + dev_dbg(dev, "%s: abort successful\n", __func__); > + break; > + > + default: /* bad control flag */ > + dev_warn(dev, "%s: unknown control flag: %#x\n", > + __func__, nd_cmd->ctrl_flags); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int nd_intel_test_finish_query(struct nfit_test *t, > + struct nd_intel_fw_finish_query *nd_cmd, > + unsigned int buf_len, int idx) > +{ > + struct device *dev = &t->pdev.dev; > + struct nfit_test_fw *fw = &t->fw[idx]; > + > + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: > %d)\n", > + __func__, t, nd_cmd, buf_len, idx); > + > + if (buf_len < sizeof(*nd_cmd)) > + return -EINVAL; > + > + if (nd_cmd->context != fw->context) { > + dev_dbg(dev, "%s: incorrect context: in: %#x > correct: %#x\n", > + __func__, nd_cmd->context, fw- > >context); > + nd_cmd->status = 0x10007; > + return 0; > + } > + > + dev_dbg(dev, "%s context: %#x\n", __func__, nd_cmd- > >context); > + > + switch (fw->state) { > + case FW_STATE_NEW: > + nd_cmd->updated_fw_rev = 0; > + nd_cmd->status = 0; > + dev_dbg(dev, "%s: new state\n", __func__); > + break; > + > + case FW_STATE_IN_PROGRESS: > + /* sequencing error */ > + nd_cmd->status = 0x40007; > + nd_cmd->updated_fw_rev = 0; > + dev_dbg(dev, "%s: sequence error\n", __func__); > + break; > + > + case FW_STATE_VERIFY: > + if (time_is_after_jiffies64(fw->end_time)) { > + nd_cmd->updated_fw_rev = 0; > + nd_cmd->status = 0x20007; > + dev_dbg(dev, "%s: still verifying\n", > __func__); > + break; > + } > + > + dev_dbg(dev, "%s: transition out verify\n", > __func__); > + fw->state = FW_STATE_UPDATED; > + /* we are going to fall through if it's "done" */ > + case FW_STATE_UPDATED: > + nd_cmd->status = 0; > + /* bogus test version */ > + fw->version = nd_cmd->updated_fw_rev = > + INTEL_FW_FAKE_VERSION; > + dev_dbg(dev, "%s: updated\n", __func__); > + break; > + > + default: /* we should never get here */ > + return -EINVAL; > + } > + > + return 0; > +} > + > static int nfit_test_cmd_get_config_size(struct > nd_cmd_get_config_size *nd_cmd, > unsigned int buf_len) > { > @@ -592,6 +821,23 @@ static int > nfit_test_cmd_ars_inject_status(struct nfit_test *t, > return 0; > } > > +static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) > +{ > + int i; > + > + /* lookup per-dimm data */ > + for (i = 0; i < ARRAY_SIZE(handle); i++) > + if (__to_nfit_memdev(nfit_mem)->device_handle == > handle[i]) > + break; > + if (i >= ARRAY_SIZE(handle)) > + return -ENXIO; > + > + if ((1 << func) & dimm_fail_cmd_flags[i]) > + return -EIO; > + > + return i; > +} > + > static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, > struct nvdimm *nvdimm, unsigned int cmd, void *buf, > unsigned int buf_len, int *cmd_rc) > @@ -620,22 +866,39 @@ static int nfit_test_ctl(struct > nvdimm_bus_descriptor *nd_desc, > func = call_pkg->nd_command; > if (call_pkg->nd_family != nfit_mem->family) > return -ENOTTY; > + > + i = get_dimm(nfit_mem, func); > + if (i < 0) > + return i; > + > + switch (func) { > + case ND_INTEL_FW_GET_INFO: > + return nd_intel_test_get_fw_info(t, > buf, > + buf_len, i - t- > >dcr_idx); > + case ND_INTEL_FW_START_UPDATE: > + return nd_intel_test_start_update(t, > buf, > + buf_len, i - t- > >dcr_idx); > + case ND_INTEL_FW_SEND_DATA: > + return nd_intel_test_send_data(t, > buf, > + buf_len, i - t- > >dcr_idx); > + case ND_INTEL_FW_FINISH_UPDATE: > + return nd_intel_test_finish_fw(t, > buf, > + buf_len, i - t- > >dcr_idx); > + case ND_INTEL_FW_FINISH_QUERY: > + return nd_intel_test_finish_query(t, > buf, > + buf_len, i - t- > >dcr_idx); > + default: > + return -ENOTTY; > + } > } > > if (!test_bit(cmd, &cmd_mask) > || !test_bit(func, &nfit_mem- > >dsm_mask)) > return -ENOTTY; > > - /* lookup per-dimm data */ > - for (i = 0; i < ARRAY_SIZE(handle); i++) > - if (__to_nfit_memdev(nfit_mem)- > >device_handle == > - handle[i]) > - break; > - if (i >= ARRAY_SIZE(handle)) > - return -ENXIO; > - > - if ((1 << func) & dimm_fail_cmd_flags[i]) > - return -EIO; > + i = get_dimm(nfit_mem, func); > + if (i < 0) > + return i; > > switch (func) { > case ND_CMD_GET_CONFIG_SIZE: > @@ -1728,6 +1991,11 @@ static void nfit_test0_setup(struct nfit_test > *t) > set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc- > >bus_nfit_cmd_force_en); > set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc- > >bus_nfit_cmd_force_en); > set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc- > >bus_nfit_cmd_force_en); > + set_bit(ND_INTEL_FW_GET_INFO, &acpi_desc- > >dimm_cmd_force_en); > + set_bit(ND_INTEL_FW_START_UPDATE, &acpi_desc- > >dimm_cmd_force_en); > + set_bit(ND_INTEL_FW_SEND_DATA, &acpi_desc- > >dimm_cmd_force_en); > + set_bit(ND_INTEL_FW_FINISH_UPDATE, &acpi_desc- > >dimm_cmd_force_en); > + set_bit(ND_INTEL_FW_FINISH_QUERY, &acpi_desc- > >dimm_cmd_force_en); > } > > static void nfit_test1_setup(struct nfit_test *t) > @@ -2134,10 +2402,13 @@ static int nfit_test_probe(struct > platform_device *pdev) > nfit_test->smart_threshold = devm_kcalloc(dev, num, > sizeof(struct > nd_intel_smart_threshold), > GFP_KERNEL); > + nfit_test->fw = devm_kcalloc(dev, num, > + sizeof(struct nfit_test_fw), > GFP_KERNEL); > if (nfit_test->dimm && nfit_test->dimm_dma && > nfit_test->label > && nfit_test->label_dma && > nfit_test->dcr > && nfit_test->dcr_dma && nfit_test- > >flush > - && nfit_test->flush_dma) > + && nfit_test->flush_dma > + && nfit_test->fw) > /* pass */; > else > 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 { > } __packed record[0]; > } __packed; > > -#define ND_INTEL_SMART 1 > -#define ND_INTEL_SMART_THRESHOLD 2 > -#define ND_INTEL_SMART_SET_THRESHOLD 17 > +#define ND_INTEL_SMART 1 > +#define ND_INTEL_SMART_THRESHOLD 2 > +#define ND_INTEL_FW_GET_INFO 12 > +#define ND_INTEL_FW_START_UPDATE 13 > +#define ND_INTEL_FW_SEND_DATA 14 > +#define ND_INTEL_FW_FINISH_UPDATE 15 > +#define ND_INTEL_FW_FINISH_QUERY 16 > +#define ND_INTEL_SMART_SET_THRESHOLD 17 > > #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) > #define ND_INTEL_SMART_SPARES_VALID (1 << 1) > @@ -152,6 +157,61 @@ struct nd_intel_smart_set_threshold { > __u32 status; > } __packed; > > +#define INTEL_FW_STORAGE_SIZE 0x100000 > +#define INTEL_FW_MAX_SEND_LEN 0xFFEC > +#define INTEL_FW_QUERY_INTERVAL 250000 > +#define INTEL_FW_QUERY_MAX_TIME 3000000 > +#define INTEL_FW_FIS_VERSION 0x0105 > +#define INTEL_FW_FAKE_VERSION 0xffffffffabcd > + > +enum intel_fw_update_state { > + FW_STATE_NEW = 0, > + FW_STATE_IN_PROGRESS, > + FW_STATE_VERIFY, > + FW_STATE_UPDATED, > +}; > + > +struct nd_intel_fw_info { > + __u32 status; > + __u32 storage_size; > + __u32 max_send_len; > + __u32 query_interval; > + __u32 max_query_time; > + __u8 update_cap; > + __u8 reserved[3]; > + __u32 fis_version; > + __u64 run_version; > + __u64 updated_version; > +} __packed; > + > +struct nd_intel_fw_start { > + __u32 status; > + __u32 context; > +} __packed; > + > +/* this one has the output first because the variable input data > size */ > +struct nd_intel_fw_send_data { > + __u32 context; > + __u32 offset; > + __u32 length; > + __u8 data[0]; > +/* this field is not declared due ot variable data from input */ > +/* __u32 status; */ > +} __packed; > + > +struct nd_intel_fw_finish_update { > + __u8 ctrl_flags; > + __u8 reserved[3]; > + __u32 context; > + __u32 status; > +} __packed; > + > +struct nd_intel_fw_finish_query { > + __u32 context; > + __u32 status; > + __u64 updated_fw_rev; > +} __packed; > + > union acpi_object; > typedef void *acpi_handle; > > > _______________________________________________ > Linux-nvdimm mailing list > Linux-nvdimm@lists.01.org > https://lists.01.org/mailman/listinfo/linux-nvdimm _______________________________________________ Linux-nvdimm mailing list Linux-nvdimm@lists.01.org https://lists.01.org/mailman/listinfo/linux-nvdimm