ia64/xen-unstable

view tools/ioemu/hw/cuda.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 8e5fc5fe636c
children f7b43e5c42b9
line source
1 /*
2 * QEMU CUDA support
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
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 */
24 #include "vl.h"
26 //#define DEBUG_CUDA
27 //#define DEBUG_CUDA_PACKET
29 /* Bits in B data register: all active low */
30 #define TREQ 0x08 /* Transfer request (input) */
31 #define TACK 0x10 /* Transfer acknowledge (output) */
32 #define TIP 0x20 /* Transfer in progress (output) */
34 /* Bits in ACR */
35 #define SR_CTRL 0x1c /* Shift register control bits */
36 #define SR_EXT 0x0c /* Shift on external clock */
37 #define SR_OUT 0x10 /* Shift out if 1 */
39 /* Bits in IFR and IER */
40 #define IER_SET 0x80 /* set bits in IER */
41 #define IER_CLR 0 /* clear bits in IER */
42 #define SR_INT 0x04 /* Shift register full/empty */
43 #define T1_INT 0x40 /* Timer 1 interrupt */
45 /* Bits in ACR */
46 #define T1MODE 0xc0 /* Timer 1 mode */
47 #define T1MODE_CONT 0x40 /* continuous interrupts */
49 /* commands (1st byte) */
50 #define ADB_PACKET 0
51 #define CUDA_PACKET 1
52 #define ERROR_PACKET 2
53 #define TIMER_PACKET 3
54 #define POWER_PACKET 4
55 #define MACIIC_PACKET 5
56 #define PMU_PACKET 6
59 /* CUDA commands (2nd byte) */
60 #define CUDA_WARM_START 0x0
61 #define CUDA_AUTOPOLL 0x1
62 #define CUDA_GET_6805_ADDR 0x2
63 #define CUDA_GET_TIME 0x3
64 #define CUDA_GET_PRAM 0x7
65 #define CUDA_SET_6805_ADDR 0x8
66 #define CUDA_SET_TIME 0x9
67 #define CUDA_POWERDOWN 0xa
68 #define CUDA_POWERUP_TIME 0xb
69 #define CUDA_SET_PRAM 0xc
70 #define CUDA_MS_RESET 0xd
71 #define CUDA_SEND_DFAC 0xe
72 #define CUDA_BATTERY_SWAP_SENSE 0x10
73 #define CUDA_RESET_SYSTEM 0x11
74 #define CUDA_SET_IPL 0x12
75 #define CUDA_FILE_SERVER_FLAG 0x13
76 #define CUDA_SET_AUTO_RATE 0x14
77 #define CUDA_GET_AUTO_RATE 0x16
78 #define CUDA_SET_DEVICE_LIST 0x19
79 #define CUDA_GET_DEVICE_LIST 0x1a
80 #define CUDA_SET_ONE_SECOND_MODE 0x1b
81 #define CUDA_SET_POWER_MESSAGES 0x21
82 #define CUDA_GET_SET_IIC 0x22
83 #define CUDA_WAKEUP 0x23
84 #define CUDA_TIMER_TICKLE 0x24
85 #define CUDA_COMBINED_FORMAT_IIC 0x25
87 #define CUDA_TIMER_FREQ (4700000 / 6)
88 #define CUDA_ADB_POLL_FREQ 50
90 typedef struct CUDATimer {
91 unsigned int latch;
92 uint16_t counter_value; /* counter value at load time */
93 int64_t load_time;
94 int64_t next_irq_time;
95 QEMUTimer *timer;
96 } CUDATimer;
98 typedef struct CUDAState {
99 /* cuda registers */
100 uint8_t b; /* B-side data */
101 uint8_t a; /* A-side data */
102 uint8_t dirb; /* B-side direction (1=output) */
103 uint8_t dira; /* A-side direction (1=output) */
104 uint8_t sr; /* Shift register */
105 uint8_t acr; /* Auxiliary control register */
106 uint8_t pcr; /* Peripheral control register */
107 uint8_t ifr; /* Interrupt flag register */
108 uint8_t ier; /* Interrupt enable register */
109 uint8_t anh; /* A-side data, no handshake */
111 CUDATimer timers[2];
113 uint8_t last_b; /* last value of B register */
114 uint8_t last_acr; /* last value of B register */
116 int data_in_size;
117 int data_in_index;
118 int data_out_index;
120 int irq;
121 openpic_t *openpic;
122 uint8_t autopoll;
123 uint8_t data_in[128];
124 uint8_t data_out[16];
125 QEMUTimer *adb_poll_timer;
126 } CUDAState;
128 static CUDAState cuda_state;
129 ADBBusState adb_bus;
131 static void cuda_update(CUDAState *s);
132 static void cuda_receive_packet_from_host(CUDAState *s,
133 const uint8_t *data, int len);
134 static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
135 int64_t current_time);
137 static void cuda_update_irq(CUDAState *s)
138 {
139 if (s->ifr & s->ier & (SR_INT | T1_INT)) {
140 openpic_set_irq(s->openpic, s->irq, 1);
141 } else {
142 openpic_set_irq(s->openpic, s->irq, 0);
143 }
144 }
146 static unsigned int get_counter(CUDATimer *s)
147 {
148 int64_t d;
149 unsigned int counter;
151 d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
152 CUDA_TIMER_FREQ, ticks_per_sec);
153 if (d <= s->counter_value) {
154 counter = d;
155 } else {
156 counter = s->latch - 1 - ((d - s->counter_value) % s->latch);
157 }
158 return counter;
159 }
161 static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
162 {
163 #ifdef DEBUG_CUDA
164 printf("cuda: T%d.counter=%d\n",
165 1 + (ti->timer == NULL), val);
166 #endif
167 ti->load_time = qemu_get_clock(vm_clock);
168 ti->counter_value = val;
169 cuda_timer_update(s, ti, ti->load_time);
170 }
172 static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
173 {
174 int64_t d, next_time, base;
175 /* current counter value */
176 d = muldiv64(current_time - s->load_time,
177 CUDA_TIMER_FREQ, ticks_per_sec);
178 if (d <= s->counter_value) {
179 next_time = s->counter_value + 1;
180 } else {
181 base = ((d - s->counter_value) / s->latch);
182 base = (base * s->latch) + s->counter_value;
183 next_time = base + s->latch;
184 }
185 #ifdef DEBUG_CUDA
186 printf("latch=%d counter=%lld delta_next=%lld\n",
187 s->latch, d, next_time - d);
188 #endif
189 next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
190 s->load_time;
191 if (next_time <= current_time)
192 next_time = current_time + 1;
193 return next_time;
194 }
196 static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
197 int64_t current_time)
198 {
199 if (!ti->timer)
200 return;
201 if ((s->acr & T1MODE) != T1MODE_CONT) {
202 qemu_del_timer(ti->timer);
203 } else {
204 ti->next_irq_time = get_next_irq_time(ti, current_time);
205 qemu_mod_timer(ti->timer, ti->next_irq_time);
206 }
207 }
209 static void cuda_timer1(void *opaque)
210 {
211 CUDAState *s = opaque;
212 CUDATimer *ti = &s->timers[0];
214 cuda_timer_update(s, ti, ti->next_irq_time);
215 s->ifr |= T1_INT;
216 cuda_update_irq(s);
217 }
219 static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
220 {
221 CUDAState *s = opaque;
222 uint32_t val;
224 addr = (addr >> 9) & 0xf;
225 switch(addr) {
226 case 0:
227 val = s->b;
228 break;
229 case 1:
230 val = s->a;
231 break;
232 case 2:
233 val = s->dirb;
234 break;
235 case 3:
236 val = s->dira;
237 break;
238 case 4:
239 val = get_counter(&s->timers[0]) & 0xff;
240 s->ifr &= ~T1_INT;
241 cuda_update_irq(s);
242 break;
243 case 5:
244 val = get_counter(&s->timers[0]) >> 8;
245 s->ifr &= ~T1_INT;
246 cuda_update_irq(s);
247 break;
248 case 6:
249 val = s->timers[0].latch & 0xff;
250 break;
251 case 7:
252 val = (s->timers[0].latch >> 8) & 0xff;
253 break;
254 case 8:
255 val = get_counter(&s->timers[1]) & 0xff;
256 break;
257 case 9:
258 val = get_counter(&s->timers[1]) >> 8;
259 break;
260 case 10:
261 val = s->sr;
262 s->ifr &= ~SR_INT;
263 cuda_update_irq(s);
264 break;
265 case 11:
266 val = s->acr;
267 break;
268 case 12:
269 val = s->pcr;
270 break;
271 case 13:
272 val = s->ifr;
273 break;
274 case 14:
275 val = s->ier;
276 break;
277 default:
278 case 15:
279 val = s->anh;
280 break;
281 }
282 #ifdef DEBUG_CUDA
283 if (addr != 13 || val != 0)
284 printf("cuda: read: reg=0x%x val=%02x\n", addr, val);
285 #endif
286 return val;
287 }
289 static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
290 {
291 CUDAState *s = opaque;
293 addr = (addr >> 9) & 0xf;
294 #ifdef DEBUG_CUDA
295 printf("cuda: write: reg=0x%x val=%02x\n", addr, val);
296 #endif
298 switch(addr) {
299 case 0:
300 s->b = val;
301 cuda_update(s);
302 break;
303 case 1:
304 s->a = val;
305 break;
306 case 2:
307 s->dirb = val;
308 break;
309 case 3:
310 s->dira = val;
311 break;
312 case 4:
313 val = val | (get_counter(&s->timers[0]) & 0xff00);
314 set_counter(s, &s->timers[0], val);
315 break;
316 case 5:
317 val = (val << 8) | (get_counter(&s->timers[0]) & 0xff);
318 set_counter(s, &s->timers[0], val);
319 break;
320 case 6:
321 s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
322 cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
323 break;
324 case 7:
325 s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
326 cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
327 break;
328 case 8:
329 val = val | (get_counter(&s->timers[1]) & 0xff00);
330 set_counter(s, &s->timers[1], val);
331 break;
332 case 9:
333 val = (val << 8) | (get_counter(&s->timers[1]) & 0xff);
334 set_counter(s, &s->timers[1], val);
335 break;
336 case 10:
337 s->sr = val;
338 break;
339 case 11:
340 s->acr = val;
341 cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
342 cuda_update(s);
343 break;
344 case 12:
345 s->pcr = val;
346 break;
347 case 13:
348 /* reset bits */
349 s->ifr &= ~val;
350 cuda_update_irq(s);
351 break;
352 case 14:
353 if (val & IER_SET) {
354 /* set bits */
355 s->ier |= val & 0x7f;
356 } else {
357 /* reset bits */
358 s->ier &= ~val;
359 }
360 cuda_update_irq(s);
361 break;
362 default:
363 case 15:
364 s->anh = val;
365 break;
366 }
367 }
369 /* NOTE: TIP and TREQ are negated */
370 static void cuda_update(CUDAState *s)
371 {
372 int packet_received, len;
374 packet_received = 0;
375 if (!(s->b & TIP)) {
376 /* transfer requested from host */
378 if (s->acr & SR_OUT) {
379 /* data output */
380 if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
381 if (s->data_out_index < sizeof(s->data_out)) {
382 #ifdef DEBUG_CUDA
383 printf("cuda: send: %02x\n", s->sr);
384 #endif
385 s->data_out[s->data_out_index++] = s->sr;
386 s->ifr |= SR_INT;
387 cuda_update_irq(s);
388 }
389 }
390 } else {
391 if (s->data_in_index < s->data_in_size) {
392 /* data input */
393 if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
394 s->sr = s->data_in[s->data_in_index++];
395 #ifdef DEBUG_CUDA
396 printf("cuda: recv: %02x\n", s->sr);
397 #endif
398 /* indicate end of transfer */
399 if (s->data_in_index >= s->data_in_size) {
400 s->b = (s->b | TREQ);
401 }
402 s->ifr |= SR_INT;
403 cuda_update_irq(s);
404 }
405 }
406 }
407 } else {
408 /* no transfer requested: handle sync case */
409 if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
410 /* update TREQ state each time TACK change state */
411 if (s->b & TACK)
412 s->b = (s->b | TREQ);
413 else
414 s->b = (s->b & ~TREQ);
415 s->ifr |= SR_INT;
416 cuda_update_irq(s);
417 } else {
418 if (!(s->last_b & TIP)) {
419 /* handle end of host to cuda transfert */
420 packet_received = (s->data_out_index > 0);
421 /* always an IRQ at the end of transfert */
422 s->ifr |= SR_INT;
423 cuda_update_irq(s);
424 }
425 /* signal if there is data to read */
426 if (s->data_in_index < s->data_in_size) {
427 s->b = (s->b & ~TREQ);
428 }
429 }
430 }
432 s->last_acr = s->acr;
433 s->last_b = s->b;
435 /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
436 recursively */
437 if (packet_received) {
438 len = s->data_out_index;
439 s->data_out_index = 0;
440 cuda_receive_packet_from_host(s, s->data_out, len);
441 }
442 }
444 static void cuda_send_packet_to_host(CUDAState *s,
445 const uint8_t *data, int len)
446 {
447 #ifdef DEBUG_CUDA_PACKET
448 {
449 int i;
450 printf("cuda_send_packet_to_host:\n");
451 for(i = 0; i < len; i++)
452 printf(" %02x", data[i]);
453 printf("\n");
454 }
455 #endif
456 memcpy(s->data_in, data, len);
457 s->data_in_size = len;
458 s->data_in_index = 0;
459 cuda_update(s);
460 s->ifr |= SR_INT;
461 cuda_update_irq(s);
462 }
464 static void cuda_adb_poll(void *opaque)
465 {
466 CUDAState *s = opaque;
467 uint8_t obuf[ADB_MAX_OUT_LEN + 2];
468 int olen;
470 olen = adb_poll(&adb_bus, obuf + 2);
471 if (olen > 0) {
472 obuf[0] = ADB_PACKET;
473 obuf[1] = 0x40; /* polled data */
474 cuda_send_packet_to_host(s, obuf, olen + 2);
475 }
476 qemu_mod_timer(s->adb_poll_timer,
477 qemu_get_clock(vm_clock) +
478 (ticks_per_sec / CUDA_ADB_POLL_FREQ));
479 }
481 static void cuda_receive_packet(CUDAState *s,
482 const uint8_t *data, int len)
483 {
484 uint8_t obuf[16];
485 int ti, autopoll;
487 switch(data[0]) {
488 case CUDA_AUTOPOLL:
489 autopoll = (data[1] != 0);
490 if (autopoll != s->autopoll) {
491 s->autopoll = autopoll;
492 if (autopoll) {
493 qemu_mod_timer(s->adb_poll_timer,
494 qemu_get_clock(vm_clock) +
495 (ticks_per_sec / CUDA_ADB_POLL_FREQ));
496 } else {
497 qemu_del_timer(s->adb_poll_timer);
498 }
499 }
500 obuf[0] = CUDA_PACKET;
501 obuf[1] = data[1];
502 cuda_send_packet_to_host(s, obuf, 2);
503 break;
504 case CUDA_GET_TIME:
505 /* XXX: add time support ? */
506 ti = time(NULL);
507 obuf[0] = CUDA_PACKET;
508 obuf[1] = 0;
509 obuf[2] = 0;
510 obuf[3] = ti >> 24;
511 obuf[4] = ti >> 16;
512 obuf[5] = ti >> 8;
513 obuf[6] = ti;
514 cuda_send_packet_to_host(s, obuf, 7);
515 break;
516 case CUDA_SET_TIME:
517 case CUDA_FILE_SERVER_FLAG:
518 case CUDA_SET_DEVICE_LIST:
519 case CUDA_SET_AUTO_RATE:
520 case CUDA_SET_POWER_MESSAGES:
521 obuf[0] = CUDA_PACKET;
522 obuf[1] = 0;
523 cuda_send_packet_to_host(s, obuf, 2);
524 break;
525 default:
526 break;
527 }
528 }
530 static void cuda_receive_packet_from_host(CUDAState *s,
531 const uint8_t *data, int len)
532 {
533 #ifdef DEBUG_CUDA_PACKET
534 {
535 int i;
536 printf("cuda_receive_packet_to_host:\n");
537 for(i = 0; i < len; i++)
538 printf(" %02x", data[i]);
539 printf("\n");
540 }
541 #endif
542 switch(data[0]) {
543 case ADB_PACKET:
544 {
545 uint8_t obuf[ADB_MAX_OUT_LEN + 2];
546 int olen;
547 olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1);
548 if (olen > 0) {
549 obuf[0] = ADB_PACKET;
550 obuf[1] = 0x00;
551 } else {
552 /* error */
553 obuf[0] = ADB_PACKET;
554 obuf[1] = -olen;
555 olen = 0;
556 }
557 cuda_send_packet_to_host(s, obuf, olen + 2);
558 }
559 break;
560 case CUDA_PACKET:
561 cuda_receive_packet(s, data + 1, len - 1);
562 break;
563 }
564 }
566 static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
567 {
568 }
570 static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
571 {
572 }
574 static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr)
575 {
576 return 0;
577 }
579 static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
580 {
581 return 0;
582 }
584 static CPUWriteMemoryFunc *cuda_write[] = {
585 &cuda_writeb,
586 &cuda_writew,
587 &cuda_writel,
588 };
590 static CPUReadMemoryFunc *cuda_read[] = {
591 &cuda_readb,
592 &cuda_readw,
593 &cuda_readl,
594 };
596 int cuda_init(openpic_t *openpic, int irq)
597 {
598 CUDAState *s = &cuda_state;
599 int cuda_mem_index;
601 s->openpic = openpic;
602 s->irq = irq;
604 s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
605 s->timers[0].latch = 0x10000;
606 set_counter(s, &s->timers[0], 0xffff);
607 s->timers[1].latch = 0x10000;
608 s->ier = T1_INT | SR_INT;
609 set_counter(s, &s->timers[1], 0xffff);
611 s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);
612 cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s);
613 return cuda_mem_index;
614 }