#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/build_bug.h>
+#include <linux/cpu_pm.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
}
}
+static struct coresight_device *coresight_cpu_get_active_source(void)
+{
+ struct coresight_device *source;
+ bool is_active = false;
+
+ source = coresight_get_percpu_source_ref(smp_processor_id());
+ if (!source)
+ return NULL;
+
+ if (coresight_get_mode(source) != CS_MODE_DISABLED)
+ is_active = true;
+
+ coresight_put_percpu_source_ref(source);
+
+ /*
+ * It is expected to run in atomic context, so it cannot be preempted
+ * to disable the source. Here returns the active source pointer
+ * without concern that its state may change. Since the build path has
+ * taken a reference on the component, the source can be safely used
+ * by the caller.
+ */
+ return is_active ? source : NULL;
+}
+
+static int coresight_pm_is_needed(struct coresight_device *csdev)
+{
+ if (!csdev)
+ return 0;
+
+ /* pm_save_disable() and pm_restore_enable() must be paired */
+ if (coresight_ops(csdev)->pm_save_disable &&
+ coresight_ops(csdev)->pm_restore_enable)
+ return 1;
+
+ return 0;
+}
+
+static int coresight_pm_device_save(struct coresight_device *csdev)
+{
+ return coresight_ops(csdev)->pm_save_disable(csdev);
+}
+
+static void coresight_pm_device_restore(struct coresight_device *csdev)
+{
+ coresight_ops(csdev)->pm_restore_enable(csdev);
+}
+
+static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
+ void *v)
+{
+ struct coresight_device *csdev = coresight_cpu_get_active_source();
+
+ if (!coresight_pm_is_needed(csdev))
+ return NOTIFY_DONE;
+
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ if (coresight_pm_device_save(csdev))
+ return NOTIFY_BAD;
+ break;
+ case CPU_PM_EXIT:
+ case CPU_PM_ENTER_FAILED:
+ coresight_pm_device_restore(csdev);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block coresight_cpu_pm_nb = {
+ .notifier_call = coresight_cpu_pm_notify,
+};
+
+static int __init coresight_pm_setup(void)
+{
+ return cpu_pm_register_notifier(&coresight_cpu_pm_nb);
+}
+
+static void coresight_pm_cleanup(void)
+{
+ cpu_pm_unregister_notifier(&coresight_cpu_pm_nb);
+}
+
const struct bus_type coresight_bustype = {
.name = "coresight",
};
/* initialise the coresight syscfg API */
ret = cscfg_init();
+ if (ret)
+ goto exit_notifier;
+
+ ret = coresight_pm_setup();
if (!ret)
return 0;
+ cscfg_exit();
+exit_notifier:
atomic_notifier_chain_unregister(&panic_notifier_list,
&coresight_notifier);
exit_perf:
static void __exit coresight_exit(void)
{
+ coresight_pm_cleanup();
cscfg_exit();
atomic_notifier_chain_unregister(&panic_notifier_list,
&coresight_notifier);