@@ -886,6 +886,241 @@ static int mpam_msc_hw_probe(struct mpam_msc *msc)
886886 return 0 ;
887887}
888888
889+ struct mon_read {
890+ struct mpam_msc_ris * ris ;
891+ struct mon_cfg * ctx ;
892+ enum mpam_device_features type ;
893+ u64 * val ;
894+ int err ;
895+ };
896+
897+ static void gen_msmon_ctl_flt_vals (struct mon_read * m , u32 * ctl_val ,
898+ u32 * flt_val )
899+ {
900+ struct mon_cfg * ctx = m -> ctx ;
901+
902+ /*
903+ * For CSU counters its implementation-defined what happens when not
904+ * filtering by partid.
905+ */
906+ * ctl_val = MSMON_CFG_x_CTL_MATCH_PARTID ;
907+
908+ * flt_val = FIELD_PREP (MSMON_CFG_x_FLT_PARTID , ctx -> partid );
909+
910+ if (m -> ctx -> match_pmg ) {
911+ * ctl_val |= MSMON_CFG_x_CTL_MATCH_PMG ;
912+ * flt_val |= FIELD_PREP (MSMON_CFG_x_FLT_PMG , ctx -> pmg );
913+ }
914+
915+ switch (m -> type ) {
916+ case mpam_feat_msmon_csu :
917+ * ctl_val |= MSMON_CFG_CSU_CTL_TYPE_CSU ;
918+
919+ if (mpam_has_feature (mpam_feat_msmon_csu_xcl , & m -> ris -> props ))
920+ * flt_val |= FIELD_PREP (MSMON_CFG_CSU_FLT_XCL , ctx -> csu_exclude_clean );
921+
922+ break ;
923+ case mpam_feat_msmon_mbwu :
924+ * ctl_val |= MSMON_CFG_MBWU_CTL_TYPE_MBWU ;
925+
926+ if (mpam_has_feature (mpam_feat_msmon_mbwu_rwbw , & m -> ris -> props ))
927+ * flt_val |= FIELD_PREP (MSMON_CFG_MBWU_FLT_RWBW , ctx -> opts );
928+
929+ break ;
930+ default :
931+ pr_warn ("Unexpected monitor type %d\n" , m -> type );
932+ }
933+ }
934+
935+ static void read_msmon_ctl_flt_vals (struct mon_read * m , u32 * ctl_val ,
936+ u32 * flt_val )
937+ {
938+ struct mpam_msc * msc = m -> ris -> vmsc -> msc ;
939+
940+ switch (m -> type ) {
941+ case mpam_feat_msmon_csu :
942+ * ctl_val = mpam_read_monsel_reg (msc , CFG_CSU_CTL );
943+ * flt_val = mpam_read_monsel_reg (msc , CFG_CSU_FLT );
944+ break ;
945+ case mpam_feat_msmon_mbwu :
946+ * ctl_val = mpam_read_monsel_reg (msc , CFG_MBWU_CTL );
947+ * flt_val = mpam_read_monsel_reg (msc , CFG_MBWU_FLT );
948+ break ;
949+ default :
950+ pr_warn ("Unexpected monitor type %d\n" , m -> type );
951+ }
952+ }
953+
954+ /* Remove values set by the hardware to prevent apparent mismatches. */
955+ static inline void clean_msmon_ctl_val (u32 * cur_ctl )
956+ {
957+ * cur_ctl &= ~MSMON_CFG_x_CTL_OFLOW_STATUS ;
958+ }
959+
960+ static void write_msmon_ctl_flt_vals (struct mon_read * m , u32 ctl_val ,
961+ u32 flt_val )
962+ {
963+ struct mpam_msc * msc = m -> ris -> vmsc -> msc ;
964+
965+ /*
966+ * Write the ctl_val with the enable bit cleared, reset the counter,
967+ * then enable counter.
968+ */
969+ switch (m -> type ) {
970+ case mpam_feat_msmon_csu :
971+ mpam_write_monsel_reg (msc , CFG_CSU_FLT , flt_val );
972+ mpam_write_monsel_reg (msc , CFG_CSU_CTL , ctl_val );
973+ mpam_write_monsel_reg (msc , CSU , 0 );
974+ mpam_write_monsel_reg (msc , CFG_CSU_CTL , ctl_val | MSMON_CFG_x_CTL_EN );
975+ break ;
976+ case mpam_feat_msmon_mbwu :
977+ mpam_write_monsel_reg (msc , CFG_MBWU_FLT , flt_val );
978+ mpam_write_monsel_reg (msc , CFG_MBWU_CTL , ctl_val );
979+ mpam_write_monsel_reg (msc , CFG_MBWU_CTL , ctl_val | MSMON_CFG_x_CTL_EN );
980+ /* Counting monitors require NRDY to be reset by software */
981+ mpam_write_monsel_reg (msc , MBWU , 0 );
982+ break ;
983+ default :
984+ pr_warn ("Unexpected monitor type %d\n" , m -> type );
985+ }
986+ }
987+
988+ static void __ris_msmon_read (void * arg )
989+ {
990+ u64 now ;
991+ bool nrdy = false;
992+ bool config_mismatch ;
993+ struct mon_read * m = arg ;
994+ struct mon_cfg * ctx = m -> ctx ;
995+ struct mpam_msc_ris * ris = m -> ris ;
996+ struct mpam_props * rprops = & ris -> props ;
997+ struct mpam_msc * msc = m -> ris -> vmsc -> msc ;
998+ u32 mon_sel , ctl_val , flt_val , cur_ctl , cur_flt ;
999+
1000+ if (!mpam_mon_sel_lock (msc )) {
1001+ m -> err = - EIO ;
1002+ return ;
1003+ }
1004+ mon_sel = FIELD_PREP (MSMON_CFG_MON_SEL_MON_SEL , ctx -> mon ) |
1005+ FIELD_PREP (MSMON_CFG_MON_SEL_RIS , ris -> ris_idx );
1006+ mpam_write_monsel_reg (msc , CFG_MON_SEL , mon_sel );
1007+
1008+ /*
1009+ * Read the existing configuration to avoid re-writing the same values.
1010+ * This saves waiting for 'nrdy' on subsequent reads.
1011+ */
1012+ read_msmon_ctl_flt_vals (m , & cur_ctl , & cur_flt );
1013+ clean_msmon_ctl_val (& cur_ctl );
1014+ gen_msmon_ctl_flt_vals (m , & ctl_val , & flt_val );
1015+ config_mismatch = cur_flt != flt_val ||
1016+ cur_ctl != (ctl_val | MSMON_CFG_x_CTL_EN );
1017+
1018+ if (config_mismatch )
1019+ write_msmon_ctl_flt_vals (m , ctl_val , flt_val );
1020+
1021+ switch (m -> type ) {
1022+ case mpam_feat_msmon_csu :
1023+ now = mpam_read_monsel_reg (msc , CSU );
1024+ if (mpam_has_feature (mpam_feat_msmon_csu_hw_nrdy , rprops ))
1025+ nrdy = now & MSMON___NRDY ;
1026+ break ;
1027+ case mpam_feat_msmon_mbwu :
1028+ now = mpam_read_monsel_reg (msc , MBWU );
1029+ if (mpam_has_feature (mpam_feat_msmon_mbwu_hw_nrdy , rprops ))
1030+ nrdy = now & MSMON___NRDY ;
1031+ break ;
1032+ default :
1033+ m -> err = - EINVAL ;
1034+ }
1035+ mpam_mon_sel_unlock (msc );
1036+
1037+ if (nrdy ) {
1038+ m -> err = - EBUSY ;
1039+ return ;
1040+ }
1041+
1042+ now = FIELD_GET (MSMON___VALUE , now );
1043+ * m -> val += now ;
1044+ }
1045+
1046+ static int _msmon_read (struct mpam_component * comp , struct mon_read * arg )
1047+ {
1048+ int err , any_err = 0 ;
1049+ struct mpam_vmsc * vmsc ;
1050+
1051+ guard (srcu )(& mpam_srcu );
1052+ list_for_each_entry_srcu (vmsc , & comp -> vmsc , comp_list ,
1053+ srcu_read_lock_held (& mpam_srcu )) {
1054+ struct mpam_msc * msc = vmsc -> msc ;
1055+ struct mpam_msc_ris * ris ;
1056+
1057+ list_for_each_entry_srcu (ris , & vmsc -> ris , vmsc_list ,
1058+ srcu_read_lock_held (& mpam_srcu )) {
1059+ arg -> ris = ris ;
1060+
1061+ err = smp_call_function_any (& msc -> accessibility ,
1062+ __ris_msmon_read , arg ,
1063+ true);
1064+ if (!err && arg -> err )
1065+ err = arg -> err ;
1066+
1067+ /*
1068+ * Save one error to be returned to the caller, but
1069+ * keep reading counters so that get reprogrammed. On
1070+ * platforms with NRDY this lets us wait once.
1071+ */
1072+ if (err )
1073+ any_err = err ;
1074+ }
1075+ }
1076+
1077+ return any_err ;
1078+ }
1079+
1080+ int mpam_msmon_read (struct mpam_component * comp , struct mon_cfg * ctx ,
1081+ enum mpam_device_features type , u64 * val )
1082+ {
1083+ int err ;
1084+ struct mon_read arg ;
1085+ u64 wait_jiffies = 0 ;
1086+ struct mpam_props * cprops = & comp -> class -> props ;
1087+
1088+ might_sleep ();
1089+
1090+ if (!mpam_is_enabled ())
1091+ return - EIO ;
1092+
1093+ if (!mpam_has_feature (type , cprops ))
1094+ return - EOPNOTSUPP ;
1095+
1096+ arg = (struct mon_read ) {
1097+ .ctx = ctx ,
1098+ .type = type ,
1099+ .val = val ,
1100+ };
1101+ * val = 0 ;
1102+
1103+ err = _msmon_read (comp , & arg );
1104+ if (err == - EBUSY && comp -> class -> nrdy_usec )
1105+ wait_jiffies = usecs_to_jiffies (comp -> class -> nrdy_usec );
1106+
1107+ while (wait_jiffies )
1108+ wait_jiffies = schedule_timeout_uninterruptible (wait_jiffies );
1109+
1110+ if (err == - EBUSY ) {
1111+ arg = (struct mon_read ) {
1112+ .ctx = ctx ,
1113+ .type = type ,
1114+ .val = val ,
1115+ };
1116+ * val = 0 ;
1117+
1118+ err = _msmon_read (comp , & arg );
1119+ }
1120+
1121+ return err ;
1122+ }
1123+
8891124static void mpam_reset_msc_bitmap (struct mpam_msc * msc , u16 reg , u16 wd )
8901125{
8911126 u32 num_words , msb ;
0 commit comments