]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/dma/dmaengine.c
Merge remote-tracking branch 'net-next/master'
[karo-tx-linux.git] / drivers / dma / dmaengine.c
index 99af4db5948bc9406d85ef841077baff2ffd5f40..81d876528c70d60152628b04bb41b08d860ec565 100644 (file)
@@ -382,20 +382,30 @@ void dma_issue_pending_all(void)
 EXPORT_SYMBOL(dma_issue_pending_all);
 
 /**
- * nth_chan - returns the nth channel of the given capability
+ * dma_chan_is_local - returns true if the channel is in the same numa-node as the cpu
+ */
+static bool dma_chan_is_local(struct dma_chan *chan, int cpu)
+{
+       int node = dev_to_node(chan->device->dev);
+       return node == -1 || cpumask_test_cpu(cpu, cpumask_of_node(node));
+}
+
+/**
+ * min_chan - returns the channel with min count and in the same numa-node as the cpu
  * @cap: capability to match
- * @n: nth channel desired
+ * @cpu: cpu index which the channel should be close to
  *
- * Defaults to returning the channel with the desired capability and the
- * lowest reference count when 'n' cannot be satisfied.  Must be called
- * under dma_list_mutex.
+ * If some channels are close to the given cpu, the one with the lowest
+ * reference count is returned. Otherwise, cpu is ignored and only the
+ * reference count is taken into account.
+ * Must be called under dma_list_mutex.
  */
-static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n)
+static struct dma_chan *min_chan(enum dma_transaction_type cap, int cpu)
 {
        struct dma_device *device;
        struct dma_chan *chan;
-       struct dma_chan *ret = NULL;
        struct dma_chan *min = NULL;
+       struct dma_chan *localmin = NULL;
 
        list_for_each_entry(device, &dma_device_list, global_node) {
                if (!dma_has_cap(cap, device->cap_mask) ||
@@ -404,27 +414,22 @@ static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n)
                list_for_each_entry(chan, &device->channels, device_node) {
                        if (!chan->client_count)
                                continue;
-                       if (!min)
-                               min = chan;
-                       else if (chan->table_count < min->table_count)
+                       if (!min || chan->table_count < min->table_count)
                                min = chan;
 
-                       if (n-- == 0) {
-                               ret = chan;
-                               break; /* done */
-                       }
+                       if (dma_chan_is_local(chan, cpu))
+                               if (!localmin ||
+                                   chan->table_count < localmin->table_count)
+                                       localmin = chan;
                }
-               if (ret)
-                       break; /* done */
        }
 
-       if (!ret)
-               ret = min;
+       chan = localmin ? localmin : min;
 
-       if (ret)
-               ret->table_count++;
+       if (chan)
+               chan->table_count++;
 
-       return ret;
+       return chan;
 }
 
 /**
@@ -441,7 +446,6 @@ static void dma_channel_rebalance(void)
        struct dma_device *device;
        int cpu;
        int cap;
-       int n;
 
        /* undo the last distribution */
        for_each_dma_cap_mask(cap, dma_cap_mask_all)
@@ -460,14 +464,9 @@ static void dma_channel_rebalance(void)
                return;
 
        /* redistribute available channels */
-       n = 0;
        for_each_dma_cap_mask(cap, dma_cap_mask_all)
                for_each_online_cpu(cpu) {
-                       if (num_possible_cpus() > 1)
-                               chan = nth_chan(cap, n++);
-                       else
-                               chan = nth_chan(cap, -1);
-
+                       chan = min_chan(cap, cpu);
                        per_cpu_ptr(channel_table[cap], cpu)->chan = chan;
                }
 }
@@ -510,7 +509,33 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask,
 }
 
 /**
- * dma_request_channel - try to allocate an exclusive channel
+ * dma_request_slave_channel - try to get specific channel exclusively
+ * @chan: target channel
+ */
+struct dma_chan *dma_get_slave_channel(struct dma_chan *chan)
+{
+       int err = -EBUSY;
+
+       /* lock against __dma_request_channel */
+       mutex_lock(&dma_list_mutex);
+
+       if (chan->client_count == 0) {
+               err = dma_chan_get(chan);
+               if (err)
+                       pr_debug("%s: failed to get %s: (%d)\n",
+                               __func__, dma_chan_name(chan), err);
+       } else
+               chan = NULL;
+
+       mutex_unlock(&dma_list_mutex);
+
+
+       return chan;
+}
+EXPORT_SYMBOL_GPL(dma_get_slave_channel);
+
+/**
+ * __dma_request_channel - try to allocate an exclusive channel
  * @mask: capabilities that the channel must satisfy
  * @fn: optional callback to disposition available channels
  * @fn_param: opaque parameter to pass to dma_filter_fn
@@ -1037,7 +1062,7 @@ dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
        unsigned long dma_sync_wait_timeout = jiffies + msecs_to_jiffies(5000);
 
        if (!tx)
-               return DMA_SUCCESS;
+               return DMA_COMPLETE;
 
        while (tx->cookie == -EBUSY) {
                if (time_after_eq(jiffies, dma_sync_wait_timeout)) {