mwl8k: add support for block ack commands
authorNishant Sarmukadam <nishants@marvell.com>
Thu, 17 Mar 2011 18:58:43 +0000 (11:58 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 30 Mar 2011 18:15:13 +0000 (14:15 -0400)
Signed-off-by: Pradeep Nemavat <pnemavat@marvell.com>
Signed-off-by: Brian Cavagnolo <brian@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwl8k.c

index 9db66d58f0efb05ce1b2e7536b685e51dac0604c..944ad030e4ddaad6a11915408ddc9678b419a9dc 100644 (file)
@@ -135,6 +135,14 @@ struct mwl8k_tx_queue {
        struct sk_buff **skb;
 };
 
+struct mwl8k_ampdu_stream {
+       struct ieee80211_sta *sta;
+       u8 tid;
+       u8 state;
+       u8 idx;
+       u8 txq_idx; /* index of this stream in priv->txq */
+};
+
 struct mwl8k_priv {
        struct ieee80211_hw *hw;
        struct pci_dev *pdev;
@@ -360,6 +368,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
 #define MWL8K_CMD_SET_NEW_STN          0x1111          /* per-vif */
 #define MWL8K_CMD_UPDATE_ENCRYPTION    0x1122          /* per-vif */
 #define MWL8K_CMD_UPDATE_STADB         0x1123
+#define MWL8K_CMD_BASTREAM             0x1125
 
 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
 {
@@ -399,6 +408,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
                MWL8K_CMDNAME(SET_NEW_STN);
                MWL8K_CMDNAME(UPDATE_ENCRYPTION);
                MWL8K_CMDNAME(UPDATE_STADB);
+               MWL8K_CMDNAME(BASTREAM);
        default:
                snprintf(buf, bufsize, "0x%x", cmd);
        }
@@ -3175,6 +3185,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
        return rc;
 }
 
+/*
+ * CMD_BASTREAM.
+ */
+
+/*
+ * UPSTREAM is tx direction
+ */
+#define BASTREAM_FLAG_DIRECTION_UPSTREAM       0x00
+#define BASTREAM_FLAG_IMMEDIATE_TYPE           0x01
+
+enum {
+       MWL8K_BA_CREATE,
+       MWL8K_BA_UPDATE,
+       MWL8K_BA_DESTROY,
+       MWL8K_BA_FLUSH,
+       MWL8K_BA_CHECK,
+} ba_stream_action_type;
+
+
+struct mwl8k_create_ba_stream {
+       __le32  flags;
+       __le32  idle_thrs;
+       __le32  bar_thrs;
+       __le32  window_size;
+       u8      peer_mac_addr[6];
+       u8      dialog_token;
+       u8      tid;
+       u8      queue_id;
+       u8      param_info;
+       __le32  ba_context;
+       u8      reset_seq_no_flag;
+       __le16  curr_seq_no;
+       u8      sta_src_mac_addr[6];
+} __packed;
+
+struct mwl8k_destroy_ba_stream {
+       __le32  flags;
+       __le32  ba_context;
+} __packed;
+
+struct mwl8k_cmd_bastream {
+       struct mwl8k_cmd_pkt    header;
+       __le32  action;
+       union {
+               struct mwl8k_create_ba_stream   create_params;
+               struct mwl8k_destroy_ba_stream  destroy_params;
+       };
+} __packed;
+
+static int
+mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+       struct mwl8k_cmd_bastream *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       cmd->action = cpu_to_le32(MWL8K_BA_CHECK);
+
+       cmd->create_params.queue_id = stream->idx;
+       memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr,
+              ETH_ALEN);
+       cmd->create_params.tid = stream->tid;
+
+       cmd->create_params.flags =
+               cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) |
+               cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+
+       kfree(cmd);
+
+       return rc;
+}
+
+static int
+mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
+               u8 buf_size)
+{
+       struct mwl8k_cmd_bastream *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       cmd->action = cpu_to_le32(MWL8K_BA_CREATE);
+
+       cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size);
+       cmd->create_params.window_size = cpu_to_le32((u32)buf_size);
+       cmd->create_params.queue_id = stream->idx;
+
+       memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN);
+       cmd->create_params.tid = stream->tid;
+       cmd->create_params.curr_seq_no = cpu_to_le16(0);
+       cmd->create_params.reset_seq_no_flag = 1;
+
+       cmd->create_params.param_info =
+               (stream->sta->ht_cap.ampdu_factor &
+                IEEE80211_HT_AMPDU_PARM_FACTOR) |
+               ((stream->sta->ht_cap.ampdu_density << 2) &
+                IEEE80211_HT_AMPDU_PARM_DENSITY);
+
+       cmd->create_params.flags =
+               cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE |
+                                       BASTREAM_FLAG_DIRECTION_UPSTREAM);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+
+       wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n",
+               stream->sta->addr, stream->tid);
+       kfree(cmd);
+
+       return rc;
+}
+
+static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
+                            struct mwl8k_ampdu_stream *stream)
+{
+       struct mwl8k_cmd_bastream *cmd;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le32(MWL8K_BA_DESTROY);
+
+       cmd->destroy_params.ba_context = cpu_to_le32(stream->idx);
+       mwl8k_post_cmd(hw, &cmd->header);
+
+       wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx);
+
+       kfree(cmd);
+}
+
 /*
  * CMD_SET_NEW_STN.
  */