| From bc9fc372ac68dcd7d57100c39b91583687e6d19e Mon Sep 17 00:00:00 2001 |
| From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> |
| Date: Thu, 24 Jan 2019 04:16:45 +0000 |
| Subject: iommu/amd: Fix IOMMU page flush when detach device from a domain |
| |
| [ Upstream commit 9825bd94e3a2baae1f4874767ae3a7d4c049720e ] |
| |
| When a VM is terminated, the VFIO driver detaches all pass-through |
| devices from VFIO domain by clearing domain id and page table root |
| pointer from each device table entry (DTE), and then invalidates |
| the DTE. Then, the VFIO driver unmap pages and invalidate IOMMU pages. |
| |
| Currently, the IOMMU driver keeps track of which IOMMU and how many |
| devices are attached to the domain. When invalidate IOMMU pages, |
| the driver checks if the IOMMU is still attached to the domain before |
| issuing the invalidate page command. |
| |
| However, since VFIO has already detached all devices from the domain, |
| the subsequent INVALIDATE_IOMMU_PAGES commands are being skipped as |
| there is no IOMMU attached to the domain. This results in data |
| corruption and could cause the PCI device to end up in indeterministic |
| state. |
| |
| Fix this by invalidate IOMMU pages when detach a device, and |
| before decrementing the per-domain device reference counts. |
| |
| Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> |
| Suggested-by: Joerg Roedel <joro@8bytes.org> |
| Co-developed-by: Brijesh Singh <brijesh.singh@amd.com> |
| Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> |
| Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> |
| Fixes: 6de8ad9b9ee0 ('x86/amd-iommu: Make iommu_flush_pages aware of multiple IOMMUs') |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/iommu/amd_iommu.c | 15 +++++++++++---- |
| 1 file changed, 11 insertions(+), 4 deletions(-) |
| |
| diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c |
| index 2ab87e3f07e6..27500abe8ca7 100644 |
| --- a/drivers/iommu/amd_iommu.c |
| +++ b/drivers/iommu/amd_iommu.c |
| @@ -1929,16 +1929,13 @@ static void do_attach(struct iommu_dev_data *dev_data, |
| |
| static void do_detach(struct iommu_dev_data *dev_data) |
| { |
| + struct protection_domain *domain = dev_data->domain; |
| struct amd_iommu *iommu; |
| u16 alias; |
| |
| iommu = amd_iommu_rlookup_table[dev_data->devid]; |
| alias = dev_data->alias; |
| |
| - /* decrease reference counters */ |
| - dev_data->domain->dev_iommu[iommu->index] -= 1; |
| - dev_data->domain->dev_cnt -= 1; |
| - |
| /* Update data structures */ |
| dev_data->domain = NULL; |
| list_del(&dev_data->list); |
| @@ -1948,6 +1945,16 @@ static void do_detach(struct iommu_dev_data *dev_data) |
| |
| /* Flush the DTE entry */ |
| device_flush_dte(dev_data); |
| + |
| + /* Flush IOTLB */ |
| + domain_flush_tlb_pde(domain); |
| + |
| + /* Wait for the flushes to finish */ |
| + domain_flush_complete(domain); |
| + |
| + /* decrease reference counters - needs to happen after the flushes */ |
| + domain->dev_iommu[iommu->index] -= 1; |
| + domain->dev_cnt -= 1; |
| } |
| |
| /* |
| -- |
| 2.19.1 |
| |