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:

committed by
Madan Koyyalamudi

parent
93e8977721
commit
8759cf1c1e
@@ -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(¶ms->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(¶ms->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(¶ms, 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, ¶ms);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -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_ */
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user