diff options
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_chip.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 161 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.h | 12 |
5 files changed, 181 insertions, 4 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 907e6562cb59..54f68f134ea7 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c | |||
@@ -1448,6 +1448,7 @@ int zd_chip_enable_rxtx(struct zd_chip *chip) | |||
1448 | mutex_lock(&chip->mutex); | 1448 | mutex_lock(&chip->mutex); |
1449 | zd_usb_enable_tx(&chip->usb); | 1449 | zd_usb_enable_tx(&chip->usb); |
1450 | r = zd_usb_enable_rx(&chip->usb); | 1450 | r = zd_usb_enable_rx(&chip->usb); |
1451 | zd_tx_watchdog_enable(&chip->usb); | ||
1451 | mutex_unlock(&chip->mutex); | 1452 | mutex_unlock(&chip->mutex); |
1452 | return r; | 1453 | return r; |
1453 | } | 1454 | } |
@@ -1455,6 +1456,7 @@ int zd_chip_enable_rxtx(struct zd_chip *chip) | |||
1455 | void zd_chip_disable_rxtx(struct zd_chip *chip) | 1456 | void zd_chip_disable_rxtx(struct zd_chip *chip) |
1456 | { | 1457 | { |
1457 | mutex_lock(&chip->mutex); | 1458 | mutex_lock(&chip->mutex); |
1459 | zd_tx_watchdog_disable(&chip->usb); | ||
1458 | zd_usb_disable_rx(&chip->usb); | 1460 | zd_usb_disable_rx(&chip->usb); |
1459 | zd_usb_disable_tx(&chip->usb); | 1461 | zd_usb_disable_tx(&chip->usb); |
1460 | mutex_unlock(&chip->mutex); | 1462 | mutex_unlock(&chip->mutex); |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index e82f0075ed93..a590a94cb6fa 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -264,7 +264,7 @@ static int set_mc_hash(struct zd_mac *mac) | |||
264 | return zd_chip_set_multicast_hash(&mac->chip, &hash); | 264 | return zd_chip_set_multicast_hash(&mac->chip, &hash); |
265 | } | 265 | } |
266 | 266 | ||
267 | static int zd_op_start(struct ieee80211_hw *hw) | 267 | int zd_op_start(struct ieee80211_hw *hw) |
268 | { | 268 | { |
269 | struct zd_mac *mac = zd_hw_mac(hw); | 269 | struct zd_mac *mac = zd_hw_mac(hw); |
270 | struct zd_chip *chip = &mac->chip; | 270 | struct zd_chip *chip = &mac->chip; |
@@ -314,7 +314,7 @@ out: | |||
314 | return r; | 314 | return r; |
315 | } | 315 | } |
316 | 316 | ||
317 | static void zd_op_stop(struct ieee80211_hw *hw) | 317 | void zd_op_stop(struct ieee80211_hw *hw) |
318 | { | 318 | { |
319 | struct zd_mac *mac = zd_hw_mac(hw); | 319 | struct zd_mac *mac = zd_hw_mac(hw); |
320 | struct zd_chip *chip = &mac->chip; | 320 | struct zd_chip *chip = &mac->chip; |
@@ -1409,6 +1409,9 @@ static void link_led_handler(struct work_struct *work) | |||
1409 | int is_associated; | 1409 | int is_associated; |
1410 | int r; | 1410 | int r; |
1411 | 1411 | ||
1412 | if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) | ||
1413 | goto requeue; | ||
1414 | |||
1412 | spin_lock_irq(&mac->lock); | 1415 | spin_lock_irq(&mac->lock); |
1413 | is_associated = mac->associated; | 1416 | is_associated = mac->associated; |
1414 | spin_unlock_irq(&mac->lock); | 1417 | spin_unlock_irq(&mac->lock); |
@@ -1418,6 +1421,7 @@ static void link_led_handler(struct work_struct *work) | |||
1418 | if (r) | 1421 | if (r) |
1419 | dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); | 1422 | dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); |
1420 | 1423 | ||
1424 | requeue: | ||
1421 | queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, | 1425 | queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, |
1422 | LINK_LED_WORK_DELAY); | 1426 | LINK_LED_WORK_DELAY); |
1423 | } | 1427 | } |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index c0f239e40bcd..f8c93c3fe755 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h | |||
@@ -314,6 +314,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length); | |||
314 | void zd_mac_tx_failed(struct urb *urb); | 314 | void zd_mac_tx_failed(struct urb *urb); |
315 | void zd_mac_tx_to_dev(struct sk_buff *skb, int error); | 315 | void zd_mac_tx_to_dev(struct sk_buff *skb, int error); |
316 | 316 | ||
317 | int zd_op_start(struct ieee80211_hw *hw); | ||
318 | void zd_op_stop(struct ieee80211_hw *hw); | ||
317 | int zd_restore_settings(struct zd_mac *mac); | 319 | int zd_restore_settings(struct zd_mac *mac); |
318 | 320 | ||
319 | #ifdef DEBUG | 321 | #ifdef DEBUG |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 861dad192871..178d794be3fd 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -798,6 +798,7 @@ void zd_usb_disable_tx(struct zd_usb *usb) | |||
798 | usb_kill_anchored_urbs(&tx->submitted); | 798 | usb_kill_anchored_urbs(&tx->submitted); |
799 | 799 | ||
800 | spin_lock_irqsave(&tx->lock, flags); | 800 | spin_lock_irqsave(&tx->lock, flags); |
801 | WARN_ON(!skb_queue_empty(&tx->submitted_skbs)); | ||
801 | WARN_ON(tx->submitted_urbs != 0); | 802 | WARN_ON(tx->submitted_urbs != 0); |
802 | tx->submitted_urbs = 0; | 803 | tx->submitted_urbs = 0; |
803 | spin_unlock_irqrestore(&tx->lock, flags); | 804 | spin_unlock_irqrestore(&tx->lock, flags); |
@@ -895,6 +896,7 @@ static void tx_urb_complete(struct urb *urb) | |||
895 | goto resubmit; | 896 | goto resubmit; |
896 | } | 897 | } |
897 | free_urb: | 898 | free_urb: |
899 | skb_unlink(skb, &usb->tx.submitted_skbs); | ||
898 | zd_mac_tx_to_dev(skb, urb->status); | 900 | zd_mac_tx_to_dev(skb, urb->status); |
899 | usb_free_urb(urb); | 901 | usb_free_urb(urb); |
900 | tx_dec_submitted_urbs(usb); | 902 | tx_dec_submitted_urbs(usb); |
@@ -924,6 +926,7 @@ resubmit: | |||
924 | int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) | 926 | int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) |
925 | { | 927 | { |
926 | int r; | 928 | int r; |
929 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
927 | struct usb_device *udev = zd_usb_to_usbdev(usb); | 930 | struct usb_device *udev = zd_usb_to_usbdev(usb); |
928 | struct urb *urb; | 931 | struct urb *urb; |
929 | struct zd_usb_tx *tx = &usb->tx; | 932 | struct zd_usb_tx *tx = &usb->tx; |
@@ -942,10 +945,14 @@ int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) | |||
942 | usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), | 945 | usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), |
943 | skb->data, skb->len, tx_urb_complete, skb); | 946 | skb->data, skb->len, tx_urb_complete, skb); |
944 | 947 | ||
948 | info->rate_driver_data[1] = (void *)jiffies; | ||
949 | skb_queue_tail(&tx->submitted_skbs, skb); | ||
945 | usb_anchor_urb(urb, &tx->submitted); | 950 | usb_anchor_urb(urb, &tx->submitted); |
951 | |||
946 | r = usb_submit_urb(urb, GFP_ATOMIC); | 952 | r = usb_submit_urb(urb, GFP_ATOMIC); |
947 | if (r) { | 953 | if (r) { |
948 | usb_unanchor_urb(urb); | 954 | usb_unanchor_urb(urb); |
955 | skb_unlink(skb, &tx->submitted_skbs); | ||
949 | goto error; | 956 | goto error; |
950 | } | 957 | } |
951 | tx_inc_submitted_urbs(usb); | 958 | tx_inc_submitted_urbs(usb); |
@@ -956,6 +963,76 @@ out: | |||
956 | return r; | 963 | return r; |
957 | } | 964 | } |
958 | 965 | ||
966 | static bool zd_tx_timeout(struct zd_usb *usb) | ||
967 | { | ||
968 | struct zd_usb_tx *tx = &usb->tx; | ||
969 | struct sk_buff_head *q = &tx->submitted_skbs; | ||
970 | struct sk_buff *skb, *skbnext; | ||
971 | struct ieee80211_tx_info *info; | ||
972 | unsigned long flags, trans_start; | ||
973 | bool have_timedout = false; | ||
974 | |||
975 | spin_lock_irqsave(&q->lock, flags); | ||
976 | skb_queue_walk_safe(q, skb, skbnext) { | ||
977 | info = IEEE80211_SKB_CB(skb); | ||
978 | trans_start = (unsigned long)info->rate_driver_data[1]; | ||
979 | |||
980 | if (time_is_before_jiffies(trans_start + ZD_TX_TIMEOUT)) { | ||
981 | have_timedout = true; | ||
982 | break; | ||
983 | } | ||
984 | } | ||
985 | spin_unlock_irqrestore(&q->lock, flags); | ||
986 | |||
987 | return have_timedout; | ||
988 | } | ||
989 | |||
990 | static void zd_tx_watchdog_handler(struct work_struct *work) | ||
991 | { | ||
992 | struct zd_usb *usb = | ||
993 | container_of(work, struct zd_usb, tx.watchdog_work.work); | ||
994 | struct zd_usb_tx *tx = &usb->tx; | ||
995 | |||
996 | if (!atomic_read(&tx->enabled) || !tx->watchdog_enabled) | ||
997 | goto out; | ||
998 | if (!zd_tx_timeout(usb)) | ||
999 | goto out; | ||
1000 | |||
1001 | /* TX halted, try reset */ | ||
1002 | dev_warn(zd_usb_dev(usb), "TX-stall detected, reseting device..."); | ||
1003 | |||
1004 | usb_queue_reset_device(usb->intf); | ||
1005 | |||
1006 | /* reset will stop this worker, don't rearm */ | ||
1007 | return; | ||
1008 | out: | ||
1009 | queue_delayed_work(zd_workqueue, &tx->watchdog_work, | ||
1010 | ZD_TX_WATCHDOG_INTERVAL); | ||
1011 | } | ||
1012 | |||
1013 | void zd_tx_watchdog_enable(struct zd_usb *usb) | ||
1014 | { | ||
1015 | struct zd_usb_tx *tx = &usb->tx; | ||
1016 | |||
1017 | if (!tx->watchdog_enabled) { | ||
1018 | dev_dbg_f(zd_usb_dev(usb), "\n"); | ||
1019 | queue_delayed_work(zd_workqueue, &tx->watchdog_work, | ||
1020 | ZD_TX_WATCHDOG_INTERVAL); | ||
1021 | tx->watchdog_enabled = 1; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | void zd_tx_watchdog_disable(struct zd_usb *usb) | ||
1026 | { | ||
1027 | struct zd_usb_tx *tx = &usb->tx; | ||
1028 | |||
1029 | if (tx->watchdog_enabled) { | ||
1030 | dev_dbg_f(zd_usb_dev(usb), "\n"); | ||
1031 | tx->watchdog_enabled = 0; | ||
1032 | cancel_delayed_work_sync(&tx->watchdog_work); | ||
1033 | } | ||
1034 | } | ||
1035 | |||
959 | static inline void init_usb_interrupt(struct zd_usb *usb) | 1036 | static inline void init_usb_interrupt(struct zd_usb *usb) |
960 | { | 1037 | { |
961 | struct zd_usb_interrupt *intr = &usb->intr; | 1038 | struct zd_usb_interrupt *intr = &usb->intr; |
@@ -984,8 +1061,11 @@ static inline void init_usb_tx(struct zd_usb *usb) | |||
984 | spin_lock_init(&tx->lock); | 1061 | spin_lock_init(&tx->lock); |
985 | atomic_set(&tx->enabled, 0); | 1062 | atomic_set(&tx->enabled, 0); |
986 | tx->stopped = 0; | 1063 | tx->stopped = 0; |
1064 | skb_queue_head_init(&tx->submitted_skbs); | ||
987 | init_usb_anchor(&tx->submitted); | 1065 | init_usb_anchor(&tx->submitted); |
988 | tx->submitted_urbs = 0; | 1066 | tx->submitted_urbs = 0; |
1067 | tx->watchdog_enabled = 0; | ||
1068 | INIT_DELAYED_WORK(&tx->watchdog_work, zd_tx_watchdog_handler); | ||
989 | } | 1069 | } |
990 | 1070 | ||
991 | void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, | 1071 | void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, |
@@ -1233,11 +1313,92 @@ static void disconnect(struct usb_interface *intf) | |||
1233 | dev_dbg(&intf->dev, "disconnected\n"); | 1313 | dev_dbg(&intf->dev, "disconnected\n"); |
1234 | } | 1314 | } |
1235 | 1315 | ||
1316 | static void zd_usb_resume(struct zd_usb *usb) | ||
1317 | { | ||
1318 | struct zd_mac *mac = zd_usb_to_mac(usb); | ||
1319 | int r; | ||
1320 | |||
1321 | dev_dbg_f(zd_usb_dev(usb), "\n"); | ||
1322 | |||
1323 | r = zd_op_start(zd_usb_to_hw(usb)); | ||
1324 | if (r < 0) { | ||
1325 | dev_warn(zd_usb_dev(usb), "Device resume failed " | ||
1326 | "with error code %d. Retrying...\n", r); | ||
1327 | if (usb->was_running) | ||
1328 | set_bit(ZD_DEVICE_RUNNING, &mac->flags); | ||
1329 | usb_queue_reset_device(usb->intf); | ||
1330 | return; | ||
1331 | } | ||
1332 | |||
1333 | if (mac->type != NL80211_IFTYPE_UNSPECIFIED) { | ||
1334 | r = zd_restore_settings(mac); | ||
1335 | if (r < 0) { | ||
1336 | dev_dbg(zd_usb_dev(usb), | ||
1337 | "failed to restore settings, %d\n", r); | ||
1338 | return; | ||
1339 | } | ||
1340 | } | ||
1341 | } | ||
1342 | |||
1343 | static void zd_usb_stop(struct zd_usb *usb) | ||
1344 | { | ||
1345 | dev_dbg_f(zd_usb_dev(usb), "\n"); | ||
1346 | |||
1347 | zd_op_stop(zd_usb_to_hw(usb)); | ||
1348 | |||
1349 | zd_usb_disable_tx(usb); | ||
1350 | zd_usb_disable_rx(usb); | ||
1351 | zd_usb_disable_int(usb); | ||
1352 | |||
1353 | usb->initialized = 0; | ||
1354 | } | ||
1355 | |||
1356 | static int pre_reset(struct usb_interface *intf) | ||
1357 | { | ||
1358 | struct ieee80211_hw *hw = usb_get_intfdata(intf); | ||
1359 | struct zd_mac *mac; | ||
1360 | struct zd_usb *usb; | ||
1361 | |||
1362 | if (!hw || intf->condition != USB_INTERFACE_BOUND) | ||
1363 | return 0; | ||
1364 | |||
1365 | mac = zd_hw_mac(hw); | ||
1366 | usb = &mac->chip.usb; | ||
1367 | |||
1368 | usb->was_running = test_bit(ZD_DEVICE_RUNNING, &mac->flags); | ||
1369 | |||
1370 | zd_usb_stop(usb); | ||
1371 | |||
1372 | mutex_lock(&mac->chip.mutex); | ||
1373 | return 0; | ||
1374 | } | ||
1375 | |||
1376 | static int post_reset(struct usb_interface *intf) | ||
1377 | { | ||
1378 | struct ieee80211_hw *hw = usb_get_intfdata(intf); | ||
1379 | struct zd_mac *mac; | ||
1380 | struct zd_usb *usb; | ||
1381 | |||
1382 | if (!hw || intf->condition != USB_INTERFACE_BOUND) | ||
1383 | return 0; | ||
1384 | |||
1385 | mac = zd_hw_mac(hw); | ||
1386 | usb = &mac->chip.usb; | ||
1387 | |||
1388 | mutex_unlock(&mac->chip.mutex); | ||
1389 | |||
1390 | if (usb->was_running) | ||
1391 | zd_usb_resume(usb); | ||
1392 | return 0; | ||
1393 | } | ||
1394 | |||
1236 | static struct usb_driver driver = { | 1395 | static struct usb_driver driver = { |
1237 | .name = KBUILD_MODNAME, | 1396 | .name = KBUILD_MODNAME, |
1238 | .id_table = usb_ids, | 1397 | .id_table = usb_ids, |
1239 | .probe = probe, | 1398 | .probe = probe, |
1240 | .disconnect = disconnect, | 1399 | .disconnect = disconnect, |
1400 | .pre_reset = pre_reset, | ||
1401 | .post_reset = post_reset, | ||
1241 | }; | 1402 | }; |
1242 | 1403 | ||
1243 | struct workqueue_struct *zd_workqueue; | 1404 | struct workqueue_struct *zd_workqueue; |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 24db0dd68421..98f09c2dde7e 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h | |||
@@ -32,6 +32,9 @@ | |||
32 | #define ZD_USB_TX_HIGH 5 | 32 | #define ZD_USB_TX_HIGH 5 |
33 | #define ZD_USB_TX_LOW 2 | 33 | #define ZD_USB_TX_LOW 2 |
34 | 34 | ||
35 | #define ZD_TX_TIMEOUT (HZ * 5) | ||
36 | #define ZD_TX_WATCHDOG_INTERVAL round_jiffies_relative(HZ) | ||
37 | |||
35 | enum devicetype { | 38 | enum devicetype { |
36 | DEVICE_ZD1211 = 0, | 39 | DEVICE_ZD1211 = 0, |
37 | DEVICE_ZD1211B = 1, | 40 | DEVICE_ZD1211B = 1, |
@@ -196,9 +199,11 @@ struct zd_usb_rx { | |||
196 | struct zd_usb_tx { | 199 | struct zd_usb_tx { |
197 | atomic_t enabled; | 200 | atomic_t enabled; |
198 | spinlock_t lock; | 201 | spinlock_t lock; |
202 | struct delayed_work watchdog_work; | ||
203 | struct sk_buff_head submitted_skbs; | ||
199 | struct usb_anchor submitted; | 204 | struct usb_anchor submitted; |
200 | int submitted_urbs; | 205 | int submitted_urbs; |
201 | int stopped; | 206 | u8 stopped:1, watchdog_enabled:1; |
202 | }; | 207 | }; |
203 | 208 | ||
204 | /* Contains the usb parts. The structure doesn't require a lock because intf | 209 | /* Contains the usb parts. The structure doesn't require a lock because intf |
@@ -210,7 +215,7 @@ struct zd_usb { | |||
210 | struct zd_usb_tx tx; | 215 | struct zd_usb_tx tx; |
211 | struct usb_interface *intf; | 216 | struct usb_interface *intf; |
212 | u8 req_buf[64]; /* zd_usb_iowrite16v needs 62 bytes */ | 217 | u8 req_buf[64]; /* zd_usb_iowrite16v needs 62 bytes */ |
213 | u8 is_zd1211b:1, initialized:1; | 218 | u8 is_zd1211b:1, initialized:1, was_running:1; |
214 | }; | 219 | }; |
215 | 220 | ||
216 | #define zd_usb_dev(usb) (&usb->intf->dev) | 221 | #define zd_usb_dev(usb) (&usb->intf->dev) |
@@ -237,6 +242,9 @@ void zd_usb_clear(struct zd_usb *usb); | |||
237 | 242 | ||
238 | int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size); | 243 | int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size); |
239 | 244 | ||
245 | void zd_tx_watchdog_enable(struct zd_usb *usb); | ||
246 | void zd_tx_watchdog_disable(struct zd_usb *usb); | ||
247 | |||
240 | int zd_usb_enable_int(struct zd_usb *usb); | 248 | int zd_usb_enable_int(struct zd_usb *usb); |
241 | void zd_usb_disable_int(struct zd_usb *usb); | 249 | void zd_usb_disable_int(struct zd_usb *usb); |
242 | 250 | ||