Skip to content

Commit dbe9f7d

Browse files
committed
Merge branch 'for-6.3/cxl-events' into cxl/next
Add the CXL event and interrupt support for the v6.3 update.
2 parents 5485eb9 + 5a84711 commit dbe9f7d

File tree

8 files changed

+1494
-2
lines changed

8 files changed

+1494
-2
lines changed

drivers/cxl/core/mbox.c

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
#include <linux/io-64-nonatomic-lo-hi.h>
44
#include <linux/security.h>
55
#include <linux/debugfs.h>
6+
#include <linux/ktime.h>
67
#include <linux/mutex.h>
78
#include <cxlmem.h>
89
#include <cxl.h>
910

1011
#include "core.h"
12+
#include "trace.h"
1113

1214
static bool cxl_raw_allow_all;
1315

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

742+
/*
743+
* General Media Event Record
744+
* CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
745+
*/
746+
static const uuid_t gen_media_event_uuid =
747+
UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
748+
0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6);
749+
750+
/*
751+
* DRAM Event Record
752+
* CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
753+
*/
754+
static const uuid_t dram_event_uuid =
755+
UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
756+
0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24);
757+
758+
/*
759+
* Memory Module Event Record
760+
* CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
761+
*/
762+
static const uuid_t mem_mod_event_uuid =
763+
UUID_INIT(0xfe927475, 0xdd59, 0x4339,
764+
0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74);
765+
766+
static void cxl_event_trace_record(const struct device *dev,
767+
enum cxl_event_log_type type,
768+
struct cxl_event_record_raw *record)
769+
{
770+
uuid_t *id = &record->hdr.id;
771+
772+
if (uuid_equal(id, &gen_media_event_uuid)) {
773+
struct cxl_event_gen_media *rec =
774+
(struct cxl_event_gen_media *)record;
775+
776+
trace_cxl_general_media(dev, type, rec);
777+
} else if (uuid_equal(id, &dram_event_uuid)) {
778+
struct cxl_event_dram *rec = (struct cxl_event_dram *)record;
779+
780+
trace_cxl_dram(dev, type, rec);
781+
} else if (uuid_equal(id, &mem_mod_event_uuid)) {
782+
struct cxl_event_mem_module *rec =
783+
(struct cxl_event_mem_module *)record;
784+
785+
trace_cxl_memory_module(dev, type, rec);
786+
} else {
787+
/* For unknown record types print just the header */
788+
trace_cxl_generic_event(dev, type, record);
789+
}
790+
}
791+
792+
static int cxl_clear_event_record(struct cxl_dev_state *cxlds,
793+
enum cxl_event_log_type log,
794+
struct cxl_get_event_payload *get_pl)
795+
{
796+
struct cxl_mbox_clear_event_payload *payload;
797+
u16 total = le16_to_cpu(get_pl->record_count);
798+
u8 max_handles = CXL_CLEAR_EVENT_MAX_HANDLES;
799+
size_t pl_size = struct_size(payload, handles, max_handles);
800+
struct cxl_mbox_cmd mbox_cmd;
801+
u16 cnt;
802+
int rc = 0;
803+
int i;
804+
805+
/* Payload size may limit the max handles */
806+
if (pl_size > cxlds->payload_size) {
807+
max_handles = (cxlds->payload_size - sizeof(*payload)) /
808+
sizeof(__le16);
809+
pl_size = struct_size(payload, handles, max_handles);
810+
}
811+
812+
payload = kvzalloc(pl_size, GFP_KERNEL);
813+
if (!payload)
814+
return -ENOMEM;
815+
816+
*payload = (struct cxl_mbox_clear_event_payload) {
817+
.event_log = log,
818+
};
819+
820+
mbox_cmd = (struct cxl_mbox_cmd) {
821+
.opcode = CXL_MBOX_OP_CLEAR_EVENT_RECORD,
822+
.payload_in = payload,
823+
.size_in = pl_size,
824+
};
825+
826+
/*
827+
* Clear Event Records uses u8 for the handle cnt while Get Event
828+
* Record can return up to 0xffff records.
829+
*/
830+
i = 0;
831+
for (cnt = 0; cnt < total; cnt++) {
832+
payload->handles[i++] = get_pl->records[cnt].hdr.handle;
833+
dev_dbg(cxlds->dev, "Event log '%d': Clearing %u\n",
834+
log, le16_to_cpu(payload->handles[i]));
835+
836+
if (i == max_handles) {
837+
payload->nr_recs = i;
838+
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
839+
if (rc)
840+
goto free_pl;
841+
i = 0;
842+
}
843+
}
844+
845+
/* Clear what is left if any */
846+
if (i) {
847+
payload->nr_recs = i;
848+
mbox_cmd.size_in = struct_size(payload, handles, i);
849+
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
850+
if (rc)
851+
goto free_pl;
852+
}
853+
854+
free_pl:
855+
kvfree(payload);
856+
return rc;
857+
}
858+
859+
static void cxl_mem_get_records_log(struct cxl_dev_state *cxlds,
860+
enum cxl_event_log_type type)
861+
{
862+
struct cxl_get_event_payload *payload;
863+
struct cxl_mbox_cmd mbox_cmd;
864+
u8 log_type = type;
865+
u16 nr_rec;
866+
867+
mutex_lock(&cxlds->event.log_lock);
868+
payload = cxlds->event.buf;
869+
870+
mbox_cmd = (struct cxl_mbox_cmd) {
871+
.opcode = CXL_MBOX_OP_GET_EVENT_RECORD,
872+
.payload_in = &log_type,
873+
.size_in = sizeof(log_type),
874+
.payload_out = payload,
875+
.size_out = cxlds->payload_size,
876+
.min_out = struct_size(payload, records, 0),
877+
};
878+
879+
do {
880+
int rc, i;
881+
882+
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
883+
if (rc) {
884+
dev_err_ratelimited(cxlds->dev,
885+
"Event log '%d': Failed to query event records : %d",
886+
type, rc);
887+
break;
888+
}
889+
890+
nr_rec = le16_to_cpu(payload->record_count);
891+
if (!nr_rec)
892+
break;
893+
894+
for (i = 0; i < nr_rec; i++)
895+
cxl_event_trace_record(cxlds->dev, type,
896+
&payload->records[i]);
897+
898+
if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW)
899+
trace_cxl_overflow(cxlds->dev, type, payload);
900+
901+
rc = cxl_clear_event_record(cxlds, type, payload);
902+
if (rc) {
903+
dev_err_ratelimited(cxlds->dev,
904+
"Event log '%d': Failed to clear events : %d",
905+
type, rc);
906+
break;
907+
}
908+
} while (nr_rec);
909+
910+
mutex_unlock(&cxlds->event.log_lock);
911+
}
912+
913+
/**
914+
* cxl_mem_get_event_records - Get Event Records from the device
915+
* @cxlds: The device data for the operation
916+
* @status: Event Status register value identifying which events are available.
917+
*
918+
* Retrieve all event records available on the device, report them as trace
919+
* events, and clear them.
920+
*
921+
* See CXL rev 3.0 @8.2.9.2.2 Get Event Records
922+
* See CXL rev 3.0 @8.2.9.2.3 Clear Event Records
923+
*/
924+
void cxl_mem_get_event_records(struct cxl_dev_state *cxlds, u32 status)
925+
{
926+
dev_dbg(cxlds->dev, "Reading event logs: %x\n", status);
927+
928+
if (status & CXLDEV_EVENT_STATUS_FATAL)
929+
cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_FATAL);
930+
if (status & CXLDEV_EVENT_STATUS_FAIL)
931+
cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_FAIL);
932+
if (status & CXLDEV_EVENT_STATUS_WARN)
933+
cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_WARN);
934+
if (status & CXLDEV_EVENT_STATUS_INFO)
935+
cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_INFO);
936+
}
937+
EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, CXL);
938+
740939
/**
741940
* cxl_mem_get_partition_info - Get partition info
742941
* @cxlds: The device data for the operation
@@ -877,6 +1076,32 @@ int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
8771076
}
8781077
EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL);
8791078

1079+
int cxl_set_timestamp(struct cxl_dev_state *cxlds)
1080+
{
1081+
struct cxl_mbox_cmd mbox_cmd;
1082+
struct cxl_mbox_set_timestamp_in pi;
1083+
int rc;
1084+
1085+
pi.timestamp = cpu_to_le64(ktime_get_real_ns());
1086+
mbox_cmd = (struct cxl_mbox_cmd) {
1087+
.opcode = CXL_MBOX_OP_SET_TIMESTAMP,
1088+
.size_in = sizeof(pi),
1089+
.payload_in = &pi,
1090+
};
1091+
1092+
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
1093+
/*
1094+
* Command is optional. Devices may have another way of providing
1095+
* a timestamp, or may return all 0s in timestamp fields.
1096+
* Don't report an error if this command isn't supported
1097+
*/
1098+
if (rc && (mbox_cmd.return_code != CXL_MBOX_CMD_RC_UNSUPPORTED))
1099+
return rc;
1100+
1101+
return 0;
1102+
}
1103+
EXPORT_SYMBOL_NS_GPL(cxl_set_timestamp, CXL);
1104+
8801105
struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
8811106
{
8821107
struct cxl_dev_state *cxlds;
@@ -888,6 +1113,7 @@ struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
8881113
}
8891114

8901115
mutex_init(&cxlds->mbox_mutex);
1116+
mutex_init(&cxlds->event.log_lock);
8911117
cxlds->dev = dev;
8921118

8931119
return cxlds;

0 commit comments

Comments
 (0)