Commit 2c01de22 authored by Karen Xie's avatar Karen Xie

XDMA v2020.1.08: allow ST c2h to end a dma transfer when EOP is received

parent 7642657b
v2020.1.08
===============
- replaced module parameter "sgdma_timeout" to "h2c_timeout" and "c2h_timeout"
for H2C and C2H channels.
value of 0 means no timeout: wait forever for the dma completion.
- added new "-e" option to dma_from_device
this is for streaming mode only, when -e is set, the driver will end the dma
and return the data when an EOP (end-of-packet) is received or the
specified bytes of data is received.
without "-e" option, the driver will end the dma when the specified bytes of
data is received.
- added gen4 device ids
- fixed next adjacent descriptors when dma_alloc_coherent doesn't return a
page-aligned address
v2020.1.06
===============
- added memory aperture support (-k) option in dma_from_device and dma_to_device.
- fixed holding spinlock while doing wait_event_interruptible_xxx
- kernel 5.0 support
- fixed next adjacent descriptors crossing the 4K boundary
Release: 2019.2 Release: 2019.2
=============== ===============
......
...@@ -40,6 +40,7 @@ static struct option const long_opts[] = { ...@@ -40,6 +40,7 @@ static struct option const long_opts[] = {
{"offset", required_argument, NULL, 'o'}, {"offset", required_argument, NULL, 'o'},
{"count", required_argument, NULL, 'c'}, {"count", required_argument, NULL, 'c'},
{"file", required_argument, NULL, 'f'}, {"file", required_argument, NULL, 'f'},
{"eop_flush", no_argument, NULL, 'e'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'}, {"verbose", no_argument, NULL, 'v'},
{0, 0, 0, 0} {0, 0, 0, 0}
...@@ -48,7 +49,7 @@ static struct option const long_opts[] = { ...@@ -48,7 +49,7 @@ static struct option const long_opts[] = {
static int test_dma(char *devname, uint64_t addr, uint64_t aperture, static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
uint64_t size, uint64_t offset, uint64_t count, uint64_t size, uint64_t offset, uint64_t count,
char *ofname); char *ofname);
static int no_write = 0; static int eop_flush = 0;
static void usage(const char *name) static void usage(const char *name)
{ {
...@@ -80,12 +81,25 @@ static void usage(const char *name) ...@@ -80,12 +81,25 @@ static void usage(const char *name)
" -%c (--%s) file to write the data of the transfers\n", " -%c (--%s) file to write the data of the transfers\n",
long_opts[i].val, long_opts[i].name); long_opts[i].val, long_opts[i].name);
i++; i++;
fprintf(stdout,
" -%c (--%s) end dma when ST end-of-packet(eop) is rcved\n",
long_opts[i].val, long_opts[i].name);
fprintf(stdout,
"\t\t* streaming only, ignored for memory-mapped channels\n");
fprintf(stdout,
"\t\t* acutal # of bytes dma'ed could be smaller than specified\n");
i++;
fprintf(stdout, " -%c (--%s) print usage help and exit\n", fprintf(stdout, " -%c (--%s) print usage help and exit\n",
long_opts[i].val, long_opts[i].name); long_opts[i].val, long_opts[i].name);
i++; i++;
fprintf(stdout, " -%c (--%s) verbose output\n", fprintf(stdout, " -%c (--%s) verbose output\n",
long_opts[i].val, long_opts[i].name); long_opts[i].val, long_opts[i].name);
i++; i++;
fprintf(stdout, "\nReturn code:\n");
fprintf(stdout, " 0: all bytes were dma'ed successfully\n");
fprintf(stdout, " * with -e set, the bytes dma'ed could be smaller\n");
fprintf(stdout, " < 0: error\n\n");
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
...@@ -99,7 +113,7 @@ int main(int argc, char *argv[]) ...@@ -99,7 +113,7 @@ int main(int argc, char *argv[])
uint64_t count = COUNT_DEFAULT; uint64_t count = COUNT_DEFAULT;
char *ofname = NULL; char *ofname = NULL;
while ((cmd_opt = getopt_long(argc, argv, "vhxc:f:d:a:k:s:o:", long_opts, while ((cmd_opt = getopt_long(argc, argv, "vhec:f:d:a:k:s:o:", long_opts,
NULL)) != -1) { NULL)) != -1) {
switch (cmd_opt) { switch (cmd_opt) {
case 0: case 0:
...@@ -133,12 +147,12 @@ int main(int argc, char *argv[]) ...@@ -133,12 +147,12 @@ int main(int argc, char *argv[])
ofname = strdup(optarg); ofname = strdup(optarg);
break; break;
/* print usage help and exit */ /* print usage help and exit */
case 'x':
no_write++;
break;
case 'v': case 'v':
verbose = 1; verbose = 1;
break; break;
case 'e':
eop_flush = 1;
break;
case 'h': case 'h':
default: default:
usage(argv[0]); usage(argv[0]);
...@@ -159,19 +173,30 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -159,19 +173,30 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
uint64_t size, uint64_t offset, uint64_t count, uint64_t size, uint64_t offset, uint64_t count,
char *ofname) char *ofname)
{ {
ssize_t rc; ssize_t rc = 0;
size_t out_offset = 0;
size_t bytes_done = 0;
uint64_t i; uint64_t i;
uint64_t apt_loop = aperture ? (size + aperture - 1) / aperture : 0; uint64_t apt_loop = aperture ? (size + aperture - 1) / aperture : 0;
char *buffer = NULL; char *buffer = NULL;
char *allocated = NULL; char *allocated = NULL;
struct timespec ts_start, ts_end; struct timespec ts_start, ts_end;
int out_fd = -1; int out_fd = -1;
int fpga_fd = open(devname, O_RDWR | O_NONBLOCK); int fpga_fd;
long total_time = 0; long total_time = 0;
float result; float result;
float avg_time = 0; float avg_time = 0;
int underflow = 0; int underflow = 0;
/*
* use O_TRUNC to indicate to the driver to flush the data up based on
* EOP (end-of-packet), streaming mode only
*/
if (eop_flush)
fpga_fd = open(devname, O_RDWR | O_TRUNC);
else
fpga_fd = open(devname, O_RDWR);
if (fpga_fd < 0) { if (fpga_fd < 0) {
fprintf(stderr, "unable to open device %s, %d.\n", fprintf(stderr, "unable to open device %s, %d.\n",
devname, fpga_fd); devname, fpga_fd);
...@@ -210,6 +235,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -210,6 +235,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
uint64_t len = size; uint64_t len = size;
char *buf = buffer; char *buf = buffer;
bytes_done = 0;
for (j = 0; j < apt_loop; j++, len -= aperture, buf += aperture) { for (j = 0; j < apt_loop; j++, len -= aperture, buf += aperture) {
uint64_t bytes = (len > aperture) ? aperture : len, uint64_t bytes = (len > aperture) ? aperture : len,
rc = read_to_buffer(devname, fpga_fd, buf, rc = read_to_buffer(devname, fpga_fd, buf,
...@@ -219,13 +245,15 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -219,13 +245,15 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
if (!underflow && rc < bytes) if (!underflow && rc < bytes)
underflow = 1; underflow = 1;
bytes_done += rc;
} }
} else { } else {
rc = read_to_buffer(devname, fpga_fd, buffer, size, addr); rc = read_to_buffer(devname, fpga_fd, buffer, size, addr);
if (rc < 0) if (rc < 0)
goto out; goto out;
bytes_done = rc;
if (!underflow && rc < size) if (!underflow && bytes_done < size)
underflow = 1; underflow = 1;
} }
clock_gettime(CLOCK_MONOTONIC, &ts_end); clock_gettime(CLOCK_MONOTONIC, &ts_end);
...@@ -238,14 +266,15 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -238,14 +266,15 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
if (verbose) if (verbose)
fprintf(stdout, fprintf(stdout,
"#%lu: CLOCK_MONOTONIC %ld.%09ld sec. read %ld/%ld bytes\n", "#%lu: CLOCK_MONOTONIC %ld.%09ld sec. read %ld/%ld bytes\n",
i, ts_end.tv_sec, ts_end.tv_nsec, rc, size); i, ts_end.tv_sec, ts_end.tv_nsec, bytes_done, size);
/* file argument given? */ /* file argument given? */
if ((out_fd >= 0) & (no_write == 0)) { if (out_fd >= 0) {
rc = write_from_buffer(ofname, out_fd, buffer, rc = write_from_buffer(ofname, out_fd, buffer,
size, i*size); bytes_done, out_offset);
if (rc < 0) if (rc < 0 || rc < bytes_done)
goto out; goto out;
out_offset += bytes_done;
} }
} }
...@@ -256,9 +285,13 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -256,9 +285,13 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
printf("** Avg time device %s, total time %ld nsec, avg_time = %f, size = %lu, BW = %f \n", printf("** Avg time device %s, total time %ld nsec, avg_time = %f, size = %lu, BW = %f \n",
devname, total_time, avg_time, size, result); devname, total_time, avg_time, size, result);
printf("%s ** Average BW = %lu, %f\n", devname, size, result); printf("%s ** Average BW = %lu, %f\n", devname, size, result);
} rc = 0;
} else if (eop_flush) {
/* allow underflow with -e option */
rc = 0;
} else
rc = -EIO;
rc = 0;
out: out:
close(fpga_fd); close(fpga_fd);
if (out_fd >= 0) if (out_fd >= 0)
......
...@@ -93,6 +93,10 @@ static void usage(const char *name) ...@@ -93,6 +93,10 @@ static void usage(const char *name)
fprintf(stdout, " -%c (--%s) verbose output\n", fprintf(stdout, " -%c (--%s) verbose output\n",
long_opts[i].val, long_opts[i].name); long_opts[i].val, long_opts[i].name);
i++; i++;
fprintf(stdout, "\nReturn code:\n");
fprintf(stdout, " 0: all bytes were dma'ed successfully\n");
fprintf(stdout, " < 0: error\n\n");
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
...@@ -173,6 +177,8 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -173,6 +177,8 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
{ {
uint64_t i; uint64_t i;
ssize_t rc; ssize_t rc;
size_t bytes_done = 0;
size_t out_offset = 0;
uint64_t apt_loop = aperture ? (size + aperture - 1) / aperture : 0; uint64_t apt_loop = aperture ? (size + aperture - 1) / aperture : 0;
char *buffer = NULL; char *buffer = NULL;
char *allocated = NULL; char *allocated = NULL;
...@@ -229,7 +235,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -229,7 +235,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
if (infile_fd >= 0) { if (infile_fd >= 0) {
rc = read_to_buffer(infname, infile_fd, buffer, size, 0); rc = read_to_buffer(infname, infile_fd, buffer, size, 0);
if (rc < 0) if (rc < 0 || rc < size)
goto out; goto out;
} }
...@@ -242,6 +248,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -242,6 +248,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
uint64_t len = size; uint64_t len = size;
char *buf = buffer; char *buf = buffer;
bytes_done = 0;
for (j = 0; j < apt_loop; j++, len -= aperture, for (j = 0; j < apt_loop; j++, len -= aperture,
buf += aperture) { buf += aperture) {
uint64_t bytes = (len > aperture) ? aperture : len, uint64_t bytes = (len > aperture) ? aperture : len,
...@@ -250,6 +257,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -250,6 +257,7 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
if (rc < 0) if (rc < 0)
goto out; goto out;
bytes_done += rc;
if (!underflow && rc < bytes) if (!underflow && rc < bytes)
underflow = 1; underflow = 1;
} }
...@@ -259,7 +267,8 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -259,7 +267,8 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
if (rc < 0) if (rc < 0)
goto out; goto out;
if (!underflow && rc < size) bytes_done = rc;
if (!underflow && bytes_done < size)
underflow = 1; underflow = 1;
} }
...@@ -275,9 +284,10 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -275,9 +284,10 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
if (outfile_fd >= 0) { if (outfile_fd >= 0) {
rc = write_from_buffer(ofname, outfile_fd, buffer, rc = write_from_buffer(ofname, outfile_fd, buffer,
size, i * size); bytes_done, out_offset);
if (rc < 0) if (rc < 0 || rc < bytes_done)
goto out; goto out;
out_offset += bytes_done;
} }
} }
...@@ -289,7 +299,6 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture, ...@@ -289,7 +299,6 @@ static int test_dma(char *devname, uint64_t addr, uint64_t aperture,
devname, total_time, avg_time, size, result); devname, total_time, avg_time, size, result);
printf("%s ** Average BW = %lu, %f\n", devname, size, result); printf("%s ** Average BW = %lu, %f\n", devname, size, result);
} }
rc = 0;
out: out:
close(fpga_fd); close(fpga_fd);
...@@ -299,5 +308,8 @@ out: ...@@ -299,5 +308,8 @@ out:
close(outfile_fd); close(outfile_fd);
free(allocated); free(allocated);
return rc; if (rc < 0)
return rc;
/* treat underflow as error */
return underflow ? -EIO : 0;
} }
...@@ -47,6 +47,7 @@ ssize_t read_to_buffer(char *fname, int fd, char *buffer, uint64_t size, ...@@ -47,6 +47,7 @@ ssize_t read_to_buffer(char *fname, int fd, char *buffer, uint64_t size,
uint64_t count = 0; uint64_t count = 0;
char *buf = buffer; char *buf = buffer;
off_t offset = base; off_t offset = base;
int loop = 0;
while (count < size) { while (count < size) {
uint64_t bytes = size - count; uint64_t bytes = size - count;
...@@ -67,7 +68,7 @@ ssize_t read_to_buffer(char *fname, int fd, char *buffer, uint64_t size, ...@@ -67,7 +68,7 @@ ssize_t read_to_buffer(char *fname, int fd, char *buffer, uint64_t size,
/* read data from file into memory buffer */ /* read data from file into memory buffer */
rc = read(fd, buf, bytes); rc = read(fd, buf, bytes);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "%s, read 0x%lx @ 0x%lx failed %d.\n", fprintf(stderr, "%s, read 0x%lx @ 0x%lx failed %ld.\n",
fname, bytes, offset, rc); fname, bytes, offset, rc);
perror("read file"); perror("read file");
return -EIO; return -EIO;
...@@ -75,19 +76,19 @@ ssize_t read_to_buffer(char *fname, int fd, char *buffer, uint64_t size, ...@@ -75,19 +76,19 @@ ssize_t read_to_buffer(char *fname, int fd, char *buffer, uint64_t size,
count += rc; count += rc;
if (rc != bytes) { if (rc != bytes) {
fprintf(stderr, "%s, read underflow 0x%lx/0x%lx, off 0x%lx.\n", fprintf(stderr, "%s, read underflow 0x%lx/0x%lx @ 0x%lx.\n",
fname, rc, bytes, offset); fname, rc, bytes, offset);
break; break;
} }
buf += bytes; buf += bytes;
offset += bytes; offset += bytes;
} loop++;
}
if (count != size) if (count != size && loop)
fprintf(stderr, "%s, read underflow 0x%lx != 0x%lx.\n", fprintf(stderr, "%s, read underflow 0x%lx/0x%lx.\n",
fname, count, size); fname, count, size);
return count; return count;
} }
...@@ -98,6 +99,7 @@ ssize_t write_from_buffer(char *fname, int fd, char *buffer, uint64_t size, ...@@ -98,6 +99,7 @@ ssize_t write_from_buffer(char *fname, int fd, char *buffer, uint64_t size,
uint64_t count = 0; uint64_t count = 0;
char *buf = buffer; char *buf = buffer;
off_t offset = base; off_t offset = base;
int loop = 0;
while (count < size) { while (count < size) {
uint64_t bytes = size - count; uint64_t bytes = size - count;
...@@ -118,7 +120,7 @@ ssize_t write_from_buffer(char *fname, int fd, char *buffer, uint64_t size, ...@@ -118,7 +120,7 @@ ssize_t write_from_buffer(char *fname, int fd, char *buffer, uint64_t size,
/* write data to file from memory buffer */ /* write data to file from memory buffer */
rc = write(fd, buf, bytes); rc = write(fd, buf, bytes);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "%s, write 0x%lx @ 0x%lx failed %d.\n", fprintf(stderr, "%s, write 0x%lx @ 0x%lx failed %ld.\n",
fname, bytes, offset, rc); fname, bytes, offset, rc);
perror("write file"); perror("write file");
return -EIO; return -EIO;
...@@ -126,16 +128,18 @@ ssize_t write_from_buffer(char *fname, int fd, char *buffer, uint64_t size, ...@@ -126,16 +128,18 @@ ssize_t write_from_buffer(char *fname, int fd, char *buffer, uint64_t size,
count += rc; count += rc;
if (rc != bytes) { if (rc != bytes) {
fprintf(stderr, "%s, write underflow 0x%lx/0x%lx, off 0x%lx.\n", fprintf(stderr, "%s, write underflow 0x%lx/0x%lx @ 0x%lx.\n",
fname, rc, bytes, offset); fname, rc, bytes, offset);
break; break;
} }
buf += bytes; buf += bytes;
offset += bytes; offset += bytes;
}
if (count != size) loop++;
fprintf(stderr, "%s, write underflow 0x%lx != 0x%lx.\n", }
if (count != size && loop)
fprintf(stderr, "%s, write underflow 0x%lx/0x%lx.\n",
fname, count, size); fname, count, size);
return count; return count;
...@@ -177,4 +181,3 @@ void timespec_sub(struct timespec *t1, struct timespec *t2) ...@@ -177,4 +181,3 @@ void timespec_sub(struct timespec *t1, struct timespec *t2)
t1->tv_nsec += 1000000000; t1->tv_nsec += 1000000000;
} }
} }
...@@ -485,7 +485,6 @@ static ssize_t cdev_aio_write(struct kiocb *iocb, const struct iovec *io, ...@@ -485,7 +485,6 @@ static ssize_t cdev_aio_write(struct kiocb *iocb, const struct iovec *io,
return -EIOCBQUEUED; return -EIOCBQUEUED;
} }
static ssize_t cdev_aio_read(struct kiocb *iocb, const struct iovec *io, static ssize_t cdev_aio_read(struct kiocb *iocb, const struct iovec *io,
unsigned long count, loff_t pos) unsigned long count, loff_t pos)
{ {
...@@ -790,6 +789,8 @@ static int char_sgdma_open(struct inode *inode, struct file *file) ...@@ -790,6 +789,8 @@ static int char_sgdma_open(struct inode *inode, struct file *file)
if (engine->device_open == 1) if (engine->device_open == 1)
return -EBUSY; return -EBUSY;
engine->device_open = 1; engine->device_open = 1;
engine->eop_flush = (file->f_flags & O_TRUNC) ? 1 : 0;
} }
return 0; return 0;
......
...@@ -95,12 +95,20 @@ static DEFINE_SPINLOCK(xdev_rcu_lock); ...@@ -95,12 +95,20 @@ static DEFINE_SPINLOCK(xdev_rcu_lock);
#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member) #define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member)
#endif #endif
static inline void xdev_list_add(struct xdma_dev *xdev) static inline int xdev_list_add(struct xdma_dev *xdev)
{ {
mutex_lock(&xdev_mutex); mutex_lock(&xdev_mutex);
if (list_empty(&xdev_list)) if (list_empty(&xdev_list)) {
xdev->idx = 0; xdev->idx = 0;
else { if (poll_mode) {
int rv = xdma_threads_create(xdev->h2c_channel_max +
xdev->c2h_channel_max);
if (rv < 0) {
mutex_unlock(&xdev_mutex);
return rv;
}
}
} else {
struct xdma_dev *last; struct xdma_dev *last;
last = list_last_entry(&xdev_list, struct xdma_dev, list_head); last = list_last_entry(&xdev_list, struct xdma_dev, list_head);
...@@ -115,6 +123,8 @@ static inline void xdev_list_add(struct xdma_dev *xdev) ...@@ -115,6 +123,8 @@ static inline void xdev_list_add(struct xdma_dev *xdev)
spin_lock(&xdev_rcu_lock); spin_lock(&xdev_rcu_lock);
list_add_tail_rcu(&xdev->rcu_node, &xdev_rcu_list); list_add_tail_rcu(&xdev->rcu_node, &xdev_rcu_list);
spin_unlock(&xdev_rcu_lock); spin_unlock(&xdev_rcu_lock);
return 0;
} }
#undef list_last_entry #undef list_last_entry
...@@ -123,6 +133,8 @@ static inline void xdev_list_remove(struct xdma_dev *xdev) ...@@ -123,6 +133,8 @@ static inline void xdev_list_remove(struct xdma_dev *xdev)
{ {
mutex_lock(&xdev_mutex); mutex_lock(&xdev_mutex);
list_del(&xdev->list_head); list_del(&xdev->list_head);
if (poll_mode && list_empty(&xdev_list))
xdma_threads_destroy();
mutex_unlock(&xdev_mutex); mutex_unlock(&xdev_mutex);
spin_lock(&xdev_rcu_lock); spin_lock(&xdev_rcu_lock);
...@@ -526,6 +538,10 @@ static int xdma_engine_stop(struct xdma_engine *engine) ...@@ -526,6 +538,10 @@ static int xdma_engine_stop(struct xdma_engine *engine)
} }
dbg_tfr("%s(engine=%p)\n", __func__, engine); dbg_tfr("%s(engine=%p)\n", __func__, engine);
if (enable_credit_mp && engine->streaming &&
engine->dir == DMA_FROM_DEVICE)
write_register(0, &engine->sgdma_regs->credits, 0);
w = 0; w = 0;
w |= (u32)XDMA_CTRL_IE_DESC_ALIGN_MISMATCH; w |= (u32)XDMA_CTRL_IE_DESC_ALIGN_MISMATCH;
w |= (u32)XDMA_CTRL_IE_MAGIC_STOPPED; w |= (u32)XDMA_CTRL_IE_MAGIC_STOPPED;
...@@ -871,8 +887,9 @@ static int engine_err_handle(struct xdma_engine *engine, ...@@ -871,8 +887,9 @@ static int engine_err_handle(struct xdma_engine *engine,
if (engine->status & XDMA_STAT_BUSY) { if (engine->status & XDMA_STAT_BUSY) {
value = read_register(&engine->regs->status); value = read_register(&engine->regs->status);
if ((value & XDMA_STAT_BUSY)) if ((value & XDMA_STAT_BUSY))
printk_ratelimited(KERN_INFO "%s has errors but is still BUSY\n", printk_ratelimited(KERN_INFO
engine->name); "%s has errors but is still BUSY\n",
engine->name);
} }
printk_ratelimited(KERN_INFO "%s, s 0x%x, aborted xfer 0x%p, cmpl %d/%d\n", printk_ratelimited(KERN_INFO "%s, s 0x%x, aborted xfer 0x%p, cmpl %d/%d\n",
...@@ -908,6 +925,7 @@ engine_service_final_transfer(struct xdma_engine *engine, ...@@ -908,6 +925,7 @@ engine_service_final_transfer(struct xdma_engine *engine,
*pdesc_completed); *pdesc_completed);
return NULL; return NULL;
} }
if (((engine->dir == DMA_FROM_DEVICE) && if (((engine->dir == DMA_FROM_DEVICE) &&
(engine->status & XDMA_STAT_C2H_ERR_MASK)) || (engine->status & XDMA_STAT_C2H_ERR_MASK)) ||
((engine->dir == DMA_TO_DEVICE) && ((engine->dir == DMA_TO_DEVICE) &&
...@@ -925,10 +943,42 @@ engine_service_final_transfer(struct xdma_engine *engine, ...@@ -925,10 +943,42 @@ engine_service_final_transfer(struct xdma_engine *engine,
/* the engine stopped on current transfer? */ /* the engine stopped on current transfer? */
if (*pdesc_completed < transfer->desc_num) { if (*pdesc_completed < transfer->desc_num) {
transfer->state = TRANSFER_STATE_FAILED; if (engine->eop_flush) {
pr_info("%s, xfer 0x%p, stopped half-way, %d/%d.\n", /* check if eop received */
engine->name, transfer, *pdesc_completed, struct xdma_result *result = transfer->res_virt;
transfer->desc_num); int i;
int max = *pdesc_completed;
for (i = 0; i < max; i++) {
if ((result[i].status & RX_STATUS_EOP) != 0) {
transfer->flags |=
XFER_FLAG_ST_C2H_EOP_RCVED;
break;
}
}
transfer->desc_cmpl += *pdesc_completed;
if (!(transfer->flags & XFER_FLAG_ST_C2H_EOP_RCVED)) {
return NULL;
}
/* mark transfer as successfully completed */
engine_service_shutdown(engine);
transfer->state = TRANSFER_STATE_COMPLETED;
engine->desc_dequeued += transfer->desc_cmpl;
} else {
transfer->state = TRANSFER_STATE_FAILED;
pr_info("%s, xfer 0x%p, stopped half-way, %d/%d.\n",
engine->name, transfer, *pdesc_completed,
transfer->desc_num);
/* add dequeued number of descriptors during this run */
engine->desc_dequeued += transfer->desc_num;
transfer->desc_cmpl = *pdesc_completed;
}
} else { } else {
dbg_tfr("engine %s completed transfer\n", engine->name); dbg_tfr("engine %s completed transfer\n", engine->name);
dbg_tfr("Completed transfer ID = 0x%p\n", transfer); dbg_tfr("Completed transfer ID = 0x%p\n", transfer);
...@@ -944,13 +994,14 @@ engine_service_final_transfer(struct xdma_engine *engine, ...@@ -944,13 +994,14 @@ engine_service_final_transfer(struct xdma_engine *engine,
} }
/* mark transfer as successfully completed */ /* mark transfer as successfully completed */
transfer->state = TRANSFER_STATE_COMPLETED; transfer->state = TRANSFER_STATE_COMPLETED;
transfer->desc_cmpl = transfer->desc_num;
/* add dequeued number of descriptors during this run */
engine->desc_dequeued += transfer->desc_num;
} }
transfer_del: transfer_del:
/* remove completed transfer from list */ /* remove completed transfer from list */
list_del(engine->transfer_list.next); list_del(engine->transfer_list.next);
/* add to dequeued number of descriptors during this run */
engine->desc_dequeued += transfer->desc_num;
/* /*
* Complete transfer - sets transfer to NULL if an asynchronous * Complete transfer - sets transfer to NULL if an asynchronous
...@@ -1021,13 +1072,8 @@ static int engine_service_resume(struct xdma_engine *engine) ...@@ -1021,13 +1072,8 @@ static int engine_service_resume(struct xdma_engine *engine)
dbg_tfr("no pending transfers, %s engine stays idle.\n", dbg_tfr("no pending transfers, %s engine stays idle.\n",
engine->name); engine->name);
} }
} else { } else if (list_empty(&engine->transfer_list)) {
/* engine is still running? */ engine_service_shutdown(engine);
if (list_empty(&engine->transfer_list)) {
pr_warn("no queued transfers but %s engine running!\n",
engine->name);
WARN_ON(1);
}
} }
return 0; return 0;
} }
...@@ -1046,23 +1092,18 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback) ...@@ -1046,23 +1092,18 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback)
u32 desc_count = desc_writeback & WB_COUNT_MASK; u32 desc_count = desc_writeback & WB_COUNT_MASK;
u32 err_flag = desc_writeback & WB_ERR_MASK; u32 err_flag = desc_writeback & WB_ERR_MASK;
int rv = 0; int rv = 0;
struct xdma_poll_wb *wb_data;
if (!engine) { if (!engine) {
pr_err("dma engine NULL\n"); pr_err("dma engine NULL\n");
return -EINVAL; return -EINVAL;
} }
/* If polling detected an error, signal to the caller */
if (err_flag)
rv = -1;
/* Service the engine */ /* Service the engine */
if (!engine->running) { if (!engine->running) {
dbg_tfr("Engine was not running!!! Clearing status\n"); dbg_tfr("Engine was not running!!! Clearing status\n");
rv = engine_status_read(engine, 1, 0); rv = engine_status_read(engine, 1, 0);
if (rv < 0) { if (rv < 0) {
pr_err("Failed to read engine status\n"); pr_err("%s failed to read status\n", engine->name);
return rv; return rv;
} }
return 0; return 0;
...@@ -1086,13 +1127,14 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback) ...@@ -1086,13 +1127,14 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback)
* shut down * shut down
*/ */
if ((engine->running && !(engine->status & XDMA_STAT_BUSY)) || if ((engine->running && !(engine->status & XDMA_STAT_BUSY)) ||
(desc_count != 0)) { (!engine->eop_flush && desc_count != 0)) {
rv = engine_service_shutdown(engine); rv = engine_service_shutdown(engine);
if (rv < 0) { if (rv < 0) {
pr_err("Failed to shutdown engine\n"); pr_err("Failed to shutdown engine\n");
return rv; return rv;
} }
} }
/* /*
* If called from the ISR, or if an error occurred, the descriptor * If called from the ISR, or if an error occurred, the descriptor
* count will be zero. In this scenario, read the descriptor count * count will be zero. In this scenario, read the descriptor count
...@@ -1101,7 +1143,12 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback) ...@@ -1101,7 +1143,12 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback)
*/ */
if (!desc_count) if (!desc_count)
desc_count = read_register(&engine->regs->completed_desc_count); desc_count = read_register(&engine->regs->completed_desc_count);
dbg_tfr("desc_count = %d\n", desc_count); dbg_tfr("%s wb 0x%x, desc_count %u, err %u, dequeued %u.\n",
engine->name, desc_writeback, desc_count, err_flag,
engine->desc_dequeued);
if (!desc_count)
goto done;
/* transfers on queue? */ /* transfers on queue? */
if (!list_empty(&engine->transfer_list)) { if (!list_empty(&engine->transfer_list)) {
...@@ -1135,18 +1182,16 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback) ...@@ -1135,18 +1182,16 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback)
*/ */
transfer = engine_service_final_transfer(engine, transfer, &desc_count); transfer = engine_service_final_transfer(engine, transfer, &desc_count);
/* Before starting engine again, clear the writeback data */
if (poll_mode) {
wb_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt;
wb_data->completed_desc_count = 0;
}
/* Restart the engine following the servicing */ /* Restart the engine following the servicing */
rv = engine_service_resume(engine); if (!engine->eop_flush) {
if (rv < 0) rv = engine_service_resume(engine);
pr_err("Failed to resume engine\n"); if (rv < 0)
pr_err("Failed to resume engine\n");
}
return rv; done:
/* If polling detected an error, signal to the caller */
return err_flag ? -1 : 0;
} }
/* engine_service_work */ /* engine_service_work */
...@@ -1214,6 +1259,9 @@ static u32 engine_service_wb_monitor(struct xdma_engine *engine, ...@@ -1214,6 +1259,9 @@ static u32 engine_service_wb_monitor(struct xdma_engine *engine,
while (expected_wb != 0) { while (expected_wb != 0) {
desc_wb = wb_data->completed_desc_count; desc_wb = wb_data->completed_desc_count;
if (desc_wb)
wb_data->completed_desc_count = 0;
if (desc_wb & WB_ERR_MASK) if (desc_wb & WB_ERR_MASK)
break; break;
else if (desc_wb >= expected_wb) else if (desc_wb >= expected_wb)
...@@ -1248,7 +1296,6 @@ static u32 engine_service_wb_monitor(struct xdma_engine *engine, ...@@ -1248,7 +1296,6 @@ static u32 engine_service_wb_monitor(struct xdma_engine *engine,
int engine_service_poll(struct xdma_engine *engine, int engine_service_poll(struct xdma_engine *engine,
u32 expected_desc_count) u32 expected_desc_count)
{ {
struct xdma_poll_wb *writeback_data;
u32 desc_wb = 0; u32 desc_wb = 0;
unsigned long flags; unsigned long flags;
int rv = 0; int rv = 0;
...@@ -1264,13 +1311,6 @@ int engine_service_poll(struct xdma_engine *engine, ...@@ -1264,13 +1311,6 @@ int engine_service_poll(struct xdma_engine *engine,
return -EINVAL; return -EINVAL;
} }
writeback_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt;
if ((expected_desc_count & WB_COUNT_MASK) != expected_desc_count) {
dbg_tfr("Queued descriptor count is larger than supported\n");
return -1;
}
/* /*
* Poll the writeback location for the expected number of * Poll the writeback location for the expected number of
* descriptors / error events This loop is skipped for cyclic mode, * descriptors / error events This loop is skipped for cyclic mode,
...@@ -1279,6 +1319,8 @@ int engine_service_poll(struct xdma_engine *engine, ...@@ -1279,6 +1319,8 @@ int engine_service_poll(struct xdma_engine *engine,
*/ */
desc_wb = engine_service_wb_monitor(engine, expected_desc_count); desc_wb = engine_service_wb_monitor(engine, expected_desc_count);
if (!desc_wb)
return 0;
spin_lock_irqsave(&engine->lock, flags); spin_lock_irqsave(&engine->lock, flags);
dbg_tfr("%s service.\n", engine->name); dbg_tfr("%s service.\n", engine->name);
...@@ -2957,6 +2999,14 @@ static int transfer_init(struct xdma_engine *engine, ...@@ -2957,6 +2999,14 @@ static int transfer_init(struct xdma_engine *engine,
control |= XDMA_DESC_COMPLETED; control |= XDMA_DESC_COMPLETED;
xdma_desc_control_set(xfer->desc_virt + last, control); xdma_desc_control_set(xfer->desc_virt + last, control);
if (engine->eop_flush) {
for (i = 0; i < last; i++)
xdma_desc_control_set(xfer->desc_virt + i,
XDMA_DESC_COMPLETED);
xfer->desc_cmpl_th = 1;
} else
xfer->desc_cmpl_th = desc_max;
xfer->desc_num = desc_max; xfer->desc_num = desc_max;
engine->desc_idx = (engine->desc_idx + desc_max) % engine->desc_idx = (engine->desc_idx + desc_max) %
XDMA_TRANSFER_MAX_DESC; XDMA_TRANSFER_MAX_DESC;
...@@ -3101,7 +3151,6 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, ...@@ -3101,7 +3151,6 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr,
int nents; int nents;
enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
struct xdma_request_cb *req = NULL; struct xdma_request_cb *req = NULL;
struct xdma_result *result;
if (!dev_hndl) if (!dev_hndl)
return -EINVAL; return -EINVAL;
...@@ -3213,34 +3262,16 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, ...@@ -3213,34 +3262,16 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr,
goto unmap_sgl; goto unmap_sgl;
} }
/* if (engine->cmplthp)
* When polling, determine how many descriptors have been queued xdma_kthread_wakeup(engine->cmplthp);
* on the engine to determine the writeback value expected
*/
if (poll_mode) {
unsigned int desc_count;
spin_lock_irqsave(&engine->lock, flags);
desc_count = xfer->desc_num;
spin_unlock_irqrestore(&engine->lock, flags);
dbg_tfr("%s poll desc_count=%d\n", engine->name,
desc_count);
rv = engine_service_poll(engine, desc_count);
if (rv < 0) {
mutex_unlock(&engine->desc_lock);
pr_err("Failed to service polling\n");
goto unmap_sgl;
}
} else { if (timeout_ms > 0)
if (timeout_ms > 0) xlx_wait_event_interruptible_timeout(xfer->wq,
xlx_wait_event_interruptible_timeout(xfer->wq,
(xfer->state != TRANSFER_STATE_SUBMITTED), (xfer->state != TRANSFER_STATE_SUBMITTED),
msecs_to_jiffies(timeout_ms)); msecs_to_jiffies(timeout_ms));
else else
xlx_wait_event_interruptible(xfer->wq, xlx_wait_event_interruptible(xfer->wq,
(xfer->state != TRANSFER_STATE_SUBMITTED)); (xfer->state != TRANSFER_STATE_SUBMITTED));
}
spin_lock_irqsave(&engine->lock, flags); spin_lock_irqsave(&engine->lock, flags);
...@@ -3248,8 +3279,7 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, ...@@ -3248,8 +3279,7 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr,
case TRANSFER_STATE_COMPLETED: case TRANSFER_STATE_COMPLETED:
spin_unlock_irqrestore(&engine->lock, flags); spin_unlock_irqrestore(&engine->lock, flags);
result = xfer->res_virt; rv = 0;
dbg_tfr("transfer %p, %u, ep 0x%llx compl, +%lu.\n", dbg_tfr("transfer %p, %u, ep 0x%llx compl, +%lu.\n",
xfer, xfer->len, req->ep_addr - xfer->len, xfer, xfer->len, req->ep_addr - xfer->len,
done); done);
...@@ -3257,12 +3287,17 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, ...@@ -3257,12 +3287,17 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr,
/* For C2H streaming use writeback results */ /* For C2H streaming use writeback results */
if (engine->streaming && if (engine->streaming &&
engine->dir == DMA_FROM_DEVICE) { engine->dir == DMA_FROM_DEVICE) {
for (i = 0; i < xfer->desc_num; i++) struct xdma_result *result = xfer->res_virt;
for (i = 0; i < xfer->desc_cmpl; i++)
done += result[i].length; done += result[i].length;
/* finish the whole request */
if (engine->eop_flush)
nents = 0;
} else } else
done += xfer->len; done += xfer->len;
rv = 0;
break; break;
case TRANSFER_STATE_FAILED: case TRANSFER_STATE_FAILED:
pr_info("xfer 0x%p,%u, failed, ep 0x%llx.\n", xfer, pr_info("xfer 0x%p,%u, failed, ep 0x%llx.\n", xfer,
...@@ -4053,7 +4088,6 @@ void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max, ...@@ -4053,7 +4088,6 @@ void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max,
xdev->c2h_channel_max = *c2h_channel_max; xdev->c2h_channel_max = *c2h_channel_max;
xdma_device_flag_set(xdev, XDEV_FLAG_OFFLINE); xdma_device_flag_set(xdev, XDEV_FLAG_OFFLINE);
xdev_list_add(xdev);
if (xdev->user_max == 0 || xdev->user_max > MAX_USER_IRQ) if (xdev->user_max == 0 || xdev->user_max > MAX_USER_IRQ)
xdev->user_max = MAX_USER_IRQ; xdev->user_max = MAX_USER_IRQ;
...@@ -4064,6 +4098,10 @@ void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max, ...@@ -4064,6 +4098,10 @@ void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max,
xdev->c2h_channel_max > XDMA_CHANNEL_NUM_MAX) xdev->c2h_channel_max > XDMA_CHANNEL_NUM_MAX)
xdev->c2h_channel_max = XDMA_CHANNEL_NUM_MAX; xdev->c2h_channel_max = XDMA_CHANNEL_NUM_MAX;
rv = xdev_list_add(xdev);
if (rv < 0)
goto free_xdev;
rv = pci_enable_device(pdev); rv = pci_enable_device(pdev);
if (rv) { if (rv) {
dbg_init("pci_enable_device() failed, %d.\n", rv); dbg_init("pci_enable_device() failed, %d.\n", rv);
...@@ -4145,6 +4183,7 @@ err_regions: ...@@ -4145,6 +4183,7 @@ err_regions:
pci_disable_device(pdev); pci_disable_device(pdev);
err_enable: err_enable:
xdev_list_remove(xdev); xdev_list_remove(xdev);
free_xdev:
kfree(xdev); kfree(xdev);
return NULL; return NULL;
} }
......
...@@ -431,6 +431,8 @@ struct sw_desc { ...@@ -431,6 +431,8 @@ struct sw_desc {
}; };
/* Describes a (SG DMA) single transfer for the engine */ /* Describes a (SG DMA) single transfer for the engine */
#define XFER_FLAG_NEED_UNMAP 0x1
#define XFER_FLAG_ST_C2H_EOP_RCVED 0x2 /* ST c2h only */
struct xdma_transfer { struct xdma_transfer {
struct list_head entry; /* queue of non-completed transfers */ struct list_head entry; /* queue of non-completed transfers */
struct xdma_desc *desc_virt; /* virt addr of the 1st descriptor */ struct xdma_desc *desc_virt; /* virt addr of the 1st descriptor */
...@@ -440,6 +442,8 @@ struct xdma_transfer { ...@@ -440,6 +442,8 @@ struct xdma_transfer {
int desc_adjacent; /* adjacent descriptors at desc_bus */ int desc_adjacent; /* adjacent descriptors at desc_bus */
int desc_num; /* number of descriptors in transfer */ int desc_num; /* number of descriptors in transfer */
int desc_index; /* index for 1st desc. in transfer */ int desc_index; /* index for 1st desc. in transfer */
int desc_cmpl; /* completed descriptors */
int desc_cmpl_th; /* completed descriptor threshold */
enum dma_data_direction dir; enum dma_data_direction dir;
#if HAS_SWAKE_UP #if HAS_SWAKE_UP
struct swait_queue_head wq; struct swait_queue_head wq;
...@@ -449,7 +453,6 @@ struct xdma_transfer { ...@@ -449,7 +453,6 @@ struct xdma_transfer {
enum transfer_state state; /* state of the transfer */ enum transfer_state state; /* state of the transfer */
unsigned int flags; unsigned int flags;
#define XFER_FLAG_NEED_UNMAP 0x1
int cyclic; /* flag if transfer is cyclic */ int cyclic; /* flag if transfer is cyclic */
int last_in_request; /* flag if last within request */ int last_in_request; /* flag if last within request */
unsigned int len; unsigned int len;
...@@ -477,8 +480,6 @@ struct xdma_engine { ...@@ -477,8 +480,6 @@ struct xdma_engine {
struct xdma_dev *xdev; /* parent device */ struct xdma_dev *xdev; /* parent device */
char name[16]; /* name of this engine */ char name[16]; /* name of this engine */
int version; /* version of this engine */ int version; /* version of this engine */
//dev_t cdevno; /* character device major:minor */
//struct cdev cdev; /* character device (embedded struct) */
/* HW register address offsets */ /* HW register address offsets */
struct engine_regs *regs; /* Control reg BAR offset */ struct engine_regs *regs; /* Control reg BAR offset */
...@@ -488,14 +489,17 @@ struct xdma_engine { ...@@ -488,14 +489,17 @@ struct xdma_engine {
/* Engine state, configuration and flags */ /* Engine state, configuration and flags */
enum shutdown_state shutdown; /* engine shutdown mode */ enum shutdown_state shutdown; /* engine shutdown mode */
enum dma_data_direction dir; enum dma_data_direction dir;
int device_open; /* flag if engine node open, ST mode only */ u8 addr_align; /* source/dest alignment in bytes */
int running; /* flag if the driver started engine */ u8 len_granularity; /* transfer length multiple */
int non_incr_addr; /* flag if non-incremental addressing used */ u8 addr_bits; /* HW datapath address width */
int streaming; u8 channel:2; /* engine indices */
int addr_align; /* source/dest alignment in bytes */ u8 streaming:1;
int len_granularity; /* transfer length multiple */ u8 device_open:1; /* flag if engine node open, ST mode only */
int addr_bits; /* HW datapath address width */ u8 running:1; /* flag if the driver started engine */
int channel; /* engine indices */ u8 non_incr_addr:1; /* flag if non-incremental addressing used */
u8 eop_flush:1; /* st c2h only, flush up the data with eop */
u8 filler:1;
int max_extra_adj; /* descriptor prefetch capability */ int max_extra_adj; /* descriptor prefetch capability */
int desc_dequeued; /* num descriptors of completed transfers */ int desc_dequeued; /* num descriptors of completed transfers */
u32 status; /* last known status of device */ u32 status; /* last known status of device */
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#define DRV_MOD_MAJOR 2020 #define DRV_MOD_MAJOR 2020
#define DRV_MOD_MINOR 1 #define DRV_MOD_MINOR 1
#define DRV_MOD_PATCHLEVEL 07 #define DRV_MOD_PATCHLEVEL 08
#define DRV_MODULE_VERSION \ #define DRV_MODULE_VERSION \
__stringify(DRV_MOD_MAJOR) "." \ __stringify(DRV_MOD_MAJOR) "." \
......
...@@ -619,8 +619,6 @@ int xdma_cdev_init(void) ...@@ -619,8 +619,6 @@ int xdma_cdev_init(void)
return -ENOMEM; return -ENOMEM;
} }
xdma_threads_create(num_online_cpus());
return 0; return 0;
} }
...@@ -631,6 +629,4 @@ void xdma_cdev_cleanup(void) ...@@ -631,6 +629,4 @@ void xdma_cdev_cleanup(void)
if (g_xdma_class) if (g_xdma_class)
class_destroy(g_xdma_class); class_destroy(g_xdma_class);
xdma_threads_destroy();
} }
...@@ -39,7 +39,7 @@ static int xdma_thread_cmpl_status_pend(struct list_head *work_item) ...@@ -39,7 +39,7 @@ static int xdma_thread_cmpl_status_pend(struct list_head *work_item)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&engine->lock, flags); spin_lock_irqsave(&engine->lock, flags);
pend = !list_empty(&engine->transfer_list); pend = !list_empty(&engine->transfer_list);
spin_unlock_irqrestore(&engine->lock, flags); spin_unlock_irqrestore(&engine->lock, flags);
return pend; return pend;
...@@ -53,12 +53,11 @@ static int xdma_thread_cmpl_status_proc(struct list_head *work_item) ...@@ -53,12 +53,11 @@ static int xdma_thread_cmpl_status_proc(struct list_head *work_item)
engine = list_entry(work_item, struct xdma_engine, cmplthp_list); engine = list_entry(work_item, struct xdma_engine, cmplthp_list);
transfer = list_entry(engine->transfer_list.next, struct xdma_transfer, transfer = list_entry(engine->transfer_list.next, struct xdma_transfer,
entry); entry);
engine_service_poll(engine, transfer->desc_num); if (transfer)
engine_service_poll(engine, transfer->desc_cmpl_th);
return 0; return 0;
} }
static inline int xthread_work_pending(struct xdma_kthread *thp) static inline int xthread_work_pending(struct xdma_kthread *thp)
{ {
struct list_head *work_item, *next; struct list_head *work_item, *next;
...@@ -67,7 +66,6 @@ static inline int xthread_work_pending(struct xdma_kthread *thp) ...@@ -67,7 +66,6 @@ static inline int xthread_work_pending(struct xdma_kthread *thp)
if (list_empty(&thp->work_list)) if (list_empty(&thp->work_list))
return 0; return 0;
/* any work item has pending work to do? */ /* any work item has pending work to do? */
list_for_each_safe(work_item, next, &thp->work_list) { list_for_each_safe(work_item, next, &thp->work_list) {
if (thp->fpending && thp->fpending(work_item)) if (thp->fpending && thp->fpending(work_item))
...@@ -101,7 +99,6 @@ static int xthread_main(void *data) ...@@ -101,7 +99,6 @@ static int xthread_main(void *data)
if (thp->finit) if (thp->finit)
thp->finit(thp); thp->finit(thp);
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
struct list_head *work_item, *next; struct list_head *work_item, *next;
...@@ -150,8 +147,10 @@ int xdma_kthread_start(struct xdma_kthread *thp, char *name, int id) ...@@ -150,8 +147,10 @@ int xdma_kthread_start(struct xdma_kthread *thp, char *name, int id)
} }
len = snprintf(thp->name, sizeof(thp->name), "%s%d", name, id); len = snprintf(thp->name, sizeof(thp->name), "%s%d", name, id);
if (len < 0) if (len < 0) {
pr_err("thread %d, error in snprintf name %s.\n", id, name);
return -EINVAL; return -EINVAL;
}
thp->id = id; thp->id = id;
...@@ -180,7 +179,6 @@ int xdma_kthread_start(struct xdma_kthread *thp, char *name, int id) ...@@ -180,7 +179,6 @@ int xdma_kthread_start(struct xdma_kthread *thp, char *name, int id)
return 0; return 0;
} }
int xdma_kthread_stop(struct xdma_kthread *thp) int xdma_kthread_stop(struct xdma_kthread *thp)
{ {
int rv; int rv;
...@@ -234,8 +232,6 @@ void xdma_thread_remove_work(struct xdma_engine *engine) ...@@ -234,8 +232,6 @@ void xdma_thread_remove_work(struct xdma_engine *engine)
cmpl_thread->work_cnt--; cmpl_thread->work_cnt--;
unlock_thread(cmpl_thread); unlock_thread(cmpl_thread);
} }
} }
void xdma_thread_add_work(struct xdma_engine *engine) void xdma_thread_add_work(struct xdma_engine *engine)
...@@ -275,7 +271,6 @@ void xdma_thread_add_work(struct xdma_engine *engine) ...@@ -275,7 +271,6 @@ void xdma_thread_add_work(struct xdma_engine *engine)
spin_lock_irqsave(&engine->lock, flags); spin_lock_irqsave(&engine->lock, flags);
engine->cmplthp = thp; engine->cmplthp = thp;
spin_unlock_irqrestore(&engine->lock, flags); spin_unlock_irqrestore(&engine->lock, flags);
} }
int xdma_threads_create(unsigned int num_threads) int xdma_threads_create(unsigned int num_threads)
...@@ -289,12 +284,12 @@ int xdma_threads_create(unsigned int num_threads) ...@@ -289,12 +284,12 @@ int xdma_threads_create(unsigned int num_threads)
return 0; return 0;
} }
pr_info("xdma_threads_create\n");
cs_threads = kzalloc(num_threads * sizeof(struct xdma_kthread), cs_threads = kzalloc(num_threads * sizeof(struct xdma_kthread),
GFP_KERNEL); GFP_KERNEL);
if (!cs_threads) if (!cs_threads) {
pr_err("OOM, # threads %u.\n", num_threads);
return -ENOMEM; return -ENOMEM;
}
/* N dma writeback monitoring threads */ /* N dma writeback monitoring threads */
thp = cs_threads; thp = cs_threads;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment