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
124141struct 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};
11291150ATTRIBUTE_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+
11311233static 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+
12121328static 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
13251454static 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+
13271486static 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};
13321492ATTRIBUTE_GROUPS (cxl_mock_mem );
0 commit comments