LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [RFC/PATCH 4/7] Powerpc MSI implementation
From: Benjamin Herrenschmidt @ 2006-11-08  2:08 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Matthew Wilcox, Greg Kroah-Hartman, Ingo Molnar, Russell King,
	linuxppc-dev, Thomas Gleixner, linux-pci, David S.Miller
In-Reply-To: <m1ac327mer.fsf@ebiederm.dsl.xmission.com>

On Tue, 2006-11-07 at 18:33 -0700, Eric W. Biederman wrote:
> Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> 
> >> For message signalled interrupts and hyptertransport interrupts we probably
> > want
> >> to add an additional field for pointing to their per irq state.  Per device
> >> interrupt controllers are truly peculiar.
> >
> > A per-irq addition field for the MSI data might indeed be useful. I
> > still want to store it in the pci_dev, but it would be good to have a
> > pointer to it in the irq_desc.
> 
> The msi_info in pci_dev is reasonable.  But storing all 4096 possible
> msi_desc's in pci_dev seems a little much.

My initial idea was that the msi_info structure would have a variable
lenght, that is, would end with msi_desc[0] and would be allocated to
the the right size, but it might suck a bit :-)

> Hopefully I can look at this a little more this evening and see what we
> need to do to harmonize the two msi implementations.

Thanks !

Ben.

^ permalink raw reply

* IDMA IN MPC82XX (i.e mpc8272)
From: Jonathan Qiang @ 2006-11-08  2:04 UTC (permalink / raw)
  To: linuxppc-embedded

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

Any one who has any experience when using IDMA on mpc82xx? 
Currently, the status what I have got is, memory-to-memory mode, both
Data bus had been set to 60x-bus, which means DDTB and SDTB are working
on 60x-bus. if set DMA_WRAP in DCM as 64-byte, SS_MAX,STS and DTS in
(IDMA Parameter RAM) all to 32 Bytes, there working good!
But if set DMA_WRAP more than 64-byte(i.e 256-bytes) ,SS_MAX,STS and DTS
in (IDMA Parameter RAM) all to 7*32 Bytes when WRAP = 256 . then got
some issues:
1. some bytes in a packet had been changed oddly. for example if  some
bytes in the packet is "20 0f 17 2c...." after 
IDMA transmission , the bytes will be changed as "20 1d 17 2c", there is
a slightly different with "17" and "1d".
2. some bytes had been swapped , for example "20 0f 17 2c" , after
transmission , the bytes in packet was "2c 17 0f 20".
Any ideas? 
Is this the cache issue? I had enabled the snooping
 

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

^ permalink raw reply

* Re: [RFC/PATCH 4/7] Powerpc MSI implementation
From: Eric W. Biederman @ 2006-11-08  2:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Matthew Wilcox, Greg Kroah-Hartman, Ingo Molnar, Russell King,
	linuxppc-dev, Thomas Gleixner, linux-pci, David S.Miller
In-Reply-To: <1162951680.28571.627.camel@localhost.localdomain>

Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:

> My initial idea was that the msi_info structure would have a variable
> lenght, that is, would end with msi_desc[0] and would be allocated to
> the the right size, but it might suck a bit :-)

That could work.  The whole array of interrupts thing allocated on
device probe, I question a little bit.  I can just about see allocating
another interrupt if you can when a network device start getting another
flow through it.  But it is working well enough at the moment it doesn't
appear time to run out and change the drivers.

>> Hopefully I can look at this a little more this evening and see what we
>> need to do to harmonize the two msi implementations.
>
> Thanks !

I'm still having a hard time wrapping my head around the sanity of not letting
the kernel touch the hardware in the presence of a hypervisor.  How do you cope
with hardware that follows a specification the hypervisor is not aware of?

This seems to be a violation of the principle that the driver knows the hardware
better than some generic layer.

Eric

^ permalink raw reply

* Re: 2.6.18 fails in call_usermodedata() on 8xx
From: Robin Gilks @ 2006-11-08  2:45 UTC (permalink / raw)
  To: ppc embedded list
In-Reply-To: <45512174.7020205@tait.co.nz>

Robin Gilks wrote:
> Greetings
> 
> Having (sort of) mastered the bdi2000, I'm trying to bring up a 8xx card
> thats been debugged and working with a 2.4 kernel for the last 3 years
> but is failing miserably on a 2.6.18 kernel.
> 
> My initial problems in dma_alloc_init I seem to have fixed by moving
> CONFIG_CONSISTENT_START to 0xa0000000 from the default of 0xff100000 but
> now I'm failing in call_usermodedata(). Any attempt to check the values 
> of structures (eg. current->fs->root) results in an error of the form:
> 
> (gdb) print *current
> Cannot access memory at address 0xc01e27a8
> 
> so I'm a bit stuck with further debugging.
> 
> Is there anything I should be looking out for in particular with an 8xx
> CPU and a late 2.6 kernel? My understanding was that it now worked but
> the config documentation is a bit thin on the ground :-(
> 
> Cheers

Never mind - was the watchdog going off - now disabled in the bootloader 
so I'm getting much further than i thought...

Just the console & rootfs to get going now :-)

-- 
Robin



=======================================================================
This email, including any attachments, is only for the intended
addressee.  It is subject to copyright, is confidential and may be
the subject of legal or other privilege, none of which is waived or
lost by reason of this transmission.
If the receiver is not the intended addressee, please accept our
apologies, notify us by return, delete all copies and perform no
other act on the email.
Unfortunately, we cannot warrant that the email has not been
 altered or corrupted during transmission.
=======================================================================

^ permalink raw reply

* Re: [RFC/PATCH 4/7] Powerpc MSI implementation
From: Benjamin Herrenschmidt @ 2006-11-08  3:02 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Matthew Wilcox, Greg Kroah-Hartman, Ingo Molnar, Russell King,
	linuxppc-dev, Thomas Gleixner, linux-pci, David S.Miller
In-Reply-To: <m1wt6664l8.fsf@ebiederm.dsl.xmission.com>


> I'm still having a hard time wrapping my head around the sanity of not letting
> the kernel touch the hardware in the presence of a hypervisor.  How do you cope
> with hardware that follows a specification the hypervisor is not aware of?

We don't cope :-)

> This seems to be a violation of the principle that the driver knows the hardware
> better than some generic layer.

Well, we got at least the HV folks to change their interfaces so we
could explicitely tell them wether we want MSI or MSI-X ... in the
initial definition of that stuff, we couldn't (the HV did what it
wanted) and we didn't even know what it did (we still don't, but at
least we can now request specifically MSI or MSI-X).

Ben.

^ permalink raw reply

* Re: [PATCH 1/1]  PPC32 : Huge-page support for ppc440
From: Edi Shmueli @ 2006-11-08  3:08 UTC (permalink / raw)
  To: Roland Dreier; +Cc: linuxppc-embedded, linuxppc-dev
In-Reply-To: <ada7iy7hysu.fsf@cisco.com>

Roland Dreier wrote:
> Is this 44x work at the point where having more people would help?  I
> have a 440SPe eval board that I'd like to get going with
> arch/powerpc.  I could work on PCI Express or something like that...
>
> On the other hand, I'm happy to wait and work on other stuff...
>
>  - R.
>   
Count me in for the 44x work. Will  be happy to contribute my 440GP 
board for this purpose :)

^ permalink raw reply

* Freescale combined ethernet driver
From: Robin Gilks @ 2006-11-08  4:12 UTC (permalink / raw)
  To: ppc embedded list

OK - I give up - whats the name of the device?

I've tried eth0, fsl-cpm-fec0 (and other combinations) with a 
commandline of the form:

   ip=172.25.206.113:172.25.140.15::255.255.0.0:unset:fsl-cpm-fec0:off \ 
panic=1 console=ttyCPM0

and I get the following errors:
[   37.249708] TCP bic registered
[   37.255389] Initializing IPsec netlink socket
[   37.264134] NET: Registered protocol family 1
[   37.272673] NET: Registered protocol family 17
[   37.281436] NET: Registered protocol family 15
[   37.796233] IP-Config: Device `fsl-cpm-fec0' not found.
[   37.807814] Looking up port of RPC 100003/2 on 172.25.140.15
[   37.819328] portmap: RPC call returned error 101

This is on an 859T CPU so its a CPM1 and I'm using the single SCC 
channel as a serial UART.

-- 
Robin

=======================================================================
This email, including any attachments, is only for the intended
addressee.  It is subject to copyright, is confidential and may be
the subject of legal or other privilege, none of which is waived or
lost by reason of this transmission.
If the receiver is not the intended addressee, please accept our
apologies, notify us by return, delete all copies and perform no
other act on the email.
Unfortunately, we cannot warrant that the email has not been
 altered or corrupted during transmission.
=======================================================================

^ permalink raw reply

* Re: [PATCH] powerpc: force 4k update_flash block and list sizes
From: John Rose @ 2006-11-08  4:30 UTC (permalink / raw)
  To: Michael Neuling; +Cc: External List, Paul Mackerras
In-Reply-To: <20286.1162951582@neuling.org>

> kmem_cache_destroy doesn't return anything.

Good call!  How's this:

The enablement of 64k pages on POWER platforms exposed a quirk in the RTAS
mechanism for updating firmware.  RTAS assumes 4k for flash block and list
sizes, and use of any other sizes results in a failure.

This patch changes the rtas_flash module to force the use of 4k memory block
and list sizes when preparing and sending a firmware image to RTAS.  It also
changes rtas_flash to use a slab cache to ensure 4k alignment of flash block
data.  Such alignment is a documented requirement.

Signed-off-by: John Rose <johnrose@austin.ibm.com>

---

---

 uf_4k-johnrose/arch/powerpc/kernel/rtas_flash.c |   52 +++++++++++++++++++-----
 1 files changed, 42 insertions(+), 10 deletions(-)

diff -puN arch/powerpc/kernel/rtas_flash.c~uf_4k_alt2 arch/powerpc/kernel/rtas_flash.c
--- uf_4k/arch/powerpc/kernel/rtas_flash.c~uf_4k_alt2	2006-11-06 16:59:27.000000000 -0600
+++ uf_4k-johnrose/arch/powerpc/kernel/rtas_flash.c	2006-11-06 17:02:31.000000000 -0600
@@ -72,6 +72,10 @@
 #define VALIDATE_BUF_SIZE 4096    
 #define RTAS_MSG_MAXLEN   64
 
+/* Quirk - RTAS requires 4k list length and block size */
+#define RTAS_BLKLIST_LENGTH 4096
+#define RTAS_BLK_SIZE 4096
+
 struct flash_block {
 	char *data;
 	unsigned long length;
@@ -83,7 +87,7 @@ struct flash_block {
  * into a version/length and translate the pointers
  * to absolute.
  */
-#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
+#define FLASH_BLOCKS_PER_NODE ((RTAS_BLKLIST_LENGTH - 16) / sizeof(struct flash_block))
 struct flash_block_list {
 	unsigned long num_blocks;
 	struct flash_block_list *next;
@@ -96,6 +100,9 @@ struct flash_block_list_header { /* just
 
 static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL};
 
+/* Use slab cache to guarantee 4k alignment */
+static kmem_cache_t *flash_block_cache = NULL;
+
 #define FLASH_BLOCK_LIST_VERSION (1UL)
 
 /* Local copy of the flash block list.
@@ -153,7 +160,7 @@ static int flash_list_valid(struct flash
 				return FLASH_IMG_NULL_DATA;
 			}
 			block_size = f->blocks[i].length;
-			if (block_size <= 0 || block_size > PAGE_SIZE) {
+			if (block_size <= 0 || block_size > RTAS_BLK_SIZE) {
 				return FLASH_IMG_BAD_LEN;
 			}
 			image_size += block_size;
@@ -177,9 +184,9 @@ static void free_flash_list(struct flash
 
 	while (f) {
 		for (i = 0; i < f->num_blocks; i++)
-			free_page((unsigned long)(f->blocks[i].data));
+			kmem_cache_free(flash_block_cache, f->blocks[i].data);
 		next = f->next;
-		free_page((unsigned long)f);
+		kmem_cache_free(flash_block_cache, f);
 		f = next;
 	}
 }
@@ -278,6 +285,12 @@ static ssize_t rtas_flash_read(struct fi
 	return msglen;
 }
 
+/* constructor for flash_block_cache */
+void rtas_block_ctor(void *ptr, kmem_cache_t *cache, unsigned long flags)
+{
+	memset(ptr, 0, RTAS_BLK_SIZE);
+}
+
 /* We could be much more efficient here.  But to keep this function
  * simple we allocate a page to the block list no matter how small the
  * count is.  If the system is low on memory it will be just as well
@@ -302,7 +315,7 @@ static ssize_t rtas_flash_write(struct f
 	 * proc file
 	 */
 	if (uf->flist == NULL) {
-		uf->flist = (struct flash_block_list *) get_zeroed_page(GFP_KERNEL);
+		uf->flist = kmem_cache_alloc(flash_block_cache, GFP_KERNEL);
 		if (!uf->flist)
 			return -ENOMEM;
 	}
@@ -313,21 +326,21 @@ static ssize_t rtas_flash_write(struct f
 	next_free = fl->num_blocks;
 	if (next_free == FLASH_BLOCKS_PER_NODE) {
 		/* Need to allocate another block_list */
-		fl->next = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL);
+		fl->next = kmem_cache_alloc(flash_block_cache, GFP_KERNEL);
 		if (!fl->next)
 			return -ENOMEM;
 		fl = fl->next;
 		next_free = 0;
 	}
 
-	if (count > PAGE_SIZE)
-		count = PAGE_SIZE;
-	p = (char *)get_zeroed_page(GFP_KERNEL);
+	if (count > RTAS_BLK_SIZE)
+		count = RTAS_BLK_SIZE;
+	p = kmem_cache_alloc(flash_block_cache, GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 	
 	if(copy_from_user(p, buffer, count)) {
-		free_page((unsigned long)p);
+		kmem_cache_free(flash_block_cache, p);
 		return -EFAULT;
 	}
 	fl->blocks[next_free].data = p;
@@ -791,6 +804,16 @@ int __init rtas_flash_init(void)
 		goto cleanup;
 
 	rtas_flash_term_hook = rtas_flash_firmware;
+
+	flash_block_cache = kmem_cache_create("rtas_flash_cache",
+				RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
+				rtas_block_ctor, NULL);
+	if (!flash_block_cache) {
+		printk(KERN_ERR "%s: failed to create block cache\n",
+				__FUNCTION__);
+		rc = -ENOMEM;
+		goto cleanup;
+	}
 	return 0;
 
 cleanup:
@@ -804,7 +827,16 @@ cleanup:
 
 void __exit rtas_flash_cleanup(void)
 {
+	int rc;
+
 	rtas_flash_term_hook = NULL;
+
+	if (flash_block_cache) {
+		rc = kmem_cache_destroy(flash_block_cache);
+		if (rc)
+			printk(KERN_WARNING "%s: cache memory leak\n",
+					__FUNCTION__);
+	}
 	remove_flash_pde(firmware_flash_pde);
 	remove_flash_pde(firmware_update_pde);
 	remove_flash_pde(validate_pde);

_

^ permalink raw reply

* Re: [PATCH] powerpc: force 4k update_flash block and list sizes
From: Michael Neuling @ 2006-11-08  4:39 UTC (permalink / raw)
  To: John Rose; +Cc: External List, Paul Mackerras
In-Reply-To: <1162960202.14254.3.camel@sinatra.austin.ibm.com>

In message <1162960202.14254.3.camel@sinatra.austin.ibm.com> you wrote:
> > kmem_cache_destroy doesn't return anything.
> 
> Good call!  How's this:
<snip>
> +	if (flash_block_cache) {
> +		rc = kmem_cache_destroy(flash_block_cache);
> +		if (rc)
> +			printk(KERN_WARNING "%s: cache memory leak\n",
> +					__FUNCTION__);
> +	}

Arrh, did anything change?

Mikey

^ permalink raw reply

* Re: [PATCH] powerpc: force 4k update_flash block and list sizes
From: Michael Ellerman @ 2006-11-08  4:41 UTC (permalink / raw)
  To: John Rose; +Cc: External List, Michael Neuling, Paul Mackerras
In-Reply-To: <1162960202.14254.3.camel@sinatra.austin.ibm.com>

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

On Tue, 2006-11-07 at 22:30 -0600, John Rose wrote:
> > kmem_cache_destroy doesn't return anything.
> 
> Good call!  How's this:
> 
> The enablement of 64k pages on POWER platforms exposed a quirk in the RTAS
> mechanism for updating firmware.  RTAS assumes 4k for flash block and list
> sizes, and use of any other sizes results in a failure.
> 
> This patch changes the rtas_flash module to force the use of 4k memory block
> and list sizes when preparing and sending a firmware image to RTAS.  It also
> changes rtas_flash to use a slab cache to ensure 4k alignment of flash block
> data.  Such alignment is a documented requirement.

Just being picky .. but why did you decide to use the slab cache? Does
it make the code neater? I would have thought you could guarantee 4k
alignment some other way, and it seems slightly odd to use the slab
cache for something you only do once ..

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

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

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

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

^ permalink raw reply

* [PATCH] cell: abstract spu management routines
From: Geoff Levand @ 2006-11-08  4:49 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, cbe-oss-dev

This adds a platform specific spu management abstraction and the corresponding
routines to support the IBM Cell Blade.  It also removes the hypervisor only
resources that were included in struct spu.

Three new platform specific routines are introduced, spu_enumerate_spus(),
spu_create_spu() and spu_destroy_spu().  The underlining design uses a new
type, struct spu_management_ops, to hold function pointers that the platform
setup code is expected to initialize to instances appropriate to that platform.

For the IBM Cell Blade support, I put the hypervisor only resources that were
in struct spu into a platform specific data structure struct platform_data.


Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>

---

Index: cell--common--6/arch/powerpc/platforms/cell/setup.c
===================================================================
--- cell--common--6.orig/arch/powerpc/platforms/cell/setup.c
+++ cell--common--6/arch/powerpc/platforms/cell/setup.c
@@ -97,7 +97,8 @@
 static void __init cell_setup_arch(void)
 {
 #ifdef CONFIG_SPU_BASE
-	spu_priv1_ops         = &spu_priv1_mmio_ops;
+	spu_priv1_ops = &spu_priv1_mmio_ops;
+	spu_management_ops = &spu_management_of_ops;
 #endif
 
 	cbe_regs_init();
Index: cell--common--6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- cell--common--6.orig/arch/powerpc/platforms/cell/spu_base.c
+++ cell--common--6/arch/powerpc/platforms/cell/spu_base.c
@@ -25,23 +25,17 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/poll.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
-
-#include <asm/firmware.h>
-#include <asm/io.h>
-#include <asm/prom.h>
+#include <linux/mm.h>
+#include <linux/io.h>
 #include <linux/mutex.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
-#include <asm/mmu_context.h>
 #include <asm/xmon.h>
 
-#include "interrupt.h"
-
+const struct spu_management_ops *spu_management_ops;
 const struct spu_priv1_ops *spu_priv1_ops;
 
 EXPORT_SYMBOL_GPL(spu_priv1_ops);
@@ -512,235 +506,6 @@
 	return ret;
 }
 
-static int __init find_spu_node_id(struct device_node *spe)
-{
-	const unsigned int *id;
-	struct device_node *cpu;
-	cpu = spe->parent->parent;
-	id = get_property(cpu, "node-id", NULL);
-	return id ? *id : 0;
-}
-
-static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
-		const char *prop)
-{
-	static DEFINE_MUTEX(add_spumem_mutex);
-
-	const struct address_prop {
-		unsigned long address;
-		unsigned int len;
-	} __attribute__((packed)) *p;
-	int proplen;
-
-	unsigned long start_pfn, nr_pages;
-	struct pglist_data *pgdata;
-	struct zone *zone;
-	int ret;
-
-	p = get_property(spe, prop, &proplen);
-	WARN_ON(proplen != sizeof (*p));
-
-	start_pfn = p->address >> PAGE_SHIFT;
-	nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-	pgdata = NODE_DATA(spu->nid);
-	zone = pgdata->node_zones;
-
-	/* XXX rethink locking here */
-	mutex_lock(&add_spumem_mutex);
-	ret = __add_pages(zone, start_pfn, nr_pages);
-	mutex_unlock(&add_spumem_mutex);
-
-	return ret;
-}
-
-static void __iomem * __init map_spe_prop(struct spu *spu,
-		struct device_node *n, const char *name)
-{
-	const struct address_prop {
-		unsigned long address;
-		unsigned int len;
-	} __attribute__((packed)) *prop;
-
-	const void *p;
-	int proplen;
-	void __iomem *ret = NULL;
-	int err = 0;
-
-	p = get_property(n, name, &proplen);
-	if (proplen != sizeof (struct address_prop))
-		return NULL;
-
-	prop = p;
-
-	err = cell_spuprop_present(spu, n, name);
-	if (err && (err != -EEXIST))
-		goto out;
-
-	ret = ioremap(prop->address, prop->len);
-
- out:
-	return ret;
-}
-
-static void spu_unmap(struct spu *spu)
-{
-	iounmap(spu->priv2);
-	iounmap(spu->priv1);
-	iounmap(spu->problem);
-	iounmap((__force u8 __iomem *)spu->local_store);
-}
-
-/* This function shall be abstracted for HV platforms */
-static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np)
-{
-	unsigned int isrc;
-	const u32 *tmp;
-
-	/* Get the interrupt source unit from the device-tree */
-	tmp = get_property(np, "isrc", NULL);
-	if (!tmp)
-		return -ENODEV;
-	isrc = tmp[0];
-
-	/* Add the node number */
-	isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
-
-	/* Now map interrupts of all 3 classes */
-	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
-	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
-	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
-
-	/* Right now, we only fail if class 2 failed */
-	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
-}
-
-static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
-{
-	const char *prop;
-	int ret;
-
-	ret = -ENODEV;
-	spu->name = get_property(node, "name", NULL);
-	if (!spu->name)
-		goto out;
-
-	prop = get_property(node, "local-store", NULL);
-	if (!prop)
-		goto out;
-	spu->local_store_phys = *(unsigned long *)prop;
-
-	/* we use local store as ram, not io memory */
-	spu->local_store = (void __force *)
-		map_spe_prop(spu, node, "local-store");
-	if (!spu->local_store)
-		goto out;
-
-	prop = get_property(node, "problem", NULL);
-	if (!prop)
-		goto out_unmap;
-	spu->problem_phys = *(unsigned long *)prop;
-
-	spu->problem= map_spe_prop(spu, node, "problem");
-	if (!spu->problem)
-		goto out_unmap;
-
-	spu->priv1= map_spe_prop(spu, node, "priv1");
-	/* priv1 is not available on a hypervisor */
-
-	spu->priv2= map_spe_prop(spu, node, "priv2");
-	if (!spu->priv2)
-		goto out_unmap;
-	ret = 0;
-	goto out;
-
-out_unmap:
-	spu_unmap(spu);
-out:
-	return ret;
-}
-
-static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
-{
-	struct of_irq oirq;
-	int ret;
-	int i;
-
-	for (i=0; i < 3; i++) {
-		ret = of_irq_map_one(np, i, &oirq);
-		if (ret)
-			goto err;
-
-		ret = -EINVAL;
-		spu->irqs[i] = irq_create_of_mapping(oirq.controller,
-					oirq.specifier, oirq.size);
-		if (spu->irqs[i] == NO_IRQ)
-			goto err;
-	}
-	return 0;
-
-err:
-	pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, spu->name);
-	for (; i >= 0; i--) {
-		if (spu->irqs[i] != NO_IRQ)
-			irq_dispose_mapping(spu->irqs[i]);
-	}
-	return ret;
-}
-
-static int spu_map_resource(struct device_node *node, int nr,
-		void __iomem** virt, unsigned long *phys)
-{
-	struct resource resource = { };
-	int ret;
-
-	ret = of_address_to_resource(node, 0, &resource);
-	if (ret)
-		goto out;
-
-	if (phys)
-		*phys = resource.start;
-	*virt = ioremap(resource.start, resource.end - resource.start);
-	if (!*virt)
-		ret = -EINVAL;
-
-out:
-	return ret;
-}
-
-static int __init spu_map_device(struct spu *spu, struct device_node *node)
-{
-	int ret = -ENODEV;
-	spu->name = get_property(node, "name", NULL);
-	if (!spu->name)
-		goto out;
-
-	ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
-					&spu->local_store_phys);
-	if (ret)
-		goto out;
-	ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
-					&spu->problem_phys);
-	if (ret)
-		goto out_unmap;
-	ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
-					NULL);
-	if (ret)
-		goto out_unmap;
-
-	if (!firmware_has_feature(FW_FEATURE_LPAR))
-		ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1,
-					NULL);
-	if (ret)
-		goto out_unmap;
-	return 0;
-
-out_unmap:
-	spu_unmap(spu);
-out:
-	pr_debug("failed to map spe %s: %d\n", spu->name, ret);
-	return ret;
-}
 
 struct sysdev_class spu_sysdev_class = {
 	set_kset_name("spu")
@@ -821,7 +586,7 @@
 	sysdev_unregister(&spu->sysdev);
 }
 
-static int __init create_spu(struct device_node *spe)
+static int __init create_spu(void *data)
 {
 	struct spu *spu;
 	int ret;
@@ -832,60 +597,37 @@
 	if (!spu)
 		goto out;
 
-	spu->node = find_spu_node_id(spe);
-	if (spu->node >= MAX_NUMNODES) {
-		printk(KERN_WARNING "SPE %s on node %d ignored,"
-		       " node number too big\n", spe->full_name, spu->node);
-		printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
-		return -ENODEV;
-	}
-	spu->nid = of_node_to_nid(spe);
-	if (spu->nid == -1)
-		spu->nid = 0;
+	spin_lock_init(&spu->register_lock);
+	mutex_lock(&spu_mutex);
+	spu->number = number++;
+	mutex_unlock(&spu_mutex);
+
+	ret = spu_create_spu(spu, data);
 
-	ret = spu_map_device(spu, spe);
-	/* try old method */
-	if (ret)
-		ret = spu_map_device_old(spu, spe);
 	if (ret)
 		goto out_free;
 
-	ret = spu_map_interrupts(spu, spe);
-	if (ret)
-		ret = spu_map_interrupts_old(spu, spe);
-	if (ret)
-		goto out_unmap;
-	spin_lock_init(&spu->register_lock);
 	spu_mfc_sdr_setup(spu);
 	spu_mfc_sr1_set(spu, 0x33);
-	mutex_lock(&spu_mutex);
-
-	spu->number = number++;
 	ret = spu_request_irqs(spu);
 	if (ret)
-		goto out_unlock;
+		goto out_destroy;
 
 	ret = spu_create_sysdev(spu);
 	if (ret)
 		goto out_free_irqs;
 
+	mutex_lock(&spu_mutex);
 	list_add(&spu->list, &spu_list[spu->node]);
 	list_add(&spu->full_list, &spu_full_list);
-	spu->devnode = of_node_get(spe);
-
 	mutex_unlock(&spu_mutex);
 
-	pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n",
-		spu->name, spu->local_store,
-		spu->problem, spu->priv1, spu->priv2, spu->number);
 	goto out;
 
 out_free_irqs:
 	spu_free_irqs(spu);
-out_unlock:
-	mutex_unlock(&spu_mutex);
-out_unmap:
-	spu_unmap(spu);
+out_destroy:
+	spu_destroy_spu(spu);
 out_free:
 	kfree(spu);
 out:
@@ -897,11 +639,9 @@
 	list_del_init(&spu->list);
 	list_del_init(&spu->full_list);
 
-	of_node_put(spu->devnode);
-
 	spu_destroy_sysdev(spu);
 	spu_free_irqs(spu);
-	spu_unmap(spu);
+	spu_destroy_spu(spu);
 	kfree(spu);
 }
 
@@ -922,7 +662,6 @@
 
 static int __init init_spu_base(void)
 {
-	struct device_node *node;
 	int i, ret;
 
 	/* create sysdev class for spus */
@@ -933,16 +672,13 @@
 	for (i = 0; i < MAX_NUMNODES; i++)
 		INIT_LIST_HEAD(&spu_list[i]);
 
-	ret = -ENODEV;
-	for (node = of_find_node_by_type(NULL, "spe");
-			node; node = of_find_node_by_type(node, "spe")) {
-		ret = create_spu(node);
-		if (ret) {
-			printk(KERN_WARNING "%s: Error initializing %s\n",
-				__FUNCTION__, node->name);
-			cleanup_spu_base();
-			break;
-		}
+	ret = spu_enumerate_spus(create_spu);
+
+	if (ret) {
+		printk(KERN_WARNING "%s: Error initializing spus\n",
+			__FUNCTION__);
+		cleanup_spu_base();
+		return ret;
 	}
 
 	xmon_register_spus(&spu_full_list);
Index: cell--common--6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
===================================================================
--- cell--common--6.orig/arch/powerpc/platforms/cell/spu_priv1_mmio.c
+++ cell--common--6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -18,120 +18,467 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#undef DEBUG
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
 #include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
 
-#include <asm/io.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
+#include <asm/firmware.h>
+#include <asm/prom.h>
 
 #include "interrupt.h"
 
+struct platform_data {
+	int nid;
+	struct device_node *devnode;
+	struct spu_priv1 __iomem *priv1;
+};
+
+static struct platform_data *platform_data(struct spu *spu)
+{
+	BUG_ON(!spu->platform_data);
+	return (struct platform_data*)spu->platform_data;
+}
+
+static int __init find_spu_node_id(struct device_node *spe)
+{
+	const unsigned int *id;
+	struct device_node *cpu;
+	cpu = spe->parent->parent;
+	id = get_property(cpu, "node-id", NULL);
+	return id ? *id : 0;
+}
+
+static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
+		const char *prop)
+{
+	static DEFINE_MUTEX(add_spumem_mutex);
+
+	const struct address_prop {
+		unsigned long address;
+		unsigned int len;
+	} __attribute__((packed)) *p;
+	int proplen;
+
+	unsigned long start_pfn, nr_pages;
+	struct pglist_data *pgdata;
+	struct zone *zone;
+	int ret;
+
+	p = get_property(spe, prop, &proplen);
+	WARN_ON(proplen != sizeof (*p));
+
+	start_pfn = p->address >> PAGE_SHIFT;
+	nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+	pgdata = NODE_DATA(spu->nid);
+	zone = pgdata->node_zones;
+
+	/* XXX rethink locking here */
+	mutex_lock(&add_spumem_mutex);
+	ret = __add_pages(zone, start_pfn, nr_pages);
+	mutex_unlock(&add_spumem_mutex);
+
+	return ret;
+}
+
+static void __iomem * __init map_spe_prop(struct spu *spu,
+		struct device_node *n, const char *name)
+{
+	const struct address_prop {
+		unsigned long address;
+		unsigned int len;
+	} __attribute__((packed)) *prop;
+
+	const void *p;
+	int proplen;
+	void __iomem *ret = NULL;
+	int err = 0;
+
+	p = get_property(n, name, &proplen);
+	if (proplen != sizeof (struct address_prop))
+		return NULL;
+
+	prop = p;
+
+	err = cell_spuprop_present(spu, n, name);
+	if (err && (err != -EEXIST))
+		goto out;
+
+	ret = ioremap(prop->address, prop->len);
+
+ out:
+	return ret;
+}
+
+static void spu_unmap(struct spu *spu)
+{
+	iounmap(spu->priv2);
+	iounmap(platform_data(spu)->priv1);
+	iounmap(spu->problem);
+	iounmap((__force u8 __iomem *)spu->local_store);
+}
+
+static int __init spu_map_interrupts_old(struct spu *spu,
+	struct device_node *np)
+{
+	unsigned int isrc;
+	const u32 *tmp;
+
+	/* Get the interrupt source unit from the device-tree */
+	tmp = get_property(np, "isrc", NULL);
+	if (!tmp)
+		return -ENODEV;
+	isrc = tmp[0];
+
+	/* Add the node number */
+	isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
+
+	/* Now map interrupts of all 3 classes */
+	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
+	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
+	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
+
+	/* Right now, we only fail if class 2 failed */
+	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
+}
+
+static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
+{
+	const char *prop;
+	int ret;
+
+	ret = -ENODEV;
+	spu->name = get_property(node, "name", NULL);
+	if (!spu->name)
+		goto out;
+
+	prop = get_property(node, "local-store", NULL);
+	if (!prop)
+		goto out;
+	spu->local_store_phys = *(unsigned long *)prop;
+
+	/* we use local store as ram, not io memory */
+	spu->local_store = (void __force *)
+		map_spe_prop(spu, node, "local-store");
+	if (!spu->local_store)
+		goto out;
+
+	prop = get_property(node, "problem", NULL);
+	if (!prop)
+		goto out_unmap;
+	spu->problem_phys = *(unsigned long *)prop;
+
+	spu->problem= map_spe_prop(spu, node, "problem");
+	if (!spu->problem)
+		goto out_unmap;
+
+	platform_data(spu)->priv1= map_spe_prop(spu, node, "priv1");
+
+	spu->priv2= map_spe_prop(spu, node, "priv2");
+	if (!spu->priv2)
+		goto out_unmap;
+	ret = 0;
+	goto out;
+
+out_unmap:
+	spu_unmap(spu);
+out:
+	return ret;
+}
+
+static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
+{
+	struct of_irq oirq;
+	int ret;
+	int i;
+
+	for (i=0; i < 3; i++) {
+		ret = of_irq_map_one(np, i, &oirq);
+		if (ret)
+			goto err;
+
+		ret = -EINVAL;
+		spu->irqs[i] = irq_create_of_mapping(oirq.controller,
+					oirq.specifier, oirq.size);
+		if (spu->irqs[i] == NO_IRQ)
+			goto err;
+	}
+	return 0;
+
+err:
+	pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier,
+		spu->name);
+	for (; i >= 0; i--) {
+		if (spu->irqs[i] != NO_IRQ)
+			irq_dispose_mapping(spu->irqs[i]);
+	}
+	return ret;
+}
+
+static int spu_map_resource(struct device_node *node, int nr,
+		void __iomem** virt, unsigned long *phys)
+{
+	struct resource resource = { };
+	int ret;
+
+	ret = of_address_to_resource(node, 0, &resource);
+	if (ret)
+		goto out;
+
+	if (phys)
+		*phys = resource.start;
+	*virt = ioremap(resource.start, resource.end - resource.start);
+	if (!*virt)
+		ret = -EINVAL;
+
+out:
+	return ret;
+}
+
+static int __init spu_map_device(struct spu *spu, struct device_node *node)
+{
+	int ret = -ENODEV;
+	spu->name = get_property(node, "name", NULL);
+	if (!spu->name)
+		goto out;
+
+	ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
+					&spu->local_store_phys);
+	if (ret)
+		goto out;
+	ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
+					&spu->problem_phys);
+	if (ret)
+		goto out_unmap;
+	ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
+					NULL);
+	if (ret)
+		goto out_unmap;
+
+	if (!firmware_has_feature(FW_FEATURE_LPAR))
+		ret = spu_map_resource(node, 3,
+			(void __iomem**)&platform_data(spu)->priv1, NULL);
+	if (ret)
+		goto out_unmap;
+	return 0;
+
+out_unmap:
+	spu_unmap(spu);
+out:
+	pr_debug("failed to map spe %s: %d\n", spu->name, ret);
+	return ret;
+}
+
+static int __init of_create_spu(struct spu *spu, void *data)
+{
+	int ret;
+	struct device_node *spe = (struct device_node *)data;
+
+	spu->platform_data = kzalloc(sizeof(struct platform_data),
+		GFP_KERNEL);
+	if (!spu->platform_data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	spu->node = find_spu_node_id(spe);
+	if (spu->node >= MAX_NUMNODES) {
+		printk(KERN_WARNING "SPE %s on node %d ignored,"
+		       " node number too big\n", spe->full_name, spu->node);
+		printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
+		ret = -ENODEV;
+		goto out_free;
+	}
+
+	platform_data(spu)->nid = of_node_to_nid(spe);
+	if (platform_data(spu)->nid == -1)
+		platform_data(spu)->nid = 0;
+
+	ret = spu_map_device(spu, spe);
+	/* try old method */
+	if (ret)
+		ret = spu_map_device_old(spu, spe);
+	if (ret)
+		goto out_free;
+
+	ret = spu_map_interrupts(spu, spe);
+	if (ret)
+		ret = spu_map_interrupts_old(spu, spe);
+	if (ret)
+		goto out_unmap;
+
+	platform_data(spu)->devnode = of_node_get(spe);
+
+	pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n", spu->name,
+		spu->local_store, spu->problem, platform_data(spu)->priv1,
+		spu->priv2, spu->number);
+	goto out;
+
+out_unmap:
+	spu_unmap(spu);
+out_free:
+	kfree(spu->platform_data);
+	spu->platform_data = NULL;
+out:
+	return ret;
+}
+
+static int of_destroy_spu(struct spu *spu)
+{
+	spu_unmap(spu);
+	of_node_put(platform_data(spu)->devnode);
+	kfree(spu->platform_data);
+	spu->platform_data = NULL;
+	return 0;
+}
+
+static int __init of_enumerate_spus(int (*fn)(void *data))
+{
+	int ret;
+	struct device_node *node;
+
+	ret = -ENODEV;
+	for (node = of_find_node_by_type(NULL, "spe");
+			node; node = of_find_node_by_type(node, "spe")) {
+		ret = fn(node);
+		if (ret) {
+			printk(KERN_WARNING "%s: Error initializing %s\n",
+				__FUNCTION__, node->name);
+			break;
+		}
+	}
+	return ret;
+}
+
+const struct spu_management_ops spu_management_of_ops = {
+	.enumerate_spus = of_enumerate_spus,
+	.create_spu = of_create_spu,
+	.destroy_spu = of_destroy_spu,
+};
+
 static void int_mask_and(struct spu *spu, int class, u64 mask)
 {
 	u64 old_mask;
 
-	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
-	out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
+	old_mask = in_be64(&platform_data(spu)->priv1->int_mask_RW[class]);
+	out_be64(&platform_data(spu)->priv1->int_mask_RW[class],
+		old_mask & mask);
 }
 
 static void int_mask_or(struct spu *spu, int class, u64 mask)
 {
 	u64 old_mask;
 
-	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
-	out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
+	old_mask = in_be64(&platform_data(spu)->priv1->int_mask_RW[class]);
+	out_be64(&platform_data(spu)->priv1->int_mask_RW[class],
+		old_mask | mask);
 }
 
 static void int_mask_set(struct spu *spu, int class, u64 mask)
 {
-	out_be64(&spu->priv1->int_mask_RW[class], mask);
+	out_be64(&platform_data(spu)->priv1->int_mask_RW[class], mask);
 }
 
 static u64 int_mask_get(struct spu *spu, int class)
 {
-	return in_be64(&spu->priv1->int_mask_RW[class]);
+	return in_be64(&platform_data(spu)->priv1->int_mask_RW[class]);
 }
 
 static void int_stat_clear(struct spu *spu, int class, u64 stat)
 {
-	out_be64(&spu->priv1->int_stat_RW[class], stat);
+	out_be64(&platform_data(spu)->priv1->int_stat_RW[class], stat);
 }
 
 static u64 int_stat_get(struct spu *spu, int class)
 {
-	return in_be64(&spu->priv1->int_stat_RW[class]);
+	return in_be64(&platform_data(spu)->priv1->int_stat_RW[class]);
 }
 
 static void cpu_affinity_set(struct spu *spu, int cpu)
 {
 	u64 target = iic_get_target_id(cpu);
 	u64 route = target << 48 | target << 32 | target << 16;
-	out_be64(&spu->priv1->int_route_RW, route);
+	out_be64(&platform_data(spu)->priv1->int_route_RW, route);
 }
 
 static u64 mfc_dar_get(struct spu *spu)
 {
-	return in_be64(&spu->priv1->mfc_dar_RW);
+	return in_be64(&platform_data(spu)->priv1->mfc_dar_RW);
 }
 
 static u64 mfc_dsisr_get(struct spu *spu)
 {
-	return in_be64(&spu->priv1->mfc_dsisr_RW);
+	return in_be64(&platform_data(spu)->priv1->mfc_dsisr_RW);
 }
 
 static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
 {
-	out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
+	out_be64(&platform_data(spu)->priv1->mfc_dsisr_RW, dsisr);
 }
 
 static void mfc_sdr_setup(struct spu *spu)
 {
-	out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
+	out_be64(&platform_data(spu)->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
 }
 
 static void mfc_sr1_set(struct spu *spu, u64 sr1)
 {
-	out_be64(&spu->priv1->mfc_sr1_RW, sr1);
+	out_be64(&platform_data(spu)->priv1->mfc_sr1_RW, sr1);
 }
 
 static u64 mfc_sr1_get(struct spu *spu)
 {
-	return in_be64(&spu->priv1->mfc_sr1_RW);
+	return in_be64(&platform_data(spu)->priv1->mfc_sr1_RW);
 }
 
 static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
 {
-	out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
+	out_be64(&platform_data(spu)->priv1->mfc_tclass_id_RW, tclass_id);
 }
 
 static u64 mfc_tclass_id_get(struct spu *spu)
 {
-	return in_be64(&spu->priv1->mfc_tclass_id_RW);
+	return in_be64(&platform_data(spu)->priv1->mfc_tclass_id_RW);
 }
 
 static void tlb_invalidate(struct spu *spu)
 {
-	out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
+	out_be64(&platform_data(spu)->priv1->tlb_invalidate_entry_W, 0ul);
 }
 
 static void resource_allocation_groupID_set(struct spu *spu, u64 id)
 {
-	out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
+	out_be64(&platform_data(spu)->priv1->resource_allocation_groupID_RW,
+		id);
 }
 
 static u64 resource_allocation_groupID_get(struct spu *spu)
 {
-	return in_be64(&spu->priv1->resource_allocation_groupID_RW);
+	return in_be64(
+		&platform_data(spu)->priv1->resource_allocation_groupID_RW);
 }
 
 static void resource_allocation_enable_set(struct spu *spu, u64 enable)
 {
-	out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
+	out_be64(&platform_data(spu)->priv1->resource_allocation_enable_RW,
+		enable);
 }
 
 static u64 resource_allocation_enable_get(struct spu *spu)
 {
-	return in_be64(&spu->priv1->resource_allocation_enable_RW);
+	return in_be64(
+		&platform_data(spu)->priv1->resource_allocation_enable_RW);
 }
 
 const struct spu_priv1_ops spu_priv1_mmio_ops =
Index: cell--common--6/include/asm-powerpc/spu.h
===================================================================
--- cell--common--6.orig/include/asm-powerpc/spu.h
+++ cell--common--6/include/asm-powerpc/spu.h
@@ -111,13 +111,11 @@
 	u8 *local_store;
 	unsigned long problem_phys;
 	struct spu_problem __iomem *problem;
-	struct spu_priv1 __iomem *priv1;
 	struct spu_priv2 __iomem *priv2;
 	struct list_head list;
 	struct list_head sched_list;
 	struct list_head full_list;
 	int number;
-	int nid;
 	unsigned int irqs[3];
 	u32 node;
 	u64 flags;
@@ -144,8 +142,7 @@
 	char irq_c1[8];
 	char irq_c2[8];
 
-	struct device_node *devnode;
-
+	void* platform_data;
 	struct sys_device sysdev;
 };
 
Index: cell--common--6/include/asm-powerpc/spu_priv1.h
===================================================================
--- cell--common--6.orig/include/asm-powerpc/spu_priv1.h
+++ cell--common--6/include/asm-powerpc/spu_priv1.h
@@ -21,12 +21,13 @@
 #define _SPU_PRIV1_H
 #if defined(__KERNEL__)
 
+#include <linux/types.h>
+
 struct spu;
 
 /* access to priv1 registers */
 
-struct spu_priv1_ops
-{
+struct spu_priv1_ops {
 	void (*int_mask_and) (struct spu *spu, int class, u64 mask);
 	void (*int_mask_or) (struct spu *spu, int class, u64 mask);
 	void (*int_mask_set) (struct spu *spu, int class, u64 mask);
@@ -171,12 +172,41 @@
 	return spu_priv1_ops->resource_allocation_enable_get(spu);
 }
 
-/* The declarations folowing are put here for convenience
- * and only intended to be used by the platform setup code
- * for initializing spu_priv1_ops.
+/* spu management abstraction */
+
+struct spu_management_ops {
+	int (*enumerate_spus)(int (*fn)(void *data));
+	int (*create_spu)(struct spu *spu, void *data);
+	int (*destroy_spu)(struct spu *spu);
+};
+
+extern const struct spu_management_ops* spu_management_ops;
+
+static inline int
+spu_enumerate_spus (int (*fn)(void *data))
+{
+	return spu_management_ops->enumerate_spus(fn);
+}
+
+static inline int
+spu_create_spu (struct spu *spu, void *data)
+{
+	return spu_management_ops->create_spu(spu, data);
+}
+
+static inline int
+spu_destroy_spu (struct spu *spu)
+{
+	return spu_management_ops->destroy_spu(spu);
+}
+
+/*
+ * The declarations folowing are put here for convenience
+ * and only intended to be used by the platform setup code.
  */
 
 extern const struct spu_priv1_ops spu_priv1_mmio_ops;
+extern const struct spu_management_ops spu_management_of_ops;
 
 #endif /* __KERNEL__ */
 #endif

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH] cell: abstract spu management routines
From: Michael Ellerman @ 2006-11-08  5:01 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <455161D2.3090004@am.sony.com>

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

On Tue, 2006-11-07 at 20:49 -0800, Geoff Levand wrote:
> This adds a platform specific spu management abstraction and the corresponding
> routines to support the IBM Cell Blade.  It also removes the hypervisor only
> resources that were included in struct spu.
> 
> Three new platform specific routines are introduced, spu_enumerate_spus(),
> spu_create_spu() and spu_destroy_spu().  The underlining design uses a new
> type, struct spu_management_ops, to hold function pointers that the platform
> setup code is expected to initialize to instances appropriate to that platform.
> 
> For the IBM Cell Blade support, I put the hypervisor only resources that were
> in struct spu into a platform specific data structure struct platform_data.
> 
> 
> Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
> 
> ---
..
> Index: cell--common--6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
> ===================================================================
> --- cell--common--6.orig/arch/powerpc/platforms/cell/spu_priv1_mmio.c
> +++ cell--common--6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
> @@ -18,120 +18,467 @@
>   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
>   */
>  
> +#undef DEBUG
> +
> +#include <linux/interrupt.h>
> +#include <linux/list.h>
>  #include <linux/module.h>
> +#include <linux/ptrace.h>
> +#include <linux/slab.h>
> +#include <linux/wait.h>
> +#include <linux/mm.h>
> +#include <linux/io.h>
> +#include <linux/mutex.h>
> +#include <linux/device.h>
>  
> -#include <asm/io.h>
>  #include <asm/spu.h>
>  #include <asm/spu_priv1.h>
> +#include <asm/firmware.h>
> +#include <asm/prom.h>
>  
>  #include "interrupt.h"
>  
> +struct platform_data {
> +	int nid;
> +	struct device_node *devnode;
> +	struct spu_priv1 __iomem *priv1;
> +};
> +
> +static struct platform_data *platform_data(struct spu *spu)
> +{
> +	BUG_ON(!spu->platform_data);
> +	return (struct platform_data*)spu->platform_data;
> +}

I don't see the point of this, why not just grab platform data directly?

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

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

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

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

^ permalink raw reply

* Clock Modification of MPC885 for USB Host Functionality
From: Prakash Ramaraju @ 2006-11-08  5:01 UTC (permalink / raw)
  To: linuxppc-embedded

Greetings

Currently I have a MPC885 based board running at 50MHz. I want USB
host working at full speed with internal clock. Assuming I need to
change the General System Clock Frequency (GCLK2) to 48MHz, I got this
calculation with input frequency of 10MHz from an u-boot script.

pdf mfi mfn mfd s dbrmo     dpref    dpgdck     jdbck     gclk2 exact?
--- --- --- --- - -----     -----    ------     -----     ----- ------
 0   9   3   4 1     0  10000000 192000000  96000000  48000000    YES
 0   9   6   9 1     0  10000000 192000000  96000000  48000000    YES
 0   9   9  14 1     0  10000000 192000000  96000000  48000000    YES
 0   9  12  19 1     0  10000000 192000000  96000000  48000000    YES

I modified CFG_PLPRCR (to 19194000) in u-boot config file to match
this. But I'm getting only 45MHz output clock (not exactly 48MHz which
is needed for USB to work)

If anyone can shed some info making the USB work on MPC885 with
internal clock or changing the clock freq to exact 48MHz, it will be
helpful.

-- 
With best regards,
Prakash

^ permalink raw reply

* Clock Modification of MPC885 for USB Host Functionality
From: Prakash Ramaraju @ 2006-11-08  5:05 UTC (permalink / raw)
  To: linuxppc-embedded

Greetings

Currently I have a MPC885 based board running at 50MHz. I want USB host
working at full speed with internal clock. Assuming I need to change the
General System Clock Frequency (GCLK2) to 48MHz, I got this calculation with
input frequency of 10MHz from an u-boot script.

pdf mfi mfn mfd s dbrmo     dpref    dpgdck     jdbck     gclk2 exact?
--- --- --- --- - -----     -----    ------     -----     ----- ------
  0   9   3   4 1     0  10000000 192000000  96000000  48000000    YES
  0   9   6   9 1     0  10000000 192000000  96000000  48000000    YES
  0   9   9  14 1     0  10000000 192000000  96000000  48000000    YES
  0   9  12  19 1     0  10000000 192000000  96000000  48000000    YES

I modified CFG_PLPRCR (to 19194000) in u-boot config file to match this. But
I'm getting only 45MHz output clock (not exactly 48MHz which is needed for
USB to work)

If anyone can shed some info making the USB work on MPC885 with internal
clock or changing the clock freq to exact 48MHz, it will be helpful.

Thanks

-- 
With best regards,
Prakash

^ permalink raw reply

* Re: [RFC/PATCH 0/7] Powerpc MSI Implementation
From: Michael Ellerman @ 2006-11-08  5:18 UTC (permalink / raw)
  To: Greg KH; +Cc: linuxppc-dev, Eric W. Biederman, linux-pci, David S. Miller
In-Reply-To: <20061107080257.GA5874@kroah.com>

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

On Tue, 2006-11-07 at 17:02 +0900, Greg KH wrote:
> On Tue, Nov 07, 2006 at 06:41:16PM +1100, Benjamin Herrenschmidt wrote:
> > 
> > >  * Moved msi_info into the pci_dev. This is ugly, but not sure where else
> > >    we can put it, pci_dn is no longer an option.
> > 
> > It's only ugly because it's currently powerpc specific (and thus needs
> > an ifdef). It's the right way to go in the long run for the generic
> > code. 
> > 
> > Now the question is wether Eric is interested in our work and thus
> > wether it's worth trying to port the intel & altix MSI stuff to our
> > infrastructure, in which case there is no more reason not to add the
> > msi_info to pci_dev without any ifdef (just define it as an empty struct
> > if CONFIG_PCI_MSI is not set).
> 
> I have no objection to taking this core change, and I do think the intel
> and altix stuff should be moved over to this new model.

Cool.

> Oh, and I think your first two patches can be applied now to the tree
> (header file changes).  Any objection to me doing this?

There's a trivial bug in 1/7 (HT #defines), so hold back on that one
until I resend. The movement of MSI-X #defines is good to go. I also
sent you the patch to add HT_SUBCAP_OFFSET yesterday that I think is
ready to merge.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

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

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

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

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH] cell: abstract spu management routines
From: Geoff Levand @ 2006-11-08  5:24 UTC (permalink / raw)
  To: michael; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <1162962074.20271.16.camel@localhost.localdomain>

Michael Ellerman wrote:
>> +static struct platform_data *platform_data(struct spu *spu)
>> +{
>> +	BUG_ON(!spu->platform_data);
>> +	return (struct platform_data*)spu->platform_data;
>> +}
> 
> I don't see the point of this, why not just grab platform data directly?

Well, first, it does a check, and second, you can't just grab platform_data,
you need to always do the cast also. So then, is something like
'((struct platform_data*)spu->platform_data)->' preferred over
'platform_data(spu)->'?

-Geoff

^ permalink raw reply

* Re: [PATCH] cell: abstract spu management routines
From: Benjamin Herrenschmidt @ 2006-11-08  5:31 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <455161D2.3090004@am.sony.com>


> For the IBM Cell Blade support, I put the hypervisor only resources that were
> in struct spu into a platform specific data structure struct platform_data.

We have no hypervisor :-) The idea looks good, the implementation, I
havent looked in too much details yet but it looks good, though I don't
like the naming of "platform_data" that much (a pain to type, and I find
it confusing to haev a struct, a field and a function all with the same
name).

Ben.


> Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
> 
> ---
> 
> Index: cell--common--6/arch/powerpc/platforms/cell/setup.c
> ===================================================================
> --- cell--common--6.orig/arch/powerpc/platforms/cell/setup.c
> +++ cell--common--6/arch/powerpc/platforms/cell/setup.c
> @@ -97,7 +97,8 @@
>  static void __init cell_setup_arch(void)
>  {
>  #ifdef CONFIG_SPU_BASE
> -	spu_priv1_ops         = &spu_priv1_mmio_ops;
> +	spu_priv1_ops = &spu_priv1_mmio_ops;
> +	spu_management_ops = &spu_management_of_ops;
>  #endif
>  
>  	cbe_regs_init();
> Index: cell--common--6/arch/powerpc/platforms/cell/spu_base.c
> ===================================================================
> --- cell--common--6.orig/arch/powerpc/platforms/cell/spu_base.c
> +++ cell--common--6/arch/powerpc/platforms/cell/spu_base.c
> @@ -25,23 +25,17 @@
>  #include <linux/interrupt.h>
>  #include <linux/list.h>
>  #include <linux/module.h>
> -#include <linux/pci.h>
> -#include <linux/poll.h>
>  #include <linux/ptrace.h>
>  #include <linux/slab.h>
>  #include <linux/wait.h>
> -
> -#include <asm/firmware.h>
> -#include <asm/io.h>
> -#include <asm/prom.h>
> +#include <linux/mm.h>
> +#include <linux/io.h>
>  #include <linux/mutex.h>
>  #include <asm/spu.h>
>  #include <asm/spu_priv1.h>
> -#include <asm/mmu_context.h>
>  #include <asm/xmon.h>
>  
> -#include "interrupt.h"
> -
> +const struct spu_management_ops *spu_management_ops;
>  const struct spu_priv1_ops *spu_priv1_ops;
>  
>  EXPORT_SYMBOL_GPL(spu_priv1_ops);
> @@ -512,235 +506,6 @@
>  	return ret;
>  }
>  
> -static int __init find_spu_node_id(struct device_node *spe)
> -{
> -	const unsigned int *id;
> -	struct device_node *cpu;
> -	cpu = spe->parent->parent;
> -	id = get_property(cpu, "node-id", NULL);
> -	return id ? *id : 0;
> -}
> -
> -static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
> -		const char *prop)
> -{
> -	static DEFINE_MUTEX(add_spumem_mutex);
> -
> -	const struct address_prop {
> -		unsigned long address;
> -		unsigned int len;
> -	} __attribute__((packed)) *p;
> -	int proplen;
> -
> -	unsigned long start_pfn, nr_pages;
> -	struct pglist_data *pgdata;
> -	struct zone *zone;
> -	int ret;
> -
> -	p = get_property(spe, prop, &proplen);
> -	WARN_ON(proplen != sizeof (*p));
> -
> -	start_pfn = p->address >> PAGE_SHIFT;
> -	nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
> -
> -	pgdata = NODE_DATA(spu->nid);
> -	zone = pgdata->node_zones;
> -
> -	/* XXX rethink locking here */
> -	mutex_lock(&add_spumem_mutex);
> -	ret = __add_pages(zone, start_pfn, nr_pages);
> -	mutex_unlock(&add_spumem_mutex);
> -
> -	return ret;
> -}
> -
> -static void __iomem * __init map_spe_prop(struct spu *spu,
> -		struct device_node *n, const char *name)
> -{
> -	const struct address_prop {
> -		unsigned long address;
> -		unsigned int len;
> -	} __attribute__((packed)) *prop;
> -
> -	const void *p;
> -	int proplen;
> -	void __iomem *ret = NULL;
> -	int err = 0;
> -
> -	p = get_property(n, name, &proplen);
> -	if (proplen != sizeof (struct address_prop))
> -		return NULL;
> -
> -	prop = p;
> -
> -	err = cell_spuprop_present(spu, n, name);
> -	if (err && (err != -EEXIST))
> -		goto out;
> -
> -	ret = ioremap(prop->address, prop->len);
> -
> - out:
> -	return ret;
> -}
> -
> -static void spu_unmap(struct spu *spu)
> -{
> -	iounmap(spu->priv2);
> -	iounmap(spu->priv1);
> -	iounmap(spu->problem);
> -	iounmap((__force u8 __iomem *)spu->local_store);
> -}
> -
> -/* This function shall be abstracted for HV platforms */
> -static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np)
> -{
> -	unsigned int isrc;
> -	const u32 *tmp;
> -
> -	/* Get the interrupt source unit from the device-tree */
> -	tmp = get_property(np, "isrc", NULL);
> -	if (!tmp)
> -		return -ENODEV;
> -	isrc = tmp[0];
> -
> -	/* Add the node number */
> -	isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
> -
> -	/* Now map interrupts of all 3 classes */
> -	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
> -	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
> -	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
> -
> -	/* Right now, we only fail if class 2 failed */
> -	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
> -}
> -
> -static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
> -{
> -	const char *prop;
> -	int ret;
> -
> -	ret = -ENODEV;
> -	spu->name = get_property(node, "name", NULL);
> -	if (!spu->name)
> -		goto out;
> -
> -	prop = get_property(node, "local-store", NULL);
> -	if (!prop)
> -		goto out;
> -	spu->local_store_phys = *(unsigned long *)prop;
> -
> -	/* we use local store as ram, not io memory */
> -	spu->local_store = (void __force *)
> -		map_spe_prop(spu, node, "local-store");
> -	if (!spu->local_store)
> -		goto out;
> -
> -	prop = get_property(node, "problem", NULL);
> -	if (!prop)
> -		goto out_unmap;
> -	spu->problem_phys = *(unsigned long *)prop;
> -
> -	spu->problem= map_spe_prop(spu, node, "problem");
> -	if (!spu->problem)
> -		goto out_unmap;
> -
> -	spu->priv1= map_spe_prop(spu, node, "priv1");
> -	/* priv1 is not available on a hypervisor */
> -
> -	spu->priv2= map_spe_prop(spu, node, "priv2");
> -	if (!spu->priv2)
> -		goto out_unmap;
> -	ret = 0;
> -	goto out;
> -
> -out_unmap:
> -	spu_unmap(spu);
> -out:
> -	return ret;
> -}
> -
> -static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
> -{
> -	struct of_irq oirq;
> -	int ret;
> -	int i;
> -
> -	for (i=0; i < 3; i++) {
> -		ret = of_irq_map_one(np, i, &oirq);
> -		if (ret)
> -			goto err;
> -
> -		ret = -EINVAL;
> -		spu->irqs[i] = irq_create_of_mapping(oirq.controller,
> -					oirq.specifier, oirq.size);
> -		if (spu->irqs[i] == NO_IRQ)
> -			goto err;
> -	}
> -	return 0;
> -
> -err:
> -	pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, spu->name);
> -	for (; i >= 0; i--) {
> -		if (spu->irqs[i] != NO_IRQ)
> -			irq_dispose_mapping(spu->irqs[i]);
> -	}
> -	return ret;
> -}
> -
> -static int spu_map_resource(struct device_node *node, int nr,
> -		void __iomem** virt, unsigned long *phys)
> -{
> -	struct resource resource = { };
> -	int ret;
> -
> -	ret = of_address_to_resource(node, 0, &resource);
> -	if (ret)
> -		goto out;
> -
> -	if (phys)
> -		*phys = resource.start;
> -	*virt = ioremap(resource.start, resource.end - resource.start);
> -	if (!*virt)
> -		ret = -EINVAL;
> -
> -out:
> -	return ret;
> -}
> -
> -static int __init spu_map_device(struct spu *spu, struct device_node *node)
> -{
> -	int ret = -ENODEV;
> -	spu->name = get_property(node, "name", NULL);
> -	if (!spu->name)
> -		goto out;
> -
> -	ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
> -					&spu->local_store_phys);
> -	if (ret)
> -		goto out;
> -	ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
> -					&spu->problem_phys);
> -	if (ret)
> -		goto out_unmap;
> -	ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
> -					NULL);
> -	if (ret)
> -		goto out_unmap;
> -
> -	if (!firmware_has_feature(FW_FEATURE_LPAR))
> -		ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1,
> -					NULL);
> -	if (ret)
> -		goto out_unmap;
> -	return 0;
> -
> -out_unmap:
> -	spu_unmap(spu);
> -out:
> -	pr_debug("failed to map spe %s: %d\n", spu->name, ret);
> -	return ret;
> -}
>  
>  struct sysdev_class spu_sysdev_class = {
>  	set_kset_name("spu")
> @@ -821,7 +586,7 @@
>  	sysdev_unregister(&spu->sysdev);
>  }
>  
> -static int __init create_spu(struct device_node *spe)
> +static int __init create_spu(void *data)
>  {
>  	struct spu *spu;
>  	int ret;
> @@ -832,60 +597,37 @@
>  	if (!spu)
>  		goto out;
>  
> -	spu->node = find_spu_node_id(spe);
> -	if (spu->node >= MAX_NUMNODES) {
> -		printk(KERN_WARNING "SPE %s on node %d ignored,"
> -		       " node number too big\n", spe->full_name, spu->node);
> -		printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
> -		return -ENODEV;
> -	}
> -	spu->nid = of_node_to_nid(spe);
> -	if (spu->nid == -1)
> -		spu->nid = 0;
> +	spin_lock_init(&spu->register_lock);
> +	mutex_lock(&spu_mutex);
> +	spu->number = number++;
> +	mutex_unlock(&spu_mutex);
> +
> +	ret = spu_create_spu(spu, data);
>  
> -	ret = spu_map_device(spu, spe);
> -	/* try old method */
> -	if (ret)
> -		ret = spu_map_device_old(spu, spe);
>  	if (ret)
>  		goto out_free;
>  
> -	ret = spu_map_interrupts(spu, spe);
> -	if (ret)
> -		ret = spu_map_interrupts_old(spu, spe);
> -	if (ret)
> -		goto out_unmap;
> -	spin_lock_init(&spu->register_lock);
>  	spu_mfc_sdr_setup(spu);
>  	spu_mfc_sr1_set(spu, 0x33);
> -	mutex_lock(&spu_mutex);
> -
> -	spu->number = number++;
>  	ret = spu_request_irqs(spu);
>  	if (ret)
> -		goto out_unlock;
> +		goto out_destroy;
>  
>  	ret = spu_create_sysdev(spu);
>  	if (ret)
>  		goto out_free_irqs;
>  
> +	mutex_lock(&spu_mutex);
>  	list_add(&spu->list, &spu_list[spu->node]);
>  	list_add(&spu->full_list, &spu_full_list);
> -	spu->devnode = of_node_get(spe);
> -
>  	mutex_unlock(&spu_mutex);
>  
> -	pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n",
> -		spu->name, spu->local_store,
> -		spu->problem, spu->priv1, spu->priv2, spu->number);
>  	goto out;
>  
>  out_free_irqs:
>  	spu_free_irqs(spu);
> -out_unlock:
> -	mutex_unlock(&spu_mutex);
> -out_unmap:
> -	spu_unmap(spu);
> +out_destroy:
> +	spu_destroy_spu(spu);
>  out_free:
>  	kfree(spu);
>  out:
> @@ -897,11 +639,9 @@
>  	list_del_init(&spu->list);
>  	list_del_init(&spu->full_list);
>  
> -	of_node_put(spu->devnode);
> -
>  	spu_destroy_sysdev(spu);
>  	spu_free_irqs(spu);
> -	spu_unmap(spu);
> +	spu_destroy_spu(spu);
>  	kfree(spu);
>  }
>  
> @@ -922,7 +662,6 @@
>  
>  static int __init init_spu_base(void)
>  {
> -	struct device_node *node;
>  	int i, ret;
>  
>  	/* create sysdev class for spus */
> @@ -933,16 +672,13 @@
>  	for (i = 0; i < MAX_NUMNODES; i++)
>  		INIT_LIST_HEAD(&spu_list[i]);
>  
> -	ret = -ENODEV;
> -	for (node = of_find_node_by_type(NULL, "spe");
> -			node; node = of_find_node_by_type(node, "spe")) {
> -		ret = create_spu(node);
> -		if (ret) {
> -			printk(KERN_WARNING "%s: Error initializing %s\n",
> -				__FUNCTION__, node->name);
> -			cleanup_spu_base();
> -			break;
> -		}
> +	ret = spu_enumerate_spus(create_spu);
> +
> +	if (ret) {
> +		printk(KERN_WARNING "%s: Error initializing spus\n",
> +			__FUNCTION__);
> +		cleanup_spu_base();
> +		return ret;
>  	}
>  
>  	xmon_register_spus(&spu_full_list);
> Index: cell--common--6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
> ===================================================================
> --- cell--common--6.orig/arch/powerpc/platforms/cell/spu_priv1_mmio.c
> +++ cell--common--6/arch/powerpc/platforms/cell/spu_priv1_mmio.c
> @@ -18,120 +18,467 @@
>   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
>   */
>  
> +#undef DEBUG
> +
> +#include <linux/interrupt.h>
> +#include <linux/list.h>
>  #include <linux/module.h>
> +#include <linux/ptrace.h>
> +#include <linux/slab.h>
> +#include <linux/wait.h>
> +#include <linux/mm.h>
> +#include <linux/io.h>
> +#include <linux/mutex.h>
> +#include <linux/device.h>
>  
> -#include <asm/io.h>
>  #include <asm/spu.h>
>  #include <asm/spu_priv1.h>
> +#include <asm/firmware.h>
> +#include <asm/prom.h>
>  
>  #include "interrupt.h"
>  
> +struct platform_data {
> +	int nid;
> +	struct device_node *devnode;
> +	struct spu_priv1 __iomem *priv1;
> +};
> +
> +static struct platform_data *platform_data(struct spu *spu)
> +{
> +	BUG_ON(!spu->platform_data);
> +	return (struct platform_data*)spu->platform_data;
> +}
> +
> +static int __init find_spu_node_id(struct device_node *spe)
> +{
> +	const unsigned int *id;
> +	struct device_node *cpu;
> +	cpu = spe->parent->parent;
> +	id = get_property(cpu, "node-id", NULL);
> +	return id ? *id : 0;
> +}
> +
> +static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
> +		const char *prop)
> +{
> +	static DEFINE_MUTEX(add_spumem_mutex);
> +
> +	const struct address_prop {
> +		unsigned long address;
> +		unsigned int len;
> +	} __attribute__((packed)) *p;
> +	int proplen;
> +
> +	unsigned long start_pfn, nr_pages;
> +	struct pglist_data *pgdata;
> +	struct zone *zone;
> +	int ret;
> +
> +	p = get_property(spe, prop, &proplen);
> +	WARN_ON(proplen != sizeof (*p));
> +
> +	start_pfn = p->address >> PAGE_SHIFT;
> +	nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
> +
> +	pgdata = NODE_DATA(spu->nid);
> +	zone = pgdata->node_zones;
> +
> +	/* XXX rethink locking here */
> +	mutex_lock(&add_spumem_mutex);
> +	ret = __add_pages(zone, start_pfn, nr_pages);
> +	mutex_unlock(&add_spumem_mutex);
> +
> +	return ret;
> +}
> +
> +static void __iomem * __init map_spe_prop(struct spu *spu,
> +		struct device_node *n, const char *name)
> +{
> +	const struct address_prop {
> +		unsigned long address;
> +		unsigned int len;
> +	} __attribute__((packed)) *prop;
> +
> +	const void *p;
> +	int proplen;
> +	void __iomem *ret = NULL;
> +	int err = 0;
> +
> +	p = get_property(n, name, &proplen);
> +	if (proplen != sizeof (struct address_prop))
> +		return NULL;
> +
> +	prop = p;
> +
> +	err = cell_spuprop_present(spu, n, name);
> +	if (err && (err != -EEXIST))
> +		goto out;
> +
> +	ret = ioremap(prop->address, prop->len);
> +
> + out:
> +	return ret;
> +}
> +
> +static void spu_unmap(struct spu *spu)
> +{
> +	iounmap(spu->priv2);
> +	iounmap(platform_data(spu)->priv1);
> +	iounmap(spu->problem);
> +	iounmap((__force u8 __iomem *)spu->local_store);
> +}
> +
> +static int __init spu_map_interrupts_old(struct spu *spu,
> +	struct device_node *np)
> +{
> +	unsigned int isrc;
> +	const u32 *tmp;
> +
> +	/* Get the interrupt source unit from the device-tree */
> +	tmp = get_property(np, "isrc", NULL);
> +	if (!tmp)
> +		return -ENODEV;
> +	isrc = tmp[0];
> +
> +	/* Add the node number */
> +	isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
> +
> +	/* Now map interrupts of all 3 classes */
> +	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
> +	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
> +	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
> +
> +	/* Right now, we only fail if class 2 failed */
> +	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
> +}
> +
> +static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
> +{
> +	const char *prop;
> +	int ret;
> +
> +	ret = -ENODEV;
> +	spu->name = get_property(node, "name", NULL);
> +	if (!spu->name)
> +		goto out;
> +
> +	prop = get_property(node, "local-store", NULL);
> +	if (!prop)
> +		goto out;
> +	spu->local_store_phys = *(unsigned long *)prop;
> +
> +	/* we use local store as ram, not io memory */
> +	spu->local_store = (void __force *)
> +		map_spe_prop(spu, node, "local-store");
> +	if (!spu->local_store)
> +		goto out;
> +
> +	prop = get_property(node, "problem", NULL);
> +	if (!prop)
> +		goto out_unmap;
> +	spu->problem_phys = *(unsigned long *)prop;
> +
> +	spu->problem= map_spe_prop(spu, node, "problem");
> +	if (!spu->problem)
> +		goto out_unmap;
> +
> +	platform_data(spu)->priv1= map_spe_prop(spu, node, "priv1");
> +
> +	spu->priv2= map_spe_prop(spu, node, "priv2");
> +	if (!spu->priv2)
> +		goto out_unmap;
> +	ret = 0;
> +	goto out;
> +
> +out_unmap:
> +	spu_unmap(spu);
> +out:
> +	return ret;
> +}
> +
> +static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
> +{
> +	struct of_irq oirq;
> +	int ret;
> +	int i;
> +
> +	for (i=0; i < 3; i++) {
> +		ret = of_irq_map_one(np, i, &oirq);
> +		if (ret)
> +			goto err;
> +
> +		ret = -EINVAL;
> +		spu->irqs[i] = irq_create_of_mapping(oirq.controller,
> +					oirq.specifier, oirq.size);
> +		if (spu->irqs[i] == NO_IRQ)
> +			goto err;
> +	}
> +	return 0;
> +
> +err:
> +	pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier,
> +		spu->name);
> +	for (; i >= 0; i--) {
> +		if (spu->irqs[i] != NO_IRQ)
> +			irq_dispose_mapping(spu->irqs[i]);
> +	}
> +	return ret;
> +}
> +
> +static int spu_map_resource(struct device_node *node, int nr,
> +		void __iomem** virt, unsigned long *phys)
> +{
> +	struct resource resource = { };
> +	int ret;
> +
> +	ret = of_address_to_resource(node, 0, &resource);
> +	if (ret)
> +		goto out;
> +
> +	if (phys)
> +		*phys = resource.start;
> +	*virt = ioremap(resource.start, resource.end - resource.start);
> +	if (!*virt)
> +		ret = -EINVAL;
> +
> +out:
> +	return ret;
> +}
> +
> +static int __init spu_map_device(struct spu *spu, struct device_node *node)
> +{
> +	int ret = -ENODEV;
> +	spu->name = get_property(node, "name", NULL);
> +	if (!spu->name)
> +		goto out;
> +
> +	ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
> +					&spu->local_store_phys);
> +	if (ret)
> +		goto out;
> +	ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
> +					&spu->problem_phys);
> +	if (ret)
> +		goto out_unmap;
> +	ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
> +					NULL);
> +	if (ret)
> +		goto out_unmap;
> +
> +	if (!firmware_has_feature(FW_FEATURE_LPAR))
> +		ret = spu_map_resource(node, 3,
> +			(void __iomem**)&platform_data(spu)->priv1, NULL);
> +	if (ret)
> +		goto out_unmap;
> +	return 0;
> +
> +out_unmap:
> +	spu_unmap(spu);
> +out:
> +	pr_debug("failed to map spe %s: %d\n", spu->name, ret);
> +	return ret;
> +}
> +
> +static int __init of_create_spu(struct spu *spu, void *data)
> +{
> +	int ret;
> +	struct device_node *spe = (struct device_node *)data;
> +
> +	spu->platform_data = kzalloc(sizeof(struct platform_data),
> +		GFP_KERNEL);
> +	if (!spu->platform_data) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	spu->node = find_spu_node_id(spe);
> +	if (spu->node >= MAX_NUMNODES) {
> +		printk(KERN_WARNING "SPE %s on node %d ignored,"
> +		       " node number too big\n", spe->full_name, spu->node);
> +		printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
> +		ret = -ENODEV;
> +		goto out_free;
> +	}
> +
> +	platform_data(spu)->nid = of_node_to_nid(spe);
> +	if (platform_data(spu)->nid == -1)
> +		platform_data(spu)->nid = 0;
> +
> +	ret = spu_map_device(spu, spe);
> +	/* try old method */
> +	if (ret)
> +		ret = spu_map_device_old(spu, spe);
> +	if (ret)
> +		goto out_free;
> +
> +	ret = spu_map_interrupts(spu, spe);
> +	if (ret)
> +		ret = spu_map_interrupts_old(spu, spe);
> +	if (ret)
> +		goto out_unmap;
> +
> +	platform_data(spu)->devnode = of_node_get(spe);
> +
> +	pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n", spu->name,
> +		spu->local_store, spu->problem, platform_data(spu)->priv1,
> +		spu->priv2, spu->number);
> +	goto out;
> +
> +out_unmap:
> +	spu_unmap(spu);
> +out_free:
> +	kfree(spu->platform_data);
> +	spu->platform_data = NULL;
> +out:
> +	return ret;
> +}
> +
> +static int of_destroy_spu(struct spu *spu)
> +{
> +	spu_unmap(spu);
> +	of_node_put(platform_data(spu)->devnode);
> +	kfree(spu->platform_data);
> +	spu->platform_data = NULL;
> +	return 0;
> +}
> +
> +static int __init of_enumerate_spus(int (*fn)(void *data))
> +{
> +	int ret;
> +	struct device_node *node;
> +
> +	ret = -ENODEV;
> +	for (node = of_find_node_by_type(NULL, "spe");
> +			node; node = of_find_node_by_type(node, "spe")) {
> +		ret = fn(node);
> +		if (ret) {
> +			printk(KERN_WARNING "%s: Error initializing %s\n",
> +				__FUNCTION__, node->name);
> +			break;
> +		}
> +	}
> +	return ret;
> +}
> +
> +const struct spu_management_ops spu_management_of_ops = {
> +	.enumerate_spus = of_enumerate_spus,
> +	.create_spu = of_create_spu,
> +	.destroy_spu = of_destroy_spu,
> +};
> +
>  static void int_mask_and(struct spu *spu, int class, u64 mask)
>  {
>  	u64 old_mask;
>  
> -	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
> -	out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
> +	old_mask = in_be64(&platform_data(spu)->priv1->int_mask_RW[class]);
> +	out_be64(&platform_data(spu)->priv1->int_mask_RW[class],
> +		old_mask & mask);
>  }
>  
>  static void int_mask_or(struct spu *spu, int class, u64 mask)
>  {
>  	u64 old_mask;
>  
> -	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
> -	out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
> +	old_mask = in_be64(&platform_data(spu)->priv1->int_mask_RW[class]);
> +	out_be64(&platform_data(spu)->priv1->int_mask_RW[class],
> +		old_mask | mask);
>  }
>  
>  static void int_mask_set(struct spu *spu, int class, u64 mask)
>  {
> -	out_be64(&spu->priv1->int_mask_RW[class], mask);
> +	out_be64(&platform_data(spu)->priv1->int_mask_RW[class], mask);
>  }
>  
>  static u64 int_mask_get(struct spu *spu, int class)
>  {
> -	return in_be64(&spu->priv1->int_mask_RW[class]);
> +	return in_be64(&platform_data(spu)->priv1->int_mask_RW[class]);
>  }
>  
>  static void int_stat_clear(struct spu *spu, int class, u64 stat)
>  {
> -	out_be64(&spu->priv1->int_stat_RW[class], stat);
> +	out_be64(&platform_data(spu)->priv1->int_stat_RW[class], stat);
>  }
>  
>  static u64 int_stat_get(struct spu *spu, int class)
>  {
> -	return in_be64(&spu->priv1->int_stat_RW[class]);
> +	return in_be64(&platform_data(spu)->priv1->int_stat_RW[class]);
>  }
>  
>  static void cpu_affinity_set(struct spu *spu, int cpu)
>  {
>  	u64 target = iic_get_target_id(cpu);
>  	u64 route = target << 48 | target << 32 | target << 16;
> -	out_be64(&spu->priv1->int_route_RW, route);
> +	out_be64(&platform_data(spu)->priv1->int_route_RW, route);
>  }
>  
>  static u64 mfc_dar_get(struct spu *spu)
>  {
> -	return in_be64(&spu->priv1->mfc_dar_RW);
> +	return in_be64(&platform_data(spu)->priv1->mfc_dar_RW);
>  }
>  
>  static u64 mfc_dsisr_get(struct spu *spu)
>  {
> -	return in_be64(&spu->priv1->mfc_dsisr_RW);
> +	return in_be64(&platform_data(spu)->priv1->mfc_dsisr_RW);
>  }
>  
>  static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
>  {
> -	out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
> +	out_be64(&platform_data(spu)->priv1->mfc_dsisr_RW, dsisr);
>  }
>  
>  static void mfc_sdr_setup(struct spu *spu)
>  {
> -	out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
> +	out_be64(&platform_data(spu)->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
>  }
>  
>  static void mfc_sr1_set(struct spu *spu, u64 sr1)
>  {
> -	out_be64(&spu->priv1->mfc_sr1_RW, sr1);
> +	out_be64(&platform_data(spu)->priv1->mfc_sr1_RW, sr1);
>  }
>  
>  static u64 mfc_sr1_get(struct spu *spu)
>  {
> -	return in_be64(&spu->priv1->mfc_sr1_RW);
> +	return in_be64(&platform_data(spu)->priv1->mfc_sr1_RW);
>  }
>  
>  static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
>  {
> -	out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
> +	out_be64(&platform_data(spu)->priv1->mfc_tclass_id_RW, tclass_id);
>  }
>  
>  static u64 mfc_tclass_id_get(struct spu *spu)
>  {
> -	return in_be64(&spu->priv1->mfc_tclass_id_RW);
> +	return in_be64(&platform_data(spu)->priv1->mfc_tclass_id_RW);
>  }
>  
>  static void tlb_invalidate(struct spu *spu)
>  {
> -	out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
> +	out_be64(&platform_data(spu)->priv1->tlb_invalidate_entry_W, 0ul);
>  }
>  
>  static void resource_allocation_groupID_set(struct spu *spu, u64 id)
>  {
> -	out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
> +	out_be64(&platform_data(spu)->priv1->resource_allocation_groupID_RW,
> +		id);
>  }
>  
>  static u64 resource_allocation_groupID_get(struct spu *spu)
>  {
> -	return in_be64(&spu->priv1->resource_allocation_groupID_RW);
> +	return in_be64(
> +		&platform_data(spu)->priv1->resource_allocation_groupID_RW);
>  }
>  
>  static void resource_allocation_enable_set(struct spu *spu, u64 enable)
>  {
> -	out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
> +	out_be64(&platform_data(spu)->priv1->resource_allocation_enable_RW,
> +		enable);
>  }
>  
>  static u64 resource_allocation_enable_get(struct spu *spu)
>  {
> -	return in_be64(&spu->priv1->resource_allocation_enable_RW);
> +	return in_be64(
> +		&platform_data(spu)->priv1->resource_allocation_enable_RW);
>  }
>  
>  const struct spu_priv1_ops spu_priv1_mmio_ops =
> Index: cell--common--6/include/asm-powerpc/spu.h
> ===================================================================
> --- cell--common--6.orig/include/asm-powerpc/spu.h
> +++ cell--common--6/include/asm-powerpc/spu.h
> @@ -111,13 +111,11 @@
>  	u8 *local_store;
>  	unsigned long problem_phys;
>  	struct spu_problem __iomem *problem;
> -	struct spu_priv1 __iomem *priv1;
>  	struct spu_priv2 __iomem *priv2;
>  	struct list_head list;
>  	struct list_head sched_list;
>  	struct list_head full_list;
>  	int number;
> -	int nid;
>  	unsigned int irqs[3];
>  	u32 node;
>  	u64 flags;
> @@ -144,8 +142,7 @@
>  	char irq_c1[8];
>  	char irq_c2[8];
>  
> -	struct device_node *devnode;
> -
> +	void* platform_data;
>  	struct sys_device sysdev;
>  };
>  
> Index: cell--common--6/include/asm-powerpc/spu_priv1.h
> ===================================================================
> --- cell--common--6.orig/include/asm-powerpc/spu_priv1.h
> +++ cell--common--6/include/asm-powerpc/spu_priv1.h
> @@ -21,12 +21,13 @@
>  #define _SPU_PRIV1_H
>  #if defined(__KERNEL__)
>  
> +#include <linux/types.h>
> +
>  struct spu;
>  
>  /* access to priv1 registers */
>  
> -struct spu_priv1_ops
> -{
> +struct spu_priv1_ops {
>  	void (*int_mask_and) (struct spu *spu, int class, u64 mask);
>  	void (*int_mask_or) (struct spu *spu, int class, u64 mask);
>  	void (*int_mask_set) (struct spu *spu, int class, u64 mask);
> @@ -171,12 +172,41 @@
>  	return spu_priv1_ops->resource_allocation_enable_get(spu);
>  }
>  
> -/* The declarations folowing are put here for convenience
> - * and only intended to be used by the platform setup code
> - * for initializing spu_priv1_ops.
> +/* spu management abstraction */
> +
> +struct spu_management_ops {
> +	int (*enumerate_spus)(int (*fn)(void *data));
> +	int (*create_spu)(struct spu *spu, void *data);
> +	int (*destroy_spu)(struct spu *spu);
> +};
> +
> +extern const struct spu_management_ops* spu_management_ops;
> +
> +static inline int
> +spu_enumerate_spus (int (*fn)(void *data))
> +{
> +	return spu_management_ops->enumerate_spus(fn);
> +}
> +
> +static inline int
> +spu_create_spu (struct spu *spu, void *data)
> +{
> +	return spu_management_ops->create_spu(spu, data);
> +}
> +
> +static inline int
> +spu_destroy_spu (struct spu *spu)
> +{
> +	return spu_management_ops->destroy_spu(spu);
> +}
> +
> +/*
> + * The declarations folowing are put here for convenience
> + * and only intended to be used by the platform setup code.
>   */
>  
>  extern const struct spu_priv1_ops spu_priv1_mmio_ops;
> +extern const struct spu_management_ops spu_management_of_ops;
>  
>  #endif /* __KERNEL__ */
>  #endif
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH] cell: abstract spu management routines
From: Benjamin Herrenschmidt @ 2006-11-08  5:35 UTC (permalink / raw)
  To: michael; +Cc: linuxppc-dev, Arnd Bergmann, cbe-oss-dev
In-Reply-To: <1162962074.20271.16.camel@localhost.localdomain>


> > +struct platform_data {
> > +	int nid;
> > +	struct device_node *devnode;
> > +	struct spu_priv1 __iomem *priv1;
> > +};
> > +
> > +static struct platform_data *platform_data(struct spu *spu)
> > +{
> > +	BUG_ON(!spu->platform_data);
> > +	return (struct platform_data*)spu->platform_data;
> > +}
> 
> I don't see the point of this, why not just grab platform data directly?

Because it's a void * in the struct spu. This accessor casts it and BUGS
if it's not set (which is probably unnecessary).

I'd prefer however a different naming:

struct spu_pdata {
	blah
};

static struct spu_pdata *spu_get_pdata(struct spu *spu)

Either that, or you could just do something like that in spu.h :

struct spu_pdata;

struct spu
{
	.../...
	struct spu_pdata *pdata;
	../...
};

And have the various priv1 implementation define their own struct
spu_pdata. A bit sneaky but provides strong typing without needing an
accessor.

Ben.

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH] cell: abstract spu management routines
From: Michael Ellerman @ 2006-11-08  5:54 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <45516A0C.5050607@am.sony.com>

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

On Tue, 2006-11-07 at 21:24 -0800, Geoff Levand wrote:
> Michael Ellerman wrote:
> >> +static struct platform_data *platform_data(struct spu *spu)
> >> +{
> >> +	BUG_ON(!spu->platform_data);
> >> +	return (struct platform_data*)spu->platform_data;
> >> +}
> > 
> > I don't see the point of this, why not just grab platform data directly?
> 
> Well, first, it does a check, and second, you can't just grab platform_data,
> you need to always do the cast also. So then, is something like
> '((struct platform_data*)spu->platform_data)->' preferred over
> 'platform_data(spu)->'?

Yeah OK I missed the cast, I guess it's worth it then. In that case can
you change the names? Having the struct, the member and the accessor all
named the same is a bit confusing.

The BUG() is pretty superfluous, you're just preempting the NULL deref
by 1 instruction.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

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

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

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

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH] cell: abstract spu management routines
From: Geoff Levand @ 2006-11-08  6:03 UTC (permalink / raw)
  To: michael; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <1162965270.20271.22.camel@localhost.localdomain>

Michael Ellerman wrote:
> On Tue, 2006-11-07 at 21:24 -0800, Geoff Levand wrote:
>> Michael Ellerman wrote:
>> >> +static struct platform_data *platform_data(struct spu *spu)
>> >> +{
>> >> +	BUG_ON(!spu->platform_data);
>> >> +	return (struct platform_data*)spu->platform_data;
>> >> +}
>> > 
>> > I don't see the point of this, why not just grab platform data directly?
>> 
>> Well, first, it does a check, and second, you can't just grab platform_data,
>> you need to always do the cast also. So then, is something like
>> '((struct platform_data*)spu->platform_data)->' preferred over
>> 'platform_data(spu)->'?
> 
> Yeah OK I missed the cast, I guess it's worth it then. In that case can
> you change the names? Having the struct, the member and the accessor all
> named the same is a bit confusing.
> 
> The BUG() is pretty superfluous, you're just preempting the NULL deref
> by 1 instruction.

OK, I'll do the name changes as Ben suggested.  Actually, that BUG check was
just a stale leftover from when I was getting things working :)

-Geoff

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH] cell: abstract spu management routines
From: Michael Ellerman @ 2006-11-08  6:06 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <45517325.3090808@am.sony.com>

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

On Tue, 2006-11-07 at 22:03 -0800, Geoff Levand wrote:
> Michael Ellerman wrote:
> > On Tue, 2006-11-07 at 21:24 -0800, Geoff Levand wrote:
> >> Michael Ellerman wrote:
> >> >> +static struct platform_data *platform_data(struct spu *spu)
> >> >> +{
> >> >> +	BUG_ON(!spu->platform_data);
> >> >> +	return (struct platform_data*)spu->platform_data;
> >> >> +}
> >> > 
> >> > I don't see the point of this, why not just grab platform data directly?
> >> 
> >> Well, first, it does a check, and second, you can't just grab platform_data,
> >> you need to always do the cast also. So then, is something like
> >> '((struct platform_data*)spu->platform_data)->' preferred over
> >> 'platform_data(spu)->'?
> > 
> > Yeah OK I missed the cast, I guess it's worth it then. In that case can
> > you change the names? Having the struct, the member and the accessor all
> > named the same is a bit confusing.
> > 
> > The BUG() is pretty superfluous, you're just preempting the NULL deref
> > by 1 instruction.
> 
> OK, I'll do the name changes as Ben suggested.

Cool, heh sorry to double-team you, I hadn't read Ben's mail :)

> Actually, that BUG check was just a stale leftover from when I was getting things working :)

No worries.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

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

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

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

^ permalink raw reply

* [PATCH] Changed gianfar device tree definition to make it more flexible
From: Andy Fleming @ 2006-11-08  6:08 UTC (permalink / raw)
  To: linuxppc-dev, Paul Mackerras, Kumar Gala

The old gianfar node definition used a concept of "models" to
determine the feature bits and interrupt settings to pass to the
driver.  This won't scale well when the hardware designers come
up with new and (hopefully) interesting variants of the eTSEC.
So one goal of this patch is to prepare for that eventuality by
listing the features, rather than inferring them.

Another goal of this patch is to lay the groundwork for adding
support for different interface types to gianfar.  It does this
by adding another field (interface), which specifies the
interfaces (GMII, RGMII, SGMII, etc).

And then, incidentally, some of the code was cleaned up so that
initialization functions will skip devices which encounter
errors, rather than bailing.  The CPM devices were not modified
in this way, as they are more complex.

Finally, all the dts files with gianfar nodes were updated to use
the new feature bits and the new interface field, and the various
MAC address conventions were all accommodated by preserving the
currently-used field, while adding local-mac-address, which will
be used in the future (once u-boot changes have been made).

Signed-off-by: Andrew Fleming <afleming@freescale.com>
---
 Documentation/powerpc/booting-without-of.txt |   31 ++
 arch/powerpc/boot/dts/mpc8349emds.dts        |   14 +
 arch/powerpc/boot/dts/mpc8349emitx.dts       |   11 +
 arch/powerpc/boot/dts/mpc8540ads.dts         |   24 +-
 arch/powerpc/boot/dts/mpc8541cds.dts         |   16 +
 arch/powerpc/boot/dts/mpc8548cds.dts         |   78 ++++-
 arch/powerpc/boot/dts/mpc8555cds.dts         |   16 +
 arch/powerpc/boot/dts/mpc8560ads.dts         |   18 +
 arch/powerpc/boot/dts/mpc8641_hpcn.dts       |   72 ++++-
 arch/powerpc/sysdev/fsl_soc.c                |  414 +++++++++++++++-----------
 include/linux/fsl_devices.h                  |    8 -
 11 files changed, 496 insertions(+), 206 deletions(-)

diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 27b457c..bb1a402 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1193,6 +1193,7 @@ platforms are moved over to use the flat
 
     - device_type : Should be "network"
     - model : Model of the device.  Can be "TSEC", "eTSEC", or "FEC"
+      (This is deprecated in favor of the feature bits)
     - compatible : Should be "gianfar"
     - reg : Offset and length of the register set for the device
     - mac-address : List of bytes representing the ethernet address of
@@ -1206,6 +1207,30 @@ platforms are moved over to use the flat
       services interrupts for this device.
     - phy-handle : The phandle for the PHY connected to this ethernet
       controller.
+    - interface : The interface this ethernet is using.  Current options are:
+        GMII, MII, RGMII, SGMII, TBI, RMII, and RTBI
+
+  Optional properties (features):
+    - gigabit : Indicates support for 1000 Mbit operation
+    - coalescing : Indicates support for interrupt coalescing
+    - rmon : Indicates support for RMON-style counters
+    - checksumming : Indicates support for hardware TCP/UDP checksumming
+    - vlan-insertion : Indicates support for hardware vlan header insertion
+    - extended-hash : Indicates support for using the Individual
+        Address Hash registers to extend the Group Address Hash registers
+    - padding : Indicates support for padding between the FCB and
+        the frame
+    - filer : Indicates support for the Filer
+    - parseL2 : Indicates support for parsing L2 headers
+    - parseL3 : Indicates support for parsing L3 headers
+    - parseL4 : Indicates support for parsing L4 headers
+    - multi-queue : Indicates support for sending and receiving
+      into multiple queues
+    
+    The "eTSEC" model implements all these features, while the
+    "TSEC" model implements only the first 3.  The "FEC" has none
+    of these features.
+  
 
   Example:
 
@@ -1213,12 +1238,16 @@ platforms are moved over to use the flat
 		#size-cells = <0>;
 		device_type = "network";
 		model = "TSEC";
+		gigabit;
+		coalescing;
+		rmon;
 		compatible = "gianfar";
 		reg = <24000 1000>;
 		mac-address = [ 00 E0 0C 00 73 00 ];
 		interrupts = <d 3 e 3 12 3>;
 		interrupt-parent = <40000>;
 		phy-handle = <2452000>
+		interface = "GMII";
 	};
 
 
@@ -1238,6 +1267,7 @@ platforms are moved over to use the flat
     - reg : The ID number for the phy, usually a small integer
     - linux,phandle :  phandle for this node; likely referenced by an
       ethernet controller node.
+    - flags : PHY-specific flags (defined by the device driver)
 
 
    Example:
@@ -1246,6 +1276,7 @@ platforms are moved over to use the flat
 		linux,phandle = <2452000>
 		interrupt-parent = <40000>;
 		interrupts = <35 1>;
+		flags = <0>;
 		reg = <0>;
 		device_type = "ethernet-phy";
 	};
diff --git a/arch/powerpc/boot/dts/mpc8349emds.dts b/arch/powerpc/boot/dts/mpc8349emds.dts
index efceb34..f6ae4e2 100644
--- a/arch/powerpc/boot/dts/mpc8349emds.dts
+++ b/arch/powerpc/boot/dts/mpc8349emds.dts
@@ -117,6 +117,7 @@
 				linux,phandle = <2452000>;
 				interrupt-parent = <700>;
 				interrupts = <11 2>;
+				flags = <0>;
 				reg = <0>;
 				device_type = "ethernet-phy";
 			};
@@ -124,6 +125,7 @@
 				linux,phandle = <2452001>;
 				interrupt-parent = <700>;
 				interrupts = <12 2>;
+				flags = <0>;
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
@@ -132,13 +134,17 @@
 		ethernet@24000 {
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			address = [ 00 00 00 00 00 00 ];
 			local-mac-address = [ 00 00 00 00 00 00 ];
+			address = [ 00 00 00 00 00 00 ];
 			interrupts = <20 8 21 8 22 8>;
 			interrupt-parent = <700>;
 			phy-handle = <2452000>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
@@ -146,13 +152,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <25000 1000>;
-			address = [ 00 00 00 00 00 00 ];
 			local-mac-address = [ 00 00 00 00 00 00 ];
+			address = [ 00 00 00 00 00 00 ];
 			interrupts = <23 8 24 8 25 8>;
 			interrupt-parent = <700>;
 			phy-handle = <2452001>;
+			interface = "GMII";
 		};
 
 		serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 27807fc..0d3ce51 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -116,6 +116,7 @@
 				linux,phandle = <245201c>;
 				interrupt-parent = <700>;
 				interrupts = <12 2>;
+				flags = <0>;
 				reg = <1c>;
 				device_type = "ethernet-phy";
 			};
@@ -125,6 +126,7 @@
 				linux,phandle = <245201f>;
 				interrupt-parent = <700>;
 				interrupts = <12 2>;
+				flags = <0>;
 				reg = <1f>;
 				device_type = "ethernet-phy";
 			};
@@ -133,13 +135,17 @@
 		ethernet@24000 {
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			address = [ 00 00 00 00 00 00 ];
 			local-mac-address = [ 00 00 00 00 00 00 ];
+			address = [ 00 00 00 00 00 00 ];
 			interrupts = <20 8 21 8 22 8>;
 			interrupt-parent = <700>;
 			phy-handle = <245201c>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
@@ -147,6 +153,9 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <25000 1000>;
 			address = [ 00 00 00 00 00 00 ];
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index 5f41c1f..53e187d 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -73,6 +73,7 @@
 				linux,phandle = <2452000>;
 				interrupt-parent = <40000>;
 				interrupts = <35 1>;
+				flags = <0>;
 				reg = <0>;
 				device_type = "ethernet-phy";
 			};
@@ -80,6 +81,7 @@
 				linux,phandle = <2452001>;
 				interrupt-parent = <40000>;
 				interrupts = <35 1>;
+				flags = <0>;
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
@@ -87,6 +89,7 @@
 				linux,phandle = <2452003>;
 				interrupt-parent = <40000>;
 				interrupts = <37 1>;
+				flags = <0>;
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
@@ -97,13 +100,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			address = [ 00 E0 0C 00 73 00 ];
-			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <d 2 e 2 12 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452000>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
@@ -111,13 +118,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <25000 1000>;
-			address = [ 00 E0 0C 00 73 01 ];
-			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <13 2 14 2 18 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452001>;
+			interface = "GMII";
 		};
 
 		ethernet@26000 {
@@ -127,11 +138,12 @@
 			model = "FEC";
 			compatible = "gianfar";
 			reg = <26000 1000>;
-			address = [ 00 E0 0C 00 73 02 ];
-			local-mac-address = [ 00 E0 0C 00 73 02 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <19 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452003>;
+			interface = "MII";
 		};
 
 		serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 7be0bc6..4191621 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -73,6 +73,7 @@
 				linux,phandle = <2452000>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <0>;
 				device_type = "ethernet-phy";
 			};
@@ -80,6 +81,7 @@
 				linux,phandle = <2452001>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
@@ -90,12 +92,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <d 2 e 2 12 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452000>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
@@ -103,12 +110,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <25000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <13 2 14 2 18 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452001>;
+			interface = "GMII";
 		};
 
 		serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index 893d795..83451c4 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -1,5 +1,5 @@
 /*
- * MPC8555 CDS Device Tree Source
+ * MPC8548 CDS Device Tree Source
  *
  * Copyright 2006 Freescale Semiconductor Inc.
  *
@@ -73,6 +73,7 @@
 				linux,phandle = <2452000>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <0>;
 				device_type = "ethernet-phy";
 			};
@@ -80,6 +81,7 @@
 				linux,phandle = <2452001>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
@@ -88,6 +90,7 @@
 				linux,phandle = <2452002>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <2>;
 				device_type = "ethernet-phy";
 			};
@@ -95,6 +98,7 @@
 				linux,phandle = <2452003>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
@@ -105,12 +109,26 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <d 2 e 2 12 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452000>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
@@ -118,41 +136,83 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <25000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <13 2 14 2 18 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452001>;
+			interface = "GMII";
 		};
+	/* eTSEC3 and eTSEC4 don't work on older CDS boards
 
 		ethernet@26000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "network";
 			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <26000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 02 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <f 2 10 2 11 2>;
 			interrupt-parent = <40000>;
-			phy-handle = <2452001>;
+			phy-handle = <2452002>;
+			interface = "RGMII";
 		};
 
-/* eTSEC 4 is currently broken
 		ethernet@27000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "network";
 			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <27000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 03 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <15 2 16 2 17 2>;
 			interrupt-parent = <40000>;
-			phy-handle = <2452001>;
+			phy-handle = <2452003>;
+			interface = "RGMII";
 		};
- */
+	*/
 
 		serial@4500 {
 			device_type = "serial";
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index 118f5a8..c559aab 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -73,6 +73,7 @@
 				linux,phandle = <2452000>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <0>;
 				device_type = "ethernet-phy";
 			};
@@ -80,6 +81,7 @@
 				linux,phandle = <2452001>;
 				interrupt-parent = <40000>;
 				interrupts = <35 0>;
+				flags = <0>;
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
@@ -90,12 +92,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <0d 2 0e 2 12 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452000>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
@@ -103,12 +110,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <25000 1000>;
-			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <13 2 14 2 18 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452001>;
+			interface = "GMII";
 		};
 
 		serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 2b16848..1b73392 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -65,6 +65,7 @@
 				linux,phandle = <2452000>;
 				interrupt-parent = <40000>;
 				interrupts = <35 1>;
+				flags = <0>;
 				reg = <0>;
 				device_type = "ethernet-phy";
 			};
@@ -72,6 +73,7 @@
 				linux,phandle = <2452001>;
 				interrupt-parent = <40000>;
 				interrupts = <35 1>;
+				flags = <0>;
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
@@ -79,6 +81,7 @@
 				linux,phandle = <2452002>;
 				interrupt-parent = <40000>;
 				interrupts = <37 1>;
+				flags = <0>;
 				reg = <2>;
 				device_type = "ethernet-phy";
 			};
@@ -86,6 +89,7 @@
 				linux,phandle = <2452003>;
 				interrupt-parent = <40000>;
 				interrupts = <37 1>;
+				flags = <0>;
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
@@ -94,12 +98,17 @@
 		ethernet@24000 {
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			address = [ 00 00 0C 00 00 FD ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <d 2 e 2 12 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452000>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
@@ -107,12 +116,17 @@
 			#size-cells = <0>;
 			device_type = "network";
 			model = "TSEC";
+			gigabit;
+			coalescing;
+			rmon;
 			compatible = "gianfar";
 			reg = <25000 1000>;
-			address = [ 00 00 0C 00 01 FD ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <13 2 14 2 18 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452001>;
+			interface = "GMII";
 		};
 
 		pci@8000 {
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index f0c7731..0fc46fa 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -91,6 +91,7 @@
 				linux,phandle = <2452000>;
 				interrupt-parent = <40000>;
 				interrupts = <4a 1>;
+				flags = <0>;
 				reg = <0>;
 				device_type = "ethernet-phy";
 			};
@@ -98,6 +99,7 @@
 				linux,phandle = <2452001>;
 				interrupt-parent = <40000>;
 				interrupts = <4a 1>;
+				flags = <0>;
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
@@ -105,6 +107,7 @@
 				linux,phandle = <2452002>;
 				interrupt-parent = <40000>;
 				interrupts = <4a 1>;
+				flags = <0>;
 				reg = <2>;
 				device_type = "ethernet-phy";
 			};
@@ -112,6 +115,7 @@
 				linux,phandle = <2452003>;
 				interrupt-parent = <40000>;
 				interrupts = <4a 1>;
+				flags = <0>;
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
@@ -121,52 +125,104 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "network";
-			model = "TSEC";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <24000 1000>;
-			mac-address = [ 00 E0 0C 00 73 00 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <1d 2 1e 2 22 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452000>;
+			interface = "GMII";
 		};
 
 		ethernet@25000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "network";
-			model = "TSEC";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <25000 1000>;
-			mac-address = [ 00 E0 0C 00 73 01 ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <23 2 24 2 28 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452001>;
+			interface = "GMII";
 		};
 		
 		ethernet@26000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "network";
-			model = "TSEC";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <26000 1000>;
-			mac-address = [ 00 E0 0C 00 02 FD ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <1F 2 20 2 21 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452002>;
+			interface = "GMII";
 		};
 
 		ethernet@27000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "network";
-			model = "TSEC";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			vlan;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
 			compatible = "gianfar";
 			reg = <27000 1000>;
-			mac-address = [ 00 E0 0C 00 03 FD ];
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <25 2 26 2 27 2>;
 			interrupt-parent = <40000>;
 			phy-handle = <2452003>;
+			interface = "GMII";
 		};
 		serial@4500 {
 			device_type = "serial";
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index ad31e56..c827c04 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -6,6 +6,9 @@
  * 2006 (c) MontaVista Software, Inc.
  * Vitaly Bordug <vbordug@ru.mvista.com>
  *
+ * 2006 (c) Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
@@ -178,58 +181,169 @@ static const char *gfar_tx_intr = "tx";
 static const char *gfar_rx_intr = "rx";
 static const char *gfar_err_intr = "error";
 
+/* Returns a bitfield with the appropriate flasgs set,
+ * based on the device tree */
+static int __init gfar_get_flags(struct device_node *np)
+{
+	int device_flags = 0;
+
+	if (get_property(np, "gigabit", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT;
+
+	if (get_property(np, "coalescing", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_COALESCE;
+
+	if (get_property(np, "rmon", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_RMON;
+
+	if (get_property(np, "checksumming", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_CSUM;
+
+	if (get_property(np, "vlan", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_VLAN;
+
+	if (get_property(np, "extended-hash", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+
+	if (get_property(np, "padding", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_PADDING;
+
+	if (get_property(np, "filer", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_FILER;
+
+	if (get_property(np, "parseL4", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_PARSE_L4;
+
+	if (get_property(np, "parseL3", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_PARSE_L3;
+
+	if (get_property(np, "parseL2", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_PARSE_L2;
+
+	if (get_property(np, "multi-queue", NULL) != NULL)
+		device_flags |= FSL_GIANFAR_DEV_HAS_MULTI_QUEUE;
+
+	return device_flags;
+}
+
+static struct device_node * __init gfar_get_phy_node(struct device_node *np)
+{
+	const phandle *ph;
+	struct device_node *phy;
+
+	ph = get_property(np, "phy-handle", NULL);
+	if (ph == NULL)
+		return NULL;
+
+	phy = of_find_node_by_phandle(*ph);
+
+	return phy;
+}
+
+/* Set the phy_id field of gfar_data to the address of the PHY
+ * Set the bus_id field of gfar_data to the memory address of the mdio bus
+ * Set the phy_flags field of gfar_data to passed in values
+ *
+ * returns 0 on success
+ */
+static int __init gfar_set_phy_info(struct device_node *np,
+		int *phy_id, int *bus_id, int *phy_flags)
+{
+	struct resource res;
+	struct device_node *phy;
+	struct device_node *mdio;
+	const unsigned int *id;
+	const unsigned int *flags;
+	int ret;
+
+	phy = gfar_get_phy_node(np);
+	if (phy == NULL)
+		return -1;
+
+	/* Get the PHY address, the parent MDIO bus,
+	 * and the phy flags, then release the phy node */
+	id = get_property(phy, "reg", NULL);
+	flags = get_property(phy, "flags", NULL);
+	mdio = of_get_parent(phy);
+
+	/* We're done with the phy node, now */
+	of_node_put(phy);
+
+	/* Set the PHY address */
+	if (id == NULL)
+		return -1;
+
+	*phy_id = *id;
+
+	/* Set the flags */
+	if (flags == NULL)
+		return -1;
+
+	*phy_flags = *flags;
+
+	/* Set the bus id */
+	if (mdio == NULL)
+		return -1;
+
+	ret = of_address_to_resource(mdio, 0, &res);
+	of_node_put(mdio);
+	if (ret)
+		return -1;
+
+	*bus_id = res.start;
 
+	return 0;
+}
+  
 static int __init gfar_of_init(void)
 {
 	struct device_node *np;
-	unsigned int i;
+	unsigned int num;
 	struct platform_device *gfar_dev;
-	struct resource res;
 	int ret;
 
-	for (np = NULL, i = 0;
+	for (np = NULL, num = 0;
 	     (np = of_find_compatible_node(np, "network", "gianfar")) != NULL;
-	     i++) {
+	     num++) {
 		struct resource r[4];
-		struct device_node *phy, *mdio;
 		struct gianfar_platform_data gfar_data;
-		const unsigned int *id;
-		const char *model;
 		const void *mac_addr;
-		const phandle *ph;
-		int n_res = 2;
+		int n_res = 0;
 
 		memset(r, 0, sizeof(r));
 		memset(&gfar_data, 0, sizeof(gfar_data));
 
 		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
+		if (ret) {
+			printk("gfar %d's address lookup failed\n", num);
+			continue;
+		}
 
-		of_irq_to_resource(np, 0, &r[1]);
+		gfar_data.device_flags = gfar_get_flags(np);
 
-		model = get_property(np, "model", NULL);
+		/* Map all the irq resources, and set n_res to
+		 * the number of irqs plus 1 (which is the total
+		 * number of resources) */
+		while (n_res < 4 &&
+			of_irq_to_resource(np, n_res, &r[++n_res]) != NO_IRQ);
+		if (n_res < 2) {
+			printk("No interrupts found for gfar %d\n", num);
+			continue;
+		}
 
-		/* If we aren't the FEC we have multiple interrupts */
-		if (model && strcasecmp(model, "FEC")) {
+		/* If we have 3 interrupts, name them, and set the flag */
+		if (n_res == 4) {
 			r[1].name = gfar_tx_intr;
-
 			r[2].name = gfar_rx_intr;
-			of_irq_to_resource(np, 1, &r[2]);
-
 			r[3].name = gfar_err_intr;
-			of_irq_to_resource(np, 2, &r[3]);
 
-			n_res += 2;
-		}
-
-		gfar_dev =
-		    platform_device_register_simple("fsl-gianfar", i, &r[0],
-						    n_res);
-
-		if (IS_ERR(gfar_dev)) {
-			ret = PTR_ERR(gfar_dev);
-			goto err;
+			gfar_data.device_flags |=
+				FSL_GIANFAR_DEV_HAS_MULTI_INTR;
+		} else if (n_res != 2) {
+			printk("gfar %d had an unexpected number"
+					"of interrupts (%d)\n",
+					num, n_res-1);
+			continue;
 		}
 
 		mac_addr = get_property(np, "local-mac-address", NULL);
@@ -243,60 +357,31 @@ static int __init gfar_of_init(void)
 		if (mac_addr)
 			memcpy(gfar_data.mac_addr, mac_addr, 6);
 
-		if (model && !strcasecmp(model, "TSEC"))
-			gfar_data.device_flags =
-			    FSL_GIANFAR_DEV_HAS_GIGABIT |
-			    FSL_GIANFAR_DEV_HAS_COALESCE |
-			    FSL_GIANFAR_DEV_HAS_RMON |
-			    FSL_GIANFAR_DEV_HAS_MULTI_INTR;
-		if (model && !strcasecmp(model, "eTSEC"))
-			gfar_data.device_flags =
-			    FSL_GIANFAR_DEV_HAS_GIGABIT |
-			    FSL_GIANFAR_DEV_HAS_COALESCE |
-			    FSL_GIANFAR_DEV_HAS_RMON |
-			    FSL_GIANFAR_DEV_HAS_MULTI_INTR |
-			    FSL_GIANFAR_DEV_HAS_CSUM |
-			    FSL_GIANFAR_DEV_HAS_VLAN |
-			    FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
-
-		ph = get_property(np, "phy-handle", NULL);
-		phy = of_find_node_by_phandle(*ph);
+		ret = gfar_set_phy_info(np, &gfar_data.phy_id,
+				&gfar_data.bus_id, &gfar_data.phy_flags);
+  		if (ret) {
+			printk("gfar %d failed to set PHY info\n", num);
+			continue;
+  		}
 
-		if (phy == NULL) {
-			ret = -ENODEV;
-			goto unreg;
+		gfar_dev = platform_device_register_simple("fsl-gianfar",
+				num, &r[0], n_res);
+		if (IS_ERR(gfar_dev)) {
+			printk("Failed to register gfar %d due to error %ld\n",
+					num, PTR_ERR(gfar_dev));
+			continue;
 		}
 
-		mdio = of_get_parent(phy);
-
-		id = get_property(phy, "reg", NULL);
-		ret = of_address_to_resource(mdio, 0, &res);
+		ret = platform_device_add_data(gfar_dev, &gfar_data,
+				sizeof(struct gianfar_platform_data));
 		if (ret) {
-			of_node_put(phy);
-			of_node_put(mdio);
-			goto unreg;
+			printk("gfar %d data not added\n", num);
+			platform_device_unregister(gfar_dev);
 		}
-
-		gfar_data.phy_id = *id;
-		gfar_data.bus_id = res.start;
-
-		of_node_put(phy);
-		of_node_put(mdio);
-
-		ret =
-		    platform_device_add_data(gfar_dev, &gfar_data,
-					     sizeof(struct
-						    gianfar_platform_data));
-		if (ret)
-			goto unreg;
 	}
 
 	return 0;
 
-unreg:
-	platform_device_unregister(gfar_dev);
-err:
-	return ret;
 }
 
 arch_initcall(gfar_of_init);
@@ -304,13 +389,13 @@ arch_initcall(gfar_of_init);
 static int __init fsl_i2c_of_init(void)
 {
 	struct device_node *np;
-	unsigned int i;
+	unsigned int num;
 	struct platform_device *i2c_dev;
 	int ret;
 
-	for (np = NULL, i = 0;
+	for (np = NULL, num = 0;
 	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL;
-	     i++) {
+	     num++) {
 		struct resource r[2];
 		struct fsl_i2c_platform_data i2c_data;
 		const unsigned char *flags = NULL;
@@ -319,15 +404,22 @@ static int __init fsl_i2c_of_init(void)
 		memset(&i2c_data, 0, sizeof(i2c_data));
 
 		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
+		if (ret) {
+			printk("i2c %d could not map registers\n", num);
+			continue;
+		}
 
-		of_irq_to_resource(np, 0, &r[1]);
+		ret = of_irq_to_resource(np, 0, &r[1]);
+		if (ret == NO_IRQ) {
+			printk("i2c %d could not map irq\n", num);
+			continue;
+		}
 
-		i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
+		i2c_dev = platform_device_register_simple("fsl-i2c", num, r, 2);
 		if (IS_ERR(i2c_dev)) {
-			ret = PTR_ERR(i2c_dev);
-			goto err;
+			printk("Failed to register i2c %d due to error %ld\n",
+					num, PTR_ERR(i2c_dev));
+			continue;
 		}
 
 		i2c_data.device_flags = 0;
@@ -339,20 +431,15 @@ static int __init fsl_i2c_of_init(void)
 		if (flags)
 			i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
 
-		ret =
-		    platform_device_add_data(i2c_dev, &i2c_data,
-					     sizeof(struct
-						    fsl_i2c_platform_data));
-		if (ret)
-			goto unreg;
+		ret = platform_device_add_data(i2c_dev, &i2c_data,
+				     sizeof(struct fsl_i2c_platform_data));
+		if (ret) {
+			printk("i2c %d data not added\n", num);
+			platform_device_unregister(i2c_dev);
+		}
 	}
 
 	return 0;
-
-unreg:
-	platform_device_unregister(i2c_dev);
-err:
-	return ret;
 }
 
 arch_initcall(fsl_i2c_of_init);
@@ -436,41 +523,44 @@ static enum fsl_usb2_phy_modes determine
 	return FSL_USB2_PHY_NONE;
 }
 
-static int __init fsl_usb_of_init(void)
+
+static void fsl_usb_of_init_one(struct device_node *np, unsigned int num,
+		enum fsl_usb2_operating_modes mode)
 {
-	struct device_node *np;
-	unsigned int i;
-	struct platform_device *usb_dev_mph = NULL, *usb_dev_dr = NULL;
+	struct resource r[2];
+	struct fsl_usb2_platform_data usb_data;
+	const unsigned char *prop = NULL;
+	struct platform_device *usb_dev = NULL;
 	int ret;
 
-	for (np = NULL, i = 0;
-	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL;
-	     i++) {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
+	memset(&r, 0, sizeof(r));
+	memset(&usb_data, 0, sizeof(usb_data));
 
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
+	ret = of_address_to_resource(np, 0, &r[0]);
+	if (ret) {
+		printk("usb %d could not map registers\n", num);
+		return;
+	}
 
-		of_irq_to_resource(np, 0, &r[1]);
+	ret = of_irq_to_resource(np, 0, &r[1]);
+	if (ret == NO_IRQ) {
+		printk("usb %d could not map irq\n", num);
+		return;
+	}
 
-		usb_dev_mph =
-		    platform_device_register_simple("fsl-ehci", i, r, 2);
-		if (IS_ERR(usb_dev_mph)) {
-			ret = PTR_ERR(usb_dev_mph);
-			goto err;
-		}
+	usb_dev = platform_device_register_simple("fsl-ehci", num, r, 2);
+	if (IS_ERR(usb_dev)) {
+		printk("usb %d register failed with error %ld\n",
+				num, PTR_ERR(usb_dev));
+		return;
+	}
 
-		usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
-		usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
+	usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
+	usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
 
-		usb_data.operating_mode = FSL_USB2_MPH_HOST;
+	usb_data.operating_mode = mode;
 
+	if (mode == FSL_USB2_DR_HOST) {
 		prop = get_property(np, "port0", NULL);
 		if (prop)
 			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
@@ -478,66 +568,36 @@ static int __init fsl_usb_of_init(void)
 		prop = get_property(np, "port1", NULL);
 		if (prop)
 			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
-
-		prop = get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		ret =
-		    platform_device_add_data(usb_dev_mph, &usb_data,
-					     sizeof(struct
-						    fsl_usb2_platform_data));
-		if (ret)
-			goto unreg_mph;
 	}
 
-	for (np = NULL;
-	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL;
-	     i++) {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
+	prop = get_property(np, "phy_type", NULL);
+	usb_data.phy_mode = determine_usb_phy(prop);
 
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto unreg_mph;
+	ret = platform_device_add_data(usb_dev, &usb_data,
+			sizeof(struct fsl_usb2_platform_data));
+	if (ret) {
+		printk("usb %d failed to add data\n", num);
+		platform_device_unregister(usb_dev);
+	}
+}
 
-		of_irq_to_resource(np, 0, &r[1]);
 
-		usb_dev_dr =
-		    platform_device_register_simple("fsl-ehci", i, r, 2);
-		if (IS_ERR(usb_dev_dr)) {
-			ret = PTR_ERR(usb_dev_dr);
-			goto err;
-		}
-
-		usb_dev_dr->dev.coherent_dma_mask = 0xffffffffUL;
-		usb_dev_dr->dev.dma_mask = &usb_dev_dr->dev.coherent_dma_mask;
+static int __init fsl_usb_of_init(void)
+{
+	struct device_node *np;
+	unsigned int num;
 
-		usb_data.operating_mode = FSL_USB2_DR_HOST;
+	for (np = NULL, num = 0;
+	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL;
+	     num++)
+		fsl_usb_of_init_one(np, num, FSL_USB2_MPH_HOST);
 
-		prop = get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
+	for (np = NULL;
+	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL;
+	     num++)
+		fsl_usb_of_init_one(np, num, FSL_USB2_DR_HOST);
 
-		ret =
-		    platform_device_add_data(usb_dev_dr, &usb_data,
-					     sizeof(struct
-						    fsl_usb2_platform_data));
-		if (ret)
-			goto unreg_dr;
-	}
 	return 0;
-
-unreg_dr:
-	if (usb_dev_dr)
-		platform_device_unregister(usb_dev_dr);
-unreg_mph:
-	if (usb_dev_mph)
-		platform_device_unregister(usb_dev_mph);
-err:
-	return ret;
 }
 
 arch_initcall(fsl_usb_of_init);
@@ -587,7 +647,11 @@ static int __init fs_enet_of_init(void)
 		r[2].name = fcc_regs_c;
 		fs_enet_data.fcc_regs_c = r[2].start;
 
-		of_irq_to_resource(np, 0, &r[3]);
+		ret = of_irq_to_resource(np, 0, &r[3]);
+		if (ret == NO_IRQ) {
+			ret = -EINVAL;
+			goto err;
+		}
 
 		fs_enet_dev =
 		    platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
@@ -749,7 +813,11 @@ static int __init cpm_uart_of_init(void)
 			goto err;
 		r[1].name = scc_pram;
 
-		of_irq_to_resource(np, 0, &r[2]);
+		ret = of_irq_to_resource(np, 0, &r[2]);
+		if (ret == NO_IRQ) {
+			ret = -EINVAL;
+			goto err;
+		}
 
 		cpm_uart_dev =
 		    platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3);
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 3da29e2..910b0eb 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -49,8 +49,10 @@ struct gianfar_platform_data {
 	u32	device_flags;
 	/* board specific information */
 	u32	board_flags;
+	u32	interface;
 	u32	bus_id;
 	u32	phy_id;
+	u32	phy_flags;
 	u8	mac_addr[6];
 };
 
@@ -68,10 +70,14 @@ #define FSL_GIANFAR_DEV_HAS_CSUM		0x0000
 #define FSL_GIANFAR_DEV_HAS_VLAN		0x00000020
 #define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH	0x00000040
 #define FSL_GIANFAR_DEV_HAS_PADDING		0x00000080
+#define FSL_GIANFAR_DEV_HAS_FILER		0x00000100
+#define FSL_GIANFAR_DEV_HAS_PARSE_L2		0x00000200
+#define FSL_GIANFAR_DEV_HAS_PARSE_L3		0x00000300
+#define FSL_GIANFAR_DEV_HAS_PARSE_L4		0x00000400
+#define FSL_GIANFAR_DEV_HAS_MULTI_QUEUE		0x00000800
 
 /* Flags in gianfar_platform_data */
 #define FSL_GIANFAR_BRD_HAS_PHY_INTR	0x00000001 /* set or use a timer */
-#define FSL_GIANFAR_BRD_IS_REDUCED	0x00000002 /* Set if RGMII, RMII */
 
 struct fsl_i2c_platform_data {
 	/* device specific information */
-- 
1.4.2.3

^ permalink raw reply related

* [PATCH] Add support for the new version of the CDS with rev2 8548 silicon
From: Andy Fleming @ 2006-11-08  6:17 UTC (permalink / raw)
  To: linuxppc-dev


Basically, just a copy of the old CDS dts with the now working
eTSEC 3 & 4 enabled and set to RGMII.

Requires the new PHY Lib interface changes to work

Signed-off-by: Andrew Fleming <afleming@freescale.com>
---
Whoops, mistyped and accidentally sent this to a non-existent address 
instead of the list.

 arch/powerpc/boot/dts/mpc8548v2cds.dts |  341 ++++++++++++++++++++++++++++++++
 1 files changed, 341 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8548v2cds.dts b/arch/powerpc/boot/dts/mpc8548v2cds.dts
new file mode 100644
index 0000000..7c66863
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8548v2cds.dts
@@ -0,0 +1,341 @@
+/*
+ * MPC8548 CDS Device Tree Source
+ * This is for the 1.3 CDS board, which has working eTSECs 3 & 4
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/ {
+	model = "MPC8548CDS";
+	compatible = "MPC85xxCDS";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,8548@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <8000>;		// L1, 32K
+			i-cache-size = <8000>;		// L1, 32K
+			timebase-frequency = <0>;	//  33 MHz, from uboot
+			bus-frequency = <0>;	// 166 MHz
+			clock-frequency = <0>;	// 825 MHz, from uboot
+			32-bit;
+			linux,phandle = <201>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 08000000>;	// 128M at 0x0
+	};
+
+	soc8548@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00100000>;	// CCSRBAR 1M
+		bus-frequency = <0>;
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <1b 2>;
+			interrupt-parent = <40000>;
+			dfsrr;
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			compatible = "gianfar";
+			reg = <24520 20>;
+			linux,phandle = <24520>;
+			ethernet-phy@0 {
+				linux,phandle = <2452000>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				flags = <0>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@1 {
+				linux,phandle = <2452001>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				flags = <0>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+			};
+
+			ethernet-phy@2 {
+				linux,phandle = <2452002>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				flags = <1>;
+				reg = <2>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@3 {
+				linux,phandle = <2452003>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				flags = <1>;
+				reg = <3>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		ethernet@24000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan-insertion;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
+			compatible = "gianfar";
+			reg = <24000 1000>;
+			mac-address = [ 00 E0 0C 00 73 00 ];
+			interrupts = <d 2 e 2 12 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452000>;
+			interface = "GMII";
+		};
+
+		ethernet@25000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan-insertion;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
+			compatible = "gianfar";
+			reg = <25000 1000>;
+			mac-address = [ 00 E0 0C 00 73 01 ];
+			interrupts = <13 2 14 2 18 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+			interface = "GMII";
+		};
+		ethernet@26000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan-insertion;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
+			compatible = "gianfar";
+			reg = <26000 1000>;
+			mac-address = [ 00 E0 0C 00 73 02 ];
+			interrupts = <f 2 10 2 11 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452002>;
+			interface = "RGMII";
+		};
+
+		ethernet@27000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			gigabit;
+			coalescing;
+			rmon;
+			checksumming;
+			vlan-insertion;
+			extended-hash;
+			padding;
+			filer;
+			parseL4;
+			parseL3;
+			parseL2;
+			multi-queue;
+			compatible = "gianfar";
+			reg = <27000 1000>;
+			mac-address = [ 00 E0 0C 00 73 03 ];
+			interrupts = <15 2 16 2 17 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452003>;
+			interface = "RGMII";
+		};
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>; 	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		pci@8000 {
+			linux,phandle = <8000>;
+			interrupt-map-mask = <1f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x10 */
+				08000 0 0 1 40000 30 1
+				08000 0 0 2 40000 31 1
+				08000 0 0 3 40000 32 1
+				08000 0 0 4 40000 33 1
+
+				/* IDSEL 0x11 */
+				08800 0 0 1 40000 30 1
+				08800 0 0 2 40000 31 1
+				08800 0 0 3 40000 32 1
+				08800 0 0 4 40000 33 1
+
+				/* IDSEL 0x12 (Slot 1) */
+				09000 0 0 1 40000 30 1
+				09000 0 0 2 40000 31 1
+				09000 0 0 3 40000 32 1
+				09000 0 0 4 40000 33 1
+
+				/* IDSEL 0x13 (Slot 2) */
+				09800 0 0 1 40000 31 1
+				09800 0 0 2 40000 32 1
+				09800 0 0 3 40000 33 1
+				09800 0 0 4 40000 30 1
+
+				/* IDSEL 0x14 (Slot 3) */
+				0a000 0 0 1 40000 32 1
+				0a000 0 0 2 40000 33 1
+				0a000 0 0 3 40000 30 1
+				0a000 0 0 4 40000 31 1
+
+				/* IDSEL 0x15 (Slot 4) */
+				0a800 0 0 1 40000 33 1
+				0a800 0 0 2 40000 30 1
+				0a800 0 0 3 40000 31 1
+				0a800 0 0 4 40000 32 1
+
+				/* Bus 1 (Tundra Bridge) */
+				/* IDSEL 0x12 (ISA bridge) */
+				19000 0 0 1 40000 30 1
+				19000 0 0 2 40000 31 1
+				19000 0 0 3 40000 32 1
+				19000 0 0 4 40000 33 1>;
+			interrupt-parent = <40000>;
+			interrupts = <08 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 80000000 80000000 0 20000000
+				  01000000 0 00000000 e2000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+
+			i8259@19000 {
+				clock-frequency = <0>;
+				interrupt-controller;
+				device_type = "interrupt-controller";
+				reg = <19000 0 0 0 1>;
+				#address-cells = <0>;
+				#interrupt-cells = <2>;
+				built-in;
+				compatible = "chrp,iic";
+				big-endian;
+				interrupts = <1>;
+				interrupt-parent = <8000>;
+			};
+		};
+
+		pci@9000 {
+			linux,phandle = <9000>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x15 */
+				a800 0 0 1 40000 3b 1
+				a800 0 0 2 40000 3b 1
+				a800 0 0 3 40000 3b 1
+				a800 0 0 4 40000 3b 1>;
+			interrupt-parent = <40000>;
+			interrupts = <09 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 a0000000 a0000000 0 20000000
+				  01000000 0 00000000 e3000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <9000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+		};
+
+		pic@40000 {
+			linux,phandle = <40000>;
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <40000 40000>;
+			built-in;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+                        big-endian;
+		};
+	};
+};
-- 
1.4.2.3

^ permalink raw reply related

* Re: 2.6.18 fails in call_usermodedata() on 8xx
From: Jim Heck @ 2006-11-08  6:17 UTC (permalink / raw)
  To: robin.gilks; +Cc: ppc embedded list
In-Reply-To: <45512174.7020205@tait.co.nz>

Robin,

Could you provide some more details of your problem with dma_alloc_init 
for the 8xx.  I posted a few days back on Saturday about problems I was 
having getting an RPXLiteDW (based on the 823) to work with a late 
2.6.xx kernel.  I had traced the problem down (working without a probe) 
to problems with cpm_dpalloc() and cpm_dpram_addr() in the allocation of 
DP Ram buffers for the network loopback device.  DMA rings a bell since 
the failure occurred near where the /arch/ppc/8xx_io/enet.c driver is 
calling  dma_alloc_coherent().

The details on what code you had to change in the kernel, and the 
problems you were seeing might help me greatly.

Thanks for any help,

-Jim Heck

Robin Gilks wrote:
> Greetings
>
> Having (sort of) mastered the bdi2000, I'm trying to bring up a 8xx card
> thats been debugged and working with a 2.4 kernel for the last 3 years
> but is failing miserably on a 2.6.18 kernel.
>
> My initial problems in dma_alloc_init I seem to have fixed by moving
> CONFIG_CONSISTENT_START to 0xa0000000 from the default of 0xff100000 but
> now I'm failing in call_usermodedata(). Any attempt to check the values 
> of structures (eg. current->fs->root) results in an error of the form:
>
> (gdb) print *current
> Cannot access memory at address 0xc01e27a8
>
> so I'm a bit stuck with further debugging.
>
> Is there anything I should be looking out for in particular with an 8xx
> CPU and a late 2.6 kernel? My understanding was that it now worked but
> the config documentation is a bit thin on the ground :-(
>
> Cheers
>
>   

^ permalink raw reply

* Re: [Cbe-oss-dev] [PATCH] cell: abstract spu management routines
From: Michael Ellerman @ 2006-11-08  6:28 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <45516A0C.5050607@am.sony.com>

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

On Tue, 2006-11-07 at 21:24 -0800, Geoff Levand wrote:
> Michael Ellerman wrote:
> >> +static struct platform_data *platform_data(struct spu *spu)
> >> +{
> >> +	BUG_ON(!spu->platform_data);
> >> +	return (struct platform_data*)spu->platform_data;
> >> +}
> > 
> > I don't see the point of this, why not just grab platform data directly?
> 
> Well, first, it does a check, and second, you can't just grab platform_data,
> you need to always do the cast also. So then, is something like
> '((struct platform_data*)spu->platform_data)->' preferred over
> 'platform_data(spu)->'?

Stephen points out that you shouldn't do the cast at all (inside the
function), it's implied by the return type. And by casting explicitly
you create the potential for the return type and the cast to get out of
sync.

At some point we'll actually read the rest of the patch ;)

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

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

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

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

^ permalink raw reply


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