aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/pci-calgary_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/pci-calgary_64.c')
-rw-r--r--arch/x86/kernel/pci-calgary_64.c107
1 files changed, 52 insertions, 55 deletions
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 19e7fc7c2c4f..080d1d27f37a 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -37,6 +37,7 @@
37#include <linux/delay.h> 37#include <linux/delay.h>
38#include <linux/scatterlist.h> 38#include <linux/scatterlist.h>
39#include <linux/iommu-helper.h> 39#include <linux/iommu-helper.h>
40
40#include <asm/iommu.h> 41#include <asm/iommu.h>
41#include <asm/calgary.h> 42#include <asm/calgary.h>
42#include <asm/tce.h> 43#include <asm/tce.h>
@@ -260,7 +261,7 @@ static void iommu_range_reserve(struct iommu_table *tbl,
260 badbit, tbl, start_addr, npages); 261 badbit, tbl, start_addr, npages);
261 } 262 }
262 263
263 set_bit_string(tbl->it_map, index, npages); 264 iommu_area_reserve(tbl->it_map, index, npages);
264 265
265 spin_unlock_irqrestore(&tbl->it_lock, flags); 266 spin_unlock_irqrestore(&tbl->it_lock, flags);
266} 267}
@@ -342,9 +343,8 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
342 /* were we called with bad_dma_address? */ 343 /* were we called with bad_dma_address? */
343 badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE); 344 badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE);
344 if (unlikely((dma_addr >= bad_dma_address) && (dma_addr < badend))) { 345 if (unlikely((dma_addr >= bad_dma_address) && (dma_addr < badend))) {
345 printk(KERN_ERR "Calgary: driver tried unmapping bad DMA " 346 WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA "
346 "address 0x%Lx\n", dma_addr); 347 "address 0x%Lx\n", dma_addr);
347 WARN_ON(1);
348 return; 348 return;
349 } 349 }
350 350
@@ -413,22 +413,6 @@ static void calgary_unmap_sg(struct device *dev,
413 } 413 }
414} 414}
415 415
416static int calgary_nontranslate_map_sg(struct device* dev,
417 struct scatterlist *sg, int nelems, int direction)
418{
419 struct scatterlist *s;
420 int i;
421
422 for_each_sg(sg, s, nelems, i) {
423 struct page *p = sg_page(s);
424
425 BUG_ON(!p);
426 s->dma_address = virt_to_bus(sg_virt(s));
427 s->dma_length = s->length;
428 }
429 return nelems;
430}
431
432static int calgary_map_sg(struct device *dev, struct scatterlist *sg, 416static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
433 int nelems, int direction) 417 int nelems, int direction)
434{ 418{
@@ -439,9 +423,6 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
439 unsigned long entry; 423 unsigned long entry;
440 int i; 424 int i;
441 425
442 if (!translation_enabled(tbl))
443 return calgary_nontranslate_map_sg(dev, sg, nelems, direction);
444
445 for_each_sg(sg, s, nelems, i) { 426 for_each_sg(sg, s, nelems, i) {
446 BUG_ON(!sg_page(s)); 427 BUG_ON(!sg_page(s));
447 428
@@ -477,7 +458,6 @@ error:
477static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr, 458static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr,
478 size_t size, int direction) 459 size_t size, int direction)
479{ 460{
480 dma_addr_t dma_handle = bad_dma_address;
481 void *vaddr = phys_to_virt(paddr); 461 void *vaddr = phys_to_virt(paddr);
482 unsigned long uaddr; 462 unsigned long uaddr;
483 unsigned int npages; 463 unsigned int npages;
@@ -486,12 +466,7 @@ static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr,
486 uaddr = (unsigned long)vaddr; 466 uaddr = (unsigned long)vaddr;
487 npages = num_dma_pages(uaddr, size); 467 npages = num_dma_pages(uaddr, size);
488 468
489 if (translation_enabled(tbl)) 469 return iommu_alloc(dev, tbl, vaddr, npages, direction);
490 dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction);
491 else
492 dma_handle = virt_to_bus(vaddr);
493
494 return dma_handle;
495} 470}
496 471
497static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle, 472static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
@@ -500,9 +475,6 @@ static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
500 struct iommu_table *tbl = find_iommu_table(dev); 475 struct iommu_table *tbl = find_iommu_table(dev);
501 unsigned int npages; 476 unsigned int npages;
502 477
503 if (!translation_enabled(tbl))
504 return;
505
506 npages = num_dma_pages(dma_handle, size); 478 npages = num_dma_pages(dma_handle, size);
507 iommu_free(tbl, dma_handle, npages); 479 iommu_free(tbl, dma_handle, npages);
508} 480}
@@ -519,24 +491,20 @@ static void* calgary_alloc_coherent(struct device *dev, size_t size,
519 npages = size >> PAGE_SHIFT; 491 npages = size >> PAGE_SHIFT;
520 order = get_order(size); 492 order = get_order(size);
521 493
494 flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
495
522 /* alloc enough pages (and possibly more) */ 496 /* alloc enough pages (and possibly more) */
523 ret = (void *)__get_free_pages(flag, order); 497 ret = (void *)__get_free_pages(flag, order);
524 if (!ret) 498 if (!ret)
525 goto error; 499 goto error;
526 memset(ret, 0, size); 500 memset(ret, 0, size);
527 501
528 if (translation_enabled(tbl)) { 502 /* set up tces to cover the allocated range */
529 /* set up tces to cover the allocated range */ 503 mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL);
530 mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL); 504 if (mapping == bad_dma_address)
531 if (mapping == bad_dma_address) 505 goto free;
532 goto free; 506 *dma_handle = mapping;
533
534 *dma_handle = mapping;
535 } else /* non translated slot */
536 *dma_handle = virt_to_bus(ret);
537
538 return ret; 507 return ret;
539
540free: 508free:
541 free_pages((unsigned long)ret, get_order(size)); 509 free_pages((unsigned long)ret, get_order(size));
542 ret = NULL; 510 ret = NULL;
@@ -544,8 +512,22 @@ error:
544 return ret; 512 return ret;
545} 513}
546 514
547static const struct dma_mapping_ops calgary_dma_ops = { 515static void calgary_free_coherent(struct device *dev, size_t size,
516 void *vaddr, dma_addr_t dma_handle)
517{
518 unsigned int npages;
519 struct iommu_table *tbl = find_iommu_table(dev);
520
521 size = PAGE_ALIGN(size);
522 npages = size >> PAGE_SHIFT;
523
524 iommu_free(tbl, dma_handle, npages);
525 free_pages((unsigned long)vaddr, get_order(size));
526}
527
528static struct dma_mapping_ops calgary_dma_ops = {
548 .alloc_coherent = calgary_alloc_coherent, 529 .alloc_coherent = calgary_alloc_coherent,
530 .free_coherent = calgary_free_coherent,
549 .map_single = calgary_map_single, 531 .map_single = calgary_map_single,
550 .unmap_single = calgary_unmap_single, 532 .unmap_single = calgary_unmap_single,
551 .map_sg = calgary_map_sg, 533 .map_sg = calgary_map_sg,
@@ -1241,6 +1223,16 @@ static int __init calgary_init(void)
1241 goto error; 1223 goto error;
1242 } while (1); 1224 } while (1);
1243 1225
1226 dev = NULL;
1227 for_each_pci_dev(dev) {
1228 struct iommu_table *tbl;
1229
1230 tbl = find_iommu_table(&dev->dev);
1231
1232 if (translation_enabled(tbl))
1233 dev->dev.archdata.dma_ops = &calgary_dma_ops;
1234 }
1235
1244 return ret; 1236 return ret;
1245 1237
1246error: 1238error:
@@ -1262,6 +1254,7 @@ error:
1262 calgary_disable_translation(dev); 1254 calgary_disable_translation(dev);
1263 calgary_free_bus(dev); 1255 calgary_free_bus(dev);
1264 pci_dev_put(dev); /* Undo calgary_init_one()'s pci_dev_get() */ 1256 pci_dev_put(dev); /* Undo calgary_init_one()'s pci_dev_get() */
1257 dev->dev.archdata.dma_ops = NULL;
1265 } while (1); 1258 } while (1);
1266 1259
1267 return ret; 1260 return ret;
@@ -1291,13 +1284,15 @@ static inline int __init determine_tce_table_size(u64 ram)
1291static int __init build_detail_arrays(void) 1284static int __init build_detail_arrays(void)
1292{ 1285{
1293 unsigned long ptr; 1286 unsigned long ptr;
1294 int i, scal_detail_size, rio_detail_size; 1287 unsigned numnodes, i;
1288 int scal_detail_size, rio_detail_size;
1295 1289
1296 if (rio_table_hdr->num_scal_dev > MAX_NUMNODES){ 1290 numnodes = rio_table_hdr->num_scal_dev;
1291 if (numnodes > MAX_NUMNODES){
1297 printk(KERN_WARNING 1292 printk(KERN_WARNING
1298 "Calgary: MAX_NUMNODES too low! Defined as %d, " 1293 "Calgary: MAX_NUMNODES too low! Defined as %d, "
1299 "but system has %d nodes.\n", 1294 "but system has %d nodes.\n",
1300 MAX_NUMNODES, rio_table_hdr->num_scal_dev); 1295 MAX_NUMNODES, numnodes);
1301 return -ENODEV; 1296 return -ENODEV;
1302 } 1297 }
1303 1298
@@ -1318,8 +1313,7 @@ static int __init build_detail_arrays(void)
1318 } 1313 }
1319 1314
1320 ptr = ((unsigned long)rio_table_hdr) + 3; 1315 ptr = ((unsigned long)rio_table_hdr) + 3;
1321 for (i = 0; i < rio_table_hdr->num_scal_dev; 1316 for (i = 0; i < numnodes; i++, ptr += scal_detail_size)
1322 i++, ptr += scal_detail_size)
1323 scal_devs[i] = (struct scal_detail *)ptr; 1317 scal_devs[i] = (struct scal_detail *)ptr;
1324 1318
1325 for (i = 0; i < rio_table_hdr->num_rio_dev; 1319 for (i = 0; i < rio_table_hdr->num_rio_dev;
@@ -1372,7 +1366,7 @@ static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl)
1372 * Function for kdump case. Get the tce tables from first kernel 1366 * Function for kdump case. Get the tce tables from first kernel
1373 * by reading the contents of the base adress register of calgary iommu 1367 * by reading the contents of the base adress register of calgary iommu
1374 */ 1368 */
1375static void get_tce_space_from_tar() 1369static void __init get_tce_space_from_tar(void)
1376{ 1370{
1377 int bus; 1371 int bus;
1378 void __iomem *target; 1372 void __iomem *target;
@@ -1503,6 +1497,10 @@ void __init detect_calgary(void)
1503 printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d, " 1497 printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d, "
1504 "CONFIG_IOMMU_DEBUG is %s.\n", specified_table_size, 1498 "CONFIG_IOMMU_DEBUG is %s.\n", specified_table_size,
1505 debugging ? "enabled" : "disabled"); 1499 debugging ? "enabled" : "disabled");
1500
1501 /* swiotlb for devices that aren't behind the Calgary. */
1502 if (max_pfn > MAX_DMA32_PFN)
1503 swiotlb = 1;
1506 } 1504 }
1507 return; 1505 return;
1508 1506
@@ -1519,7 +1517,7 @@ int __init calgary_iommu_init(void)
1519{ 1517{
1520 int ret; 1518 int ret;
1521 1519
1522 if (no_iommu || swiotlb) 1520 if (no_iommu || (swiotlb && !calgary_detected))
1523 return -ENODEV; 1521 return -ENODEV;
1524 1522
1525 if (!calgary_detected) 1523 if (!calgary_detected)
@@ -1532,15 +1530,14 @@ int __init calgary_iommu_init(void)
1532 if (ret) { 1530 if (ret) {
1533 printk(KERN_ERR "PCI-DMA: Calgary init failed %d, " 1531 printk(KERN_ERR "PCI-DMA: Calgary init failed %d, "
1534 "falling back to no_iommu\n", ret); 1532 "falling back to no_iommu\n", ret);
1535 if (max_pfn > MAX_DMA32_PFN)
1536 printk(KERN_ERR "WARNING more than 4GB of memory, "
1537 "32bit PCI may malfunction.\n");
1538 return ret; 1533 return ret;
1539 } 1534 }
1540 1535
1541 force_iommu = 1; 1536 force_iommu = 1;
1542 bad_dma_address = 0x0; 1537 bad_dma_address = 0x0;
1543 dma_ops = &calgary_dma_ops; 1538 /* dma_ops is set to swiotlb or nommu */
1539 if (!dma_ops)
1540 dma_ops = &nommu_dma_ops;
1544 1541
1545 return 0; 1542 return 0;
1546} 1543}