Commit b7d184d3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'iommu-fixes-v5.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu fixes from Joerg Roedel:

 - Fix for a potential NULL-ptr dereference in IOMMU core code

 - Two resource leak fixes

 - Cache flush fix in the Intel VT-d driver

* tag 'iommu-fixes-v5.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/vt-d: Fix incomplete cache flush in intel_pasid_tear_down_entry()
  iommu/vt-d: Fix PASID reference leak
  iommu: Check if group is NULL before remove device
  iommu/dma: Fix leak in non-contiguous API
parents d992fe53 8798d364
...@@ -768,6 +768,7 @@ static void iommu_dma_free_noncontiguous(struct device *dev, size_t size, ...@@ -768,6 +768,7 @@ static void iommu_dma_free_noncontiguous(struct device *dev, size_t size,
__iommu_dma_unmap(dev, sgt->sgl->dma_address, size); __iommu_dma_unmap(dev, sgt->sgl->dma_address, size);
__iommu_dma_free_pages(sh->pages, PAGE_ALIGN(size) >> PAGE_SHIFT); __iommu_dma_free_pages(sh->pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
sg_free_table(&sh->sgt); sg_free_table(&sh->sgt);
kfree(sh);
} }
#endif /* CONFIG_DMA_REMAP */ #endif /* CONFIG_DMA_REMAP */
......
...@@ -511,7 +511,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, ...@@ -511,7 +511,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
u32 pasid, bool fault_ignore) u32 pasid, bool fault_ignore)
{ {
struct pasid_entry *pte; struct pasid_entry *pte;
u16 did; u16 did, pgtt;
pte = intel_pasid_get_entry(dev, pasid); pte = intel_pasid_get_entry(dev, pasid);
if (WARN_ON(!pte)) if (WARN_ON(!pte))
...@@ -521,13 +521,19 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, ...@@ -521,13 +521,19 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
return; return;
did = pasid_get_domain_id(pte); did = pasid_get_domain_id(pte);
pgtt = pasid_pte_get_pgtt(pte);
intel_pasid_clear_entry(dev, pasid, fault_ignore); intel_pasid_clear_entry(dev, pasid, fault_ignore);
if (!ecap_coherent(iommu->ecap)) if (!ecap_coherent(iommu->ecap))
clflush_cache_range(pte, sizeof(*pte)); clflush_cache_range(pte, sizeof(*pte));
pasid_cache_invalidation_with_pasid(iommu, did, pasid); pasid_cache_invalidation_with_pasid(iommu, did, pasid);
qi_flush_piotlb(iommu, did, pasid, 0, -1, 0);
if (pgtt == PASID_ENTRY_PGTT_PT || pgtt == PASID_ENTRY_PGTT_FL_ONLY)
qi_flush_piotlb(iommu, did, pasid, 0, -1, 0);
else
iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
/* Device IOTLB doesn't need to be flushed in caching mode. */ /* Device IOTLB doesn't need to be flushed in caching mode. */
if (!cap_caching_mode(iommu->cap)) if (!cap_caching_mode(iommu->cap))
......
...@@ -99,6 +99,12 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte) ...@@ -99,6 +99,12 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte)
return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT; return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT;
} }
/* Get PGTT field of a PASID table entry */
static inline u16 pasid_pte_get_pgtt(struct pasid_entry *pte)
{
return (u16)((READ_ONCE(pte->val[0]) >> 6) & 0x7);
}
extern unsigned int intel_pasid_max_id; extern unsigned int intel_pasid_max_id;
int intel_pasid_alloc_table(struct device *dev); int intel_pasid_alloc_table(struct device *dev);
void intel_pasid_free_table(struct device *dev); void intel_pasid_free_table(struct device *dev);
......
...@@ -675,7 +675,6 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid) ...@@ -675,7 +675,6 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
kfree_rcu(sdev, rcu); kfree_rcu(sdev, rcu);
if (list_empty(&svm->devs)) { if (list_empty(&svm->devs)) {
intel_svm_free_pasid(mm);
if (svm->notifier.ops) { if (svm->notifier.ops) {
mmu_notifier_unregister(&svm->notifier, mm); mmu_notifier_unregister(&svm->notifier, mm);
/* Clear mm's pasid. */ /* Clear mm's pasid. */
...@@ -690,6 +689,8 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid) ...@@ -690,6 +689,8 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
kfree(svm); kfree(svm);
} }
} }
/* Drop a PASID reference and free it if no reference. */
intel_svm_free_pasid(mm);
} }
out: out:
return ret; return ret;
......
...@@ -924,6 +924,9 @@ void iommu_group_remove_device(struct device *dev) ...@@ -924,6 +924,9 @@ void iommu_group_remove_device(struct device *dev)
struct iommu_group *group = dev->iommu_group; struct iommu_group *group = dev->iommu_group;
struct group_device *tmp_device, *device = NULL; struct group_device *tmp_device, *device = NULL;
if (!group)
return;
dev_info(dev, "Removing from iommu group %d\n", group->id); dev_info(dev, "Removing from iommu group %d\n", group->id);
/* Pre-notify listeners that a device is being removed. */ /* Pre-notify listeners that a device is being removed. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment