diff --git a/target_if/mlo_mgr/src/target_if_mlo_mgr.c b/target_if/mlo_mgr/src/target_if_mlo_mgr.c index d6faac4c09..d0a394c91d 100644 --- a/target_if/mlo_mgr/src/target_if_mlo_mgr.c +++ b/target_if/mlo_mgr/src/target_if_mlo_mgr.c @@ -217,6 +217,53 @@ target_if_send_mlo_link_switch_cnf_cmd(struct wlan_objmgr_psoc *psoc, return wmi_send_mlo_link_switch_req_cnf_cmd(wmi_handle, params); } +static int +target_if_mlo_link_state_switch_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_lmac_if_mlo_rx_ops *mlo_rx_ops; + struct mlo_link_switch_state_info evt_params; + QDF_STATUS status; + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + mlo_rx_ops = target_if_mlo_get_rx_ops(psoc); + if (!mlo_rx_ops || !mlo_rx_ops->mlo_link_state_switch_event_handler) { + target_if_err("callback not registered"); + return -EINVAL; + } + + status = wmi_extract_mlo_link_state_switch_evt(wmi_handle, data, + datalen, + &evt_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Unable to extract link state switch params"); + goto exit; + } + + status = mlo_rx_ops->mlo_link_state_switch_event_handler(psoc, + &evt_params); +exit: + return qdf_status_to_os_return(status); +} + static int target_if_mlo_link_switch_request_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) @@ -282,6 +329,17 @@ target_if_mlo_register_link_switch_event_handler(struct wmi_unified *wmi_handle) wmi_mlo_link_switch_request_eventid, target_if_mlo_link_switch_request_event_handler, WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Register event:%d failed", + wmi_mlo_link_switch_request_eventid); + + status = wmi_unified_register_event_handler( + wmi_handle, wmi_mlo_link_state_switch_eventid, + target_if_mlo_link_state_switch_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Register event:%d failed", + wmi_mlo_link_state_switch_eventid); return status; } diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index 970a3b0087..f076781f23 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -1580,6 +1580,8 @@ struct wlan_lmac_if_mlo_tx_ops { * @mlo_link_disable_request_handler: function ptr for mlo link disable request * @mlo_link_switch_request_handler: Handler function pointer to deliver link * switch request params from FW to host. + * @mlo_link_state_switch_event_handler: Function pointer to handle link state + * switch event */ struct wlan_lmac_if_mlo_rx_ops { QDF_STATUS @@ -1601,6 +1603,9 @@ struct wlan_lmac_if_mlo_rx_ops { QDF_STATUS (*mlo_link_switch_request_handler)(struct wlan_objmgr_psoc *psoc, void *evt_params); + QDF_STATUS + (*mlo_link_state_switch_event_handler)(struct wlan_objmgr_psoc *psoc, + struct mlo_link_switch_state_info *info); #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ }; #endif diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c index 838b2d8853..e3057cae03 100644 --- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c +++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c @@ -982,6 +982,8 @@ wlan_lmac_if_mlo_rx_link_switch_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) { rx_ops->mlo_rx_ops.mlo_link_switch_request_handler = mlo_mgr_link_switch_request_params; + rx_ops->mlo_rx_ops.mlo_link_state_switch_event_handler = + mlo_mgr_link_state_switch_info_handler; } #else static inline void diff --git a/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h b/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h index 4ac7105040..11d32fe788 100644 --- a/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h +++ b/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h @@ -523,6 +523,18 @@ mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev, */ QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc, void *evt_params); +/** + * mlo_mgr_link_state_switch_info_handler() - Handle Link State change related + * information and generate corresponding connectivity logging event + * @psoc: Pointer to PSOC object + * @info: Source info to be sent for the logging event + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc *psoc, + struct mlo_link_switch_state_info *info); + /** * mlo_mgr_link_switch_complete() - Link switch complete notification to FW * @vdev: VDV object manager diff --git a/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h b/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h index bd580c59aa..8af5e56b31 100644 --- a/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h +++ b/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h @@ -1496,6 +1496,36 @@ struct mlo_link_disable_request_evt_params { uint32_t link_id_bitmap; }; +#define MAX_LINK_SWITCH_TLV 5 +/** + * struct mlo_link_switch_params - Structure to hold link State switch + * related parameters + * @mld_addr: MLD address + * @active_link_bitmap: Bitmap of ieee link id for active links + * @prev_link_bitmap: Bitmap of ieee link id for previous active links + * @fw_timestamp: Firmware timestamp in milliseconds + * @reason_code: Reason code for the switch + */ +struct mlo_link_switch_params { + struct qdf_mac_addr mld_addr; + uint32_t active_link_bitmap; + uint32_t prev_link_bitmap; + uint32_t fw_timestamp; + uint32_t reason_code; +}; + +/** + * struct mlo_link_switch_state_info - Structure to hold the link switch + * related parameters corresponding to all the TLV received in link state switch + * event. + * @num_params: Number of the link switch parameters + * @link_switch_param: Link switch parameters + */ +struct mlo_link_switch_state_info { + uint8_t num_params; + struct mlo_link_switch_params link_switch_param[MAX_LINK_SWITCH_TLV]; +}; + #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE /** * struct peer_ptqm_migrate_entry - peer ptqm migrate entry diff --git a/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c b/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c index 8d283c9ea1..9e51413845 100644 --- a/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c +++ b/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c @@ -1083,6 +1083,19 @@ QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc, return status; } +QDF_STATUS +mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc *psoc, + struct mlo_link_switch_state_info *info) +{ + uint8_t i; + + for (i = 0; i < info->num_params; i++) + wlan_connectivity_mld_link_status_event(psoc, + &info->link_switch_param[i]); + + return QDF_STATUS_SUCCESS; +} + QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev) { enum mlo_link_switch_req_state state; diff --git a/wmi/inc/wmi_unified_11be_api.h b/wmi/inc/wmi_unified_11be_api.h index 825e0983f0..5a9f5fb088 100644 --- a/wmi/inc/wmi_unified_11be_api.h +++ b/wmi/inc/wmi_unified_11be_api.h @@ -267,6 +267,21 @@ QDF_STATUS wmi_extract_mlo_link_disable_request_evt( struct wmi_unified *wmi, void *buf, struct mlo_link_disable_request_evt_params *params); + +/** + * wmi_extract_mlo_link_state_switch_evt() - Extract the MLO link switch state + * event parameters + * @wmi: wmi handle + * @buf: pointer to event buffer + * @len: event data length + * @info: Info on link switch state change event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_mlo_link_state_switch_evt(struct wmi_unified *wmi, void *buf, + uint8_t len, + struct mlo_link_switch_state_info *info); #endif /* WLAN_FEATURE_11BE */ #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 919ed290a8..7cd13aa418 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -5303,6 +5303,7 @@ typedef enum { wmi_mlo_link_disable_request_eventid, #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE wmi_mlo_link_switch_request_eventid, + wmi_mlo_link_state_switch_eventid, #endif #endif wmi_pdev_fips_extend_event_id, diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 727010f20c..98608bc4af 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -3208,6 +3208,11 @@ QDF_STATUS (*extract_mlo_link_disable_request_evt_param)( struct mlo_link_disable_request_evt_params *params); #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +QDF_STATUS (*extract_mlo_link_state_switch_evt)( + struct wmi_unified *wmi_handle, + void *buf, uint8_t len, + struct mlo_link_switch_state_info *params); + QDF_STATUS (*extract_mlo_link_switch_request_event)(struct wmi_unified *wmi_handle, void *buf, diff --git a/wmi/src/wmi_unified_11be_api.c b/wmi/src/wmi_unified_11be_api.c index 3e009e412e..1ec29ccf84 100644 --- a/wmi/src/wmi_unified_11be_api.c +++ b/wmi/src/wmi_unified_11be_api.c @@ -104,6 +104,18 @@ wmi_extract_mlo_link_switch_request_evt(struct wmi_unified *wmi, return QDF_STATUS_E_FAILURE; } + +QDF_STATUS +wmi_extract_mlo_link_state_switch_evt(struct wmi_unified *wmi, + void *buf, uint8_t len, + struct mlo_link_switch_state_info *info) +{ + if (wmi->ops->extract_mlo_link_state_switch_evt) + return wmi->ops->extract_mlo_link_state_switch_evt( + wmi, buf, len, info); + + return QDF_STATUS_SUCCESS; +} #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ QDF_STATUS wmi_send_mlo_link_state_request_cmd( diff --git a/wmi/src/wmi_unified_11be_tlv.c b/wmi/src/wmi_unified_11be_tlv.c index 43c2bf32dc..503746517a 100644 --- a/wmi/src/wmi_unified_11be_tlv.c +++ b/wmi/src/wmi_unified_11be_tlv.c @@ -1277,6 +1277,72 @@ extract_mlo_link_disable_request_evt_param_tlv( return QDF_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static QDF_STATUS +extract_mlo_link_state_switch_event_tlv(struct wmi_unified *wmi_handle, + void *evt_buf, uint8_t len, + struct mlo_link_switch_state_info *info) +{ + WMI_MLO_LINK_STATE_SWITCH_EVENTID_param_tlvs *param_buf = evt_buf; + wmi_mlo_link_state_switch_req_evt_fixed_param *fixed_param; + wmi_mlo_link_state_switch_trigger_reason *lnk_switch_param; + uint8_t i, num_tlv, rem_len; + + if (!param_buf) { + wmi_err("param buf is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + wmi_err("fixed param is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + num_tlv = fixed_param->link_state_switch_count; + if (num_tlv > MAX_LINK_SWITCH_TLV) + num_tlv = MAX_LINK_SWITCH_TLV; + + rem_len = len - sizeof(*fixed_param); + if (rem_len < + num_tlv * sizeof(wmi_mlo_link_state_switch_trigger_reason)) { + wmi_err_rl("Invalid link state switch TLVs rem_len:%d num_tlv:%d", + rem_len, num_tlv); + return QDF_STATUS_E_INVAL; + } + + lnk_switch_param = param_buf->switch_trigger_reason; + if (!lnk_switch_param) { + wmi_err_rl("No TLV is present"); + return QDF_STATUS_E_INVAL; + } + + info->num_params = num_tlv; + for (i = 0; i < num_tlv; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&lnk_switch_param->ml_bssid, + info->link_switch_param[i].mld_addr.bytes); + + info->link_switch_param[i].active_link_bitmap = + lnk_switch_param->cur_active_ieee_bitmap; + info->link_switch_param[i].prev_link_bitmap = + lnk_switch_param->prev_active_ieee_bitmap; + info->link_switch_param[i].fw_timestamp = + lnk_switch_param->host_ref_fw_timestamp_ms; + info->link_switch_param[i].reason_code = + lnk_switch_param->reason_code; + wmi_debug("i:%d active_link_bmap:0x%x prev_bmap:0x%x reason_code:%d MLD addr: "QDF_MAC_ADDR_FMT, + i, info->link_switch_param[i].active_link_bitmap, + info->link_switch_param[i].prev_link_bitmap, + info->link_switch_param[i].reason_code, + QDF_MAC_ADDR_REF(info->link_switch_param[i].mld_addr.bytes)); + + lnk_switch_param++; + } + + return QDF_STATUS_SUCCESS; +} +#endif + #ifdef WLAN_FEATURE_11BE size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req) { @@ -2592,5 +2658,7 @@ void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) extract_mlo_link_switch_request_event_tlv; ops->send_mlo_link_switch_req_cnf_cmd = send_link_switch_request_cnf_cmd_tlv; + ops->extract_mlo_link_state_switch_evt = + extract_mlo_link_state_switch_event_tlv; #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ } diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index fb71ffaa10..07c174889b 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -21728,6 +21728,8 @@ static void populate_tlv_events_id_mlo(WMI_EVT_ID *event_ids) #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE event_ids[wmi_mlo_link_switch_request_eventid] = WMI_MLO_LINK_SWITCH_REQUEST_EVENTID; + event_ids[wmi_mlo_link_state_switch_eventid] = + WMI_MLO_LINK_STATE_SWITCH_EVENTID; #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ } #else /* WLAN_FEATURE_11BE_MLO */