summaryrefslogtreecommitdiff
path: root/drivers/pci/intel-iommu.c
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2009-06-27 22:41:00 +0100
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-06-29 13:30:35 +0100
commit6660c63a79a639b86e3a709e25a8c4fc3ab24770 (patch)
tree8e9b0f30973bb33f588f9d80dee91bc798ff4127 /drivers/pci/intel-iommu.c
parent595badf5d65d50300319e6178e6df005ea501f70 (diff)
downloadlwn-6660c63a79a639b86e3a709e25a8c4fc3ab24770.tar.gz
lwn-6660c63a79a639b86e3a709e25a8c4fc3ab24770.zip
intel-iommu: Make dma_pte_free_pagetable() use pfns
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/pci/intel-iommu.c')
-rw-r--r--drivers/pci/intel-iommu.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index ff8b7ce4a013..1526864a9d6f 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -669,27 +669,27 @@ static inline int width_to_agaw(int width)
static inline unsigned int level_to_offset_bits(int level)
{
- return (12 + (level - 1) * LEVEL_STRIDE);
+ return (level - 1) * LEVEL_STRIDE;
}
static inline int pfn_level_offset(unsigned long pfn, int level)
{
- return (pfn >> (level_to_offset_bits(level) - 12)) & LEVEL_MASK;
+ return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
}
-static inline u64 level_mask(int level)
+static inline unsigned long level_mask(int level)
{
- return ((u64)-1 << level_to_offset_bits(level));
+ return -1UL << level_to_offset_bits(level);
}
-static inline u64 level_size(int level)
+static inline unsigned long level_size(int level)
{
- return ((u64)1 << level_to_offset_bits(level));
+ return 1UL << level_to_offset_bits(level);
}
-static inline u64 align_to_level(u64 addr, int level)
+static inline unsigned long align_to_level(unsigned long pfn, int level)
{
- return ((addr + level_size(level) - 1) & level_mask(level));
+ return (pfn + level_size(level) - 1) & level_mask(level);
}
static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
@@ -798,25 +798,29 @@ static void dma_pte_clear_range(struct dmar_domain *domain,
static void dma_pte_free_pagetable(struct dmar_domain *domain,
u64 start, u64 end)
{
- int addr_width = agaw_to_width(domain->agaw);
+ int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+ unsigned long start_pfn = start >> VTD_PAGE_SHIFT;
+ unsigned long last_pfn = (end-1) >> VTD_PAGE_SHIFT;
struct dma_pte *pte;
int total = agaw_to_level(domain->agaw);
int level;
- u64 tmp;
+ unsigned long tmp;
- BUG_ON(start >> addr_width);
- BUG_ON(end >> addr_width);
+ BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
+ BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
/* we don't need lock here, nobody else touches the iova range */
level = 2;
while (level <= total) {
- tmp = align_to_level(start, level);
- if (tmp >= end || (tmp + level_size(level) > end))
+ tmp = align_to_level(start_pfn, level);
+
+ /* Only clear this pte/pmd if we're asked to clear its
+ _whole_ range */
+ if (tmp + level_size(level) - 1 > last_pfn)
return;
- while (tmp < end) {
- pte = dma_pfn_level_pte(domain, tmp >> VTD_PAGE_SHIFT,
- level);
+ while (tmp <= last_pfn) {
+ pte = dma_pfn_level_pte(domain, tmp, level);
if (pte) {
free_pgtable_page(
phys_to_virt(dma_pte_addr(pte)));
@@ -828,7 +832,7 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
level++;
}
/* free pgd */
- if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
+ if (start == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
free_pgtable_page(domain->pgd);
domain->pgd = NULL;
}