@@ -965,6 +965,216 @@ static struct platform_driver mpam_msc_driver = {
965965 .remove = mpam_msc_drv_remove ,
966966};
967967
968+ /* Any of these features mean the BWA_WD field is valid. */
969+ static bool mpam_has_bwa_wd_feature (struct mpam_props * props )
970+ {
971+ if (mpam_has_feature (mpam_feat_mbw_min , props ))
972+ return true;
973+ if (mpam_has_feature (mpam_feat_mbw_max , props ))
974+ return true;
975+ return false;
976+ }
977+
978+ #define MISMATCHED_HELPER (parent , child , helper , field , alias ) \
979+ helper(parent) && \
980+ ((helper(child) && (parent)->field != (child)->field) || \
981+ (!helper(child) && !(alias)))
982+
983+ #define MISMATCHED_FEAT (parent , child , feat , field , alias ) \
984+ mpam_has_feature((feat), (parent)) && \
985+ ((mpam_has_feature((feat), (child)) && (parent)->field != (child)->field) || \
986+ (!mpam_has_feature((feat), (child)) && !(alias)))
987+
988+ #define CAN_MERGE_FEAT (parent , child , feat , alias ) \
989+ (alias) && !mpam_has_feature((feat), (parent)) && \
990+ mpam_has_feature((feat), (child))
991+
992+ /*
993+ * Combine two props fields.
994+ * If this is for controls that alias the same resource, it is safe to just
995+ * copy the values over. If two aliasing controls implement the same scheme
996+ * a safe value must be picked.
997+ * For non-aliasing controls, these control different resources, and the
998+ * resulting safe value must be compatible with both. When merging values in
999+ * the tree, all the aliasing resources must be handled first.
1000+ * On mismatch, parent is modified.
1001+ */
1002+ static void __props_mismatch (struct mpam_props * parent ,
1003+ struct mpam_props * child , bool alias )
1004+ {
1005+ if (CAN_MERGE_FEAT (parent , child , mpam_feat_cpor_part , alias )) {
1006+ parent -> cpbm_wd = child -> cpbm_wd ;
1007+ } else if (MISMATCHED_FEAT (parent , child , mpam_feat_cpor_part ,
1008+ cpbm_wd , alias )) {
1009+ pr_debug ("cleared cpor_part\n" );
1010+ mpam_clear_feature (mpam_feat_cpor_part , parent );
1011+ parent -> cpbm_wd = 0 ;
1012+ }
1013+
1014+ if (CAN_MERGE_FEAT (parent , child , mpam_feat_mbw_part , alias )) {
1015+ parent -> mbw_pbm_bits = child -> mbw_pbm_bits ;
1016+ } else if (MISMATCHED_FEAT (parent , child , mpam_feat_mbw_part ,
1017+ mbw_pbm_bits , alias )) {
1018+ pr_debug ("cleared mbw_part\n" );
1019+ mpam_clear_feature (mpam_feat_mbw_part , parent );
1020+ parent -> mbw_pbm_bits = 0 ;
1021+ }
1022+
1023+ /* bwa_wd is a count of bits, fewer bits means less precision */
1024+ if (alias && !mpam_has_bwa_wd_feature (parent ) &&
1025+ mpam_has_bwa_wd_feature (child )) {
1026+ parent -> bwa_wd = child -> bwa_wd ;
1027+ } else if (MISMATCHED_HELPER (parent , child , mpam_has_bwa_wd_feature ,
1028+ bwa_wd , alias )) {
1029+ pr_debug ("took the min bwa_wd\n" );
1030+ parent -> bwa_wd = min (parent -> bwa_wd , child -> bwa_wd );
1031+ }
1032+
1033+ /* For num properties, take the minimum */
1034+ if (CAN_MERGE_FEAT (parent , child , mpam_feat_msmon_csu , alias )) {
1035+ parent -> num_csu_mon = child -> num_csu_mon ;
1036+ } else if (MISMATCHED_FEAT (parent , child , mpam_feat_msmon_csu ,
1037+ num_csu_mon , alias )) {
1038+ pr_debug ("took the min num_csu_mon\n" );
1039+ parent -> num_csu_mon = min (parent -> num_csu_mon ,
1040+ child -> num_csu_mon );
1041+ }
1042+
1043+ if (CAN_MERGE_FEAT (parent , child , mpam_feat_msmon_mbwu , alias )) {
1044+ parent -> num_mbwu_mon = child -> num_mbwu_mon ;
1045+ } else if (MISMATCHED_FEAT (parent , child , mpam_feat_msmon_mbwu ,
1046+ num_mbwu_mon , alias )) {
1047+ pr_debug ("took the min num_mbwu_mon\n" );
1048+ parent -> num_mbwu_mon = min (parent -> num_mbwu_mon ,
1049+ child -> num_mbwu_mon );
1050+ }
1051+
1052+ if (alias ) {
1053+ /* Merge features for aliased resources */
1054+ bitmap_or (parent -> features , parent -> features , child -> features , MPAM_FEATURE_LAST );
1055+ } else {
1056+ /* Clear missing features for non aliasing */
1057+ bitmap_and (parent -> features , parent -> features , child -> features , MPAM_FEATURE_LAST );
1058+ }
1059+ }
1060+
1061+ /*
1062+ * If a vmsc doesn't match class feature/configuration, do the right thing(tm).
1063+ * For 'num' properties we can just take the minimum.
1064+ * For properties where the mismatched unused bits would make a difference, we
1065+ * nobble the class feature, as we can't configure all the resources.
1066+ * e.g. The L3 cache is composed of two resources with 13 and 17 portion
1067+ * bitmaps respectively.
1068+ */
1069+ static void
1070+ __class_props_mismatch (struct mpam_class * class , struct mpam_vmsc * vmsc )
1071+ {
1072+ struct mpam_props * cprops = & class -> props ;
1073+ struct mpam_props * vprops = & vmsc -> props ;
1074+ struct device * dev = & vmsc -> msc -> pdev -> dev ;
1075+
1076+ lockdep_assert_held (& mpam_list_lock ); /* we modify class */
1077+
1078+ dev_dbg (dev , "Merging features for class:0x%lx &= vmsc:0x%lx\n" ,
1079+ (long )cprops -> features , (long )vprops -> features );
1080+
1081+ /* Take the safe value for any common features */
1082+ __props_mismatch (cprops , vprops , false);
1083+ }
1084+
1085+ static void
1086+ __vmsc_props_mismatch (struct mpam_vmsc * vmsc , struct mpam_msc_ris * ris )
1087+ {
1088+ struct mpam_props * rprops = & ris -> props ;
1089+ struct mpam_props * vprops = & vmsc -> props ;
1090+ struct device * dev = & vmsc -> msc -> pdev -> dev ;
1091+
1092+ lockdep_assert_held (& mpam_list_lock ); /* we modify vmsc */
1093+
1094+ dev_dbg (dev , "Merging features for vmsc:0x%lx |= ris:0x%lx\n" ,
1095+ (long )vprops -> features , (long )rprops -> features );
1096+
1097+ /*
1098+ * Merge mismatched features - Copy any features that aren't common,
1099+ * but take the safe value for any common features.
1100+ */
1101+ __props_mismatch (vprops , rprops , true);
1102+ }
1103+
1104+ /*
1105+ * Copy the first component's first vMSC's properties and features to the
1106+ * class. __class_props_mismatch() will remove conflicts.
1107+ * It is not possible to have a class with no components, or a component with
1108+ * no resources. The vMSC properties have already been built.
1109+ */
1110+ static void mpam_enable_init_class_features (struct mpam_class * class )
1111+ {
1112+ struct mpam_vmsc * vmsc ;
1113+ struct mpam_component * comp ;
1114+
1115+ comp = list_first_entry (& class -> components ,
1116+ struct mpam_component , class_list );
1117+ vmsc = list_first_entry (& comp -> vmsc ,
1118+ struct mpam_vmsc , comp_list );
1119+
1120+ class -> props = vmsc -> props ;
1121+ }
1122+
1123+ static void mpam_enable_merge_vmsc_features (struct mpam_component * comp )
1124+ {
1125+ struct mpam_vmsc * vmsc ;
1126+ struct mpam_msc_ris * ris ;
1127+ struct mpam_class * class = comp -> class ;
1128+
1129+ list_for_each_entry (vmsc , & comp -> vmsc , comp_list ) {
1130+ list_for_each_entry (ris , & vmsc -> ris , vmsc_list ) {
1131+ __vmsc_props_mismatch (vmsc , ris );
1132+ class -> nrdy_usec = max (class -> nrdy_usec ,
1133+ vmsc -> msc -> nrdy_usec );
1134+ }
1135+ }
1136+ }
1137+
1138+ static void mpam_enable_merge_class_features (struct mpam_component * comp )
1139+ {
1140+ struct mpam_vmsc * vmsc ;
1141+ struct mpam_class * class = comp -> class ;
1142+
1143+ list_for_each_entry (vmsc , & comp -> vmsc , comp_list )
1144+ __class_props_mismatch (class , vmsc );
1145+ }
1146+
1147+ /*
1148+ * Merge all the common resource features into class.
1149+ * vmsc features are bitwise-or'd together by mpam_enable_merge_vmsc_features()
1150+ * as the first step so that mpam_enable_init_class_features() can initialise
1151+ * the class with a representative set of features.
1152+ * Next the mpam_enable_merge_class_features() bitwise-and's all the vmsc
1153+ * features to form the class features.
1154+ * Other features are the min/max as appropriate.
1155+ *
1156+ * To avoid walking the whole tree twice, the class->nrdy_usec property is
1157+ * updated when working with the vmsc as it is a max(), and doesn't need
1158+ * initialising first.
1159+ */
1160+ static void mpam_enable_merge_features (struct list_head * all_classes_list )
1161+ {
1162+ struct mpam_class * class ;
1163+ struct mpam_component * comp ;
1164+
1165+ lockdep_assert_held (& mpam_list_lock );
1166+
1167+ list_for_each_entry (class , all_classes_list , classes_list ) {
1168+ list_for_each_entry (comp , & class -> components , class_list )
1169+ mpam_enable_merge_vmsc_features (comp );
1170+
1171+ mpam_enable_init_class_features (class );
1172+
1173+ list_for_each_entry (comp , & class -> components , class_list )
1174+ mpam_enable_merge_class_features (comp );
1175+ }
1176+ }
1177+
9681178static void mpam_enable_once (void )
9691179{
9701180 /*
@@ -975,6 +1185,10 @@ static void mpam_enable_once(void)
9751185 partid_max_published = true;
9761186 spin_unlock (& partid_max_lock );
9771187
1188+ mutex_lock (& mpam_list_lock );
1189+ mpam_enable_merge_features (& mpam_classes );
1190+ mutex_unlock (& mpam_list_lock );
1191+
9781192 mpam_register_cpuhp_callbacks (mpam_cpu_online , mpam_cpu_offline ,
9791193 "mpam:online" );
9801194
0 commit comments