Loading drivers/soc/qcom/icnss2/main.c +121 −43 Original line number Diff line number Diff line Loading @@ -1095,47 +1095,61 @@ static int icnss_driver_event_unregister_driver(struct icnss_priv *priv, return 0; } static int icnss_call_driver_remove(struct icnss_priv *priv) static int icnss_fw_crashed(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data) { icnss_pr_dbg("Calling driver remove state: 0x%lx\n", priv->state); icnss_pr_dbg("FW crashed, state: 0x%lx\n", priv->state); set_bit(ICNSS_PD_RESTART, &priv->state); clear_bit(ICNSS_FW_READY, &priv->state); if (test_bit(ICNSS_DRIVER_UNLOADING, &priv->state)) return 0; icnss_pm_stay_awake(priv); if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state)) return 0; if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (event_data && event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); if (!priv->ops || !priv->ops->remove) return 0; } set_bit(ICNSS_DRIVER_UNLOADING, &priv->state); priv->ops->remove(&priv->pdev->dev); int icnss_update_hang_event_data(struct icnss_priv *priv, struct icnss_uevent_hang_data *hang_data) { if (!priv->hang_event_data_va) return -EINVAL; clear_bit(ICNSS_DRIVER_UNLOADING, &priv->state); clear_bit(ICNSS_DRIVER_PROBED, &priv->state); priv->hang_event_data = kmemdup(priv->hang_event_data_va, priv->hang_event_data_len, GFP_ATOMIC); if (!priv->hang_event_data) return -ENOMEM; icnss_hw_power_off(priv); // Update the hang event params hang_data->hang_event_data = priv->hang_event_data; hang_data->hang_event_data_len = priv->hang_event_data_len; return 0; } static int icnss_fw_crashed(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data) int icnss_send_hang_event_data(struct icnss_priv *priv) { icnss_pr_dbg("FW crashed, state: 0x%lx\n", priv->state); set_bit(ICNSS_PD_RESTART, &priv->state); clear_bit(ICNSS_FW_READY, &priv->state); icnss_pm_stay_awake(priv); struct icnss_uevent_hang_data hang_data = {0}; int ret = 0xFF; if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (priv->early_crash_ind) { ret = icnss_update_hang_event_data(priv, &hang_data); if (ret) icnss_pr_err("Unable to allocate memory for Hang event data\n"); } icnss_call_driver_uevent(priv, ICNSS_UEVENT_HANG_DATA, &hang_data); if (event_data && event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); if (!ret) { kfree(priv->hang_event_data); priv->hang_event_data = NULL; } return 0; } Loading @@ -1153,6 +1167,9 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, if (priv->force_err_fatal) ICNSS_ASSERT(0); if (priv->device_id == ADRASTEA_DEVICE_ID) icnss_send_hang_event_data(priv); if (priv->early_crash_ind) { icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n", event_data->crashed, priv->state); Loading Loading @@ -1431,8 +1448,13 @@ static void icnss_update_state_send_modem_shutdown(struct icnss_priv *priv, if (atomic_read(&priv->is_shutdown)) { atomic_set(&priv->is_shutdown, false); if (!test_bit(ICNSS_PD_RESTART, &priv->state) && !test_bit(ICNSS_SHUTDOWN_DONE, &priv->state)) { icnss_call_driver_remove(priv); !test_bit(ICNSS_SHUTDOWN_DONE, &priv->state) && !test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) { clear_bit(ICNSS_FW_READY, &priv->state); icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER, ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL); } } Loading @@ -1458,18 +1480,18 @@ 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); if (code == SUBSYS_AFTER_SHUTDOWN) { icnss_pr_info("Collecting msa0 segment dump\n"); icnss_msa0_ramdump(priv); return NOTIFY_OK; goto out; } if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; goto out; priv->is_ssr = true; Loading @@ -1479,12 +1501,13 @@ 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; } goto out; } icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n", Loading @@ -1501,20 +1524,24 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) if (event_data == NULL) { icnss_pr_vdbg("Exit %s, event_data is NULL\n", __func__); return notifier_from_errno(-ENOMEM); } event_data->crashed = notif->crashed; fw_down_data.crashed = !!notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = !!notif->crashed; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); out: icnss_pr_vdbg("Exit %s,state: 0x%lx\n", __func__, priv->state); return NOTIFY_OK; } Loading Loading @@ -1575,7 +1602,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 @@ -1628,8 +1655,8 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); fw_down_data.crashed = event_data->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) fw_down_data.crashed = event_data->crashed; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); Loading Loading @@ -1979,7 +2006,7 @@ int icnss_unregister_driver(struct icnss_driver_ops *ops) icnss_pr_dbg("Unregistering driver, state: 0x%lx\n", priv->state); if (!priv->ops) { if (!priv->ops || (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))) { icnss_pr_err("Driver not registered\n"); ret = -ENOENT; goto out; Loading Loading @@ -2487,6 +2514,7 @@ int icnss_smmu_map(struct device *dev, { struct icnss_priv *priv = dev_get_drvdata(dev); unsigned long iova; int prop_len = 0; size_t len; int ret = 0; Loading @@ -2503,9 +2531,10 @@ int icnss_smmu_map(struct device *dev, } len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); iova = roundup(priv->smmu_iova_ipa_start, PAGE_SIZE); iova = roundup(priv->smmu_iova_ipa_current, PAGE_SIZE); if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) { if (of_get_property(dev->of_node, "qcom,iommu-geometry", &prop_len) && iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) { icnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", iova, &priv->smmu_iova_ipa_start, Loading @@ -2513,6 +2542,8 @@ int icnss_smmu_map(struct device *dev, return -ENOMEM; } icnss_pr_dbg("IOMMU Map: iova %lx, len %zu\n", iova, len); ret = iommu_map(priv->iommu_domain, iova, rounddown(paddr, PAGE_SIZE), len, IOMMU_READ | IOMMU_WRITE); Loading @@ -2521,13 +2552,59 @@ int icnss_smmu_map(struct device *dev, return ret; } priv->smmu_iova_ipa_start = iova + len; priv->smmu_iova_ipa_current = iova + len; *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); icnss_pr_dbg("IOVA addr mapped to physical addr %lx\n", *iova_addr); return 0; } EXPORT_SYMBOL(icnss_smmu_map); int icnss_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size) { struct icnss_priv *priv = dev_get_drvdata(dev); unsigned long iova; size_t len, unmapped_len; if (!priv) { icnss_pr_err("Invalid drvdata: dev %pK, data %pK\n", dev, priv); return -EINVAL; } if (!iova_addr) { icnss_pr_err("iova_addr is NULL, size %zu\n", size); return -EINVAL; } len = roundup(size + iova_addr - rounddown(iova_addr, PAGE_SIZE), PAGE_SIZE); iova = rounddown(iova_addr, PAGE_SIZE); if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) { icnss_pr_err("Out of IOVA space during unmap, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", iova, &priv->smmu_iova_ipa_start, priv->smmu_iova_ipa_len); return -ENOMEM; } icnss_pr_dbg("IOMMU Unmap: iova %lx, len %zu\n", iova, len); unmapped_len = iommu_unmap(priv->iommu_domain, iova, len); if (unmapped_len != len) { icnss_pr_err("Failed to unmap, %zu\n", unmapped_len); return -EINVAL; } priv->smmu_iova_ipa_current = iova; return 0; } EXPORT_SYMBOL(icnss_smmu_unmap); unsigned int icnss_socinfo_get_serial_number(struct device *dev) { return socinfo_get_serial_number(); Loading Loading @@ -2921,6 +2998,7 @@ static int icnss_smmu_dt_parse(struct icnss_priv *priv) icnss_pr_err("SMMU IOVA IPA not found\n"); } else { priv->smmu_iova_ipa_start = res->start; priv->smmu_iova_ipa_current = res->start; priv->smmu_iova_ipa_len = resource_size(res); icnss_pr_dbg("SMMU IOVA IPA start: %pa, len: %zx\n", &priv->smmu_iova_ipa_start, Loading drivers/soc/qcom/icnss2/main.h +6 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,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 @@ -303,6 +304,7 @@ struct icnss_priv { u32 mem_base_size; struct iommu_domain *iommu_domain; dma_addr_t smmu_iova_ipa_start; dma_addr_t smmu_iova_ipa_current; size_t smmu_iova_ipa_len; struct qmi_handle qmi; struct list_head event_list; Loading Loading @@ -374,6 +376,10 @@ struct icnss_priv { struct thermal_cooling_device *tcdev; unsigned long curr_thermal_state; unsigned long max_thermal_state; 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/icnss2/qmi.c +59 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/thread_info.h> #include <linux/firmware.h> #include <linux/soc/qcom/qmi.h> #include <linux/platform_device.h> #include <soc/qcom/icnss2.h> #include <soc/qcom/service-locator.h> #include <soc/qcom/service-notifier.h> Loading Loading @@ -1460,7 +1461,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 @@ -1574,6 +1575,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 @@ -1583,6 +1588,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 include/soc/qcom/icnss2.h +8 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,12 @@ enum icnss_uevent { ICNSS_UEVENT_FW_CRASHED, ICNSS_UEVENT_FW_DOWN, ICNSS_UEVENT_HANG_DATA, }; struct icnss_uevent_hang_data { void *hang_event_data; uint16_t hang_event_data_len; }; struct icnss_uevent_fw_down_data { Loading Loading @@ -149,6 +155,8 @@ extern struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev); extern struct iommu_domain *icnss_smmu_get_domain(struct device *dev); extern int icnss_smmu_map(struct device *dev, phys_addr_t paddr, uint32_t *iova_addr, size_t size); extern int icnss_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size); extern unsigned int icnss_socinfo_get_serial_number(struct device *dev); extern bool icnss_is_qmi_disable(struct device *dev); extern bool icnss_is_fw_ready(void); Loading Loading
drivers/soc/qcom/icnss2/main.c +121 −43 Original line number Diff line number Diff line Loading @@ -1095,47 +1095,61 @@ static int icnss_driver_event_unregister_driver(struct icnss_priv *priv, return 0; } static int icnss_call_driver_remove(struct icnss_priv *priv) static int icnss_fw_crashed(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data) { icnss_pr_dbg("Calling driver remove state: 0x%lx\n", priv->state); icnss_pr_dbg("FW crashed, state: 0x%lx\n", priv->state); set_bit(ICNSS_PD_RESTART, &priv->state); clear_bit(ICNSS_FW_READY, &priv->state); if (test_bit(ICNSS_DRIVER_UNLOADING, &priv->state)) return 0; icnss_pm_stay_awake(priv); if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state)) return 0; if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (event_data && event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); if (!priv->ops || !priv->ops->remove) return 0; } set_bit(ICNSS_DRIVER_UNLOADING, &priv->state); priv->ops->remove(&priv->pdev->dev); int icnss_update_hang_event_data(struct icnss_priv *priv, struct icnss_uevent_hang_data *hang_data) { if (!priv->hang_event_data_va) return -EINVAL; clear_bit(ICNSS_DRIVER_UNLOADING, &priv->state); clear_bit(ICNSS_DRIVER_PROBED, &priv->state); priv->hang_event_data = kmemdup(priv->hang_event_data_va, priv->hang_event_data_len, GFP_ATOMIC); if (!priv->hang_event_data) return -ENOMEM; icnss_hw_power_off(priv); // Update the hang event params hang_data->hang_event_data = priv->hang_event_data; hang_data->hang_event_data_len = priv->hang_event_data_len; return 0; } static int icnss_fw_crashed(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data) int icnss_send_hang_event_data(struct icnss_priv *priv) { icnss_pr_dbg("FW crashed, state: 0x%lx\n", priv->state); set_bit(ICNSS_PD_RESTART, &priv->state); clear_bit(ICNSS_FW_READY, &priv->state); icnss_pm_stay_awake(priv); struct icnss_uevent_hang_data hang_data = {0}; int ret = 0xFF; if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (priv->early_crash_ind) { ret = icnss_update_hang_event_data(priv, &hang_data); if (ret) icnss_pr_err("Unable to allocate memory for Hang event data\n"); } icnss_call_driver_uevent(priv, ICNSS_UEVENT_HANG_DATA, &hang_data); if (event_data && event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); if (!ret) { kfree(priv->hang_event_data); priv->hang_event_data = NULL; } return 0; } Loading @@ -1153,6 +1167,9 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, if (priv->force_err_fatal) ICNSS_ASSERT(0); if (priv->device_id == ADRASTEA_DEVICE_ID) icnss_send_hang_event_data(priv); if (priv->early_crash_ind) { icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n", event_data->crashed, priv->state); Loading Loading @@ -1431,8 +1448,13 @@ static void icnss_update_state_send_modem_shutdown(struct icnss_priv *priv, if (atomic_read(&priv->is_shutdown)) { atomic_set(&priv->is_shutdown, false); if (!test_bit(ICNSS_PD_RESTART, &priv->state) && !test_bit(ICNSS_SHUTDOWN_DONE, &priv->state)) { icnss_call_driver_remove(priv); !test_bit(ICNSS_SHUTDOWN_DONE, &priv->state) && !test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) { clear_bit(ICNSS_FW_READY, &priv->state); icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER, ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL); } } Loading @@ -1458,18 +1480,18 @@ 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); if (code == SUBSYS_AFTER_SHUTDOWN) { icnss_pr_info("Collecting msa0 segment dump\n"); icnss_msa0_ramdump(priv); return NOTIFY_OK; goto out; } if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; goto out; priv->is_ssr = true; Loading @@ -1479,12 +1501,13 @@ 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; } goto out; } icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n", Loading @@ -1501,20 +1524,24 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) if (event_data == NULL) { icnss_pr_vdbg("Exit %s, event_data is NULL\n", __func__); return notifier_from_errno(-ENOMEM); } event_data->crashed = notif->crashed; fw_down_data.crashed = !!notif->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = !!notif->crashed; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); out: icnss_pr_vdbg("Exit %s,state: 0x%lx\n", __func__, priv->state); return NOTIFY_OK; } Loading Loading @@ -1575,7 +1602,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 @@ -1628,8 +1655,8 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); fw_down_data.crashed = event_data->crashed; if (test_bit(ICNSS_FW_READY, &priv->state)) fw_down_data.crashed = event_data->crashed; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); Loading Loading @@ -1979,7 +2006,7 @@ int icnss_unregister_driver(struct icnss_driver_ops *ops) icnss_pr_dbg("Unregistering driver, state: 0x%lx\n", priv->state); if (!priv->ops) { if (!priv->ops || (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))) { icnss_pr_err("Driver not registered\n"); ret = -ENOENT; goto out; Loading Loading @@ -2487,6 +2514,7 @@ int icnss_smmu_map(struct device *dev, { struct icnss_priv *priv = dev_get_drvdata(dev); unsigned long iova; int prop_len = 0; size_t len; int ret = 0; Loading @@ -2503,9 +2531,10 @@ int icnss_smmu_map(struct device *dev, } len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); iova = roundup(priv->smmu_iova_ipa_start, PAGE_SIZE); iova = roundup(priv->smmu_iova_ipa_current, PAGE_SIZE); if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) { if (of_get_property(dev->of_node, "qcom,iommu-geometry", &prop_len) && iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) { icnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", iova, &priv->smmu_iova_ipa_start, Loading @@ -2513,6 +2542,8 @@ int icnss_smmu_map(struct device *dev, return -ENOMEM; } icnss_pr_dbg("IOMMU Map: iova %lx, len %zu\n", iova, len); ret = iommu_map(priv->iommu_domain, iova, rounddown(paddr, PAGE_SIZE), len, IOMMU_READ | IOMMU_WRITE); Loading @@ -2521,13 +2552,59 @@ int icnss_smmu_map(struct device *dev, return ret; } priv->smmu_iova_ipa_start = iova + len; priv->smmu_iova_ipa_current = iova + len; *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); icnss_pr_dbg("IOVA addr mapped to physical addr %lx\n", *iova_addr); return 0; } EXPORT_SYMBOL(icnss_smmu_map); int icnss_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size) { struct icnss_priv *priv = dev_get_drvdata(dev); unsigned long iova; size_t len, unmapped_len; if (!priv) { icnss_pr_err("Invalid drvdata: dev %pK, data %pK\n", dev, priv); return -EINVAL; } if (!iova_addr) { icnss_pr_err("iova_addr is NULL, size %zu\n", size); return -EINVAL; } len = roundup(size + iova_addr - rounddown(iova_addr, PAGE_SIZE), PAGE_SIZE); iova = rounddown(iova_addr, PAGE_SIZE); if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) { icnss_pr_err("Out of IOVA space during unmap, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", iova, &priv->smmu_iova_ipa_start, priv->smmu_iova_ipa_len); return -ENOMEM; } icnss_pr_dbg("IOMMU Unmap: iova %lx, len %zu\n", iova, len); unmapped_len = iommu_unmap(priv->iommu_domain, iova, len); if (unmapped_len != len) { icnss_pr_err("Failed to unmap, %zu\n", unmapped_len); return -EINVAL; } priv->smmu_iova_ipa_current = iova; return 0; } EXPORT_SYMBOL(icnss_smmu_unmap); unsigned int icnss_socinfo_get_serial_number(struct device *dev) { return socinfo_get_serial_number(); Loading Loading @@ -2921,6 +2998,7 @@ static int icnss_smmu_dt_parse(struct icnss_priv *priv) icnss_pr_err("SMMU IOVA IPA not found\n"); } else { priv->smmu_iova_ipa_start = res->start; priv->smmu_iova_ipa_current = res->start; priv->smmu_iova_ipa_len = resource_size(res); icnss_pr_dbg("SMMU IOVA IPA start: %pa, len: %zx\n", &priv->smmu_iova_ipa_start, Loading
drivers/soc/qcom/icnss2/main.h +6 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,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 @@ -303,6 +304,7 @@ struct icnss_priv { u32 mem_base_size; struct iommu_domain *iommu_domain; dma_addr_t smmu_iova_ipa_start; dma_addr_t smmu_iova_ipa_current; size_t smmu_iova_ipa_len; struct qmi_handle qmi; struct list_head event_list; Loading Loading @@ -374,6 +376,10 @@ struct icnss_priv { struct thermal_cooling_device *tcdev; unsigned long curr_thermal_state; unsigned long max_thermal_state; 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/icnss2/qmi.c +59 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/thread_info.h> #include <linux/firmware.h> #include <linux/soc/qcom/qmi.h> #include <linux/platform_device.h> #include <soc/qcom/icnss2.h> #include <soc/qcom/service-locator.h> #include <soc/qcom/service-notifier.h> Loading Loading @@ -1460,7 +1461,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 @@ -1574,6 +1575,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 @@ -1583,6 +1588,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
include/soc/qcom/icnss2.h +8 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,12 @@ enum icnss_uevent { ICNSS_UEVENT_FW_CRASHED, ICNSS_UEVENT_FW_DOWN, ICNSS_UEVENT_HANG_DATA, }; struct icnss_uevent_hang_data { void *hang_event_data; uint16_t hang_event_data_len; }; struct icnss_uevent_fw_down_data { Loading Loading @@ -149,6 +155,8 @@ extern struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev); extern struct iommu_domain *icnss_smmu_get_domain(struct device *dev); extern int icnss_smmu_map(struct device *dev, phys_addr_t paddr, uint32_t *iova_addr, size_t size); extern int icnss_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size); extern unsigned int icnss_socinfo_get_serial_number(struct device *dev); extern bool icnss_is_qmi_disable(struct device *dev); extern bool icnss_is_fw_ready(void); Loading