From: Michael Ellerman <hidden> Date: 2008-01-29 14:13:59
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 <redacted>
---
arch/powerpc/mm/hash_utils_64.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)
@@ -505,9 +505,15 @@ void __init htab_initialize(void)_SDR1=0;}else{/* Find storage for the HPT. Must be contiguous in-*theabsoluteaddressspace.+*theabsoluteaddressspace.Oncellwewantittobe+*inthefirst1Gig.*/-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);
From: Michael Ellerman <hidden> Date: 2008-01-29 14:13:59
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 <redacted>
---
arch/powerpc/platforms/cell/iommu.c | 20 ++++++++++++++++----
1 files changed, 16 insertions(+), 4 deletions(-)
@@ -565,10 +565,9 @@ static int __init cell_iommu_get_window(struct device_node *np,return0;}-staticvoid__initcell_iommu_init_one(structdevice_node*np,unsignedlongoffset)+staticstructcbe_iommu*__initcell_iommu_alloc(structdevice_node*np){structcbe_iommu*iommu;-unsignedlongbase,size;intnid,i;/* Get node ID */
@@ -576,7 +575,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long offif(nid<0){printk(KERN_ERR"iommu: failed to get node for %s\n",np->full_name);-return;+returnNULL;}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 offif(cbe_nr_iommus>=NR_IOMMUS){printk(KERN_ERR"iommu: too many IOMMUs detected ! (%s)\n",np->full_name);-return;+returnNULL;}/* Init base fields */
@@ -603,6 +602,19 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long offsnprintf(iommu->name,sizeof(iommu->name),"iommu%d",i);INIT_LIST_HEAD(&iommu->windows);+returniommu;+}++staticvoid__initcell_iommu_init_one(structdevice_node*np,+unsignedlongoffset)+{+structcbe_iommu*iommu;+unsignedlongbase,size;++iommu=cell_iommu_alloc(np);+if(!iommu)+return;+/* Obtain a window for it */cell_iommu_get_window(np,&base,&size);
From: Michael Ellerman <hidden> Date: 2008-01-29 14:14:00
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 <redacted>
---
arch/powerpc/platforms/cell/iommu.c | 38 +++++++++++++++++++++++-----------
1 files changed, 26 insertions(+), 12 deletions(-)
@@ -306,20 +306,13 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)return-ENODEV;}-staticvoidcell_iommu_setup_hardware(structcbe_iommu*iommu,unsignedlongsize)+staticvoidcell_iommu_setup_page_tables(structcbe_iommu*iommu,+unsignedlongbase,unsignedlongsize){structpage*page;-intret,i;+inti;unsignedlongreg,segments,pages_per_segment,ptab_size,stab_size,-n_pte_pages,xlate_base;-unsignedintvirq;--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]);}+}++staticvoidcell_iommu_enable_hardware(structcbe_iommu*iommu)+{+intret;+unsignedlongreg,xlate_base;+unsignedintvirq;++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 sizout_be64(iommu->cmd_regs+IOC_IOCmd_Cfg,reg);}+staticvoidcell_iommu_setup_hardware(structcbe_iommu*iommu,+unsignedlongbase,unsignedlongsize)+{+cell_iommu_setup_page_tables(iommu,base,size);+cell_iommu_enable_hardware(iommu);+}+#if 0/* Unused for now */staticstructiommu_window*find_window(structcbe_iommu*iommu,unsignedlongoffset,unsignedlongsize)
@@ -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,
From: Michael Ellerman <hidden> Date: 2008-01-29 14:14:01
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 <redacted>
---
arch/powerpc/platforms/cell/iommu.c | 19 +++++++++++++------
1 files changed, 13 insertions(+), 6 deletions(-)
@@ -507,17 +507,12 @@ static struct cbe_iommu *cell_iommu_for_node(int nid)staticunsignedlongcell_dma_direct_offset;-staticvoidcell_dma_dev_setup(structdevice*dev)+staticvoidcell_dma_dev_setup_iommu(structdevice*dev){structiommu_window*window;structcbe_iommu*iommu;structdev_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'siommu.We-might-dosomethingsmarterlaterthoughitmay*neverbenecessary
From: Michael Ellerman <hidden> Date: 2008-01-29 14:14:01
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 <redacted>
---
arch/powerpc/platforms/cell/iommu.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
From: Michael Ellerman <hidden> Date: 2008-01-29 14:14:02
Split out the ioid fetching and checking logic so we can use it elsewhere
in a subsequent patch.
Signed-off-by: Michael Ellerman <redacted>
---
arch/powerpc/platforms/cell/iommu.c | 23 +++++++++++++++++------
1 files changed, 17 insertions(+), 6 deletions(-)
From: Michael Ellerman <hidden> Date: 2008-01-29 14:14:03
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 <redacted>
---
arch/powerpc/platforms/cell/iommu.c | 241 ++++++++++++++++++++++++++++++++++-
1 files changed, 240 insertions(+), 1 deletions(-)
@@ -545,11 +548,16 @@ static void cell_dma_dev_setup_iommu(struct device *dev)archdata->dma_data=&window->table;}+staticvoidcell_dma_dev_setup_static(structdevice*dev);+staticvoidcell_dma_dev_setup(structdevice*dev){structdev_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);+elseif(get_pci_dma_ops()==&dma_iommu_ops)cell_dma_dev_setup_iommu(dev);elseif(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)return0;}+staticu64cell_iommu_get_fixed_address(structdevice*dev)+{+u64cpu_addr,size,best_size,pci_addr=OF_BAD_ADDR;+structdevice_node*tmp,*np;+constu32*ranges=NULL;+inti,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");+gotoout;+}++len/=sizeof(u32);++/* dma-ranges format:+*1cell:pcispace+*2cells:pciaddress+*2cells:parentaddress+*2cells: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);++returnpci_addr;+}++staticintdma_set_mask_and_switch(structdevice*dev,u64dma_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;++return0;+}++staticvoidcell_dma_dev_setup_static(structdevice*dev)+{+structdev_archdata*archdata=&dev->archdata;+u64addr;++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);+}++staticvoidcell_iommu_setup_fixed_ptab(structcbe_iommu*iommu,+structdevice_node*np,unsignedlongdbase,unsignedlongdsize,+unsignedlongfbase,unsignedlongfsize)+{+unsignedlongbase_pte,uaddr,*io_pte;+inti;++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();+}++staticint__initcell_iommu_fixed_mapping_init(void)+{+unsignedlongdbase,dsize,fbase,fsize,hbase,hend;+structcbe_iommu*iommu;+structdevice_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+*dynamicregion,sofindthetopofthelargestIOMMUwindow+*onanyaxon,thenaddthesizeofRAMandthat'sourmaxvalue.+*Ifthatis>32GBwehavetodoothershennanigans.+*/+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+*RAMwiththefixedmapping,andalsofitthedynamic+*region.Sotrytoplacethedynamicregionwherethehash+*tablesits,driversneverneedtoDMAtoit,wedon't+*needafixedmappingforthatarea.+*/+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");++return0;+}++staticintiommu_fixed_disabled;++staticint__initsetup_iommu_fixed(char*str)+{+if(strcmp(str,"off")==0)+iommu_fixed_disabled=1;++return1;+}+__setup("iommu_fixed=",setup_iommu_fixed);+staticint__initcell_iommu_init(void){structdevice_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)+gotobail;+/* Create an iommu for each /axon node. */for_each_node_by_name(np,"axon"){if(np->parent==NULL||np->parent->parent!=NULL)
From: Michael Ellerman <hidden> Date: 2008-01-29 15:13:45
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:
quoted
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
From: Olof Johansson <hidden> Date: 2008-01-29 15:15:11
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
From: Olof Johansson <hidden> Date: 2008-01-29 15:50:48
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:
quoted
On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
quoted
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
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2008-01-29 21:18:15
On Wed, 2008-01-30 at 02:13 +1100, Michael Ellerman wrote:
On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
quoted
On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
quoted
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.
From: Olof Johansson <hidden> Date: 2008-01-29 21:36:46
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:
quoted
On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
quoted
On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
quoted
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
From: Michael Ellerman <hidden> Date: 2008-01-29 23:56:32
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:
quoted
On Wed, 2008-01-30 at 02:13 +1100, Michael Ellerman wrote:
quoted
On Tue, 2008-01-29 at 09:15 -0600, Olof Johansson wrote:
quoted
On Wed, Jan 30, 2008 at 01:14:03AM +1100, Michael Ellerman wrote:
quoted
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
From: Michael Ellerman <hidden> Date: 2008-01-30 00:03:44
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 <redacted>
---
arch/powerpc/platforms/cell/iommu.c | 269 ++++++++++++++++++++++++++++++++++-
1 files changed, 267 insertions(+), 2 deletions(-)
Updated to include a description in the file.
@@ -545,11 +548,16 @@ static void cell_dma_dev_setup_iommu(struct device *dev)archdata->dma_data=&window->table;}+staticvoidcell_dma_dev_setup_static(structdevice*dev);+staticvoidcell_dma_dev_setup(structdevice*dev){structdev_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);+elseif(get_pci_dma_ops()==&dma_iommu_ops)cell_dma_dev_setup_iommu(dev);elseif(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)return0;}+/*+*FixedIOMMUmappingsupport+*+*ThiscodeaddssupportforsettingupafixedIOMMUmappingoncertain+*cellmachines.For64-bitdevicesthisavoidstheperformanceoverheadof+*mappingandunmappingpagesatruntime.32-bitdevicesareunabletouse+*thefixedmapping.+*+*Thefixedmappingisestablishedatboot,andmapsallofphysicalmemory+*1:1intodevicespaceatsomeoffset.Onmachineswith<30GBofmemory+*wesetupthefixedmappingimmediatelyabovethenormalIOMMUwindow.+*+*Forexampleamachinewith4GBofmemorywouldendupwiththenormal+*IOMMUwindowfrom0-2GBandthefixedmappingwindowfrom2GBto6GB.In+*thiscasea64-bitdevicewishingtoDMAto1GBwouldbetoldtoDMAto+*3GB,plusanyoffsetrequiredbyfirmware.Thefirmwareoffsetisencoded+*inthe"dma-ranges"property.+*+*Onmachineswith30GBormoreofmemory,weareunabletoplacethefixed+*mappingabovethenormalIOMMUwindowaswewouldrunoutofaddressspace.+*InsteadwemovethenormalIOMMUwindowtocoincidewiththehashpage+*table,thisregiondoesnotneedtobepartofthefixedmappingasno+*deviceshouldeverbeDMA'ingtoit.Wethensetupthefixedmapping+*from0to32GB.+*/++staticu64cell_iommu_get_fixed_address(structdevice*dev)+{+u64cpu_addr,size,best_size,pci_addr=OF_BAD_ADDR;+structdevice_node*tmp,*np;+constu32*ranges=NULL;+inti,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");+gotoout;+}++len/=sizeof(u32);++/* dma-ranges format:+*1cell:pcispace+*2cells:pciaddress+*2cells:parentaddress+*2cells: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);++returnpci_addr;+}++staticintdma_set_mask_and_switch(structdevice*dev,u64dma_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;++return0;+}++staticvoidcell_dma_dev_setup_static(structdevice*dev)+{+structdev_archdata*archdata=&dev->archdata;+u64addr;++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);+}++staticvoidcell_iommu_setup_fixed_ptab(structcbe_iommu*iommu,+structdevice_node*np,unsignedlongdbase,unsignedlongdsize,+unsignedlongfbase,unsignedlongfsize)+{+unsignedlongbase_pte,uaddr,*io_pte;+inti;++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();+}++staticint__initcell_iommu_fixed_mapping_init(void)+{+unsignedlongdbase,dsize,fbase,fsize,hbase,hend;+structcbe_iommu*iommu;+structdevice_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+*dynamicregion,sofindthetopofthelargestIOMMUwindow+*onanyaxon,thenaddthesizeofRAMandthat'sourmaxvalue.+*Ifthatis>32GBwehavetodoothershennanigans.+*/+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+*RAMwiththefixedmapping,andalsofitthedynamic+*region.Sotrytoplacethedynamicregionwherethehash+*tablesits,driversneverneedtoDMAtoit,wedon't+*needafixedmappingforthatarea.+*/+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");++return0;+}++staticintiommu_fixed_disabled;++staticint__initsetup_iommu_fixed(char*str)+{+if(strcmp(str,"off")==0)+iommu_fixed_disabled=1;++return1;+}+__setup("iommu_fixed=",setup_iommu_fixed);+staticint__initcell_iommu_init(void){structdevice_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)+gotobail;+/* Create an iommu for each /axon node. */for_each_node_by_name(np,"axon"){if(np->parent==NULL||np->parent->parent!=NULL)
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 <><
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2008-02-05 00:23:51
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 <redacted>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -565,10 +565,9 @@ static int __init cell_iommu_get_window(struct device_node *np,return0;}-staticvoid__initcell_iommu_init_one(structdevice_node*np,unsignedlongoffset)+staticstructcbe_iommu*__initcell_iommu_alloc(structdevice_node*np){structcbe_iommu*iommu;-unsignedlongbase,size;intnid,i;/* Get node ID */
@@ -576,7 +575,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long offif(nid<0){printk(KERN_ERR"iommu: failed to get node for %s\n",np->full_name);-return;+returnNULL;}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 offif(cbe_nr_iommus>=NR_IOMMUS){printk(KERN_ERR"iommu: too many IOMMUs detected ! (%s)\n",np->full_name);-return;+returnNULL;}/* Init base fields */
@@ -603,6 +602,19 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long offsnprintf(iommu->name,sizeof(iommu->name),"iommu%d",i);INIT_LIST_HEAD(&iommu->windows);+returniommu;+}++staticvoid__initcell_iommu_init_one(structdevice_node*np,+unsignedlongoffset)+{+structcbe_iommu*iommu;+unsignedlongbase,size;++iommu=cell_iommu_alloc(np);+if(!iommu)+return;+/* Obtain a window for it */cell_iommu_get_window(np,&base,&size);
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2008-02-05 00:26:33
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 <redacted>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -507,17 +507,12 @@ static struct cbe_iommu *cell_iommu_for_node(int nid)staticunsignedlongcell_dma_direct_offset;-staticvoidcell_dma_dev_setup(structdevice*dev)+staticvoidcell_dma_dev_setup_iommu(structdevice*dev){structiommu_window*window;structcbe_iommu*iommu;structdev_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'siommu.We-might-dosomethingsmarterlaterthoughitmay*neverbenecessary
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2008-02-05 00:26:43
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 <redacted>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>