diff options
Diffstat (limited to 'arch/powerpc/platforms/powermac/pfunc_core.c')
| -rw-r--r-- | arch/powerpc/platforms/powermac/pfunc_core.c | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index 356a739e52b..43075081721 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -5,14 +5,13 @@ * FIXME: LOCKING !!! */ -#include <linux/config.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/spinlock.h> +#include <linux/slab.h> #include <linux/module.h> +#include <linux/mutex.h> -#include <asm/semaphore.h> #include <asm/prom.h> #include <asm/pmac_pfunc.h> @@ -20,7 +19,13 @@ #define LOG_PARSE(fmt...) #define LOG_ERROR(fmt...) printk(fmt) #define LOG_BLOB(t,b,c) + +#undef DEBUG +#ifdef DEBUG #define DBG(fmt...) printk(fmt) +#else +#define DBG(fmt...) +#endif /* Command numbers */ #define PMF_CMD_LIST 0 @@ -539,7 +544,8 @@ struct pmf_device { }; static LIST_HEAD(pmf_devices); -static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(pmf_lock); +static DEFINE_MUTEX(pmf_irq_mutex); static void pmf_release_device(struct kref *kref) { @@ -679,14 +685,13 @@ static int pmf_add_functions(struct pmf_device *dev, void *driverdata) int count = 0; for (pp = dev->node->properties; pp != 0; pp = pp->next) { - char *name; + const char *name; if (strncmp(pp->name, PP_PREFIX, plen) != 0) continue; name = pp->name + plen; if (strlen(name) && pp->length >= 12) count += pmf_add_function_prop(dev, driverdata, name, - (u32 *)pp->value, - pp->length); + pp->value, pp->length); } return count; } @@ -806,14 +811,15 @@ struct pmf_function *__pmf_find_function(struct device_node *target, struct pmf_device *dev; struct pmf_function *func, *result = NULL; char fname[64]; - u32 *prop, ph; + const u32 *prop; + u32 ph; /* * Look for a "platform-*" function reference. If we can't find * one, then we fallback to a direct call attempt */ snprintf(fname, 63, "platform-%s", name); - prop = (u32 *)get_property(target, fname, NULL); + prop = of_get_property(target, fname, NULL); if (prop == NULL) goto find_it; ph = *prop; @@ -830,21 +836,24 @@ struct pmf_function *__pmf_find_function(struct device_node *target, return NULL; find_it: dev = pmf_find_device(actor); - if (dev == NULL) - return NULL; + if (dev == NULL) { + result = NULL; + goto out; + } list_for_each_entry(func, &dev->functions, link) { if (name && strcmp(name, func->name)) continue; - if (func->phandle && target->node != func->phandle) + if (func->phandle && target->phandle != func->phandle) continue; if ((func->flags & flags) == 0) continue; result = func; break; } - of_node_put(actor); pmf_put_device(dev); +out: + of_node_put(actor); return result; } @@ -858,16 +867,25 @@ int pmf_register_irq_client(struct device_node *target, spin_lock_irqsave(&pmf_lock, flags); func = __pmf_find_function(target, name, PMF_FLAGS_INT_GEN); - if (func == NULL) { - spin_unlock_irqrestore(&pmf_lock, flags); + if (func) + func = pmf_get_function(func); + spin_unlock_irqrestore(&pmf_lock, flags); + if (func == NULL) return -ENODEV; - } + + /* guard against manipulations of list */ + mutex_lock(&pmf_irq_mutex); if (list_empty(&func->irq_clients)) func->dev->handlers->irq_enable(func); + + /* guard against pmf_do_irq while changing list */ + spin_lock_irqsave(&pmf_lock, flags); list_add(&client->link, &func->irq_clients); - client->func = func; spin_unlock_irqrestore(&pmf_lock, flags); + client->func = func; + mutex_unlock(&pmf_irq_mutex); + return 0; } EXPORT_SYMBOL_GPL(pmf_register_irq_client); @@ -879,12 +897,19 @@ void pmf_unregister_irq_client(struct pmf_irq_client *client) BUG_ON(func == NULL); - spin_lock_irqsave(&pmf_lock, flags); + /* guard against manipulations of list */ + mutex_lock(&pmf_irq_mutex); client->func = NULL; + + /* guard against pmf_do_irq while changing list */ + spin_lock_irqsave(&pmf_lock, flags); list_del(&client->link); + spin_unlock_irqrestore(&pmf_lock, flags); + if (list_empty(&func->irq_clients)) func->dev->handlers->irq_disable(func); - spin_unlock_irqrestore(&pmf_lock, flags); + mutex_unlock(&pmf_irq_mutex); + pmf_put_function(func); } EXPORT_SYMBOL_GPL(pmf_unregister_irq_client); |
