USB: cdc_acm: Fix memory leak after hangup
[safe/jmp/linux-2.6] / drivers / spi / au1550_spi.c
index 3860dd2..76cbc1a 100644 (file)
@@ -284,27 +284,16 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
        return 0;
 }
 
-/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)
-
 static int au1550_spi_setup(struct spi_device *spi)
 {
        struct au1550_spi *hw = spi_master_get_devdata(spi->master);
 
-       if (spi->bits_per_word == 0)
-               spi->bits_per_word = 8;
        if (spi->bits_per_word < 4 || spi->bits_per_word > 24) {
                dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n",
                        spi->bits_per_word);
                return -EINVAL;
        }
 
-       if (spi->mode & ~MODEBITS) {
-               dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
-                       spi->mode & ~MODEBITS);
-               return -EINVAL;
-       }
-
        if (spi->max_speed_hz == 0)
                spi->max_speed_hz = hw->freq_max;
        if (spi->max_speed_hz > hw->freq_max
@@ -334,7 +323,7 @@ static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size)
        hw->dma_rx_tmpbuf_size = size;
        hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf,
                        size, DMA_FROM_DEVICE);
-       if (dma_mapping_error(hw->dma_rx_tmpbuf_addr)) {
+       if (dma_mapping_error(hw->dev, hw->dma_rx_tmpbuf_addr)) {
                kfree(hw->dma_rx_tmpbuf);
                hw->dma_rx_tmpbuf = 0;
                hw->dma_rx_tmpbuf_size = 0;
@@ -369,16 +358,29 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
        dma_rx_addr = t->rx_dma;
 
        /*
-        * check if buffers are already dma mapped, map them otherwise
+        * check if buffers are already dma mapped, map them otherwise:
+        * - first map the TX buffer, so cache data gets written to memory
+        * - then map the RX buffer, so that cache entries (with
+        *   soon-to-be-stale data) get removed
         * use rx buffer in place of tx if tx buffer was not provided
         * use temp rx buffer (preallocated or realloc to fit) for rx dma
         */
+       if (t->tx_buf) {
+               if (t->tx_dma == 0) {   /* if DMA_ADDR_INVALID, map it */
+                       dma_tx_addr = dma_map_single(hw->dev,
+                                       (void *)t->tx_buf,
+                                       t->len, DMA_TO_DEVICE);
+                       if (dma_mapping_error(hw->dev, dma_tx_addr))
+                               dev_err(hw->dev, "tx dma map error\n");
+               }
+       }
+
        if (t->rx_buf) {
                if (t->rx_dma == 0) {   /* if DMA_ADDR_INVALID, map it */
                        dma_rx_addr = dma_map_single(hw->dev,
                                        (void *)t->rx_buf,
                                        t->len, DMA_FROM_DEVICE);
-                       if (dma_mapping_error(dma_rx_addr))
+                       if (dma_mapping_error(hw->dev, dma_rx_addr))
                                dev_err(hw->dev, "rx dma map error\n");
                }
        } else {
@@ -396,15 +398,8 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
                dma_sync_single_for_device(hw->dev, dma_rx_addr,
                        t->len, DMA_FROM_DEVICE);
        }
-       if (t->tx_buf) {
-               if (t->tx_dma == 0) {   /* if DMA_ADDR_INVALID, map it */
-                       dma_tx_addr = dma_map_single(hw->dev,
-                                       (void *)t->tx_buf,
-                                       t->len, DMA_TO_DEVICE);
-                       if (dma_mapping_error(dma_tx_addr))
-                               dev_err(hw->dev, "tx dma map error\n");
-               }
-       } else {
+
+       if (!t->tx_buf) {
                dma_sync_single_for_device(hw->dev, dma_rx_addr,
                                t->len, DMA_BIDIRECTIONAL);
                hw->tx = hw->rx;
@@ -484,9 +479,13 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
                au1xxx_dbdma_reset(hw->dma_tx_ch);
                au1550_spi_reset_fifos(hw);
 
-               dev_err(hw->dev,
-                       "Unexpected SPI error: event=0x%x stat=0x%x!\n",
-                       evnt, stat);
+               if (evnt == PSC_SPIEVNT_RO)
+                       dev_err(hw->dev,
+                               "dma transfer: receive FIFO overflow!\n");
+               else
+                       dev_err(hw->dev,
+                               "dma transfer: unexpected SPI error "
+                               "(event=0x%x stat=0x%x)!\n", evnt, stat);
 
                complete(&hw->master_done);
                return IRQ_HANDLED;
@@ -596,17 +595,17 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
 
        if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
                                | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
-                               | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD))
+                               | PSC_SPIEVNT_SD))
                        != 0) {
-               dev_err(hw->dev,
-                       "Unexpected SPI error: event=0x%x stat=0x%x!\n",
-                       evnt, stat);
                /*
                 * due to an error we consider transfer as done,
                 * so mask all events until before next transfer start
                 */
                au1550_spi_mask_ack_all(hw);
                au1550_spi_reset_fifos(hw);
+               dev_err(hw->dev,
+                       "pio transfer: unexpected SPI error "
+                       "(event=0x%x stat=0x%x)!\n", evnt, stat);
                complete(&hw->master_done);
                return IRQ_HANDLED;
        }
@@ -620,27 +619,50 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
                stat = hw->regs->psc_spistat;
                au_sync();
 
-               if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) {
+               /*
+                * Take care to not let the Rx FIFO overflow.
+                *
+                * We only write a byte if we have read one at least. Initially,
+                * the write fifo is full, so we should read from the read fifo
+                * first.
+                * In case we miss a word from the read fifo, we should get a
+                * RO event and should back out.
+                */
+               if (!(stat & PSC_SPISTAT_RE) && hw->rx_count < hw->len) {
                        hw->rx_word(hw);
-                       /* ack the receive request event */
-                       hw->regs->psc_spievent = PSC_SPIEVNT_RR;
-                       au_sync();
                        busy = 1;
-               }
 
-               if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) {
-                       hw->tx_word(hw);
-                       /* ack the transmit request event */
-                       hw->regs->psc_spievent = PSC_SPIEVNT_TR;
-                       au_sync();
-                       busy = 1;
+                       if (!(stat & PSC_SPISTAT_TF) && hw->tx_count < hw->len)
+                               hw->tx_word(hw);
                }
        } while (busy);
 
-       evnt = hw->regs->psc_spievent;
+       hw->regs->psc_spievent = PSC_SPIEVNT_RR | PSC_SPIEVNT_TR;
        au_sync();
 
-       if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) {
+       /*
+        * Restart the SPI transmission in case of a transmit underflow.
+        * This seems to work despite the notes in the Au1550 data book
+        * of Figure 8-4 with flowchart for SPI master operation:
+        *
+        * """Note 1: An XFR Error Interrupt occurs, unless masked,
+        * for any of the following events: Tx FIFO Underflow,
+        * Rx FIFO Overflow, or Multiple-master Error
+        *    Note 2: In case of a Tx Underflow Error, all zeroes are
+        * transmitted."""
+        *
+        * By simply restarting the spi transfer on Tx Underflow Error,
+        * we assume that spi transfer was paused instead of zeroes
+        * transmittion mentioned in the Note 2 of Au1550 data book.
+        */
+       if (evnt & PSC_SPIEVNT_TU) {
+               hw->regs->psc_spievent = PSC_SPIEVNT_TU | PSC_SPIEVNT_MD;
+               au_sync();
+               hw->regs->psc_spipcr = PSC_SPIPCR_MS;
+               au_sync();
+       }
+
+       if (hw->rx_count >= hw->len) {
                /* transfer completed successfully */
                au1550_spi_mask_ack_all(hw);
                complete(&hw->master_done);
@@ -729,6 +751,8 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
                stat = hw->regs->psc_spistat;
                au_sync();
        } while ((stat & PSC_SPISTAT_DR) == 0);
+
+       au1550_spi_reset_fifos(hw);
 }
 
 
@@ -746,6 +770,9 @@ static int __init au1550_spi_probe(struct platform_device *pdev)
                goto err_nomem;
        }
 
+       /* the spi->mode bits understood by this driver: */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+
        hw = spi_master_get_devdata(master);
 
        hw->master = spi_master_get(master);