diff options
author | Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com> | 2011-08-24 12:14:22 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-24 18:29:44 -0400 |
commit | 9d898966c4a07e4a5092215b5a2829d0ef02baa2 (patch) | |
tree | 0ba12a03b2b04b2c7203c5324c13146db950b75c /drivers/tty/serial | |
parent | d64bbeb57f9901b6919fabd1e5a555e94748c255 (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/serial')
-rw-r--r-- | drivers/tty/serial/jsm/jsm.h | 7 | ||||
-rw-r--r-- | drivers/tty/serial/jsm/jsm_driver.c | 1 | ||||
-rw-r--r-- | drivers/tty/serial/jsm/jsm_neo.c | 29 | ||||
-rw-r--r-- | drivers/tty/serial/jsm/jsm_tty.c | 94 |
4 files changed, 28 insertions, 103 deletions
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index cd53bdda77c..529bec6edaf 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 | *************************************************************************/ |
378 | int jsm_tty_write(struct uart_port *port); | ||
379 | int jsm_tty_init(struct jsm_board *); | 372 | int jsm_tty_init(struct jsm_board *); |
380 | int jsm_uart_port_init(struct jsm_board *); | 373 | int jsm_uart_port_init(struct jsm_board *); |
381 | int jsm_remove_uart_port(struct jsm_board *); | 374 | int 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 1cc8cf602af..648b6a3efa3 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 4538c3e3646..bd6e84699e1 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 7a4a914ecff..434bd881fca 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 | */ | ||
127 | static 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 | |||
121 | static void jsm_tty_start_tx(struct uart_port *port) | 134 | static 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 | */ | ||
846 | int 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 | } | ||