aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/zd1211rw
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@mbnet.fi>2011-06-20 07:42:39 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-06-22 16:09:46 -0400
commitf762d8c3f8b502b93d20bd755fc30ce99d3d0abd (patch)
treeed0826a8cf58a0261247574d8ae301154eb06490 /drivers/net/wireless/zd1211rw
parentb405e1b83dc2bb662c4be2612674a8d0ef900e26 (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.c76
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h1
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
681static 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
692static 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
700static 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
683static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) 707static 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);
785out: 827out:
786 mutex_unlock(&mac->chip.mutex);
787 kfree(ioreqs); 828 kfree(ioreqs);
829out_nofree:
830 kfree_skb(beacon);
831 mutex_unlock(&mac->chip.mutex);
832
788 return r; 833 return r;
789 834
790reset_device: 835reset_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
1078static int zd_op_config(struct ieee80211_hw *hw, u32 changed) 1128static 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
166struct beacon { 166struct 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;