From d4800fa3851d2d89c1be03ec99af81f277892579 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Fri, 17 Jun 2011 03:09:47 +0000 Subject: Coldfire: Fix the modification of IMR. Interrupts must be masked at the core level at at least the level of the interrupt being masked. Not following the datasheet and relying strictly on and/or_l causes unhandled 'Levelx' exceptions (showing itself quite often in PCM mixer work which more greatly stresses PCM lockout). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30009 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/coldfire/iriver/h300/lcd-h300.c | 2 +- firmware/target/coldfire/kernel-coldfire.c | 2 +- firmware/target/coldfire/mpio/hd200/lcd-hd200.c | 2 +- firmware/target/coldfire/pcm-coldfire.c | 24 ++++++++++++------------ firmware/target/coldfire/system-coldfire.c | 12 +++++++++++- firmware/target/coldfire/system-target.h | 5 +++++ firmware/target/coldfire/timer-coldfire.c | 4 ++-- 7 files changed, 33 insertions(+), 18 deletions(-) diff --git a/firmware/target/coldfire/iriver/h300/lcd-h300.c b/firmware/target/coldfire/iriver/h300/lcd-h300.c index ea0819aa3e..6c21a7e260 100644 --- a/firmware/target/coldfire/iriver/h300/lcd-h300.c +++ b/firmware/target/coldfire/iriver/h300/lcd-h300.c @@ -266,7 +266,7 @@ void lcd_init_device(void) DSR3 = 1; DIVR3 = 57; /* DMA3 is mapped into vector 57 in system.c */ ICR9 = (6 << 2); /* Enable DMA3 interrupt at level 6, priority 0 */ - and_l(~(1<<17), &IMR); + coldfire_imr_mod(0, 1 << 17); mutex_init(&lcd_mtx); _display_on(); diff --git a/firmware/target/coldfire/kernel-coldfire.c b/firmware/target/coldfire/kernel-coldfire.c index 0b08ed13e3..a16f7ad05e 100644 --- a/firmware/target/coldfire/kernel-coldfire.c +++ b/firmware/target/coldfire/kernel-coldfire.c @@ -51,7 +51,7 @@ void tick_start(unsigned int interval_in_ms) TER0 = 0xff; /* Clear all events */ ICR1 = 0x8c; /* Interrupt on level 3.0 */ - IMR &= ~0x200; + coldfire_imr_mod(0x000, 0x200); } void TIMER0(void) __attribute__ ((interrupt_handler)); diff --git a/firmware/target/coldfire/mpio/hd200/lcd-hd200.c b/firmware/target/coldfire/mpio/hd200/lcd-hd200.c index 682ed6a311..879352f7b4 100644 --- a/firmware/target/coldfire/mpio/hd200/lcd-hd200.c +++ b/firmware/target/coldfire/mpio/hd200/lcd-hd200.c @@ -167,7 +167,7 @@ void lcd_init_device(void) DSR3 = 1; DIVR3 = 57; /* DMA3 is mapped into vector 57 in system.c */ ICR9 = (6 << 2); /* Enable DMA3 interrupt at level 6, priority 0 */ - and_l(~(1<<17), &IMR); + coldfire_imr_mod(0, 1 << 17); mutex_init(&lcd_mtx); diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c index fa320dff3f..a06542c31f 100644 --- a/firmware/target/coldfire/pcm-coldfire.c +++ b/firmware/target/coldfire/pcm-coldfire.c @@ -219,19 +219,19 @@ void pcm_postinit(void) static struct dma_lock dma_play_lock = { .locked = 0, - .state = (0 << 14) /* bit 14 is DMA0 */ + .state = (1 << 14) /* bit 14 is DMA0 */ }; void pcm_play_lock(void) { if (++dma_play_lock.locked == 1) - or_l((1 << 14), &IMR); + coldfire_imr_mod(1 << 14, 1 << 14); } void pcm_play_unlock(void) { if (--dma_play_lock.locked == 0) - and_l(~dma_play_lock.state, &IMR); + coldfire_imr_mod(dma_play_lock.state, 1 << 14); } /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ @@ -248,7 +248,7 @@ void pcm_play_dma_start(const void *addr, size_t size) DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START; - dma_play_lock.state = (1 << 14); + dma_play_lock.state = (0 << 14); } /* pcm_play_dma_start */ /* Stops the DMA transfer and interrupt */ @@ -260,7 +260,7 @@ void pcm_play_dma_stop(void) iis_play_reset_if_playback(true); - dma_play_lock.state = (0 << 14); + dma_play_lock.state = (1 << 14); } /* pcm_play_dma_stop */ void pcm_play_dma_pause(bool pause) @@ -271,14 +271,14 @@ void pcm_play_dma_pause(bool pause) and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */ DSR0 = 1; /* stop channel */ iis_play_reset_if_playback(true); - dma_play_lock.state = (0 << 14); + dma_play_lock.state = (1 << 14); } else { /* restart playback on current buffer */ iis_play_reset_if_playback(true); or_l(DMA_INT | DMA_EEXT | DMA_START, &DCR0); /* everything ON */ - dma_play_lock.state = (1 << 14); + dma_play_lock.state = (0 << 14); } } /* pcm_play_dma_pause */ @@ -344,7 +344,7 @@ const void * pcm_play_dma_get_peak_buffer(int *count) static struct dma_lock dma_rec_lock = { .locked = 0, - .state = (0 << 15) /* bit 15 is DMA1 */ + .state = (1 << 15) /* bit 15 is DMA1 */ }; /* For the locks, DMA interrupt must be disabled when manipulating the lock @@ -353,13 +353,13 @@ static struct dma_lock dma_rec_lock = void pcm_rec_lock(void) { if (++dma_rec_lock.locked == 1) - or_l((1 << 15), &IMR); + coldfire_imr_mod(1 << 15, 1 << 15); } void pcm_rec_unlock(void) { if (--dma_rec_lock.locked == 0) - and_l(~dma_rec_lock.state, &IMR); + coldfire_imr_mod(dma_rec_lock.state, 1 << 15); } void pcm_rec_dma_start(void *addr, size_t size) @@ -382,7 +382,7 @@ void pcm_rec_dma_start(void *addr, size_t size) DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | DMA_DSIZE(DMA_SIZE_LINE) | DMA_START; - dma_rec_lock.state = (1 << 15); + dma_rec_lock.state = (0 << 15); } /* pcm_rec_dma_start */ void pcm_rec_dma_stop(void) @@ -395,7 +395,7 @@ void pcm_rec_dma_stop(void) iis_play_reset_if_playback(false); - dma_rec_lock.state = (0 << 15); + dma_rec_lock.state = (1 << 15); } /* pcm_rec_dma_stop */ void pcm_rec_dma_init(void) diff --git a/firmware/target/coldfire/system-coldfire.c b/firmware/target/coldfire/system-coldfire.c index 61a5da98cd..1fbd00825a 100644 --- a/firmware/target/coldfire/system-coldfire.c +++ b/firmware/target/coldfire/system-coldfire.c @@ -268,7 +268,7 @@ void system_init(void) will do. */ coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); - IMR = 0x3ffff; + coldfire_imr_mod(0x3ffff, 0x3ffff); INTPRI1 = 0; INTPRI2 = 0; INTPRI3 = 0; @@ -365,6 +365,16 @@ void coldfire_set_pllcr_audio_bits(long bits) PLLCR = (PLLCR & ~0x70400000) | (bits & 0x70400000); } +/* Safely modify the interrupt mask register as the core interrupt level is + required to be at least as high as the level interrupt being + masked/unmasked */ +void coldfire_imr_mod(unsigned long bits, unsigned long mask) +{ + unsigned long oldlevel = set_irq_level(DISABLE_INTERRUPTS); + IMR = (IMR & ~mask) | (bits & mask); + restore_irq(oldlevel); +} + /* Set DATAINCONTROL without disturbing FIFO reset state */ void coldfire_set_dataincontrol(unsigned long value) { diff --git a/firmware/target/coldfire/system-target.h b/firmware/target/coldfire/system-target.h index d1a2a1f115..3d7502a6dd 100644 --- a/firmware/target/coldfire/system-target.h +++ b/firmware/target/coldfire/system-target.h @@ -201,6 +201,11 @@ static inline uint32_t swap_odd_even32_hw(uint32_t value) #define DEFAULT_PLLCR_AUDIO_BITS 0x10400000 void coldfire_set_pllcr_audio_bits(long bits); +/* Safely modify the interrupt mask register as the core interrupt level is + required to be at least as high as the level interrupt being + masked/unmasked */ +void coldfire_imr_mod(unsigned long bits, unsigned long mask); + /* Set DATAINCONTROL without disturbing FIFO reset state */ void coldfire_set_dataincontrol(unsigned long value); diff --git a/firmware/target/coldfire/timer-coldfire.c b/firmware/target/coldfire/timer-coldfire.c index 49d22bb5fa..cc665cb9c6 100644 --- a/firmware/target/coldfire/timer-coldfire.c +++ b/firmware/target/coldfire/timer-coldfire.c @@ -89,7 +89,7 @@ bool timer_set(long cycles, bool start) bool timer_start(void) { ICR2 = 0x90; /* interrupt on level 4.0 */ - and_l(~(1<<10), &IMR); + coldfire_imr_mod(0, 1 << 10); TMR1 |= 1; /* start timer */ return true; } @@ -97,7 +97,7 @@ bool timer_start(void) void timer_stop(void) { TMR1 = 0; /* disable timer 1 */ - or_l((1<<10), &IMR); /* disable interrupt */ + coldfire_imr_mod(1 << 10, 1 << 10); /* disable interrupt */ } void timers_adjust_prescale(int multiplier, bool enable_irq) -- cgit v1.2.3