* [PATCH 2/8] Use it_offset not pte_offset in cell IOMMU code
2008-02-27 7:28 [PATCH 1/8] Clearup cell IOMMU fixed mapping terminology Michael Ellerman
@ 2008-02-27 7:28 ` Michael Ellerman
2008-02-27 7:28 ` [PATCH 3/8] Remove unused pte_offset variable Michael Ellerman
` (5 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 7:28 UTC (permalink / raw)
To: linuxppc-dev
The cell IOMMU tce build and free routines use pte_offset to convert
the index passed from the generic IOMMU code into a page table offset.
This takes into account the SPIDER_DMA_OFFSET which sets the top bit
of every DMA address.
However it doesn't cater for the IOMMU window starting at a non-zero
address, as the base of the window is not incorporated into pte_offset
at all.
As it turns out tbl->it_offset already contains the value we need, it
takes into account the base of the window and also pte_offset. So use
it instead!
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/iommu.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index bbe8389..4e75919 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -200,7 +200,7 @@ static void tce_build_cell(struct iommu_table *tbl, long index, long npages,
(window->ioid & IOPTE_IOID_Mask);
#endif
- io_pte = (unsigned long *)tbl->it_base + (index - window->pte_offset);
+ io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
@@ -232,7 +232,7 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
| (window->ioid & IOPTE_IOID_Mask);
#endif
- io_pte = (unsigned long *)tbl->it_base + (index - window->pte_offset);
+ io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
for (i = 0; i < npages; i++)
io_pte[i] = pte;
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 3/8] Remove unused pte_offset variable
2008-02-27 7:28 [PATCH 1/8] Clearup cell IOMMU fixed mapping terminology Michael Ellerman
2008-02-27 7:28 ` [PATCH 2/8] Use it_offset not pte_offset in cell IOMMU code Michael Ellerman
@ 2008-02-27 7:28 ` Michael Ellerman
2008-02-27 8:04 ` Benjamin Herrenschmidt
2008-02-27 7:28 ` [PATCH 5/8] Split setup of IOMMU stab and ptab, allocate dynamic/fixed ptabs separately Michael Ellerman
` (4 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 7:28 UTC (permalink / raw)
To: linuxppc-dev
The cell IOMMU code no longer needs to save the pte_offset variable
separately, it is incorporated into tbl->it_offset.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/iommu.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 4e75919..555d264 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -123,7 +123,6 @@ struct iommu_window {
struct cbe_iommu *iommu;
unsigned long offset;
unsigned long size;
- unsigned long pte_offset;
unsigned int ioid;
struct iommu_table table;
};
@@ -475,13 +474,11 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
window->size = size;
window->ioid = ioid;
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_offset = (offset >> IOMMU_PAGE_SHIFT) + pte_offset;
window->table.it_size = size >> IOMMU_PAGE_SHIFT;
iommu_init_table(&window->table, iommu->nid);
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH 3/8] Remove unused pte_offset variable
2008-02-27 7:28 ` [PATCH 3/8] Remove unused pte_offset variable Michael Ellerman
@ 2008-02-27 8:04 ` Benjamin Herrenschmidt
2008-02-27 8:11 ` Michael Ellerman
0 siblings, 1 reply; 12+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-27 8:04 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
On Wed, 2008-02-27 at 18:28 +1100, Michael Ellerman wrote:
> The cell IOMMU code no longer needs to save the pte_offset variable
> separately, it is incorporated into tbl->it_offset.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
> ---
Do this work on spider ?
There is a subtle difference with spider is that the 0x80000000 you give
to devices disappears when reaching the iommu (so isn't to be catered
in the iommu offset).
It's a bit like the offset you have to add to the direct mapping on
axon, in fact (the 0x8000060000000000 or so ...)
Ben.
> arch/powerpc/platforms/cell/iommu.c | 5 +----
> 1 files changed, 1 insertions(+), 4 deletions(-)
>
> diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
> index 4e75919..555d264 100644
> --- a/arch/powerpc/platforms/cell/iommu.c
> +++ b/arch/powerpc/platforms/cell/iommu.c
> @@ -123,7 +123,6 @@ struct iommu_window {
> struct cbe_iommu *iommu;
> unsigned long offset;
> unsigned long size;
> - unsigned long pte_offset;
> unsigned int ioid;
> struct iommu_table table;
> };
> @@ -475,13 +474,11 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
> window->size = size;
> window->ioid = ioid;
> 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_offset = (offset >> IOMMU_PAGE_SHIFT) + pte_offset;
> window->table.it_size = size >> IOMMU_PAGE_SHIFT;
>
> iommu_init_table(&window->table, iommu->nid);
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 3/8] Remove unused pte_offset variable
2008-02-27 8:04 ` Benjamin Herrenschmidt
@ 2008-02-27 8:11 ` Michael Ellerman
2008-02-27 8:18 ` Benjamin Herrenschmidt
0 siblings, 1 reply; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 8:11 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 1285 bytes --]
On Wed, 2008-02-27 at 19:04 +1100, Benjamin Herrenschmidt wrote:
> On Wed, 2008-02-27 at 18:28 +1100, Michael Ellerman wrote:
> > The cell IOMMU code no longer needs to save the pte_offset variable
> > separately, it is incorporated into tbl->it_offset.
> >
> > Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
> > ---
>
> Do this work on spider ?
>
> There is a subtle difference with spider is that the 0x80000000 you give
> to devices disappears when reaching the iommu (so isn't to be catered
> in the iommu offset).
>
> It's a bit like the offset you have to add to the direct mapping on
> axon, in fact (the 0x8000060000000000 or so ...)
I'm pretty sure I tested it and it worked.
But I didn't actually change anything WRT the spider offset anyway, we
still add it to it_offset just like we used to, it's just we don't put
it in the window and then pull it out again.
The only thing that's changed is we now use offset (aka. base) in the
tce routines in addition to pte_offset.
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] 12+ messages in thread
* Re: [PATCH 3/8] Remove unused pte_offset variable
2008-02-27 8:11 ` Michael Ellerman
@ 2008-02-27 8:18 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 12+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-27 8:18 UTC (permalink / raw)
To: michael; +Cc: linuxppc-dev
On Wed, 2008-02-27 at 19:11 +1100, Michael Ellerman wrote:
> I'm pretty sure I tested it and it worked.
>
> But I didn't actually change anything WRT the spider offset anyway, we
> still add it to it_offset just like we used to, it's just we don't put
> it in the window and then pull it out again.
>
> The only thing that's changed is we now use offset (aka. base) in the
> tce routines in addition to pte_offset.
Ok. Should be fine then.
Ben.
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 5/8] Split setup of IOMMU stab and ptab, allocate dynamic/fixed ptabs separately
2008-02-27 7:28 [PATCH 1/8] Clearup cell IOMMU fixed mapping terminology Michael Ellerman
2008-02-27 7:28 ` [PATCH 2/8] Use it_offset not pte_offset in cell IOMMU code Michael Ellerman
2008-02-27 7:28 ` [PATCH 3/8] Remove unused pte_offset variable Michael Ellerman
@ 2008-02-27 7:28 ` Michael Ellerman
2008-02-27 7:28 ` [PATCH 4/8] Move allocation of cell IOMMU pad page Michael Ellerman
` (3 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 7:28 UTC (permalink / raw)
To: linuxppc-dev
Currently the cell IOMMU code allocates the entire IOMMU page table in a
contiguous chunk. This is nice and tidy, but for machines with larger
amounts of RAM the page table allocation can fail due to it simply being
too large.
So split the segment table and page table setup routine, and arrange to
have the dynamic and fixed page tables allocated separately.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/iommu.c | 62 ++++++++++++++++++++--------------
1 files changed, 36 insertions(+), 26 deletions(-)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 8e57e1a..2c703f6 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -306,50 +306,53 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)
return -ENODEV;
}
-static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
+static void cell_iommu_setup_stab(struct cbe_iommu *iommu,
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, base;
-
- base = dbase;
- if (fsize != 0)
- base = min(fbase, dbase);
+ unsigned long segments, stab_size;
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",
- __FUNCTION__, iommu->nid, segments, pages_per_segment);
+ pr_debug("%s: iommu[%d]: segments: %lu\n",
+ __FUNCTION__, iommu->nid, segments);
/* set up the segment table */
stab_size = segments * sizeof(unsigned long);
page = alloc_pages_node(iommu->nid, GFP_KERNEL, get_order(stab_size));
BUG_ON(!page);
iommu->stab = page_address(page);
- clear_page(iommu->stab);
+ memset(iommu->stab, 0, stab_size);
+}
+
+static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
+ unsigned long base, unsigned long size)
+{
+ struct page *page;
+ int i;
+ unsigned long reg, segments, pages_per_segment, ptab_size,
+ n_pte_pages, start_seg, *ptab;
+
+ start_seg = base >> IO_SEGMENT_SHIFT;
+ segments = size >> IO_SEGMENT_SHIFT;
+ pages_per_segment = 1ull << IO_PAGENO_BITS;
- /* ... 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);
+ ptab = page_address(page);
+ memset(ptab, 0, ptab_size);
/* 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,
+ __FUNCTION__, iommu->nid, iommu->stab, ptab,
n_pte_pages);
/* initialise the STEs */
@@ -365,11 +368,13 @@ static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
}
pr_debug("Setting up IOMMU stab:\n");
- for (i = base >> IO_SEGMENT_SHIFT; i < segments; i++) {
- iommu->stab[i] = reg |
- (__pa(iommu->ptab) + n_pte_pages * IOMMU_PAGE_SIZE * i);
+ for (i = start_seg; i < (start_seg + segments); i++) {
+ iommu->stab[i] = reg | (__pa(ptab) + n_pte_pages *
+ IOMMU_PAGE_SIZE * (i - start_seg));
pr_debug("\t[%d] 0x%016lx\n", i, iommu->stab[i]);
}
+
+ return ptab;
}
static void cell_iommu_enable_hardware(struct cbe_iommu *iommu)
@@ -416,7 +421,8 @@ 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, 0, 0);
+ cell_iommu_setup_stab(iommu, base, size, 0, 0);
+ iommu->ptab = cell_iommu_alloc_ptab(iommu, base, size);
cell_iommu_enable_hardware(iommu);
}
@@ -870,8 +876,10 @@ 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;
+ unsigned long base_pte, uaddr, *io_pte, *ptab;
+
+ ptab = cell_iommu_alloc_ptab(iommu, fbase, fsize);
dma_iommu_fixed_base = fbase;
@@ -883,7 +891,7 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
- io_pte = iommu->ptab;
+ io_pte = ptab;
base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW
| (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
@@ -894,7 +902,7 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
pr_debug("iommu: fixed/dynamic overlap, skipping\n");
continue;
}
- io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
+ io_pte[i - fbase] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
}
mb();
@@ -992,7 +1000,9 @@ static int __init cell_iommu_fixed_mapping_init(void)
"fixed window 0x%lx-0x%lx\n", iommu->nid, dbase,
dbase + dsize, fbase, fbase + fsize);
- cell_iommu_setup_page_tables(iommu, dbase, dsize, fbase, fsize);
+ cell_iommu_setup_stab(iommu, dbase, dsize, fbase, fsize);
+ iommu->ptab = cell_iommu_alloc_ptab(iommu, dbase, dsize,
+ IOMMU_PAGE_SHIFT);
cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize,
fbase, fsize);
cell_iommu_enable_hardware(iommu);
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 4/8] Move allocation of cell IOMMU pad page
2008-02-27 7:28 [PATCH 1/8] Clearup cell IOMMU fixed mapping terminology Michael Ellerman
` (2 preceding siblings ...)
2008-02-27 7:28 ` [PATCH 5/8] Split setup of IOMMU stab and ptab, allocate dynamic/fixed ptabs separately Michael Ellerman
@ 2008-02-27 7:28 ` Michael Ellerman
2008-02-27 7:28 ` [PATCH 6/8] Cell IOMMU: n_pte_pages is in 4K page units, not IOMMU_PAGE_SIZE Michael Ellerman
` (2 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 7:28 UTC (permalink / raw)
To: linuxppc-dev
There's no need to allocate the pad page unless we're going to actually
use it - so move the allocation to where we know we're going to use it.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/iommu.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 555d264..8e57e1a 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -344,12 +344,6 @@ static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu,
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;
@@ -463,6 +457,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
unsigned long pte_offset)
{
struct iommu_window *window;
+ struct page *page;
u32 ioid;
ioid = cell_iommu_get_ioid(np);
@@ -501,6 +496,11 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
* This code also assumes that we have a window that starts at 0,
* which is the case on all spider based blades.
*/
+ page = alloc_pages_node(iommu->nid, GFP_KERNEL, 0);
+ BUG_ON(!page);
+ iommu->pad_page = page_address(page);
+ clear_page(iommu->pad_page);
+
__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);
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 6/8] Cell IOMMU: n_pte_pages is in 4K page units, not IOMMU_PAGE_SIZE
2008-02-27 7:28 [PATCH 1/8] Clearup cell IOMMU fixed mapping terminology Michael Ellerman
` (3 preceding siblings ...)
2008-02-27 7:28 ` [PATCH 4/8] Move allocation of cell IOMMU pad page Michael Ellerman
@ 2008-02-27 7:28 ` Michael Ellerman
2008-02-27 7:28 ` [PATCH 7/8] Allow for different IOMMU page sizes in cell IOMMU code Michael Ellerman
2008-02-27 7:28 ` [PATCH 8/8] Convert the cell IOMMU fixed mapping to 16M IOMMU pages Michael Ellerman
6 siblings, 0 replies; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 7:28 UTC (permalink / raw)
To: linuxppc-dev
We use n_pte_pages to calculate the stride through the page tables, but
we also use it to set the NPPT value in the segment table entry. That is
defined as the number of 4K pages per segment, so we should calculate
it as such regardless of the IOMMU page size.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/iommu.c | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 2c703f6..a7bbc0a 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -347,9 +347,8 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
ptab = page_address(page);
memset(ptab, 0, ptab_size);
- /* number of pages needed for a page table */
- n_pte_pages = (pages_per_segment *
- sizeof(unsigned long)) >> IOMMU_PAGE_SHIFT;
+ /* number of 4K pages needed for a page table */
+ n_pte_pages = (pages_per_segment * sizeof(unsigned long)) >> 12;
pr_debug("%s: iommu[%d]: stab at %p, ptab at %p, n_pte_pages: %lu\n",
__FUNCTION__, iommu->nid, iommu->stab, ptab,
@@ -369,8 +368,8 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
pr_debug("Setting up IOMMU stab:\n");
for (i = start_seg; i < (start_seg + segments); i++) {
- iommu->stab[i] = reg | (__pa(ptab) + n_pte_pages *
- IOMMU_PAGE_SIZE * (i - start_seg));
+ iommu->stab[i] = reg | (__pa(ptab) + (n_pte_pages << 12) *
+ (i - start_seg));
pr_debug("\t[%d] 0x%016lx\n", i, iommu->stab[i]);
}
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 7/8] Allow for different IOMMU page sizes in cell IOMMU code
2008-02-27 7:28 [PATCH 1/8] Clearup cell IOMMU fixed mapping terminology Michael Ellerman
` (4 preceding siblings ...)
2008-02-27 7:28 ` [PATCH 6/8] Cell IOMMU: n_pte_pages is in 4K page units, not IOMMU_PAGE_SIZE Michael Ellerman
@ 2008-02-27 7:28 ` Michael Ellerman
2008-02-27 7:28 ` [PATCH 8/8] Convert the cell IOMMU fixed mapping to 16M IOMMU pages Michael Ellerman
6 siblings, 0 replies; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 7:28 UTC (permalink / raw)
To: linuxppc-dev
Make some preliminary changes to cell_iommu_alloc_ptab() to allow it to
take the page size as a parameter rather than assuming IOMMU_PAGE_SIZE.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/iommu.c | 28 ++++++++++++++++------------
1 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index a7bbc0a..12db681 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -113,7 +113,7 @@
/* IOMMU sizing */
#define IO_SEGMENT_SHIFT 28
-#define IO_PAGENO_BITS (IO_SEGMENT_SHIFT - IOMMU_PAGE_SHIFT)
+#define IO_PAGENO_BITS(shift) (IO_SEGMENT_SHIFT - (shift))
/* The high bit needs to be set on every DMA address */
#define SPIDER_DMA_OFFSET 0x80000000ul
@@ -327,7 +327,8 @@ static void cell_iommu_setup_stab(struct cbe_iommu *iommu,
}
static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
- unsigned long base, unsigned long size)
+ unsigned long base, unsigned long size,
+ unsigned long page_shift)
{
struct page *page;
int i;
@@ -336,7 +337,10 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
start_seg = base >> IO_SEGMENT_SHIFT;
segments = size >> IO_SEGMENT_SHIFT;
- pages_per_segment = 1ull << IO_PAGENO_BITS;
+ pages_per_segment = 1ull << IO_PAGENO_BITS(page_shift);
+ /* PTEs for each segment must start on a 4K bounday */
+ pages_per_segment = max(pages_per_segment,
+ (1 << 12) / sizeof(unsigned long));
ptab_size = segments * pages_per_segment * sizeof(unsigned long);
pr_debug("%s: iommu[%d]: ptab_size: %lu, order: %d\n", __FUNCTION__,
@@ -357,13 +361,12 @@ static unsigned long *cell_iommu_alloc_ptab(struct cbe_iommu *iommu,
/* 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();
+ switch (page_shift) {
+ case 12: reg |= IOSTE_PS_4K; break;
+ case 16: reg |= IOSTE_PS_64K; break;
+ case 20: reg |= IOSTE_PS_1M; break;
+ case 24: reg |= IOSTE_PS_16M; break;
+ default: BUG();
}
pr_debug("Setting up IOMMU stab:\n");
@@ -421,7 +424,8 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu,
unsigned long base, unsigned long size)
{
cell_iommu_setup_stab(iommu, base, size, 0, 0);
- iommu->ptab = cell_iommu_alloc_ptab(iommu, base, size);
+ iommu->ptab = cell_iommu_alloc_ptab(iommu, base, size,
+ IOMMU_PAGE_SHIFT);
cell_iommu_enable_hardware(iommu);
}
@@ -878,7 +882,7 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
int i;
unsigned long base_pte, uaddr, *io_pte, *ptab;
- ptab = cell_iommu_alloc_ptab(iommu, fbase, fsize);
+ ptab = cell_iommu_alloc_ptab(iommu, fbase, fsize, IOMMU_PAGE_SHIFT);
dma_iommu_fixed_base = fbase;
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 8/8] Convert the cell IOMMU fixed mapping to 16M IOMMU pages
2008-02-27 7:28 [PATCH 1/8] Clearup cell IOMMU fixed mapping terminology Michael Ellerman
` (5 preceding siblings ...)
2008-02-27 7:28 ` [PATCH 7/8] Allow for different IOMMU page sizes in cell IOMMU code Michael Ellerman
@ 2008-02-27 7:28 ` Michael Ellerman
6 siblings, 0 replies; 12+ messages in thread
From: Michael Ellerman @ 2008-02-27 7:28 UTC (permalink / raw)
To: linuxppc-dev
The only tricky part is we need to adjust the PTE insertion loop to
cater for holes in the page table. The PTEs for each segment start on
a 4K boundary, so with 16M pages we have 16 PTEs per segment and then
a gap to the next 4K page boundary.
It might be possible to allocate the PTEs for each segment separately,
saving the memory currently filling the gaps. However we'd need to
check that's OK with the hardware, and that it actually saves memory.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/iommu.c | 36 +++++++++++++++++++++-------------
1 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 12db681..0e82255 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -875,37 +875,45 @@ static void cell_dma_dev_setup_fixed(struct device *dev)
dev_dbg(dev, "iommu: fixed addr = %lx\n", addr);
}
+static void insert_16M_pte(unsigned long addr, unsigned long *ptab,
+ unsigned long base_pte)
+{
+ unsigned long segment, offset;
+
+ segment = addr >> IO_SEGMENT_SHIFT;
+ offset = (addr >> 24) - (segment << IO_PAGENO_BITS(24));
+ ptab = ptab + (segment * (1 << 12) / sizeof(unsigned long));
+
+ pr_debug("iommu: addr %lx ptab %p segment %lx offset %lx\n",
+ addr, ptab, segment, offset);
+
+ ptab[offset] = base_pte | (__pa(addr) & IOPTE_RPN_Mask);
+}
+
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)
{
- int i;
- unsigned long base_pte, uaddr, *io_pte, *ptab;
+ unsigned long base_pte, uaddr, ioaddr, *ptab;
- ptab = cell_iommu_alloc_ptab(iommu, fbase, fsize, IOMMU_PAGE_SHIFT);
+ ptab = cell_iommu_alloc_ptab(iommu, fbase, fsize, 24);
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 = 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) {
+ for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) {
/* Don't touch the dynamic region */
- if (i >= dbase && i < (dbase + dsize)) {
+ ioaddr = uaddr + fbase;
+ if (ioaddr >= dbase && ioaddr < (dbase + dsize)) {
pr_debug("iommu: fixed/dynamic overlap, skipping\n");
continue;
}
- io_pte[i - fbase] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
+
+ insert_16M_pte(uaddr, ptab, base_pte);
}
mb();
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 12+ messages in thread