Commit e1cb9502426a605e30aa4a43875161ee44a66bc2
1 parent
40a2e657
User timer limit fixes (Robert Reif)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3931 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
26 additions
and
11 deletions
hw/slavio_timer.c
| ... | ... | @@ -122,10 +122,9 @@ static void slavio_timer_irq(void *opaque) |
| 122 | 122 | |
| 123 | 123 | slavio_timer_get_out(s); |
| 124 | 124 | DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); |
| 125 | - if (!slavio_timer_is_user(s)) { | |
| 126 | - s->reached = TIMER_REACHED; | |
| 125 | + s->reached = TIMER_REACHED; | |
| 126 | + if (!slavio_timer_is_user(s)) | |
| 127 | 127 | qemu_irq_raise(s->irq); |
| 128 | - } | |
| 129 | 128 | } |
| 130 | 129 | |
| 131 | 130 | static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) |
| ... | ... | @@ -141,7 +140,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) |
| 141 | 140 | if (slavio_timer_is_user(s)) { |
| 142 | 141 | // read user timer MSW |
| 143 | 142 | slavio_timer_get_out(s); |
| 144 | - ret = s->counthigh; | |
| 143 | + ret = s->counthigh | s->reached; | |
| 145 | 144 | } else { |
| 146 | 145 | // read limit |
| 147 | 146 | // clear irq |
| ... | ... | @@ -155,7 +154,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) |
| 155 | 154 | // of counter (user mode) |
| 156 | 155 | slavio_timer_get_out(s); |
| 157 | 156 | if (slavio_timer_is_user(s)) // read user timer LSW |
| 158 | - ret = s->count & TIMER_COUNT_MASK32; | |
| 157 | + ret = s->count & TIMER_MAX_COUNT64; | |
| 159 | 158 | else // read limit |
| 160 | 159 | ret = (s->count & TIMER_MAX_COUNT32) | s->reached; |
| 161 | 160 | break; |
| ... | ... | @@ -190,12 +189,20 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, |
| 190 | 189 | switch (saddr) { |
| 191 | 190 | case TIMER_LIMIT: |
| 192 | 191 | if (slavio_timer_is_user(s)) { |
| 192 | + uint64_t count; | |
| 193 | + | |
| 193 | 194 | // set user counter MSW, reset counter |
| 194 | 195 | qemu_irq_lower(s->irq); |
| 195 | 196 | 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); | |
| 197 | + s->counthigh = val & (TIMER_MAX_COUNT64 >> 32); | |
| 198 | + s->reached = 0; | |
| 199 | + count = ((uint64_t)s->counthigh << 32) | s->count; | |
| 200 | + DPRINTF("processor %d user timer set to %016llx\n", s->slave_index, | |
| 201 | + count); | |
| 202 | + if (s->timer) { | |
| 203 | + ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count)); | |
| 204 | + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0); | |
| 205 | + } | |
| 199 | 206 | } else { |
| 200 | 207 | // set limit, reset counter |
| 201 | 208 | qemu_irq_lower(s->irq); |
| ... | ... | @@ -210,12 +217,20 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, |
| 210 | 217 | break; |
| 211 | 218 | case TIMER_COUNTER: |
| 212 | 219 | if (slavio_timer_is_user(s)) { |
| 220 | + uint64_t count; | |
| 221 | + | |
| 213 | 222 | // set user counter LSW, reset counter |
| 214 | 223 | qemu_irq_lower(s->irq); |
| 215 | 224 | 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); | |
| 225 | + s->count = val & TIMER_MAX_COUNT64; | |
| 226 | + s->reached = 0; | |
| 227 | + count = ((uint64_t)s->counthigh) << 32 | s->count; | |
| 228 | + DPRINTF("processor %d user timer set to %016llx\n", s->slave_index, | |
| 229 | + count); | |
| 230 | + if (s->timer) { | |
| 231 | + ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count)); | |
| 232 | + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0); | |
| 233 | + } | |
| 219 | 234 | } else |
| 220 | 235 | DPRINTF("not user timer\n"); |
| 221 | 236 | break; | ... | ... |