aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/intel-iommu.c
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-01-06 01:18:12 -0500
committerJoerg Roedel <joro@8bytes.org>2014-01-09 06:43:27 -0500
commit5c645b35b77024fb440b2bc8847fa0193119b2a6 (patch)
tree0587d0d3cfc154cc1cbdba12a9ee2b965488bf5c /drivers/iommu/intel-iommu.c
parent852bdb04f81c276969d43b9e15048259d028881f (diff)
iommu/vt-d, trivial: refine support of 64bit guest address
In Intel IOMMU driver, it calculate page table level from adjusted guest address width as 'level = (agaw - 30) / 9', which assumes (agaw -30) could be divided by 9. On the other hand, 64bit is a valid agaw and (64 - 30) can't be divided by 9, so it needs special handling. This patch enhances Intel IOMMU driver to correctly handle 64bit agaw. It's mainly for code readability because there's no hardware supporting 64bit agaw yet. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Signed-off-by: Joerg Roedel <joro@8bytes.org>
Diffstat (limited to 'drivers/iommu/intel-iommu.c')
-rw-r--r--drivers/iommu/intel-iommu.c11
1 files changed, 5 insertions, 6 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 0cbf1dda0730..7bddb9b32da8 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -63,6 +63,7 @@
63#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48 63#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
64 64
65#define MAX_AGAW_WIDTH 64 65#define MAX_AGAW_WIDTH 64
66#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
66 67
67#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1) 68#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
68#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1) 69#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
@@ -106,12 +107,12 @@ static inline int agaw_to_level(int agaw)
106 107
107static inline int agaw_to_width(int agaw) 108static inline int agaw_to_width(int agaw)
108{ 109{
109 return 30 + agaw * LEVEL_STRIDE; 110 return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
110} 111}
111 112
112static inline int width_to_agaw(int width) 113static inline int width_to_agaw(int width)
113{ 114{
114 return (width - 30) / LEVEL_STRIDE; 115 return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
115} 116}
116 117
117static inline unsigned int level_to_offset_bits(int level) 118static inline unsigned int level_to_offset_bits(int level)
@@ -141,7 +142,7 @@ static inline unsigned long align_to_level(unsigned long pfn, int level)
141 142
142static inline unsigned long lvl_to_nr_pages(unsigned int lvl) 143static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
143{ 144{
144 return 1 << ((lvl - 1) * LEVEL_STRIDE); 145 return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
145} 146}
146 147
147/* VT-d pages must always be _smaller_ than MM pages. Otherwise things 148/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
@@ -865,7 +866,6 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
865 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; 866 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
866 unsigned int large_page = 1; 867 unsigned int large_page = 1;
867 struct dma_pte *first_pte, *pte; 868 struct dma_pte *first_pte, *pte;
868 int order;
869 869
870 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width); 870 BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
871 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width); 871 BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
@@ -890,8 +890,7 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
890 890
891 } while (start_pfn && start_pfn <= last_pfn); 891 } while (start_pfn && start_pfn <= last_pfn);
892 892
893 order = (large_page - 1) * 9; 893 return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
894 return order;
895} 894}
896 895
897static void dma_pte_free_level(struct dmar_domain *domain, int level, 896static void dma_pte_free_level(struct dmar_domain *domain, int level,