diff options
Diffstat (limited to 'arch/ia64/kernel/iosapic.c')
-rw-r--r-- | arch/ia64/kernel/iosapic.c | 165 |
1 files changed, 57 insertions, 108 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 7ded76658d2d..b0f9afebb146 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
@@ -108,10 +108,6 @@ | |||
108 | #define DBG(fmt...) | 108 | #define DBG(fmt...) |
109 | #endif | 109 | #endif |
110 | 110 | ||
111 | #define NR_PREALLOCATE_RTE_ENTRIES \ | ||
112 | (PAGE_SIZE / sizeof(struct iosapic_rte_info)) | ||
113 | #define RTE_PREALLOCATED (1) | ||
114 | |||
115 | static DEFINE_SPINLOCK(iosapic_lock); | 111 | static DEFINE_SPINLOCK(iosapic_lock); |
116 | 112 | ||
117 | /* | 113 | /* |
@@ -136,7 +132,6 @@ struct iosapic_rte_info { | |||
136 | struct list_head rte_list; /* RTEs sharing the same vector */ | 132 | struct list_head rte_list; /* RTEs sharing the same vector */ |
137 | char rte_index; /* IOSAPIC RTE index */ | 133 | char rte_index; /* IOSAPIC RTE index */ |
138 | int refcnt; /* reference counter */ | 134 | int refcnt; /* reference counter */ |
139 | unsigned int flags; /* flags */ | ||
140 | struct iosapic *iosapic; | 135 | struct iosapic *iosapic; |
141 | } ____cacheline_aligned; | 136 | } ____cacheline_aligned; |
142 | 137 | ||
@@ -155,9 +150,6 @@ static struct iosapic_intr_info { | |||
155 | 150 | ||
156 | static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ | 151 | static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ |
157 | 152 | ||
158 | static int iosapic_kmalloc_ok; | ||
159 | static LIST_HEAD(free_rte_list); | ||
160 | |||
161 | static inline void | 153 | static inline void |
162 | iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val) | 154 | iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val) |
163 | { | 155 | { |
@@ -265,7 +257,7 @@ set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask) | |||
265 | } | 257 | } |
266 | 258 | ||
267 | static void | 259 | static void |
268 | nop (unsigned int irq) | 260 | nop (struct irq_data *data) |
269 | { | 261 | { |
270 | /* do nothing... */ | 262 | /* do nothing... */ |
271 | } | 263 | } |
@@ -295,8 +287,9 @@ kexec_disable_iosapic(void) | |||
295 | #endif | 287 | #endif |
296 | 288 | ||
297 | static void | 289 | static void |
298 | mask_irq (unsigned int irq) | 290 | mask_irq (struct irq_data *data) |
299 | { | 291 | { |
292 | unsigned int irq = data->irq; | ||
300 | u32 low32; | 293 | u32 low32; |
301 | int rte_index; | 294 | int rte_index; |
302 | struct iosapic_rte_info *rte; | 295 | struct iosapic_rte_info *rte; |
@@ -313,8 +306,9 @@ mask_irq (unsigned int irq) | |||
313 | } | 306 | } |
314 | 307 | ||
315 | static void | 308 | static void |
316 | unmask_irq (unsigned int irq) | 309 | unmask_irq (struct irq_data *data) |
317 | { | 310 | { |
311 | unsigned int irq = data->irq; | ||
318 | u32 low32; | 312 | u32 low32; |
319 | int rte_index; | 313 | int rte_index; |
320 | struct iosapic_rte_info *rte; | 314 | struct iosapic_rte_info *rte; |
@@ -331,9 +325,11 @@ unmask_irq (unsigned int irq) | |||
331 | 325 | ||
332 | 326 | ||
333 | static int | 327 | static int |
334 | iosapic_set_affinity(unsigned int irq, const struct cpumask *mask) | 328 | iosapic_set_affinity(struct irq_data *data, const struct cpumask *mask, |
329 | bool force) | ||
335 | { | 330 | { |
336 | #ifdef CONFIG_SMP | 331 | #ifdef CONFIG_SMP |
332 | unsigned int irq = data->irq; | ||
337 | u32 high32, low32; | 333 | u32 high32, low32; |
338 | int cpu, dest, rte_index; | 334 | int cpu, dest, rte_index; |
339 | int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; | 335 | int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; |
@@ -387,31 +383,33 @@ iosapic_set_affinity(unsigned int irq, const struct cpumask *mask) | |||
387 | */ | 383 | */ |
388 | 384 | ||
389 | static unsigned int | 385 | static unsigned int |
390 | iosapic_startup_level_irq (unsigned int irq) | 386 | iosapic_startup_level_irq (struct irq_data *data) |
391 | { | 387 | { |
392 | unmask_irq(irq); | 388 | unmask_irq(data); |
393 | return 0; | 389 | return 0; |
394 | } | 390 | } |
395 | 391 | ||
396 | static void | 392 | static void |
397 | iosapic_end_level_irq (unsigned int irq) | 393 | iosapic_unmask_level_irq (struct irq_data *data) |
398 | { | 394 | { |
395 | unsigned int irq = data->irq; | ||
399 | ia64_vector vec = irq_to_vector(irq); | 396 | ia64_vector vec = irq_to_vector(irq); |
400 | struct iosapic_rte_info *rte; | 397 | struct iosapic_rte_info *rte; |
401 | int do_unmask_irq = 0; | 398 | int do_unmask_irq = 0; |
402 | 399 | ||
403 | irq_complete_move(irq); | 400 | irq_complete_move(irq); |
404 | if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) { | 401 | if (unlikely(irqd_is_setaffinity_pending(data))) { |
405 | do_unmask_irq = 1; | 402 | do_unmask_irq = 1; |
406 | mask_irq(irq); | 403 | mask_irq(data); |
407 | } | 404 | } else |
405 | unmask_irq(data); | ||
408 | 406 | ||
409 | list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) | 407 | list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) |
410 | iosapic_eoi(rte->iosapic->addr, vec); | 408 | iosapic_eoi(rte->iosapic->addr, vec); |
411 | 409 | ||
412 | if (unlikely(do_unmask_irq)) { | 410 | if (unlikely(do_unmask_irq)) { |
413 | move_masked_irq(irq); | 411 | irq_move_masked_irq(data); |
414 | unmask_irq(irq); | 412 | unmask_irq(data); |
415 | } | 413 | } |
416 | } | 414 | } |
417 | 415 | ||
@@ -421,16 +419,15 @@ iosapic_end_level_irq (unsigned int irq) | |||
421 | #define iosapic_ack_level_irq nop | 419 | #define iosapic_ack_level_irq nop |
422 | 420 | ||
423 | static struct irq_chip irq_type_iosapic_level = { | 421 | static struct irq_chip irq_type_iosapic_level = { |
424 | .name = "IO-SAPIC-level", | 422 | .name = "IO-SAPIC-level", |
425 | .startup = iosapic_startup_level_irq, | 423 | .irq_startup = iosapic_startup_level_irq, |
426 | .shutdown = iosapic_shutdown_level_irq, | 424 | .irq_shutdown = iosapic_shutdown_level_irq, |
427 | .enable = iosapic_enable_level_irq, | 425 | .irq_enable = iosapic_enable_level_irq, |
428 | .disable = iosapic_disable_level_irq, | 426 | .irq_disable = iosapic_disable_level_irq, |
429 | .ack = iosapic_ack_level_irq, | 427 | .irq_ack = iosapic_ack_level_irq, |
430 | .end = iosapic_end_level_irq, | 428 | .irq_mask = mask_irq, |
431 | .mask = mask_irq, | 429 | .irq_unmask = iosapic_unmask_level_irq, |
432 | .unmask = unmask_irq, | 430 | .irq_set_affinity = iosapic_set_affinity |
433 | .set_affinity = iosapic_set_affinity | ||
434 | }; | 431 | }; |
435 | 432 | ||
436 | /* | 433 | /* |
@@ -438,9 +435,9 @@ static struct irq_chip irq_type_iosapic_level = { | |||
438 | */ | 435 | */ |
439 | 436 | ||
440 | static unsigned int | 437 | static unsigned int |
441 | iosapic_startup_edge_irq (unsigned int irq) | 438 | iosapic_startup_edge_irq (struct irq_data *data) |
442 | { | 439 | { |
443 | unmask_irq(irq); | 440 | unmask_irq(data); |
444 | /* | 441 | /* |
445 | * IOSAPIC simply drops interrupts pended while the | 442 | * IOSAPIC simply drops interrupts pended while the |
446 | * corresponding pin was masked, so we can't know if an | 443 | * corresponding pin was masked, so we can't know if an |
@@ -450,37 +447,25 @@ iosapic_startup_edge_irq (unsigned int irq) | |||
450 | } | 447 | } |
451 | 448 | ||
452 | static void | 449 | static void |
453 | iosapic_ack_edge_irq (unsigned int irq) | 450 | iosapic_ack_edge_irq (struct irq_data *data) |
454 | { | 451 | { |
455 | struct irq_desc *idesc = irq_desc + irq; | 452 | irq_complete_move(data->irq); |
456 | 453 | irq_move_irq(data); | |
457 | irq_complete_move(irq); | ||
458 | move_native_irq(irq); | ||
459 | /* | ||
460 | * Once we have recorded IRQ_PENDING already, we can mask the | ||
461 | * interrupt for real. This prevents IRQ storms from unhandled | ||
462 | * devices. | ||
463 | */ | ||
464 | if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == | ||
465 | (IRQ_PENDING|IRQ_DISABLED)) | ||
466 | mask_irq(irq); | ||
467 | } | 454 | } |
468 | 455 | ||
469 | #define iosapic_enable_edge_irq unmask_irq | 456 | #define iosapic_enable_edge_irq unmask_irq |
470 | #define iosapic_disable_edge_irq nop | 457 | #define iosapic_disable_edge_irq nop |
471 | #define iosapic_end_edge_irq nop | ||
472 | 458 | ||
473 | static struct irq_chip irq_type_iosapic_edge = { | 459 | static struct irq_chip irq_type_iosapic_edge = { |
474 | .name = "IO-SAPIC-edge", | 460 | .name = "IO-SAPIC-edge", |
475 | .startup = iosapic_startup_edge_irq, | 461 | .irq_startup = iosapic_startup_edge_irq, |
476 | .shutdown = iosapic_disable_edge_irq, | 462 | .irq_shutdown = iosapic_disable_edge_irq, |
477 | .enable = iosapic_enable_edge_irq, | 463 | .irq_enable = iosapic_enable_edge_irq, |
478 | .disable = iosapic_disable_edge_irq, | 464 | .irq_disable = iosapic_disable_edge_irq, |
479 | .ack = iosapic_ack_edge_irq, | 465 | .irq_ack = iosapic_ack_edge_irq, |
480 | .end = iosapic_end_edge_irq, | 466 | .irq_mask = mask_irq, |
481 | .mask = mask_irq, | 467 | .irq_unmask = unmask_irq, |
482 | .unmask = unmask_irq, | 468 | .irq_set_affinity = iosapic_set_affinity |
483 | .set_affinity = iosapic_set_affinity | ||
484 | }; | 469 | }; |
485 | 470 | ||
486 | static unsigned int | 471 | static unsigned int |
@@ -552,37 +537,6 @@ iosapic_reassign_vector (int irq) | |||
552 | } | 537 | } |
553 | } | 538 | } |
554 | 539 | ||
555 | static struct iosapic_rte_info * __init_refok iosapic_alloc_rte (void) | ||
556 | { | ||
557 | int i; | ||
558 | struct iosapic_rte_info *rte; | ||
559 | int preallocated = 0; | ||
560 | |||
561 | if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { | ||
562 | rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * | ||
563 | NR_PREALLOCATE_RTE_ENTRIES); | ||
564 | for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) | ||
565 | list_add(&rte->rte_list, &free_rte_list); | ||
566 | } | ||
567 | |||
568 | if (!list_empty(&free_rte_list)) { | ||
569 | rte = list_entry(free_rte_list.next, struct iosapic_rte_info, | ||
570 | rte_list); | ||
571 | list_del(&rte->rte_list); | ||
572 | preallocated++; | ||
573 | } else { | ||
574 | rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC); | ||
575 | if (!rte) | ||
576 | return NULL; | ||
577 | } | ||
578 | |||
579 | memset(rte, 0, sizeof(struct iosapic_rte_info)); | ||
580 | if (preallocated) | ||
581 | rte->flags |= RTE_PREALLOCATED; | ||
582 | |||
583 | return rte; | ||
584 | } | ||
585 | |||
586 | static inline int irq_is_shared (int irq) | 540 | static inline int irq_is_shared (int irq) |
587 | { | 541 | { |
588 | return (iosapic_intr_info[irq].count > 1); | 542 | return (iosapic_intr_info[irq].count > 1); |
@@ -601,8 +555,7 @@ static int | |||
601 | register_intr (unsigned int gsi, int irq, unsigned char delivery, | 555 | register_intr (unsigned int gsi, int irq, unsigned char delivery, |
602 | unsigned long polarity, unsigned long trigger) | 556 | unsigned long polarity, unsigned long trigger) |
603 | { | 557 | { |
604 | struct irq_desc *idesc; | 558 | struct irq_chip *chip, *irq_type; |
605 | struct irq_chip *irq_type; | ||
606 | int index; | 559 | int index; |
607 | struct iosapic_rte_info *rte; | 560 | struct iosapic_rte_info *rte; |
608 | 561 | ||
@@ -615,7 +568,7 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery, | |||
615 | 568 | ||
616 | rte = find_rte(irq, gsi); | 569 | rte = find_rte(irq, gsi); |
617 | if (!rte) { | 570 | if (!rte) { |
618 | rte = iosapic_alloc_rte(); | 571 | rte = kzalloc(sizeof (*rte), GFP_ATOMIC); |
619 | if (!rte) { | 572 | if (!rte) { |
620 | printk(KERN_WARNING "%s: cannot allocate memory\n", | 573 | printk(KERN_WARNING "%s: cannot allocate memory\n", |
621 | __func__); | 574 | __func__); |
@@ -649,15 +602,18 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery, | |||
649 | 602 | ||
650 | irq_type = iosapic_get_irq_chip(trigger); | 603 | irq_type = iosapic_get_irq_chip(trigger); |
651 | 604 | ||
652 | idesc = irq_desc + irq; | 605 | chip = irq_get_chip(irq); |
653 | if (irq_type != NULL && idesc->chip != irq_type) { | 606 | if (irq_type != NULL && chip != irq_type) { |
654 | if (idesc->chip != &no_irq_chip) | 607 | if (chip != &no_irq_chip) |
655 | printk(KERN_WARNING | 608 | printk(KERN_WARNING |
656 | "%s: changing vector %d from %s to %s\n", | 609 | "%s: changing vector %d from %s to %s\n", |
657 | __func__, irq_to_vector(irq), | 610 | __func__, irq_to_vector(irq), |
658 | idesc->chip->name, irq_type->name); | 611 | chip->name, irq_type->name); |
659 | idesc->chip = irq_type; | 612 | chip = irq_type; |
660 | } | 613 | } |
614 | __irq_set_chip_handler_name_locked(irq, chip, trigger == IOSAPIC_EDGE ? | ||
615 | handle_edge_irq : handle_level_irq, | ||
616 | NULL); | ||
661 | return 0; | 617 | return 0; |
662 | } | 618 | } |
663 | 619 | ||
@@ -767,6 +723,7 @@ iosapic_register_intr (unsigned int gsi, | |||
767 | struct iosapic_rte_info *rte; | 723 | struct iosapic_rte_info *rte; |
768 | u32 low32; | 724 | u32 low32; |
769 | unsigned char dmode; | 725 | unsigned char dmode; |
726 | struct irq_desc *desc; | ||
770 | 727 | ||
771 | /* | 728 | /* |
772 | * If this GSI has already been registered (i.e., it's a | 729 | * If this GSI has already been registered (i.e., it's a |
@@ -794,12 +751,13 @@ iosapic_register_intr (unsigned int gsi, | |||
794 | goto unlock_iosapic_lock; | 751 | goto unlock_iosapic_lock; |
795 | } | 752 | } |
796 | 753 | ||
797 | raw_spin_lock(&irq_desc[irq].lock); | 754 | desc = irq_to_desc(irq); |
755 | raw_spin_lock(&desc->lock); | ||
798 | dest = get_target_cpu(gsi, irq); | 756 | dest = get_target_cpu(gsi, irq); |
799 | dmode = choose_dmode(); | 757 | dmode = choose_dmode(); |
800 | err = register_intr(gsi, irq, dmode, polarity, trigger); | 758 | err = register_intr(gsi, irq, dmode, polarity, trigger); |
801 | if (err < 0) { | 759 | if (err < 0) { |
802 | raw_spin_unlock(&irq_desc[irq].lock); | 760 | raw_spin_unlock(&desc->lock); |
803 | irq = err; | 761 | irq = err; |
804 | goto unlock_iosapic_lock; | 762 | goto unlock_iosapic_lock; |
805 | } | 763 | } |
@@ -818,7 +776,7 @@ iosapic_register_intr (unsigned int gsi, | |||
818 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), | 776 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), |
819 | cpu_logical_id(dest), dest, irq_to_vector(irq)); | 777 | cpu_logical_id(dest), dest, irq_to_vector(irq)); |
820 | 778 | ||
821 | raw_spin_unlock(&irq_desc[irq].lock); | 779 | raw_spin_unlock(&desc->lock); |
822 | unlock_iosapic_lock: | 780 | unlock_iosapic_lock: |
823 | spin_unlock_irqrestore(&iosapic_lock, flags); | 781 | spin_unlock_irqrestore(&iosapic_lock, flags); |
824 | return irq; | 782 | return irq; |
@@ -829,7 +787,6 @@ iosapic_unregister_intr (unsigned int gsi) | |||
829 | { | 787 | { |
830 | unsigned long flags; | 788 | unsigned long flags; |
831 | int irq, index; | 789 | int irq, index; |
832 | struct irq_desc *idesc; | ||
833 | u32 low32; | 790 | u32 low32; |
834 | unsigned long trigger, polarity; | 791 | unsigned long trigger, polarity; |
835 | unsigned int dest; | 792 | unsigned int dest; |
@@ -859,7 +816,6 @@ iosapic_unregister_intr (unsigned int gsi) | |||
859 | if (--rte->refcnt > 0) | 816 | if (--rte->refcnt > 0) |
860 | goto out; | 817 | goto out; |
861 | 818 | ||
862 | idesc = irq_desc + irq; | ||
863 | rte->refcnt = NO_REF_RTE; | 819 | rte->refcnt = NO_REF_RTE; |
864 | 820 | ||
865 | /* Mask the interrupt */ | 821 | /* Mask the interrupt */ |
@@ -883,7 +839,7 @@ iosapic_unregister_intr (unsigned int gsi) | |||
883 | if (iosapic_intr_info[irq].count == 0) { | 839 | if (iosapic_intr_info[irq].count == 0) { |
884 | #ifdef CONFIG_SMP | 840 | #ifdef CONFIG_SMP |
885 | /* Clear affinity */ | 841 | /* Clear affinity */ |
886 | cpumask_setall(idesc->affinity); | 842 | cpumask_setall(irq_get_irq_data(irq)->affinity); |
887 | #endif | 843 | #endif |
888 | /* Clear the interrupt information */ | 844 | /* Clear the interrupt information */ |
889 | iosapic_intr_info[irq].dest = 0; | 845 | iosapic_intr_info[irq].dest = 0; |
@@ -1161,10 +1117,3 @@ map_iosapic_to_node(unsigned int gsi_base, int node) | |||
1161 | return; | 1117 | return; |
1162 | } | 1118 | } |
1163 | #endif | 1119 | #endif |
1164 | |||
1165 | static int __init iosapic_enable_kmalloc (void) | ||
1166 | { | ||
1167 | iosapic_kmalloc_ok = 1; | ||
1168 | return 0; | ||
1169 | } | ||
1170 | core_initcall (iosapic_enable_kmalloc); | ||