Commit 81732d1926fd50283e12b0abdcbbe8242c8bb29c
1 parent
aa6ad6fe
Implement user mode for timers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3337 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
78 additions
and
21 deletions
hw/slavio_timer.c
| @@ -47,6 +47,8 @@ do { printf("TIMER: " fmt , ##args); } while (0) | @@ -47,6 +47,8 @@ do { printf("TIMER: " fmt , ##args); } while (0) | ||
| 47 | * | 47 | * |
| 48 | */ | 48 | */ |
| 49 | 49 | ||
| 50 | +#define MAX_CPUS 16 | ||
| 51 | + | ||
| 50 | typedef struct SLAVIO_TIMERState { | 52 | typedef struct SLAVIO_TIMERState { |
| 51 | qemu_irq irq; | 53 | qemu_irq irq; |
| 52 | ptimer_state *timer; | 54 | ptimer_state *timer; |
| @@ -54,10 +56,13 @@ typedef struct SLAVIO_TIMERState { | @@ -54,10 +56,13 @@ typedef struct SLAVIO_TIMERState { | ||
| 54 | uint64_t limit; | 56 | uint64_t limit; |
| 55 | int stopped; | 57 | int stopped; |
| 56 | int mode; // 0 = processor, 1 = user, 2 = system | 58 | int mode; // 0 = processor, 1 = user, 2 = system |
| 59 | + struct SLAVIO_TIMERState *slave[MAX_CPUS]; | ||
| 60 | + uint32_t slave_mode; | ||
| 57 | } SLAVIO_TIMERState; | 61 | } SLAVIO_TIMERState; |
| 58 | 62 | ||
| 59 | #define TIMER_MAXADDR 0x1f | 63 | #define TIMER_MAXADDR 0x1f |
| 60 | #define TIMER_SIZE (TIMER_MAXADDR + 1) | 64 | #define TIMER_SIZE (TIMER_MAXADDR + 1) |
| 65 | +#define CPU_TIMER_SIZE 0x10 | ||
| 61 | 66 | ||
| 62 | // Update count, set irq, update expire_time | 67 | // Update count, set irq, update expire_time |
| 63 | // Convert from ptimer countdown units | 68 | // Convert from ptimer countdown units |
| @@ -120,7 +125,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) | @@ -120,7 +125,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) | ||
| 120 | break; | 125 | break; |
| 121 | case 4: | 126 | case 4: |
| 122 | // read user/system mode | 127 | // read user/system mode |
| 123 | - ret = s->mode & 1; | 128 | + ret = s->slave_mode; |
| 124 | break; | 129 | break; |
| 125 | default: | 130 | default: |
| 126 | ret = 0; | 131 | ret = 0; |
| @@ -141,10 +146,20 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 | @@ -141,10 +146,20 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 | ||
| 141 | saddr = (addr & TIMER_MAXADDR) >> 2; | 146 | saddr = (addr & TIMER_MAXADDR) >> 2; |
| 142 | switch (saddr) { | 147 | switch (saddr) { |
| 143 | case 0: | 148 | case 0: |
| 144 | - // set limit, reset counter | 149 | + if (s->mode == 1) { |
| 150 | + // set user counter limit MSW, reset counter | ||
| 151 | + qemu_irq_lower(s->irq); | ||
| 152 | + s->limit &= 0xfffffe00ULL; | ||
| 153 | + s->limit |= (uint64_t)val << 32; | ||
| 154 | + if (!s->limit) | ||
| 155 | + s->limit = 0x7ffffffffffffe00ULL; | ||
| 156 | + ptimer_set_limit(s->timer, s->limit >> 9, 1); | ||
| 157 | + break; | ||
| 158 | + } | ||
| 159 | + // set limit, reset counter | ||
| 145 | reload = 1; | 160 | reload = 1; |
| 146 | - qemu_irq_lower(s->irq); | ||
| 147 | - // fall through | 161 | + qemu_irq_lower(s->irq); |
| 162 | + // fall through | ||
| 148 | case 2: | 163 | case 2: |
| 149 | // set limit without resetting counter | 164 | // set limit without resetting counter |
| 150 | s->limit = val & 0x7ffffe00ULL; | 165 | s->limit = val & 0x7ffffe00ULL; |
| @@ -152,6 +167,17 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 | @@ -152,6 +167,17 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 | ||
| 152 | s->limit = 0x7ffffe00ULL; | 167 | s->limit = 0x7ffffe00ULL; |
| 153 | ptimer_set_limit(s->timer, s->limit >> 9, reload); | 168 | ptimer_set_limit(s->timer, s->limit >> 9, reload); |
| 154 | break; | 169 | break; |
| 170 | + case 1: | ||
| 171 | + // set user counter limit LSW, reset counter | ||
| 172 | + if (s->mode == 1) { | ||
| 173 | + qemu_irq_lower(s->irq); | ||
| 174 | + s->limit &= 0x7fffffff00000000ULL; | ||
| 175 | + s->limit |= val & 0xfffffe00ULL; | ||
| 176 | + if (!s->limit) | ||
| 177 | + s->limit = 0x7ffffffffffffe00ULL; | ||
| 178 | + ptimer_set_limit(s->timer, s->limit >> 9, 1); | ||
| 179 | + } | ||
| 180 | + break; | ||
| 155 | case 3: | 181 | case 3: |
| 156 | // start/stop user counter | 182 | // start/stop user counter |
| 157 | if (s->mode == 1) { | 183 | if (s->mode == 1) { |
| @@ -167,13 +193,24 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 | @@ -167,13 +193,24 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 | ||
| 167 | break; | 193 | break; |
| 168 | case 4: | 194 | case 4: |
| 169 | // bit 0: user (1) or system (0) counter mode | 195 | // bit 0: user (1) or system (0) counter mode |
| 170 | - if (s->mode == 0 || s->mode == 1) | ||
| 171 | - s->mode = val & 1; | ||
| 172 | - if (s->mode == 1) { | ||
| 173 | - qemu_irq_lower(s->irq); | ||
| 174 | - s->limit = -1ULL; | 196 | + { |
| 197 | + unsigned int i; | ||
| 198 | + | ||
| 199 | + for (i = 0; i < MAX_CPUS; i++) { | ||
| 200 | + if (val & (1 << i)) { | ||
| 201 | + qemu_irq_lower(s->slave[i]->irq); | ||
| 202 | + s->slave[i]->limit = -1ULL; | ||
| 203 | + s->slave[i]->mode = 1; | ||
| 204 | + } else { | ||
| 205 | + s->slave[i]->mode = 0; | ||
| 206 | + } | ||
| 207 | + ptimer_stop(s->slave[i]->timer); | ||
| 208 | + ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9, | ||
| 209 | + 1); | ||
| 210 | + ptimer_run(s->slave[i]->timer, 0); | ||
| 211 | + } | ||
| 212 | + s->slave_mode = val & ((1 << MAX_CPUS) - 1); | ||
| 175 | } | 213 | } |
| 176 | - ptimer_set_limit(s->timer, s->limit >> 9, 1); | ||
| 177 | break; | 214 | break; |
| 178 | default: | 215 | default: |
| 179 | break; | 216 | break; |
| @@ -240,7 +277,8 @@ static void slavio_timer_reset(void *opaque) | @@ -240,7 +277,8 @@ static void slavio_timer_reset(void *opaque) | ||
| 240 | qemu_irq_lower(s->irq); | 277 | qemu_irq_lower(s->irq); |
| 241 | } | 278 | } |
| 242 | 279 | ||
| 243 | -void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) | 280 | +static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, |
| 281 | + qemu_irq irq, int mode) | ||
| 244 | { | 282 | { |
| 245 | int slavio_timer_io_memory; | 283 | int slavio_timer_io_memory; |
| 246 | SLAVIO_TIMERState *s; | 284 | SLAVIO_TIMERState *s; |
| @@ -248,7 +286,7 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) | @@ -248,7 +286,7 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) | ||
| 248 | 286 | ||
| 249 | s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); | 287 | s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); |
| 250 | if (!s) | 288 | if (!s) |
| 251 | - return; | 289 | + return s; |
| 252 | s->irq = irq; | 290 | s->irq = irq; |
| 253 | s->mode = mode; | 291 | s->mode = mode; |
| 254 | bh = qemu_bh_new(slavio_timer_irq, s); | 292 | bh = qemu_bh_new(slavio_timer_irq, s); |
| @@ -257,8 +295,29 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) | @@ -257,8 +295,29 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) | ||
| 257 | 295 | ||
| 258 | slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, | 296 | slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, |
| 259 | slavio_timer_mem_write, s); | 297 | slavio_timer_mem_write, s); |
| 260 | - cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory); | 298 | + if (mode < 2) |
| 299 | + cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory); | ||
| 300 | + else | ||
| 301 | + cpu_register_physical_memory(addr, TIMER_SIZE, | ||
| 302 | + slavio_timer_io_memory); | ||
| 261 | register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); | 303 | register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); |
| 262 | qemu_register_reset(slavio_timer_reset, s); | 304 | qemu_register_reset(slavio_timer_reset, s); |
| 263 | slavio_timer_reset(s); | 305 | slavio_timer_reset(s); |
| 306 | + | ||
| 307 | + return s; | ||
| 308 | +} | ||
| 309 | + | ||
| 310 | +void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, | ||
| 311 | + qemu_irq *cpu_irqs) | ||
| 312 | +{ | ||
| 313 | + SLAVIO_TIMERState *master; | ||
| 314 | + unsigned int i; | ||
| 315 | + | ||
| 316 | + master = slavio_timer_init(base + 0x10000ULL, master_irq, 2); | ||
| 317 | + | ||
| 318 | + for (i = 0; i < MAX_CPUS; i++) { | ||
| 319 | + master->slave[i] = slavio_timer_init(base + (target_phys_addr_t) | ||
| 320 | + (i * TARGET_PAGE_SIZE), | ||
| 321 | + cpu_irqs[i], 0); | ||
| 322 | + } | ||
| 264 | } | 323 | } |
hw/sun4m.c
| @@ -380,13 +380,10 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, | @@ -380,13 +380,10 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, | ||
| 380 | 380 | ||
| 381 | nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, | 381 | nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, |
| 382 | hwdef->nvram_size, 8); | 382 | hwdef->nvram_size, 8); |
| 383 | - for (i = 0; i < MAX_CPUS; i++) { | ||
| 384 | - slavio_timer_init(hwdef->counter_base + | ||
| 385 | - (target_phys_addr_t)(i * TARGET_PAGE_SIZE), | ||
| 386 | - slavio_cpu_irq[i], 0); | ||
| 387 | - } | ||
| 388 | - slavio_timer_init(hwdef->counter_base + 0x10000ULL, | ||
| 389 | - slavio_irq[hwdef->clock1_irq], 2); | 383 | + |
| 384 | + slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq], | ||
| 385 | + slavio_cpu_irq); | ||
| 386 | + | ||
| 390 | slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); | 387 | slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); |
| 391 | // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device | 388 | // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device |
| 392 | // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device | 389 | // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device |
vl.h
| @@ -1287,7 +1287,8 @@ int load_aout(const char *filename, uint8_t *addr); | @@ -1287,7 +1287,8 @@ int load_aout(const char *filename, uint8_t *addr); | ||
| 1287 | int load_uboot(const char *filename, target_ulong *ep, int *is_linux); | 1287 | int load_uboot(const char *filename, target_ulong *ep, int *is_linux); |
| 1288 | 1288 | ||
| 1289 | /* slavio_timer.c */ | 1289 | /* slavio_timer.c */ |
| 1290 | -void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode); | 1290 | +void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, |
| 1291 | + qemu_irq *cpu_irqs); | ||
| 1291 | 1292 | ||
| 1292 | /* slavio_serial.c */ | 1293 | /* slavio_serial.c */ |
| 1293 | SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, | 1294 | SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, |