extern void amd_iommu_uninit_devices(void);
 extern void amd_iommu_init_notifier(void);
 extern int amd_iommu_init_api(void);
+extern void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid);
 
 #ifdef CONFIG_AMD_IOMMU_DEBUGFS
 void amd_iommu_debugfs_setup(struct amd_iommu *iommu);
 
 /* kmem_cache to get tables with 128 byte alignement */
 extern struct kmem_cache *amd_iommu_irq_cache;
 
+#define PCI_SBDF_TO_SEGID(sbdf)                (((sbdf) >> 16) & 0xffff)
+#define PCI_SBDF_TO_DEVID(sbdf)                ((sbdf) & 0xffff)
+
 /* Make iterating over all pci segment easier */
 #define for_each_pci_segment(pci_seg) \
        list_for_each_entry((pci_seg), &amd_iommu_pci_seg_list, list)
 };
 
 
+struct amd_iommu;
 struct iommu_domain;
 struct irq_domain;
 struct amd_irte_ops;
         * page table root pointer.
         */
        struct dev_table_entry *dev_table;
+
+       /*
+        * The rlookup iommu table is used to find the IOMMU which is
+        * responsible for a specific device. It is indexed by the PCI
+        * device id.
+        */
+       struct amd_iommu **rlookup_table;
 };
 
 /*
 
        pci_seg->dev_table = NULL;
 }
 
+/* Allocate per PCI segment IOMMU rlookup table. */
+static inline int __init alloc_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+       pci_seg->rlookup_table = (void *)__get_free_pages(
+                                               GFP_KERNEL | __GFP_ZERO,
+                                               get_order(rlookup_table_size));
+       if (pci_seg->rlookup_table == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static inline void free_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+       free_pages((unsigned long)pci_seg->rlookup_table,
+                  get_order(rlookup_table_size));
+       pci_seg->rlookup_table = NULL;
+}
+
+
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
  * write commands to that buffer later and the IOMMU will execute them
 
        if (alloc_dev_table(pci_seg))
                return NULL;
+       if (alloc_rlookup_table(pci_seg))
+               return NULL;
 
        return pci_seg;
 }
 
        for_each_pci_segment_safe(pci_seg, next) {
                list_del(&pci_seg->list);
+               free_rlookup_table(pci_seg);
                free_dev_table(pci_seg);
                kfree(pci_seg);
        }
 
        return dev_table;
 }
 
+static inline u16 get_device_segment(struct device *dev)
+{
+       u16 seg;
+
+       if (dev_is_pci(dev)) {
+               struct pci_dev *pdev = to_pci_dev(dev);
+
+               seg = pci_domain_nr(pdev->bus);
+       } else {
+               u32 devid = get_acpihid_device_id(dev, NULL);
+
+               seg = PCI_SBDF_TO_SEGID(devid);
+       }
+
+       return seg;
+}
+
+/* Writes the specific IOMMU for a device into the PCI segment rlookup table */
+void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid)
+{
+       struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+
+       pci_seg->rlookup_table[devid] = iommu;
+}
+
+static struct amd_iommu *__rlookup_amd_iommu(u16 seg, u16 devid)
+{
+       struct amd_iommu_pci_seg *pci_seg;
+
+       for_each_pci_segment(pci_seg) {
+               if (pci_seg->id == seg)
+                       return pci_seg->rlookup_table[devid];
+       }
+       return NULL;
+}
+
+static struct amd_iommu *rlookup_amd_iommu(struct device *dev)
+{
+       u16 seg = get_device_segment(dev);
+       u16 devid = get_device_id(dev);
+
+       return __rlookup_amd_iommu(seg, devid);
+}
+
 static struct protection_domain *to_pdomain(struct iommu_domain *dom)
 {
        return container_of(dom, struct protection_domain, domain);