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