mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 13:30:45 -05:00
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:
@@ -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_DEPTH–4)*(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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user