Commit 14d502cc authored by Shiju Jose's avatar Shiju Jose Committed by Dave Jiang
Browse files

cxl/mbox: Add SET_FEATURE mailbox command



Add support for SET_FEATURE mailbox command.

CXL spec r3.2 section 8.2.9.6 describes optional device specific features.
CXL devices supports features with changeable attributes.
The settings of a feature can be optionally modified using Set Feature
command.
CXL spec r3.2 section 8.2.9.6.3 describes Set Feature command.

Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: default avatarDan Williams <dan.j.williams@intel.com>
Reviewed-by: default avatarLi Ming <ming.li@zohomail.com>
Signed-off-by: default avatarShiju Jose <shiju.jose@huawei.com>
Link: https://patch.msgid.link/20250220194438.2281088-6-dave.jiang@intel.com


Signed-off-by: default avatarDave Jiang <dave.jiang@intel.com>
parent 5e5ac21f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -122,6 +122,10 @@ size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
		       enum cxl_get_feat_selection selection,
		       void *feat_out, size_t feat_out_size, u16 offset,
		       u16 *return_code);
int cxl_set_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
		    u8 feat_version, const void *feat_data,
		    size_t feat_data_size, u32 feat_flag, u16 offset,
		    u16 *return_code);
#endif

#endif /* __CXL_CORE_H__ */
+80 −0
Original line number Diff line number Diff line
@@ -223,3 +223,83 @@ size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,

	return data_rcvd_size;
}

/*
 * FEAT_DATA_MIN_PAYLOAD_SIZE - min extra number of bytes should be
 * available in the mailbox for storing the actual feature data so that
 * the feature data transfer would work as expected.
 */
#define FEAT_DATA_MIN_PAYLOAD_SIZE 10
int cxl_set_feature(struct cxl_mailbox *cxl_mbox,
		    const uuid_t *feat_uuid, u8 feat_version,
		    const void *feat_data, size_t feat_data_size,
		    u32 feat_flag, u16 offset, u16 *return_code)
{
	size_t data_in_size, data_sent_size = 0;
	struct cxl_mbox_cmd mbox_cmd;
	size_t hdr_size;

	if (return_code)
		*return_code = CXL_MBOX_CMD_RC_INPUT;

	struct cxl_mbox_set_feat_in *pi __free(kfree) =
			kzalloc(cxl_mbox->payload_size, GFP_KERNEL);
	if (!pi)
		return -ENOMEM;

	uuid_copy(&pi->uuid, feat_uuid);
	pi->version = feat_version;
	feat_flag &= ~CXL_SET_FEAT_FLAG_DATA_TRANSFER_MASK;
	feat_flag |= CXL_SET_FEAT_FLAG_DATA_SAVED_ACROSS_RESET;
	hdr_size = sizeof(pi->hdr);
	/*
	 * Check minimum mbox payload size is available for
	 * the feature data transfer.
	 */
	if (hdr_size + FEAT_DATA_MIN_PAYLOAD_SIZE > cxl_mbox->payload_size)
		return -ENOMEM;

	if (hdr_size + feat_data_size <= cxl_mbox->payload_size) {
		pi->flags = cpu_to_le32(feat_flag |
					CXL_SET_FEAT_FLAG_FULL_DATA_TRANSFER);
		data_in_size = feat_data_size;
	} else {
		pi->flags = cpu_to_le32(feat_flag |
					CXL_SET_FEAT_FLAG_INITIATE_DATA_TRANSFER);
		data_in_size = cxl_mbox->payload_size - hdr_size;
	}

	do {
		int rc;

		pi->offset = cpu_to_le16(offset + data_sent_size);
		memcpy(pi->feat_data, feat_data + data_sent_size, data_in_size);
		mbox_cmd = (struct cxl_mbox_cmd) {
			.opcode = CXL_MBOX_OP_SET_FEATURE,
			.size_in = hdr_size + data_in_size,
			.payload_in = pi,
		};
		rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
		if (rc < 0) {
			if (return_code)
				*return_code = mbox_cmd.return_code;
			return rc;
		}

		data_sent_size += data_in_size;
		if (data_sent_size >= feat_data_size) {
			if (return_code)
				*return_code = CXL_MBOX_CMD_RC_SUCCESS;
			return 0;
		}

		if ((feat_data_size - data_sent_size) <= (cxl_mbox->payload_size - hdr_size)) {
			data_in_size = feat_data_size - data_sent_size;
			pi->flags = cpu_to_le32(feat_flag |
						CXL_SET_FEAT_FLAG_FINISH_DATA_TRANSFER);
		} else {
			pi->flags = cpu_to_le32(feat_flag |
						CXL_SET_FEAT_FLAG_CONTINUE_DATA_TRANSFER);
		}
	} while (true);
}
+33 −0
Original line number Diff line number Diff line
@@ -90,6 +90,39 @@ enum cxl_get_feat_selection {
	CXL_GET_FEAT_SEL_MAX
};

/*
 * Set Feature CXL spec r3.2  8.2.9.6.3
 */

/*
 * Set Feature input payload
 * CXL spec r3.2 section 8.2.9.6.3 Table 8-101
 */
struct cxl_mbox_set_feat_in {
	__struct_group(cxl_mbox_set_feat_hdr, hdr, /* no attrs */,
		uuid_t uuid;
		__le32 flags;
		__le16 offset;
		u8 version;
		u8 rsvd[9];
	);
	__u8 feat_data[];
}  __packed;

/* Set Feature flags field */
enum cxl_set_feat_flag_data_transfer {
	CXL_SET_FEAT_FLAG_FULL_DATA_TRANSFER = 0,
	CXL_SET_FEAT_FLAG_INITIATE_DATA_TRANSFER,
	CXL_SET_FEAT_FLAG_CONTINUE_DATA_TRANSFER,
	CXL_SET_FEAT_FLAG_FINISH_DATA_TRANSFER,
	CXL_SET_FEAT_FLAG_ABORT_DATA_TRANSFER,
	CXL_SET_FEAT_FLAG_DATA_TRANSFER_MAX
};

#define CXL_SET_FEAT_FLAG_DATA_TRANSFER_MASK	GENMASK(2, 0)

#define CXL_SET_FEAT_FLAG_DATA_SAVED_ACROSS_RESET	BIT(3)

/**
 * struct cxl_features_state - The Features state for the device
 * @cxlds: Pointer to CXL device state