Module: xenomai-2.5
Branch: master
Commit: 07bae25974ad76d29a427b195c6b7de1c0d30c63
URL:    
http://git.xenomai.org/?p=xenomai-2.5.git;a=commit;h=07bae25974ad76d29a427b195c6b7de1c0d30c63

Author: Alexis Berlemont <alexis.berlem...@gmail.com>
Date:   Mon Mar  1 01:08:28 2010 +0100

analogy: [pcimio] fix many race conditions in DMA output transfers

WARNING: Some parts of the driver mio_common cannot be tolerated in a
real-time system. For example, the function ni_ao_wait_for_dma_load
must be reviewed; it contains two busy waiting loops which can last up
to 10000 micro-seconds.

---

 .../analogy/national_instruments/mio_common.c      |   98 +++++++++++--------
 ksrc/drivers/analogy/national_instruments/mite.c   |   17 +++-
 2 files changed, 72 insertions(+), 43 deletions(-)

diff --git a/ksrc/drivers/analogy/national_instruments/mio_common.c 
b/ksrc/drivers/analogy/national_instruments/mio_common.c
index db9762a..1a39206 100644
--- a/ksrc/drivers/analogy/national_instruments/mio_common.c
+++ b/ksrc/drivers/analogy/national_instruments/mio_common.c
@@ -506,17 +506,28 @@ void mite_handle_b_linkc(a4l_subd_t *subd)
        a4l_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 }
 
-static int ni_ao_wait_for_dma_load(a4l_dev_t *dev)
+static int ni_ao_wait_for_dma_load(a4l_subd_t *subd)
 {
        static const int timeout = 10000;
+
+       a4l_dev_t *dev = subd->dev;
+       a4l_buf_t *buf = dev->transfer.bufs[subd->idx];
+
        int i;
 
        for (i = 0; i < timeout; i++) {
+               
+               int buffer_filled;
                unsigned short b_status;
 
                b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
-               if (b_status & AO_FIFO_Half_Full_St)
+
+               buffer_filled = test_bit(A4L_BUF_EOA_NR, &buf->evt_flags);
+               buffer_filled |= (b_status & AO_FIFO_Half_Full_St);
+
+               if (buffer_filled)
                        break;
+
                /* If we poll too often, the pci bus activity seems
                   to slow the dma transfer down */
                a4l_udelay(10);
@@ -569,7 +580,7 @@ static inline int ni_request_cdo_mite_channel(a4l_dev_t 
*dev)
 #define ni_sync_ai_dma(x) do { } while (0)
 #define mite_handle_b_linkc(x) do { } while (0)
 
-static inline int ni_ao_wait_for_dma_load(a4l_dev_t *dev)
+static inline int ni_ao_wait_for_dma_load(a4l_subd_t *subd)
 {
        return -ENOTSUPP;
 }
@@ -714,14 +725,12 @@ static void ni_handle_eos(a4l_subd_t *subd)
 }
 
 static void ni_event(a4l_subd_t * subd)
-{
-               
+{              
        /* Temporary hack */
        a4l_dev_t *dev = subd->dev;
        a4l_buf_t *buf = dev->transfer.bufs[subd->idx];
 
-       if(test_bit(A4L_BUF_ERROR, &buf->evt_flags)) {
-
+       if(test_bit(A4L_BUF_ERROR_NR, &buf->evt_flags)) {
                if (subd->cancel != NULL)
                        subd->cancel(subd);
        }
@@ -939,28 +948,15 @@ static void handle_b_interrupt(a4l_dev_t * dev,
 
        a4l_subd_t *subd = a4l_get_subd(dev, NI_AO_SUBDEV);
 
-       a4l_info(dev, "ni_mio_common: interrupt: b_status=%04x 
m1_status=%08x\n",
-                b_status, ao_mite_status);
-       ni_mio_print_status_b(b_status);
-
-#if (defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE) || \
-     defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE_MODULE))
-       /* Currently, mite.c requires us to handle LINKC */
-       if (ao_mite_status & CHSR_LINKC) {
-               mite_handle_b_linkc(subd);
-       }
+       a4l_dbg(1, drv_dbg, dev, 
+               "ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n",
+               b_status, ao_mite_status);
 
-       if (ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY |
-                              CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR |
-                              CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)) {
-               a4l_info(dev, "unknown mite interrupt, ack! 
(ao_mite_status=%08x)\n",
-                        ao_mite_status);
-               a4l_buf_evt(subd, A4L_BUF_ERROR);
-       }
-#endif /* CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE */
+       ni_mio_print_status_b(b_status);
 
        if (b_status == 0xffff)
                return;
+
        if (b_status & AO_Overrun_St) {
                a4l_err(dev,
                        "ni_mio_common: interrupt: "
@@ -971,15 +967,38 @@ static void handle_b_interrupt(a4l_dev_t * dev,
        }
 
        if (b_status & AO_BC_TC_St) {
-               a4l_info(dev,
-                        "ni_mio_common: interrupt: "
-                        "AO BC_TC status=0x%04x status2=0x%04x\n", 
-                        b_status, devpriv->stc_readw(dev, 
AO_Status_2_Register));
+               a4l_dbg(1, drv_dbg, dev,
+                       "ni_mio_common: interrupt: "
+                       "AO BC_TC status=0x%04x status2=0x%04x\n", 
+                       b_status, devpriv->stc_readw(dev, 
AO_Status_2_Register));
                a4l_buf_evt(subd, A4L_BUF_EOA);
        }
 
+#if (defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE) || \
+     defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE_MODULE))
+
+       if (ao_mite_status & CHSR_STOPS) {
+               a4l_dbg(1, drv_dbg, dev,
+                       "ni_mio_common: interrupt: MITE transfer stopped\n");
+       } else if (ao_mite_status & CHSR_LINKC) {
+               /* Currently, mite.c requires us to handle LINKC */
+               mite_handle_b_linkc(subd);
+       }
+
+       if (ao_mite_status & 
+           ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY |
+             CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR |
+             CHSR_SABORT | CHSR_STOPS | CHSR_XFERR | CHSR_LxERR_mask)) {
+               a4l_err(dev, 
+                       "unknown mite interrupt, ack! (ao_mite_status=%08x)\n",
+                        ao_mite_status);
+               a4l_buf_evt(subd, A4L_BUF_ERROR);
+       }
+#endif /* CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE */
+
 #if (!defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE) && \
      !defined(CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE_MODULE))
+
        if (b_status & AO_FIFO_Request_St) {
                int ret;
 
@@ -2813,9 +2832,6 @@ int ni_ao_inttrig(a4l_subd_t *subd, lsampl_t trignum)
        if (trignum != 0)
                return -EINVAL;
 
-       /* TODO: ni_ao_inttrig should allow the retrieval of the
-          subdevice index */
-
        /* TODO: disable trigger until a command is recorded.
           Null trig at beginning prevent ao start trigger from executing
           more than once per command (and doing things like trying to
@@ -2833,7 +2849,7 @@ int ni_ao_inttrig(a4l_subd_t *subd, lsampl_t trignum)
        ret = ni_ao_setup_MITE_dma(dev);
        if (ret)
                return ret;
-       ret = ni_ao_wait_for_dma_load(dev);
+       ret = ni_ao_wait_for_dma_load(subd);
        if (ret < 0)
                return ret;
 #else /* !CONFIG_XENO_DRIVERS_ANALOGY_NI_MITE */
@@ -2850,8 +2866,7 @@ int ni_ao_inttrig(a4l_subd_t *subd, lsampl_t trignum)
        /* wait for DACs to be loaded */
        for (i = 0; i < timeout; i++) {
                a4l_udelay(1);
-               if ((devpriv->stc_readw(dev,
-                                       Joint_Status_2_Register) &
+               if ((devpriv->stc_readw(dev,Joint_Status_2_Register) &
                     AO_TMRDACWRs_In_Progress_St) == 0)
                        break;
        }
@@ -2869,12 +2884,14 @@ int ni_ao_inttrig(a4l_subd_t *subd, lsampl_t trignum)
        ni_set_bits(dev, Interrupt_B_Enable_Register, interrupt_b_bits, 1);
 
        devpriv->stc_writew(dev,
-                           devpriv->
-                           ao_cmd1 | AO_UI_Arm | AO_UC_Arm | AO_BC_Arm |
-                           AO_DAC1_Update_Mode | AO_DAC0_Update_Mode,
+                           devpriv->ao_cmd1 | 
+                           AO_UI_Arm | AO_UC_Arm | 
+                           AO_BC_Arm | AO_DAC1_Update_Mode | 
+                           AO_DAC0_Update_Mode,
                            AO_Command_1_Register);
 
-       devpriv->stc_writew(dev, devpriv->ao_cmd2 | AO_START1_Pulse,
+       devpriv->stc_writew(dev, 
+                           devpriv->ao_cmd2 | AO_START1_Pulse,
                            AO_Command_2_Register);
 
        return 0;
@@ -2992,8 +3009,7 @@ int ni_ao_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd)
                if (cmd->scan_end_arg > 1) {
                        devpriv->ao_mode1 |= AO_Multiple_Channels;
                        devpriv->stc_writew(dev,
-                                           
AO_Number_Of_Channels(cmd->scan_end_arg -
-                                                                 1) |
+                                           
AO_Number_Of_Channels(cmd->scan_end_arg - 1) |
                                            AO_UPDATE_Output_Select
                                            (AO_Update_Output_High_Z),
                                            AO_Output_Control_Register);
diff --git a/ksrc/drivers/analogy/national_instruments/mite.c 
b/ksrc/drivers/analogy/national_instruments/mite.c
index 4245b21..d1a7813 100644
--- a/ksrc/drivers/analogy/national_instruments/mite.c
+++ b/ksrc/drivers/analogy/national_instruments/mite.c
@@ -587,17 +587,30 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, 
a4l_subd_t *subd)
 
 int mite_sync_output_dma(struct mite_channel *mite_chan, a4l_subd_t *subd)
 {
+       a4l_dev_t *dev = subd->dev;
+       a4l_buf_t *buf = dev->transfer.bufs[subd->idx];
+       int err;
        unsigned int nbytes_ub, nbytes_lb;
 
        nbytes_lb = mite_bytes_read_from_memory_lb(mite_chan);
        nbytes_ub = mite_bytes_read_from_memory_ub(mite_chan);
 
-       if(a4l_buf_prepare_absget(subd, nbytes_ub) != 0) {
+       err = a4l_buf_prepare_absget(subd, nbytes_ub);
+       if(err < 0) {
                __a4l_info("MITE: DMA underrun\n");
                return -EPIPE;
        }
 
-       return a4l_buf_commit_absget(subd, nbytes_lb);
+       err = a4l_buf_commit_absget(subd, nbytes_lb);
+
+       /* If the MITE has already transfered more than required, we
+          can disable it */
+       if (test_bit(A4L_BUF_EOA_NR, &buf->evt_flags))
+               writel(CHOR_STOP, 
+                      mite_chan->mite->mite_io_addr + 
+                      MITE_CHOR(mite_chan->channel));
+
+       return err;
 }
 
 u32 mite_get_status(struct mite_channel *mite_chan)


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to