diff options
Diffstat (limited to 'arch/powerpc/platforms/powermac/pfunc_core.c')
-rw-r--r-- | arch/powerpc/platforms/powermac/pfunc_core.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index f08173b0f065..b117adbf9571 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -5,7 +5,6 @@ * FIXME: LOCKING !!! */ -#include <linux/config.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> @@ -546,7 +545,7 @@ 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) @@ -871,10 +870,17 @@ int pmf_register_irq_client(struct device_node *target, 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); + spin_unlock_irqrestore(&pmf_lock, flags); + client->func = func; mutex_unlock(&pmf_irq_mutex); @@ -885,12 +891,19 @@ EXPORT_SYMBOL_GPL(pmf_register_irq_client); void pmf_unregister_irq_client(struct pmf_irq_client *client) { struct pmf_function *func = client->func; + unsigned long flags; BUG_ON(func == NULL); + /* 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); mutex_unlock(&pmf_irq_mutex); |