From patchwork Wed Apr 13 05:56:11 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sujith Manoharan X-Patchwork-Id: 702961 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3D5roqQ026376 for ; Wed, 13 Apr 2011 05:53:50 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757424Ab1DMFxt (ORCPT ); Wed, 13 Apr 2011 01:53:49 -0400 Received: from mail-iw0-f174.google.com ([209.85.214.174]:35840 "EHLO mail-iw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757105Ab1DMFxs (ORCPT ); Wed, 13 Apr 2011 01:53:48 -0400 Received: by mail-iw0-f174.google.com with SMTP id 34so276432iwn.19 for ; Tue, 12 Apr 2011 22:53:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:mime-version:content-type :content-transfer-encoding:message-id:date:to:x-mailer:cc:subject; bh=eJePd+ytFe4iLMdkSwLhHVntf7LDyO5OBstmXrNKXLA=; b=UZdMnYTvS3xehbOPKecYcEvqILve5VYz39a4GfYy+gAn6BShgIUInXgiZaM6Vumy9/ kf0hZZ0M/qAhjhSS0AqrgjEjF2KPQZIhD3Vf+pLUd2mcZR8VEO+WafU9oJge9FHBdsJ2 z3R0ZVv13L7k0w2yg9wt8mW5gC+eRIA2GrsZk= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:mime-version:content-type:content-transfer-encoding:message-id :date:to:x-mailer:cc:subject; b=MtNtdGclQPosB7S/4+Jogmx5I57Kt4EDn1ObcWlo2iOXuNH6dQuFISjteQDUxz/U5v Jh4IPuH5dpDqxeUc/7vTSiVx5jn7gv6mUPpfUPqLVG9sZKmRuNhZ/nbyZlI5jlOYZRVW DCUqPnnoviMMmRlcrkbeffBBv3vt3MCxyYNWg= Received: by 10.43.56.20 with SMTP id wa20mr12411317icb.302.1302674028051; Tue, 12 Apr 2011 22:53:48 -0700 (PDT) Received: from atheros-test ([182.72.177.186]) by mx.google.com with ESMTPS id c1sm186928ibe.17.2011.04.12.22.53.44 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 12 Apr 2011 22:53:46 -0700 (PDT) From: Sujith MIME-Version: 1.0 Message-ID: <19877.15099.999692.819296@gargle.gargle.HOWL> Date: Wed, 13 Apr 2011 11:26:11 +0530 To: linville@tuxdriver.com X-Mailer: VM 8.1.1 under 23.3.1 (x86_64-unknown-linux-gnu) CC: linux-wireless@vger.kernel.org, ath9k-devel@venema.h4ckr.net Subject: [PATCH 32/40] ath9k_htc: Drain packets on station removal 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]); Wed, 13 Apr 2011 05:53:50 +0000 (UTC) From: Sujith Manoharan When a station entry is removed, there could still be pending packets destined for that station in the HIF layer. Sending these to the target is not necessary, so drain them in the driver itself. Signed-off-by: Sujith Manoharan --- drivers/net/wireless/ath/ath9k/hif_usb.c | 35 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/htc.h | 1 + drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 ++ drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 8 +++++ drivers/net/wireless/ath/ath9k/htc_hst.c | 5 +++ drivers/net/wireless/ath/ath9k/htc_hst.h | 2 + 6 files changed, 54 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 4a12c75..1d18b1c 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -363,6 +363,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) return ret; } +static inline bool check_index(struct sk_buff *skb, u8 idx) +{ + struct ath9k_htc_tx_ctl *tx_ctl; + + tx_ctl = HTC_SKB_CB(skb); + + if ((tx_ctl->type == ATH9K_HTC_AMPDU) && + (tx_ctl->sta_idx == idx)) + return true; + + return false; +} + +static void hif_usb_sta_drain(void *hif_handle, u8 idx) +{ + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct sk_buff *skb, *tmp; + unsigned long flags; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + + skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) { + if (check_index(skb, idx)) { + __skb_unlink(skb, &hif_dev->tx.tx_skb_queue); + ath9k_htc_txcompletion_cb(hif_dev->htc_handle, + skb, false); + hif_dev->tx.tx_skb_cnt--; + TX_STAT_INC(skb_failed); + } + } + + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); +} + static struct ath9k_htc_hif hif_usb = { .transport = ATH9K_HIF_USB, .name = "ath9k_hif_usb", @@ -372,6 +406,7 @@ static struct ath9k_htc_hif hif_usb = { .start = hif_usb_start, .stop = hif_usb_stop, + .sta_drain = hif_usb_sta_drain, .send = hif_usb_send, }; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 0d2e2b1..41823fd 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -280,6 +280,7 @@ struct ath9k_htc_tx_ctl { u8 type; /* ATH9K_HTC_* */ u8 epid; u8 txok; + u8 sta_idx; }; static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index fb9ff11..ae85cc4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1303,10 +1303,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_sta *ista; int ret; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); + ista = (struct ath9k_htc_sta *) sta->drv_priv; + htc_sta_drain(priv->htc, ista->index); ret = ath9k_htc_remove_station(priv, vif, sta); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 9e0c34b..0790070 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -248,6 +248,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, tx_hdr.vif_idx = vif_idx; tx_hdr.cookie = slot; + /* + * This is a bit redundant but it helps to get + * the per-packet index quickly when draining the + * TX queue in the HIF layer. Otherwise we would + * have to parse the packet contents ... + */ + tx_ctl->sta_idx = sta_idx; + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_ctl->type = ATH9K_HTC_AMPDU; tx_hdr.data_type = ATH9K_HTC_AMPDU; diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index be3385e..cee970f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -310,6 +310,11 @@ void htc_start(struct htc_target *target) target->hif->start(target->hif_dev); } +void htc_sta_drain(struct htc_target *target, u8 idx) +{ + target->hif->sta_drain(target->hif_dev, idx); +} + void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, struct sk_buff *skb, bool txok) { diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index 191e3c0..cb9174a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -35,6 +35,7 @@ struct ath9k_htc_hif { void (*start) (void *hif_handle); void (*stop) (void *hif_handle); + void (*sta_drain) (void *hif_handle, u8 idx); int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); }; @@ -209,6 +210,7 @@ int htc_send_epid(struct htc_target *target, struct sk_buff *skb, enum htc_endpoint_id epid); void htc_stop(struct htc_target *target); void htc_start(struct htc_target *target); +void htc_sta_drain(struct htc_target *target, u8 idx); void ath9k_htc_rx_msg(struct htc_target *htc_handle, struct sk_buff *skb, u32 len, u8 pipe_id);