From 74014d914339d124e384aade785d6bf8d39efd1d Mon Sep 17 00:00:00 2001 From: Arun Kumar Khandavalli Date: Fri, 27 Mar 2020 19:32:38 +0530 Subject: [PATCH] qcacld-3.0: Update hdd hang data Whenever a recovery is triggered in the hdd layer update the various vdev data for hang event: 1) Vdev id 2) vdev opmode 3) vdev state and substate if the reason for recovery is max scan failures update the last scan reject, reason and the vdev id on which scan is rejected. Change-Id: I84928e56bac1fe58e7eada0a0574b2f23124ae65 CRs-Fixed: 2651694 --- Kbuild | 4 + core/hdd/inc/wlan_hdd_hang_event.h | 55 ++++++++++++++ core/hdd/src/wlan_hdd_hang_event.c | 117 +++++++++++++++++++++++++++++ core/hdd/src/wlan_hdd_main.c | 3 + 4 files changed, 179 insertions(+) create mode 100644 core/hdd/inc/wlan_hdd_hang_event.h create mode 100644 core/hdd/src/wlan_hdd_hang_event.c diff --git a/Kbuild b/Kbuild index 69313ea87c..d947711334 100644 --- a/Kbuild +++ b/Kbuild @@ -297,6 +297,10 @@ ifeq ($(CONFIG_FEATURE_WLAN_TIME_SYNC_FTM), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ftm_time_sync.o endif +ifeq ($(CONFIG_WLAN_HANG_EVENT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_hang_event.o +endif + ###### OSIF_SYNC ######## SYNC_DIR := os_if/sync SYNC_INC_DIR := $(SYNC_DIR)/inc diff --git a/core/hdd/inc/wlan_hdd_hang_event.h b/core/hdd/inc/wlan_hdd_hang_event.h new file mode 100644 index 0000000000..3376b2ce4b --- /dev/null +++ b/core/hdd/inc/wlan_hdd_hang_event.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020, 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 above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef WLAN_HDD_HANG_EVENT_H +#define WLAN_HDD_HANG_EVENT_H +#include +#include + +#ifdef WLAN_HANG_EVENT +/** + * wlan_hdd_hang_event_notifier_register() - HDD hang event notifier register + * @hdd_ctx: HDD context + * + * This function registers hdd layer notifier for the hang event notifier chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_hang_event_notifier_register(struct hdd_context *hdd_ctx); +/** + * wlan_hdd_hang_event_notifier_unregister() - HDD hang event notifier + * unregister + * @hdd_ctx: HDD context + * + * This function unregisters hdd layer notifier for the hang event notifier + * chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_hang_event_notifier_unregister(void); +#else +static inline +QDF_STATUS wlan_hdd_hang_event_notifier_register(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS wlan_hdd_hang_event_notifier_unregister(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/core/hdd/src/wlan_hdd_hang_event.c b/core/hdd/src/wlan_hdd_hang_event.c new file mode 100644 index 0000000000..2f0ab34a80 --- /dev/null +++ b/core/hdd/src/wlan_hdd_hang_event.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020, 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 above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include "wlan_hdd_object_manager.h" +#include + +struct hdd_hang_event_fixed_param { + uint32_t tlv_header; + uint8_t vdev_id; + uint8_t vdev_opmode; + uint8_t vdev_state; + uint8_t vdev_substate; +} qdf_packed; + +struct hdd_scan_fixed_param { + uint32_t tlv_header; + uint8_t last_scan_reject_vdev_id; + enum scan_reject_states last_scan_reject_reason; + unsigned long last_scan_reject_timestamp; + uint8_t scan_reject_cnt; +} qdf_packed; + +static int wlan_hdd_recovery_notifier_call(struct notifier_block *block, + unsigned long state, + void *data) +{ + qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block, + notif_block); + struct hdd_context *hdd_ctx; + struct qdf_notifer_data *hdd_hang_data = data; + uint8_t *hdd_buf_ptr; + struct hdd_adapter *adapter; + uint32_t total_len; + struct wlan_objmgr_vdev *vdev; + struct hdd_hang_event_fixed_param *cmd; + struct hdd_scan_fixed_param *cmd_scan; + + if (!data) + return NOTIFY_STOP_MASK; + + hdd_ctx = notif_block->priv_data; + if (!hdd_ctx) + return NOTIFY_STOP_MASK; + + if (hdd_hang_data->offset >= QDF_WLAN_MAX_HOST_OFFSET) + return NOTIFY_STOP_MASK; + + if (state == QDF_SCAN_ATTEMPT_FAILURES) { + total_len = sizeof(*cmd_scan); + hdd_buf_ptr = hdd_hang_data->hang_data + hdd_hang_data->offset; + cmd_scan = (struct hdd_scan_fixed_param *)hdd_buf_ptr; + QDF_HANG_EVT_SET_HDR(&cmd_scan->tlv_header, + HANG_EVT_TAG_OS_IF_SCAN, + QDF_HANG_GET_STRUCT_TLVLEN(struct hdd_scan_fixed_param)); + cmd_scan->last_scan_reject_vdev_id = + hdd_ctx->last_scan_reject_vdev_id; + cmd_scan->last_scan_reject_reason = + hdd_ctx->last_scan_reject_reason; + cmd_scan->scan_reject_cnt = + hdd_ctx->scan_reject_cnt; + hdd_hang_data->offset += total_len; + } + + hdd_for_each_adapter_dev_held(hdd_ctx, adapter) { + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) { + dev_put(adapter->dev); + continue; + } + total_len = sizeof(*cmd); + hdd_buf_ptr = hdd_hang_data->hang_data + hdd_hang_data->offset; + cmd = (struct hdd_hang_event_fixed_param *)hdd_buf_ptr; + QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, + HANG_EVT_TAG_OS_IF, + QDF_HANG_GET_STRUCT_TLVLEN(struct hdd_hang_event_fixed_param)); + cmd->vdev_id = wlan_vdev_get_id(vdev); + cmd->vdev_opmode = wlan_vdev_mlme_get_opmode(vdev); + cmd->vdev_state = wlan_vdev_mlme_get_state(vdev); + cmd->vdev_substate = wlan_vdev_mlme_get_substate(vdev); + hdd_hang_data->offset += total_len; + hdd_objmgr_put_vdev(vdev); + dev_put(adapter->dev); + } + + return NOTIFY_OK; +} + +static qdf_notif_block hdd_recovery_notifier = { + .notif_block.notifier_call = wlan_hdd_recovery_notifier_call, +}; + +QDF_STATUS wlan_hdd_hang_event_notifier_register(struct hdd_context *hdd_ctx) +{ + hdd_recovery_notifier.priv_data = hdd_ctx; + return qdf_hang_event_register_notifier(&hdd_recovery_notifier); +} + +QDF_STATUS wlan_hdd_hang_event_notifier_unregister(void) +{ + return qdf_hang_event_unregister_notifier(&hdd_recovery_notifier); +} diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index d6f37ff221..4d60ecba24 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -185,6 +185,7 @@ #include #include "wlan_hdd_debugfs_unit_test.h" #include "wlan_hdd_debugfs_mibstat.h" +#include #ifdef MODULE #define WLAN_MODULE_NAME module_name(THIS_MODULE) @@ -12572,6 +12573,7 @@ int hdd_configure_cds(struct hdd_context *hdd_ctx) hdd_hastings_bt_war_initialize(hdd_ctx); + wlan_hdd_hang_event_notifier_register(hdd_ctx); return 0; cds_disable: @@ -12596,6 +12598,7 @@ static int hdd_deconfigure_cds(struct hdd_context *hdd_ctx) hdd_enter(); + wlan_hdd_hang_event_notifier_unregister(); /* De-init features */ hdd_features_deinit(hdd_ctx);