diff --git a/dp/inc/cdp_txrx_cmn.h b/dp/inc/cdp_txrx_cmn.h index d24748b17a8a..af49b04f0b1e 100644 --- a/dp/inc/cdp_txrx_cmn.h +++ b/dp/inc/cdp_txrx_cmn.h @@ -133,7 +133,7 @@ static inline QDF_STATUS cdp_flow_pool_map(ol_txrx_soc_handle soc, { if (!soc || !soc->ops) { QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); + "%s: Invalid Instance:", __func__); QDF_BUG(0); return QDF_STATUS_E_INVAL; } @@ -334,43 +334,147 @@ static inline void cdp_peer_setup peer); } -static inline void *cdp_peer_ast_hash_find_soc - (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr) +/** + * cdp_peer_get_ast_info_by_soc() - search the soc AST hash table + * and return ast entry information + * of first ast entry found in the + * table with given mac address + * + * @soc - data path soc handle + * @ast_mac_addr - AST entry mac address + * @ast_entry_info - ast entry information + * + * return - true if ast entry found with ast_mac_addr + * false if ast entry not found + */ +static inline bool cdp_peer_get_ast_info_by_soc + (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, + struct cdp_ast_entry_info *ast_entry_info) { if (!soc || !soc->ops) { QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, "%s: Invalid Instance:", __func__); QDF_BUG(0); - return NULL; + return false; } if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_hash_find_soc) - return NULL; + !soc->ops->cmn_drv_ops->txrx_peer_get_ast_info_by_soc) + return false; - return soc->ops->cmn_drv_ops->txrx_peer_ast_hash_find_soc(soc, - ast_mac_addr); + return soc->ops->cmn_drv_ops->txrx_peer_get_ast_info_by_soc + (soc, ast_mac_addr, + ast_entry_info); } -static inline void *cdp_peer_ast_hash_find_by_pdevid +/** + * cdp_peer_get_ast_info_by_pdev() - search the soc AST hash table + * and return ast entry information + * if mac address and pdev_id matches + * + * @soc - data path soc handle + * @ast_mac_addr - AST entry mac address + * @pdev_id - pdev_id + * @ast_entry_info - ast entry information + * + * return - true if ast entry found with ast_mac_addr + * false if ast entry not found + */ +static inline bool cdp_peer_get_ast_info_by_pdev (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, - uint8_t pdev_id) + uint8_t pdev_id, + struct cdp_ast_entry_info *ast_entry_info) { if (!soc || !soc->ops) { QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, "%s: Invalid Instance:", __func__); QDF_BUG(0); - return NULL; + return false; } if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_hash_find_by_pdevid) - return NULL; + !soc->ops->cmn_drv_ops->txrx_peer_get_ast_info_by_pdev) + return false; - return soc->ops->cmn_drv_ops->txrx_peer_ast_hash_find_by_pdevid + return soc->ops->cmn_drv_ops->txrx_peer_get_ast_info_by_pdev (soc, ast_mac_addr, - pdev_id); + pdev_id, + ast_entry_info); +} + +/** + * cdp_peer_ast_delete_by_soc() - delete the ast entry from soc AST hash table + * with given mac address + * + * @soc - data path soc handle + * @ast_mac_addr - AST entry mac address + * @callback - callback function to called on ast delete response from FW + * @cookie - argument to be passed to callback + * + * return - QDF_STATUS_SUCCESS if ast entry found with ast_mac_addr and delete + * is sent + * QDF_STATUS_E_INVAL false if ast entry not found + */ +static inline QDF_STATUS cdp_peer_ast_delete_by_soc + (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, + txrx_ast_free_cb callback, + void *cookie) +{ + if (!soc || !soc->ops) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance:", __func__); + QDF_BUG(0); + return QDF_STATUS_E_INVAL; + } + + if (!soc->ops->cmn_drv_ops || + !soc->ops->cmn_drv_ops->txrx_peer_ast_delete_by_soc) + return QDF_STATUS_E_INVAL; + + return soc->ops->cmn_drv_ops->txrx_peer_ast_delete_by_soc + (soc, + ast_mac_addr, + callback, + cookie); +} + +/** + * cdp_peer_ast_delete_by_pdev() - delete the ast entry from soc AST hash table + * if mac address and pdev_id matches + * + * @soc - data path soc handle + * @ast_mac_addr - AST entry mac address + * @pdev_id - pdev id + * @callback - callback function to called on ast delete response from FW + * @cookie - argument to be passed to callback + * + * return - QDF_STATUS_SUCCESS if ast entry found with ast_mac_addr and delete + * is sent + * QDF_STATUS_E_INVAL false if ast entry not found + */ +static inline QDF_STATUS cdp_peer_ast_delete_by_pdev + (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, + uint8_t pdev_id, txrx_ast_free_cb callback, + void *cookie) +{ + if (!soc || !soc->ops) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance:", __func__); + QDF_BUG(0); + return QDF_STATUS_E_INVAL; + } + + if (!soc->ops->cmn_drv_ops || + !soc->ops->cmn_drv_ops->txrx_peer_ast_delete_by_pdev) + return QDF_STATUS_E_INVAL; + + return soc->ops->cmn_drv_ops->txrx_peer_ast_delete_by_pdev + (soc, + ast_mac_addr, + pdev_id, + callback, + cookie); } static inline int cdp_peer_add_ast @@ -468,213 +572,6 @@ static inline int cdp_peer_update_ast flags); } -static inline void cdp_peer_del_ast - (ol_txrx_soc_handle soc, void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); - QDF_BUG(0); - return; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_del_ast) - return; - - soc->ops->cmn_drv_ops->txrx_peer_del_ast(soc, ast_handle); -} - - -static inline uint8_t cdp_peer_ast_get_pdev_id - (ol_txrx_soc_handle soc, void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); - QDF_BUG(0); - return 0xff; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_get_pdev_id) - return 0xff; - - return soc->ops->cmn_drv_ops->txrx_peer_ast_get_pdev_id(soc, - ast_handle); -} - -static inline uint8_t cdp_peer_ast_get_next_hop - (ol_txrx_soc_handle soc, void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); - QDF_BUG(0); - return 0xff; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_get_next_hop) - return 0xff; - - return soc->ops->cmn_drv_ops->txrx_peer_ast_get_next_hop(soc, - ast_handle); -} - -/** - * cdp_peer_ast_get_type() - Return type (Static, WDS, MEC) of AST entry - * @soc: DP SoC handle - * @ast_handle: Opaque handle to AST entry - * - * Return: AST entry type (Static/WDS/MEC) - */ -static inline enum cdp_txrx_ast_entry_type cdp_peer_ast_get_type - (ol_txrx_soc_handle soc, void *ast_handle) - -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); - QDF_BUG(0); - return 0; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_get_type) - return 0; - - return soc->ops->cmn_drv_ops->txrx_peer_ast_get_type(soc, ast_handle); -} - -static inline void cdp_peer_ast_set_type - (ol_txrx_soc_handle soc, void *ast_handle, - enum cdp_txrx_ast_entry_type type) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); - QDF_BUG(0); - return; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_set_type) - return; - - soc->ops->cmn_drv_ops->txrx_peer_ast_set_type(soc, ast_handle, type); -} - -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) -static inline void cdp_peer_ast_set_cp_ctx(struct cdp_soc_t *soc, - void *ast_handle, - void *cp_ctx) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "Invalid Instance:"); - QDF_BUG(0); - return; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_set_cp_ctx) - return; - - soc->ops->cmn_drv_ops->txrx_peer_ast_set_cp_ctx(soc, ast_handle, - cp_ctx); -} - -static inline void *cdp_peer_ast_get_cp_ctx(struct cdp_soc_t *soc, - void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "Invalid Instance:"); - QDF_BUG(0); - return NULL; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_get_cp_ctx) - return NULL; - - return soc->ops->cmn_drv_ops->txrx_peer_ast_get_cp_ctx(soc, ast_handle); -} - -static inline bool cdp_peer_ast_get_wmi_sent(struct cdp_soc_t *soc, - void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "Invalid Instance:"); - QDF_BUG(0); - return false; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_get_wmi_sent) - return false; - - return soc->ops->cmn_drv_ops->txrx_peer_ast_get_wmi_sent(soc, - ast_handle); -} - -static inline -void cdp_peer_ast_free_entry(struct cdp_soc_t *soc, - void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "Invalid Instance:"); - QDF_BUG(0); - return; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_free_entry) - return; - - soc->ops->cmn_drv_ops->txrx_peer_ast_free_entry(soc, ast_handle); -} -#endif - -static inline struct cdp_peer *cdp_peer_ast_get_peer - (ol_txrx_soc_handle soc, void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); - QDF_BUG(0); - return NULL; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_get_peer) - return NULL; - - return soc->ops->cmn_drv_ops->txrx_peer_ast_get_peer(soc, ast_handle); -} - -static inline uint32_t cdp_peer_ast_get_nexthop_peer_id - (ol_txrx_soc_handle soc, void *ast_handle) -{ - if (!soc || !soc->ops) { - QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, - "%s: Invalid Instance:", __func__); - QDF_BUG(0); - return CDP_INVALID_PEER; - } - - if (!soc->ops->cmn_drv_ops || - !soc->ops->cmn_drv_ops->txrx_peer_ast_get_nexthop_peer_id) - return CDP_INVALID_PEER; - - return soc->ops->cmn_drv_ops->txrx_peer_ast_get_nexthop_peer_id - (soc, - ast_handle); -} - static inline void cdp_peer_teardown (ol_txrx_soc_handle soc, struct cdp_vdev *vdev, void *peer) { diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index af6eaef95cfc..b6e91db21d96 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -328,6 +328,50 @@ enum cdp_txrx_ast_entry_type { CDP_TXRX_AST_TYPE_MAX }; +/* + * cdp_ast_free_status: status passed to callback function before freeing ast + * @CDP_TXRX_AST_DELETED - AST is deleted from FW and delete response received + * @CDP_TXRX_AST_DELETE_IN_PROGRESS - AST delete command sent to FW and host + * is waiting for FW response + */ +enum cdp_ast_free_status { + CDP_TXRX_AST_DELETED, + CDP_TXRX_AST_DELETE_IN_PROGRESS, +}; + +/** + * txrx_ast_free_cb - callback registered for ast free + * @ctrl_soc: control path soc context + * @cdp_soc: DP soc context + * @cookie: cookie + * @cdp_ast_free_status: ast free status + */ +typedef void (*txrx_ast_free_cb)(void *ctrl_soc, + void *cdp_soc, + void *cookie, + enum cdp_ast_free_status); + +#define CDP_MAC_ADDR_LEN 6 + +/** + * struct cdp_ast_entry_info - AST entry information + * @peer_mac_addr: mac address of peer on which AST entry is added + * @type: ast entry type + * @vdev_id: vdev_id + * @pdev_id: pdev_id + * @peer_id: peer_id + * + * This structure holds the ast entry information + * + */ +struct cdp_ast_entry_info { + uint8_t peer_mac_addr[CDP_MAC_ADDR_LEN]; + enum cdp_txrx_ast_entry_type type; + uint8_t vdev_id; + uint8_t pdev_id; + uint16_t peer_id; +}; + /** * struct cdp_sec_type - security type information */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 5682b7847f95..2b5d9ee91400 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -107,52 +107,29 @@ struct cdp_cmn_ops { uint8_t *mac_addr, enum cdp_txrx_ast_entry_type type, uint32_t flags); - void (*txrx_peer_del_ast) - (ol_txrx_soc_handle soc, void *ast_hdl); - int (*txrx_peer_update_ast) (ol_txrx_soc_handle soc, struct cdp_peer *peer_hdl, uint8_t *mac_addr, uint32_t flags); - void *(*txrx_peer_ast_hash_find_soc) - (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr); - - void *(*txrx_peer_ast_hash_find_by_pdevid) + bool (*txrx_peer_get_ast_info_by_soc) (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, - uint8_t pdev_id); + struct cdp_ast_entry_info *ast_entry_info); - uint8_t (*txrx_peer_ast_get_pdev_id) - (ol_txrx_soc_handle soc, void *ast_hdl); + bool (*txrx_peer_get_ast_info_by_pdev) + (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, + uint8_t pdev_id, + struct cdp_ast_entry_info *ast_entry_info); - uint8_t (*txrx_peer_ast_get_next_hop) - (ol_txrx_soc_handle soc, void *ast_hdl); + QDF_STATUS (*txrx_peer_ast_delete_by_soc) + (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, + txrx_ast_free_cb callback, + void *cookie); - void (*txrx_peer_ast_set_type) - (ol_txrx_soc_handle soc, void *ast_hdl, - enum cdp_txrx_ast_entry_type type); -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) - void (*txrx_peer_ast_set_cp_ctx)(ol_txrx_soc_handle soc, - void *ast_entry, - void *cp_ctx); - - void * (*txrx_peer_ast_get_cp_ctx)(ol_txrx_soc_handle soc, - void *ast_entry); - - bool (*txrx_peer_ast_get_wmi_sent)(ol_txrx_soc_handle soc, - void *ast_entry); - - void (*txrx_peer_ast_free_entry)(ol_txrx_soc_handle soc, - void *ast_entry); -#endif - - enum cdp_txrx_ast_entry_type (*txrx_peer_ast_get_type) - (ol_txrx_soc_handle soc, void *ast_hdl); - - struct cdp_peer* (*txrx_peer_ast_get_peer) - (ol_txrx_soc_handle soc, void *ast_hdl); - - uint32_t (*txrx_peer_ast_get_nexthop_peer_id) - (ol_txrx_soc_handle soc, void *ast_hdl); + QDF_STATUS (*txrx_peer_ast_delete_by_pdev) + (ol_txrx_soc_handle soc, uint8_t *ast_mac_addr, + uint8_t pdev_id, + txrx_ast_free_cb callback, + void *cookie); void (*txrx_peer_delete)(void *peer, uint32_t bitmap); @@ -887,9 +864,6 @@ struct ol_if_ops { uint32_t flags); void (*peer_del_wds_entry)(void *ol_soc_handle, uint8_t *wds_macaddr); -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) - void (*peer_del_wds_cp_ctx)(void *cp_ctx); -#endif QDF_STATUS (*lro_hash_config)(struct cdp_ctrl_objmgr_pdev *ctrl_pdev, struct cdp_lro_hash_config *rx_offld_hash); diff --git a/dp/wifi3.0/dp_htt.c b/dp/wifi3.0/dp_htt.c index 466227c0301b..8949a473c78f 100644 --- a/dp/wifi3.0/dp_htt.c +++ b/dp/wifi3.0/dp_htt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -2965,11 +2965,12 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) { u_int16_t peer_id; u_int8_t vdev_id; + u_int8_t mac_addr[HTT_MAC_ADDR_LEN] = {0}; peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); vdev_id = HTT_RX_PEER_UNMAP_VDEV_ID_GET(*msg_word); dp_rx_peer_unmap_handler(soc->dp_soc, peer_id, - vdev_id, NULL, 0); + vdev_id, mac_addr, 0); break; } case HTT_T2H_MSG_TYPE_SEC_IND: @@ -3112,7 +3113,7 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) case HTT_T2H_MSG_TYPE_PEER_UNMAP_V2: { u_int8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN]; - u_int8_t *peer_mac_addr; + u_int8_t *mac_addr; u_int16_t peer_id; u_int8_t vdev_id; u_int8_t is_wds; @@ -3120,7 +3121,7 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) peer_id = HTT_RX_PEER_UNMAP_V2_SW_PEER_ID_GET(*msg_word); vdev_id = HTT_RX_PEER_UNMAP_V2_VDEV_ID_GET(*msg_word); - peer_mac_addr = + mac_addr = htt_t2h_mac_addr_deswizzle((u_int8_t *)(msg_word + 1), &mac_addr_deswizzle_buf[0]); is_wds = @@ -3131,7 +3132,7 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) peer_id, vdev_id); dp_rx_peer_unmap_handler(soc->dp_soc, peer_id, - vdev_id, peer_mac_addr, + vdev_id, mac_addr, is_wds); break; } diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 30cab8aea1e7..4ecd6c8e6b9b 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -523,17 +523,6 @@ static int dp_peer_add_ast_wifi3(struct cdp_soc_t *soc_hdl, flags); } -static void dp_peer_del_ast_wifi3(struct cdp_soc_t *soc_hdl, - void *ast_entry_hdl) -{ - struct dp_soc *soc = (struct dp_soc *)soc_hdl; - qdf_spin_lock_bh(&soc->ast_lock); - dp_peer_del_ast((struct dp_soc *)soc_hdl, - (struct dp_ast_entry *)ast_entry_hdl); - qdf_spin_unlock_bh(&soc->ast_lock); -} - - static int dp_peer_update_ast_wifi3(struct cdp_soc_t *soc_hdl, struct cdp_peer *peer_hdl, uint8_t *wds_macaddr, @@ -668,128 +657,208 @@ static void dp_wds_flush_ast_table_wifi3(struct cdp_soc_t *soc_hdl) qdf_spin_unlock_bh(&soc->ast_lock); } -static void *dp_peer_ast_hash_find_soc_wifi3(struct cdp_soc_t *soc_hdl, - uint8_t *ast_mac_addr) +/** + * dp_peer_get_ast_info_by_soc_wifi3() - search the soc AST hash table + * and return ast entry information + * of first ast entry found in the + * table with given mac address + * + * @soc : data path soc handle + * @ast_mac_addr : AST entry mac address + * @ast_entry_info : ast entry information + * + * return : true if ast entry found with ast_mac_addr + * false if ast entry not found + */ +static bool dp_peer_get_ast_info_by_soc_wifi3 + (struct cdp_soc_t *soc_hdl, + uint8_t *ast_mac_addr, + struct cdp_ast_entry_info *ast_entry_info) { struct dp_ast_entry *ast_entry; struct dp_soc *soc = (struct dp_soc *)soc_hdl; qdf_spin_lock_bh(&soc->ast_lock); + ast_entry = dp_peer_ast_hash_find_soc(soc, ast_mac_addr); + + if (ast_entry && !ast_entry->delete_in_progress) { + ast_entry_info->type = ast_entry->type; + ast_entry_info->pdev_id = ast_entry->pdev_id; + ast_entry_info->vdev_id = ast_entry->vdev_id; + ast_entry_info->peer_id = ast_entry->peer->peer_ids[0]; + qdf_mem_copy(&ast_entry_info->peer_mac_addr[0], + &ast_entry->peer->mac_addr.raw[0], + DP_MAC_ADDR_LEN); + qdf_spin_unlock_bh(&soc->ast_lock); + return true; + } + qdf_spin_unlock_bh(&soc->ast_lock); - return (void *)ast_entry; + return false; } -static void *dp_peer_ast_hash_find_by_pdevid_wifi3(struct cdp_soc_t *soc_hdl, - uint8_t *ast_mac_addr, - uint8_t pdev_id) +/** + * dp_peer_get_ast_info_by_pdevid_wifi3() - search the soc AST hash table + * and return ast entry information + * if mac address and pdev_id matches + * + * @soc : data path soc handle + * @ast_mac_addr : AST entry mac address + * @pdev_id : pdev_id + * @ast_entry_info : ast entry information + * + * return : true if ast entry found with ast_mac_addr + * false if ast entry not found + */ +static bool dp_peer_get_ast_info_by_pdevid_wifi3 + (struct cdp_soc_t *soc_hdl, + uint8_t *ast_mac_addr, + uint8_t pdev_id, + struct cdp_ast_entry_info *ast_entry_info) { struct dp_ast_entry *ast_entry; struct dp_soc *soc = (struct dp_soc *)soc_hdl; qdf_spin_lock_bh(&soc->ast_lock); + ast_entry = dp_peer_ast_hash_find_by_pdevid(soc, ast_mac_addr, pdev_id); + + if (ast_entry && !ast_entry->delete_in_progress) { + ast_entry_info->type = ast_entry->type; + ast_entry_info->pdev_id = ast_entry->pdev_id; + ast_entry_info->vdev_id = ast_entry->vdev_id; + ast_entry_info->peer_id = ast_entry->peer->peer_ids[0]; + qdf_mem_copy(&ast_entry_info->peer_mac_addr[0], + &ast_entry->peer->mac_addr.raw[0], + DP_MAC_ADDR_LEN); + qdf_spin_unlock_bh(&soc->ast_lock); + return true; + } + qdf_spin_unlock_bh(&soc->ast_lock); - return (void *)ast_entry; + return false; } -static uint8_t dp_peer_ast_get_pdev_id_wifi3(struct cdp_soc_t *soc_hdl, - void *ast_entry_hdl) -{ - return dp_peer_ast_get_pdev_id((struct dp_soc *)soc_hdl, - (struct dp_ast_entry *)ast_entry_hdl); -} +/** + * dp_peer_ast_entry_del_by_soc() - delete the ast entry from soc AST hash table + * with given mac address + * + * @soc : data path soc handle + * @ast_mac_addr : AST entry mac address + * @callback : callback function to called on ast delete response from FW + * @cookie : argument to be passed to callback + * + * return : QDF_STATUS_SUCCESS if ast entry found with ast_mac_addr and delete + * is sent + * QDF_STATUS_E_INVAL false if ast entry not found + */ +static QDF_STATUS dp_peer_ast_entry_del_by_soc(struct cdp_soc_t *soc_handle, + uint8_t *mac_addr, + txrx_ast_free_cb callback, + void *cookie) -static uint8_t dp_peer_ast_get_next_hop_wifi3(struct cdp_soc_t *soc_hdl, - void *ast_entry_hdl) -{ - return dp_peer_ast_get_next_hop((struct dp_soc *)soc_hdl, - (struct dp_ast_entry *)ast_entry_hdl); -} - -static void dp_peer_ast_set_type_wifi3( - struct cdp_soc_t *soc_hdl, - void *ast_entry_hdl, - enum cdp_txrx_ast_entry_type type) -{ - dp_peer_ast_set_type((struct dp_soc *)soc_hdl, - (struct dp_ast_entry *)ast_entry_hdl, - type); -} - -static enum cdp_txrx_ast_entry_type dp_peer_ast_get_type_wifi3( - struct cdp_soc_t *soc_hdl, - void *ast_entry_hdl) -{ - return ((struct dp_ast_entry *)ast_entry_hdl)->type; -} - -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) -void dp_peer_ast_set_cp_ctx_wifi3(struct cdp_soc_t *soc_handle, - void *ast_entry, - void *cp_ctx) { struct dp_soc *soc = (struct dp_soc *)soc_handle; + struct dp_ast_entry *ast_entry; + txrx_ast_free_cb cb = NULL; + void *arg = NULL; qdf_spin_lock_bh(&soc->ast_lock); - dp_peer_ast_set_cp_ctx(soc, - (struct dp_ast_entry *)ast_entry, cp_ctx); + ast_entry = dp_peer_ast_hash_find_soc(soc, mac_addr); + if (!ast_entry) { + qdf_spin_unlock_bh(&soc->ast_lock); + return -QDF_STATUS_E_INVAL; + } + + if (ast_entry->callback) { + cb = ast_entry->callback; + arg = ast_entry->cookie; + } + + ast_entry->callback = callback; + ast_entry->cookie = cookie; + + /* + * if delete_in_progress is set AST delete is sent to target + * and host is waiting for response should not send delete + * again + */ + if (!ast_entry->delete_in_progress) + dp_peer_del_ast(soc, ast_entry); + qdf_spin_unlock_bh(&soc->ast_lock); + if (cb) { + cb(soc->ctrl_psoc, + soc, + arg, + CDP_TXRX_AST_DELETE_IN_PROGRESS); + } + return QDF_STATUS_SUCCESS; } -void *dp_peer_ast_get_cp_ctx_wifi3(struct cdp_soc_t *soc_handle, - void *ast_entry) +/** + * dp_peer_ast_entry_del_by_pdev() - delete the ast entry from soc AST hash + * table if mac address and pdev_id matches + * + * @soc : data path soc handle + * @ast_mac_addr : AST entry mac address + * @pdev_id : pdev id + * @callback : callback function to called on ast delete response from FW + * @cookie : argument to be passed to callback + * + * return : QDF_STATUS_SUCCESS if ast entry found with ast_mac_addr and delete + * is sent + * QDF_STATUS_E_INVAL false if ast entry not found + */ + +static QDF_STATUS dp_peer_ast_entry_del_by_pdev(struct cdp_soc_t *soc_handle, + uint8_t *mac_addr, + uint8_t pdev_id, + txrx_ast_free_cb callback, + void *cookie) + { struct dp_soc *soc = (struct dp_soc *)soc_handle; - void *cp_ctx = NULL; + struct dp_ast_entry *ast_entry; + txrx_ast_free_cb cb = NULL; + void *arg = NULL; qdf_spin_lock_bh(&soc->ast_lock); - cp_ctx = dp_peer_ast_get_cp_ctx(soc, - (struct dp_ast_entry *)ast_entry); + ast_entry = dp_peer_ast_hash_find_by_pdevid(soc, mac_addr, pdev_id); + + if (!ast_entry) { + qdf_spin_unlock_bh(&soc->ast_lock); + return -QDF_STATUS_E_INVAL; + } + + if (ast_entry->callback) { + cb = ast_entry->callback; + arg = ast_entry->cookie; + } + + ast_entry->callback = callback; + ast_entry->cookie = cookie; + + /* + * if delete_in_progress is set AST delete is sent to target + * and host is waiting for response should not sent delete + * again + */ + if (!ast_entry->delete_in_progress) + dp_peer_del_ast(soc, ast_entry); + qdf_spin_unlock_bh(&soc->ast_lock); - return cp_ctx; + if (cb) { + cb(soc->ctrl_psoc, + soc, + arg, + CDP_TXRX_AST_DELETE_IN_PROGRESS); + } + return QDF_STATUS_SUCCESS; } -bool dp_peer_ast_get_wmi_sent_wifi3(struct cdp_soc_t *soc_handle, - void *ast_entry) -{ - struct dp_soc *soc = (struct dp_soc *)soc_handle; - bool wmi_sent = false; - - qdf_spin_lock_bh(&soc->ast_lock); - wmi_sent = dp_peer_ast_get_del_cmd_sent(soc, - (struct dp_ast_entry *) - ast_entry); - qdf_spin_unlock_bh(&soc->ast_lock); - - return wmi_sent; -} - -void dp_peer_ast_free_entry_wifi3(struct cdp_soc_t *soc_handle, - void *ast_entry) -{ - struct dp_soc *soc = (struct dp_soc *)soc_handle; - - qdf_spin_lock_bh(&soc->ast_lock); - dp_peer_ast_free_entry(soc, (struct dp_ast_entry *)ast_entry); - qdf_spin_unlock_bh(&soc->ast_lock); -} -#endif - -static struct cdp_peer *dp_peer_ast_get_peer_wifi3( - struct cdp_soc_t *soc_hdl, - void *ast_entry_hdl) -{ - return (struct cdp_peer *)((struct dp_ast_entry *)ast_entry_hdl)->peer; -} - -static uint32_t dp_peer_ast_get_nexhop_peer_id_wifi3( - struct cdp_soc_t *soc_hdl, - void *ast_entry_hdl) -{ - return ((struct dp_ast_entry *)ast_entry_hdl)->peer->peer_ids[0]; -} /** * dp_srng_find_ring_in_mask() - find which ext_group a ring belongs * @ring_num: ring num of the ring being queried @@ -952,7 +1021,7 @@ static void dp_srng_msi_setup(struct dp_soc *soc, struct hal_srng_params * return void */ #ifdef FEATURE_AST -static void dp_print_ast_stats(struct dp_soc *soc) +void dp_print_ast_stats(struct dp_soc *soc) { uint8_t i; uint8_t num_entries = 0; @@ -979,27 +1048,29 @@ static void dp_print_ast_stats(struct dp_soc *soc) DP_PEER_ITERATE_ASE_LIST(peer, ase, tmp_ase) { DP_PRINT_STATS("%6d mac_addr = %pM" " peer_mac_addr = %pM" + " peer_id = %u" " type = %s" " next_hop = %d" " is_active = %d" " is_bss = %d" " ast_idx = %d" " ast_hash = %d" + " delete_in_progress = %d" " pdev_id = %d" - " vdev_id = %d" - " del_cmd_sent = %d", + " vdev_id = %d", ++num_entries, ase->mac_addr.raw, ase->peer->mac_addr.raw, + ase->peer->peer_ids[0], type[ase->type], ase->next_hop, ase->is_active, ase->is_bss, ase->ast_idx, ase->ast_hash_value, + ase->delete_in_progress, ase->pdev_id, - ase->vdev_id, - ase->del_cmd_sent); + ase->vdev_id); } } } @@ -1008,7 +1079,7 @@ static void dp_print_ast_stats(struct dp_soc *soc) qdf_spin_unlock_bh(&soc->ast_lock); } #else -static void dp_print_ast_stats(struct dp_soc *soc) +void dp_print_ast_stats(struct dp_soc *soc) { DP_PRINT_STATS("AST Stats not available.Enable FEATURE_AST"); return; @@ -1031,15 +1102,18 @@ static void dp_print_peer_table(struct dp_vdev *vdev) DP_PRINT_STATS("Invalid Peer"); return; } - DP_PRINT_STATS(" peer_mac_addr = %pM nawds_enabled = %d", + DP_PRINT_STATS(" peer_mac_addr = %pM" + " nawds_enabled = %d" + " bss_peer = %d" + " wapi = %d" + " wds_enabled = %d" + " delete in progress = %d" + " peer id = %d", peer->mac_addr.raw, - peer->nawds_enabled); - DP_PRINT_STATS(" bss_peer = %d wapi = %d wds_enabled = %d", + peer->nawds_enabled, peer->bss_peer, peer->wapi, - peer->wds_enabled); - - DP_PRINT_STATS(" delete in progress = %d peer id = %d", + peer->wds_enabled, peer->delete_in_progress, peer->peer_ids[0]); } @@ -4322,9 +4396,10 @@ static void dp_vdev_flush_peers(struct dp_vdev *vdev) * */ dp_peer_unref_del_find_by_id(peer); + dp_rx_peer_unmap_handler(soc, peer_ids[i], + vdev->vdev_id, + peer->mac_addr.raw, 0); } - dp_rx_peer_unmap_handler(soc, peer_ids[i], vdev->vdev_id, - NULL, 0); } qdf_mem_free(peer_ids); @@ -4439,7 +4514,6 @@ static inline void dp_peer_delete_ast_entries(struct dp_soc *soc, dp_peer_del_ast(soc, ast_entry); peer->self_ast_entry = NULL; - TAILQ_INIT(&peer->ast_entry_list); qdf_spin_unlock_bh(&soc->ast_lock); } #else @@ -4485,8 +4559,7 @@ static inline struct dp_peer *dp_peer_can_reuse(struct dp_vdev *vdev, } #endif -#if defined(FEATURE_AST) -#if !defined(AST_HKV1_WORKAROUND) +#ifdef FEATURE_AST static inline void dp_peer_ast_handle_roam_del(struct dp_soc *soc, uint8_t *peer_mac_addr) { @@ -4494,29 +4567,12 @@ static inline void dp_peer_ast_handle_roam_del(struct dp_soc *soc, qdf_spin_lock_bh(&soc->ast_lock); ast_entry = dp_peer_ast_hash_find_soc(soc, peer_mac_addr); - if (ast_entry && ast_entry->next_hop) - dp_peer_del_ast(soc, ast_entry); - qdf_spin_unlock_bh(&soc->ast_lock); -} -#else -static inline void dp_peer_ast_handle_roam_del(struct dp_soc *soc, - uint8_t *peer_mac_addr) -{ - struct dp_ast_entry *ast_entry; - if (soc->ast_override_support) { - qdf_spin_lock_bh(&soc->ast_lock); - ast_entry = dp_peer_ast_hash_find_soc(soc, peer_mac_addr); - if (ast_entry && ast_entry->next_hop) - dp_peer_del_ast(soc, ast_entry); - qdf_spin_unlock_bh(&soc->ast_lock); - } -} -#endif -#else -static inline void dp_peer_ast_handle_roam_del(struct dp_soc *soc, - uint8_t *peer_mac_addr) -{ + if (ast_entry && ast_entry->next_hop && + !ast_entry->delete_in_progress) + dp_peer_del_ast(soc, ast_entry); + + qdf_spin_unlock_bh(&soc->ast_lock); } #endif @@ -5082,6 +5138,12 @@ static void dp_reset_and_release_peer_mem(struct dp_soc *soc, } } qdf_spin_unlock_bh(&pdev->vdev_list_lock); + + /* + * Peer AST list hast to be empty here + */ + DP_AST_ASSERT(TAILQ_EMPTY(&peer->ast_entry_list)); + qdf_mem_free(peer); } @@ -8710,9 +8772,9 @@ static void dp_peer_teardown_wifi3(struct cdp_vdev *vdev_hdl, void *peer_hdl) * * Return: 0 for success. nonzero for failure. */ -QDF_STATUS dp_vdev_get_neighbour_rssi(struct cdp_vdev *vdev_hdl, - char *mac_addr, - uint8_t *rssi) +static QDF_STATUS dp_vdev_get_neighbour_rssi(struct cdp_vdev *vdev_hdl, + char *mac_addr, + uint8_t *rssi) { struct dp_vdev *vdev = (struct dp_vdev *)vdev_hdl; struct dp_pdev *pdev = vdev->pdev; @@ -8889,24 +8951,14 @@ static struct cdp_cmn_ops dp_ops_cmn = { .txrx_peer_teardown = NULL, #endif .txrx_peer_add_ast = dp_peer_add_ast_wifi3, - .txrx_peer_del_ast = dp_peer_del_ast_wifi3, .txrx_peer_update_ast = dp_peer_update_ast_wifi3, - .txrx_peer_ast_hash_find_soc = dp_peer_ast_hash_find_soc_wifi3, - .txrx_peer_ast_hash_find_by_pdevid = - dp_peer_ast_hash_find_by_pdevid_wifi3, - .txrx_peer_ast_get_pdev_id = dp_peer_ast_get_pdev_id_wifi3, - .txrx_peer_ast_get_next_hop = dp_peer_ast_get_next_hop_wifi3, - .txrx_peer_ast_set_type = dp_peer_ast_set_type_wifi3, - .txrx_peer_ast_get_type = dp_peer_ast_get_type_wifi3, - .txrx_peer_ast_get_peer = dp_peer_ast_get_peer_wifi3, - .txrx_peer_ast_get_nexthop_peer_id = - dp_peer_ast_get_nexhop_peer_id_wifi3, -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) - .txrx_peer_ast_set_cp_ctx = dp_peer_ast_set_cp_ctx_wifi3, - .txrx_peer_ast_get_cp_ctx = dp_peer_ast_get_cp_ctx_wifi3, - .txrx_peer_ast_get_wmi_sent = dp_peer_ast_get_wmi_sent_wifi3, - .txrx_peer_ast_free_entry = dp_peer_ast_free_entry_wifi3, -#endif + .txrx_peer_get_ast_info_by_soc = dp_peer_get_ast_info_by_soc_wifi3, + .txrx_peer_get_ast_info_by_pdev = + dp_peer_get_ast_info_by_pdevid_wifi3, + .txrx_peer_ast_delete_by_soc = + dp_peer_ast_entry_del_by_soc, + .txrx_peer_ast_delete_by_pdev = + dp_peer_ast_entry_del_by_pdev, .txrx_peer_delete = dp_peer_delete_wifi3, .txrx_vdev_register = dp_vdev_register_wifi3, .txrx_soc_detach = dp_soc_detach_wifi3, diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index fc99903c5f7c..b999eed90ead 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -225,21 +225,30 @@ static int dp_peer_ast_hash_attach(struct dp_soc *soc) return 0; } -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) +/* + * dp_peer_ast_cleanup() - cleanup the references + * @soc: SoC handle + * @ast: ast entry + * + * Return: None + */ static inline void dp_peer_ast_cleanup(struct dp_soc *soc, struct dp_ast_entry *ast) { - struct cdp_soc_t *cdp_soc = &soc->cdp_soc; + txrx_ast_free_cb cb = ast->callback; + void *cookie = ast->cookie; - if (ast->cp_ctx && cdp_soc->ol_ops->peer_del_wds_cp_ctx) - cdp_soc->ol_ops->peer_del_wds_cp_ctx(ast->cp_ctx); + /* Call the callbacks to free up the cookie */ + if (cb) { + ast->callback = NULL; + ast->cookie = NULL; + cb(soc->ctrl_psoc, + soc, + cookie, + CDP_TXRX_AST_DELETE_IN_PROGRESS); + } } -#else -static inline void dp_peer_ast_cleanup(struct dp_soc *soc, - struct dp_ast_entry *ast) -{ -} -#endif + /* * dp_peer_ast_hash_detach() - Free AST Hash table * @soc: SoC handle @@ -254,6 +263,7 @@ static void dp_peer_ast_hash_detach(struct dp_soc *soc) if (!soc->ast_hash.mask) return; + qdf_spin_lock_bh(&soc->ast_lock); for (index = 0; index <= soc->ast_hash.mask; index++) { if (!TAILQ_EMPTY(&soc->ast_hash.bins[index])) { TAILQ_FOREACH_SAFE(ast, &soc->ast_hash.bins[index], @@ -265,6 +275,7 @@ static void dp_peer_ast_hash_detach(struct dp_soc *soc) } } } + qdf_spin_unlock_bh(&soc->ast_lock); qdf_mem_free(soc->ast_hash.bins); } @@ -485,17 +496,32 @@ static inline void dp_peer_map_ast(struct dp_soc *soc, return; } -#ifdef AST_HKV1_WORKAROUND -static inline void -dp_peer_ast_init_del_cmd_sent_flag(struct dp_ast_entry *ast_entry) +void dp_peer_free_hmwds_cb(void *ctrl_psoc, + void *dp_soc, + void *cookie, + enum cdp_ast_free_status status) { - ast_entry->del_cmd_sent = false; + struct dp_ast_free_cb_params *param = + (struct dp_ast_free_cb_params *)cookie; + struct dp_soc *soc = (struct dp_soc *)dp_soc; + struct dp_peer *peer = NULL; + + if (status != CDP_TXRX_AST_DELETED) { + qdf_mem_free(cookie); + return; + } + + peer = dp_peer_find_hash_find(soc, ¶m->peer_mac_addr.raw[0], + 0, param->vdev_id); + if (peer) { + dp_peer_add_ast(soc, peer, + ¶m->mac_addr.raw[0], + param->type, + param->flags); + dp_peer_unref_delete(peer); + } + qdf_mem_free(cookie); } -#else -static inline void -dp_peer_ast_init_del_cmd_sent_flag(struct dp_ast_entry *ast_entry) -{} -#endif /* * dp_peer_add_ast() - Allocate and add AST entry into peer list @@ -516,33 +542,22 @@ int dp_peer_add_ast(struct dp_soc *soc, enum cdp_txrx_ast_entry_type type, uint32_t flags) { - struct dp_ast_entry *ast_entry; + struct dp_ast_entry *ast_entry = NULL; struct dp_vdev *vdev = NULL; struct dp_pdev *pdev = NULL; uint8_t next_node_mac[6]; - bool peer_ref_cnt = false; int ret = -1; + txrx_ast_free_cb cb = NULL; + void *cookie = NULL; if (peer->delete_in_progress) - return 0; - - if (type != CDP_TXRX_AST_TYPE_STATIC && - type != CDP_TXRX_AST_TYPE_SELF) { - peer_ref_cnt = true; - qdf_spin_lock_bh(&soc->peer_ref_mutex); - qdf_atomic_inc(&peer->ref_cnt); - qdf_spin_unlock_bh(&soc->peer_ref_mutex); - } + return ret; vdev = peer->vdev; if (!vdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, FL("Peers vdev is NULL")); QDF_ASSERT(0); - /*Handling case when assert is disabled*/ - if (peer_ref_cnt) - dp_peer_unref_delete(peer); - return ret; } @@ -555,15 +570,6 @@ int dp_peer_add_ast(struct dp_soc *soc, qdf_spin_lock_bh(&soc->ast_lock); - /* For HMWDS and HWMWDS_SEC entries can be added for same mac address - * do not check for existing entry - * SON takes care of deleting any existing AST entry with other types - * before adding HMWDS entries - */ - if ((type == CDP_TXRX_AST_TYPE_WDS_HM) || - (type == CDP_TXRX_AST_TYPE_WDS_HM_SEC)) - goto add_ast_entry; - /* If AST entry already exists , just return from here * ast entry with same mac address can exist on different radios * if ast_override support is enabled use search by pdev in this @@ -574,17 +580,72 @@ int dp_peer_add_ast(struct dp_soc *soc, pdev->pdev_id); if (ast_entry) { qdf_spin_unlock_bh(&soc->ast_lock); - if (peer_ref_cnt) - dp_peer_unref_delete(peer); return 0; } } else { + /* For HWMWDS_SEC entries can be added for same mac address + * do not check for existing entry + */ + if (type == CDP_TXRX_AST_TYPE_WDS_HM_SEC) + goto add_ast_entry; + ast_entry = dp_peer_ast_hash_find_soc(soc, mac_addr); if (ast_entry) { if (ast_entry->type == CDP_TXRX_AST_TYPE_MEC) ast_entry->is_active = TRUE; + if ((ast_entry->type == CDP_TXRX_AST_TYPE_WDS_HM) && + !ast_entry->delete_in_progress) { + qdf_spin_unlock_bh(&soc->ast_lock); + return 0; + } + + /* Add for HMWDS entry we cannot be ignored if there + * is AST entry with same mac address + * + * if ast entry exists with the requested mac address + * send a delete command and register callback which + * can take care of adding HMWDS ast enty on delete + * confirmation from target + */ + if ((type == CDP_TXRX_AST_TYPE_WDS_HM) && + soc->is_peer_map_unmap_v2) { + struct dp_ast_free_cb_params *param = NULL; + + if (ast_entry->type == + CDP_TXRX_AST_TYPE_WDS_HM_SEC) + goto add_ast_entry; + + /* save existing callback */ + if (ast_entry->callback) { + cb = ast_entry->callback; + cookie = ast_entry->cookie; + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Allocation failed"); + qdf_spin_unlock_bh(&soc->ast_lock); + return ret; + } + + qdf_mem_copy(¶m->mac_addr.raw[0], mac_addr, + DP_MAC_ADDR_LEN); + qdf_mem_copy(¶m->peer_mac_addr.raw[0], + &peer->mac_addr.raw[0], + DP_MAC_ADDR_LEN); + param->type = type; + param->flags = flags; + param->vdev_id = vdev->vdev_id; + ast_entry->callback = dp_peer_free_hmwds_cb; + ast_entry->cookie = (void *)param; + if (!ast_entry->delete_in_progress) + dp_peer_del_ast(soc, ast_entry); + } + /* Modify an already existing AST entry from type * WDS to MEC on promption. This serves as a fix when * backbone of interfaces are interchanged wherein @@ -602,8 +663,12 @@ int dp_peer_add_ast(struct dp_soc *soc, dp_peer_del_ast(soc, ast_entry); } qdf_spin_unlock_bh(&soc->ast_lock); - if (peer_ref_cnt) - dp_peer_unref_delete(peer); + + /* Call the saved callback*/ + if (cb) { + cb(soc->ctrl_psoc, soc, cookie, + CDP_TXRX_AST_DELETE_IN_PROGRESS); + } return 0; } } @@ -614,8 +679,6 @@ add_ast_entry: if (!ast_entry) { qdf_spin_unlock_bh(&soc->ast_lock); - if (peer_ref_cnt) - dp_peer_unref_delete(peer); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, FL("fail to allocate ast_entry")); QDF_ASSERT(0); @@ -623,11 +686,10 @@ add_ast_entry: } qdf_mem_copy(&ast_entry->mac_addr.raw[0], mac_addr, DP_MAC_ADDR_LEN); - ast_entry->peer = peer; ast_entry->pdev_id = vdev->pdev->pdev_id; ast_entry->vdev_id = vdev->vdev_id; ast_entry->is_mapped = false; - dp_peer_ast_init_del_cmd_sent_flag(ast_entry); + ast_entry->delete_in_progress = false; switch (type) { case CDP_TXRX_AST_TYPE_STATIC: @@ -657,7 +719,7 @@ add_ast_entry: ast_entry->type = CDP_TXRX_AST_TYPE_MEC; break; case CDP_TXRX_AST_TYPE_DA: - ast_entry->peer = peer->vdev->vap_bss_peer; + peer = peer->vdev->vap_bss_peer; ast_entry->next_hop = 1; ast_entry->type = CDP_TXRX_AST_TYPE_DA; break; @@ -667,17 +729,19 @@ add_ast_entry: } ast_entry->is_active = TRUE; - TAILQ_INSERT_TAIL(&peer->ast_entry_list, ast_entry, ase_list_elem); DP_STATS_INC(soc, ast.added, 1); dp_peer_ast_hash_add(soc, ast_entry); - qdf_spin_unlock_bh(&soc->ast_lock); - if (ast_entry->type == CDP_TXRX_AST_TYPE_MEC || - ast_entry->type == CDP_TXRX_AST_TYPE_DA) + ast_entry->peer = peer; + + if (type == CDP_TXRX_AST_TYPE_MEC) qdf_mem_copy(next_node_mac, peer->vdev->mac_addr.raw, 6); else qdf_mem_copy(next_node_mac, peer->mac_addr.raw, 6); + TAILQ_INSERT_TAIL(&peer->ast_entry_list, ast_entry, ase_list_elem); + qdf_spin_unlock_bh(&soc->ast_lock); + if ((ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) && (ast_entry->type != CDP_TXRX_AST_TYPE_SELF) && (ast_entry->type != CDP_TXRX_AST_TYPE_STA_BSS) && @@ -688,60 +752,13 @@ add_ast_entry: (struct cdp_peer *)peer, mac_addr, next_node_mac, - flags)) { - if (peer_ref_cnt) - dp_peer_unref_delete(peer); + flags)) return 0; - } } - if (peer_ref_cnt) - dp_peer_unref_delete(peer); - return ret; } -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) -void dp_peer_del_ast(struct dp_soc *soc, struct dp_ast_entry *ast_entry) -{ - struct dp_peer *peer = ast_entry->peer; - - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_TRACE, - "%s: ast_entry->type: %d pdevid: %u vdev: %u mac_addr: %pM next_hop: %u peer_mac: %pM\n", - __func__, ast_entry->type, peer->vdev->pdev->pdev_id, - peer->vdev->vdev_id, ast_entry->mac_addr.raw, - ast_entry->next_hop, ast_entry->peer->mac_addr.raw); - - if (ast_entry->next_hop && - ast_entry->type != CDP_TXRX_AST_TYPE_WDS_HM_SEC) { - dp_peer_ast_send_wds_del(soc, ast_entry); - } - /* AST free happens in completion handler for HKV1 */ - if (soc->ast_override_support || !ast_entry->del_cmd_sent) { - /* - * release the reference only if it is mapped - * to ast_table - */ - if (ast_entry->is_mapped) - soc->ast_table[ast_entry->ast_idx] = NULL; - - /* ast_entry like next_hop is already removed as part of - * AST del command send, Remove ast_entry that dont - * send ast del command. - */ - if (!ast_entry->del_cmd_sent) - TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, - ase_list_elem); - - if (ast_entry == peer->self_ast_entry) - peer->self_ast_entry = NULL; - - DP_STATS_INC(soc, ast.deleted, 1); - dp_peer_ast_hash_remove(soc, ast_entry); - qdf_mem_free(ast_entry); - } -} -#else /* * dp_peer_del_ast() - Delete and free AST entry * @soc: SoC handle @@ -756,11 +773,34 @@ void dp_peer_del_ast(struct dp_soc *soc, struct dp_ast_entry *ast_entry) void dp_peer_del_ast(struct dp_soc *soc, struct dp_ast_entry *ast_entry) { struct dp_peer *peer = ast_entry->peer; + uint16_t peer_id = peer->peer_ids[0]; - if (ast_entry->next_hop && - ast_entry->type != CDP_TXRX_AST_TYPE_WDS_HM_SEC) - soc->cdp_soc.ol_ops->peer_del_wds_entry(peer->vdev->osif_vdev, - ast_entry->mac_addr.raw); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_TRACE, + "%s: ast_entry->type: %d pdevid: %u vdev: %u mac_addr: %pM next_hop: %u peer_mac: %pM\n", + __func__, ast_entry->type, peer->vdev->pdev->pdev_id, + peer->vdev->vdev_id, ast_entry->mac_addr.raw, + ast_entry->next_hop, ast_entry->peer->mac_addr.raw); + + dp_peer_ast_send_wds_del(soc, ast_entry); + + /* + * if peer map v2 is enabled we are not freeing ast entry + * here and it is supposed to be freed in unmap event (after + * we receive delete confirmation from target) + * + * if peer_id is invalid we did not get the peer map event + * for the peer free ast entry from here only in this case + */ + if (soc->is_peer_map_unmap_v2 && (peer_id != HTT_INVALID_PEER)) { + + /* + * For HM_SEC and SELF type we do not receive unmap event + * free ast_entry from here it self + */ + if ((ast_entry->type != CDP_TXRX_AST_TYPE_WDS_HM_SEC) && + (ast_entry->type != CDP_TXRX_AST_TYPE_SELF)) + return; + } /* * release the reference only if it is mapped @@ -775,9 +815,9 @@ void dp_peer_del_ast(struct dp_soc *soc, struct dp_ast_entry *ast_entry) DP_STATS_INC(soc, ast.deleted, 1); dp_peer_ast_hash_remove(soc, ast_entry); + dp_peer_ast_cleanup(soc, ast_entry); qdf_mem_free(ast_entry); } -#endif /* * dp_peer_update_ast() - Delete and free AST entry @@ -805,6 +845,9 @@ int dp_peer_update_ast(struct dp_soc *soc, struct dp_peer *peer, peer->vdev->vdev_id, flags, ast_entry->mac_addr.raw, peer->mac_addr.raw); + if (ast_entry->delete_in_progress) + return ret; + if ((ast_entry->type == CDP_TXRX_AST_TYPE_STATIC) || (ast_entry->type == CDP_TXRX_AST_TYPE_SELF) || (ast_entry->type == CDP_TXRX_AST_TYPE_STA_BSS) || @@ -943,61 +986,61 @@ uint8_t dp_peer_ast_get_next_hop(struct dp_soc *soc, } #endif -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) -void dp_peer_ast_set_cp_ctx(struct dp_soc *soc, - struct dp_ast_entry *ast_entry, - void *cp_ctx) -{ - ast_entry->cp_ctx = cp_ctx; -} - -void *dp_peer_ast_get_cp_ctx(struct dp_soc *soc, - struct dp_ast_entry *ast_entry) -{ - void *cp_ctx = NULL; - - cp_ctx = ast_entry->cp_ctx; - ast_entry->cp_ctx = NULL; - - return cp_ctx; -} - void dp_peer_ast_send_wds_del(struct dp_soc *soc, struct dp_ast_entry *ast_entry) { struct dp_peer *peer = ast_entry->peer; struct cdp_soc_t *cdp_soc = &soc->cdp_soc; - if (!ast_entry->del_cmd_sent) { + if (ast_entry->delete_in_progress) + return; + + if (ast_entry->next_hop && + ast_entry->type != CDP_TXRX_AST_TYPE_WDS_HM_SEC) cdp_soc->ol_ops->peer_del_wds_entry(peer->vdev->osif_vdev, ast_entry->mac_addr.raw); - ast_entry->del_cmd_sent = true; - TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem); - } + + ast_entry->delete_in_progress = true; } -bool dp_peer_ast_get_del_cmd_sent(struct dp_soc *soc, - struct dp_ast_entry *ast_entry) -{ - return ast_entry->del_cmd_sent; -} - -void dp_peer_ast_free_entry(struct dp_soc *soc, - struct dp_ast_entry *ast_entry) +static void dp_peer_ast_free_entry(struct dp_soc *soc, + struct dp_ast_entry *ast_entry) { + struct dp_peer *peer = ast_entry->peer; + void *cookie = NULL; + txrx_ast_free_cb cb = NULL; /* * release the reference only if it is mapped * to ast_table */ + + qdf_spin_lock_bh(&soc->ast_lock); if (ast_entry->is_mapped) soc->ast_table[ast_entry->ast_idx] = NULL; + TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem); DP_STATS_INC(soc, ast.deleted, 1); dp_peer_ast_hash_remove(soc, ast_entry); + + cb = ast_entry->callback; + cookie = ast_entry->cookie; + ast_entry->callback = NULL; + ast_entry->cookie = NULL; + + if (ast_entry == peer->self_ast_entry) + peer->self_ast_entry = NULL; + + qdf_spin_unlock_bh(&soc->ast_lock); + + if (cb) { + cb(soc->ctrl_psoc, + soc, + cookie, + CDP_TXRX_AST_DELETED); + } qdf_mem_free(ast_entry); } -#endif struct dp_peer *dp_peer_find_hash_find(struct dp_soc *soc, uint8_t *peer_mac_addr, int mac_addr_is_aligned, uint8_t vdev_id) @@ -1284,6 +1327,7 @@ dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, { struct dp_soc *soc = (struct dp_soc *)soc_handle; struct dp_peer *peer = NULL; + enum cdp_txrx_ast_entry_type type = CDP_TXRX_AST_TYPE_STATIC; QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, "peer_map_event (soc:%pK): peer_id %di, hw_peer_id %d, peer_mac " @@ -1323,6 +1367,25 @@ dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, if (peer->vdev->opmode == wlan_op_mode_sta) peer->vdev->bss_ast_hash = ast_hash; + + /* Add ast entry incase self ast entry is + * deleted due to DP CP sync issue + * + * self_ast_entry is modified in peer create + * and peer unmap path which cannot run in + * parllel with peer map, no lock need before + * referring it + */ + if (!peer->self_ast_entry) { + QDF_TRACE(QDF_MODULE_ID_DP, + QDF_TRACE_LEVEL_INFO_HIGH, + "Add self ast from map %pM", + peer_mac_addr); + dp_peer_add_ast(soc, peer, + peer_mac_addr, + type, 0); + } + } } @@ -1335,29 +1398,23 @@ dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, * @soc_handle - genereic soc handle * @peeri_id - peer_id from firmware * @vdev_id - vdev ID - * @peer_mac_addr - mac address of the peer + * @mac_addr - mac address of the peer or wds entry * @is_wds - flag to indicate peer map event for WDS ast entry * * Return: none */ void dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id, - uint8_t vdev_id, uint8_t *peer_mac_addr, + uint8_t vdev_id, uint8_t *mac_addr, uint8_t is_wds) { struct dp_peer *peer; + struct dp_ast_entry *ast_entry; struct dp_soc *soc = (struct dp_soc *)soc_handle; uint8_t i; - if (is_wds) - return; - peer = __dp_peer_find_by_id(soc, peer_id); - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, - "peer_unmap_event (soc:%pK) peer_id %d peer %pK", - soc, peer_id, peer); - /* * Currently peer IDs are assigned for vdevs as well as peers. * If the peer ID is for a vdev, then the peer pointer stored @@ -1370,6 +1427,58 @@ dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id, return; } + /* If V2 Peer map messages are enabled AST entry has to be freed here + */ + if (soc->is_peer_map_unmap_v2) { + + qdf_spin_lock_bh(&soc->ast_lock); + ast_entry = dp_peer_ast_list_find(soc, peer, + mac_addr); + + if (!ast_entry) { + /* in case of qwrap we have multiple BSS peers + * with same mac address + * + * AST entry for this mac address will be created + * only for one peer + */ + if (peer->vdev->proxysta_vdev) { + qdf_spin_unlock_bh(&soc->ast_lock); + goto peer_unmap; + } + + /* Ideally we should not enter this case where + * ast_entry is not present in host table and + * we received a unmap event + */ + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, + "%s:%d AST entry not found with peer %pK peer_id %u peer_mac %pM mac_addr %pM vdev_id %u next_hop %u\n", + __func__, __LINE__, peer, peer->peer_ids[0], + peer->mac_addr.raw, mac_addr, vdev_id, + is_wds); + + if (!is_wds) { + qdf_spin_unlock_bh(&soc->ast_lock); + goto peer_unmap; + } + } + qdf_spin_unlock_bh(&soc->ast_lock); + + /* Reuse the AST entry if delete_in_progress + * not set + */ + if (ast_entry->delete_in_progress) + dp_peer_ast_free_entry(soc, ast_entry); + + if (is_wds) + return; + } + +peer_unmap: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "peer_unmap_event (soc:%pK) peer_id %d peer %pK", + soc, peer_id, peer); + soc->peer_id_to_obj_map[peer_id] = NULL; for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { if (peer->peer_ids[i] == peer_id) { diff --git a/dp/wifi3.0/dp_peer.h b/dp/wifi3.0/dp_peer.h index 8d8d28e73031..7db40d20bbff 100644 --- a/dp/wifi3.0/dp_peer.h +++ b/dp/wifi3.0/dp_peer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -87,6 +87,7 @@ dp_peer_find_by_id(struct dp_soc *soc, } #endif /* PEER_LOCK_REF_PROTECT */ +void dp_print_ast_stats(struct dp_soc *soc); void dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, uint16_t hw_peer_id, uint8_t vdev_id, uint8_t *peer_mac_addr, uint16_t ast_hash, @@ -134,24 +135,13 @@ void dp_peer_ast_set_type(struct dp_soc *soc, struct dp_ast_entry *ast_entry, enum cdp_txrx_ast_entry_type type); -#if defined(FEATURE_AST) && defined(AST_HKV1_WORKAROUND) -void dp_peer_ast_set_cp_ctx(struct dp_soc *soc, - struct dp_ast_entry *ast_entry, - void *cp_ctx); - -void *dp_peer_ast_get_cp_ctx(struct dp_soc *soc, - struct dp_ast_entry *ast_entry); - void dp_peer_ast_send_wds_del(struct dp_soc *soc, struct dp_ast_entry *ast_entry); -bool dp_peer_ast_get_del_cmd_sent(struct dp_soc *soc, - struct dp_ast_entry *ast_entry); - -void dp_peer_ast_free_entry(struct dp_soc *soc, - struct dp_ast_entry *ast_entry); - -#endif +void dp_peer_free_hmwds_cb(void *ctrl_psoc, + void *dp_soc, + void *cookie, + enum cdp_ast_free_status status); /* * dp_get_vdev_from_soc_vdev_id_wifi3() - @@ -198,4 +188,13 @@ dp_get_vdev_from_soc_vdev_id_wifi3(struct dp_soc *soc, * Return: true if peer exists of false otherwise */ bool dp_peer_find_by_id_valid(struct dp_soc *soc, uint16_t peer_id); + +#define DP_AST_ASSERT(_condition) \ + do { \ + if (!(_condition)) { \ + dp_print_ast_stats(soc);\ + QDF_BUG(_condition); \ + } \ + } while (0) + #endif /* _DP_PEER_H_ */ diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 24d32f10e09d..dd7441207946 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -416,11 +416,9 @@ dp_rx_wds_add_or_update_ast(struct dp_soc *soc, struct dp_peer *ta_peer, uint16_t sa_idx, uint16_t sa_sw_peer_id) { struct dp_peer *sa_peer; - struct dp_peer *wds_peer; struct dp_ast_entry *ast; uint32_t flags = IEEE80211_NODE_F_WDS_HM; uint32_t ret = 0; - bool del_in_progress; struct dp_neighbour_peer *neighbour_peer = NULL; struct dp_pdev *pdev = ta_peer->vdev->pdev; @@ -471,22 +469,6 @@ dp_rx_wds_add_or_update_ast(struct dp_soc *soc, struct dp_peer *ta_peer, * cached. */ if (!soc->ast_override_support) { - wds_peer = dp_peer_find_hash_find(soc, wds_src_mac, - 0, DP_VDEV_ALL); - if (wds_peer) { - del_in_progress = wds_peer->delete_in_progress; - dp_peer_unref_delete(wds_peer); - if (!del_in_progress) { - QDF_TRACE(QDF_MODULE_ID_DP, - QDF_TRACE_LEVEL_DEBUG, - "wds peer %pM found", - wds_src_mac); - QDF_TRACE(QDF_MODULE_ID_DP, - QDF_TRACE_LEVEL_DEBUG, - "No AST no Del in progress"); - } - return; - } ret = dp_peer_add_ast(soc, ta_peer, wds_src_mac, diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index cc930075c802..f11bd13fc87d 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -136,7 +136,9 @@ static inline bool dp_rx_mcast_echo_check(struct dp_soc *soc, } } } else - ase = dp_peer_ast_hash_find_soc(soc, &data[DP_MAC_ADDR_LEN]); + ase = dp_peer_ast_hash_find_by_pdevid(soc, + &data[DP_MAC_ADDR_LEN], + vdev->pdev->pdev_id); if (ase) { diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index aed9e5ace1ee..ca3284c408a7 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -642,6 +642,22 @@ union dp_align_mac_addr { } align4_2; }; +/** + * struct dp_ast_free_cb_params - HMWDS free callback cookie + * @mac_addr: ast mac address + * @peer_mac_addr: mac address of peer + * @type: ast entry type + * @vdev_id: vdev_id + * @flags: ast flags + */ +struct dp_ast_free_cb_params { + union dp_align_mac_addr mac_addr; + union dp_align_mac_addr peer_mac_addr; + enum cdp_txrx_ast_entry_type type; + uint8_t vdev_id; + uint32_t flags; +}; + /* * dp_ast_entry * @@ -661,13 +677,14 @@ union dp_align_mac_addr { * @ast_hash_value: hast value in HW * @ref_cnt: reference count * @type: flag to indicate type of the entry(static/WDS/MEC) - * @del_cmd_sent: Flag to identify if WMI to del ast is sent - * @cp_ctx: Opaque context used by control path (AST_HKV1_WORKAROUND) + * @delete_in_progress: Flag to indicate that delete commands send to FW + * and host is waiting for response from FW + * @callback: ast free/unmap callback + * @cookie: argument to callback * @hash_list_elem: node in soc AST hash list (mac address used as hash) */ struct dp_ast_entry { uint16_t ast_idx; - /* MAC address */ union dp_align_mac_addr mac_addr; struct dp_peer *peer; bool next_hop; @@ -679,8 +696,9 @@ struct dp_ast_entry { uint16_t ast_hash_value; qdf_atomic_t ref_cnt; enum cdp_txrx_ast_entry_type type; - bool del_cmd_sent; - void *cp_ctx; + bool delete_in_progress; + txrx_ast_free_cb callback; + void *cookie; TAILQ_ENTRY(dp_ast_entry) ase_list_elem; TAILQ_ENTRY(dp_ast_entry) hash_list_elem; };