linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/8] Add set_dma_ops() to match get_dma_ops().
@ 2008-01-29 14:13 Michael Ellerman
  2008-01-29 14:13 ` [PATCH 3/8] Split out the logic that allocates struct iommus Michael Ellerman
                   ` (6 more replies)
  0 siblings, 7 replies; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:13 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 include/asm-powerpc/dma-mapping.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h
index 5eea6db..bbefb69 100644
--- a/include/asm-powerpc/dma-mapping.h
+++ b/include/asm-powerpc/dma-mapping.h
@@ -76,6 +76,11 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
 	return dev->archdata.dma_ops;
 }
 
+static inline void set_dma_ops(struct device *dev, struct dma_mapping_ops *ops)
+{
+	dev->archdata.dma_ops = ops;
+}
+
 static inline int dma_supported(struct device *dev, u64 mask)
 {
 	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/8] Allocate the hash table under 1G on cell
  2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
  2008-01-29 14:13 ` [PATCH 3/8] Split out the logic that allocates struct iommus Michael Ellerman
@ 2008-01-29 14:13 ` Michael Ellerman
  2008-01-29 14:14 ` [PATCH 4/8] Split cell_iommu_setup_hardware() into two parts Michael Ellerman
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:13 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

In order to support the fixed IOMMU mapping (in a subsequent patch), we
need the hash table to be inside the IOMMUs DMA window. This is usually 2G,
but let's make sure the hash table is under 1G as that will satisfy the
IOMMU requirements and also means the hash table will be on node 0.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/mm/hash_utils_64.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 9326a69..487c5e2 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -471,7 +471,7 @@ void __init htab_initialize(void)
 	unsigned long table;
 	unsigned long pteg_count;
 	unsigned long mode_rw;
-	unsigned long base = 0, size = 0;
+	unsigned long base = 0, size = 0, limit;
 	int i;
 
 	extern unsigned long tce_alloc_start, tce_alloc_end;
@@ -505,9 +505,15 @@ void __init htab_initialize(void)
 		_SDR1 = 0; 
 	} else {
 		/* Find storage for the HPT.  Must be contiguous in
-		 * the absolute address space.
+		 * the absolute address space. On cell we want it to be
+		 * in the first 1 Gig.
 		 */
-		table = lmb_alloc(htab_size_bytes, htab_size_bytes);
+		if (machine_is(cell))
+			limit = 0x40000000;
+		else
+			limit = 0;
+
+		table = lmb_alloc_base(htab_size_bytes, htab_size_bytes, limit);
 
 		DBG("Hash table allocated at %lx, size: %lx\n", table,
 		    htab_size_bytes);
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/8] Split out the logic that allocates struct iommus
  2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
@ 2008-01-29 14:13 ` Michael Ellerman
  2008-02-05  0:23   ` Benjamin Herrenschmidt
  2008-01-29 14:13 ` [PATCH 2/8] Allocate the hash table under 1G on cell Michael Ellerman
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:13 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

Split out the logic that allocates a struct iommu into a separate
function. This can fail however the calling code has never cared - so
just return if we can't allocate an iommu.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/iommu.c |   20 ++++++++++++++++----
 1 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 9223559..4f1ca43 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -565,10 +565,9 @@ static int __init cell_iommu_get_window(struct device_node *np,
 	return 0;
 }
 
-static void __init cell_iommu_init_one(struct device_node *np, unsigned long offset)
+static struct cbe_iommu * __init cell_iommu_alloc(struct device_node *np)
 {
 	struct cbe_iommu *iommu;
-	unsigned long base, size;
 	int nid, i;
 
 	/* Get node ID */
@@ -576,7 +575,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off
 	if (nid < 0) {
 		printk(KERN_ERR "iommu: failed to get node for %s\n",
 		       np->full_name);
-		return;
+		return NULL;
 	}
 	pr_debug("iommu: setting up iommu for node %d (%s)\n",
 		 nid, np->full_name);
@@ -592,7 +591,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off
 	if (cbe_nr_iommus >= NR_IOMMUS) {
 		printk(KERN_ERR "iommu: too many IOMMUs detected ! (%s)\n",
 		       np->full_name);
-		return;
+		return NULL;
 	}
 
 	/* Init base fields */
@@ -603,6 +602,19 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off
 	snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i);
 	INIT_LIST_HEAD(&iommu->windows);
 
+	return iommu;
+}
+
+static void __init cell_iommu_init_one(struct device_node *np,
+				       unsigned long offset)
+{
+	struct cbe_iommu *iommu;
+	unsigned long base, size;
+
+	iommu = cell_iommu_alloc(np);
+	if (!iommu)
+		return;
+
 	/* Obtain a window for it */
 	cell_iommu_get_window(np, &base, &size);
 
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 4/8] Split cell_iommu_setup_hardware() into two parts
  2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
  2008-01-29 14:13 ` [PATCH 3/8] Split out the logic that allocates struct iommus Michael Ellerman
  2008-01-29 14:13 ` [PATCH 2/8] Allocate the hash table under 1G on cell Michael Ellerman
@ 2008-01-29 14:14 ` Michael Ellerman
  2008-01-29 14:14 ` [PATCH 6/8] Add support to cell_iommu_setup_page_tables() for multiple windows Michael Ellerman
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:14 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

Split cell_iommu_setup_hardware() into two parts. Split the page table
setup into cell_iommu_setup_page_tables() and the bits that kick the
hardware into cell_iommu_enable_hardware().

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/iommu.c |   38 +++++++++++++++++++++++-----------
 1 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 4f1ca43..a86e5bb 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -306,20 +306,13 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)
 	return -ENODEV;
 }
 
-static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long size)
+static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
+					 unsigned long base, unsigned long size)
 {
 	struct page *page;
-	int ret, i;
+	int i;
 	unsigned long reg, segments, pages_per_segment, ptab_size, stab_size,
-		      n_pte_pages, 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;
+		      n_pte_pages;
 
 	segments = size >> IO_SEGMENT_SHIFT;
 	pages_per_segment = 1ull << IO_PAGENO_BITS;
@@ -378,6 +371,20 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long siz
 			(__pa(iommu->ptab) + n_pte_pages * IOMMU_PAGE_SIZE * i);
 		pr_debug("\t[%d] 0x%016lx\n", i, iommu->stab[i]);
 	}
+}
+
+static void cell_iommu_enable_hardware(struct cbe_iommu *iommu)
+{
+	int ret;
+	unsigned long reg, 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;
 
 	/* ensure that the STEs have updated */
 	mb();
@@ -407,6 +414,13 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long siz
 	out_be64(iommu->cmd_regs + IOC_IOCmd_Cfg, reg);
 }
 
+static void cell_iommu_setup_hardware(struct cbe_iommu *iommu,
+	unsigned long base, unsigned long size)
+{
+	cell_iommu_setup_page_tables(iommu, base, size);
+	cell_iommu_enable_hardware(iommu);
+}
+
 #if 0/* Unused for now */
 static struct iommu_window *find_window(struct cbe_iommu *iommu,
 		unsigned long offset, unsigned long size)
@@ -622,7 +636,7 @@ static void __init cell_iommu_init_one(struct device_node *np,
 		 base, base + size - 1);
 
 	/* Initialize the hardware */
-	cell_iommu_setup_hardware(iommu, size);
+	cell_iommu_setup_hardware(iommu, base, size);
 
 	/* Setup the iommu_table */
 	cell_iommu_setup_window(iommu, np, base, size,
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 5/8] Split out the IOMMU logic from cell_dma_dev_setup()
  2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
                   ` (3 preceding siblings ...)
  2008-01-29 14:14 ` [PATCH 6/8] Add support to cell_iommu_setup_page_tables() for multiple windows Michael Ellerman
@ 2008-01-29 14:14 ` Michael Ellerman
  2008-02-05  0:26   ` Benjamin Herrenschmidt
  2008-01-29 14:14 ` [PATCH 7/8] Split out the ioid fetching/checking logic Michael Ellerman
  2008-01-29 14:14 ` [PATCH 8/8] Cell IOMMU fixed mapping support Michael Ellerman
  6 siblings, 1 reply; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:14 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

Split the IOMMU logic out from cell_dma_dev_setup() into a separate
function. If we're not using dma_direct_ops or dma_iommu_ops we don't
know what the hell's going on, so BUG.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/iommu.c |   19 +++++++++++++------
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index a86e5bb..e9769fc 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -507,17 +507,12 @@ static struct cbe_iommu *cell_iommu_for_node(int nid)
 
 static unsigned long cell_dma_direct_offset;
 
-static void cell_dma_dev_setup(struct device *dev)
+static void cell_dma_dev_setup_iommu(struct device *dev)
 {
 	struct iommu_window *window;
 	struct cbe_iommu *iommu;
 	struct dev_archdata *archdata = &dev->archdata;
 
-	if (get_pci_dma_ops() == &dma_direct_ops) {
-		archdata->dma_data = (void *)cell_dma_direct_offset;
-		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
@@ -534,6 +529,18 @@ static void cell_dma_dev_setup(struct device *dev)
 	archdata->dma_data = &window->table;
 }
 
+static void cell_dma_dev_setup(struct device *dev)
+{
+	struct dev_archdata *archdata = &dev->archdata;
+
+	if (get_pci_dma_ops() == &dma_iommu_ops)
+		cell_dma_dev_setup_iommu(dev);
+	else if (get_pci_dma_ops() == &dma_direct_ops)
+		archdata->dma_data = (void *)cell_dma_direct_offset;
+	else
+		BUG();
+}
+
 static void cell_pci_dma_dev_setup(struct pci_dev *dev)
 {
 	cell_dma_dev_setup(&dev->dev);
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 6/8] Add support to cell_iommu_setup_page_tables() for multiple windows
  2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
                   ` (2 preceding siblings ...)
  2008-01-29 14:14 ` [PATCH 4/8] Split cell_iommu_setup_hardware() into two parts Michael Ellerman
@ 2008-01-29 14:14 ` Michael Ellerman
  2008-02-05  0:26   ` Benjamin Herrenschmidt
  2008-01-29 14:14 ` [PATCH 5/8] Split out the IOMMU logic from cell_dma_dev_setup() Michael Ellerman
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:14 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

Add support to cell_iommu_setup_page_tables() for handling two windows,
the dynamic window and the fixed window. A fixed window size of 0
indicates that there is no fixed window at all.

Currently there are no callers who pass a non-zero fixed window, but the
upcoming fixed IOMMU mapping patch will change that.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/iommu.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index e9769fc..7779dbf 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -307,14 +307,19 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)
 }
 
 static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
-					 unsigned long base, unsigned long size)
+				unsigned long dbase, unsigned long dsize,
+				unsigned long fbase, unsigned long fsize)
 {
 	struct page *page;
 	int i;
 	unsigned long reg, segments, pages_per_segment, ptab_size, stab_size,
-		      n_pte_pages;
+		      n_pte_pages, base;
 
-	segments = size >> IO_SEGMENT_SHIFT;
+	base = dbase;
+	if (fsize != 0)
+		base = min(fbase, dbase);
+
+	segments = max(dbase + dsize, fbase + fsize) >> IO_SEGMENT_SHIFT;
 	pages_per_segment = 1ull << IO_PAGENO_BITS;
 
 	pr_debug("%s: iommu[%d]: segments: %lu, pages per segment: %lu\n",
@@ -366,7 +371,7 @@ static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
 	}
 
 	pr_debug("Setting up IOMMU stab:\n");
-	for (i = 0; i * (1ul << IO_SEGMENT_SHIFT) < size; i++) {
+	for (i = base >> IO_SEGMENT_SHIFT; i < segments; 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]);
@@ -417,7 +422,7 @@ static void cell_iommu_enable_hardware(struct cbe_iommu *iommu)
 static void cell_iommu_setup_hardware(struct cbe_iommu *iommu,
 	unsigned long base, unsigned long size)
 {
-	cell_iommu_setup_page_tables(iommu, base, size);
+	cell_iommu_setup_page_tables(iommu, base, size, 0, 0);
 	cell_iommu_enable_hardware(iommu);
 }
 
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 7/8] Split out the ioid fetching/checking logic
  2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
                   ` (4 preceding siblings ...)
  2008-01-29 14:14 ` [PATCH 5/8] Split out the IOMMU logic from cell_dma_dev_setup() Michael Ellerman
@ 2008-01-29 14:14 ` Michael Ellerman
  2008-02-05  0:27   ` Benjamin Herrenschmidt
  2008-01-29 14:14 ` [PATCH 8/8] Cell IOMMU fixed mapping support Michael Ellerman
  6 siblings, 1 reply; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:14 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

Split out the ioid fetching and checking logic so we can use it elsewhere
in a subsequent patch.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/iommu.c |   23 +++++++++++++++++------
 1 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 7779dbf..3baade1 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -443,25 +443,36 @@ static struct iommu_window *find_window(struct cbe_iommu *iommu,
 }
 #endif
 
+static inline u32 cell_iommu_get_ioid(struct device_node *np)
+{
+	const u32 *ioid;
+
+	ioid = of_get_property(np, "ioid", NULL);
+	if (ioid == NULL) {
+		printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
+		       np->full_name);
+		return 0;
+	}
+
+	return *ioid;
+}
+
 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 iommu_window *window;
-	const unsigned int *ioid;
+	u32 ioid;
 
-	ioid = of_get_property(np, "ioid", NULL);
-	if (ioid == NULL)
-		printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
-		       np->full_name);
+	ioid = cell_iommu_get_ioid(np);
 
 	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->ioid = ioid;
 	window->iommu = iommu;
 	window->pte_offset = pte_offset;
 
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
                   ` (5 preceding siblings ...)
  2008-01-29 14:14 ` [PATCH 7/8] Split out the ioid fetching/checking logic Michael Ellerman
@ 2008-01-29 14:14 ` Michael Ellerman
  2008-01-29 15:15   ` Olof Johansson
  2008-01-30  0:03   ` Michael Ellerman
  6 siblings, 2 replies; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 14:14 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

This patch adds support for setting up a fixed IOMMU mapping on certain
cell machines. For 64-bit devices this avoids the performance overhead of
mapping and unmapping pages at runtime. 32-bit devices are unable to use
the fixed mapping.

The fixed mapping is established at boot, and maps all of physical memory
1:1 into device space at some offset. On machines with < 30 GB of memory
we setup the fixed mapping immediately above the normal IOMMU window.

For example a machine with 4GB of memory would end up with the normal
IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
3GB, plus any offset required by firmware. The firmware offset is encoded
in the "dma-ranges" property.

On machines with 30GB or more of memory, we are unable to place the fixed
mapping above the normal IOMMU window as we would run out of address space.
Instead we move the normal IOMMU window to coincide with the hash page
table, this region does not need to be part of the fixed mapping as no
device should ever be DMA'ing to it. We then setup the fixed mapping
from 0 to 32GB.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/iommu.c |  241 ++++++++++++++++++++++++++++++++++-
 1 files changed, 240 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 3baade1..56c69cc 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -523,6 +523,9 @@ static struct cbe_iommu *cell_iommu_for_node(int nid)
 
 static unsigned long cell_dma_direct_offset;
 
+static unsigned long dma_iommu_fixed_base;
+struct dma_mapping_ops dma_iommu_fixed_ops;
+
 static void cell_dma_dev_setup_iommu(struct device *dev)
 {
 	struct iommu_window *window;
@@ -545,11 +548,16 @@ static void cell_dma_dev_setup_iommu(struct device *dev)
 	archdata->dma_data = &window->table;
 }
 
+static void cell_dma_dev_setup_static(struct device *dev);
+
 static void cell_dma_dev_setup(struct device *dev)
 {
 	struct dev_archdata *archdata = &dev->archdata;
 
-	if (get_pci_dma_ops() == &dma_iommu_ops)
+	/* Order is important here, these are not mutually exclusive */
+	if (get_dma_ops(dev) == &dma_iommu_fixed_ops)
+		cell_dma_dev_setup_static(dev);
+	else if (get_pci_dma_ops() == &dma_iommu_ops)
 		cell_dma_dev_setup_iommu(dev);
 	else if (get_pci_dma_ops() == &dma_direct_ops)
 		archdata->dma_data = (void *)cell_dma_direct_offset;
@@ -752,6 +760,234 @@ static int __init cell_iommu_init_disabled(void)
 	return 0;
 }
 
+static u64 cell_iommu_get_fixed_address(struct device *dev)
+{
+	u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR;
+	struct device_node *tmp, *np;
+	const u32 *ranges = NULL;
+	int i, len, best;
+
+	np = dev->archdata.of_node;
+	of_node_get(np);
+	ranges = of_get_property(np, "dma-ranges", &len);
+	while (!ranges && np) {
+		tmp = of_get_parent(np);
+		of_node_put(np);
+		np = tmp;
+		ranges = of_get_property(np, "dma-ranges", &len);
+	}
+
+	if (!ranges) {
+		dev_dbg(dev, "iommu: no dma-ranges found\n");
+		goto out;
+	}
+
+	len /= sizeof(u32);
+
+	/* dma-ranges format:
+	 * 1 cell:  pci space
+	 * 2 cells: pci address
+	 * 2 cells: parent address
+	 * 2 cells: size
+	 */
+	for (i = 0, best = -1, best_size = 0; i < len; i += 7) {
+		cpu_addr = of_translate_dma_address(np, ranges +i + 3);
+		size = of_read_number(ranges + i + 5, 2);
+
+		if (cpu_addr == 0 && size > best_size) {
+			best = i;
+			best_size = size;
+		}
+	}
+
+	if (best >= 0)
+		pci_addr = of_read_number(ranges + best + 1, 2);
+	else
+		dev_dbg(dev, "iommu: no suitable range found!\n");
+
+out:
+	of_node_put(np);
+
+	return pci_addr;
+}
+
+static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+		return -EIO;
+
+	if (dma_mask == DMA_BIT_MASK(64)) {
+		if (cell_iommu_get_fixed_address(dev) == OF_BAD_ADDR)
+			dev_dbg(dev, "iommu: 64-bit OK, but bad addr\n");
+		else {
+			dev_dbg(dev, "iommu: 64-bit OK, using fixed ops\n");
+			set_dma_ops(dev, &dma_iommu_fixed_ops);
+			cell_dma_dev_setup(dev);
+		}
+	} else {
+		dev_dbg(dev, "iommu: not 64-bit, using default ops\n");
+		set_dma_ops(dev, get_pci_dma_ops());
+	}
+
+	*dev->dma_mask = dma_mask;
+
+	return 0;
+}
+
+static void cell_dma_dev_setup_static(struct device *dev)
+{
+	struct dev_archdata *archdata = &dev->archdata;
+	u64 addr;
+
+	addr = cell_iommu_get_fixed_address(dev) + dma_iommu_fixed_base;
+	archdata->dma_data = (void *)addr;
+
+	dev_dbg(dev, "iommu: fixed addr = %lx\n", addr);
+}
+
+static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
+	struct device_node *np, unsigned long dbase, unsigned long dsize,
+	unsigned long fbase, unsigned long fsize)
+{
+	unsigned long base_pte, uaddr, *io_pte;
+	int i;
+
+	dma_iommu_fixed_base = fbase;
+
+	/* convert from bytes into page table indices */
+	dbase = dbase >> IOMMU_PAGE_SHIFT;
+	dsize = dsize >> IOMMU_PAGE_SHIFT;
+	fbase = fbase >> IOMMU_PAGE_SHIFT;
+	fsize = fsize >> IOMMU_PAGE_SHIFT;
+
+	pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
+
+	io_pte = iommu->ptab;
+	base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW
+		    | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
+
+	uaddr = 0;
+	for (i = fbase; i < fbase + fsize; i++, uaddr += IOMMU_PAGE_SIZE) {
+		/* Don't touch the dynamic region */
+		if (i >= dbase && i < (dbase + dsize)) {
+			pr_debug("iommu: static/dynamic overlap, skipping\n");
+			continue;
+		}
+		io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
+	}
+
+	mb();
+}
+
+static int __init cell_iommu_fixed_mapping_init(void)
+{
+	unsigned long dbase, dsize, fbase, fsize, hbase, hend;
+	struct cbe_iommu *iommu;
+	struct device_node *np;
+
+	/* The fixed mapping is only supported on axon machines */
+	np = of_find_node_by_name(NULL, "axon");
+	if (!np) {
+		pr_debug("iommu: fixed mapping disabled, no axons found\n");
+		return -1;
+	}
+
+	/* The default setup is to have the fixed mapping sit after the
+	 * dynamic region, so find the top of the largest IOMMU window
+	 * on any axon, then add the size of RAM and that's our max value.
+	 * If that is > 32GB we have to do other shennanigans.
+	 */
+	fbase = 0;
+	for_each_node_by_name(np, "axon") {
+		cell_iommu_get_window(np, &dbase, &dsize);
+		fbase = max(fbase, dbase + dsize);
+	}
+
+	fbase = _ALIGN_UP(fbase, 1 << IO_SEGMENT_SHIFT);
+	fsize = lmb_phys_mem_size();
+
+	if ((fbase + fsize) <= 0x800000000)
+		hbase = 0; /* use the device tree window */
+	else {
+		/* If we're over 32 GB we need to cheat. We can't map all of
+		 * RAM with the fixed mapping, and also fit the dynamic
+		 * region. So try to place the dynamic region where the hash
+		 * table sits, drivers never need to DMA to it, we don't
+		 * need a fixed mapping for that area.
+		 */
+		if (!htab_address) {
+			pr_debug("iommu: htab is NULL, on LPAR? Huh?\n");
+			return -1;
+		}
+		hbase = __pa(htab_address);
+		hend  = hbase + htab_size_bytes;
+
+		/* The window must start and end on a segment boundary */
+		if ((hbase != _ALIGN_UP(hbase, 1 << IO_SEGMENT_SHIFT)) ||
+		    (hend != _ALIGN_UP(hend, 1 << IO_SEGMENT_SHIFT))) {
+			pr_debug("iommu: hash window not segment aligned\n");
+			return -1;
+		}
+
+		/* Check the hash window fits inside the real DMA window */
+		for_each_node_by_name(np, "axon") {
+			cell_iommu_get_window(np, &dbase, &dsize);
+
+			if (hbase < dbase || (hend > (dbase + dsize))) {
+				pr_debug("iommu: hash window doesn't fit in"
+					 "real DMA window\n");
+				return -1;
+			}
+		}
+
+		fbase = 0;
+	}
+
+	/* Setup the dynamic regions */
+	for_each_node_by_name(np, "axon") {
+		iommu = cell_iommu_alloc(np);
+		BUG_ON(!iommu);
+
+		if (hbase == 0)
+			cell_iommu_get_window(np, &dbase, &dsize);
+		else {
+			dbase = hbase;
+			dsize = htab_size_bytes;
+		}
+
+		pr_debug("iommu: setting up %d, dynamic window %lx-%lx " \
+			 "fixed window %lx-%lx\n", iommu->nid, dbase,
+			 dbase + dsize, fbase, fbase + fsize);
+
+		cell_iommu_setup_page_tables(iommu, dbase, dsize, fbase, fsize);
+		cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize,
+					     fbase, fsize);
+		cell_iommu_enable_hardware(iommu);
+		cell_iommu_setup_window(iommu, np, dbase, dsize, 0);
+	}
+
+	dma_iommu_fixed_ops = dma_direct_ops;
+	dma_iommu_fixed_ops.set_dma_mask = dma_set_mask_and_switch;
+
+	dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch;
+	set_pci_dma_ops(&dma_iommu_ops);
+
+	printk(KERN_DEBUG "IOMMU fixed mapping established.\n");
+
+	return 0;
+}
+
+static int iommu_fixed_disabled;
+
+static int __init setup_iommu_fixed(char *str)
+{
+	if (strcmp(str, "off") == 0)
+		iommu_fixed_disabled = 1;
+
+	return 1;
+}
+__setup("iommu_fixed=", setup_iommu_fixed);
+
 static int __init cell_iommu_init(void)
 {
 	struct device_node *np;
@@ -771,6 +1007,9 @@ static int __init cell_iommu_init(void)
 	ppc_md.tce_build = tce_build_cell;
 	ppc_md.tce_free = tce_free_cell;
 
+	if (!iommu_fixed_disabled && cell_iommu_fixed_mapping_init() == 0)
+		goto bail;
+
 	/* Create an iommu for each /axon node.  */
 	for_each_node_by_name(np, "axon") {
 		if (np->parent == NULL || np->parent->parent != NULL)
-- 
1.5.3.7.1.g4e596e

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 15:15   ` Olof Johansson
@ 2008-01-29 15:13     ` Michael Ellerman
  2008-01-29 15:50       ` Olof Johansson
  2008-01-29 21:18       ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 15:13 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, cbe-oss-dev

[-- Attachment #1: Type: text/plain, Size: 1025 bytes --]

On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
> On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
> 
> > For example a machine with 4GB of memory would end up with the normal
> > IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
> > this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
> > 3GB, plus any offset required by firmware. The firmware offset is encoded
> > in the "dma-ranges" property.
> 
> Shouldn't the fixed mapping be between 4G and 8G (and the offset for 1G
> is at 5G), to account for the MMIO range at 2-4G?

I don't think so, ie. it works setup like that, but I'm not entirely
sure why. Presumably the 2-4GB for MMIO is only for cycles heading out
of the CPU.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 14:14 ` [PATCH 8/8] Cell IOMMU fixed mapping support Michael Ellerman
@ 2008-01-29 15:15   ` Olof Johansson
  2008-01-29 15:13     ` Michael Ellerman
  2008-01-30  0:03   ` Michael Ellerman
  1 sibling, 1 reply; 21+ messages in thread
From: Olof Johansson @ 2008-01-29 15:15 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev

On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:

> For example a machine with 4GB of memory would end up with the normal
> IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
> this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
> 3GB, plus any offset required by firmware. The firmware offset is encoded
> in the "dma-ranges" property.

Shouldn't the fixed mapping be between 4G and 8G (and the offset for 1G
is at 5G), to account for the MMIO range at 2-4G?


-Olof

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 15:13     ` Michael Ellerman
@ 2008-01-29 15:50       ` Olof Johansson
  2008-01-30  0:54         ` Arnd Bergmann
  2008-01-29 21:18       ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 21+ messages in thread
From: Olof Johansson @ 2008-01-29 15:50 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev

On Wed, Jan 30, 2008 at 02:13:45AM +1100, Michael Ellerman wrote:
> On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
> > On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
> > 
> > > For example a machine with 4GB of memory would end up with the normal
> > > IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
> > > this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
> > > 3GB, plus any offset required by firmware. The firmware offset is encoded
> > > in the "dma-ranges" property.
> > 
> > Shouldn't the fixed mapping be between 4G and 8G (and the offset for 1G
> > is at 5G), to account for the MMIO range at 2-4G?
> 
> I don't think so, ie. it works setup like that, but I'm not entirely
> sure why. Presumably the 2-4GB for MMIO is only for cycles heading out
> of the CPU.

Ben denied that being so yesterday. :-)

If that's the case, then you can stick the dynamic range there for >32GB
configs, since it's still addressable with 32 bits.


-Olof

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 15:13     ` Michael Ellerman
  2008-01-29 15:50       ` Olof Johansson
@ 2008-01-29 21:18       ` Benjamin Herrenschmidt
  2008-01-29 21:36         ` Olof Johansson
  1 sibling, 1 reply; 21+ messages in thread
From: Benjamin Herrenschmidt @ 2008-01-29 21:18 UTC (permalink / raw)
  To: michael; +Cc: Olof Johansson, linuxppc-dev, cbe-oss-dev


On Wed, 2008-01-30 at 02:13 +1100, Michael Ellerman wrote:
> On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
> > On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
> > 
> > > For example a machine with 4GB of memory would end up with the normal
> > > IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
> > > this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
> > > 3GB, plus any offset required by firmware. The firmware offset is encoded
> > > in the "dma-ranges" property.
> > 
> > Shouldn't the fixed mapping be between 4G and 8G (and the offset for 1G
> > is at 5G), to account for the MMIO range at 2-4G?
> 
> I don't think so, ie. it works setup like that, but I'm not entirely
> sure why. Presumably the 2-4GB for MMIO is only for cycles heading out
> of the CPU.

No no no... it's because on the PCI segment, it's all offset up
remember ?

Basically, the PCI host bridge on these has 2 interesting windows for
us:

0....2G			-> This goes up to memory @0 (via a couple of 
                           layers)

0x80*....0xF*		-> This goes untranslated to the PLB5 which
  			   drops the top bits and does some other 
                           manipulations, which allows to access, among
                           others the full 32GB of the cell inbound 
                           range.

The MMIO region of 2...4G is on the PCI (outbound from the Cell is yet
another range of addresses with different constraints but that ends up
generating cycles between 2 and 4G on the PCI segment).

If we had set the direct mapped region so that it uses 2G...N on PCI, we
would indeed be toast. But instead, the addresses for direct DMA that we
hand out to devices are in the 0x80* region and go hit the cell
directly, they never match MMIO.

 Ben.
 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 21:18       ` Benjamin Herrenschmidt
@ 2008-01-29 21:36         ` Olof Johansson
  2008-01-29 23:56           ` Michael Ellerman
  0 siblings, 1 reply; 21+ messages in thread
From: Olof Johansson @ 2008-01-29 21:36 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, cbe-oss-dev

On Wed, Jan 30, 2008 at 08:18:15AM +1100, Benjamin Herrenschmidt wrote:
> 
> On Wed, 2008-01-30 at 02:13 +1100, Michael Ellerman wrote:
> > On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
> > > On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
> > > 
> > > > For example a machine with 4GB of memory would end up with the normal
> > > > IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
> > > > this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
> > > > 3GB, plus any offset required by firmware. The firmware offset is encoded
> > > > in the "dma-ranges" property.
> > > 
> > > Shouldn't the fixed mapping be between 4G and 8G (and the offset for 1G
> > > is at 5G), to account for the MMIO range at 2-4G?
> > 
> > I don't think so, ie. it works setup like that, but I'm not entirely
> > sure why. Presumably the 2-4GB for MMIO is only for cycles heading out
> > of the CPU.
> 
> No no no... it's because on the PCI segment, it's all offset up
> remember ?
> 
> Basically, the PCI host bridge on these has 2 interesting windows for
> us:
> 
> 0....2G			-> This goes up to memory @0 (via a couple of 
>                            layers)
> 
> 0x80*....0xF*		-> This goes untranslated to the PLB5 which
>   			   drops the top bits and does some other 
>                            manipulations, which allows to access, among
>                            others the full 32GB of the cell inbound 
>                            range.
> 
> The MMIO region of 2...4G is on the PCI (outbound from the Cell is yet
> another range of addresses with different constraints but that ends up
> generating cycles between 2 and 4G on the PCI segment).
> 
> If we had set the direct mapped region so that it uses 2G...N on PCI, we
> would indeed be toast. But instead, the addresses for direct DMA that we
> hand out to devices are in the 0x80* region and go hit the cell
> directly, they never match MMIO.

Yeah, ok. That makes more sense. Thanks for the clarification.

Michael, btw, I wonder if it would make sense to duplicate the patch
description at the top of the file as well, since it'll be lost in the
change log for people who don't go back and read history, and having
the intentions documented in the file could be a good idea.



-Olof

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 21:36         ` Olof Johansson
@ 2008-01-29 23:56           ` Michael Ellerman
  0 siblings, 0 replies; 21+ messages in thread
From: Michael Ellerman @ 2008-01-29 23:56 UTC (permalink / raw)
  To: Olof Johansson; +Cc: cbe-oss-dev, linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 3030 bytes --]

On Tue, 2008-01-29 at 15:36 -0600, Olof Johansson wrote:
> On Wed, Jan 30, 2008 at 08:18:15AM +1100, Benjamin Herrenschmidt wrote:
> > 
> > On Wed, 2008-01-30 at 02:13 +1100, Michael Ellerman wrote:
> > > On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
> > > > On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
> > > > 
> > > > > For example a machine with 4GB of memory would end up with the normal
> > > > > IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
> > > > > this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
> > > > > 3GB, plus any offset required by firmware. The firmware offset is encoded
> > > > > in the "dma-ranges" property.
> > > > 
> > > > Shouldn't the fixed mapping be between 4G and 8G (and the offset for 1G
> > > > is at 5G), to account for the MMIO range at 2-4G?
> > > 
> > > I don't think so, ie. it works setup like that, but I'm not entirely
> > > sure why. Presumably the 2-4GB for MMIO is only for cycles heading out
> > > of the CPU.
> > 
> > No no no... it's because on the PCI segment, it's all offset up
> > remember ?
> > 
> > Basically, the PCI host bridge on these has 2 interesting windows for
> > us:
> > 
> > 0....2G			-> This goes up to memory @0 (via a couple of 
> >                            layers)
> > 
> > 0x80*....0xF*		-> This goes untranslated to the PLB5 which
> >   			   drops the top bits and does some other 
> >                            manipulations, which allows to access, among
> >                            others the full 32GB of the cell inbound 
> >                            range.
> > 
> > The MMIO region of 2...4G is on the PCI (outbound from the Cell is yet
> > another range of addresses with different constraints but that ends up
> > generating cycles between 2 and 4G on the PCI segment).
> > 
> > If we had set the direct mapped region so that it uses 2G...N on PCI, we
> > would indeed be toast. But instead, the addresses for direct DMA that we
> > hand out to devices are in the 0x80* region and go hit the cell
> > directly, they never match MMIO.
> 
> Yeah, ok. That makes more sense. Thanks for the clarification.

Right, that's the firmware offset I mentioned in the changelog - 2am is
not a good time to think about these things.

> Michael, btw, I wonder if it would make sense to duplicate the patch
> description at the top of the file as well, since it'll be lost in the
> change log for people who don't go back and read history, and having
> the intentions documented in the file could be a good idea.

Yeah that probably makes sense. I've got most of the fixed mapping code
in a block, so I'll put a comment above that section. New patch coming.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 14:14 ` [PATCH 8/8] Cell IOMMU fixed mapping support Michael Ellerman
  2008-01-29 15:15   ` Olof Johansson
@ 2008-01-30  0:03   ` Michael Ellerman
  1 sibling, 0 replies; 21+ messages in thread
From: Michael Ellerman @ 2008-01-30  0:03 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: cbe-oss-dev

[-- Attachment #1: Type: text/plain, Size: 11167 bytes --]

This patch adds support for setting up a fixed IOMMU mapping on certain
cell machines. For 64-bit devices this avoids the performance overhead of
mapping and unmapping pages at runtime. 32-bit devices are unable to use
the fixed mapping.

The fixed mapping is established at boot, and maps all of physical memory
1:1 into device space at some offset. On machines with < 30 GB of memory
we setup the fixed mapping immediately above the normal IOMMU window.

For example a machine with 4GB of memory would end up with the normal
IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
3GB, plus any offset required by firmware. The firmware offset is encoded
in the "dma-ranges" property.

On machines with 30GB or more of memory, we are unable to place the fixed
mapping above the normal IOMMU window as we would run out of address space.
Instead we move the normal IOMMU window to coincide with the hash page
table, this region does not need to be part of the fixed mapping as no
device should ever be DMA'ing to it. We then setup the fixed mapping
from 0 to 32GB.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/iommu.c |  269 ++++++++++++++++++++++++++++++++++-
 1 files changed, 267 insertions(+), 2 deletions(-)


Updated to include a description in the file.

diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 3baade1..68274a0 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -1,7 +1,7 @@
 /*
  * IOMMU implementation for Cell Broadband Processor Architecture
  *
- * (C) Copyright IBM Corporation 2006
+ * (C) Copyright IBM Corporation 2006-2008
  *
  * Author: Jeremy Kerr <jk@ozlabs.org>
  *
@@ -523,6 +523,9 @@ static struct cbe_iommu *cell_iommu_for_node(int nid)
 
 static unsigned long cell_dma_direct_offset;
 
+static unsigned long dma_iommu_fixed_base;
+struct dma_mapping_ops dma_iommu_fixed_ops;
+
 static void cell_dma_dev_setup_iommu(struct device *dev)
 {
 	struct iommu_window *window;
@@ -545,11 +548,16 @@ static void cell_dma_dev_setup_iommu(struct device *dev)
 	archdata->dma_data = &window->table;
 }
 
+static void cell_dma_dev_setup_static(struct device *dev);
+
 static void cell_dma_dev_setup(struct device *dev)
 {
 	struct dev_archdata *archdata = &dev->archdata;
 
-	if (get_pci_dma_ops() == &dma_iommu_ops)
+	/* Order is important here, these are not mutually exclusive */
+	if (get_dma_ops(dev) == &dma_iommu_fixed_ops)
+		cell_dma_dev_setup_static(dev);
+	else if (get_pci_dma_ops() == &dma_iommu_ops)
 		cell_dma_dev_setup_iommu(dev);
 	else if (get_pci_dma_ops() == &dma_direct_ops)
 		archdata->dma_data = (void *)cell_dma_direct_offset;
@@ -752,6 +760,260 @@ static int __init cell_iommu_init_disabled(void)
 	return 0;
 }
 
+/*
+ *  Fixed IOMMU mapping support
+ *
+ *  This code adds support for setting up a fixed IOMMU mapping on certain
+ *  cell machines. For 64-bit devices this avoids the performance overhead of
+ *  mapping and unmapping pages at runtime. 32-bit devices are unable to use
+ *  the fixed mapping.
+ *
+ *  The fixed mapping is established at boot, and maps all of physical memory
+ *  1:1 into device space at some offset. On machines with < 30 GB of memory
+ *  we setup the fixed mapping immediately above the normal IOMMU window.
+ *
+ *  For example a machine with 4GB of memory would end up with the normal
+ *  IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In
+ *  this case a 64-bit device wishing to DMA to 1GB would be told to DMA to
+ *  3GB, plus any offset required by firmware. The firmware offset is encoded
+ *  in the "dma-ranges" property.
+ *
+ *  On machines with 30GB or more of memory, we are unable to place the fixed
+ *  mapping above the normal IOMMU window as we would run out of address space.
+ *  Instead we move the normal IOMMU window to coincide with the hash page
+ *  table, this region does not need to be part of the fixed mapping as no
+ *  device should ever be DMA'ing to it. We then setup the fixed mapping
+ *  from 0 to 32GB.
+ */
+
+static u64 cell_iommu_get_fixed_address(struct device *dev)
+{
+	u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR;
+	struct device_node *tmp, *np;
+	const u32 *ranges = NULL;
+	int i, len, best;
+
+	np = dev->archdata.of_node;
+	of_node_get(np);
+	ranges = of_get_property(np, "dma-ranges", &len);
+	while (!ranges && np) {
+		tmp = of_get_parent(np);
+		of_node_put(np);
+		np = tmp;
+		ranges = of_get_property(np, "dma-ranges", &len);
+	}
+
+	if (!ranges) {
+		dev_dbg(dev, "iommu: no dma-ranges found\n");
+		goto out;
+	}
+
+	len /= sizeof(u32);
+
+	/* dma-ranges format:
+	 * 1 cell:  pci space
+	 * 2 cells: pci address
+	 * 2 cells: parent address
+	 * 2 cells: size
+	 */
+	for (i = 0, best = -1, best_size = 0; i < len; i += 7) {
+		cpu_addr = of_translate_dma_address(np, ranges +i + 3);
+		size = of_read_number(ranges + i + 5, 2);
+
+		if (cpu_addr == 0 && size > best_size) {
+			best = i;
+			best_size = size;
+		}
+	}
+
+	if (best >= 0)
+		pci_addr = of_read_number(ranges + best + 1, 2);
+	else
+		dev_dbg(dev, "iommu: no suitable range found!\n");
+
+out:
+	of_node_put(np);
+
+	return pci_addr;
+}
+
+static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+		return -EIO;
+
+	if (dma_mask == DMA_BIT_MASK(64)) {
+		if (cell_iommu_get_fixed_address(dev) == OF_BAD_ADDR)
+			dev_dbg(dev, "iommu: 64-bit OK, but bad addr\n");
+		else {
+			dev_dbg(dev, "iommu: 64-bit OK, using fixed ops\n");
+			set_dma_ops(dev, &dma_iommu_fixed_ops);
+			cell_dma_dev_setup(dev);
+		}
+	} else {
+		dev_dbg(dev, "iommu: not 64-bit, using default ops\n");
+		set_dma_ops(dev, get_pci_dma_ops());
+	}
+
+	*dev->dma_mask = dma_mask;
+
+	return 0;
+}
+
+static void cell_dma_dev_setup_static(struct device *dev)
+{
+	struct dev_archdata *archdata = &dev->archdata;
+	u64 addr;
+
+	addr = cell_iommu_get_fixed_address(dev) + dma_iommu_fixed_base;
+	archdata->dma_data = (void *)addr;
+
+	dev_dbg(dev, "iommu: fixed addr = %lx\n", addr);
+}
+
+static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
+	struct device_node *np, unsigned long dbase, unsigned long dsize,
+	unsigned long fbase, unsigned long fsize)
+{
+	unsigned long base_pte, uaddr, *io_pte;
+	int i;
+
+	dma_iommu_fixed_base = fbase;
+
+	/* convert from bytes into page table indices */
+	dbase = dbase >> IOMMU_PAGE_SHIFT;
+	dsize = dsize >> IOMMU_PAGE_SHIFT;
+	fbase = fbase >> IOMMU_PAGE_SHIFT;
+	fsize = fsize >> IOMMU_PAGE_SHIFT;
+
+	pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
+
+	io_pte = iommu->ptab;
+	base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW
+		    | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
+
+	uaddr = 0;
+	for (i = fbase; i < fbase + fsize; i++, uaddr += IOMMU_PAGE_SIZE) {
+		/* Don't touch the dynamic region */
+		if (i >= dbase && i < (dbase + dsize)) {
+			pr_debug("iommu: static/dynamic overlap, skipping\n");
+			continue;
+		}
+		io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
+	}
+
+	mb();
+}
+
+static int __init cell_iommu_fixed_mapping_init(void)
+{
+	unsigned long dbase, dsize, fbase, fsize, hbase, hend;
+	struct cbe_iommu *iommu;
+	struct device_node *np;
+
+	/* The fixed mapping is only supported on axon machines */
+	np = of_find_node_by_name(NULL, "axon");
+	if (!np) {
+		pr_debug("iommu: fixed mapping disabled, no axons found\n");
+		return -1;
+	}
+
+	/* The default setup is to have the fixed mapping sit after the
+	 * dynamic region, so find the top of the largest IOMMU window
+	 * on any axon, then add the size of RAM and that's our max value.
+	 * If that is > 32GB we have to do other shennanigans.
+	 */
+	fbase = 0;
+	for_each_node_by_name(np, "axon") {
+		cell_iommu_get_window(np, &dbase, &dsize);
+		fbase = max(fbase, dbase + dsize);
+	}
+
+	fbase = _ALIGN_UP(fbase, 1 << IO_SEGMENT_SHIFT);
+	fsize = lmb_phys_mem_size();
+
+	if ((fbase + fsize) <= 0x800000000)
+		hbase = 0; /* use the device tree window */
+	else {
+		/* If we're over 32 GB we need to cheat. We can't map all of
+		 * RAM with the fixed mapping, and also fit the dynamic
+		 * region. So try to place the dynamic region where the hash
+		 * table sits, drivers never need to DMA to it, we don't
+		 * need a fixed mapping for that area.
+		 */
+		if (!htab_address) {
+			pr_debug("iommu: htab is NULL, on LPAR? Huh?\n");
+			return -1;
+		}
+		hbase = __pa(htab_address);
+		hend  = hbase + htab_size_bytes;
+
+		/* The window must start and end on a segment boundary */
+		if ((hbase != _ALIGN_UP(hbase, 1 << IO_SEGMENT_SHIFT)) ||
+		    (hend != _ALIGN_UP(hend, 1 << IO_SEGMENT_SHIFT))) {
+			pr_debug("iommu: hash window not segment aligned\n");
+			return -1;
+		}
+
+		/* Check the hash window fits inside the real DMA window */
+		for_each_node_by_name(np, "axon") {
+			cell_iommu_get_window(np, &dbase, &dsize);
+
+			if (hbase < dbase || (hend > (dbase + dsize))) {
+				pr_debug("iommu: hash window doesn't fit in"
+					 "real DMA window\n");
+				return -1;
+			}
+		}
+
+		fbase = 0;
+	}
+
+	/* Setup the dynamic regions */
+	for_each_node_by_name(np, "axon") {
+		iommu = cell_iommu_alloc(np);
+		BUG_ON(!iommu);
+
+		if (hbase == 0)
+			cell_iommu_get_window(np, &dbase, &dsize);
+		else {
+			dbase = hbase;
+			dsize = htab_size_bytes;
+		}
+
+		pr_debug("iommu: setting up %d, dynamic window %lx-%lx " \
+			 "fixed window %lx-%lx\n", iommu->nid, dbase,
+			 dbase + dsize, fbase, fbase + fsize);
+
+		cell_iommu_setup_page_tables(iommu, dbase, dsize, fbase, fsize);
+		cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize,
+					     fbase, fsize);
+		cell_iommu_enable_hardware(iommu);
+		cell_iommu_setup_window(iommu, np, dbase, dsize, 0);
+	}
+
+	dma_iommu_fixed_ops = dma_direct_ops;
+	dma_iommu_fixed_ops.set_dma_mask = dma_set_mask_and_switch;
+
+	dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch;
+	set_pci_dma_ops(&dma_iommu_ops);
+
+	printk(KERN_DEBUG "IOMMU fixed mapping established.\n");
+
+	return 0;
+}
+
+static int iommu_fixed_disabled;
+
+static int __init setup_iommu_fixed(char *str)
+{
+	if (strcmp(str, "off") == 0)
+		iommu_fixed_disabled = 1;
+
+	return 1;
+}
+__setup("iommu_fixed=", setup_iommu_fixed);
+
 static int __init cell_iommu_init(void)
 {
 	struct device_node *np;
@@ -771,6 +1033,9 @@ static int __init cell_iommu_init(void)
 	ppc_md.tce_build = tce_build_cell;
 	ppc_md.tce_free = tce_free_cell;
 
+	if (!iommu_fixed_disabled && cell_iommu_fixed_mapping_init() == 0)
+		goto bail;
+
 	/* Create an iommu for each /axon node.  */
 	for_each_node_by_name(np, "axon") {
 		if (np->parent == NULL || np->parent->parent != NULL)
-- 
1.5.3.7.1.g4e596e



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-29 15:50       ` Olof Johansson
@ 2008-01-30  0:54         ` Arnd Bergmann
  2008-01-30  0:58           ` Olof Johansson
  0 siblings, 1 reply; 21+ messages in thread
From: Arnd Bergmann @ 2008-01-30  0:54 UTC (permalink / raw)
  To: linuxppc-dev

On Tuesday 29 January 2008, Olof Johansson wrote:
> 
> > > Shouldn't the fixed mapping be between 4G and 8G (and the offset for 1G
> > > is at 5G), to account for the MMIO range at 2-4G?
> > 
> > I don't think so, ie. it works setup like that, but I'm not entirely
> > sure why. Presumably the 2-4GB for MMIO is only for cycles heading out
> > of the CPU.
> 
> Ben denied that being so yesterday. :-)
> 
> If that's the case, then you can stick the dynamic range there for >32GB
> configs, since it's still addressable with 32 bits.
> 

For addresses going from the CPU to the bus, RAM is occupying everything
from zero to SIZE_OF_RAM, while PCI MMIO starts at LARGE_NUMBER+2GB.

As seen from the PCI bus, DMA addresses for RAM range from zero to 2GB,
while the MMIO space is between 2GB and 4GB. The 64 bit space for
the linear mapping is between EVEN_LARGER_NUMBER and
EVEN_LARGER_NUMBER+SIZE_OF_RAM.

The bridge chip remaps EVEN_LARGER_NUMBER to zero when going into the IOMMU,
so that the IOMMU can fit both SIZE_OF_RAM and the dynamic DMA window
into the 32GB bus address range.

I don't see how it should be possible here to reuse the 2-4GB range
for anything else.

	Arnd <><

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 8/8] Cell IOMMU fixed mapping support
  2008-01-30  0:54         ` Arnd Bergmann
@ 2008-01-30  0:58           ` Olof Johansson
  0 siblings, 0 replies; 21+ messages in thread
From: Olof Johansson @ 2008-01-30  0:58 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev

On Wed, Jan 30, 2008 at 01:54:01AM +0100, Arnd Bergmann wrote:

> I don't see how it should be possible here to reuse the 2-4GB range
> for anything else.

Right, that was obvious after Ben's reply as well. Michael's description
made me think the linear mapping was at bus address 2G when it wasn't.


-Olof

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/8] Split out the logic that allocates struct iommus
  2008-01-29 14:13 ` [PATCH 3/8] Split out the logic that allocates struct iommus Michael Ellerman
@ 2008-02-05  0:23   ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 21+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05  0:23 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev


On Wed, 2008-01-30 at 01:13 +1100, Michael Ellerman wrote:
> Split out the logic that allocates a struct iommu into a separate
> function. This can fail however the calling code has never cared - so
> just return if we can't allocate an iommu.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> ---
>  arch/powerpc/platforms/cell/iommu.c |   20 ++++++++++++++++----
>  1 files changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
> index 9223559..4f1ca43 100644
> --- a/arch/powerpc/platforms/cell/iommu.c
> +++ b/arch/powerpc/platforms/cell/iommu.c
> @@ -565,10 +565,9 @@ static int __init cell_iommu_get_window(struct device_node *np,
>  	return 0;
>  }
>  
> -static void __init cell_iommu_init_one(struct device_node *np, unsigned long offset)
> +static struct cbe_iommu * __init cell_iommu_alloc(struct device_node *np)
>  {
>  	struct cbe_iommu *iommu;
> -	unsigned long base, size;
>  	int nid, i;
>  
>  	/* Get node ID */
> @@ -576,7 +575,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off
>  	if (nid < 0) {
>  		printk(KERN_ERR "iommu: failed to get node for %s\n",
>  		       np->full_name);
> -		return;
> +		return NULL;
>  	}
>  	pr_debug("iommu: setting up iommu for node %d (%s)\n",
>  		 nid, np->full_name);
> @@ -592,7 +591,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off
>  	if (cbe_nr_iommus >= NR_IOMMUS) {
>  		printk(KERN_ERR "iommu: too many IOMMUs detected ! (%s)\n",
>  		       np->full_name);
> -		return;
> +		return NULL;
>  	}
>  
>  	/* Init base fields */
> @@ -603,6 +602,19 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off
>  	snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i);
>  	INIT_LIST_HEAD(&iommu->windows);
>  
> +	return iommu;
> +}
> +
> +static void __init cell_iommu_init_one(struct device_node *np,
> +				       unsigned long offset)
> +{
> +	struct cbe_iommu *iommu;
> +	unsigned long base, size;
> +
> +	iommu = cell_iommu_alloc(np);
> +	if (!iommu)
> +		return;
> +
>  	/* Obtain a window for it */
>  	cell_iommu_get_window(np, &base, &size);
>  

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/8] Split out the IOMMU logic from cell_dma_dev_setup()
  2008-01-29 14:14 ` [PATCH 5/8] Split out the IOMMU logic from cell_dma_dev_setup() Michael Ellerman
@ 2008-02-05  0:26   ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 21+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05  0:26 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev


On Wed, 2008-01-30 at 01:14 +1100, Michael Ellerman wrote:
> Split the IOMMU logic out from cell_dma_dev_setup() into a separate
> function. If we're not using dma_direct_ops or dma_iommu_ops we don't
> know what the hell's going on, so BUG.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> ---
>  arch/powerpc/platforms/cell/iommu.c |   19 +++++++++++++------
>  1 files changed, 13 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
> index a86e5bb..e9769fc 100644
> --- a/arch/powerpc/platforms/cell/iommu.c
> +++ b/arch/powerpc/platforms/cell/iommu.c
> @@ -507,17 +507,12 @@ static struct cbe_iommu *cell_iommu_for_node(int nid)
>  
>  static unsigned long cell_dma_direct_offset;
>  
> -static void cell_dma_dev_setup(struct device *dev)
> +static void cell_dma_dev_setup_iommu(struct device *dev)
>  {
>  	struct iommu_window *window;
>  	struct cbe_iommu *iommu;
>  	struct dev_archdata *archdata = &dev->archdata;
>  
> -	if (get_pci_dma_ops() == &dma_direct_ops) {
> -		archdata->dma_data = (void *)cell_dma_direct_offset;
> -		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
> @@ -534,6 +529,18 @@ static void cell_dma_dev_setup(struct device *dev)
>  	archdata->dma_data = &window->table;
>  }
>  
> +static void cell_dma_dev_setup(struct device *dev)
> +{
> +	struct dev_archdata *archdata = &dev->archdata;
> +
> +	if (get_pci_dma_ops() == &dma_iommu_ops)
> +		cell_dma_dev_setup_iommu(dev);
> +	else if (get_pci_dma_ops() == &dma_direct_ops)
> +		archdata->dma_data = (void *)cell_dma_direct_offset;
> +	else
> +		BUG();
> +}
> +
>  static void cell_pci_dma_dev_setup(struct pci_dev *dev)
>  {
>  	cell_dma_dev_setup(&dev->dev);

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 6/8] Add support to cell_iommu_setup_page_tables() for multiple windows
  2008-01-29 14:14 ` [PATCH 6/8] Add support to cell_iommu_setup_page_tables() for multiple windows Michael Ellerman
@ 2008-02-05  0:26   ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 21+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05  0:26 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev


On Wed, 2008-01-30 at 01:14 +1100, Michael Ellerman wrote:
> Add support to cell_iommu_setup_page_tables() for handling two windows,
> the dynamic window and the fixed window. A fixed window size of 0
> indicates that there is no fixed window at all.
> 
> Currently there are no callers who pass a non-zero fixed window, but the
> upcoming fixed IOMMU mapping patch will change that.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> ---
>  arch/powerpc/platforms/cell/iommu.c |   15 ++++++++++-----
>  1 files changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
> index e9769fc..7779dbf 100644
> --- a/arch/powerpc/platforms/cell/iommu.c
> +++ b/arch/powerpc/platforms/cell/iommu.c
> @@ -307,14 +307,19 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)
>  }
>  
>  static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
> -					 unsigned long base, unsigned long size)
> +				unsigned long dbase, unsigned long dsize,
> +				unsigned long fbase, unsigned long fsize)
>  {
>  	struct page *page;
>  	int i;
>  	unsigned long reg, segments, pages_per_segment, ptab_size, stab_size,
> -		      n_pte_pages;
> +		      n_pte_pages, base;
>  
> -	segments = size >> IO_SEGMENT_SHIFT;
> +	base = dbase;
> +	if (fsize != 0)
> +		base = min(fbase, dbase);
> +
> +	segments = max(dbase + dsize, fbase + fsize) >> IO_SEGMENT_SHIFT;
>  	pages_per_segment = 1ull << IO_PAGENO_BITS;
>  
>  	pr_debug("%s: iommu[%d]: segments: %lu, pages per segment: %lu\n",
> @@ -366,7 +371,7 @@ static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
>  	}
>  
>  	pr_debug("Setting up IOMMU stab:\n");
> -	for (i = 0; i * (1ul << IO_SEGMENT_SHIFT) < size; i++) {
> +	for (i = base >> IO_SEGMENT_SHIFT; i < segments; 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]);
> @@ -417,7 +422,7 @@ static void cell_iommu_enable_hardware(struct cbe_iommu *iommu)
>  static void cell_iommu_setup_hardware(struct cbe_iommu *iommu,
>  	unsigned long base, unsigned long size)
>  {
> -	cell_iommu_setup_page_tables(iommu, base, size);
> +	cell_iommu_setup_page_tables(iommu, base, size, 0, 0);
>  	cell_iommu_enable_hardware(iommu);
>  }
>  

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 7/8] Split out the ioid fetching/checking logic
  2008-01-29 14:14 ` [PATCH 7/8] Split out the ioid fetching/checking logic Michael Ellerman
@ 2008-02-05  0:27   ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 21+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05  0:27 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev


On Wed, 2008-01-30 at 01:14 +1100, Michael Ellerman wrote:
> Split out the ioid fetching and checking logic so we can use it elsewhere
> in a subsequent patch.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> ---
>  arch/powerpc/platforms/cell/iommu.c |   23 +++++++++++++++++------
>  1 files changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
> index 7779dbf..3baade1 100644
> --- a/arch/powerpc/platforms/cell/iommu.c
> +++ b/arch/powerpc/platforms/cell/iommu.c
> @@ -443,25 +443,36 @@ static struct iommu_window *find_window(struct cbe_iommu *iommu,
>  }
>  #endif
>  
> +static inline u32 cell_iommu_get_ioid(struct device_node *np)
> +{
> +	const u32 *ioid;
> +
> +	ioid = of_get_property(np, "ioid", NULL);
> +	if (ioid == NULL) {
> +		printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
> +		       np->full_name);
> +		return 0;
> +	}
> +
> +	return *ioid;
> +}
> +
>  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 iommu_window *window;
> -	const unsigned int *ioid;
> +	u32 ioid;
>  
> -	ioid = of_get_property(np, "ioid", NULL);
> -	if (ioid == NULL)
> -		printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
> -		       np->full_name);
> +	ioid = cell_iommu_get_ioid(np);
>  
>  	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->ioid = ioid;
>  	window->iommu = iommu;
>  	window->pte_offset = pte_offset;
>  

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2008-02-05  0:27 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-29 14:13 [PATCH 1/8] Add set_dma_ops() to match get_dma_ops() Michael Ellerman
2008-01-29 14:13 ` [PATCH 3/8] Split out the logic that allocates struct iommus Michael Ellerman
2008-02-05  0:23   ` Benjamin Herrenschmidt
2008-01-29 14:13 ` [PATCH 2/8] Allocate the hash table under 1G on cell Michael Ellerman
2008-01-29 14:14 ` [PATCH 4/8] Split cell_iommu_setup_hardware() into two parts Michael Ellerman
2008-01-29 14:14 ` [PATCH 6/8] Add support to cell_iommu_setup_page_tables() for multiple windows Michael Ellerman
2008-02-05  0:26   ` Benjamin Herrenschmidt
2008-01-29 14:14 ` [PATCH 5/8] Split out the IOMMU logic from cell_dma_dev_setup() Michael Ellerman
2008-02-05  0:26   ` Benjamin Herrenschmidt
2008-01-29 14:14 ` [PATCH 7/8] Split out the ioid fetching/checking logic Michael Ellerman
2008-02-05  0:27   ` Benjamin Herrenschmidt
2008-01-29 14:14 ` [PATCH 8/8] Cell IOMMU fixed mapping support Michael Ellerman
2008-01-29 15:15   ` Olof Johansson
2008-01-29 15:13     ` Michael Ellerman
2008-01-29 15:50       ` Olof Johansson
2008-01-30  0:54         ` Arnd Bergmann
2008-01-30  0:58           ` Olof Johansson
2008-01-29 21:18       ` Benjamin Herrenschmidt
2008-01-29 21:36         ` Olof Johansson
2008-01-29 23:56           ` Michael Ellerman
2008-01-30  0:03   ` Michael Ellerman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).