Commit dbe9f7d1 authored by Dan Williams's avatar Dan Williams
Browse files

Merge branch 'for-6.3/cxl-events' into cxl/next

Add the CXL event and interrupt support for the v6.3 update.
parents 5485eb95 5a84711f
Loading
Loading
Loading
Loading
+226 −0
Original line number Diff line number Diff line
@@ -3,11 +3,13 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/security.h>
#include <linux/debugfs.h>
#include <linux/ktime.h>
#include <linux/mutex.h>
#include <cxlmem.h>
#include <cxl.h>

#include "core.h"
#include "trace.h"

static bool cxl_raw_allow_all;

@@ -737,6 +739,203 @@ int cxl_enumerate_cmds(struct cxl_dev_state *cxlds)
}
EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL);

/*
 * General Media Event Record
 * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
 */
static const uuid_t gen_media_event_uuid =
	UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
		  0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6);

/*
 * DRAM Event Record
 * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
 */
static const uuid_t dram_event_uuid =
	UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
		  0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24);

/*
 * Memory Module Event Record
 * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
 */
static const uuid_t mem_mod_event_uuid =
	UUID_INIT(0xfe927475, 0xdd59, 0x4339,
		  0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74);

static void cxl_event_trace_record(const struct device *dev,
				   enum cxl_event_log_type type,
				   struct cxl_event_record_raw *record)
{
	uuid_t *id = &record->hdr.id;

	if (uuid_equal(id, &gen_media_event_uuid)) {
		struct cxl_event_gen_media *rec =
				(struct cxl_event_gen_media *)record;

		trace_cxl_general_media(dev, type, rec);
	} else if (uuid_equal(id, &dram_event_uuid)) {
		struct cxl_event_dram *rec = (struct cxl_event_dram *)record;

		trace_cxl_dram(dev, type, rec);
	} else if (uuid_equal(id, &mem_mod_event_uuid)) {
		struct cxl_event_mem_module *rec =
				(struct cxl_event_mem_module *)record;

		trace_cxl_memory_module(dev, type, rec);
	} else {
		/* For unknown record types print just the header */
		trace_cxl_generic_event(dev, type, record);
	}
}

static int cxl_clear_event_record(struct cxl_dev_state *cxlds,
				  enum cxl_event_log_type log,
				  struct cxl_get_event_payload *get_pl)
{
	struct cxl_mbox_clear_event_payload *payload;
	u16 total = le16_to_cpu(get_pl->record_count);
	u8 max_handles = CXL_CLEAR_EVENT_MAX_HANDLES;
	size_t pl_size = struct_size(payload, handles, max_handles);
	struct cxl_mbox_cmd mbox_cmd;
	u16 cnt;
	int rc = 0;
	int i;

	/* Payload size may limit the max handles */
	if (pl_size > cxlds->payload_size) {
		max_handles = (cxlds->payload_size - sizeof(*payload)) /
				sizeof(__le16);
		pl_size = struct_size(payload, handles, max_handles);
	}

	payload = kvzalloc(pl_size, GFP_KERNEL);
	if (!payload)
		return -ENOMEM;

	*payload = (struct cxl_mbox_clear_event_payload) {
		.event_log = log,
	};

	mbox_cmd = (struct cxl_mbox_cmd) {
		.opcode = CXL_MBOX_OP_CLEAR_EVENT_RECORD,
		.payload_in = payload,
		.size_in = pl_size,
	};

	/*
	 * 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++) {
		payload->handles[i++] = get_pl->records[cnt].hdr.handle;
		dev_dbg(cxlds->dev, "Event log '%d': Clearing %u\n",
			log, le16_to_cpu(payload->handles[i]));

		if (i == max_handles) {
			payload->nr_recs = i;
			rc = cxl_internal_send_cmd(cxlds, &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(cxlds, &mbox_cmd);
		if (rc)
			goto free_pl;
	}

free_pl:
	kvfree(payload);
	return rc;
}

static void cxl_mem_get_records_log(struct cxl_dev_state *cxlds,
				    enum cxl_event_log_type type)
{
	struct cxl_get_event_payload *payload;
	struct cxl_mbox_cmd mbox_cmd;
	u8 log_type = type;
	u16 nr_rec;

	mutex_lock(&cxlds->event.log_lock);
	payload = cxlds->event.buf;

	mbox_cmd = (struct cxl_mbox_cmd) {
		.opcode = CXL_MBOX_OP_GET_EVENT_RECORD,
		.payload_in = &log_type,
		.size_in = sizeof(log_type),
		.payload_out = payload,
		.size_out = cxlds->payload_size,
		.min_out = struct_size(payload, records, 0),
	};

	do {
		int rc, i;

		rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
		if (rc) {
			dev_err_ratelimited(cxlds->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(cxlds->dev, type,
					       &payload->records[i]);

		if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW)
			trace_cxl_overflow(cxlds->dev, type, payload);

		rc = cxl_clear_event_record(cxlds, type, payload);
		if (rc) {
			dev_err_ratelimited(cxlds->dev,
				"Event log '%d': Failed to clear events : %d",
				type, rc);
			break;
		}
	} while (nr_rec);

	mutex_unlock(&cxlds->event.log_lock);
}

/**
 * cxl_mem_get_event_records - Get Event Records from the device
 * @cxlds: The device 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_dev_state *cxlds, u32 status)
{
	dev_dbg(cxlds->dev, "Reading event logs: %x\n", status);

	if (status & CXLDEV_EVENT_STATUS_FATAL)
		cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_FATAL);
	if (status & CXLDEV_EVENT_STATUS_FAIL)
		cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_FAIL);
	if (status & CXLDEV_EVENT_STATUS_WARN)
		cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_WARN);
	if (status & CXLDEV_EVENT_STATUS_INFO)
		cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_INFO);
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, CXL);

/**
 * cxl_mem_get_partition_info - Get partition info
 * @cxlds: The device data for the operation
@@ -877,6 +1076,32 @@ int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL);

int cxl_set_timestamp(struct cxl_dev_state *cxlds)
{
	struct cxl_mbox_cmd mbox_cmd;
	struct cxl_mbox_set_timestamp_in pi;
	int rc;

	pi.timestamp = cpu_to_le64(ktime_get_real_ns());
	mbox_cmd = (struct cxl_mbox_cmd) {
		.opcode = CXL_MBOX_OP_SET_TIMESTAMP,
		.size_in = sizeof(pi),
		.payload_in = &pi,
	};

	rc = cxl_internal_send_cmd(cxlds, &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;

	return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_set_timestamp, CXL);

struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
{
	struct cxl_dev_state *cxlds;
@@ -888,6 +1113,7 @@ struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
	}

	mutex_init(&cxlds->mbox_mutex);
	mutex_init(&cxlds->event.log_lock);
	cxlds->dev = dev;

	return cxlds;
+479 −1
Original line number Diff line number Diff line
@@ -6,8 +6,11 @@
#if !defined(_CXL_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
#define _CXL_EVENTS_H

#include <cxl.h>
#include <linux/tracepoint.h>
#include <asm-generic/unaligned.h>

#include <cxl.h>
#include <cxlmem.h>

#define CXL_RAS_UC_CACHE_DATA_PARITY	BIT(0)
#define CXL_RAS_UC_CACHE_ADDR_PARITY	BIT(1)
@@ -103,6 +106,481 @@ TRACE_EVENT(cxl_aer_correctable_error,
	)
);

#define cxl_event_log_type_str(type)				\
	__print_symbolic(type,					\
		{ CXL_EVENT_TYPE_INFO, "Informational" },	\
		{ CXL_EVENT_TYPE_WARN, "Warning" },		\
		{ CXL_EVENT_TYPE_FAIL, "Failure" },		\
		{ CXL_EVENT_TYPE_FATAL, "Fatal" })

TRACE_EVENT(cxl_overflow,

	TP_PROTO(const struct device *dev, enum cxl_event_log_type log,
		 struct cxl_get_event_payload *payload),

	TP_ARGS(dev, log, payload),

	TP_STRUCT__entry(
		__string(dev_name, dev_name(dev))
		__field(int, log)
		__field(u64, first_ts)
		__field(u64, last_ts)
		__field(u16, count)
	),

	TP_fast_assign(
		__assign_str(dev_name, dev_name(dev));
		__entry->log = log;
		__entry->count = le16_to_cpu(payload->overflow_err_count);
		__entry->first_ts = le64_to_cpu(payload->first_overflow_timestamp);
		__entry->last_ts = le64_to_cpu(payload->last_overflow_timestamp);
	),

	TP_printk("%s: log=%s : %u records from %llu to %llu",
		__get_str(dev_name), cxl_event_log_type_str(__entry->log),
		__entry->count, __entry->first_ts, __entry->last_ts)

);

/*
 * Common Event Record Format
 * CXL 3.0 section 8.2.9.2.1; Table 8-42
 */
#define CXL_EVENT_RECORD_FLAG_PERMANENT		BIT(2)
#define CXL_EVENT_RECORD_FLAG_MAINT_NEEDED	BIT(3)
#define CXL_EVENT_RECORD_FLAG_PERF_DEGRADED	BIT(4)
#define CXL_EVENT_RECORD_FLAG_HW_REPLACE	BIT(5)
#define show_hdr_flags(flags)	__print_flags(flags, " | ",			   \
	{ CXL_EVENT_RECORD_FLAG_PERMANENT,	"PERMANENT_CONDITION"		}, \
	{ CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,	"MAINTENANCE_NEEDED"		}, \
	{ CXL_EVENT_RECORD_FLAG_PERF_DEGRADED,	"PERFORMANCE_DEGRADED"		}, \
	{ CXL_EVENT_RECORD_FLAG_HW_REPLACE,	"HARDWARE_REPLACEMENT_NEEDED"	}  \
)

/*
 * Define macros for the common header of each CXL event.
 *
 * Tracepoints using these macros must do 3 things:
 *
 *	1) Add CXL_EVT_TP_entry to TP_STRUCT__entry
 *	2) Use CXL_EVT_TP_fast_assign within TP_fast_assign;
 *	   pass the dev, log, and CXL event header
 *	3) Use CXL_EVT_TP_printk() instead of TP_printk()
 *
 * See the generic_event tracepoint as an example.
 */
#define CXL_EVT_TP_entry					\
	__string(dev_name, dev_name(dev))			\
	__field(int, log)					\
	__field_struct(uuid_t, hdr_uuid)			\
	__field(u32, hdr_flags)					\
	__field(u16, hdr_handle)				\
	__field(u16, hdr_related_handle)			\
	__field(u64, hdr_timestamp)				\
	__field(u8, hdr_length)					\
	__field(u8, hdr_maint_op_class)

#define CXL_EVT_TP_fast_assign(dev, l, hdr)					\
	__assign_str(dev_name, dev_name(dev));					\
	__entry->log = (l);							\
	memcpy(&__entry->hdr_uuid, &(hdr).id, sizeof(uuid_t));			\
	__entry->hdr_length = (hdr).length;					\
	__entry->hdr_flags = get_unaligned_le24((hdr).flags);			\
	__entry->hdr_handle = le16_to_cpu((hdr).handle);			\
	__entry->hdr_related_handle = le16_to_cpu((hdr).related_handle);	\
	__entry->hdr_timestamp = le64_to_cpu((hdr).timestamp);			\
	__entry->hdr_maint_op_class = (hdr).maint_op_class

#define CXL_EVT_TP_printk(fmt, ...) \
	TP_printk("%s log=%s : time=%llu uuid=%pUb len=%d flags='%s' "		\
		"handle=%x related_handle=%x maint_op_class=%u"			\
		" : " fmt,							\
		__get_str(dev_name), cxl_event_log_type_str(__entry->log),	\
		__entry->hdr_timestamp, &__entry->hdr_uuid, __entry->hdr_length,\
		show_hdr_flags(__entry->hdr_flags), __entry->hdr_handle,	\
		__entry->hdr_related_handle, __entry->hdr_maint_op_class,	\
		##__VA_ARGS__)

TRACE_EVENT(cxl_generic_event,

	TP_PROTO(const struct device *dev, enum cxl_event_log_type log,
		 struct cxl_event_record_raw *rec),

	TP_ARGS(dev, log, rec),

	TP_STRUCT__entry(
		CXL_EVT_TP_entry
		__array(u8, data, CXL_EVENT_RECORD_DATA_LENGTH)
	),

	TP_fast_assign(
		CXL_EVT_TP_fast_assign(dev, log, rec->hdr);
		memcpy(__entry->data, &rec->data, CXL_EVENT_RECORD_DATA_LENGTH);
	),

	CXL_EVT_TP_printk("%s",
		__print_hex(__entry->data, CXL_EVENT_RECORD_DATA_LENGTH))
);

/*
 * Physical Address field masks
 *
 * General Media Event Record
 * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
 *
 * DRAM Event Record
 * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
 */
#define CXL_DPA_FLAGS_MASK			0x3F
#define CXL_DPA_MASK				(~CXL_DPA_FLAGS_MASK)

#define CXL_DPA_VOLATILE			BIT(0)
#define CXL_DPA_NOT_REPAIRABLE			BIT(1)
#define show_dpa_flags(flags)	__print_flags(flags, "|",		   \
	{ CXL_DPA_VOLATILE,			"VOLATILE"		}, \
	{ CXL_DPA_NOT_REPAIRABLE,		"NOT_REPAIRABLE"	}  \
)

/*
 * General Media Event Record - GMER
 * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
 */
#define CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT		BIT(0)
#define CXL_GMER_EVT_DESC_THRESHOLD_EVENT		BIT(1)
#define CXL_GMER_EVT_DESC_POISON_LIST_OVERFLOW		BIT(2)
#define show_event_desc_flags(flags)	__print_flags(flags, "|",		   \
	{ CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT,		"UNCORRECTABLE_EVENT"	}, \
	{ CXL_GMER_EVT_DESC_THRESHOLD_EVENT,		"THRESHOLD_EVENT"	}, \
	{ CXL_GMER_EVT_DESC_POISON_LIST_OVERFLOW,	"POISON_LIST_OVERFLOW"	}  \
)

#define CXL_GMER_MEM_EVT_TYPE_ECC_ERROR			0x00
#define CXL_GMER_MEM_EVT_TYPE_INV_ADDR			0x01
#define CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR		0x02
#define show_mem_event_type(type)	__print_symbolic(type,			\
	{ CXL_GMER_MEM_EVT_TYPE_ECC_ERROR,		"ECC Error" },		\
	{ CXL_GMER_MEM_EVT_TYPE_INV_ADDR,		"Invalid Address" },	\
	{ CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR,	"Data Path Error" }	\
)

#define CXL_GMER_TRANS_UNKNOWN				0x00
#define CXL_GMER_TRANS_HOST_READ			0x01
#define CXL_GMER_TRANS_HOST_WRITE			0x02
#define CXL_GMER_TRANS_HOST_SCAN_MEDIA			0x03
#define CXL_GMER_TRANS_HOST_INJECT_POISON		0x04
#define CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB		0x05
#define CXL_GMER_TRANS_INTERNAL_MEDIA_MANAGEMENT	0x06
#define show_trans_type(type)	__print_symbolic(type,					\
	{ CXL_GMER_TRANS_UNKNOWN,			"Unknown" },			\
	{ CXL_GMER_TRANS_HOST_READ,			"Host Read" },			\
	{ CXL_GMER_TRANS_HOST_WRITE,			"Host Write" },			\
	{ CXL_GMER_TRANS_HOST_SCAN_MEDIA,		"Host Scan Media" },		\
	{ CXL_GMER_TRANS_HOST_INJECT_POISON,		"Host Inject Poison" },		\
	{ CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB,		"Internal Media Scrub" },	\
	{ CXL_GMER_TRANS_INTERNAL_MEDIA_MANAGEMENT,	"Internal Media Management" }	\
)

#define CXL_GMER_VALID_CHANNEL				BIT(0)
#define CXL_GMER_VALID_RANK				BIT(1)
#define CXL_GMER_VALID_DEVICE				BIT(2)
#define CXL_GMER_VALID_COMPONENT			BIT(3)
#define show_valid_flags(flags)	__print_flags(flags, "|",		   \
	{ CXL_GMER_VALID_CHANNEL,			"CHANNEL"	}, \
	{ CXL_GMER_VALID_RANK,				"RANK"		}, \
	{ CXL_GMER_VALID_DEVICE,			"DEVICE"	}, \
	{ CXL_GMER_VALID_COMPONENT,			"COMPONENT"	}  \
)

TRACE_EVENT(cxl_general_media,

	TP_PROTO(const struct device *dev, enum cxl_event_log_type log,
		 struct cxl_event_gen_media *rec),

	TP_ARGS(dev, log, rec),

	TP_STRUCT__entry(
		CXL_EVT_TP_entry
		/* General Media */
		__field(u64, dpa)
		__field(u8, descriptor)
		__field(u8, type)
		__field(u8, transaction_type)
		__field(u8, channel)
		__field(u32, device)
		__array(u8, comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE)
		__field(u16, validity_flags)
		/* Following are out of order to pack trace record */
		__field(u8, rank)
		__field(u8, dpa_flags)
	),

	TP_fast_assign(
		CXL_EVT_TP_fast_assign(dev, log, rec->hdr);

		/* General Media */
		__entry->dpa = le64_to_cpu(rec->phys_addr);
		__entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK;
		/* Mask after flags have been parsed */
		__entry->dpa &= CXL_DPA_MASK;
		__entry->descriptor = rec->descriptor;
		__entry->type = rec->type;
		__entry->transaction_type = rec->transaction_type;
		__entry->channel = rec->channel;
		__entry->rank = rec->rank;
		__entry->device = get_unaligned_le24(rec->device);
		memcpy(__entry->comp_id, &rec->component_id,
			CXL_EVENT_GEN_MED_COMP_ID_SIZE);
		__entry->validity_flags = get_unaligned_le16(&rec->validity_flags);
	),

	CXL_EVT_TP_printk("dpa=%llx dpa_flags='%s' " \
		"descriptor='%s' type='%s' transaction_type='%s' channel=%u rank=%u " \
		"device=%x comp_id=%s validity_flags='%s'",
		__entry->dpa, show_dpa_flags(__entry->dpa_flags),
		show_event_desc_flags(__entry->descriptor),
		show_mem_event_type(__entry->type),
		show_trans_type(__entry->transaction_type),
		__entry->channel, __entry->rank, __entry->device,
		__print_hex(__entry->comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE),
		show_valid_flags(__entry->validity_flags)
	)
);

/*
 * DRAM Event Record - DER
 *
 * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
 */
/*
 * DRAM Event Record defines many fields the same as the General Media Event
 * Record.  Reuse those definitions as appropriate.
 */
#define CXL_DER_VALID_CHANNEL				BIT(0)
#define CXL_DER_VALID_RANK				BIT(1)
#define CXL_DER_VALID_NIBBLE				BIT(2)
#define CXL_DER_VALID_BANK_GROUP			BIT(3)
#define CXL_DER_VALID_BANK				BIT(4)
#define CXL_DER_VALID_ROW				BIT(5)
#define CXL_DER_VALID_COLUMN				BIT(6)
#define CXL_DER_VALID_CORRECTION_MASK			BIT(7)
#define show_dram_valid_flags(flags)	__print_flags(flags, "|",			   \
	{ CXL_DER_VALID_CHANNEL,			"CHANNEL"		}, \
	{ CXL_DER_VALID_RANK,				"RANK"			}, \
	{ CXL_DER_VALID_NIBBLE,				"NIBBLE"		}, \
	{ CXL_DER_VALID_BANK_GROUP,			"BANK GROUP"		}, \
	{ CXL_DER_VALID_BANK,				"BANK"			}, \
	{ CXL_DER_VALID_ROW,				"ROW"			}, \
	{ CXL_DER_VALID_COLUMN,				"COLUMN"		}, \
	{ CXL_DER_VALID_CORRECTION_MASK,		"CORRECTION MASK"	}  \
)

TRACE_EVENT(cxl_dram,

	TP_PROTO(const struct device *dev, enum cxl_event_log_type log,
		 struct cxl_event_dram *rec),

	TP_ARGS(dev, log, rec),

	TP_STRUCT__entry(
		CXL_EVT_TP_entry
		/* DRAM */
		__field(u64, dpa)
		__field(u8, descriptor)
		__field(u8, type)
		__field(u8, transaction_type)
		__field(u8, channel)
		__field(u16, validity_flags)
		__field(u16, column)	/* Out of order to pack trace record */
		__field(u32, nibble_mask)
		__field(u32, row)
		__array(u8, cor_mask, CXL_EVENT_DER_CORRECTION_MASK_SIZE)
		__field(u8, rank)	/* Out of order to pack trace record */
		__field(u8, bank_group)	/* Out of order to pack trace record */
		__field(u8, bank)	/* Out of order to pack trace record */
		__field(u8, dpa_flags)	/* Out of order to pack trace record */
	),

	TP_fast_assign(
		CXL_EVT_TP_fast_assign(dev, log, rec->hdr);

		/* DRAM */
		__entry->dpa = le64_to_cpu(rec->phys_addr);
		__entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK;
		__entry->dpa &= CXL_DPA_MASK;
		__entry->descriptor = rec->descriptor;
		__entry->type = rec->type;
		__entry->transaction_type = rec->transaction_type;
		__entry->validity_flags = get_unaligned_le16(rec->validity_flags);
		__entry->channel = rec->channel;
		__entry->rank = rec->rank;
		__entry->nibble_mask = get_unaligned_le24(rec->nibble_mask);
		__entry->bank_group = rec->bank_group;
		__entry->bank = rec->bank;
		__entry->row = get_unaligned_le24(rec->row);
		__entry->column = get_unaligned_le16(rec->column);
		memcpy(__entry->cor_mask, &rec->correction_mask,
			CXL_EVENT_DER_CORRECTION_MASK_SIZE);
	),

	CXL_EVT_TP_printk("dpa=%llx dpa_flags='%s' descriptor='%s' type='%s' " \
		"transaction_type='%s' channel=%u rank=%u nibble_mask=%x " \
		"bank_group=%u bank=%u row=%u column=%u cor_mask=%s " \
		"validity_flags='%s'",
		__entry->dpa, show_dpa_flags(__entry->dpa_flags),
		show_event_desc_flags(__entry->descriptor),
		show_mem_event_type(__entry->type),
		show_trans_type(__entry->transaction_type),
		__entry->channel, __entry->rank, __entry->nibble_mask,
		__entry->bank_group, __entry->bank,
		__entry->row, __entry->column,
		__print_hex(__entry->cor_mask, CXL_EVENT_DER_CORRECTION_MASK_SIZE),
		show_dram_valid_flags(__entry->validity_flags)
	)
);

/*
 * Memory Module Event Record - MMER
 *
 * CXL res 3.0 section 8.2.9.2.1.3; Table 8-45
 */
#define CXL_MMER_HEALTH_STATUS_CHANGE		0x00
#define CXL_MMER_MEDIA_STATUS_CHANGE		0x01
#define CXL_MMER_LIFE_USED_CHANGE		0x02
#define CXL_MMER_TEMP_CHANGE			0x03
#define CXL_MMER_DATA_PATH_ERROR		0x04
#define CXL_MMER_LSA_ERROR			0x05
#define show_dev_evt_type(type)	__print_symbolic(type,			   \
	{ CXL_MMER_HEALTH_STATUS_CHANGE,	"Health Status Change"	}, \
	{ CXL_MMER_MEDIA_STATUS_CHANGE,		"Media Status Change"	}, \
	{ CXL_MMER_LIFE_USED_CHANGE,		"Life Used Change"	}, \
	{ CXL_MMER_TEMP_CHANGE,			"Temperature Change"	}, \
	{ CXL_MMER_DATA_PATH_ERROR,		"Data Path Error"	}, \
	{ CXL_MMER_LSA_ERROR,			"LSA Error"		}  \
)

/*
 * Device Health Information - DHI
 *
 * CXL res 3.0 section 8.2.9.8.3.1; Table 8-100
 */
#define CXL_DHI_HS_MAINTENANCE_NEEDED				BIT(0)
#define CXL_DHI_HS_PERFORMANCE_DEGRADED				BIT(1)
#define CXL_DHI_HS_HW_REPLACEMENT_NEEDED			BIT(2)
#define show_health_status_flags(flags)	__print_flags(flags, "|",	   \
	{ CXL_DHI_HS_MAINTENANCE_NEEDED,	"MAINTENANCE_NEEDED"	}, \
	{ CXL_DHI_HS_PERFORMANCE_DEGRADED,	"PERFORMANCE_DEGRADED"	}, \
	{ CXL_DHI_HS_HW_REPLACEMENT_NEEDED,	"REPLACEMENT_NEEDED"	}  \
)

#define CXL_DHI_MS_NORMAL							0x00
#define CXL_DHI_MS_NOT_READY							0x01
#define CXL_DHI_MS_WRITE_PERSISTENCY_LOST					0x02
#define CXL_DHI_MS_ALL_DATA_LOST						0x03
#define CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_POWER_LOSS			0x04
#define CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_SHUTDOWN			0x05
#define CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_IMMINENT				0x06
#define CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_POWER_LOSS				0x07
#define CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_SHUTDOWN				0x08
#define CXL_DHI_MS_WRITE_ALL_DATA_LOSS_IMMINENT					0x09
#define show_media_status(ms)	__print_symbolic(ms,			   \
	{ CXL_DHI_MS_NORMAL,						   \
		"Normal"						}, \
	{ CXL_DHI_MS_NOT_READY,						   \
		"Not Ready"						}, \
	{ CXL_DHI_MS_WRITE_PERSISTENCY_LOST,				   \
		"Write Persistency Lost"				}, \
	{ CXL_DHI_MS_ALL_DATA_LOST,					   \
		"All Data Lost"						}, \
	{ CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_POWER_LOSS,		   \
		"Write Persistency Loss in the Event of Power Loss"	}, \
	{ CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_SHUTDOWN,		   \
		"Write Persistency Loss in Event of Shutdown"		}, \
	{ CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_IMMINENT,			   \
		"Write Persistency Loss Imminent"			}, \
	{ CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_POWER_LOSS,		   \
		"All Data Loss in Event of Power Loss"			}, \
	{ CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_SHUTDOWN,		   \
		"All Data loss in the Event of Shutdown"		}, \
	{ CXL_DHI_MS_WRITE_ALL_DATA_LOSS_IMMINENT,			   \
		"All Data Loss Imminent"				}  \
)

#define CXL_DHI_AS_NORMAL		0x0
#define CXL_DHI_AS_WARNING		0x1
#define CXL_DHI_AS_CRITICAL		0x2
#define show_two_bit_status(as) __print_symbolic(as,	   \
	{ CXL_DHI_AS_NORMAL,		"Normal"	}, \
	{ CXL_DHI_AS_WARNING,		"Warning"	}, \
	{ CXL_DHI_AS_CRITICAL,		"Critical"	}  \
)
#define show_one_bit_status(as) __print_symbolic(as,	   \
	{ CXL_DHI_AS_NORMAL,		"Normal"	}, \
	{ CXL_DHI_AS_WARNING,		"Warning"	}  \
)

#define CXL_DHI_AS_LIFE_USED(as)			(as & 0x3)
#define CXL_DHI_AS_DEV_TEMP(as)				((as & 0xC) >> 2)
#define CXL_DHI_AS_COR_VOL_ERR_CNT(as)			((as & 0x10) >> 4)
#define CXL_DHI_AS_COR_PER_ERR_CNT(as)			((as & 0x20) >> 5)

TRACE_EVENT(cxl_memory_module,

	TP_PROTO(const struct device *dev, enum cxl_event_log_type log,
		 struct cxl_event_mem_module *rec),

	TP_ARGS(dev, log, rec),

	TP_STRUCT__entry(
		CXL_EVT_TP_entry

		/* Memory Module Event */
		__field(u8, event_type)

		/* Device Health Info */
		__field(u8, health_status)
		__field(u8, media_status)
		__field(u8, life_used)
		__field(u32, dirty_shutdown_cnt)
		__field(u32, cor_vol_err_cnt)
		__field(u32, cor_per_err_cnt)
		__field(s16, device_temp)
		__field(u8, add_status)
	),

	TP_fast_assign(
		CXL_EVT_TP_fast_assign(dev, log, rec->hdr);

		/* Memory Module Event */
		__entry->event_type = rec->event_type;

		/* Device Health Info */
		__entry->health_status = rec->info.health_status;
		__entry->media_status = rec->info.media_status;
		__entry->life_used = rec->info.life_used;
		__entry->dirty_shutdown_cnt = get_unaligned_le32(rec->info.dirty_shutdown_cnt);
		__entry->cor_vol_err_cnt = get_unaligned_le32(rec->info.cor_vol_err_cnt);
		__entry->cor_per_err_cnt = get_unaligned_le32(rec->info.cor_per_err_cnt);
		__entry->device_temp = get_unaligned_le16(rec->info.device_temp);
		__entry->add_status = rec->info.add_status;
	),

	CXL_EVT_TP_printk("event_type='%s' health_status='%s' media_status='%s' " \
		"as_life_used=%s as_dev_temp=%s as_cor_vol_err_cnt=%s " \
		"as_cor_per_err_cnt=%s life_used=%u device_temp=%d " \
		"dirty_shutdown_cnt=%u cor_vol_err_cnt=%u cor_per_err_cnt=%u",
		show_dev_evt_type(__entry->event_type),
		show_health_status_flags(__entry->health_status),
		show_media_status(__entry->media_status),
		show_two_bit_status(CXL_DHI_AS_LIFE_USED(__entry->add_status)),
		show_two_bit_status(CXL_DHI_AS_DEV_TEMP(__entry->add_status)),
		show_one_bit_status(CXL_DHI_AS_COR_VOL_ERR_CNT(__entry->add_status)),
		show_one_bit_status(CXL_DHI_AS_COR_PER_ERR_CNT(__entry->add_status)),
		__entry->life_used, __entry->device_temp,
		__entry->dirty_shutdown_cnt, __entry->cor_vol_err_cnt,
		__entry->cor_per_err_cnt
	)
);

#endif /* _CXL_EVENTS_H */

#define TRACE_INCLUDE_FILE trace
+16 −0
Original line number Diff line number Diff line
@@ -156,6 +156,22 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
#define CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX 0x3
#define CXLDEV_CAP_CAP_ID_MEMDEV 0x4000

/* CXL 3.0 8.2.8.3.1 Event Status Register */
#define CXLDEV_DEV_EVENT_STATUS_OFFSET		0x00
#define CXLDEV_EVENT_STATUS_INFO		BIT(0)
#define CXLDEV_EVENT_STATUS_WARN		BIT(1)
#define CXLDEV_EVENT_STATUS_FAIL		BIT(2)
#define CXLDEV_EVENT_STATUS_FATAL		BIT(3)

#define CXLDEV_EVENT_STATUS_ALL (CXLDEV_EVENT_STATUS_INFO |	\
				 CXLDEV_EVENT_STATUS_WARN |	\
				 CXLDEV_EVENT_STATUS_FAIL |	\
				 CXLDEV_EVENT_STATUS_FATAL)

/* CXL rev 3.0 section 8.2.9.2.4; Table 8-52 */
#define CXLDEV_EVENT_INT_MODE_MASK	GENMASK(1, 0)
#define CXLDEV_EVENT_INT_MSGNUM_MASK	GENMASK(7, 4)

/* CXL 2.0 8.2.8.4 Mailbox Registers */
#define CXLDEV_MBOX_CAPS_OFFSET 0x00
#define   CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK GENMASK(4, 0)
+175 −0

File changed.

Preview size limit exceeded, changes collapsed.

+6 −0
Original line number Diff line number Diff line
@@ -53,6 +53,12 @@
#define	    CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK			GENMASK(15, 8)
#define     CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK		GENMASK(31, 16)

/*
 * NOTE: Currently all the functions which are enabled for CXL require their
 * vectors to be in the first 16.  Use this as the default max.
 */
#define CXL_PCI_DEFAULT_MAX_VECTORS 16

/* Register Block Identifier (RBI) */
enum cxl_regloc_type {
	CXL_REGLOC_RBI_EMPTY = 0,
Loading