Re: [Xen-devel] [PATCH v8 09/11] vt-d: fix the IOMMU flush issue

2016-06-14 Thread Tian, Kevin
> From: Xu, Quan
> Sent: Tuesday, June 14, 2016 5:04 PM
> 
> On June 14, 2016 4:27 PM, Jan Beulich  wrote:
> > >>> On 14.06.16 at 10:10,  wrote:
> > > On June 13, 2016 11:52 PM, Jan Beulich  wrote:
> > >> >>> "Xu, Quan"  06/13/16 5:22 PM >>>
> > >> >From: Quan Xu 
> > >> >@@ -546,17 +550,37 @@ static int __must_check iommu_flush_all(void)
> > >> >struct acpi_drhd_unit *drhd; struct iommu *iommu; int
> > >> >flush_dev_iotlb;
> > >> >+int rc = 0;
> > >>  >
> > >> >flush_all_cache();
> > >> >for_each_drhd_unit ( drhd )
> > >> >{
> > >> >+int iommu_rc, iommu_ret;
> > >> >+
> > >> >iommu = drhd->iommu;
> > >> >-iommu_flush_context_global(iommu, 0);
> > >> >+iommu_rc = iommu_flush_context_global(iommu, 0);
> > >> >flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0;
> > >> >-iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
> > >> >+iommu_ret = iommu_flush_iotlb_global(iommu, 0,
> > >> >+ flush_dev_iotlb);
> > >> >+
> > >> >+/*
> > >> >+ * The current logic for returns:
> > >> >+ *   - positive  invoke iommu_flush_write_buffer to flush 
> > >> >cache.
> > >> >+ *   - zero  on success.
> > >> >+ *   - negative  on failure. Continue to flush IOMMU IOTLB on a
> > >> >+ *   best effort basis.
> > >> >+ */
> > >> >+if ( iommu_rc > 0 || iommu_ret > 0 )
> > >> >+iommu_flush_write_buffer(iommu);
> > >> >+if ( rc >= 0 )
> > >> >+rc = iommu_rc;
> > >> >+if ( rc >= 0 )
> > >> >+rc = iommu_ret;
> > >>
> > >> First of all - is it correct to fold the two
> > >> iommu_flush_write_buffer() invocations?
> > >>
> > >
> > > Sure, it is correct..
> > >
> > > as:
> > > - For updates to remapping hardware structures that require
> > > context-cache, PASID-cache, IOTLB or IEC invalidation Operations to
> > > flush stale entries from the hardware caches, no additional action is
> > > required to make the modification Visible to hardware. This is
> > > because, hardware performs an implicit write-buffer-flushing as a
> > > pre-condition to context-cache, PASID-cache, IOTLB and IEC
> > > invalidation operations.
> > >
> > > - For updates to remapping hardware structures (such as modifying a
> > > currently not-present entry) that do not require Context-cache, IOTLB,
> > > or IEC invalidations, software must explicitly perform
> > > write-buffer-flushing to ensure the updated structures Are visible to
> > > hardware.
> >
> > But that's not the point. Instead my question was related to Kevin's concern
> > towards you making assumptions on the behavior of
> > iommu_flush_context_global() vs iommu_flush_iotlb_global(): What if the
> > first returned 1 but the second didn't?
> > It would seem to me that in such a
> > (theoretical) case iommu_flush_write_buffer() might need to be invoked prior
> > to the second flush function.
> 
> In this case, it is correct too.
> As , hardware performs an __implicit__ write-buffer-flushing as a 
> __pre-condition__ to
> IOTLB invalidation operation.
> So software is no need to call iommu_flush_write_buffer() to explicitly 
> perform
> write-buffer-flushing for that the first returned 1.
> 

Yes, there is no issue doing so based on spec.

Thanks
Kevin

___
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel


Re: [Xen-devel] [PATCH v8 09/11] vt-d: fix the IOMMU flush issue

2016-06-14 Thread Xu, Quan
On June 14, 2016 4:27 PM, Jan Beulich  wrote: 
> >>> On 14.06.16 at 10:10,  wrote:
> > On June 13, 2016 11:52 PM, Jan Beulich  wrote:
> >> >>> "Xu, Quan"  06/13/16 5:22 PM >>>
> >> >From: Quan Xu 
> >> >@@ -546,17 +550,37 @@ static int __must_check iommu_flush_all(void)
> >> >struct acpi_drhd_unit *drhd; struct iommu *iommu; int
> >> >flush_dev_iotlb;
> >> >+int rc = 0;
> >>  >
> >> >flush_all_cache();
> >> >for_each_drhd_unit ( drhd )
> >> >{
> >> >+int iommu_rc, iommu_ret;
> >> >+
> >> >iommu = drhd->iommu;
> >> >-iommu_flush_context_global(iommu, 0);
> >> >+iommu_rc = iommu_flush_context_global(iommu, 0);
> >> >flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0;
> >> >-iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
> >> >+iommu_ret = iommu_flush_iotlb_global(iommu, 0,
> >> >+ flush_dev_iotlb);
> >> >+
> >> >+/*
> >> >+ * The current logic for returns:
> >> >+ *   - positive  invoke iommu_flush_write_buffer to flush cache.
> >> >+ *   - zero  on success.
> >> >+ *   - negative  on failure. Continue to flush IOMMU IOTLB on a
> >> >+ *   best effort basis.
> >> >+ */
> >> >+if ( iommu_rc > 0 || iommu_ret > 0 )
> >> >+iommu_flush_write_buffer(iommu);
> >> >+if ( rc >= 0 )
> >> >+rc = iommu_rc;
> >> >+if ( rc >= 0 )
> >> >+rc = iommu_ret;
> >>
> >> First of all - is it correct to fold the two
> >> iommu_flush_write_buffer() invocations?
> >>
> >
> > Sure, it is correct..
> >
> > as:
> > - For updates to remapping hardware structures that require
> > context-cache, PASID-cache, IOTLB or IEC invalidation Operations to
> > flush stale entries from the hardware caches, no additional action is
> > required to make the modification Visible to hardware. This is
> > because, hardware performs an implicit write-buffer-flushing as a
> > pre-condition to context-cache, PASID-cache, IOTLB and IEC
> > invalidation operations.
> >
> > - For updates to remapping hardware structures (such as modifying a
> > currently not-present entry) that do not require Context-cache, IOTLB,
> > or IEC invalidations, software must explicitly perform
> > write-buffer-flushing to ensure the updated structures Are visible to
> > hardware.
> 
> But that's not the point. Instead my question was related to Kevin's concern
> towards you making assumptions on the behavior of
> iommu_flush_context_global() vs iommu_flush_iotlb_global(): What if the
> first returned 1 but the second didn't?
> It would seem to me that in such a
> (theoretical) case iommu_flush_write_buffer() might need to be invoked prior
> to the second flush function.

In this case, it is correct too.
As , hardware performs an __implicit__ write-buffer-flushing as a 
__pre-condition__ to IOTLB invalidation operation.
So software is no need to call iommu_flush_write_buffer() to explicitly perform 
write-buffer-flushing for that the first returned 1.

Quan

___
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel


Re: [Xen-devel] [PATCH v8 09/11] vt-d: fix the IOMMU flush issue

2016-06-14 Thread Jan Beulich
>>> On 14.06.16 at 10:10,  wrote:
> On June 13, 2016 11:52 PM, Jan Beulich  wrote:
>> >>> "Xu, Quan"  06/13/16 5:22 PM >>>
>> >From: Quan Xu 
>> >@@ -546,17 +550,37 @@ static int __must_check iommu_flush_all(void)
>> >struct acpi_drhd_unit *drhd; struct iommu *iommu; int flush_dev_iotlb;
>> >+int rc = 0;
>>  >
>> >flush_all_cache();
>> >for_each_drhd_unit ( drhd )
>> >{
>> >+int iommu_rc, iommu_ret;
>> >+
>> >iommu = drhd->iommu;
>> >-iommu_flush_context_global(iommu, 0);
>> >+iommu_rc = iommu_flush_context_global(iommu, 0);
>> >flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0;
>> >-iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
>> >+iommu_ret = iommu_flush_iotlb_global(iommu, 0,
>> >+ flush_dev_iotlb);
>> >+
>> >+/*
>> >+ * The current logic for returns:
>> >+ *   - positive  invoke iommu_flush_write_buffer to flush cache.
>> >+ *   - zero  on success.
>> >+ *   - negative  on failure. Continue to flush IOMMU IOTLB on a
>> >+ *   best effort basis.
>> >+ */
>> >+if ( iommu_rc > 0 || iommu_ret > 0 )
>> >+iommu_flush_write_buffer(iommu);
>> >+if ( rc >= 0 )
>> >+rc = iommu_rc;
>> >+if ( rc >= 0 )
>> >+rc = iommu_ret;
>> 
>> First of all - is it correct to fold the two iommu_flush_write_buffer()
>> invocations?
>> 
> 
> Sure, it is correct.. 
> 
> as:
> - For updates to remapping hardware structures that require context-cache, 
> PASID-cache, IOTLB or IEC invalidation
> Operations to flush stale entries from the hardware caches, no additional 
> action is required to make the modification
> Visible to hardware. This is because, hardware performs an implicit 
> write-buffer-flushing as a pre-condition to context-cache,
> PASID-cache, IOTLB and IEC invalidation operations.
> 
> - For updates to remapping hardware structures (such as modifying a currently 
> not-present entry) that do not require
> Context-cache, IOTLB, or IEC invalidations, software must explicitly perform 
> write-buffer-flushing to ensure the updated structures
> Are visible to hardware.

But that's not the point. Instead my question was related to Kevin's
concern towards you making assumptions on the behavior of
iommu_flush_context_global() vs iommu_flush_iotlb_global(): What
if the first returned 1 but the second didn't? It would seem to me
that in such a (theoretical) case iommu_flush_write_buffer() might
need to be invoked prior to the second flush function.

Jan


___
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel


Re: [Xen-devel] [PATCH v8 09/11] vt-d: fix the IOMMU flush issue

2016-06-14 Thread Xu, Quan
On June 13, 2016 11:52 PM, Jan Beulich  wrote:
> >>> "Xu, Quan"  06/13/16 5:22 PM >>>
> >From: Quan Xu 
> >@@ -546,17 +550,37 @@ static int __must_check iommu_flush_all(void)
> >struct acpi_drhd_unit *drhd; struct iommu *iommu; int flush_dev_iotlb;
> >+int rc = 0;
>  >
> >flush_all_cache();
> >for_each_drhd_unit ( drhd )
> >{
> >+int iommu_rc, iommu_ret;
> >+
> >iommu = drhd->iommu;
> >-iommu_flush_context_global(iommu, 0);
> >+iommu_rc = iommu_flush_context_global(iommu, 0);
> >flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0;
> >-iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
> >+iommu_ret = iommu_flush_iotlb_global(iommu, 0,
> >+ flush_dev_iotlb);
> >+
> >+/*
> >+ * The current logic for returns:
> >+ *   - positive  invoke iommu_flush_write_buffer to flush cache.
> >+ *   - zero  on success.
> >+ *   - negative  on failure. Continue to flush IOMMU IOTLB on a
> >+ *   best effort basis.
> >+ */
> >+if ( iommu_rc > 0 || iommu_ret > 0 )
> >+iommu_flush_write_buffer(iommu);
> >+if ( rc >= 0 )
> >+rc = iommu_rc;
> >+if ( rc >= 0 )
> >+rc = iommu_ret;
> 
> First of all - is it correct to fold the two iommu_flush_write_buffer()
> invocations?
> 

Sure, it is correct.. 

as:
- For updates to remapping hardware structures that require context-cache, 
PASID-cache, IOTLB or IEC invalidation
Operations to flush stale entries from the hardware caches, no additional 
action is required to make the modification
Visible to hardware. This is because, hardware performs an implicit 
write-buffer-flushing as a pre-condition to context-cache,
PASID-cache, IOTLB and IEC invalidation operations.

- For updates to remapping hardware structures (such as modifying a currently 
not-present entry) that do not require
Context-cache, IOTLB, or IEC invalidations, software must explicitly perform 
write-buffer-flushing to ensure the updated structures
Are visible to hardware.



> And then the variable naming is strange - both operations are IOMMU ones,
> so prefixing the variables with iommu_ doesn't help much here. How about
> ctxt_rc and iotlb_rc or some such?
> 

To align to that file, I'm better using context_rc  and iotlb_rc..

Quan

___
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel


Re: [Xen-devel] [PATCH v8 09/11] vt-d: fix the IOMMU flush issue

2016-06-13 Thread Jan Beulich
>>> "Xu, Quan"  06/13/16 5:22 PM >>>
>From: Quan Xu 
>
>The propagation value from IOMMU flush interfaces may be positive, which
>indicates callers need to flush cache, not one of faliures.
>
>when the propagation value is positive, this patch fixes this flush issue
>as follows:
>- call iommu_flush_write_buffer() to flush cache.
>- return zero.
>
>Signed-off-by: Quan Xu 
>Reviewed-by: Jan Beulich 
>
>CC: Kevin Tian 
>CC: Feng Wu 
>CC: Keir Fraser 
>CC: Jan Beulich 
>CC: Andrew Cooper 
>
>v8: drop assertion and check both flush_context and flush_iotlb
>whether the return values are positive.
>(note: this change is not under Jan's R-b).

In which case you should simply have dropped it.

>@@ -546,17 +550,37 @@ static int __must_check iommu_flush_all(void)
>struct acpi_drhd_unit *drhd;
>struct iommu *iommu;
>int flush_dev_iotlb;
>+int rc = 0;
 >
>flush_all_cache();
>for_each_drhd_unit ( drhd )
>{
>+int iommu_rc, iommu_ret;
>+
>iommu = drhd->iommu;
>-iommu_flush_context_global(iommu, 0);
>+iommu_rc = iommu_flush_context_global(iommu, 0);
>flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0;
>-iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
>+iommu_ret = iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
>+
>+/*
>+ * The current logic for returns:
>+ *   - positive  invoke iommu_flush_write_buffer to flush cache.
>+ *   - zero  on success.
>+ *   - negative  on failure. Continue to flush IOMMU IOTLB on a
>+ *   best effort basis.
>+ */
>+if ( iommu_rc > 0 || iommu_ret > 0 )
>+iommu_flush_write_buffer(iommu);
>+if ( rc >= 0 )
>+rc = iommu_rc;
>+if ( rc >= 0 )
>+rc = iommu_ret;

First of all - is it correct to fold the two iommu_flush_write_buffer() 
invocations?

And then the variable naming is strange - both operations are IOMMU ones, so
prefixing the variables with iommu_ doesn't help much here. How about ctxt_rc
and iotlb_rc or some such?

Jan


___
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel


[Xen-devel] [PATCH v8 09/11] vt-d: fix the IOMMU flush issue

2016-06-13 Thread Xu, Quan
From: Quan Xu 

The propagation value from IOMMU flush interfaces may be positive, which
indicates callers need to flush cache, not one of faliures.

when the propagation value is positive, this patch fixes this flush issue
as follows:
  - call iommu_flush_write_buffer() to flush cache.
  - return zero.

Signed-off-by: Quan Xu 
Reviewed-by: Jan Beulich 

CC: Kevin Tian 
CC: Feng Wu 
CC: Keir Fraser 
CC: Jan Beulich 
CC: Andrew Cooper 

v8: drop assertion and check both flush_context and flush_iotlb
whether the return values are positive.
(note: this change is not under Jan's R-b).
---
 xen/drivers/passthrough/vtd/iommu.c | 150 +---
 1 file changed, 103 insertions(+), 47 deletions(-)

diff --git a/xen/drivers/passthrough/vtd/iommu.c 
b/xen/drivers/passthrough/vtd/iommu.c
index 48edb67..2f046cb 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -388,17 +388,18 @@ static int flush_context_reg(
 return 0;
 }
 
-static int iommu_flush_context_global(
-struct iommu *iommu, int flush_non_present_entry)
+static int __must_check iommu_flush_context_global(struct iommu *iommu,
+   int flush_non_present_entry)
 {
 struct iommu_flush *flush = iommu_get_flush(iommu);
 return flush->context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
  flush_non_present_entry);
 }
 
-static int iommu_flush_context_device(
-struct iommu *iommu, u16 did, u16 source_id,
-u8 function_mask, int flush_non_present_entry)
+static int __must_check iommu_flush_context_device(struct iommu *iommu,
+   u16 did, u16 source_id,
+   u8 function_mask,
+   int flush_non_present_entry)
 {
 struct iommu_flush *flush = iommu_get_flush(iommu);
 return flush->context(iommu, did, source_id, function_mask,
@@ -473,8 +474,9 @@ static int flush_iotlb_reg(void *_iommu, u16 did,
 return 0;
 }
 
-static int iommu_flush_iotlb_global(struct iommu *iommu,
-int flush_non_present_entry, int flush_dev_iotlb)
+static int __must_check iommu_flush_iotlb_global(struct iommu *iommu,
+ int flush_non_present_entry,
+ int flush_dev_iotlb)
 {
 struct iommu_flush *flush = iommu_get_flush(iommu);
 int status;
@@ -491,8 +493,9 @@ static int iommu_flush_iotlb_global(struct iommu *iommu,
 return status;
 }
 
-static int iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did,
-int flush_non_present_entry, int flush_dev_iotlb)
+static int __must_check iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did,
+  int flush_non_present_entry,
+  int flush_dev_iotlb)
 {
 struct iommu_flush *flush = iommu_get_flush(iommu);
 int status;
@@ -509,9 +512,10 @@ static int iommu_flush_iotlb_dsi(struct iommu *iommu, u16 
did,
 return status;
 }
 
-static int iommu_flush_iotlb_psi(
-struct iommu *iommu, u16 did, u64 addr, unsigned int order,
-int flush_non_present_entry, int flush_dev_iotlb)
+static int __must_check iommu_flush_iotlb_psi(struct iommu *iommu, u16 did,
+  u64 addr, unsigned int order,
+  int flush_non_present_entry,
+  int flush_dev_iotlb)
 {
 struct iommu_flush *flush = iommu_get_flush(iommu);
 int status;
@@ -546,17 +550,37 @@ static int __must_check iommu_flush_all(void)
 struct acpi_drhd_unit *drhd;
 struct iommu *iommu;
 int flush_dev_iotlb;
+int rc = 0;
 
 flush_all_cache();
 for_each_drhd_unit ( drhd )
 {
+int iommu_rc, iommu_ret;
+
 iommu = drhd->iommu;
-iommu_flush_context_global(iommu, 0);
+iommu_rc = iommu_flush_context_global(iommu, 0);
 flush_dev_iotlb = find_ats_dev_drhd(iommu) ? 1 : 0;
-iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
+iommu_ret = iommu_flush_iotlb_global(iommu, 0, flush_dev_iotlb);
+
+/*
+ * The current logic for returns:
+ *   - positive  invoke iommu_flush_write_buffer to flush cache.
+ *   - zero  on success.
+ *   - negative  on failure. Continue to flush IOMMU IOTLB on a
+ *   best effort basis.
+ */
+if ( iommu_rc > 0 || iommu_ret > 0 )
+iommu_flush_write_buffer(iommu);
+if ( rc >= 0 )
+rc = iommu_rc;
+if ( rc >= 0 )
+rc = iommu_ret;
 }
 
-return 0;
+if ( rc > 0 )
+rc = 0;
+
+return rc;
 }
 
 static int __must_check iommu_flush_iotlb(struct domain *d,
@@ -569,6 +593,7 @@ static int __must_check iommu_flush_iotlb(struct domain *d,