Commit f762d8c3 authored by Jussi Kivilinna's avatar Jussi Kivilinna Committed by John W. Linville

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: default avatarJussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b405e1b8
...@@ -403,10 +403,8 @@ int zd_restore_settings(struct zd_mac *mac) ...@@ -403,10 +403,8 @@ int zd_restore_settings(struct zd_mac *mac)
mac->type == NL80211_IFTYPE_AP) { mac->type == NL80211_IFTYPE_AP) {
if (mac->vif != NULL) { if (mac->vif != NULL) {
beacon = ieee80211_beacon_get(mac->hw, mac->vif); beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (beacon) { if (beacon)
zd_mac_config_beacon(mac->hw, beacon); zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
}
} }
zd_set_beacon_interval(&mac->chip, beacon_interval, 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,6 +678,32 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
/* FIXME: Management frame? */ /* FIXME: Management frame? */
} }
static bool zd_mac_match_cur_beacon(struct zd_mac *mac, struct sk_buff *beacon)
{
if (!mac->beacon.cur_beacon)
return false;
if (mac->beacon.cur_beacon->len != beacon->len)
return false;
return !memcmp(beacon->data, mac->beacon.cur_beacon->data, beacon->len);
}
static void zd_mac_free_cur_beacon_locked(struct zd_mac *mac)
{
ZD_ASSERT(mutex_is_locked(&mac->chip.mutex));
kfree_skb(mac->beacon.cur_beacon);
mac->beacon.cur_beacon = NULL;
}
static void zd_mac_free_cur_beacon(struct zd_mac *mac)
{
mutex_lock(&mac->chip.mutex);
zd_mac_free_cur_beacon_locked(mac);
mutex_unlock(&mac->chip.mutex);
}
static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
{ {
struct zd_mac *mac = zd_hw_mac(hw); 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,13 +714,21 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
unsigned long end_jiffies, message_jiffies; unsigned long end_jiffies, message_jiffies;
struct zd_ioreq32 *ioreqs; struct zd_ioreq32 *ioreqs;
mutex_lock(&mac->chip.mutex);
/* Check if hw already has this beacon. */
if (zd_mac_match_cur_beacon(mac, beacon)) {
r = 0;
goto out_nofree;
}
/* Alloc memory for full beacon write at once. */ /* Alloc memory for full beacon write at once. */
num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len; num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len;
ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL); ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL);
if (!ioreqs) if (!ioreqs) {
return -ENOMEM; r = -ENOMEM;
goto out_nofree;
mutex_lock(&mac->chip.mutex); }
r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE); r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE);
if (r < 0) if (r < 0)
...@@ -773,9 +805,19 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) ...@@ -773,9 +805,19 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
if (r < 0 || ret < 0) { if (r < 0 || ret < 0) {
if (r >= 0) if (r >= 0)
r = ret; r = ret;
/* We don't know if beacon was written successfully or not,
* so clear current. */
zd_mac_free_cur_beacon_locked(mac);
goto out; goto out;
} }
/* Beacon has now been written successfully, update current. */
zd_mac_free_cur_beacon_locked(mac);
mac->beacon.cur_beacon = beacon;
beacon = NULL;
/* 802.11b/g 2.4G CCK 1Mb /* 802.11b/g 2.4G CCK 1Mb
* 802.11a, not yet implemented, uses different values (see GPL vendor * 802.11a, not yet implemented, uses different values (see GPL vendor
* driver) * driver)
...@@ -783,11 +825,17 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) ...@@ -783,11 +825,17 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19), r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19),
CR_BCN_PLCP_CFG); CR_BCN_PLCP_CFG);
out: out:
mutex_unlock(&mac->chip.mutex);
kfree(ioreqs); kfree(ioreqs);
out_nofree:
kfree_skb(beacon);
mutex_unlock(&mac->chip.mutex);
return r; return r;
reset_device: reset_device:
zd_mac_free_cur_beacon_locked(mac);
kfree_skb(beacon);
mutex_unlock(&mac->chip.mutex); mutex_unlock(&mac->chip.mutex);
kfree(ioreqs); kfree(ioreqs);
...@@ -1073,6 +1121,8 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, ...@@ -1073,6 +1121,8 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw,
mac->vif = NULL; mac->vif = NULL;
zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED); zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED);
zd_write_mac_addr(&mac->chip, NULL); zd_write_mac_addr(&mac->chip, NULL);
zd_mac_free_cur_beacon(mac);
} }
static int zd_op_config(struct ieee80211_hw *hw, u32 changed) 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,10 +1160,8 @@ static void zd_beacon_done(struct zd_mac *mac)
* Fetch next beacon so that tim_count is updated. * Fetch next beacon so that tim_count is updated.
*/ */
beacon = ieee80211_beacon_get(mac->hw, mac->vif); beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (beacon) { if (beacon)
zd_mac_config_beacon(mac->hw, beacon); zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
}
spin_lock_irq(&mac->lock); spin_lock_irq(&mac->lock);
mac->beacon.last_update = jiffies; mac->beacon.last_update = jiffies;
...@@ -1240,7 +1288,6 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1240,7 +1288,6 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
zd_chip_disable_hwint(&mac->chip); zd_chip_disable_hwint(&mac->chip);
zd_mac_config_beacon(hw, beacon); zd_mac_config_beacon(hw, beacon);
zd_chip_enable_hwint(&mac->chip); zd_chip_enable_hwint(&mac->chip);
kfree_skb(beacon);
} }
} }
...@@ -1390,8 +1437,9 @@ static void beacon_watchdog_handler(struct work_struct *work) ...@@ -1390,8 +1437,9 @@ static void beacon_watchdog_handler(struct work_struct *work)
beacon = ieee80211_beacon_get(mac->hw, mac->vif); beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (beacon) { if (beacon) {
zd_mac_free_cur_beacon(mac);
zd_mac_config_beacon(mac->hw, beacon); zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
} }
zd_set_beacon_interval(&mac->chip, interval, period, mac->type); zd_set_beacon_interval(&mac->chip, interval, period, mac->type);
...@@ -1426,6 +1474,8 @@ static void beacon_disable(struct zd_mac *mac) ...@@ -1426,6 +1474,8 @@ static void beacon_disable(struct zd_mac *mac)
{ {
dev_dbg_f(zd_mac_dev(mac), "\n"); dev_dbg_f(zd_mac_dev(mac), "\n");
cancel_delayed_work_sync(&mac->beacon.watchdog_work); cancel_delayed_work_sync(&mac->beacon.watchdog_work);
zd_mac_free_cur_beacon(mac);
} }
#define LINK_LED_WORK_DELAY HZ #define LINK_LED_WORK_DELAY HZ
......
...@@ -165,6 +165,7 @@ struct housekeeping { ...@@ -165,6 +165,7 @@ struct housekeeping {
struct beacon { struct beacon {
struct delayed_work watchdog_work; struct delayed_work watchdog_work;
struct sk_buff *cur_beacon;
unsigned long last_update; unsigned long last_update;
u16 interval; u16 interval;
u8 period; u8 period;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment