[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: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
Jeremy Kerr 2006-11-11 17:25:18 +11:00 committed by Paul Mackerras
parent acfd946a1a
commit 165785e5c0
6 changed files with 676 additions and 488 deletions

View File

@ -173,8 +173,8 @@ static unsigned long __initdata dt_string_start, dt_string_end;
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 @@ static void __init early_cmdline_parse(void)
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 @@ static void __init prom_initialize_tce_table(void)
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 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* 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);

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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 @@ static void cell_progress(char *s, unsigned short hex)
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
*/
bus_register_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 @@ static void __init cell_setup_arch(void)
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 @@ define_machine(cell) {
.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,

View File

@ -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;

View File

@ -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 @@ static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
}
#endif /* __ASSEMBLY__ */
/*
* IOMAP_MAX_ORDER defines the largest contiguous block