Re: [PATCH v5 3/7] PCI: Introduce pci_real_dma_dev()

2020-01-22 Thread Bjorn Helgaas
On Tue, Jan 21, 2020 at 06:37:47AM -0700, Jon Derrick wrote:
> The current DMA alias implementation requires the aliased device be on
> the same PCI bus as the requester ID. This introduces an arch-specific
> mechanism to point to another PCI device when doing mapping and
> PCI DMA alias search. The default case returns the actual device.
> 
> CC: Christoph Hellwig 
> Signed-off-by: Jon Derrick 

Acked-by: Bjorn Helgaas 

Looks like a nice cleanup to me.

Lorenzo, let me know if you want me to take this.

> ---
>  arch/x86/pci/common.c | 10 ++
>  drivers/pci/pci.c | 19 ++-
>  drivers/pci/search.c  |  6 ++
>  include/linux/pci.h   |  1 +
>  4 files changed, 35 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
> index 1e59df0..fe21a5c 100644
> --- a/arch/x86/pci/common.c
> +++ b/arch/x86/pci/common.c
> @@ -736,3 +736,13 @@ int pci_ext_cfg_avail(void)
>   else
>   return 0;
>  }
> +
> +#if IS_ENABLED(CONFIG_VMD)
> +struct pci_dev *pci_real_dma_dev(struct pci_dev *dev)
> +{
> + if (is_vmd(dev->bus))
> + return to_pci_sysdata(dev->bus)->vmd_dev;
> +
> + return dev;
> +}
> +#endif
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 581b177..36d24f2 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -6048,7 +6048,9 @@ bool pci_devs_are_dma_aliases(struct pci_dev *dev1, 
> struct pci_dev *dev2)
>   return (dev1->dma_alias_mask &&
>   test_bit(dev2->devfn, dev1->dma_alias_mask)) ||
>  (dev2->dma_alias_mask &&
> - test_bit(dev1->devfn, dev2->dma_alias_mask));
> + test_bit(dev1->devfn, dev2->dma_alias_mask)) ||
> +pci_real_dma_dev(dev1) == dev2 ||
> +pci_real_dma_dev(dev2) == dev1;
>  }
>  
>  bool pci_device_is_present(struct pci_dev *pdev)
> @@ -6072,6 +6074,21 @@ void pci_ignore_hotplug(struct pci_dev *dev)
>  }
>  EXPORT_SYMBOL_GPL(pci_ignore_hotplug);
>  
> +/**
> + * pci_real_dma_dev - Get PCI DMA device for PCI device
> + * @dev: the PCI device that may have a PCI DMA alias
> + *
> + * Permits the platform to provide architecture-specific functionality to
> + * devices needing to alias DMA to another PCI device on another PCI bus. If
> + * the PCI device is on the same bus, it is recommended to use
> + * pci_add_dma_alias(). This is the default implementation. Architecture
> + * implementations can override this.
> + */
> +struct pci_dev __weak *pci_real_dma_dev(struct pci_dev *dev)
> +{
> + return dev;
> +}
> +
>  resource_size_t __weak pcibios_default_alignment(void)
>  {
>   return 0;
> diff --git a/drivers/pci/search.c b/drivers/pci/search.c
> index e4dbdef..2061672 100644
> --- a/drivers/pci/search.c
> +++ b/drivers/pci/search.c
> @@ -32,6 +32,12 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
>   struct pci_bus *bus;
>   int ret;
>  
> + /*
> +  * The device may have an explicit alias requester ID for DMA where the
> +  * requester is on another PCI bus.
> +  */
> + pdev = pci_real_dma_dev(pdev);
>   ret = fn(pdev, pci_dev_id(pdev), data);
>   if (ret)
>   return ret;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 930fab2..3840a54 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1202,6 +1202,7 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, 
> struct pci_dev **limiting_dev,
>  int pci_select_bars(struct pci_dev *dev, unsigned long flags);
>  bool pci_device_is_present(struct pci_dev *pdev);
>  void pci_ignore_hotplug(struct pci_dev *dev);
> +struct pci_dev *pci_real_dma_dev(struct pci_dev *dev);
>  
>  int __printf(6, 7) pci_request_irq(struct pci_dev *dev, unsigned int nr,
>   irq_handler_t handler, irq_handler_t thread_fn, void *dev_id,
> -- 
> 1.8.3.1
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [Patch v3 1/3] iommu: avoid unnecessary magazine allocations

2020-01-22 Thread Cong Wang
On Wed, Jan 22, 2020 at 9:07 AM Robin Murphy  wrote:
>
> On 21/01/2020 5:21 pm, Cong Wang wrote:
> > On Tue, Jan 21, 2020 at 3:11 AM Robin Murphy  wrote:
> >>
> >> On 18/12/2019 4:39 am, Cong Wang wrote:
> >>> The IOVA cache algorithm implemented in IOMMU code does not
> >>> exactly match the original algorithm described in the paper
> >>> "Magazines and Vmem: Extending the Slab Allocator to Many
> >>> CPUs and Arbitrary Resources".
> >>>
> >>> Particularly, it doesn't need to free the loaded empty magazine
> >>> when trying to put it back to global depot. To make it work, we
> >>> have to pre-allocate magazines in the depot and only recycle them
> >>> when all of them are full.
> >>>
> >>> Before this patch, rcache->depot[] contains either full or
> >>> freed entries, after this patch, it contains either full or
> >>> empty (but allocated) entries.
> >>
> >> How much additional memory overhead does this impose (particularly on
> >> systems that may have many domains mostly used for large, long-term
> >> mappings)? I'm wary that trying to micro-optimise for the "churn network
> >> packets as fast as possible" case may penalise every other case,
> >> potentially quite badly. Lower-end embedded systems are using IOMMUs in
> >> front of their GPUs, video codecs, etc. precisely because they *don't*
> >> have much memory to spare (and thus need to scrape together large
> >> buffers out of whatever pages they can find).
> >
> > The calculation is not complicated: 32 * 6 * 129 * 8 = 198144 bytes,
> > which is roughly 192K, per domain.
>
> Theoretically. On many architectures, kmalloc(1032,...) is going to
> consume rather more than 1032 bytes. Either way, it's rather a lot of
> memory to waste in the many cases where it will never be used at all.

If this is a concern, we can make IOVA_MAG_SIZE tunable in Kconfig.
I myself want a larger IOVA_MAG_SIZE at least for experiments.
You know, servers now have 100G+ memory, 192k is nearly nothing...


>
> >> But on the other hand, if we were to go down this route, then why is
> >> there any dynamic allocation/freeing left at all? Once both the depot
> >> and the rcaches are preallocated, then AFAICS it would make more sense
> >> to rework the overflow case in __iova_rcache_insert() to just free the
> >> IOVAs and swap the empty mag around rather than destroying and
> >> recreating it entirely.
> >
> > It's due to the algorithm requires a swap(), which can't be done with
> > statically allocated magzine. I had the same thought initially but gave it
> > up quickly when realized this.
>
> I'm not sure I follow... we're replacing a "full magazine" pointer with
> an "empty magazine" pointer regardless of where that empty magazine came
> from. It would be trivial to preallocate an 'overflow' magazine for the
> one remaining case of handling a full depot, although to be honest, at
> that point it's probably most efficient to just free the pfns directly
> from cpu_rcache->loaded while still under the percpu lock and be done
> with it.

I don't follow you either. I thought you are suggesting to completely
get rid of dynamic memory allocations like:

@@ -31,7 +31,7 @@ struct iova_cpu_rcache;
 struct iova_rcache {
spinlock_t lock;
unsigned long depot_size;
-   struct iova_magazine *depot[MAX_GLOBAL_MAGS];
+   struct iova_magazine depot[MAX_GLOBAL_MAGS];
struct iova_cpu_rcache __percpu *cpu_rcaches;
 };

If it is so, I don't see how I can do swap() with pointers like
cpu_rcache->prev.

More importantly, this doesn't save any memory either for your embedded
case. So I don't know why you want to bring it up.

>
> > If you are suggesting to change the algorithm, it is not a goal of this
> > patchset. I do have plan to search for a better algorithm as the IOMMU
> > performance still sucks (comparing to no IOMMU) after this patchset,
> > but once again, I do not want to change it in this patchset.
>
> "Still sucks" is probably the most interesting thing here - the headline
> number for the original patch series was that it reached about 98% of
> bypass performance on Intel VT-d[1]. Sounds like it would be well worth
> digging in to what's different about your system and/or workload.

Just FYI: The latency is 10x/20x worse with IOMMU enabled on AMD
servers here. (mlx5 driver for ethernet, if matters.) The throughput
is roughly same. The patchset you linked only measures throughput.


>
> > (My ultimate goal is to find a spinlock-free algorithm, otherwise there is
> > no way to make it close to no-IOMMU performance.)
> >
> >>
> >> Perhaps there's a reasonable compromise wherein we don't preallocate,
> >> but still 'free' empty magazines back to the depot, such that busy
> >> domains will quickly reach a steady-state. In fact, having now dug up
> >> the paper at this point of writing this reply, that appears to be what
> >> fig. 3.1b describes anyway - I don't see any mention of preallocating
> >> the depot.
> >
> > That paper missed a lot of things, it 

Re: [Patch v3 2/3] iommu: optimize iova_magazine_free_pfns()

2020-01-22 Thread Cong Wang
On Wed, Jan 22, 2020 at 9:34 AM Robin Murphy  wrote:
> Sorry, but without convincing evidence, this change just looks like
> churn for the sake of it.

The time I wasted on arguing with you isn't worth anything than
the value this patch brings. So let's just drop it to save some
time.

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


Re: [Patch v3 2/3] iommu: optimize iova_magazine_free_pfns()

2020-01-22 Thread Robin Murphy

On 21/01/2020 5:29 pm, Cong Wang wrote:

On Tue, Jan 21, 2020 at 1:52 AM Robin Murphy  wrote:


On 18/12/2019 4:39 am, Cong Wang wrote:

If the magazine is empty, iova_magazine_free_pfns() should
be a nop, however it misses the case of mag->size==0. So we
should just call iova_magazine_empty().

This should reduce the contention on iovad->iova_rbtree_lock
a little bit, not much at all.


Have you measured that in any way? AFAICS the only time this can get
called with a non-full magazine is in the CPU hotplug callback, where
the impact of taking the rbtree lock and immediately releasing it seems
unlikely to be significant on top of everything else involved in that
operation.


This patchset is only tested as a whole, it is not easy to deploy
each to production and test it separately.

Is there anything wrong to optimize a CPU hotplug path? :) And,
it is called in alloc_iova_fast() too when, for example, over-cached.


And if the IOVA space is consumed to the point that we've fallen back to 
that desperate last resort, what do you think the chances are that a 
significant number of percpu magazines will be *empty*? Also bear in 
mind that in that case we've already walked the rbtree once, so any 
notion of still being fast is long, long gone.


As for CPU hotplug, it's a comparatively rare event involving all manner 
of system-wide synchronisation, and the "optimisation" of shaving a few 
dozen CPU cycles off at one point *if* things happen to line up 
correctly is taking a cup of water out of a lake. If the domain is busy 
at the time, then once again chances are the magazines aren't empty and 
having an extra check redundant with the loop condition simply adds 
(trivial, but nonzero) overhead to every call. And if the domain isn't 
busy, then the lock is unlikely to be contended anyway.


Sorry, but without convincing evidence, this change just looks like 
churn for the sake of it.


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


Re: [PATCH v5 6/7] PCI: vmd: Stop overriding dma_map_ops

2020-01-22 Thread Keith Busch
On Tue, Jan 21, 2020 at 06:37:50AM -0700, Jon Derrick wrote:
> Devices on the VMD domain use the VMD endpoint's requester ID and have
> been relying on the VMD endpoint's DMA operations. The problem with this
> was that VMD domain devices would use the VMD endpoint's attributes when
> doing DMA and IOMMU mapping. We can be smarter about this by only using
> the VMD endpoint when mapping and providing the correct child device's
> attributes during DMA operations.
> 
> This patch removes the dma_map_ops redirect.
> 
> Signed-off-by: Jon Derrick 

Looks good.

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


Re: [PATCH] svm/avic: iommu/amd: Flush IOMMU IRT after update all entries

2020-01-22 Thread Paolo Bonzini
On 20/03/19 09:14, Suthikulpanit, Suravee wrote:
> When AVIC is enabled and the VM has discrete device assignment,
> the interrupt remapping table (IRT) is used to keep track of which
> destination APIC ID the IOMMU will inject the device interrput to.
> 
> This means every time a vcpu is blocked or context-switched (i.e.
> vcpu_blocking/unblocking() and vcpu_load/put()), the information
> in IRT must be updated and the IOMMU IRT flush command must be
> issued.
> 
> The current implementation flushes IOMMU IRT every time an entry
> is modified. If the assigned device has large number of interrupts
> (hence large number of entries), this would add large amount of
> overhead to vcpu context-switch. Instead, this can be optmized by
> only flush IRT once per vcpu context-switch per device after all
> IRT entries are modified.
> 
> The function amd_iommu_update_ga() is refactored to only update
> IRT entry, while the amd_iommu_sync_ga() is introduced to allow
> IRT flushing to be done separately.
> 
> Cc: Joerg Roedel 
> Cc: Radim Krčmář 
> Cc: Paolo Bonzini 
> Signed-off-by: Suravee Suthikulpanit 
> ---
>  arch/x86/kvm/svm.c| 35 ++-
>  drivers/iommu/amd_iommu.c | 20 +---
>  include/linux/amd-iommu.h | 13 ++---
>  3 files changed, 61 insertions(+), 7 deletions(-)

I found this patch in my inbox...  I'd rather avoid allocating 8k of RAM
per vCPU.  Can you make it per-VM?

Paolo

> + /*
> +  * Bitmap used to store PCI devid to sync
> +  * AMD IOMMU interrupt remapping table
> +  */
> + unsigned long *avic_devid_sync_bitmap;
>  };
>  
>  /*
> @@ -1984,6 +1992,7 @@ static inline int
>  avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu, bool r)
>  {
>   int ret = 0;
> + int devid = 0;
>   unsigned long flags;
>   struct amd_svm_iommu_ir *ir;
>   struct vcpu_svm *svm = to_svm(vcpu);
> @@ -2001,9 +2010,21 @@ avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, 
> int cpu, bool r)
>   goto out;
>  
>   list_for_each_entry(ir, >ir_list, node) {
> - ret = amd_iommu_update_ga(cpu, r, ir->data);
> + ret = amd_iommu_update_ga(cpu, r, ir->data, );
>   if (ret)
>   break;
> + set_bit(devid, svm->avic_devid_sync_bitmap);
> + }
> +
> + /* Sync AMD IOMMU interrupt remapping table changes for each device. */
> + devid = find_next_bit(svm->avic_devid_sync_bitmap,
> +   AVIC_DEVID_BITMAP_SIZE, 0);
> +
> + while (devid < AVIC_DEVID_BITMAP_SIZE) {
> + clear_bit(devid, svm->avic_devid_sync_bitmap);
> + ret = amd_iommu_sync_ga(devid);
> + devid = find_next_bit(svm->avic_devid_sync_bitmap,
> +   AVIC_DEVID_BITMAP_SIZE, devid+1);
>   }
>  out:
>   spin_unlock_irqrestore(>ir_list_lock, flags);
> @@ -2107,6 +2128,13 @@ static int avic_init_vcpu(struct vcpu_svm *svm)
>   INIT_LIST_HEAD(>ir_list);
>   spin_lock_init(>ir_list_lock);
>  
> + svm->avic_devid_sync_bitmap = (void *)__get_free_pages(
> + GFP_KERNEL | __GFP_ZERO,
> + get_order(AVIC_DEVID_BITMAP_SIZE/8));
> + if (svm->avic_devid_sync_bitmap == NULL)
> + ret = -ENOMEM;
> + memset(svm->avic_devid_sync_bitmap, 0, AVIC_DEVID_BITMAP_SIZE/8);
> +
>   return ret;
>  }
>  
> @@ -2221,6 +2249,11 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu)
>   __free_pages(virt_to_page(svm->msrpm), MSRPM_ALLOC_ORDER);
>   __free_page(virt_to_page(svm->nested.hsave));
>   __free_pages(virt_to_page(svm->nested.msrpm), MSRPM_ALLOC_ORDER);
> +
> + free_pages((unsigned long)svm->avic_devid_sync_bitmap,
> +get_order(AVIC_DEVID_BITMAP_SIZE/8));
> + svm->avic_devid_sync_bitmap = NULL;
> +
>   kvm_vcpu_uninit(vcpu);
>   kmem_cache_free(x86_fpu_cache, svm->vcpu.arch.guest_fpu);
>   kmem_cache_free(kvm_vcpu_cache, svm);
> diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
> index 2a7b78bb98b4..637bcc9192e5 100644
> --- a/drivers/iommu/amd_iommu.c
> +++ b/drivers/iommu/amd_iommu.c
> @@ -4499,7 +4499,20 @@ int amd_iommu_create_irq_domain(struct amd_iommu 
> *iommu)
>   return 0;
>  }
>  
> -int amd_iommu_update_ga(int cpu, bool is_run, void *data)
> +int amd_iommu_sync_ga(int devid)
> +{
> + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
> +
> + if (!iommu)
> + return -ENODEV;
> +
> + iommu_flush_irt(iommu, devid);
> + iommu_completion_wait(iommu);
> + return 0;
> +}
> +EXPORT_SYMBOL(amd_iommu_sync_ga);
> +
> +int amd_iommu_update_ga(int cpu, bool is_run, void *data, int *id)
>  {
>   unsigned long flags;
>   struct amd_iommu *iommu;
> @@ -4521,6 +4534,9 @@ int amd_iommu_update_ga(int cpu, bool is_run, void 
> *data)
>   if (!table)
>   return -ENODEV;
>  
> +   

[PATCH 1/1] iommu/amd: Remove the unnecessary assignment

2020-01-22 Thread Adrian Huang
From: Adrian Huang 

The assignment of the global variable 'iommu_detected' has been
moved from amd_iommu_init_dma_ops() to amd_iommu_detect(), so
this patch removes the assignment in amd_iommu_init_dma_ops().

Signed-off-by: Adrian Huang 
---
 drivers/iommu/amd_iommu.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index bd25674ee4db..79f08c0a1f00 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2297,7 +2297,6 @@ int __init amd_iommu_init_api(void)
 int __init amd_iommu_init_dma_ops(void)
 {
swiotlb= (iommu_default_passthrough() || sme_me_mask) ? 1 : 0;
-   iommu_detected = 1;
 
if (amd_iommu_unmap_flush)
pr_info("IO/TLB flush on unmap enabled\n");
-- 
2.17.1

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


[PATCH 0/3] iommu: Add Allwinner H6 IOMMU driver

2020-01-22 Thread Maxime Ripard
Hi,

Here's a series adding support for the IOMMU introduced in the Allwinner
H6. The driver from Allwinner hints at more SoCs using it in the future
(with more masters), so we can bet on that IOMMU becoming pretty much
standard in new SoCs from Allwinner.

One thing I wasn't really sure about was how to expose the statistics
reported by the IOMMU PMU (TLB hit rates, latencies, and so on). The
Allwinner driver exposes them through custom sysfs files, while they would
be best represented through perf I guess? Anyway, I'm planning to support
them later on.

Let me know what you think,
Maxime

Maxime Ripard (3):
  dt-bindings: iommu: Add Allwinner H6 IOMMU bindings
  iommu: Add Allwinner H6 IOMMU driver
  arm64: dts: allwinner: h6: Add IOMMU

 Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml |   61 
-
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi   |   11 
+-
 drivers/iommu/Kconfig  |   10 
+-
 drivers/iommu/Makefile |1 
+-
 drivers/iommu/sun50i-iommu.c   | 1126 
-
 5 files changed, 1209 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml
 create mode 100644 drivers/iommu/sun50i-iommu.c

base-commit: e42617b825f8073569da76dc4510bfa019b1c35a
-- 
git-series 0.9.1
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 3/3] arm64: dts: allwinner: h6: Add IOMMU

2020-01-22 Thread Maxime Ripard
Now that we have a driver for the IOMMU, let's start using it.

Signed-off-by: Maxime Ripard 
---
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi 
b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 29824081b43b..8608bcf1c52c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -53,6 +53,7 @@
de: display-engine {
compatible = "allwinner,sun50i-h6-display-engine";
allwinner,pipelines = <>;
+   iommus = < 0>;
status = "disabled";
};
 
@@ -122,6 +123,7 @@
clock-names = "bus",
  "mod";
resets = <_clocks RST_MIXER0>;
+   iommus = < 0>;
 
ports {
#address-cells = <1>;
@@ -345,6 +347,15 @@
#interrupt-cells = <3>;
};
 
+   iommu: iommu@30f {
+   compatible = "allwinner,sun50i-h6-iommu";
+   reg = <0x030f 0x1>;
+   interrupts = ;
+   clocks = < CLK_BUS_IOMMU>;
+   resets = < RST_BUS_IOMMU>;
+   #iommu-cells = <1>;
+   };
+
mmc0: mmc@402 {
compatible = "allwinner,sun50i-h6-mmc",
 "allwinner,sun50i-a64-mmc";
-- 
git-series 0.9.1
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 2/3] iommu: Add Allwinner H6 IOMMU driver

2020-01-22 Thread Maxime Ripard
The Allwinner H6 has introduced an IOMMU for a few DMA controllers, mostly
video related: the display engine, the video decoders / encoders, the
camera capture controller, etc.

The design is pretty simple compared to other IOMMUs found in SoCs: there's
a single instance, controlling all the masters, with a single address
space.

It also features a performance monitoring unit that allows to retrieve
various informations (per-master and global TLB accesses, hits and misses,
access latency, etc) that isn't supported at the moment.

Signed-off-by: Maxime Ripard 
---
 drivers/iommu/Kconfig|   10 +-
 drivers/iommu/Makefile   |1 +-
 drivers/iommu/sun50i-iommu.c | 1126 +++-
 3 files changed, 1137 insertions(+)
 create mode 100644 drivers/iommu/sun50i-iommu.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 0b9d78a0f3ac..5cbfa6f282e2 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -289,6 +289,16 @@ config ROCKCHIP_IOMMU
  Say Y here if you are using a Rockchip SoC that includes an IOMMU
  device.
 
+config SUN50I_IOMMU
+   bool "Allwinner H6 IOMMU Support"
+   depends on ARM || ARM64
+   depends on ARCH_SUNXI
+   select ARM_DMA_USE_IOMMU
+   select IOMMU_API
+   select IOMMU_DMA
+   help
+ Support for the IOMMU introduced in the Allwinner H6 SoCs.
+
 config TEGRA_IOMMU_GART
bool "Tegra GART IOMMU Support"
depends on ARCH_TEGRA_2x_SOC
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 97814cc861ea..43740a755786 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_MTK_IOMMU_V1) += mtk_iommu_v1.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
+obj-$(CONFIG_SUN50I_IOMMU) += sun50i-iommu.o
 obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
 obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
 obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c
new file mode 100644
index ..ffca92628006
--- /dev/null
+++ b/drivers/iommu/sun50i-iommu.c
@@ -0,0 +1,1126 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+// Copyright (C) 2016-2018, Allwinner Technology CO., LTD.
+// Copyright (C) 2019-2020, Cerno
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define IOMMU_RESET_REG0x010
+#define IOMMU_ENABLE_REG   0x020
+#define IOMMU_ENABLE_ENABLEBIT(0)
+
+#define IOMMU_BYPASS_REG   0x030
+#define IOMMU_AUTO_GATING_REG  0x040
+#define IOMMU_AUTO_GATING_ENABLE   BIT(0)
+
+#define IOMMU_WBUF_CTRL_REG0x044
+#define IOMMU_OOO_CTRL_REG 0x048
+#define IOMMU_4KB_BDY_PRT_CTRL_REG 0x04c
+#define IOMMU_TTB_REG  0x050
+#define IOMMU_TLB_ENABLE_REG   0x060
+#define IOMMU_TLB_PREFETCH_REG 0x070
+#define IOMMU_TLB_PREFETCH_MASTER_ENABLE(m)BIT(m)
+
+#define IOMMU_TLB_FLUSH_REG0x080
+#define IOMMU_TLB_FLUSH_PTW_CACHE  BIT(17)
+#define IOMMU_TLB_FLUSH_MACRO_TLB  BIT(16)
+#define IOMMU_TLB_FLUSH_MICRO_TLB(i)   (BIT(i) & GENMASK(5, 0))
+
+#define IOMMU_TLB_IVLD_ADDR_REG0x090
+#define IOMMU_TLB_IVLD_ADDR_MASK_REG   0x094
+#define IOMMU_TLB_IVLD_ENABLE_REG  0x098
+#define IOMMU_TLB_IVLD_ENABLE_ENABLE   BIT(0)
+
+#define IOMMU_PC_IVLD_ADDR_REG 0x0a0
+#define IOMMU_PC_IVLD_ENABLE_REG   0x0a8
+#define IOMMU_PC_IVLD_ENABLE_ENABLEBIT(0)
+
+#define IOMMU_DM_AUT_CTRL_REG(d)   (0x0b0 + ((d) / 2) * 4)
+#define IOMMU_DM_AUT_CTRL_RD_UNAVAIL(d, m) (1 << (((d & 1) * 16) + ((m) * 
2)))
+#define IOMMU_DM_AUT_CTRL_RD_AVAIL(d, m)   (0 << (((d & 1) * 16) + ((m) * 
2)))
+#define IOMMU_DM_AUT_CTRL_WR_UNAVAIL(d, m) (1 << (((d & 1) * 16) + ((m) * 
2) + 1))
+#define IOMMU_DM_AUT_CTRL_WR_AVAIL(d, m)   (0 << (((d & 1) * 16) + ((m) * 
2) + 1))
+
+#define IOMMU_DM_AUT_OVWT_REG  0x0d0
+#define IOMMU_INT_ENABLE_REG   0x100
+#define IOMMU_INT_CLR_REG  0x104
+#define IOMMU_INT_STA_REG  0x108
+#define IOMMU_INT_ERR_ADDR_REG(i)  (0x110 + (i) * 4)
+#define IOMMU_INT_ERR_ADDR_L1_REG  0x130
+#define IOMMU_INT_ERR_ADDR_L2_REG  0x134
+#define IOMMU_INT_ERR_DATA_REG(i)  (0x150 + (i) * 4)
+#define IOMMU_L1PG_INT_REG 0x0180
+#define IOMMU_L2PG_INT_REG 0x0184
+
+#define IOMMU_INT_INVALID_L2PG BIT(17)
+#define IOMMU_INT_INVALID_L1PG BIT(16)
+#define IOMMU_INT_MASTER_PERMISSION(m) BIT(m)
+#define IOMMU_INT_MASTER_MASK  

[PATCH 1/3] dt-bindings: iommu: Add Allwinner H6 IOMMU bindings

2020-01-22 Thread Maxime Ripard
The Allwinner H6 has introduced an IOMMU. Let's add a device tree binding
for it.

Signed-off-by: Maxime Ripard 
---
 Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml | 61 
+
 1 file changed, 61 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml

diff --git 
a/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml 
b/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml
new file mode 100644
index ..5e125cf2a88b
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iommu/allwinner,sun50i-h6-iommu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner H6 IOMMU Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai 
+  - Maxime Ripard 
+
+properties:
+  "#iommu-cells":
+const: 1
+description:
+  The content of the cell is the master ID.
+
+  compatible:
+const: allwinner,sun50i-h6-iommu
+
+  reg:
+maxItems: 1
+
+  interrupts:
+maxItems: 1
+
+  clocks:
+maxItems: 1
+
+  resets:
+maxItems: 1
+
+required:
+  - "#iommu-cells"
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+  #include 
+  #include 
+
+  #include 
+  #include 
+
+  iommu: iommu@30f {
+  compatible = "allwinner,sun50i-h6-iommu";
+  reg = <0x030f 0x1>;
+  interrupts = ;
+  clocks = < CLK_BUS_IOMMU>;
+  resets = < RST_BUS_IOMMU>;
+  #iommu-cells = <1>;
+  };
+
+...
-- 
git-series 0.9.1
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 0/2] iommu/arm-smmu: Allow client devices to select direct mapping

2020-01-22 Thread Sai Prakash Ranjan
This series allows drm devices to set a default identity
mapping using iommu_request_dm_for_dev(). First patch is
a cleanup to support other SoCs to call into QCOM specific
implementation and preparation for second patch.
Second patch sets the default identity domain for drm devices.

Jordan Crouse (1):
  iommu/arm-smmu: Allow client devices to select direct mapping

Sai Prakash Ranjan (1):
  iommu: arm-smmu-impl: Convert to a generic reset implementation

 drivers/iommu/arm-smmu-impl.c |  8 +++--
 drivers/iommu/arm-smmu-qcom.c | 55 +--
 drivers/iommu/arm-smmu.c  |  3 ++
 drivers/iommu/arm-smmu.h  |  5 
 4 files changed, 65 insertions(+), 6 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 2/2] iommu/arm-smmu: Allow client devices to select direct mapping

2020-01-22 Thread Sai Prakash Ranjan
From: Jordan Crouse 

Some client devices want to directly map the IOMMU themselves instead
of using the DMA domain. Allow those devices to opt in to direct
mapping by way of a list of compatible strings.

Signed-off-by: Jordan Crouse 
Co-developed-by: Sai Prakash Ranjan 
Signed-off-by: Sai Prakash Ranjan 
---
 drivers/iommu/arm-smmu-qcom.c | 39 +++
 drivers/iommu/arm-smmu.c  |  3 +++
 drivers/iommu/arm-smmu.h  |  5 +
 3 files changed, 47 insertions(+)

diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c
index 64a4ab270ab7..ff746acd1c81 100644
--- a/drivers/iommu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm-smmu-qcom.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
  */
 
+#include 
 #include 
 
 #include "arm-smmu.h"
@@ -11,6 +12,43 @@ struct qcom_smmu {
struct arm_smmu_device smmu;
 };
 
+static const struct arm_smmu_client_match_data qcom_adreno = {
+   .direct_mapping = true,
+};
+
+static const struct arm_smmu_client_match_data qcom_mdss = {
+   .direct_mapping = true,
+};
+
+static const struct of_device_id qcom_smmu_client_of_match[] = {
+   { .compatible = "qcom,adreno", .data = _adreno },
+   { .compatible = "qcom,mdp4", .data = _mdss },
+   { .compatible = "qcom,mdss", .data = _mdss },
+   { .compatible = "qcom,sc7180-mdss", .data = _mdss },
+   { .compatible = "qcom,sdm845-mdss", .data = _mdss },
+   {},
+};
+
+static const struct arm_smmu_client_match_data *
+qcom_smmu_client_data(struct device *dev)
+{
+   const struct of_device_id *match =
+   of_match_device(qcom_smmu_client_of_match, dev);
+
+   return match ? match->data : NULL;
+}
+
+static int qcom_smmu_request_domain(struct device *dev)
+{
+   const struct arm_smmu_client_match_data *client;
+
+   client = qcom_smmu_client_data(dev);
+   if (client)
+   iommu_request_dm_for_dev(dev);
+
+   return 0;
+}
+
 static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
 {
int ret;
@@ -41,6 +79,7 @@ static int qcom_smmu500_reset(struct arm_smmu_device *smmu)
 }
 
 static const struct arm_smmu_impl qcom_smmu_impl = {
+   .req_domain = qcom_smmu_request_domain,
.reset = qcom_smmu500_reset,
 };
 
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 16c4b87af42b..67dd9326247a 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1448,6 +1448,9 @@ static int arm_smmu_add_device(struct device *dev)
device_link_add(dev, smmu->dev,
DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER);
 
+   if (smmu->impl && smmu->impl->req_domain)
+   return smmu->impl->req_domain(dev);
+
return 0;
 
 out_cfg_free:
diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h
index 8d1cd54d82a6..059dc9c39f64 100644
--- a/drivers/iommu/arm-smmu.h
+++ b/drivers/iommu/arm-smmu.h
@@ -244,6 +244,10 @@ enum arm_smmu_arch_version {
ARM_SMMU_V2,
 };
 
+struct arm_smmu_client_match_data {
+   bool direct_mapping;
+};
+
 enum arm_smmu_implementation {
GENERIC_SMMU,
ARM_MMU500,
@@ -386,6 +390,7 @@ struct arm_smmu_impl {
int (*init_context)(struct arm_smmu_domain *smmu_domain);
void (*tlb_sync)(struct arm_smmu_device *smmu, int page, int sync,
 int status);
+   int (*req_domain)(struct device *dev);
 };
 
 static inline void __iomem *arm_smmu_page(struct arm_smmu_device *smmu, int n)
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 1/2] iommu: arm-smmu-impl: Convert to a generic reset implementation

2020-01-22 Thread Sai Prakash Ranjan
Currently the QCOM specific smmu reset implementation is very
specific to SDM845 SoC and has a wait-for-safe logic which
may not be required for other SoCs. So move the SDM845 specific
logic to its specific reset function. Also add SC7180 SMMU
compatible for calling into QCOM specific implementation.

Signed-off-by: Sai Prakash Ranjan 
---
 drivers/iommu/arm-smmu-impl.c |  8 +---
 drivers/iommu/arm-smmu-qcom.c | 16 +---
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/arm-smmu-impl.c b/drivers/iommu/arm-smmu-impl.c
index 74d97a886e93..c75b9d957b70 100644
--- a/drivers/iommu/arm-smmu-impl.c
+++ b/drivers/iommu/arm-smmu-impl.c
@@ -150,6 +150,8 @@ static const struct arm_smmu_impl arm_mmu500_impl = {
 
 struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
 {
+   const struct device_node *np = smmu->dev->of_node;
+
/*
 * We will inevitably have to combine model-specific implementation
 * quirks with platform-specific integration quirks, but everything
@@ -166,11 +168,11 @@ struct arm_smmu_device *arm_smmu_impl_init(struct 
arm_smmu_device *smmu)
break;
}
 
-   if (of_property_read_bool(smmu->dev->of_node,
- "calxeda,smmu-secure-config-access"))
+   if (of_property_read_bool(np, "calxeda,smmu-secure-config-access"))
smmu->impl = _impl;
 
-   if (of_device_is_compatible(smmu->dev->of_node, "qcom,sdm845-smmu-500"))
+   if (of_device_is_compatible(np, "qcom,sdm845-smmu-500") ||
+   of_device_is_compatible(np, "qcom,sc7180-smmu-500"))
return qcom_smmu_impl_init(smmu);
 
return smmu;
diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c
index 24c071c1d8b0..64a4ab270ab7 100644
--- a/drivers/iommu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm-smmu-qcom.c
@@ -15,8 +15,6 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device 
*smmu)
 {
int ret;
 
-   arm_mmu500_reset(smmu);
-
/*
 * To address performance degradation in non-real time clients,
 * such as USB and UFS, turn off wait-for-safe on sdm845 based boards,
@@ -30,8 +28,20 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device 
*smmu)
return ret;
 }
 
+static int qcom_smmu500_reset(struct arm_smmu_device *smmu)
+{
+   const struct device_node *np = smmu->dev->of_node;
+
+   arm_mmu500_reset(smmu);
+
+   if (of_device_is_compatible(np, "qcom,sdm845-smmu-500"))
+   return qcom_sdm845_smmu500_reset(smmu);
+
+   return 0;
+}
+
 static const struct arm_smmu_impl qcom_smmu_impl = {
-   .reset = qcom_sdm845_smmu500_reset,
+   .reset = qcom_smmu500_reset,
 };
 
 struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu)
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] iommu/arm-smmu-v3: Batch ATC invalidation commands

2020-01-22 Thread Jean-Philippe Brucker
Hi Rob,

On Mon, Jan 13, 2020 at 08:39:06AM -0600, Rob Herring wrote:
> Similar to commit 2af2e72b18b4 ("iommu/arm-smmu-v3: Defer TLB
> invalidation until ->iotlb_sync()"), build up a list of ATC invalidation
> commands and submit them all at once to the command queue instead of
> one-by-one.
> 
> Cc: Jean-Philippe Brucker 
> Cc: Will Deacon 
> Cc: Robin Murphy 
> Cc: Joerg Roedel 
> Signed-off-by: Rob Herring 
> ---
>  drivers/iommu/arm-smmu-v3.c | 23 +++
>  1 file changed, 19 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
> index effe72eb89e7..e91b4a098215 100644
> --- a/drivers/iommu/arm-smmu-v3.c
> +++ b/drivers/iommu/arm-smmu-v3.c
> @@ -1919,10 +1919,11 @@ static int arm_smmu_atc_inv_master(struct 
> arm_smmu_master *master,
>  static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
>  int ssid, unsigned long iova, size_t size)
>  {
> - int ret = 0;
> + int i, cmdn = 0;
>   unsigned long flags;
>   struct arm_smmu_cmdq_ent cmd;
>   struct arm_smmu_master *master;
> + u64 cmds[CMDQ_BATCH_ENTRIES * CMDQ_ENT_DWORDS];
>  
>   if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
>   return 0;
> @@ -1947,11 +1948,25 @@ static int arm_smmu_atc_inv_domain(struct 
> arm_smmu_domain *smmu_domain,
>   arm_smmu_atc_inv_to_cmd(ssid, iova, size, );
>  
>   spin_lock_irqsave(_domain->devices_lock, flags);
> - list_for_each_entry(master, _domain->devices, domain_head)
> - ret |= arm_smmu_atc_inv_master(master, );

It may be worth reworking arm_smmu_atc_inv_master() as well since it's now
only called by arm_smmu_disable_ats() to invalidate the whole ATC. I don't
think it requires batching (it's not on any fast path and num_sids will
almost always be 1), but it doesn't need the cmd argument anymore.

Thanks,
Jean

> + list_for_each_entry(master, _domain->devices, domain_head) {
> + if (!master->ats_enabled)
> + continue;
> +
> + for (i = 0; i < master->num_sids; i++) {
> + if (cmdn == CMDQ_BATCH_ENTRIES) {
> + arm_smmu_cmdq_issue_cmdlist(smmu_domain->smmu,
> + cmds, cmdn, false);
> + cmdn = 0;
> + }
> +
> + cmd.atc.sid = master->sids[i];
> + arm_smmu_cmdq_build_cmd([cmdn * CMDQ_ENT_DWORDS], 
> );
> + cmdn++;
> + }
> + }
>   spin_unlock_irqrestore(_domain->devices_lock, flags);
>  
> - return ret ? -ETIMEDOUT : 0;
> + return arm_smmu_cmdq_issue_cmdlist(smmu_domain->smmu, cmds, cmdn, true);
>  }
>  
>  /* IO_PGTABLE API */
> -- 
> 2.20.1
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu