Commit d7ca2139 authored by Sujith's avatar Sujith Committed by John W. Linville

ath9k_htc: Fix ampdu_action callback

Now that ampdu_action() can sleep, remove all
the driver hacks and just issue WMI commands
to the target.
Signed-off-by: default avatarSujith <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9a2af889
...@@ -223,15 +223,6 @@ struct ath9k_htc_sta { ...@@ -223,15 +223,6 @@ struct ath9k_htc_sta {
enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID]; enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID];
}; };
struct ath9k_htc_aggr_work {
u16 tid;
u8 sta_addr[ETH_ALEN];
struct ieee80211_hw *hw;
struct ieee80211_vif *vif;
enum ieee80211_ampdu_mlme_action action;
struct mutex mutex;
};
#define ATH9K_HTC_RXBUF 256 #define ATH9K_HTC_RXBUF 256
#define HTC_RX_FRAME_HEADER_SIZE 40 #define HTC_RX_FRAME_HEADER_SIZE 40
...@@ -331,11 +322,10 @@ struct htc_beacon_config { ...@@ -331,11 +322,10 @@ struct htc_beacon_config {
#define OP_LED_ON BIT(4) #define OP_LED_ON BIT(4)
#define OP_PREAMBLE_SHORT BIT(5) #define OP_PREAMBLE_SHORT BIT(5)
#define OP_PROTECT_ENABLE BIT(6) #define OP_PROTECT_ENABLE BIT(6)
#define OP_TXAGGR BIT(7) #define OP_ASSOCIATED BIT(7)
#define OP_ASSOCIATED BIT(8) #define OP_ENABLE_BEACON BIT(8)
#define OP_ENABLE_BEACON BIT(9) #define OP_LED_DEINIT BIT(9)
#define OP_LED_DEINIT BIT(10) #define OP_UNPLUGGED BIT(10)
#define OP_UNPLUGGED BIT(11)
struct ath9k_htc_priv { struct ath9k_htc_priv {
struct device *dev; struct device *dev;
...@@ -376,8 +366,6 @@ struct ath9k_htc_priv { ...@@ -376,8 +366,6 @@ struct ath9k_htc_priv {
struct ath9k_htc_rx rx; struct ath9k_htc_rx rx;
struct tasklet_struct tx_tasklet; struct tasklet_struct tx_tasklet;
struct sk_buff_head tx_queue; struct sk_buff_head tx_queue;
struct ath9k_htc_aggr_work aggr_work;
struct delayed_work ath9k_aggr_work;
struct delayed_work ath9k_ani_work; struct delayed_work ath9k_ani_work;
struct work_struct ps_work; struct work_struct ps_work;
......
...@@ -606,7 +606,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) ...@@ -606,7 +606,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
priv->op_flags |= OP_TXAGGR;
priv->ah->opmode = NL80211_IFTYPE_STATION; priv->ah->opmode = NL80211_IFTYPE_STATION;
} }
...@@ -638,14 +637,12 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid) ...@@ -638,14 +637,12 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
spin_lock_init(&priv->beacon_lock); spin_lock_init(&priv->beacon_lock);
spin_lock_init(&priv->tx_lock); spin_lock_init(&priv->tx_lock);
mutex_init(&priv->mutex); mutex_init(&priv->mutex);
mutex_init(&priv->aggr_work.mutex);
mutex_init(&priv->htc_pm_lock); mutex_init(&priv->htc_pm_lock);
tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet, tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
(unsigned long)priv); (unsigned long)priv);
tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
(unsigned long)priv); (unsigned long)priv);
tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv); tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work);
INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
INIT_WORK(&priv->ps_work, ath9k_ps_work); INIT_WORK(&priv->ps_work, ath9k_ps_work);
......
...@@ -438,13 +438,13 @@ static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv, ...@@ -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, int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
u8 *sta_addr, u8 tid, bool oper) 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, ...@@ -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;
aggr.tidno = tid & 0xf;
rcu_read_unlock(); aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
aggr.tidno = tid;
aggr.aggr_enable = oper;
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", "%s TX aggregation for (%pM, %d)\n",
(oper) ? "Starting" : "Stopping", sta->addr, tid); (aggr.aggr_enable) ? "Starting" : "Stopping",
sta->addr, tid);
return ret;
}
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) { spin_lock_bh(&priv->tx_lock);
case IEEE80211_AMPDU_TX_START: ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr, spin_unlock_bh(&priv->tx_lock);
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");
}
mutex_unlock(&wk->mutex); return ret;
} }
/*********/ /*********/
...@@ -1266,7 +1222,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) ...@@ -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, ...@@ -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, ...@@ -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)) ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
return -ENOTSUPP; ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
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);
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)
......
...@@ -187,6 +187,19 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) ...@@ -187,6 +187,19 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
return htc_send(priv->htc, skb, epid, &tx_ctl); return htc_send(priv->htc, skb, epid, &tx_ctl);
} }
static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
struct ath9k_htc_sta *ista, u8 tid)
{
bool ret = false;
spin_lock_bh(&priv->tx_lock);
if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
ret = true;
spin_unlock_bh(&priv->tx_lock);
return ret;
}
void ath9k_tx_tasklet(unsigned long data) void ath9k_tx_tasklet(unsigned long data)
{ {
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
...@@ -216,8 +229,7 @@ void ath9k_tx_tasklet(unsigned long data) ...@@ -216,8 +229,7 @@ void ath9k_tx_tasklet(unsigned long data)
/* Check if we need to start aggregation */ /* Check if we need to start aggregation */
if (sta && conf_is_ht(&priv->hw->conf) && if (sta && conf_is_ht(&priv->hw->conf) &&
(priv->op_flags & OP_TXAGGR) !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
&& !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
if (ieee80211_is_data_qos(fc)) { if (ieee80211_is_data_qos(fc)) {
u8 *qc, tid; u8 *qc, tid;
struct ath9k_htc_sta *ista; struct ath9k_htc_sta *ista;
...@@ -226,10 +238,11 @@ void ath9k_tx_tasklet(unsigned long data) ...@@ -226,10 +238,11 @@ void ath9k_tx_tasklet(unsigned long data)
tid = qc[0] & 0xf; tid = qc[0] & 0xf;
ista = (struct ath9k_htc_sta *)sta->drv_priv; ista = (struct ath9k_htc_sta *)sta->drv_priv;
if ((tid < ATH9K_HTC_MAX_TID) && if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
ista->tid_state[tid] == AGGR_STOP) {
ieee80211_start_tx_ba_session(sta, tid); ieee80211_start_tx_ba_session(sta, tid);
spin_lock_bh(&priv->tx_lock);
ista->tid_state[tid] = AGGR_PROGRESS; ista->tid_state[tid] = AGGR_PROGRESS;
spin_unlock_bh(&priv->tx_lock);
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment