aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/pci-calgary.c
diff options
context:
space:
mode:
authorMuli Ben-Yehuda <muli@il.ibm.com>2007-07-21 11:10:58 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-21 21:37:11 -0400
commit07877cf6fd559cbdced7ad4c15ab225a552ab692 (patch)
tree37308f9b7b50d63d2f96016a7c7846497a10cace /arch/x86_64/kernel/pci-calgary.c
parentddbd41b4e76f2b586366df0e85df80729ef90bc5 (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/kernel/pci-calgary.c')
-rw-r--r--arch/x86_64/kernel/pci-calgary.c67
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
1540static 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
1571static 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 */
1605rootfs_initcall(calgary_fixup_tce_spaces);