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
1214static bool cxl_raw_allow_all ;
1315
@@ -737,6 +739,203 @@ int cxl_enumerate_cmds(struct cxl_dev_state *cxlds)
737739}
738740EXPORT_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}
8781077EXPORT_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+
8801105struct 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