Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b5e299a authored by Sameer Thalappil's avatar Sameer Thalappil
Browse files

icnss: Add support for early assert indication



When there is a FW assert, icnss receives the PD down
notification only after the PD dump is pushed to the filesystem.
And if there is a delay in pushing the dump, the notification is
delayed as well, that could result in various timeout in WLAN host
without knowing that FW is already asserted. So add support to send
FW assert early indication to host thru smp2p channel.

CRs-Fixed: 2185226
Change-Id: I470f17a31ae05685e7e3a4701b32ff792e14677e
Signed-off-by: default avatarSameer Thalappil <sameert@codeaurora.org>
parent dd5080ee
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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:

@@ -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>;
    };
+80 −4
Original line number Diff line number Diff line
@@ -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";
	}
@@ -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;

@@ -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,
@@ -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;

@@ -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;
@@ -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;
@@ -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);
@@ -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;
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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,
};

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