rpms/kernel/devel linux-2.6-ps3-gelic-wireless.patch, NONE, 1.1 linux-2.6-ps3-gelic.patch, NONE, 1.1 linux-2.6-ps3-kexec.patch, NONE, 1.1 linux-2.6-ps3-sound-autoload.patch, NONE, 1.1 linux-2.6-ps3-system-bus-rework-2.patch, NONE, 1.1 linux-2.6-ps3-system-bus-rework.patch, NONE, 1.1 kernel-2.6.spec, 1.3137, 1.3138 linux-2.6-ps3-device-init.patch, 1.1, 1.2 linux-2.6-ps3-ethernet-modular.patch, 1.2, 1.3 linux-2.6-ps3-smp-boot.patch, 1.1, 1.2 linux-2.6-ps3-sound.patch, 1.1, 1.2 linux-2.6-ps3-stable-patches.patch, 1.1, 1.2 linux-2.6-ps3-storage.patch, 1.1, 1.2 linux-2.6-ps3-drivers-only-on-ps3.patch, 1.1, NONE linux-2.6-ps3-ethernet.patch, 1.2, NONE linux-2.6-ps3-exports.patch, 1.1, NONE linux-2.6-ps3-read-cd.patch, 1.1, NONE linux-2.6-ps3-sysbus-modalias.patch, 1.1, NONE linux-2.6-systemsim-work.patch, 1.1, NONE linux-2.6-uevent-ps3.patch, 1.1, NONE linux-2.6-usb-endian-quirks.patch, 1.2, NONE

David Woodhouse (dwmw2) fedora-extras-commits at redhat.com
Fri May 4 14:53:16 UTC 2007


Author: dwmw2

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv19995

Modified Files:
	kernel-2.6.spec linux-2.6-ps3-device-init.patch 
	linux-2.6-ps3-ethernet-modular.patch 
	linux-2.6-ps3-smp-boot.patch linux-2.6-ps3-sound.patch 
	linux-2.6-ps3-stable-patches.patch linux-2.6-ps3-storage.patch 
Added Files:
	linux-2.6-ps3-gelic-wireless.patch linux-2.6-ps3-gelic.patch 
	linux-2.6-ps3-kexec.patch linux-2.6-ps3-sound-autoload.patch 
	linux-2.6-ps3-system-bus-rework-2.patch 
	linux-2.6-ps3-system-bus-rework.patch 
Removed Files:
	linux-2.6-ps3-drivers-only-on-ps3.patch 
	linux-2.6-ps3-ethernet.patch linux-2.6-ps3-exports.patch 
	linux-2.6-ps3-read-cd.patch 
	linux-2.6-ps3-sysbus-modalias.patch 
	linux-2.6-systemsim-work.patch linux-2.6-uevent-ps3.patch 
	linux-2.6-usb-endian-quirks.patch 
Log Message:
Tidy up PS3 bits

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

--- NEW FILE linux-2.6-ps3-gelic-wireless.patch ---
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"
 
 static int ps3_gelic_param = 1; /* vlan desc support */
 #ifdef CONFIG_GELIC_NET_MODULE
@@ -210,33 +78,6 @@ static uint64_t gelic_irq_status;
 
 static int dmac_status = 0;
 
[...2575 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:

--- NEW FILE linux-2.6-ps3-gelic.patch ---
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:

--- NEW FILE linux-2.6-ps3-kexec.patch ---
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-sound-autoload.patch:

--- NEW FILE linux-2.6-ps3-sound-autoload.patch ---
--- 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-system-bus-rework-2.patch:

--- NEW FILE linux-2.6-ps3-system-bus-rework-2.patch ---
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:

--- NEW FILE linux-2.6-ps3-system-bus-rework.patch ---
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
+--------------------------------------------------------------------------------


Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel-2.6.spec,v
retrieving revision 1.3137
retrieving revision 1.3138
diff -u -r1.3137 -r1.3138
--- kernel-2.6.spec	4 May 2007 04:12:27 -0000	1.3137
+++ kernel-2.6.spec	4 May 2007 14:52:31 -0000	1.3138
@@ -401,7 +401,6 @@
 # 300 - 399   ppc(64)
 Patch300: linux-2.6-g5-therm-shutdown.patch
 Patch301: linux-2.6-powerpc-slabalign.patch
-Patch302: linux-2.6-systemsim-work.patch
 Patch303: linux-2.6-ppc32-ucmpdi2.patch
 Patch304: linux-2.6-ibmvscsi-schizo.patch
 Patch305: linux-2.6-pmac-zilog.patch
@@ -414,9 +413,6 @@
 Patch311: linux-2.6-uevent-macio.patch
 Patch312: linux-2.6-uevent-of_platform.patch
 Patch313: linux-2.6-uevent-ebus.patch
-Patch314: linux-2.6-uevent-ps3.patch
-
-Patch320: linux-2.6-usb-endian-quirks.patch
 
 Patch330: linux-2.6-powermac-generic-suspend-1.patch
 Patch331: linux-2.6-powermac-generic-suspend-2.patch
@@ -426,31 +422,31 @@
 Patch340: linux-2.6-mpc52xx-sdma.patch
 Patch341: linux-2.6-mpc52xx-fec.patch
 
-# Patches from ps3-linux-patches.git
+# Patches from ps3-linux-patches.git (2007-05-04)
 Patch350: linux-2.6-ps3-stable-patches.patch
-Patch351: linux-2.6-ps3-replace-irq-alloc-free.patch
-Patch352: linux-2.6-ps3-storage.patch
-Patch353: linux-2.6-ps3-ethernet.patch
-Patch354: linux-2.6-ps3-device-init.patch
-Patch355: linux-2.6-ps3-fix-slowdown-bug.patch
-Patch356: linux-2.6-ps3-sound.patch
-Patch357: linux-2.6-ps3-smp-boot.patch
-Patch358: linux-2.6-ps3-read-cd.patch
-Patch359: linux-2.6-ps3-ehci-iso.patch
-Patch360: linux-2.6-ps3-wrap-spu-runctl.patch
-Patch361: linux-2.6-ps3-clear-spu-irq.patch
-Patch362: linux-2.6-ps3-drivers-only-on-ps3.patch
+Patch351: linux-2.6-ps3-smp-boot.patch
+Patch352: linux-2.6-ps3-system-bus-rework.patch
+Patch353: linux-2.6-ps3-kexec.patch
+Patch354: linux-2.6-ps3-gelic.patch
+Patch355: linux-2.6-ps3-gelic-wireless.patch
+Patch356: linux-2.6-ps3-ehci-iso.patch
+Patch357: linux-2.6-ps3-clear-spu-irq.patch
+Patch358: linux-2.6-ps3-wrap-spu-runctl.patch
+# Ignore the SPE logo bits. Cute, but not exactly necessary
+Patch359: linux-2.6-ps3-storage.patch
+Patch360: linux-2.6-ps3-sound.patch
+Patch361: linux-2.6-ps3-device-init.patch
+Patch362: linux-2.6-ps3-system-bus-rework-2.patch
 
 # And then some minor tweaks...
 Patch370: linux-2.6-ps3-memory-probe.patch
 Patch371: linux-2.6-ps3-legacy-ioport.patch
 Patch372: linux-2.6-ps3fb-panic.patch
 Patch373: linux-2.6-ps3-ethernet-modular.patch
-Patch374: linux-2.6-ps3-exports.patch
+Patch374: linux-2.6-ps3-sound-autoload.patch
 Patch375: linux-2.6-ps3-ethernet-autoload.patch
 Patch376: linux-2.6-ps3av-export-header.patch
 Patch377: linux-2.6-ps3-usb-autoload.patch
-Patch378: linux-2.6-ps3-sysbus-modalias.patch
 
 # 500 - 599   s390(x)
 
@@ -1061,9 +1057,6 @@
 %patch311 -p1
 %patch312 -p1
 %patch313 -p1
-%patch314 -p1
-# Big-endian USB support (Celleb, PS3, Efika)
-#%patch320 -p1
 
 %patch330 -p1
 %patch331 -p1
@@ -1096,7 +1089,6 @@
 %patch375 -p1
 %patch376 -p1
 %patch377 -p1
-%patch378 -p1
 
 # S390
 
@@ -2314,6 +2306,9 @@
 %endif
 
 %changelog
+* Fri May 04 2007 David Woodhouse <davej at redhat.com>
+- Tidy up PS3 patches to match ps3-linux-patches upstream more closely
+
 * Fri May 04 2007 Dave Jones <davej at redhat.com>
 - remove the wildcard from sata_nv driver
 

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

Index: linux-2.6-ps3-device-init.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-ps3-device-init.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6-ps3-device-init.patch	30 Mar 2007 20:10:34 -0000	1.1
+++ linux-2.6-ps3-device-init.patch	4 May 2007 14:52:31 -0000	1.2
@@ -1,21 +1,23 @@
-ps3-wip/ps3-device-init-2.patch
-ps3-wip/ps3-device-init-rework.patch
+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(+)
 
-unchanged:
 --- ps3-linux-dev.orig/arch/powerpc/platforms/ps3/Makefile
 +++ ps3-linux-dev/arch/powerpc/platforms/ps3/Makefile
-@@ -1,6 +1,7 @@
- obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o
- obj-y += interrupt.o exports.o os-area.o
- obj-y += system-bus.o
-+obj-y += device-init.o
+@@ -6,3 +6,4 @@ obj-$(CONFIG_PS3_STORAGE_ROM) += ps3rom.
  
  obj-$(CONFIG_SMP) += smp.o
  obj-$(CONFIG_SPU_BASE) += spu.o
-diff -u ps3-linux-dev/arch/powerpc/platforms/ps3/device-init.c ps3-linux-dev/arch/powerpc/platforms/ps3/device-init.c
---- ps3-linux-dev/arch/powerpc/platforms/ps3/device-init.c
++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,459 @@
+@@ -0,0 +1,500 @@
 +/*
 + *  PS3 device init routines.
 + *
@@ -40,6 +42,7 @@
 +
 +#include <linux/kernel.h>
 +#include <linux/init.h>
++#include <asm/firmware.h>
 +
 +#include "platform.h"
 +
@@ -57,7 +60,10 @@
 +	dev = kzalloc(sizeof(struct ps3_system_bus_device)
 +		+ sizeof(struct ps3_dma_region), GFP_KERNEL);
 +
-+	dev->match_id = PS3_MATCH_ID_GELIC;
++	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);
@@ -91,9 +97,9 @@
 +		+ sizeof(struct ps3_system_bus_device));
 +
 +	ps3_dma_region_init(dev->d_region, &dev->did, PS3_DMA_64K,
-+		PS3_DMA_OTHER);
++			    PS3_DMA_OTHER, NULL, 0, PS3_IOBUS_SB);
 +
-+	result = ps3_system_bus_device_register(dev);
++	result = ps3_system_bus_device_register(dev, PS3_IOBUS_SB);
 +
 +	if (result) {
 +		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
@@ -134,9 +140,10 @@
 +
 +	p = kzalloc(sizeof(struct ohci_layout), GFP_KERNEL);
 +
-+	p->dev.d_region = &p->d_region;
-+	p->dev.m_region = &p->m_region;
-+	p->dev.match_id = PS3_MATCH_ID_OHCI;
++	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);
@@ -166,12 +173,12 @@
 +	BUG_ON(len != 0x10000);
 +
 +	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
-+		PS3_DMA_INTERNAL);
++			    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);
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
 +
-+	result = ps3_system_bus_device_register(&p->dev);
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
 +
 +	if (result)
 +		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
@@ -209,9 +216,10 @@
 +
 +	p = kzalloc(sizeof(struct ohci_layout), GFP_KERNEL);
 +
-+	p->dev.d_region = &p->d_region;
-+	p->dev.m_region = &p->m_region;
-+	p->dev.match_id = PS3_MATCH_ID_OHCI;
++	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);
@@ -250,12 +258,12 @@
 +	BUG_ON(len != 0x10000);
 +
 +	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
-+		PS3_DMA_INTERNAL);
++			    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);
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
 +
-+	result = ps3_system_bus_device_register(&p->dev);
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
 +
 +	if (result)
 +		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
@@ -293,9 +301,10 @@
 +
 +	p = kzalloc(sizeof(struct ehci_layout), GFP_KERNEL);
 +
-+	p->dev.d_region = &p->d_region;
-+	p->dev.m_region = &p->m_region;
-+	p->dev.match_id = PS3_MATCH_ID_EHCI;
++	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);
@@ -325,12 +334,12 @@
 +	BUG_ON(len != 0x10000);
 +
 +	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
-+		PS3_DMA_INTERNAL);
++			    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);
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
 +
-+	result = ps3_system_bus_device_register(&p->dev);
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
 +
 +	if (result)
 +		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
@@ -368,9 +377,10 @@
 +
 +	p = kzalloc(sizeof(struct ehci_layout), GFP_KERNEL);
 +
-+	p->dev.d_region = &p->d_region;
-+	p->dev.m_region = &p->m_region;
-+	p->dev.match_id = PS3_MATCH_ID_EHCI;
++	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);
@@ -409,12 +419,12 @@
 +	BUG_ON(len != 0x10000);
 +
 +	ps3_dma_region_init(p->dev.d_region, &p->dev.did, PS3_DMA_64K,
-+		PS3_DMA_INTERNAL);
++			    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);
++			     len, PS3_MMIO_4K, PS3_IOBUS_SB);
 +
-+	result = ps3_system_bus_device_register(&p->dev);
++	result = ps3_system_bus_device_register(&p->dev, PS3_IOBUS_SB);
 +
 +	if (result)
 +		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
@@ -432,6 +442,34 @@
 +	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)
 +{
@@ -457,6 +495,9 @@
 +{
 +	int result;
 +
++	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
++		return -ENODEV;
++
 +	pr_debug(" -> %s:%d\n", __func__, __LINE__);
 +
 +	//ps3_repository_dump_bus_info();
@@ -465,6 +506,8 @@
 +	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
@@ -475,30 +518,3 @@
 +}
 +
 +device_initcall(ps3_register_known_devices);
-only in patch2:
-unchanged:
---- ps3-linux-dev.orig/arch/powerpc/platforms/ps3/system-bus.c
-+++ ps3-linux-dev/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>
-@@ -99,9 +101,10 @@ static int ps3_system_bus_probe(struct d
- 
- 	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;
- 	}

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

Index: linux-2.6-ps3-ethernet-modular.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-ps3-ethernet-modular.patch,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- linux-2.6-ps3-ethernet-modular.patch	30 Mar 2007 22:46:24 -0000	1.2
+++ linux-2.6-ps3-ethernet-modular.patch	4 May 2007 14:52:31 -0000	1.3
@@ -1,10 +1,8 @@
-From: Ben Collins <ben.collins at ubuntu.com>
-
 diff --git a/drivers/net/gelic_net.c b/drivers/net/gelic_net.c
-index 083a0d2..8eb3b55 100644
+index f931bc7..48ad627 100644
 --- a/drivers/net/gelic_net.c
 +++ b/drivers/net/gelic_net.c
-@@ -204,8 +204,9 @@ static int ps3_gelic_param = 1; /* vlan desc support */
+@@ -73,8 +73,9 @@ static int ps3_gelic_param = 1; /* vlan desc support */
  module_param(ps3_gelic_param, int, S_IRUGO);
  #endif
  
@@ -16,7 +14,7 @@
  
  static int dmac_status = 0;
  
-@@ -993,7 +994,7 @@ gelic_net_kick_txdma(struct gelic_net_card *card,
+@@ -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",\
@@ -25,7 +23,7 @@
  		}
  	}
  }
-@@ -1285,7 +1286,7 @@ gelic_net_interrupt(int irq, void *ptr)
+@@ -1130,7 +1131,7 @@ gelic_net_interrupt(int irq, void *ptr)
  	unsigned long flags;
  	uint64_t status;
  
@@ -34,38 +32,38 @@
  	rmb();
  	status0 = (uint32_t)(status >> 32);
  	status1 = (uint32_t)(status & 0xffffffff);
-@@ -1764,6 +1765,12 @@ gelic_net_alloc_card(void)
+@@ -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(card->netdev);
++		free_netdev(netdev);
 +		return NULL;
 +	}
 +
  	card = netdev_priv(netdev);
  	card->netdev = netdev;
  	INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
-@@ -1792,7 +1799,7 @@ static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev)
- 	card->dev = dev;
- 
- 	/* setup status indicator */
--	lpar = ps3_mm_phys_to_lpar(__pa(&gelic_irq_status));
-+	lpar = ps3_mm_phys_to_lpar(__pa(gelic_irq_status));
- 	status = lv1_net_set_interrupt_status_indicator(
- 						card->dev->did.bus_id,
- 						card->dev->did.dev_id,
-@@ -1811,6 +1818,8 @@ static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev)
- 	return 0;
+@@ -1677,7 +1684,7 @@ static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev)
+ 	}
  
- error:
+ 	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(card->netdev);
- 	return error;
- }
-@@ -1832,6 +1841,8 @@ ps3_gelic_driver_remove (struct ps3_system_bus_device *dev)
+ 	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);
@@ -73,9 +71,4 @@
 +	gelic_irq_status = NULL;
  	free_netdev(netdev);
  
- 	return 0;
-
--- 
-Ubuntu:    http://www.ubuntu.com/
-Linux1394: http://www.linux1394.org/
-
+ 	lv1_net_set_interrupt_status_indicator(dev->did.bus_id, dev->did.dev_id,

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

Index: linux-2.6-ps3-smp-boot.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-ps3-smp-boot.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6-ps3-smp-boot.patch	16 Apr 2007 14:16:39 -0000	1.1
+++ linux-2.6-ps3-smp-boot.patch	4 May 2007 14:52:31 -0000	1.2
@@ -1,3 +1,8 @@
+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:

linux-2.6-ps3-sound.patch:

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.1 -r 1.2 linux-2.6-ps3-sound.patch
Index: linux-2.6-ps3-sound.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-ps3-sound.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6-ps3-sound.patch	30 Mar 2007 22:46:24 -0000	1.1
+++ linux-2.6-ps3-sound.patch	4 May 2007 14:52:31 -0000	1.2
@@ -1,3 +1,5 @@
+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
@@ -5,17 +7,76 @@
 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
 
-diff -u ps3-linux-mokuno/sound/ppc/snd_ps3.c ps3-linux-mokuno/sound/ppc/snd_ps3.c
---- ps3-linux-mokuno/sound/ppc/snd_ps3.c
-+++ ps3-linux-mokuno/sound/ppc/snd_ps3.c
-@@ -0,0 +1,1445 @@
+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) 2006 Sony Computer Entertainment Inc.
-+ * Copyright 2006, 2007 Sony Corporation
++ * 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
@@ -31,12 +92,14 @@
 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 + */
 +
-+#include <sound/driver.h>
++#define DEBUG
++#undef _SND_PS3_DEV_ATTR
++
 +#include <linux/init.h>
 +#include <linux/slab.h>
 +#include <linux/io.h>
-+#include <linux/platform_device.h>
 +#include <linux/interrupt.h>
++#include <sound/driver.h>
 +#include <sound/core.h>
 +#include <sound/initval.h>
 +#include <sound/pcm.h>
@@ -46,6 +109,7 @@
 +#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>
@@ -67,24 +131,23 @@
 +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);
-+
-+/* system memory info */
-+extern unsigned long ps3_rm_limit, ps3_2nd_mem_base, ps3_2nd_mem_size, ps3_mem_total;
++#endif
 +
 +/*
 + * global
 + */
 +struct snd_ps3_card_info the_card;
 +
-+static struct ioif_map_info * ioif_map_info_array;
-+static int ioif_map_info_count;
 +static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY;
 +
 +module_param_named(start_delay, snd_ps3_start_delay, int, 0444);
@@ -98,7 +161,8 @@
 + * chip: pointer to snd_ps3_card_info
 + * name: register offset value; PS3_AUDIO_XXXX
 + */
-+#define AUDIOREGPTR(chip, name) (volatile uint32_t *)(chip->mapped_vaddr + name)
++#define AUDIOREGPTR(chip, name) \
++	(volatile uint32_t *)(chip->mapped_mmio_vaddr + name)
 +
 +#define AUDIOREG(chip, name) *(AUDIOREGPTR(chip, name))
 +
@@ -123,7 +187,8 @@
 +
 +        .buffer_bytes_max = PS3_AUDIO_FIFO_SIZE * 64,
 +
-+        .period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4, /* interrupt by four stages */
++	/* interrupt by four stages */
++        .period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
 +        .period_bytes_max = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
 +
 +        .periods_min = 16,
@@ -156,16 +221,226 @@
 +	.get = snd_ps3_get_vol_control
 +};
 +
++static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info * card,
++				   int count, int force_stop)
++{
++	int dma_ch, done, retries, stop_forced = 0;
++	uint32_t status;
++
++	for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
++		retries = count;
++		do {
++			status = AUDIOREG(card, PS3_AUDIO_KICK(dma_ch)) &
++				PS3_AUDIO_KICK_STATUS_MASK;
++			switch (status) {
++			case PS3_AUDIO_KICK_STATUS_DONE:
++			case PS3_AUDIO_KICK_STATUS_NOTIFY:
++			case PS3_AUDIO_KICK_STATUS_CLEAR:
++			case PS3_AUDIO_KICK_STATUS_ERROR:
++				done = 1;
++				break;
++			default:
++				done = 0;
++				udelay(10);
++			}
++		} while (!done && --retries);
++		if (!retries && force_stop) {
++			printk(KERN_ERR "%s: DMA ch %d is not stopped.",
[...1888 lines suppressed...]
++	/* start delay */
 +	rwlock_t start_delay_lock;
-+	/* start_delay_lock start */
++		/* start_delay_lock start */
 +		unsigned int start_delay;
-+	/* start_delay_lock end */
++		/* start_delay_lock end */
 +
 +	struct snd_kcontrol * vol_control;
 +	int attenuater[2]; /* store by attenuation, not volume*/
@@ -1598,25 +1498,23 @@
 +static int snd_ps3_pcm_prepare(struct snd_pcm_substream * substream);
 +static int snd_ps3_pcm_trigger(struct snd_pcm_substream * substream,
 +				 int cmd);
-+static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream * substream);
++static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream *
++					     substream);
 +static int snd_ps3_pcm_hw_params(struct snd_pcm_substream * substream,
 +				 struct snd_pcm_hw_params * hw_params);
 +static int snd_ps3_pcm_hw_free(struct snd_pcm_substream * substream);
 +
-+/* PS3 audio chip */
-+static int snd_ps3_init_audio(void);
-+
-+static void snd_ps3_free_audio(void);
 +
-+/* platform driver entries */
-+static int __init snd_ps3_driver_probe(struct platform_device * device);
-+static void snd_ps3_driver_shutdown(struct platform_device * device);
-+static int snd_ps3_driver_remove(struct platform_device * device);
++/* ps3_system_bus_driver entries */
++static int __init snd_ps3_driver_probe(struct ps3_system_bus_device * dev);
++//static void snd_ps3_driver_shutdown(struct ps3_system_bus_device * dev);
++static int snd_ps3_driver_remove(struct ps3_system_bus_device * dev);
 +
 +/* address setup */
-+static int snd_ps3_create_iopt(void);
-+static void snd_ps3_destruct_iopt_helper(void);
-+static void snd_ps3_destruct_iopt(void);
++static int snd_ps3_map_mmio(void);
++static void snd_ps3_unmap_mmio(void);
++static int snd_ps3_allocate_irq(void);
++static void snd_ps3_free_irq(void);
 +static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
 +
 +/* interrupt handler */
@@ -1630,33 +1528,31 @@
 +/* initialize avsetting and take it effect */
 +static int snd_ps3_init_avsetting(struct snd_ps3_card_info * card);
 +/* setup dma */
-+static int snd_ps3_program_dma(struct snd_ps3_card_info * card, enum snd_ps3_dma_filltype filltype);
-+static int snd_ps3_kick_dma(struct snd_ps3_card_info * card);
++static int snd_ps3_program_dma(struct snd_ps3_card_info * card,
++			       enum snd_ps3_dma_filltype filltype);
++//static int snd_ps3_kick_dma(struct snd_ps3_card_info * card);
 +static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info * card);
 +
-+static uint64_t p_to_dma(uint64_t paddr);
-+/* mute control */
-+static int snd_ps3_mute(struct snd_pcm_substream * substream, int mute_on);
++static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void  * vaddr, int ch);
 +
-+static ssize_t snd_ps3_get_start_delay(struct device *dev, struct device_attribute *attr, char *buf);
++#if defined(_SND_PS3_DEV_ATTR)
++static ssize_t snd_ps3_get_start_delay(struct device *dev,
++				       struct device_attribute *attr,
++				       char *buf);
 +static ssize_t snd_ps3_set_start_delay(struct device *dev,
-+				       struct device_attribute *attr, const char *buf, size_t count);
-+
++				       struct device_attribute *attr,
++				       const char *buf, size_t count);
++#endif
 +
-+static int snd_ps3_info_vol_control(struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
-+static int snd_ps3_get_vol_control(struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
-+static int snd_ps3_put_vol_control(struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
++static int snd_ps3_info_vol_control(struct snd_kcontrol * kcontrol,
++				    struct snd_ctl_elem_info * uinfo);
++static int snd_ps3_get_vol_control(struct snd_kcontrol * kcontrol,
++				   struct snd_ctl_elem_value * ucontrol);
++static int snd_ps3_put_vol_control(struct snd_kcontrol * kcontrol,
++				   struct snd_ctl_elem_value * ucontrol);
 +
-+static int snd_ps3_soft_attenuate(struct snd_ps3_card_info * card, void * start_l, void * star_r, int bytes);
-+/*
-+ * iopte management
-+ */
-+struct ioif_map_info {
-+	uint64_t ioif_addr;
-+	uint64_t start_paddr;
-+	uint64_t start_lpar_addr;
-+	uint64_t area_size;
-+};
++static int snd_ps3_soft_attenuate(struct snd_ps3_card_info * card,
++				  void * start_l, void * star_r, int bytes);
 +
 +/* PS3 audio DMAC block size in bytes */
 +#define PS3_AUDIO_DMAC_BLOCK_SIZE (128)
@@ -1665,14 +1561,16 @@
 +/* how many stages the fifo have */
 +#define PS3_AUDIO_FIFO_STAGE_COUNT (8)
 +/* fifo size 128 bytes * 8 stages * stereo (2ch) */
-+#define PS3_AUDIO_FIFO_SIZE        (PS3_AUDIO_FIFO_STAGE_SIZE * PS3_AUDIO_FIFO_STAGE_COUNT)
++#define PS3_AUDIO_FIFO_SIZE \
++	(PS3_AUDIO_FIFO_STAGE_SIZE * PS3_AUDIO_FIFO_STAGE_COUNT)
 +
 +/* PS3 audio DMAC max block count in one dma shot = 128 (0x80) blocks*/
 +#define PS3_AUDIO_DMAC_MAX_BLOCKS  (PS3_AUDIO_DMASIZE_BLOCKS_MASK + 1)
 +
 +#define PS3_AUDIO_NORMAL_DMA_START_CH (0)
 +#define PS3_AUDIO_NORMAL_DMA_COUNT    (8)
-+#define PS3_AUDIO_NULL_DMA_START_CH   (PS3_AUDIO_NORMAL_DMA_START_CH + PS3_AUDIO_NORMAL_DMA_COUNT)
++#define PS3_AUDIO_NULL_DMA_START_CH \
++	(PS3_AUDIO_NORMAL_DMA_START_CH + PS3_AUDIO_NORMAL_DMA_COUNT)
 +#define PS3_AUDIO_NULL_DMA_COUNT      (2)
 +
 +#define SND_PS3_MAX_VOL (0x0F)
@@ -1680,10 +1578,18 @@
 +#define SND_PS3_MIN_ATT SND_PS3_MIN_VOL
 +#define SND_PS3_MAX_ATT SND_PS3_MAX_VOL
 +
++#define SND_PS3_PCM_PREALLOC_SIZE \
++	(PS3_AUDIO_DMAC_BLOCK_SIZE * PS3_AUDIO_DMAC_MAX_BLOCKS * 4)
++
++#define SND_PS3_DMA_REGION_SIZE \
++	(SND_PS3_PCM_PREALLOC_SIZE + PAGE_SIZE)
++
++#define PS3_AUDIO_IOID       (1UL)
++
 +#endif /* _SND_PS3_H_ */
 unchanged:
---- ps3-linux-src/sound/ppc/snd_ps3_reg.h
-+++ ps3-linux-2.6.21-rc4/sound/ppc/snd_ps3_reg.h
+--- /dev/null	2007-05-01 15:16:24.100521312 +0100
++++ b/sound/ppc/snd_ps3_reg.h	2007-05-04 12:30:20.000000000 +0100
 @@ -0,0 +1,856 @@
 +/*
 + * Audio support for PS3
@@ -2541,60 +2447,3 @@
 +          'T' = Task
 +
 + **********************************************************************/
-unchanged:
---- ps3-linux-2.6.21-rc2.orig/sound/ppc/Kconfig
-+++ ps3-linux-2.6.21-rc2/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:
---- ps3-linux-2.6.21-rc2.orig/sound/ppc/Makefile
-+++ ps3-linux-2.6.21-rc2/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
-unchanged:
---- ps3-linux-2.6.21-rc4.orig/include/asm-powerpc/lv1call.h
-+++ ps3-linux-2.6.21-rc4/include/asm-powerpc/lv1call.h
-@@ -238,6 +238,7 @@ LV1_CALL(destruct_virtual_address_space,
- 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,        
- 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 )

linux-2.6-ps3-stable-patches.patch:

Index: linux-2.6-ps3-stable-patches.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-ps3-stable-patches.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6-ps3-stable-patches.patch	30 Mar 2007 20:10:34 -0000	1.1
+++ linux-2.6-ps3-stable-patches.patch	4 May 2007 14:52:31 -0000	1.2
@@ -1,170 +1,608 @@
-All patches in ps3-stable/*.diff of ps3-linux-patches.git
+All patches in ps3-stable/*.diff of ps3-linux-patches.git as of 
+2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440).
+
+ps3-stable/ps3-remove-bogus-dev-dbg-defs.diff
+ps3-stable/ps3-fix-hardware-watchpoints.diff
+ps3-stable/ps3-remove-extra-assignment.diff
+ps3-stable/ps3-replace-irq-alloc-free.diff
+ps3-stable/ps3-fix-slowdown-bug.diff
+#ps3-stable/ps3-def-config-updates.diff
 
 ps3-stable/ps3fb-kthread.diff
 ps3-stable/ps3fb-atomic.diff
 ps3-stable/ps3av-workqueue.diff
 ps3-stable/ps3fb-zero-init.diff
 ps3-stable/ps3av-misc.diff
-
-ps3-stable/powerpc-remove-isync-bloat.diff
-ps3-stable/ps3-fix-hardware-watchpoints.diff
-ps3-stable/CBE_RAS-depends-on-PPC_CELL_NATIVE.diff
-ps3-stable/ps3-remove-extra-assignment.diff
+ps3-stable/ps3videomode-auto-mode.diff
+ps3-stable/ps3fb-__func__.diff
+ps3-stable/ps3av-__func__.diff
 
 
-unchanged:
---- ps3-linux-2.6.21-rc3/drivers/video/ps3fb.c
-+++ ps3-linux-2.6.21-rc3/drivers/video/ps3fb.c
-@@ -32,6 +32,8 @@
- #include <linux/ioctl.h>
- #include <linux/notifier.h>
- #include <linux/reboot.h>
-+#include <linux/kthread.h>
-+#include <linux/freezer.h>
+diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
+index 6c83fe2..5719a53 100644
+--- a/arch/powerpc/kernel/irq.c
++++ b/arch/powerpc/kernel/irq.c
+@@ -67,6 +67,7 @@
+ #ifdef CONFIG_PPC64
+ #include <asm/paca.h>
+ #include <asm/firmware.h>
++#include <asm/lv1call.h>
+ #endif
  
- #include <asm/uaccess.h>
- #include <linux/fb.h>
-@@ -129,7 +131,6 @@
- 	u64 context_handle, memory_handle;
- 	void *xdr_ea;
- 	struct gpu_driver_info *dinfo;
--	struct semaphore sem;
- 	u32 res_index;
+ int __irq_offset_value;
+@@ -162,6 +163,16 @@ void local_irq_restore(unsigned long en)
+ 	local_paca->hard_enabled = en;
+ 	if ((int)mfspr(SPRN_DEC) < 0)
+ 		mtspr(SPRN_DEC, 1);
++
++	/*
++	 * Force the delivery of pending soft-disabled interrupts on PS3.
++	 * Any HV call will have this side effect.
++	 */
++	if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
++		u64 tmp;
++		lv1_get_version_info(&tmp);
++	}
++
+ 	hard_irq_enable();
+ }
+ #endif /* CONFIG_PPC64 */
+diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
+index 631c300..9da82c2 100644
+--- a/arch/powerpc/platforms/ps3/interrupt.c
++++ b/arch/powerpc/platforms/ps3/interrupt.c
+@@ -89,7 +89,18 @@ struct ps3_private {
+ 
+ static DEFINE_PER_CPU(struct ps3_private, ps3_private);
+ 
+-int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
++/**
++ * ps3_virq_setup - virq related setup.
++ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
++ * serviced on.
++ * @outlet: The HV outlet from the various create outlet routines.
++ * @virq: The assigned Linux virq.
++ *
++ * Calls irq_create_mapping() to get a virq and sets the chip data to
++ * ps3_private data.
++ */
++
++int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
+ 	unsigned int *virq)
+ {
+ 	int result;
+@@ -111,17 +122,6 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+ 		goto fail_create;
+ 	}
  
- 	u64 vblank_count;	/* frame count */
-@@ -139,6 +140,8 @@
- 	atomic_t ext_flip;	/* on/off flip with vsync */
- 	atomic_t f_count;	/* fb_open count */
- 	int is_blanked;
-+	int is_kicked;
-+	struct task_struct *task;
- };
- static struct ps3fb_priv ps3fb;
+-	/* Binds outlet to cpu + virq. */
+-
+-	result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
+-
+-	if (result) {
+-		pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
+-		__func__, __LINE__, ps3_result(result));
+-		result = -EPERM;
+-		goto fail_connect;
+-	}
+-
+ 	pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
+ 		outlet, cpu, *virq);
  
-@@ -294,10 +297,10 @@
- #define VP_OFF(i)	(WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
- #define FB_OFF(i)	(GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
+@@ -136,94 +136,118 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+ 	return result;
  
--static int ps3fb_mode = 0;
-+static int ps3fb_mode;
- module_param(ps3fb_mode, bool, 0);
+ fail_set:
+-	lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
+-fail_connect:
+ 	irq_dispose_mapping(*virq);
+ fail_create:
+ 	return result;
+ }
+-EXPORT_SYMBOL_GPL(ps3_alloc_irq);
  
--static char *mode_option __initdata = NULL;
-+static char *mode_option __initdata;
+-int ps3_free_irq(unsigned int virq)
++/**
++ * ps3_virq_destroy - virq related teardown.
++ * @virq: The assigned Linux virq.
++ *
++ * Clears chip data and calls irq_dispose_mapping() for the virq.
++ */
++
++int ps3_virq_destroy(unsigned int virq)
+ {
+-	int result;
+ 	const struct ps3_private *pd = get_irq_chip_data(virq);
  
+ 	pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
+ 		pd->node, pd->cpu, virq);
  
- static int ps3fb_get_res_table(u32 xres, u32 yres)
-@@ -677,13 +680,10 @@
+-	result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
+-
+-	if (result)
+-		pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
+-		__func__, __LINE__, ps3_result(result));
+-
+ 	set_irq_chip_data(virq, NULL);
+ 	irq_dispose_mapping(virq);
+-	return result;
++
++	pr_debug("%s:%d <-\n", __func__, __LINE__);
++	return 0;
+ }
+-EXPORT_SYMBOL_GPL(ps3_free_irq);
  
- void ps3fb_flip_ctl(int on)
+ /**
+- * ps3_alloc_io_irq - Assign a virq to a system bus device.
++ * ps3_irq_plug_setup - Generic outlet and virq related setup.
+  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+  * serviced on.
+- * @interrupt_id: The device interrupt id read from the system repository.
++ * @outlet: The HV outlet from the various create outlet routines.
+  * @virq: The assigned Linux virq.
+  *
+- * An io irq represents a non-virtualized device interrupt.  interrupt_id
+- * coresponds to the interrupt number of the interrupt controller.
++ * Sets up virq and connects the irq plug.
+  */
+ 
+-int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
++int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
+ 	unsigned int *virq)
  {
--	if (on) {
--		if (atomic_read(&ps3fb.ext_flip) > 0) {
--			atomic_dec(&ps3fb.ext_flip);
--		}
--	} else {
-+	if (on)
-+		atomic_dec_if_positive(&ps3fb.ext_flip);
-+	else
- 		atomic_inc(&ps3fb.ext_flip);
--	}
+ 	int result;
+-	unsigned long outlet;
++	struct ps3_private *pd;
+ 
+-	result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
++	result = ps3_virq_setup(cpu, outlet, virq);
+ 
+ 	if (result) {
+-		pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
+-			__func__, __LINE__, ps3_result(result));
+-		return result;
++		pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
++		goto fail_setup;
+ 	}
+ 
+-	result = ps3_alloc_irq(cpu, outlet, virq);
+-	BUG_ON(result);
++	pd = get_irq_chip_data(*virq);
++
++	/* Binds outlet to cpu + virq. */
++
++	result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
+ 
++	if (result) {
++		pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
++		__func__, __LINE__, ps3_result(result));
++		result = -EPERM;
++		goto fail_connect;
++	}
++
++	return result;
++
++fail_connect:
++	ps3_virq_destroy(*virq);
++fail_setup:
+ 	return result;
  }
+-EXPORT_SYMBOL_GPL(ps3_alloc_io_irq);
++EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);
++
++/**
++ * ps3_irq_plug_destroy - Generic outlet and virq related teardown.
++ * @virq: The assigned Linux virq.
++ *
++ * Disconnects the irq plug and tears down virq.
++ * Do not call for system bus event interrupts setup with
++ * ps3_sb_event_receive_port_setup().
++ */
  
- EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
-@@ -783,8 +783,7 @@
+-int ps3_free_io_irq(unsigned int virq)
++int ps3_irq_plug_destroy(unsigned int virq)
+ {
+ 	int result;
++	const struct ps3_private *pd = get_irq_chip_data(virq);
  
- 	case PS3FB_IOCTL_OFF:
- 		DPRINTK("PS3FB_IOCTL_OFF:\n");
--		if (atomic_read(&ps3fb.ext_flip) > 0)
--			atomic_dec(&ps3fb.ext_flip);
-+		atomic_dec_if_positive(&ps3fb.ext_flip);
- 		retval = 0;
- 		break;
+-	result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
++	pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
++		pd->node, pd->cpu, virq);
++
++	result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
  
-@@ -805,11 +804,14 @@
+ 	if (result)
+-		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
+-			__func__, __LINE__, ps3_result(result));
++		pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
++		__func__, __LINE__, ps3_result(result));
  
- static int ps3fbd(void *arg)
+-	ps3_free_irq(virq);
++	ps3_virq_destroy(virq);
+ 
+ 	return result;
+ }
+-EXPORT_SYMBOL_GPL(ps3_free_io_irq);
++EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy);
+ 
+ /**
+- * ps3_alloc_event_irq - Allocate a virq for use with a system event.
++ * ps3_event_receive_port_setup - Setup an event receive port.
+  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+  * serviced on.
+  * @virq: The assigned Linux virq.
+  *
+  * The virq can be used with lv1_connect_interrupt_event_receive_port() to
+- * arrange to receive events, or with ps3_send_event_locally() to signal
+- * events.
++ * arrange to receive interrupts from system-bus devices, or with
++ * ps3_send_event_locally() to signal events.
+  */
+ 
+-int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
++int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
  {
--	daemonize("ps3fbd");
--	for (;;) {
--		down(&ps3fb.sem);
--		if (atomic_read(&ps3fb.ext_flip) == 0)
-+	while (!kthread_should_stop()) {
-+		try_to_freeze();
-+		set_current_state(TASK_INTERRUPTIBLE);
-+		if (ps3fb.is_kicked) {
-+			ps3fb.is_kicked = 0;
- 			ps3fb_sync(0);	/* single buffer */
-+		}
-+		schedule();
+ 	int result;
+ 	unsigned long outlet;
+@@ -237,17 +261,27 @@ int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
+ 		return result;
  	}
- 	return 0;
+ 
+-	result = ps3_alloc_irq(cpu, outlet, virq);
++	result = ps3_irq_plug_setup(cpu, outlet, virq);
+ 	BUG_ON(result);
+ 
+ 	return result;
  }
-@@ -830,8 +832,11 @@
- 	if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
- 		/* VSYNC */
- 		ps3fb.vblank_count = head->vblank_count;
--		if (!ps3fb.is_blanked)
--			up(&ps3fb.sem);
-+		if (ps3fb.task && !ps3fb.is_blanked &&
-+		    !atomic_read(&ps3fb.ext_flip)) {
-+			ps3fb.is_kicked = 1;
-+			wake_up_process(ps3fb.task);
-+		}
- 		wake_up_interruptible(&ps3fb.wait_vsync);
++EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup);
++
++/**
++ * ps3_event_receive_port_destroy - Destroy an event receive port.
++ * @virq: The assigned Linux virq.
++ *
++ * Since ps3_event_receive_port_destroy destroys the receive port outlet,
++ * SB devices need to call disconnect_interrupt_event_receive_port() before
++ * this.
++ */
+ 
+-int ps3_free_event_irq(unsigned int virq)
++int ps3_event_receive_port_destroy(unsigned int virq)
+ {
+ 	int result;
+ 
+-	pr_debug(" -> %s:%d\n", __func__, __LINE__);
++	pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq);
+ 
+ 	result = lv1_destruct_event_receive_port(virq_to_hw(virq));
+ 
+@@ -255,11 +289,17 @@ int ps3_free_event_irq(unsigned int virq)
+ 		pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
+ 			__func__, __LINE__, ps3_result(result));
+ 
+-	ps3_free_irq(virq);
++	/* lv1_destruct_event_receive_port() 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;
+ }
++EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy);
+ 
+ int ps3_send_event_locally(unsigned int virq)
+ {
+@@ -267,7 +307,7 @@ int ps3_send_event_locally(unsigned int virq)
+ }
+ 
+ /**
+- * ps3_connect_event_irq - Assign a virq to a system bus device.
++ * ps3_sb_event_receive_port_setup - Setup a system bus event receive port.
+  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+  * serviced on.
+  * @did: The HV device identifier read from the system repository.
+@@ -278,13 +318,15 @@ int ps3_send_event_locally(unsigned int virq)
+  * coresponds to the software interrupt number.
+  */
+ 
+-int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
++int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
+ 	const struct ps3_device_id *did, unsigned int interrupt_id,
+ 	unsigned int *virq)
+ {
++	/* this should go in system-bus.c */
++
+ 	int result;
+ 
+-	result = ps3_alloc_event_irq(cpu, virq);
++	result = ps3_event_receive_port_setup(cpu, virq);
+ 
+ 	if (result)
+ 		return result;
+@@ -296,7 +338,7 @@ int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+ 		pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
+ 			" failed: %s\n", __func__, __LINE__,
+ 			ps3_result(result));
+-		ps3_free_event_irq(*virq);
++		ps3_event_receive_port_destroy(*virq);
+ 		*virq = NO_IRQ;
+ 		return result;
  	}
+@@ -306,10 +348,13 @@ int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
  
-@@ -968,6 +973,7 @@
- 	u64 xdr_lpar;
- 	int status;
- 	unsigned long offset;
-+	struct task_struct *task;
+ 	return 0;
+ }
++EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
  
- 	/* get gpu context handle */
- 	status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
-@@ -1050,9 +1056,18 @@
- 	       "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
- 	       info->node, ps3fb_videomemory.size >> 10);
+-int ps3_disconnect_event_irq(const struct ps3_device_id *did,
++int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
+ 	unsigned int interrupt_id, unsigned int virq)
+ {
++	/* this should go in system-bus.c */
++
+ 	int result;
  
--	kernel_thread(ps3fbd, info, CLONE_KERNEL);
-+	task = kthread_run(ps3fbd, info, "ps3fbd");
-+	if (IS_ERR(task)) {
-+		retval = PTR_ERR(task);
-+		goto err_unregister_framebuffer;
+ 	pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
+@@ -323,14 +368,65 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
+ 			" failed: %s\n", __func__, __LINE__,
+ 			ps3_result(result));
+ 
+-	ps3_free_event_irq(virq);
++	result = ps3_event_receive_port_destroy(virq);
++	BUG_ON(result);
+ 
+ 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ 	return result;
+ }
++EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy);
+ 
+ /**
+- * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
++ * ps3_io_irq_setup - Setup a system bus io irq.
++ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
++ * serviced on.
++ * @interrupt_id: The device interrupt id read from the system repository.
++ * @virq: The assigned Linux virq.
++ *
++ * An io irq represents a non-virtualized device interrupt.  interrupt_id
++ * coresponds to the interrupt number of the interrupt controller.
++ */
++
++int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
++	unsigned int *virq)
++{
++	int result;
++	unsigned long outlet;
++
++	result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
++
++	if (result) {
++		pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
++		return result;
 +	}
 +
-+	ps3fb.task = task;
++	result = ps3_irq_plug_setup(cpu, outlet, virq);
++	BUG_ON(result);
 +
++	return result;
++}
++EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
++
++int ps3_io_irq_destroy(unsigned int virq)
++{
++	int result;
++
++	result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
++
++	if (result)
++		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
++			__func__, __LINE__, ps3_result(result));
++
++	result = ps3_irq_plug_destroy(virq);
++	BUG_ON(result);
++
++	return result;
++}
++EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
++
++/**
++ * ps3_vuart_irq_setup - Setup the system virtual uart virq.
+  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+  * serviced on.
+  * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
+@@ -340,7 +436,7 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
+  * freeing the interrupt will return a wrong state error.
+  */
+ 
+-int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
++int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+ 	unsigned int *virq)
+ {
+ 	int result;
+@@ -359,13 +455,13 @@ int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+ 		return result;
+ 	}
+ 
+-	result = ps3_alloc_irq(cpu, outlet, virq);
++	result = ps3_irq_plug_setup(cpu, outlet, virq);
+ 	BUG_ON(result);
+ 
+ 	return result;
+ }
+ 
+-int ps3_free_vuart_irq(unsigned int virq)
++int ps3_vuart_irq_destroy(unsigned int virq)
+ {
+ 	int result;
+ 
+@@ -377,13 +473,14 @@ int ps3_free_vuart_irq(unsigned int virq)
+ 		return result;
+ 	}
+ 
+-	ps3_free_irq(virq);
++	result = ps3_irq_plug_destroy(virq);
++	BUG_ON(result);
+ 
+ 	return result;
+ }
+ 
+ /**
+- * ps3_alloc_spe_irq - Configure an spe virq.
++ * ps3_spe_irq_setup - Setup an spe virq.
+  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+  * serviced on.
+  * @spe_id: The spe_id returned from lv1_construct_logical_spe().
+@@ -392,7 +489,7 @@ int ps3_free_vuart_irq(unsigned int virq)
+  *
+  */
+ 
+-int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
++int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
+ 	unsigned int class, unsigned int *virq)
+ {
+ 	int result;
+@@ -408,15 +505,16 @@ int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+ 		return result;
+ 	}
+ 
+-	result = ps3_alloc_irq(cpu, outlet, virq);
++	result = ps3_irq_plug_setup(cpu, outlet, virq);
+ 	BUG_ON(result);
+ 
+ 	return result;
+ }
+ 
+-int ps3_free_spe_irq(unsigned int virq)
++int ps3_spe_irq_destroy(unsigned int virq)
+ {
+-	ps3_free_irq(virq);
++	int result = ps3_irq_plug_destroy(virq);
++	BUG_ON(result);
  	return 0;
+ }
  
-+err_unregister_framebuffer:
-+	unregister_framebuffer(info);
- err_fb_dealloc:
- 	fb_dealloc_cmap(&info->cmap);
- err_framebuffer_release:
-@@ -1083,6 +1098,11 @@
+diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
+index 2014d2b..f8a3e20 100644
+--- a/arch/powerpc/platforms/ps3/mm.c
++++ b/arch/powerpc/platforms/ps3/mm.c
+@@ -826,5 +826,4 @@ void __init ps3_mm_init(void)
+ void ps3_mm_shutdown(void)
  {
- 	int status;
+ 	ps3_mm_region_destroy(&map.r1);
+-	map.total = map.rm.size;
+ }
+diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
+index ac5df96..c989493 100644
+--- a/arch/powerpc/platforms/ps3/setup.c
++++ b/arch/powerpc/platforms/ps3/setup.c
+@@ -137,6 +137,12 @@ early_param("ps3fb", early_parse_ps3fb);
+ #define prealloc_ps3fb_videomemory()	do { } while (0)
+ #endif
  
-+	if (ps3fb.task) {
-+		struct task_struct *task = ps3fb.task;
-+		ps3fb.task = NULL;
-+		kthread_stop(task);
-+	}
- 	if (ps3fb.irq_no) {
- 		free_irq(ps3fb.irq_no, ps3fb.dev);
- 		ps3_free_irq(ps3fb.irq_no);
-@@ -1195,7 +1215,6 @@
++static int ps3_set_dabr(u64 dabr)
++{
++	enum {DABR_USER = 1, DABR_KERNEL = 2,};
++
++	return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0;
++}
  
- 	atomic_set(&ps3fb.f_count, -1);	/* fbcon opens ps3fb */
- 	atomic_set(&ps3fb.ext_flip, 0);	/* for flip with vsync */
--	init_MUTEX(&ps3fb.sem);
- 	init_waitqueue_head(&ps3fb.wait_vsync);
- 	ps3fb.num_frames = 1;
+ static void __init ps3_setup_arch(void)
+ {
+@@ -234,6 +240,7 @@ define_machine(ps3) {
+ 	.get_boot_time			= ps3_get_boot_time,
+ 	.set_rtc_time			= ps3_set_rtc_time,
+ 	.get_rtc_time			= ps3_get_rtc_time,
++	.set_dabr			= ps3_set_dabr,
+ 	.calibrate_decr			= ps3_calibrate_decr,
+ 	.progress			= ps3_progress,
+ 	.restart			= ps3_restart,
+diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
+index 6fb8879..8729348 100644
+--- a/arch/powerpc/platforms/ps3/smp.c
++++ b/arch/powerpc/platforms/ps3/smp.c
+@@ -110,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int cpu)
+ 	BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
+ 
+ 	for (i = 0; i < MSG_COUNT; i++) {
+-		result = ps3_alloc_event_irq(cpu, &virqs[i]);
++		result = ps3_event_receive_port_setup(cpu, &virqs[i]);
+ 
+ 		if (result)
+ 			continue;
+@@ -134,11 +134,13 @@ void ps3_smp_cleanup_cpu(int cpu)
+ 	int i;
  
-unchanged:
---- ps3-linux-2.6.21-rc3/drivers/ps3/ps3av.c
-+++ ps3-linux-2.6.21-rc3/drivers/ps3/ps3av.c
+ 	DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
++
+ 	for (i = 0; i < MSG_COUNT; i++) {
+-		ps3_free_event_irq(virqs[i]);
+ 		free_irq(virqs[i], (void*)(long)i);
++		ps3_event_receive_port_destroy(virqs[i]);
+ 		virqs[i] = NO_IRQ;
+ 	}
++
+ 	DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
+ }
+ 
+diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
+index a397e4e..0d051c3 100644
+--- a/arch/powerpc/platforms/ps3/spu.c
++++ b/arch/powerpc/platforms/ps3/spu.c
+@@ -230,19 +230,19 @@ static int __init setup_interrupts(struct spu *spu)
+ {
+ 	int result;
+ 
+-	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
++	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ 		0, &spu->irqs[0]);
+ 
+ 	if (result)
+ 		goto fail_alloc_0;
+ 
+-	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
++	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ 		1, &spu->irqs[1]);
+ 
+ 	if (result)
+ 		goto fail_alloc_1;
+ 
+-	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
++	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ 		2, &spu->irqs[2]);
+ 
+ 	if (result)
+@@ -251,9 +251,9 @@ static int __init setup_interrupts(struct spu *spu)
+ 	return result;
+ 
+ fail_alloc_2:
+-	ps3_free_spe_irq(spu->irqs[1]);
++	ps3_spe_irq_destroy(spu->irqs[1]);
+ fail_alloc_1:
+-	ps3_free_spe_irq(spu->irqs[0]);
++	ps3_spe_irq_destroy(spu->irqs[0]);
+ fail_alloc_0:
+ 	spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
+ 	return result;
+@@ -301,9 +301,9 @@ static int ps3_destroy_spu(struct spu *spu)
+ 	result = lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0);
+ 	BUG_ON(result);
+ 
+-	ps3_free_spe_irq(spu->irqs[2]);
+-	ps3_free_spe_irq(spu->irqs[1]);
+-	ps3_free_spe_irq(spu->irqs[0]);
++	ps3_spe_irq_destroy(spu->irqs[2]);
++	ps3_spe_irq_destroy(spu->irqs[1]);
++	ps3_spe_irq_destroy(spu->irqs[0]);
+ 
+ 	spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
+ 
+diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
+index d21e04c..1393e64 100644
+--- a/drivers/ps3/ps3av.c
++++ b/drivers/ps3/ps3av.c
 @@ -38,7 +38,24 @@
  static int timeout = 5000;	/* in msec ( 5 sec ) */
  module_param(timeout, int, 0644);
@@ -191,7 +629,52 @@
  
  static struct ps3_vuart_port_device ps3av_dev = {
  	.match_id = PS3_MATCH_ID_AV_SETTINGS
-@@ -250,7 +267,7 @@
+@@ -159,7 +176,7 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr)
+ 		else
+ 			printk(KERN_ERR
+ 			       "%s: failed event packet, cid:%08x size:%d\n",
+-			       __FUNCTION__, hdr->cid, hdr->size);
++			       __func__, hdr->cid, hdr->size);
+ 		return 1;	/* receive event packet */
+ 	}
+ 	return 0;
+@@ -181,7 +198,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
+ 	if (res < 0) {
+ 		dev_dbg(&ps3av_dev.core,
+ 			"%s: ps3av_vuart_write() failed (result=%d)\n",
+-			__FUNCTION__, res);
++			__func__, res);
+ 		return res;
+ 	}
+ 
+@@ -194,7 +211,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
+ 		if (res != PS3AV_HDR_SIZE) {
+ 			dev_dbg(&ps3av_dev.core,
+ 				"%s: ps3av_vuart_read() failed (result=%d)\n",
+-				__FUNCTION__, res);
++				__func__, res);
+ 			return res;
+ 		}
+ 
+@@ -204,7 +221,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
+ 		if (res < 0) {
+ 			dev_dbg(&ps3av_dev.core,
+ 				"%s: ps3av_vuart_read() failed (result=%d)\n",
+-				__FUNCTION__, res);
++				__func__, res);
+ 			return res;
+ 		}
+ 		res += PS3AV_HDR_SIZE;	/* total len */
+@@ -214,7 +231,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
+ 
+ 	if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
+ 		dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n",
+-			__FUNCTION__, recv_buf->cid);
++			__func__, recv_buf->cid);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -250,7 +267,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
  		 struct ps3av_send_hdr *buf)
  {
  	int res = 0;
@@ -200,7 +683,7 @@
  		struct ps3av_reply_hdr reply_hdr;
  		u8 raw[PS3AV_BUF_SIZE];
  	} recv_buf;
-@@ -259,8 +276,7 @@
+@@ -259,8 +276,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
  
  	BUG_ON(!ps3av.available);
  
@@ -210,7 +693,21 @@
  
  	table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK);
  	BUG_ON(!table);
-@@ -290,11 +306,11 @@
+@@ -277,7 +293,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
+ 	if (res < 0) {
+ 		printk(KERN_ERR
+ 		       "%s: ps3av_send_cmd_pkt() failed (result=%d)\n",
+-		       __FUNCTION__, res);
++		       __func__, res);
+ 		goto err;
+ 	}
+ 
+@@ -286,16 +302,16 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
+ 					 usr_buf_size);
+ 	if (res < 0) {
+ 		printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n",
+-		       __FUNCTION__, res);
++		       __func__, res);
  		goto err;
  	}
  
@@ -220,11 +717,13 @@
  
        err:
 -	up(&ps3av.sem);
+-	printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res);
 +	mutex_unlock(&ps3av.mutex);
- 	printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res);
++	printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
  	return res;
  }
-@@ -440,7 +456,7 @@
+ 
+@@ -440,7 +456,7 @@ static int ps3av_set_videomode(void)
  	ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON);
  
  	/* wake up ps3avd to do the actual video mode setting */
@@ -233,7 +732,16 @@
  
  	return 0;
  }
-@@ -515,18 +531,10 @@
+@@ -506,7 +522,7 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
+ 	if (res == PS3AV_STATUS_NO_SYNC_HEAD)
+ 		printk(KERN_WARNING
+ 		       "%s: Command failed. Please try your request again. \n",
+-		       __FUNCTION__);
++		       __func__);
+ 	else if (res)
+ 		dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
+ 
+@@ -515,18 +531,10 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
  	ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);
  }
  
@@ -255,7 +763,26 @@
  }
  
  static int ps3av_vid2table_id(int vid)
-@@ -725,7 +733,7 @@
+@@ -707,8 +715,7 @@ int ps3av_set_video_mode(u32 id, int boot)
+ 
+ 	size = ARRAY_SIZE(video_mode_table);
+ 	if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
+-		dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__,
+-			id);
++		dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -717,15 +724,14 @@ int ps3av_set_video_mode(u32 id, int boot)
+ 	if ((id & PS3AV_MODE_MASK) == 0) {
+ 		id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
+ 		if (id < 1) {
+-			printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__,
+-			       id);
++			printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
+ 			return -EINVAL;
+ 		}
+ 		id |= option;
  	}
  
  	/* set videomode */
@@ -264,7 +791,73 @@
  	ps3av.ps3av_mode_old = ps3av.ps3av_mode;
  	ps3av.ps3av_mode = id;
  	if (ps3av_set_videomode())
-@@ -880,13 +888,16 @@
+@@ -736,6 +742,13 @@ int ps3av_set_video_mode(u32 id, int boot)
+ 
+ EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
+ 
++int ps3av_get_auto_mode(int boot)
++{
++	return ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
++}
++
++EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
++
+ int ps3av_set_mode(u32 id, int boot)
+ {
+ 	int res;
+@@ -771,7 +784,7 @@ int ps3av_get_scanmode(int id)
+ 	id = id & PS3AV_MODE_MASK;
+ 	size = ARRAY_SIZE(video_mode_table);
+ 	if (id > size - 1 || id < 0) {
+-		printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
++		printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
+ 		return -EINVAL;
+ 	}
+ 	return video_mode_table[id].interlace;
+@@ -786,7 +799,7 @@ int ps3av_get_refresh_rate(int id)
+ 	id = id & PS3AV_MODE_MASK;
+ 	size = ARRAY_SIZE(video_mode_table);
+ 	if (id > size - 1 || id < 0) {
+-		printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
++		printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
+ 		return -EINVAL;
+ 	}
+ 	return video_mode_table[id].freq;
+@@ -802,7 +815,7 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
+ 	id = id & PS3AV_MODE_MASK;
+ 	size = ARRAY_SIZE(video_mode_table);
+ 	if (id > size - 1 || id < 0) {
+-		printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
++		printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
+ 		return -EINVAL;
+ 	}
+ 	*xres = video_mode_table[id].x;
+@@ -838,7 +851,7 @@ int ps3av_dev_open(void)
+ 		status = lv1_gpu_open(0);
+ 		if (status) {
+ 			printk(KERN_ERR "%s: lv1_gpu_open failed %d\n",
+-			       __FUNCTION__, status);
++			       __func__, status);
+ 			ps3av.open_count--;
+ 		}
+ 	}
+@@ -855,13 +868,13 @@ int ps3av_dev_close(void)
+ 
+ 	mutex_lock(&ps3av.mutex);
+ 	if (ps3av.open_count <= 0) {
+-		printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__);
++		printk(KERN_ERR "%s: GPU already closed\n", __func__);
+ 		status = -1;
+ 	} else if (!--ps3av.open_count) {
+ 		status = lv1_gpu_close();
+ 		if (status)
+ 			printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n",
+-			       __FUNCTION__, status);
++			       __func__, status);
+ 	}
+ 	mutex_unlock(&ps3av.mutex);
+ 
+@@ -880,13 +893,16 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev)
  
  	memset(&ps3av, 0, sizeof(ps3av));
  
@@ -285,7 +878,16 @@
  
  	ps3av.available = 1;
  	switch (ps3_os_area_get_av_multi_out()) {
-@@ -926,6 +937,8 @@
+@@ -908,7 +924,7 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev)
+ 	/* init avsetting modules */
+ 	res = ps3av_cmd_init();
+ 	if (res < 0)
+-		printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__,
++		printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__,
+ 		       res);
+ 
+ 	ps3av_get_hw_conf(&ps3av);
+@@ -926,6 +942,8 @@ static int ps3av_remove(struct ps3_vuart_port_device *dev)
  {
  	if (ps3av.available) {
  		ps3av_cmd_fin();
@@ -294,9 +896,636 @@
  		ps3av.available = 0;
  	}
  
-unchanged:
---- ps3-linux-2.6.21-rc3/include/asm-powerpc/ps3av.h
-+++ ps3-linux-2.6.21-rc3/include/asm-powerpc/ps3av.h
+@@ -958,7 +976,7 @@ static int ps3av_module_init(void)
+ 	if (error) {
+ 		printk(KERN_ERR
+ 		       "%s: ps3_vuart_port_driver_register failed %d\n",
+-		       __FUNCTION__, error);
++		       __func__, error);
+ 		return error;
+ 	}
+ 
+@@ -966,7 +984,7 @@ static int ps3av_module_init(void)
+ 	if (error)
+ 		printk(KERN_ERR
+ 		       "%s: ps3_vuart_port_device_register failed %d\n",
+-		       __FUNCTION__, error);
++		       __func__, error);
+ 
+ 	return error;
+ }
+diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
+index bc70e81..0145ea1 100644
+--- a/drivers/ps3/ps3av_cmd.c
++++ b/drivers/ps3/ps3av_cmd.c
+@@ -395,7 +395,7 @@ u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt,
+ 	video_mode->video_order = ps3av_video_fmt_table[video_fmt].order;
+ 
+ 	pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n",
+-		__FUNCTION__, video_vid, video_mode->width, video_mode->height,
++		__func__, video_vid, video_mode->width, video_mode->height,
+ 		video_mode->pitch, video_mode->video_out_format,
+ 		video_mode->video_format, video_mode->video_order);
+ 	return sizeof(*video_mode);
+@@ -477,7 +477,7 @@ static u8 ps3av_cnv_mclk(u32 fs)
+ 		if (ps3av_cnv_mclk_table[i].fs == fs)
+ 			return ps3av_cnv_mclk_table[i].mclk;
+ 
+-	printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
++	printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);
+ 	return 0;
+ }
+ 
+@@ -526,13 +526,12 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid)
+ 		d = 4;
+ 		break;
+ 	default:
+-		printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__,
+-		       video_vid);
++		printk(KERN_ERR "%s failed, vid:%x\n", __func__, video_vid);
+ 		break;
+ 	}
+ 
+ 	if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K)
+-		printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
++		printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);
+ 	else
+ 		ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d];
+ 
+@@ -555,8 +554,7 @@ static u8 ps3av_cnv_enable(u32 source, const u8 *enable)
+ 		ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) |
+ 		      0x01;
+ 	} else
+-		printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__,
+-		       source);
++		printk(KERN_ERR "%s failed, source:%x\n", __func__, source);
+ 	return ret;
+ }
+ 
+@@ -585,7 +583,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits)
+ 		ret = PS3AV_CMD_AV_INPUTLEN_24;
+ 		break;
+ 	default:
+-		printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__,
++		printk(KERN_ERR "%s failed, word_bits:%x\n", __func__,
+ 		       word_bits);
+ 		break;
+ 	}
+@@ -595,7 +593,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits)
+ static u8 ps3av_cnv_layout(u32 num_of_ch)
+ {
+ 	if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) {
+-		printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__,
++		printk(KERN_ERR "%s failed, num_of_ch:%x\n", __func__,
+ 		       num_of_ch);
+ 		return 0;
+ 	}
+@@ -864,7 +862,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
+ 
+ 	res = get_status(avb);
+ 	if (res)
+-		pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__,
++		pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __func__,
+ 			 res);
+ 
+       out:
+@@ -1013,7 +1011,7 @@ int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
+ 			return size;
+ 		if (error != -EAGAIN) {
+ 			printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
+-			       __FUNCTION__, error);
++			       __func__, error);
+ 			return error;
+ 		}
+ 		msleep(POLLING_INTERVAL);
+diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
+index 7d7cab1..ec2d36a 100644
+--- a/drivers/ps3/vuart.c
++++ b/drivers/ps3/vuart.c
+@@ -886,12 +886,12 @@ static int ps3_vuart_probe(struct device *_dev)
+ 
+ 	if (++vuart_bus_priv.use_count == 1) {
+ 
+-		result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
++		result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY,
+ 			(void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq);
+ 
+ 		if (result) {
+ 			dev_dbg(&dev->core,
+-				"%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
++				"%s:%d: ps3_vuart_irq_setup failed (%d)\n",
+ 				__func__, __LINE__, result);
+ 			result = -EPERM;
+ 			goto fail_alloc_irq;
+@@ -937,7 +937,7 @@ static int ps3_vuart_probe(struct device *_dev)
+ fail_probe:
+ 	ps3_vuart_set_interrupt_mask(dev, 0);
+ fail_request_irq:
+-	ps3_free_vuart_irq(vuart_bus_priv.virq);
++	ps3_vuart_irq_destroy(vuart_bus_priv.virq);
+ 	vuart_bus_priv.virq = NO_IRQ;
+ fail_alloc_irq:
+ 	--vuart_bus_priv.use_count;
+@@ -975,7 +975,7 @@ static int ps3_vuart_remove(struct device *_dev)
+ 	if (--vuart_bus_priv.use_count == 0) {
+ 		BUG();
+ 		free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
+-		ps3_free_vuart_irq(vuart_bus_priv.virq);
++		ps3_vuart_irq_destroy(vuart_bus_priv.virq);
+ 		vuart_bus_priv.virq = NO_IRQ;
+ 	}
+ 
+diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
+index 4d781a2..37b83ba 100644
+--- a/drivers/usb/host/ehci-ps3.c
++++ b/drivers/usb/host/ehci-ps3.c
+@@ -73,13 +73,6 @@ static const struct hc_driver ps3_ehci_hc_driver = {
+ #endif
+ };
+ 
+-#if !defined(DEBUG)
+-#undef dev_dbg
+-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+-	const struct device *_dev, const char *fmt, ...) {return 0;}
+-#endif
+-
+-
+ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+ {
+ 	int result;
+@@ -104,7 +97,7 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+ 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ 		__LINE__, dev->m_region->lpar_addr);
+ 
+-	result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
++	result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+ 
+ 	if (result) {
+ 		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+@@ -162,7 +155,7 @@ fail_add_hcd:
+ fail_ioremap:
+ 	usb_put_hcd(hcd);
+ fail_create_hcd:
+-	ps3_free_io_irq(virq);
++	ps3_io_irq_destroy(virq);
+ fail_irq:
+ 	ps3_free_mmio_region(dev->m_region);
+ fail_mmio:
+diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
+index 62283a3..d7cf072 100644
+--- a/drivers/usb/host/ohci-ps3.c
++++ b/drivers/usb/host/ohci-ps3.c
+@@ -75,14 +75,6 @@ static const struct hc_driver ps3_ohci_hc_driver = {
+ #endif
+ };
+ 
+-/* redefine dev_dbg to do a syntax check */
+-
+-#if !defined(DEBUG)
+-#undef dev_dbg
+-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+-	const struct device *_dev, const char *fmt, ...) {return 0;}
+-#endif
+-
+ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+ {
+ 	int result;
+@@ -107,7 +99,7 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+ 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ 		__LINE__, dev->m_region->lpar_addr);
+ 
+-	result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
++	result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+ 
+ 	if (result) {
+ 		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+@@ -165,7 +157,7 @@ fail_add_hcd:
+ fail_ioremap:
+ 	usb_put_hcd(hcd);
+ fail_create_hcd:
+-	ps3_free_io_irq(virq);
++	ps3_io_irq_destroy(virq);
+ fail_irq:
+ 	ps3_free_mmio_region(dev->m_region);
+ fail_mmio:
+diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
+index 81e43cd..9756a72 100644
+--- a/drivers/video/ps3fb.c
++++ b/drivers/video/ps3fb.c
+@@ -32,6 +32,8 @@
+ #include <linux/ioctl.h>
+ #include <linux/notifier.h>
+ #include <linux/reboot.h>
++#include <linux/kthread.h>
++#include <linux/freezer.h>
+ 
+ #include <asm/uaccess.h>
+ #include <linux/fb.h>
+@@ -45,7 +47,7 @@
+ #include <asm/ps3.h>
+ 
+ #ifdef PS3FB_DEBUG
+-#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args)
++#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
+ #else
+ #define DPRINTK(fmt, args...)
+ #endif
+@@ -129,7 +131,6 @@ struct ps3fb_priv {
+ 	u64 context_handle, memory_handle;
+ 	void *xdr_ea;
+ 	struct gpu_driver_info *dinfo;
+-	struct semaphore sem;
+ 	u32 res_index;
+ 
+ 	u64 vblank_count;	/* frame count */
+@@ -139,6 +140,8 @@ struct ps3fb_priv {
+ 	atomic_t ext_flip;	/* on/off flip with vsync */
+ 	atomic_t f_count;	/* fb_open count */
+ 	int is_blanked;
++	int is_kicked;
++	struct task_struct *task;
+ };
+ static struct ps3fb_priv ps3fb;
+ 
+@@ -294,10 +297,10 @@ static const struct fb_videomode ps3fb_modedb[] = {
+ #define VP_OFF(i)	(WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
+ #define FB_OFF(i)	(GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
+ 
+-static int ps3fb_mode = 0;
++static int ps3fb_mode;
+ module_param(ps3fb_mode, bool, 0);
+ 
+-static char *mode_option __initdata = NULL;
++static char *mode_option __initdata;
+ 
+ 
+ static int ps3fb_get_res_table(u32 xres, u32 yres)
+@@ -393,7 +396,7 @@ static int ps3fb_sync(u32 frame)
+ 
+ 	if (frame > ps3fb.num_frames - 1) {
+ 		printk(KERN_WARNING "%s: invalid frame number (%u)\n",
+-		       __FUNCTION__, frame);
++		       __func__, frame);
+ 		return -EINVAL;
+ 	}
+ 	offset = xres * yres * BPP * frame;
+@@ -406,23 +409,26 @@ static int ps3fb_sync(u32 frame)
+ 					   (xres << 16) | yres,
+ 					   xres * BPP);	/* line_length */
+ 	if (status)
+-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
+-		       __FUNCTION__, status);
++		printk(KERN_ERR
++		       "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
++		       __func__, status);
+ #ifdef HEAD_A
+ 	status = lv1_gpu_context_attribute(ps3fb.context_handle,
+ 					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
+ 					   0, offset, 0, 0);
+ 	if (status)
+-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+-		       __FUNCTION__, status);
++		printk(KERN_ERR
++		       "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
++		       __func__, status);
+ #endif
+ #ifdef HEAD_B
+ 	status = lv1_gpu_context_attribute(ps3fb.context_handle,
+ 					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
+ 					   1, offset, 0, 0);
+ 	if (status)
+-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+-		       __FUNCTION__, status);
++		printk(KERN_ERR
++		       "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
++		       __func__, status);
+ #endif
+ 	return 0;
+ }
+@@ -631,7 +637,7 @@ static int ps3fb_blank(int blank, struct fb_info *info)
+ {
+ 	int retval;
+ 
+-	DPRINTK("%s: blank:%d\n", __FUNCTION__, blank);
++	DPRINTK("%s: blank:%d\n", __func__, blank);
+ 	switch (blank) {
+ 	case FB_BLANK_POWERDOWN:
+ 	case FB_BLANK_HSYNC_SUSPEND:
+@@ -677,13 +683,10 @@ EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
+ 
+ void ps3fb_flip_ctl(int on)
+ {
+-	if (on) {
+-		if (atomic_read(&ps3fb.ext_flip) > 0) {
+-			atomic_dec(&ps3fb.ext_flip);
+-		}
+-	} else {
++	if (on)
++		atomic_dec_if_positive(&ps3fb.ext_flip);
++	else
+ 		atomic_inc(&ps3fb.ext_flip);
+-	}
+ }
+ 
+ EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
+@@ -732,6 +735,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
+ 			if (copy_from_user(&val, argp, sizeof(val)))
+ 				break;
+ 
++			if (!(val & PS3AV_MODE_MASK)) {
++				u32 id = ps3av_get_auto_mode(0);
++				if (id > 0)
++					val = (val & ~PS3AV_MODE_MASK) | id;
++			}
+ 			DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
+ 			retval = -EINVAL;
+ 			old_mode = ps3fb_mode;
+@@ -783,8 +791,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
+ 
+ 	case PS3FB_IOCTL_OFF:
+ 		DPRINTK("PS3FB_IOCTL_OFF:\n");
+-		if (atomic_read(&ps3fb.ext_flip) > 0)
+-			atomic_dec(&ps3fb.ext_flip);
++		atomic_dec_if_positive(&ps3fb.ext_flip);
+ 		retval = 0;
+ 		break;
+ 
+@@ -805,11 +812,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
+ 
+ static int ps3fbd(void *arg)
+ {
+-	daemonize("ps3fbd");
+-	for (;;) {
+-		down(&ps3fb.sem);
+-		if (atomic_read(&ps3fb.ext_flip) == 0)
++	while (!kthread_should_stop()) {
++		try_to_freeze();
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (ps3fb.is_kicked) {
++			ps3fb.is_kicked = 0;
+ 			ps3fb_sync(0);	/* single buffer */
++		}
++		schedule();
+ 	}
+ 	return 0;
+ }
+@@ -823,15 +833,18 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
+ 	status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
+ 	if (status) {
+ 		printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
+-		       __FUNCTION__, status);
++		       __func__, status);
+ 		return IRQ_NONE;
+ 	}
+ 
+ 	if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
+ 		/* VSYNC */
+ 		ps3fb.vblank_count = head->vblank_count;
+-		if (!ps3fb.is_blanked)
+-			up(&ps3fb.sem);
++		if (ps3fb.task && !ps3fb.is_blanked &&
++		    !atomic_read(&ps3fb.ext_flip)) {
++			ps3fb.is_kicked = 1;
++			wake_up_process(ps3fb.task);
++		}
+ 		wake_up_interruptible(&ps3fb.wait_vsync);
+ 	}
+ 
+@@ -879,16 +892,16 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
+ 		dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
+ 
+ 	if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
+-		printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__,
++		printk(KERN_ERR "%s: version_driver err:%x\n", __func__,
+ 		       dinfo->version_driver);
+ 		return -EINVAL;
+ 	}
+ 
+ 	ps3fb.dev = dev;
+-	error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
+-			      &ps3fb.irq_no);
++	error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
++				   &ps3fb.irq_no);
+ 	if (error) {
+-		printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__,
++		printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__,
+ 		       error);
+ 		return error;
+ 	}
+@@ -896,9 +909,9 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
+ 	error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
+ 			    "ps3fb vsync", ps3fb.dev);
+ 	if (error) {
+-		printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__,
++		printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
+ 		       error);
+-		ps3_free_irq(ps3fb.irq_no);
++		ps3_irq_plug_destroy(ps3fb.irq_no);
+ 		return error;
+ 	}
+ 
+@@ -915,7 +928,7 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
+ 				       xdr_lpar, ps3fb_videomemory.size, 0);
+ 	if (status) {
+ 		printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
+-		       __FUNCTION__, status);
++		       __func__, status);
+ 		return -ENXIO;
+ 	}
+ 	DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
+@@ -927,8 +940,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
+ 					   xdr_lpar, ps3fb_videomemory.size,
+ 					   GPU_IOIF, 0);
+ 	if (status) {
+-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
+-		       __FUNCTION__, status);
++		printk(KERN_ERR
++		       "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
++		       __func__, status);
+ 		return -ENXIO;
+ 	}
+ 	return 0;
+@@ -968,13 +982,14 @@ static int __init ps3fb_probe(struct platform_device *dev)
+ 	u64 xdr_lpar;
+ 	int status;
+ 	unsigned long offset;
++	struct task_struct *task;
+ 
+ 	/* get gpu context handle */
+ 	status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
+ 					 &ps3fb.memory_handle, &ddr_lpar);
+ 	if (status) {
+ 		printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
+-		       __FUNCTION__, status);
++		       __func__, status);
+ 		goto err;
+ 	}
+ 	DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
+@@ -985,14 +1000,14 @@ static int __init ps3fb_probe(struct platform_device *dev)
+ 					  &lpar_reports, &lpar_reports_size);
+ 	if (status) {
+ 		printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
+-		       __FUNCTION__, status);
++		       __func__, status);
+ 		goto err_gpu_memory_free;
+ 	}
+ 
+ 	/* vsync interrupt */
+ 	ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
+ 	if (!ps3fb.dinfo) {
+-		printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__);
++		printk(KERN_ERR "%s: ioremap failed\n", __func__);
+ 		goto err_gpu_context_free;
+ 	}
+ 
+@@ -1050,16 +1065,25 @@ static int __init ps3fb_probe(struct platform_device *dev)
+ 	       "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
+ 	       info->node, ps3fb_videomemory.size >> 10);
+ 
+-	kernel_thread(ps3fbd, info, CLONE_KERNEL);
++	task = kthread_run(ps3fbd, info, "ps3fbd");
++	if (IS_ERR(task)) {
++		retval = PTR_ERR(task);
++		goto err_unregister_framebuffer;
++	}
++
++	ps3fb.task = task;
++
+ 	return 0;
+ 
++err_unregister_framebuffer:
++	unregister_framebuffer(info);
+ err_fb_dealloc:
+ 	fb_dealloc_cmap(&info->cmap);
+ err_framebuffer_release:
+ 	framebuffer_release(info);
+ err_free_irq:
+ 	free_irq(ps3fb.irq_no, ps3fb.dev);
+-	ps3_free_irq(ps3fb.irq_no);
++	ps3_irq_plug_destroy(ps3fb.irq_no);
+ err_iounmap_dinfo:
+ 	iounmap((u8 __iomem *)ps3fb.dinfo);
+ err_gpu_context_free:
+@@ -1075,7 +1099,7 @@ 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_free_irq(ps3fb.irq_no);
++	ps3_irq_plug_destroy(ps3fb.irq_no);
+ 	iounmap((u8 __iomem *)ps3fb.dinfo);
+ }
+ 
+@@ -1083,9 +1107,14 @@ void ps3fb_cleanup(void)
+ {
+ 	int status;
+ 
++	if (ps3fb.task) {
++		struct task_struct *task = ps3fb.task;
++		ps3fb.task = NULL;
++		kthread_stop(task);
++	}
+ 	if (ps3fb.irq_no) {
+ 		free_irq(ps3fb.irq_no, ps3fb.dev);
+-		ps3_free_irq(ps3fb.irq_no);
++		ps3_irq_plug_destroy(ps3fb.irq_no);
+ 	}
+ 	iounmap((u8 __iomem *)ps3fb.dinfo);
+ 
+@@ -1137,8 +1166,9 @@ int ps3fb_set_sync(void)
+ 					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+ 					   0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+ 	if (status) {
+-		printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
+-		       __FUNCTION__, status);
++		printk(KERN_ERR
++		       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
++		       __func__, status);
+ 		return -1;
+ 	}
+ #endif
+@@ -1148,8 +1178,9 @@ int ps3fb_set_sync(void)
+ 					   1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+ 
+ 	if (status) {
+-		printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
+-		       __FUNCTION__, status);
++		printk(KERN_ERR
++		       "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
++		       __func__, status);
+ 		return -1;
+ 	}
+ #endif
+@@ -1174,7 +1205,7 @@ static int __init ps3fb_init(void)
+ 
+ 	error = ps3av_dev_open();
+ 	if (error) {
+-		printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__);
++		printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
+ 		goto err;
+ 	}
+ 
+@@ -1195,7 +1226,6 @@ static int __init ps3fb_init(void)
+ 
+ 	atomic_set(&ps3fb.f_count, -1);	/* fbcon opens ps3fb */
+ 	atomic_set(&ps3fb.ext_flip, 0);	/* for flip with vsync */
+-	init_MUTEX(&ps3fb.sem);
+ 	init_waitqueue_head(&ps3fb.wait_vsync);
+ 	ps3fb.num_frames = 1;
+ 
+diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
+index 821581a..13c372d 100644
+--- a/include/asm-powerpc/ps3.h
++++ b/include/asm-powerpc/ps3.h
+@@ -167,26 +167,31 @@ enum ps3_cpu_binding {
+ 	PS3_BINDING_CPU_1 = 1,
+ };
+ 
+-int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
++int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
+ 	unsigned int *virq);
+-int ps3_free_io_irq(unsigned int virq);
+-int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq);
+-int ps3_free_event_irq(unsigned int virq);
++int ps3_virq_destroy(unsigned int virq);
++int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
++	unsigned int *virq);
++int ps3_irq_plug_destroy(unsigned int virq);
++int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq);
++int ps3_event_receive_port_destroy(unsigned int virq);
+ int ps3_send_event_locally(unsigned int virq);
+-int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+-	const struct ps3_device_id *did, unsigned int interrupt_id,
++
++int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+ 	unsigned int *virq);
+-int ps3_disconnect_event_irq(const struct ps3_device_id *did,
+-	unsigned int interrupt_id, unsigned int virq);
+-int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
++int ps3_io_irq_destroy(unsigned int virq);
++int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+ 	unsigned int *virq);
+-int ps3_free_vuart_irq(unsigned int virq);
+-int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
++int ps3_vuart_irq_destroy(unsigned int virq);
++int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
+ 	unsigned int class, unsigned int *virq);
+-int ps3_free_spe_irq(unsigned int virq);
+-int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
++int ps3_spe_irq_destroy(unsigned int virq);
++
++int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
++	const struct ps3_device_id *did, unsigned int interrupt_id,
+ 	unsigned int *virq);
+-int ps3_free_irq(unsigned int virq);
++int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
++	unsigned int interrupt_id, unsigned int virq);
+ 
+ /* lv1 result codes */
+ 
+diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h
+index 43e90ea..9efc40f 100644
+--- a/include/asm-powerpc/ps3av.h
++++ b/include/asm-powerpc/ps3av.h
 @@ -18,8 +18,6 @@
  #ifndef _ASM_POWERPC_PS3AV_H_
  #define _ASM_POWERPC_PS3AV_H_
@@ -306,7 +1535,7 @@
  /** command for ioctl() **/
  #define PS3AV_VERSION 0x205	/* version of ps3av command */
  
-@@ -643,24 +641,6 @@
+@@ -643,24 +641,6 @@ struct ps3av_pkt_avb_param {
  	u8 buf[PS3AV_PKT_AVB_PARAM_MAX_BUF_SIZE];
  };
  
@@ -331,7 +1560,7 @@
  
  /** command status **/
  #define PS3AV_STATUS_SUCCESS			0x0000	/* success */
-@@ -718,6 +698,7 @@
+@@ -718,6 +698,7 @@ static inline void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_
  extern int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *,
  					    u32);
  
@@ -339,67 +1568,11 @@
  extern int ps3av_vuart_write(struct ps3_vuart_port_device *dev,
  			     const void *buf, unsigned long size);
  extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
-unchanged:
---- ps3-linux-dev.orig/arch/powerpc/kernel/head_64.S
-+++ ps3-linux-dev/arch/powerpc/kernel/head_64.S
-@@ -1555,7 +1555,6 @@ _GLOBAL(generic_secondary_smp_init)
- 	
- 	/* turn on 64-bit mode */
- 	bl	.enable_64b_mode
--	isync
- 
- 	/* Set up a paca value for this processor. Since we have the
- 	 * physical cpu id in r24, we need to search the pacas to find
-@@ -1851,7 +1850,6 @@ __secondary_start_pmac_0:
- _GLOBAL(pmac_secondary_start)
- 	/* turn on 64-bit mode */
- 	bl	.enable_64b_mode
--	isync
- 
- 	/* Copy some CPU settings from CPU 0 */
- 	bl	.__restore_cpu_ppc970
-unchanged:
---- ps3-linux-dev.orig/arch/powerpc/platforms/ps3/setup.c
-+++ ps3-linux-dev/arch/powerpc/platforms/ps3/setup.c
-@@ -137,6 +137,12 @@ early_param("ps3fb", early_parse_ps3fb);
- #define prealloc_ps3fb_videomemory()	do { } while (0)
- #endif
+@@ -725,6 +706,7 @@ extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
  
-+static int ps3_set_dabr(u64 dabr)
-+{
-+	enum {DABR_USER = 1, DABR_KERNEL = 2,};
-+
-+	return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0;
-+}
- 
- static void __init ps3_setup_arch(void)
- {
-@@ -234,6 +240,7 @@ define_machine(ps3) {
- 	.get_boot_time			= ps3_get_boot_time,
- 	.set_rtc_time			= ps3_set_rtc_time,
- 	.get_rtc_time			= ps3_get_rtc_time,
-+	.set_dabr			= ps3_set_dabr,
- 	.calibrate_decr			= ps3_calibrate_decr,
- 	.progress			= ps3_progress,
- 	.restart			= ps3_restart,
-unchanged:
---- ps3-linux-2.6.21-rc4.orig/arch/powerpc/platforms/cell/Kconfig
-+++ ps3-linux-2.6.21-rc4/arch/powerpc/platforms/cell/Kconfig
-@@ -18,6 +18,7 @@ config SPU_BASE
- 
- config CBE_RAS
- 	bool "RAS features for bare metal Cell BE"
-+	depends on PPC_CELL_NATIVE
- 	default y
- 
- config CBE_THERM
-only in patch2:
-unchanged:
---- ps3-linux-dev.orig/arch/powerpc/platforms/ps3/mm.c
-+++ ps3-linux-dev/arch/powerpc/platforms/ps3/mm.c
-@@ -826,5 +826,4 @@ void __init ps3_mm_init(void)
- void ps3_mm_shutdown(void)
- {
- 	ps3_mm_region_destroy(&map.r1);
--	map.total = map.rm.size;
- }
+ extern int ps3av_set_video_mode(u32, int);
+ extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
++extern int ps3av_get_auto_mode(int);
+ extern int ps3av_set_mode(u32, int);
+ extern int ps3av_get_mode(void);
+ extern int ps3av_get_scanmode(int);

linux-2.6-ps3-storage.patch:

Index: linux-2.6-ps3-storage.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-ps3-storage.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6-ps3-storage.patch	30 Mar 2007 20:10:34 -0000	1.1
+++ linux-2.6-ps3-storage.patch	4 May 2007 14:52:31 -0000	1.2
@@ -1,9 +1,7 @@
-Combined patch, with minor modification in platforms/ps3/setup.c, 
-generated from the following patches from ps3-linux-patches.git:
+As of 2007-05-04 (commit 197a8b29cbb721909e1bde44c6e7a588d93ba440):
 
 ps3-wip/ps3stor+snd-mem-hack.diff
 ps3-wip/ps3_storage.diff
-ps3-wip/ps3stor-needs-exports.diff
 ps3-hacks/ps3stor-repository-exports.diff
 ps3-hacks/ps3stor_alloc_bootmem_buffer.diff
 ps3-hacks/ps3stor_use_bootmem_buffer.diff
@@ -13,12 +11,15 @@
 ps3-wip/ps3stor_repository-2.diff
 ps3-wip/ps3stor_kill_DYNAMIC_BOUNCE.diff
 ps3-wip/ps3stor_rw_semaphore.diff
+ps3-wip/ps3stor-readcd.diff
+ps3-wip/ps3stor_modalias.diff
+
 
 diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
-index 2014d2b..b8b0de5 100644
+index e6ff624..64b56d7 100644
 --- a/arch/powerpc/platforms/ps3/mm.c
 +++ b/arch/powerpc/platforms/ps3/mm.c
-@@ -128,6 +128,16 @@ static void _debug_dump_map(const struct map* m, const char* func, int line)
+@@ -129,6 +129,16 @@ static void _debug_dump_map(const struct map* m, const char* func, int line)
  
  static struct map map;
  
@@ -35,9 +36,9 @@
  /**
   * ps3_mm_phys_to_lpar - translate a linux physical address to lpar address
   * @phys_addr: linux physical address
-@@ -816,6 +826,12 @@ 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);
+@@ -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;
@@ -49,7 +50,7 @@
  }
  
 diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
-index ca04f03..18b66de 100644
+index 4a1015b..dc56127 100644
 --- a/arch/powerpc/platforms/ps3/platform.h
 +++ b/arch/powerpc/platforms/ps3/platform.h
 @@ -134,6 +134,8 @@ struct ps3_repository_device {
@@ -62,7 +63,7 @@
  	enum ps3_dev_type dev_type,
  	const struct ps3_repository_device *start_dev,
 diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
-index ae586a0..c58bf37 100644
+index ae586a0..e0067bf 100644
 --- a/arch/powerpc/platforms/ps3/repository.c
 +++ b/arch/powerpc/platforms/ps3/repository.c
 @@ -182,6 +182,7 @@ int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id)
@@ -113,7 +114,7 @@
  
  int ps3_repository_read_dev_reg_type(unsigned int bus_index,
  	unsigned int dev_index, unsigned int reg_index,
-@@ -513,6 +519,30 @@ int ps3_repository_dump_bus_info(void)
+@@ -513,6 +519,31 @@ int ps3_repository_dump_bus_info(void)
  }
  #endif /* defined(DEBUG) */
  
@@ -140,11 +141,12 @@
 +	*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 +571,7 @@ static int find_device(unsigned int bus_index, unsigned int num_dev,
+@@ -541,7 +572,7 @@ static int find_device(unsigned int bus_index, unsigned int num_dev,
  	}
  
  	if (dev_index == num_dev)
@@ -153,7 +155,7 @@
  
  	pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
  		__func__, __LINE__, dev_type, dev_index);
-@@ -577,25 +607,14 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
+@@ -577,25 +608,14 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
  
  	BUG_ON(start_dev && start_dev->bus_index > 10);
  
@@ -185,7 +187,7 @@
  	pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
  		__func__, __LINE__, bus_type, bus_index);
  
-@@ -630,6 +649,7 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
+@@ -630,6 +650,7 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
  
  	return result;
  }
@@ -193,7 +195,15 @@
  
  int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
  	enum ps3_interrupt_type intr_type, unsigned int *interrupt_id)
-@@ -949,6 +969,7 @@ int ps3_repository_read_boot_dat_address(u64 *address)
+@@ -668,6 +689,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+ 
+ 	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(u64 *address)
  		0,
  		address, 0);
  }
@@ -201,7 +211,7 @@
  
  int ps3_repository_read_boot_dat_size(unsigned int *size)
  {
-@@ -1015,6 +1036,7 @@ int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq)
+@@ -1015,6 +1038,7 @@ int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq)
  		0,
  		tb_freq, 0);
  }
@@ -210,7 +220,7 @@
  int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq)
  {
 diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
-index ac5df96..dd2bfa5 100644
+index e045216..092ecd1 100644
 --- a/arch/powerpc/platforms/ps3/setup.c
 +++ b/arch/powerpc/platforms/ps3/setup.c
 @@ -117,9 +117,9 @@ static void prealloc(struct ps3_prealloc *p)
@@ -226,9 +236,9 @@
  };
  #define prealloc_ps3fb_videomemory()	prealloc(&ps3fb_videomemory)
  
-@@ -158,6 +158,18 @@ static int ps3_set_dabr(u64 dabr)
- 	return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0;
- }
+@@ -137,6 +137,18 @@ early_param("ps3fb", early_parse_ps3fb);
+ #define prealloc_ps3fb_videomemory()	do { } while (0)
+ #endif
  
 +#if defined(CONFIG_PS3_STORAGE) || defined(CONFIG_PS3_STORAGE_MODULE)
 +struct ps3_prealloc ps3_stor_bounce_buffer = {
@@ -242,10 +252,10 @@
 +#define prealloc_ps3_stor_bounce_buffer()	do { } while (0)
 +#endif
 +
- static void __init ps3_setup_arch(void)
+ static int ps3_set_dabr(u64 dabr)
  {
- 	union ps3_firmware_version v;
-@@ -160,6 +171,8 @@ static void __init ps3_setup_arch(void)
+ 	enum {DABR_USER = 1, DABR_KERNEL = 2,};
+@@ -166,6 +178,8 @@ static void __init ps3_setup_arch(void)
  #endif
  
  	prealloc_ps3fb_videomemory();
@@ -304,19 +314,19 @@
 +obj-$(CONFIG_PS3_STORAGE)	+= ps3_storage.o
  
 diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
-index 821581a..735681c 100644
+index 0369120..2ec7ae4 100644
 --- a/include/asm-powerpc/ps3.h
 +++ b/include/asm-powerpc/ps3.h
-@@ -383,5 +383,6 @@ struct ps3_prealloc {
+@@ -431,5 +431,6 @@ struct ps3_prealloc {
  };
  
  extern struct ps3_prealloc ps3fb_videomemory;
 +extern struct ps3_prealloc ps3_stor_bounce_buffer;
  
  #endif
---- /dev/null	2007-03-29 13:51:49.880883652 +0100
-+++ b/drivers/block/ps3_storage.c	2007-03-30 18:25:12.000000000 +0100
-@@ -0,0 +1,2696 @@
+--- /dev/null	2007-05-01 15:16:24.100521312 +0100
++++ b/drivers/block/ps3_storage.c	2007-05-04 11:46:56.000000000 +0100
+@@ -0,0 +1,2741 @@
 +/*
 + * Copyright (C) 2006 Sony Computer Entertainment Inc.
 + * Copyright 2006, 2007 Sony Corporation
@@ -411,6 +421,8 @@
 +static LIST_HEAD(ps3_stor_host_list);
 +static DEFINE_SPINLOCK(ps3_stor_host_list_lock);
 +
++static u64 ps3_stor_virtual_to_lpar(struct ps3_stor_dev_info *dev_info,
++				    void *va);
 +
 +/*
 + * fill buf with MODE SENSE page 8 (caching parameter)
@@ -715,55 +727,70 @@
 +	const struct scsi_command_handler_info * handler_info;
 +	unsigned char * cmnd = dev_info->srb->cmnd;
 +	int bounce_len = 0;
-+	unsigned char * bounce_buf = NULL;
 +	int error;
 +	unsigned char keys[4];
 +
 +	handler_info = &(dev_info->handler_info[cmnd[0]]);
 +
-+	/* alloc bounce buffer if needed */
-+        if (handler_info->buflen == USE_SRB_6) {
++	/* check buffer size */
++	switch (handler_info->buflen) {
++	case USE_SRB_6:
 +		bounce_len = cmnd[4];
-+	} else if (handler_info->buflen == USE_SRB_10) {
-+		bounce_len = (cmnd[7] << 8) | cmnd[8];
-+	} else {
++		break;
++	case USE_SRB_10:
++ 		bounce_len = (cmnd[7] << 8) | cmnd[8];
++		break;
++	case USE_CDDA_FRAME_RAW:
++		bounce_len = ((cmnd[6] << 16) |
++		       (cmnd[7] <<  8) |
++		       (cmnd[8] <<  0)) * CD_FRAMESIZE_RAW;
++		break;
++	default:
 +		bounce_len = handler_info->buflen;
 +	}
 +
-+	if (bounce_len)
-+		bounce_buf = kmalloc(bounce_len, GFP_NOIO);
-+
++	if (dev_info->dedicated_bounce_size < bounce_len ) {
++		static int printed;
++		if (!printed++)
++			printk(KERN_ERR "%s: data size too large %#x<%#x\n",
++			       __FUNCTION__,
++			       dev_info->dedicated_bounce_size,
++			       bounce_len);
++		dev_info->srb->result = DID_ERROR << 16;
++		memset(dev_info->srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
++		dev_info->srb->sense_buffer[0] = 0x70;
++		dev_info->srb->sense_buffer[2] = ILLEGAL_REQUEST;
++		return -1;
++	}
 +
 +	memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
 +	memcpy(&(atapi_cmnd.pkt), cmnd, 12);
 +	atapi_cmnd.pktlen = 12;
 +	atapi_cmnd.proto = handler_info->proto;
-+	if (atapi_cmnd.proto == PIO_DATA_OUT_PROTO) {
-+		atapi_cmnd.in_out = DIR_MEMORY_TO_ATAPI;
-+		fetch_to_dev_buffer(dev_info->srb, bounce_buf, bounce_len);
-+	} else
-+		atapi_cmnd.in_out = DIR_ATAPI_TO_MEMORY;
++	if (handler_info->in_out != DIR_NA)
++		atapi_cmnd.in_out = handler_info->in_out;
++
++	if (atapi_cmnd.in_out == DIR_WRITE)
++		fetch_to_dev_buffer(dev_info->srb, dev_info->bounce_buf, bounce_len);
 +
 +	atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
 +
 +	atapi_cmnd.blocks = atapi_cmnd.arglen = bounce_len;
-+	atapi_cmnd.buffer = ps3_mm_phys_to_lpar(__pa(bounce_buf)); /* no need special convert */
++	atapi_cmnd.buffer = ps3_stor_virtual_to_lpar(dev_info, dev_info->bounce_buf);
 +
 +	/* issue command */
 +	init_completion(&(dev_info->irq_done));
 +	error = lv1_storage_send_device_command(lv1_dev_info->repo.did.dev_id,
 +						LV1_STORAGE_SEND_ATAPI_COMMAND,
-+						ps3_mm_phys_to_lpar(__pa(&atapi_cmnd)), /* no need special convert */
++						ps3_mm_phys_to_lpar(__pa(&atapi_cmnd)),
 +						sizeof(struct lv1_atapi_cmnd_block),
 +						atapi_cmnd.buffer,
-+						atapi_cmnd.blocks,
++						atapi_cmnd.arglen,
 +						&lv1_dev_info->current_tag);
 +	if (error) {
 +		printk(KERN_ERR "%s: send_device failed lv1dev=%u ret=%d\n",
 +		       __FUNCTION__, lv1_dev_info->repo.did.dev_id, error);
 +		dev_info->srb->result = DID_ERROR << 16; /* FIXME: is better other error code ? */
-+		if (bounce_buf)
-+			kfree(bounce_buf);
 +		return -1;
 +	}
 +
@@ -773,18 +800,12 @@
 +	/* check error */
 +	if (!dev_info->lv1_status) {
 +		/* OK, completed */
-+		if (atapi_cmnd.proto == PIO_DATA_IN_PROTO)
-+			fill_from_dev_buffer(dev_info->srb, bounce_buf, bounce_len);
++		if (atapi_cmnd.in_out == DIR_READ)
++			fill_from_dev_buffer(dev_info->srb, dev_info->bounce_buf, bounce_len);
 +		dev_info->srb->result = DID_OK << 16;
-+		if (bounce_buf)
-+			kfree(bounce_buf);
 +		return 0;
 +	}
 +
-+	if (bounce_buf) {
-+		kfree(bounce_buf);
-+		bounce_buf = NULL;
-+	}
 +	/* error */
 +	if (!auto_sense) {
 +		dev_info->srb->result = (DID_ERROR << 16) | (CHECK_CONDITION << 1);
@@ -803,16 +824,15 @@
 +		dev_info->srb->result = SAM_STAT_CHECK_CONDITION;
 +	} else {
 +		/* do auto sense by our selves*/
-+		bounce_buf = kzalloc(18, GFP_NOIO);
 +		memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
 +		atapi_cmnd.pkt[0] = REQUEST_SENSE;
 +		atapi_cmnd.pkt[4] = 18;
 +		atapi_cmnd.pktlen = 12;
 +		atapi_cmnd.arglen = atapi_cmnd.blocks = atapi_cmnd.pkt[4];
 +		atapi_cmnd.block_size = 1;
-+		atapi_cmnd.proto = PIO_DATA_IN_PROTO;
-+		atapi_cmnd.in_out = DIR_ATAPI_TO_MEMORY;
-+		atapi_cmnd.buffer = ps3_mm_phys_to_lpar(__pa(bounce_buf));
++		atapi_cmnd.proto = DMA_PROTO;
++		atapi_cmnd.in_out = DIR_READ;
++		atapi_cmnd.buffer = ps3_stor_virtual_to_lpar(dev_info,dev_info->bounce_buf);
 +
 +		/* issue REQUEST_SENSE command */
 +		init_completion(&(dev_info->irq_done));
@@ -821,7 +841,7 @@
 +							ps3_mm_phys_to_lpar(__pa(&atapi_cmnd)),
 +							sizeof(struct lv1_atapi_cmnd_block),
 +							atapi_cmnd.buffer,
-+							atapi_cmnd.blocks,
++							atapi_cmnd.arglen,
 +							&lv1_dev_info->current_tag);
 +		if (error) {
 +			printk(KERN_ERR "%s: send_device for request sense failed lv1dev=%u ret=%d\n", __FUNCTION__,
@@ -841,9 +861,8 @@
 +			       keys[0], keys[1], keys[2]);
 +		}
 +
-+		memcpy(dev_info->srb->sense_buffer, bounce_buf, min((int)atapi_cmnd.pkt[4], SCSI_SENSE_BUFFERSIZE));
-+		if (bounce_buf)
-+			kfree(bounce_buf);
++		memcpy(dev_info->srb->sense_buffer, dev_info->bounce_buf,
++		       min((int)atapi_cmnd.pkt[4], SCSI_SENSE_BUFFERSIZE));
 +		dev_info->srb->result = SAM_STAT_CHECK_CONDITION;
 +	}
 +
@@ -2042,7 +2061,7 @@
 +}
 +
 +const static struct platform_device ps3_stor_platform_device = {
-+	.name           = "ps3_stor",
++	.name           = "ps3_storage",
 +	.dev            = {
 +		.release        = ps3_stor_device_release
 +	}
@@ -2316,48 +2335,84 @@
 +
 +static const struct scsi_command_handler_info scsi_cmnd_info_table_hdd[256] =
 +{
-+	[INQUIRY]                 = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_inquiry},
-+	[REQUEST_SENSE]           = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_request_sense},
-+	[TEST_UNIT_READY]         = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_just_ok},
-+	[READ_CAPACITY]           = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_read_capacity},
-+	[MODE_SENSE_10]           = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_mode_sense},
-+	[SYNCHRONIZE_CACHE]       = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_sync_cache},
-+	[READ_10]                 = { NOT_AVAIL, NOT_AVAIL, ps3_stor_common_handle_read},
-+	[READ_6]                  = { NOT_AVAIL, NOT_AVAIL, ps3_stor_common_handle_read},
-+	[WRITE_10]                = { NOT_AVAIL, NOT_AVAIL, ps3_stor_common_handle_write},
-+	[WRITE_6]                 = { NOT_AVAIL, NOT_AVAIL, ps3_stor_common_handle_write}
++	[INQUIRY]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_inquiry},
++	[REQUEST_SENSE]           = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_request_sense},
++	[TEST_UNIT_READY]         = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_just_ok},
++	[READ_CAPACITY]           = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_read_capacity},
++	[MODE_SENSE_10]           = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_mode_sense},
++	[SYNCHRONIZE_CACHE]       = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_sync_cache},
++	[READ_10]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_read},
++	[READ_6]                  = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_read},
++	[WRITE_10]                = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_write},
++	[WRITE_6]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_write}
 +};
 +
 +static const struct scsi_command_handler_info scsi_cmnd_info_table_flash[256] =
 +{
-+	[INQUIRY]                 = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_inquiry},
-+	[REQUEST_SENSE]           = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_request_sense},
-+	[TEST_UNIT_READY]         = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_just_ok},
-+	[READ_CAPACITY]           = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_read_capacity},
-+	[MODE_SENSE_10]           = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_mode_sense},
-+	[SYNCHRONIZE_CACHE]       = { NOT_AVAIL, NOT_AVAIL, ps3_stor_hdd_handle_sync_cache},
-+	[READ_10]                 = { NOT_AVAIL, NOT_AVAIL, ps3_stor_common_handle_read},
-+	[READ_6]                  = { NOT_AVAIL, NOT_AVAIL, ps3_stor_common_handle_read},
-+	[WRITE_10]                = { NOT_AVAIL, NOT_AVAIL, ps3_stor_handle_write_flash},
-+	[WRITE_6]                 = { NOT_AVAIL, NOT_AVAIL, ps3_stor_handle_write_flash}
++	[INQUIRY]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_inquiry},
++	[REQUEST_SENSE]           = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_request_sense},
++	[TEST_UNIT_READY]         = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_just_ok},
++	[READ_CAPACITY]           = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_read_capacity},
++	[MODE_SENSE_10]           = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_mode_sense},
++	[SYNCHRONIZE_CACHE]       = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_hdd_handle_sync_cache},
++	[READ_10]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_read},
++	[READ_6]                  = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_read},
++	[WRITE_10]                = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_handle_write_flash},
++	[WRITE_6]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_handle_write_flash}
 +};
 +
 +static const struct scsi_command_handler_info scsi_cmnd_info_table_atapi[256] =
 +{
-+	[INQUIRY]                 = {  USE_SRB_6, PIO_DATA_IN_PROTO, ps3_stor_atapi_handle_simple},
-+	[REQUEST_SENSE]           = {  USE_SRB_6, PIO_DATA_IN_PROTO, ps3_stor_atapi_handle_request_sense},
-+	[START_STOP]              = {          0,    NON_DATA_PROTO, ps3_stor_atapi_handle_simple},
-+	[ALLOW_MEDIUM_REMOVAL]    = {          0,    NON_DATA_PROTO, ps3_stor_atapi_handle_simple},
-+	[TEST_UNIT_READY]         = {          0,    NON_DATA_PROTO, ps3_stor_atapi_handle_simple},
-+	[READ_CAPACITY]           = {          8, PIO_DATA_IN_PROTO, ps3_stor_atapi_handle_simple},
-+	[MODE_SENSE_10]           = { USE_SRB_10, PIO_DATA_IN_PROTO, ps3_stor_atapi_handle_simple},
-+	[READ_TOC]                = { USE_SRB_10, PIO_DATA_IN_PROTO, ps3_stor_atapi_handle_simple},
-+	[GPCMD_GET_CONFIGURATION] = { USE_SRB_10, PIO_DATA_IN_PROTO, ps3_stor_atapi_handle_simple},
-+	[GPCMD_READ_DISC_INFO]    = { USE_SRB_10, PIO_DATA_IN_PROTO, ps3_stor_atapi_handle_simple},
-+	[READ_10]                 = {  NOT_AVAIL,         NOT_AVAIL, ps3_stor_common_handle_read},
-+	[READ_6]                  = {  NOT_AVAIL,         NOT_AVAIL, ps3_stor_common_handle_read},
-+	[WRITE_10]                = {  NOT_AVAIL,         NOT_AVAIL, ps3_stor_common_handle_write},
-+	[WRITE_6]                 = {  NOT_AVAIL,         NOT_AVAIL, ps3_stor_common_handle_write}
++	[INQUIRY]                 = {USE_SRB_6, PIO_DATA_IN_PROTO, DIR_READ,
++				     ps3_stor_atapi_handle_simple},
++	[REQUEST_SENSE]           = {USE_SRB_6, PIO_DATA_IN_PROTO, DIR_READ,
++				     ps3_stor_atapi_handle_request_sense},
++	[START_STOP]              = {0, NON_DATA_PROTO, DIR_NA,
++				     ps3_stor_atapi_handle_simple},
++	[ALLOW_MEDIUM_REMOVAL]    = {0, NON_DATA_PROTO, DIR_NA,
++				     ps3_stor_atapi_handle_simple},
++	[TEST_UNIT_READY]         = {0, NON_DATA_PROTO, DIR_NA,
++				     ps3_stor_atapi_handle_simple},
++	[READ_CAPACITY]           = {8, PIO_DATA_IN_PROTO,  DIR_READ,
++				     ps3_stor_atapi_handle_simple},
++	[MODE_SENSE_10]           = {USE_SRB_10, PIO_DATA_IN_PROTO, DIR_READ,
++				     ps3_stor_atapi_handle_simple},
++	[READ_TOC]                = {USE_SRB_10, PIO_DATA_IN_PROTO, DIR_READ,
++				     ps3_stor_atapi_handle_simple},
++	[GPCMD_GET_CONFIGURATION] = {USE_SRB_10, PIO_DATA_IN_PROTO, DIR_READ,
++				     ps3_stor_atapi_handle_simple},
++	[GPCMD_READ_DISC_INFO]    = {USE_SRB_10, PIO_DATA_IN_PROTO, DIR_READ,
++				     ps3_stor_atapi_handle_simple},
++	[READ_10]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_read},
++	[READ_6]                  = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_read},
++	[WRITE_10]                = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_write},
++	[WRITE_6]                 = {NOT_AVAIL, NA_PROTO, DIR_NA,
++				     ps3_stor_common_handle_write},
++	[GPCMD_READ_CD]           = {USE_CDDA_FRAME_RAW, DMA_PROTO, DIR_READ,
++				     ps3_stor_atapi_handle_simple}
 +};
 +
 +
@@ -2894,7 +2949,7 @@
 +
 +static struct platform_driver ps3_stor_platform_driver = {
 +	.driver = {
-+		.name = "ps3_stor"
++		.name = "ps3_storage"
 +	},
 +	.probe          = ps3_stor_driver_probe,
 +	.remove         = ps3_stor_driver_remove,
@@ -3013,9 +3068,9 @@
 +
 +device_initcall(ps3_stor_init);
 +module_exit(ps3_stor_exit);
---- /dev/null	2007-03-29 13:51:49.880883652 +0100
-+++ b/drivers/block/ps3_storage.h	2007-03-30 18:25:12.000000000 +0100
-@@ -0,0 +1,231 @@
+--- /dev/null	2007-05-01 15:16:24.100521312 +0100
++++ b/drivers/block/ps3_storage.h	2007-05-04 11:46:56.000000000 +0100
+@@ -0,0 +1,237 @@
 +/*
 + * Copyright (C) 2006 Sony Computer Entertainment Inc.
 + * Copyright 2006, 2007 Sony Corporation
@@ -3065,14 +3120,17 @@
 +};
 +
 +enum lv1_atapi_proto {
++	NA_PROTO = -1,
 +	NON_DATA_PROTO     = 0,
 +	PIO_DATA_IN_PROTO  = 1,
-+	PIO_DATA_OUT_PROTO = 2
++	PIO_DATA_OUT_PROTO = 2,
++	DMA_PROTO = 3
 +};
 +
 +enum lv1_atapi_in_out {
-+	DIR_MEMORY_TO_ATAPI = 0,
-+	DIR_ATAPI_TO_MEMORY = 1
++	DIR_NA = -1,
++	DIR_WRITE = 0, /* memory -> device */
++	DIR_READ = 1 /* device -> memory */
 +};
 +
 +/*
@@ -3083,16 +3141,19 @@
 +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
 + */
-+
-+#define NOT_AVAIL    (-1)
-+#define USE_SRB_10   (-2)
-+#define USE_SRB_6    (-3)
++enum {
++	NOT_AVAIL          = -1,
++	USE_SRB_10         = -2,
++	USE_SRB_6          = -3,
++	USE_CDDA_FRAME_RAW = -4
++};
 +/*
 + * for LV1 maintainance
 + */


--- linux-2.6-ps3-drivers-only-on-ps3.patch DELETED ---


--- linux-2.6-ps3-ethernet.patch DELETED ---


--- linux-2.6-ps3-exports.patch DELETED ---


--- linux-2.6-ps3-read-cd.patch DELETED ---


--- linux-2.6-ps3-sysbus-modalias.patch DELETED ---


--- linux-2.6-systemsim-work.patch DELETED ---


--- linux-2.6-uevent-ps3.patch DELETED ---


--- linux-2.6-usb-endian-quirks.patch DELETED ---




More information about the fedora-extras-commits mailing list