qcacld-3.0: Add dp_link data structure
Currently dp_intf is create on adapter level, but corresponds to vdev. ML connection can have multiple links for same adapter. Hence introduce a new data structure dp_link, which corresponds to the vdev, whereas dp_intf now corresponds only to adapter/netdev. Change-Id: Ia2bba89f425b64b4e404f6866a54fe0f6e05ad6d CRs-Fixed: 3518894
此提交包含在:
@@ -144,6 +144,83 @@ dp_get_intf_by_macaddr(struct wlan_dp_psoc_context *dp_ctx,
|
||||
struct wlan_dp_intf*
|
||||
dp_get_intf_by_netdev(struct wlan_dp_psoc_context *dp_ctx, qdf_netdev_t dev);
|
||||
|
||||
/**
|
||||
* dp_get_front_link_no_lock() - Get the first link from the dp links list
|
||||
* This API does not use any lock in it's implementation. It is the caller's
|
||||
* directive to ensure concurrency safety.
|
||||
* @dp_intf: DP interface handle
|
||||
* @out_link: double pointer to pass the next link
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS
|
||||
dp_get_front_link_no_lock(struct wlan_dp_intf *dp_intf,
|
||||
struct wlan_dp_link **out_link);
|
||||
|
||||
/**
|
||||
* dp_get_next_link_no_lock() - Get the next link from the link list
|
||||
* This API does not use any lock in it's implementation. It is the caller's
|
||||
* directive to ensure concurrency safety.
|
||||
* @dp_intf: DP interface handle
|
||||
* @cur_link: pointer to the currentlink
|
||||
* @out_link: double pointer to pass the nextlink
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS
|
||||
dp_get_next_link_no_lock(struct wlan_dp_intf *dp_intf,
|
||||
struct wlan_dp_link *cur_link,
|
||||
struct wlan_dp_link **out_link);
|
||||
|
||||
/**
|
||||
* __dp_take_ref_and_fetch_front_link_safe - Helper macro to lock, fetch
|
||||
* front and next link, take ref and unlock.
|
||||
* @dp_intf: DP interface handle
|
||||
* @dp_link: an dp_link pointer to use as a cursor
|
||||
* @dp_link_next: dp_link pointer to nextlink
|
||||
*/
|
||||
#define __dp_take_ref_and_fetch_front_link_safe(dp_intf, dp_link, \
|
||||
dp_link_next) \
|
||||
qdf_spin_lock_bh(&(dp_intf)->dp_link_list_lock), \
|
||||
dp_get_front_link_no_lock(dp_intf, &(dp_link)), \
|
||||
dp_get_next_link_no_lock(dp_intf, dp_link, &(dp_link_next)), \
|
||||
qdf_spin_unlock_bh(&(dp_intf)->dp_link_list_lock)
|
||||
|
||||
/**
|
||||
* __dp_take_ref_and_fetch_next_link_safe - Helper macro to lock, fetch next
|
||||
* interface, take ref and unlock.
|
||||
* @dp_intf: DP interface handle
|
||||
* @dp_link: dp_link pointer to use as a cursor
|
||||
* @dp_link_next: dp_link pointer to next link
|
||||
*/
|
||||
#define __dp_take_ref_and_fetch_next_link_safe(dp_intf, dp_link, \
|
||||
dp_link_next) \
|
||||
qdf_spin_lock_bh(&(dp_intf)->dp_link_list_lock), \
|
||||
dp_link = dp_link_next, \
|
||||
dp_get_next_link_no_lock(dp_intf, dp_link, &(dp_link_next)), \
|
||||
qdf_spin_unlock_bh(&(dp_intf)->dp_link_list_lock)
|
||||
|
||||
/**
|
||||
* __dp_is_link_valid - Helper macro to return true/false for valid interface.
|
||||
* @_dp_link: an dp_link pointer to use as a cursor
|
||||
*/
|
||||
#define __dp_is_link_valid(_dp_link) !!(_dp_link)
|
||||
|
||||
/**
|
||||
* dp_for_each_link_held_safe - Interface iterator called
|
||||
* in a delete safe manner
|
||||
* @dp_intf: DP interface handle
|
||||
* @dp_link: an dp_link pointer to use as a cursor
|
||||
* @dp_link_next: dp_link pointer to the next interface
|
||||
*
|
||||
*/
|
||||
#define dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) \
|
||||
for (__dp_take_ref_and_fetch_front_link_safe(dp_intf, dp_link, \
|
||||
dp_link_next); \
|
||||
__dp_is_link_valid(dp_link); \
|
||||
__dp_take_ref_and_fetch_next_link_safe(dp_intf, dp_link, \
|
||||
dp_link_next))
|
||||
|
||||
/* MAX iteration count to wait for dp packet process to complete */
|
||||
#define DP_TASK_MAX_WAIT_CNT 100
|
||||
/* Milli seconds to wait when packet is getting processed */
|
||||
|
@@ -613,6 +613,10 @@ struct dp_rx_fst {
|
||||
* @qdf_sta_eap_frm_done_event: EAP frame event management
|
||||
* @traffic_end_ind: store traffic end indication info
|
||||
* @direct_link_config: direct link configuration parameters
|
||||
* @num_links: Number of links for this DP interface
|
||||
* @def_link: Pointer to default link (usually used for TX operation)
|
||||
* @dp_link_list_lock: Lock to protect dp_link_list operatiosn
|
||||
* @dp_link_list: List of dp_links for this DP interface
|
||||
*/
|
||||
struct wlan_dp_intf {
|
||||
struct wlan_dp_psoc_context *dp_ctx;
|
||||
@@ -674,6 +678,24 @@ struct wlan_dp_intf {
|
||||
#ifdef FEATURE_DIRECT_LINK
|
||||
struct direct_link_info direct_link_config;
|
||||
#endif
|
||||
uint8_t num_links;
|
||||
struct wlan_dp_link *def_link;
|
||||
qdf_spinlock_t dp_link_list_lock;
|
||||
qdf_list_t dp_link_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wlan_dp_link - DP link (corresponds to objmgr vdev)
|
||||
* @node: list node for membership in the DP links list
|
||||
* @link_id: ID for this DP link (Same as vdev_id)
|
||||
* @mac_addr: mac address of this link
|
||||
* @dp_intf: Parent DP interface for this DP link
|
||||
*/
|
||||
struct wlan_dp_link {
|
||||
qdf_list_node_t node;
|
||||
uint8_t link_id;
|
||||
struct qdf_mac_addr mac_addr;
|
||||
struct wlan_dp_intf *dp_intf;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -216,6 +216,48 @@ int is_dp_intf_valid(struct wlan_dp_intf *dp_intf)
|
||||
return validate_interface_id(dp_intf->intf_id);
|
||||
}
|
||||
|
||||
QDF_STATUS dp_get_front_link_no_lock(struct wlan_dp_intf *dp_intf,
|
||||
struct wlan_dp_link **out_link)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
qdf_list_node_t *node;
|
||||
|
||||
*out_link = NULL;
|
||||
|
||||
status = qdf_list_peek_front(&dp_intf->dp_link_list, &node);
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
return status;
|
||||
|
||||
*out_link = qdf_container_of(node, struct wlan_dp_link, node);
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS dp_get_next_link_no_lock(struct wlan_dp_intf *dp_intf,
|
||||
struct wlan_dp_link *cur_link,
|
||||
struct wlan_dp_link **out_link)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
qdf_list_node_t *node;
|
||||
|
||||
if (!cur_link)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
*out_link = NULL;
|
||||
|
||||
status = qdf_list_peek_next(&dp_intf->dp_link_list,
|
||||
&cur_link->node,
|
||||
&node);
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
return status;
|
||||
|
||||
*out_link = qdf_container_of(node, struct wlan_dp_link, node);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static QDF_STATUS
|
||||
dp_intf_wait_for_task_complete(struct wlan_dp_intf *dp_intf)
|
||||
{
|
||||
@@ -919,11 +961,13 @@ dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
|
||||
struct wlan_objmgr_psoc *psoc;
|
||||
struct wlan_dp_psoc_context *dp_ctx;
|
||||
struct wlan_dp_intf *dp_intf;
|
||||
struct wlan_dp_link *dp_link;
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
struct qdf_mac_addr *mac_addr;
|
||||
qdf_netdev_t dev;
|
||||
|
||||
dp_info("DP VDEV OBJ create notification");
|
||||
dp_info("DP VDEV OBJ create notification, vdev_id %d",
|
||||
wlan_vdev_get_id(vdev));
|
||||
|
||||
psoc = wlan_vdev_get_psoc(vdev);
|
||||
if (!psoc) {
|
||||
@@ -949,36 +993,62 @@ dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
dp_intf->device_mode = wlan_vdev_mlme_get_opmode(vdev);
|
||||
dp_link = qdf_mem_malloc(sizeof(*dp_link));
|
||||
if (!dp_link) {
|
||||
dp_err("DP link(" QDF_MAC_ADDR_FMT ") memory alloc failed",
|
||||
QDF_MAC_ADDR_REF(mac_addr->bytes));
|
||||
return QDF_STATUS_E_NOMEM;
|
||||
}
|
||||
|
||||
/* Update Parent interface details */
|
||||
dp_link->dp_intf = dp_intf;
|
||||
qdf_spin_lock_bh(&dp_intf->dp_link_list_lock);
|
||||
qdf_list_insert_front(&dp_intf->dp_link_list, &dp_link->node);
|
||||
dp_intf->num_links++;
|
||||
qdf_spin_unlock_bh(&dp_intf->dp_link_list_lock);
|
||||
|
||||
qdf_copy_macaddr(&dp_link->mac_addr, mac_addr);
|
||||
|
||||
qdf_spin_lock_bh(&dp_intf->vdev_lock);
|
||||
dp_link->link_id = vdev->vdev_objmgr.vdev_id;
|
||||
dp_intf->intf_id = vdev->vdev_objmgr.vdev_id;
|
||||
dp_intf->vdev = vdev;
|
||||
qdf_spin_unlock_bh(&dp_intf->vdev_lock);
|
||||
qdf_atomic_init(&dp_intf->num_active_task);
|
||||
|
||||
if (dp_intf->device_mode == QDF_SAP_MODE ||
|
||||
dp_intf->device_mode == QDF_P2P_GO_MODE) {
|
||||
dp_intf->sap_tx_block_mask = DP_TX_FN_CLR | DP_TX_SAP_STOP;
|
||||
|
||||
status = qdf_event_create(&dp_intf->qdf_sta_eap_frm_done_event);
|
||||
if (!QDF_IS_STATUS_SUCCESS(status)) {
|
||||
dp_err("eap frm done event init failed!!");
|
||||
return status;
|
||||
}
|
||||
qdf_mem_zero(&dp_intf->stats, sizeof(qdf_net_dev_stats));
|
||||
}
|
||||
|
||||
status = wlan_objmgr_vdev_component_obj_attach(vdev,
|
||||
WLAN_COMP_DP,
|
||||
(void *)dp_intf,
|
||||
(void *)dp_link,
|
||||
QDF_STATUS_SUCCESS);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
dp_err("Failed to attach dp_intf with vdev");
|
||||
dp_err("Failed to attach dp_link with vdev");
|
||||
return status;
|
||||
}
|
||||
|
||||
dp_nud_ignore_tracking(dp_intf, false);
|
||||
dp_mic_enable_work(dp_intf);
|
||||
if (dp_intf->num_links == 1) {
|
||||
/*
|
||||
* Interface level operations to be done only
|
||||
* when the first link is created
|
||||
*/
|
||||
dp_intf->def_link = dp_link;
|
||||
dp_intf->device_mode = wlan_vdev_mlme_get_opmode(vdev);
|
||||
qdf_atomic_init(&dp_intf->num_active_task);
|
||||
dp_nud_ignore_tracking(dp_intf, false);
|
||||
dp_mic_enable_work(dp_intf);
|
||||
|
||||
if (dp_intf->device_mode == QDF_SAP_MODE ||
|
||||
dp_intf->device_mode == QDF_P2P_GO_MODE) {
|
||||
dp_intf->sap_tx_block_mask = DP_TX_FN_CLR |
|
||||
DP_TX_SAP_STOP;
|
||||
|
||||
status = qdf_event_create(&dp_intf->qdf_sta_eap_frm_done_event);
|
||||
if (!QDF_IS_STATUS_SUCCESS(status)) {
|
||||
dp_err("eap frm done event init failed!!");
|
||||
return status;
|
||||
}
|
||||
qdf_mem_zero(&dp_intf->stats,
|
||||
sizeof(qdf_net_dev_stats));
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -988,48 +1058,76 @@ dp_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg)
|
||||
|
||||
{
|
||||
struct wlan_dp_intf *dp_intf;
|
||||
struct wlan_dp_link *dp_link;
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
|
||||
dp_info("DP VDEV OBJ destroy notification");
|
||||
dp_info("DP VDEV OBJ destroy notification, vdev_id %d",
|
||||
wlan_vdev_get_id(vdev));
|
||||
|
||||
dp_intf = dp_get_vdev_priv_obj(vdev);
|
||||
if (!dp_intf) {
|
||||
dp_err("Failed to get DP interface obj");
|
||||
/*
|
||||
* TODO - Remove the below line after proto-type of
|
||||
* dp_get_vdev_priv_obj is changed
|
||||
*/
|
||||
dp_link = (struct wlan_dp_link *)dp_intf;
|
||||
if (!dp_link) {
|
||||
dp_err("Failed to get DP link obj");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
dp_nud_ignore_tracking(dp_intf, true);
|
||||
dp_nud_reset_tracking(dp_intf);
|
||||
dp_nud_flush_work(dp_intf);
|
||||
dp_mic_flush_work(dp_intf);
|
||||
dp_intf = dp_link->dp_intf;
|
||||
|
||||
qdf_spin_lock_bh(&dp_intf->dp_link_list_lock);
|
||||
qdf_list_remove_node(&dp_intf->dp_link_list, &dp_link->node);
|
||||
dp_intf->num_links--;
|
||||
qdf_spin_unlock_bh(&dp_intf->dp_link_list_lock);
|
||||
|
||||
if (dp_intf->num_links == 0) {
|
||||
/*
|
||||
* Interface level operations are stopped when last
|
||||
* link is deleted
|
||||
*/
|
||||
dp_nud_ignore_tracking(dp_intf, true);
|
||||
dp_nud_reset_tracking(dp_intf);
|
||||
dp_nud_flush_work(dp_intf);
|
||||
dp_mic_flush_work(dp_intf);
|
||||
qdf_mem_zero(&dp_intf->conn_info,
|
||||
sizeof(struct wlan_dp_conn_info));
|
||||
|
||||
if (dp_intf->device_mode == QDF_SAP_MODE ||
|
||||
dp_intf->device_mode == QDF_P2P_GO_MODE) {
|
||||
status = qdf_event_destroy(&dp_intf->qdf_sta_eap_frm_done_event);
|
||||
if (!QDF_IS_STATUS_SUCCESS(status)) {
|
||||
dp_err("eap frm done event destroy failed!!");
|
||||
return status;
|
||||
}
|
||||
dp_intf->txrx_ops.tx.tx = NULL;
|
||||
dp_intf->sap_tx_block_mask |= DP_TX_FN_CLR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change this to link level, since during link switch,
|
||||
* it might not go to 0
|
||||
*/
|
||||
status = dp_intf_wait_for_task_complete(dp_intf);
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
return status;
|
||||
|
||||
if (dp_intf->device_mode == QDF_SAP_MODE ||
|
||||
dp_intf->device_mode == QDF_P2P_GO_MODE) {
|
||||
status = qdf_event_destroy(&dp_intf->qdf_sta_eap_frm_done_event);
|
||||
if (!QDF_IS_STATUS_SUCCESS(status)) {
|
||||
dp_err("eap frm done event destroy failed!!");
|
||||
return status;
|
||||
}
|
||||
dp_intf->txrx_ops.tx.tx = NULL;
|
||||
dp_intf->sap_tx_block_mask |= DP_TX_FN_CLR;
|
||||
}
|
||||
qdf_mem_zero(&dp_intf->conn_info, sizeof(struct wlan_dp_conn_info));
|
||||
dp_intf->intf_id = WLAN_UMAC_VDEV_ID_MAX;
|
||||
qdf_spin_lock_bh(&dp_intf->vdev_lock);
|
||||
dp_intf->vdev = NULL;
|
||||
qdf_spin_unlock_bh(&dp_intf->vdev_lock);
|
||||
|
||||
status = wlan_objmgr_vdev_component_obj_detach(vdev,
|
||||
WLAN_COMP_DP,
|
||||
(void *)dp_intf);
|
||||
(void *)dp_link);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
dp_err("Failed to detach dp_intf with vdev");
|
||||
dp_err("Failed to detach dp_link with vdev");
|
||||
return status;
|
||||
}
|
||||
|
||||
qdf_mem_free(dp_link);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@@ -120,6 +120,7 @@ ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc,
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
dp_intf->def_link = NULL;
|
||||
dp_intf->dp_ctx = dp_ctx;
|
||||
dp_intf->dev = ndev;
|
||||
dp_intf->intf_id = WLAN_UMAC_VDEV_ID_MAX;
|
||||
@@ -130,6 +131,9 @@ ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc,
|
||||
qdf_list_insert_front(&dp_ctx->intf_list, &dp_intf->node);
|
||||
qdf_spin_unlock_bh(&dp_ctx->intf_list_lock);
|
||||
|
||||
qdf_spinlock_create(&dp_intf->dp_link_list_lock);
|
||||
qdf_list_create(&dp_intf->dp_link_list, 0);
|
||||
|
||||
dp_periodic_sta_stats_init(dp_intf);
|
||||
dp_periodic_sta_stats_mutex_create(dp_intf);
|
||||
dp_nud_init_tracking(dp_intf);
|
||||
@@ -167,6 +171,9 @@ ucfg_dp_destroy_intf(struct wlan_objmgr_psoc *psoc,
|
||||
dp_mic_deinit_work(dp_intf);
|
||||
qdf_spinlock_destroy(&dp_intf->vdev_lock);
|
||||
|
||||
qdf_spinlock_destroy(&dp_intf->dp_link_list_lock);
|
||||
qdf_list_destroy(&dp_intf->dp_link_list);
|
||||
|
||||
qdf_spin_lock_bh(&dp_ctx->intf_list_lock);
|
||||
qdf_list_remove_node(&dp_ctx->intf_list, &dp_intf->node);
|
||||
qdf_spin_unlock_bh(&dp_ctx->intf_list_lock);
|
||||
|
新增問題並參考
封鎖使用者