Commit 76832c28de4fabbf32fe1e5a25194724a3430070
Committed by
Linus Torvalds
1 parent
c0e7dcc8bc
Exists in
master
and in
7 other branches
[PATCH] shrink mmtimer memory size
This greatly reduces the amount of memory used by mmtimer on smaller machines with large values of MAX_COMPACT_NODES. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> Signed-off-by: Christoph Lameter <clameter@sgi.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 1 changed file with 57 additions and 33 deletions Side-by-side Diff
drivers/char/mmtimer.c
1 | 1 | /* |
2 | - * Intel Multimedia Timer device implementation for SGI SN platforms. | |
2 | + * Timer device implementation for SGI SN platforms. | |
3 | 3 | * |
4 | 4 | * This file is subject to the terms and conditions of the GNU General Public |
5 | 5 | * License. See the file "COPYING" in the main directory of this archive |
6 | 6 | * for more details. |
7 | 7 | * |
8 | - * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. | |
8 | + * Copyright (c) 2001-2006 Silicon Graphics, Inc. All rights reserved. | |
9 | 9 | * |
10 | 10 | * This driver exports an API that should be supportable by any HPET or IA-PC |
11 | 11 | * multimedia timer. The code below is currently specific to the SGI Altix |
... | ... | @@ -45,7 +45,7 @@ |
45 | 45 | /* name of the device, usually in /dev */ |
46 | 46 | #define MMTIMER_NAME "mmtimer" |
47 | 47 | #define MMTIMER_DESC "SGI Altix RTC Timer" |
48 | -#define MMTIMER_VERSION "2.0" | |
48 | +#define MMTIMER_VERSION "2.1" | |
49 | 49 | |
50 | 50 | #define RTC_BITS 55 /* 55 bits for this implementation */ |
51 | 51 | |
... | ... | @@ -227,10 +227,7 @@ |
227 | 227 | struct tasklet_struct tasklet; |
228 | 228 | } mmtimer_t; |
229 | 229 | |
230 | -/* | |
231 | - * Total number of comparators is comparators/node * MAX nodes/running kernel | |
232 | - */ | |
233 | -static mmtimer_t timers[NUM_COMPARATORS*MAX_COMPACT_NODES]; | |
230 | +static mmtimer_t ** timers; | |
234 | 231 | |
235 | 232 | /** |
236 | 233 | * mmtimer_ioctl - ioctl interface for /dev/mmtimer |
237 | 234 | |
238 | 235 | |
239 | 236 | |
240 | 237 | |
241 | 238 | |
... | ... | @@ -441,29 +438,29 @@ |
441 | 438 | mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
442 | 439 | { |
443 | 440 | int i; |
444 | - mmtimer_t *base = timers + cpu_to_node(smp_processor_id()) * | |
445 | - NUM_COMPARATORS; | |
446 | 441 | unsigned long expires = 0; |
447 | 442 | int result = IRQ_NONE; |
443 | + unsigned indx = cpu_to_node(smp_processor_id()); | |
448 | 444 | |
449 | 445 | /* |
450 | 446 | * Do this once for each comparison register |
451 | 447 | */ |
452 | 448 | for (i = 0; i < NUM_COMPARATORS; i++) { |
449 | + mmtimer_t *base = timers[indx] + i; | |
453 | 450 | /* Make sure this doesn't get reused before tasklet_sched */ |
454 | - spin_lock(&base[i].lock); | |
455 | - if (base[i].cpu == smp_processor_id()) { | |
456 | - if (base[i].timer) | |
457 | - expires = base[i].timer->it.mmtimer.expires; | |
451 | + spin_lock(&base->lock); | |
452 | + if (base->cpu == smp_processor_id()) { | |
453 | + if (base->timer) | |
454 | + expires = base->timer->it.mmtimer.expires; | |
458 | 455 | /* expires test won't work with shared irqs */ |
459 | 456 | if ((mmtimer_int_pending(i) > 0) || |
460 | 457 | (expires && (expires < rtc_time()))) { |
461 | 458 | mmtimer_clr_int_pending(i); |
462 | - tasklet_schedule(&base[i].tasklet); | |
459 | + tasklet_schedule(&base->tasklet); | |
463 | 460 | result = IRQ_HANDLED; |
464 | 461 | } |
465 | 462 | } |
466 | - spin_unlock(&base[i].lock); | |
463 | + spin_unlock(&base->lock); | |
467 | 464 | expires = 0; |
468 | 465 | } |
469 | 466 | return result; |
... | ... | @@ -523,7 +520,7 @@ |
523 | 520 | { |
524 | 521 | int i = timr->it.mmtimer.clock; |
525 | 522 | cnodeid_t nodeid = timr->it.mmtimer.node; |
526 | - mmtimer_t *t = timers + nodeid * NUM_COMPARATORS +i; | |
523 | + mmtimer_t *t = timers[nodeid] + i; | |
527 | 524 | unsigned long irqflags; |
528 | 525 | |
529 | 526 | if (i != TIMER_OFF) { |
530 | 527 | |
... | ... | @@ -609,11 +606,11 @@ |
609 | 606 | preempt_disable(); |
610 | 607 | |
611 | 608 | nodeid = cpu_to_node(smp_processor_id()); |
612 | - base = timers + nodeid * NUM_COMPARATORS; | |
613 | 609 | retry: |
614 | 610 | /* Don't use an allocated timer, or a deleted one that's pending */ |
615 | 611 | for(i = 0; i< NUM_COMPARATORS; i++) { |
616 | - if (!base[i].timer && !base[i].tasklet.state) { | |
612 | + base = timers[nodeid] + i; | |
613 | + if (!base->timer && !base->tasklet.state) { | |
617 | 614 | break; |
618 | 615 | } |
619 | 616 | } |
620 | 617 | |
621 | 618 | |
... | ... | @@ -623,14 +620,14 @@ |
623 | 620 | return -EBUSY; |
624 | 621 | } |
625 | 622 | |
626 | - spin_lock_irqsave(&base[i].lock, irqflags); | |
623 | + spin_lock_irqsave(&base->lock, irqflags); | |
627 | 624 | |
628 | - if (base[i].timer || base[i].tasklet.state != 0) { | |
629 | - spin_unlock_irqrestore(&base[i].lock, irqflags); | |
625 | + if (base->timer || base->tasklet.state != 0) { | |
626 | + spin_unlock_irqrestore(&base->lock, irqflags); | |
630 | 627 | goto retry; |
631 | 628 | } |
632 | - base[i].timer = timr; | |
633 | - base[i].cpu = smp_processor_id(); | |
629 | + base->timer = timr; | |
630 | + base->cpu = smp_processor_id(); | |
634 | 631 | |
635 | 632 | timr->it.mmtimer.clock = i; |
636 | 633 | timr->it.mmtimer.node = nodeid; |
637 | 634 | |
... | ... | @@ -645,11 +642,11 @@ |
645 | 642 | } |
646 | 643 | } else { |
647 | 644 | timr->it.mmtimer.expires -= period; |
648 | - if (reschedule_periodic_timer(base+i)) | |
645 | + if (reschedule_periodic_timer(base)) | |
649 | 646 | err = -EINVAL; |
650 | 647 | } |
651 | 648 | |
652 | - spin_unlock_irqrestore(&base[i].lock, irqflags); | |
649 | + spin_unlock_irqrestore(&base->lock, irqflags); | |
653 | 650 | |
654 | 651 | preempt_enable(); |
655 | 652 | |
... | ... | @@ -675,6 +672,7 @@ |
675 | 672 | static int __init mmtimer_init(void) |
676 | 673 | { |
677 | 674 | unsigned i; |
675 | + cnodeid_t node, maxn = -1; | |
678 | 676 | |
679 | 677 | if (!ia64_platform_is("sn2")) |
680 | 678 | return -1; |
... | ... | @@ -691,14 +689,6 @@ |
691 | 689 | mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / |
692 | 690 | 2) / sn_rtc_cycles_per_second; |
693 | 691 | |
694 | - for (i=0; i< NUM_COMPARATORS*MAX_COMPACT_NODES; i++) { | |
695 | - spin_lock_init(&timers[i].lock); | |
696 | - timers[i].timer = NULL; | |
697 | - timers[i].cpu = 0; | |
698 | - timers[i].i = i % NUM_COMPARATORS; | |
699 | - tasklet_init(&timers[i].tasklet, mmtimer_tasklet, (unsigned long) (timers+i)); | |
700 | - } | |
701 | - | |
702 | 692 | if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, SA_PERCPU_IRQ, MMTIMER_NAME, NULL)) { |
703 | 693 | printk(KERN_WARNING "%s: unable to allocate interrupt.", |
704 | 694 | MMTIMER_NAME); |
... | ... | @@ -710,6 +700,40 @@ |
710 | 700 | printk(KERN_ERR "%s: failed to register device\n", |
711 | 701 | MMTIMER_NAME); |
712 | 702 | return -1; |
703 | + } | |
704 | + | |
705 | + /* Get max numbered node, calculate slots needed */ | |
706 | + for_each_online_node(node) { | |
707 | + maxn = node; | |
708 | + } | |
709 | + maxn++; | |
710 | + | |
711 | + /* Allocate list of node ptrs to mmtimer_t's */ | |
712 | + timers = kmalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL); | |
713 | + if (timers == NULL) { | |
714 | + printk(KERN_ERR "%s: failed to allocate memory for device\n", | |
715 | + MMTIMER_NAME); | |
716 | + return -1; | |
717 | + } | |
718 | + | |
719 | + /* Allocate mmtimer_t's for each online node */ | |
720 | + for_each_online_node(node) { | |
721 | + timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node); | |
722 | + if (timers[node] == NULL) { | |
723 | + printk(KERN_ERR "%s: failed to allocate memory for device\n", | |
724 | + MMTIMER_NAME); | |
725 | + return -1; | |
726 | + } | |
727 | + for (i=0; i< NUM_COMPARATORS; i++) { | |
728 | + mmtimer_t * base = timers[node] + i; | |
729 | + | |
730 | + spin_lock_init(&base->lock); | |
731 | + base->timer = NULL; | |
732 | + base->cpu = 0; | |
733 | + base->i = i; | |
734 | + tasklet_init(&base->tasklet, mmtimer_tasklet, | |
735 | + (unsigned long) (base)); | |
736 | + } | |
713 | 737 | } |
714 | 738 | |
715 | 739 | sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second; |