mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 05:05:20 -05:00
Gigabeat S/i.MX31: Take care of an interrupt priority inversion that can happen during PCM callback lockout when DVFS switches frequecies during the lockout, preventing a thread from unlocking the callback until DVFS finishes, causing an SSI FIFO underrun. Hadn't thought of an acceptable way to deal with it before.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28996 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
2093bb021f
commit
9d97ee1b54
6 changed files with 63 additions and 14 deletions
|
|
@ -67,6 +67,11 @@ void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype);
|
||||||
#define AVIC_NIL_ENABLE (-1)
|
#define AVIC_NIL_ENABLE (-1)
|
||||||
void avic_set_ni_level(int level);
|
void avic_set_ni_level(int level);
|
||||||
|
|
||||||
|
static inline void avic_mask_int(enum IMX31_INT_LIST ints)
|
||||||
|
{ AVIC_INTDISNUM = ints; }
|
||||||
|
|
||||||
|
static inline void avic_unmask_int(enum IMX31_INT_LIST ints)
|
||||||
|
{ AVIC_INTENNUM = ints; }
|
||||||
|
|
||||||
/* Call a service routine while allowing preemption by interrupts of higher
|
/* Call a service routine while allowing preemption by interrupts of higher
|
||||||
* priority. Avoid using any app or other SVC stack by doing it with a mini
|
* priority. Avoid using any app or other SVC stack by doing it with a mini
|
||||||
|
|
|
||||||
|
|
@ -612,6 +612,22 @@ void dvfs_dptc_stop(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Mask the DVFS interrupt without affecting running status */
|
||||||
|
void dvfs_int_mask(bool mask)
|
||||||
|
{
|
||||||
|
if (mask)
|
||||||
|
{
|
||||||
|
/* Just disable, not running = already disabled */
|
||||||
|
avic_mask_int(INT_CCM_DVFS);
|
||||||
|
}
|
||||||
|
else if (dvfs_running)
|
||||||
|
{
|
||||||
|
/* DVFS is running; unmask it */
|
||||||
|
avic_unmask_int(INT_CCM_DVFS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set a signal load tracking weight */
|
/* Set a signal load tracking weight */
|
||||||
void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value)
|
void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ void dvfs_wfi_monitor(bool on);
|
||||||
void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value);
|
void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value);
|
||||||
void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge);
|
void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge);
|
||||||
void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert);
|
void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert);
|
||||||
|
void dvfs_int_mask(bool mask);
|
||||||
|
|
||||||
unsigned int dvfs_dptc_get_voltage(void);
|
unsigned int dvfs_dptc_get_voltage(void);
|
||||||
unsigned int dvfs_get_level(void);
|
unsigned int dvfs_get_level(void);
|
||||||
|
|
|
||||||
|
|
@ -85,3 +85,8 @@ void tick_stop(void)
|
||||||
ccm_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */
|
ccm_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void kernel_audio_locking(bool locking)
|
||||||
|
{
|
||||||
|
dvfs_int_mask(locking);
|
||||||
|
}
|
||||||
|
|
@ -109,12 +109,22 @@ static void play_dma_callback(void)
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
void pcm_play_lock(void)
|
||||||
{
|
{
|
||||||
|
/* Need to prevent DVFS from causing interrupt priority inversion if audio
|
||||||
|
* is locked and a DVFS interrupt fires, blocking reenabling of audio by a
|
||||||
|
* low-priority mode for at least the duration of the lengthy DVFS routine.
|
||||||
|
* Not really an issue with state changes but lockout when playing.
|
||||||
|
*
|
||||||
|
* Keep direct use of DVFS code away from here though. This could provide
|
||||||
|
* more services in the future anyway. */
|
||||||
|
kernel_audio_locking(true);
|
||||||
++dma_play_data.locked;
|
++dma_play_data.locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
void pcm_play_unlock(void)
|
||||||
{
|
{
|
||||||
if (--dma_play_data.locked == 0 && dma_play_data.state != 0)
|
if (--dma_play_data.locked == 0)
|
||||||
|
{
|
||||||
|
if (dma_play_data.state != 0)
|
||||||
{
|
{
|
||||||
int oldstatus = disable_irq_save();
|
int oldstatus = disable_irq_save();
|
||||||
int pending = dma_play_data.callback_pending;
|
int pending = dma_play_data.callback_pending;
|
||||||
|
|
@ -124,6 +134,9 @@ void pcm_play_unlock(void)
|
||||||
if (pending != 0)
|
if (pending != 0)
|
||||||
play_dma_callback();
|
play_dma_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kernel_audio_locking(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
void pcm_dma_apply_settings(void)
|
||||||
|
|
@ -442,12 +455,15 @@ static void rec_dma_callback(void)
|
||||||
|
|
||||||
void pcm_rec_lock(void)
|
void pcm_rec_lock(void)
|
||||||
{
|
{
|
||||||
|
kernel_audio_locking(true);
|
||||||
++dma_rec_data.locked;
|
++dma_rec_data.locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_rec_unlock(void)
|
void pcm_rec_unlock(void)
|
||||||
{
|
{
|
||||||
if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
|
if (--dma_rec_data.locked == 0)
|
||||||
|
{
|
||||||
|
if (dma_rec_data.state != 0)
|
||||||
{
|
{
|
||||||
int oldstatus = disable_irq_save();
|
int oldstatus = disable_irq_save();
|
||||||
int pending = dma_rec_data.callback_pending;
|
int pending = dma_rec_data.callback_pending;
|
||||||
|
|
@ -457,6 +473,9 @@ void pcm_rec_unlock(void)
|
||||||
if (pending != 0)
|
if (pending != 0)
|
||||||
rec_dma_callback();
|
rec_dma_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kernel_audio_locking(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_rec_dma_stop(void)
|
void pcm_rec_dma_stop(void)
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ void tick_stop(void);
|
||||||
void kernel_device_init(void);
|
void kernel_device_init(void);
|
||||||
void system_halt(void);
|
void system_halt(void);
|
||||||
|
|
||||||
|
/* Handle some audio lockout related tasks */
|
||||||
|
void kernel_audio_locking(bool locking);
|
||||||
|
|
||||||
#define KDEV_INIT
|
#define KDEV_INIT
|
||||||
|
|
||||||
struct ARM_REGS {
|
struct ARM_REGS {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue