os161-1.99
 All Data Structures
ltimer.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * Driver for LAMEbus clock/timer card
00032  */
00033 #include <types.h>
00034 #include <lib.h>
00035 #include <spl.h>
00036 #include <clock.h>
00037 #include <platform/bus.h>
00038 #include <lamebus/ltimer.h>
00039 #include "autoconf.h"
00040 
00041 /* Registers (offsets within slot) */
00042 #define LT_REG_SEC    0     /* time of day: seconds */
00043 #define LT_REG_NSEC   4     /* time of day: nanoseconds */
00044 #define LT_REG_ROE    8     /* Restart On countdown-timer Expiry flag */
00045 #define LT_REG_IRQ    12    /* Interrupt status register */
00046 #define LT_REG_COUNT  16    /* Time for countdown timer (usec) */
00047 #define LT_REG_SPKR   20    /* Beep control */
00048 
00049 /* Granularity of countdown timer (usec) */
00050 #define LT_GRANULARITY   1000000
00051 
00052 static bool havetimerclock;
00053 
00054 /*
00055  * Setup routine called by autoconf stuff when an ltimer is found.
00056  */
00057 int
00058 config_ltimer(struct ltimer_softc *lt, int ltimerno)
00059 {
00060         /*
00061          * Running on System/161 2.x, we always use the processor
00062          * on-chip timer for hardclock and we don't need ltimer as
00063          * hardclock.
00064          *
00065          * Ideally there should be code here that will use an ltimer
00066          * for hardclock if nothing else is available; e.g. if we
00067          * wanted to make OS/161 2.x run on System/161 1.x. However,
00068          * that requires a good bit more infrastructure for handling
00069          * timers than we have and it doesn't seem worthwhile.
00070          *
00071          * It would also require some hacking, because all CPUs need
00072          * to receive timer interrupts. (Exercise: how would you make
00073          * sure all CPUs receive exactly one timer interrupt? Remember
00074          * that LAMEbus uses level-triggered interrupts, so the
00075          * hardware interrupt line will cause repeated interrupts if
00076          * it's not reset on the device; but if it's reset on the
00077          * device before all CPUs manage to see it, those CPUs won't
00078          * be interrupted at all.)
00079          *
00080          * Note that the beep and rtclock devices *do* attach to
00081          * ltimer.
00082          */
00083         (void)ltimerno;
00084         lt->lt_hardclock = 0;
00085 
00086         /*
00087          * We do, however, use ltimer for the timer clock, since the
00088          * on-chip timer can't do that.
00089          */
00090         if (!havetimerclock) {
00091                 havetimerclock = true;
00092                 lt->lt_timerclock = 1;
00093 
00094                 /* Wire it to go off once every second. */
00095                 bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_ROE, 1);
00096                 bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT,
00097                                    LT_GRANULARITY);
00098         }
00099         
00100         return 0;
00101 }
00102 
00103 /*
00104  * Interrupt handler.
00105  */
00106 void
00107 ltimer_irq(void *vlt)
00108 {
00109         struct ltimer_softc *lt = vlt;
00110         uint32_t val;
00111 
00112         val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
00113         if (val) {
00114                 /*
00115                  * Only call hardclock if we're responsible for hardclock.
00116                  * (Any additional timer devices are unused.)
00117                  */
00118                 if (lt->lt_hardclock) {
00119                         hardclock();
00120                 }
00121                 /*
00122                  * Likewise for timerclock.
00123                  */
00124                 if (lt->lt_timerclock) {
00125                         timerclock();
00126                 }
00127         }
00128 }
00129 
00130 /*
00131  * The timer device will beep if you write to the beep register. It
00132  * doesn't matter what value you write. This function is called if
00133  * the beep device is attached to this timer. 
00134  */
00135 void
00136 ltimer_beep(void *vlt)
00137 {
00138         struct ltimer_softc *lt = vlt;
00139 
00140         bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_SPKR, 440);
00141 }
00142 
00143 /*
00144  * The timer device also has a realtime clock on it.
00145  * This function gets called if the rtclock device is attached
00146  * to this timer.
00147  */
00148 void
00149 ltimer_gettime(void *vlt, time_t *secs, uint32_t *nsecs)
00150 {
00151         struct ltimer_softc *lt = vlt;
00152         uint32_t secs1, secs2;
00153         int spl;
00154 
00155         /*
00156          * Read the seconds twice, on either side of the nanoseconds. 
00157          * If nsecs is small, use the *later* value of seconds, in case
00158          * the nanoseconds turned over between the time we got the earlier
00159          * value and the time we got nsecs.
00160          *
00161          * Note that the clock in the ltimer device is accurate down
00162          * to a single processor cycle, so this might actually matter
00163          * now and then.
00164          *
00165          * Do it with interrupts off on the current processor to avoid
00166          * getting garbage if we get an interrupt among the register
00167          * reads.
00168          */
00169 
00170         spl = splhigh();
00171 
00172         secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos,
00173                                   LT_REG_SEC);
00174         *nsecs = bus_read_register(lt->lt_bus, lt->lt_buspos,
00175                                    LT_REG_NSEC);
00176         secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos,
00177                                   LT_REG_SEC);
00178 
00179         splx(spl);
00180 
00181         if (*nsecs < 5000000) {
00182                 *secs = secs2;
00183         }
00184         else {
00185                 *secs = secs1;
00186         }
00187 }
 All Data Structures