aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2013-11-26 12:04:22 -0500
committerVinod Koul <vinod.koul@intel.com>2013-12-10 07:16:48 -0500
commit0ad7c00057dc1640647c1dc81ccbd009de17a767 (patch)
treeb73891fc496ebb59a4fb531667d7f89d58698786
parent6ce4eac1f600b34f2f7f58f9cd8f0503d79e42ae (diff)
dma: add channel request API that supports deferred probe
dma_request_slave_channel() simply returns NULL whenever DMA channel lookup fails. Lookup could fail for two distinct reasons: a) No DMA specification exists for the channel name. This includes situations where no DMA specifications exist at all, or other general lookup problems. b) A DMA specification does exist, yet the driver for that channel is not yet registered. Case (b) should trigger deferred probe in client drivers. However, since they have no way to differentiate the two situations, it cannot. Implement new function dma_request_slave_channel_reason(), which performs identically to dma_request_slave_channel(), except that it returns an error-pointer rather than NULL, which allows callers to detect when deferred probe should occur. Eventually, all drivers should be converted to this new API, the old API removed, and the new API renamed to the more desirable name. This patch doesn't convert the existing API and all drivers in one go, since some drivers call dma_request_slave_channel() then dma_request_channel() if that fails. That would require either modifying dma_request_channel() in the same way, or adding extra error-handling code to all affected drivers, and there are close to 100 drivers using the other API, rather than just the 15-20 or so that use dma_request_slave_channel(), which might be tenable in a single patch. acpi_dma_request_slave_chan_by_name() doesn't currently implement deferred probe. It should, but this will be addressed later. Acked-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/dmaengine.c35
-rw-r--r--drivers/dma/of-dma.c15
-rw-r--r--include/linux/dmaengine.h8
3 files changed, 48 insertions, 10 deletions
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index ea806bdc12ef..e17e9b22d85e 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -540,6 +540,8 @@ EXPORT_SYMBOL_GPL(dma_get_slave_channel);
540 * @mask: capabilities that the channel must satisfy 540 * @mask: capabilities that the channel must satisfy
541 * @fn: optional callback to disposition available channels 541 * @fn: optional callback to disposition available channels
542 * @fn_param: opaque parameter to pass to dma_filter_fn 542 * @fn_param: opaque parameter to pass to dma_filter_fn
543 *
544 * Returns pointer to appropriate DMA channel on success or NULL.
543 */ 545 */
544struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, 546struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
545 dma_filter_fn fn, void *fn_param) 547 dma_filter_fn fn, void *fn_param)
@@ -591,18 +593,43 @@ EXPORT_SYMBOL_GPL(__dma_request_channel);
591 * dma_request_slave_channel - try to allocate an exclusive slave channel 593 * dma_request_slave_channel - try to allocate an exclusive slave channel
592 * @dev: pointer to client device structure 594 * @dev: pointer to client device structure
593 * @name: slave channel name 595 * @name: slave channel name
596 *
597 * Returns pointer to appropriate DMA channel on success or an error pointer.
594 */ 598 */
595struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) 599struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
600 const char *name)
596{ 601{
602 struct dma_chan *chan;
603
597 /* If device-tree is present get slave info from here */ 604 /* If device-tree is present get slave info from here */
598 if (dev->of_node) 605 if (dev->of_node)
599 return of_dma_request_slave_channel(dev->of_node, name); 606 return of_dma_request_slave_channel(dev->of_node, name);
600 607
601 /* If device was enumerated by ACPI get slave info from here */ 608 /* If device was enumerated by ACPI get slave info from here */
602 if (ACPI_HANDLE(dev)) 609 if (ACPI_HANDLE(dev)) {
603 return acpi_dma_request_slave_chan_by_name(dev, name); 610 chan = acpi_dma_request_slave_chan_by_name(dev, name);
611 if (chan)
612 return chan;
613 }
604 614
605 return NULL; 615 return ERR_PTR(-ENODEV);
616}
617EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason);
618
619/**
620 * dma_request_slave_channel - try to allocate an exclusive slave channel
621 * @dev: pointer to client device structure
622 * @name: slave channel name
623 *
624 * Returns pointer to appropriate DMA channel on success or NULL.
625 */
626struct dma_chan *dma_request_slave_channel(struct device *dev,
627 const char *name)
628{
629 struct dma_chan *ch = dma_request_slave_channel_reason(dev, name);
630 if (IS_ERR(ch))
631 return NULL;
632 return ch;
606} 633}
607EXPORT_SYMBOL_GPL(dma_request_slave_channel); 634EXPORT_SYMBOL_GPL(dma_request_slave_channel);
608 635
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index 0b88dd3d05f4..e8fe9dc455f4 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -143,7 +143,7 @@ static int of_dma_match_channel(struct device_node *np, const char *name,
143 * @np: device node to get DMA request from 143 * @np: device node to get DMA request from
144 * @name: name of desired channel 144 * @name: name of desired channel
145 * 145 *
146 * Returns pointer to appropriate dma channel on success or NULL on error. 146 * Returns pointer to appropriate DMA channel on success or an error pointer.
147 */ 147 */
148struct dma_chan *of_dma_request_slave_channel(struct device_node *np, 148struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
149 const char *name) 149 const char *name)
@@ -152,17 +152,18 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
152 struct of_dma *ofdma; 152 struct of_dma *ofdma;
153 struct dma_chan *chan; 153 struct dma_chan *chan;
154 int count, i; 154 int count, i;
155 int ret_no_channel = -ENODEV;
155 156
156 if (!np || !name) { 157 if (!np || !name) {
157 pr_err("%s: not enough information provided\n", __func__); 158 pr_err("%s: not enough information provided\n", __func__);
158 return NULL; 159 return ERR_PTR(-ENODEV);
159 } 160 }
160 161
161 count = of_property_count_strings(np, "dma-names"); 162 count = of_property_count_strings(np, "dma-names");
162 if (count < 0) { 163 if (count < 0) {
163 pr_err("%s: dma-names property of node '%s' missing or empty\n", 164 pr_err("%s: dma-names property of node '%s' missing or empty\n",
164 __func__, np->full_name); 165 __func__, np->full_name);
165 return NULL; 166 return ERR_PTR(-ENODEV);
166 } 167 }
167 168
168 for (i = 0; i < count; i++) { 169 for (i = 0; i < count; i++) {
@@ -172,10 +173,12 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
172 mutex_lock(&of_dma_lock); 173 mutex_lock(&of_dma_lock);
173 ofdma = of_dma_find_controller(&dma_spec); 174 ofdma = of_dma_find_controller(&dma_spec);
174 175
175 if (ofdma) 176 if (ofdma) {
176 chan = ofdma->of_dma_xlate(&dma_spec, ofdma); 177 chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
177 else 178 } else {
179 ret_no_channel = -EPROBE_DEFER;
178 chan = NULL; 180 chan = NULL;
181 }
179 182
180 mutex_unlock(&of_dma_lock); 183 mutex_unlock(&of_dma_lock);
181 184
@@ -185,7 +188,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
185 return chan; 188 return chan;
186 } 189 }
187 190
188 return NULL; 191 return ERR_PTR(ret_no_channel);
189} 192}
190 193
191/** 194/**
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 41cf0c399288..ed92b30a02fd 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -22,6 +22,7 @@
22#define LINUX_DMAENGINE_H 22#define LINUX_DMAENGINE_H
23 23
24#include <linux/device.h> 24#include <linux/device.h>
25#include <linux/err.h>
25#include <linux/uio.h> 26#include <linux/uio.h>
26#include <linux/bug.h> 27#include <linux/bug.h>
27#include <linux/scatterlist.h> 28#include <linux/scatterlist.h>
@@ -1040,6 +1041,8 @@ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
1040void dma_issue_pending_all(void); 1041void dma_issue_pending_all(void);
1041struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, 1042struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
1042 dma_filter_fn fn, void *fn_param); 1043 dma_filter_fn fn, void *fn_param);
1044struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
1045 const char *name);
1043struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); 1046struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
1044void dma_release_channel(struct dma_chan *chan); 1047void dma_release_channel(struct dma_chan *chan);
1045#else 1048#else
@@ -1063,6 +1066,11 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
1063{ 1066{
1064 return NULL; 1067 return NULL;
1065} 1068}
1069static inline struct dma_chan *dma_request_slave_channel_reason(
1070 struct device *dev, const char *name)
1071{
1072 return ERR_PTR(-ENODEV);
1073}
1066static inline struct dma_chan *dma_request_slave_channel(struct device *dev, 1074static inline struct dma_chan *dma_request_slave_channel(struct device *dev,
1067 const char *name) 1075 const char *name)
1068{ 1076{