Merge tag 'staging-6.18-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging driver fixes from Greg KH:
 "Here are some staging driver fixes that missed 6.17-final due to my
  travel schedule. They fix a number of reported issues in the axis-fifo
  driver, one of which was just independently discovered by someone else
  today so someone is looking at this code.

  All of these fixes have been in linux-next for many weeks with no
  reported issues"

* tag 'staging-6.18-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging:
  staging: axis-fifo: flush RX FIFO on read errors
  staging: axis-fifo: fix TX handling on copy_from_user() failure
  staging: axis-fifo: fix maximum TX packet length check
This commit is contained in:
Linus Torvalds
2025-10-07 11:41:06 -07:00

View File

@@ -43,7 +43,6 @@
#define DRIVER_NAME "axis_fifo"
#define READ_BUF_SIZE 128U /* read buffer length in words */
#define WRITE_BUF_SIZE 128U /* write buffer length in words */
#define AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN 4
@@ -231,6 +230,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
}
bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET);
words_available = bytes_available / sizeof(u32);
if (!bytes_available) {
dev_err(fifo->dt_device, "received a packet of length 0\n");
ret = -EIO;
@@ -241,7 +241,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n",
bytes_available, len);
ret = -EINVAL;
goto end_unlock;
goto err_flush_rx;
}
if (bytes_available % sizeof(u32)) {
@@ -250,11 +250,9 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
*/
dev_err(fifo->dt_device, "received a packet that isn't word-aligned\n");
ret = -EIO;
goto end_unlock;
goto err_flush_rx;
}
words_available = bytes_available / sizeof(u32);
/* read data into an intermediate buffer, copying the contents
* to userspace when the buffer is full
*/
@@ -266,18 +264,23 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
tmp_buf[i] = ioread32(fifo->base_addr +
XLLF_RDFD_OFFSET);
}
words_available -= copy;
if (copy_to_user(buf + copied * sizeof(u32), tmp_buf,
copy * sizeof(u32))) {
ret = -EFAULT;
goto end_unlock;
goto err_flush_rx;
}
copied += copy;
words_available -= copy;
}
mutex_unlock(&fifo->read_lock);
ret = bytes_available;
return bytes_available;
err_flush_rx:
while (words_available--)
ioread32(fifo->base_addr + XLLF_RDFD_OFFSET);
end_unlock:
mutex_unlock(&fifo->read_lock);
@@ -305,11 +308,8 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
{
struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
unsigned int words_to_write;
unsigned int copied;
unsigned int copy;
unsigned int i;
u32 *txbuf;
int ret;
u32 tmp_buf[WRITE_BUF_SIZE];
if (len % sizeof(u32)) {
dev_err(fifo->dt_device,
@@ -325,11 +325,17 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
return -EINVAL;
}
if (words_to_write > fifo->tx_fifo_depth) {
dev_err(fifo->dt_device, "tried to write more words [%u] than slots in the fifo buffer [%u]\n",
words_to_write, fifo->tx_fifo_depth);
/*
* In 'Store-and-Forward' mode, the maximum packet that can be
* transmitted is limited by the size of the FIFO, which is
* (C_TX_FIFO_DEPTH4)*(data interface width/8) bytes.
*
* Do not attempt to send a packet larger than 'tx_fifo_depth - 4',
* otherwise a 'Transmit Packet Overrun Error' interrupt will be
* raised, which requires a reset of the TX circuit to recover.
*/
if (words_to_write > (fifo->tx_fifo_depth - 4))
return -EINVAL;
}
if (fifo->write_flags & O_NONBLOCK) {
/*
@@ -368,32 +374,20 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
}
}
/* write data from an intermediate buffer into the fifo IP, refilling
* the buffer with userspace data as needed
*/
copied = 0;
while (words_to_write > 0) {
copy = min(words_to_write, WRITE_BUF_SIZE);
if (copy_from_user(tmp_buf, buf + copied * sizeof(u32),
copy * sizeof(u32))) {
ret = -EFAULT;
goto end_unlock;
}
for (i = 0; i < copy; i++)
iowrite32(tmp_buf[i], fifo->base_addr +
XLLF_TDFD_OFFSET);
copied += copy;
words_to_write -= copy;
txbuf = vmemdup_user(buf, len);
if (IS_ERR(txbuf)) {
ret = PTR_ERR(txbuf);
goto end_unlock;
}
ret = copied * sizeof(u32);
for (int i = 0; i < words_to_write; ++i)
iowrite32(txbuf[i], fifo->base_addr + XLLF_TDFD_OFFSET);
/* write packet size to fifo */
iowrite32(ret, fifo->base_addr + XLLF_TLR_OFFSET);
iowrite32(len, fifo->base_addr + XLLF_TLR_OFFSET);
ret = len;
kvfree(txbuf);
end_unlock:
mutex_unlock(&fifo->write_lock);