From dff202269a6ca472a74fb82ff67bab9582265f56 Mon Sep 17 00:00:00 2001 From: Aditya Sathish Date: Mon, 15 Oct 2018 22:44:58 +0530 Subject: [PATCH] qcacmn: Provide WMI support for AP channel switching enhancements Provide WMI support for AP channel switching enhancements. As part of FR50393, AP is provided with the ability to notify capable connected peers to follow it to the new channel bandwidth. This change provides WMI support for sending required parameters to the firmware to update the peer list internally with the MAC address of the capable peer along with it's new channel width. Change-Id: I0696efd2b1c883d15de23364677050618f114743 CRs-Fixed: 2316625 --- wmi/inc/wmi_unified_ap_api.h | 3 ++ wmi/inc/wmi_unified_param.h | 21 ++++++++ wmi/inc/wmi_unified_priv.h | 3 ++ wmi/src/wmi_unified_ap_api.c | 18 +++++++ wmi/src/wmi_unified_ap_tlv.c | 92 +++++++++++++++++++++++++++++++++++ wmi/src/wmi_unified_non_tlv.c | 76 +++++++++++++++++++++++++++++ 6 files changed, 213 insertions(+) diff --git a/wmi/inc/wmi_unified_ap_api.h b/wmi/inc/wmi_unified_ap_api.h index 5a0f73f25188..fca365d6582a 100644 --- a/wmi/inc/wmi_unified_ap_api.h +++ b/wmi/inc/wmi_unified_ap_api.h @@ -230,4 +230,7 @@ QDF_STATUS wmi_extract_chan_info_event(void *wmi_hdl, void *evt_buf, QDF_STATUS wmi_extract_channel_hopping_event(void *wmi_hdl, void *evt_buf, wmi_host_pdev_channel_hopping_event *ch_hopping); + +QDF_STATUS wmi_unified_peer_chan_width_switch_cmd_send(void *wmi_hdl, + struct peer_chan_width_switch_params *param); #endif /* _WMI_UNIFIED_AP_API_H_ */ diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index d956d8598b87..baf6399c0457 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -3089,7 +3089,28 @@ struct set_qdepth_thresh_params { msduq_update_params update_params[QDEPTH_THRESH_MAX_UPDATES]; }; +/** + * struct peer_chan_width_switch_info - Peer channel width capability params + * @mac_addr: MAC address of peer + * @chan_width: Max supported channel width of peer + * (enum ieee80211_cwm_width) + */ +struct peer_chan_width_switch_info { + uint8_t mac_addr[IEEE80211_ADDR_LEN]; + uint32_t chan_width; +}; + +/** + * struct peer_chan_width_switch_params - Peer channel width capability wrapper + * @num_peers: Total number of peers connected to AP + * @chan_width_peer_list: List of capabilities for all connected peers + */ + +struct peer_chan_width_switch_params { + uint32_t num_peers; + struct peer_chan_width_switch_info *chan_width_peer_list; +}; /** * struct config_ratemask_params - ratemask config parameters diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 1be405fa70b2..16c07c9ba317 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1124,6 +1124,9 @@ QDF_STATUS (*send_vdev_set_custom_aggr_size_cmd)(wmi_unified_t wmi_handle, QDF_STATUS (*send_vdev_set_qdepth_thresh_cmd)(wmi_unified_t wmi_handle, struct set_qdepth_thresh_params *param); +QDF_STATUS (*send_peer_chan_width_switch_cmd)(wmi_unified_t wmi_handle, + struct peer_chan_width_switch_params *param); + QDF_STATUS (*send_wow_wakeup_cmd)(wmi_unified_t wmi_handle); QDF_STATUS (*send_wow_add_wakeup_event_cmd)(wmi_unified_t wmi_handle, diff --git a/wmi/src/wmi_unified_ap_api.c b/wmi/src/wmi_unified_ap_api.c index ed19037759f7..0b80c3a61fbd 100644 --- a/wmi/src/wmi_unified_ap_api.c +++ b/wmi/src/wmi_unified_ap_api.c @@ -1061,3 +1061,21 @@ QDF_STATUS wmi_extract_channel_hopping_event(void *wmi_hdl, void *evt_buf, return QDF_STATUS_E_FAILURE; } + +/** + * wmi_unified_peer_chan_width_switch_cmd_send() - WMI send peer chan width + * @wmi_hdl: handle to WMI + * @param: pointer to hold peer capability param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_chan_width_switch_cmd_send(void *wmi_hdl, + struct peer_chan_width_switch_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t)wmi_hdl; + + if (wmi->ops->send_peer_chan_width_switch_cmd) + return wmi->ops->send_peer_chan_width_switch_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} diff --git a/wmi/src/wmi_unified_ap_tlv.c b/wmi/src/wmi_unified_ap_tlv.c index ebea7d6e5d06..cf1ad18af0a3 100644 --- a/wmi/src/wmi_unified_ap_tlv.c +++ b/wmi/src/wmi_unified_ap_tlv.c @@ -2467,6 +2467,96 @@ static QDF_STATUS extract_channel_hopping_event_tlv( return QDF_STATUS_SUCCESS; } +/** + * send_peer_chan_width_switch_cmd_tlv() - send peer channel width params + * @wmi_handle: WMI handle + * @param: Peer channel width switching params + * + * Return: QDF_STATUS_SUCCESS on success or error code + */ + +static QDF_STATUS +send_peer_chan_width_switch_cmd_tlv(wmi_unified_t wmi_handle, + struct peer_chan_width_switch_params *param) +{ + wmi_buf_t buf; + wmi_peer_chan_width_switch_cmd_fixed_param *cmd; + int32_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + int16_t max_peers_per_command; + wmi_chan_width_peer_list *cmd_peer_list; + int16_t pending_peers = param->num_peers; + struct peer_chan_width_switch_info *param_peer_list = + param->chan_width_peer_list; + uint8_t ix; + + max_peers_per_command = (wmi_get_max_msg_len(wmi_handle) - + sizeof(*cmd) - WMI_TLV_HDR_SIZE) / + sizeof(*cmd_peer_list); + + while (pending_peers > 0) { + if (pending_peers >= max_peers_per_command) { + len += (max_peers_per_command * sizeof(*cmd_peer_list)); + } else { + len += (pending_peers * sizeof(*cmd_peer_list)); + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("wmi_buf_alloc failed"); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_peer_chan_width_switch_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_chan_width_switch_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_peer_chan_width_switch_cmd_fixed_param)); + + cmd->num_peers = (pending_peers >= max_peers_per_command) ? + max_peers_per_command : pending_peers; + + WMITLV_SET_HDR(((void *)cmd + sizeof(*cmd)), + WMITLV_TAG_ARRAY_STRUC, + cmd->num_peers * + sizeof(wmi_chan_width_peer_list)); + + cmd_peer_list = (wmi_chan_width_peer_list *) + ((void *)cmd + sizeof(*cmd) + + WMI_TLV_HDR_SIZE); + + for (ix = 0; ix < cmd->num_peers; ix++) { + WMITLV_SET_HDR(&cmd_peer_list[ix].tlv_header, + WMITLV_TAG_STRUC_wmi_chan_width_peer_list, + WMITLV_GET_STRUCT_TLVLEN( + wmi_chan_width_peer_list)); + + WMI_CHAR_ARRAY_TO_MAC_ADDR(param_peer_list[ix].mac_addr, + &cmd_peer_list[ix].peer_macaddr); + + cmd_peer_list[ix].chan_width = + param_peer_list[ix].chan_width; + + WMI_LOGD("Peer[%u]: chan_width = %u", ix, + cmd_peer_list[ix].chan_width); + } + + pending_peers -= cmd->num_peers; + param_peer_list += cmd->num_peers; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_CHAN_WIDTH_SWITCH_CMDID)) { + WMI_LOGE("Sending peers for chwidth switch failed"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + } + + return QDF_STATUS_SUCCESS; +} + void wmi_ap_attach_tlv(wmi_unified_t wmi_handle) { struct wmi_ops *ops = wmi_handle->ops; @@ -2541,4 +2631,6 @@ void wmi_ap_attach_tlv(wmi_unified_t wmi_handle) ops->extract_mgmt_tx_compl_param = extract_mgmt_tx_compl_param_tlv; ops->extract_chan_info_event = extract_chan_info_event_tlv; ops->extract_channel_hopping_event = extract_channel_hopping_event_tlv; + ops->send_peer_chan_width_switch_cmd = + send_peer_chan_width_switch_cmd_tlv; } diff --git a/wmi/src/wmi_unified_non_tlv.c b/wmi/src/wmi_unified_non_tlv.c index e40c80315fda..b558e5238460 100644 --- a/wmi/src/wmi_unified_non_tlv.c +++ b/wmi/src/wmi_unified_non_tlv.c @@ -622,6 +622,80 @@ static QDF_STATUS send_vdev_up_cmd_non_tlv(wmi_unified_t wmi_handle, return wmi_unified_cmd_send(wmi_handle, buf, len, WMI_VDEV_UP_CMDID); } +/** + * send_peer_chan_width_switch_cmd_non_tlv() - send peer channel width params + * @wmi_handle: WMI handle + * @param: Peer channel width switching params + * + * Return: 0 for success or error code + */ + +static QDF_STATUS +send_peer_chan_width_switch_cmd_non_tlv(wmi_unified_t wmi_handle, + struct peer_chan_width_switch_params *param) +{ + wmi_buf_t buf; + wmi_peer_chan_width_switch_cmd *cmd; + int len = sizeof(*cmd); + int max_peers_per_command; + struct chan_width_peer_list *cmd_peer_list; + int pending_peers = param->num_peers; + struct peer_chan_width_switch_info *param_peer_list = + param->chan_width_peer_list; + int ix; + + max_peers_per_command = (wmi_get_max_msg_len(wmi_handle) - + sizeof(*cmd)) / sizeof(*cmd_peer_list); + + while (pending_peers > 0) { + if (pending_peers >= max_peers_per_command) { + len += (max_peers_per_command * sizeof(*cmd_peer_list)); + } else { + len += (pending_peers * sizeof(*cmd_peer_list)); + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("wmi_buf_alloc failed"); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_peer_chan_width_switch_cmd *) + wmi_buf_data(buf); + + cmd->num_peers = (pending_peers >= max_peers_per_command) ? + max_peers_per_command : pending_peers; + + cmd_peer_list = (struct chan_width_peer_list *) + (cmd + sizeof(*cmd)); + + for (ix = 0; ix < cmd->num_peers; ix++) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(param_peer_list[ix].mac_addr, + &cmd_peer_list[ix].peer_macaddr); + + cmd_peer_list[ix].chan_width = + param_peer_list[ix].chan_width; + + WMI_LOGD("Peer[%u]: chan_width = %u", ix, + cmd_peer_list[ix].chan_width); + } + + pending_peers -= cmd->num_peers; + param_peer_list += cmd->num_peers; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_CHAN_WIDTH_SWITCH_CMDID)) { + WMI_LOGE("Sending peers for chwidth switch failed"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + } + + return QDF_STATUS_SUCCESS; + +} + /** * send_peer_create_cmd_non_tlv() - send peer create command to fw * @wmi_handle: wmi handle @@ -8871,6 +8945,8 @@ struct wmi_ops non_tlv_ops = { .send_set_ps_mode_cmd = send_set_ps_mode_cmd_non_tlv, .init_cmd_send = init_cmd_send_non_tlv, .send_ext_resource_config = send_ext_resource_config_non_tlv, + .send_peer_chan_width_switch_cmd = + send_peer_chan_width_switch_cmd_non_tlv, #if 0 .send_bcn_prb_template_cmd = send_bcn_prb_template_cmd_non_tlv, #endif