aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhil Edworthy <phil.edworthy@renesas.com>2016-08-18 16:39:14 +0100
committerRyo Kataoka <ryo.kataoka.wt@renesas.com>2019-03-22 20:50:34 +0900
commita176b24aa5a256f74bdf37bf3fffa1cfde838374 (patch)
tree1d0dd03e7f23bc370994285c51e45cb906452143
parentadc2d8f520e43ae9345d68363087bbd1149f4623 (diff)
downloadrenesas-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.c25
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);