aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/pci-calgary.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/pci-calgary.c')
-rw-r--r--arch/x86_64/kernel/pci-calgary.c44
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
137static 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 */
137int debugging __read_mostly = 0; 154int debugging __read_mostly = 0;
138 155
139static inline void tce_cache_blast_stress(struct iommu_table *tbl) 156static inline void tce_cache_blast_stress(struct iommu_table *tbl)
140{ 157{
141} 158}
159
160static 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
144static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen) 167static 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
186static unsigned long iommu_range_alloc(struct iommu_table *tbl, 211static 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);