#define ELM327_READY_CHAR '>'
/* Bits in elm->cmds_todo */
-enum ELM327_TX_DO_BITS {
+enum elm327_to_to_do_bits {
ELM327_TX_DO_CAN_DATA = 0,
ELM327_TX_DO_CANID_11BIT,
ELM327_TX_DO_CANID_29BIT_LOW,
/* Per-channel lock */
spinlock_t lock;
- /* Stop the channel on hardware failure.
+ /* Stop the channel on UART side hardware failure, e.g. stray
+ * characters or neverending lines. This may be caused by bad
+ * UART wiring, a bad ELM327, a bad UART bridge...
* Once this is true, nothing will be sent to the TTY.
*/
- bool hw_failure;
+ bool uart_side_failure;
/* TTY TX helpers */
struct work_struct tx_work; /* Flushes TTY TX buffer */
unsigned long cmds_todo;
};
-static inline void elm327_hw_failure(struct elmcan *elm);
+static inline void elm327_uart_side_failure(struct elmcan *elm);
static void elm327_send(struct elmcan *elm, const void *buf, size_t len)
{
lockdep_assert_held(elm->lock);
- if (elm->hw_failure)
+ if (elm->uart_side_failure)
return;
memcpy(elm->txbuf, buf, len);
netdev_err(elm->dev,
"Failed to write to tty %s.\n",
elm->tty->name);
- elm327_hw_failure(elm);
+ elm327_uart_side_failure(elm);
return;
}
}
/* Called when we're out of ideas and just want it all to end. */
-static inline void elm327_hw_failure(struct elmcan *elm)
+static inline void elm327_uart_side_failure(struct elmcan *elm)
{
struct can_frame *frame;
struct sk_buff *skb;
lockdep_assert_held(elm->lock);
- elm->hw_failure = true;
+ elm->uart_side_failure = true;
elm->can.can_stats.bus_off++;
netif_stop_queue(elm->dev);
*/
netdev_err(elm->dev,
"RX buffer overflow. Faulty ELM327 or UART?\n");
- elm327_hw_failure(elm);
+ elm327_uart_side_failure(elm);
break;
} else if (len == elm->rxfill) {
if (elm327_is_ready_char(elm->rxbuf[elm->rxfill - 1])) {
int err;
spin_lock_bh(&elm->lock);
- if (elm->hw_failure) {
- netdev_err(elm->dev, "Refusing to open interface after a hardware fault has been detected.\n");
- spin_unlock_bh(&elm->lock);
- return -EIO;
- }
if (!elm->tty) {
spin_unlock_bh(&elm->lock);
return -ENODEV;
}
+ if (elm->uart_side_failure)
+ netdev_warn(elm->dev, "Reopening netdev after a UART side fault has been detected.\n");
+
+ /* Clear TTY buffers */
+ elm->rxfill = 0;
+ elm->txleft = 0;
+
/* open_candev() checks for elm->can.bittiming.bitrate != 0 */
err = open_candev(dev);
if (err) {
{
struct elmcan *elm = netdev_priv(dev);
- netif_stop_queue(dev);
-
+ /* Interrupt whatever the ELM327 is doing right now */
spin_lock_bh(&elm->lock);
- if (elm->tty) {
- /* Interrupt whatever we're doing right now */
- elm327_send(elm, ELM327_DUMMY_STRING, 1);
-
- /* Clear the wakeup bit, as the netdev will be down and thus
- * the wakeup handler won't clear it
- */
- clear_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
+ elm327_send(elm, ELM327_DUMMY_STRING, 1);
+ spin_unlock_bh(&elm->lock);
- spin_unlock_bh(&elm->lock);
+ /* Give UART one final chance to flush.
+ * This may netif_wake_queue(), so don't netif_stop_queue()
+ * before flushing the worker.
+ */
+ clear_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
+ flush_work(&elm->tx_work);
- flush_work(&elm->tx_work);
- } else {
- spin_unlock_bh(&elm->lock);
- }
+ netif_stop_queue(dev);
can_rx_offload_disable(&elm->offload);
elm->can.state = CAN_STATE_STOPPED;
/* We shouldn't get here after a hardware fault:
* can_bus_off() calls netif_carrier_off()
*/
- WARN_ON_ONCE(elm->hw_failure);
+ WARN_ON_ONCE(elm->uart_side_failure);
if (!elm->tty ||
- elm->hw_failure ||
+ elm->uart_side_failure ||
elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
spin_unlock(&elm->lock);
goto out;
spin_lock_bh(&elm->lock);
- if (elm->hw_failure)
+ if (elm->uart_side_failure)
goto out;
while (count-- && elm->rxfill < ELM327_SIZE_RXBUF) {
if (fp && *fp++) {
netdev_err(elm->dev, "Error in received character stream. Check your wiring.");
- elm327_hw_failure(elm);
+ elm327_uart_side_failure(elm);
goto out;
}
netdev_err(elm->dev,
"Received illegal character %02x.\n",
*cp);
- elm327_hw_failure(elm);
+ elm327_uart_side_failure(elm);
goto out;
}
if (count >= 0) {
netdev_err(elm->dev, "Receive buffer overflowed. Bad chip or wiring?");
- elm327_hw_failure(elm);
+ elm327_uart_side_failure(elm);
goto out;
}
struct elmcan *elm = container_of(work, struct elmcan, tx_work);
ssize_t written;
- if (elm->hw_failure)
+ if (elm->uart_side_failure)
return;
spin_lock_bh(&elm->lock);
netdev_err(elm->dev,
"Failed to write to tty %s.\n",
elm->tty->name);
- elm327_hw_failure(elm);
+ elm327_uart_side_failure(elm);
spin_unlock_bh(&elm->lock);
return;
} else {
/* Configure TTY interface */
tty->receive_room = 65536; /* We don't flow control */
- elm->txleft = 0; /* Clear TTY TX buffer */
spin_lock_init(&elm->lock);
INIT_WORK(&elm->tx_work, elmcan_ldisc_tx_worker);
{
struct elmcan *elm = (struct elmcan *)tty->disc_data;
- /* unregister_netdev() calls .ndo_stop() so we don't have to. */
+ /* unregister_netdev() calls .ndo_stop() so we don't have to.
+ * Our .ndo_stop() also flushes the TTY write wakeup handler,
+ * so we can safely set elm->tty = NULL after this.
+ */
unregister_candev(elm->dev);
- /* Ensure that our worker won't be rescheduled */
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- flush_work(&elm->tx_work);
-
/* Mark channel as dead */
spin_lock_bh(&elm->lock);
tty->disc_data = NULL;