From 72f1f97d4927f798167855fda7881b0e22756b20 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 11 Nov 2015 22:49:41 +0000 Subject: PPC: mac99: Always add USB controller The mac99 machines always have a USB controller. Usually not having one around doesn't hurt quite as much, but Mac OS 9 really really wants one or it crashes on bootup. So always add OHCI to make it happy. Signed-off-by: Alexander Graf Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/mac_newworld.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 66d016c6fa..1b9a573cae 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -371,12 +371,13 @@ static void ppc_core99_init(MachineState *machine) /* 970 gets a U3 bus */ pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io()); machine_arch = ARCH_MAC99_U3; - machine->usb |= defaults_enabled() && !machine->usb_disabled; } else { pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io()); machine_arch = ARCH_MAC99; } + machine->usb |= defaults_enabled() && !machine->usb_disabled; + /* Timebase Frequency */ if (kvm_enabled()) { tbfreq = kvmppc_get_tbfreq(); -- cgit v1.2.3 From 6729aa40135bc96d69b5bf5e65a7d463ef7793e7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:42 +0000 Subject: cuda.c: fix CUDA ADB error packet format According to MOL, ADB error packets should be of the form (type, status, cmd) rather than just (type, status). This fixes ADB device detection under MacOS 9. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 0fd75b376f..bfcdcae549 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -560,19 +560,21 @@ static void cuda_receive_packet_from_host(CUDAState *s, switch(data[0]) { case ADB_PACKET: { - uint8_t obuf[ADB_MAX_OUT_LEN + 2]; + uint8_t obuf[ADB_MAX_OUT_LEN + 3]; int olen; olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1); if (olen > 0) { obuf[0] = ADB_PACKET; obuf[1] = 0x00; + cuda_send_packet_to_host(s, obuf, olen + 2); } else { /* error */ obuf[0] = ADB_PACKET; obuf[1] = -olen; + obuf[2] = data[1]; olen = 0; + cuda_send_packet_to_host(s, obuf, olen + 3); } - cuda_send_packet_to_host(s, obuf, olen + 2); } break; case CUDA_PACKET: -- cgit v1.2.3 From 4202e63c0432c72ba518dd882e99a794620d1665 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:43 +0000 Subject: cuda.c: fix CUDA_PACKET response packet format According to comments in MOL, the response to a CUDA_PACKET should be one of the following: Reply: (CUDA_PACKET, status, cmd) Error: (ERROR_PACKET, status, CUDA_PACKET, cmd) Update cuda_receive_packet() accordingly to reflect this in order to make MacOS 9 happy. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index bfcdcae549..89ec51eebf 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -480,7 +480,7 @@ static void cuda_adb_poll(void *opaque) static void cuda_receive_packet(CUDAState *s, const uint8_t *data, int len) { - uint8_t obuf[16]; + uint8_t obuf[16] = { CUDA_PACKET, 0, data[0] }; int autopoll; uint32_t ti; @@ -497,23 +497,15 @@ static void cuda_receive_packet(CUDAState *s, timer_del(s->adb_poll_timer); } } - obuf[0] = CUDA_PACKET; - obuf[1] = data[1]; - cuda_send_packet_to_host(s, obuf, 2); + cuda_send_packet_to_host(s, obuf, 3); break; case CUDA_SET_TIME: ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4]; s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec()); - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - obuf[2] = 0; cuda_send_packet_to_host(s, obuf, 3); break; case CUDA_GET_TIME: ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec()); - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - obuf[2] = 0; obuf[3] = ti >> 24; obuf[4] = ti >> 16; obuf[5] = ti >> 8; @@ -524,20 +516,14 @@ static void cuda_receive_packet(CUDAState *s, case CUDA_SET_DEVICE_LIST: case CUDA_SET_AUTO_RATE: case CUDA_SET_POWER_MESSAGES: - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - cuda_send_packet_to_host(s, obuf, 2); + cuda_send_packet_to_host(s, obuf, 3); break; case CUDA_POWERDOWN: - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - cuda_send_packet_to_host(s, obuf, 2); + cuda_send_packet_to_host(s, obuf, 3); qemu_system_shutdown_request(); break; case CUDA_RESET_SYSTEM: - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - cuda_send_packet_to_host(s, obuf, 2); + cuda_send_packet_to_host(s, obuf, 3); qemu_system_reset_request(); break; default: -- cgit v1.2.3 From f1f46f74a9de7298977a3ed668e71843fa904c38 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:44 +0000 Subject: cuda.c: implement simple CUDA_GET_6805_ADDR command This simply returns an empty response with no error status as implemented by MOL to allow MacOS 9 boot to proceed further. Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 89ec51eebf..1a2ab01c0a 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -499,6 +499,9 @@ static void cuda_receive_packet(CUDAState *s, } cuda_send_packet_to_host(s, obuf, 3); break; + case CUDA_GET_6805_ADDR: + cuda_send_packet_to_host(s, obuf, 3); + break; case CUDA_SET_TIME: ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4]; s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec()); -- cgit v1.2.3 From ce8d3b647b5acc2bec19602d9fac87d3da11ae77 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:45 +0000 Subject: cuda.c: implement dummy IIC access commands These are used by MacOS 9 on boot. Here we return an error except for 4-byte commands which write to the IIC bus in a similar manner to MOL. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 1a2ab01c0a..b7e9deeb15 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -529,6 +529,24 @@ static void cuda_receive_packet(CUDAState *s, cuda_send_packet_to_host(s, obuf, 3); qemu_system_reset_request(); break; + case CUDA_COMBINED_FORMAT_IIC: + obuf[0] = ERROR_PACKET; + obuf[1] = 0x5; + obuf[2] = CUDA_PACKET; + obuf[3] = data[0]; + cuda_send_packet_to_host(s, obuf, 4); + break; + case CUDA_GET_SET_IIC: + if (len == 4) { + cuda_send_packet_to_host(s, obuf, 3); + } else { + obuf[0] = ERROR_PACKET; + obuf[1] = 0x2; + obuf[2] = CUDA_PACKET; + obuf[3] = data[0]; + cuda_send_packet_to_host(s, obuf, 4); + } + break; default: break; } -- cgit v1.2.3 From d271ae36dc1e292ae140f5bbf23e0fc1392dd325 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:46 +0000 Subject: cuda.c: fix CUDA SR interrupt clearing Make sure that we also clear the data and clock interrupts at the same time. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index b7e9deeb15..364473fee2 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -57,6 +57,8 @@ #define IER_SET 0x80 /* set bits in IER */ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ +#define SR_DATA_INT 0x08 +#define SR_CLOCK_INT 0x10 #define T1_INT 0x40 /* Timer 1 interrupt */ #define T2_INT 0x20 /* Timer 2 interrupt */ @@ -261,7 +263,7 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) break; case 10: val = s->sr; - s->ifr &= ~SR_INT; + s->ifr &= ~(SR_INT | SR_CLOCK_INT | SR_DATA_INT); cuda_update_irq(s); break; case 11: -- cgit v1.2.3 From b5ac04103bc3b24042418df1a561096187165fd7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:47 +0000 Subject: cuda.c: add defines for CUDA registers Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 87 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 34 deletions(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 364473fee2..c0a3a68025 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -110,6 +110,24 @@ /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ #define RTC_OFFSET 2082844800 +/* CUDA registers */ +#define CUDA_REG_B 0x00 +#define CUDA_REG_A 0x01 +#define CUDA_REG_DIRB 0x02 +#define CUDA_REG_DIRA 0x03 +#define CUDA_REG_T1CL 0x04 +#define CUDA_REG_T1CH 0x05 +#define CUDA_REG_T1LL 0x06 +#define CUDA_REG_T1LH 0x07 +#define CUDA_REG_T2CL 0x08 +#define CUDA_REG_T2CH 0x09 +#define CUDA_REG_SR 0x0a +#define CUDA_REG_ACR 0x0b +#define CUDA_REG_PCR 0x0c +#define CUDA_REG_IFR 0x0d +#define CUDA_REG_IER 0x0e +#define CUDA_REG_ANH 0x0f + static void cuda_update(CUDAState *s); static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len); @@ -226,66 +244,67 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) addr = (addr >> 9) & 0xf; switch(addr) { - case 0: + case CUDA_REG_B: val = s->b; break; - case 1: + case CUDA_REG_A: val = s->a; break; - case 2: + case CUDA_REG_DIRB: val = s->dirb; break; - case 3: + case CUDA_REG_DIRA: val = s->dira; break; - case 4: + case CUDA_REG_T1CL: val = get_counter(&s->timers[0]) & 0xff; s->ifr &= ~T1_INT; cuda_update_irq(s); break; - case 5: + case CUDA_REG_T1CH: val = get_counter(&s->timers[0]) >> 8; cuda_update_irq(s); break; - case 6: + case CUDA_REG_T1LL: val = s->timers[0].latch & 0xff; break; - case 7: + case CUDA_REG_T1LH: /* XXX: check this */ val = (s->timers[0].latch >> 8) & 0xff; break; - case 8: + case CUDA_REG_T2CL: val = get_counter(&s->timers[1]) & 0xff; s->ifr &= ~T2_INT; break; - case 9: + case CUDA_REG_T2CH: val = get_counter(&s->timers[1]) >> 8; break; - case 10: + case CUDA_REG_SR: val = s->sr; s->ifr &= ~(SR_INT | SR_CLOCK_INT | SR_DATA_INT); cuda_update_irq(s); break; - case 11: + case CUDA_REG_ACR: val = s->acr; break; - case 12: + case CUDA_REG_PCR: val = s->pcr; break; - case 13: + case CUDA_REG_IFR: val = s->ifr; - if (s->ifr & s->ier) + if (s->ifr & s->ier) { val |= 0x80; + } break; - case 14: + case CUDA_REG_IER: val = s->ier | 0x80; break; default: - case 15: + case CUDA_REG_ANH: val = s->anh; break; } - if (addr != 13 || val != 0) { + if (addr != CUDA_REG_IFR || val != 0) { CUDA_DPRINTF("read: reg=0x%x val=%02x\n", (int)addr, val); } @@ -300,61 +319,61 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) CUDA_DPRINTF("write: reg=0x%x val=%02x\n", (int)addr, val); switch(addr) { - case 0: + case CUDA_REG_B: s->b = val; cuda_update(s); break; - case 1: + case CUDA_REG_A: s->a = val; break; - case 2: + case CUDA_REG_DIRB: s->dirb = val; break; - case 3: + case CUDA_REG_DIRA: s->dira = val; break; - case 4: + case CUDA_REG_T1CL: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; - case 5: + case CUDA_REG_T1CH: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); s->ifr &= ~T1_INT; set_counter(s, &s->timers[0], s->timers[0].latch); break; - case 6: + case CUDA_REG_T1LL: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; - case 7: + case CUDA_REG_T1LH: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); s->ifr &= ~T1_INT; cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; - case 8: + case CUDA_REG_T2CL: s->timers[1].latch = val; set_counter(s, &s->timers[1], val); break; - case 9: + case CUDA_REG_T2CH: set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); break; - case 10: + case CUDA_REG_SR: s->sr = val; break; - case 11: + case CUDA_REG_ACR: s->acr = val; cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); cuda_update(s); break; - case 12: + case CUDA_REG_PCR: s->pcr = val; break; - case 13: + case CUDA_REG_IFR: /* reset bits */ s->ifr &= ~val; cuda_update_irq(s); break; - case 14: + case CUDA_REG_IER: if (val & IER_SET) { /* set bits */ s->ier |= val & 0x7f; @@ -365,7 +384,7 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) cuda_update_irq(s); break; default: - case 15: + case CUDA_REG_ANH: s->anh = val; break; } -- cgit v1.2.3 From eda14abbb804f8ed2cb903c99ad1852848fa2e42 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:48 +0000 Subject: cuda.c: refactor get_tb() so that the time can be passed in This is in preparation for sharing the code between timers. Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index c0a3a68025..e61a3c5967 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -143,10 +143,9 @@ static void cuda_update_irq(CUDAState *s) } } -static uint64_t get_tb(uint64_t freq) +static uint64_t get_tb(uint64_t time, uint64_t freq) { - return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), - freq, get_ticks_per_sec()); + return muldiv64(time, freq, get_ticks_per_sec()); } static unsigned int get_counter(CUDATimer *s) @@ -154,9 +153,10 @@ static unsigned int get_counter(CUDATimer *s) int64_t d; unsigned int counter; uint64_t tb_diff; + uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup. */ - tb_diff = get_tb(s->frequency) - s->load_time; + tb_diff = get_tb(current_time, s->frequency) - s->load_time; d = (tb_diff * 0xBF401675E5DULL) / (s->frequency << 24); if (s->index == 0) { @@ -176,7 +176,8 @@ static unsigned int get_counter(CUDATimer *s) static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val); - ti->load_time = get_tb(s->frequency); + ti->load_time = get_tb(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + s->frequency); ti->counter_value = val; cuda_timer_update(s, ti, ti->load_time); } -- cgit v1.2.3 From 0174adb611a22bcfeeb123851cf4874e6d922d06 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:49 +0000 Subject: cuda.c: rename get_counter() state variable from s to ti for consistency Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index e61a3c5967..b6da434ee3 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -148,7 +148,7 @@ static uint64_t get_tb(uint64_t time, uint64_t freq) return muldiv64(time, freq, get_ticks_per_sec()); } -static unsigned int get_counter(CUDATimer *s) +static unsigned int get_counter(CUDATimer *ti) { int64_t d; unsigned int counter; @@ -156,19 +156,19 @@ static unsigned int get_counter(CUDATimer *s) uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup. */ - tb_diff = get_tb(current_time, s->frequency) - s->load_time; - d = (tb_diff * 0xBF401675E5DULL) / (s->frequency << 24); + tb_diff = get_tb(current_time, ti->frequency) - ti->load_time; + d = (tb_diff * 0xBF401675E5DULL) / (ti->frequency << 24); - if (s->index == 0) { + if (ti->index == 0) { /* the timer goes down from latch to -1 (period of latch + 2) */ - if (d <= (s->counter_value + 1)) { - counter = (s->counter_value - d) & 0xffff; + if (d <= (ti->counter_value + 1)) { + counter = (ti->counter_value - d) & 0xffff; } else { - counter = (d - (s->counter_value + 1)) % (s->latch + 2); - counter = (s->latch - counter) & 0xffff; + counter = (d - (ti->counter_value + 1)) % (ti->latch + 2); + counter = (ti->latch - counter) & 0xffff; } } else { - counter = (s->counter_value - d) & 0xffff; + counter = (ti->counter_value - d) & 0xffff; } return counter; } -- cgit v1.2.3 From a53cfdcca2834ec7e61fd955c4f24ac233c4ec16 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:50 +0000 Subject: cuda.c: fix T2 timer and enable its interrupt Fix the counter loading logic and enable the T2 interrupt when the timer expires. Otherwise MacOS 9 hangs on boot. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index b6da434ee3..9045c3b9f4 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -136,7 +136,7 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti, static void cuda_update_irq(CUDAState *s) { - if (s->ifr & s->ier & (SR_INT | T1_INT)) { + if (s->ifr & s->ier & (SR_INT | T1_INT | T2_INT)) { qemu_irq_raise(s->irq); } else { qemu_irq_lower(s->irq); @@ -175,7 +175,7 @@ static unsigned int get_counter(CUDATimer *ti) static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { - CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val); + CUDA_DPRINTF("T%d.counter=%d\n", 1 + ti->index, val); ti->load_time = get_tb(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), s->frequency); ti->counter_value = val; @@ -220,7 +220,7 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti, { if (!ti->timer) return; - if ((s->acr & T1MODE) != T1MODE_CONT) { + if (ti->index == 0 && (s->acr & T1MODE) != T1MODE_CONT) { timer_del(ti->timer); } else { ti->next_irq_time = get_next_irq_time(ti, current_time); @@ -238,6 +238,16 @@ static void cuda_timer1(void *opaque) cuda_update_irq(s); } +static void cuda_timer2(void *opaque) +{ + CUDAState *s = opaque; + CUDATimer *ti = &s->timers[1]; + + cuda_timer_update(s, ti, ti->next_irq_time); + s->ifr |= T2_INT; + cuda_update_irq(s); +} + static uint32_t cuda_readb(void *opaque, hwaddr addr) { CUDAState *s = opaque; @@ -276,6 +286,7 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) case CUDA_REG_T2CL: val = get_counter(&s->timers[1]) & 0xff; s->ifr &= ~T2_INT; + cuda_update_irq(s); break; case CUDA_REG_T2CH: val = get_counter(&s->timers[1]) >> 8; @@ -352,11 +363,15 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; case CUDA_REG_T2CL: - s->timers[1].latch = val; - set_counter(s, &s->timers[1], val); + s->timers[1].latch = (s->timers[1].latch & 0xff00) | val; break; case CUDA_REG_T2CH: - set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); + /* To ensure T2 generates an interrupt on zero crossing with the + common timer code, write the value directly from the latch to + the counter */ + s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8); + s->ifr &= ~T2_INT; + set_counter(s, &s->timers[1], s->timers[1].latch); break; case CUDA_REG_SR: s->sr = val; @@ -719,8 +734,7 @@ static void cuda_reset(DeviceState *dev) s->timers[0].latch = 0xffff; set_counter(s, &s->timers[0], 0xffff); - s->timers[1].latch = 0; - set_counter(s, &s->timers[1], 0xffff); + s->timers[1].latch = 0xffff; } static void cuda_realizefn(DeviceState *dev, Error **errp) @@ -730,7 +744,8 @@ static void cuda_realizefn(DeviceState *dev, Error **errp) s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s); s->timers[0].frequency = s->frequency; - s->timers[1].frequency = s->frequency; + s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer2, s); + s->timers[1].frequency = (SCALE_US * 6000) / 4700; qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; -- cgit v1.2.3 From cffc331a3156870d54883bc79e4278472ffd8f1d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:51 +0000 Subject: cuda.c: add delay to setting of SR_INT bit MacOS 9 is racy when it comes to accessing the shift register. Fix this by introducing a small delay between data accesses and raising the SR_INT interrupt bit. Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 44 +++++++++++++++++++++++++++++++++----------- hw/ppc/mac.h | 3 +++ 2 files changed, 36 insertions(+), 11 deletions(-) (limited to 'hw') diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 9045c3b9f4..9db4c64150 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -248,6 +248,31 @@ static void cuda_timer2(void *opaque) cuda_update_irq(s); } +static void cuda_set_sr_int(void *opaque) +{ + CUDAState *s = opaque; + + CUDA_DPRINTF("CUDA: %s:%d\n", __func__, __LINE__); + s->ifr |= SR_INT; + cuda_update_irq(s); +} + +static void cuda_delay_set_sr_int(CUDAState *s) +{ + int64_t expire; + + if (s->dirb == 0xff) { + /* Not in Mac OS, fire the IRQ directly */ + cuda_set_sr_int(s); + return; + } + + CUDA_DPRINTF("CUDA: %s:%d\n", __func__, __LINE__); + + expire = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 300 * SCALE_US; + timer_mod(s->sr_delay_timer, expire); +} + static uint32_t cuda_readb(void *opaque, hwaddr addr) { CUDAState *s = opaque; @@ -421,8 +446,7 @@ static void cuda_update(CUDAState *s) if (s->data_out_index < sizeof(s->data_out)) { CUDA_DPRINTF("send: %02x\n", s->sr); s->data_out[s->data_out_index++] = s->sr; - s->ifr |= SR_INT; - cuda_update_irq(s); + cuda_delay_set_sr_int(s); } } } else { @@ -435,8 +459,7 @@ static void cuda_update(CUDAState *s) if (s->data_in_index >= s->data_in_size) { s->b = (s->b | TREQ); } - s->ifr |= SR_INT; - cuda_update_irq(s); + cuda_delay_set_sr_int(s); } } } @@ -448,15 +471,13 @@ static void cuda_update(CUDAState *s) s->b = (s->b | TREQ); else s->b = (s->b & ~TREQ); - s->ifr |= SR_INT; - cuda_update_irq(s); + cuda_delay_set_sr_int(s); } else { if (!(s->last_b & TIP)) { /* handle end of host to cuda transfer */ packet_received = (s->data_out_index > 0); /* always an IRQ at the end of transfer */ - s->ifr |= SR_INT; - cuda_update_irq(s); + cuda_delay_set_sr_int(s); } /* signal if there is data to read */ if (s->data_in_index < s->data_in_size) { @@ -493,8 +514,7 @@ static void cuda_send_packet_to_host(CUDAState *s, s->data_in_size = len; s->data_in_index = 0; cuda_update(s); - s->ifr |= SR_INT; - cuda_update_irq(s); + cuda_delay_set_sr_int(s); } static void cuda_adb_poll(void *opaque) @@ -717,7 +737,7 @@ static void cuda_reset(DeviceState *dev) s->b = 0; s->a = 0; - s->dirb = 0; + s->dirb = 0xff; s->dira = 0; s->sr = 0; s->acr = 0; @@ -735,6 +755,8 @@ static void cuda_reset(DeviceState *dev) set_counter(s, &s->timers[0], 0xffff); s->timers[1].latch = 0xffff; + + s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s); } static void cuda_realizefn(DeviceState *dev, Error **errp) diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 8bdba30c1e..e375ed2b2b 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -103,6 +103,9 @@ typedef struct CUDAState { uint8_t last_b; uint8_t last_acr; + /* MacOS 9 is racy and requires a delay upon setting the SR_INT bit */ + QEMUTimer *sr_delay_timer; + int data_in_size; int data_in_index; int data_out_index; -- cgit v1.2.3