Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pps: fix poll support

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>

authored by

Denis OSTERLAND-HEIM and committed by
Greg Kroah-Hartman
12c409aa 6bca1e95

+10 -2
+9 -2
drivers/pps/pps.c
··· 41 41 42 42 poll_wait(file, &pps->queue, wait); 43 43 44 + if (pps->last_fetched_ev == pps->last_ev) 45 + return 0; 46 + 44 47 return EPOLLIN | EPOLLRDNORM; 45 48 } 46 49 ··· 189 186 if (err) 190 187 return err; 191 188 192 - /* Return the fetched timestamp */ 189 + /* Return the fetched timestamp and save last fetched event */ 193 190 spin_lock_irq(&pps->lock); 191 + 192 + pps->last_fetched_ev = pps->last_ev; 194 193 195 194 fdata.info.assert_sequence = pps->assert_sequence; 196 195 fdata.info.clear_sequence = pps->clear_sequence; ··· 277 272 if (err) 278 273 return err; 279 274 280 - /* Return the fetched timestamp */ 275 + /* Return the fetched timestamp and save last fetched event */ 281 276 spin_lock_irq(&pps->lock); 277 + 278 + pps->last_fetched_ev = pps->last_ev; 282 279 283 280 compat.info.assert_sequence = pps->assert_sequence; 284 281 compat.info.clear_sequence = pps->clear_sequence;
+1
include/linux/pps_kernel.h
··· 52 52 int current_mode; /* PPS mode at event time */ 53 53 54 54 unsigned int last_ev; /* last PPS event id */ 55 + unsigned int last_fetched_ev; /* last fetched PPS event id */ 55 56 wait_queue_head_t queue; /* PPS event queue */ 56 57 57 58 unsigned int id; /* PPS source unique ID */