@@ -678,6 +678,312 @@ static struct perf_ibs perf_ibs_op = {
678678 .get_count = get_ibs_op_count ,
679679};
680680
681+ static void perf_ibs_get_mem_op (union ibs_op_data3 * op_data3 ,
682+ struct perf_sample_data * data )
683+ {
684+ union perf_mem_data_src * data_src = & data -> data_src ;
685+
686+ data_src -> mem_op = PERF_MEM_OP_NA ;
687+
688+ if (op_data3 -> ld_op )
689+ data_src -> mem_op = PERF_MEM_OP_LOAD ;
690+ else if (op_data3 -> st_op )
691+ data_src -> mem_op = PERF_MEM_OP_STORE ;
692+ }
693+
694+ /*
695+ * Processors having CPUID_Fn8000001B_EAX[11] aka IBS_CAPS_ZEN4 has
696+ * more fine granular DataSrc encodings. Others have coarse.
697+ */
698+ static u8 perf_ibs_data_src (union ibs_op_data2 * op_data2 )
699+ {
700+ if (ibs_caps & IBS_CAPS_ZEN4 )
701+ return (op_data2 -> data_src_hi << 3 ) | op_data2 -> data_src_lo ;
702+
703+ return op_data2 -> data_src_lo ;
704+ }
705+
706+ static void perf_ibs_get_mem_lvl (union ibs_op_data2 * op_data2 ,
707+ union ibs_op_data3 * op_data3 ,
708+ struct perf_sample_data * data )
709+ {
710+ union perf_mem_data_src * data_src = & data -> data_src ;
711+ u8 ibs_data_src = perf_ibs_data_src (op_data2 );
712+
713+ data_src -> mem_lvl = 0 ;
714+
715+ /*
716+ * DcMiss, L2Miss, DataSrc, DcMissLat etc. are all invalid for Uncached
717+ * memory accesses. So, check DcUcMemAcc bit early.
718+ */
719+ if (op_data3 -> dc_uc_mem_acc && ibs_data_src != IBS_DATA_SRC_EXT_IO ) {
720+ data_src -> mem_lvl = PERF_MEM_LVL_UNC | PERF_MEM_LVL_HIT ;
721+ return ;
722+ }
723+
724+ /* L1 Hit */
725+ if (op_data3 -> dc_miss == 0 ) {
726+ data_src -> mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT ;
727+ return ;
728+ }
729+
730+ /* L2 Hit */
731+ if (op_data3 -> l2_miss == 0 ) {
732+ /* Erratum #1293 */
733+ if (boot_cpu_data .x86 != 0x19 || boot_cpu_data .x86_model > 0xF ||
734+ !(op_data3 -> sw_pf || op_data3 -> dc_miss_no_mab_alloc )) {
735+ data_src -> mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT ;
736+ return ;
737+ }
738+ }
739+
740+ /*
741+ * OP_DATA2 is valid only for load ops. Skip all checks which
742+ * uses OP_DATA2[DataSrc].
743+ */
744+ if (data_src -> mem_op != PERF_MEM_OP_LOAD )
745+ goto check_mab ;
746+
747+ /* L3 Hit */
748+ if (ibs_caps & IBS_CAPS_ZEN4 ) {
749+ if (ibs_data_src == IBS_DATA_SRC_EXT_LOC_CACHE ) {
750+ data_src -> mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT ;
751+ return ;
752+ }
753+ } else {
754+ if (ibs_data_src == IBS_DATA_SRC_LOC_CACHE ) {
755+ data_src -> mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_REM_CCE1 |
756+ PERF_MEM_LVL_HIT ;
757+ return ;
758+ }
759+ }
760+
761+ /* A peer cache in a near CCX */
762+ if (ibs_caps & IBS_CAPS_ZEN4 &&
763+ ibs_data_src == IBS_DATA_SRC_EXT_NEAR_CCX_CACHE ) {
764+ data_src -> mem_lvl = PERF_MEM_LVL_REM_CCE1 | PERF_MEM_LVL_HIT ;
765+ return ;
766+ }
767+
768+ /* A peer cache in a far CCX */
769+ if (ibs_caps & IBS_CAPS_ZEN4 ) {
770+ if (ibs_data_src == IBS_DATA_SRC_EXT_FAR_CCX_CACHE ) {
771+ data_src -> mem_lvl = PERF_MEM_LVL_REM_CCE2 | PERF_MEM_LVL_HIT ;
772+ return ;
773+ }
774+ } else {
775+ if (ibs_data_src == IBS_DATA_SRC_REM_CACHE ) {
776+ data_src -> mem_lvl = PERF_MEM_LVL_REM_CCE2 | PERF_MEM_LVL_HIT ;
777+ return ;
778+ }
779+ }
780+
781+ /* DRAM */
782+ if (ibs_data_src == IBS_DATA_SRC_EXT_DRAM ) {
783+ if (op_data2 -> rmt_node == 0 )
784+ data_src -> mem_lvl = PERF_MEM_LVL_LOC_RAM | PERF_MEM_LVL_HIT ;
785+ else
786+ data_src -> mem_lvl = PERF_MEM_LVL_REM_RAM1 | PERF_MEM_LVL_HIT ;
787+ return ;
788+ }
789+
790+ /* PMEM */
791+ if (ibs_caps & IBS_CAPS_ZEN4 && ibs_data_src == IBS_DATA_SRC_EXT_PMEM ) {
792+ data_src -> mem_lvl_num = PERF_MEM_LVLNUM_PMEM ;
793+ if (op_data2 -> rmt_node ) {
794+ data_src -> mem_remote = PERF_MEM_REMOTE_REMOTE ;
795+ /* IBS doesn't provide Remote socket detail */
796+ data_src -> mem_hops = PERF_MEM_HOPS_1 ;
797+ }
798+ return ;
799+ }
800+
801+ /* Extension Memory */
802+ if (ibs_caps & IBS_CAPS_ZEN4 &&
803+ ibs_data_src == IBS_DATA_SRC_EXT_EXT_MEM ) {
804+ data_src -> mem_lvl_num = PERF_MEM_LVLNUM_EXTN_MEM ;
805+ if (op_data2 -> rmt_node ) {
806+ data_src -> mem_remote = PERF_MEM_REMOTE_REMOTE ;
807+ /* IBS doesn't provide Remote socket detail */
808+ data_src -> mem_hops = PERF_MEM_HOPS_1 ;
809+ }
810+ return ;
811+ }
812+
813+ /* IO */
814+ if (ibs_data_src == IBS_DATA_SRC_EXT_IO ) {
815+ data_src -> mem_lvl = PERF_MEM_LVL_IO ;
816+ data_src -> mem_lvl_num = PERF_MEM_LVLNUM_IO ;
817+ if (op_data2 -> rmt_node ) {
818+ data_src -> mem_remote = PERF_MEM_REMOTE_REMOTE ;
819+ /* IBS doesn't provide Remote socket detail */
820+ data_src -> mem_hops = PERF_MEM_HOPS_1 ;
821+ }
822+ return ;
823+ }
824+
825+ check_mab :
826+ /*
827+ * MAB (Miss Address Buffer) Hit. MAB keeps track of outstanding
828+ * DC misses. However, such data may come from any level in mem
829+ * hierarchy. IBS provides detail about both MAB as well as actual
830+ * DataSrc simultaneously. Prioritize DataSrc over MAB, i.e. set
831+ * MAB only when IBS fails to provide DataSrc.
832+ */
833+ if (op_data3 -> dc_miss_no_mab_alloc ) {
834+ data_src -> mem_lvl = PERF_MEM_LVL_LFB | PERF_MEM_LVL_HIT ;
835+ return ;
836+ }
837+
838+ data_src -> mem_lvl = PERF_MEM_LVL_NA ;
839+ }
840+
841+ static bool perf_ibs_cache_hit_st_valid (void )
842+ {
843+ /* 0: Uninitialized, 1: Valid, -1: Invalid */
844+ static int cache_hit_st_valid ;
845+
846+ if (unlikely (!cache_hit_st_valid )) {
847+ if (boot_cpu_data .x86 == 0x19 &&
848+ (boot_cpu_data .x86_model <= 0xF ||
849+ (boot_cpu_data .x86_model >= 0x20 &&
850+ boot_cpu_data .x86_model <= 0x5F ))) {
851+ cache_hit_st_valid = -1 ;
852+ } else {
853+ cache_hit_st_valid = 1 ;
854+ }
855+ }
856+
857+ return cache_hit_st_valid == 1 ;
858+ }
859+
860+ static void perf_ibs_get_mem_snoop (union ibs_op_data2 * op_data2 ,
861+ struct perf_sample_data * data )
862+ {
863+ union perf_mem_data_src * data_src = & data -> data_src ;
864+ u8 ibs_data_src ;
865+
866+ data_src -> mem_snoop = PERF_MEM_SNOOP_NA ;
867+
868+ if (!perf_ibs_cache_hit_st_valid () ||
869+ data_src -> mem_op != PERF_MEM_OP_LOAD ||
870+ data_src -> mem_lvl & PERF_MEM_LVL_L1 ||
871+ data_src -> mem_lvl & PERF_MEM_LVL_L2 ||
872+ op_data2 -> cache_hit_st )
873+ return ;
874+
875+ ibs_data_src = perf_ibs_data_src (op_data2 );
876+
877+ if (ibs_caps & IBS_CAPS_ZEN4 ) {
878+ if (ibs_data_src == IBS_DATA_SRC_EXT_LOC_CACHE ||
879+ ibs_data_src == IBS_DATA_SRC_EXT_NEAR_CCX_CACHE ||
880+ ibs_data_src == IBS_DATA_SRC_EXT_FAR_CCX_CACHE )
881+ data_src -> mem_snoop = PERF_MEM_SNOOP_HITM ;
882+ } else if (ibs_data_src == IBS_DATA_SRC_LOC_CACHE ) {
883+ data_src -> mem_snoop = PERF_MEM_SNOOP_HITM ;
884+ }
885+ }
886+
887+ static void perf_ibs_get_tlb_lvl (union ibs_op_data3 * op_data3 ,
888+ struct perf_sample_data * data )
889+ {
890+ union perf_mem_data_src * data_src = & data -> data_src ;
891+
892+ data_src -> mem_dtlb = PERF_MEM_TLB_NA ;
893+
894+ if (!op_data3 -> dc_lin_addr_valid )
895+ return ;
896+
897+ if (!op_data3 -> dc_l1tlb_miss ) {
898+ data_src -> mem_dtlb = PERF_MEM_TLB_L1 | PERF_MEM_TLB_HIT ;
899+ return ;
900+ }
901+
902+ if (!op_data3 -> dc_l2tlb_miss ) {
903+ data_src -> mem_dtlb = PERF_MEM_TLB_L2 | PERF_MEM_TLB_HIT ;
904+ return ;
905+ }
906+
907+ data_src -> mem_dtlb = PERF_MEM_TLB_L2 | PERF_MEM_TLB_MISS ;
908+ }
909+
910+ static void perf_ibs_get_mem_lock (union ibs_op_data3 * op_data3 ,
911+ struct perf_sample_data * data )
912+ {
913+ union perf_mem_data_src * data_src = & data -> data_src ;
914+
915+ data_src -> mem_lock = PERF_MEM_LOCK_NA ;
916+
917+ if (op_data3 -> dc_locked_op )
918+ data_src -> mem_lock = PERF_MEM_LOCK_LOCKED ;
919+ }
920+
921+ #define ibs_op_msr_idx (msr ) (msr - MSR_AMD64_IBSOPCTL)
922+
923+ static void perf_ibs_get_data_src (struct perf_ibs_data * ibs_data ,
924+ struct perf_sample_data * data ,
925+ union ibs_op_data2 * op_data2 ,
926+ union ibs_op_data3 * op_data3 )
927+ {
928+ perf_ibs_get_mem_lvl (op_data2 , op_data3 , data );
929+ perf_ibs_get_mem_snoop (op_data2 , data );
930+ perf_ibs_get_tlb_lvl (op_data3 , data );
931+ perf_ibs_get_mem_lock (op_data3 , data );
932+ }
933+
934+ static __u64 perf_ibs_get_op_data2 (struct perf_ibs_data * ibs_data ,
935+ union ibs_op_data3 * op_data3 )
936+ {
937+ __u64 val = ibs_data -> regs [ibs_op_msr_idx (MSR_AMD64_IBSOPDATA2 )];
938+
939+ /* Erratum #1293 */
940+ if (boot_cpu_data .x86 == 0x19 && boot_cpu_data .x86_model <= 0xF &&
941+ (op_data3 -> sw_pf || op_data3 -> dc_miss_no_mab_alloc )) {
942+ /*
943+ * OP_DATA2 has only two fields on Zen3: DataSrc and RmtNode.
944+ * DataSrc=0 is 'No valid status' and RmtNode is invalid when
945+ * DataSrc=0.
946+ */
947+ val = 0 ;
948+ }
949+ return val ;
950+ }
951+
952+ static void perf_ibs_parse_ld_st_data (__u64 sample_type ,
953+ struct perf_ibs_data * ibs_data ,
954+ struct perf_sample_data * data )
955+ {
956+ union ibs_op_data3 op_data3 ;
957+ union ibs_op_data2 op_data2 ;
958+
959+ data -> data_src .val = PERF_MEM_NA ;
960+ op_data3 .val = ibs_data -> regs [ibs_op_msr_idx (MSR_AMD64_IBSOPDATA3 )];
961+
962+ perf_ibs_get_mem_op (& op_data3 , data );
963+ if (data -> data_src .mem_op != PERF_MEM_OP_LOAD &&
964+ data -> data_src .mem_op != PERF_MEM_OP_STORE )
965+ return ;
966+
967+ op_data2 .val = perf_ibs_get_op_data2 (ibs_data , & op_data3 );
968+
969+ if (sample_type & PERF_SAMPLE_DATA_SRC ) {
970+ perf_ibs_get_data_src (ibs_data , data , & op_data2 , & op_data3 );
971+ data -> sample_flags |= PERF_SAMPLE_DATA_SRC ;
972+ }
973+ }
974+
975+ static int perf_ibs_get_offset_max (struct perf_ibs * perf_ibs , u64 sample_type ,
976+ int check_rip )
977+ {
978+ if (sample_type & PERF_SAMPLE_RAW ||
979+ (perf_ibs == & perf_ibs_op &&
980+ sample_type & PERF_SAMPLE_DATA_SRC ))
981+ return perf_ibs -> offset_max ;
982+ else if (check_rip )
983+ return 3 ;
984+ return 1 ;
985+ }
986+
681987static int perf_ibs_handle_irq (struct perf_ibs * perf_ibs , struct pt_regs * iregs )
682988{
683989 struct cpu_perf_ibs * pcpu = this_cpu_ptr (perf_ibs -> pcpu );
@@ -725,12 +1031,9 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
7251031 size = 1 ;
7261032 offset = 1 ;
7271033 check_rip = (perf_ibs == & perf_ibs_op && (ibs_caps & IBS_CAPS_RIPINVALIDCHK ));
728- if (event -> attr .sample_type & PERF_SAMPLE_RAW )
729- offset_max = perf_ibs -> offset_max ;
730- else if (check_rip )
731- offset_max = 3 ;
732- else
733- offset_max = 1 ;
1034+
1035+ offset_max = perf_ibs_get_offset_max (perf_ibs , event -> attr .sample_type , check_rip );
1036+
7341037 do {
7351038 rdmsrl (msr + offset , * buf ++ );
7361039 size ++ ;
@@ -784,6 +1087,9 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
7841087 data .sample_flags |= PERF_SAMPLE_RAW ;
7851088 }
7861089
1090+ if (perf_ibs == & perf_ibs_op )
1091+ perf_ibs_parse_ld_st_data (event -> attr .sample_type , & ibs_data , & data );
1092+
7871093 /*
7881094 * rip recorded by IbsOpRip will not be consistent with rsp and rbp
7891095 * recorded as part of interrupt regs. Thus we need to use rip from
0 commit comments