From nobody Wed Dec 17 14:22:01 2025 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 09002222D7D for ; Thu, 12 Dec 2024 15:40:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734018034; cv=none; b=D/dTZpe7PFdRQTbMpXjJkf3eX7n9o7RXhQGEsXeWQb03+6jenEFoYwtk43YytNBtLsSkjqtm3Gn3mJN3QmIuveIhjk76jXAWaAOdGeCvWqF86+VcYPIeMethxYEYSfMj4jlqF+qRaAPgatXbDa1JG2PWhiUQewoGbUtLLwN4mY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734018034; c=relaxed/simple; bh=3swF8ifBeJ3AnRXz5rtd5qGjIzSvNJHs4PdlcBlQHbI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=sxucfxbhMAEJzu8+1MWITtaSfb2GV60FNJeU43TLeWn4GtriC1tKBBw9C4jjtKdcRnX7lcfHFtmZUVy/dBvV/vbMjYw1WJkEP9XCkVUMnrMmbdkB1k1+ozukdjXg9A1Gvlzg1YVCM2IVUuTgasJDuXn3AZgrnC9ho9VBmd7NCw8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 720731A25; Thu, 12 Dec 2024 07:40:58 -0800 (PST) Received: from e133380.cambridge.arm.com (e133380.arm.com [10.1.197.41]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3B60D3F720; Thu, 12 Dec 2024 07:40:29 -0800 (PST) From: Dave Martin To: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, Zeng Heng , Shaopeng Tan , James Morse Subject: [RFC PATCH 4/6] arm_mpam: Introduce flexible CLOSID/RMID translation Date: Thu, 12 Dec 2024 15:39:58 +0000 Message-Id: <20241212154000.330467-5-Dave.Martin@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241212154000.330467-1-Dave.Martin@arm.com> References: <20241212154000.330467-1-Dave.Martin@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, the MPAM driver uses the resctrl CLOSID directly as the MPAM Partition Identifier (PARTID; possibly modified to give different PARTIDs to code and data when Code/Data Partitioning / CDP is enabled), and uses the resctrl RMID directly as the MPAM Performance Monitoring Group identifier (PMG). In preparation for using the MPAM PARTID Narrowing feature to allow more resctrl monitoring groups to be provided than the number of PMG values supported by the hardware, a more flexible remapping scheme is needed. Factor out ID translation operations in the MPAM resctrl glue code into a couple of self-contained helpers, and call them as appropriate. The translation scheme has a single parameter, partid_per_closid, which is currently hard-wired to 1. As a result, this patch should have no effect on functionality. Logic to determine / control the mapping parameters can be introduced later. The ID transformation may be visualised as follows: without CDP: +---------------------------------------------------+-----------+ | CLOSID | RMID | +---------------------------------------------------+-------+---+ | PARTID : |PMG| +-----------------------------------------------------------+---+ and with CDP, where the "CDP" field is 0 for the data sub- partition and 1 for the code sub-partition: +-----------------------------------------------+---+-----------+ | CLOSID |CDP| RMID | +-----------------------------------------------+---+-------+---+ | PARTID : |PMG| +-----------------------------------------------------------+---+ where each box represents a non-negative integer spanning some fixed range starting from zero, and horizontal concatenation denotes multiplying the value denoted by the left-hand box by the span of the right-hand box, and adding the result to the value denoted by the right-hand box; thus, most-significant fields are on the left. (Except for the span of each field not necessarily being a power of two, this is conceptually identical to concatenation and cutting of bitfields.) The dotted segment indicates the least significant part of PARTID, which spans partid_per_closid PARTIDs and discriminates monitoring groups that use the same MPAM PMG value. Signed-off-by: Dave Martin --- drivers/platform/arm64/mpam/mpam_resctrl.c | 200 +++++++++++---------- 1 file changed, 110 insertions(+), 90 deletions(-) diff --git a/drivers/platform/arm64/mpam/mpam_resctrl.c b/drivers/platform/= arm64/mpam/mpam_resctrl.c index 30f2caec11d7..0473286ec65a 100644 --- a/drivers/platform/arm64/mpam/mpam_resctrl.c +++ b/drivers/platform/arm64/mpam/mpam_resctrl.c @@ -156,6 +156,18 @@ static bool mpam_resctrl_hide_cdp(enum resctrl_res_lev= el rid) return cdp_enabled && !resctrl_arch_get_cdp_enabled(rid); } =20 +static unsigned int partid_per_closid =3D 1; + +static unsigned int mpam_num_pmg(void) +{ + return mpam_pmg_max + 1; +} + +static unsigned int mpam_num_rmid(void) +{ + return mpam_num_pmg() * partid_per_closid; +} + /* * MSC may raise an error interrupt if it sees an out or range partid/pmg, * and go on to truncate the value. Regardless of what the hardware suppor= ts, @@ -163,35 +175,71 @@ static bool mpam_resctrl_hide_cdp(enum resctrl_res_le= vel rid) */ u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored) { - return mpam_partid_max + 1; + u32 res =3D (mpam_partid_max + 1) / partid_per_closid; + + WARN_ON(res < 1); + return res; } =20 -u32 resctrl_arch_system_num_rmid_idx(void) +static void mpam_resctrl_partid_range(u32 closid, enum resctrl_conf_type t= ype, + const struct rdt_resource *r, + u16 *min_partid, u16 *max_partid) { - u8 closid_shift =3D fls(mpam_pmg_max); - u32 num_partid =3D resctrl_arch_get_num_closid(NULL); + u16 base_partid =3D closid; + u16 span =3D 1; + + if (cdp_enabled) { + base_partid *=3D 2; + if (mpam_resctrl_hide_cdp(r->rid) || + type =3D=3D CDP_NONE) + span *=3D 2; + } =20 - return num_partid << closid_shift; + *min_partid =3D base_partid * partid_per_closid; + if (max_partid) + *max_partid =3D *min_partid + (span * partid_per_closid - 1); } =20 -u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid) +static void mpam_resctrl_hwid(u32 closid, u32 rmid, + u16 *partid_d, u16 *partid_i, u8 *pmg) { - u8 closid_shift =3D fls(mpam_pmg_max); + const u16 pmg_hi =3D rmid / mpam_num_pmg(); + const u16 pmg_lo =3D rmid % mpam_num_pmg(); + u16 base_partid =3D closid; + u16 partid_stride =3D 0; + + if (cdp_enabled) { + base_partid *=3D 2; + partid_stride =3D 1; + } =20 - BUG_ON(closid_shift > 8); + partid_stride *=3D partid_per_closid; + base_partid *=3D partid_per_closid; + base_partid +=3D pmg_hi; =20 - return (closid << closid_shift) | rmid; + *partid_d =3D base_partid; + if (partid_i) + *partid_i =3D base_partid + partid_stride; + + *pmg =3D pmg_lo; } =20 -void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid) +u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid) { - u8 closid_shift =3D fls(mpam_pmg_max); - u32 pmg_mask =3D ~(~0 << closid_shift); + return closid * mpam_num_rmid() + rmid; +} =20 - BUG_ON(closid_shift > 8); +u32 resctrl_arch_system_num_rmid_idx(void) +{ + u32 num_closid =3D resctrl_arch_get_num_closid(NULL); =20 - *closid =3D idx >> closid_shift; - *rmid =3D idx & pmg_mask; + return resctrl_arch_rmid_idx_encode(num_closid, 0); +} + +void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid) +{ + *closid =3D idx / mpam_num_rmid(); + *rmid =3D idx % mpam_num_rmid(); } =20 void resctrl_arch_sched_in(struct task_struct *tsk) @@ -203,21 +251,14 @@ void resctrl_arch_sched_in(struct task_struct *tsk) =20 void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmi= d) { + u16 partid_d, partid_i; + u8 pmg; + BUG_ON(closid > U16_MAX); BUG_ON(rmid > U8_MAX); =20 - if (!cdp_enabled) { - mpam_set_cpu_defaults(cpu, closid, closid, rmid, rmid); - } else { - /* - * When CDP is enabled, resctrl halves the closid range and we - * use odd/even partid for one closid. - */ - u32 partid_d =3D resctrl_get_config_index(closid, CDP_DATA); - u32 partid_i =3D resctrl_get_config_index(closid, CDP_CODE); - - mpam_set_cpu_defaults(cpu, partid_d, partid_i, rmid, rmid); - } + mpam_resctrl_hwid(closid, rmid, &partid_d, &partid_i, &pmg); + mpam_set_cpu_defaults(cpu, partid_d, partid_i, pmg, pmg); } =20 void resctrl_arch_sync_cpu_closid_rmid(void *info) @@ -236,41 +277,38 @@ void resctrl_arch_sync_cpu_closid_rmid(void *info) =20 void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32= rmid) { + u16 partid_d, partid_i; + u8 pmg; + BUG_ON(closid > U16_MAX); BUG_ON(rmid > U8_MAX); =20 - if (!cdp_enabled) { - mpam_set_task_partid_pmg(tsk, closid, closid, rmid, rmid); - } else { - u32 partid_d =3D resctrl_get_config_index(closid, CDP_DATA); - u32 partid_i =3D resctrl_get_config_index(closid, CDP_CODE); - - mpam_set_task_partid_pmg(tsk, partid_d, partid_i, rmid, rmid); - } + mpam_resctrl_hwid(closid, rmid, &partid_d, &partid_i, &pmg); + mpam_set_task_partid_pmg(tsk, partid_d, partid_i, pmg, pmg); } =20 bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid) { + u16 min_partid, max_partid; u64 regval =3D mpam_get_regval(tsk); u32 tsk_closid =3D FIELD_GET(MPAM1_EL1_PARTID_D, regval); =20 - if (cdp_enabled) - tsk_closid >>=3D 1; - - return tsk_closid =3D=3D closid; + mpam_resctrl_partid_range(closid, CDP_NONE, NULL, + &min_partid, &max_partid); + return tsk_closid >=3D min_partid && tsk_closid <=3D max_partid; } =20 /* The task's pmg is not unique, the partid must be considered too */ bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid) { + u16 partid_d; + u8 pmg; u64 regval =3D mpam_get_regval(tsk); - u32 tsk_closid =3D FIELD_GET(MPAM1_EL1_PARTID_D, regval); - u32 tsk_rmid =3D FIELD_GET(MPAM1_EL1_PMG_D, regval); - - if (cdp_enabled) - tsk_closid >>=3D 1; + u16 tsk_partid_d =3D FIELD_GET(MPAM1_EL1_PARTID_D, regval); + u8 tsk_pmg =3D FIELD_GET(MPAM1_EL1_PMG_D, regval); =20 - return (tsk_closid =3D=3D closid) && (tsk_rmid =3D=3D rmid); + mpam_resctrl_hwid(closid, rmid, &partid_d, NULL, &pmg); + return (tsk_partid_d =3D=3D partid_d) && (tsk_pmg =3D=3D pmg); } =20 struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l) @@ -370,6 +408,7 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, stru= ct rdt_mon_domain *d, struct mpam_resctrl_dom *dom; u32 mon =3D *(u32 *)arch_mon_ctx; enum mpam_device_features type; + u16 partid_d, partid_i, pmg; =20 resctrl_arch_rmid_read_context_check(); =20 @@ -391,27 +430,23 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, st= ruct rdt_mon_domain *d, if (cfg.mon =3D=3D USE_RMID_IDX) cfg.mon =3D resctrl_arch_rmid_idx_encode(closid, rmid); =20 + mpam_resctrl_hwid(closid, rmid, &partid_d, &partid_i, &cfg.pmg); cfg.match_pmg =3D true; - cfg.pmg =3D rmid; + cfg.pmg =3D pmg; cfg.opts =3D resctrl_evt_config_to_mpam(dom->mbm_local_evt_cfg); =20 if (irqs_disabled()) { /* Check if we can access this domain without an IPI */ err =3D -EIO; } else { - if (cdp_enabled) { - cfg.partid =3D closid << 1; - err =3D mpam_msmon_read(dom->comp, &cfg, type, val); - if (err) - return err; + cfg.partid =3D partid_d; + err =3D mpam_msmon_read(dom->comp, &cfg, type, val); =20 - cfg.partid +=3D 1; + if (partid_i !=3D partid_d) { + cfg.partid =3D partid_i; err =3D mpam_msmon_read(dom->comp, &cfg, type, &cdp_val); if (!err) *val +=3D cdp_val; - } else { - cfg.partid =3D closid; - err =3D mpam_msmon_read(dom->comp, &cfg, type, val); } } =20 @@ -423,6 +458,7 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, st= ruct rdt_mon_domain *d, { struct mon_cfg cfg; struct mpam_resctrl_dom *dom; + u16 partid_d, partid_i; =20 if (eventid !=3D QOS_L3_MBM_LOCAL_EVENT_ID) return; @@ -433,14 +469,13 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, = struct rdt_mon_domain *d, =20 dom =3D container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom); =20 - if (cdp_enabled) { - cfg.partid =3D closid << 1; - mpam_msmon_reset_mbwu(dom->comp, &cfg); + mpam_resctrl_hwid(closid, rmid, &partid_d, &partid_i, &cfg.pmg); =20 - cfg.partid +=3D 1; - mpam_msmon_reset_mbwu(dom->comp, &cfg); - } else { - cfg.partid =3D closid; + cfg.partid =3D partid_d; + mpam_msmon_reset_mbwu(dom->comp, &cfg); + + if (partid_i !=3D partid_d) { + cfg.partid =3D partid_i; mpam_msmon_reset_mbwu(dom->comp, &cfg); } } @@ -1081,7 +1116,7 @@ static void mpam_resctrl_exit(void) u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain= *d, u32 closid, enum resctrl_conf_type type) { - u32 partid; + u16 partid; struct mpam_config *cfg; struct mpam_props *cprops; struct mpam_resctrl_res *res; @@ -1097,15 +1132,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, = struct rdt_ctrl_domain *d, dom =3D container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom); cprops =3D &res->class->props; =20 - /* - * When CDP is enabled, but the resource doesn't support it, - * the control is cloned across both partids. - * Pick one at random to read: - */ - if (mpam_resctrl_hide_cdp(r->rid)) - type =3D CDP_DATA; - - partid =3D resctrl_get_config_index(closid, type); + mpam_resctrl_partid_range(closid, type, r, &partid, NULL); cfg =3D &dom->comp->cfg[partid]; =20 switch (r->rid) { @@ -1126,7 +1153,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, s= truct rdt_ctrl_domain *d, return -EINVAL; } =20 - if (!r->alloc_capable || partid >=3D resctrl_arch_get_num_closid(r) || + if (!r->alloc_capable || partid > mpam_partid_max || !mpam_has_feature(configured_by, cfg)) return resctrl_get_default_ctrl(r); =20 @@ -1147,8 +1174,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, s= truct rdt_ctrl_domain *d, int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain= *d, u32 closid, enum resctrl_conf_type t, u32 cfg_val) { - int err; - u32 partid; + int err =3D 0; + u16 partid, min_partid, max_partid; struct mpam_config cfg; struct mpam_props *cprops; struct mpam_resctrl_res *res; @@ -1163,8 +1190,10 @@ int resctrl_arch_update_one(struct rdt_resource *r, = struct rdt_ctrl_domain *d, dom =3D container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom); cprops =3D &res->class->props; =20 - partid =3D resctrl_get_config_index(closid, t); - if (!r->alloc_capable || partid >=3D resctrl_arch_get_num_closid(r)) + mpam_resctrl_partid_range(closid, t, r, &min_partid, &max_partid); + if (!r->alloc_capable || + min_partid > mpam_partid_max || + max_partid > mpam_partid_max) return -EINVAL; =20 cfg.features =3D 0; @@ -1190,22 +1219,13 @@ int resctrl_arch_update_one(struct rdt_resource *r,= struct rdt_ctrl_domain *d, return -EINVAL; } =20 - /* - * When CDP is enabled, but the resource doesn't support it, we need to - * apply the same configuration to the other partid. - */ - if (mpam_resctrl_hide_cdp(r->rid)) { - partid =3D resctrl_get_config_index(closid, CDP_CODE); + for (partid =3D min_partid; partid <=3D max_partid; partid++) { err =3D mpam_apply_config(dom->comp, partid, &cfg); if (err) - return err; - - partid =3D resctrl_get_config_index(closid, CDP_DATA); - return mpam_apply_config(dom->comp, partid, &cfg); - - } else { - return mpam_apply_config(dom->comp, partid, &cfg); + break; } + + return err; } =20 /* TODO: this is IPI heavy */ --=20 2.34.1