ARM: 6064/1: pmu: register IRQs at runtime
[safe/jmp/linux-2.6] / drivers / dma / dmatest.c
index 224acf4..6fa55fe 100644 (file)
@@ -38,11 +38,21 @@ module_param(max_channels, uint, S_IRUGO);
 MODULE_PARM_DESC(max_channels,
                "Maximum number of channels to use (default: all)");
 
+static unsigned int iterations;
+module_param(iterations, uint, S_IRUGO);
+MODULE_PARM_DESC(iterations,
+               "Iterations before stopping test (default: infinite)");
+
 static unsigned int xor_sources = 3;
 module_param(xor_sources, uint, S_IRUGO);
 MODULE_PARM_DESC(xor_sources,
                "Number of xor source buffers (default: 3)");
 
+static unsigned int pq_sources = 3;
+module_param(pq_sources, uint, S_IRUGO);
+MODULE_PARM_DESC(pq_sources,
+               "Number of p+q source buffers (default: 3)");
+
 /*
  * Initialization patterns. All bytes in the source buffer has bit 7
  * set, all bytes in the destination buffer has bit 7 cleared.
@@ -114,7 +124,7 @@ static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len)
                        buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
                for ( ; i < start + len; i++)
                        buf[i] = PATTERN_SRC | PATTERN_COPY
-                               | (~i & PATTERN_COUNT_MASK);;
+                               | (~i & PATTERN_COUNT_MASK);
                for ( ; i < test_buf_size; i++)
                        buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
                buf++;
@@ -196,6 +206,11 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start,
        return error_count;
 }
 
+static void dmatest_callback(void *completion)
+{
+       complete(completion);
+}
+
 /*
  * This function repeatedly tests DMA transfers of various lengths and
  * offsets for a given operation type until it is told to exit by
@@ -222,6 +237,7 @@ static int dmatest_func(void *data)
        dma_cookie_t            cookie;
        enum dma_status         status;
        enum dma_ctrl_flags     flags;
+       u8                      pq_coefs[pq_sources + 1];
        int                     ret;
        int                     src_cnt;
        int                     dst_cnt;
@@ -238,6 +254,11 @@ static int dmatest_func(void *data)
        else if (thread->type == DMA_XOR) {
                src_cnt = xor_sources | 1; /* force odd to ensure dst = src */
                dst_cnt = 1;
+       } else if (thread->type == DMA_PQ) {
+               src_cnt = pq_sources | 1; /* force odd to ensure dst = src */
+               dst_cnt = 2;
+               for (i = 0; i < src_cnt; i++)
+                       pq_coefs[i] = 1;
        } else
                goto err_srcs;
 
@@ -261,20 +282,46 @@ static int dmatest_func(void *data)
        }
        thread->dsts[i] = NULL;
 
-       flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP;
+       set_user_nice(current, 10);
+
+       flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT;
 
-       while (!kthread_should_stop()) {
+       while (!kthread_should_stop()
+              && !(iterations && total_tests >= iterations)) {
                struct dma_device *dev = chan->device;
                struct dma_async_tx_descriptor *tx = NULL;
                dma_addr_t dma_srcs[src_cnt];
                dma_addr_t dma_dsts[dst_cnt];
+               struct completion cmp;
+               unsigned long tmo = msecs_to_jiffies(3000);
+               u8 align = 0;
 
                total_tests++;
 
+               /* honor alignment restrictions */
+               if (thread->type == DMA_MEMCPY)
+                       align = dev->copy_align;
+               else if (thread->type == DMA_XOR)
+                       align = dev->xor_align;
+               else if (thread->type == DMA_PQ)
+                       align = dev->pq_align;
+
+               if (1 << align > test_buf_size) {
+                       pr_err("%u-byte buffer too small for %d-byte alignment\n",
+                              test_buf_size, 1 << align);
+                       break;
+               }
+
                len = dmatest_random() % test_buf_size + 1;
+               len = (len >> align) << align;
+               if (!len)
+                       len = 1 << align;
                src_off = dmatest_random() % (test_buf_size - len + 1);
                dst_off = dmatest_random() % (test_buf_size - len + 1);
 
+               src_off = (src_off >> align) << align;
+               dst_off = (dst_off >> align) << align;
+
                dmatest_init_srcs(thread->srcs, src_off, len);
                dmatest_init_dsts(thread->dsts, dst_off, len);
 
@@ -291,6 +338,7 @@ static int dmatest_func(void *data)
                                                     DMA_BIDIRECTIONAL);
                }
 
+
                if (thread->type == DMA_MEMCPY)
                        tx = dev->device_prep_dma_memcpy(chan,
                                                         dma_dsts[0] + dst_off,
@@ -299,8 +347,17 @@ static int dmatest_func(void *data)
                else if (thread->type == DMA_XOR)
                        tx = dev->device_prep_dma_xor(chan,
                                                      dma_dsts[0] + dst_off,
-                                                     dma_srcs, xor_sources,
+                                                     dma_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,
+                                                    src_cnt, pq_coefs,
+                                                    len, flags);
+               }
 
                if (!tx) {
                        for (i = 0; i < src_cnt; i++)
@@ -318,7 +375,10 @@ static int dmatest_func(void *data)
                        failed_tests++;
                        continue;
                }
-               tx->callback = NULL;
+
+               init_completion(&cmp);
+               tx->callback = dmatest_callback;
+               tx->callback_param = &cmp;
                cookie = tx->tx_submit(tx);
 
                if (dma_submit_error(cookie)) {
@@ -332,18 +392,23 @@ static int dmatest_func(void *data)
                }
                dma_async_issue_pending(chan);
 
-               do {
-                       msleep(1);
-                       status = dma_async_is_tx_complete(
-                                       chan, cookie, NULL, NULL);
-               } while (status == DMA_IN_PROGRESS);
+               tmo = wait_for_completion_timeout(&cmp, tmo);
+               status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
 
-               if (status == DMA_ERROR) {
-                       pr_warning("%s: #%u: error during copy\n",
-                                       thread_name, total_tests - 1);
+               if (tmo == 0) {
+                       pr_warning("%s: #%u: test timed out\n",
+                                  thread_name, total_tests - 1);
+                       failed_tests++;
+                       continue;
+               } else if (status != DMA_SUCCESS) {
+                       pr_warning("%s: #%u: got completion callback,"
+                                  " but status is \'%s\'\n",
+                                  thread_name, total_tests - 1,
+                                  status == DMA_ERROR ? "error" : "in progress");
                        failed_tests++;
                        continue;
                }
+
                /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */
                for (i = 0; i < dst_cnt; i++)
                        dma_unmap_single(dev->dev, dma_dsts[i], test_buf_size,
@@ -399,6 +464,13 @@ err_srcbuf:
 err_srcs:
        pr_notice("%s: terminating after %u tests, %u failures (status %d)\n",
                        thread_name, total_tests, failed_tests, ret);
+
+       if (iterations > 0)
+               while (!kthread_should_stop()) {
+                       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit);
+                       interruptible_sleep_on(&wait_dmatest_exit);
+               }
+
        return ret;
 }
 
@@ -429,6 +501,8 @@ static int dmatest_add_threads(struct dmatest_chan *dtc, enum dma_transaction_ty
                op = "copy";
        else if (type == DMA_XOR)
                op = "xor";
+       else if (type == DMA_PQ)
+               op = "pq";
        else
                return -EINVAL;
 
@@ -478,10 +552,14 @@ static int dmatest_add_channel(struct dma_chan *chan)
 
        if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
                cnt = dmatest_add_threads(dtc, DMA_MEMCPY);
-               thread_count += cnt > 0 ?: 0;
+               thread_count += cnt > 0 ? cnt : 0;
        }
        if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
                cnt = dmatest_add_threads(dtc, DMA_XOR);
+               thread_count += cnt > 0 ? cnt : 0;
+       }
+       if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
+               cnt = dmatest_add_threads(dtc, DMA_PQ);
                thread_count += cnt > 0 ?: 0;
        }
 
@@ -514,9 +592,7 @@ static int __init dmatest_init(void)
                chan = dma_request_channel(mask, filter, NULL);
                if (chan) {
                        err = dmatest_add_channel(chan);
-                       if (err == 0)
-                               continue;
-                       else {
+                       if (err) {
                                dma_release_channel(chan);
                                break; /* add_channel failed, punt */
                        }