mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 12:00:58 +07:00
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>
This commit is contained in:
parent
c517d838eb
commit
411fdaf846
@ -171,8 +171,7 @@ 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,
|
||||
dma_addr_t slave_addr)
|
||||
static int shdma_setup_slave(struct shdma_chan *schan, dma_addr_t slave_addr)
|
||||
{
|
||||
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
|
||||
const struct shdma_ops *ops = sdev->ops;
|
||||
@ -183,25 +182,23 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id,
|
||||
ret = ops->set_slave(schan, match, slave_addr, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
slave_id = schan->slave_id;
|
||||
} else {
|
||||
match = slave_id;
|
||||
match = schan->real_slave_id;
|
||||
}
|
||||
|
||||
if (slave_id < 0 || slave_id >= slave_num)
|
||||
if (schan->real_slave_id < 0 || schan->real_slave_id >= slave_num)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_and_set_bit(slave_id, shdma_slave_used))
|
||||
if (test_and_set_bit(schan->real_slave_id, shdma_slave_used))
|
||||
return -EBUSY;
|
||||
|
||||
ret = ops->set_slave(schan, match, slave_addr, false);
|
||||
if (ret < 0) {
|
||||
clear_bit(slave_id, shdma_slave_used);
|
||||
clear_bit(schan->real_slave_id, shdma_slave_used);
|
||||
return ret;
|
||||
}
|
||||
|
||||
schan->slave_id = slave_id;
|
||||
schan->slave_id = schan->real_slave_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -221,10 +218,12 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
|
||||
*/
|
||||
if (slave) {
|
||||
/* Legacy mode: .private is set in filter */
|
||||
ret = shdma_setup_slave(schan, slave->slave_id, 0);
|
||||
schan->real_slave_id = slave->slave_id;
|
||||
ret = shdma_setup_slave(schan, 0);
|
||||
if (ret < 0)
|
||||
goto esetslave;
|
||||
} else {
|
||||
/* Normal mode: real_slave_id was set by filter */
|
||||
schan->slave_id = -EINVAL;
|
||||
}
|
||||
|
||||
@ -258,11 +257,14 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
|
||||
|
||||
/*
|
||||
* 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
|
||||
* "old" method, using the .private pointer.
|
||||
* You always have to pass a valid slave id as the argument, old drivers that
|
||||
* pass ERR_PTR(-EINVAL) as a filter parameter and set it up in dma_slave_config
|
||||
* need to be updated so we can remove the slave_id field from dma_slave_config.
|
||||
* 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.
|
||||
* .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
|
||||
@ -276,7 +278,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg)
|
||||
{
|
||||
struct shdma_chan *schan;
|
||||
struct shdma_dev *sdev;
|
||||
int match = (long)arg;
|
||||
int slave_id = (long)arg;
|
||||
int ret;
|
||||
|
||||
/* Only support channels handled by this driver. */
|
||||
@ -284,19 +286,39 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg)
|
||||
shdma_alloc_chan_resources)
|
||||
return false;
|
||||
|
||||
if (match < 0)
|
||||
/* No slave requested - arbitrary channel */
|
||||
return true;
|
||||
|
||||
schan = to_shdma_chan(chan);
|
||||
if (!schan->dev->of_node && match >= slave_num)
|
||||
sdev = to_shdma_dev(chan->device);
|
||||
|
||||
/*
|
||||
* For DT, the schan->slave_id field is generated by the
|
||||
* set_slave function from the slave ID that is passed in
|
||||
* from xlate. For the non-DT case, the slave ID is
|
||||
* directly passed into the filter function by the driver
|
||||
*/
|
||||
if (schan->dev->of_node) {
|
||||
ret = sdev->ops->set_slave(schan, slave_id, 0, true);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
schan->real_slave_id = schan->slave_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (slave_id < 0) {
|
||||
/* No slave requested - arbitrary channel */
|
||||
dev_warn(sdev->dma_dev.dev, "invalid slave ID passed to dma_request_slave\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (slave_id >= slave_num)
|
||||
return false;
|
||||
|
||||
sdev = to_shdma_dev(schan->dma_chan.device);
|
||||
ret = sdev->ops->set_slave(schan, match, 0, true);
|
||||
ret = sdev->ops->set_slave(schan, slave_id, 0, true);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
schan->real_slave_id = slave_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(shdma_chan_filter);
|
||||
@ -452,6 +474,8 @@ static void shdma_free_chan_resources(struct dma_chan *chan)
|
||||
chan->private = NULL;
|
||||
}
|
||||
|
||||
schan->real_slave_id = 0;
|
||||
|
||||
spin_lock_irq(&schan->chan_lock);
|
||||
|
||||
list_splice_init(&schan->ld_free, &list);
|
||||
@ -764,11 +788,20 @@ static int shdma_config(struct dma_chan *chan,
|
||||
*/
|
||||
if (!config)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* overriding the slave_id through dma_slave_config is deprecated,
|
||||
* but possibly some out-of-tree drivers still do it.
|
||||
*/
|
||||
if (WARN_ON_ONCE(config->slave_id &&
|
||||
config->slave_id != schan->real_slave_id))
|
||||
schan->real_slave_id = config->slave_id;
|
||||
|
||||
/*
|
||||
* We could lock this, but you shouldn't be configuring the
|
||||
* channel, while using it...
|
||||
*/
|
||||
return shdma_setup_slave(schan, config->slave_id,
|
||||
return shdma_setup_slave(schan,
|
||||
config->direction == DMA_DEV_TO_MEM ?
|
||||
config->src_addr : config->dst_addr);
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ struct shdma_chan {
|
||||
int id; /* Raw id of this channel */
|
||||
int irq; /* Channel IRQ */
|
||||
int slave_id; /* Client ID for slave DMA */
|
||||
int real_slave_id; /* argument passed to filter function */
|
||||
int hw_req; /* DMA request line for slave DMA - same
|
||||
* as MID/RID, used with DT */
|
||||
enum shdma_pm_state pm_state;
|
||||
|
Loading…
Reference in New Issue
Block a user