diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2015-03-06 11:37:43 -0500 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2015-03-08 00:33:00 -0500 |
commit | 3e39e8f56c1c67cdd1e8f06da0d6b7c831818c76 (patch) | |
tree | b7332e00d00a4e1f1a13b01b8da7237b644e5eb0 | |
parent | e8137f4f5088d763ced1db82d3974336b76e1bd2 (diff) |
irqchip: gicv3-its: Fix unsafe locking reported by lockdep
When compiled with CONFIG_LOCKDEP, the kernel shouts badly, saying
that my locking is unsafe. I'm afraid the kernel is right:
CPU0 CPU1
---- ----
lock(&its->lock);
local_irq_disable();
lock(&irq_desc_lock_class);
lock(&its->lock);
<Interrupt>
lock(&irq_desc_lock_class);
*** DEADLOCK ***
The fix is to always take its->lock with interrupts disabled.
Reported-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Link: https://lkml.kernel.org/r/1425659870-11832-5-git-send-email-marc.zyngier@arm.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 46b9441b36bd..6850141d6524 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c | |||
@@ -416,13 +416,14 @@ static void its_send_single_command(struct its_node *its, | |||
416 | { | 416 | { |
417 | struct its_cmd_block *cmd, *sync_cmd, *next_cmd; | 417 | struct its_cmd_block *cmd, *sync_cmd, *next_cmd; |
418 | struct its_collection *sync_col; | 418 | struct its_collection *sync_col; |
419 | unsigned long flags; | ||
419 | 420 | ||
420 | raw_spin_lock(&its->lock); | 421 | raw_spin_lock_irqsave(&its->lock, flags); |
421 | 422 | ||
422 | cmd = its_allocate_entry(its); | 423 | cmd = its_allocate_entry(its); |
423 | if (!cmd) { /* We're soooooo screewed... */ | 424 | if (!cmd) { /* We're soooooo screewed... */ |
424 | pr_err_ratelimited("ITS can't allocate, dropping command\n"); | 425 | pr_err_ratelimited("ITS can't allocate, dropping command\n"); |
425 | raw_spin_unlock(&its->lock); | 426 | raw_spin_unlock_irqrestore(&its->lock, flags); |
426 | return; | 427 | return; |
427 | } | 428 | } |
428 | sync_col = builder(cmd, desc); | 429 | sync_col = builder(cmd, desc); |
@@ -442,7 +443,7 @@ static void its_send_single_command(struct its_node *its, | |||
442 | 443 | ||
443 | post: | 444 | post: |
444 | next_cmd = its_post_commands(its); | 445 | next_cmd = its_post_commands(its); |
445 | raw_spin_unlock(&its->lock); | 446 | raw_spin_unlock_irqrestore(&its->lock, flags); |
446 | 447 | ||
447 | its_wait_for_range_completion(its, cmd, next_cmd); | 448 | its_wait_for_range_completion(its, cmd, next_cmd); |
448 | } | 449 | } |
@@ -1037,8 +1038,9 @@ static void its_cpu_init_collection(void) | |||
1037 | static struct its_device *its_find_device(struct its_node *its, u32 dev_id) | 1038 | static struct its_device *its_find_device(struct its_node *its, u32 dev_id) |
1038 | { | 1039 | { |
1039 | struct its_device *its_dev = NULL, *tmp; | 1040 | struct its_device *its_dev = NULL, *tmp; |
1041 | unsigned long flags; | ||
1040 | 1042 | ||
1041 | raw_spin_lock(&its->lock); | 1043 | raw_spin_lock_irqsave(&its->lock, flags); |
1042 | 1044 | ||
1043 | list_for_each_entry(tmp, &its->its_device_list, entry) { | 1045 | list_for_each_entry(tmp, &its->its_device_list, entry) { |
1044 | if (tmp->device_id == dev_id) { | 1046 | if (tmp->device_id == dev_id) { |
@@ -1047,7 +1049,7 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id) | |||
1047 | } | 1049 | } |
1048 | } | 1050 | } |
1049 | 1051 | ||
1050 | raw_spin_unlock(&its->lock); | 1052 | raw_spin_unlock_irqrestore(&its->lock, flags); |
1051 | 1053 | ||
1052 | return its_dev; | 1054 | return its_dev; |
1053 | } | 1055 | } |
@@ -1057,6 +1059,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, | |||
1057 | { | 1059 | { |
1058 | struct its_device *dev; | 1060 | struct its_device *dev; |
1059 | unsigned long *lpi_map; | 1061 | unsigned long *lpi_map; |
1062 | unsigned long flags; | ||
1060 | void *itt; | 1063 | void *itt; |
1061 | int lpi_base; | 1064 | int lpi_base; |
1062 | int nr_lpis; | 1065 | int nr_lpis; |
@@ -1092,9 +1095,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, | |||
1092 | dev->device_id = dev_id; | 1095 | dev->device_id = dev_id; |
1093 | INIT_LIST_HEAD(&dev->entry); | 1096 | INIT_LIST_HEAD(&dev->entry); |
1094 | 1097 | ||
1095 | raw_spin_lock(&its->lock); | 1098 | raw_spin_lock_irqsave(&its->lock, flags); |
1096 | list_add(&dev->entry, &its->its_device_list); | 1099 | list_add(&dev->entry, &its->its_device_list); |
1097 | raw_spin_unlock(&its->lock); | 1100 | raw_spin_unlock_irqrestore(&its->lock, flags); |
1098 | 1101 | ||
1099 | /* Bind the device to the first possible CPU */ | 1102 | /* Bind the device to the first possible CPU */ |
1100 | cpu = cpumask_first(cpu_online_mask); | 1103 | cpu = cpumask_first(cpu_online_mask); |
@@ -1108,9 +1111,11 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, | |||
1108 | 1111 | ||
1109 | static void its_free_device(struct its_device *its_dev) | 1112 | static void its_free_device(struct its_device *its_dev) |
1110 | { | 1113 | { |
1111 | raw_spin_lock(&its_dev->its->lock); | 1114 | unsigned long flags; |
1115 | |||
1116 | raw_spin_lock_irqsave(&its_dev->its->lock, flags); | ||
1112 | list_del(&its_dev->entry); | 1117 | list_del(&its_dev->entry); |
1113 | raw_spin_unlock(&its_dev->its->lock); | 1118 | raw_spin_unlock_irqrestore(&its_dev->its->lock, flags); |
1114 | kfree(its_dev->itt); | 1119 | kfree(its_dev->itt); |
1115 | kfree(its_dev); | 1120 | kfree(its_dev); |
1116 | } | 1121 | } |