Loading drivers/soc/qcom/icnss.c +43 −10 Original line number Diff line number Diff line Loading @@ -571,6 +571,27 @@ int icnss_power_off(struct device *dev) } EXPORT_SYMBOL(icnss_power_off); int icnss_update_fw_down_params(struct icnss_priv *priv, struct icnss_uevent_fw_down_data *fw_down_data, bool crashed) { fw_down_data->crashed = crashed; if (!priv->hang_event_data_va) return -EINVAL; priv->hang_event_data = kmemdup(priv->hang_event_data_va, priv->hang_event_data_len, GFP_ATOMIC); if (!priv->hang_event_data) return -ENOMEM; // Update the hang event params fw_down_data->hang_event_data = priv->hang_event_data; fw_down_data->hang_event_data_len = priv->hang_event_data_len; return 0; } static irqreturn_t fw_error_fatal_handler(int irq, void *ctx) { struct icnss_priv *priv = ctx; Loading @@ -587,6 +608,7 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx) { struct icnss_priv *priv = ctx; struct icnss_uevent_fw_down_data fw_down_data = {0}; int ret = 0; icnss_pr_err("Received early crash indication from FW\n"); Loading @@ -595,9 +617,18 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx) icnss_ignore_fw_timeout(true); if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = true; ret = icnss_update_fw_down_params(priv, &fw_down_data, true); if (ret) icnss_pr_err("Unable to allocate memory for Hang event data\n"); icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); if (!ret) { kfree(priv->hang_event_data); priv->hang_event_data = NULL; } } } Loading Loading @@ -1426,7 +1457,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, struct notif_data *notif = data; struct icnss_priv *priv = container_of(nb, struct icnss_priv, modem_ssr_nb); struct icnss_uevent_fw_down_data fw_down_data; struct icnss_uevent_fw_down_data fw_down_data = {0}; icnss_pr_vdbg("Modem-Notify: event %lu\n", code); Loading @@ -1449,11 +1480,12 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = !!notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } return NOTIFY_OK; } Loading @@ -1476,12 +1508,12 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, event_data->crashed = notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = !!notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); Loading Loading @@ -1545,7 +1577,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, service_notifier_nb); enum pd_subsys_state *state = data; struct icnss_event_pd_service_down_data *event_data; struct icnss_uevent_fw_down_data fw_down_data; struct icnss_uevent_fw_down_data fw_down_data = {0}; enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH; icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n", Loading Loading @@ -1598,12 +1630,13 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = event_data->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } } clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state); icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, Loading drivers/soc/qcom/icnss_private.h +5 −1 Original line number Diff line number Diff line Loading @@ -253,6 +253,7 @@ struct icnss_stats { #define WLFW_MAX_NUM_CE 12 #define WLFW_MAX_NUM_SVC 24 #define WLFW_MAX_NUM_SHADOW_REG 24 #define WLFW_MAX_HANG_EVENT_DATA_SIZE 400 struct service_notifier_context { void *handle; Loading Loading @@ -350,7 +351,10 @@ struct icnss_priv { bool is_ssr; struct kobject *icnss_kobject; atomic_t is_shutdown; phys_addr_t hang_event_data_pa; void __iomem *hang_event_data_va; uint16_t hang_event_data_len; void *hang_event_data; }; struct icnss_reg_info { Loading drivers/soc/qcom/icnss_qmi.c +59 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/ipc_logging.h> #include <linux/thread_info.h> #include <linux/soc/qcom/qmi.h> #include <linux/platform_device.h> #include <soc/qcom/icnss.h> #include <soc/qcom/service-locator.h> #include <soc/qcom/service-notifier.h> Loading Loading @@ -1012,7 +1013,7 @@ int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv, void icnss_handle_rejuvenate(struct icnss_priv *priv) { struct icnss_event_pd_service_down_data *event_data; struct icnss_uevent_fw_down_data fw_down_data; struct icnss_uevent_fw_down_data fw_down_data = {0}; event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) Loading Loading @@ -1047,6 +1048,10 @@ static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *data) { struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); struct device *dev = &priv->pdev->dev; const struct wlfw_msa_ready_ind_msg_v01 *ind_msg = data; uint64_t msa_base_addr = priv->msa_pa; phys_addr_t hang_data_phy_addr; icnss_pr_dbg("Received MSA Ready Indication\n"); Loading @@ -1056,6 +1061,59 @@ static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, } priv->stats.msa_ready_ind++; /* Check if the length is valid & * the length should not be 0 and * should be <= WLFW_MAX_HANG_EVENT_DATA_SIZE(400) */ if (ind_msg->hang_data_length_valid && ind_msg->hang_data_length && ind_msg->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE) priv->hang_event_data_len = ind_msg->hang_data_length; else goto out; /* Check if the offset is valid & * the offset should be in range of 0 to msa_mem_size-hang_data_length */ if (ind_msg->hang_data_addr_offset_valid && (ind_msg->hang_data_addr_offset <= (priv->msa_mem_size - ind_msg->hang_data_length))) hang_data_phy_addr = msa_base_addr + ind_msg->hang_data_addr_offset; else goto out; if (priv->hang_event_data_pa == hang_data_phy_addr) goto exit; priv->hang_event_data_pa = hang_data_phy_addr; priv->hang_event_data_va = devm_ioremap(dev, priv->hang_event_data_pa, ind_msg->hang_data_length); if (!priv->hang_event_data_va) { icnss_pr_err("Hang Data ioremap failed: phy addr: %pa\n", &priv->hang_event_data_pa); goto fail; } exit: icnss_pr_dbg("Hang Event Data details,Offset:0x%x, Length:0x%x,va_addr: 0x%pK\n", ind_msg->hang_data_addr_offset, ind_msg->hang_data_length, priv->hang_event_data_va); return; out: icnss_pr_err("Invalid Hang Data details, Offset:0x%x, Length:0x%x", ind_msg->hang_data_addr_offset, ind_msg->hang_data_length); fail: priv->hang_event_data_va = NULL; priv->hang_event_data_pa = 0; priv->hang_event_data_len = 0; } static void pin_connect_result_ind_cb(struct qmi_handle *qmi, Loading drivers/soc/qcom/wlan_firmware_service_v01.c +37 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/soc/qcom/qmi.h> Loading Loading @@ -512,6 +512,42 @@ struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[] = { }; struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_addr_offset_valid), }, { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_addr_offset), }, { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_length_valid), }, { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, .elem_size = sizeof(u16), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_length), }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, Loading drivers/soc/qcom/wlan_firmware_service_v01.h +6 −3 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef WLAN_FIRMWARE_SERVICE_V01_H #define WLAN_FIRMWARE_SERVICE_V01_H Loading Loading @@ -211,9 +211,12 @@ struct wlfw_fw_ready_ind_msg_v01 { extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[]; struct wlfw_msa_ready_ind_msg_v01 { char placeholder; u8 hang_data_addr_offset_valid; u32 hang_data_addr_offset; u8 hang_data_length_valid; u16 hang_data_length; }; #define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0 #define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 12 extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[]; struct wlfw_pin_connect_result_ind_msg_v01 { Loading Loading
drivers/soc/qcom/icnss.c +43 −10 Original line number Diff line number Diff line Loading @@ -571,6 +571,27 @@ int icnss_power_off(struct device *dev) } EXPORT_SYMBOL(icnss_power_off); int icnss_update_fw_down_params(struct icnss_priv *priv, struct icnss_uevent_fw_down_data *fw_down_data, bool crashed) { fw_down_data->crashed = crashed; if (!priv->hang_event_data_va) return -EINVAL; priv->hang_event_data = kmemdup(priv->hang_event_data_va, priv->hang_event_data_len, GFP_ATOMIC); if (!priv->hang_event_data) return -ENOMEM; // Update the hang event params fw_down_data->hang_event_data = priv->hang_event_data; fw_down_data->hang_event_data_len = priv->hang_event_data_len; return 0; } static irqreturn_t fw_error_fatal_handler(int irq, void *ctx) { struct icnss_priv *priv = ctx; Loading @@ -587,6 +608,7 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx) { struct icnss_priv *priv = ctx; struct icnss_uevent_fw_down_data fw_down_data = {0}; int ret = 0; icnss_pr_err("Received early crash indication from FW\n"); Loading @@ -595,9 +617,18 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx) icnss_ignore_fw_timeout(true); if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = true; ret = icnss_update_fw_down_params(priv, &fw_down_data, true); if (ret) icnss_pr_err("Unable to allocate memory for Hang event data\n"); icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); if (!ret) { kfree(priv->hang_event_data); priv->hang_event_data = NULL; } } } Loading Loading @@ -1426,7 +1457,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, struct notif_data *notif = data; struct icnss_priv *priv = container_of(nb, struct icnss_priv, modem_ssr_nb); struct icnss_uevent_fw_down_data fw_down_data; struct icnss_uevent_fw_down_data fw_down_data = {0}; icnss_pr_vdbg("Modem-Notify: event %lu\n", code); Loading @@ -1449,11 +1480,12 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = !!notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } return NOTIFY_OK; } Loading @@ -1476,12 +1508,12 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, event_data->crashed = notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = !!notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); Loading Loading @@ -1545,7 +1577,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, service_notifier_nb); enum pd_subsys_state *state = data; struct icnss_event_pd_service_down_data *event_data; struct icnss_uevent_fw_down_data fw_down_data; struct icnss_uevent_fw_down_data fw_down_data = {0}; enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH; icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n", Loading Loading @@ -1598,12 +1630,13 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = event_data->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } } clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state); icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, Loading
drivers/soc/qcom/icnss_private.h +5 −1 Original line number Diff line number Diff line Loading @@ -253,6 +253,7 @@ struct icnss_stats { #define WLFW_MAX_NUM_CE 12 #define WLFW_MAX_NUM_SVC 24 #define WLFW_MAX_NUM_SHADOW_REG 24 #define WLFW_MAX_HANG_EVENT_DATA_SIZE 400 struct service_notifier_context { void *handle; Loading Loading @@ -350,7 +351,10 @@ struct icnss_priv { bool is_ssr; struct kobject *icnss_kobject; atomic_t is_shutdown; phys_addr_t hang_event_data_pa; void __iomem *hang_event_data_va; uint16_t hang_event_data_len; void *hang_event_data; }; struct icnss_reg_info { Loading
drivers/soc/qcom/icnss_qmi.c +59 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/ipc_logging.h> #include <linux/thread_info.h> #include <linux/soc/qcom/qmi.h> #include <linux/platform_device.h> #include <soc/qcom/icnss.h> #include <soc/qcom/service-locator.h> #include <soc/qcom/service-notifier.h> Loading Loading @@ -1012,7 +1013,7 @@ int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv, void icnss_handle_rejuvenate(struct icnss_priv *priv) { struct icnss_event_pd_service_down_data *event_data; struct icnss_uevent_fw_down_data fw_down_data; struct icnss_uevent_fw_down_data fw_down_data = {0}; event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) Loading Loading @@ -1047,6 +1048,10 @@ static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *data) { struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); struct device *dev = &priv->pdev->dev; const struct wlfw_msa_ready_ind_msg_v01 *ind_msg = data; uint64_t msa_base_addr = priv->msa_pa; phys_addr_t hang_data_phy_addr; icnss_pr_dbg("Received MSA Ready Indication\n"); Loading @@ -1056,6 +1061,59 @@ static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, } priv->stats.msa_ready_ind++; /* Check if the length is valid & * the length should not be 0 and * should be <= WLFW_MAX_HANG_EVENT_DATA_SIZE(400) */ if (ind_msg->hang_data_length_valid && ind_msg->hang_data_length && ind_msg->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE) priv->hang_event_data_len = ind_msg->hang_data_length; else goto out; /* Check if the offset is valid & * the offset should be in range of 0 to msa_mem_size-hang_data_length */ if (ind_msg->hang_data_addr_offset_valid && (ind_msg->hang_data_addr_offset <= (priv->msa_mem_size - ind_msg->hang_data_length))) hang_data_phy_addr = msa_base_addr + ind_msg->hang_data_addr_offset; else goto out; if (priv->hang_event_data_pa == hang_data_phy_addr) goto exit; priv->hang_event_data_pa = hang_data_phy_addr; priv->hang_event_data_va = devm_ioremap(dev, priv->hang_event_data_pa, ind_msg->hang_data_length); if (!priv->hang_event_data_va) { icnss_pr_err("Hang Data ioremap failed: phy addr: %pa\n", &priv->hang_event_data_pa); goto fail; } exit: icnss_pr_dbg("Hang Event Data details,Offset:0x%x, Length:0x%x,va_addr: 0x%pK\n", ind_msg->hang_data_addr_offset, ind_msg->hang_data_length, priv->hang_event_data_va); return; out: icnss_pr_err("Invalid Hang Data details, Offset:0x%x, Length:0x%x", ind_msg->hang_data_addr_offset, ind_msg->hang_data_length); fail: priv->hang_event_data_va = NULL; priv->hang_event_data_pa = 0; priv->hang_event_data_len = 0; } static void pin_connect_result_ind_cb(struct qmi_handle *qmi, Loading
drivers/soc/qcom/wlan_firmware_service_v01.c +37 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/soc/qcom/qmi.h> Loading Loading @@ -512,6 +512,42 @@ struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[] = { }; struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_addr_offset_valid), }, { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_addr_offset), }, { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_length_valid), }, { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, .elem_size = sizeof(u16), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_msa_ready_ind_msg_v01, hang_data_length), }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, Loading
drivers/soc/qcom/wlan_firmware_service_v01.h +6 −3 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef WLAN_FIRMWARE_SERVICE_V01_H #define WLAN_FIRMWARE_SERVICE_V01_H Loading Loading @@ -211,9 +211,12 @@ struct wlfw_fw_ready_ind_msg_v01 { extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[]; struct wlfw_msa_ready_ind_msg_v01 { char placeholder; u8 hang_data_addr_offset_valid; u32 hang_data_addr_offset; u8 hang_data_length_valid; u16 hang_data_length; }; #define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0 #define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 12 extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[]; struct wlfw_pin_connect_result_ind_msg_v01 { Loading