Pull tty/serial fixes frpm Greg KH: "Here are two bugfixes for tty stuff for 4.11-rc2. One of them resolves the pretty bad bug in the n_hdlc code that Alexander Popov found and fixed and has been reported everywhere. The other just fixes a samsung serial driver issue when DMA fails on some systems. Both have been in linux-next with no reported issues" * tag 'tty-4.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: serial: samsung: Continue to work if DMA request fails tty: n_hdlc: get rid of racy n_hdlc.tbuf
Unified · Split
| @@ -114,7 +114,7 @@ · 113 unmodified lines | ||
| 114 | 114 | #define DEFAULT_TX_BUF_COUNT 3 |
| 115 | 115 | |
| 116 | 116 | struct n_hdlc_buf { |
| 117 | − struct n_hdlc_buf *link; | |
| 117 | + struct list_head list_item; | |
| 118 | 118 | int count; |
| 119 | 119 | char buf[1]; |
| 120 | 120 | }; |
| @@ -122,8 +122,7 @@ struct n_hdlc_buf { · 1 unmodified line | ||
| 122 | 122 | #define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe) |
| 123 | 123 | |
| 124 | 124 | struct n_hdlc_buf_list { |
| 125 | − struct n_hdlc_buf *head; | |
| 126 | − struct n_hdlc_buf *tail; | |
| 125 | + struct list_head list; | |
| 127 | 126 | int count; |
| 128 | 127 | spinlock_t spinlock; |
| 129 | 128 | }; |
| @@ -136,7 +135,6 @@ struct n_hdlc_buf_list { · 6 unmodified lines | ||
| 136 | 135 | * @backup_tty - TTY to use if tty gets closed |
| 137 | 136 | * @tbusy - reentrancy flag for tx wakeup code |
| 138 | 137 | * @woke_up - FIXME: describe this field |
| 139 | − * @tbuf - currently transmitting tx buffer | |
| 140 | 138 | * @tx_buf_list - list of pending transmit frame buffers |
| 141 | 139 | * @rx_buf_list - list of received frame buffers |
| 142 | 140 | * @tx_free_buf_list - list unused transmit frame buffers |
| @@ -149,7 +147,6 @@ struct n_hdlc { · 6 unmodified lines | ||
| 149 | 147 | struct tty_struct *backup_tty; |
| 150 | 148 | int tbusy; |
| 151 | 149 | int woke_up; |
| 152 | − struct n_hdlc_buf *tbuf; | |
| 153 | 150 | struct n_hdlc_buf_list tx_buf_list; |
| 154 | 151 | struct n_hdlc_buf_list rx_buf_list; |
| 155 | 152 | struct n_hdlc_buf_list tx_free_buf_list; |
| @@ -159,6 +156,8 @@ struct n_hdlc { · 3 unmodified lines | ||
| 159 | 156 | /* |
| 160 | 157 | * HDLC buffer list manipulation functions |
| 161 | 158 | */ |
| 159 | +static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list, | |
| 160 | + struct n_hdlc_buf *buf); | |
| 162 | 161 | static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, |
| 163 | 162 | struct n_hdlc_buf *buf); |
| 164 | 163 | static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); |
| @@ -208,16 +207,9 @@ static void flush_tx_queue(struct tty_struct *tty) · 43 unmodified lines | ||
| 208 | 207 | { |
| 209 | 208 | struct n_hdlc *n_hdlc = tty2n_hdlc(tty); |
| 210 | 209 | struct n_hdlc_buf *buf; |
| 211 | − unsigned long flags; | |
| 212 | 210 | |
| 213 | 211 | while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list))) |
| 214 | 212 | n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf); |
| 215 | − spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); | |
| 216 | − if (n_hdlc->tbuf) { | |
| 217 | − n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf); | |
| 218 | − n_hdlc->tbuf = NULL; | |
| 219 | − } | |
| 220 | − spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); | |
| 221 | 213 | } |
| 222 | 214 | |
| 223 | 215 | static struct tty_ldisc_ops n_hdlc_ldisc = { |
| @@ -283,7 +275,6 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc) · 59 unmodified lines | ||
| 283 | 275 | } else |
| 284 | 276 | break; |
| 285 | 277 | } |
| 286 | − kfree(n_hdlc->tbuf); | |
| 287 | 278 | kfree(n_hdlc); |
| 288 | 279 | |
| 289 | 280 | } /* end of n_hdlc_release() */ |
| @@ -402,13 +393,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) · 112 unmodified lines | ||
| 402 | 393 | n_hdlc->woke_up = 0; |
| 403 | 394 | spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); |
| 404 | 395 | |
| 405 | − /* get current transmit buffer or get new transmit */ | |
| 406 | − /* buffer from list of pending transmit buffers */ | |
| 407 | − | |
| 408 | − tbuf = n_hdlc->tbuf; | |
| 409 | − if (!tbuf) | |
| 410 | − tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); | |
| 411 | − | |
| 396 | + tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); | |
| 412 | 397 | while (tbuf) { |
| 413 | 398 | if (debuglevel >= DEBUG_LEVEL_INFO) |
| 414 | 399 | printk("%s(%d)sending frame %p, count=%d\n", |
| @@ -420,7 +405,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) · 5 unmodified lines | ||
| 420 | 405 | |
| 421 | 406 | /* rollback was possible and has been done */ |
| 422 | 407 | if (actual == -ERESTARTSYS) { |
| 423 | − n_hdlc->tbuf = tbuf; | |
| 408 | + n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf); | |
| 424 | 409 | break; |
| 425 | 410 | } |
| 426 | 411 | /* if transmit error, throw frame away by */ |
| @@ -435,10 +420,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) · 8 unmodified lines | ||
| 435 | 420 | |
| 436 | 421 | /* free current transmit buffer */ |
| 437 | 422 | n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); |
| 438 | − | |
| 439 | − /* this tx buffer is done */ | |
| 440 | − n_hdlc->tbuf = NULL; | |
| 441 | − | |
| 423 | + | |
| 442 | 424 | /* wait up sleeping writers */ |
| 443 | 425 | wake_up_interruptible(&tty->write_wait); |
| 444 | 426 | |
| @@ -448,10 +430,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) · 3 unmodified lines | ||
| 448 | 430 | if (debuglevel >= DEBUG_LEVEL_INFO) |
| 449 | 431 | printk("%s(%d)frame %p pending\n", |
| 450 | 432 | __FILE__,__LINE__,tbuf); |
| 451 | − | |
| 452 | − /* buffer not accepted by driver */ | |
| 453 | − /* set this buffer as pending buffer */ | |
| 454 | − n_hdlc->tbuf = tbuf; | |
| 433 | + | |
| 434 | + /* | |
| 435 | + * the buffer was not accepted by driver, | |
| 436 | + * return it back into tx queue | |
| 437 | + */ | |
| 438 | + n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf); | |
| 455 | 439 | break; |
| 456 | 440 | } |
| 457 | 441 | } |
| @@ -749,7 +733,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, · 291 unmodified lines | ||
| 749 | 733 | int error = 0; |
| 750 | 734 | int count; |
| 751 | 735 | unsigned long flags; |
| 752 | − | |
| 736 | + struct n_hdlc_buf *buf = NULL; | |
| 737 | + | |
| 753 | 738 | if (debuglevel >= DEBUG_LEVEL_INFO) |
| 754 | 739 | printk("%s(%d)n_hdlc_tty_ioctl() called %d\n", |
| 755 | 740 | __FILE__,__LINE__,cmd); |
| @@ -763,8 +748,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, · 7 unmodified lines | ||
| 763 | 748 | /* report count of read data available */ |
| 764 | 749 | /* in next available frame (if any) */ |
| 765 | 750 | spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags); |
| 766 | − if (n_hdlc->rx_buf_list.head) | |
| 767 | − count = n_hdlc->rx_buf_list.head->count; | |
| 751 | + buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list, | |
| 752 | + struct n_hdlc_buf, list_item); | |
| 753 | + if (buf) | |
| 754 | + count = buf->count; | |
| 768 | 755 | else |
| 769 | 756 | count = 0; |
| 770 | 757 | spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags); |
| @@ -776,8 +763,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, · 5 unmodified lines | ||
| 776 | 763 | count = tty_chars_in_buffer(tty); |
| 777 | 764 | /* add size of next output frame in queue */ |
| 778 | 765 | spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags); |
| 779 | − if (n_hdlc->tx_buf_list.head) | |
| 780 | − count += n_hdlc->tx_buf_list.head->count; | |
| 766 | + buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list, | |
| 767 | + struct n_hdlc_buf, list_item); | |
| 768 | + if (buf) | |
| 769 | + count += buf->count; | |
| 781 | 770 | spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags); |
| 782 | 771 | error = put_user(count, (int __user *)arg); |
| 783 | 772 | break; |
| @@ -825,14 +814,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, · 41 unmodified lines | ||
| 825 | 814 | poll_wait(filp, &tty->write_wait, wait); |
| 826 | 815 | |
| 827 | 816 | /* set bits for operations that won't block */ |
| 828 | − if (n_hdlc->rx_buf_list.head) | |
| 817 | + if (!list_empty(&n_hdlc->rx_buf_list.list)) | |
| 829 | 818 | mask |= POLLIN | POLLRDNORM; /* readable */ |
| 830 | 819 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) |
| 831 | 820 | mask |= POLLHUP; |
| 832 | 821 | if (tty_hung_up_p(filp)) |
| 833 | 822 | mask |= POLLHUP; |
| 834 | 823 | if (!tty_is_writelocked(tty) && |
| 835 | − n_hdlc->tx_free_buf_list.head) | |
| 824 | + !list_empty(&n_hdlc->tx_free_buf_list.list)) | |
| 836 | 825 | mask |= POLLOUT | POLLWRNORM; /* writable */ |
| 837 | 826 | } |
| 838 | 827 | return mask; |
| @@ -856,7 +845,12 @@ static struct n_hdlc *n_hdlc_alloc(void) · 17 unmodified lines | ||
| 856 | 845 | spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock); |
| 857 | 846 | spin_lock_init(&n_hdlc->rx_buf_list.spinlock); |
| 858 | 847 | spin_lock_init(&n_hdlc->tx_buf_list.spinlock); |
| 859 | − | |
| 848 | + | |
| 849 | + INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list); | |
| 850 | + INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list); | |
| 851 | + INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list); | |
| 852 | + INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list); | |
| 853 | + | |
| 860 | 854 | /* allocate free rx buffer list */ |
| 861 | 855 | for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) { |
| 862 | 856 | buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL); |
| @@ -883,54 +877,66 @@ static struct n_hdlc *n_hdlc_alloc(void) · 20 unmodified lines | ||
| 883 | 877 | |
| 884 | 878 | } /* end of n_hdlc_alloc() */ |
| 885 | 879 | |
| 880 | +/** | |
| 881 | + * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list | |
| 882 | + * @buf_list - pointer to the buffer list | |
| 883 | + * @buf - pointer to the buffer | |
| 884 | + */ | |
| 885 | +static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list, | |
| 886 | + struct n_hdlc_buf *buf) | |
| 887 | +{ | |
| 888 | + unsigned long flags; | |
| 889 | + | |
| 890 | + spin_lock_irqsave(&buf_list->spinlock, flags); | |
| 891 | + | |
| 892 | + list_add(&buf->list_item, &buf_list->list); | |
| 893 | + buf_list->count++; | |
| 894 | + | |
| 895 | + spin_unlock_irqrestore(&buf_list->spinlock, flags); | |
| 896 | +} | |
| 897 | + | |
| 886 | 898 | /** |
| 887 | 899 | * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list |
| 888 | − * @list - pointer to buffer list | |
| 900 | + * @buf_list - pointer to buffer list | |
| 889 | 901 | * @buf - pointer to buffer |
| 890 | 902 | */ |
| 891 | −static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, | |
| 903 | +static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list, | |
| 892 | 904 | struct n_hdlc_buf *buf) |
| 893 | 905 | { |
| 894 | 906 | unsigned long flags; |
| 895 | − spin_lock_irqsave(&list->spinlock,flags); | |
| 896 | − | |
| 897 | − buf->link=NULL; | |
| 898 | − if (list->tail) | |
| 899 | − list->tail->link = buf; | |
| 900 | − else | |
| 901 | − list->head = buf; | |
| 902 | − list->tail = buf; | |
| 903 | − (list->count)++; | |
| 904 | − | |
| 905 | − spin_unlock_irqrestore(&list->spinlock,flags); | |
| 906 | − | |
| 907 | + | |
| 908 | + spin_lock_irqsave(&buf_list->spinlock, flags); | |
| 909 | + | |
| 910 | + list_add_tail(&buf->list_item, &buf_list->list); | |
| 911 | + buf_list->count++; | |
| 912 | + | |
| 913 | + spin_unlock_irqrestore(&buf_list->spinlock, flags); | |
| 907 | 914 | } /* end of n_hdlc_buf_put() */ |
| 908 | 915 | |
| 909 | 916 | /** |
| 910 | 917 | * n_hdlc_buf_get - remove and return an HDLC buffer from list |
| 911 | − * @list - pointer to HDLC buffer list | |
| 918 | + * @buf_list - pointer to HDLC buffer list | |
| 912 | 919 | * |
| 913 | 920 | * Remove and return an HDLC buffer from the head of the specified HDLC buffer |
| 914 | 921 | * list. |
| 915 | 922 | * Returns a pointer to HDLC buffer if available, otherwise %NULL. |
| 916 | 923 | */ |
| 917 | −static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list) | |
| 924 | +static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) | |
| 918 | 925 | { |
| 919 | 926 | unsigned long flags; |
| 920 | 927 | struct n_hdlc_buf *buf; |
| 921 | − spin_lock_irqsave(&list->spinlock,flags); | |
| 922 | − | |
| 923 | − buf = list->head; | |
| 928 | + | |
| 929 | + spin_lock_irqsave(&buf_list->spinlock, flags); | |
| 930 | + | |
| 931 | + buf = list_first_entry_or_null(&buf_list->list, | |
| 932 | + struct n_hdlc_buf, list_item); | |
| 924 | 933 | if (buf) { |
| 925 | − list->head = buf->link; | |
| 926 | − (list->count)--; | |
| 934 | + list_del(&buf->list_item); | |
| 935 | + buf_list->count--; | |
| 927 | 936 | } |
| 928 | − if (!list->head) | |
| 929 | − list->tail = NULL; | |
| 930 | − | |
| 931 | − spin_unlock_irqrestore(&list->spinlock,flags); | |
| 937 | + | |
| 938 | + spin_unlock_irqrestore(&buf_list->spinlock, flags); | |
| 932 | 939 | return buf; |
| 933 | − | |
| 934 | 940 | } /* end of n_hdlc_buf_get() */ |
| 935 | 941 | |
| 936 | 942 | static char hdlc_banner[] __initdata = |
| @@ -1031,8 +1031,10 @@ static int s3c64xx_serial_startup(struct uart_port *port) · 1030 unmodified lines | ||
| 1031 | 1031 | if (ourport->dma) { |
| 1032 | 1032 | ret = s3c24xx_serial_request_dma(ourport); |
| 1033 | 1033 | if (ret < 0) { |
| 1034 | − dev_warn(port->dev, "DMA request failed\n"); | |
| 1035 | − return ret; | |
| 1034 | + dev_warn(port->dev, | |
| 1035 | + "DMA request failed, DMA will not be used\n"); | |
| 1036 | + devm_kfree(port->dev, ourport->dma); | |
| 1037 | + ourport->dma = NULL; | |
| 1036 | 1038 | } |
| 1037 | 1039 | } |
| 1038 | 1040 | |