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>
This commit is contained in:
committed by
Linus Torvalds
parent
ddbd41b4e7
commit
07877cf6fd
@@ -1536,3 +1536,70 @@ static int __init calgary_parse_options(char *p)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
__setup("calgary=", calgary_parse_options);
|
__setup("calgary=", calgary_parse_options);
|
||||||
|
|
||||||
|
static void __init calgary_fixup_one_tce_space(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct iommu_table *tbl;
|
||||||
|
unsigned int npages;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
tbl = dev->sysdata;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
struct resource *r = &dev->resource[PCI_BRIDGE_RESOURCES + i];
|
||||||
|
|
||||||
|
/* Don't give out TCEs that map MEM resources */
|
||||||
|
if (!(r->flags & IORESOURCE_MEM))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* 0-based? we reserve the whole 1st MB anyway */
|
||||||
|
if (!r->start)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* cover the whole region */
|
||||||
|
npages = (r->end - r->start) >> PAGE_SHIFT;
|
||||||
|
npages++;
|
||||||
|
|
||||||
|
printk(KERN_DEBUG "Calg: dev %p [%x] tbl %p reserving "
|
||||||
|
"0x%Lx-0x%Lx [0x%x pages]\n", dev, dev->bus->number,
|
||||||
|
tbl, r->start, r->end, npages);
|
||||||
|
|
||||||
|
iommu_range_reserve(tbl, r->start, npages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init calgary_fixup_tce_spaces(void)
|
||||||
|
{
|
||||||
|
struct pci_dev *dev = NULL;
|
||||||
|
void *tce_space;
|
||||||
|
|
||||||
|
if (no_iommu || swiotlb || !calgary_detected)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
printk(KERN_DEBUG "Calgary: fixing tce spaces\n");
|
||||||
|
|
||||||
|
do {
|
||||||
|
dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
|
||||||
|
if (!dev)
|
||||||
|
break;
|
||||||
|
if (!is_cal_pci_dev(dev->device))
|
||||||
|
continue;
|
||||||
|
if (!translate_phb(dev))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tce_space = bus_info[dev->bus->number].tce_space;
|
||||||
|
if (!tce_space)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
calgary_fixup_one_tce_space(dev);
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to be call after pcibios_assign_resources (fs_initcall level)
|
||||||
|
* and before device_initcall.
|
||||||
|
*/
|
||||||
|
rootfs_initcall(calgary_fixup_tce_spaces);
|
||||||
|
Reference in New Issue
Block a user