diff options
author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2011-06-20 07:42:39 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-06-22 16:09:46 -0400 |
commit | f762d8c3f8b502b93d20bd755fc30ce99d3d0abd (patch) | |
tree | ed0826a8cf58a0261247574d8ae301154eb06490 /drivers/net/wireless/zd1211rw | |
parent | b405e1b83dc2bb662c4be2612674a8d0ef900e26 (diff) |
zd1211rw: only update HW beacon if new beacon differs from currect
Update HW beacon only when needed. This appears to make device work in AP-mode
(dtim_period=1) somewhat more stable.
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')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 76 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.h | 1 |
2 files changed, 64 insertions, 13 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 5de28bf6fa5f..082860523703 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -403,10 +403,8 @@ int zd_restore_settings(struct zd_mac *mac) | |||
403 | mac->type == NL80211_IFTYPE_AP) { | 403 | mac->type == NL80211_IFTYPE_AP) { |
404 | if (mac->vif != NULL) { | 404 | if (mac->vif != NULL) { |
405 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); | 405 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); |
406 | if (beacon) { | 406 | if (beacon) |
407 | zd_mac_config_beacon(mac->hw, beacon); | 407 | zd_mac_config_beacon(mac->hw, beacon); |
408 | kfree_skb(beacon); | ||
409 | } | ||
410 | } | 408 | } |
411 | 409 | ||
412 | zd_set_beacon_interval(&mac->chip, beacon_interval, | 410 | zd_set_beacon_interval(&mac->chip, beacon_interval, |
@@ -680,6 +678,32 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, | |||
680 | /* FIXME: Management frame? */ | 678 | /* FIXME: Management frame? */ |
681 | } | 679 | } |
682 | 680 | ||
681 | static bool zd_mac_match_cur_beacon(struct zd_mac *mac, struct sk_buff *beacon) | ||
682 | { | ||
683 | if (!mac->beacon.cur_beacon) | ||
684 | return false; | ||
685 | |||
686 | if (mac->beacon.cur_beacon->len != beacon->len) | ||
687 | return false; | ||
688 | |||
689 | return !memcmp(beacon->data, mac->beacon.cur_beacon->data, beacon->len); | ||
690 | } | ||
691 | |||
692 | static void zd_mac_free_cur_beacon_locked(struct zd_mac *mac) | ||
693 | { | ||
694 | ZD_ASSERT(mutex_is_locked(&mac->chip.mutex)); | ||
695 | |||
696 | kfree_skb(mac->beacon.cur_beacon); | ||
697 | mac->beacon.cur_beacon = NULL; | ||
698 | } | ||
699 | |||
700 | static void zd_mac_free_cur_beacon(struct zd_mac *mac) | ||
701 | { | ||
702 | mutex_lock(&mac->chip.mutex); | ||
703 | zd_mac_free_cur_beacon_locked(mac); | ||
704 | mutex_unlock(&mac->chip.mutex); | ||
705 | } | ||
706 | |||
683 | static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) | 707 | static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) |
684 | { | 708 | { |
685 | struct zd_mac *mac = zd_hw_mac(hw); | 709 | struct zd_mac *mac = zd_hw_mac(hw); |
@@ -690,13 +714,21 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) | |||
690 | unsigned long end_jiffies, message_jiffies; | 714 | unsigned long end_jiffies, message_jiffies; |
691 | struct zd_ioreq32 *ioreqs; | 715 | struct zd_ioreq32 *ioreqs; |
692 | 716 | ||
717 | mutex_lock(&mac->chip.mutex); | ||
718 | |||
719 | /* Check if hw already has this beacon. */ | ||
720 | if (zd_mac_match_cur_beacon(mac, beacon)) { | ||
721 | r = 0; | ||
722 | goto out_nofree; | ||
723 | } | ||
724 | |||
693 | /* Alloc memory for full beacon write at once. */ | 725 | /* Alloc memory for full beacon write at once. */ |
694 | num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len; | 726 | num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len; |
695 | ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL); | 727 | ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL); |
696 | if (!ioreqs) | 728 | if (!ioreqs) { |
697 | return -ENOMEM; | 729 | r = -ENOMEM; |
698 | 730 | goto out_nofree; | |
699 | mutex_lock(&mac->chip.mutex); | 731 | } |
700 | 732 | ||
701 | r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE); | 733 | r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE); |
702 | if (r < 0) | 734 | if (r < 0) |
@@ -773,9 +805,19 @@ release_sema: | |||
773 | if (r < 0 || ret < 0) { | 805 | if (r < 0 || ret < 0) { |
774 | if (r >= 0) | 806 | if (r >= 0) |
775 | r = ret; | 807 | r = ret; |
808 | |||
809 | /* We don't know if beacon was written successfully or not, | ||
810 | * so clear current. */ | ||
811 | zd_mac_free_cur_beacon_locked(mac); | ||
812 | |||
776 | goto out; | 813 | goto out; |
777 | } | 814 | } |
778 | 815 | ||
816 | /* Beacon has now been written successfully, update current. */ | ||
817 | zd_mac_free_cur_beacon_locked(mac); | ||
818 | mac->beacon.cur_beacon = beacon; | ||
819 | beacon = NULL; | ||
820 | |||
779 | /* 802.11b/g 2.4G CCK 1Mb | 821 | /* 802.11b/g 2.4G CCK 1Mb |
780 | * 802.11a, not yet implemented, uses different values (see GPL vendor | 822 | * 802.11a, not yet implemented, uses different values (see GPL vendor |
781 | * driver) | 823 | * driver) |
@@ -783,11 +825,17 @@ release_sema: | |||
783 | r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19), | 825 | r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19), |
784 | CR_BCN_PLCP_CFG); | 826 | CR_BCN_PLCP_CFG); |
785 | out: | 827 | out: |
786 | mutex_unlock(&mac->chip.mutex); | ||
787 | kfree(ioreqs); | 828 | kfree(ioreqs); |
829 | out_nofree: | ||
830 | kfree_skb(beacon); | ||
831 | mutex_unlock(&mac->chip.mutex); | ||
832 | |||
788 | return r; | 833 | return r; |
789 | 834 | ||
790 | reset_device: | 835 | reset_device: |
836 | zd_mac_free_cur_beacon_locked(mac); | ||
837 | kfree_skb(beacon); | ||
838 | |||
791 | mutex_unlock(&mac->chip.mutex); | 839 | mutex_unlock(&mac->chip.mutex); |
792 | kfree(ioreqs); | 840 | kfree(ioreqs); |
793 | 841 | ||
@@ -1073,6 +1121,8 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, | |||
1073 | mac->vif = NULL; | 1121 | mac->vif = NULL; |
1074 | zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED); | 1122 | zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED); |
1075 | zd_write_mac_addr(&mac->chip, NULL); | 1123 | zd_write_mac_addr(&mac->chip, NULL); |
1124 | |||
1125 | zd_mac_free_cur_beacon(mac); | ||
1076 | } | 1126 | } |
1077 | 1127 | ||
1078 | static int zd_op_config(struct ieee80211_hw *hw, u32 changed) | 1128 | static int zd_op_config(struct ieee80211_hw *hw, u32 changed) |
@@ -1110,10 +1160,8 @@ static void zd_beacon_done(struct zd_mac *mac) | |||
1110 | * Fetch next beacon so that tim_count is updated. | 1160 | * Fetch next beacon so that tim_count is updated. |
1111 | */ | 1161 | */ |
1112 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); | 1162 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); |
1113 | if (beacon) { | 1163 | if (beacon) |
1114 | zd_mac_config_beacon(mac->hw, beacon); | 1164 | zd_mac_config_beacon(mac->hw, beacon); |
1115 | kfree_skb(beacon); | ||
1116 | } | ||
1117 | 1165 | ||
1118 | spin_lock_irq(&mac->lock); | 1166 | spin_lock_irq(&mac->lock); |
1119 | mac->beacon.last_update = jiffies; | 1167 | mac->beacon.last_update = jiffies; |
@@ -1240,7 +1288,6 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1240 | zd_chip_disable_hwint(&mac->chip); | 1288 | zd_chip_disable_hwint(&mac->chip); |
1241 | zd_mac_config_beacon(hw, beacon); | 1289 | zd_mac_config_beacon(hw, beacon); |
1242 | zd_chip_enable_hwint(&mac->chip); | 1290 | zd_chip_enable_hwint(&mac->chip); |
1243 | kfree_skb(beacon); | ||
1244 | } | 1291 | } |
1245 | } | 1292 | } |
1246 | 1293 | ||
@@ -1390,8 +1437,9 @@ static void beacon_watchdog_handler(struct work_struct *work) | |||
1390 | 1437 | ||
1391 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); | 1438 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); |
1392 | if (beacon) { | 1439 | if (beacon) { |
1440 | zd_mac_free_cur_beacon(mac); | ||
1441 | |||
1393 | zd_mac_config_beacon(mac->hw, beacon); | 1442 | zd_mac_config_beacon(mac->hw, beacon); |
1394 | kfree_skb(beacon); | ||
1395 | } | 1443 | } |
1396 | 1444 | ||
1397 | zd_set_beacon_interval(&mac->chip, interval, period, mac->type); | 1445 | zd_set_beacon_interval(&mac->chip, interval, period, mac->type); |
@@ -1426,6 +1474,8 @@ static void beacon_disable(struct zd_mac *mac) | |||
1426 | { | 1474 | { |
1427 | dev_dbg_f(zd_mac_dev(mac), "\n"); | 1475 | dev_dbg_f(zd_mac_dev(mac), "\n"); |
1428 | cancel_delayed_work_sync(&mac->beacon.watchdog_work); | 1476 | cancel_delayed_work_sync(&mac->beacon.watchdog_work); |
1477 | |||
1478 | zd_mac_free_cur_beacon(mac); | ||
1429 | } | 1479 | } |
1430 | 1480 | ||
1431 | #define LINK_LED_WORK_DELAY HZ | 1481 | #define LINK_LED_WORK_DELAY HZ |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index f8c93c3fe755..c01eca859f95 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h | |||
@@ -165,6 +165,7 @@ struct housekeeping { | |||
165 | 165 | ||
166 | struct beacon { | 166 | struct beacon { |
167 | struct delayed_work watchdog_work; | 167 | struct delayed_work watchdog_work; |
168 | struct sk_buff *cur_beacon; | ||
168 | unsigned long last_update; | 169 | unsigned long last_update; |
169 | u16 interval; | 170 | u16 interval; |
170 | u8 period; | 171 | u8 period; |