diff options
Diffstat (limited to 'arch/x86_64/kernel/pci-calgary.c')
-rw-r--r-- | arch/x86_64/kernel/pci-calgary.c | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index ebe4e930b64d..7c43cb0f71a3 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c | |||
@@ -133,12 +133,35 @@ static inline void tce_cache_blast_stress(struct iommu_table *tbl) | |||
133 | { | 133 | { |
134 | tce_cache_blast(tbl); | 134 | tce_cache_blast(tbl); |
135 | } | 135 | } |
136 | |||
137 | static inline unsigned long verify_bit_range(unsigned long* bitmap, | ||
138 | int expected, unsigned long start, unsigned long end) | ||
139 | { | ||
140 | unsigned long idx = start; | ||
141 | |||
142 | BUG_ON(start >= end); | ||
143 | |||
144 | while (idx < end) { | ||
145 | if (!!test_bit(idx, bitmap) != expected) | ||
146 | return idx; | ||
147 | ++idx; | ||
148 | } | ||
149 | |||
150 | /* all bits have the expected value */ | ||
151 | return ~0UL; | ||
152 | } | ||
136 | #else /* debugging is disabled */ | 153 | #else /* debugging is disabled */ |
137 | int debugging __read_mostly = 0; | 154 | int debugging __read_mostly = 0; |
138 | 155 | ||
139 | static inline void tce_cache_blast_stress(struct iommu_table *tbl) | 156 | static inline void tce_cache_blast_stress(struct iommu_table *tbl) |
140 | { | 157 | { |
141 | } | 158 | } |
159 | |||
160 | static inline unsigned long verify_bit_range(unsigned long* bitmap, | ||
161 | int expected, unsigned long start, unsigned long end) | ||
162 | { | ||
163 | return ~0UL; | ||
164 | } | ||
142 | #endif /* CONFIG_IOMMU_DEBUG */ | 165 | #endif /* CONFIG_IOMMU_DEBUG */ |
143 | 166 | ||
144 | static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen) | 167 | static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen) |
@@ -162,6 +185,7 @@ static void iommu_range_reserve(struct iommu_table *tbl, | |||
162 | { | 185 | { |
163 | unsigned long index; | 186 | unsigned long index; |
164 | unsigned long end; | 187 | unsigned long end; |
188 | unsigned long badbit; | ||
165 | 189 | ||
166 | index = start_addr >> PAGE_SHIFT; | 190 | index = start_addr >> PAGE_SHIFT; |
167 | 191 | ||
@@ -173,14 +197,15 @@ static void iommu_range_reserve(struct iommu_table *tbl, | |||
173 | if (end > tbl->it_size) /* don't go off the table */ | 197 | if (end > tbl->it_size) /* don't go off the table */ |
174 | end = tbl->it_size; | 198 | end = tbl->it_size; |
175 | 199 | ||
176 | while (index < end) { | 200 | badbit = verify_bit_range(tbl->it_map, 0, index, end); |
177 | if (test_bit(index, tbl->it_map)) | 201 | if (badbit != ~0UL) { |
202 | if (printk_ratelimit()) | ||
178 | printk(KERN_ERR "Calgary: entry already allocated at " | 203 | printk(KERN_ERR "Calgary: entry already allocated at " |
179 | "0x%lx tbl %p dma 0x%lx npages %u\n", | 204 | "0x%lx tbl %p dma 0x%lx npages %u\n", |
180 | index, tbl, start_addr, npages); | 205 | badbit, tbl, start_addr, npages); |
181 | ++index; | ||
182 | } | 206 | } |
183 | set_bit_string(tbl->it_map, start_addr >> PAGE_SHIFT, npages); | 207 | |
208 | set_bit_string(tbl->it_map, index, npages); | ||
184 | } | 209 | } |
185 | 210 | ||
186 | static unsigned long iommu_range_alloc(struct iommu_table *tbl, | 211 | static unsigned long iommu_range_alloc(struct iommu_table *tbl, |
@@ -247,7 +272,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
247 | unsigned int npages) | 272 | unsigned int npages) |
248 | { | 273 | { |
249 | unsigned long entry; | 274 | unsigned long entry; |
250 | unsigned long i; | 275 | unsigned long badbit; |
251 | 276 | ||
252 | entry = dma_addr >> PAGE_SHIFT; | 277 | entry = dma_addr >> PAGE_SHIFT; |
253 | 278 | ||
@@ -255,11 +280,12 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
255 | 280 | ||
256 | tce_free(tbl, entry, npages); | 281 | tce_free(tbl, entry, npages); |
257 | 282 | ||
258 | for (i = 0; i < npages; ++i) { | 283 | badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages); |
259 | if (!test_bit(entry + i, tbl->it_map)) | 284 | if (badbit != ~0UL) { |
285 | if (printk_ratelimit()) | ||
260 | printk(KERN_ERR "Calgary: bit is off at 0x%lx " | 286 | printk(KERN_ERR "Calgary: bit is off at 0x%lx " |
261 | "tbl %p dma 0x%Lx entry 0x%lx npages %u\n", | 287 | "tbl %p dma 0x%Lx entry 0x%lx npages %u\n", |
262 | entry + i, tbl, dma_addr, entry, npages); | 288 | badbit, tbl, dma_addr, entry, npages); |
263 | } | 289 | } |
264 | 290 | ||
265 | __clear_bit_string(tbl->it_map, entry, npages); | 291 | __clear_bit_string(tbl->it_map, entry, npages); |