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