LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* RE: 83xx: Marking or Allocating Pages as Cache-Inhibited
From: Liu Dave-R63238 @ 2009-03-06  5:40 UTC (permalink / raw)
  To: Ben Menchaca; +Cc: linuxppc-dev
In-Reply-To: <64ac01180903052138k4226022cq840d497dccecd939@mail.gmail.com>

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

what is the value of ACR register?


________________________________

	From: Ben Menchaca [mailto:ben.menchaca@gmail.com] 
	Sent: Friday, March 06, 2009 1:38 PM
	To: Liu Dave-R63238
	Cc: linuxppc-dev@ozlabs.org
	Subject: Re: 83xx: Marking or Allocating Pages as
Cache-Inhibited
	
	
	1.  BAT2 in linux is set to WIMG=0010, and covers all 64M
	2.  PEX_DEVICE_CONTROL in PCI-E Config Space (0x54): 0x1020
	3.  PEX_xDMA_CTRL is set to 0x00000401 at the initiation of the
DMA.
	4.  OWAR0 is set to 0xFFFFF005, so NSNP is 0.
	5.  The DMA descriptor (randomly chosen when I hit a
trigger...just ignore the size...) contains 0002AFF3 at offset 0, so
nosnoops are cleared.  
	
	Core is 400MHz, and CSB is 133MHz.
	
	- Ben
	
	
	On Thu, Mar 5, 2009 at 11:27 PM, Liu Dave-R63238
<DaveLiu@freescale.com> wrote:
	

		and what settings  is DMA description bit 3?
		

		> -----Original Message-----
		> From:
linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
		> [mailto:linuxppc-dev-bounces+daveliu
<mailto:linuxppc-dev-bounces%2Bdaveliu> =freescale.com@ozlabs.org]
		
		>  On Behalf Of Liu Dave-R63238
		> Sent: Friday, March 06, 2009 1:22 PM
		> To: Ben Menchaca; linuxppc-dev@ozlabs.org
		> Subject: RE: 83xx: Marking or Allocating Pages as
Cache-Inhibited
		>
		> Did you enable the snoop bit at PEX_WDMA_CTRL[SNOOP]
and
		> PEX_RDMA_CTRL[SNOOP]?
		>
		> What is the freq settings? CORE/CSB bus.
		>
		> Thanks, Dave
		>
		> ________________________________
		>
		>       From:
linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
		> [mailto:linuxppc-dev-bounces+daveliu
<mailto:linuxppc-dev-bounces%2Bdaveliu> =freescale.com@ozlabs.org]
		>  On Behalf Of Ben Menchaca
		>       Sent: Friday, March 06, 2009 12:33 PM
		>       To: linuxppc-dev@ozlabs.org
		>       Subject: 83xx: Marking or Allocating Pages as
Cache-Inhibited
		>
		>
		>       I am working on a Freescale 8314e design, and
the
		> embedded device is configured as a PCI-e endpoint
running a
		> 2.6.27-5 kernel.  For context, we have written a
kernel
		> module which, among other things, uses the RDMA/WDMA
engine
		> in the PCI-e IP block.  On the host side, these DMAs
are
		> coherent.  However, on the embedded side, things are
quite a
		> bit less rosy; we must manually flush/invalidate cache
lines
		> for WDMA/RDMAs to occur successfully.  After speaking
with
		> (several) FAEs at Freescale, we believe there is a
		> configuration issue that is the cause, but we have yet
to
		> have anyone successfully point to it.
		>
		>       Disabling the data cache altogether resolves the
issue
		> entirely, but of course, also completely tanks
performance.
		> As a temporary workaround, I would like to simply mark
the
		> pages (obtained currently via dma_alloc_coherent)
involved as
		> cache-inhibited.  I have attempted to do this via some
		> snippets remaining in fec.c (va_to_pte, uncache_pte to
set
		> _PAGE_NO_CACHE, flush_tlb_page, then unmap_pte), but
this is
		> almost certainly braindead; va_to_pte is not a part of
the
		> 83xx source, as far as I can tell; 8xx only.
		>
		>       A quick pointer in the correct direction for
marking
		> pages as cache-inhibited on a 2.6.27-5 kernel would be
		> appreciated, or if my approach to a workaround is
flawed, a
		> pointer to the correct way would be great.
		>
		>       Ben Menchaca
		>
		>
		
		> _______________________________________________
		> Linuxppc-dev mailing list
		> Linuxppc-dev@ozlabs.org
		> https://ozlabs.org/mailman/listinfo/linuxppc-dev
		>
		>
		



[-- Attachment #2: Type: text/html, Size: 6497 bytes --]

^ permalink raw reply

* RE: 83xx: Marking or Allocating Pages as Cache-Inhibited
From: Liu Dave-R63238 @ 2009-03-06  5:49 UTC (permalink / raw)
  To: Liu Dave-R63238, Ben Menchaca; +Cc: linuxppc-dev
In-Reply-To: <64ac01180903052138k4226022cq840d497dccecd939@mail.gmail.com>

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

could you try to set '1' to DMA description bit3?


________________________________

	From: Liu Dave-R63238 
	Sent: Friday, March 06, 2009 1:41 PM
	To: 'Ben Menchaca'
	Cc: linuxppc-dev@ozlabs.org
	Subject: RE: 83xx: Marking or Allocating Pages as
Cache-Inhibited
	
	
	what is the value of ACR register?


________________________________

		From: Ben Menchaca [mailto:ben.menchaca@gmail.com] 
		Sent: Friday, March 06, 2009 1:38 PM
		To: Liu Dave-R63238
		Cc: linuxppc-dev@ozlabs.org
		Subject: Re: 83xx: Marking or Allocating Pages as
Cache-Inhibited
		
		
		1.  BAT2 in linux is set to WIMG=0010, and covers all
64M
		2.  PEX_DEVICE_CONTROL in PCI-E Config Space (0x54):
0x1020
		3.  PEX_xDMA_CTRL is set to 0x00000401 at the initiation
of the DMA.
		4.  OWAR0 is set to 0xFFFFF005, so NSNP is 0.
		5.  The DMA descriptor (randomly chosen when I hit a
trigger...just ignore the size...) contains 0002AFF3 at offset 0, so
nosnoops are cleared.  
		
		Core is 400MHz, and CSB is 133MHz.
		
		- Ben
		
		
		On Thu, Mar 5, 2009 at 11:27 PM, Liu Dave-R63238
<DaveLiu@freescale.com> wrote:
		

			and what settings  is DMA description bit 3?
			

			> -----Original Message-----
			> From:
linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
			> [mailto:linuxppc-dev-bounces+daveliu
<mailto:linuxppc-dev-bounces%2Bdaveliu> =freescale.com@ozlabs.org]
			
			>  On Behalf Of Liu Dave-R63238
			> Sent: Friday, March 06, 2009 1:22 PM
			> To: Ben Menchaca; linuxppc-dev@ozlabs.org
			> Subject: RE: 83xx: Marking or Allocating Pages
as Cache-Inhibited
			>
			> Did you enable the snoop bit at
PEX_WDMA_CTRL[SNOOP] and
			> PEX_RDMA_CTRL[SNOOP]?
			>
			> What is the freq settings? CORE/CSB bus.
			>
			> Thanks, Dave
			>
			> ________________________________
			>
			>       From:
linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
			> [mailto:linuxppc-dev-bounces+daveliu
<mailto:linuxppc-dev-bounces%2Bdaveliu> =freescale.com@ozlabs.org]
			>  On Behalf Of Ben Menchaca
			>       Sent: Friday, March 06, 2009 12:33 PM
			>       To: linuxppc-dev@ozlabs.org
			>       Subject: 83xx: Marking or Allocating
Pages as Cache-Inhibited
			>
			>
			>       I am working on a Freescale 8314e
design, and the
			> embedded device is configured as a PCI-e
endpoint running a
			> 2.6.27-5 kernel.  For context, we have written
a kernel
			> module which, among other things, uses the
RDMA/WDMA engine
			> in the PCI-e IP block.  On the host side,
these DMAs are
			> coherent.  However, on the embedded side,
things are quite a
			> bit less rosy; we must manually
flush/invalidate cache lines
			> for WDMA/RDMAs to occur successfully.  After
speaking with
			> (several) FAEs at Freescale, we believe there
is a
			> configuration issue that is the cause, but we
have yet to
			> have anyone successfully point to it.
			>
			>       Disabling the data cache altogether
resolves the issue
			> entirely, but of course, also completely tanks
performance.
			> As a temporary workaround, I would like to
simply mark the
			> pages (obtained currently via
dma_alloc_coherent) involved as
			> cache-inhibited.  I have attempted to do this
via some
			> snippets remaining in fec.c (va_to_pte,
uncache_pte to set
			> _PAGE_NO_CACHE, flush_tlb_page, then
unmap_pte), but this is
			> almost certainly braindead; va_to_pte is not a
part of the
			> 83xx source, as far as I can tell; 8xx only.
			>
			>       A quick pointer in the correct direction
for marking
			> pages as cache-inhibited on a 2.6.27-5 kernel
would be
			> appreciated, or if my approach to a workaround
is flawed, a
			> pointer to the correct way would be great.
			>
			>       Ben Menchaca
			>
			>
			
			>
_______________________________________________
			> Linuxppc-dev mailing list
			> Linuxppc-dev@ozlabs.org
			>
https://ozlabs.org/mailman/listinfo/linuxppc-dev
			>
			>
			



[-- Attachment #2: Type: text/html, Size: 7380 bytes --]

^ permalink raw reply

* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
From: Ben Menchaca @ 2009-03-06  6:10 UTC (permalink / raw)
  To: Liu Dave-R63238; +Cc: linuxppc-dev
In-Reply-To: <D7CCA83BB0796C49BC0BB53B6AB1208916CF81@zch01exm21.fsl.freescale.net>

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

I can look at ACR morning...although I can say with a fair amount of
certainty that I have not changed it from the POR value.

I will try enabling No Snoop for CSB in the descriptor (bit 3, yes?)...this
seems a bit counterintuitive to me.

What is the hope regarding these two?  Some combination I am not seeing?


On Thu, Mar 5, 2009 at 11:40 PM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:

>  what is the value of ACR register?
>
>  ------------------------------
> *From:* Ben Menchaca [mailto:ben.menchaca@gmail.com]
> *Sent:* Friday, March 06, 2009 1:38 PM
> *To:* Liu Dave-R63238
> *Cc:* linuxppc-dev@ozlabs.org
> *Subject:* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
>
> 1.  BAT2 in linux is set to WIMG=0010, and covers all 64M
> 2.  PEX_DEVICE_CONTROL in PCI-E Config Space (0x54): 0x1020
> 3.  PEX_xDMA_CTRL is set to 0x00000401 at the initiation of the DMA.
> 4.  OWAR0 is set to 0xFFFFF005, so NSNP is 0.
> 5.  The DMA descriptor (randomly chosen when I hit a trigger...just ignore
> the size...) contains 0002AFF3 at offset 0, so nosnoops are cleared.
>
> Core is 400MHz, and CSB is 133MHz.
>
> - Ben
>
> On Thu, Mar 5, 2009 at 11:27 PM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:
>
>> and what settings  is DMA description bit 3?
>>
>> > -----Original Message-----
>> > From: linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
>> > [mailto:linuxppc-dev-bounces+daveliu <linuxppc-dev-bounces%2Bdaveliu>=
>> freescale.com@ozlabs.org]
>>   >  On Behalf Of Liu Dave-R63238
>> > Sent: Friday, March 06, 2009 1:22 PM
>> > To: Ben Menchaca; linuxppc-dev@ozlabs.org
>> > Subject: RE: 83xx: Marking or Allocating Pages as Cache-Inhibited
>> >
>> > Did you enable the snoop bit at PEX_WDMA_CTRL[SNOOP] and
>> > PEX_RDMA_CTRL[SNOOP]?
>> >
>> > What is the freq settings? CORE/CSB bus.
>> >
>> > Thanks, Dave
>> >
>> > ________________________________
>> >
>> >       From: linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
>> > [mailto:linuxppc-dev-bounces+daveliu <linuxppc-dev-bounces%2Bdaveliu>=
>> freescale.com@ozlabs.org]
>> >  On Behalf Of Ben Menchaca
>> >       Sent: Friday, March 06, 2009 12:33 PM
>> >       To: linuxppc-dev@ozlabs.org
>> >       Subject: 83xx: Marking or Allocating Pages as Cache-Inhibited
>> >
>> >
>> >       I am working on a Freescale 8314e design, and the
>> > embedded device is configured as a PCI-e endpoint running a
>> > 2.6.27-5 kernel.  For context, we have written a kernel
>> > module which, among other things, uses the RDMA/WDMA engine
>> > in the PCI-e IP block.  On the host side, these DMAs are
>> > coherent.  However, on the embedded side, things are quite a
>> > bit less rosy; we must manually flush/invalidate cache lines
>> > for WDMA/RDMAs to occur successfully.  After speaking with
>> > (several) FAEs at Freescale, we believe there is a
>> > configuration issue that is the cause, but we have yet to
>> > have anyone successfully point to it.
>> >
>> >       Disabling the data cache altogether resolves the issue
>> > entirely, but of course, also completely tanks performance.
>> > As a temporary workaround, I would like to simply mark the
>> > pages (obtained currently via dma_alloc_coherent) involved as
>> > cache-inhibited.  I have attempted to do this via some
>> > snippets remaining in fec.c (va_to_pte, uncache_pte to set
>> > _PAGE_NO_CACHE, flush_tlb_page, then unmap_pte), but this is
>> > almost certainly braindead; va_to_pte is not a part of the
>> > 83xx source, as far as I can tell; 8xx only.
>> >
>> >       A quick pointer in the correct direction for marking
>> > pages as cache-inhibited on a 2.6.27-5 kernel would be
>> > appreciated, or if my approach to a workaround is flawed, a
>> > pointer to the correct way would be great.
>> >
>> >       Ben Menchaca
>> >
>> >
>> > _______________________________________________
>> > Linuxppc-dev mailing list
>> > Linuxppc-dev@ozlabs.org
>> > https://ozlabs.org/mailman/listinfo/linuxppc-dev
>> >
>> >
>>
>
>

[-- Attachment #2: Type: text/html, Size: 6902 bytes --]

^ permalink raw reply

* RE: 83xx: Marking or Allocating Pages as Cache-Inhibited
From: Liu Dave-R63238 @ 2009-03-06  6:30 UTC (permalink / raw)
  To: Ben Menchaca; +Cc: linuxppc-dev
In-Reply-To: <64ac01180903052210r2aee7246g50fd0656c491a40b@mail.gmail.com>

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

Did you enable the descriptor bit 3 to have a try?


________________________________

	From: Ben Menchaca [mailto:ben.menchaca@gmail.com] 
	Sent: Friday, March 06, 2009 2:10 PM
	To: Liu Dave-R63238
	Cc: linuxppc-dev@ozlabs.org
	Subject: Re: 83xx: Marking or Allocating Pages as
Cache-Inhibited
	
	
	I can look at ACR morning...although I can say with a fair
amount of certainty that I have not changed it from the POR value.
	
	I will try enabling No Snoop for CSB in the descriptor (bit 3,
yes?)...this seems a bit counterintuitive to me.
	
	What is the hope regarding these two?  Some combination I am not
seeing?
	
	
	
	On Thu, Mar 5, 2009 at 11:40 PM, Liu Dave-R63238
<DaveLiu@freescale.com> wrote:
	

		what is the value of ACR register?


________________________________

			From: Ben Menchaca
[mailto:ben.menchaca@gmail.com] 
			Sent: Friday, March 06, 2009 1:38 PM
			To: Liu Dave-R63238
			Cc: linuxppc-dev@ozlabs.org
			Subject: Re: 83xx: Marking or Allocating Pages
as Cache-Inhibited
			
			
			1.  BAT2 in linux is set to WIMG=0010, and
covers all 64M
			2.  PEX_DEVICE_CONTROL in PCI-E Config Space
(0x54): 0x1020
			3.  PEX_xDMA_CTRL is set to 0x00000401 at the
initiation of the DMA.
			4.  OWAR0 is set to 0xFFFFF005, so NSNP is 0.
			5.  The DMA descriptor (randomly chosen when I
hit a trigger...just ignore the size...) contains 0002AFF3 at offset 0,
so nosnoops are cleared.  
			
			Core is 400MHz, and CSB is 133MHz.
			
			- Ben
			
			
			On Thu, Mar 5, 2009 at 11:27 PM, Liu Dave-R63238
<DaveLiu@freescale.com> wrote:
			

				and what settings  is DMA description
bit 3?
				

				> -----Original Message-----
				> From:
linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
				> [mailto:linuxppc-dev-bounces+daveliu
<mailto:linuxppc-dev-bounces%2Bdaveliu> =freescale.com@ozlabs.org]
				
				>  On Behalf Of Liu Dave-R63238
				> Sent: Friday, March 06, 2009 1:22 PM
				> To: Ben Menchaca;
linuxppc-dev@ozlabs.org
				> Subject: RE: 83xx: Marking or
Allocating Pages as Cache-Inhibited
				>
				> Did you enable the snoop bit at
PEX_WDMA_CTRL[SNOOP] and
				> PEX_RDMA_CTRL[SNOOP]?
				>
				> What is the freq settings? CORE/CSB
bus.
				>
				> Thanks, Dave
				>
				> ________________________________
				>
				>       From:
linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
				> [mailto:linuxppc-dev-bounces+daveliu
<mailto:linuxppc-dev-bounces%2Bdaveliu> =freescale.com@ozlabs.org]
				>  On Behalf Of Ben Menchaca
				>       Sent: Friday, March 06, 2009
12:33 PM
				>       To: linuxppc-dev@ozlabs.org
				>       Subject: 83xx: Marking or
Allocating Pages as Cache-Inhibited
				>
				>
				>       I am working on a Freescale
8314e design, and the
				> embedded device is configured as a
PCI-e endpoint running a
				> 2.6.27-5 kernel.  For context, we have
written a kernel
				> module which, among other things, uses
the RDMA/WDMA engine
				> in the PCI-e IP block.  On the host
side, these DMAs are
				> coherent.  However, on the embedded
side, things are quite a
				> bit less rosy; we must manually
flush/invalidate cache lines
				> for WDMA/RDMAs to occur successfully.
After speaking with
				> (several) FAEs at Freescale, we
believe there is a
				> configuration issue that is the cause,
but we have yet to
				> have anyone successfully point to it.
				>
				>       Disabling the data cache
altogether resolves the issue
				> entirely, but of course, also
completely tanks performance.
				> As a temporary workaround, I would
like to simply mark the
				> pages (obtained currently via
dma_alloc_coherent) involved as
				> cache-inhibited.  I have attempted to
do this via some
				> snippets remaining in fec.c
(va_to_pte, uncache_pte to set
				> _PAGE_NO_CACHE, flush_tlb_page, then
unmap_pte), but this is
				> almost certainly braindead; va_to_pte
is not a part of the
				> 83xx source, as far as I can tell; 8xx
only.
				>
				>       A quick pointer in the correct
direction for marking
				> pages as cache-inhibited on a 2.6.27-5
kernel would be
				> appreciated, or if my approach to a
workaround is flawed, a
				> pointer to the correct way would be
great.
				>
				>       Ben Menchaca
				>
				>
				
				>
_______________________________________________
				> Linuxppc-dev mailing list
				> Linuxppc-dev@ozlabs.org
				>
https://ozlabs.org/mailman/listinfo/linuxppc-dev
				>
				>
				




[-- Attachment #2: Type: text/html, Size: 8562 bytes --]

^ permalink raw reply

* [RFC] More compatibles or more quirk properties
From: Li Yang-R58472 @ 2009-03-06  7:09 UTC (permalink / raw)
  To: devicetree-discuss; +Cc: linuxppc-dev

SGksDQoNCkknbSBydW5uaW5nIGludG8gYSBkaWxlbW1hIGNob29zaW5nIGJldHdlZW4gdHdvIGFw
cHJvYWNoZXMgb2YgZGVmaW5pbmcgZGV2aWNlIHRyZWUgYmluZGluZy4gIExldCdzIHNheSBpZiB3
ZSBoYXZlIHNldmVyYWwgY2hpcHMgd2l0aCBhIHNpbWlsYXIgU29DIGJsb2NrLCBidXQgZWFjaCBv
ZiB0aGVtIGhhdmUgZGlmZmVyZW50IHF1aXJrcy4gIElmIEkgZGVmaW5lIGRpZmZlcmVudCBjb21w
YXRpYmxlcyBmb3IgZWFjaCBvZiB0aGUgY2hpcHMsIHRoZSBkcml2ZXIgd2lsbCBoYXZlIGEgbG9u
Z2VyIG1hdGNoIHRhYmxlIGFuZCB0aHVzIGJsb2F0IHRoZSBkZXZpY2UgbWF0Y2hpbmcgcHJvY2Vz
cy4gIE9yIHdlIGNhbiB1c2UgYSBzYW1lIGNvbXBhdGlibGUgZm9yIGFsbCBvZiB0aGVtIGFuZCAg
ZGVmaW5lIHByb3BlcnRpZXMgZm9yIGVhY2ggb2YgdGhlIHF1aXJrcy4gIEJ1dCBpdCBzb21ld2hh
dCBibG9hdHMgdGhlIGRldmljZSB0cmVlLiAgSSdtIG1vcmUgcHJvbmUgdG8gdGhlIHNlY29uZCBz
b2x1dGlvbiwgYnV0IEkgZG8gd2FudCB0byBoZWFyIHdoYXQgeW91IGd1eXMgdGhpbmsgYWJvdXQg
aXQuDQoNCi0gTGVvDQo=

^ permalink raw reply

* Re: [RFC] More compatibles or more quirk properties
From: Mitch Bradley @ 2009-03-06  7:32 UTC (permalink / raw)
  To: Li Yang-R58472; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <3A45394FD742FA419B760BB8D398F9ED29E274@zch01exm26.fsl.freescale.net>

>
> I'm running into a dilemma choosing between two approaches of defining device tree binding.  Let's say if we have several chips with a similar SoC block, but each of them have different quirks.  If I define different compatibles for each of the chips, the driver will have a longer match table and thus bloat the device matching process.  Or we can use a same compatible for all of them and  define properties for each of the quirks.  But it somewha
Properties to describe quirks precisely are definitely better.  In fact, 
that's fundamental principle - describe the situation, don't infer a 
bunch of details from a name.

^ permalink raw reply

* Re: [PATCH/RFC] ps3/block: Add ps3vram-ng driver for accessing video    RAM as block device
From: Jens Axboe @ 2009-03-06  7:46 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Arnd Bergmann, Linux Kernel Development, Jim Paris,
	Linux/PPC Development, linux-mtd, Vivien Chappelier,
	David Woodhouse, Cell Broadband Engine OSS Development
In-Reply-To: <alpine.LRH.2.00.0903051325450.2618@vixen.sonytel.be>

On Thu, Mar 05 2009, Geert Uytterhoeven wrote:
> On Thu, 5 Mar 2009, Jens Axboe wrote:
> > On Thu, Mar 05 2009, Geert Uytterhoeven wrote:
> > > On Thu, 5 Mar 2009, Jens Axboe wrote:
> > > > On Wed, Mar 04 2009, Geert Uytterhoeven wrote:
> > > > > Below is the rewrite of the PS3 Video RAM Storage Driver as a plain block
> > > > > device, as requested by Arnd Bergmann.
> 
> > > > I'd rewrite this as a ->make_request_fn handler instead. Then you can
> > > > get rid of the kernel thread. IOW, change
> > > >
> > > > queue = blk_init_queue(ps3vram_request, &priv->lock);
> > > >
> > > > to
> > > >
> > > > queue = blk_alloc_queue(GFP_KERNEL);
> > > > blk_queue_make_request(queue, ps3vram_make_request);
> > >
> > > Thanks, I didn't know that part...
> > >
> > > > Add error handling of course, and call blk_queue_max_*() to set your
> > > > limits for this device.
> > >
> > > I took out the blk_queue_max_*() calls (compared to ps3disk.c), as
> > > none of the limits apply, and the defaults are fine.
> > >
> > > Is that OK, or is it better to make it explicit?
> >
> > I think it's always good to make it explicit. Plus for this case you
> > definitely need it, as blk_init_queue() wont do it for you anymore.
> 
> blk_queue_make_request() does it for me, too:
> 
> void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
> {
> 	...
> 	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
> 	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
> 	...
> 	blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
> 	...
> 	blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
> 	...
> }
> 
> struct request_queue *
> blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
> {
> 	...
> 	blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
> 
> 	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
> 	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
> 	...
> }

Indeed, there's some duplicated code in blk_init_queue_node(), I'll make
sure to get rid of that!

> > > > Then add a ps3vram_make_request() ala:
> > >
> > > > static void ps3vram_do_request(struct request_queue *q, struct bio *bio)
> > > > {
> 
> > > > }
> > > >
> > > > I just typed it here, so if it doesn't compile you get to keep the
> > > > pieces :-)
> > >
> > > OK, I'll give it a try...
> > >
> > > BTW, does this mean the `simple' way, which I used based on LDD3, is
> > > deprecated?
> >
> > Depends.. It's obviously not a very effective approach, since you punt
> > to a thread for each request. But if you need the IO scheduler helping
> > you with merging and sorting (for a rotational device), it still has
> > some merit. For this particular case, the ->make_request_fn approach is
> > much better.
> 
> Without the thread, performance indeed increased.
> 
> But then I noticed ps3vram_make_request() may be called concurrently,
> so I had to add a mutex to avoid data corruption. This slows the
> driver down, and in the end, the version with a thread turns out to be
> ca. 1% faster. The version without a thread is about 50 lines less
> code, though.

That is correct, ->make_request_fn may get reentered. I'm not surprised
that performance dropped if you just shoved everything under a mutex.
You could be a little more smart and queue concurrent bio's for
processing when the current one is complete though, there are several
approaches there that be a lot faster than going all the way through the
IO stack and scheduler just to avoid concurrency.

-- 
Jens Axboe

^ permalink raw reply

* [PATCH] powerpc/usb: Fix 440EPx USBH_3 & USBH_5 EHCI errata
From: - Reyneke @ 2009-03-06 11:30 UTC (permalink / raw)
  To: linuxppc-dev, dbrownell


Patch applies to 440EPx devices in USB EHCI host mode (USB 2.0).

>From the 440EPx errata:

USBH_3: Host hangs after underrun or overrun occurs
USBH_5: EHCI0_INSNREGxx registers are reset by a Soft or Light Host Control=
ler Reset

Workround for USBH_3 is to enable Break Memory Transfer (BMT) in INSNREG3. =
But the controller is reset after this fix is applied=2C and thus the curre=
nt workround is lost. The following short patch ensures INSNREG3 is correct=
ly set after reset.


Signed-off-by: Jan Reyneke=20
---
 ehci-hcd.c    |    7 +++++++
 ehci-ppc-of.c |   30 +++++++++++++++++++-----------
 ehci.h        |    5 +++++
 3 files changed=2C 31 insertions(+)=2C 11 deletions(-)

diff -uprN a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h    2009-03-04 01:05:22.000000000 +0000
+++ b/drivers/usb/host/ehci.h    2009-03-06 10:52:53.000000000 +0000
@@ -137=2C6 +137=2C11 @@ struct ehci_hcd {            /* one per controlle
=20
     u8            sbrn=3B        /* packed release number */
=20
+#if defined(CONFIG_440EPX)
+    #define     PPC440EPX_EHCI0_INSREG_BMT    (0x1 << 0)
+    __iomem u32 *insn_regs=3B        /* INSNREGx device memory/io */
+#endif
+
     /* irq statistics */
 #ifdef EHCI_STATS
     struct ehci_stats    stats=3B
diff -uprN a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c    2009-03-04 01:05:22.000000000 +0000
+++ b/drivers/usb/host/ehci-hcd.c    2009-03-06 10:54:36.000000000 +0000
@@ -217=2C6 +217=2C13 @@ static int ehci_reset (struct ehci_hcd *
     if (ehci_is_TDI(ehci))
         tdi_reset (ehci)=3B
=20
+#if defined(CONFIG_440EPX)
+    /* USBH_5: INSN values are lost on reset -> redo USBH_3.
+       See also ppc44x_enable_bmt.*/
+    if (ehci->insn_regs)
+        out_be32(ehci->insn_regs + 3=2C PPC440EPX_EHCI0_INSREG_BMT)=3B
+#endif
+
     return retval=3B
 }
=20
diff -uprN a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.=
c
--- a/drivers/usb/host/ehci-ppc-of.c    2009-03-04 01:05:22.000000000 +0000
+++ b/drivers/usb/host/ehci-ppc-of.c    2009-03-06 10:56:08.000000000 +0000
@@ -82=2C23 +82=2C24 @@ static const struct hc_driver ehci_ppc_o
=20
=20
 /*
- * 440EPx Errata USBH_3
- * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
- */
-#define PPC440EPX_EHCI0_INSREG_BMT    (0x1 << 0)
+ * 440EPx Errata USBH_3 & USBH_5
+ * Fix: Enable Break Memory Transfer (BMT) in INSNREG3. Also cache
+ * the registers so we can redo the USBH_3 fix on future resets */
 static int __devinit
-ppc44x_enable_bmt(struct device_node *dn)
+ppc44x_enable_bmt(struct device_node *dn=2C struct ehci_hcd* ehci)
 {
-    __iomem u32 *insreg_virt=3B
=20
-    insreg_virt =3D of_iomap(dn=2C 1)=3B
-    if (!insreg_virt)
+#if defined(CONFIG_440EPX)
+
+    ehci->insn_regs =3D of_iomap(dn=2C 1)=3B
+    if (!ehci->insn_regs)
         return  -EINVAL=3B
=20
-    out_be32(insreg_virt + 3=2C PPC440EPX_EHCI0_INSREG_BMT)=3B
+    out_be32(ehci->insn_regs + 3=2C PPC440EPX_EHCI0_INSREG_BMT)=3B
=20
-    iounmap(insreg_virt)=3B
+#endif
     return 0=3B
+
 }
=20
=20
@@ -183=2C7 +184=2C7 @@ ehci_hcd_ppc_of_probe(struct of_device *
     ehci->hcs_params =3D ehci_readl(ehci=2C &ehci->caps->hcs_params)=3B
=20
     if (of_device_is_compatible(dn=2C "ibm=2Cusb-ehci-440epx")) {
-        rv =3D ppc44x_enable_bmt(dn)=3B
+        rv =3D ppc44x_enable_bmt(dn=2C ehci)=3B
         ehci_dbg(ehci=2C "Break Memory Transfer (BMT) is %senabled!\n"=2C
                 rv ? "NOT ": "")=3B
     }
@@ -221=2C6 +222=2C13 @@ static int ehci_hcd_ppc_of_remove(struct
=20
     usb_remove_hcd(hcd)=3B
=20
+#if defined(CONFIG_440EPX)
+    if (ehci->insn_regs) {
+        iounmap(ehci->insn_regs)=3B
+        ehci->insn_regs =3D 0=3B
+    }
+#endif
+
     iounmap(hcd->regs)=3B
     irq_dispose_mapping(hcd->irq)=3B
     release_mem_region(hcd->rsrc_start=2C hcd->rsrc_len)=3B



_________________________________________________________________
View your Twitter and Flickr updates from one place =96 Learn more!
http://clk.atdmt.com/UKM/go/137984870/direct/01/=

^ permalink raw reply

* Re: [PATCH/RFC] ps3/block: Add ps3vram-ng driver for accessing video RAM as block device
From: Geert Uytterhoeven @ 2009-03-06 12:48 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Arnd Bergmann, Linux Kernel Development, Jim Paris,
	Linux/PPC Development, linux-mtd, Vivien Chappelier,
	David Woodhouse, Cell Broadband Engine OSS Development
In-Reply-To: <20090306074639.GN11787@kernel.dk>

On Fri, 6 Mar 2009, Jens Axboe wrote:
> On Thu, Mar 05 2009, Geert Uytterhoeven wrote:
> > But then I noticed ps3vram_make_request() may be called concurrently,
> > so I had to add a mutex to avoid data corruption. This slows the
> > driver down, and in the end, the version with a thread turns out to be
> > ca. 1% faster. The version without a thread is about 50 lines less
> > code, though.
> 
> That is correct, ->make_request_fn may get reentered. I'm not surprised
> that performance dropped if you just shoved everything under a mutex.
> You could be a little more smart and queue concurrent bio's for
> processing when the current one is complete though, there are several
> approaches there that be a lot faster than going all the way through the
> IO stack and scheduler just to avoid concurrency.

Yes, using a spinlock and queueing requests on a list if the driver is busy can
be done after 2.6.29...

With kind regards,

Geert Uytterhoeven
Software Architect

Sony Techsoft Centre Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium

Phone:    +32 (0)2 700 8453
Fax:      +32 (0)2 700 8622
E-mail:   Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/

A division of Sony Europe (Belgium) N.V.
VAT BE 0413.825.160 · RPR Brussels
Fortis · BIC GEBABEBB · IBAN BE41293037680010

^ permalink raw reply

* [PATCH] ps3/block: Replace mtd/ps3vram by block/ps3vram (was: Re: [PATCH/RFC] ps3/block: Add ps3vram-ng driver for accessing video RAM as block device)
From: Geert Uytterhoeven @ 2009-03-06 12:54 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Arnd Bergmann, Linus Torvalds, Linux Kernel Development,
	Jim Paris, Linux/PPC Development, linux-mtd, Jens Axboe,
	Vivien Chappelier, David Woodhouse,
	Cell Broadband Engine OSS Development
In-Reply-To: <20090305065423.GK11787@kernel.dk>

On Thu, 5 Mar 2009, Jens Axboe wrote:
> On Thu, Mar 05 2009, Benjamin Herrenschmidt wrote:
> > On Wed, 2009-03-04 at 14:57 +0100, Geert Uytterhoeven wrote:
> > > Below is the rewrite of the PS3 Video RAM Storage Driver as a plain block
> > > device, as requested by Arnd Bergmann.
> > > 
> > > The MTD-based PS3 Video RAM Storage Driver was integrated into the mainline
> > > kernel in 2.6.29-rc1.
> > > 
> > > Ideally, we think it would be best if the existing MTD-based ps3vram driver
> > > would be replaced by the new block-based ps3vram driver before 2.6.29 is
> > > released. This would relieve the burden of supporting two different swap space
> > > schemes on PS3 (swap on /dev/mtdblock0 vs. /dev/ps3vram) from the distro
> > > maintainer's shoulders, as in that case there would never have been a stable
> > > kernel version containing the MTD-based ps3vram driver.
> > 
> > This is very very very late ... we are at rc7, probably one rc before
> > final... as much as I like integrating drivers later, I'll ask Linus
> > opinion on this one.
> > 
> > Linus ? What do you reckon ? Maybe a better option is just to remove
> > ps3nvram from .29 and merge the new one in .30 ?
> 
> It's an isolated driver for a special purpose platform, I would have
> zero problems merging it :-)

Here's the new version, incorporating all the review comments.

Please apply for 2.6.29, thanks!
---
>From d7ddc1aaee1ff6dd6a73bd3663b6c390800e0500 Mon Sep 17 00:00:00 2001
From: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date: Wed, 25 Feb 2009 18:32:10 +0100
Subject: [PATCH] ps3/block: Replace mtd/ps3vram by block/ps3vram

Convert the PS3 Video RAM Storage Driver from an MTD driver to a plain block
device driver.

The ps3vram driver exposes unused video RAM on the PS3 as a block device
suitable for storage or swap.  Fast data transfer is achieved using a local
cache in system RAM and DMA transfers via the GPU.

The new driver is ca. 50% faster for reading, and ca. 10% for writing.

Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: David Woodhouse <David.Woodhouse@intel.com>
Cc: Vivien Chappelier <vivien.chappelier@free.fr>
Cc: Jim Paris <jim@jtan.com>
---
The MTD-based PS3 Video RAM Storage Driver was integrated into the mainline
kernel in 2.6.29-rc1.

Ideally, we think it would be best if the existing MTD-based ps3vram driver
would be replaced by the new block-based ps3vram driver before 2.6.29 is
released. This would relieve the burden of supporting two different swap space
schemes on PS3 (swap on /dev/mtdblock0 vs. /dev/ps3vram) from the distro
maintainer's shoulders, as in that case there would never have been a stable
kernel version containing the MTD-based ps3vram driver.

Changes since previous submission (Wed, 4 Mar 2009 14:57:20 +0100 (CET)):
  - Use blk_queue_make_request() to get rid of the thread
  - Add a mutex (cfr. the old driver), as ps3vram_make_request() may be called
    concurrently
    TO DO (after 2.6.29): use a spinlock and a list to queue requests while the
    driver is busy
  - Remove the old MTD-based ps3vram driver and rename ps3vram-ng to ps3vram
  - Make PS3_VRAM depend on FB_PS3=y and m for now
    ps3vram relies on ps3fb being initialized first. The easiest way to do this
    is by making ps3vram modular, and ps3fb builtin
  - Remove the dependency on ps3fb_videomemory.size
    The loop to reduce ddr_size until it succeeds does the right thing anyway,
    and a few MiB of DDR RAM are reserved by the hypervisor
  - lv1 return codes can be int
  - Correct a few debug annotations

 arch/powerpc/platforms/ps3/Kconfig |    7 +
 drivers/block/Makefile             |    1 +
 drivers/block/ps3vram.c            |  865 ++++++++++++++++++++++++++++++++++++
 drivers/mtd/devices/Kconfig        |    7 -
 drivers/mtd/devices/Makefile       |    1 -
 drivers/mtd/devices/ps3vram.c      |  768 --------------------------------
 6 files changed, 873 insertions(+), 776 deletions(-)
 create mode 100644 drivers/block/ps3vram.c
 delete mode 100644 drivers/mtd/devices/ps3vram.c

diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 920cf7a..740ef56 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -128,6 +128,13 @@ config PS3_FLASH
 	  be disabled on the kernel command line using "ps3flash=off", to
 	  not allocate this fixed buffer.
 
+config PS3_VRAM
+	tristate "PS3 Video RAM Storage Driver"
+	depends on FB_PS3=y && BLOCK && m
+	help
+	  This driver allows you to use excess PS3 video RAM as volatile
+	  storage or system swap.
+
 config PS3_LPM
 	tristate "PS3 Logical Performance Monitor support"
 	depends on PPC_PS3
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 204332b..87e120e 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy.o
 obj-$(CONFIG_AMIGA_FLOPPY)	+= amiflop.o
 obj-$(CONFIG_PS3_DISK)		+= ps3disk.o
+obj-$(CONFIG_PS3_VRAM)		+= ps3vram.o
 obj-$(CONFIG_ATARI_FLOPPY)	+= ataflop.o
 obj-$(CONFIG_AMIGA_Z2RAM)	+= z2ram.o
 obj-$(CONFIG_BLK_DEV_RAM)	+= brd.o
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
new file mode 100644
index 0000000..393ed67
--- /dev/null
+++ b/drivers/block/ps3vram.c
@@ -0,0 +1,865 @@
+/*
+ * ps3vram - Use extra PS3 video ram as MTD block device.
+ *
+ * Copyright 2009 Sony Corporation
+ *
+ * Based on the MTD ps3vram driver, which is
+ * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com>
+ * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr>
+ */
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/firmware.h>
+#include <asm/lv1call.h>
+#include <asm/ps3.h>
+
+
+#define DEVICE_NAME		"ps3vram"
+
+
+#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */
+#define XDR_IOIF 0x0c000000
+
+#define FIFO_BASE XDR_IOIF
+#define FIFO_SIZE (64 * 1024)
+
+#define DMA_PAGE_SIZE (4 * 1024)
+
+#define CACHE_PAGE_SIZE (256 * 1024)
+#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE)
+
+#define CACHE_OFFSET CACHE_PAGE_SIZE
+#define FIFO_OFFSET 0
+
+#define CTRL_PUT 0x10
+#define CTRL_GET 0x11
+#define CTRL_TOP 0x15
+
+#define UPLOAD_SUBCH	1
+#define DOWNLOAD_SUBCH	2
+
+#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN	0x0000030c
+#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY	0x00000104
+
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
+
+#define CACHE_PAGE_PRESENT 1
+#define CACHE_PAGE_DIRTY   2
+
+struct ps3vram_tag {
+	unsigned int address;
+	unsigned int flags;
+};
+
+struct ps3vram_cache {
+	unsigned int page_count;
+	unsigned int page_size;
+	struct ps3vram_tag *tags;
+	unsigned int hit;
+	unsigned int miss;
+};
+
+struct ps3vram_priv {
+	struct request_queue *queue;
+	struct gendisk *gendisk;
+
+	u64 size;
+
+	u64 memory_handle;
+	u64 context_handle;
+	u32 *ctrl;
+	u32 *reports;
+	u8 __iomem *ddr_base;
+	u8 *xdr_buf;
+
+	u32 *fifo_base;
+	u32 *fifo_ptr;
+
+	struct ps3vram_cache cache;
+
+	/* Used to serialize cache/DMA operations */
+	struct mutex lock;
+};
+
+
+static int ps3vram_major;
+
+
+static struct block_device_operations ps3vram_fops = {
+	.owner		= THIS_MODULE,
+};
+
+
+#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
+#define DMA_NOTIFIER_OFFSET_BASE 0x1000     /* first DMA notifier offset */
+#define DMA_NOTIFIER_SIZE        0x40
+#define NOTIFIER 7	/* notifier used for completion report */
+
+static char *size = "256M";
+module_param(size, charp, 0);
+MODULE_PARM_DESC(size, "memory size");
+
+static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
+{
+	return (void *)reports + DMA_NOTIFIER_OFFSET_BASE +
+	       DMA_NOTIFIER_SIZE * notifier;
+}
+
+static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
+	int i;
+
+	for (i = 0; i < 4; i++)
+		notify[i] = 0xffffffff;
+}
+
+static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
+				 unsigned int timeout_ms)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
+	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+	do {
+		if (!notify[3])
+			return 0;
+		msleep(1);
+	} while (time_before(jiffies, timeout));
+
+	return -ETIMEDOUT;
+}
+
+static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+
+	priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
+	priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
+}
+
+static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
+			     unsigned int timeout_ms)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+	do {
+		if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET])
+			return 0;
+		msleep(1);
+	} while (time_before(jiffies, timeout));
+
+	dev_warn(&dev->core, "FIFO timeout (%08x/%08x/%08x)\n",
+		 priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET],
+		 priv->ctrl[CTRL_TOP]);
+
+	return -ETIMEDOUT;
+}
+
+static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data)
+{
+	*(priv->fifo_ptr)++ = data;
+}
+
+static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag,
+			       u32 size)
+{
+	ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag);
+}
+
+static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	int status;
+
+	ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
+
+	priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
+
+	/* asking the HV for a blit will kick the FIFO */
+	status = lv1_gpu_context_attribute(priv->context_handle,
+					   L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
+					   0, 0, 0);
+	if (status)
+		dev_err(&dev->core,
+			"%s: lv1_gpu_context_attribute failed %d\n", __func__,
+			status);
+
+	priv->fifo_ptr = priv->fifo_base;
+}
+
+static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	int status;
+
+	mutex_lock(&ps3_gpu_mutex);
+
+	priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET +
+			       (priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
+
+	/* asking the HV for a blit will kick the FIFO */
+	status = lv1_gpu_context_attribute(priv->context_handle,
+					   L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
+					   0, 0, 0);
+	if (status)
+		dev_err(&dev->core,
+			"%s: lv1_gpu_context_attribute failed %d\n", __func__,
+			status);
+
+	if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
+	    FIFO_SIZE - 1024) {
+		dev_dbg(&dev->core, "FIFO full, rewinding\n");
+		ps3vram_wait_ring(dev, 200);
+		ps3vram_rewind_ring(dev);
+	}
+
+	mutex_unlock(&ps3_gpu_mutex);
+}
+
+static void ps3vram_bind(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+
+	ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
+	ps3vram_out_ring(priv, 0x31337303);
+	ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3);
+	ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
+	ps3vram_out_ring(priv, 0xfeed0001);	/* DMA system RAM instance */
+	ps3vram_out_ring(priv, 0xfeed0000);     /* DMA video RAM instance */
+
+	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1);
+	ps3vram_out_ring(priv, 0x3137c0de);
+	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3);
+	ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
+	ps3vram_out_ring(priv, 0xfeed0000);	/* DMA video RAM instance */
+	ps3vram_out_ring(priv, 0xfeed0001);	/* DMA system RAM instance */
+
+	ps3vram_fire_ring(dev);
+}
+
+static int ps3vram_upload(struct ps3_system_bus_device *dev,
+			  unsigned int src_offset, unsigned int dst_offset,
+			  int len, int count)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+
+	ps3vram_begin_ring(priv, UPLOAD_SUBCH,
+			   NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+	ps3vram_out_ring(priv, XDR_IOIF + src_offset);
+	ps3vram_out_ring(priv, dst_offset);
+	ps3vram_out_ring(priv, len);
+	ps3vram_out_ring(priv, len);
+	ps3vram_out_ring(priv, len);
+	ps3vram_out_ring(priv, count);
+	ps3vram_out_ring(priv, (1 << 8) | 1);
+	ps3vram_out_ring(priv, 0);
+
+	ps3vram_notifier_reset(dev);
+	ps3vram_begin_ring(priv, UPLOAD_SUBCH,
+			   NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
+	ps3vram_out_ring(priv, 0);
+	ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1);
+	ps3vram_out_ring(priv, 0);
+	ps3vram_fire_ring(dev);
+	if (ps3vram_notifier_wait(dev, 200) < 0) {
+		dev_warn(&dev->core, "%s: Notifier timeout\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int ps3vram_download(struct ps3_system_bus_device *dev,
+			    unsigned int src_offset, unsigned int dst_offset,
+			    int len, int count)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+
+	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
+			   NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+	ps3vram_out_ring(priv, src_offset);
+	ps3vram_out_ring(priv, XDR_IOIF + dst_offset);
+	ps3vram_out_ring(priv, len);
+	ps3vram_out_ring(priv, len);
+	ps3vram_out_ring(priv, len);
+	ps3vram_out_ring(priv, count);
+	ps3vram_out_ring(priv, (1 << 8) | 1);
+	ps3vram_out_ring(priv, 0);
+
+	ps3vram_notifier_reset(dev);
+	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
+			   NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
+	ps3vram_out_ring(priv, 0);
+	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1);
+	ps3vram_out_ring(priv, 0);
+	ps3vram_fire_ring(dev);
+	if (ps3vram_notifier_wait(dev, 200) < 0) {
+		dev_warn(&dev->core, "%s: Notifier timeout\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	struct ps3vram_cache *cache = &priv->cache;
+
+	if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY))
+		return;
+
+	dev_dbg(&dev->core, "Flushing %d: 0x%08x\n", entry,
+		cache->tags[entry].address);
+	if (ps3vram_upload(dev, CACHE_OFFSET + entry * cache->page_size,
+			   cache->tags[entry].address, DMA_PAGE_SIZE,
+			   cache->page_size / DMA_PAGE_SIZE) < 0) {
+		dev_err(&dev->core,
+			"Failed to upload from 0x%x to " "0x%x size 0x%x\n",
+			entry * cache->page_size, cache->tags[entry].address,
+			cache->page_size);
+	}
+	cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY;
+}
+
+static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
+			       unsigned int address)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	struct ps3vram_cache *cache = &priv->cache;
+
+	dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address);
+	if (ps3vram_download(dev, address,
+			     CACHE_OFFSET + entry * cache->page_size,
+			     DMA_PAGE_SIZE,
+			     cache->page_size / DMA_PAGE_SIZE) < 0) {
+		dev_err(&dev->core,
+			"Failed to download from 0x%x to 0x%x size 0x%x\n",
+			address, entry * cache->page_size, cache->page_size);
+	}
+
+	cache->tags[entry].address = address;
+	cache->tags[entry].flags |= CACHE_PAGE_PRESENT;
+}
+
+
+static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	struct ps3vram_cache *cache = &priv->cache;
+	int i;
+
+	dev_dbg(&dev->core, "FLUSH\n");
+	for (i = 0; i < cache->page_count; i++) {
+		ps3vram_cache_evict(dev, i);
+		cache->tags[i].flags = 0;
+	}
+}
+
+static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
+					loff_t address)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	struct ps3vram_cache *cache = &priv->cache;
+	unsigned int base;
+	unsigned int offset;
+	int i;
+	static int counter;
+
+	offset = (unsigned int) (address & (cache->page_size - 1));
+	base = (unsigned int) (address - offset);
+
+	/* fully associative check */
+	for (i = 0; i < cache->page_count; i++) {
+		if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) &&
+		    cache->tags[i].address == base) {
+			cache->hit++;
+			dev_dbg(&dev->core, "Found entry %d: 0x%08x\n", i,
+				cache->tags[i].address);
+			return i;
+		}
+	}
+
+	/* choose a random entry */
+	i = (jiffies + (counter++)) % cache->page_count;
+	dev_dbg(&dev->core, "Using entry %d\n", i);
+
+	ps3vram_cache_evict(dev, i);
+	ps3vram_cache_load(dev, i, base);
+
+	cache->miss++;
+	return i;
+}
+
+static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+
+	priv->cache.page_count = CACHE_PAGE_COUNT;
+	priv->cache.page_size = CACHE_PAGE_SIZE;
+	priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) *
+				   CACHE_PAGE_COUNT, GFP_KERNEL);
+	if (priv->cache.tags == NULL) {
+		dev_err(&dev->core, "Could not allocate cache tags\n");
+		return -ENOMEM;
+	}
+
+	dev_info(&dev->core, "Created ram cache: %d entries, %d KiB each\n",
+		CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024);
+
+	return 0;
+}
+
+static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+
+	ps3vram_cache_flush(dev);
+	kfree(priv->cache.tags);
+}
+
+static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
+			size_t len, size_t *retlen, u_char *buf)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	unsigned int cached, count;
+
+	dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__,
+		(unsigned int)from, len);
+
+	if (from >= priv->size)
+		return -EIO;
+
+	if (len > priv->size - from)
+		len = priv->size - from;
+
+	/* Copy from vram to buf */
+	count = len;
+	while (count) {
+		unsigned int offset, avail;
+		unsigned int entry;
+
+		offset = (unsigned int) (from & (priv->cache.page_size - 1));
+		avail  = priv->cache.page_size - offset;
+
+		mutex_lock(&priv->lock);
+
+		entry = ps3vram_cache_match(dev, from);
+		cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
+
+		dev_dbg(&dev->core, "%s: from=%08x cached=%08x offset=%08x "
+			"avail=%08x count=%08x\n", __func__,
+			(unsigned int)from, cached, offset, avail, count);
+
+		if (avail > count)
+			avail = count;
+		memcpy(buf, priv->xdr_buf + cached, avail);
+
+		mutex_unlock(&priv->lock);
+
+		buf += avail;
+		count -= avail;
+		from += avail;
+	}
+
+	*retlen = len;
+	return 0;
+}
+
+static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
+			 size_t len, size_t *retlen, const u_char *buf)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	unsigned int cached, count;
+
+	if (to >= priv->size)
+		return -EIO;
+
+	if (len > priv->size - to)
+		len = priv->size - to;
+
+	/* Copy from buf to vram */
+	count = len;
+	while (count) {
+		unsigned int offset, avail;
+		unsigned int entry;
+
+		offset = (unsigned int) (to & (priv->cache.page_size - 1));
+		avail  = priv->cache.page_size - offset;
+
+		mutex_lock(&priv->lock);
+
+		entry = ps3vram_cache_match(dev, to);
+		cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
+
+		dev_dbg(&dev->core, "%s: to=%08x cached=%08x offset=%08x "
+			"avail=%08x count=%08x\n", __func__, (unsigned int)to,
+			cached, offset, avail, count);
+
+		if (avail > count)
+			avail = count;
+		memcpy(priv->xdr_buf + cached, buf, avail);
+
+		priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
+
+		mutex_unlock(&priv->lock);
+
+		buf += avail;
+		count -= avail;
+		to += avail;
+	}
+
+	*retlen = len;
+	return 0;
+}
+
+static int ps3vram_proc_show(struct seq_file *m, void *v)
+{
+	struct ps3vram_priv *priv = m->private;
+
+	seq_printf(m, "hit:%u\nmiss:%u\n", priv->cache.hit, priv->cache.miss);
+	return 0;
+}
+
+static int ps3vram_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ps3vram_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations ps3vram_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= ps3vram_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+	struct proc_dir_entry *pde;
+
+	pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops);
+	if (!pde) {
+		dev_warn(&dev->core, "failed to create /proc entry\n");
+		return;
+	}
+
+	pde->owner = THIS_MODULE;
+	pde->data = priv;
+}
+
+static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
+{
+	struct ps3_system_bus_device *dev = q->queuedata;
+	int write = bio_data_dir(bio) == WRITE;
+	const char *op = write ? "write" : "read";
+	loff_t offset = bio->bi_sector << 9;
+	int error = 0;
+	struct bio_vec *bvec;
+	unsigned int i;
+
+	dev_dbg(&dev->core, "%s\n", __func__);
+
+	bio_for_each_segment(bvec, bio, i) {
+		/* PS3 is ppc64, so we don't handle highmem */
+		char *ptr = page_address(bvec->bv_page) + bvec->bv_offset;
+		size_t len = bvec->bv_len, retlen;
+
+		dev_dbg(&dev->core, "    %s %zu bytes at offset %llu\n", op,
+			len, offset);
+		if (write)
+			error = ps3vram_write(dev, offset, len, &retlen, ptr);
+		else
+			error = ps3vram_read(dev, offset, len, &retlen, ptr);
+
+		if (error) {
+			dev_err(&dev->core, "%s failed\n", op);
+			goto out;
+		}
+
+		if (retlen != len) {
+			dev_err(&dev->core, "Short %s\n", op);
+			goto out;
+		}
+
+		offset += len;
+	}
+
+	dev_dbg(&dev->core, "%s completed\n", op);
+
+out:
+	bio_endio(bio, error);
+	return 0;
+}
+
+static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv;
+	int error, status;
+	struct request_queue *queue;
+	struct gendisk *gendisk;
+	u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size,
+	    reports_size;
+	char *rest;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	mutex_init(&priv->lock);
+	dev->core.driver_data = priv;
+
+	priv = dev->core.driver_data;
+
+	/* Allocate XDR buffer (1MiB aligned) */
+	priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
+		get_order(XDR_BUF_SIZE));
+	if (priv->xdr_buf == NULL) {
+		dev_err(&dev->core, "Could not allocate XDR buffer\n");
+		error = -ENOMEM;
+		goto fail_free_priv;
+	}
+
+	/* Put FIFO at begginning of XDR buffer */
+	priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET);
+	priv->fifo_ptr = priv->fifo_base;
+
+	/* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */
+	if (ps3_open_hv_device(dev)) {
+		dev_err(&dev->core, "ps3_open_hv_device failed\n");
+		error = -EAGAIN;
+		goto out_close_gpu;
+	}
+
+	/* Request memory */
+	status = -1;
+	ddr_size = ALIGN(memparse(size, &rest), 1024*1024);
+	if (!ddr_size) {
+		dev_err(&dev->core, "Specified size is too small\n");
+		error = -EINVAL;
+		goto out_close_gpu;
+	}
+
+	while (ddr_size > 0) {
+		status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0,
+						 &priv->memory_handle,
+						 &ddr_lpar);
+		if (!status)
+			break;
+		ddr_size -= 1024*1024;
+	}
+	if (status) {
+		dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n",
+			status);
+		error = -ENOMEM;
+		goto out_free_xdr_buf;
+	}
+
+	/* Request context */
+	status = lv1_gpu_context_allocate(priv->memory_handle, 0,
+					  &priv->context_handle, &ctrl_lpar,
+					  &info_lpar, &reports_lpar,
+					  &reports_size);
+	if (status) {
+		dev_err(&dev->core, "lv1_gpu_context_allocate failed %d\n",
+			status);
+		error = -ENOMEM;
+		goto out_free_memory;
+	}
+
+	/* Map XDR buffer to RSX */
+	status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
+				       ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
+				       XDR_BUF_SIZE, 0);
+	if (status) {
+		dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
+			status);
+		error = -ENOMEM;
+		goto out_free_context;
+	}
+
+	priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
+
+	if (!priv->ddr_base) {
+		dev_err(&dev->core, "ioremap DDR failed\n");
+		error = -ENOMEM;
+		goto out_free_context;
+	}
+
+	priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
+	if (!priv->ctrl) {
+		dev_err(&dev->core, "ioremap CTRL failed\n");
+		error = -ENOMEM;
+		goto out_unmap_vram;
+	}
+
+	priv->reports = ioremap(reports_lpar, reports_size);
+	if (!priv->reports) {
+		dev_err(&dev->core, "ioremap REPORTS failed\n");
+		error = -ENOMEM;
+		goto out_unmap_ctrl;
+	}
+
+	mutex_lock(&ps3_gpu_mutex);
+	ps3vram_init_ring(dev);
+	mutex_unlock(&ps3_gpu_mutex);
+
+	priv->size = ddr_size;
+
+	ps3vram_bind(dev);
+
+	mutex_lock(&ps3_gpu_mutex);
+	error = ps3vram_wait_ring(dev, 100);
+	mutex_unlock(&ps3_gpu_mutex);
+	if (error < 0) {
+		dev_err(&dev->core, "Failed to initialize channels\n");
+		error = -ETIMEDOUT;
+		goto out_unmap_reports;
+	}
+
+	ps3vram_cache_init(dev);
+	ps3vram_proc_init(dev);
+
+	queue = blk_alloc_queue(GFP_KERNEL);
+	if (!queue) {
+		dev_err(&dev->core, "blk_alloc_queue failed\n");
+		error = -ENOMEM;
+		goto out_cache_cleanup;
+	}
+
+	priv->queue = queue;
+	queue->queuedata = dev;
+	blk_queue_make_request(queue, ps3vram_make_request);
+	blk_queue_max_phys_segments(queue, MAX_PHYS_SEGMENTS);
+	blk_queue_max_hw_segments(queue, MAX_HW_SEGMENTS);
+	blk_queue_max_segment_size(queue, MAX_SEGMENT_SIZE);
+	blk_queue_max_sectors(queue, SAFE_MAX_SECTORS);
+
+	gendisk = alloc_disk(1);
+	if (!gendisk) {
+		dev_err(&dev->core, "alloc_disk failed\n");
+		error = -ENOMEM;
+		goto fail_cleanup_queue;
+	}
+
+	priv->gendisk = gendisk;
+	gendisk->major = ps3vram_major;
+	gendisk->first_minor = 0;
+	gendisk->fops = &ps3vram_fops;
+	gendisk->queue = queue;
+	gendisk->private_data = dev;
+	gendisk->driverfs_dev = &dev->core;
+	strlcpy(gendisk->disk_name, DEVICE_NAME, sizeof(gendisk->disk_name));
+	set_capacity(gendisk, priv->size >> 9);
+
+	dev_info(&dev->core, "%s: Using %lu MiB of GPU memory\n",
+		 gendisk->disk_name, get_capacity(gendisk) >> 11);
+
+	add_disk(gendisk);
+	return 0;
+
+fail_cleanup_queue:
+	blk_cleanup_queue(queue);
+out_cache_cleanup:
+	remove_proc_entry(DEVICE_NAME, NULL);
+	ps3vram_cache_cleanup(dev);
+out_unmap_reports:
+	iounmap(priv->reports);
+out_unmap_ctrl:
+	iounmap(priv->ctrl);
+out_unmap_vram:
+	iounmap(priv->ddr_base);
+out_free_context:
+	lv1_gpu_context_free(priv->context_handle);
+out_free_memory:
+	lv1_gpu_memory_free(priv->memory_handle);
+out_close_gpu:
+	ps3_close_hv_device(dev);
+out_free_xdr_buf:
+	free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
+fail_free_priv:
+	kfree(priv);
+	dev->core.driver_data = NULL;
+fail:
+	return error;
+}
+
+static int ps3vram_remove(struct ps3_system_bus_device *dev)
+{
+	struct ps3vram_priv *priv = dev->core.driver_data;
+
+	del_gendisk(priv->gendisk);
+	put_disk(priv->gendisk);
+	blk_cleanup_queue(priv->queue);
+	remove_proc_entry(DEVICE_NAME, NULL);
+	ps3vram_cache_cleanup(dev);
+	iounmap(priv->reports);
+	iounmap(priv->ctrl);
+	iounmap(priv->ddr_base);
+	lv1_gpu_context_free(priv->context_handle);
+	lv1_gpu_memory_free(priv->memory_handle);
+	ps3_close_hv_device(dev);
+	free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
+	kfree(priv);
+	dev->core.driver_data = NULL;
+	return 0;
+}
+
+static struct ps3_system_bus_driver ps3vram = {
+	.match_id	= PS3_MATCH_ID_GPU,
+	.match_sub_id	= PS3_MATCH_SUB_ID_GPU_RAMDISK,
+	.core.name	= DEVICE_NAME,
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3vram_probe,
+	.remove		= ps3vram_remove,
+	.shutdown	= ps3vram_remove,
+};
+
+
+static int __init ps3vram_init(void)
+{
+	int error;
+
+	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+		return -ENODEV;
+
+	error = register_blkdev(0, DEVICE_NAME);
+	if (error <= 0) {
+		pr_err("%s: register_blkdev failed %d\n", DEVICE_NAME, error);
+		return error;
+	}
+	ps3vram_major = error;
+
+	pr_info("%s: registered block device major %d\n", DEVICE_NAME,
+		ps3vram_major);
+
+	error = ps3_system_bus_driver_register(&ps3vram);
+	if (error)
+		unregister_blkdev(ps3vram_major, DEVICE_NAME);
+
+	return error;
+}
+
+static void __exit ps3vram_exit(void)
+{
+	ps3_system_bus_driver_unregister(&ps3vram);
+	unregister_blkdev(ps3vram_major, DEVICE_NAME);
+}
+
+module_init(ps3vram_init);
+module_exit(ps3vram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 Video RAM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK);
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index bc33200..6fde0a2 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -120,13 +120,6 @@ config MTD_PHRAM
 	  doesn't have access to, memory beyond the mem=xxx limit, nvram,
 	  memory on the video card, etc...
 
-config MTD_PS3VRAM
-	tristate "PS3 video RAM"
-	depends on FB_PS3
-	help
-	  This driver allows you to use excess PS3 video RAM as volatile
-	  storage or system swap.
-
 config MTD_LART
 	tristate "28F160xx flash driver for LART"
 	depends on SA1100_LART
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index e51521d..0993d5c 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,4 +16,3 @@ obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
-obj-$(CONFIG_MTD_PS3VRAM)	+= ps3vram.o
diff --git a/drivers/mtd/devices/ps3vram.c b/drivers/mtd/devices/ps3vram.c
deleted file mode 100644
index d21e9be..0000000
--- a/drivers/mtd/devices/ps3vram.c
+++ /dev/null
@@ -1,768 +0,0 @@
-/**
- * ps3vram - Use extra PS3 video ram as MTD block device.
- *
- * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com>
- * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr>
- */
-
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <linux/gfp.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-
-#include <asm/lv1call.h>
-#include <asm/ps3.h>
-
-#define DEVICE_NAME		"ps3vram"
-
-#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */
-#define XDR_IOIF 0x0c000000
-
-#define FIFO_BASE XDR_IOIF
-#define FIFO_SIZE (64 * 1024)
-
-#define DMA_PAGE_SIZE (4 * 1024)
-
-#define CACHE_PAGE_SIZE (256 * 1024)
-#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE)
-
-#define CACHE_OFFSET CACHE_PAGE_SIZE
-#define FIFO_OFFSET 0
-
-#define CTRL_PUT 0x10
-#define CTRL_GET 0x11
-#define CTRL_TOP 0x15
-
-#define UPLOAD_SUBCH	1
-#define DOWNLOAD_SUBCH	2
-
-#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN	0x0000030c
-#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY	0x00000104
-
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
-
-struct mtd_info ps3vram_mtd;
-
-#define CACHE_PAGE_PRESENT 1
-#define CACHE_PAGE_DIRTY   2
-
-struct ps3vram_tag {
-	unsigned int address;
-	unsigned int flags;
-};
-
-struct ps3vram_cache {
-	unsigned int page_count;
-	unsigned int page_size;
-	struct ps3vram_tag *tags;
-};
-
-struct ps3vram_priv {
-	u64 memory_handle;
-	u64 context_handle;
-	u32 *ctrl;
-	u32 *reports;
-	u8 __iomem *ddr_base;
-	u8 *xdr_buf;
-
-	u32 *fifo_base;
-	u32 *fifo_ptr;
-
-	struct device *dev;
-	struct ps3vram_cache cache;
-
-	/* Used to serialize cache/DMA operations */
-	struct mutex lock;
-};
-
-#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
-#define DMA_NOTIFIER_OFFSET_BASE 0x1000     /* first DMA notifier offset */
-#define DMA_NOTIFIER_SIZE        0x40
-#define NOTIFIER 7	/* notifier used for completion report */
-
-/* A trailing '-' means to subtract off ps3fb_videomemory.size */
-char *size = "256M-";
-module_param(size, charp, 0);
-MODULE_PARM_DESC(size, "memory size");
-
-static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
-{
-	return (void *) reports +
-		DMA_NOTIFIER_OFFSET_BASE +
-		DMA_NOTIFIER_SIZE * notifier;
-}
-
-static void ps3vram_notifier_reset(struct mtd_info *mtd)
-{
-	int i;
-
-	struct ps3vram_priv *priv = mtd->priv;
-	u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
-	for (i = 0; i < 4; i++)
-		notify[i] = 0xffffffff;
-}
-
-static int ps3vram_notifier_wait(struct mtd_info *mtd, unsigned int timeout_ms)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
-	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
-
-	do {
-		if (!notify[3])
-			return 0;
-		msleep(1);
-	} while (time_before(jiffies, timeout));
-
-	return -ETIMEDOUT;
-}
-
-static void ps3vram_init_ring(struct mtd_info *mtd)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-
-	priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
-	priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
-}
-
-static int ps3vram_wait_ring(struct mtd_info *mtd, unsigned int timeout_ms)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
-
-	do {
-		if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET])
-			return 0;
-		msleep(1);
-	} while (time_before(jiffies, timeout));
-
-	dev_dbg(priv->dev, "%s:%d: FIFO timeout (%08x/%08x/%08x)\n", __func__,
-		__LINE__, priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET],
-		priv->ctrl[CTRL_TOP]);
-
-	return -ETIMEDOUT;
-}
-
-static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data)
-{
-	*(priv->fifo_ptr)++ = data;
-}
-
-static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan,
-				      u32 tag, u32 size)
-{
-	ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag);
-}
-
-static void ps3vram_rewind_ring(struct mtd_info *mtd)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	u64 status;
-
-	ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
-
-	priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
-
-	/* asking the HV for a blit will kick the fifo */
-	status = lv1_gpu_context_attribute(priv->context_handle,
-					   L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
-					   0, 0, 0, 0);
-	if (status)
-		dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n",
-			__func__, __LINE__);
-
-	priv->fifo_ptr = priv->fifo_base;
-}
-
-static void ps3vram_fire_ring(struct mtd_info *mtd)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	u64 status;
-
-	mutex_lock(&ps3_gpu_mutex);
-
-	priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET +
-		(priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
-
-	/* asking the HV for a blit will kick the fifo */
-	status = lv1_gpu_context_attribute(priv->context_handle,
-					   L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
-					   0, 0, 0, 0);
-	if (status)
-		dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n",
-			__func__, __LINE__);
-
-	if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
-		FIFO_SIZE - 1024) {
-		dev_dbg(priv->dev, "%s:%d: fifo full, rewinding\n", __func__,
-			__LINE__);
-		ps3vram_wait_ring(mtd, 200);
-		ps3vram_rewind_ring(mtd);
-	}
-
-	mutex_unlock(&ps3_gpu_mutex);
-}
-
-static void ps3vram_bind(struct mtd_info *mtd)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-
-	ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
-	ps3vram_out_ring(priv, 0x31337303);
-	ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3);
-	ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
-	ps3vram_out_ring(priv, 0xfeed0001);	/* DMA system RAM instance */
-	ps3vram_out_ring(priv, 0xfeed0000);     /* DMA video RAM instance */
-
-	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1);
-	ps3vram_out_ring(priv, 0x3137c0de);
-	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3);
-	ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
-	ps3vram_out_ring(priv, 0xfeed0000);	/* DMA video RAM instance */
-	ps3vram_out_ring(priv, 0xfeed0001);	/* DMA system RAM instance */
-
-	ps3vram_fire_ring(mtd);
-}
-
-static int ps3vram_upload(struct mtd_info *mtd, unsigned int src_offset,
-			  unsigned int dst_offset, int len, int count)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-
-	ps3vram_begin_ring(priv, UPLOAD_SUBCH,
-			   NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
-	ps3vram_out_ring(priv, XDR_IOIF + src_offset);
-	ps3vram_out_ring(priv, dst_offset);
-	ps3vram_out_ring(priv, len);
-	ps3vram_out_ring(priv, len);
-	ps3vram_out_ring(priv, len);
-	ps3vram_out_ring(priv, count);
-	ps3vram_out_ring(priv, (1 << 8) | 1);
-	ps3vram_out_ring(priv, 0);
-
-	ps3vram_notifier_reset(mtd);
-	ps3vram_begin_ring(priv, UPLOAD_SUBCH,
-			   NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
-	ps3vram_out_ring(priv, 0);
-	ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1);
-	ps3vram_out_ring(priv, 0);
-	ps3vram_fire_ring(mtd);
-	if (ps3vram_notifier_wait(mtd, 200) < 0) {
-		dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__,
-			__LINE__);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int ps3vram_download(struct mtd_info *mtd, unsigned int src_offset,
-			    unsigned int dst_offset, int len, int count)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-
-	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
-			   NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
-	ps3vram_out_ring(priv, src_offset);
-	ps3vram_out_ring(priv, XDR_IOIF + dst_offset);
-	ps3vram_out_ring(priv, len);
-	ps3vram_out_ring(priv, len);
-	ps3vram_out_ring(priv, len);
-	ps3vram_out_ring(priv, count);
-	ps3vram_out_ring(priv, (1 << 8) | 1);
-	ps3vram_out_ring(priv, 0);
-
-	ps3vram_notifier_reset(mtd);
-	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
-			   NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
-	ps3vram_out_ring(priv, 0);
-	ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1);
-	ps3vram_out_ring(priv, 0);
-	ps3vram_fire_ring(mtd);
-	if (ps3vram_notifier_wait(mtd, 200) < 0) {
-		dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__,
-			__LINE__);
-		return -1;
-	}
-
-	return 0;
-}
-
-static void ps3vram_cache_evict(struct mtd_info *mtd, int entry)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	struct ps3vram_cache *cache = &priv->cache;
-
-	if (cache->tags[entry].flags & CACHE_PAGE_DIRTY) {
-		dev_dbg(priv->dev, "%s:%d: flushing %d : 0x%08x\n", __func__,
-			__LINE__, entry, cache->tags[entry].address);
-		if (ps3vram_upload(mtd,
-				   CACHE_OFFSET + entry * cache->page_size,
-				   cache->tags[entry].address,
-				   DMA_PAGE_SIZE,
-				   cache->page_size / DMA_PAGE_SIZE) < 0) {
-			dev_dbg(priv->dev, "%s:%d: failed to upload from "
-				"0x%x to 0x%x size 0x%x\n", __func__, __LINE__,
-				entry * cache->page_size,
-				cache->tags[entry].address, cache->page_size);
-		}
-		cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY;
-	}
-}
-
-static void ps3vram_cache_load(struct mtd_info *mtd, int entry,
-			       unsigned int address)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	struct ps3vram_cache *cache = &priv->cache;
-
-	dev_dbg(priv->dev, "%s:%d: fetching %d : 0x%08x\n", __func__, __LINE__,
-		entry, address);
-	if (ps3vram_download(mtd,
-			     address,
-			     CACHE_OFFSET + entry * cache->page_size,
-			     DMA_PAGE_SIZE,
-			     cache->page_size / DMA_PAGE_SIZE) < 0) {
-		dev_err(priv->dev, "%s:%d: failed to download from "
-			"0x%x to 0x%x size 0x%x\n", __func__, __LINE__, address,
-			entry * cache->page_size, cache->page_size);
-	}
-
-	cache->tags[entry].address = address;
-	cache->tags[entry].flags |= CACHE_PAGE_PRESENT;
-}
-
-
-static void ps3vram_cache_flush(struct mtd_info *mtd)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	struct ps3vram_cache *cache = &priv->cache;
-	int i;
-
-	dev_dbg(priv->dev, "%s:%d: FLUSH\n", __func__, __LINE__);
-	for (i = 0; i < cache->page_count; i++) {
-		ps3vram_cache_evict(mtd, i);
-		cache->tags[i].flags = 0;
-	}
-}
-
-static unsigned int ps3vram_cache_match(struct mtd_info *mtd, loff_t address)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	struct ps3vram_cache *cache = &priv->cache;
-	unsigned int base;
-	unsigned int offset;
-	int i;
-	static int counter;
-
-	offset = (unsigned int) (address & (cache->page_size - 1));
-	base = (unsigned int) (address - offset);
-
-	/* fully associative check */
-	for (i = 0; i < cache->page_count; i++) {
-		if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) &&
-		    cache->tags[i].address == base) {
-			dev_dbg(priv->dev, "%s:%d: found entry %d : 0x%08x\n",
-				__func__, __LINE__, i, cache->tags[i].address);
-			return i;
-		}
-	}
-
-	/* choose a random entry */
-	i = (jiffies + (counter++)) % cache->page_count;
-	dev_dbg(priv->dev, "%s:%d: using entry %d\n", __func__, __LINE__, i);
-
-	ps3vram_cache_evict(mtd, i);
-	ps3vram_cache_load(mtd, i, base);
-
-	return i;
-}
-
-static int ps3vram_cache_init(struct mtd_info *mtd)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-
-	priv->cache.page_count = CACHE_PAGE_COUNT;
-	priv->cache.page_size = CACHE_PAGE_SIZE;
-	priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) *
-				   CACHE_PAGE_COUNT, GFP_KERNEL);
-	if (priv->cache.tags == NULL) {
-		dev_err(priv->dev, "%s:%d: could not allocate cache tags\n",
-			__func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	dev_info(priv->dev, "created ram cache: %d entries, %d KiB each\n",
-		CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024);
-
-	return 0;
-}
-
-static void ps3vram_cache_cleanup(struct mtd_info *mtd)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-
-	ps3vram_cache_flush(mtd);
-	kfree(priv->cache.tags);
-}
-
-static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-
-	if (instr->addr + instr->len > mtd->size)
-		return -EINVAL;
-
-	mutex_lock(&priv->lock);
-
-	ps3vram_cache_flush(mtd);
-
-	/* Set bytes to 0xFF */
-	memset_io(priv->ddr_base + instr->addr, 0xFF, instr->len);
-
-	mutex_unlock(&priv->lock);
-
-	instr->state = MTD_ERASE_DONE;
-	mtd_erase_callback(instr);
-
-	return 0;
-}
-
-static int ps3vram_read(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	unsigned int cached, count;
-
-	dev_dbg(priv->dev, "%s:%d: from=0x%08x len=0x%zx\n", __func__, __LINE__,
-		(unsigned int)from, len);
-
-	if (from >= mtd->size)
-		return -EINVAL;
-
-	if (len > mtd->size - from)
-		len = mtd->size - from;
-
-	/* Copy from vram to buf */
-	count = len;
-	while (count) {
-		unsigned int offset, avail;
-		unsigned int entry;
-
-		offset = (unsigned int) (from & (priv->cache.page_size - 1));
-		avail  = priv->cache.page_size - offset;
-
-		mutex_lock(&priv->lock);
-
-		entry = ps3vram_cache_match(mtd, from);
-		cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
-
-		dev_dbg(priv->dev, "%s:%d: from=%08x cached=%08x offset=%08x "
-			"avail=%08x count=%08x\n", __func__, __LINE__,
-			(unsigned int)from, cached, offset, avail, count);
-
-		if (avail > count)
-			avail = count;
-		memcpy(buf, priv->xdr_buf + cached, avail);
-
-		mutex_unlock(&priv->lock);
-
-		buf += avail;
-		count -= avail;
-		from += avail;
-	}
-
-	*retlen = len;
-	return 0;
-}
-
-static int ps3vram_write(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf)
-{
-	struct ps3vram_priv *priv = mtd->priv;
-	unsigned int cached, count;
-
-	if (to >= mtd->size)
-		return -EINVAL;
-
-	if (len > mtd->size - to)
-		len = mtd->size - to;
-
-	/* Copy from buf to vram */
-	count = len;
-	while (count) {
-		unsigned int offset, avail;
-		unsigned int entry;
-
-		offset = (unsigned int) (to & (priv->cache.page_size - 1));
-		avail  = priv->cache.page_size - offset;
-
-		mutex_lock(&priv->lock);
-
-		entry = ps3vram_cache_match(mtd, to);
-		cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
-
-		dev_dbg(priv->dev, "%s:%d: to=%08x cached=%08x offset=%08x "
-			"avail=%08x count=%08x\n", __func__, __LINE__,
-			(unsigned int)to, cached, offset, avail, count);
-
-		if (avail > count)
-			avail = count;
-		memcpy(priv->xdr_buf + cached, buf, avail);
-
-		priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
-
-		mutex_unlock(&priv->lock);
-
-		buf += avail;
-		count -= avail;
-		to += avail;
-	}
-
-	*retlen = len;
-	return 0;
-}
-
-static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
-{
-	struct ps3vram_priv *priv;
-	int status;
-	u64 ddr_lpar;
-	u64 ctrl_lpar;
-	u64 info_lpar;
-	u64 reports_lpar;
-	u64 ddr_size;
-	u64 reports_size;
-	int ret = -ENOMEM;
-	char *rest;
-
-	ret = -EIO;
-	ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL);
-	if (!ps3vram_mtd.priv)
-		goto out;
-	priv = ps3vram_mtd.priv;
-
-	mutex_init(&priv->lock);
-	priv->dev = &dev->core;
-
-	/* Allocate XDR buffer (1MiB aligned) */
-	priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
-		get_order(XDR_BUF_SIZE));
-	if (priv->xdr_buf == NULL) {
-		dev_dbg(&dev->core, "%s:%d: could not allocate XDR buffer\n",
-			__func__, __LINE__);
-		ret = -ENOMEM;
-		goto out_free_priv;
-	}
-
-	/* Put FIFO at begginning of XDR buffer */
-	priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET);
-	priv->fifo_ptr = priv->fifo_base;
-
-	/* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */
-	if (ps3_open_hv_device(dev)) {
-		dev_err(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
-			__func__, __LINE__);
-		ret = -EAGAIN;
-		goto out_close_gpu;
-	}
-
-	/* Request memory */
-	status = -1;
-	ddr_size = memparse(size, &rest);
-	if (*rest == '-')
-		ddr_size -= ps3fb_videomemory.size;
-	ddr_size = ALIGN(ddr_size, 1024*1024);
-	if (ddr_size <= 0) {
-		dev_err(&dev->core, "%s:%d: specified size is too small\n",
-			__func__, __LINE__);
-		ret = -EINVAL;
-		goto out_close_gpu;
-	}
-
-	while (ddr_size > 0) {
-		status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0,
-						 &priv->memory_handle,
-						 &ddr_lpar);
-		if (!status)
-			break;
-		ddr_size -= 1024*1024;
-	}
-	if (status || ddr_size <= 0) {
-		dev_err(&dev->core, "%s:%d: lv1_gpu_memory_allocate failed\n",
-			__func__, __LINE__);
-		ret = -ENOMEM;
-		goto out_free_xdr_buf;
-	}
-
-	/* Request context */
-	status = lv1_gpu_context_allocate(priv->memory_handle,
-					  0,
-					  &priv->context_handle,
-					  &ctrl_lpar,
-					  &info_lpar,
-					  &reports_lpar,
-					  &reports_size);
-	if (status) {
-		dev_err(&dev->core, "%s:%d: lv1_gpu_context_allocate failed\n",
-			__func__, __LINE__);
-		ret = -ENOMEM;
-		goto out_free_memory;
-	}
-
-	/* Map XDR buffer to RSX */
-	status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
-				       ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
-				       XDR_BUF_SIZE, 0);
-	if (status) {
-		dev_err(&dev->core, "%s:%d: lv1_gpu_context_iomap failed\n",
-			__func__, __LINE__);
-		ret = -ENOMEM;
-		goto out_free_context;
-	}
-
-	priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
-
-	if (!priv->ddr_base) {
-		dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
-			__LINE__);
-		ret = -ENOMEM;
-		goto out_free_context;
-	}
-
-	priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
-	if (!priv->ctrl) {
-		dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
-			__LINE__);
-		ret = -ENOMEM;
-		goto out_unmap_vram;
-	}
-
-	priv->reports = ioremap(reports_lpar, reports_size);
-	if (!priv->reports) {
-		dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
-			__LINE__);
-		ret = -ENOMEM;
-		goto out_unmap_ctrl;
-	}
-
-	mutex_lock(&ps3_gpu_mutex);
-	ps3vram_init_ring(&ps3vram_mtd);
-	mutex_unlock(&ps3_gpu_mutex);
-
-	ps3vram_mtd.name = "ps3vram";
-	ps3vram_mtd.size = ddr_size;
-	ps3vram_mtd.flags = MTD_CAP_RAM;
-	ps3vram_mtd.erase = ps3vram_erase;
-	ps3vram_mtd.point = NULL;
-	ps3vram_mtd.unpoint = NULL;
-	ps3vram_mtd.read = ps3vram_read;
-	ps3vram_mtd.write = ps3vram_write;
-	ps3vram_mtd.owner = THIS_MODULE;
-	ps3vram_mtd.type = MTD_RAM;
-	ps3vram_mtd.erasesize = CACHE_PAGE_SIZE;
-	ps3vram_mtd.writesize = 1;
-
-	ps3vram_bind(&ps3vram_mtd);
-
-	mutex_lock(&ps3_gpu_mutex);
-	ret = ps3vram_wait_ring(&ps3vram_mtd, 100);
-	mutex_unlock(&ps3_gpu_mutex);
-	if (ret < 0) {
-		dev_err(&dev->core, "%s:%d: failed to initialize channels\n",
-			__func__, __LINE__);
-		ret = -ETIMEDOUT;
-		goto out_unmap_reports;
-	}
-
-	ps3vram_cache_init(&ps3vram_mtd);
-
-	if (add_mtd_device(&ps3vram_mtd)) {
-		dev_err(&dev->core, "%s:%d: add_mtd_device failed\n",
-			__func__, __LINE__);
-		ret = -EAGAIN;
-		goto out_cache_cleanup;
-	}
-
-	dev_info(&dev->core, "reserved %u MiB of gpu memory\n",
-		(unsigned int)(ddr_size / 1024 / 1024));
-
-	return 0;
-
-out_cache_cleanup:
-	ps3vram_cache_cleanup(&ps3vram_mtd);
-out_unmap_reports:
-	iounmap(priv->reports);
-out_unmap_ctrl:
-	iounmap(priv->ctrl);
-out_unmap_vram:
-	iounmap(priv->ddr_base);
-out_free_context:
-	lv1_gpu_context_free(priv->context_handle);
-out_free_memory:
-	lv1_gpu_memory_free(priv->memory_handle);
-out_close_gpu:
-	ps3_close_hv_device(dev);
-out_free_xdr_buf:
-	free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
-out_free_priv:
-	kfree(ps3vram_mtd.priv);
-	ps3vram_mtd.priv = NULL;
-out:
-	return ret;
-}
-
-static int ps3vram_shutdown(struct ps3_system_bus_device *dev)
-{
-	struct ps3vram_priv *priv;
-
-	priv = ps3vram_mtd.priv;
-
-	del_mtd_device(&ps3vram_mtd);
-	ps3vram_cache_cleanup(&ps3vram_mtd);
-	iounmap(priv->reports);
-	iounmap(priv->ctrl);
-	iounmap(priv->ddr_base);
-	lv1_gpu_context_free(priv->context_handle);
-	lv1_gpu_memory_free(priv->memory_handle);
-	ps3_close_hv_device(dev);
-	free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
-	kfree(priv);
-	return 0;
-}
-
-static struct ps3_system_bus_driver ps3vram_driver = {
-	.match_id	= PS3_MATCH_ID_GPU,
-	.match_sub_id	= PS3_MATCH_SUB_ID_GPU_RAMDISK,
-	.core.name	= DEVICE_NAME,
-	.core.owner	= THIS_MODULE,
-	.probe		= ps3vram_probe,
-	.remove		= ps3vram_shutdown,
-	.shutdown	= ps3vram_shutdown,
-};
-
-static int __init ps3vram_init(void)
-{
-	return ps3_system_bus_driver_register(&ps3vram_driver);
-}
-
-static void __exit ps3vram_exit(void)
-{
-	ps3_system_bus_driver_unregister(&ps3vram_driver);
-}
-
-module_init(ps3vram_init);
-module_exit(ps3vram_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jim Paris <jim@jtan.com>");
-MODULE_DESCRIPTION("MTD driver for PS3 video RAM");
-MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK);
-- 
1.6.0.4


With kind regards,

Geert Uytterhoeven
Software Architect

Sony Techsoft Centre Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium

Phone:    +32 (0)2 700 8453
Fax:      +32 (0)2 700 8622
E-mail:   Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/

A division of Sony Europe (Belgium) N.V.
VAT BE 0413.825.160 · RPR Brussels
Fortis · BIC GEBABEBB · IBAN BE41293037680010

^ permalink raw reply related

* Re: [PATCH/RFC] ps3/block: Add ps3vram-ng driver for accessing video     RAM as block device
From: Jens Axboe @ 2009-03-06 12:58 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Arnd Bergmann, Linux Kernel Development, Jim Paris,
	Linux/PPC Development, linux-mtd, Vivien Chappelier,
	David Woodhouse, Cell Broadband Engine OSS Development
In-Reply-To: <alpine.LRH.2.00.0903061347360.16809@vixen.sonytel.be>

On Fri, Mar 06 2009, Geert Uytterhoeven wrote:
> On Fri, 6 Mar 2009, Jens Axboe wrote:
> > On Thu, Mar 05 2009, Geert Uytterhoeven wrote:
> > > But then I noticed ps3vram_make_request() may be called concurrently,
> > > so I had to add a mutex to avoid data corruption. This slows the
> > > driver down, and in the end, the version with a thread turns out to be
> > > ca. 1% faster. The version without a thread is about 50 lines less
> > > code, though.
> >
> > That is correct, ->make_request_fn may get reentered. I'm not surprised
> > that performance dropped if you just shoved everything under a mutex.
> > You could be a little more smart and queue concurrent bio's for
> > processing when the current one is complete though, there are several
> > approaches there that be a lot faster than going all the way through the
> > IO stack and scheduler just to avoid concurrency.
> 
> Yes, using a spinlock and queueing requests on a list if the driver is
> busy can be done after 2.6.29...

Certainly. Even just replacing your current mutex with a spinlock during
the memcpy() would surely be a lot faster. Or even just grabbing the
mutex before calling into the write for the duration of the bio. The way
you do it is certain context switch death :-)


-- 
Jens Axboe

^ permalink raw reply

* Interrupt GPIOs with MPC5200b
From: Dave Best @ 2009-03-06 13:27 UTC (permalink / raw)
  To: linuxppc-dev


Hi, I am working on a MPC5200B-tiny with 2.6.23.1 Linux (pcm030).

I want to use an interrupt GPIO to act as the source for my ISR, but i can'=
t find the IRQ numbers for the GPIOs so i can't call request_irq() to set m=
y ISR up. =20

For other platforms there seems to be the function gpio_to_irq() where enum=
erated GPIOs get an IRQ number for their request_irq calls.

Any help or hints appreciated.

Dave=0A=0A=0A      

^ permalink raw reply

* Re: support IRQ from GPIO trough OF and GPIOLIB
From: Henk Stegeman @ 2009-03-06 13:51 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <ae4f76fd0903050320j75200141we4d7c264dd387d2d@mail.gmail.com>

I just saw that I missed an earlier very useful a suggestion from Grant Lik=
ely:

http://ozlabs.org/pipermail/linuxppc-dev/2009-February/068357.html

By defining the irq in the dts directly I don't need the gpio irq
support anymore.


On Thu, Mar 5, 2009 at 12:20 PM, Henk Stegeman <henk.stegeman@gmail.com> wr=
ote:
> I forgot to include my =A0changes in arch/powerpc/include/asm/gpio.h:
>
> diff --git a/arch/powerpc/include/asm/gpio.h b/arch/powerpc/include/asm/g=
pio.h
> index ea04632..38762ed 100644
> --- a/arch/powerpc/include/asm/gpio.h
> +++ b/arch/powerpc/include/asm/gpio.h
> @@ -38,12 +38,9 @@ static inline int gpio_cansleep(unsigned int gpio)
> =A0 =A0 =A0 =A0return __gpio_cansleep(gpio);
> =A0}
>
> -/*
> - * Not implemented, yet.
> - */
> =A0static inline int gpio_to_irq(unsigned int gpio)
> =A0{
> - =A0 =A0 =A0 return -ENOSYS;
> + =A0 =A0 =A0 return __gpio_to_irq(gpio);
> =A0}
>
> =A0static inline int irq_to_gpio(unsigned int irq)
>
>
> On Thu, Mar 5, 2009 at 12:15 PM, Henk Stegeman <henk.stegeman@gmail.com> =
wrote:
>> Hello,
>>
>> I have an SPI device that sends an IRQ to the CPU (MPC5200) via GPIO (GP=
T6):
>>
>> gpt6: timer@660 { =A0 =A0 =A0 // General Purpose Timer GPT6 in GPIO mode=
 for
>> SMC4000IO sample irq.
>> =A0 =A0 =A0 =A0compatible =3D "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-g=
pio";
>> =A0 =A0 =A0 =A0cell-index =3D <6>;
>> =A0 =A0 =A0 =A0reg =3D <0x660 0x10>;
>> =A0 =A0 =A0 =A0interrupts =3D <1 15 0>;
>> =A0 =A0 =A0 =A0interrupt-parent =3D <&mpc5200_pic>;
>> =A0 =A0 =A0 =A0gpio-controller;
>> =A0 =A0 =A0 =A0#gpio-cells =3D <2>;
>> };
>>
>> spi@f00 {
>> =A0 =A0 =A0 =A0#address-cells =3D <1>;
>> =A0 =A0 =A0 =A0#size-cells =3D <0>;
>> =A0 =A0 =A0 =A0compatible =3D "fsl,mpc5200b-spi","fsl,mpc5200-spi";
>> =A0 =A0 =A0 =A0reg =3D <0xf00 0x20>;
>> =A0 =A0 =A0 =A0interrupts =3D <2 13 0 2 14 0>;
>> =A0 =A0 =A0 =A0interrupt-parent =3D <&mpc5200_pic>;
>> =A0 =A0 =A0 =A0gpios =3D <&gpt4 0 0>;
>>
>> =A0 =A0 =A0 =A0io-controller@0 {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "microkey,smc4000io";
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0linux,modalias =3D "of_smc4000io";
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0spi-max-frequency =3D <1000000>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0spi-cpha;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <0>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// gpios: first is IRQ to cpu
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gpios =3D <&gpt6 0 0>;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0word-delay-us =3D <0>;
>> =A0 =A0 =A0 =A0};
>> };
>>
>> I've got it working for a mm_gpio, but it's probably not the right
>> approach, I have the following questions to get to the right solution:
>> - Should gpiolib's gpio_to_irq function indeed return the IRQ that was
>> specified at the GPIO by the DTS (interrupts =3D <1 15 0>)?
>> =A0The effect is that if the IRQ is not specified in the DTS the
>> gpio_to_irq returns NO_IRQ.
>> =A0(On the MPC5200 the IRQ is fixed for GPT6, so instead the cell-index
>> could also be used to return a gpio's IRQ)
>> - If a GPIO controller supports several GPIOs but one IRQ, is it
>> defined what gpio_to_irq should return?
>> - Is it okay for gpio_to_irq to return NO_IRQ? =A0(returned by
>> irq_of_parse_and_map) if irq is not defined?
>>
>>
>> Henk.
>>
>> diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
>> index 6eea601..81927d7 100644
>> --- a/drivers/of/gpio.c
>> +++ b/drivers/of/gpio.c
>> @@ -150,6 +150,17 @@ int of_gpio_simple_xlate(struct of_gpio_chip
>> *of_gc, struct device_node *np,
>> =A0}
>> =A0EXPORT_SYMBOL(of_gpio_simple_xlate);
>>
>> +static int of_mm_gpio_to_irq(struct gpio_chip *gc, unsigned int gpio)
>> +{
>> + =A0 =A0 =A0 struct of_mm_gpio_chip *mm_gc;
>> + =A0 =A0 =A0 struct of_gpio_chip *of_gc;
>> +
>> + =A0 =A0 =A0 of_gc =3D container_of(gc, struct of_gpio_chip, gc);
>> + =A0 =A0 =A0 mm_gc =3D container_of(of_gc, struct of_mm_gpio_chip, of_g=
c);
>> + =A0 =A0 =A0 return mm_gc->irq;
>> +
>> +}
>> +
>> =A0/**
>> =A0* of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
>> =A0* @np: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device node of the GPIO chip
>> @@ -188,6 +199,9 @@ int of_mm_gpiochip_add(struct device_node *np,
>>
>> =A0 =A0 =A0 =A0gc->base =3D -1;
>>
>> + =A0 =A0 =A0 mm_gc->irq =3D irq_of_parse_and_map(np, 0);
>> + =A0 =A0 =A0 gc->to_irq =3D of_mm_gpio_to_irq;
>> +
>> =A0 =A0 =A0 =A0if (!of_gc->xlate)
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0of_gc->xlate =3D of_gpio_simple_xlate;
>>
>> diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
>> index fc2472c..17fe9ed 100644
>> --- a/include/linux/of_gpio.h
>> +++ b/include/linux/of_gpio.h
>> @@ -54,6 +54,7 @@ struct of_mm_gpio_chip {
>> =A0 =A0 =A0 =A0struct of_gpio_chip of_gc;
>> =A0 =A0 =A0 =A0void (*save_regs)(struct of_mm_gpio_chip *mm_gc);
>> =A0 =A0 =A0 =A0void __iomem *regs;
>> + =A0 =A0 =A0 int irq;
>> =A0};
>>
>> =A0static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_=
chip *gc)
>>
>

^ permalink raw reply

* Re: [PATCH/RFC] ps3/block: Add ps3vram-ng driver for accessing video RAM as block device
From: Geert Uytterhoeven @ 2009-03-06 14:26 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Arnd Bergmann, Linux Kernel Development, Jim Paris,
	Linux/PPC Development, linux-mtd, Vivien Chappelier,
	David Woodhouse, Cell Broadband Engine OSS Development
In-Reply-To: <20090306125832.GX11787@kernel.dk>

On Fri, 6 Mar 2009, Jens Axboe wrote:
> On Fri, Mar 06 2009, Geert Uytterhoeven wrote:
> > On Fri, 6 Mar 2009, Jens Axboe wrote:
> > > On Thu, Mar 05 2009, Geert Uytterhoeven wrote:
> > > > But then I noticed ps3vram_make_request() may be called concurrently,
> > > > so I had to add a mutex to avoid data corruption. This slows the
> > > > driver down, and in the end, the version with a thread turns out to be
> > > > ca. 1% faster. The version without a thread is about 50 lines less
> > > > code, though.
> > >
> > > That is correct, ->make_request_fn may get reentered. I'm not surprised
> > > that performance dropped if you just shoved everything under a mutex.
> > > You could be a little more smart and queue concurrent bio's for
> > > processing when the current one is complete though, there are several
> > > approaches there that be a lot faster than going all the way through the
> > > IO stack and scheduler just to avoid concurrency.
> > 
> > Yes, using a spinlock and queueing requests on a list if the driver is
> > busy can be done after 2.6.29...
> 
> Certainly. Even just replacing your current mutex with a spinlock during
> the memcpy() would surely be a lot faster. Or even just grabbing the
> mutex before calling into the write for the duration of the bio. The way
> you do it is certain context switch death :-)

It's not just the memcpy(). ps3vram_{up,down}load() call msleep(), so I cannot
use a spinlock.

With kind regards,

Geert Uytterhoeven
Software Architect

Sony Techsoft Centre Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium

Phone:    +32 (0)2 700 8453
Fax:      +32 (0)2 700 8622
E-mail:   Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/

A division of Sony Europe (Belgium) N.V.
VAT BE 0413.825.160 · RPR Brussels
Fortis · BIC GEBABEBB · IBAN BE41293037680010

^ permalink raw reply

* Re: Davicom DM9000A on MPC5200B (powerpc) works using a dirty offsetting and byte trick
From: Grant Likely @ 2009-03-06 15:02 UTC (permalink / raw)
  To: Henk Stegeman; +Cc: netdev, linuxppc-dev
In-Reply-To: <ae4f76fd0902200151m461f9336x1e2bbec61f815fde@mail.gmail.com>

On Fri, Feb 20, 2009 at 2:51 AM, Henk Stegeman <henk.stegeman@gmail.com> wr=
ote:
> I have the following definition for this network device in my dts:
>
> =A0 =A0 =A0 =A0enet1:ethernet@fb000000 {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#size-cells =3D <1>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#address-cells =3D <1>;

The ethernet node doesn't have any children, so drop the #size-cells
and #address-cells properties.

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0device_type =3D "network";

Drop device_type too.  It only makes sense if you're running real OpenFirmw=
are.

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "davicom,dm9000";
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D <0xfb000000 0x00000002 =A0 =A0 =A0=
 =A0 =A0 =A0// DM9000 Address register
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00xfb000002 0x00000002>; =
=A0 =A0 =A0 =A0 // DM9000 Data register

Just make this reg =3D <0xfb000000 0x00000004>;.  Specify in the
documentation for the "davicom,dm9000" binding that the address
register is at offset 0 and the data register is at offset 2.

Actually, since this is the local plus bus, you should have this node
as a child of the localplus node.  Like this:

localbus {
    compatible =3D "fsl,mpc5200b-lpb", "fsl,mpc5200-lpb", "simple-bus";
    #address-cells =3D <2>;  // first cell is CS#, second is offset
    #size-cells =3D <1>;
    ranges =3D <1 0 0xfb000000 0x4>;  // CS#1, offset 0, mapped to
0xfb000000, size=3D4
    enet1: ethernet@fb000000 {
        compatible =3D "davicom,dm9000";
        reg =3D <0xfb000000 0x00000002            // DM9000 Address registe=
r
        mac-address =3D [ 00 00 00 00 00 00 ]; // Filled in by u-boot
        interrupts =3D <1 1 0>;                   // External interrupt 1
    };
};

Doing it this way provides drivers with the ability to get the chip
select number, which is important if you ever decide to use the
Localplus fifo to transfer to/from the device.

> To pass this information to the unmodified DM9000 driver I put
> together a wrapper arch/powerpc/sysdev/dm9000_dev.c (see below) for
> the of_ part (I reused most of the work from
> arch/powerpc/sysdev/tsi108_dev.c):
>
> Because the dm9000 driver uses the data address both as pointer to u16
> and pointer to u8, this works for a little-endian cpu to the
> little-endian dm9000, but not for the big endian MPC5200 to little
> endian dm9000.
> So I add an offset of 1 to this pointer when it is passed to the
> dm9000 driver. This offset of 1 is wrong for the u16 accesses of the
> DM9000 driver, besides that the data needs to be byteswapped for the
> dm9000 driver.

If the driver cannot handle big endian machines, then it is a driver
bug.  Don't be afraid to modify the driver to fix this and send a
patch.

> For these two reasons I wrote the functions dm9000_outblk_16bit
> dm9000_intblk_16bit dm9000_dumpblk_16bit which are passed via the
> platform_data.
>
> Apart from comments on my assumptions I have the following questions
> about this situation and my code:
> - Is it the right way to make a separate arch/powerpc/sysdev/*_dev.c
> for reading the device-tree and passing it to a driver, in stead of
> adding it to the driver itself?

Personally, I'd use the of_platform bus infrastructure to probe the
new device.  Register an of_platform_driver which will bind against
the device node for the ethernet device.  Then you have a choice:
option 1)  Your driver's probe method can either create a child
platform device which the original driver can bind against with the
correct pdata, or
option 2) your new driver can call into the original driver at a point
that bypasses the platform bus bindings (because they are handled by
the of_platform bus instead).

I typically choose option 2 because it requires less overhead and less
memory (one fewer probe call and one fewer struct device), but it will
probably require a little bit of refactoring the original driver to
provide call points to bypass the platform bus binding bit of the
driver.  I've done this many times, but it does depend on the driver
maintainer being okay with multiple bus bindings (platform and
of_platform) for a driver.  This is an ongoing debate.

See drivers/video/xilinxfb.c for an example of a driver with both
platform and of_platform bus bindings.  You'll notice at the end of
the file that both a platform driver and an of_platform driver are
getting registered.

> - I think the best solution to handle the separate address and data
> register is the 2 entry register array in the device tree as above,
> this accounts for an odd connection to the DM9000's CMD pin. Agree?

no.  If CMD could appear at a different offset, then define an
optional property (maybe cmd-reg-offset =3D <2>;) to handle the case
where CMD appears at a different offset.

> - The MPC5200's chip-select can be configured to do byte-swapping on
> read and write, however when I configured it as such and I removed my
> offsetting by 1 and byte-swapping code It didn't work.
> - Any suggestions to what could be wrong here? Or does the MPC5200 in
> this case only byte swap u16 reads, but a u8 read is unchanged?

This I don't know.  I'd have to play with it to figure it out.

> - What about how the DM9000 driver deals with this u8 read and u16
> read, is this correct?

Fix the driver.  It will result in a more useful driver for everyone
at the end of the day.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: Interrupt GPIOs with MPC5200b
From: Grant Likely @ 2009-03-06 15:18 UTC (permalink / raw)
  To: arieswar24b; +Cc: linuxppc-dev
In-Reply-To: <538696.45538.qm@web24106.mail.ird.yahoo.com>

On Fri, Mar 6, 2009 at 6:27 AM, Dave Best <arieswar24b@yahoo.de> wrote:
>
> Hi, I am working on a MPC5200B-tiny with 2.6.23.1 Linux (pcm030).
>
> I want to use an interrupt GPIO to act as the source for my ISR, but i can't find the IRQ numbers for the GPIOs so i can't call request_irq() to set my ISR up.
>
> For other platforms there seems to be the function gpio_to_irq() where enumerated GPIOs get an IRQ number for their request_irq calls.

Which GPIO line are you using?  Is it on the gpio_simple block?
gpio_wkup?  or one of the GPT lines?

There is support in Ben Herrenschmidt's -next tree to use the GPT as
an interrupt controller.  A similar patch for the mpc52xx_gpio driver
would be fairly easy to do.  That would allow you to simply specify
the GPIO controller as the interrupt controller in the device tree and
get your IRQ number with a single call to of_irq_parse_and_map().  It
also allows each GPIO line to be assigned an independent IRQ number
and be enabled/acked independently from the others and for the
enable/ack code to live with the mpc52xx-gpio driver where it belongs.

See here for the GPT patch.  You can use it as an example to do the
same for the gpio driver.

http://patchwork.ozlabs.org/patch/21914/

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Please pull mpc52xx-merge
From: Grant Likely @ 2009-03-06 15:37 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Josh Boyer, linuxppc-dev

Hi Ben,

One last one for 2.6.29.  Single line cefconfig change only.  This
fixes defconfigs for Xilinx Virtex platforms that use the full 16550
uart instead of uartlite.

The following changes since commit 778ef1e6cbb049c9bcbf405936ee6f2b6e451892:
  Linus Torvalds (1):
        Merge git://git.kernel.org/.../gregkh/staging-2.6

are available in the git repository at:

  git://git.secretlab.ca/git/linux-2.6-mpc52xx.git merge

Grant Likely (1):
      powerpc/4xx: Enable SERIAL_OF support by default for Virtex platforms

 arch/powerpc/configs/40x/virtex_defconfig  |    2 +-
 arch/powerpc/configs/44x/virtex5_defconfig |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: next branch status
From: Grant Likely @ 2009-03-06 15:45 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1236056134.20465.18.camel@pasglop>

On Mon, Mar 2, 2009 at 9:55 PM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> Note: Kumar and Grant, pls be a bit more careful with files outside of
> arch/powerpc ... like the 5200 fec driver change, even if it's really
> powerpc only stuff and quite clearly so, it's in drivers/net, it
> wouldn't have hurt to seek davem ack for it... No big deal, it's only 2
> or 3 files that I might need to give Linus an explanation about tho :-)

Okay, will do.

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH] Xilinx: SPI: driver not releasing memory
From: Grant Likely @ 2009-03-06 15:49 UTC (permalink / raw)
  To: David Brownell
  Cc: linuxppc-dev, akonovalov, John Linn, Linux Kernel Mailing List
In-Reply-To: <20090227235456.4DED2448057@mail135-wa4.bigfish.com>

David,

Are you okay with this patch and okay with it going in via Ben's
powerpc tree?  Ben wants to ensure that changes outside arch/powerpc/
are properly acked before going into his tree.

Thanks,
g.

On Sat, Feb 28, 2009 at 9:09 PM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> On Fri, Feb 27, 2009 at 4:54 PM, John Linn <john.linn@xilinx.com> wrote:
>> The driver was not releasing memory when it was removed or
>> when there was a failure during probe. This fixes it.
>>
>> Signed-off-by: John Linn <john.linn@xilinx.com>
>
> Looks good.
>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
>
> I'll pick this up into my -next branch and ask Ben to pull it in the
> next week or so.

> ---
> This is an incremental patch to the patch (updated driver
> for device tree) that is in the next branch.
> ---
> =A0drivers/spi/xilinx_spi.c | =A0 =A09 +++++++--
> =A01 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
> index fe7e5f3..494d3f7 100644
> --- a/drivers/spi/xilinx_spi.c
> +++ b/drivers/spi/xilinx_spi.c
> @@ -354,7 +354,7 @@ static int __init xilinx_spi_of_probe(struct of_devic=
e *ofdev,
> =A0 =A0 =A0 =A0if (xspi->regs =3D=3D NULL) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rc =3D -ENOMEM;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_warn(&ofdev->dev, "ioremap failure\n")=
;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto put_master;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto release_mem;
> =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0xspi->irq =3D r_irq->start;
>
> @@ -365,7 +365,7 @@ static int __init xilinx_spi_of_probe(struct of_devic=
e *ofdev,
> =A0 =A0 =A0 =A0prop =3D of_get_property(ofdev->node, "xlnx,num-ss-bits", =
&len);
> =A0 =A0 =A0 =A0if (!prop || len < sizeof(*prop)) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bit=
s' property\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto put_master;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto unmap_io;
> =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0master->num_chipselect =3D *prop;
>
> @@ -397,6 +397,8 @@ free_irq:
> =A0 =A0 =A0 =A0free_irq(xspi->irq, xspi);
> =A0unmap_io:
> =A0 =A0 =A0 =A0iounmap(xspi->regs);
> +release_mem:
> + =A0 =A0 =A0 release_mem_region(r_mem->start, resource_size(r_mem));
> =A0put_master:
> =A0 =A0 =A0 =A0spi_master_put(master);
> =A0 =A0 =A0 =A0return rc;
> @@ -406,6 +408,7 @@ static int __devexit xilinx_spi_remove(struct of_devi=
ce *ofdev)
> =A0{
> =A0 =A0 =A0 =A0struct xilinx_spi *xspi;
> =A0 =A0 =A0 =A0struct spi_master *master;
> + =A0 =A0 =A0 struct resource r_mem;
>
> =A0 =A0 =A0 =A0master =3D platform_get_drvdata(ofdev);
> =A0 =A0 =A0 =A0xspi =3D spi_master_get_devdata(master);
> @@ -413,6 +416,8 @@ static int __devexit xilinx_spi_remove(struct of_devi=
ce *ofdev)
> =A0 =A0 =A0 =A0spi_bitbang_stop(&xspi->bitbang);
> =A0 =A0 =A0 =A0free_irq(xspi->irq, xspi);
> =A0 =A0 =A0 =A0iounmap(xspi->regs);
> + =A0 =A0 =A0 if (!of_address_to_resource(ofdev->node, 0, &r_mem))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(r_mem.start, resource_si=
ze(&r_mem));
> =A0 =A0 =A0 =A0dev_set_drvdata(&ofdev->dev, 0);
> =A0 =A0 =A0 =A0spi_master_put(xspi->bitbang.master);
>
> --
> 1.5.3.4
>
>
>
> This email and any attachments are intended for the sole use of the named=
 recipient(s) and contain(s) confidential information that may be proprieta=
ry, privileged or copyrighted under applicable law. If you are not the inte=
nded recipient, do not read, copy, or forward this email message or any att=
achments. Delete this email message and any attachments immediately.
>
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* USB Host in 2.6.24-r3 Arch=PPC
From: A. Nolson @ 2009-03-06 15:51 UTC (permalink / raw)
  To: linuxppc-dev

Hi,

 just a little question. I am using 2.6.24-rc3 (secretlab) and I would
like to use c67x00 driver from Peter Kosgaard for USB-Host in my Xilinx
ML403 board. Is there support to use USB Host in Arch=ppc  Apparently I
cannot select  CONFIG_USB_ARCH_HAS_HCD=y option. What should I do to get
the USB working? Is there any backport for hcd support in arch=ppc?
Should I upgrade to powerpc (  painful ) ?

Thx,

/Albert

^ permalink raw reply

* Re: [PATCH] Fix Xilinx SystemACE driver to handle empty CF slot
From: Grant Likely @ 2009-03-06 16:05 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linuxppc-dev, sr, linux-kernel, John.Linn
In-Reply-To: <20090228204622.29719.55082.stgit@localhost.localdomain>

Oops, sorry Jens.  I forgot to CC: you on this patch.

g.

On Sat, Feb 28, 2009 at 1:46 PM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> From: Grant Likely <grant.likely@secretlab.ca>
>
> The SystemACE driver does not handle an empty CF slot gracefully. =A0An
> empty CF slot ends up hanging the system. =A0This patch adds a check for
> the CF state and stops trying to process requests if the slot is empty.
>
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>
> =A0drivers/block/xsysace.c | =A0 22 ++++++++++++++++++++++
> =A01 files changed, 22 insertions(+), 0 deletions(-)
>
>
> diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
> index 381d686..ec5b8ca 100644
> --- a/drivers/block/xsysace.c
> +++ b/drivers/block/xsysace.c
> @@ -489,6 +489,28 @@ static void ace_fsm_dostate(struct ace_device *ace)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ace->fsm_state, ace->id_req_count);
> =A0#endif
>
> + =A0 =A0 =A0 /* Verify that there is actually a CF in the slot. =A0If no=
t, then
> + =A0 =A0 =A0 =A0* bail out back to the idle state and wake up all the wa=
iters */
> + =A0 =A0 =A0 status =3D ace_in32(ace, ACE_STATUS);
> + =A0 =A0 =A0 if ((status & ACE_STATUS_CFDETECT) =3D=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ace->fsm_state =3D ACE_FSM_STATE_IDLE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ace->media_change =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 set_capacity(ace->gd, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(ace->dev, "No CF in slot\n");
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Drop all pending requests */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((req =3D elv_next_request(ace->queue=
)) !=3D NULL)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 end_request(req, 0);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Drop back to IDLE state and notify waite=
rs */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ace->fsm_state =3D ACE_FSM_STATE_IDLE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ace->id_result =3D -EIO;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (ace->id_req_count) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 complete(&ace->id_completio=
n);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ace->id_req_count--;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> =A0 =A0 =A0 =A0switch (ace->fsm_state) {
> =A0 =A0 =A0 =A0case ACE_FSM_STATE_IDLE:
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* See if there is anything to do */
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* [RFC] drivers/base: Add bus_register_notifier_alldev() variant
From: Grant Likely @ 2009-03-06 16:10 UTC (permalink / raw)
  Cc: linuxppc-dev, Greg Kroah-Hartman, linux-kernel

From: Grant Likely <grant.likely@secretlab.ca>

bus_register_notifier_alldev() is a variation on bus_register_notifier()
which also triggers the notifier callback for devices already on the bus
and already bound to drivers.

This function is useful for the case where a driver needs to get a
reference to a struct device other than the one it is bound to and
it is not known if the device will be bound before or after this
function is called.  For example, an Ethernet device connected to
a PHY that is probed separately.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
CC: linux-kernel@vger.kernel.org
CC: linuxppc-dev@ozlabs.org
CC: Greg Kroah-Hartman <gregkh@suse.de>
---

I'm using this as part of some changes to phylib to make it easier for
Ethernet drivers to find their PHY device.  Before I'm completely committed
to this approach I'd like some feedback on this change to drivers core.

Thanks,
g.


 drivers/base/bus.c     |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/device.h |    2 ++
 2 files changed, 49 insertions(+), 0 deletions(-)


diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 83f32b8..6edde85 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -962,6 +962,53 @@ int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(bus_register_notifier);
 
+/**
+ * bus_register_notifier_alldev_helper - internal support function
+ * Used by bus_register_notifier_alldev() to create ADD and BOUND events
+ * for devices.
+ */
+static int bus_register_notifier_alldev_helper(struct device *dev, void *data)
+{
+	struct notifier_block *nb = data;
+	nb->notifier_call(nb, BUS_NOTIFY_ADD_DEVICE, dev);
+	if (dev->driver)
+		nb->notifier_call(nb, BUS_NOTIFY_BOUND_DRIVER, dev);
+	return 0;
+}
+
+/**
+ * bus_register_notifier_alldev - Register for bus events; include existing devs
+ * @bus: pointer to bus_type
+ * @nb: pointer to notifier block to register with the bus
+ *
+ * Similar to bus_register_notifier() except it also generates events for
+ * devices already on the bus when the notifier is registered.  When this
+ * function is called the notifier is called once for each device with
+ * the BUS_NOTIFY_ADD_DEVICE event, and once for each device registered to
+ * a driver * with the BUS_NOTIFY_BOUND_DRIVER event.
+ *
+ * There is a small chance that the notifier could be called more than once
+ * for a device.  This would happen if a new device was registered on the bus
+ * or bound to a driver between the call to bus_register_notifier() and the
+ * call to bus_for_each_dev().  The only way I can see to protect against
+ * this would be to take the klist_devices spinlock while calling the
+ * notifier; but that would be a Very Bad Thing (tm).  Caller needs to be
+ * aware that a notifier called before this function returns might get
+ * called a second time on the same device.
+ */
+int bus_register_notifier_alldev(struct bus_type *b, struct notifier_block *nb)
+{
+	int ret;
+
+	ret = bus_register_notifier(b, nb);
+	if (ret == 0) {
+		bus_for_each_dev(b, NULL, nb,
+				 bus_register_notifier_alldev_helper);
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bus_register_notifier_alldev);
+
 int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
 	return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb);
diff --git a/include/linux/device.h b/include/linux/device.h
index 45e5b19..05c7d5b 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -103,6 +103,8 @@ struct notifier_block;
 
 extern int bus_register_notifier(struct bus_type *bus,
 				 struct notifier_block *nb);
+extern int bus_register_notifier_alldev(struct bus_type *b,
+					struct notifier_block *nb);
 extern int bus_unregister_notifier(struct bus_type *bus,
 				   struct notifier_block *nb);
 

^ permalink raw reply related

* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
From: Ben Menchaca @ 2009-03-06 16:12 UTC (permalink / raw)
  To: Liu Dave-R63238; +Cc: linuxppc-dev
In-Reply-To: <D7CCA83BB0796C49BC0BB53B6AB1208916CF98@zch01exm21.fsl.freescale.net>

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

Testing now...it looks like it (almost) works, though!  Why does setting
no-snoop cause snooping to work?  More on the effect on setting that bit in
a few minutes...need more testing.

ACR is 0x00030300.

- Ben

On Fri, Mar 6, 2009 at 12:30 AM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:

>  Did you enable the descriptor bit 3 to have a try?
>
>  ------------------------------
> *From:* Ben Menchaca [mailto:ben.menchaca@gmail.com]
> *Sent:* Friday, March 06, 2009 2:10 PM
>
> *To:* Liu Dave-R63238
> *Cc:* linuxppc-dev@ozlabs.org
> *Subject:* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
>
> I can look at ACR morning...although I can say with a fair amount of
> certainty that I have not changed it from the POR value.
>
> I will try enabling No Snoop for CSB in the descriptor (bit 3, yes?)...this
> seems a bit counterintuitive to me.
>
> What is the hope regarding these two?  Some combination I am not seeing?
>
>
> On Thu, Mar 5, 2009 at 11:40 PM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:
>
>>  what is the value of ACR register?
>>
>>  ------------------------------
>> *From:* Ben Menchaca [mailto:ben.menchaca@gmail.com]
>> *Sent:* Friday, March 06, 2009 1:38 PM
>> *To:* Liu Dave-R63238
>> *Cc:* linuxppc-dev@ozlabs.org
>> *Subject:* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
>>
>>   1.  BAT2 in linux is set to WIMG=0010, and covers all 64M
>> 2.  PEX_DEVICE_CONTROL in PCI-E Config Space (0x54): 0x1020
>> 3.  PEX_xDMA_CTRL is set to 0x00000401 at the initiation of the DMA.
>> 4.  OWAR0 is set to 0xFFFFF005, so NSNP is 0.
>> 5.  The DMA descriptor (randomly chosen when I hit a trigger...just ignore
>> the size...) contains 0002AFF3 at offset 0, so nosnoops are cleared.
>>
>> Core is 400MHz, and CSB is 133MHz.
>>
>> - Ben
>>
>> On Thu, Mar 5, 2009 at 11:27 PM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:
>>
>>> and what settings  is DMA description bit 3?
>>>
>>> > -----Original Message-----
>>> > From: linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
>>> > [mailto:linuxppc-dev-bounces+daveliu <linuxppc-dev-bounces%2Bdaveliu>=
>>> freescale.com@ozlabs.org]
>>>  >  On Behalf Of Liu Dave-R63238
>>> > Sent: Friday, March 06, 2009 1:22 PM
>>> > To: Ben Menchaca; linuxppc-dev@ozlabs.org
>>> > Subject: RE: 83xx: Marking or Allocating Pages as Cache-Inhibited
>>> >
>>> > Did you enable the snoop bit at PEX_WDMA_CTRL[SNOOP] and
>>> > PEX_RDMA_CTRL[SNOOP]?
>>> >
>>> > What is the freq settings? CORE/CSB bus.
>>> >
>>> > Thanks, Dave
>>> >
>>> > ________________________________
>>> >
>>> >       From: linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
>>> > [mailto:linuxppc-dev-bounces+daveliu <linuxppc-dev-bounces%2Bdaveliu>=
>>> freescale.com@ozlabs.org]
>>> >  On Behalf Of Ben Menchaca
>>> >       Sent: Friday, March 06, 2009 12:33 PM
>>> >       To: linuxppc-dev@ozlabs.org
>>> >       Subject: 83xx: Marking or Allocating Pages as Cache-Inhibited
>>> >
>>> >
>>> >       I am working on a Freescale 8314e design, and the
>>> > embedded device is configured as a PCI-e endpoint running a
>>> > 2.6.27-5 kernel.  For context, we have written a kernel
>>> > module which, among other things, uses the RDMA/WDMA engine
>>> > in the PCI-e IP block.  On the host side, these DMAs are
>>> > coherent.  However, on the embedded side, things are quite a
>>> > bit less rosy; we must manually flush/invalidate cache lines
>>> > for WDMA/RDMAs to occur successfully.  After speaking with
>>> > (several) FAEs at Freescale, we believe there is a
>>> > configuration issue that is the cause, but we have yet to
>>> > have anyone successfully point to it.
>>> >
>>> >       Disabling the data cache altogether resolves the issue
>>> > entirely, but of course, also completely tanks performance.
>>> > As a temporary workaround, I would like to simply mark the
>>> > pages (obtained currently via dma_alloc_coherent) involved as
>>> > cache-inhibited.  I have attempted to do this via some
>>> > snippets remaining in fec.c (va_to_pte, uncache_pte to set
>>> > _PAGE_NO_CACHE, flush_tlb_page, then unmap_pte), but this is
>>> > almost certainly braindead; va_to_pte is not a part of the
>>> > 83xx source, as far as I can tell; 8xx only.
>>> >
>>> >       A quick pointer in the correct direction for marking
>>> > pages as cache-inhibited on a 2.6.27-5 kernel would be
>>> > appreciated, or if my approach to a workaround is flawed, a
>>> > pointer to the correct way would be great.
>>> >
>>> >       Ben Menchaca
>>> >
>>> >
>>> > _______________________________________________
>>> > Linuxppc-dev mailing list
>>> > Linuxppc-dev@ozlabs.org
>>> > https://ozlabs.org/mailman/listinfo/linuxppc-dev
>>> >
>>> >
>>>
>>
>>
>

[-- Attachment #2: Type: text/html, Size: 8684 bytes --]

^ permalink raw reply

* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
From: Ben Menchaca @ 2009-03-06 16:30 UTC (permalink / raw)
  To: Liu Dave-R63238; +Cc: linuxppc-dev
In-Reply-To: <64ac01180903060812n1f355207lb3fa6de3ed17ae41@mail.gmail.com>

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

Thank you for your help!  That bit resolved all of the RDMA/WDMA coherency
issues on the CSB side...except:

We expose a 1MB region of memory from CSB via a BAR (BAR1, if it matters) to
the Host.  This region is also not behaving correctly with respect to
coherency on SOME hosts; again, disabling our cache makes it work correctly
on all hosts.  We have set PEX_DEVICE_CONTROL in PCI-E Config Space (0x54)
to 0x2010 (sorry about the endianness below).  We thought that CLEARING the
no-snoop bit here would indicate that snooping was required for this
region...is this a similar issue?

- Ben

On Fri, Mar 6, 2009 at 10:12 AM, Ben Menchaca <ben.menchaca@gmail.com>wrote:

> Testing now...it looks like it (almost) works, though!  Why does setting
> no-snoop cause snooping to work?  More on the effect on setting that bit in
> a few minutes...need more testing.
>
> ACR is 0x00030300.
>
> - Ben
>
>
> On Fri, Mar 6, 2009 at 12:30 AM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:
>
>>  Did you enable the descriptor bit 3 to have a try?
>>
>>  ------------------------------
>> *From:* Ben Menchaca [mailto:ben.menchaca@gmail.com]
>> *Sent:* Friday, March 06, 2009 2:10 PM
>>
>> *To:* Liu Dave-R63238
>> *Cc:* linuxppc-dev@ozlabs.org
>> *Subject:* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
>>
>> I can look at ACR morning...although I can say with a fair amount of
>> certainty that I have not changed it from the POR value.
>>
>> I will try enabling No Snoop for CSB in the descriptor (bit 3,
>> yes?)...this seems a bit counterintuitive to me.
>>
>> What is the hope regarding these two?  Some combination I am not seeing?
>>
>>
>> On Thu, Mar 5, 2009 at 11:40 PM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:
>>
>>>  what is the value of ACR register?
>>>
>>>  ------------------------------
>>> *From:* Ben Menchaca [mailto:ben.menchaca@gmail.com]
>>> *Sent:* Friday, March 06, 2009 1:38 PM
>>> *To:* Liu Dave-R63238
>>> *Cc:* linuxppc-dev@ozlabs.org
>>> *Subject:* Re: 83xx: Marking or Allocating Pages as Cache-Inhibited
>>>
>>>   1.  BAT2 in linux is set to WIMG=0010, and covers all 64M
>>> 2.  PEX_DEVICE_CONTROL in PCI-E Config Space (0x54): 0x1020
>>> 3.  PEX_xDMA_CTRL is set to 0x00000401 at the initiation of the DMA.
>>> 4.  OWAR0 is set to 0xFFFFF005, so NSNP is 0.
>>> 5.  The DMA descriptor (randomly chosen when I hit a trigger...just
>>> ignore the size...) contains 0002AFF3 at offset 0, so nosnoops are cleared.
>>>
>>>
>>> Core is 400MHz, and CSB is 133MHz.
>>>
>>> - Ben
>>>
>>> On Thu, Mar 5, 2009 at 11:27 PM, Liu Dave-R63238 <DaveLiu@freescale.com>wrote:
>>>
>>>> and what settings  is DMA description bit 3?
>>>>
>>>> > -----Original Message-----
>>>> > From: linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
>>>> > [mailto:linuxppc-dev-bounces+daveliu <linuxppc-dev-bounces%2Bdaveliu>
>>>> =freescale.com@ozlabs.org]
>>>>   >  On Behalf Of Liu Dave-R63238
>>>> > Sent: Friday, March 06, 2009 1:22 PM
>>>> > To: Ben Menchaca; linuxppc-dev@ozlabs.org
>>>> > Subject: RE: 83xx: Marking or Allocating Pages as Cache-Inhibited
>>>> >
>>>> > Did you enable the snoop bit at PEX_WDMA_CTRL[SNOOP] and
>>>> > PEX_RDMA_CTRL[SNOOP]?
>>>> >
>>>> > What is the freq settings? CORE/CSB bus.
>>>> >
>>>> > Thanks, Dave
>>>> >
>>>> > ________________________________
>>>> >
>>>> >       From: linuxppc-dev-bounces+daveliu=freescale.com@ozlabs.org
>>>> > [mailto:linuxppc-dev-bounces+daveliu <linuxppc-dev-bounces%2Bdaveliu>
>>>> =freescale.com@ozlabs.org]
>>>> >  On Behalf Of Ben Menchaca
>>>> >       Sent: Friday, March 06, 2009 12:33 PM
>>>> >       To: linuxppc-dev@ozlabs.org
>>>> >       Subject: 83xx: Marking or Allocating Pages as Cache-Inhibited
>>>> >
>>>> >
>>>> >       I am working on a Freescale 8314e design, and the
>>>> > embedded device is configured as a PCI-e endpoint running a
>>>> > 2.6.27-5 kernel.  For context, we have written a kernel
>>>> > module which, among other things, uses the RDMA/WDMA engine
>>>> > in the PCI-e IP block.  On the host side, these DMAs are
>>>> > coherent.  However, on the embedded side, things are quite a
>>>> > bit less rosy; we must manually flush/invalidate cache lines
>>>> > for WDMA/RDMAs to occur successfully.  After speaking with
>>>> > (several) FAEs at Freescale, we believe there is a
>>>> > configuration issue that is the cause, but we have yet to
>>>> > have anyone successfully point to it.
>>>> >
>>>> >       Disabling the data cache altogether resolves the issue
>>>> > entirely, but of course, also completely tanks performance.
>>>> > As a temporary workaround, I would like to simply mark the
>>>> > pages (obtained currently via dma_alloc_coherent) involved as
>>>> > cache-inhibited.  I have attempted to do this via some
>>>> > snippets remaining in fec.c (va_to_pte, uncache_pte to set
>>>> > _PAGE_NO_CACHE, flush_tlb_page, then unmap_pte), but this is
>>>> > almost certainly braindead; va_to_pte is not a part of the
>>>> > 83xx source, as far as I can tell; 8xx only.
>>>> >
>>>> >       A quick pointer in the correct direction for marking
>>>> > pages as cache-inhibited on a 2.6.27-5 kernel would be
>>>> > appreciated, or if my approach to a workaround is flawed, a
>>>> > pointer to the correct way would be great.
>>>> >
>>>> >       Ben Menchaca
>>>> >
>>>> >
>>>> > _______________________________________________
>>>> > Linuxppc-dev mailing list
>>>> > Linuxppc-dev@ozlabs.org
>>>> > https://ozlabs.org/mailman/listinfo/linuxppc-dev
>>>> >
>>>> >
>>>>
>>>
>>>
>>
>

[-- Attachment #2: Type: text/html, Size: 10299 bytes --]

^ permalink raw reply

* [PATCH, RFC]
From: Eddie Dawydiuk @ 2009-03-06 17:41 UTC (permalink / raw)
  To: linuxppc-dev

Hello,

The patch below resolves the following issues. The build system for the 
AMCC Yosemite eval board is not including the proper fixups(e.g. RAM 
initialization, timer initialization). In addition the wrapper script 
was not using the fixed-head.S source(e.g. add branch instruction so one 
can jump into the image at offset 0).

Any feedback appreciated..

diff -urN linux-2.6.28.orig/arch/powerpc/boot/Makefile 
linux-2.6.28/arch/powerpc/boot/Makefile
--- linux-2.6.28.orig/arch/powerpc/boot/Makefile        2008-12-24 
16:26:37.000000000 -0700
+++ linux-2.6.28/arch/powerpc/boot/Makefile     2009-03-05 
17:35:53.000000000 -0700
@@ -70,7 +70,7 @@
                 cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
                 cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c 
simpleboot.c \
                 virtex405-head.S virtex.c redboot-83xx.c 
cuboot-sam440ep.c \
-               cuboot-acadia.c
+               cuboot-acadia.c simpleboot-yosemite.c
  src-boot := $(src-wlib) $(src-plat) empty.c

  src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -224,7 +224,7 @@
  image-$(CONFIG_TAISHAN)                        += cuImage.taishan
  image-$(CONFIG_KATMAI)                 += cuImage.katmai
  image-$(CONFIG_WARP)                   += cuImage.warp
-image-$(CONFIG_YOSEMITE)               += cuImage.yosemite
+image-$(CONFIG_YOSEMITE)               += cuImage.yosemite 
simpleImage.yosemite

  # Board ports in arch/powerpc/platform/8xx/Kconfig
  image-$(CONFIG_MPC86XADS)              += cuImage.mpc866ads

diff -urN linux-2.6.28.orig/arch/powerpc/boot/wrapper 
linux-2.6.28/arch/powerpc/boot/wrapper
--- linux-2.6.28.orig/arch/powerpc/boot/wrapper 2008-12-24 
16:26:37.000000000 -0700
+++ linux-2.6.28/arch/powerpc/boot/wrapper      2009-03-05 
17:36:10.000000000 -0700
@@ -214,8 +214,12 @@
      platformo="$object/simpleboot.o $object/virtex.o"
      binary=y
      ;;
+simpleboot-yosemite)
+    platformo="$object/fixed-head.o $object/simpleboot.o 
$object/simpleboot-yosemite.o"
+    binary=y
+    ;;
  simpleboot-*)
-    platformo="$object/simpleboot.o"
+    platformo="$object/fixed-head.o $object/simpleboot.o"
      binary=y
      ;;
  asp834x-redboot)

diff -urN linux-2.6.28.orig/arch/powerpc/boot/simpleboot-yosemite.c 
linux-2.6.28/arch/powerpc/boot/simpleboot-yosemite.c
--- linux-2.6.28.orig/arch/powerpc/boot/simpleboot-yosemite.c 
1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.28/arch/powerpc/boot/simpleboot-yosemite.c 
2009-03-06 10:48:19.000000000 -0700
@@ -0,0 +1,27 @@
+#include "ops.h"
+#include "stdio.h"
+#include "4xx.h"
+#include "44x.h"
+
+#define TARGET_4xx
+#define TARGET_44x
+#include "ppcboot.h"
+
+static unsigned char eth0adr[] = { 0x0, 0xd0, 0x69, 0x41, 0x12, 0x34 };
+static unsigned char eth1adr[] = { 0x0, 0xd0, 0x69, 0x41, 0x12, 0x56 };
+
+static void yosemite_fixups(void)
+{
+       unsigned long sysclk = 50000000;
+
+       ibm440ep_fixup_clocks(sysclk, 11059200, 400000000);
+       ibm4xx_sdram_fixup_memsize();
+       dt_fixup_mac_address_by_alias("ethernet0", eth0adr);
+       dt_fixup_mac_address_by_alias("ethernet1", eth1adr);
+}
+
+void platform_specific_init(void)
+{
+       platform_ops.fixups = yosemite_fixups;
+       platform_ops.exit = ibm44x_dbcr_reset;
+}

-- 
Best Regards,
________________________________________________________________
  Eddie Dawydiuk, Technologic Systems | voice:  (480) 837-5200
  16525 East Laser Drive 	     | fax:    (480) 837-5300
  Fountain Hills, AZ 85268            | web: www.embeddedARM.com

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox