diff options
author | Muli Ben-Yehuda <muli@il.ibm.com> | 2007-07-21 11:10:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-21 21:37:11 -0400 |
commit | 07877cf6fd559cbdced7ad4c15ab225a552ab692 (patch) | |
tree | 37308f9b7b50d63d2f96016a7c7846497a10cace /arch/x86_64 | |
parent | ddbd41b4e76f2b586366df0e85df80729ef90bc5 (diff) |
x86_64: reserve TCEs with the same address as MEM regions
This works around a bug where DMAs that have the same addresses as
some MEM regions do not go through. Not clear yet if this is due to a
mis-configuration or something deeper.
[akpm@linux-foundation.org: coding style fixlet]
Signed-off-by: Muli Ben-Yehuda <muli@il.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/kernel/pci-calgary.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index ed16a107d2d4..b32d5797208f 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c | |||
@@ -1536,3 +1536,70 @@ static int __init calgary_parse_options(char *p) | |||
1536 | return 1; | 1536 | return 1; |
1537 | } | 1537 | } |
1538 | __setup("calgary=", calgary_parse_options); | 1538 | __setup("calgary=", calgary_parse_options); |
1539 | |||
1540 | static void __init calgary_fixup_one_tce_space(struct pci_dev *dev) | ||
1541 | { | ||
1542 | struct iommu_table *tbl; | ||
1543 | unsigned int npages; | ||
1544 | int i; | ||
1545 | |||
1546 | tbl = dev->sysdata; | ||
1547 | |||
1548 | for (i = 0; i < 4; i++) { | ||
1549 | struct resource *r = &dev->resource[PCI_BRIDGE_RESOURCES + i]; | ||
1550 | |||
1551 | /* Don't give out TCEs that map MEM resources */ | ||
1552 | if (!(r->flags & IORESOURCE_MEM)) | ||
1553 | continue; | ||
1554 | |||
1555 | /* 0-based? we reserve the whole 1st MB anyway */ | ||
1556 | if (!r->start) | ||
1557 | continue; | ||
1558 | |||
1559 | /* cover the whole region */ | ||
1560 | npages = (r->end - r->start) >> PAGE_SHIFT; | ||
1561 | npages++; | ||
1562 | |||
1563 | printk(KERN_DEBUG "Calg: dev %p [%x] tbl %p reserving " | ||
1564 | "0x%Lx-0x%Lx [0x%x pages]\n", dev, dev->bus->number, | ||
1565 | tbl, r->start, r->end, npages); | ||
1566 | |||
1567 | iommu_range_reserve(tbl, r->start, npages); | ||
1568 | } | ||
1569 | } | ||
1570 | |||
1571 | static int __init calgary_fixup_tce_spaces(void) | ||
1572 | { | ||
1573 | struct pci_dev *dev = NULL; | ||
1574 | void *tce_space; | ||
1575 | |||
1576 | if (no_iommu || swiotlb || !calgary_detected) | ||
1577 | return -ENODEV; | ||
1578 | |||
1579 | printk(KERN_DEBUG "Calgary: fixing tce spaces\n"); | ||
1580 | |||
1581 | do { | ||
1582 | dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev); | ||
1583 | if (!dev) | ||
1584 | break; | ||
1585 | if (!is_cal_pci_dev(dev->device)) | ||
1586 | continue; | ||
1587 | if (!translate_phb(dev)) | ||
1588 | continue; | ||
1589 | |||
1590 | tce_space = bus_info[dev->bus->number].tce_space; | ||
1591 | if (!tce_space) | ||
1592 | continue; | ||
1593 | |||
1594 | calgary_fixup_one_tce_space(dev); | ||
1595 | |||
1596 | } while (1); | ||
1597 | |||
1598 | return 0; | ||
1599 | } | ||
1600 | |||
1601 | /* | ||
1602 | * We need to be call after pcibios_assign_resources (fs_initcall level) | ||
1603 | * and before device_initcall. | ||
1604 | */ | ||
1605 | rootfs_initcall(calgary_fixup_tce_spaces); | ||