root/kern/dev/lamebus/ltimer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. config_ltimer
  2. ltimer_irq
  3. ltimer_beep
  4. ltimer_gettime

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * Driver for LAMEbus clock/timer card
  32  */
  33 #include <types.h>
  34 #include <lib.h>
  35 #include <spl.h>
  36 #include <clock.h>
  37 #include <platform/bus.h>
  38 #include <lamebus/ltimer.h>
  39 #include "autoconf.h"
  40 
  41 /* Registers (offsets within slot) */
  42 #define LT_REG_SEC    0     /* time of day: seconds */
  43 #define LT_REG_NSEC   4     /* time of day: nanoseconds */
  44 #define LT_REG_ROE    8     /* Restart On countdown-timer Expiry flag */
  45 #define LT_REG_IRQ    12    /* Interrupt status register */
  46 #define LT_REG_COUNT  16    /* Time for countdown timer (usec) */
  47 #define LT_REG_SPKR   20    /* Beep control */
  48 
  49 /* Granularity of countdown timer (usec) */
  50 #define LT_GRANULARITY   1000000
  51 
  52 static bool havetimerclock;
  53 
  54 /*
  55  * Setup routine called by autoconf stuff when an ltimer is found.
  56  */
  57 int
  58 config_ltimer(struct ltimer_softc *lt, int ltimerno)
  59 {
  60         /*
  61          * Running on System/161 2.x, we always use the processor
  62          * on-chip timer for hardclock and we don't need ltimer as
  63          * hardclock.
  64          *
  65          * Ideally there should be code here that will use an ltimer
  66          * for hardclock if nothing else is available; e.g. if we
  67          * wanted to make OS/161 2.x run on System/161 1.x. However,
  68          * that requires a good bit more infrastructure for handling
  69          * timers than we have and it doesn't seem worthwhile.
  70          *
  71          * It would also require some hacking, because all CPUs need
  72          * to receive timer interrupts. (Exercise: how would you make
  73          * sure all CPUs receive exactly one timer interrupt? Remember
  74          * that LAMEbus uses level-triggered interrupts, so the
  75          * hardware interrupt line will cause repeated interrupts if
  76          * it's not reset on the device; but if it's reset on the
  77          * device before all CPUs manage to see it, those CPUs won't
  78          * be interrupted at all.)
  79          *
  80          * Note that the beep and rtclock devices *do* attach to
  81          * ltimer.
  82          */
  83         (void)ltimerno;
  84         lt->lt_hardclock = 0;
  85 
  86         /*
  87          * We do, however, use ltimer for the timer clock, since the
  88          * on-chip timer can't do that.
  89          */
  90         if (!havetimerclock) {
  91                 havetimerclock = true;
  92                 lt->lt_timerclock = 1;
  93 
  94                 /* Wire it to go off once every second. */
  95                 bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_ROE, 1);
  96                 bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT,
  97                                    LT_GRANULARITY);
  98         }
  99         
 100         return 0;
 101 }
 102 
 103 /*
 104  * Interrupt handler.
 105  */
 106 void
 107 ltimer_irq(void *vlt)
 108 {
 109         struct ltimer_softc *lt = vlt;
 110         uint32_t val;
 111 
 112         val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
 113         if (val) {
 114                 /*
 115                  * Only call hardclock if we're responsible for hardclock.
 116                  * (Any additional timer devices are unused.)
 117                  */
 118                 if (lt->lt_hardclock) {
 119                         hardclock();
 120                 }
 121                 /*
 122                  * Likewise for timerclock.
 123                  */
 124                 if (lt->lt_timerclock) {
 125                         timerclock();
 126                 }
 127         }
 128 }
 129 
 130 /*
 131  * The timer device will beep if you write to the beep register. It
 132  * doesn't matter what value you write. This function is called if
 133  * the beep device is attached to this timer. 
 134  */
 135 void
 136 ltimer_beep(void *vlt)
 137 {
 138         struct ltimer_softc *lt = vlt;
 139 
 140         bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_SPKR, 440);
 141 }
 142 
 143 /*
 144  * The timer device also has a realtime clock on it.
 145  * This function gets called if the rtclock device is attached
 146  * to this timer.
 147  */
 148 void
 149 ltimer_gettime(void *vlt, time_t *secs, uint32_t *nsecs)
 150 {
 151         struct ltimer_softc *lt = vlt;
 152         uint32_t secs1, secs2;
 153         int spl;
 154 
 155         /*
 156          * Read the seconds twice, on either side of the nanoseconds. 
 157          * If nsecs is small, use the *later* value of seconds, in case
 158          * the nanoseconds turned over between the time we got the earlier
 159          * value and the time we got nsecs.
 160          *
 161          * Note that the clock in the ltimer device is accurate down
 162          * to a single processor cycle, so this might actually matter
 163          * now and then.
 164          *
 165          * Do it with interrupts off on the current processor to avoid
 166          * getting garbage if we get an interrupt among the register
 167          * reads.
 168          */
 169 
 170         spl = splhigh();
 171 
 172         secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos,
 173                                   LT_REG_SEC);
 174         *nsecs = bus_read_register(lt->lt_bus, lt->lt_buspos,
 175                                    LT_REG_NSEC);
 176         secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos,
 177                                   LT_REG_SEC);
 178 
 179         splx(spl);
 180 
 181         if (*nsecs < 5000000) {
 182                 *secs = secs2;
 183         }
 184         else {
 185                 *secs = secs1;
 186         }
 187 }

/* [<][>][^][v][top][bottom][index][help] */