|
|
1.1 ! root 1: /* $Id: sun4-timer.c,v 1.2 2006/11/16 02:42:16 fredette Exp $ */ ! 2: ! 3: /* machine/sun4/sun4-timer.c - implementation of Sun 4 timer emulation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2006 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: #include <tme/common.h> ! 37: _TME_RCSID("$Id: sun4-timer.c,v 1.2 2006/11/16 02:42:16 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include <tme/generic/bus-device.h> ! 41: #include "sun4-impl.h" ! 42: ! 43: /* macros: */ ! 44: ! 45: /* real sun4/4c timer bits: */ ! 46: #define TME_SUN4_32_TIMER_LIMIT TME_BIT(31) ! 47: #define TME_SUN44C_TIMER_MASK (0x7ffffc00) ! 48: #define TME_SUN4M_TIMER_MASK (0x7ffffe00) ! 49: ! 50: /* define this to track interrupt rates, reporting once every N ! 51: seconds: */ ! 52: #if 1 ! 53: #define TME_SUN4_TIMER_TRACK_INT_RATE (10) ! 54: #endif ! 55: ! 56: /* this makes timer callouts. it must be called with the mutex held: */ ! 57: static void ! 58: _tme_sun4_timer_callout(struct tme_sun4 *sun4) ! 59: { ! 60: struct tme_bus_connection *conn_bus; ! 61: struct tme_sun4_timer *timer; ! 62: unsigned int int_asserted; ! 63: int again; ! 64: int rc; ! 65: ! 66: /* if this function is already running in another thread, return ! 67: now. the other thread will do our work: */ ! 68: if (sun4->tme_sun4_timer_callouts_running) { ! 69: return; ! 70: } ! 71: ! 72: /* callouts are now running: */ ! 73: sun4->tme_sun4_timer_callouts_running = TRUE; ! 74: ! 75: /* get our bus connection: */ ! 76: conn_bus = sun4->tme_sun4_buses[TME_SUN4_32_CONN_REG_TIMER]; ! 77: ! 78: /* loop forever: */ ! 79: for (again = TRUE; again;) { ! 80: again = FALSE; ! 81: ! 82: /* check all of the timers for changes: */ ! 83: timer = &sun4->tme_sun4_timers[0]; ! 84: do { ! 85: ! 86: /* if this timer needs an interrupt callout: */ ! 87: int_asserted = (timer->tme_sun4_timer_counter & TME_SUN4_32_TIMER_LIMIT) != 0; ! 88: if (!int_asserted ! 89: != !timer->tme_sun4_timer_int_asserted) { ! 90: ! 91: /* unlock our mutex: */ ! 92: tme_mutex_unlock(&sun4->tme_sun4_mutex); ! 93: ! 94: /* call out the bus interrupt signal edge: */ ! 95: rc = (*conn_bus->tme_bus_signal) ! 96: (conn_bus, ! 97: ((timer == &sun4->tme_sun4_timers[0] ! 98: ? TME_BUS_SIGNAL_INT(10) ! 99: : TME_BUS_SIGNAL_INT(14)) ! 100: | (int_asserted ! 101: ? TME_BUS_SIGNAL_LEVEL_ASSERTED ! 102: : TME_BUS_SIGNAL_LEVEL_NEGATED))); ! 103: ! 104: /* lock our mutex: */ ! 105: tme_mutex_lock(&sun4->tme_sun4_mutex); ! 106: ! 107: /* if this callout was successful, note the new state of the ! 108: interrupt signal: */ ! 109: if (rc == TME_OK) { ! 110: timer->tme_sun4_timer_int_asserted = int_asserted; ! 111: again = TRUE; ! 112: } ! 113: ! 114: /* otherwise, abort: */ ! 115: else { ! 116: abort(); ! 117: } ! 118: } ! 119: } while (++timer != (&sun4->tme_sun4_timers[0] + TME_ARRAY_ELS(sun4->tme_sun4_timers))); ! 120: ! 121: } ! 122: ! 123: /* there are no more callouts to make: */ ! 124: sun4->tme_sun4_timer_callouts_running = FALSE; ! 125: } ! 126: ! 127: /* this can be called to force an immediate timer interrupt: */ ! 128: void ! 129: _tme_sun4_timer_int_force(struct tme_sun4 *sun4, ! 130: struct tme_sun4_timer *timer) ! 131: { ! 132: ! 133: /* lock our mutex: */ ! 134: tme_mutex_lock(&sun4->tme_sun4_mutex); ! 135: ! 136: /* force an immediate timer interrupt: */ ! 137: timer->tme_sun4_timer_counter = TME_SUN4_32_TIMER_LIMIT; ! 138: timer->tme_sun4_timer_limit |= TME_SUN4_32_TIMER_LIMIT; ! 139: ! 140: /* call out any interrupts: */ ! 141: _tme_sun4_timer_callout(sun4); ! 142: ! 143: /* unlock our mutex: */ ! 144: tme_mutex_unlock(&sun4->tme_sun4_mutex); ! 145: } ! 146: ! 147: /* the sun4 timer update function. it must be called with the mutex ! 148: locked: */ ! 149: static void ! 150: _tme_sun4_timer_update(struct tme_sun4_timer *timer, struct timeval *now, struct timeval *sleep) ! 151: { ! 152: ! 153: /* get the current time: */ ! 154: gettimeofday(now, NULL); ! 155: ! 156: #ifdef TME_SUN4_TIMER_TRACK_INT_RATE ! 157: ! 158: /* if the sample time has finished: */ ! 159: if (timer->tme_sun4_timer_track_sample.tv_sec < now->tv_sec ! 160: || (timer->tme_sun4_timer_track_sample.tv_sec == now->tv_sec ! 161: && timer->tme_sun4_timer_track_sample.tv_usec <= now->tv_usec)) { ! 162: ! 163: /* if the timer has made any interrupts during the sample time: */ ! 164: if (timer->tme_sun4_timer_track_ints > 0) { ! 165: ! 166: /* log the interrupt rate: */ ! 167: tme_log(TME_SUN4_LOG_HANDLE(timer->tme_sun4_timer_sun4), ! 168: 0, TME_OK, ! 169: (TME_SUN4_LOG_HANDLE(timer->tme_sun4_timer_sun4), ! 170: "level %d timer interrupt rate: %ld/sec", ! 171: (timer == &timer->tme_sun4_timer_sun4->tme_sun4_timers[0] ! 172: ? 10 ! 173: : 14), ! 174: (timer->tme_sun4_timer_track_ints ! 175: / (now->tv_sec ! 176: - (timer->tme_sun4_timer_track_sample.tv_sec ! 177: - TME_SUN4_TIMER_TRACK_INT_RATE))))); ! 178: } ! 179: ! 180: /* reset the sampling: */ ! 181: timer->tme_sun4_timer_track_ints = 0; ! 182: timer->tme_sun4_timer_track_sample = *now; ! 183: timer->tme_sun4_timer_track_sample.tv_sec += TME_SUN4_TIMER_TRACK_INT_RATE; ! 184: } ! 185: ! 186: #endif /* TME_SUN4_TIMER_TRACK_INT_RATE */ ! 187: ! 188: /* if this timer has not reached its next limit: */ ! 189: if (__tme_predict_false(timer->tme_sun4_timer_limit_next.tv_sec > now->tv_sec ! 190: || (timer->tme_sun4_timer_limit_next.tv_sec == now->tv_sec ! 191: && timer->tme_sun4_timer_limit_next.tv_usec > now->tv_usec))) { ! 192: ! 193: /* sleep until this timer reaches its next limit: */ ! 194: sleep->tv_sec = timer->tme_sun4_timer_limit_next.tv_sec - now->tv_sec; ! 195: sleep->tv_usec = timer->tme_sun4_timer_limit_next.tv_usec - now->tv_usec; ! 196: if (timer->tme_sun4_timer_limit_next.tv_usec < now->tv_usec) { ! 197: sleep->tv_sec--; ! 198: sleep->tv_usec += 1000000; ! 199: } ! 200: return; ! 201: } ! 202: ! 203: /* set this timer's next limit time: */ ! 204: do { ! 205: timer->tme_sun4_timer_limit_next.tv_sec += timer->tme_sun4_timer_period.tv_sec; ! 206: timer->tme_sun4_timer_limit_next.tv_usec += timer->tme_sun4_timer_period.tv_usec; ! 207: if (__tme_predict_false(timer->tme_sun4_timer_limit_next.tv_usec >= 1000000)) { ! 208: timer->tme_sun4_timer_limit_next.tv_usec -= 1000000; ! 209: timer->tme_sun4_timer_limit_next.tv_sec += 1; ! 210: } ! 211: } while (timer->tme_sun4_timer_limit_next.tv_sec < now->tv_sec ! 212: || (timer->tme_sun4_timer_limit_next.tv_sec == now->tv_sec ! 213: && timer->tme_sun4_timer_limit_next.tv_usec <= now->tv_usec)); ! 214: ! 215: /* mark this timer as having reached its limit: */ ! 216: #ifdef TME_SUN4_TIMER_TRACK_INT_RATE ! 217: if (!(timer->tme_sun4_timer_counter ! 218: & TME_SUN4_32_TIMER_LIMIT)) { ! 219: timer->tme_sun4_timer_track_ints++; ! 220: } ! 221: #endif /* TME_SUN4_TIMER_TRACK_INT_RATE */ ! 222: timer->tme_sun4_timer_counter = TME_SUN4_32_TIMER_LIMIT; ! 223: timer->tme_sun4_timer_limit |= TME_SUN4_32_TIMER_LIMIT; ! 224: ! 225: /* sleep for the normal period: */ ! 226: *sleep = timer->tme_sun4_timer_period; ! 227: } ! 228: ! 229: /* this resets a timer: */ ! 230: static void ! 231: _tme_sun4_timer_reset(struct tme_sun4_timer *timer) ! 232: { ! 233: tme_uint32_t counter_one; ! 234: tme_uint32_t ticks; ! 235: tme_uint32_t ticks_max; ! 236: tme_uint32_t usecs; ! 237: ! 238: /* to keep things simpler, we always use the sun4m 500ns tick: */ ! 239: counter_one = TME_SUN4_IS_SUN44C(timer->tme_sun4_timer_sun4) ? 2 : 1; ! 240: ticks_max = (TME_SUN4M_TIMER_MASK / _TME_FIELD_MASK_FACTOR(TME_SUN4M_TIMER_MASK)) + 1; ! 241: ! 242: /* get this timer's period, in 500ns ticks. NB that we account for ! 243: the fact that timers count from [1..limit), and not [0..limit): */ ! 244: /* XXX FIXME - we assume that the limit value of one gives the ! 245: longest possible period. is this right? */ ! 246: ticks = TME_FIELD_MASK_EXTRACTU(timer->tme_sun4_timer_limit, TME_SUN4M_TIMER_MASK); ! 247: ticks = (ticks - counter_one) & (ticks_max - counter_one); ! 248: if (__tme_predict_false(ticks == 0)) { ! 249: ticks = ticks_max; ! 250: } ! 251: ! 252: /* convert the timer's period from 500ns ticks to a struct timeval ! 253: and save it: */ ! 254: usecs = ticks / 2; ! 255: timer->tme_sun4_timer_period.tv_sec = 0; ! 256: if (__tme_predict_false(usecs >= 1000000)) { ! 257: timer->tme_sun4_timer_period.tv_sec = usecs / 1000000; ! 258: usecs %= 1000000; ! 259: } ! 260: timer->tme_sun4_timer_period.tv_usec = usecs; ! 261: ! 262: /* set the next limit time for this timer: */ ! 263: gettimeofday(&timer->tme_sun4_timer_limit_next, NULL); ! 264: timer->tme_sun4_timer_limit_next.tv_sec += timer->tme_sun4_timer_period.tv_sec; ! 265: timer->tme_sun4_timer_limit_next.tv_usec += timer->tme_sun4_timer_period.tv_usec; ! 266: if (timer->tme_sun4_timer_limit_next.tv_usec >= 1000000) { ! 267: timer->tme_sun4_timer_limit_next.tv_usec -= 1000000; ! 268: timer->tme_sun4_timer_limit_next.tv_sec += 1; ! 269: } ! 270: } ! 271: ! 272: /* the sun4 timer thread: */ ! 273: static void ! 274: _tme_sun4_timer_th(struct tme_sun4_timer *timer) ! 275: { ! 276: struct tme_sun4 *sun4; ! 277: struct timeval now; ! 278: struct timeval sleep; ! 279: ! 280: /* recover our sun4: */ ! 281: sun4 = timer->tme_sun4_timer_sun4; ! 282: ! 283: /* lock our mutex: */ ! 284: tme_mutex_lock(&sun4->tme_sun4_mutex); ! 285: ! 286: /* loop forever: */ ! 287: for (;;) { ! 288: ! 289: /* update this timer: */ ! 290: _tme_sun4_timer_update(timer, &now, &sleep); ! 291: ! 292: /* call out any interrupts: */ ! 293: _tme_sun4_timer_callout(sun4); ! 294: ! 295: /* sleep, but wake up if our timer configuration changes: */ ! 296: tme_cond_sleep_yield(&timer->tme_sun4_timer_cond, ! 297: &sun4->tme_sun4_mutex, ! 298: &sleep); ! 299: } ! 300: /* NOTREACHED */ ! 301: } ! 302: ! 303: /* the sun4 timer control bus cycle handler: */ ! 304: int ! 305: _tme_sun4_timer_cycle_control(void *_sun4, struct tme_bus_cycle *cycle_init) ! 306: { ! 307: struct tme_sun4 *sun4; ! 308: unsigned int timer_i; ! 309: struct tme_sun4_timer *timer; ! 310: tme_uint32_t reg; ! 311: tme_uint32_t value32; ! 312: struct tme_bus_cycle cycle_resp; ! 313: struct timeval now; ! 314: struct timeval last_reset; ! 315: tme_uint32_t counter_one; ! 316: tme_uint32_t usecs; ! 317: tme_uint32_t ticks; ! 318: ! 319: /* recover our sun4: */ ! 320: sun4 = (struct tme_sun4 *) _sun4; ! 321: ! 322: /* this must be a full 32-bit register access: */ ! 323: if ((cycle_init->tme_bus_cycle_address % sizeof(tme_uint32_t)) != 0 ! 324: || cycle_init->tme_bus_cycle_size != sizeof(tme_uint32_t)) { ! 325: abort(); ! 326: } ! 327: ! 328: /* get the timer and register accessed: */ ! 329: if (TME_SUN4_IS_SUN44C(sun4)) { ! 330: timer_i = cycle_init->tme_bus_cycle_address / TME_SUN44C_TIMER_SIZ_REG; ! 331: reg = cycle_init->tme_bus_cycle_address & TME_SUN4_32_TIMER_SIZ_COUNTER; ! 332: } ! 333: else { ! 334: abort(); ! 335: } ! 336: timer = &sun4->tme_sun4_timers[timer_i]; ! 337: ! 338: /* lock our mutex: */ ! 339: tme_mutex_lock(&sun4->tme_sun4_mutex); ! 340: ! 341: /* if this is a read: */ ! 342: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) { ! 343: ! 344: /* dispatch on the register: */ ! 345: switch (reg) { ! 346: default: assert(FALSE); ! 347: case TME_SUN4_32_TIMER_REG_COUNTER: ! 348: ! 349: /* update the timers: */ ! 350: _tme_sun4_timer_update(timer, &now, &last_reset); ! 351: ! 352: /* get the time of the last reset: */ ! 353: last_reset = timer->tme_sun4_timer_limit_next; ! 354: if (last_reset.tv_usec < timer->tme_sun4_timer_period.tv_usec) { ! 355: last_reset.tv_sec -= 1; ! 356: last_reset.tv_usec += 1000000; ! 357: } ! 358: last_reset.tv_sec -= timer->tme_sun4_timer_period.tv_sec; ! 359: last_reset.tv_usec -= timer->tme_sun4_timer_period.tv_usec; ! 360: ! 361: /* get the number of microseconds since the last reset: */ ! 362: usecs = now.tv_sec - last_reset.tv_sec; ! 363: usecs *= 1000000; ! 364: usecs ! 365: += (((tme_int32_t) now.tv_usec) ! 366: - ((tme_int32_t) last_reset.tv_usec)); ! 367: ! 368: /* to keep things simpler, we always use the sun4m 500ns tick: */ ! 369: counter_one = TME_SUN4_IS_SUN44C(sun4) ? 2 : 1; ! 370: ! 371: /* convert the number of microseconds until this timer resets again, ! 372: to the 500ns tick counter value for the timer. NB that we ! 373: account for the fact that timers count from [1..limit), and not ! 374: [0..limit): */ ! 375: ticks = (usecs * 2) + counter_one; ! 376: TME_FIELD_MASK_DEPOSITU(timer->tme_sun4_timer_counter, ! 377: TME_SUN4M_TIMER_MASK, ! 378: ticks); ! 379: ! 380: /* read this timer's counter register: */ ! 381: value32 = timer->tme_sun4_timer_counter; ! 382: break; ! 383: ! 384: case TME_SUN4_32_TIMER_REG_LIMIT: ! 385: ! 386: /* read this timer's limit register: */ ! 387: value32 = timer->tme_sun4_timer_limit; ! 388: ! 389: /* a read of the limit register is used to acknowledge an ! 390: interrupt, which probably means clearing the limit bit on the ! 391: counter register: */ ! 392: timer->tme_sun4_timer_counter = 0; ! 393: timer->tme_sun4_timer_limit &= ~TME_SUN4_32_TIMER_LIMIT; ! 394: break; ! 395: } ! 396: ! 397: tme_log(TME_SUN4_LOG_HANDLE(sun4), 2000, TME_OK, ! 398: (TME_SUN4_LOG_HANDLE(sun4), ! 399: _("timer #%d %s -> 0x%08x"), ! 400: timer_i, ! 401: (reg == TME_SUN4_32_TIMER_REG_COUNTER ! 402: ? "counter" ! 403: : "limit"), ! 404: value32)); ! 405: ! 406: /* byteswap the register value: */ ! 407: value32 = tme_htobe_u32(value32); ! 408: } ! 409: ! 410: /* run the bus cycle: */ ! 411: cycle_resp.tme_bus_cycle_buffer = (tme_uint8_t *) &value32; ! 412: cycle_resp.tme_bus_cycle_buffer_increment = 1; ! 413: cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing; ! 414: cycle_resp.tme_bus_cycle_address = 0; ! 415: cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type ! 416: ^ (TME_BUS_CYCLE_WRITE ! 417: | TME_BUS_CYCLE_READ)); ! 418: cycle_resp.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS32_LOG2); ! 419: tme_bus_cycle_xfer(cycle_init, &cycle_resp); ! 420: ! 421: /* if this is a write: */ ! 422: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 423: ! 424: /* byteswap the register value: */ ! 425: value32 = tme_htobe_u32(value32); ! 426: ! 427: tme_log(TME_SUN4_LOG_HANDLE(sun4), 2000, TME_OK, ! 428: (TME_SUN4_LOG_HANDLE(sun4), ! 429: _("timer #%d %s <- 0x%08x"), ! 430: timer_i, ! 431: (reg == TME_SUN4_32_TIMER_REG_COUNTER ! 432: ? "counter" ! 433: : "limit"), ! 434: value32)); ! 435: ! 436: /* dispatch on the register: */ ! 437: switch (reg) { ! 438: default: assert(FALSE); ! 439: case TME_SUN4_32_TIMER_REG_COUNTER: ! 440: abort(); ! 441: ! 442: case TME_SUN4_32_TIMER_REG_LIMIT: ! 443: ! 444: /* write the timer's limit register: */ ! 445: timer->tme_sun4_timer_limit = value32; ! 446: ! 447: /* reset this timer: */ ! 448: _tme_sun4_timer_reset(timer); ! 449: ! 450: /* wake up the thread for this timer: */ ! 451: tme_cond_notify(&timer->tme_sun4_timer_cond, FALSE); ! 452: break; ! 453: } ! 454: } ! 455: ! 456: /* make any callouts: */ ! 457: _tme_sun4_timer_callout(sun4); ! 458: ! 459: /* unlock the mutex: */ ! 460: tme_mutex_unlock(&sun4->tme_sun4_mutex); ! 461: ! 462: /* no faults: */ ! 463: return (TME_OK); ! 464: } ! 465: ! 466: /* this creates the sun4 timers: */ ! 467: void ! 468: _tme_sun4_timer_new(struct tme_sun4 *sun4) ! 469: { ! 470: struct tme_sun4_timer *timer; ! 471: ! 472: /* loop over the timers: */ ! 473: timer = &sun4->tme_sun4_timers[0]; ! 474: do { ! 475: ! 476: /* initialize and reset the timer: */ ! 477: timer->tme_sun4_timer_sun4 = sun4; ! 478: tme_cond_init(&timer->tme_sun4_timer_cond); ! 479: _tme_sun4_timer_reset(timer); ! 480: ! 481: /* start the thread for this timer: */ ! 482: tme_thread_create((tme_thread_t) _tme_sun4_timer_th, timer); ! 483: ! 484: } while (++timer != (&sun4->tme_sun4_timers[0] + TME_ARRAY_ELS(sun4->tme_sun4_timers))); ! 485: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.