From nobody Sun Feb 8 17:37:26 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A654C332EA4; Fri, 17 Oct 2025 18:58:15 +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=1760727501; cv=none; b=QtAHSqbD0zxGdzN6sdnPprt7nd7Ryjo+/e4fMuq29LZHFlCXKebYojNSSl1EP9TRl0XWU+Kd0lYJeTGS0B03aUEPdTCQFlCXx/ATtrwnIUNGUDJO8KUJyWGX0lYlFah3jFa+aKqdWeWGFOvBIBh44S7sHqVKBvBCKnZui/Re14U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760727501; c=relaxed/simple; bh=42uw3ey5VCJc8LKjYSjfS3DrIa+6urnzM1+GLaTi06o=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=K1yvhHj+or+21eBve72uqR2zzHsZk9M1qmQBMcTK1T6fmOktsDDC0nvt6oUr8N4Kxf/p+k403G7DwPMnsPArFXh8fkEHBljzb15vPzLem0bWzOH88VFVvtu+iYv+f3ssyC7R17YXO1k7bAtbWzPutiGxdcaUiPtRiQvHf9t5Gcs= 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 1F7441C25; Fri, 17 Oct 2025 11:58:07 -0700 (PDT) Received: from merodach.members.linode.com (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E34E13F66E; Fri, 17 Oct 2025 11:58:09 -0700 (PDT) From: James Morse To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-acpi@vger.kernel.org Cc: James Morse , D Scott Phillips OS , carl@os.amperecomputing.com, lcherian@marvell.com, bobo.shaobowang@huawei.com, tan.shaopeng@fujitsu.com, baolin.wang@linux.alibaba.com, Jamie Iles , Xin Hao , peternewman@google.com, dfustini@baylibre.com, amitsinght@marvell.com, David Hildenbrand , Dave Martin , Koba Ko , Shanker Donthineni , fenghuay@nvidia.com, baisheng.gao@unisoc.com, Jonathan Cameron , Rob Herring , Rohit Mathew , Rafael Wysocki , Len Brown , Lorenzo Pieralisi , Hanjun Guo , Sudeep Holla , Catalin Marinas , Will Deacon , Greg Kroah-Hartman , Danilo Krummrich , Jeremy Linton , Gavin Shan , Dave Martin Subject: [PATCH v3 13/29] arm_mpam: Probe the hardware features resctrl supports Date: Fri, 17 Oct 2025 18:56:29 +0000 Message-Id: <20251017185645.26604-14-james.morse@arm.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20251017185645.26604-1-james.morse@arm.com> References: <20251017185645.26604-1-james.morse@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" Expand the probing support with the control and monitor types we can use with resctrl. CC: Dave Martin Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Fenghua Yu Tested-by: Fenghua Yu --- Changes since v2: * Moved some feature enum values that resctrl doesn't support to a later patch. * Swapped mpam_has_feature() out for the macro version that is used later. Changes since v1: * added an underscore to a variable name. Changes since RFC: * Made mpam_ris_hw_probe_hw_nrdy() more in C. * Added static assert on features bitmap size. --- drivers/resctrl/mpam_devices.c | 147 ++++++++++++++++++++++++++++++++ drivers/resctrl/mpam_internal.h | 33 +++++++ 2 files changed, 180 insertions(+) diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index 35011d3e8f1e..80c27c84dccc 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -142,6 +142,20 @@ static inline void _mpam_write_partsel_reg(struct mpam= _msc *msc, u16 reg, u32 va } #define mpam_write_partsel_reg(msc, reg, val) _mpam_write_partsel_reg(msc= , MPAMCFG_##reg, val) =20 +static inline u32 _mpam_read_monsel_reg(struct mpam_msc *msc, u16 reg) +{ + mpam_mon_sel_lock_held(msc); + return __mpam_read_reg(msc, reg); +} +#define mpam_read_monsel_reg(msc, reg) _mpam_read_monsel_reg(msc, MSMON_##= reg) + +static inline void _mpam_write_monsel_reg(struct mpam_msc *msc, u16 reg, u= 32 val) +{ + mpam_mon_sel_lock_held(msc); + __mpam_write_reg(msc, reg, val); +} +#define mpam_write_monsel_reg(msc, reg, val) _mpam_write_monsel_reg(msc,= MSMON_##reg, val) + static u64 mpam_msc_read_idr(struct mpam_msc *msc) { u64 idr_high =3D 0, idr_low; @@ -544,6 +558,133 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(st= ruct mpam_msc *msc, return ERR_PTR(-ENOENT); } =20 +/* + * IHI009A.a has this nugget: "If a monitor does not support automatic beh= aviour + * of NRDY, software can use this bit for any purpose" - so hardware might= not + * implement this - but it isn't RES0. + * + * Try and see what values stick in this bit. If we can write either value, + * its probably not implemented by hardware. + */ +static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_r= eg) +{ + u32 now; + u64 mon_sel; + bool can_set, can_clear; + struct mpam_msc *msc =3D ris->vmsc->msc; + + if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc))) + return false; + + mon_sel =3D FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, 0) | + FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); + _mpam_write_monsel_reg(msc, mon_reg, mon_sel); + + _mpam_write_monsel_reg(msc, mon_reg, MSMON___NRDY); + now =3D _mpam_read_monsel_reg(msc, mon_reg); + can_set =3D now & MSMON___NRDY; + + _mpam_write_monsel_reg(msc, mon_reg, 0); + now =3D _mpam_read_monsel_reg(msc, mon_reg); + can_clear =3D !(now & MSMON___NRDY); + mpam_mon_sel_unlock(msc); + + return (!can_set || !can_clear); +} + +#define mpam_ris_hw_probe_hw_nrdy(_ris, _mon_reg) \ + _mpam_ris_hw_probe_hw_nrdy(_ris, MSMON_##_mon_reg) + +static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) +{ + int err; + struct mpam_msc *msc =3D ris->vmsc->msc; + struct device *dev =3D &msc->pdev->dev; + struct mpam_props *props =3D &ris->props; + + lockdep_assert_held(&msc->probe_lock); + lockdep_assert_held(&msc->part_sel_lock); + + /* Cache Portion partitioning */ + if (FIELD_GET(MPAMF_IDR_HAS_CPOR_PART, ris->idr)) { + u32 cpor_features =3D mpam_read_partsel_reg(msc, CPOR_IDR); + + props->cpbm_wd =3D FIELD_GET(MPAMF_CPOR_IDR_CPBM_WD, cpor_features); + if (props->cpbm_wd) + mpam_set_feature(mpam_feat_cpor_part, props); + } + + /* Memory bandwidth partitioning */ + if (FIELD_GET(MPAMF_IDR_HAS_MBW_PART, ris->idr)) { + u32 mbw_features =3D mpam_read_partsel_reg(msc, MBW_IDR); + + /* portion bitmap resolution */ + props->mbw_pbm_bits =3D FIELD_GET(MPAMF_MBW_IDR_BWPBM_WD, mbw_features); + if (props->mbw_pbm_bits && + FIELD_GET(MPAMF_MBW_IDR_HAS_PBM, mbw_features)) + mpam_set_feature(mpam_feat_mbw_part, props); + + props->bwa_wd =3D 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); + } + + /* Performance Monitoring */ + if (FIELD_GET(MPAMF_IDR_HAS_MSMON, ris->idr)) { + u32 msmon_features =3D mpam_read_partsel_reg(msc, MSMON_IDR); + + /* + * If the firmware max-nrdy-us property is missing, the + * CSU counters can't be used. Should we wait forever? + */ + err =3D device_property_read_u32(&msc->pdev->dev, + "arm,not-ready-us", + &msc->nrdy_usec); + + if (FIELD_GET(MPAMF_MSMON_IDR_MSMON_CSU, msmon_features)) { + u32 csumonidr; + + csumonidr =3D mpam_read_partsel_reg(msc, CSUMON_IDR); + props->num_csu_mon =3D FIELD_GET(MPAMF_CSUMON_IDR_NUM_MON, csumonidr); + if (props->num_csu_mon) { + bool hw_managed; + + mpam_set_feature(mpam_feat_msmon_csu, props); + + /* Is NRDY hardware managed? */ + hw_managed =3D mpam_ris_hw_probe_hw_nrdy(ris, CSU); + if (hw_managed) + mpam_set_feature(mpam_feat_msmon_csu_hw_nrdy, props); + } + + /* + * Accept the missing firmware property if NRDY appears + * un-implemented. + */ + if (err && mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, props)) + dev_err_once(dev, "Counters are not usable because not-ready timeout w= as not provided by firmware."); + } + if (FIELD_GET(MPAMF_MSMON_IDR_MSMON_MBWU, msmon_features)) { + bool hw_managed; + u32 mbwumon_idr =3D mpam_read_partsel_reg(msc, MBWUMON_IDR); + + props->num_mbwu_mon =3D FIELD_GET(MPAMF_MBWUMON_IDR_NUM_MON, mbwumon_id= r); + if (props->num_mbwu_mon) + mpam_set_feature(mpam_feat_msmon_mbwu, props); + + /* Is NRDY hardware managed? */ + hw_managed =3D mpam_ris_hw_probe_hw_nrdy(ris, MBWU); + if (hw_managed) + mpam_set_feature(mpam_feat_msmon_mbwu_hw_nrdy, props); + + /* + * Don't warn about any missing firmware property for + * MBWU NRDY - it doesn't make any sense! + */ + } + } +} + static int mpam_msc_hw_probe(struct mpam_msc *msc) { u64 idr; @@ -587,6 +728,12 @@ static int mpam_msc_hw_probe(struct mpam_msc *msc) mutex_unlock(&mpam_list_lock); if (IS_ERR(ris)) return PTR_ERR(ris); + ris->idr =3D idr; + + mutex_lock(&msc->part_sel_lock); + __mpam_part_sel(ris_idx, 0, msc); + mpam_ris_hw_probe(ris); + mutex_unlock(&msc->part_sel_lock); } =20 spin_lock(&partid_max_lock); diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_interna= l.h index 1afc52b36328..be9ea0aab6d2 100644 --- a/drivers/resctrl/mpam_internal.h +++ b/drivers/resctrl/mpam_internal.h @@ -5,6 +5,7 @@ #define MPAM_INTERNAL_H =20 #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include =20 #define MPAM_MSC_MAX_NUM_RIS 16 =20 @@ -111,6 +113,33 @@ static inline void mpam_mon_sel_lock_init(struct mpam_= msc *msc) raw_spin_lock_init(&msc->_mon_sel_lock); } =20 +/* Bits for mpam features bitmaps */ +enum mpam_device_features { + mpam_feat_cpor_part =3D 0, + mpam_feat_mbw_part, + mpam_feat_mbw_min, + mpam_feat_mbw_max, + mpam_feat_msmon, + mpam_feat_msmon_csu, + mpam_feat_msmon_csu_hw_nrdy, + mpam_feat_msmon_mbwu, + mpam_feat_msmon_mbwu_hw_nrdy, + MPAM_FEATURE_LAST +}; + +struct mpam_props { + DECLARE_BITMAP(features, MPAM_FEATURE_LAST); + + u16 cpbm_wd; + u16 mbw_pbm_bits; + u16 bwa_wd; + u16 num_csu_mon; + u16 num_mbwu_mon; +}; + +#define mpam_has_feature(_feat, x) test_bit(_feat, (x)->features) +#define mpam_set_feature(_feat, x) set_bit(_feat, (x)->features) + struct mpam_class { /* mpam_components in this class */ struct list_head components; @@ -150,6 +179,8 @@ struct mpam_vmsc { /* mpam_msc_ris in this vmsc */ struct list_head ris; =20 + struct mpam_props props; + /* All RIS in this vMSC are members of this MSC */ struct mpam_msc *msc; =20 @@ -161,6 +192,8 @@ struct mpam_vmsc { =20 struct mpam_msc_ris { u8 ris_idx; + u64 idr; + struct mpam_props props; =20 cpumask_t affinity; =20 --=20 2.39.5