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

Commit 8fc75829 authored by Anurag Chouhan's avatar Anurag Chouhan
Browse files

icnss: Update the smp2p node parsing



As the architecture of the smp2p node is changed, the parsing
of the node to get the irq number need to be updated.
This change takes care of the parsing of the DT node to get
smp2p interrupts and reqister for the threaded irq.

Change-Id: I108aab009eb6bbebb1117fcf46693c801260846c
Signed-off-by: default avatarAnurag Chouhan <achouhan@codeaurora.org>
parent 9e77bc47
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -29,10 +29,13 @@ 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.
  - qcom,gpio-early-crash-ind: SMP2P bit triggered by WLAN FW to indicate FW is in assert.
  - qcom,hyp_disabled: Boolean context flag to disable hyperviser

WLAN SMP2P sub nodes

  - qcom,smp2p_map_wlan_1_in - represents the in smp2p to
				  wlan driver from modem.

Example:

    qcom,icnss@0a000000 {
@@ -62,7 +65,11 @@ 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>;
	qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>;
	qcom,hyp_disabled;
	qcom,smp2p_map_wlan_1_in {
		interrupts-extended = <&smp2p_wlan_1_in 0 0>,
			<&smp2p_wlan_1_in 1 0>;
		interrupt-names = "qcom,smp2p-force-fatal-error",
			"qcom,smp2p-early-crash-ind";
	};
    };
+75 −40
Original line number Diff line number Diff line
@@ -36,7 +36,8 @@
#include <linux/thread_info.h>
#include <linux/uaccess.h>
#include <linux/etherdevice.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/soc/qcom/qmi.h>
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/icnss.h>
@@ -653,10 +654,17 @@ static irqreturn_t fw_error_fatal_handler(int irq, void *ctx)
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};

	icnss_pr_err("Received early crash indication from FW\n");

	if (priv) {
		if (test_bit(ICNSS_FW_READY, &priv->state) &&
		    !test_bit(ICNSS_DRIVER_UNLOADING, &priv->state)) {
			fw_down_data.crashed = true;
			icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN,
						 &fw_down_data);
		}
		set_bit(ICNSS_FW_DOWN, &priv->state);
		icnss_ignore_fw_timeout(true);
	}
@@ -667,61 +675,84 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
	return IRQ_HANDLED;
}

static void register_fw_error_notifications(struct icnss_priv *priv)
static void register_fw_error_notifications(struct device *dev)
{
	int gpio, irq, ret;
	struct icnss_priv *priv = dev_get_drvdata(dev);
	struct device_node *dev_node;
	int irq = 0, ret = 0;

	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);
	if (!priv)
		return;
	}
	irq = gpio_to_irq(gpio);
	if (irq < 0) {
		icnss_pr_err("Invalid IRQ for error fatal smp2p %u\n", irq);

	dev_node = of_find_node_by_name(NULL, "qcom,smp2p_map_wlan_1_in");
	if (!dev_node) {
		icnss_pr_err("Failed to get smp2p node for force-fatal-error\n");
		return;
	}
	ret = request_irq(irq, fw_error_fatal_handler,
			IRQF_TRIGGER_RISING, "wlanfw-err", priv);

	icnss_pr_dbg("smp2p node->name=%s\n", dev_node->name);

	if (strcmp("qcom,smp2p_map_wlan_1_in", dev_node->name) == 0) {
		ret = irq = of_irq_get_byname(dev_node,
					      "qcom,smp2p-force-fatal-error");
		if (ret < 0) {
		icnss_pr_err("Unable to register for error fatal IRQ handler %d",
			icnss_pr_err("Unable to get force-fatal-error irq %d\n",
				     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");
	ret = devm_request_threaded_irq(dev, irq, NULL, fw_error_fatal_handler,
					IRQF_TRIGGER_RISING, "wlanfw-err",
					priv);
	if (ret < 0) {
		icnss_pr_err("Unable to register for error fatal IRQ handler %d ret = %d",
			     irq, ret);
		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);
	icnss_pr_dbg("FW force error fatal handler registered irq = %d\n", irq);
	priv->fw_error_fatal_irq = irq;
}

static void register_early_crash_notifications(struct device *dev)
{
	struct icnss_priv *priv = dev_get_drvdata(dev);
	struct device_node *dev_node;
	int irq = 0, ret = 0;

	if (!priv)
		return;

	dev_node = of_find_node_by_name(NULL, "qcom,smp2p_map_wlan_1_in");
	if (!dev_node) {
		icnss_pr_err("Failed to get smp2p node for early-crash-ind\n");
		return;
	}
	irq = gpio_to_irq(gpio);
	if (irq < 0) {
		icnss_pr_err("Invalid IRQ for early crash indication %u\n",

	icnss_pr_dbg("smp2p node->name=%s\n", dev_node->name);

	if (strcmp("qcom,smp2p_map_wlan_1_in", dev_node->name) == 0) {
		ret = irq = of_irq_get_byname(dev_node,
					      "qcom,smp2p-early-crash-ind");
		if (ret < 0) {
			icnss_pr_err("Unable to get early-crash-ind irq %d\n",
				     irq);
			return;
		}
	ret = request_irq(irq, fw_crash_indication_handler,
			IRQF_TRIGGER_RISING, "wlanfw-early-crash-ind", priv);
	}

	ret = devm_request_threaded_irq(dev, irq, NULL,
					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);
		icnss_pr_err("Unable to register for early crash indication IRQ handler %d ret = %d",
			     irq, ret);
		return;
	}
	icnss_pr_dbg("FW crash indication handler registered\n");
	icnss_pr_dbg("FW crash indication handler registered irq = %d\n", irq);
	priv->fw_early_crash_irq = irq;
}

int icnss_call_driver_uevent(struct icnss_priv *priv,
@@ -794,7 +825,11 @@ static int icnss_driver_event_server_arrive(void *data)
	wlfw_dynamic_feature_mask_send_sync_msg(penv,
						dynamic_feature_mask);

	register_fw_error_notifications(penv);
	if (!penv->fw_error_fatal_irq)
		register_fw_error_notifications(&penv->pdev->dev);

	if (!penv->fw_early_crash_irq)
		register_early_crash_notifications(&penv->pdev->dev);

	return ret;

+2 −0
Original line number Diff line number Diff line
@@ -348,6 +348,8 @@ struct icnss_priv {
	u16 line_number;
	struct mutex dev_lock;
	bool is_hyp_disabled;
	uint32_t fw_error_fatal_irq;
	uint32_t fw_early_crash_irq;
	char function_name[WLFW_FUNCTION_NAME_LEN + 1];
};