Skip to content

Commit 6d07bee

Browse files
ovpanaitgregkh
authored andcommitted
staging: axis-fifo: fix TX handling on copy_from_user() failure
If copy_from_user() fails, write() currently returns -EFAULT, but any partially written data leaves the TX FIFO in an inconsistent state. Subsequent write() calls then fail with "transmit length mismatch" errors. Once partial data is written to the hardware FIFO, it cannot be removed without a TX reset. Commit c6e8d85 ("staging: axis-fifo: Remove hardware resets for user errors") removed a full FIFO reset for this case, which fixed a potential RX data loss, but introduced this TX issue. Fix this by introducing a bounce buffer: copy the full packet from userspace first, and write to the hardware FIFO only if the copy was successful. Fixes: c6e8d85 ("staging: axis-fifo: Remove hardware resets for user errors") Cc: stable@vger.kernel.org Signed-off-by: Ovidiu Panait <ovidiu.panait.oss@gmail.com> Link: https://lore.kernel.org/r/20250912101322.1282507-1-ovidiu.panait.oss@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 52ff2b8 commit 6d07bee

File tree

1 file changed

+10
-26
lines changed

1 file changed

+10
-26
lines changed

drivers/staging/axis-fifo/axis-fifo.c

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
#define DRIVER_NAME "axis_fifo"
4444

4545
#define READ_BUF_SIZE 128U /* read buffer length in words */
46-
#define WRITE_BUF_SIZE 128U /* write buffer length in words */
4746

4847
#define AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN 4
4948

@@ -302,11 +301,8 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
302301
{
303302
struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
304303
unsigned int words_to_write;
305-
unsigned int copied;
306-
unsigned int copy;
307-
unsigned int i;
304+
u32 *txbuf;
308305
int ret;
309-
u32 tmp_buf[WRITE_BUF_SIZE];
310306

311307
if (len % sizeof(u32)) {
312308
dev_err(fifo->dt_device,
@@ -371,32 +367,20 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
371367
}
372368
}
373369

374-
/* write data from an intermediate buffer into the fifo IP, refilling
375-
* the buffer with userspace data as needed
376-
*/
377-
copied = 0;
378-
while (words_to_write > 0) {
379-
copy = min(words_to_write, WRITE_BUF_SIZE);
380-
381-
if (copy_from_user(tmp_buf, buf + copied * sizeof(u32),
382-
copy * sizeof(u32))) {
383-
ret = -EFAULT;
384-
goto end_unlock;
385-
}
386-
387-
for (i = 0; i < copy; i++)
388-
iowrite32(tmp_buf[i], fifo->base_addr +
389-
XLLF_TDFD_OFFSET);
390-
391-
copied += copy;
392-
words_to_write -= copy;
370+
txbuf = vmemdup_user(buf, len);
371+
if (IS_ERR(txbuf)) {
372+
ret = PTR_ERR(txbuf);
373+
goto end_unlock;
393374
}
394375

395-
ret = copied * sizeof(u32);
376+
for (int i = 0; i < words_to_write; ++i)
377+
iowrite32(txbuf[i], fifo->base_addr + XLLF_TDFD_OFFSET);
396378

397379
/* write packet size to fifo */
398-
iowrite32(ret, fifo->base_addr + XLLF_TLR_OFFSET);
380+
iowrite32(len, fifo->base_addr + XLLF_TLR_OFFSET);
399381

382+
ret = len;
383+
kvfree(txbuf);
400384
end_unlock:
401385
mutex_unlock(&fifo->write_lock);
402386

0 commit comments

Comments
 (0)