/** * DOC: cxl mbox * * Core implementation of the CXL 2.0 Type-3 Memory Device Mailbox. The * implementation is used by the cxl_pci driver to initialize the device * and implement the cxl_mem.h IOCTL UAPI. It also implements the * backend of the cxl_pmem_ctl() transport for LIBNVDIMM.
*/
#define CXL_VARIABLE_PAYLOAD ~0U /* * This table defines the supported mailbox commands for the driver. This table * is made up of a UAPI structure. Non-negative values as parameters in the * table will be validated against the user's input. For example, if size_in is * 0, and the user passed in 1, it is an error.
*/ staticstruct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = {
CXL_CMD(IDENTIFY, 0, 0x43, CXL_CMD_FLAG_FORCE_ENABLE), #ifdef CONFIG_CXL_MEM_RAW_COMMANDS
CXL_CMD(RAW, CXL_VARIABLE_PAYLOAD, CXL_VARIABLE_PAYLOAD, 0), #endif
CXL_CMD(GET_SUPPORTED_LOGS, 0, CXL_VARIABLE_PAYLOAD, CXL_CMD_FLAG_FORCE_ENABLE),
CXL_CMD(GET_FW_INFO, 0, 0x50, 0),
CXL_CMD(GET_PARTITION_INFO, 0, 0x20, 0),
CXL_CMD(GET_LSA, 0x8, CXL_VARIABLE_PAYLOAD, 0),
CXL_CMD(GET_HEALTH_INFO, 0, 0x12, 0),
CXL_CMD(GET_LOG, 0x18, CXL_VARIABLE_PAYLOAD, CXL_CMD_FLAG_FORCE_ENABLE),
CXL_CMD(GET_LOG_CAPS, 0x10, 0x4, 0),
CXL_CMD(CLEAR_LOG, 0x10, 0, 0),
CXL_CMD(GET_SUP_LOG_SUBLIST, 0x2, CXL_VARIABLE_PAYLOAD, 0),
CXL_CMD(SET_PARTITION_INFO, 0x0a, 0, 0),
CXL_CMD(SET_LSA, CXL_VARIABLE_PAYLOAD, 0, 0),
CXL_CMD(GET_ALERT_CONFIG, 0, 0x10, 0),
CXL_CMD(SET_ALERT_CONFIG, 0xc, 0, 0),
CXL_CMD(GET_SHUTDOWN_STATE, 0, 0x1, 0),
CXL_CMD(SET_SHUTDOWN_STATE, 0x1, 0, 0),
CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0),
CXL_CMD(GET_TIMESTAMP, 0, 0x8, 0),
};
/* * Commands that RAW doesn't permit. The rationale for each: * * CXL_MBOX_OP_ACTIVATE_FW: Firmware activation requires adjustment / * coordination of transaction timeout values at the root bridge level. * * CXL_MBOX_OP_SET_PARTITION_INFO: The device memory map may change live * and needs to be coordinated with HDM updates. * * CXL_MBOX_OP_SET_LSA: The label storage area may be cached by the * driver and any writes from userspace invalidates those contents. * * CXL_MBOX_OP_SET_SHUTDOWN_STATE: Set shutdown state assumes no writes * to the device after it is marked clean, userspace can not make that * assertion. * * CXL_MBOX_OP_[GET_]SCAN_MEDIA: The kernel provides a native error list that * is kept up to date with patrol notifications and error management. * * CXL_MBOX_OP_[GET_,INJECT_,CLEAR_]POISON: These commands require kernel * driver orchestration for safety.
*/ static u16 cxl_disabled_raw_commands[] = {
CXL_MBOX_OP_ACTIVATE_FW,
CXL_MBOX_OP_SET_PARTITION_INFO,
CXL_MBOX_OP_SET_LSA,
CXL_MBOX_OP_SET_SHUTDOWN_STATE,
CXL_MBOX_OP_SCAN_MEDIA,
CXL_MBOX_OP_GET_SCAN_MEDIA,
CXL_MBOX_OP_GET_POISON,
CXL_MBOX_OP_INJECT_POISON,
CXL_MBOX_OP_CLEAR_POISON,
};
/* * Command sets that RAW doesn't permit. All opcodes in this set are * disabled because they pass plain text security payloads over the * user/kernel boundary. This functionality is intended to be wrapped * behind the keys ABI which allows for encrypted payloads in the UAPI
*/ static u8 security_command_sets[] = {
0x44, /* Sanitize */
0x45, /* Persistent Memory Data-at-rest Security */
0x46, /* Security Passthrough */
};
staticbool cxl_is_security_command(u16 opcode)
{ int i;
for (i = 0; i < ARRAY_SIZE(security_command_sets); i++) if (security_command_sets[i] == (opcode >> 8)) returntrue; returnfalse;
}
staticvoid cxl_set_security_cmd_enabled(struct cxl_security_state *security,
u16 opcode)
{ switch (opcode) { case CXL_MBOX_OP_SANITIZE:
set_bit(CXL_SEC_ENABLED_SANITIZE, security->enabled_cmds); break; case CXL_MBOX_OP_SECURE_ERASE:
set_bit(CXL_SEC_ENABLED_SECURE_ERASE,
security->enabled_cmds); break; case CXL_MBOX_OP_GET_SECURITY_STATE:
set_bit(CXL_SEC_ENABLED_GET_SECURITY_STATE,
security->enabled_cmds); break; case CXL_MBOX_OP_SET_PASSPHRASE:
set_bit(CXL_SEC_ENABLED_SET_PASSPHRASE,
security->enabled_cmds); break; case CXL_MBOX_OP_DISABLE_PASSPHRASE:
set_bit(CXL_SEC_ENABLED_DISABLE_PASSPHRASE,
security->enabled_cmds); break; case CXL_MBOX_OP_UNLOCK:
set_bit(CXL_SEC_ENABLED_UNLOCK, security->enabled_cmds); break; case CXL_MBOX_OP_FREEZE_SECURITY:
set_bit(CXL_SEC_ENABLED_FREEZE_SECURITY,
security->enabled_cmds); break; case CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE:
set_bit(CXL_SEC_ENABLED_PASSPHRASE_SECURE_ERASE,
security->enabled_cmds); break; default: break;
}
}
c = cxl_mem_find_command(opcode); if (!c) return NULL;
return cxl_command_names[c->info.id].name;
}
/** * cxl_internal_send_cmd() - Kernel internal interface to send a mailbox command * @cxl_mbox: CXL mailbox context * @mbox_cmd: initialized command to execute * * Context: Any context. * Return: * * %>=0 - Number of bytes returned in @out. * * %-E2BIG - Payload is too large for hardware. * * %-EBUSY - Couldn't acquire exclusive mailbox access. * * %-EFAULT - Hardware error occurred. * * %-ENXIO - Command completed, but device reported an error. * * %-EIO - Unexpected output size. * * Mailbox commands may execute successfully yet the device itself reported an * error. While this distinction can be useful for commands from userspace, the * kernel will only be able to use results when both are successful.
*/ int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *mbox_cmd)
{
size_t out_size, min_out; int rc;
if (mbox_cmd->size_in > cxl_mbox->payload_size ||
mbox_cmd->size_out > cxl_mbox->payload_size) return -E2BIG;
out_size = mbox_cmd->size_out;
min_out = mbox_cmd->min_out;
rc = cxl_mbox->mbox_send(cxl_mbox, mbox_cmd); /* * EIO is reserved for a payload size mismatch and mbox_send() * may not return this error.
*/ if (WARN_ONCE(rc == -EIO, "Bad return code: -EIO")) return -ENXIO; if (rc) return rc;
if (mbox_cmd->return_code != CXL_MBOX_CMD_RC_SUCCESS &&
mbox_cmd->return_code != CXL_MBOX_CMD_RC_BACKGROUND) return cxl_mbox_cmd_rc2errno(mbox_cmd);
if (!out_size) return 0;
/* * Variable sized output needs to at least satisfy the caller's * minimum if not the fully requested size.
*/ if (min_out == 0)
min_out = out_size;
staticbool cxl_mem_raw_command_allowed(u16 opcode)
{ int i;
if (!IS_ENABLED(CONFIG_CXL_MEM_RAW_COMMANDS)) returnfalse;
if (security_locked_down(LOCKDOWN_PCI_ACCESS)) returnfalse;
if (cxl_raw_allow_all) returntrue;
if (cxl_is_security_command(opcode)) returnfalse;
for (i = 0; i < ARRAY_SIZE(cxl_disabled_raw_commands); i++) if (cxl_disabled_raw_commands[i] == opcode) returnfalse;
returntrue;
}
/** * cxl_payload_from_user_allowed() - Check contents of in_payload. * @opcode: The mailbox command opcode. * @payload_in: Pointer to the input payload passed in from user space. * * Return: * * true - payload_in passes check for @opcode. * * false - payload_in contains invalid or unsupported values. * * The driver may inspect payload contents before sending a mailbox * command from user space to the device. The intent is to reject * commands with input payloads that are known to be unsafe. This * check is not intended to replace the users careful selection of * mailbox command parameters and makes no guarantee that the user * command will succeed, nor that it is appropriate. * * The specific checks are determined by the opcode.
*/ staticbool cxl_payload_from_user_allowed(u16 opcode, void *payload_in)
{ switch (opcode) { case CXL_MBOX_OP_SET_PARTITION_INFO: { struct cxl_mbox_set_partition_info *pi = payload_in;
if (pi->flags & CXL_SET_PARTITION_IMMEDIATE_FLAG) returnfalse; break;
} case CXL_MBOX_OP_CLEAR_LOG: { const uuid_t *uuid = (uuid_t *)payload_in;
/* * Restrict the ‘Clear log’ action to only apply to * Vendor debug logs.
*/ return uuid_equal(uuid, &DEFINE_CXL_VENDOR_DEBUG_UUID);
} default: break;
} returntrue;
}
if (in_size) {
mbox_cmd->payload_in = vmemdup_user(u64_to_user_ptr(in_payload),
in_size); if (IS_ERR(mbox_cmd->payload_in)) return PTR_ERR(mbox_cmd->payload_in);
if (!cxl_payload_from_user_allowed(opcode, mbox_cmd->payload_in)) {
dev_dbg(cxl_mbox->host, "%s: input payload not allowed\n",
cxl_mem_opcode_to_name(opcode));
kvfree(mbox_cmd->payload_in); return -EBUSY;
}
}
/* Prepare to handle a full payload for variable sized output */ if (out_size == CXL_VARIABLE_PAYLOAD)
mbox_cmd->size_out = cxl_mbox->payload_size; else
mbox_cmd->size_out = out_size;
if (mbox_cmd->size_out) {
mbox_cmd->payload_out = kvzalloc(mbox_cmd->size_out, GFP_KERNEL); if (!mbox_cmd->payload_out) {
kvfree(mbox_cmd->payload_in); return -ENOMEM;
}
} return 0;
}
/* * Unlike supported commands, the output size of RAW commands * gets passed along without further checking, so it must be * validated here.
*/ if (send_cmd->out.size > cxl_mbox->payload_size) return -EINVAL;
if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode)) return -EPERM;
if (send_cmd->flags & ~CXL_MEM_COMMAND_FLAG_MASK) return -EINVAL;
if (send_cmd->rsvd) return -EINVAL;
if (send_cmd->in.rsvd || send_cmd->out.rsvd) return -EINVAL;
/* Check that the command is enabled for hardware */ if (!test_bit(info->id, cxl_mbox->enabled_cmds)) return -ENOTTY;
/* Check that the command is not claimed for exclusive kernel use */ if (test_bit(info->id, cxl_mbox->exclusive_cmds)) return -EBUSY;
/* Check the input buffer is the expected size */ if ((info->size_in != CXL_VARIABLE_PAYLOAD) &&
(info->size_in != send_cmd->in.size)) return -ENOMEM;
/* Check the output buffer is at least large enough */ if ((info->size_out != CXL_VARIABLE_PAYLOAD) &&
(send_cmd->out.size < info->size_out)) return -ENOMEM;
/** * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. * @mbox_cmd: Sanitized and populated &struct cxl_mbox_cmd. * @cxl_mbox: CXL mailbox context * @send_cmd: &struct cxl_send_command copied in from userspace. * * Return: * * %0 - @out_cmd is ready to send. * * %-ENOTTY - Invalid command specified. * * %-EINVAL - Reserved fields or invalid values were used. * * %-ENOMEM - Input or output buffer wasn't sized properly. * * %-EPERM - Attempted to use a protected command. * * %-EBUSY - Kernel has claimed exclusive access to this opcode * * The result of this command is a fully validated command in @mbox_cmd that is * safe to send to the hardware.
*/ staticint cxl_validate_cmd_from_user(struct cxl_mbox_cmd *mbox_cmd, struct cxl_mailbox *cxl_mbox, conststruct cxl_send_command *send_cmd)
{ struct cxl_mem_command mem_cmd; int rc;
if (send_cmd->id == 0 || send_cmd->id >= CXL_MEM_COMMAND_ID_MAX) return -ENOTTY;
/* * The user can never specify an input payload larger than what hardware * supports, but output can be arbitrarily large (simply write out as * much data as the hardware provides).
*/ if (send_cmd->in.size > cxl_mbox->payload_size) return -EINVAL;
/* Sanitize and construct a cxl_mem_command */ if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW)
rc = cxl_to_mem_cmd_raw(&mem_cmd, send_cmd, cxl_mbox); else
rc = cxl_to_mem_cmd(&mem_cmd, send_cmd, cxl_mbox);
if (rc) return rc;
/* Sanitize and construct a cxl_mbox_cmd */ return cxl_mbox_cmd_ctor(mbox_cmd, cxl_mbox, mem_cmd.opcode,
mem_cmd.info.size_in, mem_cmd.info.size_out,
send_cmd->in.payload);
}
rc = cxl_mbox->mbox_send(cxl_mbox, mbox_cmd); if (rc) goto out;
/* * @size_out contains the max size that's allowed to be written back out * to userspace. While the payload may have written more output than * this it will have to be ignored.
*/ if (mbox_cmd->size_out) {
dev_WARN_ONCE(dev, mbox_cmd->size_out > *size_out, "Invalid return size\n"); if (copy_to_user(u64_to_user_ptr(out_payload),
mbox_cmd->payload_out, mbox_cmd->size_out)) {
rc = -EFAULT; goto out;
}
}
/* * The output payload length that indicates the number * of valid bytes can be smaller than the Log buffer * size.
*/ if (rc == -EIO && mbox_cmd.size_out < xfer_size) {
offset += mbox_cmd.size_out; break;
}
if (rc < 0) return rc;
out += xfer_size;
remaining -= xfer_size;
offset += xfer_size;
}
*size = offset;
return 0;
}
staticint check_features_opcodes(u16 opcode, int *ro_cmds, int *wr_cmds)
{ switch (opcode) { case CXL_MBOX_OP_GET_SUPPORTED_FEATURES: case CXL_MBOX_OP_GET_FEATURE:
(*ro_cmds)++; return 1; case CXL_MBOX_OP_SET_FEATURE:
(*wr_cmds)++; return 1; default: return 0;
}
}
/* 'Get Supported Features' and 'Get Feature' */ #define MAX_FEATURES_READ_CMDS 2 staticvoid set_features_cap(struct cxl_mailbox *cxl_mbox, int ro_cmds, int wr_cmds)
{ /* Setting up Features capability while walking the CEL */ if (ro_cmds == MAX_FEATURES_READ_CMDS) { if (wr_cmds)
cxl_mbox->feat_cap = CXL_FEATURES_RW; else
cxl_mbox->feat_cap = CXL_FEATURES_RO;
}
}
/** * cxl_walk_cel() - Walk through the Command Effects Log. * @mds: The driver data for the operation * @size: Length of the Command Effects Log. * @cel: CEL * * Iterate over each entry in the CEL and determine if the driver supports the * command. If so, the command is enabled for the device and can be used later.
*/ staticvoid cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel)
{ struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; struct cxl_cel_entry *cel_entry; constint cel_entries = size / sizeof(*cel_entry); struct device *dev = mds->cxlds.dev; int i, ro_cmds = 0, wr_cmds = 0;
cel_entry = (struct cxl_cel_entry *) cel;
for (i = 0; i < cel_entries; i++) {
u16 opcode = le16_to_cpu(cel_entry[i].opcode); struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); int enabled = 0;
if (cmd) {
set_bit(cmd->info.id, cxl_mbox->enabled_cmds);
enabled++;
}
ret = kvmalloc(cxl_mbox->payload_size, GFP_KERNEL); if (!ret) return ERR_PTR(-ENOMEM);
mbox_cmd = (struct cxl_mbox_cmd) {
.opcode = CXL_MBOX_OP_GET_SUPPORTED_LOGS,
.size_out = cxl_mbox->payload_size,
.payload_out = ret, /* At least the record number field must be valid */
.min_out = 2,
};
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); if (rc < 0) {
kvfree(ret); return ERR_PTR(rc);
}
/** * cxl_enumerate_cmds() - Enumerate commands for a device. * @mds: The driver data for the operation * * Returns 0 if enumerate completed successfully. * * CXL devices have optional support for certain commands. This function will * determine the set of supported commands for the hardware and update the * enabled_cmds bitmap in the @mds.
*/ int cxl_enumerate_cmds(struct cxl_memdev_state *mds)
{ struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; struct cxl_mbox_get_supported_logs *gsl; struct device *dev = mds->cxlds.dev; struct cxl_mem_command *cmd; int i, rc;
gsl = cxl_get_gsl(mds); if (IS_ERR(gsl)) return PTR_ERR(gsl);
rc = -ENOENT; for (i = 0; i < le16_to_cpu(gsl->entries); i++) {
u32 size = le32_to_cpu(gsl->entry[i].size);
uuid_t uuid = gsl->entry[i].uuid;
u8 *log;
dev_dbg(dev, "Found LOG type %pU of size %d", &uuid, size);
if (!uuid_equal(&uuid, &log_uuid[CEL_UUID])) continue;
/* In case CEL was bogus, enable some default commands. */
cxl_for_each_cmd(cmd) if (cmd->flags & CXL_CMD_FLAG_FORCE_ENABLE)
set_bit(cmd->info.id, cxl_mbox->enabled_cmds);
/* Found the required CEL */
rc = 0;
}
out:
kvfree(gsl); return rc;
}
EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, "CXL");
/* * These trace points are annotated with HPA and region * translations. Take topology mutation locks and lookup * { HPA, REGION } from { DPA, MEMDEV } in the event record.
*/
guard(rwsem_read)(&cxl_rwsem.region);
guard(rwsem_read)(&cxl_rwsem.dpa);
if (event_type == CXL_CPER_EVENT_GEN_MEDIA) { if (cxl_store_rec_gen_media((struct cxl_memdev *)cxlmd, evt))
dev_dbg(&cxlmd->dev, "CXL store rec_gen_media failed\n");
/* * Clear Event Records uses u8 for the handle cnt while Get Event * Record can return up to 0xffff records.
*/
i = 0; for (cnt = 0; cnt < total; cnt++) { struct cxl_event_record_raw *raw = &get_pl->records[cnt]; struct cxl_event_generic *gen = &raw->event.generic;
if (i == max_handles) {
payload->nr_recs = i;
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); if (rc) goto free_pl;
i = 0;
}
}
/* Clear what is left if any */ if (i) {
payload->nr_recs = i;
mbox_cmd.size_in = struct_size(payload, handles, i);
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); if (rc) goto free_pl;
}
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); if (rc) {
dev_err_ratelimited(dev, "Event log '%d': Failed to query event records : %d",
type, rc); break;
}
nr_rec = le16_to_cpu(payload->record_count); if (!nr_rec) break;
for (i = 0; i < nr_rec; i++)
__cxl_event_trace_record(cxlmd, type,
&payload->records[i]);
if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW)
trace_cxl_overflow(cxlmd, type, payload);
rc = cxl_clear_event_record(mds, type, payload); if (rc) {
dev_err_ratelimited(dev, "Event log '%d': Failed to clear events : %d",
type, rc); break;
}
} while (nr_rec);
mutex_unlock(&mds->event.log_lock);
}
/** * cxl_mem_get_event_records - Get Event Records from the device * @mds: The driver data for the operation * @status: Event Status register value identifying which events are available. * * Retrieve all event records available on the device, report them as trace * events, and clear them. * * See CXL rev 3.0 @8.2.9.2.2 Get Event Records * See CXL rev 3.0 @8.2.9.2.3 Clear Event Records
*/ void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status)
{
dev_dbg(mds->cxlds.dev, "Reading event logs: %x\n", status);
if (status & CXLDEV_EVENT_STATUS_FATAL)
cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_FATAL); if (status & CXLDEV_EVENT_STATUS_FAIL)
cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_FAIL); if (status & CXLDEV_EVENT_STATUS_WARN)
cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_WARN); if (status & CXLDEV_EVENT_STATUS_INFO)
cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_INFO);
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, "CXL");
/** * cxl_mem_get_partition_info - Get partition info * @mds: The driver data for the operation * * Retrieve the current partition info for the device specified. The active * values are the current capacity in bytes. If not 0, the 'next' values are * the pending values, in bytes, which take affect on next cold reset. * * Return: 0 if no error: or the result of the mailbox command. * * See CXL @8.2.9.5.2.1 Get Partition Info
*/ staticint cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
{ struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; struct cxl_mbox_get_partition_info pi; struct cxl_mbox_cmd mbox_cmd; int rc;
/** * cxl_dev_state_identify() - Send the IDENTIFY command to the device. * @mds: The driver data for the operation * * Return: 0 if identify was executed successfully or media not ready. * * This will dispatch the identify command to the device and on success populate * structures to be exported to sysfs.
*/ int cxl_dev_state_identify(struct cxl_memdev_state *mds)
{ struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; /* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ struct cxl_mbox_identify id; struct cxl_mbox_cmd mbox_cmd;
u32 val; int rc;
if (cmd != CXL_MBOX_OP_SANITIZE && cmd != CXL_MBOX_OP_SECURE_ERASE) return -EINVAL;
rc = cxl_internal_send_cmd(cxl_mbox, &sec_cmd); if (rc < 0) {
dev_err(cxl_mbox->host, "Failed to get security state : %d", rc); return rc;
}
/* * Prior to using these commands, any security applied to * the user data areas of the device shall be DISABLED (or * UNLOCKED for secure erase case).
*/
sec_out = le32_to_cpu(out.flags); if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET) return -EINVAL;
if (cmd == CXL_MBOX_OP_SECURE_ERASE &&
sec_out & CXL_PMEM_SEC_STATE_LOCKED) return -EINVAL;
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); if (rc < 0) {
dev_err(cxl_mbox->host, "Failed to sanitize device : %d", rc); return rc;
}
return 0;
}
/** * cxl_mem_sanitize() - Send a sanitization command to the device. * @cxlmd: The device for the operation * @cmd: The specific sanitization command opcode * * Return: 0 if the command was executed successfully, regardless of * whether or not the actual security operation is done in the background, * such as for the Sanitize case. * Error return values can be the result of the mailbox command, -EINVAL * when security requirements are not met or invalid contexts, or -EBUSY * if the sanitize operation is already in flight. * * See CXL 3.0 @8.2.9.8.5.1 Sanitize and @8.2.9.8.5.2 Secure Erase.
*/ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
{ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); struct cxl_port *endpoint;
/* synchronize with cxl_mem_probe() and decoder write operations */
guard(device)(&cxlmd->dev);
endpoint = cxlmd->endpoint;
guard(rwsem_read)(&cxl_rwsem.region); /* * Require an endpoint to be safe otherwise the driver can not * be sure that the device is unmapped.
*/ if (endpoint && cxl_num_decoders_committed(endpoint) == 0) return __cxl_mem_sanitize(mds, cmd);
return -EBUSY;
}
staticvoid add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
{ int i = info->nr_partitions;
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); /* * Command is optional. Devices may have another way of providing * a timestamp, or may return all 0s in timestamp fields. * Don't report an error if this command isn't supported
*/ if (rc && (mbox_cmd.return_code != CXL_MBOX_CMD_RC_UNSUPPORTED)) return rc;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.