summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRajeev Kumar <rajekuma@codeaurora.org>2016-09-20 16:16:17 -0700
committerqcabuildsw <qcabuildsw@localhost>2016-09-23 02:21:17 -0700
commitfb02a5e3ed7dcb8df2b2874d1bc3e1c3739987c1 (patch)
treebf523d169cc2ccad0cbadc4afa451a6a8f15efd3
parent58aae0e57ecdb7023cff5c72263bd7043125ca69 (diff)
qcacld-3.0: Fix kernel panic during driver load failure
In low memory conditions TX/RX histogram memory allocation failure is not handled properly and because of it 2 kernel panics are observed. 1st kernel panic is caused when freed HDD context is de-referenced in hdd_wlan_startup and 2nd kernel panic is caused by kernel wake lock list corruption because WLAN driver during load failure corrupted kernel's wake lock list. As part of this fix make sure TX/RX histogram memory allocation failure is handled gracefully by properly sending failure reason code to hdd_wlan_startup. Also in order to make fix complete and avoid any other kernel panic, deinit HDD context properly by freeing all HDD created wake locks such that when HDD context is freed its wake locks are not poisoned to 0x6b6b6b6b6b6b6b6b (SLUB magic pattern) pattern by kernel and hence corrupting kernel wake lock list. This fix ensures driver load failure caused by TX/RX histogram allocation failure is handled gracefully in low memory conditions without leading to any kernel panic. Change-Id: I17a46c346402642f39e6548cd40bedd1f7ff96a4 CRs-Fixed: 1069014
-rw-r--r--core/hdd/inc/wlan_hdd_main.h1
-rw-r--r--core/hdd/src/wlan_hdd_main.c41
2 files changed, 37 insertions, 5 deletions
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 19135f1b05d8..4ac3abbac81f 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1676,7 +1676,6 @@ void wlan_hdd_txrx_pause_cb(uint8_t vdev_id,
enum netif_action_type action, enum netif_reason_type reason);
void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value);
-int wlan_hdd_init_tx_rx_histogram(hdd_context_t *hdd_ctx);
void wlan_hdd_deinit_tx_rx_histogram(hdd_context_t *hdd_ctx);
void wlan_hdd_display_tx_rx_histogram(hdd_context_t *pHddCtx);
void wlan_hdd_clear_tx_rx_histogram(hdd_context_t *pHddCtx);
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 1262361bd4e9..6e779b5d2e7e 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -5263,7 +5263,7 @@ static void hdd_bus_bw_compute_cbk(void *priv)
*
* Return: 0 for success or error code
*/
-int wlan_hdd_init_tx_rx_histogram(hdd_context_t *hdd_ctx)
+static int wlan_hdd_init_tx_rx_histogram(hdd_context_t *hdd_ctx)
{
hdd_ctx->hdd_txrx_hist = qdf_mem_malloc(
(sizeof(struct hdd_tx_rx_histogram) * NUM_TX_RX_HISTOGRAM));
@@ -6130,6 +6130,36 @@ static void hdd_set_trace_level_for_each(hdd_context_t *hdd_ctx)
}
/**
+ * hdd_context_deinit() - Deinitialize HDD context
+ * @hdd_ctx: HDD context.
+ *
+ * Deinitialize HDD context along with all the feature specific contexts but
+ * do not free hdd context itself. Caller of this API is supposed to free
+ * HDD context.
+ *
+ * return: 0 on success and errno on failure.
+ */
+static int hdd_context_deinit(hdd_context_t *hdd_ctx)
+{
+ wlan_hdd_cfg80211_deinit(hdd_ctx->wiphy);
+
+ hdd_roc_context_destroy(hdd_ctx);
+
+ hdd_sap_context_destroy(hdd_ctx);
+
+ hdd_rx_wake_lock_destroy(hdd_ctx);
+
+ hdd_tdls_context_destroy(hdd_ctx);
+
+ hdd_scan_context_destroy(hdd_ctx);
+
+ qdf_list_destroy(&hdd_ctx->hddAdapters);
+
+ return 0;
+}
+
+
+/**
* hdd_context_init() - Initialize HDD context
* @hdd_ctx: HDD context.
*
@@ -6286,9 +6316,9 @@ hdd_context_t *hdd_context_create(struct device *dev)
cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs);
- status = wlan_hdd_init_tx_rx_histogram(hdd_ctx);
- if (status)
- goto err_free_config;
+ ret = wlan_hdd_init_tx_rx_histogram(hdd_ctx);
+ if (ret)
+ goto err_deinit_hdd_context;
ret = hdd_logging_sock_activate_svc(hdd_ctx);
if (ret)
@@ -6311,6 +6341,9 @@ skip_multicast_logging:
err_free_histogram:
wlan_hdd_deinit_tx_rx_histogram(hdd_ctx);
+err_deinit_hdd_context:
+ hdd_context_deinit(hdd_ctx);
+
err_free_config:
qdf_mem_free(hdd_ctx->config);