ath11k: Add sta debugfs support to configure ADDBA and DELBA
authorMaharaja Kennadyrajan <mkenna@codeaurora.org>
Thu, 26 Mar 2020 16:36:32 +0000 (18:36 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 6 Apr 2020 16:13:37 +0000 (19:13 +0300)
Add support to test aggregation procedures (addba/addba_resp/delba)
manually by adding the required callbacks in sta debugfs files.

To enable automatic aggregation in target,

    echo 0 > /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/
     stations/XX:XX:XX:XX:XX:XX/aggr_mode

For manual mode,

    echo 1 > /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/
     stations/XX:XX:XX:XX:XX:XX/aggr_mode

To send addba response,
    echo 0 25 > /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/
stations/XX:XX:XX:XX:XX:XX/addba_resp

To send addba,
    echo 1 32 > /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/
stations/XX:XX:XX:XX:XX:XX/addba

To send delba,
    echo 0 1 37 > /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/
  stations/XX:XX:XX:XX:XX:XX/delba

Signed-off-by: Maharaja Kennadyrajan <mkenna@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1585213026-28406-1-git-send-email-mkenna@codeaurora.org
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/debug.h
drivers/net/wireless/ath/ath11k/debugfs_sta.c
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/ath/ath11k/wmi.h

index 6e7b8ecd09a6bdef5dd5b67aa43737981c25fadb..96ca114c2c4413c5fadf38eecd2bf64eca596d7a 100644 (file)
@@ -341,6 +341,11 @@ struct ath11k_sta {
        u8 rssi_comb;
        struct ath11k_htt_tx_stats *tx_stats;
        struct ath11k_rx_peer_stats *rx_stats;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* protected by conf_mutex */
+       bool aggr_mode;
+#endif
 };
 
 #define ATH11K_NUM_CHANS 41
index 97e7306c506d9eb1d9f6739612d6b8156c820809..4a3ff8227187c5223dd0caa4bfa4cb280dd8e4ab 100644 (file)
@@ -112,6 +112,12 @@ enum ath11k_pktlog_enum {
        ATH11K_PKTLOG_TYPE_LITE_RX      = 24,
 };
 
+enum ath11k_dbg_aggr_mode {
+       ATH11K_DBG_AGGR_MODE_AUTO,
+       ATH11K_DBG_AGGR_MODE_MANUAL,
+       ATH11K_DBG_AGGR_MODE_MAX,
+};
+
 __printf(2, 3) void ath11k_info(struct ath11k_base *ab, const char *fmt, ...);
 __printf(2, 3) void ath11k_err(struct ath11k_base *ab, const char *fmt, ...);
 __printf(2, 3) void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...);
index 389dac2192380dd4e0f38bf15e6dad1148a3ef0f..68963cfc5097f90a7e166323f612d60b1d5776d5 100644 (file)
@@ -533,6 +533,222 @@ static const struct file_operations fops_peer_pktlog = {
        .llseek = default_llseek,
 };
 
+static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 tid, initiator, reason;
+       int ret;
+       char buf[64] = {0};
+
+       ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
+                                    user_buf, count);
+       if (ret <= 0)
+               return ret;
+
+       ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
+       if (ret != 3)
+               return -EINVAL;
+
+       /* Valid TID values are 0 through 15 */
+       if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
+                                   tid, initiator, reason);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
+                           arsta->arvif->vdev_id, sta->addr, tid, initiator,
+                           reason);
+       }
+       ret = count;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_delba = {
+       .write = ath11k_dbg_sta_write_delba,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
+                                              const char __user *user_buf,
+                                              size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 tid, status;
+       int ret;
+       char buf[64] = {0};
+
+       ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
+                                    user_buf, count);
+       if (ret <= 0)
+               return ret;
+
+       ret = sscanf(buf, "%u %u", &tid, &status);
+       if (ret != 2)
+               return -EINVAL;
+
+       /* Valid TID values are 0 through 15 */
+       if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
+                                       tid, status);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
+                           arsta->arvif->vdev_id, sta->addr, tid, status);
+       }
+       ret = count;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_addba_resp = {
+       .write = ath11k_dbg_sta_write_addba_resp,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 tid, buf_size;
+       int ret;
+       char buf[64] = {0};
+
+       ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
+                                    user_buf, count);
+       if (ret <= 0)
+               return ret;
+
+       ret = sscanf(buf, "%u %u", &tid, &buf_size);
+       if (ret != 2)
+               return -EINVAL;
+
+       /* Valid TID values are 0 through 15 */
+       if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
+                                   tid, buf_size);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
+                           arsta->arvif->vdev_id, sta->addr, tid, buf_size);
+       }
+
+       ret = count;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_addba = {
+       .write = ath11k_dbg_sta_write_addba,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
+                                            char __user *user_buf,
+                                            size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       char buf[64];
+       int len = 0;
+
+       mutex_lock(&ar->conf_mutex);
+       len = scnprintf(buf, sizeof(buf) - len,
+                       "aggregation mode: %s\n\n%s\n%s\n",
+                       (arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
+                       "auto" : "manual", "auto = 0", "manual = 1");
+       mutex_unlock(&ar->conf_mutex);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
+                                             const char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       u32 aggr_mode;
+       int ret;
+
+       if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
+               return -EINVAL;
+
+       if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON ||
+           aggr_mode == arsta->aggr_mode) {
+               ret = count;
+               goto out;
+       }
+
+       ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
+                           ret);
+               goto out;
+       }
+
+       arsta->aggr_mode = aggr_mode;
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static const struct file_operations fops_aggr_mode = {
+       .read = ath11k_dbg_sta_read_aggr_mode,
+       .write = ath11k_dbg_sta_write_aggr_mode,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, struct dentry *dir)
 {
@@ -550,4 +766,9 @@ void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
        debugfs_create_file("peer_pktlog", 0644, dir, sta,
                            &fops_peer_pktlog);
+
+       debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
+       debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
+       debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
+       debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
 }
index e7ce36966d6a74ec0bd2646f84ea573344e5e4e0..49a17c85303a446e44eac6342ff1c588aa5d66a3 100644 (file)
@@ -2368,6 +2368,146 @@ int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar,
        return ret;
 }
 
+int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 initiator, u32 reason)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_delba_send_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_delba_send_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_DELBA_SEND_CMD) |
+                       FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+       cmd->tid = tid;
+       cmd->initiator = initiator;
+       cmd->reasoncode = reason;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n",
+                  vdev_id, mac, tid, initiator, reason);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_DELBA_SEND_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_DELBA_SEND_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_addba_set_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                             u32 tid, u32 status)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_addba_setresponse_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_addba_setresponse_cmd *)skb->data;
+       cmd->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ADDBA_SETRESPONSE_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+       cmd->tid = tid;
+       cmd->statuscode = status;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n",
+                  vdev_id, mac, tid, status);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SET_RESP_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_ADDBA_SET_RESP_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_addba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 buf_size)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_addba_send_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_addba_send_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ADDBA_SEND_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+       cmd->tid = tid;
+       cmd->buffersize = buf_size;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n",
+                  vdev_id, mac, tid, buf_size);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SEND_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_ADDBA_SEND_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_addba_clear_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_addba_clear_resp_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_addba_clear_resp_cmd *)skb->data;
+       cmd->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ADDBA_CLEAR_RESP_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, mac);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n",
+                  vdev_id, mac);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_CLEAR_RESP_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_ADDBA_CLEAR_RESP_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
 int ath11k_wmi_pdev_peer_pktlog_filter(struct ath11k *ar, u8 *addr, u8 enable)
 {
        struct ath11k_pdev_wmi *wmi = ar->wmi;
index 510f9c6bc1d78a56140602c5f6f95d0036535793..780e6620142de6c203fc988ce70c005ec27e7f0c 100644 (file)
@@ -3649,6 +3649,37 @@ struct wmi_therm_throt_level_config_info {
        u32 prio;
 } __packed;
 
+struct wmi_delba_send_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid;
+       u32 initiator;
+       u32 reasoncode;
+} __packed;
+
+struct wmi_addba_setresponse_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid;
+       u32 statuscode;
+} __packed;
+
+struct wmi_addba_send_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid;
+       u32 buffersize;
+} __packed;
+
+struct wmi_addba_clear_resp_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
 struct wmi_pdev_pktlog_filter_info {
        u32 tlv_header;
        struct wmi_mac_addr peer_macaddr;
@@ -4822,6 +4853,13 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
                                       struct scan_chan_list_params *chan_list);
 int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar,
                                                  u32 pdev_id);
+int ath11k_wmi_addba_clear_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac);
+int ath11k_wmi_addba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 buf_size);
+int ath11k_wmi_addba_set_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                             u32 tid, u32 status);
+int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
+                         u32 tid, u32 initiator, u32 reason);
 int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
                                            u32 vdev_id, u32 bcn_ctrl_op);
 int