From d1cab34c039584ebe76b04d2f2109e0d87d344e1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Oct 2013 19:35:21 +0200 Subject: dmatest: make driver unmap also source buffers by itself Make the driver DMA unmap also source buffers by itself (currently it DMA unmaps only destination buffers) as a preparation for introducing generic 'ummap' data. Cc: Dan Williams Cc: Vinod Koul Cc: Tomasz Figa Cc: Dave Jiang Cc: Andy Shevchenko Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 92f796cdc6ab..f4a2a25fae31 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -597,11 +597,10 @@ static int dmatest_func(void *data) set_user_nice(current, 10); /* - * src buffers are freed by the DMAEngine code with dma_unmap_single() - * dst buffers are freed by ourselves below + * src and dst buffers are freed by ourselves below */ - flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT - | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE; + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | + DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP; while (!kthread_should_stop() && !(params->iterations && total_tests >= params->iterations)) { @@ -750,7 +749,8 @@ static int dmatest_func(void *data) continue; } - /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ + /* Unmap by myself */ + unmap_src(dev->dev, dma_srcs, len, src_cnt); unmap_dst(dev->dev, dma_dsts, params->buf_size, dst_cnt); error_count = 0; -- cgit v1.2.3-59-g8ed1b From 0776ae7b89782124ddd72eafe0b1e0fdcdabe32e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 18 Oct 2013 19:35:33 +0200 Subject: dmaengine: remove DMA unmap flags Remove no longer needed DMA unmap flags: - DMA_COMPL_SKIP_SRC_UNMAP - DMA_COMPL_SKIP_DEST_UNMAP - DMA_COMPL_SRC_UNMAP_SINGLE - DMA_COMPL_DEST_UNMAP_SINGLE Cc: Vinod Koul Cc: Tomasz Figa Cc: Dave Jiang Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Acked-by: Jon Mason Acked-by: Mark Brown [djbw: clean up straggling skip unmap flags in ntb] Signed-off-by: Dan Williams --- crypto/async_tx/async_memcpy.c | 3 +-- crypto/async_tx/async_pq.c | 1 - crypto/async_tx/async_raid6_recov.c | 8 ++------ crypto/async_tx/async_xor.c | 6 ++---- drivers/ata/pata_arasan_cf.c | 3 +-- drivers/dma/dmaengine.c | 3 +-- drivers/dma/dmatest.c | 3 +-- drivers/dma/ioat/dma.c | 3 +-- drivers/dma/ioat/dma_v3.c | 12 +++--------- drivers/media/platform/m2m-deinterlace.c | 3 +-- drivers/media/platform/timblogiw.c | 2 +- drivers/misc/carma/carma-fpga.c | 3 +-- drivers/mtd/nand/atmel_nand.c | 3 +-- drivers/mtd/nand/fsmc_nand.c | 2 -- drivers/net/ethernet/micrel/ks8842.c | 6 ++---- drivers/ntb/ntb_transport.c | 11 +++-------- drivers/spi/spi-dw-mid.c | 4 ++-- include/linux/dmaengine.h | 18 ++++-------------- 18 files changed, 27 insertions(+), 67 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c index 72750214f779..f8c0b8dbeb75 100644 --- a/crypto/async_tx/async_memcpy.c +++ b/crypto/async_tx/async_memcpy.c @@ -56,8 +56,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOIO); if (unmap && is_dma_copy_aligned(device, src_offset, dest_offset, len)) { - unsigned long dma_prep_flags = DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP; + unsigned long dma_prep_flags = 0; if (submit->cb_fn) dma_prep_flags |= DMA_PREP_INTERRUPT; diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c index 4126b56fbc01..d05327caf69d 100644 --- a/crypto/async_tx/async_pq.c +++ b/crypto/async_tx/async_pq.c @@ -62,7 +62,6 @@ do_async_gen_syndrome(struct dma_chan *chan, dma_addr_t dma_dest[2]; int src_off = 0; - dma_flags |= DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP; if (submit->flags & ASYNC_TX_FENCE) dma_flags |= DMA_PREP_FENCE; diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c index a3a72a784421..934a84981495 100644 --- a/crypto/async_tx/async_raid6_recov.c +++ b/crypto/async_tx/async_raid6_recov.c @@ -47,9 +47,7 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef, struct device *dev = dma->dev; dma_addr_t pq[2]; struct dma_async_tx_descriptor *tx; - enum dma_ctrl_flags dma_flags = DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP | - DMA_PREP_PQ_DISABLE_P; + enum dma_ctrl_flags dma_flags = DMA_PREP_PQ_DISABLE_P; if (submit->flags & ASYNC_TX_FENCE) dma_flags |= DMA_PREP_FENCE; @@ -113,9 +111,7 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len, dma_addr_t dma_dest[2]; struct device *dev = dma->dev; struct dma_async_tx_descriptor *tx; - enum dma_ctrl_flags dma_flags = DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP | - DMA_PREP_PQ_DISABLE_P; + enum dma_ctrl_flags dma_flags = DMA_PREP_PQ_DISABLE_P; if (submit->flags & ASYNC_TX_FENCE) dma_flags |= DMA_PREP_FENCE; diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c index d2cc77d501c7..3c562f5a60bb 100644 --- a/crypto/async_tx/async_xor.c +++ b/crypto/async_tx/async_xor.c @@ -41,7 +41,7 @@ do_async_xor(struct dma_chan *chan, struct dmaengine_unmap_data *unmap, dma_async_tx_callback cb_fn_orig = submit->cb_fn; void *cb_param_orig = submit->cb_param; enum async_tx_flags flags_orig = submit->flags; - enum dma_ctrl_flags dma_flags; + enum dma_ctrl_flags dma_flags = 0; int src_cnt = unmap->to_cnt; int xor_src_cnt; dma_addr_t dma_dest = unmap->addr[unmap->to_cnt]; @@ -55,7 +55,6 @@ do_async_xor(struct dma_chan *chan, struct dmaengine_unmap_data *unmap, /* if we are submitting additional xors, leave the chain open * and clear the callback parameters */ - dma_flags = DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP; if (src_cnt > xor_src_cnt) { submit->flags &= ~ASYNC_TX_ACK; submit->flags |= ASYNC_TX_FENCE; @@ -284,8 +283,7 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, if (unmap && src_cnt <= device->max_xor && is_dma_xor_aligned(device, offset, 0, len)) { - unsigned long dma_prep_flags = DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP; + unsigned long dma_prep_flags = 0; int i; pr_debug("%s: (async) len: %zu\n", __func__, len); diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 853f610af28f..e88690ebfd82 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -396,8 +396,7 @@ dma_xfer(struct arasan_cf_dev *acdev, dma_addr_t src, dma_addr_t dest, u32 len) struct dma_async_tx_descriptor *tx; struct dma_chan *chan = acdev->dma_chan; dma_cookie_t cookie; - unsigned long flags = DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP; + unsigned long flags = DMA_PREP_INTERRUPT; int ret = 0; tx = chan->device->device_prep_dma_memcpy(chan, dest, src, len, flags); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index f878c808466e..b69ac3892b86 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1065,8 +1065,7 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg, unmap->addr[1] = dma_map_page(dev->dev, dest_pg, dest_off, len, DMA_FROM_DEVICE); unmap->len = len; - flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP; + flags = DMA_CTRL_ACK; tx = dev->device_prep_dma_memcpy(chan, unmap->addr[1], unmap->addr[0], len, flags); diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index f4a2a25fae31..5791091c13ca 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -599,8 +599,7 @@ static int dmatest_func(void *data) /* * src and dst buffers are freed by ourselves below */ - flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | - DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP; + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; while (!kthread_should_stop() && !(params->iterations && total_tests >= params->iterations)) { diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index c123e32dbbb0..6fcf741ad91b 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -818,8 +818,7 @@ int ioat_dma_self_test(struct ioatdma_device *device) dma_src = dma_map_single(dev, src, IOAT_TEST_SIZE, DMA_TO_DEVICE); dma_dest = dma_map_single(dev, dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE); - flags = DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP | - DMA_PREP_INTERRUPT; + flags = DMA_PREP_INTERRUPT; tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src, IOAT_TEST_SIZE, flags); if (!tx) { diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index 43386c171bba..a4798f0cc225 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -1279,9 +1279,7 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device) DMA_TO_DEVICE); tx = dma->device_prep_dma_xor(dma_chan, dest_dma, dma_srcs, IOAT_NUM_SRC_TEST, PAGE_SIZE, - DMA_PREP_INTERRUPT | - DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP); + DMA_PREP_INTERRUPT); if (!tx) { dev_err(dev, "Self-test xor prep failed\n"); @@ -1342,9 +1340,7 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device) DMA_TO_DEVICE); tx = dma->device_prep_dma_xor_val(dma_chan, dma_srcs, IOAT_NUM_SRC_TEST + 1, PAGE_SIZE, - &xor_val_result, DMA_PREP_INTERRUPT | - DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP); + &xor_val_result, DMA_PREP_INTERRUPT); if (!tx) { dev_err(dev, "Self-test zero prep failed\n"); err = -ENODEV; @@ -1389,9 +1385,7 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device) DMA_TO_DEVICE); tx = dma->device_prep_dma_xor_val(dma_chan, dma_srcs, IOAT_NUM_SRC_TEST + 1, PAGE_SIZE, - &xor_val_result, DMA_PREP_INTERRUPT | - DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP); + &xor_val_result, DMA_PREP_INTERRUPT); if (!tx) { dev_err(dev, "Self-test 2nd zero prep failed\n"); err = -ENODEV; diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 540516ca872c..879ea6fdd1be 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -341,8 +341,7 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op, ctx->xt->dir = DMA_MEM_TO_MEM; ctx->xt->src_sgl = false; ctx->xt->dst_sgl = true; - flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | - DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SKIP_SRC_UNMAP; + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags); if (tx == NULL) { diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c index b557caf5b1a4..59a95e3ab0e3 100644 --- a/drivers/media/platform/timblogiw.c +++ b/drivers/media/platform/timblogiw.c @@ -565,7 +565,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) desc = dmaengine_prep_slave_sg(fh->chan, buf->sg, sg_elems, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); + DMA_PREP_INTERRUPT); if (!desc) { spin_lock_irq(&fh->queue_lock); list_del_init(&vb->queue); diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 7b56563f8b74..5335104e7c84 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c @@ -631,8 +631,7 @@ static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf) struct dma_async_tx_descriptor *tx; dma_cookie_t cookie; dma_addr_t dst, src; - unsigned long dma_flags = DMA_COMPL_SKIP_DEST_UNMAP | - DMA_COMPL_SKIP_SRC_UNMAP; + unsigned long dma_flags = 0; dst_sg = buf->vb.sglist; dst_nents = buf->vb.sglen; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 060feeaf6b3e..2a837cb425d7 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -375,8 +375,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, dma_dev = host->dma_chan->device; - flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP | - DMA_COMPL_SKIP_DEST_UNMAP; + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; phys_addr = dma_map_single(dma_dev->dev, p, len, dir); if (dma_mapping_error(dma_dev->dev, phys_addr)) { diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 3dc1a7564d87..8b2752263db9 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -573,8 +573,6 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, dma_dev = chan->device; dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction); - flags |= DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP; - if (direction == DMA_TO_DEVICE) { dma_src = dma_addr; dma_dst = host->data_pa; diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c index 0951f7aca1ef..822616e3c375 100644 --- a/drivers/net/ethernet/micrel/ks8842.c +++ b/drivers/net/ethernet/micrel/ks8842.c @@ -459,8 +459,7 @@ static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev) sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4; ctl->adesc = dmaengine_prep_slave_sg(ctl->chan, - &ctl->sg, 1, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); + &ctl->sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!ctl->adesc) return NETDEV_TX_BUSY; @@ -571,8 +570,7 @@ static int __ks8842_start_new_rx_dma(struct net_device *netdev) sg_dma_len(sg) = DMA_BUFFER_SIZE; ctl->adesc = dmaengine_prep_slave_sg(ctl->chan, - sg, 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); + sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!ctl->adesc) goto out; diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 222c2baa3a4b..d0222f13d154 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1037,7 +1037,6 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset, struct dmaengine_unmap_data *unmap; dma_cookie_t cookie; void *buf = entry->buf; - unsigned long flags; entry->len = len; @@ -1073,10 +1072,9 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset, unmap->from_cnt = 1; - flags = DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP | - DMA_PREP_INTERRUPT; txd = device->device_prep_dma_memcpy(chan, unmap->addr[1], - unmap->addr[0], len, flags); + unmap->addr[0], len, + DMA_PREP_INTERRUPT); if (!txd) goto err_get_unmap; @@ -1266,7 +1264,6 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, void __iomem *offset; size_t len = entry->len; void *buf = entry->buf; - unsigned long flags; offset = qp->tx_mw + qp->tx_max_frame * qp->tx_index; hdr = offset + qp->tx_max_frame - sizeof(struct ntb_payload_header); @@ -1301,10 +1298,8 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, unmap->to_cnt = 1; - flags = DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP | - DMA_PREP_INTERRUPT; txd = device->device_prep_dma_memcpy(chan, dest, unmap->addr[0], len, - flags); + DMA_PREP_INTERRUPT); if (!txd) goto err_get_unmap; diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index b9f0192758d6..6d207afec8cb 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -150,7 +150,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) &dws->tx_sgl, 1, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP); + DMA_PREP_INTERRUPT); txdesc->callback = dw_spi_dma_done; txdesc->callback_param = dws; @@ -173,7 +173,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) &dws->rx_sgl, 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP); + DMA_PREP_INTERRUPT); rxdesc->callback = dw_spi_dma_done; rxdesc->callback_param = dws; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 3782cdb782a8..491072cb5ba0 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -171,12 +171,6 @@ struct dma_interleaved_template { * @DMA_CTRL_ACK - if clear, the descriptor cannot be reused until the client * acknowledges receipt, i.e. has has a chance to establish any dependency * chains - * @DMA_COMPL_SKIP_SRC_UNMAP - set to disable dma-unmapping the source buffer(s) - * @DMA_COMPL_SKIP_DEST_UNMAP - set to disable dma-unmapping the destination(s) - * @DMA_COMPL_SRC_UNMAP_SINGLE - set to do the source dma-unmapping as single - * (if not set, do the source dma-unmapping as page) - * @DMA_COMPL_DEST_UNMAP_SINGLE - set to do the destination dma-unmapping as single - * (if not set, do the destination dma-unmapping as page) * @DMA_PREP_PQ_DISABLE_P - prevent generation of P while generating Q * @DMA_PREP_PQ_DISABLE_Q - prevent generation of Q while generating P * @DMA_PREP_CONTINUE - indicate to a driver that it is reusing buffers as @@ -188,14 +182,10 @@ struct dma_interleaved_template { enum dma_ctrl_flags { DMA_PREP_INTERRUPT = (1 << 0), DMA_CTRL_ACK = (1 << 1), - DMA_COMPL_SKIP_SRC_UNMAP = (1 << 2), - DMA_COMPL_SKIP_DEST_UNMAP = (1 << 3), - DMA_COMPL_SRC_UNMAP_SINGLE = (1 << 4), - DMA_COMPL_DEST_UNMAP_SINGLE = (1 << 5), - DMA_PREP_PQ_DISABLE_P = (1 << 6), - DMA_PREP_PQ_DISABLE_Q = (1 << 7), - DMA_PREP_CONTINUE = (1 << 8), - DMA_PREP_FENCE = (1 << 9), + DMA_PREP_PQ_DISABLE_P = (1 << 2), + DMA_PREP_PQ_DISABLE_Q = (1 << 3), + DMA_PREP_CONTINUE = (1 << 4), + DMA_PREP_FENCE = (1 << 5), }; /** -- cgit v1.2.3-59-g8ed1b From 7b61017822cdff9c18ae70005cf52d84e8dafe5d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:29:57 -0800 Subject: Revert "dmatest: append verify result to results" This reverts commit d86b2f298e6de124984f5d5817ed1e6e759b3ada. The kernel log buffer is sufficient for collecting test results. The current logging OOMs the machine on long running tests, and usually only the first error is relevant. It is better to stop on error and parse the kernel output. If output volume becomes an issue we can always investigate using trace messages. Cc: Andy Shevchenko Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- Documentation/dmatest.txt | 6 +- drivers/dma/dmatest.c | 180 +++++++++++++--------------------------------- 2 files changed, 53 insertions(+), 133 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt index a2b5663eae26..8b7a5c879df9 100644 --- a/Documentation/dmatest.txt +++ b/Documentation/dmatest.txt @@ -76,7 +76,5 @@ The message format is unified across the different types of errors. A number in the parens represents additional information, e.g. error code, error counter, or status. -Comparison between buffers is stored to the dedicated structure. - -Note that the verify result is now accessible only via file 'results' in the -debugfs. +Note that the buffer comparison is done in the old way, i.e. data is not +collected and just printed out. diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 5791091c13ca..dcb38d86550e 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -98,20 +98,6 @@ enum dmatest_error_type { DMATEST_ET_DMA_ERROR, DMATEST_ET_DMA_IN_PROGRESS, DMATEST_ET_VERIFY, - DMATEST_ET_VERIFY_BUF, -}; - -struct dmatest_verify_buffer { - unsigned int index; - u8 expected; - u8 actual; -}; - -struct dmatest_verify_result { - unsigned int error_count; - struct dmatest_verify_buffer data[MAX_ERROR_COUNT]; - u8 pattern; - bool is_srcbuf; }; struct dmatest_thread_result { @@ -122,11 +108,10 @@ struct dmatest_thread_result { unsigned int len; enum dmatest_error_type type; union { - unsigned long data; - dma_cookie_t cookie; - enum dma_status status; - int error; - struct dmatest_verify_result *vr; + unsigned long data; + dma_cookie_t cookie; + enum dma_status status; + int error; }; }; @@ -262,9 +247,31 @@ static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len, } } -static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, - unsigned int start, unsigned int end, unsigned int counter, - u8 pattern, bool is_srcbuf) +static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index, + unsigned int counter, bool is_srcbuf) +{ + u8 diff = actual ^ pattern; + u8 expected = pattern | (~counter & PATTERN_COUNT_MASK); + const char *thread_name = current->comm; + + if (is_srcbuf) + pr_warn("%s: srcbuf[0x%x] overwritten! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if ((pattern & PATTERN_COPY) + && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) + pr_warn("%s: dstbuf[0x%x] not copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if (diff & PATTERN_SRC) + pr_warn("%s: dstbuf[0x%x] was copied! Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else + pr_warn("%s: dstbuf[0x%x] mismatch! Expected %02x, got %02x\n", + thread_name, index, expected, actual); +} + +static unsigned int dmatest_verify(u8 **bufs, unsigned int start, + unsigned int end, unsigned int counter, u8 pattern, + bool is_srcbuf) { unsigned int i; unsigned int error_count = 0; @@ -272,7 +279,6 @@ static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, u8 expected; u8 *buf; unsigned int counter_orig = counter; - struct dmatest_verify_buffer *vb; for (; (buf = *bufs); bufs++) { counter = counter_orig; @@ -280,12 +286,9 @@ static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, actual = buf[i]; expected = pattern | (~counter & PATTERN_COUNT_MASK); if (actual != expected) { - if (error_count < MAX_ERROR_COUNT && vr) { - vb = &vr->data[error_count]; - vb->index = i; - vb->expected = expected; - vb->actual = actual; - } + if (error_count < MAX_ERROR_COUNT) + dmatest_mismatch(actual, pattern, i, + counter, is_srcbuf); error_count++; } counter++; @@ -293,7 +296,7 @@ static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, } if (error_count > MAX_ERROR_COUNT) - pr_warning("%s: %u errors suppressed\n", + pr_warn("%s: %u errors suppressed\n", current->comm, error_count - MAX_ERROR_COUNT); return error_count; @@ -334,30 +337,6 @@ static unsigned int min_odd(unsigned int x, unsigned int y) return val % 2 ? val : val - 1; } -static char *verify_result_get_one(struct dmatest_verify_result *vr, - unsigned int i) -{ - struct dmatest_verify_buffer *vb = &vr->data[i]; - u8 diff = vb->actual ^ vr->pattern; - static char buf[512]; - char *msg; - - if (vr->is_srcbuf) - msg = "srcbuf overwritten!"; - else if ((vr->pattern & PATTERN_COPY) - && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) - msg = "dstbuf not copied!"; - else if (diff & PATTERN_SRC) - msg = "dstbuf was copied!"; - else - msg = "dstbuf mismatch!"; - - snprintf(buf, sizeof(buf) - 1, "%s [0x%x] Expected %02x, got %02x", msg, - vb->index, vb->expected, vb->actual); - - return buf; -} - static char *thread_result_get(const char *name, struct dmatest_thread_result *tr) { @@ -373,7 +352,6 @@ static char *thread_result_get(const char *name, [DMATEST_ET_DMA_IN_PROGRESS] = "got completion callback (DMA_IN_PROGRESS)", [DMATEST_ET_VERIFY] = "errors", - [DMATEST_ET_VERIFY_BUF] = "verify errors", }; static char buf[512]; @@ -415,51 +393,6 @@ static int thread_result_add(struct dmatest_info *info, return 0; } -static unsigned int verify_result_add(struct dmatest_info *info, - struct dmatest_result *r, unsigned int n, - unsigned int src_off, unsigned int dst_off, unsigned int len, - u8 **bufs, int whence, unsigned int counter, u8 pattern, - bool is_srcbuf) -{ - struct dmatest_verify_result *vr; - unsigned int error_count; - unsigned int buf_off = is_srcbuf ? src_off : dst_off; - unsigned int start, end; - - if (whence < 0) { - start = 0; - end = buf_off; - } else if (whence > 0) { - start = buf_off + len; - end = info->params.buf_size; - } else { - start = buf_off; - end = buf_off + len; - } - - vr = kmalloc(sizeof(*vr), GFP_KERNEL); - if (!vr) { - pr_warn("dmatest: No memory to store verify result\n"); - return dmatest_verify(NULL, bufs, start, end, counter, pattern, - is_srcbuf); - } - - vr->pattern = pattern; - vr->is_srcbuf = is_srcbuf; - - error_count = dmatest_verify(vr, bufs, start, end, counter, pattern, - is_srcbuf); - if (error_count) { - vr->error_count = error_count; - thread_result_add(info, r, DMATEST_ET_VERIFY_BUF, n, src_off, - dst_off, len, (unsigned long)vr); - return error_count; - } - - kfree(vr); - return 0; -} - static void result_free(struct dmatest_info *info, const char *name) { struct dmatest_result *r, *_r; @@ -472,8 +405,6 @@ static void result_free(struct dmatest_info *info, const char *name) continue; list_for_each_entry_safe(tr, _tr, &r->results, node) { - if (tr->type == DMATEST_ET_VERIFY_BUF) - kfree(tr->vr); list_del(&tr->node); kfree(tr); } @@ -755,26 +686,25 @@ static int dmatest_func(void *data) error_count = 0; pr_debug("%s: verifying source buffer...\n", thread_name); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->srcs, -1, + error_count += dmatest_verify(thread->srcs, 0, src_off, 0, PATTERN_SRC, true); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->srcs, 0, - src_off, PATTERN_SRC | PATTERN_COPY, true); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->srcs, 1, - src_off + len, PATTERN_SRC, true); - - pr_debug("%s: verifying dest buffer...\n", thread_name); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->dsts, -1, + error_count += dmatest_verify(thread->srcs, src_off, + src_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, true); + error_count += dmatest_verify(thread->srcs, src_off + len, + params->buf_size, src_off + len, + PATTERN_SRC, true); + + pr_debug("%s: verifying dest buffer...\n", + thread->task->comm); + error_count += dmatest_verify(thread->dsts, 0, dst_off, 0, PATTERN_DST, false); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->dsts, 0, - src_off, PATTERN_SRC | PATTERN_COPY, false); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->dsts, 1, - dst_off + len, PATTERN_DST, false); + error_count += dmatest_verify(thread->dsts, dst_off, + dst_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, false); + error_count += dmatest_verify(thread->dsts, dst_off + len, + params->buf_size, dst_off + len, + PATTERN_DST, false); if (error_count) { thread_result_add(info, result, DMATEST_ET_VERIFY, @@ -1099,20 +1029,12 @@ static int dtf_results_show(struct seq_file *sf, void *data) struct dmatest_info *info = sf->private; struct dmatest_result *result; struct dmatest_thread_result *tr; - unsigned int i; mutex_lock(&info->results_lock); list_for_each_entry(result, &info->results, node) { - list_for_each_entry(tr, &result->results, node) { + list_for_each_entry(tr, &result->results, node) seq_printf(sf, "%s\n", thread_result_get(result->name, tr)); - if (tr->type == DMATEST_ET_VERIFY_BUF) { - for (i = 0; i < tr->vr->error_count; i++) { - seq_printf(sf, "\t%s\n", - verify_result_get_one(tr->vr, i)); - } - } - } } mutex_unlock(&info->results_lock); -- cgit v1.2.3-59-g8ed1b From 872f05c6e9a37e9358fd58eb54deee7337863496 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:29:58 -0800 Subject: dmatest: replace stored results mechanism, with uniform messages For long running tests the tracking results in a memory leak for the "ok" results, and for the failures the kernel log should be sufficient. Provide a uniform format for error messages so they can be easily parsed and remove the debugfs file. Cc: Andy Shevchenko Signed-off-by: Dan Williams --- Documentation/dmatest.txt | 27 +++--- drivers/dma/dmatest.c | 240 +++++++--------------------------------------- 2 files changed, 46 insertions(+), 221 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt index 8b7a5c879df9..45b8c95f1a21 100644 --- a/Documentation/dmatest.txt +++ b/Documentation/dmatest.txt @@ -16,9 +16,8 @@ be built as module or inside kernel. Let's consider those cases. Part 2 - When dmatest is built as a module... After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest -folder with nodes will be created. There are two important files located. First -is the 'run' node that controls run and stop phases of the test, and the second -one, 'results', is used to get the test case results. +folder with a file named 'run' nodes will be created. 'run' controls run and +stop phases of the test. Note that in this case test will not run on load automatically. @@ -32,8 +31,9 @@ Hint: available channel list could be extracted by running the following command: % ls -1 /sys/class/dma/ -After a while you will start to get messages about current status or error like -in the original code. +Once started a message like "dmatest: Started 1 threads using dma0chan0" is +emitted. After that only test failure messages are reported until the test +stops. Note that running a new test will not stop any in progress test. @@ -62,19 +62,18 @@ case. You always could check them at run-time by running Part 4 - Gathering the test results -The module provides a storage for the test results in the memory. The gathered -data could be used after test is done. +Test results are printed to the kernel log buffer with the format: -The special file 'results' in the debugfs represents gathered data of the in -progress test. The messages collected are printed to the kernel log as well. +"dmatest: result : : '' with src_off= dst_off= len= ()" Example of output: - % cat /sys/kernel/debug/dmatest/results - dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0) + % dmesg | tail -n 1 + dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0) The message format is unified across the different types of errors. A number in the parens represents additional information, e.g. error code, error counter, -or status. +or status. A test thread also emits a summary line at completion listing the +number of tests executed, number that failed, and a result code. -Note that the buffer comparison is done in the old way, i.e. data is not -collected and just printed out. +The details of a data miscompare error are also emitted, but do not follow the +above format. diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index dcb38d86550e..58b195f9d03c 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -8,6 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -88,39 +90,6 @@ MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " #define PATTERN_OVERWRITE 0x20 #define PATTERN_COUNT_MASK 0x1f -enum dmatest_error_type { - DMATEST_ET_OK, - DMATEST_ET_MAP_SRC, - DMATEST_ET_MAP_DST, - DMATEST_ET_PREP, - DMATEST_ET_SUBMIT, - DMATEST_ET_TIMEOUT, - DMATEST_ET_DMA_ERROR, - DMATEST_ET_DMA_IN_PROGRESS, - DMATEST_ET_VERIFY, -}; - -struct dmatest_thread_result { - struct list_head node; - unsigned int n; - unsigned int src_off; - unsigned int dst_off; - unsigned int len; - enum dmatest_error_type type; - union { - unsigned long data; - dma_cookie_t cookie; - enum dma_status status; - int error; - }; -}; - -struct dmatest_result { - struct list_head node; - char *name; - struct list_head results; -}; - struct dmatest_info; struct dmatest_thread { @@ -180,10 +149,6 @@ struct dmatest_info { /* debugfs related stuff */ struct dentry *root; - - /* Test results */ - struct list_head results; - struct mutex results_lock; }; static struct dmatest_info test_info; @@ -337,100 +302,19 @@ static unsigned int min_odd(unsigned int x, unsigned int y) return val % 2 ? val : val - 1; } -static char *thread_result_get(const char *name, - struct dmatest_thread_result *tr) +static void result(const char *err, unsigned int n, unsigned int src_off, + unsigned int dst_off, unsigned int len, unsigned long data) { - static const char * const messages[] = { - [DMATEST_ET_OK] = "No errors", - [DMATEST_ET_MAP_SRC] = "src mapping error", - [DMATEST_ET_MAP_DST] = "dst mapping error", - [DMATEST_ET_PREP] = "prep error", - [DMATEST_ET_SUBMIT] = "submit error", - [DMATEST_ET_TIMEOUT] = "test timed out", - [DMATEST_ET_DMA_ERROR] = - "got completion callback (DMA_ERROR)", - [DMATEST_ET_DMA_IN_PROGRESS] = - "got completion callback (DMA_IN_PROGRESS)", - [DMATEST_ET_VERIFY] = "errors", - }; - static char buf[512]; - - snprintf(buf, sizeof(buf) - 1, - "%s: #%u: %s with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)", - name, tr->n, messages[tr->type], tr->src_off, tr->dst_off, - tr->len, tr->data); - - return buf; + pr_info("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)", + current->comm, n, err, src_off, dst_off, len, data); } -static int thread_result_add(struct dmatest_info *info, - struct dmatest_result *r, enum dmatest_error_type type, - unsigned int n, unsigned int src_off, unsigned int dst_off, - unsigned int len, unsigned long data) +static void dbg_result(const char *err, unsigned int n, unsigned int src_off, + unsigned int dst_off, unsigned int len, + unsigned long data) { - struct dmatest_thread_result *tr; - - tr = kzalloc(sizeof(*tr), GFP_KERNEL); - if (!tr) - return -ENOMEM; - - tr->type = type; - tr->n = n; - tr->src_off = src_off; - tr->dst_off = dst_off; - tr->len = len; - tr->data = data; - - mutex_lock(&info->results_lock); - list_add_tail(&tr->node, &r->results); - mutex_unlock(&info->results_lock); - - if (tr->type == DMATEST_ET_OK) - pr_debug("%s\n", thread_result_get(r->name, tr)); - else - pr_warn("%s\n", thread_result_get(r->name, tr)); - - return 0; -} - -static void result_free(struct dmatest_info *info, const char *name) -{ - struct dmatest_result *r, *_r; - - mutex_lock(&info->results_lock); - list_for_each_entry_safe(r, _r, &info->results, node) { - struct dmatest_thread_result *tr, *_tr; - - if (name && strcmp(r->name, name)) - continue; - - list_for_each_entry_safe(tr, _tr, &r->results, node) { - list_del(&tr->node); - kfree(tr); - } - - kfree(r->name); - list_del(&r->node); - kfree(r); - } - - mutex_unlock(&info->results_lock); -} - -static struct dmatest_result *result_init(struct dmatest_info *info, - const char *name) -{ - struct dmatest_result *r; - - r = kzalloc(sizeof(*r), GFP_KERNEL); - if (r) { - r->name = kstrdup(name, GFP_KERNEL); - INIT_LIST_HEAD(&r->results); - mutex_lock(&info->results_lock); - list_add_tail(&r->node, &info->results); - mutex_unlock(&info->results_lock); - } - return r; + pr_debug("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)", + current->comm, n, err, src_off, dst_off, len, data); } /* @@ -456,7 +340,6 @@ static int dmatest_func(void *data) struct dmatest_params *params; struct dma_chan *chan; struct dma_device *dev; - const char *thread_name; unsigned int src_off, dst_off, len; unsigned int error_count; unsigned int failed_tests = 0; @@ -469,9 +352,7 @@ static int dmatest_func(void *data) int src_cnt; int dst_cnt; int i; - struct dmatest_result *result; - thread_name = current->comm; set_freezable(); ret = -ENOMEM; @@ -501,10 +382,6 @@ static int dmatest_func(void *data) } else goto err_thread_type; - result = result_init(info, thread_name); - if (!result) - goto err_srcs; - thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL); if (!thread->srcs) goto err_srcs; @@ -576,10 +453,8 @@ static int dmatest_func(void *data) ret = dma_mapping_error(dev->dev, dma_srcs[i]); if (ret) { unmap_src(dev->dev, dma_srcs, len, i); - thread_result_add(info, result, - DMATEST_ET_MAP_SRC, - total_tests, src_off, dst_off, - len, ret); + result("src mapping error", total_tests, + src_off, dst_off, len, ret); failed_tests++; continue; } @@ -594,10 +469,8 @@ static int dmatest_func(void *data) unmap_src(dev->dev, dma_srcs, len, src_cnt); unmap_dst(dev->dev, dma_dsts, params->buf_size, i); - thread_result_add(info, result, - DMATEST_ET_MAP_DST, - total_tests, src_off, dst_off, - len, ret); + result("dst mapping error", total_tests, + src_off, dst_off, len, ret); failed_tests++; continue; } @@ -627,9 +500,8 @@ static int dmatest_func(void *data) unmap_src(dev->dev, dma_srcs, len, src_cnt); unmap_dst(dev->dev, dma_dsts, params->buf_size, dst_cnt); - thread_result_add(info, result, DMATEST_ET_PREP, - total_tests, src_off, dst_off, - len, 0); + result("prep error", total_tests, src_off, + dst_off, len, ret); msleep(100); failed_tests++; continue; @@ -641,9 +513,8 @@ static int dmatest_func(void *data) cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { - thread_result_add(info, result, DMATEST_ET_SUBMIT, - total_tests, src_off, dst_off, - len, cookie); + result("submit error", total_tests, src_off, + dst_off, len, ret); msleep(100); failed_tests++; continue; @@ -664,17 +535,15 @@ static int dmatest_func(void *data) * free it this time?" dancing. For now, just * leave it dangling. */ - thread_result_add(info, result, DMATEST_ET_TIMEOUT, - total_tests, src_off, dst_off, - len, 0); + result("test timed out", total_tests, src_off, dst_off, + len, 0); failed_tests++; continue; } else if (status != DMA_SUCCESS) { - enum dmatest_error_type type = (status == DMA_ERROR) ? - DMATEST_ET_DMA_ERROR : DMATEST_ET_DMA_IN_PROGRESS; - thread_result_add(info, result, type, - total_tests, src_off, dst_off, - len, status); + result(status == DMA_ERROR ? + "completion error status" : + "completion busy status", total_tests, src_off, + dst_off, len, ret); failed_tests++; continue; } @@ -685,7 +554,7 @@ static int dmatest_func(void *data) error_count = 0; - pr_debug("%s: verifying source buffer...\n", thread_name); + pr_debug("%s: verifying source buffer...\n", current->comm); error_count += dmatest_verify(thread->srcs, 0, src_off, 0, PATTERN_SRC, true); error_count += dmatest_verify(thread->srcs, src_off, @@ -695,8 +564,7 @@ static int dmatest_func(void *data) params->buf_size, src_off + len, PATTERN_SRC, true); - pr_debug("%s: verifying dest buffer...\n", - thread->task->comm); + pr_debug("%s: verifying dest buffer...\n", current->comm); error_count += dmatest_verify(thread->dsts, 0, dst_off, 0, PATTERN_DST, false); error_count += dmatest_verify(thread->dsts, dst_off, @@ -707,14 +575,12 @@ static int dmatest_func(void *data) PATTERN_DST, false); if (error_count) { - thread_result_add(info, result, DMATEST_ET_VERIFY, - total_tests, src_off, dst_off, - len, error_count); + result("data error", total_tests, src_off, dst_off, + len, error_count); failed_tests++; } else { - thread_result_add(info, result, DMATEST_ET_OK, - total_tests, src_off, dst_off, - len, 0); + dbg_result("test passed", total_tests, src_off, dst_off, + len, 0); } } @@ -731,8 +597,8 @@ err_srcbuf: err_srcs: kfree(pq_coefs); err_thread_type: - pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", - thread_name, total_tests, failed_tests, ret); + pr_info("%s: terminating after %u tests, %u failures (status %d)\n", + current->comm, total_tests, failed_tests, ret); /* terminate all transfers on specified channels */ if (ret) @@ -937,9 +803,6 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run) if (run == false) return 0; - /* Clear results from previous run */ - result_free(info, NULL); - /* Copy test parameters */ params->buf_size = test_buf_size; strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); @@ -1024,35 +887,6 @@ static const struct file_operations dtf_run_fops = { .llseek = default_llseek, }; -static int dtf_results_show(struct seq_file *sf, void *data) -{ - struct dmatest_info *info = sf->private; - struct dmatest_result *result; - struct dmatest_thread_result *tr; - - mutex_lock(&info->results_lock); - list_for_each_entry(result, &info->results, node) { - list_for_each_entry(tr, &result->results, node) - seq_printf(sf, "%s\n", - thread_result_get(result->name, tr)); - } - - mutex_unlock(&info->results_lock); - return 0; -} - -static int dtf_results_open(struct inode *inode, struct file *file) -{ - return single_open(file, dtf_results_show, inode->i_private); -} - -static const struct file_operations dtf_results_fops = { - .open = dtf_results_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int dmatest_register_dbgfs(struct dmatest_info *info) { struct dentry *d; @@ -1069,10 +903,6 @@ static int dmatest_register_dbgfs(struct dmatest_info *info) debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info, &dtf_run_fops); - /* Results of test in progress */ - debugfs_create_file("results", S_IRUGO, info->root, info, - &dtf_results_fops); - return 0; err_root: @@ -1090,9 +920,6 @@ static int __init dmatest_init(void) mutex_init(&info->lock); INIT_LIST_HEAD(&info->channels); - mutex_init(&info->results_lock); - INIT_LIST_HEAD(&info->results); - ret = dmatest_register_dbgfs(info); if (ret) return ret; @@ -1112,7 +939,6 @@ static void __exit dmatest_exit(void) debugfs_remove_recursive(info->root); stop_threaded_test(info); - result_free(info, NULL); } module_exit(dmatest_exit); -- cgit v1.2.3-59-g8ed1b From 0adff800662f52d0ffc3e420db231769cb3fff13 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:00 -0800 Subject: dmatest: cleanup redundant "dmatest: " prefixes ...now that we have a common pr_fmt. Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 58b195f9d03c..15199edcc366 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -623,8 +623,8 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) list_for_each_entry_safe(thread, _thread, &dtc->threads, node) { ret = kthread_stop(thread->task); - pr_debug("dmatest: thread %s exited with status %d\n", - thread->task->comm, ret); + pr_debug("thread %s exited with status %d\n", + thread->task->comm, ret); list_del(&thread->node); kfree(thread); } @@ -656,9 +656,8 @@ static int dmatest_add_threads(struct dmatest_info *info, for (i = 0; i < params->threads_per_chan; i++) { thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); if (!thread) { - pr_warning("dmatest: No memory for %s-%s%u\n", - dma_chan_name(chan), op, i); - + pr_warn("No memory for %s-%s%u\n", + dma_chan_name(chan), op, i); break; } thread->info = info; @@ -668,8 +667,8 @@ static int dmatest_add_threads(struct dmatest_info *info, thread->task = kthread_run(dmatest_func, thread, "%s-%s%u", dma_chan_name(chan), op, i); if (IS_ERR(thread->task)) { - pr_warning("dmatest: Failed to run thread %s-%s%u\n", - dma_chan_name(chan), op, i); + pr_warn("Failed to run thread %s-%s%u\n", + dma_chan_name(chan), op, i); kfree(thread); break; } @@ -692,7 +691,7 @@ static int dmatest_add_channel(struct dmatest_info *info, dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL); if (!dtc) { - pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan)); + pr_warn("No memory for %s\n", dma_chan_name(chan)); return -ENOMEM; } @@ -712,7 +711,7 @@ static int dmatest_add_channel(struct dmatest_info *info, thread_count += cnt > 0 ? cnt : 0; } - pr_info("dmatest: Started %u threads using %s\n", + pr_info("Started %u threads using %s\n", thread_count, dma_chan_name(chan)); list_add_tail(&dtc->node, &info->channels); @@ -779,7 +778,7 @@ static void __stop_threaded_test(struct dmatest_info *info) list_del(&dtc->node); chan = dtc->chan; dmatest_cleanup_channel(dtc); - pr_debug("dmatest: dropped channel %s\n", dma_chan_name(chan)); + pr_debug("dropped channel %s\n", dma_chan_name(chan)); dma_release_channel(chan); } @@ -906,7 +905,7 @@ static int dmatest_register_dbgfs(struct dmatest_info *info) return 0; err_root: - pr_err("dmatest: Failed to initialize debugfs\n"); + pr_err("Failed to initialize debugfs\n"); return -ENOMEM; } -- cgit v1.2.3-59-g8ed1b From a310d037b8d06755c62bb4878c00d19490af5550 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:01 -0800 Subject: dmatest: restore ability to start test at module load and init 1/ move 'run' control to a module parameter so we can do: modprobe dmatest run=1. With this moved the rest of the debugfs boilerplate can go. 2/ Fix parameter initialization. Previously the test was being started without taking the parameters into account in the built-in case. Also killed off the '__' version of some routines. The new rule is just hold the lock when calling a *threaded_test() routine. Acked-by: Linus Walleij Cc: Andy Shevchenko Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- Documentation/dmatest.txt | 18 ++-- drivers/dma/dmatest.c | 265 +++++++++++++++++++--------------------------- 2 files changed, 116 insertions(+), 167 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt index 45b8c95f1a21..e6e16a7f3706 100644 --- a/Documentation/dmatest.txt +++ b/Documentation/dmatest.txt @@ -15,17 +15,19 @@ be built as module or inside kernel. Let's consider those cases. Part 2 - When dmatest is built as a module... -After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest -folder with a file named 'run' nodes will be created. 'run' controls run and -stop phases of the test. - -Note that in this case test will not run on load automatically. - Example of usage: + % modprobe dmatest channel=dma0chan0 timeout=2000 iterations=1 run=1 + +...or: + % modprobe dmatest % echo dma0chan0 > /sys/module/dmatest/parameters/channel % echo 2000 > /sys/module/dmatest/parameters/timeout % echo 1 > /sys/module/dmatest/parameters/iterations - % echo 1 > /sys/kernel/debug/dmatest/run + % echo 1 > /sys/module/dmatest/parameters/run + +...or on the kernel command line: + + dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1 Hint: available channel list could be extracted by running the following command: @@ -42,7 +44,7 @@ The following command should return actual state of the test. To wait for test done the user may perform a busy loop that checks the state. - % while [ $(cat /sys/kernel/debug/dmatest/run) = "Y" ] + % while [ $(cat /sys/module/dmatest/parameters/run) = "Y" ] > do > echo -n "." > sleep 1 diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 15199edcc366..c5048671daf7 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -21,10 +21,6 @@ #include #include #include -#include -#include -#include -#include static unsigned int test_buf_size = 16384; module_param(test_buf_size, uint, S_IRUGO | S_IWUSR); @@ -70,45 +66,6 @@ module_param(timeout, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " "Pass -1 for infinite timeout"); -/* Maximum amount of mismatched bytes in buffer to print */ -#define MAX_ERROR_COUNT 32 - -/* - * Initialization patterns. All bytes in the source buffer has bit 7 - * set, all bytes in the destination buffer has bit 7 cleared. - * - * Bit 6 is set for all bytes which are to be copied by the DMA - * engine. Bit 5 is set for all bytes which are to be overwritten by - * the DMA engine. - * - * The remaining bits are the inverse of a counter which increments by - * one for each byte address. - */ -#define PATTERN_SRC 0x80 -#define PATTERN_DST 0x00 -#define PATTERN_COPY 0x40 -#define PATTERN_OVERWRITE 0x20 -#define PATTERN_COUNT_MASK 0x1f - -struct dmatest_info; - -struct dmatest_thread { - struct list_head node; - struct dmatest_info *info; - struct task_struct *task; - struct dma_chan *chan; - u8 **srcs; - u8 **dsts; - enum dma_transaction_type type; - bool done; -}; - -struct dmatest_chan { - struct list_head node; - struct dma_chan *chan; - struct list_head threads; -}; - /** * struct dmatest_params - test parameters. * @buf_size: size of the memcpy test buffer @@ -138,7 +95,7 @@ struct dmatest_params { * @params: test parameters * @lock: access protection to the fields of this structure */ -struct dmatest_info { +static struct dmatest_info { /* Test parameters */ struct dmatest_params params; @@ -146,12 +103,58 @@ struct dmatest_info { struct list_head channels; unsigned int nr_channels; struct mutex lock; + bool did_init; +} test_info = { + .channels = LIST_HEAD_INIT(test_info.channels), + .lock = __MUTEX_INITIALIZER(test_info.lock), +}; - /* debugfs related stuff */ - struct dentry *root; +static int dmatest_run_set(const char *val, const struct kernel_param *kp); +static int dmatest_run_get(char *val, const struct kernel_param *kp); +static struct kernel_param_ops run_ops = { + .set = dmatest_run_set, + .get = dmatest_run_get, }; +static bool dmatest_run; +module_param_cb(run, &run_ops, &dmatest_run, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(run, "Run the test (default: false)"); -static struct dmatest_info test_info; +/* Maximum amount of mismatched bytes in buffer to print */ +#define MAX_ERROR_COUNT 32 + +/* + * Initialization patterns. All bytes in the source buffer has bit 7 + * set, all bytes in the destination buffer has bit 7 cleared. + * + * Bit 6 is set for all bytes which are to be copied by the DMA + * engine. Bit 5 is set for all bytes which are to be overwritten by + * the DMA engine. + * + * The remaining bits are the inverse of a counter which increments by + * one for each byte address. + */ +#define PATTERN_SRC 0x80 +#define PATTERN_DST 0x00 +#define PATTERN_COPY 0x40 +#define PATTERN_OVERWRITE 0x20 +#define PATTERN_COUNT_MASK 0x1f + +struct dmatest_thread { + struct list_head node; + struct dmatest_info *info; + struct task_struct *task; + struct dma_chan *chan; + u8 **srcs; + u8 **dsts; + enum dma_transaction_type type; + bool done; +}; + +struct dmatest_chan { + struct list_head node; + struct dma_chan *chan; + struct list_head threads; +}; static bool dmatest_match_channel(struct dmatest_params *params, struct dma_chan *chan) @@ -731,13 +734,24 @@ static bool filter(struct dma_chan *chan, void *param) return true; } -static int __run_threaded_test(struct dmatest_info *info) +static int run_threaded_test(struct dmatest_info *info) { dma_cap_mask_t mask; struct dma_chan *chan; struct dmatest_params *params = &info->params; int err = 0; + /* Copy test parameters */ + params->buf_size = test_buf_size; + strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); + strlcpy(params->device, strim(test_device), sizeof(params->device)); + params->threads_per_chan = threads_per_chan; + params->max_channels = max_channels; + params->iterations = iterations; + params->xor_sources = xor_sources; + params->pq_sources = pq_sources; + params->timeout = timeout; + dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); for (;;) { @@ -757,19 +771,8 @@ static int __run_threaded_test(struct dmatest_info *info) return err; } -#ifndef MODULE -static int run_threaded_test(struct dmatest_info *info) -{ - int ret; - - mutex_lock(&info->lock); - ret = __run_threaded_test(info); - mutex_unlock(&info->lock); - return ret; -} -#endif -static void __stop_threaded_test(struct dmatest_info *info) +static void stop_threaded_test(struct dmatest_info *info) { struct dmatest_chan *dtc, *_dtc; struct dma_chan *chan; @@ -785,39 +788,22 @@ static void __stop_threaded_test(struct dmatest_info *info) info->nr_channels = 0; } -static void stop_threaded_test(struct dmatest_info *info) -{ - mutex_lock(&info->lock); - __stop_threaded_test(info); - mutex_unlock(&info->lock); -} - -static int __restart_threaded_test(struct dmatest_info *info, bool run) +static int restart_threaded_test(struct dmatest_info *info, bool run) { - struct dmatest_params *params = &info->params; - - /* Stop any running test first */ - __stop_threaded_test(info); - - if (run == false) + /* we might be called early to set run=, defer running until all + * parameters have been evaluated + */ + if (!info->did_init) return 0; - /* Copy test parameters */ - params->buf_size = test_buf_size; - strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); - strlcpy(params->device, strim(test_device), sizeof(params->device)); - params->threads_per_chan = threads_per_chan; - params->max_channels = max_channels; - params->iterations = iterations; - params->xor_sources = xor_sources; - params->pq_sources = pq_sources; - params->timeout = timeout; + /* Stop any running test first */ + stop_threaded_test(info); /* Run test with new parameters */ - return __run_threaded_test(info); + return run_threaded_test(info); } -static bool __is_threaded_test_run(struct dmatest_info *info) +static bool is_threaded_test_run(struct dmatest_info *info) { struct dmatest_chan *dtc; @@ -833,101 +819,61 @@ static bool __is_threaded_test_run(struct dmatest_info *info) return false; } -static ssize_t dtf_read_run(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int dmatest_run_get(char *val, const struct kernel_param *kp) { - struct dmatest_info *info = file->private_data; - char buf[3]; + struct dmatest_info *info = &test_info; mutex_lock(&info->lock); - - if (__is_threaded_test_run(info)) { - buf[0] = 'Y'; + if (is_threaded_test_run(info)) { + dmatest_run = true; } else { - __stop_threaded_test(info); - buf[0] = 'N'; + stop_threaded_test(info); + dmatest_run = false; } - mutex_unlock(&info->lock); - buf[1] = '\n'; - buf[2] = 0x00; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); + + return param_get_bool(val, kp); } -static ssize_t dtf_write_run(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) +static int dmatest_run_set(const char *val, const struct kernel_param *kp) { - struct dmatest_info *info = file->private_data; - char buf[16]; - bool bv; - int ret = 0; - - if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) - return -EFAULT; - - if (strtobool(buf, &bv) == 0) { - mutex_lock(&info->lock); - - if (__is_threaded_test_run(info)) - ret = -EBUSY; - else - ret = __restart_threaded_test(info, bv); + struct dmatest_info *info = &test_info; + int ret; + mutex_lock(&info->lock); + ret = param_set_bool(val, kp); + if (ret) { mutex_unlock(&info->lock); + return ret; } - return ret ? ret : count; -} - -static const struct file_operations dtf_run_fops = { - .read = dtf_read_run, - .write = dtf_write_run, - .open = simple_open, - .llseek = default_llseek, -}; - -static int dmatest_register_dbgfs(struct dmatest_info *info) -{ - struct dentry *d; - - d = debugfs_create_dir("dmatest", NULL); - if (IS_ERR(d)) - return PTR_ERR(d); - if (!d) - goto err_root; + if (is_threaded_test_run(info)) + ret = -EBUSY; + else if (dmatest_run) + ret = restart_threaded_test(info, dmatest_run); - info->root = d; - - /* Run or stop threaded test */ - debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info, - &dtf_run_fops); - - return 0; + mutex_unlock(&info->lock); -err_root: - pr_err("Failed to initialize debugfs\n"); - return -ENOMEM; + return ret; } static int __init dmatest_init(void) { struct dmatest_info *info = &test_info; - int ret; - - memset(info, 0, sizeof(*info)); + int ret = 0; - mutex_init(&info->lock); - INIT_LIST_HEAD(&info->channels); + if (dmatest_run) { + mutex_lock(&info->lock); + ret = run_threaded_test(info); + mutex_unlock(&info->lock); + } - ret = dmatest_register_dbgfs(info); - if (ret) - return ret; + /* module parameters are stable, inittime tests are started, + * let userspace take over 'run' control + */ + info->did_init = true; -#ifdef MODULE - return 0; -#else - return run_threaded_test(info); -#endif + return ret; } /* when compiled-in wait for drivers to load first */ late_initcall(dmatest_init); @@ -936,8 +882,9 @@ static void __exit dmatest_exit(void) { struct dmatest_info *info = &test_info; - debugfs_remove_recursive(info->root); + mutex_lock(&info->lock); stop_threaded_test(info); + mutex_unlock(&info->lock); } module_exit(dmatest_exit); -- cgit v1.2.3-59-g8ed1b From a9e554957de406d6adc581731f571b8a1503f6b0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:02 -0800 Subject: dmatest: support xor-only, or pq-only channels in tests Currently we only test raid channels that happen to also have 'copy' capability. Search for capable channels that do not have DMA_MEMCPY. Note the return value from run_threaded_test never really made sense because it could return errors after successfully starting tests. We already have the test results per channel so missing channels can be detected at that time. Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 58 ++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index c5048671daf7..ea829659149a 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -734,31 +734,20 @@ static bool filter(struct dma_chan *chan, void *param) return true; } -static int run_threaded_test(struct dmatest_info *info) +static void request_channels(struct dmatest_info *info, + enum dma_transaction_type type) { dma_cap_mask_t mask; - struct dma_chan *chan; - struct dmatest_params *params = &info->params; - int err = 0; - - /* Copy test parameters */ - params->buf_size = test_buf_size; - strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); - strlcpy(params->device, strim(test_device), sizeof(params->device)); - params->threads_per_chan = threads_per_chan; - params->max_channels = max_channels; - params->iterations = iterations; - params->xor_sources = xor_sources; - params->pq_sources = pq_sources; - params->timeout = timeout; dma_cap_zero(mask); - dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(type, mask); for (;;) { + struct dmatest_params *params = &info->params; + struct dma_chan *chan; + chan = dma_request_channel(mask, filter, params); if (chan) { - err = dmatest_add_channel(info, chan); - if (err) { + if (dmatest_add_channel(info, chan)) { dma_release_channel(chan); break; /* add_channel failed, punt */ } @@ -768,9 +757,27 @@ static int run_threaded_test(struct dmatest_info *info) info->nr_channels >= params->max_channels) break; /* we have all we need */ } - return err; } +static void run_threaded_test(struct dmatest_info *info) +{ + struct dmatest_params *params = &info->params; + + /* Copy test parameters */ + params->buf_size = test_buf_size; + strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); + strlcpy(params->device, strim(test_device), sizeof(params->device)); + params->threads_per_chan = threads_per_chan; + params->max_channels = max_channels; + params->iterations = iterations; + params->xor_sources = xor_sources; + params->pq_sources = pq_sources; + params->timeout = timeout; + + request_channels(info, DMA_MEMCPY); + request_channels(info, DMA_XOR); + request_channels(info, DMA_PQ); +} static void stop_threaded_test(struct dmatest_info *info) { @@ -788,19 +795,19 @@ static void stop_threaded_test(struct dmatest_info *info) info->nr_channels = 0; } -static int restart_threaded_test(struct dmatest_info *info, bool run) +static void restart_threaded_test(struct dmatest_info *info, bool run) { /* we might be called early to set run=, defer running until all * parameters have been evaluated */ if (!info->did_init) - return 0; + return; /* Stop any running test first */ stop_threaded_test(info); /* Run test with new parameters */ - return run_threaded_test(info); + run_threaded_test(info); } static bool is_threaded_test_run(struct dmatest_info *info) @@ -850,7 +857,7 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp) if (is_threaded_test_run(info)) ret = -EBUSY; else if (dmatest_run) - ret = restart_threaded_test(info, dmatest_run); + restart_threaded_test(info, dmatest_run); mutex_unlock(&info->lock); @@ -860,11 +867,10 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp) static int __init dmatest_init(void) { struct dmatest_info *info = &test_info; - int ret = 0; if (dmatest_run) { mutex_lock(&info->lock); - ret = run_threaded_test(info); + run_threaded_test(info); mutex_unlock(&info->lock); } @@ -873,7 +879,7 @@ static int __init dmatest_init(void) */ info->did_init = true; - return ret; + return 0; } /* when compiled-in wait for drivers to load first */ late_initcall(dmatest_init); -- cgit v1.2.3-59-g8ed1b From be9fa5a43641103bf13cd1bb8101a1453da03616 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:03 -0800 Subject: dmatest: use pseudo random numbers There is no need for dmatest to drain the entropy pool. It would be nice to one day have repeatable runs, but would need a larger rework to synchronize and order calls to the rng across test threads. Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/dma/dmatest.c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index ea829659149a..01ac7112b5fd 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -176,7 +176,7 @@ static unsigned long dmatest_random(void) { unsigned long buf; - get_random_bytes(&buf, sizeof(buf)); + prandom_bytes(&buf, sizeof(buf)); return buf; } -- cgit v1.2.3-59-g8ed1b From e3b9c347316fe243bea6abd08681050c43ca22ee Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:05 -0800 Subject: dmatest: add support for skipping verification and random data setup Towards enabling dmatest to checkout performance add a 'noverify' mode. Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 01ac7112b5fd..d07b73275d0f 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -66,6 +66,10 @@ module_param(timeout, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " "Pass -1 for infinite timeout"); +static bool noverify; +module_param(noverify, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(noverify, "Disable random data setup and verification"); + /** * struct dmatest_params - test parameters. * @buf_size: size of the memcpy test buffer @@ -88,6 +92,7 @@ struct dmatest_params { unsigned int xor_sources; unsigned int pq_sources; int timeout; + bool noverify; }; /** @@ -435,18 +440,30 @@ static int dmatest_func(void *data) break; } - len = dmatest_random() % params->buf_size + 1; + if (params->noverify) { + len = params->buf_size; + src_off = 0; + dst_off = 0; + } else { + len = dmatest_random() % params->buf_size + 1; + len = (len >> align) << align; + if (!len) + len = 1 << align; + 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; + + dmatest_init_srcs(thread->srcs, src_off, len, + params->buf_size); + dmatest_init_dsts(thread->dsts, dst_off, len, + params->buf_size); + } + len = (len >> align) << align; if (!len) len = 1 << align; - 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; - - dmatest_init_srcs(thread->srcs, src_off, len, params->buf_size); - dmatest_init_dsts(thread->dsts, dst_off, len, params->buf_size); for (i = 0; i < src_cnt; i++) { u8 *buf = thread->srcs[i] + src_off; @@ -555,10 +572,14 @@ static int dmatest_func(void *data) unmap_src(dev->dev, dma_srcs, len, src_cnt); unmap_dst(dev->dev, dma_dsts, params->buf_size, dst_cnt); - error_count = 0; + if (params->noverify) { + dbg_result("test passed", total_tests, src_off, dst_off, + len, 0); + continue; + } pr_debug("%s: verifying source buffer...\n", current->comm); - error_count += dmatest_verify(thread->srcs, 0, src_off, + error_count = dmatest_verify(thread->srcs, 0, src_off, 0, PATTERN_SRC, true); error_count += dmatest_verify(thread->srcs, src_off, src_off + len, src_off, @@ -773,6 +794,7 @@ static void run_threaded_test(struct dmatest_info *info) params->xor_sources = xor_sources; params->pq_sources = pq_sources; params->timeout = timeout; + params->noverify = noverify; request_channels(info, DMA_MEMCPY); request_channels(info, DMA_XOR); -- cgit v1.2.3-59-g8ed1b From 86727443a04fdb25397041188efd2527f2b7237b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:07 -0800 Subject: dmatest: add basic performance metrics Add iops and throughput to the summary output. Acked-by: Andy Shevchenko Signed-off-by: Dan Williams --- Documentation/dmatest.txt | 4 ++++ drivers/dma/dmatest.c | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt index e6e16a7f3706..0beb4b68d81f 100644 --- a/Documentation/dmatest.txt +++ b/Documentation/dmatest.txt @@ -77,5 +77,9 @@ the parens represents additional information, e.g. error code, error counter, or status. A test thread also emits a summary line at completion listing the number of tests executed, number that failed, and a result code. +Example: + % dmesg | tail -n 1 + dmatest: dma3chan0-copy0: summary 400000 tests, 0 failures iops: 61524 KB/s 246098 (0) + The details of a data miscompare error are also emitted, but do not follow the above format. diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index d07b73275d0f..26b502069638 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -325,6 +325,29 @@ static void dbg_result(const char *err, unsigned int n, unsigned int src_off, current->comm, n, err, src_off, dst_off, len, data); } +static unsigned long long dmatest_persec(s64 runtime, unsigned int val) +{ + unsigned long long per_sec = 1000000; + + if (runtime <= 0) + return 0; + + /* drop precision until runtime is 32-bits */ + while (runtime > UINT_MAX) { + runtime >>= 1; + per_sec <<= 1; + } + + per_sec *= val; + do_div(per_sec, runtime); + return per_sec; +} + +static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len) +{ + return dmatest_persec(runtime, len >> 10); +} + /* * This function repeatedly tests DMA transfers of various lengths and * offsets for a given operation type until it is told to exit by @@ -360,6 +383,9 @@ static int dmatest_func(void *data) int src_cnt; int dst_cnt; int i; + ktime_t ktime; + s64 runtime = 0; + unsigned long long total_len = 0; set_freezable(); @@ -417,6 +443,7 @@ static int dmatest_func(void *data) */ flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + ktime = ktime_get(); while (!kthread_should_stop() && !(params->iterations && total_tests >= params->iterations)) { struct dma_async_tx_descriptor *tx = NULL; @@ -464,6 +491,7 @@ static int dmatest_func(void *data) len = (len >> align) << align; if (!len) len = 1 << align; + total_len += len; for (i = 0; i < src_cnt; i++) { u8 *buf = thread->srcs[i] + src_off; @@ -607,6 +635,7 @@ static int dmatest_func(void *data) len, 0); } } + runtime = ktime_us_delta(ktime_get(), ktime); ret = 0; for (i = 0; thread->dsts[i]; i++) @@ -621,8 +650,10 @@ err_srcbuf: err_srcs: kfree(pq_coefs); err_thread_type: - pr_info("%s: terminating after %u tests, %u failures (status %d)\n", - current->comm, total_tests, failed_tests, ret); + pr_info("%s: summary %u tests, %u failures %llu iops %llu KB/s (%d)\n", + current->comm, total_tests, failed_tests, + dmatest_persec(runtime, total_tests), + dmatest_KBs(runtime, total_len), ret); /* terminate all transfers on specified channels */ if (ret) -- cgit v1.2.3-59-g8ed1b From 2d88ce76eb98c4ac4411dcb299cf61ca8999d2b9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:09 -0800 Subject: dmatest: add a 'wait' parameter Allows for scripting test runs by module load / unload. Prevent module load from returning until 'iterations' (finite) tests have completed, or cause reads of the 'wait' parameter in sysfs to pause until the tests are done. Also killed the local waitqueue since we can just let the thread exit naturally as long as we hold a reference. Cc: Nicolas Ferre Signed-off-by: Dan Williams --- Documentation/dmatest.txt | 27 +++++++++++------- drivers/dma/dmatest.c | 72 +++++++++++++++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 35 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/Documentation/dmatest.txt b/Documentation/dmatest.txt index 0beb4b68d81f..dd77a81bdb80 100644 --- a/Documentation/dmatest.txt +++ b/Documentation/dmatest.txt @@ -39,17 +39,24 @@ stops. Note that running a new test will not stop any in progress test. -The following command should return actual state of the test. - % cat /sys/kernel/debug/dmatest/run +The following command returns the state of the test. + % cat /sys/module/dmatest/parameters/run -To wait for test done the user may perform a busy loop that checks the state. +To wait for test completion userpace can poll 'run' until it is false, or use +the wait parameter. Specifying 'wait=1' when loading the module causes module +initialization to pause until a test run has completed, while reading +/sys/module/dmatest/parameters/wait waits for any running test to complete +before returning. For example, the following scripts wait for 42 tests +to complete before exiting. Note that if 'iterations' is set to 'infinite' then +waiting is disabled. - % while [ $(cat /sys/module/dmatest/parameters/run) = "Y" ] - > do - > echo -n "." - > sleep 1 - > done - > echo +Example: + % modprobe dmatest run=1 iterations=42 wait=1 + % modprobe -r dmatest +...or: + % modprobe dmatest run=1 iterations=42 + % cat /sys/module/dmatest/parameters/wait + % modprobe -r dmatest Part 3 - When built-in in the kernel... @@ -79,7 +86,7 @@ number of tests executed, number that failed, and a result code. Example: % dmesg | tail -n 1 - dmatest: dma3chan0-copy0: summary 400000 tests, 0 failures iops: 61524 KB/s 246098 (0) + dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0) The details of a data miscompare error are also emitted, but do not follow the above format. diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 26b502069638..dd4d84d556d5 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -161,6 +161,43 @@ struct dmatest_chan { struct list_head threads; }; +static DECLARE_WAIT_QUEUE_HEAD(thread_wait); +static bool wait; + +static bool is_threaded_test_run(struct dmatest_info *info) +{ + struct dmatest_chan *dtc; + + list_for_each_entry(dtc, &info->channels, node) { + struct dmatest_thread *thread; + + list_for_each_entry(thread, &dtc->threads, node) { + if (!thread->done) + return true; + } + } + + return false; +} + +static int dmatest_wait_get(char *val, const struct kernel_param *kp) +{ + struct dmatest_info *info = &test_info; + struct dmatest_params *params = &info->params; + + if (params->iterations) + wait_event(thread_wait, !is_threaded_test_run(info)); + wait = true; + return param_get_bool(val, kp); +} + +static struct kernel_param_ops wait_ops = { + .get = dmatest_wait_get, + .set = param_set_bool, +}; +module_param_cb(wait, &wait_ops, &wait, S_IRUGO); +MODULE_PARM_DESC(wait, "Wait for tests to complete (default: false)"); + static bool dmatest_match_channel(struct dmatest_params *params, struct dma_chan *chan) { @@ -660,12 +697,7 @@ err_thread_type: dmaengine_terminate_all(chan); thread->done = true; - - if (params->iterations > 0) - while (!kthread_should_stop()) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); - interruptible_sleep_on(&wait_dmatest_exit); - } + wake_up(&thread_wait); return ret; } @@ -681,6 +713,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) pr_debug("thread %s exited with status %d\n", thread->task->comm, ret); list_del(&thread->node); + put_task_struct(thread->task); kfree(thread); } @@ -719,18 +752,19 @@ static int dmatest_add_threads(struct dmatest_info *info, thread->chan = dtc->chan; thread->type = type; smp_wmb(); - thread->task = kthread_run(dmatest_func, thread, "%s-%s%u", + thread->task = kthread_create(dmatest_func, thread, "%s-%s%u", dma_chan_name(chan), op, i); if (IS_ERR(thread->task)) { - pr_warn("Failed to run thread %s-%s%u\n", + pr_warn("Failed to create thread %s-%s%u\n", dma_chan_name(chan), op, i); kfree(thread); break; } /* srcbuf and dstbuf are allocated by the thread itself */ - + get_task_struct(thread->task); list_add_tail(&thread->node, &dtc->threads); + wake_up_process(thread->task); } return i; @@ -863,22 +897,6 @@ static void restart_threaded_test(struct dmatest_info *info, bool run) run_threaded_test(info); } -static bool is_threaded_test_run(struct dmatest_info *info) -{ - struct dmatest_chan *dtc; - - list_for_each_entry(dtc, &info->channels, node) { - struct dmatest_thread *thread; - - list_for_each_entry(thread, &dtc->threads, node) { - if (!thread->done) - return true; - } - } - - return false; -} - static int dmatest_run_get(char *val, const struct kernel_param *kp) { struct dmatest_info *info = &test_info; @@ -920,6 +938,7 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp) static int __init dmatest_init(void) { struct dmatest_info *info = &test_info; + struct dmatest_params *params = &info->params; if (dmatest_run) { mutex_lock(&info->lock); @@ -927,6 +946,9 @@ static int __init dmatest_init(void) mutex_unlock(&info->lock); } + if (params->iterations && wait) + wait_event(thread_wait, !is_threaded_test_run(info)); + /* module parameters are stable, inittime tests are started, * let userspace take over 'run' control */ -- cgit v1.2.3-59-g8ed1b From 4076e755dbec078c85352a8f77cec4c10181da4e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 Nov 2013 16:30:10 -0800 Subject: dmatest: convert to dmaengine_unmap_data Remove the open coded unmap and add coverage for this core functionality to dmatest. Also fixes up a couple places where we leaked dma mappings. Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 86 ++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index dd4d84d556d5..0d050d2324e3 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -326,20 +326,6 @@ static void dmatest_callback(void *arg) wake_up_all(done->wait); } -static inline void unmap_src(struct device *dev, dma_addr_t *addr, size_t len, - unsigned int count) -{ - while (count--) - dma_unmap_single(dev, addr[count], len, DMA_TO_DEVICE); -} - -static inline void unmap_dst(struct device *dev, dma_addr_t *addr, size_t len, - unsigned int count) -{ - while (count--) - dma_unmap_single(dev, addr[count], len, DMA_BIDIRECTIONAL); -} - static unsigned int min_odd(unsigned int x, unsigned int y) { unsigned int val = min(x, y); @@ -484,8 +470,9 @@ static int dmatest_func(void *data) while (!kthread_should_stop() && !(params->iterations && total_tests >= params->iterations)) { struct dma_async_tx_descriptor *tx = NULL; - dma_addr_t dma_srcs[src_cnt]; - dma_addr_t dma_dsts[dst_cnt]; + struct dmaengine_unmap_data *um; + dma_addr_t srcs[src_cnt]; + dma_addr_t *dsts; u8 align = 0; total_tests++; @@ -530,61 +517,75 @@ static int dmatest_func(void *data) len = 1 << align; total_len += len; - for (i = 0; i < src_cnt; i++) { - u8 *buf = thread->srcs[i] + src_off; + 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); + continue; + } - dma_srcs[i] = dma_map_single(dev->dev, buf, len, - DMA_TO_DEVICE); - ret = dma_mapping_error(dev->dev, dma_srcs[i]); + um->len = params->buf_size; + for (i = 0; i < src_cnt; i++) { + unsigned long buf = (unsigned long) thread->srcs[i]; + struct page *pg = virt_to_page(buf); + unsigned pg_off = buf & ~PAGE_MASK; + + um->addr[i] = dma_map_page(dev->dev, pg, pg_off, + um->len, DMA_TO_DEVICE); + srcs[i] = um->addr[i] + src_off; + ret = dma_mapping_error(dev->dev, um->addr[i]); if (ret) { - unmap_src(dev->dev, dma_srcs, len, i); + dmaengine_unmap_put(um); result("src mapping error", total_tests, 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++) { - dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i], - params->buf_size, - DMA_BIDIRECTIONAL); - ret = dma_mapping_error(dev->dev, dma_dsts[i]); + unsigned long buf = (unsigned long) thread->dsts[i]; + struct page *pg = virt_to_page(buf); + unsigned pg_off = buf & ~PAGE_MASK; + + dsts[i] = dma_map_page(dev->dev, pg, pg_off, um->len, + DMA_BIDIRECTIONAL); + ret = dma_mapping_error(dev->dev, dsts[i]); if (ret) { - unmap_src(dev->dev, dma_srcs, len, src_cnt); - unmap_dst(dev->dev, dma_dsts, params->buf_size, - i); + dmaengine_unmap_put(um); result("dst mapping error", total_tests, src_off, dst_off, len, ret); failed_tests++; continue; } + um->bidi_cnt++; } if (thread->type == DMA_MEMCPY) tx = dev->device_prep_dma_memcpy(chan, - dma_dsts[0] + dst_off, - dma_srcs[0], len, - flags); + dsts[0] + dst_off, + srcs[0], len, flags); else if (thread->type == DMA_XOR) tx = dev->device_prep_dma_xor(chan, - dma_dsts[0] + dst_off, - dma_srcs, src_cnt, + dsts[0] + dst_off, + srcs, src_cnt, len, flags); else if (thread->type == DMA_PQ) { dma_addr_t dma_pq[dst_cnt]; for (i = 0; i < dst_cnt; i++) - dma_pq[i] = dma_dsts[i] + dst_off; - tx = dev->device_prep_dma_pq(chan, dma_pq, dma_srcs, + dma_pq[i] = dsts[i] + dst_off; + tx = dev->device_prep_dma_pq(chan, dma_pq, srcs, src_cnt, pq_coefs, len, flags); } if (!tx) { - unmap_src(dev->dev, dma_srcs, len, src_cnt); - unmap_dst(dev->dev, dma_dsts, params->buf_size, - dst_cnt); + dmaengine_unmap_put(um); result("prep error", total_tests, src_off, dst_off, len, ret); msleep(100); @@ -598,6 +599,7 @@ static int dmatest_func(void *data) cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { + dmaengine_unmap_put(um); result("submit error", total_tests, src_off, dst_off, len, ret); msleep(100); @@ -620,11 +622,13 @@ static int dmatest_func(void *data) * free it this time?" dancing. For now, just * leave it dangling. */ + dmaengine_unmap_put(um); result("test timed out", total_tests, src_off, dst_off, len, 0); failed_tests++; continue; } else if (status != DMA_SUCCESS) { + dmaengine_unmap_put(um); result(status == DMA_ERROR ? "completion error status" : "completion busy status", total_tests, src_off, @@ -633,9 +637,7 @@ static int dmatest_func(void *data) continue; } - /* Unmap by myself */ - unmap_src(dev->dev, dma_srcs, len, src_cnt); - unmap_dst(dev->dev, dma_dsts, params->buf_size, dst_cnt); + dmaengine_unmap_put(um); if (params->noverify) { dbg_result("test passed", total_tests, src_off, dst_off, -- cgit v1.2.3-59-g8ed1b From 50137a7df982f3767fe0b3b0cd0b9cfaf09c2cd9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 8 Nov 2013 12:26:26 -0800 Subject: dmatest: verbose mode Verbose mode turns on test success messages, by default we only output test summaries and failure results. Also cleaned up some stray quotes, leftover from putting the result message format string all on one line. Cc: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/dma/dmatest.c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 0d050d2324e3..329b7cf02f8e 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -70,6 +70,10 @@ static bool noverify; module_param(noverify, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(noverify, "Disable random data setup and verification"); +static bool verbose; +module_param(verbose, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)"); + /** * struct dmatest_params - test parameters. * @buf_size: size of the memcpy test buffer @@ -336,7 +340,7 @@ static unsigned int min_odd(unsigned int x, unsigned int y) static void result(const char *err, unsigned int n, unsigned int src_off, unsigned int dst_off, unsigned int len, unsigned long data) { - pr_info("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)", + pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)", current->comm, n, err, src_off, dst_off, len, data); } @@ -344,10 +348,17 @@ static void dbg_result(const char *err, unsigned int n, unsigned int src_off, unsigned int dst_off, unsigned int len, unsigned long data) { - pr_debug("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)", - current->comm, n, err, src_off, dst_off, len, data); + pr_debug("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)", + current->comm, n, err, src_off, dst_off, len, data); } +#define verbose_result(err, n, src_off, dst_off, len, data) ({ \ + if (verbose) \ + result(err, n, src_off, dst_off, len, data); \ + else \ + dbg_result(err, n, src_off, dst_off, len, data); \ +}) + static unsigned long long dmatest_persec(s64 runtime, unsigned int val) { unsigned long long per_sec = 1000000; @@ -640,8 +651,8 @@ static int dmatest_func(void *data) dmaengine_unmap_put(um); if (params->noverify) { - dbg_result("test passed", total_tests, src_off, dst_off, - len, 0); + verbose_result("test passed", total_tests, src_off, + dst_off, len, 0); continue; } @@ -670,8 +681,8 @@ static int dmatest_func(void *data) len, error_count); failed_tests++; } else { - dbg_result("test passed", total_tests, src_off, dst_off, - len, 0); + verbose_result("test passed", total_tests, src_off, + dst_off, len, 0); } } runtime = ktime_us_delta(ktime_get(), ktime); -- cgit v1.2.3-59-g8ed1b