aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-15 05:16:08 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-11-03 15:49:36 -0500
commit5ab5a7215a0cfd40572a9f09276ebcb071ee6fb7 (patch)
tree3847969bc4148ecba2eea45aaf3a5706350ca892 /drivers/net
parentc931ceeb780560ff652a8f9875f88778439ee87e (diff)
wimax/i2400m: fix device getting stuck in IDLE mode
The i2400m, when conected, will negotiate with the WiMAX basestation to put the link in IDLE mode when it is not being used. Upon RX/TX traffic, the link has to be restablished and that might require some crypto handshakes and maybe a DHCP renew. This process might take up to 20 (!) seconds and in some cases we were seeing network watchdog warnings that weren't needed. So the network watchdog timeout is updated to be slightly above that 20s threshold. As well, the driver itself will double check if the device is stuck in IDLE mode -- if that happens, the device will be reset (in this case the queue is also woken up to remove bogus--once the device is reset--warnings). Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wimax/i2400m/netdev.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index f67af4291f8c..599aa4eb9baa 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -89,7 +89,10 @@ enum {
89 * The MTU is 1400 or less 89 * The MTU is 1400 or less
90 */ 90 */
91 I2400M_MAX_MTU = 1400, 91 I2400M_MAX_MTU = 1400,
92 I2400M_TX_TIMEOUT = HZ, 92 /* 20 secs? yep, this is the maximum timeout that the device
93 * might take to get out of IDLE / negotiate it with the base
94 * station. We add 1sec for good measure. */
95 I2400M_TX_TIMEOUT = 21 * HZ,
93 I2400M_TX_QLEN = 5, 96 I2400M_TX_QLEN = 5,
94}; 97};
95 98
@@ -151,6 +154,7 @@ void i2400m_wake_tx_work(struct work_struct *ws)
151{ 154{
152 int result; 155 int result;
153 struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws); 156 struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
157 struct net_device *net_dev = i2400m->wimax_dev.net_dev;
154 struct device *dev = i2400m_dev(i2400m); 158 struct device *dev = i2400m_dev(i2400m);
155 struct sk_buff *skb = i2400m->wake_tx_skb; 159 struct sk_buff *skb = i2400m->wake_tx_skb;
156 unsigned long flags; 160 unsigned long flags;
@@ -166,6 +170,11 @@ void i2400m_wake_tx_work(struct work_struct *ws)
166 dev_err(dev, "WAKE&TX: skb dissapeared!\n"); 170 dev_err(dev, "WAKE&TX: skb dissapeared!\n");
167 goto out_put; 171 goto out_put;
168 } 172 }
173 /* If we have, somehow, lost the connection after this was
174 * queued, don't do anything; this might be the device got
175 * reset or just disconnected. */
176 if (unlikely(!netif_carrier_ok(net_dev)))
177 goto out_kfree;
169 result = i2400m_cmd_exit_idle(i2400m); 178 result = i2400m_cmd_exit_idle(i2400m);
170 if (result == -EILSEQ) 179 if (result == -EILSEQ)
171 result = 0; 180 result = 0;
@@ -176,7 +185,8 @@ void i2400m_wake_tx_work(struct work_struct *ws)
176 goto error; 185 goto error;
177 } 186 }
178 result = wait_event_timeout(i2400m->state_wq, 187 result = wait_event_timeout(i2400m->state_wq,
179 i2400m->state != I2400M_SS_IDLE, 5 * HZ); 188 i2400m->state != I2400M_SS_IDLE,
189 net_dev->watchdog_timeo - HZ/2);
180 if (result == 0) 190 if (result == 0)
181 result = -ETIMEDOUT; 191 result = -ETIMEDOUT;
182 if (result < 0) { 192 if (result < 0) {
@@ -187,8 +197,9 @@ void i2400m_wake_tx_work(struct work_struct *ws)
187 } 197 }
188 msleep(20); /* device still needs some time or it drops it */ 198 msleep(20); /* device still needs some time or it drops it */
189 result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); 199 result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
190 netif_wake_queue(i2400m->wimax_dev.net_dev);
191error: 200error:
201 netif_wake_queue(net_dev);
202out_kfree:
192 kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */ 203 kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */
193out_put: 204out_put:
194 i2400m_put(i2400m); 205 i2400m_put(i2400m);