From 1490fbedbcf4c6c143a500d78adb1d1ee7a7f48c Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Tue, 24 Jul 2007 16:15:50 +0000 Subject: [PATCH] DMA works for input with buffered counting on e-series now. --- comedi/drivers/mite.c | 3 +- comedi/drivers/mite.h | 7 ++ comedi/drivers/ni_mio_common.c | 133 ++++++++++++++++++++++++++++++--- comedi/drivers/ni_tio.c | 104 ++++++++++++++++++-------- 4 files changed, 204 insertions(+), 43 deletions(-) diff --git a/comedi/drivers/mite.c b/comedi/drivers/mite.c index f2276fd8..6da64c8f 100644 --- a/comedi/drivers/mite.c +++ b/comedi/drivers/mite.c @@ -367,7 +367,8 @@ void mite_prep_dma(struct mite_channel *mite_chan, { /* Doing a combined 32 and 16 bit byteswap gets the 16 bit samples into the fifo in the right order. Tested doing 32 bit memory to 16 bit device transfers to the analog out of a pxi-6281, - which has mite version = 1, type = 4*/ + which has mite version = 1, type = 4. This also works for dma reads from the counters + on e-series boards. */ chcr |= CHCR_BYTE_SWAP_DEVICE | CHCR_BYTE_SWAP_MEMORY; } if(mite_chan->dir == COMEDI_INPUT){ diff --git a/comedi/drivers/mite.h b/comedi/drivers/mite.h index 0569f028..df9ff1c7 100644 --- a/comedi/drivers/mite.h +++ b/comedi/drivers/mite.h @@ -427,5 +427,12 @@ static inline void mite_dma_reset(struct mite_channel *mite_chan) writel(CHOR_DMARESET | CHOR_FRESET, mite_chan->mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); }; +static inline unsigned mite_get_status(struct mite_channel *mite_chan) +{ + struct mite_struct *mite = mite_chan->mite; + + return readl(mite->mite_io_addr + MITE_CHSR(mite_chan->channel)); +} + #endif diff --git a/comedi/drivers/ni_mio_common.c b/comedi/drivers/ni_mio_common.c index f7434fb6..de9c653f 100644 --- a/comedi/drivers/ni_mio_common.c +++ b/comedi/drivers/ni_mio_common.c @@ -284,8 +284,8 @@ static int ni_6143_pwm_config(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data); static int ni_set_master_clock(comedi_device *dev, unsigned source, unsigned period_ns); -static void ack_a_interrupt(comedi_device *dev, unsigned short a_status); -static void ack_b_interrupt(comedi_device *dev, unsigned short b_status); +static void ack_a_interrupt(comedi_device *dev, unsigned short a_status, unsigned short g_status); +static void ack_b_interrupt(comedi_device *dev, unsigned short b_status, unsigned short g_status); enum aimodes { @@ -505,6 +505,36 @@ void ni_release_gpct_mite_channel(comedi_device *dev, unsigned gpct_index) #endif // PCIDMA } +// e-series boards use the second irq signals to generate dma requests for their counters +static void ni_e_series_enable_second_irq(comedi_device *dev, unsigned gpct_index, short enable) +{ + if(boardtype.reg_type & ni_reg_m_series_mask) return; + switch(gpct_index) + { + case 0: + if(enable) + { + devpriv->stc_writew(dev, G0_Gate_Second_Irq_Enable, Second_IRQ_A_Enable_Register); + }else + { + devpriv->stc_writew(dev, 0, Second_IRQ_A_Enable_Register); + } + break; + case 1: + if(enable) + { + devpriv->stc_writew(dev, G1_Gate_Second_Irq_Enable, Second_IRQ_B_Enable_Register); + }else + { + devpriv->stc_writew(dev, 0, Second_IRQ_B_Enable_Register); + } + break; + default: + BUG(); + break; + } +} + static void ni_clear_ai_fifo(comedi_device *dev){ if(boardtype.reg_type == ni_reg_6143){ // Flush the 6143 data FIFO @@ -628,6 +658,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) unsigned short b_status; unsigned int ai_mite_status = 0; unsigned int ao_mite_status = 0; + unsigned g_status; unsigned long flags; struct mite_struct *mite = devpriv->mite; @@ -649,8 +680,9 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) ao_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ao_mite_chan->channel)); comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags_too); } - ack_a_interrupt(dev, a_status); - ack_b_interrupt(dev, b_status); + g_status = devpriv->stc_readw(dev, G_Status_Register); + ack_a_interrupt(dev, a_status, g_status); + ack_b_interrupt(dev, b_status, g_status); if((a_status & Interrupt_A_St) || (ai_mite_status & CHSR_INT)) handle_a_interrupt(dev, a_status, ai_mite_status); if((b_status & Interrupt_B_St) || (ao_mite_status & CHSR_INT)) @@ -826,7 +858,33 @@ static void handle_gpct_interrupt(comedi_device *dev, unsigned short counter_ind ni_event(dev, s, s->async->events); } -static void ack_a_interrupt(comedi_device *dev, unsigned short a_status) + /* During buffered input counter operation for e-series, the gate interrupt is acked + automatically by the dma controller, due to the Gi_Read/Write_Acknowledges_IRQ bits + in the input select register. */ +int should_ack_gate(comedi_device *dev, unsigned counter_index) +{ + unsigned long flags; + int retval = 0; + + if(boardtype.reg_type & ni_reg_m_series_mask) return 1; + + comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + { + struct mite_channel *mite_chan = devpriv->counter_dev->counters[counter_index].mite_chan; + + if(mite_chan == NULL || + mite_chan->dir != COMEDI_INPUT || + (mite_get_status(devpriv->counter_dev->counters[counter_index].mite_chan) & CHSR_DONE)) + { + retval = 1; + } + } + comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + + return retval; +} + +static void ack_a_interrupt(comedi_device *dev, unsigned short a_status, unsigned short g_status) { unsigned short ack = 0; @@ -853,7 +911,12 @@ static void ack_a_interrupt(comedi_device *dev, unsigned short a_status) } if(a_status & G0_Gate_Interrupt_St) { - ack |= G0_Gate_Interrupt_Ack; + if(should_ack_gate(dev, 0)) + ack |= G0_Gate_Interrupt_Ack; + } + if(g_status & G0_Gate_Error_St) + { + ack |= G0_Gate_Error_Confirm; } if(ack) devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register); } @@ -955,7 +1018,7 @@ static void handle_a_interrupt(comedi_device *dev, unsigned short status, #endif } -static void ack_b_interrupt(comedi_device *dev, unsigned short b_status) +static void ack_b_interrupt(comedi_device *dev, unsigned short b_status, unsigned short g_status) { unsigned short ack = 0; if(b_status & AO_BC_TC_St) @@ -988,7 +1051,12 @@ static void ack_b_interrupt(comedi_device *dev, unsigned short b_status) } if(b_status & G1_Gate_Interrupt_St) { - ack |= G1_Gate_Interrupt_Ack; + if(should_ack_gate(dev, 1)) + ack |= G1_Gate_Interrupt_Ack; + } + if(g_status & G1_Gate_Error_St) + { + ack |= G1_Gate_Error_Confirm; } if(b_status & G1_TC_St) { @@ -4424,6 +4492,46 @@ static inline unsigned Gi_Gate_Interrupt_Ack_Bit(unsigned counter_index) return bit; } +static inline unsigned Gi_Gate_Error_Confirm_Bit(unsigned counter_index) +{ + unsigned bit; + + switch(counter_index) + { + case 0: + bit = G0_Gate_Error_Confirm; + break; + case 1: + bit = G1_Gate_Error_Confirm; + break; + default: + BUG(); + return 0; + break; + } + return bit; +} + +static inline unsigned Gi_TC_Error_Confirm_Bit(unsigned counter_index) +{ + unsigned bit; + + switch(counter_index) + { + case 0: + bit = G0_TC_Error_Confirm; + break; + case 1: + bit = G1_TC_Error_Confirm; + break; + default: + BUG(); + return 0; + break; + } + return bit; +} + static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s) { int retval; @@ -4438,13 +4546,16 @@ static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s) comedi_error(dev, "no dma channel available for use by counter"); return retval; } + devpriv->stc_writew(dev, Gi_Gate_Interrupt_Ack_Bit(counter->counter_index) | + Gi_Gate_Error_Confirm_Bit(counter->counter_index) | + Gi_TC_Error_Confirm_Bit(counter->counter_index), + Gi_Interrupt_Ack_Register(counter->counter_index)); if(cmd->flags & TRIG_WAKE_EOS) { - devpriv->stc_writew(dev, Gi_Gate_Interrupt_Ack_Bit(counter->counter_index), - Gi_Interrupt_Ack_Register(counter->counter_index)); ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index), Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 1); } + ni_e_series_enable_second_irq(dev, counter->counter_index, 1); comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); retval = ni_tio_cmd(counter, s->async); @@ -4471,6 +4582,8 @@ static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s) comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); retval = ni_tio_cancel(counter); comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + + ni_e_series_enable_second_irq(dev, counter->counter_index, 0); ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index), Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 0); ni_release_gpct_mite_channel(dev, counter->counter_index); diff --git a/comedi/drivers/ni_tio.c b/comedi/drivers/ni_tio.c index 871fba87..4da555e8 100644 --- a/comedi/drivers/ni_tio.c +++ b/comedi/drivers/ni_tio.c @@ -597,6 +597,8 @@ static inline unsigned NI_M_Series_PFI_Gate_Select(unsigned n) #define Gi_Gate_Select_Shift 7 enum Gi_Input_Select_Bits { + Gi_Read_Acknowledges_Irq = 0x1, // e-series only + Gi_Write_Acknowledges_Irq = 0x2, // e-series only Gi_Source_Select_Mask = 0x7c, Gi_Gate_Select_Mask = 0x1f << Gi_Gate_Select_Shift, Gi_Gate_Select_Load_Source_Bit = 0x1000, @@ -2124,6 +2126,60 @@ int ni_tio_winsn(struct ni_gpct *counter, return 0; } +static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, short read_not_write) +{ + struct ni_gpct_device *counter_dev = counter->counter_dev; + + switch(counter_dev->variant) + { + case ni_gpct_variant_e_series: + { + const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index); + if(enable) + { + if(read_not_write) + { + counter_dev->regs[input_select_reg] |= Gi_Read_Acknowledges_Irq; + counter_dev->regs[input_select_reg] &= ~Gi_Write_Acknowledges_Irq; + }else + { + counter_dev->regs[input_select_reg] &= ~Gi_Read_Acknowledges_Irq; + counter_dev->regs[input_select_reg] |= Gi_Write_Acknowledges_Irq; + } + }else + { + counter_dev->regs[input_select_reg] &= ~(Gi_Read_Acknowledges_Irq | Gi_Write_Acknowledges_Irq); + } + counter_dev->write_register(counter, counter_dev->regs[input_select_reg], input_select_reg); + } + break; + case ni_gpct_variant_m_series: + case ni_gpct_variant_660x: + { + const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index); + + if(enable) + { + counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Enable_Bit; + counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Int_Bit; + }else + { + counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Enable_Bit; + counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Int_Bit; + } + if(read_not_write) + { + counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Write_Bit; + }else + { + counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Write_Bit; + } + counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg); + } + break; + } +} + static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async *async) { struct ni_gpct_device *counter_dev = counter->counter_dev; @@ -2133,40 +2189,34 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async *async) /* write alloc the entire buffer */ comedi_buf_write_alloc(async, async->prealloc_bufsz); counter->mite_chan->dir = COMEDI_INPUT; - mite_prep_dma(counter->mite_chan, 32, 32); - counter_dev->regs[command_reg] &= ~Gi_Save_Trace_Bit; - counter_dev->write_register(counter, counter_dev->regs[command_reg], command_reg); - if(counter_dev->variant == ni_gpct_variant_m_series || - counter_dev->variant == ni_gpct_variant_660x) + switch(counter_dev->variant) { - const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index); - - counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Enable_Bit; - counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Write_Bit; - counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Int_Bit; - counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg); + case ni_gpct_variant_m_series: + case ni_gpct_variant_660x: + mite_prep_dma(counter->mite_chan, 32, 32); + break; + case ni_gpct_variant_e_series: + mite_prep_dma(counter->mite_chan, 16, 32); + break; + default: + BUG(); + break; } + counter_dev->regs[command_reg] &= ~Gi_Save_Trace_Bit; + counter_dev->write_register(counter, counter_dev->regs[command_reg], command_reg); + ni_tio_configure_dma(counter, 1, 1); mite_dma_arm(counter->mite_chan); return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); } static int ni_tio_output_cmd(struct ni_gpct *counter, comedi_async *async) { - struct ni_gpct_device *counter_dev = counter->counter_dev; - rt_printk("ni_tio: output commands not yet implemented.\n"); return -ENOTSUPP; counter->mite_chan->dir = COMEDI_OUTPUT; mite_prep_dma(counter->mite_chan, 32, 32); - if(counter_dev->variant == ni_gpct_variant_m_series || - counter_dev->variant == ni_gpct_variant_660x) - { - const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index); - - counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Enable_Bit | Gi_DMA_Write_Bit; - counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg); - } + ni_tio_configure_dma(counter, 1, 0); mite_dma_arm(counter->mite_chan); return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); } @@ -2200,22 +2250,12 @@ int ni_tio_cmdtest(struct ni_gpct *counter) int ni_tio_cancel(struct ni_gpct *counter) { - struct ni_gpct_device *counter_dev = counter->counter_dev; - ni_tio_arm(counter, 0, 0); - if(counter_dev->variant == ni_gpct_variant_m_series || - counter_dev->variant == ni_gpct_variant_660x) - { - const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index); - - counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Enable_Bit; - counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Int_Bit; - counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg); - } if(counter->mite_chan) { mite_dma_disarm(counter->mite_chan); } + ni_tio_configure_dma(counter, 0, 0); return 0; } -- 2.26.2