diff options
Diffstat (limited to 'arch/x86/kernel/pci-calgary_64.c')
-rw-r--r-- | arch/x86/kernel/pci-calgary_64.c | 107 |
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 | ||
416 | static 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 | |||
432 | static int calgary_map_sg(struct device *dev, struct scatterlist *sg, | 416 | static 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: | |||
477 | static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr, | 458 | static 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 | ||
497 | static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle, | 472 | static 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 | |||
540 | free: | 508 | free: |
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 | ||
547 | static const struct dma_mapping_ops calgary_dma_ops = { | 515 | static 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 | |||
528 | static 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 | ||
1246 | error: | 1238 | error: |
@@ -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) | |||
1291 | static int __init build_detail_arrays(void) | 1284 | static 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 | */ |
1375 | static void get_tce_space_from_tar() | 1369 | static 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 | } |