diff --git a/wmi/inc/wmi_unified_11be_api.h b/wmi/inc/wmi_unified_11be_api.h new file mode 100644 index 0000000000..425b2117e0 --- /dev/null +++ b/wmi/inc/wmi_unified_11be_api.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * This file contains the API definitions for the Unified Wireless Module + * Interface (WMI) specific to 11be. + */ + +#ifndef _WMI_UNIFIED_11BE_API_H_ +#define _WMI_UNIFIED_11BE_API_H_ + +#include +#include +#include + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wmi_extract_mlo_link_set_active_resp() - extract mlo link set active + * response event + * @wmi: wmi handle + * @evt_buf: pointer to event buffer + * @evt: Pointer to hold mlo link set active response event + * + * This function gets called to extract mlo link set active response event + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_mlo_link_set_active_resp(wmi_unified_t wmi, + void *evt_buf, + struct wmi_mlo_link_set_active_resp *evt); + +/** + * wmi_send_mlo_link_set_active_cmd() - send mlo link set active command + * @wmi: WMI handle for this pdev + * @param: Pointer to mlo link set active param + * + * Return: QDF_STATUS code + */ +QDF_STATUS +wmi_send_mlo_link_set_active_cmd(wmi_unified_t wmi_handle, + struct wmi_mlo_link_set_active_param *param); +#endif /*WLAN_FEATURE_11BE_MLO*/ +#endif /*_WMI_UNIFIED_11BE_API_H_*/ diff --git a/wmi/inc/wmi_unified_11be_param.h b/wmi/inc/wmi_unified_11be_param.h index da5dfdbdf8..b1731032a3 100644 --- a/wmi/inc/wmi_unified_11be_param.h +++ b/wmi/inc/wmi_unified_11be_param.h @@ -18,8 +18,6 @@ #ifndef _WMI_UNIFIED_11BE_PARAM_H_ #define _WMI_UNIFIED_11BE_PARAM_H_ -#include - #ifdef WLAN_FEATURE_11BE_MLO #define MAX_LINK_IN_MLO 6 @@ -97,5 +95,96 @@ struct wmi_mlo_teardown_cmpl_params { uint32_t pdev_id; enum wmi_mlo_teardown_status status; }; + +/* maximum size of vdev bitmap array for MLO link set active command */ +#define WMI_MLO_VDEV_BITMAP_SZ 2 + +/* maximum size of link number param array for MLO link set active command */ +#define WMI_MLO_LINK_NUM_SZ 2 + +/** + * enum wmi_mlo_link_force_mode: MLO link force modes + * @WMI_MLO_LINK_FORCE_MODE_ACTIVE: + * Force specific links active + * @WMI_MLO_LINK_FORCE_MODE_INACTIVE: + * Force specific links inactive + * @WMI_MLO_LINK_FORCE_MODE_ACTIVE_NUM: + * Force active a number of links, firmware to decide which links to inactive + * @WMI_MLO_LINK_FORCE_MODE_INACTIVE_NUM: + * Force inactive a number of links, firmware to decide which links to inactive + * @WMI_MLO_LINK_FORCE_MODE_NO_FORCE: + * Cancel the force operation of specific links, allow firmware to decide + */ +enum wmi_mlo_link_force_mode { + WMI_MLO_LINK_FORCE_MODE_ACTIVE = 1, + WMI_MLO_LINK_FORCE_MODE_INACTIVE = 2, + WMI_MLO_LINK_FORCE_MODE_ACTIVE_NUM = 3, + WMI_MLO_LINK_FORCE_MODE_INACTIVE_NUM = 4, + WMI_MLO_LINK_FORCE_MODE_NO_FORCE = 5, +}; + +/** + * enum wmi_mlo_link_force_reason: MLO link force reasons + * @WMI_MLO_LINK_FORCE_REASON_CONNECT: + * Set force specific links because of new connection + * @WMI_MLO_LINK_FORCE_REASON_DISCONNECT: + * Set force specific links because of new dis-connection + */ +enum wmi_mlo_link_force_reason { + WMI_MLO_LINK_FORCE_REASON_CONNECT = 1, + WMI_MLO_LINK_FORCE_REASON_DISCONNECT = 2, +}; + +/** + * struct wmi_mlo_link_set_active_resp: MLO link set active response structure + * @status: Return status, 0 for success, non-zero otherwise + * @active_sz: size of current active vdev bitmap array + * @active: current active vdev bitmap array + * @inactive_sz: size of current inactive vdev bitmap array + * @inactive: current inactive vdev bitmap array + */ +struct wmi_mlo_link_set_active_resp { + uint32_t status; + uint32_t active_sz; + uint32_t active[WMI_MLO_VDEV_BITMAP_SZ]; + uint32_t inactive_sz; + uint32_t inactive[WMI_MLO_VDEV_BITMAP_SZ]; +}; + +/** + * struct wmi_mlo_link_num_param: MLO link set active number params + * @num_of_link: number of links to active/inactive + * @vdev_type: type of vdev + * @vdev_subtype: subtype of vdev + * @home_freq: home frequency of the link + */ +struct wmi_mlo_link_num_param { + uint32_t num_of_link; + uint32_t vdev_type; + uint32_t vdev_subtype; + uint32_t home_freq; +}; + +/** + * struct wmi_mlo_link_set_active_param: MLO link set active params + * @force_mode: operation to take (enum wmi_mlo_link_force_mode) + * @reason: reason for the operation (enum wmi_mlo_link_force_reason) + * @entry_num: number of the valid entries for link_num/vdev_bitmap + * @link_num: link number param array + * It's present only when force_mode is WMI_MLO_LINK_FORCE_MODE_ACTIVE_NUM or + * WMI_MLO_LINK_FORCE_MODE_INACTIVE_NUM + * @vdev_bitmap: active/inactive vdev bitmap array + * It's present only when force_mode is WMI_MLO_LINK_FORCE_MODE_ACTIVE, + * WMI_MLO_LINK_FORCE_MODE_INACTIVE or WMI_MLO_LINK_FORCE_MODE_NO_FORCE. + */ +struct wmi_mlo_link_set_active_param { + uint32_t force_mode; + uint32_t reason; + uint32_t entry_num; + union { + struct wmi_mlo_link_num_param link_num[WMI_MLO_LINK_NUM_SZ]; + uint32_t vdev_bitmap[WMI_MLO_VDEV_BITMAP_SZ]; + }; +}; #endif #endif diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 74467c9537..4959036f53 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -4654,6 +4654,7 @@ typedef enum { #ifdef WLAN_FEATURE_11BE_MLO wmi_mlo_setup_complete_event_id, wmi_mlo_teardown_complete_event_id, + wmi_mlo_link_set_active_resp_eventid, #endif wmi_events_max, } wmi_conv_event_id; diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index d80f390050..4db47ddf17 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -2738,6 +2738,14 @@ QDF_STATUS (*extract_mlo_teardown_cmpl_event)(wmi_unified_t wmi_handle, uint8_t *buf, struct wmi_mlo_teardown_cmpl_params *param); +QDF_STATUS +(*send_mlo_link_set_active_cmd)(wmi_unified_t wmi_handle, + struct wmi_mlo_link_set_active_param *param); + +QDF_STATUS +(*extract_mlo_link_set_active_resp)(wmi_unified_t wmi_handle, + void *evt_buf, + struct wmi_mlo_link_set_active_resp *resp); #endif }; diff --git a/wmi/src/wmi_unified_11be_api.c b/wmi/src/wmi_unified_11be_api.c new file mode 100644 index 0000000000..251e728d17 --- /dev/null +++ b/wmi/src/wmi_unified_11be_api.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implement API's specific to 11be. + */ + +#include "wmi_unified_11be_api.h" + +/** + * wmi_extract_mlo_link_set_active_resp() - extract mlo link set active resp + * from event + * @wmi: WMI handle for this pdev + * @evt_buf: pointer to event buffer + * @resp: Pointer to hold mlo link set active resp + * + * Return: QDF_STATUS code + */ +QDF_STATUS +wmi_extract_mlo_link_set_active_resp(wmi_unified_t wmi, + void *evt_buf, + struct wmi_mlo_link_set_active_resp *resp) +{ + if (wmi->ops->extract_mlo_link_set_active_resp) { + return wmi->ops->extract_mlo_link_set_active_resp(wmi, + evt_buf, + resp); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_send_mlo_link_set_active_cmd() - send mlo link set active command + * @wmi: WMI handle for this pdev + * @param: Pointer to mlo link set active param + * + * Return: QDF_STATUS code + */ +QDF_STATUS +wmi_send_mlo_link_set_active_cmd(wmi_unified_t wmi, + struct wmi_mlo_link_set_active_param *param) +{ + if (wmi->ops->send_mlo_link_set_active_cmd) + return wmi->ops->send_mlo_link_set_active_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} diff --git a/wmi/src/wmi_unified_11be_tlv.c b/wmi/src/wmi_unified_11be_tlv.c index d4ca81757d..de76b6e5b4 100644 --- a/wmi/src/wmi_unified_11be_tlv.c +++ b/wmi/src/wmi_unified_11be_tlv.c @@ -258,6 +258,229 @@ uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr, sizeof(wmi_peer_assoc_mlo_partner_link_params)); } +/** + * force_mode_host_to_fw() - translate force mode for MLO link set active + * command + * @force_mode: force mode defined by host + * + * Return: force mode defined by firmware + */ +static inline WMI_MLO_LINK_FORCE_MODE +force_mode_host_to_fw(enum wmi_mlo_link_force_mode force_mode) +{ + switch (force_mode) { + case WMI_MLO_LINK_FORCE_MODE_ACTIVE: + return WMI_MLO_LINK_FORCE_ACTIVE; + case WMI_MLO_LINK_FORCE_MODE_INACTIVE: + return WMI_MLO_LINK_FORCE_INACTIVE; + case WMI_MLO_LINK_FORCE_MODE_ACTIVE_NUM: + return WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM; + case WMI_MLO_LINK_FORCE_MODE_INACTIVE_NUM: + return WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM; + case WMI_MLO_LINK_FORCE_MODE_NO_FORCE: + return WMI_MLO_LINK_NO_FORCE; + default: + return force_mode; + } +} + +/** + * force_reason_host_to_fw() - translate force reason for MLO link set active + * command + * @force_reason: force reason defined by host + * + * Return: force reason defined by firmware + */ +static inline WMI_MLO_LINK_FORCE_REASON +force_reason_host_to_fw(enum wmi_mlo_link_force_reason force_reason) +{ + switch (force_reason) { + case WMI_MLO_LINK_FORCE_REASON_CONNECT: + return WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT; + case WMI_MLO_LINK_FORCE_REASON_DISCONNECT: + return WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT; + default: + return force_reason; + } +} + +/** + * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command + * @wmi_handle: wmi handle + * @param: Pointer to mlo link set active param + * + * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error + */ +static QDF_STATUS +send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_mlo_link_set_active_param *param) +{ + QDF_STATUS status; + wmi_mlo_link_set_active_cmd_fixed_param *cmd; + wmi_mlo_set_active_link_number_param *link_num_param; + uint32_t *vdev_bitmap; + uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + int i; + WMITLV_TAG_ID tag_id; + uint32_t force_mode, force_reason; + + if (!param->entry_num) { + wmi_err("No entry is provided"); + return QDF_STATUS_E_INVAL; + } + + force_mode = force_mode_host_to_fw(param->force_mode); + switch (force_mode) { + case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM: + case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM: + num_link_num_param = param->entry_num; + break; + case WMI_MLO_LINK_FORCE_ACTIVE: + case WMI_MLO_LINK_FORCE_INACTIVE: + case WMI_MLO_LINK_NO_FORCE: + num_vdev_bitmap = param->entry_num; + break; + default: + wmi_err("Invalid force mode: %d", force_mode); + return QDF_STATUS_E_INVAL; + } + + force_reason = force_reason_host_to_fw(param->reason); + if (force_reason < WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT || + force_reason > WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT) { + wmi_err("Invalid force reason: %d", force_reason); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param + + WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr; + tlv_len = WMITLV_GET_STRUCT_TLVLEN + (wmi_mlo_link_set_active_cmd_fixed_param); + + tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param; + WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len); + cmd->force_mode = force_mode; + cmd->reason = force_reason; + wmi_debug("mode %d reason %d", cmd->force_mode, cmd->reason); + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(*link_num_param) * num_link_num_param); + buf_ptr += WMI_TLV_HDR_SIZE; + + if (num_link_num_param) { + link_num_param = + (wmi_mlo_set_active_link_number_param *)buf_ptr; + tlv_len = WMITLV_GET_STRUCT_TLVLEN + (wmi_mlo_set_active_link_number_param); + for (i = 0; i < num_link_num_param; i++) { + WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len); + link_num_param->num_of_link = + param->link_num[i].num_of_link; + link_num_param->vdev_type = + param->link_num[i].vdev_type; + link_num_param->vdev_subtype = + param->link_num[i].vdev_subtype; + link_num_param->home_freq = + param->link_num[i].home_freq; + wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d", + i, link_num_param->num_of_link, + link_num_param->vdev_type, + link_num_param->vdev_subtype, + link_num_param->home_freq); + link_num_param++; + } + + buf_ptr += sizeof(*link_num_param) * num_link_num_param; + } + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + sizeof(*vdev_bitmap) * num_vdev_bitmap); + buf_ptr += WMI_TLV_HDR_SIZE; + + if (num_vdev_bitmap) { + vdev_bitmap = (A_UINT32 *)(buf_ptr); + for (i = 0; i < num_vdev_bitmap; i++) { + vdev_bitmap[i] = param->vdev_bitmap[i]; + wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ", + i, vdev_bitmap[i]); + } + + buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap; + } + + wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_MLO_LINK_SET_ACTIVE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("Failed to send MLO link set active command to FW: %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp + * from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @resp: Pointer to hold mlo link set active resp + * + * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error + */ +static QDF_STATUS +extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct wmi_mlo_link_set_active_resp *resp) +{ + wmi_mlo_link_set_active_resp_event_fixed_param *evt; + WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf; + uint32_t entry_num, *bitmap; + int i; + + param_buf = evt_buf; + if (!param_buf || !resp) { + wmi_err("Invalid param"); + return QDF_STATUS_E_INVAL; + } + + evt = param_buf->fixed_param; + resp->status = evt->status; + wmi_debug("status: %u", resp->status); + + bitmap = param_buf->force_active_vdev_bitmap; + entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap, + (uint32_t)WMI_MLO_VDEV_BITMAP_SZ); + resp->active_sz = entry_num; + for (i = 0; i < entry_num; i++) { + resp->active[i] = bitmap[i]; + wmi_debug("active[%d]: 0x%x", i, resp->active[i]); + } + + bitmap = param_buf->force_inactive_vdev_bitmap; + entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap, + (uint32_t)WMI_MLO_VDEV_BITMAP_SZ); + resp->inactive_sz = entry_num; + for (i = 0; i < entry_num; i++) { + resp->inactive[i] = bitmap[i]; + wmi_debug("inactive[%d]: 0x%x", i, resp->inactive[i]); + } + + return QDF_STATUS_SUCCESS; +} + #ifdef WLAN_MLO_MULTI_CHIP QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle, struct wmi_mlo_setup_params *param) @@ -456,5 +679,11 @@ static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) { + struct wmi_ops *ops = wmi_handle->ops; + wmi_11be_attach_mlo_setup_tlv(wmi_handle); + ops->extract_mlo_link_set_active_resp = + extract_mlo_link_set_active_resp_tlv; + ops->send_mlo_link_set_active_cmd = + send_mlo_link_set_active_cmd_tlv; } diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index acb1b31871..fa39714efa 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -17064,6 +17064,8 @@ event_ids[wmi_roam_scan_chan_list_id] = WMI_MLO_SETUP_COMPLETE_EVENTID; event_ids[wmi_mlo_teardown_complete_event_id] = WMI_MLO_TEARDOWN_COMPLETE_EVENTID; + event_ids[wmi_mlo_link_set_active_resp_eventid] = + WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID; #endif }