static void xdma_start_transfer(struct xdma_chan *chan, int start_index, int end_index) { dma_addr_t cur_phys; dma_addr_t tail_phys; u32 regval; if (chan->err) return; cur_phys = chan->bd_phys_addr + (start_index * sizeof(struct xdma_desc_hw)); tail_phys = chan->bd_phys_addr + (end_index * sizeof(struct xdma_desc_hw)); /* If hardware is busy, move the tail & return */ if (dma_is_running(chan) || dma_is_idle(chan)) { /* Update tail ptr register and start the transfer */ DMA_OUT(&chan->regs->tdr, tail_phys); return; } DMA_OUT(&chan->regs->cdr, cur_phys); dma_start(chan); /* Enable interrupts */ regval = DMA_IN(&chan->regs->cr); regval |= (chan->poll_mode ? XDMA_XR_IRQ_ERROR_MASK : XDMA_XR_IRQ_ALL_MASK); DMA_OUT(&chan->regs->cr, regval); /* Update tail ptr register and start the transfer */ DMA_OUT(&chan->regs->tdr, tail_phys); }
void test_dma_writes(ssize_t f) { int PAGE_SIZE = 4*1024; int BUF_SIZE = PAGE_SIZE; char *data = 0; char *ret_data = 0; posix_memalign ((void*)&data, PAGE_SIZE, BUF_SIZE); posix_memalign ((void*)&ret_data, PAGE_SIZE, BUF_SIZE); memset (data, 1234, BUF_SIZE/4); sprintf (data, "Hello from DE4!\n"); data[15] = '\0'; fprintf (stderr, "First small part of what we're writing: %s\n", data); // fprintf (stderr, "Writing %d bytes to %p from %p\n", BUF_SIZE, 0, data); write_mem (f, 0, (void*)(0), data, BUF_SIZE); while (!dma_is_idle(f)) dma_update(f); // fprintf (stderr, "Reading back %d bytes from %p to %p\n", BUF_SIZE, 0, ret_data); read_mem (f, 0, (void*)(0), ret_data, BUF_SIZE); while (!dma_is_idle(f)) dma_update(f); fprintf (stderr, "First small part of data we got back: %s\n", ret_data); assert (memcmp(data, ret_data, BUF_SIZE) == 0); fprintf (stderr, "DMA write passed!\n"); return; }
/* Test reading and writing long chunks of data */ void test_large_read_write (ssize_t f) { int j, num_write_runs = 5; size_t buf_size = 80 * 1024 * 1024; char *buf1 = NULL; char *buf2 = NULL; const size_t ALIGNMENT = 4096; posix_memalign ((void**)&buf1, ALIGNMENT, buf_size); posix_memalign ((void**)&buf2, ALIGNMENT, buf_size); if (buf1 == NULL || buf2 == NULL) { printf ("Couldn't allocate memory! FAILED\n"); } /* Some "real" data to fill memory with. */ FILE *data_file = fopen ("tests/ulysses.txt", "r"); if (data_file == NULL) { printf ("Couldn't open data file! FAILED\n"); } /* read data file in chunks of 4 KB */ size_t read_step = 1024 * 4; size_t num_read = 0; size_t incr = 0, file_size = 0; while ( (num_read = fread (buf1 + incr, sizeof(char), read_step, data_file)) ) { incr += num_read; if (num_read < read_step) { /* Done reading */ break; } } /* Copy the file content until fill the buffer */ file_size = incr; while (incr < (buf_size - file_size)) { memcpy (buf1 + incr, buf1, file_size); incr += file_size; } assert (incr < buf_size); incr = incr - (incr % ALIGNMENT); printf ("Useful data size for large read/write test is %zu bytes\n", incr); clock_t start = clock(); clock_t e1, e2; /* Write to different locations on each run just to avoid * any kind of caching on PCIe block. */ for (j = 0; j < num_write_runs; j++) { write_mem (f, 0, (void*)(incr * j), buf1, incr); while (!dma_is_idle(f)) dma_update(f); } e1 = clock(); read_mem (f, 0, 0, buf2, incr); while (!dma_is_idle(f)) dma_update(f); e2 = clock(); double t1 = ((double)e1 - start) / CLOCKS_PER_SEC; double t2 = ((double)e2 - e1) / CLOCKS_PER_SEC; int mb = 1024 * 1024; printf ("Writing %zu bytes took %.3f seconds (%.3f MB / sec)\n", incr, t1, incr / mb / t1 * num_write_runs ); printf ("Reading %zu bytes took %.3f seconds (%.3f MB / sec)\n", incr, t2, incr / mb / t2 ); /* Make sure what we read back is the same as what we wrote */ assert (memcmp (buf1, buf2, incr) == 0); printf ("test_large_read_write PASSED\n"); free (buf1); free (buf2); return; }