Commit b1576ca4 authored by James Morse's avatar James Morse Committed by Zeng Heng
Browse files

arm_mpam: Probe and reset the rest of the features

maillist inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/morse/linux.git/log/?h=mpam/snapshot/v6.7-rc2



---------------------------

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>
Signed-off-by: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarZeng Heng <zengheng4@huawei.com>
parent be74872a
Loading
Loading
Loading
Loading
+91 −0
Original line number Diff line number Diff line
@@ -549,10 +549,20 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
	int err;
	struct mpam_msc *msc = ris->msc;
	struct mpam_props *props = &ris->props;
	struct mpam_class *class = ris->comp->class;

	lockdep_assert_held(&msc->lock);
	lockdep_assert_held(&msc->part_sel_lock);

	/* Cache Capacity Partitioning */
	if (FIELD_GET(MPAMF_IDR_HAS_CCAP_PART, ris->idr)) {
		u32 ccap_features = mpam_read_partsel_reg(msc, CCAP_IDR);

		props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features);
		if (props->cmax_wd)
			mpam_set_feature(mpam_feat_ccap_part, props);
	}

	/* Cache Portion partitioning */
	if (FIELD_GET(MPAMF_IDR_HAS_CPOR_PART, ris->idr)) {
		u32 cpor_features = mpam_read_partsel_reg(msc, CPOR_IDR);
@@ -575,6 +585,31 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
		props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features);
		if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features))
			mpam_set_feature(mpam_feat_mbw_max, props);

		if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MIN, mbw_features))
			mpam_set_feature(mpam_feat_mbw_min, props);

		if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_PROP, mbw_features))
			mpam_set_feature(mpam_feat_mbw_prop, props);
	}

	/* Priority partitioning */
	if (FIELD_GET(MPAMF_IDR_HAS_PRI_PART, ris->idr)) {
		u32 pri_features = mpam_read_partsel_reg(msc, PRI_IDR);

		props->intpri_wd = FIELD_GET(MPAMF_PRI_IDR_INTPRI_WD, pri_features);
		if (props->intpri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_INTPRI, pri_features)) {
			mpam_set_feature(mpam_feat_intpri_part, props);
			if (FIELD_GET(MPAMF_PRI_IDR_INTPRI_0_IS_LOW, pri_features))
				mpam_set_feature(mpam_feat_intpri_part_0_low, props);
		}

		props->dspri_wd = FIELD_GET(MPAMF_PRI_IDR_DSPRI_WD, pri_features);
		if (props->dspri_wd && FIELD_GET(MPAMF_PRI_IDR_HAS_DSPRI, pri_features)) {
			mpam_set_feature(mpam_feat_dspri_part, props);
			if (FIELD_GET(MPAMF_PRI_IDR_DSPRI_0_IS_LOW, pri_features))
				mpam_set_feature(mpam_feat_dspri_part_0_low, props);
		}
	}

	/* Performance Monitoring */
@@ -610,6 +645,21 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
				mpam_set_feature(mpam_feat_msmon_mbwu_rwbw, props);
		}
	}

	/*
	 * RIS with PARTID narrowing don't have enough storage for one
	 * configuration per PARTID. If these are in a class we could use,
	 * reduce the supported partid_max to match the numer of intpartid.
	 * If the class is unknown, just ignore it.
	 */
	if (FIELD_GET(MPAMF_IDR_HAS_PARTID_NRW, ris->idr) &&
	    class->type != MPAM_CLASS_UNKNOWN) {
		u32 nrwidr = mpam_read_partsel_reg(msc, PARTID_NRW_IDR);
		u16 partid_max = FIELD_GET(MPAMF_PARTID_NRW_IDR_INTPARTID_MAX, nrwidr);

		mpam_set_feature(mpam_feat_partid_nrw, props);
		msc->partid_max = min(msc->partid_max, partid_max);
	}
}

static int mpam_msc_hw_probe(struct mpam_msc *msc)
@@ -702,13 +752,21 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
				      struct mpam_config *cfg)
{
	u32 pri_val = 0;
	u16 cmax = MPAMCFG_CMAX_CMAX;
	struct mpam_msc *msc = ris->msc;
	u16 bwa_fract = MPAMCFG_MBW_MAX_MAX;
	struct mpam_props *rprops = &ris->props;
	u16 dspri = GENMASK(rprops->dspri_wd, 0);
	u16 intpri = GENMASK(rprops->intpri_wd, 0);

	spin_lock(&msc->part_sel_lock);
	__mpam_part_sel(ris->ris_idx, partid, msc);

	if(mpam_has_feature(mpam_feat_partid_nrw, rprops))
		mpam_write_partsel_reg(msc, INTPARTID,
				      (MPAMCFG_PART_SEL_INTERNAL | partid));

	if (mpam_has_feature(mpam_feat_cpor_part, rprops)) {
		if (mpam_has_feature(mpam_feat_cpor_part, cfg))
			mpam_write_partsel_reg(msc, CPBM, cfg->cpbm);
@@ -737,6 +795,26 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,

	if (mpam_has_feature(mpam_feat_mbw_prop, rprops))
		mpam_write_partsel_reg(msc, MBW_PROP, bwa_fract);

	if (mpam_has_feature(mpam_feat_ccap_part, rprops))
		mpam_write_partsel_reg(msc, CMAX, cmax);

	if (mpam_has_feature(mpam_feat_intpri_part, rprops) ||
	    mpam_has_feature(mpam_feat_dspri_part, rprops)) {
		/* aces high? */
		if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops))
			intpri = 0;
		if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops))
			dspri = 0;

		if (mpam_has_feature(mpam_feat_intpri_part, rprops))
			pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, intpri);
		if (mpam_has_feature(mpam_feat_dspri_part, rprops))
			pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri);

		mpam_write_partsel_reg(msc, PRI, pri_val);
	}

	spin_unlock(&msc->part_sel_lock);
}

@@ -1285,6 +1363,19 @@ __resource_props_mismatch(struct mpam_msc_ris *ris, struct mpam_class *class)
		cprops->num_csu_mon = min(cprops->num_csu_mon, rprops->num_csu_mon);
	if (cprops->num_mbwu_mon != rprops->num_mbwu_mon)
		cprops->num_mbwu_mon = min(cprops->num_mbwu_mon, rprops->num_mbwu_mon);

	if (cprops->intpri_wd != rprops->intpri_wd)
		cprops->intpri_wd = min(cprops->intpri_wd, rprops->intpri_wd);
	if (cprops->dspri_wd != rprops->dspri_wd)
		cprops->dspri_wd = min(cprops->dspri_wd, rprops->dspri_wd);

	/* {int,ds}pri may not have differing 0-low behaviour */
	if (mpam_has_feature(mpam_feat_intpri_part_0_low, cprops) !=
	    mpam_has_feature(mpam_feat_intpri_part_0_low, rprops))
		mpam_clear_feature(mpam_feat_intpri_part, &cprops->features);
	if (mpam_has_feature(mpam_feat_dspri_part_0_low, cprops) !=
	    mpam_has_feature(mpam_feat_dspri_part_0_low, rprops))
		mpam_clear_feature(mpam_feat_dspri_part, &cprops->features);
}

/*
+9 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ struct mpam_msc
 * When we compact the supported features, we don't care what they are.
 * Storing them as a bitmap makes life easy.
 */
typedef u16 mpam_features_t;
typedef u32 mpam_features_t;

/* Bits for mpam_features_t */
enum mpam_device_features {
@@ -80,6 +80,10 @@ enum mpam_device_features {
	mpam_feat_mbw_min,
	mpam_feat_mbw_max,
	mpam_feat_mbw_prop,
	mpam_feat_intpri_part,
	mpam_feat_intpri_part_0_low,
	mpam_feat_dspri_part,
	mpam_feat_dspri_part_0_low,
	mpam_feat_msmon,
	mpam_feat_msmon_csu,
	mpam_feat_msmon_csu_capture,
@@ -87,6 +91,7 @@ enum mpam_device_features {
	mpam_feat_msmon_mbwu_capture,
	mpam_feat_msmon_mbwu_rwbw,
	mpam_feat_msmon_capt,
	mpam_feat_partid_nrw,
	MPAM_FEATURE_LAST,
};
#define MPAM_ALL_FEATURES      ((1<<MPAM_FEATURE_LAST) - 1)
@@ -98,6 +103,9 @@ struct mpam_props
	u16			cpbm_wd;
	u16			mbw_pbm_bits;
	u8			bwa_wd;
	u16			cmax_wd;
	u16			intpri_wd;
	u16			dspri_wd;
	u16			num_csu_mon;
	u16			num_mbwu_mon;
};