aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-07 09:46:29 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 02:56:20 -0400
commit46c501473d0a6fa62435dfd65c6884e1fd63b327 (patch)
tree00cfe53c4542e3f44e86b28245b33dcdda137e90 /drivers/net/wimax
parenta0beba21c3e2dff9a31739f1660ba3ff8c7150a7 (diff)
wimax/i2400m: fix oops in TX when tearing down the device
All the entry points into the TX module should check if the device has been torn down. Otherwise, when the device resets or shuts down, there are windows when a call to i2400m_tx*() will oops the system. For that, make i2400m_tx_release() set i2400m->tx_buf to NULL under the tx_lock. Then, any entry point [i2400m_tx(), _tx_msg_sent(), _tx_msg_get()] will check for i2400m->tx_buf to be NULL and exit gracefully. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net/wimax')
-rw-r--r--drivers/net/wimax/i2400m/sdio-tx.c5
-rw-r--r--drivers/net/wimax/i2400m/tx.c18
2 files changed, 21 insertions, 2 deletions
diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c
index 5105a5ebc44f..de66d068c9cb 100644
--- a/drivers/net/wimax/i2400m/sdio-tx.c
+++ b/drivers/net/wimax/i2400m/sdio-tx.c
@@ -149,5 +149,8 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
149 149
150void i2400ms_tx_release(struct i2400ms *i2400ms) 150void i2400ms_tx_release(struct i2400ms *i2400ms)
151{ 151{
152 destroy_workqueue(i2400ms->tx_workqueue); 152 if (i2400ms->tx_workqueue) {
153 destroy_workqueue(i2400ms->tx_workqueue);
154 i2400ms->tx_workqueue = NULL;
155 }
153} 156}
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 8c2080248aec..54480e8947f1 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -642,6 +642,9 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
642 * current one is out of payload slots or we have a singleton, 642 * current one is out of payload slots or we have a singleton,
643 * close it and start a new one */ 643 * close it and start a new one */
644 spin_lock_irqsave(&i2400m->tx_lock, flags); 644 spin_lock_irqsave(&i2400m->tx_lock, flags);
645 result = -ESHUTDOWN;
646 if (i2400m->tx_buf == NULL)
647 goto error_tx_new;
645try_new: 648try_new:
646 if (unlikely(i2400m->tx_msg == NULL)) 649 if (unlikely(i2400m->tx_msg == NULL))
647 i2400m_tx_new(i2400m); 650 i2400m_tx_new(i2400m);
@@ -697,7 +700,10 @@ try_new:
697 } 700 }
698error_tx_new: 701error_tx_new:
699 spin_unlock_irqrestore(&i2400m->tx_lock, flags); 702 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
700 i2400m->bus_tx_kick(i2400m); /* always kick, might free up space */ 703 /* kick in most cases, except when the TX subsys is down, as
704 * it might free space */
705 if (likely(result != -ESHUTDOWN))
706 i2400m->bus_tx_kick(i2400m);
701 d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n", 707 d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n",
702 i2400m, buf, buf_len, pl_type, result); 708 i2400m, buf, buf_len, pl_type, result);
703 return result; 709 return result;
@@ -740,6 +746,9 @@ struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m,
740 746
741 d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size); 747 d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size);
742 spin_lock_irqsave(&i2400m->tx_lock, flags); 748 spin_lock_irqsave(&i2400m->tx_lock, flags);
749 tx_msg_moved = NULL;
750 if (i2400m->tx_buf == NULL)
751 goto out_unlock;
743skip: 752skip:
744 tx_msg_moved = NULL; 753 tx_msg_moved = NULL;
745 if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */ 754 if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */
@@ -829,6 +838,8 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
829 838
830 d_fnstart(3, dev, "(i2400m %p)\n", i2400m); 839 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
831 spin_lock_irqsave(&i2400m->tx_lock, flags); 840 spin_lock_irqsave(&i2400m->tx_lock, flags);
841 if (i2400m->tx_buf == NULL)
842 goto out_unlock;
832 i2400m->tx_out += i2400m->tx_msg_size; 843 i2400m->tx_out += i2400m->tx_msg_size;
833 d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size); 844 d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size);
834 i2400m->tx_msg_size = 0; 845 i2400m->tx_msg_size = 0;
@@ -837,6 +848,7 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
837 n = i2400m->tx_out / I2400M_TX_BUF_SIZE; 848 n = i2400m->tx_out / I2400M_TX_BUF_SIZE;
838 i2400m->tx_out %= I2400M_TX_BUF_SIZE; 849 i2400m->tx_out %= I2400M_TX_BUF_SIZE;
839 i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; 850 i2400m->tx_in -= n * I2400M_TX_BUF_SIZE;
851out_unlock:
840 spin_unlock_irqrestore(&i2400m->tx_lock, flags); 852 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
841 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); 853 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
842} 854}
@@ -876,5 +888,9 @@ int i2400m_tx_setup(struct i2400m *i2400m)
876 */ 888 */
877void i2400m_tx_release(struct i2400m *i2400m) 889void i2400m_tx_release(struct i2400m *i2400m)
878{ 890{
891 unsigned long flags;
892 spin_lock_irqsave(&i2400m->tx_lock, flags);
879 kfree(i2400m->tx_buf); 893 kfree(i2400m->tx_buf);
894 i2400m->tx_buf = NULL;
895 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
880} 896}