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