Blackfin SPI Driver: add timeout while waiting for SPIF in dma irq handler
[safe/jmp/linux-2.6] / drivers / spi / spi_bfin5xx.c
index 5ebb67b..e706de1 100644 (file)
@@ -198,8 +198,6 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
                udelay(chip->cs_chg_udelay);
 }
 
-#define MAX_SPI_SSEL   7
-
 /* stop controller and re-config current chip*/
 static void restore_state(struct driver_data *drv_data)
 {
@@ -559,6 +557,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
        struct driver_data *drv_data = dev_id;
        struct chip_data *chip = drv_data->cur_chip;
        struct spi_message *msg = drv_data->cur_msg;
+       unsigned long timeout;
        unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel);
        u16 spistat = read_STAT(drv_data);
 
@@ -584,8 +583,17 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
                        cpu_relax();
        }
 
+       dev_dbg(&drv_data->pdev->dev,
+               "in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
+               dmastat, read_STAT(drv_data));
+
+       timeout = jiffies + HZ;
        while (!(read_STAT(drv_data) & SPIF))
-               cpu_relax();
+               if (!time_before(jiffies, timeout)) {
+                       dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF");
+                       break;
+               } else
+                       cpu_relax();
 
        if ((dmastat & DMA_ERR) && (spistat & RBSY)) {
                msg->state = ERROR_STATE;
@@ -763,11 +771,10 @@ static void pump_transfers(unsigned long data)
        if (!full_duplex && drv_data->cur_chip->enable_dma
                                && drv_data->len > 6) {
 
-               unsigned long dma_start_addr;
+               unsigned long dma_start_addr, flags;
 
                disable_dma(drv_data->dma_channel);
                clear_dma_irqstat(drv_data->dma_channel);
-               bfin_spi_disable(drv_data);
 
                /* config dma channel */
                dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
@@ -798,8 +805,7 @@ static void pump_transfers(unsigned long data)
                        enable_dma(drv_data->dma_channel);
 
                        /* start SPI transfer */
-                       write_CTRL(drv_data,
-                               (cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE));
+                       write_CTRL(drv_data, cr | BIT_CTL_TIMOD_DMA_TX);
 
                        /* just return here, there can only be one transfer
                         * in this mode
@@ -827,7 +833,7 @@ static void pump_transfers(unsigned long data)
 
                        dma_config |= WNR;
                        dma_start_addr = (unsigned long)drv_data->rx;
-                       cr |= CFG_SPI_DMAREAD;
+                       cr |= BIT_CTL_TIMOD_DMA_RX | BIT_CTL_SENDOPT;
 
                } else if (drv_data->tx != NULL) {
                        dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
@@ -839,19 +845,27 @@ static void pump_transfers(unsigned long data)
                                                drv_data->len_in_bytes));
 
                        dma_start_addr = (unsigned long)drv_data->tx;
-                       cr |= CFG_SPI_DMAWRITE;
+                       cr |= BIT_CTL_TIMOD_DMA_TX;
 
                } else
                        BUG();
 
-               /* start dma */
-               dma_enable_irq(drv_data->dma_channel);
-               set_dma_config(drv_data->dma_channel, dma_config);
+               /* oh man, here there be monsters ... and i dont mean the
+                * fluffy cute ones from pixar, i mean the kind that'll eat
+                * your data, kick your dog, and love it all.  do *not* try
+                * and change these lines unless you (1) heavily test DMA
+                * with SPI flashes on a loaded system (e.g. ping floods),
+                * (2) know just how broken the DMA engine interaction with
+                * the SPI peripheral is, and (3) have someone else to blame
+                * when you screw it all up anyways.
+                */
                set_dma_start_addr(drv_data->dma_channel, dma_start_addr);
+               set_dma_config(drv_data->dma_channel, dma_config);
+               local_irq_save(flags);
                enable_dma(drv_data->dma_channel);
-
-               /* start SPI transfer */
-               write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
+               write_CTRL(drv_data, cr);
+               dma_enable_irq(drv_data->dma_channel);
+               local_irq_restore(flags);
 
        } else {
                /* IO mode write then read */
@@ -1001,7 +1015,7 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
 
 #define MAX_SPI_SSEL   7
 
-static u16 ssel[3][MAX_SPI_SSEL] = {
+static u16 ssel[][MAX_SPI_SSEL] = {
        {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
        P_SPI0_SSEL4, P_SPI0_SSEL5,
        P_SPI0_SSEL6, P_SPI0_SSEL7},