- if (sl->lin_state != SLSTATE_BREAK_SENT)
- remains = sl->tx_lim - sl->tx_cnt;
- else
- remains = SLLIN_BUFF_BREAK + 1 - sl->tx_cnt;
-
- if (remains > 0) {
- actual = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt,
- sl->tx_cnt - sl->tx_lim);
- sl->tx_cnt += actual;
-
- if (sl->tx_cnt < sl->tx_lim) {
- pr_debug("sllin: sllin_write_wakeup sent %d, "
- "remains %d, waiting\n",
- sl->tx_cnt, sl->tx_lim - sl->tx_cnt);
- return;
+ set_bit(SLF_TXBUFF_RQ, &sl->flags);
+ do {
+ if (unlikely(test_and_set_bit(SLF_TXBUFF_INPR, &sl->flags)))
+ return; /* ongoing concurrent processing */
+
+ clear_bit(SLF_TXBUFF_RQ, &sl->flags);
+ smp_mb__after_clear_bit();
+
+ if (sl->lin_state != SLSTATE_BREAK_SENT)
+ remains = sl->tx_lim - sl->tx_cnt;
+ else
+ remains = SLLIN_BUFF_BREAK + 1 - sl->tx_cnt;
+
+ if (remains > 0) {
+ actual = tty->ops->write(tty, sl->tx_buff + sl->tx_cnt,
+ sl->tx_cnt - sl->tx_lim);
+ sl->tx_cnt += actual;
+ remains -= actual;