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: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
9a2af8892a
commit
d7ca21393d
|
@ -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 {
|
||||||
#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 {
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,74 +453,30 @@ 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);
|
||||||
|
|
||||||
|
spin_lock_bh(&priv->tx_lock);
|
||||||
|
ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
|
||||||
|
spin_unlock_bh(&priv->tx_lock);
|
||||||
|
|
||||||
return ret;
|
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) {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&wk->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********/
|
/*********/
|
||||||
/* DEBUG */
|
/* DEBUG */
|
||||||
/*********/
|
/*********/
|
||||||
|
@ -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))
|
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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue