diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-15 20:51:09 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-15 20:51:09 +0400 |
commit | 723e9db7a46e328527cc3da2b478b831184fe828 (patch) | |
tree | cdeda255633057dcb4c84097bed27b2bbf76970f /drivers/ps3/ps3stor_lib.c | |
parent | ada3fa15057205b7d3f727bba5cd26b5912e350f (diff) | |
parent | d331d8305cba713605854aab63a000fb892353a7 (diff) | |
download | linux-723e9db7a46e328527cc3da2b478b831184fe828.tar.xz |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (134 commits)
powerpc/nvram: Enable use Generic NVRAM driver for different size chips
powerpc/iseries: Fix oops reading from /proc/iSeries/mf/*/cmdline
powerpc/ps3: Workaround for flash memory I/O error
powerpc/booke: Don't set DABR on 64-bit BookE, use DAC1 instead
powerpc/perf_counters: Reduce stack usage of power_check_constraints
powerpc: Fix bug where perf_counters breaks oprofile
powerpc/85xx: Fix SMP compile error and allow NULL for smp_ops
powerpc/irq: Improve nanodoc
powerpc: Fix some late PowerMac G5 with PCIe ATI graphics
powerpc/fsl-booke: Use HW PTE format if CONFIG_PTE_64BIT
powerpc/book3e: Add missing page sizes
powerpc/pseries: Fix to handle slb resize across migration
powerpc/powermac: Thermal control turns system off too eagerly
powerpc/pci: Merge ppc32 and ppc64 versions of phb_scan()
powerpc/405ex: support cuImage via included dtb
powerpc/405ex: provide necessary fixup function to support cuImage
powerpc/40x: Add support for the ESTeem 195E (PPC405EP) SBC
powerpc/44x: Add Eiger AMCC (AppliedMicro) PPC460SX evaluation board support.
powerpc/44x: Update Arches defconfig
powerpc/44x: Update Arches dts
...
Fix up conflicts in drivers/char/agp/uninorth-agp.c
Diffstat (limited to 'drivers/ps3/ps3stor_lib.c')
-rw-r--r-- | drivers/ps3/ps3stor_lib.c | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c index 18066d555397..af0afa1db4a8 100644 --- a/drivers/ps3/ps3stor_lib.c +++ b/drivers/ps3/ps3stor_lib.c @@ -23,6 +23,65 @@ #include <asm/lv1call.h> #include <asm/ps3stor.h> +/* + * A workaround for flash memory I/O errors when the internal hard disk + * has not been formatted for OtherOS use. Delay disk close until flash + * memory is closed. + */ + +static struct ps3_flash_workaround { + int flash_open; + int disk_open; + struct ps3_system_bus_device *disk_sbd; +} ps3_flash_workaround; + +static int ps3stor_open_hv_device(struct ps3_system_bus_device *sbd) +{ + int error = ps3_open_hv_device(sbd); + + if (error) + return error; + + if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH) + ps3_flash_workaround.flash_open = 1; + + if (sbd->match_id == PS3_MATCH_ID_STOR_DISK) + ps3_flash_workaround.disk_open = 1; + + return 0; +} + +static int ps3stor_close_hv_device(struct ps3_system_bus_device *sbd) +{ + int error; + + if (sbd->match_id == PS3_MATCH_ID_STOR_DISK + && ps3_flash_workaround.disk_open + && ps3_flash_workaround.flash_open) { + ps3_flash_workaround.disk_sbd = sbd; + return 0; + } + + error = ps3_close_hv_device(sbd); + + if (error) + return error; + + if (sbd->match_id == PS3_MATCH_ID_STOR_DISK) + ps3_flash_workaround.disk_open = 0; + + if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH) { + ps3_flash_workaround.flash_open = 0; + + if (ps3_flash_workaround.disk_sbd) { + ps3_close_hv_device(ps3_flash_workaround.disk_sbd); + ps3_flash_workaround.disk_open = 0; + ps3_flash_workaround.disk_sbd = NULL; + } + } + + return 0; +} static int ps3stor_probe_access(struct ps3_storage_device *dev) { @@ -90,7 +149,7 @@ int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler) int error, res, alignment; enum ps3_dma_page_size page_size; - error = ps3_open_hv_device(&dev->sbd); + error = ps3stor_open_hv_device(&dev->sbd); if (error) { dev_err(&dev->sbd.core, "%s:%u: ps3_open_hv_device failed %d\n", __func__, @@ -166,7 +225,7 @@ fail_free_irq: fail_sb_event_receive_port_destroy: ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq); fail_close_device: - ps3_close_hv_device(&dev->sbd); + ps3stor_close_hv_device(&dev->sbd); fail: return error; } @@ -193,7 +252,7 @@ void ps3stor_teardown(struct ps3_storage_device *dev) "%s:%u: destroy event receive port failed %d\n", __func__, __LINE__, error); - error = ps3_close_hv_device(&dev->sbd); + error = ps3stor_close_hv_device(&dev->sbd); if (error) dev_err(&dev->sbd.core, "%s:%u: ps3_close_hv_device failed %d\n", __func__, |