From 58b267d3e3f3ce87c3e559e4c330c8c03e905f5e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 24 Jul 2013 15:05:08 -0700 Subject: dma: convert dma_devclass to use dev_groups The dev_attrs field of struct class is going away soon, dev_groups should be used instead. This converts the dma dma_devclass code to use the correct field. Cc: Dan Williams Acked-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/dmaengine.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/dma/dmaengine.c') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 9e56745f87bf..99af4db5948b 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -87,7 +87,8 @@ static struct dma_chan *dev_to_dma_chan(struct device *dev) return chan_dev->chan; } -static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t memcpy_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct dma_chan *chan; unsigned long count = 0; @@ -106,9 +107,10 @@ static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *at return err; } +static DEVICE_ATTR_RO(memcpy_count); -static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t bytes_transferred_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct dma_chan *chan; unsigned long count = 0; @@ -127,8 +129,10 @@ static ssize_t show_bytes_transferred(struct device *dev, struct device_attribut return err; } +static DEVICE_ATTR_RO(bytes_transferred); -static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t in_use_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct dma_chan *chan; int err; @@ -143,13 +147,15 @@ static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, ch return err; } +static DEVICE_ATTR_RO(in_use); -static struct device_attribute dma_attrs[] = { - __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL), - __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL), - __ATTR(in_use, S_IRUGO, show_in_use, NULL), - __ATTR_NULL +static struct attribute *dma_dev_attrs[] = { + &dev_attr_memcpy_count.attr, + &dev_attr_bytes_transferred.attr, + &dev_attr_in_use.attr, + NULL, }; +ATTRIBUTE_GROUPS(dma_dev); static void chan_dev_release(struct device *dev) { @@ -167,7 +173,7 @@ static void chan_dev_release(struct device *dev) static struct class dma_devclass = { .name = "dma", - .dev_attrs = dma_attrs, + .dev_groups = dma_dev_groups, .dev_release = chan_dev_release, }; -- cgit v1.2.3 From 7bb587f4eef8f71ce589f360ab99bb54ab0fc85d Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Fri, 28 Jun 2013 20:39:12 +0800 Subject: dmaengine: add interface of dma_get_slave_channel Suggested by Arnd, add dma_get_slave_channel interface Dma host driver could get specific channel specificied by request line, rather than filter. host example: static struct dma_chan *xx_of_dma_simple_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { struct xx_dma_dev *d = ofdma->of_dma_data; unsigned int request = dma_spec->args[0]; if (request > d->dma_requests) return NULL; return dma_get_slave_channel(&(d->chans[request].vc.chan)); } probe: of_dma_controller_register((&op->dev)->of_node, xx_of_dma_simple_xlate, d); Signed-off-by: Zhangfei Gao Acked-by: Arnd Bergmann Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/dma/dmaengine.c') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 9e56745f87bf..5932ab164ace 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -503,6 +503,32 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask, return NULL; } +/** + * dma_request_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); + else + chan = NULL; + + mutex_unlock(&dma_list_mutex); + + if (err) + pr_debug("%s: failed to get %s: (%d)\n", + __func__, dma_chan_name(chan), err); + + 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 -- cgit v1.2.3 From d9a6c8f52d1039333bef6234126485409e8f7501 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 19 Aug 2013 10:47:26 +0530 Subject: dmaengine: fix - error: potential NULL dereference 'chan' commit 7bb587f4 "dmaengine: add interface of dma_get_slave_channel" introduced the above error so fix it Reported-by: Dan Carpenter Suggested-by: Zhangfei Gao Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/dma/dmaengine.c') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 5932ab164ace..755ba2f4f1d5 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -514,16 +514,16 @@ struct dma_chan *dma_get_slave_channel(struct dma_chan *chan) /* lock against __dma_request_channel */ mutex_lock(&dma_list_mutex); - if (chan->client_count == 0) + if (chan->client_count == 0) { err = dma_chan_get(chan); - else + 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); - if (err) - pr_debug("%s: failed to get %s: (%d)\n", - __func__, dma_chan_name(chan), err); return chan; } -- cgit v1.2.3 From c4d27c4d024f5440497106bb2ae15e9e60f7099c Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Mon, 19 Aug 2013 11:43:35 +0200 Subject: dmaengine: make dma_channel_rebalance() NUMA aware dma_channel_rebalance() currently distributes channels by processor ID. These IDs often change with the BIOS, and the order isn't related to the DMA channel list (related to PCI bus ids). * On my SuperMicro dual E5 machine, first socket has processor IDs [0-7] (and [16-23] for hyperthreads), second socket has [8-15]+[24-31] => channels are properly allocated to local CPUs. * On Dells R720 with same processors, first socket has even processor IDs, second socket has odd numbers => half the processors get channels on the remote socket, causing cross-NUMA traffic and lower DMA performance. Change nth_chan() to return the channel with min table_count and in the NUMA node of the given CPU, if any. If none, the (non-local) channel with min table_count is returned. nth_chan() is therefore renamed into min_chan() since we don't iterate until the nth channel anymore. In practice, the behavior is the same because first channels are taken first and are then ignored because they got an additional reference. The new code has a slightly higher complexity since we always scan the entire list of channels for finding the minimal table_count (instead of stopping after N chans), and because we check whether the CPU is in the DMA device locality mask. Overall we still have time complexity = number of chans x number of processors. This rebalance is rarely used, so this won't hurt. On the above SuperMicro machine, channels are still allocated the same. On the Dells, there are no locality issue anymore (MEMCPY channel X goes to processor X and to its hyperthread sibling). Signed-off-by: Brice Goglin Signed-off-by: Dan Williams --- drivers/dma/dmaengine.c | 55 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'drivers/dma/dmaengine.c') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 9e56745f87bf..e428cf2a458b 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -376,20 +376,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) || @@ -398,27 +408,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; } /** @@ -435,7 +440,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) @@ -454,14 +458,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; } } -- cgit v1.2.3 From 6b9019a7f0b4958230df6563ccd585b858145991 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 14 Aug 2013 18:35:03 +0200 Subject: dma: dmagengine: fix function names in comments Trivial fix for function name mismatches I stumbled over. Signed-off-by: Daniel Mack Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/dma/dmaengine.c') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 5932ab164ace..0947ff64152e 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -504,7 +504,7 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask, } /** - * dma_request_channel - try to get specific channel exclusively + * dma_request_slave_channel - try to get specific channel exclusively * @chan: target channel */ struct dma_chan *dma_get_slave_channel(struct dma_chan *chan) @@ -530,7 +530,7 @@ struct dma_chan *dma_get_slave_channel(struct dma_chan *chan) EXPORT_SYMBOL_GPL(dma_get_slave_channel); /** - * dma_request_channel - try to allocate an exclusive 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 -- cgit v1.2.3