Annotation of tme/ic/stp22xx/stp222x-timer.c, revision 1.1.1.1

1.1       root        1: /* $Id: stp222x-timer.c,v 1.3 2010/06/05 14:38:00 fredette Exp $ */
                      2: 
                      3: /* ic/stp22xx/stp222x-timer.c - emulation of the timers of the UPA to
                      4:    SBus interface controller (STP2220) and the UPA to PCI interface
                      5:    controller (STP2222): */
                      6: 
                      7: /*
                      8:  * Copyright (c) 2009 Matt Fredette
                      9:  * All rights reserved.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *      This product includes software developed by Matt Fredette.
                     22:  * 4. The name of the author may not be used to endorse or promote products
                     23:  *    derived from this software without specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     26:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     27:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     28:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     29:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     30:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     31:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     32:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     33:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     34:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     35:  * POSSIBILITY OF SUCH DAMAGE.
                     36:  */
                     37: 
                     38: #include <tme/common.h>
                     39: _TME_RCSID("$Id: stp222x-timer.c,v 1.3 2010/06/05 14:38:00 fredette Exp $");
                     40: 
                     41: /* includes: */
                     42: #include "stp222x-impl.h"
                     43: 
                     44: /* macros: */
                     45: 
                     46: /* the counter register: */
                     47: #define TME_STP222X_TIMER_COUNT_COUNT          ((2 << 28) - (1 << 0))
                     48: 
                     49: /* the limit register: */
                     50: #define TME_STP222X_TIMER_LIMIT_INT_EN         (((tme_uint32_t) 1) << 31)
                     51: #define TME_STP222X_TIMER_LIMIT_RELOAD         TME_BIT(30)
                     52: #define TME_STP222X_TIMER_LIMIT_PERIODIC       TME_BIT(29)
                     53: #define TME_STP222X_TIMER_LIMIT_LIMIT          TME_STP222X_TIMER_COUNT_COUNT
                     54: 
                     55: /* define this to track interrupt rates, reporting once every N
                     56:    seconds: */
                     57: #if 1
                     58: #define TME_STP222X_TIMER_TRACK_INT_RATE               (10)
                     59: #endif
                     60: 
                     61: /* this updates a timer: */
                     62: static void
                     63: _tme_stp222x_timer_update(struct tme_stp222x_timer *timer,
                     64:                          struct timeval *now,
                     65:                          struct timeval *sleep)
                     66: {
                     67: 
                     68:   /* get the current time: */
                     69:   gettimeofday(now, NULL);
                     70: 
                     71: #ifdef TME_STP222X_TIMER_TRACK_INT_RATE
                     72: 
                     73:   /* if the sample time has finished: */
                     74:   if (timer->tme_stp222x_timer_track_sample.tv_sec < now->tv_sec
                     75:       || (timer->tme_stp222x_timer_track_sample.tv_sec == now->tv_sec
                     76:          && timer->tme_stp222x_timer_track_sample.tv_usec <= now->tv_usec)) {
                     77: 
                     78:     /* if the timer has made any interrupts during the sample time: */
                     79:     if (timer->tme_stp222x_timer_track_ints > 0) {
                     80: 
                     81:       /* log the interrupt rate: */
                     82:       tme_log(TME_STP222X_LOG_HANDLE(timer->tme_stp222x_timer_stp222x),
                     83:              0, TME_OK,
                     84:              (TME_STP222X_LOG_HANDLE(timer->tme_stp222x_timer_stp222x),
                     85:               "timer %d timer interrupt rate: %ld/sec",
                     86:               (timer == &timer->tme_stp222x_timer_stp222x->tme_stp222x_timers[1]),
                     87:               (timer->tme_stp222x_timer_track_ints
                     88:                / (unsigned long) (now->tv_sec
                     89:                                   - (timer->tme_stp222x_timer_track_sample.tv_sec
                     90:                                      - TME_STP222X_TIMER_TRACK_INT_RATE)))));
                     91:     }
                     92: 
                     93:     /* reset the sampling: */
                     94:     timer->tme_stp222x_timer_track_ints = 0;
                     95:     timer->tme_stp222x_timer_track_sample = *now;
                     96:     timer->tme_stp222x_timer_track_sample.tv_sec += TME_STP222X_TIMER_TRACK_INT_RATE;
                     97:   }
                     98: 
                     99: #endif /* TME_STP222X_TIMER_TRACK_INT_RATE */
                    100: 
                    101:   /* if this timer has reached its next limit: */
                    102:   if (__tme_predict_true(timer->tme_stp222x_timer_limit_next.tv_sec < now->tv_sec
                    103:                         || (timer->tme_stp222x_timer_limit_next.tv_sec == now->tv_sec
                    104:                             && timer->tme_stp222x_timer_limit_next.tv_usec <= now->tv_usec))) {
                    105: 
                    106:     /* if this timer is not in periodic mode: */
                    107:     if ((timer->tme_stp222x_timer_limit & TME_STP222X_TIMER_LIMIT_PERIODIC) == 0) {
                    108: 
                    109:       /* this timer's period is now the maximum: */
                    110:       timer->tme_stp222x_timer_period.tv_sec = ((TME_STP222X_TIMER_COUNT_COUNT + 1) / 1000000);
                    111:       timer->tme_stp222x_timer_period.tv_usec = ((TME_STP222X_TIMER_COUNT_COUNT + 1) % 1000000);
                    112:     }
                    113: 
                    114:     /* set this timer's next limit time: */
                    115:     do {
                    116:       timer->tme_stp222x_timer_limit_next.tv_sec += timer->tme_stp222x_timer_period.tv_sec;
                    117:       timer->tme_stp222x_timer_limit_next.tv_usec += timer->tme_stp222x_timer_period.tv_usec;
                    118:       if (__tme_predict_false(timer->tme_stp222x_timer_limit_next.tv_usec >= 1000000)) {
                    119:        timer->tme_stp222x_timer_limit_next.tv_usec -= 1000000;
                    120:        timer->tme_stp222x_timer_limit_next.tv_sec += 1;
                    121:       }
                    122:     } while (timer->tme_stp222x_timer_limit_next.tv_sec < now->tv_sec
                    123:             || (timer->tme_stp222x_timer_limit_next.tv_sec == now->tv_sec
                    124:                 && timer->tme_stp222x_timer_limit_next.tv_usec <= now->tv_usec));
                    125: 
                    126:     /* if this timer's interrupt is enabled: */
                    127:     if (timer->tme_stp222x_timer_limit & TME_STP222X_TIMER_LIMIT_INT_EN) {
                    128: 
                    129:       /* receive an interrupt: */
                    130: #ifdef TME_STP222X_TIMER_TRACK_INT_RATE
                    131:       timer->tme_stp222x_timer_track_ints++;
                    132: #endif /* TME_STP222X_TIMER_TRACK_INT_RATE */
                    133:       tme_stp222x_mdu_receive(timer->tme_stp222x_timer_stp222x,
                    134:                              timer->tme_stp222x_timer_idi);
                    135:     }
                    136:   }
                    137: 
                    138:   /* sleep until this timer reaches its next limit: */
                    139:   sleep->tv_sec = timer->tme_stp222x_timer_limit_next.tv_sec - now->tv_sec;
                    140:   sleep->tv_usec = timer->tme_stp222x_timer_limit_next.tv_usec - now->tv_usec;
                    141:   if (timer->tme_stp222x_timer_limit_next.tv_usec < now->tv_usec) {
                    142:     sleep->tv_sec--;
                    143:     sleep->tv_usec += 1000000;
                    144:   }
                    145: }
                    146: 
                    147: /* the stp222x timer thread: */
                    148: static void
                    149: _tme_stp222x_timer_th(void *_timer)
                    150: {
                    151:   struct tme_stp222x_timer *timer;
                    152:   struct tme_stp222x *stp222x;
                    153:   struct timeval now;
                    154:   struct timeval sleep;
                    155: 
                    156:   /* recover our data structures: */
                    157:   timer = (struct tme_stp222x_timer *) _timer;
                    158:   stp222x = timer->tme_stp222x_timer_stp222x;
                    159: 
                    160:   /* enter: */
                    161:   tme_stp22xx_enter(&stp222x->tme_stp222x);
                    162: 
                    163:   /* loop forever: */
                    164:   for (;;) {
                    165: 
                    166:     /* update this timer: */
                    167:     _tme_stp222x_timer_update(timer, &now, &sleep);
                    168: 
                    169:     /* sleep, but wake up if our timer configuration changes: */
                    170:     tme_stp22xx_cond_sleep_yield(&stp222x->tme_stp222x,
                    171:                                 &timer->tme_stp222x_timer_cond,
                    172:                                 &sleep);
                    173:   }
                    174:   /* NOTREACHED */
                    175: }
                    176: 
                    177: /* this resets a timer: */
                    178: static void
                    179: _tme_stp222x_timer_reset(struct tme_stp222x_timer *timer,
                    180:                         tme_uint32_t count)
                    181: {
                    182:   tme_uint32_t limit;
                    183:   tme_uint32_t period;
                    184: 
                    185:   /* get the timer's initial period, until the count register next
                    186:      reaches the limit.  NB that we assume that if count and limit are
                    187:      already equal now, that does not count as reaching the limit, and
                    188:      that a complete timer period is needed: */
                    189:   limit = TME_FIELD_MASK_EXTRACTU(timer->tme_stp222x_timer_limit, TME_STP222X_TIMER_LIMIT_LIMIT);
                    190:   period = ((limit - (count + 1)) & TME_STP222X_TIMER_COUNT_COUNT) + 1;
                    191: 
                    192:   /* save this timer's initial period: */
                    193:   timer->tme_stp222x_timer_period.tv_sec = 0;
                    194:   if (__tme_predict_false(period >= 1000000)) {
                    195:     timer->tme_stp222x_timer_period.tv_sec = period / 1000000;
                    196:     period %= 1000000;
                    197:   }
                    198:   timer->tme_stp222x_timer_period.tv_usec = period;
                    199: 
                    200:   /* set the next limit time for this timer: */
                    201:   gettimeofday(&timer->tme_stp222x_timer_limit_next, NULL);
                    202:   timer->tme_stp222x_timer_limit_next.tv_sec += timer->tme_stp222x_timer_period.tv_sec;
                    203:   timer->tme_stp222x_timer_limit_next.tv_usec += timer->tme_stp222x_timer_period.tv_usec;
                    204:   if (timer->tme_stp222x_timer_limit_next.tv_usec >= 1000000) {
                    205:     timer->tme_stp222x_timer_limit_next.tv_usec -= 1000000;
                    206:     timer->tme_stp222x_timer_limit_next.tv_sec += 1;
                    207:   }
                    208: }
                    209: 
                    210: /* this reads a timer's count register: */
                    211: static tme_uint32_t
                    212: _tme_stp222x_timer_count(struct tme_stp222x_timer *timer)
                    213: {
                    214:   struct timeval now;
                    215:   struct timeval sleep;
                    216:   tme_uint32_t count;
                    217: 
                    218:   /* update the timers: */
                    219:   _tme_stp222x_timer_update(timer, &now, &sleep);
                    220: 
                    221:   /* get the absolute count until the next limit: */
                    222:   count = sleep.tv_sec;
                    223:   count *= 1000000;
                    224:   count += sleep.tv_usec;
                    225: 
                    226:   /* the count register value is that distance to the limit
                    227:      register: */
                    228:   return ((timer->tme_stp222x_timer_limit
                    229:           - count)
                    230:          & TME_STP222X_TIMER_COUNT_COUNT);
                    231: }
                    232: 
                    233: /* the timer register handler: */
                    234: void
                    235: tme_stp222x_timer_regs(struct tme_stp222x *stp222x,
                    236:                       struct tme_stp222x_reg *reg)
                    237: {
                    238:   unsigned int timer_i;
                    239:   struct tme_stp222x_timer *timer;
                    240:   tme_uint32_t reg_address;
                    241:   tme_uint32_t count;
                    242:   tme_uint32_t limit;
                    243: 
                    244:   /* get the timer and register accessed: */
                    245:   reg_address = reg->tme_stp222x_reg_address;
                    246:   timer_i
                    247:     = ((reg_address
                    248:        / TME_STP222X_TIMER_SIZE)
                    249:        % TME_ARRAY_ELS(stp222x->tme_stp222x_timers));
                    250:   timer = &stp222x->tme_stp222x_timers[timer_i];
                    251:   reg_address %= TME_STP222X_TIMER_SIZE;
                    252: 
                    253:   /* if this is a write: */
                    254:   if (reg->tme_stp222x_reg_write) {
                    255: 
                    256:     tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
                    257:            (TME_STP222X_LOG_HANDLE(stp222x),
                    258:             _("timer #%d %s <- 0x%08" TME_PRIx64),
                    259:             timer_i,
                    260:             (reg_address == TME_STP222X_TIMER_COUNT
                    261:              ? "count"
                    262:              : "limit"),
                    263:             reg->tme_stp222x_reg_value));
                    264: 
                    265:     /* dispatch on the register: */
                    266:     switch (reg_address) {
                    267:     case TME_STP222X_TIMER_COUNT:
                    268: 
                    269:       /* get the new count register value: */
                    270:       count
                    271:        = (((tme_uint32_t) reg->tme_stp222x_reg_value)
                    272:           & TME_STP222X_TIMER_COUNT_COUNT);
                    273:       break;
                    274: 
                    275:     case TME_STP222X_TIMER_LIMIT:
                    276: 
                    277:       /* get the new limit register value: */
                    278:       limit
                    279:        = (((tme_uint32_t) reg->tme_stp222x_reg_value)
                    280:           & (TME_STP222X_TIMER_LIMIT_LIMIT
                    281:              | TME_STP222X_TIMER_LIMIT_INT_EN
                    282:              | TME_STP222X_TIMER_LIMIT_RELOAD
                    283:              | TME_STP222X_TIMER_LIMIT_PERIODIC));
                    284: 
                    285:       /* get the new count register value: */
                    286:       count
                    287:        = ((limit & TME_STP222X_TIMER_LIMIT_RELOAD)
                    288:           ? 0
                    289:           :  _tme_stp222x_timer_count(timer));
                    290: 
                    291:       /* write the timer's limit register: */
                    292:       timer->tme_stp222x_timer_limit = limit & ~TME_STP222X_TIMER_LIMIT_RELOAD;
                    293:       break;
                    294: 
                    295:     default: return;
                    296:     }
                    297: 
                    298:     /* reset this timer: */
                    299:     _tme_stp222x_timer_reset(timer, count);
                    300: 
                    301:     /* wake up the thread for this timer: */
                    302:     tme_stp22xx_cond_notify(&timer->tme_stp222x_timer_cond);
                    303:   }
                    304: 
                    305:   /* otherwise, this must be a read: */
                    306:   else {
                    307: 
                    308:     /* dispatch on the register: */
                    309:     switch (reg_address) {
                    310:     case TME_STP222X_TIMER_COUNT:
                    311: 
                    312:       /* read this timer's count register: */
                    313:       reg->tme_stp222x_reg_value = _tme_stp222x_timer_count(timer);
                    314:       break;
                    315: 
                    316:     case TME_STP222X_TIMER_LIMIT:
                    317: 
                    318:       /* read this timer's limit register: */
                    319:       reg->tme_stp222x_reg_value = timer->tme_stp222x_timer_limit;     
                    320:       break;
                    321: 
                    322:     default: return;
                    323:     }
                    324: 
                    325:     tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
                    326:            (TME_STP222X_LOG_HANDLE(stp222x),
                    327:             _("timer #%d %s -> 0x%08" TME_PRIx64),
                    328:             timer_i,
                    329:             (reg_address == TME_STP222X_TIMER_COUNT
                    330:              ? "count"
                    331:              : "limit"),
                    332:             reg->tme_stp222x_reg_value));
                    333:   }
                    334: 
                    335:   /* this register access has been completed: */
                    336:   reg->tme_stp222x_reg_completed = TRUE;
                    337: }
                    338: 
                    339: /* this initializes an stp222x timer: */
                    340: void
                    341: tme_stp222x_timer_init(struct tme_stp222x *stp222x,
                    342:                       struct tme_stp222x_timer *timer)
                    343: {
                    344: 
                    345:   /* initialize and reset the timer: */
                    346:   timer->tme_stp222x_timer_stp222x = stp222x;
                    347:   tme_stp22xx_cond_init(&timer->tme_stp222x_timer_cond);
                    348:   _tme_stp222x_timer_reset(timer, 0);
                    349: 
                    350:   /* start the thread for this timer: */
                    351:   tme_thread_create(_tme_stp222x_timer_th, timer);
                    352: 
                    353:   /* set the IDI for this timer: */
                    354:   timer->tme_stp222x_timer_idi
                    355:     = (TME_STP222X_IS_2220(stp222x)
                    356:        ? TME_STP2220_IDI_TIMER(timer
                    357:                               == &timer->tme_stp222x_timer_stp222x->tme_stp222x_timers[1])
                    358:        : TME_STP2222_IDI_TIMER(timer
                    359:                               == &timer->tme_stp222x_timer_stp222x->tme_stp222x_timers[1]));;
                    360: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.