mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 07:03:09 -04:00
qcacld-3.0: LRO - Fix LRO disable crash
- Fix a crash seen due to memory being freed twice - Deregister the LRO flush callback during LRO disable CRs-Fixed: 933123 Change-Id: I18edadc620da04b9a571da6e1b143c099c308d90
This commit is contained in:
parent
98815d2b8e
commit
8d97817435
7 changed files with 135 additions and 25 deletions
|
|
@ -279,5 +279,6 @@ void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer,
|
|||
|
||||
#if defined(FEATURE_LRO)
|
||||
void ol_register_lro_flush_cb(void (handler)(void *), void *data);
|
||||
void ol_deregister_lro_flush_cb(void);
|
||||
#endif
|
||||
#endif /* _OL_TXRX_OSIF_API__H_ */
|
||||
|
|
|
|||
|
|
@ -3112,6 +3112,18 @@ CDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb)
|
|||
#endif
|
||||
|
||||
#if defined(FEATURE_LRO)
|
||||
/**
|
||||
* ol_txrx_lro_flush_handler() - LRO flush handler
|
||||
* @context: dev handle
|
||||
* @rxpkt: rx data
|
||||
* @staid: station id
|
||||
*
|
||||
* This function handles an LRO flush indication.
|
||||
* If the rx thread is enabled, it will be invoked by the rx
|
||||
* thread else it will be called in the tasklet context
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void ol_txrx_lro_flush_handler(void *context,
|
||||
void *rxpkt,
|
||||
uint16_t staid)
|
||||
|
|
@ -3132,6 +3144,15 @@ void ol_txrx_lro_flush_handler(void *context,
|
|||
"%s: lro_flush_cb NULL", __func__);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_txrx_lro_flush() - LRO flush callback
|
||||
* @data: opaque data pointer
|
||||
*
|
||||
* This is the callback registered with CE to trigger
|
||||
* an LRO flush
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void ol_txrx_lro_flush(void *data)
|
||||
{
|
||||
p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
|
||||
|
|
@ -3151,7 +3172,8 @@ void ol_txrx_lro_flush(void *data)
|
|||
return;
|
||||
}
|
||||
|
||||
pkt->callback = (cds_ol_rx_thread_cb) ol_txrx_lro_flush_handler;
|
||||
pkt->callback =
|
||||
(cds_ol_rx_thread_cb) ol_txrx_lro_flush_handler;
|
||||
pkt->context = pdev;
|
||||
pkt->Rxpkt = NULL;
|
||||
pkt->staId = 0;
|
||||
|
|
@ -3159,6 +3181,16 @@ void ol_txrx_lro_flush(void *data)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_register_lro_flush_cb() - register the LRO flush callback
|
||||
* @handler: callback function
|
||||
* @data: opaque data pointer to be passed back
|
||||
*
|
||||
* Store the LRO flush callback provided and in turn
|
||||
* register OL's LRO flush handler with CE
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void ol_register_lro_flush_cb(void (handler)(void *), void *data)
|
||||
{
|
||||
struct ol_softc *hif_device =
|
||||
|
|
@ -3170,4 +3202,25 @@ void ol_register_lro_flush_cb(void (handler)(void *), void *data)
|
|||
|
||||
ce_lro_flush_cb_register(hif_device, ol_txrx_lro_flush, pdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_deregister_lro_flush_cb() - deregister the LRO flush
|
||||
* callback
|
||||
*
|
||||
* Remove the LRO flush callback provided and in turn
|
||||
* deregister OL's LRO flush handler with CE
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void ol_deregister_lro_flush_cb(void)
|
||||
{
|
||||
struct ol_softc *hif_device =
|
||||
(struct ol_softc *)cds_get_context(CDF_MODULE_ID_HIF);
|
||||
struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
|
||||
|
||||
ce_lro_flush_cb_deregister(hif_device);
|
||||
|
||||
pdev->lro_info.lro_flush_cb = NULL;
|
||||
pdev->lro_info.lro_data = NULL;
|
||||
}
|
||||
#endif /* FEATURE_LRO */
|
||||
|
|
|
|||
|
|
@ -138,14 +138,7 @@ static void hdd_lro_desc_info_init(struct hdd_lro_s *hdd_info)
|
|||
*/
|
||||
static void hdd_lro_desc_pool_deinit(struct hdd_lro_desc_pool *lro_desc_pool)
|
||||
{
|
||||
|
||||
if (lro_desc_pool->lro_desc_array) {
|
||||
cdf_mem_free(lro_desc_pool->lro_desc_array);
|
||||
lro_desc_pool->lro_desc_array = NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&lro_desc_pool->lro_free_list_head);
|
||||
|
||||
cdf_spinlock_destroy(&lro_desc_pool->lro_pool_lock);
|
||||
}
|
||||
|
||||
|
|
@ -161,19 +154,10 @@ static void hdd_lro_desc_pool_deinit(struct hdd_lro_desc_pool *lro_desc_pool)
|
|||
*/
|
||||
static void hdd_lro_desc_info_deinit(struct hdd_lro_s *hdd_info)
|
||||
{
|
||||
int i;
|
||||
struct hdd_lro_desc_info *desc_info = &hdd_info->lro_desc_info;
|
||||
|
||||
cdf_mem_free(hdd_info->lro_mgr->lro_arr);
|
||||
hdd_info->lro_mgr->lro_arr = NULL;
|
||||
hdd_lro_desc_pool_deinit(&desc_info->lro_desc_pool);
|
||||
/* Free the a list of LRO desc for each entry of the hash table */
|
||||
for (i = 0; i < LRO_DESC_TABLE_SZ; i++)
|
||||
INIT_LIST_HEAD(&desc_info->lro_hash_table[i].lro_desc_list);
|
||||
|
||||
cdf_spinlock_destroy(&desc_info->lro_hash_lock);
|
||||
cdf_mem_free(desc_info->lro_hash_table);
|
||||
desc_info->lro_hash_table = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -605,9 +589,18 @@ void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
|
|||
NL80211_IFTYPE_STATION != adapter->wdev.iftype)
|
||||
return;
|
||||
|
||||
hdd_lro_desc_info_deinit(&adapter->lro_info);
|
||||
cdf_mem_free(adapter->lro_info.lro_mgr);
|
||||
adapter->lro_info.lro_mgr = NULL;
|
||||
/* Deregister the flush callback */
|
||||
ol_deregister_lro_flush_cb();
|
||||
|
||||
if (adapter->lro_info.lro_mgr) {
|
||||
hdd_lro_desc_info_deinit(&adapter->lro_info);
|
||||
cdf_mem_free(adapter->lro_info.lro_mgr);
|
||||
adapter->lro_info.lro_mgr = NULL;
|
||||
adapter->lro_info.lro_desc_info.
|
||||
lro_desc_pool.lro_desc_array = NULL;
|
||||
adapter->lro_info.lro_desc_info.
|
||||
lro_hash_table = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -467,5 +467,6 @@ bool ce_check_rx_pending(struct ol_softc *scn, int ce_id);
|
|||
#if defined(FEATURE_LRO)
|
||||
void ce_lro_flush_cb_register(struct ol_softc *scn,
|
||||
void (handler)(void *), void *data);
|
||||
void ce_lro_flush_cb_deregister(struct ol_softc *scn);
|
||||
#endif
|
||||
#endif /* __COPY_ENGINE_API_H__ */
|
||||
|
|
|
|||
|
|
@ -2584,10 +2584,65 @@ u32 shadow_dst_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEATURE_LRO)
|
||||
/**
|
||||
* ce_lro_flush_cb_register() - register the LRO flush
|
||||
* callback
|
||||
* @scn: HIF context
|
||||
* @handler: callback function
|
||||
* @data: opaque data pointer to be passed back
|
||||
*
|
||||
* Store the LRO flush callback provided
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void ce_lro_flush_cb_register(struct ol_softc *scn,
|
||||
void (handler)(void *), void *data)
|
||||
{
|
||||
struct CE_state *ce_state = scn->ce_id_to_state[CE_HTT_T2H_MSG];
|
||||
ce_state->lro_flush_cb = handler;
|
||||
ce_state->lro_data = data;
|
||||
uint8_t ul, dl;
|
||||
int ul_polled, dl_polled;
|
||||
|
||||
CDF_ASSERT(scn != NULL);
|
||||
|
||||
if (CDF_STATUS_SUCCESS !=
|
||||
hif_map_service_to_pipe(scn, HTT_DATA_MSG_SVC,
|
||||
&ul, &dl, &ul_polled, &dl_polled)) {
|
||||
printk("%s cannot map service to pipe\n", __FUNCTION__);
|
||||
return;
|
||||
} else {
|
||||
struct CE_state *ce_state;
|
||||
ce_state = scn->ce_id_to_state[dl];
|
||||
ce_state->lro_flush_cb = handler;
|
||||
ce_state->lro_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ce_lro_flush_cb_deregister() - deregister the LRO flush
|
||||
* callback
|
||||
* @scn: HIF context
|
||||
*
|
||||
* Remove the LRO flush callback
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void ce_lro_flush_cb_deregister(struct ol_softc *scn)
|
||||
{
|
||||
uint8_t ul, dl;
|
||||
int ul_polled, dl_polled;
|
||||
|
||||
CDF_ASSERT(scn != NULL);
|
||||
|
||||
if (CDF_STATUS_SUCCESS !=
|
||||
hif_map_service_to_pipe(scn, HTT_DATA_MSG_SVC,
|
||||
&ul, &dl, &ul_polled, &dl_polled)) {
|
||||
printk("%s cannot map service to pipe\n", __FUNCTION__);
|
||||
return;
|
||||
} else {
|
||||
struct CE_state *ce_state;
|
||||
ce_state = scn->ce_id_to_state[dl];
|
||||
ce_state->lro_flush_cb = NULL;
|
||||
ce_state->lro_data = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -214,8 +214,7 @@ static void ce_tasklet(unsigned long data)
|
|||
|
||||
ce_per_engine_service(scn, tasklet_entry->ce_id);
|
||||
|
||||
if (tasklet_entry->ce_id == CE_HTT_T2H_MSG &&
|
||||
CE_state->lro_flush_cb != NULL) {
|
||||
if (CE_state->lro_flush_cb != NULL) {
|
||||
CE_state->lro_flush_cb(CE_state->lro_data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <hif_debug.h>
|
||||
#include <hif_io32.h>
|
||||
#include <ce_api.h>
|
||||
#include <ce_internal.h>
|
||||
|
||||
enum napi_decision_vector {
|
||||
HIF_NAPI_NOEVENT = 0,
|
||||
|
|
@ -399,6 +400,7 @@ int hif_napi_poll(struct napi_struct *napi, int budget)
|
|||
int cpu = smp_processor_id();
|
||||
struct ol_softc *hif;
|
||||
struct qca_napi_info *napi_info;
|
||||
struct CE_state *ce_state;
|
||||
|
||||
NAPI_DEBUG("%s -->(.., budget=%d)\n", budget);
|
||||
|
||||
|
|
@ -413,6 +415,12 @@ int hif_napi_poll(struct napi_struct *napi, int budget)
|
|||
__func__, rc);
|
||||
napi_info->stats[cpu].napi_workdone += rc;
|
||||
normalized = (rc / napi_info->scale);
|
||||
|
||||
ce_state = hif->ce_id_to_state[NAPI_ID2PIPE(napi_info->id)];
|
||||
if (ce_state->lro_flush_cb != NULL) {
|
||||
ce_state->lro_flush_cb(ce_state->lro_data);
|
||||
}
|
||||
|
||||
/* do not return 0, if there was some work done,
|
||||
even if it is below the scale */
|
||||
if (rc)
|
||||
|
|
|
|||
Loading…
Reference in a new issue