ia64/xen-unstable

changeset 5152:6ce01dc5f62f

bitkeeper revision 1.1553 (42948b95-gTo139RVAa2sLFVDy4KRA)

More simplification and cleanup of the ac_timer interface.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 25 14:28:37 2005 +0000 (2005-05-25)
parents 0c7bde5b8e83
children ce83bd80b6bd
files xen/arch/ia64/vlsapic.c xen/arch/x86/vmx_intercept.c xen/common/ac_timer.c xen/common/sched_bvt.c xen/common/sched_sedf.c xen/common/schedule.c xen/include/asm-ia64/vtm.h xen/include/xen/ac_timer.h
line diff
     1.1 --- a/xen/arch/ia64/vlsapic.c	Wed May 25 13:43:27 2005 +0000
     1.2 +++ b/xen/arch/ia64/vlsapic.c	Wed May 25 14:28:37 2005 +0000
     1.3 @@ -88,10 +88,10 @@ static void vtm_reset(VCPU *vcpu)
     1.4  }
     1.5  
     1.6  /* callback function when vtm_timer expires */
     1.7 -static void vtm_timer_fn(unsigned long data)
     1.8 +static void vtm_timer_fn(void *data)
     1.9  {
    1.10      vtime_t *vtm;
    1.11 -    VCPU    *vcpu = (VCPU*)data;
    1.12 +    VCPU    *vcpu = data;
    1.13      u64	    cur_itc,vitm;
    1.14  
    1.15      UINT64  vec;
    1.16 @@ -105,7 +105,6 @@ static void vtm_timer_fn(unsigned long d
    1.17   //fire_itc2 = cur_itc;
    1.18   //fire_itm2 = vitm;
    1.19      update_last_itc(vtm,cur_itc);  // pseudo read to update vITC
    1.20 -    vtm->timer_hooked = 0;
    1.21  }
    1.22  
    1.23  void vtm_init(VCPU *vcpu)
    1.24 @@ -118,12 +117,7 @@ void vtm_init(VCPU *vcpu)
    1.25      itc_freq = local_cpu_data->itc_freq;
    1.26      vtm->cfg_max_jump=itc_freq*MAX_JUMP_STEP/1000;
    1.27      vtm->cfg_min_grun=itc_freq*MIN_GUEST_RUNNING_TIME/1000;
    1.28 -    /* set up the actimer */
    1.29 -    init_ac_timer(&(vtm->vtm_timer));
    1.30 -    vtm->timer_hooked = 0;
    1.31 -    vtm->vtm_timer.cpu = 0;     /* Init value for SMP case */
    1.32 -    vtm->vtm_timer.data = (unsigned long)vcpu;
    1.33 -    vtm->vtm_timer.function = vtm_timer_fn;
    1.34 +    init_ac_timer(&vtm->vtm_timer, vtm_timer_fn, vcpu, 0);
    1.35      vtm_reset(vcpu);
    1.36  }
    1.37  
    1.38 @@ -166,10 +160,8 @@ void vtm_set_itv(VCPU *vcpu)
    1.39      vtm=&(vcpu->arch.arch_vmx.vtm);
    1.40      local_irq_save(spsr);
    1.41      itv = VPD_CR(vcpu, itv);
    1.42 -    if ( ITV_IRQ_MASK(itv) && vtm->timer_hooked ) {
    1.43 -        rem_ac_timer(&(vtm->vtm_timer));
    1.44 -        vtm->timer_hooked = 0;
    1.45 -    }
    1.46 +    if ( ITV_IRQ_MASK(itv) )
    1.47 +        rem_ac_timer(&vtm->vtm_timer);
    1.48      vtm_interruption_update(vcpu, vtm);
    1.49      local_irq_restore(spsr);
    1.50  }
    1.51 @@ -204,26 +196,17 @@ void vtm_interruption_update(VCPU *vcpu,
    1.52      
    1.53      if ( diff_last >= 0 ) {
    1.54          // interrupt already fired.
    1.55 -        if ( vtm->timer_hooked ) {
    1.56 -            rem_ac_timer(&(vtm->vtm_timer));
    1.57 -            vtm->timer_hooked = 0;          
    1.58 -        }
    1.59 +        rem_ac_timer(&vtm->vtm_timer);
    1.60      }
    1.61      else if ( diff_now >= 0 ) {
    1.62          // ITV is fired.
    1.63          vmx_vcpu_pend_interrupt(vcpu, vitv&0xff);
    1.64      }
    1.65      /* Both last_itc & cur_itc < itm, wait for fire condition */
    1.66 -    else if ( vtm->timer_hooked ) {
    1.67 +    else {
    1.68          expires = NOW() + tick_to_ns(0-diff_now) + TIMER_SLOP;
    1.69          set_ac_timer(&vtm->vtm_timer, expires);
    1.70      }
    1.71 -    else {
    1.72 -        expires = NOW() + tick_to_ns(0-diff_now) + TIMER_SLOP;
    1.73 -        vtm->vtm_timer.cpu = vcpu->processor;
    1.74 -        set_ac_timer(&vtm->vtm_timer, expires);
    1.75 -        vtm->timer_hooked = 1;
    1.76 -    }
    1.77      local_irq_restore(spsr);
    1.78  }
    1.79  
    1.80 @@ -233,16 +216,7 @@ void vtm_interruption_update(VCPU *vcpu,
    1.81   */
    1.82  void vtm_domain_out(VCPU *vcpu)
    1.83  {
    1.84 -    vtime_t     *vtm;
    1.85 -    uint64_t    spsr;
    1.86 -    
    1.87 -    vtm=&(vcpu->arch.arch_vmx.vtm);
    1.88 -    local_irq_save(spsr);
    1.89 -    if ( vtm->timer_hooked ) {
    1.90 -        rem_ac_timer(&(vtm->vtm_timer));
    1.91 -        vtm->timer_hooked = 0;
    1.92 -    }
    1.93 -    local_irq_restore(spsr);
    1.94 +    rem_ac_timer(&vcpu->arch.arch_vmx.vtm.vtm_timer);
    1.95  }
    1.96  
    1.97  /*
    1.98 @@ -257,8 +231,6 @@ void vtm_domain_in(VCPU *vcpu)
    1.99      vtm_interruption_update(vcpu, vtm);
   1.100  }
   1.101  
   1.102 -
   1.103 -
   1.104  /*
   1.105   * Next for vLSapic
   1.106   */
     2.1 --- a/xen/arch/x86/vmx_intercept.c	Wed May 25 13:43:27 2005 +0000
     2.2 +++ b/xen/arch/x86/vmx_intercept.c	Wed May 25 14:28:37 2005 +0000
     2.3 @@ -189,13 +189,13 @@ int intercept_pit_io(ioreq_t *p)
     2.4  }
     2.5  
     2.6  /* hooks function for the PIT initialization response iopacket */
     2.7 -static void pit_timer_fn(unsigned long data)
     2.8 +static void pit_timer_fn(void *data)
     2.9  {
    2.10 -    struct vmx_virpit_t *vpit = (struct vmx_virpit_t*)data;
    2.11 +    struct vmx_virpit_t *vpit = data;
    2.12  
    2.13 -    /*set the pending intr bit in shared page, send evtchn notification to myself*/
    2.14 +    /* Set the pending intr bit, and send evtchn notification to myself. */
    2.15      if (test_and_set_bit(vpit->vector, vpit->intr_bitmap))
    2.16 -        vpit->pending_intr_nr++; /* if originaly set, then count the pending intr */
    2.17 +        vpit->pending_intr_nr++; /* already set, then count the pending intr */
    2.18  
    2.19      set_ac_timer(&vpit->pit_timer, NOW() + MILLISECS(vpit->period));
    2.20  }
    2.21 @@ -249,11 +249,8 @@ void vmx_hooks_assist(struct exec_domain
    2.22          vpit->intr_bitmap = intr;
    2.23  
    2.24          /* set up the actimer */
    2.25 -        init_ac_timer(&(vpit->pit_timer));
    2.26 -        vpit->pit_timer.cpu = 0; /*FIXME: change for SMP */
    2.27 -        vpit->pit_timer.data = (unsigned long)vpit;
    2.28 -        vpit->pit_timer.function = pit_timer_fn;
    2.29 -        pit_timer_fn((unsigned long)vpit); /* timer seed */
    2.30 +        init_ac_timer(&vpit->pit_timer, pit_timer_fn, vpit, 0);
    2.31 +        pit_timer_fn(vpit); /* timer seed */
    2.32  
    2.33          /*restore the state*/
    2.34          p->state = STATE_IORESP_READY;
     3.1 --- a/xen/common/ac_timer.c	Wed May 25 13:43:27 2005 +0000
     3.2 +++ b/xen/common/ac_timer.c	Wed May 25 14:28:37 2005 +0000
     3.3 @@ -1,14 +1,8 @@
     3.4 -/****************************************************************************
     3.5 - * (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge
     3.6 - * (C) 2002-2003 University of Cambridge
     3.7 - ****************************************************************************
     3.8 - *
     3.9 - *        File: ac_timer.c
    3.10 - *      Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
    3.11 - *              Keir Fraser (kaf24@cl.cam.ac.uk)
    3.12 - *              
    3.13 - * Environment: Xen Hypervisor
    3.14 - * Description: Accurate timer for the Hypervisor
    3.15 +/******************************************************************************
    3.16 + * ac_timer.c
    3.17 + * 
    3.18 + * Copyright (c) 2002-2003 Rolf Neugebauer
    3.19 + * Copyright (c) 2002-2005 K A Fraser
    3.20   */
    3.21  
    3.22  #include <xen/config.h>
    3.23 @@ -202,7 +196,7 @@ static void ac_timer_softirq_action(void
    3.24      int              cpu = smp_processor_id();
    3.25      struct ac_timer *t, **heap;
    3.26      s_time_t         now;
    3.27 -    void             (*fn)(unsigned long);
    3.28 +    void             (*fn)(void *);
    3.29  
    3.30      ac_timers[cpu].softirqs++;
    3.31  
    3.32 @@ -219,7 +213,7 @@ static void ac_timer_softirq_action(void
    3.33  
    3.34              if ( (fn = t->function) != NULL )
    3.35              {
    3.36 -                unsigned long data = t->data;
    3.37 +                void *data = t->data;
    3.38                  spin_unlock_irq(&ac_timers[cpu].lock);
    3.39                  (*fn)(data);
    3.40                  spin_lock_irq(&ac_timers[cpu].lock);
    3.41 @@ -252,7 +246,7 @@ static void dump_timerq(unsigned char ke
    3.42          for ( j = 1; j <= GET_HEAP_SIZE(ac_timers[i].heap); j++ )
    3.43          {
    3.44              t = ac_timers[i].heap[j];
    3.45 -            printk ("  %d : %p ex=0x%08X%08X %lu\n",
    3.46 +            printk ("  %d : %p ex=0x%08X%08X %p\n",
    3.47                      j, t, (u32)(t->expires>>32), (u32)t->expires, t->data);
    3.48          }
    3.49          spin_unlock_irqrestore(&ac_timers[i].lock, flags);
     4.1 --- a/xen/common/sched_bvt.c	Wed May 25 13:43:27 2005 +0000
     4.2 +++ b/xen/common/sched_bvt.c	Wed May 25 14:28:37 2005 +0000
     4.3 @@ -94,9 +94,9 @@ static inline int __task_on_runqueue(str
     4.4  
     4.5  
     4.6  /* Warp/unwarp timer functions */
     4.7 -static void warp_timer_fn(unsigned long pointer)
     4.8 +static void warp_timer_fn(void *data)
     4.9  {
    4.10 -    struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer;
    4.11 +    struct bvt_dom_info *inf = data;
    4.12      unsigned int cpu = inf->domain->exec_domain[0]->processor;
    4.13      
    4.14      spin_lock_irq(&schedule_data[cpu].schedule_lock);
    4.15 @@ -115,9 +115,9 @@ static void warp_timer_fn(unsigned long 
    4.16      spin_unlock_irq(&schedule_data[cpu].schedule_lock);
    4.17  }
    4.18  
    4.19 -static void unwarp_timer_fn(unsigned long pointer)
    4.20 +static void unwarp_timer_fn(void *data)
    4.21  {
    4.22 -    struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer;
    4.23 +    struct bvt_dom_info *inf = data;
    4.24      unsigned int cpu = inf->domain->exec_domain[0]->processor;
    4.25  
    4.26      spin_lock_irq(&schedule_data[cpu].schedule_lock);
    4.27 @@ -212,15 +212,9 @@ static void bvt_add_task(struct exec_dom
    4.28          inf->warp_value  = 0;
    4.29          inf->warpl       = MILLISECS(2000);
    4.30          inf->warpu       = MILLISECS(1000);
    4.31 -        /* initialise the timers */
    4.32 -        init_ac_timer(&inf->warp_timer);
    4.33 -        inf->warp_timer.cpu = d->processor;
    4.34 -        inf->warp_timer.data = (unsigned long)inf;
    4.35 -        inf->warp_timer.function = &warp_timer_fn;
    4.36 -        init_ac_timer(&inf->unwarp_timer);
    4.37 -        inf->unwarp_timer.cpu = d->processor;
    4.38 -        inf->unwarp_timer.data = (unsigned long)inf;
    4.39 -        inf->unwarp_timer.function = &unwarp_timer_fn;
    4.40 +        /* Initialise the warp timers. */
    4.41 +        init_ac_timer(&inf->warp_timer, warp_timer_fn, inf, d->processor);
    4.42 +        init_ac_timer(&inf->unwarp_timer, unwarp_timer_fn, inf, d->processor);
    4.43      }
    4.44  
    4.45      einf->exec_domain = d;
     5.1 --- a/xen/common/sched_sedf.c	Wed May 25 13:43:27 2005 +0000
     5.2 +++ b/xen/common/sched_sedf.c	Wed May 25 14:28:37 2005 +0000
     5.3 @@ -116,6 +116,7 @@ struct sedf_cpu_info {
     5.4      struct list_head runnableq;
     5.5      struct list_head waitq;
     5.6      struct list_head extraq[2];
     5.7 +    s_time_t         current_slice_expires;
     5.8  };
     5.9  
    5.10  #define EDOM_INFO(d)  ((struct sedf_edom_info *)((d)->sched_priv))
    5.11 @@ -350,11 +351,12 @@ static void sedf_add_task(struct exec_do
    5.12            d->vcpu_id);
    5.13  
    5.14      /* Allocate per-CPU context if this is the first domain to be added. */
    5.15 -    if ( schedule_data[d->processor].sched_priv == NULL )
    5.16 +    if ( unlikely(schedule_data[d->processor].sched_priv == NULL) )
    5.17      {
    5.18          schedule_data[d->processor].sched_priv = 
    5.19              xmalloc(struct sedf_cpu_info);
    5.20          BUG_ON(schedule_data[d->processor].sched_priv == NULL);
    5.21 +        memset(CPU_INFO(d->processor), 0, sizeof(*CPU_INFO(d->processor)));
    5.22          INIT_LIST_HEAD(WAITQ(d->processor));
    5.23          INIT_LIST_HEAD(RUNQ(d->processor));
    5.24          INIT_LIST_HEAD(EXTRAQ(d->processor,EXTRA_PEN_Q));
    5.25 @@ -783,6 +785,7 @@ static struct task_slice sedf_do_schedul
    5.26      EDOM_INFO(ret.task)->sched_start_abs = now;
    5.27      CHECK(ret.time > 0);
    5.28      ASSERT(sedf_runnable(ret.task));
    5.29 +    CPU_INFO(cpu)->current_slice_expires = now + ret.time;
    5.30      return ret;
    5.31  }
    5.32  
    5.33 @@ -1085,8 +1088,8 @@ static inline int should_switch(struct e
    5.34      other_inf = EDOM_INFO(other);
    5.35   
    5.36   /*check whether we need to make an earlier sched-decision*/
    5.37 -    if ((PERIOD_BEGIN(other_inf) < 
    5.38 -         schedule_data[other->processor].s_timer.expires))
    5.39 +    if (PERIOD_BEGIN(other_inf) < 
    5.40 +        CPU_INFO(other->processor)->current_slice_expires)
    5.41          return 1;
    5.42      /*no timing-based switches need to be taken into account here*/
    5.43      switch (get_run_type(cur)) {
     6.1 --- a/xen/common/schedule.c	Wed May 25 13:43:27 2005 +0000
     6.2 +++ b/xen/common/schedule.c	Wed May 25 14:28:37 2005 +0000
     6.3 @@ -50,9 +50,9 @@ string_param("sched", opt_sched);
     6.4  #define TIME_SLOP      (s32)MICROSECS(50)     /* allow time to slip a bit */
     6.5  
     6.6  /* Various timer handlers. */
     6.7 -static void s_timer_fn(unsigned long unused);
     6.8 -static void t_timer_fn(unsigned long unused);
     6.9 -static void dom_timer_fn(unsigned long data);
    6.10 +static void s_timer_fn(void *unused);
    6.11 +static void t_timer_fn(void *unused);
    6.12 +static void dom_timer_fn(void *data);
    6.13  
    6.14  /* This is global for now so that private implementations can reach it */
    6.15  struct schedule_data schedule_data[NR_CPUS];
    6.16 @@ -164,10 +164,7 @@ void sched_add_domain(struct exec_domain
    6.17      struct domain *d = ed->domain;
    6.18  
    6.19      /* Initialise the per-domain timer. */
    6.20 -    init_ac_timer(&ed->timer);
    6.21 -    ed->timer.cpu      = ed->processor;
    6.22 -    ed->timer.data     = (unsigned long)ed;
    6.23 -    ed->timer.function = &dom_timer_fn;
    6.24 +    init_ac_timer(&ed->timer, dom_timer_fn, ed, ed->processor);
    6.25  
    6.26      if ( is_idle_task(d) )
    6.27      {
    6.28 @@ -486,14 +483,14 @@ int idle_cpu(int cpu)
    6.29   ****************************************************************************/
    6.30  
    6.31  /* The scheduler timer: force a run through the scheduler */
    6.32 -static void s_timer_fn(unsigned long unused)
    6.33 +static void s_timer_fn(void *unused)
    6.34  {
    6.35      raise_softirq(SCHEDULE_SOFTIRQ);
    6.36      perfc_incrc(sched_irq);
    6.37  }
    6.38  
    6.39  /* Periodic tick timer: send timer event to current domain */
    6.40 -static void t_timer_fn(unsigned long unused)
    6.41 +static void t_timer_fn(void *unused)
    6.42  {
    6.43      struct exec_domain *ed  = current;
    6.44      unsigned int        cpu = ed->processor;
    6.45 @@ -512,9 +509,9 @@ static void t_timer_fn(unsigned long unu
    6.46  }
    6.47  
    6.48  /* Domain timer function, sends a virtual timer interrupt to domain */
    6.49 -static void dom_timer_fn(unsigned long data)
    6.50 +static void dom_timer_fn(void *data)
    6.51  {
    6.52 -    struct exec_domain *ed = (struct exec_domain *)data;
    6.53 +    struct exec_domain *ed = data;
    6.54  
    6.55      update_dom_time(ed);
    6.56      send_guest_virq(ed, VIRQ_TIMER);
    6.57 @@ -530,16 +527,8 @@ void __init scheduler_init(void)
    6.58      for ( i = 0; i < NR_CPUS; i++ )
    6.59      {
    6.60          spin_lock_init(&schedule_data[i].schedule_lock);
    6.61 -
    6.62 -        init_ac_timer(&schedule_data[i].s_timer);
    6.63 -        schedule_data[i].s_timer.cpu      = i;
    6.64 -        schedule_data[i].s_timer.data     = 2;
    6.65 -        schedule_data[i].s_timer.function = &s_timer_fn;
    6.66 -
    6.67 -        init_ac_timer(&t_timer[i]);
    6.68 -        t_timer[i].cpu      = i;
    6.69 -        t_timer[i].data     = 3;
    6.70 -        t_timer[i].function = &t_timer_fn;
    6.71 +        init_ac_timer(&schedule_data[i].s_timer, s_timer_fn, NULL, i);
    6.72 +        init_ac_timer(&t_timer[i], t_timer_fn, NULL, i);
    6.73      }
    6.74  
    6.75      schedule_data[0].curr = idle_task[0];
     7.1 --- a/xen/include/asm-ia64/vtm.h	Wed May 25 13:43:27 2005 +0000
     7.2 +++ b/xen/include/asm-ia64/vtm.h	Wed May 25 14:28:37 2005 +0000
     7.3 @@ -47,7 +47,6 @@ typedef struct vtime {
     7.4      	uint64_t    cfg_min_grun;   // min guest running time since last jump
     7.5  //    	uint64_t    latest_read_itc;    // latest guest read ITC
     7.6      	struct ac_timer	vtm_timer;
     7.7 -	int        timer_hooked;	// vtm_timer is hooked
     7.8  //	int        triggered;
     7.9      	
    7.10  
     8.1 --- a/xen/include/xen/ac_timer.h	Wed May 25 13:43:27 2005 +0000
     8.2 +++ b/xen/include/xen/ac_timer.h	Wed May 25 14:28:37 2005 +0000
     8.3 @@ -1,19 +1,8 @@
     8.4 -/****************************************************************************
     8.5 - * (C) 2002 - Rolf Neugebauer - Intel Research Cambridge
     8.6 - ****************************************************************************
     8.7 - *
     8.8 - *        File: ac_timer.h
     8.9 - *      Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
    8.10 - *     Changes: 
    8.11 - *              
    8.12 - *        Date: Nov 2002
    8.13 +/******************************************************************************
    8.14 + * ac_timer.h
    8.15   * 
    8.16 - * Environment: Xen Hypervisor
    8.17 - * Description: Accurate timer for the Hypervisor
    8.18 - * 
    8.19 - ****************************************************************************
    8.20 - * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
    8.21 - ****************************************************************************
    8.22 + * Copyright (c) 2002-2003 Rolf Neugebauer
    8.23 + * Copyright (c) 2002-2005 K A Fraser
    8.24   */
    8.25  
    8.26  #ifndef _AC_TIMER_H_
    8.27 @@ -23,53 +12,53 @@
    8.28  #include <xen/time.h>
    8.29  
    8.30  struct ac_timer {
    8.31 -    /*
    8.32 -     * PUBLIC FIELDS
    8.33 -     */
    8.34      /* System time expiry value (nanoseconds since boot). */
    8.35 -    s_time_t         expires;
    8.36 +    s_time_t      expires;
    8.37      /* CPU on which this timer will be installed and executed. */
    8.38 -    unsigned int     cpu;
    8.39 +    unsigned int  cpu;
    8.40      /* On expiry, '(*function)(data)' will be executed in softirq context. */
    8.41 -    unsigned long    data;
    8.42 -    void             (*function)(unsigned long);
    8.43 -
    8.44 -    /*
    8.45 -     * PRIVATE FIELDS
    8.46 -     */
    8.47 -    unsigned int     heap_offset;
    8.48 +    void        (*function)(void *);
    8.49 +    void         *data;
    8.50 +    /* Timer-heap offset. */
    8.51 +    unsigned int  heap_offset;
    8.52  };
    8.53  
    8.54  /*
    8.55 - * This function can be called for any CPU from any CPU in any context.
    8.56 - * It initialises the private fields of the ac_timer structure.
    8.57 + * All functions below can be called for any CPU from any CPU in any context.
    8.58   */
    8.59 -static __inline__ void init_ac_timer(struct ac_timer *timer)
    8.60 -{
    8.61 -    timer->heap_offset = 0;
    8.62 -}
    8.63  
    8.64 -/*
    8.65 - * This function can be called for any CPU from any CPU in any context.
    8.66 - * It returns TRUE if the given timer is on a timer list.
    8.67 - */
    8.68 +/* Returns TRUE if the given timer is on a timer list. */
    8.69  static __inline__ int active_ac_timer(struct ac_timer *timer)
    8.70  {
    8.71      return (timer->heap_offset != 0);
    8.72  }
    8.73  
    8.74  /*
    8.75 - * This function can be called for any CPU from any CPU in any context, BUT:
    8.76 - *  -- The private fields must have been initialised (ac_timer_init).
    8.77 - *  -- All public fields must be initialised.
    8.78 + * It initialises the static fields of the ac_timer structure.
    8.79 + * It can be called multiple times to reinitialise a single (inactive) timer.
    8.80 + */
    8.81 +static __inline__ void init_ac_timer(
    8.82 +    struct ac_timer *timer,
    8.83 +    void           (*function)(void *),
    8.84 +    void            *data,
    8.85 +    unsigned int     cpu)
    8.86 +{
    8.87 +    memset(timer, 0, sizeof(*timer));
    8.88 +    timer->function = function;
    8.89 +    timer->data     = data;
    8.90 +    timer->cpu      = cpu;
    8.91 +}
    8.92 +
    8.93 +/*
    8.94 + * Set the expiry time and activate a timer (which must previously have been
    8.95 + * initialised by init_ac_timer).
    8.96   */
    8.97  extern void set_ac_timer(struct ac_timer *timer, s_time_t expires);
    8.98  
    8.99  /*
   8.100 - * This function can be called for any CPU from any CPU in any context, BUT:
   8.101 - *  -- The private fields must have been initialised (ac_timer_init).
   8.102 - *  -- All public fields must be initialised.
   8.103 - *  -- The timer must currently be on a timer list.
   8.104 + * Deactivate a timer (which must previously have been initialised by
   8.105 + * init_ac_timer). This function has no effect if the timer is not currently
   8.106 + * active.
   8.107   */
   8.108  extern void rem_ac_timer(struct ac_timer *timer);
   8.109