diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/card/sdio_uart.c | 93 |
1 files changed, 30 insertions, 63 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index f53755533e7e..3fab78ba8952 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/gfp.h> | 37 | #include <linux/gfp.h> |
| 38 | #include <linux/tty.h> | 38 | #include <linux/tty.h> |
| 39 | #include <linux/tty_flip.h> | 39 | #include <linux/tty_flip.h> |
| 40 | #include <linux/kfifo.h> | ||
| 40 | 41 | ||
| 41 | #include <linux/mmc/core.h> | 42 | #include <linux/mmc/core.h> |
| 42 | #include <linux/mmc/card.h> | 43 | #include <linux/mmc/card.h> |
| @@ -47,19 +48,9 @@ | |||
| 47 | #define UART_NR 8 /* Number of UARTs this driver can handle */ | 48 | #define UART_NR 8 /* Number of UARTs this driver can handle */ |
| 48 | 49 | ||
| 49 | 50 | ||
| 50 | #define UART_XMIT_SIZE PAGE_SIZE | 51 | #define FIFO_SIZE PAGE_SIZE |
| 51 | #define WAKEUP_CHARS 256 | 52 | #define WAKEUP_CHARS 256 |
| 52 | 53 | ||
| 53 | #define circ_empty(circ) ((circ)->head == (circ)->tail) | ||
| 54 | #define circ_clear(circ) ((circ)->head = (circ)->tail = 0) | ||
| 55 | |||
| 56 | #define circ_chars_pending(circ) \ | ||
| 57 | (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) | ||
| 58 | |||
| 59 | #define circ_chars_free(circ) \ | ||
| 60 | (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) | ||
| 61 | |||
| 62 | |||
| 63 | struct uart_icount { | 54 | struct uart_icount { |
| 64 | __u32 cts; | 55 | __u32 cts; |
| 65 | __u32 dsr; | 56 | __u32 dsr; |
| @@ -82,7 +73,7 @@ struct sdio_uart_port { | |||
| 82 | struct mutex func_lock; | 73 | struct mutex func_lock; |
| 83 | struct task_struct *in_sdio_uart_irq; | 74 | struct task_struct *in_sdio_uart_irq; |
| 84 | unsigned int regs_offset; | 75 | unsigned int regs_offset; |
| 85 | struct circ_buf xmit; | 76 | struct kfifo xmit_fifo; |
| 86 | spinlock_t write_lock; | 77 | spinlock_t write_lock; |
| 87 | struct uart_icount icount; | 78 | struct uart_icount icount; |
| 88 | unsigned int uartclk; | 79 | unsigned int uartclk; |
| @@ -105,6 +96,8 @@ static int sdio_uart_add_port(struct sdio_uart_port *port) | |||
| 105 | kref_init(&port->kref); | 96 | kref_init(&port->kref); |
| 106 | mutex_init(&port->func_lock); | 97 | mutex_init(&port->func_lock); |
| 107 | spin_lock_init(&port->write_lock); | 98 | spin_lock_init(&port->write_lock); |
| 99 | if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL)) | ||
| 100 | return -ENOMEM; | ||
| 108 | 101 | ||
| 109 | spin_lock(&sdio_uart_table_lock); | 102 | spin_lock(&sdio_uart_table_lock); |
| 110 | for (index = 0; index < UART_NR; index++) { | 103 | for (index = 0; index < UART_NR; index++) { |
| @@ -140,6 +133,7 @@ static void sdio_uart_port_destroy(struct kref *kref) | |||
| 140 | { | 133 | { |
| 141 | struct sdio_uart_port *port = | 134 | struct sdio_uart_port *port = |
| 142 | container_of(kref, struct sdio_uart_port, kref); | 135 | container_of(kref, struct sdio_uart_port, kref); |
| 136 | kfifo_free(&port->xmit_fifo); | ||
| 143 | kfree(port); | 137 | kfree(port); |
| 144 | } | 138 | } |
| 145 | 139 | ||
| @@ -456,9 +450,11 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, | |||
| 456 | 450 | ||
| 457 | static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | 451 | static void sdio_uart_transmit_chars(struct sdio_uart_port *port) |
| 458 | { | 452 | { |
| 459 | struct circ_buf *xmit = &port->xmit; | 453 | struct kfifo *xmit = &port->xmit_fifo; |
| 460 | int count; | 454 | int count; |
| 461 | struct tty_struct *tty; | 455 | struct tty_struct *tty; |
| 456 | u8 iobuf[16]; | ||
| 457 | int len; | ||
| 462 | 458 | ||
| 463 | if (port->x_char) { | 459 | if (port->x_char) { |
| 464 | sdio_out(port, UART_TX, port->x_char); | 460 | sdio_out(port, UART_TX, port->x_char); |
| @@ -469,27 +465,25 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | |||
| 469 | 465 | ||
| 470 | tty = tty_port_tty_get(&port->port); | 466 | tty = tty_port_tty_get(&port->port); |
| 471 | 467 | ||
| 472 | if (tty == NULL || circ_empty(xmit) || | 468 | if (tty == NULL || !kfifo_len(xmit) || |
| 473 | tty->stopped || tty->hw_stopped) { | 469 | tty->stopped || tty->hw_stopped) { |
| 474 | sdio_uart_stop_tx(port); | 470 | sdio_uart_stop_tx(port); |
| 475 | tty_kref_put(tty); | 471 | tty_kref_put(tty); |
| 476 | return; | 472 | return; |
| 477 | } | 473 | } |
| 478 | 474 | ||
| 479 | count = 16; | 475 | len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock); |
| 480 | do { | 476 | for (count = 0; count < len; count++) { |
| 481 | sdio_out(port, UART_TX, xmit->buf[xmit->tail]); | 477 | sdio_out(port, UART_TX, iobuf[count]); |
| 482 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
| 483 | port->icount.tx++; | 478 | port->icount.tx++; |
| 484 | if (circ_empty(xmit)) | 479 | } |
| 485 | break; | ||
| 486 | } while (--count > 0); | ||
| 487 | 480 | ||
| 488 | if (circ_chars_pending(xmit) < WAKEUP_CHARS) | 481 | len = kfifo_len(xmit); |
| 482 | if (len < WAKEUP_CHARS) { | ||
| 489 | tty_wakeup(tty); | 483 | tty_wakeup(tty); |
| 490 | 484 | if (len == 0) | |
| 491 | if (circ_empty(xmit)) | 485 | sdio_uart_stop_tx(port); |
| 492 | sdio_uart_stop_tx(port); | 486 | } |
| 493 | tty_kref_put(tty); | 487 | tty_kref_put(tty); |
| 494 | } | 488 | } |
| 495 | 489 | ||
| @@ -632,7 +626,6 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) | |||
| 632 | { | 626 | { |
| 633 | struct sdio_uart_port *port = | 627 | struct sdio_uart_port *port = |
| 634 | container_of(tport, struct sdio_uart_port, port); | 628 | container_of(tport, struct sdio_uart_port, port); |
| 635 | unsigned long page; | ||
| 636 | int ret; | 629 | int ret; |
| 637 | 630 | ||
| 638 | /* | 631 | /* |
| @@ -641,22 +634,17 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) | |||
| 641 | */ | 634 | */ |
| 642 | set_bit(TTY_IO_ERROR, &tty->flags); | 635 | set_bit(TTY_IO_ERROR, &tty->flags); |
| 643 | 636 | ||
| 644 | /* Initialise and allocate the transmit buffer. */ | 637 | kfifo_reset(&port->xmit_fifo); |
| 645 | page = __get_free_page(GFP_KERNEL); | ||
| 646 | if (!page) | ||
| 647 | return -ENOMEM; | ||
| 648 | port->xmit.buf = (unsigned char *)page; | ||
| 649 | circ_clear(&port->xmit); | ||
| 650 | 638 | ||
| 651 | ret = sdio_uart_claim_func(port); | 639 | ret = sdio_uart_claim_func(port); |
| 652 | if (ret) | 640 | if (ret) |
| 653 | goto err1; | 641 | return ret; |
| 654 | ret = sdio_enable_func(port->func); | 642 | ret = sdio_enable_func(port->func); |
| 655 | if (ret) | 643 | if (ret) |
| 656 | goto err2; | 644 | goto err1; |
| 657 | ret = sdio_claim_irq(port->func, sdio_uart_irq); | 645 | ret = sdio_claim_irq(port->func, sdio_uart_irq); |
| 658 | if (ret) | 646 | if (ret) |
| 659 | goto err3; | 647 | goto err2; |
| 660 | 648 | ||
| 661 | /* | 649 | /* |
| 662 | * Clear the FIFO buffers and disable them. | 650 | * Clear the FIFO buffers and disable them. |
| @@ -700,12 +688,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) | |||
| 700 | sdio_uart_release_func(port); | 688 | sdio_uart_release_func(port); |
| 701 | return 0; | 689 | return 0; |
| 702 | 690 | ||
| 703 | err3: | ||
| 704 | sdio_disable_func(port->func); | ||
| 705 | err2: | 691 | err2: |
| 706 | sdio_uart_release_func(port); | 692 | sdio_disable_func(port->func); |
| 707 | err1: | 693 | err1: |
| 708 | free_page((unsigned long)port->xmit.buf); | 694 | sdio_uart_release_func(port); |
| 709 | return ret; | 695 | return ret; |
| 710 | } | 696 | } |
| 711 | 697 | ||
| @@ -727,7 +713,7 @@ static void sdio_uart_shutdown(struct tty_port *tport) | |||
| 727 | 713 | ||
| 728 | ret = sdio_uart_claim_func(port); | 714 | ret = sdio_uart_claim_func(port); |
| 729 | if (ret) | 715 | if (ret) |
| 730 | goto skip; | 716 | return; |
| 731 | 717 | ||
| 732 | sdio_uart_stop_rx(port); | 718 | sdio_uart_stop_rx(port); |
| 733 | 719 | ||
| @@ -749,10 +735,6 @@ static void sdio_uart_shutdown(struct tty_port *tport) | |||
| 749 | sdio_disable_func(port->func); | 735 | sdio_disable_func(port->func); |
| 750 | 736 | ||
| 751 | sdio_uart_release_func(port); | 737 | sdio_uart_release_func(port); |
| 752 | |||
| 753 | skip: | ||
| 754 | /* Free the transmit buffer page. */ | ||
| 755 | free_page((unsigned long)port->xmit.buf); | ||
| 756 | } | 738 | } |
| 757 | 739 | ||
| 758 | /** | 740 | /** |
| @@ -822,27 +804,12 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, | |||
| 822 | int count) | 804 | int count) |
| 823 | { | 805 | { |
| 824 | struct sdio_uart_port *port = tty->driver_data; | 806 | struct sdio_uart_port *port = tty->driver_data; |
| 825 | struct circ_buf *circ = &port->xmit; | 807 | int ret; |
| 826 | int c, ret = 0; | ||
| 827 | 808 | ||
| 828 | if (!port->func) | 809 | if (!port->func) |
| 829 | return -ENODEV; | 810 | return -ENODEV; |
| 830 | 811 | ||
| 831 | spin_lock(&port->write_lock); | 812 | ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock); |
| 832 | while (1) { | ||
| 833 | c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); | ||
| 834 | if (count < c) | ||
| 835 | c = count; | ||
| 836 | if (c <= 0) | ||
| 837 | break; | ||
| 838 | memcpy(circ->buf + circ->head, buf, c); | ||
| 839 | circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); | ||
| 840 | buf += c; | ||
| 841 | count -= c; | ||
| 842 | ret += c; | ||
| 843 | } | ||
| 844 | spin_unlock(&port->write_lock); | ||
| 845 | |||
| 846 | if (!(port->ier & UART_IER_THRI)) { | 813 | if (!(port->ier & UART_IER_THRI)) { |
| 847 | int err = sdio_uart_claim_func(port); | 814 | int err = sdio_uart_claim_func(port); |
| 848 | if (!err) { | 815 | if (!err) { |
| @@ -859,13 +826,13 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, | |||
| 859 | static int sdio_uart_write_room(struct tty_struct *tty) | 826 | static int sdio_uart_write_room(struct tty_struct *tty) |
| 860 | { | 827 | { |
| 861 | struct sdio_uart_port *port = tty->driver_data; | 828 | struct sdio_uart_port *port = tty->driver_data; |
| 862 | return port ? circ_chars_free(&port->xmit) : 0; | 829 | return FIFO_SIZE - kfifo_len(&port->xmit_fifo); |
| 863 | } | 830 | } |
| 864 | 831 | ||
| 865 | static int sdio_uart_chars_in_buffer(struct tty_struct *tty) | 832 | static int sdio_uart_chars_in_buffer(struct tty_struct *tty) |
| 866 | { | 833 | { |
| 867 | struct sdio_uart_port *port = tty->driver_data; | 834 | struct sdio_uart_port *port = tty->driver_data; |
| 868 | return port ? circ_chars_pending(&port->xmit) : 0; | 835 | return kfifo_len(&port->xmit_fifo); |
| 869 | } | 836 | } |
| 870 | 837 | ||
| 871 | static void sdio_uart_send_xchar(struct tty_struct *tty, char ch) | 838 | static void sdio_uart_send_xchar(struct tty_struct *tty, char ch) |
