Commit 26d060e4 authored by Kent Gibson's avatar Kent Gibson Committed by Linus Walleij
Browse files

gpiolib: cdev: allow edge event timestamps to be configured as REALTIME



Using CLOCK_REALTIME as the source for event timestamps is crucial for
some specific applications, particularly those requiring timetamps
relative to a PTP clock, so provide an option to switch the event
timestamp source from the default CLOCK_MONOTONIC to CLOCK_REALTIME.

Note that CLOCK_REALTIME was the default source clock for GPIO until
Linux 5.7 when it was changed to CLOCK_MONOTONIC due to issues with the
shifting of the realtime clock.
Providing this option maintains the CLOCK_MONOTONIC as the default,
while also providing a path forward for those dependent on the pre-5.7
behaviour.

Suggested-by: default avatarJack Winch <sunt.un.morcov@gmail.com>
Signed-off-by: default avatarKent Gibson <warthog618@gmail.com>
Link: https://lore.kernel.org/r/20201014231158.34117-2-warthog618@gmail.com


Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 93224edf
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -509,6 +509,7 @@ struct linereq {
	 GPIO_V2_LINE_DIRECTION_FLAGS | \
	 GPIO_V2_LINE_DRIVE_FLAGS | \
	 GPIO_V2_LINE_EDGE_FLAGS | \
	 GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME | \
	 GPIO_V2_LINE_BIAS_FLAGS)

static void linereq_put_event(struct linereq *lr,
@@ -529,6 +530,14 @@ static void linereq_put_event(struct linereq *lr,
		pr_debug_ratelimited("event FIFO is full - event dropped\n");
}

static u64 line_event_timestamp(struct line *line)
{
	if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags))
		return ktime_get_real_ns();

	return ktime_get_ns();
}

static irqreturn_t edge_irq_thread(int irq, void *p)
{
	struct line *line = p;
@@ -546,7 +555,7 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
		 * which case we didn't get the timestamp from
		 * edge_irq_handler().
		 */
		le.timestamp_ns = ktime_get_ns();
		le.timestamp_ns = line_event_timestamp(line);
		if (lr->num_lines != 1)
			line->req_seqno = atomic_inc_return(&lr->seqno);
	}
@@ -590,7 +599,7 @@ static irqreturn_t edge_irq_handler(int irq, void *p)
	 * Just store the timestamp in hardirq context so we get it as
	 * close in time as possible to the actual event.
	 */
	line->timestamp_ns = ktime_get_ns();
	line->timestamp_ns = line_event_timestamp(line);

	if (lr->num_lines != 1)
		line->req_seqno = atomic_inc_return(&lr->seqno);
@@ -663,7 +672,7 @@ static void debounce_work_func(struct work_struct *work)
	memset(&le, 0, sizeof(le));

	lr = line->req;
	le.timestamp_ns = ktime_get_ns();
	le.timestamp_ns = line_event_timestamp(line);
	le.offset = gpio_chip_hwgpio(line->desc);
	line->line_seqno++;
	le.line_seqno = line->line_seqno;
@@ -967,6 +976,9 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 flags,
		   flags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN);
	assign_bit(FLAG_BIAS_DISABLE, flagsp,
		   flags & GPIO_V2_LINE_FLAG_BIAS_DISABLED);

	assign_bit(FLAG_EVENT_CLOCK_REALTIME, flagsp,
		   flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME);
}

static long linereq_get_values(struct linereq *lr, void __user *ip)
@@ -1930,6 +1942,9 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
	if (test_bit(FLAG_EDGE_FALLING, &desc->flags))
		info->flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;

	if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags))
		info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;

	debounce_period_us = READ_ONCE(desc->debounce_period_us);
	if (debounce_period_us) {
		info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
+1 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ struct gpio_desc {
#define FLAG_BIAS_DISABLE    15	/* GPIO has pull disabled */
#define FLAG_EDGE_RISING     16	/* GPIO CDEV detects rising edge events */
#define FLAG_EDGE_FALLING    17	/* GPIO CDEV detects falling edge events */
#define FLAG_EVENT_CLOCK_REALTIME	18 /* GPIO CDEV reports REALTIME timestamps in events */

	/* Connection label */
	const char		*label;
+9 −3
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ struct gpiochip_info {
 * @GPIO_V2_LINE_FLAG_BIAS_PULL_UP: line has pull-up bias enabled
 * @GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN: line has pull-down bias enabled
 * @GPIO_V2_LINE_FLAG_BIAS_DISABLED: line has bias disabled
 * @GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME: line events contain REALTIME timestamps
 */
enum gpio_v2_line_flag {
	GPIO_V2_LINE_FLAG_USED			= _BITULL(0),
@@ -78,6 +79,7 @@ enum gpio_v2_line_flag {
	GPIO_V2_LINE_FLAG_BIAS_PULL_UP		= _BITULL(8),
	GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN	= _BITULL(9),
	GPIO_V2_LINE_FLAG_BIAS_DISABLED		= _BITULL(10),
	GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME	= _BITULL(11),
};

/**
@@ -270,9 +272,6 @@ enum gpio_v2_line_event_id {
/**
 * struct gpio_v2_line_event - The actual event being pushed to userspace
 * @timestamp_ns: best estimate of time of event occurrence, in nanoseconds.
 * The @timestamp_ns is read from %CLOCK_MONOTONIC and is intended to allow
 * the accurate measurement of the time between events. It does not provide
 * the wall-clock time.
 * @id: event identifier with value from &enum gpio_v2_line_event_id
 * @offset: the offset of the line that triggered the event
 * @seqno: the sequence number for this event in the sequence of events for
@@ -280,6 +279,13 @@ enum gpio_v2_line_event_id {
 * @line_seqno: the sequence number for this event in the sequence of
 * events on this particular line
 * @padding: reserved for future use
 *
 * By default the @timestamp_ns is read from %CLOCK_MONOTONIC and is
 * intended to allow the accurate measurement of the time between events.
 * It does not provide the wall-clock time.
 *
 * If the %GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME flag is set then the
 * @timestamp_ns is read from %CLOCK_REALTIME.
 */
struct gpio_v2_line_event {
	__aligned_u64 timestamp_ns;