Loading Documentation/devicetree/bindings/cnss/icnss.txt +2 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ Optional properties: - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory - qcom,gpio-force-fatal-error: SMP2P bit triggered by WLAN FW to force error fatal. - qcom,gpio-early-crash-ind: SMP2P bit triggered by WLAN FW to indicate FW is in assert. Example: Loading Loading @@ -61,4 +62,5 @@ Example: vdd-0.8-cx-mx-supply = <&pm8998_l5>; qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>; qcom,gpio-forced-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; }; arch/arm64/boot/dts/qcom/sm8150.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -3307,6 +3307,7 @@ <0 425 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x100000>; qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; qcom,smmu-s1-bypass; vdd-cx-mx-supply = <&pm855_l1>; Loading drivers/soc/qcom/icnss.c +80 −4 Original line number Diff line number Diff line Loading @@ -272,6 +272,8 @@ static char *icnss_driver_event_to_str(enum icnss_driver_event_type type) return "UNREGISTER_DRIVER"; case ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN: return "PD_SERVICE_DOWN"; case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND: return "FW_EARLY_CRASH_IND"; case ICNSS_DRIVER_EVENT_MAX: return "EVENT_MAX"; } Loading Loading @@ -633,7 +635,24 @@ static irqreturn_t fw_error_fatal_handler(int irq, void *ctx) return IRQ_HANDLED; } static void icnss_register_force_error_fatal(struct icnss_priv *priv) static irqreturn_t fw_crash_indication_handler(int irq, void *ctx) { struct icnss_priv *priv = ctx; icnss_pr_err("Received early crash indication from FW\n"); if (priv) { set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); } icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND, 0, NULL); return IRQ_HANDLED; } static void register_fw_error_notifications(struct icnss_priv *priv) { int gpio, irq, ret; Loading @@ -656,11 +675,38 @@ static void icnss_register_force_error_fatal(struct icnss_priv *priv) ret = request_irq(irq, fw_error_fatal_handler, IRQF_TRIGGER_RISING, "wlanfw-err", priv); if (ret < 0) { icnss_pr_err("Unable to regiser for error fatal IRQ handler %d", icnss_pr_err("Unable to register for error fatal IRQ handler %d", irq); return; } icnss_pr_dbg("FW force error fatal handler registered\n"); if (!of_find_property(priv->pdev->dev.of_node, "qcom,gpio-early-crash-ind", NULL)) { icnss_pr_dbg("FW early crash indication handler not registered\n"); return; } gpio = of_get_named_gpio(priv->pdev->dev.of_node, "qcom,gpio-early-crash-ind", 0); if (!gpio_is_valid(gpio)) { icnss_pr_err("Invalid GPIO for early crash indication %d\n", gpio); return; } irq = gpio_to_irq(gpio); if (irq < 0) { icnss_pr_err("Invalid IRQ for early crash indication %u\n", irq); return; } ret = request_irq(irq, fw_crash_indication_handler, IRQF_TRIGGER_RISING, "wlanfw-early-crash-ind", priv); if (ret < 0) { icnss_pr_err("Unable to register for early crash indication IRQ handler %d", irq); return; } icnss_pr_dbg("FW crash indication handler registered\n"); } int icnss_call_driver_uevent(struct icnss_priv *priv, Loading Loading @@ -733,7 +779,7 @@ static int icnss_driver_event_server_arrive(void *data) wlfw_dynamic_feature_mask_send_sync_msg(penv, dynamic_feature_mask); icnss_register_force_error_fatal(penv); register_fw_error_notifications(penv); return ret; Loading Loading @@ -825,6 +871,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_call_driver_shutdown(priv); clear_bit(ICNSS_PD_RESTART, &priv->state); priv->early_crash_ind = false; if (!priv->ops || !priv->ops->reinit) goto out; Loading Loading @@ -979,7 +1026,7 @@ static int icnss_fw_crashed(struct icnss_priv *priv, if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (event_data->fw_rejuvenate) if (event_data && event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); return 0; Loading @@ -994,6 +1041,12 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) goto out; 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); goto out; } if (test_bit(ICNSS_PD_RESTART, &priv->state) && event_data->crashed) { icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n", event_data->crashed, priv->state); Loading @@ -1015,6 +1068,25 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, return ret; } static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv, void *data) { int ret = 0; if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) goto out; priv->early_crash_ind = true; icnss_fw_crashed(priv, NULL); out: kfree(data); icnss_ignore_fw_timeout(false); return ret; } static void icnss_driver_event_work(struct work_struct *work) { struct icnss_driver_event *event; Loading Loading @@ -1056,6 +1128,10 @@ static void icnss_driver_event_work(struct work_struct *work) ret = icnss_driver_event_pd_service_down(penv, event->data); break; case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND: ret = icnss_driver_event_early_crash_ind(penv, event->data); break; default: icnss_pr_err("Invalid Event type: %d", event->type); kfree(event); Loading drivers/soc/qcom/icnss_private.h +2 −0 Original line number Diff line number Diff line Loading @@ -111,6 +111,7 @@ enum icnss_driver_event_type { ICNSS_DRIVER_EVENT_REGISTER_DRIVER, ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND, ICNSS_DRIVER_EVENT_MAX, }; Loading Loading @@ -340,6 +341,7 @@ struct icnss_priv { bool bypass_s1_smmu; bool force_err_fatal; bool allow_recursive_recovery; bool early_crash_ind; u8 cause_for_rejuvenation; u8 requesting_sub_system; u16 line_number; Loading Loading
Documentation/devicetree/bindings/cnss/icnss.txt +2 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ Optional properties: - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory - qcom,gpio-force-fatal-error: SMP2P bit triggered by WLAN FW to force error fatal. - qcom,gpio-early-crash-ind: SMP2P bit triggered by WLAN FW to indicate FW is in assert. Example: Loading Loading @@ -61,4 +62,5 @@ Example: vdd-0.8-cx-mx-supply = <&pm8998_l5>; qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>; qcom,gpio-forced-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; };
arch/arm64/boot/dts/qcom/sm8150.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -3307,6 +3307,7 @@ <0 425 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x100000>; qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; qcom,smmu-s1-bypass; vdd-cx-mx-supply = <&pm855_l1>; Loading
drivers/soc/qcom/icnss.c +80 −4 Original line number Diff line number Diff line Loading @@ -272,6 +272,8 @@ static char *icnss_driver_event_to_str(enum icnss_driver_event_type type) return "UNREGISTER_DRIVER"; case ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN: return "PD_SERVICE_DOWN"; case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND: return "FW_EARLY_CRASH_IND"; case ICNSS_DRIVER_EVENT_MAX: return "EVENT_MAX"; } Loading Loading @@ -633,7 +635,24 @@ static irqreturn_t fw_error_fatal_handler(int irq, void *ctx) return IRQ_HANDLED; } static void icnss_register_force_error_fatal(struct icnss_priv *priv) static irqreturn_t fw_crash_indication_handler(int irq, void *ctx) { struct icnss_priv *priv = ctx; icnss_pr_err("Received early crash indication from FW\n"); if (priv) { set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_fw_timeout(true); } icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND, 0, NULL); return IRQ_HANDLED; } static void register_fw_error_notifications(struct icnss_priv *priv) { int gpio, irq, ret; Loading @@ -656,11 +675,38 @@ static void icnss_register_force_error_fatal(struct icnss_priv *priv) ret = request_irq(irq, fw_error_fatal_handler, IRQF_TRIGGER_RISING, "wlanfw-err", priv); if (ret < 0) { icnss_pr_err("Unable to regiser for error fatal IRQ handler %d", icnss_pr_err("Unable to register for error fatal IRQ handler %d", irq); return; } icnss_pr_dbg("FW force error fatal handler registered\n"); if (!of_find_property(priv->pdev->dev.of_node, "qcom,gpio-early-crash-ind", NULL)) { icnss_pr_dbg("FW early crash indication handler not registered\n"); return; } gpio = of_get_named_gpio(priv->pdev->dev.of_node, "qcom,gpio-early-crash-ind", 0); if (!gpio_is_valid(gpio)) { icnss_pr_err("Invalid GPIO for early crash indication %d\n", gpio); return; } irq = gpio_to_irq(gpio); if (irq < 0) { icnss_pr_err("Invalid IRQ for early crash indication %u\n", irq); return; } ret = request_irq(irq, fw_crash_indication_handler, IRQF_TRIGGER_RISING, "wlanfw-early-crash-ind", priv); if (ret < 0) { icnss_pr_err("Unable to register for early crash indication IRQ handler %d", irq); return; } icnss_pr_dbg("FW crash indication handler registered\n"); } int icnss_call_driver_uevent(struct icnss_priv *priv, Loading Loading @@ -733,7 +779,7 @@ static int icnss_driver_event_server_arrive(void *data) wlfw_dynamic_feature_mask_send_sync_msg(penv, dynamic_feature_mask); icnss_register_force_error_fatal(penv); register_fw_error_notifications(penv); return ret; Loading Loading @@ -825,6 +871,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_call_driver_shutdown(priv); clear_bit(ICNSS_PD_RESTART, &priv->state); priv->early_crash_ind = false; if (!priv->ops || !priv->ops->reinit) goto out; Loading Loading @@ -979,7 +1026,7 @@ static int icnss_fw_crashed(struct icnss_priv *priv, if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (event_data->fw_rejuvenate) if (event_data && event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); return 0; Loading @@ -994,6 +1041,12 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) goto out; 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); goto out; } if (test_bit(ICNSS_PD_RESTART, &priv->state) && event_data->crashed) { icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n", event_data->crashed, priv->state); Loading @@ -1015,6 +1068,25 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, return ret; } static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv, void *data) { int ret = 0; if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) goto out; priv->early_crash_ind = true; icnss_fw_crashed(priv, NULL); out: kfree(data); icnss_ignore_fw_timeout(false); return ret; } static void icnss_driver_event_work(struct work_struct *work) { struct icnss_driver_event *event; Loading Loading @@ -1056,6 +1128,10 @@ static void icnss_driver_event_work(struct work_struct *work) ret = icnss_driver_event_pd_service_down(penv, event->data); break; case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND: ret = icnss_driver_event_early_crash_ind(penv, event->data); break; default: icnss_pr_err("Invalid Event type: %d", event->type); kfree(event); Loading
drivers/soc/qcom/icnss_private.h +2 −0 Original line number Diff line number Diff line Loading @@ -111,6 +111,7 @@ enum icnss_driver_event_type { ICNSS_DRIVER_EVENT_REGISTER_DRIVER, ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND, ICNSS_DRIVER_EVENT_MAX, }; Loading Loading @@ -340,6 +341,7 @@ struct icnss_priv { bool bypass_s1_smmu; bool force_err_fatal; bool allow_recursive_recovery; bool early_crash_ind; u8 cause_for_rejuvenation; u8 requesting_sub_system; u16 line_number; Loading