From 06a5299aff38ba25c7742ae6293c588e38445f8b Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 12 Mar 2008 10:03:52 +0000 Subject: Do some crackdown on kernel object reinitialization after they could be in use and use before initialization. For c200/e200: Be sure fat cache and ata locks are acquired in the proper order during hot swapping. Delay hotswap monitoring until after initial file mounting (address 2nd kobj concern + possible call of fat driver before init). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16636 a1c6a512-1295-4272-9138-f99709370657 --- firmware/common/disk.c | 5 +-- firmware/drivers/audio/as3514.c | 3 -- firmware/drivers/fat.c | 19 ++++++++- firmware/export/fat.h | 4 ++ firmware/target/arm/i2c-pp.c | 3 +- firmware/target/arm/sandisk/ata-c200_e200.c | 65 +++++++++++++++++++++-------- firmware/target/arm/wmcodec-pp.c | 3 -- 7 files changed, 73 insertions(+), 29 deletions(-) diff --git a/firmware/common/disk.c b/firmware/common/disk.c index 3d4dd3dc1d..c6200ba286 100644 --- a/firmware/common/disk.c +++ b/firmware/common/disk.c @@ -104,7 +104,7 @@ int disk_mount_all(void) int mounted; int i; -#ifdef HAVE_MMC +#if defined(HAVE_MMC) || defined(HAVE_HOTSWAP) card_enable_monitoring(false); #endif @@ -118,9 +118,8 @@ int disk_mount_all(void) { mounted += disk_mount(1); /* try 2nd "drive", too */ } -#ifdef HAVE_MMC + card_enable_monitoring(true); -#endif #endif return mounted; diff --git a/firmware/drivers/audio/as3514.c b/firmware/drivers/audio/as3514.c index 08d4d538a4..d51341d8c3 100644 --- a/firmware/drivers/audio/as3514.c +++ b/firmware/drivers/audio/as3514.c @@ -132,9 +132,6 @@ void audiohw_init(void) { unsigned int i; - /* reset I2C */ - i2c_init(); - /* normal outputs for CDI and I2S pin groups */ DEV_INIT2 &= ~0x300; diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index 9dd27cf72a..f3374fc4c4 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c @@ -172,6 +172,7 @@ struct bpb }; static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */ +static bool initialized = false; static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb)); static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb)); @@ -202,6 +203,18 @@ static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE]; static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE]; static struct mutex cache_mutex NOCACHEBSS_ATTR; +#ifdef HAVE_HOTSWAP +void fat_lock(void) +{ + mutex_lock(&cache_mutex); +} + +void fat_unlock(void) +{ + mutex_unlock(&cache_mutex); +} +#endif + static long cluster2sec(IF_MV2(struct bpb* fat_bpb,) long cluster) { #ifndef HAVE_MULTIVOLUME @@ -240,7 +253,11 @@ void fat_init(void) { unsigned int i; - mutex_init(&cache_mutex); + if (!initialized) + { + initialized = true; + mutex_init(&cache_mutex); + } /* mark the FAT cache as unused */ for(i = 0;i < FAT_CACHE_SIZE;i++) diff --git a/firmware/export/fat.h b/firmware/export/fat.h index 0dfd395ea7..3cf2923b78 100644 --- a/firmware/export/fat.h +++ b/firmware/export/fat.h @@ -82,6 +82,10 @@ struct fat_dir unsigned char sectorcache[3][SECTOR_SIZE]; }; +#ifdef HAVE_HOTSWAP +extern void fat_lock(void); +extern void fat_unlock(void); +#endif extern void fat_init(void); extern int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector); diff --git a/firmware/target/arm/i2c-pp.c b/firmware/target/arm/i2c-pp.c index b8e3869907..092a59be84 100644 --- a/firmware/target/arm/i2c-pp.c +++ b/firmware/target/arm/i2c-pp.c @@ -187,6 +187,7 @@ int pp_i2c_send(unsigned int addr, int data0, int data1) void i2c_init(void) { /* From ipodlinux */ + mutex_init(&i2c_mtx); #ifdef IPOD_MINI /* GPIO port C disable port 0x10 */ @@ -231,7 +232,5 @@ void i2c_init(void) #endif #endif - mutex_init(&i2c_mtx); - i2c_readbyte(0x8, 0); } diff --git a/firmware/target/arm/sandisk/ata-c200_e200.c b/firmware/target/arm/sandisk/ata-c200_e200.c index 150b08fd92..99a00358ff 100644 --- a/firmware/target/arm/sandisk/ata-c200_e200.c +++ b/firmware/target/arm/sandisk/ata-c200_e200.c @@ -16,7 +16,7 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "ata.h" +#include "fat.h" #include "hotswap-target.h" #include "ata-target.h" #include "ata_idle_notify.h" @@ -29,8 +29,8 @@ #include "panic.h" #include "usb.h" -#define BLOCK_SIZE (512) -#define SECTOR_SIZE (512) +#define BLOCK_SIZE 512 +#define SECTOR_SIZE 512 #define BLOCKS_PER_BANK 0x7a7800 #define STATUS_REG (*(volatile unsigned int *)(0x70008204)) @@ -1045,22 +1045,33 @@ static void sd_thread(void) { #ifdef HAVE_HOTSWAP case SYS_HOTSWAP_INSERTED: - mutex_lock(&sd_mtx); /* Lock-out card activity */ - card_info[1].initialized = 0; - sd_status[1].retry = 0; - disk_unmount(1); /* Force remount */ - disk_mount(1); /* mount microSD card */ - queue_broadcast(SYS_FS_CHANGED, 0); - mutex_unlock(&sd_mtx); - break; - case SYS_HOTSWAP_EXTRACTED: - mutex_lock(&sd_mtx); /* Lock-out card activity */ - card_info[1].initialized = 0; + fat_lock(); /* lock-out FAT activity first - + prevent deadlocking via disk_mount that + would cause a reverse-order attempt with + another thread */ + mutex_lock(&sd_mtx); /* lock-out card activity - direct calls + into driver that bypass the fat cache */ + + /* We now have exclusive control of fat cache and ata */ + + disk_unmount(1); /* release "by force", ensure file + descriptors aren't leaked and any busy + ones are invalid if mounting */ + + /* Force card init for new card, re-init for re-inserted one or + * clear if the last attempt to init failed with an error. */ + card_info[1].initialized = 0; sd_status[1].retry = 0; - disk_unmount(1); /* release "by force" */ + + if (ev.id == SYS_HOTSWAP_INSERTED) + disk_mount(1); + queue_broadcast(SYS_FS_CHANGED, 0); + + /* Access is now safe */ mutex_unlock(&sd_mtx); + fat_unlock(); break; #endif case SYS_TIMEOUT: @@ -1135,6 +1146,28 @@ void ata_enable(bool on) } } +#ifdef HAVE_HOTSWAP +void card_enable_monitoring(bool on) +{ + if (on) + { +#ifdef SANSA_E200 + GPIO_SET_BITWISE(GPIOA_INT_EN, 0x80); +#elif defined(SANSA_C200) + GPIO_SET_BITWISE(GPIOL_INT_EN, 0x08); +#endif + } + else + { +#ifdef SANSA_E200 + GPIO_CLEAR_BITWISE(GPIOA_INT_EN, 0x80); +#elif defined(SANSA_C200) + GPIO_CLEAR_BITWISE(GPIOL_INT_EN, 0x08); +#endif + } +} +#endif + int ata_init(void) { int ret = 0; @@ -1193,7 +1226,6 @@ int ata_init(void) GPIOA_INT_LEV = (0x80 << 8) | (~GPIOA_INPUT_VAL & 0x80); GPIOA_INT_CLR = 0x80; - GPIO_SET_BITWISE(GPIOA_INT_EN, 0x80); #elif defined SANSA_C200 CPU_INT_EN = HI_MASK; CPU_HI_INT_EN = GPIO2_MASK; @@ -1201,7 +1233,6 @@ int ata_init(void) GPIOL_INT_LEV = (0x08 << 8) | (~GPIOL_INPUT_VAL & 0x08); GPIOL_INT_CLR = 0x08; - GPIO_SET_BITWISE(GPIOL_INT_EN, 0x08); #endif #endif } diff --git a/firmware/target/arm/wmcodec-pp.c b/firmware/target/arm/wmcodec-pp.c index 3bd9d7fd2b..cfdd311c52 100644 --- a/firmware/target/arm/wmcodec-pp.c +++ b/firmware/target/arm/wmcodec-pp.c @@ -41,9 +41,6 @@ * Initialise the PP I2C and I2S. */ void audiohw_init(void) { - /* reset I2C */ - i2c_init(); - #ifdef CPU_PP502x /* normal outputs for CDI and I2S pin groups */ DEV_INIT2 &= ~0x300; -- cgit v1.2.3