rpms/kernel/F-7 linux-2.6-ps3-clear-spu-irq.patch, 1.2, 1.3 linux-2.6-ps3-device-init.patch, 1.3, 1.4 linux-2.6-ps3-ehci-iso.patch, 1.2, 1.3 linux-2.6-ps3-ethernet-autoload.patch, 1.2, 1.3 linux-2.6-ps3-ethernet-modular.patch, 1.4, 1.5 linux-2.6-ps3-gelic-wireless.patch, 1.2, 1.3 linux-2.6-ps3-gelic.patch, 1.2, 1.3 linux-2.6-ps3-kexec.patch, 1.2, 1.3 linux-2.6-ps3-legacy-ioport.patch, 1.2, 1.3 linux-2.6-ps3-memory-probe.patch, 1.2, 1.3 linux-2.6-ps3-smp-boot.patch, 1.3, 1.4 linux-2.6-ps3-sound-autoload.patch, 1.2, 1.3 linux-2.6-ps3-sound.patch, 1.3, 1.4 linux-2.6-ps3-storage.patch, 1.3, 1.4 linux-2.6-ps3-system-bus-rework-2.patch, 1.2, 1.3 linux-2.6-ps3-system-bus-rework.patch, 1.2, 1.3 linux-2.6-ps3-usb-autoload.patch, 1.2, 1.3 linux-2.6-ps3-wrap-spu-runctl.patch, 1.4, 1.5 linux-2.6-ps3av-export-header.patch, 1.2, 1.3 linux-2.6-ps3fb-panic.patch, 1.2, 1.3 kernel-2.6.spec, 1.3277, 1.3278

Dave Jones (davej) fedora-extras-commits at redhat.com
Thu Jul 12 21:31:18 UTC 2007


Author: davej

Update of /cvs/pkgs/rpms/kernel/F-7
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv27738

Modified Files:
	kernel-2.6.spec 
Added Files:
	linux-2.6-ps3-clear-spu-irq.patch 
	linux-2.6-ps3-device-init.patch linux-2.6-ps3-ehci-iso.patch 
	linux-2.6-ps3-ethernet-autoload.patch 
	linux-2.6-ps3-ethernet-modular.patch 
	linux-2.6-ps3-gelic-wireless.patch linux-2.6-ps3-gelic.patch 
	linux-2.6-ps3-kexec.patch linux-2.6-ps3-legacy-ioport.patch 
	linux-2.6-ps3-memory-probe.patch linux-2.6-ps3-smp-boot.patch 
	linux-2.6-ps3-sound-autoload.patch linux-2.6-ps3-sound.patch 
	linux-2.6-ps3-storage.patch 
	linux-2.6-ps3-system-bus-rework-2.patch 
	linux-2.6-ps3-system-bus-rework.patch 
	linux-2.6-ps3-usb-autoload.patch 
	linux-2.6-ps3-wrap-spu-runctl.patch 
	linux-2.6-ps3av-export-header.patch 
	linux-2.6-ps3fb-panic.patch 
Log Message:
* Thu Jul 12 2007 Dave Jones <davej at redhat.com>
- Add back the rediffed PS3 patches.


linux-2.6-ps3-clear-spu-irq.patch:

Index: linux-2.6-ps3-clear-spu-irq.patch
===================================================================
RCS file: linux-2.6-ps3-clear-spu-irq.patch
diff -N linux-2.6-ps3-clear-spu-irq.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-clear-spu-irq.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,92 @@
+From: Masato Noguchi <Masato.Noguchi at jp.sony.com>
+
+In the PS3 platform, all interrupts are virtuailzed by hypervisor.
+Thus, there is a little difference between baremetal and PS3.
+
+Cell BE Architecture says SPU MFC class 0 interrupt is a pulse.
+That means, once interrupt raised, never re-raised until someone
+changes interrupt status.
+
+Current spufs inplementation rely on it.
+Class 0 handler just wake up a process and interrupt status is
+cleared by that process at outside of interrupt handler.
+
+While, the PS3 hypervisor treats all SPU interrupt as a level.
+That means, if unmasked interrupt status bit remaind at
+the end of interrupt handler, the hypervisor creates renewed
+virtual interrupt packet.
+
+Thus, Current kernel will freeze by interrupts raised 
+over and over again, once SPE raised class 0 interrupt.
+
+
+Signed-off-by: Masato Noguchi <Masato.Noguchi at jp.sony.com>
+Signed-off-by: Geoff Levand <geoffrey.levand at am.sony.com>
+---
+ arch/powerpc/platforms/cell/spu_base.c |   23 +++++++++++++++--------
+ include/asm-powerpc/spu.h              |    2 +-
+ 2 files changed, 16 insertions(+), 9 deletions(-)
+
+--- ps3-linux-2.6.20.orig/arch/powerpc/platforms/cell/spu_base.c
++++ ps3-linux-2.6.20/arch/powerpc/platforms/cell/spu_base.c
+@@ -158,27 +158,34 @@ static irqreturn_t
+ spu_irq_class_0(int irq, void *data)
+ {
+ 	struct spu *spu;
++	unsigned long stat, mask;
+ 
+ 	spu = data;
+-	spu->class_0_pending = 1;
++
++	mask = spu_int_mask_get(spu, 0);
++	stat = spu_int_stat_get(spu, 0);
++	stat &= mask;
++
++	spin_lock(&spu->register_lock);
++	spu->class_0_pending |= stat;
++	spin_unlock(&spu->register_lock);
++
+ 	spu->stop_callback(spu);
+ 
++	spu_int_stat_clear(spu, 0, stat);
++
+ 	return IRQ_HANDLED;
+ }
+ 
+ int
+ spu_irq_class_0_bottom(struct spu *spu)
+ {
+-	unsigned long stat, mask;
+ 	unsigned long flags;
+-
+-	spu->class_0_pending = 0;
++	unsigned long stat;
+ 
+ 	spin_lock_irqsave(&spu->register_lock, flags);
+-	mask = spu_int_mask_get(spu, 0);
+-	stat = spu_int_stat_get(spu, 0);
+-
+-	stat &= mask;
++	stat = spu->class_0_pending;
++	spu->class_0_pending = 0;
+ 
+ 	if (stat & 1) /* invalid DMA alignment */
+ 		__spu_trap_dma_align(spu);
+--- ps3-linux-2.6.20.orig/include/asm-powerpc/spu.h
++++ ps3-linux-2.6.20/include/asm-powerpc/spu.h
+@@ -122,6 +122,7 @@ struct spu {
+ 	u64 flags;
+ 	u64 dar;
+ 	u64 dsisr;
++	u64 class_0_pending;
+ 	size_t ls_size;
+ 	unsigned int slb_replace;
+ 	struct mm_struct *mm;
+@@ -129,7 +130,6 @@ struct spu {
+ 	struct spu_runqueue *rq;
+ 	unsigned long long timestamp;
+ 	pid_t pid;
+-	int class_0_pending;
+ 	spinlock_t register_lock;
+ 
+ 	void (* wbox_callback)(struct spu *spu);

linux-2.6-ps3-device-init.patch:

Index: linux-2.6-ps3-device-init.patch
===================================================================
RCS file: linux-2.6-ps3-device-init.patch
diff -N linux-2.6-ps3-device-init.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-device-init.patch	12 Jul 2007 21:31:10 -0000	1.4
@@ -0,0 +1,520 @@
+PS3 device init routines.
+
+Signed-off-by: Geoff Levand <geoffrey.levand at am.sony.com>
+
+---
+ arch/powerpc/platforms/ps3/Makefile      |    1 
+ arch/powerpc/platforms/ps3/device-init.c |  500 +++++++++++++++++++++++++++++++
+ 2 files changed, 501 insertions(+)
+
+--- ps3-linux-dev.orig/arch/powerpc/platforms/ps3/Makefile
++++ ps3-linux-dev/arch/powerpc/platforms/ps3/Makefile
+@@ -6,3 +6,4 @@ obj-$(CONFIG_PS3_STORAGE_ROM) += ps3rom.
+ 
+ obj-$(CONFIG_SMP) += smp.o
+ obj-$(CONFIG_SPU_BASE) += spu.o
++obj-y += device-init.o
+\ No newline at end of file
+--- /dev/null
++++ ps3-linux-dev/arch/powerpc/platforms/ps3/device-init.c
+@@ -0,0 +1,500 @@
++/*
++ *  PS3 device init routines.
++ *
++ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
++ *  Copyright 2006 Sony Corp.
++ *
++ *  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; version 2 of the License.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#define DEBUG 1
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <asm/firmware.h>
++
++#include "platform.h"
++
++static int __devinit
++ps3_register_gelic (void)
++{
++	int result;
++	struct ps3_system_bus_device *dev;
++	struct ps3_repository_device repo;
++
++	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++
++	/* Puts the regions at the end of the system_bus_device. */
++
++	dev = kzalloc(sizeof(struct ps3_system_bus_device)
++		+ sizeof(struct ps3_dma_region), GFP_KERNEL);
++
++	ps3_system_bus_device_init(dev,
++				   PS3_MATCH_ID_GELIC,
++				   NULL,
++				   NULL);
++
++	result = ps3_repository_find_first_device(PS3_BUS_TYPE_SB,
++		PS3_DEV_TYPE_SB_GELIC, &repo);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_first_device failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	dev->did = repo.did;
++
++	result = ps3_repository_find_interrupt(&repo,
++		PS3_INTERRUPT_TYPE_EVENT_PORT, &dev->interrupt_id);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	BUG_ON(dev->interrupt_id != 0);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_get_interrupt_id failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	dev->d_region = (struct ps3_dma_region *)((char*)dev
++		+ sizeof(struct ps3_system_bus_device));
++
++	ps3_dma_region_init(dev->d_region, &dev->did, PS3_DMA_64K,
++			    PS3_DMA_OTHER, NULL, 0, PS3_IOBUS_SB);
++
++	result = ps3_system_bus_device_register(dev, PS3_IOBUS_SB);
++
++	if (result) {
++		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++
++fail:
++#if defined(DEBUG)
++	memset(dev, 0xad, sizeof(struct ps3_system_bus_device)
++		+ sizeof(struct ps3_dma_region));
++#endif
++	kfree(dev);
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++}
++
++static int __devinit
++ps3_register_ohci_0 (void)
++{
++	int result;
++	struct ps3_repository_device repo;
++	u64 bus_addr;
++	u64 len;
++
++	/* Puts the regions at the end of the system_bus_device. */
++
++	struct ohci_layout {
++		struct ps3_system_bus_device dev;
++		struct ps3_dma_region d_region;
++		struct ps3_mmio_region m_region;
++	} *p;
++
++	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++
++	p = kzalloc(sizeof(struct ohci_layout), GFP_KERNEL);
++
++	ps3_system_bus_device_init(&p->dev,
++				   PS3_MATCH_ID_OHCI,
++				   &p->d_region,
++				   &p->m_region);
++
++	result = ps3_repository_find_first_device(PS3_BUS_TYPE_SB,
++		PS3_DEV_TYPE_SB_USB, &repo);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_device failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	p->dev.did = repo.did;
++
++	result = ps3_repository_find_interrupt(&repo,
++		PS3_INTERRUPT_TYPE_SB_OHCI, &p->dev.interrupt_id);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	ps3_repository_find_reg(&repo, PS3_REG_TYPE_SB_OHCI,
++		&bus_addr, &len);
++
++	BUG_ON(p->dev.interrupt_id != 16);
++	BUG_ON(bus_addr != 0x3010000);
++	BUG_ON(len != 0x10000);
++
++	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
++			    PS3_DMA_INTERNAL, NULL, 0, PS3_IOBUS_SB);
++
++	ps3_mmio_region_init(p->dev.m_region, &p->dev.did, bus_addr,
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
++
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
++
++	if (result)
++		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
++			__func__, __LINE__);
++
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++
++fail:
++#if defined(DEBUG)
++	memset(p, 0xad, sizeof(struct ohci_layout));
++#endif
++	kfree(p);
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++}
++
++static int __devinit
++ps3_register_ohci_1 (void)
++{
++	int result;
++	struct ps3_repository_device repo;
++	u64 bus_addr;
++	u64 len;
++
++	/* Puts the regions at the end of the system_bus_device. */
++
++	struct ohci_layout {
++		struct ps3_system_bus_device dev;
++		struct ps3_dma_region d_region;
++		struct ps3_mmio_region m_region;
++	} *p;
++
++	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++
++	p = kzalloc(sizeof(struct ohci_layout), GFP_KERNEL);
++
++	ps3_system_bus_device_init(&p->dev,
++				   PS3_MATCH_ID_OHCI,
++				   &p->d_region,
++				   &p->m_region);
++
++	result = ps3_repository_find_first_device(PS3_BUS_TYPE_SB,
++		PS3_DEV_TYPE_SB_USB, &repo);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_device failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	result = ps3_repository_find_device(PS3_BUS_TYPE_SB,
++		PS3_DEV_TYPE_SB_USB, &repo, &repo);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_device failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	p->dev.did = repo.did;
++
++	result = ps3_repository_find_interrupt(&repo,
++		PS3_INTERRUPT_TYPE_SB_OHCI, &p->dev.interrupt_id);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	ps3_repository_find_reg(&repo, PS3_REG_TYPE_SB_OHCI,
++		&bus_addr, &len);
++
++	BUG_ON(p->dev.interrupt_id != 17);
++	BUG_ON(bus_addr != 0x3020000);
++	BUG_ON(len != 0x10000);
++
++	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
++			    PS3_DMA_INTERNAL, NULL, 0, PS3_IOBUS_SB);
++
++	ps3_mmio_region_init(p->dev.m_region, &p->dev.did, bus_addr,
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
++
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
++
++	if (result)
++		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
++			__func__, __LINE__);
++
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++
++fail:
++#if defined(DEBUG)
++	memset(p, 0xad, sizeof(struct ohci_layout));
++#endif
++	kfree(p);
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++}
++
++static int __devinit
++ps3_register_ehci_0 (void)
++{
++	int result;
++	struct ps3_repository_device repo;
++	u64 bus_addr;
++	u64 len;
++
++	/* Puts the regions at the end of the system_bus_device. */
++
++	struct ehci_layout {
++		struct ps3_system_bus_device dev;
++		struct ps3_dma_region d_region;
++		struct ps3_mmio_region m_region;
++	} *p;
++
++	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++
++	p = kzalloc(sizeof(struct ehci_layout), GFP_KERNEL);
++
++	ps3_system_bus_device_init(&p->dev,
++				   PS3_MATCH_ID_EHCI,
++				   &p->d_region,
++				   &p->m_region);
++
++	result = ps3_repository_find_first_device(PS3_BUS_TYPE_SB,
++		PS3_DEV_TYPE_SB_USB, &repo);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_device failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	p->dev.did = repo.did;
++
++	result = ps3_repository_find_interrupt(&repo,
++		PS3_INTERRUPT_TYPE_SB_EHCI, &p->dev.interrupt_id);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	ps3_repository_find_reg(&repo, PS3_REG_TYPE_SB_EHCI,
++		&bus_addr, &len);
++
++	BUG_ON(p->dev.interrupt_id != 10);
++	BUG_ON(bus_addr != 0x3810000);
++	BUG_ON(len != 0x10000);
++
++	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
++			    PS3_DMA_INTERNAL, NULL, 0, PS3_IOBUS_SB);
++
++	ps3_mmio_region_init(p->dev.m_region, &p->dev.did, bus_addr,
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
++
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
++
++	if (result)
++		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
++			__func__, __LINE__);
++
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++
++fail:
++#if defined(DEBUG)
++	memset(p, 0xad, sizeof(struct ehci_layout));
++#endif
++	kfree(p);
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++}
++
++static int __devinit
++ps3_register_ehci_1 (void)
++{
++	int result;
++	struct ps3_repository_device repo;
++	u64 bus_addr;
++	u64 len;
++
++	/* Puts the regions at the end of the system_bus_device. */
++
++	struct ehci_layout {
++		struct ps3_system_bus_device dev;
++		struct ps3_dma_region d_region;
++		struct ps3_mmio_region m_region;
++	} *p;
++
++	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++
++	p = kzalloc(sizeof(struct ehci_layout), GFP_KERNEL);
++
++	ps3_system_bus_device_init(&p->dev,
++				   PS3_MATCH_ID_EHCI,
++				   &p->d_region,
++				   &p->m_region);
++
++	result = ps3_repository_find_first_device(PS3_BUS_TYPE_SB,
++		PS3_DEV_TYPE_SB_USB, &repo);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_device failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	result = ps3_repository_find_device(PS3_BUS_TYPE_SB,
++		PS3_DEV_TYPE_SB_USB, &repo, &repo);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_device failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	p->dev.did = repo.did;
++
++	result = ps3_repository_find_interrupt(&repo,
++		PS3_INTERRUPT_TYPE_SB_EHCI, &p->dev.interrupt_id);
++
++	if (result) {
++		pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
++			__func__, __LINE__);
++		goto fail;
++	}
++
++	ps3_repository_find_reg(&repo, PS3_REG_TYPE_SB_EHCI,
++		&bus_addr, &len);
++
++	BUG_ON(p->dev.interrupt_id != 11);
++	BUG_ON(bus_addr != 0x3820000);
++	BUG_ON(len != 0x10000);
++
++	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
++			    PS3_DMA_INTERNAL, NULL, 0, PS3_IOBUS_SB);
++
++	ps3_mmio_region_init(p->dev.m_region, &p->dev.did, bus_addr,
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
++
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
++
++	if (result)
++		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
++			__func__, __LINE__);
++
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++
++fail:
++#if defined(DEBUG)
++	memset(p, 0xad, sizeof(struct ehci_layout));
++#endif
++	kfree(p);
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++}
++
++static int __devinit ps3_register_sound(void)
++{
++	int result;
++
++	struct snd_ps3_layout {
++		struct ps3_system_bus_device dev;
++		struct ps3_dma_region d_region;
++		struct ps3_mmio_region m_region;
++	} *p;
++
++	p = kzalloc(sizeof(*p), GFP_KERNEL);
++	if (!p)
++		return -ENOMEM;
++
++	ps3_system_bus_device_init(&p->dev, PS3_MATCH_ID_SOUND,
++				   &p->d_region,
++				   &p->m_region);
++
++#warning need device specific data here
++
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_IOC0);
++
++	if (result)
++		kfree(p);
++
++	return result;
++}
++
++static int __devinit
++ps3_register_sys_manager (void)
++{
++	int result;
++	static struct ps3_vuart_port_device dev = {
++		.match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
++	};
++
++	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++
++	result = ps3_vuart_port_device_register(&dev);
++
++	if (result)
++		pr_debug("%s:%d ps3_vuart_port_device_register failed\n",
++			__func__, __LINE__);
++
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++}
++
++int __init
++ps3_register_known_devices (void)
++{
++	int result;
++
++	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
++		return -ENODEV;
++
++	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++
++	//ps3_repository_dump_bus_info();
++
++	result = ps3_register_ohci_0();
++	result = ps3_register_ehci_0();
++	result = ps3_register_ohci_1();
++	result = ps3_register_ehci_1();
++	result = ps3_register_sound();
++
++#if defined(CONFIG_PS3_SYS_MANAGER)
++	result = ps3_register_sys_manager();
++#endif
++	result = ps3_register_gelic();
++
++	pr_debug(" <- %s:%d\n", __func__, __LINE__);
++	return result;
++}
++
++device_initcall(ps3_register_known_devices);

linux-2.6-ps3-ehci-iso.patch:

Index: linux-2.6-ps3-ehci-iso.patch
===================================================================
RCS file: linux-2.6-ps3-ehci-iso.patch
diff -N linux-2.6-ps3-ehci-iso.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-ehci-iso.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,73 @@
+From: Masashi Kimoto <Masashi_Kimoto at hq.scei.sony.co.jp>
+
+When we use Linux git tree on PS3 we face a error msg from 
+ps3-ehci-driver,
+        ps3-ehci-driver sb_04: port 1 resume error -19
+        hub 2-0:1.0: hub_port_status failed (err = -32)
+        ...
+Built-in Bluetooth uses a USB isochronous and causes this error.
+
+USB host controller refers TD after echi driver modify it's Periodic Frame 
+List.
+Because of this, NULLed TD is asscessed and causes USB error.
+
+In this patch the driver holds the TD while host controller refers the 
+list after Active bit=0.
+
+From: Masashi Kimoto <Masashi_Kimoto at hq.scei.sony.co.jp>
+Signed-off-by: Geoff Levand <geoffrey.levand at am.sony.com>
+
+---
+ drivers/usb/host/ehci-sched.c |   34 ++++++++++++++++++++++++++++++----
+ 1 file changed, 30 insertions(+), 4 deletions(-)
+
+--- ps3-linux-dev.orig/drivers/usb/host/ehci-sched.c
++++ ps3-linux-dev/drivers/usb/host/ehci-sched.c
+@@ -1168,8 +1168,21 @@ itd_urb_transaction (
+ 		if (likely (!list_empty(&stream->free_list))) {
+ 			itd = list_entry (stream->free_list.prev,
+ 					 struct ehci_itd, itd_list);
+-			list_del (&itd->itd_list);
+-			itd_dma = itd->itd_dma;
++#if defined(CONFIG_PPC_PS3)
++			/* Fix for Cell SCC ISO transfer (PS3 Bluetooth). */
++			if (firmware_has_feature(FW_FEATURE_PS3_LV1)
++				&& itd->frame == ((ehci_readl(ehci,
++				&ehci->regs->frame_index) >> 3)
++				% ehci->periodic_size))
++				itd = NULL;
++			else {
++				list_del (&itd->itd_list);
++				itd_dma = itd->itd_dma;
++			}
++#else
++                       list_del (&itd->itd_list);
++                       itd_dma = itd->itd_dma;
++#endif
+ 		} else
+ 			itd = NULL;
+ 
+@@ -1784,8 +1797,21 @@ sitd_urb_transaction (
+ 		if (!list_empty(&stream->free_list)) {
+ 			sitd = list_entry (stream->free_list.prev,
+ 					 struct ehci_sitd, sitd_list);
+-			list_del (&sitd->sitd_list);
+-			sitd_dma = sitd->sitd_dma;
++#if defined(CONFIG_PPC_PS3)
++			/* Fix for Cell SCC ISO transfer (PS3 Bluetooth). */
++			if (firmware_has_feature(FW_FEATURE_PS3_LV1)
++				&& sitd->frame == ((ehci_readl(ehci,
++				&ehci->regs->frame_index) >> 3)
++				% ehci->periodic_size))
++				sitd = NULL;
++			else {
++				list_del (&sitd->sitd_list);
++				sitd_dma = sitd->sitd_dma;
++			}
++#else
++                       list_del (&sitd->sitd_list);
++                       sitd_dma = sitd->sitd_dma;
++#endif
+ 		} else
+ 			sitd = NULL;
+ 

linux-2.6-ps3-ethernet-autoload.patch:

Index: linux-2.6-ps3-ethernet-autoload.patch
===================================================================
RCS file: linux-2.6-ps3-ethernet-autoload.patch
diff -N linux-2.6-ps3-ethernet-autoload.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-ethernet-autoload.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,7 @@
+--- linux-2.6.20.ppc64/drivers/net/gelic_net.c	2007-03-30 18:35:11.000000000 +0100
++++ linux-2.6.20.ps3/drivers/net/gelic_net.c	2007-03-30 22:50:00.000000000 +0100
+@@ -1875,3 +1886,4 @@ static int __init early_param_gelic_net(
+ }
+ early_param("gelic_vlan", early_param_gelic_net);
+ #endif
++MODULE_ALIAS("ps3:3");

linux-2.6-ps3-ethernet-modular.patch:

Index: linux-2.6-ps3-ethernet-modular.patch
===================================================================
RCS file: linux-2.6-ps3-ethernet-modular.patch
diff -N linux-2.6-ps3-ethernet-modular.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-ethernet-modular.patch	12 Jul 2007 21:31:10 -0000	1.5
@@ -0,0 +1,74 @@
+diff --git a/drivers/net/gelic_net.c b/drivers/net/gelic_net.c
+index f931bc7..48ad627 100644
+--- a/drivers/net/gelic_net.c
++++ b/drivers/net/gelic_net.c
+@@ -73,8 +73,9 @@ static int ps3_gelic_param = 1; /* vlan desc support */
+ module_param(ps3_gelic_param, int, S_IRUGO);
+ #endif
+ 
+-struct gelic_net_card *gcard;
+-static uint64_t gelic_irq_status;
++static struct gelic_net_card *gcard;
++static uint64_t *gelic_irq_status;
++
+ 
+ static int dmac_status = 0;
+ 
+@@ -838,7 +839,7 @@ gelic_net_kick_txdma(struct gelic_net_card *card,
+ 		}
+ 		if (!count) {
+ 			printk("lv1_net_start_txdma failed, status=%ld %016lx\n",\
+-				status, gelic_irq_status);
++				status, *gelic_irq_status);
+ 		}
+ 	}
+ }
+@@ -1130,7 +1131,7 @@ gelic_net_interrupt(int irq, void *ptr)
+ 	unsigned long flags;
+ 	uint64_t status;
+ 
+-	status = gelic_irq_status;
++	status = *gelic_irq_status;
+ 	rmb();
+ 	status0 = (uint32_t)(status >> 32);
+ 	status1 = (uint32_t)(status & 0xffffffff);
+@@ -1632,6 +1633,12 @@ gelic_net_alloc_card(void)
+ 	if (!netdev)
+ 		return NULL;
+ 
++	gelic_irq_status = kzalloc(sizeof(*gelic_irq_status), GFP_DMA);
++	if (!gelic_irq_status) {
++		free_netdev(netdev);
++		return NULL;
++	}
++
+ 	card = netdev_priv(netdev);
+ 	card->netdev = netdev;
+ 	INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
+@@ -1677,7 +1684,7 @@ static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev)
+ 	}
+ 
+ 	result = lv1_net_set_interrupt_status_indicator(dev->did.bus_id,
+-		dev->did.dev_id, ps3_mm_phys_to_lpar(__pa(&gelic_irq_status)),
++		dev->did.dev_id, ps3_mm_phys_to_lpar(__pa(gelic_irq_status)),
+ 		0);
+ 
+ 	if (result) {
+@@ -1706,6 +1713,8 @@ fail_status_indicator:
+ fail_dma_region:
+ 	ps3_close_hv_device(&dev->did);
+ fail_open:
++	kfree(gelic_irq_status);
++	gelic_irq_status = NULL;
+ 	free_netdev(gcard->netdev); // enough???
+ 	gcard = NULL;
+ fail_alloc_card:
+@@ -1732,6 +1741,8 @@ ps3_gelic_driver_remove (struct ps3_system_bus_device *dev)
+ 		   atomic_read(&card->tx_timeout_task_counter) == 0);
+ 
+ 	unregister_netdev(netdev);
++	kfree(gelic_irq_status);
++	gelic_irq_status = NULL;
+ 	free_netdev(netdev);
+ 
+ 	lv1_net_set_interrupt_status_indicator(dev->did.bus_id, dev->did.dev_id,

linux-2.6-ps3-gelic-wireless.patch:

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.2 -r 1.3 linux-2.6-ps3-gelic-wireless.patch
Index: linux-2.6-ps3-gelic-wireless.patch
===================================================================
RCS file: linux-2.6-ps3-gelic-wireless.patch
diff -N linux-2.6-ps3-gelic-wireless.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-gelic-wireless.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,2974 @@
+As of 2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440):
+
+ps3-wip/ps3-gelic_wireless_base.diff
+ps3-wip/ps3-gelic_wireless_kern16.diff
+ps3-wip/ps3-gelic_wireless_kern21.diff
+ps3-wip/ps3-gelic_wireless_wext.diff
+
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index 7876697..ea828bf 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -2270,6 +2270,13 @@ config GELIC_NET
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called gelic_net.
+ 
++config GELIC_WIRELESS
++	bool "Gelic net Wireless Extension"
++	depends on GELIC_NET
++	select WIRELESS_EXT
++	help
++	  Wireless Extension support for Gelic Gigabit Ethernet driver
++
+ config GIANFAR
+ 	tristate "Gianfar Ethernet"
+ 	depends on 85xx || 83xx || PPC_86xx
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index 9fa106a..704b839 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -61,6 +61,9 @@ obj-$(CONFIG_BNX2) += bnx2.o
+ spidernet-y += spider_net.o spider_net_ethtool.o
+ obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
+ obj-$(CONFIG_GELIC_NET) += gelic_net.o
++ifeq ($(CONFIG_GELIC_WIRELESS),y)
++  obj-$(CONFIG_GELIC_NET) += gelic_wireless.o
++endif
+ obj-$(CONFIG_TC35815) += tc35815.o
+ obj-$(CONFIG_SKGE) += skge.o
+ obj-$(CONFIG_SKY2) += sky2.o
+diff --git a/drivers/net/gelic_net.c b/drivers/net/gelic_net.c
+index 79ca65f..f931bc7 100644
+--- a/drivers/net/gelic_net.c
++++ b/drivers/net/gelic_net.c
+@@ -60,145 +60,13 @@
+ #include <asm/ps3.h>
+ #include <asm/lv1call.h>
+ 
+-#define GELIC_NET_DRV_NAME "Gelic Network Driver"
+-#define GELIC_NET_DRV_VERSION "1.0"
+-
+-#define GELIC_NET_DEBUG
+-
+-#ifdef GELIC_NET_DEBUG
+-#define DPRINTK(fmt,arg...)   printk(KERN_ERR fmt ,##arg)
+-#define DPRINTKK(fmt,arg...)  printk(KERN_ERR fmt ,##arg)
+-#else
+-#define DPRINTK(fmt,arg...)
+-#define DPRINTKK(fmt,arg...)
++#ifdef CONFIG_GELIC_WIRELESS
++#include "gelic_wireless.h"
+ #endif
++#include "gelic_net.h"
+ 
+-#define GELIC_NET_ETHTOOL               /* use ethtool */
+-
+-/* ioctl */
+-#define GELIC_NET_GET_MODE              (SIOCDEVPRIVATE + 0)
+-#define GELIC_NET_SET_MODE              (SIOCDEVPRIVATE + 1)
+-
+-/* descriptors */
+-#define GELIC_NET_RX_DESCRIPTORS        128 /* num of descriptors */
+-#define GELIC_NET_TX_DESCRIPTORS        128 /* num of descriptors */
+-
+-#define GELIC_NET_MAX_MTU               2308
+-#define GELIC_NET_MIN_MTU               64
+-#define GELIC_NET_RXBUF_ALIGN           128
+-#define GELIC_NET_RX_CSUM_DEFAULT       1 /* hw chksum */
+-#define GELIC_NET_WATCHDOG_TIMEOUT      5*HZ
+-#define GELIC_NET_NAPI_WEIGHT           64
+-#define GELIC_NET_BROADCAST_ADDR        0xffffffffffff
+-#define GELIC_NET_VLAN_POS              (VLAN_ETH_ALEN * 2)
+-#define GELIC_NET_VLAN_MAX              4
+-#define GELIC_NET_MC_COUNT_MAX          32 /* multicast address list */
+-
+-enum gelic_net_int0_status {
+-	GELIC_NET_GDTDCEINT  = 24,
+-	GELIC_NET_GRFANMINT  = 28,
+-};
+-
+-/* GHIINT1STS bits */
+-enum gelic_net_int1_status {
+-	GELIC_NET_GDADCEINT = 14,
+-};
+-
+-/* interrupt mask */
+-#define GELIC_NET_TXINT                   (1L << (GELIC_NET_GDTDCEINT + 32))
+-
+-#define GELIC_NET_RXINT0                  (1L << (GELIC_NET_GRFANMINT + 32))
+-#define GELIC_NET_RXINT1                  (1L << GELIC_NET_GDADCEINT)
+-#define GELIC_NET_RXINT                   (GELIC_NET_RXINT0 | GELIC_NET_RXINT1)
+-
+- /* descriptor data_status bits */
+-#define GELIC_NET_RXIPCHK                 29
+-#define GELIC_NET_TCPUDPIPCHK             28
+-#define GELIC_NET_DATA_STATUS_CHK_MASK    (1 << GELIC_NET_RXIPCHK | \
+-                                           1 << GELIC_NET_TCPUDPIPCHK)
+-
+-/* descriptor data_error bits */
+-#define GELIC_NET_RXIPCHKERR              27
+-#define GELIC_NET_RXTCPCHKERR             26
+-#define GELIC_NET_DATA_ERROR_CHK_MASK     (1 << GELIC_NET_RXIPCHKERR | \
+-                                           1 << GELIC_NET_RXTCPCHKERR)
+-
+-#define GELIC_NET_DMAC_CMDSTAT_NOCS       0xa0080000 /* middle of frame */
+-#define GELIC_NET_DMAC_CMDSTAT_TCPCS      0xa00a0000
+-#define GELIC_NET_DMAC_CMDSTAT_UDPCS      0xa00b0000
+-#define GELIC_NET_DMAC_CMDSTAT_END_FRAME  0x00040000 /* end of frame */
+-
+-#define GELIC_NET_DMAC_CMDSTAT_CHAIN_END  0x00000002 /* RXDCEIS:DMA stopped */
+-
+-#define GELIC_NET_DESCR_IND_PROC_SHIFT    28
+-#define GELIC_NET_DESCR_IND_PROC_MASKO    0x0fffffff
+-
+-/* ignore ipsec ans multicast */
+-#define GELIC_NET_DATA_ERROR_MASK         0xfdefbfff
+-/* ignore unmatched sp on sp, drop_packet, multicast address frame*/
+-#define GELIC_NET_DATA_ERROR_FLG          0x7def8000
+-
+-enum gelic_net_descr_status {
+-	GELIC_NET_DESCR_COMPLETE            = 0x00, /* used in rx and tx */
+-	GELIC_NET_DESCR_RESPONSE_ERROR      = 0x01, /* used in rx and tx */
+-	GELIC_NET_DESCR_PROTECTION_ERROR    = 0x02, /* used in rx and tx */
+-	GELIC_NET_DESCR_FRAME_END           = 0x04, /* used in rx */
+-	GELIC_NET_DESCR_FORCE_END           = 0x05, /* used in rx and tx */
+-	GELIC_NET_DESCR_CARDOWNED           = 0x0a, /* used in rx and tx */
+-	GELIC_NET_DESCR_NOT_IN_USE                  /* any other value */
+-};
+-#define GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE 0xb0000000
+-
+-#define GELIC_NET_DESCR_SIZE              32
+-struct gelic_net_descr {
+-	/* as defined by the hardware */
+-	uint32_t buf_addr;
+-	uint32_t buf_size;
+-	uint32_t next_descr_addr;
+-	uint32_t dmac_cmd_status;
+-	uint32_t result_size;
+-	uint32_t valid_size;	/* all zeroes for tx */
+-	uint32_t data_status;
+-	uint32_t data_error;	/* all zeroes for tx */
+-
+-	/* used in the driver */
+-	struct sk_buff *skb;
+-	dma_addr_t bus_addr;
+-	struct gelic_net_descr *next;
+-	struct gelic_net_descr *prev;
+-	struct vlan_ethhdr vlan;
+-} __attribute__((aligned(32)));
+-
+-struct gelic_net_descr_chain {
+-	/* we walk from tail to head */
+-	struct gelic_net_descr *head;
+-	struct gelic_net_descr *tail;
+-	spinlock_t lock;
+-};
+-
+-struct gelic_net_card {
+-	struct net_device *netdev;
+-	uint64_t ghiintmask;
+-	struct ps3_system_bus_device *dev;
+-	uint32_t vlan_id[GELIC_NET_VLAN_MAX];
+-	int vlan_index;
+-
+-	struct gelic_net_descr_chain tx_chain;
+-	struct gelic_net_descr_chain rx_chain;
+-	spinlock_t chain_lock;
+-
+-	struct net_device_stats netdev_stats;
+-	int rx_csum;
+-	spinlock_t intmask_lock;
+-
+-	struct work_struct tx_timeout_task;
+-	atomic_t tx_timeout_task_counter;
+-	wait_queue_head_t waitq;
+-
+-	struct gelic_net_descr *tx_top, *rx_top;
+-
+-	struct gelic_net_descr descr[0];
+-};
++#define GELIC_NET_DRV_NAME "Gelic Network Driver"
++#define GELIC_NET_DRV_VERSION "1.0"
+ 
[...2581 lines suppressed...]
++#define MAX_SCAN_BSS			16
++
++#define GELICW_SCAN_INTERVAL		(HZ)
++
++#ifdef DEBUG
++#define CH_INFO_FAIL 0x0600 /* debug */
++#else
++#define CH_INFO_FAIL 0
++#endif
++
++struct gelicw_bss {
++	u8 bssid[ETH_ALEN];
++	u8 channel;
++	u8 mode;
++	u8 essid_len;
++	u8 essid[IW_ESSID_MAX_SIZE + 1]; /* null terminated for debug msg */
++
++	u16 capability;
++	u16 beacon_interval;
++
++	u8 rates_len;
++	u8 rates[MAX_RATES_LENGTH];
++	u8 rates_ex_len;
++	u8 rates_ex[MAX_RATES_EX_LENGTH];
++	u8 rssi;
++
++	/* scan results have sec_info instead of rsn_ie or wpa_ie */
++	u16 sec_info;
++};
++
++struct gelic_wireless {
++	struct gelic_net_card *card;
++	struct completion cmd_done, rssi_done;
++	struct work_struct work_event, work_start_done;
++	struct delayed_work work_rssi, work_scan_all, work_scan_essid;
++	struct delayed_work work_common, work_encode;
++	struct delayed_work work_start, work_stop, work_roam;
++	wait_queue_head_t waitq_cmd, waitq_scan;
++
++	u64 cmd_tag, cmd_id;
++	u8 cmd_send_flg;
++
++	struct iw_public_data wireless_data;
++	u8 *data_buf; /* data buffer for lv1_net_control */
++
++	u8 wireless; /* wireless support */
++	u8 state;
++	u8 scan_all; /* essid scan or all scan */
++	u8 essid_search; /* essid background scan */
++	u8 is_assoc;
++
++	u16 ch_info; /* supoprted channels */
++	u8 wireless_mode; /* 11b/g */
++	u8 channel; /* current ch */
++	u8 iw_mode; /* INFRA or Ad-hoc */
++	u8 rssi;
++	u8 essid_len;
++	u8 essid[IW_ESSID_MAX_SIZE + 1]; /* null terminated for debug msg */
++	u8 nick[IW_ESSID_MAX_SIZE + 1];
++	u8 bssid[ETH_ALEN];
++
++	u8 key_index;
++	u8 key[WEP_KEYS][IW_ENCODING_TOKEN_MAX]; /* 4 * 64byte */
++	u8 key_len[WEP_KEYS];
++	u8 key_alg; /* key algorithm  */
++	u8 auth_mode; /* authenticaton mode */
++
++	u8 bss_index; /* current bss in bss_list */
++	u8 num_bss_list;
++	u8 bss_key_alg; /* key alg of bss */
++	u8 wap_bssid[ETH_ALEN];
++	unsigned long last_scan; /* last scan time */
++	struct gelicw_bss current_bss;
++	struct gelicw_bss bss_list[MAX_SCAN_BSS];
++};
++
++/* net_control command */
++#define GELICW_SET_PORT			3 /* control Ether port */
++#define GELICW_GET_INFO			6 /* get supported channels */
++#define GELICW_SET_CMD			9 /* set configuration */
++#define GELICW_GET_RES			10 /* get command response */
++#define GELICW_GET_EVENT		11 /* get event from device */
++/* net_control command data buffer */
++#define GELICW_DATA_BUF_SIZE		0x1000
++
++/* GELICW_SET_CMD params */
++#define GELICW_CMD_START		1
++#define GELICW_CMD_STOP			2
++#define GELICW_CMD_SCAN			3
++#define GELICW_CMD_GET_SCAN		4
++#define GELICW_CMD_SET_CONFIG		5
++#define GELICW_CMD_GET_CONFIG		6
++#define GELICW_CMD_SET_WEP		7
++#define GELICW_CMD_GET_WEP		8
++#define GELICW_CMD_SET_WPA		9
++#define GELICW_CMD_GET_WPA		10
++#define GELICW_CMD_GET_RSSI		11
++
++/* GELICW_SET_PORT params */
++#define GELICW_ETHER_PORT		2
++#define GELICW_PORT_DOWN		0 /* Ether port off */
++#define GELICW_PORT_UP			4 /* Ether port on (auto neg) */
++
++/* interrupt status bit */
++#define GELICW_DEVICE_CMD_COMP		0x0000000080000000UL
++#define GELICW_DEVICE_EVENT_RECV	0x0000000040000000UL
++
++/* GELICW_GET_EVENT ID */
++#define GELICW_EVENT_UNKNOWN		0x00
++#define GELICW_EVENT_DEVICE_READY	0x01
++#define GELICW_EVENT_SCAN_COMPLETED	0x02
++#define GELICW_EVENT_DEAUTH		0x04
++#define GELICW_EVENT_BEACON_LOST	0x08
++#define GELICW_EVENT_CONNECTED		0x10
++#define GELICW_EVENT_WPA_CONNECTED	0x20
++#define GELICW_EVENT_WPA_ERROR		0x40
++#define GELICW_EVENT_NO_ENTRY		(-6)
++
++#define MAX_IW_PRIV_SIZE		32
++
++/* structure of data buffer for lv1_net_contol */
++/* wep_config: sec */
++#define GELICW_WEP_SEC_NONE		0
++#define GELICW_WEP_SEC_40BIT		1
++#define GELICW_WEP_SEC_104BIT		2
++struct wep_config {
++	u16 sec;
++	u8  key[4][16];
++} __attribute__ ((packed));
++
++/* wpa_config: sec */
++#define GELICW_WPA_SEC_NONE		0
++#define GELICW_WPA_SEC_TKIP		1
++#define GELICW_WPA_SEC_AES		2
++/* wpa_config: psk_type */
++#define GELICW_PSK_PASSPHRASE		0
++#define GELICW_PSK_64HEX		1
++struct wpa_config {
++	u16 sec;
++	u16 psk_type;
++	u8  psk_material[64]; /* key */
++} __attribute__ ((packed));
++
++/* common_config: bss_type */
++#define GELICW_BSS_INFRA		0
++#define GELICW_BSS_ADHOC		1
++/* common_config: auth_method */
++#define GELICW_AUTH_OPEN		0
++#define GELICW_AUTH_SHARED		1
++/* common_config: op_mode */
++#define GELICW_OP_MODE_11BG		0
++#define GELICW_OP_MODE_11B		1
++#define GELICW_OP_MODE_11G		2
++struct common_config {
++	u16 scan_index; /* index of scan_desc list */
++	u16 bss_type;
++	u16 auth_method;
++	u16 op_mode;
++} __attribute__ ((packed));
++
++/* scan_descriptor: security */
++#define GELICW_SEC_TYPE_NONE		0x0000
++#define GELICW_SEC_TYPE_WEP		0x0100
++#define GELICW_SEC_TYPE_WEP40		0x0101
++#define GELICW_SEC_TYPE_WEP104		0x0102
++#define GELICW_SEC_TYPE_TKIP		0x0201
++#define GELICW_SEC_TYPE_AES		0x0202
++#define GELICW_SEC_TYPE_WEP_MASK	0xFF00
++struct scan_desc {
++	u16 size;
++	u16 rssi;
++	u16 channel;
++	u16 beacon_period;
++	u16 capability;
++	u16 security;
++	u64 bssid;
++	u8  essid[32];
++	u8  rate[16];
++	u8  ext_rate[16];
++	u32 reserved1;
++	u32 reserved2;
++	u32 reserved3;
++	u32 reserved4;
++} __attribute__ ((packed));
++
++/* rssi_descriptor */
++struct rssi_desc {
++	u16 rssi; /* max rssi = 100 */
++} __attribute__ ((packed));
++
++
++extern unsigned long p_to_lp(long pa);
++extern int gelicw_setup_netdev(struct net_device *netdev, int wi);
++extern void gelicw_up(struct net_device *netdev);
++extern int gelicw_down(struct net_device *netdev);
++extern void gelicw_remove(struct net_device *netdev);
++extern void gelicw_interrupt(struct net_device *netdev, u32 status1);
++extern int gelicw_is_associated(struct net_device *netdev);
++
++#endif //  _GELIC_WIRELESS_H_

linux-2.6-ps3-gelic.patch:

Index: linux-2.6-ps3-gelic.patch
===================================================================
RCS file: linux-2.6-ps3-gelic.patch
diff -N linux-2.6-ps3-gelic.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-gelic.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,1964 @@
+As of 2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440):
+
+ps3-wip/ps3-gelic.patch
+ps3-wip/ps3-gelic-2.6.21-version-up.diff
+ps3-wip/ps3-gelic-system-bus.patch
+ps3-wip/ps3-gelic-fix-ipv6.diff
+
++ s/ip_hdr(skb)/skb->nh.iph/ to work on 2.6.21
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index dcdad21..7876697 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -2260,6 +2260,16 @@ config TSI108_ETH
+ 	     To compile this driver as a module, choose M here: the module
+ 	     will be called tsi108_eth.
+ 
++config GELIC_NET
++	tristate "PS3 Gigabit Ethernet driver"
++	depends on PPC_PS3
++	help
++	  This driver supports the Gigabit Ethernet device on the
++	  PS3 game console.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called gelic_net.
++
+ config GIANFAR
+ 	tristate "Gianfar Ethernet"
+ 	depends on 85xx || 83xx || PPC_86xx
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index 59c0459..9fa106a 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -60,6 +60,7 @@ obj-$(CONFIG_TIGON3) += tg3.o
+ obj-$(CONFIG_BNX2) += bnx2.o
+ spidernet-y += spider_net.o spider_net_ethtool.o
+ obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
++obj-$(CONFIG_GELIC_NET) += gelic_net.o
+ obj-$(CONFIG_TC35815) += tc35815.o
+ obj-$(CONFIG_SKGE) += skge.o
+ obj-$(CONFIG_SKY2) += sky2.o
+--- /dev/null	2007-05-01 15:16:24.100521312 +0100
++++ b/drivers/net/gelic_net.c	2007-05-04 11:35:42.000000000 +0100
+@@ -0,0 +1,1919 @@
++/*
++ *  PS3 Platfom gelic network driver.
++ *
++ * Copyright (C) 2006 Sony Computer Entertainment Inc.
++ *
++ *  this file is based on: spider_net.c
++ *
++ * Network device driver for Cell Processor-Based Blade
++ *
++ * (C) Copyright IBM Corp. 2005
++ *
++ * Authors : Utz Bacher <utz.bacher at de.ibm.com>
++ *           Jens Osterkamp <Jens.Osterkamp at de.ibm.com>
++ *
++ * 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, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#define DEBUG 1
++
++#include <linux/compiler.h>
++#include <linux/crc32.h>
++#include <linux/delay.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/firmware.h>
++#include <linux/if_vlan.h>
++#include <linux/in.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/ip.h>
++#include <linux/kernel.h>
++#include <linux/mii.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/device.h>
++#include <linux/pci.h>
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/tcp.h>
++#include <linux/types.h>
++#include <linux/wait.h>
++#include <linux/workqueue.h>
++#include <asm/bitops.h>
++#include <asm/pci-bridge.h>
++#include <net/checksum.h>
++#include <asm/io.h>
++#include <asm/firmware.h>
++#include <asm/ps3.h>
++#include <asm/lv1call.h>
++
++#define GELIC_NET_DRV_NAME "Gelic Network Driver"
++#define GELIC_NET_DRV_VERSION "1.0"
++
++#define GELIC_NET_DEBUG
++
++#ifdef GELIC_NET_DEBUG
++#define DPRINTK(fmt,arg...)   printk(KERN_ERR fmt ,##arg)
++#define DPRINTKK(fmt,arg...)  printk(KERN_ERR fmt ,##arg)
++#else
++#define DPRINTK(fmt,arg...)
++#define DPRINTKK(fmt,arg...)
++#endif
++
++#define GELIC_NET_ETHTOOL               /* use ethtool */
++
++/* ioctl */
++#define GELIC_NET_GET_MODE              (SIOCDEVPRIVATE + 0)
++#define GELIC_NET_SET_MODE              (SIOCDEVPRIVATE + 1)
++
++/* descriptors */
++#define GELIC_NET_RX_DESCRIPTORS        128 /* num of descriptors */
++#define GELIC_NET_TX_DESCRIPTORS        128 /* num of descriptors */
++
++#define GELIC_NET_MAX_MTU               2308
++#define GELIC_NET_MIN_MTU               64
++#define GELIC_NET_RXBUF_ALIGN           128
++#define GELIC_NET_RX_CSUM_DEFAULT       1 /* hw chksum */
++#define GELIC_NET_WATCHDOG_TIMEOUT      5*HZ
++#define GELIC_NET_NAPI_WEIGHT           64
++#define GELIC_NET_BROADCAST_ADDR        0xffffffffffff
++#define GELIC_NET_VLAN_POS              (VLAN_ETH_ALEN * 2)
++#define GELIC_NET_VLAN_MAX              4
++#define GELIC_NET_MC_COUNT_MAX          32 /* multicast address list */
++
++enum gelic_net_int0_status {
++	GELIC_NET_GDTDCEINT  = 24,
++	GELIC_NET_GRFANMINT  = 28,
++};
++
++/* GHIINT1STS bits */
++enum gelic_net_int1_status {
++	GELIC_NET_GDADCEINT = 14,
++};
++
++/* interrupt mask */
++#define GELIC_NET_TXINT                   (1L << (GELIC_NET_GDTDCEINT + 32))
++
++#define GELIC_NET_RXINT0                  (1L << (GELIC_NET_GRFANMINT + 32))
++#define GELIC_NET_RXINT1                  (1L << GELIC_NET_GDADCEINT)
++#define GELIC_NET_RXINT                   (GELIC_NET_RXINT0 | GELIC_NET_RXINT1)
++
++ /* descriptor data_status bits */
++#define GELIC_NET_RXIPCHK                 29
++#define GELIC_NET_TCPUDPIPCHK             28
++#define GELIC_NET_DATA_STATUS_CHK_MASK    (1 << GELIC_NET_RXIPCHK | \
++                                           1 << GELIC_NET_TCPUDPIPCHK)
++
++/* descriptor data_error bits */
++#define GELIC_NET_RXIPCHKERR              27
++#define GELIC_NET_RXTCPCHKERR             26
++#define GELIC_NET_DATA_ERROR_CHK_MASK     (1 << GELIC_NET_RXIPCHKERR | \
++                                           1 << GELIC_NET_RXTCPCHKERR)
++
++#define GELIC_NET_DMAC_CMDSTAT_NOCS       0xa0080000 /* middle of frame */
++#define GELIC_NET_DMAC_CMDSTAT_TCPCS      0xa00a0000
++#define GELIC_NET_DMAC_CMDSTAT_UDPCS      0xa00b0000
++#define GELIC_NET_DMAC_CMDSTAT_END_FRAME  0x00040000 /* end of frame */
++
++#define GELIC_NET_DMAC_CMDSTAT_CHAIN_END  0x00000002 /* RXDCEIS:DMA stopped */
++
++#define GELIC_NET_DESCR_IND_PROC_SHIFT    28
++#define GELIC_NET_DESCR_IND_PROC_MASKO    0x0fffffff
++
++/* ignore ipsec ans multicast */
++#define GELIC_NET_DATA_ERROR_MASK         0xfdefbfff
++/* ignore unmatched sp on sp, drop_packet, multicast address frame*/
++#define GELIC_NET_DATA_ERROR_FLG          0x7def8000
++
++enum gelic_net_descr_status {
++	GELIC_NET_DESCR_COMPLETE            = 0x00, /* used in rx and tx */
++	GELIC_NET_DESCR_RESPONSE_ERROR      = 0x01, /* used in rx and tx */
++	GELIC_NET_DESCR_PROTECTION_ERROR    = 0x02, /* used in rx and tx */
++	GELIC_NET_DESCR_FRAME_END           = 0x04, /* used in rx */
++	GELIC_NET_DESCR_FORCE_END           = 0x05, /* used in rx and tx */
++	GELIC_NET_DESCR_CARDOWNED           = 0x0a, /* used in rx and tx */
++	GELIC_NET_DESCR_NOT_IN_USE                  /* any other value */
++};
++#define GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE 0xb0000000
++
++#define GELIC_NET_DESCR_SIZE              32
++struct gelic_net_descr {
++	/* as defined by the hardware */
++	uint32_t buf_addr;
++	uint32_t buf_size;
++	uint32_t next_descr_addr;
++	uint32_t dmac_cmd_status;
++	uint32_t result_size;
++	uint32_t valid_size;	/* all zeroes for tx */
++	uint32_t data_status;
++	uint32_t data_error;	/* all zeroes for tx */
++
++	/* used in the driver */
++	struct sk_buff *skb;
++	dma_addr_t bus_addr;
++	struct gelic_net_descr *next;
++	struct gelic_net_descr *prev;
++	struct vlan_ethhdr vlan;
++} __attribute__((aligned(32)));
++
++struct gelic_net_descr_chain {
++	/* we walk from tail to head */
++	struct gelic_net_descr *head;
++	struct gelic_net_descr *tail;
++	spinlock_t lock;
++};
++
++struct gelic_net_card {
++	struct net_device *netdev;
++	uint64_t ghiintmask;
++	struct ps3_system_bus_device *dev;
++	uint32_t vlan_id[GELIC_NET_VLAN_MAX];
++	int vlan_index;
++
++	struct gelic_net_descr_chain tx_chain;
++	struct gelic_net_descr_chain rx_chain;
++	spinlock_t chain_lock;
++
++	struct net_device_stats netdev_stats;
++	int rx_csum;
++	spinlock_t intmask_lock;
++
++	struct work_struct tx_timeout_task;
++	atomic_t tx_timeout_task_counter;
++	wait_queue_head_t waitq;
++
++	struct gelic_net_descr *tx_top, *rx_top;
++
++	struct gelic_net_descr descr[0];
++};
++
++static int ps3_gelic_param = 1; /* vlan desc support */
++#ifdef CONFIG_GELIC_NET_MODULE
++module_param(ps3_gelic_param, int, S_IRUGO);
++#endif
++
++struct gelic_net_card *gcard;
++static uint64_t gelic_irq_status;
++
++static int dmac_status = 0;
++
++/* for lv1_net_control */
++#define GELIC_NET_GET_MAC_ADDRESS               0x0000000000000001
++#define GELIC_NET_GET_ETH_PORT_STATUS           0x0000000000000002
++#define GELIC_NET_SET_NEGOTIATION_MODE          0x0000000000000003
++#define GELIC_NET_GET_VLAN_ID                   0x0000000000000004
++
++#define GELIC_NET_LINK_UP                       0x0000000000000001
++#define GELIC_NET_FULL_DUPLEX                   0x0000000000000002
++#define GELIC_NET_AUTO_NEG                      0x0000000000000004
++#define GELIC_NET_SPEED_10                      0x0000000000000010
++#define GELIC_NET_SPEED_100                     0x0000000000000020
++#define GELIC_NET_SPEED_1000                    0x0000000000000040
++
++#define GELIC_NET_VLAN_ALL                      0x0000000000000001
++#define GELIC_NET_VLAN_WIRED                    0x0000000000000002
++#define GELIC_NET_VLAN_WIRELESS                 0x0000000000000003
++#define GELIC_NET_VLAN_PSP                      0x0000000000000004
++#define GELIC_NET_VLAN_PORT0                    0x0000000000000010
++#define GELIC_NET_VLAN_PORT1                    0x0000000000000011
++#define GELIC_NET_VLAN_PORT2                    0x0000000000000012
++#define GELIC_NET_VLAN_DAEMON_CLIENT_BSS        0x0000000000000013
++#define GELIC_NET_VLAN_LIBERO_CLIENT_BSS        0x0000000000000014
++#define GELIC_NET_VLAN_NO_ENTRY                 -6
++
++#define GELIC_NET_PORT                          2 /* for port status */
++
++
++MODULE_AUTHOR("SCE Inc.");
++MODULE_DESCRIPTION("Gelic Network driver");
++MODULE_LICENSE("GPL");
++
++static int rx_descriptors = GELIC_NET_RX_DESCRIPTORS;
++static int tx_descriptors = GELIC_NET_TX_DESCRIPTORS;
++
++
++/* set irq_mask */
++static int
++gelic_net_set_irq_mask(struct gelic_net_card *card, uint64_t mask)
++{
++	uint64_t status = 0;
++
++	status = lv1_net_set_interrupt_mask(card->dev->did.bus_id,
++		card->dev->did.dev_id, mask, 0);
++	if (status) {
++		printk("lv1_net_set_interrupt_mask failed, status=%ld\n",
++			status);
++	}
++	return status;
++}
++
++/**
++ * gelic_net_get_descr_status -- returns the status of a descriptor
++ * @descr: descriptor to look at
++ *
++ * returns the status as in the dmac_cmd_status field of the descriptor
++ */
++enum gelic_net_descr_status
++gelic_net_get_descr_status(struct gelic_net_descr *descr)
++{
++	uint32_t cmd_status;
++
++	rmb();
++	cmd_status = descr->dmac_cmd_status;
++	rmb();
++	cmd_status >>= GELIC_NET_DESCR_IND_PROC_SHIFT;
++	return cmd_status;
++}
++
++/**
++ * gelic_net_set_descr_status -- sets the status of a descriptor
++ * @descr: descriptor to change
++ * @status: status to set in the descriptor
++ *
++ * changes the status to the specified value. Doesn't change other bits
++ * in the status
++ */
++static void
++gelic_net_set_descr_status(struct gelic_net_descr *descr,
++			    enum gelic_net_descr_status status)
++{
++	uint32_t cmd_status;
++
++	/* read the status */
++	mb();
++	cmd_status = descr->dmac_cmd_status;
++	/* clean the upper 4 bits */
++	cmd_status &= GELIC_NET_DESCR_IND_PROC_MASKO;
++	/* add the status to it */
++	cmd_status |= ((uint32_t)status)<<GELIC_NET_DESCR_IND_PROC_SHIFT;
++	/* and write it back */
++	descr->dmac_cmd_status = cmd_status;
++	wmb();
++}
++
++/**
++ * gelic_net_free_chain - free descriptor chain
++ * @card: card structure
++ * @descr_in: address of desc
++ */
++static void
++gelic_net_free_chain(struct gelic_net_card *card,
++		      struct gelic_net_descr *descr_in)
++{
++	struct gelic_net_descr *descr;
++
++	for (descr = descr_in; descr && !descr->bus_addr; descr = descr->next) {
++		dma_unmap_single(&card->dev->core, descr->bus_addr,
++				 GELIC_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
++		descr->bus_addr = 0;
++	}
++}
++
++/**
++ * gelic_net_init_chain - links descriptor chain
++ * @card: card structure
++ * @chain: address of chain
++ * @start_descr: address of descriptor array
++ * @no: number of descriptors
++ *
++ * we manage a circular list that mirrors the hardware structure,
++ * except that the hardware uses bus addresses.
++ *
++ * returns 0 on success, <0 on failure
++ */
++static int
++gelic_net_init_chain(struct gelic_net_card *card,
++		       struct gelic_net_descr_chain *chain,
++		       struct gelic_net_descr *start_descr, int no)
++{
++	int i;
++	struct gelic_net_descr *descr;
++
++	spin_lock_init(&chain->lock);
++	descr = start_descr;
++	memset(descr, 0, sizeof(*descr) * no);
++
++	/* set up the hardware pointers in each descriptor */
++	for (i=0; i<no; i++, descr++) {
++		gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
++		descr->bus_addr =
++			dma_map_single(&card->dev->core, descr,
++				       GELIC_NET_DESCR_SIZE,
++				       PCI_DMA_BIDIRECTIONAL);
++
++		if (descr->bus_addr == DMA_ERROR_CODE)
++			goto iommu_error;
++
++		descr->next = descr + 1;
++		descr->prev = descr - 1;
++	}
++	/* do actual chain list */
++	(descr-1)->next = start_descr;
++	start_descr->prev = (descr-1);
++
++	descr = start_descr;
++	for (i=0; i < no; i++, descr++) {
++		if (descr->next) {
++			descr->next_descr_addr = descr->next->bus_addr;
++		} else {
++			descr->next_descr_addr = 0;
++		}
++	}
++
++	chain->head = start_descr;
++	chain->tail = start_descr;
++	(descr-1)->next_descr_addr = 0; /* last descr */
++	return 0;
++
++iommu_error:
++	descr = start_descr;
++	for (i=0; i < no; i++, descr++)
++		if (descr->bus_addr)
++			dma_unmap_single(&card->dev->core, descr->bus_addr,
++					 GELIC_NET_DESCR_SIZE,
++					 PCI_DMA_BIDIRECTIONAL);
++	return -ENOMEM;
++}
++
++/**
++ * gelic_net_prepare_rx_descr - reinitializes a rx descriptor
++ * @card: card structure
++ * @descr: descriptor to re-init
++ *
++ * return 0 on succes, <0 on failure
++ *
++ * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
++ * Activate the descriptor state-wise
++ */
++static int
++gelic_net_prepare_rx_descr(struct gelic_net_card *card,
++			    struct gelic_net_descr *descr)
++{
++	dma_addr_t buf;
++	int error = 0;
++	int offset;
++	int bufsize;
++
++	if( gelic_net_get_descr_status(descr) !=  GELIC_NET_DESCR_NOT_IN_USE) {
++		printk("%s: ERROR status \n", __FUNCTION__);
++	}
++	/* we need to round up the buffer size to a multiple of 128 */
++	bufsize = (GELIC_NET_MAX_MTU + GELIC_NET_RXBUF_ALIGN - 1) &
++		(~(GELIC_NET_RXBUF_ALIGN - 1));
++
++	/* and we need to have it 128 byte aligned, therefore we allocate a
++	 * bit more */
++	/* allocate an skb */
++	descr->skb = dev_alloc_skb(bufsize + GELIC_NET_RXBUF_ALIGN - 1);
++	if (!descr->skb) {
++		if (net_ratelimit())
++			printk("Not enough memory to allocate rx buffer\n");
++		return -ENOMEM;
++	}
++	descr->buf_size = bufsize;
++	descr->dmac_cmd_status = 0;
++	descr->result_size = 0;
++	descr->valid_size = 0;
++	descr->data_error = 0;
++
++	offset = ((unsigned long)descr->skb->data) &
++		(GELIC_NET_RXBUF_ALIGN - 1);
++	if (offset)
++		skb_reserve(descr->skb, GELIC_NET_RXBUF_ALIGN - offset);
++	/* io-mmu-map the skb */
++	buf = dma_map_single(&card->dev->core, descr->skb->data,
++					GELIC_NET_MAX_MTU,
++					PCI_DMA_BIDIRECTIONAL);
++	descr->buf_addr = buf;
++	if (buf == DMA_ERROR_CODE) {
++		dev_kfree_skb_any(descr->skb);
++		printk("Could not iommu-map rx buffer\n");
++		gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
++	} else {
++		gelic_net_set_descr_status(descr, GELIC_NET_DESCR_CARDOWNED);
++	}
++
++	return error;
++}
++
++/**
++ * gelic_net_release_rx_chain - free all rx descr
++ * @card: card structure
++ *
++ */
++static void
++gelic_net_release_rx_chain(struct gelic_net_card *card)
++{
++	struct gelic_net_descr_chain *chain = &card->rx_chain;
++
++	while(chain->tail != chain->head) {
++		if (chain->tail->skb) {
++			dma_unmap_single(&card->dev->core,
++						chain->tail->buf_addr,
++						chain->tail->skb->len,
++						PCI_DMA_BIDIRECTIONAL);
++			chain->tail->buf_addr = 0;
++			dev_kfree_skb_any(chain->tail->skb);
++			chain->tail->skb = NULL;
++			chain->tail->dmac_cmd_status =
++						GELIC_NET_DESCR_NOT_IN_USE;
++			chain->tail = chain->tail->next;
++		}
++	}
++}
++
++/**
++ * gelic_net_enable_rxdmac - enables a receive DMA controller
++ * @card: card structure
++ *
++ * gelic_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
++ * in the GDADMACCNTR register
++ */
++static void
++gelic_net_enable_rxdmac(struct gelic_net_card *card)
++{
++	uint64_t status;
++
++	status = lv1_net_start_rx_dma(card->dev->did.bus_id,
++				card->dev->did.dev_id,
++				(uint64_t)card->rx_chain.tail->bus_addr, 0);
++	if (status) {
++		printk("lv1_net_start_rx_dma failed, status=%ld\n", status);
++	}
++}
++
++/**
++ * gelic_net_refill_rx_chain - refills descriptors/skbs in the rx chains
++ * @card: card structure
++ *
++ * refills descriptors in all chains (last used chain first): allocates skbs
++ * and iommu-maps them.
++ */
++static void
++gelic_net_refill_rx_chain(struct gelic_net_card *card)
++{
++	struct gelic_net_descr_chain *chain;
++	int count = 0;
++
++	chain = &card->rx_chain;
++	while (chain->head && gelic_net_get_descr_status(chain->head) ==
++		GELIC_NET_DESCR_NOT_IN_USE) {
++		if (gelic_net_prepare_rx_descr(card, chain->head))
++			break;
++		count++;
++		chain->head = chain->head->next;
++	}
++}
++
++/**
++ * gelic_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
++ * @card: card structure
++ *
++ * returns 0 on success, <0 on failure
++ */
++static int
++gelic_net_alloc_rx_skbs(struct gelic_net_card *card)
++{
++	struct gelic_net_descr_chain *chain;
++
++	chain = &card->rx_chain;
++	gelic_net_refill_rx_chain(card);
++	chain->head = card->rx_top->prev; /* point to the last */
++	return 0;
++}
++
++/**
++ * gelic_net_release_tx_descr - processes a used tx descriptor
++ * @card: card structure
++ * @descr: descriptor to release
++ *
++ * releases a used tx descriptor (unmapping, freeing of skb)
++ */
++static void
++gelic_net_release_tx_descr(struct gelic_net_card *card,
++			    struct gelic_net_descr *descr)
++{
++	struct sk_buff *skb;
++
++  if (!ps3_gelic_param) {
++	/* unmap the skb */
++	skb = descr->skb;
++	dma_unmap_single(&card->dev->core, descr->buf_addr, skb->len,
++			 PCI_DMA_BIDIRECTIONAL);
++
++	dev_kfree_skb_any(skb);
++  } else {
++	if ((descr->data_status & 0x00000001) == 1) { /* end of frame */
++		skb = descr->skb;
++		dma_unmap_single(&card->dev->core, descr->buf_addr, skb->len,
++			 PCI_DMA_BIDIRECTIONAL);
++		dev_kfree_skb_any(skb);
++	} else {
++		dma_unmap_single(&card->dev->core, descr->buf_addr,
++			descr->buf_size, PCI_DMA_BIDIRECTIONAL);
++	}
++  }
++	descr->buf_addr = 0;
++	descr->buf_size = 0;
++	descr->next_descr_addr = 0;
++	descr->result_size = 0;
++	descr->valid_size = 0;
++	descr->data_status = 0;
++	descr->data_error = 0;
++	descr->skb = NULL;
++	card->tx_chain.tail = card->tx_chain.tail->next;
++
++	/* set descr status */
++	descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE;
++}
++
++/**
++ * gelic_net_release_tx_chain - processes sent tx descriptors
++ * @card: adapter structure
++ * @stop: net_stop sequence
++ *
++ * releases the tx descriptors that gelic has finished with
++ */
++static void
++gelic_net_release_tx_chain(struct gelic_net_card *card, int stop)
++{
++	struct gelic_net_descr_chain *tx_chain = &card->tx_chain;
++	enum gelic_net_descr_status status;
++	int release = 0;
++
++	for (;tx_chain->head != tx_chain->tail && tx_chain->tail;) {
++		status = gelic_net_get_descr_status(tx_chain->tail);
++		switch (status) {
++		case GELIC_NET_DESCR_RESPONSE_ERROR:
++		case GELIC_NET_DESCR_PROTECTION_ERROR:
++		case GELIC_NET_DESCR_FORCE_END:
++			printk("%s: forcing end of tx descriptor "
++			       "with status x%02x\n",
++			       card->netdev->name, status);
++			card->netdev_stats.tx_dropped++;
++			break;
++
++		case GELIC_NET_DESCR_COMPLETE:
++			card->netdev_stats.tx_packets++;
++			card->netdev_stats.tx_bytes +=
++				tx_chain->tail->skb->len;
++			break;
++
++		case GELIC_NET_DESCR_CARDOWNED:
++		default: /* any other value (== GELIC_NET_DESCR_NOT_IN_USE) */
++			goto out;
++		}
++		gelic_net_release_tx_descr(card, tx_chain->tail);
++		release = 1;
++	}
++out:
++	/* status NOT_IN_USE or chain end */
++	if (!tx_chain->tail) {
++		/* release all chains */
++		if(card->tx_chain.head) printk("ERROR tx_chain.head is NULL\n");
++		card->tx_chain.tail = card->tx_top;
++		card->tx_chain.head = card->tx_top;
++	}
++	if (!stop && release && netif_queue_stopped(card->netdev)) {
++		netif_wake_queue(card->netdev);
++	}
++}
++
++/**
++ * gelic_net_set_multi - sets multicast addresses and promisc flags
++ * @netdev: interface device structure
++ *
++ * gelic_net_set_multi configures multicast addresses as needed for the
++ * netdev interface. It also sets up multicast, allmulti and promisc
++ * flags appropriately
++ */
++static void
++gelic_net_set_multi(struct net_device *netdev)
++{
++	int i;
++	uint8_t *p;
++	uint64_t addr, status;
++	struct dev_mc_list *mc;
++	struct gelic_net_card *card = netdev_priv(netdev);
++
++	/* clear all multicast address */
++	status = lv1_net_remove_multicast_address(card->dev->did.bus_id,
++				card->dev->did.dev_id, 0, 1);
++	if (status) {
++		printk("lv1_net_remove_multicast_address failed, status=%ld\n",\
++			status);
++	}
++	/* set broadcast address */
++	status = lv1_net_add_multicast_address(card->dev->did.bus_id,
++			card->dev->did.dev_id, GELIC_NET_BROADCAST_ADDR, 0);
++	if (status) {
++		printk("lv1_net_add_multicast_address failed, status=%ld\n",\
++			status);
++	}
++
++	if (netdev->flags & IFF_ALLMULTI
++		|| netdev->mc_count > GELIC_NET_MC_COUNT_MAX) { /* list max */
++		status = lv1_net_add_multicast_address(card->dev->did.bus_id,
++				card->dev->did.dev_id,
++				0, 1);
++		if (status) {
++			printk("lv1_net_add_multicast_address failed, status=%ld\n",\
++				status);
++		}
++		return ;
++	}
++
++	/* set multicalst address */
++	for ( mc = netdev->mc_list; mc; mc = mc->next) {
++		addr = 0;
++		p = mc->dmi_addr;
++		for (i = 0; i < ETH_ALEN; i++) {
++			addr <<= 8;
++			addr |= *p++;
++		}
++		status = lv1_net_add_multicast_address(card->dev->did.bus_id,
++				card->dev->did.dev_id,
++				addr, 0);
++		if (status) {
++			printk("lv1_net_add_multicast_address failed, status=%ld\n",\
++				status);
++		}
++	}
++}
++
++/**
++ * gelic_net_disable_rxdmac - disables the receive DMA controller
++ * @card: card structure
++ *
++ * gelic_net_disable_rxdmac terminates processing on the DMA controller by
++ * turing off DMA and issueing a force end
++ */
++static void
++gelic_net_disable_rxdmac(struct gelic_net_card *card)
++{
++	uint64_t status;
++
++	status = lv1_net_stop_rx_dma(card->dev->did.bus_id,
++		card->dev->did.dev_id, 0);
++	if (status) {
++		printk("lv1_net_stop_rx_dma faild, status=%ld\n", status);
++	}
++}
++
++/**
++ * gelic_net_disable_txdmac - disables the transmit DMA controller
++ * @card: card structure
++ *
++ * gelic_net_disable_txdmac terminates processing on the DMA controller by
++ * turing off DMA and issueing a force end
++ */
++static void
++gelic_net_disable_txdmac(struct gelic_net_card *card)
++{
++	uint64_t status;
++
++	status = lv1_net_stop_tx_dma(card->dev->did.bus_id,
++		card->dev->did.dev_id, 0);
++	if (status) {
++		printk("lv1_net_stop_tx_dma faild, status=%ld\n", status);
++	}
++}
++
++/**
++ * gelic_net_stop - called upon ifconfig down
++ * @netdev: interface device structure
++ *
++ * always returns 0
++ */
++int
++gelic_net_stop(struct net_device *netdev)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++
++	netif_poll_disable(netdev);
++	netif_stop_queue(netdev);
++
++	/* turn off DMA, force end */
++	gelic_net_disable_rxdmac(card);
++	gelic_net_disable_txdmac(card);
++
++	gelic_net_set_irq_mask(card, 0);
++
++	/* disconnect event port */
++	free_irq(card->netdev->irq, card->netdev);
++	ps3_sb_event_receive_port_destroy(&card->dev->did,
++		card->dev->interrupt_id, card->netdev->irq);
++	card->netdev->irq = NO_IRQ;
++
++	netif_carrier_off(netdev);
++
++	/* release chains */
++	gelic_net_release_tx_chain(card, 1);
++	gelic_net_release_rx_chain(card);
++
++	gelic_net_free_chain(card, card->tx_top);
++	gelic_net_free_chain(card, card->rx_top);
++
++	return 0;
++}
++
++/**
++ * gelic_net_get_next_tx_descr - returns the next available tx descriptor
++ * @card: device structure to get descriptor from
++ *
++ * returns the address of the next descriptor, or NULL if not available.
++ */
++static struct gelic_net_descr *
++gelic_net_get_next_tx_descr(struct gelic_net_card *card)
++{
++	if (card->tx_chain.head == NULL) return NULL;
++	/* check, if head points to not-in-use descr */
++  if (!ps3_gelic_param) {
++	if ( card->tx_chain.tail != card->tx_chain.head->next
++		&& gelic_net_get_descr_status(card->tx_chain.head) ==
++		     GELIC_NET_DESCR_NOT_IN_USE ) {
++		return card->tx_chain.head;
++	} else {
++		return NULL;
++	}
++  } else {
++	if ( card->tx_chain.tail != card->tx_chain.head->next
++		&& card->tx_chain.tail != card->tx_chain.head->next->next
++		&& gelic_net_get_descr_status(card->tx_chain.head) ==
++		     GELIC_NET_DESCR_NOT_IN_USE
++		&& gelic_net_get_descr_status(card->tx_chain.head->next) ==
++		     GELIC_NET_DESCR_NOT_IN_USE ) {
++		return card->tx_chain.head;
++	} else {
++		return NULL;
++	}
++  }
++}
++
++/**
++ * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
++ * @descr: descriptor structure to fill out
++ * @skb: packet to consider
++ * @middle: middle of frame
++ *
++ * fills out the command and status field of the descriptor structure,
++ * depending on hardware checksum settings. This function assumes a wmb()
++ * has executed before.
++ */
++static void
++gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr,
++			       struct sk_buff *skb, int middle)
++{
++	uint32_t nocs, tcpcs, udpcs;
++
++	if (middle) {
++		nocs =  GELIC_NET_DMAC_CMDSTAT_NOCS;
++		tcpcs = GELIC_NET_DMAC_CMDSTAT_TCPCS;
++		udpcs = GELIC_NET_DMAC_CMDSTAT_UDPCS;
++	}else {
++		nocs =  GELIC_NET_DMAC_CMDSTAT_NOCS
++			| GELIC_NET_DMAC_CMDSTAT_END_FRAME;
++		tcpcs = GELIC_NET_DMAC_CMDSTAT_TCPCS
++			| GELIC_NET_DMAC_CMDSTAT_END_FRAME;
++		udpcs = GELIC_NET_DMAC_CMDSTAT_UDPCS
++			| GELIC_NET_DMAC_CMDSTAT_END_FRAME;
++	}
++
++	if (skb->ip_summed != CHECKSUM_PARTIAL) {
++		descr->dmac_cmd_status = nocs;
++	} else {
++		/* is packet ip?
++		 * if yes: tcp? udp? */
++		if (skb->protocol == htons(ETH_P_IP)) {
++			if (skb->nh.iph->protocol == IPPROTO_TCP) {
++				descr->dmac_cmd_status = tcpcs;
++			} else if (skb->nh.iph->protocol == IPPROTO_UDP) {
++				descr->dmac_cmd_status = udpcs;
++			} else { /* the stack should checksum non-tcp and non-udp
++				    packets on his own: NETIF_F_IP_CSUM */
++				descr->dmac_cmd_status = nocs;
++			}
++		}
++	}
++}
++
++/**
++ * gelic_net_prepare_tx_descr - get dma address of skb_data
++ * @card: card structure
++ * @descr: descriptor structure
++ * @skb: packet to use
++ *
++ * returns 0 on success, <0 on failure.
++ *
++ */
++static int
++gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
++			    struct gelic_net_descr *descr,
++			    struct sk_buff *skb)
++{
++	dma_addr_t buf;
++	uint8_t *hdr;
++	struct vlan_ethhdr *v_hdr;
++	int vlan_len;
++
++	if (skb->len < GELIC_NET_VLAN_POS) {
++		printk("error: skb->len:%d\n", skb->len);
++		return -EINVAL;
++	}
++	hdr = skb->data;
++	v_hdr = (struct vlan_ethhdr *)skb->data;
++	memcpy(&descr->vlan, v_hdr, GELIC_NET_VLAN_POS);
++	if (card->vlan_index != -1) {
++		descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/
++		descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]);
++		vlan_len = GELIC_NET_VLAN_POS + VLAN_HLEN; /* VLAN_HLEN=4 */
++	} else {
++		vlan_len = GELIC_NET_VLAN_POS; /* no vlan tag */
++	}
++
++	/* first descr */
++	buf = dma_map_single(&card->dev->core, &descr->vlan,
++					 vlan_len, PCI_DMA_BIDIRECTIONAL);
++
++	if (buf == DMA_ERROR_CODE) {
++		printk("could not iommu-map packet (%p, %i). "
++			  "Dropping packet\n", v_hdr, vlan_len);
++		return -ENOMEM;
++	}
++
++	descr->buf_addr = buf;
++	descr->buf_size = vlan_len;
++	descr->skb = skb; /* not used */
++	descr->data_status = 0;
++	gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
++
++	/* second descr */
++	card->tx_chain.head = card->tx_chain.head->next;
++	descr->next_descr_addr = descr->next->bus_addr;
++	descr = descr->next;
++	if (gelic_net_get_descr_status(descr) !=
++			GELIC_NET_DESCR_NOT_IN_USE) {
++		printk("ERROR descr()\n"); /* XXX will be removed */
++	}
++	buf = dma_map_single(&card->dev->core, hdr + GELIC_NET_VLAN_POS,
++				skb->len - GELIC_NET_VLAN_POS,
++				PCI_DMA_BIDIRECTIONAL);
++
++	if (buf == DMA_ERROR_CODE) {
++		printk("could not iommu-map packet (%p, %i). "
++			  "Dropping packet\n", hdr + GELIC_NET_VLAN_POS,
++			  skb->len - GELIC_NET_VLAN_POS);
++		return -ENOMEM;
++	}
++
++	descr->buf_addr = buf;
++	descr->buf_size = skb->len - GELIC_NET_VLAN_POS;
++	descr->skb = skb;
++	descr->data_status = 0;
++	descr->next_descr_addr= 0;
++	gelic_net_set_txdescr_cmdstat(descr,skb, 0);
++
++	return 0;
++}
++
++static int
++gelic_net_prepare_tx_descr(struct gelic_net_card *card,
++			    struct gelic_net_descr *descr,
++			    struct sk_buff *skb)
++{
++	dma_addr_t buf = dma_map_single(&card->dev->core, skb->data,
++					 skb->len, PCI_DMA_BIDIRECTIONAL);
++
++	if (buf == DMA_ERROR_CODE) {
++		printk("could not iommu-map packet (%p, %i). "
++			  "Dropping packet\n", skb->data, skb->len);
++		return -ENOMEM;
++	}
++
++	descr->buf_addr = buf;
++	descr->buf_size = skb->len;
++	descr->skb = skb;
++	descr->data_status = 0;
++
++	return 0;
++}
++
++static void
++gelic_net_set_frame_end(struct gelic_net_card *card,
++		struct gelic_net_descr *descr, struct sk_buff *skb)
++{
++	descr->next_descr_addr= 0;
++	gelic_net_set_txdescr_cmdstat(descr,skb, 0);
++	wmb();
++	if (descr->prev) {
++		descr->prev->next_descr_addr = descr->bus_addr;
++	}
++}
++
++/**
++ * gelic_net_kick_txdma - enables TX DMA processing
++ * @card: card structure
++ * @descr: descriptor address to enable TX processing at
++ *
++ */
++static void
++gelic_net_kick_txdma(struct gelic_net_card *card,
++		       struct gelic_net_descr *descr)
++{
++	uint64_t status = -1;
++	int count = 10;
++
++	if (dmac_status) {
++		return ;
++	}
++
++	if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) {
++		/* kick */
++		dmac_status = 1;
++
++		while(count--) {
++			status = lv1_net_start_tx_dma(card->dev->did.bus_id,
++					card->dev->did.dev_id,
++					(uint64_t)descr->bus_addr, 0);
++			if (!status) {
++				break;
++			}
++		}
++		if (!count) {
++			printk("lv1_net_start_txdma failed, status=%ld %016lx\n",\
++				status, gelic_irq_status);
++		}
++	}
++}
++
++/**
++ * gelic_net_xmit - transmits a frame over the device
++ * @skb: packet to send out
++ * @netdev: interface device structure
++ *
++ * returns 0 on success, <0 on failure
++ */
++static int
++gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++	struct gelic_net_descr *descr = NULL;
++	int result;
++	unsigned long flags;
++
++	spin_lock_irqsave(&card->intmask_lock, flags);
++
++	gelic_net_release_tx_chain(card, 0);
++	if (skb == NULL){
++		goto kick;
++	}
++	descr = gelic_net_get_next_tx_descr(card); /* get tx_chain.head */
++	if (!descr) {
++		netif_stop_queue(netdev);
++		spin_unlock_irqrestore(&card->intmask_lock, flags);
++		return 1;
++	}
++  if (!ps3_gelic_param) {
++	result = gelic_net_prepare_tx_descr(card, descr, skb);
++  } else {
++	result = gelic_net_prepare_tx_descr_v(card, descr, skb);
++  }
++	if (result)
++		goto error;
++
++	card->tx_chain.head = card->tx_chain.head->next;
++  if (!ps3_gelic_param) {
++	gelic_net_set_frame_end(card, descr, skb);
++  } else {
++	if (descr->prev) {
++		descr->prev->next_descr_addr = descr->bus_addr;
++	}
++  }
++kick:
++	wmb();
++	gelic_net_kick_txdma(card, card->tx_chain.tail);
++
++	netdev->trans_start = jiffies;
++	spin_unlock_irqrestore(&card->intmask_lock, flags);
++	return NETDEV_TX_OK;
++
++error:
++	card->netdev_stats.tx_dropped++;
++	spin_unlock_irqrestore(&card->intmask_lock, flags);
++	return NETDEV_TX_LOCKED;
++}
++
++/**
++ * gelic_net_pass_skb_up - takes an skb from a descriptor and passes it on
++ * @descr: descriptor to process
++ * @card: card structure
++ *
++ * returns 1 on success, 0 if no packet was passed to the stack
++ *
++ * iommu-unmaps the skb, fills out skb structure and passes the data to the
++ * stack. The descriptor state is not changed.
++ */
++static int
++gelic_net_pass_skb_up(struct gelic_net_descr *descr,
++		       struct gelic_net_card *card)
++{
++	struct sk_buff *skb;
++	struct net_device *netdev;
++	uint32_t data_status, data_error;
++
++	data_status = descr->data_status;
++	data_error = descr->data_error;
++
++	netdev = card->netdev;
++	/* check for errors in the data_error flag */
++	if ((data_error & GELIC_NET_DATA_ERROR_MASK))
++		DPRINTK("error in received descriptor found, "
++		       "data_status=x%08x, data_error=x%08x\n",
++		       data_status, data_error);
++	/* prepare skb, unmap descriptor */
++	skb = descr->skb;
++	dma_unmap_single(&card->dev->core, descr->buf_addr, GELIC_NET_MAX_MTU,
++			 PCI_DMA_BIDIRECTIONAL);
++
++	/* the cases we'll throw away the packet immediately */
++	if (data_error & GELIC_NET_DATA_ERROR_FLG) {
++		DPRINTK("ERROR DESTROY:%x\n", data_error);
++		return 0;
++	}
++
++	skb->dev = netdev;
++	skb_put(skb, descr->valid_size);
++	descr->skb = NULL;
++	/* the card seems to add 2 bytes of junk in front
++	 * of the ethernet frame */
++#define GELIC_NET_MISALIGN		2
++	skb_pull(skb, GELIC_NET_MISALIGN);
++	skb->protocol = eth_type_trans(skb, netdev);
++
++	/* checksum offload */
++	if (card->rx_csum) {
++		if ( (data_status & GELIC_NET_DATA_STATUS_CHK_MASK) &&
++		     (!(data_error & GELIC_NET_DATA_ERROR_CHK_MASK)) )
++			skb->ip_summed = CHECKSUM_UNNECESSARY;
++		else
++			skb->ip_summed = CHECKSUM_NONE;
++	} else {
++		skb->ip_summed = CHECKSUM_NONE;
++	}
++
++	/* pass skb up to stack */
++	netif_receive_skb(skb);
++
++	/* update netdevice statistics */
++	card->netdev_stats.rx_packets++;
++	card->netdev_stats.rx_bytes += skb->len;
++
++	return 1;
++}
++
++/**
++ * gelic_net_decode_descr - processes an rx descriptor
++ * @card: card structure
++ *
++ * returns 1 if a packet has been sent to the stack, otherwise 0
++ *
++ * processes an rx descriptor by iommu-unmapping the data buffer and passing
++ * the packet up to the stack
++ */
++static int
++gelic_net_decode_one_descr(struct gelic_net_card *card)
++{
++	enum gelic_net_descr_status status;
++	struct gelic_net_descr *descr;
++	struct gelic_net_descr_chain *chain = &card->rx_chain;
++	int result = 0;
++	int kick = 0;
++	uint32_t cmd_status;
++
++	descr = chain->tail;
++	cmd_status = chain->tail->dmac_cmd_status;
++	rmb();
++	status = cmd_status >> GELIC_NET_DESCR_IND_PROC_SHIFT;
++	if (status == GELIC_NET_DESCR_CARDOWNED) {
++		goto no_decode;
++	}
++	if (status == GELIC_NET_DESCR_NOT_IN_USE) {
++		printk("err: decode_one_descr\n");
++		goto no_decode;
++	}
++
++	if ( (status == GELIC_NET_DESCR_RESPONSE_ERROR) ||
++	     (status == GELIC_NET_DESCR_PROTECTION_ERROR) ||
++	     (status == GELIC_NET_DESCR_FORCE_END) ) {
++		printk("%s: dropping RX descriptor with state %d\n",
++		       card->netdev->name, status);
++		card->netdev_stats.rx_dropped++;
++		goto refill;
++	}
++
++	if ( (status != GELIC_NET_DESCR_COMPLETE) &&
++	     (status != GELIC_NET_DESCR_FRAME_END) ) {
++		printk("%s: RX descriptor with state %d\n",
++		       card->netdev->name, status);
++		goto refill;
++	}
++
++	/* ok, we've got a packet in descr */
++	result = gelic_net_pass_skb_up(descr, card); /* 1: skb_up sccess */
++	if (cmd_status & GELIC_NET_DMAC_CMDSTAT_CHAIN_END) {
++		kick = 1;
++	}
++refill:
++	descr->next_descr_addr = 0; /* unlink the descr */
++	wmb();
++	gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
++	/* change the descriptor state: */
++	gelic_net_prepare_rx_descr(card, descr); /* refill one desc */
++	chain->head = descr;
++	chain->tail = descr->next;
++	descr->prev->next_descr_addr = descr->bus_addr;
++	if(kick) {
++		wmb();
++		gelic_net_enable_rxdmac(card);
++	}
++	return result;
++
++no_decode:
++	return 0;
++}
++
++/**
++ * gelic_net_poll - NAPI poll function called by the stack to return packets
++ * @netdev: interface device structure
++ * @budget: number of packets we can pass to the stack at most
++ *
++ * returns 0 if no more packets available to the driver/stack. Returns 1,
++ * if the quota is exceeded, but the driver has still packets.
++ *
++ */
++static int
++gelic_net_poll(struct net_device *netdev, int *budget)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++	int packets_to_do, packets_done = 0;
++	int no_more_packets = 0;
++
++	packets_to_do = min(*budget, netdev->quota);
++
++	while (packets_to_do) {
++		if (gelic_net_decode_one_descr(card)) {
++			packets_done++;
++			packets_to_do--;
++		} else {
++			/* no more packets for the stack */
++			no_more_packets = 1;
++			break;
++		}
++	}
++	netdev->quota -= packets_done;
++	*budget -= packets_done;
++	if (no_more_packets == 1) {
++		netif_rx_complete(netdev);
++
++		/* one more check */
++		while (1) {
++			if (!gelic_net_decode_one_descr(card) ) break;
++		};
++
++		return 0;
++	}else {
++		return 1;
++	}
++}
++
++/**
++ * gelic_net_get_stats - get interface statistics
++ * @netdev: interface device structure
++ *
++ * returns the interface statistics residing in the gelic_net_card struct
++ */
++static struct net_device_stats *
++gelic_net_get_stats(struct net_device *netdev)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++	struct net_device_stats *stats = &card->netdev_stats;
++
++	return stats;
++}
++
++/**
++ * gelic_net_change_mtu - changes the MTU of an interface
++ * @netdev: interface device structure
++ * @new_mtu: new MTU value
++ *
++ * returns 0 on success, <0 on failure
++ */
++static int
++gelic_net_change_mtu(struct net_device *netdev, int new_mtu)
++{
++	/* no need to re-alloc skbs or so -- the max mtu is about 2.3k
++	 * and mtu is outbound only anyway */
++	if ( (new_mtu < GELIC_NET_MIN_MTU ) ||
++		(new_mtu > GELIC_NET_MAX_MTU) ) {
++		return -EINVAL;
++	}
++	netdev->mtu = new_mtu;
++	return 0;
++}
++
++/**
++ * gelic_net_interrupt - event handler for gelic_net
++ */
++static irqreturn_t
++gelic_net_interrupt(int irq, void *ptr)
++{
++	struct net_device *netdev = ptr;
++	struct gelic_net_card *card = netdev_priv(netdev);
++	uint32_t status0, status1, status2;
++	unsigned long flags;
++	uint64_t status;
++
++	status = gelic_irq_status;
++	rmb();
++	status0 = (uint32_t)(status >> 32);
++	status1 = (uint32_t)(status & 0xffffffff);
++	status2 = 0;
++
++	if (!status0 && !status1 && !status2) {
++		return IRQ_NONE;
++	}
++
++	if(status1 & (1 << GELIC_NET_GDADCEINT) )  {
++		netif_rx_schedule(netdev);
++	}else
++	if (status0 & (1 << GELIC_NET_GRFANMINT) ) {
++		netif_rx_schedule(netdev);
++	}
++
++	if (status0 & (1 << GELIC_NET_GDTDCEINT) ) {
++		spin_lock_irqsave(&card->intmask_lock, flags);
++		dmac_status = 0;
++		spin_unlock_irqrestore(&card->intmask_lock, flags);
++		gelic_net_xmit(NULL, netdev);
++	}
++	return IRQ_HANDLED;
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++/**
++ * gelic_net_poll_controller - artificial interrupt for netconsole etc.
++ * @netdev: interface device structure
++ *
++ * see Documentation/networking/netconsole.txt
++ */
++static void
++gelic_net_poll_controller(struct net_device *netdev)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++
++	gelic_net_set_irq_mask(card, 0);
++	gelic_net_interrupt(netdev->irq, netdev);
++	gelic_net_set_irq_mask(card, card->ghiintmask);
++}
++#endif /* CONFIG_NET_POLL_CONTROLLER */
++
++/**
++ * gelic_net_open_device - open device and map dma region
++ * @card: card structure
++ */
++static int
++gelic_net_open_device(struct gelic_net_card *card)
++{
++	unsigned long result;
++	int ret;
++
++	result = ps3_sb_event_receive_port_setup(PS3_BINDING_CPU_ANY,
++		&card->dev->did, card->dev->interrupt_id, &card->netdev->irq);
++
++	if (result) {
++		printk("%s:%d: gelic_net_open_device failed (%ld)\n",
++			__func__, __LINE__, result);
++		ret = -EPERM;
++		goto fail_alloc_irq;
++	}
++
++	ret = request_irq(card->netdev->irq, gelic_net_interrupt, IRQF_DISABLED,
++		"gelic network", card->netdev);
++
++	if (ret) {
++		printk("%s:%d: request_irq failed (%ld)\n",
++			__func__, __LINE__, result);
++		goto fail_request_irq;
++	}
++
++	return 0;
++
++fail_request_irq:
++	ps3_sb_event_receive_port_destroy(&card->dev->did,
++		card->dev->interrupt_id, card->netdev->irq);
++	card->netdev->irq = NO_IRQ;
++fail_alloc_irq:
++	return ret;
++}
++
++
++/**
++ * gelic_net_open - called upon ifonfig up
++ * @netdev: interface device structure
++ *
++ * returns 0 on success, <0 on failure
++ *
++ * gelic_net_open allocates all the descriptors and memory needed for
++ * operation, sets up multicast list and enables interrupts
++ */
++int
++gelic_net_open(struct net_device *netdev)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++
++	printk(" -> %s:%d\n", __func__, __LINE__);
++
++	gelic_net_open_device(card);
++
++	if (gelic_net_init_chain(card, &card->tx_chain,
++			card->descr, tx_descriptors))
++		goto alloc_tx_failed;
++	if (gelic_net_init_chain(card, &card->rx_chain,
++			card->descr + tx_descriptors, rx_descriptors))
++		goto alloc_rx_failed;
++
++	/* head of chain */
++	card->tx_top = card->tx_chain.head;
++	card->rx_top = card->rx_chain.head;
++
++	/* allocate rx skbs */
++	if (gelic_net_alloc_rx_skbs(card))
++		goto alloc_skbs_failed;
++
++	dmac_status = 0;
++	card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT;
++	gelic_net_set_irq_mask(card, card->ghiintmask);
++	gelic_net_enable_rxdmac(card);
++
++	netif_start_queue(netdev);
++	netif_carrier_on(netdev);
++	netif_poll_enable(netdev);
++
++	return 0;
++
++alloc_skbs_failed:
++	gelic_net_free_chain(card, card->rx_top);
++alloc_rx_failed:
++	gelic_net_free_chain(card, card->tx_top);
++alloc_tx_failed:
++	return -ENOMEM;
++}
++
++#ifdef GELIC_NET_ETHTOOL
++static void
++gelic_net_get_drvinfo (struct net_device *netdev, struct ethtool_drvinfo *info)
++{
++	strncpy(info->driver, GELIC_NET_DRV_NAME, sizeof(info->driver) - 1);
++	strncpy(info->version, GELIC_NET_DRV_VERSION, sizeof(info->version) - 1);
++}
++
++static int
++gelic_net_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++	uint64_t status, v1, v2;
++	int speed, duplex;
++
++	speed = duplex = -1;
++	status = lv1_net_control(card->dev->did.bus_id, card->dev->did.dev_id,
++			GELIC_NET_GET_ETH_PORT_STATUS, GELIC_NET_PORT, 0, 0,
++			&v1, &v2);
++	if (status) {
++		/* link down */
++	} else {
++		if (v1 & GELIC_NET_FULL_DUPLEX) {
++			duplex = DUPLEX_FULL;
++		} else {
++			duplex = DUPLEX_HALF;
++		}
++
++		if (v1 & GELIC_NET_SPEED_10 ) {
++			speed = SPEED_10;
++		} else if (v1 & GELIC_NET_SPEED_100) {
++			speed = SPEED_100;
++		} else if (v1 & GELIC_NET_SPEED_1000) {
++			speed = SPEED_1000;
++		}
++	}
++	cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg |
++			SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
++			SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
++			SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
++	cmd->advertising = cmd->supported;
++	cmd->speed = speed;
++	cmd->duplex = duplex;
++	cmd->autoneg = AUTONEG_ENABLE; /* always enabled */
++	cmd->port = PORT_TP;
++
++	return 0;
++}
++
++static uint32_t
++gelic_net_get_link(struct net_device *netdev)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++	uint64_t status, v1, v2;
++	int link;
++
++	status = lv1_net_control(card->dev->did.bus_id, card->dev->did.dev_id,
++			GELIC_NET_GET_ETH_PORT_STATUS, GELIC_NET_PORT, 0, 0,
++			&v1, &v2);
++	if (status) {
++		return 0; /* link down */
++	}
++	if (v1 & GELIC_NET_LINK_UP)
++		link = 1;
++	else
++		link = 0;
++	return link;
++}
++
++static int
++gelic_net_nway_reset(struct net_device *netdev)
++{
++	if (netif_running(netdev)) {
++		gelic_net_stop(netdev);
++		gelic_net_open(netdev);
++	}
++	return 0;
++}
++
++static uint32_t
++gelic_net_get_tx_csum(struct net_device *netdev)
++{
++	return (netdev->features & NETIF_F_IP_CSUM) != 0;
++}
++
++static int
++gelic_net_set_tx_csum(struct net_device *netdev, uint32_t data)
++{
++	if (data)
++		netdev->features |= NETIF_F_IP_CSUM;
++	else
++		netdev->features &= ~NETIF_F_IP_CSUM;
++
++	return 0;
++}
++
++static uint32_t
++gelic_net_get_rx_csum(struct net_device *netdev)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++
++	return card->rx_csum;
++}
++
++static int
++gelic_net_set_rx_csum(struct net_device *netdev, uint32_t data)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++
++	card->rx_csum = data;
++	return 0;
++}
++
++static struct ethtool_ops gelic_net_ethtool_ops = {
++	.get_drvinfo	= gelic_net_get_drvinfo,
++	.get_settings	= gelic_net_get_settings,
++	.get_link	= gelic_net_get_link,
++	.nway_reset	= gelic_net_nway_reset,
++	.get_tx_csum	= gelic_net_get_tx_csum,
++	.set_tx_csum	= gelic_net_set_tx_csum,
++	.get_rx_csum	= gelic_net_get_rx_csum,
++	.set_rx_csum	= gelic_net_set_rx_csum,
++};
++#endif
++
++static int
++gelic_net_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
++{
++	struct gelic_net_card *card = netdev_priv(netdev);
++	void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data;
++	int mode, res = 0;
++
++	switch(cmd) {
++	case GELIC_NET_GET_MODE:
++		DPRINTK("GELIC_NET_GET_MODE:\n");
++		mode = card->vlan_index;
++		if (copy_to_user(addr, &mode, sizeof(mode)) ) {
++			printk("error copy_to_user\n");
++		}
++		res = 0;
++		break;
++	case GELIC_NET_SET_MODE:
++		if (card->vlan_index == -1) {
++			res = -EOPNOTSUPP; /* vlan mode only */
++			break;
++		}
++		if (copy_from_user(&mode, addr, sizeof(mode)) ) {
++			printk("error copy_from_user\n");
++		}
++		DPRINTK("GELIC_NET_SET_MODE:%x --> %x \n",
++				card->vlan_index, mode);
++		if (mode > GELIC_NET_VLAN_MAX -1 || mode < -1)
++			mode = GELIC_NET_VLAN_WIRED - 1;
++
++		if (card->vlan_index != mode) {
++			card->vlan_index = mode;
++			if (netif_running(netdev)) {
++				gelic_net_stop(netdev);
++				gelic_net_open(netdev);
++			}
++		}
++		res = 0;
++		break;
++	default:
++		res = -EOPNOTSUPP;
++		break;
++	}
++
++	return res;
++}
++
++/**
++ * gelic_net_tx_timeout_task - task scheduled by the watchdog timeout
++ * function (to be called not under interrupt status)
++ * @data: data, is interface device structure
++ *
++ * called as task when tx hangs, resets interface (if interface is up)
++ */
++static void
++gelic_net_tx_timeout_task(struct work_struct *work)
++{
++	struct gelic_net_card *card =
++		container_of(work, struct gelic_net_card, tx_timeout_task);
++	struct net_device *netdev = card->netdev;
++
++	printk("Timed out. Restarting... \n");
++
++	if (!(netdev->flags & IFF_UP))
++		goto out;
++
++	netif_device_detach(netdev);
++	gelic_net_stop(netdev);
++
++	gelic_net_open(netdev);
++	netif_device_attach(netdev);
++
++out:
++	atomic_dec(&card->tx_timeout_task_counter);
++}
++
++/**
++ * gelic_net_tx_timeout - called when the tx timeout watchdog kicks in.
++ * @netdev: interface device structure
++ *
++ * called, if tx hangs. Schedules a task that resets the interface
++ */
++static void
++gelic_net_tx_timeout(struct net_device *netdev)
++{
++	struct gelic_net_card *card;
++
++	card = netdev_priv(netdev);
++	atomic_inc(&card->tx_timeout_task_counter);
++	if (netdev->flags & IFF_UP)
++		schedule_work(&card->tx_timeout_task);
++	else
++		atomic_dec(&card->tx_timeout_task_counter);
++}
++
++/**
++ * gelic_net_setup_netdev_ops - initialization of net_device operations
++ * @netdev: net_device structure
++ *
++ * fills out function pointers in the net_device structure
++ */
++static void
++gelic_net_setup_netdev_ops(struct net_device *netdev)
++{
++	netdev->open = &gelic_net_open;
++	netdev->stop = &gelic_net_stop;
++	netdev->hard_start_xmit = &gelic_net_xmit;
++	netdev->get_stats = &gelic_net_get_stats;
++	netdev->set_multicast_list = &gelic_net_set_multi;
++	netdev->change_mtu = &gelic_net_change_mtu;
++	/* tx watchdog */
++	netdev->tx_timeout = &gelic_net_tx_timeout;
++	netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
++	/* NAPI */
++	netdev->poll = &gelic_net_poll;
++	netdev->weight = GELIC_NET_NAPI_WEIGHT;
++#ifdef GELIC_NET_ETHTOOL
++	netdev->ethtool_ops = &gelic_net_ethtool_ops;
++#endif
++	netdev->do_ioctl = &gelic_net_ioctl;
++}
++
++/**
++ * gelic_net_setup_netdev - initialization of net_device
++ * @card: card structure
++ *
++ * Returns 0 on success or <0 on failure
++ *
++ * gelic_net_setup_netdev initializes the net_device structure
++ **/
++static int
++gelic_net_setup_netdev(struct gelic_net_card *card)
++{
++	int i, result;
++	struct net_device *netdev = card->netdev;
++	struct sockaddr addr;
++	uint8_t *mac;
++	uint64_t status, v1, v2;
++
++	SET_MODULE_OWNER(netdev);
++	spin_lock_init(&card->intmask_lock);
++
++	card->rx_csum = GELIC_NET_RX_CSUM_DEFAULT;
++
++	gelic_net_setup_netdev_ops(netdev);
++
++	netdev->features = NETIF_F_IP_CSUM;
++
++	status = lv1_net_control(card->dev->did.bus_id, card->dev->did.dev_id,
++				GELIC_NET_GET_MAC_ADDRESS,
++				0, 0, 0, &v1, &v2);
++	if (status || !v1) {
++		printk("lv1_net_control GET_MAC_ADDR not supported, status=%ld\n",
++			status);
++		return -EINVAL;
++	}
++	v1 <<= 16;
++	mac = (uint8_t *)&v1;
++	memcpy(addr.sa_data, mac, ETH_ALEN);
++	memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN);
++
++	result = register_netdev(netdev);
++	if (result) {
++			printk("Couldn't register net_device: %i\n", result);
++		return result;
++	}
++
++	printk("%s: %s\n", netdev->name, GELIC_NET_DRV_NAME);
++	printk("%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
++		netdev->name,
++		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
++		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
++
++	card->vlan_index = -1;	/* no vlan */
++	for (i = 0; i < GELIC_NET_VLAN_MAX ;i++) {
++		status = lv1_net_control(card->dev->did.bus_id,
++					card->dev->did.dev_id,
++					GELIC_NET_GET_VLAN_ID,
++					i + 1, /* GELIC_NET_VLAN_X */
++					0, 0, &v1, &v2);
++		if (status == GELIC_NET_VLAN_NO_ENTRY) {
++			DPRINTK("GELIC_VLAN_ID no entry:%ld, VLAN disabled\n",
++				status);
++			card->vlan_id[i] = 0;
++		} else if (status) {
++			printk("GELIC_NET_VLAN_ID faild, status=%ld\n", status);
++			card->vlan_id[i] = 0;
++		} else {
++			card->vlan_id[i] = (uint32_t)v1;
++			DPRINTK("vlan_id:%d, %lx\n", i, v1);
++		}
++	}
++	if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) {
++		card->vlan_index = GELIC_NET_VLAN_WIRED - 1;
++	}
++	return 0;
++}
++
++/**
++ * gelic_net_alloc_card - allocates net_device and card structure
++ *
++ * returns the card structure or NULL in case of errors
++ *
++ * the card and net_device structures are linked to each other
++ */
++static struct gelic_net_card *
++gelic_net_alloc_card(void)
++{
++	struct net_device *netdev;
++	struct gelic_net_card *card;
++	size_t alloc_size;
++
++	alloc_size = sizeof (*card) +
++		sizeof (struct gelic_net_descr) * rx_descriptors +
++		sizeof (struct gelic_net_descr) * tx_descriptors;
++	netdev = alloc_etherdev(alloc_size);
++	if (!netdev)
++		return NULL;
++
++	card = netdev_priv(netdev);
++	card->netdev = netdev;
++	INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
++	init_waitqueue_head(&card->waitq);
++	atomic_set(&card->tx_timeout_task_counter, 0);
++
++	return card;
++}
++
++/**
++ * ps3_gelic_driver_probe - add a device to the control of this driver
++ */
++static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev)
++{
++	int result;
++
++	gcard = gelic_net_alloc_card();
++
++	if (!gcard) {
++		dev_dbg(&dev->core, "%s:%d: gelic_net_alloc_card failed\n",
++			__func__, __LINE__);
++		result = -ENOMEM;
++		goto fail_alloc_card;
++	}
++
++	gcard->dev = dev;
++
++	result = ps3_open_hv_device(&dev->did);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
++			__func__, __LINE__);
++		goto fail_open;
++	}
++
++	result = ps3_dma_region_create(dev->d_region);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
++			"(%d)\n", __func__, __LINE__, result);
++		BUG_ON("check region type");
++		goto fail_dma_region;
++	}
++
++	result = lv1_net_set_interrupt_status_indicator(dev->did.bus_id,
++		dev->did.dev_id, ps3_mm_phys_to_lpar(__pa(&gelic_irq_status)),
++		0);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: "
++			"lv1_net_set_interrupt_status_indicator failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
++		result = -EIO;
++		goto fail_status_indicator;
++	}
++
++	result = gelic_net_setup_netdev(gcard);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
++			"(%d)\n", __func__, __LINE__, result);
++		goto fail_setup_netdev;
++	}
++
++	return 0;
++
++fail_setup_netdev:
++	lv1_net_set_interrupt_status_indicator(dev->did.bus_id, dev->did.dev_id,
++		0 , 0); // check if ok!!!
++fail_status_indicator:
++	ps3_dma_region_free(dev->d_region);
++fail_dma_region:
++	ps3_close_hv_device(&dev->did);
++fail_open:
++	free_netdev(gcard->netdev); // enough???
++	gcard = NULL;
++fail_alloc_card:
++	return result;
++}
++
++/**
++ * ps3_gelic_driver_remove - remove a device from the control of this driver
++ */
++
++static int
++ps3_gelic_driver_remove (struct ps3_system_bus_device *dev)
++{
++	struct net_device *netdev;
++	struct gelic_net_card *card;
++
++	card = gcard;
++	netdev = card->netdev;
++
++	wait_event(card->waitq,
++		   atomic_read(&card->tx_timeout_task_counter) == 0);
++
++	unregister_netdev(netdev);
++	free_netdev(netdev);
++
++	lv1_net_set_interrupt_status_indicator(dev->did.bus_id, dev->did.dev_id,
++		0 , 0); // check if ok!!!
++
++	ps3_dma_region_free(dev->d_region);
++
++	ps3_close_hv_device(&dev->did);
++
++	// anything else needed???
++
++	printk(" <- %s:%d:\n", __func__, __LINE__);
++	return 0;
++}
++
++static struct ps3_system_bus_driver ps3_gelic_driver = {
++	.match_id = PS3_MATCH_ID_GELIC,
++	.probe = ps3_gelic_driver_probe,
++	.remove = ps3_gelic_driver_remove,
++	.core = {
++		.name = "ps3_gelic_driver",
++	},
++};
++
++static int __init
++ps3_gelic_driver_init (void)
++{
++	return firmware_has_feature(FW_FEATURE_PS3_LV1)
++		? ps3_system_bus_driver_register(&ps3_gelic_driver)
++		: -ENODEV;
++}
++
++static void __exit
++ps3_gelic_driver_exit (void)
++{
++	ps3_system_bus_driver_unregister(&ps3_gelic_driver);
++}
++
++module_init (ps3_gelic_driver_init);
++module_exit (ps3_gelic_driver_exit);
++
++#ifdef CONFIG_GELIC_NET
++static int __init early_param_gelic_net(char *p)
++{
++	if (strstr(p, "n")) {
++		ps3_gelic_param = 0;	/* gelic_vlan off */
++		printk("ps3_gelic_param:vlan off\n");
++	} else {
++		ps3_gelic_param = 1;	/* gelic_vlan on */
++	}
++	return 0;
++
++}
++early_param("gelic_vlan", early_param_gelic_net);
++#endif

linux-2.6-ps3-kexec.patch:

Index: linux-2.6-ps3-kexec.patch
===================================================================
RCS file: linux-2.6-ps3-kexec.patch
diff -N linux-2.6-ps3-kexec.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-kexec.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,1008 @@
+As of 2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440):
+
+ps3-wip/ps3-kexec-core.diff
+ps3-wip/ps3-kexec-system-bus.diff
+ps3-wip/ps3-kexec-usb.diff
+ps3-wip/ps3-kexec-ps3fb.diff
+
+diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
+index ea60c45..08a9074 100644
+--- a/arch/powerpc/platforms/ps3/htab.c
++++ b/arch/powerpc/platforms/ps3/htab.c
+@@ -234,10 +234,18 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va,
+ 
+ static void ps3_hpte_clear(void)
+ {
+-	/* Make sure to clean up the frame buffer device first */
+-	ps3fb_cleanup();
++	int result;
+ 
+-	lv1_unmap_htab(htab_addr);
++	DBG(" -> %s:%d\n", __func__, __LINE__);
++
++	result = lv1_unmap_htab(htab_addr);
++	BUG_ON(result);
++
++	ps3_mm_shutdown();
++
++	ps3_mm_vas_destroy();
++
++	DBG(" <- %s:%d\n", __func__, __LINE__);
+ }
+ 
+ void __init ps3_hpte_init(unsigned long htab_size)
+diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
+index 9da82c2..f5c31fb 100644
+--- a/arch/powerpc/platforms/ps3/interrupt.c
++++ b/arch/powerpc/platforms/ps3/interrupt.c
+@@ -90,6 +90,92 @@ struct ps3_private {
+ static DEFINE_PER_CPU(struct ps3_private, ps3_private);
+ 
+ /**
++ * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp.
++ * @virq: The assigned Linux virq.
++ *
++ * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
++ */
++
++static void ps3_chip_mask(unsigned int virq)
++{
++	struct ps3_private *pd = get_irq_chip_data(virq);
++	u64 bit = 0x8000000000000000UL >> virq;
++	u64 *p = &pd->bmp.mask;
++	u64 old;
++	unsigned long flags;
++
++	pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
++
++	local_irq_save(flags);
++	asm volatile(
++		     "1:	ldarx %0,0,%3\n"
++		     "andc	%0,%0,%2\n"
++		     "stdcx.	%0,0,%3\n"
++		     "bne-	1b"
++		     : "=&r" (old), "+m" (*p)
++		     : "r" (bit), "r" (p)
++		     : "cc" );
++
++	lv1_did_update_interrupt_mask(pd->node, pd->cpu);
++	local_irq_restore(flags);
++}
++
++/**
++ * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp.
++ * @virq: The assigned Linux virq.
++ *
++ * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
++ */
++
++static void ps3_chip_unmask(unsigned int virq)
++{
++	struct ps3_private *pd = get_irq_chip_data(virq);
++	u64 bit = 0x8000000000000000UL >> virq;
++	u64 *p = &pd->bmp.mask;
++	u64 old;
++	unsigned long flags;
++
++	pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
++
++	local_irq_save(flags);
++	asm volatile(
++		     "1:	ldarx %0,0,%3\n"
++		     "or	%0,%0,%2\n"
++		     "stdcx.	%0,0,%3\n"
++		     "bne-	1b"
++		     : "=&r" (old), "+m" (*p)
++		     : "r" (bit), "r" (p)
++		     : "cc" );
++
++	lv1_did_update_interrupt_mask(pd->node, pd->cpu);
++	local_irq_restore(flags);
++}
++
++/**
++ * ps3_chip_eoi - HV end-of-interrupt.
++ * @virq: The assigned Linux virq.
++ *
++ * Calls lv1_end_of_interrupt_ext().
++ */
++
++static void ps3_chip_eoi(unsigned int virq)
++{
++	const struct ps3_private *pd = get_irq_chip_data(virq);
++	lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
++}
++
++/**
++ * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip.
++ */
++
++static struct irq_chip ps3_irq_chip = {
++	.typename = "ps3",
++	.mask = ps3_chip_mask,
++	.unmask = ps3_chip_unmask,
++	.eoi = ps3_chip_eoi,
++};
++
++/**
+  * ps3_virq_setup - virq related setup.
+  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+  * serviced on.
+@@ -133,6 +219,8 @@ int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
+ 		goto fail_set;
+ 	}
+ 
++	ps3_chip_mask(*virq);
++
+ 	return result;
+ 
+ fail_set:
+@@ -224,6 +312,8 @@ int ps3_irq_plug_destroy(unsigned int virq)
+ 	pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
+ 		pd->node, pd->cpu, virq);
+ 
++	ps3_chip_mask(virq);
++
+ 	result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
+ 
+ 	if (result)
+@@ -283,23 +373,21 @@ int ps3_event_receive_port_destroy(unsigned int virq)
+ 
+ 	pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq);
+ 
++	ps3_chip_mask(virq);
++
+ 	result = lv1_destruct_event_receive_port(virq_to_hw(virq));
+ 
+ 	if (result)
+ 		pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
+ 			__func__, __LINE__, ps3_result(result));
+ 
+-	/* lv1_destruct_event_receive_port() destroys the IRQ plug,
+-	 * so don't call ps3_irq_plug_destroy() here.
++	/* Can't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu()
++	 * calls from interrupt context (smp_call_function).
+ 	 */
+ 
+-	result = ps3_virq_destroy(virq);
+-	BUG_ON(result);
+-
+ 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ 	return result;
+ }
+-EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy);
+ 
+ int ps3_send_event_locally(unsigned int virq)
+ {
+@@ -371,6 +459,13 @@ int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
+ 	result = ps3_event_receive_port_destroy(virq);
+ 	BUG_ON(result);
+ 
++	/* ps3_event_receive_port_destroy() destroys the IRQ plug,
++	 * so don't call ps3_irq_plug_destroy() here.
++	 */
++
++	result = ps3_virq_destroy(virq);
++	BUG_ON(result);
++
+ 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ 	return result;
+ }
+@@ -411,16 +506,23 @@ EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
+ int ps3_io_irq_destroy(unsigned int virq)
+ {
+ 	int result;
++	unsigned int outlet = virq_to_hw(virq);
+ 
+-	result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
++	ps3_chip_mask(virq);
+ 
+-	if (result)
+-		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
+-			__func__, __LINE__, ps3_result(result));
++	/* lv1_destruct_io_irq_outlet() will destroy the IRQ plug,
++	 * so call ps3_irq_plug_destroy() first.
++	 */
+ 
+ 	result = ps3_irq_plug_destroy(virq);
+ 	BUG_ON(result);
+ 
++	result = lv1_destruct_io_irq_outlet(outlet);
++
++	if (result)
++		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
++
+ 	return result;
+ }
+ EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
+@@ -465,6 +567,7 @@ int ps3_vuart_irq_destroy(unsigned int virq)
+ {
+ 	int result;
+ 
++	ps3_chip_mask(virq);
+ 	result = lv1_deconfigure_virtual_uart_irq();
+ 
+ 	if (result) {
+@@ -564,67 +667,6 @@ static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
+ static void dump_bmp(struct ps3_private* pd) {};
+ #endif /* defined(DEBUG) */
+ 
+-static void ps3_chip_mask(unsigned int virq)
+-{
+-	struct ps3_private *pd = get_irq_chip_data(virq);
+-	u64 bit = 0x8000000000000000UL >> virq;
+-	u64 *p = &pd->bmp.mask;
+-	u64 old;
+-	unsigned long flags;
+-
+-	pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
+-
+-	local_irq_save(flags);
+-	asm volatile(
+-		     "1:	ldarx %0,0,%3\n"
+-		     "andc	%0,%0,%2\n"
+-		     "stdcx.	%0,0,%3\n"
+-		     "bne-	1b"
+-		     : "=&r" (old), "+m" (*p)
+-		     : "r" (bit), "r" (p)
+-		     : "cc" );
+-
+-	lv1_did_update_interrupt_mask(pd->node, pd->cpu);
+-	local_irq_restore(flags);
+-}
+-
+-static void ps3_chip_unmask(unsigned int virq)
+-{
+-	struct ps3_private *pd = get_irq_chip_data(virq);
+-	u64 bit = 0x8000000000000000UL >> virq;
+-	u64 *p = &pd->bmp.mask;
+-	u64 old;
+-	unsigned long flags;
+-
+-	pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
+-
+-	local_irq_save(flags);
+-	asm volatile(
+-		     "1:	ldarx %0,0,%3\n"
+-		     "or	%0,%0,%2\n"
+-		     "stdcx.	%0,0,%3\n"
+-		     "bne-	1b"
+-		     : "=&r" (old), "+m" (*p)
+-		     : "r" (bit), "r" (p)
+-		     : "cc" );
+-
+-	lv1_did_update_interrupt_mask(pd->node, pd->cpu);
+-	local_irq_restore(flags);
+-}
+-
+-static void ps3_chip_eoi(unsigned int virq)
+-{
+-	const struct ps3_private *pd = get_irq_chip_data(virq);
+-	lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
+-}
+-
+-static struct irq_chip irq_chip = {
+-	.typename = "ps3",
+-	.mask = ps3_chip_mask,
+-	.unmask = ps3_chip_unmask,
+-	.eoi = ps3_chip_eoi,
+-};
+-
+ static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
+ {
+ 	set_irq_chip_data(virq, NULL);
+@@ -636,7 +678,7 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,
+ 	pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
+ 		virq);
+ 
+-	set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
++	set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq);
+ 
+ 	return 0;
+ }
+diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
+index 25cf1f0..e6ff624 100644
+--- a/arch/powerpc/platforms/ps3/mm.c
++++ b/arch/powerpc/platforms/ps3/mm.c
+@@ -213,9 +213,15 @@ fail:
+ 
+ void ps3_mm_vas_destroy(void)
+ {
++	int result;
++
++	DBG("%s:%d: map.vas_id    = %lu\n", __func__, __LINE__, map.vas_id);
++
+ 	if (map.vas_id) {
+-		lv1_select_virtual_address_space(0);
+-		lv1_destruct_virtual_address_space(map.vas_id);
++		result = lv1_select_virtual_address_space(0);
++		BUG_ON(result);
++		result = lv1_destruct_virtual_address_space(map.vas_id);
++		BUG_ON(result);
+ 		map.vas_id = 0;
+ 	}
+ }
+@@ -276,8 +282,12 @@ zero_region:
+ 
+ void ps3_mm_region_destroy(struct mem_region *r)
+ {
++	int result;
++
++	DBG("%s:%d: r->base = %lxh\n", __func__, __LINE__, r->base);
+ 	if (r->base) {
+-		lv1_release_memory(r->base);
++		result = lv1_release_memory(r->base);
++		BUG_ON(result);
+ 		r->size = r->base = r->offset = 0;
+ 		map.total = map.rm.size;
+ 	}
+@@ -643,6 +653,13 @@ static int dma_sb_region_create(struct ps3_dma_region* r)
+ 	u64 len;
+ 	int result;
+ 
++	BUG_ON(!r);
++	if(!r->did.bus_id) {
++		pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__,
++			r->did.bus_id, r->did.dev_id);
++		return 0;
++	}
++
+ 	DBG("%s:%u: len = 0x%lx, page_size = %u, offset = 0x%lx\n", __func__,
+ 	    __LINE__, r->len, r->page_size, r->offset);
+ 	INIT_LIST_HEAD(&r->chunk_list.head);
+@@ -697,6 +714,13 @@ static int dma_sb_region_free(struct ps3_dma_region* r)
+ 	struct dma_chunk *c;
+ 	struct dma_chunk *tmp;
+ 
++	BUG_ON(!r);
++	if(!r->did.bus_id) {
++		pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__,
++			r->did.bus_id, r->did.dev_id);
++		return 0;
++	}
++
+ 	list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) {
+ 		list_del(&c->link);
+ 		dma_sb_free_chunk(c);
+@@ -706,7 +730,7 @@ static int dma_sb_region_free(struct ps3_dma_region* r)
+ 		r->bus_addr);
+ 
+ 	if (result)
+-		DBG("%s:%d: lv1_free_device_dma_region failed: %s\n",
++		DBG("%s:%d: lv1_release_io_segment failed: %s\n",
+ 			__func__, __LINE__, ps3_result(result));
+ 
+ 	r->len = r->bus_addr = 0;
+@@ -1122,12 +1146,18 @@ EXPORT_SYMBOL(ps3_dma_region_init);
+ 
+ int ps3_dma_region_create(struct ps3_dma_region *r)
+ {
++	BUG_ON(!r);
++	BUG_ON(!r->region_ops);
++	BUG_ON(!r->region_ops->create);
+ 	return r->region_ops->create(r);
+ }
+ EXPORT_SYMBOL(ps3_dma_region_create);
+ 
+ int ps3_dma_region_free(struct ps3_dma_region *r)
+ {
++	BUG_ON(!r);
++	BUG_ON(!r->region_ops);
++	BUG_ON(!r->region_ops->free);
+ 	return r->region_ops->free(r);
+ }
+ EXPORT_SYMBOL(ps3_dma_region_free);
+diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
+index c989493..e045216 100644
+--- a/arch/powerpc/platforms/ps3/setup.c
++++ b/arch/powerpc/platforms/ps3/setup.c
+@@ -201,31 +201,28 @@ static int __init ps3_probe(void)
+ #if defined(CONFIG_KEXEC)
+ static void ps3_kexec_cpu_down(int crash_shutdown, int secondary)
+ {
+-	DBG(" -> %s:%d\n", __func__, __LINE__);
++	int result;
++	u64 ppe_id;
++	u64 thread_id = secondary ? 1 : 0;
++
++	DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, secondary);
++	ps3_smp_cleanup_cpu(thread_id);
++
++	lv1_get_logical_ppe_id(&ppe_id);
++	result = lv1_configure_irq_state_bitmap(ppe_id, secondary ? 0 : 1, 0);
+ 
+-	if (secondary) {
+-		int cpu;
+-		for_each_online_cpu(cpu)
+-			if (cpu)
+-				ps3_smp_cleanup_cpu(cpu);
+-	} else
+-		ps3_smp_cleanup_cpu(0);
++	/* seems to fail on second call */
++	DBG("%s:%d: lv1_configure_irq_state_bitmap (%d) %s\n", __func__,
++		__LINE__, secondary, ps3_result(result));
+ 
+ 	DBG(" <- %s:%d\n", __func__, __LINE__);
+ }
+ 
+ static void ps3_machine_kexec(struct kimage *image)
+ {
+-	unsigned long ppe_id;
+-
+ 	DBG(" -> %s:%d\n", __func__, __LINE__);
+ 
+-	lv1_get_logical_ppe_id(&ppe_id);
+-	lv1_configure_irq_state_bitmap(ppe_id, 0, 0);
+-	ps3_mm_shutdown();
+-	ps3_mm_vas_destroy();
+-
+-	default_machine_kexec(image);
++	default_machine_kexec(image); // needs ipi, never returns.
+ 
+ 	DBG(" <- %s:%d\n", __func__, __LINE__);
+ }
+diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
+index a2591b8..c5afa82 100644
+--- a/arch/powerpc/platforms/ps3/system-bus.c
++++ b/arch/powerpc/platforms/ps3/system-bus.c
+@@ -36,6 +36,71 @@ static struct device ps3_system_bus = {
+         .bus_id         = "ps3_system",
+ };
+ 
++// FIXME: need device usage counters!
++struct {
++	int id_11; // usb 0
++	int id_12; // usb 1
++} static usage_hack;
++
++int ps3_open_hv_device(struct ps3_device_id *did)
++{
++	int result;
++
++	BUG_ON(!did->bus_id); // now just for sb devices.
++
++	// FIXME: hacks for dev usage counts.
++
++	if(did->bus_id == 1 && did->dev_id == 1) {
++		usage_hack.id_11++;
++		if (usage_hack.id_11 > 1)
++			return 0;
++	}
++
++	if(did->bus_id == 1 && did->dev_id == 2) {
++		usage_hack.id_12++;
++		if (usage_hack.id_12 > 1)
++			return 0;
++	}
++
++	result = lv1_open_device(did->bus_id, did->dev_id, 0);
++
++  	if (result) {
++  		pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__,
++			__LINE__, ps3_result(result));
++			result = -EPERM;
++	}
++
++	return result;
++}
++EXPORT_SYMBOL_GPL(ps3_open_hv_device);
++
++int ps3_close_hv_device(struct ps3_device_id *did)
++{
++	int result;
++
++	BUG_ON(!did->bus_id); // now just for sb devices.
++
++	// FIXME: hacks for dev usage counts.
++
++	if(did->bus_id == 1 && did->dev_id == 1) {
++		usage_hack.id_11--;
++		if (usage_hack.id_11)
++			return 0;
++	}
++
++	if(did->bus_id == 1 && did->dev_id == 2) {
++		usage_hack.id_12--;
++		if (usage_hack.id_12)
++			return 0;
++	}
++
++	result = lv1_close_device(did->bus_id, did->dev_id);
++	BUG_ON(result);
++
++	return result;
++}
++EXPORT_SYMBOL_GPL(ps3_close_hv_device);
++
+ #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
+ static void _dump_mmio_region(const struct ps3_mmio_region* r,
+ 	const char* func, int line)
+@@ -80,6 +145,8 @@ static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r)
+ {
+ 	int result;
+ 
++	dump_mmio_region(r);
++;
+ 	result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
+ 		r->lpar_addr);
+ 
+@@ -156,76 +223,83 @@ static int ps3_system_bus_probe(struct device *_dev)
+ {
+ 	int result = 0;
+ 	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+-	struct ps3_system_bus_driver *drv =
+-		to_ps3_system_bus_driver(_dev->driver);
+-
+-	if (dev->did.bus_id)
+-		result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
+-
+-	if (result && (result != LV1_BUSY || (dev->match_id != PS3_MATCH_ID_EHCI
+-		&& dev->match_id != PS3_MATCH_ID_OHCI))) {
+-		pr_debug("%s:%d: lv1_open_device failed: %s\n",
+-			__func__, __LINE__, ps3_result(result));
+-		result = -EACCES;
+-		goto clean_none;
+-	}
++	struct ps3_system_bus_driver *drv;
+ 
+-	if (dev->d_region && dev->d_region->did.bus_id) {
+-		result = ps3_dma_region_create(dev->d_region);
+-
+-		if (result) {
+-			pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
+-				__func__, __LINE__, result);
+-			BUG_ON("check region type");
+-			result = -EINVAL;
+-			goto clean_device;
+-		}
+-	}
++	BUG_ON(!dev);
++	pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
+ 
++	drv = to_ps3_system_bus_driver(_dev->driver);
+ 	BUG_ON(!drv);
+ 
+-	if (drv->probe)
++	if(drv->probe)
+ 		result = drv->probe(dev);
+ 	else
+ 		pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
+ 			dev->core.bus_id);
+ 
+-	if (result) {
+-		pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
+-		goto clean_dma;
+-	}
+-
+-	return result;
+-
+-clean_dma:
+-	if (dev->d_region && dev->d_region->did.bus_id)
+-		ps3_dma_region_free(dev->d_region);
+-clean_device:
+-	if (dev->did.bus_id)
+-		lv1_close_device(dev->did.bus_id, dev->did.dev_id);
+-clean_none:
++	pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
+ 	return result;
+ }
+ 
+ static int ps3_system_bus_remove(struct device *_dev)
+ {
++	int result = 0;
+ 	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+-	struct ps3_system_bus_driver *drv =
+-		to_ps3_system_bus_driver(_dev->driver);
++	struct ps3_system_bus_driver *drv;
++
++	BUG_ON(!dev);
++	pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
++
++	drv = to_ps3_system_bus_driver(_dev->driver);
++	BUG_ON(!drv);
+ 
+ 	if (drv->remove)
+-		drv->remove(dev);
++		result = drv->remove(dev);
+ 	else
+ 		pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
+ 			dev->core.bus_id);
+ 
+-	if (dev->d_region && dev->d_region->did.dev_id)
+-		ps3_dma_region_free(dev->d_region);
++	pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
++	return result;
++}
++
++static void ps3_system_bus_shutdown(struct device *_dev)
++{
++	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
++	struct ps3_system_bus_driver *drv
++		= to_ps3_system_bus_driver(_dev->driver);
++
++	BUG_ON(!dev);
++
++	pr_info(" -> %s:%d: %s, match_id %d\n", __func__, __LINE__,
++		dev->core.bus_id, dev->match_id);
++
++	if(!dev->core.driver) {
++		pr_info("%s:%d: %s: no driver bound\n", __func__, __LINE__,
++			dev->core.bus_id);
++		return;
++	}
++
++	drv = to_ps3_system_bus_driver(dev->core.driver);
+ 
+-	if (dev->did.bus_id)
+-		lv1_close_device(dev->did.bus_id, dev->did.dev_id);
++	BUG_ON(!drv);
+ 
+-	return 0;
++	pr_info("%s:%d: %s -> %s\n", __func__, __LINE__, dev->core.bus_id,
++		drv->core.name);
++
++	if (drv->shutdown)
++		drv->shutdown(dev);
++	else if (drv->remove) {
++		pr_info("%s:%d: %s no shutdown, calling remove\n",
++			__func__, __LINE__, dev->core.bus_id);
++		drv->remove(dev);
++	} else {
++		pr_info("%s:%d: %s no shutdown method\n", __func__, __LINE__,
++			dev->core.bus_id);
++		BUG();
++	}
++
++	pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
+ }
+ 
+ static int ps3_system_bus_uevent(struct device *_dev, char **envp,
+@@ -262,6 +336,7 @@ struct bus_type ps3_system_bus_type = {
+ 	.match = ps3_system_bus_match,
+ 	.probe = ps3_system_bus_probe,
+ 	.remove = ps3_system_bus_remove,
++ 	.shutdown = ps3_system_bus_shutdown,
+ 	.uevent = ps3_system_bus_uevent,
+ 	.dev_attrs = ps3_system_bus_dev_attrs,
+ };
+@@ -272,10 +347,13 @@ int __init ps3_system_bus_init(void)
+ 
+ 	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ 		return -ENODEV;
++
++	printk(" -> %s:%d\n", __func__, __LINE__);
+ 	result = device_register(&ps3_system_bus);
+ 	BUG_ON(result);
+ 	result = bus_register(&ps3_system_bus_type);
+ 	BUG_ON(result);
++	printk(" <- %s:%d\n", __func__, __LINE__);
+ 	return result;
+ }
+ 
+@@ -541,9 +619,11 @@ int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv,
+ {
+ 	int result;
+ 
++	printk(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
+ 	drv->core.bus = &ps3_system_bus_type;
+ 
+ 	result = driver_register(&drv->core);
++	printk(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
+ 	return result;
+ }
+ 
+@@ -551,7 +631,9 @@ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
+ 
+ void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
+ {
++	printk(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
+ 	driver_unregister(&drv->core);
++	printk(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
+ }
+ 
+ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
+diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
+index 37b83ba..339f985 100644
+--- a/drivers/usb/host/ehci-ps3.c
++++ b/drivers/usb/host/ehci-ps3.c
+@@ -19,6 +19,7 @@
+  */
+ 
+ #include <asm/ps3.h>
++#include <asm/lv1call.h>
+ 
+ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+ {
+@@ -85,13 +86,30 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+ 		goto fail_start;
+ 	}
+ 
++	result = ps3_open_hv_device(&dev->did);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
++			__func__, __LINE__);
++		goto fail_open;
++	}
++
++	result = ps3_dma_region_create(dev->d_region);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
++			"(%d)\n", __func__, __LINE__, result);
++		BUG_ON("check region type");
++		goto fail_dma_region;
++	}
++
+ 	result = ps3_mmio_region_create(dev->m_region);
+ 
+ 	if (result) {
+ 		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ 			__func__, __LINE__);
+ 		result = -EPERM;
+-		goto fail_mmio;
++		goto fail_mmio_region;
+ 	}
+ 
+ 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+@@ -120,6 +138,11 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+ 
+ 	hcd->rsrc_start = dev->m_region->lpar_addr;
+ 	hcd->rsrc_len = dev->m_region->len;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
++		dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
++			__func__, __LINE__);
++
+ 	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+ 
+ 	if (!hcd->regs) {
+@@ -153,12 +176,17 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+ fail_add_hcd:
+ 	iounmap(hcd->regs);
+ fail_ioremap:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ 	usb_put_hcd(hcd);
+ fail_create_hcd:
+ 	ps3_io_irq_destroy(virq);
+ fail_irq:
+ 	ps3_free_mmio_region(dev->m_region);
+-fail_mmio:
++fail_mmio_region:
++	ps3_dma_region_free(dev->d_region);
++fail_dma_region:
++	ps3_close_hv_device(&dev->did);
++fail_open:
+ fail_start:
+ 	return result;
+ }
+@@ -168,9 +196,27 @@ static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+ 	struct usb_hcd *hcd =
+ 		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+ 
+-	usb_put_hcd(hcd);
++	BUG_ON(!hcd);
++
++	dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
++	dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
++
++	usb_remove_hcd(hcd);
++
+ 	ps3_system_bus_set_driver_data(dev, NULL);
+ 
++	BUG_ON(!hcd->regs);
++	iounmap(hcd->regs);
++
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++
++	ps3_io_irq_destroy(hcd->irq);
++	ps3_free_mmio_region(dev->m_region);
++
++	ps3_dma_region_free(dev->d_region);
++	ps3_close_hv_device(&dev->did);
++
+ 	return 0;
+ }
+ 
+@@ -183,4 +229,5 @@ static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+ 	},
+ 	.probe = ps3_ehci_sb_probe,
+ 	.remove = ps3_ehci_sb_remove,
++	.shutdown = ps3_ehci_sb_remove,
+ };
+diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
+index d7cf072..429628f 100644
+--- a/drivers/usb/host/ohci-ps3.c
++++ b/drivers/usb/host/ohci-ps3.c
+@@ -19,6 +19,7 @@
+  */
+ 
+ #include <asm/ps3.h>
++#include <asm/lv1call.h>
+ 
+ static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+ {
+@@ -84,16 +85,35 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+ 
+ 	if (usb_disabled()) {
+ 		result = -ENODEV;
++		BUG();
+ 		goto fail_start;
+ 	}
+ 
++	result = ps3_open_hv_device(&dev->did);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: lv1_open_device failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
++		result = -EPERM;
++		goto fail_open;
++	}
++
++	result = ps3_dma_region_create(dev->d_region);
++
++	if (result) {
++		dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
++			"(%d)\n", __func__, __LINE__, result);
++		BUG_ON("check region type");
++		goto fail_dma_region;
++	}
++
+ 	result = ps3_mmio_region_create(dev->m_region);
+ 
+ 	if (result) {
+ 		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ 			__func__, __LINE__);
+ 		result = -EPERM;
+-		goto fail_mmio;
++		goto fail_mmio_region;
+ 	}
+ 
+ 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+@@ -122,6 +142,11 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+ 
+ 	hcd->rsrc_start = dev->m_region->lpar_addr;
+ 	hcd->rsrc_len = dev->m_region->len;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
++		dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
++			__func__, __LINE__);
++
+ 	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+ 
+ 	if (!hcd->regs) {
+@@ -155,12 +180,17 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+ fail_add_hcd:
+ 	iounmap(hcd->regs);
+ fail_ioremap:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ 	usb_put_hcd(hcd);
+ fail_create_hcd:
+ 	ps3_io_irq_destroy(virq);
+ fail_irq:
+ 	ps3_free_mmio_region(dev->m_region);
+-fail_mmio:
++fail_mmio_region:
++	ps3_dma_region_free(dev->d_region);
++fail_dma_region:
++	ps3_close_hv_device(&dev->did);
++fail_open:
+ fail_start:
+ 	return result;
+ }
+@@ -170,9 +200,27 @@ static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+ 	struct usb_hcd *hcd =
+ 		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+ 
+-	usb_put_hcd(hcd);
++	BUG_ON(!hcd);
++
++	dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
++	dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
++
++	usb_remove_hcd(hcd);
++
+ 	ps3_system_bus_set_driver_data(dev, NULL);
+ 
++	BUG_ON(!hcd->regs);
++	iounmap(hcd->regs);
++
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++
++	ps3_io_irq_destroy(hcd->irq);
++	ps3_free_mmio_region(dev->m_region);
++
++	ps3_dma_region_free(dev->d_region);
++	ps3_close_hv_device(&dev->did);
++
+ 	return 0;
+ }
+ 
+@@ -185,4 +233,5 @@ static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+ 	},
+ 	.probe = ps3_ohci_sb_probe,
+ 	.remove = ps3_ohci_sb_remove,
++	.shutdown = ps3_ohci_sb_remove,
+ };
+diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
+index 9756a72..0237237 100644
+--- a/drivers/video/ps3fb.c
++++ b/drivers/video/ps3fb.c
+@@ -1094,19 +1094,11 @@ err:
+ 	return retval;
+ }
+ 
+-static void ps3fb_shutdown(struct platform_device *dev)
+-{
+-	ps3fb_flip_ctl(0);	/* flip off */
+-	ps3fb.dinfo->irq.mask = 0;
+-	free_irq(ps3fb.irq_no, ps3fb.dev);
+-	ps3_irq_plug_destroy(ps3fb.irq_no);
+-	iounmap((u8 __iomem *)ps3fb.dinfo);
+-}
+-
+ void ps3fb_cleanup(void)
+ {
+ 	int status;
+ 
++	printk(" -> %s:%d\n", __func__, __LINE__);
+ 	if (ps3fb.task) {
+ 		struct task_struct *task = ps3fb.task;
+ 		ps3fb.task = NULL;
+@@ -1135,15 +1127,32 @@ static int ps3fb_remove(struct platform_device *dev)
+ {
+ 	struct fb_info *info = platform_get_drvdata(dev);
+ 
++	printk(" -> %s:%d\n", __func__, __LINE__);
++
+ 	if (info) {
+ 		unregister_framebuffer(info);
+ 		fb_dealloc_cmap(&info->cmap);
+ 		framebuffer_release(info);
+ 	}
+ 	ps3fb_cleanup();
++	printk(" <- %s:%d\n", __func__, __LINE__);
+ 	return 0;
+ }
+ 
++static void ps3fb_shutdown(struct platform_device *dev)
++{
++	printk(" -> %s:%d\n", __func__, __LINE__);
++
++	ps3fb_remove(dev);
++
++	ps3fb_flip_ctl(0);	/* flip off */
++	ps3fb.dinfo->irq.mask = 0;
++	free_irq(ps3fb.irq_no, ps3fb.dev);
++	ps3_irq_plug_destroy(ps3fb.irq_no);
++	iounmap((u8 __iomem *)ps3fb.dinfo);
++	printk(" <- %s:%d\n", __func__, __LINE__);
++}
++
+ static struct platform_driver ps3fb_driver = {
+ 	.probe	= ps3fb_probe,
+ 	.remove = ps3fb_remove,
+diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
+index 46e8282..0369120 100644
+--- a/include/asm-powerpc/ps3.h
++++ b/include/asm-powerpc/ps3.h
+@@ -59,6 +59,8 @@ struct ps3_device_id {
+ 	unsigned int dev_id;
+ };
+ 
++int ps3_open_hv_device(struct ps3_device_id *did);
++int ps3_close_hv_device(struct ps3_device_id *did);
+ 
+ /* dma routines */
+ 
+@@ -357,6 +359,7 @@ struct ps3_system_bus_driver {
+ 	struct device_driver core;
+ 	int (*probe)(struct ps3_system_bus_device *);
+ 	int (*remove)(struct ps3_system_bus_device *);
++	int (*shutdown)(struct ps3_system_bus_device *);
+ /*	int (*suspend)(struct ps3_system_bus_device *, pm_message_t); */
+ /*	int (*resume)(struct ps3_system_bus_device *); */
+ };

linux-2.6-ps3-legacy-ioport.patch:

Index: linux-2.6-ps3-legacy-ioport.patch
===================================================================
RCS file: linux-2.6-ps3-legacy-ioport.patch
diff -N linux-2.6-ps3-legacy-ioport.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-legacy-ioport.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,22 @@
+--- linux-2.6.20.ppc64/arch/powerpc/platforms/ps3/setup.c.orig	2007-03-30 00:45:59.000000000 +0100
++++ linux-2.6.20.ppc64/arch/powerpc/platforms/ps3/setup.c	2007-03-30 00:48:29.000000000 +0100
+@@ -230,6 +230,11 @@ static void ps3_machine_kexec(struct kim
+ }
+ #endif
+ 
++static int ps3_check_legacy_ioport(unsigned int baseport)
++{
++        return -ENODEV;
++}
++
+ define_machine(ps3) {
+ 	.name				= "PS3",
+ 	.probe				= ps3_probe,
+@@ -240,6 +245,7 @@ define_machine(ps3) {
+ 	.set_rtc_time			= ps3_set_rtc_time,
+ 	.get_rtc_time			= ps3_get_rtc_time,
+ 	.calibrate_decr			= ps3_calibrate_decr,
++	.check_legacy_ioport		= ps3_check_legacy_ioport,
+ 	.progress			= ps3_progress,
+ 	.restart			= ps3_restart,
+ 	.power_off			= ps3_power_off,

linux-2.6-ps3-memory-probe.patch:

Index: linux-2.6-ps3-memory-probe.patch
===================================================================
RCS file: linux-2.6-ps3-memory-probe.patch
diff -N linux-2.6-ps3-memory-probe.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-memory-probe.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,36 @@
+--- linux-2.6.20.ppc64/include/asm-powerpc/lmb.h~	2007-02-04 18:44:54.000000000 +0000
++++ linux-2.6.20.ppc64/include/asm-powerpc/lmb.h	2007-03-30 01:13:45.000000000 +0100
+@@ -51,6 +51,7 @@ extern unsigned long __init __lmb_alloc_
+ extern unsigned long __init lmb_phys_mem_size(void);
+ extern unsigned long __init lmb_end_of_DRAM(void);
+ extern void __init lmb_enforce_memory_limit(unsigned long memory_limit);
++void __init lmb_reset_available(void);
+ 
+ extern void lmb_dump_all(void);
+ 
+--- linux-2.6.20.ppc64/arch/powerpc/mm/lmb.c~	2007-02-04 18:44:54.000000000 +0000
++++ linux-2.6.20.ppc64/arch/powerpc/mm/lmb.c	2007-03-30 01:12:17.000000000 +0100
+@@ -338,3 +338,11 @@ void __init lmb_enforce_memory_limit(uns
+ 		}
+ 	}
+ }
++
++void __init lmb_reset_available(void)
++{
++	lmb.memory.region[0].base = 0;
++	lmb.memory.region[0].size = 0;
++	lmb.memory.cnt = 1;
++	lmb.memory.size = 0;
++}
+--- linux-2.6.20.ppc64/arch/powerpc/platforms/ps3/mm.c~	2007-03-29 17:48:27.000000000 +0100
++++ linux-2.6.20.ppc64/arch/powerpc/platforms/ps3/mm.c	2007-03-30 01:24:04.000000000 +0100
+@@ -796,6 +796,9 @@ void __init ps3_mm_init(void)
+ 
+ 	DBG(" -> %s:%d\n", __func__, __LINE__);
+ 
++	/* If an old-style device-tree registered memory, forget it */
++	lmb_reset_available();
++
+ 	result = ps3_repository_read_mm_info(&map.rm.base, &map.rm.size,
+ 		&map.total);
+ 

linux-2.6-ps3-smp-boot.patch:

Index: linux-2.6-ps3-smp-boot.patch
===================================================================
RCS file: linux-2.6-ps3-smp-boot.patch
diff -N linux-2.6-ps3-smp-boot.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-smp-boot.patch	12 Jul 2007 21:31:10 -0000	1.4
@@ -0,0 +1,52 @@
+As of 2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440):
+
+ps3-wip/powerpc-localize-mmu-off.diff
+ps3-wip/powerpc-wait-for-secondary.diff
+
+--- linux-2.6.20.ppc64/arch/powerpc/kernel/head_64.S.orig	2007-04-16 14:40:03.000000000 +0100
++++ linux-2.6.20.ppc64/arch/powerpc/kernel/head_64.S	2007-04-16 14:40:18.000000000 +0100
+@@ -103,8 +103,8 @@ __secondary_hold_acknowledge:
+ 
+ 	. = 0x60
+ /*
+- * The following code is used on pSeries to hold secondary processors
+- * in a spin loop after they have been freed from OpenFirmware, but
++ * The following code is used to hold secondary processors
++ * in a spin loop after they have entered the kernel, but
+  * before the bulk of the kernel has been relocated.  This code
+  * is relocated to physical address 0x60 before prom_init is run.
+  * All of it must fit below the first exception vector at 0x100.
+@@ -1689,9 +1689,32 @@ _GLOBAL(__start_initialization_multiplat
+ 2:
+ 
+ 	/* Switch off MMU if not already */
+-	LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
++	LOAD_REG_IMMEDIATE(r4, __mmu_off_return - KERNELBASE)
+ 	add	r4,r4,r30
+ 	bl	.__mmu_off
++__mmu_off_return:
++
++	/* Test if this is a secondary cpu and if so send it off to
++	 * __secondary_hold with a thread number in r3.  Secondary processors
++	 * call _start with regs r3,r4,r5 zeroed.
++	 * Pass cpu number in r6???
++	 */
++	or.	r3, r31, r30
++	bne	1f
++	li	r3, 1
++	b	.__secondary_hold
++1:
++
++	/* The primary cpu waits here for all the expected secondary cpus to
++	 * enter the kernel, after which time it is safe to reclaim the
++	 * memory use by the bootwrapper.
++	 * How to know what to wait for???
++	 * !!! need to use the kexec entry mechanism here!!!!
++	*/
++1:	LOAD_REG_IMMEDIATE(r4, __secondary_hold_acknowledge)
++	cmpwi	r4, 0
++	beq	1b
++	mr	r3, r30
+ 	b	.__after_prom_start
+ 
+ _STATIC(__boot_from_prom)

linux-2.6-ps3-sound-autoload.patch:

Index: linux-2.6-ps3-sound-autoload.patch
===================================================================
RCS file: linux-2.6-ps3-sound-autoload.patch
diff -N linux-2.6-ps3-sound-autoload.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-sound-autoload.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,10 @@
+--- linux-2.6.21.ppc64/sound/ppc/snd_ps3.c~	2007-05-04 15:14:46.000000000 +0100
++++ linux-2.6.21.ppc64/sound/ppc/snd_ps3.c	2007-05-04 15:47:10.000000000 +0100
+@@ -45,6 +45,7 @@
+ MODULE_LICENSE("GPL v2");
+ MODULE_DESCRIPTION("PS3 sound driver");
+ MODULE_AUTHOR("Sony Computer Entertainment Inc.");
++MODULE_ALIAS("ps3:9");
+ 
+ static int index = SNDRV_DEFAULT_IDX1;
+ static char *id = SNDRV_DEFAULT_STR1;

linux-2.6-ps3-sound.patch:

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.3 -r 1.4 linux-2.6-ps3-sound.patch
Index: linux-2.6-ps3-sound.patch
===================================================================
RCS file: linux-2.6-ps3-sound.patch
diff -N linux-2.6-ps3-sound.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-sound.patch	12 Jul 2007 21:31:10 -0000	1.4
@@ -0,0 +1,2449 @@
+As of 2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440):
+
+ps3-wip/ps3snd-core.diff
+ps3-wip/ps3snd-bugfix.diff
+ps3-wip/ps3snd-glue-2.6.20.diff
+ps3-wip/ps3snd-core-2.6.20-version-up.diff
+ps3-wip/ps3snd-lv1-returns-int.diff
+ps3-wip/ps3snd-kill-iopte-failure.diff
+ps3-wip/ps3snd-fix-noise.diff
+ps3-wip/ps3snd-fix-style.diff
+
+ps3-wip/ps3-ioc0-dma-sound.diff
+
+unchanged:
+--- a/include/asm-powerpc/lv1call.h
++++ b/include/asm-powerpc/lv1call.h
+@@ -238,6 +238,7 @@ LV1_CALL(destruct_virtual_address_space,                1, 0,  10 )
+ LV1_CALL(configure_irq_state_bitmap,                    3, 0,  11 )
+ LV1_CALL(connect_irq_plug_ext,                          5, 0,  12 )
+ LV1_CALL(release_memory,                                1, 0,  13 )
++LV1_CALL(put_iopte,                                     5, 0,  15 )
+ LV1_CALL(disconnect_irq_plug_ext,                       3, 0,  17 )
+ LV1_CALL(construct_event_receive_port,                  0, 1,  18 )
+ LV1_CALL(destruct_event_receive_port,                   1, 0,  19 )
+@@ -268,6 +269,8 @@ LV1_CALL(remove_repository_node,                        4, 0,  93 )
+ LV1_CALL(read_htab_entries,                             2, 5,  95 )
+ LV1_CALL(set_dabr,                                      2, 0,  96 )
+ LV1_CALL(get_total_execution_time,                      2, 1, 103 )
++LV1_CALL(allocate_io_segment,                           3, 1, 116 )
++LV1_CALL(release_io_segment,                            2, 0, 117 )
+ LV1_CALL(construct_io_irq_outlet,                       1, 1, 120 )
+ LV1_CALL(destruct_io_irq_outlet,                        1, 0, 121 )
+ LV1_CALL(map_htab,                                      1, 1, 122 )
+unchanged:
+--- a/sound/ppc/Kconfig
++++ b/sound/ppc/Kconfig
+@@ -33,3 +33,23 @@ config SND_POWERMAC_AUTO_DRC
+ 	  option.
+ 
+ endmenu
++
++menu "ALSA PowerPC devices"
++	depends on SND!=n && ( PPC64 || PPC32 )
++
++config SND_PS3
++	tristate "PS3 Audio support"
++	depends on SND && PS3_PS3AV
++	select SND_PCM
++	default m
++	help
++	  Say Y here to include support for audio on the PS3
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called snd_ps3.
++
++config SND_PS3_DEFAULT_START_DELAY
++	int "Startup delay time in ms"
++	depends on SND_PS3
++	default "2000"
++endmenu
+unchanged:
+--- a/sound/ppc/Makefile
++++ b/sound/ppc/Makefile
+@@ -6,4 +6,5 @@
+ snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
+ 
+ # Toplevel Module Dependency
+-obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
++obj-$(CONFIG_SND_POWERMAC)	+= snd-powermac.o
++obj-$(CONFIG_SND_PS3)		+= snd_ps3.o
+diff -u b/sound/ppc/snd_ps3.c ps3-linux-dev/sound/ppc/snd_ps3.c
+--- b/sound/ppc/snd_ps3.c	2007-05-04 12:30:20.000000000 +0100
++++ ps3-linux-dev/sound/ppc/snd_ps3.c
+@@ -0,0 +1,1304 @@
++/*
++ * Audio support for PS3
++ * Copyright (C) 2007 Sony Computer Entertainment Inc.
++ * All rights reserved.
++ * Copyright 2006, 2007 Sony Corporation
++ *
++ * 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; version 2 of the Licence.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ */
++
++#define DEBUG
++#undef _SND_PS3_DEV_ATTR
++
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/interrupt.h>
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++#include <sound/asound.h>
++#include <sound/memalloc.h>
++#include <sound/pcm_params.h>
++#include <sound/control.h>
++#include <linux/dmapool.h>
++#include <linux/dma-mapping.h>
++#include <asm/firmware.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/lv1call.h>
++#include <asm/ps3.h>
++#include <asm/ps3av.h>
++
++#include "snd_ps3_reg.h"
++#include "snd_ps3.h"
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("PS3 sound driver");
++MODULE_AUTHOR("Sony Computer Entertainment Inc.");
++
++static int index = SNDRV_DEFAULT_IDX1;
++static char *id = SNDRV_DEFAULT_STR1;
++
++module_param(index, int, 0444);
++MODULE_PARM_DESC(index, "Index value for PS3 soundchip.");
++module_param(id, charp, 0444);
++MODULE_PARM_DESC(id, "ID string for PS3 soundchip.");
++
++
++module_init(snd_ps3_init);
++module_exit(snd_ps3_exit);
++
++
++#if defined(_SND_PS3_DEV_ATTR)
++static DEVICE_ATTR(start_delay,
++		   S_IRUGO | S_IWUSR,
++		   snd_ps3_get_start_delay,
++		   snd_ps3_set_start_delay);
++#endif
++
++/*
++ * global
++ */
++struct snd_ps3_card_info the_card;
++
++static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY;
++
++module_param_named(start_delay, snd_ps3_start_delay, int, 0444);
++MODULE_PARM_DESC(start_delay, "time to insert silent data in milisec");
++
++/*
++ * PS3 audio register access macros
++ */
++
++/*
++ * chip: pointer to snd_ps3_card_info
++ * name: register offset value; PS3_AUDIO_XXXX
++ */
++#define AUDIOREGPTR(chip, name) \
++	(volatile uint32_t *)(chip->mapped_mmio_vaddr + name)
++
++#define AUDIOREG(chip, name) *(AUDIOREGPTR(chip, name))
++
++/*
++ * ALSA defs
++ */
++const static struct snd_pcm_hardware snd_ps3_pcm_hw = {
++        .info = (SNDRV_PCM_INFO_MMAP |
++                 SNDRV_PCM_INFO_NONINTERLEAVED |
++                 SNDRV_PCM_INFO_MMAP_VALID),
++        .formats = (SNDRV_PCM_FMTBIT_S16_BE |
++		    SNDRV_PCM_FMTBIT_S24_BE),
++        .rates = (SNDRV_PCM_RATE_44100 |
++		  SNDRV_PCM_RATE_48000 |
++		  SNDRV_PCM_RATE_88200 |
++		  SNDRV_PCM_RATE_96000),
++        .rate_min = 44100,
++        .rate_max = 96000,
++
++        .channels_min = 2, /* stereo only */
++        .channels_max = 2,
++
++        .buffer_bytes_max = PS3_AUDIO_FIFO_SIZE * 64,
++
++	/* interrupt by four stages */
++        .period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
++        .period_bytes_max = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
++
[...2056 lines suppressed...]
++Configures user bit settings for each block (384 bits).
++Output is performed from the MSB(ao_spdub0 register bit 31).
++
++
++ 31            24 23           16 15            8 7             0
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++ |                             SPOUB                             | AO_SPDUB
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++*/
++/*******************************************************************************
++ *
++ * DMAC register
++ *
++ *******************************************************************************/
++/*
++The PS3_AUDIO_KICK register is used to initiate a DMA transfer and monitor its status
++
++
++ 31            24 23           16 15            8 7             0
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++ |0 0 0 0 0|STATU|0 0 0|  EVENT  |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|R| KICK
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++*/
++/*
++The REQUEST field is written to ACTIVE to initiate a DMA request when EVENT occurs.
++It will return to the DONE state when the request is completed.
++The registers for a DMA channel should only be written if REQUEST is IDLE.
++*/
++
++#define PS3_AUDIO_KICK_REQUEST                           (1 << 0) /* RWIVF */
++#define PS3_AUDIO_KICK_REQUEST_IDLE                      (0 << 0) /* RWI-V */
++#define PS3_AUDIO_KICK_REQUEST_ACTIVE                    (1 << 0) /* -W--T */
++
++/* The EVENT field is used to set the event in which the DMA request becomes active. */
++#define PS3_AUDIO_KICK_EVENT_MASK                        (0x1f << 16) /* RWIVF */
++#define PS3_AUDIO_KICK_EVENT_ALWAYS                      (0x00 << 16) /* RWI-V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY            (0x01 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_UNDERFLOW        (0x02 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_EMPTY            (0x03 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_UNDERFLOW        (0x04 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_EMPTY            (0x05 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_UNDERFLOW        (0x06 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_EMPTY            (0x07 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_UNDERFLOW        (0x08 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SPDIF0_BLOCKTRANSFERCOMPLETE (0x09 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SPDIF0_UNDERFLOW            (0x0A << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SPDIF0_EMPTY                (0x0B << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SPDIF1_BLOCKTRANSFERCOMPLETE (0x0C << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SPDIF1_UNDERFLOW            (0x0D << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_SPDIF1_EMPTY                (0x0E << 16) /* RW--V */
++
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA(n)                ((0x13 + (n)) << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA0                  (0x13 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA1                  (0x14 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA2                  (0x15 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA3                  (0x16 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA4                  (0x17 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA5                  (0x18 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA6                  (0x19 << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA7                  (0x1A << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA8                  (0x1B << 16) /* RW--V */
++#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA9                  (0x1C << 16) /* RW--V */
++
++/*
++The STATUS field can be used to monitor the progress of a DMA request.
++DONE indicates the previous request has completed.
++EVENT indicates that the DMA engine is waiting for the EVENT to occur.
++PENDING indicates that the DMA engine has not started processing this
++request, but the EVENT has occured.
++DMA indicates that the data transfer is in progress.
++NOTIFY indicates that the notifier signalling end of transfer is being written.
++CLEAR indicated that the previous transfer was cleared.
++ERROR indicates the previous transfer requested an unsupported source/destination combination.
++*/
++
++#define PS3_AUDIO_KICK_STATUS_MASK                       (0x7 << 24) /* R-IVF */
++#define PS3_AUDIO_KICK_STATUS_DONE                       (0x0 << 24) /* R-I-V */
++#define PS3_AUDIO_KICK_STATUS_EVENT                      (0x1 << 24) /* R---V */
++#define PS3_AUDIO_KICK_STATUS_PENDING                    (0x2 << 24) /* R---V */
++#define PS3_AUDIO_KICK_STATUS_DMA                        (0x3 << 24) /* R---V */
++#define PS3_AUDIO_KICK_STATUS_NOTIFY                     (0x4 << 24) /* R---V */
++#define PS3_AUDIO_KICK_STATUS_CLEAR                      (0x5 << 24) /* R---V */
++#define PS3_AUDIO_KICK_STATUS_ERROR                      (0x6 << 24) /* R---V */
++
++/*
++The PS3_AUDIO_SOURCE register specifies the source address for transfers.
++
++
++ 31            24 23           16 15            8 7             0
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++ |                      START                      |0 0 0 0 0|TAR| SOURCE
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++*/
++
++/*
++The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
++to a 128 byte boundary.  The low seven bits are assumed to be 0.
++*/
++
++#define PS3_AUDIO_SOURCE_START_MASK                      (0x01FFFFFF << 7) /* RWIUF */
++
++/*
++The TARGET field specifies the memory space containing the source address.
++*/
++
++#define PS3_AUDIO_SOURCE_TARGET_MASK                     (3 << 0) /* RWIVF */
++#define PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY            (2 << 0) /* RW--V */
++
++/*
++The PS3_AUDIO_DEST register specifies the destination address for transfers.
++
++
++ 31            24 23           16 15            8 7             0
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++ |                      START                      |0 0 0 0 0|TAR| DEST
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++*/
++
++/*
++The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
++to a 128 byte boundary.  The low seven bits are assumed to be 0.
++*/
++
++#define PS3_AUDIO_DEST_START_MASK                       (0x01FFFFFF << 7) /* RWIUF */
++
++/*
++The TARGET field specifies the memory space containing the destination address
++AUDIOFIFO = Audio WriteData FIFO,
++*/
++
++#define PS3_AUDIO_DEST_TARGET_MASK                       (3 << 0) /* RWIVF */
++#define PS3_AUDIO_DEST_TARGET_AUDIOFIFO                  (1 << 0) /* RW--V */
++
++/*
++PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer.
++So a value of 0 means 128-bytes will get transfered.
++
++
++ 31            24 23           16 15            8 7             0
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|   BLOCKS    | DMASIZE
++ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
++*/
++
++
++#define PS3_AUDIO_DMASIZE_BLOCKS_MASK                    (0x7f << 0) /* RWIUF */
++
++/*
++ * source/destination address for internal fifos
++ */
++#define PS3_AUDIO_AO_3W_LDATA(n)                         (0x1000 + (0x100 * (n)))
++#define PS3_AUDIO_AO_3W_RDATA(n)                         (0x1080 + (0x100 * (n)))
++
++#define PS3_AUDIO_AO_SPD_DATA(n)                         (0x2000 + (0x400 * (n)))
++
++
++/************************************************************************
++ field attiribute
++
++	Read
++	  ' ' = Other Information
++	  '-' = Field is part of a write-only register
++	  'C' = Value read is always the same, constant value line follows (C)
++	  'R' = Value is read
++
++	Write
++	  ' ' = Other Information
++	  '-' = Must not be written (D), value ignored when written (R,A,F)
++	  'W' = Can be written
++
++	Internal State
++	  ' ' = Other Information
++	  '-' = No internal state
++	  'X' = Internal state, initial value is unknown
++	  'I' = Internal state, initial value is known and follows (I)
++
++	Declaration/Size
++	  ' ' = Other Information
++	  '-' = Does Not Apply
++	  'V' = Type is void
++	  'U' = Type is unsigned integer
++	  'S' = Type is signed integer
++	  'F' = Type is IEEE floating point
++	  '1' = Byte size (008)
++	  '2' = Short size (016)
++	  '3' = Three byte size (024)
++	  '4' = Word size (032)
++	  '8' = Double size (064)
++
++	Define Indicator
++	  ' ' = Other Information
++	  'D' = Device
++	  'M' = Memory
++	  'R' = Register
++	  'A' = Array of Registers
++	  'F' = Field
++	  'V' = Value
++          'T' = Task
++
++ **********************************************************************/

linux-2.6-ps3-storage.patch:

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.3 -r 1.4 linux-2.6-ps3-storage.patch
Index: linux-2.6-ps3-storage.patch
===================================================================
RCS file: linux-2.6-ps3-storage.patch
diff -N linux-2.6-ps3-storage.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-storage.patch	12 Jul 2007 21:31:10 -0000	1.4
@@ -0,0 +1,3288 @@
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/ps3/mm.c ps3/arch/powerpc/platforms/ps3/mm.c
+--- linux-2.6.22.noarch/arch/powerpc/platforms/ps3/mm.c	2007-07-12 17:25:14.000000000 -0400
++++ ps3/arch/powerpc/platforms/ps3/mm.c	2007-07-12 17:25:30.000000000 -0400
+@@ -129,6 +129,16 @@ static void _debug_dump_map(const struct
+ 
+ static struct map map;
+ 
++// FIXME Temporary solution for the storage and sound drivers
++unsigned long ps3_mem_total;
++EXPORT_SYMBOL_GPL(ps3_mem_total);
++unsigned long ps3_rm_limit;
++EXPORT_SYMBOL_GPL(ps3_rm_limit);
++unsigned long ps3_2nd_mem_base;
++EXPORT_SYMBOL_GPL(ps3_2nd_mem_base);
++unsigned long ps3_2nd_mem_size;
++EXPORT_SYMBOL_GPL(ps3_2nd_mem_size);
++
+ /**
+  * ps3_mm_phys_to_lpar - translate a linux physical address to lpar address
+  * @phys_addr: linux physical address
+@@ -1212,6 +1222,12 @@ void __init ps3_mm_init(void)
+ 	/* correct map.total for the real total amount of memory we use */
+ 	map.total = map.rm.size + map.r1.size;
+ 
++	// FIXME Temporary solution for the storage and sound drivers
++	ps3_mem_total = map.rm.size + map.r1.size;
++	ps3_rm_limit = map.rm.size;
++	ps3_2nd_mem_base = map.r1.base;
++	ps3_2nd_mem_size = map.r1.size;
++
+ 	DBG(" <- %s:%d\n", __func__, __LINE__);
+ }
+ 
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/ps3/platform.h ps3/arch/powerpc/platforms/ps3/platform.h
+--- linux-2.6.22.noarch/arch/powerpc/platforms/ps3/platform.h	2007-07-12 17:25:14.000000000 -0400
++++ ps3/arch/powerpc/platforms/ps3/platform.h	2007-07-12 17:25:30.000000000 -0400
+@@ -134,6 +134,8 @@ struct ps3_repository_device {
+ 	struct ps3_device_id did;
+ };
+ 
++int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,
++	unsigned int *bus_index);
+ int ps3_repository_find_device(enum ps3_bus_type bus_type,
+ 	enum ps3_dev_type dev_type,
+ 	const struct ps3_repository_device *start_dev,
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/ps3/repository.c ps3/arch/powerpc/platforms/ps3/repository.c
+--- linux-2.6.22.noarch/arch/powerpc/platforms/ps3/repository.c	2007-07-12 17:25:14.000000000 -0400
++++ ps3/arch/powerpc/platforms/ps3/repository.c	2007-07-12 17:25:30.000000000 -0400
+@@ -182,6 +182,7 @@ int ps3_repository_read_bus_id(unsigned 
+ 	*bus_id = v1;
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_read_bus_id);
+ 
+ int ps3_repository_read_bus_type(unsigned int bus_index,
+ 	enum ps3_bus_type *bus_type)
+@@ -197,6 +198,7 @@ int ps3_repository_read_bus_type(unsigne
+ 	*bus_type = v1;
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_read_bus_type);
+ 
+ int ps3_repository_read_bus_num_dev(unsigned int bus_index,
+ 	unsigned int *num_dev)
+@@ -212,6 +214,7 @@ int ps3_repository_read_bus_num_dev(unsi
+ 	*num_dev = v1;
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_read_bus_num_dev);
+ 
+ int ps3_repository_read_dev_str(unsigned int bus_index,
+ 	unsigned int dev_index, const char *dev_str, u64 *value)
+@@ -239,6 +242,7 @@ int ps3_repository_read_dev_id(unsigned 
+ 	*dev_id = v1;
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_read_dev_id);
+ 
+ int ps3_repository_read_dev_type(unsigned int bus_index,
+ 	unsigned int dev_index, enum ps3_dev_type *dev_type)
+@@ -255,6 +259,7 @@ int ps3_repository_read_dev_type(unsigne
+ 	*dev_type = v1;
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_read_dev_type);
+ 
+ int ps3_repository_read_dev_intr(unsigned int bus_index,
+ 	unsigned int dev_index, unsigned int intr_index,
+@@ -274,6 +279,7 @@ int ps3_repository_read_dev_intr(unsigne
+ 	*interrupt_id = v2;
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_read_dev_intr);
+ 
+ int ps3_repository_read_dev_reg_type(unsigned int bus_index,
+ 	unsigned int dev_index, unsigned int reg_index,
+@@ -513,6 +519,31 @@ int ps3_repository_dump_bus_info(void)
+ }
+ #endif /* defined(DEBUG) */
+ 
++int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,
++	unsigned int *bus_index)
++{
++	unsigned int i;
++	enum ps3_bus_type type;
++	int error;
++
++	for (i = from; i < 10; i++) {
++		error = ps3_repository_read_bus_type(i, &type);
++		if (error) {
++			pr_debug("%s:%d read_bus_type failed\n",
++				__func__, __LINE__);
++			*bus_index = UINT_MAX;
++			return error;
++		}
++		if (type == bus_type) {
++			*bus_index = i;
++			return 0;
++		}
++	}
++	*bus_index = UINT_MAX;
++	return -ENODEV;
++}
++EXPORT_SYMBOL_GPL(ps3_repository_find_bus);
++
+ static int find_device(unsigned int bus_index, unsigned int num_dev,
+ 	unsigned int start_dev_index, enum ps3_dev_type dev_type,
+ 	struct ps3_repository_device *dev)
+@@ -541,7 +572,7 @@ static int find_device(unsigned int bus_
+ 	}
+ 
+ 	if (dev_index == num_dev)
+-		return -1;
++		return -ENODEV;
+ 
+ 	pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
+ 		__func__, __LINE__, dev_type, dev_index);
+@@ -577,25 +608,14 @@ int ps3_repository_find_device (enum ps3
+ 
+ 	BUG_ON(start_dev && start_dev->bus_index > 10);
+ 
+-	for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10;
+-		bus_index++) {
+-		enum ps3_bus_type x;
+-
+-		result = ps3_repository_read_bus_type(bus_index, &x);
+-
+-		if (result) {
+-			pr_debug("%s:%d read_bus_type failed\n",
+-				__func__, __LINE__);
+-			dev->bus_index = UINT_MAX;
+-			return result;
+-		}
+-		if (x == bus_type)
+-			break;
++	result = ps3_repository_find_bus(bus_type,
++					 start_dev ? start_dev->bus_index : 0,
++					 &bus_index);
++	if (result) {
++		dev->bus_index = UINT_MAX;
++		return result;
+ 	}
+ 
+-	if (bus_index >= 10)
+-		return -ENODEV;
+-
+ 	pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
+ 		__func__, __LINE__, bus_type, bus_index);
+ 
+@@ -630,6 +650,7 @@ int ps3_repository_find_device (enum ps3
+ 
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_find_device);
+ 
+ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+ 	enum ps3_interrupt_type intr_type, unsigned int *interrupt_id)
+@@ -668,6 +689,7 @@ int ps3_repository_find_interrupt(const 
+ 
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_find_interrupt);
+ 
+ int ps3_repository_find_reg(const struct ps3_repository_device *dev,
+ 	enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
+@@ -949,6 +971,7 @@ int ps3_repository_read_boot_dat_address
+ 		0,
+ 		address, 0);
+ }
++EXPORT_SYMBOL_GPL(ps3_repository_read_stor_dev_info);
+ 
+ int ps3_repository_read_boot_dat_size(unsigned int *size)
+ {
[...2895 lines suppressed...]
++
++enum lv1_atapi_proto {
++	NA_PROTO = -1,
++	NON_DATA_PROTO     = 0,
++	PIO_DATA_IN_PROTO  = 1,
++	PIO_DATA_OUT_PROTO = 2,
++	DMA_PROTO = 3
++};
++
++enum lv1_atapi_in_out {
++	DIR_NA = -1,
++	DIR_WRITE = 0, /* memory -> device */
++	DIR_READ = 1 /* device -> memory */
++};
++
++/*
++ * describe protocol of an ATAPI command
++ */
++struct ps3_stor_dev_info;
++
++struct scsi_command_handler_info {
++	int buflen;
++	int proto;
++	int in_out;
++	int (*cmnd_handler)(struct ps3_stor_dev_info *, struct scsi_cmnd *);
++};
++
++/*
++ * to position parameter
++ */
++enum {
++	NOT_AVAIL          = -1,
++	USE_SRB_10         = -2,
++	USE_SRB_6          = -3,
++	USE_CDDA_FRAME_RAW = -4
++};
++/*
++ * for LV1 maintainance
++ */
++enum  {
++	PS3_STORAGE_PATA_0, /* primary   PATA bus */
++	PS3_STORAGE_PATA_1, /* secondary PATA bus */
++	PS3_STORAGE_FLASH,
++	PS3_STORAGE_NUM_OF_BUS_TYPES /* terminator */
++};
++
++/*
++ * LV1 per physical bus info:
++ * PATA0, PATA1, FLASH
++ */
++struct ps3_stor_lv1_bus_info {
++	int bus_type;           /* PATA0, PATA1, FLASH */
++	int devices;            /* number of devices on the bus */
++	struct list_head dev_list;
++};
++
++/*
++ * LV1 per region info
++ */
++struct ps3_stor_lv1_region_info {
++	int region_index;	/* index of this region       */
++	unsigned int region_id;	/* id of this region          */
++	u64 region_size;	/* region size in sector      */
++	u64 region_start;	/* start sector */
++};
++
++/*
++ * LV1 per device info
++ */
++struct ps3_stor_lv1_dev_info {
++	struct list_head bus_dev_list; /* device list of devices          */
++				       /* which share same physical bus   */
++	struct ps3_stor_dev_info * dev_info;
++	/* repository values */
++	struct ps3_repository_device repo;
++	enum ps3_dev_type device_type;	/* bus#X.dev#Y.type     */
++	u64 attached_port;		/* bus#x.dev#Y.port     */
++	u64 sector_size;		/* bus#X.dev#Y.blk_size */
++
++	/* house keeping */
++	int bus_type;			/* PATA0,1 or FLASH */
++	unsigned int irq_plug_id;
++	unsigned int interrupt_id;
++	u64 dma_region;
++	u64 current_tag;
++	int bus_device_index;		/*
++					 * device index of same lv1 phy bus.
++					 * 0 for first device, 1 for second.
++					 * should be same as SCSI id
++					 */
++	/* regions */
++	unsigned int regions;	/* number of regions reported thru repository */
++	unsigned long accessible_region_flag; /* flag of accessible regions */
++	unsigned int accessible_regions; /* number of accessible regions of this dev.
++				 * currently, this includes region #0
++				 * NOTE: maximum is 8, if exceed, the rest of
++				 * regions are ignored
++				 */
++	struct ps3_stor_lv1_region_info * region_info_array;
++};
++
++enum read_or_write {
++	SCSIDEBUG_READ,
++	SCSIDEBUG_WRITE
++};
++
++
++enum thread_wakeup_reason {
++	SRB_QUEUED,
++	THREAD_TERMINATE
++};
++
++enum bounce_buffer_type {
++	DEDICATED_KMALLOC,
++	DEDICATED_SPECIAL,
++};
++
++struct ps3_stor_dev_info {
++	struct list_head dev_list;
++	struct ps3_stor_lv1_dev_info * lv1_dev_info;
++	struct ps3_stor_host_info *host_info;
++	const struct scsi_command_handler_info * handler_info;
++	unsigned int target;
++
++	u64 sector_size;	/* copied from lv1 repository at initialize */
++	/* devices may change these value */
++	struct rw_semaphore bounce_sem;	/* protect the following members:
++					* bounce_buf (pointer itself, not buffer),
++					* dedicated_bounce_size
++					* max_sectors in scsi_dev->request_queue
++					*/
++	int  dedicated_bounce;	/* set nonzero if the bounce buffer is dedicated */
++	int  dedicated_bounce_size;
++	int  dedicated_dma_region; /* set if partial dma region allocated */
++	enum bounce_buffer_type bounce_type;	/* bounce buffer type */
++	void * bounce_buf;
++	u64 separate_bounce_lpar; /* lpar address for separated buffer  */
++
++	char used;
++
++	/* main thread communication */
++	struct task_struct * thread_struct;
++	spinlock_t srb_lock;
++	struct scsi_cmnd * srb;              /* queued srb; just one srb allowd             */
++	struct semaphore thread_sema;        /* device main thread wakeup                   */
++	struct completion thread_terminated; /* notify thread temination to slave_destory() */
++	int thread_wakeup_reason;
++
++	/* interrupt handler communication */
++	struct completion irq_done;
++	volatile u64 lv1_status;	/* result of get_async_status() */
++	volatile int lv1_retval;	/* return value of get_async_status() */
++
++};
++
++struct ps3_stor_host_info {
++	struct list_head host_list;
++	struct Scsi_Host *scsi_host;
++	struct platform_device dev;
++	struct list_head dev_info_list;
++	struct ps3_stor_lv1_bus_info * lv1_bus_info;
++};
++
++#define from_dev_to_ps3_stor_host(p) \
++	container_of(p, struct ps3_stor_host_info, dev)
++#define from_dev_to_scsi_device(p) \
++	container_of(p, struct scsi_device, sdev_gendev)
++
++
++struct ps3_stor_quirk_probe_info {
++	struct completion irq_done;
++	unsigned int device_id;
++	int lv1_retval;
++	u64 lv1_status;
++	u64 lv1_tag;
++	u64 lv1_ret_tag;
++};
++
++
++#define NOTIFICATION_DEVID ((u64)(-1L))
++
++struct device_probe_info {
++	unsigned int device_id;
++	enum ps3_dev_type device_type;
++	int      found;
++	int      region_expected;
++	int      region_ready;
++};
++
++#endif
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/include/asm-powerpc/ps3.h ps3/include/asm-powerpc/ps3.h
+--- linux-2.6.22.noarch/include/asm-powerpc/ps3.h	2007-07-12 17:25:14.000000000 -0400
++++ ps3/include/asm-powerpc/ps3.h	2007-07-12 17:25:30.000000000 -0400
+@@ -436,5 +436,6 @@ struct ps3_prealloc {
+ };
+ 
+ extern struct ps3_prealloc ps3fb_videomemory;
++extern struct ps3_prealloc ps3_stor_bounce_buffer;
+ 
+ #endif

linux-2.6-ps3-system-bus-rework-2.patch:

Index: linux-2.6-ps3-system-bus-rework-2.patch
===================================================================
RCS file: linux-2.6-ps3-system-bus-rework-2.patch
diff -N linux-2.6-ps3-system-bus-rework-2.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-system-bus-rework-2.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,46 @@
+Relevant parts of ps3-wip/ps3-ioc0-dma-clients-adopted.diff
+
+diff --git a/drivers/net/gelic_net.c b/drivers/net/gelic_net.c
+index 48ad627..82c5744 100644
+--- a/drivers/net/gelic_net.c
++++ b/drivers/net/gelic_net.c
+@@ -1771,7 +1771,8 @@ static int __init
+ ps3_gelic_driver_init (void)
+ {
+ 	return firmware_has_feature(FW_FEATURE_PS3_LV1)
+-		? ps3_system_bus_driver_register(&ps3_gelic_driver)
++		? ps3_system_bus_driver_register(&ps3_gelic_driver,
++						 PS3_IOBUS_SB)
+ 		: -ENODEV;
+ }
+ 
+diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
+index c7458f7..d0881eb 100644
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -973,8 +973,8 @@ static int __init ehci_hcd_init(void)
+ 
+ #ifdef PS3_SYSTEM_BUS_DRIVER
+ 	if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
+-		retval = ps3_system_bus_driver_register(
+-				&PS3_SYSTEM_BUS_DRIVER);
++		retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER,
++							PS3_IOBUS_SB);
+ 		if (retval < 0) {
+ #ifdef PLATFORM_DRIVER
+ 			platform_driver_unregister(&PLATFORM_DRIVER);
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index e8bbe8b..fd2e1ab 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -942,8 +942,8 @@ static int __init ohci_hcd_mod_init(void)
+ 
+ #ifdef PS3_SYSTEM_BUS_DRIVER
+ 	if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
+-		retval = ps3_system_bus_driver_register(
+-				&PS3_SYSTEM_BUS_DRIVER);
++		retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER,
++							PS3_IOBUS_SB);
+ 		if (retval < 0)
+ 			goto error_ps3;
+ 	}

linux-2.6-ps3-system-bus-rework.patch:

Index: linux-2.6-ps3-system-bus-rework.patch
===================================================================
RCS file: linux-2.6-ps3-system-bus-rework.patch
diff -N linux-2.6-ps3-system-bus-rework.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-system-bus-rework.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,1511 @@
+As of 2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440):
+
+ps3-wip/ps3-system-bus-rework.diff
+ps3-wip/ps3-system-bus-uevent.diff
+ps3-wip/ps3-system-bus-add-modinfo-attribute.diff
+
+diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
+index 2014d2b..e1136f7 100644
+--- a/arch/powerpc/platforms/ps3/mm.c
++++ b/arch/powerpc/platforms/ps3/mm.c
+@@ -17,6 +17,7 @@
+  *  along with this program; if not, write to the Free Software
+  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
++#define DEBUG
+ 
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -32,7 +33,7 @@
+ #if defined(DEBUG)
+ #define DBG(fmt...) udbg_printf(fmt)
+ #else
+-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
++#define DBG(fmt...) do { if (0) printk(fmt);} while (0)
+ #endif
+ 
+ enum {
+@@ -329,17 +330,19 @@ core_initcall(ps3_mm_add_memory);
+ /*============================================================================*/
+ 
+ /**
+- * dma_lpar_to_bus - Translate an lpar address to ioc mapped bus address.
++ * dma_sb_lpar_to_bus - Translate an lpar address to ioc mapped bus address.
+  * @r: pointer to dma region structure
+  * @lpar_addr: HV lpar address
+  */
+ 
+-static unsigned long dma_lpar_to_bus(struct ps3_dma_region *r,
++static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r,
+ 	unsigned long lpar_addr)
+ {
+-	BUG_ON(lpar_addr >= map.r1.base + map.r1.size);
+-	return r->bus_addr + (lpar_addr <= map.rm.size ? lpar_addr
+-		: lpar_addr - map.r1.offset);
++	if (lpar_addr >= map.rm.size)
++		lpar_addr -= map.r1.offset;
++	BUG_ON(lpar_addr < r->offset);
++	BUG_ON(lpar_addr >= r->offset + r->len);
++	return r->bus_addr + lpar_addr - r->offset;
+ }
+ 
+ #define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__)
+@@ -351,6 +354,7 @@ static void _dma_dump_region(const struct ps3_dma_region *r, const char* func,
+ 	DBG("%s:%d: page_size  %u\n", func, line, r->page_size);
+ 	DBG("%s:%d: bus_addr   %lxh\n", func, line, r->bus_addr);
+ 	DBG("%s:%d: len        %lxh\n", func, line, r->len);
++	DBG("%s:%d: offset     %lxh\n", func, line, r->offset);
+ }
+ 
+ /**
+@@ -385,6 +389,7 @@ static void _dma_dump_chunk (const struct dma_chunk* c, const char* func,
+ 	DBG("%s:%d: r.bus_addr   %lxh\n", func, line, c->region->bus_addr);
+ 	DBG("%s:%d: r.page_size  %u\n", func, line, c->region->page_size);
+ 	DBG("%s:%d: r.len        %lxh\n", func, line, c->region->len);
++	DBG("%s:%d: r.offset     %lxh\n", func, line, c->region->offset);
+ 	DBG("%s:%d: c.lpar_addr  %lxh\n", func, line, c->lpar_addr);
+ 	DBG("%s:%d: c.bus_addr   %lxh\n", func, line, c->bus_addr);
+ 	DBG("%s:%d: c.len        %lxh\n", func, line, c->len);
+@@ -395,33 +400,62 @@ static struct dma_chunk * dma_find_chunk(struct ps3_dma_region *r,
+ {
+ 	struct dma_chunk *c;
+ 	unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size);
+-	unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
++	unsigned long aligned_len = _ALIGN_UP(len+bus_addr-aligned_bus,
++					      1 << r->page_size);
+ 
+ 	list_for_each_entry(c, &r->chunk_list.head, link) {
+ 		/* intersection */
+-		if (aligned_bus >= c->bus_addr
+-			&& aligned_bus < c->bus_addr + c->len
+-			&& aligned_bus + aligned_len <= c->bus_addr + c->len) {
++		if (aligned_bus >= c->bus_addr &&
++		    aligned_bus + aligned_len <= c->bus_addr + c->len)
+ 			return c;
+-		}
++
+ 		/* below */
+-		if (aligned_bus + aligned_len <= c->bus_addr) {
++		if (aligned_bus + aligned_len <= c->bus_addr)
+ 			continue;
+-		}
++
+ 		/* above */
+-		if (aligned_bus >= c->bus_addr + c->len) {
++		if (aligned_bus >= c->bus_addr + c->len)
+ 			continue;
+-		}
+ 
+ 		/* we don't handle the multi-chunk case for now */
+-
+ 		dma_dump_chunk(c);
+ 		BUG();
+ 	}
+ 	return NULL;
+ }
+ 
+-static int dma_free_chunk(struct dma_chunk *c)
++static struct dma_chunk * dma_find_chunk_lpar(struct ps3_dma_region *r,
++	unsigned long lpar_addr, unsigned long len)
++{
++	struct dma_chunk *c;
++	unsigned long aligned_lpar = _ALIGN_DOWN(lpar_addr, 1 << r->page_size);
++	unsigned long aligned_len = _ALIGN_UP(len + lpar_addr - aligned_lpar,
++					      1 << r->page_size);
++
++	list_for_each_entry(c, &r->chunk_list.head, link) {
++		/* intersection */
++		if (c->lpar_addr <= aligned_lpar &&
++		    aligned_lpar < c->lpar_addr + c->len) {
++			if (aligned_lpar + aligned_len <= c->lpar_addr + c->len)
++				return c;
++			else {
++				dma_dump_chunk(c);
++				BUG();
++			}
++		}
++		/* below */
++		if (aligned_lpar + aligned_len <= c->lpar_addr) {
++			continue;
++		}
++		/* above */
++		if (c->lpar_addr + c->len <= aligned_lpar) {
++			continue;
++		}
++	}
++	return NULL;
++}
++
++static int dma_sb_free_chunk(struct dma_chunk *c)
+ {
+ 	int result = 0;
+ 
+@@ -435,8 +469,39 @@ static int dma_free_chunk(struct dma_chunk *c)
+ 	return result;
+ }
+ 
++static int dma_ioc0_free_chunk(struct dma_chunk *c)
++{
++	int result = 0;
++	int iopage;
++	unsigned long offset;
++	struct ps3_dma_region * r = c->region;
++
++	DBG("%s:start\n", __func__);
++	for (iopage = 0; iopage < (c->len >> r->page_size); iopage++) {
++		offset = (1 << r->page_size) * iopage;
++		/* put INVALID entry */
++		result = lv1_put_iopte(0,
++				       c->bus_addr + offset,
++				       c->lpar_addr + offset,
++				       r->ioid,
++				       0);
++		DBG("%s: bus=%#lx, lpar=%#lx, ioid=%d\n", __func__,
++		    c->bus_addr + offset,
++		    c->lpar_addr + offset,
++		    r->ioid);
++
++		if (result) {
++			DBG("%s:%d: lv1_map_device_dma_region failed: %s\n",
++			    __func__, __LINE__, ps3_result(result));
++		}
++	}
++	kfree(c);
++	DBG("%s:end\n", __func__);
++	return result;
++}
++
+ /**
+- * dma_map_pages - Maps dma pages into the io controller bus address space.
++ * dma_sb_map_pages - Maps dma pages into the io controller bus address space.
+  * @r: Pointer to a struct ps3_dma_region.
+  * @phys_addr: Starting physical address of the area to map.
+  * @len: Length in bytes of the area to map.
+@@ -446,8 +511,8 @@ static int dma_free_chunk(struct dma_chunk *c)
+  * make the HV call to add the pages into the io controller address space.
+  */
+ 
+-static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
+-	unsigned long len, struct dma_chunk **c_out)
++static int dma_sb_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
++	    unsigned long len, struct dma_chunk **c_out, u64 iopte_flag)
+ {
+ 	int result;
+ 	struct dma_chunk *c;
+@@ -461,13 +526,13 @@ static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
+ 
+ 	c->region = r;
+ 	c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
+-	c->bus_addr = dma_lpar_to_bus(r, c->lpar_addr);
++	c->bus_addr = dma_sb_lpar_to_bus(r, c->lpar_addr);
+ 	c->len = len;
+ 
++	BUG_ON(iopte_flag != 0xf800000000000000UL);
+ 	result = lv1_map_device_dma_region(c->region->did.bus_id,
+-		c->region->did.dev_id, c->lpar_addr, c->bus_addr, c->len,
+-		0xf800000000000000UL);
+-
++					   c->region->did.dev_id, c->lpar_addr,
++					   c->bus_addr, c->len, iopte_flag);
+ 	if (result) {
+ 		DBG("%s:%d: lv1_map_device_dma_region failed: %s\n",
+ 			__func__, __LINE__, ps3_result(result));
+@@ -487,25 +552,105 @@ fail_alloc:
+ 	return result;
+ }
+ 
++static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
++			      unsigned long len, struct dma_chunk **c_out,
++			      u64 iopte_flag)
++{
++	int result;
++	struct dma_chunk *c, *last;
++	int iopage, pages;
++	unsigned long offset;
++
++	DBG(KERN_ERR "%s: phy=%#lx, lpar%#lx, len=%#lx\n", __func__,
++	    phys_addr, ps3_mm_phys_to_lpar(phys_addr), len);
++	c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC);
++
++	if (!c) {
++		result = -ENOMEM;
++		goto fail_alloc;
++	}
++
++	c->region = r;
++	c->len = len;
++	c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
++	/* allocate IO address */
++	if (list_empty(&r->chunk_list.head)) {
++		/* first one */
++		c->bus_addr = r->bus_addr;
++	} else {
++		/* derive from last bus addr*/
++		last  = list_entry(r->chunk_list.head.next,
++				   struct dma_chunk, link);
++		c->bus_addr = last->bus_addr + last->len;
++		DBG("%s: last bus=%#lx, len=%#lx\n", __func__,
++		    last->bus_addr, last->len);
++	}
++
++	/* FIXME: check whether length exceeds region size */
++
++	/* build ioptes for the area */
++	pages = len >> r->page_size;
++	DBG("%s: pgsize=%#x len=%#lx pages=%#x iopteflag=%#lx\n", __func__,
++	    r->page_size, r->len, pages, iopte_flag);
++	for (iopage = 0; iopage < pages; iopage++) {
++		offset = (1 << r->page_size) * iopage;
++		result = lv1_put_iopte(0,
++				       c->bus_addr + offset,
++				       c->lpar_addr + offset,
++				       r->ioid,
++				       iopte_flag);
++		if (result) {
++			printk("%s:%d: lv1_map_device_dma_region failed: %s\n",
++			    __func__, __LINE__, ps3_result(result));
++			goto fail_map;
++		}
++		DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__,
++		    iopage, c->bus_addr + offset, c->lpar_addr + offset,
++		    r->ioid);
++	}
++
++	/* be sure that last allocated one is inserted at head */
++	list_add(&c->link, &r->chunk_list.head);
++
++	*c_out = c;
++	DBG("%s: end\n", __func__);
++	return 0;
++
++fail_map:
++	for (iopage--; 0 <= iopage; iopage--) {
++		lv1_put_iopte(0,
++			      c->bus_addr + offset,
++			      c->lpar_addr + offset,
++			      r->ioid,
++			      0);
++	}
++	kfree(c);
++fail_alloc:
++	*c_out = NULL;
++	return result;
++}
++
+ /**
+- * dma_region_create - Create a device dma region.
++ * dma_sb_region_create - Create a device dma region.
+  * @r: Pointer to a struct ps3_dma_region.
+  *
+  * This is the lowest level dma region create routine, and is the one that
+  * will make the HV call to create the region.
+  */
+ 
+-static int dma_region_create(struct ps3_dma_region* r)
++static int dma_sb_region_create(struct ps3_dma_region* r)
+ {
++	u64 len;
+ 	int result;
+ 
+-	r->len = _ALIGN_UP(map.total, 1 << r->page_size);
++	DBG("%s:%u: len = 0x%lx, page_size = %u, offset = 0x%lx\n", __func__,
++	    __LINE__, r->len, r->page_size, r->offset);
+ 	INIT_LIST_HEAD(&r->chunk_list.head);
+ 	spin_lock_init(&r->chunk_list.lock);
+ 
++	len = roundup_pow_of_two(r->len);
+ 	result = lv1_allocate_device_dma_region(r->did.bus_id, r->did.dev_id,
+-		r->len, r->page_size, r->region_type, &r->bus_addr);
+-
++		len, r->page_size, r->region_type, &r->bus_addr);
+ 	dma_dump_region(r);
+ 
+ 	if (result) {
+@@ -517,6 +662,27 @@ static int dma_region_create(struct ps3_dma_region* r)
+ 	return result;
+ }
+ 
++static int dma_ioc0_region_create(struct ps3_dma_region* r)
++{
++	int result;
++
++	INIT_LIST_HEAD(&r->chunk_list.head);
++	spin_lock_init(&r->chunk_list.lock);
++
++	result = lv1_allocate_io_segment(0,
++					 r->len,
++					 r->page_size,
++					 &r->bus_addr);
++	if (result) {
++		DBG("%s:%d: lv1_allocate_io_segment failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
++		r->len = r->bus_addr = 0;
++	}
++	DBG("%s: len=%#lx, pg=%d, bus=%#lx\n", __func__,
++	    r->len, r->page_size, r->bus_addr);
++	return result;
++}
++
+ /**
+  * dma_region_free - Free a device dma region.
+  * @r: Pointer to a struct ps3_dma_region.
+@@ -525,7 +691,7 @@ static int dma_region_create(struct ps3_dma_region* r)
+  * will make the HV call to free the region.
+  */
+ 
+-static int dma_region_free(struct ps3_dma_region* r)
++static int dma_sb_region_free(struct ps3_dma_region* r)
+ {
+ 	int result;
+ 	struct dma_chunk *c;
+@@ -533,7 +699,7 @@ static int dma_region_free(struct ps3_dma_region* r)
+ 
+ 	list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) {
+ 		list_del(&c->link);
+-		dma_free_chunk(c);
++		dma_sb_free_chunk(c);
+ 	}
+ 
+ 	result = lv1_free_device_dma_region(r->did.bus_id, r->did.dev_id,
+@@ -548,8 +714,31 @@ static int dma_region_free(struct ps3_dma_region* r)
+ 	return result;
+ }
+ 
++static int dma_ioc0_region_free(struct ps3_dma_region* r)
++{
++	int result;
++	struct dma_chunk *c, *n;
++
++	DBG("%s: start\n", __func__);
++	list_for_each_entry_safe(c, n, &r->chunk_list.head, link) {
++		list_del(&c->link);
++		dma_ioc0_free_chunk(c);
++	}
++
++	result = lv1_release_io_segment(0, r->bus_addr);
++
++	if (result)
++		DBG("%s:%d: lv1_free_device_dma_region failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
++
++	r->len = r->bus_addr = 0;
++	DBG("%s: end\n", __func__);
++
++	return result;
++}
++
+ /**
+- * dma_map_area - Map an area of memory into a device dma region.
++ * dma_sb_map_area - Map an area of memory into a device dma region.
+  * @r: Pointer to a struct ps3_dma_region.
+  * @virt_addr: Starting virtual address of the area to map.
+  * @len: Length in bytes of the area to map.
+@@ -559,16 +748,19 @@ static int dma_region_free(struct ps3_dma_region* r)
+  * This is the common dma mapping routine.
+  */
+ 
+-static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+-	unsigned long len, unsigned long *bus_addr)
++static int dma_sb_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
++	   unsigned long len, unsigned long *bus_addr,
++	   u64 iopte_flag)
+ {
+ 	int result;
+ 	unsigned long flags;
+ 	struct dma_chunk *c;
+ 	unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
+ 		: virt_addr;
+-
+-	*bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
++	unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size);
++	unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys,
++					      1 << r->page_size);
++	*bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
+ 
+ 	if (!USE_DYNAMIC_DMA) {
+ 		unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
+@@ -588,17 +780,18 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+ 	c = dma_find_chunk(r, *bus_addr, len);
+ 
+ 	if (c) {
++		DBG("%s:%d: reusing mapped chunk", __func__, __LINE__);
++		dma_dump_chunk(c);
+ 		c->usage_count++;
+ 		spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ 		return 0;
+ 	}
+ 
+-	result = dma_map_pages(r, _ALIGN_DOWN(phys_addr, 1 << r->page_size),
+-		_ALIGN_UP(len, 1 << r->page_size), &c);
++	result = dma_sb_map_pages(r, aligned_phys, aligned_len, &c, iopte_flag);
+ 
+ 	if (result) {
+ 		*bus_addr = 0;
+-		DBG("%s:%d: dma_map_pages failed (%d)\n",
++		DBG("%s:%d: dma_sb_map_pages failed (%d)\n",
+ 			__func__, __LINE__, result);
+ 		spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ 		return result;
+@@ -610,8 +803,57 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+ 	return result;
+ }
+ 
++static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
++	     unsigned long len, unsigned long *bus_addr,
++	     u64 iopte_flag)
++{
++	int result;
++	unsigned long flags;
++	struct dma_chunk *c;
++	unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
++		: virt_addr;
++	unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size);
++	unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys,
++					      1 << r->page_size);
++
++	DBG(KERN_ERR "%s: vaddr=%#lx, len=%#lx\n", __func__,
++	    virt_addr, len);
++	DBG(KERN_ERR "%s: ph=%#lx a_ph=%#lx a_l=%#lx\n", __func__,
++	    phys_addr, aligned_phys, aligned_len);
++
++	spin_lock_irqsave(&r->chunk_list.lock, flags);
++	c = dma_find_chunk_lpar(r, ps3_mm_phys_to_lpar(phys_addr), len);
++
++	if (c) {
++		/* FIXME */
++		BUG();
++		*bus_addr = c->bus_addr + phys_addr - aligned_phys;
++		c->usage_count++;
++		spin_unlock_irqrestore(&r->chunk_list.lock, flags);
++		return 0;
++	}
++
++	result = dma_ioc0_map_pages(r, aligned_phys, aligned_len, &c,
++				    iopte_flag);
++
++	if (result) {
++		*bus_addr = 0;
++		DBG("%s:%d: dma_ioc0_map_pages failed (%d)\n",
++			__func__, __LINE__, result);
++		spin_unlock_irqrestore(&r->chunk_list.lock, flags);
++		return result;
++	}
++	*bus_addr = c->bus_addr + phys_addr - aligned_phys;
++	DBG("%s: va=%#lx pa=%#lx a_pa=%#lx bus=%#lx\n", __func__,
++	    virt_addr, phys_addr, aligned_phys, *bus_addr);
++	c->usage_count = 1;
++
++	spin_unlock_irqrestore(&r->chunk_list.lock, flags);
++	return result;
++}
++
+ /**
+- * dma_unmap_area - Unmap an area of memory from a device dma region.
++ * dma_sb_unmap_area - Unmap an area of memory from a device dma region.
+  * @r: Pointer to a struct ps3_dma_region.
+  * @bus_addr: The starting ioc bus address of the area to unmap.
+  * @len: Length in bytes of the area to unmap.
+@@ -619,7 +861,7 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+  * This is the common dma unmap routine.
+  */
+ 
+-int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
++int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
+ 	unsigned long len)
+ {
+ 	unsigned long flags;
+@@ -631,7 +873,8 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
+ 	if (!c) {
+ 		unsigned long aligned_bus = _ALIGN_DOWN(bus_addr,
+ 			1 << r->page_size);
+-		unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
++		unsigned long aligned_len = _ALIGN_UP(len + bus_addr - aligned_bus,
++						      1 << r->page_size);
+ 		DBG("%s:%d: not found: bus_addr %lxh\n",
+ 			__func__, __LINE__, bus_addr);
+ 		DBG("%s:%d: not found: len %lxh\n",
+@@ -647,94 +890,165 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
+ 
+ 	if (!c->usage_count) {
+ 		list_del(&c->link);
+-		dma_free_chunk(c);
++		dma_sb_free_chunk(c);
++	}
++
++	spin_unlock_irqrestore(&r->chunk_list.lock, flags);
++	return 0;
++}
++
++int dma_ioc0_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
++			unsigned long len)
++{
++	unsigned long flags;
++	struct dma_chunk *c;
++
++	DBG("%s: start a=%#lx l=%#lx\n", __func__, bus_addr, len);
++	spin_lock_irqsave(&r->chunk_list.lock, flags);
++	c = dma_find_chunk(r, bus_addr, len);
++
++	if (!c) {
++		unsigned long aligned_bus = _ALIGN_DOWN(bus_addr,
++							1 << r->page_size);
++		unsigned long aligned_len = _ALIGN_UP(len + bus_addr - aligned_bus,
++						      1 << r->page_size);
++		DBG("%s:%d: not found: bus_addr %lxh\n",
++		    __func__, __LINE__, bus_addr);
++		DBG("%s:%d: not found: len %lxh\n",
++		    __func__, __LINE__, len);
++		DBG("%s:%d: not found: aligned_bus %lxh\n",
++		    __func__, __LINE__, aligned_bus);
++		DBG("%s:%d: not found: aligned_len %lxh\n",
++		    __func__, __LINE__, aligned_len);
++		BUG();
++	}
++
++	c->usage_count--;
++
++	if (!c->usage_count) {
++		list_del(&c->link);
++		dma_ioc0_free_chunk(c);
+ 	}
+ 
+ 	spin_unlock_irqrestore(&r->chunk_list.lock, flags);
++	DBG("%s: end\n", __func__);
+ 	return 0;
+ }
+ 
+ /**
+- * dma_region_create_linear - Setup a linear dma maping for a device.
++ * dma_sb_region_create_linear - Setup a linear dma mapping for a device.
+  * @r: Pointer to a struct ps3_dma_region.
+  *
+  * This routine creates an HV dma region for the device and maps all available
+  * ram into the io controller bus address space.
+  */
+ 
+-static int dma_region_create_linear(struct ps3_dma_region *r)
++static int dma_sb_region_create_linear(struct ps3_dma_region *r)
+ {
+ 	int result;
+-	unsigned long tmp;
+-
+-	/* force 16M dma pages for linear mapping */
+-
+-	if (r->page_size != PS3_DMA_16M) {
+-		pr_info("%s:%d: forcing 16M pages for linear map\n",
+-			__func__, __LINE__);
+-		r->page_size = PS3_DMA_16M;
++	unsigned long virt_addr, len, tmp;
++
++	if (r->len > 16*1024*1024) {	// FIXME
++		/* force 16M dma pages for linear mapping */
++		if (r->page_size != PS3_DMA_16M) {
++			pr_info("%s:%d: forcing 16M pages for linear map\n",
++				__func__, __LINE__);
++			r->page_size = PS3_DMA_16M;
++			r->len = _ALIGN_UP(r->len, 1 << r->page_size);
++		}
+ 	}
+ 
+-	result = dma_region_create(r);
+-	BUG_ON(result);
+-
+-	result = dma_map_area(r, map.rm.base, map.rm.size, &tmp);
++	result = dma_sb_region_create(r);
+ 	BUG_ON(result);
+ 
+-	if (USE_LPAR_ADDR)
+-		result = dma_map_area(r, map.r1.base, map.r1.size,
+-			&tmp);
+-	else
+-		result = dma_map_area(r, map.rm.size, map.r1.size,
+-			&tmp);
++	if (r->offset < map.rm.size) {
++		/* Map (part of) 1st RAM chunk */
++		virt_addr = map.rm.base + r->offset;
++		len = map.rm.size - r->offset;
++		if (len > r->len)
++			len = r->len;
++		result = dma_sb_map_area(r, virt_addr, len, &tmp,
++			IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
++		BUG_ON(result);
++	}
+ 
+-	BUG_ON(result);
++	if (r->offset+r->len > map.rm.size) {
++		/* Map (part of) 2nd RAM chunk */
++		virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size;
++		len = r->len;
++		if (r->offset >= map.rm.size)
++			virt_addr += r->offset - map.rm.size;
++		else
++			len -= map.rm.size - r->offset;
++		result = dma_sb_map_area(r, virt_addr, len, &tmp,
++			IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
++		BUG_ON(result);
++	}
+ 
+ 	return result;
+ }
+ 
+ /**
+- * dma_region_free_linear - Free a linear dma mapping for a device.
++ * dma_sb_region_free_linear - Free a linear dma mapping for a device.
+  * @r: Pointer to a struct ps3_dma_region.
+  *
+  * This routine will unmap all mapped areas and free the HV dma region.
+  */
+ 
+-static int dma_region_free_linear(struct ps3_dma_region *r)
++static int dma_sb_region_free_linear(struct ps3_dma_region *r)
+ {
+ 	int result;
++	unsigned long bus_addr, len, lpar_addr;
++
++	if (r->offset < map.rm.size) {
++		/* Unmap (part of) 1st RAM chunk */
++		lpar_addr = map.rm.base + r->offset;
++		len = map.rm.size - r->offset;
++		if (len > r->len)
++			len = r->len;
++		bus_addr = dma_sb_lpar_to_bus(r, lpar_addr);
++		result = dma_sb_unmap_area(r, bus_addr, len);
++		BUG_ON(result);
++	}
+ 
+-	result = dma_unmap_area(r, dma_lpar_to_bus(r, 0), map.rm.size);
+-	BUG_ON(result);
+-
+-	result = dma_unmap_area(r, dma_lpar_to_bus(r, map.r1.base),
+-		map.r1.size);
+-	BUG_ON(result);
++	if (r->offset+r->len > map.rm.size) {
++		/* Unmap (part of) 2nd RAM chunk */
++		lpar_addr = map.r1.base;
++		len = r->len;
++		if (r->offset >= map.rm.size)
++			lpar_addr += r->offset - map.rm.size;
++		else
++			len -= map.rm.size - r->offset;
++		bus_addr = dma_sb_lpar_to_bus(r, lpar_addr);
++		result = dma_sb_unmap_area(r, bus_addr, len);
++		BUG_ON(result);
++	}
+ 
+-	result = dma_region_free(r);
++	result = dma_sb_region_free(r);
+ 	BUG_ON(result);
+ 
+ 	return result;
+ }
+ 
+ /**
+- * dma_map_area_linear - Map an area of memory into a device dma region.
++ * dma_sb_map_area_linear - Map an area of memory into a device dma region.
+  * @r: Pointer to a struct ps3_dma_region.
+  * @virt_addr: Starting virtual address of the area to map.
+  * @len: Length in bytes of the area to map.
+  * @bus_addr: A pointer to return the starting ioc bus address of the area to
+  * map.
+  *
+- * This routine just returns the coresponding bus address.  Actual mapping
++ * This routine just returns the corresponding bus address.  Actual mapping
+  * occurs in dma_region_create_linear().
+  */
+ 
+-static int dma_map_area_linear(struct ps3_dma_region *r,
+-	unsigned long virt_addr, unsigned long len, unsigned long *bus_addr)
++static int dma_sb_map_area_linear(struct ps3_dma_region *r,
++	unsigned long virt_addr, unsigned long len, unsigned long *bus_addr,
++	u64 iopte_flag)
+ {
+ 	unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
+ 		: virt_addr;
+-	*bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
++	*bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
+ 	return 0;
+ }
+ 
+@@ -744,42 +1058,91 @@ static int dma_map_area_linear(struct ps3_dma_region *r,
+  * @bus_addr: The starting ioc bus address of the area to unmap.
+  * @len: Length in bytes of the area to unmap.
+  *
+- * This routine does nothing.  Unmapping occurs in dma_region_free_linear().
++ * This routine does nothing.  Unmapping occurs in dma_sb_region_free_linear().
+  */
+ 
+-static int dma_unmap_area_linear(struct ps3_dma_region *r,
++static int dma_sb_unmap_area_linear(struct ps3_dma_region *r,
+ 	unsigned long bus_addr, unsigned long len)
+ {
+ 	return 0;
++};
++
++static const struct ps3_dma_region_ops ps3_dma_sb_region_ops =  {
++	.create = dma_sb_region_create,
++	.free = dma_sb_region_free,
++	.map = dma_sb_map_area,
++	.unmap = dma_sb_unmap_area
++};
++
++static const struct ps3_dma_region_ops ps3_dma_sb_region_linear_ops = {
++	.create = dma_sb_region_create_linear,
++	.free = dma_sb_region_free_linear,
++	.map = dma_sb_map_area_linear,
++	.unmap = dma_sb_unmap_area_linear
++};
++
++static const struct ps3_dma_region_ops ps3_dma_ioc0_region_ops = {
++	.create = dma_ioc0_region_create,
++	.free = dma_ioc0_region_free,
++	.map = dma_ioc0_map_area,
++	.unmap = dma_ioc0_unmap_area
++};
++
++void ps3_dma_region_init(struct ps3_dma_region *r,
++	const struct ps3_device_id *did, enum ps3_dma_page_size page_size,
++	enum ps3_dma_region_type region_type, void *addr, unsigned long len,
++	enum ps3_iobus_type iobus_type)
++{
++	unsigned long lpar_addr;
++
++	lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0;
++
++	r->did = *did;
++	r->page_size = page_size;
++	r->region_type = region_type;
++	r->offset = lpar_addr;
++	if (r->offset >= map.rm.size)
++		r->offset -= map.r1.offset;
++	r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size);
++
++	switch(iobus_type) {
++	case PS3_IOBUS_SB:
++		r->region_ops =  (USE_DYNAMIC_DMA)
++			? &ps3_dma_sb_region_ops
++			: &ps3_dma_sb_region_linear_ops;
++		break;
++	case PS3_IOBUS_IOC0:
++		r->region_ops = &ps3_dma_ioc0_region_ops;
++		break;
++	default:
++		BUG();
++	}
+ }
++EXPORT_SYMBOL(ps3_dma_region_init);
+ 
+ int ps3_dma_region_create(struct ps3_dma_region *r)
+ {
+-	return (USE_DYNAMIC_DMA)
+-		? dma_region_create(r)
+-		: dma_region_create_linear(r);
++	return r->region_ops->create(r);
+ }
++EXPORT_SYMBOL(ps3_dma_region_create);
+ 
+ int ps3_dma_region_free(struct ps3_dma_region *r)
+ {
+-	return (USE_DYNAMIC_DMA)
+-		? dma_region_free(r)
+-		: dma_region_free_linear(r);
++	return r->region_ops->free(r);
+ }
++EXPORT_SYMBOL(ps3_dma_region_free);
+ 
+ int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr,
+-	unsigned long len, unsigned long *bus_addr)
++	unsigned long len, unsigned long *bus_addr,
++	u64 iopte_flag)
+ {
+-	return (USE_DYNAMIC_DMA)
+-		? dma_map_area(r, virt_addr, len, bus_addr)
+-		: dma_map_area_linear(r, virt_addr, len, bus_addr);
++	return r->region_ops->map(r, virt_addr, len, bus_addr, iopte_flag);
+ }
+ 
+ int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr,
+ 	unsigned long len)
+ {
+-	return (USE_DYNAMIC_DMA) ? dma_unmap_area(r, bus_addr, len)
+-		: dma_unmap_area_linear(r, bus_addr, len);
++	return r->region_ops->unmap(r, bus_addr, len);
+ }
+ 
+ /*============================================================================*/
+@@ -816,6 +1179,9 @@ void __init ps3_mm_init(void)
+ 	/* arrange to do this in ps3_mm_add_memory */
+ 	ps3_mm_region_create(&map.r1, map.total - map.rm.size);
+ 
++	/* correct map.total for the real total amount of memory we use */
++	map.total = map.rm.size + map.r1.size;
++
+ 	DBG(" <- %s:%d\n", __func__, __LINE__);
+ }
+ 
+diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
+index ca04f03..4a1015b 100644
+--- a/arch/powerpc/platforms/ps3/platform.h
++++ b/arch/powerpc/platforms/ps3/platform.h
+@@ -216,4 +216,14 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
+ int ps3_repository_read_spu_resource_id(unsigned int res_index,
+ 	enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
+ 
++/* Page table entries */
++#define IOPTE_PP_W		0x8000000000000000ul /* protection: write */
++#define IOPTE_PP_R		0x4000000000000000ul /* protection: read */
++#define IOPTE_M			0x2000000000000000ul /* coherency required */
++#define IOPTE_SO_R		0x1000000000000000ul /* ordering: writes */
++#define IOPTE_SO_RW             0x1800000000000000ul /* ordering: r & w */
++#define IOPTE_RPN_Mask		0x07fffffffffff000ul /* RPN */
++#define IOPTE_H			0x0000000000000800ul /* cache hint */
++#define IOPTE_IOID_Mask		0x00000000000007fful /* ioid */
++
+ #endif
+diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
+index 3c48cce..a2591b8 100644
+--- a/arch/powerpc/platforms/ps3/system-bus.c
++++ b/arch/powerpc/platforms/ps3/system-bus.c
+@@ -18,6 +18,8 @@
+  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+ 
++#define DEBUG
++
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+@@ -30,6 +32,10 @@
+ 
+ #include "platform.h"
+ 
++static struct device ps3_system_bus = {
++        .bus_id         = "ps3_system",
++};
++
+ #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
+ static void _dump_mmio_region(const struct ps3_mmio_region* r,
+ 	const char* func, int line)
+@@ -41,7 +47,7 @@ static void _dump_mmio_region(const struct ps3_mmio_region* r,
+ 	pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
+ }
+ 
+-int ps3_mmio_region_create(struct ps3_mmio_region *r)
++static int ps3_sb_mmio_region_create(struct ps3_mmio_region *r)
+ {
+ 	int result;
+ 
+@@ -57,9 +63,20 @@ int ps3_mmio_region_create(struct ps3_mmio_region *r)
+ 	dump_mmio_region(r);
+ 	return result;
+ }
++
++static int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r)
++{
++	/* device specific; do nothing currently */
++	return 0;
++}
++
++int ps3_mmio_region_create(struct ps3_mmio_region *r)
++{
++	return r->mmio_ops->create(r);
++}
+ EXPORT_SYMBOL_GPL(ps3_mmio_region_create);
+ 
+-int ps3_free_mmio_region(struct ps3_mmio_region *r)
++static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r)
+ {
+ 	int result;
+ 
+@@ -73,8 +90,53 @@ int ps3_free_mmio_region(struct ps3_mmio_region *r)
+ 	r->lpar_addr = 0;
+ 	return result;
+ }
++
++static int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r)
++{
++	/* device specific; do nothing currently */
++	return 0;
++}
++
++
++int ps3_free_mmio_region(struct ps3_mmio_region *r)
++{
++	return r->mmio_ops->free(r);
++}
++
+ EXPORT_SYMBOL_GPL(ps3_free_mmio_region);
+ 
++static const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = {
++	.create = ps3_sb_mmio_region_create,
++	.free = ps3_sb_free_mmio_region
++};
++
++static const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = {
++	.create = ps3_ioc0_mmio_region_create,
++	.free = ps3_ioc0_free_mmio_region
++};
++
++void ps3_mmio_region_init(struct ps3_mmio_region *r,
++	const struct ps3_device_id* did, unsigned long bus_addr,
++	unsigned long len, enum ps3_mmio_page_size page_size,
++	enum ps3_iobus_type iobus_type)
++{
++	r->did = *did;
++	r->bus_addr = bus_addr;
++	r->len = len;
++	r->page_size = page_size;
++	switch (iobus_type) {
++	case PS3_IOBUS_SB:
++		r->mmio_ops = &ps3_mmio_sb_region_ops;
++		break;
++	case PS3_IOBUS_IOC0:
++		r->mmio_ops = &ps3_mmio_ioc0_region_ops;
++		break;
++	default:
++		BUG();
++	}
++}
++EXPORT_SYMBOL_GPL(ps3_mmio_region_init);
++
+ static int ps3_system_bus_match(struct device *_dev,
+ 	struct device_driver *_drv)
+ {
+@@ -92,21 +154,23 @@ static int ps3_system_bus_match(struct device *_dev,
+ 
+ static int ps3_system_bus_probe(struct device *_dev)
+ {
+-	int result;
++	int result = 0;
+ 	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ 	struct ps3_system_bus_driver *drv =
+ 		to_ps3_system_bus_driver(_dev->driver);
+ 
+-	result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
++	if (dev->did.bus_id)
++		result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
+ 
+-	if (result) {
+-		pr_debug("%s:%d: lv1_open_device failed (%d)\n",
+-			__func__, __LINE__, result);
++	if (result && (result != LV1_BUSY || (dev->match_id != PS3_MATCH_ID_EHCI
++		&& dev->match_id != PS3_MATCH_ID_OHCI))) {
++		pr_debug("%s:%d: lv1_open_device failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
+ 		result = -EACCES;
+ 		goto clean_none;
+ 	}
+ 
+-	if (dev->d_region->did.bus_id) {
++	if (dev->d_region && dev->d_region->did.bus_id) {
+ 		result = ps3_dma_region_create(dev->d_region);
+ 
+ 		if (result) {
+@@ -134,9 +198,11 @@ static int ps3_system_bus_probe(struct device *_dev)
+ 	return result;
+ 
+ clean_dma:
+-	ps3_dma_region_free(dev->d_region);
++	if (dev->d_region && dev->d_region->did.bus_id)
++		ps3_dma_region_free(dev->d_region);
+ clean_device:
+-	lv1_close_device(dev->did.bus_id, dev->did.dev_id);
++	if (dev->did.bus_id)
++		lv1_close_device(dev->did.bus_id, dev->did.dev_id);
+ clean_none:
+ 	return result;
+ }
+@@ -153,18 +219,51 @@ static int ps3_system_bus_remove(struct device *_dev)
+ 		pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
+ 			dev->core.bus_id);
+ 
+-	ps3_dma_region_free(dev->d_region);
+-	ps3_free_mmio_region(dev->m_region);
+-	lv1_close_device(dev->did.bus_id, dev->did.dev_id);
++	if (dev->d_region && dev->d_region->did.dev_id)
++		ps3_dma_region_free(dev->d_region);
++
++	if (dev->did.bus_id)
++		lv1_close_device(dev->did.bus_id, dev->did.dev_id);
+ 
+ 	return 0;
+ }
+ 
++static int ps3_system_bus_uevent(struct device *_dev, char **envp,
++				 int num_envp, char *buffer, int buffer_size)
++{
++	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
++	int i=0, length = 0;
++
++	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
++			   &length, "MODALIAS=ps3:%d",
++			   dev->match_id))
++		return -ENOMEM;
++
++	envp[i] = NULL;
++	return 0;
++}
++
++static ssize_t modalias_show(struct device *_dev, struct device_attribute *a,
++			     char *buf)
++{
++	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
++        int len = snprintf(buf, PAGE_SIZE, "ps3:%d\n", dev->match_id);
++
++        return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
++}
++
++static struct device_attribute ps3_system_bus_dev_attrs[] = {
++        __ATTR_RO(modalias),
++        __ATTR_NULL,
++};
++
+ struct bus_type ps3_system_bus_type = {
+ 	.name = "ps3_system_bus",
+ 	.match = ps3_system_bus_match,
+ 	.probe = ps3_system_bus_probe,
+ 	.remove = ps3_system_bus_remove,
++	.uevent = ps3_system_bus_uevent,
++	.dev_attrs = ps3_system_bus_dev_attrs,
+ };
+ 
+ int __init ps3_system_bus_init(void)
+@@ -173,7 +272,8 @@ int __init ps3_system_bus_init(void)
+ 
+ 	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ 		return -ENODEV;
+-
++	result = device_register(&ps3_system_bus);
++	BUG_ON(result);
+ 	result = bus_register(&ps3_system_bus_type);
+ 	BUG_ON(result);
+ 	return result;
+@@ -185,16 +285,13 @@ core_initcall(ps3_system_bus_init);
+  * Returns the virtual address of the buffer and sets dma_handle
+  * to the dma address (mapping) of the first page.
+  */
+-
+ static void * ps3_alloc_coherent(struct device *_dev, size_t size,
+-	dma_addr_t *dma_handle, gfp_t flag)
++				      dma_addr_t *dma_handle, gfp_t flag)
+ {
+ 	int result;
+ 	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ 	unsigned long virt_addr;
+ 
+-	BUG_ON(!dev->d_region->bus_addr);
+-
+ 	flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
+ 	flag |= __GFP_ZERO;
+ 
+@@ -205,7 +302,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size,
+ 		goto clean_none;
+ 	}
+ 
+-	result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
++	result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle,
++			     IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+ 
+ 	if (result) {
+ 		pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
+@@ -239,7 +337,7 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
+  * byte within the page as vaddr.
+  */
+ 
+-static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
++static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size,
+ 	enum dma_data_direction direction)
+ {
+ 	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+@@ -247,7 +345,8 @@ static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
+ 	unsigned long bus_addr;
+ 
+ 	result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
+-		&bus_addr);
++			     &bus_addr,
++			     IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M);
+ 
+ 	if (result) {
+ 		pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
+@@ -257,6 +356,39 @@ static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
+ 	return bus_addr;
+ }
+ 
++static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, size_t size,
++				      enum dma_data_direction direction)
++{
++	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
++	int result;
++	unsigned long bus_addr;
++	u64 iopte_flag;
++
++	iopte_flag = IOPTE_M;
++	switch (direction) {
++	case DMA_BIDIRECTIONAL:
++		iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW;
++		break;
++	case DMA_TO_DEVICE:
++		iopte_flag |= IOPTE_PP_R | IOPTE_SO_R;
++		break;
++	case DMA_FROM_DEVICE:
++		iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW;
++		break;
++	default:
++		/* not happned */
++		BUG();
++	};
++	result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
++			     &bus_addr, iopte_flag);
++
++	if (result) {
++		pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
++			__func__, __LINE__, result);
++	}
++	return bus_addr;
++}
++
+ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
+ 	size_t size, enum dma_data_direction direction)
+ {
+@@ -271,7 +403,7 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
+ 	}
+ }
+ 
+-static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
++static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
+ 	enum dma_data_direction direction)
+ {
+ 	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+@@ -284,7 +416,7 @@ static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
+ 	for (i = 0; i < nents; i++, sg++) {
+ 		int result = ps3_dma_map(dev->d_region,
+ 			page_to_phys(sg->page) + sg->offset, sg->length,
+-			&sg->dma_address);
++					 &sg->dma_address, 0);
+ 
+ 		if (result) {
+ 			pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
+@@ -299,7 +431,14 @@ static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
+ #endif
+ }
+ 
+-static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
++static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
++			   enum dma_data_direction direction)
++{
++	BUG();
++	return 0;
++}
++
++static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg,
+ 	int nents, enum dma_data_direction direction)
+ {
+ #if defined(CONFIG_PS3_DYNAMIC_DMA)
+@@ -307,20 +446,38 @@ static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
+ #endif
+ }
+ 
++static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg,
++			    int nents, enum dma_data_direction direction)
++{
++	BUG();
++}
++
+ static int ps3_dma_supported(struct device *_dev, u64 mask)
+ {
+ 	return mask >= DMA_32BIT_MASK;
+ }
+ 
+-static struct dma_mapping_ops ps3_dma_ops = {
++struct dma_mapping_ops ps3_sb_dma_ops = {
++	.alloc_coherent = ps3_alloc_coherent,
++	.free_coherent = ps3_free_coherent,
++	.map_single = ps3_sb_map_single,
++	.unmap_single = ps3_unmap_single,
++	.map_sg = ps3_sb_map_sg,
++	.unmap_sg = ps3_sb_unmap_sg,
++	.dma_supported = ps3_dma_supported
++};
++EXPORT_SYMBOL(ps3_sb_dma_ops);
++
++struct dma_mapping_ops ps3_ioc0_dma_ops = {
+ 	.alloc_coherent = ps3_alloc_coherent,
+ 	.free_coherent = ps3_free_coherent,
+-	.map_single = ps3_map_single,
++	.map_single = ps3_ioc0_map_single,
+ 	.unmap_single = ps3_unmap_single,
+-	.map_sg = ps3_map_sg,
+-	.unmap_sg = ps3_unmap_sg,
++	.map_sg = ps3_ioc0_map_sg,
++	.unmap_sg = ps3_ioc0_unmap_sg,
+ 	.dma_supported = ps3_dma_supported
+ };
++EXPORT_SYMBOL(ps3_ioc0_dma_ops);
+ 
+ /**
+  * ps3_system_bus_release_device - remove a device from the system bus
+@@ -340,22 +497,37 @@ static void ps3_system_bus_release_device(struct device *_dev)
+  * object and frees the object in ps3_system_bus_release_device().
+  */
+ 
+-int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
++int ps3_system_bus_device_register(struct ps3_system_bus_device *dev,
++	enum ps3_iobus_type iobus_type)
+ {
+ 	int result;
+-	static unsigned int dev_count = 1;
++	static unsigned int dev_ioc0_count = 1;
++	static unsigned int dev_sb_count = 1;
+ 
+-	dev->core.parent = NULL;
++	if (!dev->core.parent)
++		dev->core.parent = &ps3_system_bus;
+ 	dev->core.bus = &ps3_system_bus_type;
+ 	dev->core.release = ps3_system_bus_release_device;
++	switch (iobus_type) {
++	case PS3_IOBUS_SB:
++		dev->core.archdata.dma_ops = &ps3_sb_dma_ops;
++		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
++			 dev_sb_count++);
++
++		break;
++
++	case PS3_IOBUS_IOC0:
++		dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops;
++		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
++			"ioc0_%02x", dev_ioc0_count++);
++		break;
++	default:
++		BUG();
++	};
+ 
+ 	dev->core.archdata.of_node = NULL;
+-	dev->core.archdata.dma_ops = &ps3_dma_ops;
+ 	dev->core.archdata.numa_node = 0;
+ 
+-	snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
+-		dev_count++);
+-
+ 	pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
+ 
+ 	result = device_register(&dev->core);
+@@ -364,7 +536,8 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
+ 
+ EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
+ 
+-int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
++int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv,
++	enum ps3_iobus_type iobus_type)
+ {
+ 	int result;
+ 
+diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
+index 821581a..25503a5 100644
+--- a/include/asm-powerpc/ps3.h
++++ b/include/asm-powerpc/ps3.h
+@@ -74,28 +74,54 @@ enum ps3_dma_region_type {
+ 	PS3_DMA_INTERNAL = 2,
+ };
+ 
++enum ps3_iobus_type {
++	PS3_IOBUS_IOC0 = 1,
++	PS3_IOBUS_SB
++};
++
++struct ps3_dma_region_ops;
++
+ /**
++ * struct ps3_dma_region_ops - dma region operations
+  * struct ps3_dma_region - A per device dma state variables structure
+  * @did: The HV device id.
+  * @page_size: The ioc pagesize.
+  * @region_type: The HV region type.
+  * @bus_addr: The 'translated' bus address of the region.
+  * @len: The length in bytes of the region.
++ * @offset: The offset from the start of memory of the region.
++ * @ioid: The IOID of the device who owns this region
+  * @chunk_list: Opaque variable used by the ioc page manager.
+  */
+ 
+ struct ps3_dma_region {
++	const struct ps3_dma_region_ops * region_ops;
+ 	struct ps3_device_id did;
+ 	enum ps3_dma_page_size page_size;
+ 	enum ps3_dma_region_type region_type;
+ 	unsigned long bus_addr;
+ 	unsigned long len;
++	unsigned long offset;
++	unsigned char ioid;
++ 	//unsigned long iopte_flag;
+ 	struct {
+ 		spinlock_t lock;
+ 		struct list_head head;
+ 	} chunk_list;
+ };
+ 
++struct ps3_dma_region_ops {
++	int (*create)(struct ps3_dma_region *);
++	int (*free)(struct ps3_dma_region *);
++	int (*map)(struct ps3_dma_region *,
++		   unsigned long virt_addr,
++		   unsigned long len,
++		   unsigned long * bus_addr,
++		   u64 iopte_pp);
++	int (*unmap)(struct ps3_dma_region *,
++		     unsigned long bus_addr,
++		     unsigned long len);
++};
+ /**
+  * struct ps3_dma_region_init - Helper to initialize structure variables
+  *
+@@ -103,18 +129,16 @@ struct ps3_dma_region {
+  * ps3_system_bus_device_register.
+  */
+ 
+-static inline void ps3_dma_region_init(struct ps3_dma_region *r,
+-	const struct ps3_device_id* did, enum ps3_dma_page_size page_size,
+-	enum ps3_dma_region_type region_type)
+-{
+-	r->did = *did;
+-	r->page_size = page_size;
+-	r->region_type = region_type;
+-}
++void ps3_dma_region_init(struct ps3_dma_region *r,
++	 const struct ps3_device_id *did,
++	 enum ps3_dma_page_size page_size,
++	 enum ps3_dma_region_type region_type, void *addr,
++	 unsigned long len, enum ps3_iobus_type iobus_type);
+ int ps3_dma_region_create(struct ps3_dma_region *r);
+ int ps3_dma_region_free(struct ps3_dma_region *r);
+ int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr,
+-	unsigned long len, unsigned long *bus_addr);
++	unsigned long len, unsigned long *bus_addr,
++	u64 iopte_pp);
+ int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr,
+ 	unsigned long len);
+ 
+@@ -125,6 +149,7 @@ enum ps3_mmio_page_size {
+ 	PS3_MMIO_64K = 16U
+ };
+ 
++struct ps3_mmio_region_ops;
+ /**
+  * struct ps3_mmio_region - a per device mmio state variables structure
+  *
+@@ -132,6 +157,7 @@ enum ps3_mmio_page_size {
+  */
+ 
+ struct ps3_mmio_region {
++	const struct ps3_mmio_region_ops * mmio_ops;
+ 	struct ps3_device_id did;
+ 	unsigned long bus_addr;
+ 	unsigned long len;
+@@ -139,6 +165,10 @@ struct ps3_mmio_region {
+ 	unsigned long lpar_addr;
+ };
+ 
++struct ps3_mmio_region_ops {
++	int (*create)(struct ps3_mmio_region *);
++	int (*free)(struct ps3_mmio_region *);
++};
+ /**
+  * struct ps3_mmio_region_init - Helper to initialize structure variables
+  *
+@@ -146,15 +176,10 @@ struct ps3_mmio_region {
+  * ps3_system_bus_device_register.
+  */
+ 
+-static inline void ps3_mmio_region_init(struct ps3_mmio_region *r,
++void ps3_mmio_region_init(struct ps3_mmio_region *r,
+ 	const struct ps3_device_id* did, unsigned long bus_addr,
+-	unsigned long len, enum ps3_mmio_page_size page_size)
+-{
+-	r->did = *did;
+-	r->bus_addr = bus_addr;
+-	r->len = len;
+-	r->page_size = page_size;
+-}
++	unsigned long len, enum ps3_mmio_page_size page_size,
++			  enum ps3_iobus_type iobus_type);
+ int ps3_mmio_region_create(struct ps3_mmio_region *r);
+ int ps3_free_mmio_region(struct ps3_mmio_region *r);
+ unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr);
+@@ -289,6 +314,10 @@ enum ps3_match_id {
+ 	PS3_MATCH_ID_GELIC,
+ 	PS3_MATCH_ID_AV_SETTINGS,
+ 	PS3_MATCH_ID_SYSTEM_MANAGER,
++	PS3_MATCH_ID_STOR_DISK,
++	PS3_MATCH_ID_STOR_ROM,
++	PS3_MATCH_ID_STOR_FLASH,
++	PS3_MATCH_ID_SOUND,
+ };
+ 
+ /**
+@@ -305,6 +334,15 @@ struct ps3_system_bus_device {
+ 	struct device core;
+ };
+ 
++static inline void ps3_system_bus_device_init(struct ps3_system_bus_device * dev,
++		enum ps3_match_id match_id,
++		struct ps3_dma_region * d_region,
++		struct ps3_mmio_region * m_region)
++{
++	dev->match_id = match_id;
++	dev->m_region = m_region;
++	dev->d_region = d_region;
++};
+ /**
+  * struct ps3_system_bus_driver - a driver for a device on the system bus
+  */
+@@ -318,8 +356,10 @@ struct ps3_system_bus_driver {
+ /*	int (*resume)(struct ps3_system_bus_device *); */
+ };
+ 
+-int ps3_system_bus_device_register(struct ps3_system_bus_device *dev);
+-int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv);
++int ps3_system_bus_device_register(struct ps3_system_bus_device *dev,
++				   enum ps3_iobus_type iobus_type);
++int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv,
++				   enum ps3_iobus_type iobus_type);
+ void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv);
+ static inline struct ps3_system_bus_driver *to_ps3_system_bus_driver(
+ 	struct device_driver *_drv)
+--- /dev/null	2007-05-01 15:16:24.100521312 +0100
++++ b/arch/powerpc/platforms/ps3/system-bus-rework.txt	2007-05-04 11:22:01.000000000 +0100
+@@ -0,0 +1,37 @@
++Status of the system-bus re-work
++
++o=working
++x=not working
++
++				flash	kexec		kexec	reboot		insmod	rmmod
++				boot	shutdown	boot	shutdown
++
++CONFIG_GELIC_NET		o(1)
++CONFIG_FB_PS3			o
++CONFIG_USB_EHCI_HCD		o
++CONFIG_USB_OHCI_HCD		o
++CONFIG_PS3_VUART		o
++CONFIG_PS3_STORAGE		o
++CONFIG_PS3_STORAGE_BUS		o
++CONFIG_PS3_STORAGE_FLASH	o
++CONFIG_PS3_STORAGE_DISK		o
++CONFIG_PS3_STORAGE_ROM		o
++CONFIG_SND_PS3			o
++
++
++(1) Root-NFS: Unable to get nfsd port number from server
++    Only tested on FC7
++    Startup timing problem?
++
++--------------------------------------------------------------------------------
++-- drv.probe routines --
++
++ps3_gelic_driver_probe
++fb?
++ps3_ohci_sb_probe
++ps3_ehci_sb_probe
++ps3flash_probe
++ps3disk_probe
++ps3rom_probe
++snd_ps3_driver_probe
++--------------------------------------------------------------------------------

linux-2.6-ps3-usb-autoload.patch:

Index: linux-2.6-ps3-usb-autoload.patch
===================================================================
RCS file: linux-2.6-ps3-usb-autoload.patch
diff -N linux-2.6-ps3-usb-autoload.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-usb-autoload.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,24 @@
+diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
+index 4d781a2..fe485a0 100644
+--- a/drivers/usb/host/ehci-ps3.c
++++ b/drivers/usb/host/ehci-ps3.c
+@@ -182,6 +182,7 @@ static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+ }
+ 
+ MODULE_ALIAS("ps3-ehci");
++MODULE_ALIAS("ps3:1");
+ 
+ static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+ 	.match_id = PS3_MATCH_ID_EHCI,
+diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
+index 62283a3..1004d91 100644
+--- a/drivers/usb/host/ohci-ps3.c
++++ b/drivers/usb/host/ohci-ps3.c
+@@ -185,6 +185,7 @@ static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+ }
+ 
+ MODULE_ALIAS("ps3-ohci");
++MODULE_ALIAS("ps3:2");
+ 
+ static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+ 	.match_id = PS3_MATCH_ID_OHCI,

linux-2.6-ps3-wrap-spu-runctl.patch:

Index: linux-2.6-ps3-wrap-spu-runctl.patch
===================================================================
RCS file: linux-2.6-ps3-wrap-spu-runctl.patch
diff -N linux-2.6-ps3-wrap-spu-runctl.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3-wrap-spu-runctl.patch	12 Jul 2007 21:31:10 -0000	1.5
@@ -0,0 +1,190 @@
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/backing_ops.c ps3/arch/powerpc/platforms/cell/spufs/backing_ops.c
+--- linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/backing_ops.c	2007-07-08 19:32:17.000000000 -0400
++++ ps3/arch/powerpc/platforms/cell/spufs/backing_ops.c	2007-07-12 17:28:28.000000000 -0400
+@@ -284,6 +284,11 @@ static void spu_backing_runcntl_write(st
+ 	spin_unlock(&ctx->csa.register_lock);
+ }
+ 
++static void spu_backing_runcntl_stop(struct spu_context *ctx)
++{
++	spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
++}
++
+ static void spu_backing_master_start(struct spu_context *ctx)
+ {
+ 	struct spu_state *csa = &ctx->csa;
+@@ -374,6 +379,7 @@ struct spu_context_ops spu_backing_ops =
+ 	.get_ls = spu_backing_get_ls,
+ 	.runcntl_read = spu_backing_runcntl_read,
+ 	.runcntl_write = spu_backing_runcntl_write,
++	.runcntl_stop = spu_backing_runcntl_stop,
+ 	.master_start = spu_backing_master_start,
+ 	.master_stop = spu_backing_master_stop,
+ 	.set_mfc_query = spu_backing_set_mfc_query,
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/hw_ops.c ps3/arch/powerpc/platforms/cell/spufs/hw_ops.c
+--- linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/hw_ops.c	2007-07-08 19:32:17.000000000 -0400
++++ ps3/arch/powerpc/platforms/cell/spufs/hw_ops.c	2007-07-12 17:28:28.000000000 -0400
+@@ -220,6 +220,15 @@ static void spu_hw_runcntl_write(struct 
+ 	spin_unlock_irq(&ctx->spu->register_lock);
+ }
+ 
++static void spu_hw_runcntl_stop(struct spu_context *ctx)
++{
++	spin_lock_irq(&ctx->spu->register_lock);
++	out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
++	while(in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
++		cpu_relax();
++	spin_unlock_irq(&ctx->spu->register_lock);
++}
++
+ static void spu_hw_master_start(struct spu_context *ctx)
+ {
+ 	struct spu *spu = ctx->spu;
+@@ -321,6 +330,7 @@ struct spu_context_ops spu_hw_ops = {
+ 	.get_ls = spu_hw_get_ls,
+ 	.runcntl_read = spu_hw_runcntl_read,
+ 	.runcntl_write = spu_hw_runcntl_write,
++	.runcntl_stop = spu_hw_runcntl_stop,
+ 	.master_start = spu_hw_master_start,
+ 	.master_stop = spu_hw_master_stop,
+ 	.set_mfc_query = spu_hw_set_mfc_query,
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/run.c ps3/arch/powerpc/platforms/cell/spufs/run.c
+--- linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/run.c	2007-07-08 19:32:17.000000000 -0400
++++ ps3/arch/powerpc/platforms/cell/spufs/run.c	2007-07-12 17:28:28.000000000 -0400
+@@ -295,7 +295,7 @@ long spufs_run_spu(struct file *file, st
+ 	if (mutex_lock_interruptible(&ctx->run_mutex))
+ 		return -ERESTARTSYS;
+ 
+-	ctx->ops->master_start(ctx);
++	spu_enable_spu(ctx);
+ 	ctx->event_return = 0;
+ 
+ 	ret = spu_acquire_runnable(ctx, 0);
+@@ -336,7 +336,7 @@ long spufs_run_spu(struct file *file, st
+ 	} while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
+ 				      SPU_STATUS_STOPPED_BY_HALT)));
+ 
+-	ctx->ops->master_stop(ctx);
++	spu_disable_spu(ctx);
+ 	ret = spu_run_fini(ctx, npc, &status);
+ 	spu_yield(ctx);
+ 
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/spufs.h ps3/arch/powerpc/platforms/cell/spufs/spufs.h
+--- linux-2.6.22.noarch/arch/powerpc/platforms/cell/spufs/spufs.h	2007-07-08 19:32:17.000000000 -0400
++++ ps3/arch/powerpc/platforms/cell/spufs/spufs.h	2007-07-12 17:28:28.000000000 -0400
+@@ -130,6 +130,7 @@ struct spu_context_ops {
+ 	char*(*get_ls) (struct spu_context * ctx);
+ 	 u32 (*runcntl_read) (struct spu_context * ctx);
+ 	void (*runcntl_write) (struct spu_context * ctx, u32 data);
++	void (*runcntl_stop) (struct spu_context * ctx);
+ 	void (*master_start) (struct spu_context * ctx);
+ 	void (*master_stop) (struct spu_context * ctx);
+ 	int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/cell/spu_manage.c ps3/arch/powerpc/platforms/cell/spu_manage.c
+--- linux-2.6.22.noarch/arch/powerpc/platforms/cell/spu_manage.c	2007-07-08 19:32:17.000000000 -0400
++++ ps3/arch/powerpc/platforms/cell/spu_manage.c	2007-07-12 17:28:28.000000000 -0400
+@@ -35,6 +35,7 @@
+ #include <asm/firmware.h>
+ #include <asm/prom.h>
+ 
++#include "spufs/spufs.h"
+ #include "interrupt.h"
+ 
+ struct device_node *spu_devnode(struct spu *spu)
+@@ -359,8 +360,22 @@ static int of_destroy_spu(struct spu *sp
+ 	return 0;
+ }
+ 
++static int enable_spu_by_master_run(struct spu_context *ctx)
++{
++	ctx->ops->master_start(ctx);
++	return 0;
++}
++
++static int disable_spu_by_master_run(struct spu_context *ctx)
++{
++	ctx->ops->master_stop(ctx);
++	return 0;
++}
++
+ const struct spu_management_ops spu_management_of_ops = {
+ 	.enumerate_spus = of_enumerate_spus,
+ 	.create_spu = of_create_spu,
+ 	.destroy_spu = of_destroy_spu,
++	.enable_spu = enable_spu_by_master_run,
++	.disable_spu = disable_spu_by_master_run,
+ };
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/arch/powerpc/platforms/ps3/spu.c ps3/arch/powerpc/platforms/ps3/spu.c
+--- linux-2.6.22.noarch/arch/powerpc/platforms/ps3/spu.c	2007-07-08 19:32:17.000000000 -0400
++++ ps3/arch/powerpc/platforms/ps3/spu.c	2007-07-12 17:28:28.000000000 -0400
+@@ -28,6 +28,7 @@
+ #include <asm/spu_priv1.h>
+ #include <asm/lv1call.h>
+ 
++#include "../cell/spufs/spufs.h"
+ #include "platform.h"
+ 
+ /* spu_management_ops */
+@@ -407,10 +408,23 @@ static int __init ps3_enumerate_spus(int
+ 	return result;
+ }
+ 
++static int ps3_enable_spu(struct spu_context *ctx)
++{
++	return -ENOSYS;
++}
++
++static int ps3_disable_spu(struct spu_context *ctx)
++{
++	ctx->ops->runcntl_stop(ctx);
++	return -ENOSYS;
++}
++
+ const struct spu_management_ops spu_management_ps3_ops = {
+ 	.enumerate_spus = ps3_enumerate_spus,
+ 	.create_spu = ps3_create_spu,
+ 	.destroy_spu = ps3_destroy_spu,
++	.enable_spu = ps3_enable_spu,
++	.disable_spu = ps3_disable_spu,
+ };
+ 
+ /* spu_priv1_ops */
+diff -urpN --exclude-from=/home/davej/.exclude linux-2.6.22.noarch/include/asm-powerpc/spu_priv1.h ps3/include/asm-powerpc/spu_priv1.h
+--- linux-2.6.22.noarch/include/asm-powerpc/spu_priv1.h	2007-07-08 19:32:17.000000000 -0400
++++ ps3/include/asm-powerpc/spu_priv1.h	2007-07-12 17:28:28.000000000 -0400
+@@ -24,6 +24,7 @@
+ #include <linux/types.h>
+ 
+ struct spu;
++struct spu_context;
+ 
+ /* access to priv1 registers */
+ 
+@@ -178,6 +179,8 @@ 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);
++	int (*enable_spu)(struct spu_context *ctx);
++	int (*disable_spu)(struct spu_context *ctx);
+ };
+ 
+ extern const struct spu_management_ops* spu_management_ops;
+@@ -200,6 +203,18 @@ spu_destroy_spu (struct spu *spu)
+ 	return spu_management_ops->destroy_spu(spu);
+ }
+ 
++static inline int
++spu_enable_spu (struct spu_context *ctx)
++{
++	return spu_management_ops->enable_spu(ctx);
++}
++
++static inline int
++spu_disable_spu (struct spu_context *ctx)
++{
++	return spu_management_ops->disable_spu(ctx);
++}
++
+ /*
+  * The declarations folowing are put here for convenience
+  * and only intended to be used by the platform setup code.

linux-2.6-ps3av-export-header.patch:

Index: linux-2.6-ps3av-export-header.patch
===================================================================
RCS file: linux-2.6-ps3av-export-header.patch
diff -N linux-2.6-ps3av-export-header.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3av-export-header.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,31 @@
+diff --git a/include/asm-powerpc/Kbuild b/include/asm-powerpc/Kbuild
+index 4869513..0f6c60b 100644
+--- a/include/asm-powerpc/Kbuild
++++ b/include/asm-powerpc/Kbuild
+@@ -34,6 +34,7 @@ unifdef-y += elf.h
+ unifdef-y += nvram.h
+ unifdef-y += param.h
+ unifdef-y += posix_types.h
++unifdef-y += ps3av.h
+ unifdef-y += ptrace.h
+ unifdef-y += seccomp.h
+ unifdef-y += signal.h
+diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h
+index 1366fc5..6e34bcf 100644
+--- a/include/asm-powerpc/ps3av.h
++++ b/include/asm-powerpc/ps3av.h
+@@ -664,6 +664,8 @@ struct ps3av_pkt_avb_param {
+ #define PS3AV_STATUS_UNSUPPORTED_HDMI_MODE	0x0012	/* unsupported hdmi mode */
+ #define PS3AV_STATUS_NO_SYNC_HEAD		0x0013	/* sync head failed */
+ 
++#ifdef __KERNEL__
++
+ extern void ps3av_set_hdr(u32, u16, struct ps3av_send_hdr *);
+ extern int ps3av_do_pkt(u32, u16, size_t, struct ps3av_send_hdr *);
+ 
+@@ -716,4 +718,5 @@ extern int ps3av_audio_mute(int);
+ extern int ps3av_dev_open(void);
+ extern int ps3av_dev_close(void);
+ 
++#endif  /* __KERNEL__ */
+ #endif	/* _ASM_POWERPC_PS3AV_H_ */

linux-2.6-ps3fb-panic.patch:

Index: linux-2.6-ps3fb-panic.patch
===================================================================
RCS file: linux-2.6-ps3fb-panic.patch
diff -N linux-2.6-ps3fb-panic.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-ps3fb-panic.patch	12 Jul 2007 21:31:10 -0000	1.3
@@ -0,0 +1,47 @@
+diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
+index ac5df96..1ae9091 100644
+--- a/arch/powerpc/platforms/ps3/setup.c
++++ b/arch/powerpc/platforms/ps3/setup.c
+@@ -46,6 +46,8 @@
+ static void smp_send_stop(void) {}
+ #endif
+ 
++extern void ps3fb_sync(int);
++
+ int ps3_get_firmware_version(union ps3_firmware_version *v)
+ {
+ 	int result = lv1_get_version_info(&v->raw);
+@@ -88,8 +90,20 @@ static void ps3_power_off(void)
+ 
+ static void ps3_panic(char *str)
+ {
++	static int panicked = 0;
++
+ 	DBG("%s:%d %s\n", __func__, __LINE__, str);
+ 
++#ifdef CONFIG_FB_PS3
++	/* It's almost certainly the only available console device outside
++	   Sony, and we don't _see_ the events leading up to the panic 
++	   unless we ask the hypervisor to update it. So do so. Once. */
++	if (!panicked) {
++		panicked = 1;
++		ps3fb_sync(0);
++	}
++#endif
++
+ 	smp_send_stop();
+ 	printk("\n");
+ 	printk("   System does not reboot automatically.\n");
+diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
+index 81e43cd..f90a43e 100644
+--- a/drivers/video/ps3fb.c
++++ b/drivers/video/ps3fb.c
+@@ -381,7 +381,7 @@ static const struct fb_videomode *ps3fb_default_mode(void)
+ 	return &ps3fb_modedb[mode - 1];
+ }
+ 
+-static int ps3fb_sync(u32 frame)
++int ps3fb_sync(u32 frame)
+ {
+ 	int i, status;
+ 	u32 xres, yres;


Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-7/kernel-2.6.spec,v
retrieving revision 1.3277
retrieving revision 1.3278
diff -u -r1.3277 -r1.3278
--- kernel-2.6.spec	12 Jul 2007 20:00:24 -0000	1.3277
+++ kernel-2.6.spec	12 Jul 2007 21:31:10 -0000	1.3278
@@ -579,6 +579,19 @@
 Patch1010: linux-2.6-ondemand-timer.patch
 Patch1020: linux-2.6-usb-autosuspend-default-disable.patch
 Patch1030: linux-2.6-nfs-nosharecache.patch
+Patch1351: linux-2.6-ps3-smp-boot.patch
+Patch1352: linux-2.6-ps3-system-bus-rework.patch
+Patch1353: linux-2.6-ps3-kexec.patch
+Patch1354: linux-2.6-ps3-gelic.patch
+Patch1355: linux-2.6-ps3-gelic-wireless.patch
+Patch1356: linux-2.6-ps3-ehci-iso.patch
+Patch1357: linux-2.6-ps3-clear-spu-irq.patch
+Patch1358: linux-2.6-ps3-wrap-spu-runctl.patch
+# Ignore the SPE logo bits. Cute, but not exactly necessary
+Patch1359: linux-2.6-ps3-storage.patch
+Patch1360: linux-2.6-ps3-sound.patch
+Patch1361: linux-2.6-ps3-device-init.patch
+Patch1362: linux-2.6-ps3-system-bus-rework-2.patch
 
 %endif
 
@@ -1215,6 +1228,20 @@
 # NFS: Add the mount option "nosharecache"
 ApplyPatch linux-2.6-nfs-nosharecache.patch
 
+# PS3 patches.
+ApplyPatch linux-2.6-ps3-smp-boot.patch
+ApplyPatch linux-2.6-ps3-system-bus-rework.patch
+ApplyPatch linux-2.6-ps3-kexec.patch
+ApplyPatch linux-2.6-ps3-gelic.patch
+ApplyPatch linux-2.6-ps3-gelic-wireless.patch
+ApplyPatch linux-2.6-ps3-ehci-iso.patch
+ApplyPatch linux-2.6-ps3-clear-spu-irq.patch
+ApplyPatch linux-2.6-ps3-wrap-spu-runctl.patch
+ApplyPatch linux-2.6-ps3-storage.patch
+ApplyPatch linux-2.6-ps3-sound.patch
+ApplyPatch linux-2.6-ps3-device-init.patch
+ApplyPatch linux-2.6-ps3-system-bus-rework-2.patch
+
 # END OF PATCH APPLICATIONS
 
 # Any further pre-build tree manipulations happen here.
@@ -2136,6 +2163,9 @@
 %endif
 
 %changelog
+* Thu Jul 12 2007 Dave Jones <davej at redhat.com>
+- Add back the rediffed PS3 patches.
+
 * Thu Jul 12 2007 Chuck Ebbert <cebbert at redhat.com>
 - ata: update noncq list
 - idr: multiple bugfixes




More information about the scm-commits mailing list