Commit 76832c28de4fabbf32fe1e5a25194724a3430070

Authored by Dimitri Sivanich
Committed by Linus Torvalds
1 parent c0e7dcc8bc

[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;