|
@@ -147,75 +147,153 @@ static struct nfit_test *to_nfit_test(struct device *dev)
|
|
|
return container_of(pdev, struct nfit_test, pdev);
|
|
|
}
|
|
|
|
|
|
+static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd,
|
|
|
+ unsigned int buf_len)
|
|
|
+{
|
|
|
+ if (buf_len < sizeof(*nd_cmd))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ nd_cmd->status = 0;
|
|
|
+ nd_cmd->config_size = LABEL_SIZE;
|
|
|
+ nd_cmd->max_xfer = SZ_4K;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfit_test_cmd_get_config_data(struct nd_cmd_get_config_data_hdr
|
|
|
+ *nd_cmd, unsigned int buf_len, void *label)
|
|
|
+{
|
|
|
+ unsigned int len, offset = nd_cmd->in_offset;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ if (buf_len < sizeof(*nd_cmd))
|
|
|
+ return -EINVAL;
|
|
|
+ if (offset >= LABEL_SIZE)
|
|
|
+ return -EINVAL;
|
|
|
+ if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ nd_cmd->status = 0;
|
|
|
+ len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
|
|
+ memcpy(nd_cmd->out_buf, label + offset, len);
|
|
|
+ rc = buf_len - sizeof(*nd_cmd) - len;
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd,
|
|
|
+ unsigned int buf_len, void *label)
|
|
|
+{
|
|
|
+ unsigned int len, offset = nd_cmd->in_offset;
|
|
|
+ u32 *status;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ if (buf_len < sizeof(*nd_cmd))
|
|
|
+ return -EINVAL;
|
|
|
+ if (offset >= LABEL_SIZE)
|
|
|
+ return -EINVAL;
|
|
|
+ if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ status = (void *)nd_cmd + nd_cmd->in_length + sizeof(*nd_cmd);
|
|
|
+ *status = 0;
|
|
|
+ len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
|
|
+ memcpy(label + offset, nd_cmd->in_buf, len);
|
|
|
+ rc = buf_len - sizeof(*nd_cmd) - (len + 4);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd,
|
|
|
+ unsigned int buf_len)
|
|
|
+{
|
|
|
+ if (buf_len < sizeof(*nd_cmd))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ nd_cmd->max_ars_out = 256;
|
|
|
+ nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfit_test_cmd_ars_start(struct nd_cmd_ars_start *nd_cmd,
|
|
|
+ unsigned int buf_len)
|
|
|
+{
|
|
|
+ if (buf_len < sizeof(*nd_cmd))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ nd_cmd->status = 0;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
|
|
|
+ unsigned int buf_len)
|
|
|
+{
|
|
|
+ if (buf_len < sizeof(*nd_cmd))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ nd_cmd->out_length = 256;
|
|
|
+ nd_cmd->num_records = 0;
|
|
|
+ nd_cmd->status = 0;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
|
|
|
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
|
|
|
unsigned int buf_len)
|
|
|
{
|
|
|
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
|
|
|
struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc);
|
|
|
- struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
|
|
|
- int i, rc;
|
|
|
+ int i, rc = 0;
|
|
|
+
|
|
|
+ if (nvdimm) {
|
|
|
+ struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
|
|
|
|
|
|
- if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask))
|
|
|
- return -ENOTTY;
|
|
|
+ if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask))
|
|
|
+ return -ENOTTY;
|
|
|
|
|
|
- /* lookup label space for the given dimm */
|
|
|
- for (i = 0; i < ARRAY_SIZE(handle); i++)
|
|
|
- if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i])
|
|
|
+ /* lookup label space for the given dimm */
|
|
|
+ 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;
|
|
|
+
|
|
|
+ switch (cmd) {
|
|
|
+ case ND_CMD_GET_CONFIG_SIZE:
|
|
|
+ rc = nfit_test_cmd_get_config_size(buf, buf_len);
|
|
|
break;
|
|
|
- if (i >= ARRAY_SIZE(handle))
|
|
|
- return -ENXIO;
|
|
|
+ case ND_CMD_GET_CONFIG_DATA:
|
|
|
+ rc = nfit_test_cmd_get_config_data(buf, buf_len,
|
|
|
+ t->label[i]);
|
|
|
+ break;
|
|
|
+ case ND_CMD_SET_CONFIG_DATA:
|
|
|
+ rc = nfit_test_cmd_set_config_data(buf, buf_len,
|
|
|
+ t->label[i]);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -ENOTTY;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask))
|
|
|
+ return -ENOTTY;
|
|
|
|
|
|
- switch (cmd) {
|
|
|
- case ND_CMD_GET_CONFIG_SIZE: {
|
|
|
- struct nd_cmd_get_config_size *nd_cmd = buf;
|
|
|
-
|
|
|
- if (buf_len < sizeof(*nd_cmd))
|
|
|
- return -EINVAL;
|
|
|
- nd_cmd->status = 0;
|
|
|
- nd_cmd->config_size = LABEL_SIZE;
|
|
|
- nd_cmd->max_xfer = SZ_4K;
|
|
|
- rc = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
- case ND_CMD_GET_CONFIG_DATA: {
|
|
|
- struct nd_cmd_get_config_data_hdr *nd_cmd = buf;
|
|
|
- unsigned int len, offset = nd_cmd->in_offset;
|
|
|
-
|
|
|
- if (buf_len < sizeof(*nd_cmd))
|
|
|
- return -EINVAL;
|
|
|
- if (offset >= LABEL_SIZE)
|
|
|
- return -EINVAL;
|
|
|
- if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- nd_cmd->status = 0;
|
|
|
- len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
|
|
- memcpy(nd_cmd->out_buf, t->label[i] + offset, len);
|
|
|
- rc = buf_len - sizeof(*nd_cmd) - len;
|
|
|
- break;
|
|
|
- }
|
|
|
- case ND_CMD_SET_CONFIG_DATA: {
|
|
|
- struct nd_cmd_set_config_hdr *nd_cmd = buf;
|
|
|
- unsigned int len, offset = nd_cmd->in_offset;
|
|
|
- u32 *status;
|
|
|
-
|
|
|
- if (buf_len < sizeof(*nd_cmd))
|
|
|
- return -EINVAL;
|
|
|
- if (offset >= LABEL_SIZE)
|
|
|
- return -EINVAL;
|
|
|
- if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- status = buf + nd_cmd->in_length + sizeof(*nd_cmd);
|
|
|
- *status = 0;
|
|
|
- len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
|
|
- memcpy(t->label[i] + offset, nd_cmd->in_buf, len);
|
|
|
- rc = buf_len - sizeof(*nd_cmd) - (len + 4);
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- return -ENOTTY;
|
|
|
+ switch (cmd) {
|
|
|
+ case ND_CMD_ARS_CAP:
|
|
|
+ rc = nfit_test_cmd_ars_cap(buf, buf_len);
|
|
|
+ break;
|
|
|
+ case ND_CMD_ARS_START:
|
|
|
+ rc = nfit_test_cmd_ars_start(buf, buf_len);
|
|
|
+ break;
|
|
|
+ case ND_CMD_ARS_STATUS:
|
|
|
+ rc = nfit_test_cmd_ars_status(buf, buf_len);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -ENOTTY;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return rc;
|
|
@@ -876,6 +954,9 @@ static void nfit_test0_setup(struct nfit_test *t)
|
|
|
set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en);
|
|
|
set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
|
|
set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
|
|
+ set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en);
|
|
|
+ set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en);
|
|
|
+ set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en);
|
|
|
nd_desc = &acpi_desc->nd_desc;
|
|
|
nd_desc->ndctl = nfit_test_ctl;
|
|
|
}
|