mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
iommu/vt-d: Fix to convert mm pfn to dma pfn
[ Upstream commit fb5f50a43d ]
For the case that VT-d page is smaller than mm page, converting dma pfn
should be handled in two cases which are for start pfn and for end pfn.
Currently the calculation of end dma pfn is incorrect and the result is
less than real page frame number which is causing the mapping of iova
always misses some page frames.
Rename the mm_to_dma_pfn() to mm_to_dma_pfn_start() and add a new helper
for converting end dma pfn named mm_to_dma_pfn_end().
Signed-off-by: Yanfei Xu <yanfei.xu@intel.com>
Link: https://lore.kernel.org/r/20230625082046.979742-1-yanfei.xu@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Stable-dep-of: 31000732d56b ("iommu/vt-d: Fix identity map bounds in si_domain_init()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
4396c6ad49
commit
0aaef4e7b0
@@ -113,13 +113,17 @@ static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
|
|||||||
|
|
||||||
/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
|
/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
|
||||||
are never going to work. */
|
are never going to work. */
|
||||||
static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
|
static inline unsigned long mm_to_dma_pfn_start(unsigned long mm_pfn)
|
||||||
{
|
{
|
||||||
return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
|
return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
|
||||||
}
|
}
|
||||||
|
static inline unsigned long mm_to_dma_pfn_end(unsigned long mm_pfn)
|
||||||
|
{
|
||||||
|
return ((mm_pfn + 1) << (PAGE_SHIFT - VTD_PAGE_SHIFT)) - 1;
|
||||||
|
}
|
||||||
static inline unsigned long page_to_dma_pfn(struct page *pg)
|
static inline unsigned long page_to_dma_pfn(struct page *pg)
|
||||||
{
|
{
|
||||||
return mm_to_dma_pfn(page_to_pfn(pg));
|
return mm_to_dma_pfn_start(page_to_pfn(pg));
|
||||||
}
|
}
|
||||||
static inline unsigned long virt_to_dma_pfn(void *p)
|
static inline unsigned long virt_to_dma_pfn(void *p)
|
||||||
{
|
{
|
||||||
@@ -2439,8 +2443,8 @@ static int __init si_domain_init(int hw)
|
|||||||
|
|
||||||
for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
|
for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
|
||||||
ret = iommu_domain_identity_map(si_domain,
|
ret = iommu_domain_identity_map(si_domain,
|
||||||
mm_to_dma_pfn(start_pfn),
|
mm_to_dma_pfn_start(start_pfn),
|
||||||
mm_to_dma_pfn(end_pfn));
|
mm_to_dma_pfn_end(end_pfn));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2461,8 +2465,8 @@ static int __init si_domain_init(int hw)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = iommu_domain_identity_map(si_domain,
|
ret = iommu_domain_identity_map(si_domain,
|
||||||
mm_to_dma_pfn(start >> PAGE_SHIFT),
|
mm_to_dma_pfn_start(start >> PAGE_SHIFT),
|
||||||
mm_to_dma_pfn(end >> PAGE_SHIFT));
|
mm_to_dma_pfn_end(end >> PAGE_SHIFT));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -3698,8 +3702,8 @@ static int intel_iommu_memory_notifier(struct notifier_block *nb,
|
|||||||
unsigned long val, void *v)
|
unsigned long val, void *v)
|
||||||
{
|
{
|
||||||
struct memory_notify *mhp = v;
|
struct memory_notify *mhp = v;
|
||||||
unsigned long start_vpfn = mm_to_dma_pfn(mhp->start_pfn);
|
unsigned long start_vpfn = mm_to_dma_pfn_start(mhp->start_pfn);
|
||||||
unsigned long last_vpfn = mm_to_dma_pfn(mhp->start_pfn +
|
unsigned long last_vpfn = mm_to_dma_pfn_end(mhp->start_pfn +
|
||||||
mhp->nr_pages - 1);
|
mhp->nr_pages - 1);
|
||||||
|
|
||||||
switch (val) {
|
switch (val) {
|
||||||
@@ -4401,7 +4405,7 @@ static void intel_iommu_tlb_sync(struct iommu_domain *domain,
|
|||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
nrpages = aligned_nrpages(gather->start, size);
|
nrpages = aligned_nrpages(gather->start, size);
|
||||||
start_pfn = mm_to_dma_pfn(iova_pfn);
|
start_pfn = mm_to_dma_pfn_start(iova_pfn);
|
||||||
|
|
||||||
xa_for_each(&dmar_domain->iommu_array, i, info)
|
xa_for_each(&dmar_domain->iommu_array, i, info)
|
||||||
iommu_flush_iotlb_psi(info->iommu, dmar_domain,
|
iommu_flush_iotlb_psi(info->iommu, dmar_domain,
|
||||||
|
|||||||
Reference in New Issue
Block a user