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