diff options
author | Phil Edworthy <phil.edworthy@renesas.com> | 2016-08-18 16:39:14 +0100 |
---|---|---|
committer | Ryo Kataoka <ryo.kataoka.wt@renesas.com> | 2019-03-22 20:50:34 +0900 |
commit | a176b24aa5a256f74bdf37bf3fffa1cfde838374 (patch) | |
tree | 1d0dd03e7f23bc370994285c51e45cb906452143 | |
parent | adc2d8f520e43ae9345d68363087bbd1149f4623 (diff) | |
download | renesas-bsp-a176b24aa5a256f74bdf37bf3fffa1cfde838374.tar.gz |
iommu/ipmmu-vmsa: Allow PCI Host controller to be a proxy for all connected PCI devices
The IOMMU can't distinguish between different PCI Functions.
Use PCI Host controller as a proxy for all connected PCI devices.
Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
Signed-off-by: Hai Nguyen Pham <hai.pham.ud@renesas.com>
-rw-r--r-- | drivers/iommu/ipmmu-vmsa.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 47de9c5ec188d..b6527bbe296b0 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -26,6 +26,7 @@ #include <linux/sizes.h> #include <linux/slab.h> #include <linux/sys_soc.h> +#include <linux/pci.h> #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) #include <asm/dma-iommu.h> @@ -1240,8 +1241,21 @@ error: return ret; } +static struct device *ipmmu_get_pci_host_device(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_bus *bus = pdev->bus; + + /* Walk up to the root bus to look for PCI Host controller */ + while (!pci_is_root_bus(bus)) + bus = bus->parent; + + return bus->bridge->parent; +} + static int ipmmu_add_device(struct device *dev) { + struct device *root_dev; struct iommu_group *group; struct ipmmu_vmsa_backup *dev_backup; struct iommu_fwspec *fwspec; @@ -1257,6 +1271,17 @@ static int ipmmu_add_device(struct device *dev) if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA)) return ipmmu_init_arm_mapping(dev); + /* + * The IOMMU can't distinguish between different PCI Functions. + * Use PCI Host controller as a proxy for all connected PCI devices + */ + if (dev_is_pci(dev)) { + root_dev = ipmmu_get_pci_host_device(dev); + + if (root_dev->iommu_group) + dev->iommu_group = root_dev->iommu_group; + } + group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) return PTR_ERR(group); |