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);