diff options
-rw-r--r-- | arch/x86_64/kernel/pci-calgary.c | 40 |
1 files changed, 17 insertions, 23 deletions
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index a2f9c5369292..fa50d6a1ce46 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c | |||
@@ -233,6 +233,7 @@ static void iommu_range_reserve(struct iommu_table *tbl, | |||
233 | unsigned long index; | 233 | unsigned long index; |
234 | unsigned long end; | 234 | unsigned long end; |
235 | unsigned long badbit; | 235 | unsigned long badbit; |
236 | unsigned long flags; | ||
236 | 237 | ||
237 | index = start_addr >> PAGE_SHIFT; | 238 | index = start_addr >> PAGE_SHIFT; |
238 | 239 | ||
@@ -244,6 +245,8 @@ static void iommu_range_reserve(struct iommu_table *tbl, | |||
244 | if (end > tbl->it_size) /* don't go off the table */ | 245 | if (end > tbl->it_size) /* don't go off the table */ |
245 | end = tbl->it_size; | 246 | end = tbl->it_size; |
246 | 247 | ||
248 | spin_lock_irqsave(&tbl->it_lock, flags); | ||
249 | |||
247 | badbit = verify_bit_range(tbl->it_map, 0, index, end); | 250 | badbit = verify_bit_range(tbl->it_map, 0, index, end); |
248 | if (badbit != ~0UL) { | 251 | if (badbit != ~0UL) { |
249 | if (printk_ratelimit()) | 252 | if (printk_ratelimit()) |
@@ -253,15 +256,20 @@ static void iommu_range_reserve(struct iommu_table *tbl, | |||
253 | } | 256 | } |
254 | 257 | ||
255 | set_bit_string(tbl->it_map, index, npages); | 258 | set_bit_string(tbl->it_map, index, npages); |
259 | |||
260 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
256 | } | 261 | } |
257 | 262 | ||
258 | static unsigned long iommu_range_alloc(struct iommu_table *tbl, | 263 | static unsigned long iommu_range_alloc(struct iommu_table *tbl, |
259 | unsigned int npages) | 264 | unsigned int npages) |
260 | { | 265 | { |
266 | unsigned long flags; | ||
261 | unsigned long offset; | 267 | unsigned long offset; |
262 | 268 | ||
263 | BUG_ON(npages == 0); | 269 | BUG_ON(npages == 0); |
264 | 270 | ||
271 | spin_lock_irqsave(&tbl->it_lock, flags); | ||
272 | |||
265 | offset = find_next_zero_string(tbl->it_map, tbl->it_hint, | 273 | offset = find_next_zero_string(tbl->it_map, tbl->it_hint, |
266 | tbl->it_size, npages); | 274 | tbl->it_size, npages); |
267 | if (offset == ~0UL) { | 275 | if (offset == ~0UL) { |
@@ -270,6 +278,7 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, | |||
270 | tbl->it_size, npages); | 278 | tbl->it_size, npages); |
271 | if (offset == ~0UL) { | 279 | if (offset == ~0UL) { |
272 | printk(KERN_WARNING "Calgary: IOMMU full.\n"); | 280 | printk(KERN_WARNING "Calgary: IOMMU full.\n"); |
281 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
273 | if (panic_on_overflow) | 282 | if (panic_on_overflow) |
274 | panic("Calgary: fix the allocator.\n"); | 283 | panic("Calgary: fix the allocator.\n"); |
275 | else | 284 | else |
@@ -281,17 +290,17 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, | |||
281 | tbl->it_hint = offset + npages; | 290 | tbl->it_hint = offset + npages; |
282 | BUG_ON(tbl->it_hint > tbl->it_size); | 291 | BUG_ON(tbl->it_hint > tbl->it_size); |
283 | 292 | ||
293 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
294 | |||
284 | return offset; | 295 | return offset; |
285 | } | 296 | } |
286 | 297 | ||
287 | static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr, | 298 | static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr, |
288 | unsigned int npages, int direction) | 299 | unsigned int npages, int direction) |
289 | { | 300 | { |
290 | unsigned long entry, flags; | 301 | unsigned long entry; |
291 | dma_addr_t ret = bad_dma_address; | 302 | dma_addr_t ret = bad_dma_address; |
292 | 303 | ||
293 | spin_lock_irqsave(&tbl->it_lock, flags); | ||
294 | |||
295 | entry = iommu_range_alloc(tbl, npages); | 304 | entry = iommu_range_alloc(tbl, npages); |
296 | 305 | ||
297 | if (unlikely(entry == bad_dma_address)) | 306 | if (unlikely(entry == bad_dma_address)) |
@@ -304,12 +313,9 @@ static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr, | |||
304 | tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK, | 313 | tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK, |
305 | direction); | 314 | direction); |
306 | 315 | ||
307 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
308 | |||
309 | return ret; | 316 | return ret; |
310 | 317 | ||
311 | error: | 318 | error: |
312 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
313 | printk(KERN_WARNING "Calgary: failed to allocate %u pages in " | 319 | printk(KERN_WARNING "Calgary: failed to allocate %u pages in " |
314 | "iommu %p\n", npages, tbl); | 320 | "iommu %p\n", npages, tbl); |
315 | return bad_dma_address; | 321 | return bad_dma_address; |
@@ -321,6 +327,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
321 | unsigned long entry; | 327 | unsigned long entry; |
322 | unsigned long badbit; | 328 | unsigned long badbit; |
323 | unsigned long badend; | 329 | unsigned long badend; |
330 | unsigned long flags; | ||
324 | 331 | ||
325 | /* were we called with bad_dma_address? */ | 332 | /* were we called with bad_dma_address? */ |
326 | badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE); | 333 | badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE); |
@@ -337,6 +344,8 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
337 | 344 | ||
338 | tce_free(tbl, entry, npages); | 345 | tce_free(tbl, entry, npages); |
339 | 346 | ||
347 | spin_lock_irqsave(&tbl->it_lock, flags); | ||
348 | |||
340 | badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages); | 349 | badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages); |
341 | if (badbit != ~0UL) { | 350 | if (badbit != ~0UL) { |
342 | if (printk_ratelimit()) | 351 | if (printk_ratelimit()) |
@@ -346,18 +355,14 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
346 | } | 355 | } |
347 | 356 | ||
348 | __clear_bit_string(tbl->it_map, entry, npages); | 357 | __clear_bit_string(tbl->it_map, entry, npages); |
358 | |||
359 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
349 | } | 360 | } |
350 | 361 | ||
351 | static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | 362 | static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, |
352 | unsigned int npages) | 363 | unsigned int npages) |
353 | { | 364 | { |
354 | unsigned long flags; | ||
355 | |||
356 | spin_lock_irqsave(&tbl->it_lock, flags); | ||
357 | |||
358 | __iommu_free(tbl, dma_addr, npages); | 365 | __iommu_free(tbl, dma_addr, npages); |
359 | |||
360 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
361 | } | 366 | } |
362 | 367 | ||
363 | static inline struct iommu_table *find_iommu_table(struct device *dev) | 368 | static inline struct iommu_table *find_iommu_table(struct device *dev) |
@@ -402,17 +407,12 @@ static void __calgary_unmap_sg(struct iommu_table *tbl, | |||
402 | void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist, | 407 | void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist, |
403 | int nelems, int direction) | 408 | int nelems, int direction) |
404 | { | 409 | { |
405 | unsigned long flags; | ||
406 | struct iommu_table *tbl = find_iommu_table(dev); | 410 | struct iommu_table *tbl = find_iommu_table(dev); |
407 | 411 | ||
408 | if (!translate_phb(to_pci_dev(dev))) | 412 | if (!translate_phb(to_pci_dev(dev))) |
409 | return; | 413 | return; |
410 | 414 | ||
411 | spin_lock_irqsave(&tbl->it_lock, flags); | ||
412 | |||
413 | __calgary_unmap_sg(tbl, sglist, nelems, direction); | 415 | __calgary_unmap_sg(tbl, sglist, nelems, direction); |
414 | |||
415 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
416 | } | 416 | } |
417 | 417 | ||
418 | static int calgary_nontranslate_map_sg(struct device* dev, | 418 | static int calgary_nontranslate_map_sg(struct device* dev, |
@@ -433,7 +433,6 @@ int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
433 | int nelems, int direction) | 433 | int nelems, int direction) |
434 | { | 434 | { |
435 | struct iommu_table *tbl = find_iommu_table(dev); | 435 | struct iommu_table *tbl = find_iommu_table(dev); |
436 | unsigned long flags; | ||
437 | unsigned long vaddr; | 436 | unsigned long vaddr; |
438 | unsigned int npages; | 437 | unsigned int npages; |
439 | unsigned long entry; | 438 | unsigned long entry; |
@@ -442,8 +441,6 @@ int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
442 | if (!translate_phb(to_pci_dev(dev))) | 441 | if (!translate_phb(to_pci_dev(dev))) |
443 | return calgary_nontranslate_map_sg(dev, sg, nelems, direction); | 442 | return calgary_nontranslate_map_sg(dev, sg, nelems, direction); |
444 | 443 | ||
445 | spin_lock_irqsave(&tbl->it_lock, flags); | ||
446 | |||
447 | for (i = 0; i < nelems; i++ ) { | 444 | for (i = 0; i < nelems; i++ ) { |
448 | struct scatterlist *s = &sg[i]; | 445 | struct scatterlist *s = &sg[i]; |
449 | BUG_ON(!s->page); | 446 | BUG_ON(!s->page); |
@@ -467,8 +464,6 @@ int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
467 | s->dma_length = s->length; | 464 | s->dma_length = s->length; |
468 | } | 465 | } |
469 | 466 | ||
470 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
471 | |||
472 | return nelems; | 467 | return nelems; |
473 | error: | 468 | error: |
474 | __calgary_unmap_sg(tbl, sg, nelems, direction); | 469 | __calgary_unmap_sg(tbl, sg, nelems, direction); |
@@ -476,7 +471,6 @@ error: | |||
476 | sg[i].dma_address = bad_dma_address; | 471 | sg[i].dma_address = bad_dma_address; |
477 | sg[i].dma_length = 0; | 472 | sg[i].dma_length = 0; |
478 | } | 473 | } |
479 | spin_unlock_irqrestore(&tbl->it_lock, flags); | ||
480 | return 0; | 474 | return 0; |
481 | } | 475 | } |
482 | 476 | ||