aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/mmtimer.c
diff options
context:
space:
mode:
authorDimitri Sivanich <sivanich@sgi.com>2006-01-06 12:33:41 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 18:22:28 -0500
commit76832c28de4fabbf32fe1e5a25194724a3430070 (patch)
treeaf30f03ef07b2532332b53f95f43f93c0ec3553d /drivers/char/mmtimer.c
parentc0e7dcc8bc01d7ea1865e7040a586207d1b34b36 (diff)
[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>
Diffstat (limited to 'drivers/char/mmtimer.c')
-rw-r--r--drivers/char/mmtimer.c90
1 files changed, 57 insertions, 33 deletions
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 78c89a3e7825..c92378121b4c 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -1,11 +1,11 @@
1/* 1/*
2 * Intel Multimedia Timer device implementation for SGI SN platforms. 2 * Timer device implementation for SGI SN platforms.
3 * 3 *
4 * This file is subject to the terms and conditions of the GNU General Public 4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive 5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details. 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 * This driver exports an API that should be supportable by any HPET or IA-PC 10 * This driver exports an API that should be supportable by any HPET or IA-PC
11 * multimedia timer. The code below is currently specific to the SGI Altix 11 * multimedia timer. The code below is currently specific to the SGI Altix
@@ -45,7 +45,7 @@ MODULE_LICENSE("GPL");
45/* name of the device, usually in /dev */ 45/* name of the device, usually in /dev */
46#define MMTIMER_NAME "mmtimer" 46#define MMTIMER_NAME "mmtimer"
47#define MMTIMER_DESC "SGI Altix RTC Timer" 47#define MMTIMER_DESC "SGI Altix RTC Timer"
48#define MMTIMER_VERSION "2.0" 48#define MMTIMER_VERSION "2.1"
49 49
50#define RTC_BITS 55 /* 55 bits for this implementation */ 50#define RTC_BITS 55 /* 55 bits for this implementation */
51 51
@@ -227,10 +227,7 @@ typedef struct mmtimer {
227 struct tasklet_struct tasklet; 227 struct tasklet_struct tasklet;
228} mmtimer_t; 228} mmtimer_t;
229 229
230/* 230static mmtimer_t ** timers;
231 * Total number of comparators is comparators/node * MAX nodes/running kernel
232 */
233static mmtimer_t timers[NUM_COMPARATORS*MAX_COMPACT_NODES];
234 231
235/** 232/**
236 * mmtimer_ioctl - ioctl interface for /dev/mmtimer 233 * mmtimer_ioctl - ioctl interface for /dev/mmtimer
@@ -441,29 +438,29 @@ static irqreturn_t
441mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 438mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
442{ 439{
443 int i; 440 int i;
444 mmtimer_t *base = timers + cpu_to_node(smp_processor_id()) *
445 NUM_COMPARATORS;
446 unsigned long expires = 0; 441 unsigned long expires = 0;
447 int result = IRQ_NONE; 442 int result = IRQ_NONE;
443 unsigned indx = cpu_to_node(smp_processor_id());
448 444
449 /* 445 /*
450 * Do this once for each comparison register 446 * Do this once for each comparison register
451 */ 447 */
452 for (i = 0; i < NUM_COMPARATORS; i++) { 448 for (i = 0; i < NUM_COMPARATORS; i++) {
449 mmtimer_t *base = timers[indx] + i;
453 /* Make sure this doesn't get reused before tasklet_sched */ 450 /* Make sure this doesn't get reused before tasklet_sched */
454 spin_lock(&base[i].lock); 451 spin_lock(&base->lock);
455 if (base[i].cpu == smp_processor_id()) { 452 if (base->cpu == smp_processor_id()) {
456 if (base[i].timer) 453 if (base->timer)
457 expires = base[i].timer->it.mmtimer.expires; 454 expires = base->timer->it.mmtimer.expires;
458 /* expires test won't work with shared irqs */ 455 /* expires test won't work with shared irqs */
459 if ((mmtimer_int_pending(i) > 0) || 456 if ((mmtimer_int_pending(i) > 0) ||
460 (expires && (expires < rtc_time()))) { 457 (expires && (expires < rtc_time()))) {
461 mmtimer_clr_int_pending(i); 458 mmtimer_clr_int_pending(i);
462 tasklet_schedule(&base[i].tasklet); 459 tasklet_schedule(&base->tasklet);
463 result = IRQ_HANDLED; 460 result = IRQ_HANDLED;
464 } 461 }
465 } 462 }
466 spin_unlock(&base[i].lock); 463 spin_unlock(&base->lock);
467 expires = 0; 464 expires = 0;
468 } 465 }
469 return result; 466 return result;
@@ -523,7 +520,7 @@ static int sgi_timer_del(struct k_itimer *timr)
523{ 520{
524 int i = timr->it.mmtimer.clock; 521 int i = timr->it.mmtimer.clock;
525 cnodeid_t nodeid = timr->it.mmtimer.node; 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 unsigned long irqflags; 524 unsigned long irqflags;
528 525
529 if (i != TIMER_OFF) { 526 if (i != TIMER_OFF) {
@@ -609,11 +606,11 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
609 preempt_disable(); 606 preempt_disable();
610 607
611 nodeid = cpu_to_node(smp_processor_id()); 608 nodeid = cpu_to_node(smp_processor_id());
612 base = timers + nodeid * NUM_COMPARATORS;
613retry: 609retry:
614 /* Don't use an allocated timer, or a deleted one that's pending */ 610 /* Don't use an allocated timer, or a deleted one that's pending */
615 for(i = 0; i< NUM_COMPARATORS; i++) { 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 break; 614 break;
618 } 615 }
619 } 616 }
@@ -623,14 +620,14 @@ retry:
623 return -EBUSY; 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) { 625 if (base->timer || base->tasklet.state != 0) {
629 spin_unlock_irqrestore(&base[i].lock, irqflags); 626 spin_unlock_irqrestore(&base->lock, irqflags);
630 goto retry; 627 goto retry;
631 } 628 }
632 base[i].timer = timr; 629 base->timer = timr;
633 base[i].cpu = smp_processor_id(); 630 base->cpu = smp_processor_id();
634 631
635 timr->it.mmtimer.clock = i; 632 timr->it.mmtimer.clock = i;
636 timr->it.mmtimer.node = nodeid; 633 timr->it.mmtimer.node = nodeid;
@@ -645,11 +642,11 @@ retry:
645 } 642 }
646 } else { 643 } else {
647 timr->it.mmtimer.expires -= period; 644 timr->it.mmtimer.expires -= period;
648 if (reschedule_periodic_timer(base+i)) 645 if (reschedule_periodic_timer(base))
649 err = -EINVAL; 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 preempt_enable(); 651 preempt_enable();
655 652
@@ -675,6 +672,7 @@ static struct k_clock sgi_clock = {
675static int __init mmtimer_init(void) 672static int __init mmtimer_init(void)
676{ 673{
677 unsigned i; 674 unsigned i;
675 cnodeid_t node, maxn = -1;
678 676
679 if (!ia64_platform_is("sn2")) 677 if (!ia64_platform_is("sn2"))
680 return -1; 678 return -1;
@@ -691,14 +689,6 @@ static int __init mmtimer_init(void)
691 mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / 689 mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second /
692 2) / sn_rtc_cycles_per_second; 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 if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, SA_PERCPU_IRQ, MMTIMER_NAME, NULL)) { 692 if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, SA_PERCPU_IRQ, MMTIMER_NAME, NULL)) {
703 printk(KERN_WARNING "%s: unable to allocate interrupt.", 693 printk(KERN_WARNING "%s: unable to allocate interrupt.",
704 MMTIMER_NAME); 694 MMTIMER_NAME);
@@ -712,6 +702,40 @@ static int __init mmtimer_init(void)
712 return -1; 702 return -1;
713 } 703 }
714 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 }
737 }
738
715 sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second; 739 sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second;
716 register_posix_clock(CLOCK_SGI_CYCLE, &sgi_clock); 740 register_posix_clock(CLOCK_SGI_CYCLE, &sgi_clock);
717 741