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

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

Merge "esoc: Fix irq unbalance wake disable warning"

parents 2e31fcf8 ce5f7bfe
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -110,6 +110,10 @@ Optional driver parameters:
			   on behalf of the subsystem driver.
- qcom,mdm-link-info: a string indicating additional info about the physical link.
			For example: "devID_domain.bus.slot" in case of PCIe.
- qcom,mdm-auto-boot: Boolean. To indicate this instance of esoc boots independently.
- qcom,mdm-statusline-not-a-powersource: Boolean. If set, status line to esoc device is not a
		power source.
- qcom,mdm-userspace-handle-shutdown: Boolean. If set, userspace handles shutdown requests.

Example:
	mdm0: qcom,mdm0 {
+75 −22
Original line number Diff line number Diff line
@@ -88,12 +88,10 @@ static void mdm_enable_irqs(struct mdm_ctrl *mdm)
		return;
	if (mdm->irq_mask & IRQ_ERRFATAL) {
		enable_irq(mdm->errfatal_irq);
		irq_set_irq_wake(mdm->errfatal_irq, 1);
		mdm->irq_mask &= ~IRQ_ERRFATAL;
	}
	if (mdm->irq_mask & IRQ_STATUS) {
		enable_irq(mdm->status_irq);
		irq_set_irq_wake(mdm->status_irq, 1);
		mdm->irq_mask &= ~IRQ_STATUS;
	}
	if (mdm->irq_mask & IRQ_PBLRDY) {
@@ -107,12 +105,10 @@ static void mdm_disable_irqs(struct mdm_ctrl *mdm)
	if (!mdm)
		return;
	if (!(mdm->irq_mask & IRQ_ERRFATAL)) {
		irq_set_irq_wake(mdm->errfatal_irq, 0);
		disable_irq_nosync(mdm->errfatal_irq);
		mdm->irq_mask |= IRQ_ERRFATAL;
	}
	if (!(mdm->irq_mask & IRQ_STATUS)) {
		irq_set_irq_wake(mdm->status_irq, 0);
		disable_irq_nosync(mdm->status_irq);
		mdm->irq_mask |= IRQ_STATUS;
	}
@@ -179,27 +175,49 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc)
	struct device *dev = mdm->dev;
	int ret;
	bool graceful_shutdown = false;
	u32 status, err_fatal;

	switch (cmd) {
	case ESOC_PWR_ON:
		if (esoc->auto_boot) {
			/*
			 * If esoc has already booted, we would have missed
			 * status change interrupt. Read status and err_fatal
			 * signals to arrive at the state of esoc.
			 */
			esoc->clink_ops->get_status(&status, esoc);
			esoc->clink_ops->get_err_fatal(&err_fatal, esoc);
			if (err_fatal)
				return -EIO;
			if (status && !mdm->ready) {
				mdm->ready = true;
				esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc);
			}
		}
		gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
		mdm_enable_irqs(mdm);
		mdm->init = 1;
		mdm_do_first_power_on(mdm);
		mdm_enable_irqs(mdm);
		break;
	case ESOC_PWR_OFF:
		mdm_disable_irqs(mdm);
		mdm->debug = 0;
		mdm->ready = false;
		mdm->trig_cnt = 0;
		if (esoc->primary)
			break;
		graceful_shutdown = true;
		if (!esoc->userspace_handle_shutdown) {
			ret = sysmon_send_shutdown(&esoc->subsys);
			if (ret) {
			dev_err(mdm->dev, "sysmon shutdown fail, ret = %d\n",
									ret);
				dev_err(mdm->dev,
				 "sysmon shutdown fail, ret = %d\n", ret);
				graceful_shutdown = false;
				goto force_poff;
			}
		} else {
			esoc_clink_queue_request(ESOC_REQ_SEND_SHUTDOWN, esoc);
		}
		dev_dbg(mdm->dev, "Waiting for status gpio go low\n");
		status_down = false;
		end_time = jiffies + msecs_to_jiffies(10000);
@@ -229,11 +247,16 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc)
				esoc->subsys.sysmon_shutdown_ret);
		}

		if (esoc->primary)
			break;
		/*
		 * Force a shutdown of the mdm. This is required in order
		 * to prevent the mdm from immediately powering back on
		 * after the shutdown
		 * after the shutdown. Avoid setting status to 0, if line is
		 * monitored by multiple mdms(might be wrongly interpreted as
		 * a primary crash).
		 */
		if (esoc->statusline_not_a_powersource == false)
			gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
		esoc_clink_queue_request(ESOC_REQ_SHUTDOWN, esoc);
		mdm_power_down(mdm);
@@ -250,9 +273,12 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc)
		 */
		mdm->ready = false;
		cancel_delayed_work(&mdm->mdm2ap_status_check_work);
		if (!mdm->esoc->auto_boot) {
			gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
		dev_dbg(mdm->dev, "set ap2mdm errfatal to force reset\n");
			dev_dbg(mdm->dev,
				"set ap2mdm errfatal to force reset\n");
			msleep(mdm->ramdump_delay_ms);
		}
		break;
	case ESOC_EXE_DEBUG:
		mdm->debug = 1;
@@ -380,6 +406,8 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc)
		status_down = false;
		dev_dbg(dev, "signal apq err fatal for graceful restart\n");
		gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
		if (esoc->primary)
			break;
		timeout = local_clock();
		do_div(timeout, NSEC_PER_MSEC);
		timeout += MDM_MODEM_TIMEOUT;
@@ -422,6 +450,7 @@ static irqreturn_t mdm_errfatal(int irq, void *dev_id)
	esoc = mdm->esoc;
	dev_err(dev, "%s: mdm sent errfatal interrupt\n",
					__func__);
	subsys_set_crash_status(esoc->subsys_dev, true);
	/* disable irq ?*/
	esoc_clink_evt_notify(ESOC_ERR_FATAL, esoc);
	return IRQ_HANDLED;
@@ -442,11 +471,26 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id)
		return IRQ_HANDLED;
	dev = mdm->dev;
	esoc = mdm->esoc;
	/*
	 * On auto boot devices, there is a possibility of receiving
	 * status change interrupt before esoc_clink structure is
	 * initialized. Ignore them.
	 */
	if (!esoc)
		return IRQ_HANDLED;
	value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS));
	if (value == 0 && mdm->ready) {
		dev_err(dev, "unexpected reset external modem\n");
		subsys_set_crash_status(esoc->subsys_dev, true);
		esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc);
	} else if (value == 1) {
		/*
		 * In auto_boot cases, bailout early if mdm
		 * is up already.
		 */
		if (esoc->auto_boot && mdm->ready)
			return IRQ_HANDLED;

		cancel_delayed_work(&mdm->mdm2ap_status_check_work);
		dev_dbg(dev, "status = 1: mdm is now ready\n");
		mdm->ready = true;
@@ -454,6 +498,8 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id)
		queue_work(mdm->mdm_queue, &mdm->mdm_status_work);
		if (mdm->get_restart_reason)
			queue_work(mdm->mdm_queue, &mdm->restart_reason_work);
		if (esoc->auto_boot)
			esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc);
	}
	return IRQ_HANDLED;
}
@@ -582,13 +628,21 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
						&mdm->ramdump_delay_ms);
	if (ret)
		mdm->ramdump_delay_ms = DEF_RAMDUMP_DELAY;
	/* Multilple gpio_request calls are allowed */
	/*
	 * In certain scenarios, multiple esoc devices are monitoring
	 * same AP2MDM_STATUS line. But only one of them will have a
	 * successful gpio_request call. Initialize gpio only if request
	 * succeeds.
	 */
	if (gpio_request(MDM_GPIO(mdm, AP2MDM_STATUS), "AP2MDM_STATUS"))
		dev_err(dev, "Failed to configure AP2MDM_STATUS gpio\n");
	/* Multilple gpio_request calls are allowed */
	else
		gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
	if (gpio_request(MDM_GPIO(mdm, AP2MDM_ERRFATAL), "AP2MDM_ERRFATAL"))
		dev_err(dev, "%s Failed to configure AP2MDM_ERRFATAL gpio\n",
			   __func__);
	else
		gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
	if (gpio_request(MDM_GPIO(mdm, MDM2AP_STATUS), "MDM2AP_STATUS")) {
		dev_err(dev, "%s Failed to configure MDM2AP_STATUS gpio\n",
			   __func__);
@@ -621,9 +675,6 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
		}
	}

	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);

	if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_CHNLRDY)))
		gpio_direction_output(MDM_GPIO(mdm, AP2MDM_CHNLRDY), 0);

@@ -646,6 +697,7 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
		goto errfatal_err;
	}
	mdm->errfatal_irq = irq;
	irq_set_irq_wake(mdm->errfatal_irq, 1);

errfatal_err:
	 /* status irq */
@@ -664,6 +716,7 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
		goto status_err;
	}
	mdm->status_irq = irq;
	irq_set_irq_wake(mdm->status_irq, 1);
status_err:
	if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) {
		irq =  platform_get_irq_byname(pdev, "plbrdy_irq");
+28 −8
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/reboot.h>
#include <linux/of.h>
#include "esoc.h"
#include "mdm-dbg.h"

@@ -74,7 +75,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt,
		break;
	case ESOC_UNEXPECTED_RESET:
	case ESOC_ERR_FATAL:
		if (mdm_drv->mode == CRASH)
		/*
		 * Modem can crash while we are waiting for boot_done during
		 * a subsystem_get(). Setting mode to CRASH will prevent a
		 * subsequent subsystem_get() from entering poweron ops. Avoid
		 * this by seting mode to CRASH only if device was up and
		 * running.
		 */
		if (mdm_drv->mode == CRASH || mdm_drv->mode != RUN)
			return;
		mdm_drv->mode = CRASH;
		queue_work(mdm_drv->mdm_queue, &mdm_drv->ssr_work);
@@ -164,8 +172,9 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
								subsys);
	struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink);
	const struct esoc_clink_ops * const clink_ops = esoc_clink->clink_ops;
	int timeout = INT_MAX;

	if (!esoc_req_eng_enabled(esoc_clink)) {
	if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) {
		dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n");
		wait_for_completion(&mdm_drv->req_eng_wait);
	}
@@ -190,8 +199,17 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
			return ret;
		}
	}
	wait_for_completion(&mdm_drv->boot_done);
	if (mdm_drv->boot_fail) {

	/*
	 * In autoboot case, it is possible that we can forever wait for
	 * boot completion, when esoc fails to boot. This is because there
	 * is no helper application which can alert esoc driver about boot
	 * failure. Prevent going to wait forever in such case.
	 */
	if (esoc_clink->auto_boot)
		timeout = 10 * HZ;
	ret = wait_for_completion_timeout(&mdm_drv->boot_done, timeout);
	if (mdm_drv->boot_fail || ret <= 0) {
		dev_err(&esoc_clink->dev, "booting failed\n");
		return -EIO;
	}
@@ -219,10 +237,12 @@ static int mdm_subsys_ramdumps(int want_dumps,

static int mdm_register_ssr(struct esoc_clink *esoc_clink)
{
	esoc_clink->subsys.shutdown = mdm_subsys_shutdown;
	esoc_clink->subsys.ramdump = mdm_subsys_ramdumps;
	esoc_clink->subsys.powerup = mdm_subsys_powerup;
	esoc_clink->subsys.crash_shutdown = mdm_crash_shutdown;
	struct subsys_desc *subsys = &esoc_clink->subsys;

	subsys->shutdown = mdm_subsys_shutdown;
	subsys->ramdump = mdm_subsys_ramdumps;
	subsys->powerup = mdm_subsys_powerup;
	subsys->crash_shutdown = mdm_crash_shutdown;
	return esoc_clink_register_ssr(esoc_clink);
}

+7 −1
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -68,6 +68,9 @@ static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
	struct device *dev = mdm->dev;

	dev_dbg(dev, "Powering on modem for the first time\n");
	if (mdm->esoc->auto_boot)
		return 0;

	mdm_toggle_soft_reset(mdm, false);
	/* Add a delay to allow PON sequence to complete*/
	mdelay(50);
@@ -134,6 +137,9 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm)

static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
{
	if (!gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET)))
		return;

	dev_dbg(mdm->dev, "Triggering mdm cold reset");
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
			!!mdm->soft_reset_inverted);
+10 −0
Original line number Diff line number Diff line
@@ -60,6 +60,12 @@ struct esoc_eng {
 * @subsys_desc: descriptor for subsystem restart
 * @subsys_dev: ssr device handle.
 * @np: device tree node for esoc_clink.
 * @auto_boot: boots independently.
 * @primary: primary esoc controls(reset/poweroff) all secondary
 *	 esocs, but not	otherway around.
 * @statusline_not_a_powersource: True if status line to esoc is not a
 *				power source.
 * @userspace_handle_shutdown: True if user space handles shutdown requests.
 */
struct esoc_clink {
	const char *name;
@@ -79,6 +85,10 @@ struct esoc_clink {
	struct subsys_desc subsys;
	struct subsys_device *subsys_dev;
	struct device_node *np;
	bool auto_boot;
	bool primary;
	bool statusline_not_a_powersource;
	bool userspace_handle_shutdown;
};

/**
Loading