Skip to content

Commit fbd2e22

Browse files
committed
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
2 parents 3d15d6c + 82a051e commit fbd2e22

1 file changed

Lines changed: 31 additions & 37 deletions

File tree

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

Lines changed: 31 additions & 37 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

@@ -231,6 +230,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
231230
}
232231

233232
bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET);
233+
words_available = bytes_available / sizeof(u32);
234234
if (!bytes_available) {
235235
dev_err(fifo->dt_device, "received a packet of length 0\n");
236236
ret = -EIO;
@@ -241,7 +241,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
241241
dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n",
242242
bytes_available, len);
243243
ret = -EINVAL;
244-
goto end_unlock;
244+
goto err_flush_rx;
245245
}
246246

247247
if (bytes_available % sizeof(u32)) {
@@ -250,11 +250,9 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
250250
*/
251251
dev_err(fifo->dt_device, "received a packet that isn't word-aligned\n");
252252
ret = -EIO;
253-
goto end_unlock;
253+
goto err_flush_rx;
254254
}
255255

256-
words_available = bytes_available / sizeof(u32);
257-
258256
/* read data into an intermediate buffer, copying the contents
259257
* to userspace when the buffer is full
260258
*/
@@ -266,18 +264,23 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
266264
tmp_buf[i] = ioread32(fifo->base_addr +
267265
XLLF_RDFD_OFFSET);
268266
}
267+
words_available -= copy;
269268

270269
if (copy_to_user(buf + copied * sizeof(u32), tmp_buf,
271270
copy * sizeof(u32))) {
272271
ret = -EFAULT;
273-
goto end_unlock;
272+
goto err_flush_rx;
274273
}
275274

276275
copied += copy;
277-
words_available -= copy;
278276
}
277+
mutex_unlock(&fifo->read_lock);
278+
279+
return bytes_available;
279280

280-
ret = bytes_available;
281+
err_flush_rx:
282+
while (words_available--)
283+
ioread32(fifo->base_addr + XLLF_RDFD_OFFSET);
281284

282285
end_unlock:
283286
mutex_unlock(&fifo->read_lock);
@@ -305,11 +308,8 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
305308
{
306309
struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
307310
unsigned int words_to_write;
308-
unsigned int copied;
309-
unsigned int copy;
310-
unsigned int i;
311+
u32 *txbuf;
311312
int ret;
312-
u32 tmp_buf[WRITE_BUF_SIZE];
313313

314314
if (len % sizeof(u32)) {
315315
dev_err(fifo->dt_device,
@@ -325,11 +325,17 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
325325
return -EINVAL;
326326
}
327327

328-
if (words_to_write > fifo->tx_fifo_depth) {
329-
dev_err(fifo->dt_device, "tried to write more words [%u] than slots in the fifo buffer [%u]\n",
330-
words_to_write, fifo->tx_fifo_depth);
328+
/*
329+
* In 'Store-and-Forward' mode, the maximum packet that can be
330+
* transmitted is limited by the size of the FIFO, which is
331+
* (C_TX_FIFO_DEPTH–4)*(data interface width/8) bytes.
332+
*
333+
* Do not attempt to send a packet larger than 'tx_fifo_depth - 4',
334+
* otherwise a 'Transmit Packet Overrun Error' interrupt will be
335+
* raised, which requires a reset of the TX circuit to recover.
336+
*/
337+
if (words_to_write > (fifo->tx_fifo_depth - 4))
331338
return -EINVAL;
332-
}
333339

334340
if (fifo->write_flags & O_NONBLOCK) {
335341
/*
@@ -368,32 +374,20 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
368374
}
369375
}
370376

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

392-
ret = copied * sizeof(u32);
383+
for (int i = 0; i < words_to_write; ++i)
384+
iowrite32(txbuf[i], fifo->base_addr + XLLF_TDFD_OFFSET);
393385

394386
/* write packet size to fifo */
395-
iowrite32(ret, fifo->base_addr + XLLF_TLR_OFFSET);
387+
iowrite32(len, fifo->base_addr + XLLF_TLR_OFFSET);
396388

389+
ret = len;
390+
kvfree(txbuf);
397391
end_unlock:
398392
mutex_unlock(&fifo->write_lock);
399393

0 commit comments

Comments
 (0)