cxd56: Fix lock issue in Spresense audio driver

Replace semaphore with spinlock in the DMA buffer handling code
since it is called from an interrupt.
This commit is contained in:
Tobias Johansson 2020-06-04 13:37:29 +02:00 committed by Xiang Xiao
parent 36ae29c21c
commit 368fbd0dea
1 changed files with 11 additions and 22 deletions

View File

@ -430,8 +430,6 @@ static void cxd56_set_mic_gains(uint8_t gain,
static void cxd56_set_mic_out_channel(FAR struct cxd56_dev_s *dev);
static int cxd56_set_volume(enum cxd56_vol_id_e id, int16_t vol);
static void cxd56_swap_buffer_rl(uint32_t addr, uint16_t size);
static int cxd56_take_sem(sem_t *sem);
#define cxd56_give_sem(s) (nxsem_post(s))
static void *cxd56_workerthread(pthread_addr_t pvarg);
/****************************************************************************
@ -1097,20 +1095,6 @@ static void write_reg_addr(const cxd56_aureg_t *reg, uint32_t val)
#define write_reg(reg, val) (write_reg_addr(&(reg), (val)))
#define write_reg32(reg, val) (*((volatile uint32_t *)(reg).addr) = (val))
/****************************************************************************
* Name: cxd56_take_sem
*
* Description:
* Take a semaphore count, handling the nasty EINTR return if we are
* interrupted by a signal.
*
****************************************************************************/
static int cxd56_take_sem(sem_t *sem)
{
return nxsem_wait_uninterruptible(sem);
}
static void cxd56_int_clear(cxd56_dmahandle_t handle, uint8_t intbits)
{
if (handle == CXD56_AUDIO_DMA_MIC)
@ -1383,13 +1367,14 @@ static void cxd56_dma_int_handler(void)
{
struct audio_msg_s msg;
struct cxd56_dev_s *dev;
irqstate_t flags;
int ret;
dev = g_dev[hdl];
/* Trigger new DMA job */
cxd56_take_sem(&dev->pendsem);
flags = spin_lock_irqsave();
if (dq_count(&dev->runningq) > 0)
{
@ -1399,7 +1384,7 @@ static void cxd56_dma_int_handler(void)
dev->dev.upper(dev->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
}
cxd56_give_sem(&dev->pendsem);
spin_unlock_irqrestore(flags);
if (err_code == CXD56_AUDIO_ECODE_DMA_TRANS)
{
@ -3067,13 +3052,14 @@ static void cxd56_swap_buffer_rl(uint32_t addr, uint16_t size)
static int cxd56_start_dma(FAR struct cxd56_dev_s *dev)
{
FAR struct ap_buffer_s *apb;
irqstate_t flags;
int retry;
int timeout;
uint32_t addr;
uint32_t size;
int ret = OK;
cxd56_take_sem(&dev->pendsem);
flags = spin_lock_irqsave();
if (dq_count(&dev->pendingq) == 0)
{
/* Pending queue empty, nothing to do */
@ -3242,7 +3228,7 @@ static int cxd56_start_dma(FAR struct cxd56_dev_s *dev)
}
exit:
cxd56_give_sem(&dev->pendsem);
spin_unlock_irqrestore(flags);
return ret;
}
@ -3259,11 +3245,14 @@ static int cxd56_enqueuebuffer(FAR struct audio_lowerhalf_s *lower,
{
FAR struct cxd56_dev_s *priv = (FAR struct cxd56_dev_s *)lower;
struct audio_msg_s msg;
irqstate_t flags;
flags = spin_lock_irqsave();
cxd56_take_sem(&priv->pendsem);
apb->dq_entry.flink = NULL;
dq_put(&priv->pendingq, &apb->dq_entry);
cxd56_give_sem(&priv->pendsem);
spin_unlock_irqrestore(flags);
if (priv->mq != NULL)
{