Annotation of qemu/hw/slavio_timer.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * QEMU Sparc SLAVIO timer controller emulation
                      3:  *
                      4:  * Copyright (c) 2003-2005 Fabrice Bellard
1.1.1.4   root        5:  *
1.1       root        6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
1.1.1.4   root       24: #include "hw.h"
                     25: #include "sun4m.h"
                     26: #include "qemu-timer.h"
1.1       root       27: 
                     28: //#define DEBUG_TIMER
                     29: 
                     30: #ifdef DEBUG_TIMER
                     31: #define DPRINTF(fmt, args...) \
                     32: do { printf("TIMER: " fmt , ##args); } while (0)
                     33: #else
1.1.1.5 ! root       34: #define DPRINTF(fmt, args...) do {} while (0)
1.1       root       35: #endif
                     36: 
                     37: /*
                     38:  * Registers of hardware timer in sun4m.
                     39:  *
                     40:  * This is the timer/counter part of chip STP2001 (Slave I/O), also
                     41:  * produced as NCR89C105. See
                     42:  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
1.1.1.4   root       43:  *
1.1       root       44:  * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
                     45:  * are zero. Bit 31 is 1 when count has been reached.
                     46:  *
1.1.1.2   root       47:  * Per-CPU timers interrupt local CPU, system timer uses normal
                     48:  * interrupt routing.
                     49:  *
1.1       root       50:  */
                     51: 
1.1.1.4   root       52: #define MAX_CPUS 16
                     53: 
1.1       root       54: typedef struct SLAVIO_TIMERState {
1.1.1.4   root       55:     qemu_irq irq;
                     56:     ptimer_state *timer;
                     57:     uint32_t count, counthigh, reached;
                     58:     uint64_t limit;
                     59:     // processor only
1.1.1.5 ! root       60:     uint32_t running;
1.1.1.4   root       61:     struct SLAVIO_TIMERState *master;
1.1.1.5 ! root       62:     uint32_t slave_index;
1.1.1.4   root       63:     // system only
1.1.1.5 ! root       64:     uint32_t num_slaves;
1.1.1.4   root       65:     struct SLAVIO_TIMERState *slave[MAX_CPUS];
                     66:     uint32_t slave_mode;
1.1       root       67: } SLAVIO_TIMERState;
                     68: 
1.1.1.4   root       69: #define SYS_TIMER_SIZE 0x14
                     70: #define CPU_TIMER_SIZE 0x10
                     71: 
                     72: #define SYS_TIMER_OFFSET      0x10000ULL
                     73: #define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
                     74: 
                     75: #define TIMER_LIMIT         0
                     76: #define TIMER_COUNTER       1
                     77: #define TIMER_COUNTER_NORST 2
                     78: #define TIMER_STATUS        3
                     79: #define TIMER_MODE          4
                     80: 
                     81: #define TIMER_COUNT_MASK32 0xfffffe00
                     82: #define TIMER_LIMIT_MASK32 0x7fffffff
                     83: #define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
                     84: #define TIMER_MAX_COUNT32  0x7ffffe00ULL
                     85: #define TIMER_REACHED      0x80000000
                     86: #define TIMER_PERIOD       500ULL // 500ns
                     87: #define LIMIT_TO_PERIODS(l) ((l) >> 9)
                     88: #define PERIODS_TO_LIMIT(l) ((l) << 9)
                     89: 
                     90: static int slavio_timer_is_user(SLAVIO_TIMERState *s)
                     91: {
                     92:     return s->master && (s->master->slave_mode & (1 << s->slave_index));
                     93: }
1.1       root       94: 
                     95: // Update count, set irq, update expire_time
1.1.1.4   root       96: // Convert from ptimer countdown units
1.1       root       97: static void slavio_timer_get_out(SLAVIO_TIMERState *s)
                     98: {
1.1.1.4   root       99:     uint64_t count, limit;
1.1       root      100: 
1.1.1.4   root      101:     if (s->limit == 0) /* free-run processor or system counter */
                    102:         limit = TIMER_MAX_COUNT32;
1.1       root      103:     else
1.1.1.4   root      104:         limit = s->limit;
1.1       root      105: 
1.1.1.4   root      106:     if (s->timer)
                    107:         count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer));
                    108:     else
                    109:         count = 0;
1.1       root      110: 
1.1.1.4   root      111:     DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit,
                    112:             s->counthigh, s->count);
                    113:     s->count = count & TIMER_COUNT_MASK32;
                    114:     s->counthigh = count >> 32;
1.1       root      115: }
                    116: 
                    117: // timer callback
                    118: static void slavio_timer_irq(void *opaque)
                    119: {
                    120:     SLAVIO_TIMERState *s = opaque;
                    121: 
                    122:     slavio_timer_get_out(s);
1.1.1.4   root      123:     DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
1.1.1.5 ! root      124:     s->reached = TIMER_REACHED;
        !           125:     if (!slavio_timer_is_user(s))
1.1.1.4   root      126:         qemu_irq_raise(s->irq);
1.1       root      127: }
                    128: 
                    129: static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
                    130: {
                    131:     SLAVIO_TIMERState *s = opaque;
1.1.1.4   root      132:     uint32_t saddr, ret;
1.1       root      133: 
1.1.1.5 ! root      134:     saddr = addr >> 2;
1.1       root      135:     switch (saddr) {
1.1.1.4   root      136:     case TIMER_LIMIT:
                    137:         // read limit (system counter mode) or read most signifying
                    138:         // part of counter (user mode)
                    139:         if (slavio_timer_is_user(s)) {
                    140:             // read user timer MSW
                    141:             slavio_timer_get_out(s);
1.1.1.5 ! root      142:             ret = s->counthigh | s->reached;
1.1.1.4   root      143:         } else {
                    144:             // read limit
                    145:             // clear irq
                    146:             qemu_irq_lower(s->irq);
                    147:             s->reached = 0;
                    148:             ret = s->limit & TIMER_LIMIT_MASK32;
                    149:         }
                    150:         break;
                    151:     case TIMER_COUNTER:
                    152:         // read counter and reached bit (system mode) or read lsbits
                    153:         // of counter (user mode)
                    154:         slavio_timer_get_out(s);
                    155:         if (slavio_timer_is_user(s)) // read user timer LSW
1.1.1.5 ! root      156:             ret = s->count & TIMER_MAX_COUNT64;
1.1.1.4   root      157:         else // read limit
                    158:             ret = (s->count & TIMER_MAX_COUNT32) | s->reached;
                    159:         break;
                    160:     case TIMER_STATUS:
                    161:         // only available in processor counter/timer
                    162:         // read start/stop status
                    163:         ret = s->running;
                    164:         break;
                    165:     case TIMER_MODE:
                    166:         // only available in system counter
                    167:         // read user/system mode
                    168:         ret = s->slave_mode;
                    169:         break;
1.1       root      170:     default:
1.1.1.4   root      171:         DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr);
                    172:         ret = 0;
                    173:         break;
1.1       root      174:     }
1.1.1.4   root      175:     DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
                    176: 
                    177:     return ret;
1.1       root      178: }
                    179: 
1.1.1.4   root      180: static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
                    181:                                     uint32_t val)
1.1       root      182: {
                    183:     SLAVIO_TIMERState *s = opaque;
                    184:     uint32_t saddr;
                    185: 
1.1.1.4   root      186:     DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
1.1.1.5 ! root      187:     saddr = addr >> 2;
1.1       root      188:     switch (saddr) {
1.1.1.4   root      189:     case TIMER_LIMIT:
                    190:         if (slavio_timer_is_user(s)) {
1.1.1.5 ! root      191:             uint64_t count;
        !           192: 
1.1.1.4   root      193:             // set user counter MSW, reset counter
                    194:             s->limit = TIMER_MAX_COUNT64;
1.1.1.5 ! root      195:             s->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
        !           196:             s->reached = 0;
        !           197:             count = ((uint64_t)s->counthigh << 32) | s->count;
        !           198:             DPRINTF("processor %d user timer set to %016llx\n", s->slave_index,
        !           199:                     count);
1.1.1.4   root      200:             if (s->timer)
1.1.1.5 ! root      201:                 ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count));
1.1.1.4   root      202:         } else {
                    203:             // set limit, reset counter
                    204:             qemu_irq_lower(s->irq);
                    205:             s->limit = val & TIMER_MAX_COUNT32;
                    206:             if (s->timer) {
                    207:                 if (s->limit == 0) /* free-run */
1.1.1.5 ! root      208:                     ptimer_set_limit(s->timer,
        !           209:                                      LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
1.1.1.4   root      210:                 else
                    211:                     ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
                    212:             }
                    213:         }
                    214:         break;
                    215:     case TIMER_COUNTER:
                    216:         if (slavio_timer_is_user(s)) {
1.1.1.5 ! root      217:             uint64_t count;
        !           218: 
1.1.1.4   root      219:             // set user counter LSW, reset counter
                    220:             s->limit = TIMER_MAX_COUNT64;
1.1.1.5 ! root      221:             s->count = val & TIMER_MAX_COUNT64;
        !           222:             s->reached = 0;
        !           223:             count = ((uint64_t)s->counthigh) << 32 | s->count;
        !           224:             DPRINTF("processor %d user timer set to %016llx\n", s->slave_index,
        !           225:                     count);
1.1.1.4   root      226:             if (s->timer)
1.1.1.5 ! root      227:                 ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count));
1.1.1.4   root      228:         } else
                    229:             DPRINTF("not user timer\n");
                    230:         break;
                    231:     case TIMER_COUNTER_NORST:
                    232:         // set limit without resetting counter
                    233:         s->limit = val & TIMER_MAX_COUNT32;
                    234:         if (s->timer) {
                    235:             if (s->limit == 0) /* free-run */
1.1.1.5 ! root      236:                 ptimer_set_limit(s->timer,
        !           237:                                  LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
1.1.1.4   root      238:             else
                    239:                 ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
                    240:         }
                    241:         break;
                    242:     case TIMER_STATUS:
                    243:         if (slavio_timer_is_user(s)) {
                    244:             // start/stop user counter
                    245:             if ((val & 1) && !s->running) {
                    246:                 DPRINTF("processor %d user timer started\n", s->slave_index);
                    247:                 if (s->timer)
                    248:                     ptimer_run(s->timer, 0);
                    249:                 s->running = 1;
                    250:             } else if (!(val & 1) && s->running) {
                    251:                 DPRINTF("processor %d user timer stopped\n", s->slave_index);
                    252:                 if (s->timer)
                    253:                     ptimer_stop(s->timer);
                    254:                 s->running = 0;
                    255:             }
                    256:         }
                    257:         break;
                    258:     case TIMER_MODE:
                    259:         if (s->master == NULL) {
                    260:             unsigned int i;
                    261: 
                    262:             for (i = 0; i < s->num_slaves; i++) {
1.1.1.5 ! root      263:                 unsigned int processor = 1 << i;
        !           264: 
        !           265:                 // check for a change in timer mode for this processor
        !           266:                 if ((val & processor) != (s->slave_mode & processor)) {
        !           267:                     if (val & processor) { // counter -> user timer
        !           268:                         qemu_irq_lower(s->slave[i]->irq);
        !           269:                         // counters are always running
        !           270:                         ptimer_stop(s->slave[i]->timer);
        !           271:                         s->slave[i]->running = 0;
        !           272:                         // user timer limit is always the same
        !           273:                         s->slave[i]->limit = TIMER_MAX_COUNT64;
        !           274:                         ptimer_set_limit(s->slave[i]->timer,
        !           275:                                          LIMIT_TO_PERIODS(s->slave[i]->limit),
        !           276:                                          1);
        !           277:                         // set this processors user timer bit in config
        !           278:                         // register
        !           279:                         s->slave_mode |= processor;
        !           280:                         DPRINTF("processor %d changed from counter to user "
        !           281:                                 "timer\n", s->slave[i]->slave_index);
        !           282:                     } else { // user timer -> counter
        !           283:                         // stop the user timer if it is running
        !           284:                         if (s->slave[i]->running)
        !           285:                             ptimer_stop(s->slave[i]->timer);
        !           286:                         // start the counter
        !           287:                         ptimer_run(s->slave[i]->timer, 0);
        !           288:                         s->slave[i]->running = 1;
        !           289:                         // clear this processors user timer bit in config
        !           290:                         // register
        !           291:                         s->slave_mode &= ~processor;
        !           292:                         DPRINTF("processor %d changed from user timer to "
        !           293:                                 "counter\n", s->slave[i]->slave_index);
        !           294:                     }
1.1.1.4   root      295:                 }
                    296:             }
                    297:         } else
                    298:             DPRINTF("not system timer\n");
                    299:         break;
1.1       root      300:     default:
1.1.1.4   root      301:         DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
                    302:         break;
1.1       root      303:     }
                    304: }
                    305: 
                    306: static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
1.1.1.4   root      307:     NULL,
                    308:     NULL,
1.1       root      309:     slavio_timer_mem_readl,
                    310: };
                    311: 
                    312: static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
1.1.1.4   root      313:     NULL,
                    314:     NULL,
1.1       root      315:     slavio_timer_mem_writel,
                    316: };
                    317: 
                    318: static void slavio_timer_save(QEMUFile *f, void *opaque)
                    319: {
                    320:     SLAVIO_TIMERState *s = opaque;
                    321: 
1.1.1.4   root      322:     qemu_put_be64s(f, &s->limit);
1.1       root      323:     qemu_put_be32s(f, &s->count);
                    324:     qemu_put_be32s(f, &s->counthigh);
                    325:     qemu_put_be32s(f, &s->reached);
1.1.1.4   root      326:     qemu_put_be32s(f, &s->running);
                    327:     if (s->timer)
                    328:         qemu_put_ptimer(f, s->timer);
1.1       root      329: }
                    330: 
                    331: static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
                    332: {
                    333:     SLAVIO_TIMERState *s = opaque;
1.1.1.4   root      334: 
                    335:     if (version_id != 3)
1.1       root      336:         return -EINVAL;
                    337: 
1.1.1.4   root      338:     qemu_get_be64s(f, &s->limit);
1.1       root      339:     qemu_get_be32s(f, &s->count);
                    340:     qemu_get_be32s(f, &s->counthigh);
                    341:     qemu_get_be32s(f, &s->reached);
1.1.1.4   root      342:     qemu_get_be32s(f, &s->running);
                    343:     if (s->timer)
                    344:         qemu_get_ptimer(f, s->timer);
                    345: 
1.1       root      346:     return 0;
                    347: }
                    348: 
                    349: static void slavio_timer_reset(void *opaque)
                    350: {
                    351:     SLAVIO_TIMERState *s = opaque;
                    352: 
                    353:     s->limit = 0;
                    354:     s->count = 0;
                    355:     s->reached = 0;
1.1.1.4   root      356:     s->slave_mode = 0;
                    357:     if (!s->master || s->slave_index < s->master->num_slaves) {
                    358:         ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
                    359:         ptimer_run(s->timer, 0);
                    360:     }
                    361:     s->running = 1;
                    362:     qemu_irq_lower(s->irq);
1.1       root      363: }
                    364: 
1.1.1.4   root      365: static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr,
                    366:                                             qemu_irq irq,
                    367:                                             SLAVIO_TIMERState *master,
1.1.1.5 ! root      368:                                             uint32_t slave_index)
1.1       root      369: {
                    370:     int slavio_timer_io_memory;
                    371:     SLAVIO_TIMERState *s;
1.1.1.4   root      372:     QEMUBH *bh;
1.1       root      373: 
                    374:     s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
                    375:     s->irq = irq;
1.1.1.4   root      376:     s->master = master;
                    377:     s->slave_index = slave_index;
                    378:     if (!master || slave_index < master->num_slaves) {
                    379:         bh = qemu_bh_new(slavio_timer_irq, s);
                    380:         s->timer = ptimer_init(bh);
                    381:         ptimer_set_period(s->timer, TIMER_PERIOD);
                    382:     }
1.1       root      383: 
                    384:     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
1.1.1.4   root      385:                                                     slavio_timer_mem_write, s);
                    386:     if (master)
                    387:         cpu_register_physical_memory(addr, CPU_TIMER_SIZE,
                    388:                                      slavio_timer_io_memory);
                    389:     else
                    390:         cpu_register_physical_memory(addr, SYS_TIMER_SIZE,
                    391:                                      slavio_timer_io_memory);
                    392:     register_savevm("slavio_timer", addr, 3, slavio_timer_save,
                    393:                     slavio_timer_load, s);
1.1       root      394:     qemu_register_reset(slavio_timer_reset, s);
                    395:     slavio_timer_reset(s);
1.1.1.4   root      396: 
                    397:     return s;
                    398: }
                    399: 
                    400: void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
                    401:                            qemu_irq *cpu_irqs, unsigned int num_cpus)
                    402: {
                    403:     SLAVIO_TIMERState *master;
                    404:     unsigned int i;
                    405: 
                    406:     master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0);
                    407: 
                    408:     master->num_slaves = num_cpus;
                    409: 
                    410:     for (i = 0; i < MAX_CPUS; i++) {
                    411:         master->slave[i] = slavio_timer_init(base + (target_phys_addr_t)
                    412:                                              CPU_TIMER_OFFSET(i),
                    413:                                              cpu_irqs[i], master, i);
                    414:     }
1.1       root      415: }

unix.superglobalmegacorp.com

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