aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorThadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>2011-08-24 12:14:22 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-24 18:29:44 -0400
commit9d898966c4a07e4a5092215b5a2829d0ef02baa2 (patch)
tree0ba12a03b2b04b2c7203c5324c13146db950b75c /drivers/tty
parentd64bbeb57f9901b6919fabd1e5a555e94748c255 (diff)
jsm: remove buggy write queue
jsm uses a write queue that copies from uart_core circular buffer. This copying however has some bugs, like not wrapping the head counter. Since this write queue is also a circular buffer, the consumer function is ready to use the uart_core circular buffer directly. This buggy copying function was making some bytes be dropped when transmitting to a raw tty, doing something like this. [root@hostname ~]$ cat /dev/ttyn1 > cascardo/dump & [1] 2658 [root@hostname ~]$ cat /proc/tty/drivers > /dev/ttyn0 [root@hostname ~]$ cat /proc/tty/drivers /dev/tty /dev/tty 5 0 system:/dev/tty /dev/console /dev/console 5 1 system:console /dev/ptmx /dev/ptmx 5 2 system /dev/vc/0 /dev/vc/0 4 0 system:vtmaster jsm /dev/ttyn 250 0-31 serial serial /dev/ttyS 4 64-95 serial hvc /dev/hvc 229 0-7 system pty_slave /dev/pts 136 0-1048575 pty:slave pty_master /dev/ptm 128 0-1048575 pty:master unknown /dev/tty 4 1-63 console [root@hostname ~]$ cat cascardo/dump /dev/tty /dev/tty 5 0 system:/dev/tty /dev/console /dev/console 5 1 system:console /dev/ptmx /dev/ptmx 5 2 system /dev/vc/0 /dev/vc/0 4 0 system:vtmaste[root@hostname ~]$ This patch drops the driver write queue entirely, using the circular buffer from uart_core only. Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/jsm/jsm.h7
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c1
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c29
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c94
4 files changed, 28 insertions, 103 deletions
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
index cd53bdda77ce..529bec6edaf8 100644
--- a/drivers/tty/serial/jsm/jsm.h
+++ b/drivers/tty/serial/jsm/jsm.h
@@ -180,10 +180,8 @@ struct jsm_board
180/* Our Read/Error/Write queue sizes */ 180/* Our Read/Error/Write queue sizes */
181#define RQUEUEMASK 0x1FFF /* 8 K - 1 */ 181#define RQUEUEMASK 0x1FFF /* 8 K - 1 */
182#define EQUEUEMASK 0x1FFF /* 8 K - 1 */ 182#define EQUEUEMASK 0x1FFF /* 8 K - 1 */
183#define WQUEUEMASK 0x0FFF /* 4 K - 1 */
184#define RQUEUESIZE (RQUEUEMASK + 1) 183#define RQUEUESIZE (RQUEUEMASK + 1)
185#define EQUEUESIZE RQUEUESIZE 184#define EQUEUESIZE RQUEUESIZE
186#define WQUEUESIZE (WQUEUEMASK + 1)
187 185
188 186
189/************************************************************************ 187/************************************************************************
@@ -223,10 +221,6 @@ struct jsm_channel {
223 u16 ch_e_head; /* Head location of the error queue */ 221 u16 ch_e_head; /* Head location of the error queue */
224 u16 ch_e_tail; /* Tail location of the error queue */ 222 u16 ch_e_tail; /* Tail location of the error queue */
225 223
226 u8 *ch_wqueue; /* Our write queue buffer - malloc'ed */
227 u16 ch_w_head; /* Head location of the write queue */
228 u16 ch_w_tail; /* Tail location of the write queue */
229
230 u64 ch_rxcount; /* total of data received so far */ 224 u64 ch_rxcount; /* total of data received so far */
231 u64 ch_txcount; /* total of data transmitted so far */ 225 u64 ch_txcount; /* total of data transmitted so far */
232 226
@@ -375,7 +369,6 @@ extern int jsm_debug;
375 * Prototypes for non-static functions used in more than one module 369 * Prototypes for non-static functions used in more than one module
376 * 370 *
377 *************************************************************************/ 371 *************************************************************************/
378int jsm_tty_write(struct uart_port *port);
379int jsm_tty_init(struct jsm_board *); 372int jsm_tty_init(struct jsm_board *);
380int jsm_uart_port_init(struct jsm_board *); 373int jsm_uart_port_init(struct jsm_board *);
381int jsm_remove_uart_port(struct jsm_board *); 374int jsm_remove_uart_port(struct jsm_board *);
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 1cc8cf602af8..648b6a3efa32 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -194,7 +194,6 @@ static void __devexit jsm_remove_one(struct pci_dev *pdev)
194 if (brd->channels[i]) { 194 if (brd->channels[i]) {
195 kfree(brd->channels[i]->ch_rqueue); 195 kfree(brd->channels[i]->ch_rqueue);
196 kfree(brd->channels[i]->ch_equeue); 196 kfree(brd->channels[i]->ch_equeue);
197 kfree(brd->channels[i]->ch_wqueue);
198 kfree(brd->channels[i]); 197 kfree(brd->channels[i]);
199 } 198 }
200 } 199 }
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 4538c3e3646e..bd6e84699e11 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -496,12 +496,15 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
496 int s; 496 int s;
497 int qlen; 497 int qlen;
498 u32 len_written = 0; 498 u32 len_written = 0;
499 struct circ_buf *circ;
499 500
500 if (!ch) 501 if (!ch)
501 return; 502 return;
502 503
504 circ = &ch->uart_port.state->xmit;
505
503 /* No data to write to the UART */ 506 /* No data to write to the UART */
504 if (ch->ch_w_tail == ch->ch_w_head) 507 if (uart_circ_empty(circ))
505 return; 508 return;
506 509
507 /* If port is "stopped", don't send any data to the UART */ 510 /* If port is "stopped", don't send any data to the UART */
@@ -517,11 +520,10 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
517 if (ch->ch_cached_lsr & UART_LSR_THRE) { 520 if (ch->ch_cached_lsr & UART_LSR_THRE) {
518 ch->ch_cached_lsr &= ~(UART_LSR_THRE); 521 ch->ch_cached_lsr &= ~(UART_LSR_THRE);
519 522
520 writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx); 523 writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
521 jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev, 524 jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
522 "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]); 525 "Tx data: %x\n", circ->buf[circ->head]);
523 ch->ch_w_tail++; 526 circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
524 ch->ch_w_tail &= WQUEUEMASK;
525 ch->ch_txcount++; 527 ch->ch_txcount++;
526 } 528 }
527 return; 529 return;
@@ -536,36 +538,36 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
536 n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; 538 n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
537 539
538 /* cache head and tail of queue */ 540 /* cache head and tail of queue */
539 head = ch->ch_w_head & WQUEUEMASK; 541 head = circ->head & (UART_XMIT_SIZE - 1);
540 tail = ch->ch_w_tail & WQUEUEMASK; 542 tail = circ->tail & (UART_XMIT_SIZE - 1);
541 qlen = (head - tail) & WQUEUEMASK; 543 qlen = uart_circ_chars_pending(circ);
542 544
543 /* Find minimum of the FIFO space, versus queue length */ 545 /* Find minimum of the FIFO space, versus queue length */
544 n = min(n, qlen); 546 n = min(n, qlen);
545 547
546 while (n > 0) { 548 while (n > 0) {
547 549
548 s = ((head >= tail) ? head : WQUEUESIZE) - tail; 550 s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
549 s = min(s, n); 551 s = min(s, n);
550 552
551 if (s <= 0) 553 if (s <= 0)
552 break; 554 break;
553 555
554 memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s); 556 memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s);
555 /* Add and flip queue if needed */ 557 /* Add and flip queue if needed */
556 tail = (tail + s) & WQUEUEMASK; 558 tail = (tail + s) & (UART_XMIT_SIZE - 1);
557 n -= s; 559 n -= s;
558 ch->ch_txcount += s; 560 ch->ch_txcount += s;
559 len_written += s; 561 len_written += s;
560 } 562 }
561 563
562 /* Update the final tail */ 564 /* Update the final tail */
563 ch->ch_w_tail = tail & WQUEUEMASK; 565 circ->tail = tail & (UART_XMIT_SIZE - 1);
564 566
565 if (len_written >= ch->ch_t_tlevel) 567 if (len_written >= ch->ch_t_tlevel)
566 ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 568 ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
567 569
568 if (!jsm_tty_write(&ch->uart_port)) 570 if (uart_circ_empty(circ))
569 uart_write_wakeup(&ch->uart_port); 571 uart_write_wakeup(&ch->uart_port);
570} 572}
571 573
@@ -946,7 +948,6 @@ static void neo_param(struct jsm_channel *ch)
946 if ((ch->ch_c_cflag & (CBAUD)) == 0) { 948 if ((ch->ch_c_cflag & (CBAUD)) == 0) {
947 ch->ch_r_head = ch->ch_r_tail = 0; 949 ch->ch_r_head = ch->ch_r_tail = 0;
948 ch->ch_e_head = ch->ch_e_tail = 0; 950 ch->ch_e_head = ch->ch_e_tail = 0;
949 ch->ch_w_head = ch->ch_w_tail = 0;
950 951
951 neo_flush_uart_write(ch); 952 neo_flush_uart_write(ch);
952 neo_flush_uart_read(ch); 953 neo_flush_uart_read(ch);
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 7a4a914ecff0..434bd881fcae 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -118,6 +118,19 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
118 udelay(10); 118 udelay(10);
119} 119}
120 120
121/*
122 * jsm_tty_write()
123 *
124 * Take data from the user or kernel and send it out to the FEP.
125 * In here exists all the Transparent Print magic as well.
126 */
127static void jsm_tty_write(struct uart_port *port)
128{
129 struct jsm_channel *channel;
130 channel = container_of(port, struct jsm_channel, uart_port);
131 channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
132}
133
121static void jsm_tty_start_tx(struct uart_port *port) 134static void jsm_tty_start_tx(struct uart_port *port)
122{ 135{
123 struct jsm_channel *channel = (struct jsm_channel *)port; 136 struct jsm_channel *channel = (struct jsm_channel *)port;
@@ -216,14 +229,6 @@ static int jsm_tty_open(struct uart_port *port)
216 return -ENOMEM; 229 return -ENOMEM;
217 } 230 }
218 } 231 }
219 if (!channel->ch_wqueue) {
220 channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
221 if (!channel->ch_wqueue) {
222 jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
223 "unable to allocate write queue buf");
224 return -ENOMEM;
225 }
226 }
227 232
228 channel->ch_flags &= ~(CH_OPENING); 233 channel->ch_flags &= ~(CH_OPENING);
229 /* 234 /*
@@ -237,7 +242,6 @@ static int jsm_tty_open(struct uart_port *port)
237 */ 242 */
238 channel->ch_r_head = channel->ch_r_tail = 0; 243 channel->ch_r_head = channel->ch_r_tail = 0;
239 channel->ch_e_head = channel->ch_e_tail = 0; 244 channel->ch_e_head = channel->ch_e_tail = 0;
240 channel->ch_w_head = channel->ch_w_tail = 0;
241 245
242 brd->bd_ops->flush_uart_write(channel); 246 brd->bd_ops->flush_uart_write(channel);
243 brd->bd_ops->flush_uart_read(channel); 247 brd->bd_ops->flush_uart_read(channel);
@@ -836,75 +840,3 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
836 } 840 }
837 } 841 }
838} 842}
839
840/*
841 * jsm_tty_write()
842 *
843 * Take data from the user or kernel and send it out to the FEP.
844 * In here exists all the Transparent Print magic as well.
845 */
846int jsm_tty_write(struct uart_port *port)
847{
848 int bufcount;
849 int data_count = 0,data_count1 =0;
850 u16 head;
851 u16 tail;
852 u16 tmask;
853 u32 remain;
854 int temp_tail = port->state->xmit.tail;
855 struct jsm_channel *channel = (struct jsm_channel *)port;
856
857 tmask = WQUEUEMASK;
858 head = (channel->ch_w_head) & tmask;
859 tail = (channel->ch_w_tail) & tmask;
860
861 if ((bufcount = tail - head - 1) < 0)
862 bufcount += WQUEUESIZE;
863
864 bufcount = min(bufcount, 56);
865 remain = WQUEUESIZE - head;
866
867 data_count = 0;
868 if (bufcount >= remain) {
869 bufcount -= remain;
870 while ((port->state->xmit.head != temp_tail) &&
871 (data_count < remain)) {
872 channel->ch_wqueue[head++] =
873 port->state->xmit.buf[temp_tail];
874
875 temp_tail++;
876 temp_tail &= (UART_XMIT_SIZE - 1);
877 data_count++;
878 }
879 if (data_count == remain) head = 0;
880 }
881
882 data_count1 = 0;
883 if (bufcount > 0) {
884 remain = bufcount;
885 while ((port->state->xmit.head != temp_tail) &&
886 (data_count1 < remain)) {
887 channel->ch_wqueue[head++] =
888 port->state->xmit.buf[temp_tail];
889
890 temp_tail++;
891 temp_tail &= (UART_XMIT_SIZE - 1);
892 data_count1++;
893
894 }
895 }
896
897 port->state->xmit.tail = temp_tail;
898
899 data_count += data_count1;
900 if (data_count) {
901 head &= tmask;
902 channel->ch_w_head = head;
903 }
904
905 if (data_count) {
906 channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
907 }
908
909 return data_count;
910}