aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/zd1211rw/zd_mac.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@mbnet.fi>2011-01-31 13:48:55 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-02-04 16:29:50 -0500
commit9be232563666b7d1bd424780aef7ee2aa261ba04 (patch)
tree28c4455cce240e9a81962d67cb613c692b254bf0 /drivers/net/wireless/zd1211rw/zd_mac.c
parent512119b36f7945a650877cbc7e9b5f4cc4d92e4c (diff)
zd1211rw: add beacon watchdog and setting HW beacon more failsafe
When doing tx/rx at high packet rate (for example simply using ping -f), device starts to fail to respond to control messages. On non-AP modes this only causes problems for LED updating code but when we are running in AP-mode we are writing new beacon to HW usually every 100ms. Now if control message fails in HW beacon setup, device lock is kept locked and beacon data partially written. This can and usually does cause: 1. HW beacon setup fail now on, as driver cannot acquire device lock. 2. Beacon-done interrupt stop working as device has incomplete beacon. Therefore make zd_mac_config_beacon() always try to release device lock and add beacon watchdog to restart beaconing when stall is detected. Also fix zd_mac_config_beacon() try acquiring device lock for max 500ms, as what old code appeared to be trying to do using loop and msleep(1). Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_mac.c')
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c188
1 files changed, 157 insertions, 31 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 49ab3c357100..78c8f8ba50f6 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -138,6 +138,9 @@ static const struct ieee80211_channel zd_channels[] = {
138static void housekeeping_init(struct zd_mac *mac); 138static void housekeeping_init(struct zd_mac *mac);
139static void housekeeping_enable(struct zd_mac *mac); 139static void housekeeping_enable(struct zd_mac *mac);
140static void housekeeping_disable(struct zd_mac *mac); 140static void housekeeping_disable(struct zd_mac *mac);
141static void beacon_init(struct zd_mac *mac);
142static void beacon_enable(struct zd_mac *mac);
143static void beacon_disable(struct zd_mac *mac);
141 144
142static int zd_reg2alpha2(u8 regdomain, char *alpha2) 145static int zd_reg2alpha2(u8 regdomain, char *alpha2)
143{ 146{
@@ -295,6 +298,8 @@ static int zd_op_start(struct ieee80211_hw *hw)
295 goto disable_rxtx; 298 goto disable_rxtx;
296 299
297 housekeeping_enable(mac); 300 housekeeping_enable(mac);
301 beacon_enable(mac);
302 set_bit(ZD_DEVICE_RUNNING, &mac->flags);
298 return 0; 303 return 0;
299disable_rxtx: 304disable_rxtx:
300 zd_chip_disable_rxtx(chip); 305 zd_chip_disable_rxtx(chip);
@@ -313,12 +318,15 @@ static void zd_op_stop(struct ieee80211_hw *hw)
313 struct sk_buff *skb; 318 struct sk_buff *skb;
314 struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue; 319 struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue;
315 320
321 clear_bit(ZD_DEVICE_RUNNING, &mac->flags);
322
316 /* The order here deliberately is a little different from the open() 323 /* The order here deliberately is a little different from the open()
317 * method, since we need to make sure there is no opportunity for RX 324 * method, since we need to make sure there is no opportunity for RX
318 * frames to be processed by mac80211 after we have stopped it. 325 * frames to be processed by mac80211 after we have stopped it.
319 */ 326 */
320 327
321 zd_chip_disable_rxtx(chip); 328 zd_chip_disable_rxtx(chip);
329 beacon_disable(mac);
322 housekeeping_disable(mac); 330 housekeeping_disable(mac);
323 flush_workqueue(zd_workqueue); 331 flush_workqueue(zd_workqueue);
324 332
@@ -594,64 +602,99 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
594static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) 602static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
595{ 603{
596 struct zd_mac *mac = zd_hw_mac(hw); 604 struct zd_mac *mac = zd_hw_mac(hw);
597 int r; 605 int r, ret;
598 u32 tmp, j = 0; 606 u32 tmp, j = 0;
599 /* 4 more bytes for tail CRC */ 607 /* 4 more bytes for tail CRC */
600 u32 full_len = beacon->len + 4; 608 u32 full_len = beacon->len + 4;
609 unsigned long end_jiffies, message_jiffies;
610
611 mutex_lock(&mac->chip.mutex);
601 612
602 r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0); 613 r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE);
603 if (r < 0) 614 if (r < 0)
604 return r; 615 goto out;
605 r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); 616 r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE);
606 if (r < 0) 617 if (r < 0)
607 return r; 618 goto release_sema;
608 619
620 end_jiffies = jiffies + HZ / 2; /*~500ms*/
621 message_jiffies = jiffies + HZ / 10; /*~100ms*/
609 while (tmp & 0x2) { 622 while (tmp & 0x2) {
610 r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); 623 r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE);
611 if (r < 0) 624 if (r < 0)
612 return r; 625 goto release_sema;
613 if ((++j % 100) == 0) { 626 if (time_is_before_eq_jiffies(message_jiffies)) {
614 printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n"); 627 message_jiffies = jiffies + HZ / 10;
615 if (j >= 500) { 628 dev_err(zd_mac_dev(mac),
616 printk(KERN_ERR "Giving up beacon config.\n"); 629 "CR_BCN_FIFO_SEMAPHORE not ready\n");
617 return -ETIMEDOUT; 630 if (time_is_before_eq_jiffies(end_jiffies)) {
631 dev_err(zd_mac_dev(mac),
632 "Giving up beacon config.\n");
633 r = -ETIMEDOUT;
634 goto release_sema;
618 } 635 }
619 } 636 }
620 msleep(1); 637 msleep(20);
621 } 638 }
622 639
623 r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1); 640 r = zd_iowrite32_locked(&mac->chip, full_len - 1, CR_BCN_FIFO);
624 if (r < 0) 641 if (r < 0)
625 return r; 642 goto release_sema;
626 if (zd_chip_is_zd1211b(&mac->chip)) { 643 if (zd_chip_is_zd1211b(&mac->chip)) {
627 r = zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1); 644 r = zd_iowrite32_locked(&mac->chip, full_len - 1,
645 CR_BCN_LENGTH);
628 if (r < 0) 646 if (r < 0)
629 return r; 647 goto release_sema;
630 } 648 }
631 649
632 for (j = 0 ; j < beacon->len; j++) { 650 for (j = 0 ; j < beacon->len; j++) {
633 r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, 651 r = zd_iowrite32_locked(&mac->chip, *((u8 *)(beacon->data + j)),
634 *((u8 *)(beacon->data + j))); 652 CR_BCN_FIFO);
635 if (r < 0) 653 if (r < 0)
636 return r; 654 goto release_sema;
637 } 655 }
638 656
639 for (j = 0; j < 4; j++) { 657 for (j = 0; j < 4; j++) {
640 r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0); 658 r = zd_iowrite32_locked(&mac->chip, 0x0, CR_BCN_FIFO);
641 if (r < 0) 659 if (r < 0)
642 return r; 660 goto release_sema;
643 } 661 }
644 662
645 r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1); 663release_sema:
646 if (r < 0) 664 /*
647 return r; 665 * Try very hard to release device beacon semaphore, as otherwise
666 * device/driver can be left in unusable state.
667 */
668 end_jiffies = jiffies + HZ / 2; /*~500ms*/
669 ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE);
670 while (ret < 0) {
671 if (time_is_before_eq_jiffies(end_jiffies)) {
672 ret = -ETIMEDOUT;
673 break;
674 }
675
676 msleep(20);
677 ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE);
678 }
679
680 if (ret < 0)
681 dev_err(zd_mac_dev(mac), "Could not release "
682 "CR_BCN_FIFO_SEMAPHORE!\n");
683 if (r < 0 || ret < 0) {
684 if (r >= 0)
685 r = ret;
686 goto out;
687 }
648 688
649 /* 802.11b/g 2.4G CCK 1Mb 689 /* 802.11b/g 2.4G CCK 1Mb
650 * 802.11a, not yet implemented, uses different values (see GPL vendor 690 * 802.11a, not yet implemented, uses different values (see GPL vendor
651 * driver) 691 * driver)
652 */ 692 */
653 return zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 | 693 r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19),
654 (full_len << 19)); 694 CR_BCN_PLCP_CFG);
695out:
696 mutex_unlock(&mac->chip.mutex);
697 return r;
655} 698}
656 699
657static int fill_ctrlset(struct zd_mac *mac, 700static int fill_ctrlset(struct zd_mac *mac,
@@ -942,6 +985,8 @@ static void zd_beacon_done(struct zd_mac *mac)
942{ 985{
943 struct sk_buff *skb, *beacon; 986 struct sk_buff *skb, *beacon;
944 987
988 if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags))
989 return;
945 if (!mac->vif || mac->vif->type != NL80211_IFTYPE_AP) 990 if (!mac->vif || mac->vif->type != NL80211_IFTYPE_AP)
946 return; 991 return;
947 992
@@ -959,11 +1004,14 @@ static void zd_beacon_done(struct zd_mac *mac)
959 * Fetch next beacon so that tim_count is updated. 1004 * Fetch next beacon so that tim_count is updated.
960 */ 1005 */
961 beacon = ieee80211_beacon_get(mac->hw, mac->vif); 1006 beacon = ieee80211_beacon_get(mac->hw, mac->vif);
962 if (!beacon) 1007 if (beacon) {
963 return; 1008 zd_mac_config_beacon(mac->hw, beacon);
1009 kfree_skb(beacon);
1010 }
964 1011
965 zd_mac_config_beacon(mac->hw, beacon); 1012 spin_lock_irq(&mac->lock);
966 kfree_skb(beacon); 1013 mac->beacon.last_update = jiffies;
1014 spin_unlock_irq(&mac->lock);
967} 1015}
968 1016
969static void zd_process_intr(struct work_struct *work) 1017static void zd_process_intr(struct work_struct *work)
@@ -1082,7 +1130,9 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
1082 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); 1130 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1083 1131
1084 if (beacon) { 1132 if (beacon) {
1133 zd_chip_disable_hwint(&mac->chip);
1085 zd_mac_config_beacon(hw, beacon); 1134 zd_mac_config_beacon(hw, beacon);
1135 zd_chip_enable_hwint(&mac->chip);
1086 kfree_skb(beacon); 1136 kfree_skb(beacon);
1087 } 1137 }
1088 } 1138 }
@@ -1096,6 +1146,12 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
1096 interval = bss_conf->beacon_int; 1146 interval = bss_conf->beacon_int;
1097 } 1147 }
1098 1148
1149 spin_lock_irq(&mac->lock);
1150 mac->beacon.period = period;
1151 mac->beacon.interval = interval;
1152 mac->beacon.last_update = jiffies;
1153 spin_unlock_irq(&mac->lock);
1154
1099 zd_set_beacon_interval(&mac->chip, interval, period, 1155 zd_set_beacon_interval(&mac->chip, interval, period,
1100 mac->type); 1156 mac->type);
1101 } 1157 }
@@ -1188,12 +1244,82 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
1188 1244
1189 zd_chip_init(&mac->chip, hw, intf); 1245 zd_chip_init(&mac->chip, hw, intf);
1190 housekeeping_init(mac); 1246 housekeeping_init(mac);
1247 beacon_init(mac);
1191 INIT_WORK(&mac->process_intr, zd_process_intr); 1248 INIT_WORK(&mac->process_intr, zd_process_intr);
1192 1249
1193 SET_IEEE80211_DEV(hw, &intf->dev); 1250 SET_IEEE80211_DEV(hw, &intf->dev);
1194 return hw; 1251 return hw;
1195} 1252}
1196 1253
1254#define BEACON_WATCHDOG_DELAY round_jiffies_relative(HZ)
1255
1256static void beacon_watchdog_handler(struct work_struct *work)
1257{
1258 struct zd_mac *mac =
1259 container_of(work, struct zd_mac, beacon.watchdog_work.work);
1260 struct sk_buff *beacon;
1261 unsigned long timeout;
1262 int interval, period;
1263
1264 if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags))
1265 goto rearm;
1266 if (mac->type != NL80211_IFTYPE_AP || !mac->vif)
1267 goto rearm;
1268
1269 spin_lock_irq(&mac->lock);
1270 interval = mac->beacon.interval;
1271 period = mac->beacon.period;
1272 timeout = mac->beacon.last_update + msecs_to_jiffies(interval) + HZ;
1273 spin_unlock_irq(&mac->lock);
1274
1275 if (interval > 0 && time_is_before_jiffies(timeout)) {
1276 dev_dbg_f(zd_mac_dev(mac), "beacon interrupt stalled, "
1277 "restarting. "
1278 "(interval: %d, dtim: %d)\n",
1279 interval, period);
1280
1281 zd_chip_disable_hwint(&mac->chip);
1282
1283 beacon = ieee80211_beacon_get(mac->hw, mac->vif);
1284 if (beacon) {
1285 zd_mac_config_beacon(mac->hw, beacon);
1286 kfree_skb(beacon);
1287 }
1288
1289 zd_set_beacon_interval(&mac->chip, interval, period, mac->type);
1290
1291 zd_chip_enable_hwint(&mac->chip);
1292
1293 spin_lock_irq(&mac->lock);
1294 mac->beacon.last_update = jiffies;
1295 spin_unlock_irq(&mac->lock);
1296 }
1297
1298rearm:
1299 queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work,
1300 BEACON_WATCHDOG_DELAY);
1301}
1302
1303static void beacon_init(struct zd_mac *mac)
1304{
1305 INIT_DELAYED_WORK(&mac->beacon.watchdog_work, beacon_watchdog_handler);
1306}
1307
1308static void beacon_enable(struct zd_mac *mac)
1309{
1310 dev_dbg_f(zd_mac_dev(mac), "\n");
1311
1312 mac->beacon.last_update = jiffies;
1313 queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work,
1314 BEACON_WATCHDOG_DELAY);
1315}
1316
1317static void beacon_disable(struct zd_mac *mac)
1318{
1319 dev_dbg_f(zd_mac_dev(mac), "\n");
1320 cancel_delayed_work_sync(&mac->beacon.watchdog_work);
1321}
1322
1197#define LINK_LED_WORK_DELAY HZ 1323#define LINK_LED_WORK_DELAY HZ
1198 1324
1199static void link_led_handler(struct work_struct *work) 1325static void link_led_handler(struct work_struct *work)