From 79ee65659e116a49c81f63480a7672b7cbafa323 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 6 Oct 2014 20:23:55 +0200 Subject: [PATCH 1/7] rtl818x_pci: fix response rate may be incorrect. Currently the allowed "respose rate" set (rates for HW generated frames like ACKs) is the same as the basic rate set. The HW will use the higher allowed response rate that is lower than the rate of the received frame. This is more or less what IEEE80211 mandates, but I missed the fact that IEEE80211 also says that whenever it happens that for a modulation class there is no any rate in the basic rates set, then the response rate set shall include also all the mandatory rates for that modulation class. This patch adds mandatory OFDM rates to the allowed response rate set if no OFDM rate is included in the basic rate set. Depending by the AP, I faced cases in which this patch seems to cause a noticeable perfomance improvement. - With my usual test AP there is no particular perfomance difference. - With a prism54/hostapd AP this patch causes RX thoughput increase from about 5Mbps to about 20Mbps. Hopefully this patch may help people that faced performance regression wrt the old staging driver. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 34 +++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index ded967aa6ecb..706b844bce00 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -742,35 +742,49 @@ static void rtl8180_int_disable(struct ieee80211_hw *dev) } static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev, - u32 rates_mask) + u32 basic_mask) { struct rtl8180_priv *priv = dev->priv; - - u8 max, min; u16 reg; + u32 resp_mask; + u8 basic_max; + u8 resp_max, resp_min; - max = fls(rates_mask) - 1; - min = ffs(rates_mask) - 1; + resp_mask = basic_mask; + /* IEEE80211 says the response rate should be equal to the highest basic + * rate that is not faster than received frame. But it says also that if + * the basic rate set does not contains any rate for the current + * modulation class then mandatory rate set must be used for that + * modulation class. Eventually add OFDM mandatory rates.. + */ + if ((resp_mask & 0xf) == resp_mask) + resp_mask |= 0x150; /* 6, 12, 24Mbps */ switch (priv->chip_family) { case RTL818X_CHIP_FAMILY_RTL8180: /* in 8180 this is NOT a BITMAP */ + basic_max = fls(basic_mask) - 1; reg = rtl818x_ioread16(priv, &priv->map->BRSR); reg &= ~3; - reg |= max; + reg |= basic_max; rtl818x_iowrite16(priv, &priv->map->BRSR, reg); break; case RTL818X_CHIP_FAMILY_RTL8185: + resp_max = fls(resp_mask) - 1; + resp_min = ffs(resp_mask) - 1; /* in 8185 this is a BITMAP */ - rtl818x_iowrite16(priv, &priv->map->BRSR, rates_mask); - rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (max << 4) | min); + rtl818x_iowrite16(priv, &priv->map->BRSR, basic_mask); + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (resp_max << 4) | + resp_min); break; case RTL818X_CHIP_FAMILY_RTL8187SE: - /* in 8187se this is a BITMAP */ - rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, rates_mask); + /* in 8187se this is a BITMAP. BRSR reg actually sets + * response rates. + */ + rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, resp_mask); break; } } From d2a993e20e717a4ccbfa9a58b29362e4446208a0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 7 Oct 2014 10:14:36 +0530 Subject: [PATCH 2/7] ath: Fix smatch warning drivers/net/wireless/ath/main.c:88 ath_printk() error: we previously assumed 'common->hw' could be null (see line 82) Reported-by: Dan Carpenter Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index 83f47af19280..338d72337604 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -79,13 +79,13 @@ void ath_printk(const char *level, const struct ath_common* common, vaf.fmt = fmt; vaf.va = &args; - if (common && common->hw && common->hw->wiphy) + if (common && common->hw && common->hw->wiphy) { printk("%sath: %s: %pV", level, wiphy_name(common->hw->wiphy), &vaf); - else + trace_ath_log(common->hw->wiphy, &vaf); + } else { printk("%sath: %pV", level, &vaf); - - trace_ath_log(common->hw->wiphy, &vaf); + } va_end(args); } From b18111d911980af52bead74ee45250cc96ad5108 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 7 Oct 2014 10:14:37 +0530 Subject: [PATCH 3/7] ath9k: Fix crash in MCC mode When a channel context is removed, the hw_queue_base is set to -1, this will result in a panic because ath9k_chanctx_stop_queues() can be called on an interface that is not assigned to any context yet - for example, when trying to scan. Fix this issue by setting the hw_queue_base to zero when a channel context is removed. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 205162449b72..6f6a974f7fdb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2332,7 +2332,7 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw, conf->def.chan->center_freq); ctx->assigned = false; - ctx->hw_queue_base = -1; + ctx->hw_queue_base = 0; ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); mutex_unlock(&sc->mutex); From c393d179924685d5c8c72446c5b6401f25fdb2a0 Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Tue, 7 Oct 2014 17:04:30 +0200 Subject: [PATCH 4/7] ath9k_htc: avoid kernel panic in ath9k_hw_reset hw pointer of ath_hw is not assigned to proper value in function ath9k_hw_reset what finally causes kernel panic. This can be solved by proper initialization of ath_hw in ath9k_init_priv. Signed-off-by: Marek Puzyniak Acked-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index d779f4fa50e3..4014c4be6e79 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -464,6 +464,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, return -ENOMEM; ah->dev = priv->dev; + ah->hw = priv->hw; ah->hw_version.devid = devid; ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; From 2f29fed3f814f652a24b10c975b9d415a154fc9c Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 7 Oct 2014 22:20:23 +0200 Subject: [PATCH 5/7] net: rfkill: kernel-doc warning fixes s/state/blocked Signed-off-by: Fabian Frederick Signed-off-by: John W. Linville --- net/rfkill/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index b3b16c070a7f..fa7cd792791c 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -329,7 +329,7 @@ static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); /** * __rfkill_switch_all - Toggle state of all switches of given type * @type: type of interfaces to be affected - * @state: the new state + * @blocked: the new state * * This function sets the state of all switches of given type, * unless a specific switch is claimed by userspace (in which case, @@ -353,7 +353,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) /** * rfkill_switch_all - Toggle state of all switches of given type * @type: type of interfaces to be affected - * @state: the new state + * @blocked: the new state * * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). * Please refer to __rfkill_switch_all() for details. From ca14405e3b25b38221d027d8970c1d74ed0b6532 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 8 Oct 2014 08:43:19 +0530 Subject: [PATCH 6/7] ath9k: Fix sequence number assignment Currently, ath9k uses a global counter for all frames that need to be assigned a sequence number. QoS-data frames are handled properly since they have a per-tid counter. But, beacons and other management frames use the same counter even if multiple interfaces or contexts are present. Fix this issue by making the counter per-interface and using it when mac80211 sets IEEE80211_TX_CTL_ASSIGN_SEQ. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++- drivers/net/wireless/ath/ath9k/beacon.c | 12 ++------- drivers/net/wireless/ath/ath9k/tx99.c | 8 +++++- drivers/net/wireless/ath/ath9k/xmit.c | 34 +++++++++++++++++-------- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bfa0b1518da1..01a7db061c6a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -294,7 +294,6 @@ struct ath_tx_control { * (axq_qnum). */ struct ath_tx { - u16 seq_no; u32 txqsetup; spinlock_t txbuflock; struct list_head txbuf; @@ -563,6 +562,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop); +void ath_assign_seq(struct ath_common *common, struct sk_buff *skb); int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl); void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -592,6 +592,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, struct ath_vif { struct list_head list; + u16 seq_no; + /* BSS info */ u8 bssid[ETH_ALEN]; u16 aid; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index a6af855ef6ed..ecb783beeec2 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -144,16 +144,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust; info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - /* - * TODO: make sure the seq# gets assigned properly (vs. other - * TX frames) - */ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } + + ath_assign_seq(common, skb); if (vif->p2p) ath9k_beacon_add_noa(sc, avp, skb); diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 8a69d08ec55c..40ab65e6882f 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -54,6 +54,12 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb; + struct ath_vif *avp; + + if (!sc->tx99_vif) + return NULL; + + avp = (struct ath_vif *)sc->tx99_vif->drv_priv; skb = alloc_skb(len, GFP_KERNEL); if (!skb) @@ -71,7 +77,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); tx_info = IEEE80211_SKB_CB(skb); memset(tx_info, 0, sizeof(*tx_info)); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 151ae49fa57e..493a183d0aaf 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2139,6 +2139,28 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, return bf; } +void ath_assign_seq(struct ath_common *common, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct ath_vif *avp; + + if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) + return; + + if (!vif) + return; + + avp = (struct ath_vif *)vif->drv_priv; + + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + avp->seq_no += 0x10; + + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); +} + static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl) { @@ -2162,17 +2184,7 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, if (info->control.hw_key) frmlen += info->control.hw_key->icv_len; - /* - * As a temporary workaround, assign seq# here; this will likely need - * to be cleaned up to work better with Beacon transmission and virtual - * BSSes. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } + ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb); if ((vif && vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_AP_VLAN) || From 1fca350b761631d182c2e8bce530896e66404bc2 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 8 Oct 2014 12:44:55 -0500 Subject: [PATCH 7/7] rtlwifi: Fix possible unaligned array in ether_addr_copy() Two macros used to copy BSSID information use ether_addr_copy(), thus the arrays must be 2-byte aligned. In one case, the array could become unaligned if the struct containing it were changed. Use the __unaligned(2) attribute to retain the necessary alignment. In addition, the magic number used to specify the size of the array is replaced by ETH_ALEN. Signed-off-by: Larry Finger Acked-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/wifi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 976667ae8549..6866dcf24340 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1370,7 +1370,7 @@ struct rtl_mac { bool rdg_en; /*AP*/ - u8 bssid[6]; + u8 bssid[ETH_ALEN] __aligned(2); u32 vendor; u8 mcs[16]; /* 16 bytes mcs for HT rates. */ u32 basic_rates; /* b/g rates */