diff options
author | Arnd Bergmann <arnd@arndb.de> | 2015-02-16 20:46:49 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2015-02-23 05:42:24 -0500 |
commit | 411fdaf846afb0be1b54383c184f58a42fa416ff (patch) | |
tree | 2460b59f2c049f6e47c59d67f8c2f18c4be23b33 | |
parent | c517d838eb7d07bbe9507871fab3931deccff539 (diff) |
dmaengine: shdma: use normal interface for passing slave id
in dma_slave_config, which is incompatible with the way that the
dmaengine API normally works.
I've had a closer look at the existing code now and found that all
slave drivers that pass a slave_id in dma_slave_config for SH do that
right after passing the same ID into shdma_chan_filter, so we can just
rely on that. However, the various shdma drivers currently do not
remember the slave ID that was passed into the filter function when
used in non-DT mode and only check the value to find a matching channel,
unlike all other drivers.
There might still be drivers that are not part of the kernel that rely
on setting the slave_id to some other value, so to be on the safe side,
this adds another 'real_slave_id' field to shdma_chan that remembers
the ID and uses it when a driver passes a zero slave_id in dma_slave_config,
like most drivers do.
Eventually, the real_slave_id and slave_id fields should just get merged
into one field, but that requires other changes.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r-- | drivers/dma/sh/shdma-base.c | 73 | ||||
-rw-r--r-- | include/linux/shdma-base.h | 1 |
2 files changed, 54 insertions, 20 deletions
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 8ee383d339a5..10fcabad80f3 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c | |||
@@ -171,8 +171,7 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan) | |||
171 | return NULL; | 171 | return NULL; |
172 | } | 172 | } |
173 | 173 | ||
174 | static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, | 174 | static int shdma_setup_slave(struct shdma_chan *schan, dma_addr_t slave_addr) |
175 | dma_addr_t slave_addr) | ||
176 | { | 175 | { |
177 | struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); | 176 | struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); |
178 | const struct shdma_ops *ops = sdev->ops; | 177 | const struct shdma_ops *ops = sdev->ops; |
@@ -183,25 +182,23 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, | |||
183 | ret = ops->set_slave(schan, match, slave_addr, true); | 182 | ret = ops->set_slave(schan, match, slave_addr, true); |
184 | if (ret < 0) | 183 | if (ret < 0) |
185 | return ret; | 184 | return ret; |
186 | |||
187 | slave_id = schan->slave_id; | ||
188 | } else { | 185 | } else { |
189 | match = slave_id; | 186 | match = schan->real_slave_id; |
190 | } | 187 | } |
191 | 188 | ||
192 | if (slave_id < 0 || slave_id >= slave_num) | 189 | if (schan->real_slave_id < 0 || schan->real_slave_id >= slave_num) |
193 | return -EINVAL; | 190 | return -EINVAL; |
194 | 191 | ||
195 | if (test_and_set_bit(slave_id, shdma_slave_used)) | 192 | if (test_and_set_bit(schan->real_slave_id, shdma_slave_used)) |
196 | return -EBUSY; | 193 | return -EBUSY; |
197 | 194 | ||
198 | ret = ops->set_slave(schan, match, slave_addr, false); | 195 | ret = ops->set_slave(schan, match, slave_addr, false); |
199 | if (ret < 0) { | 196 | if (ret < 0) { |
200 | clear_bit(slave_id, shdma_slave_used); | 197 | clear_bit(schan->real_slave_id, shdma_slave_used); |
201 | return ret; | 198 | return ret; |
202 | } | 199 | } |
203 | 200 | ||
204 | schan->slave_id = slave_id; | 201 | schan->slave_id = schan->real_slave_id; |
205 | 202 | ||
206 | return 0; | 203 | return 0; |
207 | } | 204 | } |
@@ -221,10 +218,12 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan) | |||
221 | */ | 218 | */ |
222 | if (slave) { | 219 | if (slave) { |
223 | /* Legacy mode: .private is set in filter */ | 220 | /* Legacy mode: .private is set in filter */ |
224 | ret = shdma_setup_slave(schan, slave->slave_id, 0); | 221 | schan->real_slave_id = slave->slave_id; |
222 | ret = shdma_setup_slave(schan, 0); | ||
225 | if (ret < 0) | 223 | if (ret < 0) |
226 | goto esetslave; | 224 | goto esetslave; |
227 | } else { | 225 | } else { |
226 | /* Normal mode: real_slave_id was set by filter */ | ||
228 | schan->slave_id = -EINVAL; | 227 | schan->slave_id = -EINVAL; |
229 | } | 228 | } |
230 | 229 | ||
@@ -258,11 +257,14 @@ esetslave: | |||
258 | 257 | ||
259 | /* | 258 | /* |
260 | * This is the standard shdma filter function to be used as a replacement to the | 259 | * This is the standard shdma filter function to be used as a replacement to the |
261 | * "old" method, using the .private pointer. If for some reason you allocate a | 260 | * "old" method, using the .private pointer. |
262 | * channel without slave data, use something like ERR_PTR(-EINVAL) as a filter | 261 | * You always have to pass a valid slave id as the argument, old drivers that |
262 | * pass ERR_PTR(-EINVAL) as a filter parameter and set it up in dma_slave_config | ||
263 | * need to be updated so we can remove the slave_id field from dma_slave_config. | ||
263 | * parameter. If this filter is used, the slave driver, after calling | 264 | * parameter. If this filter is used, the slave driver, after calling |
264 | * dma_request_channel(), will also have to call dmaengine_slave_config() with | 265 | * dma_request_channel(), will also have to call dmaengine_slave_config() with |
265 | * .slave_id, .direction, and either .src_addr or .dst_addr set. | 266 | * .direction, and either .src_addr or .dst_addr set. |
267 | * | ||
266 | * NOTE: this filter doesn't support multiple DMAC drivers with the DMA_SLAVE | 268 | * NOTE: this filter doesn't support multiple DMAC drivers with the DMA_SLAVE |
267 | * capability! If this becomes a requirement, hardware glue drivers, using this | 269 | * capability! If this becomes a requirement, hardware glue drivers, using this |
268 | * services would have to provide their own filters, which first would check | 270 | * services would have to provide their own filters, which first would check |
@@ -276,7 +278,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) | |||
276 | { | 278 | { |
277 | struct shdma_chan *schan; | 279 | struct shdma_chan *schan; |
278 | struct shdma_dev *sdev; | 280 | struct shdma_dev *sdev; |
279 | int match = (long)arg; | 281 | int slave_id = (long)arg; |
280 | int ret; | 282 | int ret; |
281 | 283 | ||
282 | /* Only support channels handled by this driver. */ | 284 | /* Only support channels handled by this driver. */ |
@@ -284,19 +286,39 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) | |||
284 | shdma_alloc_chan_resources) | 286 | shdma_alloc_chan_resources) |
285 | return false; | 287 | return false; |
286 | 288 | ||
287 | if (match < 0) | 289 | schan = to_shdma_chan(chan); |
290 | sdev = to_shdma_dev(chan->device); | ||
291 | |||
292 | /* | ||
293 | * For DT, the schan->slave_id field is generated by the | ||
294 | * set_slave function from the slave ID that is passed in | ||
295 | * from xlate. For the non-DT case, the slave ID is | ||
296 | * directly passed into the filter function by the driver | ||
297 | */ | ||
298 | if (schan->dev->of_node) { | ||
299 | ret = sdev->ops->set_slave(schan, slave_id, 0, true); | ||
300 | if (ret < 0) | ||
301 | return false; | ||
302 | |||
303 | schan->real_slave_id = schan->slave_id; | ||
304 | return true; | ||
305 | } | ||
306 | |||
307 | if (slave_id < 0) { | ||
288 | /* No slave requested - arbitrary channel */ | 308 | /* No slave requested - arbitrary channel */ |
309 | dev_warn(sdev->dma_dev.dev, "invalid slave ID passed to dma_request_slave\n"); | ||
289 | return true; | 310 | return true; |
311 | } | ||
290 | 312 | ||
291 | schan = to_shdma_chan(chan); | 313 | if (slave_id >= slave_num) |
292 | if (!schan->dev->of_node && match >= slave_num) | ||
293 | return false; | 314 | return false; |
294 | 315 | ||
295 | sdev = to_shdma_dev(schan->dma_chan.device); | 316 | ret = sdev->ops->set_slave(schan, slave_id, 0, true); |
296 | ret = sdev->ops->set_slave(schan, match, 0, true); | ||
297 | if (ret < 0) | 317 | if (ret < 0) |
298 | return false; | 318 | return false; |
299 | 319 | ||
320 | schan->real_slave_id = slave_id; | ||
321 | |||
300 | return true; | 322 | return true; |
301 | } | 323 | } |
302 | EXPORT_SYMBOL(shdma_chan_filter); | 324 | EXPORT_SYMBOL(shdma_chan_filter); |
@@ -452,6 +474,8 @@ static void shdma_free_chan_resources(struct dma_chan *chan) | |||
452 | chan->private = NULL; | 474 | chan->private = NULL; |
453 | } | 475 | } |
454 | 476 | ||
477 | schan->real_slave_id = 0; | ||
478 | |||
455 | spin_lock_irq(&schan->chan_lock); | 479 | spin_lock_irq(&schan->chan_lock); |
456 | 480 | ||
457 | list_splice_init(&schan->ld_free, &list); | 481 | list_splice_init(&schan->ld_free, &list); |
@@ -764,11 +788,20 @@ static int shdma_config(struct dma_chan *chan, | |||
764 | */ | 788 | */ |
765 | if (!config) | 789 | if (!config) |
766 | return -EINVAL; | 790 | return -EINVAL; |
791 | |||
792 | /* | ||
793 | * overriding the slave_id through dma_slave_config is deprecated, | ||
794 | * but possibly some out-of-tree drivers still do it. | ||
795 | */ | ||
796 | if (WARN_ON_ONCE(config->slave_id && | ||
797 | config->slave_id != schan->real_slave_id)) | ||
798 | schan->real_slave_id = config->slave_id; | ||
799 | |||
767 | /* | 800 | /* |
768 | * We could lock this, but you shouldn't be configuring the | 801 | * We could lock this, but you shouldn't be configuring the |
769 | * channel, while using it... | 802 | * channel, while using it... |
770 | */ | 803 | */ |
771 | return shdma_setup_slave(schan, config->slave_id, | 804 | return shdma_setup_slave(schan, |
772 | config->direction == DMA_DEV_TO_MEM ? | 805 | config->direction == DMA_DEV_TO_MEM ? |
773 | config->src_addr : config->dst_addr); | 806 | config->src_addr : config->dst_addr); |
774 | } | 807 | } |
diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index abdf1f229dc3..dd0ba502ccb3 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h | |||
@@ -69,6 +69,7 @@ struct shdma_chan { | |||
69 | int id; /* Raw id of this channel */ | 69 | int id; /* Raw id of this channel */ |
70 | int irq; /* Channel IRQ */ | 70 | int irq; /* Channel IRQ */ |
71 | int slave_id; /* Client ID for slave DMA */ | 71 | int slave_id; /* Client ID for slave DMA */ |
72 | int real_slave_id; /* argument passed to filter function */ | ||
72 | int hw_req; /* DMA request line for slave DMA - same | 73 | int hw_req; /* DMA request line for slave DMA - same |
73 | * as MID/RID, used with DT */ | 74 | * as MID/RID, used with DT */ |
74 | enum shdma_pm_state pm_state; | 75 | enum shdma_pm_state pm_state; |