Commit 46da0f54 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

kernel: fixed another race condition (totally disabling IRQs when…

kernel: fixed another race condition (totally disabling IRQs when ft_irq_disable_save() was called twice in a row)
parent f1fb504e
......@@ -162,9 +162,8 @@ static inline struct fmctdc_trig *to_fmctdc_trig(struct zio_ti *ti_ptr)
/*
* Main TDC device context
* @unique_id unique identifier from the temperature sensor
* @lock it protects: irq_imr (irq vs user), offset (user vs user),
* @lock it protects: offset (user vs user),
* wr_mode (user vs user)
* @irq_imr it holds the IMR value since our last modification
* @dma_chan_mask: bitmask to keep track of which channels are
* transferring data. Timestamp interrupts are disabled
* while DMA is running and we touch and this is the only
......@@ -203,7 +202,6 @@ struct fmctdc_dev {
struct ft_channel_state channels[FT_NUM_CHANNELS];
int wr_mode;
uint32_t irq_imr;
struct work_struct ts_work;
struct zio_dma_sgt *zdma;
......
......@@ -124,24 +124,23 @@ static inline uint32_t ft_chan_to_irq_mask(struct fmctdc_dev *ft, uint32_t chan_
}
/**
* It disbles interrupts on specific channels according to the given mask
* It disables selected EIC interrupts
* @ft FmcTdc device instance
* @chan_mask channel bitmask, a bit to one will disable the corresponding
* IRQ channel line
* @mask interrupt mask (1 = disable)
*/
static void ft_irq_disable_save(struct fmctdc_dev *ft)
static void ft_eic_irq_disable(struct fmctdc_dev *ft, uint32_t mask)
{
ft->irq_imr = ft_ioread(ft, ft->ft_irq_base + TDC_EIC_REG_EIC_IMR);
ft_iowrite(ft, ft->irq_imr, ft->ft_irq_base + TDC_EIC_REG_EIC_IDR);
ft_iowrite(ft, mask, ft->ft_irq_base + TDC_EIC_REG_EIC_IDR);
}
/**
* It restores the previous known IRQ status
* It enables selected EIC interrupts
* @ft FmcTdc device instance
* @mask interrupt mask (1 = enable)
*/
static void ft_irq_enable_restore(struct fmctdc_dev *ft)
static void ft_eic_irq_enable(struct fmctdc_dev *ft, uint32_t mask)
{
ft_iowrite(ft, ft->irq_imr, ft->ft_irq_base + TDC_EIC_REG_EIC_IER);
ft_iowrite(ft, mask, ft->ft_irq_base + TDC_EIC_REG_EIC_IER);
}
......@@ -296,15 +295,12 @@ static void ft_dma_work(struct work_struct *work)
if (!spin_trylock(&ft->dma_lock))
{
printk("dma already in progress\n");
ft_irq_enable_restore(ft);
ft_eic_irq_enable(ft, TDC_EIC_EIC_IMR_TDC_DMA_MASK);
return;
}
irq_stat = ft_ioread(ft, ft->ft_irq_base + TDC_EIC_REG_EIC_ISR);
printk("dma read %x\n", irq_stat);
irq_stat &= TDC_EIC_EIC_IMR_TDC_DMA_MASK;
irq_stat >>= TDC_EIC_EIC_IMR_TDC_DMA_SHIFT;
ft->dma_chan_mask = irq_stat;
......@@ -350,6 +346,7 @@ static void ft_dma_work(struct work_struct *work)
sizeof(struct gncore_dma_item) * ft->zdma->sgt.nents,
DMA_TO_DEVICE);
gn4124_dma_start(ft);
ft_eic_irq_enable(ft, TDC_EIC_EIC_IMR_TDC_DMA_MASK);
return;
err_map:
......@@ -363,7 +360,7 @@ err_alloc:
}
spin_unlock(&ft->dma_lock);
ft_irq_enable_restore(ft);
ft_eic_irq_enable(ft, TDC_EIC_EIC_IMR_TDC_DMA_MASK);
}
/**
......@@ -446,7 +443,7 @@ irq:
goto irq;
/* Re-Enable interrupts that where disabled in the IRQ handler */
ft_irq_enable_restore(ft);
ft_eic_irq_enable(ft, TDC_EIC_EIC_IMR_TDC_FIFO_MASK );
return;
}
......@@ -512,7 +509,7 @@ out:
spin_unlock(&ft->dma_lock);
/* Re-Enable interrupts that were disabled in the IRQ handler */
ft_irq_enable_restore(ft);
ft_eic_irq_enable(ft, TDC_EIC_EIC_IMR_TDC_DMA_MASK);
return IRQ_HANDLED;
}
......@@ -529,7 +526,7 @@ static irqreturn_t ft_irq_handler_ts(int irq, void *dev_id)
return IRQ_NONE;
/* Disable interrupts until we fetch all stored samples */
ft_irq_disable_save(ft);
ft_eic_irq_disable(ft, ~0);
queue_work(ft_workqueue, &ft->ts_work);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment