Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

arm_mpam: Probe and reset the rest of the features

MPAM supports more features than are going to be exposed to resctrl.
For partid other than 0, the reset values of these controls isn't
known.

Discover the rest of the features so they can be reset to avoid any
side effects when resctrl is in use.

PARTID narrowing allows MSC/RIS to support less configuration space than
is usable. If this feature is found on a class of device we are likely
to use, then reduce the partid_max to make it usable. This allows us
to map a PARTID to itself.

CC: Rohit Mathew <Rohit.Mathew@arm.com>
CC: Zeng Heng <zengheng4@huawei.com>
CC: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: Fenghua Yu <fenghuay@nvidia.com>
Tested-by: Fenghua Yu <fenghuay@nvidia.com>
Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Peter Newman <peternewman@google.com>
Tested-by: Carl Worth <carl@os.amperecomputing.com>
Tested-by: Gavin Shan <gshan@redhat.com>
Tested-by: Zeng Heng <zengheng4@huawei.com>
Tested-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

James Morse and committed by
Catalin Marinas
880df85d 09b89d2a

+206
+188
drivers/resctrl/mpam_devices.c
··· 259 259 __mpam_part_sel_raw(partsel, msc); 260 260 } 261 261 262 + static void __mpam_intpart_sel(u8 ris_idx, u16 intpartid, struct mpam_msc *msc) 263 + { 264 + u32 partsel = FIELD_PREP(MPAMCFG_PART_SEL_RIS, ris_idx) | 265 + FIELD_PREP(MPAMCFG_PART_SEL_PARTID_SEL, intpartid) | 266 + MPAMCFG_PART_SEL_INTERNAL; 267 + 268 + __mpam_part_sel_raw(partsel, msc); 269 + } 270 + 262 271 int mpam_register_requestor(u16 partid_max, u8 pmg_max) 263 272 { 264 273 guard(spinlock)(&partid_max_lock); ··· 665 656 struct mpam_msc *msc = ris->vmsc->msc; 666 657 struct device *dev = &msc->pdev->dev; 667 658 struct mpam_props *props = &ris->props; 659 + struct mpam_class *class = ris->vmsc->comp->class; 668 660 669 661 lockdep_assert_held(&msc->probe_lock); 670 662 lockdep_assert_held(&msc->part_sel_lock); 663 + 664 + /* Cache Capacity Partitioning */ 665 + if (FIELD_GET(MPAMF_IDR_HAS_CCAP_PART, ris->idr)) { 666 + u32 ccap_features = mpam_read_partsel_reg(msc, CCAP_IDR); 667 + 668 + props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features); 669 + if (props->cmax_wd && 670 + FIELD_GET(MPAMF_CCAP_IDR_HAS_CMAX_SOFTLIM, ccap_features)) 671 + mpam_set_feature(mpam_feat_cmax_softlim, props); 672 + 673 + if (props->cmax_wd && 674 + !FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) 675 + mpam_set_feature(mpam_feat_cmax_cmax, props); 676 + 677 + if (props->cmax_wd && 678 + FIELD_GET(MPAMF_CCAP_IDR_HAS_CMIN, ccap_features)) 679 + mpam_set_feature(mpam_feat_cmax_cmin, props); 680 + 681 + props->cassoc_wd = FIELD_GET(MPAMF_CCAP_IDR_CASSOC_WD, ccap_features); 682 + if (props->cassoc_wd && 683 + FIELD_GET(MPAMF_CCAP_IDR_HAS_CASSOC, ccap_features)) 684 + mpam_set_feature(mpam_feat_cmax_cassoc, props); 685 + } 671 686 672 687 /* Cache Portion partitioning */ 673 688 if (FIELD_GET(MPAMF_IDR_HAS_CPOR_PART, ris->idr)) { ··· 715 682 props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features); 716 683 if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features)) 717 684 mpam_set_feature(mpam_feat_mbw_max, props); 685 + 686 + if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MIN, mbw_features)) 687 + mpam_set_feature(mpam_feat_mbw_min, props); 688 + 689 + if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_PROP, mbw_features)) 690 + mpam_set_feature(mpam_feat_mbw_prop, props); 691 + } 692 + 693 + /* Priority partitioning */ 694 + if (FIELD_GET(MPAMF_IDR_HAS_PRI_PART, ris->idr)) { 695 + u32 pri_features = mpam_read_partsel_reg(msc, PRI_IDR); 696 + 697 + props->intpri_wd = FIELD_GET(MPAMF_PRI_IDR_INTPRI_WD, pri_features); 698 + if (props->intpri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_INTPRI, pri_features)) { 699 + mpam_set_feature(mpam_feat_intpri_part, props); 700 + if (FIELD_GET(MPAMF_PRI_IDR_INTPRI_0_IS_LOW, pri_features)) 701 + mpam_set_feature(mpam_feat_intpri_part_0_low, props); 702 + } 703 + 704 + props->dspri_wd = FIELD_GET(MPAMF_PRI_IDR_DSPRI_WD, pri_features); 705 + if (props->dspri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_DSPRI, pri_features)) { 706 + mpam_set_feature(mpam_feat_dspri_part, props); 707 + if (FIELD_GET(MPAMF_PRI_IDR_DSPRI_0_IS_LOW, pri_features)) 708 + mpam_set_feature(mpam_feat_dspri_part_0_low, props); 709 + } 718 710 } 719 711 720 712 /* Performance Monitoring */ ··· 764 706 765 707 mpam_set_feature(mpam_feat_msmon_csu, props); 766 708 709 + if (FIELD_GET(MPAMF_CSUMON_IDR_HAS_XCL, csumonidr)) 710 + mpam_set_feature(mpam_feat_msmon_csu_xcl, props); 711 + 767 712 /* Is NRDY hardware managed? */ 768 713 hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, CSU); 769 714 if (hw_managed) ··· 788 727 if (props->num_mbwu_mon) 789 728 mpam_set_feature(mpam_feat_msmon_mbwu, props); 790 729 730 + if (FIELD_GET(MPAMF_MBWUMON_IDR_HAS_RWBW, mbwumon_idr)) 731 + mpam_set_feature(mpam_feat_msmon_mbwu_rwbw, props); 732 + 791 733 /* Is NRDY hardware managed? */ 792 734 hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, MBWU); 793 735 if (hw_managed) ··· 801 737 * MBWU NRDY - it doesn't make any sense! 802 738 */ 803 739 } 740 + } 741 + 742 + /* 743 + * RIS with PARTID narrowing don't have enough storage for one 744 + * configuration per PARTID. If these are in a class we could use, 745 + * reduce the supported partid_max to match the number of intpartid. 746 + * If the class is unknown, just ignore it. 747 + */ 748 + if (FIELD_GET(MPAMF_IDR_HAS_PARTID_NRW, ris->idr) && 749 + class->type != MPAM_CLASS_UNKNOWN) { 750 + u32 nrwidr = mpam_read_partsel_reg(msc, PARTID_NRW_IDR); 751 + u16 partid_max = FIELD_GET(MPAMF_PARTID_NRW_IDR_INTPARTID_MAX, nrwidr); 752 + 753 + mpam_set_feature(mpam_feat_partid_nrw, props); 754 + msc->partid_max = min(msc->partid_max, partid_max); 804 755 } 805 756 } 806 757 ··· 916 837 static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, 917 838 struct mpam_config *cfg) 918 839 { 840 + u32 pri_val = 0; 841 + u16 cmax = MPAMCFG_CMAX_CMAX; 919 842 struct mpam_msc *msc = ris->vmsc->msc; 920 843 struct mpam_props *rprops = &ris->props; 844 + u16 dspri = GENMASK(rprops->dspri_wd, 0); 845 + u16 intpri = GENMASK(rprops->intpri_wd, 0); 921 846 922 847 mutex_lock(&msc->part_sel_lock); 923 848 __mpam_part_sel(ris->ris_idx, partid, msc); 849 + 850 + if (mpam_has_feature(mpam_feat_partid_nrw, rprops)) { 851 + /* Update the intpartid mapping */ 852 + mpam_write_partsel_reg(msc, INTPARTID, 853 + MPAMCFG_INTPARTID_INTERNAL | partid); 854 + 855 + /* 856 + * Then switch to the 'internal' partid to update the 857 + * configuration. 858 + */ 859 + __mpam_intpart_sel(ris->ris_idx, partid, msc); 860 + } 924 861 925 862 if (mpam_has_feature(mpam_feat_cpor_part, rprops) && 926 863 mpam_has_feature(mpam_feat_cpor_part, cfg)) { ··· 964 869 mpam_write_partsel_reg(msc, MBW_MAX, MPAMCFG_MBW_MAX_MAX); 965 870 else 966 871 mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max); 872 + } 873 + 874 + if (mpam_has_feature(mpam_feat_mbw_prop, rprops) && 875 + mpam_has_feature(mpam_feat_mbw_prop, cfg)) 876 + mpam_write_partsel_reg(msc, MBW_PROP, 0); 877 + 878 + if (mpam_has_feature(mpam_feat_cmax_cmax, rprops)) 879 + mpam_write_partsel_reg(msc, CMAX, cmax); 880 + 881 + if (mpam_has_feature(mpam_feat_cmax_cmin, rprops)) 882 + mpam_write_partsel_reg(msc, CMIN, 0); 883 + 884 + if (mpam_has_feature(mpam_feat_cmax_cassoc, rprops)) 885 + mpam_write_partsel_reg(msc, CASSOC, MPAMCFG_CASSOC_CASSOC); 886 + 887 + if (mpam_has_feature(mpam_feat_intpri_part, rprops) || 888 + mpam_has_feature(mpam_feat_dspri_part, rprops)) { 889 + /* aces high? */ 890 + if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops)) 891 + intpri = 0; 892 + if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops)) 893 + dspri = 0; 894 + 895 + if (mpam_has_feature(mpam_feat_intpri_part, rprops)) 896 + pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, intpri); 897 + if (mpam_has_feature(mpam_feat_dspri_part, rprops)) 898 + pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri); 899 + 900 + mpam_write_partsel_reg(msc, PRI, pri_val); 967 901 } 968 902 969 903 mutex_unlock(&msc->part_sel_lock); ··· 1432 1308 return true; 1433 1309 if (mpam_has_feature(mpam_feat_mbw_max, props)) 1434 1310 return true; 1311 + if (mpam_has_feature(mpam_feat_mbw_prop, props)) 1312 + return true; 1313 + return false; 1314 + } 1315 + 1316 + /* Any of these features mean the CMAX_WD field is valid. */ 1317 + static bool mpam_has_cmax_wd_feature(struct mpam_props *props) 1318 + { 1319 + if (mpam_has_feature(mpam_feat_cmax_cmax, props)) 1320 + return true; 1321 + if (mpam_has_feature(mpam_feat_cmax_cmin, props)) 1322 + return true; 1435 1323 return false; 1436 1324 } 1437 1325 ··· 1502 1366 parent->bwa_wd = min(parent->bwa_wd, child->bwa_wd); 1503 1367 } 1504 1368 1369 + if (alias && !mpam_has_cmax_wd_feature(parent) && mpam_has_cmax_wd_feature(child)) { 1370 + parent->cmax_wd = child->cmax_wd; 1371 + } else if (MISMATCHED_HELPER(parent, child, mpam_has_cmax_wd_feature, 1372 + cmax_wd, alias)) { 1373 + pr_debug("%s took the min cmax_wd\n", __func__); 1374 + parent->cmax_wd = min(parent->cmax_wd, child->cmax_wd); 1375 + } 1376 + 1377 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_cmax_cassoc, alias)) { 1378 + parent->cassoc_wd = child->cassoc_wd; 1379 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_cmax_cassoc, 1380 + cassoc_wd, alias)) { 1381 + pr_debug("%s cleared cassoc_wd\n", __func__); 1382 + mpam_clear_feature(mpam_feat_cmax_cassoc, parent); 1383 + parent->cassoc_wd = 0; 1384 + } 1385 + 1505 1386 /* For num properties, take the minimum */ 1506 1387 if (CAN_MERGE_FEAT(parent, child, mpam_feat_msmon_csu, alias)) { 1507 1388 parent->num_csu_mon = child->num_csu_mon; ··· 1536 1383 pr_debug("took the min num_mbwu_mon\n"); 1537 1384 parent->num_mbwu_mon = min(parent->num_mbwu_mon, 1538 1385 child->num_mbwu_mon); 1386 + } 1387 + 1388 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_intpri_part, alias)) { 1389 + parent->intpri_wd = child->intpri_wd; 1390 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_intpri_part, 1391 + intpri_wd, alias)) { 1392 + pr_debug("%s took the min intpri_wd\n", __func__); 1393 + parent->intpri_wd = min(parent->intpri_wd, child->intpri_wd); 1394 + } 1395 + 1396 + if (CAN_MERGE_FEAT(parent, child, mpam_feat_dspri_part, alias)) { 1397 + parent->dspri_wd = child->dspri_wd; 1398 + } else if (MISMATCHED_FEAT(parent, child, mpam_feat_dspri_part, 1399 + dspri_wd, alias)) { 1400 + pr_debug("%s took the min dspri_wd\n", __func__); 1401 + parent->dspri_wd = min(parent->dspri_wd, child->dspri_wd); 1402 + } 1403 + 1404 + /* TODO: alias support for these two */ 1405 + /* {int,ds}pri may not have differing 0-low behaviour */ 1406 + if (mpam_has_feature(mpam_feat_intpri_part, parent) && 1407 + (!mpam_has_feature(mpam_feat_intpri_part, child) || 1408 + mpam_has_feature(mpam_feat_intpri_part_0_low, parent) != 1409 + mpam_has_feature(mpam_feat_intpri_part_0_low, child))) { 1410 + pr_debug("%s cleared intpri_part\n", __func__); 1411 + mpam_clear_feature(mpam_feat_intpri_part, parent); 1412 + mpam_clear_feature(mpam_feat_intpri_part_0_low, parent); 1413 + } 1414 + if (mpam_has_feature(mpam_feat_dspri_part, parent) && 1415 + (!mpam_has_feature(mpam_feat_dspri_part, child) || 1416 + mpam_has_feature(mpam_feat_dspri_part_0_low, parent) != 1417 + mpam_has_feature(mpam_feat_dspri_part_0_low, child))) { 1418 + pr_debug("%s cleared dspri_part\n", __func__); 1419 + mpam_clear_feature(mpam_feat_dspri_part, parent); 1420 + mpam_clear_feature(mpam_feat_dspri_part_0_low, parent); 1539 1421 } 1540 1422 1541 1423 if (alias) {
+18
drivers/resctrl/mpam_internal.h
··· 143 143 /* Bits for mpam features bitmaps */ 144 144 enum mpam_device_features { 145 145 mpam_feat_cpor_part, 146 + mpam_feat_cmax_softlim, 147 + mpam_feat_cmax_cmax, 148 + mpam_feat_cmax_cmin, 149 + mpam_feat_cmax_cassoc, 146 150 mpam_feat_mbw_part, 147 151 mpam_feat_mbw_min, 148 152 mpam_feat_mbw_max, 153 + mpam_feat_mbw_prop, 154 + mpam_feat_intpri_part, 155 + mpam_feat_intpri_part_0_low, 156 + mpam_feat_dspri_part, 157 + mpam_feat_dspri_part_0_low, 149 158 mpam_feat_msmon, 150 159 mpam_feat_msmon_csu, 160 + mpam_feat_msmon_csu_capture, 161 + mpam_feat_msmon_csu_xcl, 151 162 mpam_feat_msmon_csu_hw_nrdy, 152 163 mpam_feat_msmon_mbwu, 164 + mpam_feat_msmon_mbwu_capture, 165 + mpam_feat_msmon_mbwu_rwbw, 153 166 mpam_feat_msmon_mbwu_hw_nrdy, 167 + mpam_feat_partid_nrw, 154 168 MPAM_FEATURE_LAST 155 169 }; 156 170 ··· 174 160 u16 cpbm_wd; 175 161 u16 mbw_pbm_bits; 176 162 u16 bwa_wd; 163 + u16 cmax_wd; 164 + u16 cassoc_wd; 165 + u16 intpri_wd; 166 + u16 dspri_wd; 177 167 u16 num_csu_mon; 178 168 u16 num_mbwu_mon; 179 169 };