Revision f8f48b69
b/hw/usb/hcd-uhci.c | ||
---|---|---|
78 | 78 |
/* Must be large enough to handle 10 frame delay for initial isoc requests */ |
79 | 79 |
#define QH_VALID 32 |
80 | 80 |
|
81 |
#define MAX_FRAMES_PER_TICK (QH_VALID / 2) |
|
82 |
|
|
81 | 83 |
#define NB_PORTS 2 |
82 | 84 |
|
83 | 85 |
enum { |
... | ... | |
500 | 502 |
trace_usb_uhci_schedule_start(); |
501 | 503 |
s->expire_time = qemu_get_clock_ns(vm_clock) + |
502 | 504 |
(get_ticks_per_sec() / FRAME_TIMER_FREQ); |
503 |
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
|
|
505 |
qemu_mod_timer(s->frame_timer, s->expire_time);
|
|
504 | 506 |
s->status &= ~UHCI_STS_HCHALTED; |
505 | 507 |
} else if (!(val & UHCI_CMD_RS)) { |
506 | 508 |
s->status |= UHCI_STS_HCHALTED; |
... | ... | |
1176 | 1178 |
static void uhci_frame_timer(void *opaque) |
1177 | 1179 |
{ |
1178 | 1180 |
UHCIState *s = opaque; |
1181 |
uint64_t t_now, t_last_run; |
|
1182 |
int i, frames; |
|
1183 |
const uint64_t frame_t = get_ticks_per_sec() / FRAME_TIMER_FREQ; |
|
1179 | 1184 |
|
1180 |
/* prepare the timer for the next frame */ |
|
1181 |
s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); |
|
1182 |
s->frame_bytes = 0; |
|
1183 | 1185 |
s->completions_only = false; |
1184 | 1186 |
qemu_bh_cancel(s->bh); |
1185 | 1187 |
|
... | ... | |
1193 | 1195 |
return; |
1194 | 1196 |
} |
1195 | 1197 |
|
1196 |
/* Process the current frame */ |
|
1197 |
trace_usb_uhci_frame_start(s->frnum); |
|
1198 |
|
|
1199 |
uhci_async_validate_begin(s); |
|
1200 |
|
|
1201 |
uhci_process_frame(s); |
|
1198 |
/* We still store expire_time in our state, for migration */ |
|
1199 |
t_last_run = s->expire_time - frame_t; |
|
1200 |
t_now = qemu_get_clock_ns(vm_clock); |
|
1202 | 1201 |
|
1203 |
uhci_async_validate_end(s); |
|
1202 |
/* Process up to MAX_FRAMES_PER_TICK frames */ |
|
1203 |
frames = (t_now - t_last_run) / frame_t; |
|
1204 |
if (frames > MAX_FRAMES_PER_TICK) { |
|
1205 |
frames = MAX_FRAMES_PER_TICK; |
|
1206 |
} |
|
1204 | 1207 |
|
1205 |
/* The uhci spec says frnum reflects the frame currently being processed, |
|
1206 |
* and the guest must look at frnum - 1 on interrupt, so inc frnum now */ |
|
1207 |
s->frnum = (s->frnum + 1) & 0x7ff; |
|
1208 |
for (i = 0; i < frames; i++) { |
|
1209 |
s->frame_bytes = 0; |
|
1210 |
trace_usb_uhci_frame_start(s->frnum); |
|
1211 |
uhci_async_validate_begin(s); |
|
1212 |
uhci_process_frame(s); |
|
1213 |
uhci_async_validate_end(s); |
|
1214 |
/* The spec says frnum is the frame currently being processed, and |
|
1215 |
* the guest must look at frnum - 1 on interrupt, so inc frnum now */ |
|
1216 |
s->frnum = (s->frnum + 1) & 0x7ff; |
|
1217 |
s->expire_time += frame_t; |
|
1218 |
} |
|
1208 | 1219 |
|
1209 |
/* Complete the previous frame */ |
|
1220 |
/* Complete the previous frame(s) */
|
|
1210 | 1221 |
if (s->pending_int_mask) { |
1211 | 1222 |
s->status2 |= s->pending_int_mask; |
1212 | 1223 |
s->status |= UHCI_STS_USBINT; |
... | ... | |
1214 | 1225 |
} |
1215 | 1226 |
s->pending_int_mask = 0; |
1216 | 1227 |
|
1217 |
qemu_mod_timer(s->frame_timer, s->expire_time);
|
|
1228 |
qemu_mod_timer(s->frame_timer, t_now + frame_t);
|
|
1218 | 1229 |
} |
1219 | 1230 |
|
1220 | 1231 |
static const MemoryRegionPortio uhci_portio[] = { |
Also available in: Unified diff