aboutsummaryrefslogtreecommitdiffstats
path: root/tty
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2010-06-17 10:56:11 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-06-17 10:56:11 -0700
commit716f37f0b1935f62d717d0ca930453e10ddb4f08 (patch)
tree4a8cf7152623f985bad35ed9f700167602f9e520 /tty
parent257f39f2ae41a2830e6aac990ffcf9d419875ff5 (diff)
downloadpatches-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.patch155
-rw-r--r--tty/serial-replace-open-coded-mutex-with-a-real-mutex-in-mrst_max3110.c.patch81
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;