Skip to content

Commit 880df85

Browse files
James Morsectmarinas
authored andcommitted
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>
1 parent 09b89d2 commit 880df85

2 files changed

Lines changed: 206 additions & 0 deletions

File tree

drivers/resctrl/mpam_devices.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,15 @@ static void __mpam_part_sel(u8 ris_idx, u16 partid, struct mpam_msc *msc)
259259
__mpam_part_sel_raw(partsel, msc);
260260
}
261261

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+
262271
int mpam_register_requestor(u16 partid_max, u8 pmg_max)
263272
{
264273
guard(spinlock)(&partid_max_lock);
@@ -656,10 +665,34 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
656665
struct mpam_msc *msc = ris->vmsc->msc;
657666
struct device *dev = &msc->pdev->dev;
658667
struct mpam_props *props = &ris->props;
668+
struct mpam_class *class = ris->vmsc->comp->class;
659669

660670
lockdep_assert_held(&msc->probe_lock);
661671
lockdep_assert_held(&msc->part_sel_lock);
662672

673+
/* Cache Capacity Partitioning */
674+
if (FIELD_GET(MPAMF_IDR_HAS_CCAP_PART, ris->idr)) {
675+
u32 ccap_features = mpam_read_partsel_reg(msc, CCAP_IDR);
676+
677+
props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features);
678+
if (props->cmax_wd &&
679+
FIELD_GET(MPAMF_CCAP_IDR_HAS_CMAX_SOFTLIM, ccap_features))
680+
mpam_set_feature(mpam_feat_cmax_softlim, props);
681+
682+
if (props->cmax_wd &&
683+
!FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features))
684+
mpam_set_feature(mpam_feat_cmax_cmax, props);
685+
686+
if (props->cmax_wd &&
687+
FIELD_GET(MPAMF_CCAP_IDR_HAS_CMIN, ccap_features))
688+
mpam_set_feature(mpam_feat_cmax_cmin, props);
689+
690+
props->cassoc_wd = FIELD_GET(MPAMF_CCAP_IDR_CASSOC_WD, ccap_features);
691+
if (props->cassoc_wd &&
692+
FIELD_GET(MPAMF_CCAP_IDR_HAS_CASSOC, ccap_features))
693+
mpam_set_feature(mpam_feat_cmax_cassoc, props);
694+
}
695+
663696
/* Cache Portion partitioning */
664697
if (FIELD_GET(MPAMF_IDR_HAS_CPOR_PART, ris->idr)) {
665698
u32 cpor_features = mpam_read_partsel_reg(msc, CPOR_IDR);
@@ -682,6 +715,31 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
682715
props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features);
683716
if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features))
684717
mpam_set_feature(mpam_feat_mbw_max, props);
718+
719+
if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MIN, mbw_features))
720+
mpam_set_feature(mpam_feat_mbw_min, props);
721+
722+
if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_PROP, mbw_features))
723+
mpam_set_feature(mpam_feat_mbw_prop, props);
724+
}
725+
726+
/* Priority partitioning */
727+
if (FIELD_GET(MPAMF_IDR_HAS_PRI_PART, ris->idr)) {
728+
u32 pri_features = mpam_read_partsel_reg(msc, PRI_IDR);
729+
730+
props->intpri_wd = FIELD_GET(MPAMF_PRI_IDR_INTPRI_WD, pri_features);
731+
if (props->intpri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_INTPRI, pri_features)) {
732+
mpam_set_feature(mpam_feat_intpri_part, props);
733+
if (FIELD_GET(MPAMF_PRI_IDR_INTPRI_0_IS_LOW, pri_features))
734+
mpam_set_feature(mpam_feat_intpri_part_0_low, props);
735+
}
736+
737+
props->dspri_wd = FIELD_GET(MPAMF_PRI_IDR_DSPRI_WD, pri_features);
738+
if (props->dspri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_DSPRI, pri_features)) {
739+
mpam_set_feature(mpam_feat_dspri_part, props);
740+
if (FIELD_GET(MPAMF_PRI_IDR_DSPRI_0_IS_LOW, pri_features))
741+
mpam_set_feature(mpam_feat_dspri_part_0_low, props);
742+
}
685743
}
686744

687745
/* Performance Monitoring */
@@ -706,6 +764,9 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
706764

707765
mpam_set_feature(mpam_feat_msmon_csu, props);
708766

767+
if (FIELD_GET(MPAMF_CSUMON_IDR_HAS_XCL, csumonidr))
768+
mpam_set_feature(mpam_feat_msmon_csu_xcl, props);
769+
709770
/* Is NRDY hardware managed? */
710771
hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, CSU);
711772
if (hw_managed)
@@ -727,6 +788,9 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
727788
if (props->num_mbwu_mon)
728789
mpam_set_feature(mpam_feat_msmon_mbwu, props);
729790

791+
if (FIELD_GET(MPAMF_MBWUMON_IDR_HAS_RWBW, mbwumon_idr))
792+
mpam_set_feature(mpam_feat_msmon_mbwu_rwbw, props);
793+
730794
/* Is NRDY hardware managed? */
731795
hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, MBWU);
732796
if (hw_managed)
@@ -738,6 +802,21 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
738802
*/
739803
}
740804
}
805+
806+
/*
807+
* RIS with PARTID narrowing don't have enough storage for one
808+
* configuration per PARTID. If these are in a class we could use,
809+
* reduce the supported partid_max to match the number of intpartid.
810+
* If the class is unknown, just ignore it.
811+
*/
812+
if (FIELD_GET(MPAMF_IDR_HAS_PARTID_NRW, ris->idr) &&
813+
class->type != MPAM_CLASS_UNKNOWN) {
814+
u32 nrwidr = mpam_read_partsel_reg(msc, PARTID_NRW_IDR);
815+
u16 partid_max = FIELD_GET(MPAMF_PARTID_NRW_IDR_INTPARTID_MAX, nrwidr);
816+
817+
mpam_set_feature(mpam_feat_partid_nrw, props);
818+
msc->partid_max = min(msc->partid_max, partid_max);
819+
}
741820
}
742821

743822
static int mpam_msc_hw_probe(struct mpam_msc *msc)
@@ -837,12 +916,28 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
837916
static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
838917
struct mpam_config *cfg)
839918
{
919+
u32 pri_val = 0;
920+
u16 cmax = MPAMCFG_CMAX_CMAX;
840921
struct mpam_msc *msc = ris->vmsc->msc;
841922
struct mpam_props *rprops = &ris->props;
923+
u16 dspri = GENMASK(rprops->dspri_wd, 0);
924+
u16 intpri = GENMASK(rprops->intpri_wd, 0);
842925

843926
mutex_lock(&msc->part_sel_lock);
844927
__mpam_part_sel(ris->ris_idx, partid, msc);
845928

929+
if (mpam_has_feature(mpam_feat_partid_nrw, rprops)) {
930+
/* Update the intpartid mapping */
931+
mpam_write_partsel_reg(msc, INTPARTID,
932+
MPAMCFG_INTPARTID_INTERNAL | partid);
933+
934+
/*
935+
* Then switch to the 'internal' partid to update the
936+
* configuration.
937+
*/
938+
__mpam_intpart_sel(ris->ris_idx, partid, msc);
939+
}
940+
846941
if (mpam_has_feature(mpam_feat_cpor_part, rprops) &&
847942
mpam_has_feature(mpam_feat_cpor_part, cfg)) {
848943
if (cfg->reset_cpbm)
@@ -871,6 +966,35 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
871966
mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max);
872967
}
873968

969+
if (mpam_has_feature(mpam_feat_mbw_prop, rprops) &&
970+
mpam_has_feature(mpam_feat_mbw_prop, cfg))
971+
mpam_write_partsel_reg(msc, MBW_PROP, 0);
972+
973+
if (mpam_has_feature(mpam_feat_cmax_cmax, rprops))
974+
mpam_write_partsel_reg(msc, CMAX, cmax);
975+
976+
if (mpam_has_feature(mpam_feat_cmax_cmin, rprops))
977+
mpam_write_partsel_reg(msc, CMIN, 0);
978+
979+
if (mpam_has_feature(mpam_feat_cmax_cassoc, rprops))
980+
mpam_write_partsel_reg(msc, CASSOC, MPAMCFG_CASSOC_CASSOC);
981+
982+
if (mpam_has_feature(mpam_feat_intpri_part, rprops) ||
983+
mpam_has_feature(mpam_feat_dspri_part, rprops)) {
984+
/* aces high? */
985+
if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops))
986+
intpri = 0;
987+
if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops))
988+
dspri = 0;
989+
990+
if (mpam_has_feature(mpam_feat_intpri_part, rprops))
991+
pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, intpri);
992+
if (mpam_has_feature(mpam_feat_dspri_part, rprops))
993+
pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri);
994+
995+
mpam_write_partsel_reg(msc, PRI, pri_val);
996+
}
997+
874998
mutex_unlock(&msc->part_sel_lock);
875999
}
8761000

@@ -1308,6 +1432,18 @@ static bool mpam_has_bwa_wd_feature(struct mpam_props *props)
13081432
return true;
13091433
if (mpam_has_feature(mpam_feat_mbw_max, props))
13101434
return true;
1435+
if (mpam_has_feature(mpam_feat_mbw_prop, props))
1436+
return true;
1437+
return false;
1438+
}
1439+
1440+
/* Any of these features mean the CMAX_WD field is valid. */
1441+
static bool mpam_has_cmax_wd_feature(struct mpam_props *props)
1442+
{
1443+
if (mpam_has_feature(mpam_feat_cmax_cmax, props))
1444+
return true;
1445+
if (mpam_has_feature(mpam_feat_cmax_cmin, props))
1446+
return true;
13111447
return false;
13121448
}
13131449

@@ -1366,6 +1502,23 @@ static void __props_mismatch(struct mpam_props *parent,
13661502
parent->bwa_wd = min(parent->bwa_wd, child->bwa_wd);
13671503
}
13681504

1505+
if (alias && !mpam_has_cmax_wd_feature(parent) && mpam_has_cmax_wd_feature(child)) {
1506+
parent->cmax_wd = child->cmax_wd;
1507+
} else if (MISMATCHED_HELPER(parent, child, mpam_has_cmax_wd_feature,
1508+
cmax_wd, alias)) {
1509+
pr_debug("%s took the min cmax_wd\n", __func__);
1510+
parent->cmax_wd = min(parent->cmax_wd, child->cmax_wd);
1511+
}
1512+
1513+
if (CAN_MERGE_FEAT(parent, child, mpam_feat_cmax_cassoc, alias)) {
1514+
parent->cassoc_wd = child->cassoc_wd;
1515+
} else if (MISMATCHED_FEAT(parent, child, mpam_feat_cmax_cassoc,
1516+
cassoc_wd, alias)) {
1517+
pr_debug("%s cleared cassoc_wd\n", __func__);
1518+
mpam_clear_feature(mpam_feat_cmax_cassoc, parent);
1519+
parent->cassoc_wd = 0;
1520+
}
1521+
13691522
/* For num properties, take the minimum */
13701523
if (CAN_MERGE_FEAT(parent, child, mpam_feat_msmon_csu, alias)) {
13711524
parent->num_csu_mon = child->num_csu_mon;
@@ -1385,6 +1538,41 @@ static void __props_mismatch(struct mpam_props *parent,
13851538
child->num_mbwu_mon);
13861539
}
13871540

1541+
if (CAN_MERGE_FEAT(parent, child, mpam_feat_intpri_part, alias)) {
1542+
parent->intpri_wd = child->intpri_wd;
1543+
} else if (MISMATCHED_FEAT(parent, child, mpam_feat_intpri_part,
1544+
intpri_wd, alias)) {
1545+
pr_debug("%s took the min intpri_wd\n", __func__);
1546+
parent->intpri_wd = min(parent->intpri_wd, child->intpri_wd);
1547+
}
1548+
1549+
if (CAN_MERGE_FEAT(parent, child, mpam_feat_dspri_part, alias)) {
1550+
parent->dspri_wd = child->dspri_wd;
1551+
} else if (MISMATCHED_FEAT(parent, child, mpam_feat_dspri_part,
1552+
dspri_wd, alias)) {
1553+
pr_debug("%s took the min dspri_wd\n", __func__);
1554+
parent->dspri_wd = min(parent->dspri_wd, child->dspri_wd);
1555+
}
1556+
1557+
/* TODO: alias support for these two */
1558+
/* {int,ds}pri may not have differing 0-low behaviour */
1559+
if (mpam_has_feature(mpam_feat_intpri_part, parent) &&
1560+
(!mpam_has_feature(mpam_feat_intpri_part, child) ||
1561+
mpam_has_feature(mpam_feat_intpri_part_0_low, parent) !=
1562+
mpam_has_feature(mpam_feat_intpri_part_0_low, child))) {
1563+
pr_debug("%s cleared intpri_part\n", __func__);
1564+
mpam_clear_feature(mpam_feat_intpri_part, parent);
1565+
mpam_clear_feature(mpam_feat_intpri_part_0_low, parent);
1566+
}
1567+
if (mpam_has_feature(mpam_feat_dspri_part, parent) &&
1568+
(!mpam_has_feature(mpam_feat_dspri_part, child) ||
1569+
mpam_has_feature(mpam_feat_dspri_part_0_low, parent) !=
1570+
mpam_has_feature(mpam_feat_dspri_part_0_low, child))) {
1571+
pr_debug("%s cleared dspri_part\n", __func__);
1572+
mpam_clear_feature(mpam_feat_dspri_part, parent);
1573+
mpam_clear_feature(mpam_feat_dspri_part_0_low, parent);
1574+
}
1575+
13881576
if (alias) {
13891577
/* Merge features for aliased resources */
13901578
bitmap_or(parent->features, parent->features, child->features, MPAM_FEATURE_LAST);

drivers/resctrl/mpam_internal.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,28 @@ static inline void mpam_mon_sel_lock_init(struct mpam_msc *msc)
143143
/* Bits for mpam features bitmaps */
144144
enum mpam_device_features {
145145
mpam_feat_cpor_part,
146+
mpam_feat_cmax_softlim,
147+
mpam_feat_cmax_cmax,
148+
mpam_feat_cmax_cmin,
149+
mpam_feat_cmax_cassoc,
146150
mpam_feat_mbw_part,
147151
mpam_feat_mbw_min,
148152
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,
149158
mpam_feat_msmon,
150159
mpam_feat_msmon_csu,
160+
mpam_feat_msmon_csu_capture,
161+
mpam_feat_msmon_csu_xcl,
151162
mpam_feat_msmon_csu_hw_nrdy,
152163
mpam_feat_msmon_mbwu,
164+
mpam_feat_msmon_mbwu_capture,
165+
mpam_feat_msmon_mbwu_rwbw,
153166
mpam_feat_msmon_mbwu_hw_nrdy,
167+
mpam_feat_partid_nrw,
154168
MPAM_FEATURE_LAST
155169
};
156170

@@ -160,6 +174,10 @@ struct mpam_props {
160174
u16 cpbm_wd;
161175
u16 mbw_pbm_bits;
162176
u16 bwa_wd;
177+
u16 cmax_wd;
178+
u16 cassoc_wd;
179+
u16 intpri_wd;
180+
u16 dspri_wd;
163181
u16 num_csu_mon;
164182
u16 num_mbwu_mon;
165183
};

0 commit comments

Comments
 (0)