Commit 165785e5 authored by Jeremy Kerr's avatar Jeremy Kerr Committed by Paul Mackerras

[POWERPC] Cell iommu support

This patch adds full cell iommu support (and iommu disabled 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: default avatarJeremy Kerr <jk@ozlabs.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent acfd946a
...@@ -173,8 +173,8 @@ static unsigned long __initdata dt_string_start, dt_string_end; ...@@ -173,8 +173,8 @@ static unsigned long __initdata dt_string_start, dt_string_end;
static unsigned long __initdata prom_initrd_start, prom_initrd_end; static unsigned long __initdata prom_initrd_start, prom_initrd_end;
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
static int __initdata iommu_force_on; static int __initdata prom_iommu_force_on;
static int __initdata ppc64_iommu_off; static int __initdata prom_iommu_off;
static unsigned long __initdata prom_tce_alloc_start; static unsigned long __initdata prom_tce_alloc_start;
static unsigned long __initdata prom_tce_alloc_end; static unsigned long __initdata prom_tce_alloc_end;
#endif #endif
...@@ -582,9 +582,9 @@ static void __init early_cmdline_parse(void) ...@@ -582,9 +582,9 @@ static void __init early_cmdline_parse(void)
while (*opt && *opt == ' ') while (*opt && *opt == ' ')
opt++; opt++;
if (!strncmp(opt, RELOC("off"), 3)) if (!strncmp(opt, RELOC("off"), 3))
RELOC(ppc64_iommu_off) = 1; RELOC(prom_iommu_off) = 1;
else if (!strncmp(opt, RELOC("force"), 5)) else if (!strncmp(opt, RELOC("force"), 5))
RELOC(iommu_force_on) = 1; RELOC(prom_iommu_force_on) = 1;
} }
#endif #endif
} }
...@@ -1167,7 +1167,7 @@ static void __init prom_initialize_tce_table(void) ...@@ -1167,7 +1167,7 @@ static void __init prom_initialize_tce_table(void)
u64 local_alloc_top, local_alloc_bottom; u64 local_alloc_top, local_alloc_bottom;
u64 i; u64 i;
if (RELOC(ppc64_iommu_off)) if (RELOC(prom_iommu_off))
return; return;
prom_debug("starting prom_initialize_tce_table\n"); prom_debug("starting prom_initialize_tce_table\n");
...@@ -2283,11 +2283,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, ...@@ -2283,11 +2283,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* Fill in some infos for use by the kernel later on * Fill in some infos for use by the kernel later on
*/ */
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
if (RELOC(ppc64_iommu_off)) if (RELOC(prom_iommu_off))
prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
NULL, 0); NULL, 0);
if (RELOC(iommu_force_on)) if (RELOC(prom_iommu_force_on))
prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on", prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
NULL, 0); NULL, 0);
......
This diff is collapsed.
#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
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/memory_hotplug.h> #include <linux/memory_hotplug.h>
#include <linux/notifier.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -55,7 +54,6 @@ ...@@ -55,7 +54,6 @@
#include <asm/of_platform.h> #include <asm/of_platform.h>
#include "interrupt.h" #include "interrupt.h"
#include "iommu.h"
#include "cbe_regs.h" #include "cbe_regs.h"
#include "pervasive.h" #include "pervasive.h"
#include "ras.h" #include "ras.h"
...@@ -83,38 +81,11 @@ static void cell_progress(char *s, unsigned short hex) ...@@ -83,38 +81,11 @@ static void cell_progress(char *s, unsigned short hex)
printk("*** %04x : %s\n", hex, s ? s : ""); 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) static int __init cell_publish_devices(void)
{ {
if (!machine_is(cell)) if (!machine_is(cell))
return 0; return 0;
/* Register callbacks on OF platform device addition/removal
* to handle linking them to the right DMA operations
*/
bus_register_notifier(&of_platform_bus_type, &cell_of_bus_notifier);
/* Publish OF platform devices for southbridge IOs */ /* Publish OF platform devices for southbridge IOs */
of_platform_bus_probe(NULL, NULL, NULL); of_platform_bus_probe(NULL, NULL, NULL);
...@@ -205,19 +176,6 @@ static void __init cell_setup_arch(void) ...@@ -205,19 +176,6 @@ static void __init cell_setup_arch(void)
mmio_nvram_init(); 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) static int __init cell_probe(void)
{ {
unsigned long root = of_get_flat_dt_root(); unsigned long root = of_get_flat_dt_root();
...@@ -244,7 +202,6 @@ define_machine(cell) { ...@@ -244,7 +202,6 @@ define_machine(cell) {
.name = "Cell", .name = "Cell",
.probe = cell_probe, .probe = cell_probe,
.setup_arch = cell_setup_arch, .setup_arch = cell_setup_arch,
.init_early = cell_init_early,
.show_cpuinfo = cell_show_cpuinfo, .show_cpuinfo = cell_show_cpuinfo,
.restart = rtas_restart, .restart = rtas_restart,
.power_off = rtas_power_off, .power_off = rtas_power_off,
......
...@@ -48,9 +48,6 @@ ...@@ -48,9 +48,6 @@
#include "dart.h" #include "dart.h"
extern int iommu_is_off;
extern int iommu_force_on;
/* Physical base address and size of the DART table */ /* Physical base address and size of the DART table */
unsigned long dart_tablebase; /* exported to htab_initialize */ unsigned long dart_tablebase; /* exported to htab_initialize */
static unsigned long dart_tablesize; static unsigned long dart_tablesize;
......
...@@ -34,7 +34,9 @@ ...@@ -34,7 +34,9 @@
#define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1)) #define IOMMU_PAGE_MASK (~((1 << IOMMU_PAGE_SHIFT) - 1))
#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE) #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 */ /* Pure 2^n version of get_order */
static __inline__ __attribute_const__ int get_iommu_order(unsigned long size) static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
...@@ -42,8 +44,6 @@ static __inline__ __attribute_const__ int get_iommu_order(unsigned long size) ...@@ -42,8 +44,6 @@ static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1; return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
} }
#endif /* __ASSEMBLY__ */
/* /*
* IOMAP_MAX_ORDER defines the largest contiguous block * IOMAP_MAX_ORDER defines the largest contiguous block
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment