mirror of
https://github.com/torvalds/linux.git
synced 2026-09-29 04:22:03 +02:00
Merge branch 'topic/config_prep_api' into next
This commit is contained in:
commit
678a0f8580
|
|
@ -80,6 +80,10 @@ The details of these operations are:
|
|||
|
||||
- slave_sg: DMA a list of scatter gather buffers from/to a peripheral
|
||||
|
||||
- config_sg: Similar with slave_sg, just pass down dma_slave_config
|
||||
struct to avoid calling dmaengine_slave_config() every time adjusting the
|
||||
burst length or the FIFO address is needed.
|
||||
|
||||
- peripheral_dma_vec: DMA an array of scatter gather buffers from/to a
|
||||
peripheral. Similar to slave_sg, but uses an array of dma_vec
|
||||
structures instead of a scatterlist.
|
||||
|
|
@ -106,6 +110,11 @@ The details of these operations are:
|
|||
unsigned int sg_len, enum dma_data_direction direction,
|
||||
unsigned long flags);
|
||||
|
||||
struct dma_async_tx_descriptor *dmaengine_prep_config_sg(
|
||||
struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction dir,
|
||||
unsigned long flags, struct dma_slave_config *config);
|
||||
|
||||
struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
|
||||
struct dma_chan *chan, const struct dma_vec *vecs,
|
||||
size_t nents, enum dma_data_direction direction,
|
||||
|
|
|
|||
|
|
@ -795,7 +795,6 @@ static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
|
|||
struct dma_slave_config config;
|
||||
dma_async_tx_callback callback;
|
||||
struct atmel_aes_dma *dma;
|
||||
int err;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.src_addr_width = addr_width;
|
||||
|
|
@ -820,12 +819,9 @@ static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = dmaengine_slave_config(dma->chan, &config);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
desc = dmaengine_prep_slave_sg(dma->chan, dma->sg, dma->sg_len, dir,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
desc = dmaengine_prep_config_sg(dma->chan, dma->sg, dma->sg_len, dir,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
|
||||
&config);
|
||||
if (!desc)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -1100,6 +1100,8 @@ static int __dma_async_device_channel_register(struct dma_device *device,
|
|||
chan->dev->device.parent = device->dev;
|
||||
chan->dev->chan = chan;
|
||||
chan->dev->dev_id = device->dev_id;
|
||||
spin_lock_init(&chan->lock);
|
||||
|
||||
if (!name)
|
||||
dev_set_name(&chan->dev->device, "dma%dchan%d", device->dev_id, chan->chan_id);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -267,6 +267,20 @@ static int dw_edma_device_config(struct dma_chan *dchan,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dma_slave_config *
|
||||
dw_edma_device_get_config(struct dma_chan *dchan,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct dw_edma_chan *chan;
|
||||
|
||||
if (config)
|
||||
return config;
|
||||
|
||||
chan = dchan2dw_edma_chan(dchan);
|
||||
|
||||
return &chan->config;
|
||||
}
|
||||
|
||||
static int dw_edma_device_pause(struct dma_chan *dchan)
|
||||
{
|
||||
struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
|
||||
|
|
@ -385,7 +399,8 @@ dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
|
|||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
dw_edma_device_transfer(struct dw_edma_transfer *xfer)
|
||||
dw_edma_device_transfer(struct dw_edma_transfer *xfer,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
|
||||
enum dma_transfer_direction dir = xfer->direction;
|
||||
|
|
@ -472,8 +487,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
|
|||
src_addr = xfer->xfer.il->src_start;
|
||||
dst_addr = xfer->xfer.il->dst_start;
|
||||
} else {
|
||||
src_addr = chan->config.src_addr;
|
||||
dst_addr = chan->config.dst_addr;
|
||||
src_addr = config->src_addr;
|
||||
dst_addr = config->dst_addr;
|
||||
}
|
||||
|
||||
if (dir == DMA_DEV_TO_MEM)
|
||||
|
|
@ -577,10 +592,11 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
|
|||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
|
||||
unsigned int len,
|
||||
enum dma_transfer_direction direction,
|
||||
unsigned long flags, void *context)
|
||||
dw_edma_device_prep_config_sg(struct dma_chan *dchan, struct scatterlist *sgl,
|
||||
unsigned int len,
|
||||
enum dma_transfer_direction direction,
|
||||
unsigned long flags,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct dw_edma_transfer xfer;
|
||||
|
||||
|
|
@ -591,7 +607,10 @@ dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
|
|||
xfer.flags = flags;
|
||||
xfer.type = EDMA_XFER_SCATTER_GATHER;
|
||||
|
||||
return dw_edma_device_transfer(&xfer);
|
||||
if (config && dw_edma_device_config(dchan, config))
|
||||
return NULL;
|
||||
|
||||
return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, config));
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
|
|
@ -610,7 +629,7 @@ dw_edma_device_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t paddr,
|
|||
xfer.flags = flags;
|
||||
xfer.type = EDMA_XFER_CYCLIC;
|
||||
|
||||
return dw_edma_device_transfer(&xfer);
|
||||
return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
|
|
@ -626,7 +645,7 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan,
|
|||
xfer.flags = flags;
|
||||
xfer.type = EDMA_XFER_INTERLEAVED;
|
||||
|
||||
return dw_edma_device_transfer(&xfer);
|
||||
return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
|
||||
}
|
||||
|
||||
static void dw_hdma_set_callback_result(struct virt_dma_desc *vd,
|
||||
|
|
@ -970,7 +989,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
|
|||
dma->device_terminate_all = dw_edma_device_terminate_all;
|
||||
dma->device_issue_pending = dw_edma_device_issue_pending;
|
||||
dma->device_tx_status = dw_edma_device_tx_status;
|
||||
dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
|
||||
dma->device_prep_config_sg = dw_edma_device_prep_config_sg;
|
||||
dma->device_prep_dma_cyclic = dw_edma_device_prep_dma_cyclic;
|
||||
dma->device_prep_interleaved_dma = dw_edma_device_prep_interleaved_dma;
|
||||
|
||||
|
|
|
|||
|
|
@ -210,9 +210,7 @@ struct nvmet_pci_epf {
|
|||
|
||||
bool dma_enabled;
|
||||
struct dma_chan *dma_tx_chan;
|
||||
struct mutex dma_tx_lock;
|
||||
struct dma_chan *dma_rx_chan;
|
||||
struct mutex dma_rx_lock;
|
||||
|
||||
struct mutex mmio_lock;
|
||||
|
||||
|
|
@ -295,9 +293,6 @@ static void nvmet_pci_epf_init_dma(struct nvmet_pci_epf *nvme_epf)
|
|||
struct dma_chan *chan;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
mutex_init(&nvme_epf->dma_rx_lock);
|
||||
mutex_init(&nvme_epf->dma_tx_lock);
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
|
|
@ -336,8 +331,6 @@ static void nvmet_pci_epf_init_dma(struct nvmet_pci_epf *nvme_epf)
|
|||
nvme_epf->dma_rx_chan = NULL;
|
||||
|
||||
out_dma_no_rx:
|
||||
mutex_destroy(&nvme_epf->dma_rx_lock);
|
||||
mutex_destroy(&nvme_epf->dma_tx_lock);
|
||||
nvme_epf->dma_enabled = false;
|
||||
|
||||
dev_info(&epf->dev, "DMA not supported, falling back to MMIO\n");
|
||||
|
|
@ -352,8 +345,6 @@ static void nvmet_pci_epf_deinit_dma(struct nvmet_pci_epf *nvme_epf)
|
|||
nvme_epf->dma_tx_chan = NULL;
|
||||
dma_release_channel(nvme_epf->dma_rx_chan);
|
||||
nvme_epf->dma_rx_chan = NULL;
|
||||
mutex_destroy(&nvme_epf->dma_rx_lock);
|
||||
mutex_destroy(&nvme_epf->dma_tx_lock);
|
||||
nvme_epf->dma_enabled = false;
|
||||
}
|
||||
|
||||
|
|
@ -368,18 +359,15 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
|
|||
struct dma_chan *chan;
|
||||
dma_cookie_t cookie;
|
||||
dma_addr_t dma_addr;
|
||||
struct mutex *lock;
|
||||
int ret;
|
||||
|
||||
switch (dir) {
|
||||
case DMA_FROM_DEVICE:
|
||||
lock = &nvme_epf->dma_rx_lock;
|
||||
chan = nvme_epf->dma_rx_chan;
|
||||
sconf.direction = DMA_DEV_TO_MEM;
|
||||
sconf.src_addr = seg->pci_addr;
|
||||
break;
|
||||
case DMA_TO_DEVICE:
|
||||
lock = &nvme_epf->dma_tx_lock;
|
||||
chan = nvme_epf->dma_tx_chan;
|
||||
sconf.direction = DMA_MEM_TO_DEV;
|
||||
sconf.dst_addr = seg->pci_addr;
|
||||
|
|
@ -388,22 +376,15 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(lock);
|
||||
|
||||
dma_dev = dmaengine_get_dma_device(chan);
|
||||
dma_addr = dma_map_single(dma_dev, seg->buf, seg->length, dir);
|
||||
ret = dma_mapping_error(dma_dev, dma_addr);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
ret = dmaengine_slave_config(chan, &sconf);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to configure DMA channel\n");
|
||||
goto unmap;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(chan, dma_addr, seg->length,
|
||||
sconf.direction, DMA_CTRL_ACK);
|
||||
desc = dmaengine_prep_config_single_safe(chan, dma_addr, seg->length,
|
||||
sconf.direction,
|
||||
DMA_CTRL_ACK, &sconf);
|
||||
if (!desc) {
|
||||
dev_err(dev, "Failed to prepare DMA\n");
|
||||
ret = -EIO;
|
||||
|
|
@ -420,16 +401,12 @@ static int nvmet_pci_epf_dma_transfer(struct nvmet_pci_epf *nvme_epf,
|
|||
if (dma_sync_wait(chan, cookie) != DMA_COMPLETE) {
|
||||
dev_err(dev, "DMA transfer failed\n");
|
||||
ret = -EIO;
|
||||
dmaengine_terminate_sync(chan);
|
||||
}
|
||||
|
||||
dmaengine_terminate_sync(chan);
|
||||
|
||||
unmap:
|
||||
dma_unmap_single(dma_dev, dma_addr, seg->length, dir);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -328,12 +328,6 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
config.direction = DMA_DEV_TO_MEM;
|
||||
config.src_addr = buf_info->host_addr;
|
||||
|
||||
ret = dmaengine_slave_config(chan, &config);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to configure DMA channel\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
|
||||
DMA_FROM_DEVICE);
|
||||
ret = dma_mapping_error(dma_dev, dst_addr);
|
||||
|
|
@ -342,9 +336,10 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
goto err_unlock;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
|
||||
desc = dmaengine_prep_config_single(chan, dst_addr, buf_info->size,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
|
||||
&config);
|
||||
if (!desc) {
|
||||
dev_err(dev, "Failed to prepare DMA\n");
|
||||
ret = -EIO;
|
||||
|
|
@ -401,12 +396,6 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
config.direction = DMA_MEM_TO_DEV;
|
||||
config.dst_addr = buf_info->host_addr;
|
||||
|
||||
ret = dmaengine_slave_config(chan, &config);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to configure DMA channel\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
|
||||
DMA_TO_DEVICE);
|
||||
ret = dma_mapping_error(dma_dev, src_addr);
|
||||
|
|
@ -415,9 +404,10 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
goto err_unlock;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
|
||||
desc = dmaengine_prep_config_single(chan, src_addr, buf_info->size,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
|
||||
&config);
|
||||
if (!desc) {
|
||||
dev_err(dev, "Failed to prepare DMA\n");
|
||||
ret = -EIO;
|
||||
|
|
@ -506,12 +496,6 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
config.direction = DMA_DEV_TO_MEM;
|
||||
config.src_addr = buf_info->host_addr;
|
||||
|
||||
ret = dmaengine_slave_config(chan, &config);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to configure DMA channel\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
|
||||
DMA_FROM_DEVICE);
|
||||
ret = dma_mapping_error(dma_dev, dst_addr);
|
||||
|
|
@ -520,9 +504,10 @@ static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
goto err_unlock;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
|
||||
desc = dmaengine_prep_config_single(chan, dst_addr, buf_info->size,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
|
||||
&config);
|
||||
if (!desc) {
|
||||
dev_err(dev, "Failed to prepare DMA\n");
|
||||
ret = -EIO;
|
||||
|
|
@ -585,12 +570,6 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
config.direction = DMA_MEM_TO_DEV;
|
||||
config.dst_addr = buf_info->host_addr;
|
||||
|
||||
ret = dmaengine_slave_config(chan, &config);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to configure DMA channel\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
|
||||
DMA_TO_DEVICE);
|
||||
ret = dma_mapping_error(dma_dev, src_addr);
|
||||
|
|
@ -599,9 +578,10 @@ static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
|
|||
goto err_unlock;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
|
||||
desc = dmaengine_prep_config_single(chan, src_addr, buf_info->size,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_CTRL_ACK | DMA_PREP_INTERRUPT,
|
||||
&config);
|
||||
if (!desc) {
|
||||
dev_err(dev, "Failed to prepare DMA\n");
|
||||
ret = -EIO;
|
||||
|
|
|
|||
|
|
@ -183,12 +183,8 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
|
|||
else
|
||||
sconf.src_addr = dma_remote;
|
||||
|
||||
if (dmaengine_slave_config(chan, &sconf)) {
|
||||
dev_err(dev, "DMA slave config fail\n");
|
||||
return -EIO;
|
||||
}
|
||||
tx = dmaengine_prep_slave_single(chan, dma_local, len, dir,
|
||||
flags);
|
||||
tx = dmaengine_prep_config_single(chan, dma_local, len,
|
||||
dir, flags, &sconf);
|
||||
} else {
|
||||
tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len,
|
||||
flags);
|
||||
|
|
|
|||
|
|
@ -322,6 +322,8 @@ struct dma_router {
|
|||
* @slave: ptr to the device using this channel
|
||||
* @cookie: last cookie value returned to client
|
||||
* @completed_cookie: last completed cookie for this channel
|
||||
* @lock: protect between config and prepare transfer when driver have not
|
||||
* implemented callback device_prep_config_sg().
|
||||
* @chan_id: channel ID for sysfs
|
||||
* @dev: class device for sysfs
|
||||
* @name: backlink name for sysfs
|
||||
|
|
@ -341,6 +343,12 @@ struct dma_chan {
|
|||
dma_cookie_t cookie;
|
||||
dma_cookie_t completed_cookie;
|
||||
|
||||
/*
|
||||
* protect between config and prepare transfer because *_prep() may be
|
||||
* called from complete callback, which is in GFP_NOSLEEP context.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
/* sysfs */
|
||||
int chan_id;
|
||||
struct dma_chan_dev *dev;
|
||||
|
|
@ -835,6 +843,7 @@ struct dma_filter {
|
|||
* where the address and size of each segment is located in one entry of
|
||||
* the dma_vec array.
|
||||
* @device_prep_slave_sg: prepares a slave dma operation
|
||||
* @device_prep_config_sg: prepares a slave DMA operation with dma_slave_config
|
||||
* @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
|
||||
* The function takes a buffer of size buf_len. The callback function will
|
||||
* be called after period_len bytes have been transferred.
|
||||
|
|
@ -934,6 +943,10 @@ struct dma_device {
|
|||
struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction direction,
|
||||
unsigned long flags, void *context);
|
||||
struct dma_async_tx_descriptor *(*device_prep_config_sg)(
|
||||
struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction direction,
|
||||
unsigned long flags, struct dma_slave_config *config);
|
||||
struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
|
||||
struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
|
||||
size_t period_len, enum dma_transfer_direction direction,
|
||||
|
|
@ -974,22 +987,44 @@ static inline bool is_slave_direction(enum dma_transfer_direction direction)
|
|||
(direction == DMA_DEV_TO_DEV);
|
||||
}
|
||||
|
||||
static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
|
||||
struct dma_chan *chan, dma_addr_t buf, size_t len,
|
||||
enum dma_transfer_direction dir, unsigned long flags)
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_config_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
|
||||
enum dma_transfer_direction dir,
|
||||
unsigned long flags,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct scatterlist sg;
|
||||
|
||||
if (!chan || !chan->device)
|
||||
return NULL;
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_dma_address(&sg) = buf;
|
||||
sg_dma_len(&sg) = len;
|
||||
|
||||
if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
|
||||
if (chan->device->device_prep_config_sg)
|
||||
return chan->device->device_prep_config_sg(chan, &sg, 1, dir,
|
||||
flags, config);
|
||||
|
||||
if (config)
|
||||
if (dmaengine_slave_config(chan, config))
|
||||
return NULL;
|
||||
|
||||
if (!chan->device->device_prep_slave_sg)
|
||||
return NULL;
|
||||
|
||||
return chan->device->device_prep_slave_sg(chan, &sg, 1,
|
||||
dir, flags, NULL);
|
||||
}
|
||||
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_slave_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
|
||||
enum dma_transfer_direction dir,
|
||||
unsigned long flags)
|
||||
{
|
||||
return dmaengine_prep_config_single(chan, buf, len, dir, flags, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor
|
||||
* @chan: The channel to be used for this descriptor
|
||||
|
|
@ -1010,17 +1045,115 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
|
|||
dir, flags);
|
||||
}
|
||||
|
||||
static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
|
||||
struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
|
||||
enum dma_transfer_direction dir, unsigned long flags)
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_config_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction dir,
|
||||
unsigned long flags, struct dma_slave_config *config)
|
||||
{
|
||||
if (!chan || !chan->device || !chan->device->device_prep_slave_sg)
|
||||
if (!chan || !chan->device)
|
||||
return NULL;
|
||||
|
||||
if (chan->device->device_prep_config_sg)
|
||||
return chan->device->device_prep_config_sg(chan, sgl, sg_len,
|
||||
dir, flags, config);
|
||||
|
||||
if (config)
|
||||
if (dmaengine_slave_config(chan, config))
|
||||
return NULL;
|
||||
|
||||
if (!chan->device->device_prep_slave_sg)
|
||||
return NULL;
|
||||
|
||||
return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
|
||||
dir, flags, NULL);
|
||||
}
|
||||
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction dir,
|
||||
unsigned long flags)
|
||||
{
|
||||
return dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_prep_config_sg_safe - prepare a scatter-gather DMA transfer
|
||||
* with atomic slave configuration update
|
||||
* @chan: DMA channel
|
||||
* @sgl: scatterlist for the transfer
|
||||
* @sg_len: number of entries in @sgl
|
||||
* @dir: DMA transfer direction
|
||||
* @flags: transfer preparation flags
|
||||
* @config: DMA slave configuration for this transfer
|
||||
*
|
||||
* Prepare a DMA scatter-gather transfer together with a corresponding slave
|
||||
* configuration update in a re-entrant and race-safe manner.
|
||||
*
|
||||
* DMA engine drivers may implement the optional
|
||||
* device_prep_config_sg() callback to perform both the slave configuration
|
||||
* and descriptor preparation atomically. In this case, the operation is
|
||||
* fully handled by the DMA engine driver.
|
||||
*
|
||||
* If the DMA engine driver does not implement device_prep_config_sg(), falls
|
||||
* back to calling dmaengine_slave_config() followed by dmaengine_prep_slave_sg().
|
||||
* The fallback path is protected by a per-channel spinlock to ensure that
|
||||
* concurrent callers cannot interleave configuration and descriptor preparation
|
||||
* on the same DMA channel.
|
||||
*
|
||||
* Return: Pointer to a prepared DMA async transaction descriptor on success,
|
||||
* or %NULL if the transfer could not be prepared.
|
||||
*/
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_config_sg_safe(struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len,
|
||||
enum dma_transfer_direction dir,
|
||||
unsigned long flags,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
unsigned long spinlock_flags;
|
||||
|
||||
if (!chan || !chan->device)
|
||||
return NULL;
|
||||
|
||||
if (!chan->device->device_prep_config_sg)
|
||||
spin_lock_irqsave(&chan->lock, spinlock_flags);
|
||||
|
||||
tx = dmaengine_prep_config_sg(chan, sgl, sg_len, dir, flags, config);
|
||||
|
||||
if (!chan->device->device_prep_config_sg)
|
||||
spin_unlock_irqrestore(&chan->lock, spinlock_flags);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_prep_config_single_safe - prepare a single-buffer DMA transfer
|
||||
* with atomic slave configuration update
|
||||
* @chan: DMA channel
|
||||
* @buf: DMA buffer address
|
||||
* @len: length of the transfer in bytes
|
||||
* @dir: DMA transfer direction
|
||||
* @flags: transfer preparation flags
|
||||
* @config: DMA slave configuration for this transfer
|
||||
*
|
||||
* Detail see dmaengine_prep_config_sg_safe().
|
||||
*/
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_config_single_safe(struct dma_chan *chan, dma_addr_t buf,
|
||||
size_t len, enum dma_transfer_direction dir,
|
||||
unsigned long flags,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct scatterlist sg;
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_dma_address(&sg) = buf;
|
||||
sg_dma_len(&sg) = len;
|
||||
|
||||
return dmaengine_prep_config_sg_safe(chan, &sg, 1, dir, flags, config);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RAPIDIO_DMA_ENGINE
|
||||
struct rio_dma_ext;
|
||||
static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user