From dedc9937e876cb5430bca6a1dccfcc2ff22f8b7c Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH] x86-64: Calgary IOMMU: deobfuscate calgary_init calgary_init's for loop does not correspond to the actual device being checked, which makes its upperbound check for array overflow useless. Changing this to a do-while loop is the correct way of doing this. There should be no possibility of spinning forever in this loop, as pci_get_device states that it will go through all iterations, then return NULL (thus breaking the loop). Signed-off-by: Jon Mason Signed-off-by: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- arch/x86_64/kernel/pci-calgary.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/kernel/pci-calgary.c') diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index f760045d6d3..1100031528d 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -816,6 +816,8 @@ static int __init calgary_init_one(struct pci_dev *dev) void __iomem *bbar; int ret; + BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM); + address = locate_register_space(dev); /* map entire 1MB of Calgary config space */ bbar = ioremap_nocache(address, 1024 * 1024); @@ -842,10 +844,10 @@ done: static int __init calgary_init(void) { - int i, ret = -ENODEV; + int ret = -ENODEV; struct pci_dev *dev = NULL; - for (i = 0; i < MAX_PHB_BUS_NUM; i++) { + do { dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CALGARY, dev); @@ -861,12 +863,12 @@ static int __init calgary_init(void) ret = calgary_init_one(dev); if (ret) goto error; - } + } while (1); return ret; error: - for (i--; i >= 0; i--) { + do { dev = pci_find_device_reverse(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CALGARY, dev); @@ -882,7 +884,7 @@ error: calgary_disable_translation(dev); calgary_free_bus(dev); pci_dev_put(dev); /* Undo calgary_init_one()'s pci_dev_get() */ - } + } while (1); return ret; } -- cgit v1.2.3 From 76fd231717453e06347ad17b3fc1707c6918d172 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH] x86-64: Calgary IOMMU: Fix off by one when calculating register space location The purpose of the code being modified is to determine the location of the calgary chip address space. This is done by a magical formula of FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase) to find the offset where BIOS puts it. In this formula, OneBasedChassisNumber corresponds to the NUMA node, and rionodeid is always 2 or 3 depending on which chip in the system it is. The problem was that we had an off by one error that caused us to account some busses to the wrong chip and thus give them the wrong address space. Fixes RH bugzilla #203971. Signed-off-by: Jon Mason Signed-off-bu: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- arch/x86_64/kernel/pci-calgary.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/kernel/pci-calgary.c') diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index 1100031528d..3c0c7fde09d 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -790,7 +790,16 @@ static inline unsigned int __init locate_register_space(struct pci_dev *dev) int rionodeid; u32 address; - rionodeid = (dev->bus->number % 15 > 4) ? 3 : 2; + /* + * Each Calgary has four busses. The first four busses (first Calgary) + * have RIO node ID 2, then the next four (second Calgary) have RIO + * node ID 3, the next four (third Calgary) have node ID 2 again, etc. + * We use a gross hack - relying on the dev->bus->number ordering, + * modulo 14 - to decide which Calgary a given bus is on. Busses 0, 1, + * 2 and 4 are on the first Calgary (id 2), 6, 8, a and c are on the + * second (id 3), and then it repeats modulo 14. + */ + rionodeid = (dev->bus->number % 14 > 4) ? 3 : 2; /* * register space address calculation as follows: * FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase) @@ -798,7 +807,7 @@ static inline unsigned int __init locate_register_space(struct pci_dev *dev) * RioNodeId is 2 for first Calgary, 3 for second Calgary */ address = START_ADDRESS - - (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 15)) + + (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 14)) + (0x100000) * (rionodeid - CHASSIS_BASE); return address; } -- cgit v1.2.3 From d8d2bedf6002bf40b07fc5989dd9dbe56609fe3e Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH] x86-64: Calgary IOMMU: Update Jon's contact info Also add copyright for work done after leaving IBM. Signed-off-by: Jon Mason Signed-off-by: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- arch/x86_64/kernel/pci-calgary.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/kernel/pci-calgary.c') diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index 3c0c7fde09d..c4692b67878 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -2,8 +2,9 @@ * Derived from arch/powerpc/kernel/iommu.c * * Copyright (C) IBM Corporation, 2006 + * Copyright (C) 2006 Jon Mason * - * Author: Jon Mason + * Author: Jon Mason * Author: Muli Ben-Yehuda * This program is free software; you can redistribute it and/or modify -- cgit v1.2.3 From 70d666d6ae9724c0a08434c20f8830c90a635bd3 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 5 Oct 2006 18:47:21 +0200 Subject: [PATCH] x86-64: Calgary IOMMU: print PCI bus numbers in hex Make the references to the bus number in hex instead of decimal, as that is the way that lspci prints out the bus numbers. Signed-off-by: Jon Mason Signed-off-by: Muli Ben-Yehuda Signed-off-by: Andi Kleen --- arch/x86_64/kernel/pci-calgary.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/kernel/pci-calgary.c') diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index c4692b67878..b3296cc2f2f 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -715,7 +715,7 @@ static void calgary_watchdog(unsigned long data) /* If no error, the agent ID in the CSR is not valid */ if (val32 & CSR_AGENT_MASK) { - printk(KERN_EMERG "calgary_watchdog: DMA error on bus %d, " + printk(KERN_EMERG "calgary_watchdog: DMA error on PHB %#x, " "CSR = %#x\n", dev->bus->number, val32); writel(0, target); @@ -749,7 +749,7 @@ static void __init calgary_enable_translation(struct pci_dev *dev) val32 = be32_to_cpu(readl(target)); val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE; - printk(KERN_INFO "Calgary: enabling translation on PHB %d\n", busnum); + printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum); printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this " "bus.\n"); @@ -779,7 +779,7 @@ static void __init calgary_disable_translation(struct pci_dev *dev) val32 = be32_to_cpu(readl(target)); val32 &= ~(PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE); - printk(KERN_INFO "Calgary: disabling translation on PHB %d!\n", busnum); + printk(KERN_INFO "Calgary: disabling translation on PHB %#x!\n", busnum); writel(cpu_to_be32(val32), target); readl(target); /* flush */ @@ -1064,7 +1064,7 @@ static int __init calgary_parse_options(char *p) if (bridge < MAX_PHB_BUS_NUM) { printk(KERN_INFO "Calgary: disabling " - "translation for PHB 0x%x\n", bridge); + "translation for PHB %#x\n", bridge); bus_info[bridge].translation_disabled = 1; } } -- cgit v1.2.3