From: Qinxin Xia <xiaqinxin@huawei.com>
To: <ben.horgan@arm.com>, <zhangzhanpeng.jasper@bytedance.com>,
<joro@8bytes.org>, <palmer@dabbelt.com>, <tony.luck@intel.com>,
<reinette.chatre@intel.com>, <tomasz.jeznach@linux.dev>,
<zengheng4@huawei.com>, <fustini@kernel.org>,
<cuiyunhui@bytedance.com>, <wangzhou1@hisilicon.com>,
<xiaqinxin@huawei.com>
Cc: <will@kernel.org>, <robin.murphy@arm.com>, <pjw@kernel.org>,
<aou@eecs.berkeley.edu>, <alex@ghiti.fr>, <Dave.Martin@arm.com>,
<james.morse@arm.com>, <babu.moger@amd.com>, <corbet@lwn.net>,
<shuah@kernel.org>, <jgg@ziepe.ca>, <kevin.tian@intel.com>,
<yuanzhu@bytedance.com>, <iommu@lists.linux.dev>,
<linuxarm@huawei.com>, <baolin.wang@linux.alibaba.com>
Subject: [RFC PATCH 3/5] iommu/arm-smmu-v3: Support MPAM device DMA QoS tagging
Date: Tue, 1 Sep 2026 22:08:00 +0800 [thread overview]
Message-ID: <20260901140802.1215508-4-xiaqinxin@huawei.com> (raw)
In-Reply-To: <20260901140802.1215508-1-xiaqinxin@huawei.com>
Enable tagging a master's DMA with an MPAM PARTID/PMG so resctrl can assign
a device to a resource group.
When the SMMU supports MPAM, register it with the MPAM code and let resctrl
program a device's PARTID/PMG, bounded by the hardware limits.
Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 96 +++++++++++++++++++++
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 13 +++
2 files changed, 109 insertions(+)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 5732f3ba0122..7b1f65c0ee6d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -11,6 +11,7 @@
#include <linux/acpi.h>
#include <linux/acpi_iort.h>
+#include <linux/arm_mpam.h>
#include <linux/bitops.h>
#include <linux/crash_dump.h>
#include <linux/delay.h>
@@ -4374,6 +4375,65 @@ static int arm_smmu_def_domain_type(struct device *dev)
return 0;
}
+static int arm_smmu_set_dev_requestor_id(struct device *dev, u32 partid,
+ u8 pmg)
+{
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+ struct arm_smmu_cmd cmd;
+ struct arm_smmu_cmdq_batch cmds;
+ struct arm_smmu_device *smmu;
+ u64 val;
+ int i;
+
+ /*
+ * TODO: This writes the PARTID/PMG directly into the live STEs, so the
+ * tag is lost on any later STE rewrite and can race a concurrent writer.
+ * It should be stored on arm_smmu_master and stamped in the STE
+ * generators via a group-mutex-holding path instead.
+ */
+ if (!master || !master->smmu)
+ return -ENODEV;
+ smmu = master->smmu;
+
+ if (!(smmu->features & ARM_SMMU_FEAT_MPAM))
+ return -EOPNOTSUPP;
+
+ if (partid > smmu->partid_max || pmg > smmu->pmg_max)
+ return -ERANGE;
+
+ /* Program the stream-level PARTID/PMG into every STE the master owns. */
+ arm_smmu_cmdq_batch_init_cmd(smmu, &cmds, &cmd);
+ mutex_lock(&smmu->streams_mutex);
+ for (i = 0; i < master->num_streams; i++) {
+ u32 sid = master->streams[i].id;
+ struct arm_smmu_ste *ste = arm_smmu_get_step_for_sid(smmu, sid);
+
+ if (!ste)
+ continue;
+
+ val = le64_to_cpu(ste->data[1]);
+ val &= ~STRTAB_STE_1_S1MPAM;
+ WRITE_ONCE(ste->data[1], cpu_to_le64(val));
+
+ val = le64_to_cpu(ste->data[4]);
+ val &= ~STRTAB_STE_4_PARTID;
+ val |= FIELD_PREP(STRTAB_STE_4_PARTID, partid);
+ WRITE_ONCE(ste->data[4], cpu_to_le64(val));
+
+ val = le64_to_cpu(ste->data[5]);
+ val &= ~STRTAB_STE_5_PMG;
+ val |= FIELD_PREP(STRTAB_STE_5_PMG, pmg);
+ WRITE_ONCE(ste->data[5], cpu_to_le64(val));
+
+ cmd = arm_smmu_make_cmd_cfgi_ste(sid, true);
+ arm_smmu_cmdq_batch_add_cmd_p(smmu, &cmds, &cmd);
+ }
+
+ mutex_unlock(&smmu->streams_mutex);
+ arm_smmu_cmdq_batch_submit(smmu, &cmds);
+ return 0;
+}
+
static const struct iommu_ops arm_smmu_ops = {
.identity_domain = &arm_smmu_identity_domain,
.blocked_domain = &arm_smmu_blocked_domain,
@@ -4388,6 +4448,7 @@ static const struct iommu_ops arm_smmu_ops = {
.of_xlate = arm_smmu_of_xlate,
.get_resv_regions = arm_smmu_get_resv_regions,
.page_response = arm_smmu_page_response,
+ .set_dev_requestor_id = arm_smmu_set_dev_requestor_id,
.def_domain_type = arm_smmu_def_domain_type,
.get_viommu_size = arm_smmu_get_viommu_size,
.viommu_init = arm_vsmmu_init,
@@ -5046,6 +5107,36 @@ static void arm_smmu_get_httu(struct arm_smmu_device *smmu, u32 reg)
hw_features, fw_features);
}
+static void arm_smmu_mpam_register_smmu(struct arm_smmu_device *smmu)
+{
+ u16 partid_max;
+ u8 pmg_max;
+ u32 reg;
+
+ if (!IS_ENABLED(CONFIG_ARM64_MPAM))
+ return;
+
+ if (!(smmu->features & ARM_SMMU_FEAT_MPAM))
+ return;
+
+ reg = readl_relaxed(smmu->base + ARM_SMMU_MPAMIDR);
+ if (!reg)
+ return;
+
+ partid_max = FIELD_GET(SMMU_MPAMIDR_PARTID_MAX, reg);
+ pmg_max = FIELD_GET(SMMU_MPAMIDR_PMG_MAX, reg);
+
+ smmu->partid_max = partid_max;
+ smmu->pmg_max = pmg_max;
+
+ if (mpam_register_requestor(partid_max, pmg_max)) {
+ smmu->features &= ~ARM_SMMU_FEAT_MPAM;
+ return;
+ }
+
+ mpam_register_device_requestor();
+}
+
static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
{
u32 reg;
@@ -5197,6 +5288,9 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
if (FIELD_GET(IDR3_BBM, reg) == 2)
smmu->features |= ARM_SMMU_FEAT_BBML2;
+ if (FIELD_GET(IDR3_MPAM, reg))
+ smmu->features |= ARM_SMMU_FEAT_MPAM;
+
/* IDR5 */
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
@@ -5261,6 +5355,8 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
if (arm_smmu_sva_supported(smmu))
smmu->features |= ARM_SMMU_FEAT_SVA;
+ arm_smmu_mpam_register_smmu(smmu);
+
dev_info(smmu->dev, "oas %lu-bit (features 0x%08x)\n",
smmu->oas, smmu->features);
return 0;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 50f8321e979c..f0118214c81c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -59,6 +59,7 @@ struct arm_vsmmu;
#define IDR1_SIDSIZE GENMASK(5, 0)
#define ARM_SMMU_IDR3 0xc
+#define IDR3_MPAM (1 << 7)
#define IDR3_FWB (1 << 8)
#define IDR3_RIL (1 << 10)
#define IDR3_BBM GENMASK(12, 11)
@@ -171,6 +172,10 @@ struct arm_vsmmu;
#define ARM_SMMU_PRIQ_IRQ_CFG1 0xd8
#define ARM_SMMU_PRIQ_IRQ_CFG2 0xdc
+#define ARM_SMMU_MPAMIDR 0x130
+#define SMMU_MPAMIDR_PARTID_MAX GENMASK(15, 0)
+#define SMMU_MPAMIDR_PMG_MAX GENMASK(23, 16)
+
#define ARM_SMMU_REG_SZ 0xe00
/* Common MSI config fields */
@@ -300,6 +305,10 @@ static inline u32 arm_smmu_strtab_l2_idx(u32 sid)
#define STRTAB_STE_2_S2S (1UL << 57)
#define STRTAB_STE_2_S2R (1UL << 58)
+#define STRTAB_STE_1_S1MPAM (1UL << 26)
+#define STRTAB_STE_4_PARTID GENMASK_ULL(31, 16)
+#define STRTAB_STE_5_PMG GENMASK_ULL(7, 0)
+
#define STRTAB_STE_3_S2TTB_MASK GENMASK_ULL(51, 4)
/* These bits can be controlled by userspace for STRTAB_STE_0_CFG_NESTED */
@@ -927,8 +936,12 @@ struct arm_smmu_device {
#define ARM_SMMU_FEAT_BBML2 (1 << 24)
#define ARM_SMMU_FEAT_HAFT (1 << 25)
#define ARM_SMMU_FEAT_DS (1 << 26)
+#define ARM_SMMU_FEAT_MPAM (1 << 27)
u32 features;
+ u16 partid_max;
+ u8 pmg_max;
+
#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0)
#define ARM_SMMU_OPT_PAGE0_REGS_ONLY (1 << 1)
#define ARM_SMMU_OPT_MSIPOLL (1 << 2)
--
2.33.0
next prev parent reply other threads:[~2026-09-01 14:08 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 14:07 [RFC PATCH 0/5] resctrl: Assign devices to resource groups via IOMMU DMA QoS tagging Qinxin Xia
2026-09-01 14:07 ` [RFC PATCH 1/5] iommu: Add per-device requestor QoS tagging and lookup helpers Qinxin Xia
2026-09-01 14:07 ` [RFC PATCH 2/5] arm_mpam: resctrl: Add arch query for device DMA QoS support Qinxin Xia
2026-09-01 14:08 ` Qinxin Xia [this message]
2026-09-01 14:08 ` [RFC PATCH 4/5] fs/resctrl: Add device-to-group QoS tracking infrastructure Qinxin Xia
2026-09-01 14:08 ` [RFC PATCH 5/5] fs/resctrl: Add a "devices" file to assign devices to groups Qinxin Xia
2026-09-10 10:24 ` Ben Horgan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260901140802.1215508-4-xiaqinxin@huawei.com \
--to=xiaqinxin@huawei.com \
--cc=Dave.Martin@arm.com \
--cc=alex@ghiti.fr \
--cc=aou@eecs.berkeley.edu \
--cc=babu.moger@amd.com \
--cc=baolin.wang@linux.alibaba.com \
--cc=ben.horgan@arm.com \
--cc=corbet@lwn.net \
--cc=cuiyunhui@bytedance.com \
--cc=fustini@kernel.org \
--cc=iommu@lists.linux.dev \
--cc=james.morse@arm.com \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=linuxarm@huawei.com \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=reinette.chatre@intel.com \
--cc=robin.murphy@arm.com \
--cc=shuah@kernel.org \
--cc=tomasz.jeznach@linux.dev \
--cc=tony.luck@intel.com \
--cc=wangzhou1@hisilicon.com \
--cc=will@kernel.org \
--cc=yuanzhu@bytedance.com \
--cc=zengheng4@huawei.com \
--cc=zhangzhanpeng.jasper@bytedance.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.