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

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.6 ! root       24: 
1.1.1.4   root       25: #include "sun4m.h"
                     26: #include "qemu-timer.h"
1.1.1.6 ! root       27: #include "sysbus.h"
1.1       root       28: 
                     29: //#define DEBUG_TIMER
                     30: 
                     31: #ifdef DEBUG_TIMER
1.1.1.6 ! root       32: #define DPRINTF(fmt, ...)                                       \
        !            33:     do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
1.1       root       34: #else
1.1.1.6 ! root       35: #define DPRINTF(fmt, ...) do {} while (0)
1.1       root       36: #endif
                     37: 
                     38: /*
                     39:  * Registers of hardware timer in sun4m.
                     40:  *
                     41:  * This is the timer/counter part of chip STP2001 (Slave I/O), also
                     42:  * produced as NCR89C105. See
                     43:  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
1.1.1.4   root       44:  *
1.1       root       45:  * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
                     46:  * are zero. Bit 31 is 1 when count has been reached.
                     47:  *
1.1.1.2   root       48:  * Per-CPU timers interrupt local CPU, system timer uses normal
                     49:  * interrupt routing.
                     50:  *
1.1       root       51:  */
                     52: 
1.1.1.4   root       53: #define MAX_CPUS 16
                     54: 
1.1       root       55: typedef struct SLAVIO_TIMERState {
1.1.1.6 ! root       56:     SysBusDevice busdev;
1.1.1.4   root       57:     qemu_irq irq;
                     58:     ptimer_state *timer;
                     59:     uint32_t count, counthigh, reached;
                     60:     uint64_t limit;
                     61:     // processor only
1.1.1.5   root       62:     uint32_t running;
1.1.1.4   root       63:     struct SLAVIO_TIMERState *master;
1.1.1.5   root       64:     uint32_t slave_index;
1.1.1.4   root       65:     // system only
1.1.1.5   root       66:     uint32_t num_slaves;
1.1.1.4   root       67:     struct SLAVIO_TIMERState *slave[MAX_CPUS];
                     68:     uint32_t slave_mode;
1.1       root       69: } SLAVIO_TIMERState;
                     70: 
1.1.1.4   root       71: #define SYS_TIMER_SIZE 0x14
                     72: #define CPU_TIMER_SIZE 0x10
                     73: 
                     74: #define SYS_TIMER_OFFSET      0x10000ULL
                     75: #define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
                     76: 
                     77: #define TIMER_LIMIT         0
                     78: #define TIMER_COUNTER       1
                     79: #define TIMER_COUNTER_NORST 2
                     80: #define TIMER_STATUS        3
                     81: #define TIMER_MODE          4
                     82: 
                     83: #define TIMER_COUNT_MASK32 0xfffffe00
                     84: #define TIMER_LIMIT_MASK32 0x7fffffff
                     85: #define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
                     86: #define TIMER_MAX_COUNT32  0x7ffffe00ULL
                     87: #define TIMER_REACHED      0x80000000
                     88: #define TIMER_PERIOD       500ULL // 500ns
                     89: #define LIMIT_TO_PERIODS(l) ((l) >> 9)
                     90: #define PERIODS_TO_LIMIT(l) ((l) << 9)
                     91: 
                     92: static int slavio_timer_is_user(SLAVIO_TIMERState *s)
                     93: {
                     94:     return s->master && (s->master->slave_mode & (1 << s->slave_index));
                     95: }
1.1       root       96: 
                     97: // Update count, set irq, update expire_time
1.1.1.4   root       98: // Convert from ptimer countdown units
1.1       root       99: static void slavio_timer_get_out(SLAVIO_TIMERState *s)
                    100: {
1.1.1.4   root      101:     uint64_t count, limit;
1.1       root      102: 
1.1.1.4   root      103:     if (s->limit == 0) /* free-run processor or system counter */
                    104:         limit = TIMER_MAX_COUNT32;
1.1       root      105:     else
1.1.1.4   root      106:         limit = s->limit;
1.1       root      107: 
1.1.1.4   root      108:     if (s->timer)
                    109:         count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer));
                    110:     else
                    111:         count = 0;
1.1       root      112: 
1.1.1.4   root      113:     DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit,
                    114:             s->counthigh, s->count);
                    115:     s->count = count & TIMER_COUNT_MASK32;
                    116:     s->counthigh = count >> 32;
1.1       root      117: }
                    118: 
                    119: // timer callback
                    120: static void slavio_timer_irq(void *opaque)
                    121: {
                    122:     SLAVIO_TIMERState *s = opaque;
                    123: 
                    124:     slavio_timer_get_out(s);
1.1.1.4   root      125:     DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
1.1.1.5   root      126:     s->reached = TIMER_REACHED;
                    127:     if (!slavio_timer_is_user(s))
1.1.1.4   root      128:         qemu_irq_raise(s->irq);
1.1       root      129: }
                    130: 
                    131: static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
                    132: {
                    133:     SLAVIO_TIMERState *s = opaque;
1.1.1.4   root      134:     uint32_t saddr, ret;
1.1       root      135: 
1.1.1.5   root      136:     saddr = addr >> 2;
1.1       root      137:     switch (saddr) {
1.1.1.4   root      138:     case TIMER_LIMIT:
                    139:         // read limit (system counter mode) or read most signifying
                    140:         // part of counter (user mode)
                    141:         if (slavio_timer_is_user(s)) {
                    142:             // read user timer MSW
                    143:             slavio_timer_get_out(s);
1.1.1.5   root      144:             ret = s->counthigh | s->reached;
1.1.1.4   root      145:         } else {
                    146:             // read limit
                    147:             // clear irq
                    148:             qemu_irq_lower(s->irq);
                    149:             s->reached = 0;
                    150:             ret = s->limit & TIMER_LIMIT_MASK32;
                    151:         }
                    152:         break;
                    153:     case TIMER_COUNTER:
                    154:         // read counter and reached bit (system mode) or read lsbits
                    155:         // of counter (user mode)
                    156:         slavio_timer_get_out(s);
                    157:         if (slavio_timer_is_user(s)) // read user timer LSW
1.1.1.5   root      158:             ret = s->count & TIMER_MAX_COUNT64;
1.1.1.4   root      159:         else // read limit
                    160:             ret = (s->count & TIMER_MAX_COUNT32) | s->reached;
                    161:         break;
                    162:     case TIMER_STATUS:
                    163:         // only available in processor counter/timer
                    164:         // read start/stop status
                    165:         ret = s->running;
                    166:         break;
                    167:     case TIMER_MODE:
                    168:         // only available in system counter
                    169:         // read user/system mode
                    170:         ret = s->slave_mode;
                    171:         break;
1.1       root      172:     default:
1.1.1.4   root      173:         DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr);
                    174:         ret = 0;
                    175:         break;
1.1       root      176:     }
1.1.1.4   root      177:     DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
                    178: 
                    179:     return ret;
1.1       root      180: }
                    181: 
1.1.1.4   root      182: static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
                    183:                                     uint32_t val)
1.1       root      184: {
                    185:     SLAVIO_TIMERState *s = opaque;
                    186:     uint32_t saddr;
                    187: 
1.1.1.4   root      188:     DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
1.1.1.5   root      189:     saddr = addr >> 2;
1.1       root      190:     switch (saddr) {
1.1.1.4   root      191:     case TIMER_LIMIT:
                    192:         if (slavio_timer_is_user(s)) {
1.1.1.5   root      193:             uint64_t count;
                    194: 
1.1.1.4   root      195:             // set user counter MSW, reset counter
                    196:             s->limit = TIMER_MAX_COUNT64;
1.1.1.5   root      197:             s->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
                    198:             s->reached = 0;
                    199:             count = ((uint64_t)s->counthigh << 32) | s->count;
1.1.1.6 ! root      200:             DPRINTF("processor %d user timer set to %016" PRIx64 "\n",
        !           201:                     s->slave_index, count);
1.1.1.4   root      202:             if (s->timer)
1.1.1.5   root      203:                 ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count));
1.1.1.4   root      204:         } else {
                    205:             // set limit, reset counter
                    206:             qemu_irq_lower(s->irq);
                    207:             s->limit = val & TIMER_MAX_COUNT32;
                    208:             if (s->timer) {
                    209:                 if (s->limit == 0) /* free-run */
1.1.1.5   root      210:                     ptimer_set_limit(s->timer,
                    211:                                      LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
1.1.1.4   root      212:                 else
                    213:                     ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
                    214:             }
                    215:         }
                    216:         break;
                    217:     case TIMER_COUNTER:
                    218:         if (slavio_timer_is_user(s)) {
1.1.1.5   root      219:             uint64_t count;
                    220: 
1.1.1.4   root      221:             // set user counter LSW, reset counter
                    222:             s->limit = TIMER_MAX_COUNT64;
1.1.1.5   root      223:             s->count = val & TIMER_MAX_COUNT64;
                    224:             s->reached = 0;
                    225:             count = ((uint64_t)s->counthigh) << 32 | s->count;
1.1.1.6 ! root      226:             DPRINTF("processor %d user timer set to %016" PRIx64 "\n",
        !           227:                     s->slave_index, count);
1.1.1.4   root      228:             if (s->timer)
1.1.1.5   root      229:                 ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count));
1.1.1.4   root      230:         } else
                    231:             DPRINTF("not user timer\n");
                    232:         break;
                    233:     case TIMER_COUNTER_NORST:
                    234:         // set limit without resetting counter
                    235:         s->limit = val & TIMER_MAX_COUNT32;
                    236:         if (s->timer) {
                    237:             if (s->limit == 0) /* free-run */
1.1.1.5   root      238:                 ptimer_set_limit(s->timer,
                    239:                                  LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
1.1.1.4   root      240:             else
                    241:                 ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
                    242:         }
                    243:         break;
                    244:     case TIMER_STATUS:
                    245:         if (slavio_timer_is_user(s)) {
                    246:             // start/stop user counter
                    247:             if ((val & 1) && !s->running) {
                    248:                 DPRINTF("processor %d user timer started\n", s->slave_index);
                    249:                 if (s->timer)
                    250:                     ptimer_run(s->timer, 0);
                    251:                 s->running = 1;
                    252:             } else if (!(val & 1) && s->running) {
                    253:                 DPRINTF("processor %d user timer stopped\n", s->slave_index);
                    254:                 if (s->timer)
                    255:                     ptimer_stop(s->timer);
                    256:                 s->running = 0;
                    257:             }
                    258:         }
                    259:         break;
                    260:     case TIMER_MODE:
                    261:         if (s->master == NULL) {
                    262:             unsigned int i;
                    263: 
                    264:             for (i = 0; i < s->num_slaves; i++) {
1.1.1.5   root      265:                 unsigned int processor = 1 << i;
                    266: 
                    267:                 // check for a change in timer mode for this processor
                    268:                 if ((val & processor) != (s->slave_mode & processor)) {
                    269:                     if (val & processor) { // counter -> user timer
                    270:                         qemu_irq_lower(s->slave[i]->irq);
                    271:                         // counters are always running
                    272:                         ptimer_stop(s->slave[i]->timer);
                    273:                         s->slave[i]->running = 0;
                    274:                         // user timer limit is always the same
                    275:                         s->slave[i]->limit = TIMER_MAX_COUNT64;
                    276:                         ptimer_set_limit(s->slave[i]->timer,
                    277:                                          LIMIT_TO_PERIODS(s->slave[i]->limit),
                    278:                                          1);
                    279:                         // set this processors user timer bit in config
                    280:                         // register
                    281:                         s->slave_mode |= processor;
                    282:                         DPRINTF("processor %d changed from counter to user "
                    283:                                 "timer\n", s->slave[i]->slave_index);
                    284:                     } else { // user timer -> counter
                    285:                         // stop the user timer if it is running
                    286:                         if (s->slave[i]->running)
                    287:                             ptimer_stop(s->slave[i]->timer);
                    288:                         // start the counter
                    289:                         ptimer_run(s->slave[i]->timer, 0);
                    290:                         s->slave[i]->running = 1;
                    291:                         // clear this processors user timer bit in config
                    292:                         // register
                    293:                         s->slave_mode &= ~processor;
                    294:                         DPRINTF("processor %d changed from user timer to "
                    295:                                 "counter\n", s->slave[i]->slave_index);
                    296:                     }
1.1.1.4   root      297:                 }
                    298:             }
                    299:         } else
                    300:             DPRINTF("not system timer\n");
                    301:         break;
1.1       root      302:     default:
1.1.1.4   root      303:         DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
                    304:         break;
1.1       root      305:     }
                    306: }
                    307: 
                    308: static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
1.1.1.4   root      309:     NULL,
                    310:     NULL,
1.1       root      311:     slavio_timer_mem_readl,
                    312: };
                    313: 
                    314: static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
1.1.1.4   root      315:     NULL,
                    316:     NULL,
1.1       root      317:     slavio_timer_mem_writel,
                    318: };
                    319: 
                    320: static void slavio_timer_save(QEMUFile *f, void *opaque)
                    321: {
                    322:     SLAVIO_TIMERState *s = opaque;
                    323: 
1.1.1.4   root      324:     qemu_put_be64s(f, &s->limit);
1.1       root      325:     qemu_put_be32s(f, &s->count);
                    326:     qemu_put_be32s(f, &s->counthigh);
                    327:     qemu_put_be32s(f, &s->reached);
1.1.1.4   root      328:     qemu_put_be32s(f, &s->running);
                    329:     if (s->timer)
                    330:         qemu_put_ptimer(f, s->timer);
1.1       root      331: }
                    332: 
                    333: static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
                    334: {
                    335:     SLAVIO_TIMERState *s = opaque;
1.1.1.4   root      336: 
                    337:     if (version_id != 3)
1.1       root      338:         return -EINVAL;
                    339: 
1.1.1.4   root      340:     qemu_get_be64s(f, &s->limit);
1.1       root      341:     qemu_get_be32s(f, &s->count);
                    342:     qemu_get_be32s(f, &s->counthigh);
                    343:     qemu_get_be32s(f, &s->reached);
1.1.1.4   root      344:     qemu_get_be32s(f, &s->running);
                    345:     if (s->timer)
                    346:         qemu_get_ptimer(f, s->timer);
                    347: 
1.1       root      348:     return 0;
                    349: }
                    350: 
                    351: static void slavio_timer_reset(void *opaque)
                    352: {
                    353:     SLAVIO_TIMERState *s = opaque;
                    354: 
                    355:     s->limit = 0;
                    356:     s->count = 0;
                    357:     s->reached = 0;
1.1.1.4   root      358:     s->slave_mode = 0;
                    359:     if (!s->master || s->slave_index < s->master->num_slaves) {
                    360:         ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
                    361:         ptimer_run(s->timer, 0);
                    362:     }
                    363:     s->running = 1;
1.1       root      364: }
                    365: 
1.1.1.4   root      366: static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr,
                    367:                                             qemu_irq irq,
                    368:                                             SLAVIO_TIMERState *master,
1.1.1.6 ! root      369:                                             uint32_t slave_index,
        !           370:                                             uint32_t num_slaves)
        !           371: {
        !           372:     DeviceState *dev;
        !           373:     SysBusDevice *s;
        !           374:     SLAVIO_TIMERState *d;
        !           375: 
        !           376:     dev = qdev_create(NULL, "slavio_timer");
        !           377:     qdev_prop_set_uint32(dev, "slave_index", slave_index);
        !           378:     qdev_prop_set_uint32(dev, "num_slaves", num_slaves);
        !           379:     qdev_prop_set_ptr(dev, "master", master);
        !           380:     qdev_init(dev);
        !           381:     s = sysbus_from_qdev(dev);
        !           382:     sysbus_connect_irq(s, 0, irq);
        !           383:     sysbus_mmio_map(s, 0, addr);
        !           384: 
        !           385:     d = FROM_SYSBUS(SLAVIO_TIMERState, s);
        !           386: 
        !           387:     return d;
        !           388: }
        !           389: 
        !           390: static void slavio_timer_init1(SysBusDevice *dev)
1.1       root      391: {
1.1.1.6 ! root      392:     int io;
        !           393:     SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
1.1.1.4   root      394:     QEMUBH *bh;
1.1       root      395: 
1.1.1.6 ! root      396:     sysbus_init_irq(dev, &s->irq);
        !           397: 
        !           398:     if (!s->master || s->slave_index < s->master->num_slaves) {
1.1.1.4   root      399:         bh = qemu_bh_new(slavio_timer_irq, s);
                    400:         s->timer = ptimer_init(bh);
                    401:         ptimer_set_period(s->timer, TIMER_PERIOD);
                    402:     }
1.1       root      403: 
1.1.1.6 ! root      404:     io = cpu_register_io_memory(slavio_timer_mem_read, slavio_timer_mem_write,
        !           405:                                 s);
        !           406:     if (s->master) {
        !           407:         sysbus_init_mmio(dev, CPU_TIMER_SIZE, io);
        !           408:     } else {
        !           409:         sysbus_init_mmio(dev, SYS_TIMER_SIZE, io);
        !           410:     }
        !           411: 
        !           412:     register_savevm("slavio_timer", -1, 3, slavio_timer_save,
1.1.1.4   root      413:                     slavio_timer_load, s);
1.1       root      414:     qemu_register_reset(slavio_timer_reset, s);
                    415:     slavio_timer_reset(s);
1.1.1.4   root      416: }
                    417: 
                    418: void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
                    419:                            qemu_irq *cpu_irqs, unsigned int num_cpus)
                    420: {
                    421:     SLAVIO_TIMERState *master;
                    422:     unsigned int i;
                    423: 
1.1.1.6 ! root      424:     master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0,
        !           425:                                num_cpus);
1.1.1.4   root      426: 
                    427:     for (i = 0; i < MAX_CPUS; i++) {
                    428:         master->slave[i] = slavio_timer_init(base + (target_phys_addr_t)
                    429:                                              CPU_TIMER_OFFSET(i),
1.1.1.6 ! root      430:                                              cpu_irqs[i], master, i, 0);
        !           431:     }
        !           432: }
        !           433: 
        !           434: static SysBusDeviceInfo slavio_timer_info = {
        !           435:     .init = slavio_timer_init1,
        !           436:     .qdev.name  = "slavio_timer",
        !           437:     .qdev.size  = sizeof(SLAVIO_TIMERState),
        !           438:     .qdev.props = (Property[]) {
        !           439:         {
        !           440:             .name = "num_slaves",
        !           441:             .info = &qdev_prop_uint32,
        !           442:             .offset = offsetof(SLAVIO_TIMERState, num_slaves),
        !           443:         },
        !           444:         {
        !           445:             .name = "slave_index",
        !           446:             .info = &qdev_prop_uint32,
        !           447:             .offset = offsetof(SLAVIO_TIMERState, slave_index),
        !           448:         },
        !           449:         {
        !           450:             .name = "master",
        !           451:             .info = &qdev_prop_ptr,
        !           452:             .offset = offsetof(SLAVIO_TIMERState, master),
        !           453:         },
        !           454:         {/* end of property list */}
1.1.1.4   root      455:     }
1.1.1.6 ! root      456: };
        !           457: 
        !           458: static void slavio_timer_register_devices(void)
        !           459: {
        !           460:     sysbus_register_withprop(&slavio_timer_info);
1.1       root      461: }
1.1.1.6 ! root      462: 
        !           463: device_init(slavio_timer_register_devices)

unix.superglobalmegacorp.com

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