Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 316671
b: refs/heads/master
c: 1ff8df4
h: refs/heads/master
i:
  316669: d6bb9a9
  316667: 5465273
  316663: 6111123
  316655: 6476202
  316639: ec47fe3
  316607: 4bcafb1
  316543: 097bd31
  316415: e774075
v: v3
  • Loading branch information
Guennadi Liakhovetski authored and Vinod Koul committed Jul 20, 2012
1 parent 1cdd188 commit a09113b
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c2cdb7e4d16394fc51dc5c2c5b3e7c3733bdfaac
refs/heads/master: 1ff8df4f5388ad66bd7d0199b5839a2e3345c055
114 changes: 89 additions & 25 deletions trunk/drivers/dma/sh/shdma-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,65 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan)
return NULL;
}

static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
{
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
const struct shdma_ops *ops = sdev->ops;
int ret;

if (slave_id < 0 || slave_id >= slave_num)
return -EINVAL;

if (test_and_set_bit(slave_id, shdma_slave_used))
return -EBUSY;

ret = ops->set_slave(schan, slave_id, false);
if (ret < 0) {
clear_bit(slave_id, shdma_slave_used);
return ret;
}

schan->slave_id = slave_id;

return 0;
}

/*
* This is the standard shdma filter function to be used as a replacement to the
* "old" method, using the .private pointer. If for some reason you allocate a
* channel without slave data, use something like ERR_PTR(-EINVAL) as a filter
* parameter. If this filter is used, the slave driver, after calling
* dma_request_channel(), will also have to call dmaengine_slave_config() with
* .slave_id, .direction, and either .src_addr or .dst_addr set.
* NOTE: this filter doesn't support multiple DMAC drivers with the DMA_SLAVE
* capability! If this becomes a requirement, hardware glue drivers, using this
* services would have to provide their own filters, which first would check
* the device driver, similar to how other DMAC drivers, e.g., sa11x0-dma.c, do
* this, and only then, in case of a match, call this common filter.
*/
bool shdma_chan_filter(struct dma_chan *chan, void *arg)
{
struct shdma_chan *schan = to_shdma_chan(chan);
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
const struct shdma_ops *ops = sdev->ops;
int slave_id = (int)arg;
int ret;

if (slave_id < 0)
/* No slave requested - arbitrary channel */
return true;

if (slave_id >= slave_num)
return false;

ret = ops->set_slave(schan, slave_id, true);
if (ret < 0)
return false;

return true;
}
EXPORT_SYMBOL(shdma_chan_filter);

static int shdma_alloc_chan_resources(struct dma_chan *chan)
{
struct shdma_chan *schan = to_shdma_chan(chan);
Expand All @@ -185,21 +244,10 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
* never runs concurrently with itself or free_chan_resources.
*/
if (slave) {
if (slave->slave_id < 0 || slave->slave_id >= slave_num) {
ret = -EINVAL;
goto evalid;
}

if (test_and_set_bit(slave->slave_id, shdma_slave_used)) {
ret = -EBUSY;
goto etestused;
}

ret = ops->set_slave(schan, slave->slave_id);
/* Legacy mode: .private is set in filter */
ret = shdma_setup_slave(schan, slave->slave_id);
if (ret < 0)
goto esetslave;

schan->slave_id = slave->slave_id;
} else {
schan->slave_id = -EINVAL;
}
Expand Down Expand Up @@ -228,8 +276,6 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
if (slave)
esetslave:
clear_bit(slave->slave_id, shdma_slave_used);
etestused:
evalid:
chan->private = NULL;
return ret;
}
Expand Down Expand Up @@ -587,22 +633,40 @@ static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
struct shdma_chan *schan = to_shdma_chan(chan);
struct shdma_dev *sdev = to_shdma_dev(chan->device);
const struct shdma_ops *ops = sdev->ops;
struct dma_slave_config *config;
unsigned long flags;

/* Only supports DMA_TERMINATE_ALL */
if (cmd != DMA_TERMINATE_ALL)
return -ENXIO;
int ret;

if (!chan)
return -EINVAL;

spin_lock_irqsave(&schan->chan_lock, flags);

ops->halt_channel(schan);

spin_unlock_irqrestore(&schan->chan_lock, flags);
switch (cmd) {
case DMA_TERMINATE_ALL:
spin_lock_irqsave(&schan->chan_lock, flags);
ops->halt_channel(schan);
spin_unlock_irqrestore(&schan->chan_lock, flags);

shdma_chan_ld_cleanup(schan, true);
shdma_chan_ld_cleanup(schan, true);
break;
case DMA_SLAVE_CONFIG:
/*
* So far only .slave_id is used, but the slave drivers are
* encouraged to also set a transfer direction and an address.
*/
if (!arg)
return -EINVAL;
/*
* We could lock this, but you shouldn't be configuring the
* channel, while using it...
*/
config = (struct dma_slave_config *)arg;
ret = shdma_setup_slave(schan, config->slave_id);
if (ret < 0)
return ret;
break;
default:
return -ENXIO;
}

return 0;
}
Expand Down
5 changes: 3 additions & 2 deletions trunk/drivers/dma/sh/shdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,15 +320,16 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
}

static int sh_dmae_set_slave(struct shdma_chan *schan,
int slave_id)
int slave_id, bool try)
{
struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
shdma_chan);
const struct sh_dmae_slave_config *cfg = dmae_find_slave(sh_chan, slave_id);
if (!cfg)
return -ENODEV;

sh_chan->config = cfg;
if (!try)
sh_chan->config = cfg;

return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/sh_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,6 @@ struct sh_dmae_pdata {
#define CHCR_TE 0x00000002
#define CHCR_IE 0x00000004

bool shdma_chan_filter(struct dma_chan *chan, void *arg);

#endif
2 changes: 1 addition & 1 deletion trunk/include/linux/shdma-base.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ struct shdma_ops {
dma_addr_t (*slave_addr)(struct shdma_chan *);
int (*desc_setup)(struct shdma_chan *, struct shdma_desc *,
dma_addr_t, dma_addr_t, size_t *);
int (*set_slave)(struct shdma_chan *, int);
int (*set_slave)(struct shdma_chan *, int, bool);
void (*setup_xfer)(struct shdma_chan *, int);
void (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
struct shdma_desc *(*embedded_desc)(void *, int);
Expand Down

0 comments on commit a09113b

Please sign in to comment.