diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-06-17 10:56:11 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-06-17 10:56:11 -0700 |
| commit | 716f37f0b1935f62d717d0ca930453e10ddb4f08 (patch) | |
| tree | 4a8cf7152623f985bad35ed9f700167602f9e520 /tty | |
| parent | 257f39f2ae41a2830e6aac990ffcf9d419875ff5 (diff) | |
| download | patches-716f37f0b1935f62d717d0ca930453e10ddb4f08.tar.gz | |
usb patches and 2 serial ones
Diffstat (limited to 'tty')
| -rw-r--r-- | tty/serial-fix-wakup-races-in-the-mrst_max3110-driver.patch | 155 | ||||
| -rw-r--r-- | tty/serial-replace-open-coded-mutex-with-a-real-mutex-in-mrst_max3110.c.patch | 81 |
2 files changed, 236 insertions, 0 deletions
diff --git a/tty/serial-fix-wakup-races-in-the-mrst_max3110-driver.patch b/tty/serial-fix-wakup-races-in-the-mrst_max3110-driver.patch new file mode 100644 index 00000000000000..44de4ed4764898 --- /dev/null +++ b/tty/serial-fix-wakup-races-in-the-mrst_max3110-driver.patch @@ -0,0 +1,155 @@ +From alan@linux.intel.com Thu Jun 17 10:32:38 2010 +From: Arjan van de Ven <arjan@linux.intel.com> +Date: Thu, 17 Jun 2010 11:02:15 +0100 +Subject: serial: fix wakup races in the mrst_max3110 driver +To: greg@kroah.com, linux-serial@vger.kernel.org +Message-ID: <20100617100213.4379.16616.stgit@localhost.localdomain> + + +From: Arjan van de Ven <arjan@linux.intel.com> + +The mrst_max3110 driver had a set of unsafe wakeup sequences +along the following line: + +if (!atomic_read(&foo)) { + atomic_set(&foo, 1); + wake_up(worker_thread); +} +and the worker thread would do + +if (atomic_read(&foo)) { + do_work(); + atomic_set(&foo, 0); +} + +which can result in various missed wakups due to test-then-set races, +as well as due to clear-after-work instead of clear-before-work. + +This patch fixes these races by using the proper bit test-and-set operations, +and by doing clear-before-work. + +Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/mrst_max3110.c | 46 ++++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 28 deletions(-) + +--- a/drivers/serial/mrst_max3110.c ++++ b/drivers/serial/mrst_max3110.c +@@ -48,6 +48,10 @@ + + #define PR_FMT "mrst_max3110: " + ++#define UART_TX_NEEDED 1 ++#define CON_TX_NEEDED 2 ++#define BIT_IRQ_PENDING 3 ++ + struct uart_max3110 { + struct uart_port port; + struct spi_device *spi; +@@ -63,15 +67,13 @@ struct uart_max3110 { + u8 clock; + u8 parity, word_7bits; + +- atomic_t uart_tx_need; ++ unsigned long uart_flags; + + /* console related */ + struct circ_buf con_xmit; +- atomic_t con_tx_need; + + /* irq related */ + u16 irq; +- atomic_t irq_pending; + }; + + /* global data structure, may need be removed */ +@@ -176,10 +178,9 @@ static void serial_m3110_con_putchar(str + xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1); + } + +- if (!atomic_read(&max->con_tx_need)) { +- atomic_set(&max->con_tx_need, 1); ++ ++ if (!test_and_set_bit(CON_TX_NEEDED, &max->uart_flags)) + wake_up_process(max->main_thread); +- } + } + + /* +@@ -318,10 +319,8 @@ static void serial_m3110_start_tx(struct + struct uart_max3110 *max = + container_of(port, struct uart_max3110, port); + +- if (!atomic_read(&max->uart_tx_need)) { +- atomic_set(&max->uart_tx_need, 1); ++ if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags)) + wake_up_process(max->main_thread); +- } + } + + static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len) +@@ -392,32 +391,23 @@ static int max3110_main_thread(void *_ma + pr_info(PR_FMT "start main thread\n"); + + do { +- wait_event_interruptible(*wq, (atomic_read(&max->irq_pending) || +- atomic_read(&max->con_tx_need) || +- atomic_read(&max->uart_tx_need)) || +- kthread_should_stop()); ++ wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop()); + + mutex_lock(&max->thread_mutex); + +-#ifdef CONFIG_MRST_MAX3110_IRQ +- if (atomic_read(&max->irq_pending)) { ++ if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags)) + max3110_console_receive(max); +- atomic_set(&max->irq_pending, 0); +- } +-#endif + + /* first handle console output */ +- if (atomic_read(&max->con_tx_need)) { ++ if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags)) + send_circ_buf(max, xmit); +- atomic_set(&max->con_tx_need, 0); +- } + + /* handle uart output */ +- if (atomic_read(&max->uart_tx_need)) { ++ if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags)) + transmit_char(max); +- atomic_set(&max->uart_tx_need, 0); +- } ++ + mutex_unlock(&max->thread_mutex); ++ + } while (!kthread_should_stop()); + + return ret; +@@ -430,10 +420,9 @@ static irqreturn_t serial_m3110_irq(int + + /* max3110's irq is a falling edge, not level triggered, + * so no need to disable the irq */ +- if (!atomic_read(&max->irq_pending)) { +- atomic_inc(&max->irq_pending); ++ if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags)) + wake_up_process(max->main_thread); +- } ++ + return IRQ_HANDLED; + } + #else +@@ -753,7 +742,8 @@ static int serial_m3110_probe(struct spi + max->baud = 0; + + max->cur_conf = 0; +- atomic_set(&max->irq_pending, 0); ++ max->uart_flags = 0; ++ + /* Check if reading configuration register returns something sane */ + + res = RC_TAG; diff --git a/tty/serial-replace-open-coded-mutex-with-a-real-mutex-in-mrst_max3110.c.patch b/tty/serial-replace-open-coded-mutex-with-a-real-mutex-in-mrst_max3110.c.patch new file mode 100644 index 00000000000000..bc97764a0a9e78 --- /dev/null +++ b/tty/serial-replace-open-coded-mutex-with-a-real-mutex-in-mrst_max3110.c.patch @@ -0,0 +1,81 @@ +From alan@linux.intel.com Thu Jun 17 10:32:04 2010 +From: Arjan van de Ven <arjan@linux.intel.com> +Date: Thu, 17 Jun 2010 11:02:06 +0100 +Subject: serial: replace open coded mutex with a real mutex in mrst_max3110.c +To: greg@kroah.com, linux-serial@vger.kernel.org +Message-ID: <20100617100204.4379.5286.stgit@localhost.localdomain> + + +From: Arjan van de Ven <arjan@linux.intel.com> + +The mrst_max3110.c driver uses an open coded, non atomic variable +to create exclusion between two of its worker threads. More than that, +while the main thread does a proper set-work-clear sequence, +the other thread only does a test, with the result that no actual +exclusion is happening. + +this patch replaces this open coded variable with a proper mutex + +in addition, the 'lock' spinlock is removed from the per adapter structure, +the lock was only ever initialized but never used + +Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/mrst_max3110.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +--- a/drivers/serial/mrst_max3110.c ++++ b/drivers/serial/mrst_max3110.c +@@ -56,8 +56,7 @@ struct uart_max3110 { + wait_queue_head_t wq; + struct task_struct *main_thread; + struct task_struct *read_thread; +- int mthread_up; +- spinlock_t lock; ++ struct mutex thread_mutex;; + + u32 baud; + u16 cur_conf; +@@ -397,7 +396,8 @@ static int max3110_main_thread(void *_ma + atomic_read(&max->con_tx_need) || + atomic_read(&max->uart_tx_need)) || + kthread_should_stop()); +- max->mthread_up = 1; ++ ++ mutex_lock(&max->thread_mutex); + + #ifdef CONFIG_MRST_MAX3110_IRQ + if (atomic_read(&max->irq_pending)) { +@@ -417,7 +417,7 @@ static int max3110_main_thread(void *_ma + transmit_char(max); + atomic_set(&max->uart_tx_need, 0); + } +- max->mthread_up = 0; ++ mutex_unlock(&max->thread_mutex); + } while (!kthread_should_stop()); + + return ret; +@@ -444,8 +444,9 @@ static int max3110_read_thread(void *_ma + + pr_info(PR_FMT "start read thread\n"); + do { +- if (!max->mthread_up) +- max3110_console_receive(max); ++ mutex_lock(&max->thread_mutex); ++ max3110_console_receive(max); ++ mutex_unlock(&max->thread_mutex); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 20); +@@ -745,7 +746,7 @@ static int serial_m3110_probe(struct spi + max->name = spi->modalias; /* use spi name as the name */ + max->irq = (u16)spi->irq; + +- spin_lock_init(&max->lock); ++ mutex_init(&max->thread_mutex); + + max->word_7bits = 0; + max->parity = 0; |
