RE: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices

2021-01-06 Thread Liu, Yi L
Hi Will,

> From: Will Deacon 
> Sent: Wednesday, January 6, 2021 1:24 AM
> 
> On Tue, Jan 05, 2021 at 05:50:22AM +, Liu, Yi L wrote:
> > > > +static void __iommu_flush_dev_iotlb(struct device_domain_info
> *info,
> > > > +   u64 addr, unsigned int mask)
> > > > +{
> > > > +   u16 sid, qdep;
> > > > +
> > > > +   if (!info || !info->ats_enabled)
> > > > +   return;
> > > > +
> > > > +   sid = info->bus << 8 | info->devfn;
> > > > +   qdep = info->ats_qdep;
> > > > +   qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > > +  qdep, addr, mask);
> > > > +}
> > > > +
> > > >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> > > >   u64 addr, unsigned mask)
> > > >   {
> > > > -   u16 sid, qdep;
> > > > unsigned long flags;
> > > > struct device_domain_info *info;
> > > > +   struct subdev_domain_info *sinfo;
> > > >
> > > > if (!domain->has_iotlb_device)
> > > > return;
> > > >
> > > > spin_lock_irqsave(_domain_lock, flags);
> > > > -   list_for_each_entry(info, >devices, link) {
> > > > -   if (!info->ats_enabled)
> > > > -   continue;
> > > > +   list_for_each_entry(info, >devices, link)
> > > > +   __iommu_flush_dev_iotlb(info, addr, mask);
> > > >
> > > > -   sid = info->bus << 8 | info->devfn;
> > > > -   qdep = info->ats_qdep;
> > > > -   qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > > -   qdep, addr, mask);
> > > > +   list_for_each_entry(sinfo, >subdevices, link_domain) {
> > > > +   __iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > > > +   addr, mask);
> > > > }
> > >
> > > Nit:
> > >   list_for_each_entry(sinfo, >subdevices, link_domain) {
> > >   info = get_domain_info(sinfo->pdev);
> > >   __iommu_flush_dev_iotlb(info, addr, mask);
> > >   }
> >
> > you are right. this should be better.
> 
> Please can you post a v4, with Lu's acks and the issue reported by Dan fixed
> too?

sure, will send out later.

Regards,
Yi Liu

> Thanks,
> 
> Will


Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices

2021-01-05 Thread Will Deacon
On Tue, Jan 05, 2021 at 05:50:22AM +, Liu, Yi L wrote:
> > > +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> > > + u64 addr, unsigned int mask)
> > > +{
> > > + u16 sid, qdep;
> > > +
> > > + if (!info || !info->ats_enabled)
> > > + return;
> > > +
> > > + sid = info->bus << 8 | info->devfn;
> > > + qdep = info->ats_qdep;
> > > + qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > +qdep, addr, mask);
> > > +}
> > > +
> > >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> > > u64 addr, unsigned mask)
> > >   {
> > > - u16 sid, qdep;
> > >   unsigned long flags;
> > >   struct device_domain_info *info;
> > > + struct subdev_domain_info *sinfo;
> > >
> > >   if (!domain->has_iotlb_device)
> > >   return;
> > >
> > >   spin_lock_irqsave(_domain_lock, flags);
> > > - list_for_each_entry(info, >devices, link) {
> > > - if (!info->ats_enabled)
> > > - continue;
> > > + list_for_each_entry(info, >devices, link)
> > > + __iommu_flush_dev_iotlb(info, addr, mask);
> > >
> > > - sid = info->bus << 8 | info->devfn;
> > > - qdep = info->ats_qdep;
> > > - qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > - qdep, addr, mask);
> > > + list_for_each_entry(sinfo, >subdevices, link_domain) {
> > > + __iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > > + addr, mask);
> > >   }
> > 
> > Nit:
> > list_for_each_entry(sinfo, >subdevices, link_domain) {
> > info = get_domain_info(sinfo->pdev);
> > __iommu_flush_dev_iotlb(info, addr, mask);
> > }
> 
> you are right. this should be better.

Please can you post a v4, with Lu's acks and the issue reported by Dan fixed
too?

Thanks,

Will


RE: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices

2021-01-04 Thread Liu, Yi L
Hi Baolu,

> From: Lu Baolu 
> Sent: Tuesday, December 29, 2020 4:42 PM
> 
> Hi Yi,
> 
> On 2020/12/29 11:25, Liu Yi L wrote:
> > iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
> > loops the devices which are full-attached to the domain. For sub-devices,
> > this is ineffective. This results in invalid caching entries left on the
> > device. Fix it by adding loop for subdevices as well. Also, the domain->
> > has_iotlb_device needs to be updated when attaching to subdevices.
> >
> > Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain
> attach/detach")
> > Signed-off-by: Liu Yi L 
> > ---
> >   drivers/iommu/intel/iommu.c | 53 ++-
> --
> >   1 file changed, 37 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> > index d7720a836268..d48a60b61ba6 100644
> > --- a/drivers/iommu/intel/iommu.c
> > +++ b/drivers/iommu/intel/iommu.c
> > @@ -719,6 +719,8 @@ static int domain_update_device_node(struct
> dmar_domain *domain)
> > return nid;
> >   }
> >
> > +static void domain_update_iotlb(struct dmar_domain *domain);
> > +
> >   /* Some capabilities may be different across iommus */
> >   static void domain_update_iommu_cap(struct dmar_domain *domain)
> >   {
> > @@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct
> dmar_domain *domain)
> > domain->domain.geometry.aperture_end =
> __DOMAIN_MAX_ADDR(domain->gaw - 1);
> > else
> > domain->domain.geometry.aperture_end =
> __DOMAIN_MAX_ADDR(domain->gaw);
> > +
> > +   domain_update_iotlb(domain);
> >   }
> >
> >   struct context_entry *iommu_context_addr(struct intel_iommu *iommu,
> u8 bus,
> > @@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct
> dmar_domain *domain)
> >
> > assert_spin_locked(_domain_lock);
> >
> > -   list_for_each_entry(info, >devices, link) {
> > -   struct pci_dev *pdev;
> > -
> > -   if (!info->dev || !dev_is_pci(info->dev))
> > -   continue;
> > -
> > -   pdev = to_pci_dev(info->dev);
> > -   if (pdev->ats_enabled) {
> > +   list_for_each_entry(info, >devices, link)
> > +   if (info && info->ats_enabled) {
> > has_iotlb_device = true;
> > break;
> > }
> > +
> > +   if (!has_iotlb_device) {
> > +   struct subdev_domain_info *sinfo;
> > +
> > +   list_for_each_entry(sinfo, >subdevices,
> link_domain) {
> > +   info = get_domain_info(sinfo->pdev);
> > +   if (info && info->ats_enabled) {
> > +   has_iotlb_device = true;
> > +   break;
> > +   }
> > +   }
> > }
> >
> > domain->has_iotlb_device = has_iotlb_device;
> > @@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct
> device_domain_info *info)
> >   #endif
> >   }
> >
> > +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> > +   u64 addr, unsigned int mask)
> > +{
> > +   u16 sid, qdep;
> > +
> > +   if (!info || !info->ats_enabled)
> > +   return;
> > +
> > +   sid = info->bus << 8 | info->devfn;
> > +   qdep = info->ats_qdep;
> > +   qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > +  qdep, addr, mask);
> > +}
> > +
> >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> >   u64 addr, unsigned mask)
> >   {
> > -   u16 sid, qdep;
> > unsigned long flags;
> > struct device_domain_info *info;
> > +   struct subdev_domain_info *sinfo;
> >
> > if (!domain->has_iotlb_device)
> > return;
> >
> > spin_lock_irqsave(_domain_lock, flags);
> > -   list_for_each_entry(info, >devices, link) {
> > -   if (!info->ats_enabled)
> > -   continue;
> > +   list_for_each_entry(info, >devices, link)
> > +   __iommu_flush_dev_iotlb(info, addr, mask);
> >
> > -   sid = info->bus << 8 | info->devfn;
> > -   qdep = info->ats_qdep;
> > -   qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > -   qdep, addr, mask);
> > +   list_for_each_entry(sinfo, >subdevices, link_domain) {
> > +   __iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > +   addr, mask);
> > }
> 
> Nit:
>   list_for_each_entry(sinfo, >subdevices, link_domain) {
>   info = get_domain_info(sinfo->pdev);
>   __iommu_flush_dev_iotlb(info, addr, mask);
>   }

you are right. this should be better.

> Others look good to me.
>
> Acked-by: Lu Baolu 
> 
> Best regards,
> baolu

Regards,
Yi Liu

> > spin_unlock_irqrestore(_domain_lock, flags);
> >   }
> >


Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices

2020-12-29 Thread Lu Baolu

Hi Yi,

On 2020/12/29 11:25, Liu Yi L wrote:

iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
loops the devices which are full-attached to the domain. For sub-devices,
this is ineffective. This results in invalid caching entries left on the
device. Fix it by adding loop for subdevices as well. Also, the domain->
has_iotlb_device needs to be updated when attaching to subdevices.

Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain attach/detach")
Signed-off-by: Liu Yi L 
---
  drivers/iommu/intel/iommu.c | 53 ++---
  1 file changed, 37 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index d7720a836268..d48a60b61ba6 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -719,6 +719,8 @@ static int domain_update_device_node(struct dmar_domain 
*domain)
return nid;
  }
  
+static void domain_update_iotlb(struct dmar_domain *domain);

+
  /* Some capabilities may be different across iommus */
  static void domain_update_iommu_cap(struct dmar_domain *domain)
  {
@@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct dmar_domain 
*domain)
domain->domain.geometry.aperture_end = 
__DOMAIN_MAX_ADDR(domain->gaw - 1);
else
domain->domain.geometry.aperture_end = 
__DOMAIN_MAX_ADDR(domain->gaw);
+
+   domain_update_iotlb(domain);
  }
  
  struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,

@@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct dmar_domain 
*domain)
  
  	assert_spin_locked(_domain_lock);
  
-	list_for_each_entry(info, >devices, link) {

-   struct pci_dev *pdev;
-
-   if (!info->dev || !dev_is_pci(info->dev))
-   continue;
-
-   pdev = to_pci_dev(info->dev);
-   if (pdev->ats_enabled) {
+   list_for_each_entry(info, >devices, link)
+   if (info && info->ats_enabled) {
has_iotlb_device = true;
break;
}
+
+   if (!has_iotlb_device) {
+   struct subdev_domain_info *sinfo;
+
+   list_for_each_entry(sinfo, >subdevices, link_domain) {
+   info = get_domain_info(sinfo->pdev);
+   if (info && info->ats_enabled) {
+   has_iotlb_device = true;
+   break;
+   }
+   }
}
  
  	domain->has_iotlb_device = has_iotlb_device;

@@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct 
device_domain_info *info)
  #endif
  }
  
+static void __iommu_flush_dev_iotlb(struct device_domain_info *info,

+   u64 addr, unsigned int mask)
+{
+   u16 sid, qdep;
+
+   if (!info || !info->ats_enabled)
+   return;
+
+   sid = info->bus << 8 | info->devfn;
+   qdep = info->ats_qdep;
+   qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
+  qdep, addr, mask);
+}
+
  static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
  u64 addr, unsigned mask)
  {
-   u16 sid, qdep;
unsigned long flags;
struct device_domain_info *info;
+   struct subdev_domain_info *sinfo;
  
  	if (!domain->has_iotlb_device)

return;
  
  	spin_lock_irqsave(_domain_lock, flags);

-   list_for_each_entry(info, >devices, link) {
-   if (!info->ats_enabled)
-   continue;
+   list_for_each_entry(info, >devices, link)
+   __iommu_flush_dev_iotlb(info, addr, mask);
  
-		sid = info->bus << 8 | info->devfn;

-   qdep = info->ats_qdep;
-   qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
-   qdep, addr, mask);
+   list_for_each_entry(sinfo, >subdevices, link_domain) {
+   __iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
+   addr, mask);
}


Nit:
list_for_each_entry(sinfo, >subdevices, link_domain) {
info = get_domain_info(sinfo->pdev);
__iommu_flush_dev_iotlb(info, addr, mask);
}

Others look good to me.

Acked-by: Lu Baolu 

Best regards,
baolu


spin_unlock_irqrestore(_domain_lock, flags);
  }