]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
pps: fix poll support
authorDenis OSTERLAND-HEIM <denis.osterland@diehl.com>
Wed, 28 May 2025 10:57:50 +0000 (12:57 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Jul 2025 10:29:29 +0000 (12:29 +0200)
Because pps_cdev_poll() returns unconditionally EPOLLIN,
a user space program that calls select/poll get always an immediate data
ready-to-read response. As a result the intended use to wait until next
data becomes ready does not work.

User space snippet:

    struct pollfd pollfd = {
      .fd = open("/dev/pps0", O_RDONLY),
      .events = POLLIN|POLLERR,
      .revents = 0 };
    while(1) {
      poll(&pollfd, 1, 2000/*ms*/); // returns immediate, but should wait
      if(revents & EPOLLIN) { // always true
        struct pps_fdata fdata;
        memset(&fdata, 0, sizeof(memdata));
        ioctl(PPS_FETCH, &fdata); // currently fetches data at max speed
      }
    }

Lets remember the last fetch event counter and compare this value
in pps_cdev_poll() with most recent event counter
and return 0 if they are equal.

Signed-off-by: Denis OSTERLAND-HEIM <denis.osterland@diehl.com>
Co-developed-by: Rodolfo Giometti <giometti@enneenne.com>
Signed-off-by: Rodolfo Giometti <giometti@enneenne.com>
Fixes: eae9d2ba0cfc ("LinuxPPS: core support")
Link: https://lore.kernel.org/all/f6bed779-6d59-4f0f-8a59-b6312bd83b4e@enneenne.com/
Acked-by: Rodolfo Giometti <giometti@enneenne.com>
Link: https://lore.kernel.org/r/c3c50ad1eb19ef553eca8a57c17f4c006413ab70.camel@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/pps/pps.c
include/linux/pps_kernel.h

index 6a02245ea35fecce3682622aad88e0b65748d049..9463232af8d2e63dbad81dad689a63a51cd3b4f8 100644 (file)
@@ -41,6 +41,9 @@ static __poll_t pps_cdev_poll(struct file *file, poll_table *wait)
 
        poll_wait(file, &pps->queue, wait);
 
+       if (pps->last_fetched_ev == pps->last_ev)
+               return 0;
+
        return EPOLLIN | EPOLLRDNORM;
 }
 
@@ -186,9 +189,11 @@ static long pps_cdev_ioctl(struct file *file,
                if (err)
                        return err;
 
-               /* Return the fetched timestamp */
+               /* Return the fetched timestamp and save last fetched event  */
                spin_lock_irq(&pps->lock);
 
+               pps->last_fetched_ev = pps->last_ev;
+
                fdata.info.assert_sequence = pps->assert_sequence;
                fdata.info.clear_sequence = pps->clear_sequence;
                fdata.info.assert_tu = pps->assert_tu;
@@ -272,9 +277,11 @@ static long pps_cdev_compat_ioctl(struct file *file,
                if (err)
                        return err;
 
-               /* Return the fetched timestamp */
+               /* Return the fetched timestamp and save last fetched event  */
                spin_lock_irq(&pps->lock);
 
+               pps->last_fetched_ev = pps->last_ev;
+
                compat.info.assert_sequence = pps->assert_sequence;
                compat.info.clear_sequence = pps->clear_sequence;
                compat.info.current_mode = pps->current_mode;
index c7abce28ed29958db487a1bc249966e080a10236..aab0aebb529e02d735789fb2bf9b2be2bfa5a2a7 100644 (file)
@@ -52,6 +52,7 @@ struct pps_device {
        int current_mode;                       /* PPS mode at event time */
 
        unsigned int last_ev;                   /* last PPS event id */
+       unsigned int last_fetched_ev;           /* last fetched PPS event id */
        wait_queue_head_t queue;                /* PPS event queue */
 
        unsigned int id;                        /* PPS source unique ID */