提交 d70a672b 编写于 作者: L luochunsheng 提交者: Yang Yingliang

iommu: smmu-v3 support Virtualization feature when 3408iMR/3416iMRraid card exist

hulk inclusion
category: drivers/iommu
bugzilla: 28210
CVE: NA
----------------------------------
arm64 cannot support virtualization when using the 3408iMR/3416iMRraid card.
For solving the problem,we add two fuctions:
1.we prepare init bypass level2 entry for specific devices when smmu uses 2 level streamid entry.
2. we add smmu.bypassdev cmdline to allow SMMU bypass streams for some specific devices.

Signed-off-by: luochunsheng<luochunsheng@huawei.com>
Reviewed-by: NXie XiuQi <xiexiuqi@huawei.com>
Reviewed-by: NZhen Lei <thunder.leizhen@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 67202be0
......@@ -443,4 +443,10 @@ config QCOM_IOMMU
help
Support for IOMMU on certain Qualcomm SoCs.
config SMMU_BYPASS_DEV
bool "SMMU bypass streams for some specific devices"
help
according smmu.bypassdev cmdline, SMMU performs attribute
transformation only,with no address translation.
endif # IOMMU_SUPPORT
......@@ -369,6 +369,42 @@ module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO);
MODULE_PARM_DESC(disable_bypass,
"Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
#ifdef CONFIG_SMMU_BYPASS_DEV
struct smmu_bypass_device {
unsigned short vendor;
unsigned short device;
};
#define MAX_CMDLINE_SMMU_BYPASS_DEV 16
static struct smmu_bypass_device smmu_bypass_devices[MAX_CMDLINE_SMMU_BYPASS_DEV];
static int smmu_bypass_devices_num;
static int __init arm_smmu_bypass_dev_setup(char *str)
{
unsigned short vendor;
unsigned short device;
int ret;
if (!str)
return -EINVAL;
ret = sscanf(str, "%hx:%hx", &vendor, &device);
if (ret != 2)
return -EINVAL;
if (smmu_bypass_devices_num >= MAX_CMDLINE_SMMU_BYPASS_DEV)
return -ERANGE;
smmu_bypass_devices[smmu_bypass_devices_num].vendor = vendor;
smmu_bypass_devices[smmu_bypass_devices_num].device = device;
smmu_bypass_devices_num++;
return 0;
}
__setup("smmu.bypassdev=", arm_smmu_bypass_dev_setup);
#endif
enum pri_resp {
PRI_RESP_DENY = 0,
PRI_RESP_FAIL = 1,
......@@ -2634,6 +2670,30 @@ static void arm_smmu_put_resv_regions(struct device *dev,
kfree(entry);
}
#ifdef CONFIG_SMMU_BYPASS_DEV
static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type)
{
int i;
struct pci_dev *pdev;
if (!dev_is_pci(dev))
return -ERANGE;
pdev = to_pci_dev(dev);
for (i = 0; i < smmu_bypass_devices_num; i++) {
if ((smmu_bypass_devices[i].vendor == pdev->vendor)
&& (smmu_bypass_devices[i].device == pdev->device)) {
dev_info(dev, "device 0x%hx:0x%hx uses identity mapping.",
pdev->vendor, pdev->device);
*type = IOMMU_DOMAIN_IDENTITY;
return 0;
}
}
return -ERANGE;
}
#endif
static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_alloc = arm_smmu_domain_alloc,
......@@ -2660,6 +2720,9 @@ static struct iommu_ops arm_smmu_ops = {
.of_xlate = arm_smmu_of_xlate,
.get_resv_regions = arm_smmu_get_resv_regions,
.put_resv_regions = arm_smmu_put_resv_regions,
#ifdef CONFIG_SMMU_BYPASS_DEV
.device_domain_type = arm_smmu_device_domain_type,
#endif
.pgsize_bitmap = -1UL, /* Restricted during device attach */
};
......@@ -2741,12 +2804,60 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
return 0;
}
#ifdef CONFIG_SMMU_BYPASS_DEV
static void arm_smmu_install_bypass_ste_for_dev(struct arm_smmu_device *smmu,
u32 sid)
{
u64 val;
__le64 *step = arm_smmu_get_step_for_sid(smmu, sid);
if (!step)
return;
val = STRTAB_STE_0_V;
val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
step[0] = cpu_to_le64(val);
step[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
STRTAB_STE_1_SHCFG_INCOMING));
step[2] = 0;
}
static int arm_smmu_prepare_init_l2_strtab(struct device *dev, void *data)
{
u32 sid;
int ret;
unsigned int type;
struct pci_dev *pdev;
struct arm_smmu_device *smmu = (struct arm_smmu_device *)data;
if (arm_smmu_device_domain_type(dev, &type))
return 0;
pdev = to_pci_dev(dev);
sid = PCI_DEVID(pdev->bus->number, pdev->devfn);
if (!arm_smmu_sid_in_range(smmu, sid))
return -ERANGE;
ret = arm_smmu_init_l2_strtab(smmu, sid);
if (ret)
return ret;
arm_smmu_install_bypass_ste_for_dev(smmu, sid);
return 0;
}
#endif
static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
{
void *strtab;
u64 reg;
u32 size, l1size;
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
#ifdef CONFIG_SMMU_BYPASS_DEV
int ret;
#endif
/* Calculate the L1 size, capped to the SIDSIZE. */
size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
......@@ -2776,7 +2887,19 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
reg |= FIELD_PREP(STRTAB_BASE_CFG_SPLIT, STRTAB_SPLIT);
cfg->strtab_base_cfg = reg;
#ifdef CONFIG_SMMU_BYPASS_DEV
ret = arm_smmu_init_l1_strtab(smmu);
if (ret)
return ret;
if (smmu_bypass_devices_num) {
ret = bus_for_each_dev(&pci_bus_type, NULL, (void *)smmu,
arm_smmu_prepare_init_l2_strtab);
}
return ret;
#else
return arm_smmu_init_l1_strtab(smmu);
#endif
}
static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
......
......@@ -1269,7 +1269,9 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev)
const struct iommu_ops *ops = dev->bus->iommu_ops;
struct iommu_group *group;
int ret;
#ifdef CONFIG_SMMU_BYPASS_DEV
unsigned int type = iommu_def_domain_type;
#endif
group = iommu_group_get(dev);
if (group)
return group;
......@@ -1291,8 +1293,19 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev)
if (!group->default_domain) {
struct iommu_domain *dom;
#ifdef CONFIG_SMMU_BYPASS_DEV
/* direct allocate required default domain type for some specific devices. */
if (ops->device_domain_type != NULL) {
if (ops->device_domain_type(dev, &type))
type = iommu_def_domain_type;
}
dom = __iommu_domain_alloc(dev->bus, type);
if (!dom && type != IOMMU_DOMAIN_DMA) {
#else
dom = __iommu_domain_alloc(dev->bus, iommu_def_domain_type);
if (!dom && iommu_def_domain_type != IOMMU_DOMAIN_DMA) {
#endif
dev_warn(dev,
"failed to allocate default IOMMU domain of type %u; falling back to IOMMU_DOMAIN_DMA",
iommu_def_domain_type);
......
......@@ -362,6 +362,12 @@ struct iommu_ops {
int (*page_response)(struct device *dev, struct page_response_msg *msg);
unsigned long pgsize_bitmap;
#ifdef CONFIG_SMMU_BYPASS_DEV
#ifndef __GENKSYMS__
int (*device_domain_type)(struct device *dev, unsigned int *type);
#endif
#endif
};
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册