Skip to content

Commit 916566a

Browse files
djbwstellarhopper
authored andcommitted
tools/testing/nvdimm: Emulate firmware activation commands
Augment the existing firmware update emulation to track activations and validate proper update vs activate sequencing. The DIMM firmware activate capability has a concept of a maximum amount of time platform firmware will quiesce the system relative to how many DIMMs are being activated in parallel. Simulate that DIMM activation happens serially, 1 second per-DIMM, and limit the max at 3 seconds. The nfit_test0 bus emulates 5 DIMMs so it will take 2 activations to update all DIMMs. Cc: Vishal Verma <[email protected]> Cc: Dave Jiang <[email protected]> Cc: Ira Weiny <[email protected]> Reported-by: Andy Shevchenko <[email protected]> Signed-off-by: Dan Williams <[email protected]> Signed-off-by: Vishal Verma <[email protected]>
1 parent abfd4d9 commit 916566a

File tree

2 files changed

+210
-4
lines changed

2 files changed

+210
-4
lines changed

drivers/acpi/nfit/intel.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ struct nd_intel_fw_activate_dimminfo {
132132
u8 reserved[7];
133133
} __packed;
134134

135+
#define ND_INTEL_DIMM_FWA_ARM 1
136+
#define ND_INTEL_DIMM_FWA_DISARM 0
137+
135138
struct nd_intel_fw_activate_arm {
136139
u8 activate_arm;
137140
u32 status;
@@ -160,6 +163,8 @@ struct nd_intel_bus_fw_activate_businfo {
160163
#define ND_INTEL_BUS_FWA_STATUS_NOIDLE (6 | 5 << 16)
161164
#define ND_INTEL_BUS_FWA_STATUS_ABORT (6 | 6 << 16)
162165

166+
#define ND_INTEL_BUS_FWA_IODEV_FORCE_IDLE (0)
167+
#define ND_INTEL_BUS_FWA_IODEV_OS_IDLE (1)
163168
struct nd_intel_bus_fw_activate {
164169
u8 iodev_state;
165170
u32 status;

tools/testing/nvdimm/test/nfit.c

Lines changed: 205 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ struct nfit_test_fw {
173173
u64 version;
174174
u32 size_received;
175175
u64 end_time;
176+
bool armed;
177+
bool missed_activate;
178+
unsigned long last_activate;
176179
};
177180

178181
struct nfit_test {
@@ -345,7 +348,7 @@ static int nd_intel_test_finish_fw(struct nfit_test *t,
345348
__func__, t, nd_cmd, buf_len, idx);
346349

347350
if (fw->state == FW_STATE_UPDATED) {
348-
/* update already done, need cold boot */
351+
/* update already done, need activation */
349352
nd_cmd->status = 0x20007;
350353
return 0;
351354
}
@@ -430,6 +433,7 @@ static int nd_intel_test_finish_query(struct nfit_test *t,
430433
}
431434
dev_dbg(dev, "%s: transition out verify\n", __func__);
432435
fw->state = FW_STATE_UPDATED;
436+
fw->missed_activate = false;
433437
/* fall through */
434438
case FW_STATE_UPDATED:
435439
nd_cmd->status = 0;
@@ -1178,6 +1182,134 @@ static int nd_intel_test_cmd_master_secure_erase(struct nfit_test *t,
11781182
return 0;
11791183
}
11801184

1185+
static unsigned long last_activate;
1186+
1187+
static int nvdimm_bus_intel_fw_activate_businfo(struct nfit_test *t,
1188+
struct nd_intel_bus_fw_activate_businfo *nd_cmd,
1189+
unsigned int buf_len)
1190+
{
1191+
int i, armed = 0;
1192+
int state;
1193+
u64 tmo;
1194+
1195+
for (i = 0; i < NUM_DCR; i++) {
1196+
struct nfit_test_fw *fw = &t->fw[i];
1197+
1198+
if (fw->armed)
1199+
armed++;
1200+
}
1201+
1202+
/*
1203+
* Emulate 3 second activation max, and 1 second incremental
1204+
* quiesce time per dimm requiring multiple activates to get all
1205+
* DIMMs updated.
1206+
*/
1207+
if (armed)
1208+
state = ND_INTEL_FWA_ARMED;
1209+
else if (!last_activate || time_after(jiffies, last_activate + 3 * HZ))
1210+
state = ND_INTEL_FWA_IDLE;
1211+
else
1212+
state = ND_INTEL_FWA_BUSY;
1213+
1214+
tmo = armed * USEC_PER_SEC;
1215+
*nd_cmd = (struct nd_intel_bus_fw_activate_businfo) {
1216+
.capability = ND_INTEL_BUS_FWA_CAP_FWQUIESCE
1217+
| ND_INTEL_BUS_FWA_CAP_OSQUIESCE
1218+
| ND_INTEL_BUS_FWA_CAP_RESET,
1219+
.state = state,
1220+
.activate_tmo = tmo,
1221+
.cpu_quiesce_tmo = tmo,
1222+
.io_quiesce_tmo = tmo,
1223+
.max_quiesce_tmo = 3 * USEC_PER_SEC,
1224+
};
1225+
1226+
return 0;
1227+
}
1228+
1229+
static int nvdimm_bus_intel_fw_activate(struct nfit_test *t,
1230+
struct nd_intel_bus_fw_activate *nd_cmd,
1231+
unsigned int buf_len)
1232+
{
1233+
struct nd_intel_bus_fw_activate_businfo info;
1234+
u32 status = 0;
1235+
int i;
1236+
1237+
nvdimm_bus_intel_fw_activate_businfo(t, &info, sizeof(info));
1238+
if (info.state == ND_INTEL_FWA_BUSY)
1239+
status = ND_INTEL_BUS_FWA_STATUS_BUSY;
1240+
else if (info.activate_tmo > info.max_quiesce_tmo)
1241+
status = ND_INTEL_BUS_FWA_STATUS_TMO;
1242+
else if (info.state == ND_INTEL_FWA_IDLE)
1243+
status = ND_INTEL_BUS_FWA_STATUS_NOARM;
1244+
1245+
dev_dbg(&t->pdev.dev, "status: %d\n", status);
1246+
nd_cmd->status = status;
1247+
if (status && status != ND_INTEL_BUS_FWA_STATUS_TMO)
1248+
return 0;
1249+
1250+
last_activate = jiffies;
1251+
for (i = 0; i < NUM_DCR; i++) {
1252+
struct nfit_test_fw *fw = &t->fw[i];
1253+
1254+
if (!fw->armed)
1255+
continue;
1256+
if (fw->state != FW_STATE_UPDATED)
1257+
fw->missed_activate = true;
1258+
else
1259+
fw->state = FW_STATE_NEW;
1260+
fw->armed = false;
1261+
fw->last_activate = last_activate;
1262+
}
1263+
1264+
return 0;
1265+
}
1266+
1267+
static int nd_intel_test_cmd_fw_activate_dimminfo(struct nfit_test *t,
1268+
struct nd_intel_fw_activate_dimminfo *nd_cmd,
1269+
unsigned int buf_len, int dimm)
1270+
{
1271+
struct nd_intel_bus_fw_activate_businfo info;
1272+
struct nfit_test_fw *fw = &t->fw[dimm];
1273+
u32 result, state;
1274+
1275+
nvdimm_bus_intel_fw_activate_businfo(t, &info, sizeof(info));
1276+
1277+
if (info.state == ND_INTEL_FWA_BUSY)
1278+
state = ND_INTEL_FWA_BUSY;
1279+
else if (info.state == ND_INTEL_FWA_IDLE)
1280+
state = ND_INTEL_FWA_IDLE;
1281+
else if (fw->armed)
1282+
state = ND_INTEL_FWA_ARMED;
1283+
else
1284+
state = ND_INTEL_FWA_IDLE;
1285+
1286+
result = ND_INTEL_DIMM_FWA_NONE;
1287+
if (last_activate && fw->last_activate == last_activate &&
1288+
state == ND_INTEL_FWA_IDLE) {
1289+
if (fw->missed_activate)
1290+
result = ND_INTEL_DIMM_FWA_NOTSTAGED;
1291+
else
1292+
result = ND_INTEL_DIMM_FWA_SUCCESS;
1293+
}
1294+
1295+
*nd_cmd = (struct nd_intel_fw_activate_dimminfo) {
1296+
.result = result,
1297+
.state = state,
1298+
};
1299+
1300+
return 0;
1301+
}
1302+
1303+
static int nd_intel_test_cmd_fw_activate_arm(struct nfit_test *t,
1304+
struct nd_intel_fw_activate_arm *nd_cmd,
1305+
unsigned int buf_len, int dimm)
1306+
{
1307+
struct nfit_test_fw *fw = &t->fw[dimm];
1308+
1309+
fw->armed = nd_cmd->activate_arm == ND_INTEL_DIMM_FWA_ARM;
1310+
nd_cmd->status = 0;
1311+
return 0;
1312+
}
11811313

11821314
static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func)
11831315
{
@@ -1296,6 +1428,14 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
12961428
rc = nd_intel_test_cmd_master_secure_erase(t,
12971429
buf, buf_len, i);
12981430
break;
1431+
case NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO:
1432+
rc = nd_intel_test_cmd_fw_activate_dimminfo(
1433+
t, buf, buf_len, i);
1434+
break;
1435+
case NVDIMM_INTEL_FW_ACTIVATE_ARM:
1436+
rc = nd_intel_test_cmd_fw_activate_arm(
1437+
t, buf, buf_len, i);
1438+
break;
12991439
case ND_INTEL_ENABLE_LSS_STATUS:
13001440
rc = nd_intel_test_cmd_set_lss_status(t,
13011441
buf, buf_len);
@@ -1380,9 +1520,9 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
13801520
if (!nd_desc)
13811521
return -ENOTTY;
13821522

1383-
if (cmd == ND_CMD_CALL) {
1523+
if (cmd == ND_CMD_CALL && call_pkg->nd_family
1524+
== NVDIMM_BUS_FAMILY_NFIT) {
13841525
func = call_pkg->nd_command;
1385-
13861526
buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out;
13871527
buf = (void *) call_pkg->nd_payload;
13881528

@@ -1406,7 +1546,26 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
14061546
default:
14071547
return -ENOTTY;
14081548
}
1409-
}
1549+
} else if (cmd == ND_CMD_CALL && call_pkg->nd_family
1550+
== NVDIMM_BUS_FAMILY_INTEL) {
1551+
func = call_pkg->nd_command;
1552+
buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out;
1553+
buf = (void *) call_pkg->nd_payload;
1554+
1555+
switch (func) {
1556+
case NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO:
1557+
rc = nvdimm_bus_intel_fw_activate_businfo(t,
1558+
buf, buf_len);
1559+
return rc;
1560+
case NVDIMM_BUS_INTEL_FW_ACTIVATE:
1561+
rc = nvdimm_bus_intel_fw_activate(t, buf,
1562+
buf_len);
1563+
return rc;
1564+
default:
1565+
return -ENOTTY;
1566+
}
1567+
} else if (cmd == ND_CMD_CALL)
1568+
return -ENOTTY;
14101569

14111570
if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask))
14121571
return -ENOTTY;
@@ -1832,6 +1991,7 @@ static void nfit_test0_setup(struct nfit_test *t)
18321991
struct acpi_nfit_flush_address *flush;
18331992
struct acpi_nfit_capabilities *pcap;
18341993
unsigned int offset = 0, i;
1994+
unsigned long *acpi_mask;
18351995

18361996
/*
18371997
* spa0 (interleave first half of dimm0 and dimm1, note storage
@@ -2558,6 +2718,12 @@ static void nfit_test0_setup(struct nfit_test *t)
25582718
&acpi_desc->dimm_cmd_force_en);
25592719
set_bit(NVDIMM_INTEL_MASTER_SECURE_ERASE,
25602720
&acpi_desc->dimm_cmd_force_en);
2721+
set_bit(NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO, &acpi_desc->dimm_cmd_force_en);
2722+
set_bit(NVDIMM_INTEL_FW_ACTIVATE_ARM, &acpi_desc->dimm_cmd_force_en);
2723+
2724+
acpi_mask = &acpi_desc->family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL];
2725+
set_bit(NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO, acpi_mask);
2726+
set_bit(NVDIMM_BUS_INTEL_FW_ACTIVATE, acpi_mask);
25612727
}
25622728

25632729
static void nfit_test1_setup(struct nfit_test *t)
@@ -2733,6 +2899,7 @@ static int nfit_ctl_test(struct device *dev)
27332899
struct nd_cmd_clear_error clear_err;
27342900
struct nd_cmd_ars_status ars_stat;
27352901
struct nd_cmd_ars_cap ars_cap;
2902+
struct nd_intel_bus_fw_activate_businfo fwa_info;
27362903
char buf[sizeof(struct nd_cmd_ars_status)
27372904
+ sizeof(struct nd_ars_record)];
27382905
};
@@ -2761,11 +2928,15 @@ static int nfit_ctl_test(struct device *dev)
27612928
.module = THIS_MODULE,
27622929
.provider_name = "ACPI.NFIT",
27632930
.ndctl = acpi_nfit_ctl,
2931+
.bus_family_mask = 1UL << NVDIMM_BUS_FAMILY_NFIT
2932+
| 1UL << NVDIMM_BUS_FAMILY_INTEL,
27642933
},
27652934
.bus_dsm_mask = 1UL << NFIT_CMD_TRANSLATE_SPA
27662935
| 1UL << NFIT_CMD_ARS_INJECT_SET
27672936
| 1UL << NFIT_CMD_ARS_INJECT_CLEAR
27682937
| 1UL << NFIT_CMD_ARS_INJECT_GET,
2938+
.family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL] =
2939+
NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK,
27692940
.dev = &adev->dev,
27702941
};
27712942

@@ -2932,6 +3103,36 @@ static int nfit_ctl_test(struct device *dev)
29323103
return -EIO;
29333104
}
29343105

3106+
/* test firmware activate bus info */
3107+
cmd_size = sizeof(cmd.fwa_info);
3108+
cmd = (struct nfit_ctl_test_cmd) {
3109+
.pkg = {
3110+
.nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO,
3111+
.nd_family = NVDIMM_BUS_FAMILY_INTEL,
3112+
.nd_size_out = cmd_size,
3113+
.nd_fw_size = cmd_size,
3114+
},
3115+
.fwa_info = {
3116+
.state = ND_INTEL_FWA_IDLE,
3117+
.capability = ND_INTEL_BUS_FWA_CAP_FWQUIESCE
3118+
| ND_INTEL_BUS_FWA_CAP_OSQUIESCE,
3119+
.activate_tmo = 1,
3120+
.cpu_quiesce_tmo = 1,
3121+
.io_quiesce_tmo = 1,
3122+
.max_quiesce_tmo = 1,
3123+
},
3124+
};
3125+
rc = setup_result(cmd.buf, cmd_size);
3126+
if (rc)
3127+
return rc;
3128+
rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_CALL,
3129+
&cmd, sizeof(cmd.pkg) + cmd_size, &cmd_rc);
3130+
if (rc < 0 || cmd_rc) {
3131+
dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
3132+
__func__, __LINE__, rc, cmd_rc);
3133+
return -EIO;
3134+
}
3135+
29353136
return 0;
29363137
}
29373138

0 commit comments

Comments
 (0)