remoteproc: sysmon: Ensure remote notification ordering
[linux-2.6-microblaze.git] / drivers / remoteproc / qcom_sysmon.c
index 6c3275b..13284d9 100644 (file)
@@ -22,6 +22,9 @@ struct qcom_sysmon {
        struct rproc_subdev subdev;
        struct rproc *rproc;
 
+       int state;
+       struct mutex state_lock;
+
        struct list_head node;
 
        const char *name;
@@ -448,7 +451,10 @@ static int sysmon_prepare(struct rproc_subdev *subdev)
                .ssr_event = SSCTL_SSR_EVENT_BEFORE_POWERUP
        };
 
+       mutex_lock(&sysmon->state_lock);
+       sysmon->state = SSCTL_SSR_EVENT_BEFORE_POWERUP;
        blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event);
+       mutex_unlock(&sysmon->state_lock);
 
        return 0;
 }
@@ -472,20 +478,25 @@ static int sysmon_start(struct rproc_subdev *subdev)
                .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP
        };
 
+       mutex_lock(&sysmon->state_lock);
+       sysmon->state = SSCTL_SSR_EVENT_AFTER_POWERUP;
        blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event);
+       mutex_unlock(&sysmon->state_lock);
 
        mutex_lock(&sysmon_lock);
        list_for_each_entry(target, &sysmon_list, node) {
-               if (target == sysmon ||
-                   target->rproc->state != RPROC_RUNNING)
+               if (target == sysmon)
                        continue;
 
+               mutex_lock(&target->state_lock);
                event.subsys_name = target->name;
+               event.ssr_event = target->state;
 
                if (sysmon->ssctl_version == 2)
                        ssctl_send_event(sysmon, &event);
                else if (sysmon->ept)
                        sysmon_send_event(sysmon, &event);
+               mutex_unlock(&target->state_lock);
        }
        mutex_unlock(&sysmon_lock);
 
@@ -500,7 +511,10 @@ static void sysmon_stop(struct rproc_subdev *subdev, bool crashed)
                .ssr_event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN
        };
 
+       mutex_lock(&sysmon->state_lock);
+       sysmon->state = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN;
        blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event);
+       mutex_unlock(&sysmon->state_lock);
 
        /* Don't request graceful shutdown if we've crashed */
        if (crashed)
@@ -521,7 +535,10 @@ static void sysmon_unprepare(struct rproc_subdev *subdev)
                .ssr_event = SSCTL_SSR_EVENT_AFTER_SHUTDOWN
        };
 
+       mutex_lock(&sysmon->state_lock);
+       sysmon->state = SSCTL_SSR_EVENT_AFTER_SHUTDOWN;
        blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event);
+       mutex_unlock(&sysmon->state_lock);
 }
 
 /**
@@ -534,11 +551,10 @@ static int sysmon_notify(struct notifier_block *nb, unsigned long event,
                         void *data)
 {
        struct qcom_sysmon *sysmon = container_of(nb, struct qcom_sysmon, nb);
-       struct rproc *rproc = sysmon->rproc;
        struct sysmon_event *sysmon_event = data;
 
        /* Skip non-running rprocs and the originating instance */
-       if (rproc->state != RPROC_RUNNING ||
+       if (sysmon->state != SSCTL_SSR_EVENT_AFTER_POWERUP ||
            !strcmp(sysmon_event->subsys_name, sysmon->name)) {
                dev_dbg(sysmon->dev, "not notifying %s\n", sysmon->name);
                return NOTIFY_DONE;
@@ -591,6 +607,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
        init_completion(&sysmon->ind_comp);
        init_completion(&sysmon->shutdown_comp);
        mutex_init(&sysmon->lock);
+       mutex_init(&sysmon->state_lock);
 
        sysmon->shutdown_irq = of_irq_get_byname(sysmon->dev->of_node,
                                                 "shutdown-ack");