提交 ae86d53e 编写于 作者: X Xingang Wang 提交者: Zheng Zengkai

iommu/arm-smmu-v3: Add support to configure mpam in STE/CD context

ascend inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I4L735
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: NXingang Wang <wangxingang5@huawei.com>
Reviewed-by: NZhen Lei <thunder.leizhen@huawei.com>
Reviewed-by: NWeilong Chen <chenweilong@huawei.com>
Acked-by: NXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 9662b1ba
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/acpi_iort.h> #include <linux/acpi_iort.h>
#include <linux/arm-smmu.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/crash_dump.h> #include <linux/crash_dump.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -4081,6 +4082,111 @@ static int arm_smmu_device_domain_type(struct device *dev) ...@@ -4081,6 +4082,111 @@ static int arm_smmu_device_domain_type(struct device *dev)
} }
#endif #endif
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 *master = arm_smmu_find_master(smmu, sid);
struct arm_smmu_domain *domain = master ? master->domain : NULL;
u64 val;
__le64 *ste, *cd;
struct arm_smmu_cmdq_ent prefetch_cmd = {
.opcode = CMDQ_OP_PREFETCH_CFG,
.prefetch = {
.sid = sid,
},
};
if (WARN_ON(!domain))
return -EINVAL;
if (WARN_ON(!domain->s1_cfg.set))
return -EINVAL;
if (WARN_ON(ssid >= (1 << domain->s1_cfg.s1cdmax)))
return -E2BIG;
if (!(smmu->features & ARM_SMMU_FEAT_MPAM))
return -ENODEV;
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;
}
/* 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);
/* 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;
}
/* get cd ptr */
cd = arm_smmu_get_cd_ptr(domain, ssid);
if (s1mpam && WARN_ON(!cd))
return -ENOMEM;
val = le64_to_cpu(cd[5]);
val &= ~CTXDESC_CD_5_PARTID_MASK;
val &= ~CTXDESC_CD_5_PMG_MASK;
val |= FIELD_PREP(CTXDESC_CD_5_PARTID_MASK, partid);
val |= FIELD_PREP(CTXDESC_CD_5_PMG_MASK, pmg);
WRITE_ONCE(cd[5], cpu_to_le64(val));
arm_smmu_sync_cd(domain, ssid, true);
/* 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;
}
static int arm_smmu_device_set_mpam(struct device *dev,
struct arm_smmu_mpam *mpam)
{
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
int ret;
if (WARN_ON(!master) || WARN_ON(!mpam))
return -EINVAL;
if (mpam->flags & ARM_SMMU_DEV_SET_MPAM) {
ret = arm_smmu_set_mpam(master->domain->smmu,
master->streams->id,
mpam->pasid,
mpam->partid,
mpam->pmg,
mpam->s1mpam);
if (ret < 0)
return ret;
}
return 0;
}
static int arm_smmu_device_get_config(struct device *dev, int type, void *data) static int arm_smmu_device_get_config(struct device *dev, int type, void *data)
{ {
switch (type) { switch (type) {
...@@ -4092,6 +4198,8 @@ static int arm_smmu_device_get_config(struct device *dev, int type, void *data) ...@@ -4092,6 +4198,8 @@ static int arm_smmu_device_get_config(struct device *dev, int type, void *data)
static int arm_smmu_device_set_config(struct device *dev, int type, void *data) static int arm_smmu_device_set_config(struct device *dev, int type, void *data)
{ {
switch (type) { switch (type) {
case ARM_SMMU_MPAM:
return arm_smmu_device_set_mpam(dev, data);
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -5210,6 +5318,14 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) ...@@ -5210,6 +5318,14 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
if (FIELD_GET(IDR3_RIL, reg)) if (FIELD_GET(IDR3_RIL, reg))
smmu->features |= ARM_SMMU_FEAT_RANGE_INV; smmu->features |= ARM_SMMU_FEAT_RANGE_INV;
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;
}
/* IDR5 */ /* IDR5 */
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5); reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
......
...@@ -61,6 +61,8 @@ ...@@ -61,6 +61,8 @@
#define IDR3_BBML1 1 #define IDR3_BBML1 1
#define IDR3_BBML2 2 #define IDR3_BBML2 2
#define IDR3_RIL (1 << 10) #define IDR3_RIL (1 << 10)
#define IDR3_MPAM (1 << 7)
#define ARM_SMMU_IDR3_CFG 0x140C
#define ARM_SMMU_IDR5 0x14 #define ARM_SMMU_IDR5 0x14
#define IDR5_STALL_MAX GENMASK(31, 16) #define IDR5_STALL_MAX GENMASK(31, 16)
...@@ -162,6 +164,10 @@ ...@@ -162,6 +164,10 @@
#define ARM_SMMU_PRIQ_IRQ_CFG1 0xd8 #define ARM_SMMU_PRIQ_IRQ_CFG1 0xd8
#define ARM_SMMU_PRIQ_IRQ_CFG2 0xdc #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)
#define ARM_SMMU_IDR6 0x190 #define ARM_SMMU_IDR6 0x190
#define IDR6_LOG2NUMP GENMASK(27, 24) #define IDR6_LOG2NUMP GENMASK(27, 24)
#define IDR6_LOG2NUMQ GENMASK(19, 16) #define IDR6_LOG2NUMQ GENMASK(19, 16)
...@@ -258,6 +264,7 @@ ...@@ -258,6 +264,7 @@
#define STRTAB_STE_1_S1CSH GENMASK_ULL(7, 6) #define STRTAB_STE_1_S1CSH GENMASK_ULL(7, 6)
#define STRTAB_STE_1_PPAR (1UL << 18) #define STRTAB_STE_1_PPAR (1UL << 18)
#define STRTAB_STE_1_S1MPAM (1UL << 26)
#define STRTAB_STE_1_S1STALLD (1UL << 27) #define STRTAB_STE_1_S1STALLD (1UL << 27)
#define STRTAB_STE_1_EATS GENMASK_ULL(29, 28) #define STRTAB_STE_1_EATS GENMASK_ULL(29, 28)
...@@ -290,6 +297,11 @@ ...@@ -290,6 +297,11 @@
#define STRTAB_STE_3_S2TTB_MASK GENMASK_ULL(51, 4) #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)
/* /*
* Context descriptors. * Context descriptors.
* *
...@@ -331,6 +343,9 @@ ...@@ -331,6 +343,9 @@
#define CTXDESC_CD_1_TTB0_MASK GENMASK_ULL(51, 4) #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)
/* /*
* When the SMMU only supports linear context descriptor tables, pick a * When the SMMU only supports linear context descriptor tables, pick a
* reasonable size limit (64kB). * reasonable size limit (64kB).
...@@ -698,6 +713,7 @@ struct arm_smmu_device { ...@@ -698,6 +713,7 @@ struct arm_smmu_device {
#define ARM_SMMU_FEAT_BBML1 (1 << 21) #define ARM_SMMU_FEAT_BBML1 (1 << 21)
#define ARM_SMMU_FEAT_BBML2 (1 << 22) #define ARM_SMMU_FEAT_BBML2 (1 << 22)
#define ARM_SMMU_FEAT_ECMDQ (1 << 23) #define ARM_SMMU_FEAT_ECMDQ (1 << 23)
#define ARM_SMMU_FEAT_MPAM (1 << 24)
u32 features; u32 features;
#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0) #define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0)
...@@ -739,6 +755,9 @@ struct arm_smmu_device { ...@@ -739,6 +755,9 @@ struct arm_smmu_device {
struct rb_root streams; struct rb_root streams;
struct mutex streams_mutex; struct mutex streams_mutex;
unsigned int mpam_partid_max;
unsigned int mpam_pmg_max;
}; };
struct arm_smmu_stream { struct arm_smmu_stream {
......
#ifndef _ARM_SMMU_H_
#define _ARM_SMMU_H_
enum arm_smmu_device_config_type {
ARM_SMMU_MPAM = 0,
};
struct arm_smmu_mpam {
#define ARM_SMMU_DEV_SET_MPAM (1 << 0)
int flags;
int pasid;
int partid;
int pmg;
int s1mpam;
};
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册