* [PATCH 24/32] powerpc: Cell "Spider" MMIO workarounds
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
This is totally untested, I just put it together quickly, but gives an
example of how the hooks can be used which is why I introduced it in
this serie. Hopefully, I'll test & fix it up properly this week.
This patch implements a workaround for a Spider PCI host bridge bug
where it doesn't enforce some of the PCI ordering rules unless some
manual manipulation of a special register is done. In order to be
fully compliant with the PCI spec, I do this on every MMIO read
operation.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/Kconfig | 1
arch/powerpc/platforms/cell/Makefile | 3
arch/powerpc/platforms/cell/io-workarounds.c | 346 +++++++++++++++++++++++++++
3 files changed, 349 insertions(+), 1 deletion(-)
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig 2006-11-08 15:18:10.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig 2006-11-09 17:29:40.000000000 +1100
@@ -468,6 +468,7 @@ config PPC_CELL_NATIVE
select PPC_CELL
select PPC_DCR_MMIO
select PPC_OF_PLATFORM_PCI
+ select PPC_INDIRECT_IO
select MPIC
default n
Index: linux-cell/arch/powerpc/platforms/cell/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/Makefile 2006-11-08 15:18:10.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/Makefile 2006-11-08 15:21:34.000000000 +1100
@@ -1,5 +1,6 @@
obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \
- cbe_regs.o spider-pic.o pervasive.o
+ cbe_regs.o spider-pic.o \
+ pervasive.o io-workarounds.o
obj-$(CONFIG_CBE_RAS) += ras.o
ifeq ($(CONFIG_SMP),y)
Index: linux-cell/arch/powerpc/platforms/cell/io-workarounds.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/platforms/cell/io-workarounds.c 2006-11-09 17:30:11.000000000 +1100
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * IBM, Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+
+#define SPIDER_PCI_REG_BASE 0xd000
+#define SPIDER_PCI_VCI_CNTL_STAT 0x0110
+#define SPIDER_PCI_DUMMY_READ 0x0810
+#define SPIDER_PCI_DUMMY_READ_BASE 0x0814
+
+/* Undefine that to re-enable bogus prefetch
+ *
+ * Without that workaround, the chip will do bogus prefetch past
+ * page boundary from system memory. This setting will disable that,
+ * though the documentation is unclear as to the consequences of doing
+ * so, either purely performances, or possible misbehaviour... It's not
+ * clear wether the chip can handle unaligned accesses at all without
+ * prefetching enabled.
+ *
+ * For now, things appear to be behaving properly with that prefetching
+ * disabled and IDE, possibly because IDE isn't doing any unaligned
+ * access.
+ */
+#define SPIDER_DISABLE_PREFETCH
+
+#define MAX_SPIDERS 2
+
+static struct spider_pci_bus {
+ void __iomem *regs;
+ unsigned long mmio_start;
+ unsigned long mmio_end;
+ unsigned long pio_vstart;
+ unsigned long pio_vend;
+} spider_pci_busses[MAX_SPIDERS];
+static int spider_pci_count;
+
+static struct spider_pci_bus *spider_pci_find(unsigned long vaddr,
+ unsigned long paddr)
+{
+ int i;
+
+ for (i = 0; i < spider_pci_count; i++) {
+ struct spider_pci_bus *bus = &spider_pci_busses[i];
+ if (paddr && paddr >= bus->mmio_start && paddr < bus->mmio_end)
+ return bus;
+ if (vaddr && vaddr >= bus->pio_vstart && vaddr < bus->pio_vend)
+ return bus;
+ }
+ return NULL;
+}
+
+static void spider_io_flush(const volatile void __iomem *addr)
+{
+ struct spider_pci_bus *bus;
+ int token;
+
+ /* Get platform token (set by ioremap) from address */
+ token = PCI_GET_ADDR_TOKEN(addr);
+
+ /* Fast path if we have a non-0 token, it indicates which bus we
+ * are on.
+ *
+ * If the token is 0, that means either the the ioremap was done
+ * before we initialized this layer, or it's a PIO operation. We
+ * fallback to a low path in this case. Hopefully, internal devices
+ * which are ioremap'ed early should use in_XX/out_XX functions
+ * instead of the PCI ones and thus not suffer from the slowdown.
+ *
+ * Also note that currently, the workaround will not work for areas
+ * that are not mapped with PTEs (bolted in the hash table). This
+ * is the case for ioremaps done very early at boot (before
+ * mem_init_done) and includes the mapping of the ISA IO space.
+ *
+ * Fortunately, none of the affected devices is expected to do DMA
+ * and thus there should be no problem in practice.
+ *
+ * In order to improve performances, we only do the PTE search for
+ * addresses falling in the PHB IO space area. That means it will
+ * not work for hotplug'ed PHBs but those don't exist with Spider.
+ */
+ if (token && token <= spider_pci_count)
+ bus = &spider_pci_busses[token - 1];
+ else {
+ unsigned long vaddr, paddr;
+ pte_t *ptep;
+
+ /* Fixup physical address */
+ vaddr = (unsigned long)PCI_FIX_ADDR(addr);
+
+ /* Check if it's in allowed range for PIO */
+ if (vaddr < PHBS_IO_BASE || vaddr >= IMALLOC_BASE)
+ return;
+
+ /* Try to find a PTE. If not, clear the paddr, we'll do
+ * a vaddr only lookup (PIO only)
+ */
+ ptep = find_linux_pte(init_mm.pgd, vaddr);
+ if (ptep == NULL)
+ paddr = 0;
+ else
+ paddr = pte_pfn(*ptep) << PAGE_SHIFT;
+
+ bus = spider_pci_find(vaddr, paddr);
+ if (bus == NULL)
+ return;
+ }
+
+ /* Now do the workaround
+ */
+ (void)in_be32(bus->regs + SPIDER_PCI_DUMMY_READ);
+}
+
+static u8 spider_readb(const volatile void __iomem *addr)
+{
+ u8 val = __do_readb(addr);
+ spider_io_flush(addr);
+ return val;
+}
+
+static u16 spider_readw(const volatile void __iomem *addr)
+{
+ u16 val = __do_readw(addr);
+ spider_io_flush(addr);
+ return val;
+}
+
+static u32 spider_readl(const volatile void __iomem *addr)
+{
+ u32 val = __do_readl(addr);
+ spider_io_flush(addr);
+ return val;
+}
+
+static u64 spider_readq(const volatile void __iomem *addr)
+{
+ u64 val = __do_readq(addr);
+ spider_io_flush(addr);
+ return val;
+}
+
+static u16 spider_readw_be(const volatile void __iomem *addr)
+{
+ u16 val = __do_readw_be(addr);
+ spider_io_flush(addr);
+ return val;
+}
+
+static u32 spider_readl_be(const volatile void __iomem *addr)
+{
+ u32 val = __do_readl_be(addr);
+ spider_io_flush(addr);
+ return val;
+}
+
+static u64 spider_readq_be(const volatile void __iomem *addr)
+{
+ u64 val = __do_readq_be(addr);
+ spider_io_flush(addr);
+ return val;
+}
+
+static void spider_readsb(const volatile void __iomem *addr, void *buf,
+ unsigned long count)
+{
+ __do_readsb(addr, buf, count);
+ spider_io_flush(addr);
+}
+
+static void spider_readsw(const volatile void __iomem *addr, void *buf,
+ unsigned long count)
+{
+ __do_readsw(addr, buf, count);
+ spider_io_flush(addr);
+}
+
+static void spider_readsl(const volatile void __iomem *addr, void *buf,
+ unsigned long count)
+{
+ __do_readsl(addr, buf, count);
+ spider_io_flush(addr);
+}
+
+static void spider_memcpy_fromio(void *dest, const volatile void __iomem *src,
+ unsigned long n)
+{
+ __do_memcpy_fromio(dest, src, n);
+ spider_io_flush(src);
+}
+
+
+static void __iomem * spider_ioremap(unsigned long addr, unsigned long size,
+ unsigned long flags)
+{
+ struct spider_pci_bus *bus;
+ void __iomem *res = __ioremap(addr, size, flags);
+ int busno;
+
+ pr_debug("spider_ioremap(0x%lx, 0x%lx, 0x%lx) -> 0x%p\n",
+ addr, size, flags, res);
+
+ bus = spider_pci_find(0, addr);
+ if (bus != NULL) {
+ busno = bus - spider_pci_busses;
+ pr_debug(" found bus %d, setting token\n", busno);
+ PCI_SET_ADDR_TOKEN(res, busno + 1);
+ }
+ pr_debug(" result=0x%p\n", res);
+
+ return res;
+}
+
+static void __init spider_pci_setup_chip(struct spider_pci_bus *bus)
+{
+#ifdef SPIDER_DISABLE_PREFETCH
+ u32 val = in_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT);
+ pr_debug(" PVCI_Control_Status was 0x%08x\n", val);
+ out_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
+#endif
+
+ /* Configure the dummy address for the workaround */
+ out_be32(bus->regs + SPIDER_PCI_DUMMY_READ_BASE, 0x80000000);
+}
+
+static void __init spider_pci_add_one(struct pci_controller *phb)
+{
+ struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count];
+ struct device_node *np = phb->arch_data;
+ struct resource rsrc;
+ void __iomem *regs;
+
+ if (spider_pci_count >= MAX_SPIDERS) {
+ printk(KERN_ERR "Too many spider bridges, workarounds"
+ " disabled for %s\n", np->full_name);
+ return;
+ }
+
+ /* Get the registers for the beast */
+ if (of_address_to_resource(np, 0, &rsrc)) {
+ printk(KERN_ERR "Failed to get registers for spider %s"
+ " workarounds disabled\n", np->full_name);
+ return;
+ }
+
+ /* Mask out some useless bits in there to get to the base of the
+ * spider chip
+ */
+ rsrc.start &= ~0xfffffffful;
+
+ /* Map them */
+ regs = ioremap(rsrc.start + SPIDER_PCI_REG_BASE, 0x1000);
+ if (regs == NULL) {
+ printk(KERN_ERR "Failed to map registers for spider %s"
+ " workarounds disabled\n", np->full_name);
+ return;
+ }
+
+ spider_pci_count++;
+
+ /* We assume spiders only have one MMIO resource */
+ bus->mmio_start = phb->mem_resources[0].start;
+ bus->mmio_end = phb->mem_resources[0].end + 1;
+
+ bus->pio_vstart = (unsigned long)phb->io_base_virt;
+ bus->pio_vend = bus->pio_vstart + phb->pci_io_size;
+
+ bus->regs = regs;
+
+ printk(KERN_INFO "PCI: Spider MMIO workaround for %s\n",np->full_name);
+
+ pr_debug(" mmio (P) = 0x%016lx..0x%016lx\n",
+ bus->mmio_start, bus->mmio_end);
+ pr_debug(" pio (V) = 0x%016lx..0x%016lx\n",
+ bus->pio_vstart, bus->pio_vend);
+ pr_debug(" regs (P) = 0x%016lx (V) = 0x%p\n",
+ rsrc.start + SPIDER_PCI_REG_BASE, bus->regs);
+
+ spider_pci_setup_chip(bus);
+}
+
+static struct ppc_pci_io __initdata spider_pci_io = {
+ .readb = spider_readb,
+ .readw = spider_readw,
+ .readl = spider_readl,
+ .readq = spider_readq,
+ .readw_be = spider_readw_be,
+ .readl_be = spider_readl_be,
+ .readq_be = spider_readq_be,
+ .readsb = spider_readsb,
+ .readsw = spider_readsw,
+ .readsl = spider_readsl,
+ .memcpy_fromio = spider_memcpy_fromio,
+};
+
+static int __init spider_pci_workaround_init(void)
+{
+ struct pci_controller *phb;
+
+ if (!machine_is(cell))
+ return 0;
+
+ /* Find spider bridges. We assume they have been all probed
+ * in setup_arch(). If that was to change, we would need to
+ * update this code to cope with dynamically added busses
+ */
+ list_for_each_entry(phb, &hose_list, list_node) {
+ struct device_node *np = phb->arch_data;
+ const char *model = get_property(np, "model", NULL);
+
+ /* If no model property or name isn't exactly "pci", skip */
+ if (model == NULL || strcmp(np->name, "pci"))
+ continue;
+ /* If model is not "Spider", skip */
+ if (strcmp(model, "Spider"))
+ continue;
+ spider_pci_add_one(phb);
+ }
+
+ /* No Spider PCI found, exit */
+ if (spider_pci_count == 0)
+ return 0;
+
+ /* Setup IO callbacks. We only setup MMIO reads. PIO reads will
+ * fallback to MMIO reads (though without a token, thus slower)
+ */
+ ppc_pci_io = spider_pci_io;
+
+ /* Setup ioremap callback */
+ ppc_md.ioremap = spider_ioremap;
+
+ return 0;
+}
+arch_initcall(spider_pci_workaround_init);
^ permalink raw reply
* [PATCH 25/32] powerpc: spider uses low level BE MMIO accessors
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
We use the powerpc specific low level MMIO accessor variants instead
of readl() or readl_be() because we know spidernet is not a real PCI
device and we can thus avoid the performance hit caused by the PCI
workarounds.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
drivers/net/spider_net.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
Index: linux-cell/drivers/net/spider_net.c
===================================================================
--- linux-cell.orig/drivers/net/spider_net.c 2006-11-07 15:10:08.000000000 +1100
+++ linux-cell/drivers/net/spider_net.c 2006-11-07 15:11:26.000000000 +1100
@@ -88,12 +88,11 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_
static inline u32
spider_net_read_reg(struct spider_net_card *card, u32 reg)
{
- u32 value;
-
- value = readl(card->regs + reg);
- value = le32_to_cpu(value);
-
- return value;
+ /* We use the powerpc specific variants instead of readl_be() because
+ * we know spidernet is not a real PCI device and we can thus avoid the
+ * performance hit caused by the PCI workarounds.
+ */
+ return in_be32(card->regs + reg);
}
/**
@@ -105,8 +104,11 @@ spider_net_read_reg(struct spider_net_ca
static inline void
spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
{
- value = cpu_to_le32(value);
- writel(value, card->regs + reg);
+ /* We use the powerpc specific variants instead of writel_be() because
+ * we know spidernet is not a real PCI device and we can thus avoid the
+ * performance hit caused by the PCI workarounds.
+ */
+ out_be32(card->regs + reg, value);
}
/** spider_net_write_phy - write to phy register
^ permalink raw reply
* [PATCH 26/32] powerpc: Add an optional offset to direct DMA on 64 bits
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
This patch adds an optional global offset that can be added to DMA addresses
when using the direct DMA operations.
That brings it a step closer to the 32 bits direct DMA operations, and makes
it useable on Cell when the MMU is disabled and we are using a spider
southbridge.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/dma_64.c | 11 ++++++++---
include/asm-powerpc/dma-mapping.h | 2 ++
2 files changed, 10 insertions(+), 3 deletions(-)
Index: linux-cell/arch/powerpc/kernel/dma_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/dma_64.c 2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/dma_64.c 2006-11-10 16:45:21.000000000 +1100
@@ -111,7 +111,11 @@ EXPORT_SYMBOL(dma_iommu_ops);
/*
* Generic direct DMA implementation
+ *
+ * This implementation supports a global offset that can be applied if
+ * the address at which memory is visible to devices is not 0.
*/
+unsigned long dma_direct_offset;
static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
@@ -122,7 +126,7 @@ static void *dma_direct_alloc_coherent(s
ret = (void *)__get_free_pages(flag, get_order(size));
if (ret != NULL) {
memset(ret, 0, size);
- *dma_handle = virt_to_abs(ret);
+ *dma_handle = virt_to_abs(ret) | dma_direct_offset;
}
return ret;
}
@@ -137,7 +141,7 @@ static dma_addr_t dma_direct_map_single(
size_t size,
enum dma_data_direction direction)
{
- return virt_to_abs(ptr);
+ return virt_to_abs(ptr) | dma_direct_offset;
}
static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr,
@@ -152,7 +156,8 @@ static int dma_direct_map_sg(struct devi
int i;
for (i = 0; i < nents; i++, sg++) {
- sg->dma_address = page_to_phys(sg->page) + sg->offset;
+ sg->dma_address = (page_to_phys(sg->page) + sg->offset) |
+ dma_direct_offset;
sg->dma_length = sg->length;
}
Index: linux-cell/include/asm-powerpc/dma-mapping.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/dma-mapping.h 2006-11-10 16:26:34.000000000 +1100
+++ linux-cell/include/asm-powerpc/dma-mapping.h 2006-11-10 16:45:21.000000000 +1100
@@ -187,6 +187,8 @@ static inline void dma_unmap_sg(struct d
extern struct dma_mapping_ops dma_iommu_ops;
extern struct dma_mapping_ops dma_direct_ops;
+extern unsigned long dma_direct_offset;
+
#else /* CONFIG_PPC64 */
#define dma_supported(dev, mask) (1)
^ permalink raw reply
* [PATCH 27/32] powerpc: Make direct DMA use node local allocations
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
This patch makes dma_alloc_coherent() use node local allocation when
using the direct DMA ops. The node is obtained from the new device
extension. If no such extension is present, the current node is used.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/dma_64.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
Index: linux-cell/arch/powerpc/kernel/dma_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/dma_64.c 2006-11-10 16:53:23.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/dma_64.c 2006-11-10 16:53:56.000000000 +1100
@@ -120,14 +120,18 @@ unsigned long dma_direct_offset;
static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
+ struct page *page;
void *ret;
+ int node = dev->archdata.numa_node;
/* TODO: Maybe use the numa node here too ? */
- ret = (void *)__get_free_pages(flag, get_order(size));
- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_abs(ret) | dma_direct_offset;
- }
+ page = alloc_pages_node(node, flag, get_order(size));
+ if (page == NULL)
+ return NULL;
+ ret = page_address(page);
+ memset(ret, 0, size);
+ *dma_handle = virt_to_abs(ret) | dma_direct_offset;
+
return ret;
}
^ permalink raw reply
* [PATCH 28/32] powerpc: Make cell use direct DMA ops
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
Now that the direct DMA ops supports an offset, we use that instead
of defining our own.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/platforms/cell/iommu.c | 79 ++----------------------------------
1 file changed, 6 insertions(+), 73 deletions(-)
Index: linux-cell/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.c 2006-11-07 16:45:08.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/iommu.c 2006-11-07 16:48:00.000000000 +1100
@@ -46,8 +46,6 @@
#include "iommu.h"
-static dma_addr_t cell_dma_valid = SPIDER_DMA_VALID;
-
static inline unsigned long
get_iopt_entry(unsigned long real_address, unsigned long ioid,
unsigned long prot)
@@ -417,83 +415,18 @@ static int cell_map_iommu(void)
return 1;
}
-static void *cell_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- void *ret;
-
- ret = (void *)__get_free_pages(flag, get_order(size));
- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_abs(ret) | cell_dma_valid;
- }
- return ret;
-}
-
-static void cell_free_coherent(struct device *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t cell_map_single(struct device *hwdev, void *ptr,
- size_t size, enum dma_data_direction direction)
-{
- return virt_to_abs(ptr) | cell_dma_valid;
-}
-
-static void cell_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction direction)
-{
-}
-
-static int cell_map_sg(struct device *hwdev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction)
-{
- int i;
-
- for (i = 0; i < nents; i++, sg++) {
- sg->dma_address = (page_to_phys(sg->page) + sg->offset)
- | cell_dma_valid;
- sg->dma_length = sg->length;
- }
-
- return nents;
-}
-
-static void cell_unmap_sg(struct device *hwdev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction)
-{
-}
-
-static int cell_dma_supported(struct device *dev, u64 mask)
-{
- return mask < 0x100000000ull;
-}
-
-static struct dma_mapping_ops cell_iommu_ops = {
- .alloc_coherent = cell_alloc_coherent,
- .free_coherent = cell_free_coherent,
- .map_single = cell_map_single,
- .unmap_single = cell_unmap_single,
- .map_sg = cell_map_sg,
- .unmap_sg = cell_unmap_sg,
- .dma_supported = cell_dma_supported,
-};
-
void cell_init_iommu(void)
{
int setup_bus = 0;
- /* If we have an Axon bridge, clear the DMA valid mask. This is fairly
- * hackish but will work well enough until we have proper iommu code.
- */
- if (of_find_node_by_name(NULL, "axon"))
- cell_dma_valid = 0;
-
if (of_find_node_by_path("/mambo")) {
pr_info("Not using iommu on systemsim\n");
} else {
+ /* If we don't have an Axon bridge, we assume we have a
+ * spider which requires a DMA offset
+ */
+ if (of_find_node_by_name(NULL, "axon") == NULL)
+ dma_direct_offset = SPIDER_DMA_VALID;
if (!(of_chosen &&
get_property(of_chosen, "linux,iommu-off", NULL)))
@@ -509,5 +442,5 @@ void cell_init_iommu(void)
}
}
- pci_dma_ops = &cell_iommu_ops;
+ pci_dma_ops = &dma_direct_ops;
}
^ permalink raw reply
* [PATCH 29/32] powerpc: Cell iommu support
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
From: Jeremy Kerr <jk@ozlabs.org>
This patch adds full cell iommu support (and iommu diabled mode).
It implements mapping/unmapping of iommu pages on demand using the
standard powerpc iommu framework. It also supports running with
iommu disabled for machines with less than 2Gb of memory. (The
default is off in that case, though it can be forced on with the
kernel command line option iommu=force).
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/prom_init.c | 14
arch/powerpc/kernel/setup_64.c | 3
arch/powerpc/platforms/cell/iommu.c | 995 +++++++++++++++++++++++-------------
arch/powerpc/platforms/cell/iommu.h | 67 --
arch/powerpc/platforms/cell/setup.c | 43 -
arch/powerpc/sysdev/dart_iommu.c | 3
include/asm-powerpc/iommu.h | 6
7 files changed, 660 insertions(+), 471 deletions(-)
Index: linux-cell/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.c 2006-11-11 14:55:34.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/iommu.c 2006-11-11 14:55:40.000000000 +1100
@@ -1,446 +1,747 @@
/*
* IOMMU implementation for Cell Broadband Processor Architecture
- * We just establish a linear mapping at boot by setting all the
- * IOPT cache entries in the CPU.
- * The mapping functions should be identical to pci_direct_iommu,
- * except for the handling of the high order bit that is required
- * by the Spider bridge. These should be split into a separate
- * file at the point where we get a different bridge chip.
*
- * Copyright (C) 2005 IBM Deutschland Entwicklung GmbH,
- * Arnd Bergmann <arndb@de.ibm.com>
+ * (C) Copyright IBM Corporation 2006
*
- * Based on linear mapping
- * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ * Author: Jeremy Kerr <jk@ozlabs.org>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#undef DEBUG
#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/compiler.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
-#include <asm/sections.h>
-#include <asm/iommu.h>
-#include <asm/io.h>
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
+#include <asm/iommu.h>
#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/abs_addr.h>
-#include <asm/system.h>
-#include <asm/ppc-pci.h>
+#include <asm/pci-bridge.h>
#include <asm/udbg.h>
+#include <asm/of_platform.h>
+#include <asm/lmb.h>
-#include "iommu.h"
+#include "cbe_regs.h"
+#include "interrupt.h"
-static inline unsigned long
-get_iopt_entry(unsigned long real_address, unsigned long ioid,
- unsigned long prot)
-{
- return (prot & IOPT_PROT_MASK)
- | (IOPT_COHERENT)
- | (IOPT_ORDER_VC)
- | (real_address & IOPT_RPN_MASK)
- | (ioid & IOPT_IOID_MASK);
-}
-
-typedef struct {
- unsigned long val;
-} ioste;
-
-static inline ioste
-mk_ioste(unsigned long val)
-{
- ioste ioste = { .val = val, };
- return ioste;
-}
-
-static inline ioste
-get_iost_entry(unsigned long iopt_base, unsigned long io_address, unsigned page_size)
-{
- unsigned long ps;
- unsigned long iostep;
- unsigned long nnpt;
- unsigned long shift;
-
- switch (page_size) {
- case 0x1000000:
- ps = IOST_PS_16M;
- nnpt = 0; /* one page per segment */
- shift = 5; /* segment has 16 iopt entries */
- break;
-
- case 0x100000:
- ps = IOST_PS_1M;
- nnpt = 0; /* one page per segment */
- shift = 1; /* segment has 256 iopt entries */
- break;
-
- case 0x10000:
- ps = IOST_PS_64K;
- nnpt = 0x07; /* 8 pages per io page table */
- shift = 0; /* all entries are used */
- break;
-
- case 0x1000:
- ps = IOST_PS_4K;
- nnpt = 0x7f; /* 128 pages per io page table */
- shift = 0; /* all entries are used */
- break;
-
- default: /* not a known compile time constant */
- {
- /* BUILD_BUG_ON() is not usable here */
- extern void __get_iost_entry_bad_page_size(void);
- __get_iost_entry_bad_page_size();
- }
- break;
- }
+/* Define CELL_IOMMU_REAL_UNMAP to actually unmap non-used pages
+ * instead of leaving them mapped to some dummy page. This can be
+ * enabled once the appropriate workarounds for spider bugs have
+ * been enabled
+ */
+#define CELL_IOMMU_REAL_UNMAP
- iostep = iopt_base +
- /* need 8 bytes per iopte */
- (((io_address / page_size * 8)
- /* align io page tables on 4k page boundaries */
- << shift)
- /* nnpt+1 pages go into each iopt */
- & ~(nnpt << 12));
+/* Define CELL_IOMMU_STRICT_PROTECTION to enforce protection of
+ * IO PTEs based on the transfer direction. That can be enabled
+ * once spider-net has been fixed to pass the correct direction
+ * to the DMA mapping functions
+ */
+#define CELL_IOMMU_STRICT_PROTECTION
- nnpt++; /* this seems to work, but the documentation is not clear
- about wether we put nnpt or nnpt-1 into the ioste bits.
- In theory, this can't work for 4k pages. */
- return mk_ioste(IOST_VALID_MASK
- | (iostep & IOST_PT_BASE_MASK)
- | ((nnpt << 5) & IOST_NNPT_MASK)
- | (ps & IOST_PS_MASK));
-}
-/* compute the address of an io pte */
-static inline unsigned long
-get_ioptep(ioste iost_entry, unsigned long io_address)
-{
- unsigned long iopt_base;
- unsigned long page_size;
- unsigned long page_number;
- unsigned long iopt_offset;
+#define NR_IOMMUS 2
- iopt_base = iost_entry.val & IOST_PT_BASE_MASK;
- page_size = iost_entry.val & IOST_PS_MASK;
+/* IOC mmap registers */
+#define IOC_Reg_Size 0x2000
- /* decode page size to compute page number */
- page_number = (io_address & 0x0fffffff) >> (10 + 2 * page_size);
- /* page number is an offset into the io page table */
- iopt_offset = (page_number << 3) & 0x7fff8ul;
- return iopt_base + iopt_offset;
-}
+#define IOC_IOPT_CacheInvd 0x908
+#define IOC_IOPT_CacheInvd_NE_Mask 0xffe0000000000000ul
+#define IOC_IOPT_CacheInvd_IOPTE_Mask 0x000003fffffffff8ul
+#define IOC_IOPT_CacheInvd_Busy 0x0000000000000001ul
+
+#define IOC_IOST_Origin 0x918
+#define IOC_IOST_Origin_E 0x8000000000000000ul
+#define IOC_IOST_Origin_HW 0x0000000000000800ul
+#define IOC_IOST_Origin_HL 0x0000000000000400ul
+
+#define IOC_IO_ExcpStat 0x920
+#define IOC_IO_ExcpStat_V 0x8000000000000000ul
+#define IOC_IO_ExcpStat_SPF_Mask 0x6000000000000000ul
+#define IOC_IO_ExcpStat_SPF_S 0x6000000000000000ul
+#define IOC_IO_ExcpStat_SPF_P 0x4000000000000000ul
+#define IOC_IO_ExcpStat_ADDR_Mask 0x00000007fffff000ul
+#define IOC_IO_ExcpStat_RW_Mask 0x0000000000000800ul
+#define IOC_IO_ExcpStat_IOID_Mask 0x00000000000007fful
+
+#define IOC_IO_ExcpMask 0x928
+#define IOC_IO_ExcpMask_SFE 0x4000000000000000ul
+#define IOC_IO_ExcpMask_PFE 0x2000000000000000ul
+
+#define IOC_IOCmd_Offset 0x1000
+
+#define IOC_IOCmd_Cfg 0xc00
+#define IOC_IOCmd_Cfg_TE 0x0000800000000000ul
+
+
+/* Segment table entries */
+#define IOSTE_V 0x8000000000000000ul /* valid */
+#define IOSTE_H 0x4000000000000000ul /* cache hint */
+#define IOSTE_PT_Base_RPN_Mask 0x3ffffffffffff000ul /* base RPN of IOPT */
+#define IOSTE_NPPT_Mask 0x0000000000000fe0ul /* no. pages in IOPT */
+#define IOSTE_PS_Mask 0x0000000000000007ul /* page size */
+#define IOSTE_PS_4K 0x0000000000000001ul /* - 4kB */
+#define IOSTE_PS_64K 0x0000000000000003ul /* - 64kB */
+#define IOSTE_PS_1M 0x0000000000000005ul /* - 1MB */
+#define IOSTE_PS_16M 0x0000000000000007ul /* - 16MB */
+
+/* Page table entries */
+#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */
+#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */
+#define IOPTE_M 0x2000000000000000ul /* coherency required */
+#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */
+#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */
+#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */
+#define IOPTE_H 0x0000000000000800ul /* cache hint */
+#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */
+
+
+/* IOMMU sizing */
+#define IO_SEGMENT_SHIFT 28
+#define IO_PAGENO_BITS (IO_SEGMENT_SHIFT - IOMMU_PAGE_SHIFT)
+
+/* The high bit needs to be set on every DMA address */
+#define SPIDER_DMA_OFFSET 0x80000000ul
+
+struct iommu_window {
+ struct list_head list;
+ struct cbe_iommu *iommu;
+ unsigned long offset;
+ unsigned long size;
+ unsigned long pte_offset;
+ unsigned int ioid;
+ struct iommu_table table;
+};
-/* compute the tag field of the iopt cache entry */
-static inline unsigned long
-get_ioc_tag(ioste iost_entry, unsigned long io_address)
-{
- unsigned long iopte = get_ioptep(iost_entry, io_address);
+#define NAMESIZE 8
+struct cbe_iommu {
+ int nid;
+ char name[NAMESIZE];
+ void __iomem *xlate_regs;
+ void __iomem *cmd_regs;
+ unsigned long *stab;
+ unsigned long *ptab;
+ void *pad_page;
+ struct list_head windows;
+};
- return IOPT_VALID_MASK
- | ((iopte & 0x00000000000000ff8ul) >> 3)
- | ((iopte & 0x0000003fffffc0000ul) >> 9);
-}
+/* Static array of iommus, one per node
+ * each contains a list of windows, keyed from dma_window property
+ * - on bus setup, look for a matching window, or create one
+ * - on dev setup, assign iommu_table ptr
+ */
+static struct cbe_iommu iommus[NR_IOMMUS];
+static int cbe_nr_iommus;
-/* compute the hashed 6 bit index for the 4-way associative pte cache */
-static inline unsigned long
-get_ioc_hash(ioste iost_entry, unsigned long io_address)
+static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte,
+ long n_ptes)
{
- unsigned long iopte = get_ioptep(iost_entry, io_address);
+ unsigned long *reg, val;
+ long n;
+
+ reg = iommu->xlate_regs + IOC_IOPT_CacheInvd;
+
+ while (n_ptes > 0) {
+ /* we can invalidate up to 1 << 11 PTEs at once */
+ n = min(n_ptes, 1l << 11);
+ val = (((n /*- 1*/) << 53) & IOC_IOPT_CacheInvd_NE_Mask)
+ | (__pa(pte) & IOC_IOPT_CacheInvd_IOPTE_Mask)
+ | IOC_IOPT_CacheInvd_Busy;
+
+ out_be64(reg, val);
+ while (in_be64(reg) & IOC_IOPT_CacheInvd_Busy)
+ ;
- return ((iopte & 0x000000000000001f8ul) >> 3)
- ^ ((iopte & 0x00000000000020000ul) >> 17)
- ^ ((iopte & 0x00000000000010000ul) >> 15)
- ^ ((iopte & 0x00000000000008000ul) >> 13)
- ^ ((iopte & 0x00000000000004000ul) >> 11)
- ^ ((iopte & 0x00000000000002000ul) >> 9)
- ^ ((iopte & 0x00000000000001000ul) >> 7);
+ n_ptes -= n;
+ pte += n;
+ }
}
-/* same as above, but pretend that we have a simpler 1-way associative
- pte cache with an 8 bit index */
-static inline unsigned long
-get_ioc_hash_1way(ioste iost_entry, unsigned long io_address)
+static void tce_build_cell(struct iommu_table *tbl, long index, long npages,
+ unsigned long uaddr, enum dma_data_direction direction)
{
- unsigned long iopte = get_ioptep(iost_entry, io_address);
+ int i;
+ unsigned long *io_pte, base_pte;
+ struct iommu_window *window =
+ container_of(tbl, struct iommu_window, table);
- return ((iopte & 0x000000000000001f8ul) >> 3)
- ^ ((iopte & 0x00000000000020000ul) >> 17)
- ^ ((iopte & 0x00000000000010000ul) >> 15)
- ^ ((iopte & 0x00000000000008000ul) >> 13)
- ^ ((iopte & 0x00000000000004000ul) >> 11)
- ^ ((iopte & 0x00000000000002000ul) >> 9)
- ^ ((iopte & 0x00000000000001000ul) >> 7)
- ^ ((iopte & 0x0000000000000c000ul) >> 8);
-}
+ /* implementing proper protection causes problems with the spidernet
+ * driver - check mapping directions later, but allow read & write by
+ * default for now.*/
+#ifdef CELL_IOMMU_STRICT_PROTECTION
+ /* to avoid referencing a global, we use a trick here to setup the
+ * protection bit. "prot" is setup to be 3 fields of 4 bits apprended
+ * together for each of the 3 supported direction values. It is then
+ * shifted left so that the fields matching the desired direction
+ * lands on the appropriate bits, and other bits are masked out.
+ */
+ const unsigned long prot = 0xc48;
+ base_pte =
+ ((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R))
+ | IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask);
+#else
+ base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW |
+ (window->ioid & IOPTE_IOID_Mask);
+#endif
-static inline ioste
-get_iost_cache(void __iomem *base, unsigned long index)
-{
- unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR);
- return mk_ioste(in_be64(&p[index]));
-}
+ io_pte = (unsigned long *)tbl->it_base + (index - window->pte_offset);
-static inline void
-set_iost_cache(void __iomem *base, unsigned long index, ioste ste)
-{
- unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR);
- pr_debug("ioste %02lx was %016lx, store %016lx", index,
- get_iost_cache(base, index).val, ste.val);
- out_be64(&p[index], ste.val);
- pr_debug(" now %016lx\n", get_iost_cache(base, index).val);
-}
+ for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
+ io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
-static inline unsigned long
-get_iopt_cache(void __iomem *base, unsigned long index, unsigned long *tag)
-{
- unsigned long __iomem *tags = (void *)(base + IOC_PT_CACHE_DIR);
- unsigned long __iomem *p = (void *)(base + IOC_PT_CACHE_REG);
+ mb();
+
+ invalidate_tce_cache(window->iommu, io_pte, npages);
- *tag = tags[index];
- rmb();
- return *p;
+ pr_debug("tce_build_cell(index=%lx,n=%lx,dir=%d,base_pte=%lx)\n",
+ index, npages, direction, base_pte);
}
-static inline void
-set_iopt_cache(void __iomem *base, unsigned long index,
- unsigned long tag, unsigned long val)
+static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
{
- unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR;
- unsigned long __iomem *p = base + IOC_PT_CACHE_REG;
- out_be64(p, val);
- out_be64(&tags[index], tag);
-}
+ int i;
+ unsigned long *io_pte, pte;
+ struct iommu_window *window =
+ container_of(tbl, struct iommu_window, table);
-static inline void
-set_iost_origin(void __iomem *base)
-{
- unsigned long __iomem *p = base + IOC_ST_ORIGIN;
- unsigned long origin = IOSTO_ENABLE | IOSTO_SW;
+ pr_debug("tce_free_cell(index=%lx,n=%lx)\n", index, npages);
- pr_debug("iost_origin %016lx, now %016lx\n", in_be64(p), origin);
- out_be64(p, origin);
-}
+#ifdef CELL_IOMMU_REAL_UNMAP
+ pte = 0;
+#else
+ /* spider bridge does PCI reads after freeing - insert a mapping
+ * to a scratch page instead of an invalid entry */
+ pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page)
+ | (window->ioid & IOPTE_IOID_Mask);
+#endif
-static inline void
-set_iocmd_config(void __iomem *base)
-{
- unsigned long __iomem *p = base + 0xc00;
- unsigned long conf;
+ io_pte = (unsigned long *)tbl->it_base + (index - window->pte_offset);
- conf = in_be64(p);
- pr_debug("iost_conf %016lx, now %016lx\n", conf, conf | IOCMD_CONF_TE);
- out_be64(p, conf | IOCMD_CONF_TE);
+ for (i = 0; i < npages; i++)
+ io_pte[i] = pte;
+
+ mb();
+
+ invalidate_tce_cache(window->iommu, io_pte, npages);
}
-static void enable_mapping(void __iomem *base, void __iomem *mmio_base)
+static irqreturn_t ioc_interrupt(int irq, void *data)
{
- set_iocmd_config(base);
- set_iost_origin(mmio_base);
+ unsigned long stat;
+ struct cbe_iommu *iommu = data;
+
+ stat = in_be64(iommu->xlate_regs + IOC_IO_ExcpStat);
+
+ /* Might want to rate limit it */
+ printk(KERN_ERR "iommu: DMA exception 0x%016lx\n", stat);
+ printk(KERN_ERR " V=%d, SPF=[%c%c], RW=%s, IOID=0x%04x\n",
+ !!(stat & IOC_IO_ExcpStat_V),
+ (stat & IOC_IO_ExcpStat_SPF_S) ? 'S' : ' ',
+ (stat & IOC_IO_ExcpStat_SPF_P) ? 'P' : ' ',
+ (stat & IOC_IO_ExcpStat_RW_Mask) ? "Read" : "Write",
+ (unsigned int)(stat & IOC_IO_ExcpStat_IOID_Mask));
+ printk(KERN_ERR " page=0x%016lx\n",
+ stat & IOC_IO_ExcpStat_ADDR_Mask);
+
+ /* clear interrupt */
+ stat &= ~IOC_IO_ExcpStat_V;
+ out_be64(iommu->xlate_regs + IOC_IO_ExcpStat, stat);
+
+ return IRQ_HANDLED;
}
-struct cell_iommu {
- unsigned long base;
- unsigned long mmio_base;
- void __iomem *mapped_base;
- void __iomem *mapped_mmio_base;
-};
+static int cell_iommu_find_ioc(int nid, unsigned long *base)
+{
+ struct device_node *np;
+ struct resource r;
-static struct cell_iommu cell_iommus[NR_CPUS];
+ *base = 0;
-/* initialize the iommu to support a simple linear mapping
- * for each DMA window used by any device. For now, we
- * happen to know that there is only one DMA window in use,
- * starting at iopt_phys_offset. */
-static void cell_do_map_iommu(struct cell_iommu *iommu,
- unsigned int ioid,
- unsigned long map_start,
- unsigned long map_size)
-{
- unsigned long io_address, real_address;
- void __iomem *ioc_base, *ioc_mmio_base;
- ioste ioste;
- unsigned long index;
+ /* First look for new style /be nodes */
+ for_each_node_by_name(np, "ioc") {
+ if (of_node_to_nid(np) != nid)
+ continue;
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_ERR "iommu: can't get address for %s\n",
+ np->full_name);
+ continue;
+ }
+ *base = r.start;
+ of_node_put(np);
+ return 0;
+ }
- /* we pretend the io page table was at a very high address */
- const unsigned long fake_iopt = 0x10000000000ul;
- const unsigned long io_page_size = 0x1000000; /* use 16M pages */
- const unsigned long io_segment_size = 0x10000000; /* 256M */
-
- ioc_base = iommu->mapped_base;
- ioc_mmio_base = iommu->mapped_mmio_base;
-
- for (real_address = 0, io_address = map_start;
- io_address <= map_start + map_size;
- real_address += io_page_size, io_address += io_page_size) {
- ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
- if ((real_address % io_segment_size) == 0) /* segment start */
- set_iost_cache(ioc_mmio_base,
- io_address >> 28, ioste);
- index = get_ioc_hash_1way(ioste, io_address);
- pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
- io_address, index, ioste.val);
- set_iopt_cache(ioc_mmio_base,
- get_ioc_hash_1way(ioste, io_address),
- get_ioc_tag(ioste, io_address),
- get_iopt_entry(real_address, ioid, IOPT_PROT_RW));
+ /* Ok, let's try the old way */
+ for_each_node_by_type(np, "cpu") {
+ const unsigned int *nidp;
+ const unsigned long *tmp;
+
+ nidp = get_property(np, "node-id", NULL);
+ if (nidp && *nidp == nid) {
+ tmp = get_property(np, "ioc-translation", NULL);
+ if (tmp) {
+ *base = *tmp;
+ of_node_put(np);
+ return 0;
+ }
+ }
}
+
+ return -ENODEV;
}
-static void pci_dma_cell_bus_setup(struct pci_bus *b)
+static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long size)
{
- const unsigned int *ioid;
- unsigned long map_start, map_size, token;
- const unsigned long *dma_window;
- struct cell_iommu *iommu;
- struct device_node *d;
+ struct page *page;
+ int ret, i;
+ unsigned long reg, segments, pages_per_segment, ptab_size, n_pte_pages;
+ unsigned long xlate_base;
+ unsigned int virq;
+
+ if (cell_iommu_find_ioc(iommu->nid, &xlate_base))
+ panic("%s: missing IOC register mappings for node %d\n",
+ __FUNCTION__, iommu->nid);
+
+ iommu->xlate_regs = ioremap(xlate_base, IOC_Reg_Size);
+ iommu->cmd_regs = iommu->xlate_regs + IOC_IOCmd_Offset;
+
+ segments = size >> IO_SEGMENT_SHIFT;
+ pages_per_segment = 1ull << IO_PAGENO_BITS;
+
+ pr_debug("%s: iommu[%d]: segments: %lu, pages per segment: %lu\n",
+ __FUNCTION__, iommu->nid, segments, pages_per_segment);
+
+ /* set up the segment table */
+ page = alloc_pages_node(iommu->nid, GFP_KERNEL, 0);
+ BUG_ON(!page);
+ iommu->stab = page_address(page);
+ clear_page(iommu->stab);
+
+ /* ... and the page tables. Since these are contiguous, we can treat
+ * the page tables as one array of ptes, like pSeries does.
+ */
+ ptab_size = segments * pages_per_segment * sizeof(unsigned long);
+ pr_debug("%s: iommu[%d]: ptab_size: %lu, order: %d\n", __FUNCTION__,
+ iommu->nid, ptab_size, get_order(ptab_size));
+ page = alloc_pages_node(iommu->nid, GFP_KERNEL, get_order(ptab_size));
+ BUG_ON(!page);
+
+ iommu->ptab = page_address(page);
+ memset(iommu->ptab, 0, ptab_size);
+
+ /* allocate a bogus page for the end of each mapping */
+ page = alloc_pages_node(iommu->nid, GFP_KERNEL, 0);
+ BUG_ON(!page);
+ iommu->pad_page = page_address(page);
+ clear_page(iommu->pad_page);
+
+ /* number of pages needed for a page table */
+ n_pte_pages = (pages_per_segment *
+ sizeof(unsigned long)) >> IOMMU_PAGE_SHIFT;
+
+ pr_debug("%s: iommu[%d]: stab at %p, ptab at %p, n_pte_pages: %lu\n",
+ __FUNCTION__, iommu->nid, iommu->stab, iommu->ptab,
+ n_pte_pages);
+
+ /* initialise the STEs */
+ reg = IOSTE_V | ((n_pte_pages - 1) << 5);
+
+ if (IOMMU_PAGE_SIZE == 0x1000)
+ reg |= IOSTE_PS_4K;
+ else if (IOMMU_PAGE_SIZE == 0x10000)
+ reg |= IOSTE_PS_64K;
+ else {
+ extern void __unknown_page_size_error(void);
+ __unknown_page_size_error();
+ }
+
+ pr_debug("Setting up IOMMU stab:\n");
+ for (i = 0; i * (1ul << IO_SEGMENT_SHIFT) < size; i++) {
+ iommu->stab[i] = reg |
+ (__pa(iommu->ptab) + n_pte_pages * IOMMU_PAGE_SIZE * i);
+ pr_debug("\t[%d] 0x%016lx\n", i, iommu->stab[i]);
+ }
- d = pci_bus_to_OF_node(b);
+ /* ensure that the STEs have updated */
+ mb();
- ioid = get_property(d, "ioid", NULL);
- if (!ioid)
- pr_debug("No ioid entry found !\n");
+ /* setup interrupts for the iommu. */
+ reg = in_be64(iommu->xlate_regs + IOC_IO_ExcpStat);
+ out_be64(iommu->xlate_regs + IOC_IO_ExcpStat,
+ reg & ~IOC_IO_ExcpStat_V);
+ out_be64(iommu->xlate_regs + IOC_IO_ExcpMask,
+ IOC_IO_ExcpMask_PFE | IOC_IO_ExcpMask_SFE);
- dma_window = get_property(d, "ibm,dma-window", NULL);
- if (!dma_window)
- pr_debug("No ibm,dma-window entry found !\n");
+ virq = irq_create_mapping(NULL,
+ IIC_IRQ_IOEX_ATI | (iommu->nid << IIC_IRQ_NODE_SHIFT));
+ BUG_ON(virq == NO_IRQ);
- map_start = dma_window[1];
- map_size = dma_window[2];
- token = dma_window[0] >> 32;
+ ret = request_irq(virq, ioc_interrupt, IRQF_DISABLED,
+ iommu->name, iommu);
+ BUG_ON(ret);
- iommu = &cell_iommus[token];
+ /* set the IOC segment table origin register (and turn on the iommu) */
+ reg = IOC_IOST_Origin_E | __pa(iommu->stab) | IOC_IOST_Origin_HW;
+ out_be64(iommu->xlate_regs + IOC_IOST_Origin, reg);
+ in_be64(iommu->xlate_regs + IOC_IOST_Origin);
- cell_do_map_iommu(iommu, *ioid, map_start, map_size);
+ /* turn on IO translation */
+ reg = in_be64(iommu->cmd_regs + IOC_IOCmd_Cfg) | IOC_IOCmd_Cfg_TE;
+ out_be64(iommu->cmd_regs + IOC_IOCmd_Cfg, reg);
}
+#if 0/* Unused for now */
+static struct iommu_window *find_window(struct cbe_iommu *iommu,
+ unsigned long offset, unsigned long size)
+{
+ struct iommu_window *window;
+
+ /* todo: check for overlapping (but not equal) windows) */
-static int cell_map_iommu_hardcoded(int num_nodes)
+ list_for_each_entry(window, &(iommu->windows), list) {
+ if (window->offset == offset && window->size == size)
+ return window;
+ }
+
+ return NULL;
+}
+#endif
+
+static struct iommu_window * __init
+cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
+ unsigned long offset, unsigned long size,
+ unsigned long pte_offset)
{
- struct cell_iommu *iommu = NULL;
+ struct iommu_window *window;
+ const unsigned int *ioid;
- pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
+ ioid = get_property(np, "ioid", NULL);
+ if (ioid == NULL)
+ printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
+ np->full_name);
+
+ window = kmalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid);
+ BUG_ON(window == NULL);
+
+ window->offset = offset;
+ window->size = size;
+ window->ioid = ioid ? *ioid : 0;
+ window->iommu = iommu;
+ window->pte_offset = pte_offset;
+
+ window->table.it_blocksize = 16;
+ window->table.it_base = (unsigned long)iommu->ptab;
+ window->table.it_index = iommu->nid;
+ window->table.it_offset = (offset >> IOMMU_PAGE_SHIFT) +
+ window->pte_offset;
+ window->table.it_size = size >> IOMMU_PAGE_SHIFT;
+
+ iommu_init_table(&window->table, iommu->nid);
+
+ pr_debug("\tioid %d\n", window->ioid);
+ pr_debug("\tblocksize %ld\n", window->table.it_blocksize);
+ pr_debug("\tbase 0x%016lx\n", window->table.it_base);
+ pr_debug("\toffset 0x%lx\n", window->table.it_offset);
+ pr_debug("\tsize %ld\n", window->table.it_size);
+
+ list_add(&window->list, &iommu->windows);
+
+ if (offset != 0)
+ return window;
+
+ /* We need to map and reserve the first IOMMU page since it's used
+ * by the spider workaround. In theory, we only need to do that when
+ * running on spider but it doesn't really matter.
+ *
+ * This code also assumes that we have a window that starts at 0,
+ * which is the case on all spider based blades.
+ */
+ __set_bit(0, window->table.it_map);
+ tce_build_cell(&window->table, window->table.it_offset, 1,
+ (unsigned long)iommu->pad_page, DMA_TO_DEVICE);
+ window->table.it_hint = window->table.it_blocksize;
+
+ return window;
+}
+
+static struct cbe_iommu *cell_iommu_for_node(int nid)
+{
+ int i;
+
+ for (i = 0; i < cbe_nr_iommus; i++)
+ if (iommus[i].nid == nid)
+ return &iommus[i];
+ return NULL;
+}
+
+static void cell_dma_dev_setup(struct device *dev)
+{
+ struct iommu_window *window;
+ struct cbe_iommu *iommu;
+ struct dev_archdata *archdata = &dev->archdata;
+
+ /* If we run without iommu, no need to do anything */
+ if (pci_dma_ops == &dma_direct_ops)
+ return;
+
+ /* Current implementation uses the first window available in that
+ * node's iommu. We -might- do something smarter later though it may
+ * never be necessary
+ */
+ iommu = cell_iommu_for_node(archdata->numa_node);
+ if (iommu == NULL || list_empty(&iommu->windows)) {
+ printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n",
+ archdata->of_node ? archdata->of_node->full_name : "?",
+ archdata->numa_node);
+ return;
+ }
+ window = list_entry(iommu->windows.next, struct iommu_window, list);
- /* node 0 */
- iommu = &cell_iommus[0];
- iommu->mapped_base = ioremap(0x20000511000ul, 0x1000);
- iommu->mapped_mmio_base = ioremap(0x20000510000ul, 0x1000);
+ archdata->dma_data = &window->table;
+}
- enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+static void cell_pci_dma_dev_setup(struct pci_dev *dev)
+{
+ cell_dma_dev_setup(&dev->dev);
+}
- cell_do_map_iommu(iommu, 0x048a,
- 0x20000000ul,0x20000000ul);
+static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct device *dev = data;
- if (num_nodes < 2)
+ /* We are only intereted in device addition */
+ if (action != BUS_NOTIFY_ADD_DEVICE)
return 0;
- /* node 1 */
- iommu = &cell_iommus[1];
- iommu->mapped_base = ioremap(0x30000511000ul, 0x1000);
- iommu->mapped_mmio_base = ioremap(0x30000510000ul, 0x1000);
-
- enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+ /* We use the PCI DMA ops */
+ dev->archdata.dma_ops = pci_dma_ops;
- cell_do_map_iommu(iommu, 0x048a,
- 0x20000000,0x20000000ul);
+ cell_dma_dev_setup(dev);
return 0;
}
+static struct notifier_block cell_of_bus_notifier = {
+ .notifier_call = cell_of_bus_notify
+};
-static int cell_map_iommu(void)
+static int __init cell_iommu_get_window(struct device_node *np,
+ unsigned long *base,
+ unsigned long *size)
{
- unsigned int num_nodes = 0;
- const unsigned int *node_id;
- const unsigned long *base, *mmio_base;
- struct device_node *dn;
- struct cell_iommu *iommu = NULL;
-
- /* determine number of nodes (=iommus) */
- pr_debug("%s(%d): determining number of nodes...", __FUNCTION__, __LINE__);
- for(dn = of_find_node_by_type(NULL, "cpu");
- dn;
- dn = of_find_node_by_type(dn, "cpu")) {
- node_id = get_property(dn, "node-id", NULL);
+ const void *dma_window;
+ unsigned long index;
- if (num_nodes < *node_id)
- num_nodes = *node_id;
- }
+ /* Use ibm,dma-window if available, else, hard code ! */
+ dma_window = get_property(np, "ibm,dma-window", NULL);
+ if (dma_window == NULL) {
+ *base = 0;
+ *size = 0x80000000u;
+ return -ENODEV;
+ }
- num_nodes++;
- pr_debug("%i found.\n", num_nodes);
+ of_parse_dma_window(np, dma_window, &index, base, size);
+ return 0;
+}
- /* map the iommu registers for each node */
- pr_debug("%s(%d): Looping through nodes\n", __FUNCTION__, __LINE__);
- for(dn = of_find_node_by_type(NULL, "cpu");
- dn;
- dn = of_find_node_by_type(dn, "cpu")) {
+static void __init cell_iommu_init_one(struct device_node *np, unsigned long offset)
+{
+ struct cbe_iommu *iommu;
+ unsigned long base, size;
+ int nid, i;
+
+ /* Get node ID */
+ nid = of_node_to_nid(np);
+ if (nid < 0) {
+ printk(KERN_ERR "iommu: failed to get node for %s\n",
+ np->full_name);
+ return;
+ }
+ pr_debug("iommu: setting up iommu for node %d (%s)\n",
+ nid, np->full_name);
- node_id = get_property(dn, "node-id", NULL);
- base = get_property(dn, "ioc-cache", NULL);
- mmio_base = get_property(dn, "ioc-translation", NULL);
+ /* XXX todo: If we can have multiple windows on the same IOMMU, which
+ * isn't the case today, we probably want here to check wether the
+ * iommu for that node is already setup.
+ * However, there might be issue with getting the size right so let's
+ * ignore that for now. We might want to completely get rid of the
+ * multiple window support since the cell iommu supports per-page ioids
+ */
+
+ if (cbe_nr_iommus >= NR_IOMMUS) {
+ printk(KERN_ERR "iommu: too many IOMMUs detected ! (%s)\n",
+ np->full_name);
+ return;
+ }
- if (!base || !mmio_base || !node_id)
- return cell_map_iommu_hardcoded(num_nodes);
+ /* Init base fields */
+ i = cbe_nr_iommus++;
+ iommu = &iommus[i];
+ iommu->stab = 0;
+ iommu->nid = nid;
+ snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i);
+ INIT_LIST_HEAD(&iommu->windows);
+
+ /* Obtain a window for it */
+ cell_iommu_get_window(np, &base, &size);
+
+ pr_debug("\ttranslating window 0x%lx...0x%lx\n",
+ base, base + size - 1);
+
+ /* Initialize the hardware */
+ cell_iommu_setup_hardware(iommu, size);
+
+ /* Setup the iommu_table */
+ cell_iommu_setup_window(iommu, np, base, size,
+ offset >> IOMMU_PAGE_SHIFT);
+}
+
+static void __init cell_disable_iommus(void)
+{
+ int node;
+ unsigned long base, val;
+ void __iomem *xregs, *cregs;
+
+ /* Make sure IOC translation is disabled on all nodes */
+ for_each_online_node(node) {
+ if (cell_iommu_find_ioc(node, &base))
+ continue;
+ xregs = ioremap(base, IOC_Reg_Size);
+ if (xregs == NULL)
+ continue;
+ cregs = xregs + IOC_IOCmd_Offset;
+
+ pr_debug("iommu: cleaning up iommu on node %d\n", node);
+
+ out_be64(xregs + IOC_IOST_Origin, 0);
+ (void)in_be64(xregs + IOC_IOST_Origin);
+ val = in_be64(cregs + IOC_IOCmd_Cfg);
+ val &= ~IOC_IOCmd_Cfg_TE;
+ out_be64(cregs + IOC_IOCmd_Cfg, val);
+ (void)in_be64(cregs + IOC_IOCmd_Cfg);
- iommu = &cell_iommus[*node_id];
- iommu->base = *base;
- iommu->mmio_base = *mmio_base;
+ iounmap(xregs);
+ }
+}
- iommu->mapped_base = ioremap(*base, 0x1000);
- iommu->mapped_mmio_base = ioremap(*mmio_base, 0x1000);
+static int __init cell_iommu_init_disabled(void)
+{
+ struct device_node *np = NULL;
+ unsigned long base = 0, size;
- enable_mapping(iommu->mapped_base,
- iommu->mapped_mmio_base);
+ /* When no iommu is present, we use direct DMA ops */
+ pci_dma_ops = &dma_direct_ops;
+
+ /* First make sure all IOC translation is turned off */
+ cell_disable_iommus();
+
+ /* If we have no Axon, we set up the spider DMA magic offset */
+ if (of_find_node_by_name(NULL, "axon") == NULL)
+ dma_direct_offset = SPIDER_DMA_OFFSET;
+
+ /* Now we need to check to see where the memory is mapped
+ * in PCI space. We assume that all busses use the same dma
+ * window which is always the case so far on Cell, thus we
+ * pick up the first pci-internal node we can find and check
+ * the DMA window from there.
+ */
+ for_each_node_by_name(np, "axon") {
+ if (np->parent == NULL || np->parent->parent != NULL)
+ continue;
+ if (cell_iommu_get_window(np, &base, &size) == 0)
+ break;
+ }
+ if (np == NULL) {
+ for_each_node_by_name(np, "pci-internal") {
+ if (np->parent == NULL || np->parent->parent != NULL)
+ continue;
+ if (cell_iommu_get_window(np, &base, &size) == 0)
+ break;
+ }
+ }
+ of_node_put(np);
- /* everything else will be done in iommu_bus_setup */
+ /* If we found a DMA window, we check if it's big enough to enclose
+ * all of physical memory. If not, we force enable IOMMU
+ */
+ if (np && size < lmb_end_of_DRAM()) {
+ printk(KERN_WARNING "iommu: force-enabled, dma window"
+ " (%ldMB) smaller than total memory (%ldMB)\n",
+ size >> 20, lmb_end_of_DRAM() >> 20);
+ return -ENODEV;
}
- return 1;
+ dma_direct_offset += base;
+
+ printk("iommu: disabled, direct DMA offset is 0x%lx\n",
+ dma_direct_offset);
+
+ return 0;
}
-void cell_init_iommu(void)
+static int __init cell_iommu_init(void)
{
- int setup_bus = 0;
+ struct device_node *np;
- if (of_find_node_by_path("/mambo")) {
- pr_info("Not using iommu on systemsim\n");
- } else {
- /* If we don't have an Axon bridge, we assume we have a
- * spider which requires a DMA offset
- */
- if (of_find_node_by_name(NULL, "axon") == NULL)
- dma_direct_offset = SPIDER_DMA_VALID;
+ if (!machine_is(cell))
+ return -ENODEV;
- if (!(of_chosen &&
- get_property(of_chosen, "linux,iommu-off", NULL)))
- setup_bus = cell_map_iommu();
+ /* If IOMMU is disabled or we have little enough RAM to not need
+ * to enable it, we setup a direct mapping.
+ *
+ * Note: should we make sure we have the IOMMU actually disabled ?
+ */
+ if (iommu_is_off ||
+ (!iommu_force_on && lmb_end_of_DRAM() <= 0x80000000ull))
+ if (cell_iommu_init_disabled() == 0)
+ goto bail;
+
+ /* Setup various ppc_md. callbacks */
+ ppc_md.pci_dma_dev_setup = cell_pci_dma_dev_setup;
+ ppc_md.tce_build = tce_build_cell;
+ ppc_md.tce_free = tce_free_cell;
+
+ /* Create an iommu for each /axon node. */
+ for_each_node_by_name(np, "axon") {
+ if (np->parent == NULL || np->parent->parent != NULL)
+ continue;
+ cell_iommu_init_one(np, 0);
+ }
- if (setup_bus) {
- pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__);
- ppc_md.pci_dma_bus_setup = pci_dma_cell_bus_setup;
- } else {
- pr_debug("%s: IOMMU mapping activated, "
- "no device action necessary\n", __FUNCTION__);
- /* Direct I/O, IOMMU off */
- }
+ /* Create an iommu for each toplevel /pci-internal node for
+ * old hardware/firmware
+ */
+ for_each_node_by_name(np, "pci-internal") {
+ if (np->parent == NULL || np->parent->parent != NULL)
+ continue;
+ cell_iommu_init_one(np, SPIDER_DMA_OFFSET);
}
- pci_dma_ops = &dma_direct_ops;
+ /* Setup default PCI iommu ops */
+ pci_dma_ops = &dma_iommu_ops;
+
+ bail:
+ /* Register callbacks on OF platform device addition/removal
+ * to handle linking them to the right DMA operations
+ */
+ register_bus_notifier(&of_platform_bus_type, &cell_of_bus_notifier);
+
+ return 0;
}
+arch_initcall(cell_iommu_init);
+
Index: linux-cell/arch/powerpc/platforms/cell/iommu.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/iommu.h 2006-11-11 14:55:02.000000000 +1100
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,67 +0,0 @@
-#ifndef CELL_IOMMU_H
-#define CELL_IOMMU_H
-
-/* some constants */
-enum {
- /* segment table entries */
- IOST_VALID_MASK = 0x8000000000000000ul,
- IOST_TAG_MASK = 0x3000000000000000ul,
- IOST_PT_BASE_MASK = 0x000003fffffff000ul,
- IOST_NNPT_MASK = 0x0000000000000fe0ul,
- IOST_PS_MASK = 0x000000000000000ful,
-
- IOST_PS_4K = 0x1,
- IOST_PS_64K = 0x3,
- IOST_PS_1M = 0x5,
- IOST_PS_16M = 0x7,
-
- /* iopt tag register */
- IOPT_VALID_MASK = 0x0000000200000000ul,
- IOPT_TAG_MASK = 0x00000001fffffffful,
-
- /* iopt cache register */
- IOPT_PROT_MASK = 0xc000000000000000ul,
- IOPT_PROT_NONE = 0x0000000000000000ul,
- IOPT_PROT_READ = 0x4000000000000000ul,
- IOPT_PROT_WRITE = 0x8000000000000000ul,
- IOPT_PROT_RW = 0xc000000000000000ul,
- IOPT_COHERENT = 0x2000000000000000ul,
-
- IOPT_ORDER_MASK = 0x1800000000000000ul,
- /* order access to same IOID/VC on same address */
- IOPT_ORDER_ADDR = 0x0800000000000000ul,
- /* similar, but only after a write access */
- IOPT_ORDER_WRITES = 0x1000000000000000ul,
- /* Order all accesses to same IOID/VC */
- IOPT_ORDER_VC = 0x1800000000000000ul,
-
- IOPT_RPN_MASK = 0x000003fffffff000ul,
- IOPT_HINT_MASK = 0x0000000000000800ul,
- IOPT_IOID_MASK = 0x00000000000007fful,
-
- IOSTO_ENABLE = 0x8000000000000000ul,
- IOSTO_ORIGIN = 0x000003fffffff000ul,
- IOSTO_HW = 0x0000000000000800ul,
- IOSTO_SW = 0x0000000000000400ul,
-
- IOCMD_CONF_TE = 0x0000800000000000ul,
-
- /* memory mapped registers */
- IOC_PT_CACHE_DIR = 0x000,
- IOC_ST_CACHE_DIR = 0x800,
- IOC_PT_CACHE_REG = 0x910,
- IOC_ST_ORIGIN = 0x918,
- IOC_CONF = 0x930,
-
- /* The high bit needs to be set on every DMA address when using
- * a spider bridge and only 2GB are addressable with the current
- * iommu code.
- */
- SPIDER_DMA_VALID = 0x80000000,
- CELL_DMA_MASK = 0x7fffffff,
-};
-
-
-void cell_init_iommu(void);
-
-#endif
Index: linux-cell/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/setup.c 2006-11-11 14:55:00.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/setup.c 2006-11-11 14:56:11.000000000 +1100
@@ -30,7 +30,6 @@
#include <linux/console.h>
#include <linux/mutex.h>
#include <linux/memory_hotplug.h>
-#include <linux/notifier.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -55,7 +54,6 @@
#include <asm/of_platform.h>
#include "interrupt.h"
-#include "iommu.h"
#include "cbe_regs.h"
#include "pervasive.h"
#include "ras.h"
@@ -83,38 +81,11 @@
printk("*** %04x : %s\n", hex, s ? s : "");
}
-static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
- void *data)
-{
- struct device *dev = data;
-
- if (action != BUS_NOTIFY_ADD_DEVICE)
- return 0;
-
- /* For now, we just use the PCI DMA ops for everything, though
- * we'll need something better when we have a real iommu
- * implementation.
- */
- dev->archdata.dma_ops = pci_dma_ops;
-
- return 0;
-}
-
-static struct notifier_block cell_of_bus_notifier = {
- .notifier_call = cell_of_bus_notify
-};
-
-
static int __init cell_publish_devices(void)
{
if (!machine_is(cell))
return 0;
- /* Register callbacks on OF platform device addition/removal
- * to handle linking them to the right DMA operations
- */
- register_bus_notifier(&of_platform_bus_type, &cell_of_bus_notifier);
-
/* Publish OF platform devices for southbridge IOs */
of_platform_bus_probe(NULL, NULL, NULL);
@@ -205,19 +176,6 @@
mmio_nvram_init();
}
-/*
- * Early initialization. Relocation is on but do not reference unbolted pages
- */
-static void __init cell_init_early(void)
-{
- DBG(" -> cell_init_early()\n");
-
- cell_init_iommu();
-
- DBG(" <- cell_init_early()\n");
-}
-
-
static int __init cell_probe(void)
{
unsigned long root = of_get_flat_dt_root();
@@ -244,7 +202,6 @@
.name = "Cell",
.probe = cell_probe,
.setup_arch = cell_setup_arch,
- .init_early = cell_init_early,
.show_cpuinfo = cell_show_cpuinfo,
.restart = rtas_restart,
.power_off = rtas_power_off,
Index: linux-cell/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-11-11 14:55:04.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-11-11 14:55:40.000000000 +1100
@@ -393,7 +393,8 @@
* setting up the hash table pointers. It also sets up some interrupt-mapping
* related options that will be used by finish_device_tree()
*/
- ppc_md.init_early();
+ if (ppc_md.init_early)
+ ppc_md.init_early();
/*
* We can discover serial ports now since the above did setup the
Index: linux-cell/arch/powerpc/kernel/prom_init.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/prom_init.c 2006-10-21 16:36:50.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/prom_init.c 2006-11-11 14:55:40.000000000 +1100
@@ -173,8 +173,8 @@
static unsigned long __initdata prom_initrd_start, prom_initrd_end;
#ifdef CONFIG_PPC64
-static int __initdata iommu_force_on;
-static int __initdata ppc64_iommu_off;
+static int __initdata prom_iommu_force_on;
+static int __initdata prom_iommu_off;
static unsigned long __initdata prom_tce_alloc_start;
static unsigned long __initdata prom_tce_alloc_end;
#endif
@@ -582,9 +582,9 @@
while (*opt && *opt == ' ')
opt++;
if (!strncmp(opt, RELOC("off"), 3))
- RELOC(ppc64_iommu_off) = 1;
+ RELOC(prom_iommu_off) = 1;
else if (!strncmp(opt, RELOC("force"), 5))
- RELOC(iommu_force_on) = 1;
+ RELOC(prom_iommu_force_on) = 1;
}
#endif
}
@@ -1167,7 +1167,7 @@
u64 local_alloc_top, local_alloc_bottom;
u64 i;
- if (RELOC(ppc64_iommu_off))
+ if (RELOC(prom_iommu_off))
return;
prom_debug("starting prom_initialize_tce_table\n");
@@ -2283,11 +2283,11 @@
* Fill in some infos for use by the kernel later on
*/
#ifdef CONFIG_PPC64
- if (RELOC(ppc64_iommu_off))
+ if (RELOC(prom_iommu_off))
prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
NULL, 0);
- if (RELOC(iommu_force_on))
+ if (RELOC(prom_iommu_force_on))
prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
NULL, 0);
Index: linux-cell/arch/powerpc/sysdev/dart_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/dart_iommu.c 2006-11-11 14:44:58.000000000 +1100
+++ linux-cell/arch/powerpc/sysdev/dart_iommu.c 2006-11-11 14:55:40.000000000 +1100
@@ -48,9 +48,6 @@
#include "dart.h"
-extern int iommu_is_off;
-extern int iommu_force_on;
-
/* Physical base address and size of the DART table */
unsigned long dart_tablebase; /* exported to htab_initialize */
static unsigned long dart_tablesize;
Index: linux-cell/include/asm-powerpc/iommu.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/iommu.h 2006-11-11 14:44:58.000000000 +1100
+++ linux-cell/include/asm-powerpc/iommu.h 2006-11-11 14:55:40.000000000 +1100
@@ -34,7 +34,9 @@
#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1))
#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
-#ifndef __ASSEMBLY__
+/* Boot time flags */
+extern int iommu_is_off;
+extern int iommu_force_on;
/* Pure 2^n version of get_order */
static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
@@ -42,8 +44,6 @@
return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
}
-#endif /* __ASSEMBLY__ */
-
/*
* IOMAP_MAX_ORDER defines the largest contiguous block
^ permalink raw reply
* [PATCH 30/32] powerpc: remove ioremap64 and fixup_bigphys_addr
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
In order to suppose platforms with devices above 4Gb on 32 bits platforms
with a >32 bits physical address space, we used to have a special ioremap64
along with a fixup routine fixup_bigphys_addr.
This shouldn't be necessary anymore as struct resource now supports 64 bits
addresses even on 32 bits archs. This patch enables that option when
CONFIG_PHYS_64BIT is set and removes ioremap64 and fixup_bigphys_addr.
This is a preliminary work for the upcoming merge of 32 and 64 bits io.h
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/Kconfig | 1 +
arch/powerpc/mm/pgtable_32.c | 17 -----------------
arch/powerpc/platforms/85xx/misc.c | 8 --------
3 files changed, 1 insertion(+), 25 deletions(-)
Index: linux-cell/arch/powerpc/mm/pgtable_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_32.c 2006-11-06 15:18:35.000000000 +1100
+++ linux-cell/arch/powerpc/mm/pgtable_32.c 2006-11-06 15:55:37.000000000 +1100
@@ -141,28 +141,11 @@ void pte_free(struct page *ptepage)
__free_page(ptepage);
}
-#ifndef CONFIG_PHYS_64BIT
void __iomem *
ioremap(phys_addr_t addr, unsigned long size)
{
return __ioremap(addr, size, _PAGE_NO_CACHE);
}
-#else /* CONFIG_PHYS_64BIT */
-void __iomem *
-ioremap64(unsigned long long addr, unsigned long size)
-{
- return __ioremap(addr, size, _PAGE_NO_CACHE);
-}
-EXPORT_SYMBOL(ioremap64);
-
-void __iomem *
-ioremap(phys_addr_t addr, unsigned long size)
-{
- phys_addr_t addr64 = fixup_bigphys_addr(addr, size);
-
- return ioremap64(addr64, size);
-}
-#endif /* CONFIG_PHYS_64BIT */
EXPORT_SYMBOL(ioremap);
void __iomem *
Index: linux-cell/arch/powerpc/platforms/85xx/misc.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/85xx/misc.c 2006-11-06 15:18:35.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/85xx/misc.c 2006-11-06 15:55:37.000000000 +1100
@@ -21,11 +21,3 @@ void mpc85xx_restart(char *cmd)
local_irq_disable();
abort();
}
-
-/* For now this is a pass through */
-phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
-{
- return addr;
-};
-
-EXPORT_SYMBOL(fixup_bigphys_addr);
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig 2006-11-06 15:55:34.000000000 +1100
+++ linux-cell/arch/powerpc/Kconfig 2006-11-06 15:55:37.000000000 +1100
@@ -247,6 +247,7 @@ config PTE_64BIT
config PHYS_64BIT
bool 'Large physical address support' if E500
depends on 44x || E500
+ select RESOURCES_64BIT
default y if 44x
---help---
This option enables kernel support for larger than 32-bit physical
^ permalink raw reply
* [PATCH 31/32] powerpc: Merge 32 and 64 bits asm-powerpc/io.h
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
The rework on io.h done for the new hookable accessors made it easier,
so I just finished the work and merged 32 and 64 bits io.h for arch/powerpc.
arch/ppc still uses the old version in asm-ppc, there is just too much gunk
in there that I really can't be bothered trying to cleanup.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/Makefile | 2
arch/powerpc/kernel/io.c | 87 +++++++++
arch/powerpc/kernel/iomap.c | 2
arch/powerpc/kernel/pci_32.c | 34 ---
arch/powerpc/kernel/rtas_pci.c | 1
arch/powerpc/kernel/traps.c | 8
arch/powerpc/mm/pgtable_32.c | 22 --
arch/powerpc/mm/pgtable_64.c | 16 -
arch/powerpc/platforms/chrp/setup.c | 1
arch/powerpc/platforms/iseries/setup.c | 4
arch/powerpc/platforms/powermac/setup.c | 2
include/asm-powerpc/eeh.h | 95 ----------
include/asm-powerpc/ide.h | 7
include/asm-powerpc/io-defs.h | 9 -
include/asm-powerpc/io.h | 284 +++++++++++++++++++++++++++-----
include/asm-powerpc/machdep.h | 4
16 files changed, 366 insertions(+), 212 deletions(-)
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/Makefile 2006-11-07 17:40:29.000000000 +1100
@@ -73,7 +73,7 @@ obj-$(CONFIG_AUDIT) += audit.o
obj64-$(CONFIG_AUDIT) += compat_audit.o
ifneq ($(CONFIG_PPC_INDIRECT_IO),y)
-pci64-$(CONFIG_PPC64) += iomap.o
+obj-y += iomap.o
endif
ifeq ($(CONFIG_PPC_ISERIES),y)
Index: linux-cell/arch/powerpc/kernel/io.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/io.c 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/io.c 2006-11-07 17:40:29.000000000 +1100
@@ -117,3 +117,90 @@ void _outsl_ns(volatile u32 __iomem *por
asm volatile("sync");
}
EXPORT_SYMBOL(_outsl_ns);
+
+#define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0)
+
+void _memset_io(volatile void __iomem *addr, int c, unsigned long n)
+{
+ void *p = (void __force *)addr;
+ u32 lc = c;
+ lc |= lc << 8;
+ lc |= lc << 16;
+
+ __asm__ __volatile__ ("sync" : : : "memory");
+ while(n && !IO_CHECK_ALIGN(p, 4)) {
+ *((volatile u8 *)p) = c;
+ p++;
+ n--;
+ }
+ while(n >= 4) {
+ *((volatile u32 *)p) = lc;
+ p += 4;
+ n -= 4;
+ }
+ while(n) {
+ *((volatile u8 *)p) = c;
+ p++;
+ n--;
+ }
+ __asm__ __volatile__ ("sync" : : : "memory");
+}
+EXPORT_SYMBOL(_memset_io);
+
+void _memcpy_fromio(void *dest, const volatile void __iomem *src,
+ unsigned long n)
+{
+ void *vsrc = (void __force *) src;
+
+ __asm__ __volatile__ ("sync" : : : "memory");
+ while(n && (!IO_CHECK_ALIGN(vsrc, 4) || !IO_CHECK_ALIGN(dest, 4))) {
+ *((u8 *)dest) = *((volatile u8 *)vsrc);
+ __asm__ __volatile__ ("eieio" : : : "memory");
+ vsrc++;
+ dest++;
+ n--;
+ }
+ while(n > 4) {
+ *((u32 *)dest) = *((volatile u32 *)vsrc);
+ __asm__ __volatile__ ("eieio" : : : "memory");
+ vsrc += 4;
+ dest += 4;
+ n -= 4;
+ }
+ while(n) {
+ *((u8 *)dest) = *((volatile u8 *)vsrc);
+ __asm__ __volatile__ ("eieio" : : : "memory");
+ vsrc++;
+ dest++;
+ n--;
+ }
+ __asm__ __volatile__ ("sync" : : : "memory");
+}
+EXPORT_SYMBOL(_memcpy_fromio);
+
+void _memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n)
+{
+ void *vdest = (void __force *) dest;
+
+ __asm__ __volatile__ ("sync" : : : "memory");
+ while(n && (!IO_CHECK_ALIGN(vdest, 4) || !IO_CHECK_ALIGN(src, 4))) {
+ *((volatile u8 *)vdest) = *((u8 *)src);
+ src++;
+ vdest++;
+ n--;
+ }
+ while(n > 4) {
+ *((volatile u32 *)vdest) = *((volatile u32 *)src);
+ src += 4;
+ vdest += 4;
+ n-=4;
+ }
+ while(n) {
+ *((volatile u8 *)vdest) = *((u8 *)src);
+ src++;
+ vdest++;
+ n--;
+ }
+ __asm__ __volatile__ ("sync" : : : "memory");
+}
+EXPORT_SYMBOL(_memcpy_toio);
Index: linux-cell/include/asm-powerpc/eeh.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/eeh.h 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/eeh.h 2006-11-07 17:40:29.000000000 +1100
@@ -169,104 +169,19 @@ static inline u64 eeh_readq_be(const vol
return val;
}
-#define EEH_CHECK_ALIGN(v,a) \
- ((((unsigned long)(v)) & ((a) - 1)) == 0)
-
-static inline void eeh_memset_io(volatile void __iomem *addr, int c,
- unsigned long n)
-{
- void *p = (void __force *)addr;
- u32 lc = c;
- lc |= lc << 8;
- lc |= lc << 16;
-
- __asm__ __volatile__ ("sync" : : : "memory");
- while(n && !EEH_CHECK_ALIGN(p, 4)) {
- *((volatile u8 *)p) = c;
- p++;
- n--;
- }
- while(n >= 4) {
- *((volatile u32 *)p) = lc;
- p += 4;
- n -= 4;
- }
- while(n) {
- *((volatile u8 *)p) = c;
- p++;
- n--;
- }
- __asm__ __volatile__ ("sync" : : : "memory");
-}
-static inline void eeh_memcpy_fromio(void *dest, const volatile void __iomem *src,
+static inline void eeh_memcpy_fromio(void *dest, const
+ volatile void __iomem *src,
unsigned long n)
{
- void *vsrc = (void __force *) src;
- void *destsave = dest;
- unsigned long nsave = n;
-
- __asm__ __volatile__ ("sync" : : : "memory");
- while(n && (!EEH_CHECK_ALIGN(vsrc, 4) || !EEH_CHECK_ALIGN(dest, 4))) {
- *((u8 *)dest) = *((volatile u8 *)vsrc);
- __asm__ __volatile__ ("eieio" : : : "memory");
- vsrc++;
- dest++;
- n--;
- }
- while(n > 4) {
- *((u32 *)dest) = *((volatile u32 *)vsrc);
- __asm__ __volatile__ ("eieio" : : : "memory");
- vsrc += 4;
- dest += 4;
- n -= 4;
- }
- while(n) {
- *((u8 *)dest) = *((volatile u8 *)vsrc);
- __asm__ __volatile__ ("eieio" : : : "memory");
- vsrc++;
- dest++;
- n--;
- }
- __asm__ __volatile__ ("sync" : : : "memory");
+ _memcpy_fromio(dest, src, n);
/* Look for ffff's here at dest[n]. Assume that at least 4 bytes
* were copied. Check all four bytes.
*/
- if ((nsave >= 4) &&
- (EEH_POSSIBLE_ERROR((*((u32 *) destsave+nsave-4)), u32))) {
- eeh_check_failure(src, (*((u32 *) destsave+nsave-4)));
- }
-}
-
-static inline void eeh_memcpy_toio(volatile void __iomem *dest, const void *src,
- unsigned long n)
-{
- void *vdest = (void __force *) dest;
-
- __asm__ __volatile__ ("sync" : : : "memory");
- while(n && (!EEH_CHECK_ALIGN(vdest, 4) || !EEH_CHECK_ALIGN(src, 4))) {
- *((volatile u8 *)vdest) = *((u8 *)src);
- src++;
- vdest++;
- n--;
- }
- while(n > 4) {
- *((volatile u32 *)vdest) = *((volatile u32 *)src);
- src += 4;
- vdest += 4;
- n-=4;
- }
- while(n) {
- *((volatile u8 *)vdest) = *((u8 *)src);
- src++;
- vdest++;
- n--;
- }
- __asm__ __volatile__ ("sync" : : : "memory");
+ if (n >= 4 && EEH_POSSIBLE_ERROR(*((u32 *)(dest + n - 4)), u32))
+ eeh_check_failure(src, *((u32 *)(dest + n - 4)));
}
-#undef EEH_CHECK_ALIGN
-
/* in-string eeh macros */
static inline void eeh_readsb(const volatile void __iomem *addr, void * buf,
int ns)
Index: linux-cell/include/asm-powerpc/io-defs.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io-defs.h 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/io-defs.h 2006-11-07 17:40:29.000000000 +1100
@@ -3,17 +3,20 @@
DEF_PCI_AC_RET(readb, u8, (const PCI_IO_ADDR addr), (addr))
DEF_PCI_AC_RET(readw, u16, (const PCI_IO_ADDR addr), (addr))
DEF_PCI_AC_RET(readl, u32, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr))
DEF_PCI_AC_RET(readw_be, u16, (const PCI_IO_ADDR addr), (addr))
DEF_PCI_AC_RET(readl_be, u32, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr))
DEF_PCI_AC_NORET(writeb, (u8 val, PCI_IO_ADDR addr), (val, addr))
DEF_PCI_AC_NORET(writew, (u16 val, PCI_IO_ADDR addr), (val, addr))
DEF_PCI_AC_NORET(writel, (u32 val, PCI_IO_ADDR addr), (val, addr))
-DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr))
DEF_PCI_AC_NORET(writew_be, (u16 val, PCI_IO_ADDR addr), (val, addr))
DEF_PCI_AC_NORET(writel_be, (u32 val, PCI_IO_ADDR addr), (val, addr))
+
+#ifdef __powerpc64__
+DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr))
+DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr))
DEF_PCI_AC_NORET(writeq_be, (u64 val, PCI_IO_ADDR addr), (val, addr))
+#endif /* __powerpc64__ */
DEF_PCI_AC_RET(inb, u8, (unsigned long port), (port))
DEF_PCI_AC_RET(inw, u16, (unsigned long port), (port))
Index: linux-cell/include/asm-powerpc/io.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io.h 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/io.h 2006-11-07 17:40:29.000000000 +1100
@@ -13,24 +13,51 @@
extern int check_legacy_ioport(unsigned long base_port);
#define PNPBIOS_BASE 0xf000 /* only relevant for PReP */
-#ifndef CONFIG_PPC64
-#include <asm-ppc/io.h>
-#else
-
#include <linux/compiler.h>
#include <asm/page.h>
#include <asm/byteorder.h>
-#include <asm/paca.h>
#include <asm/synch.h>
#include <asm/delay.h>
+#include <asm/mmu.h>
#include <asm-generic/iomap.h>
+#ifdef CONFIG_PPC64
+#include <asm/paca.h>
+#endif
+
#define SIO_CONFIG_RA 0x398
#define SIO_CONFIG_RD 0x399
#define SLOW_DOWN_IO
+/* 32 bits uses slightly different variables for the various IO
+ * bases. Most of this file only uses _IO_BASE though which we
+ * define properly based on the platform
+ */
+#ifdef CONFIG_PCI
+#define _IO_BASE 0
+#define _ISA_MEM_BASE 0
+#define PCI_DRAM_OFFSET 0
+#elif defined(CONFIG_PPC32)
+#define _IO_BASE isa_io_base
+#define _ISA_MEM_BASE isa_mem_base
+#define PCI_DRAM_OFFSET pci_dram_offset
+#else
+#define _IO_BASE pci_io_base
+#define _ISA_MEM_BASE 0
+#define PCI_DRAM_OFFSET 0
+#endif
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_io_base;
+extern unsigned long pci_dram_offset;
+
+#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_INDIRECT_IO)
+#error CONFIG_PPC_INDIRECT_IO is not yet support on 32 bits
+#endif
+
/*
*
* Low level MMIO accessors
@@ -53,7 +80,11 @@ extern int check_legacy_ioport(unsigned
*
*/
+#ifdef CONFIG_PPC64
#define IO_SET_SYNC_FLAG() do { get_paca()->io_sync = 1; } while(0)
+#else
+#define IO_SET_SYNC_FLAG()
+#endif
#define DEF_MMIO_IN(name, type, insn) \
static inline type name(const volatile type __iomem *addr) \
@@ -86,17 +117,19 @@ static inline void name(volatile type __
DEF_MMIO_IN_BE(in_8, 8, lbz);
DEF_MMIO_IN_BE(in_be16, 16, lhz);
DEF_MMIO_IN_BE(in_be32, 32, lwz);
-DEF_MMIO_IN_BE(in_be64, 64, ld);
DEF_MMIO_IN_LE(in_le16, 16, lhbrx);
DEF_MMIO_IN_LE(in_le32, 32, lwbrx);
DEF_MMIO_OUT_BE(out_8, 8, stb);
DEF_MMIO_OUT_BE(out_be16, 16, sth);
DEF_MMIO_OUT_BE(out_be32, 32, stw);
-DEF_MMIO_OUT_BE(out_be64, 64, std);
DEF_MMIO_OUT_LE(out_le16, 16, sthbrx);
DEF_MMIO_OUT_LE(out_le32, 32, stwbrx);
+#ifdef __powerpc64__
+DEF_MMIO_OUT_BE(out_be64, 64, std);
+DEF_MMIO_IN_BE(in_be64, 64, ld);
+
/* There is no asm instructions for 64 bits reverse loads and stores */
static inline u64 in_le64(const volatile u64 __iomem *addr)
{
@@ -107,6 +140,7 @@ static inline void out_le64(volatile u64
{
out_be64(addr, cpu_to_le64(val));
}
+#endif /* __powerpc64__ */
/*
* Low level IO stream instructions are defined out of line for now
@@ -126,6 +160,17 @@ extern void _outsl_ns(volatile u32 __iom
#define _outsw _outsw_ns
#define _outsl _outsl_ns
+
+/*
+ * memset_io, memcpy_toio, memcpy_fromio base implementations are out of line
+ */
+
+extern void _memset_io(volatile void __iomem *addr, int c, unsigned long n);
+extern void _memcpy_fromio(void *dest, const volatile void __iomem *src,
+ unsigned long n);
+extern void _memcpy_toio(volatile void __iomem *dest, const void *src,
+ unsigned long n);
+
/*
*
* PCI and standard ISA accessors
@@ -140,9 +185,6 @@ extern void _outsl_ns(volatile u32 __iom
* of the accessors.
*/
-extern unsigned long isa_io_base;
-extern unsigned long pci_io_base;
-
/*
* Non ordered and non-swapping "raw" accessors
@@ -160,10 +202,6 @@ static inline unsigned int __raw_readl(c
{
return *(volatile unsigned int __force *)addr;
}
-static inline unsigned long __raw_readq(const volatile void __iomem *addr)
-{
- return *(volatile unsigned long __force *)addr;
-}
static inline void __raw_writeb(unsigned char v, volatile void __iomem *addr)
{
*(volatile unsigned char __force *)addr = v;
@@ -176,11 +214,17 @@ static inline void __raw_writel(unsigned
{
*(volatile unsigned int __force *)addr = v;
}
+
+#ifdef __powerpc64__
+static inline unsigned long __raw_readq(const volatile void __iomem *addr)
+{
+ return *(volatile unsigned long __force *)addr;
+}
static inline void __raw_writeq(unsigned long v, volatile void __iomem *addr)
{
*(volatile unsigned long __force *)addr = v;
}
-
+#endif /* __powerpc64__ */
/*
*
@@ -188,7 +232,13 @@ static inline void __raw_writeq(unsigned
*
*/
+/*
+ * Include the EEH definitions when EEH is enabled only so they don't get
+ * in the way when building for 32 bits
+ */
+#ifdef CONFIG_EEH
#include <asm/eeh.h>
+#endif
/* Shortcut to the MMIO argument pointer */
#define PCI_IO_ADDR volatile void __iomem *
@@ -196,7 +246,7 @@ static inline void __raw_writeq(unsigned
/* Indirect IO address tokens:
*
* When CONFIG_PPC_INDIRECT_IO is set, the platform can provide hooks
- * on all IOs.
+ * on all IOs. (Note that this is all 64 bits only for now)
*
* To help platforms who may need to differenciate MMIO addresses in
* their hooks, a bitfield is reserved for use by the platform near the
@@ -241,6 +291,70 @@ do { \
#define PCI_FIX_ADDR(addr) (addr)
#endif
+/*
+ * On 32 bits, PIO operations have a recovery mechanism in case they trigger
+ * machine checks (which they occasionally do when probing non existing
+ * IO ports on some platforms, like PowerMac and 8xx).
+ * I always found it to be of dubious reliability and I am tempted to get
+ * rid of it one of these days. So if you think it's important to keep it,
+ * please voice up asap. We never had it for 64 bits and I do not intend
+ * to port it over
+ */
+
+#ifdef CONFIG_PPC32
+
+#define __do_in_asm(name, op) \
+extern __inline__ unsigned int name(unsigned int port) \
+{ \
+ unsigned int x; \
+ __asm__ __volatile__( \
+ "sync\n" \
+ "0:" op " %0,0,%1\n" \
+ "1: twi 0,%0,0\n" \
+ "2: isync\n" \
+ "3: nop\n" \
+ "4:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "5: li %0,-1\n" \
+ " b 4b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 0b,5b\n" \
+ " .long 1b,5b\n" \
+ " .long 2b,5b\n" \
+ " .long 3b,5b\n" \
+ ".previous" \
+ : "=&r" (x) \
+ : "r" (port + _IO_BASE)); \
+ return x; \
+}
+
+#define __do_out_asm(name, op) \
+extern __inline__ void name(unsigned int val, unsigned int port) \
+{ \
+ __asm__ __volatile__( \
+ "sync\n" \
+ "0:" op " %0,0,%1\n" \
+ "1: sync\n" \
+ "2:\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 0b,2b\n" \
+ " .long 1b,2b\n" \
+ ".previous" \
+ : : "r" (val), "r" (port + _IO_BASE)); \
+}
+
+__do_in_asm(_rec_inb, "lbzx")
+__do_in_asm(_rec_inw, "lhbrx")
+__do_in_asm(_rec_inl, "lwbrx")
+__do_out_asm(_rec_outb, "stbx")
+__do_out_asm(_rec_outw, "sthbrx")
+__do_out_asm(_rec_outl, "stwbrx")
+
+#endif /* CONFIG_PPC32 */
+
/* The "__do_*" operations below provide the actual "base" implementation
* for each of the defined acccessor. Some of them use the out_* functions
* directly, some of them still use EEH, though we might change that in the
@@ -263,6 +377,8 @@ do { \
#define __do_writew_be(val, addr) out_be16(PCI_FIX_ADDR(addr), val)
#define __do_writel_be(val, addr) out_be32(PCI_FIX_ADDR(addr), val)
#define __do_writeq_be(val, addr) out_be64(PCI_FIX_ADDR(addr), val)
+
+#ifdef CONFIG_EEH
#define __do_readb(addr) eeh_readb(PCI_FIX_ADDR(addr))
#define __do_readw(addr) eeh_readw(PCI_FIX_ADDR(addr))
#define __do_readl(addr) eeh_readl(PCI_FIX_ADDR(addr))
@@ -270,33 +386,64 @@ do { \
#define __do_readw_be(addr) eeh_readw_be(PCI_FIX_ADDR(addr))
#define __do_readl_be(addr) eeh_readl_be(PCI_FIX_ADDR(addr))
#define __do_readq_be(addr) eeh_readq_be(PCI_FIX_ADDR(addr))
+#else /* CONFIG_EEH */
+#define __do_readb(addr) in_8(PCI_FIX_ADDR(addr))
+#define __do_readw(addr) in_le16(PCI_FIX_ADDR(addr))
+#define __do_readl(addr) in_le32(PCI_FIX_ADDR(addr))
+#define __do_readq(addr) in_le64(PCI_FIX_ADDR(addr))
+#define __do_readw_be(addr) in_be16(PCI_FIX_ADDR(addr))
+#define __do_readl_be(addr) in_be32(PCI_FIX_ADDR(addr))
+#define __do_readq_be(addr) in_be64(PCI_FIX_ADDR(addr))
+#endif /* !defined(CONFIG_EEH) */
+
+#ifdef CONFIG_PPC32
+#define __do_outb(val, port) _rec_outb(val, port)
+#define __do_outw(val, port) _rec_outw(val, port)
+#define __do_outl(val, port) _rec_outl(val, port)
+#define __do_inb(port) _rec_inb(port)
+#define __do_inw(port) _rec_inw(port)
+#define __do_inl(port) _rec_inl(port)
+#else /* CONFIG_PPC32 */
+#define __do_outb(val, port) writeb(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_outw(val, port) writew(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_outl(val, port) writel(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_inb(port) readb((PCI_IO_ADDR)_IO_BASE + port);
+#define __do_inw(port) readw((PCI_IO_ADDR)_IO_BASE + port);
+#define __do_inl(port) readl((PCI_IO_ADDR)_IO_BASE + port);
+#endif /* !CONFIG_PPC32 */
-#define __do_outb(val, port) writeb(val,(PCI_IO_ADDR)pci_io_base+port);
-#define __do_outw(val, port) writew(val,(PCI_IO_ADDR)pci_io_base+port);
-#define __do_outl(val, port) writel(val,(PCI_IO_ADDR)pci_io_base+port);
-#define __do_inb(port) readb((PCI_IO_ADDR)pci_io_base + port);
-#define __do_inw(port) readw((PCI_IO_ADDR)pci_io_base + port);
-#define __do_inl(port) readl((PCI_IO_ADDR)pci_io_base + port);
-
+#ifdef CONFIG_EEH
#define __do_readsb(a, b, n) eeh_readsb(PCI_FIX_ADDR(a), (b), (n))
#define __do_readsw(a, b, n) eeh_readsw(PCI_FIX_ADDR(a), (b), (n))
#define __do_readsl(a, b, n) eeh_readsl(PCI_FIX_ADDR(a), (b), (n))
+#else /* CONFIG_EEH */
+#define __do_readsb(a, b, n) _insb(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsw(a, b, n) _insw(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsl(a, b, n) _insl(PCI_FIX_ADDR(a), (b), (n))
+#endif /* !CONFIG_EEH */
#define __do_writesb(a, b, n) _outsb(PCI_FIX_ADDR(a),(b),(n))
#define __do_writesw(a, b, n) _outsw(PCI_FIX_ADDR(a),(b),(n))
#define __do_writesl(a, b, n) _outsl(PCI_FIX_ADDR(a),(b),(n))
-#define __do_insb(p, b, n) readsb((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
-#define __do_insw(p, b, n) readsw((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
-#define __do_insl(p, b, n) readsl((PCI_IO_ADDR)pci_io_base+(p), (b), (n))
-#define __do_outsb(p, b, n) writesb((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
-#define __do_outsw(p, b, n) writesw((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
-#define __do_outsl(p, b, n) writesl((PCI_IO_ADDR)pci_io_base+(p),(b),(n))
-
-#define __do_memset_io(addr, c, n) eeh_memset_io(PCI_FIX_ADDR(addr), c, n)
-#define __do_memcpy_fromio(dst, src, n) eeh_memcpy_fromio(dst, \
- PCI_FIX_ADDR(src), n)
-#define __do_memcpy_toio(dst, src, n) eeh_memcpy_toio(PCI_FIX_ADDR(dst), \
- src, n)
+#define __do_insb(p, b, n) readsb((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_insw(p, b, n) readsw((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_insl(p, b, n) readsl((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_outsb(p, b, n) writesb((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+#define __do_outsw(p, b, n) writesw((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+#define __do_outsl(p, b, n) writesl((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+
+#define __do_memset_io(addr, c, n) \
+ _memset_io(PCI_FIX_ADDR(addr), c, n)
+#define __do_memcpy_toio(dst, src, n) \
+ _memcpy_toio(PCI_FIX_ADDR(dst), src, n)
+
+#ifdef CONFIG_EEH
+#define __do_memcpy_fromio(dst, src, n) \
+ eeh_memcpy_fromio(dst, PCI_FIX_ADDR(src), n)
+#else /* CONFIG_EEH */
+#define __do_memcpy_fromio(dst, src, n) \
+ _memcpy_fromio(dst,PCI_FIX_ADDR(src),n)
+#endif /* !CONFIG_EEH */
#ifdef CONFIG_PPC_INDIRECT_IO
#define DEF_PCI_HOOK(x) x
@@ -343,15 +490,27 @@ static inline void name at \
/* Some drivers check for the presence of readq & writeq with
* a #ifdef, so we make them happy here.
*/
+#ifdef __powerpc64__
#define readq readq
#define writeq writeq
+#endif
-/* Nothing to do for cache stuff x*/
+#ifdef CONFIG_NOT_COHERENT_CACHE
+
+#define dma_cache_inv(_start,_size) \
+ invalidate_dcache_range(_start, (_start + _size))
+#define dma_cache_wback(_start,_size) \
+ clean_dcache_range(_start, (_start + _size))
+#define dma_cache_wback_inv(_start,_size) \
+ flush_dcache_range(_start, (_start + _size))
+
+#else /* CONFIG_NOT_COHERENT_CACHE */
#define dma_cache_inv(_start,_size) do { } while (0)
#define dma_cache_wback(_start,_size) do { } while (0)
#define dma_cache_wback_inv(_start,_size) do { } while (0)
+#endif /* !CONFIG_NOT_COHERENT_CACHE */
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
@@ -372,6 +531,9 @@ static inline void name at \
#define readl_relaxed(addr) readl(addr)
#define readq_relaxed(addr) readq(addr)
+#ifdef CONFIG_PPC32
+#define mmiowb()
+#else
/*
* Enforce synchronisation of stores vs. spin_unlock
* (this does it explicitely, though our implementation of spin_unlock
@@ -385,6 +547,7 @@ static inline void mmiowb(void)
: "=&r" (tmp) : "i" (offsetof(struct paca_struct, io_sync))
: "memory");
}
+#endif /* !CONFIG_PPC32 */
static inline void iosync(void)
{
@@ -453,22 +616,29 @@ static inline void iosync(void)
* be hooked (but can be used by a hook on iounmap)
*
*/
-extern void __iomem *ioremap(unsigned long address, unsigned long size);
-extern void __iomem *ioremap_flags(unsigned long address, unsigned long size,
+extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
+extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size,
unsigned long flags);
#define ioremap_nocache(addr, size) ioremap((addr), (size))
-extern void iounmap(void __iomem *addr);
+extern void iounmap(volatile void __iomem *addr);
-extern void __iomem *__ioremap(unsigned long address, unsigned long size,
+extern void __iomem *__ioremap(phys_addr_t, unsigned long size,
unsigned long flags);
-extern void __iounmap(void __iomem *addr);
+extern void __iounmap(volatile void __iomem *addr);
-extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
+extern int __ioremap_explicit(phys_addr_t p_addr, unsigned long v_addr,
unsigned long size, unsigned long flags);
-extern int __iounmap_explicit(void __iomem *start, unsigned long size);
+extern int __iounmap_explicit(volatile void __iomem *start,
+ unsigned long size);
extern void __iomem * reserve_phb_iospace(unsigned long size);
+/* Those are more 32 bits only functions */
+extern unsigned long iopa(unsigned long addr);
+extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
+extern void io_block_mapping(unsigned long virt, phys_addr_t phys,
+ unsigned int size, int flags);
+
/*
* When CONFIG_PPC_INDIRECT_IO is set, we use the generic iomap implementation
@@ -538,7 +708,33 @@ static inline void * phys_to_virt(unsign
*/
#define BIO_VMERGE_BOUNDARY 0
+/*
+ * 32 bits still uses virt_to_bus() for it's implementation of DMA
+ * mappings se we have to keep it defined here. We also have some old
+ * drivers (shame shame shame) that use bus_to_virt() and haven't been
+ * fixed yet so I need to define it here.
+ */
+#ifdef CONFIG_PPC32
+
+static inline unsigned long virt_to_bus(volatile void * address)
+{
+ if (address == NULL)
+ return 0;
+ return __pa(address) + PCI_DRAM_OFFSET;
+}
+
+static inline void * bus_to_virt(unsigned long address)
+{
+ if (address == 0)
+ return NULL;
+ return __va(address - PCI_DRAM_OFFSET);
+}
+
+#define page_to_bus(page) (page_to_phys(page) + PCI_DRAM_OFFSET)
+
+#endif /* CONFIG_PPC32 */
+
+
#endif /* __KERNEL__ */
-#endif /* CONFIG_PPC64 */
#endif /* _ASM_POWERPC_IO_H */
Index: linux-cell/arch/powerpc/kernel/traps.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/traps.c 2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/traps.c 2006-11-07 17:40:29.000000000 +1100
@@ -53,10 +53,6 @@
#endif
#include <asm/kexec.h>
-#ifdef CONFIG_PPC64 /* XXX */
-#define _IO_BASE pci_io_base
-#endif
-
#ifdef CONFIG_DEBUGGER
int (*__debugger)(struct pt_regs *regs);
int (*__debugger_ipi)(struct pt_regs *regs);
@@ -241,7 +237,7 @@ void system_reset_exception(struct pt_re
*/
static inline int check_io_access(struct pt_regs *regs)
{
-#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
+#ifdef CONFIG_PPC32
unsigned long msr = regs->msr;
const struct exception_table_entry *entry;
unsigned int *nip = (unsigned int *)regs->nip;
@@ -274,7 +270,7 @@ static inline int check_io_access(struct
return 1;
}
}
-#endif /* CONFIG_PPC_PMAC && CONFIG_PPC32 */
+#endif /* CONFIG_PPC32 */
return 0;
}
Index: linux-cell/arch/powerpc/kernel/rtas_pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/rtas_pci.c 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/rtas_pci.c 2006-11-07 17:40:29.000000000 +1100
@@ -38,6 +38,7 @@
#include <asm/rtas.h>
#include <asm/mpic.h>
#include <asm/ppc-pci.h>
+#include <asm/eeh.h>
/* RTAS tokens */
static int read_pci_config;
Index: linux-cell/arch/powerpc/platforms/chrp/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/chrp/setup.c 2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/chrp/setup.c 2006-11-07 17:40:29.000000000 +1100
@@ -588,7 +588,6 @@ static int __init chrp_probe(void)
ISA_DMA_THRESHOLD = ~0L;
DMA_MODE_READ = 0x44;
DMA_MODE_WRITE = 0x48;
- isa_io_base = CHRP_ISA_IO_BASE; /* default value */
return 1;
}
Index: linux-cell/arch/powerpc/platforms/powermac/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/setup.c 2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/powermac/setup.c 2006-11-07 17:40:29.000000000 +1100
@@ -677,8 +677,6 @@ static int __init pmac_probe(void)
#ifdef CONFIG_PPC32
/* isa_io_base gets set in pmac_pci_init */
- isa_mem_base = PMAC_ISA_MEM_BASE;
- pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
ISA_DMA_THRESHOLD = ~0L;
DMA_MODE_READ = 1;
DMA_MODE_WRITE = 2;
Index: linux-cell/arch/powerpc/mm/pgtable_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_32.c 2006-11-07 17:40:28.000000000 +1100
+++ linux-cell/arch/powerpc/mm/pgtable_32.c 2006-11-07 17:40:29.000000000 +1100
@@ -149,6 +149,13 @@ ioremap(phys_addr_t addr, unsigned long
EXPORT_SYMBOL(ioremap);
void __iomem *
+ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
+{
+ return __ioremap(addr, size, flags);
+}
+EXPORT_SYMBOL(ioremap_flags);
+
+void __iomem *
__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
{
unsigned long v, i;
@@ -247,20 +254,7 @@ void iounmap(volatile void __iomem *addr
}
EXPORT_SYMBOL(iounmap);
-void __iomem *ioport_map(unsigned long port, unsigned int len)
-{
- return (void __iomem *) (port + _IO_BASE);
-}
-
-void ioport_unmap(void __iomem *addr)
-{
- /* Nothing to do */
-}
-EXPORT_SYMBOL(ioport_map);
-EXPORT_SYMBOL(ioport_unmap);
-
-int
-map_page(unsigned long va, phys_addr_t pa, int flags)
+int map_page(unsigned long va, phys_addr_t pa, int flags)
{
pmd_t *pd;
pte_t *pg;
Index: linux-cell/arch/powerpc/mm/pgtable_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_64.c 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/mm/pgtable_64.c 2006-11-07 17:40:29.000000000 +1100
@@ -113,7 +113,7 @@ static int map_io_page(unsigned long ea,
}
-static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa,
+static void __iomem * __ioremap_com(phys_addr_t addr, unsigned long pa,
unsigned long ea, unsigned long size,
unsigned long flags)
{
@@ -129,7 +129,7 @@ static void __iomem * __ioremap_com(unsi
return (void __iomem *) (ea + (addr & ~PAGE_MASK));
}
-void __iomem * __ioremap(unsigned long addr, unsigned long size,
+void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
unsigned long flags)
{
unsigned long pa, ea;
@@ -169,7 +169,7 @@ void __iomem * __ioremap(unsigned long a
}
-void __iomem * ioremap(unsigned long addr, unsigned long size)
+void __iomem * ioremap(phys_addr_t addr, unsigned long size)
{
unsigned long flags = _PAGE_NO_CACHE | _PAGE_GUARDED;
@@ -178,7 +178,7 @@ void __iomem * ioremap(unsigned long add
return __ioremap(addr, size, flags);
}
-void __iomem * ioremap_flags(unsigned long addr, unsigned long size,
+void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size,
unsigned long flags)
{
if (ppc_md.ioremap)
@@ -189,7 +189,7 @@ void __iomem * ioremap_flags(unsigned lo
#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
-int __ioremap_explicit(unsigned long pa, unsigned long ea,
+int __ioremap_explicit(phys_addr_t pa, unsigned long ea,
unsigned long size, unsigned long flags)
{
struct vm_struct *area;
@@ -244,7 +244,7 @@ int __ioremap_explicit(unsigned long pa,
*
* XXX what about calls before mem_init_done (ie python_countermeasures())
*/
-void __iounmap(void __iomem *token)
+void __iounmap(volatile void __iomem *token)
{
void *addr;
@@ -256,7 +256,7 @@ void __iounmap(void __iomem *token)
im_free(addr);
}
-void iounmap(void __iomem *token)
+void iounmap(volatile void __iomem *token)
{
if (ppc_md.iounmap)
ppc_md.iounmap(token);
@@ -282,7 +282,7 @@ static int iounmap_subset_regions(unsign
return 0;
}
-int __iounmap_explicit(void __iomem *start, unsigned long size)
+int __iounmap_explicit(volatile void __iomem *start, unsigned long size)
{
struct vm_struct *area;
unsigned long addr;
Index: linux-cell/arch/powerpc/platforms/iseries/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/setup.c 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/iseries/setup.c 2006-11-07 17:40:29.000000000 +1100
@@ -649,13 +649,13 @@ static void iseries_dedicated_idle(void)
void __init iSeries_init_IRQ(void) { }
#endif
-static void __iomem *iseries_ioremap(unsigned long address, unsigned long size,
+static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,
unsigned long flags)
{
return (void __iomem *)address;
}
-static void iseries_iounmap(void __iomem *token)
+static void iseries_iounmap(volatile void __iomem *token)
{
}
Index: linux-cell/include/asm-powerpc/machdep.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/machdep.h 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/machdep.h 2006-11-07 17:40:29.000000000 +1100
@@ -88,9 +88,9 @@ struct machdep_calls {
void (*pci_dma_dev_setup)(struct pci_dev *dev);
void (*pci_dma_bus_setup)(struct pci_bus *bus);
- void __iomem * (*ioremap)(unsigned long addr, unsigned long size,
+ void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
unsigned long flags);
- void (*iounmap)(void __iomem *token);
+ void (*iounmap)(volatile void __iomem *token);
#endif /* CONFIG_PPC64 */
int (*probe)(void);
Index: linux-cell/arch/powerpc/kernel/pci_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_32.c 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/pci_32.c 2006-11-07 17:40:29.000000000 +1100
@@ -1561,7 +1561,7 @@ static struct resource *__pci_mmap_make_
*offset += hose->pci_mem_offset;
res_bit = IORESOURCE_MEM;
} else {
- io_offset = hose->io_base_virt - ___IO_BASE;
+ io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
*offset += io_offset;
res_bit = IORESOURCE_IO;
}
@@ -1816,7 +1816,8 @@ void pci_resource_to_user(const struct p
return;
if (rsrc->flags & IORESOURCE_IO)
- offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+ offset = (void __iomem *)_IO_BASE - hose->io_base_virt
+ + hose->io_base_phys;
*start = rsrc->start + offset;
*end = rsrc->end + offset;
@@ -1835,35 +1836,6 @@ pci_init_resource(struct resource *res,
res->child = NULL;
}
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
-{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
- unsigned long flags = pci_resource_flags(dev, bar);
-
- if (!len)
- return NULL;
- if (max && len > max)
- len = max;
- if (flags & IORESOURCE_IO)
- return ioport_map(start, len);
- if (flags & IORESOURCE_MEM)
- /* Not checking IORESOURCE_CACHEABLE because PPC does
- * not currently distinguish between ioremap and
- * ioremap_nocache.
- */
- return ioremap(start, len);
- /* What? */
- return NULL;
-}
-
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-{
- /* Nothing to do */
-}
-EXPORT_SYMBOL(pci_iomap);
-EXPORT_SYMBOL(pci_iounmap);
-
unsigned long pci_address_to_pio(phys_addr_t address)
{
struct pci_controller* hose = hose_head;
Index: linux-cell/arch/powerpc/kernel/iomap.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/iomap.c 2006-11-07 15:04:29.000000000 +1100
+++ linux-cell/arch/powerpc/kernel/iomap.c 2006-11-07 17:40:29.000000000 +1100
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(iowrite32_rep);
void __iomem *ioport_map(unsigned long port, unsigned int len)
{
- return (void __iomem *) (port+pci_io_base);
+ return (void __iomem *) (port + _IO_BASE);
}
void ioport_unmap(void __iomem *addr)
Index: linux-cell/include/asm-powerpc/ide.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ide.h 2006-11-07 16:59:19.000000000 +1100
+++ linux-cell/include/asm-powerpc/ide.h 2006-11-07 17:40:29.000000000 +1100
@@ -22,17 +22,10 @@
#endif
#endif
-#ifdef __powerpc64__
#define __ide_mm_insw(p, a, c) readsw((void __iomem *)(p), (a), (c))
#define __ide_mm_insl(p, a, c) readsl((void __iomem *)(p), (a), (c))
#define __ide_mm_outsw(p, a, c) writesw((void __iomem *)(p), (a), (c))
#define __ide_mm_outsl(p, a, c) writesl((void __iomem *)(p), (a), (c))
-#else
-#define __ide_mm_insw(p, a, c) _insw_ns((volatile u16 __iomem *)(p), (a), (c))
-#define __ide_mm_insl(p, a, c) _insl_ns((volatile u32 __iomem *)(p), (a), (c))
-#define __ide_mm_outsw(p, a, c) _outsw_ns((volatile u16 __iomem *)(p), (a), (c))
-#define __ide_mm_outsl(p, a, c) _outsl_ns((volatile u32 __iomem *)(p), (a), (c))
-#endif
#ifndef __powerpc64__
#include <linux/hdreg.h>
^ permalink raw reply
* [PATCH 32/32] powerpc: Fix a typo in new style SPE mapping code
From: Benjamin Herrenschmidt @ 2006-11-11 6:25 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1163226282.72526.823314634857.qpush@butch>
This patch fixes a typo in the "new style" code for mapping SPE
resources, which causes it to try to map 4 times the same resource.
It also adds some pr_debug's that are useful to track down issues with
the firmware when bringinh up new machines.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
The bug is in 2.6.19 so we should merge that asap.
arch/powerpc/platforms/cell/spu_base.c | 41 ++++++++++++++++++++++++++-------
1 file changed, 33 insertions(+), 8 deletions(-)
Index: linux-cell/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spu_base.c 2006-11-11 14:57:59.000000000 +1100
+++ linux-cell/arch/powerpc/platforms/cell/spu_base.c 2006-11-11 15:01:52.000000000 +1100
@@ -655,14 +655,19 @@
for (i=0; i < 3; i++) {
ret = of_irq_map_one(np, i, &oirq);
- if (ret)
+ if (ret) {
+ pr_debug("spu_new: failed to get irq %d\n", i);
goto err;
-
+ }
ret = -EINVAL;
+ pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0],
+ oirq.controller->full_name);
spu->irqs[i] = irq_create_of_mapping(oirq.controller,
oirq.specifier, oirq.size);
- if (spu->irqs[i] == NO_IRQ)
+ if (spu->irqs[i] == NO_IRQ) {
+ pr_debug("spu_new: failed to map it !\n");
goto err;
+ }
}
return 0;
@@ -681,7 +686,7 @@
struct resource resource = { };
int ret;
- ret = of_address_to_resource(node, 0, &resource);
+ ret = of_address_to_resource(node, nr, &resource);
if (ret)
goto out;
@@ -704,22 +709,42 @@
ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
&spu->local_store_phys);
- if (ret)
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 0\n",
+ node->full_name);
goto out;
+ }
ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
&spu->problem_phys);
- if (ret)
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 1\n",
+ node->full_name);
goto out_unmap;
+ }
ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
NULL);
- if (ret)
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 2\n",
+ node->full_name);
goto out_unmap;
+ }
if (!firmware_has_feature(FW_FEATURE_LPAR))
ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1,
NULL);
- if (ret)
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 3\n",
+ node->full_name);
goto out_unmap;
+ }
+ pr_debug("spu_new: %s maps:\n", node->full_name);
+ pr_debug(" local store : 0x%016lx -> 0x%p\n",
+ spu->local_store_phys, spu->local_store);
+ pr_debug(" problem state : 0x%016lx -> 0x%p\n",
+ spu->problem_phys, spu->problem);
+ pr_debug(" priv2 : 0x%p\n", spu->priv2);
+ pr_debug(" priv1 : 0x%p\n", spu->priv1);
+
return 0;
out_unmap:
^ permalink raw reply
* [PATCH] ppc/powerpc: Fix io.h for config with CONFIG_PCI not set
From: Sylvain Munaut @ 2006-11-11 9:53 UTC (permalink / raw)
To: Paul Mackerras; +Cc: Linux PPC dev
When CONFIG_PCI option is not set, the variables
pci_dram_offset, isa_io_base and isa_mem_base are not defined.
Currently, the test is handled in each platform header. This
patch moves the test in io.h once and for all.
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
---
include/asm-powerpc/mpc85xx.h | 8 --------
include/asm-ppc/io.h | 8 +-------
include/asm-ppc/mpc52xx.h | 11 -----------
include/asm-ppc/mpc83xx.h | 8 --------
include/asm-ppc/mpc85xx.h | 8 --------
5 files changed, 1 insertions(+), 42 deletions(-)
diff --git a/include/asm-powerpc/mpc85xx.h b/include/asm-powerpc/mpc85xx.h
index ccdb8a2..5414299 100644
--- a/include/asm-powerpc/mpc85xx.h
+++ b/include/asm-powerpc/mpc85xx.h
@@ -31,14 +31,6 @@ #ifdef CONFIG_MPC85xx_CDS
#include <platforms/85xx/mpc85xx_cds.h>
#endif
-#define _IO_BASE isa_io_base
-#define _ISA_MEM_BASE isa_mem_base
-#ifdef CONFIG_PCI
-#define PCI_DRAM_OFFSET pci_dram_offset
-#else
-#define PCI_DRAM_OFFSET 0
-#endif
-
/* Let modules/drivers get at CCSRBAR */
extern phys_addr_t get_ccsrbar(void);
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index a4c411b..b744baf 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -26,17 +26,11 @@ #define PREP_PCI_DRAM_OFFSET 0x80000000
#if defined(CONFIG_4xx)
#include <asm/ibm4xx.h>
-#elif defined(CONFIG_PPC_MPC52xx)
-#include <asm/mpc52xx.h>
#elif defined(CONFIG_8xx)
#include <asm/mpc8xx.h>
#elif defined(CONFIG_8260)
#include <asm/mpc8260.h>
-#elif defined(CONFIG_83xx)
-#include <asm/mpc83xx.h>
-#elif defined(CONFIG_85xx)
-#include <asm/mpc85xx.h>
-#elif defined(CONFIG_APUS)
+#elif defined(CONFIG_APUS) || !defined(CONFIG_PCI)
#define _IO_BASE 0
#define _ISA_MEM_BASE 0
#define PCI_DRAM_OFFSET 0
diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
index 64c8874..d9d21aa 100644
--- a/include/asm-ppc/mpc52xx.h
+++ b/include/asm-ppc/mpc52xx.h
@@ -29,17 +29,6 @@ struct pt_regs;
#endif /* __ASSEMBLY__ */
-#ifdef CONFIG_PCI
-#define _IO_BASE isa_io_base
-#define _ISA_MEM_BASE isa_mem_base
-#define PCI_DRAM_OFFSET pci_dram_offset
-#else
-#define _IO_BASE 0
-#define _ISA_MEM_BASE 0
-#define PCI_DRAM_OFFSET 0
-#endif
-
-
/* ======================================================================== */
/* PPC Sys devices definition */
/* ======================================================================== */
diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h
index 02ed2c3..c306197 100644
--- a/include/asm-ppc/mpc83xx.h
+++ b/include/asm-ppc/mpc83xx.h
@@ -25,14 +25,6 @@ #ifdef CONFIG_MPC834x_SYS
#include <platforms/83xx/mpc834x_sys.h>
#endif
-#define _IO_BASE isa_io_base
-#define _ISA_MEM_BASE isa_mem_base
-#ifdef CONFIG_PCI
-#define PCI_DRAM_OFFSET pci_dram_offset
-#else
-#define PCI_DRAM_OFFSET 0
-#endif
-
/*
* The "residual" board information structure the boot loader passes
* into the kernel.
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
index 9b48511..d7e4a79 100644
--- a/include/asm-ppc/mpc85xx.h
+++ b/include/asm-ppc/mpc85xx.h
@@ -44,14 +44,6 @@ #if defined(CONFIG_TQM8540) || defined(C
#include <platforms/85xx/tqm85xx.h>
#endif
-#define _IO_BASE isa_io_base
-#define _ISA_MEM_BASE isa_mem_base
-#ifdef CONFIG_PCI
-#define PCI_DRAM_OFFSET pci_dram_offset
-#else
-#define PCI_DRAM_OFFSET 0
-#endif
-
/*
* The "residual" board information structure the boot loader passes
* into the kernel.
--
1.4.2
^ permalink raw reply related
* [PATCH] 8xx: Off-by-one fixes to SCC parameter RAM definitions
From: Kalle Pokki @ 2006-11-11 10:09 UTC (permalink / raw)
To: linuxppc-embedded, Paul Mackerras
Paul,
Please apply this trivial fix.
The SCC parameter RAM areas are mapped wrong in MPC8xx device descriptions. All
memory areas overlap with the next one, so that I2C, SPI, SMC1 and SMC2 cannot
be enabled if the four SCCs are.
Signed-off-by: Kalle Pokki <kalle.pokki@iki.fi>
---
arch/ppc/syslib/mpc8xx_devices.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/ppc/syslib/mpc8xx_devices.c b/arch/ppc/syslib/mpc8xx_devices.c
index cf5ab47..31fb565 100644
--- a/arch/ppc/syslib/mpc8xx_devices.c
+++ b/arch/ppc/syslib/mpc8xx_devices.c
@@ -78,7 +78,7 @@ struct platform_device ppc_sys_platform_
{
.name = "pram",
.start = 0x3c00,
- .end = 0x3c80,
+ .end = 0x3c7f,
.flags = IORESOURCE_MEM,
},
{
@@ -103,7 +103,7 @@ struct platform_device ppc_sys_platform_
{
.name = "pram",
.start = 0x3d00,
- .end = 0x3d80,
+ .end = 0x3d7f,
.flags = IORESOURCE_MEM,
},
@@ -129,7 +129,7 @@ struct platform_device ppc_sys_platform_
{
.name = "pram",
.start = 0x3e00,
- .end = 0x3e80,
+ .end = 0x3e7f,
.flags = IORESOURCE_MEM,
},
@@ -155,7 +155,7 @@ struct platform_device ppc_sys_platform_
{
.name = "pram",
.start = 0x3f00,
- .end = 0x3f80,
+ .end = 0x3f7f,
.flags = IORESOURCE_MEM,
},
--
1.4.1.1
^ permalink raw reply related
* Re: [PATCH 7/16] powerpc: add support for ps3 platform
From: Christoph Hellwig @ 2006-11-11 11:21 UTC (permalink / raw)
To: Geoff Levand; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <4554DACB.8060809@am.sony.com>
On Fri, Nov 10, 2006 at 12:02:19PM -0800, Geoff Levand wrote:
> This adds the core platform support for the PS3 game console and other
> platforms using the PS3 Platform hypervisor.
Please give the port a less confusing name. I'd expect platforms/ps3
to be the bare metal port once people have revere-engineered the
hardware, so your crappy hipervisor code should make it very clear what
it is. sonyhv or ps3hv would suite I think.
^ permalink raw reply
* Re: [PATCH 8/16] powerpc: add ps3 platform hvcalls
From: Christoph Hellwig @ 2006-11-11 11:22 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <200611110313.40940.arnd@arndb.de>
On Sat, Nov 11, 2006 at 03:13:40AM +0100, Arnd Bergmann wrote:
> On Friday 10 November 2006 21:02, Geoff Levand wrote:
> > Adds the ps3pf hvcalls.
> >
> > Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
>
> This one reminds of the inline hcall abstraction layer I did
> some time ago. The implementation in your patch is a lot
> less elegant than both the pseries in its current incarnation
> and the one that I did (IMHO). Any opinions on how we should
> proceed here?
Please try to reuse Arnd's code as much as possible. What's in
this patch is more than ugly.
^ permalink raw reply
* Re: [PATCH 7/16] powerpc: add support for ps3 platform
From: Christoph Hellwig @ 2006-11-11 11:24 UTC (permalink / raw)
To: Geoff Levand; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20061111112125.GA24288@lst.de>
On Sat, Nov 11, 2006 at 12:21:25PM +0100, Christoph Hellwig wrote:
> On Fri, Nov 10, 2006 at 12:02:19PM -0800, Geoff Levand wrote:
> > This adds the core platform support for the PS3 game console and other
> > platforms using the PS3 Platform hypervisor.
>
> Please give the port a less confusing name. I'd expect platforms/ps3
> to be the bare metal port once people have revere-engineered the
> hardware, so your crappy hipervisor code should make it very clear what
> it is. sonyhv or ps3hv would suite I think.
Any while we're at it it probably shouldn't be it's own directory
under platforms, as platforms/cell contains a lot of generic cell
stuff. We should rather have platforms/cell for all cell stuff
and then sub-platform prefixed bits. Especially as e.g. the cpbw and
native cell port will probably share a lot of code.
^ permalink raw reply
* Re: [PATCH 13/16] powerpc: add ps3 platform lpar addressing
From: Christoph Hellwig @ 2006-11-11 11:28 UTC (permalink / raw)
To: Geoff Levand; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <4554DB14.3070900@am.sony.com>
On Fri, Nov 10, 2006 at 12:03:32PM -0800, Geoff Levand wrote:
> Adds some needed bits for a config option PS3PF_USE_LPAR_ADDR that disables
> the ps3pf lpar address translation mechanism. This is a currently needed
> workaround for limitations in the design of the spu support.
So make the code do the sane thing and don't put the config in the
kernel tree.
^ permalink raw reply
* Re: [PATCH] CPM_UART: Fix non-console initialisation (v2)
From: Paul Mackerras @ 2006-11-11 11:29 UTC (permalink / raw)
To: Kalle Pokki; +Cc: linuxppc-embedded
In-Reply-To: <Pine.LNX.4.64.0611101359200.25024@host32.eke.fi>
Kalle Pokki writes:
> Hmm, it seems you already pushed the changes. This should apply to the
> current 'merge' branch.
That on its own is hard to justify as a bug fix, isn't it?
Paul.
^ permalink raw reply
* Please pull powerpc.git 'merge' branch
From: Paul Mackerras @ 2006-11-11 11:32 UTC (permalink / raw)
To: torvalds; +Cc: linuxppc-dev
Linus,
Please do:
git pull \
git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git merge
to get some more PowerPC bugfixes, as listed below. I have included
the full commit messages this time.
Thanks,
Paul.
arch/powerpc/Kconfig | 2 +
arch/powerpc/boot/wrapper | 4 +--
arch/powerpc/boot/zImage.lds.S | 5 +++
arch/powerpc/kernel/rtas_flash.c | 47 ++++++++++++++++++++++++-------
arch/powerpc/platforms/cell/spu_base.c | 41 ++++++++++++++++++++++-----
drivers/serial/cpm_uart/cpm_uart.h | 2 +
drivers/serial/cpm_uart/cpm_uart_core.c | 16 +++++------
drivers/serial/cpm_uart/cpm_uart_cpm1.c | 2 +
8 files changed, 88 insertions(+), 31 deletions(-)
commit 36b600f2649e3be49039efe31edeeb64277dbd99
Author: Geoff Levand <geoffrey.levand@am.sony.com>
Date: Thu Nov 2 21:08:45 2006 -0800
[POWERPC] cell: set ARCH_SPARSEMEM_DEFAULT in Kconfig
The current cell processor support needs sparsemem, so set it as
the default memory model.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
commit ab56dbddc8a23ff3f4602855aaf0fcb3c814118b
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Fri Nov 10 15:11:20 2006 +1100
[POWERPC] Fix cell "new style" mapping and add debug
This fixes a typo in the "new style" code for mapping SPE resources,
which causes it to try to map the same resource 4 times.
It also adds some pr_debug's that are useful to track down issues with
the firmware when bringinh up new machines.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
commit ae883cab9457aad0fb3342249e1207873d3b64de
Author: John Rose <johnrose@austin.ibm.com>
Date: Wed Nov 8 10:07:30 2006 -0600
[POWERPC] pseries: Force 4k update_flash block and list sizes
The enablement of 64k pages on pseries platforms exposed a bug in
the RTAS mechanism for updating firmware. RTAS assumes 4k for flash
block and list sizes, and use of any other sizes results in a failure,
even though PAPR does not specify any such requirement.
This patch changes the rtas_flash module to force the use of 4k memory
block and list sizes when preparing and sending a firmware image to
RTAS. The rtas_flash function now uses a slab cache of 4k blocks with
4k alignment, rather than get_zeroed_page(), to allocate the memory for
the flash blocks and lists. The 4k alignment requirement is specified
in PAPR.
Signed-off-by: John Rose <johnrose@austin.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
commit 0091cf5a6ae6e52fc95ceb53200975ef2c81c206
Author: Kalle Pokki <kalle.pokki@iki.fi>
Date: Wed Nov 1 15:08:13 2006 +0200
[POWERPC] CPM_UART: Fix non-console initialisation
The cpm_uart driver is initialised incorrectly, if there is a frame buffer
console, and CONFIG_SERIAL_CPM_CONSOLE is defined. The driver fails to
call cpm_uart_init_portdesc() and set_lineif() in this case.
Signed-off-by: Kalle Pokki <kalle.pokki@iki.fi>
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
commit 599540a85595bd5950354bd95f5ebf9c6e07c971
Author: Kalle Pokki <kalle.pokki@iki.fi>
Date: Wed Nov 1 09:52:41 2006 +0200
[POWERPC] CPM_UART: Fix non-console transmit
The SMC and SCC hardware transmitter is enabled at the wrong
place. Simply writing twice to the non-console port, like
$ echo asdf > /dev/ttyCPM1
$ echo asdf > /dev/ttyCPM1
puts the shell into endless uninterruptible sleep, since the
transmitter is stopped after the first write, and is not enabled
before the shutdown function of the second write. Thus the transmit
buffers are never emptied.
Signed-off-by: Kalle Pokki <kalle.pokki@iki.fi>
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
commit 621da0f8af228525e4b40390e36fbdc44a587cf1
Author: Paul Mackerras <paulus@samba.org>
Date: Thu Nov 9 16:00:06 2006 +1100
[POWERPC] Make sure initrd and dtb sections get into zImage correctly
The "wrapper" script was using the wrong names for the initrd and
dtb (device-tree blob) sections. This fixes it, and also ensures
the symbols for the start and end of the dtb get defined correctly.
Signed-off-by: Paul Mackerras <paulus@samba.org>
^ permalink raw reply
* Re: [PATCH 7/16] powerpc: add support for ps3 platform
From: Arnd Bergmann @ 2006-11-11 11:50 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras
In-Reply-To: <4554DACB.8060809@am.sony.com>
On Friday 10 November 2006 21:02, Geoff Levand wrote:
> @@ -876,7 +885,7 @@
> =A0=A0=A0=A0=A0=A0=A0=A0bool "PCI support" if 40x || CPM2 || PPC_83xx || =
PPC_85xx || PPC_86xx \
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0|| PPC_MPC52xx || (EMBEDD=
ED && PPC_ISERIES) || MPC7448HPC2
> =A0=A0=A0=A0=A0=A0=A0=A0default y if !40x && !CPM2 && !8xx && !APUS && !P=
PC_83xx \
> -=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0&& !PPC_85xx && !PPC_86xx
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0&& !PPC_85xx && !PPC_86xx &=
& !PS3PF
> =A0=A0=A0=A0=A0=A0=A0=A0default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && =
APUS
> =A0=A0=A0=A0=A0=A0=A0=A0default PCI_QSPAN if !4xx && !CPM2 && 8xx
> =A0=A0=A0=A0=A0=A0=A0=A0help
This change causes trouble when trying to build a multiplatform kernel
that includes PS3PF and others at the same time, because PCI gets
disabled unconditionally when PS3PF is selected. As a short-term
fix, I'd change this to do
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86=
xx \
=2D || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) || MPC7448HPC2
+ || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) || MPC7448HPC2 \
+ || PS3PF
default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \
&& !PPC_85xx && !PPC_86xx
Which makes PCI support optional when PS3PF is selected. However, this still
means that you can choose broken configurations (e.g. PSERIES=3Dy, PS3PF=3D=
y,
PCI=3Dn).
The real fix should be to get rid of the long conditional for CONFIG_PCI,
and have PCI selected by the platforms themselves:
config PPC_PSERIES
select PCI
Arnd <><
^ permalink raw reply
* Re: [PATCH] CPM_UART: Fix non-console initialisation (v2)
From: Kalle Pokki @ 2006-11-11 14:15 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-embedded
In-Reply-To: <17749.46096.241328.470093@cargo.ozlabs.ibm.com>
On 11/11/06, Paul Mackerras <paulus@samba.org> wrote:
> Kalle Pokki writes:
>
> > Hmm, it seems you already pushed the changes. This should apply to the
> > current 'merge' branch.
>
> That on its own is hard to justify as a bug fix, isn't it?
Sure, but since you removed the last hunk of the patch that became
0091cf5a6ae6e52fc95ceb53200975ef2c81c206, we now have a little
inconsistent definitions:
in cpm_uart.h
int __init cpm_uart_init_portdesc(void);
in cpm_uart_cpm1.c
int __init cpm_uart_init_portdesc(void)
{
}
in cpm_uart_cpm2.c
int cpm_uart_init_portdesc(void)
{
}
^ permalink raw reply
* Re: ipr SATA support is causing problems
From: Brian King @ 2006-11-11 23:56 UTC (permalink / raw)
To: Paul Mackerras; +Cc: James.Bottomley, linuxppc-dev, torvalds, akpm
In-Reply-To: <17749.1504.630761.341652@cargo.ozlabs.ibm.com>
Paul Mackerras wrote:
> How hard would it be to make the SATA bits conditionally compiled in,
> depending on CONFIG_ATA?
I took a look at doing this. It got a bit messy with a bunch of ifdefs,
then I realized that doing this would break module dependencies. If
ipr does not depend on CONFIG_ATA, then libata will not automatically
get loaded (or built into initrd's) when ipr is needed.
The best way I can see to accomplish your desired goal is to do something
like the fusion driver did and separate out the sas bits from the scsi
bits and essentially end up with multiple ipr modules. Unfortunately,
this is not 2.6.19 material, but I could start working on it if you
thought it sounded like a reasonable direction.
Brian
--
Brian King
eServer Storage I/O
IBM Linux Technology Center
^ permalink raw reply
* Re: [PATCH 13/16] powerpc: add ps3 platform lpar addressing
From: Benjamin Herrenschmidt @ 2006-11-12 0:45 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20061111112847.GD24288@lst.de>
On Sat, 2006-11-11 at 12:28 +0100, Christoph Hellwig wrote:
> On Fri, Nov 10, 2006 at 12:03:32PM -0800, Geoff Levand wrote:
> > Adds some needed bits for a config option PS3PF_USE_LPAR_ADDR that disables
> > the ps3pf lpar address translation mechanism. This is a currently needed
> > workaround for limitations in the design of the spu support.
>
> So make the code do the sane thing and don't put the config in the
> kernel tree.
Well... I'd like to keep the option for a little while.
There are performances issues with sparsemem the way it's used by
ps3pf.. the problem is that the memory map looks like you get a bunch of
memory at 0 (the RMO, not sure exactly how much in practice) and the
rest in a chunk all the way up the 48 bits or so max physical space.
So sparsemem ends up with an enormous mapping only populated at the very
beginning and the very end.
Thus, I'd like Geoff to keep the option of doing the manual translation
in the hash code for now until I finally get some HW and thus can do
some measurements, and possibly figure out a nicer way to deal with
that.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH 8/16] powerpc: add ps3 platform hvcalls
From: Benjamin Herrenschmidt @ 2006-11-12 0:46 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linuxppc-dev, Paul Mackerras, Arnd Bergmann
In-Reply-To: <20061111112239.GB24288@lst.de>
On Sat, 2006-11-11 at 12:22 +0100, Christoph Hellwig wrote:
> On Sat, Nov 11, 2006 at 03:13:40AM +0100, Arnd Bergmann wrote:
> > On Friday 10 November 2006 21:02, Geoff Levand wrote:
> > > Adds the ps3pf hvcalls.
> > >
> > > Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
> >
> > This one reminds of the inline hcall abstraction layer I did
> > some time ago. The implementation in your patch is a lot
> > less elegant than both the pseries in its current incarnation
> > and the one that I did (IMHO). Any opinions on how we should
> > proceed here?
>
> Please try to reuse Arnd's code as much as possible. What's in
> this patch is more than ugly.
Last I heard, there wasn't complete agreement between Paulus and Arnd
about how those Hcalls should look like and Arnd patch, I think,
conflicts with something else (though it's not off the top of my mind, I
haven't paid too much attention there).
I asked Paulus and we agreed that Geoff should keep his current macros
for now, and we'll look into a general consolidation once it's in and
the Toshiba stuff is in too (it should be posted next week).
Ben.
^ permalink raw reply
* Re: ipr SATA support is causing problems
From: Benjamin Herrenschmidt @ 2006-11-12 0:50 UTC (permalink / raw)
To: Brian King; +Cc: James.Bottomley, linuxppc-dev, torvalds, Paul Mackerras, akpm
In-Reply-To: <4556631C.1070308@us.ibm.com>
On Sat, 2006-11-11 at 17:56 -0600, Brian King wrote:
> Paul Mackerras wrote:
> > How hard would it be to make the SATA bits conditionally compiled in,
> > depending on CONFIG_ATA?
>
> I took a look at doing this. It got a bit messy with a bunch of ifdefs,
> then I realized that doing this would break module dependencies. If
> ipr does not depend on CONFIG_ATA, then libata will not automatically
> get loaded (or built into initrd's) when ipr is needed.
>
> The best way I can see to accomplish your desired goal is to do something
> like the fusion driver did and separate out the sas bits from the scsi
> bits and essentially end up with multiple ipr modules. Unfortunately,
> this is not 2.6.19 material, but I could start working on it if you
> thought it sounded like a reasonable direction.
Yeah, something like
/--- SATA sub-modules (depends on CONFIG_ATA)
- core IPR module /
\
\--- SAS sub-module (depends on CONFIG_SCSI)
\
\--- SCSI sub-module (depends on CONFIG_SCSI)
Or do you need SAS and SATA to be one and only one ?
Cheers,
Ben.
^ permalink raw reply
* Re: ipr SATA support is causing problems
From: Brian King @ 2006-11-12 3:55 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: James.Bottomley, linuxppc-dev, torvalds, Paul Mackerras, akpm
In-Reply-To: <1163292641.4982.249.camel@localhost.localdomain>
Benjamin Herrenschmidt wrote:
> On Sat, 2006-11-11 at 17:56 -0600, Brian King wrote:
>> Paul Mackerras wrote:
>>> How hard would it be to make the SATA bits conditionally compiled in,
>>> depending on CONFIG_ATA?
>> I took a look at doing this. It got a bit messy with a bunch of ifdefs,
>> then I realized that doing this would break module dependencies. If
>> ipr does not depend on CONFIG_ATA, then libata will not automatically
>> get loaded (or built into initrd's) when ipr is needed.
>>
>> The best way I can see to accomplish your desired goal is to do something
>> like the fusion driver did and separate out the sas bits from the scsi
>> bits and essentially end up with multiple ipr modules. Unfortunately,
>> this is not 2.6.19 material, but I could start working on it if you
>> thought it sounded like a reasonable direction.
>
> Yeah, something like
>
> /--- SATA sub-modules (depends on CONFIG_ATA)
> - core IPR module /
> \
> \--- SAS sub-module (depends on CONFIG_SCSI)
> \
> \--- SCSI sub-module (depends on CONFIG_SCSI)
>
>
> Or do you need SAS and SATA to be one and only one ?
SAS and SATA need to be one and only one. Splitting them is where
the complication comes in. So that would mean we would have
something like:
/--- SCSI sub-module
- core IPR module /
(depends on \
CONFIG_SCSI) \--- SAS/SATA sub-module (depends on CONFIG_ATA)
Brian
--
Brian King
eServer Storage I/O
IBM Linux Technology Center
^ permalink raw reply
* Re: [PATCH] PowerPC: clockevents and HRT support
From: Sergei Shtylyov @ 2006-11-12 18:30 UTC (permalink / raw)
To: Paul Mackerras; +Cc: tglx, greg.weeks, John Stultz, linuxppc-dev
In-Reply-To: <17749.4257.415783.451756@cargo.ozlabs.ibm.com>
Hello.
Paul Mackerras wrote:
>> I think the usual rule is: "you want it, you do it". ;-)
> Sure! And I will, at some point, if someone else doesn't do it
> first.
> My point is simply that as maintainer I won't accept a patch that
> breaks an important feature, even if it adds another important
> feature.
It's too early to talk about the mainline acceptance of this patch ATM,
while TOD vsyscalls are broken/removed by the GENERIC_TIME support patches
(which are aboslutely needed for HRT as well). We'll try to return to getting
them straight when the time permits, but for now the HRT patchset is still in
better form than it was for several months before that (not even compilable,
and vsyscalls broken)...
>> Seriously, we have neither time, not hardware, nor docs for the h/w this
>>accounting option applies to.
> Really? You're working on machines that don't have a timebase
> register? What powerpc chip doesn't have a timebase register, other
> than the really old 601? :) The timebase is all the hardware that is
> needed.
If you look at arch/powerpc/Kconfig, you'll see that this option depends
on PPC64 which basically says it all: we have only 32-bit targets to care
about ATM. When it comes to 64-bit ones, we'll see... :-)
>>And coercing the generic clcokevents/hrtimers
>>code into calling the arch hooks is serious design decision which I felt is
>>better to be left to Thomas as a maintainer...
> CONFIG_VIRT_CPU_ACCOUNTING is used, and needed, on powerpc and s390,
> both of which also want to do dynticks. If the current framework
> can't cope with that, then it needs to be extended.
Well, why not make Linus "extend" update_process_times() for starters? :-)
> Paul.
WBR, Sergei
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox