aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2015-02-16 20:46:49 -0500
committerVinod Koul <vinod.koul@intel.com>2015-02-23 05:42:24 -0500
commit411fdaf846afb0be1b54383c184f58a42fa416ff (patch)
tree2460b59f2c049f6e47c59d67f8c2f18c4be23b33
parentc517d838eb7d07bbe9507871fab3931deccff539 (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.c73
-rw-r--r--include/linux/shdma-base.h1
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
174static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, 174static 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}
302EXPORT_SYMBOL(shdma_chan_filter); 324EXPORT_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;