staging: vme_user: allow large read()/write()

This changes large master transfers to do shorter read/write rather than
return -EINVAL. User space will now be able to optimistically request a
large transfer and get at least some data.

This also removes comments suggesting on how to implement large
transfers. Current vme_master_* read and write implementations use CPU
copies that don't produce burst PCI accesses and subsequently no block
transfer on VME bus. In the end overall performance is quiet low and it
can't be fixed by doing direct copy to user space. Much easier solution
would be to just reuse kernel buffer.

Signed-off-by: Dmitry Kalinkin <dmitry.kalinkin@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Dmitry Kalinkin 2015-06-26 23:39:40 +03:00 committed by Greg Kroah-Hartman
parent 1f0622de0d
commit 8e4d138cc0

View File

@ -120,75 +120,50 @@ struct vme_user_vma_priv {
atomic_t refcnt;
};
/*
* We are going ot alloc a page during init per window for small transfers.
* Small transfers will go VME -> buffer -> user space. Larger (more than a
* page) transfers will lock the user space buffer into memory and then
* transfer the data directly into the user space buffers.
*/
static ssize_t resource_to_user(int minor, char __user *buf, size_t count,
loff_t *ppos)
{
ssize_t retval;
ssize_t copied = 0;
if (count <= image[minor].size_buf) {
/* We copy to kernel buffer */
copied = vme_master_read(image[minor].resource,
image[minor].kern_buf, count, *ppos);
if (copied < 0)
return (int)copied;
if (count > image[minor].size_buf)
count = image[minor].size_buf;
retval = __copy_to_user(buf, image[minor].kern_buf,
(unsigned long)copied);
if (retval != 0) {
copied = (copied - retval);
pr_info("User copy failed\n");
return -EINVAL;
}
/* We copy to kernel buffer */
copied = vme_master_read(image[minor].resource, image[minor].kern_buf,
count, *ppos);
if (copied < 0)
return (int)copied;
} else {
/* XXX Need to write this */
pr_info("Currently don't support large transfers\n");
/* Map in pages from userspace */
/* Call vme_master_read to do the transfer */
retval = __copy_to_user(buf, image[minor].kern_buf,
(unsigned long)copied);
if (retval != 0) {
copied = (copied - retval);
pr_info("User copy failed\n");
return -EINVAL;
}
return copied;
}
/*
* We are going to alloc a page during init per window for small transfers.
* Small transfers will go user space -> buffer -> VME. Larger (more than a
* page) transfers will lock the user space buffer into memory and then
* transfer the data directly from the user space buffers out to VME.
*/
static ssize_t resource_from_user(unsigned int minor, const char __user *buf,
size_t count, loff_t *ppos)
{
ssize_t retval;
ssize_t copied = 0;
if (count <= image[minor].size_buf) {
retval = __copy_from_user(image[minor].kern_buf, buf,
(unsigned long)count);
if (retval != 0)
copied = (copied - retval);
else
copied = count;
if (count > image[minor].size_buf)
count = image[minor].size_buf;
copied = vme_master_write(image[minor].resource,
image[minor].kern_buf, copied, *ppos);
} else {
/* XXX Need to write this */
pr_info("Currently don't support large transfers\n");
/* Map in pages from userspace */
retval = __copy_from_user(image[minor].kern_buf, buf,
(unsigned long)count);
if (retval != 0)
copied = (copied - retval);
else
copied = count;
/* Call vme_master_write to do the transfer */
return -EINVAL;
}
copied = vme_master_write(image[minor].resource, image[minor].kern_buf,
copied, *ppos);
return copied;
}