From: Albert H. <he...@us...> - 2009-03-28 20:44:23
|
Update of /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv15781/arch/powerpc/platforms/embedded6xx Modified Files: flipper-pic.c flipper-pic.h starlet-es.c starlet-ipc.c starlet-stm.c wii.c Log Message: ** Import git changes up to 2.6.29 merge ** commit 82670a7d050e5001f723a056e4827750c0f65dfc Author: Albert Herranz <alb...@ya...> Date: Sat Mar 28 19:57:29 2009 +0100 gamecube: update defconfig Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/configs/gamecube_defconfig | 72 +++++++++++++++++++++--------- 1 files changed, 50 insertions(+), 22 deletions(-) commit e28f75ea563c7c9e3fdec767ce029b4b1803172b Author: Albert Herranz <alb...@ya...> Date: Sat Mar 28 19:48:31 2009 +0100 wii: update defconfig Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/configs/wii_defconfig | 167 ++++++++++++++++++++++++++++++------ 1 files changed, 140 insertions(+), 27 deletions(-) commit 51a7be2130487abc9f47dc201d55b8049b0e8fba Author: Albert Herranz <alb...@ya...> Date: Wed Mar 25 19:28:44 2009 +0100 wii: kexec: save/restore lowmem stub Add a save/restore mechanism to preserve the lowest 16KiB of memory and make them available again after a kexec reboot. This is useful to preserve the "resident" reloader stubs installed by the existing bootloaders. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/boot/dts/wii.dts | 6 +++ arch/powerpc/boot/wii.c | 38 ++++++++++++++++++++++ arch/powerpc/platforms/embedded6xx/wii.c | 51 +++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 1 deletions(-) commit 0dc2ea8a60ff7f96091393d999add383f3d15cbf Author: Albert Herranz <alb...@ya...> Date: Wed Mar 25 18:13:12 2009 +0100 kexec: add preserved region This patch allows kexec to copy back a previously preserved memory region to its original location at kexec time. For example, the preserved region can be saved during boot time to a safe area and then restored back during the final kexec phase. The caller is responsible to ensure that the destination memory area can be safely overwritten. The source memory area must be available during the kexec relocation stage. One immediate use is preserving the lowest 16KiB in the Nintendo GameCube and Wii video game consoles which are traditionally used to host reloader stubs. Signed-off-by: Albert Herranz <alb...@ya...> include/linux/kexec.h | 11 +++++++---- kernel/kexec.c | 43 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 8 deletions(-) commit e163fdd92acdf7a903fce2a1e5249dd386ff712c Author: Albert Herranz <alb...@ya...> Date: Thu Mar 26 20:26:46 2009 +0100 wii: enhance bootwrapper entry The bootloaders used on the Nintendo Wii may load the kernel and transfer control to it in a variety of environments. This patch modifies the entry point of the bootwrapper to not make any particular assumption about the initial state of the MMU. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/boot/wii.c | 98 ++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 84 insertions(+), 14 deletions(-) commit 8034bd01f7068191d0f1044e942b8067d4f046e1 Author: Albert Herranz <alb...@ya...> Date: Wed Mar 25 00:14:18 2009 +0100 flipper-pic: add quiesce method Add a quiesce method to the "flipper" interrupt controller driver to inhibit all interrupt sources before a restart or kexec. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/platforms/embedded6xx/flipper-pic.c | 24 +++++++++++++++++++-- arch/powerpc/platforms/embedded6xx/flipper-pic.h | 1 + arch/powerpc/platforms/embedded6xx/wii.c | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) commit c75c681771ab387ee53ca6cfaed9a432ee99f0d9 Author: Albert Herranz <alb...@ya...> Date: Wed Mar 25 00:05:33 2009 +0100 exi: add quiesce method Add a quiesce method to the EXternal Interface (EXI) driver to calm down the EXI hardware before a restart or kexec. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/platforms/embedded6xx/wii.c | 3 ++- drivers/exi/exi-driver.c | 10 ++++++++++ drivers/exi/exi-hw.c | 5 +++++ drivers/exi/exi-hw.h | 2 ++ include/linux/exi.h | 12 ++++++++++++ 5 files changed, 31 insertions(+), 1 deletions(-) commit f063156b4a5ff84206d0b79a5ae25d50262fc010 Author: Albert Herranz <alb...@ya...> Date: Wed Mar 25 00:27:19 2009 +0100 gcn-si: add shutdown method Add a shutdown method to the Serial Interface (SI) driver to quiesce the SI hardware before a restart or kexec. Signed-off-by: Albert Herranz <alb...@ya...> drivers/input/si/gcn-si.c | 31 +++++++++++++++++++++++++++---- 1 files changed, 27 insertions(+), 4 deletions(-) commit afebd827733d7a76f323a59c8797b983d9e3655f Author: Albert Herranz <alb...@ya...> Date: Sat Mar 28 14:37:11 2009 +0100 gcn-vi: re-detect tv mode if cable type changes Force a video mode detection cycle when setting up a video mode if the cable type has changed (component vs non-component). Signed-off-by: Albert Herranz <alb...@ya...> drivers/video/gcnfb.c | 27 ++++++++++++++++++--------- 1 files changed, 18 insertions(+), 9 deletions(-) commit 584224e2479475edb51a399b419205f7e2368bc2 Author: Albert Herranz <alb...@ya...> Date: Tue Mar 24 23:56:48 2009 +0100 gcn-vi: add shutdown method Add a shutdown method to the Video Interface (VI) driver to quiesce the VI hardware before a restart or kexec. Signed-off-by: Albert Herranz <alb...@ya...> drivers/video/gcnfb.c | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) commit a6e357287734b326ce05de38f8588fc4526d11a5 Author: Albert Herranz <alb...@ya...> Date: Tue Mar 24 23:46:03 2009 +0100 gcn-vi: reset video hardware before initiating detection Issue a hardware reset of the Video Interface (VI) hardware before performing the TV video mode autodetection. This fixes graphics glitches (swapped colors, green-red artifacts) seen after an incomplete video initialization. Signed-off-by: Albert Herranz <alb...@ya...> drivers/video/gcnfb.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) commit 2d13698e4014c461351658ee3a2c3f923f51cf3a Author: Albert Herranz <alb...@ya...> Date: Tue Mar 24 21:11:38 2009 +0100 wii: platform restart rework Use the new IOS reload helpers in the platform restart code and kexec path. A platform restart tries now to load The Homebrew Channel and falls back to a normal STM restart if the former fails. On the other hand, the kexec reboot path reloads IOS before the final kexec phase to ensure that the kexec'ed image will get IOS in a known clean state. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/include/asm/starlet.h | 2 + arch/powerpc/platforms/embedded6xx/wii.c | 36 ++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) commit e11bbe78fc0c212db0ff18553dbf7841e190f828 Author: Albert Herranz <alb...@ya...> Date: Tue Mar 24 20:38:02 2009 +0100 wii: starlet/ios: add ios reload helpers Add helpers for reloading IOS and optionally launching titles from NAND. These helpers will be used later in the platform code to implement a clean "direct reboot to channel" method, which finally will allow rebooting to The Homebrew Channel. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/include/asm/starlet.h | 5 ++ arch/powerpc/platforms/embedded6xx/starlet-es.c | 86 +++++++++++++++++++++++ 2 files changed, 91 insertions(+), 0 deletions(-) commit e4d9d4e747632a6657f650c537e6e10a06f2747b Author: Albert Herranz <alb...@ya...> Date: Tue Mar 24 20:25:42 2009 +0100 wii: starlet/ios: use polled ipc api on title launch This patch converts the title launch helper code to the new polled IPC call interface, and prepares it to be called from non-sleeping contexts. This change is required to implement later the new IOS reload helpers. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/platforms/embedded6xx/starlet-es.c | 184 +++++++++++------------ 1 files changed, 89 insertions(+), 95 deletions(-) commit e09ea011b5c14e16b6498d7063abf54751901878 Author: Albert Herranz <alb...@ya...> Date: Tue Mar 24 20:08:26 2009 +0100 wii: starlet/ios: use polled ipc api on platform restart This patch fixes some known restart failure scenarios by switching the platform restart code to the new polled IPC call interface. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/platforms/embedded6xx/starlet-stm.c | 25 ++++++++++++++++----- 1 files changed, 19 insertions(+), 6 deletions(-) commit 644ec5f6c15bbdb275bd9b485f7a811d8eb67e2b Author: Albert Herranz <alb...@ya...> Date: Tue Mar 24 19:57:08 2009 +0100 wii: starlet/ios: add polled ipc api Add a new set of functions enabling the use of IOS IPC calls from non-sleeping contexts or critical paths. The *_polled functions actively sample the status of their related IPC requests until they complete. Execution of this family of calls is serialized and use processor resources so they should be only used for very specific contexts where the other existing functions are not suitable. Signed-off-by: Albert Herranz <alb...@ya...> arch/powerpc/include/asm/starlet.h | 37 +++-- arch/powerpc/platforms/embedded6xx/starlet-ipc.c | 197 +++++++++++++++++----- 2 files changed, 179 insertions(+), 55 deletions(-) commit fc5f68b629dbe6706fbabedf15e340428b196d5e Author: Albert Herranz <alb...@ya...> Date: Tue Mar 10 18:14:20 2009 +0100 gcn-si: fix named module parameter declaration This patch fixes the following build error due to an incorrect module parameter declaration. drivers/input/si/gcn-si.c:130: error: expected ')' before 'int' make[2]: *** [drivers/input/si/gcn-si.o] Error 1 make[1]: *** [drivers/input/si] Error 2 make: *** [drivers] Error 2 Signed-off-by: Albert Herranz <alb...@ya...> drivers/input/si/gcn-si.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) Index: flipper-pic.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx/flipper-pic.c,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** flipper-pic.c 1 Feb 2009 18:29:35 -0000 1.3 --- flipper-pic.c 28 Mar 2009 20:44:19 -0000 1.4 *************** *** 113,116 **** --- 113,123 ---- */ + static void __flipper_quiesce(void __iomem *io_base) + { + /* mask and ack all IRQs */ + out_be32(io_base + FLIPPER_IMR, 0x00000000); + out_be32(io_base + FLIPPER_ICR, 0xffffffff); + } + struct irq_host * __init flipper_pic_init(struct device_node *np) { *************** *** 130,136 **** res.start, io_base); ! /* mask and ack all IRQs */ ! out_be32(io_base + FLIPPER_IMR, 0x00000000); ! out_be32(io_base + FLIPPER_ICR, 0xffffffff); irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS, --- 137,141 ---- res.start, io_base); ! __flipper_quiesce(io_base); irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS, *************** *** 186,189 **** --- 191,207 ---- */ + /** + * flipper_quiesce() - quiesce flipper irq controller + * + * Mask and ack all interrupt sources. + * + */ + void flipper_quiesce(void) + { + void __iomem *io_base = flipper_irq_host->host_data; + + __flipper_quiesce(io_base); + } + /* * Resets the platform. Index: flipper-pic.h =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx/flipper-pic.h,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** flipper-pic.h 1 Feb 2009 18:29:35 -0000 1.3 --- flipper-pic.h 28 Mar 2009 20:44:19 -0000 1.4 *************** *** 36,39 **** --- 36,40 ---- void __init flipper_pic_probe(void); + void flipper_quiesce(void); void flipper_platform_reset(void); int flipper_is_reset_button_pressed(void); Index: starlet-stm.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx/starlet-stm.c,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** starlet-stm.c 1 Feb 2009 18:29:35 -0000 1.5 --- starlet-stm.c 28 Mar 2009 20:44:19 -0000 1.6 *************** *** 28,31 **** --- 28,33 ---- #define STARLET_STM_SHUTDOWN 0x2003 + #define STARLET_STM_TIMEOUT 1000000 /* usecs */ + #define STARLET_DEV_STM_IMMEDIATE "/dev/stm/immediate" *************** *** 45,48 **** --- 47,51 ---- static void starlet_stm_common_restart(int request, u32 value) { + static int already_in_restart; u32 *buf = starlet_stm_buf; size_t len = sizeof(starlet_stm_buf); *************** *** 50,59 **** int error; ! /* REVISIT, use polled ipc calls here */ ! drv_printk(KERN_INFO, "trying IPC restart...\n"); ! fd = starlet_open(dev_stm_immediate, 0); if (fd < 0) { drv_printk(KERN_ERR, "failed to open %s\n", dev_stm_immediate); --- 53,66 ---- int error; ! if (already_in_restart) { ! drv_printk(KERN_ERR, "previous restart attempt failed," ! " halting\n"); ! goto halt; ! } drv_printk(KERN_INFO, "trying IPC restart...\n"); + already_in_restart = 1; ! fd = starlet_open_polled(dev_stm_immediate, 0, STARLET_STM_TIMEOUT); if (fd < 0) { drv_printk(KERN_ERR, "failed to open %s\n", dev_stm_immediate); *************** *** 63,70 **** *buf = value; ! error = starlet_ioctl(fd, request, buf, len, buf, len); ! if (error < 0) drv_printk(KERN_ERR, "ioctl %d failed\n", request); ! starlet_close(fd); done: --- 70,83 ---- *buf = value; ! error = starlet_ioctl_polled(fd, request, buf, len, buf, len, ! STARLET_STM_TIMEOUT); ! if (error < 0) { drv_printk(KERN_ERR, "ioctl %d failed\n", request); ! starlet_close_polled(fd, STARLET_STM_TIMEOUT); ! } else { ! halt: ! for(;;) ! cpu_relax(); ! } done: Index: starlet-es.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx/starlet-es.c,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** starlet-es.c 1 Feb 2009 18:29:35 -0000 1.5 --- starlet-es.c 28 Mar 2009 20:44:19 -0000 1.6 *************** *** 31,36 **** --- 31,44 ---- printk(level DRV_MODULE_NAME ": " format , ## arg) + + #define STARLET_ES_IOS_MIN 30 + #define STARLET_ES_IOS_MAX 36 + + #define STARLET_ES_TIMEOUT 1000000 /* usecs */ + + struct starlet_es_device { int fd; + u64 ios_title; struct device *dev; *************** *** 54,74 **** } __attribute__((packed)); - #if 0 - struct starlet_es_ticket { - char issuer[0x40]; - u8 fill[63]; /* TODO: not really fill */ - u8 title_key[16]; - u8 fill2; - u64 ticketid; - u32 devicetype; - u64 title; - u16 access_mask; - u8 reserved[0x3c]; - u8 cidx_mask[0x40]; - u16 padding; - struct starlet_es_ticket_limit limits[8]; - } __attribute__((packed)); - #endif - /* * /dev/es --- 62,65 ---- *************** *** 101,105 **** if (!mutex_trylock(&es_small_buf_lock)) ! buf = starlet_kzalloc(es_small_buf_size, GFP_KERNEL); else { memset(es_small_buf, 0, es_small_buf_size); --- 92,96 ---- if (!mutex_trylock(&es_small_buf_lock)) ! buf = starlet_kzalloc(es_small_buf_size, GFP_ATOMIC); else { memset(es_small_buf, 0, es_small_buf_size); *************** *** 118,135 **** } - #if 0 - static void es_small_buf_dump(void) - { - int i; - size_t nelems = sizeof(es_small_buf) / sizeof(u32); - - drv_printk(KERN_INFO, "es_small_buf[%d]= {\n", nelems); - for (i = 0; i < nelems; i++) - drv_printk(KERN_INFO, "%08x, ", es_small_buf[i]); - drv_printk(KERN_INFO, "\n}\n"); - - } - #endif - /* * --- 109,112 ---- *************** *** 140,144 **** --- 117,123 ---- /** + * starlet_es_get_device() - get ES device handle * + * Returns the handle for the Encryption Services (ES) device instance. */ struct starlet_es_device *starlet_es_get_device(void) *************** *** 150,157 **** EXPORT_SYMBOL_GPL(starlet_es_get_device); ! /** * */ ! int starlet_es_get_title_count(unsigned long *count) { struct starlet_es_device *es_dev = starlet_es_get_device(); --- 129,136 ---- EXPORT_SYMBOL_GPL(starlet_es_get_device); ! /* * */ ! static int starlet_es_get_title_count(unsigned long *count) { struct starlet_es_device *es_dev = starlet_es_get_device(); *************** *** 182,189 **** } ! /** * */ ! int starlet_es_get_titles(u64 *titles, unsigned long count) { struct starlet_es_device *es_dev = starlet_es_get_device(); --- 161,168 ---- } ! /* * */ ! static int starlet_es_get_titles(u64 *titles, unsigned long count) { struct starlet_es_device *es_dev = starlet_es_get_device(); *************** *** 213,220 **** } ! /** ! * */ ! int starlet_es_get_ticket_view_count(u64 title, unsigned long *count) { struct starlet_es_device *es_dev = starlet_es_get_device(); --- 192,199 ---- } ! /* ! * This call may be used in a non-sleeping context */ ! static int starlet_es_get_ticket_view_count(u64 title, unsigned long *count) { struct starlet_es_device *es_dev = starlet_es_get_device(); *************** *** 227,231 **** return -ENODEV; ! title_buf = starlet_kzalloc(sizeof(*title_buf), GFP_KERNEL); if (!title_buf) return -ENOMEM; --- 206,210 ---- return -ENODEV; ! title_buf = starlet_kzalloc(sizeof(*title_buf), GFP_ATOMIC); if (!title_buf) return -ENOMEM; *************** *** 241,246 **** sg_init_one(io, count_buf, sizeof(*count_buf)); ! error = starlet_ioctlv(es_dev->fd, ES_IOCTLV_GETTICKETVIEWCOUNT, ! 1, in, 1, io); if (error) DBG("%s: error=%d (%08x)\n", __func__, error, error); --- 220,225 ---- sg_init_one(io, count_buf, sizeof(*count_buf)); ! error = starlet_ioctlv_polled(es_dev->fd, ES_IOCTLV_GETTICKETVIEWCOUNT, ! 1, in, 1, io, STARLET_ES_TIMEOUT); if (error) DBG("%s: error=%d (%08x)\n", __func__, error, error); *************** *** 254,263 **** } ! /** ! * */ ! int starlet_es_get_ticket_views(u64 title, ! struct starlet_es_ticket_view *views, ! unsigned long count) { struct starlet_es_device *es_dev = starlet_es_get_device(); --- 233,242 ---- } ! /* ! * This call may be used in a non-sleeping context */ ! static int starlet_es_get_ticket_views(u64 title, ! struct starlet_es_ticket_view *views, ! unsigned long count) { struct starlet_es_device *es_dev = starlet_es_get_device(); *************** *** 270,274 **** return -ENODEV; ! title_buf = starlet_kzalloc(sizeof(*title_buf), GFP_KERNEL); if (!title_buf) return -ENOMEM; --- 249,253 ---- return -ENODEV; ! title_buf = starlet_kzalloc(sizeof(*title_buf), GFP_ATOMIC); if (!title_buf) return -ENOMEM; *************** *** 288,293 **** sg_init_one(io, views, sizeof(*views)*count); ! error = starlet_ioctlv(es_dev->fd, ES_IOCTLV_GETTICKETVIEWS, ! 2, in, 1, io); if (error) DBG("%s: error=%d (%08x)\n", __func__, error, error); --- 267,272 ---- sg_init_one(io, views, sizeof(*views)*count); ! error = starlet_ioctlv_polled(es_dev->fd, ES_IOCTLV_GETTICKETVIEWS, ! 2, in, 1, io, STARLET_ES_TIMEOUT); if (error) DBG("%s: error=%d (%08x)\n", __func__, error, error); *************** *** 299,306 **** } ! /** ! * */ ! int starlet_es_launch_title_view(u64 title, struct starlet_es_ticket_view *view) { struct starlet_es_device *es_dev = starlet_es_get_device(); --- 278,286 ---- } ! /* ! * This call may be used in a non-sleeping context */ ! static int starlet_es_launch_title_view(u64 title, ! struct starlet_es_ticket_view *view) { struct starlet_es_device *es_dev = starlet_es_get_device(); *************** *** 312,316 **** return -ENODEV; ! title_buf = starlet_kzalloc(sizeof(*title_buf), GFP_KERNEL); if (!title_buf) return -ENOMEM; --- 292,296 ---- return -ENODEV; ! title_buf = starlet_kzalloc(sizeof(*title_buf), GFP_ATOMIC); if (!title_buf) return -ENOMEM; *************** *** 322,327 **** error = starlet_ioctlv_and_reboot(es_dev->fd, ! ES_IOCTLV_LAUNCHTITLE, ! 2, in, 0, NULL); if (error) DBG("%s: error=%d (%08x)\n", __func__, error, error); --- 302,307 ---- error = starlet_ioctlv_and_reboot(es_dev->fd, ! ES_IOCTLV_LAUNCHTITLE, ! 2, in, 0, NULL); if (error) DBG("%s: error=%d (%08x)\n", __func__, error, error); *************** *** 332,344 **** } /* ! * Setup routines. * */ ! #define STARLET_ES_IOS_MIN 30 ! #define STARLET_ES_IOS_MAX 36 static int starlet_es_find_newest_title(struct starlet_es_device *es_dev, --- 312,451 ---- } + /* + * This call may be used in a non-sleeping context + */ + static int starlet_es_launch_title(struct starlet_es_device *es_dev, u64 title) + { + struct starlet_es_ticket_view *views; + unsigned long count; + int error; + error = starlet_es_get_ticket_view_count(title, &count); + if (error) + return error; + + views = starlet_kzalloc(sizeof(*views)*count, GFP_ATOMIC); + if (!views) { + DBG("%s: out of memory\n", __func__); + return -ENOMEM; + } + + error = starlet_es_get_ticket_views(title, views, count); + if (error) { + starlet_kfree(views); + return error; + } + + drv_printk(KERN_INFO, "launching title %u-%u\n", + (u32)(title >> 32), (u32)title); + error = starlet_es_launch_title_view(title, views); /* first view */ + + starlet_kfree(views); + + return error; + } /* ! * This call may be used in a non-sleeping context ! */ ! static int starlet_es_reopen(struct starlet_es_device *es_dev) ! { ! int error; ! ! error = starlet_open_polled(dev_es, 0, STARLET_ES_TIMEOUT); ! if (error < 0) { ! drv_printk(KERN_ERR, "unable to reopen %s (%d)\n", ! dev_es, error); ! goto out; ! } ! es_dev->fd = error; ! error = 0; ! out: ! return error; ! } ! ! /* ! * This call may be used in a non-sleeping context ! */ ! static int __starlet_es_reload_ios(struct starlet_es_device *es_dev) ! { ! int error = -EINVAL; ! ! if (!es_dev->ios_title) { ! drv_printk(KERN_ERR, "no IOS previously loaded\n"); ! goto out; ! } ! ! error = starlet_es_launch_title(es_dev, es_dev->ios_title); ! if (!error) ! es_dev->fd = -1; ! out: ! return error; ! } ! ! /* ! * This call may be used in a non-sleeping context ! */ ! static int starlet_es_reload_ios(struct starlet_es_device *es_dev) ! { ! int error; ! ! error = __starlet_es_reload_ios(es_dev); ! if (!error) ! error = starlet_es_reopen(es_dev); ! ! if (error) ! DBG("%s: error=%d (%08x)\n", __func__, error, error); ! return error; ! } ! ! ! /** ! * starlet_es_reload_ios_and_discard() - reload IOS and stop using it ! * ! * Reloads the version of IOS loaded at boot time. ! * All IOS dependent devices will fail after this call unless they are ! * reinitialized. * + * This call may be used in a non-sleeping context */ + int starlet_es_reload_ios_and_discard(void) + { + struct starlet_es_device *es_dev = starlet_es_get_device(); + int error = -EINVAL; ! if (!es_dev) ! goto err_out; ! ! error = starlet_es_reload_ios(es_dev); ! err_out: ! return error; ! } ! EXPORT_SYMBOL_GPL(starlet_es_reload_ios_and_discard); ! ! /** ! * starlet_es_reload_ios_and_launch() - reload IOS and launch a title ! * ! * Reload the version of IOS loaded at boot time and launch a title. ! * If the title loaded is a non-IOS title, this function will not return and ! * is equivalent to a platform restart. ! * ! * This call may be used in a non-sleeping context ! */ ! int starlet_es_reload_ios_and_launch(u64 title) ! { ! struct starlet_es_device *es_dev = starlet_es_get_device(); ! int error = -EINVAL; ! ! if (!es_dev) ! goto err_out; ! ! error = starlet_es_reload_ios(es_dev); ! if (!error) ! error = starlet_es_launch_title(es_dev, title); ! err_out: ! return error; ! } ! EXPORT_SYMBOL_GPL(starlet_es_reload_ios_and_launch); static int starlet_es_find_newest_title(struct starlet_es_device *es_dev, *************** *** 387,421 **** } ! static int starlet_es_launch_title(struct starlet_es_device *es_dev, u64 title) ! { ! struct starlet_es_ticket_view *views; ! unsigned long count; ! int error; ! ! error = starlet_es_get_ticket_view_count(title, &count); ! if (error) ! return error; ! ! views = starlet_kzalloc(sizeof(*views)*count, GFP_KERNEL); ! if (!views) { ! DBG("%s: out of memory\n", __func__); ! return -ENOMEM; ! } ! ! error = starlet_es_get_ticket_views(title, views, count); ! if (error) { ! starlet_kfree(views); ! return error; ! } ! ! drv_printk(KERN_INFO, "launching IOS%u\n", (u32)(title & 0xffffffff)); ! error = starlet_es_launch_title_view(title, views); /* first view */ ! ! starlet_kfree(views); ! ! return error; ! } ! ! static int starlet_es_load_preferred(struct starlet_es_device *es_dev, u64 ios_min, u64 ios_max) { --- 494,498 ---- } ! static int starlet_es_load_preferred_ios(struct starlet_es_device *es_dev, u64 ios_min, u64 ios_max) { *************** *** 426,431 **** if (!error) return -EINVAL; ! if (error > 0) error = starlet_es_launch_title(es_dev, title); return error; --- 503,512 ---- if (!error) return -EINVAL; ! if (error > 0) { ! es_dev->ios_title = title; error = starlet_es_launch_title(es_dev, title); + if (!error) + error = starlet_es_reopen(es_dev); + } return error; *************** *** 469,478 **** ios_max = 0x100000000ULL | STARLET_ES_IOS_MAX; ! error = starlet_es_load_preferred(es_dev, ios_min, ios_max); ! if (error) { drv_printk(KERN_WARNING, "unable to load preferred" " IOS version (min %llx, max %llx)\n", ios_min, ios_max); - } } --- 550,558 ---- ios_max = 0x100000000ULL | STARLET_ES_IOS_MAX; ! error = starlet_es_load_preferred_ios(es_dev, ios_min, ios_max); ! if (error) drv_printk(KERN_WARNING, "unable to load preferred" " IOS version (min %llx, max %llx)\n", ios_min, ios_max); } Index: wii.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx/wii.c,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** wii.c 1 Feb 2009 18:29:35 -0000 1.4 --- wii.c 28 Mar 2009 20:44:19 -0000 1.5 *************** *** 18,21 **** --- 18,22 ---- #include <linux/seq_file.h> #include <linux/kexec.h> + #include <linux/exi.h> #include <asm/io.h> *************** *** 33,39 **** static void wii_restart(char *cmd) { - starlet_stm_restart(); local_irq_disable(); ! /* spin until power button pressed */ for (;;) cpu_relax(); --- 34,45 ---- static void wii_restart(char *cmd) { local_irq_disable(); ! ! /* try first to launch The Homebrew Channel... */ ! starlet_es_reload_ios_and_launch(STARLET_TITLE_HBC); ! /* ..and if that fails, try an assisted restart */ ! starlet_stm_restart(); ! ! /* fallback to spinning until the power button pressed */ for (;;) cpu_relax(); *************** *** 42,48 **** static void wii_power_off(void) { - starlet_stm_power_off(); local_irq_disable(); ! /* spin until power button pressed */ for (;;) cpu_relax(); --- 48,57 ---- static void wii_power_off(void) { local_irq_disable(); ! ! /* try an assisted poweroff */ ! starlet_stm_power_off(); ! ! /* fallback to spinning until the power button pressed */ for (;;) cpu_relax(); *************** *** 84,94 **** static void wii_shutdown(void) { ! /* currently not used */ } ! static int wii_kexec_prepare(struct kimage *image) { ! return 0; } #endif /* CONFIG_KEXEC */ --- 93,167 ---- static void wii_shutdown(void) { ! exi_quiesce(); ! flipper_quiesce(); } ! static int restore_lowmem_stub(struct kimage *image) { ! struct device_node *node; ! struct resource res; ! const unsigned long *prop; ! unsigned long dst, src; ! size_t size; ! int error; ! ! node = of_find_node_by_name(NULL, "lowmem-stub"); ! if (!node) { ! printk(KERN_ERR "unable to find node %s\n", "lowmem-stub"); ! error = -ENODEV; ! goto out; ! } ! ! error = of_address_to_resource(node, 0, &res); ! if (error) { ! printk(KERN_ERR "no lowmem-stub range found\n"); ! goto out_put; ! } ! dst = res.start; ! size = res.end - res.start + 1; ! ! prop = of_get_property(node, "save-area", NULL); ! if (!prop) { ! printk(KERN_ERR "unable to find %s property\n", "save-area"); ! error = -EINVAL; ! goto out_put; ! } ! src = *prop; ! ! printk(KERN_DEBUG "lowmem-stub: preparing restore from %08lX to %08lX" ! " (%u bytes)\n", src, dst, size); ! ! /* schedule a copy of the lowmem stub to its original location */ ! error = kimage_add_preserved_region(image, dst, src, PAGE_ALIGN(size)); ! ! out_put: ! of_node_put(node); ! out: ! return error; } + + static int wii_machine_kexec_prepare(struct kimage *image) + { + int error; + + error = restore_lowmem_stub(image); + if (error) + printk(KERN_ERR "%s: error %d\n", __func__, error); + return error; + } + + static void wii_machine_kexec(struct kimage *image) + { + local_irq_disable(); + + /* + * Reload IOS to make sure that I/O resources are freed before + * the final kexec phase. + */ + starlet_es_reload_ios_and_discard(); + + default_machine_kexec(image); + } + #endif /* CONFIG_KEXEC */ *************** *** 109,114 **** #ifdef CONFIG_KEXEC .machine_shutdown = wii_shutdown, ! .machine_kexec_prepare = wii_kexec_prepare, ! .machine_kexec = default_machine_kexec, #endif }; --- 182,187 ---- #ifdef CONFIG_KEXEC .machine_shutdown = wii_shutdown, ! .machine_kexec_prepare = wii_machine_kexec_prepare, ! .machine_kexec = wii_machine_kexec, #endif }; Index: starlet-ipc.c =================================================================== RCS file: /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx/starlet-ipc.c,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** starlet-ipc.c 1 Feb 2009 18:29:35 -0000 1.7 --- starlet-ipc.c 28 Mar 2009 20:44:19 -0000 1.8 *************** *** 32,36 **** #include <asm/io.h> #include <asm/bitops.h> ! #include <asm/starlet.h> --- 32,36 ---- #include <asm/io.h> #include <asm/bitops.h> ! #include <asm/time.h> #include <asm/starlet.h> *************** *** 40,44 **** #define DRV_AUTHOR "Albert Herranz" ! static char starlet_ipc_driver_version[] = "0.2i"; #define drv_printk(level, format, arg...) \ --- 40,44 ---- #define DRV_AUTHOR "Albert Herranz" ! static char starlet_ipc_driver_version[] = "0.3i"; #define drv_printk(level, format, arg...) \ *************** *** 51,58 **** #define STARLET_IPC_CSR 0x04 ! #define STARLET_IPC_CSR_TSTART (1<<0) /* start transmit */ #define STARLET_IPC_CSR_TBEI (1<<1) /* tx buf empty int */ #define STARLET_IPC_CSR_RBFI (1<<2) /* rx buf full int */ ! #define STARLET_IPC_CSR_INT (1<<3) /* interrupt ack */ #define STARLET_IPC_CSR_RBFIMASK (1<<4) /* rx buf full int mask */ #define STARLET_IPC_CSR_TBEIMASK (1<<5) /* tx buf empty int mask */ --- 51,58 ---- #define STARLET_IPC_CSR 0x04 ! #define STARLET_IPC_CSR_TXSTART (1<<0) /* start transmit */ #define STARLET_IPC_CSR_TBEI (1<<1) /* tx buf empty int */ #define STARLET_IPC_CSR_RBFI (1<<2) /* rx buf full int */ ! #define STARLET_IPC_CSR_RXRDY (1<<3) /* receiver ready */ #define STARLET_IPC_CSR_RBFIMASK (1<<4) /* rx buf full int mask */ #define STARLET_IPC_CSR_TBEIMASK (1<<5) /* tx buf empty int mask */ *************** *** 113,119 **** * Issue an end-of-interrupt sequence. */ ! static void starlet_ipc_eoi(void __iomem *io_base) { ! starlet_ipc_update_csr(io_base, STARLET_IPC_CSR_INT); } --- 113,119 ---- * Issue an end-of-interrupt sequence. */ ! static void starlet_ipc_rx_ready(void __iomem *io_base) { ! starlet_ipc_update_csr(io_base, STARLET_IPC_CSR_RXRDY); } *************** *** 223,227 **** starlet_ipc_sendto(io_base, (u32) req->dma_addr); ! starlet_ipc_update_csr(io_base, STARLET_IPC_CSR_TSTART); } --- 223,227 ---- starlet_ipc_sendto(io_base, (u32) req->dma_addr); ! starlet_ipc_update_csr(io_base, STARLET_IPC_CSR_TXSTART); } *************** *** 234,237 **** --- 234,238 ---- list_del_init(&req->node); ipc_dev->nr_outstanding--; + req->jiffies = 0; spin_unlock_irqrestore(&ipc_dev->list_lock, flags); *************** *** 257,263 **** ipc_dev->nr_pending++; spin_unlock_irqrestore(&ipc_dev->list_lock, flags); ! } else { starlet_ipc_start_request(req); - } } --- 258,263 ---- ipc_dev->nr_pending++; spin_unlock_irqrestore(&ipc_dev->list_lock, flags); ! } else starlet_ipc_start_request(req); } *************** *** 273,276 **** --- 273,277 ---- if (req && req->sig != ipc_dev->random_id) { drv_printk(KERN_ERR, "IPC trash detected\n"); + /* leak memory, we can't safely use it */ ipc_dev->nr_outstanding = 0; INIT_LIST_HEAD(&ipc_dev->outstanding_list); *************** *** 311,317 **** } spin_unlock_irqrestore(&ipc_dev->list_lock, flags); ! if (req) { starlet_ipc_start_request(req); ! } else { if (!test_and_clear_bit(__TX_INUSE, &ipc_dev->flags)) { /* we get two consecutive TBEIs on reboot */ --- 312,318 ---- } spin_unlock_irqrestore(&ipc_dev->list_lock, flags); ! if (req) starlet_ipc_start_request(req); ! else { if (!test_and_clear_bit(__TX_INUSE, &ipc_dev->flags)) { /* we get two consecutive TBEIs on reboot */ *************** *** 320,327 **** ipc_dev->req = NULL; if (req) { - starlet_ipc_complete_request(req); req->result = 0; } ! starlet_ipc_eoi(io_base); } } --- 321,328 ---- ipc_dev->req = NULL; if (req) { req->result = 0; + starlet_ipc_complete_request(req); } ! starlet_ipc_rx_ready(io_base); } } *************** *** 345,355 **** req = starlet_ipc_find_request_by_bus_addr(ipc_dev, req_bus_addr); ! if (req) { starlet_ipc_complete_request(req); ! } else { drv_printk(KERN_WARNING, "unknown request, bus=%p\n", (void *)req_bus_addr); ! } ! starlet_ipc_eoi(io_base); return IRQ_HANDLED; } --- 346,355 ---- req = starlet_ipc_find_request_by_bus_addr(ipc_dev, req_bus_addr); ! if (req) starlet_ipc_complete_request(req); ! else drv_printk(KERN_WARNING, "unknown request, bus=%p\n", (void *)req_bus_addr); ! starlet_ipc_rx_ready(io_base); return IRQ_HANDLED; } *************** *** 433,436 **** --- 433,478 ---- } + static DEFINE_SPINLOCK(starlet_ipc_poll_lock); + + #define __spin_event_timeout(condition, usecs, result, __end_ts) \ + for (__end_ts = get_tbl() + tb_ticks_per_usec * usecs; \ + !(result = (condition)) && __end_ts - get_tbl() > 0;) + + static int __starlet_ipc_poll_req(struct starlet_ipc_request *req, + unsigned long usecs) + { + struct starlet_ipc_device *ipc_dev = req->ipc_dev; + unsigned long counter; + int result; + + __spin_event_timeout(req->jiffies == 0 && + !test_bit(__REBOOT, &ipc_dev->flags), + usecs, result, counter) + starlet_ipc_handler(0, ipc_dev); + + if (!result) + req->result = -ETIME; + + /* debug */ + if (req->result < 0) + drv_printk(KERN_ERR, "%s: result %d\n", __func__, + req->result); + return req->result; + } + + static int starlet_ipc_call_polled(struct starlet_ipc_request *req, + unsigned long usecs) + { + unsigned long flags; + int error; + + req->done = NULL; + spin_lock_irqsave(&starlet_ipc_poll_lock, flags); + starlet_ipc_submit_request(req); + error = __starlet_ipc_poll_req(req, usecs); + spin_unlock_irqrestore(&starlet_ipc_poll_lock, flags); + return error; + } + /* * *************** *** 454,458 **** * */ ! int starlet_open(const char *pathname, int flags) { #define STSD_OPEN_BUF_SIZE 64 --- 496,501 ---- * */ ! static int _starlet_open(const char *pathname, int flags, ! gfp_t gfp_flags, int poll, unsigned long usecs) { #define STSD_OPEN_BUF_SIZE 64 *************** *** 471,475 **** return -ENODEV; ! req = starlet_ipc_alloc_request(ipc_dev, GFP_KERNEL); if (req) { len = strlen(pathname) + 1; --- 514,518 ---- return -ENODEV; ! req = starlet_ipc_alloc_request(ipc_dev, gfp_flags); if (req) { len = strlen(pathname) + 1; *************** *** 479,483 **** } if (!local_pathname) { ! local_pathname = starlet_kzalloc(len, GFP_KERNEL); if (!local_pathname) { starlet_ipc_free_request(req); --- 522,526 ---- } if (!local_pathname) { ! local_pathname = starlet_kzalloc(len, gfp_flags); if (!local_pathname) { starlet_ipc_free_request(req); *************** *** 494,498 **** req->open.pathname = dma_addr; /* bus address */ req->open.mode = flags; ! error = starlet_ipc_call(req); dma_unmap_single(ipc_dev->dev, dma_addr, len, DMA_TO_DEVICE); --- 537,542 ---- req->open.pathname = dma_addr; /* bus address */ req->open.mode = flags; ! error = (poll) ? starlet_ipc_call_polled(req, usecs) : ! starlet_ipc_call(req); dma_unmap_single(ipc_dev->dev, dma_addr, len, DMA_TO_DEVICE); *************** *** 506,518 **** } if (error < 0) ! DBG("%s: error=%d (%x)\n", __func__, error, error); return error; } EXPORT_SYMBOL_GPL(starlet_open); /* * */ ! int starlet_close(int fd) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); --- 550,576 ---- } if (error < 0) ! DBG("%s: %s: error=%d (%x)\n", __func__, pathname, ! error, error); return error; } + + int starlet_open(const char *pathname, int flags) + { + return _starlet_open(pathname, flags, GFP_KERNEL, 0, 0); + } EXPORT_SYMBOL_GPL(starlet_open); + int starlet_open_polled(const char *pathname, int flags, + unsigned long usecs) + { + return _starlet_open(pathname, flags, GFP_ATOMIC, 1, usecs); + } + EXPORT_SYMBOL_GPL(starlet_open_polled); + /* * */ ! static int _starlet_close(int fd, gfp_t gfp_flags, int poll, ! unsigned long usecs) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); *************** *** 523,537 **** return -ENODEV; ! req = starlet_ipc_alloc_request(ipc_dev, GFP_KERNEL); if (req) { req->cmd = STARLET_IOS_CLOSE; req->fd = fd; ! error = starlet_ipc_call(req); starlet_ipc_free_request(req); } return error; } EXPORT_SYMBOL_GPL(starlet_close); /* --- 581,608 ---- return -ENODEV; ! req = starlet_ipc_alloc_request(ipc_dev, gfp_flags); if (req) { req->cmd = STARLET_IOS_CLOSE; req->fd = fd; ! error = (poll) ? starlet_ipc_call_polled(req, usecs) : ! starlet_ipc_call(req); starlet_ipc_free_request(req); } return error; } + + int starlet_close(int fd) + { + return _starlet_close(fd, GFP_KERNEL, 0, 0); + } EXPORT_SYMBOL_GPL(starlet_close); + int starlet_close_polled(int fd, unsigned long usecs) + { + return _starlet_close(fd, GFP_ATOMIC, 1, usecs); + } + EXPORT_SYMBOL_GPL(starlet_close_polled); + + /* *************** *** 688,694 **** * */ ! int starlet_ioctl(int fd, int request, ! void *ibuf, size_t ilen, ! void *obuf, size_t olen) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); --- 759,766 ---- * */ ! static int _starlet_ioctl(int fd, int request, ! void *ibuf, size_t ilen, ! void *obuf, size_t olen, ! int poll, unsigned long usecs) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); *************** *** 703,707 **** ibuf, ilen, obuf, olen); if (!error) ! error = starlet_ipc_call(req); starlet_ipc_free_request(req); --- 775,780 ---- ibuf, ilen, obuf, olen); if (!error) ! error = (poll) ? starlet_ipc_call_polled(req, usecs) : ! starlet_ipc_call(req); starlet_ipc_free_request(req); *************** *** 710,715 **** --- 783,804 ---- return error; } + + int starlet_ioctl(int fd, int request, + void *ibuf, size_t ilen, + void *obuf, size_t olen) + { + return _starlet_ioctl(fd, request, ibuf, ilen, obuf, olen, 0, 0); + } EXPORT_SYMBOL_GPL(starlet_ioctl); + int starlet_ioctl_polled(int fd, int request, + void *ibuf, size_t ilen, + void *obuf, size_t olen, + unsigned long usecs) + { + return _starlet_ioctl(fd, request, ibuf, ilen, obuf, olen, 1, usecs); + } + EXPORT_SYMBOL_GPL(starlet_ioctl_polled); + /** * *************** *** 881,889 **** * */ ! int starlet_ioctlv(int fd, int request, ! unsigned int nents_in, ! struct scatterlist *sgl_in, ! unsigned int nents_io, ! struct scatterlist *sgl_io) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); --- 970,979 ---- * */ ! static int _starlet_ioctlv(int fd, int request, ! unsigned int nents_in, ! struct scatterlist *sgl_in, ! unsigned int nents_io, ! struct scatterlist *sgl_io, ! int poll, unsigned long usecs) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); *************** *** 899,903 **** nents_io, sgl_io); if (!error) ! error = starlet_ipc_call(req); starlet_ipc_free_request(req); --- 989,994 ---- nents_io, sgl_io); if (!error) ! error = (poll) ? starlet_ipc_call_polled(req, usecs) : ! starlet_ipc_call(req); starlet_ipc_free_request(req); *************** *** 906,911 **** --- 997,1024 ---- return error; } + + int starlet_ioctlv(int fd, int request, + unsigned int nents_in, + struct scatterlist *sgl_in, + unsigned int nents_io, + struct scatterlist *sgl_io) + { + return _starlet_ioctlv(fd, request, + nents_in, sgl_in, nents_io, sgl_io, 0, 0); + } EXPORT_SYMBOL_GPL(starlet_ioctlv); + int starlet_ioctlv_polled(int fd, int request, + unsigned int nents_in, + struct scatterlist *sgl_in, + unsigned int nents_io, + struct scatterlist *sgl_io, + unsigned long usecs) + { + return _starlet_ioctlv(fd, request, + nents_in, sgl_in, nents_io, sgl_io, 1, usecs); + } + EXPORT_SYMBOL_GPL(starlet_ioctlv_polled); + /** * *************** *** 944,951 **** */ int starlet_ioctlv_and_reboot(int fd, int request, ! unsigned int nents_in, ! struct scatterlist *sgl_in, ! unsigned int nents_io, ! struct scatterlist *sgl_io) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); --- 1057,1064 ---- */ int starlet_ioctlv_and_reboot(int fd, int request, ! unsigned int nents_in, ! struct scatterlist *sgl_in, ! unsigned int nents_io, ! struct scatterlist *sgl_io) { struct starlet_ipc_device *ipc_dev = starlet_ipc_get_device(); *************** *** 958,967 **** error = starlet_ioctlv_prepare(req, fd, request, ! nents_in, sgl_in, ! nents_io, sgl_io); if (!error) { ipc_dev->req = req; set_bit(__REBOOT, &ipc_dev->flags); ! error = starlet_ipc_call(req); } starlet_ipc_free_request(req); --- 1071,1080 ---- error = starlet_ioctlv_prepare(req, fd, request, ! nents_in, sgl_in, ! nents_io, sgl_io); if (!error) { ipc_dev->req = req; set_bit(__REBOOT, &ipc_dev->flags); ! error = starlet_ipc_call_polled(req, 10000000 /* usecs */); } starlet_ipc_free_request(req); |