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, |