aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2012-11-29 22:13:08 -0500
committerJon Medhurst <tixy@linaro.org>2013-04-29 09:43:15 +0100
commitf6863ac8241d0a31fb70faaa09fbb5e3394304ef (patch)
treec188a87183dc46668f53e26295684534a79e591c /drivers
parentf7f504c31c18cf4ac1bf35cdb946553c31f3af20 (diff)
misc: vexpress/spc: attempt to init the spc driver from vexpress_spc_check_loaded()
Even if it is initialized via early_INITCALL(), there are other pieces of code that also have to be initialized with early_initcall() and the relative call ordering may not always be satisfied. So try to initialize the SPC code when vexpress_spc_check_loaded() is called if that has not been done yet. Signed-off-by: Nicolas Pitre <nico@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/vexpress/arm-spc.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/drivers/misc/vexpress/arm-spc.c b/drivers/misc/vexpress/arm-spc.c
index 82ca8efcd17..0432e3d9506 100644
--- a/drivers/misc/vexpress/arm-spc.c
+++ b/drivers/misc/vexpress/arm-spc.c
@@ -538,14 +538,6 @@ int vexpress_spc_wfi_cpustat(int cluster)
}
EXPORT_SYMBOL_GPL(vexpress_spc_wfi_cpustat);
-static bool vexpress_spc_loaded;
-
-bool vexpress_spc_check_loaded(void)
-{
- return vexpress_spc_loaded;
-}
-EXPORT_SYMBOL_GPL(vexpress_spc_check_loaded);
-
irqreturn_t vexpress_spc_irq_handler(int irq, void *data)
{
struct vexpress_spc_drvdata *drv_data = data;
@@ -624,10 +616,12 @@ static int vexpress_spc_populate_opps(uint32_t cluster)
return ret;
}
-static int __init vexpress_spc_early_init(void)
+static int vexpress_spc_init(void)
{
struct device_node *node = of_find_compatible_node(NULL, NULL,
"arm,spc");
+ if (!node)
+ return -ENODEV;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
@@ -635,9 +629,7 @@ static int __init vexpress_spc_early_init(void)
return -ENOMEM;
}
- if (node)
- info->baseaddr = of_iomap(node, 0);
-
+ info->baseaddr = of_iomap(node, 0);
if (WARN_ON(!info->baseaddr)) {
kfree(info);
return -EIO;
@@ -684,11 +676,31 @@ static int __init vexpress_spc_early_init(void)
outer_clean_range(virt_to_phys(info), virt_to_phys(info + 1));
pr_info("vexpress_spc loaded at %p\n", info->baseaddr);
- vexpress_spc_loaded = true;
-
return 0;
}
+static int vexpress_spc_load_result = -EAGAIN;
+static DEFINE_MUTEX(vexpress_spc_loading);
+
+bool vexpress_spc_check_loaded(void)
+{
+ if (vexpress_spc_load_result != -EAGAIN)
+ return (vexpress_spc_load_result == 0);
+
+ mutex_lock(&vexpress_spc_loading);
+ if (vexpress_spc_load_result == -EAGAIN)
+ vexpress_spc_load_result = vexpress_spc_init();
+ mutex_unlock(&vexpress_spc_loading);
+ return (vexpress_spc_load_result == 0);
+}
+EXPORT_SYMBOL_GPL(vexpress_spc_check_loaded);
+
+static int __init vexpress_spc_early_init(void)
+{
+ vexpress_spc_check_loaded();
+ return vexpress_spc_load_result;
+}
+
early_initcall(vexpress_spc_early_init);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Serial Power Controller (SPC) support");