The bfin-uart code uses real time with struct timeval. This will cause problems on 32-bit architectures in 2038 when time_t overflows. Since the code just needs delta value of time, it is not necessary to record them in real time. This patch changes the code to use the monotonic time instead, replaces do_gettimeofday() and struct timeval with ktime_get() and ktime_t.
Signed-off-by: DengChao chao.deng@linaro.org --- drivers/tty/serial/bfin_uart.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index ae3cf94..abfb988 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -213,7 +213,7 @@ static void bfin_serial_stop_rx(struct uart_port *port) static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { unsigned int status, ch, flg; - static struct timeval anomaly_start = { .tv_sec = 0 }; + static time64_t anomaly_start;
status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); @@ -246,42 +246,40 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) * character time +/- some percent. So 1.5 sounds good. All other * Blackfin families operate properly. Woo. */ - if (anomaly_start.tv_sec) { - struct timeval curr; - suseconds_t usecs; + if (anomaly_start >= NSEC_PER_SEC) { + ktime_t curr; + time64_t nsecs, threshold_ns;
if ((~ch & (~ch + 1)) & 0xff) goto known_good_char;
- do_gettimeofday(&curr); - if (curr.tv_sec - anomaly_start.tv_sec > 1) + curr = ktime_get(); + nsecs = ktime_to_ns(ktime_sub_ns(curr, anomaly_start)); + if (nsecs > NSEC_PER_SEC) goto known_good_char;
- usecs = 0; - if (curr.tv_sec != anomaly_start.tv_sec) - usecs += USEC_PER_SEC; - usecs += curr.tv_usec - anomaly_start.tv_usec; - - if (usecs > UART_GET_ANOMALY_THRESHOLD(uart)) + threshold_ns = UART_GET_ANOMALY_THRESHOLD(uart) + * NSEC_PER_USEC; + if (nsecs > threshold_ns) goto known_good_char;
if (ch) - anomaly_start.tv_sec = 0; + anomaly_start = 0; else - anomaly_start = curr; + anomaly_start = ktime_to_ns(curr);
return;
known_good_char: status &= ~BI; - anomaly_start.tv_sec = 0; + anomaly_start = 0; } }
if (status & BI) { if (ANOMALY_05000363) if (bfin_revid() < 5) - do_gettimeofday(&anomaly_start); + anomaly_start = ktime_to_ns(ktime_get()); uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto ignore_char;
On Monday 02 November 2015 23:04:51 DengChao wrote:
The bfin-uart code uses real time with struct timeval. This will cause problems on 32-bit architectures in 2038 when time_t overflows. Since the code just needs delta value of time, it is not necessary to record them in real time. This patch changes the code to use the monotonic time instead, replaces do_gettimeofday() and struct timeval with ktime_get() and ktime_t.
Signed-off-by: DengChao chao.deng@linaro.org
drivers/tty/serial/bfin_uart.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index ae3cf94..abfb988 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -213,7 +213,7 @@ static void bfin_serial_stop_rx(struct uart_port *port) static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { unsigned int status, ch, flg;
- static struct timeval anomaly_start = { .tv_sec = 0 };
- static time64_t anomaly_start;
status = UART_GET_LSR(uart);
You store a nanosecond value in anomaly_start, so the time64_t type doesn't really apply, as it is meant to store seconds. Better use 'u64' instead.
UART_CLEAR_LSR(uart); @@ -246,42 +246,40 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) * character time +/- some percent. So 1.5 sounds good. All other * Blackfin families operate properly. Woo. */
if (anomaly_start.tv_sec) {
struct timeval curr;
suseconds_t usecs;
if (anomaly_start >= NSEC_PER_SEC) {
ktime_t curr;
time64_t nsecs, threshold_ns;
Same here.
The '>= NSEC_PER_SEC' check will technically do the right thing, but it is a bit misleading, as you are storing an absolute time value in anomaly_start, so it will never be smaller than NSEC_PER_SEC unless it is exactly zero.
if ((~ch & (~ch + 1)) & 0xff) goto known_good_char;
do_gettimeofday(&curr);
if (curr.tv_sec - anomaly_start.tv_sec > 1)
curr = ktime_get();
nsecs = ktime_to_ns(ktime_sub_ns(curr, anomaly_start));
This could be simpler if you use ktime_get_ns().
if (nsecs > NSEC_PER_SEC) goto known_good_char;
Note that this code is an optimization to avoid doing the full comparison with anomaly_threshold, but by converting to a u64, there is very little to gain. Maybe just drop this part and only do the real compare. Alternatively, convert this into a check of the upper 32 bits, followed by a 32-bit comparison with the threshold.
if (status & BI) { if (ANOMALY_05000363) if (bfin_revid() < 5)
do_gettimeofday(&anomaly_start);
uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto ignore_char;anomaly_start = ktime_to_ns(ktime_get());
ktime_get_ns() again.
Arnd