mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-27 23:51:54 +02:00
mac80211: backport latest version from trunk
git-svn-id: svn://svn.openwrt.org/openwrt/branches/backfire@25693 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
3b03945e09
commit
dc205de668
@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
|
|||||||
|
|
||||||
PKG_NAME:=mac80211
|
PKG_NAME:=mac80211
|
||||||
|
|
||||||
PKG_VERSION:=2011-01-24
|
PKG_VERSION:=2011-02-07
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
|
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
|
||||||
PKG_MD5SUM:=c91b57972276b26824d4b18e927a9e5f
|
PKG_MD5SUM:=a194610426c81ed5ad71ee83330c9669
|
||||||
|
|
||||||
PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2
|
PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2
|
||||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
|
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
|
||||||
|
@ -186,24 +186,3 @@
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
--- a/drivers/net/wireless/ath/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/main.c
|
|
||||||
@@ -60,16 +60,13 @@ EXPORT_SYMBOL(ath_rxbuf_alloc);
|
|
||||||
int ath_printk(const char *level, struct ath_common *common,
|
|
||||||
const char *fmt, ...)
|
|
||||||
{
|
|
||||||
- struct va_format vaf;
|
|
||||||
va_list args;
|
|
||||||
int rtn;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
|
|
||||||
- vaf.fmt = fmt;
|
|
||||||
- vaf.va = &args;
|
|
||||||
-
|
|
||||||
- rtn = printk("%sath: %pV", level, &vaf);
|
|
||||||
+ printk("%sath: ", level);
|
|
||||||
+ rtn = vprintk(fmt, args);
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
--- a/include/linux/compat-2.6.38.h
|
|
||||||
+++ b/include/linux/compat-2.6.38.h
|
|
||||||
@@ -8,23 +8,6 @@
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/skbuff.h>
|
|
||||||
|
|
||||||
-/*
|
|
||||||
- * This is not part of The 2.6.37 kernel yet but we
|
|
||||||
- * we use it to optimize the backport code we
|
|
||||||
- * need to implement. Instead of using ifdefs
|
|
||||||
- * to check what version of the check we use
|
|
||||||
- * we just replace all checks on current code
|
|
||||||
- * with this. I'll submit this upstream too, that
|
|
||||||
- * way all we'd have to do is to implement this
|
|
||||||
- * for older kernels, then we would not have to
|
|
||||||
- * edit the upstrema code for backport efforts.
|
|
||||||
- */
|
|
||||||
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
|
|
||||||
-#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
|
|
||||||
-#else
|
|
||||||
-#define br_port_exists(dev) (dev->br_port)
|
|
||||||
-#endif
|
|
||||||
-
|
|
||||||
/* rename member in struct mmc_host in include/linux/mmc/host.h */
|
|
||||||
#define max_segs max_hw_segs
|
|
||||||
|
|
||||||
--- a/include/linux/compat-2.6.h
|
|
||||||
+++ b/include/linux/compat-2.6.h
|
|
||||||
@@ -32,4 +32,21 @@
|
|
||||||
#include <linux/compat-2.6.37.h>
|
|
||||||
#include <linux/compat-2.6.38.h>
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * This is not part of The 2.6.37 kernel yet but we
|
|
||||||
+ * we use it to optimize the backport code we
|
|
||||||
+ * need to implement. Instead of using ifdefs
|
|
||||||
+ * to check what version of the check we use
|
|
||||||
+ * we just replace all checks on current code
|
|
||||||
+ * with this. I'll submit this upstream too, that
|
|
||||||
+ * way all we'd have to do is to implement this
|
|
||||||
+ * for older kernels, then we would not have to
|
|
||||||
+ * edit the upstrema code for backport efforts.
|
|
||||||
+ */
|
|
||||||
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
|
|
||||||
+#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
|
|
||||||
+#else
|
|
||||||
+#define br_port_exists(dev) (dev->br_port)
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#endif /* LINUX_26_COMPAT_H */
|
|
@ -1,6 +1,6 @@
|
|||||||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||||||
@@ -1200,6 +1200,12 @@ int ath9k_init_debug(struct ath_hw *ah)
|
@@ -1091,6 +1091,12 @@ int ath9k_init_debug(struct ath_hw *ah)
|
||||||
sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
|
sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -26,7 +26,7 @@
|
|||||||
struct ar5416IniArray iniCommon;
|
struct ar5416IniArray iniCommon;
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
@@ -1175,6 +1175,20 @@ static bool ath9k_hw_channel_change(stru
|
@@ -1213,6 +1213,20 @@ static bool ath9k_hw_channel_change(stru
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@
|
|||||||
bool ath9k_hw_check_alive(struct ath_hw *ah)
|
bool ath9k_hw_check_alive(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
int count = 50;
|
int count = 50;
|
||||||
@@ -1463,6 +1477,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
@@ -1501,6 +1515,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
||||||
if (AR_SREV_9300_20_OR_LATER(ah))
|
if (AR_SREV_9300_20_OR_LATER(ah))
|
||||||
ar9003_hw_bb_watchdog_config(ah);
|
ar9003_hw_bb_watchdog_config(ah);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
--- a/drivers/net/wireless/ath/regd.c
|
--- a/drivers/net/wireless/ath/regd.c
|
||||||
+++ b/drivers/net/wireless/ath/regd.c
|
+++ b/drivers/net/wireless/ath/regd.c
|
||||||
@@ -185,6 +185,10 @@ ath_reg_apply_beaconing_flags(struct wip
|
@@ -192,6 +192,10 @@ ath_reg_apply_beaconing_flags(struct wip
|
||||||
u32 bandwidth = 0;
|
u32 bandwidth = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -11,7 +11,7 @@
|
|||||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||||
|
|
||||||
if (!wiphy->bands[band])
|
if (!wiphy->bands[band])
|
||||||
@@ -244,6 +248,10 @@ ath_reg_apply_active_scan_flags(struct w
|
@@ -251,6 +255,10 @@ ath_reg_apply_active_scan_flags(struct w
|
||||||
u32 bandwidth = 0;
|
u32 bandwidth = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -22,7 +22,7 @@
|
|||||||
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
|
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -291,6 +299,10 @@ static void ath_reg_apply_radar_flags(st
|
@@ -298,6 +306,10 @@ static void ath_reg_apply_radar_flags(st
|
||||||
struct ieee80211_channel *ch;
|
struct ieee80211_channel *ch;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@
|
|||||||
if (!wiphy->bands[IEEE80211_BAND_5GHZ])
|
if (!wiphy->bands[IEEE80211_BAND_5GHZ])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -457,6 +469,10 @@ ath_regd_init_wiphy(struct ath_regulator
|
@@ -464,6 +476,10 @@ ath_regd_init_wiphy(struct ath_regulator
|
||||||
{
|
{
|
||||||
const struct ieee80211_regdomain *regd;
|
const struct ieee80211_regdomain *regd;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||||||
@@ -1007,6 +1007,53 @@ static const struct file_operations fops
|
@@ -1027,6 +1027,53 @@ static const struct file_operations fops
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,7 +54,7 @@
|
|||||||
int ath9k_init_debug(struct ath_hw *ah)
|
int ath9k_init_debug(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
@@ -1077,6 +1124,10 @@ int ath9k_init_debug(struct ath_hw *ah)
|
@@ -1097,6 +1144,10 @@ int ath9k_init_debug(struct ath_hw *ah)
|
||||||
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
|
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
|
||||||
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
|
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
@@ -447,26 +447,20 @@ void ath9k_btcoex_timer_pause(struct ath
|
@@ -449,26 +449,20 @@ void ath9k_btcoex_timer_pause(struct ath
|
||||||
|
|
||||||
#define ATH_LED_PIN_DEF 1
|
#define ATH_LED_PIN_DEF 1
|
||||||
#define ATH_LED_PIN_9287 8
|
#define ATH_LED_PIN_9287 8
|
||||||
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
/* Antenna diversity/combining */
|
/* Antenna diversity/combining */
|
||||||
#define ATH_ANT_RX_CURRENT_SHIFT 4
|
#define ATH_ANT_RX_CURRENT_SHIFT 4
|
||||||
@@ -618,15 +612,11 @@ struct ath_softc {
|
@@ -620,15 +614,11 @@ struct ath_softc {
|
||||||
struct ath_beacon beacon;
|
struct ath_beacon beacon;
|
||||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||||
|
|
||||||
@ -253,7 +253,7 @@
|
|||||||
/* Rfkill */
|
/* Rfkill */
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
@@ -1259,9 +1259,6 @@ static void ath9k_stop(struct ieee80211_
|
@@ -1204,9 +1204,6 @@ static void ath9k_stop(struct ieee80211_
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
mutex_lock(&sc->mutex);
|
||||||
|
|
||||||
@ -261,8 +261,8 @@
|
|||||||
- cancel_delayed_work_sync(&sc->ath_led_blink_work);
|
- cancel_delayed_work_sync(&sc->ath_led_blink_work);
|
||||||
-
|
-
|
||||||
cancel_delayed_work_sync(&sc->tx_complete_work);
|
cancel_delayed_work_sync(&sc->tx_complete_work);
|
||||||
|
cancel_delayed_work_sync(&sc->hw_pll_work);
|
||||||
cancel_work_sync(&sc->paprd_work);
|
cancel_work_sync(&sc->paprd_work);
|
||||||
cancel_work_sync(&sc->hw_check_work);
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||||
@@ -145,6 +145,21 @@ static struct ieee80211_rate ath9k_legac
|
@@ -145,6 +145,21 @@ static struct ieee80211_rate ath9k_legac
|
||||||
@ -287,7 +287,7 @@
|
|||||||
static void ath9k_deinit_softc(struct ath_softc *sc);
|
static void ath9k_deinit_softc(struct ath_softc *sc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -748,6 +763,13 @@ int ath9k_init_device(u16 devid, struct
|
@@ -746,6 +761,13 @@ int ath9k_init_device(u16 devid, struct
|
||||||
|
|
||||||
ath9k_init_txpower_limits(sc);
|
ath9k_init_txpower_limits(sc);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
@@ -1429,8 +1429,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
@@ -1467,8 +1467,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
||||||
REG_WRITE(ah, AR_OBS, 8);
|
REG_WRITE(ah, AR_OBS, 8);
|
||||||
|
|
||||||
if (ah->config.rx_intr_mitigation) {
|
if (ah->config.rx_intr_mitigation) {
|
||||||
|
37
package/mac80211/patches/530-mac80211_drv_tim_override.patch
Normal file
37
package/mac80211/patches/530-mac80211_drv_tim_override.patch
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
--- a/include/net/mac80211.h
|
||||||
|
+++ b/include/net/mac80211.h
|
||||||
|
@@ -2198,6 +2198,20 @@ static inline int ieee80211_sta_ps_trans
|
||||||
|
#define IEEE80211_TX_STATUS_HEADROOM 13
|
||||||
|
|
||||||
|
/**
|
||||||
|
+ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
|
||||||
|
+ *
|
||||||
|
+ * If a driver buffers frames for a powersave station instead of passing
|
||||||
|
+ * them back to mac80211 for retransmission, the station needs to be told
|
||||||
|
+ * to wake up using the TIM bitmap in the beacon.
|
||||||
|
+ *
|
||||||
|
+ * This function sets the station's TIM bit - it will be cleared automatically
|
||||||
|
+ * either when the station wakes up (and mac80211 has flushed out its
|
||||||
|
+ * buffered frames), or if all remaining buffered frames in mac80211 have
|
||||||
|
+ * timed out.
|
||||||
|
+ */
|
||||||
|
+void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
* ieee80211_tx_status - transmit status callback
|
||||||
|
*
|
||||||
|
* Call this function for all transmitted frames after they have been
|
||||||
|
--- a/net/mac80211/sta_info.c
|
||||||
|
+++ b/net/mac80211/sta_info.c
|
||||||
|
@@ -991,3 +991,11 @@ void ieee80211_sta_block_awake(struct ie
|
||||||
|
ieee80211_queue_work(hw, &sta->drv_unblock_wk);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_sta_block_awake);
|
||||||
|
+
|
||||||
|
+void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
|
||||||
|
+{
|
||||||
|
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||||
|
+
|
||||||
|
+ sta_info_set_tim_bit(sta);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(ieee80211_sta_set_tim);
|
@ -1,12 +0,0 @@
|
|||||||
--- a/net/mac80211/tx.c
|
|
||||||
+++ b/net/mac80211/tx.c
|
|
||||||
@@ -2241,6 +2241,9 @@ struct sk_buff *ieee80211_beacon_get_tim
|
|
||||||
|
|
||||||
sdata = vif_to_sdata(vif);
|
|
||||||
|
|
||||||
+ if (!ieee80211_sdata_running(sdata))
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
if (tim_offset)
|
|
||||||
*tim_offset = 0;
|
|
||||||
if (tim_length)
|
|
311
package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch
Normal file
311
package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
|
@@ -205,6 +205,7 @@ struct ath_atx_ac {
|
||||||
|
int sched;
|
||||||
|
struct list_head list;
|
||||||
|
struct list_head tid_q;
|
||||||
|
+ bool clear_ps_filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ath_frame_info {
|
||||||
|
@@ -262,6 +263,8 @@ struct ath_node {
|
||||||
|
struct ath_atx_ac ac[WME_NUM_AC];
|
||||||
|
u16 maxampdu;
|
||||||
|
u8 mpdudensity;
|
||||||
|
+
|
||||||
|
+ bool sleeping;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AGGR_CLEANUP BIT(1)
|
||||||
|
@@ -343,6 +346,9 @@ int ath_tx_aggr_start(struct ath_softc *
|
||||||
|
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||||
|
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||||
|
|
||||||
|
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
|
||||||
|
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
|
||||||
|
+
|
||||||
|
/********/
|
||||||
|
/* VIFs */
|
||||||
|
/********/
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
@@ -1791,6 +1791,27 @@ static int ath9k_sta_remove(struct ieee8
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
|
||||||
|
+ struct ieee80211_vif *vif,
|
||||||
|
+ enum sta_notify_cmd cmd,
|
||||||
|
+ struct ieee80211_sta *sta)
|
||||||
|
+{
|
||||||
|
+ struct ath_softc *sc = hw->priv;
|
||||||
|
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
|
||||||
|
+
|
||||||
|
+ switch (cmd) {
|
||||||
|
+ case STA_NOTIFY_SLEEP:
|
||||||
|
+ an->sleeping = true;
|
||||||
|
+ if (ath_tx_aggr_sleep(sc, an))
|
||||||
|
+ ieee80211_sta_set_tim(sta);
|
||||||
|
+ break;
|
||||||
|
+ case STA_NOTIFY_AWAKE:
|
||||||
|
+ an->sleeping = false;
|
||||||
|
+ ath_tx_aggr_wakeup(sc, an);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||||
|
const struct ieee80211_tx_queue_params *params)
|
||||||
|
{
|
||||||
|
@@ -2130,6 +2151,7 @@ struct ieee80211_ops ath9k_ops = {
|
||||||
|
.configure_filter = ath9k_configure_filter,
|
||||||
|
.sta_add = ath9k_sta_add,
|
||||||
|
.sta_remove = ath9k_sta_remove,
|
||||||
|
+ .sta_notify = ath9k_sta_notify,
|
||||||
|
.conf_tx = ath9k_conf_tx,
|
||||||
|
.bss_info_changed = ath9k_bss_info_changed,
|
||||||
|
.set_key = ath9k_set_key,
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
|
@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct
|
||||||
|
struct ath_frame_info *fi;
|
||||||
|
int nframes;
|
||||||
|
u8 tidno;
|
||||||
|
+ bool clear_filter;
|
||||||
|
|
||||||
|
skb = bf->bf_mpdu;
|
||||||
|
hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
|
@@ -442,7 +443,11 @@ static void ath_tx_complete_aggr(struct
|
||||||
|
acked_cnt++;
|
||||||
|
} else {
|
||||||
|
if (!(tid->state & AGGR_CLEANUP) && retry) {
|
||||||
|
- if (fi->retries < ATH_MAX_SW_RETRIES) {
|
||||||
|
+ if (ts->ts_status & ATH9K_TXERR_FILT) {
|
||||||
|
+ if (!an->sleeping)
|
||||||
|
+ clear_filter = true;
|
||||||
|
+ txpending = 1;
|
||||||
|
+ } else if (fi->retries < ATH_MAX_SW_RETRIES) {
|
||||||
|
ath_tx_set_retry(sc, txq, bf->bf_mpdu);
|
||||||
|
txpending = 1;
|
||||||
|
} else {
|
||||||
|
@@ -496,6 +501,7 @@ static void ath_tx_complete_aggr(struct
|
||||||
|
!txfail, sendbar);
|
||||||
|
} else {
|
||||||
|
/* retry the un-acked ones */
|
||||||
|
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
|
||||||
|
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
|
||||||
|
if (bf->bf_next == NULL && bf_last->bf_stale) {
|
||||||
|
struct ath_buf *tbf;
|
||||||
|
@@ -546,7 +552,12 @@ static void ath_tx_complete_aggr(struct
|
||||||
|
|
||||||
|
/* prepend un-acked frames to the beginning of the pending frame queue */
|
||||||
|
if (!list_empty(&bf_pending)) {
|
||||||
|
+ if (an->sleeping)
|
||||||
|
+ ieee80211_sta_set_tim(sta);
|
||||||
|
+
|
||||||
|
spin_lock_bh(&txq->axq_lock);
|
||||||
|
+ if (clear_filter)
|
||||||
|
+ tid->ac->clear_ps_filter = true;
|
||||||
|
list_splice(&bf_pending, &tid->buf_q);
|
||||||
|
ath_tx_queue_tid(txq, tid);
|
||||||
|
spin_unlock_bh(&txq->axq_lock);
|
||||||
|
@@ -816,6 +827,11 @@ static void ath_tx_sched_aggr(struct ath
|
||||||
|
bf = list_first_entry(&bf_q, struct ath_buf, list);
|
||||||
|
bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
|
||||||
|
|
||||||
|
+ if (tid->ac->clear_ps_filter) {
|
||||||
|
+ tid->ac->clear_ps_filter = false;
|
||||||
|
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* if only one frame, send as non-aggregate */
|
||||||
|
if (bf == bf->bf_lastbf) {
|
||||||
|
fi = get_frame_info(bf->bf_mpdu);
|
||||||
|
@@ -896,6 +912,67 @@ void ath_tx_aggr_stop(struct ath_softc *
|
||||||
|
ath_tx_flush_tid(sc, txtid);
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
|
||||||
|
+{
|
||||||
|
+ struct ath_atx_tid *tid;
|
||||||
|
+ struct ath_atx_ac *ac;
|
||||||
|
+ struct ath_txq *txq;
|
||||||
|
+ bool buffered = false;
|
||||||
|
+ int tidno;
|
||||||
|
+
|
||||||
|
+ for (tidno = 0, tid = &an->tid[tidno];
|
||||||
|
+ tidno < WME_NUM_TID; tidno++, tid++) {
|
||||||
|
+
|
||||||
|
+ if (!tid->sched)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ ac = tid->ac;
|
||||||
|
+ txq = ac->txq;
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&txq->axq_lock);
|
||||||
|
+
|
||||||
|
+ if (!list_empty(&tid->buf_q))
|
||||||
|
+ buffered = true;
|
||||||
|
+
|
||||||
|
+ tid->sched = false;
|
||||||
|
+ list_del(&tid->list);
|
||||||
|
+
|
||||||
|
+ if (ac->sched) {
|
||||||
|
+ ac->sched = false;
|
||||||
|
+ list_del(&ac->list);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ spin_unlock_bh(&txq->axq_lock);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return buffered;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
|
||||||
|
+{
|
||||||
|
+ struct ath_atx_tid *tid;
|
||||||
|
+ struct ath_atx_ac *ac;
|
||||||
|
+ struct ath_txq *txq;
|
||||||
|
+ int tidno;
|
||||||
|
+
|
||||||
|
+ for (tidno = 0, tid = &an->tid[tidno];
|
||||||
|
+ tidno < WME_NUM_TID; tidno++, tid++) {
|
||||||
|
+
|
||||||
|
+ ac = tid->ac;
|
||||||
|
+ txq = ac->txq;
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&txq->axq_lock);
|
||||||
|
+ ac->clear_ps_filter = true;
|
||||||
|
+
|
||||||
|
+ if (!list_empty(&tid->buf_q) && !tid->paused) {
|
||||||
|
+ ath_tx_queue_tid(txq, tid);
|
||||||
|
+ ath_txq_schedule(sc, txq);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ spin_unlock_bh(&txq->axq_lock);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||||
|
{
|
||||||
|
struct ath_atx_tid *txtid;
|
||||||
|
@@ -1492,7 +1569,6 @@ static int setup_tx_flags(struct sk_buff
|
||||||
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
- flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
|
||||||
|
flags |= ATH9K_TXDESC_INTREQ;
|
||||||
|
|
||||||
|
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||||
|
@@ -1755,6 +1831,9 @@ static void ath_tx_start_dma(struct ath_
|
||||||
|
if (txctl->paprd)
|
||||||
|
bf->bf_state.bfs_paprd_timestamp = jiffies;
|
||||||
|
|
||||||
|
+ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
|
||||||
|
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
|
||||||
|
+
|
||||||
|
ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
|
||||||
|
@@ -128,6 +128,11 @@ static inline void ath9k_hw_set11n_virtu
|
||||||
|
ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
|
||||||
|
+{
|
||||||
|
+ ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Private hardware call ops */
|
||||||
|
|
||||||
|
/* PHY ops */
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||||
|
@@ -642,6 +642,7 @@ struct ath_hw_ops {
|
||||||
|
u32 burstDuration);
|
||||||
|
void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
|
||||||
|
u32 vmf);
|
||||||
|
+ void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ath_nf_limits {
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
|
||||||
|
@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(stru
|
||||||
|
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
|
||||||
|
| SM(txPower, AR_XmitPower)
|
||||||
|
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
|
||||||
|
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
|
||||||
|
| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
|
||||||
|
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
|
||||||
|
|
||||||
|
@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(stru
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
|
||||||
|
+{
|
||||||
|
+ struct ar5416_desc *ads = AR5416DESC(ds);
|
||||||
|
+
|
||||||
|
+ if (val)
|
||||||
|
+ ads->ds_ctl0 |= AR_ClrDestMask;
|
||||||
|
+ else
|
||||||
|
+ ads->ds_ctl0 &= ~AR_ClrDestMask;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
|
||||||
|
void *lastds,
|
||||||
|
u32 durUpdateEn, u32 rtsctsRate,
|
||||||
|
@@ -460,4 +469,5 @@ void ar9002_hw_attach_mac_ops(struct ath
|
||||||
|
ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
|
||||||
|
ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
|
||||||
|
ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag;
|
||||||
|
+ ops->set_clrdmask = ar9002_hw_set_clrdmask;
|
||||||
|
}
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
|
||||||
|
@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(stru
|
||||||
|
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
|
||||||
|
| SM(txpower, AR_XmitPower)
|
||||||
|
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
|
||||||
|
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
|
||||||
|
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
|
||||||
|
| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
|
||||||
|
|
||||||
|
@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(stru
|
||||||
|
ads->ctl22 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
|
||||||
|
+{
|
||||||
|
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
||||||
|
+
|
||||||
|
+ if (val)
|
||||||
|
+ ads->ctl11 |= AR_ClrDestMask;
|
||||||
|
+ else
|
||||||
|
+ ads->ctl11 &= ~AR_ClrDestMask;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
|
||||||
|
void *lastds,
|
||||||
|
u32 durUpdateEn, u32 rtsctsRate,
|
||||||
|
@@ -522,6 +531,7 @@ void ar9003_hw_attach_mac_ops(struct ath
|
||||||
|
ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
|
||||||
|
ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
|
||||||
|
ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag;
|
||||||
|
+ ops->set_clrdmask = ar9003_hw_set_clrdmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/mac.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/mac.h
|
||||||
|
@@ -239,7 +239,6 @@ struct ath_desc {
|
||||||
|
void *ds_vdata;
|
||||||
|
} __packed __aligned(4);
|
||||||
|
|
||||||
|
-#define ATH9K_TXDESC_CLRDMASK 0x0001
|
||||||
|
#define ATH9K_TXDESC_NOACK 0x0002
|
||||||
|
#define ATH9K_TXDESC_RTSENA 0x0004
|
||||||
|
#define ATH9K_TXDESC_CTSENA 0x0008
|
@ -0,0 +1,36 @@
|
|||||||
|
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
|
@@ -2223,33 +2223,6 @@ static void ath_tx_complete_poll_work(st
|
||||||
|
} else {
|
||||||
|
txq->axq_tx_inprogress = true;
|
||||||
|
}
|
||||||
|
- } else {
|
||||||
|
- /* If the queue has pending buffers, then it
|
||||||
|
- * should be doing tx work (and have axq_depth).
|
||||||
|
- * Shouldn't get to this state I think..but
|
||||||
|
- * we do.
|
||||||
|
- */
|
||||||
|
- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) &&
|
||||||
|
- (txq->pending_frames > 0 ||
|
||||||
|
- !list_empty(&txq->axq_acq) ||
|
||||||
|
- txq->stopped)) {
|
||||||
|
- ath_err(ath9k_hw_common(sc->sc_ah),
|
||||||
|
- "txq: %p axq_qnum: %u,"
|
||||||
|
- " mac80211_qnum: %i"
|
||||||
|
- " axq_link: %p"
|
||||||
|
- " pending frames: %i"
|
||||||
|
- " axq_acq empty: %i"
|
||||||
|
- " stopped: %i"
|
||||||
|
- " axq_depth: 0 Attempting to"
|
||||||
|
- " restart tx logic.\n",
|
||||||
|
- txq, txq->axq_qnum,
|
||||||
|
- txq->mac80211_qnum,
|
||||||
|
- txq->axq_link,
|
||||||
|
- txq->pending_frames,
|
||||||
|
- list_empty(&txq->axq_acq),
|
||||||
|
- txq->stopped);
|
||||||
|
- ath_txq_schedule(sc, txq);
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&txq->axq_lock);
|
||||||
|
}
|
@ -1,111 +0,0 @@
|
|||||||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
|
||||||
@@ -450,14 +450,15 @@ static const struct file_operations fops
|
|
||||||
.llseek = default_llseek,
|
|
||||||
};
|
|
||||||
|
|
||||||
+#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
|
|
||||||
#define PR(str, elem) \
|
|
||||||
do { \
|
|
||||||
len += snprintf(buf + len, size - len, \
|
|
||||||
"%s%13u%11u%10u%10u\n", str, \
|
|
||||||
- sc->debug.stats.txstats[WME_AC_BE].elem, \
|
|
||||||
- sc->debug.stats.txstats[WME_AC_BK].elem, \
|
|
||||||
- sc->debug.stats.txstats[WME_AC_VI].elem, \
|
|
||||||
- sc->debug.stats.txstats[WME_AC_VO].elem); \
|
|
||||||
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \
|
|
||||||
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \
|
|
||||||
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \
|
|
||||||
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \
|
|
||||||
if (len >= size) \
|
|
||||||
goto done; \
|
|
||||||
} while(0)
|
|
||||||
@@ -466,10 +467,10 @@ static const struct file_operations fops
|
|
||||||
do { \
|
|
||||||
len += snprintf(buf + len, size - len, \
|
|
||||||
"%s%13u%11u%10u%10u\n", str, \
|
|
||||||
- (unsigned int)(sc->tx.txq[ATH_TXQ_AC_BE].elem), \
|
|
||||||
- (unsigned int)(sc->tx.txq[ATH_TXQ_AC_BK].elem), \
|
|
||||||
- (unsigned int)(sc->tx.txq[ATH_TXQ_AC_VI].elem), \
|
|
||||||
- (unsigned int)(sc->tx.txq[ATH_TXQ_AC_VO].elem)); \
|
|
||||||
+ (unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem), \
|
|
||||||
+ (unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem), \
|
|
||||||
+ (unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem), \
|
|
||||||
+ (unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem)); \
|
|
||||||
if (len >= size) \
|
|
||||||
goto done; \
|
|
||||||
} while(0)
|
|
||||||
@@ -478,10 +479,10 @@ do { \
|
|
||||||
do { \
|
|
||||||
len += snprintf(buf + len, size - len, \
|
|
||||||
"%s%13i%11i%10i%10i\n", str, \
|
|
||||||
- list_empty(&sc->tx.txq[ATH_TXQ_AC_BE].elem), \
|
|
||||||
- list_empty(&sc->tx.txq[ATH_TXQ_AC_BK].elem), \
|
|
||||||
- list_empty(&sc->tx.txq[ATH_TXQ_AC_VI].elem), \
|
|
||||||
- list_empty(&sc->tx.txq[ATH_TXQ_AC_VO].elem)); \
|
|
||||||
+ list_empty(&sc->tx.txq_map[WME_AC_BE]->elem), \
|
|
||||||
+ list_empty(&sc->tx.txq_map[WME_AC_BK]->elem), \
|
|
||||||
+ list_empty(&sc->tx.txq_map[WME_AC_VI]->elem), \
|
|
||||||
+ list_empty(&sc->tx.txq_map[WME_AC_VO]->elem)); \
|
|
||||||
if (len >= size) \
|
|
||||||
goto done; \
|
|
||||||
} while (0)
|
|
||||||
@@ -528,10 +529,10 @@ static ssize_t read_file_xmit(struct fil
|
|
||||||
PR("hw-tx-proc-desc: ", txprocdesc);
|
|
||||||
len += snprintf(buf + len, size - len,
|
|
||||||
"%s%11p%11p%10p%10p\n", "txq-memory-address:",
|
|
||||||
- &(sc->tx.txq[ATH_TXQ_AC_BE]),
|
|
||||||
- &(sc->tx.txq[ATH_TXQ_AC_BK]),
|
|
||||||
- &(sc->tx.txq[ATH_TXQ_AC_VI]),
|
|
||||||
- &(sc->tx.txq[ATH_TXQ_AC_VO]));
|
|
||||||
+ &(sc->tx.txq_map[WME_AC_BE]),
|
|
||||||
+ &(sc->tx.txq_map[WME_AC_BK]),
|
|
||||||
+ &(sc->tx.txq_map[WME_AC_VI]),
|
|
||||||
+ &(sc->tx.txq_map[WME_AC_VO]));
|
|
||||||
if (len >= size)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
@@ -751,9 +752,9 @@ static ssize_t read_file_misc(struct fil
|
|
||||||
}
|
|
||||||
|
|
||||||
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
|
|
||||||
- struct ath_tx_status *ts)
|
|
||||||
+ struct ath_tx_status *ts, struct ath_txq *txq)
|
|
||||||
{
|
|
||||||
- int qnum = skb_get_queue_mapping(bf->bf_mpdu);
|
|
||||||
+ int qnum = txq->axq_qnum;
|
|
||||||
|
|
||||||
TX_STAT_INC(qnum, tx_pkts_all);
|
|
||||||
sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len;
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/debug.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/debug.h
|
|
||||||
@@ -175,7 +175,7 @@ int ath9k_init_debug(struct ath_hw *ah);
|
|
||||||
|
|
||||||
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
|
|
||||||
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
|
|
||||||
- struct ath_tx_status *ts);
|
|
||||||
+ struct ath_tx_status *ts, struct ath_txq *txq);
|
|
||||||
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs);
|
|
||||||
|
|
||||||
#else
|
|
||||||
@@ -192,7 +192,8 @@ static inline void ath_debug_stat_interr
|
|
||||||
|
|
||||||
static inline void ath_debug_stat_tx(struct ath_softc *sc,
|
|
||||||
struct ath_buf *bf,
|
|
||||||
- struct ath_tx_status *ts)
|
|
||||||
+ struct ath_tx_status *ts,
|
|
||||||
+ struct ath_txq *txq)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
|
||||||
@@ -1913,7 +1913,7 @@ static void ath_tx_complete_buf(struct a
|
|
||||||
else
|
|
||||||
complete(&sc->paprd_complete);
|
|
||||||
} else {
|
|
||||||
- ath_debug_stat_tx(sc, bf, ts);
|
|
||||||
+ ath_debug_stat_tx(sc, bf, ts, txq);
|
|
||||||
ath_tx_complete(sc, skb, tx_flags,
|
|
||||||
bf->bf_state.bfs_ftype, txq);
|
|
||||||
}
|
|
232
package/mac80211/patches/540-mac80211_add_rx_rate.patch
Normal file
232
package/mac80211/patches/540-mac80211_add_rx_rate.patch
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
--- a/include/net/cfg80211.h
|
||||||
|
+++ b/include/net/cfg80211.h
|
||||||
|
@@ -414,7 +414,7 @@ struct station_parameters {
|
||||||
|
* @STATION_INFO_PLID: @plid filled
|
||||||
|
* @STATION_INFO_PLINK_STATE: @plink_state filled
|
||||||
|
* @STATION_INFO_SIGNAL: @signal filled
|
||||||
|
- * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
|
||||||
|
+ * @STATION_INFO_TX_BITRATE: @txrate fields are filled
|
||||||
|
* (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
|
||||||
|
* @STATION_INFO_RX_PACKETS: @rx_packets filled
|
||||||
|
* @STATION_INFO_TX_PACKETS: @tx_packets filled
|
||||||
|
@@ -422,6 +422,7 @@ struct station_parameters {
|
||||||
|
* @STATION_INFO_TX_FAILED: @tx_failed filled
|
||||||
|
* @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
|
||||||
|
* @STATION_INFO_SIGNAL_AVG: @signal_avg filled
|
||||||
|
+ * @STATION_INFO_RX_BITRATE: @rxrate fields are filled
|
||||||
|
*/
|
||||||
|
enum station_info_flags {
|
||||||
|
STATION_INFO_INACTIVE_TIME = 1<<0,
|
||||||
|
@@ -438,6 +439,7 @@ enum station_info_flags {
|
||||||
|
STATION_INFO_TX_FAILED = 1<<11,
|
||||||
|
STATION_INFO_RX_DROP_MISC = 1<<12,
|
||||||
|
STATION_INFO_SIGNAL_AVG = 1<<13,
|
||||||
|
+ STATION_INFO_RX_BITRATE = 1<<14,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -507,6 +509,7 @@ struct station_info {
|
||||||
|
s8 signal;
|
||||||
|
s8 signal_avg;
|
||||||
|
struct rate_info txrate;
|
||||||
|
+ struct rate_info rxrate;
|
||||||
|
u32 rx_packets;
|
||||||
|
u32 tx_packets;
|
||||||
|
u32 tx_retries;
|
||||||
|
--- a/include/linux/nl80211.h
|
||||||
|
+++ b/include/linux/nl80211.h
|
||||||
|
@@ -1243,6 +1243,8 @@ enum nl80211_rate_info {
|
||||||
|
* @NL80211_STA_INFO_LLID: the station's mesh LLID
|
||||||
|
* @NL80211_STA_INFO_PLID: the station's mesh PLID
|
||||||
|
* @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
|
||||||
|
+ * @NL80211_STA_INFO_RX_BITRATE: last unicast rx rate, nested attribute
|
||||||
|
+ * containing info as possible, see &enum nl80211_sta_info_txrate.
|
||||||
|
* @__NL80211_STA_INFO_AFTER_LAST: internal
|
||||||
|
* @NL80211_STA_INFO_MAX: highest possible station info attribute
|
||||||
|
*/
|
||||||
|
@@ -1261,6 +1263,7 @@ enum nl80211_sta_info {
|
||||||
|
NL80211_STA_INFO_TX_RETRIES,
|
||||||
|
NL80211_STA_INFO_TX_FAILED,
|
||||||
|
NL80211_STA_INFO_SIGNAL_AVG,
|
||||||
|
+ NL80211_STA_INFO_RX_BITRATE,
|
||||||
|
|
||||||
|
/* keep last */
|
||||||
|
__NL80211_STA_INFO_AFTER_LAST,
|
||||||
|
--- a/net/wireless/nl80211.c
|
||||||
|
+++ b/net/wireless/nl80211.c
|
||||||
|
@@ -1968,13 +1968,41 @@ static int parse_station_flags(struct ge
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||||
|
+ int attr)
|
||||||
|
+{
|
||||||
|
+ struct nlattr *rate;
|
||||||
|
+ u16 bitrate;
|
||||||
|
+
|
||||||
|
+ rate = nla_nest_start(msg, attr);
|
||||||
|
+ if (!rate)
|
||||||
|
+ goto nla_put_failure;
|
||||||
|
+
|
||||||
|
+ /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
|
||||||
|
+ bitrate = cfg80211_calculate_bitrate(info);
|
||||||
|
+ if (bitrate > 0)
|
||||||
|
+ NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
|
||||||
|
+
|
||||||
|
+ if (info->flags & RATE_INFO_FLAGS_MCS)
|
||||||
|
+ NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
|
||||||
|
+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
|
||||||
|
+ NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
|
||||||
|
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||||
|
+ NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
|
||||||
|
+
|
||||||
|
+ nla_nest_end(msg, rate);
|
||||||
|
+ return true;
|
||||||
|
+
|
||||||
|
+nla_put_failure:
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
|
||||||
|
int flags, struct net_device *dev,
|
||||||
|
const u8 *mac_addr, struct station_info *sinfo)
|
||||||
|
{
|
||||||
|
void *hdr;
|
||||||
|
- struct nlattr *sinfoattr, *txrate;
|
||||||
|
- u16 bitrate;
|
||||||
|
+ struct nlattr *sinfoattr;
|
||||||
|
|
||||||
|
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
|
||||||
|
if (!hdr)
|
||||||
|
@@ -2013,24 +2041,14 @@ static int nl80211_send_station(struct s
|
||||||
|
NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG,
|
||||||
|
sinfo->signal_avg);
|
||||||
|
if (sinfo->filled & STATION_INFO_TX_BITRATE) {
|
||||||
|
- txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE);
|
||||||
|
- if (!txrate)
|
||||||
|
+ if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
|
||||||
|
+ NL80211_STA_INFO_TX_BITRATE))
|
||||||
|
+ goto nla_put_failure;
|
||||||
|
+ }
|
||||||
|
+ if (sinfo->filled & STATION_INFO_RX_BITRATE) {
|
||||||
|
+ if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
|
||||||
|
+ NL80211_STA_INFO_RX_BITRATE))
|
||||||
|
goto nla_put_failure;
|
||||||
|
-
|
||||||
|
- /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
|
||||||
|
- bitrate = cfg80211_calculate_bitrate(&sinfo->txrate);
|
||||||
|
- if (bitrate > 0)
|
||||||
|
- NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
|
||||||
|
-
|
||||||
|
- if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)
|
||||||
|
- NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS,
|
||||||
|
- sinfo->txrate.mcs);
|
||||||
|
- if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
|
||||||
|
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
|
||||||
|
- if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||||
|
- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
|
||||||
|
-
|
||||||
|
- nla_nest_end(msg, txrate);
|
||||||
|
}
|
||||||
|
if (sinfo->filled & STATION_INFO_RX_PACKETS)
|
||||||
|
NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS,
|
||||||
|
--- a/net/mac80211/sta_info.h
|
||||||
|
+++ b/net/mac80211/sta_info.h
|
||||||
|
@@ -209,6 +209,8 @@ enum plink_state {
|
||||||
|
* @rate_ctrl_priv: rate control private per-STA pointer
|
||||||
|
* @last_tx_rate: rate used for last transmit, to report to userspace as
|
||||||
|
* "the" transmit rate
|
||||||
|
+ * @last_rx_rate_idx: rx status rate index of the last data packet
|
||||||
|
+ * @last_rx_rate_flag: rx status flag of the last data packet
|
||||||
|
* @lock: used for locking all fields that require locking, see comments
|
||||||
|
* in the header file.
|
||||||
|
* @flaglock: spinlock for flags accesses
|
||||||
|
@@ -311,6 +313,8 @@ struct sta_info {
|
||||||
|
unsigned long tx_bytes;
|
||||||
|
unsigned long tx_fragments;
|
||||||
|
struct ieee80211_tx_rate last_tx_rate;
|
||||||
|
+ int last_rx_rate_idx;
|
||||||
|
+ int last_rx_rate_flag;
|
||||||
|
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
|
||||||
|
|
||||||
|
/*
|
||||||
|
--- a/net/mac80211/rx.c
|
||||||
|
+++ b/net/mac80211/rx.c
|
||||||
|
@@ -1166,14 +1166,23 @@ ieee80211_rx_h_sta_process(struct ieee80
|
||||||
|
if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||||
|
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
|
||||||
|
NL80211_IFTYPE_ADHOC);
|
||||||
|
- if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
|
||||||
|
+ if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) {
|
||||||
|
sta->last_rx = jiffies;
|
||||||
|
+ if (ieee80211_is_data(hdr->frame_control)) {
|
||||||
|
+ sta->last_rx_rate_idx = status->rate_idx;
|
||||||
|
+ sta->last_rx_rate_flag = status->flag;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
} else if (!is_multicast_ether_addr(hdr->addr1)) {
|
||||||
|
/*
|
||||||
|
* Mesh beacons will update last_rx when if they are found to
|
||||||
|
* match the current local configuration when processed.
|
||||||
|
*/
|
||||||
|
sta->last_rx = jiffies;
|
||||||
|
+ if (ieee80211_is_data(hdr->frame_control)) {
|
||||||
|
+ sta->last_rx_rate_idx = status->rate_idx;
|
||||||
|
+ sta->last_rx_rate_flag = status->flag;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||||
|
--- a/net/mac80211/cfg.c
|
||||||
|
+++ b/net/mac80211/cfg.c
|
||||||
|
@@ -316,6 +316,17 @@ static int ieee80211_config_default_mgmt
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
|
||||||
|
+{
|
||||||
|
+ if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
|
||||||
|
+ struct ieee80211_supported_band *sband;
|
||||||
|
+ sband = sta->local->hw.wiphy->bands[
|
||||||
|
+ sta->local->hw.conf.channel->band];
|
||||||
|
+ rate->legacy = sband->bitrates[idx].bitrate;
|
||||||
|
+ } else
|
||||||
|
+ rate->mcs = idx;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
|
||||||
|
{
|
||||||
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
|
@@ -330,6 +341,7 @@ static void sta_set_sinfo(struct sta_inf
|
||||||
|
STATION_INFO_TX_RETRIES |
|
||||||
|
STATION_INFO_TX_FAILED |
|
||||||
|
STATION_INFO_TX_BITRATE |
|
||||||
|
+ STATION_INFO_RX_BITRATE |
|
||||||
|
STATION_INFO_RX_DROP_MISC;
|
||||||
|
|
||||||
|
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
|
||||||
|
@@ -355,15 +367,16 @@ static void sta_set_sinfo(struct sta_inf
|
||||||
|
sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
|
||||||
|
if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
|
||||||
|
sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||||
|
+ rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx);
|
||||||
|
|
||||||
|
- if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
|
||||||
|
- struct ieee80211_supported_band *sband;
|
||||||
|
- sband = sta->local->hw.wiphy->bands[
|
||||||
|
- sta->local->hw.conf.channel->band];
|
||||||
|
- sinfo->txrate.legacy =
|
||||||
|
- sband->bitrates[sta->last_tx_rate.idx].bitrate;
|
||||||
|
- } else
|
||||||
|
- sinfo->txrate.mcs = sta->last_tx_rate.idx;
|
||||||
|
+ sinfo->rxrate.flags = 0;
|
||||||
|
+ if (sta->last_rx_rate_flag & RX_FLAG_HT)
|
||||||
|
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
|
||||||
|
+ if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
|
||||||
|
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
|
||||||
|
+ if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
|
||||||
|
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||||
|
+ rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
|
||||||
|
|
||||||
|
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||||
|
#ifdef CONFIG_MAC80211_MESH
|
21
package/mac80211/patches/550-ath9k_fix_interrupts.patch
Normal file
21
package/mac80211/patches/550-ath9k_fix_interrupts.patch
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
--- a/drivers/net/wireless/ath/ath9k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/mac.c
|
||||||
|
@@ -891,7 +891,7 @@ void ath9k_hw_set_interrupts(struct ath_
|
||||||
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
|
||||||
|
if (!(ints & ATH9K_INT_GLOBAL))
|
||||||
|
- ath9k_hw_enable_interrupts(ah);
|
||||||
|
+ ath9k_hw_disable_interrupts(ah);
|
||||||
|
|
||||||
|
ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
|
||||||
|
|
||||||
|
@@ -969,7 +969,8 @@ void ath9k_hw_set_interrupts(struct ath_
|
||||||
|
REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
|
||||||
|
}
|
||||||
|
|
||||||
|
- ath9k_hw_enable_interrupts(ah);
|
||||||
|
+ if (ints & ATH9K_INT_GLOBAL)
|
||||||
|
+ ath9k_hw_enable_interrupts(ah);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
@ -1,200 +0,0 @@
|
|||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -1291,6 +1291,11 @@ static void ath9k_stop(struct ieee80211_
|
|
||||||
} else
|
|
||||||
sc->rx.rxlink = NULL;
|
|
||||||
|
|
||||||
+ if (sc->rx.frag) {
|
|
||||||
+ dev_kfree_skb_any(sc->rx.frag);
|
|
||||||
+ sc->rx.frag = NULL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* disable HAL and put h/w to sleep */
|
|
||||||
ath9k_hw_disable(ah);
|
|
||||||
ath9k_hw_configpcipowersave(ah, 1, 1);
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/recv.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/recv.c
|
|
||||||
@@ -209,11 +209,6 @@ static int ath_rx_edma_init(struct ath_s
|
|
||||||
int error = 0, i;
|
|
||||||
u32 size;
|
|
||||||
|
|
||||||
-
|
|
||||||
- common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN +
|
|
||||||
- ah->caps.rx_status_len,
|
|
||||||
- min(common->cachelsz, (u16)64));
|
|
||||||
-
|
|
||||||
ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
|
|
||||||
ah->caps.rx_status_len);
|
|
||||||
|
|
||||||
@@ -300,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, in
|
|
||||||
sc->sc_flags &= ~SC_OP_RXFLUSH;
|
|
||||||
spin_lock_init(&sc->rx.rxbuflock);
|
|
||||||
|
|
||||||
+ common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
|
|
||||||
+ sc->sc_ah->caps.rx_status_len;
|
|
||||||
+
|
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
|
||||||
return ath_rx_edma_init(sc, nbufs);
|
|
||||||
} else {
|
|
||||||
- common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
|
|
||||||
- min(common->cachelsz, (u16)64));
|
|
||||||
-
|
|
||||||
ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
|
|
||||||
common->cachelsz, common->rx_bufsize);
|
|
||||||
|
|
||||||
@@ -815,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_c
|
|
||||||
if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * rs_more indicates chained descriptors which can be used
|
|
||||||
- * to link buffers together for a sort of scatter-gather
|
|
||||||
- * operation.
|
|
||||||
- * reject the frame, we don't support scatter-gather yet and
|
|
||||||
- * the frame is probably corrupt anyway
|
|
||||||
- */
|
|
||||||
+ /* Only use error bits from the last fragment */
|
|
||||||
if (rx_stats->rs_more)
|
|
||||||
- return false;
|
|
||||||
+ return true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The rx_stats->rs_status will not be set until the end of the
|
|
||||||
@@ -981,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struc
|
|
||||||
if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
+ /* Only use status info from the last fragment */
|
|
||||||
+ if (rx_stats->rs_more)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
ath9k_process_rssi(common, hw, hdr, rx_stats);
|
|
||||||
|
|
||||||
if (ath9k_process_rate(common, hw, rx_stats, rx_status))
|
|
||||||
@@ -1582,7 +1575,7 @@ div_comb_done:
|
|
||||||
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|
||||||
{
|
|
||||||
struct ath_buf *bf;
|
|
||||||
- struct sk_buff *skb = NULL, *requeue_skb;
|
|
||||||
+ struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb;
|
|
||||||
struct ieee80211_rx_status *rxs;
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
|
||||||
@@ -1633,8 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc,
|
|
||||||
if (!skb)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
- hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len);
|
|
||||||
- rxs = IEEE80211_SKB_RXCB(skb);
|
|
||||||
+ /*
|
|
||||||
+ * Take frame header from the first fragment and RX status from
|
|
||||||
+ * the last one.
|
|
||||||
+ */
|
|
||||||
+ if (sc->rx.frag)
|
|
||||||
+ hdr_skb = sc->rx.frag;
|
|
||||||
+ else
|
|
||||||
+ hdr_skb = skb;
|
|
||||||
+
|
|
||||||
+ hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len);
|
|
||||||
+ rxs = IEEE80211_SKB_RXCB(hdr_skb);
|
|
||||||
|
|
||||||
ath_debug_stat_rx(sc, &rs);
|
|
||||||
|
|
||||||
@@ -1643,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc,
|
|
||||||
* chain it back at the queue without processing it.
|
|
||||||
*/
|
|
||||||
if (flush)
|
|
||||||
- goto requeue;
|
|
||||||
+ goto requeue_drop_frag;
|
|
||||||
|
|
||||||
retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
|
|
||||||
rxs, &decrypt_error);
|
|
||||||
if (retval)
|
|
||||||
- goto requeue;
|
|
||||||
+ goto requeue_drop_frag;
|
|
||||||
|
|
||||||
rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
|
|
||||||
if (rs.rs_tstamp > tsf_lower &&
|
|
||||||
@@ -1668,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
|
|
||||||
* skb and put it at the tail of the sc->rx.rxbuf list for
|
|
||||||
* processing. */
|
|
||||||
if (!requeue_skb)
|
|
||||||
- goto requeue;
|
|
||||||
+ goto requeue_drop_frag;
|
|
||||||
|
|
||||||
/* Unmap the frame */
|
|
||||||
dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
|
||||||
@@ -1679,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc,
|
|
||||||
if (ah->caps.rx_status_len)
|
|
||||||
skb_pull(skb, ah->caps.rx_status_len);
|
|
||||||
|
|
||||||
- ath9k_rx_skb_postprocess(common, skb, &rs,
|
|
||||||
- rxs, decrypt_error);
|
|
||||||
+ if (!rs.rs_more)
|
|
||||||
+ ath9k_rx_skb_postprocess(common, hdr_skb, &rs,
|
|
||||||
+ rxs, decrypt_error);
|
|
||||||
|
|
||||||
/* We will now give hardware our shiny new allocated skb */
|
|
||||||
bf->bf_mpdu = requeue_skb;
|
|
||||||
@@ -1697,6 +1700,38 @@ int ath_rx_tasklet(struct ath_softc *sc,
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (rs.rs_more) {
|
|
||||||
+ /*
|
|
||||||
+ * rs_more indicates chained descriptors which can be
|
|
||||||
+ * used to link buffers together for a sort of
|
|
||||||
+ * scatter-gather operation.
|
|
||||||
+ */
|
|
||||||
+ if (sc->rx.frag) {
|
|
||||||
+ /* too many fragments - cannot handle frame */
|
|
||||||
+ dev_kfree_skb_any(sc->rx.frag);
|
|
||||||
+ dev_kfree_skb_any(skb);
|
|
||||||
+ skb = NULL;
|
|
||||||
+ }
|
|
||||||
+ sc->rx.frag = skb;
|
|
||||||
+ goto requeue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (sc->rx.frag) {
|
|
||||||
+ int space = skb->len - skb_tailroom(hdr_skb);
|
|
||||||
+
|
|
||||||
+ sc->rx.frag = NULL;
|
|
||||||
+
|
|
||||||
+ if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
|
|
||||||
+ dev_kfree_skb(skb);
|
|
||||||
+ goto requeue_drop_frag;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len),
|
|
||||||
+ skb->len);
|
|
||||||
+ dev_kfree_skb_any(skb);
|
|
||||||
+ skb = hdr_skb;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* change the default rx antenna if rx diversity chooses the
|
|
||||||
* other antenna 3 times in a row.
|
|
||||||
@@ -1722,6 +1757,11 @@ int ath_rx_tasklet(struct ath_softc *sc,
|
|
||||||
|
|
||||||
ieee80211_rx(hw, skb);
|
|
||||||
|
|
||||||
+requeue_drop_frag:
|
|
||||||
+ if (sc->rx.frag) {
|
|
||||||
+ dev_kfree_skb_any(sc->rx.frag);
|
|
||||||
+ sc->rx.frag = NULL;
|
|
||||||
+ }
|
|
||||||
requeue:
|
|
||||||
if (edma) {
|
|
||||||
list_add_tail(&bf->list, &sc->rx.rxbuf);
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
||||||
@@ -311,6 +311,8 @@ struct ath_rx {
|
|
||||||
struct ath_descdma rxdma;
|
|
||||||
struct ath_buf *rx_bufptr;
|
|
||||||
struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
|
|
||||||
+
|
|
||||||
+ struct sk_buff *frag;
|
|
||||||
};
|
|
||||||
|
|
||||||
int ath_startrecv(struct ath_softc *sc);
|
|
@ -1,11 +0,0 @@
|
|||||||
--- a/net/mac80211/rx.c
|
|
||||||
+++ b/net/mac80211/rx.c
|
|
||||||
@@ -798,7 +798,7 @@ ieee80211_rx_h_check(struct ieee80211_rx
|
|
||||||
rx->local->dot11FrameDuplicateCount++;
|
|
||||||
rx->sta->num_duplicates++;
|
|
||||||
}
|
|
||||||
- return RX_DROP_MONITOR;
|
|
||||||
+ return RX_DROP_UNUSABLE;
|
|
||||||
} else
|
|
||||||
rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -177,7 +177,12 @@ static void ath_update_survey_nf(struct
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void ath_update_survey_stats(struct ath_softc *sc)
|
|
||||||
+/*
|
|
||||||
+ * Updates the survey statistics and returns the busy time since last
|
|
||||||
+ * update in %, if the measurement duration was long enough for the
|
|
||||||
+ * result to be useful, -1 otherwise.
|
|
||||||
+ */
|
|
||||||
+static int ath_update_survey_stats(struct ath_softc *sc)
|
|
||||||
{
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
|
||||||
@@ -185,9 +190,10 @@ static void ath_update_survey_stats(stru
|
|
||||||
struct survey_info *survey = &sc->survey[pos];
|
|
||||||
struct ath_cycle_counters *cc = &common->cc_survey;
|
|
||||||
unsigned int div = common->clockrate * 1000;
|
|
||||||
+ int ret = 0;
|
|
||||||
|
|
||||||
if (!ah->curchan)
|
|
||||||
- return;
|
|
||||||
+ return -1;
|
|
||||||
|
|
||||||
if (ah->power_mode == ATH9K_PM_AWAKE)
|
|
||||||
ath_hw_cycle_counters_update(common);
|
|
||||||
@@ -202,9 +208,18 @@ static void ath_update_survey_stats(stru
|
|
||||||
survey->channel_time_rx += cc->rx_frame / div;
|
|
||||||
survey->channel_time_tx += cc->tx_frame / div;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ if (cc->cycles < div)
|
|
||||||
+ return -1;
|
|
||||||
+
|
|
||||||
+ if (cc->cycles > 0)
|
|
||||||
+ ret = cc->rx_busy * 100 / cc->cycles;
|
|
||||||
+
|
|
||||||
memset(cc, 0, sizeof(*cc));
|
|
||||||
|
|
||||||
ath_update_survey_nf(sc, pos);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -226,6 +241,8 @@ int ath_set_channel(struct ath_softc *sc
|
|
||||||
if (sc->sc_flags & SC_OP_INVALID)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
+ sc->hw_busy_count = 0;
|
|
||||||
+
|
|
||||||
del_timer_sync(&common->ani.timer);
|
|
||||||
cancel_work_sync(&sc->paprd_work);
|
|
||||||
cancel_work_sync(&sc->hw_check_work);
|
|
||||||
@@ -584,17 +601,25 @@ static void ath_node_detach(struct ath_s
|
|
||||||
void ath_hw_check(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
|
|
||||||
- int i;
|
|
||||||
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ int busy;
|
|
||||||
|
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
+ if (ath9k_hw_check_alive(sc->sc_ah))
|
|
||||||
+ goto out;
|
|
||||||
|
|
||||||
- for (i = 0; i < 3; i++) {
|
|
||||||
- if (ath9k_hw_check_alive(sc->sc_ah))
|
|
||||||
- goto out;
|
|
||||||
+ spin_lock_irqsave(&common->cc_lock, flags);
|
|
||||||
+ busy = ath_update_survey_stats(sc);
|
|
||||||
+ spin_unlock_irqrestore(&common->cc_lock, flags);
|
|
||||||
|
|
||||||
- msleep(1);
|
|
||||||
- }
|
|
||||||
- ath_reset(sc, true);
|
|
||||||
+ ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
|
|
||||||
+ "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
|
|
||||||
+ if (busy >= 99) {
|
|
||||||
+ if (++sc->hw_busy_count >= 3)
|
|
||||||
+ ath_reset(sc, true);
|
|
||||||
+ } else if (busy >= 0)
|
|
||||||
+ sc->hw_busy_count = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
ath9k_ps_restore(sc);
|
|
||||||
@@ -988,6 +1013,8 @@ int ath_reset(struct ath_softc *sc, bool
|
|
||||||
struct ieee80211_hw *hw = sc->hw;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
+ sc->hw_busy_count = 0;
|
|
||||||
+
|
|
||||||
/* Stop ANI */
|
|
||||||
del_timer_sync(&common->ani.timer);
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
||||||
@@ -598,6 +598,8 @@ struct ath_softc {
|
|
||||||
struct completion paprd_complete;
|
|
||||||
bool paprd_pending;
|
|
||||||
|
|
||||||
+ unsigned int hw_busy_count;
|
|
||||||
+
|
|
||||||
u32 intrstatus;
|
|
||||||
u32 sc_flags; /* SC_OP_* */
|
|
||||||
u16 ps_flags; /* PS_* */
|
|
@ -1,12 +0,0 @@
|
|||||||
--- a/net/mac80211/rx.c
|
|
||||||
+++ b/net/mac80211/rx.c
|
|
||||||
@@ -2609,7 +2609,8 @@ static int prepare_for_handlers(struct i
|
|
||||||
return 0;
|
|
||||||
if (!multicast &&
|
|
||||||
compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
|
|
||||||
- if (!(sdata->dev->flags & IFF_PROMISC))
|
|
||||||
+ if (!(sdata->dev->flags & IFF_PROMISC) ||
|
|
||||||
+ sdata->u.mgd.use_4addr)
|
|
||||||
return 0;
|
|
||||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
--- a/net/mac80211/tx.c
|
|
||||||
+++ b/net/mac80211/tx.c
|
|
||||||
@@ -1547,7 +1547,7 @@ static int ieee80211_skb_resize(struct i
|
|
||||||
skb_orphan(skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (skb_header_cloned(skb))
|
|
||||||
+ if (skb_cloned(skb))
|
|
||||||
I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
|
|
||||||
else if (head_need || tail_need)
|
|
||||||
I802_DEBUG_INC(local->tx_expand_skb_head);
|
|
@ -1,6 +1,6 @@
|
|||||||
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
|
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
|
||||||
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
|
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
|
||||||
@@ -209,6 +209,7 @@ void rt2x00pci_uninitialize(struct rt2x0
|
@@ -196,6 +196,7 @@ void rt2x00pci_uninitialize(struct rt2x0
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
|
EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
|
||||||
|
|
||||||
@ -8,7 +8,7 @@
|
|||||||
/*
|
/*
|
||||||
* PCI driver handlers.
|
* PCI driver handlers.
|
||||||
*/
|
*/
|
||||||
@@ -388,6 +389,7 @@ int rt2x00pci_resume(struct pci_dev *pci
|
@@ -372,6 +373,7 @@ int rt2x00pci_resume(struct pci_dev *pci
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
|
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
|
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
|
||||||
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
|
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
|
||||||
@@ -277,8 +277,10 @@ int rt2x00pci_probe(struct pci_dev *pci_
|
@@ -261,8 +261,10 @@ int rt2x00pci_probe(struct pci_dev *pci_
|
||||||
|
|
||||||
pci_set_master(pci_dev);
|
pci_set_master(pci_dev);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user