]> git.karo-electronics.de Git - linux-beck.git/commitdiff
staging/fwserial: Rip out rx buffering
authorPeter Hurley <peter@hurleysoftware.com>
Fri, 22 Nov 2013 18:06:08 +0000 (13:06 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 9 Dec 2013 01:03:03 +0000 (17:03 -0800)
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/fwserial/fwserial.c
drivers/staging/fwserial/fwserial.h
drivers/tty/tty_buffer.c

index 62df009e5ac7c8e9bcd5779bf57e9b8c1d2c309d..ed7806b8b1dc2eb4c8ebdaa162e95b08e994adff 100644 (file)
@@ -456,16 +456,27 @@ static int fwtty_write_port_status(struct fwtty_port *port)
        return err;
 }
 
-static void __fwtty_throttle(struct fwtty_port *port, struct tty_struct *tty)
+static void fwtty_throttle_port(struct fwtty_port *port)
 {
+       struct tty_struct *tty;
        unsigned old;
 
+       tty = tty_port_tty_get(&port->port);
+       if (!tty)
+               return;
+
+       spin_lock_bh(&port->lock);
+
        old = port->mctrl;
        port->mctrl |= OOB_RX_THROTTLE;
        if (C_CRTSCTS(tty))
                port->mctrl &= ~TIOCM_RTS;
        if (~old & OOB_RX_THROTTLE)
                __fwtty_write_port_status(port);
+
+       spin_unlock_bh(&port->lock);
+
+       tty_kref_put(tty);
 }
 
 /**
@@ -532,74 +543,8 @@ static void fwtty_emit_breaks(struct work_struct *work)
        port->icount.brk += brk;
 }
 
-static void fwtty_pushrx(struct work_struct *work)
-{
-       struct fwtty_port *port = to_port(work, push);
-       struct tty_struct *tty;
-       struct buffered_rx *buf, *next;
-       int n, c = 0;
-
-       spin_lock_bh(&port->lock);
-       list_for_each_entry_safe(buf, next, &port->buf_list, list) {
-               n = tty_insert_flip_string_fixed_flag(&port->port, buf->data,
-                                                     TTY_NORMAL, buf->n);
-               c += n;
-               port->buffered -= n;
-               if (n < buf->n) {
-                       if (n > 0) {
-                               memmove(buf->data, buf->data + n, buf->n - n);
-                               buf->n -= n;
-                       }
-                       tty = tty_port_tty_get(&port->port);
-                       if (tty) {
-                               __fwtty_throttle(port, tty);
-                               tty_kref_put(tty);
-                       }
-                       break;
-               } else {
-                       list_del(&buf->list);
-                       kfree(buf);
-               }
-       }
-       if (c > 0)
-               tty_flip_buffer_push(&port->port);
-
-       if (list_empty(&port->buf_list))
-               clear_bit(BUFFERING_RX, &port->flags);
-       spin_unlock_bh(&port->lock);
-}
-
-static int fwtty_buffer_rx(struct fwtty_port *port, unsigned char *d, size_t n)
-{
-       struct buffered_rx *buf;
-       size_t size = (n + sizeof(struct buffered_rx) + 0xFF) & ~0xFF;
-
-       if (port->buffered + n > HIGH_WATERMARK) {
-               fwtty_err_ratelimited(port, "overflowed rx buffer: buffered: %d new: %zu wtrmk: %d\n",
-                                     port->buffered, n, HIGH_WATERMARK);
-               return 0;
-       }
-       buf = kmalloc(size, GFP_ATOMIC);
-       if (!buf)
-               return 0;
-       INIT_LIST_HEAD(&buf->list);
-       buf->n = n;
-       memcpy(buf->data, d, n);
-
-       spin_lock_bh(&port->lock);
-       list_add_tail(&buf->list, &port->buf_list);
-       port->buffered += n;
-       if (port->buffered > port->stats.watermark)
-               port->stats.watermark = port->buffered;
-       set_bit(BUFFERING_RX, &port->flags);
-       spin_unlock_bh(&port->lock);
-
-       return n;
-}
-
 static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
 {
-       struct tty_struct *tty;
        int c, n = len;
        unsigned lsr;
        int err = 0;
@@ -636,31 +581,24 @@ static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
                goto out;
        }
 
-       if (!test_bit(BUFFERING_RX, &port->flags)) {
-               c = tty_insert_flip_string_fixed_flag(&port->port, data,
-                               TTY_NORMAL, n);
-               if (c > 0)
-                       tty_flip_buffer_push(&port->port);
-               n -= c;
-
-               if (n) {
-                       /* start buffering and throttling */
-                       n -= fwtty_buffer_rx(port, &data[c], n);
-
-                       tty = tty_port_tty_get(&port->port);
-                       if (tty) {
-                               spin_lock_bh(&port->lock);
-                               __fwtty_throttle(port, tty);
-                               spin_unlock_bh(&port->lock);
-                               tty_kref_put(tty);
-                       }
-               }
-       } else
-               n -= fwtty_buffer_rx(port, data, n);
+       c = tty_insert_flip_string_fixed_flag(&port->port, data, TTY_NORMAL, n);
+       if (c > 0)
+               tty_flip_buffer_push(&port->port);
+       n -= c;
 
        if (n) {
                port->overrun = true;
                err = -EIO;
+               fwtty_err_ratelimited(port, "flip buffer overrun\n");
+
+       } else {
+               /* throttle the sender if remaining flip buffer space has
+                * reached high watermark to avoid losing data which may be
+                * in-flight. Since the AR request context is 32k, that much
+                * data may have _already_ been acked.
+                */
+               if (tty_buffer_space_avail(&port->port) < HIGH_WATERMARK)
+                       fwtty_throttle_port(port);
        }
 
 out:
@@ -1101,20 +1039,13 @@ static int fwtty_port_activate(struct tty_port *tty_port,
 static void fwtty_port_shutdown(struct tty_port *tty_port)
 {
        struct fwtty_port *port = to_port(tty_port, port);
-       struct buffered_rx *buf, *next;
 
        /* TODO: cancel outstanding transactions */
 
        cancel_delayed_work_sync(&port->emit_breaks);
        cancel_delayed_work_sync(&port->drain);
-       cancel_work_sync(&port->push);
 
        spin_lock_bh(&port->lock);
-       list_for_each_entry_safe(buf, next, &port->buf_list, list) {
-               list_del(&buf->list);
-               kfree(buf);
-       }
-       port->buffered = 0;
        port->flags = 0;
        port->break_ctl = 0;
        port->overrun = 0;
@@ -1264,8 +1195,6 @@ static void fwtty_unthrottle(struct tty_struct *tty)
 
        profile_fifo_avail(port, port->stats.unthrottle);
 
-       schedule_work(&port->push);
-
        spin_lock_bh(&port->lock);
        port->mctrl &= ~OOB_RX_THROTTLE;
        if (C_CRTSCTS(tty))
@@ -1523,8 +1452,7 @@ static void fwtty_debugfs_show_port(struct seq_file *m, struct fwtty_port *port)
 
        seq_printf(m, " dr:%d st:%d err:%d lost:%d", stats.dropped,
                   stats.tx_stall, stats.fifo_errs, stats.lost);
-       seq_printf(m, " pkts:%d thr:%d wtrmk:%d", stats.sent, stats.throttled,
-                  stats.watermark);
+       seq_printf(m, " pkts:%d thr:%d", stats.sent, stats.throttled);
 
        if (port->port.console) {
                seq_puts(m, "\n    ");
@@ -2302,8 +2230,6 @@ static int fwserial_create(struct fw_unit *unit)
                INIT_DELAYED_WORK(&port->drain, fwtty_drain_tx);
                INIT_DELAYED_WORK(&port->emit_breaks, fwtty_emit_breaks);
                INIT_WORK(&port->hangup, fwtty_do_hangup);
-               INIT_WORK(&port->push, fwtty_pushrx);
-               INIT_LIST_HEAD(&port->buf_list);
                init_waitqueue_head(&port->wait_tx);
                port->max_payload = link_speed_to_max_payload(SCODE_100);
                dma_fifo_init(&port->tx_fifo);
index 24635014a2acdad232634248794e41eff2450ffa..149b24dd0ba6e416a5625a6e30e0dc83818260a4 100644 (file)
@@ -166,7 +166,6 @@ struct stats {
        unsigned        sent;
        unsigned        lost;
        unsigned        throttled;
-       unsigned        watermark;
        unsigned        reads[DISTRIBUTION_MAX_INDEX + 1];
        unsigned        writes[DISTRIBUTION_MAX_INDEX + 1];
        unsigned        txns[DISTRIBUTION_MAX_INDEX + 1];
@@ -183,12 +182,6 @@ struct fwconsole_ops {
 #define FWCON_NOTIFY_ATTACH            1
 #define FWCON_NOTIFY_DETACH            2
 
-struct buffered_rx {
-       struct list_head        list;
-       size_t                  n;
-       unsigned char           data[0];
-};
-
 /**
  * fwtty_port: structure used to track/represent underlying tty_port
  * @port: underlying tty_port
@@ -223,11 +216,6 @@ struct buffered_rx {
  *         The work can race with the writer but concurrent sending is
  *         prevented with the IN_TX flag. Scheduled under lock to
  *         limit scheduling when fifo has just been drained.
- * @push: work responsible for pushing buffered rx to the ldisc.
- *       rx can become buffered if the tty buffer is filled before the
- *       ldisc throttles the sender.
- * @buf_list: list of buffered rx yet to be sent to ldisc
- * @buffered: byte count of buffered rx
  * @tx_fifo: fifo used to store & block-up writes for dma to remote
  * @max_payload: max bytes transmissable per dma (based on peer's max_payload)
  * @status_mask: UART_LSR_* bitmask significant to rx (based on termios)
@@ -267,9 +255,6 @@ struct fwtty_port {
        spinlock_t                 lock;
        unsigned                   mctrl;
        struct delayed_work        drain;
-       struct work_struct         push;
-       struct list_head           buf_list;
-       int                        buffered;
        struct dma_fifo            tx_fifo;
        int                        max_payload;
        unsigned                   status_mask;
@@ -291,7 +276,6 @@ struct fwtty_port {
 /* bit #s for flags field */
 #define IN_TX                      0
 #define STOP_TX                    1
-#define BUFFERING_RX              2
 
 /* bitmasks for special mctrl/mstatus bits */
 #define OOB_RX_THROTTLE   0x00010000
index 6a3620e1cc7aa119687a8a2acce41d6ac7fe4b9e..6454c0a747ef935805e84e921a954529e5b9d76c 100644 (file)
@@ -92,6 +92,7 @@ int tty_buffer_space_avail(struct tty_port *port)
        int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);
        return max(space, 0);
 }
+EXPORT_SYMBOL_GPL(tty_buffer_space_avail);
 
 static void tty_buffer_reset(struct tty_buffer *p, size_t size)
 {