Skip to content

Commit 6450ddb

Browse files
djbwstellarhopper
authored andcommitted
ACPI: NFIT: Define runtime firmware activation commands
Platform reboots are expensive. Towards reducing downtime to apply firmware updates the Intel NVDIMM command definition is growing support for applying live firmware updates that only require temporarily suspending memory traffic instead of a full reboot. Follow-on commits add support for triggering firmware activation, this patch only defines the commands, adds probe support, and validates that they are blocked via the ioctl path. The ioctl-path block ensures that the OS is in charge since these commands have side effects only the OS can handle. Specifically firmware activation may cause the memory controller to be quiesced on the order of 100s of milliseconds. In that case Linux ensure the activation only takes place while the OS is in a suspend state. Link: https://pmem.io/documents/IntelOptanePMem_DSM_Interface-V2.0.pdf Cc: Vishal Verma <[email protected]> Cc: Dave Jiang <[email protected]> Cc: Ira Weiny <[email protected]> Cc: "Rafael J. Wysocki" <[email protected]> Cc: Len Brown <[email protected]> Signed-off-by: Dan Williams <[email protected]> Signed-off-by: Vishal Verma <[email protected]>
1 parent d46e6a2 commit 6450ddb

File tree

4 files changed

+137
-30
lines changed

4 files changed

+137
-30
lines changed

drivers/acpi/nfit/core.c

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ const guid_t *to_nfit_uuid(enum nfit_uuids id)
7373
}
7474
EXPORT_SYMBOL(to_nfit_uuid);
7575

76+
static const guid_t *to_nfit_bus_uuid(int family)
77+
{
78+
if (WARN_ONCE(family == NVDIMM_BUS_FAMILY_NFIT,
79+
"only secondary bus families can be translated\n"))
80+
return NULL;
81+
/*
82+
* The index of bus UUIDs starts immediately following the last
83+
* NVDIMM/leaf family.
84+
*/
85+
return to_nfit_uuid(family + NVDIMM_FAMILY_MAX);
86+
}
87+
7688
static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
7789
{
7890
struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
@@ -362,24 +374,8 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func)
362374
{
363375
static const u8 revid_table[NVDIMM_FAMILY_MAX+1][NVDIMM_CMD_MAX+1] = {
364376
[NVDIMM_FAMILY_INTEL] = {
365-
[NVDIMM_INTEL_GET_MODES] = 2,
366-
[NVDIMM_INTEL_GET_FWINFO] = 2,
367-
[NVDIMM_INTEL_START_FWUPDATE] = 2,
368-
[NVDIMM_INTEL_SEND_FWUPDATE] = 2,
369-
[NVDIMM_INTEL_FINISH_FWUPDATE] = 2,
370-
[NVDIMM_INTEL_QUERY_FWUPDATE] = 2,
371-
[NVDIMM_INTEL_SET_THRESHOLD] = 2,
372-
[NVDIMM_INTEL_INJECT_ERROR] = 2,
373-
[NVDIMM_INTEL_GET_SECURITY_STATE] = 2,
374-
[NVDIMM_INTEL_SET_PASSPHRASE] = 2,
375-
[NVDIMM_INTEL_DISABLE_PASSPHRASE] = 2,
376-
[NVDIMM_INTEL_UNLOCK_UNIT] = 2,
377-
[NVDIMM_INTEL_FREEZE_LOCK] = 2,
378-
[NVDIMM_INTEL_SECURE_ERASE] = 2,
379-
[NVDIMM_INTEL_OVERWRITE] = 2,
380-
[NVDIMM_INTEL_QUERY_OVERWRITE] = 2,
381-
[NVDIMM_INTEL_SET_MASTER_PASSPHRASE] = 2,
382-
[NVDIMM_INTEL_MASTER_SECURE_ERASE] = 2,
377+
[NVDIMM_INTEL_GET_MODES ...
378+
NVDIMM_INTEL_FW_ACTIVATE_ARM] = 2,
383379
},
384380
};
385381
u8 id;
@@ -406,7 +402,7 @@ static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func)
406402
}
407403

408404
static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd,
409-
struct nd_cmd_pkg *call_pkg)
405+
struct nd_cmd_pkg *call_pkg, int *family)
410406
{
411407
if (call_pkg) {
412408
int i;
@@ -417,6 +413,7 @@ static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd,
417413
for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++)
418414
if (call_pkg->nd_reserved2[i])
419415
return -EINVAL;
416+
*family = call_pkg->nd_family;
420417
return call_pkg->nd_command;
421418
}
422419

@@ -450,13 +447,14 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
450447
acpi_handle handle;
451448
const guid_t *guid;
452449
int func, rc, i;
450+
int family = 0;
453451

454452
if (cmd_rc)
455453
*cmd_rc = -EINVAL;
456454

457455
if (cmd == ND_CMD_CALL)
458456
call_pkg = buf;
459-
func = cmd_to_func(nfit_mem, cmd, call_pkg);
457+
func = cmd_to_func(nfit_mem, cmd, call_pkg, &family);
460458
if (func < 0)
461459
return func;
462460

@@ -478,9 +476,17 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
478476

479477
cmd_name = nvdimm_bus_cmd_name(cmd);
480478
cmd_mask = nd_desc->cmd_mask;
481-
dsm_mask = acpi_desc->bus_dsm_mask;
479+
if (cmd == ND_CMD_CALL && call_pkg->nd_family) {
480+
family = call_pkg->nd_family;
481+
if (!test_bit(family, &nd_desc->bus_family_mask))
482+
return -EINVAL;
483+
dsm_mask = acpi_desc->family_dsm_mask[family];
484+
guid = to_nfit_bus_uuid(family);
485+
} else {
486+
dsm_mask = acpi_desc->bus_dsm_mask;
487+
guid = to_nfit_uuid(NFIT_DEV_BUS);
488+
}
482489
desc = nd_cmd_bus_desc(cmd);
483-
guid = to_nfit_uuid(NFIT_DEV_BUS);
484490
handle = adev->handle;
485491
dimm_name = "bus";
486492
}
@@ -516,8 +522,8 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
516522
in_buf.buffer.length = call_pkg->nd_size_in;
517523
}
518524

519-
dev_dbg(dev, "%s cmd: %d: func: %d input length: %d\n",
520-
dimm_name, cmd, func, in_buf.buffer.length);
525+
dev_dbg(dev, "%s cmd: %d: family: %d func: %d input length: %d\n",
526+
dimm_name, cmd, family, func, in_buf.buffer.length);
521527
if (payload_dumpable(nvdimm, func))
522528
print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4,
523529
in_buf.buffer.pointer,
@@ -2153,14 +2159,21 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
21532159
{
21542160
struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
21552161
const guid_t *guid = to_nfit_uuid(NFIT_DEV_BUS);
2162+
unsigned long dsm_mask, *mask;
21562163
struct acpi_device *adev;
2157-
unsigned long dsm_mask;
21582164
int i;
21592165

2160-
nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
21612166
set_bit(ND_CMD_CALL, &nd_desc->cmd_mask);
21622167
set_bit(NVDIMM_BUS_FAMILY_NFIT, &nd_desc->bus_family_mask);
21632168

2169+
/* enable nfit_test to inject bus command emulation */
2170+
if (acpi_desc->bus_cmd_force_en) {
2171+
nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;
2172+
mask = &nd_desc->bus_family_mask;
2173+
if (acpi_desc->family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL])
2174+
set_bit(NVDIMM_BUS_FAMILY_INTEL, mask);
2175+
}
2176+
21642177
adev = to_acpi_dev(acpi_desc);
21652178
if (!adev)
21662179
return;
@@ -2181,6 +2194,14 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
21812194
for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
21822195
if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i))
21832196
set_bit(i, &acpi_desc->bus_dsm_mask);
2197+
2198+
/* Enumerate allowed NVDIMM_BUS_FAMILY_INTEL commands */
2199+
dsm_mask = NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK;
2200+
guid = to_nfit_bus_uuid(NVDIMM_BUS_FAMILY_INTEL);
2201+
mask = &acpi_desc->family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL];
2202+
for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
2203+
if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i))
2204+
set_bit(i, mask);
21842205
}
21852206

21862207
static ssize_t range_index_show(struct device *dev,
@@ -3492,7 +3513,10 @@ static int __acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
34923513
return 0;
34933514
}
34943515

3495-
/* prevent security commands from being issued via ioctl */
3516+
/*
3517+
* Prevent security and firmware activate commands from being issued via
3518+
* ioctl.
3519+
*/
34963520
static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
34973521
struct nvdimm *nvdimm, unsigned int cmd, void *buf)
34983522
{
@@ -3503,10 +3527,15 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
35033527
call_pkg->nd_family == NVDIMM_FAMILY_INTEL) {
35043528
func = call_pkg->nd_command;
35053529
if (func > NVDIMM_CMD_MAX ||
3506-
(1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK)
3530+
(1 << func) & NVDIMM_INTEL_DENY_CMDMASK)
35073531
return -EOPNOTSUPP;
35083532
}
35093533

3534+
/* block all non-nfit bus commands */
3535+
if (!nvdimm && cmd == ND_CMD_CALL &&
3536+
call_pkg->nd_family != NVDIMM_BUS_FAMILY_NFIT)
3537+
return -EOPNOTSUPP;
3538+
35103539
return __acpi_nfit_clear_to_send(nd_desc, nvdimm, cmd);
35113540
}
35123541

@@ -3798,6 +3827,7 @@ static __init int nfit_init(void)
37983827
guid_parse(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
37993828
guid_parse(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
38003829
guid_parse(UUID_NFIT_DIMM_N_HYPERV, &nfit_uuid[NFIT_DEV_DIMM_N_HYPERV]);
3830+
guid_parse(UUID_INTEL_BUS, &nfit_uuid[NFIT_BUS_INTEL]);
38013831

38023832
nfit_wq = create_singlethread_workqueue("nfit");
38033833
if (!nfit_wq)

drivers/acpi/nfit/intel.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,57 @@ struct nd_intel_master_secure_erase {
111111
u8 passphrase[ND_INTEL_PASSPHRASE_SIZE];
112112
u32 status;
113113
} __packed;
114+
115+
#define ND_INTEL_FWA_IDLE 0
116+
#define ND_INTEL_FWA_ARMED 1
117+
#define ND_INTEL_FWA_BUSY 2
118+
119+
#define ND_INTEL_DIMM_FWA_NONE 0
120+
#define ND_INTEL_DIMM_FWA_NOTSTAGED 1
121+
#define ND_INTEL_DIMM_FWA_SUCCESS 2
122+
#define ND_INTEL_DIMM_FWA_NEEDRESET 3
123+
#define ND_INTEL_DIMM_FWA_MEDIAFAILED 4
124+
#define ND_INTEL_DIMM_FWA_ABORT 5
125+
#define ND_INTEL_DIMM_FWA_NOTSUPP 6
126+
#define ND_INTEL_DIMM_FWA_ERROR 7
127+
128+
struct nd_intel_fw_activate_dimminfo {
129+
u32 status;
130+
u16 result;
131+
u8 state;
132+
u8 reserved[7];
133+
} __packed;
134+
135+
struct nd_intel_fw_activate_arm {
136+
u8 activate_arm;
137+
u32 status;
138+
} __packed;
139+
140+
/* Root device command payloads */
141+
#define ND_INTEL_BUS_FWA_CAP_FWQUIESCE (1 << 0)
142+
#define ND_INTEL_BUS_FWA_CAP_OSQUIESCE (1 << 1)
143+
#define ND_INTEL_BUS_FWA_CAP_RESET (1 << 2)
144+
145+
struct nd_intel_bus_fw_activate_businfo {
146+
u32 status;
147+
u16 reserved;
148+
u8 state;
149+
u8 capability;
150+
u64 activate_tmo;
151+
u64 cpu_quiesce_tmo;
152+
u64 io_quiesce_tmo;
153+
u64 max_quiesce_tmo;
154+
} __packed;
155+
156+
#define ND_INTEL_BUS_FWA_STATUS_NOARM (6 | 1 << 16)
157+
#define ND_INTEL_BUS_FWA_STATUS_BUSY (6 | 2 << 16)
158+
#define ND_INTEL_BUS_FWA_STATUS_NOFW (6 | 3 << 16)
159+
#define ND_INTEL_BUS_FWA_STATUS_TMO (6 | 4 << 16)
160+
#define ND_INTEL_BUS_FWA_STATUS_NOIDLE (6 | 5 << 16)
161+
#define ND_INTEL_BUS_FWA_STATUS_ABORT (6 | 6 << 16)
162+
163+
struct nd_intel_bus_fw_activate {
164+
u8 iodev_state;
165+
u32 status;
166+
} __packed;
114167
#endif

drivers/acpi/nfit/nfit.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
/* http://pmem.io/documents/NVDIMM_DSM_Interface-V1.6.pdf */
2020
#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
21+
#define UUID_INTEL_BUS "c7d8acd4-2df8-4b82-9f65-a325335af149"
2122

2223
/* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */
2324
#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"
@@ -65,6 +66,13 @@ enum nvdimm_family_cmds {
6566
NVDIMM_INTEL_QUERY_OVERWRITE = 26,
6667
NVDIMM_INTEL_SET_MASTER_PASSPHRASE = 27,
6768
NVDIMM_INTEL_MASTER_SECURE_ERASE = 28,
69+
NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO = 29,
70+
NVDIMM_INTEL_FW_ACTIVATE_ARM = 30,
71+
};
72+
73+
enum nvdimm_bus_family_cmds {
74+
NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO = 1,
75+
NVDIMM_BUS_INTEL_FW_ACTIVATE = 2,
6876
};
6977

7078
#define NVDIMM_INTEL_SECURITY_CMDMASK \
@@ -75,13 +83,22 @@ enum nvdimm_family_cmds {
7583
| 1 << NVDIMM_INTEL_SET_MASTER_PASSPHRASE \
7684
| 1 << NVDIMM_INTEL_MASTER_SECURE_ERASE)
7785

86+
#define NVDIMM_INTEL_FW_ACTIVATE_CMDMASK \
87+
(1 << NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO | 1 << NVDIMM_INTEL_FW_ACTIVATE_ARM)
88+
89+
#define NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK \
90+
(1 << NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO | 1 << NVDIMM_BUS_INTEL_FW_ACTIVATE)
91+
7892
#define NVDIMM_INTEL_CMDMASK \
7993
(NVDIMM_STANDARD_CMDMASK | 1 << NVDIMM_INTEL_GET_MODES \
8094
| 1 << NVDIMM_INTEL_GET_FWINFO | 1 << NVDIMM_INTEL_START_FWUPDATE \
8195
| 1 << NVDIMM_INTEL_SEND_FWUPDATE | 1 << NVDIMM_INTEL_FINISH_FWUPDATE \
8296
| 1 << NVDIMM_INTEL_QUERY_FWUPDATE | 1 << NVDIMM_INTEL_SET_THRESHOLD \
8397
| 1 << NVDIMM_INTEL_INJECT_ERROR | 1 << NVDIMM_INTEL_LATCH_SHUTDOWN \
84-
| NVDIMM_INTEL_SECURITY_CMDMASK)
98+
| NVDIMM_INTEL_SECURITY_CMDMASK | NVDIMM_INTEL_FW_ACTIVATE_CMDMASK)
99+
100+
#define NVDIMM_INTEL_DENY_CMDMASK \
101+
(NVDIMM_INTEL_SECURITY_CMDMASK | NVDIMM_INTEL_FW_ACTIVATE_CMDMASK)
85102

86103
enum nfit_uuids {
87104
/* for simplicity alias the uuid index with the family id */
@@ -90,6 +107,11 @@ enum nfit_uuids {
90107
NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
91108
NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT,
92109
NFIT_DEV_DIMM_N_HYPERV = NVDIMM_FAMILY_HYPERV,
110+
/*
111+
* to_nfit_bus_uuid() expects to translate bus uuid family ids
112+
* to a UUID index using NVDIMM_FAMILY_MAX as an offset
113+
*/
114+
NFIT_BUS_INTEL = NVDIMM_FAMILY_MAX + NVDIMM_BUS_FAMILY_INTEL,
93115
NFIT_SPA_VOLATILE,
94116
NFIT_SPA_PM,
95117
NFIT_SPA_DCR,
@@ -238,6 +260,7 @@ struct acpi_nfit_desc {
238260
unsigned long dimm_cmd_force_en;
239261
unsigned long bus_cmd_force_en;
240262
unsigned long bus_dsm_mask;
263+
unsigned long family_dsm_mask[NVDIMM_BUS_FAMILY_MAX + 1];
241264
unsigned int platform_cap;
242265
unsigned int scrub_tmo;
243266
int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,

include/uapi/linux/ndctl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ struct nd_cmd_pkg {
248248
#define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_PAPR
249249

250250
#define NVDIMM_BUS_FAMILY_NFIT 0
251-
#define NVDIMM_BUS_FAMILY_MAX NVDIMM_BUS_FAMILY_NFIT
251+
#define NVDIMM_BUS_FAMILY_INTEL 1
252+
#define NVDIMM_BUS_FAMILY_MAX NVDIMM_BUS_FAMILY_INTEL
252253

253254
#define ND_IOCTL_CALL _IOWR(ND_IOCTL, ND_CMD_CALL,\
254255
struct nd_cmd_pkg)

0 commit comments

Comments
 (0)