qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 2/2] intel-iommu: Basic isolation group provider sup


From: Alex Williamson
Subject: [Qemu-devel] [PATCH 2/2] intel-iommu: Basic isolation group provider support
Date: Mon, 12 Mar 2012 16:33:02 -0600
User-agent: StGIT/0.14.3

Signed-off-by: Alex Williamson <address@hidden>
---

 drivers/iommu/intel-iommu.c |   70 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c9c6053..2e5a709 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -42,6 +42,7 @@
 #include <linux/dmi.h>
 #include <linux/pci-ats.h>
 #include <linux/memblock.h>
+#include <linux/isolation.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
 
@@ -3597,6 +3598,73 @@ static struct notifier_block device_nb = {
        .notifier_call = device_notifier,
 };
 
+static int isolation_notifier(struct notifier_block *nb,
+                             unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       if (iommu_no_mapping(dev) ||
+           !device_to_iommu(pci_domain_nr(pdev->bus),
+                            pdev->bus->number, pdev->devfn))
+               return NOTIFY_DONE;
+
+
+       if (action == ISOLATION_NOTIFY_ADD_DEVICE) {
+               struct device *dma_dev = NULL;
+               struct pci_dev *bridge = pci_find_upstream_pcie_bridge(pdev);
+               struct isolation_group *group;
+
+               if (bridge) {
+                       if (pci_is_pcie(bridge)) {
+                               struct pci_dev *dma_pdev;
+                               dma_pdev = pci_get_domain_bus_and_slot(
+                                       pci_domain_nr(pdev->bus),
+                                       bridge->subordinate->number, 0);
+                               dma_dev = &dma_pdev->dev;
+                       }
+
+                       if (!dma_dev)
+                               dma_dev = &bridge->dev;
+               } else
+                       dma_dev = dev;
+
+               group = to_isolation_group(dma_dev);
+
+               if (!group) {
+                       group = isolation_create_group();
+                       if (IS_ERR(group))
+                               return NOTIFY_BAD;
+
+                       isolation_group_set_iommu_ops(group, &intel_iommu_ops);
+
+                       if (dma_dev != dev)
+                               isolation_group_add_dev(group, dma_dev);
+               }
+
+               if (isolation_group_add_dev(group, dev))
+                       return NOTIFY_BAD;
+
+               return NOTIFY_STOP;
+
+       } else if (action == ISOLATION_NOTIFY_DEL_DEVICE) {
+               struct isolation_group *group = to_isolation_group(dev);
+
+               if (isolation_group_del_dev(dev))
+                       return NOTIFY_BAD;
+
+               isolation_free_group(group);
+
+               return NOTIFY_STOP;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block isolation_nb = {
+       .notifier_call = isolation_notifier,
+};
+
 int __init intel_iommu_init(void)
 {
        int ret = 0;
@@ -3663,6 +3731,8 @@ int __init intel_iommu_init(void)
 
        bus_register_notifier(&pci_bus_type, &device_nb);
 
+       isolation_register_notifier(&pci_bus_type, &isolation_nb);
+
        intel_iommu_enabled = 1;
 
        return 0;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]