qcacld-3.0: Send vdev create to fw from object create notification
Send vdev create to firmware when the mlme vdev create handler is invoked as part of the vdev object create. Change-Id: Ibba02f6b5885d7b3a62529ef51768f520395513e CRs-Fixed: 2555943
This commit is contained in:

committed by
nshrivas

parent
bdc713cfde
commit
4f6a5bd519
@@ -1172,35 +1172,6 @@ vdevmgr_vdev_start_rsp_handle(struct vdev_mlme_obj *vdev_mlme,
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS mlme_vdev_create_send(struct wlan_objmgr_vdev *vdev)
|
||||
{
|
||||
struct vdev_mlme_obj *vdev_mlme = NULL;
|
||||
QDF_STATUS status;
|
||||
|
||||
vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
|
||||
if (!vdev_mlme) {
|
||||
mlme_err("Failed to get vdev mlme obj for vdev id %d",
|
||||
wlan_vdev_get_id(vdev));
|
||||
status = QDF_STATUS_E_INVAL;
|
||||
goto return_status;
|
||||
}
|
||||
|
||||
status = vdev_mgr_create_send(vdev_mlme);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err("Failed to create vdev for vdev id %d",
|
||||
wlan_vdev_get_id(vdev));
|
||||
goto return_status;
|
||||
}
|
||||
|
||||
status = wma_post_vdev_create_setup(vdev);
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
vdev_mgr_delete_send(vdev_mlme);
|
||||
|
||||
return_status:
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS mlme_vdev_self_peer_create(struct wlan_objmgr_vdev *vdev)
|
||||
{
|
||||
struct vdev_mlme_obj *vdev_mlme;
|
||||
@@ -1215,6 +1186,98 @@ QDF_STATUS mlme_vdev_self_peer_create(struct wlan_objmgr_vdev *vdev)
|
||||
return wma_vdev_self_peer_create(vdev_mlme);
|
||||
}
|
||||
|
||||
/**
|
||||
* mlme_get_vdev_types() - get vdev type and subtype from its operation mode
|
||||
* @mode: operation mode of vdev
|
||||
* @type: type of vdev
|
||||
* @sub_type: sub_type of vdev
|
||||
*
|
||||
* This API is called to get vdev type and subtype from its operation mode.
|
||||
* Vdev operation modes are defined in enum QDF_OPMODE.
|
||||
*
|
||||
* Type of vdev are WLAN_VDEV_MLME_TYPE_AP, WLAN_VDEV_MLME_TYPE_STA,
|
||||
* WLAN_VDEV_MLME_TYPE_IBSS, ,WLAN_VDEV_MLME_TYPE_MONITOR,
|
||||
* WLAN_VDEV_MLME_TYPE_NAN, WLAN_VDEV_MLME_TYPE_OCB, WLAN_VDEV_MLME_TYPE_NDI
|
||||
*
|
||||
* Sub_types of vdev are WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE,
|
||||
* WLAN_VDEV_MLME_SUBTYPE_P2P_CLIENT, WLAN_VDEV_MLME_SUBTYPE_P2P_GO,
|
||||
* WLAN_VDEV_MLME_SUBTYPE_PROXY_STA, WLAN_VDEV_MLME_SUBTYPE_MESH
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
|
||||
static QDF_STATUS mlme_get_vdev_types(enum QDF_OPMODE mode, uint8_t *type,
|
||||
uint8_t *sub_type)
|
||||
{
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
*type = 0;
|
||||
*sub_type = 0;
|
||||
|
||||
switch (mode) {
|
||||
case QDF_STA_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_STA;
|
||||
break;
|
||||
case QDF_SAP_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_AP;
|
||||
break;
|
||||
case QDF_P2P_DEVICE_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_AP;
|
||||
*sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE;
|
||||
break;
|
||||
case QDF_P2P_CLIENT_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_STA;
|
||||
*sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_CLIENT;
|
||||
break;
|
||||
case QDF_P2P_GO_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_AP;
|
||||
*sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_GO;
|
||||
break;
|
||||
case QDF_OCB_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_OCB;
|
||||
break;
|
||||
case QDF_IBSS_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_IBSS;
|
||||
break;
|
||||
case QDF_MONITOR_MODE:
|
||||
*type = WMI_HOST_VDEV_TYPE_MONITOR;
|
||||
break;
|
||||
case QDF_NDI_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_NDI;
|
||||
break;
|
||||
default:
|
||||
mlme_err("Invalid device mode %d", mode);
|
||||
status = QDF_STATUS_E_INVAL;
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static
|
||||
QDF_STATUS vdevmgr_mlme_ext_post_hdl_create(struct vdev_mlme_obj *vdev_mlme)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
|
||||
sme_get_vdev_type_nss(wlan_vdev_mlme_get_opmode(vdev_mlme->vdev),
|
||||
&vdev_mlme->proto.generic.nss_2g,
|
||||
&vdev_mlme->proto.generic.nss_5g);
|
||||
|
||||
status = mlme_get_vdev_types(wlan_vdev_mlme_get_opmode(vdev_mlme->vdev),
|
||||
&vdev_mlme->mgmt.generic.type,
|
||||
&vdev_mlme->mgmt.generic.subtype);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err("Get vdev type failed; status:%d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = vdev_mgr_create_send(vdev_mlme);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err("Failed to create vdev for vdev id %d",
|
||||
wlan_vdev_get_id(vdev_mlme->vdev));
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct sta_mlme_ops - VDEV MLME operation callbacks strucutre for sta
|
||||
* @mlme_vdev_start_send: callback to initiate actions of VDEV
|
||||
@@ -1324,20 +1387,10 @@ static struct vdev_mlme_ops mon_mlme_ops = {
|
||||
.mlme_vdev_ext_start_rsp = vdevmgr_vdev_start_rsp_handle,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mlme_ext_ops - MLME legacy global callbacks structure
|
||||
* @mlme_psoc_ext_hdl_create: callback to invoke creation of legacy
|
||||
* psoc object
|
||||
* @mlme_psoc_ext_hdl_destroy: callback to invoke destroy of legacy
|
||||
* psoc object
|
||||
* @mlme_vdev_ext_hdl_create: callback to invoke creation of legacy
|
||||
* vdev object
|
||||
* @mlme_vdev_ext_hdl_destroy: callback to invoke destroy of legacy
|
||||
* vdev object
|
||||
*/
|
||||
static struct mlme_ext_ops ext_ops = {
|
||||
.mlme_psoc_ext_hdl_create = psoc_mlme_ext_hdl_create,
|
||||
.mlme_psoc_ext_hdl_destroy = psoc_mlme_ext_hdl_destroy,
|
||||
.mlme_vdev_ext_hdl_create = vdevmgr_mlme_ext_hdl_create,
|
||||
.mlme_vdev_ext_hdl_destroy = vdevmgr_mlme_ext_hdl_destroy,
|
||||
.mlme_vdev_ext_hdl_post_create = vdevmgr_mlme_ext_post_hdl_create,
|
||||
};
|
||||
|
@@ -329,27 +329,6 @@ QDF_STATUS cds_free_context(QDF_MODULE_ID module_id, void *module_context);
|
||||
|
||||
QDF_STATUS cds_set_context(QDF_MODULE_ID module_id, void *context);
|
||||
|
||||
/**
|
||||
* cds_get_vdev_types() - get vdev type and subtype from it's operation mode
|
||||
* @mode: operation mode of vdev
|
||||
* @type: type of vdev
|
||||
* @sub_type: sub_type of vdev
|
||||
*
|
||||
* This API is called to get vdev type and subtype from it's operation mode.
|
||||
* Vdev operation modes are defined in enum QDF_OPMODE.
|
||||
*
|
||||
* Type of vdev are WLAN_VDEV_MLME_TYPE_AP, WLAN_VDEV_MLME_TYPE_STA,
|
||||
* WLAN_VDEV_MLME_TYPE_IBSS, ,WLAN_VDEV_MLME_TYPE_MONITOR,
|
||||
* WLAN_VDEV_MLME_TYPE_NAN, WLAN_VDEV_MLME_TYPE_OCB, WLAN_VDEV_MLME_TYPE_NDI
|
||||
*
|
||||
* Sub_types of vdev are WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE,
|
||||
* WLAN_VDEV_MLME_SUBTYPE_P2P_CLIENT, WLAN_VDEV_MLME_SUBTYPE_P2P_GO,
|
||||
* WLAN_VDEV_MLME_SUBTYPE_PROXY_STA, WLAN_VDEV_MLME_SUBTYPE_MESH
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS cds_get_vdev_types(enum QDF_OPMODE mode, uint8_t *type,
|
||||
uint8_t *sub_type);
|
||||
|
||||
void cds_flush_work(void *work);
|
||||
void cds_flush_delayed_work(void *dwork);
|
||||
|
||||
|
@@ -1640,51 +1640,6 @@ QDF_STATUS cds_free_context(QDF_MODULE_ID module_id, void *module_context)
|
||||
return QDF_STATUS_SUCCESS;
|
||||
} /* cds_free_context() */
|
||||
|
||||
QDF_STATUS cds_get_vdev_types(enum QDF_OPMODE mode, uint8_t *type,
|
||||
uint8_t *sub_type)
|
||||
{
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
*type = 0;
|
||||
*sub_type = 0;
|
||||
|
||||
switch (mode) {
|
||||
case QDF_STA_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_STA;
|
||||
break;
|
||||
case QDF_SAP_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_AP;
|
||||
break;
|
||||
case QDF_P2P_DEVICE_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_AP;
|
||||
*sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE;
|
||||
break;
|
||||
case QDF_P2P_CLIENT_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_STA;
|
||||
*sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_CLIENT;
|
||||
break;
|
||||
case QDF_P2P_GO_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_AP;
|
||||
*sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_GO;
|
||||
break;
|
||||
case QDF_OCB_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_OCB;
|
||||
break;
|
||||
case QDF_IBSS_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_IBSS;
|
||||
break;
|
||||
case QDF_MONITOR_MODE:
|
||||
*type = WMI_HOST_VDEV_TYPE_MONITOR;
|
||||
break;
|
||||
case QDF_NDI_MODE:
|
||||
*type = WLAN_VDEV_MLME_TYPE_NDI;
|
||||
break;
|
||||
default:
|
||||
cds_err("Invalid device mode %d", mode);
|
||||
status = QDF_STATUS_E_INVAL;
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* cds_flush_work() - flush pending works
|
||||
|
@@ -4399,7 +4399,7 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
|
||||
|
||||
/* close sme session (destroy vdev in firmware via legacy API) */
|
||||
qdf_event_reset(&adapter->qdf_session_close_event);
|
||||
status = sme_vdev_delete(hdd_ctx->mac_handle, adapter->vdev_id);
|
||||
status = sme_vdev_delete(hdd_ctx->mac_handle, vdev);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
hdd_err("failed to delete vdev; status:%d", status);
|
||||
goto release_vdev;
|
||||
@@ -4441,13 +4441,6 @@ release_vdev:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdd_set_sme_session_param(struct hdd_adapter *adapter,
|
||||
struct sme_session_params *session_param)
|
||||
{
|
||||
session_param->vdev = adapter->vdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hdd_store_nss_chains_cfg_in_vdev(struct hdd_adapter *adapter)
|
||||
{
|
||||
@@ -4483,14 +4476,31 @@ bool hdd_is_vdev_in_conn_state(struct hdd_adapter *adapter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vdev_osif_priv *
|
||||
hdd_init_vdev_os_priv(struct hdd_adapter *adapter)
|
||||
{
|
||||
struct vdev_osif_priv *os_priv;
|
||||
|
||||
os_priv = qdf_mem_malloc(sizeof(*os_priv));
|
||||
if (!os_priv)
|
||||
return NULL;
|
||||
|
||||
/* Initialize the vdev OS private structure*/
|
||||
os_priv->wdev = adapter->dev->ieee80211_ptr;
|
||||
os_priv->legacy_osif_priv = adapter;
|
||||
|
||||
return os_priv;
|
||||
}
|
||||
|
||||
int hdd_vdev_create(struct hdd_adapter *adapter)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
int errno;
|
||||
bool bval;
|
||||
struct hdd_context *hdd_ctx;
|
||||
struct sme_session_params sme_session_params = {0};
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
struct vdev_osif_priv *osif_priv;
|
||||
struct wlan_vdev_create_params vdev_params = {0};
|
||||
|
||||
hdd_info("creating new vdev");
|
||||
|
||||
@@ -4503,26 +4513,39 @@ int hdd_vdev_create(struct hdd_adapter *adapter)
|
||||
errno = qdf_status_to_os_return(status);
|
||||
return errno;
|
||||
}
|
||||
errno = hdd_objmgr_create_and_store_vdev(hdd_ctx->pdev, adapter);
|
||||
if (errno) {
|
||||
hdd_err("failed to create objmgr vdev: %d", errno);
|
||||
return errno;
|
||||
|
||||
osif_priv = hdd_init_vdev_os_priv(adapter);
|
||||
if (!osif_priv) {
|
||||
hdd_err("Failed to allocate osif_priv");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
errno = hdd_set_sme_session_param(adapter, &sme_session_params);
|
||||
if (errno) {
|
||||
hdd_err("failed to populating SME params");
|
||||
goto objmgr_vdev_destroy_procedure;
|
||||
vdev_params.opmode = adapter->device_mode;
|
||||
vdev_params.osifp = osif_priv;
|
||||
qdf_mem_copy(vdev_params.macaddr,
|
||||
adapter->mac_addr.bytes,
|
||||
QDF_NET_MAC_ADDR_MAX_LEN);
|
||||
|
||||
vdev = sme_vdev_create(hdd_ctx->mac_handle, &vdev_params);
|
||||
if (!vdev) {
|
||||
hdd_err("failed to create vdev");
|
||||
return -EINVAL;
|
||||
}
|
||||
status = sme_create_vdev(hdd_ctx->mac_handle,
|
||||
&sme_session_params);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
hdd_err("failed to create vdev: %d", status);
|
||||
errno = qdf_status_to_os_return(status);
|
||||
goto objmgr_vdev_destroy_procedure;
|
||||
|
||||
if (wlan_objmgr_vdev_try_get_ref(vdev, WLAN_HDD_ID_OBJ_MGR) !=
|
||||
QDF_STATUS_SUCCESS) {
|
||||
errno = QDF_STATUS_E_INVAL;
|
||||
sme_vdev_delete(hdd_ctx->mac_handle, vdev);
|
||||
wlan_objmgr_vdev_obj_delete(vdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
set_bit(SME_SESSION_OPENED, &adapter->event_flags);
|
||||
qdf_spin_lock_bh(&adapter->vdev_lock);
|
||||
adapter->vdev_id = wlan_vdev_get_id(vdev);
|
||||
adapter->vdev = vdev;
|
||||
qdf_spin_unlock_bh(&adapter->vdev_lock);
|
||||
|
||||
/* firmware ready for component communication, raise vdev_ready event */
|
||||
errno = hdd_vdev_ready(adapter);
|
||||
if (errno) {
|
||||
@@ -4562,16 +4585,6 @@ int hdd_vdev_create(struct hdd_adapter *adapter)
|
||||
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Due to legacy constraints, we need to destroy in the same order as
|
||||
* create. So, split error handling into 2 cases to accommodate.
|
||||
*/
|
||||
|
||||
objmgr_vdev_destroy_procedure:
|
||||
QDF_BUG(!hdd_objmgr_release_and_destroy_vdev(adapter));
|
||||
|
||||
return errno;
|
||||
|
||||
hdd_vdev_destroy_procedure:
|
||||
QDF_BUG(!hdd_vdev_destroy(adapter));
|
||||
|
||||
|
@@ -52,23 +52,6 @@ static void hdd_deinit_pdev_os_priv(struct wlan_objmgr_pdev *pdev)
|
||||
os_if_spectral_netlink_deinit(pdev);
|
||||
wlan_cfg80211_scan_priv_deinit(pdev);
|
||||
}
|
||||
|
||||
static struct vdev_osif_priv *
|
||||
hdd_init_vdev_os_priv(struct hdd_adapter *adapter)
|
||||
{
|
||||
struct vdev_osif_priv *os_priv;
|
||||
|
||||
os_priv = qdf_mem_malloc(sizeof(*os_priv));
|
||||
if (!os_priv)
|
||||
return NULL;
|
||||
|
||||
/* Initialize the vdev OS private structure*/
|
||||
os_priv->wdev = adapter->dev->ieee80211_ptr;
|
||||
os_priv->legacy_osif_priv = adapter;
|
||||
|
||||
return os_priv;
|
||||
}
|
||||
|
||||
static void hdd_init_psoc_qdf_ctx(struct wlan_objmgr_psoc *psoc)
|
||||
{
|
||||
qdf_device_t qdf_ctx;
|
||||
@@ -231,63 +214,6 @@ int hdd_objmgr_release_and_destroy_pdev(struct hdd_context *hdd_ctx)
|
||||
return qdf_status_to_os_return(status);
|
||||
}
|
||||
|
||||
int hdd_objmgr_create_and_store_vdev(struct wlan_objmgr_pdev *pdev,
|
||||
struct hdd_adapter *adapter)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
int errno = 0;
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
struct vdev_osif_priv *osif_priv;
|
||||
struct wlan_vdev_create_params vdev_params = {0};
|
||||
|
||||
QDF_BUG(pdev);
|
||||
if (!pdev) {
|
||||
hdd_err("pdev is null");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
osif_priv = hdd_init_vdev_os_priv(adapter);
|
||||
if (!osif_priv) {
|
||||
hdd_err("Failed to allocate osif_priv; out of memory");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vdev_params.opmode = adapter->device_mode;
|
||||
vdev_params.osifp = osif_priv;
|
||||
qdf_mem_copy(vdev_params.macaddr,
|
||||
adapter->mac_addr.bytes,
|
||||
QDF_NET_MAC_ADDR_MAX_LEN);
|
||||
|
||||
vdev = wlan_objmgr_vdev_obj_create(pdev, &vdev_params);
|
||||
if (!vdev) {
|
||||
hdd_err("Failed to create vdev object");
|
||||
errno = -ENOMEM;
|
||||
return errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* To enable legacy use cases, we need to delay physical vdev destroy
|
||||
* until after the sme session has been closed. We accomplish this by
|
||||
* getting a reference here.
|
||||
*/
|
||||
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
hdd_err("Failed to acquire vdev ref; status:%d", status);
|
||||
errno = qdf_status_to_os_return(status);
|
||||
goto vdev_destroy;
|
||||
}
|
||||
|
||||
qdf_spin_lock_bh(&adapter->vdev_lock);
|
||||
adapter->vdev = vdev;
|
||||
adapter->vdev_id = wlan_vdev_get_id(vdev);
|
||||
qdf_spin_unlock_bh(&adapter->vdev_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
vdev_destroy:
|
||||
wlan_objmgr_vdev_obj_delete(vdev);
|
||||
return errno;
|
||||
}
|
||||
|
||||
int hdd_objmgr_release_and_destroy_vdev(struct hdd_adapter *adapter)
|
||||
{
|
||||
|
@@ -109,19 +109,6 @@ int hdd_objmgr_create_and_store_pdev(struct hdd_context *hdd_ctx);
|
||||
*/
|
||||
int hdd_objmgr_release_and_destroy_pdev(struct hdd_context *hdd_ctx);
|
||||
|
||||
/**
|
||||
* hdd_objmgr_create_and_store_vdev() - Create vdev and store in hdd adapter
|
||||
* @pdev: pdev pointer
|
||||
* @adapter: hdd adapter
|
||||
*
|
||||
* This API creates the vdev object and store the vdev reference to the
|
||||
* given @adapter. Also, creates a self peer for the vdev.
|
||||
*
|
||||
* Return: 0 for success, negative error code for failure
|
||||
*/
|
||||
int hdd_objmgr_create_and_store_vdev(struct wlan_objmgr_pdev *pdev,
|
||||
struct hdd_adapter *adapter);
|
||||
|
||||
/**
|
||||
* hdd_objmgr_release_and_destroy_vdev() - Delete vdev and remove from adapter
|
||||
* @adapter: hdd adapter
|
||||
|
@@ -357,34 +357,43 @@ sme_nss_chains_update(mac_handle_t mac_handle,
|
||||
uint8_t vdev_id);
|
||||
|
||||
/**
|
||||
* sme_create_vdev() - Create vdev for given persona
|
||||
* sme_vdev_create() - Create vdev for given persona
|
||||
* @mac_handle: The handle returned by mac_open
|
||||
* @params: to initialize the session open params
|
||||
* @vdev_params: params required for vdev creation
|
||||
*
|
||||
* This is a synchronous API. For any protocol stack related activity
|
||||
* requires vdev to be created. This API needs to be called to create
|
||||
* vdev in SME module.
|
||||
* This API will create the object manager vdev and in the same
|
||||
* context vdev mlme object manager notification is invoked, which
|
||||
* will send the vdev create to the firmware.
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS - vdev is created
|
||||
* Other status means SME is failed to create vdev
|
||||
* If the vdev creation is successful the following object is referenced
|
||||
* by below modules:
|
||||
* 1) WLAN_OBJMGR_ID
|
||||
* 2) WLAN_LEGACY_SME_ID
|
||||
* 3) WLAN_LEGACY_WMA_ID
|
||||
*
|
||||
* Return: Newly created Vdev object or NULL incase in any error
|
||||
*/
|
||||
QDF_STATUS sme_create_vdev(mac_handle_t mac_handle,
|
||||
struct sme_session_params *params);
|
||||
struct wlan_objmgr_vdev *sme_vdev_create(mac_handle_t mac_handle,
|
||||
struct wlan_vdev_create_params *vdev_params);
|
||||
|
||||
|
||||
/**
|
||||
* sme_vdev_delete() - Delete vdev for given id
|
||||
* @mac_handle: The handle returned by mac_open.
|
||||
* @vdev: VDEV Object
|
||||
*
|
||||
* This is a synchronous API. This API needs to be called to delete vdev
|
||||
* in SME module before terminating the session completely.
|
||||
*
|
||||
* mac_handle: The handle returned by mac_open.
|
||||
* vdev_id: A previous created vdev id.
|
||||
* The following modules releases their reference to the vdev object:
|
||||
* 1) WLAN_LEGACY_WMA_ID
|
||||
* 2) WLAN_LEGACY_SME_ID
|
||||
*
|
||||
* Return:
|
||||
* QDF_STATUS_SUCCESS - vdev is deleted.
|
||||
* Other status means SME is failed to delete vdev.
|
||||
* Return: QDF_STATUS_SUCCESS - vdev is deleted.
|
||||
* QDF_STATUS_E_INVAL when failed to delete vdev.
|
||||
*/
|
||||
QDF_STATUS sme_vdev_delete(mac_handle_t mac_handle, uint8_t vdev_id);
|
||||
QDF_STATUS sme_vdev_delete(mac_handle_t mac_handle,
|
||||
struct wlan_objmgr_vdev *vdev);
|
||||
|
||||
/**
|
||||
* sme_cleanup_session() - clean up sme session info for vdev
|
||||
|
@@ -4499,38 +4499,77 @@ release_ref:
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS sme_create_vdev(mac_handle_t mac_handle,
|
||||
struct sme_session_params *params)
|
||||
struct wlan_objmgr_vdev *sme_vdev_create(mac_handle_t mac_handle,
|
||||
struct wlan_vdev_create_params *vdev_params)
|
||||
{
|
||||
QDF_STATUS status = QDF_STATUS_E_INVAL;
|
||||
struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle);
|
||||
uint8_t vdev_id;
|
||||
u8 *mac_addr;
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
struct vdev_mlme_obj *vdev_mlme;
|
||||
|
||||
vdev_id = wlan_vdev_get_id(params->vdev);
|
||||
mac_addr = wlan_vdev_mlme_get_macaddr(params->vdev);
|
||||
sme_debug("addr:%pM opmode:%d", vdev_params->macaddr,
|
||||
vdev_params->opmode);
|
||||
|
||||
sme_debug("vdev_id %d addr:%pM", vdev_id, mac_addr);
|
||||
vdev = wlan_objmgr_vdev_obj_create(mac_ctx->pdev, vdev_params);
|
||||
if (!vdev) {
|
||||
sme_err("Failed to create vdev object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = sme_acquire_global_lock(&mac_ctx->sme);
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
return status;
|
||||
if (wlan_objmgr_vdev_try_get_ref(vdev, WLAN_LEGACY_SME_ID) !=
|
||||
QDF_STATUS_SUCCESS) {
|
||||
wlan_objmgr_vdev_obj_delete(vdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = csr_create_vdev(mac_ctx, params->vdev, params);
|
||||
if (QDF_IS_STATUS_SUCCESS(status))
|
||||
status = mlme_vdev_self_peer_create(params->vdev);
|
||||
sme_release_global_lock(&mac_ctx->sme);
|
||||
vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
|
||||
if (!vdev_mlme) {
|
||||
sme_err("Failed to get vdev mlme obj!");
|
||||
QDF_BUG(0);
|
||||
goto vdev_obj_del;
|
||||
}
|
||||
|
||||
MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_OPEN_SESSION,
|
||||
vdev_id = wlan_vdev_get_id(vdev);
|
||||
status = wma_post_vdev_create_setup(vdev);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
sme_err("Failed to setup wma for vdev: %d", vdev_id);
|
||||
goto vdev_obj_del;
|
||||
}
|
||||
|
||||
status = csr_setup_vdev_session(vdev_mlme);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
sme_err("Failed to setup CSR layer for vdev: %d", vdev_id);
|
||||
goto cleanup_wma;
|
||||
}
|
||||
|
||||
status = mlme_vdev_self_peer_create(vdev);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
sme_err("Failed to create vdev selfpeer for vdev:%d", vdev_id);
|
||||
goto csr_cleanup_vdev_session;
|
||||
}
|
||||
MTRACE(qdf_trace(QDF_MODULE_ID_SME,
|
||||
TRACE_CODE_SME_RX_HDD_OPEN_SESSION,
|
||||
vdev_id, 0));
|
||||
|
||||
return status;
|
||||
return vdev;
|
||||
|
||||
csr_cleanup_vdev_session:
|
||||
csr_cleanup_vdev_session(mac_ctx, vdev_id);
|
||||
cleanup_wma:
|
||||
wma_cleanup_vdev(vdev);
|
||||
vdev_obj_del:
|
||||
wlan_objmgr_vdev_obj_delete(vdev);
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QDF_STATUS sme_vdev_delete(mac_handle_t mac_handle, uint8_t vdev_id)
|
||||
QDF_STATUS sme_vdev_delete(mac_handle_t mac_handle,
|
||||
struct wlan_objmgr_vdev *vdev)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
struct mac_context *mac = MAC_CONTEXT(mac_handle);
|
||||
uint8_t vdev_id = wlan_vdev_get_id(vdev);
|
||||
|
||||
MTRACE(qdf_trace(QDF_MODULE_ID_SME,
|
||||
TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, vdev_id, 0));
|
||||
@@ -4540,6 +4579,8 @@ QDF_STATUS sme_vdev_delete(mac_handle_t mac_handle, uint8_t vdev_id)
|
||||
sme_release_global_lock(&mac->sme);
|
||||
}
|
||||
|
||||
/* Release the reference acquired during vdev create */
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -4551,7 +4592,7 @@ void sme_cleanup_session(mac_handle_t mac_handle, uint8_t vdev_id)
|
||||
status = sme_acquire_global_lock(&mac->sme);
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
return;
|
||||
csr_cleanup_session(mac, vdev_id);
|
||||
csr_cleanup_vdev_session(mac, vdev_id);
|
||||
sme_release_global_lock(&mac->sme);
|
||||
}
|
||||
|
||||
@@ -13400,14 +13441,7 @@ QDF_STATUS sme_process_mac_pwr_dbg_cmd(mac_handle_t mac_handle,
|
||||
void sme_get_vdev_type_nss(enum QDF_OPMODE dev_mode,
|
||||
uint8_t *nss_2g, uint8_t *nss_5g)
|
||||
{
|
||||
struct mac_context *mac_ctx = sme_get_mac_context();
|
||||
|
||||
if (!mac_ctx) {
|
||||
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
|
||||
FL("Invalid MAC context"));
|
||||
return;
|
||||
}
|
||||
csr_get_vdev_type_nss(mac_ctx, dev_mode, nss_2g, nss_5g);
|
||||
csr_get_vdev_type_nss(dev_mode, nss_2g, nss_5g);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -17199,21 +17199,16 @@ static void csr_send_set_ie(uint8_t type, uint8_t sub_type,
|
||||
sme_err("Failed to send set IE req for vdev_%d", vdev_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* csr_get_vdev_type_nss() - gets the nss value based on vdev type
|
||||
* @mac_ctx: Pointer to Global MAC structure
|
||||
* @dev_mode: current device operating mode.
|
||||
* @nss2g: Pointer to the 2G Nss parameter.
|
||||
* @nss5g: Pointer to the 5G Nss parameter.
|
||||
*
|
||||
* Fills the 2G and 5G Nss values based on device mode.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void csr_get_vdev_type_nss(struct mac_context *mac_ctx,
|
||||
enum QDF_OPMODE dev_mode,
|
||||
uint8_t *nss_2g, uint8_t *nss_5g)
|
||||
void csr_get_vdev_type_nss(enum QDF_OPMODE dev_mode, uint8_t *nss_2g,
|
||||
uint8_t *nss_5g)
|
||||
{
|
||||
struct mac_context *mac_ctx = sme_get_mac_context();
|
||||
|
||||
if (!mac_ctx) {
|
||||
sme_err("Invalid MAC context");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev_mode) {
|
||||
case QDF_STA_MODE:
|
||||
*nss_2g = mac_ctx->vdev_type_nss_2g.sta;
|
||||
@@ -17261,19 +17256,25 @@ void csr_get_vdev_type_nss(struct mac_context *mac_ctx,
|
||||
dev_mode, *nss_2g, *nss_5g);
|
||||
}
|
||||
|
||||
QDF_STATUS csr_create_vdev(struct mac_context *mac_ctx,
|
||||
struct wlan_objmgr_vdev *vdev,
|
||||
struct sme_session_params *session_param)
|
||||
QDF_STATUS csr_setup_vdev_session(struct vdev_mlme_obj *vdev_mlme)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
uint32_t existing_session_id;
|
||||
struct mlme_ht_capabilities_info *ht_cap_info;
|
||||
struct csr_roam_session *session;
|
||||
struct mlme_vht_capabilities_info *vht_cap_info;
|
||||
struct vdev_mlme_obj *vdev_mlme;
|
||||
enum QDF_OPMODE op_mode;
|
||||
u8 vdev_id;
|
||||
struct qdf_mac_addr *mac_addr;
|
||||
mac_handle_t mac_handle;
|
||||
struct mac_context *mac_ctx;
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
|
||||
mac_handle = cds_get_context(QDF_MODULE_ID_SME);
|
||||
mac_ctx = MAC_CONTEXT(mac_handle);
|
||||
if (!mac_ctx) {
|
||||
QDF_ASSERT(0);
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
if (!(mac_ctx->mlme_cfg)) {
|
||||
sme_err("invalid mlme cfg");
|
||||
@@ -17281,28 +17282,10 @@ QDF_STATUS csr_create_vdev(struct mac_context *mac_ctx,
|
||||
}
|
||||
vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info;
|
||||
|
||||
vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
|
||||
if (!vdev_mlme) {
|
||||
sme_err("Failed to get cmpt obj");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
vdev = vdev_mlme->vdev;
|
||||
|
||||
vdev_id = wlan_vdev_get_id(session_param->vdev);
|
||||
mac_addr = (struct qdf_mac_addr *)
|
||||
wlan_vdev_mlme_get_macaddr(session_param->vdev);
|
||||
|
||||
op_mode = wlan_vdev_mlme_get_opmode(vdev);
|
||||
csr_get_vdev_type_nss(mac_ctx, op_mode,
|
||||
&vdev_mlme->proto.generic.nss_2g,
|
||||
&vdev_mlme->proto.generic.nss_5g);
|
||||
|
||||
status = cds_get_vdev_types(op_mode,
|
||||
&vdev_mlme->mgmt.generic.type,
|
||||
&vdev_mlme->mgmt.generic.subtype);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
sme_err("Get vdev type failed; status:%d", status);
|
||||
return status;
|
||||
}
|
||||
vdev_id = wlan_vdev_get_id(vdev);
|
||||
mac_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_macaddr(vdev);
|
||||
|
||||
/* check to see if the mac address already belongs to a session */
|
||||
status = csr_roam_get_session_id_from_bssid(mac_ctx, mac_addr,
|
||||
@@ -17393,13 +17376,6 @@ QDF_STATUS csr_create_vdev(struct mac_context *mac_ctx,
|
||||
*/
|
||||
csr_init_session_twt_cap(session, vdev_mlme->mgmt.generic.type);
|
||||
|
||||
status = mlme_vdev_create_send(vdev);
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
csr_cleanup_session(mac_ctx, vdev_id);
|
||||
return status;
|
||||
}
|
||||
|
||||
csr_send_set_ie(vdev_mlme->mgmt.generic.type,
|
||||
vdev_mlme->mgmt.generic.subtype,
|
||||
wlan_vdev_get_id(vdev));
|
||||
@@ -17435,7 +17411,7 @@ QDF_STATUS csr_process_vdev_del_rsp(struct mac_context *mac_ctx,
|
||||
* for this vdev. Active cmnd is e_sme_command_del_vdev and will
|
||||
* be removed anyway next.
|
||||
*/
|
||||
csr_cleanup_session(mac_ctx, vdev_id);
|
||||
csr_cleanup_vdev_session(mac_ctx, vdev_id);
|
||||
|
||||
if (rsp->sme_callback) {
|
||||
status = sme_release_global_lock(&mac_ctx->sme);
|
||||
@@ -17491,7 +17467,7 @@ csr_issue_vdev_del_req(struct mac_context *mac_ctx, uint8_t vdev_id,
|
||||
return status;
|
||||
}
|
||||
|
||||
void csr_cleanup_session(struct mac_context *mac, uint8_t vdev_id)
|
||||
void csr_cleanup_vdev_session(struct mac_context *mac, uint8_t vdev_id)
|
||||
{
|
||||
if (CSR_IS_SESSION_VALID(mac, vdev_id)) {
|
||||
struct csr_roam_session *pSession = CSR_GET_SESSION(mac,
|
||||
@@ -17531,7 +17507,7 @@ QDF_STATUS csr_roam_vdev_delete(struct mac_context *mac_ctx,
|
||||
/* Vdev going down stop roaming */
|
||||
session->fCancelRoaming = true;
|
||||
if (cleanup) {
|
||||
csr_cleanup_session(mac_ctx, vdev_id);
|
||||
csr_cleanup_vdev_session(mac_ctx, vdev_id);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@@ -377,7 +377,7 @@ QDF_STATUS csr_roam_vdev_delete(struct mac_context *mac_ctx,
|
||||
uint8_t vdev_id, bool cleanup);
|
||||
|
||||
/*
|
||||
* csr_cleanup_session() - CSR api to cleanup vdev
|
||||
* csr_cleanup_vdev_session() - CSR api to cleanup vdev
|
||||
* @mac_ctx: pointer to mac context
|
||||
* @vdev_id: vdev id to be deleted.
|
||||
*
|
||||
@@ -386,7 +386,7 @@ QDF_STATUS csr_roam_vdev_delete(struct mac_context *mac_ctx,
|
||||
*
|
||||
* Return QDF_STATUS
|
||||
*/
|
||||
void csr_cleanup_session(struct mac_context *mac, uint8_t vdev_id);
|
||||
void csr_cleanup_vdev_session(struct mac_context *mac, uint8_t vdev_id);
|
||||
|
||||
QDF_STATUS csr_roam_get_session_id_from_bssid(struct mac_context *mac,
|
||||
struct qdf_mac_addr *bssid,
|
||||
@@ -567,9 +567,18 @@ void csr_release_command_buffer(struct mac_context *mac, tSmeCmd *pCommand);
|
||||
bool csr_is_profile_wapi(struct csr_roam_profile *pProfile);
|
||||
#endif /* FEATURE_WLAN_WAPI */
|
||||
|
||||
void csr_get_vdev_type_nss(struct mac_context *mac_ctx,
|
||||
enum QDF_OPMODE dev_mode,
|
||||
uint8_t *nss_2g, uint8_t *nss_5g);
|
||||
/**
|
||||
* csr_get_vdev_type_nss() - gets the nss value based on vdev type
|
||||
* @dev_mode: current device operating mode.
|
||||
* @nss2g: Pointer to the 2G Nss parameter.
|
||||
* @nss5g: Pointer to the 5G Nss parameter.
|
||||
*
|
||||
* Fills the 2G and 5G Nss values based on device mode.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void csr_get_vdev_type_nss(enum QDF_OPMODE dev_mode, uint8_t *nss_2g,
|
||||
uint8_t *nss_5g);
|
||||
|
||||
#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
|
||||
|
||||
@@ -1120,16 +1129,15 @@ csr_scan_get_channel_for_hw_mode_change(
|
||||
struct mac_context *mac_ctx, uint32_t session_id,
|
||||
struct csr_roam_profile *profile);
|
||||
/**
|
||||
* csr_create_vdev() - API to create vdev
|
||||
* @mac_ctx: pointer to mac context
|
||||
* @vdev: vdev object
|
||||
* @session_param: Session params
|
||||
* csr_setup_vdev_session() - API to setup vdev mac session
|
||||
* @vdev_mlme: vdev mlme private object
|
||||
*
|
||||
* This API setsup the vdev session for the mac layer
|
||||
*
|
||||
* Returns: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS csr_create_vdev(struct mac_context *mac,
|
||||
struct wlan_objmgr_vdev *vdev,
|
||||
struct sme_session_params *session_param);
|
||||
QDF_STATUS csr_setup_vdev_session(struct vdev_mlme_obj *vdev_mlme);
|
||||
|
||||
|
||||
#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
|
||||
/**
|
||||
|
@@ -773,4 +773,15 @@ void wma_update_roam_offload_flag(void *handle,
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS wma_vdev_self_peer_create(struct vdev_mlme_obj *vdev_mlme);
|
||||
|
||||
/**
|
||||
* wma_cleanup_vdev() - cleanup wma layers vdev
|
||||
* @vdev: Object manager vdev
|
||||
*
|
||||
* This function cleansup the wma layers vdev related data.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void wma_cleanup_vdev(struct wlan_objmgr_vdev *vdev);
|
||||
|
||||
#endif /* WMA_API_H */
|
||||
|
@@ -2467,14 +2467,38 @@ QDF_STATUS wma_vdev_stop_resp_handler(struct vdev_mlme_obj *vdev_mlme,
|
||||
return status;
|
||||
}
|
||||
|
||||
static void wma_clean_up_iface(void *soc, tp_wma_handle wma_handle,
|
||||
struct wlan_objmgr_vdev *vdev)
|
||||
void wma_cleanup_vdev(struct wlan_objmgr_vdev *vdev)
|
||||
{
|
||||
tp_wma_handle wma_handle;
|
||||
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
|
||||
uint8_t vdev_id = wlan_vdev_get_id(vdev);
|
||||
struct vdev_mlme_obj *vdev_mlme;
|
||||
|
||||
if (!soc) {
|
||||
wma_err("SOC handle is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
|
||||
if (!wma_handle) {
|
||||
wma_err("WMA context is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wma_handle->interfaces[vdev_id].vdev) {
|
||||
wma_err("vdev is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
|
||||
if (!vdev_mlme) {
|
||||
wma_err("Failed to get vdev mlme obj for vdev id %d", vdev_id);
|
||||
return;
|
||||
}
|
||||
|
||||
wma_cdp_vdev_detach(soc, wma_handle, vdev_id);
|
||||
wma_handle->interfaces[vdev_id].vdev = NULL;
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID);
|
||||
wma_handle->interfaces[vdev_id].vdev = NULL;
|
||||
wma_handle->interfaces[vdev_id].vdev_active = false;
|
||||
}
|
||||
|
||||
@@ -2485,12 +2509,6 @@ QDF_STATUS wma_vdev_self_peer_create(struct vdev_mlme_obj *vdev_mlme)
|
||||
struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
|
||||
struct cdp_pdev *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX);
|
||||
tp_wma_handle wma_handle;
|
||||
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
|
||||
|
||||
if (!soc) {
|
||||
wma_err("SOC handle is NULL");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
if (!txrx_pdev) {
|
||||
wma_err("TXRX PDEV is NULL");
|
||||
@@ -2523,10 +2541,6 @@ QDF_STATUS wma_vdev_self_peer_create(struct vdev_mlme_obj *vdev_mlme)
|
||||
}
|
||||
}
|
||||
|
||||
/* If error cleanup the interface */
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
wma_clean_up_iface(soc, wma_handle, vdev);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -2813,7 +2827,7 @@ QDF_STATUS wma_post_vdev_create_setup(struct wlan_objmgr_vdev *vdev)
|
||||
return QDF_STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
wma_clean_up_iface(soc, wma_handle, vdev);
|
||||
wma_cleanup_vdev(vdev);
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user