[PATCH v2 2/2] wcn36xx: initiate TX BA sessions

Eugene Krasnikov k.eugene.e at gmail.com
Mon Mar 24 04:59:43 EDT 2014


Looks good to me.

2014-03-21 20:23 GMT+00:00 Bob Copeland <me at bobcopeland.com>:
> Currently, wcn36xx only asks for a TX BA session if it has
> already established one for RX.  Thus, two wcn36xx devices cannot
> do a-mpdu between themselves since they both wait for the other
> to go first.  Fix this by starting a BA session after a few QoS
> data frames have been sent to a STA.
>
> Signed-off-by: Bob Copeland <bob at cozybit.com>
> ---
> Changes since v1:
>
> - moved wcn36xx_tx_start_ampdu() inside set_tx_data
>   and removed some redundant checks
>
>  main.c    |   14 +++++++++++++-
>  txrx.c    |   48 +++++++++++++++++++++++++++++++++++++++++++++++-
>  wcn36xx.h |   20 ++++++++++++++++++++
>  3 files changed, 80 insertions(+), 2 deletions(-)
>
> diff --git a/main.c b/main.c
> index 8908d3a..477d51f 100644
> --- a/main.c
> +++ b/main.c
> @@ -844,6 +844,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
>         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
>                     vif, sta->addr);
>
> +       spin_lock_init(&sta_priv->ampdu_lock);
>         sta_priv->vif = vif_priv;
>         /*
>          * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
> @@ -917,21 +918,32 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
>                         get_sta_index(vif, sta_priv));
>                 wcn36xx_smd_add_ba(wcn);
>                 wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
> -               ieee80211_start_tx_ba_session(sta, tid, 0);
>                 break;
>         case IEEE80211_AMPDU_RX_STOP:
>                 wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
>                 break;
>         case IEEE80211_AMPDU_TX_START:
> +               spin_lock_bh(&sta_priv->ampdu_lock);
> +               sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
> +               spin_unlock_bh(&sta_priv->ampdu_lock);
> +
>                 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
>                 break;
>         case IEEE80211_AMPDU_TX_OPERATIONAL:
> +               spin_lock_bh(&sta_priv->ampdu_lock);
> +               sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
> +               spin_unlock_bh(&sta_priv->ampdu_lock);
> +
>                 wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
>                         get_sta_index(vif, sta_priv));
>                 break;
>         case IEEE80211_AMPDU_TX_STOP_FLUSH:
>         case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
>         case IEEE80211_AMPDU_TX_STOP_CONT:
> +               spin_lock_bh(&sta_priv->ampdu_lock);
> +               sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;
> +               spin_unlock_bh(&sta_priv->ampdu_lock);
> +
>                 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
>                 break;
>         default:
> diff --git a/txrx.c b/txrx.c
> index 37f3d1b..a11a805 100644
> --- a/txrx.c
> +++ b/txrx.c
> @@ -111,6 +111,45 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
>         wcn36xx_warn("vif %pM not found\n", addr);
>         return NULL;
>  }
> +
> +/*
> + * Initiate TX a-mpdu with the station if we can.
> + */
> +static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn,
> +                                  struct wcn36xx_sta *sta_priv,
> +                                  struct sk_buff *skb)
> +{
> +       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +       struct ieee80211_sta *sta;
> +       u8 *qc, tid;
> +
> +       if (!conf_is_ht(&wcn->hw->conf))
> +               return;
> +
> +       sta = wcn36xx_priv_to_sta(sta_priv);
> +
> +       if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control)))
> +               return;
> +
> +       if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
> +               return;
> +
> +       qc = ieee80211_get_qos_ctl(hdr);
> +       tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
> +
> +       spin_lock(&sta_priv->ampdu_lock);
> +       if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE)
> +               goto out_unlock;
> +
> +       if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) {
> +               sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
> +               sta_priv->non_agg_frame_ct = 0;
> +               ieee80211_start_tx_ba_session(sta, tid, 0);
> +       }
> +out_unlock:
> +       spin_unlock(&sta_priv->ampdu_lock);
> +}
> +
>  static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
>                                 struct wcn36xx *wcn,
>                                 struct wcn36xx_vif **vif_priv,
> @@ -121,6 +160,8 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
>         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
>         struct ieee80211_vif *vif = NULL;
>         struct wcn36xx_vif *__vif_priv = NULL;
> +       bool is_data_qos;
> +
>         bd->bd_rate = WCN36XX_BD_RATE_DATA;
>
>         /*
> @@ -158,11 +199,16 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
>         }
>         *vif_priv = __vif_priv;
>
> +       is_data_qos = ieee80211_is_data_qos(hdr->frame_control);
> +
>         wcn36xx_set_tx_pdu(bd,
> -                          ieee80211_is_data_qos(hdr->frame_control) ?
> +                          is_data_qos ?
>                            sizeof(struct ieee80211_qos_hdr) :
>                            sizeof(struct ieee80211_hdr_3addr),
>                            skb->len, sta_priv ? sta_priv->tid : 0);
> +
> +       if (sta_priv && is_data_qos)
> +               wcn36xx_tx_start_ampdu(wcn, sta_priv, skb);
>  }
>
>  static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
> diff --git a/wcn36xx.h b/wcn36xx.h
> index 70b0d06..725389e 100644
> --- a/wcn36xx.h
> +++ b/wcn36xx.h
> @@ -33,6 +33,9 @@
>  #define WLAN_NV_FILE               "wlan/prima/WCNSS_qcom_wlan_nv.bin"
>  #define WCN36XX_AGGR_BUFFER_SIZE 64
>
> +/* How many frames until we start a-mpdu TX session */
> +#define WCN36XX_AMPDU_START_THRESH     20
> +
>  extern unsigned int wcn36xx_dbg_mask;
>
>  enum wcn36xx_debug_mask {
> @@ -75,6 +78,13 @@ enum wcn36xx_debug_mask {
>                                buf, len, false);                \
>  } while (0)
>
> +enum wcn36xx_ampdu_state {
> +       WCN36XX_AMPDU_NONE,
> +       WCN36XX_AMPDU_INIT,
> +       WCN36XX_AMPDU_START,
> +       WCN36XX_AMPDU_OPERATIONAL,
> +};
> +
>  #define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value)
>  #define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band)
>  #define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq)
> @@ -166,6 +176,10 @@ struct wcn36xx_sta {
>         bool is_data_encrypted;
>         /* Rates */
>         struct wcn36xx_hal_supported_rates supported_rates;
> +
> +       spinlock_t ampdu_lock;          /* protects next two fields */
> +       enum wcn36xx_ampdu_state ampdu_state[16];
> +       int non_agg_frame_ct;
>  };
>  struct wcn36xx_dxe_ch;
>  struct wcn36xx {
> @@ -262,4 +276,10 @@ struct wcn36xx_sta *wcn36xx_sta_to_priv(struct ieee80211_sta *sta)
>         return (struct wcn36xx_sta *)sta->drv_priv;
>  }
>
> +static inline
> +struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv)
> +{
> +       return container_of((void *) sta_priv, struct ieee80211_sta, drv_priv);
> +}
> +
>  #endif /* _WCN36XX_H_ */
> --
> 1.7.10.4
>
>
> _______________________________________________
> wcn36xx mailing list
> wcn36xx at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/wcn36xx



-- 
Best regards,
Eugene



More information about the wcn36xx mailing list