net: gianfar: Add of_node_put() before goto statement
[linux-2.6-microblaze.git] / drivers / spi / spidev.c
index 80dd102..455e99c 100644 (file)
@@ -62,7 +62,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
 #define SPI_MODE_MASK          (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
                                | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
                                | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
-                               | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)
+                               | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
+                               | SPI_RX_QUAD | SPI_RX_OCTAL)
 
 struct spidev_data {
        dev_t                   devt;
@@ -223,6 +224,11 @@ static int spidev_message(struct spidev_data *spidev,
        for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
                        n;
                        n--, k_tmp++, u_tmp++) {
+               /* Ensure that also following allocations from rx_buf/tx_buf will meet
+                * DMA alignment requirements.
+                */
+               unsigned int len_aligned = ALIGN(u_tmp->len, ARCH_KMALLOC_MINALIGN);
+
                k_tmp->len = u_tmp->len;
 
                total += k_tmp->len;
@@ -238,17 +244,17 @@ static int spidev_message(struct spidev_data *spidev,
 
                if (u_tmp->rx_buf) {
                        /* this transfer needs space in RX bounce buffer */
-                       rx_total += k_tmp->len;
+                       rx_total += len_aligned;
                        if (rx_total > bufsiz) {
                                status = -EMSGSIZE;
                                goto done;
                        }
                        k_tmp->rx_buf = rx_buf;
-                       rx_buf += k_tmp->len;
+                       rx_buf += len_aligned;
                }
                if (u_tmp->tx_buf) {
                        /* this transfer needs space in TX bounce buffer */
-                       tx_total += k_tmp->len;
+                       tx_total += len_aligned;
                        if (tx_total > bufsiz) {
                                status = -EMSGSIZE;
                                goto done;
@@ -258,7 +264,7 @@ static int spidev_message(struct spidev_data *spidev,
                                                (uintptr_t) u_tmp->tx_buf,
                                        u_tmp->len))
                                goto done;
-                       tx_buf += k_tmp->len;
+                       tx_buf += len_aligned;
                }
 
                k_tmp->cs_change = !!u_tmp->cs_change;
@@ -292,16 +298,16 @@ static int spidev_message(struct spidev_data *spidev,
                goto done;
 
        /* copy any rx data out of bounce buffer */
-       rx_buf = spidev->rx_buffer;
-       for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
+       for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
+                       n;
+                       n--, k_tmp++, u_tmp++) {
                if (u_tmp->rx_buf) {
                        if (copy_to_user((u8 __user *)
-                                       (uintptr_t) u_tmp->rx_buf, rx_buf,
+                                       (uintptr_t) u_tmp->rx_buf, k_tmp->rx_buf,
                                        u_tmp->len)) {
                                status = -EFAULT;
                                goto done;
                        }
-                       rx_buf += u_tmp->len;
                }
        }
        status = total;
@@ -608,15 +614,20 @@ err_find_dev:
 static int spidev_release(struct inode *inode, struct file *filp)
 {
        struct spidev_data      *spidev;
+       int                     dofree;
 
        mutex_lock(&device_list_lock);
        spidev = filp->private_data;
        filp->private_data = NULL;
 
+       spin_lock_irq(&spidev->spi_lock);
+       /* ... after we unbound from the underlying device? */
+       dofree = (spidev->spi == NULL);
+       spin_unlock_irq(&spidev->spi_lock);
+
        /* last close? */
        spidev->users--;
        if (!spidev->users) {
-               int             dofree;
 
                kfree(spidev->tx_buffer);
                spidev->tx_buffer = NULL;
@@ -624,19 +635,14 @@ static int spidev_release(struct inode *inode, struct file *filp)
                kfree(spidev->rx_buffer);
                spidev->rx_buffer = NULL;
 
-               spin_lock_irq(&spidev->spi_lock);
-               if (spidev->spi)
-                       spidev->speed_hz = spidev->spi->max_speed_hz;
-
-               /* ... after we unbound from the underlying device? */
-               dofree = (spidev->spi == NULL);
-               spin_unlock_irq(&spidev->spi_lock);
-
                if (dofree)
                        kfree(spidev);
+               else
+                       spidev->speed_hz = spidev->spi->max_speed_hz;
        }
 #ifdef CONFIG_SPI_SLAVE
-       spi_slave_abort(spidev->spi);
+       if (!dofree)
+               spi_slave_abort(spidev->spi);
 #endif
        mutex_unlock(&device_list_lock);
 
@@ -786,13 +792,13 @@ static int spidev_remove(struct spi_device *spi)
 {
        struct spidev_data      *spidev = spi_get_drvdata(spi);
 
+       /* prevent new opens */
+       mutex_lock(&device_list_lock);
        /* make sure ops on existing fds can abort cleanly */
        spin_lock_irq(&spidev->spi_lock);
        spidev->spi = NULL;
        spin_unlock_irq(&spidev->spi_lock);
 
-       /* prevent new opens */
-       mutex_lock(&device_list_lock);
        list_del(&spidev->device_entry);
        device_destroy(spidev_class, spidev->devt);
        clear_bit(MINOR(spidev->devt), minors);