Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / tty / cyclades.c
index b09c8d1f9a662d50f1eed1520a5f51104a4c43f0..345bd0e0884ef73439be07a4d81741bd7a78732e 100644 (file)
@@ -441,7 +441,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
                void __iomem *base_addr)
 {
        struct cyclades_port *info;
-       struct tty_struct *tty;
+       struct tty_port *port;
        int len, index = cinfo->bus_index;
        u8 ivr, save_xir, channel, save_car, data, char_count;
 
@@ -452,22 +452,11 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
        save_xir = readb(base_addr + (CyRIR << index));
        channel = save_xir & CyIRChannel;
        info = &cinfo->ports[channel + chip * 4];
+       port = &info->port;
        save_car = cyy_readb(info, CyCAR);
        cyy_writeb(info, CyCAR, save_xir);
        ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
 
-       tty = tty_port_tty_get(&info->port);
-       /* if there is nowhere to put the data, discard it */
-       if (tty == NULL) {
-               if (ivr == CyIVRRxEx) { /* exception */
-                       data = cyy_readb(info, CyRDSR);
-               } else {        /* normal character reception */
-                       char_count = cyy_readb(info, CyRDCR);
-                       while (char_count--)
-                               data = cyy_readb(info, CyRDSR);
-               }
-               goto end;
-       }
        /* there is an open port for this data */
        if (ivr == CyIVRRxEx) { /* exception */
                data = cyy_readb(info, CyRDSR);
@@ -484,40 +473,45 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
 
                if (data & info->ignore_status_mask) {
                        info->icount.rx++;
-                       tty_kref_put(tty);
                        return;
                }
-               if (tty_buffer_request_room(tty, 1)) {
+               if (tty_buffer_request_room(port, 1)) {
                        if (data & info->read_status_mask) {
                                if (data & CyBREAK) {
-                                       tty_insert_flip_char(tty,
+                                       tty_insert_flip_char(port,
                                                cyy_readb(info, CyRDSR),
                                                TTY_BREAK);
                                        info->icount.rx++;
-                                       if (info->port.flags & ASYNC_SAK)
-                                               do_SAK(tty);
+                                       if (port->flags & ASYNC_SAK) {
+                                               struct tty_struct *tty =
+                                                       tty_port_tty_get(port);
+                                               if (tty) {
+                                                       do_SAK(tty);
+                                                       tty_kref_put(tty);
+                                               }
+                                       }
                                } else if (data & CyFRAME) {
-                                       tty_insert_flip_char(tty,
+                                       tty_insert_flip_char(port,
                                                cyy_readb(info, CyRDSR),
                                                TTY_FRAME);
                                        info->icount.rx++;
                                        info->idle_stats.frame_errs++;
                                } else if (data & CyPARITY) {
                                        /* Pieces of seven... */
-                                       tty_insert_flip_char(tty,
+                                       tty_insert_flip_char(port,
                                                cyy_readb(info, CyRDSR),
                                                TTY_PARITY);
                                        info->icount.rx++;
                                        info->idle_stats.parity_errs++;
                                } else if (data & CyOVERRUN) {
-                                       tty_insert_flip_char(tty, 0,
+                                       tty_insert_flip_char(port, 0,
                                                        TTY_OVERRUN);
                                        info->icount.rx++;
                                        /* If the flip buffer itself is
                                           overflowing, we still lose
                                           the next incoming character.
                                         */
-                                       tty_insert_flip_char(tty,
+                                       tty_insert_flip_char(port,
                                                cyy_readb(info, CyRDSR),
                                                TTY_FRAME);
                                        info->icount.rx++;
@@ -527,12 +521,12 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
                                /* } else if(data & CyTIMEOUT) { */
                                /* } else if(data & CySPECHAR) { */
                                } else {
-                                       tty_insert_flip_char(tty, 0,
+                                       tty_insert_flip_char(port, 0,
                                                        TTY_NORMAL);
                                        info->icount.rx++;
                                }
                        } else {
-                               tty_insert_flip_char(tty, 0, TTY_NORMAL);
+                               tty_insert_flip_char(port, 0, TTY_NORMAL);
                                info->icount.rx++;
                        }
                } else {
@@ -552,10 +546,10 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
                        info->mon.char_max = char_count;
                info->mon.char_last = char_count;
 #endif
-               len = tty_buffer_request_room(tty, char_count);
+               len = tty_buffer_request_room(port, char_count);
                while (len--) {
                        data = cyy_readb(info, CyRDSR);
-                       tty_insert_flip_char(tty, data, TTY_NORMAL);
+                       tty_insert_flip_char(port, data, TTY_NORMAL);
                        info->idle_stats.recv_bytes++;
                        info->icount.rx++;
 #ifdef CY_16Y_HACK
@@ -564,9 +558,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
                }
                info->idle_stats.recv_idle = jiffies;
        }
-       tty_schedule_flip(tty);
-       tty_kref_put(tty);
-end:
+       tty_schedule_flip(port);
+
        /* end of service */
        cyy_writeb(info, CyRIR, save_xir & 0x3f);
        cyy_writeb(info, CyCAR, save_car);
@@ -924,10 +917,11 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
        return 0;
 }                              /* cyz_issue_cmd */
 
-static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
+static void cyz_handle_rx(struct cyclades_port *info)
 {
        struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
        struct cyclades_card *cinfo = info->card;
+       struct tty_port *port = &info->port;
        unsigned int char_count;
        int len;
 #ifdef BLOCKMOVE
@@ -946,80 +940,77 @@ static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
        else
                char_count = rx_put - rx_get + rx_bufsize;
 
-       if (char_count) {
+       if (!char_count)
+               return;
+
 #ifdef CY_ENABLE_MONITORING
-               info->mon.int_count++;
-               info->mon.char_count += char_count;
-               if (char_count > info->mon.char_max)
-                       info->mon.char_max = char_count;
-               info->mon.char_last = char_count;
+       info->mon.int_count++;
+       info->mon.char_count += char_count;
+       if (char_count > info->mon.char_max)
+               info->mon.char_max = char_count;
+       info->mon.char_last = char_count;
 #endif
-               if (tty == NULL) {
-                       /* flush received characters */
-                       new_rx_get = (new_rx_get + char_count) &
-                                       (rx_bufsize - 1);
-                       info->rflush_count++;
-               } else {
+
 #ifdef BLOCKMOVE
-               /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
-                  for performance, but because of buffer boundaries, there
-                  may be several steps to the operation */
-                       while (1) {
-                               len = tty_prepare_flip_string(tty, &buf,
-                                               char_count);
-                               if (!len)
-                                       break;
+       /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+          for performance, but because of buffer boundaries, there
+          may be several steps to the operation */
+       while (1) {
+               len = tty_prepare_flip_string(port, &buf,
+                               char_count);
+               if (!len)
+                       break;
 
-                               len = min_t(unsigned int, min(len, char_count),
-                                               rx_bufsize - new_rx_get);
+               len = min_t(unsigned int, min(len, char_count),
+                               rx_bufsize - new_rx_get);
 
-                               memcpy_fromio(buf, cinfo->base_addr +
-                                               rx_bufaddr + new_rx_get, len);
+               memcpy_fromio(buf, cinfo->base_addr +
+                               rx_bufaddr + new_rx_get, len);
 
-                               new_rx_get = (new_rx_get + len) &
-                                               (rx_bufsize - 1);
-                               char_count -= len;
-                               info->icount.rx += len;
-                               info->idle_stats.recv_bytes += len;
-                       }
+               new_rx_get = (new_rx_get + len) &
+                               (rx_bufsize - 1);
+               char_count -= len;
+               info->icount.rx += len;
+               info->idle_stats.recv_bytes += len;
+       }
 #else
-                       len = tty_buffer_request_room(tty, char_count);
-                       while (len--) {
-                               data = readb(cinfo->base_addr + rx_bufaddr +
-                                               new_rx_get);
-                               new_rx_get = (new_rx_get + 1) &
-                                                       (rx_bufsize - 1);
-                               tty_insert_flip_char(tty, data, TTY_NORMAL);
-                               info->idle_stats.recv_bytes++;
-                               info->icount.rx++;
-                       }
+       len = tty_buffer_request_room(port, char_count);
+       while (len--) {
+               data = readb(cinfo->base_addr + rx_bufaddr +
+                               new_rx_get);
+               new_rx_get = (new_rx_get + 1) &
+                                       (rx_bufsize - 1);
+               tty_insert_flip_char(port, data, TTY_NORMAL);
+               info->idle_stats.recv_bytes++;
+               info->icount.rx++;
+       }
 #endif
 #ifdef CONFIG_CYZ_INTR
-               /* Recalculate the number of chars in the RX buffer and issue
-                  a cmd in case it's higher than the RX high water mark */
-                       rx_put = readl(&buf_ctrl->rx_put);
-                       if (rx_put >= rx_get)
-                               char_count = rx_put - rx_get;
-                       else
-                               char_count = rx_put - rx_get + rx_bufsize;
-                       if (char_count >= readl(&buf_ctrl->rx_threshold) &&
-                                       !timer_pending(&cyz_rx_full_timer[
-                                                       info->line]))
-                               mod_timer(&cyz_rx_full_timer[info->line],
-                                               jiffies + 1);
+       /* Recalculate the number of chars in the RX buffer and issue
+          a cmd in case it's higher than the RX high water mark */
+       rx_put = readl(&buf_ctrl->rx_put);
+       if (rx_put >= rx_get)
+               char_count = rx_put - rx_get;
+       else
+               char_count = rx_put - rx_get + rx_bufsize;
+       if (char_count >= readl(&buf_ctrl->rx_threshold) &&
+                       !timer_pending(&cyz_rx_full_timer[
+                                       info->line]))
+               mod_timer(&cyz_rx_full_timer[info->line],
+                               jiffies + 1);
 #endif
-                       info->idle_stats.recv_idle = jiffies;
-                       tty_schedule_flip(tty);
-               }
-               /* Update rx_get */
-               cy_writel(&buf_ctrl->rx_get, new_rx_get);
-       }
+       info->idle_stats.recv_idle = jiffies;
+       tty_schedule_flip(&info->port);
+
+       /* Update rx_get */
+       cy_writel(&buf_ctrl->rx_get, new_rx_get);
 }
 
-static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
+static void cyz_handle_tx(struct cyclades_port *info)
 {
        struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
        struct cyclades_card *cinfo = info->card;
+       struct tty_struct *tty;
        u8 data;
        unsigned int char_count;
 #ifdef BLOCKMOVE
@@ -1039,63 +1030,63 @@ static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
        else
                char_count = tx_get - tx_put - 1;
 
-       if (char_count) {
-
-               if (tty == NULL)
-                       goto ztxdone;
+       if (!char_count)
+               return;
+               
+       tty = tty_port_tty_get(&info->port);
+       if (tty == NULL)
+               goto ztxdone;
 
-               if (info->x_char) {     /* send special char */
-                       data = info->x_char;
+       if (info->x_char) {     /* send special char */
+               data = info->x_char;
 
-                       cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
-                       tx_put = (tx_put + 1) & (tx_bufsize - 1);
-                       info->x_char = 0;
-                       char_count--;
-                       info->icount.tx++;
-               }
+               cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
+               tx_put = (tx_put + 1) & (tx_bufsize - 1);
+               info->x_char = 0;
+               char_count--;
+               info->icount.tx++;
+       }
 #ifdef BLOCKMOVE
-               while (0 < (small_count = min_t(unsigned int,
-                               tx_bufsize - tx_put, min_t(unsigned int,
-                                       (SERIAL_XMIT_SIZE - info->xmit_tail),
-                                       min_t(unsigned int, info->xmit_cnt,
-                                               char_count))))) {
-
-                       memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
-                                       tx_put),
-                                       &info->port.xmit_buf[info->xmit_tail],
-                                       small_count);
-
-                       tx_put = (tx_put + small_count) & (tx_bufsize - 1);
-                       char_count -= small_count;
-                       info->icount.tx += small_count;
-                       info->xmit_cnt -= small_count;
-                       info->xmit_tail = (info->xmit_tail + small_count) &
-                                       (SERIAL_XMIT_SIZE - 1);
-               }
+       while (0 < (small_count = min_t(unsigned int,
+                       tx_bufsize - tx_put, min_t(unsigned int,
+                               (SERIAL_XMIT_SIZE - info->xmit_tail),
+                               min_t(unsigned int, info->xmit_cnt,
+                                       char_count))))) {
+
+               memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
+                               &info->port.xmit_buf[info->xmit_tail],
+                               small_count);
+
+               tx_put = (tx_put + small_count) & (tx_bufsize - 1);
+               char_count -= small_count;
+               info->icount.tx += small_count;
+               info->xmit_cnt -= small_count;
+               info->xmit_tail = (info->xmit_tail + small_count) &
+                               (SERIAL_XMIT_SIZE - 1);
+       }
 #else
-               while (info->xmit_cnt && char_count) {
-                       data = info->port.xmit_buf[info->xmit_tail];
-                       info->xmit_cnt--;
-                       info->xmit_tail = (info->xmit_tail + 1) &
-                                       (SERIAL_XMIT_SIZE - 1);
-
-                       cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
-                       tx_put = (tx_put + 1) & (tx_bufsize - 1);
-                       char_count--;
-                       info->icount.tx++;
-               }
+       while (info->xmit_cnt && char_count) {
+               data = info->port.xmit_buf[info->xmit_tail];
+               info->xmit_cnt--;
+               info->xmit_tail = (info->xmit_tail + 1) &
+                               (SERIAL_XMIT_SIZE - 1);
+
+               cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
+               tx_put = (tx_put + 1) & (tx_bufsize - 1);
+               char_count--;
+               info->icount.tx++;
+       }
 #endif
-               tty_wakeup(tty);
+       tty_wakeup(tty);
+       tty_kref_put(tty);
 ztxdone:
-               /* Update tx_put */
-               cy_writel(&buf_ctrl->tx_put, tx_put);
-       }
+       /* Update tx_put */
+       cy_writel(&buf_ctrl->tx_put, tx_put);
 }
 
 static void cyz_handle_cmd(struct cyclades_card *cinfo)
 {
        struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
-       struct tty_struct *tty;
        struct cyclades_port *info;
        __u32 channel, param, fw_ver;
        __u8 cmd;
@@ -1108,23 +1099,20 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                special_count = 0;
                delta_count = 0;
                info = &cinfo->ports[channel];
-               tty = tty_port_tty_get(&info->port);
-               if (tty == NULL)
-                       continue;
 
                switch (cmd) {
                case C_CM_PR_ERROR:
-                       tty_insert_flip_char(tty, 0, TTY_PARITY);
+                       tty_insert_flip_char(&info->port, 0, TTY_PARITY);
                        info->icount.rx++;
                        special_count++;
                        break;
                case C_CM_FR_ERROR:
-                       tty_insert_flip_char(tty, 0, TTY_FRAME);
+                       tty_insert_flip_char(&info->port, 0, TTY_FRAME);
                        info->icount.rx++;
                        special_count++;
                        break;
                case C_CM_RXBRK:
-                       tty_insert_flip_char(tty, 0, TTY_BREAK);
+                       tty_insert_flip_char(&info->port, 0, TTY_BREAK);
                        info->icount.rx++;
                        special_count++;
                        break;
@@ -1136,8 +1124,14 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                                        readl(&info->u.cyz.ch_ctrl->rs_status);
                                if (dcd & C_RS_DCD)
                                        wake_up_interruptible(&info->port.open_wait);
-                               else
-                                       tty_hangup(tty);
+                               else {
+                                       struct tty_struct *tty;
+                                       tty = tty_port_tty_get(&info->port);
+                                       if (tty) {
+                                               tty_hangup(tty);
+                                               tty_kref_put(tty);
+                                       }
+                               }
                        }
                        break;
                case C_CM_MCTS:
@@ -1166,7 +1160,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                        printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
                                        "port %ld\n", info->card, channel);
 #endif
-                       cyz_handle_rx(info, tty);
+                       cyz_handle_rx(info);
                        break;
                case C_CM_TXBEMPTY:
                case C_CM_TXLOWWM:
@@ -1176,7 +1170,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                        printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
                                        "port %ld\n", info->card, channel);
 #endif
-                       cyz_handle_tx(info, tty);
+                       cyz_handle_tx(info);
                        break;
 #endif                         /* CONFIG_CYZ_INTR */
                case C_CM_FATAL:
@@ -1188,8 +1182,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                if (delta_count)
                        wake_up_interruptible(&info->port.delta_msr_wait);
                if (special_count)
-                       tty_schedule_flip(tty);
-               tty_kref_put(tty);
+                       tty_schedule_flip(&info->port);
        }
 }
 
@@ -1255,17 +1248,11 @@ static void cyz_poll(unsigned long arg)
                cyz_handle_cmd(cinfo);
 
                for (port = 0; port < cinfo->nports; port++) {
-                       struct tty_struct *tty;
-
                        info = &cinfo->ports[port];
-                       tty = tty_port_tty_get(&info->port);
-                       /* OK to pass NULL to the handle functions below.
-                          They need to drop the data in that case. */
 
                        if (!info->throttle)
-                               cyz_handle_rx(info, tty);
-                       cyz_handle_tx(info, tty);
-                       tty_kref_put(tty);
+                               cyz_handle_rx(info);
+                       cyz_handle_tx(info);
                }
                /* poll every 'cyz_polling_cycle' period */
                expires = jiffies + cyz_polling_cycle;