From: Alexander Stein Date: Mon, 16 Dec 2013 07:54:05 +0000 (+0100) Subject: sllin: If length is unknown read until timer occurs or break is received X-Git-Url: http://rtime.felk.cvut.cz/gitweb/linux-lin.git/commitdiff_plain/4d395daeab8a91e2eb519fba8b213a84f33d1ea0 sllin: If length is unknown read until timer occurs or break is received If the length is unknown stop waiting for new data until the tty rx queue is empty once is not working on fast systems where sllin_receive_buf is called for each byte received. Instead wait up to 8 bytes, when the timeout occurs or when a new break is received. Signed-off-by: Alexander Stein --- diff --git a/sllin/sllin.c b/sllin/sllin.c index e8aca08..36f23a5 100644 --- a/sllin/sllin.c +++ b/sllin/sllin.c @@ -670,6 +670,23 @@ static int sllin_rx_validate(struct sllin *sl) return 0; } +static void sllin_slave_finish_rx_msg(struct sllin *sl) +{ + if (sllin_rx_validate(sl) == -1) { + netdev_dbg(sl->dev, "sllin: RX validation failed.\n"); + sllin_report_error(sl, LIN_ERR_CHECKSUM); + } else { + /* Send CAN non-RTR frame with data */ + netdev_dbg(sl->dev, "sllin: sending NON-RTR CAN frame with LIN payload."); + sll_bump(sl); /* send packet to the network layer */ + } + /* Prepare for reception of new header */ + sl->rx_cnt = 0; + sl->rx_expect = SLLIN_BUFF_ID + 1; + sl->rx_len_unknown = false; /* We do know exact length of the header */ + sl->header_received = false; +} + static void sllin_slave_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { @@ -681,6 +698,20 @@ static void sllin_slave_receive_buf(struct tty_struct *tty, /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { + /* + * If we don't know the length of the current message + * we received the break of the next message. + * Evaluate the previous one before continuing + */ + if (sl->rx_len_unknown == true) + { + hrtimer_cancel(&sl->rx_timer); + sllin_slave_finish_rx_msg(sl); + + set_bit(SLF_RXEVENT, &sl->flags); + wake_up(&sl->kwt_wq); + } + netdev_dbg(sl->dev, "sllin_slave_receive_buf char 0x%02x ignored " "due marker 0x%02x, flags 0x%lx\n", *cp, *(fp-1), sl->flags); @@ -736,25 +767,23 @@ static void sllin_slave_receive_buf(struct tty_struct *tty, sl->header_received = true; + hrtimer_start(&sl->rx_timer, + ktime_add(ktime_get(), sl->rx_timer_timeout), + HRTIMER_MODE_ABS); sll_send_rtr(sl); continue; } /* Response received */ if ((sl->header_received == true) && - ((sl->rx_cnt >= sl->rx_expect) || - ((sl->rx_len_unknown == true) && (count == 0)))) { + ((sl->rx_cnt >= sl->rx_expect))) { - sll_bump(sl); + hrtimer_cancel(&sl->rx_timer); netdev_dbg(sl->dev, "Received LIN header & LIN response. " "rx_cnt = %u, rx_expect = %u\n", sl->rx_cnt, sl->rx_expect); + sllin_slave_finish_rx_msg(sl); - /* Prepare for reception of new header */ - sl->rx_cnt = 0; - sl->rx_expect = SLLIN_BUFF_ID + 1; - sl->rx_len_unknown = false; /* We do know exact length of the header */ - sl->header_received = false; } } } @@ -905,8 +934,13 @@ static enum hrtimer_restart sllin_rx_timeout_handler(struct hrtimer *hrtimer) { struct sllin *sl = container_of(hrtimer, struct sllin, rx_timer); - sllin_report_error(sl, LIN_ERR_RX_TIMEOUT); - set_bit(SLF_TMOUTEVENT, &sl->flags); + if (sl->lin_master) { + sllin_report_error(sl, LIN_ERR_RX_TIMEOUT); + set_bit(SLF_TMOUTEVENT, &sl->flags); + } else { + sllin_slave_finish_rx_msg(sl); + set_bit(SLF_RXEVENT, &sl->flags); + } wake_up(&sl->kwt_wq); return HRTIMER_NORESTART;