Merge branch 'mfd/wm8994' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux-2.6.git] / drivers / dma / dmaengine.c
index 8f99354..b48967b 100644 (file)
@@ -45,6 +45,7 @@
  * See Documentation/dmaengine.txt for more details
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/jiffies.h>
 #include <linux/rculist.h>
 #include <linux/idr.h>
+#include <linux/slab.h>
 
 static DEFINE_MUTEX(dma_list_mutex);
+static DEFINE_IDR(dma_idr);
 static LIST_HEAD(dma_device_list);
 static long dmaengine_ref_count;
-static struct idr dma_idr;
 
 /* --- sysfs implementation --- */
 
@@ -284,7 +286,7 @@ struct dma_chan_tbl_ent {
 /**
  * channel_table - percpu lookup table for memory-to-memory offload providers
  */
-static struct dma_chan_tbl_ent *channel_table[DMA_TX_TYPE_END];
+static struct dma_chan_tbl_ent __percpu *channel_table[DMA_TX_TYPE_END];
 
 static int __init dma_channel_table_init(void)
 {
@@ -326,14 +328,7 @@ arch_initcall(dma_channel_table_init);
  */
 struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
 {
-       struct dma_chan *chan;
-       int cpu;
-
-       cpu = get_cpu();
-       chan = per_cpu_ptr(channel_table[tx_type], cpu)->chan;
-       put_cpu();
-
-       return chan;
+       return this_cpu_read(channel_table[tx_type]->chan);
 }
 EXPORT_SYMBOL(dma_find_channel);
 
@@ -515,13 +510,12 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v
                                         dma_chan_name(chan));
                                list_del_rcu(&device->global_node);
                        } else if (err)
-                               pr_err("dmaengine: failed to get %s: (%d)\n",
-                                      dma_chan_name(chan), err);
+                               pr_debug("dmaengine: failed to get %s: (%d)\n",
+                                        dma_chan_name(chan), err);
                        else
                                break;
                        if (--device->privatecnt == 0)
                                dma_cap_clear(DMA_PRIVATE, device->cap_mask);
-                       chan->private = NULL;
                        chan = NULL;
                }
        }
@@ -543,7 +537,6 @@ void dma_release_channel(struct dma_chan *chan)
        /* drop PRIVATE cap enabled by __dma_request_channel() */
        if (--chan->device->privatecnt == 0)
                dma_cap_clear(DMA_PRIVATE, chan->device->cap_mask);
-       chan->private = NULL;
        mutex_unlock(&dma_list_mutex);
 }
 EXPORT_SYMBOL_GPL(dma_release_channel);
@@ -698,19 +691,23 @@ int dma_async_device_register(struct dma_device *device)
                !device->device_prep_dma_memset);
        BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
                !device->device_prep_dma_interrupt);
+       BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
+               !device->device_prep_dma_sg);
        BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
                !device->device_prep_slave_sg);
+       BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) &&
+               !device->device_prep_dma_cyclic);
        BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
-               !device->device_terminate_all);
+               !device->device_control);
 
        BUG_ON(!device->device_alloc_chan_resources);
        BUG_ON(!device->device_free_chan_resources);
-       BUG_ON(!device->device_is_tx_complete);
+       BUG_ON(!device->device_tx_status);
        BUG_ON(!device->device_issue_pending);
        BUG_ON(!device->dev);
 
        /* note: this only matters in the
-        * CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH=y case
+        * CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=n case
         */
        if (device_has_all_tx_types(device))
                dma_cap_set(DMA_ASYNC_TX, device->cap_mask);
@@ -833,6 +830,7 @@ void dma_async_device_unregister(struct dma_device *device)
                chan->dev->chan = NULL;
                mutex_unlock(&dma_list_mutex);
                device_unregister(&chan->dev->device);
+               free_percpu(chan->local);
        }
 }
 EXPORT_SYMBOL(dma_async_device_unregister);
@@ -857,7 +855,6 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
        struct dma_async_tx_descriptor *tx;
        dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
-       int cpu;
        unsigned long flags;
 
        dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
@@ -876,10 +873,10 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
        tx->callback = NULL;
        cookie = tx->tx_submit(tx);
 
-       cpu = get_cpu();
-       per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
-       per_cpu_ptr(chan->local, cpu)->memcpy_count++;
-       put_cpu();
+       preempt_disable();
+       __this_cpu_add(chan->local->bytes_transferred, len);
+       __this_cpu_inc(chan->local->memcpy_count);
+       preempt_enable();
 
        return cookie;
 }
@@ -906,7 +903,6 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
        struct dma_async_tx_descriptor *tx;
        dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
-       int cpu;
        unsigned long flags;
 
        dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
@@ -923,10 +919,10 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
        tx->callback = NULL;
        cookie = tx->tx_submit(tx);
 
-       cpu = get_cpu();
-       per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
-       per_cpu_ptr(chan->local, cpu)->memcpy_count++;
-       put_cpu();
+       preempt_disable();
+       __this_cpu_add(chan->local->bytes_transferred, len);
+       __this_cpu_inc(chan->local->memcpy_count);
+       preempt_enable();
 
        return cookie;
 }
@@ -955,7 +951,6 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
        struct dma_async_tx_descriptor *tx;
        dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
-       int cpu;
        unsigned long flags;
 
        dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
@@ -973,10 +968,10 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
        tx->callback = NULL;
        cookie = tx->tx_submit(tx);
 
-       cpu = get_cpu();
-       per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
-       per_cpu_ptr(chan->local, cpu)->memcpy_count++;
-       put_cpu();
+       preempt_disable();
+       __this_cpu_add(chan->local->bytes_transferred, len);
+       __this_cpu_inc(chan->local->memcpy_count);
+       preempt_enable();
 
        return cookie;
 }
@@ -986,7 +981,9 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
        struct dma_chan *chan)
 {
        tx->chan = chan;
+       #ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
        spin_lock_init(&tx->lock);
+       #endif
 }
 EXPORT_SYMBOL(dma_async_tx_descriptor_init);
 
@@ -1019,7 +1016,7 @@ EXPORT_SYMBOL_GPL(dma_wait_for_async_tx);
  */
 void dma_run_dependencies(struct dma_async_tx_descriptor *tx)
 {
-       struct dma_async_tx_descriptor *dep = tx->next;
+       struct dma_async_tx_descriptor *dep = txd_next(tx);
        struct dma_async_tx_descriptor *dep_next;
        struct dma_chan *chan;
 
@@ -1027,7 +1024,7 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx)
                return;
 
        /* we'll submit tx->next now, so clear the link */
-       tx->next = NULL;
+       txd_clear_next(tx);
        chan = dep->chan;
 
        /* keep submitting up until a channel switch is detected
@@ -1035,14 +1032,14 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx)
         * processing the interrupt from async_tx_channel_switch
         */
        for (; dep; dep = dep_next) {
-               spin_lock_bh(&dep->lock);
-               dep->parent = NULL;
-               dep_next = dep->next;
+               txd_lock(dep);
+               txd_clear_parent(dep);
+               dep_next = txd_next(dep);
                if (dep_next && dep_next->chan == chan)
-                       dep->next = NULL; /* ->next will be submitted */
+                       txd_clear_next(dep); /* ->next will be submitted */
                else
                        dep_next = NULL; /* submit current dep and terminate */
-               spin_unlock_bh(&dep->lock);
+               txd_unlock(dep);
 
                dep->tx_submit(dep);
        }
@@ -1053,8 +1050,6 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies);
 
 static int __init dma_bus_init(void)
 {
-       idr_init(&dma_idr);
-       mutex_init(&dma_list_mutex);
        return class_register(&dma_devclass);
 }
 arch_initcall(dma_bus_init);