Re: [PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-04-22 Thread Cho KyongHo
On Tue, 22 Apr 2014 18:53:51 +0530, Shaik Ameer Basha wrote:
> Hi KyongHo Cho,
> 
> 
> 
> On Fri, Mar 14, 2014 at 10:40 AM, Cho KyongHo  wrote:
> > Some master device descriptor like fimc-is which is an abstraction
> > of very complex H/W may have multiple System MMUs. For those devices,
> > the design of the link between System MMU and its master H/W is needed
> > to be reconsidered.
> >
> > A link structure, sysmmu_list_data is introduced that provides a link
> > to master H/W and that has a pointer to the device descriptor of a
> > System MMU. Given a device descriptor of a master H/W, it is possible
> > to traverse all System MMUs that must be controlled along with the
> > master H/W.
> >
> > Signed-off-by: Cho KyongHo 
> > ---
> >  drivers/iommu/exynos-iommu.c |  534 
> > ++
> >  1 file changed, 333 insertions(+), 201 deletions(-)
> >
> > diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
> > index 84ba29a..7489343 100644
> > --- a/drivers/iommu/exynos-iommu.c
> > +++ b/drivers/iommu/exynos-iommu.c
> > @@ -128,6 +128,10 @@
> >  #define __master_clk_disable(data) __clk_gate_ctrl(data, clk_master, 
> > dis)
> >
> 
> [snip]
> 
> > +static int __init __sysmmu_init_master(struct device *dev)
> > +{
> > +   int ret;
> > +   int i = 0;
> > +   struct device_node *node;
> > +
> > +   while ((node = of_parse_phandle(dev->of_node, "mmu-masters", i++))) 
> > {
> > struct platform_device *master = 
> > of_find_device_by_node(node);
> > +   struct exynos_iommu_owner *owner;
> > +   struct sysmmu_list_data *list_data;
> >
> > if (!master) {
> > dev_err(dev, "%s: mmu-master '%s' not found\n",
> > __func__, node->name);
> > -   return -EINVAL;
> > +   ret = -EINVAL;
> > +   goto err;
> > }
> >
> > -   if (master->dev.archdata.iommu != NULL) {
> > -   dev_err(dev, "%s: '%s' is master of other MMU\n",
> > -   __func__, node->name);
> > -   return -EINVAL;
> > +   owner = master->dev.archdata.iommu;
> > +   if (!owner) {
> > +   owner = devm_kzalloc(dev, sizeof(*owner), 
> > GFP_KERNEL);
> > +   if (!owner) {
> > +   dev_err(dev,
> > +   "%s: Failed to allocate owner structure\n",
> > +   __func__);
> > +   ret = -ENOMEM;
> > +   goto err;
> > +   }
> > +
> > +   INIT_LIST_HEAD(&owner->mmu_list);
> > +   INIT_LIST_HEAD(&owner->client);
> > +   owner->dev = &master->dev;
> > +   spin_lock_init(&owner->lock);
> > +
> > +   master->dev.archdata.iommu = owner;
> > }
> >
> > +   list_data = devm_kzalloc(dev, sizeof(*list_data), 
> > GFP_KERNEL);
> > +   if (!list_data) {
> > +   dev_err(dev,
> > +   "%s: Failed to allocate sysmmu_list_data\n",
> > +   __func__);
> > +   ret = -ENOMEM;
> > +   goto err;
> > +   }
> > +
> > +   INIT_LIST_HEAD(&list_data->entry);
> > +   list_data->sysmmu = dev;
> > +
> > /*
> > -* archdata.iommu will be initialized with 
> > exynos_iommu_client
> > -* in sysmmu_hook_driver_register().
> > +* System MMUs are attached in the order of the presence
> > +* in device tree
> >  */
> > -   master->dev.archdata.iommu = dev;
> > +   list_add_tail(&list_data->entry, &owner->mmu_list);
> > }
> >
> > -   data->sysmmu = dev;
> > -   rwlock_init(&data->lock);
> > +   return 0;
> > +err:
> > +   while ((node = of_parse_phandle(dev->of_node, "mmu-masters", i++))) 
> > {
> 
> Don't we need to reinitialize variable 'i' here before using?
> i = 0;
> 

Oh. You are right.

Thanks.

> 
> 
> 
> > +   struct platform_device *master = 
> > of_find_device_by_node(node);
> > +   struct exynos_iommu_owner *owner;
> > +   struct sysmmu_list_data *list_data;
> >
> > -   platform_set_drvdata(pdev, data);
> > +   if (!master)
> > +   continue;
> >
> > -   pm_runtime_enable(dev);
> > -   data->runtime_active = !pm_runtime_enabled(dev);
> > +   owner = master->dev.archdata.iommu;
> > +   if (!owner)
> > +   continue;
> >
> > -   dev_dbg(dev, "Probed and initialized\n");
> > -   return 0;
> > +   

[PATCH] iommu/amd: Fix interrupt remapping for aliased devices

2014-04-22 Thread Alex Williamson
An apparent cut and paste error prevents the correct flags from being
set on the alias device resulting in MSI on conventional PCI devices
failing to work.  This also produces error events from the IOMMU like:

AMD-Vi: Event logged [INVALID_DEVICE_REQUEST device=00:14.4 
address=0x00fdf800 flags=0x0a00]

Where 14.4 is a PCIe-to-PCI bridge with a device behind it trying to
use MSI interrupts.

Signed-off-by: Alex Williamson 
Cc: sta...@vger.kernel.org
---
 drivers/iommu/amd_iommu.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 5113dce..6c0cca5 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4004,7 +4004,7 @@ static struct irq_remap_table *get_irq_table(u16 devid, 
bool ioapic)
iommu_flush_dte(iommu, devid);
if (devid != alias) {
irq_lookup_table[alias] = table;
-   set_dte_irq_entry(devid, table);
+   set_dte_irq_entry(alias, table);
iommu_flush_dte(iommu, alias);
}
 

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [Patch Part3 V1 17/22] pci, ACPI, iommu: enhance pci_root to support DMAR device hotplug

2014-04-22 Thread Rafael J. Wysocki
On Tuesday, April 22, 2014 03:07:28 PM Jiang Liu wrote:
> Finally enhance pci_root driver to support DMAR device hotplug when
> hot-plugging PCI host bridges.
> 
> Signed-off-by: Jiang Liu 
> ---
>  drivers/acpi/pci_root.c |   16 ++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
> index d388f13d48b4..aa8f549869f3 100644
> --- a/drivers/acpi/pci_root.c
> +++ b/drivers/acpi/pci_root.c
> @@ -33,6 +33,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include/* for acpi_hest_init() */
> @@ -511,6 +512,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
>   struct acpi_pci_root *root;
>   acpi_handle handle = device->handle;
>   int no_aspm = 0, clear_aspm = 0;
> + bool hotadd = (system_state != SYSTEM_BOOTING);

The parens are not necessary in the above instruction.

>   root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
>   if (!root)
> @@ -557,6 +559,11 @@ static int acpi_pci_root_add(struct acpi_device *device,
>   strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
>   device->driver_data = root;
>  
> + if (hotadd && dmar_device_hotplug(handle, true)) {
> + result = -ENXIO;
> + goto end;
> + }
> +
>   pr_info(PREFIX "%s [%s] (domain %04x %pR)\n",
>  acpi_device_name(device), acpi_device_bid(device),
>  root->segment, &root->secondary);
> @@ -583,7 +590,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
>   root->segment, (unsigned int)root->secondary.start);
>   device->driver_data = NULL;
>   result = -ENODEV;
> - goto end;
> + goto remove_dmar;
>   }
>  
>   if (clear_aspm) {
> @@ -597,7 +604,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
>   if (device->wakeup.flags.run_wake)
>   device_set_run_wake(root->bus->bridge, true);
>  
> - if (system_state != SYSTEM_BOOTING) {
> + if (hotadd) {
>   pcibios_resource_survey_bus(root->bus);
>   pci_assign_unassigned_root_bus_resources(root->bus);
>   }
> @@ -607,6 +614,9 @@ static int acpi_pci_root_add(struct acpi_device *device,
>   pci_unlock_rescan_remove();
>   return 1;
>  
> +remove_dmar:
> + if (hotadd)
> + dmar_device_hotplug(handle, false);

I suppose that works if dmar_device_hotplug() returned false before?

>  end:
>   kfree(root);
>   return result;
> @@ -625,6 +635,8 @@ static void acpi_pci_root_remove(struct acpi_device 
> *device)
>  
>   pci_remove_root_bus(root->bus);
>  
> + dmar_device_hotplug(device->handle, false);
> +
>   pci_unlock_rescan_remove();
>  
>   kfree(root);
> 

-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-04-22 Thread Shaik Ameer Basha
Hi KyongHo Cho,



On Fri, Mar 14, 2014 at 10:40 AM, Cho KyongHo  wrote:
> Some master device descriptor like fimc-is which is an abstraction
> of very complex H/W may have multiple System MMUs. For those devices,
> the design of the link between System MMU and its master H/W is needed
> to be reconsidered.
>
> A link structure, sysmmu_list_data is introduced that provides a link
> to master H/W and that has a pointer to the device descriptor of a
> System MMU. Given a device descriptor of a master H/W, it is possible
> to traverse all System MMUs that must be controlled along with the
> master H/W.
>
> Signed-off-by: Cho KyongHo 
> ---
>  drivers/iommu/exynos-iommu.c |  534 
> ++
>  1 file changed, 333 insertions(+), 201 deletions(-)
>
> diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
> index 84ba29a..7489343 100644
> --- a/drivers/iommu/exynos-iommu.c
> +++ b/drivers/iommu/exynos-iommu.c
> @@ -128,6 +128,10 @@
>  #define __master_clk_disable(data) __clk_gate_ctrl(data, clk_master, dis)
>

[snip]

> +static int __init __sysmmu_init_master(struct device *dev)
> +{
> +   int ret;
> +   int i = 0;
> +   struct device_node *node;
> +
> +   while ((node = of_parse_phandle(dev->of_node, "mmu-masters", i++))) {
> struct platform_device *master = of_find_device_by_node(node);
> +   struct exynos_iommu_owner *owner;
> +   struct sysmmu_list_data *list_data;
>
> if (!master) {
> dev_err(dev, "%s: mmu-master '%s' not found\n",
> __func__, node->name);
> -   return -EINVAL;
> +   ret = -EINVAL;
> +   goto err;
> }
>
> -   if (master->dev.archdata.iommu != NULL) {
> -   dev_err(dev, "%s: '%s' is master of other MMU\n",
> -   __func__, node->name);
> -   return -EINVAL;
> +   owner = master->dev.archdata.iommu;
> +   if (!owner) {
> +   owner = devm_kzalloc(dev, sizeof(*owner), GFP_KERNEL);
> +   if (!owner) {
> +   dev_err(dev,
> +   "%s: Failed to allocate owner structure\n",
> +   __func__);
> +   ret = -ENOMEM;
> +   goto err;
> +   }
> +
> +   INIT_LIST_HEAD(&owner->mmu_list);
> +   INIT_LIST_HEAD(&owner->client);
> +   owner->dev = &master->dev;
> +   spin_lock_init(&owner->lock);
> +
> +   master->dev.archdata.iommu = owner;
> }
>
> +   list_data = devm_kzalloc(dev, sizeof(*list_data), GFP_KERNEL);
> +   if (!list_data) {
> +   dev_err(dev,
> +   "%s: Failed to allocate sysmmu_list_data\n",
> +   __func__);
> +   ret = -ENOMEM;
> +   goto err;
> +   }
> +
> +   INIT_LIST_HEAD(&list_data->entry);
> +   list_data->sysmmu = dev;
> +
> /*
> -* archdata.iommu will be initialized with exynos_iommu_client
> -* in sysmmu_hook_driver_register().
> +* System MMUs are attached in the order of the presence
> +* in device tree
>  */
> -   master->dev.archdata.iommu = dev;
> +   list_add_tail(&list_data->entry, &owner->mmu_list);
> }
>
> -   data->sysmmu = dev;
> -   rwlock_init(&data->lock);
> +   return 0;
> +err:
> +   while ((node = of_parse_phandle(dev->of_node, "mmu-masters", i++))) {

Don't we need to reinitialize variable 'i' here before using?
i = 0;

Regards,
Shaik Ameer Basha



> +   struct platform_device *master = of_find_device_by_node(node);
> +   struct exynos_iommu_owner *owner;
> +   struct sysmmu_list_data *list_data;
>
> -   platform_set_drvdata(pdev, data);
> +   if (!master)
> +   continue;
>
> -   pm_runtime_enable(dev);
> -   data->runtime_active = !pm_runtime_enabled(dev);
> +   owner = master->dev.archdata.iommu;
> +   if (!owner)
> +   continue;
>
> -   dev_dbg(dev, "Probed and initialized\n");
> -   return 0;
> +   for_each_sysmmu_list(owner->dev, list_data) {
> +   if (list_data->sysmmu == dev) {
> +   list_del(&list_data->entry);
> +   kfree(list_data);
> +   break;
> +   }
> +   }
> +   }
> +
> +   return ret;
>  }
>


Re: [PATCH v11 12/27] ARM: dts: Add description of System MMU of Exynos SoCs

2014-04-22 Thread Cho KyongHo
On Sun, 20 Apr 2014 15:25:59 +0530, Shaik Ameer Basha wrote:
> Hi KyongHo Cho,
> 
> Please find the comments inline.
> 
> On Fri, Mar 14, 2014 at 10:36 AM, Cho KyongHo  wrote:
> > This patch adds dts entries for the System MMU devices found on
> > Exynos4 and Exynos5 SoC series and the System MMU binding
> > documentation.
> >
> > CC: Rob Herring 
> > CC: Sylwester Nawrocki 
> > Signed-off-by: Cho KyongHo 
> > ---
> >  .../bindings/iommu/samsung,exynos4210-sysmmu.txt   |   86 +++
> >  arch/arm/boot/dts/exynos4.dtsi |  107 
> >  arch/arm/boot/dts/exynos4210.dtsi  |   23 +-
> >  arch/arm/boot/dts/exynos4x12.dtsi  |   77 +-
> >  arch/arm/boot/dts/exynos5250.dtsi  |  266 
> > +++-
> >  arch/arm/boot/dts/exynos5420.dtsi  |  205 ++-
> >  6 files changed, 758 insertions(+), 6 deletions(-)
> >  create mode 100644 
> > Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
> >
> > diff --git 
> > a/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt 
> > b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
> > new file mode 100644
> > index 000..e4417bb
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
> > @@ -0,0 +1,86 @@
> > +Samsung Exynos IOMMU H/W, System MMU (System Memory Management Unit)
> > +
> > +Samsung's Exynos architecture contains System MMUs that enables scattered
> > +physical memory chunks visible as a contiguous region to DMA-capable 
> > peripheral
> > +devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth.
> > +
> 
> [snip]
> 
> 
> > diff --git a/arch/arm/boot/dts/exynos5250.dtsi 
> > b/arch/arm/boot/dts/exynos5250.dtsi
> > index 8f6300f..df336ea 100644
> > --- a/arch/arm/boot/dts/exynos5250.dtsi
> > +++ b/arch/arm/boot/dts/exynos5250.dtsi
> > @@ -80,6 +80,16 @@
> > reg = <0x10044040 0x20>;
> > };
> >
> > +   pd_isp: isp-power-domain@0x10044020 {
> > +   compatible = "samsung,exynos4210-pd";
> > +   reg = <0x10044020 0x20>;
> > +   };
> > +
> > +   pd_disp1: disp1-power-domain@0x100440A0 {
> > +   compatible = "samsung,exynos4210-pd";
> > +   reg = <0x100440A0 0x20>;
> > +   };
> > +
> > clock: clock-controller@1001 {
> > compatible = "samsung,exynos5250-clock";
> > reg = <0x1001 0x3>;
> > @@ -679,7 +689,7 @@
> > "sclk_hdmiphy", "mout_hdmi";
> > };
> >
> > -   mixer {
> > +   mixer: mixer {
> > compatible = "samsung,exynos5250-mixer";
> > reg = <0x1445 0x1>;
> > interrupts = <0 94 0>;
> > @@ -700,7 +710,7 @@
> > phy-names = "dp";
> > };
> >
> > -   fimd@1440 {
> > +   fimd: fimd@1440 {
> > clocks = <&clock 133>, <&clock 339>;
> > clock-names = "sclk_fimd", "fimd";
> > };
> > @@ -715,4 +725,256 @@
> > io-channel-ranges;
> > status = "disabled";
> > };
> > +
> > +   sysmmu_g2d: sysmmu@10A6 {
> > +   compatible = "samsung,sysmmu-v1";
> > +   reg = <0x10A6 0x1000>;
> > +   interrupt-parent = <&combiner>;
> > +   interrupts = <24 5>;
> > +   clock-names = "sysmmu";
> > +   clocks = <&clock 361>;
> > +   };
> > +
> > +   sysmmu_mfc_r: sysmmu@1120 {
> > +   compatible = "samsung,sysmmu-v2";
> > +   reg = <0x1120 0x1000>;
> > +   interrupt-parent = <&combiner>;
> > +   interrupts = <6 2>;
> > +   clock-names = "sysmmu", "master";
> > +   clocks = <&clock 268>, <&clock 266>;
> 
> Add mmu-masters...
> mmu-masters = <&mfc>;
> 

Ok.

> > +   samsung,power-domain = <&pd_mfc>;
> > +   };
> > +
> > +   sysmmu_mfc_l: sysmmu@1121 {
> > +   compatible = "samsung,sysmmu-v2";
> > +   reg = <0x1121 0x1000>;
> > +   interrupt-parent = <&combiner>;
> > +   interrupts = <8 5>;
> > +   clock-names = "sysmmu", "master";
> > +   clocks = <&clock 267>, <&clock 266>;
> 
> Add mmu-masters...
> mmu-masters = <&mfc>;
> 

OK.

> 
> > +   samsung,power-domain = <&pd_mfc>;
> > +   };
> > +
> > +   sysmmu_rotator: sysmmu@11D4 {
> > +   compatible = "samsung,sysmmu-v1";
> > +   reg = <0x11D4 0x1000>;
> > +   interrupt-parent = <&combiner>;
> > +   interrupts = <4 0>;
> > +   clock-names = "sysmmu";
> > +   clocks = <&clock 272>;
> > +   };
> > +
> 
> [snip]
> 
> >  };
> > diff --git a/arch/arm/boot/dts/exynos5420.dtsi 
> > b/arch/arm

Re: [PATCH 0/9] Renesas ipmmu-vmsa: Miscellaneous cleanups and fixes

2014-04-22 Thread Laurent Pinchart
Hi Will,

On Tuesday 22 April 2014 12:34:23 Will Deacon wrote:
> On Mon, Apr 21, 2014 at 03:13:00PM +0100, Laurent Pinchart wrote:
> > Hello,
> 
> Hi Laurent,
> 
> > This patch set cleans up and fixes small issues in the ipmmu-vmsa driver.
> > The patches are based on top of "[PATCH v3] iommu: Add driver for Renesas
> > VMSA-compatible IPMMU" that adds the ipmmu-vmsa driver.
> > 
> > The most interesting part of this series is the rewrite of the page table
> > management code. The IOMMU core guarantees that the map and unmap
> > operations will always be called only with page sizes advertised by the
> > driver. We can use that assumption to remove loops of PGD and PMD
> > entries, simplifying the code.
> 
> Hmm, interesting. We still have to handle the case where a mapping created
> with one page-size could be unmapped with another though (in particular,
> unmapping part of the range).

Correct. I've implemented that in patch 9/9. Note that the patch also frees 
pages use for page directory entries when they're not needed anymore, instead 
of just marking them as invalid. That's something you probably should do in 
the arm-smmu driver as well.

> > Will, would it make sense to perform the same cleanup for the arm-smmu
> > driver, or is there a reason to keep loops over PGD and PMD entries ?
> > Removing them makes the implementation of 68kB and 2MB pages easier.
> 
> Is this an assumption that's relied on by other IOMMU drivers? It certainly
> makes mapping of large ranges less efficient than it could be, so I'm more
> inclined to set all the bits > PAGE_SIZE in pgsize_bitmap if it's only used
> to determine the granularity at which map/unmap are called (which is
> unrelated to what the hardware can actually do).

I haven't checked all the other IOMMU drivers, but at least the OMAP IOMMU 
driver relies on the same assumption. Splitting map/unmap operations in page 
size chunks inside the IOMMU core might indeed have a negative performance 
impact due to locking, but I'm not sure it would be noticeable.

-- 
Regards,

Laurent Pinchart

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 0/9] Renesas ipmmu-vmsa: Miscellaneous cleanups and fixes

2014-04-22 Thread Will Deacon
On Mon, Apr 21, 2014 at 03:13:00PM +0100, Laurent Pinchart wrote:
> Hello,

Hi Laurent,

> This patch set cleans up and fixes small issues in the ipmmu-vmsa driver. The
> patches are based on top of "[PATCH v3] iommu: Add driver for Renesas
> VMSA-compatible IPMMU" that adds the ipmmu-vmsa driver.
> 
> The most interesting part of this series is the rewrite of the page table
> management code. The IOMMU core guarantees that the map and unmap operations
> will always be called only with page sizes advertised by the driver. We can
> use that assumption to remove loops of PGD and PMD entries, simplifying the
> code.

Hmm, interesting. We still have to handle the case where a mapping created
with one page-size could be unmapped with another though (in particular,
unmapping part of the range).

> Will, would it make sense to perform the same cleanup for the arm-smmu driver,
> or is there a reason to keep loops over PGD and PMD entries ? Removing them
> makes the implementation of 68kB and 2MB pages easier.

Is this an assumption that's relied on by other IOMMU drivers? It
certainly makes mapping of large ranges less efficient than it could be, so
I'm more inclined to set all the bits > PAGE_SIZE in pgsize_bitmap if it's
only used to determine the granularity at which map/unmap are called (which
is unrelated to what the hardware can actually do).

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] iommu/arm-smmu: fix incorrect use of S2CR_TYPE_SHIFT

2014-04-22 Thread Will Deacon
On Tue, Apr 22, 2014 at 11:27:42AM +0100, Kefeng Wang wrote:
> On 04/22 18:00, Will Deacon wrote:
> > On Fri, Apr 18, 2014 at 03:31:17AM +0100, Kefeng Wang wrote:
> >> On 04/18 10:07, Kefeng Wang wrote:
> >>> There is already S2CR_TYPE_TRANS in S2CR_TYPE_TRANS macro,
>  ^^^
> >>> so drop the second shift.
> >>
> >> Typo issue, please use following patch.
> > 
> > They look the same to me -- which one should I take?
> > 
> > Also, since S2CR_TYPE_TRANS is 0x0, this fix isn't critical, so I'll include
> > it in my updates pull for 3.16.
> 
> OK, please use second one, thanks.

Ok, thanks.

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] iommu/arm-smmu: fix incorrect use of S2CR_TYPE_SHIFT

2014-04-22 Thread Kefeng Wang
On 04/22 18:00, Will Deacon wrote:
> On Fri, Apr 18, 2014 at 03:31:17AM +0100, Kefeng Wang wrote:
>> On 04/18 10:07, Kefeng Wang wrote:
>>> There is already S2CR_TYPE_TRANS in S2CR_TYPE_TRANS macro,
 ^^^
>>> so drop the second shift.
>>
>> Typo issue, please use following patch.
> 
> They look the same to me -- which one should I take?
> 
> Also, since S2CR_TYPE_TRANS is 0x0, this fix isn't critical, so I'll include
> it in my updates pull for 3.16.

OK, please use second one, thanks.

Kefeng

> 
> Cheers,
> 
> Will
> 
>>> Signed-off-by: Kefeng Wang 
>>> ---
>>>  drivers/iommu/arm-smmu.c |2 +-
>>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>>> index 8b89e33..96755ec 100644
>>> --- a/drivers/iommu/arm-smmu.c
>>> +++ b/drivers/iommu/arm-smmu.c
>>> @@ -1167,7 +1167,7 @@ static int arm_smmu_domain_add_master(struct 
>>> arm_smmu_domain *smmu_domain,
>>> for (i = 0; i < master->num_streamids; ++i) {
>>> u32 idx, s2cr;
>>> idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
>>> -   s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
>>> +   s2cr = S2CR_TYPE_TRANS |
>>>(smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
>>> writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
>>> }
>>>
>>
>>
>> From bfcdbee6f5e71c561dfddf8751c4eabdca1e3a56 Mon Sep 17 00:00:00 2001
>> From: Kefeng Wang 
>> Date: Fri, 18 Apr 2014 10:20:48 +0800
>> Subject: [PATCH] iommu/arm-smmu: fix incorrect use of S2CR_TYPE_SHIFT
>>
>> There is already S2CR_TYPE_SHIFT in S2CR_TYPE_TRANS macro,
>> so drop the second shift.
>>
>> Signed-off-by: Kefeng Wang 
>> ---
>>  drivers/iommu/arm-smmu.c |2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>> index 8b89e33..96755ec 100644
>> --- a/drivers/iommu/arm-smmu.c
>> +++ b/drivers/iommu/arm-smmu.c
>> @@ -1167,7 +1167,7 @@ static int arm_smmu_domain_add_master(struct 
>> arm_smmu_domain *smmu_domain,
>>  for (i = 0; i < master->num_streamids; ++i) {
>>  u32 idx, s2cr;
>>  idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
>> -s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
>> +s2cr = S2CR_TYPE_TRANS |
>> (smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
>>  writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
>>  }
>> -- 
>> 1.7.1
>>
>>
>>
> 
> .
> 


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] iommu/arm-smmu: fix incorrect use of S2CR_TYPE_SHIFT

2014-04-22 Thread Will Deacon
On Fri, Apr 18, 2014 at 03:31:17AM +0100, Kefeng Wang wrote:
> On 04/18 10:07, Kefeng Wang wrote:
> > There is already S2CR_TYPE_TRANS in S2CR_TYPE_TRANS macro,
> > so drop the second shift.
> 
> Typo issue, please use following patch.

They look the same to me -- which one should I take?

Also, since S2CR_TYPE_TRANS is 0x0, this fix isn't critical, so I'll include
it in my updates pull for 3.16.

Cheers,

Will

> > Signed-off-by: Kefeng Wang 
> > ---
> >  drivers/iommu/arm-smmu.c |2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> > 
> > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> > index 8b89e33..96755ec 100644
> > --- a/drivers/iommu/arm-smmu.c
> > +++ b/drivers/iommu/arm-smmu.c
> > @@ -1167,7 +1167,7 @@ static int arm_smmu_domain_add_master(struct 
> > arm_smmu_domain *smmu_domain,
> > for (i = 0; i < master->num_streamids; ++i) {
> > u32 idx, s2cr;
> > idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
> > -   s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
> > +   s2cr = S2CR_TYPE_TRANS |
> >(smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
> > writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
> > }
> > 
> 
> 
> From bfcdbee6f5e71c561dfddf8751c4eabdca1e3a56 Mon Sep 17 00:00:00 2001
> From: Kefeng Wang 
> Date: Fri, 18 Apr 2014 10:20:48 +0800
> Subject: [PATCH] iommu/arm-smmu: fix incorrect use of S2CR_TYPE_SHIFT
> 
> There is already S2CR_TYPE_SHIFT in S2CR_TYPE_TRANS macro,
> so drop the second shift.
> 
> Signed-off-by: Kefeng Wang 
> ---
>  drivers/iommu/arm-smmu.c |2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index 8b89e33..96755ec 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -1167,7 +1167,7 @@ static int arm_smmu_domain_add_master(struct 
> arm_smmu_domain *smmu_domain,
>   for (i = 0; i < master->num_streamids; ++i) {
>   u32 idx, s2cr;
>   idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
> - s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
> + s2cr = S2CR_TYPE_TRANS |
>  (smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
>   writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
>   }
> -- 
> 1.7.1
> 
> 
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] arm: dma-mapping: Fix mapping size value

2014-04-22 Thread Marek Szyprowski

Hello,

On 2014-04-21 08:47, Ritesh Harjani wrote:

68efd7d2fb("arm: dma-mapping: remove order parameter from
arm_iommu_create_mapping()") is causing kernel panic
because it wrongly sets the value of mapping->size:

Unable to handle kernel NULL pointer dereference at virtual
address 00a0
pgd = e7a84000
[00a0] *pgd=
...
PC is at bitmap_clear+0x48/0xd0
LR is at __iommu_remove_mapping+0x130/0x164

Fix it by correcting mapping->size value.

Signed-off-by: Ritesh Harjani 
Acked-by: Laurent Pinchart 


Thanks for spotting this issue! I'm really sorry for introducing it. I 
will push it to the fixes branch asap.



---
  arch/arm/mm/dma-mapping.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index f62aa06..6b00be1 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1963,8 +1963,8 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t 
base, size_t size)
mapping->nr_bitmaps = 1;
mapping->extensions = extensions;
mapping->base = base;
-   mapping->size = bitmap_size << PAGE_SHIFT;
mapping->bits = BITS_PER_BYTE * bitmap_size;
+   mapping->size = mapping->bits << PAGE_SHIFT;
  
  	spin_lock_init(&mapping->lock);


Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] arm: dma-mapping: Fix mapping size value

2014-04-22 Thread Will Deacon
On Mon, Apr 21, 2014 at 07:47:27AM +0100, Ritesh Harjani wrote:
> 68efd7d2fb("arm: dma-mapping: remove order parameter from
> arm_iommu_create_mapping()") is causing kernel panic
> because it wrongly sets the value of mapping->size:
> 
> Unable to handle kernel NULL pointer dereference at virtual
> address 00a0
> pgd = e7a84000
> [00a0] *pgd=
> ...
> PC is at bitmap_clear+0x48/0xd0
> LR is at __iommu_remove_mapping+0x130/0x164
> 
> Fix it by correcting mapping->size value.
> 
> Signed-off-by: Ritesh Harjani 
> Acked-by: Laurent Pinchart 
> ---
>  arch/arm/mm/dma-mapping.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index f62aa06..6b00be1 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -1963,8 +1963,8 @@ arm_iommu_create_mapping(struct bus_type *bus, 
> dma_addr_t base, size_t size)
>   mapping->nr_bitmaps = 1;
>   mapping->extensions = extensions;
>   mapping->base = base;
> - mapping->size = bitmap_size << PAGE_SHIFT;
>   mapping->bits = BITS_PER_BYTE * bitmap_size;
> + mapping->size = mapping->bits << PAGE_SHIFT;

Ok, but given that mapping->size is derived from mapping->bits, do we really
need both of these fields in struct dma_iommu_mapping?

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [Patch Part3 V1 19/22] iommu/vt-d: simplify intel_unmap_sg() and kill duplicated code

2014-04-22 Thread Jiang Liu
On 2014/4/22 15:38, David Woodhouse wrote:
> On Tue, 2014-04-22 at 15:07 +0800, Jiang Liu wrote:
>> +   size_t size = 0;
>> +#if 0
>> +   /* current the third argument of intel_unmap_page is unsued */
>> +   int i;
>> +   struct scatterlist *sg;
>>  
>> -   freelist = domain_unmap(domain, start_pfn, last_pfn);
>> +   for_each_sg(sglist, sg, nelems, i)
>> +   size += sg->length;
>> +#endif
> 
> Please don't do that. If you want to rely on the fact that
> intel_unmap_page() currently just uses the size from the IOVA it finds,
> then split it out into a separate function which explicitly does
> precisely that. And call that new function from both intel_unmap_sg()
> and intel_unmap_page().

Good suggestion, will change to follow that way in next version.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [Patch Part3 V1 19/22] iommu/vt-d: simplify intel_unmap_sg() and kill duplicated code

2014-04-22 Thread David Woodhouse
On Tue, 2014-04-22 at 15:07 +0800, Jiang Liu wrote:
> +   size_t size = 0;
> +#if 0
> +   /* current the third argument of intel_unmap_page is unsued */
> +   int i;
> +   struct scatterlist *sg;
>  
> -   freelist = domain_unmap(domain, start_pfn, last_pfn);
> +   for_each_sg(sglist, sg, nelems, i)
> +   size += sg->length;
> +#endif

Please don't do that. If you want to rely on the fact that
intel_unmap_page() currently just uses the size from the IOVA it finds,
then split it out into a separate function which explicitly does
precisely that. And call that new function from both intel_unmap_sg()
and intel_unmap_page().

-- 
David WoodhouseOpen Source Technology Centre
david.woodho...@intel.com  Intel Corporation


smime.p7s
Description: S/MIME cryptographic signature
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

[RFC Patch Part3 V1 00/22] Enable Intel DMAR device hotplug

2014-04-22 Thread Jiang Liu
When hot plugging a descrete IOH or a physical processor with embedded
IIO, we need to handle DMAR(or IOMMU) unit in the PCIe host bridge if
DMAR is in use. This patch set tries to enhance current DMAR/IOMMU/IR
drivers to support hotplug and is based on latest mainstream kernel
v3.15-rc2-36-gc089b229dfdd.

Patch 1-9 are bugfixes and code improvement for current drivers.
Patch 10-13 enhances DMAR framework to support hotplug
Patch 14 enhances Intel interrupt remapping driver to support hotplug
Patch 15 enhances error handling in Intel IR driver
Patch 16 enhance Intel IOMMU to support hotplug
Patch 17 enhance ACPI pci_root driver to handle DMAR units
Patch 18-22 are bugfixes and code improvement again

This patch set has been tested on Intel development machine.
Appreciate any comments and tests.

Best Regards!

Jiang Liu (22):
  iommu/vt-d: match segment number when searching for dev_iotlb capable
devices
  iommu/vt-d: use correct domain id to flush virtual machine domains
  iommu/vt-d: introduce helper functions to improve code readability
  iommu/vt-d: introduce helper functions to make code symmetric for
readability
  iommu/vt-d: only dynamically allocate domain id for virtual domains
  iommu/vt-d: fix possible invalid memory access caused by
free_dmar_iommu()
  iommu/vt-d: avoid freeing virtual machine domain in free_dmar_iommu()
  iommu/VT-d: simplify include/linux/dmar.h
  iommu/vt-d: change iommu_enable/disable_translation to return void
  iommu/vt-d: dynamically allocate and free seq_id for DMAR units
  IOMMU/vt-d: introduce helper function dmar_walk_resources()
  iommu/vt-d: implement DMAR unit hotplug framework
  iommu/vt-d: search _DSM method for DMAR hotplug
  iommu/vt-d: enhance intel_irq_remapping driver to support DMAR unit
hotplug
  iommu/vt-d: enhance error recovery in function
intel_enable_irq_remapping()
  iommu/vt-d: enhance intel-iommu driver to support DMAR unit hotplug
  pci, ACPI, iommu: enhance pci_root to support DMAR device hotplug
  iommu/vt-d: update proximity information when a new node with memory
available
  iommu/vt-d: simplify intel_unmap_sg() and kill duplicated code
  iommu/vt-d: introduce helper domain_pfn_within_range() to simplify
code
  iommu/vt-d: introduce helper function iova_size() to improve code
readability
  iommu/vt-d: fix bug in computing domain's iommu_snooping flag

 drivers/acpi/pci_root.c |   16 +-
 drivers/iommu/dmar.c|  568 ++--
 drivers/iommu/intel-iommu.c |  711 +--
 drivers/iommu/intel_irq_remapping.c |  233 +---
 include/linux/dmar.h|   80 ++--
 include/linux/intel-iommu.h |1 +
 include/linux/iova.h|5 +
 7 files changed, 1133 insertions(+), 481 deletions(-)

-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 22/22] iommu/vt-d: fix bug in computing domain's iommu_snooping flag

2014-04-22 Thread Jiang Liu
IOMMU units may dynamically attached to/detached from domains,
so we should scan all active IOMMU units when computing iommu_snooping
flag for a domain instead of only scanning IOMMU units associated
with the domain.

Also check snooping and superpage capabilities when hot-adding DMAR units.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |   54 ---
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 6d5b94aaac6e..9c39cab62cc1 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -626,50 +626,56 @@ static void domain_update_iommu_coherency(struct 
dmar_domain *domain)
rcu_read_unlock();
 }
 
-static void domain_update_iommu_snooping(struct dmar_domain *domain)
+static int domain_update_iommu_snooping(struct intel_iommu *skip)
 {
-   int i;
-
-   domain->iommu_snooping = 1;
+   struct dmar_drhd_unit *drhd;
+   struct intel_iommu *iommu;
+   int ret = 1;
 
-   for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
-   if (!ecap_sc_support(g_iommus[i]->ecap)) {
-   domain->iommu_snooping = 0;
-   break;
+   rcu_read_lock();
+   for_each_active_iommu(iommu, drhd) {
+   if (iommu != skip) {
+   if (!ecap_sc_support(iommu->ecap)) {
+   ret = 0;
+   break;
+   }
}
}
+   rcu_read_unlock();
+
+   return ret;
 }
 
-static void domain_update_iommu_superpage(struct dmar_domain *domain)
+static int domain_update_iommu_superpage(struct intel_iommu *skip)
 {
struct dmar_drhd_unit *drhd;
-   struct intel_iommu *iommu = NULL;
+   struct intel_iommu *iommu;
int mask = 0xf;
 
if (!intel_iommu_superpage) {
-   domain->iommu_superpage = 0;
-   return;
+   return 0;
}
 
/* set iommu_superpage to the smallest common denominator */
rcu_read_lock();
for_each_active_iommu(iommu, drhd) {
-   mask &= cap_super_page_val(iommu->cap);
-   if (!mask) {
-   break;
+   if (iommu != skip) {
+   mask &= cap_super_page_val(iommu->cap);
+   if (!mask)
+   break;
}
}
rcu_read_unlock();
 
-   domain->iommu_superpage = fls(mask);
+   return fls(mask);
 }
 
 /* Some capabilities may be different across iommus */
 static void domain_update_iommu_cap(struct dmar_domain *domain)
 {
domain_update_iommu_coherency(domain);
-   domain_update_iommu_snooping(domain);
-   domain_update_iommu_superpage(domain);
+   domain->iommu_snooping = domain_update_iommu_snooping(NULL);
+   domain->iommu_superpage = domain_update_iommu_superpage(NULL);
 }
 
 static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 
*devfn)
@@ -3793,6 +3799,18 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
iommu->name);
return -ENXIO;
}
+   if (!ecap_sc_support(iommu->ecap) &&
+   domain_update_iommu_snooping(iommu)) {
+   pr_warn("IOMMU: %s doesn't support snooping.\n",
+   iommu->name);
+   return -ENXIO;
+   }
+   if ((cap_super_page_val(iommu->cap) &
+   (1 << domain_update_iommu_superpage(iommu))) == 0) {
+   pr_warn("IOMMU: %s doesn't support large page.\n",
+   iommu->name);
+   return -ENXIO;
+   }
 
/*
 * Disable translation if already enabled prior to OS handover.
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 21/22] iommu/vt-d: introduce helper function iova_size() to improve code readability

2014-04-22 Thread Jiang Liu
Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |7 +++
 include/linux/iova.h|5 +
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c4bca2d814c8..6d5b94aaac6e 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3114,10 +3114,10 @@ static void flush_unmaps(void)
/* On real hardware multiple invalidations are 
expensive */
if (cap_caching_mode(iommu->cap))
iommu_flush_iotlb_psi(iommu, domain->id,
-   iova->pfn_lo, iova->pfn_hi - 
iova->pfn_lo + 1,
+   iova->pfn_lo, iova_size(iova),
!deferred_flush[i].freelist[j], 0);
else {
-   mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - 
iova->pfn_lo + 1));
+   mask = ilog2(mm_to_dma_pfn(iova_size(iova)));

iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
(uint64_t)iova->pfn_lo << 
PAGE_SHIFT, mask);
}
@@ -4061,8 +4061,7 @@ static int intel_iommu_memory_notifier(struct 
notifier_block *nb,
rcu_read_lock();
for_each_active_iommu(iommu, drhd)
iommu_flush_iotlb_psi(iommu, si_domain->id,
-   iova->pfn_lo,
-   iova->pfn_hi - iova->pfn_lo + 1,
+   iova->pfn_lo, iova_size(iova),
!freelist, 0);
rcu_read_unlock();
dma_free_pagelist(freelist);
diff --git a/include/linux/iova.h b/include/linux/iova.h
index 3277f4711349..19e81d5ccb6d 100644
--- a/include/linux/iova.h
+++ b/include/linux/iova.h
@@ -34,6 +34,11 @@ struct iova_domain {
unsigned long   dma_32bit_pfn;
 };
 
+static inline unsigned long iova_size(struct iova *iova)
+{
+   return iova->pfn_hi - iova->pfn_lo + 1;
+}
+
 struct iova *alloc_iova_mem(void);
 void free_iova_mem(struct iova *iova);
 void free_iova(struct iova_domain *iovad, unsigned long pfn);
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 18/22] iommu/vt-d: update proximity information when a new node with memory available

2014-04-22 Thread Jiang Liu
If node associated with a DMAR unit has no memory available, it uses -1
as default NUMA node id. So when memory hot-addition adds new memory to
an empty NUMA node, we should update the NUMA node id associated with
the DMAR unit. This will help to optomize memory allocation.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/dmar.c|   50 ---
 include/linux/intel-iommu.h |1 +
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 7a7383858c34..d607691a6a80 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -38,6 +38,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -444,6 +445,7 @@ static int dmar_parse_one_rhsa(struct acpi_dmar_header 
*header, void *arg)
if (!node_online(node))
node = -1;
drhd->iommu->node = node;
+   drhd->iommu->proximity_domain = rhsa->proximity_domain;
return 0;
}
}
@@ -458,8 +460,48 @@ static int dmar_parse_one_rhsa(struct acpi_dmar_header 
*header, void *arg)
 
return 0;
 }
+
+static int dmar_memory_notifier(struct notifier_block *nb,
+   unsigned long val, void *v)
+{
+   struct memory_notify *mhp = v;
+   struct dmar_drhd_unit *drhd;
+   struct intel_iommu *iommu;
+   int nid;
+
+   if (val != MEM_ONLINE)
+   return NOTIFY_OK;
+
+   if (mhp->status_change_nid < 0)
+   return NOTIFY_OK;
+
+   down_read(&dmar_global_lock);
+   for_each_iommu(iommu, drhd) {
+   if (iommu->node != -1)
+   continue;
+   nid = acpi_map_pxm_to_node(iommu->proximity_domain);
+   if (nid == mhp->status_change_nid)
+   iommu->node = nid;
+   }
+   up_read(&dmar_global_lock);
+
+   return NOTIFY_OK;
+}
+
+static struct notifier_block dmar_memory_nb = {
+   .notifier_call = dmar_memory_notifier,
+};
+
+static void dmar_register_memory_notifier(void)
+{
+   register_memory_notifier(&dmar_memory_nb);
+}
 #else
 #definedmar_parse_one_rhsa dmar_res_noop
+
+static void dmar_register_memory_notifier(void)
+{
+}
 #endif
 
 static void __init
@@ -1715,12 +1757,14 @@ static inline bool dmar_in_use(void)
return irq_remapping_enabled || intel_iommu_enabled;
 }
 
-static int __init dmar_free_unused_resources(void)
+static int __init dmar_late_init(void)
 {
struct dmar_drhd_unit *dmaru, *dmaru_n;
 
-   if (dmar_in_use())
+   if (dmar_in_use()) {
+   dmar_register_memory_notifier();
return 0;
+   }
 
if (dmar_dev_scope_status != 1 && !list_empty(&dmar_drhd_units))
bus_unregister_notifier(&pci_bus_type, &dmar_pci_bus_nb);
@@ -1735,7 +1779,7 @@ static int __init dmar_free_unused_resources(void)
return 0;
 }
 
-late_initcall(dmar_free_unused_resources);
+late_initcall(dmar_late_init);
 IOMMU_INIT_POST(detect_intel_iommu);
 
 /*
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 0a2da5188217..eea52ccdbd8e 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -337,6 +337,7 @@ struct intel_iommu {
struct ir_table *ir_table;  /* Interrupt remapping info */
 #endif
int node;
+   int proximity_domain;
 };
 
 static inline void __iommu_flush_cache(
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 14/22] iommu/vt-d: enhance intel_irq_remapping driver to support DMAR unit hotplug

2014-04-22 Thread Jiang Liu
Implement required callback functions for intel_irq_remapping driver
to support DMAR unit hotplug.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel_irq_remapping.c |  222 ++-
 1 file changed, 169 insertions(+), 53 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index aa309a8e4d3a..9f1c86566452 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -36,7 +36,6 @@ struct hpet_scope {
 
 static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
 static struct hpet_scope ir_hpet[MAX_HPET_TBS];
-static int ir_ioapic_num, ir_hpet_num;
 
 /*
  * Lock ordering:
@@ -320,7 +319,7 @@ static int set_ioapic_sid(struct irte *irte, int apic)
 
down_read(&dmar_global_lock);
for (i = 0; i < MAX_IO_APICS; i++) {
-   if (ir_ioapic[i].id == apic) {
+   if (ir_ioapic[i].iommu && ir_ioapic[i].id == apic) {
sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn;
break;
}
@@ -347,7 +346,7 @@ static int set_hpet_sid(struct irte *irte, u8 id)
 
down_read(&dmar_global_lock);
for (i = 0; i < MAX_HPET_TBS; i++) {
-   if (ir_hpet[i].id == id) {
+   if (ir_hpet[i].iommu && ir_hpet[i].id == id) {
sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn;
break;
}
@@ -446,17 +445,17 @@ static void iommu_set_irq_remapping(struct intel_iommu 
*iommu, int mode)
raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
-
-static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode)
+static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 {
struct ir_table *ir_table;
struct page *pages;
unsigned long *bitmap;
 
-   ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
-GFP_ATOMIC);
+   if (iommu->ir_table)
+   return 0;
 
-   if (!iommu->ir_table)
+   ir_table = kzalloc(sizeof(struct ir_table), GFP_ATOMIC);
+   if (!ir_table)
return -ENOMEM;
 
pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO,
@@ -465,7 +464,7 @@ static int intel_setup_irq_remapping(struct intel_iommu 
*iommu, int mode)
if (!pages) {
pr_err("IR%d: failed to allocate pages of order %d\n",
   iommu->seq_id, INTR_REMAP_PAGE_ORDER);
-   kfree(iommu->ir_table);
+   kfree(ir_table);
return -ENOMEM;
}
 
@@ -480,11 +479,22 @@ static int intel_setup_irq_remapping(struct intel_iommu 
*iommu, int mode)
 
ir_table->base = page_address(pages);
ir_table->bitmap = bitmap;
+   iommu->ir_table = ir_table;
 
-   iommu_set_irq_remapping(iommu, mode);
return 0;
 }
 
+static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
+{
+   if (iommu && iommu->ir_table) {
+   free_pages((unsigned long)iommu->ir_table->base,
+  INTR_REMAP_PAGE_ORDER);
+   kfree(iommu->ir_table->bitmap);
+   kfree(iommu->ir_table);
+   iommu->ir_table = NULL;
+   }
+}
+
 /*
  * Disable Interrupt Remapping.
  */
@@ -639,9 +649,10 @@ static int __init intel_enable_irq_remapping(void)
if (!ecap_ir_support(iommu->ecap))
continue;
 
-   if (intel_setup_irq_remapping(iommu, eim))
+   if (intel_setup_irq_remapping(iommu))
goto error;
 
+   iommu_set_irq_remapping(iommu, eim);
setup = 1;
}
 
@@ -672,12 +683,13 @@ error:
return -1;
 }
 
-static void ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope,
- struct intel_iommu *iommu)
+static int ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope,
+  struct intel_iommu *iommu,
+  struct acpi_dmar_hardware_unit *drhd)
 {
struct acpi_dmar_pci_path *path;
u8 bus;
-   int count;
+   int count, free = -1;
 
bus = scope->bus;
path = (struct acpi_dmar_pci_path *)(scope + 1);
@@ -693,19 +705,36 @@ static void ir_parse_one_hpet_scope(struct 
acpi_dmar_device_scope *scope,
   PCI_SECONDARY_BUS);
path++;
}
-   ir_hpet[ir_hpet_num].bus   = bus;
-   ir_hpet[ir_hpet_num].devfn = PCI_DEVFN(path->device, path->function);
-   ir_hpet[ir_hpet_num].iommu = iommu;
-   ir_hpet[ir_hpet_num].id= scope->enumeration_id;
-   ir_hpet_num++;
+
+   for (count = 0; count < MAX_HPET_TBS; count++) {
+   if (ir_hpet[count].iommu == iommu &&
+   ir_hpet[count].id == scope->enumeration_id)
+   return 0;
+ 

[Patch Part3 V1 11/22] IOMMU/vt-d: introduce helper function dmar_walk_resources()

2014-04-22 Thread Jiang Liu
Introduce helper function dmar_walk_resources to walk resource entries
in DMAR table and ACPI buffer object returned by ACPI _DSM method
for IOMMU hot-plug.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/dmar.c|  207 +++
 drivers/iommu/intel-iommu.c |4 +-
 include/linux/dmar.h|   19 ++--
 3 files changed, 121 insertions(+), 109 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 3e4168cddc64..d09ee0d55946 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -43,6 +43,14 @@
 
 #include "irq_remapping.h"
 
+typedef int (*dmar_res_handler_t)(struct acpi_dmar_header *, void *);
+struct dmar_res_callback {
+   dmar_res_handler_t  cb[ACPI_DMAR_TYPE_RESERVED];
+   void*arg[ACPI_DMAR_TYPE_RESERVED];
+   boolignore_unhandled;
+   boolprint_entry;
+};
+
 /*
  * Assumptions:
  * 1) The hotplug framework guarentees that DMAR unit will be hot-added
@@ -333,7 +341,7 @@ static struct notifier_block dmar_pci_bus_nb = {
  * present in the platform
  */
 static int __init
-dmar_parse_one_drhd(struct acpi_dmar_header *header)
+dmar_parse_one_drhd(struct acpi_dmar_header *header, void *arg)
 {
struct acpi_dmar_hardware_unit *drhd;
struct dmar_drhd_unit *dmaru;
@@ -364,6 +372,10 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
return ret;
}
dmar_register_drhd_unit(dmaru);
+
+   if (arg)
+   (*(int *)arg)++;
+
return 0;
 }
 
@@ -376,7 +388,7 @@ static void dmar_free_drhd(struct dmar_drhd_unit *dmaru)
kfree(dmaru);
 }
 
-static int __init dmar_parse_one_andd(struct acpi_dmar_header *header)
+static int __init dmar_parse_one_andd(struct acpi_dmar_header *header, void 
*arg)
 {
struct acpi_dmar_andd *andd = (void *)header;
 
@@ -398,7 +410,7 @@ static int __init dmar_parse_one_andd(struct 
acpi_dmar_header *header)
 
 #ifdef CONFIG_ACPI_NUMA
 static int __init
-dmar_parse_one_rhsa(struct acpi_dmar_header *header)
+dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
 {
struct acpi_dmar_rhsa *rhsa;
struct dmar_drhd_unit *drhd;
@@ -425,6 +437,8 @@ dmar_parse_one_rhsa(struct acpi_dmar_header *header)
 
return 0;
 }
+#else
+#definedmar_parse_one_rhsa dmar_res_noop
 #endif
 
 static void __init
@@ -486,6 +500,52 @@ static int __init dmar_table_detect(void)
return (ACPI_SUCCESS(status) ? 1 : 0);
 }
 
+static int dmar_walk_resources(struct acpi_dmar_header *start, size_t len,
+  struct dmar_res_callback *cb)
+{
+   int ret = 0;
+   struct acpi_dmar_header *iter, *next;
+   struct acpi_dmar_header *end = ((void *)start) + len;
+
+   for (iter = start; iter < end && ret == 0; iter = next) {
+   next = (void *)iter + iter->length;
+   if (iter->length == 0) {
+   /* Avoid looping forever on bad ACPI tables */
+   pr_debug(FW_BUG "Invalid 0-length structure\n");
+   break;
+   } else if (next > end) {
+   /* Avoid passing table end */
+   pr_warn(FW_BUG "record passes table end\n");
+   ret = -EINVAL;
+   break;
+   }
+
+   if (cb->print_entry)
+   dmar_table_print_dmar_entry(iter);
+
+   if (iter->type >= ACPI_DMAR_TYPE_RESERVED) {
+   /* continue for forward compatibility */
+   pr_debug("Unknown DMAR structure type %d\n",
+iter->type);
+   } else if (cb->cb[iter->type]) {
+   ret = cb->cb[iter->type](iter, cb->arg[iter->type]);
+   } else if (!cb->ignore_unhandled) {
+   pr_warn("No handler for DMAR structure type %d\n",
+   iter->type);
+   ret = -EINVAL;
+   }
+   }
+
+   return ret;
+}
+
+static inline int dmar_walk_dmar_table(struct acpi_table_dmar *dmar,
+  struct dmar_res_callback *cb)
+{
+   return dmar_walk_resources((struct acpi_dmar_header *)(dmar + 1),
+  dmar->header.length - sizeof(*dmar), cb);
+}
+
 /**
  * parse_dmar_table - parses the DMA reporting table
  */
@@ -493,9 +553,18 @@ static int __init
 parse_dmar_table(void)
 {
struct acpi_table_dmar *dmar;
-   struct acpi_dmar_header *entry_header;
int ret = 0;
int drhd_count = 0;
+   struct dmar_res_callback cb = {
+   .print_entry = true,
+   .ignore_unhandled = true,
+   .arg[ACPI_DMAR_TYPE_HARDWARE_UNIT] = &drhd_count,
+   .cb[ACPI_DMAR_TYPE_HARDWARE_UNIT] = &dmar_parse_one_drhd,
+   .cb[ACPI_DMAR_TYPE_RESERVED_ME

[Patch Part3 V1 10/22] iommu/vt-d: dynamically allocate and free seq_id for DMAR units

2014-04-22 Thread Jiang Liu
Introduce functions to support dynamic IOMMU seq_id allocating and
releasing, which will be used to support DMAR hotplug.

Also rename IOMMU_UNITS_SUPPORTED as DMAR_UNITS_SUPPORTED.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/dmar.c|   40 ++--
 drivers/iommu/intel-iommu.c |   13 +++--
 include/linux/dmar.h|6 ++
 3 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 39f8b717fe84..3e4168cddc64 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -61,6 +61,7 @@ LIST_HEAD(dmar_drhd_units);
 struct acpi_table_header * __initdata dmar_tbl;
 static acpi_size dmar_tbl_size;
 static int dmar_dev_scope_status = 1;
+static unsigned long dmar_seq_ids[BITS_TO_LONGS(DMAR_UNITS_SUPPORTED)];
 
 static int alloc_iommu(struct dmar_drhd_unit *drhd);
 static void free_iommu(struct intel_iommu *iommu);
@@ -914,11 +915,32 @@ out:
return err;
 }
 
+static int dmar_alloc_seq_id(struct intel_iommu *iommu)
+{
+   iommu->seq_id = find_first_zero_bit(dmar_seq_ids,
+   DMAR_UNITS_SUPPORTED);
+   if (iommu->seq_id >= DMAR_UNITS_SUPPORTED) {
+   iommu->seq_id = -1;
+   } else {
+   set_bit(iommu->seq_id, dmar_seq_ids);
+   sprintf(iommu->name, "dmar%d", iommu->seq_id);
+   }
+
+   return iommu->seq_id;
+}
+
+static void dmar_free_seq_id(struct intel_iommu *iommu)
+{
+   if (iommu->seq_id >= 0) {
+   clear_bit(iommu->seq_id, dmar_seq_ids);
+   iommu->seq_id = -1;
+   }
+}
+
 static int alloc_iommu(struct dmar_drhd_unit *drhd)
 {
struct intel_iommu *iommu;
u32 ver, sts;
-   static int iommu_allocated = 0;
int agaw = 0;
int msagaw = 0;
int err;
@@ -932,13 +954,16 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
if (!iommu)
return -ENOMEM;
 
-   iommu->seq_id = iommu_allocated++;
-   sprintf (iommu->name, "dmar%d", iommu->seq_id);
+   if (dmar_alloc_seq_id(iommu) < 0) {
+   pr_err("IOMMU: failed to allocate seq_id\n");
+   err = -ENOSPC;
+   goto error;
+   }
 
err = map_iommu(iommu, drhd->reg_base_addr);
if (err) {
pr_err("IOMMU: failed to map %s\n", iommu->name);
-   goto error;
+   goto error_free_seq_id;
}
 
err = -EINVAL;
@@ -982,9 +1007,11 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
drhd->iommu = iommu;
return 0;
 
- err_unmap:
+err_unmap:
unmap_iommu(iommu);
- error:
+error_free_seq_id:
+   dmar_free_seq_id(iommu);
+error:
kfree(iommu);
return err;
 }
@@ -1006,6 +1033,7 @@ static void free_iommu(struct intel_iommu *iommu)
if (iommu->reg)
unmap_iommu(iommu);
 
+   dmar_free_seq_id(iommu);
kfree(iommu);
 }
 
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 75d7c5e3f77d..92d7b276edb3 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -328,17 +328,10 @@ static int hw_pass_through = 1;
 /* si_domain contains mulitple devices */
 #define DOMAIN_FLAG_STATIC_IDENTITY(1 << 1)
 
-/* define the limit of IOMMUs supported in each domain */
-#ifdef CONFIG_X86
-# define   IOMMU_UNITS_SUPPORTED   MAX_IO_APICS
-#else
-# define   IOMMU_UNITS_SUPPORTED   64
-#endif
-
 struct dmar_domain {
int id; /* domain id */
int nid;/* node id */
-   DECLARE_BITMAP(iommu_bmp, IOMMU_UNITS_SUPPORTED);
+   DECLARE_BITMAP(iommu_bmp, DMAR_UNITS_SUPPORTED);
/* bitmap of iommus this domain uses*/
 
struct list_head devices;   /* all devices' list */
@@ -2707,12 +2700,12 @@ static int __init init_dmars(void)
 * threaded kernel __init code path all other access are read
 * only
 */
-   if (g_num_of_iommus < IOMMU_UNITS_SUPPORTED) {
+   if (g_num_of_iommus < DMAR_UNITS_SUPPORTED) {
g_num_of_iommus++;
continue;
}
printk_once(KERN_ERR "intel-iommu: exceeded %d IOMMUs\n",
- IOMMU_UNITS_SUPPORTED);
+ DMAR_UNITS_SUPPORTED);
}
 
g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 1deece46a0ca..4aa8de0d1b97 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -30,6 +30,12 @@
 
 struct acpi_dmar_header;
 
+#ifdef CONFIG_X86
+# define   DMAR_UNITS_SUPPORTEDMAX_IO_APICS
+#else
+# define   DMAR_UNITS_SUPPORTED64
+#endif
+
 /* DMAR Flags */
 #define DMAR_INTR_REMAP0x1
 #define DMAR_X2APIC_OPT_OUT0x2
-- 
1.7.10

[Patch Part3 V1 19/22] iommu/vt-d: simplify intel_unmap_sg() and kill duplicated code

2014-04-22 Thread Jiang Liu
Simplify intel_unmap_sg() by calling intel_unmap_page() and
kill duplicated code, no functionality changes.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |   63 +--
 1 file changed, 18 insertions(+), 45 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f2143b59ad68..4738e64fe097 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -979,6 +979,8 @@ static void dma_pte_free_pagetable(struct dmar_domain 
*domain,
BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
BUG_ON(start_pfn > last_pfn);
 
+   dma_pte_clear_range(domain, start_pfn, last_pfn);
+
/* We don't need lock here; nobody else touches the iova range */
dma_pte_free_level(domain, agaw_to_level(domain->agaw),
   domain->pgd, 0, start_pfn, last_pfn);
@@ -2031,12 +2033,14 @@ static int __domain_mapping(struct dmar_domain *domain, 
unsigned long iov_pfn,
/* It is large page*/
if (largepage_lvl > 1) {
pteval |= DMA_PTE_LARGE_PAGE;
-   /* Ensure that old small page tables are 
removed to make room
-  for superpage, if they exist. */
-   dma_pte_clear_range(domain, iov_pfn,
-   iov_pfn + 
lvl_to_nr_pages(largepage_lvl) - 1);
+   lvl_pages = lvl_to_nr_pages(largepage_lvl);
+   /*
+* Ensure that old small page tables are
+* removed to make room for superpage,
+* if they exist.
+*/
dma_pte_free_pagetable(domain, iov_pfn,
-  iov_pfn + 
lvl_to_nr_pages(largepage_lvl) - 1);
+  iov_pfn + lvl_pages - 1);
} else {
pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
}
@@ -3256,43 +3260,17 @@ static void intel_unmap_sg(struct device *dev, struct 
scatterlist *sglist,
   int nelems, enum dma_data_direction dir,
   struct dma_attrs *attrs)
 {
-   struct dmar_domain *domain;
-   unsigned long start_pfn, last_pfn;
-   struct iova *iova;
-   struct intel_iommu *iommu;
-   struct page *freelist;
-
-   if (iommu_no_mapping(dev))
-   return;
-
-   domain = find_domain(dev);
-   BUG_ON(!domain);
-
-   iommu = domain_get_iommu(domain);
-
-   iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
-   if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
- (unsigned long long)sglist[0].dma_address))
-   return;
-
-   start_pfn = mm_to_dma_pfn(iova->pfn_lo);
-   last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
+   size_t size = 0;
+#if 0
+   /* current the third argument of intel_unmap_page is unsued */
+   int i;
+   struct scatterlist *sg;
 
-   freelist = domain_unmap(domain, start_pfn, last_pfn);
+   for_each_sg(sglist, sg, nelems, i)
+   size += sg->length;
+#endif
 
-   if (intel_iommu_strict) {
-   iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
- last_pfn - start_pfn + 1, !freelist, 0);
-   /* free iova */
-   __free_iova(&domain->iovad, iova);
-   dma_free_pagelist(freelist);
-   } else {
-   add_unmap(domain, iova, freelist);
-   /*
-* queue up the release of the unmap to save the 1/6th of the
-* cpu used up by the iotlb flush operation...
-*/
-   }
+   intel_unmap_page(dev, sglist[0].dma_address, size, dir, attrs);
 }
 
 static int intel_nontranslate_map_sg(struct device *hddev,
@@ -3356,13 +3334,8 @@ static int intel_map_sg(struct device *dev, struct 
scatterlist *sglist, int nele
 
ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
if (unlikely(ret)) {
-   /*  clear the page */
-   dma_pte_clear_range(domain, start_vpfn,
-   start_vpfn + size - 1);
-   /* free page tables */
dma_pte_free_pagetable(domain, start_vpfn,
   start_vpfn + size - 1);
-   /* free iova */
__free_iova(&domain->iovad, iova);
return 0;
}
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 17/22] pci, ACPI, iommu: enhance pci_root to support DMAR device hotplug

2014-04-22 Thread Jiang Liu
Finally enhance pci_root driver to support DMAR device hotplug when
hot-plugging PCI host bridges.

Signed-off-by: Jiang Liu 
---
 drivers/acpi/pci_root.c |   16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index d388f13d48b4..aa8f549869f3 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -33,6 +33,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include  /* for acpi_hest_init() */
@@ -511,6 +512,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
struct acpi_pci_root *root;
acpi_handle handle = device->handle;
int no_aspm = 0, clear_aspm = 0;
+   bool hotadd = (system_state != SYSTEM_BOOTING);
 
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
@@ -557,6 +559,11 @@ static int acpi_pci_root_add(struct acpi_device *device,
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
device->driver_data = root;
 
+   if (hotadd && dmar_device_hotplug(handle, true)) {
+   result = -ENXIO;
+   goto end;
+   }
+
pr_info(PREFIX "%s [%s] (domain %04x %pR)\n",
   acpi_device_name(device), acpi_device_bid(device),
   root->segment, &root->secondary);
@@ -583,7 +590,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
root->segment, (unsigned int)root->secondary.start);
device->driver_data = NULL;
result = -ENODEV;
-   goto end;
+   goto remove_dmar;
}
 
if (clear_aspm) {
@@ -597,7 +604,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
 
-   if (system_state != SYSTEM_BOOTING) {
+   if (hotadd) {
pcibios_resource_survey_bus(root->bus);
pci_assign_unassigned_root_bus_resources(root->bus);
}
@@ -607,6 +614,9 @@ static int acpi_pci_root_add(struct acpi_device *device,
pci_unlock_rescan_remove();
return 1;
 
+remove_dmar:
+   if (hotadd)
+   dmar_device_hotplug(handle, false);
 end:
kfree(root);
return result;
@@ -625,6 +635,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
 
pci_remove_root_bus(root->bus);
 
+   dmar_device_hotplug(device->handle, false);
+
pci_unlock_rescan_remove();
 
kfree(root);
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 20/22] iommu/vt-d: introduce helper domain_pfn_within_range() to simplify code

2014-04-22 Thread Jiang Liu
Introduce helper function domain_pfn_within_range() to simplify code
and improve readability.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |   30 --
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 4738e64fe097..c4bca2d814c8 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -542,6 +542,14 @@ static inline int domain_type_is_vm_or_si(struct 
dmar_domain *domain)
DOMAIN_FLAG_STATIC_IDENTITY);
 }
 
+static inline int domain_pfn_supported(struct dmar_domain *domain,
+  unsigned long pfn)
+{
+   int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+
+   return !(addr_width < BITS_PER_LONG && pfn >> addr_width);
+}
+
 static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
 {
unsigned long sagaw;
@@ -815,14 +823,13 @@ out:
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
  unsigned long pfn, int *target_level)
 {
-   int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
struct dma_pte *parent, *pte = NULL;
int level = agaw_to_level(domain->agaw);
int offset;
 
BUG_ON(!domain->pgd);
 
-   if (addr_width < BITS_PER_LONG && pfn >> addr_width)
+   if (!domain_pfn_supported(domain, pfn))
/* Address beyond IOMMU's addressing capabilities. */
return NULL;
 
@@ -907,12 +914,11 @@ static void dma_pte_clear_range(struct dmar_domain 
*domain,
unsigned long start_pfn,
unsigned long last_pfn)
 {
-   int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
unsigned int large_page = 1;
struct dma_pte *first_pte, *pte;
 
-   BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
-   BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+   BUG_ON(!domain_pfn_supported(domain, start_pfn));
+   BUG_ON(!domain_pfn_supported(domain, last_pfn));
BUG_ON(start_pfn > last_pfn);
 
/* we don't need lock here; nobody else touches the iova range */
@@ -973,10 +979,8 @@ static void dma_pte_free_pagetable(struct dmar_domain 
*domain,
   unsigned long start_pfn,
   unsigned long last_pfn)
 {
-   int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
-
-   BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
-   BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+   BUG_ON(!domain_pfn_supported(domain, start_pfn));
+   BUG_ON(!domain_pfn_supported(domain, last_pfn));
BUG_ON(start_pfn > last_pfn);
 
dma_pte_clear_range(domain, start_pfn, last_pfn);
@@ -1078,11 +1082,10 @@ struct page *domain_unmap(struct dmar_domain *domain,
  unsigned long start_pfn,
  unsigned long last_pfn)
 {
-   int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
struct page *freelist = NULL;
 
-   BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
-   BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+   BUG_ON(!domain_pfn_supported(domain, start_pfn));
+   BUG_ON(!domain_pfn_supported(domain, last_pfn));
BUG_ON(start_pfn > last_pfn);
 
/* we don't need lock here; nobody else touches the iova range */
@@ -1994,12 +1997,11 @@ static int __domain_mapping(struct dmar_domain *domain, 
unsigned long iov_pfn,
 {
struct dma_pte *first_pte = NULL, *pte = NULL;
phys_addr_t uninitialized_var(pteval);
-   int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
unsigned long sg_res;
unsigned int largepage_lvl = 0;
unsigned long lvl_pages = 0;
 
-   BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> 
addr_width);
+   BUG_ON(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1));
 
if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
return -EINVAL;
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 16/22] iommu/vt-d: enhance intel-iommu driver to support DMAR unit hotplug

2014-04-22 Thread Jiang Liu
Implement required callback functions for intel-iommu driver
to support DMAR unit hotplug.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |  194 +++
 1 file changed, 139 insertions(+), 55 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 33e636c246a6..f2143b59ad68 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1116,8 +1116,11 @@ static int iommu_alloc_root_entry(struct intel_iommu 
*iommu)
unsigned long flags;
 
root = (struct root_entry *)alloc_pgtable_page(iommu->node);
-   if (!root)
+   if (!root) {
+   pr_err("IOMMU: allocating root entry for %s failed\n",
+   iommu->name);
return -ENOMEM;
+   }
 
__iommu_flush_cache(iommu, root, ROOT_SIZE);
 
@@ -1457,7 +1460,7 @@ static int iommu_init_domains(struct intel_iommu *iommu)
return 0;
 }
 
-static void free_dmar_iommu(struct intel_iommu *iommu)
+static void disable_dmar_iommu(struct intel_iommu *iommu)
 {
struct dmar_domain *domain;
int i;
@@ -1481,11 +1484,16 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 
if (iommu->gcmd & DMA_GCMD_TE)
iommu_disable_translation(iommu);
+}
 
-   kfree(iommu->domains);
-   kfree(iommu->domain_ids);
-   iommu->domains = NULL;
-   iommu->domain_ids = NULL;
+static void free_dmar_iommu(struct intel_iommu *iommu)
+{
+   if ((iommu->domains) && (iommu->domain_ids)) {
+   kfree(iommu->domains);
+   kfree(iommu->domain_ids);
+   iommu->domains = NULL;
+   iommu->domain_ids = NULL;
+   }
 
g_iommus[iommu->seq_id] = NULL;
 
@@ -2680,6 +2688,41 @@ static int __init 
iommu_prepare_static_identity_mapping(int hw)
return 0;
 }
 
+static void intel_iommu_init_qi(struct intel_iommu *iommu)
+{
+   /*
+* 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;
+   pr_info("IOMMU: %s using Register based invalidation\n",
+   iommu->name);
+   } else {
+   iommu->flush.flush_context = qi_flush_context;
+   iommu->flush.flush_iotlb = qi_flush_iotlb;
+   pr_info("IOMMU: %s using Queued invalidation\n", iommu->name);
+   }
+}
+
 static int __init init_dmars(void)
 {
struct dmar_drhd_unit *drhd;
@@ -2708,6 +2751,10 @@ static int __init init_dmars(void)
  DMAR_UNITS_SUPPORTED);
}
 
+   /* Preallocate enough resources for IOMMU hot-addition */
+   if (g_num_of_iommus < DMAR_UNITS_SUPPORTED)
+   g_num_of_iommus = DMAR_UNITS_SUPPORTED;
+
g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
GFP_KERNEL);
if (!g_iommus) {
@@ -2736,58 +2783,14 @@ static int __init init_dmars(void)
 * 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");
+   if (ret)
goto free_iommu;
-   }
if (!ecap_pass_through(iommu->ecap))
hw_pass_through = 0;
}
 
-   /*
-* Start from the sane iommu hardware state.
-*/
-   for_each_active_iommu(iommu, drhd) {
-   /*
-* 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)
-   continue;
-
-   /*
-* Clear any previous faults.
-*/
-   dmar_fault(-1, iommu);
-   /*
-* Disable queued invalidation if supported and already enabled
-* before OS handover.
-*/
-   dmar_disable_qi(iommu);
-   }
-
-  

[Patch Part3 V1 15/22] iommu/vt-d: enhance error recovery in function intel_enable_irq_remapping()

2014-04-22 Thread Jiang Liu
Enhance error recovery in function intel_enable_irq_remapping()
by tearing down all created data structures.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel_irq_remapping.c |8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 9f1c86566452..f65b68d3de10 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -673,9 +673,11 @@ static int __init intel_enable_irq_remapping(void)
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
 
 error:
-   /*
-* handle error condition gracefully here!
-*/
+   for_each_iommu(iommu, drhd)
+   if (ecap_ir_support(iommu->ecap)) {
+   iommu_disable_irq_remapping(iommu);
+   intel_teardown_irq_remapping(iommu);
+   }
 
if (x2apic_present)
pr_warn("Failed to enable irq remapping.  You are vulnerable to 
irq-injection attacks.\n");
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 12/22] iommu/vt-d: implement DMAR unit hotplug framework

2014-04-22 Thread Jiang Liu
On Intel platforms, an IO Hub (PCI/PCIe host bridge) may contain DMAR
units, so we need to support DMAR hotplug when supporting PCI host
bridge hotplug on Intel platforms.

According to Section 8.8 "Remapping Hardware Unit Hot Plug" in "Intel
Virtualization Technology for Directed IO Architecture Specification
Rev 2.2", ACPI BIOS should implement ACPI _DSM method under the ACPI
object for the PCI host bridge to support DMAR hotplug.

This patch introduces interfaces to parse ACPI _DSM method for
DMAR unit hotplug. It also implements state machines for DMAR unit
hot-addition and hot-removal.

The PCI host bridge hotplug driver should call dmar_hotplug_hotplug()
before scanning PCI devices connected for hot-addition and after
destroying all PCI devices for hot-removal.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/dmar.c|  257 +--
 drivers/iommu/intel-iommu.c |   78 ++-
 drivers/iommu/intel_irq_remapping.c |5 +
 include/linux/dmar.h|   27 
 4 files changed, 353 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index d09ee0d55946..290b4bdcaa3a 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -74,7 +74,7 @@ static unsigned long 
dmar_seq_ids[BITS_TO_LONGS(DMAR_UNITS_SUPPORTED)];
 static int alloc_iommu(struct dmar_drhd_unit *drhd);
 static void free_iommu(struct intel_iommu *iommu);
 
-static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
+static void dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
 {
/*
 * add INCLUDE_ALL at the tail, so scan the list will find it at
@@ -335,24 +335,45 @@ static struct notifier_block dmar_pci_bus_nb = {
.priority = INT_MIN,
 };
 
+static struct dmar_drhd_unit *
+dmar_find_dmaru(struct acpi_dmar_hardware_unit *drhd)
+{
+   struct dmar_drhd_unit *dmaru;
+
+   list_for_each_entry_rcu(dmaru, &dmar_drhd_units, list)
+   if (dmaru->segment == drhd->segment &&
+   dmaru->reg_base_addr == drhd->address)
+   return dmaru;
+
+   return NULL;
+}
+
 /**
  * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
  * 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, void *arg)
+static int dmar_parse_one_drhd(struct acpi_dmar_header *header, void *arg)
 {
struct acpi_dmar_hardware_unit *drhd;
struct dmar_drhd_unit *dmaru;
int ret = 0;
 
drhd = (struct acpi_dmar_hardware_unit *)header;
-   dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
+   dmaru = dmar_find_dmaru(drhd);
+   if (dmaru)
+   goto out;
+
+   dmaru = kzalloc(sizeof(*dmaru) + header->length, GFP_KERNEL);
if (!dmaru)
return -ENOMEM;
 
-   dmaru->hdr = header;
+   /*
+* If header is allocated from slab by ACPI _DSM method, we need to
+* copy the content because the memory buffer will be freed on return.
+*/
+   dmaru->hdr = (void *)(dmaru + 1);
+   memcpy(dmaru->hdr, header, header->length);
dmaru->reg_base_addr = drhd->address;
dmaru->segment = drhd->segment;
dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
@@ -373,6 +394,7 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header, void 
*arg)
}
dmar_register_drhd_unit(dmaru);
 
+out:
if (arg)
(*(int *)arg)++;
 
@@ -409,8 +431,7 @@ static int __init dmar_parse_one_andd(struct 
acpi_dmar_header *header, void *arg
 }
 
 #ifdef CONFIG_ACPI_NUMA
-static int __init
-dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
+static int dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
 {
struct acpi_dmar_rhsa *rhsa;
struct dmar_drhd_unit *drhd;
@@ -804,14 +825,22 @@ dmar_validate_one_drhd(struct acpi_dmar_header *entry, 
void *arg)
return -EINVAL;
}
 
-   addr = early_ioremap(drhd->address, VTD_PAGE_SIZE);
+   if (arg)
+   addr = ioremap(drhd->address, VTD_PAGE_SIZE);
+   else
+   addr = early_ioremap(drhd->address, VTD_PAGE_SIZE);
if (!addr) {
pr_warn("IOMMU: can't validate: %llx\n", drhd->address);
return -EINVAL;
}
+
cap = dmar_readq(addr + DMAR_CAP_REG);
ecap = dmar_readq(addr + DMAR_ECAP_REG);
-   early_iounmap(addr, VTD_PAGE_SIZE);
+
+   if (arg)
+   iounmap(addr);
+   else
+   early_iounmap(addr, VTD_PAGE_SIZE);
 
if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
warn_invalid_dmar(drhd->address, " returns all ones");
@@ -1680,12 +1709,17 @@ int __init dmar_ir_support(void)
return dmar->flags & 0x1;
 }
 
+/* Check whether DMAR units are in use */
+static inline bool dmar_in_use(

[Patch Part3 V1 13/22] iommu/vt-d: search _DSM method for DMAR hotplug

2014-04-22 Thread Jiang Liu
According to Intel VT-d specification, _DSM method to support DMAR
hotplug should exist directly under corresponding ACPI object
representing PCI host bridge. But some BIOSes doesn't conform to
this, so search for _DSM method in the subtree starting from the
ACPI object representing the PCI host bridge.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/dmar.c |   34 +++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 290b4bdcaa3a..7a7383858c34 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -1920,20 +1920,48 @@ static int dmar_hotplug_remove(acpi_handle handle)
return ret;
 }
 
+static acpi_status dmar_get_dsm_handle(acpi_handle handle, u32 lvl,
+  void *context, void **retval)
+{
+   acpi_handle *phdl = retval;
+
+   if (dmar_detect_dsm(handle, DMAR_DSM_FUNC_DRHD)) {
+   *phdl = handle;
+   return AE_CTRL_TERMINATE;
+   }
+
+   return AE_OK;
+}
+
 int dmar_device_hotplug(acpi_handle handle, bool insert)
 {
int ret;
+   acpi_handle tmp = NULL;
+   acpi_status status;
 
if (!dmar_in_use())
return 0;
-   if (!dmar_detect_dsm(handle, DMAR_DSM_FUNC_DRHD))
+
+   if (dmar_detect_dsm(handle, DMAR_DSM_FUNC_DRHD)) {
+   tmp = handle;
+   } else {
+   status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ACPI_UINT32_MAX,
+dmar_get_dsm_handle,
+NULL, NULL, &tmp);
+   if (ACPI_FAILURE(status)) {
+   pr_warn("Failed to locate _DSM method.\n");
+   return -ENXIO;
+   }
+   }
+   if (tmp == NULL)
return 0;
 
down_write(&dmar_global_lock);
if (insert)
-   ret = dmar_hotplug_insert(handle);
+   ret = dmar_hotplug_insert(tmp);
else
-   ret = dmar_hotplug_remove(handle);
+   ret = dmar_hotplug_remove(tmp);
up_write(&dmar_global_lock);
 
return ret;
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 07/22] iommu/vt-d: avoid freeing virtual machine domain in free_dmar_iommu()

2014-04-22 Thread Jiang Liu
Virtual machine domains are created by intel_iommu_domain_init() and
should be destroyed by intel_iommu_domain_destroy(). So avoid freeing
virtual machine domain data structure in free_dmar_iommu() when
doamin->iommu_count reaches zero, otherwise it may cause invalid
memory access because the IOMMU framework still holds references
to the domain structure.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 1f10fcd1c696..5e865c1265ad 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1482,7 +1482,8 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 
domain = iommu->domains[i];
clear_bit(i, iommu->domain_ids);
-   if (domain_detach_iommu(domain, iommu) == 0)
+   if (domain_detach_iommu(domain, iommu) == 0 &&
+   !domain_type_is_vm(domain))
domain_exit(domain);
}
}
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 09/22] iommu/vt-d: change iommu_enable/disable_translation to return void

2014-04-22 Thread Jiang Liu
Simplify error handling path by changing iommu_{enable|disable}_translation
to return void.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |   18 +-
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 5e865c1265ad..75d7c5e3f77d 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1391,7 +1391,7 @@ static void iommu_disable_protect_mem_regions(struct 
intel_iommu *iommu)
raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
-static int iommu_enable_translation(struct intel_iommu *iommu)
+static void iommu_enable_translation(struct intel_iommu *iommu)
 {
u32 sts;
unsigned long flags;
@@ -1405,10 +1405,9 @@ static int iommu_enable_translation(struct intel_iommu 
*iommu)
  readl, (sts & DMA_GSTS_TES), sts);
 
raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
-   return 0;
 }
 
-static int iommu_disable_translation(struct intel_iommu *iommu)
+static void iommu_disable_translation(struct intel_iommu *iommu)
 {
u32 sts;
unsigned long flag;
@@ -1422,7 +1421,6 @@ static int iommu_disable_translation(struct intel_iommu 
*iommu)
  readl, (!(sts & DMA_GSTS_TES)), sts);
 
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
-   return 0;
 }
 
 
@@ -2875,11 +2873,7 @@ static int __init init_dmars(void)
 
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 free_iommu;
-
+   iommu_enable_translation(iommu);
iommu_disable_protect_mem_regions(iommu);
}
 
@@ -3577,10 +3571,8 @@ static int init_iommu_hw(void)
 
iommu->flush.flush_context(iommu, 0, 0, 0,
   DMA_CCMD_GLOBAL_INVL);
-   iommu->flush.flush_iotlb(iommu, 0, 0, 0,
-DMA_TLB_GLOBAL_FLUSH);
-   if (iommu_enable_translation(iommu))
-   return 1;
+   iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
+   iommu_enable_translation(iommu);
iommu_disable_protect_mem_regions(iommu);
}
 
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 08/22] iommu/VT-d: simplify include/linux/dmar.h

2014-04-22 Thread Jiang Liu
Simplify include/linux/dmar.h a bit based on the fact that
both CONFIG_INTEL_IOMMU and CONFIG_IRQ_REMAP select CONFIG_DMAR_TABLE.

Signed-off-by: Jiang Liu 
---
 include/linux/dmar.h |   50 ++
 1 file changed, 18 insertions(+), 32 deletions(-)

diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 23c8db129560..1deece46a0ca 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -114,22 +114,30 @@ extern int dmar_remove_dev_scope(struct 
dmar_pci_notify_info *info,
 /* Intel IOMMU detection */
 extern int detect_intel_iommu(void);
 extern int enable_drhd_fault_handling(void);
-#else
-struct dmar_pci_notify_info;
-static inline int detect_intel_iommu(void)
+
+#ifdef CONFIG_INTEL_IOMMU
+extern int iommu_detected, no_iommu;
+extern int intel_iommu_init(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_iommu_notify_scope_dev(struct dmar_pci_notify_info *info);
+#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)
 {
-   return -ENODEV;
+   return 0;
 }
-
-static inline int dmar_table_init(void)
+static inline int dmar_parse_one_atsr(struct acpi_dmar_header *header)
 {
-   return -ENODEV;
+   return 0;
 }
-static inline int enable_drhd_fault_handling(void)
+static inline int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info 
*info)
 {
-   return -1;
+   return 0;
 }
-#endif /* !CONFIG_DMAR_TABLE */
+#endif /* CONFIG_INTEL_IOMMU */
+
+#endif /* CONFIG_DMAR_TABLE */
 
 struct irte {
union {
@@ -177,26 +185,4 @@ 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_INTEL_IOMMU
-extern int iommu_detected, no_iommu;
-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_iommu_notify_scope_dev(struct dmar_pci_notify_info *info);
-extern int intel_iommu_init(void);
-#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)
-{
-   return 0;
-}
-static inline int dmar_parse_one_atsr(struct acpi_dmar_header *header)
-{
-   return 0;
-}
-static inline int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info 
*info)
-{
-   return 0;
-}
-#endif /* CONFIG_INTEL_IOMMU */
-
 #endif /* __DMAR_H__ */
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 06/22] iommu/vt-d: fix possible invalid memory access caused by free_dmar_iommu()

2014-04-22 Thread Jiang Liu
Static identity and virtual machine domains may be cached in
iommu->domain_ids array after corresponding IOMMUs have been removed
from domain->iommu_bmp. So we should check domain->iommu_bmp before
decreasing domain->iommu_count in function free_dmar_iommu(), otherwise
it may cause free of inuse domain data structure.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |   11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 0ab0cd236b16..1f10fcd1c696 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -425,6 +425,8 @@ static void domain_remove_one_dev_info(struct dmar_domain 
*domain,
   struct device *dev);
 static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
   struct device *dev);
+static int domain_detach_iommu(struct dmar_domain *domain,
+  struct intel_iommu *iommu);
 
 #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
 int dmar_disabled = 0;
@@ -1467,8 +1469,7 @@ static int iommu_init_domains(struct intel_iommu *iommu)
 static void free_dmar_iommu(struct intel_iommu *iommu)
 {
struct dmar_domain *domain;
-   int i, count;
-   unsigned long flags;
+   int i;
 
if ((iommu->domains) && (iommu->domain_ids)) {
for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
@@ -1481,11 +1482,7 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 
domain = iommu->domains[i];
clear_bit(i, iommu->domain_ids);
-
-   spin_lock_irqsave(&domain->iommu_lock, flags);
-   count = --domain->iommu_count;
-   spin_unlock_irqrestore(&domain->iommu_lock, flags);
-   if (count == 0)
+   if (domain_detach_iommu(domain, iommu) == 0)
domain_exit(domain);
}
}
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 04/22] iommu/vt-d: introduce helper functions to make code symmetric for readability

2014-04-22 Thread Jiang Liu
Introduce domain_attach_iommu()/domain_detach_iommu() and refine
iommu_attach_domain()/iommu_detach_domain() to make code symmetric
and improve readability.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |  146 ---
 1 file changed, 80 insertions(+), 66 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 63f351a39c63..29f613e7eea3 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1525,32 +1525,39 @@ static struct dmar_domain *alloc_domain(int flags)
return domain;
 }
 
-static int iommu_attach_domain(struct dmar_domain *domain,
-  struct intel_iommu *iommu)
+static int __iommu_attach_domain(struct dmar_domain *domain,
+struct intel_iommu *iommu)
 {
int num;
unsigned long ndomains;
-   unsigned long flags;
 
ndomains = cap_ndoms(iommu->cap);
-
-   spin_lock_irqsave(&iommu->lock, flags);
-
num = find_first_zero_bit(iommu->domain_ids, ndomains);
-   if (num >= ndomains) {
-   spin_unlock_irqrestore(&iommu->lock, flags);
-   printk(KERN_ERR "IOMMU: no free domain ids\n");
-   return -ENOMEM;
+   if (num < ndomains) {
+   set_bit(num, iommu->domain_ids);
+   iommu->domains[num] = domain;
+   } else {
+   num = -ENOSPC;
}
 
-   domain->id = num;
-   domain->iommu_count++;
-   set_bit(num, iommu->domain_ids);
-   set_bit(iommu->seq_id, domain->iommu_bmp);
-   iommu->domains[num] = domain;
+   return num;
+}
+
+static int iommu_attach_domain(struct dmar_domain *domain,
+  struct intel_iommu *iommu)
+{
+   int num;
+   unsigned long flags;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+   num = __iommu_attach_domain(domain, iommu);
+   if (num < 0)
+   pr_err("IOMMU: no free domain ids\n");
+   else
+   domain->id = num;
spin_unlock_irqrestore(&iommu->lock, flags);
 
-   return 0;
+   return num;
 }
 
 static void iommu_detach_domain(struct dmar_domain *domain,
@@ -1560,17 +1567,53 @@ static void iommu_detach_domain(struct dmar_domain 
*domain,
int num, ndomains;
 
spin_lock_irqsave(&iommu->lock, flags);
-   ndomains = cap_ndoms(iommu->cap);
-   for_each_set_bit(num, iommu->domain_ids, ndomains) {
-   if (iommu->domains[num] == domain) {
-   clear_bit(num, iommu->domain_ids);
-   iommu->domains[num] = NULL;
-   break;
+   if (domain_type_is_vm_or_si(domain)) {
+   ndomains = cap_ndoms(iommu->cap);
+   for_each_set_bit(num, iommu->domain_ids, ndomains) {
+   if (iommu->domains[num] == domain) {
+   clear_bit(num, iommu->domain_ids);
+   iommu->domains[num] = NULL;
+   break;
+   }
}
+   } else {
+   clear_bit(domain->id, iommu->domain_ids);
+   iommu->domains[domain->id] = NULL;
}
spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
+static void domain_attach_iommu(struct dmar_domain *domain,
+  struct intel_iommu *iommu)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(&domain->iommu_lock, flags);
+   if (!test_and_set_bit(iommu->seq_id, domain->iommu_bmp)) {
+   domain->iommu_count++;
+   if (domain->iommu_count == 1)
+   domain->nid = iommu->node;
+   domain_update_iommu_cap(domain);
+   }
+   spin_unlock_irqrestore(&domain->iommu_lock, flags);
+}
+
+static int domain_detach_iommu(struct dmar_domain *domain,
+  struct intel_iommu *iommu)
+{
+   unsigned long flags;
+   int count = INT_MAX;
+
+   spin_lock_irqsave(&domain->iommu_lock, flags);
+   if (test_and_clear_bit(iommu->seq_id, domain->iommu_bmp)) {
+   count = --domain->iommu_count;
+   domain_update_iommu_cap(domain);
+   }
+   spin_unlock_irqrestore(&domain->iommu_lock, flags);
+
+   return count;
+}
+
 static struct iova_domain reserved_iova_list;
 static struct lock_class_key reserved_rbtree_key;
 
@@ -1708,9 +1751,7 @@ static void domain_exit(struct dmar_domain *domain)
/* clear attached or cached domains */
rcu_read_lock();
for_each_active_iommu(iommu, drhd)
-   if (domain_type_is_vm(domain) ||
-   test_bit(iommu->seq_id, domain->iommu_bmp))
-   iommu_detach_domain(domain, iommu);
+   iommu_detach_domain(domain, iommu);
rcu_read_unlock();
 
dma_free_pagelist(freelist);
@@ -1764,16 +1805,12 @@ static int domain_context_mapping_one(struct 
dmar_

[Patch Part3 V1 05/22] iommu/vt-d: only dynamically allocate domain id for virtual domains

2014-04-22 Thread Jiang Liu
Check the same domain id is allocated for si_domain on each IOMMU,
otherwise the IOTLB flush for si_domain will fail.

Now the rules to allocate and manage domain id are:
1) For normal and static identity domains, domain id is allocated
   when creating domain structure. And this id will be written into
   context entry.
2) For virtual machine domain, a virtual id is allocated when creating
   domain. And when binding virtual machine domain to an iommu, a real
   domain id is allocated on demand and this domain id will be written
   into context entry. So domain->id for virtual machine domain may be
   different from the domain id written into context entry(used by
   hardware).

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |   46 ---
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 29f613e7eea3..0ab0cd236b16 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1551,15 +1551,27 @@ static int iommu_attach_domain(struct dmar_domain 
*domain,
 
spin_lock_irqsave(&iommu->lock, flags);
num = __iommu_attach_domain(domain, iommu);
+   spin_unlock_irqrestore(&iommu->lock, flags);
if (num < 0)
pr_err("IOMMU: no free domain ids\n");
-   else
-   domain->id = num;
-   spin_unlock_irqrestore(&iommu->lock, flags);
 
return num;
 }
 
+static int iommu_attach_vm_domain(struct dmar_domain *domain,
+ struct intel_iommu *iommu)
+{
+   int num;
+   unsigned long ndomains;
+
+   ndomains = cap_ndoms(iommu->cap);
+   for_each_set_bit(num, iommu->domain_ids, ndomains)
+   if (iommu->domains[num] == domain)
+   return num;
+
+   return __iommu_attach_domain(domain, iommu);
+}
+
 static void iommu_detach_domain(struct dmar_domain *domain,
struct intel_iommu *iommu)
 {
@@ -1766,8 +1778,6 @@ static int domain_context_mapping_one(struct dmar_domain 
*domain,
struct context_entry *context;
unsigned long flags;
struct dma_pte *pgd;
-   unsigned long num;
-   unsigned long ndomains;
int id;
int agaw;
struct device_domain_info *info = NULL;
@@ -1792,20 +1802,8 @@ static int domain_context_mapping_one(struct dmar_domain 
*domain,
pgd = domain->pgd;
 
if (domain_type_is_vm_or_si(domain)) {
-   int found = 0;
-
-   /* find an available domain id for this device in iommu */
-   ndomains = cap_ndoms(iommu->cap);
-   for_each_set_bit(num, iommu->domain_ids, ndomains) {
-   if (iommu->domains[num] == domain) {
-   id = num;
-   found = 1;
-   break;
-   }
-   }
-
-   if (found == 0) {
-   id = __iommu_attach_domain(domain, iommu);
+   if (domain_type_is_vm(domain)) {
+   id = iommu_attach_vm_domain(domain, iommu);
if (id < 0) {
spin_unlock_irqrestore(&iommu->lock, flags);
pr_err("IOMMU: no free domain ids\n");
@@ -2281,7 +2279,8 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
goto error;
-   if (iommu_attach_domain(domain, iommu) < 0) {
+   domain->id = iommu_attach_domain(domain, iommu);
+   if (domain->id < 0) {
free_domain_mem(domain);
domain = NULL;
goto error;
@@ -2442,6 +2441,7 @@ static int __init si_domain_init(int hw)
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
int nid, ret = 0;
+   bool first = true;
 
si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY);
if (!si_domain)
@@ -2452,6 +2452,12 @@ static int __init si_domain_init(int hw)
if (ret < 0) {
domain_exit(si_domain);
return -EFAULT;
+   } else if (first) {
+   si_domain->id = ret;
+   first = false;
+   } else if (si_domain->id != ret) {
+   domain_exit(si_domain);
+   return -EFAULT;
}
domain_attach_iommu(si_domain, iommu);
}
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 03/22] iommu/vt-d: introduce helper functions to improve code readability

2014-04-22 Thread Jiang Liu
Introduce domain_type_is_vm() and domain_type_is_vm_or_si() to improve
code readability.

Also kill useless macro DOMAIN_FLAG_P2P_MULTIPLE_DEVICES.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |   59 +++
 1 file changed, 26 insertions(+), 33 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 0b3e6981a2da..63f351a39c63 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -320,16 +320,13 @@ static inline int first_pte_in_page(struct dma_pte *pte)
 static struct dmar_domain *si_domain;
 static int hw_pass_through = 1;
 
-/* devices under the same p2p bridge are owned in one domain */
-#define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
-
 /* domain represents a virtual machine, more than one devices
  * across iommus may be owned in one domain, e.g. kvm guest.
  */
-#define DOMAIN_FLAG_VIRTUAL_MACHINE(1 << 1)
+#define DOMAIN_FLAG_VIRTUAL_MACHINE(1 << 0)
 
 /* si_domain contains mulitple devices */
-#define DOMAIN_FLAG_STATIC_IDENTITY(1 << 2)
+#define DOMAIN_FLAG_STATIC_IDENTITY(1 << 1)
 
 /* define the limit of IOMMUs supported in each domain */
 #ifdef CONFIG_X86
@@ -539,6 +536,16 @@ void free_iova_mem(struct iova *iova)
kmem_cache_free(iommu_iova_cache, iova);
 }
 
+static inline int domain_type_is_vm(struct dmar_domain *domain)
+{
+   return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE;
+}
+
+static inline int domain_type_is_vm_or_si(struct dmar_domain *domain)
+{
+   return domain->flags & (DOMAIN_FLAG_VIRTUAL_MACHINE |
+   DOMAIN_FLAG_STATIC_IDENTITY);
+}
 
 static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
 {
@@ -579,9 +586,7 @@ static struct intel_iommu *domain_get_iommu(struct 
dmar_domain *domain)
int iommu_id;
 
/* si_domain and vm domain should not get here. */
-   BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE);
-   BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY);
-
+   BUG_ON(domain_type_is_vm_or_si(domain));
iommu_id = find_first_bit(domain->iommu_bmp, g_num_of_iommus);
if (iommu_id < 0 || iommu_id >= g_num_of_iommus)
return NULL;
@@ -1499,7 +1504,7 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
free_context_table(iommu);
 }
 
-static struct dmar_domain *alloc_domain(bool vm)
+static struct dmar_domain *alloc_domain(int flags)
 {
/* domain id for virtual machine, it won't be set in context */
static atomic_t vm_domid = ATOMIC_INIT(0);
@@ -1509,16 +1514,13 @@ static struct dmar_domain *alloc_domain(bool vm)
if (!domain)
return NULL;
 
+   memset(domain, 0, sizeof(*domain));
domain->nid = -1;
-   domain->iommu_count = 0;
-   memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
-   domain->flags = 0;
+   domain->flags = flags;
spin_lock_init(&domain->iommu_lock);
INIT_LIST_HEAD(&domain->devices);
-   if (vm) {
+   if (flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
domain->id = atomic_inc_return(&vm_domid);
-   domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
-   }
 
return domain;
 }
@@ -1706,7 +1708,7 @@ static void domain_exit(struct dmar_domain *domain)
/* clear attached or cached domains */
rcu_read_lock();
for_each_active_iommu(iommu, drhd)
-   if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
+   if (domain_type_is_vm(domain) ||
test_bit(iommu->seq_id, domain->iommu_bmp))
iommu_detach_domain(domain, iommu);
rcu_read_unlock();
@@ -1748,8 +1750,7 @@ static int domain_context_mapping_one(struct dmar_domain 
*domain,
id = domain->id;
pgd = domain->pgd;
 
-   if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
-   domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) {
+   if (domain_type_is_vm_or_si(domain)) {
int found = 0;
 
/* find an available domain id for this device in iommu */
@@ -2115,7 +2116,7 @@ static void domain_remove_dev_info(struct dmar_domain 
*domain)
iommu_disable_dev_iotlb(info);
iommu_detach_dev(info->iommu, info->bus, info->devfn);
 
-   if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) {
+   if (domain_type_is_vm(domain)) {
iommu_detach_dependent_devices(info->iommu, info->dev);
/* clear this iommu in iommu_bmp, update iommu count
 * and capabilities
@@ -2181,8 +2182,6 @@ static struct dmar_domain *dmar_insert_dev_info(struct 
intel_iommu *iommu,
info->dev = dev;
info->domain = domain;
info->iommu = iommu;
-   if (!dev)
-   domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
 
spin_lock_irqsave(&device_domain_lock, flags);
if (dev)
@@ -2257,

[Patch Part3 V1 01/22] iommu/vt-d: match segment number when searching for dev_iotlb capable devices

2014-04-22 Thread Jiang Liu
For virtual machine and static identity domains, there may be devices
from different PCI segments associated with the same domain.
So function iommu_support_dev_iotlb() should also match PCI segment
number (iommu unit) when searching for dev_iotlb capable devices.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f256ffc02e29..612fd441b225 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1274,7 +1274,8 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, 
struct intel_iommu *iommu,
 
spin_lock_irqsave(&device_domain_lock, flags);
list_for_each_entry(info, &domain->devices, link)
-   if (info->bus == bus && info->devfn == devfn) {
+   if (info->iommu == iommu && info->bus == bus &&
+   info->devfn == devfn) {
found = 1;
break;
}
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[Patch Part3 V1 02/22] iommu/vt-d: use correct domain id to flush virtual machine domains

2014-04-22 Thread Jiang Liu
For virtual machine domains, domain->id is a virtual id, and the real
domain id written into context entry is dynamically allocated.
So use the real domain id instead of domain->id when flushing iotlbs
for virtual machine domains.

Signed-off-by: Jiang Liu 
---
 drivers/iommu/intel-iommu.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 612fd441b225..0b3e6981a2da 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1824,7 +1824,7 @@ static int domain_context_mapping_one(struct dmar_domain 
*domain,
   (((u16)bus) << 8) | devfn,
   DMA_CCMD_MASK_NOBIT,
   DMA_CCMD_DEVICE_INVL);
-   iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, 
DMA_TLB_DSI_FLUSH);
+   iommu->flush.flush_iotlb(iommu, id, 0, 0, DMA_TLB_DSI_FLUSH);
} else {
iommu_flush_write_buffer(iommu);
}
-- 
1.7.10.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu