From: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
To: linux-wireless@vger.kernel.org
Cc: Daniel Drake <dsd@gentoo.org>,
"John W. Linville" <linville@tuxdriver.com>,
Ulrich Kunitz <kune@deine-taler.de>
Subject: [PATCH 3/6] zd1211rw: only update HW beacon if new beacon differs from currect
Date: Mon, 20 Jun 2011 14:42:39 +0300 [thread overview]
Message-ID: <20110620114238.964.59892.stgit@localhost6.localdomain6> (raw)
In-Reply-To: <20110620114228.964.35459.stgit@localhost6.localdomain6>
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>
---
drivers/net/wireless/zd1211rw/zd_mac.c | 76 +++++++++++++++++++++++++++-----
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 5de28bf..0828605 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)
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,
@@ -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);
@@ -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)
@@ -773,9 +805,19 @@ release_sema:
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)
@@ -783,11 +825,17 @@ release_sema:
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);
@@ -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)
@@ -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;
@@ -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);
}
}
@@ -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);
@@ -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
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index f8c93c3..c01eca8 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -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;
next prev parent reply other threads:[~2011-06-20 11:42 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-20 11:42 [PATCH 1/6] zd1211rw: fix invalid signal values from device Jussi Kivilinna
2011-06-20 11:42 ` [PATCH 2/6] zd1211rw: make 'handle_rx_packet: invalid, small RX packet' message debug-only Jussi Kivilinna
2011-06-20 11:42 ` Jussi Kivilinna [this message]
2011-07-02 12:34 ` [PATCH 3/6] zd1211rw: only update HW beacon if new beacon differs from currect Walter Goldens
2011-07-04 14:37 ` Jussi Kivilinna
2011-06-20 11:42 ` [PATCH 4/6] zd1211rw: handle lost read-reg interrupts Jussi Kivilinna
2011-06-20 11:42 ` [PATCH 5/6] zd1211rw: don't let zd_mac_config_beacon() run too long from beacon interrupt handler Jussi Kivilinna
2011-06-20 11:42 ` [PATCH 6/6] zd1211rw: detect stalled beacon interrupt faster Jussi Kivilinna
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110620114238.964.59892.stgit@localhost6.localdomain6 \
--to=jussi.kivilinna@mbnet.fi \
--cc=dsd@gentoo.org \
--cc=kune@deine-taler.de \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox