From patchwork Mon Jun 20 11:42:39 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jussi Kivilinna X-Patchwork-Id: 897032 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p5KBgh4I000455 for ; Mon, 20 Jun 2011 11:42:43 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753271Ab1FTLml (ORCPT ); Mon, 20 Jun 2011 07:42:41 -0400 Received: from sd-mail-sa-01.sanoma.fi ([158.127.18.161]:59501 "EHLO sd-mail-sa-01.sanoma.fi" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752840Ab1FTLmk (ORCPT ); Mon, 20 Jun 2011 07:42:40 -0400 Received: from localhost (localhost [127.0.0.1]) by sd-mail-sa-01.sanoma.fi (Postfix) with ESMTP id 87D45F033B; Mon, 20 Jun 2011 14:42:39 +0300 (EEST) X-Virus-Scanned: Debian amavisd-new at sd-mail-sa-01.sanoma.fi Received: from sd-mail-sa-01.sanoma.fi ([127.0.0.1]) by localhost (sd-mail-sa-01.sanoma.fi [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hRlckRss-O0k; Mon, 20 Jun 2011 14:42:39 +0300 (EEST) Received: from hayate.81.fi (dyn2-85-23-163-91.psoas.suomi.net [85.23.163.91]) by sd-mail-sa-01.sanoma.fi (Postfix) with ESMTPSA id 5A1B7F014E; Mon, 20 Jun 2011 14:42:39 +0300 (EEST) Received: from fate.lan ([10.0.0.10] helo=fate) by hayate.81.fi with esmtp (Exim 4.72) (envelope-from ) id 1QYcsJ-0000mF-2i; Mon, 20 Jun 2011 14:42:39 +0300 Received: from localhost6.localdomain6 (unknown [127.0.0.1]) by fate (Postfix) with ESMTP id 0FD9425206; Mon, 20 Jun 2011 14:42:39 +0300 (EEST) Subject: [PATCH 3/6] zd1211rw: only update HW beacon if new beacon differs from currect To: linux-wireless@vger.kernel.org From: Jussi Kivilinna Cc: Daniel Drake , "John W. Linville" , Ulrich Kunitz Date: Mon, 20 Jun 2011 14:42:39 +0300 Message-ID: <20110620114238.964.59892.stgit@localhost6.localdomain6> In-Reply-To: <20110620114228.964.35459.stgit@localhost6.localdomain6> References: <20110620114228.964.35459.stgit@localhost6.localdomain6> User-Agent: StGit/0.15 MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 20 Jun 2011 11:42:44 +0000 (UTC) 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 --- drivers/net/wireless/zd1211rw/zd_mac.c | 76 +++++++++++++++++++++++++++----- drivers/net/wireless/zd1211rw/zd_mac.h | 1 2 files changed, 64 insertions(+), 13 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html 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;