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: Jack Winch <sunt.un.morcov@gmail.com> Signed-off-by: Kent Gibson <warthog618@gmail.com> Link: https://lore.kernel.org/r/20201014231158.34117-2-warthog618@gmail.com Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
committed by
Linus Walleij
parent
93224edf0b
commit
26d060e47e
@@ -509,6 +509,7 @@ struct linereq {
|
|||||||
GPIO_V2_LINE_DIRECTION_FLAGS | \
|
GPIO_V2_LINE_DIRECTION_FLAGS | \
|
||||||
GPIO_V2_LINE_DRIVE_FLAGS | \
|
GPIO_V2_LINE_DRIVE_FLAGS | \
|
||||||
GPIO_V2_LINE_EDGE_FLAGS | \
|
GPIO_V2_LINE_EDGE_FLAGS | \
|
||||||
|
GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME | \
|
||||||
GPIO_V2_LINE_BIAS_FLAGS)
|
GPIO_V2_LINE_BIAS_FLAGS)
|
||||||
|
|
||||||
static void linereq_put_event(struct linereq *lr,
|
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");
|
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)
|
static irqreturn_t edge_irq_thread(int irq, void *p)
|
||||||
{
|
{
|
||||||
struct line *line = 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
|
* which case we didn't get the timestamp from
|
||||||
* edge_irq_handler().
|
* edge_irq_handler().
|
||||||
*/
|
*/
|
||||||
le.timestamp_ns = ktime_get_ns();
|
le.timestamp_ns = line_event_timestamp(line);
|
||||||
if (lr->num_lines != 1)
|
if (lr->num_lines != 1)
|
||||||
line->req_seqno = atomic_inc_return(&lr->seqno);
|
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
|
* Just store the timestamp in hardirq context so we get it as
|
||||||
* close in time as possible to the actual event.
|
* 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)
|
if (lr->num_lines != 1)
|
||||||
line->req_seqno = atomic_inc_return(&lr->seqno);
|
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));
|
memset(&le, 0, sizeof(le));
|
||||||
|
|
||||||
lr = line->req;
|
lr = line->req;
|
||||||
le.timestamp_ns = ktime_get_ns();
|
le.timestamp_ns = line_event_timestamp(line);
|
||||||
le.offset = gpio_chip_hwgpio(line->desc);
|
le.offset = gpio_chip_hwgpio(line->desc);
|
||||||
line->line_seqno++;
|
line->line_seqno++;
|
||||||
le.line_seqno = 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);
|
flags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN);
|
||||||
assign_bit(FLAG_BIAS_DISABLE, flagsp,
|
assign_bit(FLAG_BIAS_DISABLE, flagsp,
|
||||||
flags & GPIO_V2_LINE_FLAG_BIAS_DISABLED);
|
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)
|
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))
|
if (test_bit(FLAG_EDGE_FALLING, &desc->flags))
|
||||||
info->flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
|
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);
|
debounce_period_us = READ_ONCE(desc->debounce_period_us);
|
||||||
if (debounce_period_us) {
|
if (debounce_period_us) {
|
||||||
info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
|
info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ struct gpio_desc {
|
|||||||
#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */
|
#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */
|
||||||
#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */
|
#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */
|
||||||
#define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling 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 */
|
/* Connection label */
|
||||||
const char *label;
|
const char *label;
|
||||||
|
|||||||
@@ -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_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_PULL_DOWN: line has pull-down bias enabled
|
||||||
* @GPIO_V2_LINE_FLAG_BIAS_DISABLED: line has bias disabled
|
* @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 {
|
enum gpio_v2_line_flag {
|
||||||
GPIO_V2_LINE_FLAG_USED = _BITULL(0),
|
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_UP = _BITULL(8),
|
||||||
GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = _BITULL(9),
|
GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = _BITULL(9),
|
||||||
GPIO_V2_LINE_FLAG_BIAS_DISABLED = _BITULL(10),
|
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
|
* struct gpio_v2_line_event - The actual event being pushed to userspace
|
||||||
* @timestamp_ns: best estimate of time of event occurrence, in nanoseconds.
|
* @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
|
* @id: event identifier with value from &enum gpio_v2_line_event_id
|
||||||
* @offset: the offset of the line that triggered the event
|
* @offset: the offset of the line that triggered the event
|
||||||
* @seqno: the sequence number for this event in the sequence of events for
|
* @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
|
* @line_seqno: the sequence number for this event in the sequence of
|
||||||
* events on this particular line
|
* events on this particular line
|
||||||
* @padding: reserved for future use
|
* @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 {
|
struct gpio_v2_line_event {
|
||||||
__aligned_u64 timestamp_ns;
|
__aligned_u64 timestamp_ns;
|
||||||
|
|||||||
Reference in New Issue
Block a user