linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support
@ 2012-04-03  2:19 Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 01/14] ACPI, PCI: Stop pci devices before acpi_pci_driver remove calling Yinghai Lu
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

During pci root bus hot-add, ioapic and iommu need to be parsed at first.
Using acpi_pci_driver->add to do that.

The patches need to apply to for-pci-root-bus-hotplug and for-x86-irq
and those two patches have been rebased to 3.4-rc1.

could get from
        git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-iommu

Thanks

Yinghai

Yinghai Lu (14):
  ACPI, PCI: Stop pci devices before acpi_pci_driver remove calling
  PCI, x86: Move pci_enable_bridges() down
  ACPI, PCI: Skip extra pci_enable_bridges for non hot-add root
  PCI: set dev_node early for pci_dev
  IOMMU: Update dmar units devices list during hotplug
  IOMMU: Fix tboot force iommu logic
  IOMMU: Don't clean handler data before free_irq()
  IOMMU: iommu_unique_seq_id()
  ACPI: Add acpi_run_dsm()
  IOMMU: Separate free_dmar_iommu from free_iommu
  IOMMU: Add init_dmar_one()
  IOMMU: Add intel_enable_irq_remapping_one()
  IOMMU: Add dmar_parse_one_drhd()
  IOMMU: Add intel iommu irq-remapping and dmar hotplug support

 arch/x86/pci/legacy.c               |    1 +
 drivers/acpi/bus.c                  |   77 +++++++
 drivers/acpi/pci_root.c             |   15 +-
 drivers/acpi/pci_root_hp.c          |    1 +
 drivers/iommu/dmar.c                |  420 +++++++++++++++++++++++++++++++++--
 drivers/iommu/intel-iommu.c         |  167 ++++++++++++--
 drivers/iommu/intel_irq_remapping.c |  172 ++++++++++++++-
 drivers/pci/probe.c                 |    2 +
 drivers/pci/remove.c                |    2 +-
 drivers/pci/setup-bus.c             |    2 -
 include/acpi/acpi_bus.h             |    1 +
 include/linux/acpi.h                |   10 +
 include/linux/dmar.h                |   59 +++++-
 include/linux/pci.h                 |    1 +
 14 files changed, 867 insertions(+), 63 deletions(-)

-- 
1.7.7


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH 01/14] ACPI, PCI: Stop pci devices before acpi_pci_driver remove calling
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 02/14] PCI, x86: Move pci_enable_bridges() down Yinghai Lu
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

During stop pci drivers, it still need to access ioapic and iommu.
So need to make sure those drivers need to be stop at first.

Also change the acpi_pci_drivers remove calling sequence to reverse.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/acpi/pci_root.c |   11 +++++++----
 drivers/pci/remove.c    |    2 +-
 include/linux/pci.h     |    1 +
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 4a7d575..ce662ae 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -657,10 +657,6 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
 
 	mutex_lock(&acpi_pci_root_lock);
 
-	list_for_each_entry(driver, &acpi_pci_drivers, node)
-		if (driver->remove)
-			driver->remove(root->device->handle);
-
 	/* that root bus could be removed already */
 	if (!pci_find_bus(root->segment, root->secondary.start)) {
 		dev_printk(KERN_DEBUG, &device->dev,
@@ -668,6 +664,13 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
 		goto out;
 	}
 
+	/* stop normal pci drivers before we stop ioapic and dmar etc */
+	pci_stop_bus_devices(root->bus);
+
+	list_for_each_entry_reverse(driver, &acpi_pci_drivers, node)
+		if (driver->remove)
+			driver->remove(root->device->handle);
+
 	device_set_run_wake(root->bus->bridge, false);
 	pci_acpi_remove_bus_pm_notifier(device);
 
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 18efb31..f672731 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -118,7 +118,7 @@ static void __pci_remove_bus_devices(struct pci_bus *bus)
 		__pci_remove_bus_device(dev);
 }
 
-static void pci_stop_bus_devices(struct pci_bus *bus)
+void pci_stop_bus_devices(struct pci_bus *bus)
 {
 	struct pci_dev *dev, *tmp;
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8199563..944f49e 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -706,6 +706,7 @@ extern void pci_dev_put(struct pci_dev *dev);
 extern void pci_remove_bus(struct pci_bus *b);
 extern void __pci_remove_bus_device(struct pci_dev *dev);
 extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+void pci_stop_bus_devices(struct pci_bus *bus);
 void pci_stop_and_remove_bus(struct pci_bus *bus);
 extern void pci_stop_bus_device(struct pci_dev *dev);
 void pci_setup_cardbus(struct pci_bus *bus);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 02/14] PCI, x86: Move pci_enable_bridges() down
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 01/14] ACPI, PCI: Stop pci devices before acpi_pci_driver remove calling Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 03/14] ACPI, PCI: Skip extra pci_enable_bridges for non hot-add root Yinghai Lu
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

After we get hot-added ioapic registered.

pci_enable_bridges will try to enable ioapic irq for pci bridge.

So need to move it down.

Or We can move out pcibios_enable_irq() out of pci_enable_device()
and call pcibios_enable_irq in pci_bus_add_devices ?
also will need to move ...
        pcibios_resource_survey_bus(root->bus);
        pci_assign_unassigned_bus_resources(root->bus);
to the start add ....

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/legacy.c   |    1 +
 drivers/acpi/pci_root.c |    3 +++
 drivers/pci/probe.c     |    1 +
 drivers/pci/setup-bus.c |    2 --
 4 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index 8b6048a..5c63bb6 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -101,6 +101,7 @@ void __ref pcibios_root_rescan(void)
 
 		pcibios_resource_survey_bus(bus);
 		pci_assign_unassigned_bus_resources(bus);
+		pci_enable_bridges(bus);
 
 		pci_bus_add_devices(bus);
 	}
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index ce662ae..95b8f22 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -644,6 +644,9 @@ static int acpi_pci_root_start(struct acpi_device *device)
 		if (driver->add)
 			driver->add(device->handle);
 
+	/* need to after hot-added ioapic is registered */
+	pci_enable_bridges(root->bus);
+
 	pci_bus_add_devices(root->bus);
 	mutex_unlock(&acpi_pci_root_lock);
 
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bfa111b..320f38e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2065,6 +2065,7 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
 
 	max = pci_scan_child_bus(bus);
 	pci_assign_unassigned_bus_resources(bus);
+	pci_enable_bridges(bus);
 	pci_bus_add_devices(bus);
 
 	return max;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index d9a5500..20ccd89 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1504,6 +1504,4 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
 	up_read(&pci_bus_sem);
 	__pci_bus_assign_resources(bus, &add_list, NULL);
 	BUG_ON(!list_empty(&add_list));
-
-	pci_enable_bridges(bus);
 }
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 03/14] ACPI, PCI: Skip extra pci_enable_bridges for non hot-add root
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 01/14] ACPI, PCI: Stop pci devices before acpi_pci_driver remove calling Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 02/14] PCI, x86: Move pci_enable_bridges() down Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 04/14] PCI: set dev_node early for pci_dev Yinghai Lu
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

Pre-installed will be handled later, need to skip the one only for hot-added
roots.

Otherwise will get anonying failing message about can not reserve, irq ...

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/acpi/pci_root.c    |    3 ++-
 drivers/acpi/pci_root_hp.c |    1 +
 include/acpi/acpi_bus.h    |    1 +
 3 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 95b8f22..b313125 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -645,7 +645,8 @@ static int acpi_pci_root_start(struct acpi_device *device)
 			driver->add(device->handle);
 
 	/* need to after hot-added ioapic is registered */
-	pci_enable_bridges(root->bus);
+	if (root->hot_added)
+		pci_enable_bridges(root->bus);
 
 	pci_bus_add_devices(root->bus);
 	mutex_unlock(&acpi_pci_root_lock);
diff --git a/drivers/acpi/pci_root_hp.c b/drivers/acpi/pci_root_hp.c
index e16b53d..7d7f809 100644
--- a/drivers/acpi/pci_root_hp.c
+++ b/drivers/acpi/pci_root_hp.c
@@ -86,6 +86,7 @@ static void acpi_root_configure_bridge(acpi_handle handle)
 
 	pcibios_resource_survey_bus(root->bus);
 	pci_assign_unassigned_bus_resources(root->bus);
+	root->hot_added = true;
 }
 
 static void handle_root_bridge_insertion(acpi_handle handle)
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f1c8ca6..333d38c 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -370,6 +370,7 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
+	bool hot_added;
 };
 
 /* helper */
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 04/14] PCI: set dev_node early for pci_dev
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (2 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 03/14] ACPI, PCI: Skip extra pci_enable_bridges for non hot-add root Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 05/14] IOMMU: Update dmar units devices list during hotplug Yinghai Lu
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

otherwise irq_desc for pci bridge with hot-added ioapic can not be
on local node.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/probe.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 320f38e..1eed2fd 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1447,6 +1447,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
 	dev->dev.release = pci_release_dev;
 	pci_dev_get(dev);
 
+	set_dev_node(&dev->dev, pcibus_to_node(bus));
 	dev->dev.dma_mask = &dev->dma_mask;
 	dev->dev.dma_parms = &dev->dma_parms;
 	dev->dev.coherent_dma_mask = 0xffffffffull;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 05/14] IOMMU: Update dmar units devices list during hotplug
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (3 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 04/14] PCI: set dev_node early for pci_dev Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 06/14] IOMMU: Fix tboot force iommu logic Yinghai Lu
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu, David Woodhouse, Vinod Koul,
	Dan Williams, iommu

When do pci remove/rescan on system that have more iommus, got

[  894.089745] Set context mapping for c4:00.0
[  894.110890] mpt2sas3: Allocated physical memory: size(4293 kB)
[  894.112556] mpt2sas3: Current Controller Queue Depth(1883), Max Controller Queue Depth(2144)
[  894.127278] mpt2sas3: Scatter Gather Elements per IO(128)
[  894.361295] DRHD: handling fault status reg 2
[  894.364053] DMAR:[DMA Read] Request device [c4:00.0] fault addr fffbe000
[  894.364056] DMAR:[fault reason 02] Present bit in context entry is cl

It turns out when remove/rescan, pci dev will be freed and will get another
new dev. But drhd units still keep old one... so dmar_find_matched_drhd_unit
will return wrong drhd and iommu for the device that is not on first iommu.

So need to update devices in drhd_units during pci remove/rescan.

Could save domain/bus/device/function aside in the list and according that
info restore new dev to drhd_units later.
Then dmar_find_matched_drdh_unit and device_to_iommu could return right drhd
and iommu.

Add remove_dev_from_drhd/restore_dev_to_drhd functions to do the real work.
call them in device ADD_DEVICE and UNBOUND_DRIVER

Need to do the samething to atsr. (expose dmar_atsr_units and add
atsru->segment)

After patch, will have right iommu for the new dev and will not get DMAR
error anymore.

-v2: add pci_dev_put/pci_dev_get to make refcount consistent.
-v3: fix one left over CONFIG_DMAR
-v4: pass pci_dev *dev in save_dev_dmaru()/get_dev_dmaru() according to Bjorn.
-v5: fix case only have intr-remap enabled.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/dmar.c                |  129 +++++++++++++++++++++++++++++++++++
 drivers/iommu/intel-iommu.c         |   36 +++++++---
 drivers/iommu/intel_irq_remapping.c |   36 ++++++++++-
 include/linux/dmar.h                |   17 +++++
 4 files changed, 206 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index ec01bc7..fde4991 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -455,6 +455,135 @@ fail:
 	return ret;
 }
 
+#ifdef CONFIG_HOTPLUG
+struct dev_dmaru {
+	struct list_head list;
+	void *dmaru;
+	int index;
+	int segment;
+	unsigned char bus;
+	unsigned int devfn;
+};
+
+static int save_dev_dmaru(struct pci_dev *dev, void *dmaru,
+			  int index, struct list_head *lh)
+{
+	struct dev_dmaru *m;
+
+	m = kzalloc(sizeof(*m), GFP_KERNEL);
+	if (!m)
+		return -ENOMEM;
+
+	m->segment = pci_domain_nr(dev->bus);
+	m->bus     = dev->bus->number;
+	m->devfn   = dev->devfn;
+	m->dmaru   = dmaru;
+	m->index   = index;
+
+	list_add(&m->list, lh);
+
+	return 0;
+}
+static void *get_dev_dmaru(struct pci_dev *dev, int *index,
+				struct list_head *lh)
+{
+	int segment = pci_domain_nr(dev->bus);
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	struct dev_dmaru *m;
+	void *dmaru = NULL;
+
+	list_for_each_entry(m, lh, list) {
+		if (m->segment == segment &&
+		    m->bus == bus && m->devfn == devfn) {
+			*index = m->index;
+			dmaru  = m->dmaru;
+			list_del(&m->list);
+			kfree(m);
+			break;
+		}
+	}
+
+	return dmaru;
+}
+
+static LIST_HEAD(saved_dev_drhd_list);
+void remove_dev_from_drhd(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd = NULL;
+	int segment = pci_domain_nr(dev->bus);
+	int i;
+
+	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] == dev) {
+				/* save it at first if it is in drhd */
+				save_dev_dmaru(dev, drhd, i,
+						&saved_dev_drhd_list);
+				/* always remove it */
+				pci_dev_put(dev);
+				drhd->devices[i] = NULL;
+				return;
+			}
+		}
+	}
+}
+void restore_dev_to_drhd(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd = NULL;
+	int i;
+
+	/* find the stored drhd */
+	drhd = get_dev_dmaru(dev, &i, &saved_dev_drhd_list);
+	/* restore that into drhd */
+	if (drhd)
+		drhd->devices[i] = pci_dev_get(dev);
+}
+
+#ifdef CONFIG_INTEL_IOMMU
+static LIST_HEAD(saved_dev_atsr_list);
+void remove_dev_from_atsr(struct pci_dev *dev)
+{
+	struct dmar_atsr_unit *atsr = NULL;
+	int segment = pci_domain_nr(dev->bus);
+	int i;
+
+	for_each_atsr_unit(atsr) {
+		if (segment != atsr->segment)
+			continue;
+
+		for (i = 0; i < atsr->devices_cnt; i++) {
+			if (atsr->devices[i] == dev) {
+				/* save it at first if it is in drhd */
+				save_dev_dmaru(dev, atsr, i,
+						&saved_dev_atsr_list);
+				/* always remove it */
+				pci_dev_put(dev);
+				atsr->devices[i] = NULL;
+				return;
+			}
+		}
+	}
+}
+void restore_dev_to_atsr(struct pci_dev *dev)
+{
+	struct dmar_atsr_unit *atsr = NULL;
+	int i;
+
+	/* find the stored atsr */
+	atsr = get_dev_dmaru(dev, &i, &saved_dev_atsr_list);
+	/* restore that into atsr */
+	if (atsr)
+		atsr->devices[i] = pci_dev_get(dev);
+}
+#endif  /* CONFIG_INTEL_IOMMU */
+
+#endif  /* CONFIG_HOTPLUG */
 
 int __init dmar_table_init(void)
 {
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 430224b..be867e6 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3472,7 +3472,7 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
 	return ret;
 }
 
-static LIST_HEAD(dmar_atsr_units);
+LIST_HEAD(dmar_atsr_units);
 
 int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 {
@@ -3486,6 +3486,7 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 
 	atsru->hdr = hdr;
 	atsru->include_all = atsr->flags & 0x1;
+	atsru->segment = atsr->segment;
 
 	list_add(&atsru->list, &dmar_atsr_units);
 
@@ -3517,16 +3518,13 @@ 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;
 
 	dev = pci_physfn(dev);
 
-	list_for_each_entry(atsru, &dmar_atsr_units, list) {
-		atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
-		if (atsr->segment == pci_domain_nr(dev->bus))
+	list_for_each_entry(atsru, &dmar_atsr_units, list)
+		if (atsru->segment == pci_domain_nr(dev->bus))
 			goto found;
-	}
 
 	return 0;
 
@@ -3586,20 +3584,36 @@ static int device_notifier(struct notifier_block *nb,
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct dmar_domain *domain;
 
-	if (iommu_no_mapping(dev))
+	if (unlikely(dev->bus != &pci_bus_type))
 		return 0;
 
-	domain = find_domain(pdev);
-	if (!domain)
-		return 0;
+	switch (action) {
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		if (iommu_no_mapping(dev))
+			goto out;
+
+		if (iommu_pass_through)
+			goto out;
+
+		domain = find_domain(pdev);
+		if (!domain)
+			goto out;
 
-	if (action == BUS_NOTIFY_UNBOUND_DRIVER && !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);
+out:
+		remove_dev_from_drhd(pdev);
+		remove_dev_from_atsr(pdev);
+
+		break;
+	case BUS_NOTIFY_ADD_DEVICE:
+		restore_dev_to_drhd(pdev);
+		restore_dev_to_atsr(pdev);
+		break;
 	}
 
 	return 0;
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index b4d3950..05ffe20 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -757,12 +757,46 @@ int __init parse_ioapics_under_ir(void)
 	return ir_supported;
 }
 
+static int device_notifier(struct notifier_block *nb,
+				  unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (unlikely(dev->bus != &pci_bus_type))
+		return 0;
+
+	switch (action) {
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		remove_dev_from_drhd(pdev);
+		break;
+	case BUS_NOTIFY_ADD_DEVICE:
+		restore_dev_to_drhd(pdev);
+		break;
+	}
+
+	return 0;
+}
+
+static struct notifier_block device_nb = {
+	.notifier_call = device_notifier,
+};
+
 int __init ir_dev_scope_init(void)
 {
+	int ret;
+
 	if (!irq_remapping_enabled)
 		return 0;
 
-	return dmar_dev_scope_init();
+	ret = dmar_dev_scope_init();
+	if (ret < 0)
+		return ret;
+
+	if (intel_iommu_enabled != 1)
+		bus_register_notifier(&pci_bus_type, &device_nb);
+
+	return ret;
 }
 rootfs_initcall(ir_dev_scope_init);
 
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index b029d1a..305db55 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -131,6 +131,18 @@ extern int dmar_set_interrupt(struct intel_iommu *iommu);
 extern irqreturn_t dmar_fault(int irq, void *dev_id);
 extern int arch_setup_dmar_msi(unsigned int irq);
 
+#ifdef CONFIG_HOTPLUG
+void remove_dev_from_drhd(struct pci_dev *dev);
+void restore_dev_to_drhd(struct pci_dev *dev);
+void remove_dev_from_atsr(struct pci_dev *dev);
+void restore_dev_to_atsr(struct pci_dev *dev);
+#else
+static inline void remove_dev_from_drhd(struct pci_dev *dev) { }
+static inline void restore_dev_to_drhd(struct pci_dev *dev) { }
+static inline void remove_dev_from_atsr(struct pci_dev *dev) { }
+static inline void restore_dev_to_atsr(struct pci_dev *dev) { }
+#endif
+
 #ifdef CONFIG_INTEL_IOMMU
 extern int iommu_detected, no_iommu;
 extern struct list_head dmar_rmrr_units;
@@ -146,14 +158,19 @@ struct dmar_rmrr_unit {
 #define for_each_rmrr_units(rmrr) \
 	list_for_each_entry(rmrr, &dmar_rmrr_units, list)
 
+extern struct list_head dmar_atsr_units;
 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 */
+	u16 segment;			/* PCI domain */
 	u8 include_all:1;		/* include all ports */
 };
 
+#define for_each_atsr_unit(atsr) \
+	list_for_each_entry(atsr, &dmar_atsr_units, list)
+
 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);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 06/14] IOMMU: Fix tboot force iommu logic
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (4 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 05/14] IOMMU: Update dmar units devices list during hotplug Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 07/14] IOMMU: Don't clean handler data before free_irq() Yinghai Lu
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu, David Woodhouse, iommu

Should check dmar_disabled just after tboot_force_iommu.

Otherwise when tboot is not used, and intel_iommu=off, and nointrmap
still get dmar_table_init() called. that will cause some get_device
calling, and it will have some device refcount leaking.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/intel-iommu.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index be867e6..b7e5a7e 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3630,6 +3630,9 @@ int __init intel_iommu_init(void)
 	/* VT-d is required for a TXT/tboot launch, so enforce that */
 	force_on = tboot_force_iommu();
 
+	if (no_iommu || dmar_disabled)
+		return -ENODEV;
+
 	if (dmar_table_init()) {
 		if (force_on)
 			panic("tboot: Failed to initialize DMAR table\n");
@@ -3642,9 +3645,6 @@ int __init intel_iommu_init(void)
 		return 	-ENODEV;
 	}
 
-	if (no_iommu || dmar_disabled)
-		return -ENODEV;
-
 	if (iommu_init_mempool()) {
 		if (force_on)
 			panic("tboot: Failed to initialize iommu memory\n");
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 07/14] IOMMU: Don't clean handler data before free_irq()
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (5 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 06/14] IOMMU: Fix tboot force iommu logic Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 08/14] IOMMU: iommu_unique_seq_id() Yinghai Lu
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

need that in __free_irq.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/iommu/intel-iommu.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index b7e5a7e..4116944 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1308,7 +1308,6 @@ void free_dmar_iommu(struct intel_iommu *iommu)
 		iommu_disable_translation(iommu);
 
 	if (iommu->irq) {
-		irq_set_handler_data(iommu->irq, NULL);
 		/* This will mask the irq */
 		free_irq(iommu->irq, iommu);
 		destroy_irq(iommu->irq);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 08/14] IOMMU: iommu_unique_seq_id()
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (6 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 07/14] IOMMU: Don't clean handler data before free_irq() Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 09/14] ACPI: Add acpi_run_dsm() Yinghai Lu
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

So for hot-remove/hot-add will reuse seq_id.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/iommu/dmar.c |   16 ++++++++++++++--
 1 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index fde4991..043192e 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -707,13 +707,23 @@ int __init detect_intel_iommu(void)
 	return ret ? 1 : -ENODEV;
 }
 
+static DECLARE_BITMAP(iommu_allocated, 1024);
+
+static int iommu_unique_seq_id(void)
+{
+	int id;
+
+	id = find_first_zero_bit(iommu_allocated, 1024);
+	__set_bit(id, iommu_allocated);
+
+	return id;
+}
 
 int alloc_iommu(struct dmar_drhd_unit *drhd)
 {
 	struct intel_iommu *iommu;
 	int map_size;
 	u32 ver;
-	static int iommu_allocated = 0;
 	int agaw = 0;
 	int msagaw = 0;
 
@@ -726,7 +736,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 	if (!iommu)
 		return -ENOMEM;
 
-	iommu->seq_id = iommu_allocated++;
+	iommu->seq_id = iommu_unique_seq_id();
 	sprintf (iommu->name, "dmar%d", iommu->seq_id);
 
 	iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
@@ -790,6 +800,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
  err_unmap:
 	iounmap(iommu->reg);
  error:
+	__clear_bit(iommu->seq_id, iommu_allocated);
 	kfree(iommu);
 	return -1;
 }
@@ -803,6 +814,7 @@ void free_iommu(struct intel_iommu *iommu)
 
 	if (iommu->reg)
 		iounmap(iommu->reg);
+	__clear_bit(iommu->seq_id, iommu_allocated);
 	kfree(iommu);
 }
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 09/14] ACPI: Add acpi_run_dsm()
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (7 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 08/14] IOMMU: iommu_unique_seq_id() Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 10/14] IOMMU: Separate free_dmar_iommu from free_iommu Yinghai Lu
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

Will need to use that get dmar entries for hotplug

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/acpi/bus.c   |   77 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi.h |   10 ++++++
 2 files changed, 87 insertions(+), 0 deletions(-)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index e0960c7..9025dbb 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -520,6 +520,83 @@ out_kfree:
 }
 EXPORT_SYMBOL(acpi_run_osc);
 
+static void acpi_print_dsm_error(acpi_handle handle,
+	struct acpi_dsm_context *context, char *error)
+{
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
+
+	if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer)))
+		printk(KERN_DEBUG "%s for idx %x\n", error, context->func_idx);
+	else {
+		printk(KERN_DEBUG "%s:%s for idx %x\n",
+			(char *)buffer.pointer, error, context->func_idx);
+		kfree(buffer.pointer);
+	}
+}
+
+acpi_status acpi_run_dsm(acpi_handle handle, struct acpi_dsm_context *context)
+{
+	acpi_status status;
+	struct acpi_object_list input;
+	union acpi_object in_params[4];
+	union acpi_object *out_obj;
+	u8 uuid[16];
+	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+
+	if (!context)
+		return AE_ERROR;
+	if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid)))
+		return AE_ERROR;
+	context->ret.length = ACPI_ALLOCATE_BUFFER;
+	context->ret.pointer = NULL;
+
+	/* Setting up input parameters */
+	input.count = 4;
+	input.pointer = in_params;
+	in_params[0].type		= ACPI_TYPE_BUFFER;
+	in_params[0].buffer.length	= 16;
+	in_params[0].buffer.pointer	= uuid;
+	in_params[1].type		= ACPI_TYPE_INTEGER;
+	in_params[1].integer.value	= context->rev;
+	in_params[2].type		= ACPI_TYPE_INTEGER;
+	in_params[2].integer.value	= context->func_idx;
+	in_params[3].type		= ACPI_TYPE_PACKAGE;
+	in_params[3].package.count	= context->func_argc;
+	in_params[3].package.elements	= context->func_argv;
+
+	status = acpi_evaluate_object(handle, "_DSM", &input, &output);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	if (!output.length)
+		return AE_NULL_OBJECT;
+
+	out_obj = output.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		acpi_print_dsm_error(handle, context,
+			"_DSM evaluation returned wrong type");
+		status = AE_TYPE;
+		goto out_kfree;
+	}
+
+	context->ret.length = out_obj->buffer.length;
+	context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL);
+	if (!context->ret.pointer) {
+		status =  AE_NO_MEMORY;
+		goto out_kfree;
+	}
+	memcpy(context->ret.pointer, out_obj->buffer.pointer,
+		context->ret.length);
+	status =  AE_OK;
+
+out_kfree:
+	kfree(output.pointer);
+	if (status != AE_OK)
+		context->ret.pointer = NULL;
+	return status;
+}
+EXPORT_SYMBOL(acpi_run_dsm);
+
 bool osc_sb_apei_support_acked;
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_support(void)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index d78baa7..14ad7d7 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -273,6 +273,16 @@ struct acpi_osc_context {
 
 acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 
+struct acpi_dsm_context {
+	char *uuid_str; /* uuid string */
+	int rev;
+	int func_idx;	/* function index */
+	int func_argc;
+	union acpi_object *func_argv;
+	struct acpi_buffer ret; /* free by caller if success */
+};
+acpi_status acpi_run_dsm(acpi_handle handle, struct acpi_dsm_context *context);
+
 /* platform-wide _OSC bits */
 #define OSC_SB_PAD_SUPPORT		1
 #define OSC_SB_PPC_OST_SUPPORT		2
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 10/14] IOMMU: Separate free_dmar_iommu from free_iommu
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (8 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 09/14] ACPI: Add acpi_run_dsm() Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 11/14] IOMMU: Add init_dmar_one() Yinghai Lu
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

We will need separate two calling later for iommu_remove.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/iommu/dmar.c        |    2 --
 drivers/iommu/intel-iommu.c |    1 +
 2 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 043192e..ea9d210 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -810,8 +810,6 @@ void free_iommu(struct intel_iommu *iommu)
 	if (!iommu)
 		return;
 
-	free_dmar_iommu(iommu);
-
 	if (iommu->reg)
 		iounmap(iommu->reg);
 	__clear_bit(iommu->seq_id, iommu_allocated);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 4116944..662932f 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2613,6 +2613,7 @@ error:
 		if (drhd->ignored)
 			continue;
 		iommu = drhd->iommu;
+		free_dmar_iommu(iommu);
 		free_iommu(iommu);
 	}
 	kfree(g_iommus);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 11/14] IOMMU: Add init_dmar_one()
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (9 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 10/14] IOMMU: Separate free_dmar_iommu from free_iommu Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 12/14] IOMMU: Add intel_enable_irq_remapping_one() Yinghai Lu
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

Will need that for hot added intel iommu

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/iommu/dmar.c        |    4 +-
 drivers/iommu/intel-iommu.c |  123 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 115 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index ea9d210..cd5eee3 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -62,7 +62,7 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
 		list_add(&drhd->list, &dmar_drhd_units);
 }
 
-static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
+static int dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 					   struct pci_dev **dev, u16 segment)
 {
 	struct pci_bus *bus;
@@ -119,7 +119,7 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
 	return 0;
 }
 
-int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
+int dmar_parse_dev_scope(void *start, void *end, int *cnt,
 				struct pci_dev ***devices, u16 segment)
 {
 	struct acpi_dmar_device_scope *scope;
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 662932f..56b886f 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2407,19 +2407,12 @@ static int __init init_dmars(void)
 	 *    initialize and program root entry to not present
 	 * endfor
 	 */
-	for_each_drhd_unit(drhd) {
 		/*
 		 * lock not needed as this is only incremented in the single
 		 * threaded kernel __init code path all other access are read
 		 * only
 		 */
-		if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
-			g_num_of_iommus++;
-			continue;
-		}
-		printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
-			  IOMMU_UNITS_SUPPORTED);
-	}
+	g_num_of_iommus = IOMMU_UNITS_SUPPORTED;
 
 	g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
 			GFP_KERNEL);
@@ -2620,6 +2613,109 @@ error:
 	return ret;
 }
 
+int init_dmar_one(struct dmar_drhd_unit *drhd)
+{
+	struct intel_iommu *iommu;
+	int ret;
+
+	/*
+	 * for each drhd
+	 *    allocate root
+	 *    initialize and program root entry to not present
+	 * endfor
+	 */
+
+	if (drhd->ignored)
+		return 0;
+
+	iommu = drhd->iommu;
+	g_iommus[iommu->seq_id] = iommu;
+
+	ret = iommu_init_domains(iommu);
+	if (ret)
+		goto error;
+
+	/*
+	 * TBD:
+	 * we could share the same root & context tables
+	 * among all IOMMU's. Need to Split it later.
+	 */
+	ret = iommu_alloc_root_entry(iommu);
+	if (ret) {
+		printk(KERN_ERR "IOMMU: allocate root entry failed\n");
+		goto error;
+	}
+
+	/*
+	 * Start from the sane iommu hardware state.
+	 */
+	/*
+	 * If the queued invalidation is already initialized by us
+	 * (for example, while enabling interrupt-remapping) then
+	 * we got the things already rolling from a sane state.
+	 */
+	if (!iommu->qi) {
+		/*
+		 * Clear any previous faults.
+		 */
+		dmar_fault(-1, iommu);
+		/*
+		 * Disable queued invalidation if supported and already enabled
+		 * before OS handover.
+		 */
+		dmar_disable_qi(iommu);
+	}
+
+	if (dmar_enable_qi(iommu)) {
+		/*
+		 * Queued Invalidate not enabled, use Register Based
+		 * Invalidate
+		 */
+		iommu->flush.flush_context = __iommu_flush_context;
+		iommu->flush.flush_iotlb = __iommu_flush_iotlb;
+		printk(KERN_INFO
+		       "IOMMU %d 0x%Lx: using Register based invalidation\n",
+		       iommu->seq_id, (unsigned long long)drhd->reg_base_addr);
+	} else {
+		iommu->flush.flush_context = qi_flush_context;
+		iommu->flush.flush_iotlb = qi_flush_iotlb;
+		printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued invalidation\n",
+		       iommu->seq_id, (unsigned long long)drhd->reg_base_addr);
+	}
+
+	/*
+	 * for each drhd
+	 *   enable fault log
+	 *   global invalidate context cache
+	 *   global invalidate iotlb
+	 *   enable translation
+	 */
+	iommu_flush_write_buffer(iommu);
+
+	ret = dmar_set_interrupt(iommu);
+	if (ret)
+		goto error;
+
+	iommu_set_root_entry(iommu);
+
+	iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
+	iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
+
+	ret = iommu_enable_translation(iommu);
+	if (ret)
+		goto error;
+
+	iommu_disable_protect_mem_regions(iommu);
+
+	return 0;
+error:
+	free_dmar_iommu(iommu);
+	free_iommu(iommu);
+	drhd->iommu = NULL;
+	return ret;
+}
+
+
 /* This takes a number of _MM_ pages, not VTD pages */
 static struct iova *intel_alloc_iova(struct device *dev,
 				     struct dmar_domain *domain,
@@ -3474,7 +3570,8 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
 
 LIST_HEAD(dmar_atsr_units);
 
-int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
+int __dmar_parse_one_atsr(struct acpi_dmar_header *hdr,
+			  struct dmar_atsr_unit **patsru)
 {
 	struct acpi_dmar_atsr *atsr;
 	struct dmar_atsr_unit *atsru;
@@ -3489,11 +3586,17 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 	atsru->segment = atsr->segment;
 
 	list_add(&atsru->list, &dmar_atsr_units);
+	if (patsru)
+		*patsru = atsru;
 
 	return 0;
 }
+int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
+{
+	return __dmar_parse_one_atsr(hdr, NULL);
+}
 
-static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
+int atsr_parse_dev(struct dmar_atsr_unit *atsru)
 {
 	int rc;
 	struct acpi_dmar_atsr *atsr;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 12/14] IOMMU: Add intel_enable_irq_remapping_one()
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (10 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 11/14] IOMMU: Add init_dmar_one() Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 13/14] IOMMU: Add dmar_parse_one_drhd() Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 14/14] IOMMU: Add intel iommu irq-remapping and dmar hotplug support Yinghai Lu
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

Will need that for hot-added iommu interrupt remapping suppor.

Signed-off-by: Yinghai <yinghai@kernel.org>
---
 drivers/iommu/intel_irq_remapping.c |  136 +++++++++++++++++++++++++++++++++--
 1 files changed, 129 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 05ffe20..e20503d 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -214,7 +214,7 @@ static struct intel_iommu *map_ioapic_to_ir(int apic)
 {
 	int i;
 
-	for (i = 0; i < MAX_IO_APICS; i++)
+	for (i = 0; i < ir_ioapic_num; i++)
 		if (ir_ioapic[i].id == apic)
 			return ir_ioapic[i].iommu;
 	return NULL;
@@ -320,7 +320,7 @@ static int set_ioapic_sid(struct irte *irte, int apic)
 	if (!irte)
 		return -1;
 
-	for (i = 0; i < MAX_IO_APICS; i++) {
+	for (i = 0; i < ir_ioapic_num; i++) {
 		if (ir_ioapic[i].id == apic) {
 			sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn;
 			break;
@@ -662,6 +662,7 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
 	struct acpi_dmar_pci_path *path;
 	u8 bus;
 	int count;
+	int i;
 
 	bus = scope->bus;
 	path = (struct acpi_dmar_pci_path *)(scope + 1);
@@ -678,11 +679,16 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
 		path++;
 	}
 
-	ir_ioapic[ir_ioapic_num].bus   = bus;
-	ir_ioapic[ir_ioapic_num].devfn = PCI_DEVFN(path->dev, path->fn);
-	ir_ioapic[ir_ioapic_num].iommu = iommu;
-	ir_ioapic[ir_ioapic_num].id    = scope->enumeration_id;
-	ir_ioapic_num++;
+	for (i = 0; i < ir_ioapic_num; i++)
+		if (!ir_ioapic[i].iommu)
+			break;
+
+	ir_ioapic[i].bus   = bus;
+	ir_ioapic[i].devfn = PCI_DEVFN(path->dev, path->fn);
+	ir_ioapic[i].iommu = iommu;
+	ir_ioapic[i].id    = scope->enumeration_id;
+	if (i == ir_ioapic_num)
+		ir_ioapic_num++;
 }
 
 static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
@@ -1082,6 +1088,122 @@ static int intel_setup_hpet_msi(unsigned int irq, unsigned int id)
 	return 0;
 }
 
+void disable_irq_remapping_one(struct dmar_drhd_unit *drhd)
+{
+	struct intel_iommu *iommu = drhd->iommu;
+	int i;
+
+	/*
+	 * Disable Interrupt-remapping for the DRHD's now.
+	 */
+	if (!ecap_ir_support(iommu->ecap))
+		return;
+
+	iommu_disable_irq_remapping(iommu);
+
+	/* remove it from ir_ioapic */
+	for (i = 0; i < ir_ioapic_num; i++)
+		if (ir_ioapic[i].iommu == iommu) {
+			ir_ioapic[i].iommu = NULL;
+			ir_ioapic[i].id	= 0xff;
+		}
+}
+
+static int parse_ioapics_under_ir_one(struct dmar_drhd_unit *drhd)
+{
+	int ir_supported = 0;
+
+	struct intel_iommu *iommu = drhd->iommu;
+
+	if (ecap_ir_support(iommu->ecap)) {
+		if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu))
+			return -1;
+
+		ir_supported = 1;
+	}
+
+	return ir_supported;
+}
+
+int intel_enable_irq_remapping_one(struct dmar_drhd_unit *drhd)
+{
+	int setup = 0;
+	int eim = 1;
+	int ret;
+	struct intel_iommu *iommu = drhd->iommu;
+
+	if (parse_ioapics_under_ir_one(drhd) != 1) {
+		printk(KERN_INFO "Not enable interrupt remapping\n");
+		return -1;
+	}
+
+	/*
+	 * If the queued invalidation is already initialized,
+	 * shouldn't disable it.
+	 */
+	if (!iommu->qi) {
+		/*
+		 * Clear previous faults.
+		 */
+		dmar_fault(-1, iommu);
+
+		/*
+		 * Disable intr remapping and queued invalidation, if already
+		 * enabled prior to OS handover.
+		 */
+		iommu_disable_irq_remapping(iommu);
+
+		dmar_disable_qi(iommu);
+	}
+
+	/*
+	 * check for the Interrupt-remapping support
+	 */
+
+	if (ecap_ir_support(iommu->ecap))
+		if (eim && !ecap_eim_support(iommu->ecap)) {
+			printk(KERN_INFO
+			"DRHD %Lx: EIM not supported by DRHD, ecap %Lx\n",
+				drhd->reg_base_addr, iommu->ecap);
+			return -1;
+		}
+
+	/*
+	 * Enable queued invalidation for the DRHD's.
+	 */
+	ret = dmar_enable_qi(iommu);
+
+	if (ret) {
+		printk(KERN_ERR
+			"DRHD %Lx: failed to enable queued, invalidation, ecap %Lx, ret %d\n",
+		       drhd->reg_base_addr, iommu->ecap, ret);
+		return -1;
+	}
+
+	/*
+	 * Setup Interrupt-remapping for the DRHD's now.
+	 */
+	if (ecap_ir_support(iommu->ecap)) {
+		if (intel_setup_irq_remapping(iommu, eim))
+			goto error;
+
+		setup = 1;
+	}
+
+	if (!setup)
+		goto error;
+
+	pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
+
+	return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
+
+error:
+	/*
+	 * handle error condition gracefully here!
+	 */
+	return -1;
+}
+
 struct irq_remap_ops intel_irq_remap_ops = {
 	.supported		= intel_irq_remapping_supported,
 	.prepare		= dmar_table_init,
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 13/14] IOMMU: Add dmar_parse_one_drhd()
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (11 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 12/14] IOMMU: Add intel_enable_irq_remapping_one() Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  2012-04-03  2:19 ` [RFC PATCH 14/14] IOMMU: Add intel iommu irq-remapping and dmar hotplug support Yinghai Lu
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

To parse new hot-added iommu dmar entry table

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/iommu/dmar.c |   51 ++++++++++++++++++++++++++++++++++++++++---------
 include/linux/dmar.h |   46 ++++++++++++++++++++++++++++++++++++--------
 2 files changed, 78 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index cd5eee3..f96b8ce 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -171,8 +171,9 @@ int dmar_parse_dev_scope(void *start, void *end, int *cnt,
  * structure which uniquely represent one DMA remapping hardware unit
  * present in the platform
  */
-static int __init
-dmar_parse_one_drhd(struct acpi_dmar_header *header)
+static int
+__dmar_parse_one_drhd(struct acpi_dmar_header *header,
+		      struct dmar_drhd_unit **pdmaru)
 {
 	struct acpi_dmar_hardware_unit *drhd;
 	struct dmar_drhd_unit *dmaru;
@@ -194,10 +195,18 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
 		return ret;
 	}
 	dmar_register_drhd_unit(dmaru);
+	if (pdmaru)
+		*pdmaru = dmaru;
 	return 0;
 }
 
-static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
+static int __init
+dmar_parse_one_drhd(struct acpi_dmar_header *header)
+{
+	return __dmar_parse_one_drhd(header, NULL);
+}
+
+static int dmar_parse_dev(struct dmar_drhd_unit *dmaru)
 {
 	struct acpi_dmar_hardware_unit *drhd;
 	int ret = 0;
@@ -218,10 +227,10 @@ static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
 	return ret;
 }
 
-#ifdef CONFIG_ACPI_NUMA
-static int __init
+static int
 dmar_parse_one_rhsa(struct acpi_dmar_header *header)
 {
+#ifdef CONFIG_ACPI_NUMA
 	struct acpi_dmar_rhsa *rhsa;
 	struct dmar_drhd_unit *drhd;
 
@@ -245,12 +254,11 @@ dmar_parse_one_rhsa(struct acpi_dmar_header *header)
 		dmi_get_system_info(DMI_BIOS_VERSION),
 		dmi_get_system_info(DMI_PRODUCT_VERSION));
 
+#endif
 	return 0;
 }
-#endif
 
-static void __init
-dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
+static void dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
 {
 	struct acpi_dmar_hardware_unit *drhd;
 	struct acpi_dmar_reserved_memory *rmrr;
@@ -364,9 +372,7 @@ parse_dmar_table(void)
 			ret = dmar_parse_one_atsr(entry_header);
 			break;
 		case ACPI_DMAR_HARDWARE_AFFINITY:
-#ifdef CONFIG_ACPI_NUMA
 			ret = dmar_parse_one_rhsa(entry_header);
-#endif
 			break;
 		default:
 			printk(KERN_WARNING PREFIX
@@ -545,6 +551,23 @@ void restore_dev_to_drhd(struct pci_dev *dev)
 		drhd->devices[i] = pci_dev_get(dev);
 }
 
+static void remove_dmaru_from_saved_list(void *drhd,
+				  struct list_head *lh)
+{
+	struct dev_dmaru *m, *n;
+
+	list_for_each_entry_safe(m, n, lh, list) {
+		if (m->dmaru == drhd) {
+			list_del(&m->list);
+			kfree(m);
+		}
+	}
+}
+static void remove_dmaru_from_saved_dev_drhd_list(void *drhd)
+{
+	remove_dmaru_from_saved_list(drhd, &saved_dev_drhd_list);
+}
+
 #ifdef CONFIG_INTEL_IOMMU
 static LIST_HEAD(saved_dev_atsr_list);
 void remove_dev_from_atsr(struct pci_dev *dev)
@@ -581,6 +604,14 @@ void restore_dev_to_atsr(struct pci_dev *dev)
 	if (atsr)
 		atsr->devices[i] = pci_dev_get(dev);
 }
+static void remove_atsru_from_saved_dev_atsru_list(void *atsr)
+{
+	remove_dmaru_from_saved_list(atsr, &saved_dev_atsr_list);
+}
+#else
+static void remove_atsru_from_saved_dev_atsru_list(struct dmar_atsr_unit *atsr)
+{
+}
 #endif  /* CONFIG_INTEL_IOMMU */
 
 #endif  /* CONFIG_HOTPLUG */
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 305db55..79c3898 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -143,6 +143,15 @@ static inline void remove_dev_from_atsr(struct pci_dev *dev) { }
 static inline void restore_dev_to_atsr(struct pci_dev *dev) { }
 #endif
 
+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 */
+	u16 segment;			/* PCI domain */
+	u8 include_all:1;		/* include all ports */
+};
+
 #ifdef CONFIG_INTEL_IOMMU
 extern int iommu_detected, no_iommu;
 extern struct list_head dmar_rmrr_units;
@@ -159,24 +168,19 @@ struct dmar_rmrr_unit {
 	list_for_each_entry(rmrr, &dmar_rmrr_units, list)
 
 extern struct list_head dmar_atsr_units;
-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 */
-	u16 segment;			/* PCI domain */
-	u8 include_all:1;		/* include all ports */
-};
-
 #define for_each_atsr_unit(atsr) \
 	list_for_each_entry(atsr, &dmar_atsr_units, list)
 
 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);
+int __dmar_parse_one_atsr(struct acpi_dmar_header *header,
+			  struct dmar_atsr_unit **patsru);
+int atsr_parse_dev(struct dmar_atsr_unit *atsru);
 extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
 				struct pci_dev ***devices, u16 segment);
 extern int intel_iommu_init(void);
+int init_dmar_one(struct dmar_drhd_unit *drhd);
 #else /* !CONFIG_INTEL_IOMMU: */
 static inline int intel_iommu_init(void) { return -ENODEV; }
 static inline int dmar_parse_one_rmrr(struct acpi_dmar_header *header)
@@ -187,10 +191,34 @@ static inline int dmar_parse_one_atsr(struct acpi_dmar_header *header)
 {
 	return 0;
 }
+static inline int __dmar_parse_one_atsr(struct acpi_dmar_header *header,
+			  struct dmar_atsr_unit **patsru)
+{
+	return 0;
+}
+static inline int atsr_parse_dev(struct dmar_atsr_unit *atsru)
+{
+	return 0;
+}
 static inline int dmar_parse_rmrr_atsr_dev(void)
 {
 	return 0;
 }
+static inline int init_dmar_one(struct dmar_drhd_unit *drhd)
+{
+	return 0;
+}
 #endif /* CONFIG_INTEL_IOMMU */
 
+#ifdef CONFIG_IRQ_REMAP
+void disable_irq_remapping_one(struct dmar_drhd_unit *drhd);
+int intel_enable_irq_remapping_one(struct dmar_drhd_unit *drhd);
+#else
+static inline void disable_irq_remapping_one(struct dmar_drhd_unit *drhd) { }
+static inline int intel_enable_irq_remapping_one(struct dmar_drhd_unit *drhd)
+{
+	return 0;
+}
+#endif
+
 #endif /* __DMAR_H__ */
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 14/14] IOMMU: Add intel iommu irq-remapping and dmar hotplug support
  2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
                   ` (12 preceding siblings ...)
  2012-04-03  2:19 ` [RFC PATCH 13/14] IOMMU: Add dmar_parse_one_drhd() Yinghai Lu
@ 2012-04-03  2:19 ` Yinghai Lu
  13 siblings, 0 replies; 15+ messages in thread
From: Yinghai Lu @ 2012-04-03  2:19 UTC (permalink / raw)
  To: Bjorn Helgaas, Len Brown, Jiang Liu, Suresh Siddha, x86
  Cc: Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, linux-pci,
	linux-kernel, Yinghai Lu

Will use acpi_pci_driver to parse and init them between pci root bus scanning
and start.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/iommu/dmar.c |  218 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 218 insertions(+), 0 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index f96b8ce..918a063 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -36,6 +36,7 @@
 #include <linux/tboot.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <acpi/acpi.h>
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
@@ -1480,3 +1481,220 @@ int __init dmar_ir_support(void)
 	return dmar->flags & 0x1;
 }
 IOMMU_INIT_POST(detect_intel_iommu);
+
+#ifdef CONFIG_HOTPLUG
+static u8 dmar_uuid_str[] = "D8C1A3A6-BE9B-4C9B-91BF-C3CB81FC5DAF";
+
+static int acpi_dmar_dsm_support(acpi_handle handle)
+{
+	int support = 0;
+	struct acpi_dsm_context context = {
+		.uuid_str = dmar_uuid_str,
+		.rev = 1,
+		.func_idx = 0,
+	};
+
+	if (ACPI_SUCCESS(acpi_run_dsm(handle, &context))) {
+		u32 *ret = context.ret.pointer;
+		support = ret[0];
+		kfree(context.ret.pointer);
+	}
+
+	if (support & 1)
+		return support & 0x0e;
+
+	return 0;
+}
+
+static void *acpi_dmar_dsm_run(acpi_handle handle, int idx)
+{
+	struct acpi_dsm_context context = {
+		.uuid_str = dmar_uuid_str,
+		.rev = 1,
+		.func_idx = idx,
+	};
+
+	if (ACPI_SUCCESS(acpi_run_dsm(handle, &context)))
+		return context.ret.pointer;
+
+	return NULL;
+}
+
+static void handle_iommu_add(acpi_handle handle, void **d, void **a)
+{
+	int support;
+	struct acpi_dmar_header *header;
+	struct dmar_drhd_unit *dmaru = NULL;
+	struct dmar_atsr_unit *atsru = NULL;
+
+	*d = NULL;
+	*a = NULL;
+
+	support = acpi_dmar_dsm_support(handle);
+
+	if (!support)
+		return;
+
+	/* DRHD */
+	if (support & (1<<1)) {
+		header = acpi_dmar_dsm_run(handle, 1);
+		dmar_table_print_dmar_entry(header);
+		__dmar_parse_one_drhd(header, &dmaru);
+	}
+
+	if (!dmaru)
+		return;
+
+	/* ATSR */
+	if (support & (1<<2)) {
+		header = acpi_dmar_dsm_run(handle, 2);
+		dmar_table_print_dmar_entry(header);
+		__dmar_parse_one_atsr(header, &atsru);
+	}
+
+	/* RHSA */
+	if (support & (1<<3)) {
+		header = acpi_dmar_dsm_run(handle, 3);
+		dmar_table_print_dmar_entry(header);
+		dmar_parse_one_rhsa(header);
+		kfree(header);
+	}
+
+	/*
+	 *  only need to init intr_remap and dmar for hot-add ones
+	 *  after enable_IR() or pci_iommu_init
+	 */
+	/*
+	 * TODO: handle parsing failure for pre-installed hotplug one
+	 *	Could make every parse_one duplicate the entry table?
+	 */
+	if (irq_remapping_enabled == 1)
+		intel_enable_irq_remapping_one(dmaru);
+	if (irq_remapping_enabled == 1 || intel_iommu_enabled == 1)
+		dmar_parse_dev(dmaru);
+	if (intel_iommu_enabled == 1) {
+		init_dmar_one(dmaru);
+		if (atsru) {
+			header = atsru->hdr;
+			if (atsr_parse_dev(atsru)) {
+				kfree(header);
+				atsru = NULL;
+			}
+			*a = atsru;
+		}
+	}
+	*d = dmaru;
+}
+
+static void handle_iommu_remove(void *drhd, void *atsr)
+{
+	struct dmar_drhd_unit *dmaru = drhd;
+	struct dmar_atsr_unit *atsru = atsr;
+
+	if (!dmaru)
+		return;
+
+	if (irq_remapping_enabled == 1)
+		disable_irq_remapping_one(dmaru);
+	if (intel_iommu_enabled == 1) {
+		free_dmar_iommu(dmaru->iommu);
+		if (atsru) {
+			kfree(atsru->devices);
+			remove_atsru_from_saved_dev_atsru_list(atsru);
+		}
+	}
+	if (irq_remapping_enabled == 1 || intel_iommu_enabled == 1) {
+		kfree(dmaru->devices);
+		remove_dmaru_from_saved_dev_drhd_list(dmaru);
+	}
+	if (atsru) {
+		kfree(atsru->hdr);
+		list_del(&atsru->list);
+		kfree(atsru);
+	}
+	free_iommu(dmaru->iommu);
+	kfree(dmaru->hdr);
+	list_del(&dmaru->list);
+	kfree(dmaru);
+}
+
+struct acpi_pci_iommu {
+	acpi_handle root_handle;
+	void *dmaru;
+	void *atsru;
+	struct list_head list;
+};
+
+static LIST_HEAD(iommu_list);
+static DEFINE_MUTEX(iommu_list_lock);
+
+static acpi_status register_iommu(acpi_handle handle, u32 lvl,
+				  void *context, void **rv)
+{
+	acpi_handle root_handle = context;
+	void *dmaru, *atsru;
+	struct acpi_pci_iommu *iommu;
+
+	handle_iommu_add(handle, &dmaru, &atsru);
+	if (!dmaru)
+		return AE_OK;
+
+	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+	if (!iommu) {
+		printk(KERN_ERR "%s: cannot allocate memory\n", __func__);
+		handle_iommu_remove(dmaru, atsru);
+		return AE_OK;
+	}
+	iommu->root_handle = root_handle;
+	iommu->dmaru = dmaru;
+	iommu->atsru = atsru;
+
+	mutex_lock(&iommu_list_lock);
+	list_add(&iommu->list, &iommu_list);
+	mutex_unlock(&iommu_list_lock);
+
+	return AE_OK;
+}
+
+static int acpi_pci_iommu_add(acpi_handle handle)
+{
+	acpi_status status;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+				     register_iommu, NULL, handle, NULL);
+	if (ACPI_FAILURE(status))
+		printk(KERN_ERR "%s: register_iommu failure - %d", __func__,
+			status);
+
+	return status;
+}
+
+static void acpi_pci_iommu_remove(acpi_handle handle)
+{
+	struct acpi_pci_iommu *iommu, *tmp;
+
+	mutex_lock(&iommu_list_lock);
+	list_for_each_entry_safe(iommu, tmp, &iommu_list, list) {
+		if (handle != iommu->root_handle)
+			continue;
+		list_del(&iommu->list);
+		handle_iommu_remove(iommu->dmaru, iommu->atsru);
+		kfree(iommu);
+	}
+	mutex_unlock(&iommu_list_lock);
+}
+
+static struct acpi_pci_driver acpi_pci_iommu_driver = {
+	.add = acpi_pci_iommu_add,
+	.remove = acpi_pci_iommu_remove,
+};
+
+static int __init acpi_pci_iommu_init(void)
+{
+	acpi_pci_register_driver(&acpi_pci_iommu_driver);
+
+	return 0;
+}
+
+subsys_initcall(acpi_pci_iommu_init);
+#endif
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2012-04-03  2:23 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-03  2:19 [RFC PATCH 00/14] IOMMU: irq-remapping and dmar hotplug support Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 01/14] ACPI, PCI: Stop pci devices before acpi_pci_driver remove calling Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 02/14] PCI, x86: Move pci_enable_bridges() down Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 03/14] ACPI, PCI: Skip extra pci_enable_bridges for non hot-add root Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 04/14] PCI: set dev_node early for pci_dev Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 05/14] IOMMU: Update dmar units devices list during hotplug Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 06/14] IOMMU: Fix tboot force iommu logic Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 07/14] IOMMU: Don't clean handler data before free_irq() Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 08/14] IOMMU: iommu_unique_seq_id() Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 09/14] ACPI: Add acpi_run_dsm() Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 10/14] IOMMU: Separate free_dmar_iommu from free_iommu Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 11/14] IOMMU: Add init_dmar_one() Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 12/14] IOMMU: Add intel_enable_irq_remapping_one() Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 13/14] IOMMU: Add dmar_parse_one_drhd() Yinghai Lu
2012-04-03  2:19 ` [RFC PATCH 14/14] IOMMU: Add intel iommu irq-remapping and dmar hotplug support Yinghai Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).