|
|
1.1.1.2 ! root 1: /* $Id: sun4-timer.c,v 1.3 2010/06/05 14:38:23 fredette Exp $ */ 1.1 root 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> 1.1.1.2 ! root 37: _TME_RCSID("$Id: sun4-timer.c,v 1.3 2010/06/05 14:38:23 fredette Exp $"); 1.1 root 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 1.1.1.2 ! root 175: / (unsigned long) (now->tv_sec ! 176: - (timer->tme_sun4_timer_track_sample.tv_sec ! 177: - TME_SUN4_TIMER_TRACK_INT_RATE))))); 1.1 root 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.