* dma: axi-dmac: Split too large segments
From: Lars-Peter Clausen @ 2019-02-18 7:34 UTC (permalink / raw)
To: Ardelean, Alexandru, lkp@intel.com
Cc: kbuild-all@01.org, dmaengine@vger.kernel.org, vkoul@kernel.org
On 2/18/19 8:28 AM, Ardelean, Alexandru wrote:
> On Sat, 2019-02-16 at 17:03 +0800, kbuild test robot wrote:
>>
>
> My bad here.
> I took this patch from our kernel tree and sent it.
> I assumed it works, since it works in our tree.
> I'll take a look and see about the order of patches, and which one(s)
> need(s) to be sent before this one
https://github.com/analogdevicesinc/linux/commit/414a555896b2abca3518c3c878f21e7b1ea95904#diff-b5b2fd5430b4f9aff1ae97bae60dd5c5
That patch was sent upstream, not sure why it was never merged.
But if necessary you can also re-write this patch to not rely on the
other one.
^ permalink raw reply
* dma: axi-dmac: Split too large segments
From: Ardelean, Alexandru @ 2019-02-18 7:28 UTC (permalink / raw)
To: lkp@intel.com
Cc: kbuild-all@01.org, dmaengine@vger.kernel.org, vkoul@kernel.org,
lars@metafoo.de
On Sat, 2019-02-16 at 17:03 +0800, kbuild test robot wrote:
>
My bad here.
I took this patch from our kernel tree and sent it.
I assumed it works, since it works in our tree.
I'll take a look and see about the order of patches, and which one(s)
need(s) to be sent before this one
Thanks
Alex
>
> Hi Lars-Peter,
>
> I love your patch! Yet something to improve:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v5.0-rc4 next-20190215]
> [if your patch is applied to the wrong git tree, please drop us a note to
> help improve the system]
>
> url:
> https://github.com/0day-ci/linux/commits/Alexandru-Ardelean/dma-axi-dmac-Split-too-large-segments/20190216-160002
> config: nds32-allyesconfig (attached as .config)
> compiler: nds32le-linux-gcc (GCC) 6.4.0
> reproduce:
> wget
> https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross
> -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> GCC_VERSION=6.4.0 make.cross ARCH=nds32
>
> All errors (new ones prefixed by >>):
>
> drivers//dma/dma-axi-dmac.c: In function 'axi_dmac_prep_slave_sg':
> > > drivers//dma/dma-axi-dmac.c:443:12: error: implicit declaration of
> > > function 'sg_nents_for_dma' [-Werror=implicit-function-declaration]
>
> num_sgs = sg_nents_for_dma(sgl, sg_len, chan->max_length);
> ^~~~~~~~~~~~~~~~
> cc1: some warnings being treated as errors
>
> vim +/sg_nents_for_dma +443 drivers//dma/dma-axi-dmac.c
>
> 427
> 428 static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
> 429 struct dma_chan *c, struct scatterlist *sgl,
> 430 unsigned int sg_len, enum dma_transfer_direction
> direction,
> 431 unsigned long flags, void *context)
> 432 {
> 433 struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
> 434 struct axi_dmac_desc *desc;
> 435 struct axi_dmac_sg *dsg;
> 436 struct scatterlist *sg;
> 437 unsigned int num_sgs;
> 438 unsigned int i;
> 439
> 440 if (direction != chan->direction)
> 441 return NULL;
> 442
> > 443 num_sgs = sg_nents_for_dma(sgl, sg_len, chan-
> >max_length);
> 444 desc = axi_dmac_alloc_desc(num_sgs);
> 445 if (!desc)
> 446 return NULL;
> 447
> 448 dsg = desc->sg;
> 449
> 450 for_each_sg(sgl, sg, sg_len, i) {
> 451 if (!axi_dmac_check_addr(chan,
> sg_dma_address(sg)) ||
> 452 !axi_dmac_check_len(chan, sg_dma_len(sg))) {
> 453 kfree(desc);
> 454 return NULL;
> 455 }
> 456
> 457 dsg = axi_dmac_fill_linear_sg(chan, direction,
> sg_dma_address(sg), 1,
> 458 sg_dma_len(sg), dsg);
> 459 }
> 460
> 461 desc->cyclic = false;
> 462
> 463 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
> 464 }
> 465
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology
> Center
> https://lists.01.org/pipermail/kbuild-all Intel
> Corporation
^ permalink raw reply
* dma: axi-dmac: Split too large segments
From: kbuild test robot @ 2019-02-16 10:08 UTC (permalink / raw)
To: Alexandru Ardelean; +Cc: kbuild-all, dmaengine, vkoul, Lars-Peter Clausen
Hi Lars-Peter,
I love your patch! Yet something to improve:
[auto build test ERROR on linus/master]
[also build test ERROR on v5.0-rc4 next-20190215]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Alexandru-Ardelean/dma-axi-dmac-Split-too-large-segments/20190216-160002
config: xtensa-allyesconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 8.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=8.2.0 make.cross ARCH=xtensa
All errors (new ones prefixed by >>):
drivers/dma/dma-axi-dmac.c: In function 'axi_dmac_prep_slave_sg':
>> drivers/dma/dma-axi-dmac.c:443:12: error: implicit declaration of function 'sg_nents_for_dma'; did you mean 'sg_nents_for_len'? [-Werror=implicit-function-declaration]
num_sgs = sg_nents_for_dma(sgl, sg_len, chan->max_length);
^~~~~~~~~~~~~~~~
sg_nents_for_len
cc1: some warnings being treated as errors
vim +443 drivers/dma/dma-axi-dmac.c
427
428 static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
429 struct dma_chan *c, struct scatterlist *sgl,
430 unsigned int sg_len, enum dma_transfer_direction direction,
431 unsigned long flags, void *context)
432 {
433 struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
434 struct axi_dmac_desc *desc;
435 struct axi_dmac_sg *dsg;
436 struct scatterlist *sg;
437 unsigned int num_sgs;
438 unsigned int i;
439
440 if (direction != chan->direction)
441 return NULL;
442
> 443 num_sgs = sg_nents_for_dma(sgl, sg_len, chan->max_length);
444 desc = axi_dmac_alloc_desc(num_sgs);
445 if (!desc)
446 return NULL;
447
448 dsg = desc->sg;
449
450 for_each_sg(sgl, sg, sg_len, i) {
451 if (!axi_dmac_check_addr(chan, sg_dma_address(sg)) ||
452 !axi_dmac_check_len(chan, sg_dma_len(sg))) {
453 kfree(desc);
454 return NULL;
455 }
456
457 dsg = axi_dmac_fill_linear_sg(chan, direction, sg_dma_address(sg), 1,
458 sg_dma_len(sg), dsg);
459 }
460
461 desc->cyclic = false;
462
463 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
464 }
465
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply
* ARM64 boot failure on espressobin with 5.0.0-rc6 (1f947a7a011fcceb14cb912f5481a53b18f1879a)
From: John David Anglin @ 2019-02-15 16:05 UTC (permalink / raw)
To: Robin Murphy, Christoph Hellwig; +Cc: dmaengine, iommu, linux-arm-kernel
On 2019-02-14 12:58 p.m., Robin Murphy wrote:
> Hmm, having felt brave enough to take a closer look, it might actually be as simple as this - Dave, are you able to give the diff below a spin?
>
> Robin.
>
> ----->8-----
> diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
> index 7f595355fb79..fe4a7c71fede 100644
> --- a/drivers/dma/mv_xor.c
> +++ b/drivers/dma/mv_xor.c
> @@ -1059,6 +1059,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
> mv_chan->op_in_desc = XOR_MODE_IN_DESC;
>
> dma_dev = &mv_chan->dmadev;
> + dma_dev->dev = &pdev->dev;
> mv_chan->xordev = xordev;
>
> /*
> @@ -1091,7 +1092,6 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
> dma_dev->device_free_chan_resources = mv_xor_free_chan_resources;
> dma_dev->device_tx_status = mv_xor_status;
> dma_dev->device_issue_pending = mv_xor_issue_pending;
> - dma_dev->dev = &pdev->dev;
>
> /* set prep routines based on capability */
> if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask))
The patch is fine and it fixes the boot failure.
I misapplied it in previous test.
Thanks,
Dave
^ permalink raw reply
* ARM64 boot failure on espressobin with 5.0.0-rc6 (1f947a7a011fcceb14cb912f5481a53b18f1879a)
From: John David Anglin @ 2019-02-15 15:22 UTC (permalink / raw)
To: Robin Murphy, Christoph Hellwig; +Cc: dmaengine, iommu, linux-arm-kernel
On 2019-02-14 12:58 p.m., Robin Murphy wrote:
> Hmm, having felt brave enough to take a closer look, it might actually be as simple as this - Dave, are you able to give the diff below a spin?
Still crashes but in slightly different spot:
[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[ 0.000000] Linux version 5.0.0-rc6+ (root@espressobin) (gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)) #1 SMP PREEMPT Wed Feb 13
16:17:46 EST 2019
[ 0.000000] Machine model: Globalscale Marvell ESPRESSOBin Board
[ 0.000000] earlycon: ar3700_uart0 at MMIO 0x00000000d0012000 (options '')
[ 0.000000] printk: bootconsole [ar3700_uart0] enabled
[ 3.210276] Internal error: Oops: 96000045 [#1] PREEMPT SMP
[ 3.215932] Modules linked in:
[ 3.219072] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.0.0-rc6+ #1
[ 3.225519] Hardware name: Globalscale Marvell ESPRESSOBin Board (DT)
[ 3.232151] pstate: a0000005 (NzCv daif -PAN -UAO)
[ 3.237090] pc : mv_xor_channel_add+0x4c/0xb28
[ 3.241650] lr : mv_xor_probe+0x20c/0x4b8
[ 3.245768] sp : ffffff8010033ac0
[ 3.249173] x29: ffffff8010033ac0 x28: 0000000000000000
[ 3.254639] x27: ffffff8010e76068 x26: 0000000000000029
[ 3.260104] x25: 0000000000000000 x24: 0000000000000000
[ 3.265570] x23: ffffffc03fb47400 x22: ffffff8010ead000
[ 3.271035] x21: ffffffc03fb47410 x20: ffffffc03bea8d80
[ 3.276501] x19: ffffffc03fb47400 x18: ffffffffffffffff
[ 3.281966] x17: 000000000000000c x16: 000000000000000a
[ 3.287432] x15: ffffff8010ead6c8 x14: ffffffc03beaa003
[ 3.292898] x13: ffffffc03beaa002 x12: 0000000000000038
[ 3.298363] x11: 0000000000001fff x10: 0000000000000001
[ 3.303829] x9 : 0000000000000040 x8 : ffffff8010ec7928
[ 3.309294] x7 : ffffffc03cc003b8 x6 : 0000000000000000
[ 3.314760] x5 : 0000000000000000 x4 : 0000000000000029
[ 3.320226] x3 : 0000000000000083 x2 : 00000000000080c0
[ 3.325691] x1 : 0000000000000000 x0 : ffffffc03fb47410
[ 3.331158] Process swapper/0 (pid: 1, stack limit = 0x(____ptrval____))
[ 3.338056] Call trace:
[ 3.340569] mv_xor_channel_add+0x4c/0xb28
[ 3.344779] mv_xor_probe+0x20c/0x4b8
[ 3.348544] platform_drv_probe+0x50/0xb0
[ 3.352663] really_probe+0x1fc/0x2c0
[ 3.356427] driver_probe_device+0x58/0x100
[ 3.360727] __driver_attach+0xd8/0xe0
[ 3.364580] bus_for_each_dev+0x68/0xc8
[ 3.368522] driver_attach+0x20/0x28
[ 3.372196] bus_add_driver+0x108/0x228
[ 3.376139] driver_register+0x60/0x110
[ 3.380081] __platform_driver_register+0x44/0x50
[ 3.384923] mv_xor_driver_init+0x18/0x20
[ 3.389043] do_one_initcall+0x58/0x170
[ 3.392985] kernel_init_freeable+0x190/0x234
[ 3.397465] kernel_init+0x10/0x108
[ 3.401047] ret_from_fork+0x10/0x1c
[ 3.404723] Code: f90067a5 d2800005 52901802 aa1503e0 (f9003035)
[ 3.411004] ---[ end trace 65be82a62724e328 ]---
[ 3.415804] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[ 3.423626] SMP: stopping secondary CPUs
[ 3.427661] Kernel Offset: disabled
[ 3.431243] CPU features: 0x002,2000200c
[ 3.435272] Memory Limit: none
[ 3.438412] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
ffffff8010630440 <mv_xor_channel_add>:
ffffff8010630440: a9b37bfd stp x29, x30, [sp, #-208]!
ffffff8010630444: 910003fd mov x29, sp
ffffff8010630448: a9025bf5 stp x21, x22, [sp, #32]
ffffff801063044c: b00043f6 adrp x22, ffffff8010ead000 <crypto_il_tab+0x940>
ffffff8010630450: a90363f7 stp x23, x24, [sp, #48]
ffffff8010630454: aa0103f7 mov x23, x1
ffffff8010630458: a9046bf9 stp x25, x26, [sp, #64]
ffffff801063045c: d2800001 mov x1, #0x0 // #0
ffffff8010630460: a90153f3 stp x19, x20, [sp, #16]
ffffff8010630464: 910042f5 add x21, x23, #0x10
ffffff8010630468: a90573fb stp x27, x28, [sp, #80]
ffffff801063046c: aa0003f4 mov x20, x0
ffffff8010630470: 911b22c0 add x0, x22, #0x6c8
ffffff8010630474: 2a0203f9 mov w25, w2
ffffff8010630478: f9400005 ldr x5, [x0]
ffffff801063047c: f90067a5 str x5, [x29, #200]
ffffff8010630480: d2800005 mov x5, #0x0 // #0
ffffff8010630484: 52901802 mov w2, #0x80c0 // #32960
ffffff8010630488: aa1503e0 mov x0, x21
ffffff801063048c: f9003035 str x21, [x1, #96]
ffffff8010630490: 72a00c02 movk w2, #0x60, lsl #16
ffffff8010630494: d2806a01 mov x1, #0x350
...
Dave
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply
* dma: axi-dmac: Split too large segments
From: Alexandru Ardelean @ 2019-02-15 11:06 UTC (permalink / raw)
To: dmaengine, vkoul; +Cc: Lars-Peter Clausen, Alexandru Ardelean
From: Lars-Peter Clausen <lars@metafoo.de>
The axi-dmac driver currently rejects transfers with segments that are
larger than what the hardware can handle.
Re-work the driver so that these large segments are split into multiple
segments instead where each segment is smaller or equal to the maximum
segment size.
This allows the driver to handle transfers with segments of arbitrary size.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/dma/dma-axi-dmac.c | 80 ++++++++++++++++++++++++++++----------
1 file changed, 60 insertions(+), 20 deletions(-)
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index ffc0adc2f6ce..6a41e1f49077 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -83,6 +83,7 @@ struct axi_dmac_sg {
unsigned int dest_stride;
unsigned int src_stride;
unsigned int id;
+ bool last;
bool schedule_when_free;
};
@@ -166,7 +167,7 @@ static int axi_dmac_dest_is_mem(struct axi_dmac_chan *chan)
static bool axi_dmac_check_len(struct axi_dmac_chan *chan, unsigned int len)
{
- if (len == 0 || len > chan->max_length)
+ if (len == 0)
return false;
if ((len & chan->align_mask) != 0) /* Not aligned */
return false;
@@ -379,6 +380,50 @@ static struct axi_dmac_desc *axi_dmac_alloc_desc(unsigned int num_sgs)
return desc;
}
+static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
+ enum dma_transfer_direction direction, dma_addr_t addr,
+ unsigned int num_periods, unsigned int period_len,
+ struct axi_dmac_sg *sg)
+{
+ unsigned int num_segments, i;
+ unsigned int segment_size;
+ unsigned int len;
+
+ /* Split into multiple equally sized segments if necessary */
+ num_segments = DIV_ROUND_UP(period_len, chan->max_length);
+ segment_size = DIV_ROUND_UP(period_len, num_segments);
+ /* Take care of alignment */
+ segment_size = ((segment_size - 1) | chan->align_mask) + 1;
+
+ for (i = 0; i < num_periods; i++) {
+ len = period_len;
+
+ while (len > segment_size) {
+ if (direction == DMA_DEV_TO_MEM)
+ sg->dest_addr = addr;
+ else
+ sg->src_addr = addr;
+ sg->x_len = segment_size;
+ sg->y_len = 1;
+ sg++;
+ addr += segment_size;
+ len -= segment_size;
+ }
+
+ if (direction == DMA_DEV_TO_MEM)
+ sg->dest_addr = addr;
+ else
+ sg->src_addr = addr;
+ sg->x_len = len;
+ sg->y_len = 1;
+ sg->last = true;
+ sg++;
+ addr += len;
+ }
+
+ return sg;
+}
+
static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
struct dma_chan *c, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@@ -386,16 +431,21 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
{
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
struct axi_dmac_desc *desc;
+ struct axi_dmac_sg *dsg;
struct scatterlist *sg;
+ unsigned int num_sgs;
unsigned int i;
if (direction != chan->direction)
return NULL;
- desc = axi_dmac_alloc_desc(sg_len);
+ num_sgs = sg_nents_for_dma(sgl, sg_len, chan->max_length);
+ desc = axi_dmac_alloc_desc(num_sgs);
if (!desc)
return NULL;
+ dsg = desc->sg;
+
for_each_sg(sgl, sg, sg_len, i) {
if (!axi_dmac_check_addr(chan, sg_dma_address(sg)) ||
!axi_dmac_check_len(chan, sg_dma_len(sg))) {
@@ -403,12 +453,8 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
return NULL;
}
- if (direction == DMA_DEV_TO_MEM)
- desc->sg[i].dest_addr = sg_dma_address(sg);
- else
- desc->sg[i].src_addr = sg_dma_address(sg);
- desc->sg[i].x_len = sg_dma_len(sg);
- desc->sg[i].y_len = 1;
+ dsg = axi_dmac_fill_linear_sg(chan, direction, sg_dma_address(sg), 1,
+ sg_dma_len(sg), dsg);
}
desc->cyclic = false;
@@ -423,7 +469,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
{
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
struct axi_dmac_desc *desc;
- unsigned int num_periods, i;
+ unsigned int num_periods, num_segments;
if (direction != chan->direction)
return NULL;
@@ -436,20 +482,14 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
return NULL;
num_periods = buf_len / period_len;
+ num_segments = DIV_ROUND_UP(period_len, chan->max_length);
- desc = axi_dmac_alloc_desc(num_periods);
+ desc = axi_dmac_alloc_desc(num_periods * num_segments);
if (!desc)
return NULL;
- for (i = 0; i < num_periods; i++) {
- if (direction == DMA_DEV_TO_MEM)
- desc->sg[i].dest_addr = buf_addr;
- else
- desc->sg[i].src_addr = buf_addr;
- desc->sg[i].x_len = period_len;
- desc->sg[i].y_len = 1;
- buf_addr += period_len;
- }
+ axi_dmac_fill_linear_sg(chan, direction, buf_addr, num_periods,
+ buf_len, desc->sg);
desc->cyclic = true;
@@ -647,7 +687,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
of_node_put(of_channels);
pdev->dev.dma_parms = &dmac->dma_parms;
- dma_set_max_seg_size(&pdev->dev, dmac->chan.max_length);
+ dma_set_max_seg_size(&pdev->dev, UINT_MAX);
dma_dev = &dmac->dma_dev;
dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
^ permalink raw reply related
* dma: axi-dmac: assign `copy_align` property
From: Alexandru Ardelean @ 2019-02-15 11:02 UTC (permalink / raw)
To: dmaengine, vkoul; +Cc: Alexandru Ardelean
The `copy_align` property is a generic property that describes alignment
for DMA memcpy & sg ops.
It serves mostly an informational purpose, and can be used in DMA tests, to
pass the info to know what alignment to expect.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/dma/dma-axi-dmac.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index a54157ab00b2..a58aee7090dd 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -814,6 +814,8 @@ static int axi_dmac_probe(struct platform_device *pdev)
if (ret)
goto err_clk_disable;
+ dma_dev->copy_align = (dmac->chan.address_align_mask + 1);
+
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00);
ret = dma_async_device_register(dma_dev);
^ permalink raw reply related
* [2/2] dma: axi-dmac: report DMA_INTERLEAVE capability
From: Alexandru Ardelean @ 2019-02-15 9:17 UTC (permalink / raw)
To: dmaengine, vkoul; +Cc: Dragos Bogdan, Alexandru Ardelean
From: Dragos Bogdan <dragos.bogdan@analog.com>
Fixes commit 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices
AXI-DMAC DMA controller")
The `device_prep_interleaved_dma()` callback is already present since the
driver was submitted initially.
This change adds the DMA_INTERLEAVE capability to the capability mask of
the DMA engine.
Signed-off-by: Dragos Bogdan <dragos.bogdan@analog.com>
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/dma/dma-axi-dmac.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index 2c999113b989..b2039e60ae04 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -652,6 +652,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
dma_dev = &dmac->dma_dev;
dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
dma_cap_set(DMA_CYCLIC, dma_dev->cap_mask);
+ dma_cap_set(DMA_INTERLEAVE, dma_dev->cap_mask);
dma_dev->device_free_chan_resources = axi_dmac_free_chan_resources;
dma_dev->device_tx_status = dma_cookie_status;
dma_dev->device_issue_pending = axi_dmac_issue_pending;
^ permalink raw reply related
* [1/2] dma: axi-dmac: don't check the number of frames for alignment
From: Alexandru Ardelean @ 2019-02-15 9:17 UTC (permalink / raw)
To: dmaengine, vkoul; +Cc: Alexandru Ardelean
Fixes commit 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices
AXI-DMAC DMA controller")
For 2D transfers, there is no requirement for Y_LENGTH to be aligned
to the bus-width (or anything). X_LENGTH is required to be aligned
though.
So, we shouldn't check that the number of frames is aligned.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/dma/dma-axi-dmac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index ffc0adc2f6ce..2c999113b989 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -485,7 +485,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved(
if (chan->hw_2d) {
if (!axi_dmac_check_len(chan, xt->sgl[0].size) ||
- !axi_dmac_check_len(chan, xt->numf))
+ xt->numf == 0)
return NULL;
if (xt->sgl[0].size + dst_icg > chan->max_length ||
xt->sgl[0].size + src_icg > chan->max_length)
^ permalink raw reply related
* ARM64 boot failure on espressobin with 5.0.0-rc6 (1f947a7a011fcceb14cb912f5481a53b18f1879a)
From: John David Anglin @ 2019-02-14 18:11 UTC (permalink / raw)
To: Robin Murphy, Christoph Hellwig; +Cc: dmaengine, iommu, linux-arm-kernel
On 2019-02-14 12:58 p.m., Robin Murphy wrote:
> Hmm, having felt brave enough to take a closer look, it might actually be as simple as this - Dave, are you able to give the diff below a spin?
Yes.
^ permalink raw reply
* ARM64 boot failure on espressobin with 5.0.0-rc6 (1f947a7a011fcceb14cb912f5481a53b18f1879a)
From: Robin Murphy @ 2019-02-14 17:58 UTC (permalink / raw)
To: Christoph Hellwig, John David Anglin; +Cc: dmaengine, iommu, linux-arm-kernel
On 14/02/2019 17:36, Christoph Hellwig wrote:
> On Thu, Feb 14, 2019 at 05:27:41PM +0000, Robin Murphy wrote:
>> Oh wow, that driver has possibly the most inventive way of passing a NULL
>> device to the DMA API that I've ever seen, and on arm64 it will certainly
>> have been failing since 4.2, but of course there's also no error checking
>> for anyone to notice...
>
> I did take a brief look and didn't see how we got the NULL device
> pointer, so it is well hidden for sure.
>
>> This crash will be a fallout from 356da6d0cd (plus the subsequent fix in
>> 9ab91e7c5c51) that's otherwise missed Christoph's big cleanup. Obviously
>> the right thing to do is for someone to try to figure out the steaming pile
>> of mess in that driver, but if necessary I think the quick fix below should
>> probably suffice to mitigate the change in the short term.
>
> The fix looks ok. And for 5.2 I plan to explicitly reject all uses of
> NULL device arguments in the DMA API. I've sent patches out for all
> the obviously problemetic drivers, and most of them got accepted by the
> maintainers for the 5.1 merge window.
>
> It seems like the mv_xor code is mostly unmaintained as far as I can
> tell unfortunately.
Hmm, having felt brave enough to take a closer look, it might actually
be as simple as this - Dave, are you able to give the diff below a spin?
Robin.
----->8-----
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 7f595355fb79..fe4a7c71fede 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -1059,6 +1059,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
mv_chan->op_in_desc = XOR_MODE_IN_DESC;
dma_dev = &mv_chan->dmadev;
+ dma_dev->dev = &pdev->dev;
mv_chan->xordev = xordev;
/*
@@ -1091,7 +1092,6 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
dma_dev->device_free_chan_resources = mv_xor_free_chan_resources;
dma_dev->device_tx_status = mv_xor_status;
dma_dev->device_issue_pending = mv_xor_issue_pending;
- dma_dev->dev = &pdev->dev;
/* set prep routines based on capability */
if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask))
^ permalink raw reply related
* ARM64 boot failure on espressobin with 5.0.0-rc6 (1f947a7a011fcceb14cb912f5481a53b18f1879a)
From: Christoph Hellwig @ 2019-02-14 17:36 UTC (permalink / raw)
To: Robin Murphy
Cc: Christoph Hellwig, dmaengine, iommu, John David Anglin,
linux-arm-kernel
On Thu, Feb 14, 2019 at 05:27:41PM +0000, Robin Murphy wrote:
> Oh wow, that driver has possibly the most inventive way of passing a NULL
> device to the DMA API that I've ever seen, and on arm64 it will certainly
> have been failing since 4.2, but of course there's also no error checking
> for anyone to notice...
I did take a brief look and didn't see how we got the NULL device
pointer, so it is well hidden for sure.
> This crash will be a fallout from 356da6d0cd (plus the subsequent fix in
> 9ab91e7c5c51) that's otherwise missed Christoph's big cleanup. Obviously
> the right thing to do is for someone to try to figure out the steaming pile
> of mess in that driver, but if necessary I think the quick fix below should
> probably suffice to mitigate the change in the short term.
The fix looks ok. And for 5.2 I plan to explicitly reject all uses of
NULL device arguments in the DMA API. I've sent patches out for all
the obviously problemetic drivers, and most of them got accepted by the
maintainers for the 5.1 merge window.
It seems like the mv_xor code is mostly unmaintained as far as I can
tell unfortunately.
^ permalink raw reply
* ARM64 boot failure on espressobin with 5.0.0-rc6 (1f947a7a011fcceb14cb912f5481a53b18f1879a)
From: Robin Murphy @ 2019-02-14 17:27 UTC (permalink / raw)
To: Christoph Hellwig, dmaengine, iommu; +Cc: John David Anglin, linux-arm-kernel
On 14/02/2019 16:09, John David Anglin wrote:
> Starting kernel ...
>
> [ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
> [ 0.000000] Linux version 5.0.0-rc6+ (root@espressobin) (gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)) #1 SMP PREEMPT Wed Feb 13
> 16:17:46 EST 2019
> [ 0.000000] Machine model: Globalscale Marvell ESPRESSOBin Board
> [ 0.000000] earlycon: ar3700_uart0 at MMIO 0x00000000d0012000 (options '')
> [ 0.000000] printk: bootconsole [ar3700_uart0] enabled
> [ 3.219693] Internal error: Oops: 96000005 [#1] PREEMPT SMP
> [ 3.225349] Modules linked in:
> [ 3.228489] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.0.0-rc6+ #1
> [ 3.234936] Hardware name: Globalscale Marvell ESPRESSOBin Board (DT)
> [ 3.241568] pstate: 20000005 (nzCv daif -PAN -UAO)
> [ 3.246505] pc : dma_direct_map_page+0x48/0x1d8
> [ 3.251159] lr : mv_xor_channel_add+0x3b0/0xb28
> [ 3.255812] sp : ffffff8010033a60
> [ 3.259217] x29: ffffff8010033a60 x28: ffffffc03befec80
> [ 3.264682] x27: ffffff8010e97068 x26: 0000000000000000
> [ 3.270148] x25: 0000000000000029 x24: 0000000000000083
> [ 3.275613] x23: 0000000000000000 x22: 0000000000000002
> [ 3.281079] x21: 0000000000000080 x20: ffffff8010ecd000
> [ 3.286544] x19: 0000000000000000 x18: ffffffffffffffff
> [ 3.292010] x17: 00000000f8f63085 x16: 0000000074242664
> [ 3.297476] x15: ffffff8010ecd6c8 x14: ffffffc03bed9e83
> [ 3.302941] x13: ffffffc03bed9e82 x12: 0000000000000038
> [ 3.308407] x11: 0000000000001fff x10: 0000000000000001
> [ 3.313872] x9 : 0000000000000000 x8 : ffffff8010dbe000
> [ 3.319338] x7 : ffffff8010fbe000 x6 : ffffffbf00000000
> [ 3.324804] x5 : 0000000000000000 x4 : 0000000000000002
> [ 3.330269] x3 : 0000000000000002 x2 : 0000000000000eac
> [ 3.335735] x1 : ffffffbf00efbf80 x0 : 0000000000000000
> [ 3.341202] Process swapper/0 (pid: 1, stack limit = 0x(____ptrval____))
> [ 3.348100] Call trace:
> [ 3.350612] dma_direct_map_page+0x48/0x1d8
> [ 3.354912] mv_xor_channel_add+0x3b0/0xb28
> [ 3.359213] mv_xor_probe+0x20c/0x4b8
> [ 3.362978] platform_drv_probe+0x50/0xb0
> [ 3.367097] really_probe+0x1fc/0x2c0
> [ 3.370860] driver_probe_device+0x58/0x100
> [ 3.375160] __driver_attach+0xd8/0xe0
> [ 3.379016] bus_for_each_dev+0x68/0xc8
> [ 3.382957] driver_attach+0x20/0x28
> [ 3.386631] bus_add_driver+0x108/0x228
> [ 3.390572] driver_register+0x60/0x110
> [ 3.394515] __platform_driver_register+0x44/0x50
> [ 3.399357] mv_xor_driver_init+0x18/0x20
> [ 3.403477] do_one_initcall+0x58/0x170
> [ 3.407419] kernel_init_freeable+0x190/0x234
> [ 3.411900] kernel_init+0x10/0x108
> [ 3.415482] ret_from_fork+0x10/0x1c
> [ 3.419157] Code: 2a0403f6 934cfc00 aa0503f7 7100047f (f9412663)
> [ 3.425438] ---[ end trace f62a451df663a071 ]---
> [ 3.430228] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
> [ 3.438060] SMP: stopping secondary CPUs
> [ 3.442093] Kernel Offset: disabled
> [ 3.445676] CPU features: 0x002,2000200c
> [ 3.449706] Memory Limit: none
> [ 3.452846] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
>
> The same error occurs with linux-net 5.0.0-rc5 (91986ee166cf0816ae92668476ea7872d51b0c6e). v4.20.x
> boots okay. Seems to be a hard failure.
Oh wow, that driver has possibly the most inventive way of passing a
NULL device to the DMA API that I've ever seen, and on arm64 it will
certainly have been failing since 4.2, but of course there's also no
error checking for anyone to notice...
This crash will be a fallout from 356da6d0cd (plus the subsequent fix in
9ab91e7c5c51) that's otherwise missed Christoph's big cleanup. Obviously
the right thing to do is for someone to try to figure out the steaming
pile of mess in that driver, but if necessary I think the quick fix
below should probably suffice to mitigate the change in the short term.
Robin.
----->8-----
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
diff --git a/arch/arm64/include/asm/dma-mapping.h
b/arch/arm64/include/asm/dma-mapping.h
index 95dbf3ef735a..f530edfe5678 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -26,7 +26,7 @@
static inline const struct dma_map_ops *get_arch_dma_ops(struct
bus_type *bus)
{
- return NULL;
+ return bus ? NULL : &dma_dummy_ops;
}
^ permalink raw reply related
* [v10,3/3] dt-bindings: dma: uart: rename binding
From: Matthias Brugger @ 2019-02-14 10:13 UTC (permalink / raw)
To: Long Cheng, Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland,
Ryder Lee, Sean Wang, Nicolas Boichat
Cc: Dan Williams, Greg Kroah-Hartman, Jiri Slaby, Sean Wang,
dmaengine, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-serial, srv_heupstream, Yingjoe Chen, YT Shen,
Zhenbao Liu
On 18/01/2019 04:10, Long Cheng wrote:
> The filename matches mtk-uart-apdma.c.
> So using "mtk-uart-apdma.txt" should be better.
>
> Signed-off-by: Long Cheng <long.cheng@mediatek.com>
> ---
> .../devicetree/bindings/dma/8250_mtk_dma.txt | 33 --------------------
> .../devicetree/bindings/dma/mtk-uart-apdma.txt | 33 ++++++++++++++++++++
> 2 files changed, 33 insertions(+), 33 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
> create mode 100644 Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
>
> diff --git a/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt b/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
> deleted file mode 100644
> index 3fe0961..0000000
> --- a/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
> +++ /dev/null
> @@ -1,33 +0,0 @@
> -* Mediatek UART APDMA Controller
> -
> -Required properties:
> -- compatible should contain:
> - * "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
> - * "mediatek,mt6577-uart-dma" for MT6577 and all of the above
> -
> -- reg: The base address of the APDMA register bank.> -
> -- interrupts: A single interrupt specifier.
One interrupt per dma-request, or 8 if no dma-requests property is present.
> -
> -- clocks : Must contain an entry for each entry in clock-names.
> - See ../clocks/clock-bindings.txt for details.
> -- clock-names: The APDMA clock for register accesses> -
> -Examples:
> -
> - apdma: dma-controller@11000380 {
> - compatible = "mediatek,mt2712-uart-dma";
> - reg = <0 0x11000380 0 0x400>;
> - interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_LOW>,
> - <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>,
> - <GIC_SPI 65 IRQ_TYPE_LEVEL_LOW>,
> - <GIC_SPI 66 IRQ_TYPE_LEVEL_LOW>,
> - <GIC_SPI 67 IRQ_TYPE_LEVEL_LOW>,
> - <GIC_SPI 68 IRQ_TYPE_LEVEL_LOW>,
> - <GIC_SPI 69 IRQ_TYPE_LEVEL_LOW>,
> - <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
> - clocks = <&pericfg CLK_PERI_AP_DMA>;
> - clock-names = "apdma";
> - #dma-cells = <1>;
> - };
> -
> diff --git a/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt b/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
> new file mode 100644
> index 0000000..3fe0961
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
> @@ -0,0 +1,33 @@
> +* Mediatek UART APDMA Controller
> +
> +Required properties:
> +- compatible should contain:
> + * "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
> + * "mediatek,mt6577-uart-dma" for MT6577 and all of the above
> +
> +- reg: The base address of the APDMA register bank.
> +
There is one address needed for every dma-request or 8 if dma-requests property
is not present. As already mentioned in the driver review dma-requests property
is missing.
> +- interrupts: A single interrupt specifier.
> +
> +- clocks : Must contain an entry for each entry in clock-names.
> + See ../clocks/clock-bindings.txt for details.
> +- clock-names: The APDMA clock for register accesses
> +
Missing option property dma-33bits (should be mtk,dma-33bits?).
> +Examples:
> +
> + apdma: dma-controller@11000380 {
> + compatible = "mediatek,mt2712-uart-dma";
> + reg = <0 0x11000380 0 0x400>;
We are missing the io mem areas here, right?
Regards,
Matthias
> + interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 65 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 66 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 67 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 68 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 69 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
> + clocks = <&pericfg CLK_PERI_AP_DMA>;
> + clock-names = "apdma";
> + #dma-cells = <1>;
> + };
> +
>
^ permalink raw reply
* [v10,1/3] dmaengine: 8250_mtk_dma: add MediaTek uart DMA support
From: Matthias Brugger @ 2019-02-14 10:08 UTC (permalink / raw)
To: Long Cheng, Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland,
Ryder Lee, Sean Wang, Nicolas Boichat
Cc: Dan Williams, Greg Kroah-Hartman, Jiri Slaby, Sean Wang,
dmaengine, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-serial, srv_heupstream, Yingjoe Chen, YT Shen,
Zhenbao Liu
On 18/01/2019 04:10, Long Cheng wrote:
> In DMA engine framework, add 8250 uart dma to support MediaTek uart.
> If MediaTek uart enabled(SERIAL_8250_MT6577), and want to improve
> the performance, can enable the function.
>
> Signed-off-by: Long Cheng <long.cheng@mediatek.com>
> ---
> drivers/dma/mediatek/Kconfig | 11 +
> drivers/dma/mediatek/Makefile | 1 +
> drivers/dma/mediatek/mtk-uart-apdma.c | 669 +++++++++++++++++++++++++++++++++
> 3 files changed, 681 insertions(+)
> create mode 100644 drivers/dma/mediatek/mtk-uart-apdma.c
>
[...]
> +
> +static int mtk_uart_apdma_probe(struct platform_device *pdev)
> +{
> + struct device_node *np = pdev->dev.of_node;
> + struct mtk_uart_apdmadev *mtkd;
> + struct resource *res;
> + struct mtk_chan *c;
> + int bit_mask = 32, rc;
> + unsigned int i;
> +
> + mtkd = devm_kzalloc(&pdev->dev, sizeof(*mtkd), GFP_KERNEL);
> + if (!mtkd)
> + return -ENOMEM;
> +
> + mtkd->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(mtkd->clk)) {
> + dev_err(&pdev->dev, "No clock specified\n");
> + rc = PTR_ERR(mtkd->clk);
> + return rc;
> + }
> +
> + if (of_property_read_bool(np, "dma-33bits"))
> + mtkd->support_33bits = true;
dma-33bits not defined in the binding description.
> +
> + if (mtkd->support_33bits)
> + bit_mask = 33;
> +
> + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(bit_mask));
> + if (rc)
> + return rc;
> +
> + dma_cap_set(DMA_SLAVE, mtkd->ddev.cap_mask);
> + mtkd->ddev.device_alloc_chan_resources =
> + mtk_uart_apdma_alloc_chan_resources;
> + mtkd->ddev.device_free_chan_resources =
> + mtk_uart_apdma_free_chan_resources;
> + mtkd->ddev.device_tx_status = mtk_uart_apdma_tx_status;
> + mtkd->ddev.device_issue_pending = mtk_uart_apdma_issue_pending;
> + mtkd->ddev.device_prep_slave_sg = mtk_uart_apdma_prep_slave_sg;
> + mtkd->ddev.device_config = mtk_uart_apdma_slave_config;
> + mtkd->ddev.device_pause = mtk_uart_apdma_device_pause;
> + mtkd->ddev.device_terminate_all = mtk_uart_apdma_terminate_all;
> + mtkd->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
> + mtkd->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
> + mtkd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
> + mtkd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
> + mtkd->ddev.dev = &pdev->dev;
> + INIT_LIST_HEAD(&mtkd->ddev.channels);
> +
> + mtkd->dma_requests = MTK_UART_APDMA_NR_VCHANS;
Do this if dma-requests property is not present.
> + if (of_property_read_u32(np, "dma-requests", &mtkd->dma_requests)) {
It's quite obvious what this does, but IMHO it should be reflected in the binding.
Regards,
Matthias
> + dev_info(&pdev->dev,
> + "Using %u as missing dma-requests property\n",
> + MTK_UART_APDMA_NR_VCHANS);
> + }
> +
> + mtkd->dma_irq = devm_kcalloc(&pdev->dev, mtkd->dma_requests,
> + sizeof(*mtkd->dma_irq), GFP_KERNEL);
> + if (!mtkd->dma_irq)
> + return -ENOMEM;
> +
> + for (i = 0; i < mtkd->dma_requests; i++) {
> + c = devm_kzalloc(mtkd->ddev.dev, sizeof(*c), GFP_KERNEL);
> + if (!c) {
> + rc = -ENODEV;
> + goto err_no_dma;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, i);
> + if (!res) {
> + rc = -ENODEV;
> + goto err_no_dma;
> + }
> +
> + c->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(c->base)) {
> + rc = PTR_ERR(c->base);
> + goto err_no_dma;
> + }
> + c->requested = false;
> + c->vc.desc_free = mtk_uart_apdma_desc_free;
> + vchan_init(&c->vc, &mtkd->ddev);
> +
> + mtkd->dma_irq[i] = platform_get_irq(pdev, i);
> + if ((int)mtkd->dma_irq[i] < 0) {
> + dev_err(&pdev->dev, "failed to get IRQ[%d]\n", i);
> + rc = -EINVAL;
> + goto err_no_dma;
> + }
> + }
> +
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_set_active(&pdev->dev);
> +
> + rc = dma_async_device_register(&mtkd->ddev);
> + if (rc)
> + goto rpm_disable;
> +
> + platform_set_drvdata(pdev, mtkd);
> +
> + /* Device-tree DMA controller registration */
> + rc = of_dma_controller_register(np, of_dma_xlate_by_chan_id, mtkd);
> + if (rc)
> + goto dma_remove;
> +
> + return rc;
> +
> +dma_remove:
> + dma_async_device_unregister(&mtkd->ddev);
> +rpm_disable:
> + pm_runtime_disable(&pdev->dev);
> +err_no_dma:
> + mtk_uart_apdma_free(mtkd);
> + return rc;
> +}
> +
> +static int mtk_uart_apdma_remove(struct platform_device *pdev)
> +{
> + struct mtk_uart_apdmadev *mtkd = platform_get_drvdata(pdev);
> +
> + if (pdev->dev.of_node)
> + of_dma_controller_free(pdev->dev.of_node);
> +
> + pm_runtime_disable(&pdev->dev);
> + pm_runtime_put_noidle(&pdev->dev);
> +
> + dma_async_device_unregister(&mtkd->ddev);
> + mtk_uart_apdma_free(mtkd);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int mtk_uart_apdma_suspend(struct device *dev)
> +{
> + struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
> +
> + if (!pm_runtime_suspended(dev))
> + clk_disable_unprepare(mtkd->clk);
> +
> + return 0;
> +}
> +
> +static int mtk_uart_apdma_resume(struct device *dev)
> +{
> + int ret;
> + struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
> +
> + if (!pm_runtime_suspended(dev)) {
> + ret = clk_prepare_enable(mtkd->clk);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +#ifdef CONFIG_PM
> +static int mtk_uart_apdma_runtime_suspend(struct device *dev)
> +{
> + struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(mtkd->clk);
> +
> + return 0;
> +}
> +
> +static int mtk_uart_apdma_runtime_resume(struct device *dev)
> +{
> + int ret;
> + struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
> +
> + ret = clk_prepare_enable(mtkd->clk);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +#endif /* CONFIG_PM */
> +
> +static const struct dev_pm_ops mtk_uart_apdma_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(mtk_uart_apdma_suspend, mtk_uart_apdma_resume)
> + SET_RUNTIME_PM_OPS(mtk_uart_apdma_runtime_suspend,
> + mtk_uart_apdma_runtime_resume, NULL)
> +};
> +
> +static struct platform_driver mtk_uart_apdma_driver = {
> + .probe = mtk_uart_apdma_probe,
> + .remove = mtk_uart_apdma_remove,
> + .driver = {
> + .name = KBUILD_MODNAME,
> + .pm = &mtk_uart_apdma_pm_ops,
> + .of_match_table = of_match_ptr(mtk_uart_apdma_match),
> + },
> +};
> +
> +module_platform_driver(mtk_uart_apdma_driver);
> +
> +MODULE_DESCRIPTION("MediaTek UART APDMA Controller Driver");
> +MODULE_AUTHOR("Long Cheng <long.cheng@mediatek.com>");
> +MODULE_LICENSE("GPL v2");
> +
>
^ permalink raw reply
* [v2,1/1] dt-bindings: dmaengine: Add MediaTek Command-Queue DMA controller bindings
From: Matthias Brugger @ 2019-02-14 9:19 UTC (permalink / raw)
To: shun-chih.yu, Sean Wang, Vinod Koul, Rob Herring, Dan Williams
Cc: dmaengine, linux-arm-kernel, linux-mediatek, devicetree,
linux-kernel, srv_wsdupstream
On 14/02/2019 08:54, shun-chih.yu@mediatek.com wrote:
> From: Shun-Chih Yu <shun-chih.yu@mediatek.com>
>
> Document the devicetree bindings for MediaTek Command-Queue DMA controller
> which could be found on MT6765 SoC or other similar Mediatek SoCs.
>
> Signed-off-by: Shun-Chih Yu <shun-chih.yu@mediatek.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Acked-by: Sean Wang <sean.wang@kernel.org>
> ---
> .../devicetree/bindings/dma/mtk-cqdma.txt | 31 ++++++++++++++++++++
> 1 file changed, 31 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/dma/mtk-cqdma.txt
>
> diff --git a/Documentation/devicetree/bindings/dma/mtk-cqdma.txt b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
> new file mode 100644
> index 0000000..fb12927
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
> @@ -0,0 +1,31 @@
> +MediaTek Command-Queue DMA Controller
> +==================================
> +
> +Required properties:
> +
> +- compatible: Must be "mediatek,mt6765-cqdma" for MT6765.
> +- reg: Should contain the base address and length for each channel.
> +- interrupts: Should contain references to the interrupts for each channel.
> +- clocks: Should be the clock specifiers corresponding to the entry in
> + clock-names property.
> +- clock-names: Should contain "cqdma" entries.
entries -> entry. There is only one clock
> +- dma-channels: The number of DMA channels supported by the controller.
> +- dma-requests: The number of DMA request supported by the controller.
The driver handles these as optional and uses MTK_CQDMA_NR_VCHANS and
MTK_CQDMA_NR_PCHANS in case the property is not present.
> +- #dma-cells: The length of the DMA specifier, must be <1>. This one cell
> + in dmas property of a client device represents the channel
> + number.
> +Example:
> +
> + cqdma: dma-controller@10212000 {
> + compatible = "mediatek,mt6765-cqdma";
> + reg = <0 0x10212000 0 0x1000>;
Does this mean that you have to resources at base = 0x0 with different length?
For the next time, please send driver and binding description in one series (two
patches). That makes things easier to review.
Thanks,
Matthias
> + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
> + clocks = <&infracfg CLK_IFR_CQ_DMA>;
> + clock-names = "cqdma";
> + dma-channels = <2>;
> + dma-requests = <32>;
> + #dma-cells = <1>;
> + };
> +
> +DMA clients must use the format described in dma/dma.txt file.
>
^ permalink raw reply
* [v2,1/1] dt-bindings: dmaengine: Add MediaTek Command-Queue DMA controller bindings
From: Matthias Brugger @ 2019-02-14 9:18 UTC (permalink / raw)
To: shun-chih.yu, Sean Wang, Vinod Koul, Rob Herring, Dan Williams
Cc: dmaengine, linux-arm-kernel, linux-mediatek, devicetree,
linux-kernel, srv_wsdupstream
On 14/02/2019 08:54, shun-chih.yu@mediatek.com wrote:
> From: Shun-Chih Yu <shun-chih.yu@mediatek.com>
>
> Document the devicetree bindings for MediaTek Command-Queue DMA controller
> which could be found on MT6765 SoC or other similar Mediatek SoCs.
>
> Signed-off-by: Shun-Chih Yu <shun-chih.yu@mediatek.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Acked-by: Sean Wang <sean.wang@kernel.org>
> ---
> .../devicetree/bindings/dma/mtk-cqdma.txt | 31 ++++++++++++++++++++
> 1 file changed, 31 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/dma/mtk-cqdma.txt
>
> diff --git a/Documentation/devicetree/bindings/dma/mtk-cqdma.txt b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
> new file mode 100644
> index 0000000..fb12927
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
> @@ -0,0 +1,31 @@
> +MediaTek Command-Queue DMA Controller
> +==================================
> +
> +Required properties:
> +
> +- compatible: Must be "mediatek,mt6765-cqdma" for MT6765.
> +- reg: Should contain the base address and length for each channel.
> +- interrupts: Should contain references to the interrupts for each channel.
> +- clocks: Should be the clock specifiers corresponding to the entry in
> + clock-names property.
> +- clock-names: Should contain "cqdma" entries.
entries -> entry. There is only one clock
> +- dma-channels: The number of DMA channels supported by the controller.
> +- dma-requests: The number of DMA request supported by the controller.
The driver handles these as optional and uses MTK_CQDMA_NR_VCHANS and
MTK_CQDMA_NR_PCHANS in case the property is not present.
> +- #dma-cells: The length of the DMA specifier, must be <1>. This one cell
> + in dmas property of a client device represents the channel
> + number.
> +Example:
> +
> + cqdma: dma-controller@10212000 {
> + compatible = "mediatek,mt6765-cqdma";
> + reg = <0 0x10212000 0 0x1000>;
Does this mean that you have to resources at base = 0x0 with different length?
Regards,
Matthias
> + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
> + clocks = <&infracfg CLK_IFR_CQ_DMA>;
> + clock-names = "cqdma";
> + dma-channels = <2>;
> + dma-requests = <32>;
> + #dma-cells = <1>;
> + };
> +
> +DMA clients must use the format described in dma/dma.txt file.
>
^ permalink raw reply
* [v2,1/1] dt-bindings: dmaengine: Add MediaTek Command-Queue DMA controller bindings
From: Matthias Brugger @ 2019-02-14 9:04 UTC (permalink / raw)
To: shun-chih.yu, Sean Wang, Vinod Koul, Rob Herring, Dan Williams
Cc: dmaengine, linux-arm-kernel, linux-mediatek, devicetree,
linux-kernel, srv_wsdupstream
On 14/02/2019 08:54, shun-chih.yu@mediatek.com wrote:
> From: Shun-Chih Yu <shun-chih.yu@mediatek.com>
>
> Document the devicetree bindings for MediaTek Command-Queue DMA controller
> which could be found on MT6765 SoC or other similar Mediatek SoCs.
>
> Signed-off-by: Shun-Chih Yu <shun-chih.yu@mediatek.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Acked-by: Sean Wang <sean.wang@kernel.org>
> ---
Please don't send cover letters for single patches, just for series.
If you want to add some information to a single patch, which should not show up
in the commit message (e.g. change log) you can do that below the "---"
Regards,
Matthias
> .../devicetree/bindings/dma/mtk-cqdma.txt | 31 ++++++++++++++++++++
> 1 file changed, 31 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/dma/mtk-cqdma.txt
>
> diff --git a/Documentation/devicetree/bindings/dma/mtk-cqdma.txt b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
> new file mode 100644
> index 0000000..fb12927
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
> @@ -0,0 +1,31 @@
> +MediaTek Command-Queue DMA Controller
> +==================================
> +
> +Required properties:
> +
> +- compatible: Must be "mediatek,mt6765-cqdma" for MT6765.
> +- reg: Should contain the base address and length for each channel.
> +- interrupts: Should contain references to the interrupts for each channel.
> +- clocks: Should be the clock specifiers corresponding to the entry in
> + clock-names property.
> +- clock-names: Should contain "cqdma" entries.
> +- dma-channels: The number of DMA channels supported by the controller.
> +- dma-requests: The number of DMA request supported by the controller.
> +- #dma-cells: The length of the DMA specifier, must be <1>. This one cell
> + in dmas property of a client device represents the channel
> + number.
> +Example:
> +
> + cqdma: dma-controller@10212000 {
> + compatible = "mediatek,mt6765-cqdma";
> + reg = <0 0x10212000 0 0x1000>;
> + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
> + clocks = <&infracfg CLK_IFR_CQ_DMA>;
> + clock-names = "cqdma";
> + dma-channels = <2>;
> + dma-requests = <32>;
> + #dma-cells = <1>;
> + };
> +
> +DMA clients must use the format described in dma/dma.txt file.
>
^ permalink raw reply
* [v2,1/1] dt-bindings: dmaengine: Add MediaTek Command-Queue DMA controller bindings
From: shun-chih.yu @ 2019-02-14 7:54 UTC (permalink / raw)
To: Sean Wang, Vinod Koul, Rob Herring, Matthias Brugger,
Dan Williams
Cc: dmaengine, linux-arm-kernel, linux-mediatek, devicetree,
linux-kernel, srv_wsdupstream, Shun-Chih Yu
From: Shun-Chih Yu <shun-chih.yu@mediatek.com>
Document the devicetree bindings for MediaTek Command-Queue DMA controller
which could be found on MT6765 SoC or other similar Mediatek SoCs.
Signed-off-by: Shun-Chih Yu <shun-chih.yu@mediatek.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Acked-by: Sean Wang <sean.wang@kernel.org>
---
.../devicetree/bindings/dma/mtk-cqdma.txt | 31 ++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/mtk-cqdma.txt
diff --git a/Documentation/devicetree/bindings/dma/mtk-cqdma.txt b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
new file mode 100644
index 0000000..fb12927
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
@@ -0,0 +1,31 @@
+MediaTek Command-Queue DMA Controller
+==================================
+
+Required properties:
+
+- compatible: Must be "mediatek,mt6765-cqdma" for MT6765.
+- reg: Should contain the base address and length for each channel.
+- interrupts: Should contain references to the interrupts for each channel.
+- clocks: Should be the clock specifiers corresponding to the entry in
+ clock-names property.
+- clock-names: Should contain "cqdma" entries.
+- dma-channels: The number of DMA channels supported by the controller.
+- dma-requests: The number of DMA request supported by the controller.
+- #dma-cells: The length of the DMA specifier, must be <1>. This one cell
+ in dmas property of a client device represents the channel
+ number.
+Example:
+
+ cqdma: dma-controller@10212000 {
+ compatible = "mediatek,mt6765-cqdma";
+ reg = <0 0x10212000 0 0x1000>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_IFR_CQ_DMA>;
+ clock-names = "cqdma";
+ dma-channels = <2>;
+ dma-requests = <32>;
+ #dma-cells = <1>;
+ };
+
+DMA clients must use the format described in dma/dma.txt file.
^ permalink raw reply related
* [1/1] dt-bindings: dmaengine: Add MediaTek Command-Queue DMA controller bindings
From: shun-chih.yu @ 2019-02-14 7:40 UTC (permalink / raw)
To: Sean Wang, Vinod Koul, Rob Herring, Matthias Brugger,
Dan Williams
Cc: dmaengine, linux-arm-kernel, linux-mediatek, devicetree,
linux-kernel, srv_wsdupstream, Shun-Chih Yu
From: Shun-Chih Yu <shun-chih.yu@mediatek.com>
Document the devicetree bindings for MediaTek Command-Queue DMA controller
which could be found on MT6765 SoC or other similar Mediatek SoCs.
Change-Id: I9736c8cac9be160358feeab935fabaffc5730519
Signed-off-by: Shun-Chih Yu <shun-chih.yu@mediatek.com>
---
.../devicetree/bindings/dma/mtk-cqdma.txt | 31 ++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/mtk-cqdma.txt
diff --git a/Documentation/devicetree/bindings/dma/mtk-cqdma.txt b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
new file mode 100644
index 0000000..fb12927
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/mtk-cqdma.txt
@@ -0,0 +1,31 @@
+MediaTek Command-Queue DMA Controller
+==================================
+
+Required properties:
+
+- compatible: Must be "mediatek,mt6765-cqdma" for MT6765.
+- reg: Should contain the base address and length for each channel.
+- interrupts: Should contain references to the interrupts for each channel.
+- clocks: Should be the clock specifiers corresponding to the entry in
+ clock-names property.
+- clock-names: Should contain "cqdma" entries.
+- dma-channels: The number of DMA channels supported by the controller.
+- dma-requests: The number of DMA request supported by the controller.
+- #dma-cells: The length of the DMA specifier, must be <1>. This one cell
+ in dmas property of a client device represents the channel
+ number.
+Example:
+
+ cqdma: dma-controller@10212000 {
+ compatible = "mediatek,mt6765-cqdma";
+ reg = <0 0x10212000 0 0x1000>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_IFR_CQ_DMA>;
+ clock-names = "cqdma";
+ dma-channels = <2>;
+ dma-requests = <32>;
+ #dma-cells = <1>;
+ };
+
+DMA clients must use the format described in dma/dma.txt file.
^ permalink raw reply related
* [v10,1/3] dmaengine: 8250_mtk_dma: add MediaTek uart DMA support
From: Long Cheng @ 2019-02-14 2:44 UTC (permalink / raw)
To: Vinod Koul
Cc: Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee, Sean Wang,
Nicolas Boichat, Matthias Brugger, Dan Williams,
Greg Kroah-Hartman, Jiri Slaby, Sean Wang, dmaengine, devicetree,
linux-arm-kernel, linux-mediatek, linux-kernel, linux-serial,
srv_heupstream, Yingjoe Chen, YT Shen, Zhenbao Liu, Long Cheng
On Mon, 2019-02-04 at 12:51 +0530, Vinod Koul wrote:
Hi Vinod sir,
> On 18-01-19, 11:10, Long Cheng wrote:
> > +static enum dma_status mtk_uart_apdma_tx_status(struct dma_chan *chan,
> > + dma_cookie_t cookie,
> > + struct dma_tx_state *txstate)
> > +{
> > + struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
> > + enum dma_status ret;
> > + unsigned long flags;
> > +
> > + if (!txstate)
> > + return DMA_ERROR;
>
> Why, it is not a mandatory arg!
Next version, I will remove it.
>
> > + ret = dma_cookie_status(chan, cookie, txstate);
> > + spin_lock_irqsave(&c->vc.lock, flags);
> > + if (ret == DMA_IN_PROGRESS) {
> > + c->rx_status = mtk_uart_apdma_read(c, VFF_RPT) & VFF_RING_SIZE;
> > + dma_set_residue(txstate, c->rx_status);
> > + } else if (ret == DMA_COMPLETE && c->dir == DMA_DEV_TO_MEM) {
> > + dma_set_residue(txstate, c->rx_status);
>
> what is the point is setting residue to comleted txn, it is zero!
>
> > + } else {
> > + dma_set_residue(txstate, 0);
>
> naah that doesnt sound correct!
>
Next version, I will modify the function.
> > +static void mtk_uart_apdma_config_write(struct dma_chan *chan,
> > + struct dma_slave_config *cfg,
> > + enum dma_transfer_direction dir)
> > +{
> > + struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
> > + struct mtk_uart_apdmadev *mtkd =
> > + to_mtk_uart_apdma_dev(c->vc.chan.device);
> > + unsigned int tmp;
> > +
> > + if (mtk_uart_apdma_read(c, VFF_EN) == VFF_EN_B)
> > + return;
> > +
> > + c->dir = dir;
> > +
> > + if (dir == DMA_DEV_TO_MEM) {
> > + tmp = cfg->src_addr_width * 1024;
>
> why multiply by 1024?
>
Next version, I will modify the this, with 'src_port_window_size' &&
'dst_port_window_size'.
> > +static int mtk_uart_apdma_device_pause(struct dma_chan *chan)
> > +{
> > + /* just for check caps pass */
> > + return 0;
> > +}
>
> please remove, this is not a mandatory fn
Can't remove it. Before the mail, i had explained it. in 8250 uart
framework, will check the function..
thanks.
^ permalink raw reply
* [01/18] MIPS: lantiq: pass struct device to DMA API functions
From: Paul Burton @ 2019-02-12 17:41 UTC (permalink / raw)
To: Christoph Hellwig
Cc: John Crispin, Vinod Koul, Dmitry Tarnyagin, Nicolas Ferre,
Sudip Mukherjee, Felipe Balbi, linux-mips@vger.kernel.org,
linux-kernel@vger.kernel.org, dmaengine@vger.kernel.org,
netdev@vger.kernel.org, linux-usb@vger.kernel.org,
linux-fbdev@vger.kernel.org, alsa-devel@alsa-project.org,
iommu@lists.linux-foundation.org
Hello,
Christoph Hellwig wrote:
> The DMA API generally relies on a struct device to work properly, and
> only barely works without one for legacy reasons. Pass the easily
> available struct device from the platform_device to remedy this.
>
> Also use GFP_KERNEL instead of GFP_ATOMIC as the gfp_t for the memory
> allocation, as we aren't in interrupt context or under a lock.
>
> Note that this whole function looks somewhat bogus given that we never
> even look at the returned dma address, and the CPHYSADDR magic on
> a returned noncached mapping looks "interesting". But I'll leave
> that to people more familiar with the code to sort out.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Applied to mips-fixes.
Thanks,
Paul
[ This message was auto-generated; if you believe anything is incorrect
then please email paul.burton@mips.com to report it. ]
^ permalink raw reply
* [V2,3/3] dmaengine: dmatest: move test data alloc & free into functions
From: Alexandru Ardelean @ 2019-02-12 15:11 UTC (permalink / raw)
To: dmaengine, vkoul; +Cc: Alexandru Ardelean
This patch starts to take advantage of the `dmatest_data` struct by moving
the common allocation & free-ing bits into functions.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/dma/dmatest.c | 110 +++++++++++++++++++++---------------------
1 file changed, 55 insertions(+), 55 deletions(-)
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 3b148c2647f8..50221d467d86 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -486,6 +486,53 @@ static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len)
return FIXPT_TO_INT(dmatest_persec(runtime, len >> 10));
}
+static void __dmatest_free_test_data(struct dmatest_data *d, unsigned int cnt)
+{
+ unsigned int i;
+
+ for (i = 0; i < cnt; i++)
+ kfree(d->raw[i]);
+
+ kfree(d->aligned);
+ kfree(d->raw);
+}
+
+static void dmatest_free_test_data(struct dmatest_data *d)
+{
+ __dmatest_free_test_data(d, d->cnt);
+}
+
+static int dmatest_alloc_test_data(struct dmatest_data *d,
+ unsigned int buf_size, u8 align)
+{
+ unsigned int i = 0;
+
+ d->raw = kcalloc(d->cnt + 1, sizeof(u8 *), GFP_KERNEL);
+ if (!d->raw)
+ return -ENOMEM;
+
+ d->aligned = kcalloc(d->cnt + 1, sizeof(u8 *), GFP_KERNEL);
+ if (!d->aligned)
+ goto err;
+
+ for (i = 0; i < d->cnt; i++) {
+ d->raw[i] = kmalloc(buf_size + align, GFP_KERNEL);
+ if (!d->raw[i])
+ goto err;
+
+ /* align to alignment restriction */
+ if (align)
+ d->aligned[i] = PTR_ALIGN(d->raw[i], align);
+ else
+ d->aligned[i] = d->raw[i];
+ }
+
+ return 0;
+err:
+ __dmatest_free_test_data(d, i);
+ return -ENOMEM;
+}
+
/*
* This function repeatedly tests DMA transfers of various lengths and
* offsets for a given operation type until it is told to exit by
@@ -588,55 +635,17 @@ static int dmatest_func(void *data)
goto err_free_coefs;
}
- src->aligned = kcalloc(src->cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!src->aligned)
+ if (dmatest_alloc_test_data(src, buf_size, align) < 0)
goto err_free_coefs;
- src->raw = kcalloc(src->cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!src->raw)
- goto err_usrcs;
-
- for (i = 0; i < src->cnt; i++) {
- src->raw[i] = kmalloc(buf_size + align,
- GFP_KERNEL);
- if (!src->raw[i])
- goto err_srcbuf;
-
- /* align srcs to alignment restriction */
- if (align)
- src->aligned[i] = PTR_ALIGN(src->raw[i], align);
- else
- src->aligned[i] = src->raw[i];
- }
- src->aligned[i] = NULL;
-
- dst->aligned = kcalloc(dst->cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!dst->aligned)
- goto err_dsts;
-
- dst->raw = kcalloc(dst->cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!dst->raw)
- goto err_udsts;
-
- for (i = 0; i < dst->cnt; i++) {
- dst->raw[i] = kmalloc(buf_size + align,
- GFP_KERNEL);
- if (!dst->raw[i])
- goto err_dstbuf;
-
- /* align dsts to alignment restriction */
- if (align)
- dst->aligned[i] = PTR_ALIGN(dst->raw[i], align);
- else
- dst->aligned[i] = dst->raw[i];
- }
- dst->aligned[i] = NULL;
+ if (dmatest_alloc_test_data(dst, buf_size, align) < 0)
+ goto err_src;
set_user_nice(current, 10);
srcs = kcalloc(src->cnt, sizeof(dma_addr_t), GFP_KERNEL);
if (!srcs)
- goto err_dstbuf;
+ goto err_dst;
dma_pq = kcalloc(dst->cnt, sizeof(dma_addr_t), GFP_KERNEL);
if (!dma_pq)
@@ -865,19 +874,10 @@ static int dmatest_func(void *data)
kfree(dma_pq);
err_srcs_array:
kfree(srcs);
-err_dstbuf:
- for (i = 0; dst->raw[i]; i++)
- kfree(dst->raw[i]);
- kfree(dst->raw);
-err_udsts:
- kfree(dst->aligned);
-err_dsts:
-err_srcbuf:
- for (i = 0; src->raw[i]; i++)
- kfree(src->raw[i]);
- kfree(src->raw);
-err_usrcs:
- kfree(src->aligned);
+err_dst:
+ dmatest_free_test_data(dst);
+err_src:
+ dmatest_free_test_data(src);
err_free_coefs:
kfree(pq_coefs);
err_thread_type:
^ permalink raw reply related
* [V2,2/3] dmaengine: dmatest: add short-hand `buf_size` var in dmatest_func()
From: Alexandru Ardelean @ 2019-02-12 15:11 UTC (permalink / raw)
To: dmaengine, vkoul; +Cc: Alexandru Ardelean
This is just a cosmetic change, since this variable gets used quite a bit
inside the dmatest_func() routine.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/dma/dmatest.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index ea1f885e70f4..3b148c2647f8 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -516,6 +516,7 @@ static int dmatest_func(void *data)
enum dma_ctrl_flags flags;
u8 *pq_coefs = NULL;
int ret;
+ unsigned int buf_size;
struct dmatest_data *src;
struct dmatest_data *dst;
int i;
@@ -580,9 +581,10 @@ static int dmatest_func(void *data)
goto err_free_coefs;
}
- if (1 << align > params->buf_size) {
+ buf_size = params->buf_size;
+ if (1 << align > buf_size) {
pr_err("%u-byte buffer too small for %d-byte alignment\n",
- params->buf_size, 1 << align);
+ buf_size, 1 << align);
goto err_free_coefs;
}
@@ -595,7 +597,7 @@ static int dmatest_func(void *data)
goto err_usrcs;
for (i = 0; i < src->cnt; i++) {
- src->raw[i] = kmalloc(params->buf_size + align,
+ src->raw[i] = kmalloc(buf_size + align,
GFP_KERNEL);
if (!src->raw[i])
goto err_srcbuf;
@@ -617,7 +619,7 @@ static int dmatest_func(void *data)
goto err_udsts;
for (i = 0; i < dst->cnt; i++) {
- dst->raw[i] = kmalloc(params->buf_size + align,
+ dst->raw[i] = kmalloc(buf_size + align,
GFP_KERNEL);
if (!dst->raw[i])
goto err_dstbuf;
@@ -656,16 +658,16 @@ static int dmatest_func(void *data)
total_tests++;
if (params->transfer_size) {
- if (params->transfer_size >= params->buf_size) {
+ if (params->transfer_size >= buf_size) {
pr_err("%u-byte transfer size must be lower than %u-buffer size\n",
- params->transfer_size, params->buf_size);
+ params->transfer_size, buf_size);
break;
}
len = params->transfer_size;
} else if (params->norandom) {
- len = params->buf_size;
+ len = buf_size;
} else {
- len = dmatest_random() % params->buf_size + 1;
+ len = dmatest_random() % buf_size + 1;
}
/* Do not alter transfer size explicitly defined by user */
@@ -680,8 +682,8 @@ static int dmatest_func(void *data)
src->off = 0;
dst->off = 0;
} else {
- src->off = dmatest_random() % (params->buf_size - len + 1);
- dst->off = dmatest_random() % (params->buf_size - len + 1);
+ src->off = dmatest_random() % (buf_size - len + 1);
+ dst->off = dmatest_random() % (buf_size - len + 1);
src->off = (src->off >> align) << align;
dst->off = (dst->off >> align) << align;
@@ -690,9 +692,9 @@ static int dmatest_func(void *data)
if (!params->noverify) {
start = ktime_get();
dmatest_init_srcs(src->aligned, src->off, len,
- params->buf_size, is_memset);
+ buf_size, is_memset);
dmatest_init_dsts(dst->aligned, dst->off, len,
- params->buf_size, is_memset);
+ buf_size, is_memset);
diff = ktime_sub(ktime_get(), start);
filltime = ktime_add(filltime, diff);
@@ -707,7 +709,7 @@ static int dmatest_func(void *data)
continue;
}
- um->len = params->buf_size;
+ um->len = buf_size;
for (i = 0; i < src->cnt; i++) {
void *buf = src->aligned[i];
struct page *pg = virt_to_page(buf);
@@ -827,7 +829,7 @@ static int dmatest_func(void *data)
src->off + len, src->off,
PATTERN_SRC | PATTERN_COPY, true, is_memset);
error_count += dmatest_verify(src->aligned, src->off + len,
- params->buf_size, src->off + len,
+ buf_size, src->off + len,
PATTERN_SRC, true, is_memset);
pr_debug("%s: verifying dest buffer...\n", current->comm);
@@ -839,7 +841,7 @@ static int dmatest_func(void *data)
PATTERN_SRC | PATTERN_COPY, false, is_memset);
error_count += dmatest_verify(dst->aligned, dst->off + len,
- params->buf_size, dst->off + len,
+ buf_size, dst->off + len,
PATTERN_DST, false, is_memset);
diff = ktime_sub(ktime_get(), start);
^ permalink raw reply related
* [V2,1/3] dmaengine: dmatest: wrap src & dst data into a struct
From: Alexandru Ardelean @ 2019-02-12 15:11 UTC (permalink / raw)
To: dmaengine, vkoul; +Cc: Alexandru Ardelean
This change wraps the data for the source & destination buffers into a
`struct dmatest_data`. The rename patterns are:
* src_cnt -> src->cnt
* dst_cnt -> dst->cnt
* src_off -> src->off
* dst_off -> dst->off
* thread->srcs -> src->aligned
* thread->usrcs -> src->raw
* thread->dsts -> dst->aligned
* thread->udsts -> dst->raw
The intent is to make a function that moves duplicate parts of the code
into common alloc & free functions, which will unclutter the
`dmatest_func()` function.
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
Changelog v1 -> v2:
* split original `[PATCH] dmaengine: dmatest: wrap src & dst data into a
struct` into 3 smaller patches
drivers/dma/dmatest.c | 195 ++++++++++++++++++++++--------------------
1 file changed, 101 insertions(+), 94 deletions(-)
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 2eea4ef72915..ea1f885e70f4 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -200,15 +200,20 @@ struct dmatest_done {
wait_queue_head_t *wait;
};
+struct dmatest_data {
+ u8 **raw;
+ u8 **aligned;
+ unsigned int cnt;
+ unsigned int off;
+};
+
struct dmatest_thread {
struct list_head node;
struct dmatest_info *info;
struct task_struct *task;
struct dma_chan *chan;
- u8 **srcs;
- u8 **usrcs;
- u8 **dsts;
- u8 **udsts;
+ struct dmatest_data src;
+ struct dmatest_data dst;
enum dma_transaction_type type;
wait_queue_head_t done_wait;
struct dmatest_done test_done;
@@ -511,8 +516,8 @@ static int dmatest_func(void *data)
enum dma_ctrl_flags flags;
u8 *pq_coefs = NULL;
int ret;
- int src_cnt;
- int dst_cnt;
+ struct dmatest_data *src;
+ struct dmatest_data *dst;
int i;
ktime_t ktime, start, diff;
ktime_t filltime = 0;
@@ -535,25 +540,27 @@ static int dmatest_func(void *data)
params = &info->params;
chan = thread->chan;
dev = chan->device;
+ src = &thread->src;
+ dst = &thread->dst;
if (thread->type == DMA_MEMCPY) {
align = params->alignment < 0 ? dev->copy_align :
params->alignment;
- src_cnt = dst_cnt = 1;
+ src->cnt = dst->cnt = 1;
} else if (thread->type == DMA_MEMSET) {
align = params->alignment < 0 ? dev->fill_align :
params->alignment;
- src_cnt = dst_cnt = 1;
+ src->cnt = dst->cnt = 1;
is_memset = true;
} else if (thread->type == DMA_XOR) {
/* force odd to ensure dst = src */
- src_cnt = min_odd(params->xor_sources | 1, dev->max_xor);
- dst_cnt = 1;
+ src->cnt = min_odd(params->xor_sources | 1, dev->max_xor);
+ dst->cnt = 1;
align = params->alignment < 0 ? dev->xor_align :
params->alignment;
} else if (thread->type == DMA_PQ) {
/* force odd to ensure dst = src */
- src_cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0));
- dst_cnt = 2;
+ src->cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0));
+ dst->cnt = 2;
align = params->alignment < 0 ? dev->pq_align :
params->alignment;
@@ -561,15 +568,15 @@ static int dmatest_func(void *data)
if (!pq_coefs)
goto err_thread_type;
- for (i = 0; i < src_cnt; i++)
+ for (i = 0; i < src->cnt; i++)
pq_coefs[i] = 1;
} else
goto err_thread_type;
/* Check if buffer count fits into map count variable (u8) */
- if ((src_cnt + dst_cnt) >= 255) {
+ if ((src->cnt + dst->cnt) >= 255) {
pr_err("too many buffers (%d of 255 supported)\n",
- src_cnt + dst_cnt);
+ src->cnt + dst->cnt);
goto err_free_coefs;
}
@@ -579,57 +586,57 @@ static int dmatest_func(void *data)
goto err_free_coefs;
}
- thread->srcs = kcalloc(src_cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!thread->srcs)
+ src->aligned = kcalloc(src->cnt + 1, sizeof(u8 *), GFP_KERNEL);
+ if (!src->aligned)
goto err_free_coefs;
- thread->usrcs = kcalloc(src_cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!thread->usrcs)
+ src->raw = kcalloc(src->cnt + 1, sizeof(u8 *), GFP_KERNEL);
+ if (!src->raw)
goto err_usrcs;
- for (i = 0; i < src_cnt; i++) {
- thread->usrcs[i] = kmalloc(params->buf_size + align,
+ for (i = 0; i < src->cnt; i++) {
+ src->raw[i] = kmalloc(params->buf_size + align,
GFP_KERNEL);
- if (!thread->usrcs[i])
+ if (!src->raw[i])
goto err_srcbuf;
/* align srcs to alignment restriction */
if (align)
- thread->srcs[i] = PTR_ALIGN(thread->usrcs[i], align);
+ src->aligned[i] = PTR_ALIGN(src->raw[i], align);
else
- thread->srcs[i] = thread->usrcs[i];
+ src->aligned[i] = src->raw[i];
}
- thread->srcs[i] = NULL;
+ src->aligned[i] = NULL;
- thread->dsts = kcalloc(dst_cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!thread->dsts)
+ dst->aligned = kcalloc(dst->cnt + 1, sizeof(u8 *), GFP_KERNEL);
+ if (!dst->aligned)
goto err_dsts;
- thread->udsts = kcalloc(dst_cnt + 1, sizeof(u8 *), GFP_KERNEL);
- if (!thread->udsts)
+ dst->raw = kcalloc(dst->cnt + 1, sizeof(u8 *), GFP_KERNEL);
+ if (!dst->raw)
goto err_udsts;
- for (i = 0; i < dst_cnt; i++) {
- thread->udsts[i] = kmalloc(params->buf_size + align,
+ for (i = 0; i < dst->cnt; i++) {
+ dst->raw[i] = kmalloc(params->buf_size + align,
GFP_KERNEL);
- if (!thread->udsts[i])
+ if (!dst->raw[i])
goto err_dstbuf;
/* align dsts to alignment restriction */
if (align)
- thread->dsts[i] = PTR_ALIGN(thread->udsts[i], align);
+ dst->aligned[i] = PTR_ALIGN(dst->raw[i], align);
else
- thread->dsts[i] = thread->udsts[i];
+ dst->aligned[i] = dst->raw[i];
}
- thread->dsts[i] = NULL;
+ dst->aligned[i] = NULL;
set_user_nice(current, 10);
- srcs = kcalloc(src_cnt, sizeof(dma_addr_t), GFP_KERNEL);
+ srcs = kcalloc(src->cnt, sizeof(dma_addr_t), GFP_KERNEL);
if (!srcs)
goto err_dstbuf;
- dma_pq = kcalloc(dst_cnt, sizeof(dma_addr_t), GFP_KERNEL);
+ dma_pq = kcalloc(dst->cnt, sizeof(dma_addr_t), GFP_KERNEL);
if (!dma_pq)
goto err_srcs_array;
@@ -644,7 +651,7 @@ static int dmatest_func(void *data)
struct dma_async_tx_descriptor *tx = NULL;
struct dmaengine_unmap_data *um;
dma_addr_t *dsts;
- unsigned int src_off, dst_off, len;
+ unsigned int len;
total_tests++;
@@ -670,59 +677,59 @@ static int dmatest_func(void *data)
total_len += len;
if (params->norandom) {
- src_off = 0;
- dst_off = 0;
+ src->off = 0;
+ dst->off = 0;
} else {
- src_off = dmatest_random() % (params->buf_size - len + 1);
- dst_off = dmatest_random() % (params->buf_size - len + 1);
+ src->off = dmatest_random() % (params->buf_size - len + 1);
+ dst->off = dmatest_random() % (params->buf_size - len + 1);
- src_off = (src_off >> align) << align;
- dst_off = (dst_off >> align) << align;
+ src->off = (src->off >> align) << align;
+ dst->off = (dst->off >> align) << align;
}
if (!params->noverify) {
start = ktime_get();
- dmatest_init_srcs(thread->srcs, src_off, len,
+ dmatest_init_srcs(src->aligned, src->off, len,
params->buf_size, is_memset);
- dmatest_init_dsts(thread->dsts, dst_off, len,
+ dmatest_init_dsts(dst->aligned, dst->off, len,
params->buf_size, is_memset);
diff = ktime_sub(ktime_get(), start);
filltime = ktime_add(filltime, diff);
}
- um = dmaengine_get_unmap_data(dev->dev, src_cnt + dst_cnt,
+ um = dmaengine_get_unmap_data(dev->dev, src->cnt + dst->cnt,
GFP_KERNEL);
if (!um) {
failed_tests++;
result("unmap data NULL", total_tests,
- src_off, dst_off, len, ret);
+ src->off, dst->off, len, ret);
continue;
}
um->len = params->buf_size;
- for (i = 0; i < src_cnt; i++) {
- void *buf = thread->srcs[i];
+ for (i = 0; i < src->cnt; i++) {
+ void *buf = src->aligned[i];
struct page *pg = virt_to_page(buf);
unsigned long pg_off = offset_in_page(buf);
um->addr[i] = dma_map_page(dev->dev, pg, pg_off,
um->len, DMA_TO_DEVICE);
- srcs[i] = um->addr[i] + src_off;
+ srcs[i] = um->addr[i] + src->off;
ret = dma_mapping_error(dev->dev, um->addr[i]);
if (ret) {
dmaengine_unmap_put(um);
result("src mapping error", total_tests,
- src_off, dst_off, len, ret);
+ src->off, dst->off, len, ret);
failed_tests++;
continue;
}
um->to_cnt++;
}
/* map with DMA_BIDIRECTIONAL to force writeback/invalidate */
- dsts = &um->addr[src_cnt];
- for (i = 0; i < dst_cnt; i++) {
- void *buf = thread->dsts[i];
+ dsts = &um->addr[src->cnt];
+ for (i = 0; i < dst->cnt; i++) {
+ void *buf = dst->aligned[i];
struct page *pg = virt_to_page(buf);
unsigned long pg_off = offset_in_page(buf);
@@ -732,7 +739,7 @@ static int dmatest_func(void *data)
if (ret) {
dmaengine_unmap_put(um);
result("dst mapping error", total_tests,
- src_off, dst_off, len, ret);
+ src->off, dst->off, len, ret);
failed_tests++;
continue;
}
@@ -741,30 +748,30 @@ static int dmatest_func(void *data)
if (thread->type == DMA_MEMCPY)
tx = dev->device_prep_dma_memcpy(chan,
- dsts[0] + dst_off,
+ dsts[0] + dst->off,
srcs[0], len, flags);
else if (thread->type == DMA_MEMSET)
tx = dev->device_prep_dma_memset(chan,
- dsts[0] + dst_off,
- *(thread->srcs[0] + src_off),
+ dsts[0] + dst->off,
+ *(src->aligned[0] + src->off),
len, flags);
else if (thread->type == DMA_XOR)
tx = dev->device_prep_dma_xor(chan,
- dsts[0] + dst_off,
- srcs, src_cnt,
+ dsts[0] + dst->off,
+ srcs, src->cnt,
len, flags);
else if (thread->type == DMA_PQ) {
- for (i = 0; i < dst_cnt; i++)
- dma_pq[i] = dsts[i] + dst_off;
+ for (i = 0; i < dst->cnt; i++)
+ dma_pq[i] = dsts[i] + dst->off;
tx = dev->device_prep_dma_pq(chan, dma_pq, srcs,
- src_cnt, pq_coefs,
+ src->cnt, pq_coefs,
len, flags);
}
if (!tx) {
dmaengine_unmap_put(um);
- result("prep error", total_tests, src_off,
- dst_off, len, ret);
+ result("prep error", total_tests, src->off,
+ dst->off, len, ret);
msleep(100);
failed_tests++;
continue;
@@ -777,8 +784,8 @@ static int dmatest_func(void *data)
if (dma_submit_error(cookie)) {
dmaengine_unmap_put(um);
- result("submit error", total_tests, src_off,
- dst_off, len, ret);
+ result("submit error", total_tests, src->off,
+ dst->off, len, ret);
msleep(100);
failed_tests++;
continue;
@@ -793,58 +800,58 @@ static int dmatest_func(void *data)
dmaengine_unmap_put(um);
if (!done->done) {
- result("test timed out", total_tests, src_off, dst_off,
+ result("test timed out", total_tests, src->off, dst->off,
len, 0);
failed_tests++;
continue;
} else if (status != DMA_COMPLETE) {
result(status == DMA_ERROR ?
"completion error status" :
- "completion busy status", total_tests, src_off,
- dst_off, len, ret);
+ "completion busy status", total_tests, src->off,
+ dst->off, len, ret);
failed_tests++;
continue;
}
if (params->noverify) {
- verbose_result("test passed", total_tests, src_off,
- dst_off, len, 0);
+ verbose_result("test passed", total_tests, src->off,
+ dst->off, len, 0);
continue;
}
start = ktime_get();
pr_debug("%s: verifying source buffer...\n", current->comm);
- error_count = dmatest_verify(thread->srcs, 0, src_off,
+ error_count = dmatest_verify(src->aligned, 0, src->off,
0, PATTERN_SRC, true, is_memset);
- error_count += dmatest_verify(thread->srcs, src_off,
- src_off + len, src_off,
+ error_count += dmatest_verify(src->aligned, src->off,
+ src->off + len, src->off,
PATTERN_SRC | PATTERN_COPY, true, is_memset);
- error_count += dmatest_verify(thread->srcs, src_off + len,
- params->buf_size, src_off + len,
+ error_count += dmatest_verify(src->aligned, src->off + len,
+ params->buf_size, src->off + len,
PATTERN_SRC, true, is_memset);
pr_debug("%s: verifying dest buffer...\n", current->comm);
- error_count += dmatest_verify(thread->dsts, 0, dst_off,
+ error_count += dmatest_verify(dst->aligned, 0, dst->off,
0, PATTERN_DST, false, is_memset);
- error_count += dmatest_verify(thread->dsts, dst_off,
- dst_off + len, src_off,
+ error_count += dmatest_verify(dst->aligned, dst->off,
+ dst->off + len, src->off,
PATTERN_SRC | PATTERN_COPY, false, is_memset);
- error_count += dmatest_verify(thread->dsts, dst_off + len,
- params->buf_size, dst_off + len,
+ error_count += dmatest_verify(dst->aligned, dst->off + len,
+ params->buf_size, dst->off + len,
PATTERN_DST, false, is_memset);
diff = ktime_sub(ktime_get(), start);
comparetime = ktime_add(comparetime, diff);
if (error_count) {
- result("data error", total_tests, src_off, dst_off,
+ result("data error", total_tests, src->off, dst->off,
len, error_count);
failed_tests++;
} else {
- verbose_result("test passed", total_tests, src_off,
- dst_off, len, 0);
+ verbose_result("test passed", total_tests, src->off,
+ dst->off, len, 0);
}
}
ktime = ktime_sub(ktime_get(), ktime);
@@ -857,18 +864,18 @@ static int dmatest_func(void *data)
err_srcs_array:
kfree(srcs);
err_dstbuf:
- for (i = 0; thread->udsts[i]; i++)
- kfree(thread->udsts[i]);
- kfree(thread->udsts);
+ for (i = 0; dst->raw[i]; i++)
+ kfree(dst->raw[i]);
+ kfree(dst->raw);
err_udsts:
- kfree(thread->dsts);
+ kfree(dst->aligned);
err_dsts:
err_srcbuf:
- for (i = 0; thread->usrcs[i]; i++)
- kfree(thread->usrcs[i]);
- kfree(thread->usrcs);
+ for (i = 0; src->raw[i]; i++)
+ kfree(src->raw[i]);
+ kfree(src->raw);
err_usrcs:
- kfree(thread->srcs);
+ kfree(src->aligned);
err_free_coefs:
kfree(pq_coefs);
err_thread_type:
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox