From: Xingang Wang wangxingang5@huawei.com
This series patches introduce mpam feature for ascend: - 1. The mpam driver resctrlfs need to add write interface for rmid, so that the rmid can be configured from userspace. - 2. Add support to configure SMMU mpam from svm.
bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2
Xingang Wang (9): iommu/arm-smmu-v3: Add support to configure mpam in STE/CD context iommu/arm-smmu-v3: Add support to get SMMU mpam configuration iommu/arm-smmu-v3: Add support to enable/disable SMMU user_mpam_en svm: Add support to get svm mpam configuration svm: Add support to set svm mpam configuration svm: Add svm_set_user_mpam_en to enable/disable mpam for smmu mpam: enable rdt_mon_capable for mbw monitor mpam: Add support for group rmid modify mpam: update monitor rmid and group configuration
arch/arm64/kernel/mpam/mpam_ctrlmon.c | 33 ++-- arch/arm64/kernel/mpam/mpam_resctrl.c | 104 +++++++++- arch/arm64/kernel/mpam/mpam_setup.c | 1 + drivers/char/svm.c | 227 ++++++++++++++++++++++ drivers/iommu/arm-smmu-v3-context.c | 42 ++++ drivers/iommu/arm-smmu-v3.c | 265 ++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 21 ++ 7 files changed, 674 insertions(+), 19 deletions(-) create mode 100644 include/linux/ascend_smmu.h
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
To support limiting qos of device, the partid and pmg need to be set into the SMMU STE/CD context. This introduce support of SMMU mpam feature and add interface to set mpam configuration in STE/CD.
Signed-off-by: Xingang Wang wangxingang5@huawei.com Signed-off-by: Rui Zhu zhurui3@huawei.com --- drivers/iommu/arm-smmu-v3-context.c | 25 +++++ drivers/iommu/arm-smmu-v3.c | 152 ++++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 9 ++ 3 files changed, 186 insertions(+) create mode 100644 include/linux/ascend_smmu.h
diff --git a/drivers/iommu/arm-smmu-v3-context.c b/drivers/iommu/arm-smmu-v3-context.c index 2351de86d..b30a93e07 100644 --- a/drivers/iommu/arm-smmu-v3-context.c +++ b/drivers/iommu/arm-smmu-v3-context.c @@ -66,6 +66,9 @@
#define CTXDESC_CD_1_TTB0_MASK GENMASK_ULL(51, 4)
+#define CTXDESC_CD_5_PARTID_MASK GENMASK_ULL(47, 32) +#define CTXDESC_CD_5_PMG_MASK GENMASK_ULL(55, 48) + /* Convert between AArch64 (CPU) TCR format and SMMU CD format */ #define ARM_SMMU_TCR2CD(tcr, fld) FIELD_PREP(CTXDESC_CD_0_TCR_##fld, \ FIELD_GET(ARM64_TCR_##fld, tcr)) @@ -563,6 +566,28 @@ static int arm_smmu_set_cd(struct iommu_pasid_table_ops *ops, int pasid, return arm_smmu_write_ctx_desc(tbl, pasid, cd); }
+int arm_smmu_set_cd_mpam(struct iommu_pasid_table_ops *ops, + int ssid, int partid, int pmg) +{ + struct arm_smmu_cd_tables *tbl = pasid_ops_to_tables(ops); + u64 val; + __le64 *cdptr = arm_smmu_get_cd_ptr(tbl, ssid); + + if (!cdptr) + return -ENOMEM; + + val = le64_to_cpu(cdptr[5]); + val &= ~CTXDESC_CD_5_PARTID_MASK; + val |= FIELD_PREP(CTXDESC_CD_5_PARTID_MASK, partid); + val &= ~CTXDESC_CD_5_PMG_MASK; + val |= FIELD_PREP(CTXDESC_CD_5_PMG_MASK, pmg); + WRITE_ONCE(cdptr[5], cpu_to_le64(val)); + + iommu_pasid_flush(&tbl->pasid, ssid, true); + + return 0; +} + static void arm_smmu_clear_cd(struct iommu_pasid_table_ops *ops, int pasid, struct iommu_pasid_entry *entry) { diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 292fd9a10..47ed3c77f 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -88,6 +88,10 @@ #define IDR1_SSIDSIZE GENMASK(10, 6) #define IDR1_SIDSIZE GENMASK(5, 0)
+#define ARM_SMMU_IDR3 0xc +#define IDR3_MPAM (1 << 7) +#define ARM_SMMU_IDR3_CFG 0x140C + #define ARM_SMMU_IDR5 0x14 #define IDR5_STALL_MAX GENMASK(31, 16) #define IDR5_GRAN64K (1 << 6) @@ -186,6 +190,10 @@ #define ARM_SMMU_PRIQ_IRQ_CFG1 0xd8 #define ARM_SMMU_PRIQ_IRQ_CFG2 0xdc
+#define ARM_SMMU_MPAMIDR 0x130 +#define MPAMIDR_PMG_MAX GENMASK(23, 16) +#define MPAMIDR_PARTID_MAX GENMASK(15, 0) + /* Common MSI config fields */ #define MSI_CFG0_ADDR_MASK GENMASK_ULL(51, 2) #define MSI_CFG2_SH GENMASK(5, 4) @@ -250,6 +258,7 @@ #define STRTAB_STE_1_S1COR GENMASK_ULL(5, 4) #define STRTAB_STE_1_S1CSH GENMASK_ULL(7, 6)
+#define STRTAB_STE_1_S1MPAM (1UL << 26) #define STRTAB_STE_1_S1STALLD (1UL << 27)
#define STRTAB_STE_1_EATS GENMASK_ULL(29, 28) @@ -273,6 +282,11 @@
#define STRTAB_STE_3_S2TTB_MASK GENMASK_ULL(51, 4)
+#define STRTAB_STE_4_PARTID_MASK GENMASK_ULL(31, 16) + +#define STRTAB_STE_5_MPAM_NS (1UL << 8) +#define STRTAB_STE_5_PMG_MASK GENMASK_ULL(7, 0) + /* Command queue */ #define CMDQ_ENT_SZ_SHIFT 4 #define CMDQ_ENT_DWORDS ((1 << CMDQ_ENT_SZ_SHIFT) >> 3) @@ -634,6 +648,7 @@ struct arm_smmu_device { #define ARM_SMMU_FEAT_SVA (1 << 17) #define ARM_SMMU_FEAT_HA (1 << 18) #define ARM_SMMU_FEAT_HD (1 << 19) +#define ARM_SMMU_FEAT_MPAM (1 << 20) u32 features;
#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0) @@ -672,6 +687,9 @@ struct arm_smmu_device { struct mutex streams_mutex;
struct iopf_queue *iopf_queue; + + unsigned int mpam_partid_max; + unsigned int mpam_pmg_max; };
struct arm_smmu_stream { @@ -3979,6 +3997,26 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) if (smmu->sid_bits <= STRTAB_SPLIT) smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB;
+ /* IDR3 */ + reg = readl_relaxed(smmu->base + ARM_SMMU_IDR3); + + if (!(reg & IDR3_MPAM)) { + reg |= FIELD_PREP(IDR3_MPAM, 1); + writel_relaxed(reg, smmu->base + ARM_SMMU_IDR3_CFG); + } + reg = readl_relaxed(smmu->base + ARM_SMMU_IDR3); + if (reg & IDR3_MPAM) { + reg = readl_relaxed(smmu->base + ARM_SMMU_MPAMIDR); + + smmu->mpam_partid_max = FIELD_GET(MPAMIDR_PARTID_MAX, reg); + smmu->mpam_pmg_max = FIELD_GET(MPAMIDR_PMG_MAX, reg); + if (smmu->mpam_partid_max || smmu->mpam_pmg_max) + smmu->features |= ARM_SMMU_FEAT_MPAM; + } else { + dev_warn(smmu->dev, "enable smmu mpam failed\n"); + } + + /* IDR5 */ reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
@@ -4126,6 +4164,120 @@ static unsigned long arm_smmu_resource_size(struct arm_smmu_device *smmu) return SZ_128K; }
+static int arm_smmu_set_ste_mpam(struct arm_smmu_device *smmu, + int sid, int partid, int pmg, int s1mpam) +{ + u64 val; + __le64 *ste; + + if (!arm_smmu_sid_in_range(smmu, sid)) + return -ERANGE; + + /* get ste ptr */ + ste = arm_smmu_get_step_for_sid(smmu, sid); + + /* write s1mpam to ste */ + val = le64_to_cpu(ste[1]); + val &= ~STRTAB_STE_1_S1MPAM; + val |= FIELD_PREP(STRTAB_STE_1_S1MPAM, s1mpam); + WRITE_ONCE(ste[1], cpu_to_le64(val)); + + val = le64_to_cpu(ste[4]); + val &= ~STRTAB_STE_4_PARTID_MASK; + val |= FIELD_PREP(STRTAB_STE_4_PARTID_MASK, partid); + WRITE_ONCE(ste[4], cpu_to_le64(val)); + + val = le64_to_cpu(ste[5]); + val &= ~STRTAB_STE_5_PMG_MASK; + val |= FIELD_PREP(STRTAB_STE_5_PMG_MASK, pmg); + WRITE_ONCE(ste[5], cpu_to_le64(val)); + + arm_smmu_sync_ste_for_sid(smmu, sid); + + return 0; +} + +int arm_smmu_set_cd_mpam(struct iommu_pasid_table_ops *ops, + int ssid, int partid, int pmg); + +static int arm_smmu_set_mpam(struct arm_smmu_device *smmu, + int sid, int ssid, int partid, int pmg, int s1mpam) +{ + struct arm_smmu_master_data *master = arm_smmu_find_master(smmu, sid); + struct arm_smmu_s1_cfg *cfg = master ? master->ste.s1_cfg : NULL; + struct arm_smmu_domain *domain = master ? master->domain : NULL; + int ret; + + struct arm_smmu_cmdq_ent prefetch_cmd = { + .opcode = CMDQ_OP_PREFETCH_CFG, + .prefetch = { + .sid = sid, + }, + }; + + if (!(smmu->features & ARM_SMMU_FEAT_MPAM)) + return -ENODEV; + + if (WARN_ON(!domain)) + return -EINVAL; + + if (WARN_ON(!cfg)) + return -EINVAL; + + if (WARN_ON(ssid >= (1 << master->ssid_bits))) + return -E2BIG; + + if (partid > smmu->mpam_partid_max || pmg > smmu->mpam_pmg_max) { + dev_err(smmu->dev, + "mpam rmid out of range: partid[0, %d] pmg[0, %d]\n", + smmu->mpam_partid_max, smmu->mpam_pmg_max); + return -ERANGE; + } + + ret = arm_smmu_set_ste_mpam(smmu, sid, partid, pmg, s1mpam); + if (ret < 0) { + dev_err(smmu->dev, "set ste mpam configuration error %d\n", + ret); + return ret; + } + + /* do not modify cd table which owned by guest */ + if (domain->stage == ARM_SMMU_DOMAIN_NESTED) { + dev_err(smmu->dev, + "mpam: smmu cd is owned by guest, not modified\n"); + return 0; + } + + ret = arm_smmu_set_cd_mpam(cfg->ops, ssid, partid, pmg); + if (ret < 0) { + dev_err(smmu->dev, "set cd mpam configuration error %d\n", + ret); + return ret; + } + + /* It's likely that we'll want to use the new STE soon */ + if (!(smmu->options & ARM_SMMU_OPT_SKIP_PREFETCH)) + arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd); + + dev_info(smmu->dev, "partid %d, pmg %d\n", partid, pmg); + + return 0; +} + +/** + * arm_smmu_set_dev_mpam() - Set mpam configuration to SMMU STE/CD + */ +int arm_smmu_set_dev_mpam(struct device *dev, int ssid, int partid, int pmg, + int s1mpam) +{ + struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv; + struct arm_smmu_device *smmu = master->domain->smmu; + int sid = master->streams->id; + + return arm_smmu_set_mpam(smmu, sid, ssid, partid, pmg, s1mpam); +} +EXPORT_SYMBOL(arm_smmu_set_dev_mpam); + static int arm_smmu_device_probe(struct platform_device *pdev) { int irq, ret; diff --git a/include/linux/ascend_smmu.h b/include/linux/ascend_smmu.h new file mode 100644 index 000000000..bd0edd250 --- /dev/null +++ b/include/linux/ascend_smmu.h @@ -0,0 +1,9 @@ +#ifndef __LINUX_ASCEND_SMMU_H +#define __LINUX_ASCEND_SMMU_H + +#include <linux/device.h> + +extern int arm_smmu_set_dev_mpam(struct device *dev, int ssid, int partid, + int pmg, int s1mpam); + +#endif /* __LINUX_ASCEND_SMMU_H */
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
Add interface to get mpam configuration of CD/STE context, use s1mpam to indicate whether partid and pmg from CD or STE.
Signed-off-by: Xingang Wang wangxingang5@huawei.com --- drivers/iommu/arm-smmu-v3-context.c | 17 +++++++ drivers/iommu/arm-smmu-v3.c | 76 +++++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 3 ++ 3 files changed, 96 insertions(+)
diff --git a/drivers/iommu/arm-smmu-v3-context.c b/drivers/iommu/arm-smmu-v3-context.c index b30a93e07..d87d6f72e 100644 --- a/drivers/iommu/arm-smmu-v3-context.c +++ b/drivers/iommu/arm-smmu-v3-context.c @@ -588,6 +588,23 @@ int arm_smmu_set_cd_mpam(struct iommu_pasid_table_ops *ops, return 0; }
+int arm_smmu_get_cd_mpam(struct iommu_pasid_table_ops *ops, + int ssid, int *partid, int *pmg) +{ + struct arm_smmu_cd_tables *tbl = pasid_ops_to_tables(ops); + u64 val; + __le64 *cdptr = arm_smmu_get_cd_ptr(tbl, ssid); + + if (!cdptr) + return -ENOMEM; + + val = le64_to_cpu(cdptr[5]); + *partid = FIELD_GET(CTXDESC_CD_5_PARTID_MASK, val); + *pmg = FIELD_GET(CTXDESC_CD_5_PMG_MASK, val); + + return 0; +} + static void arm_smmu_clear_cd(struct iommu_pasid_table_ops *ops, int pasid, struct iommu_pasid_entry *entry) { diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 47ed3c77f..4717c3eb6 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -4197,9 +4197,39 @@ static int arm_smmu_set_ste_mpam(struct arm_smmu_device *smmu, return 0; }
+static int arm_smmu_get_ste_mpam(struct arm_smmu_device *smmu, + int sid, int *partid, int *pmg, int *s1mpam) +{ + u64 val; + __le64 *ste; + + if (!arm_smmu_sid_in_range(smmu, sid)) + return -ERANGE; + + /* get ste ptr */ + ste = arm_smmu_get_step_for_sid(smmu, sid); + + val = le64_to_cpu(ste[1]); + *s1mpam = FIELD_GET(STRTAB_STE_1_S1MPAM, val); + + if (*s1mpam) + return 0; + + val = le64_to_cpu(ste[4]); + *partid = FIELD_GET(STRTAB_STE_4_PARTID_MASK, val); + + val = le64_to_cpu(ste[5]); + *pmg = FIELD_GET(STRTAB_STE_5_PMG_MASK, val); + + return 0; +} + int arm_smmu_set_cd_mpam(struct iommu_pasid_table_ops *ops, int ssid, int partid, int pmg);
+int arm_smmu_get_cd_mpam(struct iommu_pasid_table_ops *ops, + int ssid, int *partid, int *pmg); + static int arm_smmu_set_mpam(struct arm_smmu_device *smmu, int sid, int ssid, int partid, int pmg, int s1mpam) { @@ -4278,6 +4308,52 @@ int arm_smmu_set_dev_mpam(struct device *dev, int ssid, int partid, int pmg, } EXPORT_SYMBOL(arm_smmu_set_dev_mpam);
+static int arm_smmu_get_mpam(struct arm_smmu_device *smmu, + int sid, int ssid, int *partid, int *pmg, int *s1mpam) +{ + struct arm_smmu_master_data *master = arm_smmu_find_master(smmu, sid); + struct arm_smmu_s1_cfg *cfg = master ? master->ste.s1_cfg : NULL; + int ret; + + if (!(smmu->features & ARM_SMMU_FEAT_MPAM)) + return -ENODEV; + + ret = arm_smmu_get_ste_mpam(smmu, sid, partid, pmg, s1mpam); + if (ret) + return ret; + + /* return STE mpam configuration when s1mpam == 0 */ + if (!(*s1mpam)) + return 0; + + if (WARN_ON(!cfg)) + return -EINVAL; + + if (WARN_ON(ssid >= (1 << master->ssid_bits))) + return -E2BIG; + + ret = arm_smmu_get_cd_mpam(cfg->ops, ssid, partid, pmg); + if (ret) + return ret; + + return 0; +} + +/** + * arm_smmu_get_dev_mpam() - get mpam configuration + * @dev: the device + */ +int arm_smmu_get_dev_mpam(struct device *dev, int ssid, int *partid, int *pmg, + int *s1mpam) +{ + struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv; + struct arm_smmu_device *smmu = master->domain->smmu; + int sid = master->streams->id; + + return arm_smmu_get_mpam(smmu, sid, ssid, partid, pmg, s1mpam); +} +EXPORT_SYMBOL(arm_smmu_get_dev_mpam); + static int arm_smmu_device_probe(struct platform_device *pdev) { int irq, ret; diff --git a/include/linux/ascend_smmu.h b/include/linux/ascend_smmu.h index bd0edd250..a9f449a13 100644 --- a/include/linux/ascend_smmu.h +++ b/include/linux/ascend_smmu.h @@ -6,4 +6,7 @@ extern int arm_smmu_set_dev_mpam(struct device *dev, int ssid, int partid, int pmg, int s1mpam);
+extern int arm_smmu_get_dev_mpam(struct device *dev, int ssid, int *partid, + int *pmg, int *s1mpam); + #endif /* __LINUX_ASCEND_SMMU_H */
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
The user_mpam_en configuration is used to enable/disable whether SMMU mpam configuration will be used. If user_mpam_en is 1, the memory requests across SMMU will not carry the SMMU mpam configuration.
Signed-off-by: Xingang Wang wangxingang5@huawei.com --- drivers/iommu/arm-smmu-v3.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 3 +++ 2 files changed, 40 insertions(+)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 4717c3eb6..77a5dcb55 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -194,6 +194,9 @@ #define MPAMIDR_PMG_MAX GENMASK(23, 16) #define MPAMIDR_PARTID_MAX GENMASK(15, 0)
+#define ARM_SMMU_USER_CFG0 0xe00 +#define ARM_SMMU_USER_MPAM_EN (1UL << 30) + /* Common MSI config fields */ #define MSI_CFG0_ADDR_MASK GENMASK_ULL(51, 2) #define MSI_CFG2_SH GENMASK(5, 4) @@ -4354,6 +4357,40 @@ int arm_smmu_get_dev_mpam(struct device *dev, int ssid, int *partid, int *pmg, } EXPORT_SYMBOL(arm_smmu_get_dev_mpam);
+/** + * arm_smmu_set_dev_user_mpam_en() - set user_mpam_en to smmu user cfg0 + */ +int arm_smmu_set_dev_user_mpam_en(struct device *dev, int user_mpam_en) +{ + struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv; + struct arm_smmu_device *smmu = master->domain->smmu; + u32 reg, __iomem *cfg = smmu->base + ARM_SMMU_USER_CFG0; + + reg = readl_relaxed(cfg); + reg &= ~ARM_SMMU_USER_MPAM_EN; + reg |= FIELD_PREP(ARM_SMMU_USER_MPAM_EN, user_mpam_en); + writel_relaxed(reg, cfg); + + return 0; +} +EXPORT_SYMBOL(arm_smmu_set_dev_user_mpam_en); + +/** + * arm_smmu_get_dev_user_mpam_en() - get user_mpam_en from smmu user cfg0 + */ +int arm_smmu_get_dev_user_mpam_en(struct device *dev, int *user_mpam_en) +{ + struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv; + struct arm_smmu_device *smmu = master->domain->smmu; + u32 reg, __iomem *cfg = smmu->base + ARM_SMMU_USER_CFG0; + + reg = readl_relaxed(cfg); + *user_mpam_en = FIELD_GET(ARM_SMMU_USER_MPAM_EN, reg); + + return 0; +} +EXPORT_SYMBOL(arm_smmu_get_dev_user_mpam_en); + static int arm_smmu_device_probe(struct platform_device *pdev) { int irq, ret; diff --git a/include/linux/ascend_smmu.h b/include/linux/ascend_smmu.h index a9f449a13..c52968e98 100644 --- a/include/linux/ascend_smmu.h +++ b/include/linux/ascend_smmu.h @@ -9,4 +9,7 @@ extern int arm_smmu_set_dev_mpam(struct device *dev, int ssid, int partid, extern int arm_smmu_get_dev_mpam(struct device *dev, int ssid, int *partid, int *pmg, int *s1mpam);
+extern int arm_smmu_set_dev_user_mpam_en(struct device *dev, int user_mpam_en); +extern int arm_smmu_get_dev_user_mpam_en(struct device *dev, int *user_mpam_en); + #endif /* __LINUX_ASCEND_SMMU_H */
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
This add interface to get mpam configuration of accelarators managed by svm. The svm mpam get interface traverse all accelrators, and if all succeed, return the last successful result.
Signed-off-by: Xingang Wang wangxingang5@huawei.com --- drivers/char/svm.c | 84 +++++++++++++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 2 + 2 files changed, 86 insertions(+)
diff --git a/drivers/char/svm.c b/drivers/char/svm.c index f312b7e02..8abad302f 100644 --- a/drivers/char/svm.c +++ b/drivers/char/svm.c @@ -33,6 +33,7 @@ #include <linux/msi.h> #include <linux/acpi.h> #include <linux/share_pool.h> +#include <linux/ascend_smmu.h>
#define SVM_DEVICE_NAME "svm" #define ASID_SHIFT 48 @@ -76,8 +77,11 @@ struct svm_device { struct device *dev; phys_addr_t l2buff; unsigned long l2size; + struct list_head entry; };
+static LIST_HEAD(sdev_list); + struct svm_bind_process { pid_t vpid; u64 ttbr; @@ -146,6 +150,15 @@ struct spalloc { unsigned long flag; };
+struct svm_mpam { +#define SVM_GET_DEV_MPAM (1 << 0) + int flags; + int pasid; + int partid; + int pmg; + int s1mpam; +}; + static struct bus_type svm_bus_type = { .name = "svm_bus", }; @@ -1457,6 +1470,76 @@ int svm_get_pasid(pid_t vpid, int dev_id __maybe_unused) } EXPORT_SYMBOL_GPL(svm_get_pasid);
+static int svm_get_core_mpam(struct device *dev, void *data) +{ + int err = 0; + struct svm_mpam *mpam = data; + + if (mpam->flags & SVM_GET_DEV_MPAM) { + err = arm_smmu_get_dev_mpam(dev, mpam->pasid, &mpam->partid, + &mpam->pmg, &mpam->s1mpam); + if (err) { + dev_err(dev, "get mpam failed, %d\n", err); + return err; + } + } + + return err; +} + +int __svm_get_mpam(struct svm_mpam *mpam) +{ + int err = 0; +#ifdef CONFIG_ACPI + struct core_device *cdev = NULL; +#else + struct svm_device *sdev = NULL; +#endif +#ifdef CONFIG_ACPI + list_for_each_entry(cdev, &child_list, entry) { + err = svm_get_core_mpam(&cdev->dev, mpam); + if (err) + return err; + } +#else + list_for_each_entry(sdev, &sdev_list, entry) { + err = device_for_each_child(sdev->dev, mpam, svm_get_core_mpam); + if (err) + return err; + } +#endif + return 0; +} + +/** + * svm_get_mpam() - get smmu mpam configuration of core device + * @pasid: substream id + * @partid: pointer to partid + * @pmg: pointer to pmg + * @s1mpam: pointer to s1mpam + */ +int svm_get_mpam(int pasid, int *partid, int *pmg, int *s1mpam) +{ + int err = 0; + struct svm_mpam mpam; + + if (!partid || !pmg || !s1mpam) + return -EINVAL; + + mpam.flags = SVM_GET_DEV_MPAM, + mpam.pasid = pasid, + err = __svm_get_mpam(&mpam); + if (err) + return err; + + *partid = mpam.partid; + *pmg = mpam.pmg; + *s1mpam = mpam.s1mpam; + + return 0; +} +EXPORT_SYMBOL_GPL(svm_get_mpam); + static int svm_set_rc(unsigned long __user *arg) { unsigned long addr, size, rc; @@ -2129,6 +2212,7 @@ static int svm_device_probe(struct platform_device *pdev) if (sdev->miscdev.name == NULL) return -ENOMEM;
+ list_add(&sdev->entry, &sdev_list); dev_set_drvdata(dev, sdev); err = misc_register(&sdev->miscdev); if (err) { diff --git a/include/linux/ascend_smmu.h b/include/linux/ascend_smmu.h index c52968e98..a6d205859 100644 --- a/include/linux/ascend_smmu.h +++ b/include/linux/ascend_smmu.h @@ -12,4 +12,6 @@ extern int arm_smmu_get_dev_mpam(struct device *dev, int ssid, int *partid, extern int arm_smmu_set_dev_user_mpam_en(struct device *dev, int user_mpam_en); extern int arm_smmu_get_dev_user_mpam_en(struct device *dev, int *user_mpam_en);
+extern int svm_get_mpam(int pasid, int *partid, int *pmg, int *s1mpam); + #endif /* __LINUX_ASCEND_SMMU_H */
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
This add svm_set_mpam interface in svm module, which traverse all accelerators, and set the mpam configuration in SMMU. If error occurs during the traverse process, mpam configuration of all accelerators will rollback to previous.
Signed-off-by: Xingang Wang wangxingang5@huawei.com --- drivers/char/svm.c | 79 +++++++++++++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 1 + 2 files changed, 80 insertions(+)
diff --git a/drivers/char/svm.c b/drivers/char/svm.c index 8abad302f..169177b17 100644 --- a/drivers/char/svm.c +++ b/drivers/char/svm.c @@ -152,6 +152,7 @@ struct spalloc {
struct svm_mpam { #define SVM_GET_DEV_MPAM (1 << 0) +#define SVM_SET_DEV_MPAM (1 << 1) int flags; int pasid; int partid; @@ -1511,6 +1512,84 @@ int __svm_get_mpam(struct svm_mpam *mpam) return 0; }
+static int svm_set_core_mpam(struct device *dev, void *data) +{ + int err = 0; + struct svm_mpam *mpam = data; + + if (mpam->flags & SVM_SET_DEV_MPAM) { + err = arm_smmu_set_dev_mpam(dev, mpam->pasid, mpam->partid, + mpam->pmg, mpam->s1mpam); + if (err) { + dev_err(dev, "set mpam failed, %d\n", err); + return err; + } + } + + return 0; +} + +static int __svm_set_mpam(struct svm_mpam *mpam) +{ + int err = 0; +#ifdef CONFIG_ACPI + struct core_device *cdev = NULL; +#else + struct svm_device *sdev = NULL; +#endif + +#ifdef CONFIG_ACPI + list_for_each_entry(cdev, &child_list, entry) { + err = svm_set_core_mpam(&cdev->dev, mpam); + if (err) + return err; + } +#else + list_for_each_entry(sdev, &sdev_list, entry) { + err = device_for_each_child(sdev->dev, mpam, svm_set_core_mpam); + if (err) + return err; + } +#endif + + return 0; +} + +/** + * svm_set_mpam() - set mpam configuration of all core device in smmu + * @pasid: substream id + * @partid: mpam partition id + * @pmg: mpam pmg + * @s1mpam: 0 for ste mpam, 1 for cd mpam + */ +int svm_set_mpam(int pasid, int partid, int pmg, int s1mpam) +{ + int err; + struct svm_mpam mpam, old_mpam; + + old_mpam.flags = SVM_GET_DEV_MPAM; + old_mpam.pasid = pasid; + err = __svm_get_mpam(&old_mpam); + if (err) + return err; + + mpam.flags = SVM_SET_DEV_MPAM; + mpam.pasid = pasid; + mpam.partid = partid; + mpam.pmg = pmg; + mpam.s1mpam = s1mpam; + err = __svm_set_mpam(&mpam); + if (err) + goto rollback; + + return 0; + +rollback: + __svm_set_mpam(&old_mpam); + return err; +} +EXPORT_SYMBOL_GPL(svm_set_mpam); + /** * svm_get_mpam() - get smmu mpam configuration of core device * @pasid: substream id diff --git a/include/linux/ascend_smmu.h b/include/linux/ascend_smmu.h index a6d205859..e570acfc8 100644 --- a/include/linux/ascend_smmu.h +++ b/include/linux/ascend_smmu.h @@ -13,5 +13,6 @@ extern int arm_smmu_set_dev_user_mpam_en(struct device *dev, int user_mpam_en); extern int arm_smmu_get_dev_user_mpam_en(struct device *dev, int *user_mpam_en);
extern int svm_get_mpam(int pasid, int *partid, int *pmg, int *s1mpam); +extern int svm_set_mpam(int pasid, int partid, int pmg, int s1mpam);
#endif /* __LINUX_ASCEND_SMMU_H */
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
The user_mpam_en configuration is used to enable/disable mpam for SMMU. If user_mpam_en is set as true, the memory requests across SMMU will carry the mpamid information, otherwise the mpamid will not take effect.
Signed-off-by: Xingang Wang wangxingang5@huawei.com --- drivers/char/svm.c | 64 +++++++++++++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 3 ++ 2 files changed, 67 insertions(+)
diff --git a/drivers/char/svm.c b/drivers/char/svm.c index 169177b17..f6ad1af2c 100644 --- a/drivers/char/svm.c +++ b/drivers/char/svm.c @@ -153,11 +153,14 @@ struct spalloc { struct svm_mpam { #define SVM_GET_DEV_MPAM (1 << 0) #define SVM_SET_DEV_MPAM (1 << 1) +#define SVM_GET_USER_MPAM_EN (1 << 2) +#define SVM_SET_USER_MPAM_EN (1 << 3) int flags; int pasid; int partid; int pmg; int s1mpam; + int user_mpam_en; };
static struct bus_type svm_bus_type = { @@ -1485,6 +1488,14 @@ static int svm_get_core_mpam(struct device *dev, void *data) } }
+ if (mpam->flags & SVM_GET_USER_MPAM_EN) { + err = arm_smmu_get_dev_user_mpam_en(dev, &mpam->user_mpam_en); + if (err) { + dev_err(dev, "set user_mpam_en failed, %d\n", err); + return err; + } + } + return err; }
@@ -1526,6 +1537,14 @@ static int svm_set_core_mpam(struct device *dev, void *data) } }
+ if (mpam->flags & SVM_SET_USER_MPAM_EN) { + err = arm_smmu_set_dev_user_mpam_en(dev, mpam->user_mpam_en); + if (err) { + dev_err(dev, "set user_mpam_en failed, %d\n", err); + return err; + } + } + return 0; }
@@ -1619,6 +1638,51 @@ int svm_get_mpam(int pasid, int *partid, int *pmg, int *s1mpam) } EXPORT_SYMBOL_GPL(svm_get_mpam);
+/** + * svm_set_user_mpam_en() - set user_mpam_en + * @user_mpam_en: 0 for smmu mpam, 1 for user mpam + */ +int svm_set_user_mpam_en(int user_mpam_en) +{ + int err; + struct svm_mpam mpam, old_mpam; + + old_mpam.flags = SVM_GET_USER_MPAM_EN; + err = __svm_get_mpam(&old_mpam); + + mpam.flags = SVM_SET_USER_MPAM_EN, + mpam.user_mpam_en = user_mpam_en, + err = __svm_set_mpam(&mpam); + if (err) + goto rollback; + + return 0; + +rollback: + __svm_set_mpam(&mpam); + return err; +} +EXPORT_SYMBOL_GPL(svm_set_user_mpam_en); + +/** + * svm_set_user_mpam_en() - set user_mpam_en + * @user_mpam_en: pointer to user_mpam_en + */ +int svm_get_user_mpam_en(int *user_mpam_en) +{ + int err; + struct svm_mpam mpam; + + mpam.flags = SVM_GET_USER_MPAM_EN; + err = __svm_get_mpam(&mpam); + if (err) + return err; + + *user_mpam_en = mpam.user_mpam_en; + return 0; +} +EXPORT_SYMBOL_GPL(svm_get_user_mpam_en); + static int svm_set_rc(unsigned long __user *arg) { unsigned long addr, size, rc; diff --git a/include/linux/ascend_smmu.h b/include/linux/ascend_smmu.h index e570acfc8..32241a02a 100644 --- a/include/linux/ascend_smmu.h +++ b/include/linux/ascend_smmu.h @@ -15,4 +15,7 @@ extern int arm_smmu_get_dev_user_mpam_en(struct device *dev, int *user_mpam_en); extern int svm_get_mpam(int pasid, int *partid, int *pmg, int *s1mpam); extern int svm_set_mpam(int pasid, int partid, int pmg, int s1mpam);
+extern int svm_set_user_mpam_en(int user_mpam_en); +extern int svm_get_user_mpam_en(int *user_mpam_en); + #endif /* __LINUX_ASCEND_SMMU_H */
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
The rdt_mon_capable should be enabled when the msmon_mbwu feature is supported, so that the mpam monitor function can be effective.
Signed-off-by: Xingang Wang wangxingang5@huawei.com Signed-off-by: Shaobo Wang bobo.shaobowang@huawei.com --- arch/arm64/kernel/mpam/mpam_setup.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm64/kernel/mpam/mpam_setup.c b/arch/arm64/kernel/mpam/mpam_setup.c index 8fd76dc38..f32ece505 100644 --- a/arch/arm64/kernel/mpam/mpam_setup.c +++ b/arch/arm64/kernel/mpam/mpam_setup.c @@ -335,6 +335,7 @@ static void mpam_resctrl_pick_event_mbm_local(void)
if (mpam_has_feature(mpam_feat_msmon_mbwu, res->class->features)) { res->resctrl_res.mon_capable = true; + rdt_mon_capable = true; mpam_resctrl_events[QOS_L3_MBM_LOCAL_EVENT_ID] = *res; } }
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
The mpam driver controls the allocation of rmid, however there are some ocassions that the partid and pmg of a group might come from elsewhere. This add support for group rmid modify. The sysfs rmid file is set to write accessible, and this add a write interface to accept rmid from user. When the rmid from user is different and valid, update the group with new rmid.
Signed-off-by: Xingang Wang wangxingang5@huawei.com Signed-off-by: Shaobo Wang bobo.shaobowang@huawei.com --- arch/arm64/kernel/mpam/mpam_resctrl.c | 100 +++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kernel/mpam/mpam_resctrl.c b/arch/arm64/kernel/mpam/mpam_resctrl.c index a7fef0ac3..18bb992e7 100644 --- a/arch/arm64/kernel/mpam/mpam_resctrl.c +++ b/arch/arm64/kernel/mpam/mpam_resctrl.c @@ -808,6 +808,11 @@ static void unset_rmid_remap_bmp_occ(unsigned long *bmp) set_bit(0, bmp); }
+static int is_rmid_remap_bmp_bdr_set(unsigned long *bmp, int b) +{ + return (test_bit(b + 1, bmp) == 0) ? 1 : 0; +} + static void rmid_remap_bmp_bdr_set(unsigned long *bmp, int b) { set_bit(b + 1, bmp); @@ -914,11 +919,11 @@ static int rmid_to_partid_pmg(int rmid, int *partid, int *pmg) return 0; }
-static int __rmid_alloc(int partid) +static int __rmid_alloc(int partid, int pmg) { int stride = 0; int partid_sel = 0; - int ret, pmg; + int ret; int rmid[2] = {-1, -1}; unsigned long **cmp, **bmp;
@@ -933,10 +938,19 @@ static int __rmid_alloc(int partid) continue; set_rmid_remap_bmp_occ(*bmp);
- ret = rmid_remap_bmp_alloc_pmg(*bmp); - if (ret < 0) - goto out; - pmg = ret; + if (pmg >= 0) { + if (is_rmid_remap_bmp_bdr_set(*bmp, pmg)) { + ret = -EEXIST; + goto out; + } + rmid_remap_bmp_bdr_clear(*bmp, pmg); + } else { + ret = rmid_remap_bmp_alloc_pmg(*bmp); + if (ret < 0) + goto out; + pmg = ret; + } + rmid[stride] = to_rmid(partid + stride, pmg); if (STRIDE_INC_CHK(stride)) break; @@ -976,7 +990,7 @@ static int __rmid_alloc(int partid)
int rmid_alloc(int partid) { - return __rmid_alloc(partid); + return __rmid_alloc(partid, -1); }
void rmid_free(int rmid) @@ -1851,6 +1865,75 @@ static int resctrl_group_rmid_show(struct kernfs_open_file *of, return ret; }
+static ssize_t resctrl_group_rmid_write(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + struct rdtgroup *rdtgrp; + int ret = 0; + int partid; + int pmg; + int rmid; + struct task_struct *p, *t; + + if (kstrtoint(strstrip(buf), 0, &rmid) || rmid < 0) + return -EINVAL; + + rdtgrp = resctrl_group_kn_lock_live(of->kn); + if (!rdtgrp) { + ret = -ENOENT; + goto unlock; + } + + rdt_last_cmd_clear(); + + ret = rmid_to_partid_pmg(rmid, &partid, &pmg); + if (ret < 0) { + ret = -EINVAL; + goto unlock; + } + + if (rmid == rdtgrp->mon.rmid) + goto unlock; + + if (rdtgrp->type != RDTCTRL_GROUP || + !list_empty(&rdtgrp->mon.crdtgrp_list)) { + rdt_last_cmd_puts("unsupported operation\n"); + goto unlock; + } + + ret = __rmid_alloc(partid, pmg); + if (ret < 0) { + rdt_last_cmd_puts("set rmid failed\n"); + goto unlock; + } + + rmid_free(rdtgrp->mon.rmid); + + rdtgrp->mon.rmid = rmid; + + /* + * we use intpartid as group control, use reqpartid for config + * synchronization and monitor, only update the reqpartid + */ + rdtgrp->closid.reqpartid = partid; + + read_lock(&tasklist_lock); + for_each_process_thread(p, t) { + if (rmid == rdtgrp->mon.rmid) + __resctrl_group_move_task(t, rdtgrp); + } + read_unlock(&tasklist_lock); + + update_closid_rmid(&rdtgrp->cpu_mask, rdtgrp); + +unlock: + resctrl_group_kn_unlock(of->kn); + if (ret) + return ret; + + return nbytes; +} + /* rdtgroup information files for one cache resource. */ static struct rftype res_specific_files[] = { { @@ -1950,8 +2033,9 @@ static struct rftype res_specific_files[] = { }, { .name = "rmid", - .mode = 0444, + .mode = 0644, .kf_ops = &resctrl_group_kf_single_ops, + .write = resctrl_group_rmid_write, .seq_show = resctrl_group_rmid_show, .fflags = RFTYPE_BASE, },
From: Xingang Wang wangxingang5@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2 CVE: NA
-------------------------------------------------
When group rmid changes, as introduced by 6bbf2791b ("mpam: Add support for group rmid modify") the sysfs monitor data file rmid needs to update as well. This add support for updating rmid for monitoring, and then update the group configuration.
Signed-off-by: Xingang Wang wangxingang5@huawei.com Signed-off-by: Shaobo Wang bobo.shaobowang@huawei.com --- arch/arm64/kernel/mpam/mpam_ctrlmon.c | 33 ++++++++++++++++++--------- arch/arm64/kernel/mpam/mpam_resctrl.c | 4 ++++ 2 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/kernel/mpam/mpam_ctrlmon.c b/arch/arm64/kernel/mpam/mpam_ctrlmon.c index a4a298a45..d292a0dbe 100644 --- a/arch/arm64/kernel/mpam/mpam_ctrlmon.c +++ b/arch/arm64/kernel/mpam/mpam_ctrlmon.c @@ -667,20 +667,31 @@ static int resctrl_mkdir_mondata_dom(struct kernfs_node *parent_kn,
md.u.cdp_both_mon = s->cdp_mc_both;
+ if (!parent_kn) { + pr_err("%s: error parent_kn null\n", __func__); + return -EINVAL; + } + snprintf(name, sizeof(name), "mon_%s_%02d", s->name, d->id); - kn = __kernfs_create_file(parent_kn, name, 0444, - GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0, - &kf_mondata_ops, md.priv, NULL, NULL); - if (IS_ERR(kn)) - return PTR_ERR(kn); - - ret = resctrl_group_kn_set_ugid(kn); - if (ret) { - pr_info("%s: create name %s, error ret %d\n", __func__, name, ret); - kernfs_remove(kn); - return ret; + kn = kernfs_find_and_get(parent_kn, name); + if (!kn) { + kn = __kernfs_create_file(parent_kn, name, 0444, + GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0, + &kf_mondata_ops, md.priv, NULL, NULL); + if (IS_ERR(kn)) + return PTR_ERR(kn); + + ret = resctrl_group_kn_set_ugid(kn); + if (ret) { + pr_info("%s: create name %s, error ret %d\n", + __func__, name, ret); + kernfs_remove(kn); + return ret; + } }
+ kn->priv = md.priv; + /* Could we remove the MATCH_* param ? */ rr->mon_write(d, md.priv);
diff --git a/arch/arm64/kernel/mpam/mpam_resctrl.c b/arch/arm64/kernel/mpam/mpam_resctrl.c index 18bb992e7..d5ebd6a96 100644 --- a/arch/arm64/kernel/mpam/mpam_resctrl.c +++ b/arch/arm64/kernel/mpam/mpam_resctrl.c @@ -1926,6 +1926,10 @@ static ssize_t resctrl_group_rmid_write(struct kernfs_open_file *of,
update_closid_rmid(&rdtgrp->cpu_mask, rdtgrp);
+ /* update rmid for mondata */ + resctrl_mkdir_mondata_all_subdir(rdtgrp->mon.mon_data_kn, rdtgrp); + resctrl_update_groups_config(rdtgrp); + unlock: resctrl_group_kn_unlock(of->kn); if (ret)
Hi bobo,
Please help to review this series.
On 2021/9/22 10:05, Wang Xingang wrote:
From: Xingang Wang wangxingang5@huawei.com
This series patches introduce mpam feature for ascend:
- The mpam driver resctrlfs need to add write interface for rmid, so that
the rmid can be configured from userspace.
- Add support to configure SMMU mpam from svm.
bugzilla: https://gitee.com/openeuler/kernel/issues/I49RB2
Xingang Wang (9): iommu/arm-smmu-v3: Add support to configure mpam in STE/CD context iommu/arm-smmu-v3: Add support to get SMMU mpam configuration iommu/arm-smmu-v3: Add support to enable/disable SMMU user_mpam_en svm: Add support to get svm mpam configuration svm: Add support to set svm mpam configuration svm: Add svm_set_user_mpam_en to enable/disable mpam for smmu mpam: enable rdt_mon_capable for mbw monitor mpam: Add support for group rmid modify mpam: update monitor rmid and group configuration
arch/arm64/kernel/mpam/mpam_ctrlmon.c | 33 ++-- arch/arm64/kernel/mpam/mpam_resctrl.c | 104 +++++++++- arch/arm64/kernel/mpam/mpam_setup.c | 1 + drivers/char/svm.c | 227 ++++++++++++++++++++++ drivers/iommu/arm-smmu-v3-context.c | 42 ++++ drivers/iommu/arm-smmu-v3.c | 265 ++++++++++++++++++++++++++ include/linux/ascend_smmu.h | 21 ++ 7 files changed, 674 insertions(+), 19 deletions(-) create mode 100644 include/linux/ascend_smmu.h