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

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
                     34: #define DPRINTF(fmt, args...)
                     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
        !            60:     int running;
        !            61:     struct SLAVIO_TIMERState *master;
        !            62:     int slave_index;
        !            63:     // system only
        !            64:     unsigned int num_slaves;
        !            65:     struct SLAVIO_TIMERState *slave[MAX_CPUS];
        !            66:     uint32_t slave_mode;
1.1       root       67: } SLAVIO_TIMERState;
                     68: 
                     69: #define TIMER_MAXADDR 0x1f
1.1.1.4 ! root       70: #define SYS_TIMER_SIZE 0x14
        !            71: #define CPU_TIMER_SIZE 0x10
        !            72: 
        !            73: #define SYS_TIMER_OFFSET      0x10000ULL
        !            74: #define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
        !            75: 
        !            76: #define TIMER_LIMIT         0
        !            77: #define TIMER_COUNTER       1
        !            78: #define TIMER_COUNTER_NORST 2
        !            79: #define TIMER_STATUS        3
        !            80: #define TIMER_MODE          4
        !            81: 
        !            82: #define TIMER_COUNT_MASK32 0xfffffe00
        !            83: #define TIMER_LIMIT_MASK32 0x7fffffff
        !            84: #define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
        !            85: #define TIMER_MAX_COUNT32  0x7ffffe00ULL
        !            86: #define TIMER_REACHED      0x80000000
        !            87: #define TIMER_PERIOD       500ULL // 500ns
        !            88: #define LIMIT_TO_PERIODS(l) ((l) >> 9)
        !            89: #define PERIODS_TO_LIMIT(l) ((l) << 9)
        !            90: 
        !            91: static int slavio_timer_is_user(SLAVIO_TIMERState *s)
        !            92: {
        !            93:     return s->master && (s->master->slave_mode & (1 << s->slave_index));
        !            94: }
1.1       root       95: 
                     96: // Update count, set irq, update expire_time
1.1.1.4 ! root       97: // Convert from ptimer countdown units
1.1       root       98: static void slavio_timer_get_out(SLAVIO_TIMERState *s)
                     99: {
1.1.1.4 ! root      100:     uint64_t count, limit;
1.1       root      101: 
1.1.1.4 ! root      102:     if (s->limit == 0) /* free-run processor or system counter */
        !           103:         limit = TIMER_MAX_COUNT32;
1.1       root      104:     else
1.1.1.4 ! root      105:         limit = s->limit;
1.1       root      106: 
1.1.1.4 ! root      107:     if (s->timer)
        !           108:         count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer));
        !           109:     else
        !           110:         count = 0;
1.1       root      111: 
1.1.1.4 ! root      112:     DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit,
        !           113:             s->counthigh, s->count);
        !           114:     s->count = count & TIMER_COUNT_MASK32;
        !           115:     s->counthigh = count >> 32;
1.1       root      116: }
                    117: 
                    118: // timer callback
                    119: static void slavio_timer_irq(void *opaque)
                    120: {
                    121:     SLAVIO_TIMERState *s = opaque;
                    122: 
                    123:     slavio_timer_get_out(s);
1.1.1.4 ! root      124:     DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
        !           125:     if (!slavio_timer_is_user(s)) {
        !           126:         s->reached = TIMER_REACHED;
        !           127:         qemu_irq_raise(s->irq);
        !           128:     }
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: 
                    136:     saddr = (addr & TIMER_MAXADDR) >> 2;
                    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);
        !           144:             ret = s->counthigh;
        !           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
        !           158:             ret = s->count & TIMER_COUNT_MASK32;
        !           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       root      189:     saddr = (addr & TIMER_MAXADDR) >> 2;
                    190:     switch (saddr) {
1.1.1.4 ! root      191:     case TIMER_LIMIT:
        !           192:         if (slavio_timer_is_user(s)) {
        !           193:             // set user counter MSW, reset counter
        !           194:             qemu_irq_lower(s->irq);
        !           195:             s->limit = TIMER_MAX_COUNT64;
        !           196:             DPRINTF("processor %d user timer reset\n", s->slave_index);
        !           197:             if (s->timer)
        !           198:                 ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
        !           199:         } else {
        !           200:             // set limit, reset counter
        !           201:             qemu_irq_lower(s->irq);
        !           202:             s->limit = val & TIMER_MAX_COUNT32;
        !           203:             if (s->timer) {
        !           204:                 if (s->limit == 0) /* free-run */
        !           205:                     ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
        !           206:                 else
        !           207:                     ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
        !           208:             }
        !           209:         }
        !           210:         break;
        !           211:     case TIMER_COUNTER:
        !           212:         if (slavio_timer_is_user(s)) {
        !           213:             // set user counter LSW, reset counter
        !           214:             qemu_irq_lower(s->irq);
        !           215:             s->limit = TIMER_MAX_COUNT64;
        !           216:             DPRINTF("processor %d user timer reset\n", s->slave_index);
        !           217:             if (s->timer)
        !           218:                 ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
        !           219:         } else
        !           220:             DPRINTF("not user timer\n");
        !           221:         break;
        !           222:     case TIMER_COUNTER_NORST:
        !           223:         // set limit without resetting counter
        !           224:         s->limit = val & TIMER_MAX_COUNT32;
        !           225:         if (s->timer) {
        !           226:             if (s->limit == 0) /* free-run */
        !           227:                 ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
        !           228:             else
        !           229:                 ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
        !           230:         }
        !           231:         break;
        !           232:     case TIMER_STATUS:
        !           233:         if (slavio_timer_is_user(s)) {
        !           234:             // start/stop user counter
        !           235:             if ((val & 1) && !s->running) {
        !           236:                 DPRINTF("processor %d user timer started\n", s->slave_index);
        !           237:                 if (s->timer)
        !           238:                     ptimer_run(s->timer, 0);
        !           239:                 s->running = 1;
        !           240:             } else if (!(val & 1) && s->running) {
        !           241:                 DPRINTF("processor %d user timer stopped\n", s->slave_index);
        !           242:                 if (s->timer)
        !           243:                     ptimer_stop(s->timer);
        !           244:                 s->running = 0;
        !           245:             }
        !           246:         }
        !           247:         break;
        !           248:     case TIMER_MODE:
        !           249:         if (s->master == NULL) {
        !           250:             unsigned int i;
        !           251: 
        !           252:             for (i = 0; i < s->num_slaves; i++) {
        !           253:                 if (val & (1 << i)) {
        !           254:                     qemu_irq_lower(s->slave[i]->irq);
        !           255:                     s->slave[i]->limit = -1ULL;
        !           256:                 } else {
        !           257:                     ptimer_stop(s->slave[i]->timer);
        !           258:                 }
        !           259:                 if ((val & (1 << i)) != (s->slave_mode & (1 << i))) {
        !           260:                     ptimer_stop(s->slave[i]->timer);
        !           261:                     ptimer_set_limit(s->slave[i]->timer,
        !           262:                                      LIMIT_TO_PERIODS(s->slave[i]->limit), 1);
        !           263:                     DPRINTF("processor %d timer changed\n",
        !           264:                             s->slave[i]->slave_index);
        !           265:                     ptimer_run(s->slave[i]->timer, 0);
        !           266:                 }
        !           267:             }
        !           268:             s->slave_mode = val & ((1 << s->num_slaves) - 1);
        !           269:         } else
        !           270:             DPRINTF("not system timer\n");
        !           271:         break;
1.1       root      272:     default:
1.1.1.4 ! root      273:         DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
        !           274:         break;
1.1       root      275:     }
                    276: }
                    277: 
                    278: static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
1.1.1.4 ! root      279:     NULL,
        !           280:     NULL,
1.1       root      281:     slavio_timer_mem_readl,
                    282: };
                    283: 
                    284: static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
1.1.1.4 ! root      285:     NULL,
        !           286:     NULL,
1.1       root      287:     slavio_timer_mem_writel,
                    288: };
                    289: 
                    290: static void slavio_timer_save(QEMUFile *f, void *opaque)
                    291: {
                    292:     SLAVIO_TIMERState *s = opaque;
                    293: 
1.1.1.4 ! root      294:     qemu_put_be64s(f, &s->limit);
1.1       root      295:     qemu_put_be32s(f, &s->count);
                    296:     qemu_put_be32s(f, &s->counthigh);
                    297:     qemu_put_be32s(f, &s->reached);
1.1.1.4 ! root      298:     qemu_put_be32s(f, &s->running);
        !           299:     if (s->timer)
        !           300:         qemu_put_ptimer(f, s->timer);
1.1       root      301: }
                    302: 
                    303: static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
                    304: {
                    305:     SLAVIO_TIMERState *s = opaque;
1.1.1.4 ! root      306: 
        !           307:     if (version_id != 3)
1.1       root      308:         return -EINVAL;
                    309: 
1.1.1.4 ! root      310:     qemu_get_be64s(f, &s->limit);
1.1       root      311:     qemu_get_be32s(f, &s->count);
                    312:     qemu_get_be32s(f, &s->counthigh);
                    313:     qemu_get_be32s(f, &s->reached);
1.1.1.4 ! root      314:     qemu_get_be32s(f, &s->running);
        !           315:     if (s->timer)
        !           316:         qemu_get_ptimer(f, s->timer);
        !           317: 
1.1       root      318:     return 0;
                    319: }
                    320: 
                    321: static void slavio_timer_reset(void *opaque)
                    322: {
                    323:     SLAVIO_TIMERState *s = opaque;
                    324: 
                    325:     s->limit = 0;
                    326:     s->count = 0;
                    327:     s->reached = 0;
1.1.1.4 ! root      328:     s->slave_mode = 0;
        !           329:     if (!s->master || s->slave_index < s->master->num_slaves) {
        !           330:         ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
        !           331:         ptimer_run(s->timer, 0);
        !           332:     }
        !           333:     s->running = 1;
        !           334:     qemu_irq_lower(s->irq);
1.1       root      335: }
                    336: 
1.1.1.4 ! root      337: static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr,
        !           338:                                             qemu_irq irq,
        !           339:                                             SLAVIO_TIMERState *master,
        !           340:                                             int slave_index)
1.1       root      341: {
                    342:     int slavio_timer_io_memory;
                    343:     SLAVIO_TIMERState *s;
1.1.1.4 ! root      344:     QEMUBH *bh;
1.1       root      345: 
                    346:     s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
                    347:     if (!s)
1.1.1.4 ! root      348:         return s;
1.1       root      349:     s->irq = irq;
1.1.1.4 ! root      350:     s->master = master;
        !           351:     s->slave_index = slave_index;
        !           352:     if (!master || slave_index < master->num_slaves) {
        !           353:         bh = qemu_bh_new(slavio_timer_irq, s);
        !           354:         s->timer = ptimer_init(bh);
        !           355:         ptimer_set_period(s->timer, TIMER_PERIOD);
        !           356:     }
1.1       root      357: 
                    358:     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
1.1.1.4 ! root      359:                                                     slavio_timer_mem_write, s);
        !           360:     if (master)
        !           361:         cpu_register_physical_memory(addr, CPU_TIMER_SIZE,
        !           362:                                      slavio_timer_io_memory);
        !           363:     else
        !           364:         cpu_register_physical_memory(addr, SYS_TIMER_SIZE,
        !           365:                                      slavio_timer_io_memory);
        !           366:     register_savevm("slavio_timer", addr, 3, slavio_timer_save,
        !           367:                     slavio_timer_load, s);
1.1       root      368:     qemu_register_reset(slavio_timer_reset, s);
                    369:     slavio_timer_reset(s);
1.1.1.4 ! root      370: 
        !           371:     return s;
        !           372: }
        !           373: 
        !           374: void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
        !           375:                            qemu_irq *cpu_irqs, unsigned int num_cpus)
        !           376: {
        !           377:     SLAVIO_TIMERState *master;
        !           378:     unsigned int i;
        !           379: 
        !           380:     master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0);
        !           381: 
        !           382:     master->num_slaves = num_cpus;
        !           383: 
        !           384:     for (i = 0; i < MAX_CPUS; i++) {
        !           385:         master->slave[i] = slavio_timer_init(base + (target_phys_addr_t)
        !           386:                                              CPU_TIMER_OFFSET(i),
        !           387:                                              cpu_irqs[i], master, i);
        !           388:     }
1.1       root      389: }

unix.superglobalmegacorp.com

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