Skip to content

Commit dcfb706

Browse files
committed
Merge branch 'for-6.5/cxl-background' into for-6.5/cxl
Pick up the sanitization work and the infrastructure for other background commands for 6.5. Sanitization has a different completion path than typical background commands so it was important to have both thought out and implemented before either went upstream.
2 parents 858fd16 + f337043 commit dcfb706

9 files changed

Lines changed: 543 additions & 24 deletions

File tree

Documentation/ABI/testing/sysfs-bus-cxl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,43 @@ Description:
5858
affinity for this device.
5959

6060

61+
What: /sys/bus/cxl/devices/memX/security/state
62+
Date: June, 2023
63+
KernelVersion: v6.5
64+
Contact: linux-cxl@vger.kernel.org
65+
Description:
66+
(RO) Reading this file will display the CXL security state for
67+
that device. Such states can be: 'disabled', 'sanitize', when
68+
a sanitization is currently underway; or those available only
69+
for persistent memory: 'locked', 'unlocked' or 'frozen'. This
70+
sysfs entry is select/poll capable from userspace to notify
71+
upon completion of a sanitize operation.
72+
73+
74+
What: /sys/bus/cxl/devices/memX/security/sanitize
75+
Date: June, 2023
76+
KernelVersion: v6.5
77+
Contact: linux-cxl@vger.kernel.org
78+
Description:
79+
(WO) Write a boolean 'true' string value to this attribute to
80+
sanitize the device to securely re-purpose or decommission it.
81+
This is done by ensuring that all user data and meta-data,
82+
whether it resides in persistent capacity, volatile capacity,
83+
or the LSA, is made permanently unavailable by whatever means
84+
is appropriate for the media type. This functionality requires
85+
the device to be not be actively decoding any HPA ranges.
86+
87+
88+
What /sys/bus/cxl/devices/memX/security/erase
89+
Date: June, 2023
90+
KernelVersion: v6.5
91+
Contact: linux-cxl@vger.kernel.org
92+
Description:
93+
(WO) Write a boolean 'true' string value to this attribute to
94+
secure erase user data by changing the media encryption keys for
95+
all user data areas of the device.
96+
97+
6198
What: /sys/bus/cxl/devices/*/devtype
6299
Date: June, 2021
63100
KernelVersion: v5.14

drivers/cxl/core/mbox.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ int cxl_internal_send_cmd(struct cxl_dev_state *cxlds,
220220
if (rc)
221221
return rc;
222222

223-
if (mbox_cmd->return_code != CXL_MBOX_CMD_RC_SUCCESS)
223+
if (mbox_cmd->return_code != CXL_MBOX_CMD_RC_SUCCESS &&
224+
mbox_cmd->return_code != CXL_MBOX_CMD_RC_BACKGROUND)
224225
return cxl_mbox_cmd_rc2errno(mbox_cmd);
225226

226227
if (!out_size)
@@ -1074,6 +1075,65 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
10741075
}
10751076
EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
10761077

1078+
/**
1079+
* cxl_mem_sanitize() - Send a sanitization command to the device.
1080+
* @cxlds: The device data for the operation
1081+
* @cmd: The specific sanitization command opcode
1082+
*
1083+
* Return: 0 if the command was executed successfully, regardless of
1084+
* whether or not the actual security operation is done in the background,
1085+
* such as for the Sanitize case.
1086+
* Error return values can be the result of the mailbox command, -EINVAL
1087+
* when security requirements are not met or invalid contexts.
1088+
*
1089+
* See CXL 3.0 @8.2.9.8.5.1 Sanitize and @8.2.9.8.5.2 Secure Erase.
1090+
*/
1091+
int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
1092+
{
1093+
int rc;
1094+
u32 sec_out = 0;
1095+
struct cxl_get_security_output {
1096+
__le32 flags;
1097+
} out;
1098+
struct cxl_mbox_cmd sec_cmd = {
1099+
.opcode = CXL_MBOX_OP_GET_SECURITY_STATE,
1100+
.payload_out = &out,
1101+
.size_out = sizeof(out),
1102+
};
1103+
struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
1104+
1105+
if (cmd != CXL_MBOX_OP_SANITIZE && cmd != CXL_MBOX_OP_SECURE_ERASE)
1106+
return -EINVAL;
1107+
1108+
rc = cxl_internal_send_cmd(cxlds, &sec_cmd);
1109+
if (rc < 0) {
1110+
dev_err(cxlds->dev, "Failed to get security state : %d", rc);
1111+
return rc;
1112+
}
1113+
1114+
/*
1115+
* Prior to using these commands, any security applied to
1116+
* the user data areas of the device shall be DISABLED (or
1117+
* UNLOCKED for secure erase case).
1118+
*/
1119+
sec_out = le32_to_cpu(out.flags);
1120+
if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)
1121+
return -EINVAL;
1122+
1123+
if (cmd == CXL_MBOX_OP_SECURE_ERASE &&
1124+
sec_out & CXL_PMEM_SEC_STATE_LOCKED)
1125+
return -EINVAL;
1126+
1127+
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
1128+
if (rc < 0) {
1129+
dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
1130+
return rc;
1131+
}
1132+
1133+
return 0;
1134+
}
1135+
EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL);
1136+
10771137
static int add_dpa_res(struct device *dev, struct resource *parent,
10781138
struct resource *res, resource_size_t start,
10791139
resource_size_t size, const char *type)

drivers/cxl/core/memdev.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright(c) 2020 Intel Corporation. */
33

4+
#include <linux/io-64-nonatomic-lo-hi.h>
45
#include <linux/device.h>
56
#include <linux/slab.h>
67
#include <linux/idr.h>
@@ -107,6 +108,88 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
107108
}
108109
static DEVICE_ATTR_RO(numa_node);
109110

111+
static ssize_t security_state_show(struct device *dev,
112+
struct device_attribute *attr,
113+
char *buf)
114+
{
115+
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
116+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
117+
unsigned long state = cxlds->security.state;
118+
u64 reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
119+
u32 pct = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_PCT_MASK, reg);
120+
u16 cmd = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
121+
122+
if (cmd == CXL_MBOX_OP_SANITIZE && pct != 100)
123+
return sysfs_emit(buf, "sanitize\n");
124+
125+
if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
126+
return sysfs_emit(buf, "disabled\n");
127+
if (state & CXL_PMEM_SEC_STATE_FROZEN ||
128+
state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT ||
129+
state & CXL_PMEM_SEC_STATE_USER_PLIMIT)
130+
return sysfs_emit(buf, "frozen\n");
131+
if (state & CXL_PMEM_SEC_STATE_LOCKED)
132+
return sysfs_emit(buf, "locked\n");
133+
else
134+
return sysfs_emit(buf, "unlocked\n");
135+
}
136+
static struct device_attribute dev_attr_security_state =
137+
__ATTR(state, 0444, security_state_show, NULL);
138+
139+
static ssize_t security_sanitize_store(struct device *dev,
140+
struct device_attribute *attr,
141+
const char *buf, size_t len)
142+
{
143+
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
144+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
145+
struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
146+
ssize_t rc;
147+
bool sanitize;
148+
149+
if (kstrtobool(buf, &sanitize) || !sanitize)
150+
return -EINVAL;
151+
152+
if (!port || !is_cxl_endpoint(port))
153+
return -EINVAL;
154+
155+
/* ensure no regions are mapped to this memdev */
156+
if (port->commit_end != -1)
157+
return -EBUSY;
158+
159+
rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SANITIZE);
160+
161+
return rc ? rc : len;
162+
}
163+
static struct device_attribute dev_attr_security_sanitize =
164+
__ATTR(sanitize, 0200, NULL, security_sanitize_store);
165+
166+
static ssize_t security_erase_store(struct device *dev,
167+
struct device_attribute *attr,
168+
const char *buf, size_t len)
169+
{
170+
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
171+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
172+
struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
173+
ssize_t rc;
174+
bool erase;
175+
176+
if (kstrtobool(buf, &erase) || !erase)
177+
return -EINVAL;
178+
179+
if (!port || !is_cxl_endpoint(port))
180+
return -EINVAL;
181+
182+
/* ensure no regions are mapped to this memdev */
183+
if (port->commit_end != -1)
184+
return -EBUSY;
185+
186+
rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE);
187+
188+
return rc ? rc : len;
189+
}
190+
static struct device_attribute dev_attr_security_erase =
191+
__ATTR(erase, 0200, NULL, security_erase_store);
192+
110193
static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
111194
{
112195
struct cxl_dev_state *cxlds = cxlmd->cxlds;
@@ -352,6 +435,13 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
352435
NULL,
353436
};
354437

438+
static struct attribute *cxl_memdev_security_attributes[] = {
439+
&dev_attr_security_state.attr,
440+
&dev_attr_security_sanitize.attr,
441+
&dev_attr_security_erase.attr,
442+
NULL,
443+
};
444+
355445
static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
356446
int n)
357447
{
@@ -375,10 +465,16 @@ static struct attribute_group cxl_memdev_pmem_attribute_group = {
375465
.attrs = cxl_memdev_pmem_attributes,
376466
};
377467

468+
static struct attribute_group cxl_memdev_security_attribute_group = {
469+
.name = "security",
470+
.attrs = cxl_memdev_security_attributes,
471+
};
472+
378473
static const struct attribute_group *cxl_memdev_attribute_groups[] = {
379474
&cxl_memdev_attribute_group,
380475
&cxl_memdev_ram_attribute_group,
381476
&cxl_memdev_pmem_attribute_group,
477+
&cxl_memdev_security_attribute_group,
382478
NULL,
383479
};
384480

@@ -427,11 +523,21 @@ void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cm
427523
}
428524
EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
429525

526+
static void cxl_memdev_security_shutdown(struct device *dev)
527+
{
528+
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
529+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
530+
531+
if (cxlds->security.poll)
532+
cancel_delayed_work_sync(&cxlds->security.poll_dwork);
533+
}
534+
430535
static void cxl_memdev_shutdown(struct device *dev)
431536
{
432537
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
433538

434539
down_write(&cxl_memdev_rwsem);
540+
cxl_memdev_security_shutdown(dev);
435541
cxlmd->cxlds = NULL;
436542
up_write(&cxl_memdev_rwsem);
437543
}
@@ -551,6 +657,34 @@ static const struct file_operations cxl_memdev_fops = {
551657
.llseek = noop_llseek,
552658
};
553659

660+
static void put_sanitize(void *data)
661+
{
662+
struct cxl_dev_state *cxlds = data;
663+
664+
sysfs_put(cxlds->security.sanitize_node);
665+
}
666+
667+
static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
668+
{
669+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
670+
struct device *dev = &cxlmd->dev;
671+
struct kernfs_node *sec;
672+
673+
sec = sysfs_get_dirent(dev->kobj.sd, "security");
674+
if (!sec) {
675+
dev_err(dev, "sysfs_get_dirent 'security' failed\n");
676+
return -ENODEV;
677+
}
678+
cxlds->security.sanitize_node = sysfs_get_dirent(sec, "state");
679+
sysfs_put(sec);
680+
if (!cxlds->security.sanitize_node) {
681+
dev_err(dev, "sysfs_get_dirent 'state' failed\n");
682+
return -ENODEV;
683+
}
684+
685+
return devm_add_action_or_reset(cxlds->dev, put_sanitize, cxlds);
686+
}
687+
554688
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
555689
{
556690
struct cxl_memdev *cxlmd;
@@ -579,6 +713,10 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
579713
if (rc)
580714
goto err;
581715

716+
rc = cxl_memdev_security_init(cxlmd);
717+
if (rc)
718+
goto err;
719+
582720
rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
583721
if (rc)
584722
return ERR_PTR(rc);

drivers/cxl/cxl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,22 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
176176
/* CXL 2.0 8.2.8.4 Mailbox Registers */
177177
#define CXLDEV_MBOX_CAPS_OFFSET 0x00
178178
#define CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK GENMASK(4, 0)
179+
#define CXLDEV_MBOX_CAP_BG_CMD_IRQ BIT(6)
180+
#define CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK GENMASK(10, 7)
179181
#define CXLDEV_MBOX_CTRL_OFFSET 0x04
180182
#define CXLDEV_MBOX_CTRL_DOORBELL BIT(0)
183+
#define CXLDEV_MBOX_CTRL_BG_CMD_IRQ BIT(2)
181184
#define CXLDEV_MBOX_CMD_OFFSET 0x08
182185
#define CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK GENMASK_ULL(15, 0)
183186
#define CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK GENMASK_ULL(36, 16)
184187
#define CXLDEV_MBOX_STATUS_OFFSET 0x10
188+
#define CXLDEV_MBOX_STATUS_BG_CMD BIT(0)
185189
#define CXLDEV_MBOX_STATUS_RET_CODE_MASK GENMASK_ULL(47, 32)
186190
#define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18
191+
#define CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK GENMASK_ULL(15, 0)
192+
#define CXLDEV_MBOX_BG_CMD_COMMAND_PCT_MASK GENMASK_ULL(22, 16)
193+
#define CXLDEV_MBOX_BG_CMD_COMMAND_RC_MASK GENMASK_ULL(47, 32)
194+
#define CXLDEV_MBOX_BG_CMD_COMMAND_VENDOR_MASK GENMASK_ULL(63, 48)
187195
#define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20
188196

189197
/*

0 commit comments

Comments
 (0)