Skip to content

Commit 33cd6e6

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Flush PASID-based iotlb for iova over first level
When software has changed first-level tables, it should invalidate the affected IOTLB and the paging-structure-caches using the PASID- based-IOTLB Invalidate Descriptor defined in spec 6.5.2.4. Signed-off-by: Lu Baolu <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent ddf09b6 commit 33cd6e6

File tree

3 files changed

+84
-15
lines changed

3 files changed

+84
-15
lines changed

drivers/iommu/dmar.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,47 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid,
13711371
qi_submit_sync(&desc, iommu);
13721372
}
13731373

1374+
/* PASID-based IOTLB invalidation */
1375+
void qi_flush_piotlb(struct intel_iommu *iommu, u16 did, u32 pasid, u64 addr,
1376+
unsigned long npages, bool ih)
1377+
{
1378+
struct qi_desc desc = {.qw2 = 0, .qw3 = 0};
1379+
1380+
/*
1381+
* npages == -1 means a PASID-selective invalidation, otherwise,
1382+
* a positive value for Page-selective-within-PASID invalidation.
1383+
* 0 is not a valid input.
1384+
*/
1385+
if (WARN_ON(!npages)) {
1386+
pr_err("Invalid input npages = %ld\n", npages);
1387+
return;
1388+
}
1389+
1390+
if (npages == -1) {
1391+
desc.qw0 = QI_EIOTLB_PASID(pasid) |
1392+
QI_EIOTLB_DID(did) |
1393+
QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) |
1394+
QI_EIOTLB_TYPE;
1395+
desc.qw1 = 0;
1396+
} else {
1397+
int mask = ilog2(__roundup_pow_of_two(npages));
1398+
unsigned long align = (1ULL << (VTD_PAGE_SHIFT + mask));
1399+
1400+
if (WARN_ON_ONCE(!ALIGN(addr, align)))
1401+
addr &= ~(align - 1);
1402+
1403+
desc.qw0 = QI_EIOTLB_PASID(pasid) |
1404+
QI_EIOTLB_DID(did) |
1405+
QI_EIOTLB_GRAN(QI_GRAN_PSI_PASID) |
1406+
QI_EIOTLB_TYPE;
1407+
desc.qw1 = QI_EIOTLB_ADDR(addr) |
1408+
QI_EIOTLB_IH(ih) |
1409+
QI_EIOTLB_AM(mask);
1410+
}
1411+
1412+
qi_submit_sync(&desc, iommu);
1413+
}
1414+
13741415
/*
13751416
* Disable Queued Invalidation interface.
13761417
*/

drivers/iommu/intel-iommu.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,20 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
15091509
spin_unlock_irqrestore(&device_domain_lock, flags);
15101510
}
15111511

1512+
static void domain_flush_piotlb(struct intel_iommu *iommu,
1513+
struct dmar_domain *domain,
1514+
u64 addr, unsigned long npages, bool ih)
1515+
{
1516+
u16 did = domain->iommu_did[iommu->seq_id];
1517+
1518+
if (domain->default_pasid)
1519+
qi_flush_piotlb(iommu, did, domain->default_pasid,
1520+
addr, npages, ih);
1521+
1522+
if (!list_empty(&domain->devices))
1523+
qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr, npages, ih);
1524+
}
1525+
15121526
static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
15131527
struct dmar_domain *domain,
15141528
unsigned long pfn, unsigned int pages,
@@ -1522,18 +1536,23 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
15221536

15231537
if (ih)
15241538
ih = 1 << 6;
1525-
/*
1526-
* Fallback to domain selective flush if no PSI support or the size is
1527-
* too big.
1528-
* PSI requires page size to be 2 ^ x, and the base address is naturally
1529-
* aligned to the size
1530-
*/
1531-
if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
1532-
iommu->flush.flush_iotlb(iommu, did, 0, 0,
1533-
DMA_TLB_DSI_FLUSH);
1534-
else
1535-
iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
1536-
DMA_TLB_PSI_FLUSH);
1539+
1540+
if (domain_use_first_level(domain)) {
1541+
domain_flush_piotlb(iommu, domain, addr, pages, ih);
1542+
} else {
1543+
/*
1544+
* Fallback to domain selective flush if no PSI support or
1545+
* the size is too big. PSI requires page size to be 2 ^ x,
1546+
* and the base address is naturally aligned to the size.
1547+
*/
1548+
if (!cap_pgsel_inv(iommu->cap) ||
1549+
mask > cap_max_amask_val(iommu->cap))
1550+
iommu->flush.flush_iotlb(iommu, did, 0, 0,
1551+
DMA_TLB_DSI_FLUSH);
1552+
else
1553+
iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
1554+
DMA_TLB_PSI_FLUSH);
1555+
}
15371556

15381557
/*
15391558
* In caching mode, changes of pages from non-present to present require
@@ -1548,8 +1567,11 @@ static inline void __mapping_notify_one(struct intel_iommu *iommu,
15481567
struct dmar_domain *domain,
15491568
unsigned long pfn, unsigned int pages)
15501569
{
1551-
/* It's a non-present to present mapping. Only flush if caching mode */
1552-
if (cap_caching_mode(iommu->cap))
1570+
/*
1571+
* It's a non-present to present mapping. Only flush if caching mode
1572+
* and second level.
1573+
*/
1574+
if (cap_caching_mode(iommu->cap) && !domain_use_first_level(domain))
15531575
iommu_flush_iotlb_psi(iommu, domain, pfn, pages, 0, 1);
15541576
else
15551577
iommu_flush_write_buffer(iommu);
@@ -1566,7 +1588,11 @@ static void iommu_flush_iova(struct iova_domain *iovad)
15661588
struct intel_iommu *iommu = g_iommus[idx];
15671589
u16 did = domain->iommu_did[iommu->seq_id];
15681590

1569-
iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
1591+
if (domain_use_first_level(domain))
1592+
domain_flush_piotlb(iommu, domain, 0, -1, 0);
1593+
else
1594+
iommu->flush.flush_iotlb(iommu, did, 0, 0,
1595+
DMA_TLB_DSI_FLUSH);
15701596

15711597
if (!cap_caching_mode(iommu->cap))
15721598
iommu_flush_dev_iotlb(get_iommu_domain(iommu, did),

include/linux/intel-iommu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,8 @@ extern void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
650650
unsigned int size_order, u64 type);
651651
extern void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid,
652652
u16 qdep, u64 addr, unsigned mask);
653+
void qi_flush_piotlb(struct intel_iommu *iommu, u16 did, u32 pasid, u64 addr,
654+
unsigned long npages, bool ih);
653655
extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
654656

655657
extern int dmar_ir_support(void);

0 commit comments

Comments
 (0)