diff options
author | Jon Hunter <jonathanh@nvidia.com> | 2016-05-10 11:14:42 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2016-05-11 05:12:43 -0400 |
commit | dc9722cc57eba336038b2ade111436656c5a87d0 (patch) | |
tree | 733721c1e42a0256969b0f9a33f2d21c33f9b73d /drivers/irqchip/irq-gic.c | |
parent | c2baa2f3f42fc6ea302bb666889c5843986a19a3 (diff) |
irqchip/gic: Return an error if GIC initialisation fails
If the GIC initialisation fails, then currently we do not return an error
or clean-up afterwards. Although for root controllers, this failure may be
fatal anyway, for secondary controllers, it may not be fatal and so return
an error on failure and clean-up.
Update the functions gic_cpu_init() and gic_pm_init() to return an error
instead of calling BUG() and perform any necessary clean-up.
For non-banked GIC controllers, make sure that we free any memory
allocated if we fail to initialise the IRQ domain. Please note that
free_percpu() only frees memory if the pointer passed to it is not NULL
and so it is unnecessary to check if both pointers are valid or not.
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/irqchip/irq-gic.c')
-rw-r--r-- | drivers/irqchip/irq-gic.c | 99 |
1 files changed, 73 insertions, 26 deletions
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index a8cb86bea544..7cf138286442 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c | |||
@@ -467,7 +467,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) | |||
467 | writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL); | 467 | writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL); |
468 | } | 468 | } |
469 | 469 | ||
470 | static void gic_cpu_init(struct gic_chip_data *gic) | 470 | static int gic_cpu_init(struct gic_chip_data *gic) |
471 | { | 471 | { |
472 | void __iomem *dist_base = gic_data_dist_base(gic); | 472 | void __iomem *dist_base = gic_data_dist_base(gic); |
473 | void __iomem *base = gic_data_cpu_base(gic); | 473 | void __iomem *base = gic_data_cpu_base(gic); |
@@ -483,7 +483,9 @@ static void gic_cpu_init(struct gic_chip_data *gic) | |||
483 | /* | 483 | /* |
484 | * Get what the GIC says our CPU mask is. | 484 | * Get what the GIC says our CPU mask is. |
485 | */ | 485 | */ |
486 | BUG_ON(cpu >= NR_GIC_CPU_IF); | 486 | if (WARN_ON(cpu >= NR_GIC_CPU_IF)) |
487 | return -EINVAL; | ||
488 | |||
487 | cpu_mask = gic_get_cpumask(gic); | 489 | cpu_mask = gic_get_cpumask(gic); |
488 | gic_cpu_map[cpu] = cpu_mask; | 490 | gic_cpu_map[cpu] = cpu_mask; |
489 | 491 | ||
@@ -500,6 +502,8 @@ static void gic_cpu_init(struct gic_chip_data *gic) | |||
500 | 502 | ||
501 | writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); | 503 | writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); |
502 | gic_cpu_if_up(gic); | 504 | gic_cpu_if_up(gic); |
505 | |||
506 | return 0; | ||
503 | } | 507 | } |
504 | 508 | ||
505 | int gic_cpu_if_down(unsigned int gic_nr) | 509 | int gic_cpu_if_down(unsigned int gic_nr) |
@@ -713,26 +717,39 @@ static struct notifier_block gic_notifier_block = { | |||
713 | .notifier_call = gic_notifier, | 717 | .notifier_call = gic_notifier, |
714 | }; | 718 | }; |
715 | 719 | ||
716 | static void __init gic_pm_init(struct gic_chip_data *gic) | 720 | static int __init gic_pm_init(struct gic_chip_data *gic) |
717 | { | 721 | { |
718 | gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, | 722 | gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, |
719 | sizeof(u32)); | 723 | sizeof(u32)); |
720 | BUG_ON(!gic->saved_ppi_enable); | 724 | if (WARN_ON(!gic->saved_ppi_enable)) |
725 | return -ENOMEM; | ||
721 | 726 | ||
722 | gic->saved_ppi_active = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, | 727 | gic->saved_ppi_active = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, |
723 | sizeof(u32)); | 728 | sizeof(u32)); |
724 | BUG_ON(!gic->saved_ppi_active); | 729 | if (WARN_ON(!gic->saved_ppi_active)) |
730 | goto free_ppi_enable; | ||
725 | 731 | ||
726 | gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4, | 732 | gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4, |
727 | sizeof(u32)); | 733 | sizeof(u32)); |
728 | BUG_ON(!gic->saved_ppi_conf); | 734 | if (WARN_ON(!gic->saved_ppi_conf)) |
735 | goto free_ppi_active; | ||
729 | 736 | ||
730 | if (gic == &gic_data[0]) | 737 | if (gic == &gic_data[0]) |
731 | cpu_pm_register_notifier(&gic_notifier_block); | 738 | cpu_pm_register_notifier(&gic_notifier_block); |
739 | |||
740 | return 0; | ||
741 | |||
742 | free_ppi_active: | ||
743 | free_percpu(gic->saved_ppi_active); | ||
744 | free_ppi_enable: | ||
745 | free_percpu(gic->saved_ppi_enable); | ||
746 | |||
747 | return -ENOMEM; | ||
732 | } | 748 | } |
733 | #else | 749 | #else |
734 | static void __init gic_pm_init(struct gic_chip_data *gic) | 750 | static int __init gic_pm_init(struct gic_chip_data *gic) |
735 | { | 751 | { |
752 | return 0; | ||
736 | } | 753 | } |
737 | #endif | 754 | #endif |
738 | 755 | ||
@@ -1005,13 +1022,13 @@ static const struct irq_domain_ops gic_irq_domain_ops = { | |||
1005 | .unmap = gic_irq_domain_unmap, | 1022 | .unmap = gic_irq_domain_unmap, |
1006 | }; | 1023 | }; |
1007 | 1024 | ||
1008 | static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, | 1025 | static int __init __gic_init_bases(unsigned int gic_nr, int irq_start, |
1009 | void __iomem *dist_base, void __iomem *cpu_base, | 1026 | void __iomem *dist_base, void __iomem *cpu_base, |
1010 | u32 percpu_offset, struct fwnode_handle *handle) | 1027 | u32 percpu_offset, struct fwnode_handle *handle) |
1011 | { | 1028 | { |
1012 | irq_hw_number_t hwirq_base; | 1029 | irq_hw_number_t hwirq_base; |
1013 | struct gic_chip_data *gic; | 1030 | struct gic_chip_data *gic; |
1014 | int gic_irqs, irq_base, i; | 1031 | int gic_irqs, irq_base, i, ret; |
1015 | 1032 | ||
1016 | BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR); | 1033 | BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR); |
1017 | 1034 | ||
@@ -1026,7 +1043,7 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, | |||
1026 | gic->chip.irq_mask = gic_eoimode1_mask_irq; | 1043 | gic->chip.irq_mask = gic_eoimode1_mask_irq; |
1027 | gic->chip.irq_eoi = gic_eoimode1_eoi_irq; | 1044 | gic->chip.irq_eoi = gic_eoimode1_eoi_irq; |
1028 | gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity; | 1045 | gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity; |
1029 | gic->chip.name = "GICv2"; | 1046 | gic->chip.name = kasprintf(GFP_KERNEL, "GICv2"); |
1030 | } else { | 1047 | } else { |
1031 | gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr); | 1048 | gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr); |
1032 | } | 1049 | } |
@@ -1036,17 +1053,16 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, | |||
1036 | gic->chip.irq_set_affinity = gic_set_affinity; | 1053 | gic->chip.irq_set_affinity = gic_set_affinity; |
1037 | #endif | 1054 | #endif |
1038 | 1055 | ||
1039 | #ifdef CONFIG_GIC_NON_BANKED | 1056 | if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) { |
1040 | if (percpu_offset) { /* Frankein-GIC without banked registers... */ | 1057 | /* Frankein-GIC without banked registers... */ |
1041 | unsigned int cpu; | 1058 | unsigned int cpu; |
1042 | 1059 | ||
1043 | gic->dist_base.percpu_base = alloc_percpu(void __iomem *); | 1060 | gic->dist_base.percpu_base = alloc_percpu(void __iomem *); |
1044 | gic->cpu_base.percpu_base = alloc_percpu(void __iomem *); | 1061 | gic->cpu_base.percpu_base = alloc_percpu(void __iomem *); |
1045 | if (WARN_ON(!gic->dist_base.percpu_base || | 1062 | if (WARN_ON(!gic->dist_base.percpu_base || |
1046 | !gic->cpu_base.percpu_base)) { | 1063 | !gic->cpu_base.percpu_base)) { |
1047 | free_percpu(gic->dist_base.percpu_base); | 1064 | ret = -ENOMEM; |
1048 | free_percpu(gic->cpu_base.percpu_base); | 1065 | goto error; |
1049 | return; | ||
1050 | } | 1066 | } |
1051 | 1067 | ||
1052 | for_each_possible_cpu(cpu) { | 1068 | for_each_possible_cpu(cpu) { |
@@ -1058,9 +1074,8 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, | |||
1058 | } | 1074 | } |
1059 | 1075 | ||
1060 | gic_set_base_accessor(gic, gic_get_percpu_base); | 1076 | gic_set_base_accessor(gic, gic_get_percpu_base); |
1061 | } else | 1077 | } else { |
1062 | #endif | 1078 | /* Normal, sane GIC... */ |
1063 | { /* Normal, sane GIC... */ | ||
1064 | WARN(percpu_offset, | 1079 | WARN(percpu_offset, |
1065 | "GIC_NON_BANKED not enabled, ignoring %08x offset!", | 1080 | "GIC_NON_BANKED not enabled, ignoring %08x offset!", |
1066 | percpu_offset); | 1081 | percpu_offset); |
@@ -1110,8 +1125,10 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, | |||
1110 | hwirq_base, &gic_irq_domain_ops, gic); | 1125 | hwirq_base, &gic_irq_domain_ops, gic); |
1111 | } | 1126 | } |
1112 | 1127 | ||
1113 | if (WARN_ON(!gic->domain)) | 1128 | if (WARN_ON(!gic->domain)) { |
1114 | return; | 1129 | ret = -ENODEV; |
1130 | goto error; | ||
1131 | } | ||
1115 | 1132 | ||
1116 | if (gic_nr == 0) { | 1133 | if (gic_nr == 0) { |
1117 | /* | 1134 | /* |
@@ -1131,8 +1148,25 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, | |||
1131 | } | 1148 | } |
1132 | 1149 | ||
1133 | gic_dist_init(gic); | 1150 | gic_dist_init(gic); |
1134 | gic_cpu_init(gic); | 1151 | ret = gic_cpu_init(gic); |
1135 | gic_pm_init(gic); | 1152 | if (ret) |
1153 | goto error; | ||
1154 | |||
1155 | ret = gic_pm_init(gic); | ||
1156 | if (ret) | ||
1157 | goto error; | ||
1158 | |||
1159 | return 0; | ||
1160 | |||
1161 | error: | ||
1162 | if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) { | ||
1163 | free_percpu(gic->dist_base.percpu_base); | ||
1164 | free_percpu(gic->cpu_base.percpu_base); | ||
1165 | } | ||
1166 | |||
1167 | kfree(gic->chip.name); | ||
1168 | |||
1169 | return ret; | ||
1136 | } | 1170 | } |
1137 | 1171 | ||
1138 | void __init gic_init(unsigned int gic_nr, int irq_start, | 1172 | void __init gic_init(unsigned int gic_nr, int irq_start, |
@@ -1193,7 +1227,7 @@ gic_of_init(struct device_node *node, struct device_node *parent) | |||
1193 | void __iomem *cpu_base; | 1227 | void __iomem *cpu_base; |
1194 | void __iomem *dist_base; | 1228 | void __iomem *dist_base; |
1195 | u32 percpu_offset; | 1229 | u32 percpu_offset; |
1196 | int irq; | 1230 | int irq, ret; |
1197 | 1231 | ||
1198 | if (WARN_ON(!node)) | 1232 | if (WARN_ON(!node)) |
1199 | return -ENODEV; | 1233 | return -ENODEV; |
@@ -1218,8 +1252,14 @@ gic_of_init(struct device_node *node, struct device_node *parent) | |||
1218 | if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) | 1252 | if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) |
1219 | percpu_offset = 0; | 1253 | percpu_offset = 0; |
1220 | 1254 | ||
1221 | __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, | 1255 | ret = __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, |
1222 | &node->fwnode); | 1256 | &node->fwnode); |
1257 | if (ret) { | ||
1258 | iounmap(dist_base); | ||
1259 | iounmap(cpu_base); | ||
1260 | return ret; | ||
1261 | } | ||
1262 | |||
1223 | if (!gic_cnt) | 1263 | if (!gic_cnt) |
1224 | gic_init_physaddr(node); | 1264 | gic_init_physaddr(node); |
1225 | 1265 | ||
@@ -1308,7 +1348,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, | |||
1308 | struct acpi_madt_generic_distributor *dist; | 1348 | struct acpi_madt_generic_distributor *dist; |
1309 | void __iomem *cpu_base, *dist_base; | 1349 | void __iomem *cpu_base, *dist_base; |
1310 | struct fwnode_handle *domain_handle; | 1350 | struct fwnode_handle *domain_handle; |
1311 | int count; | 1351 | int count, ret; |
1312 | 1352 | ||
1313 | /* Collect CPU base addresses */ | 1353 | /* Collect CPU base addresses */ |
1314 | count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, | 1354 | count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, |
@@ -1351,7 +1391,14 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, | |||
1351 | return -ENOMEM; | 1391 | return -ENOMEM; |
1352 | } | 1392 | } |
1353 | 1393 | ||
1354 | __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); | 1394 | ret = __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); |
1395 | if (ret) { | ||
1396 | pr_err("Failed to initialise GIC\n"); | ||
1397 | irq_domain_free_fwnode(domain_handle); | ||
1398 | iounmap(cpu_base); | ||
1399 | iounmap(dist_base); | ||
1400 | return ret; | ||
1401 | } | ||
1355 | 1402 | ||
1356 | acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); | 1403 | acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); |
1357 | 1404 | ||