diff options
Diffstat (limited to 'arch/x86/kernel/pci-calgary_64.c')
| -rw-r--r-- | arch/x86/kernel/pci-calgary_64.c | 94 |
1 files changed, 40 insertions, 54 deletions
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 971a3bec47a8..c563e4c8ff39 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include <asm/dma.h> | 46 | #include <asm/dma.h> |
| 47 | #include <asm/rio.h> | 47 | #include <asm/rio.h> |
| 48 | #include <asm/bios_ebda.h> | 48 | #include <asm/bios_ebda.h> |
| 49 | #include <asm/x86_init.h> | ||
| 49 | 50 | ||
| 50 | #ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT | 51 | #ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT |
| 51 | int use_calgary __read_mostly = 1; | 52 | int use_calgary __read_mostly = 1; |
| @@ -244,7 +245,7 @@ static unsigned long iommu_range_alloc(struct device *dev, | |||
| 244 | if (panic_on_overflow) | 245 | if (panic_on_overflow) |
| 245 | panic("Calgary: fix the allocator.\n"); | 246 | panic("Calgary: fix the allocator.\n"); |
| 246 | else | 247 | else |
| 247 | return bad_dma_address; | 248 | return DMA_ERROR_CODE; |
| 248 | } | 249 | } |
| 249 | } | 250 | } |
| 250 | 251 | ||
| @@ -260,12 +261,15 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, | |||
| 260 | void *vaddr, unsigned int npages, int direction) | 261 | void *vaddr, unsigned int npages, int direction) |
| 261 | { | 262 | { |
| 262 | unsigned long entry; | 263 | unsigned long entry; |
| 263 | dma_addr_t ret = bad_dma_address; | 264 | dma_addr_t ret; |
| 264 | 265 | ||
| 265 | entry = iommu_range_alloc(dev, tbl, npages); | 266 | entry = iommu_range_alloc(dev, tbl, npages); |
| 266 | 267 | ||
| 267 | if (unlikely(entry == bad_dma_address)) | 268 | if (unlikely(entry == DMA_ERROR_CODE)) { |
| 268 | goto error; | 269 | printk(KERN_WARNING "Calgary: failed to allocate %u pages in " |
| 270 | "iommu %p\n", npages, tbl); | ||
| 271 | return DMA_ERROR_CODE; | ||
| 272 | } | ||
| 269 | 273 | ||
| 270 | /* set the return dma address */ | 274 | /* set the return dma address */ |
| 271 | ret = (entry << PAGE_SHIFT) | ((unsigned long)vaddr & ~PAGE_MASK); | 275 | ret = (entry << PAGE_SHIFT) | ((unsigned long)vaddr & ~PAGE_MASK); |
| @@ -273,13 +277,7 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, | |||
| 273 | /* put the TCEs in the HW table */ | 277 | /* put the TCEs in the HW table */ |
| 274 | tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK, | 278 | tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK, |
| 275 | direction); | 279 | direction); |
| 276 | |||
| 277 | return ret; | 280 | return ret; |
| 278 | |||
| 279 | error: | ||
| 280 | printk(KERN_WARNING "Calgary: failed to allocate %u pages in " | ||
| 281 | "iommu %p\n", npages, tbl); | ||
| 282 | return bad_dma_address; | ||
| 283 | } | 281 | } |
| 284 | 282 | ||
| 285 | static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | 283 | static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, |
| @@ -290,8 +288,8 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
| 290 | unsigned long flags; | 288 | unsigned long flags; |
| 291 | 289 | ||
| 292 | /* were we called with bad_dma_address? */ | 290 | /* were we called with bad_dma_address? */ |
| 293 | badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE); | 291 | badend = DMA_ERROR_CODE + (EMERGENCY_PAGES * PAGE_SIZE); |
| 294 | if (unlikely((dma_addr >= bad_dma_address) && (dma_addr < badend))) { | 292 | if (unlikely((dma_addr >= DMA_ERROR_CODE) && (dma_addr < badend))) { |
| 295 | WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA " | 293 | WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA " |
| 296 | "address 0x%Lx\n", dma_addr); | 294 | "address 0x%Lx\n", dma_addr); |
| 297 | return; | 295 | return; |
| @@ -318,13 +316,15 @@ static inline struct iommu_table *find_iommu_table(struct device *dev) | |||
| 318 | 316 | ||
| 319 | pdev = to_pci_dev(dev); | 317 | pdev = to_pci_dev(dev); |
| 320 | 318 | ||
| 319 | /* search up the device tree for an iommu */ | ||
| 321 | pbus = pdev->bus; | 320 | pbus = pdev->bus; |
| 322 | 321 | do { | |
| 323 | /* is the device behind a bridge? Look for the root bus */ | 322 | tbl = pci_iommu(pbus); |
| 324 | while (pbus->parent) | 323 | if (tbl && tbl->it_busno == pbus->number) |
| 324 | break; | ||
| 325 | tbl = NULL; | ||
| 325 | pbus = pbus->parent; | 326 | pbus = pbus->parent; |
| 326 | 327 | } while (pbus); | |
| 327 | tbl = pci_iommu(pbus); | ||
| 328 | 328 | ||
| 329 | BUG_ON(tbl && (tbl->it_busno != pbus->number)); | 329 | BUG_ON(tbl && (tbl->it_busno != pbus->number)); |
| 330 | 330 | ||
| @@ -373,7 +373,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
| 373 | npages = iommu_num_pages(vaddr, s->length, PAGE_SIZE); | 373 | npages = iommu_num_pages(vaddr, s->length, PAGE_SIZE); |
| 374 | 374 | ||
| 375 | entry = iommu_range_alloc(dev, tbl, npages); | 375 | entry = iommu_range_alloc(dev, tbl, npages); |
| 376 | if (entry == bad_dma_address) { | 376 | if (entry == DMA_ERROR_CODE) { |
| 377 | /* makes sure unmap knows to stop */ | 377 | /* makes sure unmap knows to stop */ |
| 378 | s->dma_length = 0; | 378 | s->dma_length = 0; |
| 379 | goto error; | 379 | goto error; |
| @@ -391,7 +391,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
| 391 | error: | 391 | error: |
| 392 | calgary_unmap_sg(dev, sg, nelems, dir, NULL); | 392 | calgary_unmap_sg(dev, sg, nelems, dir, NULL); |
| 393 | for_each_sg(sg, s, nelems, i) { | 393 | for_each_sg(sg, s, nelems, i) { |
| 394 | sg->dma_address = bad_dma_address; | 394 | sg->dma_address = DMA_ERROR_CODE; |
| 395 | sg->dma_length = 0; | 395 | sg->dma_length = 0; |
| 396 | } | 396 | } |
| 397 | return 0; | 397 | return 0; |
| @@ -446,7 +446,7 @@ static void* calgary_alloc_coherent(struct device *dev, size_t size, | |||
| 446 | 446 | ||
| 447 | /* set up tces to cover the allocated range */ | 447 | /* set up tces to cover the allocated range */ |
| 448 | mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL); | 448 | mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL); |
| 449 | if (mapping == bad_dma_address) | 449 | if (mapping == DMA_ERROR_CODE) |
| 450 | goto free; | 450 | goto free; |
| 451 | *dma_handle = mapping; | 451 | *dma_handle = mapping; |
| 452 | return ret; | 452 | return ret; |
| @@ -727,7 +727,7 @@ static void __init calgary_reserve_regions(struct pci_dev *dev) | |||
| 727 | struct iommu_table *tbl = pci_iommu(dev->bus); | 727 | struct iommu_table *tbl = pci_iommu(dev->bus); |
| 728 | 728 | ||
| 729 | /* reserve EMERGENCY_PAGES from bad_dma_address and up */ | 729 | /* reserve EMERGENCY_PAGES from bad_dma_address and up */ |
| 730 | iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES); | 730 | iommu_range_reserve(tbl, DMA_ERROR_CODE, EMERGENCY_PAGES); |
| 731 | 731 | ||
| 732 | /* avoid the BIOS/VGA first 640KB-1MB region */ | 732 | /* avoid the BIOS/VGA first 640KB-1MB region */ |
| 733 | /* for CalIOC2 - avoid the entire first MB */ | 733 | /* for CalIOC2 - avoid the entire first MB */ |
| @@ -1344,6 +1344,23 @@ static void __init get_tce_space_from_tar(void) | |||
| 1344 | return; | 1344 | return; |
| 1345 | } | 1345 | } |
| 1346 | 1346 | ||
| 1347 | static int __init calgary_iommu_init(void) | ||
| 1348 | { | ||
| 1349 | int ret; | ||
| 1350 | |||
| 1351 | /* ok, we're trying to use Calgary - let's roll */ | ||
| 1352 | printk(KERN_INFO "PCI-DMA: Using Calgary IOMMU\n"); | ||
| 1353 | |||
| 1354 | ret = calgary_init(); | ||
| 1355 | if (ret) { | ||
| 1356 | printk(KERN_ERR "PCI-DMA: Calgary init failed %d, " | ||
| 1357 | "falling back to no_iommu\n", ret); | ||
| 1358 | return ret; | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | return 0; | ||
| 1362 | } | ||
| 1363 | |||
| 1347 | void __init detect_calgary(void) | 1364 | void __init detect_calgary(void) |
| 1348 | { | 1365 | { |
| 1349 | int bus; | 1366 | int bus; |
| @@ -1357,7 +1374,7 @@ void __init detect_calgary(void) | |||
| 1357 | * if the user specified iommu=off or iommu=soft or we found | 1374 | * if the user specified iommu=off or iommu=soft or we found |
| 1358 | * another HW IOMMU already, bail out. | 1375 | * another HW IOMMU already, bail out. |
| 1359 | */ | 1376 | */ |
| 1360 | if (swiotlb || no_iommu || iommu_detected) | 1377 | if (no_iommu || iommu_detected) |
| 1361 | return; | 1378 | return; |
| 1362 | 1379 | ||
| 1363 | if (!use_calgary) | 1380 | if (!use_calgary) |
| @@ -1442,9 +1459,7 @@ void __init detect_calgary(void) | |||
| 1442 | printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d\n", | 1459 | printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d\n", |
| 1443 | specified_table_size); | 1460 | specified_table_size); |
| 1444 | 1461 | ||
| 1445 | /* swiotlb for devices that aren't behind the Calgary. */ | 1462 | x86_init.iommu.iommu_init = calgary_iommu_init; |
| 1446 | if (max_pfn > MAX_DMA32_PFN) | ||
| 1447 | swiotlb = 1; | ||
| 1448 | } | 1463 | } |
| 1449 | return; | 1464 | return; |
| 1450 | 1465 | ||
| @@ -1457,35 +1472,6 @@ cleanup: | |||
| 1457 | } | 1472 | } |
| 1458 | } | 1473 | } |
| 1459 | 1474 | ||
| 1460 | int __init calgary_iommu_init(void) | ||
| 1461 | { | ||
| 1462 | int ret; | ||
| 1463 | |||
| 1464 | if (no_iommu || (swiotlb && !calgary_detected)) | ||
| 1465 | return -ENODEV; | ||
| 1466 | |||
| 1467 | if (!calgary_detected) | ||
| 1468 | return -ENODEV; | ||
| 1469 | |||
| 1470 | /* ok, we're trying to use Calgary - let's roll */ | ||
| 1471 | printk(KERN_INFO "PCI-DMA: Using Calgary IOMMU\n"); | ||
| 1472 | |||
| 1473 | ret = calgary_init(); | ||
| 1474 | if (ret) { | ||
| 1475 | printk(KERN_ERR "PCI-DMA: Calgary init failed %d, " | ||
| 1476 | "falling back to no_iommu\n", ret); | ||
| 1477 | return ret; | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | force_iommu = 1; | ||
| 1481 | bad_dma_address = 0x0; | ||
| 1482 | /* dma_ops is set to swiotlb or nommu */ | ||
| 1483 | if (!dma_ops) | ||
| 1484 | dma_ops = &nommu_dma_ops; | ||
| 1485 | |||
| 1486 | return 0; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | static int __init calgary_parse_options(char *p) | 1475 | static int __init calgary_parse_options(char *p) |
| 1490 | { | 1476 | { |
| 1491 | unsigned int bridge; | 1477 | unsigned int bridge; |
