Skip to content

Commit f6448cb

Browse files
stellarhopperdjbw
authored andcommitted
tools/testing/cxl: add firmware update emulation to CXL memdevs
Add emulation for the 'Get FW Info', 'Transfer FW', and 'Activate FW' CXL mailbox commands to the cxl_test emulated memdevs to enable end-to-end unit testing of a firmware update flow. For now, only advertise an 'offline activation' capability as that is all the CXL memdev driver currently implements. Add some canned values for the serial number fields, and create a platform device sysfs knob to calculate the sha256sum of the firmware image that was received, so a unit test can compare it with the original file that was uploaded. Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Jonathan Cameron <Jonathan.Cameron@Huawei.com> Cc: Russ Weight <russell.h.weight@intel.com> Cc: Alison Schofield <alison.schofield@intel.com> Cc: Ira Weiny <ira.weiny@intel.com> Cc: Dave Jiang <dave.jiang@intel.com> Cc: Ben Widawsky <bwidawsk@kernel.org> Cc: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> Link: https://lore.kernel.org/r/20230602-vv-fw_update-v4-4-c6265bd7343b@intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 6e4ca04 commit f6448cb

1 file changed

Lines changed: 160 additions & 0 deletions

File tree

  • tools/testing/cxl/test

tools/testing/cxl/test/mem.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
#include <linux/sizes.h>
99
#include <linux/bits.h>
1010
#include <asm/unaligned.h>
11+
#include <crypto/sha2.h>
1112
#include <cxlmem.h>
1213

1314
#include "trace.h"
1415

1516
#define LSA_SIZE SZ_128K
17+
#define FW_SIZE SZ_64M
18+
#define FW_SLOTS 3
1619
#define DEV_SIZE SZ_2G
1720
#define EFFECT(x) (1U << x)
1821

@@ -72,6 +75,20 @@ static struct cxl_cel_entry mock_cel[] = {
7275
.opcode = cpu_to_le16(CXL_MBOX_OP_CLEAR_POISON),
7376
.effect = cpu_to_le16(EFFECT(DATA_CHANGE_IMMEDIATE)),
7477
},
78+
{
79+
.opcode = cpu_to_le16(CXL_MBOX_OP_GET_FW_INFO),
80+
.effect = CXL_CMD_EFFECT_NONE,
81+
},
82+
{
83+
.opcode = cpu_to_le16(CXL_MBOX_OP_TRANSFER_FW),
84+
.effect = cpu_to_le16(EFFECT(CONF_CHANGE_COLD_RESET) |
85+
EFFECT(BACKGROUND_OP)),
86+
},
87+
{
88+
.opcode = cpu_to_le16(CXL_MBOX_OP_ACTIVATE_FW),
89+
.effect = cpu_to_le16(EFFECT(CONF_CHANGE_COLD_RESET) |
90+
EFFECT(CONF_CHANGE_IMMEDIATE)),
91+
},
7592
};
7693

7794
/* See CXL 2.0 Table 181 Get Health Info Output Payload */
@@ -123,6 +140,10 @@ struct mock_event_store {
123140

124141
struct cxl_mockmem_data {
125142
void *lsa;
143+
void *fw;
144+
int fw_slot;
145+
int fw_staged;
146+
size_t fw_size;
126147
u32 security_state;
127148
u8 user_pass[NVDIMM_PASSPHRASE_LEN];
128149
u8 master_pass[NVDIMM_PASSPHRASE_LEN];
@@ -1128,6 +1149,87 @@ static struct attribute *cxl_mock_mem_core_attrs[] = {
11281149
};
11291150
ATTRIBUTE_GROUPS(cxl_mock_mem_core);
11301151

1152+
static int mock_fw_info(struct cxl_dev_state *cxlds,
1153+
struct cxl_mbox_cmd *cmd)
1154+
{
1155+
struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
1156+
struct cxl_mbox_get_fw_info fw_info = {
1157+
.num_slots = FW_SLOTS,
1158+
.slot_info = (mdata->fw_slot & 0x7) |
1159+
((mdata->fw_staged & 0x7) << 3),
1160+
.activation_cap = 0,
1161+
};
1162+
1163+
strcpy(fw_info.slot_1_revision, "cxl_test_fw_001");
1164+
strcpy(fw_info.slot_2_revision, "cxl_test_fw_002");
1165+
strcpy(fw_info.slot_3_revision, "cxl_test_fw_003");
1166+
strcpy(fw_info.slot_4_revision, "");
1167+
1168+
if (cmd->size_out < sizeof(fw_info))
1169+
return -EINVAL;
1170+
1171+
memcpy(cmd->payload_out, &fw_info, sizeof(fw_info));
1172+
return 0;
1173+
}
1174+
1175+
static int mock_transfer_fw(struct cxl_dev_state *cxlds,
1176+
struct cxl_mbox_cmd *cmd)
1177+
{
1178+
struct cxl_mbox_transfer_fw *transfer = cmd->payload_in;
1179+
struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
1180+
void *fw = mdata->fw;
1181+
size_t offset, length;
1182+
1183+
offset = le32_to_cpu(transfer->offset) * CXL_FW_TRANSFER_ALIGNMENT;
1184+
length = cmd->size_in - sizeof(*transfer);
1185+
if (offset + length > FW_SIZE)
1186+
return -EINVAL;
1187+
1188+
switch (transfer->action) {
1189+
case CXL_FW_TRANSFER_ACTION_FULL:
1190+
if (offset != 0)
1191+
return -EINVAL;
1192+
fallthrough;
1193+
case CXL_FW_TRANSFER_ACTION_END:
1194+
if (transfer->slot == 0 || transfer->slot > FW_SLOTS)
1195+
return -EINVAL;
1196+
mdata->fw_size = offset + length;
1197+
break;
1198+
case CXL_FW_TRANSFER_ACTION_INITIATE:
1199+
case CXL_FW_TRANSFER_ACTION_CONTINUE:
1200+
break;
1201+
case CXL_FW_TRANSFER_ACTION_ABORT:
1202+
return 0;
1203+
default:
1204+
return -EINVAL;
1205+
}
1206+
1207+
memcpy(fw + offset, transfer->data, length);
1208+
return 0;
1209+
}
1210+
1211+
static int mock_activate_fw(struct cxl_dev_state *cxlds,
1212+
struct cxl_mbox_cmd *cmd)
1213+
{
1214+
struct cxl_mbox_activate_fw *activate = cmd->payload_in;
1215+
struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
1216+
1217+
if (activate->slot == 0 || activate->slot > FW_SLOTS)
1218+
return -EINVAL;
1219+
1220+
switch (activate->action) {
1221+
case CXL_FW_ACTIVATE_ONLINE:
1222+
mdata->fw_slot = activate->slot;
1223+
mdata->fw_staged = 0;
1224+
return 0;
1225+
case CXL_FW_ACTIVATE_OFFLINE:
1226+
mdata->fw_staged = activate->slot;
1227+
return 0;
1228+
}
1229+
1230+
return -EINVAL;
1231+
}
1232+
11311233
static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
11321234
{
11331235
struct device *dev = cxlds->dev;
@@ -1194,6 +1296,15 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *
11941296
case CXL_MBOX_OP_CLEAR_POISON:
11951297
rc = mock_clear_poison(cxlds, cmd);
11961298
break;
1299+
case CXL_MBOX_OP_GET_FW_INFO:
1300+
rc = mock_fw_info(cxlds, cmd);
1301+
break;
1302+
case CXL_MBOX_OP_TRANSFER_FW:
1303+
rc = mock_transfer_fw(cxlds, cmd);
1304+
break;
1305+
case CXL_MBOX_OP_ACTIVATE_FW:
1306+
rc = mock_activate_fw(cxlds, cmd);
1307+
break;
11971308
default:
11981309
break;
11991310
}
@@ -1209,6 +1320,11 @@ static void label_area_release(void *lsa)
12091320
vfree(lsa);
12101321
}
12111322

1323+
static void fw_buf_release(void *buf)
1324+
{
1325+
vfree(buf);
1326+
}
1327+
12121328
static bool is_rcd(struct platform_device *pdev)
12131329
{
12141330
const struct platform_device_id *id = platform_get_device_id(pdev);
@@ -1241,10 +1357,19 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
12411357
mdata->lsa = vmalloc(LSA_SIZE);
12421358
if (!mdata->lsa)
12431359
return -ENOMEM;
1360+
mdata->fw = vmalloc(FW_SIZE);
1361+
if (!mdata->fw)
1362+
return -ENOMEM;
1363+
mdata->fw_slot = 2;
1364+
12441365
rc = devm_add_action_or_reset(dev, label_area_release, mdata->lsa);
12451366
if (rc)
12461367
return rc;
12471368

1369+
rc = devm_add_action_or_reset(dev, fw_buf_release, mdata->fw);
1370+
if (rc)
1371+
return rc;
1372+
12481373
cxlds = cxl_dev_state_create(dev);
12491374
if (IS_ERR(cxlds))
12501375
return PTR_ERR(cxlds);
@@ -1286,6 +1411,10 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
12861411
if (IS_ERR(cxlmd))
12871412
return PTR_ERR(cxlmd);
12881413

1414+
rc = cxl_memdev_setup_fw_upload(cxlds);
1415+
if (rc)
1416+
return rc;
1417+
12891418
cxl_mem_get_event_records(cxlds, CXLDEV_EVENT_STATUS_ALL);
12901419

12911420
return 0;
@@ -1324,9 +1453,40 @@ static ssize_t security_lock_store(struct device *dev, struct device_attribute *
13241453

13251454
static DEVICE_ATTR_RW(security_lock);
13261455

1456+
static ssize_t fw_buf_checksum_show(struct device *dev,
1457+
struct device_attribute *attr, char *buf)
1458+
{
1459+
struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
1460+
u8 hash[SHA256_DIGEST_SIZE];
1461+
unsigned char *hstr, *hptr;
1462+
struct sha256_state sctx;
1463+
ssize_t written = 0;
1464+
int i;
1465+
1466+
sha256_init(&sctx);
1467+
sha256_update(&sctx, mdata->fw, mdata->fw_size);
1468+
sha256_final(&sctx, hash);
1469+
1470+
hstr = kzalloc((SHA256_DIGEST_SIZE * 2) + 1, GFP_KERNEL);
1471+
if (!hstr)
1472+
return -ENOMEM;
1473+
1474+
hptr = hstr;
1475+
for (i = 0; i < SHA256_DIGEST_SIZE; i++)
1476+
hptr += sprintf(hptr, "%02x", hash[i]);
1477+
1478+
written = sysfs_emit(buf, "%s\n", hstr);
1479+
1480+
kfree(hstr);
1481+
return written;
1482+
}
1483+
1484+
static DEVICE_ATTR_RO(fw_buf_checksum);
1485+
13271486
static struct attribute *cxl_mock_mem_attrs[] = {
13281487
&dev_attr_security_lock.attr,
13291488
&dev_attr_event_trigger.attr,
1489+
&dev_attr_fw_buf_checksum.attr,
13301490
NULL
13311491
};
13321492
ATTRIBUTE_GROUPS(cxl_mock_mem);

0 commit comments

Comments
 (0)