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) ...@@ -162,9 +162,8 @@ static inline struct fmctdc_trig *to_fmctdc_trig(struct zio_ti *ti_ptr)
/* /*
* Main TDC device context * Main TDC device context
* @unique_id unique identifier from the temperature sensor * @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) * 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 * @dma_chan_mask: bitmask to keep track of which channels are
* transferring data. Timestamp interrupts are disabled * transferring data. Timestamp interrupts are disabled
* while DMA is running and we touch and this is the only * while DMA is running and we touch and this is the only
...@@ -203,7 +202,6 @@ struct fmctdc_dev { ...@@ -203,7 +202,6 @@ struct fmctdc_dev {
struct ft_channel_state channels[FT_NUM_CHANNELS]; struct ft_channel_state channels[FT_NUM_CHANNELS];
int wr_mode; int wr_mode;
uint32_t irq_imr;
struct work_struct ts_work; struct work_struct ts_work;
struct zio_dma_sgt *zdma; 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_ ...@@ -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 * @ft FmcTdc device instance
* @chan_mask channel bitmask, a bit to one will disable the corresponding * @mask interrupt mask (1 = disable)
* IRQ channel line
*/ */
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, mask, ft->ft_irq_base + TDC_EIC_REG_EIC_IDR);
ft_iowrite(ft, ft->irq_imr, 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 * @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) ...@@ -296,15 +295,12 @@ static void ft_dma_work(struct work_struct *work)
if (!spin_trylock(&ft->dma_lock)) if (!spin_trylock(&ft->dma_lock))
{ {
printk("dma already in progress\n"); ft_eic_irq_enable(ft, TDC_EIC_EIC_IMR_TDC_DMA_MASK);
ft_irq_enable_restore(ft);
return; return;
} }
irq_stat = ft_ioread(ft, ft->ft_irq_base + TDC_EIC_REG_EIC_ISR); 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_MASK;
irq_stat >>= TDC_EIC_EIC_IMR_TDC_DMA_SHIFT; irq_stat >>= TDC_EIC_EIC_IMR_TDC_DMA_SHIFT;
ft->dma_chan_mask = irq_stat; ft->dma_chan_mask = irq_stat;
...@@ -350,6 +346,7 @@ static void ft_dma_work(struct work_struct *work) ...@@ -350,6 +346,7 @@ static void ft_dma_work(struct work_struct *work)
sizeof(struct gncore_dma_item) * ft->zdma->sgt.nents, sizeof(struct gncore_dma_item) * ft->zdma->sgt.nents,
DMA_TO_DEVICE); DMA_TO_DEVICE);
gn4124_dma_start(ft); gn4124_dma_start(ft);
ft_eic_irq_enable(ft, TDC_EIC_EIC_IMR_TDC_DMA_MASK);
return; return;
err_map: err_map:
...@@ -363,7 +360,7 @@ err_alloc: ...@@ -363,7 +360,7 @@ err_alloc:
} }
spin_unlock(&ft->dma_lock); 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: ...@@ -446,7 +443,7 @@ irq:
goto irq; goto irq;
/* Re-Enable interrupts that where disabled in the IRQ handler */ /* 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; return;
} }
...@@ -512,7 +509,7 @@ out: ...@@ -512,7 +509,7 @@ out:
spin_unlock(&ft->dma_lock); spin_unlock(&ft->dma_lock);
/* Re-Enable interrupts that were disabled in the IRQ handler */ /* 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; return IRQ_HANDLED;
} }
...@@ -529,7 +526,7 @@ static irqreturn_t ft_irq_handler_ts(int irq, void *dev_id) ...@@ -529,7 +526,7 @@ static irqreturn_t ft_irq_handler_ts(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
/* Disable interrupts until we fetch all stored samples */ /* 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); 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