3
3
#include <linux/io-64-nonatomic-lo-hi.h>
4
4
#include <linux/security.h>
5
5
#include <linux/debugfs.h>
6
+ #include <linux/ktime.h>
6
7
#include <linux/mutex.h>
7
8
#include <cxlmem.h>
8
9
#include <cxl.h>
9
10
10
11
#include "core.h"
12
+ #include "trace.h"
11
13
12
14
static bool cxl_raw_allow_all ;
13
15
@@ -737,6 +739,203 @@ int cxl_enumerate_cmds(struct cxl_dev_state *cxlds)
737
739
}
738
740
EXPORT_SYMBOL_NS_GPL (cxl_enumerate_cmds , CXL );
739
741
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
+
740
939
/**
741
940
* cxl_mem_get_partition_info - Get partition info
742
941
* @cxlds: The device data for the operation
@@ -877,6 +1076,32 @@ int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
877
1076
}
878
1077
EXPORT_SYMBOL_NS_GPL (cxl_mem_create_range_info , CXL );
879
1078
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
+
880
1105
struct cxl_dev_state * cxl_dev_state_create (struct device * dev )
881
1106
{
882
1107
struct cxl_dev_state * cxlds ;
@@ -888,6 +1113,7 @@ struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
888
1113
}
889
1114
890
1115
mutex_init (& cxlds -> mbox_mutex );
1116
+ mutex_init (& cxlds -> event .log_lock );
891
1117
cxlds -> dev = dev ;
892
1118
893
1119
return cxlds ;
0 commit comments