Skip to content

Commit c437279

Browse files
committed
Merge tag 'dmaengine-fix-4.15-rc4' of git://git.infradead.org/users/vkoul/slave-dma
Pull dmaengine fixes from Vinod Koul: "This time consisting of fixes in a bunch of drivers and the dmatest module: - Fix for disable clk on error path in fsl-edma driver - Disable clk fail fix in jz4740 driver - Fix long pending bug in dmatest driver for dangling pointer - Fix potential NULL pointer dereference in at_hdmac driver - Error handling path in ioat driver" * tag 'dmaengine-fix-4.15-rc4' of git://git.infradead.org/users/vkoul/slave-dma: dmaengine: fsl-edma: disable clks on all error paths dmaengine: jz4740: disable/unprepare clk if probe fails dmaengine: dmatest: move callback wait queue to thread context dmaengine: at_hdmac: fix potential NULL pointer dereference in atc_prep_dma_interleaved dmaengine: ioat: Fix error handling path
2 parents b9f5fb1 + 2610acf commit c437279

File tree

5 files changed

+52
-41
lines changed

5 files changed

+52
-41
lines changed

drivers/dma/at_hdmac.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
708708
unsigned long flags)
709709
{
710710
struct at_dma_chan *atchan = to_at_dma_chan(chan);
711-
struct data_chunk *first = xt->sgl;
711+
struct data_chunk *first;
712712
struct at_desc *desc = NULL;
713713
size_t xfer_count;
714714
unsigned int dwidth;
@@ -720,6 +720,8 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
720720
if (unlikely(!xt || xt->numf != 1 || !xt->frame_size))
721721
return NULL;
722722

723+
first = xt->sgl;
724+
723725
dev_info(chan2dev(chan),
724726
"%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
725727
__func__, &xt->src_start, &xt->dst_start, xt->numf,

drivers/dma/dma-jz4740.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ static int jz4740_dma_probe(struct platform_device *pdev)
555555

556556
ret = dma_async_device_register(dd);
557557
if (ret)
558-
return ret;
558+
goto err_clk;
559559

560560
irq = platform_get_irq(pdev, 0);
561561
ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
@@ -568,6 +568,8 @@ static int jz4740_dma_probe(struct platform_device *pdev)
568568

569569
err_unregister:
570570
dma_async_device_unregister(dd);
571+
err_clk:
572+
clk_disable_unprepare(dmadev->clk);
571573
return ret;
572574
}
573575

drivers/dma/dmatest.c

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ MODULE_PARM_DESC(run, "Run the test (default: false)");
155155
#define PATTERN_COUNT_MASK 0x1f
156156
#define PATTERN_MEMSET_IDX 0x01
157157

158+
/* poor man's completion - we want to use wait_event_freezable() on it */
159+
struct dmatest_done {
160+
bool done;
161+
wait_queue_head_t *wait;
162+
};
163+
158164
struct dmatest_thread {
159165
struct list_head node;
160166
struct dmatest_info *info;
@@ -165,6 +171,8 @@ struct dmatest_thread {
165171
u8 **dsts;
166172
u8 **udsts;
167173
enum dma_transaction_type type;
174+
wait_queue_head_t done_wait;
175+
struct dmatest_done test_done;
168176
bool done;
169177
};
170178

@@ -342,18 +350,25 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start,
342350
return error_count;
343351
}
344352

345-
/* poor man's completion - we want to use wait_event_freezable() on it */
346-
struct dmatest_done {
347-
bool done;
348-
wait_queue_head_t *wait;
349-
};
350353

351354
static void dmatest_callback(void *arg)
352355
{
353356
struct dmatest_done *done = arg;
354-
355-
done->done = true;
356-
wake_up_all(done->wait);
357+
struct dmatest_thread *thread =
358+
container_of(arg, struct dmatest_thread, done_wait);
359+
if (!thread->done) {
360+
done->done = true;
361+
wake_up_all(done->wait);
362+
} else {
363+
/*
364+
* If thread->done, it means that this callback occurred
365+
* after the parent thread has cleaned up. This can
366+
* happen in the case that driver doesn't implement
367+
* the terminate_all() functionality and a dma operation
368+
* did not occur within the timeout period
369+
*/
370+
WARN(1, "dmatest: Kernel memory may be corrupted!!\n");
371+
}
357372
}
358373

359374
static unsigned int min_odd(unsigned int x, unsigned int y)
@@ -424,9 +439,8 @@ static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len)
424439
*/
425440
static int dmatest_func(void *data)
426441
{
427-
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait);
428442
struct dmatest_thread *thread = data;
429-
struct dmatest_done done = { .wait = &done_wait };
443+
struct dmatest_done *done = &thread->test_done;
430444
struct dmatest_info *info;
431445
struct dmatest_params *params;
432446
struct dma_chan *chan;
@@ -673,9 +687,9 @@ static int dmatest_func(void *data)
673687
continue;
674688
}
675689

676-
done.done = false;
690+
done->done = false;
677691
tx->callback = dmatest_callback;
678-
tx->callback_param = &done;
692+
tx->callback_param = done;
679693
cookie = tx->tx_submit(tx);
680694

681695
if (dma_submit_error(cookie)) {
@@ -688,21 +702,12 @@ static int dmatest_func(void *data)
688702
}
689703
dma_async_issue_pending(chan);
690704

691-
wait_event_freezable_timeout(done_wait, done.done,
705+
wait_event_freezable_timeout(thread->done_wait, done->done,
692706
msecs_to_jiffies(params->timeout));
693707

694708
status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
695709

696-
if (!done.done) {
697-
/*
698-
* We're leaving the timed out dma operation with
699-
* dangling pointer to done_wait. To make this
700-
* correct, we'll need to allocate wait_done for
701-
* each test iteration and perform "who's gonna
702-
* free it this time?" dancing. For now, just
703-
* leave it dangling.
704-
*/
705-
WARN(1, "dmatest: Kernel stack may be corrupted!!\n");
710+
if (!done->done) {
706711
dmaengine_unmap_put(um);
707712
result("test timed out", total_tests, src_off, dst_off,
708713
len, 0);
@@ -789,7 +794,7 @@ static int dmatest_func(void *data)
789794
dmatest_KBs(runtime, total_len), ret);
790795

791796
/* terminate all transfers on specified channels */
792-
if (ret)
797+
if (ret || failed_tests)
793798
dmaengine_terminate_all(chan);
794799

795800
thread->done = true;
@@ -849,6 +854,8 @@ static int dmatest_add_threads(struct dmatest_info *info,
849854
thread->info = info;
850855
thread->chan = dtc->chan;
851856
thread->type = type;
857+
thread->test_done.wait = &thread->done_wait;
858+
init_waitqueue_head(&thread->done_wait);
852859
smp_wmb();
853860
thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
854861
dma_chan_name(chan), op, i);

drivers/dma/fsl-edma.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -863,11 +863,11 @@ static void fsl_edma_irq_exit(
863863
}
864864
}
865865

866-
static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma)
866+
static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks)
867867
{
868868
int i;
869869

870-
for (i = 0; i < DMAMUX_NR; i++)
870+
for (i = 0; i < nr_clocks; i++)
871871
clk_disable_unprepare(fsl_edma->muxclk[i]);
872872
}
873873

@@ -904,25 +904,25 @@ static int fsl_edma_probe(struct platform_device *pdev)
904904

905905
res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
906906
fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
907-
if (IS_ERR(fsl_edma->muxbase[i]))
907+
if (IS_ERR(fsl_edma->muxbase[i])) {
908+
/* on error: disable all previously enabled clks */
909+
fsl_disable_clocks(fsl_edma, i);
908910
return PTR_ERR(fsl_edma->muxbase[i]);
911+
}
909912

910913
sprintf(clkname, "dmamux%d", i);
911914
fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
912915
if (IS_ERR(fsl_edma->muxclk[i])) {
913916
dev_err(&pdev->dev, "Missing DMAMUX block clock.\n");
917+
/* on error: disable all previously enabled clks */
918+
fsl_disable_clocks(fsl_edma, i);
914919
return PTR_ERR(fsl_edma->muxclk[i]);
915920
}
916921

917922
ret = clk_prepare_enable(fsl_edma->muxclk[i]);
918-
if (ret) {
919-
/* disable only clks which were enabled on error */
920-
for (; i >= 0; i--)
921-
clk_disable_unprepare(fsl_edma->muxclk[i]);
922-
923-
dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
924-
return ret;
925-
}
923+
if (ret)
924+
/* on error: disable all previously enabled clks */
925+
fsl_disable_clocks(fsl_edma, i);
926926

927927
}
928928

@@ -976,7 +976,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
976976
if (ret) {
977977
dev_err(&pdev->dev,
978978
"Can't register Freescale eDMA engine. (%d)\n", ret);
979-
fsl_disable_clocks(fsl_edma);
979+
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
980980
return ret;
981981
}
982982

@@ -985,7 +985,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
985985
dev_err(&pdev->dev,
986986
"Can't register Freescale eDMA of_dma. (%d)\n", ret);
987987
dma_async_device_unregister(&fsl_edma->dma_dev);
988-
fsl_disable_clocks(fsl_edma);
988+
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
989989
return ret;
990990
}
991991

@@ -1015,7 +1015,7 @@ static int fsl_edma_remove(struct platform_device *pdev)
10151015
fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
10161016
of_dma_controller_free(np);
10171017
dma_async_device_unregister(&fsl_edma->dma_dev);
1018-
fsl_disable_clocks(fsl_edma);
1018+
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
10191019

10201020
return 0;
10211021
}

drivers/dma/ioat/init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ static int ioat_dma_self_test(struct ioatdma_device *ioat_dma)
390390
if (memcmp(src, dest, IOAT_TEST_SIZE)) {
391391
dev_err(dev, "Self-test copy failed compare, disabling\n");
392392
err = -ENODEV;
393-
goto free_resources;
393+
goto unmap_dma;
394394
}
395395

396396
unmap_dma:

0 commit comments

Comments
 (0)