{
        u8 *p = (void *)h, *end = (void *)h;
        struct ivhd_entry *dev;
+       int last_devid = -EINVAL;
 
        u32 ivhd_size = get_ivhd_header_size(h);
 
                case IVHD_DEV_ALL:
                        /* Use maximum BDF value for DEV_ALL */
                        update_last_devid(0xffff);
-                       break;
+                       return 0xffff;
                case IVHD_DEV_SELECT:
                case IVHD_DEV_RANGE_END:
                case IVHD_DEV_ALIAS:
                case IVHD_DEV_EXT_SELECT:
                        /* all the above subfield types refer to device ids */
                        update_last_devid(dev->devid);
+                       if (dev->devid > last_devid)
+                               last_devid = dev->devid;
                        break;
                default:
                        break;
 
        WARN_ON(p != end);
 
-       return 0;
+       return last_devid;
 }
 
 static int __init check_ivrs_checksum(struct acpi_table_header *table)
  * id which we need to handle. This is the first of three functions which parse
  * the ACPI table. So we check the checksum here.
  */
-static int __init find_last_devid_acpi(struct acpi_table_header *table)
+static int __init find_last_devid_acpi(struct acpi_table_header *table, u16 pci_seg)
 {
        u8 *p = (u8 *)table, *end = (u8 *)table;
        struct ivhd_header *h;
+       int last_devid, last_bdf = 0;
 
        p += IVRS_HEADER_LENGTH;
 
        end += table->length;
        while (p < end) {
                h = (struct ivhd_header *)p;
-               if (h->type == amd_iommu_target_ivhd_type) {
-                       int ret = find_last_devid_from_ivhd(h);
-
-                       if (ret)
-                               return ret;
+               if (h->pci_seg == pci_seg &&
+                   h->type == amd_iommu_target_ivhd_type) {
+                       last_devid = find_last_devid_from_ivhd(h);
+
+                       if (last_devid < 0)
+                               return -EINVAL;
+                       if (last_devid > last_bdf)
+                               last_bdf = last_devid;
                }
                p += h->length;
        }
        WARN_ON(p != end);
 
-       return 0;
+       return last_bdf;
 }
 
 /****************************************************************************
 }
 
 /* Allocate PCI segment data structure */
-static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)
+static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id,
+                                         struct acpi_table_header *ivrs_base)
 {
        struct amd_iommu_pci_seg *pci_seg;
+       int last_bdf;
+
+       /*
+        * First parse ACPI tables to find the largest Bus/Dev/Func we need to
+        * handle in this PCI segment. Upon this information the shared data
+        * structures for the PCI segments in the system will be allocated.
+        */
+       last_bdf = find_last_devid_acpi(ivrs_base, id);
+       if (last_bdf < 0)
+               return NULL;
 
        pci_seg = kzalloc(sizeof(struct amd_iommu_pci_seg), GFP_KERNEL);
        if (pci_seg == NULL)
                return NULL;
 
+       pci_seg->last_bdf = last_bdf;
+       DUMP_printk("PCI segment : 0x%0x, last bdf : 0x%04x\n", id, last_bdf);
+
        pci_seg->id = id;
        init_llist_head(&pci_seg->dev_data_list);
        INIT_LIST_HEAD(&pci_seg->unity_map);
        return pci_seg;
 }
 
-static struct amd_iommu_pci_seg *__init get_pci_segment(u16 id)
+static struct amd_iommu_pci_seg *__init get_pci_segment(u16 id,
+                                       struct acpi_table_header *ivrs_base)
 {
        struct amd_iommu_pci_seg *pci_seg;
 
                        return pci_seg;
        }
 
-       return alloc_pci_segment(id);
+       return alloc_pci_segment(id, ivrs_base);
 }
 
 static void __init free_pci_segments(void)
  * together and also allocates the command buffer and programs the
  * hardware. It does NOT enable the IOMMU. This is done afterwards.
  */
-static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
+static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h,
+                                struct acpi_table_header *ivrs_base)
 {
        struct amd_iommu_pci_seg *pci_seg;
        int ret;
 
-       pci_seg = get_pci_segment(h->pci_seg);
+       pci_seg = get_pci_segment(h->pci_seg, ivrs_base);
        if (pci_seg == NULL)
                return -ENOMEM;
        iommu->pci_seg = pci_seg;
                        if (iommu == NULL)
                                return -ENOMEM;
 
-                       ret = init_iommu_one(iommu, h);
+                       ret = init_iommu_one(iommu, h, table);
                        if (ret)
                                return ret;
                }
 }
 
 /* called for unity map ACPI definition */
-static int __init init_unity_map_range(struct ivmd_header *m)
+static int __init init_unity_map_range(struct ivmd_header *m,
+                                      struct acpi_table_header *ivrs_base)
 {
        struct unity_map_entry *e = NULL;
        struct amd_iommu_pci_seg *pci_seg;
        char *s;
 
-       pci_seg = get_pci_segment(m->pci_seg);
+       pci_seg = get_pci_segment(m->pci_seg, ivrs_base);
        if (pci_seg == NULL)
                return -ENOMEM;
 
        while (p < end) {
                m = (struct ivmd_header *)p;
                if (m->flags & (IVMD_FLAG_UNITY_MAP | IVMD_FLAG_EXCL_RANGE))
-                       init_unity_map_range(m);
+                       init_unity_map_range(m, table);
 
                p += m->length;
        }
        amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
        DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type);
 
-       /*
-        * First parse ACPI tables to find the largest Bus/Dev/Func
-        * we need to handle. Upon this information the shared data
-        * structures for the IOMMUs in the system will be allocated
-        */
-       ret = find_last_devid_acpi(ivrs_base);
-       if (ret)
-               goto out;
-
        dev_table_size     = tbl_size(DEV_TABLE_ENTRY_SIZE);
        alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
        rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);