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

Commit 61713ccb authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: subsys_notif: Add support for early SSR notifications"

parents 9c4f7965 d561d4ae
Loading
Loading
Loading
Loading
+117 −0
Original line number Diff line number Diff line
@@ -21,10 +21,25 @@
#include <linux/slab.h>
#include <soc/qcom/subsystem_notif.h>

/**
 * The callbacks that are registered in this data structure as early
 * notification callbacks will be called as soon as the SSR framework is
 * informed that the subsystem has crashed. This means that these functions will
 * be invoked as part of an IRQ handler, and thus, will be called in an atomic
 * context. Therefore, functions that are registered as early notification
 * callback must obey to the same constraints as interrupt handlers
 * (i.e. these functions must not sleep or block, etc).
 */
struct subsys_early_notif_info {
	spinlock_t cb_lock;
	void (*early_notif_cb[NUM_EARLY_NOTIFS])(void *);
	void *data[NUM_EARLY_NOTIFS];
};

struct subsys_notif_info {
	char name[50];
	struct srcu_notifier_head subsys_notif_rcvr_list;
	struct subsys_early_notif_info early_notif_info;
	struct list_head list;
};

@@ -94,6 +109,105 @@ int subsys_notif_unregister_notifier(void *subsys_handle,
}
EXPORT_SYMBOL(subsys_notif_unregister_notifier);

void send_early_notifications(void *early_notif_handle)
{
	struct subsys_early_notif_info *early_info = early_notif_handle;
	unsigned long flags;
	unsigned int i;
	void (*notif_cb)(void *data);

	if (!early_notif_handle)
		return;

	spin_lock_irqsave(&early_info->cb_lock, flags);
	for (i = 0; i < NUM_EARLY_NOTIFS; i++) {
		notif_cb = early_info->early_notif_cb[i];
		if (notif_cb)
			notif_cb(early_info->data[i]);
	}
	spin_unlock_irqrestore(&early_info->cb_lock, flags);
}
EXPORT_SYMBOL(send_early_notifications);

static bool valid_early_notif(enum early_subsys_notif_type notif_type)
{
	return  notif_type >= 0 && notif_type < NUM_EARLY_NOTIFS;
}

/**
 * The early_notif_cb parameter must point to a function that conforms to the
 * same constraints placed upon interrupt handlers, as the function will be
 * called in an atomic context (i.e. these functions must not sleep or block).
 */
int subsys_register_early_notifier(const char *subsys_name,
				   enum early_subsys_notif_type notif_type,
				   void (*early_notif_cb)(void *), void *data)
{
	struct subsys_notif_info *subsys;
	struct subsys_early_notif_info *early_notif_info;
	unsigned long flags;
	int rc = 0;

	if (!subsys_name || !early_notif_cb || !valid_early_notif(notif_type))
		return -EINVAL;

	subsys = _notif_find_subsys(subsys_name);
	if (!subsys)
		return -EINVAL;

	early_notif_info = &subsys->early_notif_info;
	spin_lock_irqsave(&early_notif_info->cb_lock, flags);
	if (early_notif_info->early_notif_cb[notif_type]) {
		rc = -EEXIST;
		goto out;
	}
	early_notif_info->early_notif_cb[notif_type] = early_notif_cb;
	early_notif_info->data[notif_type] = data;
out:
	spin_unlock_irqrestore(&early_notif_info->cb_lock, flags);
	return rc;
}
EXPORT_SYMBOL(subsys_register_early_notifier);

int subsys_unregister_early_notifier(const char *subsys_name, enum
				     early_subsys_notif_type notif_type)
{
	struct subsys_notif_info *subsys;
	struct subsys_early_notif_info *early_notif_info;
	unsigned long flags;

	if (!subsys_name || !valid_early_notif(notif_type))
		return -EINVAL;

	subsys = _notif_find_subsys(subsys_name);
	if (!subsys)
		return -EINVAL;

	early_notif_info = &subsys->early_notif_info;
	spin_lock_irqsave(&early_notif_info->cb_lock, flags);
	early_notif_info->early_notif_cb[notif_type] = NULL;
	early_notif_info->data[notif_type] = NULL;
	spin_unlock_irqrestore(&early_notif_info->cb_lock, flags);
	return 0;
}
EXPORT_SYMBOL(subsys_unregister_early_notifier);

void *subsys_get_early_notif_info(const char *subsys_name)
{
	struct subsys_notif_info *subsys;

	if (!subsys_name)
		return ERR_PTR(-EINVAL);

	subsys = _notif_find_subsys(subsys_name);

	if (!subsys)
		return ERR_PTR(-EINVAL);

	return &subsys->early_notif_info;
}
EXPORT_SYMBOL(subsys_get_early_notif_info);

void *subsys_notif_add_subsys(const char *subsys_name)
{
	struct subsys_notif_info *subsys = NULL;
@@ -121,6 +235,9 @@ void *subsys_notif_add_subsys(const char *subsys_name)

	srcu_init_notifier_head(&subsys->subsys_notif_rcvr_list);

	memset(&subsys->early_notif_info, 0, sizeof(struct
						    subsys_early_notif_info));
	spin_lock_init(&subsys->early_notif_info.cb_lock);
	INIT_LIST_HEAD(&subsys->list);

	mutex_lock(&notif_lock);
+4 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ struct subsys_device {
	struct subsys_tracking track;

	void *notify;
	void *early_notify;
	struct device dev;
	struct module *owner;
	int count;
@@ -1218,6 +1219,8 @@ int subsystem_restart_dev(struct subsys_device *dev)

	name = dev->desc->name;

	send_early_notifications(dev->early_notify);

	/*
	 * If a system reboot/shutdown is underway, ignore subsystem errors.
	 * However, print a message so that we know that a subsystem behaved
@@ -1792,6 +1795,7 @@ struct subsys_device *subsys_register(struct subsys_desc *desc)
			sizeof(subsys->desc->fw_name));

	subsys->notify = subsys_notif_add_subsys(desc->name);
	subsys->early_notify = subsys_get_early_notif_info(desc->name);

	snprintf(subsys->wlname, sizeof(subsys->wlname), "ssr(%s)", desc->name);
	wakeup_source_init(&subsys->ssr_wlock, subsys->wlname);
+37 −0
Original line number Diff line number Diff line
@@ -25,6 +25,11 @@ enum subsys_notif_type {
	SUBSYS_NOTIF_TYPE_COUNT
};

enum early_subsys_notif_type {
	XPORT_LAYER_NOTIF,
	NUM_EARLY_NOTIFS
};

#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
/* Use the subsys_notif_register_notifier API to register for notifications for
 * a particular subsystem. This API will return a handle that can be used to
@@ -50,6 +55,14 @@ void *subsys_notif_add_subsys(const char *subsys_name);
int subsys_notif_queue_notification(void *subsys_handle,
					enum subsys_notif_type notif_type,
					void *data);
void *subsys_get_early_notif_info(const char *subsys_name);
int subsys_register_early_notifier(const char *subsys_name,
				   enum early_subsys_notif_type notif_type,
				   void (*early_notif_cb)(void *),
				   void *data);
int subsys_unregister_early_notifier(const char *subsys_name, enum
				     early_subsys_notif_type notif_type);
void send_early_notifications(void *early_notif_handle);
#else

static inline void *subsys_notif_register_notifier(
@@ -75,6 +88,30 @@ static inline int subsys_notif_queue_notification(void *subsys_handle,
{
	return 0;
}

static inline void *subsys_get_early_notif_info(const char *subsys_name)
{
	return NULL;
}

static inline int subsys_register_early_notifier(const char *subsys_name,
				   enum early_subsys_notif_type notif_type,
				   void (*early_notif_cb)(void *),
				   void *data)
{
	return -ENOTSUPP;
}

static inline int subsys_unregister_early_notifier(const char *subsys_name,
						   enum early_subsys_notif_type
						   notif_type)
{
	return -ENOTSUPP;
}

static inline void send_early_notifications(void *early_notif_handle)
{
}
#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */

#endif