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

Commit 3166e4b3 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "icnss: Add support for force error fatal from WLAN FW"

parents 3173d171 6ce5178b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ Optional properties:
  - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs.
  - 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.

Example:

@@ -59,4 +60,5 @@ Example:
	qcom,smmu-s1-bypass;
	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>;
    };
+59 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/thread_info.h>
#include <linux/uaccess.h>
#include <linux/etherdevice.h>
#include <linux/of_gpio.h>
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/icnss.h>
#include <soc/qcom/secure_buffer.h>
@@ -607,6 +608,47 @@ int icnss_power_off(struct device *dev)
}
EXPORT_SYMBOL(icnss_power_off);

static irqreturn_t fw_error_fatal_handler(int irq, void *ctx)
{
	struct icnss_priv *priv = ctx;

	if (priv)
		priv->force_err_fatal = true;

	icnss_pr_err("Received force error fatal request from FW\n");

	return IRQ_HANDLED;
}

static void icnss_register_force_error_fatal(struct icnss_priv *priv)
{
	int gpio, irq, ret;

	if (!of_find_property(priv->pdev->dev.of_node,
				"qcom,gpio-force-fatal-error", NULL)) {
		icnss_pr_dbg("Error fatal smp2p handler not registered\n");
		return;
	}
	gpio = of_get_named_gpio(priv->pdev->dev.of_node,
				"qcom,gpio-force-fatal-error", 0);
	if (!gpio_is_valid(gpio)) {
		icnss_pr_err("Invalid GPIO for error fatal smp2p %d\n", gpio);
		return;
	}
	irq = gpio_to_irq(gpio);
	if (irq < 0) {
		icnss_pr_err("Invalid IRQ for error fatal smp2p %u\n", irq);
		return;
	}
	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",
				irq);
		return;
	}
	icnss_pr_dbg("FW force error fatal handler registered\n");
}

int icnss_call_driver_uevent(struct icnss_priv *priv,
				    enum icnss_uevent uevent, void *data)
@@ -678,6 +720,8 @@ 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);

	return ret;

err_setup_msa:
@@ -772,6 +816,12 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv)
	if (!priv->ops || !priv->ops->reinit)
		goto out;

	if (test_bit(ICNSS_FW_DOWN, &priv->state)) {
		icnss_pr_err("FW is in bad state, state: 0x%lx\n",
			     priv->state);
		goto out;
	}

	if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
		goto call_probe;

@@ -844,6 +894,12 @@ static int icnss_driver_event_register_driver(void *data)
	if (test_bit(SKIP_QMI, &quirks))
		set_bit(ICNSS_FW_READY, &penv->state);

	if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
		icnss_pr_err("FW is in bad state, state: 0x%lx\n",
			     penv->state);
		return -ENODEV;
	}

	if (!test_bit(ICNSS_FW_READY, &penv->state)) {
		icnss_pr_dbg("FW is not ready yet, state: 0x%lx\n",
			     penv->state);
@@ -952,6 +1008,9 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
		goto out;
	}

	if (priv->force_err_fatal)
		ICNSS_ASSERT(0);

	if (event_data->crashed)
		icnss_fw_crashed(priv, event_data);
	else
+1 −0
Original line number Diff line number Diff line
@@ -332,6 +332,7 @@ struct icnss_priv {
	atomic_t pm_count;
	struct ramdump_device *msa0_dump_dev;
	bool bypass_s1_smmu;
	bool force_err_fatal;
	u8 cause_for_rejuvenation;
	u8 requesting_sub_system;
	u16 line_number;