[PATCH] iommu: Allocate dev_iommu before accessing priv data

2020-09-01 Thread Torsten Hilbrich
After updating from v5.8 to v5.9-rc2 I noticed some problems when
booting a system with kernel cmdline "intel_iommu=on,igfx_off".

The following stacktrace was produced:

<6>[0.00] Command line: BOOT_IMAGE=/isolinux/bzImage console=tty1 
intel_iommu=on,igfx_off
...
<6>[3.341682] DMAR: Host address width 39
<6>[3.341684] DMAR: DRHD base: 0x00fed9 flags: 0x0
<6>[3.341702] DMAR: dmar0: reg_base_addr fed9 ver 1:0 cap 
1cc40660462 ecap 19e2ff0505e
<6>[3.341705] DMAR: DRHD base: 0x00fed91000 flags: 0x1
<6>[3.341711] DMAR: dmar1: reg_base_addr fed91000 ver 1:0 cap 
d2008c40660462 ecap f050da
<6>[3.341713] DMAR: RMRR base: 0x009aa9f000 end: 0x009aabefff
<6>[3.341716] DMAR: RMRR base: 0x009d00 end: 0x009f7f
<6>[3.341726] DMAR: No ATSR found
<1>[3.341772] BUG: kernel NULL pointer dereference, address: 
0038
<1>[3.341774] #PF: supervisor write access in kernel mode
<1>[3.341776] #PF: error_code(0x0002) - not-present page
<6>[3.341777] PGD 0 P4D 0
<4>[3.341780] Oops: 0002 [#1] SMP PTI
<4>[3.341783] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.9.0-devel+ #2
<4>[3.341785] Hardware name: LENOVO 20HGS0TW00/20HGS0TW00, BIOS N1WET46S 
(1.25s ) 03/30/2018
<4>[3.341790] RIP: 0010:intel_iommu_init+0xed0/0x1136
<4>[3.341792] Code: fe e9 61 02 00 00 bb f4 ff ff ff e9 57 02 00 00 48 63 
d1 48 c1 e2 04 48 03 50 20 48 8b 12 48 85 d2 74 0b 48 8b 92 d0 02 00 00 <48> 89 
7a 38 ff c1 e9 15 f5 ff ff 48 c7 c7 60 99 ac a7 49 c7 c7 a0
<4>[3.341796] RSP: :96d180073dd0 EFLAGS: 00010282
<4>[3.341798] RAX: 8c91037a7d20 RBX:  RCX: 

<4>[3.341800] RDX:  RSI:  RDI: 

<4>[3.341802] RBP: 96d180073e90 R08: 0001 R09: 
8c91039fe3c0
<4>[3.341804] R10: 0226 R11: 0226 R12: 
000b
<4>[3.341806] R13: 8c910367c650 R14: a8426d60 R15: 

<4>[3.341808] FS:  () GS:8c910748() 
knlGS:
<4>[3.341810] CS:  0010 DS:  ES:  CR0: 80050033
<4>[3.341812] CR2: 0038 CR3: 0004b100a001 CR4: 
003706e0
<4>[3.341814] Call Trace:
<4>[3.341820]  ? _raw_spin_unlock_irqrestore+0x1f/0x30
<4>[3.341824]  ? call_rcu+0x10e/0x320
<4>[3.341828]  ? trace_hardirqs_on+0x2c/0xd0
<4>[3.341831]  ? rdinit_setup+0x2c/0x2c
<4>[3.341834]  ? e820__memblock_setup+0x8b/0x8b
<4>[3.341836]  pci_iommu_init+0x16/0x3f
<4>[3.341839]  do_one_initcall+0x46/0x1e4
<4>[3.341842]  kernel_init_freeable+0x169/0x1b2
<4>[3.341845]  ? rest_init+0x9f/0x9f
<4>[3.341847]  kernel_init+0xa/0x101
<4>[3.341849]  ret_from_fork+0x22/0x30
<4>[3.341851] Modules linked in:
<4>[3.341854] CR2: 0038
<4>[3.341860] ---[ end trace 3653722a6f936f18 ]---

I could track the problem down to the dev_iommu_priv_set call in the function
init_no_remapping_devices in the path where !dmar_map_gfx. It turned out that
the dev->iommu entry is NULL at this time.

Lu Baolu  suggested for dev_iommu_priv_set
to automatically allocate the iommu entry by using the function
dev_iommu_get to retrieve that pointer. This function allocates the
entry if needed.

Fixes: 01b9d4e21148 ("iommu/vt-d: Use dev_iommu_priv_get/set()")
Signed-off-by: Torsten Hilbrich 
Tested-by: Torsten Hilbrich 
Link: https://lists.linuxfoundation.org/pipermail/iommu/2020-August/048098.html
---
 drivers/iommu/iommu.c | 22 ++
 include/linux/iommu.h | 11 ++-
 2 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 609bd25bf154..3edca2a31296 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2849,3 +2849,25 @@ int iommu_sva_get_pasid(struct iommu_sva *handle)
return ops->sva_get_pasid(handle);
 }
 EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
+
+void *dev_iommu_priv_get(struct device *dev)
+{
+   struct dev_iommu *param = dev_iommu_get(dev);
+
+   if (WARN_ON(!param))
+   return ERR_PTR(-ENOMEM);
+
+return param->priv;
+}
+EXPORT_SYMBOL_GPL(dev_iommu_priv_get);
+
+void dev_iommu_priv_set(struct device *dev, void *priv)
+{
+   struct dev_iommu *param = dev_iommu_get(dev);
+
+   if (WARN_ON(!param))
+   return;
+
+param->priv = priv;
+}
+EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index fee209efb756..e3e725cf64b3 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -609,15 +609,8 @@ static inline void dev_iommu_fwspec_set(struct device *dev,
dev->iommu->fwspec = fwspec;
 }
 
-static inline void *dev_iommu_priv_get(struct device *dev)
-{
-   return dev->iommu->priv;
-}
-
-static inline void dev_iommu_priv_set(struct device *dev, void *priv)
-{
-   

[PATCH 2/2] iommu: amd: Use cmpxchg_double() when updating 128-bit IRTE

2020-09-01 Thread Suravee Suthikulpanit
When using 128-bit interrupt-remapping table entry (IRTE) (a.k.a GA mode),
current driver disables interrupt remapping when it updates the IRTE
so that the upper and lower 64-bit values can be updated safely.

However, this creates a small window, where the interrupt could
arrive and result in IO_PAGE_FAULT (for interrupt) as shown below.

  IOMMU DriverDevice IRQ
  ===
  irte.RemapEn=0
   ...
   change IRTEIRQ from device ==> IO_PAGE_FAULT !!
   ...
  irte.RemapEn=1

This scenario has been observed when changing irq affinity on a system
running I/O-intensive workload, in which the destination APIC ID
in the IRTE is updated.

Instead, use cmpxchg_double() to update the 128-bit IRTE at once without
disabling the interrupt remapping. However, this means several features,
which require GA (128-bit IRTE) support will also be affected if cmpxchg16b
is not supported (which is unprecedented for AMD processors w/ IOMMU).

Reported-by: Sean Osborne 
Tested-by: Erik Rockstrom 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/Kconfig |  2 +-
 drivers/iommu/amd/init.c  | 21 +++--
 drivers/iommu/amd/iommu.c | 17 +
 3 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/amd/Kconfig b/drivers/iommu/amd/Kconfig
index 1f061d91e0b8..626b97d0dd21 100644
--- a/drivers/iommu/amd/Kconfig
+++ b/drivers/iommu/amd/Kconfig
@@ -10,7 +10,7 @@ config AMD_IOMMU
select IOMMU_API
select IOMMU_IOVA
select IOMMU_DMA
-   depends on X86_64 && PCI && ACPI
+   depends on X86_64 && PCI && ACPI && HAVE_CMPXCHG_DOUBLE
help
  With this option you can enable support for AMD IOMMU hardware in
  your system. An IOMMU is a hardware component which provides
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index c652f16eb702..ad30467f6930 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1511,7 +1511,14 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
else
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-   if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
+
+   /*
+* Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
+* GAM also requires GA mode. Therefore, we need to
+* check cmbxchg16b support before enabling it.
+*/
+   if (!boot_cpu_has(X86_FEATURE_CX16) ||
+   ((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
break;
case 0x11:
@@ -1520,8 +1527,18 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
else
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-   if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0))
+
+   /*
+* Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
+* XT, GAM also requires GA mode. Therefore, we need to
+* check cmbxchg16b support before enabling them.
+*/
+   if (boot_cpu_has(X86_FEATURE_CX16) ||
+   ((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) {
amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
+   break;
+   }
+
/*
 * Note: Since iommu_update_intcapxt() leverages
 * the IOMMU MMIO access to MSI capability block registers
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 967f4e96d1eb..a382d7a73eaa 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3292,6 +3292,7 @@ static int alloc_irq_index(u16 devid, int count, bool 
align,
 static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
  struct amd_ir_data *data)
 {
+   bool ret;
struct irq_remap_table *table;
struct amd_iommu *iommu;
unsigned long flags;
@@ -3309,10 +3310,18 @@ static int modify_irte_ga(u16 devid, int index, struct 
irte_ga *irte,
 
entry = (struct irte_ga *)table->table;
entry = [index];
-   entry->lo.fields_remap.valid = 0;
-   entry->hi.val = irte->hi.val;
-   entry->lo.val = irte->lo.val;
-   entry->lo.fields_remap.valid = 1;
+
+   ret = cmpxchg_double(>lo.val, >hi.val,
+entry->lo.val, entry->hi.val,
+irte->lo.val, irte->hi.val);
+   /*
+* We use cmpxchg16 to atomically update the 128-bit IRTE,
+* and it cannot be updated by the hardware or other processors
+* 

答复: 答复: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI device in RMRR

2020-09-01 Thread FelixCui-oc
hi baolu,

> So you have a hidden device (invisible to host kernel). But you need to

>setup some identity mappings for this device, so that the firmware
>could keep working, right?

>The platform designs this by putting that range in the RMRR table and
>expecting the OS kernel to setup identity mappings during boot.

>Do I understand it right?


Yes. What you understand is correct.


Best regards

Felixcui-oc


发件人: Lu Baolu 
发送时间: 2020年9月2日 10:32:36
收件人: FelixCui-oc; Joerg Roedel; iommu@lists.linux-foundation.org; 
linux-ker...@vger.kernel.org; David Woodhouse; Dan Carpenter; 
kbu...@lists.01.org
抄送: baolu...@linux.intel.com; CobeChen-oc; RaymondPang-oc; Tony W Wang-oc; 
Ashok Raj
主题: Re: 答复: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI device in 
RMRR

On 9/1/20 5:13 PM, FelixCui-oc wrote:
> hi  baolu ,
>
> These ACPI devices can be retrieved from the kernel
> and there is no bound device driver .

So you have a hidden device (invisible to host kernel). But you need to
setup some identity mappings for this device, so that the firmware
could keep working, right?

The platform designs this by putting that range in the RMRR table and
expecting the OS kernel to setup identity mappings during boot.

Do I understand it right?

Best regards,
baolu

>
>
> Best regards
>
> Felixcui-oc
>
> 
> *发件人:* Lu Baolu 
> *发送时间:* 2020年9月1日 14:12:34
> *收件人:* FelixCui-oc; Joerg Roedel; iommu@lists.linux-foundation.org;
> linux-ker...@vger.kernel.org; David Woodhouse; Dan Carpenter;
> kbu...@lists.01.org
> *抄送:* baolu...@linux.intel.com; CobeChen-oc; RaymondPang-oc; Tony W
> Wang-oc
> *主题:* Re: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI
> device in RMRR
> Hi Felix,
>
> On 8/27/20 6:02 PM, FelixCuioc wrote:
>> After acpi device in RMRR is detected,it is necessary
>> to establish a mapping for these devices.
>> In acpi_device_create_direct_mappings(),create a mapping
>> for the acpi device in RMRR.
>> Add a helper to achieve the acpi namespace device can
>> access the RMRR region.
>
> Are those ACPI devices visible to kernel? If so, any device driver bound
> for it?
>
> Best regards,
> baolu
>
>>
>> Signed-off-by: FelixCuioc 
>> ---
>>   drivers/iommu/intel/iommu.c | 29 +
>>   drivers/iommu/iommu.c   |  6 ++
>>   include/linux/iommu.h   |  3 +++
>>   3 files changed, 38 insertions(+)
>>
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index 208a91605288..51d7a5b18f41 100644
>> --- a/drivers/iommu/intel/iommu.c
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4799,6 +4799,21 @@ static int __init platform_optin_force_iommu(void)
>>return 1;
>>   }
>>
>> +static int acpi_device_create_direct_mappings(struct device *pn_dev, struct 
>> device *acpi_device)
>> +{
>> + struct iommu_group *group;
>> +
>> + acpi_device->bus->iommu_ops = _iommu_ops;
>> + group = iommu_group_get(pn_dev);
>> + if (!group) {
>> + pr_warn("ACPI name space devices create direct mappings 
>> wrong!\n");
>> + return -EINVAL;
>> + }
>> + __acpi_device_create_direct_mappings(group, acpi_device);
>> +
>> + return 0;
>> +}
>> +
>>   static int __init probe_acpi_namespace_devices(void)
>>   {
>>struct dmar_drhd_unit *drhd;
>> @@ -4813,6 +4828,7 @@ static int __init probe_acpi_namespace_devices(void)
>>struct acpi_device_physical_node *pn;
>>struct iommu_group *group;
>>struct acpi_device *adev;
>> + struct device *pn_dev = NULL;
>>
>>if (dev->bus != _bus_type)
>>continue;
>> @@ -4823,6 +4839,7 @@ static int __init probe_acpi_namespace_devices(void)
>>>physical_node_list, node) {
>>group = iommu_group_get(pn->dev);
>>if (group) {
>> + pn_dev = pn->dev;
>>iommu_group_put(group);
>>continue;
>>}
>> @@ -4831,7 +4848,19 @@ static int __init probe_acpi_namespace_devices(void)
>>ret = iommu_probe_device(pn->dev);
>>if (ret)
>>break;
>> + pn_dev = pn->dev;
>> + }
>> + if (!pn_dev) {
>> + dev->bus->iommu_ops = _iommu_ops;
>> + ret = iommu_probe_device(dev);
>> + if (ret) {
>> + pr_err("acpi_device probe fail! 
>> ret:%d\n", ret);
>> + goto unlock;
>> + }
>> 

Re: [Regression] [PATCH] iommu: Avoid crash in init_no_remapping_devices if iommu is NULL

2020-09-01 Thread Lu Baolu

Hi Torsten,

On 9/1/20 10:41 PM, Torsten Hilbrich wrote:

On 01.09.20 04:02, Lu Baolu wrote:
[...]

This looks more like a generic issue, used-before-allocated, and should
be fixed in iommu.c instead of VT-d driver. How about

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 8fd93a5b8764..a599da87eb60 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -190,6 +190,28 @@ static void dev_iommu_free(struct device *dev)
     dev->iommu = NULL;
  }

+void *dev_iommu_priv_get(struct device *dev)
+{
+   struct dev_iommu *param = dev_iommu_get(dev);
+
+   if (WARN_ON(!param))
+   return ERR_PTR(-ENOMEM);
+
+    return param->priv;
+}
+EXPORT_SYMBOL_GPL(dev_iommu_priv_get);
+
+void dev_iommu_priv_set(struct device *dev, void *priv)
+{
+   struct dev_iommu *param = dev_iommu_get(dev);
+
+   if (WARN_ON(!param))
+   return;
+
+    param->priv = priv;
+}
+EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
+


This fix would work in my case. I tested it with slight modification to
replace the inline routines in include/linux/iommu.h.

The WARN_ON was not triggered during my tests. However, looking at the
definition of dev_iommu_get this is to be expected.


So I suppose you will post a new version. :-)

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

Re: [Regression] [PATCH] iommu: Avoid crash in init_no_remapping_devices if iommu is NULL

2020-09-01 Thread Lu Baolu

hi Torsten,

On 9/1/20 10:41 PM, Torsten Hilbrich wrote:

On 01.09.20 04:02, Lu Baolu wrote:
[...]

This looks more like a generic issue, used-before-allocated, and should
be fixed in iommu.c instead of VT-d driver. How about

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 8fd93a5b8764..a599da87eb60 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -190,6 +190,28 @@ static void dev_iommu_free(struct device *dev)
     dev->iommu = NULL;
  }

+void *dev_iommu_priv_get(struct device *dev)
+{
+   struct dev_iommu *param = dev_iommu_get(dev);
+
+   if (WARN_ON(!param))
+   return ERR_PTR(-ENOMEM);
+
+    return param->priv;
+}
+EXPORT_SYMBOL_GPL(dev_iommu_priv_get);
+
+void dev_iommu_priv_set(struct device *dev, void *priv)
+{
+   struct dev_iommu *param = dev_iommu_get(dev);
+
+   if (WARN_ON(!param))
+   return;
+
+    param->priv = priv;
+}
+EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
+


This fix would work in my case. I tested it with slight modification to
replace the inline routines in include/linux/iommu.h.

The WARN_ON was not triggered during my tests. However, looking at the
definition of dev_iommu_get this is to be expected.


So I suppose you will post a new version. :-)

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

Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs

2020-09-01 Thread Lu Baolu

Hi,

On 9/2/20 5:28 AM, Jacob Pan wrote:

On Mon, 24 Aug 2020 10:24:11 +0800
Lu Baolu  wrote:


Hi Jacob,

On 8/22/20 12:35 PM, Jacob Pan wrote:

ioasid_set was introduced as an arbitrary token that are shared by a
group of IOASIDs. For example, if IOASID #1 and #2 are allocated
via the same ioasid_set*, they are viewed as to belong to the same
set.

For guest SVA usages, system-wide IOASID resources need to be
partitioned such that VMs can have its own quota and being managed
separately. ioasid_set is the perfect candidate for meeting such
requirements. This patch redefines and extends ioasid_set with the
following new fields:
- Quota
- Reference count
- Storage of its namespace
- The token is stored in the new ioasid_set but with optional types

ioasid_set level APIs are introduced that wires up these new data.
Existing users of IOASID APIs are converted where a host IOASID set
is allocated for bare-metal usage.

Signed-off-by: Liu Yi L 
Signed-off-by: Jacob Pan 
---
   drivers/iommu/intel/iommu.c |  27 ++-
   drivers/iommu/intel/pasid.h |   1 +
   drivers/iommu/intel/svm.c   |   8 +-
   drivers/iommu/ioasid.c  | 390
+---
include/linux/ioasid.h  |  82 -- 5 files changed, 465
insertions(+), 43 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c
b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb
100644 --- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -42,6 +42,7 @@
   #include 
   #include 
   #include 
+#include 
   #include 
   #include 
   #include 
@@ -103,6 +104,9 @@
*/
   #define INTEL_IOMMU_PGSIZES  (~0xFFFUL)
   
+/* PASIDs used by host SVM */

+struct ioasid_set *host_pasid_set;
+
   static inline int agaw_to_level(int agaw)
   {
return agaw + 2;
@@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t
ioasid, void *data)
 * Sanity check the ioasid owner is done at upper layer,
e.g. VFIO
 * We can only free the PASID when all the devices are
unbound. */
-   if (ioasid_find(NULL, ioasid, NULL)) {
-   pr_alert("Cannot free active IOASID %d\n", ioasid);
+   if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) {
+   pr_err("Cannot free IOASID %d, not in system
set\n", ioasid); return;
}
vcmd_free_pasid(iommu, ioasid);
@@ -3288,6 +3292,19 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
   
+	/* PASID is needed for scalable mode irrespective to SVM */

+   if (intel_iommu_sm) {
+   ioasid_install_capacity(intel_pasid_max_id);
+   /* We should not run out of IOASIDs at boot */
+   host_pasid_set = ioasid_alloc_set(NULL,
PID_MAX_DEFAULT,
+
IOASID_SET_TYPE_NULL);
+   if (IS_ERR_OR_NULL(host_pasid_set)) {
+   pr_err("Failed to enable host PASID
allocator %lu\n",
+   PTR_ERR(host_pasid_set));
+   intel_iommu_sm = 0;
+   }
+   }
+
/*
 * for each drhd
 *   enable fault log
@@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct
dmar_domain *domain, domain->auxd_refcnt--;
   
   	if (!domain->auxd_refcnt && domain->default_pasid > 0)

-   ioasid_free(domain->default_pasid);
+   ioasid_free(host_pasid_set, domain->default_pasid);
   }
   
   static int aux_domain_add_dev(struct dmar_domain *domain,

@@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct
dmar_domain *domain, int pasid;
   
   		/* No private data needed for the default pasid */

-   pasid = ioasid_alloc(NULL, PASID_MIN,
+   pasid = ioasid_alloc(host_pasid_set, PASID_MIN,
 pci_max_pasids(to_pci_dev(dev))
- 1, NULL);
if (pasid == INVALID_IOASID) {
@@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct
dmar_domain *domain, spin_unlock(>lock);
spin_unlock_irqrestore(_domain_lock, flags);
if (!domain->auxd_refcnt && domain->default_pasid > 0)
-   ioasid_free(domain->default_pasid);
+   ioasid_free(host_pasid_set, domain->default_pasid);
   
   	return ret;

   }
diff --git a/drivers/iommu/intel/pasid.h
b/drivers/iommu/intel/pasid.h index c9850766c3a9..ccdc23446015
100644 --- a/drivers/iommu/intel/pasid.h
+++ b/drivers/iommu/intel/pasid.h
@@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct
pasid_entry *pte) }
   
   extern u32 intel_pasid_max_id;

+extern struct ioasid_set *host_pasid_set;
   int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t
gfp); void intel_pasid_free_id(int pasid);
   void *intel_pasid_lookup_id(int pasid);
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 37a9beabc0ca..634e191ca2c3 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -551,7 +551,7 @@ intel_svm_bind_mm(struct device *dev, int
flags, struct svm_dev_ops *ops, pasid_max = 

Re: 答复: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI device in RMRR

2020-09-01 Thread Lu Baolu

On 9/1/20 5:13 PM, FelixCui-oc wrote:

hi  baolu ,

                    These ACPI devices can be retrieved from the kernel 
and there is no bound device driver .


So you have a hidden device (invisible to host kernel). But you need to
setup some identity mappings for this device, so that the firmware
could keep working, right?

The platform designs this by putting that range in the RMRR table and
expecting the OS kernel to setup identity mappings during boot.

Do I understand it right?

Best regards,
baolu




Best regards

Felixcui-oc


*发件人:* Lu Baolu 
*发送时间:* 2020年9月1日 14:12:34
*收件人:* FelixCui-oc; Joerg Roedel; iommu@lists.linux-foundation.org; 
linux-ker...@vger.kernel.org; David Woodhouse; Dan Carpenter; 
kbu...@lists.01.org
*抄送:* baolu...@linux.intel.com; CobeChen-oc; RaymondPang-oc; Tony W 
Wang-oc
*主题:* Re: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI 
device in RMRR

Hi Felix,

On 8/27/20 6:02 PM, FelixCuioc wrote:

After acpi device in RMRR is detected,it is necessary
to establish a mapping for these devices.
In acpi_device_create_direct_mappings(),create a mapping
for the acpi device in RMRR.
Add a helper to achieve the acpi namespace device can
access the RMRR region.


Are those ACPI devices visible to kernel? If so, any device driver bound
for it?

Best regards,
baolu



Signed-off-by: FelixCuioc 
---
   drivers/iommu/intel/iommu.c | 29 +
   drivers/iommu/iommu.c   |  6 ++
   include/linux/iommu.h   |  3 +++
   3 files changed, 38 insertions(+)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 208a91605288..51d7a5b18f41 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4799,6 +4799,21 @@ static int __init platform_optin_force_iommu(void)
    return 1;
   }
  
+static int acpi_device_create_direct_mappings(struct device *pn_dev, struct device *acpi_device)

+{
+ struct iommu_group *group;
+
+ acpi_device->bus->iommu_ops = _iommu_ops;
+ group = iommu_group_get(pn_dev);
+ if (!group) {
+ pr_warn("ACPI name space devices create direct mappings 
wrong!\n");
+ return -EINVAL;
+ }
+ __acpi_device_create_direct_mappings(group, acpi_device);
+
+ return 0;
+}
+
   static int __init probe_acpi_namespace_devices(void)
   {
    struct dmar_drhd_unit *drhd;
@@ -4813,6 +4828,7 @@ static int __init probe_acpi_namespace_devices(void)
    struct acpi_device_physical_node *pn;
    struct iommu_group *group;
    struct acpi_device *adev;
+ struct device *pn_dev = NULL;
  
    if (dev->bus != _bus_type)

    continue;
@@ -4823,6 +4839,7 @@ static int __init probe_acpi_namespace_devices(void)
    >physical_node_list, node) {
    group = iommu_group_get(pn->dev);
    if (group) {
+ pn_dev = pn->dev;
    iommu_group_put(group);
    continue;
    }
@@ -4831,7 +4848,19 @@ static int __init probe_acpi_namespace_devices(void)
    ret = iommu_probe_device(pn->dev);
    if (ret)
    break;
+ pn_dev = pn->dev;
+ }
+ if (!pn_dev) {
+ dev->bus->iommu_ops = _iommu_ops;
+ ret = iommu_probe_device(dev);
+ if (ret) {
+ pr_err("acpi_device probe fail! 
ret:%d\n", ret);
+ goto unlock;
+ }
+ goto unlock;
    }
+ ret = acpi_device_create_direct_mappings(pn_dev, dev);
+unlock:
    mutex_unlock(>physical_node_lock);
  
    if (ret)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 609bd25bf154..4f714a2d5ef7 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -779,6 +779,12 @@ static bool iommu_is_attach_deferred(struct iommu_domain 
*domain,
    return false;
   }
  
+void  __acpi_device_create_direct_mappings(struct iommu_group *group, struct device *acpi_device)

+{
+ iommu_create_device_direct_mappings(group, acpi_device);
+}
+EXPORT_SYMBOL_GPL(__acpi_device_create_direct_mappings);
+
   /**
    * iommu_group_add_device - add a device to an iommu group
    * @group: the group into which to add the device (reference should be held)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index fee209efb756..9be134775886 100644
--- a/include/linux/iommu.h
+++ 

答复: [PATCH v3 1/2] iommu/vt-d:Add support for detecting ACPI device in RMRR

2020-09-01 Thread FelixCui-oc
hi  baolu ,

   Add pr_info(), there will be a problem.

   dmar_acpi_bus_add_dev() will call 
dmar_acpi_insert_dev_scope() twice. So it will  print two identical  logs. This 
is similar to dmar_pci_bus_add_dev(). What do you think?



  Add pr_warn(), No problem.


Best regards

Felixcui-oc




发件人: FelixCui-oc
发送时间: 2020年9月1日 15:53:47
收件人: Lu Baolu; Joerg Roedel; iommu@lists.linux-foundation.org; 
linux-ker...@vger.kernel.org; David Woodhouse; Dan Carpenter; 
kbu...@lists.01.org
抄送: CobeChen-oc; RaymondPang-oc; Tony W Wang-oc
主题: 答复: [PATCH v3 1/2] iommu/vt-d:Add support for detecting ACPI device in RMRR


hi  baolu,

  The function dmar_rmrr_add_acpi_dev() is defined in 
intel/iommu.c because struct dmar_rmrr_unit {} is defined in intel/iommu.c.

  And dmar_parse_one_rmrr()  is also defined here, so we think 
it should be defined in iommu.c.


Best regards
Felixcui-oc


发件人: Lu Baolu 
发送时间: 2020年9月1日 14:05
收件人: FelixCui-oc; Joerg Roedel; iommu@lists.linux-foundation.org; 
linux-ker...@vger.kernel.org; David Woodhouse; Dan Carpenter; 
kbu...@lists.01.org
抄送: baolu...@linux.intel.com; CobeChen-oc; RaymondPang-oc; Tony W Wang-oc
主题: Re: [PATCH v3 1/2] iommu/vt-d:Add support for detecting ACPI device in RMRR

Hi Felix,

On 8/27/20 6:02 PM, FelixCuioc wrote:
> Some ACPI devices need to issue dma requests to access
> the reserved memory area.BIOS uses the device scope type
> ACPI_NAMESPACE_DEVICE in RMRR to report these ACPI devices.
> This patch add support for detecting ACPI devices in RMRR.
>
> Signed-off-by: FelixCuioc 
> ---
>   drivers/iommu/intel/dmar.c  | 76 +
>   drivers/iommu/intel/iommu.c | 23 ++-
>   include/linux/dmar.h| 12 +-
>   3 files changed, 76 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
> index 93e6345f3414..f6691c36bd3f 100644
> --- a/drivers/iommu/intel/dmar.c
> +++ b/drivers/iommu/intel/dmar.c
> @@ -215,7 +215,7 @@ static bool dmar_match_pci_path(struct 
> dmar_pci_notify_info *info, int bus,
>   }
>
>   /* Return: > 0 if match found, 0 if no match found, < 0 if error happens */
> -int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
> +int dmar_pci_insert_dev_scope(struct dmar_pci_notify_info *info,
>  void *start, void*end, u16 segment,
>  struct dmar_dev_scope *devices,
>  int devices_cnt)
> @@ -304,7 +304,7 @@ static int dmar_pci_bus_add_dev(struct 
> dmar_pci_notify_info *info)
>
>drhd = container_of(dmaru->hdr,
>struct acpi_dmar_hardware_unit, header);
> - ret = dmar_insert_dev_scope(info, (void *)(drhd + 1),
> + ret = dmar_pci_insert_dev_scope(info, (void *)(drhd + 1),
>((void *)drhd) + drhd->header.length,
>dmaru->segment,
>dmaru->devices, dmaru->devices_cnt);
> @@ -697,47 +697,59 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
>return dmaru;
>   }
>
> -static void __init dmar_acpi_insert_dev_scope(u8 device_number,
> -   struct acpi_device *adev)
> +/* Return: > 0 if match found, 0 if no match found */
> +bool dmar_acpi_insert_dev_scope(u8 device_number,
> + struct acpi_device *adev,
> + void *start, void *end,
> + struct dmar_dev_scope *devices,
> + int devices_cnt)
>   {
> - struct dmar_drhd_unit *dmaru;
> - struct acpi_dmar_hardware_unit *drhd;
>struct acpi_dmar_device_scope *scope;
>struct device *tmp;
>int i;
>struct acpi_dmar_pci_path *path;
>
> + for (; start < end; start += scope->length) {
> + scope = start;
> + if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_NAMESPACE)
> + continue;
> + if (scope->enumeration_id != device_number)
> + continue;
> + path = (void *)(scope + 1);
> + for_each_dev_scope(devices, devices_cnt, i, tmp)
> + if (tmp == NULL) {
> + devices[i].bus = scope->bus;
> + devices[i].devfn = PCI_DEVFN(path->device, 
> path->function);
> + rcu_assign_pointer(devices[i].dev,
> +get_device(>dev));
> + return true;
> + }
> + WARN_ON(i >= devices_cnt);
> + }
> + return false;
> +}
> +
> +static int dmar_acpi_bus_add_dev(u8 device_number, struct acpi_device *adev)
> +{
> + struct dmar_drhd_unit *dmaru;
> + struct 

Re: [PATCH v9 12/32] drm: msm: fix common struct sg_table related issues

2020-09-01 Thread Rob Clark
On Tue, Sep 1, 2020 at 12:14 PM Robin Murphy  wrote:
>
> On 2020-08-26 07:32, Marek Szyprowski wrote:
> > The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
> > returns the number of the created entries in the DMA address space.
> > However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
> > dma_unmap_sg must be called with the original number of the entries
> > passed to the dma_map_sg().
> >
> > struct sg_table is a common structure used for describing a non-contiguous
> > memory buffer, used commonly in the DRM and graphics subsystems. It
> > consists of a scatterlist with memory pages and DMA addresses (sgl entry),
> > as well as the number of scatterlist entries: CPU pages (orig_nents entry)
> > and DMA mapped pages (nents entry).
> >
> > It turned out that it was a common mistake to misuse nents and orig_nents
> > entries, calling DMA-mapping functions with a wrong number of entries or
> > ignoring the number of mapped entries returned by the dma_map_sg()
> > function.
> >
> > To avoid such issues, lets use a common dma-mapping wrappers operating
> > directly on the struct sg_table objects and use scatterlist page
> > iterators where possible. This, almost always, hides references to the
> > nents and orig_nents entries, making the code robust, easier to follow
> > and copy/paste safe.
> >
> > Signed-off-by: Marek Szyprowski 
> > Acked-by: Rob Clark 
> > ---
> >   drivers/gpu/drm/msm/msm_gem.c| 13 +
> >   drivers/gpu/drm/msm/msm_gpummu.c | 14 ++
> >   drivers/gpu/drm/msm/msm_iommu.c  |  2 +-
> >   3 files changed, 12 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
> > index b2f49152b4d4..8c7ae812b813 100644
> > --- a/drivers/gpu/drm/msm/msm_gem.c
> > +++ b/drivers/gpu/drm/msm/msm_gem.c
> > @@ -53,11 +53,10 @@ static void sync_for_device(struct msm_gem_object 
> > *msm_obj)
> >   struct device *dev = msm_obj->base.dev->dev;
> >
> >   if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {
> > - dma_sync_sg_for_device(dev, msm_obj->sgt->sgl,
> > - msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
> > + dma_sync_sgtable_for_device(dev, msm_obj->sgt,
> > + DMA_BIDIRECTIONAL);
> >   } else {
> > - dma_map_sg(dev, msm_obj->sgt->sgl,
> > - msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
> > + dma_map_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0);
> >   }
> >   }
> >
> > @@ -66,11 +65,9 @@ static void sync_for_cpu(struct msm_gem_object *msm_obj)
> >   struct device *dev = msm_obj->base.dev->dev;
> >
> >   if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {
> > - dma_sync_sg_for_cpu(dev, msm_obj->sgt->sgl,
> > - msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
> > + dma_sync_sgtable_for_cpu(dev, msm_obj->sgt, 
> > DMA_BIDIRECTIONAL);
> >   } else {
> > - dma_unmap_sg(dev, msm_obj->sgt->sgl,
> > - msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
> > + dma_unmap_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0);
> >   }
> >   }
> >
> > diff --git a/drivers/gpu/drm/msm/msm_gpummu.c 
> > b/drivers/gpu/drm/msm/msm_gpummu.c
> > index 310a31b05faa..319f06c28235 100644
> > --- a/drivers/gpu/drm/msm/msm_gpummu.c
> > +++ b/drivers/gpu/drm/msm/msm_gpummu.c
> > @@ -30,21 +30,19 @@ static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t 
> > iova,
> >   {
> >   struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
> >   unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE;
> > - struct scatterlist *sg;
> > + struct sg_dma_page_iter dma_iter;
> >   unsigned prot_bits = 0;
> > - unsigned i, j;
> >
> >   if (prot & IOMMU_WRITE)
> >   prot_bits |= 1;
> >   if (prot & IOMMU_READ)
> >   prot_bits |= 2;
> >
> > - for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> > - dma_addr_t addr = sg->dma_address;
> > - for (j = 0; j < sg->length / GPUMMU_PAGE_SIZE; j++, idx++) {
> > - gpummu->table[idx] = addr | prot_bits;
> > - addr += GPUMMU_PAGE_SIZE;
> > - }
> > + for_each_sgtable_dma_page(sgt, _iter, 0) {
> > + dma_addr_t addr = sg_page_iter_dma_address(_iter);
> > +
> > + BUILD_BUG_ON(GPUMMU_PAGE_SIZE != PAGE_SIZE);
> > + gpummu->table[idx++] = addr | prot_bits;
>
> Given that the BUILD_BUG_ON might prevent valid arm64 configs from
> building, how about a simple tweak like:
>
> for (i = 0; i < PAGE_SIZE; i += GPUMMU_PAGE_SIZE)
> gpummu->table[idx++] = i + addr | prot_bits;
> ?
>
> Or alternatively perhaps some more aggressive #ifdefs or makefile tweaks
> to prevent the GPUMMU code building for arm64 at all if it's only
> relevant to 32-bit platforms (which I believe might be the case).


Re: [PATCH v9 11/32] drm: mediatek: use common helper for extracting pages array

2020-09-01 Thread Chun-Kuang Hu
Robin Murphy  於 2020年9月2日 週三 上午2:55寫道:
>
> On 2020-08-26 07:32, Marek Szyprowski wrote:
> > Use common helper for converting a sg_table object into struct
> > page pointer array.
>
> Reviewed-by: Robin Murphy 
>
> Side note: is mtk_drm_gem_prime_vmap() missing a call to
> sg_free_table(sgt) before its kfree(sgt)?

Yes, we need another patch to fix that bug, But for this patch,

Acked-by: Chun-Kuang Hu 

>
> > Signed-off-by: Marek Szyprowski 
> > ---
> >   drivers/gpu/drm/mediatek/mtk_drm_gem.c | 9 ++---
> >   1 file changed, 2 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
> > b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> > index 3654ec732029..0583e557ad37 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> > @@ -233,9 +233,7 @@ void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj)
> >   {
> >   struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
> >   struct sg_table *sgt;
> > - struct sg_page_iter iter;
> >   unsigned int npages;
> > - unsigned int i = 0;
> >
> >   if (mtk_gem->kvaddr)
> >   return mtk_gem->kvaddr;
> > @@ -249,11 +247,8 @@ void *mtk_drm_gem_prime_vmap(struct drm_gem_object 
> > *obj)
> >   if (!mtk_gem->pages)
> >   goto out;
> >
> > - for_each_sg_page(sgt->sgl, , sgt->orig_nents, 0) {
> > - mtk_gem->pages[i++] = sg_page_iter_page();
> > - if (i > npages)
> > - break;
> > - }
> > + drm_prime_sg_to_page_addr_arrays(sgt, mtk_gem->pages, NULL, npages);
> > +
> >   mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
> >  pgprot_writecombine(PAGE_KERNEL));
> >
> >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH v9 10/32] drm: mediatek: use common helper for a scatterlist contiguity check

2020-09-01 Thread Chun-Kuang Hu
Hi, Marek:

Marek Szyprowski  於 2020年8月26日 週三 下午2:35寫道:
>
> Use common helper for checking the contiguity of the imported dma-buf and
> do this check before allocating resources, so the error path is simpler.
>

Acked-by: Chun-Kuang Hu 

> Signed-off-by: Marek Szyprowski 
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_gem.c | 28 ++
>  1 file changed, 6 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
> b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> index 6190cc3b7b0d..3654ec732029 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> @@ -212,37 +212,21 @@ struct drm_gem_object 
> *mtk_gem_prime_import_sg_table(struct drm_device *dev,
> struct dma_buf_attachment *attach, struct sg_table 
> *sg)
>  {
> struct mtk_drm_gem_obj *mtk_gem;
> -   int ret;
> -   struct scatterlist *s;
> -   unsigned int i;
> -   dma_addr_t expected;
>
> -   mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size);
> +   /* check if the entries in the sg_table are contiguous */
> +   if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
> +   DRM_ERROR("sg_table is not contiguous");
> +   return ERR_PTR(-EINVAL);
> +   }
>
> +   mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size);
> if (IS_ERR(mtk_gem))
> return ERR_CAST(mtk_gem);
>
> -   expected = sg_dma_address(sg->sgl);
> -   for_each_sg(sg->sgl, s, sg->nents, i) {
> -   if (!sg_dma_len(s))
> -   break;
> -
> -   if (sg_dma_address(s) != expected) {
> -   DRM_ERROR("sg_table is not contiguous");
> -   ret = -EINVAL;
> -   goto err_gem_free;
> -   }
> -   expected = sg_dma_address(s) + sg_dma_len(s);
> -   }
> -
> mtk_gem->dma_addr = sg_dma_address(sg->sgl);
> mtk_gem->sg = sg;
>
> return _gem->base;
> -
> -err_gem_free:
> -   kfree(mtk_gem);
> -   return ERR_PTR(ret);
>  }
>
>  void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj)
> --
> 2.17.1
>
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs

2020-09-01 Thread Jacob Pan
On Mon, 24 Aug 2020 10:24:11 +0800
Lu Baolu  wrote:

> Hi Jacob,
> 
> On 8/22/20 12:35 PM, Jacob Pan wrote:
> > ioasid_set was introduced as an arbitrary token that are shared by a
> > group of IOASIDs. For example, if IOASID #1 and #2 are allocated
> > via the same ioasid_set*, they are viewed as to belong to the same
> > set.
> > 
> > For guest SVA usages, system-wide IOASID resources need to be
> > partitioned such that VMs can have its own quota and being managed
> > separately. ioasid_set is the perfect candidate for meeting such
> > requirements. This patch redefines and extends ioasid_set with the
> > following new fields:
> > - Quota
> > - Reference count
> > - Storage of its namespace
> > - The token is stored in the new ioasid_set but with optional types
> > 
> > ioasid_set level APIs are introduced that wires up these new data.
> > Existing users of IOASID APIs are converted where a host IOASID set
> > is allocated for bare-metal usage.
> > 
> > Signed-off-by: Liu Yi L 
> > Signed-off-by: Jacob Pan 
> > ---
> >   drivers/iommu/intel/iommu.c |  27 ++-
> >   drivers/iommu/intel/pasid.h |   1 +
> >   drivers/iommu/intel/svm.c   |   8 +-
> >   drivers/iommu/ioasid.c  | 390
> > +---
> > include/linux/ioasid.h  |  82 -- 5 files changed, 465
> > insertions(+), 43 deletions(-)
> > 
> > diff --git a/drivers/iommu/intel/iommu.c
> > b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb
> > 100644 --- a/drivers/iommu/intel/iommu.c
> > +++ b/drivers/iommu/intel/iommu.c
> > @@ -42,6 +42,7 @@
> >   #include 
> >   #include 
> >   #include 
> > +#include 
> >   #include 
> >   #include 
> >   #include 
> > @@ -103,6 +104,9 @@
> >*/
> >   #define INTEL_IOMMU_PGSIZES   (~0xFFFUL)
> >   
> > +/* PASIDs used by host SVM */
> > +struct ioasid_set *host_pasid_set;
> > +
> >   static inline int agaw_to_level(int agaw)
> >   {
> > return agaw + 2;
> > @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t
> > ioasid, void *data)
> >  * Sanity check the ioasid owner is done at upper layer,
> > e.g. VFIO
> >  * We can only free the PASID when all the devices are
> > unbound. */
> > -   if (ioasid_find(NULL, ioasid, NULL)) {
> > -   pr_alert("Cannot free active IOASID %d\n", ioasid);
> > +   if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) {
> > +   pr_err("Cannot free IOASID %d, not in system
> > set\n", ioasid); return;
> > }
> > vcmd_free_pasid(iommu, ioasid);
> > @@ -3288,6 +3292,19 @@ static int __init init_dmars(void)
> > if (ret)
> > goto free_iommu;
> >   
> > +   /* PASID is needed for scalable mode irrespective to SVM */
> > +   if (intel_iommu_sm) {
> > +   ioasid_install_capacity(intel_pasid_max_id);
> > +   /* We should not run out of IOASIDs at boot */
> > +   host_pasid_set = ioasid_alloc_set(NULL,
> > PID_MAX_DEFAULT,
> > +
> > IOASID_SET_TYPE_NULL);
> > +   if (IS_ERR_OR_NULL(host_pasid_set)) {
> > +   pr_err("Failed to enable host PASID
> > allocator %lu\n",
> > +   PTR_ERR(host_pasid_set));
> > +   intel_iommu_sm = 0;
> > +   }
> > +   }
> > +
> > /*
> >  * for each drhd
> >  *   enable fault log
> > @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct
> > dmar_domain *domain, domain->auxd_refcnt--;
> >   
> > if (!domain->auxd_refcnt && domain->default_pasid > 0)
> > -   ioasid_free(domain->default_pasid);
> > +   ioasid_free(host_pasid_set, domain->default_pasid);
> >   }
> >   
> >   static int aux_domain_add_dev(struct dmar_domain *domain,
> > @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct
> > dmar_domain *domain, int pasid;
> >   
> > /* No private data needed for the default pasid */
> > -   pasid = ioasid_alloc(NULL, PASID_MIN,
> > +   pasid = ioasid_alloc(host_pasid_set, PASID_MIN,
> >  pci_max_pasids(to_pci_dev(dev))
> > - 1, NULL);
> > if (pasid == INVALID_IOASID) {
> > @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct
> > dmar_domain *domain, spin_unlock(>lock);
> > spin_unlock_irqrestore(_domain_lock, flags);
> > if (!domain->auxd_refcnt && domain->default_pasid > 0)
> > -   ioasid_free(domain->default_pasid);
> > +   ioasid_free(host_pasid_set, domain->default_pasid);
> >   
> > return ret;
> >   }
> > diff --git a/drivers/iommu/intel/pasid.h
> > b/drivers/iommu/intel/pasid.h index c9850766c3a9..ccdc23446015
> > 100644 --- a/drivers/iommu/intel/pasid.h
> > +++ b/drivers/iommu/intel/pasid.h
> > @@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct
> > pasid_entry *pte) }
> >   
> >   extern u32 intel_pasid_max_id;
> > +extern struct ioasid_set *host_pasid_set;
> >   int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t
> > gfp); void intel_pasid_free_id(int pasid);
> >   void 

[PATCH v5] iommu/tegra-smmu: Add locking around mapping operations

2020-09-01 Thread Dmitry Osipenko
The mapping operations of the Tegra SMMU driver are subjected to a race
condition issues because SMMU Address Space isn't allocated and freed
atomically, while it should be. This patch makes the mapping operations
atomic, it fixes an accidentally released Host1x Address Space problem
which happens while running multiple graphics tests in parallel on
Tegra30, i.e. by having multiple threads racing with each other in the
Host1x's submission and completion code paths, performing IOVA mappings
and unmappings in parallel.

Signed-off-by: Dmitry Osipenko 
---

Changelog:

v5: - Replaced GFP_NOWAIT check with __GFP_ATOMIC to fix "sleep in
  atomic context" warnings, NOWAIT != ATOMIC.

v4: - Returned to use spinlock, but now using a smarter allocation
  logic that performs allocation in a sleeping context whenever
  possible.

- Removed the stable tag because patch isn't portable as-is
  since the arguments of map/unmap() callbacks changed recently.
  Perhaps we could just ignore older kernels for now. It will be
  possible to fix older kernels with a custom patch if will be needed.

v3: - No changes. Resending for visibility.

 drivers/iommu/tegra-smmu.c | 95 +-
 1 file changed, 84 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 124c8848ab7e..4853a2f8dc7b 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -49,6 +50,7 @@ struct tegra_smmu_as {
struct iommu_domain domain;
struct tegra_smmu *smmu;
unsigned int use_count;
+   spinlock_t lock;
u32 *count;
struct page **pts;
struct page *pd;
@@ -308,6 +310,8 @@ static struct iommu_domain 
*tegra_smmu_domain_alloc(unsigned type)
return NULL;
}
 
+   spin_lock_init(>lock);
+
/* setup aperture */
as->domain.geometry.aperture_start = 0;
as->domain.geometry.aperture_end = 0x;
@@ -569,19 +573,14 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as 
*as, unsigned long iova,
 }
 
 static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
-  dma_addr_t *dmap)
+  dma_addr_t *dmap, struct page *page)
 {
unsigned int pde = iova_pd_index(iova);
struct tegra_smmu *smmu = as->smmu;
 
if (!as->pts[pde]) {
-   struct page *page;
dma_addr_t dma;
 
-   page = alloc_page(GFP_KERNEL | __GFP_DMA | __GFP_ZERO);
-   if (!page)
-   return NULL;
-
dma = dma_map_page(smmu->dev, page, 0, SMMU_SIZE_PT,
   DMA_TO_DEVICE);
if (dma_mapping_error(smmu->dev, dma)) {
@@ -655,15 +654,61 @@ static void tegra_smmu_set_pte(struct tegra_smmu_as *as, 
unsigned long iova,
smmu_flush(smmu);
 }
 
-static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
+static struct page *as_get_pde_page(struct tegra_smmu_as *as,
+   unsigned long iova, gfp_t gfp,
+   unsigned long *flags)
+{
+   unsigned int pde = iova_pd_index(iova);
+   struct page *page = as->pts[pde];
+
+   /* at first check whether allocation needs to be done at all */
+   if (page)
+   return page;
+
+   /*
+* In order to prevent exhaustion of the atomic memory pool, we
+* allocate page in a sleeping context if GFP flags permit. Hence
+* spinlock needs to be unlocked and re-locked after allocation.
+*/
+   if (!(gfp & __GFP_ATOMIC))
+   spin_unlock_irqrestore(>lock, *flags);
+
+   page = alloc_page(gfp | __GFP_DMA | __GFP_ZERO);
+
+   if (!(gfp & __GFP_ATOMIC))
+   spin_lock_irqsave(>lock, *flags);
+
+   /*
+* In a case of blocking allocation, a concurrent mapping may win
+* the PDE allocation. In this case the allocated page isn't needed
+* if allocation succeeded and the allocation failure isn't fatal.
+*/
+   if (as->pts[pde]) {
+   if (page)
+   __free_page(page);
+
+   page = as->pts[pde];
+   }
+
+   return page;
+}
+
+static int
+__tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
+phys_addr_t paddr, size_t size, int prot, gfp_t gfp,
+unsigned long *flags)
 {
struct tegra_smmu_as *as = to_smmu_as(domain);
dma_addr_t pte_dma;
+   struct page *page;
u32 pte_attrs;
u32 *pte;
 
-   pte = as_get_pte(as, iova, _dma);
+   page = as_get_pde_page(as, iova, gfp, flags);
+   if (!page)
+   return -ENOMEM;
+
+   pte = as_get_pte(as, iova, _dma, 

RE: [Intel-gfx] [PATCH v9 08/32] drm: i915: fix common struct sg_table related issues

2020-09-01 Thread Ruhl, Michael J
>-Original Message-
>From: Robin Murphy 
>Sent: Tuesday, September 1, 2020 3:54 PM
>To: Ruhl, Michael J ; Marek Szyprowski
>; dri-de...@lists.freedesktop.org;
>iommu@lists.linux-foundation.org; linaro-mm-...@lists.linaro.org; linux-
>ker...@vger.kernel.org
>Cc: Bartlomiej Zolnierkiewicz ; David Airlie
>; intel-...@lists.freedesktop.org; Christoph Hellwig
>; linux-arm-ker...@lists.infradead.org
>Subject: Re: [Intel-gfx] [PATCH v9 08/32] drm: i915: fix common struct
>sg_table related issues
>
>On 2020-09-01 20:38, Ruhl, Michael J wrote:
>>> -Original Message-
>>> From: Intel-gfx  On Behalf Of
>>> Marek Szyprowski
>>> Sent: Wednesday, August 26, 2020 2:33 AM
>>> To: dri-de...@lists.freedesktop.org; iommu@lists.linux-foundation.org;
>>> linaro-mm-...@lists.linaro.org; linux-ker...@vger.kernel.org
>>> Cc: Bartlomiej Zolnierkiewicz ; David Airlie
>>> ; intel-...@lists.freedesktop.org; Robin Murphy
>>> ; Christoph Hellwig ; linux-arm-
>>> ker...@lists.infradead.org; Marek Szyprowski
>>> 
>>> Subject: [Intel-gfx] [PATCH v9 08/32] drm: i915: fix common struct sg_table
>>> related issues
>>>
>>> The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg()
>>> function
>>> returns the number of the created entries in the DMA address space.
>>> However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
>>> dma_unmap_sg must be called with the original number of the entries
>>> passed to the dma_map_sg().
>>>
>>> struct sg_table is a common structure used for describing a non-contiguous
>>> memory buffer, used commonly in the DRM and graphics subsystems. It
>>> consists of a scatterlist with memory pages and DMA addresses (sgl entry),
>>> as well as the number of scatterlist entries: CPU pages (orig_nents entry)
>>> and DMA mapped pages (nents entry).
>>>
>>> It turned out that it was a common mistake to misuse nents and orig_nents
>>> entries, calling DMA-mapping functions with a wrong number of entries or
>>> ignoring the number of mapped entries returned by the dma_map_sg()
>>> function.
>>>
>>> This driver creatively uses sg_table->orig_nents to store the size of the
>>> allocated scatterlist and ignores the number of the entries returned by
>>> dma_map_sg function. The sg_table->orig_nents is (mis)used to properly
>>> free the (over)allocated scatterlist.
>>>
>>> This patch only introduces the common DMA-mapping wrappers operating
>>> directly on the struct sg_table objects to the dmabuf related functions,
>>> so the other drivers, which might share buffers with i915 could rely on
>>> the properly set nents and orig_nents values.
>>>
>>> Signed-off-by: Marek Szyprowski 
>>> ---
>>> drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c   | 11 +++
>>> drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c |  7 +++
>>> 2 files changed, 6 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>>> b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>>> index 2679380159fc..8a988592715b 100644
>>> --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>>> @@ -48,12 +48,9 @@ static struct sg_table
>*i915_gem_map_dma_buf(struct
>>> dma_buf_attachment *attachme
>>> src = sg_next(src);
>>> }
>>>
>>> -   if (!dma_map_sg_attrs(attachment->dev,
>>> - st->sgl, st->nents, dir,
>>> - DMA_ATTR_SKIP_CPU_SYNC)) {
>>> -   ret = -ENOMEM;
>>
>> You have dropped this error value.
>>
>> Do you now if this is a benign loss?
>
>True, dma_map_sgtable() will return -EINVAL rather than -ENOMEM for
>failure. A quick look through other .map_dma_buf callbacks suggests
>they're returning a motley mix of error values and NULL for failure
>cases, so I'd imagine that importers shouldn't be too sensitive to the
>exact value.

I followed some of our code through to see if anyone is checking for -ENOMEM...

I have found in some test paths... However, it is not clear to me if we can get
to those paths from here.

Anyways,

Reviewed-by: Michael J. Ruhl 

Mike

>Robin.
>
>>
>> M
>>
>>> +   ret = dma_map_sgtable(attachment->dev, st, dir,
>>> DMA_ATTR_SKIP_CPU_SYNC);
>>> +   if (ret)
>>> goto err_free_sg;
>>> -   }
>>>
>>> return st;
>>>
>>> @@ -73,9 +70,7 @@ static void i915_gem_unmap_dma_buf(struct
>>> dma_buf_attachment *attachment,
>>> {
>>> struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment-
 dmabuf);
>>>
>>> -   dma_unmap_sg_attrs(attachment->dev,
>>> -  sg->sgl, sg->nents, dir,
>>> -  DMA_ATTR_SKIP_CPU_SYNC);
>>> +   dma_unmap_sgtable(attachment->dev, sg, dir,
>>> DMA_ATTR_SKIP_CPU_SYNC);
>>> sg_free_table(sg);
>>> kfree(sg);
>>>
>>> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
>>> b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
>>> index debaf7b18ab5..be30b27e2926 100644
>>> --- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
>>> +++ 

Re: [PATCH v9 31/32] media: pci: fix common ALSA DMA-mapping related codes

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that dma_map_sg returns the
numer of the created entries in the DMA address space. However the
subsequent calls to dma_sync_sg_for_{device,cpu} and dma_unmap_sg must be
called with the original number of entries passed to dma_map_sg. The
sg_table->nents in turn holds the result of the dma_map_sg call as stated
in include/linux/scatterlist.h. Adapt the code to obey those rules.

Signed-off-by: Marek Szyprowski 
---
  drivers/media/pci/cx23885/cx23885-alsa.c | 2 +-
  drivers/media/pci/cx25821/cx25821-alsa.c | 2 +-
  drivers/media/pci/cx88/cx88-alsa.c   | 2 +-
  drivers/media/pci/saa7134/saa7134-alsa.c | 2 +-
  4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c 
b/drivers/media/pci/cx23885/cx23885-alsa.c
index df44ed7393a0..3f366e4e4685 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -129,7 +129,7 @@ static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev 
*dev)
if (!buf->sglen)
return 0;
  
-	dma_unmap_sg(>pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);

+   dma_unmap_sg(>pci->dev, buf->sglist, buf->nr_pages, 
PCI_DMA_FROMDEVICE);


If we're touching these lines anyway, we should update them to use the 
modern DMA_FROM_DEVICE definitions too.


Robin.


buf->sglen = 0;
return 0;
  }
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c 
b/drivers/media/pci/cx25821/cx25821-alsa.c
index 301616426d8a..c40304d33776 100644
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -193,7 +193,7 @@ static int cx25821_alsa_dma_unmap(struct cx25821_audio_dev 
*dev)
if (!buf->sglen)
return 0;
  
-	dma_unmap_sg(>pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);

+   dma_unmap_sg(>pci->dev, buf->sglist, buf->nr_pages, 
PCI_DMA_FROMDEVICE);
buf->sglen = 0;
return 0;
  }
diff --git a/drivers/media/pci/cx88/cx88-alsa.c 
b/drivers/media/pci/cx88/cx88-alsa.c
index 7d7aceecc985..3c6fe6ceb0b7 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -332,7 +332,7 @@ static int cx88_alsa_dma_unmap(struct cx88_audio_dev *dev)
if (!buf->sglen)
return 0;
  
-	dma_unmap_sg(>pci->dev, buf->sglist, buf->sglen,

+   dma_unmap_sg(>pci->dev, buf->sglist, buf->nr_pages,
 PCI_DMA_FROMDEVICE);
buf->sglen = 0;
return 0;
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c 
b/drivers/media/pci/saa7134/saa7134-alsa.c
index 544ca57eee75..398c47ff473d 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -313,7 +313,7 @@ static int saa7134_alsa_dma_unmap(struct saa7134_dev *dev)
if (!dma->sglen)
return 0;
  
-	dma_unmap_sg(>pci->dev, dma->sglist, dma->sglen, PCI_DMA_FROMDEVICE);

+   dma_unmap_sg(>pci->dev, dma->sglist, dma->nr_pages, 
PCI_DMA_FROMDEVICE);
dma->sglen = 0;
return 0;
  }


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


Re: [PATCH v9 32/32] videobuf2: use sgtable-based scatterlist wrappers

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

Use recently introduced common wrappers operating directly on the struct
sg_table objects and scatterlist page iterators to make the code a bit
more compact, robust, easier to follow and copy/paste safe.

No functional change, because the code already properly did all the
scaterlist related calls.


^^ typo

Otherwise,

Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  .../common/videobuf2/videobuf2-dma-contig.c   | 34 ---
  .../media/common/videobuf2/videobuf2-dma-sg.c | 32 +++--
  .../common/videobuf2/videobuf2-vmalloc.c  | 12 +++
  3 files changed, 31 insertions(+), 47 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c 
b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
index ec3446cc45b8..1b242d844dde 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
@@ -58,10 +58,10 @@ static unsigned long vb2_dc_get_contiguous_size(struct 
sg_table *sgt)
unsigned int i;
unsigned long size = 0;
  
-	for_each_sg(sgt->sgl, s, sgt->nents, i) {

+   for_each_sgtable_dma_sg(sgt, s, i) {
if (sg_dma_address(s) != expected)
break;
-   expected = sg_dma_address(s) + sg_dma_len(s);
+   expected += sg_dma_len(s);
size += sg_dma_len(s);
}
return size;
@@ -103,8 +103,7 @@ static void vb2_dc_prepare(void *buf_priv)
if (!sgt)
return;
  
-	dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents,

-  buf->dma_dir);
+   dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir);
  }
  
  static void vb2_dc_finish(void *buf_priv)

@@ -115,7 +114,7 @@ static void vb2_dc_finish(void *buf_priv)
if (!sgt)
return;
  
-	dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);

+   dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir);
  }
  
  /*/

@@ -275,8 +274,8 @@ static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf,
 * memory locations do not require any explicit cache
 * maintenance prior or after being used by the device.
 */
-   dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
-  attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sgt);
kfree(attach);
db_attach->priv = NULL;
@@ -301,8 +300,8 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
  
  	/* release any previous cache */

if (attach->dma_dir != DMA_NONE) {
-   dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
-  attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
attach->dma_dir = DMA_NONE;
}
  
@@ -310,9 +309,8 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(

 * mapping to the client with new direction, no cache sync
 * required see comment in vb2_dc_dmabuf_ops_detach()
 */
-   sgt->nents = dma_map_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
- dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
-   if (!sgt->nents) {
+   if (dma_map_sgtable(db_attach->dev, sgt, dma_dir,
+   DMA_ATTR_SKIP_CPU_SYNC)) {
pr_err("failed to map scatterlist\n");
mutex_unlock(lock);
return ERR_PTR(-EIO);
@@ -455,8 +453,8 @@ static void vb2_dc_put_userptr(void *buf_priv)
 * No need to sync to CPU, it's already synced to the CPU
 * since the finish() memop will have been called before this.
 */
-   dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-  buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
pages = frame_vector_pages(buf->vec);
/* sgt should exist only if vector contains pages... */
BUG_ON(IS_ERR(pages));
@@ -553,9 +551,8 @@ static void *vb2_dc_get_userptr(struct device *dev, 
unsigned long vaddr,
 * No need to sync to the device, this will happen later when the
 * prepare() memop is called.
 */
-   sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
-   if (sgt->nents <= 0) {
+   if (dma_map_sgtable(buf->dev, sgt, buf->dma_dir,
+

Re: [PATCH v9 30/32] samples: vfio-mdev/mbochs: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

While touching this code, also add missing call to dma_unmap_sgtable.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  samples/vfio-mdev/mbochs.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c
index 3cc5e5921682..e03068917273 100644
--- a/samples/vfio-mdev/mbochs.c
+++ b/samples/vfio-mdev/mbochs.c
@@ -846,7 +846,7 @@ static struct sg_table *mbochs_map_dmabuf(struct 
dma_buf_attachment *at,
if (sg_alloc_table_from_pages(sg, dmabuf->pages, dmabuf->pagecount,
  0, dmabuf->mode.size, GFP_KERNEL) < 0)
goto err2;
-   if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction))
+   if (dma_map_sgtable(at->dev, sg, direction, 0))
goto err3;
  
  	return sg;

@@ -868,6 +868,7 @@ static void mbochs_unmap_dmabuf(struct dma_buf_attachment 
*at,
  
  	dev_dbg(dev, "%s: %d\n", __func__, dmabuf->id);
  
+	dma_unmap_sgtable(at->dev, sg, direction, 0);

sg_free_table(sg);
kfree(sg);
  }


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


Re: [PATCH v9 29/32] rapidio: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  drivers/rapidio/devices/rio_mport_cdev.c | 11 ---
  1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/rapidio/devices/rio_mport_cdev.c 
b/drivers/rapidio/devices/rio_mport_cdev.c
index a30342942e26..89eb3d212652 100644
--- a/drivers/rapidio/devices/rio_mport_cdev.c
+++ b/drivers/rapidio/devices/rio_mport_cdev.c
@@ -573,8 +573,7 @@ static void dma_req_free(struct kref *ref)
refcount);
struct mport_cdev_priv *priv = req->priv;
  
-	dma_unmap_sg(req->dmach->device->dev,

-req->sgt.sgl, req->sgt.nents, req->dir);
+   dma_unmap_sgtable(req->dmach->device->dev, >sgt, req->dir, 0);
sg_free_table(>sgt);
if (req->page_list) {
unpin_user_pages(req->page_list, req->nr_pages);
@@ -814,7 +813,6 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
struct mport_dev *md = priv->md;
struct dma_chan *chan;
int ret;
-   int nents;
  
  	if (xfer->length == 0)

return -EINVAL;
@@ -930,15 +928,14 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
xfer->offset, xfer->length);
}
  
-	nents = dma_map_sg(chan->device->dev,

-  req->sgt.sgl, req->sgt.nents, dir);
-   if (nents == 0) {
+   ret = dma_map_sgtable(chan->device->dev, >sgt, dir, 0);
+   if (ret) {
rmcd_error("Failed to map SG list");
ret = -EFAULT;
goto err_pg;
}
  
-	ret = do_dma_request(req, xfer, sync, nents);

+   ret = do_dma_request(req, xfer, sync, req->sgt.nents);
  
  	if (ret >= 0) {

if (sync == RIO_TRANSFER_ASYNC)


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


Re: [PATCH v9 28/32] misc: fastrpc: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  drivers/misc/fastrpc.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 7939c55daceb..9d6867749316 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -518,7 +518,7 @@ fastrpc_map_dma_buf(struct dma_buf_attachment *attachment,
  
  	table = >sgt;
  
-	if (!dma_map_sg(attachment->dev, table->sgl, table->nents, dir))

+   if (!dma_map_sgtable(attachment->dev, table, dir, 0))
return ERR_PTR(-ENOMEM);
  
  	return table;

@@ -528,7 +528,7 @@ static void fastrpc_unmap_dma_buf(struct dma_buf_attachment 
*attach,
  struct sg_table *table,
  enum dma_data_direction dir)
  {
-   dma_unmap_sg(attach->dev, table->sgl, table->nents, dir);
+   dma_unmap_sgtable(attach->dev, table, dir, 0);
  }
  
  static void fastrpc_release(struct dma_buf *dmabuf)



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


Re: [PATCH v9 24/32] drm: host1x: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/host1x/job.c | 22 --
  1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index 89b6c14b7392..82d0a60ba3f7 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -170,11 +170,9 @@ static unsigned int pin_job(struct host1x *host, struct 
host1x_job *job)
goto unpin;
}
  
-			err = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);

-   if (!err) {
-   err = -ENOMEM;
+   err = dma_map_sgtable(dev, sgt, dir, 0);
+   if (err)
goto unpin;
-   }
  
  			job->unpins[job->num_unpins].dev = dev;

job->unpins[job->num_unpins].dir = dir;
@@ -228,7 +226,7 @@ static unsigned int pin_job(struct host1x *host, struct 
host1x_job *job)
}
  
  		if (host->domain) {

-   for_each_sg(sgt->sgl, sg, sgt->nents, j)
+   for_each_sgtable_sg(sgt, sg, j)
gather_size += sg->length;
gather_size = iova_align(>iova, gather_size);
  
@@ -240,9 +238,9 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)

goto put;
}
  
-			err = iommu_map_sg(host->domain,

+   err = iommu_map_sgtable(host->domain,
iova_dma_addr(>iova, alloc),
-   sgt->sgl, sgt->nents, IOMMU_READ);
+   sgt, IOMMU_READ);
if (err == 0) {
__free_iova(>iova, alloc);
err = -EINVAL;
@@ -252,12 +250,9 @@ static unsigned int pin_job(struct host1x *host, struct 
host1x_job *job)
job->unpins[job->num_unpins].size = gather_size;
phys_addr = iova_dma_addr(>iova, alloc);
} else if (sgt) {
-   err = dma_map_sg(host->dev, sgt->sgl, sgt->nents,
-DMA_TO_DEVICE);
-   if (!err) {
-   err = -ENOMEM;
+   err = dma_map_sgtable(host->dev, sgt, DMA_TO_DEVICE, 0);
+   if (err)
goto put;
-   }
  
  			job->unpins[job->num_unpins].dir = DMA_TO_DEVICE;

job->unpins[job->num_unpins].dev = host->dev;
@@ -660,8 +655,7 @@ void host1x_job_unpin(struct host1x_job *job)
}
  
  		if (unpin->dev && sgt)

-   dma_unmap_sg(unpin->dev, sgt->sgl, sgt->nents,
-unpin->dir);
+   dma_unmap_sgtable(unpin->dev, sgt, unpin->dir, 0);
  
  		host1x_bo_unpin(dev, unpin->bo, sgt);

host1x_bo_put(unpin->bo);


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


Re: [PATCH v9 18/32] drm: tegra: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/tegra/gem.c   | 27 ++-
  drivers/gpu/drm/tegra/plane.c | 15 +--
  2 files changed, 15 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 723df142a981..01d94befab11 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -98,8 +98,8 @@ static struct sg_table *tegra_bo_pin(struct device *dev, 
struct host1x_bo *bo,
 * the SG table needs to be copied to avoid overwriting any
 * other potential users of the original SG table.
 */
-   err = sg_alloc_table_from_sg(sgt, obj->sgt->sgl, 
obj->sgt->nents,
-GFP_KERNEL);
+   err = sg_alloc_table_from_sg(sgt, obj->sgt->sgl,
+obj->sgt->orig_nents, GFP_KERNEL);
if (err < 0)
goto free;
} else {
@@ -196,8 +196,7 @@ static int tegra_bo_iommu_map(struct tegra_drm *tegra, 
struct tegra_bo *bo)
  
  	bo->iova = bo->mm->start;
  
-	bo->size = iommu_map_sg(tegra->domain, bo->iova, bo->sgt->sgl,

-   bo->sgt->nents, prot);
+   bo->size = iommu_map_sgtable(tegra->domain, bo->iova, bo->sgt, prot);
if (!bo->size) {
dev_err(tegra->drm->dev, "failed to map buffer\n");
err = -ENOMEM;
@@ -264,8 +263,7 @@ static struct tegra_bo *tegra_bo_alloc_object(struct 
drm_device *drm,
  static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
  {
if (bo->pages) {
-   dma_unmap_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents,
-DMA_FROM_DEVICE);
+   dma_unmap_sgtable(drm->dev, bo->sgt, DMA_FROM_DEVICE, 0);
drm_gem_put_pages(>gem, bo->pages, true, true);
sg_free_table(bo->sgt);
kfree(bo->sgt);
@@ -290,12 +288,9 @@ static int tegra_bo_get_pages(struct drm_device *drm, 
struct tegra_bo *bo)
goto put_pages;
}
  
-	err = dma_map_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents,

-DMA_FROM_DEVICE);
-   if (err == 0) {
-   err = -EFAULT;
+   err = dma_map_sgtable(drm->dev, bo->sgt, DMA_FROM_DEVICE, 0);
+   if (err)
goto free_sgt;
-   }
  
  	return 0;
  
@@ -571,7 +566,7 @@ tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,

goto free;
}
  
-	if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0)

+   if (dma_map_sgtable(attach->dev, sgt, dir, 0))
goto free;
  
  	return sgt;

@@ -590,7 +585,7 @@ static void tegra_gem_prime_unmap_dma_buf(struct 
dma_buf_attachment *attach,
struct tegra_bo *bo = to_tegra_bo(gem);
  
  	if (bo->pages)

-   dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+   dma_unmap_sgtable(attach->dev, sgt, dir, 0);
  
  	sg_free_table(sgt);

kfree(sgt);
@@ -609,8 +604,7 @@ static int tegra_gem_prime_begin_cpu_access(struct dma_buf 
*buf,
struct drm_device *drm = gem->dev;
  
  	if (bo->pages)

-   dma_sync_sg_for_cpu(drm->dev, bo->sgt->sgl, bo->sgt->nents,
-   DMA_FROM_DEVICE);
+   dma_sync_sgtable_for_cpu(drm->dev, bo->sgt, DMA_FROM_DEVICE);
  
  	return 0;

  }
@@ -623,8 +617,7 @@ static int tegra_gem_prime_end_cpu_access(struct dma_buf 
*buf,
struct drm_device *drm = gem->dev;
  
  	if (bo->pages)

-   dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents,
-  DMA_TO_DEVICE);
+ 

Re: [PATCH v9 17/32] drm: rockchip: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.


Reviewed-by: Robin Murphy 

(Until now I hadn't noticed the crimes against the API that 
rockchip_gem_get_pages() is committing, but it's not this patch's 
fault... I'll have to take a closer look at that)



Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 23 +
  1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index 2970e534e2bb..cb50f2ba2e46 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -36,8 +36,8 @@ static int rockchip_gem_iommu_map(struct rockchip_gem_object 
*rk_obj)
  
  	rk_obj->dma_addr = rk_obj->mm.start;
  
-	ret = iommu_map_sg(private->domain, rk_obj->dma_addr, rk_obj->sgt->sgl,

-  rk_obj->sgt->nents, prot);
+   ret = iommu_map_sgtable(private->domain, rk_obj->dma_addr, rk_obj->sgt,
+   prot);
if (ret < rk_obj->base.size) {
DRM_ERROR("failed to map buffer: size=%zd request_size=%zd\n",
  ret, rk_obj->base.size);
@@ -98,11 +98,10 @@ static int rockchip_gem_get_pages(struct 
rockchip_gem_object *rk_obj)
 * TODO: Replace this by drm_clflush_sg() once it can be implemented
 * without relying on symbols that are not exported.
 */
-   for_each_sg(rk_obj->sgt->sgl, s, rk_obj->sgt->nents, i)
+   for_each_sgtable_sg(rk_obj->sgt, s, i)
sg_dma_address(s) = sg_phys(s);
  
-	dma_sync_sg_for_device(drm->dev, rk_obj->sgt->sgl, rk_obj->sgt->nents,

-  DMA_TO_DEVICE);
+   dma_sync_sgtable_for_device(drm->dev, rk_obj->sgt, DMA_TO_DEVICE);
  
  	return 0;
  
@@ -350,8 +349,8 @@ void rockchip_gem_free_object(struct drm_gem_object *obj)

if (private->domain) {
rockchip_gem_iommu_unmap(rk_obj);
} else {
-   dma_unmap_sg(drm->dev, rk_obj->sgt->sgl,
-rk_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(drm->dev, rk_obj->sgt,
+ DMA_BIDIRECTIONAL, 0);
}
drm_prime_gem_destroy(obj, rk_obj->sgt);
} else {
@@ -476,15 +475,13 @@ rockchip_gem_dma_map_sg(struct drm_device *drm,
struct sg_table *sg,
struct rockchip_gem_object *rk_obj)
  {
-   int count = dma_map_sg(drm->dev, sg->sgl, sg->nents,
-  DMA_BIDIRECTIONAL);
-   if (!count)
-   return -EINVAL;
+   int err = dma_map_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
+   if (err)
+   return err;
  
  	if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {

DRM_ERROR("failed to map sg_table to contiguous linear 
address.\n");
-   dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
-DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
return -EINVAL;
}
  


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


Re: [Intel-gfx] [PATCH v9 08/32] drm: i915: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-09-01 20:38, Ruhl, Michael J wrote:

-Original Message-
From: Intel-gfx  On Behalf Of
Marek Szyprowski
Sent: Wednesday, August 26, 2020 2:33 AM
To: dri-de...@lists.freedesktop.org; iommu@lists.linux-foundation.org;
linaro-mm-...@lists.linaro.org; linux-ker...@vger.kernel.org
Cc: Bartlomiej Zolnierkiewicz ; David Airlie
; intel-...@lists.freedesktop.org; Robin Murphy
; Christoph Hellwig ; linux-arm-
ker...@lists.infradead.org; Marek Szyprowski

Subject: [Intel-gfx] [PATCH v9 08/32] drm: i915: fix common struct sg_table
related issues

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg()
function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

This driver creatively uses sg_table->orig_nents to store the size of the
allocated scatterlist and ignores the number of the entries returned by
dma_map_sg function. The sg_table->orig_nents is (mis)used to properly
free the (over)allocated scatterlist.

This patch only introduces the common DMA-mapping wrappers operating
directly on the struct sg_table objects to the dmabuf related functions,
so the other drivers, which might share buffers with i915 could rely on
the properly set nents and orig_nents values.

Signed-off-by: Marek Szyprowski 
---
drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c   | 11 +++
drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c |  7 +++
2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
index 2679380159fc..8a988592715b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
@@ -48,12 +48,9 @@ static struct sg_table *i915_gem_map_dma_buf(struct
dma_buf_attachment *attachme
src = sg_next(src);
}

-   if (!dma_map_sg_attrs(attachment->dev,
- st->sgl, st->nents, dir,
- DMA_ATTR_SKIP_CPU_SYNC)) {
-   ret = -ENOMEM;


You have dropped this error value.

Do you now if this is a benign loss?


True, dma_map_sgtable() will return -EINVAL rather than -ENOMEM for 
failure. A quick look through other .map_dma_buf callbacks suggests 
they're returning a motley mix of error values and NULL for failure 
cases, so I'd imagine that importers shouldn't be too sensitive to the 
exact value.


Robin.



M


+   ret = dma_map_sgtable(attachment->dev, st, dir,
DMA_ATTR_SKIP_CPU_SYNC);
+   if (ret)
goto err_free_sg;
-   }

return st;

@@ -73,9 +70,7 @@ static void i915_gem_unmap_dma_buf(struct
dma_buf_attachment *attachment,
{
struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment-

dmabuf);


-   dma_unmap_sg_attrs(attachment->dev,
-  sg->sgl, sg->nents, dir,
-  DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(attachment->dev, sg, dir,
DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sg);
kfree(sg);

diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
index debaf7b18ab5..be30b27e2926 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
@@ -28,10 +28,9 @@ static struct sg_table *mock_map_dma_buf(struct
dma_buf_attachment *attachment,
sg = sg_next(sg);
}

-   if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
-   err = -ENOMEM;
+   err = dma_map_sgtable(attachment->dev, st, dir, 0);
+   if (err)
goto err_st;
-   }

return st;

@@ -46,7 +45,7 @@ static void mock_unmap_dma_buf(struct
dma_buf_attachment *attachment,
   struct sg_table *st,
   enum dma_data_direction dir)
{
-   dma_unmap_sg(attachment->dev, st->sgl, st->nents, dir);
+   dma_unmap_sgtable(attachment->dev, st, dir, 0);
sg_free_table(st);
kfree(st);
}
--
2.17.1

___
Intel-gfx mailing list
intel-...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

___
iommu mailing list

RE: [Intel-gfx] [PATCH v9 08/32] drm: i915: fix common struct sg_table related issues

2020-09-01 Thread Ruhl, Michael J
>-Original Message-
>From: Intel-gfx  On Behalf Of
>Marek Szyprowski
>Sent: Wednesday, August 26, 2020 2:33 AM
>To: dri-de...@lists.freedesktop.org; iommu@lists.linux-foundation.org;
>linaro-mm-...@lists.linaro.org; linux-ker...@vger.kernel.org
>Cc: Bartlomiej Zolnierkiewicz ; David Airlie
>; intel-...@lists.freedesktop.org; Robin Murphy
>; Christoph Hellwig ; linux-arm-
>ker...@lists.infradead.org; Marek Szyprowski
>
>Subject: [Intel-gfx] [PATCH v9 08/32] drm: i915: fix common struct sg_table
>related issues
>
>The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg()
>function
>returns the number of the created entries in the DMA address space.
>However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
>dma_unmap_sg must be called with the original number of the entries
>passed to the dma_map_sg().
>
>struct sg_table is a common structure used for describing a non-contiguous
>memory buffer, used commonly in the DRM and graphics subsystems. It
>consists of a scatterlist with memory pages and DMA addresses (sgl entry),
>as well as the number of scatterlist entries: CPU pages (orig_nents entry)
>and DMA mapped pages (nents entry).
>
>It turned out that it was a common mistake to misuse nents and orig_nents
>entries, calling DMA-mapping functions with a wrong number of entries or
>ignoring the number of mapped entries returned by the dma_map_sg()
>function.
>
>This driver creatively uses sg_table->orig_nents to store the size of the
>allocated scatterlist and ignores the number of the entries returned by
>dma_map_sg function. The sg_table->orig_nents is (mis)used to properly
>free the (over)allocated scatterlist.
>
>This patch only introduces the common DMA-mapping wrappers operating
>directly on the struct sg_table objects to the dmabuf related functions,
>so the other drivers, which might share buffers with i915 could rely on
>the properly set nents and orig_nents values.
>
>Signed-off-by: Marek Szyprowski 
>---
> drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c   | 11 +++
> drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c |  7 +++
> 2 files changed, 6 insertions(+), 12 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>index 2679380159fc..8a988592715b 100644
>--- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>+++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
>@@ -48,12 +48,9 @@ static struct sg_table *i915_gem_map_dma_buf(struct
>dma_buf_attachment *attachme
>   src = sg_next(src);
>   }
>
>-  if (!dma_map_sg_attrs(attachment->dev,
>-st->sgl, st->nents, dir,
>-DMA_ATTR_SKIP_CPU_SYNC)) {
>-  ret = -ENOMEM;

You have dropped this error value.

Do you now if this is a benign loss?

M

>+  ret = dma_map_sgtable(attachment->dev, st, dir,
>DMA_ATTR_SKIP_CPU_SYNC);
>+  if (ret)
>   goto err_free_sg;
>-  }
>
>   return st;
>
>@@ -73,9 +70,7 @@ static void i915_gem_unmap_dma_buf(struct
>dma_buf_attachment *attachment,
> {
>   struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment-
>>dmabuf);
>
>-  dma_unmap_sg_attrs(attachment->dev,
>- sg->sgl, sg->nents, dir,
>- DMA_ATTR_SKIP_CPU_SYNC);
>+  dma_unmap_sgtable(attachment->dev, sg, dir,
>DMA_ATTR_SKIP_CPU_SYNC);
>   sg_free_table(sg);
>   kfree(sg);
>
>diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
>b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
>index debaf7b18ab5..be30b27e2926 100644
>--- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
>+++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
>@@ -28,10 +28,9 @@ static struct sg_table *mock_map_dma_buf(struct
>dma_buf_attachment *attachment,
>   sg = sg_next(sg);
>   }
>
>-  if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
>-  err = -ENOMEM;
>+  err = dma_map_sgtable(attachment->dev, st, dir, 0);
>+  if (err)
>   goto err_st;
>-  }
>
>   return st;
>
>@@ -46,7 +45,7 @@ static void mock_unmap_dma_buf(struct
>dma_buf_attachment *attachment,
>  struct sg_table *st,
>  enum dma_data_direction dir)
> {
>-  dma_unmap_sg(attachment->dev, st->sgl, st->nents, dir);
>+  dma_unmap_sgtable(attachment->dev, st, dir, 0);
>   sg_free_table(st);
>   kfree(st);
> }
>--
>2.17.1
>
>___
>Intel-gfx mailing list
>intel-...@lists.freedesktop.org
>https://lists.freedesktop.org/mailman/listinfo/intel-gfx
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v9 16/32] drm: rockchip: use common helper for a scatterlist contiguity check

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:33, Marek Szyprowski wrote:

Use common helper for checking the contiguity of the imported dma-buf.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 19 +--
  1 file changed, 1 insertion(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index b9275ba7c5a5..2970e534e2bb 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -460,23 +460,6 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct 
drm_gem_object *obj)
return sgt;
  }
  
-static unsigned long rockchip_sg_get_contiguous_size(struct sg_table *sgt,

-int count)
-{
-   struct scatterlist *s;
-   dma_addr_t expected = sg_dma_address(sgt->sgl);
-   unsigned int i;
-   unsigned long size = 0;
-
-   for_each_sg(sgt->sgl, s, count, i) {
-   if (sg_dma_address(s) != expected)
-   break;
-   expected = sg_dma_address(s) + sg_dma_len(s);
-   size += sg_dma_len(s);
-   }
-   return size;
-}
-
  static int
  rockchip_gem_iommu_map_sg(struct drm_device *drm,
  struct dma_buf_attachment *attach,
@@ -498,7 +481,7 @@ rockchip_gem_dma_map_sg(struct drm_device *drm,
if (!count)
return -EINVAL;
  
-	if (rockchip_sg_get_contiguous_size(sg, count) < attach->dmabuf->size) {

+   if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
DRM_ERROR("failed to map sg_table to contiguous linear 
address.\n");
dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
 DMA_BIDIRECTIONAL);


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


Re: [PATCH v9 14/32] drm: omapdrm: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

Fix the code to refer to proper nents or orig_nents entries. This driver
checks for a buffer contiguity in DMA address space, so it should test
sg_table->nents entry.

Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/omapdrm/omap_gem.c | 6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c 
b/drivers/gpu/drm/omapdrm/omap_gem.c
index ff0c4b0c3fd0..a7a9a0afe2b6 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -48,7 +48,7 @@ struct omap_gem_object {
 *   OMAP_BO_MEM_DMA_API flag set)
 *
 * - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set)
-*   if they are physically contiguous (when sgt->orig_nents == 1)
+*   if they are physically contiguous (when sgt->nents == 1)


Hmm, if this really does mean *physically* contiguous - i.e. if buffers 
might be shared between DMA-translatable and non-DMA-translatable 
devices - then these changes might not be appropriate. If not and it 
only actually means DMA-contiguous, then it would be good to clarify the 
comments to that effect.


Can anyone familiar with omapdrm clarify what exactly the case is here? 
I know that IOMMUs might be involved to some degree, and I've skimmed 
the interconnect chapters of enough OMAP TRMs to be scared by the 
reference to the tiler aperture in the context below :)


Robin.


 *
 * - buffers mapped through the TILER when dma_addr_cnt is not zero, in
 *   which case the DMA address points to the TILER aperture
@@ -1279,7 +1279,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct 
drm_device *dev, size_t size,
union omap_gem_size gsize;
  
  	/* Without a DMM only physically contiguous buffers can be supported. */

-   if (sgt->orig_nents != 1 && !priv->has_dmm)
+   if (sgt->nents != 1 && !priv->has_dmm)
return ERR_PTR(-EINVAL);
  
  	gsize.bytes = PAGE_ALIGN(size);

@@ -1293,7 +1293,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct 
drm_device *dev, size_t size,
  
  	omap_obj->sgt = sgt;
  
-	if (sgt->orig_nents == 1) {

+   if (sgt->nents == 1) {
omap_obj->dma_addr = sg_dma_address(sgt->sgl);
} else {
/* Create pages list from sgt */


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


Re: [PATCH v9 13/32] drm: omapdrm: use common helper for extracting pages array

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

Use common helper for converting a sg_table object into struct
page pointer array.

Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/omapdrm/omap_gem.c | 14 --
  1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c 
b/drivers/gpu/drm/omapdrm/omap_gem.c
index d0d12d5dd76c..ff0c4b0c3fd0 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -1297,10 +1297,9 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct 
drm_device *dev, size_t size,
omap_obj->dma_addr = sg_dma_address(sgt->sgl);
} else {
/* Create pages list from sgt */
-   struct sg_page_iter iter;
struct page **pages;
unsigned int npages;
-   unsigned int i = 0;
+   unsigned int ret;
  
  		npages = DIV_ROUND_UP(size, PAGE_SIZE);

pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL);
@@ -1311,14 +1310,9 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct 
drm_device *dev, size_t size,
}
  
  		omap_obj->pages = pages;

-
-   for_each_sg_page(sgt->sgl, , sgt->orig_nents, 0) {
-   pages[i++] = sg_page_iter_page();
-   if (i > npages)
-   break;
-   }
-
-   if (WARN_ON(i != npages)) {
+   ret = drm_prime_sg_to_page_addr_arrays(sgt, pages, NULL,
+  npages);
+   if (WARN_ON(ret)) {


Again, I'm inclined to think the WARN_ON should remain in 
drm_prime_sg_to_page_addr_arrays() itself such that it could be removed 
here, but either way,


Reviewed-by: Robin Murphy 


omap_gem_free_object(obj);
obj = ERR_PTR(-ENOMEM);
goto done;


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


Re: [PATCH v9 12/32] drm: msm: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
Acked-by: Rob Clark 
---
  drivers/gpu/drm/msm/msm_gem.c| 13 +
  drivers/gpu/drm/msm/msm_gpummu.c | 14 ++
  drivers/gpu/drm/msm/msm_iommu.c  |  2 +-
  3 files changed, 12 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index b2f49152b4d4..8c7ae812b813 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -53,11 +53,10 @@ static void sync_for_device(struct msm_gem_object *msm_obj)
struct device *dev = msm_obj->base.dev->dev;
  
  	if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {

-   dma_sync_sg_for_device(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_sync_sgtable_for_device(dev, msm_obj->sgt,
+   DMA_BIDIRECTIONAL);
} else {
-   dma_map_sg(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_map_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0);
}
  }
  
@@ -66,11 +65,9 @@ static void sync_for_cpu(struct msm_gem_object *msm_obj)

struct device *dev = msm_obj->base.dev->dev;
  
  	if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {

-   dma_sync_sg_for_cpu(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_sync_sgtable_for_cpu(dev, msm_obj->sgt, DMA_BIDIRECTIONAL);
} else {
-   dma_unmap_sg(dev, msm_obj->sgt->sgl,
-   msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0);
}
  }
  
diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c

index 310a31b05faa..319f06c28235 100644
--- a/drivers/gpu/drm/msm/msm_gpummu.c
+++ b/drivers/gpu/drm/msm/msm_gpummu.c
@@ -30,21 +30,19 @@ static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t 
iova,
  {
struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE;
-   struct scatterlist *sg;
+   struct sg_dma_page_iter dma_iter;
unsigned prot_bits = 0;
-   unsigned i, j;
  
  	if (prot & IOMMU_WRITE)

prot_bits |= 1;
if (prot & IOMMU_READ)
prot_bits |= 2;
  
-	for_each_sg(sgt->sgl, sg, sgt->nents, i) {

-   dma_addr_t addr = sg->dma_address;
-   for (j = 0; j < sg->length / GPUMMU_PAGE_SIZE; j++, idx++) {
-   gpummu->table[idx] = addr | prot_bits;
-   addr += GPUMMU_PAGE_SIZE;
-   }
+   for_each_sgtable_dma_page(sgt, _iter, 0) {
+   dma_addr_t addr = sg_page_iter_dma_address(_iter);
+
+   BUILD_BUG_ON(GPUMMU_PAGE_SIZE != PAGE_SIZE);
+   gpummu->table[idx++] = addr | prot_bits;


Given that the BUILD_BUG_ON might prevent valid arm64 configs from 
building, how about a simple tweak like:


for (i = 0; i < PAGE_SIZE; i += GPUMMU_PAGE_SIZE)
gpummu->table[idx++] = i + addr | prot_bits;
?

Or alternatively perhaps some more aggressive #ifdefs or makefile tweaks 
to prevent the GPUMMU code building for arm64 at all if it's only 
relevant to 32-bit platforms (which I believe might be the case).


Robin.


}
  
  	/* we can improve by deferring flush for multiple map() */

diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 3a381a9674c9..6c31e65834c6 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -36,7 +36,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,

Re: [PATCH v4] iommu/tegra-smmu: Add locking around mapping operations

2020-09-01 Thread Dmitry Osipenko
01.09.2020 20:13, Dmitry Osipenko пишет:
...
> + /*
> +  * In order to prevent exhaustion of the atomic memory pool, we
> +  * allocate page in a sleeping context if GFP flags permit. Hence
> +  * spinlock needs to be unlocked and re-locked after allocation.
> +  */
> + if (!(gfp & GFP_NOWAIT))
> + spin_unlock_irqrestore(>lock, *flags);
> +
> + page = alloc_page(gfp | __GFP_DMA | __GFP_ZERO);
> +
> + if (!(gfp & GFP_NOWAIT))
> + spin_lock_irqsave(>lock, *flags);

I realized that GFP_NOWAIT is a wrong flag to check here once I saw
warnings about sleeping in atomic context. Apparently __GFP_ATOMIC
should be used instead, I'll make v5.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH v9 11/32] drm: mediatek: use common helper for extracting pages array

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

Use common helper for converting a sg_table object into struct
page pointer array.


Reviewed-by: Robin Murphy 

Side note: is mtk_drm_gem_prime_vmap() missing a call to 
sg_free_table(sgt) before its kfree(sgt)?



Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/mediatek/mtk_drm_gem.c | 9 ++---
  1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index 3654ec732029..0583e557ad37 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -233,9 +233,7 @@ void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj)
  {
struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
struct sg_table *sgt;
-   struct sg_page_iter iter;
unsigned int npages;
-   unsigned int i = 0;
  
  	if (mtk_gem->kvaddr)

return mtk_gem->kvaddr;
@@ -249,11 +247,8 @@ void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj)
if (!mtk_gem->pages)
goto out;
  
-	for_each_sg_page(sgt->sgl, , sgt->orig_nents, 0) {

-   mtk_gem->pages[i++] = sg_page_iter_page();
-   if (i > npages)
-   break;
-   }
+   drm_prime_sg_to_page_addr_arrays(sgt, mtk_gem->pages, NULL, npages);
+
mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
   pgprot_writecombine(PAGE_KERNEL));
  


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


Re: [PATCH v9 10/32] drm: mediatek: use common helper for a scatterlist contiguity check

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

Use common helper for checking the contiguity of the imported dma-buf and
do this check before allocating resources, so the error path is simpler.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/mediatek/mtk_drm_gem.c | 28 ++
  1 file changed, 6 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index 6190cc3b7b0d..3654ec732029 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -212,37 +212,21 @@ struct drm_gem_object 
*mtk_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct sg_table *sg)
  {
struct mtk_drm_gem_obj *mtk_gem;
-   int ret;
-   struct scatterlist *s;
-   unsigned int i;
-   dma_addr_t expected;
  
-	mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size);

+   /* check if the entries in the sg_table are contiguous */
+   if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
+   DRM_ERROR("sg_table is not contiguous");
+   return ERR_PTR(-EINVAL);
+   }
  
+	mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size);

if (IS_ERR(mtk_gem))
return ERR_CAST(mtk_gem);
  
-	expected = sg_dma_address(sg->sgl);

-   for_each_sg(sg->sgl, s, sg->nents, i) {
-   if (!sg_dma_len(s))
-   break;
-
-   if (sg_dma_address(s) != expected) {
-   DRM_ERROR("sg_table is not contiguous");
-   ret = -EINVAL;
-   goto err_gem_free;
-   }
-   expected = sg_dma_address(s) + sg_dma_len(s);
-   }
-
mtk_gem->dma_addr = sg_dma_address(sg->sgl);
mtk_gem->sg = sg;
  
  	return _gem->base;

-
-err_gem_free:
-   kfree(mtk_gem);
-   return ERR_PTR(ret);
  }
  
  void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj)



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


Re: [PATCH v9 08/32] drm: i915: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

This driver creatively uses sg_table->orig_nents to store the size of the
allocated scatterlist and ignores the number of the entries returned by
dma_map_sg function. The sg_table->orig_nents is (mis)used to properly
free the (over)allocated scatterlist.

This patch only introduces the common DMA-mapping wrappers operating
directly on the struct sg_table objects to the dmabuf related functions,
so the other drivers, which might share buffers with i915 could rely on
the properly set nents and orig_nents values.


This one looks mechanical enough :)

Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c   | 11 +++
  drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c |  7 +++
  2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c 
b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
index 2679380159fc..8a988592715b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
@@ -48,12 +48,9 @@ static struct sg_table *i915_gem_map_dma_buf(struct 
dma_buf_attachment *attachme
src = sg_next(src);
}
  
-	if (!dma_map_sg_attrs(attachment->dev,

- st->sgl, st->nents, dir,
- DMA_ATTR_SKIP_CPU_SYNC)) {
-   ret = -ENOMEM;
+   ret = dma_map_sgtable(attachment->dev, st, dir, DMA_ATTR_SKIP_CPU_SYNC);
+   if (ret)
goto err_free_sg;
-   }
  
  	return st;
  
@@ -73,9 +70,7 @@ static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,

  {
struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment->dmabuf);
  
-	dma_unmap_sg_attrs(attachment->dev,

-  sg->sgl, sg->nents, dir,
-  DMA_ATTR_SKIP_CPU_SYNC);
+   dma_unmap_sgtable(attachment->dev, sg, dir, DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sg);
kfree(sg);
  
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c

index debaf7b18ab5..be30b27e2926 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c
@@ -28,10 +28,9 @@ static struct sg_table *mock_map_dma_buf(struct 
dma_buf_attachment *attachment,
sg = sg_next(sg);
}
  
-	if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {

-   err = -ENOMEM;
+   err = dma_map_sgtable(attachment->dev, st, dir, 0);
+   if (err)
goto err_st;
-   }
  
  	return st;
  
@@ -46,7 +45,7 @@ static void mock_unmap_dma_buf(struct dma_buf_attachment *attachment,

   struct sg_table *st,
   enum dma_data_direction dir)
  {
-   dma_unmap_sg(attachment->dev, st->sgl, st->nents, dir);
+   dma_unmap_sgtable(attachment->dev, st, dir, 0);
sg_free_table(st);
kfree(st);
  }


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


Re: [PATCH v9 05/32] drm: etnaviv: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/etnaviv/etnaviv_gem.c | 12 +---
  drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 13 +++--
  2 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index f06e19e7be04..eaf1949bc2e4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -27,7 +27,7 @@ static void etnaviv_gem_scatter_map(struct etnaviv_gem_object 
*etnaviv_obj)
 * because display controller, GPU, etc. are not coherent.
 */
if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
-   dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+   dma_map_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
  }
  
  static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)

@@ -51,7 +51,7 @@ static void etnaviv_gem_scatterlist_unmap(struct 
etnaviv_gem_object *etnaviv_obj
 * discard those writes.
 */
if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
-   dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
  }
  
  /* called with etnaviv_obj->lock held */

@@ -404,9 +404,8 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
}
  
  	if (etnaviv_obj->flags & ETNA_BO_CACHED) {

-   dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
-   etnaviv_obj->sgt->nents,
-   etnaviv_op_to_dma_dir(op));
+   dma_sync_sgtable_for_cpu(dev->dev, etnaviv_obj->sgt,
+etnaviv_op_to_dma_dir(op));
etnaviv_obj->last_cpu_prep_op = op;
}
  
@@ -421,8 +420,7 @@ int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)

if (etnaviv_obj->flags & ETNA_BO_CACHED) {
/* fini without a prep is almost certainly a userspace error */
WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
-   dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
-   etnaviv_obj->sgt->nents,
+   dma_sync_sgtable_for_device(dev->dev, etnaviv_obj->sgt,
etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
etnaviv_obj->last_cpu_prep_op = 0;
}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index 3607d348c298..13b100553a0b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -79,7 +79,7 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context 
*context, u32 iova,
if (!context || !sgt)
return -EINVAL;
  
-	for_each_sg(sgt->sgl, sg, sgt->nents, i) {

+   for_each_sgtable_dma_sg(sgt, sg, i) {
u32 pa = sg_dma_address(sg) - sg->offset;
size_t bytes = sg_dma_len(sg) + sg->offset;
  
@@ -95,14 +95,7 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova,

return 0;
  
  fail:

-   da = iova;
-
-   for_each_sg(sgt->sgl, sg, i, j) {
-   size_t bytes = sg_dma_len(sg) + sg->offset;
-
-   etnaviv_context_unmap(context, da, bytes);
-   da += bytes;
-   }
+   etnaviv_context_unmap(context, iova, da - iova);


I had to take a closer look to figure this out, but AFAICS it does 
indeed work out as a simpler way of achieving the exact same result, and 
in fact neatly mirrors how etnaviv_context_map() itself cleans up.


Reviewed-by: Robin Murphy 


return ret;
  }
  
@@ -113,7 +106,7 @@ static void etnaviv_iommu_unmap(struct etnaviv_iommu_context 

Re: [PATCH v9 04/32] drm: armada: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
---
  drivers/gpu/drm/armada/armada_gem.c | 12 ++--
  1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_gem.c 
b/drivers/gpu/drm/armada/armada_gem.c
index 8005614d2e6b..bedd8937d8a1 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -395,7 +395,7 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment 
*attach,
  
  		mapping = dobj->obj.filp->f_mapping;
  
-		for_each_sg(sgt->sgl, sg, count, i) {

+   for_each_sgtable_sg(sgt, sg, i) {
struct page *page;
  
  			page = shmem_read_mapping_page(mapping, i);

@@ -407,8 +407,8 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment 
*attach,
sg_set_page(sg, page, PAGE_SIZE, 0);
}
  
-		if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) {

-   num = sgt->nents;
+   if (dma_map_sgtable(attach->dev, sgt, dir, 0)) {
+   num = count;


I think it might be even nicer to get rid of "num" entirely and convert 
the cleanup path to for_each_sgtable_sg() for completeness - AFAICS it 
should only need an extra "if (sg_page(sg))..." check in that loop. Then 
"count" could possibly be squashed into its one remaining use as well, 
but maybe it's worth keeping for readability.


Robin.


goto release;
}
} else if (dobj->page) {
@@ -418,7 +418,7 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment 
*attach,
  
  		sg_set_page(sgt->sgl, dobj->page, dobj->obj.size, 0);
  
-		if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0)

+   if (dma_map_sgtable(attach->dev, sgt, dir, 0))
goto free_table;
} else if (dobj->linear) {
/* Single contiguous physical region - no struct page */
@@ -449,11 +449,11 @@ static void armada_gem_prime_unmap_dma_buf(struct 
dma_buf_attachment *attach,
int i;
  
  	if (!dobj->linear)

-   dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+   dma_unmap_sgtable(attach->dev, sgt, dir, 0);
  
  	if (dobj->obj.filp) {

struct scatterlist *sg;
-   for_each_sg(sgt->sgl, sg, sgt->nents, i)
+   for_each_sgtable_sg(sgt, sg, i)
put_page(sg_page(sg));
}
  


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


Re: [PATCH v9 03/32] drm: core: fix common struct sg_table related issues

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski 
Reviewed-by: Andrzej Hajda 
---
  drivers/gpu/drm/drm_cache.c|  2 +-
  drivers/gpu/drm/drm_gem_shmem_helper.c | 14 +-
  drivers/gpu/drm/drm_prime.c| 11 ++-
  3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 03e01b000f7a..0fe3c496002a 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -127,7 +127,7 @@ drm_clflush_sg(struct sg_table *st)
struct sg_page_iter sg_iter;
  
  		mb(); /*CLFLUSH is ordered only by using memory barriers*/

-   for_each_sg_page(st->sgl, _iter, st->nents, 0)
+   for_each_sgtable_page(st, _iter, 0)
drm_clflush_page(sg_page_iter_page(_iter));
mb(); /*Make sure that all cache line entry is flushed*/
  
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c

index 4b7cfbac4daa..47d8211221f2 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -126,8 +126,8 @@ void drm_gem_shmem_free_object(struct drm_gem_object *obj)
drm_prime_gem_destroy(obj, shmem->sgt);
} else {
if (shmem->sgt) {
-   dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl,
-shmem->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(obj->dev->dev, shmem->sgt,
+ DMA_BIDIRECTIONAL, 0);
sg_free_table(shmem->sgt);
kfree(shmem->sgt);
}
@@ -424,8 +424,7 @@ void drm_gem_shmem_purge_locked(struct drm_gem_object *obj)
  
  	WARN_ON(!drm_gem_shmem_is_purgeable(shmem));
  
-	dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl,

-shmem->sgt->nents, DMA_BIDIRECTIONAL);
+   dma_unmap_sgtable(obj->dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);
sg_free_table(shmem->sgt);
kfree(shmem->sgt);
shmem->sgt = NULL;
@@ -697,12 +696,17 @@ struct sg_table *drm_gem_shmem_get_pages_sgt(struct 
drm_gem_object *obj)
goto err_put_pages;
}
/* Map the pages for use by the h/w. */
-   dma_map_sg(obj->dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+   ret = dma_map_sgtable(obj->dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
+   if (ret)
+   goto err_free_sgt;
  
  	shmem->sgt = sgt;
  
  	return sgt;
  
+err_free_sgt:

+   sg_free_table(sgt);
+   kfree(sgt);


Should this be a separate patch to add the missing error handling to the 
existing code first?


Otherwise the rest of the mechanical conversion looks straightforward 
enough, and I'm not the separation-of-concerns police (for this 
subsystem, at least), so either way,


Reviewed-by: Robin Murphy 


  err_put_pages:
drm_gem_shmem_put_pages(shmem);
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 5d181bf60a44..c45b0cc6e31d 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -617,6 +617,7 @@ struct sg_table *drm_gem_map_dma_buf(struct 
dma_buf_attachment *attach,
  {
struct drm_gem_object *obj = attach->dmabuf->priv;
struct sg_table *sgt;
+   int ret;
  
  	if (WARN_ON(dir == DMA_NONE))

return ERR_PTR(-EINVAL);
@@ -626,11 +627,12 @@ struct sg_table *drm_gem_map_dma_buf(struct 
dma_buf_attachment *attach,
else
sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
  
-	if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,

- DMA_ATTR_SKIP_CPU_SYNC)) {
+   ret = 

Re: [PATCH 22/28] sgiseeq: convert from dma_cache_sync to dma_sync_single_for_device

2020-09-01 Thread Thomas Bogendoerfer
On Tue, Sep 01, 2020 at 07:16:27PM +0200, Christoph Hellwig wrote:
> Well, if IP22 doesn't speculate (which I'm pretty sure is the case),
> dma_sync_single_for_cpu should indeeed be a no-op.  But then there
> also shouldn't be anything in the cache, as the previous
> dma_sync_single_for_device should have invalidated it.  So it seems like
> we are missing one (or more) ownership transfers to the device.  I'll
> try to look at the the ownership management in a little more detail
> tomorrow.

this is the problem:

   /* Always check for received packets. */
sgiseeq_rx(dev, sp, hregs, sregs);

so the driver will look at the rx descriptor on every interrupt, so
we cache the rx descriptor on the first interrupt and if there was
$no rx packet, we will only see it, if cache line gets flushed for
some other reason. kick_tx() does a busy loop checking tx descriptors,
with just sync_desc_cpu...

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.[ RFC1925, 2.3 ]
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v9 01/32] drm: prime: add common helper to check scatterlist contiguity

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

It is a common operation done by DRM drivers to check the contiguity
of the DMA-mapped buffer described by a scatterlist in the
sg_table object. Let's add a common helper for this operation.


I still think this could be hoisted even further out to the common 
sgtable API level, but let's get the individual subsystems straightened 
out first then worry about consolidation later.


Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
Reviewed-by: Andrzej Hajda 
---
  drivers/gpu/drm/drm_gem_cma_helper.c | 23 +++--
  drivers/gpu/drm/drm_prime.c  | 31 
  include/drm/drm_prime.h  |  2 ++
  3 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c 
b/drivers/gpu/drm/drm_gem_cma_helper.c
index 822edeadbab3..59b9ca207b42 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -471,26 +471,9 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
  {
struct drm_gem_cma_object *cma_obj;
  
-	if (sgt->nents != 1) {

-   /* check if the entries in the sg_table are contiguous */
-   dma_addr_t next_addr = sg_dma_address(sgt->sgl);
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt->sgl, s, sgt->nents, i) {
-   /*
-* sg_dma_address(s) is only valid for entries
-* that have sg_dma_len(s) != 0
-*/
-   if (!sg_dma_len(s))
-   continue;
-
-   if (sg_dma_address(s) != next_addr)
-   return ERR_PTR(-EINVAL);
-
-   next_addr = sg_dma_address(s) + sg_dma_len(s);
-   }
-   }
+   /* check if the entries in the sg_table are contiguous */
+   if (drm_prime_get_contiguous_size(sgt) < attach->dmabuf->size)
+   return ERR_PTR(-EINVAL);
  
  	/* Create a CMA GEM buffer. */

cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 1693aa7c14b5..4ed5ed1f078c 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -825,6 +825,37 @@ struct sg_table *drm_prime_pages_to_sg(struct page 
**pages, unsigned int nr_page
  }
  EXPORT_SYMBOL(drm_prime_pages_to_sg);
  
+/**

+ * drm_prime_get_contiguous_size - returns the contiguous size of the buffer
+ * @sgt: sg_table describing the buffer to check
+ *
+ * This helper calculates the contiguous size in the DMA address space
+ * of the the buffer described by the provided sg_table.
+ *
+ * This is useful for implementing
+ * _gem_object_funcs.gem_prime_import_sg_table.
+ */
+unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt)
+{
+   dma_addr_t expected = sg_dma_address(sgt->sgl);
+   struct scatterlist *sg;
+   unsigned long size = 0;
+   int i;
+
+   for_each_sgtable_dma_sg(sgt, sg, i) {
+   unsigned int len = sg_dma_len(sg);
+
+   if (!len)
+   break;
+   if (sg_dma_address(sg) != expected)
+   break;
+   expected += len;
+   size += len;
+   }
+   return size;
+}
+EXPORT_SYMBOL(drm_prime_get_contiguous_size);
+
  /**
   * drm_gem_prime_export - helper library implementation of the export callback
   * @obj: GEM object to export
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
index 9af7422b44cf..47ef11614627 100644
--- a/include/drm/drm_prime.h
+++ b/include/drm/drm_prime.h
@@ -92,6 +92,8 @@ struct sg_table *drm_prime_pages_to_sg(struct page **pages, 
unsigned int nr_page
  struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj,
 int flags);
  
+unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt);

+
  /* helper functions for importing */
  struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
struct dma_buf *dma_buf,


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


Re: [PATCH v9 02/32] drm: prime: use sgtable iterators in drm_prime_sg_to_page_addr_arrays()

2020-09-01 Thread Robin Murphy

On 2020-08-26 07:32, Marek Szyprowski wrote:

Replace the current hand-crafted code for extracting pages and DMA
addresses from the given scatterlist by the much more robust
code based on the generic scatterlist iterators and recently
introduced sg_table-based wrappers. The resulting code is simple and
easy to understand, so the comment describing the old code is no
longer needed.


Is removing the WARN_ON()s intentional? It certainly seems like it would 
be a genuine driver bug if the caller asked for addresses but didn't 
allocate appropriately-sized arrays. Might be worth noting either way. 
I'm also assuming this isn't called in performance-critical paths with 
massive lists such that the two separate iterations might have a 
noticeable impact.


Nits aside,

Reviewed-by: Robin Murphy 


Signed-off-by: Marek Szyprowski 
Reviewed-by: Andrzej Hajda 
---
  drivers/gpu/drm/drm_prime.c | 49 -
  1 file changed, 15 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 4ed5ed1f078c..5d181bf60a44 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -990,45 +990,26 @@ EXPORT_SYMBOL(drm_gem_prime_import);
  int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page 
**pages,
 dma_addr_t *addrs, int max_entries)
  {
-   unsigned count;
-   struct scatterlist *sg;
-   struct page *page;
-   u32 page_len, page_index;
-   dma_addr_t addr;
-   u32 dma_len, dma_index;
-
-   /*
-* Scatterlist elements contains both pages and DMA addresses, but
-* one shoud not assume 1:1 relation between them. The sg->length is
-* the size of the physical memory chunk described by the sg->page,
-* while sg_dma_len(sg) is the size of the DMA (IO virtual) chunk
-* described by the sg_dma_address(sg).
-*/
-   page_index = 0;
-   dma_index = 0;
-   for_each_sg(sgt->sgl, sg, sgt->nents, count) {
-   page_len = sg->length;
-   page = sg_page(sg);
-   dma_len = sg_dma_len(sg);
-   addr = sg_dma_address(sg);
-
-   while (pages && page_len > 0) {
-   if (WARN_ON(page_index >= max_entries))
+   struct sg_dma_page_iter dma_iter;
+   struct sg_page_iter page_iter;
+   struct page **p = pages;
+   dma_addr_t *a = addrs;
+
+   if (pages) {
+   for_each_sgtable_page(sgt, _iter, 0) {
+   if (p - pages >= max_entries)
return -1;
-   pages[page_index] = page;
-   page++;
-   page_len -= PAGE_SIZE;
-   page_index++;
+   *p++ = sg_page_iter_page(_iter);
}
-   while (addrs && dma_len > 0) {
-   if (WARN_ON(dma_index >= max_entries))
+   }
+   if (addrs) {
+   for_each_sgtable_dma_page(sgt, _iter, 0) {
+   if (a - addrs >= max_entries)
return -1;
-   addrs[dma_index] = addr;
-   addr += PAGE_SIZE;
-   dma_len -= PAGE_SIZE;
-   dma_index++;
+   *a++ = sg_page_iter_dma_address(_iter);
}
}
+
return 0;
  }
  EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays);


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


Re: [PATCH 22/28] sgiseeq: convert from dma_cache_sync to dma_sync_single_for_device

2020-09-01 Thread Christoph Hellwig
On Tue, Sep 01, 2020 at 07:12:41PM +0200, Thomas Bogendoerfer wrote:
> On Tue, Sep 01, 2020 at 05:22:09PM +0200, Thomas Bogendoerfer wrote:
> > On Wed, Aug 19, 2020 at 08:55:49AM +0200, Christoph Hellwig wrote:
> > > Use the proper modern API to transfer cache ownership for incoherent DMA.
> > > 
> > > Signed-off-by: Christoph Hellwig 
> > > ---
> > >  drivers/net/ethernet/seeq/sgiseeq.c | 12 
> > >  1 file changed, 8 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/drivers/net/ethernet/seeq/sgiseeq.c 
> > > b/drivers/net/ethernet/seeq/sgiseeq.c
> > > index 39599bbb5d45b6..f91dae16d69a19 100644
> > > --- a/drivers/net/ethernet/seeq/sgiseeq.c
> > > +++ b/drivers/net/ethernet/seeq/sgiseeq.c
> > > @@ -112,14 +112,18 @@ struct sgiseeq_private {
> > >  
> > >  static inline void dma_sync_desc_cpu(struct net_device *dev, void *addr)
> > >  {
> > > - dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
> > > -DMA_FROM_DEVICE);
> > > + struct sgiseeq_private *sp = netdev_priv(dev);
> > > +
> > > + dma_sync_single_for_cpu(dev->dev.parent, VIRT_TO_DMA(sp, addr),
> > > + sizeof(struct sgiseeq_rx_desc), DMA_BIDIRECTIONAL);
> > >  }
> > >  
> > >  static inline void dma_sync_desc_dev(struct net_device *dev, void *addr)
> > >  {
> > > - dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
> > > -DMA_TO_DEVICE);
> > > + struct sgiseeq_private *sp = netdev_priv(dev);
> > > +
> > > + dma_sync_single_for_device(dev->dev.parent, VIRT_TO_DMA(sp, addr),
> > > + sizeof(struct sgiseeq_rx_desc), DMA_BIDIRECTIONAL);
> > >  }
> > 
> > this breaks ethernet on IP22 completely, but I haven't figured out why, yet.
> 
> the problem is that dma_sync_single_for_cpu() doesn't flush anything
> for IP22, because it only flushes for CPUs which do speculation. So
> either MIPS arch_sync_dma_for_cpu() should always flush or sgiseeq
> needs to use a different sync funktion, when it wants to re-read descriptors
> from memory.

Well, if IP22 doesn't speculate (which I'm pretty sure is the case),
dma_sync_single_for_cpu should indeeed be a no-op.  But then there
also shouldn't be anything in the cache, as the previous
dma_sync_single_for_device should have invalidated it.  So it seems like
we are missing one (or more) ownership transfers to the device.  I'll
try to look at the the ownership management in a little more detail
tomorrow.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 22/28] sgiseeq: convert from dma_cache_sync to dma_sync_single_for_device

2020-09-01 Thread Thomas Bogendoerfer
On Tue, Sep 01, 2020 at 05:22:09PM +0200, Thomas Bogendoerfer wrote:
> On Wed, Aug 19, 2020 at 08:55:49AM +0200, Christoph Hellwig wrote:
> > Use the proper modern API to transfer cache ownership for incoherent DMA.
> > 
> > Signed-off-by: Christoph Hellwig 
> > ---
> >  drivers/net/ethernet/seeq/sgiseeq.c | 12 
> >  1 file changed, 8 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/seeq/sgiseeq.c 
> > b/drivers/net/ethernet/seeq/sgiseeq.c
> > index 39599bbb5d45b6..f91dae16d69a19 100644
> > --- a/drivers/net/ethernet/seeq/sgiseeq.c
> > +++ b/drivers/net/ethernet/seeq/sgiseeq.c
> > @@ -112,14 +112,18 @@ struct sgiseeq_private {
> >  
> >  static inline void dma_sync_desc_cpu(struct net_device *dev, void *addr)
> >  {
> > -   dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
> > -  DMA_FROM_DEVICE);
> > +   struct sgiseeq_private *sp = netdev_priv(dev);
> > +
> > +   dma_sync_single_for_cpu(dev->dev.parent, VIRT_TO_DMA(sp, addr),
> > +   sizeof(struct sgiseeq_rx_desc), DMA_BIDIRECTIONAL);
> >  }
> >  
> >  static inline void dma_sync_desc_dev(struct net_device *dev, void *addr)
> >  {
> > -   dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
> > -  DMA_TO_DEVICE);
> > +   struct sgiseeq_private *sp = netdev_priv(dev);
> > +
> > +   dma_sync_single_for_device(dev->dev.parent, VIRT_TO_DMA(sp, addr),
> > +   sizeof(struct sgiseeq_rx_desc), DMA_BIDIRECTIONAL);
> >  }
> 
> this breaks ethernet on IP22 completely, but I haven't figured out why, yet.

the problem is that dma_sync_single_for_cpu() doesn't flush anything
for IP22, because it only flushes for CPUs which do speculation. So
either MIPS arch_sync_dma_for_cpu() should always flush or sgiseeq
needs to use a different sync funktion, when it wants to re-read descriptors
from memory.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.[ RFC1925, 2.3 ]
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 9/9] iommu/vt-d: Store guest PASID during bind

2020-09-01 Thread Auger Eric
Hi Jacob,
On 8/22/20 6:35 AM, Jacob Pan wrote:
> IOASID core maintains the guest-host mapping in the form of SPID and
> IOASID. This patch assigns the guest PASID (if valid) as SPID while
> binding guest page table with a host PASID. This mapping will be used
> for lookup and notifications.
> 
> Signed-off-by: Jacob Pan 
> ---
>  drivers/iommu/intel/svm.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index d8a5efa75095..4c958b1aec4c 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -406,6 +406,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, 
> struct device *dev,
>   if (data->flags & IOMMU_SVA_GPASID_VAL) {
>   svm->gpasid = data->gpasid;
>   svm->flags |= SVM_FLAG_GUEST_PASID;
> + ioasid_attach_spid(data->hpasid, data->gpasid);
don't you want to handle the returned value?
>   }
>   svm->iommu = iommu;
>   /*
> @@ -517,6 +518,7 @@ int intel_svm_unbind_gpasid(struct device *dev, int pasid)
>   ioasid_attach_data(pasid, NULL);
>   ioasid_notify(pasid, IOASID_UNBIND,
>   IOASID_NOTIFY_SET);
> + ioasid_attach_spid(pasid, INVALID_IOASID);
So this answers my previous question ;-) but won't it enter the if
(!ioasid_data) path and fail to reset the spid?

Eric
>   kfree(svm);
>   }
>   }
> 

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


Re: [PATCH v2 7/9] iommu/vt-d: Listen to IOASID notifications

2020-09-01 Thread Auger Eric
Hi Jacob,

On 8/22/20 6:35 AM, Jacob Pan wrote:
> On Intel Scalable I/O Virtualization (SIOV) enabled platforms, IOMMU
> driver is one of the users of IOASIDs. In normal flow, callers will
> perform IOASID allocation, bind, unbind, and free in order. However, for
> guest SVA, IOASID free could come before unbind as guest is untrusted.
> This patch registers IOASID notification handler such that IOMMU driver
> can perform PASID teardown upon receiving an unexpected IOASID free
> event.
> 
> Signed-off-by: Jacob Pan 
> ---
>  drivers/iommu/intel/svm.c   | 74 
> -
>  include/linux/intel-iommu.h |  2 ++
>  2 files changed, 75 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index 634e191ca2c3..600e3ae5b656 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -95,6 +95,72 @@ static inline bool intel_svm_capable(struct intel_iommu 
> *iommu)
>   return iommu->flags & VTD_FLAG_SVM_CAPABLE;
>  }
>  
> +#define pasid_lock_held() lock_is_held(_mutex.dep_map)
put after the pasid_mutex definition?
> +static DEFINE_MUTEX(pasid_mutex);
> +
> +static void intel_svm_free_async_fn(struct work_struct *work)
> +{
> + struct intel_svm *svm = container_of(work, struct intel_svm, work);
> + struct intel_svm_dev *sdev;
> +
> + /*
> +  * Unbind all devices associated with this PASID which is
> +  * being freed by other users such as VFIO.
> +  */
> + mutex_lock(_mutex);
> + list_for_each_entry_rcu(sdev, >devs, list, pasid_lock_held()) {
> + /* Does not poison forward pointer */
> + list_del_rcu(>list);
> + spin_lock(>iommu->lock);
> + intel_pasid_tear_down_entry(svm->iommu, sdev->dev,
> + svm->pasid, true);
> + spin_unlock(>iommu->lock);
> + kfree_rcu(sdev, rcu);
> + /*
> +  * Free before unbind only happens with guest usaged
usaged?
> +  * host PASIDs. IOASID free will detach private data
> +  * and free the IOASID entry.
> +  */
> + ioasid_put(NULL, svm->pasid);
> + if (list_empty(>devs))
> + kfree(svm);
> + }
> + mutex_unlock(_mutex);
> +}
> +
> +
> +static int pasid_status_change(struct notifier_block *nb,
> + unsigned long code, void *data)
> +{
> + struct ioasid_nb_args *args = (struct ioasid_nb_args *)data;
> + struct intel_svm *svm = (struct intel_svm *)args->pdata;
> + int ret = NOTIFY_DONE;
> +
> + if (code == IOASID_FREE) {
> + if (!svm)
> + goto done;
> + if (args->id != svm->pasid) {
> + pr_warn("Notify PASID does not match data %d : %d\n",
> + args->id, svm->pasid);
> + goto done;
> + }
> + schedule_work(>work);
> + return NOTIFY_OK;
> + }
> +done:
> + return ret;> +}
> +
> +static struct notifier_block pasid_nb = {
> + .notifier_call = pasid_status_change,
> +};
> +
> +void intel_svm_add_pasid_notifier(void)
> +{
> + /* Listen to all PASIDs, not specific to a set */
> + ioasid_register_notifier(NULL, _nb);
> +}
> +
>  void intel_svm_check(struct intel_iommu *iommu)
>  {
>   if (!pasid_supported(iommu))
> @@ -221,7 +287,6 @@ static const struct mmu_notifier_ops intel_mmuops = {
>   .invalidate_range = intel_invalidate_range,
>  };
>  
> -static DEFINE_MUTEX(pasid_mutex);
>  static LIST_HEAD(global_svm_list);
>  
>  #define for_each_svm_dev(sdev, svm, d)   \
> @@ -342,7 +407,14 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, 
> struct device *dev,
>   svm->gpasid = data->gpasid;
>   svm->flags |= SVM_FLAG_GUEST_PASID;
>   }
> + svm->iommu = iommu;
> + /*
> +  * Set up cleanup async work in case IOASID core notify us PASID
> +  * is freed before unbind.
> +  */
> + INIT_WORK(>work, intel_svm_free_async_fn);
>   ioasid_attach_data(data->hpasid, svm);
> + ioasid_get(NULL, svm->pasid);
>   INIT_LIST_HEAD_RCU(>devs);
>   mmput(svm->mm);
>   }
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index b1ed2f25f7c0..d36038e6ae0b 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>  int intel_svm_get_pasid(struct iommu_sva *handle);
>  int intel_svm_page_response(struct device *dev, struct iommu_fault_event 
> *evt,
>   struct iommu_page_response *msg);
> +void intel_svm_add_pasid_notifier(void);
>  
>  struct svm_dev_ops;
>  
> @@ -770,6 +771,7 @@ struct intel_svm {
>   int gpasid; /* 

Re: [PATCH 07/28] 53c700: improve non-coherent DMA handling

2020-09-01 Thread Matthew Wilcox
On Tue, Sep 01, 2020 at 06:41:12PM +0200, Helge Deller wrote:
> > I still have a zoo of machines running for such testing, including a
> > 715/64 and two 730.
> > I'm going to test this git tree on the 715/64:

The 715/64 is a 7100LC machine though.  I think you need to boot on
the 730 to test the non-coherent path.

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


Re: [PATCH v2 1/9] docs: Document IO Address Space ID (IOASID) APIs

2020-09-01 Thread Jacob Pan
Hi Eric,

On Thu, 27 Aug 2020 18:21:07 +0200
Auger Eric  wrote:

> Hi Jacob,
> On 8/24/20 12:32 PM, Jean-Philippe Brucker wrote:
> > On Fri, Aug 21, 2020 at 09:35:10PM -0700, Jacob Pan wrote:  
> >> IOASID is used to identify address spaces that can be targeted by
> >> device DMA. It is a system-wide resource that is essential to its
> >> many users. This document is an attempt to help developers from
> >> all vendors navigate the APIs. At this time, ARM SMMU and Intel’s
> >> Scalable IO Virtualization (SIOV) enabled platforms are the
> >> primary users of IOASID. Examples of how SIOV components interact
> >> with IOASID APIs are provided in that many APIs are driven by the
> >> requirements from SIOV.
> >>
> >> Signed-off-by: Liu Yi L 
> >> Signed-off-by: Wu Hao 
> >> Signed-off-by: Jacob Pan 
> >> ---
> >>  Documentation/ioasid.rst | 618
> >> +++ 1 file changed,
> >> 618 insertions(+) create mode 100644 Documentation/ioasid.rst
> >>
> >> diff --git a/Documentation/ioasid.rst b/Documentation/ioasid.rst  
> > 
> > Thanks for writing this up. Should it go to
> > Documentation/driver-api/, or Documentation/driver-api/iommu/? I
> > think this also needs to Cc linux-...@vger.kernel.org and
> > cor...@lwn.net 
> >> new file mode 100644
> >> index ..b6a8cdc885ff
> >> --- /dev/null
> >> +++ b/Documentation/ioasid.rst
> >> @@ -0,0 +1,618 @@
> >> +.. ioasid:
> >> +
> >> +=
> >> +IO Address Space ID
> >> +=
> >> +
> >> +IOASID is a generic name for PCIe Process Address ID (PASID) or
> >> ARM +SMMU sub-stream ID. An IOASID identifies an address space
> >> that DMA  
> > 
> > "SubstreamID"  
> On ARM if we don't use PASIDs we have streamids (SID) which can also
> identify address spaces that DMA requests can target. So maybe this
> definition is not sufficient.
> 
According to SMMU spec, the SubstreamID is equivalent to PASID. My
understanding is that SID is equivalent to PCI requester ID that
identifies stage 2. Do you plan to use IOASID for stage 2?
IOASID is mostly for SVA and DMA request w/ PASID.

> >   
> >> +requests can target.
> >> +
> >> +The primary use cases for IOASID are Shared Virtual Address (SVA)
> >> and +IO Virtual Address (IOVA). However, the requirements for
> >> IOASID  
> > 
> > IOVA alone isn't a use case, maybe "multiple IOVA spaces per
> > device"? 
> >> +management can vary among hardware architectures.
> >> +
> >> +This document covers the generic features supported by IOASID
> >> +APIs. Vendor-specific use cases are also illustrated with Intel's
> >> VT-d +based platforms as the first example.
> >> +
> >> +.. contents:: :local:
> >> +
> >> +Glossary
> >> +
> >> +PASID - Process Address Space ID
> >> +
> >> +IOASID - IO Address Space ID (generic term for PCIe PASID and
> >> +sub-stream ID in SMMU)  
> > 
> > "SubstreamID"
> >   
> >> +
> >> +SVA/SVM - Shared Virtual Addressing/Memory
> >> +
> >> +ENQCMD - New Intel X86 ISA for efficient workqueue submission
> >> [1]  
> > 
> > Maybe drop the "New", to keep the documentation perennial. It might
> > be good to add internal links here to the specifications URLs at
> > the bottom. 
> >> +
> >> +DSA - Intel Data Streaming Accelerator [2]
> >> +
> >> +VDCM - Virtual device composition module [3]
> >> +
> >> +SIOV - Intel Scalable IO Virtualization
> >> +
> >> +
> >> +Key Concepts
> >> +
> >> +
> >> +IOASID Set
> >> +---
> >> +An IOASID set is a group of IOASIDs allocated from the system-wide
> >> +IOASID pool. An IOASID set is created and can be identified by a
> >> +token of u64. Refer to IOASID set APIs for more details.  
> > 
> > Identified either by an u64 or an mm_struct, right?  Maybe just
> > drop the second sentence if it's detailed in the IOASID set section
> > below. 
> >> +
> >> +IOASID set is particularly useful for guest SVA where each guest
> >> could +have its own IOASID set for security and efficiency reasons.
> >> +
> >> +IOASID Set Private ID (SPID)
> >> +
> >> +SPIDs are introduced as IOASIDs within its set. Each SPID maps to
> >> a +system-wide IOASID but the namespace of SPID is within its
> >> IOASID +set.  
> > 
> > The intro isn't super clear. Perhaps this is simpler:
> > "Each IOASID set has a private namespace of SPIDs. An SPID maps to a
> > single system-wide IOASID."  
> or, "within an ioasid set, each ioasid can be associated with an alias
> ID, named SPID."
I don't have strong opinion, I feel it is good to explain the
relationship between SPID and IOASID in both directions, how about add?
" Conversely, each IOASID is associated with an alias ID, named SPID."

> >   
> >> SPIDs can be used as guest IOASIDs where each guest could do
> >> +IOASID allocation from its own pool and map them to host physical
> >> +IOASIDs. SPIDs are particularly useful for supporting live
> >> migration +where decoupling guest and host physical resources are

Re: [PATCH v2 6/9] iommu/ioasid: Introduce notification APIs

2020-09-01 Thread Auger Eric
Hi Jacob,

On 8/22/20 6:35 AM, Jacob Pan wrote:
> Relations among IOASID users largely follow a publisher-subscriber
> pattern. E.g. to support guest SVA on Intel Scalable I/O Virtualization
> (SIOV) enabled platforms, VFIO, IOMMU, device drivers, KVM are all users
> of IOASIDs. When a state change occurs, VFIO publishes the change event
> that needs to be processed by other users/subscribers.
> 
> This patch introduced two types of notifications: global and per
> ioasid_set. The latter is intended for users who only needs to handle
> events related to the IOASID of a given set.
> For more information, refer to the kernel documentation at
> Documentation/ioasid.rst.
> 
> Signed-off-by: Liu Yi L 
> Signed-off-by: Wu Hao 
> Signed-off-by: Jacob Pan 
> ---
>  drivers/iommu/ioasid.c | 280 
> -
>  include/linux/ioasid.h |  70 +
>  2 files changed, 348 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iommu/ioasid.c b/drivers/iommu/ioasid.c
> index c0aef38a4fde..6ddc09a7fe74 100644
> --- a/drivers/iommu/ioasid.c
> +++ b/drivers/iommu/ioasid.c
> @@ -9,8 +9,35 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  static DEFINE_XARRAY_ALLOC(ioasid_sets);
> +/*
> + * An IOASID could have multiple consumers where each consumeer may have
can have multiple consumers
> + * hardware contexts associated with IOASIDs.
> + * When a status change occurs, such as IOASID is being freed, notifier 
> chains
s/such as IOASID is being freed/, like on IOASID deallocation,
> + * are used to keep the consumers in sync.
> + * This is a publisher-subscriber pattern where publisher can change the
> + * state of each IOASID, e.g. alloc/free, bind IOASID to a device and mm.
> + * On the other hand, subscribers gets notified for the state change and
> + * keep local states in sync.
> + *
> + * Currently, the notifier is global. A further optimization could be per
> + * IOASID set notifier chain.
> + */
> +static ATOMIC_NOTIFIER_HEAD(ioasid_chain);
> +
> +/* List to hold pending notification block registrations */
> +static LIST_HEAD(ioasid_nb_pending_list);
> +static DEFINE_SPINLOCK(ioasid_nb_lock);
> +struct ioasid_set_nb {
> + struct list_headlist;
> + struct notifier_block   *nb;
> + void*token;
> + struct ioasid_set   *set;
> + boolactive;
> +};
> +
>  enum ioasid_state {
>   IOASID_STATE_INACTIVE,
>   IOASID_STATE_ACTIVE,
> @@ -394,6 +421,7 @@ EXPORT_SYMBOL_GPL(ioasid_find_by_spid);
>  ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max,
> void *private)
>  {
> + struct ioasid_nb_args args;
>   struct ioasid_data *data;
>   void *adata;
>   ioasid_t id = INVALID_IOASID;
> @@ -445,8 +473,14 @@ ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t 
> min, ioasid_t max,
>   goto exit_free;
>   }
>   set->nr_ioasids++;
> - goto done_unlock;
> + args.id = id;
> + /* Set private ID is not attached during allocation */
> + args.spid = INVALID_IOASID;
> + args.set = set;
> + atomic_notifier_call_chain(>nh, IOASID_ALLOC, );
>  
> + spin_unlock(_allocator_lock);
> + return id;
spurious change
>  exit_free:
>   kfree(data);
>  done_unlock:
> @@ -479,6 +513,7 @@ static void ioasid_do_free(struct ioasid_data *data)
>  
>  static void ioasid_free_locked(struct ioasid_set *set, ioasid_t ioasid)
>  {
> + struct ioasid_nb_args args;
>   struct ioasid_data *data;
>  
>   data = xa_load(_allocator->xa, ioasid);
> @@ -491,7 +526,16 @@ static void ioasid_free_locked(struct ioasid_set *set, 
> ioasid_t ioasid)
>   pr_warn("Cannot free IOASID %u due to set ownership\n", ioasid);
>   return;
>   }
> +
spurious new line
>   data->state = IOASID_STATE_FREE_PENDING;
> + /* Notify all users that this IOASID is being freed */
> + args.id = ioasid;
> + args.spid = data->spid;
> + args.pdata = data->private;
> + args.set = data->set;
> + atomic_notifier_call_chain(_chain, IOASID_FREE, );
> + /* Notify the ioasid_set for per set users */
> + atomic_notifier_call_chain(>nh, IOASID_FREE, );
>  
>   if (!refcount_dec_and_test(>users))
>   return;
Shouldn't we call the notifier only when ref count == 0?
> @@ -514,6 +558,28 @@ void ioasid_free(struct ioasid_set *set, ioasid_t ioasid)
>  }
>  EXPORT_SYMBOL_GPL(ioasid_free);
>  
> +static void ioasid_add_pending_nb(struct ioasid_set *set)
> +{
> + struct ioasid_set_nb *curr;
> +
> + if (set->type != IOASID_SET_TYPE_MM)
> + return;
> +
> + /*
> +  * Check if there are any pending nb requests for the given token, if so
> +  * add them to the notifier chain.
> +  */
> + spin_lock(_nb_lock);
> + list_for_each_entry(curr, _nb_pending_list, list) {
> + if (curr->token == set->token && !curr->active) {
> +

[PATCH v16 11/20] drm/msm: Show process names in gem_describe

2020-09-01 Thread Rob Clark
From: Rob Clark 

In $debugfs/gem we already show any vma(s) associated with an object.
Also show process names if the vma's address space is a per-process
address space.

Signed-off-by: Rob Clark 
Reviewed-by: Jordan Crouse 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/msm_drv.c |  2 +-
 drivers/gpu/drm/msm/msm_gem.c | 25 +
 drivers/gpu/drm/msm/msm_gem.h |  5 +
 drivers/gpu/drm/msm/msm_gem_vma.c |  1 +
 drivers/gpu/drm/msm/msm_gpu.c |  8 +---
 drivers/gpu/drm/msm/msm_gpu.h |  2 +-
 6 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 7e963f707852..7143756b7e83 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -597,7 +597,7 @@ static int context_init(struct drm_device *dev, struct 
drm_file *file)
kref_init(>ref);
msm_submitqueue_init(dev, ctx);
 
-   ctx->aspace = msm_gpu_create_private_address_space(priv->gpu);
+   ctx->aspace = msm_gpu_create_private_address_space(priv->gpu, current);
file->driver_priv = ctx;
 
return 0;
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 3cb7aeb93fd3..76a6c5271e57 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -842,11 +842,28 @@ void msm_gem_describe(struct drm_gem_object *obj, struct 
seq_file *m)
 
seq_puts(m, "  vmas:");
 
-   list_for_each_entry(vma, _obj->vmas, list)
-   seq_printf(m, " [%s: %08llx,%s,inuse=%d]",
-   vma->aspace != NULL ? vma->aspace->name : NULL,
-   vma->iova, vma->mapped ? "mapped" : "unmapped",
+   list_for_each_entry(vma, _obj->vmas, list) {
+   const char *name, *comm;
+   if (vma->aspace) {
+   struct msm_gem_address_space *aspace = 
vma->aspace;
+   struct task_struct *task =
+   get_pid_task(aspace->pid, PIDTYPE_PID);
+   if (task) {
+   comm = kstrdup(task->comm, GFP_KERNEL);
+   } else {
+   comm = NULL;
+   }
+   name = aspace->name;
+   } else {
+   name = comm = NULL;
+   }
+   seq_printf(m, " [%s%s%s: aspace=%p, 
%08llx,%s,inuse=%d]",
+   name, comm ? ":" : "", comm ? comm : "",
+   vma->aspace, vma->iova,
+   vma->mapped ? "mapped" : "unmapped",
vma->inuse);
+   kfree(comm);
+   }
 
seq_puts(m, "\n");
}
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 9c573c4269cb..7b1c7a5f8eef 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -24,6 +24,11 @@ struct msm_gem_address_space {
spinlock_t lock; /* Protects drm_mm node allocation/removal */
struct msm_mmu *mmu;
struct kref kref;
+
+   /* For address spaces associated with a specific process, this
+* will be non-NULL:
+*/
+   struct pid *pid;
 };
 
 struct msm_gem_vma {
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c 
b/drivers/gpu/drm/msm/msm_gem_vma.c
index 29cc1305cf37..80a8a266d68f 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -17,6 +17,7 @@ msm_gem_address_space_destroy(struct kref *kref)
drm_mm_takedown(>mm);
if (aspace->mmu)
aspace->mmu->funcs->destroy(aspace->mmu);
+   put_pid(aspace->pid);
kfree(aspace);
 }
 
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 951850804d77..ac8961187a73 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -825,10 +825,9 @@ static int get_clocks(struct platform_device *pdev, struct 
msm_gpu *gpu)
 
 /* Return a new address space for a msm_drm_private instance */
 struct msm_gem_address_space *
-msm_gpu_create_private_address_space(struct msm_gpu *gpu)
+msm_gpu_create_private_address_space(struct msm_gpu *gpu, struct task_struct 
*task)
 {
struct msm_gem_address_space *aspace = NULL;
-
if (!gpu)
return NULL;
 
@@ -836,8 +835,11 @@ msm_gpu_create_private_address_space(struct msm_gpu *gpu)
 * If the target doesn't support private address spaces then return
 * the global one
 */
-   if (gpu->funcs->create_private_address_space)
+   if (gpu->funcs->create_private_address_space) {
aspace = gpu->funcs->create_private_address_space(gpu);
+   if 

[PATCH v16 16/20] iommu/arm-smmu-qcom: Add implementation for the adreno GPU SMMU

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Add a special implementation for the SMMU attached to most Adreno GPU
target triggered from the qcom,adreno-smmu compatible string.

The new Adreno SMMU implementation will enable split pagetables
(TTBR1) for the domain attached to the GPU device (SID 0) and
hard code it context bank 0 so the GPU hardware can implement
per-instance pagetables.

Co-developed-by: Rob Clark 
Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/iommu/arm/arm-smmu/arm-smmu-impl.c |   3 +
 drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 149 -
 drivers/iommu/arm/arm-smmu/arm-smmu.h  |   1 +
 3 files changed, 151 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
index 88f17cc33023..d199b4bff15d 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
@@ -223,6 +223,9 @@ struct arm_smmu_device *arm_smmu_impl_init(struct 
arm_smmu_device *smmu)
of_device_is_compatible(np, "qcom,sm8250-smmu-500"))
return qcom_smmu_impl_init(smmu);
 
+   if (of_device_is_compatible(smmu->dev->of_node, "qcom,adreno-smmu"))
+   return qcom_adreno_smmu_impl_init(smmu);
+
if (of_device_is_compatible(np, "marvell,ap806-smmu-500"))
smmu->impl = _mmu500_impl;
 
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index be4318044f96..5640d9960610 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
  */
 
+#include 
 #include 
 #include 
 
@@ -12,6 +13,132 @@ struct qcom_smmu {
struct arm_smmu_device smmu;
 };
 
+#define QCOM_ADRENO_SMMU_GPU_SID 0
+
+static bool qcom_adreno_smmu_is_gpu_device(struct device *dev)
+{
+   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+   int i;
+
+   /*
+* The GPU will always use SID 0 so that is a handy way to uniquely
+* identify it and configure it for per-instance pagetables
+*/
+   for (i = 0; i < fwspec->num_ids; i++) {
+   u16 sid = FIELD_GET(ARM_SMMU_SMR_ID, fwspec->ids[i]);
+
+   if (sid == QCOM_ADRENO_SMMU_GPU_SID)
+   return true;
+   }
+
+   return false;
+}
+
+static const struct io_pgtable_cfg *qcom_adreno_smmu_get_ttbr1_cfg(
+   const void *cookie)
+{
+   struct arm_smmu_domain *smmu_domain = (void *)cookie;
+   struct io_pgtable *pgtable =
+   io_pgtable_ops_to_pgtable(smmu_domain->pgtbl_ops);
+   return >cfg;
+}
+
+/*
+ * Local implementation to configure TTBR0 with the specified pagetable config.
+ * The GPU driver will call this to enable TTBR0 when per-instance pagetables
+ * are active
+ */
+
+static int qcom_adreno_smmu_set_ttbr0_cfg(const void *cookie,
+   const struct io_pgtable_cfg *pgtbl_cfg)
+{
+   struct arm_smmu_domain *smmu_domain = (void *)cookie;
+   struct io_pgtable *pgtable = 
io_pgtable_ops_to_pgtable(smmu_domain->pgtbl_ops);
+   struct arm_smmu_cfg *cfg = _domain->cfg;
+   struct arm_smmu_cb *cb = _domain->smmu->cbs[cfg->cbndx];
+
+   /* The domain must have split pagetables already enabled */
+   if (cb->tcr[0] & ARM_SMMU_TCR_EPD1)
+   return -EINVAL;
+
+   /* If the pagetable config is NULL, disable TTBR0 */
+   if (!pgtbl_cfg) {
+   /* Do nothing if it is already disabled */
+   if ((cb->tcr[0] & ARM_SMMU_TCR_EPD0))
+   return -EINVAL;
+
+   /* Set TCR to the original configuration */
+   cb->tcr[0] = arm_smmu_lpae_tcr(>cfg);
+   cb->ttbr[0] = FIELD_PREP(ARM_SMMU_TTBRn_ASID, cb->cfg->asid);
+   } else {
+   u32 tcr = cb->tcr[0];
+
+   /* Don't call this again if TTBR0 is already enabled */
+   if (!(cb->tcr[0] & ARM_SMMU_TCR_EPD0))
+   return -EINVAL;
+
+   tcr |= arm_smmu_lpae_tcr(pgtbl_cfg);
+   tcr &= ~(ARM_SMMU_TCR_EPD0 | ARM_SMMU_TCR_EPD1);
+
+   cb->tcr[0] = tcr;
+   cb->ttbr[0] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr;
+   cb->ttbr[0] |= FIELD_PREP(ARM_SMMU_TTBRn_ASID, cb->cfg->asid);
+   }
+
+   arm_smmu_write_context_bank(smmu_domain->smmu, cb->cfg->cbndx);
+
+   return 0;
+}
+
+static int qcom_adreno_smmu_alloc_context_bank(struct arm_smmu_domain 
*smmu_domain,
+   struct device *dev, int start, int count)
+{
+   struct arm_smmu_device *smmu = smmu_domain->smmu;
+
+   /*
+* Assign context bank 0 to the GPU device so the GPU hardware can
+* switch pagetables
+*/
+   if (qcom_adreno_smmu_is_gpu_device(dev)) {
+   start = 0;
+   count = 1;
+   

[PATCH v16 17/20] iommu/arm-smmu: Add a way for implementations to influence SCTLR

2020-09-01 Thread Rob Clark
From: Rob Clark 

For the Adreno GPU's SMMU, we want SCTLR.HUPCF set to ensure that
pending translations are not terminated on iova fault.  Otherwise
a terminated CP read could hang the GPU by returning invalid
command-stream data.

Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 6 ++
 drivers/iommu/arm/arm-smmu/arm-smmu.c  | 3 +++
 drivers/iommu/arm/arm-smmu/arm-smmu.h  | 3 +++
 3 files changed, 12 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index 5640d9960610..2aa6249050ff 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -127,6 +127,12 @@ static int qcom_adreno_smmu_init_context(struct 
arm_smmu_domain *smmu_domain,
(smmu_domain->cfg.fmt == ARM_SMMU_CTX_FMT_AARCH64))
pgtbl_cfg->quirks |= IO_PGTABLE_QUIRK_ARM_TTBR1;
 
+   /*
+* On the GPU device we want to process subsequent transactions after a
+* fault to keep the GPU from hanging
+*/
+   smmu_domain->cfg.sctlr_set |= ARM_SMMU_SCTLR_HUPCF;
+
/*
 * Initialize private interface with GPU:
 */
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 68b7b9e6140e..1773f54a7464 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -617,6 +617,9 @@ void arm_smmu_write_context_bank(struct arm_smmu_device 
*smmu, int idx)
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
reg |= ARM_SMMU_SCTLR_E;
 
+   reg |= cfg->sctlr_set;
+   reg &= ~cfg->sctlr_clr;
+
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, reg);
 }
 
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h 
b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index cd75a33967bb..2df3a70a8a41 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -144,6 +144,7 @@ enum arm_smmu_cbar_type {
 #define ARM_SMMU_CB_SCTLR  0x0
 #define ARM_SMMU_SCTLR_S1_ASIDPNE  BIT(12)
 #define ARM_SMMU_SCTLR_CFCFG   BIT(7)
+#define ARM_SMMU_SCTLR_HUPCF   BIT(8)
 #define ARM_SMMU_SCTLR_CFIEBIT(6)
 #define ARM_SMMU_SCTLR_CFREBIT(5)
 #define ARM_SMMU_SCTLR_E   BIT(4)
@@ -341,6 +342,8 @@ struct arm_smmu_cfg {
u16 asid;
u16 vmid;
};
+   u32 sctlr_set;/* extra bits to set in 
SCTLR */
+   u32 sctlr_clr;/* bits to mask in SCTLR 
*/
enum arm_smmu_cbar_type cbar;
enum arm_smmu_context_fmt   fmt;
 };
-- 
2.26.2

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


[PATCH v16 10/20] drm/msm/a6xx: Add support for per-instance pagetables

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Add support for using per-instance pagetables if all the dependencies are
available.

Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Akhil P Oommen 
---
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 63 +++
 drivers/gpu/drm/msm/adreno/a6xx_gpu.h |  1 +
 drivers/gpu/drm/msm/msm_ringbuffer.h  |  1 +
 3 files changed, 65 insertions(+)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 5eabb0109577..d7ad6c78d787 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -81,6 +81,49 @@ static void get_stats_counter(struct msm_ringbuffer *ring, 
u32 counter,
OUT_RING(ring, upper_32_bits(iova));
 }
 
+static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,
+   struct msm_ringbuffer *ring, struct msm_file_private *ctx)
+{
+   phys_addr_t ttbr;
+   u32 asid;
+   u64 memptr = rbmemptr(ring, ttbr0);
+
+   if (ctx == a6xx_gpu->cur_ctx)
+   return;
+
+   if (msm_iommu_pagetable_params(ctx->aspace->mmu, , ))
+   return;
+
+   /* Execute the table update */
+   OUT_PKT7(ring, CP_SMMU_TABLE_UPDATE, 4);
+   OUT_RING(ring, CP_SMMU_TABLE_UPDATE_0_TTBR0_LO(lower_32_bits(ttbr)));
+
+   OUT_RING(ring,
+   CP_SMMU_TABLE_UPDATE_1_TTBR0_HI(upper_32_bits(ttbr)) |
+   CP_SMMU_TABLE_UPDATE_1_ASID(asid));
+   OUT_RING(ring, CP_SMMU_TABLE_UPDATE_2_CONTEXTIDR(0));
+   OUT_RING(ring, CP_SMMU_TABLE_UPDATE_3_CONTEXTBANK(0));
+
+   /*
+* Write the new TTBR0 to the memstore. This is good for debugging.
+*/
+   OUT_PKT7(ring, CP_MEM_WRITE, 4);
+   OUT_RING(ring, CP_MEM_WRITE_0_ADDR_LO(lower_32_bits(memptr)));
+   OUT_RING(ring, CP_MEM_WRITE_1_ADDR_HI(upper_32_bits(memptr)));
+   OUT_RING(ring, lower_32_bits(ttbr));
+   OUT_RING(ring, (asid << 16) | upper_32_bits(ttbr));
+
+   /*
+* And finally, trigger a uche flush to be sure there isn't anything
+* lingering in that part of the GPU
+*/
+
+   OUT_PKT7(ring, CP_EVENT_WRITE, 1);
+   OUT_RING(ring, 0x31);
+
+   a6xx_gpu->cur_ctx = ctx;
+}
+
 static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
 {
unsigned int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT;
@@ -90,6 +133,8 @@ static void a6xx_submit(struct msm_gpu *gpu, struct 
msm_gem_submit *submit)
struct msm_ringbuffer *ring = submit->ring;
unsigned int i;
 
+   a6xx_set_pagetable(a6xx_gpu, ring, submit->queue->ctx);
+
get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP_0_LO,
rbmemptr_stats(ring, index, cpcycles_start));
 
@@ -696,6 +741,8 @@ static int a6xx_hw_init(struct msm_gpu *gpu)
/* Always come up on rb 0 */
a6xx_gpu->cur_ring = gpu->rb[0];
 
+   a6xx_gpu->cur_ctx = NULL;
+
/* Enable the SQE_to start the CP engine */
gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 1);
 
@@ -1008,6 +1055,21 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu)
return (unsigned long)busy_time;
 }
 
+static struct msm_gem_address_space *
+a6xx_create_private_address_space(struct msm_gpu *gpu)
+{
+   struct msm_gem_address_space *aspace = NULL;
+   struct msm_mmu *mmu;
+
+   mmu = msm_iommu_pagetable_create(gpu->aspace->mmu);
+
+   if (!IS_ERR(mmu))
+   aspace = msm_gem_address_space_create(mmu,
+   "gpu", 0x1ULL, 0x1ULL);
+
+   return aspace;
+}
+
 static const struct adreno_gpu_funcs funcs = {
.base = {
.get_param = adreno_get_param,
@@ -1031,6 +1093,7 @@ static const struct adreno_gpu_funcs funcs = {
.gpu_state_put = a6xx_gpu_state_put,
 #endif
.create_address_space = adreno_iommu_create_address_space,
+   .create_private_address_space = 
a6xx_create_private_address_space,
},
.get_timestamp = a6xx_get_timestamp,
 };
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h 
b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 03ba60d5b07f..da22d7549d9b 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -19,6 +19,7 @@ struct a6xx_gpu {
uint64_t sqe_iova;
 
struct msm_ringbuffer *cur_ring;
+   struct msm_file_private *cur_ctx;
 
struct a6xx_gmu gmu;
 };
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h 
b/drivers/gpu/drm/msm/msm_ringbuffer.h
index 7764373d0ed2..0987d6bf848c 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.h
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.h
@@ -31,6 +31,7 @@ struct msm_rbmemptrs {
volatile uint32_t fence;
 
volatile struct msm_gpu_submit_stats stats[MSM_GPU_SUBMIT_STATS_COUNT];
+   volatile u64 ttbr0;
 };
 
 struct msm_ringbuffer {
-- 
2.26.2

___
iommu mailing list
iommu@lists.linux-foundation.org

[PATCH v16 19/20] arm: dts: qcom: sm845: Set the compatible string for the GPU SMMU

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Set the qcom,adreno-smmu compatible string for the GPU SMMU to enable
split pagetables and per-instance pagetables for drm/msm.

Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
---
 arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi | 9 +
 arch/arm64/boot/dts/qcom/sdm845.dtsi   | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
index 64fc1bfd66fa..39f23cdcbd02 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
@@ -633,6 +633,15 @@ _mdp {
status = "okay";
 };
 
+/*
+ * Cheza fw does not properly program the GPU aperture to allow the
+ * GPU to update the SMMU pagetables for context switches.  Work
+ * around this by dropping the "qcom,adreno-smmu" compat string.
+ */
+_smmu {
+   compatible = "qcom,sdm845-smmu-v2", "qcom,smmu-v2";
+};
+
 _pil {
iommus = <_smmu 0x781 0x0>,
 <_smmu 0x724 0x3>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 2884577dcb77..76a8a34640ae 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -4058,7 +4058,7 @@ opp-25700 {
};
 
adreno_smmu: iommu@504 {
-   compatible = "qcom,sdm845-smmu-v2", "qcom,smmu-v2";
+   compatible = "qcom,sdm845-smmu-v2", "qcom,adreno-smmu", 
"qcom,smmu-v2";
reg = <0 0x504 0 0x1>;
#iommu-cells = <1>;
#global-interrupts = <2>;
-- 
2.26.2

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


[PATCH v16 18/20] dt-bindings: arm-smmu: Add compatible string for Adreno GPU SMMU

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Every Qcom Adreno GPU has an embedded SMMU for its own use. These
devices depend on unique features such as split pagetables,
different stall/halt requirements and other settings. Identify them
with a compatible string so that they can be identified in the
arm-smmu implementation specific code.

Signed-off-by: Jordan Crouse 
Reviewed-by: Rob Herring 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml 
b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index 503160a7b9a0..3b63f2ae24db 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -28,8 +28,6 @@ properties:
   - enum:
   - qcom,msm8996-smmu-v2
   - qcom,msm8998-smmu-v2
-  - qcom,sc7180-smmu-v2
-  - qcom,sdm845-smmu-v2
   - const: qcom,smmu-v2
 
   - description: Qcom SoCs implementing "arm,mmu-500"
@@ -40,6 +38,13 @@ properties:
   - qcom,sm8150-smmu-500
   - qcom,sm8250-smmu-500
   - const: arm,mmu-500
+  - description: Qcom Adreno GPUs implementing "arm,smmu-v2"
+items:
+  - enum:
+  - qcom,sc7180-smmu-v2
+  - qcom,sdm845-smmu-v2
+  - const: qcom,adreno-smmu
+  - const: qcom,smmu-v2
   - description: Marvell SoCs implementing "arm,mmu-500"
 items:
   - const: marvell,ap806-smmu-500
-- 
2.26.2

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


[PATCH v16 20/20] arm: dts: qcom: sc7180: Set the compatible string for the GPU SMMU

2020-09-01 Thread Rob Clark
From: Rob Clark 

Set the qcom,adreno-smmu compatible string for the GPU SMMU to enable
split pagetables and per-instance pagetables for drm/msm.

Signed-off-by: Rob Clark 
---
 arch/arm64/boot/dts/qcom/sc7180.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi 
b/arch/arm64/boot/dts/qcom/sc7180.dtsi
index d46b3833e52f..f3bef1cad889 100644
--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi
@@ -1937,7 +1937,7 @@ opp-18000 {
};
 
adreno_smmu: iommu@504 {
-   compatible = "qcom,sc7180-smmu-v2", "qcom,smmu-v2";
+   compatible = "qcom,sc7180-smmu-v2", "qcom,adreno-smmu", 
"qcom,smmu-v2";
reg = <0 0x0504 0 0x1>;
#iommu-cells = <1>;
#global-interrupts = <2>;
-- 
2.26.2

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


[PATCH v16 13/20] iommu/arm-smmu: Add support for split pagetables

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Enable TTBR1 for a context bank if IO_PGTABLE_QUIRK_ARM_TTBR1 is selected
by the io-pgtable configuration.

Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 19 +++
 drivers/iommu/arm/arm-smmu/arm-smmu.h | 25 +++--
 2 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 37d8d49299b4..8e884e58f208 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -552,11 +552,15 @@ static void arm_smmu_init_context_bank(struct 
arm_smmu_domain *smmu_domain,
cb->ttbr[0] = pgtbl_cfg->arm_v7s_cfg.ttbr;
cb->ttbr[1] = 0;
} else {
-   cb->ttbr[0] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr;
-   cb->ttbr[0] |= FIELD_PREP(ARM_SMMU_TTBRn_ASID,
- cfg->asid);
+   cb->ttbr[0] = FIELD_PREP(ARM_SMMU_TTBRn_ASID,
+cfg->asid);
cb->ttbr[1] = FIELD_PREP(ARM_SMMU_TTBRn_ASID,
 cfg->asid);
+
+   if (pgtbl_cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
+   cb->ttbr[1] |= pgtbl_cfg->arm_lpae_s1_cfg.ttbr;
+   else
+   cb->ttbr[0] |= pgtbl_cfg->arm_lpae_s1_cfg.ttbr;
}
} else {
cb->ttbr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
@@ -822,7 +826,14 @@ static int arm_smmu_init_domain_context(struct 
iommu_domain *domain,
 
/* Update the domain's page sizes to reflect the page table format */
domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
-   domain->geometry.aperture_end = (1UL << ias) - 1;
+
+   if (pgtbl_cfg.quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) {
+   domain->geometry.aperture_start = ~0UL << ias;
+   domain->geometry.aperture_end = ~0UL;
+   } else {
+   domain->geometry.aperture_end = (1UL << ias) - 1;
+   }
+
domain->geometry.force_aperture = true;
 
/* Initialise the context bank with our page table cfg */
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h 
b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 83294516ac08..f3e456893f28 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -169,10 +169,12 @@ enum arm_smmu_cbar_type {
 #define ARM_SMMU_CB_TCR0x30
 #define ARM_SMMU_TCR_EAE   BIT(31)
 #define ARM_SMMU_TCR_EPD1  BIT(23)
+#define ARM_SMMU_TCR_A1BIT(22)
 #define ARM_SMMU_TCR_TG0   GENMASK(15, 14)
 #define ARM_SMMU_TCR_SH0   GENMASK(13, 12)
 #define ARM_SMMU_TCR_ORGN0 GENMASK(11, 10)
 #define ARM_SMMU_TCR_IRGN0 GENMASK(9, 8)
+#define ARM_SMMU_TCR_EPD0  BIT(7)
 #define ARM_SMMU_TCR_T0SZ  GENMASK(5, 0)
 
 #define ARM_SMMU_VTCR_RES1 BIT(31)
@@ -350,12 +352,23 @@ struct arm_smmu_domain {
 
 static inline u32 arm_smmu_lpae_tcr(struct io_pgtable_cfg *cfg)
 {
-   return ARM_SMMU_TCR_EPD1 |
-  FIELD_PREP(ARM_SMMU_TCR_TG0, cfg->arm_lpae_s1_cfg.tcr.tg) |
-  FIELD_PREP(ARM_SMMU_TCR_SH0, cfg->arm_lpae_s1_cfg.tcr.sh) |
-  FIELD_PREP(ARM_SMMU_TCR_ORGN0, cfg->arm_lpae_s1_cfg.tcr.orgn) |
-  FIELD_PREP(ARM_SMMU_TCR_IRGN0, cfg->arm_lpae_s1_cfg.tcr.irgn) |
-  FIELD_PREP(ARM_SMMU_TCR_T0SZ, cfg->arm_lpae_s1_cfg.tcr.tsz);
+   u32 tcr = FIELD_PREP(ARM_SMMU_TCR_TG0, cfg->arm_lpae_s1_cfg.tcr.tg) |
+   FIELD_PREP(ARM_SMMU_TCR_SH0, cfg->arm_lpae_s1_cfg.tcr.sh) |
+   FIELD_PREP(ARM_SMMU_TCR_ORGN0, cfg->arm_lpae_s1_cfg.tcr.orgn) |
+   FIELD_PREP(ARM_SMMU_TCR_IRGN0, cfg->arm_lpae_s1_cfg.tcr.irgn) |
+   FIELD_PREP(ARM_SMMU_TCR_T0SZ, cfg->arm_lpae_s1_cfg.tcr.tsz);
+
+   /*
+   * When TTBR1 is selected shift the TCR fields by 16 bits and disable
+   * translation in TTBR0
+   */
+   if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) {
+   tcr = (tcr << 16) & ~ARM_SMMU_TCR_A1;
+   tcr |= ARM_SMMU_TCR_EPD0;
+   } else
+   tcr |= ARM_SMMU_TCR_EPD1;
+
+   return tcr;
 }
 
 static inline u32 arm_smmu_lpae_tcr2(struct io_pgtable_cfg *cfg)
-- 
2.26.2

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


[PATCH v16 14/20] iommu/arm-smmu: Prepare for the adreno-smmu implementation

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Do a bit of prep work to add the upcoming adreno-smmu implementation.

Add an hook to allow the implementation to choose which context banks
to allocate.

Move some of the common structs to arm-smmu.h in anticipation of them
being used by the implementations and update some of the existing hooks
to pass more information that the implementation will need.

These modifications will be used by the upcoming Adreno SMMU
implementation to identify the GPU device and properly configure it
for pagetable switching.

Co-developed-by: Rob Clark 
Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
---
 drivers/iommu/arm/arm-smmu/arm-smmu-impl.c |  2 +-
 drivers/iommu/arm/arm-smmu/arm-smmu.c  | 69 ++
 drivers/iommu/arm/arm-smmu/arm-smmu.h  | 51 +++-
 3 files changed, 68 insertions(+), 54 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
index a9861dcd0884..88f17cc33023 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
@@ -69,7 +69,7 @@ static int cavium_cfg_probe(struct arm_smmu_device *smmu)
 }
 
 static int cavium_init_context(struct arm_smmu_domain *smmu_domain,
-   struct io_pgtable_cfg *pgtbl_cfg)
+   struct io_pgtable_cfg *pgtbl_cfg, struct device *dev)
 {
struct cavium_smmu *cs = container_of(smmu_domain->smmu,
  struct cavium_smmu, smmu);
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 8e884e58f208..68b7b9e6140e 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -65,41 +65,10 @@ module_param(disable_bypass, bool, S_IRUGO);
 MODULE_PARM_DESC(disable_bypass,
"Disable bypass streams such that incoming transactions from devices 
that are not attached to an iommu domain will report an abort back to the 
device and will not be allowed to pass through the SMMU.");
 
-struct arm_smmu_s2cr {
-   struct iommu_group  *group;
-   int count;
-   enum arm_smmu_s2cr_type type;
-   enum arm_smmu_s2cr_privcfg  privcfg;
-   u8  cbndx;
-};
-
 #define s2cr_init_val (struct arm_smmu_s2cr){  \
.type = disable_bypass ? S2CR_TYPE_FAULT : S2CR_TYPE_BYPASS,\
 }
 
-struct arm_smmu_smr {
-   u16 mask;
-   u16 id;
-   boolvalid;
-};
-
-struct arm_smmu_cb {
-   u64 ttbr[2];
-   u32 tcr[2];
-   u32 mair[2];
-   struct arm_smmu_cfg *cfg;
-};
-
-struct arm_smmu_master_cfg {
-   struct arm_smmu_device  *smmu;
-   s16 smendx[];
-};
-#define INVALID_SMENDX -1
-#define cfg_smendx(cfg, fw, i) \
-   (i >= fw->num_ids ? INVALID_SMENDX : cfg->smendx[i])
-#define for_each_cfg_sme(cfg, fw, i, idx) \
-   for (i = 0; idx = cfg_smendx(cfg, fw, i), i < fw->num_ids; ++i)
-
 static bool using_legacy_binding, using_generic_binding;
 
 static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
@@ -234,19 +203,6 @@ static int arm_smmu_register_legacy_master(struct device 
*dev,
 }
 #endif /* CONFIG_ARM_SMMU_LEGACY_DT_BINDINGS */
 
-static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
-{
-   int idx;
-
-   do {
-   idx = find_next_zero_bit(map, end, start);
-   if (idx == end)
-   return -ENOSPC;
-   } while (test_and_set_bit(idx, map));
-
-   return idx;
-}
-
 static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
 {
clear_bit(idx, map);
@@ -578,7 +534,7 @@ static void arm_smmu_init_context_bank(struct 
arm_smmu_domain *smmu_domain,
}
 }
 
-static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx)
+void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx)
 {
u32 reg;
bool stage1;
@@ -665,7 +621,8 @@ static void arm_smmu_write_context_bank(struct 
arm_smmu_device *smmu, int idx)
 }
 
 static int arm_smmu_init_domain_context(struct iommu_domain *domain,
-   struct arm_smmu_device *smmu)
+   struct arm_smmu_device *smmu,
+   struct device *dev)
 {
int irq, start, ret = 0;
unsigned long ias, oas;
@@ -780,10 +737,20 @@ static int arm_smmu_init_domain_context(struct 
iommu_domain *domain,
ret = -EINVAL;
goto out_unlock;
}
-   ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
+
+   smmu_domain->smmu = smmu;
+
+   if (smmu->impl && smmu->impl->alloc_context_bank)
+ 

[PATCH v16 15/20] iommu/arm-smmu: Constify some helpers

2020-09-01 Thread Rob Clark
From: Rob Clark 

Sprinkle a few `const`s where helpers don't need write access.

Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/iommu/arm/arm-smmu/arm-smmu.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h 
b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 59ff3fc5c6c8..27c8fc50 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -377,7 +377,7 @@ struct arm_smmu_master_cfg {
s16 smendx[];
 };
 
-static inline u32 arm_smmu_lpae_tcr(struct io_pgtable_cfg *cfg)
+static inline u32 arm_smmu_lpae_tcr(const struct io_pgtable_cfg *cfg)
 {
u32 tcr = FIELD_PREP(ARM_SMMU_TCR_TG0, cfg->arm_lpae_s1_cfg.tcr.tg) |
FIELD_PREP(ARM_SMMU_TCR_SH0, cfg->arm_lpae_s1_cfg.tcr.sh) |
@@ -398,13 +398,13 @@ static inline u32 arm_smmu_lpae_tcr(struct io_pgtable_cfg 
*cfg)
return tcr;
 }
 
-static inline u32 arm_smmu_lpae_tcr2(struct io_pgtable_cfg *cfg)
+static inline u32 arm_smmu_lpae_tcr2(const struct io_pgtable_cfg *cfg)
 {
return FIELD_PREP(ARM_SMMU_TCR2_PASIZE, cfg->arm_lpae_s1_cfg.tcr.ips) |
   FIELD_PREP(ARM_SMMU_TCR2_SEP, ARM_SMMU_TCR2_SEP_UPSTREAM);
 }
 
-static inline u32 arm_smmu_lpae_vtcr(struct io_pgtable_cfg *cfg)
+static inline u32 arm_smmu_lpae_vtcr(const struct io_pgtable_cfg *cfg)
 {
return ARM_SMMU_VTCR_RES1 |
   FIELD_PREP(ARM_SMMU_VTCR_PS, cfg->arm_lpae_s2_cfg.vtcr.ps) |
-- 
2.26.2

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


[PATCH v16 12/20] iommu/arm-smmu: Pass io-pgtable config to implementation specific function

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Construct the io-pgtable config before calling the implementation specific
init_context function and pass it so the implementation specific function
can get a chance to change it before the io-pgtable is created.

Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/iommu/arm/arm-smmu/arm-smmu-impl.c |  3 ++-
 drivers/iommu/arm/arm-smmu/arm-smmu.c  | 11 ++-
 drivers/iommu/arm/arm-smmu/arm-smmu.h  |  3 ++-
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
index f4ff124a1967..a9861dcd0884 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
@@ -68,7 +68,8 @@ static int cavium_cfg_probe(struct arm_smmu_device *smmu)
return 0;
 }
 
-static int cavium_init_context(struct arm_smmu_domain *smmu_domain)
+static int cavium_init_context(struct arm_smmu_domain *smmu_domain,
+   struct io_pgtable_cfg *pgtbl_cfg)
 {
struct cavium_smmu *cs = container_of(smmu_domain->smmu,
  struct cavium_smmu, smmu);
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c 
b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 09c42af9f31e..37d8d49299b4 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -795,11 +795,6 @@ static int arm_smmu_init_domain_context(struct 
iommu_domain *domain,
cfg->asid = cfg->cbndx;
 
smmu_domain->smmu = smmu;
-   if (smmu->impl && smmu->impl->init_context) {
-   ret = smmu->impl->init_context(smmu_domain);
-   if (ret)
-   goto out_unlock;
-   }
 
pgtbl_cfg = (struct io_pgtable_cfg) {
.pgsize_bitmap  = smmu->pgsize_bitmap,
@@ -810,6 +805,12 @@ static int arm_smmu_init_domain_context(struct 
iommu_domain *domain,
.iommu_dev  = smmu->dev,
};
 
+   if (smmu->impl && smmu->impl->init_context) {
+   ret = smmu->impl->init_context(smmu_domain, _cfg);
+   if (ret)
+   goto out_clear_smmu;
+   }
+
if (smmu_domain->non_strict)
pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
 
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h 
b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index d890a4a968e8..83294516ac08 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -386,7 +386,8 @@ struct arm_smmu_impl {
u64 val);
int (*cfg_probe)(struct arm_smmu_device *smmu);
int (*reset)(struct arm_smmu_device *smmu);
-   int (*init_context)(struct arm_smmu_domain *smmu_domain);
+   int (*init_context)(struct arm_smmu_domain *smmu_domain,
+   struct io_pgtable_cfg *cfg);
void (*tlb_sync)(struct arm_smmu_device *smmu, int page, int sync,
 int status);
int (*def_domain_type)(struct device *dev);
-- 
2.26.2

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


[PATCH v16 09/20] drm/msm: Add support for private address space instances

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Add support for allocating private address space instances. Targets that
support per-context pagetables should implement their own function to
allocate private address spaces.

The default will return a pointer to the global address space.

Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/msm_drv.c | 13 +++--
 drivers/gpu/drm/msm/msm_drv.h |  5 +
 drivers/gpu/drm/msm/msm_gem_vma.c |  9 +
 drivers/gpu/drm/msm/msm_gpu.c | 22 ++
 drivers/gpu/drm/msm/msm_gpu.h |  5 +
 5 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 75cd7639f560..7e963f707852 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -597,7 +597,7 @@ static int context_init(struct drm_device *dev, struct 
drm_file *file)
kref_init(>ref);
msm_submitqueue_init(dev, ctx);
 
-   ctx->aspace = priv->gpu ? priv->gpu->aspace : NULL;
+   ctx->aspace = msm_gpu_create_private_address_space(priv->gpu);
file->driver_priv = ctx;
 
return 0;
@@ -780,18 +780,19 @@ static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, 
void *data,
 }
 
 static int msm_ioctl_gem_info_iova(struct drm_device *dev,
-   struct drm_gem_object *obj, uint64_t *iova)
+   struct drm_file *file, struct drm_gem_object *obj,
+   uint64_t *iova)
 {
-   struct msm_drm_private *priv = dev->dev_private;
+   struct msm_file_private *ctx = file->driver_priv;
 
-   if (!priv->gpu)
+   if (!ctx->aspace)
return -EINVAL;
 
/*
 * Don't pin the memory here - just get an address so that userspace can
 * be productive
 */
-   return msm_gem_get_iova(obj, priv->gpu->aspace, iova);
+   return msm_gem_get_iova(obj, ctx->aspace, iova);
 }
 
 static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
@@ -830,7 +831,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void 
*data,
args->value = msm_gem_mmap_offset(obj);
break;
case MSM_INFO_GET_IOVA:
-   ret = msm_ioctl_gem_info_iova(dev, obj, >value);
+   ret = msm_ioctl_gem_info_iova(dev, file, obj, >value);
break;
case MSM_INFO_SET_NAME:
/* length check should leave room for terminating null: */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 4561bfb5e745..2ca9c3c03845 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -249,6 +249,10 @@ int msm_gem_map_vma(struct msm_gem_address_space *aspace,
 void msm_gem_close_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma);
 
+
+struct msm_gem_address_space *
+msm_gem_address_space_get(struct msm_gem_address_space *aspace);
+
 void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
 
 struct msm_gem_address_space *
@@ -434,6 +438,7 @@ static inline void __msm_file_private_destroy(struct kref 
*kref)
struct msm_file_private *ctx = container_of(kref,
struct msm_file_private, ref);
 
+   msm_gem_address_space_put(ctx->aspace);
kfree(ctx);
 }
 
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c 
b/drivers/gpu/drm/msm/msm_gem_vma.c
index 5f6a11211b64..29cc1305cf37 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -27,6 +27,15 @@ void msm_gem_address_space_put(struct msm_gem_address_space 
*aspace)
kref_put(>kref, msm_gem_address_space_destroy);
 }
 
+struct msm_gem_address_space *
+msm_gem_address_space_get(struct msm_gem_address_space *aspace)
+{
+   if (!IS_ERR_OR_NULL(aspace))
+   kref_get(>kref);
+
+   return aspace;
+}
+
 /* Actually unmap memory for the vma */
 void msm_gem_purge_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index e1a3cbe25a0c..951850804d77 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -823,6 +823,28 @@ static int get_clocks(struct platform_device *pdev, struct 
msm_gpu *gpu)
return 0;
 }
 
+/* Return a new address space for a msm_drm_private instance */
+struct msm_gem_address_space *
+msm_gpu_create_private_address_space(struct msm_gpu *gpu)
+{
+   struct msm_gem_address_space *aspace = NULL;
+
+   if (!gpu)
+   return NULL;
+
+   /*
+* If the target doesn't support private address spaces then return
+* the global one
+*/
+   if (gpu->funcs->create_private_address_space)
+   aspace = gpu->funcs->create_private_address_space(gpu);
+
+   if (IS_ERR_OR_NULL(aspace))
+   aspace = msm_gem_address_space_get(gpu->aspace);
+
+   return aspace;

[PATCH v16 03/20] drm/msm/gpu: Add dev_to_gpu() helper

2020-09-01 Thread Rob Clark
From: Rob Clark 

In a later patch, the drvdata will not directly be 'struct msm_gpu *',
so add a helper to reduce the churn.

Signed-off-by: Rob Clark 
Reviewed-by: Jordan Crouse 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/adreno/adreno_device.c | 10 --
 drivers/gpu/drm/msm/msm_gpu.c  |  6 +++---
 drivers/gpu/drm/msm/msm_gpu.h  |  5 +
 3 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c 
b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 9eeb46bf2a5d..26664e1b30c0 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -282,7 +282,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
int ret;
 
if (pdev)
-   gpu = platform_get_drvdata(pdev);
+   gpu = dev_to_gpu(>dev);
 
if (!gpu) {
dev_err_once(dev->dev, "no GPU device was found\n");
@@ -425,7 +425,7 @@ static int adreno_bind(struct device *dev, struct device 
*master, void *data)
 static void adreno_unbind(struct device *dev, struct device *master,
void *data)
 {
-   struct msm_gpu *gpu = dev_get_drvdata(dev);
+   struct msm_gpu *gpu = dev_to_gpu(dev);
 
pm_runtime_force_suspend(dev);
gpu->funcs->destroy(gpu);
@@ -490,16 +490,14 @@ static const struct of_device_id dt_match[] = {
 #ifdef CONFIG_PM
 static int adreno_resume(struct device *dev)
 {
-   struct platform_device *pdev = to_platform_device(dev);
-   struct msm_gpu *gpu = platform_get_drvdata(pdev);
+   struct msm_gpu *gpu = dev_to_gpu(dev);
 
return gpu->funcs->pm_resume(gpu);
 }
 
 static int adreno_suspend(struct device *dev)
 {
-   struct platform_device *pdev = to_platform_device(dev);
-   struct msm_gpu *gpu = platform_get_drvdata(pdev);
+   struct msm_gpu *gpu = dev_to_gpu(dev);
 
return gpu->funcs->pm_suspend(gpu);
 }
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index d5645472b25d..6aa9e04e52e7 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -24,7 +24,7 @@
 static int msm_devfreq_target(struct device *dev, unsigned long *freq,
u32 flags)
 {
-   struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
+   struct msm_gpu *gpu = dev_to_gpu(dev);
struct dev_pm_opp *opp;
 
opp = devfreq_recommended_opp(dev, freq, flags);
@@ -45,7 +45,7 @@ static int msm_devfreq_target(struct device *dev, unsigned 
long *freq,
 static int msm_devfreq_get_dev_status(struct device *dev,
struct devfreq_dev_status *status)
 {
-   struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
+   struct msm_gpu *gpu = dev_to_gpu(dev);
ktime_t time;
 
if (gpu->funcs->gpu_get_freq)
@@ -64,7 +64,7 @@ static int msm_devfreq_get_dev_status(struct device *dev,
 
 static int msm_devfreq_get_cur_freq(struct device *dev, unsigned long *freq)
 {
-   struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
+   struct msm_gpu *gpu = dev_to_gpu(dev);
 
if (gpu->funcs->gpu_get_freq)
*freq = gpu->funcs->gpu_get_freq(gpu);
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 0db117a7339b..8bda7beaed4b 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -141,6 +141,11 @@ struct msm_gpu {
struct msm_gpu_state *crashstate;
 };
 
+static inline struct msm_gpu *dev_to_gpu(struct device *dev)
+{
+   return dev_get_drvdata(dev);
+}
+
 /* It turns out that all targets use the same ringbuffer size */
 #define MSM_GPU_RINGBUFFER_SZ SZ_32K
 #define MSM_GPU_RINGBUFFER_BLKSIZE 32
-- 
2.26.2

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


[PATCH v16 02/20] drm/msm: Add private interface for adreno-smmu

2020-09-01 Thread Rob Clark
From: Rob Clark 

This interface will be used for drm/msm to coordinate with the
qcom_adreno_smmu_impl to enable/disable TTBR0 translation.

Once TTBR0 translation is enabled, the GPU's CP (Command Processor)
will directly switch TTBR0 pgtables (and do the necessary TLB inv)
synchronized to the GPU's operation.  But help from the SMMU driver
is needed to initially bootstrap TTBR0 translation, which cannot be
done from the GPU.

Since this is a very special case, a private interface is used to
avoid adding highly driver specific things to the public iommu
interface.

Signed-off-by: Rob Clark 
Reviewed-by: Jordan Crouse 
Reviewed-by: Bjorn Andersson 
---
 include/linux/adreno-smmu-priv.h | 36 
 1 file changed, 36 insertions(+)
 create mode 100644 include/linux/adreno-smmu-priv.h

diff --git a/include/linux/adreno-smmu-priv.h b/include/linux/adreno-smmu-priv.h
new file mode 100644
index ..a889f28afb42
--- /dev/null
+++ b/include/linux/adreno-smmu-priv.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 Google, Inc
+ */
+
+#ifndef __ADRENO_SMMU_PRIV_H
+#define __ADRENO_SMMU_PRIV_H
+
+#include 
+
+/**
+ * struct adreno_smmu_priv - private interface between adreno-smmu and GPU
+ *
+ * @cookie:An opque token provided by adreno-smmu and passed
+ * back into the callbacks
+ * @get_ttbr1_cfg: Get the TTBR1 config for the GPUs context-bank
+ * @set_ttbr0_cfg: Set the TTBR0 config for the GPUs context bank.  A
+ * NULL config disables TTBR0 translation, otherwise
+ * TTBR0 translation is enabled with the specified cfg
+ *
+ * The GPU driver (drm/msm) and adreno-smmu work together for controlling
+ * the GPU's SMMU instance.  This is by necessity, as the GPU is directly
+ * updating the SMMU for context switches, while on the other hand we do
+ * not want to duplicate all of the initial setup logic from arm-smmu.
+ *
+ * This private interface is used for the two drivers to coordinate.  The
+ * cookie and callback functions are populated when the GPU driver attaches
+ * it's domain.
+ */
+struct adreno_smmu_priv {
+const void *cookie;
+const struct io_pgtable_cfg *(*get_ttbr1_cfg)(const void *cookie);
+int (*set_ttbr0_cfg)(const void *cookie, const struct io_pgtable_cfg *cfg);
+};
+
+#endif /* __ADRENO_SMMU_PRIV_H */
\ No newline at end of file
-- 
2.26.2

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


[PATCH v16 04/20] drm/msm: Set adreno_smmu as gpu's drvdata

2020-09-01 Thread Rob Clark
From: Rob Clark 

This will be populated by adreno-smmu, to provide a way for coordinating
enabling/disabling TTBR0 translation.

Signed-off-by: Rob Clark 
Reviewed-by: Jordan Crouse 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/adreno/adreno_device.c | 2 --
 drivers/gpu/drm/msm/msm_gpu.c  | 2 +-
 drivers/gpu/drm/msm/msm_gpu.h  | 6 +-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c 
b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 26664e1b30c0..58e03b20e1c7 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -417,8 +417,6 @@ static int adreno_bind(struct device *dev, struct device 
*master, void *data)
return PTR_ERR(gpu);
}
 
-   dev_set_drvdata(dev, gpu);
-
return 0;
 }
 
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 6aa9e04e52e7..806eb0957280 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -892,7 +892,7 @@ int msm_gpu_init(struct drm_device *drm, struct 
platform_device *pdev,
gpu->gpu_cx = NULL;
 
gpu->pdev = pdev;
-   platform_set_drvdata(pdev, gpu);
+   platform_set_drvdata(pdev, >adreno_smmu);
 
msm_devfreq_init(gpu);
 
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 8bda7beaed4b..f91b141add75 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -7,6 +7,7 @@
 #ifndef __MSM_GPU_H__
 #define __MSM_GPU_H__
 
+#include 
 #include 
 #include 
 #include 
@@ -73,6 +74,8 @@ struct msm_gpu {
struct platform_device *pdev;
const struct msm_gpu_funcs *funcs;
 
+   struct adreno_smmu_priv adreno_smmu;
+
/* performance counters (hw & sw): */
spinlock_t perf_lock;
bool perfcntr_active;
@@ -143,7 +146,8 @@ struct msm_gpu {
 
 static inline struct msm_gpu *dev_to_gpu(struct device *dev)
 {
-   return dev_get_drvdata(dev);
+   struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(dev);
+   return container_of(adreno_smmu, struct msm_gpu, adreno_smmu);
 }
 
 /* It turns out that all targets use the same ringbuffer size */
-- 
2.26.2

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


[PATCH v16 07/20] drm/msm: Set the global virtual address range from the IOMMU domain

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Use the aperture settings from the IOMMU domain to set up the virtual
address range for the GPU. This allows us to transparently deal with
IOMMU side features (like split pagetables).

Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/adreno/adreno_gpu.c | 13 +++--
 drivers/gpu/drm/msm/msm_iommu.c |  7 +++
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 533a34b4cce2..34e6242c1767 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -192,9 +192,18 @@ adreno_iommu_create_address_space(struct msm_gpu *gpu,
struct iommu_domain *iommu = iommu_domain_alloc(_bus_type);
struct msm_mmu *mmu = msm_iommu_new(>dev, iommu);
struct msm_gem_address_space *aspace;
+   u64 start, size;
 
-   aspace = msm_gem_address_space_create(mmu, "gpu", SZ_16M,
-   0x - SZ_16M);
+   /*
+* Use the aperture start or SZ_16M, whichever is greater. This will
+* ensure that we align with the allocated pagetable range while still
+* allowing room in the lower 32 bits for GMEM and whatnot
+*/
+   start = max_t(u64, SZ_16M, iommu->geometry.aperture_start);
+   size = iommu->geometry.aperture_end - start + 1;
+
+   aspace = msm_gem_address_space_create(mmu, "gpu",
+   start & GENMASK(48, 0), size);
 
if (IS_ERR(aspace) && !IS_ERR(mmu))
mmu->funcs->destroy(mmu);
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 3a381a9674c9..1b6635504069 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -36,6 +36,10 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
struct msm_iommu *iommu = to_msm_iommu(mmu);
size_t ret;
 
+   /* The arm-smmu driver expects the addresses to be sign extended */
+   if (iova & BIT_ULL(48))
+   iova |= GENMASK_ULL(63, 49);
+
ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot);
WARN_ON(!ret);
 
@@ -46,6 +50,9 @@ static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t 
iova, size_t len)
 {
struct msm_iommu *iommu = to_msm_iommu(mmu);
 
+   if (iova & BIT_ULL(48))
+   iova |= GENMASK_ULL(63, 49);
+
iommu_unmap(iommu->domain, iova, len);
 
return 0;
-- 
2.26.2

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


[PATCH v16 08/20] drm/msm: Add support to create a local pagetable

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Add support to create a io-pgtable for use by targets that support
per-instance pagetables. In order to support per-instance pagetables the
GPU SMMU device needs to have the qcom,adreno-smmu compatible string and
split pagetables enabled.

Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/Kconfig  |   1 +
 drivers/gpu/drm/msm/msm_gpummu.c |   2 +-
 drivers/gpu/drm/msm/msm_iommu.c  | 199 ++-
 drivers/gpu/drm/msm/msm_mmu.h|  16 ++-
 4 files changed, 215 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 6deaa7d01654..5102a58830b9 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -8,6 +8,7 @@ config DRM_MSM
depends on MMU
depends on INTERCONNECT || !INTERCONNECT
depends on QCOM_OCMEM || QCOM_OCMEM=n
+   select IOMMU_IO_PGTABLE
select QCOM_MDT_LOADER if ARCH_QCOM
select REGULATOR
select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
index 310a31b05faa..aab121f4beb7 100644
--- a/drivers/gpu/drm/msm/msm_gpummu.c
+++ b/drivers/gpu/drm/msm/msm_gpummu.c
@@ -102,7 +102,7 @@ struct msm_mmu *msm_gpummu_new(struct device *dev, struct 
msm_gpu *gpu)
}
 
gpummu->gpu = gpu;
-   msm_mmu_init(>base, dev, );
+   msm_mmu_init(>base, dev, , MSM_MMU_GPUMMU);
 
return >base;
 }
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 1b6635504069..697cc0a059d6 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -4,15 +4,210 @@
  * Author: Rob Clark 
  */
 
+#include 
+#include 
 #include "msm_drv.h"
 #include "msm_mmu.h"
 
 struct msm_iommu {
struct msm_mmu base;
struct iommu_domain *domain;
+   atomic_t pagetables;
 };
+
 #define to_msm_iommu(x) container_of(x, struct msm_iommu, base)
 
+struct msm_iommu_pagetable {
+   struct msm_mmu base;
+   struct msm_mmu *parent;
+   struct io_pgtable_ops *pgtbl_ops;
+   phys_addr_t ttbr;
+   u32 asid;
+};
+static struct msm_iommu_pagetable *to_pagetable(struct msm_mmu *mmu)
+{
+   return container_of(mmu, struct msm_iommu_pagetable, base);
+}
+
+static int msm_iommu_pagetable_unmap(struct msm_mmu *mmu, u64 iova,
+   size_t size)
+{
+   struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
+   struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
+   size_t unmapped = 0;
+
+   /* Unmap the block one page at a time */
+   while (size) {
+   unmapped += ops->unmap(ops, iova, 4096, NULL);
+   iova += 4096;
+   size -= 4096;
+   }
+
+   iommu_flush_tlb_all(to_msm_iommu(pagetable->parent)->domain);
+
+   return (unmapped == size) ? 0 : -EINVAL;
+}
+
+static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova,
+   struct sg_table *sgt, size_t len, int prot)
+{
+   struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
+   struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
+   struct scatterlist *sg;
+   size_t mapped = 0;
+   u64 addr = iova;
+   unsigned int i;
+
+   for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+   size_t size = sg->length;
+   phys_addr_t phys = sg_phys(sg);
+
+   /* Map the block one page at a time */
+   while (size) {
+   if (ops->map(ops, addr, phys, 4096, prot, GFP_KERNEL)) {
+   msm_iommu_pagetable_unmap(mmu, iova, mapped);
+   return -EINVAL;
+   }
+
+   phys += 4096;
+   addr += 4096;
+   size -= 4096;
+   mapped += 4096;
+   }
+   }
+
+   return 0;
+}
+
+static void msm_iommu_pagetable_destroy(struct msm_mmu *mmu)
+{
+   struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
+   struct msm_iommu *iommu = to_msm_iommu(pagetable->parent);
+   struct adreno_smmu_priv *adreno_smmu =
+   dev_get_drvdata(pagetable->parent->dev);
+
+   /*
+* If this is the last attached pagetable for the parent,
+* disable TTBR0 in the arm-smmu driver
+*/
+   if (atomic_dec_return(>pagetables) == 0)
+   adreno_smmu->set_ttbr0_cfg(adreno_smmu->cookie, NULL);
+
+   free_io_pgtable_ops(pagetable->pgtbl_ops);
+   kfree(pagetable);
+}
+
+int msm_iommu_pagetable_params(struct msm_mmu *mmu,
+   phys_addr_t *ttbr, int *asid)
+{
+   struct msm_iommu_pagetable *pagetable;
+
+   if (mmu->type != MSM_MMU_IOMMU_PAGETABLE)
+   return -EINVAL;
+
+   pagetable = to_pagetable(mmu);
+
+   if (ttbr)
+   *ttbr = pagetable->ttbr;
+
+   if (asid)
+   *asid = 

[PATCH v16 05/20] drm/msm: Add a context pointer to the submitqueue

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Each submitqueue is attached to a context. Add a pointer to the
context to the submitqueue at create time and refcount it so
that it stays around through the life of the queue.

Co-developed-by: Rob Clark 
Signed-off-by: Jordan Crouse 
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/msm_drv.c |  3 ++-
 drivers/gpu/drm/msm/msm_drv.h | 20 
 drivers/gpu/drm/msm/msm_gem.h |  1 +
 drivers/gpu/drm/msm/msm_gem_submit.c  |  6 +++---
 drivers/gpu/drm/msm/msm_gpu.h |  1 +
 drivers/gpu/drm/msm/msm_submitqueue.c |  3 +++
 6 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 79333842f70a..75cd7639f560 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -594,6 +594,7 @@ static int context_init(struct drm_device *dev, struct 
drm_file *file)
if (!ctx)
return -ENOMEM;
 
+   kref_init(>ref);
msm_submitqueue_init(dev, ctx);
 
ctx->aspace = priv->gpu ? priv->gpu->aspace : NULL;
@@ -615,7 +616,7 @@ static int msm_open(struct drm_device *dev, struct drm_file 
*file)
 static void context_close(struct msm_file_private *ctx)
 {
msm_submitqueue_close(ctx);
-   kfree(ctx);
+   msm_file_private_put(ctx);
 }
 
 static void msm_postclose(struct drm_device *dev, struct drm_file *file)
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index af259b0573ea..4561bfb5e745 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -57,6 +57,7 @@ struct msm_file_private {
struct list_head submitqueues;
int queueid;
struct msm_gem_address_space *aspace;
+   struct kref ref;
 };
 
 enum msm_mdp_plane_property {
@@ -428,6 +429,25 @@ void msm_submitqueue_close(struct msm_file_private *ctx);
 
 void msm_submitqueue_destroy(struct kref *kref);
 
+static inline void __msm_file_private_destroy(struct kref *kref)
+{
+   struct msm_file_private *ctx = container_of(kref,
+   struct msm_file_private, ref);
+
+   kfree(ctx);
+}
+
+static inline void msm_file_private_put(struct msm_file_private *ctx)
+{
+   kref_put(>ref, __msm_file_private_destroy);
+}
+
+static inline struct msm_file_private *msm_file_private_get(
+   struct msm_file_private *ctx)
+{
+   kref_get(>ref);
+   return ctx;
+}
 
 #define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)
 #define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 972490b14ba5..9c573c4269cb 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -142,6 +142,7 @@ struct msm_gem_submit {
bool valid; /* true if no cmdstream patching needed */
bool in_rb; /* "sudo" mode, copy cmds into RB */
struct msm_ringbuffer *ring;
+   struct msm_file_private *ctx;
unsigned int nr_cmds;
unsigned int nr_bos;
u32 ident; /* A "identifier" for the submit for logging */
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c 
b/drivers/gpu/drm/msm/msm_gem_submit.c
index 8cb9aa15ff90..1464b04d25d3 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -27,7 +27,7 @@
 #define BO_PINNED   0x2000
 
 static struct msm_gem_submit *submit_create(struct drm_device *dev,
-   struct msm_gpu *gpu, struct msm_gem_address_space *aspace,
+   struct msm_gpu *gpu,
struct msm_gpu_submitqueue *queue, uint32_t nr_bos,
uint32_t nr_cmds)
 {
@@ -43,7 +43,7 @@ static struct msm_gem_submit *submit_create(struct drm_device 
*dev,
return NULL;
 
submit->dev = dev;
-   submit->aspace = aspace;
+   submit->aspace = queue->ctx->aspace;
submit->gpu = gpu;
submit->fence = NULL;
submit->cmd = (void *)>bos[nr_bos];
@@ -677,7 +677,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
}
}
 
-   submit = submit_create(dev, gpu, ctx->aspace, queue, args->nr_bos,
+   submit = submit_create(dev, gpu, queue, args->nr_bos,
args->nr_cmds);
if (!submit) {
ret = -ENOMEM;
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index f91b141add75..97c527e98391 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -190,6 +190,7 @@ struct msm_gpu_submitqueue {
u32 flags;
u32 prio;
int faults;
+   struct msm_file_private *ctx;
struct list_head node;
struct kref ref;
 };
diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c 
b/drivers/gpu/drm/msm/msm_submitqueue.c
index 90c9d84e6155..c3d206105d28 100644
--- a/drivers/gpu/drm/msm/msm_submitqueue.c
+++ b/drivers/gpu/drm/msm/msm_submitqueue.c

[PATCH v16 00/20] iommu/arm-smmu + drm/msm: per-process GPU pgtables

2020-09-01 Thread Rob Clark
From: Rob Clark 

NOTE: I have re-ordered the series, and propose that we could merge this
  series in the following order:

   1) 01-11 - merge via drm / msm-next
   2) 12-15 - merge via iommu, no dependency on msm-next pull req
   3) 16-18 - patch 16 has a dependency on 02 and 04, so it would
  need to come post -rc1 or on following cycle, but I
  think it would be unlikely to conflict with other
  arm-smmu patches (other than Bjorn's smmu handover
  series?)
   4) 19-20 - dt bits should be safe to land in any order without
  breaking anything



This series adds an Adreno SMMU implementation to arm-smmu to allow GPU hardware
pagetable switching.

The Adreno GPU has built in capabilities to switch the TTBR0 pagetable during
runtime to allow each individual instance or application to have its own
pagetable.  In order to take advantage of the HW capabilities there are certain
requirements needed of the SMMU hardware.

This series adds support for an Adreno specific arm-smmu implementation. The new
implementation 1) ensures that the GPU domain is always assigned context bank 0,
2) enables split pagetable support (TTBR1) so that the instance specific
pagetable can be swapped while the global memory remains in place and 3) shares
the current pagetable configuration with the GPU driver to allow it to create
its own io-pgtable instances.

The series then adds the drm/msm code to enable these features. For targets that
support it allocate new pagetables using the io-pgtable configuration shared by
the arm-smmu driver and swap them in during runtime.

This version of the series merges the previous patchset(s) [1] and [2]
with the following improvements:

v16: (Respin by Rob)
  - Fix indentation
  - Re-order series to split drm and iommu parts
v15: (Respin by Rob)
  - Adjust dt bindings to keep SoC specific compatible (Doug)
  - Add dts workaround for cheza fw limitation
  - Add missing 'select IOMMU_IO_PGTABLE' (Guenter)
v14: (Respin by Rob)
  - Minor update to 16/20 (only force ASID to zero in one place)
  - Addition of sc7180 dtsi patch.
v13: (Respin by Rob)
  - Switch to a private interface between adreno-smmu and GPU driver,
dropping the custom domain attr (Will Deacon)
  - Rework the SCTLR.HUPCF patch to add new fields in smmu_domain->cfg
rather than adding new impl hook (Will Deacon)
  - Drop for_each_cfg_sme() in favor of plain for() loop (Will Deacon)
  - Fix context refcnt'ing issue which was causing problems with GPU
crash recover stress testing.
  - Spiff up $debugfs/gem to show process information associated with
VMAs
v12:
  - Nitpick cleanups in gpu/drm/msm/msm_iommu.c (Rob Clark)
  - Reorg in gpu/drm/msm/msm_gpu.c (Rob Clark)
  - Use the default asid for the context bank so that iommu_tlb_flush_all works
  - Flush the UCHE after a page switch
  - Add the SCTLR.HUPCF patch at the end of the series
v11:
  - Add implementation specific get_attr/set_attr functions (per Rob Clark)
  - Fix context bank allocation (per Bjorn Andersson)
v10:
  - arm-smmu: add implementation hook to allocate context banks
  - arm-smmu: Match the GPU domain by stream ID instead of compatible string
  - arm-smmu: Make DOMAIN_ATTR_PGTABLE_CFG bi-directional. The leaf driver
queries the configuration to create a pagetable and then sends the newly
created configuration back to the smmu-driver to enable TTBR0
  - drm/msm: Add context reference counting for submissions
  - drm/msm: Use dummy functions to skip TLB operations on per-instance
pagetables

[1] https://lists.linuxfoundation.org/pipermail/iommu/2020-June/045653.html
[2] https://lists.linuxfoundation.org/pipermail/iommu/2020-June/045659.html

Jordan Crouse (12):
  drm/msm: Add a context pointer to the submitqueue
  drm/msm: Drop context arg to gpu->submit()
  drm/msm: Set the global virtual address range from the IOMMU domain
  drm/msm: Add support to create a local pagetable
  drm/msm: Add support for private address space instances
  drm/msm/a6xx: Add support for per-instance pagetables
  iommu/arm-smmu: Pass io-pgtable config to implementation specific
function
  iommu/arm-smmu: Add support for split pagetables
  iommu/arm-smmu: Prepare for the adreno-smmu implementation
  iommu/arm-smmu-qcom: Add implementation for the adreno GPU SMMU
  dt-bindings: arm-smmu: Add compatible string for Adreno GPU SMMU
  arm: dts: qcom: sm845: Set the compatible string for the GPU SMMU

Rob Clark (8):
  drm/msm: Remove dangling submitqueue references
  drm/msm: Add private interface for adreno-smmu
  drm/msm/gpu: Add dev_to_gpu() helper
  drm/msm: Set adreno_smmu as gpu's drvdata
  drm/msm: Show process names in gem_describe
  iommu/arm-smmu: Constify some helpers
  iommu/arm-smmu: Add a way for implementations to influence SCTLR
  arm: dts: qcom: sc7180: Set the compatible string for the GPU SMMU

 .../devicetree/bindings/iommu/arm,smmu.yaml   |   9 +-

[PATCH v16 01/20] drm/msm: Remove dangling submitqueue references

2020-09-01 Thread Rob Clark
From: Rob Clark 

Currently it doesn't matter, since we free the ctx immediately.  But
when we start refcnt'ing the ctx, we don't want old dangling list
entries to hang around.

Signed-off-by: Rob Clark 
Reviewed-by: Jordan Crouse 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/msm_submitqueue.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c 
b/drivers/gpu/drm/msm/msm_submitqueue.c
index a1d94be7883a..90c9d84e6155 100644
--- a/drivers/gpu/drm/msm/msm_submitqueue.c
+++ b/drivers/gpu/drm/msm/msm_submitqueue.c
@@ -49,8 +49,10 @@ void msm_submitqueue_close(struct msm_file_private *ctx)
 * No lock needed in close and there won't
 * be any more user ioctls coming our way
 */
-   list_for_each_entry_safe(entry, tmp, >submitqueues, node)
+   list_for_each_entry_safe(entry, tmp, >submitqueues, node) {
+   list_del(>node);
msm_submitqueue_put(entry);
+   }
 }
 
 int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private 
*ctx,
-- 
2.26.2

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


[PATCH v16 06/20] drm/msm: Drop context arg to gpu->submit()

2020-09-01 Thread Rob Clark
From: Jordan Crouse 

Now that we can get the ctx from the submitqueue, the extra arg is
redundant.

Signed-off-by: Jordan Crouse 
[split out of previous patch to reduce churny noise]
Signed-off-by: Rob Clark 
Reviewed-by: Bjorn Andersson 
---
 drivers/gpu/drm/msm/adreno/a5xx_gpu.c   | 12 +---
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c   |  5 ++---
 drivers/gpu/drm/msm/adreno/adreno_gpu.c |  5 ++---
 drivers/gpu/drm/msm/adreno/adreno_gpu.h |  3 +--
 drivers/gpu/drm/msm/msm_gem_submit.c|  2 +-
 drivers/gpu/drm/msm/msm_gpu.c   |  9 -
 drivers/gpu/drm/msm/msm_gpu.h   |  6 ++
 7 files changed, 17 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c 
b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 9e63a190642c..eff2439ea57b 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -43,8 +43,7 @@ static void a5xx_flush(struct msm_gpu *gpu, struct 
msm_ringbuffer *ring)
gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr);
 }
 
-static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit 
*submit,
-   struct msm_file_private *ctx)
+static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit 
*submit)
 {
struct msm_drm_private *priv = gpu->dev->dev_private;
struct msm_ringbuffer *ring = submit->ring;
@@ -57,7 +56,7 @@ static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct 
msm_gem_submit *submit
case MSM_SUBMIT_CMD_IB_TARGET_BUF:
break;
case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
-   if (priv->lastctx == ctx)
+   if (priv->lastctx == submit->queue->ctx)
break;
/* fall-thru */
case MSM_SUBMIT_CMD_BUF:
@@ -103,8 +102,7 @@ static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct 
msm_gem_submit *submit
msm_gpu_retire(gpu);
 }
 
-static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
-   struct msm_file_private *ctx)
+static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
 {
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
@@ -114,7 +112,7 @@ static void a5xx_submit(struct msm_gpu *gpu, struct 
msm_gem_submit *submit,
 
if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) {
priv->lastctx = NULL;
-   a5xx_submit_in_rb(gpu, submit, ctx);
+   a5xx_submit_in_rb(gpu, submit);
return;
}
 
@@ -148,7 +146,7 @@ static void a5xx_submit(struct msm_gpu *gpu, struct 
msm_gem_submit *submit,
case MSM_SUBMIT_CMD_IB_TARGET_BUF:
break;
case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
-   if (priv->lastctx == ctx)
+   if (priv->lastctx == submit->queue->ctx)
break;
/* fall-thru */
case MSM_SUBMIT_CMD_BUF:
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index c5a3e4d4c007..5eabb0109577 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -81,8 +81,7 @@ static void get_stats_counter(struct msm_ringbuffer *ring, 
u32 counter,
OUT_RING(ring, upper_32_bits(iova));
 }
 
-static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
-   struct msm_file_private *ctx)
+static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
 {
unsigned int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT;
struct msm_drm_private *priv = gpu->dev->dev_private;
@@ -115,7 +114,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct 
msm_gem_submit *submit,
case MSM_SUBMIT_CMD_IB_TARGET_BUF:
break;
case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
-   if (priv->lastctx == ctx)
+   if (priv->lastctx == submit->queue->ctx)
break;
/* fall-thru */
case MSM_SUBMIT_CMD_BUF:
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index d2dbb6968cba..533a34b4cce2 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -457,8 +457,7 @@ void adreno_recover(struct msm_gpu *gpu)
}
 }
 
-void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
-   struct msm_file_private *ctx)
+void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
 {
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct msm_drm_private *priv = gpu->dev->dev_private;
@@ -472,7 +471,7 @@ void adreno_submit(struct msm_gpu *gpu, struct 
msm_gem_submit *submit,
break;
 

Re: [PATCH 07/28] 53c700: improve non-coherent DMA handling

2020-09-01 Thread Helge Deller
On 01.09.20 18:21, Helge Deller wrote:
> On 01.09.20 17:22, James Bottomley wrote:
>> On Tue, 2020-09-01 at 16:05 +0100, Matthew Wilcox wrote:
>>> On Tue, Sep 01, 2020 at 07:52:40AM -0700, James Bottomley wrote:
 I think this looks mostly OK, except for one misnamed parameter
 below. Unfortunately, the last non-coherent parisc was the 700
 series and I no longer own a box, so I can't test that part of it
 (I can fire up the C360 to test it on a coherent arch).
>>>
>>> I have a 715/50 that probably hasn't been powered on in 15 years if
>>> you need something that old to test on (I believe the 725/100 uses
>>> the 7100LC and so is coherent).  I'll need to set up a cross-compiler
>>> ...
>>
>> I'm not going to say no to actual testing, but it's going to be a world
>> of pain getting something so old going.  I do have a box of older
>> systems I keep for architectural testing that I need to rummage around
>> in ... I just have a vague memory that my 715 actually caught fire a
>> decade ago and had to be disposed of.
>
> I still have a zoo of machines running for such testing, including a
> 715/64 and two 730.
> I'm going to test this git tree on the 715/64:
> git://git.infradead.org/users/hch/misc.git dma_alloc_pages

This tree boots nicely (up to a command prompt with i82596 nic working):

53c700: Version 2.8 By james.bottom...@hansenpartnership.com
scsi0: 53c710 rev 2
scsi host0: LASI SCSI 53c700
scsi 0:0:6:0: Direct-Access QUANTUM  FIREBALL_TM3200S 300X PQ: 0 ANSI: 2
scsi target0:0:6: Beginning Domain Validation
scsi 0:0:6:0: tag#56 Enabling Tag Command Queuing
scsi target0:0:6: asynchronous
scsi target0:0:6: FAST-10 SCSI 10.0 MB/s ST (100 ns, offset 8)
scsi target0:0:6: Domain Validation skipping write tests
scsi target0:0:6: Ending Domain Validation
scsi 0:0:6:1: tag#63 Disabling Tag Command Queuing
st: Version 20160209, fixed bufsize 32768, s/g segs 256
sd 0:0:6:0: Power-on or device reset occurred
sd 0:0:6:0: Attached scsi generic sg0 type 0
LASI 82596 driver - Revision: 1.30
Found i82596 at 0xf0107000, IRQ 17
eth0: 82596 at 0xf0107000, 08:00:09:c2:9e:60 IRQ 17.
sd 0:0:6:0: [sda] 6281856 512-byte logical blocks: (3.22 GB/3.00 GiB)
sd 0:0:6:0: [sda] Write Protect is off

Christoph, you may add a
Tested-by: Helge Deller  # parisc
to the series.

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


Re: [PATCH 07/28] 53c700: improve non-coherent DMA handling

2020-09-01 Thread Helge Deller
On 01.09.20 17:22, James Bottomley wrote:
> On Tue, 2020-09-01 at 16:05 +0100, Matthew Wilcox wrote:
>> On Tue, Sep 01, 2020 at 07:52:40AM -0700, James Bottomley wrote:
>>> I think this looks mostly OK, except for one misnamed parameter
>>> below. Unfortunately, the last non-coherent parisc was the 700
>>> series and I no longer own a box, so I can't test that part of it
>>> (I can fire up the C360 to test it on a coherent arch).
>>
>> I have a 715/50 that probably hasn't been powered on in 15 years if
>> you need something that old to test on (I believe the 725/100 uses
>> the 7100LC and so is coherent).  I'll need to set up a cross-compiler
>> ...
>
> I'm not going to say no to actual testing, but it's going to be a world
> of pain getting something so old going.  I do have a box of older
> systems I keep for architectural testing that I need to rummage around
> in ... I just have a vague memory that my 715 actually caught fire a
> decade ago and had to be disposed of.

I still have a zoo of machines running for such testing, including a
715/64 and two 730.
I'm going to test this git tree on the 715/64:
git://git.infradead.org/users/hch/misc.git dma_alloc_pages

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


Re: [PATCH 06/19] drm/msm/gpu: add dev_to_gpu() helper

2020-09-01 Thread Rob Clark
On Mon, Aug 31, 2020 at 9:32 PM Bjorn Andersson
 wrote:
>
> On Thu 13 Aug 21:41 CDT 2020, Rob Clark wrote:
>
> > From: Rob Clark 
> >
> > In a later patch, the drvdata will not directly be 'struct msm_gpu *',
> > so add a helper to reduce the churn.
> >
> > Signed-off-by: Rob Clark 
> > ---
> >  drivers/gpu/drm/msm/adreno/adreno_device.c | 10 --
> >  drivers/gpu/drm/msm/msm_gpu.c  |  6 +++---
> >  drivers/gpu/drm/msm/msm_gpu.h  |  5 +
> >  3 files changed, 12 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c 
> > b/drivers/gpu/drm/msm/adreno/adreno_device.c
> > index 9eeb46bf2a5d..26664e1b30c0 100644
> > --- a/drivers/gpu/drm/msm/adreno/adreno_device.c
> > +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
> > @@ -282,7 +282,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
> >   int ret;
> >
> >   if (pdev)
> > - gpu = platform_get_drvdata(pdev);
> > + gpu = dev_to_gpu(>dev);
> >
> >   if (!gpu) {
> >   dev_err_once(dev->dev, "no GPU device was found\n");
> > @@ -425,7 +425,7 @@ static int adreno_bind(struct device *dev, struct 
> > device *master, void *data)
> >  static void adreno_unbind(struct device *dev, struct device *master,
> >   void *data)
> >  {
> > - struct msm_gpu *gpu = dev_get_drvdata(dev);
> > + struct msm_gpu *gpu = dev_to_gpu(dev);
> >
> >   pm_runtime_force_suspend(dev);
> >   gpu->funcs->destroy(gpu);
> > @@ -490,16 +490,14 @@ static const struct of_device_id dt_match[] = {
> >  #ifdef CONFIG_PM
> >  static int adreno_resume(struct device *dev)
> >  {
> > - struct platform_device *pdev = to_platform_device(dev);
> > - struct msm_gpu *gpu = platform_get_drvdata(pdev);
> > + struct msm_gpu *gpu = dev_to_gpu(dev);
> >
> >   return gpu->funcs->pm_resume(gpu);
> >  }
> >
> >  static int adreno_suspend(struct device *dev)
> >  {
> > - struct platform_device *pdev = to_platform_device(dev);
> > - struct msm_gpu *gpu = platform_get_drvdata(pdev);
> > + struct msm_gpu *gpu = dev_to_gpu(dev);
> >
> >   return gpu->funcs->pm_suspend(gpu);
> >  }
> > diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
> > index d5645472b25d..6aa9e04e52e7 100644
> > --- a/drivers/gpu/drm/msm/msm_gpu.c
> > +++ b/drivers/gpu/drm/msm/msm_gpu.c
> > @@ -24,7 +24,7 @@
> >  static int msm_devfreq_target(struct device *dev, unsigned long *freq,
> >   u32 flags)
> >  {
> > - struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
> > + struct msm_gpu *gpu = dev_to_gpu(dev);
> >   struct dev_pm_opp *opp;
> >
> >   opp = devfreq_recommended_opp(dev, freq, flags);
> > @@ -45,7 +45,7 @@ static int msm_devfreq_target(struct device *dev, 
> > unsigned long *freq,
> >  static int msm_devfreq_get_dev_status(struct device *dev,
> >   struct devfreq_dev_status *status)
> >  {
> > - struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
> > + struct msm_gpu *gpu = dev_to_gpu(dev);
> >   ktime_t time;
> >
> >   if (gpu->funcs->gpu_get_freq)
> > @@ -64,7 +64,7 @@ static int msm_devfreq_get_dev_status(struct device *dev,
> >
> >  static int msm_devfreq_get_cur_freq(struct device *dev, unsigned long 
> > *freq)
> >  {
> > - struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
> > + struct msm_gpu *gpu = dev_to_gpu(dev);
> >
> >   if (gpu->funcs->gpu_get_freq)
> >   *freq = gpu->funcs->gpu_get_freq(gpu);
> > diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
> > index 0db117a7339b..8bda7beaed4b 100644
> > --- a/drivers/gpu/drm/msm/msm_gpu.h
> > +++ b/drivers/gpu/drm/msm/msm_gpu.h
> > @@ -141,6 +141,11 @@ struct msm_gpu {
> >   struct msm_gpu_state *crashstate;
> >  };
> >
> > +static inline struct msm_gpu *dev_to_gpu(struct device *dev)
>
> That's a fairly generic name for a driver-global helper :)

tbf, it is only global to the gpu part of the driver..

thanks for the review

BR,
-R

> Reviewed-by: Bjorn Andersson 
>
> Regards,
> Bjorn
>
> > +{
> > + return dev_get_drvdata(dev);
> > +}
> > +
> >  /* It turns out that all targets use the same ringbuffer size */
> >  #define MSM_GPU_RINGBUFFER_SZ SZ_32K
> >  #define MSM_GPU_RINGBUFFER_BLKSIZE 32
> > --
> > 2.26.2
> >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 5/9] iommu/ioasid: Introduce ioasid_set private ID

2020-09-01 Thread Auger Eric
Hi Jacob,
On 8/22/20 6:35 AM, Jacob Pan wrote:
> When an IOASID set is used for guest SVA, each VM will acquire its
> ioasid_set for IOASID allocations. IOASIDs within the VM must have a
> host/physical IOASID backing, mapping between guest and host IOASIDs can
> be non-identical. IOASID set private ID (SPID) is introduced in this
> patch to be used as guest IOASID. However, the concept of ioasid_set
> specific namespace is generic, thus named SPID.
> 
> As SPID namespace is within the IOASID set, the IOASID core can provide
> lookup services at both directions. SPIDs may not be allocated when its
> IOASID is allocated, the mapping between SPID and IOASID is usually
> established when a guest page table is bound to a host PASID.
> 
> Signed-off-by: Jacob Pan 
> ---
>  drivers/iommu/ioasid.c | 54 
> ++
>  include/linux/ioasid.h | 12 +++
>  2 files changed, 66 insertions(+)
> 
> diff --git a/drivers/iommu/ioasid.c b/drivers/iommu/ioasid.c
> index 5f31d63c75b1..c0aef38a4fde 100644
> --- a/drivers/iommu/ioasid.c
> +++ b/drivers/iommu/ioasid.c
> @@ -21,6 +21,7 @@ enum ioasid_state {
>   * struct ioasid_data - Meta data about ioasid
>   *
>   * @id:  Unique ID
> + * @spid:Private ID unique within a set
>   * @usersNumber of active users
>   * @stateTrack state of the IOASID
>   * @set  Meta data of the set this IOASID belongs to
> @@ -29,6 +30,7 @@ enum ioasid_state {
>   */
>  struct ioasid_data {
>   ioasid_t id;
> + ioasid_t spid;
>   struct ioasid_set *set;
>   refcount_t users;
>   enum ioasid_state state;
> @@ -326,6 +328,58 @@ int ioasid_attach_data(ioasid_t ioasid, void *data)
>  EXPORT_SYMBOL_GPL(ioasid_attach_data);
>  
>  /**
> + * ioasid_attach_spid - Attach ioasid_set private ID to an IOASID
> + *
> + * @ioasid: the ID to attach
> + * @spid:   the ioasid_set private ID of @ioasid
> + *
> + * For IOASID that is already allocated, private ID within the set can be
> + * attached via this API. Future lookup can be done via ioasid_find.
I would remove "For IOASID that is already allocated, private ID within
the set can be attached via this API"
> + */
> +int ioasid_attach_spid(ioasid_t ioasid, ioasid_t spid)
> +{
> + struct ioasid_data *ioasid_data;
> + int ret = 0;
> +
> + spin_lock(_allocator_lock);
We keep on saying the SPID is local to an IOASID set but we don't check
any IOASID set contains this ioasid. It looks a bit weird to me.
> + ioasid_data = xa_load(_allocator->xa, ioasid);
> +
> + if (!ioasid_data) {
> + pr_err("No IOASID entry %d to attach SPID %d\n",
> + ioasid, spid);
> + ret = -ENOENT;
> + goto done_unlock;
> + }
> + ioasid_data->spid = spid;
is there any way/need to remove an spid binding?
> +
> +done_unlock:
> + spin_unlock(_allocator_lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ioasid_attach_spid);
> +
> +ioasid_t ioasid_find_by_spid(struct ioasid_set *set, ioasid_t spid)
> +{
> + struct ioasid_data *entry;
> + unsigned long index;
> +
> + if (!xa_load(_sets, set->sid)) {
> + pr_warn("Invalid set\n");
> + return INVALID_IOASID;
> + }
> +
> + xa_for_each(>xa, index, entry) {
> + if (spid == entry->spid) {
> + pr_debug("Found ioasid %lu by spid %u\n", index, spid);
> + refcount_inc(>users);
> + return index;
> + }
> + }
> + return INVALID_IOASID;
> +}
> +EXPORT_SYMBOL_GPL(ioasid_find_by_spid);
> +
> +/**
>   * ioasid_alloc - Allocate an IOASID
>   * @set: the IOASID set
>   * @min: the minimum ID (inclusive)
> diff --git a/include/linux/ioasid.h b/include/linux/ioasid.h
> index 310abe4187a3..d4b3e83672f6 100644
> --- a/include/linux/ioasid.h
> +++ b/include/linux/ioasid.h
> @@ -73,6 +73,8 @@ bool ioasid_is_active(ioasid_t ioasid);
>  
>  void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid, bool 
> (*getter)(void *));
>  int ioasid_attach_data(ioasid_t ioasid, void *data);
> +int ioasid_attach_spid(ioasid_t ioasid, ioasid_t spid);
> +ioasid_t ioasid_find_by_spid(struct ioasid_set *set, ioasid_t spid);
>  int ioasid_register_allocator(struct ioasid_allocator_ops *allocator);
>  void ioasid_unregister_allocator(struct ioasid_allocator_ops *allocator);
>  void ioasid_is_in_set(struct ioasid_set *set, ioasid_t ioasid);
> @@ -136,5 +138,15 @@ static inline int ioasid_attach_data(ioasid_t ioasid, 
> void *data)
>   return -ENOTSUPP;
>  }
>  
> +staic inline int ioasid_attach_spid(ioasid_t ioasid, ioasid_t spid)
> +{
> + return -ENOTSUPP;
> +}
> +
> +static inline ioasid_t ioasid_find_by_spid(struct ioasid_set *set, ioasid_t 
> spid)
> +{
> + return -ENOTSUPP;
> +}
> +
>  #endif /* CONFIG_IOASID */
>  #endif /* __LINUX_IOASID_H */
> 
Thanks

Eric

___
iommu mailing list

Re: [PATCH 22/28] sgiseeq: convert from dma_cache_sync to dma_sync_single_for_device

2020-09-01 Thread Thomas Bogendoerfer
On Wed, Aug 19, 2020 at 08:55:49AM +0200, Christoph Hellwig wrote:
> Use the proper modern API to transfer cache ownership for incoherent DMA.
> 
> Signed-off-by: Christoph Hellwig 
> ---
>  drivers/net/ethernet/seeq/sgiseeq.c | 12 
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/seeq/sgiseeq.c 
> b/drivers/net/ethernet/seeq/sgiseeq.c
> index 39599bbb5d45b6..f91dae16d69a19 100644
> --- a/drivers/net/ethernet/seeq/sgiseeq.c
> +++ b/drivers/net/ethernet/seeq/sgiseeq.c
> @@ -112,14 +112,18 @@ struct sgiseeq_private {
>  
>  static inline void dma_sync_desc_cpu(struct net_device *dev, void *addr)
>  {
> - dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
> -DMA_FROM_DEVICE);
> + struct sgiseeq_private *sp = netdev_priv(dev);
> +
> + dma_sync_single_for_cpu(dev->dev.parent, VIRT_TO_DMA(sp, addr),
> + sizeof(struct sgiseeq_rx_desc), DMA_BIDIRECTIONAL);
>  }
>  
>  static inline void dma_sync_desc_dev(struct net_device *dev, void *addr)
>  {
> - dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
> -DMA_TO_DEVICE);
> + struct sgiseeq_private *sp = netdev_priv(dev);
> +
> + dma_sync_single_for_device(dev->dev.parent, VIRT_TO_DMA(sp, addr),
> + sizeof(struct sgiseeq_rx_desc), DMA_BIDIRECTIONAL);
>  }

this breaks ethernet on IP22 completely, but I haven't figured out why, yet.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.[ RFC1925, 2.3 ]
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 07/28] 53c700: improve non-coherent DMA handling

2020-09-01 Thread James Bottomley
On Tue, 2020-09-01 at 16:05 +0100, Matthew Wilcox wrote:
> On Tue, Sep 01, 2020 at 07:52:40AM -0700, James Bottomley wrote:
> > I think this looks mostly OK, except for one misnamed parameter
> > below. Unfortunately, the last non-coherent parisc was the 700
> > series and I no longer own a box, so I can't test that part of it
> > (I can fire up the C360 to test it on a coherent arch).
> 
> I have a 715/50 that probably hasn't been powered on in 15 years if
> you need something that old to test on (I believe the 725/100 uses
> the 7100LC and so is coherent).  I'll need to set up a cross-compiler 
> ...

I'm not going to say no to actual testing, but it's going to be a world
of pain getting something so old going.  I do have a box of older
systems I keep for architectural testing that I need to rummage around
in ... I just have a vague memory that my 715 actually caught fire a
decade ago and had to be disposed of.

James

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


Re: [PATCH 05/28] media/v4l2: remove V4L2-FLAG-MEMORY-NON-CONSISTENT

2020-09-01 Thread Tomasz Figa
On Tue, Sep 1, 2020 at 1:06 PM Christoph Hellwig  wrote:
>
> On Thu, Aug 20, 2020 at 07:33:48PM +0200, Tomasz Figa wrote:
> > > It wasn't meant to be too insulting, but I found this out when trying
> > > to figure out how to just disable it.  But it also ends up using
> > > the actual dma attr flags for it's own consistency checks, so just
> > > not setting the flag did not turn out to work that easily.
> > >
> >
> > Yes, sadly the videobuf2 ended up becoming quite counterintuitive
> > after growing for the long years and that is reflected in the design
> > of this feature as well. I think we need to do something about it.
>
> So I'm about to respin the series and wonder how we should proceed.
> I've failed to come up with a clean patch to keep the flag and make
> it a no-op.  Can you or your team give it a spin?
>

Okay, I'll take a look.

> Also I wonder if the flag should be renamed from NON_CONSISTENT
> to NON_COHERENT - the consistent thing is a weird wart from the times
> the old PCI DMA API that is mostly gone now.

It originated from the DMA_ATTR_NON_CONSISTENT flag, but agreed that
NON_COHERENT would be more consistent (pun not intended) with the rest
of the DMA API given the removal of that flag. Let me see if we can
still change it.

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


Re: [PATCH 07/28] 53c700: improve non-coherent DMA handling

2020-09-01 Thread Matthew Wilcox
On Tue, Sep 01, 2020 at 07:52:40AM -0700, James Bottomley wrote:
> I think this looks mostly OK, except for one misnamed parameter below. 
> Unfortunately, the last non-coherent parisc was the 700 series and I no
> longer own a box, so I can't test that part of it (I can fire up the
> C360 to test it on a coherent arch).

I have a 715/50 that probably hasn't been powered on in 15 years if you
need something that old to test on (I believe the 725/100 uses the 7100LC
and so is coherent).  I'll need to set up a cross-compiler ...
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 07/28] 53c700: improve non-coherent DMA handling

2020-09-01 Thread James Bottomley
On Wed, 2020-08-19 at 08:55 +0200, Christoph Hellwig wrote:
> Switch the 53c700 driver to only use non-coherent descriptor memory
> if it really has to because dma_alloc_coherent fails.  This doesn't
> matter for any of the platforms it runs on currently, but that will
> change soon.
> 
> To help with this two new helpers to transfer ownership to and from
> the device are added that abstract the syncing of the non-coherent
> memory. The two current bidirectional cases are mapped to transfers
> to the device, as that appears to what they are used for.  Note that
> for parisc, which is the only architecture this driver needs to use
> non-coherent memory on, the direction argument of dma_cache_sync is
> ignored, so this will not change behavior in any way.

I think this looks mostly OK, except for one misnamed parameter below. 
Unfortunately, the last non-coherent parisc was the 700 series and I no
longer own a box, so I can't test that part of it (I can fire up the
C360 to test it on a coherent arch).

[...]
> diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
> index 05fe439b66afe5..0f545b05fe611d 100644
> --- a/drivers/scsi/53c700.h
> +++ b/drivers/scsi/53c700.h
> @@ -209,6 +209,7 @@ struct NCR_700_Host_Parameters {
>  #endif
>   __u32   chip710:1;  /* set if really a 710 not
> 700 */
>   __u32   burst_length:4; /* set to 0 to disable
> 710 bursting */
> + __u32   noncoherent:1;  /* needs to use non-
> coherent DMA */
>  
>   /* NOTHING BELOW HERE NEEDS ALTERING */
>   __u32   fast:1; /* if we can alter the
> SCSI bus clock
> @@ -429,7 +430,7 @@ struct NCR_700_Host_Parameters {
>   for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32));
> i++) { \
>   __u32 val =
> bS_to_cpu((script)[A_##symbol##_used[i]]) + da; \
>   (script)[A_##symbol##_used[i]] = bS_to_host(val); \
> - dma_cache_sync((dev),
> &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
> + dma_sync_to_dev((dev),
> &(script)[A_##symbol##_used[i]], 4); \
>   DEBUG((" script, patching %s at %d to %pad\n", \
>  #symbol, A_##symbol##_used[i], )); \
>   } \
> @@ -441,7 +442,7 @@ struct NCR_700_Host_Parameters {
>   dma_addr_t da = value; \
>   for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32));
> i++) { \
>   (script)[A_##symbol##_used[i]] = bS_to_host(da); \
> - dma_cache_sync((dev),
> &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
> + dma_sync_to_dev((dev),
> &(script)[A_##symbol##_used[i]], 4); \
>   DEBUG((" script, patching %s at %d to %pad\n", \
>  #symbol, A_##symbol##_used[i], )); \
>   } \
> @@ -456,7 +457,7 @@ struct NCR_700_Host_Parameters {
>   val &= 0xff00; \
>   val |= ((value) & 0xff) << 16; \
>   (script)[A_##symbol##_used[i]] = bS_to_host(val); \
> - dma_cache_sync((dev),
> &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
> + dma_sync_to_dev((dev),
> &(script)[A_##symbol##_used[i]], 4); \
>   DEBUG((" script, patching ID field %s at %d to
> 0x%x\n", \
>  #symbol, A_##symbol##_used[i], val)); \
>   } \
> @@ -470,7 +471,7 @@ struct NCR_700_Host_Parameters {
>   val &= 0x; \
>   val |= ((value) & 0x); \
>   (script)[A_##symbol##_used[i]] = bS_to_host(val); \
> - dma_cache_sync((dev),
> &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
> + dma_sync_to_dev((dev),
> &(script)[A_##symbol##_used[i]], 4); \
>   DEBUG((" script, patching short field %s at %d to
> 0x%x\n", \
>  #symbol, A_##symbol##_used[i], val)); \
>   } \

These macro arguments need updating.  Since you changed the input from
hostdata->dev to hostdata, leaving the macro argument as dev is simply
misleading.  It needs to become hostdata or h.

James

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


Re: [Regression] [PATCH] iommu: Avoid crash in init_no_remapping_devices if iommu is NULL

2020-09-01 Thread Torsten Hilbrich
On 01.09.20 04:02, Lu Baolu wrote:
[...]
> This looks more like a generic issue, used-before-allocated, and should
> be fixed in iommu.c instead of VT-d driver. How about
> 
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 8fd93a5b8764..a599da87eb60 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -190,6 +190,28 @@ static void dev_iommu_free(struct device *dev)
>     dev->iommu = NULL;
>  }
> 
> +void *dev_iommu_priv_get(struct device *dev)
> +{
> +   struct dev_iommu *param = dev_iommu_get(dev);
> +
> +   if (WARN_ON(!param))
> +   return ERR_PTR(-ENOMEM);
> +
> +    return param->priv;
> +}
> +EXPORT_SYMBOL_GPL(dev_iommu_priv_get);
> +
> +void dev_iommu_priv_set(struct device *dev, void *priv)
> +{
> +   struct dev_iommu *param = dev_iommu_get(dev);
> +
> +   if (WARN_ON(!param))
> +   return;
> +
> +    param->priv = priv;
> +}
> +EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
> +

This fix would work in my case. I tested it with slight modification to
replace the inline routines in include/linux/iommu.h.

The WARN_ON was not triggered during my tests. However, looking at the
definition of dev_iommu_get this is to be expected.

Regards,

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

Re: [PATCH 09/28] MIPS/jazzdma: remove the unused vdma_remap function

2020-09-01 Thread Thomas Bogendoerfer
On Wed, Aug 19, 2020 at 08:55:36AM +0200, Christoph Hellwig wrote:
> Signed-off-by: Christoph Hellwig 
> ---
>  arch/mips/include/asm/jazzdma.h |  2 -
>  arch/mips/jazz/jazzdma.c| 70 -
>  2 files changed, 72 deletions(-)

Acked-by: Thomas Bogendoerfer 

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.[ RFC1925, 2.3 ]
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 10/28] MIPS/jazzdma: decouple from dma-direct

2020-09-01 Thread Thomas Bogendoerfer
On Wed, Aug 19, 2020 at 08:55:37AM +0200, Christoph Hellwig wrote:
> The jazzdma ops implement support for a very basic IOMMU.  Thus we really
> should not use the dma-direct code that takes physical address limits
> into account.  This survived through the great MIPS DMA ops cleanup mostly
> because I was lazy, but now it is time to fully split the implementations.
> 
> Signed-off-by: Christoph Hellwig 
> ---
>  arch/mips/jazz/jazzdma.c | 32 +---
>  1 file changed, 21 insertions(+), 11 deletions(-)

Acked-by: Thomas Bogendoerfer 

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.[ RFC1925, 2.3 ]
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 08/28] MIPS: make dma_sync_*_for_cpu a little less overzealous

2020-09-01 Thread Thomas Bogendoerfer
On Wed, Aug 19, 2020 at 08:55:35AM +0200, Christoph Hellwig wrote:
> When transferring DMA ownership back to the CPU there should never
> be any writeback from the cache, as the buffer was owned by the
> device until now.  Instead it should just be invalidated for the
> mapping directions where the device could have written data.
> Note that the changes rely on the fact that kmap_atomic is stubbed
> out for the !HIGHMEM case to simplify the code a bit.
> 
> Signed-off-by: Christoph Hellwig 
> ---
>  arch/mips/mm/dma-noncoherent.c | 44 +-
>  1 file changed, 28 insertions(+), 16 deletions(-)

Acked-by: Thomas Bogendoerfer 

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.[ RFC1925, 2.3 ]
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 06/28] lib82596: move DMA allocation into the callers of i82596_probe

2020-09-01 Thread Thomas Bogendoerfer
On Wed, Aug 19, 2020 at 08:55:33AM +0200, Christoph Hellwig wrote:
> This allows us to get rid of the LIB82596_DMA_ATTR defined and prepare
> for untangling the coherent vs non-coherent DMA allocation API.
> 
> Signed-off-by: Christoph Hellwig 
> ---
>  drivers/net/ethernet/i825xx/lasi_82596.c | 24 ++--
>  drivers/net/ethernet/i825xx/lib82596.c   | 36 
>  drivers/net/ethernet/i825xx/sni_82596.c  | 19 +
>  3 files changed, 40 insertions(+), 39 deletions(-)
> 
> [...]
> diff --git a/drivers/net/ethernet/i825xx/sni_82596.c 
> b/drivers/net/ethernet/i825xx/sni_82596.c
> index 22f5887578b2bd..e80e790ffbd4d4 100644
> --- a/drivers/net/ethernet/i825xx/sni_82596.c
> +++ b/drivers/net/ethernet/i825xx/sni_82596.c
> @@ -24,8 +24,6 @@
>  
>  static const char sni_82596_string[] = "snirm_82596";
>  
> -#define LIB82596_DMA_ATTR0
> -
>  #define DMA_WBACK(priv, addr, len) do { } while (0)
>  #define DMA_INV(priv, addr, len)   do { } while (0)
>  #define DMA_WBACK_INV(priv, addr, len) do { } while (0)
> @@ -134,10 +132,19 @@ static int sni_82596_probe(struct platform_device *dev)
>   lp->ca = ca_addr;
>   lp->mpu_port = mpu_addr;
>  
> + lp->dma = dma_alloc_coherent(dev->dev.parent, sizeof(struct i596_dma),
> +  >dma_addr, GFP_KERNEL);

this needs to use >dev as device argument otherwise I get a

WARNING: CPU: 0 PID: 1 at linux/kernel/dma/mapping.c:416 
dma_alloc_attrs+0x64/0x98

(coherent_dma_mask is set correctly).

dev->dev.parent was correct when going from netdevice to underlying device,
but now allocation is done via platform_device probe. I wonder why this works
for parisc.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.[ RFC1925, 2.3 ]
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 4/9] iommu/ioasid: Add reference couting functions

2020-09-01 Thread Auger Eric
Hi Jacob,

On 8/22/20 6:35 AM, Jacob Pan wrote:
> There can be multiple users of an IOASID, each user could have hardware
> contexts associated with the IOASID. In order to align lifecycles,
> reference counting is introduced in this patch. It is expected that when
> an IOASID is being freed, each user will drop a reference only after its
> context is cleared.
> 
> Signed-off-by: Jacob Pan 
> ---
>  drivers/iommu/ioasid.c | 113 
> +
>  include/linux/ioasid.h |   4 ++
>  2 files changed, 117 insertions(+)
> 
> diff --git a/drivers/iommu/ioasid.c b/drivers/iommu/ioasid.c
> index f73b3dbfc37a..5f31d63c75b1 100644
> --- a/drivers/iommu/ioasid.c
> +++ b/drivers/iommu/ioasid.c
> @@ -717,6 +717,119 @@ int ioasid_set_for_each_ioasid(struct ioasid_set *set,
>  EXPORT_SYMBOL_GPL(ioasid_set_for_each_ioasid);
>  
>  /**
> + * IOASID refcounting rules
> + * - ioasid_alloc() set initial refcount to 1
> + *
> + * - ioasid_free() decrement and test refcount.
> + * If refcount is 0, ioasid will be freed. Deleted from the system-wide
> + * xarray as well as per set xarray. The IOASID will be returned to the
> + * pool and available for new allocations.
> + *
> + * If recount is non-zero, mark IOASID as IOASID_STATE_FREE_PENDING.
s/recount/refcount
> + * No new reference can be added. The IOASID is not returned to the pool
can be taken
> + * for reuse.
> + * After free, ioasid_get() will return error but ioasid_find() and other
> + * non refcount adding APIs will continue to work until the last 
> reference
> + * is dropped
> + *
> + * - ioasid_get() get a reference on an active IOASID
> + *
> + * - ioasid_put() decrement and test refcount of the IOASID.
> + * If refcount is 0, ioasid will be freed. Deleted from the system-wide
> + * xarray as well as per set xarray. The IOASID will be returned to the
> + * pool and available for new allocations.
> + * Do nothing if refcount is non-zero.
I would drop this last sentence
> + *
> + * - ioasid_find() does not take reference, caller must hold reference
So can you use ioasid_find() once the state is
IOASID_STATE_FREE_PENDING? According to Jean's reply, the "IOASID may be
freed once ioasid_find() returns but not the returned data." So holding
a ref is not mandated right?
> + *
> + * ioasid_free() can be called multiple times without error until all refs 
> are
> + * dropped.
> + */
> +
> +int ioasid_get_locked(struct ioasid_set *set, ioasid_t ioasid)
> +{
> + struct ioasid_data *data;
> +
> + data = xa_load(_allocator->xa, ioasid);
> + if (!data) {
> + pr_err("Trying to get unknown IOASID %u\n", ioasid);
> + return -EINVAL;
> + }
> + if (data->state == IOASID_STATE_FREE_PENDING) {
> + pr_err("Trying to get IOASID being freed%u\n", ioasid);
> + return -EBUSY;
> + }
> +
> + if (set && data->set != set) {
> + pr_err("Trying to get IOASID not in set%u\n", ioasid);
maybe try to normalize your traces using always the same formatting for
ioasids and ioasid sets. Also we can understand %u is the id of the set.
> + /* data found but does not belong to the set */
you can get rid of this comment
> + return -EACCES;
> + }
> + refcount_inc(>users);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ioasid_get_locked);
> +
> +/**
> + * ioasid_get - Obtain a reference of an ioasid
> + * @set
> + * @ioasid
> + *
> + * Check set ownership if @set is non-null.
> + */
> +int ioasid_get(struct ioasid_set *set, ioasid_t ioasid)
> +{
> + int ret = 0;
> +
> + spin_lock(_allocator_lock);
> + ret = ioasid_get_locked(set, ioasid);
> + spin_unlock(_allocator_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ioasid_get);
> +
> +void ioasid_put_locked(struct ioasid_set *set, ioasid_t ioasid)
> +{
> + struct ioasid_data *data;
> +
> + data = xa_load(_allocator->xa, ioasid);
> + if (!data) {
> + pr_err("Trying to put unknown IOASID %u\n", ioasid);
> + return;
> + }
> +
> + if (set && data->set != set) {
> + pr_err("Trying to drop IOASID not in the set %u\n", ioasid);
was set%u above
> + return;
> + }
> +
> + if (!refcount_dec_and_test(>users)) {
> + pr_debug("%s: IOASID %d has %d remainning users\n",
> + __func__, ioasid, refcount_read(>users));
> + return;
> + }
> + ioasid_do_free(data);
> +}
> +EXPORT_SYMBOL_GPL(ioasid_put_locked);
> +
> +/**
> + * ioasid_put - Drop a reference of an ioasid
> + * @set
> + * @ioasid
> + *
> + * Check set ownership if @set is non-null.
> + */
> +void ioasid_put(struct ioasid_set *set, ioasid_t ioasid)
> +{
> + spin_lock(_allocator_lock);
> + ioasid_put_locked(set, ioasid);
> + spin_unlock(_allocator_lock);
> +}
> +EXPORT_SYMBOL_GPL(ioasid_put);
> +
> +/**
>   * ioasid_find - Find IOASID data
>   * @set: 

Re: [PATCH v2 2/9] iommu/ioasid: Rename ioasid_set_data()

2020-09-01 Thread Auger Eric
Hi jacob,

On 8/22/20 6:35 AM, Jacob Pan wrote:
> Rename ioasid_set_data() to ioasid_attach_data() to avoid confusion with
> struct ioasid_set. ioasid_set is a group of IOASIDs that share a common
> token.
> 
> Signed-off-by: Jacob Pan 
Reviewed-by: Eric Auger 

Eric
> ---
>  drivers/iommu/intel/svm.c | 6 +++---
>  drivers/iommu/ioasid.c| 6 +++---
>  include/linux/ioasid.h| 4 ++--
>  3 files changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index b6972dca2ae0..37a9beabc0ca 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -342,7 +342,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, 
> struct device *dev,
>   svm->gpasid = data->gpasid;
>   svm->flags |= SVM_FLAG_GUEST_PASID;
>   }
> - ioasid_set_data(data->hpasid, svm);
> + ioasid_attach_data(data->hpasid, svm);
>   INIT_LIST_HEAD_RCU(>devs);
>   mmput(svm->mm);
>   }
> @@ -394,7 +394,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, 
> struct device *dev,
>   list_add_rcu(>list, >devs);
>   out:
>   if (!IS_ERR_OR_NULL(svm) && list_empty(>devs)) {
> - ioasid_set_data(data->hpasid, NULL);
> + ioasid_attach_data(data->hpasid, NULL);
>   kfree(svm);
>   }
>  
> @@ -437,7 +437,7 @@ int intel_svm_unbind_gpasid(struct device *dev, int pasid)
>* the unbind, IOMMU driver will get notified
>* and perform cleanup.
>*/
> - ioasid_set_data(pasid, NULL);
> + ioasid_attach_data(pasid, NULL);
>   kfree(svm);
>   }
>   }
> diff --git a/drivers/iommu/ioasid.c b/drivers/iommu/ioasid.c
> index 0f8dd377aada..5f63af07acd5 100644
> --- a/drivers/iommu/ioasid.c
> +++ b/drivers/iommu/ioasid.c
> @@ -258,14 +258,14 @@ void ioasid_unregister_allocator(struct 
> ioasid_allocator_ops *ops)
>  EXPORT_SYMBOL_GPL(ioasid_unregister_allocator);
>  
>  /**
> - * ioasid_set_data - Set private data for an allocated ioasid
> + * ioasid_attach_data - Set private data for an allocated ioasid
>   * @ioasid: the ID to set data
>   * @data:   the private data
>   *
>   * For IOASID that is already allocated, private data can be set
>   * via this API. Future lookup can be done via ioasid_find.
>   */
> -int ioasid_set_data(ioasid_t ioasid, void *data)
> +int ioasid_attach_data(ioasid_t ioasid, void *data)
>  {
>   struct ioasid_data *ioasid_data;
>   int ret = 0;
> @@ -287,7 +287,7 @@ int ioasid_set_data(ioasid_t ioasid, void *data)
>  
>   return ret;
>  }
> -EXPORT_SYMBOL_GPL(ioasid_set_data);
> +EXPORT_SYMBOL_GPL(ioasid_attach_data);
>  
>  /**
>   * ioasid_alloc - Allocate an IOASID
> diff --git a/include/linux/ioasid.h b/include/linux/ioasid.h
> index 6f000d7a0ddc..9c44947a68c8 100644
> --- a/include/linux/ioasid.h
> +++ b/include/linux/ioasid.h
> @@ -39,7 +39,7 @@ void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
> bool (*getter)(void *));
>  int ioasid_register_allocator(struct ioasid_allocator_ops *allocator);
>  void ioasid_unregister_allocator(struct ioasid_allocator_ops *allocator);
> -int ioasid_set_data(ioasid_t ioasid, void *data);
> +int ioasid_attach_data(ioasid_t ioasid, void *data);
>  
>  #else /* !CONFIG_IOASID */
>  static inline ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min,
> @@ -67,7 +67,7 @@ static inline void ioasid_unregister_allocator(struct 
> ioasid_allocator_ops *allo
>  {
>  }
>  
> -static inline int ioasid_set_data(ioasid_t ioasid, void *data)
> +static inline int ioasid_attach_data(ioasid_t ioasid, void *data)
>  {
>   return -ENOTSUPP;
>  }
> 

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


Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs

2020-09-01 Thread Auger Eric
Hi Jacob,

On 8/22/20 6:35 AM, Jacob Pan wrote:
> ioasid_set was introduced as an arbitrary token that are shared by a
that is
> group of IOASIDs. For example, if IOASID #1 and #2 are allocated via the
> same ioasid_set*, they are viewed as to belong to the same set.
two IOASIDs allocated via the same ioasid_set pointer belong to the same
set?
> 
> For guest SVA usages, system-wide IOASID resources need to be
> partitioned such that VMs can have its own quota and being managed
their own
> separately. ioasid_set is the perfect candidate for meeting such
> requirements. This patch redefines and extends ioasid_set with the
> following new fields:
> - Quota
> - Reference count
> - Storage of its namespace
> - The token is stored in the new ioasid_set but with optional types
> 
> ioasid_set level APIs are introduced that wires up these new data.
that wire
> Existing users of IOASID APIs are converted where a host IOASID set is
> allocated for bare-metal usage.
> 
> Signed-off-by: Liu Yi L 
> Signed-off-by: Jacob Pan 
> ---
>  drivers/iommu/intel/iommu.c |  27 ++-
>  drivers/iommu/intel/pasid.h |   1 +
>  drivers/iommu/intel/svm.c   |   8 +-
>  drivers/iommu/ioasid.c  | 390 
> +---
>  include/linux/ioasid.h  |  82 --
>  5 files changed, 465 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index a3a0b5c8921d..5813eeaa5edb 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -42,6 +42,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -103,6 +104,9 @@
>   */
>  #define INTEL_IOMMU_PGSIZES  (~0xFFFUL)
>  
> +/* PASIDs used by host SVM */
> +struct ioasid_set *host_pasid_set;
> +
>  static inline int agaw_to_level(int agaw)
>  {
>   return agaw + 2;
> @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t ioasid, 
> void *data)
>* Sanity check the ioasid owner is done at upper layer, e.g. VFIO
>* We can only free the PASID when all the devices are unbound.
>*/
> - if (ioasid_find(NULL, ioasid, NULL)) {
> - pr_alert("Cannot free active IOASID %d\n", ioasid);
> + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) {
> + pr_err("Cannot free IOASID %d, not in system set\n", ioasid);
not sure the change in the trace is worth. Also you may be more explicit
like IOASID %d to be freed cannot be found in the system ioasid set.
shouldn't it be rate_limited as it is originated from user space?
>   return;
>   }
>   vcmd_free_pasid(iommu, ioasid);
> @@ -3288,6 +3292,19 @@ static int __init init_dmars(void)
>   if (ret)
>   goto free_iommu;
>  
> + /* PASID is needed for scalable mode irrespective to SVM */
> + if (intel_iommu_sm) {
> + ioasid_install_capacity(intel_pasid_max_id);
> + /* We should not run out of IOASIDs at boot */
> + host_pasid_set = ioasid_alloc_set(NULL, PID_MAX_DEFAULT,
s/PID_MAX_DEFAULT/intel_pasid_max_id?
> + IOASID_SET_TYPE_NULL);
as suggested by jean-Philippe ioasid_set_alloc
> + if (IS_ERR_OR_NULL(host_pasid_set)) {
> + pr_err("Failed to enable host PASID allocator %lu\n",
> + PTR_ERR(host_pasid_set));
does not sound like the correct error message? failed to allocate the
system ioasid_set?
> + intel_iommu_sm = 0;
> + }
> + }
> +
>   /*
>* for each drhd
>*   enable fault log
> @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct dmar_domain 
> *domain,
>   domain->auxd_refcnt--;
>  
>   if (!domain->auxd_refcnt && domain->default_pasid > 0)
> - ioasid_free(domain->default_pasid);
> + ioasid_free(host_pasid_set, domain->default_pasid);
>  }
>  
>  static int aux_domain_add_dev(struct dmar_domain *domain,
> @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct dmar_domain 
> *domain,
>   int pasid;
>  
>   /* No private data needed for the default pasid */
> - pasid = ioasid_alloc(NULL, PASID_MIN,
> + pasid = ioasid_alloc(host_pasid_set, PASID_MIN,
>pci_max_pasids(to_pci_dev(dev)) - 1,
>NULL);
don't you want to ioasid_set_put() the ioasid_set in
intel_iommu_free_dmars()?
>   if (pasid == INVALID_IOASID) {
> @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct dmar_domain 
> *domain,
>   spin_unlock(>lock);
>   spin_unlock_irqrestore(_domain_lock, flags);
>   if (!domain->auxd_refcnt && domain->default_pasid > 0)
> - ioasid_free(domain->default_pasid);
> + ioasid_free(host_pasid_set, domain->default_pasid);
>  
>   return ret;
>  }
> diff --git a/drivers/iommu/intel/pasid.h 

RE: [PATCH v2 0/2] iommu/arm-smmu-v3: Improve cmdq lock efficiency

2020-09-01 Thread Song Bao Hua (Barry Song)



> -Original Message-
> From: linux-kernel-ow...@vger.kernel.org
> [mailto:linux-kernel-ow...@vger.kernel.org] On Behalf Of John Garry
> Sent: Saturday, August 22, 2020 1:54 AM
> To: w...@kernel.org; robin.mur...@arm.com
> Cc: j...@8bytes.org; linux-arm-ker...@lists.infradead.org;
> iommu@lists.linux-foundation.org; m...@kernel.org; Linuxarm
> ; linux-ker...@vger.kernel.org; John Garry
> 
> Subject: [PATCH v2 0/2] iommu/arm-smmu-v3: Improve cmdq lock efficiency
> 
> As mentioned in [0], the CPU may consume many cycles processing
> arm_smmu_cmdq_issue_cmdlist(). One issue we find is the cmpxchg() loop to
> get space on the queue takes a lot of time once we start getting many CPUs
> contending - from experiment, for 64 CPUs contending the cmdq, success rate
> is ~ 1 in 12, which is poor, but not totally awful.
> 
> This series removes that cmpxchg() and replaces with an atomic_add, same as
> how the actual cmdq deals with maintaining the prod pointer.
> 
> For my NVMe test with 3x NVMe SSDs, I'm getting a ~24% throughput
> increase:
> Before: 1250K IOPs
> After: 1550K IOPs
> 
> I also have a test harness to check the rate of DMA map+unmaps we can
> achieve:
> 
> CPU count 8   16  32  64
> Before:   282K115K36K 11K
> After:302K193K80K 30K
> 
> (unit is map+unmaps per CPU per second)

I have seen performance improvement on hns3 network by sending UDP with 1-32 
threads:

Threads number14   8 16   32
Before patch(TX Mbps)  7636.05  16444.36  21694.48  25746.40   25295.93
After  patch(TX Mbps)  7711.60  16478.98  26561.06  32628.75   33764.56

As you can see, for 8,16,32 threads, network TX throughput improve much. For 1 
and 4 threads,
Tx throughput is almost seem before and after patch. This should be sensible as 
this patch
is mainly for decreasing the lock contention.

> 
> [0]
> https://lore.kernel.org/linux-iommu/B926444035E5E2439431908E3842AFD2
> 4b8...@dggemi525-mbs.china.huawei.com/T/#ma02e301c38c3e94b7725e
> 685757c27e39c7cbde3
> 
> Differences to v1:
> - Simplify by dropping patch to always issue a CMD_SYNC
> - Use 64b atomic add, keeping prod in a separate 32b field
> 
> John Garry (2):
>   iommu/arm-smmu-v3: Calculate max commands per batch
>   iommu/arm-smmu-v3: Remove cmpxchg() in
> arm_smmu_cmdq_issue_cmdlist()
> 
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 166
> ++--
>  1 file changed, 114 insertions(+), 52 deletions(-)
> 
> --
> 2.26.2

Thanks
Barry

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


Re: [PATCH 05/28] media/v4l2: remove V4L2-FLAG-MEMORY-NON-CONSISTENT

2020-09-01 Thread Christoph Hellwig
On Thu, Aug 20, 2020 at 07:33:48PM +0200, Tomasz Figa wrote:
> > It wasn't meant to be too insulting, but I found this out when trying
> > to figure out how to just disable it.  But it also ends up using
> > the actual dma attr flags for it's own consistency checks, so just
> > not setting the flag did not turn out to work that easily.
> >
> 
> Yes, sadly the videobuf2 ended up becoming quite counterintuitive
> after growing for the long years and that is reflected in the design
> of this feature as well. I think we need to do something about it.

So I'm about to respin the series and wonder how we should proceed.
I've failed to come up with a clean patch to keep the flag and make
it a no-op.  Can you or your team give it a spin?

Also I wonder if the flag should be renamed from NON_CONSISTENT
to NON_COHERENT - the consistent thing is a weird wart from the times
the old PCI DMA API that is mostly gone now.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


答复: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI device in RMRR

2020-09-01 Thread FelixCui-oc
hi  baolu ,

   These ACPI devices can be retrieved from the kernel and 
there is no bound device driver .


Best regards

Felixcui-oc


发件人: Lu Baolu 
发送时间: 2020年9月1日 14:12:34
收件人: FelixCui-oc; Joerg Roedel; iommu@lists.linux-foundation.org; 
linux-ker...@vger.kernel.org; David Woodhouse; Dan Carpenter; 
kbu...@lists.01.org
抄送: baolu...@linux.intel.com; CobeChen-oc; RaymondPang-oc; Tony W Wang-oc
主题: Re: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI device in RMRR

Hi Felix,

On 8/27/20 6:02 PM, FelixCuioc wrote:
> After acpi device in RMRR is detected,it is necessary
> to establish a mapping for these devices.
> In acpi_device_create_direct_mappings(),create a mapping
> for the acpi device in RMRR.
> Add a helper to achieve the acpi namespace device can
> access the RMRR region.

Are those ACPI devices visible to kernel? If so, any device driver bound
for it?

Best regards,
baolu

>
> Signed-off-by: FelixCuioc 
> ---
>   drivers/iommu/intel/iommu.c | 29 +
>   drivers/iommu/iommu.c   |  6 ++
>   include/linux/iommu.h   |  3 +++
>   3 files changed, 38 insertions(+)
>
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 208a91605288..51d7a5b18f41 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4799,6 +4799,21 @@ static int __init platform_optin_force_iommu(void)
>return 1;
>   }
>
> +static int acpi_device_create_direct_mappings(struct device *pn_dev, struct 
> device *acpi_device)
> +{
> + struct iommu_group *group;
> +
> + acpi_device->bus->iommu_ops = _iommu_ops;
> + group = iommu_group_get(pn_dev);
> + if (!group) {
> + pr_warn("ACPI name space devices create direct mappings 
> wrong!\n");
> + return -EINVAL;
> + }
> + __acpi_device_create_direct_mappings(group, acpi_device);
> +
> + return 0;
> +}
> +
>   static int __init probe_acpi_namespace_devices(void)
>   {
>struct dmar_drhd_unit *drhd;
> @@ -4813,6 +4828,7 @@ static int __init probe_acpi_namespace_devices(void)
>struct acpi_device_physical_node *pn;
>struct iommu_group *group;
>struct acpi_device *adev;
> + struct device *pn_dev = NULL;
>
>if (dev->bus != _bus_type)
>continue;
> @@ -4823,6 +4839,7 @@ static int __init probe_acpi_namespace_devices(void)
>>physical_node_list, node) {
>group = iommu_group_get(pn->dev);
>if (group) {
> + pn_dev = pn->dev;
>iommu_group_put(group);
>continue;
>}
> @@ -4831,7 +4848,19 @@ static int __init probe_acpi_namespace_devices(void)
>ret = iommu_probe_device(pn->dev);
>if (ret)
>break;
> + pn_dev = pn->dev;
> + }
> + if (!pn_dev) {
> + dev->bus->iommu_ops = _iommu_ops;
> + ret = iommu_probe_device(dev);
> + if (ret) {
> + pr_err("acpi_device probe fail! 
> ret:%d\n", ret);
> + goto unlock;
> + }
> + goto unlock;
>}
> + ret = acpi_device_create_direct_mappings(pn_dev, dev);
> +unlock:
>mutex_unlock(>physical_node_lock);
>
>if (ret)
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 609bd25bf154..4f714a2d5ef7 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -779,6 +779,12 @@ static bool iommu_is_attach_deferred(struct iommu_domain 
> *domain,
>return false;
>   }
>
> +void  __acpi_device_create_direct_mappings(struct iommu_group *group, struct 
> device *acpi_device)
> +{
> + iommu_create_device_direct_mappings(group, acpi_device);
> +}
> +EXPORT_SYMBOL_GPL(__acpi_device_create_direct_mappings);
> +
>   /**
>* iommu_group_add_device - add a device to an iommu group
>* @group: the group into which to add the device (reference should be held)
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index fee209efb756..9be134775886 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -514,6 +514,9 @@ extern void iommu_domain_window_disable(struct 
> iommu_domain *domain, u32 wnd_nr)
>   extern int report_iommu_fault(struct iommu_domain *domain, struct device 
> *dev,
>  unsigned long iova, int flags);
>
> +extern 

Re: [patch V2 00/46] x86, PCI, XEN, genirq ...: Prepare for device MSI

2020-09-01 Thread Boqun Feng
Hi Thomas,

On Wed, Aug 26, 2020 at 01:16:28PM +0200, Thomas Gleixner wrote:
[...]
> 
> The whole lot is also available from git:
> 
>git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git device-msi
> 
> This has been tested on Intel/AMD/KVM but lacks testing on:
> 
> - HYPERV (-ENODEV)

FWIW, I did a build and boot test in a hyperv guest with your
development branch, the latest commit is 71cbf478eb6f ("irqchip: Add
IMS (Interrupt Message Storm) driver - NOT FOR MERGING"). And everything
seemed working fine.

If you want me to set/unset a particular CONFIG option or run some
command for testing purposes, please let me know ;-)

Regards,
Bqoun

> - VMD enabled systems (-ENODEV)
> - XEN (-ENOCLUE)
> - IMS (-ENODEV)
> 
> - Any non-X86 code which might depend on the broken compose MSI message
>   logic. Marc excpects not much fallout, but agrees that we need to fix
>   it anyway.
> 
> #1 - #3 should be applied unconditionally for obvious reasons
> #4 - #6 are wortwhile cleanups which should be done independent of device MSI
> 
> #7 - #8 look promising to cleanup the platform MSI implementation
>   independent of #8, but I neither had cycles nor the stomach to
>   tackle that.
> 
> #9is obviously just for the folks interested in IMS
> 
> Thanks,
> 
>   tglx
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 07/11] device-mapping: Introduce DMA range map, supplanting dma_pfn_offset

2020-09-01 Thread Christoph Hellwig
I've applied this to the dma-mapping tree.

I had to resolve a conflict in drivers/of/address.c with a recent
mainline commit.  I also applied the minor tweaks Andy pointed out
plus a few more style changes.  A real change is that I changed the
prototype for dma_copy_dma_range_map to require less boilerplate code.

The result is here:


http://git.infradead.org/users/hch/dma-mapping.git/commitdiff/eef520b232c60e74eb8b33a5a7863ad8f2b4a5c7

please double check that everyting works as expected.

I can cut a stable branch with this if you need it for other trees, but
I'd like to wait a few days to see if there is any fallout first.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


答复: [PATCH v3 1/2] iommu/vt-d:Add support for detecting ACPI device in RMRR

2020-09-01 Thread FelixCui-oc
hi  baolu,

  The function dmar_rmrr_add_acpi_dev() is defined in 
intel/iommu.c because struct dmar_rmrr_unit {} is defined in intel/iommu.c.

  And dmar_parse_one_rmrr()  is also defined here, so we think 
it should be defined in iommu.c.


Best regards
Felixcui-oc


发件人: Lu Baolu 
发送时间: 2020年9月1日 14:05
收件人: FelixCui-oc; Joerg Roedel; iommu@lists.linux-foundation.org; 
linux-ker...@vger.kernel.org; David Woodhouse; Dan Carpenter; 
kbu...@lists.01.org
抄送: baolu...@linux.intel.com; CobeChen-oc; RaymondPang-oc; Tony W Wang-oc
主题: Re: [PATCH v3 1/2] iommu/vt-d:Add support for detecting ACPI device in RMRR

Hi Felix,

On 8/27/20 6:02 PM, FelixCuioc wrote:
> Some ACPI devices need to issue dma requests to access
> the reserved memory area.BIOS uses the device scope type
> ACPI_NAMESPACE_DEVICE in RMRR to report these ACPI devices.
> This patch add support for detecting ACPI devices in RMRR.
>
> Signed-off-by: FelixCuioc 
> ---
>   drivers/iommu/intel/dmar.c  | 76 +
>   drivers/iommu/intel/iommu.c | 23 ++-
>   include/linux/dmar.h| 12 +-
>   3 files changed, 76 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
> index 93e6345f3414..f6691c36bd3f 100644
> --- a/drivers/iommu/intel/dmar.c
> +++ b/drivers/iommu/intel/dmar.c
> @@ -215,7 +215,7 @@ static bool dmar_match_pci_path(struct 
> dmar_pci_notify_info *info, int bus,
>   }
>
>   /* Return: > 0 if match found, 0 if no match found, < 0 if error happens */
> -int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
> +int dmar_pci_insert_dev_scope(struct dmar_pci_notify_info *info,
>  void *start, void*end, u16 segment,
>  struct dmar_dev_scope *devices,
>  int devices_cnt)
> @@ -304,7 +304,7 @@ static int dmar_pci_bus_add_dev(struct 
> dmar_pci_notify_info *info)
>
>drhd = container_of(dmaru->hdr,
>struct acpi_dmar_hardware_unit, header);
> - ret = dmar_insert_dev_scope(info, (void *)(drhd + 1),
> + ret = dmar_pci_insert_dev_scope(info, (void *)(drhd + 1),
>((void *)drhd) + drhd->header.length,
>dmaru->segment,
>dmaru->devices, dmaru->devices_cnt);
> @@ -697,47 +697,59 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
>return dmaru;
>   }
>
> -static void __init dmar_acpi_insert_dev_scope(u8 device_number,
> -   struct acpi_device *adev)
> +/* Return: > 0 if match found, 0 if no match found */
> +bool dmar_acpi_insert_dev_scope(u8 device_number,
> + struct acpi_device *adev,
> + void *start, void *end,
> + struct dmar_dev_scope *devices,
> + int devices_cnt)
>   {
> - struct dmar_drhd_unit *dmaru;
> - struct acpi_dmar_hardware_unit *drhd;
>struct acpi_dmar_device_scope *scope;
>struct device *tmp;
>int i;
>struct acpi_dmar_pci_path *path;
>
> + for (; start < end; start += scope->length) {
> + scope = start;
> + if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_NAMESPACE)
> + continue;
> + if (scope->enumeration_id != device_number)
> + continue;
> + path = (void *)(scope + 1);
> + for_each_dev_scope(devices, devices_cnt, i, tmp)
> + if (tmp == NULL) {
> + devices[i].bus = scope->bus;
> + devices[i].devfn = PCI_DEVFN(path->device, 
> path->function);
> + rcu_assign_pointer(devices[i].dev,
> +get_device(>dev));
> + return true;
> + }
> + WARN_ON(i >= devices_cnt);
> + }
> + return false;
> +}
> +
> +static int dmar_acpi_bus_add_dev(u8 device_number, struct acpi_device *adev)
> +{
> + struct dmar_drhd_unit *dmaru;
> + struct acpi_dmar_hardware_unit *drhd;
> + int ret;
> +
>for_each_drhd_unit(dmaru) {
>drhd = container_of(dmaru->hdr,
>struct acpi_dmar_hardware_unit,
>header);
> + ret = dmar_acpi_insert_dev_scope(device_number, adev, (void 
> *)(drhd+1),
> + ((void 
> *)drhd)+drhd->header.length,
> + dmaru->devices, 
> dmaru->devices_cnt);
> + if (ret)
> + break;
> + }
> + if (ret > 0)
> + ret = dmar_rmrr_add_acpi_dev(device_number, adev);
>
> - for (scope = (void *)(drhd 

Re: [PATCH v8 0/3] make dma_alloc_coherent NUMA-aware by per-NUMA CMA

2020-09-01 Thread Christoph Hellwig
Thanks,

applied to the dma-mapping tree.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v3 2/2] iommu/vt-d:Add support for probing ACPI device in RMRR

2020-09-01 Thread Lu Baolu

Hi Felix,

On 8/27/20 6:02 PM, FelixCuioc wrote:

After acpi device in RMRR is detected,it is necessary
to establish a mapping for these devices.
In acpi_device_create_direct_mappings(),create a mapping
for the acpi device in RMRR.
Add a helper to achieve the acpi namespace device can
access the RMRR region.


Are those ACPI devices visible to kernel? If so, any device driver bound
for it?

Best regards,
baolu



Signed-off-by: FelixCuioc 
---
  drivers/iommu/intel/iommu.c | 29 +
  drivers/iommu/iommu.c   |  6 ++
  include/linux/iommu.h   |  3 +++
  3 files changed, 38 insertions(+)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 208a91605288..51d7a5b18f41 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4799,6 +4799,21 @@ static int __init platform_optin_force_iommu(void)
return 1;
  }
  
+static int acpi_device_create_direct_mappings(struct device *pn_dev, struct device *acpi_device)

+{
+   struct iommu_group *group;
+
+   acpi_device->bus->iommu_ops = _iommu_ops;
+   group = iommu_group_get(pn_dev);
+   if (!group) {
+   pr_warn("ACPI name space devices create direct mappings 
wrong!\n");
+   return -EINVAL;
+   }
+   __acpi_device_create_direct_mappings(group, acpi_device);
+
+   return 0;
+}
+
  static int __init probe_acpi_namespace_devices(void)
  {
struct dmar_drhd_unit *drhd;
@@ -4813,6 +4828,7 @@ static int __init probe_acpi_namespace_devices(void)
struct acpi_device_physical_node *pn;
struct iommu_group *group;
struct acpi_device *adev;
+   struct device *pn_dev = NULL;
  
  			if (dev->bus != _bus_type)

continue;
@@ -4823,6 +4839,7 @@ static int __init probe_acpi_namespace_devices(void)
>physical_node_list, node) {
group = iommu_group_get(pn->dev);
if (group) {
+   pn_dev = pn->dev;
iommu_group_put(group);
continue;
}
@@ -4831,7 +4848,19 @@ static int __init probe_acpi_namespace_devices(void)
ret = iommu_probe_device(pn->dev);
if (ret)
break;
+   pn_dev = pn->dev;
+   }
+   if (!pn_dev) {
+   dev->bus->iommu_ops = _iommu_ops;
+   ret = iommu_probe_device(dev);
+   if (ret) {
+   pr_err("acpi_device probe fail! 
ret:%d\n", ret);
+   goto unlock;
+   }
+   goto unlock;
}
+   ret = acpi_device_create_direct_mappings(pn_dev, dev);
+unlock:
mutex_unlock(>physical_node_lock);
  
  			if (ret)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 609bd25bf154..4f714a2d5ef7 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -779,6 +779,12 @@ static bool iommu_is_attach_deferred(struct iommu_domain 
*domain,
return false;
  }
  
+void  __acpi_device_create_direct_mappings(struct iommu_group *group, struct device *acpi_device)

+{
+   iommu_create_device_direct_mappings(group, acpi_device);
+}
+EXPORT_SYMBOL_GPL(__acpi_device_create_direct_mappings);
+
  /**
   * iommu_group_add_device - add a device to an iommu group
   * @group: the group into which to add the device (reference should be held)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index fee209efb756..9be134775886 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -514,6 +514,9 @@ extern void iommu_domain_window_disable(struct iommu_domain 
*domain, u32 wnd_nr)
  extern int report_iommu_fault(struct iommu_domain *domain, struct device *dev,
  unsigned long iova, int flags);
  
+extern void __acpi_device_create_direct_mappings(struct iommu_group *group,

+   struct device *acpi_device);
+
  static inline void iommu_flush_tlb_all(struct iommu_domain *domain)
  {
if (domain->ops->flush_iotlb_all)


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


Re: [PATCH v3 1/2] iommu/vt-d:Add support for detecting ACPI device in RMRR

2020-09-01 Thread Lu Baolu

Hi Felix,

On 8/27/20 6:02 PM, FelixCuioc wrote:

Some ACPI devices need to issue dma requests to access
the reserved memory area.BIOS uses the device scope type
ACPI_NAMESPACE_DEVICE in RMRR to report these ACPI devices.
This patch add support for detecting ACPI devices in RMRR.

Signed-off-by: FelixCuioc 
---
  drivers/iommu/intel/dmar.c  | 76 +
  drivers/iommu/intel/iommu.c | 23 ++-
  include/linux/dmar.h| 12 +-
  3 files changed, 76 insertions(+), 35 deletions(-)

diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 93e6345f3414..f6691c36bd3f 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -215,7 +215,7 @@ static bool dmar_match_pci_path(struct dmar_pci_notify_info 
*info, int bus,
  }
  
  /* Return: > 0 if match found, 0 if no match found, < 0 if error happens */

-int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
+int dmar_pci_insert_dev_scope(struct dmar_pci_notify_info *info,
  void *start, void*end, u16 segment,
  struct dmar_dev_scope *devices,
  int devices_cnt)
@@ -304,7 +304,7 @@ static int dmar_pci_bus_add_dev(struct dmar_pci_notify_info 
*info)
  
  		drhd = container_of(dmaru->hdr,

struct acpi_dmar_hardware_unit, header);
-   ret = dmar_insert_dev_scope(info, (void *)(drhd + 1),
+   ret = dmar_pci_insert_dev_scope(info, (void *)(drhd + 1),
((void *)drhd) + drhd->header.length,
dmaru->segment,
dmaru->devices, dmaru->devices_cnt);
@@ -697,47 +697,59 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
return dmaru;
  }
  
-static void __init dmar_acpi_insert_dev_scope(u8 device_number,

- struct acpi_device *adev)
+/* Return: > 0 if match found, 0 if no match found */
+bool dmar_acpi_insert_dev_scope(u8 device_number,
+   struct acpi_device *adev,
+   void *start, void *end,
+   struct dmar_dev_scope *devices,
+   int devices_cnt)
  {
-   struct dmar_drhd_unit *dmaru;
-   struct acpi_dmar_hardware_unit *drhd;
struct acpi_dmar_device_scope *scope;
struct device *tmp;
int i;
struct acpi_dmar_pci_path *path;
  
+	for (; start < end; start += scope->length) {

+   scope = start;
+   if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_NAMESPACE)
+   continue;
+   if (scope->enumeration_id != device_number)
+   continue;
+   path = (void *)(scope + 1);
+   for_each_dev_scope(devices, devices_cnt, i, tmp)
+   if (tmp == NULL) {
+   devices[i].bus = scope->bus;
+   devices[i].devfn = PCI_DEVFN(path->device, 
path->function);
+   rcu_assign_pointer(devices[i].dev,
+  get_device(>dev));
+   return true;
+   }
+   WARN_ON(i >= devices_cnt);
+   }
+   return false;
+}
+
+static int dmar_acpi_bus_add_dev(u8 device_number, struct acpi_device *adev)
+{
+   struct dmar_drhd_unit *dmaru;
+   struct acpi_dmar_hardware_unit *drhd;
+   int ret;
+
for_each_drhd_unit(dmaru) {
drhd = container_of(dmaru->hdr,
struct acpi_dmar_hardware_unit,
header);
+   ret = dmar_acpi_insert_dev_scope(device_number, adev, (void 
*)(drhd+1),
+   ((void 
*)drhd)+drhd->header.length,
+   dmaru->devices, 
dmaru->devices_cnt);
+   if (ret)
+   break;
+   }
+   if (ret > 0)
+   ret = dmar_rmrr_add_acpi_dev(device_number, adev);
  
-		for (scope = (void *)(drhd + 1);

-(unsigned long)scope < ((unsigned long)drhd) + 
drhd->header.length;
-scope = ((void *)scope) + scope->length) {
-   if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_NAMESPACE)
-   continue;
-   if (scope->enumeration_id != device_number)
-   continue;
+   return ret;
  
-			path = (void *)(scope + 1);

-   pr_info("ACPI device \"%s\" under DMAR at %llx as 
%02x:%02x.%d\n",
-   dev_name(>dev), dmaru->reg_base_addr,
-   scope->bus, path->device, path->function);


Please keep such information. People are used to use them as a method to
know the hardware