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

Commit f41dec67 authored by Raghavendra Rao Ananta's avatar Raghavendra Rao Ananta
Browse files

esoc: Add support for client hooks based on priority



Some subsystems/drivers require notifications from the esoc
driver as soon as the it powers on/off the modem.
For this, the clients cannot directly depend on the
SSR notifications.

Hence, adding support such that the clients who are
interested in listening to such events can register
themselves. Moreover, the order in which these notifications
are sent to the clients can be prioritized statically.

Also, a flexibilty is added such that the user-space
can get information, such as link-id, from the interested
client.

Change-Id: I8274f0fd5210b7d0186dddf63afd69fc98d2e110
Signed-off-by: default avatarRaghavendra Rao Ananta <rananta@codeaurora.org>
parent caebd597
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/workqueue.h>
#include <linux/reboot.h>
#include <linux/of.h>
#include <linux/esoc_client.h>
#include "esoc.h"
#include "mdm-dbg.h"

@@ -105,6 +106,39 @@ static void mdm_ssr_fn(struct work_struct *work)
	esoc_clink_request_ssr(mdm_drv->esoc_clink);
}

static void esoc_client_link_power_on(struct esoc_clink *esoc_clink,
							bool mdm_crashed)
{
	int i;
	struct esoc_client_hook *client_hook;

	dev_dbg(&esoc_clink->dev, "Calling power_on hooks\n");

	for (i = 0; i < ESOC_MAX_HOOKS; i++) {
		client_hook = esoc_clink->client_hook[i];
		if (client_hook && client_hook->esoc_link_power_on)
			client_hook->esoc_link_power_on(client_hook->priv,
							mdm_crashed);
	}
}

static void esoc_client_link_power_off(struct esoc_clink *esoc_clink,
							bool mdm_crashed)
{
	int i;
	struct esoc_client_hook *client_hook;

	dev_dbg(&esoc_clink->dev, "Calling power_off hooks\n");

	for (i = 0; i < ESOC_MAX_HOOKS; i++) {
		client_hook = esoc_clink->client_hook[i];
		if (client_hook && client_hook->esoc_link_power_off) {
			client_hook->esoc_link_power_off(client_hook->priv,
							mdm_crashed);
		}
	}
}

static void mdm_crash_shutdown(const struct subsys_desc *mdm_subsys)
{
	struct esoc_clink *esoc_clink =
@@ -134,6 +168,9 @@ static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys,
			 * to move to next stage
			 */
			return 0;

		esoc_client_link_power_off(esoc_clink, true);

		ret = clink_ops->cmd_exe(ESOC_PREPARE_DEBUG,
							esoc_clink);
		if (ret) {
@@ -159,6 +196,7 @@ static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys,
			return ret;
		}
		mdm_drv->mode = PWR_OFF;
		esoc_client_link_power_off(esoc_clink, false);
	}
	return 0;
}
@@ -185,6 +223,7 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
			dev_err(&esoc_clink->dev, "pwr on fail\n");
			return ret;
		}
		esoc_client_link_power_on(esoc_clink, false);
	} else if (mdm_drv->mode == IN_DEBUG) {
		ret = clink_ops->cmd_exe(ESOC_EXIT_DEBUG, esoc_clink);
		if (ret) {
@@ -197,6 +236,7 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
			dev_err(&esoc_clink->dev, "pwr on fail\n");
			return ret;
		}
		esoc_client_link_power_on(esoc_clink, true);
	}

	/*
+2 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/cdev.h>
#include <linux/completion.h>
#include <linux/esoc_ctrl.h>
#include <linux/esoc_client.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -89,6 +90,7 @@ struct esoc_clink {
	bool primary;
	bool statusline_not_a_powersource;
	bool userspace_handle_shutdown;
	struct esoc_client_hook *client_hook[ESOC_MAX_HOOKS];
};

/**
+64 −0
Original line number Diff line number Diff line
@@ -142,3 +142,67 @@ void notify_esoc_clients(struct esoc_clink *esoc_clink, unsigned long evt)
	spin_unlock_irqrestore(&notify_lock, flags);
}
EXPORT_SYMBOL(notify_esoc_clients);

int esoc_register_client_hook(struct esoc_desc *desc,
				struct esoc_client_hook *client_hook)
{
	int i;
	struct esoc_clink *esoc_clink;

	if (IS_ERR_OR_NULL(desc) || IS_ERR_OR_NULL(client_hook)) {
		pr_debug("%s: Invalid parameters\n", __func__);
		return -EINVAL;
	}

	esoc_clink = desc->priv;
	if (IS_ERR_OR_NULL(esoc_clink)) {
		pr_debug("%s: Invalid esoc link\n", __func__);
		return -EINVAL;
	}

	for (i = 0; i < ESOC_MAX_HOOKS; i++) {
		if (i == client_hook->prio &&
			esoc_clink->client_hook[i] == NULL) {
			esoc_clink->client_hook[i] = client_hook;
			dev_dbg(&esoc_clink->dev,
				"Client hook registration successful\n");
			return 0;
		}
	}

	dev_dbg(&esoc_clink->dev, "Client hook registration failed!\n");
	return -EINVAL;
}
EXPORT_SYMBOL(esoc_register_client_hook);

int esoc_unregister_client_hook(struct esoc_desc *desc,
				struct esoc_client_hook *client_hook)
{
	int i;
	struct esoc_clink *esoc_clink;

	if (IS_ERR_OR_NULL(desc) || IS_ERR_OR_NULL(client_hook)) {
		pr_debug("%s: Invalid parameters\n", __func__);
		return -EINVAL;
	}

	esoc_clink = desc->priv;
	if (IS_ERR_OR_NULL(esoc_clink)) {
		pr_debug("%s: Invalid esoc link\n", __func__);
		return -EINVAL;
	}

	for (i = 0; i < ESOC_MAX_HOOKS; i++) {
		if (i == client_hook->prio &&
			esoc_clink->client_hook[i] != NULL) {
			esoc_clink->client_hook[i] = NULL;
			dev_dbg(&esoc_clink->dev,
				"Client hook unregistration successful\n");
			return 0;
		}
	}

	dev_dbg(&esoc_clink->dev, "Client hook unregistration failed!\n");
	return -EINVAL;
}
EXPORT_SYMBOL(esoc_unregister_client_hook);
+47 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/esoc_client.h>
#include "esoc.h"

/**
@@ -172,6 +173,50 @@ void esoc_udev_handle_clink_evt(enum esoc_evt evt, struct esoc_eng *eng)
	wake_up_interruptible(&esoc_udev->evt_wait);
}

static int esoc_get_link_id(struct esoc_clink *esoc_clink,
						unsigned long arg)
{
	struct esoc_link_data link_data;
	struct esoc_client_hook *client_hook;
	struct esoc_link_data __user *user_arg;

	user_arg = (struct esoc_link_data __user *) arg;
	if (!user_arg) {
		dev_err(&esoc_clink->dev, "Missing argument for link id\n");
		return -EINVAL;
	}

	if (copy_from_user((void *) &link_data, user_arg, sizeof(*user_arg))) {
		dev_err(&esoc_clink->dev,
			"Unable to copy the data from the user\n");
		return -EFAULT;
	}

	if (link_data.prio < 0 || link_data.prio >= ESOC_MAX_HOOKS) {
		dev_err(&esoc_clink->dev, "Invalid client identifier passed\n");
		return -EINVAL;
	}

	client_hook = esoc_clink->client_hook[link_data.prio];
	if (client_hook && client_hook->esoc_link_get_id) {
		link_data.link_id =
		client_hook->esoc_link_get_id(client_hook->priv);

		if (copy_to_user((void *) user_arg, &link_data,
						sizeof(*user_arg))) {
			dev_err(&esoc_clink->dev,
				"Failed to send the data to the user\n");
			return -EFAULT;
		}

		return 0;
	}

	dev_err(&esoc_clink->dev,
			"Client hooks not registered for the device\n");
	return -EINVAL;
}

static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
						unsigned long arg)
{
@@ -246,6 +291,8 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
			put_user(evt, (unsigned int __user *)uarg);
		}
		return err;
	case ESOC_GET_LINK_ID:
		return esoc_get_link_id(esoc_clink, arg);
	default:
		return -EINVAL;
	};
+23 −0
Original line number Diff line number Diff line
@@ -16,6 +16,15 @@
#include <linux/esoc_ctrl.h>
#include <linux/notifier.h>

struct esoc_client_hook {
	char *name;
	void *priv;
	enum esoc_client_hook_prio prio;
	int (*esoc_link_power_on)(void *priv, bool mdm_crashed);
	void (*esoc_link_power_off)(void *priv, bool mdm_crashed);
	u64 (*esoc_link_get_id)(void *priv);
};

/*
 * struct esoc_desc: Describes an external soc
 * @name: external soc name
@@ -35,6 +44,10 @@ struct esoc_desc *devm_register_esoc_client(struct device *dev,
void devm_unregister_esoc_client(struct device *dev,
						struct esoc_desc *esoc_desc);
int esoc_register_client_notifier(struct notifier_block *nb);
int esoc_register_client_hook(struct esoc_desc *desc,
				struct esoc_client_hook *client_hook);
int esoc_unregister_client_hook(struct esoc_desc *desc,
				struct esoc_client_hook *client_hook);
#else
static inline struct esoc_desc *devm_register_esoc_client(struct device *dev,
							const char *name)
@@ -49,5 +62,15 @@ static inline int esoc_register_client_notifier(struct notifier_block *nb)
{
	return -EIO;
}
int esoc_register_client_hook(struct esoc_desc *desc,
				struct esoc_client_hook *client_hook)
{
	return -EIO;
}
int esoc_unregister_client_hook(struct esoc_desc *desc,
				struct esoc_client_hook *client_hook);
{
	return -EIO;
}
#endif
#endif
Loading