Skip to content

Commit 0443b3f

Browse files
Quentin Deslandesgregkh
authored andcommitted
staging: axis-fifo: replace spinlock with mutex
Following the device's documentation guidance, reading a packet from the device or writing a packet to it must be atomic. Previously, only reading device's vacancy (before writing on it) or occupancy (before reading from it) was locked. Hence, effectively reading the packet or writing the packet wasn't locked at all. However, reading a packet (and writing one, to a lesser extent) requires to read 3 different registers in a specific order, without missing one or else we should reset the device. This patch fixes the device's locking mechanism on the FIFO character device. As the device was using copy_from_user() and copy_to_user(), we need to replace spinlocks with mutexes. Signed-off-by: Quentin Deslandes <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b17028d commit 0443b3f

File tree

1 file changed

+101
-59
lines changed

1 file changed

+101
-59
lines changed

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

Lines changed: 101 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#include <linux/kernel.h>
1818
#include <linux/wait.h>
19-
#include <linux/spinlock_types.h>
19+
#include <linux/mutex.h>
2020
#include <linux/device.h>
2121
#include <linux/cdev.h>
2222
#include <linux/init.h>
@@ -133,9 +133,9 @@ struct axis_fifo {
133133
int has_tx_fifo; /* whether the IP has the tx fifo enabled */
134134

135135
wait_queue_head_t read_queue; /* wait queue for asynchronos read */
136-
spinlock_t read_queue_lock; /* lock for reading waitqueue */
136+
struct mutex read_lock; /* lock for reading */
137137
wait_queue_head_t write_queue; /* wait queue for asynchronos write */
138-
spinlock_t write_queue_lock; /* lock for writing waitqueue */
138+
struct mutex write_lock; /* lock for writing */
139139
unsigned int write_flags; /* write file flags */
140140
unsigned int read_flags; /* read file flags */
141141

@@ -336,7 +336,21 @@ static void reset_ip_core(struct axis_fifo *fifo)
336336
iowrite32(XLLF_INT_ALL_MASK, fifo->base_addr + XLLF_ISR_OFFSET);
337337
}
338338

339-
/* reads a single packet from the fifo as dictated by the tlast signal */
339+
/**
340+
* axis_fifo_write() - Read a packet from AXIS-FIFO character device.
341+
* @f Open file.
342+
* @buf User space buffer to read to.
343+
* @len User space buffer length.
344+
* @off Buffer offset.
345+
*
346+
* As defined by the device's documentation, we need to check the device's
347+
* occupancy before reading the length register and then the data. All these
348+
* operations must be executed atomically, in order and one after the other
349+
* without missing any.
350+
*
351+
* Returns the number of bytes read from the device or negative error code
352+
* on failure.
353+
*/
340354
static ssize_t axis_fifo_read(struct file *f, char __user *buf,
341355
size_t len, loff_t *off)
342356
{
@@ -350,51 +364,54 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
350364
u32 tmp_buf[READ_BUF_SIZE];
351365

352366
if (fifo->read_flags & O_NONBLOCK) {
353-
/* opened in non-blocking mode
354-
* return if there are no packets available
367+
/*
368+
* Device opened in non-blocking mode. Try to lock it and then
369+
* check if any packet is available.
355370
*/
356-
if (!ioread32(fifo->base_addr + XLLF_RDFO_OFFSET))
371+
if (!mutex_trylock(&fifo->read_lock))
357372
return -EAGAIN;
373+
374+
if (!ioread32(fifo->base_addr + XLLF_RDFO_OFFSET)) {
375+
ret = -EAGAIN;
376+
goto end_unlock;
377+
}
358378
} else {
359379
/* opened in blocking mode
360380
* wait for a packet available interrupt (or timeout)
361381
* if nothing is currently available
362382
*/
363-
spin_lock_irq(&fifo->read_queue_lock);
364-
ret = wait_event_interruptible_lock_irq_timeout
365-
(fifo->read_queue,
366-
ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
367-
fifo->read_queue_lock,
368-
(read_timeout >= 0) ? msecs_to_jiffies(read_timeout) :
383+
mutex_lock(&fifo->read_lock);
384+
ret = wait_event_interruptible_timeout(fifo->read_queue,
385+
ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
386+
(read_timeout >= 0) ? msecs_to_jiffies(read_timeout) :
369387
MAX_SCHEDULE_TIMEOUT);
370-
spin_unlock_irq(&fifo->read_queue_lock);
371388

372-
if (ret == 0) {
373-
/* timeout occurred */
374-
dev_dbg(fifo->dt_device, "read timeout");
375-
return -EAGAIN;
376-
} else if (ret == -ERESTARTSYS) {
377-
/* signal received */
378-
return -ERESTARTSYS;
379-
} else if (ret < 0) {
380-
dev_err(fifo->dt_device, "wait_event_interruptible_timeout() error in read (ret=%i)\n",
381-
ret);
382-
return ret;
389+
if (ret <= 0) {
390+
if (ret == 0) {
391+
ret = -EAGAIN;
392+
} else if (ret != -ERESTARTSYS) {
393+
dev_err(fifo->dt_device, "wait_event_interruptible_timeout() error in read (ret=%i)\n",
394+
ret);
395+
}
396+
397+
goto end_unlock;
383398
}
384399
}
385400

386401
bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET);
387402
if (!bytes_available) {
388403
dev_err(fifo->dt_device, "received a packet of length 0 - fifo core will be reset\n");
389404
reset_ip_core(fifo);
390-
return -EIO;
405+
ret = -EIO;
406+
goto end_unlock;
391407
}
392408

393409
if (bytes_available > len) {
394410
dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu) - fifo core will be reset\n",
395411
bytes_available, len);
396412
reset_ip_core(fifo);
397-
return -EINVAL;
413+
ret = -EINVAL;
414+
goto end_unlock;
398415
}
399416

400417
if (bytes_available % sizeof(u32)) {
@@ -403,7 +420,8 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
403420
*/
404421
dev_err(fifo->dt_device, "received a packet that isn't word-aligned - fifo core will be reset\n");
405422
reset_ip_core(fifo);
406-
return -EIO;
423+
ret = -EIO;
424+
goto end_unlock;
407425
}
408426

409427
words_available = bytes_available / sizeof(u32);
@@ -423,16 +441,37 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
423441
if (copy_to_user(buf + copied * sizeof(u32), tmp_buf,
424442
copy * sizeof(u32))) {
425443
reset_ip_core(fifo);
426-
return -EFAULT;
444+
ret = -EFAULT;
445+
goto end_unlock;
427446
}
428447

429448
copied += copy;
430449
words_available -= copy;
431450
}
432451

433-
return bytes_available;
452+
ret = bytes_available;
453+
454+
end_unlock:
455+
mutex_unlock(&fifo->read_lock);
456+
457+
return ret;
434458
}
435459

460+
/**
461+
* axis_fifo_write() - Write buffer to AXIS-FIFO character device.
462+
* @f Open file.
463+
* @buf User space buffer to write to the device.
464+
* @len User space buffer length.
465+
* @off Buffer offset.
466+
*
467+
* As defined by the device's documentation, we need to write to the device's
468+
* data buffer then to the device's packet length register atomically. Also,
469+
* we need to lock before checking if the device has available space to avoid
470+
* any concurrency issue.
471+
*
472+
* Returns the number of bytes written to the device or negative error code
473+
* on failure.
474+
*/
436475
static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
437476
size_t len, loff_t *off)
438477
{
@@ -465,43 +504,40 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
465504
}
466505

467506
if (fifo->write_flags & O_NONBLOCK) {
468-
/* opened in non-blocking mode
469-
* return if there is not enough room available in the fifo
507+
/*
508+
* Device opened in non-blocking mode. Try to lock it and then
509+
* check if there is any room to write the given buffer.
470510
*/
511+
if (!mutex_trylock(&fifo->write_lock))
512+
return -EAGAIN;
513+
471514
if (words_to_write > ioread32(fifo->base_addr +
472515
XLLF_TDFV_OFFSET)) {
473-
return -EAGAIN;
516+
ret = -EAGAIN;
517+
goto end_unlock;
474518
}
475519
} else {
476520
/* opened in blocking mode */
477521

478522
/* wait for an interrupt (or timeout) if there isn't
479523
* currently enough room in the fifo
480524
*/
481-
spin_lock_irq(&fifo->write_queue_lock);
482-
ret = wait_event_interruptible_lock_irq_timeout
483-
(fifo->write_queue,
484-
ioread32(fifo->base_addr + XLLF_TDFV_OFFSET)
525+
mutex_lock(&fifo->write_lock);
526+
ret = wait_event_interruptible_timeout(fifo->write_queue,
527+
ioread32(fifo->base_addr + XLLF_TDFV_OFFSET)
485528
>= words_to_write,
486-
fifo->write_queue_lock,
487-
(write_timeout >= 0) ?
488-
msecs_to_jiffies(write_timeout) :
529+
(write_timeout >= 0) ? msecs_to_jiffies(write_timeout) :
489530
MAX_SCHEDULE_TIMEOUT);
490-
spin_unlock_irq(&fifo->write_queue_lock);
491531

492-
if (ret == 0) {
493-
/* timeout occurred */
494-
dev_dbg(fifo->dt_device, "write timeout\n");
495-
return -EAGAIN;
496-
} else if (ret == -ERESTARTSYS) {
497-
/* signal received */
498-
return -ERESTARTSYS;
499-
} else if (ret < 0) {
500-
/* unknown error */
501-
dev_err(fifo->dt_device,
502-
"wait_event_interruptible_timeout() error in write (ret=%i)\n",
503-
ret);
504-
return ret;
532+
if (ret <= 0) {
533+
if (ret == 0) {
534+
ret = -EAGAIN;
535+
} else if (ret != -ERESTARTSYS) {
536+
dev_err(fifo->dt_device, "wait_event_interruptible_timeout() error in write (ret=%i)\n",
537+
ret);
538+
}
539+
540+
goto end_unlock;
505541
}
506542
}
507543

@@ -515,7 +551,8 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
515551
if (copy_from_user(tmp_buf, buf + copied * sizeof(u32),
516552
copy * sizeof(u32))) {
517553
reset_ip_core(fifo);
518-
return -EFAULT;
554+
ret = -EFAULT;
555+
goto end_unlock;
519556
}
520557

521558
for (i = 0; i < copy; i++)
@@ -526,10 +563,15 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
526563
words_to_write -= copy;
527564
}
528565

566+
ret = copied * sizeof(u32);
567+
529568
/* write packet size to fifo */
530-
iowrite32(copied * sizeof(u32), fifo->base_addr + XLLF_TLR_OFFSET);
569+
iowrite32(ret, fifo->base_addr + XLLF_TLR_OFFSET);
570+
571+
end_unlock:
572+
mutex_unlock(&fifo->write_lock);
531573

532-
return (ssize_t)copied * sizeof(u32);
574+
return ret;
533575
}
534576

535577
static irqreturn_t axis_fifo_irq(int irq, void *dw)
@@ -789,8 +831,8 @@ static int axis_fifo_probe(struct platform_device *pdev)
789831
init_waitqueue_head(&fifo->read_queue);
790832
init_waitqueue_head(&fifo->write_queue);
791833

792-
spin_lock_init(&fifo->read_queue_lock);
793-
spin_lock_init(&fifo->write_queue_lock);
834+
mutex_init(&fifo->read_lock);
835+
mutex_init(&fifo->write_lock);
794836

795837
/* ----------------------------
796838
* init device memory space

0 commit comments

Comments
 (0)