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

Commit 65a9fe67 authored by Prasad Sodagudi's avatar Prasad Sodagudi Committed by Prakruthi Deepak Heragu
Browse files

soc: qcom: Refactor subsystem registration process



Restructure subsystem registration process and IRQ registration
step such that, both subsystem restart framework and secure pil
drivers should be able to handle all the asychronous events
coming from subsystem. If both subsystem restart framework
and secure pil drivers are not in proper state to handle
asychronous events from subsystem leading to kernel faults.

Change-Id: Iacda38a9d7d4aeb4549f45533c91791f096c3b1c
Signed-off-by: default avatarPrasad Sodagudi <psodagud@codeaurora.org>
Signed-off-by: default avatarPrakruthi Deepak Heragu <pheragu@codeaurora.org>
parent b38b5109
Loading
Loading
Loading
Loading
+0 −313
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/sysmon.h>
#include <linux/soc/qcom/smem_state.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <asm/current.h>
@@ -43,9 +42,6 @@
static uint disable_restart_work;
module_param(disable_restart_work, uint, 0644);

static int enable_debug;
module_param(enable_debug, int, 0644);

/* The maximum shutdown timeout is the product of MAX_LOOPS and DELAY_MS. */
#define SHUTDOWN_ACK_MAX_LOOPS	100
#define SHUTDOWN_ACK_DELAY_MS	100
@@ -176,7 +172,6 @@ struct restart_log {
 * @restart_order: order of other devices this devices restarts with
 * @crash_count: number of times the device has crashed
 * @do_ramdump_on_put: ramdump on subsystem_put() if true
 * @err_ready: completion variable to record error ready from subsystem
 * @crashed: indicates if subsystem has crashed
 * @notif_state: current state of subsystem in terms of subsys notifications
 */
@@ -200,7 +195,6 @@ struct subsys_device {
	bool do_ramdump_on_put;
	struct cdev char_dev;
	dev_t dev_no;
	struct completion err_ready;
	enum crash_status crashed;
	int notif_state;
	struct list_head list;
@@ -211,12 +205,6 @@ static struct subsys_device *to_subsys(struct device *d)
	return container_of(d, struct subsys_device, dev);
}

void complete_err_ready(struct subsys_device *subsys)
{
	complete(&subsys->err_ready);
}
EXPORT_SYMBOL(complete_err_ready);

static struct subsys_tracking *subsys_get_track(struct subsys_device *subsys)
{
	struct subsys_soc_restart_order *order = subsys->restart_order;
@@ -637,62 +625,6 @@ static void notify_each_subsys_device(struct subsys_device **list,
	}
}

static void enable_all_irqs(struct subsys_device *dev)
{
	if (dev->desc->err_ready_irq)
		enable_irq(dev->desc->err_ready_irq);
	if (dev->desc->wdog_bite_irq && dev->desc->wdog_bite_handler) {
		enable_irq(dev->desc->wdog_bite_irq);
		irq_set_irq_wake(dev->desc->wdog_bite_irq, 1);
	}
	if (dev->desc->err_fatal_irq && dev->desc->err_fatal_handler)
		enable_irq(dev->desc->err_fatal_irq);
	if (dev->desc->stop_ack_irq && dev->desc->stop_ack_handler)
		enable_irq(dev->desc->stop_ack_irq);
	if (dev->desc->shutdown_ack_irq && dev->desc->shutdown_ack_handler)
		enable_irq(dev->desc->shutdown_ack_irq);
	if (dev->desc->ramdump_disable_irq &&
			dev->desc->ramdump_disable_handler)
		enable_irq(dev->desc->ramdump_disable_irq);
	if (dev->desc->generic_irq && dev->desc->generic_handler) {
		enable_irq(dev->desc->generic_irq);
		irq_set_irq_wake(dev->desc->generic_irq, 1);
	}
}

static void disable_all_irqs(struct subsys_device *dev)
{
	if (dev->desc->err_ready_irq)
		disable_irq(dev->desc->err_ready_irq);
	if (dev->desc->wdog_bite_irq && dev->desc->wdog_bite_handler) {
		disable_irq(dev->desc->wdog_bite_irq);
		irq_set_irq_wake(dev->desc->wdog_bite_irq, 0);
	}
	if (dev->desc->err_fatal_irq && dev->desc->err_fatal_handler)
		disable_irq(dev->desc->err_fatal_irq);
	if (dev->desc->stop_ack_irq && dev->desc->stop_ack_handler)
		disable_irq(dev->desc->stop_ack_irq);
	if (dev->desc->shutdown_ack_irq && dev->desc->shutdown_ack_handler)
		disable_irq(dev->desc->shutdown_ack_irq);
	if (dev->desc->generic_irq && dev->desc->generic_handler) {
		disable_irq(dev->desc->generic_irq);
		irq_set_irq_wake(dev->desc->generic_irq, 0);
	}
}

static int wait_for_err_ready(struct subsys_device *subsys)
{
	/*
	 * If subsys is using generic_irq in which case err_ready_irq will be 0,
	 * don't return.
	 */
	if ((subsys->desc->generic_irq <= 0 && !subsys->desc->err_ready_irq) ||
				enable_debug == 1)
		return 0;

	return wait_for_completion_interruptible(&subsys->err_ready);
}

static int subsystem_shutdown(struct subsys_device *dev, void *data)
{
	const char *name = dev->desc->name;
@@ -712,7 +644,6 @@ static int subsystem_shutdown(struct subsys_device *dev, void *data)
	}
	dev->crash_count++;
	subsys_set_state(dev, SUBSYS_OFFLINE);
	disable_all_irqs(dev);

	return 0;
}
@@ -742,7 +673,6 @@ static int subsystem_powerup(struct subsys_device *dev, void *data)
	int ret;

	pr_info("[%s:%d]: Powering up %s\n", current->comm, current->pid, name);
	reinit_completion(&dev->err_ready);

	ret = dev->desc->powerup(dev->desc);
	if (ret < 0) {
@@ -759,9 +689,7 @@ static int subsystem_powerup(struct subsys_device *dev, void *data)
			pr_err("Powerup failure on %s\n", name);
		return ret;
	}
	enable_all_irqs(dev);

	ret = wait_for_err_ready(dev);
	if (ret) {
		notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
								NULL);
@@ -803,32 +731,12 @@ static int subsys_start(struct subsys_device *subsys)

	notify_each_subsys_device(&subsys, 1, SUBSYS_BEFORE_POWERUP,
								NULL);

	reinit_completion(&subsys->err_ready);
	ret = subsys->desc->powerup(subsys->desc);
	if (ret) {
		notify_each_subsys_device(&subsys, 1, SUBSYS_POWERUP_FAILURE,
									NULL);
		return ret;
	}
	enable_all_irqs(subsys);

	if (subsys->desc->is_not_loadable) {
		subsys_set_state(subsys, SUBSYS_ONLINE);
		return 0;
	}

	ret = wait_for_err_ready(subsys);
	if (ret) {
		/* pil-boot succeeded but we need to shutdown
		 * the device because error ready timed out.
		 */
		notify_each_subsys_device(&subsys, 1, SUBSYS_POWERUP_FAILURE,
									NULL);
		subsys->desc->shutdown(subsys->desc, false);
		disable_all_irqs(subsys);
		return ret;
	}
	subsys_set_state(subsys, SUBSYS_ONLINE);

	notify_each_subsys_device(&subsys, 1, SUBSYS_AFTER_POWERUP,
@@ -855,7 +763,6 @@ static void subsys_stop(struct subsys_device *subsys)

	subsys->desc->shutdown(subsys->desc, false);
	subsys_set_state(subsys, SUBSYS_OFFLINE);
	disable_all_irqs(subsys);
	notify_each_subsys_device(&subsys, 1, SUBSYS_AFTER_SHUTDOWN, NULL);
}

@@ -1351,19 +1258,6 @@ static void subsys_device_release(struct device *dev)
	ida_simple_remove(&subsys_ida, subsys->id);
	kfree(subsys);
}
static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
{
	struct subsys_device *subsys_dev = subsys;

	dev_info(subsys_dev->desc->dev,
		"Subsystem error monitoring/handling services are up\n");

	if (subsys_dev->desc->is_not_loadable)
		return IRQ_HANDLED;

	complete(&subsys_dev->err_ready);
	return IRQ_HANDLED;
}

static int subsys_char_device_add(struct subsys_device *subsys_dev)
{
@@ -1511,84 +1405,12 @@ static struct subsys_soc_restart_order *ssr_parse_restart_orders(struct
	return tmp;
}

static int __get_irq(struct subsys_desc *desc, const char *prop,
		unsigned int *irq)
{
	int irql = 0;
	struct device_node *dnode = desc->dev->of_node;

	if (of_property_match_string(dnode, "interrupt-names", prop) < 0)
		return -ENOENT;

	irql = of_irq_get_byname(dnode, prop);
	if (irql < 0) {
		pr_err("[%s]: Error getting IRQ \"%s\"\n", desc->name,
		prop);
		return irql;
	}
	*irq = irql;
	return 0;
}

static int __get_smem_state(struct subsys_desc *desc, const char *prop,
		int *smem_bit)
{
	struct device_node *dnode = desc->dev->of_node;

	if (of_find_property(dnode, "qcom,smem-states", NULL)) {
		desc->state = qcom_smem_state_get(desc->dev, prop, smem_bit);
		if (IS_ERR_OR_NULL(desc->state)) {
			pr_err("Could not get smem-states %s\n", prop);
			return PTR_ERR(desc->state);
		}
		return 0;
	}
	return -ENOENT;
}

static int subsys_parse_devicetree(struct subsys_desc *desc)
{
	struct subsys_soc_restart_order *order;
	int ret;
	struct platform_device *pdev = container_of(desc->dev,
					struct platform_device, dev);

	ret = __get_irq(desc, "qcom,err-fatal", &desc->err_fatal_irq);
	if (ret && ret != -ENOENT)
		return ret;

	ret = __get_irq(desc, "qcom,err-ready", &desc->err_ready_irq);
	if (ret && ret != -ENOENT)
		return ret;

	ret = __get_irq(desc, "qcom,stop-ack", &desc->stop_ack_irq);
	if (ret && ret != -ENOENT)
		return ret;

	ret = __get_irq(desc, "qcom,ramdump-disabled",
			&desc->ramdump_disable_irq);
	if (ret && ret != -ENOENT)
		return ret;

	ret = __get_irq(desc, "qcom,shutdown-ack", &desc->shutdown_ack_irq);
	if (ret && ret != -ENOENT)
		return ret;

	ret = __get_irq(desc, "qcom,wdog", &desc->wdog_bite_irq);
	if (ret && ret != -ENOENT)
		return ret;

	ret = __get_smem_state(desc, "qcom,force-stop", &desc->force_stop_bit);
	if (ret && ret != -ENOENT)
		return ret;

	if (of_property_read_bool(pdev->dev.of_node,
					"qcom,pil-generic-irq-handler")) {
		ret = platform_get_irq(pdev, 0);
		if (ret > 0)
			desc->generic_irq = ret;
	}

	desc->ignore_ssr_failure = of_property_read_bool(pdev->dev.of_node,
						"qcom,ignore-ssr-failure");

@@ -1610,130 +1432,6 @@ static int subsys_parse_devicetree(struct subsys_desc *desc)
	return 0;
}

static int subsys_setup_irqs(struct subsys_device *subsys)
{
	struct subsys_desc *desc = subsys->desc;
	int ret;

	if (desc->err_fatal_irq && desc->err_fatal_handler) {
		ret = devm_request_threaded_irq(desc->dev, desc->err_fatal_irq,
				NULL,
				desc->err_fatal_handler,
				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
				desc->name, desc);
		if (ret < 0) {
			dev_err(desc->dev, "[%s]: Unable to register error fatal IRQ handler: %d, irq is %d\n",
				desc->name, ret, desc->err_fatal_irq);
			return ret;
		}
		disable_irq(desc->err_fatal_irq);
	}

	if (desc->stop_ack_irq && desc->stop_ack_handler) {
		ret = devm_request_threaded_irq(desc->dev, desc->stop_ack_irq,
				NULL,
				desc->stop_ack_handler,
				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
				desc->name, desc);
		if (ret < 0) {
			dev_err(desc->dev, "[%s]: Unable to register stop ack handler: %d\n",
				desc->name, ret);
			return ret;
		}
		disable_irq(desc->stop_ack_irq);
	}

	if (desc->wdog_bite_irq && desc->wdog_bite_handler) {
		ret = devm_request_irq(desc->dev, desc->wdog_bite_irq,
			desc->wdog_bite_handler,
			IRQF_TRIGGER_RISING, desc->name, desc);
		if (ret < 0) {
			dev_err(desc->dev, "[%s]: Unable to register wdog bite handler: %d\n",
				desc->name, ret);
			return ret;
		}
		disable_irq(desc->wdog_bite_irq);
	}

	if (desc->shutdown_ack_irq && desc->shutdown_ack_handler) {
		ret = devm_request_threaded_irq(desc->dev,
				desc->shutdown_ack_irq,
				NULL,
				desc->shutdown_ack_handler,
				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
				desc->name, desc);
		if (ret < 0) {
			dev_err(desc->dev, "[%s]: Unable to register shutdown ack handler: %d\n",
				desc->name, ret);
			return ret;
		}
		disable_irq(desc->shutdown_ack_irq);
	}

	if (desc->ramdump_disable_irq && desc->ramdump_disable_handler) {
		ret = devm_request_threaded_irq(desc->dev,
				desc->ramdump_disable_irq,
				NULL,
				desc->ramdump_disable_handler,
				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
				desc->name, desc);
		if (ret < 0) {
			dev_err(desc->dev, "[%s]: Unable to register shutdown ack handler: %d\n",
				desc->name, ret);
			return ret;
		}
		disable_irq(desc->ramdump_disable_irq);
	}

	if (desc->generic_irq && desc->generic_handler) {
		ret = devm_request_irq(desc->dev, desc->generic_irq,
			desc->generic_handler,
			IRQF_TRIGGER_HIGH, desc->name, desc);
		if (ret < 0) {
			dev_err(desc->dev, "[%s]: Unable to register generic irq handler: %d\n",
				desc->name, ret);
			return ret;
		}
		disable_irq(desc->generic_irq);
	}

	if (desc->err_ready_irq) {
		ret = devm_request_threaded_irq(desc->dev,
					desc->err_ready_irq,
					NULL,
					subsys_err_ready_intr_handler,
					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
					"error_ready_interrupt", subsys);
		if (ret < 0) {
			dev_err(desc->dev,
				"[%s]: Unable to register err ready handler\n",
				desc->name);
			return ret;
		}
		disable_irq(desc->err_ready_irq);
	}

	return 0;
}

static void subsys_free_irqs(struct subsys_device *subsys)
{
	struct subsys_desc *desc = subsys->desc;

	if (desc->err_fatal_irq && desc->err_fatal_handler)
		devm_free_irq(desc->dev, desc->err_fatal_irq, desc);
	if (desc->stop_ack_irq && desc->stop_ack_handler)
		devm_free_irq(desc->dev, desc->stop_ack_irq, desc);
	if (desc->shutdown_ack_irq && desc->shutdown_ack_handler)
		devm_free_irq(desc->dev, desc->shutdown_ack_irq, desc);
	if (desc->ramdump_disable_irq && desc->ramdump_disable_handler)
		devm_free_irq(desc->dev, desc->ramdump_disable_irq, desc);
	if (desc->wdog_bite_irq && desc->wdog_bite_handler)
		devm_free_irq(desc->dev, desc->wdog_bite_irq, desc);
	if (desc->err_ready_irq)
		devm_free_irq(desc->dev, desc->err_ready_irq, subsys);
}

struct subsys_device *subsys_register(struct subsys_desc *desc)
{
	struct subsys_device *subsys;
@@ -1775,7 +1473,6 @@ struct subsys_device *subsys_register(struct subsys_desc *desc)
	dev_set_name(&subsys->dev, "subsys%d", subsys->id);

	mutex_init(&subsys->track.lock);
	init_completion(&subsys->err_ready);

	ret = device_register(&subsys->dev);
	if (ret) {
@@ -1832,16 +1529,7 @@ struct subsys_device *subsys_register(struct subsys_desc *desc)
	list_add_tail(&subsys->list, &subsys_list);
	mutex_unlock(&subsys_list_lock);

	if (ofnode) {
		ret = subsys_setup_irqs(subsys);
		if (ret < 0)
			goto err_setup_irqs;
	}

	return subsys;
err_setup_irqs:
	if (subsys->desc->edge)
		sysmon_glink_unregister(desc);
err_sysmon_glink_register:
	sysmon_notifier_unregister(subsys->desc);
err_sysmon_notifier:
@@ -1873,7 +1561,6 @@ void subsys_unregister(struct subsys_device *subsys)
		mutex_unlock(&subsys_list_lock);

		if (device) {
			subsys_free_irqs(subsys);
			subsys_remove_restart_order(device);
		}
		mutex_lock(&subsys->track.lock);
+330 −35

File changed.

Preview size limit exceeded, changes collapsed.

+0 −15
Original line number Diff line number Diff line
@@ -69,8 +69,6 @@ struct subsys_notif_timeout {
 * @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep)
 * @ramdump: Collect a ramdump of the subsystem
 * @free_memory: Free the memory associated with this subsystem
 * @is_not_loadable: Indicate if subsystem firmware is not loadable via pil
 * framework
 * @no_auth: Set if subsystem does not rely on PIL to authenticate and bring
 * it out of reset
 * @ssctl_instance_id: Instance id used to connect with SSCTL service
@@ -95,20 +93,8 @@ struct subsys_desc {
	void (*crash_shutdown)(const struct subsys_desc *desc);
	int (*ramdump)(int need_dumps, const struct subsys_desc *desc);
	void (*free_memory)(const struct subsys_desc *desc);
	irqreturn_t (*err_fatal_handler)(int irq, void *dev_id);
	irqreturn_t (*stop_ack_handler)(int irq, void *dev_id);
	irqreturn_t (*shutdown_ack_handler)(int irq, void *dev_id);
	irqreturn_t (*ramdump_disable_handler)(int irq, void *dev_id);
	irqreturn_t (*wdog_bite_handler)(int irq, void *dev_id);
	irqreturn_t (*generic_handler)(int irq, void *dev_id);
	struct completion shutdown_ack;
	int is_not_loadable;
	int err_fatal_gpio;
	unsigned int err_fatal_irq;
	unsigned int err_ready_irq;
	unsigned int stop_ack_irq;
	unsigned int wdog_bite_irq;
	unsigned int generic_irq;
	int force_stop_bit;
	int ramdump_disable_irq;
	int shutdown_ack_irq;
@@ -164,7 +150,6 @@ extern enum crash_status subsys_get_crash_status(struct subsys_device *dev);
void notify_proxy_vote(struct device *device);
void notify_proxy_unvote(struct device *device);
void notify_before_auth_and_reset(struct device *device);
void complete_err_ready(struct subsys_device *subsys);
static inline void complete_shutdown_ack(struct subsys_desc *desc)
{
	complete(&desc->shutdown_ack);