Re: [PATCH] firmware: QCOM_SCM: Allow qcom_scm driver to be loadable as a permenent module

2021-07-16 Thread Bjorn Andersson
On Tue 06 Jul 23:53 CDT 2021, John Stultz wrote:

> Allow the qcom_scm driver to be loadable as a permenent module.
> 
> This still uses the "depends on QCOM_SCM || !QCOM_SCM" bit to
> ensure that drivers that call into the qcom_scm driver are
> also built as modules. While not ideal in some cases its the
> only safe way I can find to avoid build errors without having
> those drivers select QCOM_SCM and have to force it on (as
> QCOM_SCM=n can be valid for those drivers).
> 
> Reviving this now that Saravana's fw_devlink defaults to on,
> which should avoid loading troubles seen before.
> 

Are you (in this last paragraph) saying that all those who have been
burnt by fw_devlink during the last months and therefor run with it
disabled will have a less fun experience once this is merged?


(I'm picking this up, but I don't fancy the idea that some people are
turning the boot process into a lottery)

Regards,
Bjorn

> Cc: Catalin Marinas 
> Cc: Will Deacon 
> Cc: Andy Gross 
> Cc: Bjorn Andersson 
> Cc: Joerg Roedel 
> Cc: Thomas Gleixner 
> Cc: Marc Zyngier 
> Cc: Linus Walleij 
> Cc: Vinod Koul 
> Cc: Kalle Valo 
> Cc: Maulik Shah 
> Cc: Saravana Kannan 
> Cc: Todd Kjos 
> Cc: Greg Kroah-Hartman 
> Cc: linux-arm-...@vger.kernel.org
> Cc: iommu@lists.linux-foundation.org
> Cc: linux-g...@vger.kernel.org
> Acked-by: Kalle Valo 
> Acked-by: Greg Kroah-Hartman 
> Acked-by: Will Deacon 
> Reviewed-by: Bjorn Andersson 
> Signed-off-by: John Stultz 
> ---
> v3:
> * Fix __arm_smccc_smc build issue reported by
>   kernel test robot 
> v4:
> * Add "depends on QCOM_SCM || !QCOM_SCM" bit to ath10k
>   config that requires it.
> v5:
> * Fix QCOM_QCM typo in Kconfig, it should be QCOM_SCM
> ---
>  drivers/firmware/Kconfig| 2 +-
>  drivers/firmware/Makefile   | 3 ++-
>  drivers/firmware/qcom_scm.c | 4 
>  drivers/iommu/Kconfig   | 2 ++
>  drivers/net/wireless/ath/ath10k/Kconfig | 1 +
>  5 files changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
> index db0ea2d2d75a..af53778edc7e 100644
> --- a/drivers/firmware/Kconfig
> +++ b/drivers/firmware/Kconfig
> @@ -235,7 +235,7 @@ config INTEL_STRATIX10_RSU
> Say Y here if you want Intel RSU support.
>  
>  config QCOM_SCM
> - bool
> + tristate "Qcom SCM driver"
>   depends on ARM || ARM64
>   depends on HAVE_ARM_SMCCC
>   select RESET_CONTROLLER
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> index 5e013b6a3692..523173cbff33 100644
> --- a/drivers/firmware/Makefile
> +++ b/drivers/firmware/Makefile
> @@ -17,7 +17,8 @@ obj-$(CONFIG_ISCSI_IBFT)+= iscsi_ibft.o
>  obj-$(CONFIG_FIRMWARE_MEMMAP)+= memmap.o
>  obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
>  obj-$(CONFIG_FW_CFG_SYSFS)   += qemu_fw_cfg.o
> -obj-$(CONFIG_QCOM_SCM)   += qcom_scm.o qcom_scm-smc.o 
> qcom_scm-legacy.o
> +obj-$(CONFIG_QCOM_SCM)   += qcom-scm.o
> +qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
>  obj-$(CONFIG_TI_SCI_PROTOCOL)+= ti_sci.o
>  obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
>  obj-$(CONFIG_TURRIS_MOX_RWTM)+= turris-mox-rwtm.o
> diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
> index ee9cb545e73b..bb9ce3f92931 100644
> --- a/drivers/firmware/qcom_scm.c
> +++ b/drivers/firmware/qcom_scm.c
> @@ -1296,6 +1296,7 @@ static const struct of_device_id qcom_scm_dt_match[] = {
>   { .compatible = "qcom,scm" },
>   {}
>  };
> +MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
>  
>  static struct platform_driver qcom_scm_driver = {
>   .driver = {
> @@ -1312,3 +1313,6 @@ static int __init qcom_scm_init(void)
>   return platform_driver_register(&qcom_scm_driver);
>  }
>  subsys_initcall(qcom_scm_init);
> +
> +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SCM driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index 07b7c25cbed8..f61516c17589 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -253,6 +253,7 @@ config SPAPR_TCE_IOMMU
>  config ARM_SMMU
>   tristate "ARM Ltd. System MMU (SMMU) Support"
>   depends on ARM64 || ARM || (COMPILE_TEST && !GENERIC_ATOMIC64)
> + depends on QCOM_SCM || !QCOM_SCM #if QCOM_SCM=m this can't be =y
>   select IOMMU_API
>   select IOMMU_IO_PGTABLE_LPAE
>   select ARM_DMA_USE_IOMMU if ARM
> @@ -382,6 +383,7 @@ config QCOM_IOMMU
>   # Note: iommu drivers cannot (yet?) be built as modules
>   bool "Qualcomm IOMMU Support"
>   depends on ARCH_QCOM || (COMPILE_TEST && !GENERIC_ATOMIC64)
> + depends on QCOM_SCM=y
>   select IOMMU_API
>   select IOMMU_IO_PGTABLE_LPAE
>   select ARM_DMA_USE_IOMMU
> diff --git a/drivers/net/wireless/ath/ath10k/Kconfig 
> b/drivers/net/wireless/ath/ath10k/Kconfig
> index 40f91bc8514d..741289e385d5 100644
> --- a/drivers/net/wireless/ath/ath10k/Kconf

Re: [PATCH v6 8/9] iommu/arm-smmu: Get associated RMR info and install bypass SMR

2021-07-16 Thread Jon Nettleton
On Fri, Jul 16, 2021 at 3:52 PM Steven Price  wrote:
>
> On 16/07/2021 09:34, Shameer Kolothum wrote:
> > From: Jon Nettleton 
> >
> > Check if there is any RMR info associated with the devices behind
> > the SMMU and if any, install bypass SMRs for them. This is to
> > keep any ongoing traffic associated with these devices alive
> > when we enable/reset SMMU during probe().
> >
> > Signed-off-by: Jon Nettleton 
> > Signed-off-by: Steven Price 
> > Signed-off-by: Shameer Kolothum 
> > ---
> >  drivers/iommu/arm/arm-smmu/arm-smmu.c | 48 +++
> >  1 file changed, 48 insertions(+)
> >
> > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
> > b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> > index f22dbeb1e510..e9fb3d962a86 100644
> > --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
> > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> > @@ -2063,6 +2063,50 @@ err_reset_platform_ops: __maybe_unused;
> >   return err;
> >  }
> >
> > +static void arm_smmu_rmr_install_bypass_smr(struct arm_smmu_device *smmu)
> > +{
> > + struct list_head rmr_list;
> > + struct iommu_resv_region *e;
> > + int i, cnt = 0;
> > + u32 reg;
> > +
> > + INIT_LIST_HEAD(&rmr_list);
> > + if (iommu_dma_get_rmrs(dev_fwnode(smmu->dev), &rmr_list))
> > + return;
> > +
> > + /*
> > +  * Rather than trying to look at existing mappings that
> > +  * are setup by the firmware and then invalidate the ones
> > +  * that do no have matching RMR entries, just disable the
> > +  * SMMU until it gets enabled again in the reset routine.
> > +  */
> > + reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sCR0);
> > + reg &= ~ARM_SMMU_sCR0_CLIENTPD;
>
> This looks backwards, the spec states:
>
>   Client Port Disable. The possible values of this bit are:
>   0 - Each SMMU client access is subject to SMMU translation, access
>   control, and attribute generation.
>   1 - Each SMMU client access bypasses SMMU translation, access control,
>   and attribute generation.
>   This bit resets to 1.
>
> And indeed with the current code if sCR0_USFCFG was set when
> sCR0_CLIENTPD is cleared then I get a blank screen until the smmu is reset.
>
> So I believe this should be ORing in the value, i.e.
>
>   reg |= ARM_SMMU_sCR0_CLIENTPD;
>
> And in my testing that works fine even if sCR0_USFCFG is set.

Sorry that is my bad.  It was a hurried and sloppy copy paste on my part.

Thanks for catching it
-Jon

>
> Steve
>
> > + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, reg);
> > +
> > + list_for_each_entry(e, &rmr_list, list) {
> > + u32 sid = e->fw_data.rmr.sid;
> > +
> > + i = arm_smmu_find_sme(smmu, sid, ~0);
> > + if (i < 0)
> > + continue;
> > + if (smmu->s2crs[i].count == 0) {
> > + smmu->smrs[i].id = sid;
> > + smmu->smrs[i].mask = 0;
> > + smmu->smrs[i].valid = true;
> > + }
> > + smmu->s2crs[i].count++;
> > + smmu->s2crs[i].type = S2CR_TYPE_BYPASS;
> > + smmu->s2crs[i].privcfg = S2CR_PRIVCFG_DEFAULT;
> > +
> > + cnt++;
> > + }
> > +
> > + dev_notice(smmu->dev, "\tpreserved %d boot mapping%s\n", cnt,
> > +cnt == 1 ? "" : "s");
> > + iommu_dma_put_rmrs(dev_fwnode(smmu->dev), &rmr_list);
> > +}
> > +
> >  static int arm_smmu_device_probe(struct platform_device *pdev)
> >  {
> >   struct resource *res;
> > @@ -2189,6 +2233,10 @@ static int arm_smmu_device_probe(struct 
> > platform_device *pdev)
> >   }
> >
> >   platform_set_drvdata(pdev, smmu);
> > +
> > + /* Check for RMRs and install bypass SMRs if any */
> > + arm_smmu_rmr_install_bypass_smr(smmu);
> > +
> >   arm_smmu_device_reset(smmu);
> >   arm_smmu_test_smr_masks(smmu);
> >
> >
>
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RFC v2] /dev/iommu uAPI proposal

2021-07-16 Thread Jason Gunthorpe via iommu
On Fri, Jul 16, 2021 at 01:20:15AM +, Tian, Kevin wrote:

> One thought is to have vfio device driver deal with it. In this proposal
> it is the vfio device driver to define the PASID virtualization policy and
> report it to userspace via VFIO_DEVICE_GET_INFO. The driver understands
> the restriction thus could just hide the vPASID capability when the user 
> calls GET_INFO on the 2nd mdev in above scenario. In this way the 
> user even doesn't need to know such restriction at all and both mdevs
> can be assigned to a single VM w/o any problem.

I think it makes more sense to expose some kind of "pasid group" to
qemu that identifies that each PASID must be unique across the
group. For vIOMMUs that are doing funky things with the RID This means
a single PASID group must not be exposed as two RIDs to the guest.

If the kernel blocks it then it can never be fixed by updating the
vIOMMU design.

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


Re: [PATCH v1 16/16] dma-mapping: Disallow .map_sg operations from returning zero on error

2021-07-16 Thread Logan Gunthorpe



On 2021-07-16 12:33 a.m., Christoph Hellwig wrote:
> On Thu, Jul 15, 2021 at 10:45:44AM -0600, Logan Gunthorpe wrote:
>> @@ -194,6 +194,8 @@ static int __dma_map_sg_attrs(struct device *dev, struct 
>> scatterlist *sg,
>>  else
>>  ents = ops->map_sg(dev, sg, nents, dir, attrs);
>>  
>> +WARN_ON_ONCE(ents == 0);
> 
> Turns this into a negative error code while we're at it, just to keep
> the callers sane?
> 

Sure thing. All the feedback makes sense, we'll fix it up and send a v2
in due course.

Thanks,

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


Re: [PATCH v4 0/3] Apple M1 DART IOMMU driver

2021-07-16 Thread Robin Murphy

On 2021-07-16 07:24, Christoph Hellwig wrote:

On Wed, Jul 14, 2021 at 07:19:50PM +0100, Robin Murphy wrote:

Even at the DMA API level you could hide *some* of it (at the cost of
effectively only having 1/4 of the usable address space), but there are
still cases like where v4l2 has a hard requirement that a page-aligned
scatterlist can be mapped into a contiguous region of DMA addresses.


Where does v4l2 make that broken assumption?  Plenty of dma mapping
implementations including dma-direct do not support that.


See vb2_dc_get_contiguous_size() and its callers. I still remember 
spending an entire work day on writing one email at the culmination of 
this discussion:


https://lore.kernel.org/linux-iommu/56409b6d.5090...@arm.com/

809eac54cdd6 was framed as an efficiency improvement because it 
technically was one (and something I had wanted to implement anyway), 
but it was also very much to save myself from any further email debates 
or customer calls about "regressing" code ported from 32-bit platforms...


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


Re: [PATCH v2] dma-mapping: use vmalloc_to_page for vmalloc addresses

2021-07-16 Thread Stefano Stabellini
On Fri, 16 Jul 2021, Roman Skakun wrote:
> > Technically this looks good.  But given that exposing a helper
> > that does either vmalloc_to_page or virt_to_page is one of the
> > never ending MM discussions I don't want to get into that discussion
> > and just keep it local in the DMA code.
> >
> > Are you fine with me applying this version?
> 
> Looks good to me, thanks!
> But, Stefano asked me about using created helper in the
> xen_swiotlb_free_coherent()
> and I created a patch according to this mention.
> 
> We can merge this patch and create a new one for
> xen_swiotlb_free_coherent() later.

Yeah, no worries, I didn't know that exposing dma_common_vaddr_to_page
was problematic.

This patch is fine by me.


> пт, 16 июл. 2021 г. в 12:35, Christoph Hellwig :
> >
> > Technically this looks good.  But given that exposing a helper
> > that does either vmalloc_to_page or virt_to_page is one of the
> > never ending MM discussions I don't want to get into that discussion
> > and just keep it local in the DMA code.
> >
> > Are you fine with me applying this version?
> >
> > ---
> > From 40ac971eab89330d6153e7721e88acd2d98833f9 Mon Sep 17 00:00:00 2001
> > From: Roman Skakun 
> > Date: Fri, 16 Jul 2021 11:39:34 +0300
> > Subject: dma-mapping: handle vmalloc addresses in
> >  dma_common_{mmap,get_sgtable}
> >
> > xen-swiotlb can use vmalloc backed addresses for dma coherent allocations
> > and uses the common helpers.  Properly handle them to unbreak Xen on
> > ARM platforms.
> >
> > Fixes: 1b65c4e5a9af ("swiotlb-xen: use xen_alloc/free_coherent_pages")
> > Signed-off-by: Roman Skakun 
> > Reviewed-by: Andrii Anisov 
> > [hch: split the patch, renamed the helpers]
> > Signed-off-by: Christoph Hellwig 
> > ---
> >  kernel/dma/ops_helpers.c | 12 ++--
> >  1 file changed, 10 insertions(+), 2 deletions(-)
> >
> > diff --git a/kernel/dma/ops_helpers.c b/kernel/dma/ops_helpers.c
> > index 910ae69cae77..af4a6ef48ce0 100644
> > --- a/kernel/dma/ops_helpers.c
> > +++ b/kernel/dma/ops_helpers.c
> > @@ -5,6 +5,13 @@
> >   */
> >  #include 
> >
> > +static struct page *dma_common_vaddr_to_page(void *cpu_addr)
> > +{
> > +   if (is_vmalloc_addr(cpu_addr))
> > +   return vmalloc_to_page(cpu_addr);
> > +   return virt_to_page(cpu_addr);
> > +}
> > +
> >  /*
> >   * Create scatter-list for the already allocated DMA buffer.
> >   */
> > @@ -12,7 +19,7 @@ int dma_common_get_sgtable(struct device *dev, struct 
> > sg_table *sgt,
> >  void *cpu_addr, dma_addr_t dma_addr, size_t size,
> >  unsigned long attrs)
> >  {
> > -   struct page *page = virt_to_page(cpu_addr);
> > +   struct page *page = dma_common_vaddr_to_page(cpu_addr);
> > int ret;
> >
> > ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
> > @@ -32,6 +39,7 @@ int dma_common_mmap(struct device *dev, struct 
> > vm_area_struct *vma,
> > unsigned long user_count = vma_pages(vma);
> > unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
> > unsigned long off = vma->vm_pgoff;
> > +   struct page *page = dma_common_vaddr_to_page(cpu_addr);
> > int ret = -ENXIO;
> >
> > vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
> > @@ -43,7 +51,7 @@ int dma_common_mmap(struct device *dev, struct 
> > vm_area_struct *vma,
> > return -ENXIO;
> >
> > return remap_pfn_range(vma, vma->vm_start,
> > -   page_to_pfn(virt_to_page(cpu_addr)) + vma->vm_pgoff,
> > +   page_to_pfn(page) + vma->vm_pgoff,
> > user_count << PAGE_SHIFT, vma->vm_page_prot);
> >  #else
> > return -ENXIO;
> > --
> > 2.30.2
> >
> 
> 
> -- 
> Best Regards, Roman.
> ___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH v2 2/5] iommu: Implement of_iommu_get_resv_regions()

2021-07-16 Thread Rob Herring
On Fri, Jul 2, 2021 at 8:05 AM Dmitry Osipenko  wrote:
>
> 23.04.2021 19:32, Thierry Reding пишет:
> > +void of_iommu_get_resv_regions(struct device *dev, struct list_head *list)
> > +{
> > + struct of_phandle_iterator it;
> > + int err;
> > +
> > + of_for_each_phandle(&it, err, dev->of_node, "memory-region", 
> > "#memory-region-cells", 0) {
> > + struct iommu_resv_region *region;
> > + struct of_phandle_args args;
> > + struct resource res;
> > +
> > + args.args_count = of_phandle_iterator_args(&it, args.args, 
> > MAX_PHANDLE_ARGS);
> > +
> > + err = of_address_to_resource(it.node, 0, &res);
> > + if (err < 0) {
> > + dev_err(dev, "failed to parse memory region %pOF: 
> > %d\n",
> > + it.node, err);
> > + continue;
> > + }
> > +
> > + if (args.args_count > 0) {
> > + /*
> > +  * Active memory regions are expected to be accessed 
> > by hardware during
> > +  * boot and must therefore have an identity mapping 
> > created prior to the
> > +  * driver taking control of the hardware. This 
> > ensures that non-quiescent
> > +  * hardware doesn't cause IOMMU faults during boot.
> > +  */
> > + if (args.args[0] & MEMORY_REGION_IDENTITY_MAPPING) {
> > + region = iommu_alloc_resv_region(res.start, 
> > resource_size(&res),
> > +  IOMMU_READ | 
> > IOMMU_WRITE,
> > +  
> > IOMMU_RESV_DIRECT_RELAXABLE);
> > + if (!region)
> > + continue;
> > +
> > + list_add_tail(®ion->list, list);
> > + }
> > + }
> > + }
> > +}
> > +EXPORT_SYMBOL(of_iommu_get_resv_regions);
>
> Any reason why this is not EXPORT_SYMBOL_GPL? I'm curious what is the
> logic behind the OF symbols in general since it looks like half of them
> are GPL.

Generally, new ones are _GPL. Old ones probably predate _GPL.

This one is up to the IOMMU maintainers.

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

Re: [PATCH v6 8/9] iommu/arm-smmu: Get associated RMR info and install bypass SMR

2021-07-16 Thread Steven Price
On 16/07/2021 09:34, Shameer Kolothum wrote:
> From: Jon Nettleton 
> 
> Check if there is any RMR info associated with the devices behind
> the SMMU and if any, install bypass SMRs for them. This is to
> keep any ongoing traffic associated with these devices alive
> when we enable/reset SMMU during probe().
> 
> Signed-off-by: Jon Nettleton 
> Signed-off-by: Steven Price 
> Signed-off-by: Shameer Kolothum 
> ---
>  drivers/iommu/arm/arm-smmu/arm-smmu.c | 48 +++
>  1 file changed, 48 insertions(+)
> 
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
> b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> index f22dbeb1e510..e9fb3d962a86 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> @@ -2063,6 +2063,50 @@ err_reset_platform_ops: __maybe_unused;
>   return err;
>  }
>  
> +static void arm_smmu_rmr_install_bypass_smr(struct arm_smmu_device *smmu)
> +{
> + struct list_head rmr_list;
> + struct iommu_resv_region *e;
> + int i, cnt = 0;
> + u32 reg;
> +
> + INIT_LIST_HEAD(&rmr_list);
> + if (iommu_dma_get_rmrs(dev_fwnode(smmu->dev), &rmr_list))
> + return;
> +
> + /*
> +  * Rather than trying to look at existing mappings that
> +  * are setup by the firmware and then invalidate the ones
> +  * that do no have matching RMR entries, just disable the
> +  * SMMU until it gets enabled again in the reset routine.
> +  */
> + reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sCR0);
> + reg &= ~ARM_SMMU_sCR0_CLIENTPD;

This looks backwards, the spec states:

  Client Port Disable. The possible values of this bit are:
  0 - Each SMMU client access is subject to SMMU translation, access
  control, and attribute generation.
  1 - Each SMMU client access bypasses SMMU translation, access control,
  and attribute generation.
  This bit resets to 1.

And indeed with the current code if sCR0_USFCFG was set when
sCR0_CLIENTPD is cleared then I get a blank screen until the smmu is reset.

So I believe this should be ORing in the value, i.e.

  reg |= ARM_SMMU_sCR0_CLIENTPD;

And in my testing that works fine even if sCR0_USFCFG is set.

Steve

> + arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, reg);
> +
> + list_for_each_entry(e, &rmr_list, list) {
> + u32 sid = e->fw_data.rmr.sid;
> +
> + i = arm_smmu_find_sme(smmu, sid, ~0);
> + if (i < 0)
> + continue;
> + if (smmu->s2crs[i].count == 0) {
> + smmu->smrs[i].id = sid;
> + smmu->smrs[i].mask = 0;
> + smmu->smrs[i].valid = true;
> + }
> + smmu->s2crs[i].count++;
> + smmu->s2crs[i].type = S2CR_TYPE_BYPASS;
> + smmu->s2crs[i].privcfg = S2CR_PRIVCFG_DEFAULT;
> +
> + cnt++;
> + }
> +
> + dev_notice(smmu->dev, "\tpreserved %d boot mapping%s\n", cnt,
> +cnt == 1 ? "" : "s");
> + iommu_dma_put_rmrs(dev_fwnode(smmu->dev), &rmr_list);
> +}
> +
>  static int arm_smmu_device_probe(struct platform_device *pdev)
>  {
>   struct resource *res;
> @@ -2189,6 +2233,10 @@ static int arm_smmu_device_probe(struct 
> platform_device *pdev)
>   }
>  
>   platform_set_drvdata(pdev, smmu);
> +
> + /* Check for RMRs and install bypass SMRs if any */
> + arm_smmu_rmr_install_bypass_smr(smmu);
> +
>   arm_smmu_device_reset(smmu);
>   arm_smmu_test_smr_masks(smmu);
>  
> 

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


Re: [PATCH v2] dma-mapping: use vmalloc_to_page for vmalloc addresses

2021-07-16 Thread Roman Skakun
> Technically this looks good.  But given that exposing a helper
> that does either vmalloc_to_page or virt_to_page is one of the
> never ending MM discussions I don't want to get into that discussion
> and just keep it local in the DMA code.
>
> Are you fine with me applying this version?

Looks good to me, thanks!
But, Stefano asked me about using created helper in the
xen_swiotlb_free_coherent()
and I created a patch according to this mention.

We can merge this patch and create a new one for
xen_swiotlb_free_coherent() later.

пт, 16 июл. 2021 г. в 12:35, Christoph Hellwig :
>
> Technically this looks good.  But given that exposing a helper
> that does either vmalloc_to_page or virt_to_page is one of the
> never ending MM discussions I don't want to get into that discussion
> and just keep it local in the DMA code.
>
> Are you fine with me applying this version?
>
> ---
> From 40ac971eab89330d6153e7721e88acd2d98833f9 Mon Sep 17 00:00:00 2001
> From: Roman Skakun 
> Date: Fri, 16 Jul 2021 11:39:34 +0300
> Subject: dma-mapping: handle vmalloc addresses in
>  dma_common_{mmap,get_sgtable}
>
> xen-swiotlb can use vmalloc backed addresses for dma coherent allocations
> and uses the common helpers.  Properly handle them to unbreak Xen on
> ARM platforms.
>
> Fixes: 1b65c4e5a9af ("swiotlb-xen: use xen_alloc/free_coherent_pages")
> Signed-off-by: Roman Skakun 
> Reviewed-by: Andrii Anisov 
> [hch: split the patch, renamed the helpers]
> Signed-off-by: Christoph Hellwig 
> ---
>  kernel/dma/ops_helpers.c | 12 ++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/dma/ops_helpers.c b/kernel/dma/ops_helpers.c
> index 910ae69cae77..af4a6ef48ce0 100644
> --- a/kernel/dma/ops_helpers.c
> +++ b/kernel/dma/ops_helpers.c
> @@ -5,6 +5,13 @@
>   */
>  #include 
>
> +static struct page *dma_common_vaddr_to_page(void *cpu_addr)
> +{
> +   if (is_vmalloc_addr(cpu_addr))
> +   return vmalloc_to_page(cpu_addr);
> +   return virt_to_page(cpu_addr);
> +}
> +
>  /*
>   * Create scatter-list for the already allocated DMA buffer.
>   */
> @@ -12,7 +19,7 @@ int dma_common_get_sgtable(struct device *dev, struct 
> sg_table *sgt,
>  void *cpu_addr, dma_addr_t dma_addr, size_t size,
>  unsigned long attrs)
>  {
> -   struct page *page = virt_to_page(cpu_addr);
> +   struct page *page = dma_common_vaddr_to_page(cpu_addr);
> int ret;
>
> ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
> @@ -32,6 +39,7 @@ int dma_common_mmap(struct device *dev, struct 
> vm_area_struct *vma,
> unsigned long user_count = vma_pages(vma);
> unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
> unsigned long off = vma->vm_pgoff;
> +   struct page *page = dma_common_vaddr_to_page(cpu_addr);
> int ret = -ENXIO;
>
> vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
> @@ -43,7 +51,7 @@ int dma_common_mmap(struct device *dev, struct 
> vm_area_struct *vma,
> return -ENXIO;
>
> return remap_pfn_range(vma, vma->vm_start,
> -   page_to_pfn(virt_to_page(cpu_addr)) + vma->vm_pgoff,
> +   page_to_pfn(page) + vma->vm_pgoff,
> user_count << PAGE_SHIFT, vma->vm_page_prot);
>  #else
> return -ENXIO;
> --
> 2.30.2
>


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

Re: [PATCH v1 10/16] s390/pci: return error code from s390_dma_map_sg()

2021-07-16 Thread Niklas Schnelle
On Thu, 2021-07-15 at 10:45 -0600, Logan Gunthorpe wrote:
> From: Martin Oliveira 
> 
> The .map_sg() op now expects an error code instead of zero on failure.
> 
> So propagate the error from __s390_dma_map_sg() up.
> 
> Signed-off-by: Martin Oliveira 
> Signed-off-by: Logan Gunthorpe 
> Cc: Niklas Schnelle 
> Cc: Gerald Schaefer 
> Cc: Heiko Carstens 
> Cc: Vasily Gorbik 
> Cc: Christian Borntraeger 
> ---
>  arch/s390/pci/pci_dma.c | 12 +++-
>  1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
> index ebc9a49523aa..c78b02012764 100644
> --- a/arch/s390/pci/pci_dma.c
> +++ b/arch/s390/pci/pci_dma.c
> @@ -487,7 +487,7 @@ static int s390_dma_map_sg(struct device *dev, struct 
> scatterlist *sg,
>   unsigned int max = dma_get_max_seg_size(dev);
>   unsigned int size = s->offset + s->length;
>   unsigned int offset = s->offset;
> - int count = 0, i;
> + int count = 0, i, ret;
>  
>   for (i = 1; i < nr_elements; i++) {
>   s = sg_next(s);
> @@ -497,8 +497,9 @@ static int s390_dma_map_sg(struct device *dev, struct 
> scatterlist *sg,
>  
>   if (s->offset || (size & ~PAGE_MASK) ||
>   size + s->length > max) {
> - if (__s390_dma_map_sg(dev, start, size,
> -   &dma->dma_address, dir))
> + ret = __s390_dma_map_sg(dev, start, size,
> + &dma->dma_address, dir);
> + if (ret)
>   goto unmap;
>  
>   dma->dma_address += offset;
> @@ -511,7 +512,8 @@ static int s390_dma_map_sg(struct device *dev, struct 
> scatterlist *sg,
>   }
>   size += s->length;
>   }
> - if (__s390_dma_map_sg(dev, start, size, &dma->dma_address, dir))
> + ret = __s390_dma_map_sg(dev, start, size, &dma->dma_address, dir);
> + if (ret)
>   goto unmap;
>  
>   dma->dma_address += offset;
> @@ -523,7 +525,7 @@ static int s390_dma_map_sg(struct device *dev, struct 
> scatterlist *sg,
>   s390_dma_unmap_pages(dev, sg_dma_address(s), sg_dma_len(s),
>dir, attrs);
>  
> - return 0;
> + return ret;
>  }
>  
>  static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg,

So the error codes we return are -ENOMEM if allocating a DMA
translation entry fails and -EINVAL if the DMA translation table hasn't
been initialized or the caller tries to map 0 sized memory. Are these
error codes that you would expect? If yes then this change looks good
to me.

Acked-by: Niklas Schnelle 

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


Re: [RFC v2] /dev/iommu uAPI proposal

2021-07-16 Thread Shenming Lu
On 2021/7/16 9:20, Tian, Kevin wrote:
 > To summarize, for vIOMMU we can work with the spec owner to
> define a proper interface to feedback such restriction into the guest 
> if necessary. For the kernel part, it's clear that IOMMU fd should 
> disallow two devices attached to a single [RID] or [RID, PASID] slot 
> in the first place.
> 
> Then the next question is how to communicate such restriction
> to the userspace. It sounds like a group, but different in concept.
> An iommu group describes the minimal isolation boundary thus all
> devices in the group can be only assigned to a single user. But this
> case is opposite - the two mdevs (both support ENQCMD submission)
> with the same parent have problem when assigned to a single VM 
> (in this case vPASID is vm-wide translated thus a same pPASID will be 
> used cross both mdevs) while they instead work pretty well when 
> assigned to different VMs (completely different vPASID spaces thus 
> different pPASIDs).
> 
> One thought is to have vfio device driver deal with it. In this proposal
> it is the vfio device driver to define the PASID virtualization policy and
> report it to userspace via VFIO_DEVICE_GET_INFO. The driver understands
> the restriction thus could just hide the vPASID capability when the user 
> calls GET_INFO on the 2nd mdev in above scenario. In this way the 
> user even doesn't need to know such restriction at all and both mdevs
> can be assigned to a single VM w/o any problem.
> 

The restriction only probably happens when two mdevs are assigned to one VM,
how could the vfio device driver get to know this info to accurately hide
the vPASID capability for the 2nd mdev when VFIO_DEVICE_GET_INFO? There is no
need to do this in other cases.

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


Re: [PATCH v1 16/16] dma-mapping: Disallow .map_sg operations from returning zero on error

2021-07-16 Thread Robin Murphy

On 2021-07-16 07:33, Christoph Hellwig wrote:

On Thu, Jul 15, 2021 at 10:45:44AM -0600, Logan Gunthorpe wrote:

@@ -194,6 +194,8 @@ static int __dma_map_sg_attrs(struct device *dev, struct 
scatterlist *sg,
else
ents = ops->map_sg(dev, sg, nents, dir, attrs);
  
+	WARN_ON_ONCE(ents == 0);


Turns this into a negative error code while we're at it, just to keep
the callers sane?


Right, by this point returning the 0 would pass through 
dma_map_sg_attrs() OK, but AFAICS dma_map_sgtable() would now get 
confused and return success but with sgt->nents = 0. Coercing it to an 
error code (which dma_map_sg_attrs() would then just change right back) 
seems sensible for the sake of easy robustness.


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


Re: [PATCH v1 14/16] x86/amd_gart: return error code from gart_map_sg()

2021-07-16 Thread Robin Murphy

On 2021-07-16 07:32, Christoph Hellwig wrote:

On Thu, Jul 15, 2021 at 10:45:42AM -0600, Logan Gunthorpe wrote:

@@ -458,7 +460,7 @@ static int gart_map_sg(struct device *dev, struct 
scatterlist *sg, int nents,
iommu_full(dev, pages << PAGE_SHIFT, dir);
for_each_sg(sg, s, nents, i)
s->dma_address = DMA_MAPPING_ERROR;
-   return 0;
+   return ret;


While we're at it - setting the ->dma_address to DMA_MAPPING_ERROR is
not part of the ->map_sg calling convention.  Might be worth to fix
up while we're at it.


Especially since it's not even zeroing dma_length, which at least is a 
documented indicator of validity (even if it's not strictly defined for 
failure cases either).


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


Re: [PATCH v2] iommu: Streamline iommu_iova_to_phys()

2021-07-16 Thread Robin Murphy

On 2021-07-16 07:19, Christoph Hellwig wrote:

On Thu, Jul 15, 2021 at 03:16:08PM +0100, Robin Murphy wrote:

On 2021-07-15 15:07, Christoph Hellwig wrote:

On Thu, Jul 15, 2021 at 02:04:24PM +0100, Robin Murphy wrote:

If people are going to insist on calling iommu_iova_to_phys()
pointlessly and expecting it to work,


Maybe we need to fix that?


Feel free to try, but we didn't have much luck pushing back on it
previously, so playing whack-a-mole against netdev now is a game I'm
personally happy to stay away from ;)


One thing I've done with symbols I want people to not use it to
unexport them.  But what about vfio?


Yeah, it's not like they shouldn't be calling it at all - I see it as 
primarily intended for use by drivers managing their own domains, but I 
don't entirely disagree with using it on DMA domains either in niche 
cases - it's that they blindly grab the default domain without even 
checking whether DMA mappings are actually translated or not (and thus 
whether they even need to make that call every time they pull a 
descriptor back out of a ringbuffer). IIRC the argument was essentially 
that checking the domain type was an IOMMU API detail that those driver 
shouldn't have to know about and the abstraction should just take care 
of it, despite the fact that they're punching through 2 layers of 
abstraction to even reach that point. And apparently keeping track of 
their own descriptor addresses would be too much work, but expensive 
indirect calls to either return the address they already have or go off 
and do a software table walk with atomic synchronisation and everything 
are fine :/



While we're talking about iommu_iova_to_phys: __iommu_dma_unmap_swiotlb
calls it unconditionally, despite only needed ing the physical address.
Can we optimize that somehow by splitting out the bounce buffering case
out?


Indeed, as I think I mentioned recently on another thread, all the 
bounce-buffering stuff is fairly ugly because it's basically the old 
intel-iommu code dropped in with as few changes as possible for ease of 
review, since Tom was no longer able to spend time refining it, and 
nobody else has got round to cleaning it up yet either. In fact the 
whole flow through iommu_dma_unmap_page() flow might be the worst-hit - 
reusing the iommu_dma_sync op made perfect sense when it was just cache 
maintenance, but now means that at worst we do iova_to_phys *twice* plus 
a pointless swiotlb_sync :(


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


Re: [PATCH v2] dma-mapping: use vmalloc_to_page for vmalloc addresses

2021-07-16 Thread Christoph Hellwig
Technically this looks good.  But given that exposing a helper
that does either vmalloc_to_page or virt_to_page is one of the
never ending MM discussions I don't want to get into that discussion
and just keep it local in the DMA code.

Are you fine with me applying this version?

---
>From 40ac971eab89330d6153e7721e88acd2d98833f9 Mon Sep 17 00:00:00 2001
From: Roman Skakun 
Date: Fri, 16 Jul 2021 11:39:34 +0300
Subject: dma-mapping: handle vmalloc addresses in
 dma_common_{mmap,get_sgtable}

xen-swiotlb can use vmalloc backed addresses for dma coherent allocations
and uses the common helpers.  Properly handle them to unbreak Xen on
ARM platforms.

Fixes: 1b65c4e5a9af ("swiotlb-xen: use xen_alloc/free_coherent_pages")
Signed-off-by: Roman Skakun 
Reviewed-by: Andrii Anisov 
[hch: split the patch, renamed the helpers]
Signed-off-by: Christoph Hellwig 
---
 kernel/dma/ops_helpers.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/kernel/dma/ops_helpers.c b/kernel/dma/ops_helpers.c
index 910ae69cae77..af4a6ef48ce0 100644
--- a/kernel/dma/ops_helpers.c
+++ b/kernel/dma/ops_helpers.c
@@ -5,6 +5,13 @@
  */
 #include 
 
+static struct page *dma_common_vaddr_to_page(void *cpu_addr)
+{
+   if (is_vmalloc_addr(cpu_addr))
+   return vmalloc_to_page(cpu_addr);
+   return virt_to_page(cpu_addr);
+}
+
 /*
  * Create scatter-list for the already allocated DMA buffer.
  */
@@ -12,7 +19,7 @@ int dma_common_get_sgtable(struct device *dev, struct 
sg_table *sgt,
 void *cpu_addr, dma_addr_t dma_addr, size_t size,
 unsigned long attrs)
 {
-   struct page *page = virt_to_page(cpu_addr);
+   struct page *page = dma_common_vaddr_to_page(cpu_addr);
int ret;
 
ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
@@ -32,6 +39,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct 
*vma,
unsigned long user_count = vma_pages(vma);
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long off = vma->vm_pgoff;
+   struct page *page = dma_common_vaddr_to_page(cpu_addr);
int ret = -ENXIO;
 
vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
@@ -43,7 +51,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct 
*vma,
return -ENXIO;
 
return remap_pfn_range(vma, vma->vm_start,
-   page_to_pfn(virt_to_page(cpu_addr)) + vma->vm_pgoff,
+   page_to_pfn(page) + vma->vm_pgoff,
user_count << PAGE_SHIFT, vma->vm_page_prot);
 #else
return -ENXIO;
-- 
2.30.2

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


[PATCH v2] dma-mapping: use vmalloc_to_page for vmalloc addresses

2021-07-16 Thread Roman Skakun
From: Roman Skakun 

This commit is dedicated to fix incorrect conversion from
cpu_addr to page address in cases when we get virtual
address which allocated in the vmalloc range.
As the result, virt_to_page() cannot convert this address
properly and return incorrect page address.

Need to detect such cases and obtains the page address using
vmalloc_to_page() instead.

Signed-off-by: Roman Skakun 
Reviewed-by: Andrii Anisov 
---
Hi, Christoph!
It's updated patch in accordance with your and Stefano 
suggestions. 

 drivers/xen/swiotlb-xen.c   |  7 +--
 include/linux/dma-map-ops.h |  2 ++
 kernel/dma/ops_helpers.c| 16 ++--
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 92ee6eea30cd..c2f612a10a95 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -337,7 +337,7 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t 
size, void *vaddr,
int order = get_order(size);
phys_addr_t phys;
u64 dma_mask = DMA_BIT_MASK(32);
-   struct page *page;
+   struct page *page = cpu_addr_to_page(vaddr);
 
if (hwdev && hwdev->coherent_dma_mask)
dma_mask = hwdev->coherent_dma_mask;
@@ -349,11 +349,6 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t 
size, void *vaddr,
/* Convert the size to actually allocated. */
size = 1UL << (order + XEN_PAGE_SHIFT);
 
-   if (is_vmalloc_addr(vaddr))
-   page = vmalloc_to_page(vaddr);
-   else
-   page = virt_to_page(vaddr);
-
if (!WARN_ON((dev_addr + size - 1 > dma_mask) ||
 range_straddles_page_boundary(phys, size)) &&
TestClearPageXenRemapped(page))
diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index a5f89fc4d6df..ce0edb0bb603 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -226,6 +226,8 @@ struct page *dma_alloc_from_pool(struct device *dev, size_t 
size,
bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t));
 bool dma_free_from_pool(struct device *dev, void *start, size_t size);
 
+struct page *cpu_addr_to_page(void *cpu_addr);
+
 #ifdef CONFIG_ARCH_HAS_DMA_COHERENCE_H
 #include 
 #elif defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \
diff --git a/kernel/dma/ops_helpers.c b/kernel/dma/ops_helpers.c
index 910ae69cae77..472e861750d3 100644
--- a/kernel/dma/ops_helpers.c
+++ b/kernel/dma/ops_helpers.c
@@ -5,6 +5,17 @@
  */
 #include 
 
+/*
+ * This helper converts virtual address to page address.
+ */
+struct page *cpu_addr_to_page(void *cpu_addr)
+{
+   if (is_vmalloc_addr(cpu_addr))
+   return vmalloc_to_page(cpu_addr);
+   else
+   return virt_to_page(cpu_addr);
+}
+
 /*
  * Create scatter-list for the already allocated DMA buffer.
  */
@@ -12,7 +23,7 @@ int dma_common_get_sgtable(struct device *dev, struct 
sg_table *sgt,
 void *cpu_addr, dma_addr_t dma_addr, size_t size,
 unsigned long attrs)
 {
-   struct page *page = virt_to_page(cpu_addr);
+   struct page *page = cpu_addr_to_page(cpu_addr);
int ret;
 
ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
@@ -32,6 +43,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct 
*vma,
unsigned long user_count = vma_pages(vma);
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long off = vma->vm_pgoff;
+   struct page *page = cpu_addr_to_page(cpu_addr);
int ret = -ENXIO;
 
vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
@@ -43,7 +55,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct 
*vma,
return -ENXIO;
 
return remap_pfn_range(vma, vma->vm_start,
-   page_to_pfn(virt_to_page(cpu_addr)) + vma->vm_pgoff,
+   page_to_pfn(page) + vma->vm_pgoff,
user_count << PAGE_SHIFT, vma->vm_page_prot);
 #else
return -ENXIO;
-- 
2.27.0

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


[PATCH v6 9/9] iommu/dma: Reserve any RMR regions associated with a dev

2021-07-16 Thread Shameer Kolothum
Get ACPI IORT RMR regions associated with a dev reserved
so that there is a unity mapping for them in SMMU.

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/dma-iommu.c | 56 +++
 1 file changed, 51 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 1b6e27475279..c1ae0c3d4b33 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -207,22 +207,68 @@ void iommu_dma_put_rmrs(struct fwnode_handle 
*iommu_fwnode,
 }
 EXPORT_SYMBOL(iommu_dma_put_rmrs);
 
+static bool iommu_dma_dev_has_rmr(struct iommu_fwspec *fwspec,
+ struct iommu_resv_region *e)
+{
+   int i;
+
+   for (i = 0; i < fwspec->num_ids; i++) {
+   if (e->fw_data.rmr.sid == fwspec->ids[i])
+   return true;
+   }
+
+   return false;
+}
+
+static void iommu_dma_get_rmr_resv_regions(struct device *dev,
+  struct list_head *list)
+{
+   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+   struct list_head rmr_list;
+   struct iommu_resv_region *rmr, *tmp;
+
+   INIT_LIST_HEAD(&rmr_list);
+   if (iommu_dma_get_rmrs(fwspec->iommu_fwnode, &rmr_list))
+   return;
+
+   if (dev_is_pci(dev)) {
+   struct pci_dev *pdev = to_pci_dev(dev);
+   struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
+
+   if (!host->preserve_config)
+   return;
+   }
+
+   list_for_each_entry_safe(rmr, tmp, &rmr_list, list) {
+   if (!iommu_dma_dev_has_rmr(fwspec, rmr))
+   continue;
+
+   /* Remove from iommu RMR list and add to dev resv_regions */
+   list_del_init(&rmr->list);
+   list_add_tail(&rmr->list, list);
+   }
+
+   iommu_dma_put_rmrs(fwspec->iommu_fwnode, &rmr_list);
+}
+
 /**
  * iommu_dma_get_resv_regions - Reserved region driver helper
  * @dev: Device from iommu_get_resv_regions()
  * @list: Reserved region list from iommu_get_resv_regions()
  *
  * IOMMU drivers can use this to implement their .get_resv_regions callback
- * for general non-IOMMU-specific reservations. Currently, this covers GICv3
- * ITS region reservation on ACPI based ARM platforms that may require HW MSI
- * reservation.
+ * for general non-IOMMU-specific reservations. Currently this covers,
+ *  -GICv3 ITS region reservation on ACPI based ARM platforms that may
+ *   require HW MSI reservation.
+ *  -Any ACPI IORT RMR memory range reservations (IORT spec rev E.b)
  */
 void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
 {
 
-   if (!is_of_node(dev_iommu_fwspec_get(dev)->iommu_fwnode))
+   if (!is_of_node(dev_iommu_fwspec_get(dev)->iommu_fwnode)) {
iort_iommu_msi_get_resv_regions(dev, list);
-
+   iommu_dma_get_rmr_resv_regions(dev, list);
+   }
 }
 EXPORT_SYMBOL(iommu_dma_get_resv_regions);
 
-- 
2.17.1

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


[PATCH v6 8/9] iommu/arm-smmu: Get associated RMR info and install bypass SMR

2021-07-16 Thread Shameer Kolothum
From: Jon Nettleton 

Check if there is any RMR info associated with the devices behind
the SMMU and if any, install bypass SMRs for them. This is to
keep any ongoing traffic associated with these devices alive
when we enable/reset SMMU during probe().

Signed-off-by: Jon Nettleton 
Signed-off-by: Steven Price 
Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 48 +++
 1 file changed, 48 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index f22dbeb1e510..e9fb3d962a86 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -2063,6 +2063,50 @@ err_reset_platform_ops: __maybe_unused;
return err;
 }
 
+static void arm_smmu_rmr_install_bypass_smr(struct arm_smmu_device *smmu)
+{
+   struct list_head rmr_list;
+   struct iommu_resv_region *e;
+   int i, cnt = 0;
+   u32 reg;
+
+   INIT_LIST_HEAD(&rmr_list);
+   if (iommu_dma_get_rmrs(dev_fwnode(smmu->dev), &rmr_list))
+   return;
+
+   /*
+* Rather than trying to look at existing mappings that
+* are setup by the firmware and then invalidate the ones
+* that do no have matching RMR entries, just disable the
+* SMMU until it gets enabled again in the reset routine.
+*/
+   reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sCR0);
+   reg &= ~ARM_SMMU_sCR0_CLIENTPD;
+   arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, reg);
+
+   list_for_each_entry(e, &rmr_list, list) {
+   u32 sid = e->fw_data.rmr.sid;
+
+   i = arm_smmu_find_sme(smmu, sid, ~0);
+   if (i < 0)
+   continue;
+   if (smmu->s2crs[i].count == 0) {
+   smmu->smrs[i].id = sid;
+   smmu->smrs[i].mask = 0;
+   smmu->smrs[i].valid = true;
+   }
+   smmu->s2crs[i].count++;
+   smmu->s2crs[i].type = S2CR_TYPE_BYPASS;
+   smmu->s2crs[i].privcfg = S2CR_PRIVCFG_DEFAULT;
+
+   cnt++;
+   }
+
+   dev_notice(smmu->dev, "\tpreserved %d boot mapping%s\n", cnt,
+  cnt == 1 ? "" : "s");
+   iommu_dma_put_rmrs(dev_fwnode(smmu->dev), &rmr_list);
+}
+
 static int arm_smmu_device_probe(struct platform_device *pdev)
 {
struct resource *res;
@@ -2189,6 +2233,10 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
}
 
platform_set_drvdata(pdev, smmu);
+
+   /* Check for RMRs and install bypass SMRs if any */
+   arm_smmu_rmr_install_bypass_smr(smmu);
+
arm_smmu_device_reset(smmu);
arm_smmu_test_smr_masks(smmu);
 
-- 
2.17.1

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


[PATCH v6 7/9] iommu/arm-smmu-v3: Get associated RMR info and install bypass STE

2021-07-16 Thread Shameer Kolothum
Check if there is any RMR info associated with the devices behind
the SMMUv3 and if any, install bypass STEs for them. This is to
keep any ongoing traffic associated with these devices alive
when we enable/reset SMMUv3 during probe().

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 31 +
 1 file changed, 31 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 34f84641dc6a..71a682fb375b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3759,6 +3759,34 @@ static void __iomem *arm_smmu_ioremap(struct device 
*dev, resource_size_t start,
return devm_ioremap_resource(dev, &res);
 }
 
+static void arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device *smmu)
+{
+   struct list_head rmr_list;
+   struct iommu_resv_region *e;
+   int ret;
+
+   INIT_LIST_HEAD(&rmr_list);
+   if (iommu_dma_get_rmrs(dev_fwnode(smmu->dev), &rmr_list))
+   return;
+
+   list_for_each_entry(e, &rmr_list, list) {
+   __le64 *step;
+   u32 sid = e->fw_data.rmr.sid;
+
+   ret = arm_smmu_init_sid_strtab(smmu, sid);
+   if (ret) {
+   dev_err(smmu->dev, "RMR SID(0x%x) bypass failed\n",
+   sid);
+   continue;
+   }
+
+   step = arm_smmu_get_step_for_sid(smmu, sid);
+   arm_smmu_init_bypass_stes(step, 1, true);
+   }
+
+   iommu_dma_put_rmrs(dev_fwnode(smmu->dev), &rmr_list);
+}
+
 static int arm_smmu_device_probe(struct platform_device *pdev)
 {
int irq, ret;
@@ -3840,6 +3868,9 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
/* Record our private device structure */
platform_set_drvdata(pdev, smmu);
 
+   /* Check for RMRs and install bypass STEs if any */
+   arm_smmu_rmr_install_bypass_ste(smmu);
+
/* Reset the device */
ret = arm_smmu_device_reset(smmu, bypass);
if (ret)
-- 
2.17.1

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

[PATCH v6 6/9] iommu/arm-smmu-v3: Refactor arm_smmu_init_bypass_stes() to force bypass

2021-07-16 Thread Shameer Kolothum
By default, disable_bypass flag is set and any dev without
an iommu domain installs STE with CFG_ABORT during
arm_smmu_init_bypass_stes(). Introduce a "force" flag and
move the STE update logic to arm_smmu_init_bypass_stes()
so that we can force it to install CFG_BYPASS STE for specific
SIDs.

This will be useful in follow-up patch to install bypass
for IORT RMR SIDs.

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 33f5556aefeb..34f84641dc6a 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1356,12 +1356,21 @@ static void arm_smmu_write_strtab_ent(struct 
arm_smmu_master *master, u32 sid,
arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
 }
 
-static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent)
+static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent, bool 
force)
 {
unsigned int i;
+   u64 val = STRTAB_STE_0_V;
+
+   if (disable_bypass && !force)
+   val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_ABORT);
+   else
+   val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
 
for (i = 0; i < nent; ++i) {
-   arm_smmu_write_strtab_ent(NULL, -1, strtab);
+   strtab[0] = cpu_to_le64(val);
+   strtab[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
+  
STRTAB_STE_1_SHCFG_INCOMING));
+   strtab[2] = 0;
strtab += STRTAB_STE_DWORDS;
}
 }
@@ -1389,7 +1398,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device 
*smmu, u32 sid)
return -ENOMEM;
}
 
-   arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
+   arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT, false);
arm_smmu_write_strtab_l1_desc(strtab, desc);
return 0;
 }
@@ -3041,7 +3050,7 @@ static int arm_smmu_init_strtab_linear(struct 
arm_smmu_device *smmu)
reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits);
cfg->strtab_base_cfg = reg;
 
-   arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents);
+   arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents, false);
return 0;
 }
 
-- 
2.17.1

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

[PATCH v6 5/9] iommu/arm-smmu-v3: Introduce strtab init helper

2021-07-16 Thread Shameer Kolothum
Introduce a helper to check the sid range and to init the l2 strtab
entries(bypass). This will be useful when we have to initialize the
l2 strtab with bypass for RMR SIDs.

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 28 +++--
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index dd20b01771c4..33f5556aefeb 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2517,6 +2517,19 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device 
*smmu, u32 sid)
return sid < limit;
 }
 
+static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
+{
+   /* Check the SIDs are in range of the SMMU and our stream table */
+   if (!arm_smmu_sid_in_range(smmu, sid))
+   return -ERANGE;
+
+   /* Ensure l2 strtab is initialised */
+   if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
+   return arm_smmu_init_l2_strtab(smmu, sid);
+
+   return 0;
+}
+
 static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
  struct arm_smmu_master *master)
 {
@@ -2540,20 +2553,9 @@ static int arm_smmu_insert_master(struct arm_smmu_device 
*smmu,
new_stream->id = sid;
new_stream->master = master;
 
-   /*
-* Check the SIDs are in range of the SMMU and our stream table
-*/
-   if (!arm_smmu_sid_in_range(smmu, sid)) {
-   ret = -ERANGE;
+   ret = arm_smmu_init_sid_strtab(smmu, sid);
+   if (ret)
break;
-   }
-
-   /* Ensure l2 strtab is initialised */
-   if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
-   ret = arm_smmu_init_l2_strtab(smmu, sid);
-   if (ret)
-   break;
-   }
 
/* Insert into SID tree */
new_node = &(smmu->streams.rb_node);
-- 
2.17.1

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


[PATCH v6 4/9] ACPI/IORT: Add a helper to retrieve RMR memory regions

2021-07-16 Thread Shameer Kolothum
Add a helper function (iort_iommu_get_rmrs()) that retrieves RMR
memory descriptors associated with a given IOMMU. This will be used
by IOMMU drivers to setup necessary mappings.

Invoke it from the generic helper iommu_dma_get_rmrs().

Signed-off-by: Shameer Kolothum 
---
 drivers/acpi/arm64/iort.c | 38 ++
 drivers/iommu/dma-iommu.c |  4 
 include/linux/acpi_iort.h |  7 +++
 3 files changed, 49 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index d76ba46ebe67..3c32d62e63b6 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -809,6 +809,42 @@ static struct acpi_iort_node 
*iort_get_msi_resv_iommu(struct device *dev)
return NULL;
 }
 
+/**
+ * iort_iommu_get_rmrs() - Helper to retrieve RMR info associated with IOMMU
+ * @iommu_fwnode: fwnode for the IOMMU
+ * @head: RMR list head to be populated
+ *
+ * Returns: 0 on success, <0 failure. Please note, we will keep the already
+ *  allocated RMR reserve regions in case of a kmemdup()
+ *  failure.
+ */
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
+   struct list_head *head)
+{
+   struct iommu_resv_region *e;
+   struct acpi_iort_node *iommu;
+   int rmrs = 0;
+
+   iommu = iort_get_iort_node(iommu_fwnode);
+   if (!iommu || list_empty(&iort_rmr_list))
+   return -ENODEV;
+
+   list_for_each_entry(e, &iort_rmr_list, list) {
+   struct iommu_resv_region *region;
+
+   if (e->fw_data.rmr.smmu != iommu)
+   continue;
+
+   region = kmemdup(e, sizeof(*region), GFP_KERNEL);
+   if (region) {
+   list_add_tail(®ion->list, head);
+   rmrs++;
+   }
+   }
+
+   return (rmrs == 0) ? -ENODEV : 0;
+}
+
 /**
  * iort_iommu_msi_get_resv_regions - Reserved region driver helper
  * @dev: Device from iommu_get_resv_regions()
@@ -1041,6 +1077,8 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, 
struct list_head *head)
 { return 0; }
 int iort_iommu_configure_id(struct device *dev, const u32 *input_id)
 { return -ENODEV; }
+int iort_iommu_get_rmrs(struct fwnode_handle *fwnode, struct list_head *head)
+{ return -ENODEV; }
 #endif
 
 static int nc_dma_get_range(struct device *dev, u64 *size)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 2fa2445e9070..1b6e27475279 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -185,6 +185,9 @@ EXPORT_SYMBOL(iommu_put_dma_cookie);
 int iommu_dma_get_rmrs(struct fwnode_handle *iommu_fwnode,
   struct list_head *list)
 {
+   if (!is_of_node(iommu_fwnode))
+   return iort_iommu_get_rmrs(iommu_fwnode, list);
+
return -EINVAL;
 }
 EXPORT_SYMBOL(iommu_dma_get_rmrs);
@@ -200,6 +203,7 @@ EXPORT_SYMBOL(iommu_dma_get_rmrs);
 void iommu_dma_put_rmrs(struct fwnode_handle *iommu_fwnode,
struct list_head *list)
 {
+   generic_iommu_put_resv_regions(iommu_fwnode->dev, list);
 }
 EXPORT_SYMBOL(iommu_dma_put_rmrs);
 
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index f1f0842a2cb2..d8c030c103f5 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -38,6 +38,8 @@ int iort_dma_get_ranges(struct device *dev, u64 *size);
 int iort_iommu_configure_id(struct device *dev, const u32 *id_in);
 int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head 
*head);
 phys_addr_t acpi_iort_dma_get_max_cpu_address(void);
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
+   struct list_head *list);
 #else
 static inline void acpi_iort_init(void) { }
 static inline u32 iort_msi_map_id(struct device *dev, u32 id)
@@ -57,6 +59,11 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, 
struct list_head *head)
 
 static inline phys_addr_t acpi_iort_dma_get_max_cpu_address(void)
 { return PHYS_ADDR_MAX; }
+
+static inline
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
+   struct list_head *list)
+{ return -ENODEV; }
 #endif
 
 #endif /* __ACPI_IORT_H__ */
-- 
2.17.1

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


[PATCH v6 3/9] iommu/dma: Introduce generic helper to retrieve RMR info

2021-07-16 Thread Shameer Kolothum
Reserved Memory Regions(RMR) associated with an IOMMU can be
described through ACPI IORT tables in systems with devices
that require a unity mapping or bypass for those
regions.

Introduce a generic interface so that IOMMU drivers can retrieve
and set up necessary mappings.

Signed-off-by: Shameer Kolothum 
---
 drivers/iommu/dma-iommu.c | 29 +
 include/linux/dma-iommu.h | 13 +
 2 files changed, 42 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 98ba927aee1a..2fa2445e9070 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -174,6 +174,35 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
 }
 EXPORT_SYMBOL(iommu_put_dma_cookie);
 
+/**
+ *
+ * iommu_dma_get_rmrs - Retrieve Reserved Memory Regions(RMRs) associated
+ *  with a given IOMMU
+ * @iommu_fwnode: fwnode associated with IOMMU
+ * @list: RMR list to be populated
+ *
+ */
+int iommu_dma_get_rmrs(struct fwnode_handle *iommu_fwnode,
+  struct list_head *list)
+{
+   return -EINVAL;
+}
+EXPORT_SYMBOL(iommu_dma_get_rmrs);
+
+/**
+ *
+ * iommu_dma_put_rmrs - Release Reserved Memory Regions(RMRs) associated
+ *  with a given IOMMU
+ * @iommu_fwnode: fwnode associated with IOMMU
+ * @list: RMR list
+ *
+ */
+void iommu_dma_put_rmrs(struct fwnode_handle *iommu_fwnode,
+   struct list_head *list)
+{
+}
+EXPORT_SYMBOL(iommu_dma_put_rmrs);
+
 /**
  * iommu_dma_get_resv_regions - Reserved region driver helper
  * @dev: Device from iommu_get_resv_regions()
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index 758ca4694257..3b7b2d096c6e 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -42,12 +42,16 @@ void iommu_dma_free_cpu_cached_iovas(unsigned int cpu,
 
 extern bool iommu_dma_forcedac;
 
+int iommu_dma_get_rmrs(struct fwnode_handle *iommu, struct list_head *list);
+void iommu_dma_put_rmrs(struct fwnode_handle *iommu, struct list_head *list);
+
 #else /* CONFIG_IOMMU_DMA */
 
 struct iommu_domain;
 struct msi_desc;
 struct msi_msg;
 struct device;
+struct fwnode_handle;
 
 static inline void iommu_setup_dma_ops(struct device *dev, u64 dma_base,
   u64 dma_limit)
@@ -83,5 +87,14 @@ static inline void iommu_dma_get_resv_regions(struct device 
*dev, struct list_he
 {
 }
 
+static int iommu_dma_get_rmrs(struct fwnode_handle *iommu, struct list_head 
*list)
+{
+   return -ENODEV;
+}
+
+static void iommu_dma_put_rmrs(struct fwnode_handle *iommu, struct list_head 
*list)
+{
+}
+
 #endif /* CONFIG_IOMMU_DMA */
 #endif /* __DMA_IOMMU_H */
-- 
2.17.1

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


[PATCH v6 2/9] ACPI/IORT: Add support for RMR node parsing

2021-07-16 Thread Shameer Kolothum
Add support for parsing RMR node information from ACPI.

Find the associated streamid and smmu node info from the
RMR node and populate a linked list with RMR memory
descriptors.

Signed-off-by: Shameer Kolothum 
---
 drivers/acpi/arm64/iort.c | 134 +-
 1 file changed, 133 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 3b23fb775ac4..d76ba46ebe67 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -40,6 +40,8 @@ struct iort_fwnode {
 static LIST_HEAD(iort_fwnode_list);
 static DEFINE_SPINLOCK(iort_fwnode_lock);
 
+static LIST_HEAD(iort_rmr_list);   /* list of RMR regions from ACPI */
+
 /**
  * iort_set_fwnode() - Create iort_fwnode and use it to register
  *iommu data in the iort_fwnode_list
@@ -393,7 +395,8 @@ static struct acpi_iort_node *iort_node_get_id(struct 
acpi_iort_node *node,
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX ||
node->type == ACPI_IORT_NODE_SMMU_V3 ||
-   node->type == ACPI_IORT_NODE_PMCG) {
+   node->type == ACPI_IORT_NODE_PMCG ||
+   node->type == ACPI_IORT_NODE_RMR) {
*id_out = map->output_base;
return parent;
}
@@ -1566,6 +1569,134 @@ static void __init iort_enable_acs(struct 
acpi_iort_node *iort_node)
 #else
 static inline void iort_enable_acs(struct acpi_iort_node *iort_node) { }
 #endif
+static void iort_rmr_desc_check_overlap(struct acpi_iort_rmr_desc *desc, u32 
count)
+{
+   int i, j;
+
+   for (i = 0; i < count; i++) {
+   u64 end, start = desc[i].base_address, length = desc[i].length;
+
+   end = start + length - 1;
+
+   /* Check for address overlap */
+   for (j = i + 1; j < count; j++) {
+   u64 e_start = desc[j].base_address;
+   u64 e_end = e_start + desc[j].length - 1;
+
+   if (start <= e_end && end >= e_start)
+   pr_err(FW_BUG "RMR descriptor[0x%llx - 0x%llx] 
overlaps, continue anyway\n",
+  start, end);
+   }
+   }
+}
+
+static void __init iort_node_get_rmr_info(struct acpi_iort_node *iort_node)
+{
+   struct acpi_iort_node *smmu;
+   struct acpi_iort_rmr *rmr;
+   struct acpi_iort_rmr_desc *rmr_desc;
+   u32 map_count = iort_node->mapping_count;
+   u32 sid;
+   int i;
+
+   if (!iort_node->mapping_offset || map_count != 1) {
+   pr_err(FW_BUG "Invalid ID mapping, skipping RMR node %p\n",
+  iort_node);
+   return;
+   }
+
+   /* Retrieve associated smmu and stream id */
+   smmu = iort_node_get_id(iort_node, &sid, 0);
+   if (!smmu) {
+   pr_err(FW_BUG "Invalid SMMU reference, skipping RMR node %p\n",
+  iort_node);
+   return;
+   }
+
+   /* Retrieve RMR data */
+   rmr = (struct acpi_iort_rmr *)iort_node->node_data;
+   if (!rmr->rmr_offset || !rmr->rmr_count) {
+   pr_err(FW_BUG "Invalid RMR descriptor array, skipping RMR node 
%p\n",
+  iort_node);
+   return;
+   }
+
+   rmr_desc = ACPI_ADD_PTR(struct acpi_iort_rmr_desc, iort_node,
+   rmr->rmr_offset);
+
+   iort_rmr_desc_check_overlap(rmr_desc, rmr->rmr_count);
+
+   for (i = 0; i < rmr->rmr_count; i++, rmr_desc++) {
+   struct iommu_resv_region *region;
+   enum iommu_resv_type type;
+   int prot = IOMMU_READ | IOMMU_WRITE;
+   u64 addr = rmr_desc->base_address, size = rmr_desc->length;
+
+   if (!IS_ALIGNED(addr, SZ_64K) || !IS_ALIGNED(size, SZ_64K)) {
+   /* PAGE align base addr and size */
+   addr &= PAGE_MASK;
+   size = PAGE_ALIGN(size + 
offset_in_page(rmr_desc->base_address));
+
+   pr_err(FW_BUG "RMR descriptor[0x%llx - 0x%llx] not 
aligned to 64K, continue with [0x%llx - 0x%llx]\n",
+  rmr_desc->base_address,
+  rmr_desc->base_address + rmr_desc->length - 1,
+  addr, addr + size - 1);
+   }
+   if (rmr->flags & IOMMU_RMR_REMAP_PERMITTED) {
+   type = IOMMU_RESV_DIRECT_RELAXABLE;
+   /*
+* Set IOMMU_CACHE as IOMMU_RESV_DIRECT_RELAXABLE is
+* normally used for allocated system memory that is
+* then used for device specific reserved regions.
+*/
+   prot |= IOMMU_CACHE;
+   } else {
+   typ

[PATCH v6 1/9] iommu: Introduce a union to struct iommu_resv_region

2021-07-16 Thread Shameer Kolothum
A union is introduced to struct iommu_resv_region to hold
any firmware specific data. This is in preparation to add
support for IORT RMR reserve regions and the union now holds
the RMR specific information.

Signed-off-by: Shameer Kolothum 
---
 include/linux/iommu.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 32d448050bf7..bd0e4641c569 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -114,6 +114,13 @@ enum iommu_resv_type {
IOMMU_RESV_SW_MSI,
 };
 
+struct iommu_iort_rmr_data {
+#define IOMMU_RMR_REMAP_PERMITTED  (1 << 0)
+   u32 flags;
+   u32 sid;/* Stream Id associated with RMR entry */
+   void *smmu; /* Associated IORT SMMU node pointer */
+};
+
 /**
  * struct iommu_resv_region - descriptor for a reserved memory region
  * @list: Linked list pointers
@@ -121,6 +128,7 @@ enum iommu_resv_type {
  * @length: Length of the region in bytes
  * @prot: IOMMU Protection flags (READ/WRITE/...)
  * @type: Type of the reserved region
+ * @rmr: ACPI IORT RMR specific data
  */
 struct iommu_resv_region {
struct list_headlist;
@@ -128,6 +136,9 @@ struct iommu_resv_region {
size_t  length;
int prot;
enum iommu_resv_typetype;
+   union {
+   struct iommu_iort_rmr_data rmr;
+   } fw_data;
 };
 
 /**
-- 
2.17.1

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


[PATCH v6 0/9] ACPI/IORT: Support for IORT RMR node

2021-07-16 Thread Shameer Kolothum
Hi,

Major Changes from v5:
- Addressed comments from Robin & Lorenzo.
  : Moved iort_parse_rmr() to acpi_iort_init() from
iort_init_platform_devices().
  : Removed use of struct iort_rmr_entry during the initial
parse. Using struct iommu_resv_region instead.
  : Report RMR address alignment and overlap errors, but continue.
  : Reworked arm_smmu_init_bypass_stes() (patch # 6).
- Updated SMMUv2 bypass SMR code. Thanks to Jon N (patch #8).
- Set IOMMU protection flags(IOMMU_CACHE, IOMMU_MMIO) based
  on Type of RMR region. Suggested by Jon N.

Sanity tested on a HiSilicon D06(SMMUv3). Further testing and
feedback is greatly appreciated.

Thanks,
Shameer

--
v4 --> v5
 -Added a fw_data union to struct iommu_resv_region and removed
  struct iommu_rmr (Based on comments from Joerg/Robin).
 -Added iommu_put_rmrs() to release mem.
 -Thanks to Steve for verifying on SMMUv2, but not added the Tested-by
  yet because of the above changes.

v3 -->v4
-Included the SMMUv2 SMR bypass install changes suggested by
 Steve(patch #7)
-As per Robin's comments, RMR reserve implementation is now
 more generic  (patch #8) and dropped v3 patches 8 and 10.
-Rebase to 5.13-rc1

RFC v2 --> v3
 -Dropped RFC tag as the ACPICA header changes are now ready to be
  part of 5.13[0]. But this series still has a dependency on that patch.
 -Added IORT E.b related changes(node flags, _DSM function 5 checks for
  PCIe).
 -Changed RMR to stream id mapping from M:N to M:1 as per the spec and
  discussion here[1].
 -Last two patches add support for SMMUv2(Thanks to Jon Nettleton!)
--

Jon Nettleton (1):
  iommu/arm-smmu: Get associated RMR info and install bypass SMR

Shameer Kolothum (8):
  iommu: Introduce a union to struct iommu_resv_region
  ACPI/IORT: Add support for RMR node parsing
  iommu/dma: Introduce generic helper to retrieve RMR info
  ACPI/IORT: Add a helper to retrieve RMR memory regions
  iommu/arm-smmu-v3: Introduce strtab init helper
  iommu/arm-smmu-v3: Refactor arm_smmu_init_bypass_stes() to force
bypass
  iommu/arm-smmu-v3: Get associated RMR info and install bypass STE
  iommu/dma: Reserve any RMR regions associated with a dev

 drivers/acpi/arm64/iort.c   | 172 +++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  76 +++--
 drivers/iommu/arm/arm-smmu/arm-smmu.c   |  48 ++
 drivers/iommu/dma-iommu.c   |  89 +-
 include/linux/acpi_iort.h   |   7 +
 include/linux/dma-iommu.h   |  13 ++
 include/linux/iommu.h   |  11 ++
 7 files changed, 393 insertions(+), 23 deletions(-)

-- 
2.17.1

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

Re: [PATCH] iommu/sun50i: fix protection flag check

2021-07-16 Thread Maxime Ripard
On Fri, Jul 16, 2021 at 01:24:31PM +0900, David Stevens wrote:
> From: David Stevens 
> 
> Fix RW protection check when making a pte, so that it properly checks
> that both R and W flags are set, instead of either R or W.
> 
> Signed-off-by: David Stevens 

Acked-by: Maxime Ripard 

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