diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 8b452c9..012b431 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -65,11 +65,12 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
 }
 
 static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
-					   struct pci_dev **dev, u16 segment)
+					   struct list_head *head, u16 segment)
 {
 	struct pci_bus *bus;
 	struct pci_dev *pdev = NULL;
 	struct acpi_dmar_pci_path *path;
+	struct dmar_device *dmar_dev;
 	int count;
 
 	bus = pci_find_bus(segment, scope->bus);
@@ -99,8 +100,7 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 	}
 	if (!pdev) {
 		pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n",
-			segment, scope->bus, path->device, path->function);
-		*dev = NULL;
+			segment, scope->bus, path->dev, path->fn);
 		return 0;
 	}
 	if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \
@@ -111,50 +111,36 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 			pci_name(pdev));
 		return -EINVAL;
 	}
-	*dev = pdev;
+
+	dmar_dev = kzalloc(sizeof(struct dmar_device), GFP_KERNEL);
+	if (!dmar_dev) {
+		pci_dev_put(pdev);
+		return -ENOMEM;
+	}
+	dmar_dev->pdev = pdev;
+	dmar_dev->bus = pdev->bus->number;
+	dmar_dev->devfn = pdev->devfn;
+	dmar_dev->segment = segment;
+
+	list_add_tail(&dmar_dev->list, head);
+
 	return 0;
 }
 
-int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
-				struct pci_dev ***devices, u16 segment)
+int __init dmar_parse_dev_scope(void *start, void *end,
+		struct list_head *head, u16 segment)
 {
 	struct acpi_dmar_device_scope *scope;
-	void * tmp = start;
-	int index;
 	int ret;
 
-	*cnt = 0;
-	while (start < end) {
-		scope = start;
-		if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
-		    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
-			(*cnt)++;
-		else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC &&
-			scope->entry_type != ACPI_DMAR_SCOPE_TYPE_HPET) {
-			pr_warn("Unsupported device scope\n");
-		}
-		start += scope->length;
-	}
-	if (*cnt == 0)
-		return 0;
-
-	*devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL);
-	if (!*devices)
-		return -ENOMEM;
-
-	start = tmp;
-	index = 0;
 	while (start < end) {
 		scope = start;
 		if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
 		    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) {
-			ret = dmar_parse_one_dev_scope(scope,
-				&(*devices)[index], segment);
+			ret = dmar_parse_one_dev_scope(scope, head, segment);
 			if (ret) {
-				kfree(*devices);
 				return ret;
 			}
-			index ++;
 		}
 		start += scope->length;
 	}
@@ -183,6 +169,7 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
 	dmaru->reg_base_addr = drhd->address;
 	dmaru->segment = drhd->segment;
 	dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
+	INIT_LIST_HEAD(&dmaru->devices);
 
 	ret = alloc_iommu(dmaru);
 	if (ret) {
@@ -193,6 +180,19 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
 	return 0;
 }
 
+static void dmar_free(struct dmar_drhd_unit *dmaru)
+{
+	struct dmar_device *dmar_dev, *tmp;
+
+	list_for_each_entry_safe(dmar_dev, tmp,
+			&dmaru->devices, list) {
+		if (dmar_dev->pdev)
+			pci_dev_put(dmar_dev->pdev);
+		list_del(&dmar_dev->list);
+		kfree(dmar_dev);
+	}
+}
+
 static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
 {
 	struct acpi_dmar_hardware_unit *drhd;
@@ -205,11 +205,10 @@ static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
 
 	ret = dmar_parse_dev_scope((void *)(drhd + 1),
 				((void *)drhd) + drhd->header.length,
-				&dmaru->devices_cnt, &dmaru->devices,
-				drhd->segment);
+				&dmaru->devices, drhd->segment);
 	if (ret) {
 		list_del(&dmaru->list);
-		kfree(dmaru);
+		dmar_free(dmaru);
 	}
 	return ret;
 }
@@ -378,14 +377,14 @@ parse_dmar_table(void)
 	return ret;
 }
 
-static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
+static int dmar_pci_device_match(struct list_head *head,
 			  struct pci_dev *dev)
 {
-	int index;
+	struct dmar_device *dmar_dev;
 
 	while (dev) {
-		for (index = 0; index < cnt; index++)
-			if (dev == devices[index])
+		list_for_each_entry(dmar_dev, head, list)
+			if (dev == dmar_dev->pdev)
 				return 1;
 
 		/* Check our parent */
@@ -412,8 +411,7 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
 		    drhd->segment == pci_domain_nr(dev->bus))
 			return dmaru;
 
-		if (dmar_pci_device_match(dmaru->devices,
-					  dmaru->devices_cnt, dev))
+		if (dmar_pci_device_match(&dmaru->devices, dev))
 			return dmaru;
 	}
 
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 43b9bfe..8dd7dbe 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -650,23 +650,23 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
 static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
 {
 	struct dmar_drhd_unit *drhd = NULL;
-	int i;
+	struct dmar_device *dmar_dev;
 
 	for_each_drhd_unit(drhd) {
 		if (drhd->ignored)
 			continue;
 		if (segment != drhd->segment)
 			continue;
-
-		for (i = 0; i < drhd->devices_cnt; i++) {
-			if (drhd->devices[i] &&
-			    drhd->devices[i]->bus->number == bus &&
-			    drhd->devices[i]->devfn == devfn)
+
+		list_for_each_entry(dmar_dev, &drhd->devices, list) {
+			if (dmar_dev->pdev &&
+			    dmar_dev->pdev->bus->number == bus &&
+			    dmar_dev->pdev->devfn == devfn)
 				return drhd->iommu;
-			if (drhd->devices[i] &&
-			    drhd->devices[i]->subordinate &&
-			    drhd->devices[i]->subordinate->number <= bus &&
-			    drhd->devices[i]->subordinate->busn_res.end >= bus)
+			if (dmar_dev->pdev &&
+			    dmar_dev->pdev->subordinate &&
+				dmar_dev->pdev->subordinate->number <= bus &&
+			    dmar_dev->pdev->subordinate->busn_res.end >= bus)
 				return drhd->iommu;
 		}
 
@@ -2335,15 +2335,16 @@ static int domain_add_dev_info(struct dmar_domain *domain,
 static bool device_has_rmrr(struct pci_dev *dev)
 {
 	struct dmar_rmrr_unit *rmrr;
-	int i;
+	struct dmar_device *dmar_dev;
 
 	for_each_rmrr_units(rmrr) {
-		for (i = 0; i < rmrr->devices_cnt; i++) {
+		list_for_each_entry(dmar_dev, &rmrr->devices,
+				list) {
 			/*
 			 * Return TRUE if this RMRR contains the device that
 			 * is passed in.
 			 */
-			if (rmrr->devices[i] == dev)
+			if (dmar_dev->pdev == dev)
 				return true;
 		}
 	}
@@ -2455,7 +2456,7 @@ static int __init init_dmars(void)
 	struct dmar_rmrr_unit *rmrr;
 	struct pci_dev *pdev;
 	struct intel_iommu *iommu;
-	int i, ret;
+	int ret;
 
 	/*
 	 * for each drhd
@@ -2609,8 +2610,10 @@ static int __init init_dmars(void)
 	 */
 	printk(KERN_INFO "IOMMU: Setting RMRR:\n");
 	for_each_rmrr_units(rmrr) {
-		for (i = 0; i < rmrr->devices_cnt; i++) {
-			pdev = rmrr->devices[i];
+		struct dmar_device *dmar_dev;
+		list_for_each_entry(dmar_dev, &rmrr->devices,
+			 list) {
+			pdev = dmar_dev->pdev;
 			/*
 			 * some BIOS lists non-exist devices in DMAR
 			 * table.
@@ -3305,30 +3308,39 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quir
 static void __init init_no_remapping_devices(void)
 {
 	struct dmar_drhd_unit *drhd;
+	int ignore;
 
 	for_each_drhd_unit(drhd) {
 		if (!drhd->include_all) {
-			int i;
-			for (i = 0; i < drhd->devices_cnt; i++)
-				if (drhd->devices[i] != NULL)
+			struct dmar_device *dmar_dev;
+			ignore = 1;
+			list_for_each_entry(dmar_dev, &drhd->devices,
+					list)
+				if (dmar_dev->pdev != NULL) {
+					ignore = 0;
 					break;
+				}
 			/* ignore DMAR unit if no pci devices exist */
-			if (i == drhd->devices_cnt)
+			if (ignore)
 				drhd->ignored = 1;
 		}
 	}
 
 	for_each_drhd_unit(drhd) {
-		int i;
+		struct dmar_device *dmar_dev;
+		int flag = 0;
+
 		if (drhd->ignored || drhd->include_all)
 			continue;
 
-		for (i = 0; i < drhd->devices_cnt; i++)
-			if (drhd->devices[i] &&
-			    !IS_GFX_DEVICE(drhd->devices[i]))
+		list_for_each_entry(dmar_dev, &drhd->devices, list)
+			if (dmar_dev->pdev &&
+			    !IS_GFX_DEVICE(dmar_dev->pdev)) {
+				flag = 1;
 				break;
+			}
 
-		if (i < drhd->devices_cnt)
+		if (flag)
 			continue;
 
 		/* This IOMMU has *only* gfx devices. Either bypass it or
@@ -3337,10 +3349,10 @@ static void __init init_no_remapping_devices(void)
 			intel_iommu_gfx_mapped = 1;
 		} else {
 			drhd->ignored = 1;
-			for (i = 0; i < drhd->devices_cnt; i++) {
-				if (!drhd->devices[i])
+			list_for_each_entry(dmar_dev, &drhd->devices, list) {
+				if (!dmar_dev->pdev)
 					continue;
-				drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+				dmar_dev->pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
 			}
 		}
 	}
@@ -3505,11 +3517,25 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
 	rmrr = (struct acpi_dmar_reserved_memory *)header;
 	rmrru->base_address = rmrr->base_address;
 	rmrru->end_address = rmrr->end_address;
+	INIT_LIST_HEAD(&rmrru->devices);
 
 	dmar_register_rmrr_unit(rmrru);
 	return 0;
 }
 
+static void rmrr_free(struct dmar_rmrr_unit *rmrru)
+{
+	struct dmar_device *dmar_dev, *tmp;
+
+	list_for_each_entry_safe(dmar_dev, tmp,
+			&rmrru->devices, list) {
+		if (dmar_dev->pdev)
+			pci_dev_put(dmar_dev->pdev);
+		list_del(&dmar_dev->list);
+		kfree(dmar_dev);
+	}
+}
+
 static int __init
 rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
 {
@@ -3519,11 +3545,11 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
 	rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
 	ret = dmar_parse_dev_scope((void *)(rmrr + 1),
 		((void *)rmrr) + rmrr->header.length,
-		&rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
+		&rmrru->devices, rmrr->segment);
 
-	if (ret || (rmrru->devices_cnt == 0)) {
+	if (ret || list_empty(&rmrru->devices)) {
 		list_del(&rmrru->list);
-		kfree(rmrru);
+		rmrr_free(rmrru);
 	}
 	return ret;
 }
@@ -3542,12 +3568,26 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 
 	atsru->hdr = hdr;
 	atsru->include_all = atsr->flags & 0x1;
+	INIT_LIST_HEAD(&atsru->devices);
 
 	list_add(&atsru->list, &dmar_atsr_units);
 
 	return 0;
 }
 
+static void atsr_free(struct dmar_atsr_unit *atsru)
+{
+	struct dmar_device *dmar_dev, *tmp;
+
+	list_for_each_entry_safe(dmar_dev, tmp,
+			&atsru->devices, list) {
+		if (dmar_dev->pdev)
+			pci_dev_put(dmar_dev->pdev);
+		list_del(&dmar_dev->list);
+		kfree(dmar_dev);
+	}
+}
+
 static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
 {
 	int rc;
@@ -3559,11 +3599,10 @@ static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
 	atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
 	rc = dmar_parse_dev_scope((void *)(atsr + 1),
 				(void *)atsr + atsr->header.length,
-				&atsru->devices_cnt, &atsru->devices,
-				atsr->segment);
-	if (rc || !atsru->devices_cnt) {
+				&atsru->devices, atsr->segment);
+	if (rc || list_empty(&atsru->devices)) {
 		list_del(&atsru->list);
-		kfree(atsru);
+		atsr_free(atsru);
 	}
 
 	return rc;
@@ -3571,7 +3610,6 @@ static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
 
 int dmar_find_matched_atsr_unit(struct pci_dev *dev)
 {
-	int i;
 	struct pci_bus *bus;
 	struct acpi_dmar_atsr *atsr;
 	struct dmar_atsr_unit *atsru;
@@ -3589,14 +3627,16 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
 found:
 	for (bus = dev->bus; bus; bus = bus->parent) {
 		struct pci_dev *bridge = bus->self;
+		struct dmar_device *dmar_dev;
 
 		if (!bridge || !pci_is_pcie(bridge) ||
 		    pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
 			return 0;
 
 		if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT) {
-			for (i = 0; i < atsru->devices_cnt; i++)
-				if (atsru->devices[i] == bridge)
+			list_for_each_entry(dmar_dev, &atsru->devices,
+					list)
+				if (dmar_dev->pdev == bridge)
 					return 1;
 			break;
 		}
@@ -3641,21 +3681,42 @@ static int device_notifier(struct notifier_block *nb,
 	struct device *dev = data;
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct dmar_domain *domain;
+	struct dmar_device *dmar_dev;
+	struct dmar_drhd_unit *drhd;
 
-	if (iommu_no_mapping(dev))
-		return 0;
-
-	domain = find_domain(pdev);
-	if (!domain)
-		return 0;
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		for_each_drhd_unit(drhd)
+			list_for_each_entry(dmar_dev, &drhd->devices, list)
+				if (dmar_dev->segment == pci_domain_nr(pdev->bus)
+					&& dmar_dev->bus == pdev->bus->number
+					&& dmar_dev->devfn == pdev->devfn)
+					dmar_dev->pdev = pci_dev_get(pdev);
+		break;
+	case BUS_NOTIFY_DEL_DEVICE:
+		for_each_drhd_unit(drhd)
+			list_for_each_entry(dmar_dev, &drhd->devices, list)
+				if (dmar_dev->pdev == pdev) {
+					pci_dev_put(pdev);
+					dmar_dev->pdev = NULL;
+				}
+		break;
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		if (iommu_no_mapping(dev))
+			return 0;
 
-	if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
-		domain_remove_one_dev_info(domain, pdev);
+		domain = find_domain(pdev);
+		if (!domain)
+			return 0;
 
-		if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
-		    !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
-		    list_empty(&domain->devices))
-			domain_exit(domain);
+		if (!iommu_pass_through) {
+			domain_remove_one_dev_info(domain, pdev);
+			if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
+				&& !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)
+				&& list_empty(&domain->devices))
+				domain_exit(domain);
+		}
+		break;
 	}
 
 	return 0;
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index b029d1a..022cb80 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -32,6 +32,17 @@ struct acpi_dmar_header;
 #define DMAR_INTR_REMAP		0x1
 #define DMAR_X2APIC_OPT_OUT	0x2
 
+/* Save pci device id here to help update
+ * (pci_dev *) pointer during device hotplug
+ */
+struct dmar_device {
+	struct list_head list;
+	u8 bus;
+	u8 devfn;
+	u16 segment;
+	struct pci_dev *pdev;
+};
+
 struct intel_iommu;
 #ifdef CONFIG_DMAR_TABLE
 extern struct acpi_table_header *dmar_tbl;
@@ -39,8 +50,7 @@ struct dmar_drhd_unit {
 	struct list_head list;		/* list of drhd units	*/
 	struct  acpi_dmar_header *hdr;	/* ACPI header		*/
 	u64	reg_base_addr;		/* register base address*/
-	struct	pci_dev **devices; 	/* target device array	*/
-	int	devices_cnt;		/* target device count	*/
+	struct list_head devices; /* target device list */
 	u16	segment;		/* PCI domain		*/
 	u8	ignored:1; 		/* ignore drhd		*/
 	u8	include_all:1;
@@ -139,8 +149,7 @@ struct dmar_rmrr_unit {
 	struct acpi_dmar_header *hdr;	/* ACPI header		*/
 	u64	base_address;		/* reserved base address*/
 	u64	end_address;		/* reserved end address */
-	struct pci_dev **devices;	/* target devices */
-	int	devices_cnt;		/* target device count */
+	struct list_head devices; /* target device list */
 };
 
 #define for_each_rmrr_units(rmrr) \
@@ -149,16 +158,15 @@ struct dmar_rmrr_unit {
 struct dmar_atsr_unit {
 	struct list_head list;		/* list of ATSR units */
 	struct acpi_dmar_header *hdr;	/* ACPI header */
-	struct pci_dev **devices;	/* target devices */
-	int devices_cnt;		/* target device count */
+	struct list_head devices;	/* target device list */
 	u8 include_all:1;		/* include all ports */
 };
 
 int dmar_parse_rmrr_atsr_dev(void);
 extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
-extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
-				struct pci_dev ***devices, u16 segment);
+extern int dmar_parse_dev_scope(void *start, void *end,
+				struct list_head *head, u16 segment);
 extern int intel_iommu_init(void);
 #else /* !CONFIG_INTEL_IOMMU: */
 static inline int intel_iommu_init(void) { return -ENODEV; }
