Don't unconditionally set in_sync on newly added device in raid5_reshape
[safe/jmp/linux-2.6] / drivers / char / synclink_gt.c
index efb3dc9..8678f0c 100644 (file)
@@ -60,7 +60,9 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
@@ -154,7 +156,6 @@ static void tx_hold(struct tty_struct *tty);
 static void tx_release(struct tty_struct *tty);
 
 static int  ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static int  read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
 static int  chars_in_buffer(struct tty_struct *tty);
 static void throttle(struct tty_struct * tty);
 static void unthrottle(struct tty_struct * tty);
@@ -214,6 +215,7 @@ struct slgt_desc
 #define set_desc_next(a,b) (a).next   = cpu_to_le32((unsigned int)(b))
 #define set_desc_count(a,b)(a).count  = cpu_to_le16((unsigned short)(b))
 #define set_desc_eof(a,b)  (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
+#define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b))
 #define desc_count(a)      (le16_to_cpu((a).count))
 #define desc_status(a)     (le16_to_cpu((a).status))
 #define desc_complete(a)   (le16_to_cpu((a).status) & BIT15)
@@ -297,7 +299,9 @@ struct slgt_info {
        u32 max_frame_size;       /* as set by device config */
 
        unsigned int rbuf_fill_level;
+       unsigned int rx_pio;
        unsigned int if_mode;
+       unsigned int base_clock;
 
        /* device status */
 
@@ -330,6 +334,8 @@ struct slgt_info {
        struct slgt_desc *rbufs;
        unsigned int rbuf_current;
        unsigned int rbuf_index;
+       unsigned int rbuf_fill_index;
+       unsigned short rbuf_fill_count;
 
        unsigned int tbuf_count;
        struct slgt_desc *tbufs;
@@ -462,7 +468,6 @@ static unsigned int free_tbuf_count(struct slgt_info *info);
 static unsigned int tbuf_bytes(struct slgt_info *info);
 static void reset_tbufs(struct slgt_info *info);
 static void tdma_reset(struct slgt_info *info);
-static void tdma_start(struct slgt_info *info);
 static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
 
 static void get_signals(struct slgt_info *info);
@@ -790,6 +795,18 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        }
 }
 
+static void update_tx_timer(struct slgt_info *info)
+{
+       /*
+        * use worst case speed of 1200bps to calculate transmit timeout
+        * based on data in buffers (tbuf_bytes) and FIFO (128 bytes)
+        */
+       if (info->params.mode == MGSL_MODE_HDLC) {
+               int timeout  = (tbuf_bytes(info) * 7) + 1000;
+               mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout));
+       }
+}
+
 static int write(struct tty_struct *tty,
                 const unsigned char *buf, int count)
 {
@@ -833,8 +850,18 @@ start:
                spin_lock_irqsave(&info->lock,flags);
                if (!info->tx_active)
                        tx_start(info);
-               else
-                       tdma_start(info);
+               else if (!(rd_reg32(info, TDCSR) & BIT0)) {
+                       /* transmit still active but transmit DMA stopped */
+                       unsigned int i = info->tbuf_current;
+                       if (!i)
+                               i = info->tbuf_count;
+                       i--;
+                       /* if DMA buf unsent must try later after tx idle */
+                       if (desc_count(info->tbufs[i]))
+                               ret = 0;
+               }
+               if (ret > 0)
+                       update_tx_timer(info);
                spin_unlock_irqrestore(&info->lock,flags);
        }
 
@@ -1156,22 +1183,26 @@ static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *ne
                return -EFAULT;
 
        spin_lock(&info->lock);
-       info->params.mode            = tmp_params.mode;
-       info->params.loopback        = tmp_params.loopback;
-       info->params.flags           = tmp_params.flags;
-       info->params.encoding        = tmp_params.encoding;
-       info->params.clock_speed     = tmp_params.clock_speed;
-       info->params.addr_filter     = tmp_params.addr_filter;
-       info->params.crc_type        = tmp_params.crc_type;
-       info->params.preamble_length = tmp_params.preamble_length;
-       info->params.preamble        = tmp_params.preamble;
-       info->params.data_rate       = tmp_params.data_rate;
-       info->params.data_bits       = tmp_params.data_bits;
-       info->params.stop_bits       = tmp_params.stop_bits;
-       info->params.parity          = tmp_params.parity;
+       if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) {
+               info->base_clock = tmp_params.clock_speed;
+       } else {
+               info->params.mode            = tmp_params.mode;
+               info->params.loopback        = tmp_params.loopback;
+               info->params.flags           = tmp_params.flags;
+               info->params.encoding        = tmp_params.encoding;
+               info->params.clock_speed     = tmp_params.clock_speed;
+               info->params.addr_filter     = tmp_params.addr_filter;
+               info->params.crc_type        = tmp_params.crc_type;
+               info->params.preamble_length = tmp_params.preamble_length;
+               info->params.preamble        = tmp_params.preamble;
+               info->params.data_rate       = tmp_params.data_rate;
+               info->params.data_bits       = tmp_params.data_bits;
+               info->params.stop_bits       = tmp_params.stop_bits;
+               info->params.parity          = tmp_params.parity;
+       }
        spin_unlock(&info->lock);
 
-       change_params(info);
+       program_hw(info);
 
        return 0;
 }
@@ -1229,13 +1260,12 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
 /*
  * proc fs support
  */
-static inline int line_info(char *buf, struct slgt_info *info)
+static inline void line_info(struct seq_file *m, struct slgt_info *info)
 {
        char stat_buf[30];
-       int ret;
        unsigned long flags;
 
-       ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
+       seq_printf(m, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
                      info->device_name, info->phys_reg_addr,
                      info->irq_level, info->max_frame_size);
 
@@ -1260,75 +1290,70 @@ static inline int line_info(char *buf, struct slgt_info *info)
                strcat(stat_buf, "|RI");
 
        if (info->params.mode != MGSL_MODE_ASYNC) {
-               ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+               seq_printf(m, "\tHDLC txok:%d rxok:%d",
                               info->icount.txok, info->icount.rxok);
                if (info->icount.txunder)
-                       ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+                       seq_printf(m, " txunder:%d", info->icount.txunder);
                if (info->icount.txabort)
-                       ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+                       seq_printf(m, " txabort:%d", info->icount.txabort);
                if (info->icount.rxshort)
-                       ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+                       seq_printf(m, " rxshort:%d", info->icount.rxshort);
                if (info->icount.rxlong)
-                       ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+                       seq_printf(m, " rxlong:%d", info->icount.rxlong);
                if (info->icount.rxover)
-                       ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+                       seq_printf(m, " rxover:%d", info->icount.rxover);
                if (info->icount.rxcrc)
-                       ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+                       seq_printf(m, " rxcrc:%d", info->icount.rxcrc);
        } else {
-               ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+               seq_printf(m, "\tASYNC tx:%d rx:%d",
                               info->icount.tx, info->icount.rx);
                if (info->icount.frame)
-                       ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+                       seq_printf(m, " fe:%d", info->icount.frame);
                if (info->icount.parity)
-                       ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+                       seq_printf(m, " pe:%d", info->icount.parity);
                if (info->icount.brk)
-                       ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+                       seq_printf(m, " brk:%d", info->icount.brk);
                if (info->icount.overrun)
-                       ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+                       seq_printf(m, " oe:%d", info->icount.overrun);
        }
 
        /* Append serial signal status to end */
-       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       seq_printf(m, " %s\n", stat_buf+1);
 
-       ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+       seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
                       info->tx_active,info->bh_requested,info->bh_running,
                       info->pending_bh);
-
-       return ret;
 }
 
 /* Called to print information about devices
  */
-static int read_proc(char *page, char **start, off_t off, int count,
-                    int *eof, void *data)
+static int synclink_gt_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0, l;
-       off_t   begin = 0;
        struct slgt_info *info;
 
-       len += sprintf(page, "synclink_gt driver\n");
+       seq_puts(m, "synclink_gt driver\n");
 
        info = slgt_device_list;
        while( info ) {
-               l = line_info(page + len, info);
-               len += l;
-               if (len+begin > off+count)
-                       goto done;
-               if (len+begin < off) {
-                       begin += len;
-                       len = 0;
-               }
+               line_info(m, info);
                info = info->next_device;
        }
+       return 0;
+}
 
-       *eof = 1;
-done:
-       if (off >= len+begin)
-               return 0;
-       *start = page + (off-begin);
-       return ((count < begin+len-off) ? count : begin+len-off);
+static int synclink_gt_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, synclink_gt_proc_show, NULL);
 }
 
+static const struct file_operations synclink_gt_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = synclink_gt_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * return count of bytes in transmit buffer
  */
@@ -1472,10 +1497,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
  *
  * skb  socket buffer containing HDLC frame
  * dev  pointer to network device structure
- *
- * returns 0 if success, otherwise error code
  */
-static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
+                                     struct net_device *dev)
 {
        struct slgt_info *info = dev_to_port(dev);
        unsigned long flags;
@@ -1499,13 +1523,12 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
        /* save start time for transmit timeout detection */
        dev->trans_start = jiffies;
 
-       /* start hardware transmitter if necessary */
        spin_lock_irqsave(&info->lock,flags);
-       if (!info->tx_active)
-               tx_start(info);
+       tx_start(info);
+       update_tx_timer(info);
        spin_unlock_irqrestore(&info->lock,flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /**
@@ -2111,6 +2134,40 @@ static void ri_change(struct slgt_info *info, unsigned short status)
        info->pending_bh |= BH_STATUS;
 }
 
+static void isr_rxdata(struct slgt_info *info)
+{
+       unsigned int count = info->rbuf_fill_count;
+       unsigned int i = info->rbuf_fill_index;
+       unsigned short reg;
+
+       while (rd_reg16(info, SSR) & IRQ_RXDATA) {
+               reg = rd_reg16(info, RDR);
+               DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg));
+               if (desc_complete(info->rbufs[i])) {
+                       /* all buffers full */
+                       rx_stop(info);
+                       info->rx_restart = 1;
+                       continue;
+               }
+               info->rbufs[i].buf[count++] = (unsigned char)reg;
+               /* async mode saves status byte to buffer for each data byte */
+               if (info->params.mode == MGSL_MODE_ASYNC)
+                       info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8);
+               if (count == info->rbuf_fill_level || (reg & BIT10)) {
+                       /* buffer full or end of frame */
+                       set_desc_count(info->rbufs[i], count);
+                       set_desc_status(info->rbufs[i], BIT15 | (reg >> 8));
+                       info->rbuf_fill_count = count = 0;
+                       if (++i == info->rbuf_count)
+                               i = 0;
+                       info->pending_bh |= BH_RECEIVE;
+               }
+       }
+
+       info->rbuf_fill_index = i;
+       info->rbuf_fill_count = count;
+}
+
 static void isr_serial(struct slgt_info *info)
 {
        unsigned short status = rd_reg16(info, SSR);
@@ -2126,6 +2183,8 @@ static void isr_serial(struct slgt_info *info)
                        if (info->tx_count)
                                isr_txeom(info, status);
                }
+               if (info->rx_pio && (status & IRQ_RXDATA))
+                       isr_rxdata(info);
                if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
                        info->icount.brk++;
                        /* process break detection if tty control allows */
@@ -2142,7 +2201,8 @@ static void isr_serial(struct slgt_info *info)
        } else {
                if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
                        isr_txeom(info, status);
-
+               if (info->rx_pio && (status & IRQ_RXDATA))
+                       isr_rxdata(info);
                if (status & IRQ_RXIDLE) {
                        if (status & RXIDLE)
                                info->icount.rxidle++;
@@ -2565,10 +2625,13 @@ static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params)
                return -EFAULT;
 
        spin_lock_irqsave(&info->lock, flags);
-       memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
+       if (tmp_params.mode == MGSL_MODE_BASE_CLOCK)
+               info->base_clock = tmp_params.clock_speed;
+       else
+               memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
        spin_unlock_irqrestore(&info->lock, flags);
 
-       change_params(info);
+       program_hw(info);
 
        return 0;
 }
@@ -2640,6 +2703,10 @@ static int rx_enable(struct slgt_info *info, int enable)
                        return -EINVAL;
                }
                info->rbuf_fill_level = rbuf_fill_level;
+               if (rbuf_fill_level < 128)
+                       info->rx_pio = 1; /* PIO mode */
+               else
+                       info->rx_pio = 0; /* DMA mode */
                rx_stop(info); /* restart receiver to use new fill level */
        }
 
@@ -3097,13 +3164,16 @@ static int carrier_raised(struct tty_port *port)
        return (info->signals & SerialSignal_DCD) ? 1 : 0;
 }
 
-static void raise_dtr_rts(struct tty_port *port)
+static void dtr_rts(struct tty_port *port, int on)
 {
        unsigned long flags;
        struct slgt_info *info = container_of(port, struct slgt_info, port);
 
        spin_lock_irqsave(&info->lock,flags);
-       info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+       if (on)
+               info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+       else
+               info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
        set_signals(info);
        spin_unlock_irqrestore(&info->lock,flags);
 }
@@ -3417,7 +3487,7 @@ static void add_device(struct slgt_info *info)
 
 static const struct tty_port_operations slgt_port_ops = {
        .carrier_raised = carrier_raised,
-       .raise_dtr_rts = raise_dtr_rts,
+       .dtr_rts = dtr_rts,
 };
 
 /*
@@ -3438,6 +3508,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
+               info->base_clock = 14745600;
                info->rbuf_fill_level = DMABUFSIZE;
                info->port.close_delay = 5*HZ/10;
                info->port.closing_wait = 30*HZ;
@@ -3562,13 +3633,13 @@ static const struct tty_operations ops = {
        .send_xchar = send_xchar,
        .break_ctl = set_break,
        .wait_until_sent = wait_until_sent,
-       .read_proc = read_proc,
        .set_termios = set_termios,
        .stop = tx_hold,
        .start = tx_release,
        .hangup = hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .proc_fops = &synclink_gt_proc_fops,
 };
 
 static void slgt_cleanup(void)
@@ -3785,7 +3856,7 @@ static void enable_loopback(struct slgt_info *info)
 static void set_rate(struct slgt_info *info, u32 rate)
 {
        unsigned int div;
-       static unsigned int osc = 14745600;
+       unsigned int osc = info->base_clock;
 
        /* div = osc/rate - 1
         *
@@ -3838,15 +3909,27 @@ static void rx_start(struct slgt_info *info)
        rdma_reset(info);
        reset_rbufs(info);
 
-       /* set 1st descriptor address */
-       wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
-
-       if (info->params.mode != MGSL_MODE_ASYNC) {
-               /* enable rx DMA and DMA interrupt */
-               wr_reg32(info, RDCSR, (BIT2 + BIT0));
+       if (info->rx_pio) {
+               /* rx request when rx FIFO not empty */
+               wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14));
+               slgt_irq_on(info, IRQ_RXDATA);
+               if (info->params.mode == MGSL_MODE_ASYNC) {
+                       /* enable saving of rx status */
+                       wr_reg32(info, RDCSR, BIT6);
+               }
        } else {
-               /* enable saving of rx status, rx DMA and DMA interrupt */
-               wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
+               /* rx request when rx FIFO half full */
+               wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14));
+               /* set 1st descriptor address */
+               wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
+
+               if (info->params.mode != MGSL_MODE_ASYNC) {
+                       /* enable rx DMA and DMA interrupt */
+                       wr_reg32(info, RDCSR, (BIT2 + BIT0));
+               } else {
+                       /* enable saving of rx status, rx DMA and DMA interrupt */
+                       wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
+               }
        }
 
        slgt_irq_on(info, IRQ_RXOVER);
@@ -3883,50 +3966,19 @@ static void tx_start(struct slgt_info *info)
                        slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
                        /* clear tx idle and underrun status bits */
                        wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
-                       if (info->params.mode == MGSL_MODE_HDLC)
-                               mod_timer(&info->tx_timer, jiffies +
-                                               msecs_to_jiffies(5000));
                } else {
                        slgt_irq_off(info, IRQ_TXDATA);
                        slgt_irq_on(info, IRQ_TXIDLE);
                        /* clear tx idle status bit */
                        wr_reg16(info, SSR, IRQ_TXIDLE);
                }
-               tdma_start(info);
+               /* set 1st descriptor address and start DMA */
+               wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+               wr_reg32(info, TDCSR, BIT2 + BIT0);
                info->tx_active = true;
        }
 }
 
-/*
- * start transmit DMA if inactive and there are unsent buffers
- */
-static void tdma_start(struct slgt_info *info)
-{
-       unsigned int i;
-
-       if (rd_reg32(info, TDCSR) & BIT0)
-               return;
-
-       /* transmit DMA inactive, check for unsent buffers */
-       i = info->tbuf_start;
-       while (!desc_count(info->tbufs[i])) {
-               if (++i == info->tbuf_count)
-                       i = 0;
-               if (i == info->tbuf_current)
-                       return;
-       }
-       info->tbuf_start = i;
-
-       /* there are unsent buffers, start transmit DMA */
-
-       /* reset needed if previous error condition */
-       tdma_reset(info);
-
-       /* set 1st descriptor address */
-       wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-       wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
-}
-
 static void tx_stop(struct slgt_info *info)
 {
        unsigned short val;
@@ -4089,18 +4141,27 @@ static void async_mode(struct slgt_info *info)
         * 06  CTS      IRQ enable
         * 05  DCD      IRQ enable
         * 04  RI       IRQ enable
-        * 03  reserved, must be zero
+        * 03  0=16x sampling, 1=8x sampling
         * 02  1=txd->rxd internal loopback enable
         * 01  reserved, must be zero
         * 00  1=master IRQ enable
         */
        val = BIT15 + BIT14 + BIT0;
+       /* JCR[8] : 1 = x8 async mode feature available */
+       if ((rd_reg32(info, JCR) & BIT8) && info->params.data_rate &&
+           ((info->base_clock < (info->params.data_rate * 16)) ||
+            (info->base_clock % (info->params.data_rate * 16)))) {
+               /* use 8x sampling */
+               val |= BIT3;
+               set_rate(info, info->params.data_rate * 8);
+       } else {
+               /* use 16x sampling */
+               set_rate(info, info->params.data_rate * 16);
+       }
        wr_reg16(info, SCR, val);
 
        slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER);
 
-       set_rate(info, info->params.data_rate * 16);
-
        if (info->params.loopback)
                enable_loopback(info);
 }
@@ -4455,6 +4516,8 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
 static void reset_rbufs(struct slgt_info *info)
 {
        free_rbufs(info, 0, info->rbuf_count - 1);
+       info->rbuf_fill_index = 0;
+       info->rbuf_fill_count = 0;
 }
 
 /*
@@ -4930,8 +4993,7 @@ static void tx_timeout(unsigned long context)
                info->icount.txtimeout++;
        }
        spin_lock_irqsave(&info->lock,flags);
-       info->tx_active = false;
-       info->tx_count = 0;
+       tx_stop(info);
        spin_unlock_irqrestore(&info->lock,flags);
 
 #if SYNCLINK_GENERIC_HDLC