diff options
author | John Crispin <john@phrozen.org> | 2022-01-31 16:16:44 +0200 |
---|---|---|
committer | Kalle Valo <quic_kvalo@quicinc.com> | 2022-02-01 12:57:07 +0200 |
commit | 3d00e8b5b818266f43d1fabdb961e215cab45dfb (patch) | |
tree | f70a11c5c9694be083c42b352dda0e7597c37cda /drivers/net/wireless/ath/ath11k/wmi.c | |
parent | f295ad912910e08d9b887a0c952f82d9612459d4 (diff) |
ath11k: add WMI calls to manually add/del/pause/resume TWT dialogs
These calls are used for debugging and will be required for WFA
certification tests.
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1
Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220131031043.1295-1-alokad@codeaurora.org
Diffstat (limited to 'drivers/net/wireless/ath/ath11k/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/ath11k/wmi.c | 247 |
1 files changed, 243 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 5b2d8a0e71ee..b4f86c45d81f 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -144,6 +144,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_11d_new_cc_ev) }, [WMI_TAG_PER_CHAIN_RSSI_STATS] = { .min_len = sizeof(struct wmi_per_chain_rssi_stats) }, + [WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT] = { + .min_len = sizeof(struct wmi_twt_add_dialog_event) }, }; #define PRIMAP(_hw_mode_) \ @@ -3085,11 +3087,12 @@ ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id) /* TODO add MBSSID support */ cmd->mbss_support = 0; - ret = ath11k_wmi_cmd_send(wmi, skb, - WMI_TWT_ENABLE_CMDID); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ENABLE_CMDID); if (ret) { ath11k_warn(ab, "Failed to send WMI_TWT_ENABLE_CMDID"); dev_kfree_skb(skb); + } else { + ar->twt_enabled = 1; } return ret; } @@ -3114,11 +3117,181 @@ ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id) FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); cmd->pdev_id = pdev_id; - ret = ath11k_wmi_cmd_send(wmi, skb, - WMI_TWT_DISABLE_CMDID); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DISABLE_CMDID); if (ret) { ath11k_warn(ab, "Failed to send WMI_TWT_DISABLE_CMDID"); dev_kfree_skb(skb); + } else { + ar->twt_enabled = 0; + } + return ret; +} + +int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, + struct wmi_twt_add_dialog_params *params) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct ath11k_base *ab = wmi->wmi_ab->ab; + struct wmi_twt_add_dialog_params_cmd *cmd; + struct sk_buff *skb; + int ret, len; + + len = sizeof(*cmd); + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_twt_add_dialog_params_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_ADD_DIALOG_CMD) | + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + + cmd->vdev_id = params->vdev_id; + ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); + cmd->dialog_id = params->dialog_id; + cmd->wake_intvl_us = params->wake_intvl_us; + cmd->wake_intvl_mantis = params->wake_intvl_mantis; + cmd->wake_dura_us = params->wake_dura_us; + cmd->sp_offset_us = params->sp_offset_us; + cmd->flags = params->twt_cmd; + if (params->flag_bcast) + cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_BCAST; + if (params->flag_trigger) + cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_TRIGGER; + if (params->flag_flow_type) + cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_FLOW_TYPE; + if (params->flag_protection) + cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_PROTECTION; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "wmi add twt dialog vdev %u dialog id %u wake interval %u mantissa %u wake duration %u service period offset %u flags 0x%x\n", + cmd->vdev_id, cmd->dialog_id, cmd->wake_intvl_us, + cmd->wake_intvl_mantis, cmd->wake_dura_us, cmd->sp_offset_us, + cmd->flags); + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ADD_DIALOG_CMDID); + + if (ret) { + ath11k_warn(ab, + "failed to send wmi command to add twt dialog: %d", + ret); + dev_kfree_skb(skb); + } + return ret; +} + +int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, + struct wmi_twt_del_dialog_params *params) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct ath11k_base *ab = wmi->wmi_ab->ab; + struct wmi_twt_del_dialog_params_cmd *cmd; + struct sk_buff *skb; + int ret, len; + + len = sizeof(*cmd); + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_twt_del_dialog_params_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_DEL_DIALOG_CMD) | + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + + cmd->vdev_id = params->vdev_id; + ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); + cmd->dialog_id = params->dialog_id; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "wmi delete twt dialog vdev %u dialog id %u\n", + cmd->vdev_id, cmd->dialog_id); + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DEL_DIALOG_CMDID); + if (ret) { + ath11k_warn(ab, + "failed to send wmi command to delete twt dialog: %d", + ret); + dev_kfree_skb(skb); + } + return ret; +} + +int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, + struct wmi_twt_pause_dialog_params *params) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct ath11k_base *ab = wmi->wmi_ab->ab; + struct wmi_twt_pause_dialog_params_cmd *cmd; + struct sk_buff *skb; + int ret, len; + + len = sizeof(*cmd); + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_twt_pause_dialog_params_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_TWT_PAUSE_DIALOG_CMD) | + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + + cmd->vdev_id = params->vdev_id; + ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); + cmd->dialog_id = params->dialog_id; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "wmi pause twt dialog vdev %u dialog id %u\n", + cmd->vdev_id, cmd->dialog_id); + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_PAUSE_DIALOG_CMDID); + if (ret) { + ath11k_warn(ab, + "failed to send wmi command to pause twt dialog: %d", + ret); + dev_kfree_skb(skb); + } + return ret; +} + +int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, + struct wmi_twt_resume_dialog_params *params) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct ath11k_base *ab = wmi->wmi_ab->ab; + struct wmi_twt_resume_dialog_params_cmd *cmd; + struct sk_buff *skb; + int ret, len; + + len = sizeof(*cmd); + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_twt_resume_dialog_params_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_TWT_RESUME_DIALOG_CMD) | + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + + cmd->vdev_id = params->vdev_id; + ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); + cmd->dialog_id = params->dialog_id; + cmd->sp_offset_us = params->sp_offset_us; + cmd->next_twt_size = params->next_twt_size; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "wmi resume twt dialog vdev %u dialog id %u service period offset %u next twt subfield size %u\n", + cmd->vdev_id, cmd->dialog_id, cmd->sp_offset_us, + cmd->next_twt_size); + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_RESUME_DIALOG_CMDID); + if (ret) { + ath11k_warn(ab, + "failed to send wmi command to resume twt dialog: %d", + ret); + dev_kfree_skb(skb); } return ret; } @@ -7532,6 +7705,66 @@ ath11k_wmi_diag_event(struct ath11k_base *ab, trace_ath11k_wmi_diag(ab, skb->data, skb->len); } +static const char *ath11k_wmi_twt_add_dialog_event_status(u32 status) +{ + switch (status) { + case WMI_ADD_TWT_STATUS_OK: + return "ok"; + case WMI_ADD_TWT_STATUS_TWT_NOT_ENABLED: + return "twt disabled"; + case WMI_ADD_TWT_STATUS_USED_DIALOG_ID: + return "dialog id in use"; + case WMI_ADD_TWT_STATUS_INVALID_PARAM: + return "invalid parameters"; + case WMI_ADD_TWT_STATUS_NOT_READY: + return "not ready"; + case WMI_ADD_TWT_STATUS_NO_RESOURCE: + return "resource unavailable"; + case WMI_ADD_TWT_STATUS_NO_ACK: + return "no ack"; + case WMI_ADD_TWT_STATUS_NO_RESPONSE: + return "no response"; + case WMI_ADD_TWT_STATUS_DENIED: + return "denied"; + case WMI_ADD_TWT_STATUS_UNKNOWN_ERROR: + fallthrough; + default: + return "unknown error"; + } +} + +static void ath11k_wmi_twt_add_dialog_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_twt_add_dialog_event *ev; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, + "failed to parse wmi twt add dialog status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT]; + if (!ev) { + ath11k_warn(ab, "failed to fetch twt add dialog wmi event\n"); + goto exit; + } + + if (ev->status) + ath11k_warn(ab, + "wmi add twt dialog event vdev %d dialog id %d status %s\n", + ev->vdev_id, ev->dialog_id, + ath11k_wmi_twt_add_dialog_event_status(ev->status)); + +exit: + kfree(tb); +} + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -7629,11 +7862,17 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: ath11k_wmi_obss_color_collision_event(ab, skb); break; + case WMI_TWT_ADD_DIALOG_EVENTID: + ath11k_wmi_twt_add_dialog_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: case WMI_TWT_ENABLE_EVENTID: case WMI_TWT_DISABLE_EVENTID: + case WMI_TWT_DEL_DIALOG_EVENTID: + case WMI_TWT_PAUSE_DIALOG_EVENTID: + case WMI_TWT_RESUME_DIALOG_EVENTID: case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: case WMI_PEER_CREATE_CONF_EVENTID: ath11k_dbg(ab, ATH11K_DBG_WMI, |