1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-12-24 20:53:22 +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:
nbd 2011-02-24 01:56:10 +00:00
parent 3b03945e09
commit dc205de668
23 changed files with 657 additions and 2851 deletions

View File

@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mac80211
PKG_VERSION:=2011-01-24
PKG_VERSION:=2011-02-07
PKG_RELEASE:=1
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
PKG_MD5SUM:=c91b57972276b26824d4b18e927a9e5f
PKG_MD5SUM:=a194610426c81ed5ad71ee83330c9669
PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)

View File

@ -186,24 +186,3 @@
va_end(args);
}
#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);

View File

@ -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 */

View File

@ -1,6 +1,6 @@
--- a/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))
goto err;
@ -26,7 +26,7 @@
struct ar5416IniArray iniCommon;
--- a/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;
}
@ -47,7 +47,7 @@
bool ath9k_hw_check_alive(struct ath_hw *ah)
{
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))
ar9003_hw_bb_watchdog_config(ah);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
--- a/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;
int r;
@ -11,7 +11,7 @@
for (band = 0; band < IEEE80211_NUM_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;
int r;
@ -22,7 +22,7 @@
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;
unsigned int i;
@ -33,7 +33,7 @@
if (!wiphy->bands[IEEE80211_BAND_5GHZ])
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;

View File

@ -1,6 +1,6 @@
--- a/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,
};
@ -54,7 +54,7 @@
int ath9k_init_debug(struct ath_hw *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,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);

View File

@ -1,6 +1,6 @@
--- a/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_9287 8
@ -38,7 +38,7 @@
/* Antenna diversity/combining */
#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 ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@ -253,7 +253,7 @@
/* Rfkill */
--- a/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);
@ -261,8 +261,8 @@
- cancel_delayed_work_sync(&sc->ath_led_blink_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->hw_check_work);
--- a/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
@ -287,7 +287,7 @@
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);

View File

@ -1,6 +1,6 @@
--- a/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);
if (ah->config.rx_intr_mitigation) {

View 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);

View File

@ -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)

View 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

View File

@ -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);
}

View File

@ -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);
}

View 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

View 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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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_* */

View File

@ -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;
}

View File

@ -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);

View File

@ -1,6 +1,6 @@
--- a/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);
@ -8,7 +8,7 @@
/*
* 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);
#endif /* CONFIG_PM */

View File

@ -1,6 +1,6 @@
--- a/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);