|
@@ -438,13 +438,13 @@ static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
|
|
bss_conf->bssid, be32_to_cpu(trate.capflags));
|
|
bss_conf->bssid, be32_to_cpu(trate.capflags));
|
|
}
|
|
}
|
|
|
|
|
|
-static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
|
|
|
|
- struct ieee80211_vif *vif,
|
|
|
|
- u8 *sta_addr, u8 tid, bool oper)
|
|
|
|
|
|
+int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
|
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
|
+ enum ieee80211_ampdu_mlme_action action, u16 tid)
|
|
{
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(priv->ah);
|
|
struct ath_common *common = ath9k_hw_common(priv->ah);
|
|
struct ath9k_htc_target_aggr aggr;
|
|
struct ath9k_htc_target_aggr aggr;
|
|
- struct ieee80211_sta *sta = NULL;
|
|
|
|
struct ath9k_htc_sta *ista;
|
|
struct ath9k_htc_sta *ista;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
u8 cmd_rsp;
|
|
u8 cmd_rsp;
|
|
@@ -453,72 +453,28 @@ static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
|
|
memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
|
|
-
|
|
|
|
- rcu_read_lock();
|
|
|
|
-
|
|
|
|
- /* Check if we are able to retrieve the station */
|
|
|
|
- sta = ieee80211_find_sta(vif, sta_addr);
|
|
|
|
- if (!sta) {
|
|
|
|
- rcu_read_unlock();
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
ista = (struct ath9k_htc_sta *) sta->drv_priv;
|
|
ista = (struct ath9k_htc_sta *) sta->drv_priv;
|
|
|
|
|
|
- if (oper)
|
|
|
|
- ista->tid_state[tid] = AGGR_START;
|
|
|
|
- else
|
|
|
|
- ista->tid_state[tid] = AGGR_STOP;
|
|
|
|
-
|
|
|
|
aggr.sta_index = ista->index;
|
|
aggr.sta_index = ista->index;
|
|
-
|
|
|
|
- rcu_read_unlock();
|
|
|
|
-
|
|
|
|
- aggr.tidno = tid;
|
|
|
|
- aggr.aggr_enable = oper;
|
|
|
|
|
|
+ aggr.tidno = tid & 0xf;
|
|
|
|
+ aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
|
|
|
|
|
|
WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
|
|
WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
|
|
if (ret)
|
|
if (ret)
|
|
ath_print(common, ATH_DBG_CONFIG,
|
|
ath_print(common, ATH_DBG_CONFIG,
|
|
"Unable to %s TX aggregation for (%pM, %d)\n",
|
|
"Unable to %s TX aggregation for (%pM, %d)\n",
|
|
- (oper) ? "start" : "stop", sta->addr, tid);
|
|
|
|
|
|
+ (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
|
|
else
|
|
else
|
|
ath_print(common, ATH_DBG_CONFIG,
|
|
ath_print(common, ATH_DBG_CONFIG,
|
|
- "%s aggregation for (%pM, %d)\n",
|
|
|
|
- (oper) ? "Starting" : "Stopping", sta->addr, tid);
|
|
|
|
-
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
|
|
+ "%s TX aggregation for (%pM, %d)\n",
|
|
|
|
+ (aggr.aggr_enable) ? "Starting" : "Stopping",
|
|
|
|
+ sta->addr, tid);
|
|
|
|
|
|
-void ath9k_htc_aggr_work(struct work_struct *work)
|
|
|
|
-{
|
|
|
|
- int ret = 0;
|
|
|
|
- struct ath9k_htc_priv *priv =
|
|
|
|
- container_of(work, struct ath9k_htc_priv,
|
|
|
|
- ath9k_aggr_work.work);
|
|
|
|
- struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
|
|
|
|
-
|
|
|
|
- mutex_lock(&wk->mutex);
|
|
|
|
-
|
|
|
|
- switch (wk->action) {
|
|
|
|
- case IEEE80211_AMPDU_TX_START:
|
|
|
|
- ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
|
|
|
|
- wk->tid, true);
|
|
|
|
- if (!ret)
|
|
|
|
- ieee80211_start_tx_ba_cb_irqsafe(wk->vif, wk->sta_addr,
|
|
|
|
- wk->tid);
|
|
|
|
- break;
|
|
|
|
- case IEEE80211_AMPDU_TX_STOP:
|
|
|
|
- ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
|
|
|
|
- wk->tid, false);
|
|
|
|
- ieee80211_stop_tx_ba_cb_irqsafe(wk->vif, wk->sta_addr, wk->tid);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
|
|
|
|
- "Unknown AMPDU action\n");
|
|
|
|
- }
|
|
|
|
|
|
+ spin_lock_bh(&priv->tx_lock);
|
|
|
|
+ ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
|
|
|
|
+ spin_unlock_bh(&priv->tx_lock);
|
|
|
|
|
|
- mutex_unlock(&wk->mutex);
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/*********/
|
|
/*********/
|
|
@@ -1266,7 +1222,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
|
|
/* Cancel all the running timers/work .. */
|
|
/* Cancel all the running timers/work .. */
|
|
cancel_work_sync(&priv->ps_work);
|
|
cancel_work_sync(&priv->ps_work);
|
|
cancel_delayed_work_sync(&priv->ath9k_ani_work);
|
|
cancel_delayed_work_sync(&priv->ath9k_ani_work);
|
|
- cancel_delayed_work_sync(&priv->ath9k_aggr_work);
|
|
|
|
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
|
|
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
|
|
ath9k_led_stop_brightness(priv);
|
|
ath9k_led_stop_brightness(priv);
|
|
|
|
|
|
@@ -1767,8 +1722,8 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
|
u16 tid, u16 *ssn)
|
|
u16 tid, u16 *ssn)
|
|
{
|
|
{
|
|
struct ath9k_htc_priv *priv = hw->priv;
|
|
struct ath9k_htc_priv *priv = hw->priv;
|
|
- struct ath9k_htc_aggr_work *work = &priv->aggr_work;
|
|
|
|
struct ath9k_htc_sta *ista;
|
|
struct ath9k_htc_sta *ista;
|
|
|
|
+ int ret = 0;
|
|
|
|
|
|
switch (action) {
|
|
switch (action) {
|
|
case IEEE80211_AMPDU_RX_START:
|
|
case IEEE80211_AMPDU_RX_START:
|
|
@@ -1776,26 +1731,26 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
|
case IEEE80211_AMPDU_RX_STOP:
|
|
case IEEE80211_AMPDU_RX_STOP:
|
|
break;
|
|
break;
|
|
case IEEE80211_AMPDU_TX_START:
|
|
case IEEE80211_AMPDU_TX_START:
|
|
|
|
+ ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
|
|
|
|
+ if (!ret)
|
|
|
|
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
|
|
|
+ break;
|
|
case IEEE80211_AMPDU_TX_STOP:
|
|
case IEEE80211_AMPDU_TX_STOP:
|
|
- if (!(priv->op_flags & OP_TXAGGR))
|
|
|
|
- return -ENOTSUPP;
|
|
|
|
- memcpy(work->sta_addr, sta->addr, ETH_ALEN);
|
|
|
|
- work->hw = hw;
|
|
|
|
- work->vif = vif;
|
|
|
|
- work->action = action;
|
|
|
|
- work->tid = tid;
|
|
|
|
- ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
|
|
|
|
|
|
+ ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
|
|
|
|
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
|
break;
|
|
break;
|
|
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
|
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
|
ista = (struct ath9k_htc_sta *) sta->drv_priv;
|
|
ista = (struct ath9k_htc_sta *) sta->drv_priv;
|
|
|
|
+ spin_lock_bh(&priv->tx_lock);
|
|
ista->tid_state[tid] = AGGR_OPERATIONAL;
|
|
ista->tid_state[tid] = AGGR_OPERATIONAL;
|
|
|
|
+ spin_unlock_bh(&priv->tx_lock);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
|
|
ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
|
|
"Unknown AMPDU action\n");
|
|
"Unknown AMPDU action\n");
|
|
}
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
|
|
static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
|