From: Andi Kleen This patch has several fixes for serious x86-64 bugs in 2.6.8rc2. - Fix array overflow in PCI bus checking (Travis Betak) - Fix broken pci_map_sg in swiotlb (Suresh B. Siddha) - Remove bogus bus check in IOMMU code Signed-off-by: Andrew Morton --- 25-akpm/arch/x86_64/kernel/mpparse.c | 2 +- 25-akpm/arch/x86_64/kernel/pci-gart.c | 33 +++++++++++++++++++++++++-------- 25-akpm/include/asm-x86_64/mpspec.h | 2 +- 25-akpm/include/asm-x86_64/topology.h | 6 +++--- 4 files changed, 30 insertions(+), 13 deletions(-) diff -puN arch/x86_64/kernel/mpparse.c~critical-x86-64-patches-for-268rc2 arch/x86_64/kernel/mpparse.c --- 25/arch/x86_64/kernel/mpparse.c~critical-x86-64-patches-for-268rc2 2004-07-27 23:15:38.813793992 -0700 +++ 25-akpm/arch/x86_64/kernel/mpparse.c 2004-07-27 23:15:38.824792320 -0700 @@ -44,7 +44,7 @@ int acpi_found_madt; int apic_version [MAX_APICS]; unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; -cpumask_t mp_bus_to_cpumask [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = CPU_MASK_ALL }; +cpumask_t pci_bus_to_cpumask [256] = { [0 ... 255] = CPU_MASK_ALL }; int mp_current_pci_id = 0; /* I/O APIC entries */ diff -puN arch/x86_64/kernel/pci-gart.c~critical-x86-64-patches-for-268rc2 arch/x86_64/kernel/pci-gart.c --- 25/arch/x86_64/kernel/pci-gart.c~critical-x86-64-patches-for-268rc2 2004-07-27 23:15:38.815793688 -0700 +++ 25-akpm/arch/x86_64/kernel/pci-gart.c 2004-07-27 23:15:38.826792016 -0700 @@ -70,6 +70,8 @@ int iommu_fullflush = 1; static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED; static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */ +static u32 gart_unmapped_entry; + #define GPTE_VALID 1 #define GPTE_COHERENT 2 #define GPTE_ENCODE(x) \ @@ -147,8 +149,6 @@ static void free_iommu(unsigned long off static void flush_gart(struct pci_dev *dev) { unsigned long flags; - int bus = dev ? dev->bus->number : -1; - cpumask_t bus_cpumask = pcibus_to_cpumask(bus); int flushed = 0; int i; @@ -158,8 +158,6 @@ static void flush_gart(struct pci_dev *d u32 w; if (!northbridges[i]) continue; - if (bus >= 0 && !(cpu_isset(i, bus_cpumask))) - continue; pci_write_config_dword(northbridges[i], 0x9c, northbridge_flush_word[i] | 1); /* Make sure the hardware actually executed the flush. */ @@ -169,7 +167,7 @@ static void flush_gart(struct pci_dev *d flushed++; } if (!flushed) - printk("nothing to flush? %d\n", bus); + printk("nothing to flush?\n"); need_flush = 0; } spin_unlock_irqrestore(&iommu_bitmap_lock, flags); @@ -479,6 +477,11 @@ int pci_map_sg(struct pci_dev *dev, stru unsigned long pages = 0; int need = 0, nextneed; +#ifdef CONFIG_SWIOTLB + if (swiotlb) + return swiotlb_map_sg(&dev->dev,sg,nents,dir); +#endif + BUG_ON(dir == PCI_DMA_NONE); if (nents == 0) return 0; @@ -562,7 +565,7 @@ void pci_unmap_single(struct pci_dev *hw iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; npages = to_pages(dma_addr, size); for (i = 0; i < npages; i++) { - iommu_gatt_base[iommu_page + i] = 0; + iommu_gatt_base[iommu_page + i] = gart_unmapped_entry; CLEAR_LEAK(iommu_page + i); } free_iommu(iommu_page, npages); @@ -729,7 +732,8 @@ static int __init pci_iommu_init(void) unsigned long aper_size; unsigned long iommu_start; struct pci_dev *dev; - + unsigned long scratch; + long i; #ifndef CONFIG_AGP_AMD64 no_agp = 1; @@ -766,7 +770,7 @@ static int __init pci_iommu_init(void) return -1; } } - + aper_size = info.aper_size * 1024 * 1024; iommu_size = check_iommu_size(info.aper_base, aper_size); iommu_pages = iommu_size >> PAGE_SHIFT; @@ -815,6 +819,19 @@ static int __init pci_iommu_init(void) */ clear_kernel_mapping((unsigned long)__va(iommu_bus_base), iommu_size); + /* + * Try to workaround a bug (thanks to BenH) + * Set unmapped entries to a scratch page instead of 0. + * Any prefetches that hit unmapped entries won't get an bus abort + * then. + */ + scratch = get_zeroed_page(GFP_KERNEL); + if (!scratch) + panic("Cannot allocate iommu scratch page"); + gart_unmapped_entry = GPTE_ENCODE(__pa(scratch)); + for (i = EMERGENCY_PAGES; i < iommu_pages; i++) + iommu_gatt_base[i] = gart_unmapped_entry; + for_all_nb(dev) { u32 flag; int cpu = PCI_SLOT(dev->devfn) - 24; diff -puN include/asm-x86_64/mpspec.h~critical-x86-64-patches-for-268rc2 include/asm-x86_64/mpspec.h --- 25/include/asm-x86_64/mpspec.h~critical-x86-64-patches-for-268rc2 2004-07-27 23:15:38.817793384 -0700 +++ 25-akpm/include/asm-x86_64/mpspec.h 2004-07-27 23:15:38.826792016 -0700 @@ -166,7 +166,7 @@ enum mp_bustype { }; extern unsigned char mp_bus_id_to_type [MAX_MP_BUSSES]; extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; -extern cpumask_t mp_bus_to_cpumask [MAX_MP_BUSSES]; +extern cpumask_t pci_bus_to_cpumask [256]; extern unsigned int boot_cpu_physical_apicid; extern int smp_found_config; diff -puN include/asm-x86_64/topology.h~critical-x86-64-patches-for-268rc2 include/asm-x86_64/topology.h --- 25/include/asm-x86_64/topology.h~critical-x86-64-patches-for-268rc2 2004-07-27 23:15:38.819793080 -0700 +++ 25-akpm/include/asm-x86_64/topology.h 2004-07-27 23:15:38.827791864 -0700 @@ -22,9 +22,9 @@ extern cpumask_t node_to_cpumask[]; static inline cpumask_t pcibus_to_cpumask(int bus) { - cpumask_t tmp; - cpus_and(tmp, mp_bus_to_cpumask[bus], cpu_online_map); - return tmp; + cpumask_t res; + cpus_and(res, pci_bus_to_cpumask[bus], cpu_online_map); + return res; } #define NODE_BALANCE_RATE 30 /* CHECKME */ _