x86, AMD IOMMU: add functions to find IOMMU device resources
authorJoerg Roedel <joerg.roedel@amd.com>
Thu, 26 Jun 2008 19:27:59 +0000 (21:27 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 27 Jun 2008 08:12:17 +0000 (10:12 +0200)
This patch adds functions necessary to find the IOMMU resources for a specific
device.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Cc: iommu@lists.linux-foundation.org
Cc: bhavna.sarathy@amd.com
Cc: Sebastian.Biemueller@amd.com
Cc: robert.richter@amd.com
Cc: joro@8bytes.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/amd_iommu.c

index c43d15dbc8fa0fe1f370246b4e91a96dc37bb79e..47e80b5814bf6bd5e6113a141650e62a3ee3fb44 100644 (file)
@@ -461,3 +461,78 @@ free_dma_dom:
        return NULL;
 }
 
+static struct protection_domain *domain_for_device(u16 devid)
+{
+       struct protection_domain *dom;
+       unsigned long flags;
+
+       read_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       dom = amd_iommu_pd_table[devid];
+       read_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       return dom;
+}
+
+static void set_device_domain(struct amd_iommu *iommu,
+                             struct protection_domain *domain,
+                             u16 devid)
+{
+       unsigned long flags;
+
+       u64 pte_root = virt_to_phys(domain->pt_root);
+
+       pte_root |= (domain->mode & 0x07) << 9;
+       pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | 2;
+
+       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       amd_iommu_dev_table[devid].data[0] = pte_root;
+       amd_iommu_dev_table[devid].data[1] = pte_root >> 32;
+       amd_iommu_dev_table[devid].data[2] = domain->id;
+
+       amd_iommu_pd_table[devid] = domain;
+       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       iommu_queue_inv_dev_entry(iommu, devid);
+
+       iommu->need_sync = 1;
+}
+
+static int get_device_resources(struct device *dev,
+                               struct amd_iommu **iommu,
+                               struct protection_domain **domain,
+                               u16 *bdf)
+{
+       struct dma_ops_domain *dma_dom;
+       struct pci_dev *pcidev;
+       u16 _bdf;
+
+       BUG_ON(!dev || dev->bus != &pci_bus_type || !dev->dma_mask);
+
+       pcidev = to_pci_dev(dev);
+       _bdf = (pcidev->bus->number << 8) | pcidev->devfn;
+
+       if (_bdf >= amd_iommu_last_bdf) {
+               *iommu = NULL;
+               *domain = NULL;
+               *bdf = 0xffff;
+               return 0;
+       }
+
+       *bdf = amd_iommu_alias_table[_bdf];
+
+       *iommu = amd_iommu_rlookup_table[*bdf];
+       if (*iommu == NULL)
+               return 0;
+       dma_dom = (*iommu)->default_dom;
+       *domain = domain_for_device(*bdf);
+       if (*domain == NULL) {
+               *domain = &dma_dom->domain;
+               set_device_domain(*iommu, *domain, *bdf);
+               printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
+                               "device ", (*domain)->id);
+               print_devid(_bdf, 1);
+       }
+
+       return 1;
+}
+