diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/ras.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/ras.c | 82 |
1 files changed, 53 insertions, 29 deletions
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 9639c66b453d..9df783088b61 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c | |||
@@ -72,32 +72,62 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id, | |||
72 | 72 | ||
73 | /* #define DEBUG */ | 73 | /* #define DEBUG */ |
74 | 74 | ||
75 | static void request_ras_irqs(struct device_node *np, char *propname, | 75 | |
76 | static void request_ras_irqs(struct device_node *np, | ||
76 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | 77 | irqreturn_t (*handler)(int, void *, struct pt_regs *), |
77 | const char *name) | 78 | const char *name) |
78 | { | 79 | { |
79 | unsigned int *ireg, len, i; | 80 | int i, index, count = 0; |
80 | int virq, n_intr; | 81 | struct of_irq oirq; |
81 | 82 | u32 *opicprop; | |
82 | ireg = (unsigned int *)get_property(np, propname, &len); | 83 | unsigned int opicplen; |
83 | if (ireg == NULL) | 84 | unsigned int virqs[16]; |
84 | return; | 85 | |
85 | n_intr = prom_n_intr_cells(np); | 86 | /* Check for obsolete "open-pic-interrupt" property. If present, then |
86 | len /= n_intr * sizeof(*ireg); | 87 | * map those interrupts using the default interrupt host and default |
87 | 88 | * trigger | |
88 | for (i = 0; i < len; i++) { | 89 | */ |
89 | virq = virt_irq_create_mapping(*ireg); | 90 | opicprop = (u32 *)get_property(np, "open-pic-interrupt", &opicplen); |
90 | if (virq == NO_IRQ) { | 91 | if (opicprop) { |
91 | printk(KERN_ERR "Unable to allocate interrupt " | 92 | opicplen /= sizeof(u32); |
92 | "number for %s\n", np->full_name); | 93 | for (i = 0; i < opicplen; i++) { |
93 | return; | 94 | if (count > 15) |
95 | break; | ||
96 | virqs[count] = irq_create_mapping(NULL, *(opicprop++), | ||
97 | IRQ_TYPE_NONE); | ||
98 | if (virqs[count] == NO_IRQ) | ||
99 | printk(KERN_ERR "Unable to allocate interrupt " | ||
100 | "number for %s\n", np->full_name); | ||
101 | else | ||
102 | count++; | ||
103 | |||
94 | } | 104 | } |
95 | if (request_irq(irq_offset_up(virq), handler, 0, name, NULL)) { | 105 | } |
106 | /* Else use normal interrupt tree parsing */ | ||
107 | else { | ||
108 | /* First try to do a proper OF tree parsing */ | ||
109 | for (index = 0; of_irq_map_one(np, index, &oirq) == 0; | ||
110 | index++) { | ||
111 | if (count > 15) | ||
112 | break; | ||
113 | virqs[count] = irq_create_of_mapping(oirq.controller, | ||
114 | oirq.specifier, | ||
115 | oirq.size); | ||
116 | if (virqs[count] == NO_IRQ) | ||
117 | printk(KERN_ERR "Unable to allocate interrupt " | ||
118 | "number for %s\n", np->full_name); | ||
119 | else | ||
120 | count++; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | /* Now request them */ | ||
125 | for (i = 0; i < count; i++) { | ||
126 | if (request_irq(virqs[i], handler, 0, name, NULL)) { | ||
96 | printk(KERN_ERR "Unable to request interrupt %d for " | 127 | printk(KERN_ERR "Unable to request interrupt %d for " |
97 | "%s\n", irq_offset_up(virq), np->full_name); | 128 | "%s\n", virqs[i], np->full_name); |
98 | return; | 129 | return; |
99 | } | 130 | } |
100 | ireg += n_intr; | ||
101 | } | 131 | } |
102 | } | 132 | } |
103 | 133 | ||
@@ -115,20 +145,14 @@ static int __init init_ras_IRQ(void) | |||
115 | /* Internal Errors */ | 145 | /* Internal Errors */ |
116 | np = of_find_node_by_path("/event-sources/internal-errors"); | 146 | np = of_find_node_by_path("/event-sources/internal-errors"); |
117 | if (np != NULL) { | 147 | if (np != NULL) { |
118 | request_ras_irqs(np, "open-pic-interrupt", ras_error_interrupt, | 148 | request_ras_irqs(np, ras_error_interrupt, "RAS_ERROR"); |
119 | "RAS_ERROR"); | ||
120 | request_ras_irqs(np, "interrupts", ras_error_interrupt, | ||
121 | "RAS_ERROR"); | ||
122 | of_node_put(np); | 149 | of_node_put(np); |
123 | } | 150 | } |
124 | 151 | ||
125 | /* EPOW Events */ | 152 | /* EPOW Events */ |
126 | np = of_find_node_by_path("/event-sources/epow-events"); | 153 | np = of_find_node_by_path("/event-sources/epow-events"); |
127 | if (np != NULL) { | 154 | if (np != NULL) { |
128 | request_ras_irqs(np, "open-pic-interrupt", ras_epow_interrupt, | 155 | request_ras_irqs(np, ras_epow_interrupt, "RAS_EPOW"); |
129 | "RAS_EPOW"); | ||
130 | request_ras_irqs(np, "interrupts", ras_epow_interrupt, | ||
131 | "RAS_EPOW"); | ||
132 | of_node_put(np); | 156 | of_node_put(np); |
133 | } | 157 | } |
134 | 158 | ||
@@ -162,7 +186,7 @@ ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
162 | 186 | ||
163 | status = rtas_call(ras_check_exception_token, 6, 1, NULL, | 187 | status = rtas_call(ras_check_exception_token, 6, 1, NULL, |
164 | RAS_VECTOR_OFFSET, | 188 | RAS_VECTOR_OFFSET, |
165 | virt_irq_to_real(irq_offset_down(irq)), | 189 | irq_map[irq].hwirq, |
166 | RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, | 190 | RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, |
167 | critical, __pa(&ras_log_buf), | 191 | critical, __pa(&ras_log_buf), |
168 | rtas_get_error_log_max()); | 192 | rtas_get_error_log_max()); |
@@ -198,7 +222,7 @@ ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
198 | 222 | ||
199 | status = rtas_call(ras_check_exception_token, 6, 1, NULL, | 223 | status = rtas_call(ras_check_exception_token, 6, 1, NULL, |
200 | RAS_VECTOR_OFFSET, | 224 | RAS_VECTOR_OFFSET, |
201 | virt_irq_to_real(irq_offset_down(irq)), | 225 | irq_map[irq].hwirq, |
202 | RTAS_INTERNAL_ERROR, 1 /*Time Critical */, | 226 | RTAS_INTERNAL_ERROR, 1 /*Time Critical */, |
203 | __pa(&ras_log_buf), | 227 | __pa(&ras_log_buf), |
204 | rtas_get_error_log_max()); | 228 | rtas_get_error_log_max()); |