diff options
-rw-r--r-- | arch/ia64/kernel/iosapic.c | 57 | ||||
-rw-r--r-- | include/asm-ia64/iosapic.h | 4 |
2 files changed, 31 insertions, 30 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index b3dcdb7e7fc7..29fea0a8c2c6 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
@@ -125,6 +125,7 @@ static struct iosapic { | |||
125 | #ifdef CONFIG_NUMA | 125 | #ifdef CONFIG_NUMA |
126 | unsigned short node; /* numa node association via pxm */ | 126 | unsigned short node; /* numa node association via pxm */ |
127 | #endif | 127 | #endif |
128 | spinlock_t lock; /* lock for indirect reg access */ | ||
128 | } iosapic_lists[NR_IOSAPICS]; | 129 | } iosapic_lists[NR_IOSAPICS]; |
129 | 130 | ||
130 | struct iosapic_rte_info { | 131 | struct iosapic_rte_info { |
@@ -153,6 +154,16 @@ static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ | |||
153 | static int iosapic_kmalloc_ok; | 154 | static int iosapic_kmalloc_ok; |
154 | static LIST_HEAD(free_rte_list); | 155 | static LIST_HEAD(free_rte_list); |
155 | 156 | ||
157 | static inline void | ||
158 | iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val) | ||
159 | { | ||
160 | unsigned long flags; | ||
161 | |||
162 | spin_lock_irqsave(&iosapic->lock, flags); | ||
163 | __iosapic_write(iosapic->addr, reg, val); | ||
164 | spin_unlock_irqrestore(&iosapic->lock, flags); | ||
165 | } | ||
166 | |||
156 | /* | 167 | /* |
157 | * Find an IOSAPIC associated with a GSI | 168 | * Find an IOSAPIC associated with a GSI |
158 | */ | 169 | */ |
@@ -226,7 +237,6 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) | |||
226 | { | 237 | { |
227 | unsigned long pol, trigger, dmode; | 238 | unsigned long pol, trigger, dmode; |
228 | u32 low32, high32; | 239 | u32 low32, high32; |
229 | char __iomem *addr; | ||
230 | int rte_index; | 240 | int rte_index; |
231 | char redir; | 241 | char redir; |
232 | struct iosapic_rte_info *rte; | 242 | struct iosapic_rte_info *rte; |
@@ -238,7 +248,6 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) | |||
238 | return; /* not an IOSAPIC interrupt */ | 248 | return; /* not an IOSAPIC interrupt */ |
239 | 249 | ||
240 | rte_index = rte->rte_index; | 250 | rte_index = rte->rte_index; |
241 | addr = rte->iosapic->addr; | ||
242 | pol = iosapic_intr_info[vector].polarity; | 251 | pol = iosapic_intr_info[vector].polarity; |
243 | trigger = iosapic_intr_info[vector].trigger; | 252 | trigger = iosapic_intr_info[vector].trigger; |
244 | dmode = iosapic_intr_info[vector].dmode; | 253 | dmode = iosapic_intr_info[vector].dmode; |
@@ -268,8 +277,8 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) | |||
268 | /* dest contains both id and eid */ | 277 | /* dest contains both id and eid */ |
269 | high32 = (dest << IOSAPIC_DEST_SHIFT); | 278 | high32 = (dest << IOSAPIC_DEST_SHIFT); |
270 | 279 | ||
271 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); | 280 | iosapic_write(rte->iosapic, IOSAPIC_RTE_HIGH(rte_index), high32); |
272 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 281 | iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32); |
273 | iosapic_intr_info[vector].low32 = low32; | 282 | iosapic_intr_info[vector].low32 = low32; |
274 | iosapic_intr_info[vector].dest = dest; | 283 | iosapic_intr_info[vector].dest = dest; |
275 | } | 284 | } |
@@ -292,7 +301,7 @@ kexec_disable_iosapic(void) | |||
292 | iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) { | 301 | iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) { |
293 | list_for_each_entry(rte, &info->rtes, | 302 | list_for_each_entry(rte, &info->rtes, |
294 | rte_list) { | 303 | rte_list) { |
295 | iosapic_write(rte->iosapic->addr, | 304 | iosapic_write(rte->iosapic, |
296 | IOSAPIC_RTE_LOW(rte->rte_index), | 305 | IOSAPIC_RTE_LOW(rte->rte_index), |
297 | IOSAPIC_MASK|vec); | 306 | IOSAPIC_MASK|vec); |
298 | iosapic_eoi(rte->iosapic->addr, vec); | 307 | iosapic_eoi(rte->iosapic->addr, vec); |
@@ -304,8 +313,6 @@ kexec_disable_iosapic(void) | |||
304 | static void | 313 | static void |
305 | mask_irq (unsigned int irq) | 314 | mask_irq (unsigned int irq) |
306 | { | 315 | { |
307 | unsigned long flags; | ||
308 | char __iomem *addr; | ||
309 | u32 low32; | 316 | u32 low32; |
310 | int rte_index; | 317 | int rte_index; |
311 | ia64_vector vec = irq_to_vector(irq); | 318 | ia64_vector vec = irq_to_vector(irq); |
@@ -314,22 +321,17 @@ mask_irq (unsigned int irq) | |||
314 | if (list_empty(&iosapic_intr_info[vec].rtes)) | 321 | if (list_empty(&iosapic_intr_info[vec].rtes)) |
315 | return; /* not an IOSAPIC interrupt! */ | 322 | return; /* not an IOSAPIC interrupt! */ |
316 | 323 | ||
317 | spin_lock_irqsave(&iosapic_lock, flags); | ||
318 | /* set only the mask bit */ | 324 | /* set only the mask bit */ |
319 | low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; | 325 | low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; |
320 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { | 326 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { |
321 | addr = rte->iosapic->addr; | ||
322 | rte_index = rte->rte_index; | 327 | rte_index = rte->rte_index; |
323 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 328 | iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32); |
324 | } | 329 | } |
325 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
326 | } | 330 | } |
327 | 331 | ||
328 | static void | 332 | static void |
329 | unmask_irq (unsigned int irq) | 333 | unmask_irq (unsigned int irq) |
330 | { | 334 | { |
331 | unsigned long flags; | ||
332 | char __iomem *addr; | ||
333 | u32 low32; | 335 | u32 low32; |
334 | int rte_index; | 336 | int rte_index; |
335 | ia64_vector vec = irq_to_vector(irq); | 337 | ia64_vector vec = irq_to_vector(irq); |
@@ -338,14 +340,11 @@ unmask_irq (unsigned int irq) | |||
338 | if (list_empty(&iosapic_intr_info[vec].rtes)) | 340 | if (list_empty(&iosapic_intr_info[vec].rtes)) |
339 | return; /* not an IOSAPIC interrupt! */ | 341 | return; /* not an IOSAPIC interrupt! */ |
340 | 342 | ||
341 | spin_lock_irqsave(&iosapic_lock, flags); | ||
342 | low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; | 343 | low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; |
343 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { | 344 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { |
344 | addr = rte->iosapic->addr; | ||
345 | rte_index = rte->rte_index; | 345 | rte_index = rte->rte_index; |
346 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 346 | iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32); |
347 | } | 347 | } |
348 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
349 | } | 348 | } |
350 | 349 | ||
351 | 350 | ||
@@ -353,13 +352,12 @@ static void | |||
353 | iosapic_set_affinity (unsigned int irq, cpumask_t mask) | 352 | iosapic_set_affinity (unsigned int irq, cpumask_t mask) |
354 | { | 353 | { |
355 | #ifdef CONFIG_SMP | 354 | #ifdef CONFIG_SMP |
356 | unsigned long flags; | ||
357 | u32 high32, low32; | 355 | u32 high32, low32; |
358 | int dest, rte_index; | 356 | int dest, rte_index; |
359 | char __iomem *addr; | ||
360 | int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; | 357 | int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; |
361 | ia64_vector vec; | 358 | ia64_vector vec; |
362 | struct iosapic_rte_info *rte; | 359 | struct iosapic_rte_info *rte; |
360 | struct iosapic *iosapic; | ||
363 | 361 | ||
364 | irq &= (~IA64_IRQ_REDIRECTED); | 362 | irq &= (~IA64_IRQ_REDIRECTED); |
365 | vec = irq_to_vector(irq); | 363 | vec = irq_to_vector(irq); |
@@ -377,7 +375,6 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) | |||
377 | /* dest contains both id and eid */ | 375 | /* dest contains both id and eid */ |
378 | high32 = dest << IOSAPIC_DEST_SHIFT; | 376 | high32 = dest << IOSAPIC_DEST_SHIFT; |
379 | 377 | ||
380 | spin_lock_irqsave(&iosapic_lock, flags); | ||
381 | low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); | 378 | low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); |
382 | if (redir) | 379 | if (redir) |
383 | /* change delivery mode to lowest priority */ | 380 | /* change delivery mode to lowest priority */ |
@@ -389,12 +386,11 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) | |||
389 | iosapic_intr_info[vec].low32 = low32; | 386 | iosapic_intr_info[vec].low32 = low32; |
390 | iosapic_intr_info[vec].dest = dest; | 387 | iosapic_intr_info[vec].dest = dest; |
391 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { | 388 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { |
392 | addr = rte->iosapic->addr; | 389 | iosapic = rte->iosapic; |
393 | rte_index = rte->rte_index; | 390 | rte_index = rte->rte_index; |
394 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); | 391 | iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32); |
395 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 392 | iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32); |
396 | } | 393 | } |
397 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
398 | #endif | 394 | #endif |
399 | } | 395 | } |
400 | 396 | ||
@@ -499,7 +495,7 @@ iosapic_version (char __iomem *addr) | |||
499 | * unsigned int reserved2 : 8; | 495 | * unsigned int reserved2 : 8; |
500 | * } | 496 | * } |
501 | */ | 497 | */ |
502 | return iosapic_read(addr, IOSAPIC_VERSION); | 498 | return __iosapic_read(addr, IOSAPIC_VERSION); |
503 | } | 499 | } |
504 | 500 | ||
505 | static int iosapic_find_sharable_vector (unsigned long trigger, | 501 | static int iosapic_find_sharable_vector (unsigned long trigger, |
@@ -857,8 +853,7 @@ iosapic_unregister_intr (unsigned int gsi) | |||
857 | 853 | ||
858 | /* Mask the interrupt */ | 854 | /* Mask the interrupt */ |
859 | low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; | 855 | low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; |
860 | iosapic_write(rte->iosapic->addr, | 856 | iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32); |
861 | IOSAPIC_RTE_LOW(rte->rte_index), low32); | ||
862 | 857 | ||
863 | iosapic_intr_info[vector].count--; | 858 | iosapic_intr_info[vector].count--; |
864 | iosapic_free_rte(rte); | 859 | iosapic_free_rte(rte); |
@@ -1060,9 +1055,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) | |||
1060 | unsigned long flags; | 1055 | unsigned long flags; |
1061 | 1056 | ||
1062 | spin_lock_irqsave(&iosapic_lock, flags); | 1057 | spin_lock_irqsave(&iosapic_lock, flags); |
1058 | index = find_iosapic(gsi_base); | ||
1059 | if (index >= 0) { | ||
1060 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
1061 | return -EBUSY; | ||
1062 | } | ||
1063 | |||
1063 | addr = ioremap(phys_addr, 0); | 1064 | addr = ioremap(phys_addr, 0); |
1064 | ver = iosapic_version(addr); | 1065 | ver = iosapic_version(addr); |
1065 | |||
1066 | if ((err = iosapic_check_gsi_range(gsi_base, ver))) { | 1066 | if ((err = iosapic_check_gsi_range(gsi_base, ver))) { |
1067 | iounmap(addr); | 1067 | iounmap(addr); |
1068 | spin_unlock_irqrestore(&iosapic_lock, flags); | 1068 | spin_unlock_irqrestore(&iosapic_lock, flags); |
@@ -1083,6 +1083,7 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) | |||
1083 | #ifdef CONFIG_NUMA | 1083 | #ifdef CONFIG_NUMA |
1084 | iosapic_lists[index].node = MAX_NUMNODES; | 1084 | iosapic_lists[index].node = MAX_NUMNODES; |
1085 | #endif | 1085 | #endif |
1086 | spin_lock_init(&iosapic_lists[index].lock); | ||
1086 | spin_unlock_irqrestore(&iosapic_lock, flags); | 1087 | spin_unlock_irqrestore(&iosapic_lock, flags); |
1087 | 1088 | ||
1088 | if ((gsi_base == 0) && pcat_compat) { | 1089 | if ((gsi_base == 0) && pcat_compat) { |
diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h index 421cb6b62a7c..09bdc3898df8 100644 --- a/include/asm-ia64/iosapic.h +++ b/include/asm-ia64/iosapic.h | |||
@@ -53,13 +53,13 @@ | |||
53 | 53 | ||
54 | #define NR_IOSAPICS 256 | 54 | #define NR_IOSAPICS 256 |
55 | 55 | ||
56 | static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg) | 56 | static inline unsigned int __iosapic_read(char __iomem *iosapic, unsigned int reg) |
57 | { | 57 | { |
58 | writel(reg, iosapic + IOSAPIC_REG_SELECT); | 58 | writel(reg, iosapic + IOSAPIC_REG_SELECT); |
59 | return readl(iosapic + IOSAPIC_WINDOW); | 59 | return readl(iosapic + IOSAPIC_WINDOW); |
60 | } | 60 | } |
61 | 61 | ||
62 | static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val) | 62 | static inline void __iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val) |
63 | { | 63 | { |
64 | writel(reg, iosapic + IOSAPIC_REG_SELECT); | 64 | writel(reg, iosapic + IOSAPIC_REG_SELECT); |
65 | writel(val, iosapic + IOSAPIC_WINDOW); | 65 | writel(val, iosapic + IOSAPIC_WINDOW); |