X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Fchar%2Fsynclink_gt.c;h=3e9058993e41805c0b2cd699ad836c76844fe398;hb=53f1b1433da7eac2607a4a0898a221a4485fd732;hp=0e59cf54adaf88e4eede6003866c73dca9fb1dce;hpb=8a38c2851d6950502252982af712ac65ef6784ed;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 0e59cf54ada..3e9058993e4 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -214,6 +214,7 @@ struct slgt_desc char *buf; /* virtual address of data buffer */ unsigned int pdesc; /* physical address of this descriptor */ dma_addr_t buf_dma_addr; + unsigned short buf_count; }; #define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b)) @@ -302,7 +303,7 @@ struct slgt_info { u32 idle_mode; u32 max_frame_size; /* as set by device config */ - unsigned int raw_rx_size; + unsigned int rbuf_fill_level; unsigned int if_mode; /* device status */ @@ -466,6 +467,7 @@ static void tx_start(struct slgt_info *info); static void tx_stop(struct slgt_info *info); static void tx_set_idle(struct slgt_info *info); 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); @@ -1388,10 +1390,12 @@ done: static int chars_in_buffer(struct tty_struct *tty) { struct slgt_info *info = tty->driver_data; + int count; if (sanity_check(info, tty->name, "chars_in_buffer")) return 0; - DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count)); - return info->tx_count; + count = tbuf_bytes(info); + DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count)); + return count; } /* @@ -2672,8 +2676,31 @@ static int tx_abort(struct slgt_info *info) static int rx_enable(struct slgt_info *info, int enable) { unsigned long flags; - DBGINFO(("%s rx_enable(%d)\n", info->device_name, enable)); + unsigned int rbuf_fill_level; + DBGINFO(("%s rx_enable(%08x)\n", info->device_name, enable)); spin_lock_irqsave(&info->lock,flags); + /* + * enable[31..16] = receive DMA buffer fill level + * 0 = noop (leave fill level unchanged) + * fill level must be multiple of 4 and <= buffer size + */ + rbuf_fill_level = ((unsigned int)enable) >> 16; + if (rbuf_fill_level) { + if ((rbuf_fill_level > DMABUFSIZE) || (rbuf_fill_level % 4)) { + spin_unlock_irqrestore(&info->lock, flags); + return -EINVAL; + } + info->rbuf_fill_level = rbuf_fill_level; + rx_stop(info); /* restart receiver to use new fill level */ + } + + /* + * enable[1..0] = receiver enable command + * 0 = disable + * 1 = enable + * 2 = enable or force hunt mode if already enabled + */ + enable &= 3; if (enable) { if (!info->rx_enabled) rx_start(info); @@ -3440,7 +3467,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->raw_rx_size = DMABUFSIZE; + info->rbuf_fill_level = DMABUFSIZE; info->port.close_delay = 5*HZ/10; info->port.closing_wait = 30*HZ; init_waitqueue_head(&info->status_event_wait_q); @@ -4130,7 +4157,7 @@ static void sync_mode(struct slgt_info *info) * 01 enable * 00 auto-CTS enable */ - val = 0; + val = BIT2; switch(info->params.mode) { case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; @@ -4403,6 +4430,8 @@ static void msc_set_vcr(struct slgt_info *info) break; } + if (info->if_mode & MGSL_INTERFACE_MSB_FIRST) + val |= BIT4; if (info->signals & SerialSignal_DTR) val |= BIT3; if (info->signals & SerialSignal_RTS) @@ -4441,16 +4470,7 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last while(!done) { /* reset current buffer for reuse */ info->rbufs[i].status = 0; - switch(info->params.mode) { - case MGSL_MODE_RAW: - case MGSL_MODE_MONOSYNC: - case MGSL_MODE_BISYNC: - set_desc_count(info->rbufs[i], info->raw_rx_size); - break; - default: - set_desc_count(info->rbufs[i], DMABUFSIZE); - } - + set_desc_count(info->rbufs[i], info->rbuf_fill_level); if (i == last) done = 1; if (++i == info->rbuf_count) @@ -4557,7 +4577,7 @@ check_again: DBGBH(("%s rx frame status=%04X size=%d\n", info->device_name, status, framesize)); - DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx"); + DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, info->rbuf_fill_level), "rx"); if (framesize) { if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) { @@ -4577,7 +4597,7 @@ check_again: info->icount.rxok++; while(copy_count) { - int partial_count = min(copy_count, DMABUFSIZE); + int partial_count = min_t(int, copy_count, info->rbuf_fill_level); memcpy(p, info->rbufs[i].buf, partial_count); p += partial_count; copy_count -= partial_count; @@ -4668,6 +4688,56 @@ static unsigned int free_tbuf_count(struct slgt_info *info) return count; } +/* + * return number of bytes in unsent transmit DMA buffers + * and the serial controller tx FIFO + */ +static unsigned int tbuf_bytes(struct slgt_info *info) +{ + unsigned int total_count = 0; + unsigned int i = info->tbuf_current; + unsigned int reg_value; + unsigned int count; + unsigned int active_buf_count = 0; + + /* + * Add descriptor counts for all tx DMA buffers. + * If count is zero (cleared by DMA controller after read), + * the buffer is complete or is actively being read from. + * + * Record buf_count of last buffer with zero count starting + * from current ring position. buf_count is mirror + * copy of count and is not cleared by serial controller. + * If DMA controller is active, that buffer is actively + * being read so add to total. + */ + do { + count = desc_count(info->tbufs[i]); + if (count) + total_count += count; + else if (!total_count) + active_buf_count = info->tbufs[i].buf_count; + if (++i == info->tbuf_count) + i = 0; + } while (i != info->tbuf_current); + + /* read tx DMA status register */ + reg_value = rd_reg32(info, TDCSR); + + /* if tx DMA active, last zero count buffer is in use */ + if (reg_value & BIT0) + total_count += active_buf_count; + + /* add tx FIFO count = reg_value[15..8] */ + total_count += (reg_value >> 8) & 0xff; + + /* if transmitter active add one byte for shift register */ + if (info->tx_active) + total_count++; + + return total_count; +} + /* * load transmit DMA buffer(s) with data */ @@ -4706,6 +4776,7 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size) set_desc_eof(*d, 0); set_desc_count(*d, count); + d->buf_count = count; } info->tbuf_current = i;