dmaengine updates for 4.4-rc1

This time we have a very typical update which is mostly fixes and updates to
 drivers and no new drivers.
 
 - Biggest change is coming from Peter for edma cleanup which even caused
   some last minute regression, things seem settled now
 - idma64 and dw updates
 - iotdma updates
 - module autoload fixes for various drivers
 - scatter gather support for hdmac
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWP1vYAAoJEHwUBw8lI4NHKg8QAKwJ/iPxZDMfWwCLAoZoeaDp
 GgOmxIZ3LWrFQHIziI1IUcxSAU28Z+N6GBziaXycw49oQic4J/ukHGhgxwI2GM/W
 JGbFzHalnwdGqKzVZyfWGV0njT3KRvwKl7qqb66ZhikF5lD5imga66QGGxof8wBK
 uoXra7yycrE8nGpyY5Gdd4H59aWVyAK1fW6+0cxa2kMfWo8vLkgj/olbzYZydhQz
 DFCEvx2hbTyP/8VjGybVhtd+oeLjX43tGJOm6weyCb/8z3/soD73CChZIP53Mt6i
 g+LKPfurRZ3VGILgdemkiMB+5pXi4jhmziw5pCSI6BluUGVZAMyg8hC1zapFUr/2
 HaLfVmtxYdsBlceuMss1f3vyN2d+kRdDPKlOb9Td0PC2TEpSa5QayuMscvVfau+Q
 epSdIxgjlHqAVDVZJ0kX55FLdmItx36tat6zJL5cUcZmrDvEY3TQmvcXyR2dIltY
 U9WB2lRaETOG4Js0gAItXDjijNvLs0F4q10Zk6RdH4BcWbuqvONAhaCpWKeOWNsf
 NgQkkg+DqHqol6+C0pI0uX6dvEfwJuZ4bqq98wl4SryuxWJNra/g55/oFEFDbJCU
 oRMPYguMUgV8tzCpAurmDhxcrsZu/dvaSSW+flVz2QP81ecvFjRnZ8hhXbCr6iWi
 VVoAISmQBQPCXoqPr7ZC
 =tIzO
 -----END PGP SIGNATURE-----

Merge tag 'dmaengine-4.4-rc1' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine updates from Vinod Koul:
 "This time we have a very typical update which is mostly fixes and
  updates to drivers and no new drivers.

   - the biggest change is coming from Peter for edma cleanup which even
     caused some last minute regression, things seem settled now
   - idma64 and dw updates
   - iotdma updates
   - module autoload fixes for various drivers
   - scatter gather support for hdmac"

* tag 'dmaengine-4.4-rc1' of git://git.infradead.org/users/vkoul/slave-dma: (77 commits)
  dmaengine: edma: Add dummy driver skeleton for edma3-tptc
  Revert "ARM: DTS: am33xx: Use the new DT bindings for the eDMA3"
  Revert "ARM: DTS: am437x: Use the new DT bindings for the eDMA3"
  dmaengine: dw: some Intel devices has no memcpy support
  dmaengine: dw: platform: provide platform data for Intel
  dmaengine: dw: don't override platform data with autocfg
  dmaengine: hdmac: Add scatter-gathered memset support
  dmaengine: hdmac: factorise memset descriptor allocation
  dmaengine: virt-dma: Fix kernel-doc annotations
  ARM: DTS: am437x: Use the new DT bindings for the eDMA3
  ARM: DTS: am33xx: Use the new DT bindings for the eDMA3
  dmaengine: edma: New device tree binding
  dmaengine: Kconfig: edma: Select TI_DMA_CROSSBAR in case of ARCH_OMAP
  dmaengine: ti-dma-crossbar: Add support for crossbar on AM33xx/AM43xx
  dmaengine: edma: Merge the of parsing functions
  dmaengine: edma: Do not allocate memory for edma_rsv_info in case of DT boot
  dmaengine: edma: Refactor the dma device and channel struct initialization
  dmaengine: edma: Get qDMA channel information from HW also
  dmaengine: edma: Merge map_dmach_to_queue into assign_channel_eventq
  dmaengine: edma: Correct PaRAM access function names (_parm_ to _param_)
  ...
This commit is contained in:
Linus Torvalds 2015-11-10 10:05:17 -08:00
commit 041c79514a
46 changed files with 2533 additions and 2684 deletions

View file

@ -229,7 +229,7 @@ config IMX_SDMA
Support the i.MX SDMA engine. This engine is integrated into
Freescale i.MX25/31/35/51/53/6 chips.
config IDMA64
config INTEL_IDMA64
tristate "Intel integrated DMA 64-bit support"
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
@ -486,7 +486,7 @@ config TI_EDMA
depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
select TI_PRIV_EDMA
select TI_DMA_CROSSBAR if ARCH_OMAP
default n
help
Enable support for the TI EDMA controller. This DMA

View file

@ -34,7 +34,7 @@ obj-$(CONFIG_HSU_DMA) += hsu/
obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
obj-$(CONFIG_IMX_DMA) += imx-dma.o
obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
obj-$(CONFIG_IDMA64) += idma64.o
obj-$(CONFIG_INTEL_IDMA64) += idma64.o
obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o

View file

@ -161,10 +161,8 @@ int acpi_dma_controller_register(struct device *dev,
return -EINVAL;
/* Check if the device was enumerated by ACPI */
if (!ACPI_HANDLE(dev))
return -EINVAL;
if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev))
adev = ACPI_COMPANION(dev);
if (!adev)
return -EINVAL;
adma = kzalloc(sizeof(*adma), GFP_KERNEL);
@ -359,10 +357,11 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
int found;
/* Check if the device was enumerated by ACPI */
if (!dev || !ACPI_HANDLE(dev))
if (!dev)
return ERR_PTR(-ENODEV);
if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev))
adev = ACPI_COMPANION(dev);
if (!adev)
return ERR_PTR(-ENODEV);
memset(&pdata, 0, sizeof(pdata));

View file

@ -458,10 +458,10 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
dma_cookie_complete(txd);
/* If the transfer was a memset, free our temporary buffer */
if (desc->memset) {
if (desc->memset_buffer) {
dma_pool_free(atdma->memset_pool, desc->memset_vaddr,
desc->memset_paddr);
desc->memset = false;
desc->memset_buffer = false;
}
/* move children to free_list */
@ -881,6 +881,46 @@ err_desc_get:
return NULL;
}
static struct at_desc *atc_create_memset_desc(struct dma_chan *chan,
dma_addr_t psrc,
dma_addr_t pdst,
size_t len)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
struct at_desc *desc;
size_t xfer_count;
u32 ctrla = ATC_SRC_WIDTH(2) | ATC_DST_WIDTH(2);
u32 ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN |
ATC_SRC_ADDR_MODE_FIXED |
ATC_DST_ADDR_MODE_INCR |
ATC_FC_MEM2MEM;
xfer_count = len >> 2;
if (xfer_count > ATC_BTSIZE_MAX) {
dev_err(chan2dev(chan), "%s: buffer is too big\n",
__func__);
return NULL;
}
desc = atc_desc_get(atchan);
if (!desc) {
dev_err(chan2dev(chan), "%s: can't get a descriptor\n",
__func__);
return NULL;
}
desc->lli.saddr = psrc;
desc->lli.daddr = pdst;
desc->lli.ctrla = ctrla | xfer_count;
desc->lli.ctrlb = ctrlb;
desc->txd.cookie = 0;
desc->len = len;
return desc;
}
/**
* atc_prep_dma_memset - prepare a memcpy operation
* @chan: the channel to prepare operation on
@ -893,12 +933,10 @@ static struct dma_async_tx_descriptor *
atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
size_t len, unsigned long flags)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
struct at_dma *atdma = to_at_dma(chan->device);
struct at_desc *desc = NULL;
size_t xfer_count;
u32 ctrla;
u32 ctrlb;
struct at_desc *desc;
void __iomem *vaddr;
dma_addr_t paddr;
dev_vdbg(chan2dev(chan), "%s: d0x%x v0x%x l0x%zx f0x%lx\n", __func__,
dest, value, len, flags);
@ -914,46 +952,26 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
return NULL;
}
xfer_count = len >> 2;
if (xfer_count > ATC_BTSIZE_MAX) {
dev_err(chan2dev(chan), "%s: buffer is too big\n",
__func__);
return NULL;
}
ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN
| ATC_SRC_ADDR_MODE_FIXED
| ATC_DST_ADDR_MODE_INCR
| ATC_FC_MEM2MEM;
ctrla = ATC_SRC_WIDTH(2) |
ATC_DST_WIDTH(2);
desc = atc_desc_get(atchan);
if (!desc) {
dev_err(chan2dev(chan), "%s: can't get a descriptor\n",
__func__);
return NULL;
}
desc->memset_vaddr = dma_pool_alloc(atdma->memset_pool, GFP_ATOMIC,
&desc->memset_paddr);
if (!desc->memset_vaddr) {
vaddr = dma_pool_alloc(atdma->memset_pool, GFP_ATOMIC, &paddr);
if (!vaddr) {
dev_err(chan2dev(chan), "%s: couldn't allocate buffer\n",
__func__);
goto err_put_desc;
return NULL;
}
*(u32*)vaddr = value;
desc = atc_create_memset_desc(chan, paddr, dest, len);
if (!desc) {
dev_err(chan2dev(chan), "%s: couldn't get a descriptor\n",
__func__);
goto err_free_buffer;
}
*desc->memset_vaddr = value;
desc->memset = true;
desc->lli.saddr = desc->memset_paddr;
desc->lli.daddr = dest;
desc->lli.ctrla = ctrla | xfer_count;
desc->lli.ctrlb = ctrlb;
desc->memset_paddr = paddr;
desc->memset_vaddr = vaddr;
desc->memset_buffer = true;
desc->txd.cookie = -EBUSY;
desc->len = len;
desc->total_len = len;
/* set end-of-link on the descriptor */
@ -963,11 +981,87 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
return &desc->txd;
err_put_desc:
atc_desc_put(atchan, desc);
err_free_buffer:
dma_pool_free(atdma->memset_pool, vaddr, paddr);
return NULL;
}
static struct dma_async_tx_descriptor *
atc_prep_dma_memset_sg(struct dma_chan *chan,
struct scatterlist *sgl,
unsigned int sg_len, int value,
unsigned long flags)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
struct at_dma *atdma = to_at_dma(chan->device);
struct at_desc *desc = NULL, *first = NULL, *prev = NULL;
struct scatterlist *sg;
void __iomem *vaddr;
dma_addr_t paddr;
size_t total_len = 0;
int i;
dev_vdbg(chan2dev(chan), "%s: v0x%x l0x%zx f0x%lx\n", __func__,
value, sg_len, flags);
if (unlikely(!sgl || !sg_len)) {
dev_dbg(chan2dev(chan), "%s: scatterlist is empty!\n",
__func__);
return NULL;
}
vaddr = dma_pool_alloc(atdma->memset_pool, GFP_ATOMIC, &paddr);
if (!vaddr) {
dev_err(chan2dev(chan), "%s: couldn't allocate buffer\n",
__func__);
return NULL;
}
*(u32*)vaddr = value;
for_each_sg(sgl, sg, sg_len, i) {
dma_addr_t dest = sg_dma_address(sg);
size_t len = sg_dma_len(sg);
dev_vdbg(chan2dev(chan), "%s: d0x%08x, l0x%zx\n",
__func__, dest, len);
if (!is_dma_fill_aligned(chan->device, dest, 0, len)) {
dev_err(chan2dev(chan), "%s: buffer is not aligned\n",
__func__);
goto err_put_desc;
}
desc = atc_create_memset_desc(chan, paddr, dest, len);
if (!desc)
goto err_put_desc;
atc_desc_chain(&first, &prev, desc);
total_len += len;
}
/*
* Only set the buffer pointers on the last descriptor to
* avoid free'ing while we have our transfer still going
*/
desc->memset_paddr = paddr;
desc->memset_vaddr = vaddr;
desc->memset_buffer = true;
first->txd.cookie = -EBUSY;
first->total_len = total_len;
/* set end-of-link on the descriptor */
set_desc_eol(desc);
first->txd.flags = flags;
return &first->txd;
err_put_desc:
atc_desc_put(atchan, first);
return NULL;
}
/**
* atc_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
@ -1851,6 +1945,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
dma_cap_set(DMA_INTERLEAVE, at91sam9g45_config.cap_mask);
dma_cap_set(DMA_MEMCPY, at91sam9g45_config.cap_mask);
dma_cap_set(DMA_MEMSET, at91sam9g45_config.cap_mask);
dma_cap_set(DMA_MEMSET_SG, at91sam9g45_config.cap_mask);
dma_cap_set(DMA_PRIVATE, at91sam9g45_config.cap_mask);
dma_cap_set(DMA_SLAVE, at91sam9g45_config.cap_mask);
dma_cap_set(DMA_SG, at91sam9g45_config.cap_mask);
@ -1972,6 +2067,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
if (dma_has_cap(DMA_MEMSET, atdma->dma_common.cap_mask)) {
atdma->dma_common.device_prep_dma_memset = atc_prep_dma_memset;
atdma->dma_common.device_prep_dma_memset_sg = atc_prep_dma_memset_sg;
atdma->dma_common.fill_align = DMAENGINE_ALIGN_4_BYTES;
}

View file

@ -202,7 +202,7 @@ struct at_desc {
size_t src_hole;
/* Memset temporary buffer */
bool memset;
bool memset_buffer;
dma_addr_t memset_paddr;
int *memset_vaddr;
};

View file

@ -938,13 +938,19 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
{
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac_desc *prev = NULL, *first = NULL;
struct data_chunk *chunk, *prev_chunk = NULL;
dma_addr_t dst_addr, src_addr;
size_t dst_skip, src_skip, len = 0;
size_t prev_dst_icg = 0, prev_src_icg = 0;
size_t src_skip = 0, dst_skip = 0, len = 0;
struct data_chunk *chunk;
int i;
if (!xt || (xt->numf != 1) || (xt->dir != DMA_MEM_TO_MEM))
if (!xt || !xt->numf || (xt->dir != DMA_MEM_TO_MEM))
return NULL;
/*
* TODO: Handle the case where we have to repeat a chain of
* descriptors...
*/
if ((xt->numf > 1) && (xt->frame_size > 1))
return NULL;
dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n",
@ -954,66 +960,60 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
src_addr = xt->src_start;
dst_addr = xt->dst_start;
for (i = 0; i < xt->frame_size; i++) {
struct at_xdmac_desc *desc;
size_t src_icg, dst_icg;
chunk = xt->sgl + i;
dst_icg = dmaengine_get_dst_icg(xt, chunk);
src_icg = dmaengine_get_src_icg(xt, chunk);
src_skip = chunk->size + src_icg;
dst_skip = chunk->size + dst_icg;
dev_dbg(chan2dev(chan),
"%s: chunk size=%d, src icg=%d, dst icg=%d\n",
__func__, chunk->size, src_icg, dst_icg);
/*
* Handle the case where we just have the same
* transfer to setup, we can just increase the
* block number and reuse the same descriptor.
*/
if (prev_chunk && prev &&
(prev_chunk->size == chunk->size) &&
(prev_src_icg == src_icg) &&
(prev_dst_icg == dst_icg)) {
dev_dbg(chan2dev(chan),
"%s: same configuration that the previous chunk, merging the descriptors...\n",
__func__);
at_xdmac_increment_block_count(chan, prev);
continue;
}
desc = at_xdmac_interleaved_queue_desc(chan, atchan,
prev,
src_addr, dst_addr,
xt, chunk);
if (!desc) {
list_splice_init(&first->descs_list,
&atchan->free_descs_list);
return NULL;
}
if (!first)
first = desc;
if (xt->numf > 1) {
first = at_xdmac_interleaved_queue_desc(chan, atchan,
NULL,
src_addr, dst_addr,
xt, xt->sgl);
for (i = 0; i < xt->numf; i++)
at_xdmac_increment_block_count(chan, first);
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
__func__, desc, first);
list_add_tail(&desc->desc_node, &first->descs_list);
__func__, first, first);
list_add_tail(&first->desc_node, &first->descs_list);
} else {
for (i = 0; i < xt->frame_size; i++) {
size_t src_icg = 0, dst_icg = 0;
struct at_xdmac_desc *desc;
if (xt->src_sgl)
src_addr += src_skip;
chunk = xt->sgl + i;
if (xt->dst_sgl)
dst_addr += dst_skip;
dst_icg = dmaengine_get_dst_icg(xt, chunk);
src_icg = dmaengine_get_src_icg(xt, chunk);
len += chunk->size;
prev_chunk = chunk;
prev_dst_icg = dst_icg;
prev_src_icg = src_icg;
prev = desc;
src_skip = chunk->size + src_icg;
dst_skip = chunk->size + dst_icg;
dev_dbg(chan2dev(chan),
"%s: chunk size=%d, src icg=%d, dst icg=%d\n",
__func__, chunk->size, src_icg, dst_icg);
desc = at_xdmac_interleaved_queue_desc(chan, atchan,
prev,
src_addr, dst_addr,
xt, chunk);
if (!desc) {
list_splice_init(&first->descs_list,
&atchan->free_descs_list);
return NULL;
}
if (!first)
first = desc;
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
__func__, desc, first);
list_add_tail(&desc->desc_node, &first->descs_list);
if (xt->src_sgl)
src_addr += src_skip;
if (xt->dst_sgl)
dst_addr += dst_skip;
len += chunk->size;
prev = desc;
}
}
first->tx_dma_desc.cookie = -EBUSY;

View file

@ -1074,11 +1074,9 @@ static void dmaengine_destroy_unmap_pool(void)
for (i = 0; i < ARRAY_SIZE(unmap_pool); i++) {
struct dmaengine_unmap_pool *p = &unmap_pool[i];
if (p->pool)
mempool_destroy(p->pool);
mempool_destroy(p->pool);
p->pool = NULL;
if (p->cache)
kmem_cache_destroy(p->cache);
kmem_cache_destroy(p->cache);
p->cache = NULL;
}
}

View file

@ -163,7 +163,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
/*----------------------------------------------------------------------*/
static inline unsigned int dwc_fast_fls(unsigned long long v)
static inline unsigned int dwc_fast_ffs(unsigned long long v)
{
/*
* We can be a lot more clever here, but this should take care
@ -712,7 +712,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
dw->data_width[dwc->dst_master]);
src_width = dst_width = min_t(unsigned int, data_width,
dwc_fast_fls(src | dest | len));
dwc_fast_ffs(src | dest | len));
ctllo = DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(dst_width)
@ -791,7 +791,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
switch (direction) {
case DMA_MEM_TO_DEV:
reg_width = __fls(sconfig->dst_addr_width);
reg_width = __ffs(sconfig->dst_addr_width);
reg = sconfig->dst_addr;
ctllo = (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(reg_width)
@ -811,7 +811,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
len = sg_dma_len(sg);
mem_width = min_t(unsigned int,
data_width, dwc_fast_fls(mem | len));
data_width, dwc_fast_ffs(mem | len));
slave_sg_todev_fill_desc:
desc = dwc_desc_get(dwc);
@ -848,7 +848,7 @@ slave_sg_todev_fill_desc:
}
break;
case DMA_DEV_TO_MEM:
reg_width = __fls(sconfig->src_addr_width);
reg_width = __ffs(sconfig->src_addr_width);
reg = sconfig->src_addr;
ctllo = (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_SRC_WIDTH(reg_width)
@ -868,7 +868,7 @@ slave_sg_todev_fill_desc:
len = sg_dma_len(sg);
mem_width = min_t(unsigned int,
data_width, dwc_fast_fls(mem | len));
data_width, dwc_fast_ffs(mem | len));
slave_sg_fromdev_fill_desc:
desc = dwc_desc_get(dwc);
@ -1499,9 +1499,8 @@ EXPORT_SYMBOL(dw_dma_cyclic_free);
int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
{
struct dw_dma *dw;
bool autocfg;
bool autocfg = false;
unsigned int dw_params;
unsigned int nr_channels;
unsigned int max_blk_size = 0;
int err;
int i;
@ -1515,33 +1514,42 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
pm_runtime_get_sync(chip->dev);
dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
autocfg = dw_params >> DW_PARAMS_EN & 0x1;
if (!pdata) {
dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params);
dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params);
autocfg = dw_params >> DW_PARAMS_EN & 1;
if (!autocfg) {
err = -EINVAL;
goto err_pdata;
}
if (!pdata && autocfg) {
pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
err = -ENOMEM;
goto err_pdata;
}
/* Get hardware configuration parameters */
pdata->nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 7) + 1;
pdata->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
for (i = 0; i < pdata->nr_masters; i++) {
pdata->data_width[i] =
(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
}
max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
/* Fill platform data with the default values */
pdata->is_private = true;
pdata->is_memcpy = true;
pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING;
pdata->chan_priority = CHAN_PRIORITY_ASCENDING;
} else if (!pdata || pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
} else if (pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
err = -EINVAL;
goto err_pdata;
}
if (autocfg)
nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 0x7) + 1;
else
nr_channels = pdata->nr_channels;
dw->chan = devm_kcalloc(chip->dev, nr_channels, sizeof(*dw->chan),
dw->chan = devm_kcalloc(chip->dev, pdata->nr_channels, sizeof(*dw->chan),
GFP_KERNEL);
if (!dw->chan) {
err = -ENOMEM;
@ -1549,22 +1557,12 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
}
/* Get hardware configuration parameters */
if (autocfg) {
max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
for (i = 0; i < dw->nr_masters; i++) {
dw->data_width[i] =
(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
}
} else {
dw->nr_masters = pdata->nr_masters;
for (i = 0; i < dw->nr_masters; i++)
dw->data_width[i] = pdata->data_width[i];
}
dw->nr_masters = pdata->nr_masters;
for (i = 0; i < dw->nr_masters; i++)
dw->data_width[i] = pdata->data_width[i];
/* Calculate all channel mask before DMA setup */
dw->all_chan_mask = (1 << nr_channels) - 1;
dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
/* Force dma off, just in case */
dw_dma_off(dw);
@ -1589,7 +1587,7 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
goto err_pdata;
INIT_LIST_HEAD(&dw->dma.channels);
for (i = 0; i < nr_channels; i++) {
for (i = 0; i < pdata->nr_channels; i++) {
struct dw_dma_chan *dwc = &dw->chan[i];
dwc->chan.device = &dw->dma;
@ -1602,7 +1600,7 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
/* 7 is highest priority & 0 is lowest. */
if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
dwc->priority = nr_channels - i - 1;
dwc->priority = pdata->nr_channels - i - 1;
else
dwc->priority = i;
@ -1656,10 +1654,13 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
/* Set capabilities */
dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
if (pdata->is_private)
dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask);
if (pdata->is_memcpy)
dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
dw->dma.dev = chip->dev;
dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources;
dw->dma.device_free_chan_resources = dwc_free_chan_resources;
@ -1687,7 +1688,7 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
goto err_dma_register;
dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
nr_channels);
pdata->nr_channels);
pm_runtime_put_sync_suspend(chip->dev);

View file

@ -15,12 +15,6 @@
#include "internal.h"
static struct dw_dma_platform_data dw_pci_pdata = {
.is_private = 1,
.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
.chan_priority = CHAN_PRIORITY_ASCENDING,
};
static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
{
struct dw_dma_chip *chip;
@ -101,19 +95,19 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
static const struct pci_device_id dw_pci_id_table[] = {
/* Medfield */
{ PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x0830), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x0827) },
{ PCI_VDEVICE(INTEL, 0x0830) },
/* BayTrail */
{ PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x0f06) },
{ PCI_VDEVICE(INTEL, 0x0f40) },
/* Braswell */
{ PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x2286) },
{ PCI_VDEVICE(INTEL, 0x22c0) },
/* Haswell */
{ PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x9c60) },
{ }
};
MODULE_DEVICE_TABLE(pci, dw_pci_id_table);

View file

@ -155,6 +155,7 @@ static int dw_probe(struct platform_device *pdev)
struct dw_dma_chip *chip;
struct device *dev = &pdev->dev;
struct resource *mem;
const struct acpi_device_id *id;
struct dw_dma_platform_data *pdata;
int err;
@ -178,6 +179,11 @@ static int dw_probe(struct platform_device *pdev)
pdata = dev_get_platdata(dev);
if (!pdata)
pdata = dw_dma_parse_dt(pdev);
if (!pdata && has_acpi_companion(dev)) {
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (id)
pdata = (struct dw_dma_platform_data *)id->driver_data;
}
chip->dev = dev;
@ -246,8 +252,17 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
#endif
#ifdef CONFIG_ACPI
static struct dw_dma_platform_data dw_dma_acpi_pdata = {
.nr_channels = 8,
.is_private = true,
.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
.chan_priority = CHAN_PRIORITY_ASCENDING,
.block_size = 4095,
.nr_masters = 2,
};
static const struct acpi_device_id dw_dma_acpi_id_table[] = {
{ "INTL9C60", 0 },
{ "INTL9C60", (kernel_ulong_t)&dw_dma_acpi_pdata },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);

File diff suppressed because it is too large Load diff

View file

@ -1512,6 +1512,7 @@ static const struct of_device_id fsldma_of_ids[] = {
{ .compatible = "fsl,elo-dma", },
{}
};
MODULE_DEVICE_TABLE(of, fsldma_of_ids);
static struct platform_driver fsldma_of_driver = {
.driver = {

View file

@ -65,9 +65,6 @@ static void idma64_chan_init(struct idma64 *idma64, struct idma64_chan *idma64c)
u32 cfghi = IDMA64C_CFGH_SRC_PER(1) | IDMA64C_CFGH_DST_PER(0);
u32 cfglo = 0;
/* Enforce FIFO drain when channel is suspended */
cfglo |= IDMA64C_CFGL_CH_DRAIN;
/* Set default burst alignment */
cfglo |= IDMA64C_CFGL_DST_BURST_ALIGN | IDMA64C_CFGL_SRC_BURST_ALIGN;
@ -257,15 +254,15 @@ static u64 idma64_hw_desc_fill(struct idma64_hw_desc *hw,
dar = config->dst_addr;
ctllo |= IDMA64C_CTLL_DST_FIX | IDMA64C_CTLL_SRC_INC |
IDMA64C_CTLL_FC_M2P;
src_width = min_t(u32, 2, __fls(sar | hw->len));
dst_width = __fls(config->dst_addr_width);
src_width = __ffs(sar | hw->len | 4);
dst_width = __ffs(config->dst_addr_width);
} else { /* DMA_DEV_TO_MEM */
sar = config->src_addr;
dar = hw->phys;
ctllo |= IDMA64C_CTLL_DST_INC | IDMA64C_CTLL_SRC_FIX |
IDMA64C_CTLL_FC_P2M;
src_width = __fls(config->src_addr_width);
dst_width = min_t(u32, 2, __fls(dar | hw->len));
src_width = __ffs(config->src_addr_width);
dst_width = __ffs(dar | hw->len | 4);
}
lli->sar = sar;
@ -428,12 +425,17 @@ static int idma64_slave_config(struct dma_chan *chan,
return 0;
}
static void idma64_chan_deactivate(struct idma64_chan *idma64c)
static void idma64_chan_deactivate(struct idma64_chan *idma64c, bool drain)
{
unsigned short count = 100;
u32 cfglo;
cfglo = channel_readl(idma64c, CFG_LO);
if (drain)
cfglo |= IDMA64C_CFGL_CH_DRAIN;
else
cfglo &= ~IDMA64C_CFGL_CH_DRAIN;
channel_writel(idma64c, CFG_LO, cfglo | IDMA64C_CFGL_CH_SUSP);
do {
udelay(1);
@ -456,7 +458,7 @@ static int idma64_pause(struct dma_chan *chan)
spin_lock_irqsave(&idma64c->vchan.lock, flags);
if (idma64c->desc && idma64c->desc->status == DMA_IN_PROGRESS) {
idma64_chan_deactivate(idma64c);
idma64_chan_deactivate(idma64c, false);
idma64c->desc->status = DMA_PAUSED;
}
spin_unlock_irqrestore(&idma64c->vchan.lock, flags);
@ -486,7 +488,7 @@ static int idma64_terminate_all(struct dma_chan *chan)
LIST_HEAD(head);
spin_lock_irqsave(&idma64c->vchan.lock, flags);
idma64_chan_deactivate(idma64c);
idma64_chan_deactivate(idma64c, true);
idma64_stop_transfer(idma64c);
if (idma64c->desc) {
idma64_vdesc_free(&idma64c->desc->vdesc);

View file

@ -16,6 +16,8 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm-generic/io-64-nonatomic-lo-hi.h>
#include "virt-dma.h"
/* Channel registers */
@ -166,19 +168,13 @@ static inline void idma64c_writel(struct idma64_chan *idma64c, int offset,
static inline u64 idma64c_readq(struct idma64_chan *idma64c, int offset)
{
u64 l, h;
l = idma64c_readl(idma64c, offset);
h = idma64c_readl(idma64c, offset + 4);
return l | (h << 32);
return lo_hi_readq(idma64c->regs + offset);
}
static inline void idma64c_writeq(struct idma64_chan *idma64c, int offset,
u64 value)
{
idma64c_writel(idma64c, offset, value);
idma64c_writel(idma64c, offset + 4, value >> 32);
lo_hi_writeq(value, idma64c->regs + offset);
}
#define channel_readq(idma64c, reg) \
@ -217,7 +213,7 @@ static inline void idma64_writel(struct idma64 *idma64, int offset, u32 value)
idma64_writel(idma64, IDMA64_##reg, (value))
/**
* struct idma64_chip - representation of DesignWare DMA controller hardware
* struct idma64_chip - representation of iDMA 64-bit controller hardware
* @dev: struct device of the DMA controller
* @irq: irq line
* @regs: memory mapped I/O space

View file

@ -1478,7 +1478,7 @@ static int __init sdma_event_remap(struct sdma_engine *sdma)
event_remap = of_find_property(np, propname, NULL);
num_map = event_remap ? (event_remap->length / sizeof(u32)) : 0;
if (!num_map) {
dev_warn(sdma->dev, "no event needs to be remapped\n");
dev_dbg(sdma->dev, "no event needs to be remapped\n");
goto out;
} else if (num_map % EVENT_REMAP_CELLS) {
dev_err(sdma->dev, "the property %s must modulo %d\n",
@ -1826,8 +1826,6 @@ static int sdma_probe(struct platform_device *pdev)
of_node_put(spba_bus);
}
dev_info(sdma->dev, "initialized\n");
return 0;
err_register:
@ -1852,7 +1850,6 @@ static int sdma_remove(struct platform_device *pdev)
}
platform_set_drvdata(pdev, NULL);
dev_info(&pdev->dev, "Removed...\n");
return 0;
}

View file

@ -197,7 +197,8 @@ static void __ioat_start_null_desc(struct ioatdma_chan *ioat_chan)
void ioat_start_null_desc(struct ioatdma_chan *ioat_chan)
{
spin_lock_bh(&ioat_chan->prep_lock);
__ioat_start_null_desc(ioat_chan);
if (!test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
__ioat_start_null_desc(ioat_chan);
spin_unlock_bh(&ioat_chan->prep_lock);
}

View file

@ -82,8 +82,9 @@ struct ioatdma_device {
struct dma_pool *sed_hw_pool[MAX_SED_POOLS];
struct dma_device dma_dev;
u8 version;
struct msix_entry msix_entries[4];
struct ioatdma_chan *idx[4];
#define IOAT_MAX_CHANS 4
struct msix_entry msix_entries[IOAT_MAX_CHANS];
struct ioatdma_chan *idx[IOAT_MAX_CHANS];
struct dca_provider *dca;
enum ioat_irq_mode irq_mode;
u32 cap;
@ -95,6 +96,7 @@ struct ioatdma_chan {
dma_addr_t last_completion;
spinlock_t cleanup_lock;
unsigned long state;
#define IOAT_CHAN_DOWN 0
#define IOAT_COMPLETION_ACK 1
#define IOAT_RESET_PENDING 2
#define IOAT_KOBJ_INIT_FAIL 3

View file

@ -27,6 +27,7 @@
#include <linux/workqueue.h>
#include <linux/prefetch.h>
#include <linux/dca.h>
#include <linux/aer.h>
#include "dma.h"
#include "registers.h"
#include "hw.h"
@ -1186,13 +1187,116 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca)
return 0;
}
static void ioat_shutdown(struct pci_dev *pdev)
{
struct ioatdma_device *ioat_dma = pci_get_drvdata(pdev);
struct ioatdma_chan *ioat_chan;
int i;
if (!ioat_dma)
return;
for (i = 0; i < IOAT_MAX_CHANS; i++) {
ioat_chan = ioat_dma->idx[i];
if (!ioat_chan)
continue;
spin_lock_bh(&ioat_chan->prep_lock);
set_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
del_timer_sync(&ioat_chan->timer);
spin_unlock_bh(&ioat_chan->prep_lock);
/* this should quiesce then reset */
ioat_reset_hw(ioat_chan);
}
ioat_disable_interrupts(ioat_dma);
}
void ioat_resume(struct ioatdma_device *ioat_dma)
{
struct ioatdma_chan *ioat_chan;
u32 chanerr;
int i;
for (i = 0; i < IOAT_MAX_CHANS; i++) {
ioat_chan = ioat_dma->idx[i];
if (!ioat_chan)
continue;
spin_lock_bh(&ioat_chan->prep_lock);
clear_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
spin_unlock_bh(&ioat_chan->prep_lock);
chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
/* no need to reset as shutdown already did that */
}
}
#define DRV_NAME "ioatdma"
static pci_ers_result_t ioat_pcie_error_detected(struct pci_dev *pdev,
enum pci_channel_state error)
{
dev_dbg(&pdev->dev, "%s: PCIe AER error %d\n", DRV_NAME, error);
/* quiesce and block I/O */
ioat_shutdown(pdev);
return PCI_ERS_RESULT_NEED_RESET;
}
static pci_ers_result_t ioat_pcie_error_slot_reset(struct pci_dev *pdev)
{
pci_ers_result_t result = PCI_ERS_RESULT_RECOVERED;
int err;
dev_dbg(&pdev->dev, "%s post reset handling\n", DRV_NAME);
if (pci_enable_device_mem(pdev) < 0) {
dev_err(&pdev->dev,
"Failed to enable PCIe device after reset.\n");
result = PCI_ERS_RESULT_DISCONNECT;
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
pci_wake_from_d3(pdev, false);
}
err = pci_cleanup_aer_uncorrect_error_status(pdev);
if (err) {
dev_err(&pdev->dev,
"AER uncorrect error status clear failed: %#x\n", err);
}
return result;
}
static void ioat_pcie_error_resume(struct pci_dev *pdev)
{
struct ioatdma_device *ioat_dma = pci_get_drvdata(pdev);
dev_dbg(&pdev->dev, "%s: AER handling resuming\n", DRV_NAME);
/* initialize and bring everything back */
ioat_resume(ioat_dma);
}
static const struct pci_error_handlers ioat_err_handler = {
.error_detected = ioat_pcie_error_detected,
.slot_reset = ioat_pcie_error_slot_reset,
.resume = ioat_pcie_error_resume,
};
static struct pci_driver ioat_pci_driver = {
.name = DRV_NAME,
.id_table = ioat_pci_tbl,
.probe = ioat_pci_probe,
.remove = ioat_remove,
.shutdown = ioat_shutdown,
.err_handler = &ioat_err_handler,
};
static struct ioatdma_device *
@ -1245,13 +1349,17 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, device);
device->version = readb(device->reg_base + IOAT_VER_OFFSET);
if (device->version >= IOAT_VER_3_0)
if (device->version >= IOAT_VER_3_0) {
err = ioat3_dma_probe(device, ioat_dca_enabled);
else
if (device->version >= IOAT_VER_3_3)
pci_enable_pcie_error_reporting(pdev);
} else
return -ENODEV;
if (err) {
dev_err(dev, "Intel(R) I/OAT DMA Engine init failed\n");
pci_disable_pcie_error_reporting(pdev);
return -ENODEV;
}
@ -1271,6 +1379,8 @@ static void ioat_remove(struct pci_dev *pdev)
free_dca_provider(device->dca);
device->dca = NULL;
}
pci_disable_pcie_error_reporting(pdev);
ioat_dma_remove(device);
}

View file

@ -121,6 +121,9 @@ ioat_dma_prep_memcpy_lock(struct dma_chan *c, dma_addr_t dma_dest,
size_t total_len = len;
int num_descs, idx, i;
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
num_descs = ioat_xferlen_to_descs(ioat_chan, len);
if (likely(num_descs) &&
ioat_check_space_lock(ioat_chan, num_descs) == 0)
@ -254,6 +257,11 @@ struct dma_async_tx_descriptor *
ioat_prep_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
unsigned int src_cnt, size_t len, unsigned long flags)
{
struct ioatdma_chan *ioat_chan = to_ioat_chan(chan);
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
return __ioat_prep_xor_lock(chan, NULL, dest, src, src_cnt, len, flags);
}
@ -262,6 +270,11 @@ ioat_prep_xor_val(struct dma_chan *chan, dma_addr_t *src,
unsigned int src_cnt, size_t len,
enum sum_check_flags *result, unsigned long flags)
{
struct ioatdma_chan *ioat_chan = to_ioat_chan(chan);
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
/* the cleanup routine only sets bits on validate failure, it
* does not clear bits on validate success... so clear it here
*/
@ -574,6 +587,11 @@ ioat_prep_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
unsigned int src_cnt, const unsigned char *scf, size_t len,
unsigned long flags)
{
struct ioatdma_chan *ioat_chan = to_ioat_chan(chan);
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
/* specify valid address for disabled result */
if (flags & DMA_PREP_PQ_DISABLE_P)
dst[0] = dst[1];
@ -614,6 +632,11 @@ ioat_prep_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
unsigned int src_cnt, const unsigned char *scf, size_t len,
enum sum_check_flags *pqres, unsigned long flags)
{
struct ioatdma_chan *ioat_chan = to_ioat_chan(chan);
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
/* specify valid address for disabled result */
if (flags & DMA_PREP_PQ_DISABLE_P)
pq[0] = pq[1];
@ -638,6 +661,10 @@ ioat_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src,
{
unsigned char scf[MAX_SCF];
dma_addr_t pq[2];
struct ioatdma_chan *ioat_chan = to_ioat_chan(chan);
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
if (src_cnt > MAX_SCF)
return NULL;
@ -661,6 +688,10 @@ ioat_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src,
{
unsigned char scf[MAX_SCF];
dma_addr_t pq[2];
struct ioatdma_chan *ioat_chan = to_ioat_chan(chan);
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
if (src_cnt > MAX_SCF)
return NULL;
@ -689,6 +720,9 @@ ioat_prep_interrupt_lock(struct dma_chan *c, unsigned long flags)
struct ioat_ring_ent *desc;
struct ioat_dma_descriptor *hw;
if (test_bit(IOAT_CHAN_DOWN, &ioat_chan->state))
return NULL;
if (ioat_check_space_lock(ioat_chan, 1) == 0)
desc = ioat_get_ring_ent(ioat_chan, ioat_chan->head);
else

View file

@ -652,6 +652,7 @@ static const struct of_device_id moxart_dma_match[] = {
{ .compatible = "moxa,moxart-dma" },
{ }
};
MODULE_DEVICE_TABLE(of, moxart_dma_match);
static struct platform_driver moxart_driver = {
.probe = moxart_probe,

View file

@ -1073,6 +1073,7 @@ static const struct of_device_id mpc_dma_match[] = {
{ .compatible = "fsl,mpc8308-dma", },
{},
};
MODULE_DEVICE_TABLE(of, mpc_dma_match);
static struct platform_driver mpc_dma_driver = {
.probe = mpc_dma_probe,

View file

@ -935,8 +935,12 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(
else
d->ccr |= CCR_SYNC_ELEMENT;
if (dir == DMA_DEV_TO_MEM)
if (dir == DMA_DEV_TO_MEM) {
d->ccr |= CCR_TRIGGER_SRC;
d->csdp |= CSDP_DST_PACKED;
} else {
d->csdp |= CSDP_SRC_PACKED;
}
d->cicr |= CICR_MISALIGNED_ERR_IE | CICR_TRANS_ERR_IE;

View file

@ -1149,6 +1149,7 @@ static const struct of_device_id sirfsoc_dma_match[] = {
{ .compatible = "sirf,atlas7-dmac-v2", .data = &sirfsoc_dmadata_a7v2,},
{},
};
MODULE_DEVICE_TABLE(of, sirfsoc_dma_match);
static struct platform_driver sirfsoc_dma_driver = {
.probe = sirfsoc_dma_probe,

View file

@ -2907,7 +2907,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
if (err) {
d40_err(base->dev,
"Failed to regsiter memcpy only channels\n");
"Failed to register memcpy only channels\n");
goto failure2;
}

View file

@ -908,6 +908,7 @@ static const struct of_device_id sun6i_dma_match[] = {
{ .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun6i_dma_match);
static int sun6i_dma_probe(struct platform_device *pdev)
{

View file

@ -17,13 +17,184 @@
#include <linux/of_device.h>
#include <linux/of_dma.h>
#define TI_XBAR_OUTPUTS 127
#define TI_XBAR_INPUTS 256
#define TI_XBAR_DRA7 0
#define TI_XBAR_AM335X 1
static const struct of_device_id ti_dma_xbar_match[] = {
{
.compatible = "ti,dra7-dma-crossbar",
.data = (void *)TI_XBAR_DRA7,
},
{
.compatible = "ti,am335x-edma-crossbar",
.data = (void *)TI_XBAR_AM335X,
},
{},
};
/* Crossbar on AM335x/AM437x family */
#define TI_AM335X_XBAR_LINES 64
struct ti_am335x_xbar_data {
void __iomem *iomem;
struct dma_router dmarouter;
u32 xbar_events; /* maximum number of events to select in xbar */
u32 dma_requests; /* number of DMA requests on eDMA */
};
struct ti_am335x_xbar_map {
u16 dma_line;
u16 mux_val;
};
static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u16 val)
{
writeb_relaxed(val & 0x1f, iomem + event);
}
static void ti_am335x_xbar_free(struct device *dev, void *route_data)
{
struct ti_am335x_xbar_data *xbar = dev_get_drvdata(dev);
struct ti_am335x_xbar_map *map = route_data;
dev_dbg(dev, "Unmapping XBAR event %u on channel %u\n",
map->mux_val, map->dma_line);
ti_am335x_xbar_write(xbar->iomem, map->dma_line, 0);
kfree(map);
}
static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev);
struct ti_am335x_xbar_map *map;
if (dma_spec->args_count != 3)
return ERR_PTR(-EINVAL);
if (dma_spec->args[2] >= xbar->xbar_events) {
dev_err(&pdev->dev, "Invalid XBAR event number: %d\n",
dma_spec->args[2]);
return ERR_PTR(-EINVAL);
}
if (dma_spec->args[0] >= xbar->dma_requests) {
dev_err(&pdev->dev, "Invalid DMA request line number: %d\n",
dma_spec->args[0]);
return ERR_PTR(-EINVAL);
}
/* The of_node_put() will be done in the core for the node */
dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
if (!dma_spec->np) {
dev_err(&pdev->dev, "Can't get DMA master\n");
return ERR_PTR(-EINVAL);
}
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map) {
of_node_put(dma_spec->np);
return ERR_PTR(-ENOMEM);
}
map->dma_line = (u16)dma_spec->args[0];
map->mux_val = (u16)dma_spec->args[2];
dma_spec->args[2] = 0;
dma_spec->args_count = 2;
dev_dbg(&pdev->dev, "Mapping XBAR event%u to DMA%u\n",
map->mux_val, map->dma_line);
ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val);
return map;
}
static const struct of_device_id ti_am335x_master_match[] = {
{ .compatible = "ti,edma3-tpcc", },
{},
};
static int ti_am335x_xbar_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *dma_node;
struct ti_am335x_xbar_data *xbar;
struct resource *res;
void __iomem *iomem;
int i, ret;
if (!node)
return -ENODEV;
xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
if (!xbar)
return -ENOMEM;
dma_node = of_parse_phandle(node, "dma-masters", 0);
if (!dma_node) {
dev_err(&pdev->dev, "Can't get DMA master node\n");
return -ENODEV;
}
match = of_match_node(ti_am335x_master_match, dma_node);
if (!match) {
dev_err(&pdev->dev, "DMA master is not supported\n");
return -EINVAL;
}
if (of_property_read_u32(dma_node, "dma-requests",
&xbar->dma_requests)) {
dev_info(&pdev->dev,
"Missing XBAR output information, using %u.\n",
TI_AM335X_XBAR_LINES);
xbar->dma_requests = TI_AM335X_XBAR_LINES;
}
of_node_put(dma_node);
if (of_property_read_u32(node, "dma-requests", &xbar->xbar_events)) {
dev_info(&pdev->dev,
"Missing XBAR input information, using %u.\n",
TI_AM335X_XBAR_LINES);
xbar->xbar_events = TI_AM335X_XBAR_LINES;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iomem = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(iomem))
return PTR_ERR(iomem);
xbar->iomem = iomem;
xbar->dmarouter.dev = &pdev->dev;
xbar->dmarouter.route_free = ti_am335x_xbar_free;
platform_set_drvdata(pdev, xbar);
/* Reset the crossbar */
for (i = 0; i < xbar->dma_requests; i++)
ti_am335x_xbar_write(xbar->iomem, i, 0);
ret = of_dma_router_register(node, ti_am335x_xbar_route_allocate,
&xbar->dmarouter);
return ret;
}
/* Crossbar on DRA7xx family */
#define TI_DRA7_XBAR_OUTPUTS 127
#define TI_DRA7_XBAR_INPUTS 256
#define TI_XBAR_EDMA_OFFSET 0
#define TI_XBAR_SDMA_OFFSET 1
struct ti_dma_xbar_data {
struct ti_dra7_xbar_data {
void __iomem *iomem;
struct dma_router dmarouter;
@ -35,35 +206,35 @@ struct ti_dma_xbar_data {
u32 dma_offset;
};
struct ti_dma_xbar_map {
struct ti_dra7_xbar_map {
u16 xbar_in;
int xbar_out;
};
static inline void ti_dma_xbar_write(void __iomem *iomem, int xbar, u16 val)
static inline void ti_dra7_xbar_write(void __iomem *iomem, int xbar, u16 val)
{
writew_relaxed(val, iomem + (xbar * 2));
}
static void ti_dma_xbar_free(struct device *dev, void *route_data)
static void ti_dra7_xbar_free(struct device *dev, void *route_data)
{
struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
struct ti_dma_xbar_map *map = route_data;
struct ti_dra7_xbar_data *xbar = dev_get_drvdata(dev);
struct ti_dra7_xbar_map *map = route_data;
dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n",
map->xbar_in, map->xbar_out);
ti_dma_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
idr_remove(&xbar->map_idr, map->xbar_out);
kfree(map);
}
static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
struct ti_dma_xbar_data *xbar = platform_get_drvdata(pdev);
struct ti_dma_xbar_map *map;
struct ti_dra7_xbar_data *xbar = platform_get_drvdata(pdev);
struct ti_dra7_xbar_map *map;
if (dma_spec->args[0] >= xbar->xbar_requests) {
dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
@ -93,12 +264,12 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec,
dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n",
map->xbar_in, map->xbar_out);
ti_dma_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
return map;
}
static const struct of_device_id ti_dma_master_match[] = {
static const struct of_device_id ti_dra7_master_match[] = {
{
.compatible = "ti,omap4430-sdma",
.data = (void *)TI_XBAR_SDMA_OFFSET,
@ -110,12 +281,12 @@ static const struct of_device_id ti_dma_master_match[] = {
{},
};
static int ti_dma_xbar_probe(struct platform_device *pdev)
static int ti_dra7_xbar_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *dma_node;
struct ti_dma_xbar_data *xbar;
struct ti_dra7_xbar_data *xbar;
struct resource *res;
u32 safe_val;
void __iomem *iomem;
@ -136,7 +307,7 @@ static int ti_dma_xbar_probe(struct platform_device *pdev)
return -ENODEV;
}
match = of_match_node(ti_dma_master_match, dma_node);
match = of_match_node(ti_dra7_master_match, dma_node);
if (!match) {
dev_err(&pdev->dev, "DMA master is not supported\n");
return -EINVAL;
@ -146,16 +317,16 @@ static int ti_dma_xbar_probe(struct platform_device *pdev)
&xbar->dma_requests)) {
dev_info(&pdev->dev,
"Missing XBAR output information, using %u.\n",
TI_XBAR_OUTPUTS);
xbar->dma_requests = TI_XBAR_OUTPUTS;
TI_DRA7_XBAR_OUTPUTS);
xbar->dma_requests = TI_DRA7_XBAR_OUTPUTS;
}
of_node_put(dma_node);
if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
dev_info(&pdev->dev,
"Missing XBAR input information, using %u.\n",
TI_XBAR_INPUTS);
xbar->xbar_requests = TI_XBAR_INPUTS;
TI_DRA7_XBAR_INPUTS);
xbar->xbar_requests = TI_DRA7_XBAR_INPUTS;
}
if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
@ -169,30 +340,50 @@ static int ti_dma_xbar_probe(struct platform_device *pdev)
xbar->iomem = iomem;
xbar->dmarouter.dev = &pdev->dev;
xbar->dmarouter.route_free = ti_dma_xbar_free;
xbar->dmarouter.route_free = ti_dra7_xbar_free;
xbar->dma_offset = (u32)match->data;
platform_set_drvdata(pdev, xbar);
/* Reset the crossbar */
for (i = 0; i < xbar->dma_requests; i++)
ti_dma_xbar_write(xbar->iomem, i, xbar->safe_val);
ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val);
ret = of_dma_router_register(node, ti_dma_xbar_route_allocate,
ret = of_dma_router_register(node, ti_dra7_xbar_route_allocate,
&xbar->dmarouter);
if (ret) {
/* Restore the defaults for the crossbar */
for (i = 0; i < xbar->dma_requests; i++)
ti_dma_xbar_write(xbar->iomem, i, i);
ti_dra7_xbar_write(xbar->iomem, i, i);
}
return ret;
}
static const struct of_device_id ti_dma_xbar_match[] = {
{ .compatible = "ti,dra7-dma-crossbar" },
{},
};
static int ti_dma_xbar_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
int ret;
match = of_match_node(ti_dma_xbar_match, pdev->dev.of_node);
if (unlikely(!match))
return -EINVAL;
switch ((u32)match->data) {
case TI_XBAR_DRA7:
ret = ti_dra7_xbar_probe(pdev);
break;
case TI_XBAR_AM335X:
ret = ti_am335x_xbar_probe(pdev);
break;
default:
dev_err(&pdev->dev, "Unsupported crossbar\n");
ret = -ENODEV;
break;
}
return ret;
}
static struct platform_driver ti_dma_xbar_driver = {
.driver = {

View file

@ -47,9 +47,9 @@ struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *, dma_cookie_t);
/**
* vchan_tx_prep - prepare a descriptor
* vc: virtual channel allocating this descriptor
* vd: virtual descriptor to prepare
* tx_flags: flags argument passed in to prepare function
* @vc: virtual channel allocating this descriptor
* @vd: virtual descriptor to prepare
* @tx_flags: flags argument passed in to prepare function
*/
static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan *vc,
struct virt_dma_desc *vd, unsigned long tx_flags)
@ -65,7 +65,7 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
/**
* vchan_issue_pending - move submitted descriptors to issued list
* vc: virtual channel to update
* @vc: virtual channel to update
*
* vc.lock must be held by caller
*/
@ -77,7 +77,7 @@ static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
/**
* vchan_cookie_complete - report completion of a descriptor
* vd: virtual descriptor to update
* @vd: virtual descriptor to update
*
* vc.lock must be held by caller
*/
@ -97,7 +97,7 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
/**
* vchan_cyclic_callback - report the completion of a period
* vd: virtual descriptor
* @vd: virtual descriptor
*/
static inline void vchan_cyclic_callback(struct virt_dma_desc *vd)
{
@ -109,7 +109,7 @@ static inline void vchan_cyclic_callback(struct virt_dma_desc *vd)
/**
* vchan_next_desc - peek at the next descriptor to be processed
* vc: virtual channel to obtain descriptor from
* @vc: virtual channel to obtain descriptor from
*
* vc.lock must be held by caller
*/
@ -123,8 +123,8 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
/**
* vchan_get_all_descriptors - obtain all submitted and issued descriptors
* vc: virtual channel to get descriptors from
* head: list of descriptors found
* @vc: virtual channel to get descriptors from
* @head: list of descriptors found
*
* vc.lock must be held by caller
*

View file

@ -547,14 +547,12 @@ static struct xgene_dma_desc_sw *xgene_dma_alloc_descriptor(
struct xgene_dma_desc_sw *desc;
dma_addr_t phys;
desc = dma_pool_alloc(chan->desc_pool, GFP_NOWAIT, &phys);
desc = dma_pool_zalloc(chan->desc_pool, GFP_NOWAIT, &phys);
if (!desc) {
chan_err(chan, "Failed to allocate LDs\n");
return NULL;
}
memset(desc, 0, sizeof(*desc));
INIT_LIST_HEAD(&desc->tx_list);
desc->tx.phys = phys;
desc->tx.tx_submit = xgene_dma_tx_submit;
@ -894,60 +892,6 @@ static void xgene_dma_free_chan_resources(struct dma_chan *dchan)
chan->desc_pool = NULL;
}
static struct dma_async_tx_descriptor *xgene_dma_prep_memcpy(
struct dma_chan *dchan, dma_addr_t dst, dma_addr_t src,
size_t len, unsigned long flags)
{
struct xgene_dma_desc_sw *first = NULL, *new;
struct xgene_dma_chan *chan;
size_t copy;
if (unlikely(!dchan || !len))
return NULL;
chan = to_dma_chan(dchan);
do {
/* Allocate the link descriptor from DMA pool */
new = xgene_dma_alloc_descriptor(chan);
if (!new)
goto fail;
/* Create the largest transaction possible */
copy = min_t(size_t, len, XGENE_DMA_MAX_64B_DESC_BYTE_CNT);
/* Prepare DMA descriptor */
xgene_dma_prep_cpy_desc(chan, new, dst, src, copy);
if (!first)
first = new;
new->tx.cookie = 0;
async_tx_ack(&new->tx);
/* Update metadata */
len -= copy;
dst += copy;
src += copy;
/* Insert the link descriptor to the LD ring */
list_add_tail(&new->node, &first->tx_list);
} while (len);
new->tx.flags = flags; /* client is in control of this ack */
new->tx.cookie = -EBUSY;
list_splice(&first->tx_list, &new->tx_list);
return &new->tx;
fail:
if (!first)
return NULL;
xgene_dma_free_desc_list(chan, &first->tx_list);
return NULL;
}
static struct dma_async_tx_descriptor *xgene_dma_prep_sg(
struct dma_chan *dchan, struct scatterlist *dst_sg,
u32 dst_nents, struct scatterlist *src_sg,
@ -1707,7 +1651,6 @@ static void xgene_dma_set_caps(struct xgene_dma_chan *chan,
dma_cap_zero(dma_dev->cap_mask);
/* Set DMA device capability */
dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
dma_cap_set(DMA_SG, dma_dev->cap_mask);
/* Basically here, the X-Gene SoC DMA engine channel 0 supports XOR
@ -1734,7 +1677,6 @@ static void xgene_dma_set_caps(struct xgene_dma_chan *chan,
dma_dev->device_free_chan_resources = xgene_dma_free_chan_resources;
dma_dev->device_issue_pending = xgene_dma_issue_pending;
dma_dev->device_tx_status = xgene_dma_tx_status;
dma_dev->device_prep_dma_memcpy = xgene_dma_prep_memcpy;
dma_dev->device_prep_dma_sg = xgene_dma_prep_sg;
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
@ -1787,8 +1729,7 @@ static int xgene_dma_async_register(struct xgene_dma *pdma, int id)
/* DMA capability info */
dev_info(pdma->dev,
"%s: CAPABILITY ( %s%s%s%s)\n", dma_chan_name(&chan->dma_chan),
dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "MEMCPY " : "",
"%s: CAPABILITY ( %s%s%s)\n", dma_chan_name(&chan->dma_chan),
dma_has_cap(DMA_SG, dma_dev->cap_mask) ? "SGCPY " : "",
dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "XOR " : "",
dma_has_cap(DMA_PQ, dma_dev->cap_mask) ? "PQ " : "");

View file

@ -1349,6 +1349,7 @@ static const struct of_device_id xilinx_vdma_of_ids[] = {
{ .compatible = "xlnx,axi-vdma-1.00.a",},
{}
};
MODULE_DEVICE_TABLE(of, xilinx_vdma_of_ids);
static struct platform_driver xilinx_vdma_driver = {
.driver = {

View file

@ -441,7 +441,7 @@ static struct zx_dma_desc_sw *zx_alloc_desc_resource(int num,
kfree(ds);
return NULL;
}
memset(ds->desc_hw, sizeof(struct zx_desc_hw) * num, 0);
memset(ds->desc_hw, 0, sizeof(struct zx_desc_hw) * num);
ds->desc_num = num;
return ds;
}