2007-05-22 08:06:29

by Muli Ben-Yehuda

[permalink] [raw]
Subject: Calgary updates for 2.6.23

Andi,

Here are Calgary updates for 2.6.23. The most notable change is the
addition of support for the CalIOC2 PCI-E IOMMU - more details in the
patchset. Please apply.

Thanks,
Muli



2007-05-22 08:06:49

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 5/15] x86-64: Calgary - abstract how we find the iommu_table for a device

From: Muli Ben-Yehuda <[email protected]>

... in preparation for doing it differently for CalIOC2.

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 21 ++++++++++++++-------
1 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index acee770..c5f92ea 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -344,6 +344,15 @@ static void iommu_free(struct iommu_tabl
spin_unlock_irqrestore(&tbl->it_lock, flags);
}

+static inline struct iommu_table *find_iommu_table(struct device *dev)
+{
+ struct iommu_table *tbl;
+
+ tbl = to_pci_dev(dev)->bus->self->sysdata;
+
+ return tbl;
+}
+
static void __calgary_unmap_sg(struct iommu_table *tbl,
struct scatterlist *sglist, int nelems, int direction)
{
@@ -365,7 +374,7 @@ void calgary_unmap_sg(struct device *dev
int nelems, int direction)
{
unsigned long flags;
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);

if (!translate_phb(to_pci_dev(dev)))
return;
@@ -394,7 +403,7 @@ static int calgary_nontranslate_map_sg(s
int calgary_map_sg(struct device *dev, struct scatterlist *sg,
int nelems, int direction)
{
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);
unsigned long flags;
unsigned long vaddr;
unsigned int npages;
@@ -448,7 +457,7 @@ dma_addr_t calgary_map_single(struct dev
dma_addr_t dma_handle = bad_dma_address;
unsigned long uaddr;
unsigned int npages;
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);

uaddr = (unsigned long)vaddr;
npages = num_dma_pages(uaddr, size);
@@ -464,7 +473,7 @@ dma_addr_t calgary_map_single(struct dev
void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
size_t size, int direction)
{
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);
unsigned int npages;

if (!translate_phb(to_pci_dev(dev)))
@@ -480,9 +489,7 @@ void* calgary_alloc_coherent(struct devi
void *ret = NULL;
dma_addr_t mapping;
unsigned int npages, order;
- struct iommu_table *tbl;
-
- tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);

size = PAGE_ALIGN(size); /* size rounded up to full pages */
npages = size >> PAGE_SHIFT;
--
1.4.4

2007-05-22 08:07:14

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 6/15] x86-64: Calgary - introduce CalIOC2 support

From: Muli Ben-Yehuda <[email protected]>

CalIOC2 is a PCI-e implementation of the Calgary logic. Most of the
programming details are the same, but some differ, e.g., TCE cache
flush. This patch introduces CalIOC2 support - detection and various
support routines. It's not expected to work yet (but will with
follow-on patches).

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 196 ++++++++++++++++++++++++++++++--------
1 files changed, 156 insertions(+), 40 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index c5f92ea..3945437 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -50,8 +50,7 @@ int use_calgary __read_mostly = 0;
#endif /* CONFIG_CALGARY_DEFAULT_ENABLED */

#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
-#define PCI_VENDOR_DEVICE_ID_CALGARY \
- (PCI_VENDOR_ID_IBM | PCI_DEVICE_ID_IBM_CALGARY << 16)
+#define PCI_DEVICE_ID_IBM_CALIOC2 0x0308

/* we need these for register space address calculation */
#define START_ADDRESS 0xfe000000
@@ -193,6 +192,7 @@ static inline unsigned long verify_bit_r
{
return ~0UL;
}
+
#endif /* CONFIG_IOMMU_DEBUG */

static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
@@ -346,9 +346,20 @@ static void iommu_free(struct iommu_tabl

static inline struct iommu_table *find_iommu_table(struct device *dev)
{
+ struct pci_dev *pdev;
+ struct pci_bus *pbus;
struct iommu_table *tbl;

- tbl = to_pci_dev(dev)->bus->self->sysdata;
+ pdev = to_pci_dev(dev);
+
+ /* is the device behind a bridge? */
+ if (unlikely(pdev->bus->parent))
+ pbus = pdev->bus->parent;
+ else
+ pbus = pdev->bus;
+
+ tbl = pbus->self->sysdata;
+ BUG_ON(pdev->bus->parent && (tbl->it_busno != pdev->bus->parent->number));

return tbl;
}
@@ -565,6 +576,21 @@ static inline void __iomem* calgary_reg(
return (void __iomem*)target;
}

+static inline int is_calioc2(unsigned short device)
+{
+ return (device == PCI_DEVICE_ID_IBM_CALIOC2);
+}
+
+static inline int is_calgary(unsigned short device)
+{
+ return (device == PCI_DEVICE_ID_IBM_CALGARY);
+}
+
+static inline int is_cal_pci_dev(unsigned short device)
+{
+ return (is_calgary(device) || is_calioc2(device));
+}
+
static void calgary_tce_cache_blast(struct iommu_table *tbl)
{
u64 val;
@@ -685,8 +711,14 @@ static void __init calgary_reserve_regio
iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES);

/* avoid the BIOS/VGA first 640KB-1MB region */
- start = (640 * 1024);
- npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+ /* for CalIOC2 - avoid the entire first 2MB */
+ if (is_calgary(dev->device)) {
+ start = (640 * 1024);
+ npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+ } else { /* calioc2 */
+ start = 0;
+ npages = (2 * 1024 * 1024) >> PAGE_SHIFT;
+ }
iommu_range_reserve(tbl, start, npages);

/* reserve the two PCI peripheral memory regions in IO space */
@@ -721,15 +753,15 @@ static int __init calgary_setup_tar(stru

/* zero out all TAR bits under sw control */
val64 &= ~TAR_SW_BITS;
-
- tbl = dev->sysdata;
table_phys = (u64)__pa(tbl->it_base);
+
val64 |= table_phys;

BUG_ON(specified_table_size > TCE_TABLE_SIZE_8M);
val64 |= (u64) specified_table_size;

tbl->tar_val = cpu_to_be64(val64);
+
writeq(tbl->tar_val, target);
readq(target); /* flush */

@@ -760,6 +792,43 @@ static void __init calgary_free_bus(stru
bus_info[dev->bus->number].tce_space = NULL;
}

+static void calgary_dump_error_regs(struct iommu_table *tbl)
+{
+ void __iomem *bbar = tbl->bbar;
+ u32 csr, csmr, plssr, mck;
+ void __iomem *target;
+ unsigned long phboff = phb_offset(tbl->it_busno);
+ unsigned long erroff;
+ u32 errregs[7];
+ int i;
+
+ /* dump CSR */
+ target = calgary_reg(bbar, phboff | PHB_CSR_OFFSET);
+ csr = be32_to_cpu(readl(target));
+ /* dump PLSSR */
+ target = calgary_reg(bbar, phboff | PHB_PLSSR_OFFSET);
+ plssr = be32_to_cpu(readl(target));
+ /* dump CSMR */
+ target = calgary_reg(bbar, phboff | 0x290);
+ csmr = be32_to_cpu(readl(target));
+ /* dump mck */
+ target = calgary_reg(bbar, phboff | 0x800);
+ mck = be32_to_cpu(readl(target));
+
+ printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR "
+ "0x%08x@MCK\n", csr, plssr, csmr, mck);
+
+ /* dump rest of error regs */
+ printk(KERN_EMERG "Calgary: ");
+ for (i = 0; i < ARRAY_SIZE(errregs); i++) {
+ erroff = (0x810 + (i * 0x10)); /* err regs are at 0x810 - 0x870 */
+ target = calgary_reg(bbar, phboff | erroff);
+ errregs[i] = be32_to_cpu(readl(target));
+ printk("0x%08x@0x%lx ", errregs[i], erroff);
+ }
+ printk("\n");
+}
+
static void calgary_watchdog(unsigned long data)
{
struct pci_dev *dev = (struct pci_dev *)data;
@@ -773,13 +842,16 @@ static void calgary_watchdog(unsigned lo

/* 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 PHB %#x, "
- "CSR = %#x\n", dev->bus->number, val32);
+ printk(KERN_EMERG "Calgary: DMA error on PHB %#x\n",
+ dev->bus->number);
+ calgary_dump_error_regs(tbl);
+
+ /* reset error */
writel(0, target);

/* Disable bus that caused the error */
target = calgary_reg(bbar, phb_offset(tbl->it_busno) |
- PHB_CONFIG_RW_OFFSET);
+ PHB_CONFIG_RW_OFFSET);
val32 = be32_to_cpu(readl(target));
val32 |= PHB_SLOT_DISABLE;
writel(cpu_to_be32(val32), target);
@@ -853,7 +925,9 @@ static void __init calgary_enable_transl
val32 = be32_to_cpu(readl(target));
val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE;

- printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum);
+ printk(KERN_INFO "Calgary: enabling translation on %s PHB %#x\n",
+ (dev->device == PCI_DEVICE_ID_IBM_CALGARY) ?
+ "Calgary" : "CalIOC2", busnum);
printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this "
"bus.\n");

@@ -894,7 +968,12 @@ static void __init calgary_init_one_nont
{
pci_dev_get(dev);
dev->sysdata = NULL;
- dev->bus->self = dev;
+
+ /* is the device behind a bridge? */
+ if (dev->bus->parent)
+ dev->bus->parent->self = dev;
+ else
+ dev->bus->self = dev;
}

static int __init calgary_init_one(struct pci_dev *dev)
@@ -911,7 +990,14 @@ static int __init calgary_init_one(struc
goto done;

pci_dev_get(dev);
- dev->bus->self = dev;
+
+ if (dev->bus->parent) {
+ if (dev->bus->parent->self)
+ printk(KERN_WARNING "Calgary: IEEEE, dev %p has "
+ "bus->parent->self!\n", dev);
+ dev->bus->parent->self = dev;
+ } else
+ dev->bus->self = dev;

tbl = dev->sysdata;
tbl->chip_ops->handle_quirks(tbl, dev);
@@ -951,11 +1037,18 @@ static int __init calgary_locate_bbars(v
target = calgary_reg(bbar, offset);

val = be32_to_cpu(readl(target));
+
start_bus = (u8)((val & 0x00FF0000) >> 16);
end_bus = (u8)((val & 0x0000FF00) >> 8);
- for (bus = start_bus; bus <= end_bus; bus++) {
- bus_info[bus].bbar = bbar;
- bus_info[bus].phbid = phb;
+
+ if (end_bus) {
+ for (bus = start_bus; bus <= end_bus; bus++) {
+ bus_info[bus].bbar = bbar;
+ bus_info[bus].phbid = phb;
+ }
+ } else {
+ bus_info[start_bus].bbar = bbar;
+ bus_info[start_bus].phbid = phb;
}
}
}
@@ -975,24 +1068,27 @@ static int __init calgary_init(void)
{
int ret;
struct pci_dev *dev = NULL;
+ void* tce_space;

ret = calgary_locate_bbars();
if (ret)
return ret;

do {
- dev = pci_get_device(PCI_VENDOR_ID_IBM,
- PCI_DEVICE_ID_IBM_CALGARY,
- dev);
+ 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)) {
calgary_init_one_nontraslated(dev);
continue;
}
- if (!bus_info[dev->bus->number].tce_space && !translate_empty_slots)
+ tce_space = bus_info[dev->bus->number].tce_space;
+ if (!tce_space && !translate_empty_slots) {
+ printk("Calg: %p failed tce_space check\n", dev);
continue;
-
+ }
ret = calgary_init_one(dev);
if (ret)
goto error;
@@ -1003,10 +1099,11 @@ static int __init calgary_init(void)
error:
do {
dev = pci_get_device_reverse(PCI_VENDOR_ID_IBM,
- PCI_DEVICE_ID_IBM_CALGARY,
- dev);
+ PCI_ANY_ID, dev);
if (!dev)
break;
+ if (!is_cal_pci_dev(dev->device))
+ continue;
if (!translate_phb(dev)) {
pci_dev_put(dev);
continue;
@@ -1084,9 +1181,29 @@ static int __init build_detail_arrays(vo
return 0;
}

-void __init detect_calgary(void)
+static int __init calgary_bus_has_devices(int bus, unsigned short pci_dev)
{
+ int dev;
u32 val;
+
+ if (pci_dev == PCI_DEVICE_ID_IBM_CALIOC2) {
+ /*
+ * FIXME: properly scan for devices accross the
+ * PCI-to-PCI bridge on every CalIOC2 port.
+ */
+ return 1;
+ }
+
+ for (dev = 1; dev < 8; dev++) {
+ val = read_pci_config(bus, dev, 0, 0);
+ if (val != 0xffffffff)
+ break;
+ }
+ return (val != 0xffffffff);
+}
+
+void __init detect_calgary(void)
+{
int bus;
void *tbl;
int calgary_found = 0;
@@ -1143,29 +1260,28 @@ void __init detect_calgary(void)
specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);

for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
- int dev;
struct calgary_bus_info *info = &bus_info[bus];
+ unsigned short pci_device;
+ u32 val;
+
+ val = read_pci_config(bus, 0, 0, 0);
+ pci_device = (val & 0xFFFF0000) >> 16;

- if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
+ if (!is_cal_pci_dev(pci_device))
continue;

if (info->translation_disabled)
continue;

- /*
- * Scan the slots of the PCI bus to see if there is a device present.
- * The parent bus will be the zero-ith device, so start at 1.
- */
- for (dev = 1; dev < 8; dev++) {
- val = read_pci_config(bus, dev, 0, 0);
- if (val != 0xffffffff || translate_empty_slots) {
- tbl = alloc_tce_table();
- if (!tbl)
- goto cleanup;
- info->tce_space = tbl;
- calgary_found = 1;
- break;
- }
+ if (calgary_bus_has_devices(bus, pci_device) ||
+ translate_empty_slots) {
+ tbl = alloc_tce_table();
+ if (!tbl)
+ goto cleanup;
+ info->tce_space = tbl;
+ calgary_found = 1;
+ printk("Calg: allocated tce_table %p for bus 0x%x\n",
+ info->tce_space, bus);
}
}

--
1.4.4

2007-05-22 08:07:41

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 10/15] x86-64: Calgary - grab PLSSR too when a DMA error occurs

From: Muli Ben-Yehuda <[email protected]>

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 57ac81b..a49b19d 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -902,15 +902,18 @@ static void __init calgary_free_bus(stru
static void calgary_dump_error_regs(struct iommu_table *tbl)
{
void __iomem *bbar = tbl->bbar;
- u32 val32;
void __iomem *target;
+ u32 csr, plssr;

target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_CSR_OFFSET);
- val32 = be32_to_cpu(readl(target));
+ csr = be32_to_cpu(readl(target));
+
+ target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_PLSSR_OFFSET);
+ plssr = be32_to_cpu(readl(target));

/* If no error, the agent ID in the CSR is not valid */
printk(KERN_EMERG "Calgary: DMA error on Calgary PHB 0x%x, "
- "CSR = 0x%08x\n", tbl->it_busno, val32);
+ "0x%08x@CSR 0x%08x@PLSSR\n", tbl->it_busno, csr, plssr);
}

static void calioc2_dump_error_regs(struct iommu_table *tbl)
--
1.4.4

2007-05-22 08:08:07

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 2/15] x86-64: Calgary - update copyright notice

From: Muli Ben-Yehuda <[email protected]>

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 4b0c3ad..b1ab0d5 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -1,7 +1,7 @@
/*
* Derived from arch/powerpc/kernel/iommu.c
*
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
* Copyright (C) 2006 Jon Mason <[email protected]>
*
* Author: Jon Mason <[email protected]>
--
1.4.4

2007-05-22 08:08:32

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 1/15] x86-64: Calgary - generalize calgary_increase_split_completion_timeout

From: Muli Ben-Yehuda <[email protected]>

... will be used by CalIOC2 later

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 5bd20b5..4b0c3ad 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -775,8 +775,8 @@ static void calgary_watchdog(unsigned lo
}
}

-static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
- unsigned char busnum)
+static void __init calgary_set_split_completion_timeout(void __iomem *bbar,
+ unsigned char busnum, unsigned long timeout)
{
u64 val64;
void __iomem *target;
@@ -802,7 +802,7 @@ static void __init calgary_increase_spli
/* zero out this PHB's timer bits */
mask = ~(0xFUL << phb_shift);
val64 &= mask;
- val64 |= (CCR_2SEC_TIMEOUT << phb_shift);
+ val64 |= (timeout << phb_shift);
writeq(cpu_to_be64(val64), target);
readq(target); /* flush */
}
@@ -836,7 +836,8 @@ static void __init calgary_enable_transl
* http://bugzilla.kernel.org/show_bug.cgi?id=7180
*/
if (busnum == 1)
- calgary_increase_split_completion_timeout(bbar, busnum);
+ calgary_set_split_completion_timeout(bbar, busnum,
+ CCR_2SEC_TIMEOUT);

init_timer(&tbl->watchdog_timer);
tbl->watchdog_timer.function = &calgary_watchdog;
--
1.4.4

2007-05-22 08:08:54

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 9/15] x86-64: Calgary - make dump_error_regs a chip op

From: Muli Ben-Yehuda <[email protected]>

Provide seperate versions for Calgary and CalIOC2

Also print out the PCIe Root Complex Status on CalIOC2 errors

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 43 ++++++++++++++++++++++++++++++-------
include/asm-x86_64/calgary.h | 1 +
2 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 06a5db3..57ac81b 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -83,6 +83,7 @@ int use_calgary __read_mostly = 0;
#define PHB_SAVIOR_L2 0x0DB0
#define PHB_PAGE_MIG_CTRL 0x0DA8
#define PHB_PAGE_MIG_DEBUG 0x0DA0
+#define PHB_ROOT_COMPLEX_STATUS 0x0CB0

/* PHB_CONFIG_RW */
#define PHB_TCE_ENABLE 0x20000000
@@ -163,20 +164,25 @@ struct calgary_bus_info {
void __iomem *bbar;
};

+
static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
static void calgary_tce_cache_blast(struct iommu_table *tbl);
+static void calgary_dump_error_regs(struct iommu_table *tbl);

static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
static void calioc2_tce_cache_blast(struct iommu_table *tbl);
+static void calioc2_dump_error_regs(struct iommu_table *tbl);

struct cal_chipset_ops calgary_chip_ops = {
.handle_quirks = calgary_handle_quirks,
- .tce_cache_blast = calgary_tce_cache_blast
+ .tce_cache_blast = calgary_tce_cache_blast,
+ .dump_error_regs = calgary_dump_error_regs
};

struct cal_chipset_ops calioc2_chip_ops = {
.handle_quirks = calioc2_handle_quirks,
- .tce_cache_blast = calioc2_tce_cache_blast
+ .tce_cache_blast = calioc2_tce_cache_blast,
+ .dump_error_regs = calioc2_dump_error_regs
};

static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
@@ -896,7 +902,21 @@ static void __init calgary_free_bus(stru
static void calgary_dump_error_regs(struct iommu_table *tbl)
{
void __iomem *bbar = tbl->bbar;
- u32 csr, csmr, plssr, mck;
+ u32 val32;
+ void __iomem *target;
+
+ target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_CSR_OFFSET);
+ val32 = be32_to_cpu(readl(target));
+
+ /* If no error, the agent ID in the CSR is not valid */
+ printk(KERN_EMERG "Calgary: DMA error on Calgary PHB 0x%x, "
+ "CSR = 0x%08x\n", tbl->it_busno, val32);
+}
+
+static void calioc2_dump_error_regs(struct iommu_table *tbl)
+{
+ void __iomem *bbar = tbl->bbar;
+ u32 csr, csmr, plssr, mck, rcstat;
void __iomem *target;
unsigned long phboff = phb_offset(tbl->it_busno);
unsigned long erroff;
@@ -916,8 +936,11 @@ static void calgary_dump_error_regs(stru
target = calgary_reg(bbar, phboff | 0x800);
mck = be32_to_cpu(readl(target));

- printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR "
- "0x%08x@MCK\n", csr, plssr, csmr, mck);
+ printk(KERN_EMERG "Calgary: DMA error on CalIOC2 PHB 0x%x\n",
+ tbl->it_busno);
+
+ printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
+ csr, plssr, csmr, mck);

/* dump rest of error regs */
printk(KERN_EMERG "Calgary: ");
@@ -928,6 +951,12 @@ static void calgary_dump_error_regs(stru
printk("0x%08x@0x%lx ", errregs[i], erroff);
}
printk("\n");
+
+ /* root complex status */
+ target = calgary_reg(bbar, phboff | PHB_ROOT_COMPLEX_STATUS);
+ rcstat = be32_to_cpu(readl(target));
+ printk(KERN_EMERG "Calgary: 0x%08x@0x%x\n", rcstat,
+ PHB_ROOT_COMPLEX_STATUS);
}

static void calgary_watchdog(unsigned long data)
@@ -943,9 +972,7 @@ static void calgary_watchdog(unsigned lo

/* If no error, the agent ID in the CSR is not valid */
if (val32 & CSR_AGENT_MASK) {
- printk(KERN_EMERG "Calgary: DMA error on PHB %#x\n",
- dev->bus->number);
- calgary_dump_error_regs(tbl);
+ tbl->chip_ops->dump_error_regs(tbl);

/* reset error */
writel(0, target);
diff --git a/include/asm-x86_64/calgary.h b/include/asm-x86_64/calgary.h
index 3aa8ad5..3c81436 100644
--- a/include/asm-x86_64/calgary.h
+++ b/include/asm-x86_64/calgary.h
@@ -45,6 +45,7 @@ struct iommu_table {
struct cal_chipset_ops {
void (*handle_quirks)(struct iommu_table *tbl, struct pci_dev *dev);
void (*tce_cache_blast)(struct iommu_table *tbl);
+ void (*dump_error_regs)(struct iommu_table *tbl);
};

#define TCE_TABLE_SIZE_UNSPECIFIED ~0
--
1.4.4

2007-05-22 08:09:19

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 8/15] x86-64: Calgary - implement CalIOC2 TCE cache flush sequence

From: Muli Ben-Yehuda <[email protected]>

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 88 +++++++++++++++++++++++++++++++++++++-
1 files changed, 87 insertions(+), 1 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index ee0b52c..06a5db3 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -81,6 +81,8 @@ int use_calgary __read_mostly = 0;

/* CalIOC2 specific */
#define PHB_SAVIOR_L2 0x0DB0
+#define PHB_PAGE_MIG_CTRL 0x0DA8
+#define PHB_PAGE_MIG_DEBUG 0x0DA0

/* PHB_CONFIG_RW */
#define PHB_TCE_ENABLE 0x20000000
@@ -95,6 +97,10 @@ int use_calgary __read_mostly = 0;
#define CSR_AGENT_MASK 0xffe0ffff
/* CCR (Calgary Configuration Register) */
#define CCR_2SEC_TIMEOUT 0x000000000000000EUL
+/* PMCR/PMDR (Page Migration Control/Debug Registers */
+#define PMR_SOFTSTOP 0x80000000
+#define PMR_SOFTSTOPFAULT 0x40000000
+#define PMR_HARDSTOP 0x20000000

#define MAX_NUM_OF_PHBS 8 /* how many PHBs in total? */
#define MAX_NUM_CHASSIS 8 /* max number of chassis */
@@ -161,6 +167,7 @@ static void calgary_handle_quirks(struct
static void calgary_tce_cache_blast(struct iommu_table *tbl);

static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calioc2_tce_cache_blast(struct iommu_table *tbl);

struct cal_chipset_ops calgary_chip_ops = {
.handle_quirks = calgary_handle_quirks,
@@ -169,7 +176,7 @@ struct cal_chipset_ops calgary_chip_ops

struct cal_chipset_ops calioc2_chip_ops = {
.handle_quirks = calioc2_handle_quirks,
- .tce_cache_blast = NULL
+ .tce_cache_blast = calioc2_tce_cache_blast
};

static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
@@ -638,6 +645,85 @@ static void calgary_tce_cache_blast(stru
(void)readl(target); /* flush */
}

+static void calioc2_tce_cache_blast(struct iommu_table *tbl)
+{
+ void __iomem *bbar = tbl->bbar;
+ void __iomem *target;
+ u64 val64;
+ u32 val;
+ int i = 0;
+ int count = 1;
+ unsigned char bus = tbl->it_busno;
+
+begin:
+ printk(KERN_DEBUG "Calgary: CalIOC2 bus 0x%x entering tce cache blast "
+ "sequence - count %d\n", bus, count);
+
+ /* 1. using the Page Migration Control reg set SoftStop */
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "1a. read 0x%x [LE] from %p\n", val, target);
+ val |= PMR_SOFTSTOP;
+ printk(KERN_DEBUG "1b. writing 0x%x [LE] to %p\n", val, target);
+ writel(cpu_to_be32(val), target);
+
+ /* 2. poll split queues until all DMA activity is done */
+ printk(KERN_DEBUG "2a. starting to poll split queues\n");
+ target = calgary_reg(bbar, split_queue_offset(bus));
+ do {
+ val64 = readq(target);
+ i++;
+ } while ((val64 & 0xff) != 0xff && i < 100);
+ if (i == 100)
+ printk(KERN_WARNING "CalIOC2: PCI bus not quiesced, "
+ "continuing anyway\n");
+
+ /* 3. poll Page Migration DEBUG for SoftStopFault */
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "3. read 0x%x [LE] from %p\n", val, target);
+
+ /* 4. if SoftStopFault - goto (1) */
+ if (val & PMR_SOFTSTOPFAULT) {
+ if (++count < 100)
+ goto begin;
+ else {
+ printk(KERN_WARNING "CalIOC2: too many SoftStopFaults, "
+ "aborting TCE cache flush sequence!\n");
+ return; /* pray for the best */
+ }
+ }
+
+ /* 5. Slam into HardStop by reading PHB_PAGE_MIG_CTRL */
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ printk(KERN_DEBUG "5a. slamming into HardStop by reading %p\n", target);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "5b. read 0x%x [LE] from %p\n", val, target);
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "5c. read 0x%x [LE] from %p (debug)\n", val, target);
+
+ /* 6. invalidate TCE cache */
+ printk(KERN_DEBUG "6. invalidating TCE cache\n");
+ target = calgary_reg(bbar, tar_offset(bus));
+ writeq(tbl->tar_val, target);
+
+ /* 7. Re-read PMCR */
+ printk(KERN_DEBUG "7a. Re-reading PMCR\n");
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "7b. read 0x%x [LE] from %p\n", val, target);
+
+ /* 8. Remove HardStop */
+ printk(KERN_DEBUG "8a. removing HardStop from PMCR\n");
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ val = 0;
+ printk(KERN_DEBUG "8b. writing 0x%x [LE] to %p\n", val, target);
+ writel(cpu_to_be32(val), target);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "8c. read 0x%x [LE] from %p\n", val, target);
+}
+
static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
u64 limit)
{
--
1.4.4

2007-05-22 08:09:42

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 14/15] x86-64: Calgary - only reserve the first 1MB of IO space for CalIOC2

From: Muli Ben-Yehuda <[email protected]>

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 0bb0eb0..1df556c 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -808,13 +808,13 @@ static void __init calgary_reserve_regio
iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES);

/* avoid the BIOS/VGA first 640KB-1MB region */
- /* for CalIOC2 - avoid the entire first 2MB */
+ /* for CalIOC2 - avoid the entire first MB */
if (is_calgary(dev->device)) {
start = (640 * 1024);
npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
} else { /* calioc2 */
start = 0;
- npages = (2 * 1024 * 1024) >> PAGE_SHIFT;
+ npages = (1 * 1024 * 1024) >> PAGE_SHIFT;
}
iommu_range_reserve(tbl, start, npages);

--
1.4.4

2007-05-22 08:10:09

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 7/15] x86-64: Calgary - add chip_ops and a quirk function for CalIOC2

From: Muli Ben-Yehuda <[email protected]>

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 38 ++++++++++++++++++++++++++++++++++----
1 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 3945437..ee0b52c 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -79,6 +79,9 @@ int use_calgary __read_mostly = 0;
#define PHB_MEM_2_SIZE_LOW 0x02E0
#define PHB_DOSHOLE_OFFSET 0x08E0

+/* CalIOC2 specific */
+#define PHB_SAVIOR_L2 0x0DB0
+
/* PHB_CONFIG_RW */
#define PHB_TCE_ENABLE 0x20000000
#define PHB_SLOT_DISABLE 0x1C000000
@@ -157,11 +160,18 @@ struct calgary_bus_info {
static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
static void calgary_tce_cache_blast(struct iommu_table *tbl);

+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+
struct cal_chipset_ops calgary_chip_ops = {
.handle_quirks = calgary_handle_quirks,
.tce_cache_blast = calgary_tce_cache_blast
};

+struct cal_chipset_ops calioc2_chip_ops = {
+ .handle_quirks = calioc2_handle_quirks,
+ .tce_cache_blast = NULL
+};
+
static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };

/* enable this to stress test the chip's TCE cache */
@@ -743,7 +753,12 @@ static int __init calgary_setup_tar(stru
tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
tce_free(tbl, 0, tbl->it_size);

- tbl->chip_ops = &calgary_chip_ops;
+ if (is_calgary(dev->device))
+ tbl->chip_ops = &calgary_chip_ops;
+ else if (is_calioc2(dev->device))
+ tbl->chip_ops = &calioc2_chip_ops;
+ else
+ BUG();

calgary_reserve_regions(dev);

@@ -894,8 +909,23 @@ static void __init calgary_set_split_com
readq(target); /* flush */
}

-static void __init calgary_handle_quirks(struct iommu_table *tbl,
- struct pci_dev *dev)
+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+{
+ unsigned char busnum = dev->bus->number;
+ void __iomem *bbar = tbl->bbar;
+ void __iomem *target;
+ u32 val;
+
+ /*
+ * CalIOC2 designers recommend setting bit 8 in 0xnDB0 to 1
+ */
+ target = calgary_reg(bbar, phb_offset(busnum) | PHB_SAVIOR_L2);
+ val = cpu_to_be32(readl(target));
+ val |= 0x00800000;
+ writel(cpu_to_be32(val), target);
+}
+
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
{
unsigned char busnum = dev->bus->number;

@@ -903,7 +933,7 @@ static void __init calgary_handle_quirks
* Give split completion a longer timeout on bus 1 for aic94xx
* http://bugzilla.kernel.org/show_bug.cgi?id=7180
*/
- if (busnum == 1)
+ if (is_calgary(dev->device) && (busnum == 1))
calgary_set_split_completion_timeout(tbl->bbar, busnum,
CCR_2SEC_TIMEOUT);
}
--
1.4.4

2007-05-22 08:10:40

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 15/15] x86-64: Calgary - tidy up debug printks

From: Muli Ben-Yehuda <[email protected]>

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 13 +++----------
1 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 1df556c..0bbe839 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -1226,10 +1226,9 @@ static int __init calgary_init(void)
continue;
}
tce_space = bus_info[dev->bus->number].tce_space;
- if (!tce_space && !translate_empty_slots) {
- printk("Calg: %p failed tce_space check\n", dev);
+ if (!tce_space && !translate_empty_slots)
continue;
- }
+
ret = calgary_init_one(dev);
if (ret)
goto error;
@@ -1421,8 +1420,6 @@ void __init detect_calgary(void)
goto cleanup;
info->tce_space = tbl;
calgary_found = 1;
- printk("Calg: allocated tce_table %p for bus 0x%x\n",
- info->tce_space, bus);
}
}

@@ -1557,10 +1554,6 @@ static void __init calgary_fixup_one_tce
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);
}
}
@@ -1573,7 +1566,7 @@ static int __init calgary_fixup_tce_spac
if (no_iommu || swiotlb || !calgary_detected)
return -ENODEV;

- printk(KERN_DEBUG "Calgary: fixing tce spaces\n");
+ printk(KERN_DEBUG "Calgary: fixing up tce spaces\n");

do {
dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
--
1.4.4

2007-05-22 08:11:06

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 4/15] x86-64: Calgary - introduce chipset specific ops

From: Muli Ben-Yehuda <[email protected]>

Calgary and CalIOC2 share most of the same logic. Introduce struct
cal_chipset_ops for quirks and tce flush logic which are
different. CalIOC2 implementation to appear in a later patch.

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 24 +++++++++++++++++-------
include/asm-x86_64/calgary.h | 8 +++++++-
2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 9f6dd44..acee770 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -155,9 +155,15 @@ struct calgary_bus_info {
void __iomem *bbar;
};

-static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calgary_tce_cache_blast(struct iommu_table *tbl);
+
+struct cal_chipset_ops calgary_chip_ops = {
+ .handle_quirks = calgary_handle_quirks,
+ .tce_cache_blast = calgary_tce_cache_blast
+};

-static void tce_cache_blast(struct iommu_table *tbl);
+static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };

/* enable this to stress test the chip's TCE cache */
#ifdef CONFIG_IOMMU_DEBUG
@@ -243,7 +249,7 @@ static unsigned long iommu_range_alloc(s
offset = find_next_zero_string(tbl->it_map, tbl->it_hint,
tbl->it_size, npages);
if (offset == ~0UL) {
- tce_cache_blast(tbl);
+ tbl->chip_ops->tce_cache_blast(tbl);
offset = find_next_zero_string(tbl->it_map, 0,
tbl->it_size, npages);
if (offset == ~0UL) {
@@ -552,7 +558,7 @@ static inline void __iomem* calgary_reg(
return (void __iomem*)target;
}

-static void tce_cache_blast(struct iommu_table *tbl)
+static void calgary_tce_cache_blast(struct iommu_table *tbl)
{
u64 val;
u32 aer;
@@ -698,6 +704,8 @@ static int __init calgary_setup_tar(stru
tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
tce_free(tbl, 0, tbl->it_size);

+ tbl->chip_ops = &calgary_chip_ops;
+
calgary_reserve_regions(dev);

/* set TARs for each PHB */
@@ -807,10 +815,10 @@ static void __init calgary_set_split_com
readq(target); /* flush */
}

-static void __init calgary_handle_quirks(struct pci_dev* dev)
+static void __init calgary_handle_quirks(struct iommu_table *tbl,
+ struct pci_dev *dev)
{
unsigned char busnum = dev->bus->number;
- struct iommu_table *tbl = dev->sysdata;

/*
* Give split completion a longer timeout on bus 1 for aic94xx
@@ -885,6 +893,7 @@ static void __init calgary_init_one_nont
static int __init calgary_init_one(struct pci_dev *dev)
{
void __iomem *bbar;
+ struct iommu_table *tbl;
int ret;

BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
@@ -897,7 +906,8 @@ static int __init calgary_init_one(struc
pci_dev_get(dev);
dev->bus->self = dev;

- calgary_handle_quirks(dev);
+ tbl = dev->sysdata;
+ tbl->chip_ops->handle_quirks(tbl, dev);

calgary_enable_translation(dev);

diff --git a/include/asm-x86_64/calgary.h b/include/asm-x86_64/calgary.h
index 7ee9006..3aa8ad5 100644
--- a/include/asm-x86_64/calgary.h
+++ b/include/asm-x86_64/calgary.h
@@ -1,7 +1,7 @@
/*
* Derived from include/asm-powerpc/iommu.h
*
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
*
* Author: Jon Mason <[email protected]>
* Author: Muli Ben-Yehuda <[email protected]>
@@ -30,6 +30,7 @@
#include <asm/types.h>

struct iommu_table {
+ struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
unsigned long it_base; /* mapped address of tce table */
unsigned long it_hint; /* Hint for next alloc */
unsigned long *it_map; /* A simple allocation bitmap for now */
@@ -41,6 +42,11 @@ struct iommu_table {
unsigned char it_busno; /* Bus number this table belongs to */
};

+struct cal_chipset_ops {
+ void (*handle_quirks)(struct iommu_table *tbl, struct pci_dev *dev);
+ void (*tce_cache_blast)(struct iommu_table *tbl);
+};
+
#define TCE_TABLE_SIZE_UNSPECIFIED ~0
#define TCE_TABLE_SIZE_64K 0
#define TCE_TABLE_SIZE_128K 1
--
1.4.4

2007-05-22 08:11:28

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 3/15] x86-64: Calgary - introduce handle_quirks() for various chipset quirks

From: Muli Ben-Yehuda <[email protected]>

Move the aic94xx split completion timeout handling there.

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 25 +++++++++++++++++--------
1 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index b1ab0d5..9f6dd44 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -807,6 +807,20 @@ static void __init calgary_set_split_com
readq(target); /* flush */
}

+static void __init calgary_handle_quirks(struct pci_dev* dev)
+{
+ unsigned char busnum = dev->bus->number;
+ struct iommu_table *tbl = dev->sysdata;
+
+ /*
+ * Give split completion a longer timeout on bus 1 for aic94xx
+ * http://bugzilla.kernel.org/show_bug.cgi?id=7180
+ */
+ if (busnum == 1)
+ calgary_set_split_completion_timeout(tbl->bbar, busnum,
+ CCR_2SEC_TIMEOUT);
+}
+
static void __init calgary_enable_translation(struct pci_dev *dev)
{
u32 val32;
@@ -831,14 +845,6 @@ static void __init calgary_enable_transl
writel(cpu_to_be32(val32), target);
readl(target); /* flush */

- /*
- * Give split completion a longer timeout on bus 1 for aic94xx
- * http://bugzilla.kernel.org/show_bug.cgi?id=7180
- */
- if (busnum == 1)
- calgary_set_split_completion_timeout(bbar, busnum,
- CCR_2SEC_TIMEOUT);
-
init_timer(&tbl->watchdog_timer);
tbl->watchdog_timer.function = &calgary_watchdog;
tbl->watchdog_timer.data = (unsigned long)dev;
@@ -890,6 +896,9 @@ static int __init calgary_init_one(struc

pci_dev_get(dev);
dev->bus->self = dev;
+
+ calgary_handle_quirks(dev);
+
calgary_enable_translation(dev);

return 0;
--
1.4.4

2007-05-22 08:11:55

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 12/15] x86-64: Calgary - cleanup of unneeded macros

From: Guillaume Thouvenin <[email protected]>

Cleanup unneeded macros used for register space address calculation.
Now we are using the EBDA to find the space address.

Signed-off-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
arch/x86_64/kernel/pci-calgary.c | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 9efecf3..5ec9be2 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -52,11 +52,6 @@ int use_calgary __read_mostly = 0;
#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
#define PCI_DEVICE_ID_IBM_CALIOC2 0x0308

-/* we need these for register space address calculation */
-#define START_ADDRESS 0xfe000000
-#define CHASSIS_BASE 0
-#define ONE_BASED_CHASSIS_NUM 1
-
/* register offsets inside the host bridge space */
#define CALGARY_CONFIG_REG 0x0108
#define PHB_CSR_OFFSET 0x0110 /* Channel Status */
--
1.4.4

2007-05-22 08:12:20

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 11/15] x86-64: Calgary - reserve TCEs with the same address as MEM regions

From: Muli Ben-Yehuda <[email protected]>

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.

Signed-off-by: Muli Ben-Yehuda <[email protected]>
---
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 a49b19d..9efecf3 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -1538,3 +1538,70 @@ static int __init calgary_parse_options(
return 1;
}
__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);
--
1.4.4

2007-05-22 08:12:44

by Muli Ben-Yehuda

[permalink] [raw]
Subject: [PATCH 13/15] x86-64: Calgary - tabify and trim trailing whitespace

From: Muli Ben-Yehuda <[email protected]>

---
arch/x86_64/kernel/pci-calgary.c | 44 +++++++++++++++++++-------------------
1 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 5ec9be2..0bb0eb0 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -75,9 +75,9 @@ int use_calgary __read_mostly = 0;
#define PHB_DOSHOLE_OFFSET 0x08E0

/* CalIOC2 specific */
-#define PHB_SAVIOR_L2 0x0DB0
-#define PHB_PAGE_MIG_CTRL 0x0DA8
-#define PHB_PAGE_MIG_DEBUG 0x0DA0
+#define PHB_SAVIOR_L2 0x0DB0
+#define PHB_PAGE_MIG_CTRL 0x0DA8
+#define PHB_PAGE_MIG_DEBUG 0x0DA0
#define PHB_ROOT_COMPLEX_STATUS 0x0CB0

/* PHB_CONFIG_RW */
@@ -92,11 +92,11 @@ int use_calgary __read_mostly = 0;
/* CSR (Channel/DMA Status Register) */
#define CSR_AGENT_MASK 0xffe0ffff
/* CCR (Calgary Configuration Register) */
-#define CCR_2SEC_TIMEOUT 0x000000000000000EUL
+#define CCR_2SEC_TIMEOUT 0x000000000000000EUL
/* PMCR/PMDR (Page Migration Control/Debug Registers */
-#define PMR_SOFTSTOP 0x80000000
-#define PMR_SOFTSTOPFAULT 0x40000000
-#define PMR_HARDSTOP 0x20000000
+#define PMR_SOFTSTOP 0x80000000
+#define PMR_SOFTSTOPFAULT 0x40000000
+#define PMR_HARDSTOP 0x20000000

#define MAX_NUM_OF_PHBS 8 /* how many PHBs in total? */
#define MAX_NUM_CHASSIS 8 /* max number of chassis */
@@ -230,7 +230,7 @@ static inline int translate_phb(struct p
}

static void iommu_range_reserve(struct iommu_table *tbl,
- unsigned long start_addr, unsigned int npages)
+ unsigned long start_addr, unsigned int npages)
{
unsigned long index;
unsigned long end;
@@ -420,7 +420,7 @@ static int calgary_nontranslate_map_sg(s
{
int i;

- for (i = 0; i < nelems; i++ ) {
+ for (i = 0; i < nelems; i++ ) {
struct scatterlist *s = &sg[i];
BUG_ON(!s->page);
s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
@@ -840,12 +840,12 @@ static int __init calgary_setup_tar(stru
tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
tce_free(tbl, 0, tbl->it_size);

- if (is_calgary(dev->device))
- tbl->chip_ops = &calgary_chip_ops;
+ if (is_calgary(dev->device))
+ tbl->chip_ops = &calgary_chip_ops;
else if (is_calioc2(dev->device))
tbl->chip_ops = &calioc2_chip_ops;
- else
- BUG();
+ else
+ BUG();

calgary_reserve_regions(dev);

@@ -899,7 +899,7 @@ static void calgary_dump_error_regs(stru
void __iomem *bbar = tbl->bbar;
void __iomem *target;
u32 csr, plssr;
-
+
target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_CSR_OFFSET);
csr = be32_to_cpu(readl(target));

@@ -1027,13 +1027,13 @@ static void calioc2_handle_quirks(struct
void __iomem *target;
u32 val;

- /*
- * CalIOC2 designers recommend setting bit 8 in 0xnDB0 to 1
- */
- target = calgary_reg(bbar, phb_offset(busnum) | PHB_SAVIOR_L2);
- val = cpu_to_be32(readl(target));
- val |= 0x00800000;
- writel(cpu_to_be32(val), target);
+ /*
+ * CalIOC2 designers recommend setting bit 8 in 0xnDB0 to 1
+ */
+ target = calgary_reg(bbar, phb_offset(busnum) | PHB_SAVIOR_L2);
+ val = cpu_to_be32(readl(target));
+ val |= 0x00800000;
+ writel(cpu_to_be32(val), target);
}

static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
@@ -1560,7 +1560,7 @@ static void __init calgary_fixup_one_tce
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);
}
}
--
1.4.4

2007-06-04 19:07:09

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH 5/15] x86-64: Calgary - abstract how we find the iommu_table for a device

On Mon, Jun 04, 2007 at 11:33:44AM -0700, Andrew Morton wrote:
> On Tue, 22 May 2007 04:05:54 -0400
> [email protected] wrote:
>
> > From: Muli Ben-Yehuda <[email protected]>
> >
> > ... in preparation for doing it differently for CalIOC2.
> >
>
> This patch gets
>
> patching file arch/x86_64/kernel/pci-calgary.c
> Hunk #2 FAILED at 374.
> Hunk #3 FAILED at 403.
> Hunk #4 FAILED at 457.
> Hunk #5 FAILED at 473.
> Hunk #6 FAILED at 489.
> 5 out of 6 hunks FAILED -- saving rejects to file arch/x86_64/kernel/pci-calgary.c.rej
> Failed to apply x86-64-calgary-abstract-how-we-find-the-iommu_table-for-a-device
>
>
> due to git-pciseg.patch.
>
> So I'll drop git-pciseg until this patch gets to mainline and then
> git-pciseg gets fixed up for it.


Regardless of who it is, people have to stop fighting over ->sysdata.
It's unscalable, regardless of who it is.

Whoever wants to be upstream first should take the basic "x86 sysdata"
bits from jgarzik/misc-2.6.git#pciseg and push those upstream... which
I note includes Calgary work.

Then NUMA, Calgary and PCI domain stuff merely involve modifying the x86
version of struct pci_sysdata.

I would NAK any [PCI domain | NUMA | Calgary]-only approach to using
->sysdata. It clearly does NOT belong to any one subsystem, regardless
of who gets upstream first.

Drop git-pciseg? sure. Make sysdata Calgary-specific? NAK.

Jeff


2007-06-04 19:14:31

by Muli Ben-Yehuda

[permalink] [raw]
Subject: Re: [PATCH 5/15] x86-64: Calgary - abstract how we find the iommu_table for a device

On Mon, Jun 04, 2007 at 03:06:54PM -0400, Jeff Garzik wrote:

> On Mon, Jun 04, 2007 at 11:33:44AM -0700, Andrew Morton wrote:
> > On Tue, 22 May 2007 04:05:54 -0400
> > [email protected] wrote:
> >
> > > From: Muli Ben-Yehuda <[email protected]>
> > >
> > > ... in preparation for doing it differently for CalIOC2.
> > >
> >
> > This patch gets
> >
> > patching file arch/x86_64/kernel/pci-calgary.c
> > Hunk #2 FAILED at 374.
> > Hunk #3 FAILED at 403.
> > Hunk #4 FAILED at 457.
> > Hunk #5 FAILED at 473.
> > Hunk #6 FAILED at 489.
> > 5 out of 6 hunks FAILED -- saving rejects to file arch/x86_64/kernel/pci-calgary.c.rej
> > Failed to apply x86-64-calgary-abstract-how-we-find-the-iommu_table-for-a-device
> >
> >
> > due to git-pciseg.patch.
> >
> > So I'll drop git-pciseg until this patch gets to mainline and then
> > git-pciseg gets fixed up for it.
>
>
> Regardless of who it is, people have to stop fighting over
> ->sysdata. It's unscalable, regardless of who it is.
>
> Whoever wants to be upstream first should take the basic "x86
> sysdata" bits from jgarzik/misc-2.6.git#pciseg and push those
> upstream... which I note includes Calgary work.
>
> Then NUMA, Calgary and PCI domain stuff merely involve modifying the
> x86 version of struct pci_sysdata.
>
> I would NAK any [PCI domain | NUMA | Calgary]-only approach to using
> ->sysdata. It clearly does NOT belong to any one subsystem,
> regardless of who gets upstream first.

It's already being used in mainline by both NUMA and Calgary (but in
such a way that both work. Magic). Clearly the solution is what we did
for pciseg, have a struct sysdata that is extensible, but those pciseg
bits don't seem any closer to going upstream?

Cheers,
Muli

2007-06-04 19:31:59

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH 5/15] x86-64: Calgary - abstract how we find the iommu_table for a device

On Mon, Jun 04, 2007 at 10:13:46PM +0300, Muli Ben-Yehuda wrote:
> It's already being used in mainline by both NUMA and Calgary (but in
> such a way that both work. Magic). Clearly the solution is what we did
> for pciseg, have a struct sysdata that is extensible, but those pciseg
> bits don't seem any closer to going upstream?

You are missing:

* allocation code in arch/i386/pci/common.c
* use of the more-generic pci_iommu() wrapper in Calgary code
* ditto in arch/x86_64/kernel/tce.c
* pci_sysdata initialization in arch/x86_64/pci/k8-bus.c
* definition of pci_sysdata in include/asm-i386/pci.h
* bug fix in include/asm-i386/topology.h
* definition of pci_sysdata in include/asm-x86_64/pci.h
* bug fix in include/asm-x86_64/topology.h

You need to take the obviously relevant, non-PCI-domain code from
#pciseg and push it upstream.

Jeff



2007-06-04 21:06:05

by Jeff Garzik

[permalink] [raw]
Subject: [PATCH] stop x86 ->sysdata abuse; introduce pci_sysdata


This patch introduces struct pci_sysdata to x86 and x86-64, and
converts the existing two users (NUMA, Calgary) to use it.

This eliminates the conflict between NUMA and Calgary using the same
pointer for different uses, and lays the groundwork for adding x86
PCI domain support.

Signed-off-by: Jeff Garzik <[email protected]>

---

NOTE: This patch is untested, extract from the larger changes found in
jgarzik/misc-2.6.git#pciseg. Hopefully NUMA and/or Calgary users will
test and ack this, then build patches on top of it.


diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
index b33aea8..1210a89 100644
--- a/arch/i386/pci/acpi.c
+++ b/arch/i386/pci/acpi.c
@@ -8,20 +8,46 @@
struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
{
struct pci_bus *bus;
+ struct pci_sysdata *sd;
+ int pxm;

+ /* Allocate per-root-bus (not per bus) arch-specific data.
+ * TODO: leak; this memory is never freed.
+ * It's arguable whether it's worth the trouble to care.
+ */
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+ return NULL;
+ }
+
+#ifdef CONFIG_PCI_DOMAINS
+ sd->domain = domain;
+#else
if (domain != 0) {
printk(KERN_WARNING "PCI: Multiple domains not supported\n");
+ kfree(sd);
return NULL;
}
+#endif /* CONFIG_PCI_DOMAINS */
+
+ sd->node = -1;
+
+ pxm = acpi_get_pxm(device->handle);
+#ifdef CONFIG_ACPI_NUMA
+ if (pxm >= 0)
+ sd->node = pxm_to_node(pxm);
+#endif
+
+ bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+ if (!bus)
+ kfree(sd);

- bus = pcibios_scan_root(busnum);
#ifdef CONFIG_ACPI_NUMA
if (bus != NULL) {
- int pxm = acpi_get_pxm(device->handle);
if (pxm >= 0) {
- bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm);
- printk("bus %d -> pxm %d -> node %ld\n",
- busnum, pxm, (long)(bus->sysdata));
+ printk("bus %d -> pxm %d -> node %d\n",
+ busnum, pxm, sd->node);
}
}
#endif
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index 3f78d4d..0519519 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -29,12 +29,14 @@ struct pci_raw_ops *raw_pci_ops;

static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
- return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
+ return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
+ devfn, where, size, value);
}

static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
- return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
+ return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
+ devfn, where, size, value);
}

struct pci_ops pci_root_ops = {
@@ -293,6 +295,7 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
struct pci_bus *bus = NULL;
+ struct pci_sysdata *sd;

dmi_check_system(pciprobe_dmi_table);

@@ -303,9 +306,19 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
}
}

+ /* Allocate per-root-bus (not per bus) arch-specific data.
+ * TODO: leak; this memory is never freed.
+ * It's arguable whether it's worth the trouble to care.
+ */
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+ return NULL;
+ }
+
printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);

- return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
+ return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
}

extern u8 pci_cache_line_size;
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 5ce9443..6a27e08 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -716,6 +716,10 @@ config PCI_MMCONFIG
bool "Support mmconfig PCI config space access"
depends on PCI && ACPI

+config PCI_DOMAINS
+ bool "PCI domain support"
+ depends on PCI
+
source "drivers/pci/pcie/Kconfig"

source "drivers/pci/Kconfig"
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 5bd20b5..55725ec 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -359,7 +359,7 @@ void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
int nelems, int direction)
{
unsigned long flags;
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = pci_iommu(to_pci_dev(dev)->bus);

if (!translate_phb(to_pci_dev(dev)))
return;
@@ -388,7 +388,7 @@ static int calgary_nontranslate_map_sg(struct device* dev,
int calgary_map_sg(struct device *dev, struct scatterlist *sg,
int nelems, int direction)
{
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = pci_iommu(to_pci_dev(dev)->bus);
unsigned long flags;
unsigned long vaddr;
unsigned int npages;
@@ -442,7 +442,7 @@ dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
dma_addr_t dma_handle = bad_dma_address;
unsigned long uaddr;
unsigned int npages;
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = pci_iommu(to_pci_dev(dev)->bus);

uaddr = (unsigned long)vaddr;
npages = num_dma_pages(uaddr, size);
@@ -458,7 +458,7 @@ dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
size_t size, int direction)
{
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = pci_iommu(to_pci_dev(dev)->bus);
unsigned int npages;

if (!translate_phb(to_pci_dev(dev)))
@@ -476,7 +476,7 @@ void* calgary_alloc_coherent(struct device *dev, size_t size,
unsigned int npages, order;
struct iommu_table *tbl;

- tbl = to_pci_dev(dev)->bus->self->sysdata;
+ tbl = pci_iommu(to_pci_dev(dev)->bus);

size = PAGE_ALIGN(size); /* size rounded up to full pages */
npages = size >> PAGE_SHIFT;
@@ -598,7 +598,7 @@ static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
limit++;

numpages = ((limit - start) >> PAGE_SHIFT);
- iommu_range_reserve(dev->sysdata, start, numpages);
+ iommu_range_reserve(pci_iommu(dev->bus), start, numpages);
}

static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
@@ -606,7 +606,7 @@ static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
void __iomem *target;
u64 low, high, sizelow;
u64 start, limit;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
unsigned char busnum = dev->bus->number;
void __iomem *bbar = tbl->bbar;

@@ -630,7 +630,7 @@ static void __init calgary_reserve_peripheral_mem_2(struct pci_dev *dev)
u32 val32;
u64 low, high, sizelow, sizehigh;
u64 start, limit;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
unsigned char busnum = dev->bus->number;
void __iomem *bbar = tbl->bbar;

@@ -666,7 +666,7 @@ static void __init calgary_reserve_regions(struct pci_dev *dev)
{
unsigned int npages;
u64 start;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);

/* reserve EMERGENCY_PAGES from bad_dma_address and up */
iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES);
@@ -694,7 +694,7 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
if (ret)
return ret;

- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
tce_free(tbl, 0, tbl->it_size);

@@ -707,7 +707,7 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
/* zero out all TAR bits under sw control */
val64 &= ~TAR_SW_BITS;

- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
table_phys = (u64)__pa(tbl->it_base);
val64 |= table_phys;

@@ -724,7 +724,7 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
static void __init calgary_free_bus(struct pci_dev *dev)
{
u64 val64;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
void __iomem *target;
unsigned int bitmapsz;

@@ -739,7 +739,8 @@ static void __init calgary_free_bus(struct pci_dev *dev)
tbl->it_map = NULL;

kfree(tbl);
- dev->sysdata = NULL;
+
+ set_pci_iommu(dev->bus, NULL);

/* Can't free bootmem allocated memory after system is up :-( */
bus_info[dev->bus->number].tce_space = NULL;
@@ -748,7 +749,7 @@ static void __init calgary_free_bus(struct pci_dev *dev)
static void calgary_watchdog(unsigned long data)
{
struct pci_dev *dev = (struct pci_dev *)data;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
void __iomem *bbar = tbl->bbar;
u32 val32;
void __iomem *target;
@@ -816,7 +817,7 @@ static void __init calgary_enable_translation(struct pci_dev *dev)
struct iommu_table *tbl;

busnum = dev->bus->number;
- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
bbar = tbl->bbar;

/* enable TCE in PHB Config Register */
@@ -853,7 +854,7 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
struct iommu_table *tbl;

busnum = dev->bus->number;
- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
bbar = tbl->bbar;

/* disable TCE in PHB Config Register */
@@ -871,8 +872,7 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
{
pci_dev_get(dev);
- dev->sysdata = NULL;
- dev->bus->self = dev;
+ set_pci_iommu(dev->bus, NULL);
}

static int __init calgary_init_one(struct pci_dev *dev)
diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c
index f61fb8e..3aeae2f 100644
--- a/arch/x86_64/kernel/tce.c
+++ b/arch/x86_64/kernel/tce.c
@@ -136,9 +136,9 @@ int build_tce_table(struct pci_dev *dev, void __iomem *bbar)
struct iommu_table *tbl;
int ret;

- if (dev->sysdata) {
- printk(KERN_ERR "Calgary: dev %p has sysdata %p\n",
- dev, dev->sysdata);
+ if (pci_iommu(dev->bus)) {
+ printk(KERN_ERR "Calgary: dev %p has sysdata->iommu %p\n",
+ dev, pci_iommu(dev->bus));
BUG();
}

@@ -155,11 +155,7 @@ int build_tce_table(struct pci_dev *dev, void __iomem *bbar)

tbl->bbar = bbar;

- /*
- * NUMA is already using the bus's sysdata pointer, so we use
- * the bus's pci_dev's sysdata instead.
- */
- dev->sysdata = tbl;
+ set_pci_iommu(dev->bus, tbl);

return 0;

diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
index 3acf60d..9cc813e 100644
--- a/arch/x86_64/pci/k8-bus.c
+++ b/arch/x86_64/pci/k8-bus.c
@@ -59,6 +59,8 @@ fill_mp_bus_to_cpumask(void)
j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
j++) {
struct pci_bus *bus;
+ struct pci_sysdata *sd;
+
long node = NODE_ID(nid);
/* Algorithm a bit dumb, but
it shouldn't matter here */
@@ -67,7 +69,9 @@ fill_mp_bus_to_cpumask(void)
continue;
if (!node_online(node))
node = 0;
- bus->sysdata = (void *)node;
+
+ sd = bus->sysdata;
+ sd->node = node;
}
}
}
diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h
index 64b6d0b..2c8b5e9 100644
--- a/include/asm-i386/pci.h
+++ b/include/asm-i386/pci.h
@@ -3,6 +3,25 @@


#ifdef __KERNEL__
+
+struct pci_sysdata {
+ int domain; /* PCI domain */
+ int node; /* NUMA node */
+};
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ return sd->domain;
+}
+
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+ return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
#include <linux/mm.h> /* for struct page */

/* Can be used to override the logic in pci_scan_bus for skipping
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index 7fc512d..19b2daf 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -67,7 +67,7 @@ static inline int node_to_first_cpu(int node)
return first_cpu(mask);
}

-#define pcibus_to_node(bus) ((long) (bus)->sysdata)
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
#define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus))

/* sched_domains SD_NODE_INIT for NUMAQ machines */
diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
index 49c5e92..550207f 100644
--- a/include/asm-x86_64/pci.h
+++ b/include/asm-x86_64/pci.h
@@ -5,6 +5,39 @@

#ifdef __KERNEL__

+struct pci_sysdata {
+ int domain; /* PCI domain */
+ int node; /* NUMA node */
+ void* iommu; /* IOMMU private data */
+};
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ return sd->domain;
+}
+
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+ return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
+#ifdef CONFIG_CALGARY_IOMMU
+static inline void* pci_iommu(struct pci_bus *bus)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ return sd->iommu;
+}
+
+static inline void set_pci_iommu(struct pci_bus *bus, void *val)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ sd->iommu = val;
+}
+#endif /* CONFIG_CALGARY_IOMMU */
+
#include <linux/mm.h> /* for struct page */

/* Can be used to override the logic in pci_scan_bus for skipping
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 4fd6fb2..36e52fb 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -22,7 +22,7 @@ extern int __node_distance(int, int);
#define parent_node(node) (node)
#define node_to_first_cpu(node) (first_cpu(node_to_cpumask[node]))
#define node_to_cpumask(node) (node_to_cpumask[node])
-#define pcibus_to_node(bus) ((long)(bus->sysdata))
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
#define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus));

#define numa_node_id() read_pda(nodenumber)

2007-06-04 23:31:23

by Keshavamurthy, Anil S

[permalink] [raw]
Subject: Re: [PATCH] stop x86 ->sysdata abuse; introduce pci_sysdata

On Mon, Jun 04, 2007 at 05:05:51PM -0400, Jeff Garzik wrote:
>
> This patch introduces struct pci_sysdata to x86 and x86-64, and
> converts the existing two users (NUMA, Calgary) to use it.
>
> This eliminates the conflict between NUMA and Calgary using the same
> pointer for different uses, and lays the groundwork for adding x86
> PCI domain support.
>
> Signed-off-by: Jeff Garzik <[email protected]>
>
> ---
>
> NOTE: This patch is untested, extract from the larger changes found in
> jgarzik/misc-2.6.git#pciseg. Hopefully NUMA and/or Calgary users will
> test and ack this, then build patches on top of it.

Looks like the recently announced Intel-IOMMU too (just like Calgary)
depends on sysdata. I will modify my Intel-IOMMU accordingly and
will let you know how it goes with your patch.

thanks,
Anil

2007-06-05 10:29:18

by Muli Ben-Yehuda

[permalink] [raw]
Subject: Re: [PATCH] stop x86 ->sysdata abuse; introduce pci_sysdata

On Mon, Jun 04, 2007 at 05:05:51PM -0400, Jeff Garzik wrote:
>
> This patch introduces struct pci_sysdata to x86 and x86-64, and
> converts the existing two users (NUMA, Calgary) to use it.
>
> This eliminates the conflict between NUMA and Calgary using the same
> pointer for different uses, and lays the groundwork for adding x86
> PCI domain support.

Thanks for the patch. I am testing with Calgary and will push upstream
through the next batch of Calgary updates when it will be ready. At
the moment it doesn't boot on one of my test machines, I'm looking
into it.

Also, FWIW, we don't use the same pointer for different uses (that
wouldn't have worked, obviously) but I've never been 100% comfortable
with the hack we use and this is obviously the right thing to do.

Cheers,
Muli

2007-06-06 21:04:05

by Muli Ben-Yehuda

[permalink] [raw]
Subject: Re: [PATCH] stop x86 ->sysdata abuse; introduce pci_sysdata

On Tue, Jun 05, 2007 at 01:29:05PM +0300, Muli Ben-Yehuda wrote:
> On Mon, Jun 04, 2007 at 05:05:51PM -0400, Jeff Garzik wrote:
> >
> > This patch introduces struct pci_sysdata to x86 and x86-64, and
> > converts the existing two users (NUMA, Calgary) to use it.
> >
> > This eliminates the conflict between NUMA and Calgary using the same
> > pointer for different uses, and lays the groundwork for adding x86
> > PCI domain support.
>
> Thanks for the patch. I am testing with Calgary and will push upstream
> through the next batch of Calgary updates when it will be ready. At
> the moment it doesn't boot on one of my test machines, I'm looking
> into it.

Ok, patch fixed, works for me with Calgary. Andi, it looks like you
added the acpi.c NUMA bits originally, perhaps you could test and/or
ack them?

This patch introduces struct pci_sysdata to x86 and x86-64, and
converts the existing two users (NUMA, Calgary) to use it.

This lays the groundwork for having other users of sysdata, such as
the PCI domains work.

Signed-off-by: Jeff Garzik <[email protected]>
Signed-off-by: Muli Ben-Yehuda <[email protected]>

---

NOTE: Calgary bits are tested, NUMA bits need to be tested.

NOTE: I removed the PCI domains bits in Jeff's original patch so that
this patch only deals with ->sysdata users which are in mainline at
the moment. The PCI domains bits can be trivially added.

diff -r 05804111dbee arch/i386/pci/acpi.c
--- a/arch/i386/pci/acpi.c Tue Jun 05 11:34:51 2007 +0300
+++ b/arch/i386/pci/acpi.c Wed Jun 06 22:49:08 2007 +0300
@@ -8,20 +8,42 @@ struct pci_bus * __devinit pci_acpi_scan
struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
{
struct pci_bus *bus;
+ struct pci_sysdata *sd;
+ int pxm;
+
+ /* Allocate per-root-bus (not per bus) arch-specific data.
+ * TODO: leak; this memory is never freed.
+ * It's arguable whether it's worth the trouble to care.
+ */
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+ return NULL;
+ }

if (domain != 0) {
printk(KERN_WARNING "PCI: Multiple domains not supported\n");
+ kfree(sd);
return NULL;
}

- bus = pcibios_scan_root(busnum);
+ sd->node = -1;
+
+ pxm = acpi_get_pxm(device->handle);
+#ifdef CONFIG_ACPI_NUMA
+ if (pxm >= 0)
+ sd->node = pxm_to_node(pxm);
+#endif
+
+ bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+ if (!bus)
+ kfree(sd);
+
#ifdef CONFIG_ACPI_NUMA
if (bus != NULL) {
- int pxm = acpi_get_pxm(device->handle);
if (pxm >= 0) {
- bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm);
- printk("bus %d -> pxm %d -> node %ld\n",
- busnum, pxm, (long)(bus->sysdata));
+ printk("bus %d -> pxm %d -> node %d\n",
+ busnum, pxm, sd->node);
}
}
#endif
diff -r 05804111dbee arch/i386/pci/common.c
--- a/arch/i386/pci/common.c Tue Jun 05 11:34:51 2007 +0300
+++ b/arch/i386/pci/common.c Wed Jun 06 22:36:53 2007 +0300
@@ -29,12 +29,14 @@ struct pci_raw_ops *raw_pci_ops;

static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
- return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
+ return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
+ devfn, where, size, value);
}

static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
- return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
+ return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
+ devfn, where, size, value);
}

struct pci_ops pci_root_ops = {
@@ -293,6 +295,7 @@ struct pci_bus * __devinit pcibios_scan_
struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
struct pci_bus *bus = NULL;
+ struct pci_sysdata *sd;

dmi_check_system(pciprobe_dmi_table);

@@ -303,9 +306,19 @@ struct pci_bus * __devinit pcibios_scan_
}
}

+ /* Allocate per-root-bus (not per bus) arch-specific data.
+ * TODO: leak; this memory is never freed.
+ * It's arguable whether it's worth the trouble to care.
+ */
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+ return NULL;
+ }
+
printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);

- return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
+ return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
}

extern u8 pci_cache_line_size;
diff -r 05804111dbee arch/x86_64/kernel/pci-calgary.c
--- a/arch/x86_64/kernel/pci-calgary.c Tue Jun 05 11:34:51 2007 +0300
+++ b/arch/x86_64/kernel/pci-calgary.c Wed Jun 06 23:27:53 2007 +0300
@@ -375,7 +375,7 @@ static inline struct iommu_table *find_i
else
pbus = pdev->bus;

- tbl = pbus->self->sysdata;
+ tbl = pci_iommu(pbus);

BUG_ON(pdev->bus->parent &&
(tbl->it_busno != pdev->bus->parent->number));
@@ -718,7 +718,7 @@ static void __init calgary_reserve_mem_r
limit++;

numpages = ((limit - start) >> PAGE_SHIFT);
- iommu_range_reserve(dev->sysdata, start, numpages);
+ iommu_range_reserve(pci_iommu(dev->bus), start, numpages);
}

static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
@@ -726,7 +726,7 @@ static void __init calgary_reserve_perip
void __iomem *target;
u64 low, high, sizelow;
u64 start, limit;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
unsigned char busnum = dev->bus->number;
void __iomem *bbar = tbl->bbar;

@@ -750,7 +750,7 @@ static void __init calgary_reserve_perip
u32 val32;
u64 low, high, sizelow, sizehigh;
u64 start, limit;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
unsigned char busnum = dev->bus->number;
void __iomem *bbar = tbl->bbar;

@@ -786,7 +786,7 @@ static void __init calgary_reserve_regio
{
unsigned int npages;
u64 start;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
void __iomem *target;
u32 val1, val2;
unsigned char busnum = dev->bus->number;
@@ -831,7 +831,7 @@ static int __init calgary_setup_tar(stru
if (ret)
return ret;

- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
tce_free(tbl, 0, tbl->it_size);

@@ -868,7 +868,7 @@ static void __init calgary_free_bus(stru
static void __init calgary_free_bus(struct pci_dev *dev)
{
u64 val64;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
void __iomem *target;
unsigned int bitmapsz;

@@ -883,7 +883,8 @@ static void __init calgary_free_bus(stru
tbl->it_map = NULL;

kfree(tbl);
- dev->sysdata = NULL;
+
+ set_pci_iommu(dev->bus, NULL);

/* Can't free bootmem allocated memory after system is up :-( */
bus_info[dev->bus->number].tce_space = NULL;
@@ -956,7 +957,7 @@ static void calgary_watchdog(unsigned lo
static void calgary_watchdog(unsigned long data)
{
struct pci_dev *dev = (struct pci_dev *)data;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
void __iomem *bbar = tbl->bbar;
u32 val32;
void __iomem *target;
@@ -1056,7 +1057,7 @@ static void __init calgary_enable_transl
struct iommu_table *tbl;

busnum = dev->bus->number;
- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
bbar = tbl->bbar;

/* dump the configuration register */
@@ -1093,7 +1094,7 @@ static void __init calgary_disable_trans
struct iommu_table *tbl;

busnum = dev->bus->number;
- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
bbar = tbl->bbar;

/* disable TCE in PHB Config Register */
@@ -1111,7 +1112,7 @@ static void __init calgary_init_one_nont
static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
{
pci_dev_get(dev);
- dev->sysdata = NULL;
+ set_pci_iommu(dev->bus, NULL);

/* is the device behind a bridge? */
if (dev->bus->parent)
@@ -1144,7 +1145,7 @@ static int __init calgary_init_one(struc
else
dev->bus->self = dev;

- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
tbl->chip_ops->handle_quirks(tbl, dev);

calgary_enable_translation(dev);
@@ -1541,7 +1542,7 @@ static void __init calgary_fixup_one_tce
unsigned int npages;
int i;

- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);

for (i = 0; i < 4; i++) {
struct resource *r = &dev->resource[PCI_BRIDGE_RESOURCES + i];
diff -r 05804111dbee arch/x86_64/kernel/tce.c
--- a/arch/x86_64/kernel/tce.c Tue Jun 05 11:34:51 2007 +0300
+++ b/arch/x86_64/kernel/tce.c Wed Jun 06 22:36:53 2007 +0300
@@ -136,9 +136,9 @@ int build_tce_table(struct pci_dev *dev,
struct iommu_table *tbl;
int ret;

- if (dev->sysdata) {
- printk(KERN_ERR "Calgary: dev %p has sysdata %p\n",
- dev, dev->sysdata);
+ if (pci_iommu(dev->bus)) {
+ printk(KERN_ERR "Calgary: dev %p has sysdata->iommu %p\n",
+ dev, pci_iommu(dev->bus));
BUG();
}

@@ -155,11 +155,7 @@ int build_tce_table(struct pci_dev *dev,

tbl->bbar = bbar;

- /*
- * NUMA is already using the bus's sysdata pointer, so we use
- * the bus's pci_dev's sysdata instead.
- */
- dev->sysdata = tbl;
+ set_pci_iommu(dev->bus, tbl);

return 0;

diff -r 05804111dbee arch/x86_64/pci/k8-bus.c
--- a/arch/x86_64/pci/k8-bus.c Tue Jun 05 11:34:51 2007 +0300
+++ b/arch/x86_64/pci/k8-bus.c Wed Jun 06 22:36:53 2007 +0300
@@ -59,6 +59,8 @@ fill_mp_bus_to_cpumask(void)
j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
j++) {
struct pci_bus *bus;
+ struct pci_sysdata *sd;
+
long node = NODE_ID(nid);
/* Algorithm a bit dumb, but
it shouldn't matter here */
@@ -67,7 +69,9 @@ fill_mp_bus_to_cpumask(void)
continue;
if (!node_online(node))
node = 0;
- bus->sysdata = (void *)node;
+
+ sd = bus->sysdata;
+ sd->node = node;
}
}
}
diff -r 05804111dbee include/asm-i386/pci.h
--- a/include/asm-i386/pci.h Tue Jun 05 11:34:51 2007 +0300
+++ b/include/asm-i386/pci.h Wed Jun 06 22:48:04 2007 +0300
@@ -3,6 +3,11 @@


#ifdef __KERNEL__
+
+struct pci_sysdata {
+ int node; /* NUMA node */
+};
+
#include <linux/mm.h> /* for struct page */

/* Can be used to override the logic in pci_scan_bus for skipping
diff -r 05804111dbee include/asm-i386/topology.h
--- a/include/asm-i386/topology.h Tue Jun 05 11:34:51 2007 +0300
+++ b/include/asm-i386/topology.h Wed Jun 06 22:36:53 2007 +0300
@@ -67,7 +67,7 @@ static inline int node_to_first_cpu(int
return first_cpu(mask);
}

-#define pcibus_to_node(bus) ((long) (bus)->sysdata)
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
#define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus))

/* sched_domains SD_NODE_INIT for NUMAQ machines */
diff -r 05804111dbee include/asm-x86_64/pci.h
--- a/include/asm-x86_64/pci.h Tue Jun 05 11:34:51 2007 +0300
+++ b/include/asm-x86_64/pci.h Wed Jun 06 22:48:15 2007 +0300
@@ -4,6 +4,25 @@
#include <asm/io.h>

#ifdef __KERNEL__
+
+struct pci_sysdata {
+ int node; /* NUMA node */
+ void* iommu; /* IOMMU private data */
+};
+
+#ifdef CONFIG_CALGARY_IOMMU
+static inline void* pci_iommu(struct pci_bus *bus)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ return sd->iommu;
+}
+
+static inline void set_pci_iommu(struct pci_bus *bus, void *val)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ sd->iommu = val;
+}
+#endif /* CONFIG_CALGARY_IOMMU */

#include <linux/mm.h> /* for struct page */

diff -r 05804111dbee include/asm-x86_64/topology.h
--- a/include/asm-x86_64/topology.h Tue Jun 05 11:34:51 2007 +0300
+++ b/include/asm-x86_64/topology.h Wed Jun 06 22:36:53 2007 +0300
@@ -22,7 +22,7 @@ extern int __node_distance(int, int);
#define parent_node(node) (node)
#define node_to_first_cpu(node) (first_cpu(node_to_cpumask[node]))
#define node_to_cpumask(node) (node_to_cpumask[node])
-#define pcibus_to_node(bus) ((long)(bus->sysdata))
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
#define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus));

#define numa_node_id() read_pda(nodenumber)


2007-06-06 21:22:04

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH] stop x86 ->sysdata abuse; introduce pci_sysdata

> Ok, patch fixed, works for me with Calgary. Andi, it looks like you
> added the acpi.c NUMA bits originally, perhaps you could test and/or
> ack them?

Just so there is no misunderstanding, I added the allocation bits.

No idea who added the direct usage of ->sysdata for NUMA info.


> diff -r 05804111dbee arch/i386/pci/common.c
> --- a/arch/i386/pci/common.c Tue Jun 05 11:34:51 2007 +0300
> +++ b/arch/i386/pci/common.c Wed Jun 06 22:36:53 2007 +0300
> @@ -29,12 +29,14 @@ struct pci_raw_ops *raw_pci_ops;
>
> static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
> {
> - return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
> + return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
> + devfn, where, size, value);
> }
>
> static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
> {
> - return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
> + return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
> + devfn, where, size, value);
> }
>
> struct pci_ops pci_root_ops = {

Patch leakage? I thought I had removed this portion, as being specific
to PCI domains.

No objection, obviously, and it's obviously safe given that
CONFIG_PCI_DOMAINS is not defined on x86/x86-64.

Nonetheless, it appears "off-topic" for NUMA/Calgary purposes.

ACK everything, but IMO the pci_domain_nr() bits should be in a separate
patch.

Jeff





2007-06-06 21:26:25

by Muli Ben-Yehuda

[permalink] [raw]
Subject: Re: [PATCH] stop x86 ->sysdata abuse; introduce pci_sysdata

On Wed, Jun 06, 2007 at 05:21:51PM -0400, Jeff Garzik wrote:
> > Ok, patch fixed, works for me with Calgary. Andi, it looks like you
> > added the acpi.c NUMA bits originally, perhaps you could test and/or
> > ack them?
>
> Just so there is no misunderstanding, I added the allocation bits.
>
> No idea who added the direct usage of ->sysdata for NUMA info.

Andi Kleen did according to the git log. I'm trying to get access to a
NUMA system, but in the meantime perhaps Andi can just eyeball it and
ack.

> > diff -r 05804111dbee arch/i386/pci/common.c
> > --- a/arch/i386/pci/common.c Tue Jun 05 11:34:51 2007 +0300
> > +++ b/arch/i386/pci/common.c Wed Jun 06 22:36:53 2007 +0300
> > @@ -29,12 +29,14 @@ struct pci_raw_ops *raw_pci_ops;
> >
> > static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
> > {
> > - return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
> > + return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
> > + devfn, where, size, value);
> > }
> >
> > static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
> > {
> > - return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
> > + return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
> > + devfn, where, size, value);
> > }
> >
> > struct pci_ops pci_root_ops = {
>
> Patch leakage? I thought I had removed this portion, as being
> specific to PCI domains.

Nope, it was there in your original patch and I kept it since it's
obviously harmless (without CONFIG_PCI_DOMAINS pci_domain_nr() is
defined to 0).

> No objection, obviously, and it's obviously safe given that
> CONFIG_PCI_DOMAINS is not defined on x86/x86-64.
>
> Nonetheless, it appears "off-topic" for NUMA/Calgary purposes.
>
> ACK everything, but IMO the pci_domain_nr() bits should be in a
> separate patch.

Fair enough, I'll drop it out of this one.

Cheers,
Muli