Skip to content

Commit

Permalink
zd1211rw: only update HW beacon if new beacon differs from currect
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jussi Kivilinna authored and John W. Linville committed Jun 22, 2011
1 parent b405e1b commit f762d8c
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 13 deletions.
76 changes: 63 additions & 13 deletions drivers/net/wireless/zd1211rw/zd_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,8 @@ int zd_restore_settings(struct zd_mac *mac)
mac->type == NL80211_IFTYPE_AP) {
if (mac->vif != NULL) {
beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (beacon) {
if (beacon)
zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
}
}

zd_set_beacon_interval(&mac->chip, beacon_interval,
Expand Down Expand Up @@ -680,6 +678,32 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
/* 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)
{
struct zd_mac *mac = zd_hw_mac(hw);
Expand All @@ -690,13 +714,21 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
unsigned long end_jiffies, message_jiffies;
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. */
num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len;
ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL);
if (!ioreqs)
return -ENOMEM;

mutex_lock(&mac->chip.mutex);
if (!ioreqs) {
r = -ENOMEM;
goto out_nofree;
}

r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE);
if (r < 0)
Expand Down Expand Up @@ -773,21 +805,37 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
if (r < 0 || ret < 0) {
if (r >= 0)
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;
}

/* 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.11a, not yet implemented, uses different values (see GPL vendor
* driver)
*/
r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19),
CR_BCN_PLCP_CFG);
out:
mutex_unlock(&mac->chip.mutex);
kfree(ioreqs);
out_nofree:
kfree_skb(beacon);
mutex_unlock(&mac->chip.mutex);

return r;

reset_device:
zd_mac_free_cur_beacon_locked(mac);
kfree_skb(beacon);

mutex_unlock(&mac->chip.mutex);
kfree(ioreqs);

Expand Down Expand Up @@ -1073,6 +1121,8 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw,
mac->vif = NULL;
zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED);
zd_write_mac_addr(&mac->chip, NULL);

zd_mac_free_cur_beacon(mac);
}

static int zd_op_config(struct ieee80211_hw *hw, u32 changed)
Expand Down Expand Up @@ -1110,10 +1160,8 @@ static void zd_beacon_done(struct zd_mac *mac)
* Fetch next beacon so that tim_count is updated.
*/
beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (beacon) {
if (beacon)
zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
}

spin_lock_irq(&mac->lock);
mac->beacon.last_update = jiffies;
Expand Down Expand Up @@ -1240,7 +1288,6 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
zd_chip_disable_hwint(&mac->chip);
zd_mac_config_beacon(hw, beacon);
zd_chip_enable_hwint(&mac->chip);
kfree_skb(beacon);
}
}

Expand Down Expand Up @@ -1390,8 +1437,9 @@ static void beacon_watchdog_handler(struct work_struct *work)

beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (beacon) {
zd_mac_free_cur_beacon(mac);

zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
}

zd_set_beacon_interval(&mac->chip, interval, period, mac->type);
Expand Down Expand Up @@ -1426,6 +1474,8 @@ static void beacon_disable(struct zd_mac *mac)
{
dev_dbg_f(zd_mac_dev(mac), "\n");
cancel_delayed_work_sync(&mac->beacon.watchdog_work);

zd_mac_free_cur_beacon(mac);
}

#define LINK_LED_WORK_DELAY HZ
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/zd1211rw/zd_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ struct housekeeping {

struct beacon {
struct delayed_work watchdog_work;
struct sk_buff *cur_beacon;
unsigned long last_update;
u16 interval;
u8 period;
Expand Down

0 comments on commit f762d8c

Please sign in to comment.