Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dmitry Kalinkin and committed by
Greg Kroah-Hartman
8e4d138c 1f0622de

+22 -47
+22 -47
drivers/staging/vme/devices/vme_user.c
··· 120 120 atomic_t refcnt; 121 121 }; 122 122 123 - /* 124 - * We are going ot alloc a page during init per window for small transfers. 125 - * Small transfers will go VME -> buffer -> user space. Larger (more than a 126 - * page) transfers will lock the user space buffer into memory and then 127 - * transfer the data directly into the user space buffers. 128 - */ 129 123 static ssize_t resource_to_user(int minor, char __user *buf, size_t count, 130 124 loff_t *ppos) 131 125 { 132 126 ssize_t retval; 133 127 ssize_t copied = 0; 134 128 135 - if (count <= image[minor].size_buf) { 136 - /* We copy to kernel buffer */ 137 - copied = vme_master_read(image[minor].resource, 138 - image[minor].kern_buf, count, *ppos); 139 - if (copied < 0) 140 - return (int)copied; 129 + if (count > image[minor].size_buf) 130 + count = image[minor].size_buf; 141 131 142 - retval = __copy_to_user(buf, image[minor].kern_buf, 143 - (unsigned long)copied); 144 - if (retval != 0) { 145 - copied = (copied - retval); 146 - pr_info("User copy failed\n"); 147 - return -EINVAL; 148 - } 132 + /* We copy to kernel buffer */ 133 + copied = vme_master_read(image[minor].resource, image[minor].kern_buf, 134 + count, *ppos); 135 + if (copied < 0) 136 + return (int)copied; 149 137 150 - } else { 151 - /* XXX Need to write this */ 152 - pr_info("Currently don't support large transfers\n"); 153 - /* Map in pages from userspace */ 154 - 155 - /* Call vme_master_read to do the transfer */ 138 + retval = __copy_to_user(buf, image[minor].kern_buf, 139 + (unsigned long)copied); 140 + if (retval != 0) { 141 + copied = (copied - retval); 142 + pr_info("User copy failed\n"); 156 143 return -EINVAL; 157 144 } 158 145 159 146 return copied; 160 147 } 161 148 162 - /* 163 - * We are going to alloc a page during init per window for small transfers. 164 - * Small transfers will go user space -> buffer -> VME. Larger (more than a 165 - * page) transfers will lock the user space buffer into memory and then 166 - * transfer the data directly from the user space buffers out to VME. 167 - */ 168 149 static ssize_t resource_from_user(unsigned int minor, const char __user *buf, 169 150 size_t count, loff_t *ppos) 170 151 { 171 152 ssize_t retval; 172 153 ssize_t copied = 0; 173 154 174 - if (count <= image[minor].size_buf) { 175 - retval = __copy_from_user(image[minor].kern_buf, buf, 176 - (unsigned long)count); 177 - if (retval != 0) 178 - copied = (copied - retval); 179 - else 180 - copied = count; 155 + if (count > image[minor].size_buf) 156 + count = image[minor].size_buf; 181 157 182 - copied = vme_master_write(image[minor].resource, 183 - image[minor].kern_buf, copied, *ppos); 184 - } else { 185 - /* XXX Need to write this */ 186 - pr_info("Currently don't support large transfers\n"); 187 - /* Map in pages from userspace */ 158 + retval = __copy_from_user(image[minor].kern_buf, buf, 159 + (unsigned long)count); 160 + if (retval != 0) 161 + copied = (copied - retval); 162 + else 163 + copied = count; 188 164 189 - /* Call vme_master_write to do the transfer */ 190 - return -EINVAL; 191 - } 165 + copied = vme_master_write(image[minor].resource, image[minor].kern_buf, 166 + copied, *ppos); 192 167 193 168 return copied; 194 169 }