qcacmn: Add support for T2LM timer handling

Adds api's to handle t2lm timer functionality.
Api's added are timer initialize, start, stop, expiry handler.

Change-Id: If52453135921067d04f8349ece64c33cd524af00
CRs-Fixed: 3342822
This commit is contained in:
Amruta Kulkarni
2022-12-06 21:46:34 +05:30
committed by Madan Koyyalamudi
parent 93e8977721
commit 8759cf1c1e
6 changed files with 628 additions and 9 deletions

View File

@@ -23,6 +23,8 @@
#include <wmi_unified_11be_api.h> #include <wmi_unified_11be_api.h>
#include <init_deinit_lmac.h> #include <init_deinit_lmac.h>
#include "target_if_mlo_mgr.h" #include "target_if_mlo_mgr.h"
#include <wlan_objmgr_peer_obj.h>
#include <wlan_mlo_t2lm.h>
/** /**
* target_if_mlo_link_set_active_resp_handler() - function to handle mlo link * target_if_mlo_link_set_active_resp_handler() - function to handle mlo link
@@ -238,6 +240,92 @@ target_if_mlo_unregister_vdev_tid_to_link_map_event(
wmi_handle, wmi_mlo_ap_vdev_tid_to_link_map_eventid); wmi_handle, wmi_mlo_ap_vdev_tid_to_link_map_eventid);
} }
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
/**
* target_if_fill_provisioned_links() - API to fill the provisioned links
* @params: Pointer to T2LM params structure
* @t2lm: Pointer to T2LM info structure
*
* Return: none
*/
static inline void target_if_fill_provisioned_links(
struct wmi_host_tid_to_link_map_params *params,
struct wlan_t2lm_info *t2lm)
{
qdf_mem_copy(&params->t2lm_info[params->num_dir].t2lm_provisioned_links,
&t2lm->ieee_link_map_tid,
sizeof(uint16_t) * T2LM_MAX_NUM_TIDS);
}
#else
static inline void target_if_fill_provisioned_links(
struct wmi_host_tid_to_link_map_params *params,
struct wlan_t2lm_info *t2lm)
{
qdf_mem_copy(&params->t2lm_info[params->num_dir].t2lm_provisioned_links,
&t2lm->hw_link_map_tid,
sizeof(uint16_t) * T2LM_MAX_NUM_TIDS);
}
#endif
static QDF_STATUS
target_if_mlo_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev,
struct wlan_t2lm_info *t2lm)
{
struct wmi_unified *wmi_handle = NULL;
struct wmi_host_tid_to_link_map_params params = {0};
struct wlan_objmgr_pdev *pdev = NULL;
int tid = 0;
QDF_STATUS status;
pdev = wlan_vdev_get_pdev(vdev);
if (!pdev) {
t2lm_err("null pdev");
return QDF_STATUS_E_NULL_VALUE;
}
wmi_handle = lmac_get_pdev_wmi_handle(pdev);
if (!wmi_handle) {
t2lm_err("null wmi handle");
return QDF_STATUS_E_NULL_VALUE;
}
params.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
qdf_mem_copy(params.peer_macaddr, vdev->vdev_objmgr.bss_peer->macaddr,
QDF_MAC_ADDR_SIZE);
t2lm_debug("Fill T2LM WMI info for peer: " QDF_MAC_ADDR_FMT " pdev_id:%d",
QDF_MAC_ADDR_REF(params.peer_macaddr), params.pdev_id);
params.t2lm_info[params.num_dir].direction = t2lm->direction;
params.t2lm_info[params.num_dir].default_link_mapping =
t2lm->default_link_mapping;
if (!params.t2lm_info[params.num_dir].default_link_mapping)
target_if_fill_provisioned_links(&params, t2lm);
t2lm_debug("num_dir:%d direction:%d default_link_mapping:%d",
params.num_dir, params.t2lm_info[params.num_dir].direction,
params.t2lm_info[params.num_dir].default_link_mapping);
for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) {
t2lm_debug("tid:%d hw_link_map:%x ieee_lin_map:%x", tid,
params.t2lm_info[params.num_dir].t2lm_provisioned_links[tid],
t2lm->ieee_link_map_tid[tid]);
}
params.num_dir++;
status = wmi_send_mlo_peer_tid_to_link_map_cmd(wmi_handle, &params);
if (QDF_IS_STATUS_ERROR(status)) {
t2lm_err("Failed to send T2LM WMI command for pdev_id:%d peer_mac: " QDF_MAC_ADDR_FMT,
params.pdev_id,
QDF_MAC_ADDR_REF(params.peer_macaddr));
return status;
}
return status;
}
/** /**
* target_if_mlo_register_tx_ops() - lmac handler to register mlo tx ops * target_if_mlo_register_tx_ops() - lmac handler to register mlo tx ops
* callback functions * callback functions
@@ -266,6 +354,8 @@ target_if_mlo_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
mlo_tx_ops->unregister_events = mlo_tx_ops->unregister_events =
target_if_mlo_unregister_event_handler; target_if_mlo_unregister_event_handler;
mlo_tx_ops->link_set_active = target_if_mlo_link_set_active; mlo_tx_ops->link_set_active = target_if_mlo_link_set_active;
mlo_tx_ops->send_tid_to_link_mapping =
target_if_mlo_send_tid_to_link_mapping;
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;
} }

View File

@@ -1387,6 +1387,7 @@ struct wlan_lmac_if_son_rx_ops {
* @register_events: function to register event handlers with FW * @register_events: function to register event handlers with FW
* @unregister_events: function to de-register event handlers with FW * @unregister_events: function to de-register event handlers with FW
* @link_set_active: function to send mlo link set active command to FW * @link_set_active: function to send mlo link set active command to FW
* @send_tid_to_link_mapping: function to send T2LM command to FW
*/ */
struct wlan_lmac_if_mlo_tx_ops { struct wlan_lmac_if_mlo_tx_ops {
QDF_STATUS (*register_events)(struct wlan_objmgr_psoc *psoc); QDF_STATUS (*register_events)(struct wlan_objmgr_psoc *psoc);
@@ -1396,6 +1397,8 @@ struct wlan_lmac_if_mlo_tx_ops {
#ifdef WLAN_MLO_GLOBAL_SHMEM_SUPPORT #ifdef WLAN_MLO_GLOBAL_SHMEM_SUPPORT
struct wlan_lmac_if_global_shmem_local_ops shmem_local_ops; struct wlan_lmac_if_global_shmem_local_ops shmem_local_ops;
#endif #endif
QDF_STATUS (*send_tid_to_link_mapping)(struct wlan_objmgr_vdev *vdev,
struct wlan_t2lm_info *t2lm);
}; };
/** /**

View File

@@ -300,6 +300,7 @@ enum wlan_t2lm_direction {
WLAN_T2LM_INVALID_DIRECTION, WLAN_T2LM_INVALID_DIRECTION,
}; };
#define T2LM_EXPECTED_DURATION_MAX_VALUE 0xFFFFFF
/** /**
* struct wlan_t2lm_info - TID-to-Link mapping information for the frames * struct wlan_t2lm_info - TID-to-Link mapping information for the frames
* transmitted on the uplink, downlink and bidirectional. * transmitted on the uplink, downlink and bidirectional.
@@ -352,11 +353,21 @@ struct wlan_mlo_t2lm_ie {
* struct wlan_t2lm_timer - T2LM timer information * struct wlan_t2lm_timer - T2LM timer information
* *
* @t2lm_timer: T2LM timer * @t2lm_timer: T2LM timer
* @timer_interval: T2LM timer interval value * @timer_interval: T2LM Timer value
* @timer_started: T2LM timer started or not
* @t2lm_ie_index: T2LM IE index value
* @t2lm_dev_lock: lock to access struct
*/ */
struct wlan_t2lm_timer { struct wlan_t2lm_timer {
qdf_timer_t t2lm_timer; qdf_timer_t t2lm_timer;
uint32_t timer_interval; uint32_t timer_interval;
bool timer_started;
uint8_t t2lm_ie_index;
#ifdef WLAN_MLO_USE_SPINLOCK
qdf_spinlock_t t2lm_dev_lock;
#else
qdf_mutex_t t2lm_dev_lock;
#endif
}; };
/** /**
@@ -366,6 +377,7 @@ struct wlan_t2lm_timer {
* @t2lm_ie: T2LM IE information * @t2lm_ie: T2LM IE information
* @t2lm_timer: T2LM timer information * @t2lm_timer: T2LM timer information
* @t2lm_dev_lock: t2lm dev context lock * @t2lm_dev_lock: t2lm dev context lock
* @tsf: time sync func value received via beacon
*/ */
struct wlan_t2lm_context { struct wlan_t2lm_context {
uint8_t num_of_t2lm_ie; uint8_t num_of_t2lm_ie;
@@ -376,6 +388,7 @@ struct wlan_t2lm_context {
#else #else
qdf_mutex_t t2lm_dev_lock; qdf_mutex_t t2lm_dev_lock;
#endif #endif
uint64_t tsf;
}; };
/* /*

View File

@@ -45,6 +45,86 @@
#define WLAN_T2LM_MAX_NUM_LINKS 16 #define WLAN_T2LM_MAX_NUM_LINKS 16
#ifdef WLAN_MLO_USE_SPINLOCK
/**
* t2lm_dev_lock_create - Create T2LM device mutex/spinlock
* @t2lm_ctx: T2LM context
*
* Creates mutex/spinlock
*
* Return: void
*/
static inline void
t2lm_dev_lock_create(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_spinlock_create(&t2lm_ctx->t2lm_dev_lock);
}
/**
* t2lm_dev_lock_destroy - Destroy T2LM mutex/spinlock
* @t2lm_ctx: T2LM context
*
* Destroy mutex/spinlock
*
* Return: void
*/
static inline void
t2lm_dev_lock_destroy(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_spinlock_destroy(&t2lm_ctx->t2lm_dev_lock);
}
/**
* t2lm_dev_lock_acquire - acquire T2LM mutex/spinlock
* @t2lm_ctx: T2LM context
*
* acquire mutex/spinlock
*
* return: void
*/
static inline
void t2lm_dev_lock_acquire(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_spin_lock_bh(&t2lm_ctx->t2lm_dev_lock);
}
/**
* t2lm_dev_lock_release - release T2LM dev mutex/spinlock
* @t2lm_ctx: T2LM context
*
* release mutex/spinlock
*
* return: void
*/
static inline
void t2lm_dev_lock_release(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_spin_unlock_bh(&t2lm_ctx->t2lm_dev_lock);
}
#else /* WLAN_MLO_USE_SPINLOCK */
static inline
void t2lm_dev_lock_create(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_mutex_create(&t2lm_ctx->t2lm_dev_lock);
}
static inline
void t2lm_dev_lock_destroy(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_mutex_destroy(&t2lm_ctx->t2lm_dev_lock);
}
static inline void t2lm_dev_lock_acquire(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_mutex_acquire(&t2lm_ctx->t2lm_dev_lock);
}
static inline void t2lm_dev_lock_release(struct wlan_t2lm_context *t2lm_ctx)
{
qdf_mutex_release(&t2lm_ctx->t2lm_dev_lock);
}
#endif
/** /**
* wlan_mlo_parse_t2lm_ie() - API to parse the T2LM IE * wlan_mlo_parse_t2lm_ie() - API to parse the T2LM IE
* @t2lm: Pointer to T2LM structure * @t2lm: Pointer to T2LM structure
@@ -122,6 +202,69 @@ QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie(
* Return: Updated frame pointer * Return: Updated frame pointer
*/ */
uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm); uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm);
/**
* wlan_mlo_t2lm_timer_init() - API to add TID-to-link mapping IE
* @vdev: Pointer to vdev
*
* Return: qdf status
*/
QDF_STATUS
wlan_mlo_t2lm_timer_init(struct wlan_objmgr_vdev *vdev);
/**
* wlan_mlo_t2lm_timer_start() - API to start T2LM timer
* @vdev: Pointer to vdev
* @interval: T2LM timer interval
* @t2lm_ie_index: T2LM IE index
*
* Return: qdf status
*/
QDF_STATUS
wlan_mlo_t2lm_timer_start(struct wlan_objmgr_vdev *vdev,
uint32_t interval, uint8_t t2lm_ie_index);
/**
* wlan_mlo_t2lm_timer_stop() - API to stop TID-to-link mapping timer
* @vdev: Pointer to vdev
*
* Return: qdf status
*/
QDF_STATUS
wlan_mlo_t2lm_timer_stop(struct wlan_objmgr_vdev *vdev);
/**
* wlan_mlo_t2lm_timer_expiry_handler() - API to handle t2lm timer expiry
* @vdev: Pointer to vdev structure
*
* Return: none
*/
void
wlan_mlo_t2lm_timer_expiry_handler(void *vdev);
/**
* wlan_handle_t2lm_timer() - API to handle TID-to-link mapping timer
* @vdev: Pointer to vdev
* @ie_idx: ie index value
*
* Return: qdf status
*/
QDF_STATUS
wlan_handle_t2lm_timer(struct wlan_objmgr_vdev *vdev, uint8_t ie_idx);
/**
* wlan_process_bcn_prbrsp_t2lm_ie() - API to process the received T2LM IE from
* beacon/probe response.
* @vdev: Pointer to vdev
* @rx_t2lm_ie: Received T2LM IE
* @tsf: Local TSF value
*
* Return QDF_STATUS
*/
QDF_STATUS wlan_process_bcn_prbrsp_t2lm_ie(struct wlan_objmgr_vdev *vdev,
struct wlan_t2lm_context *rx_t2lm_ie,
uint64_t tsf);
#else #else
static inline QDF_STATUS wlan_mlo_parse_t2lm_ie( static inline QDF_STATUS wlan_mlo_parse_t2lm_ie(
struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie) struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie)
@@ -165,5 +308,42 @@ uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm)
{ {
return frm; return frm;
} }
static inline QDF_STATUS
wlan_mlo_t2lm_timer_init(struct wlan_objmgr_vdev *vdev)
{
return QDF_STATUS_E_NOSUPPORT;
}
static inline QDF_STATUS
wlan_mlo_t2lm_timer_start(struct wlan_objmgr_vdev *vdev,
uint32_t interval, uint8_t t2lm_ie_index)
{
return QDF_STATUS_E_NOSUPPORT;
}
static inline QDF_STATUS
wlan_mlo_t2lm_timer_stop(struct wlan_objmgr_vdev *vdev)
{
return QDF_STATUS_E_NOSUPPORT;
}
static inline void
wlan_mlo_t2lm_timer_expiry_handler(void *vdev)
{}
static inline QDF_STATUS
wlan_handle_t2lm_timer(struct wlan_objmgr_vdev *vdev, uint8_t ie_idx)
{
return QDF_STATUS_E_NOSUPPORT;
}
static inline QDF_STATUS
wlan_process_bcn_prbrsp_t2lm_ie(struct wlan_objmgr_vdev *vdev,
struct wlan_t2lm_context *rx_t2lm_ie,
uint64_t tsf)
{
return QDF_STATUS_SUCCESS;
}
#endif /* WLAN_FEATURE_11BE */ #endif /* WLAN_FEATURE_11BE */
#endif /* _WLAN_MLO_T2LM_H_ */ #endif /* _WLAN_MLO_T2LM_H_ */

View File

@@ -29,6 +29,7 @@
#include <wlan_cm_public_struct.h> #include <wlan_cm_public_struct.h>
#include "wlan_mlo_mgr_msgq.h" #include "wlan_mlo_mgr_msgq.h"
#include <target_if_mlo_mgr.h> #include <target_if_mlo_mgr.h>
#include <wlan_mlo_t2lm.h>
static void mlo_global_ctx_deinit(void) static void mlo_global_ctx_deinit(void)
{ {
@@ -436,10 +437,12 @@ QDF_STATUS wlan_mlo_check_valid_config(struct wlan_mlo_dev_context *ml_dev,
* mlo_t2lm_ctx_init() - API to initialize the t2lm context with the default * mlo_t2lm_ctx_init() - API to initialize the t2lm context with the default
* values. * values.
* @ml_dev: Pointer to ML Dev context * @ml_dev: Pointer to ML Dev context
* @vdev: Pointer to vdev structure
* *
* Return: None * Return: None
*/ */
static inline void mlo_t2lm_ctx_init(struct wlan_mlo_dev_context *ml_dev) static inline void mlo_t2lm_ctx_init(struct wlan_mlo_dev_context *ml_dev,
struct wlan_objmgr_vdev *vdev)
{ {
struct wlan_t2lm_info *t2lm; struct wlan_t2lm_info *t2lm;
@@ -450,6 +453,8 @@ static inline void mlo_t2lm_ctx_init(struct wlan_mlo_dev_context *ml_dev)
ml_dev->t2lm_ctx.num_of_t2lm_ie = 1; ml_dev->t2lm_ctx.num_of_t2lm_ie = 1;
t2lm->direction = WLAN_T2LM_BIDI_DIRECTION; t2lm->direction = WLAN_T2LM_BIDI_DIRECTION;
t2lm->default_link_mapping = 1; t2lm->default_link_mapping = 1;
wlan_mlo_t2lm_timer_init(vdev);
} }
static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev) static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
@@ -527,7 +532,7 @@ static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node); qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node);
ml_link_lock_release(g_mlo_ctx); ml_link_lock_release(g_mlo_ctx);
mlo_t2lm_ctx_init(ml_dev); mlo_t2lm_ctx_init(ml_dev, vdev);
return status; return status;
} }

View File

@@ -25,6 +25,7 @@
#include <wlan_mlo_t2lm.h> #include <wlan_mlo_t2lm.h>
#include <wlan_mlo_mgr_cmn.h> #include <wlan_mlo_mgr_cmn.h>
#include <qdf_util.h> #include <qdf_util.h>
#include <wlan_cm_api.h>
/** /**
* wlan_mlo_parse_t2lm_info() - Parse T2LM IE fields * wlan_mlo_parse_t2lm_info() - Parse T2LM IE fields
@@ -621,12 +622,31 @@ static void wlan_mlo_t2lm_handle_expected_duration_expiry(
if (!t2lm_ctx->t2lm_ie[i].t2lm.expected_duration_present) if (!t2lm_ctx->t2lm_ie[i].t2lm.expected_duration_present)
continue; continue;
qdf_mem_zero(&t2lm_ctx->t2lm_ie[i], /* If two T2LM IEs are present, and expected duration of first
sizeof(struct wlan_mlo_t2lm_ie)); * T2LM IE is expired, copy the T2LM IE from index 1 to index 0.
t2lm_ctx->t2lm_ie[i].t2lm.direction = WLAN_T2LM_BIDI_DIRECTION; * Mark mapping switch time present as false and clear the
t2lm_ctx->t2lm_ie[i].t2lm.default_link_mapping = 1; * mapping switch time value.
t2lm_debug("vdev_id:%d Expected duration is expired", * If one T2LM IE is present, and the expected duration is
vdev_id); * expired, configure the T2LM IE with the default values.
*/
if (!i && t2lm_ctx->num_of_t2lm_ie == WLAN_MAX_T2LM_IE) {
qdf_mem_copy(&t2lm_ctx->t2lm_ie[0],
&t2lm_ctx->t2lm_ie[1],
sizeof(struct wlan_mlo_t2lm_ie));
t2lm_ctx->t2lm_ie[0].t2lm.mapping_switch_time_present =
false;
t2lm_ctx->t2lm_ie[0].t2lm.mapping_switch_time = 0;
t2lm_debug("vdev_id:%d mark the advertised T2LM as established",
vdev_id);
} else {
qdf_mem_zero(&t2lm_ctx->t2lm_ie[i],
sizeof(struct wlan_mlo_t2lm_ie));
t2lm_ctx->t2lm_ie[i].t2lm.direction =
WLAN_T2LM_BIDI_DIRECTION;
t2lm_ctx->t2lm_ie[i].t2lm.default_link_mapping = 1;
t2lm_debug("vdev_id:%d Expected duration is expired",
vdev_id);
}
} }
} }
@@ -678,3 +698,311 @@ QDF_STATUS wlan_mlo_vdev_tid_to_link_map_event(
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;
} }
static
QDF_STATUS wlan_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev,
struct wlan_t2lm_info *t2lm)
{
struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
struct wlan_objmgr_vdev *co_mld_vdev;
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
uint16_t vdev_count = 0;
int i = 0;
QDF_STATUS status = QDF_STATUS_E_FAILURE;
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
t2lm_err("null psoc");
return QDF_STATUS_E_NULL_VALUE;
}
mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
if (!mlo_tx_ops) {
t2lm_err("tx_ops is null!");
return QDF_STATUS_E_NULL_VALUE;
}
if (!mlo_tx_ops->send_tid_to_link_mapping) {
t2lm_err("send_tid_to_link_mapping is null");
return QDF_STATUS_E_NULL_VALUE;
}
mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
if (!vdev_count) {
t2lm_err("Number of VDEVs under MLD is reported as 0");
return QDF_STATUS_E_NULL_VALUE;
}
for (i = 0; i < vdev_count; i++) {
co_mld_vdev = wlan_vdev_list[i];
if (!co_mld_vdev) {
t2lm_err("co_mld_vdev is null");
mlo_release_vdev_ref(co_mld_vdev);
continue;
}
status = mlo_tx_ops->send_tid_to_link_mapping(co_mld_vdev,
t2lm);
if (QDF_IS_STATUS_ERROR(status))
t2lm_err("Failed to send T2LM command to FW");
mlo_release_vdev_ref(co_mld_vdev);
}
return status;
}
void wlan_mlo_t2lm_timer_expiry_handler(void *vdev)
{
struct wlan_objmgr_vdev *vdev_ctx = (struct wlan_objmgr_vdev *)vdev;
struct wlan_t2lm_timer *t2lm_timer;
struct wlan_t2lm_context *t2lm_ctx;
uint8_t t2lm_ie_idx;
if (!vdev_ctx || !vdev_ctx->mlo_dev_ctx)
return;
t2lm_ctx = &vdev_ctx->mlo_dev_ctx->t2lm_ctx;
t2lm_timer = &vdev_ctx->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
t2lm_ie_idx = t2lm_timer->t2lm_ie_index;
if (t2lm_ie_idx >= WLAN_MAX_T2LM_IE)
return;
wlan_mlo_t2lm_timer_stop(vdev_ctx);
if (t2lm_ctx->t2lm_ie[t2lm_ie_idx].t2lm.mapping_switch_time_present) {
wlan_send_tid_to_link_mapping(
vdev, &t2lm_ctx->t2lm_ie[t2lm_ie_idx].t2lm);
wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev);
wlan_handle_t2lm_timer(vdev_ctx, t2lm_timer->t2lm_ie_index);
} else if (!t2lm_ie_idx) {
wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev);
wlan_handle_t2lm_timer(vdev_ctx, t2lm_timer->t2lm_ie_index);
}
}
QDF_STATUS
wlan_mlo_t2lm_timer_init(struct wlan_objmgr_vdev *vdev)
{
struct wlan_t2lm_timer *t2lm_timer = NULL;
if (!vdev || !vdev->mlo_dev_ctx)
return QDF_STATUS_E_FAILURE;
t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
if (!t2lm_timer) {
t2lm_err("t2lm timer ctx is null");
return QDF_STATUS_E_NULL_VALUE;
}
t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
qdf_timer_init(NULL, &t2lm_timer->t2lm_timer,
wlan_mlo_t2lm_timer_expiry_handler,
vdev, QDF_TIMER_TYPE_WAKE_APPS);
t2lm_timer->timer_started = false;
t2lm_timer->timer_interval = 0;
t2lm_timer->t2lm_ie_index = 0;
t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS
wlan_mlo_t2lm_timer_start(struct wlan_objmgr_vdev *vdev,
uint32_t interval, uint8_t t2lm_ie_index)
{
struct wlan_t2lm_timer *t2lm_timer;
struct wlan_t2lm_context *t2lm_ctx;
struct vdev_mlme_obj *vdev_mlme;
if (!vdev || !vdev->mlo_dev_ctx)
return QDF_STATUS_E_NULL_VALUE;
if (interval == 0) {
t2lm_debug("Timer interval is 0");
return QDF_STATUS_E_NULL_VALUE;
}
vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
if (!vdev_mlme)
return QDF_STATUS_E_FAILURE;
t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
if (!t2lm_timer) {
t2lm_err("t2lm timer ctx is null");
return QDF_STATUS_E_NULL_VALUE;
}
t2lm_debug("t2lm timer started with interval %d", interval);
t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
if (t2lm_ctx->t2lm_ie[t2lm_ie_index].t2lm.mapping_switch_time_present)
t2lm_timer->timer_interval =
t2lm_ctx->t2lm_ie[t2lm_ie_index].t2lm.mapping_switch_time;
else
t2lm_timer->timer_interval = interval *
vdev_mlme->proto.generic.beacon_interval * 1000;
t2lm_timer->t2lm_ie_index = t2lm_ie_index;
t2lm_timer->timer_started = true;
qdf_timer_start(&t2lm_timer->t2lm_timer, t2lm_timer->timer_interval);
t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS
wlan_mlo_t2lm_timer_stop(struct wlan_objmgr_vdev *vdev)
{
struct wlan_t2lm_timer *t2lm_timer;
if (!vdev || !vdev->mlo_dev_ctx)
return QDF_STATUS_E_NULL_VALUE;
t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
if (!t2lm_timer) {
t2lm_err("t2lm timer ctx is null");
return QDF_STATUS_E_NULL_VALUE;
}
t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
if (t2lm_timer->timer_started) {
qdf_timer_stop(&t2lm_timer->t2lm_timer);
t2lm_timer->timer_started = false;
t2lm_timer->timer_interval = 0;
}
t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_handle_t2lm_timer(struct wlan_objmgr_vdev *vdev, uint8_t ie_idx)
{
struct wlan_t2lm_context *t2lm_ctx;
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!vdev || !vdev->mlo_dev_ctx)
return QDF_STATUS_E_NULL_VALUE;
t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
if (!t2lm_ctx->num_of_t2lm_ie) {
t2lm_err("No T2LM IE present");
return QDF_STATUS_SUCCESS;
}
if (ie_idx >= WLAN_MAX_T2LM_IE) {
t2lm_err("Invalid T2LM IE index");
return QDF_STATUS_E_FAILURE;
}
if (!t2lm_ctx->t2lm_ie[ie_idx].t2lm.mapping_switch_time_present &&
!t2lm_ctx->t2lm_ie[ie_idx].t2lm.expected_duration_present) {
/* non-default to default mapping case */
wlan_send_tid_to_link_mapping(vdev,
&t2lm_ctx->t2lm_ie[ie_idx].t2lm);
} else if (t2lm_ctx->t2lm_ie[ie_idx].t2lm.mapping_switch_time_present) {
/* Default to non-default mapping case */
status = wlan_mlo_t2lm_timer_start(
vdev,
t2lm_ctx->t2lm_ie[ie_idx].t2lm.mapping_switch_time,
ie_idx);
} else if (t2lm_ctx->t2lm_ie[ie_idx].t2lm.expected_duration_present) {
wlan_send_tid_to_link_mapping(
vdev, &t2lm_ctx->t2lm_ie[ie_idx].t2lm);
if (t2lm_ctx->t2lm_ie[ie_idx].t2lm.expected_duration !=
T2LM_EXPECTED_DURATION_MAX_VALUE)
status = wlan_mlo_t2lm_timer_start(
vdev,
t2lm_ctx->t2lm_ie[ie_idx].t2lm.expected_duration,
ie_idx);
}
return status;
}
/**
* wlan_update_mapping_switch_time_expected_dur() - API to update the mapping
* switch time and expected duration.
* @vdev:Pointer to vdev
* @rx_t2lm: Pointer to received T2LM IE
* @tsf: TSF value of beacon/probe response
*
* Return: None
*/
static void wlan_update_mapping_switch_time_expected_dur(
struct wlan_objmgr_vdev *vdev, struct wlan_t2lm_info *rx_t2lm,
uint64_t tsf)
{
struct wlan_t2lm_context *t2lm_ctx;
uint16_t tsf_bit25_16, ms_time;
bool match_found = false;
int j;
tsf_bit25_16 = (tsf & 0x3FF0000) >> 16;
t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
for (j = 0; j < t2lm_ctx->num_of_t2lm_ie; j++) {
/* Match not found */
if (qdf_mem_cmp(rx_t2lm->ieee_link_map_tid,
t2lm_ctx->t2lm_ie[j].t2lm.ieee_link_map_tid,
sizeof(uint16_t) * T2LM_MAX_NUM_TIDS))
continue;
if (t2lm_ctx->t2lm_ie[j].t2lm.mapping_switch_time_present) {
ms_time = rx_t2lm->mapping_switch_time;
if (ms_time > tsf_bit25_16) {
t2lm_ctx->t2lm_ie[j].t2lm.mapping_switch_time =
((ms_time - tsf_bit25_16) * 1024) / 1000;
} else {
t2lm_ctx->t2lm_ie[j].t2lm.mapping_switch_time =
((0xFFFF - (tsf_bit25_16 - ms_time)) * 1024) / 1000;
}
}
if (t2lm_ctx->t2lm_ie[j].t2lm.expected_duration_present) {
t2lm_ctx->t2lm_ie[j].t2lm.expected_duration =
rx_t2lm->expected_duration;
}
match_found = true;
break;
}
if (!match_found &&
t2lm_ctx->num_of_t2lm_ie < WLAN_MAX_T2LM_IE) {
qdf_mem_copy(&t2lm_ctx->t2lm_ie[t2lm_ctx->num_of_t2lm_ie].t2lm,
rx_t2lm, sizeof(struct wlan_t2lm_info));
t2lm_ctx->num_of_t2lm_ie++;
}
}
QDF_STATUS wlan_process_bcn_prbrsp_t2lm_ie(
struct wlan_objmgr_vdev *vdev,
struct wlan_t2lm_context *rx_t2lm_ie, uint64_t tsf)
{
struct wlan_t2lm_context *t2lm_ctx;
int i;
t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
for (i = 0; i < rx_t2lm_ie->num_of_t2lm_ie; i++) {
wlan_update_mapping_switch_time_expected_dur(
vdev, &rx_t2lm_ie->t2lm_ie[i].t2lm, tsf);
}
if (!wlan_cm_is_vdev_connected(vdev))
return QDF_STATUS_SUCCESS;
/* Do not start the timer if STA is not in connected state */
for (i = 0; i < t2lm_ctx->num_of_t2lm_ie; i++) {
if (t2lm_ctx->t2lm_ie[i].t2lm.mapping_switch_time_present ||
t2lm_ctx->t2lm_ie[i].t2lm.expected_duration_present) {
wlan_handle_t2lm_timer(vdev, i);
break;
}
}
return QDF_STATUS_SUCCESS;
}