hcd-ehci.c 73.5 KB
Newer Older
G
Gerd Hoffmann 已提交
1 2 3 4
/*
 * QEMU USB EHCI Emulation
 *
 * Copyright(c) 2008  Emutex Ltd. (address@hidden)
5 6 7 8 9
 * Copyright(c) 2011-2012 Red Hat, Inc.
 *
 * Red Hat Authors:
 * Gerd Hoffmann <kraxel@redhat.com>
 * Hans de Goede <hdegoede@redhat.com>
G
Gerd Hoffmann 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 * EHCI project was started by Mark Burkley, with contributions by
 * Niels de Vos.  David S. Ahern continued working on it.  Kevin Wolf,
 * Jan Kiszka and Vincent Palatin contributed bugfixes.
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or(at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

30
#include "hw/usb/hcd-ehci.h"
G
Gerd Hoffmann 已提交
31 32

/* Capability Registers Base Address - section 2.2 */
33 34 35 36
#define CAPLENGTH        0x0000  /* 1-byte, 0x0001 reserved */
#define HCIVERSION       0x0002  /* 2-bytes, i/f version # */
#define HCSPARAMS        0x0004  /* 4-bytes, structural params */
#define HCCPARAMS        0x0008  /* 4-bytes, capability params */
G
Gerd Hoffmann 已提交
37
#define EECP             HCCPARAMS + 1
38 39
#define HCSPPORTROUTE1   0x000c
#define HCSPPORTROUTE2   0x0010
G
Gerd Hoffmann 已提交
40

41
#define USBCMD           0x0000
G
Gerd Hoffmann 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54
#define USBCMD_RUNSTOP   (1 << 0)      // run / Stop
#define USBCMD_HCRESET   (1 << 1)      // HC Reset
#define USBCMD_FLS       (3 << 2)      // Frame List Size
#define USBCMD_FLS_SH    2             // Frame List Size Shift
#define USBCMD_PSE       (1 << 4)      // Periodic Schedule Enable
#define USBCMD_ASE       (1 << 5)      // Asynch Schedule Enable
#define USBCMD_IAAD      (1 << 6)      // Int Asynch Advance Doorbell
#define USBCMD_LHCR      (1 << 7)      // Light Host Controller Reset
#define USBCMD_ASPMC     (3 << 8)      // Async Sched Park Mode Count
#define USBCMD_ASPME     (1 << 11)     // Async Sched Park Mode Enable
#define USBCMD_ITC       (0x7f << 16)  // Int Threshold Control
#define USBCMD_ITC_SH    16            // Int Threshold Control Shift

55
#define USBSTS           0x0004
G
Gerd Hoffmann 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#define USBSTS_RO_MASK   0x0000003f
#define USBSTS_INT       (1 << 0)      // USB Interrupt
#define USBSTS_ERRINT    (1 << 1)      // Error Interrupt
#define USBSTS_PCD       (1 << 2)      // Port Change Detect
#define USBSTS_FLR       (1 << 3)      // Frame List Rollover
#define USBSTS_HSE       (1 << 4)      // Host System Error
#define USBSTS_IAA       (1 << 5)      // Interrupt on Async Advance
#define USBSTS_HALT      (1 << 12)     // HC Halted
#define USBSTS_REC       (1 << 13)     // Reclamation
#define USBSTS_PSS       (1 << 14)     // Periodic Schedule Status
#define USBSTS_ASS       (1 << 15)     // Asynchronous Schedule Status

/*
 *  Interrupt enable bits correspond to the interrupt active bits in USBSTS
 *  so no need to redefine here.
 */
72
#define USBINTR              0x0008
G
Gerd Hoffmann 已提交
73 74
#define USBINTR_MASK         0x0000003f

75 76 77 78
#define FRINDEX              0x000c
#define CTRLDSSEGMENT        0x0010
#define PERIODICLISTBASE     0x0014
#define ASYNCLISTADDR        0x0018
G
Gerd Hoffmann 已提交
79 80
#define ASYNCLISTADDR_MASK   0xffffffe0

81
#define CONFIGFLAG           0x0040
G
Gerd Hoffmann 已提交
82 83

/*
84
 * Bits that are reserved or are read-only are masked out of values
G
Gerd Hoffmann 已提交
85 86
 * written to us by software
 */
87
#define PORTSC_RO_MASK       0x007001c0
G
Gerd Hoffmann 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
#define PORTSC_RWC_MASK      0x0000002a
#define PORTSC_WKOC_E        (1 << 22)    // Wake on Over Current Enable
#define PORTSC_WKDS_E        (1 << 21)    // Wake on Disconnect Enable
#define PORTSC_WKCN_E        (1 << 20)    // Wake on Connect Enable
#define PORTSC_PTC           (15 << 16)   // Port Test Control
#define PORTSC_PTC_SH        16           // Port Test Control shift
#define PORTSC_PIC           (3 << 14)    // Port Indicator Control
#define PORTSC_PIC_SH        14           // Port Indicator Control Shift
#define PORTSC_POWNER        (1 << 13)    // Port Owner
#define PORTSC_PPOWER        (1 << 12)    // Port Power
#define PORTSC_LINESTAT      (3 << 10)    // Port Line Status
#define PORTSC_LINESTAT_SH   10           // Port Line Status Shift
#define PORTSC_PRESET        (1 << 8)     // Port Reset
#define PORTSC_SUSPEND       (1 << 7)     // Port Suspend
#define PORTSC_FPRES         (1 << 6)     // Force Port Resume
#define PORTSC_OCC           (1 << 5)     // Over Current Change
#define PORTSC_OCA           (1 << 4)     // Over Current Active
#define PORTSC_PEDC          (1 << 3)     // Port Enable/Disable Change
#define PORTSC_PED           (1 << 2)     // Port Enable/Disable
#define PORTSC_CSC           (1 << 1)     // Connect Status Change
#define PORTSC_CONNECT       (1 << 0)     // Current Connect Status

#define FRAME_TIMER_FREQ 1000
G
Gerd Hoffmann 已提交
111
#define FRAME_TIMER_NS   (1000000000 / FRAME_TIMER_FREQ)
112
#define UFRAME_TIMER_NS  (FRAME_TIMER_NS / 8)
G
Gerd Hoffmann 已提交
113 114 115 116

#define NB_MAXINTRATE    8        // Max rate at which controller issues ints
#define BUFF_SIZE        5*4096   // Max bytes to transfer per transaction
#define MAX_QH           100      // Max allowable queue heads in a chain
117 118
#define MIN_UFR_PER_TICK 24       /* Min frames to process when catching up */
#define PERIODIC_ACTIVE  512      /* Micro-frames */
G
Gerd Hoffmann 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132

/*  Internal periodic / asynchronous schedule state machine states
 */
typedef enum {
    EST_INACTIVE = 1000,
    EST_ACTIVE,
    EST_EXECUTING,
    EST_SLEEPING,
    /*  The following states are internal to the state machine function
    */
    EST_WAITLISTHEAD,
    EST_FETCHENTRY,
    EST_FETCHQH,
    EST_FETCHITD,
G
Gerd Hoffmann 已提交
133
    EST_FETCHSITD,
G
Gerd Hoffmann 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    EST_ADVANCEQUEUE,
    EST_FETCHQTD,
    EST_EXECUTE,
    EST_WRITEBACK,
    EST_HORIZONTALQH
} EHCI_STATES;

/* macros for accessing fields within next link pointer entry */
#define NLPTR_GET(x)             ((x) & 0xffffffe0)
#define NLPTR_TYPE_GET(x)        (((x) >> 1) & 3)
#define NLPTR_TBIT(x)            ((x) & 1)  // 1=invalid, 0=valid

/* link pointer types */
#define NLPTR_TYPE_ITD           0     // isoc xfer descriptor
#define NLPTR_TYPE_QH            1     // queue head
#define NLPTR_TYPE_STITD         2     // split xaction, isoc xfer descriptor
#define NLPTR_TYPE_FSTN          3     // frame span traversal node

#define SET_LAST_RUN_CLOCK(s) \
G
Gerd Hoffmann 已提交
153
    (s)->last_run_ns = qemu_get_clock_ns(vm_clock);
G
Gerd Hoffmann 已提交
154 155 156 157 158 159 160 161 162 163 164 165

/* nifty macros from Arnon's EHCI version  */
#define get_field(data, field) \
    (((data) & field##_MASK) >> field##_SH)

#define set_field(data, newval, field) do { \
    uint32_t val = *data; \
    val &= ~ field##_MASK; \
    val |= ((newval) << field##_SH) & field##_MASK; \
    *data = val; \
    } while(0)

166
static const char *ehci_state_names[] = {
G
Gerd Hoffmann 已提交
167 168 169 170 171 172 173 174 175 176 177 178 179
    [EST_INACTIVE]     = "INACTIVE",
    [EST_ACTIVE]       = "ACTIVE",
    [EST_EXECUTING]    = "EXECUTING",
    [EST_SLEEPING]     = "SLEEPING",
    [EST_WAITLISTHEAD] = "WAITLISTHEAD",
    [EST_FETCHENTRY]   = "FETCH ENTRY",
    [EST_FETCHQH]      = "FETCH QH",
    [EST_FETCHITD]     = "FETCH ITD",
    [EST_ADVANCEQUEUE] = "ADVANCEQUEUE",
    [EST_FETCHQTD]     = "FETCH QTD",
    [EST_EXECUTE]      = "EXECUTE",
    [EST_WRITEBACK]    = "WRITEBACK",
    [EST_HORIZONTALQH] = "HORIZONTALQH",
180 181 182
};

static const char *ehci_mmio_names[] = {
G
Gerd Hoffmann 已提交
183 184 185 186 187 188 189
    [USBCMD]            = "USBCMD",
    [USBSTS]            = "USBSTS",
    [USBINTR]           = "USBINTR",
    [FRINDEX]           = "FRINDEX",
    [PERIODICLISTBASE]  = "P-LIST BASE",
    [ASYNCLISTADDR]     = "A-LIST ADDR",
    [CONFIGFLAG]        = "CONFIGFLAG",
190
};
G
Gerd Hoffmann 已提交
191

192 193
static int ehci_state_executing(EHCIQueue *q);
static int ehci_state_writeback(EHCIQueue *q);
194
static int ehci_state_advqueue(EHCIQueue *q);
195
static int ehci_fill_queue(EHCIPacket *p);
196
static void ehci_free_packet(EHCIPacket *p);
197

198
static const char *nr2str(const char **n, size_t len, uint32_t nr)
G
Gerd Hoffmann 已提交
199
{
200 201
    if (nr < len && n[nr] != NULL) {
        return n[nr];
G
Gerd Hoffmann 已提交
202
    } else {
203
        return "unknown";
G
Gerd Hoffmann 已提交
204 205 206
    }
}

207 208 209 210 211
static const char *state2str(uint32_t state)
{
    return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
}

A
Avi Kivity 已提交
212
static const char *addr2str(hwaddr addr)
213
{
214
    return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
215 216
}

G
Gerd Hoffmann 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
static void ehci_trace_usbsts(uint32_t mask, int state)
{
    /* interrupts */
    if (mask & USBSTS_INT) {
        trace_usb_ehci_usbsts("INT", state);
    }
    if (mask & USBSTS_ERRINT) {
        trace_usb_ehci_usbsts("ERRINT", state);
    }
    if (mask & USBSTS_PCD) {
        trace_usb_ehci_usbsts("PCD", state);
    }
    if (mask & USBSTS_FLR) {
        trace_usb_ehci_usbsts("FLR", state);
    }
    if (mask & USBSTS_HSE) {
        trace_usb_ehci_usbsts("HSE", state);
    }
    if (mask & USBSTS_IAA) {
        trace_usb_ehci_usbsts("IAA", state);
    }

    /* status */
    if (mask & USBSTS_HALT) {
        trace_usb_ehci_usbsts("HALT", state);
    }
    if (mask & USBSTS_REC) {
        trace_usb_ehci_usbsts("REC", state);
    }
    if (mask & USBSTS_PSS) {
        trace_usb_ehci_usbsts("PSS", state);
    }
    if (mask & USBSTS_ASS) {
        trace_usb_ehci_usbsts("ASS", state);
    }
}

static inline void ehci_set_usbsts(EHCIState *s, int mask)
{
    if ((s->usbsts & mask) == mask) {
        return;
    }
    ehci_trace_usbsts(mask, 1);
    s->usbsts |= mask;
}

static inline void ehci_clear_usbsts(EHCIState *s, int mask)
{
    if ((s->usbsts & mask) == 0) {
        return;
    }
    ehci_trace_usbsts(mask, 0);
    s->usbsts &= ~mask;
}
G
Gerd Hoffmann 已提交
271

272 273
/* update irq line */
static inline void ehci_update_irq(EHCIState *s)
G
Gerd Hoffmann 已提交
274 275 276 277 278 279 280
{
    int level = 0;

    if ((s->usbsts & USBINTR_MASK) & s->usbintr) {
        level = 1;
    }

281
    trace_usb_ehci_irq(level, s->frindex, s->usbsts, s->usbintr);
G
Gerd Hoffmann 已提交
282 283 284
    qemu_set_irq(s->irq, level);
}

285 286
/* flag interrupt condition */
static inline void ehci_raise_irq(EHCIState *s, int intr)
G
Gerd Hoffmann 已提交
287
{
288 289 290 291 292 293
    if (intr & (USBSTS_PCD | USBSTS_FLR | USBSTS_HSE)) {
        s->usbsts |= intr;
        ehci_update_irq(s);
    } else {
        s->usbsts_pending |= intr;
    }
G
Gerd Hoffmann 已提交
294 295
}

296 297 298 299 300
/*
 * Commit pending interrupts (added via ehci_raise_irq),
 * at the rate allowed by "Interrupt Threshold Control".
 */
static inline void ehci_commit_irq(EHCIState *s)
G
Gerd Hoffmann 已提交
301
{
302 303
    uint32_t itc;

G
Gerd Hoffmann 已提交
304 305 306
    if (!s->usbsts_pending) {
        return;
    }
307 308 309 310 311 312
    if (s->usbsts_frindex > s->frindex) {
        return;
    }

    itc = (s->usbcmd >> 16) & 0xff;
    s->usbsts |= s->usbsts_pending;
G
Gerd Hoffmann 已提交
313
    s->usbsts_pending = 0;
314 315
    s->usbsts_frindex = s->frindex + itc;
    ehci_update_irq(s);
G
Gerd Hoffmann 已提交
316 317
}

G
Gerd Hoffmann 已提交
318 319 320 321 322 323 324 325 326 327 328
static void ehci_update_halt(EHCIState *s)
{
    if (s->usbcmd & USBCMD_RUNSTOP) {
        ehci_clear_usbsts(s, USBSTS_HALT);
    } else {
        if (s->astate == EST_INACTIVE && s->pstate == EST_INACTIVE) {
            ehci_set_usbsts(s, USBSTS_HALT);
        }
    }
}

329 330 331 332 333
static void ehci_set_state(EHCIState *s, int async, int state)
{
    if (async) {
        trace_usb_ehci_state("async", state2str(state));
        s->astate = state;
334 335
        if (s->astate == EST_INACTIVE) {
            ehci_clear_usbsts(s, USBSTS_ASS);
G
Gerd Hoffmann 已提交
336
            ehci_update_halt(s);
337 338 339
        } else {
            ehci_set_usbsts(s, USBSTS_ASS);
        }
340 341 342
    } else {
        trace_usb_ehci_state("periodic", state2str(state));
        s->pstate = state;
343 344
        if (s->pstate == EST_INACTIVE) {
            ehci_clear_usbsts(s, USBSTS_PSS);
G
Gerd Hoffmann 已提交
345
            ehci_update_halt(s);
346 347 348
        } else {
            ehci_set_usbsts(s, USBSTS_PSS);
        }
349 350 351 352 353 354 355 356
    }
}

static int ehci_get_state(EHCIState *s, int async)
{
    return async ? s->astate : s->pstate;
}

G
Gerd Hoffmann 已提交
357 358 359 360 361 362 363 364 365 366 367 368 369 370
static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
{
    if (async) {
        s->a_fetch_addr = addr;
    } else {
        s->p_fetch_addr = addr;
    }
}

static int ehci_get_fetch_addr(EHCIState *s, int async)
{
    return async ? s->a_fetch_addr : s->p_fetch_addr;
}

A
Avi Kivity 已提交
371
static void ehci_trace_qh(EHCIQueue *q, hwaddr addr, EHCIqh *qh)
372
{
373 374 375 376 377 378 379 380 381 382 383 384 385 386
    /* need three here due to argument count limits */
    trace_usb_ehci_qh_ptrs(q, addr, qh->next,
                           qh->current_qtd, qh->next_qtd, qh->altnext_qtd);
    trace_usb_ehci_qh_fields(addr,
                             get_field(qh->epchar, QH_EPCHAR_RL),
                             get_field(qh->epchar, QH_EPCHAR_MPLEN),
                             get_field(qh->epchar, QH_EPCHAR_EPS),
                             get_field(qh->epchar, QH_EPCHAR_EP),
                             get_field(qh->epchar, QH_EPCHAR_DEVADDR));
    trace_usb_ehci_qh_bits(addr,
                           (bool)(qh->epchar & QH_EPCHAR_C),
                           (bool)(qh->epchar & QH_EPCHAR_H),
                           (bool)(qh->epchar & QH_EPCHAR_DTC),
                           (bool)(qh->epchar & QH_EPCHAR_I));
387 388
}

A
Avi Kivity 已提交
389
static void ehci_trace_qtd(EHCIQueue *q, hwaddr addr, EHCIqtd *qtd)
390
{
391 392 393 394 395 396 397 398 399 400 401 402 403
    /* need three here due to argument count limits */
    trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext);
    trace_usb_ehci_qtd_fields(addr,
                              get_field(qtd->token, QTD_TOKEN_TBYTES),
                              get_field(qtd->token, QTD_TOKEN_CPAGE),
                              get_field(qtd->token, QTD_TOKEN_CERR),
                              get_field(qtd->token, QTD_TOKEN_PID));
    trace_usb_ehci_qtd_bits(addr,
                            (bool)(qtd->token & QTD_TOKEN_IOC),
                            (bool)(qtd->token & QTD_TOKEN_ACTIVE),
                            (bool)(qtd->token & QTD_TOKEN_HALT),
                            (bool)(qtd->token & QTD_TOKEN_BABBLE),
                            (bool)(qtd->token & QTD_TOKEN_XACTERR));
404 405
}

A
Avi Kivity 已提交
406
static void ehci_trace_itd(EHCIState *s, hwaddr addr, EHCIitd *itd)
407
{
G
Gerd Hoffmann 已提交
408 409 410 411 412
    trace_usb_ehci_itd(addr, itd->next,
                       get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT),
                       get_field(itd->bufptr[2], ITD_BUFPTR_MULT),
                       get_field(itd->bufptr[0], ITD_BUFPTR_EP),
                       get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
413 414
}

A
Avi Kivity 已提交
415
static void ehci_trace_sitd(EHCIState *s, hwaddr addr,
G
Gerd Hoffmann 已提交
416 417 418 419 420 421
                            EHCIsitd *sitd)
{
    trace_usb_ehci_sitd(addr, sitd->next,
                        (bool)(sitd->results & SITD_RESULTS_ACTIVE));
}

G
Gerd Hoffmann 已提交
422 423 424 425 426 427
static void ehci_trace_guest_bug(EHCIState *s, const char *message)
{
    trace_usb_ehci_guest_bug(message);
    fprintf(stderr, "ehci warning: %s\n", message);
}

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
static inline bool ehci_enabled(EHCIState *s)
{
    return s->usbcmd & USBCMD_RUNSTOP;
}

static inline bool ehci_async_enabled(EHCIState *s)
{
    return ehci_enabled(s) && (s->usbcmd & USBCMD_ASE);
}

static inline bool ehci_periodic_enabled(EHCIState *s)
{
    return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE);
}

443 444 445 446 447 448
/* Get an array of dwords from main memory */
static inline int get_dwords(EHCIState *ehci, uint32_t addr,
                             uint32_t *buf, int num)
{
    int i;

P
Paolo Bonzini 已提交
449
    if (!ehci->as) {
450 451 452 453 454 455 456
        ehci_raise_irq(ehci, USBSTS_HSE);
        ehci->usbcmd &= ~USBCMD_RUNSTOP;
        trace_usb_ehci_dma_error();
        return -1;
    }

    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
P
Paolo Bonzini 已提交
457
        dma_memory_read(ehci->as, addr, buf, sizeof(*buf));
458 459 460 461 462 463 464 465 466 467 468 469
        *buf = le32_to_cpu(*buf);
    }

    return num;
}

/* Put an array of dwords in to main memory */
static inline int put_dwords(EHCIState *ehci, uint32_t addr,
                             uint32_t *buf, int num)
{
    int i;

P
Paolo Bonzini 已提交
470
    if (!ehci->as) {
471 472 473 474 475 476 477 478
        ehci_raise_irq(ehci, USBSTS_HSE);
        ehci->usbcmd &= ~USBCMD_RUNSTOP;
        trace_usb_ehci_dma_error();
        return -1;
    }

    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
        uint32_t tmp = cpu_to_le32(*buf);
P
Paolo Bonzini 已提交
479
        dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp));
480 481 482 483 484
    }

    return num;
}

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
static int ehci_get_pid(EHCIqtd *qtd)
{
    switch (get_field(qtd->token, QTD_TOKEN_PID)) {
    case 0:
        return USB_TOKEN_OUT;
    case 1:
        return USB_TOKEN_IN;
    case 2:
        return USB_TOKEN_SETUP;
    default:
        fprintf(stderr, "bad token\n");
        return 0;
    }
}

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh)
{
    uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
    uint32_t endp    = get_field(qh->epchar, QH_EPCHAR_EP);
    if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
        (endp    != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
        (qh->current_qtd != q->qh.current_qtd) ||
        (q->async && qh->next_qtd != q->qh.next_qtd) ||
        (memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd,
                                 7 * sizeof(uint32_t)) != 0) ||
        (q->dev != NULL && q->dev->addr != devaddr)) {
        return false;
    } else {
        return true;
    }
}

static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
{
    if (p->qtdaddr != p->queue->qtdaddr ||
        (p->queue->async && !NLPTR_TBIT(p->qtd.next) &&
            (p->qtd.next != qtd->next)) ||
        (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) ||
523
        p->qtd.token != qtd->token ||
524 525 526 527 528 529 530
        p->qtd.bufptr[0] != qtd->bufptr[0]) {
        return false;
    } else {
        return true;
    }
}

531 532 533 534 535 536 537 538 539 540 541 542 543
static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
{
    int ep  = get_field(q->qh.epchar, QH_EPCHAR_EP);
    int pid = ehci_get_pid(qtd);

    /* Note the pid changing is normal for ep 0 (the control ep) */
    if (q->last_pid && ep != 0 && pid != q->last_pid) {
        return false;
    } else {
        return true;
    }
}

544 545 546 547 548
/* Finish executing and writeback a packet outside of the regular
   fetchqh -> fetchqtd -> execute -> writeback cycle */
static void ehci_writeback_async_complete_packet(EHCIPacket *p)
{
    EHCIQueue *q = p->queue;
549 550
    EHCIqtd qtd;
    EHCIqh qh;
551 552
    int state;

553 554 555 556 557 558 559 560 561 562 563
    /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */
    get_dwords(q->ehci, NLPTR_GET(q->qhaddr),
               (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
    get_dwords(q->ehci, NLPTR_GET(q->qtdaddr),
               (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
    if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) {
        p->async = EHCI_ASYNC_INITIALIZED;
        ehci_free_packet(p);
        return;
    }

564 565 566 567 568 569 570 571 572
    state = ehci_get_state(q->ehci, q->async);
    ehci_state_executing(q);
    ehci_state_writeback(q); /* Frees the packet! */
    if (!(q->qh.token & QTD_TOKEN_HALT)) {
        ehci_state_advqueue(q);
    }
    ehci_set_state(q->ehci, q->async, state);
}

G
Gerd Hoffmann 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
/* packet management */

static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
{
    EHCIPacket *p;

    p = g_new0(EHCIPacket, 1);
    p->queue = q;
    usb_packet_init(&p->packet);
    QTAILQ_INSERT_TAIL(&q->packets, p, next);
    trace_usb_ehci_packet_action(p->queue, p, "alloc");
    return p;
}

static void ehci_free_packet(EHCIPacket *p)
{
589 590
    if (p->async == EHCI_ASYNC_FINISHED &&
            !(p->queue->qh.token & QTD_TOKEN_HALT)) {
591
        ehci_writeback_async_complete_packet(p);
592 593
        return;
    }
594 595 596
    trace_usb_ehci_packet_action(p->queue, p, "free");
    if (p->async == EHCI_ASYNC_INFLIGHT) {
        usb_cancel_packet(&p->packet);
597 598 599 600 601 602 603 604 605
    }
    if (p->async == EHCI_ASYNC_FINISHED &&
            p->packet.status == USB_RET_SUCCESS) {
        fprintf(stderr,
                "EHCI: Dropping completed packet from halted %s ep %02X\n",
                (p->pid == USB_TOKEN_IN) ? "in" : "out",
                get_field(p->queue->qh.epchar, QH_EPCHAR_EP));
    }
    if (p->async != EHCI_ASYNC_NONE) {
606 607 608
        usb_packet_unmap(&p->packet, &p->sgl);
        qemu_sglist_destroy(&p->sgl);
    }
G
Gerd Hoffmann 已提交
609 610 611 612 613
    QTAILQ_REMOVE(&p->queue->packets, p, next);
    usb_packet_cleanup(&p->packet);
    g_free(p);
}

G
Gerd Hoffmann 已提交
614 615
/* queue management */

G
Gerd Hoffmann 已提交
616
static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
G
Gerd Hoffmann 已提交
617
{
618
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
G
Gerd Hoffmann 已提交
619 620
    EHCIQueue *q;

621
    q = g_malloc0(sizeof(*q));
G
Gerd Hoffmann 已提交
622
    q->ehci = ehci;
G
Gerd Hoffmann 已提交
623
    q->qhaddr = addr;
624
    q->async = async;
G
Gerd Hoffmann 已提交
625
    QTAILQ_INIT(&q->packets);
626
    QTAILQ_INSERT_HEAD(head, q, next);
G
Gerd Hoffmann 已提交
627 628 629 630
    trace_usb_ehci_queue_action(q, "alloc");
    return q;
}

631 632 633 634 635 636 637 638 639 640 641
static void ehci_queue_stopped(EHCIQueue *q)
{
    int endp  = get_field(q->qh.epchar, QH_EPCHAR_EP);

    if (!q->last_pid || !q->dev) {
        return;
    }

    usb_device_ep_stopped(q->dev, usb_ep_get(q->dev, q->last_pid, endp));
}

G
Gerd Hoffmann 已提交
642
static int ehci_cancel_queue(EHCIQueue *q)
G
Gerd Hoffmann 已提交
643 644
{
    EHCIPacket *p;
G
Gerd Hoffmann 已提交
645
    int packets = 0;
G
Gerd Hoffmann 已提交
646 647 648

    p = QTAILQ_FIRST(&q->packets);
    if (p == NULL) {
649
        goto leave;
G
Gerd Hoffmann 已提交
650 651 652 653 654
    }

    trace_usb_ehci_queue_action(q, "cancel");
    do {
        ehci_free_packet(p);
G
Gerd Hoffmann 已提交
655
        packets++;
G
Gerd Hoffmann 已提交
656
    } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
657 658 659

leave:
    ehci_queue_stopped(q);
G
Gerd Hoffmann 已提交
660
    return packets;
G
Gerd Hoffmann 已提交
661 662
}

G
Gerd Hoffmann 已提交
663
static int ehci_reset_queue(EHCIQueue *q)
664
{
G
Gerd Hoffmann 已提交
665 666
    int packets;

667
    trace_usb_ehci_queue_action(q, "reset");
G
Gerd Hoffmann 已提交
668
    packets = ehci_cancel_queue(q);
669 670
    q->dev = NULL;
    q->qtdaddr = 0;
671
    q->last_pid = 0;
G
Gerd Hoffmann 已提交
672
    return packets;
673 674
}

675
static void ehci_free_queue(EHCIQueue *q, const char *warn)
G
Gerd Hoffmann 已提交
676
{
677
    EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
678
    int cancelled;
G
Gerd Hoffmann 已提交
679

G
Gerd Hoffmann 已提交
680
    trace_usb_ehci_queue_action(q, "free");
681 682 683 684
    cancelled = ehci_cancel_queue(q);
    if (warn && cancelled > 0) {
        ehci_trace_guest_bug(q->ehci, warn);
    }
685
    QTAILQ_REMOVE(head, q, next);
686
    g_free(q);
G
Gerd Hoffmann 已提交
687 688
}

689 690
static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
                                        int async)
G
Gerd Hoffmann 已提交
691
{
692
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
G
Gerd Hoffmann 已提交
693 694
    EHCIQueue *q;

695
    QTAILQ_FOREACH(q, head, next) {
G
Gerd Hoffmann 已提交
696 697 698 699 700 701 702
        if (addr == q->qhaddr) {
            return q;
        }
    }
    return NULL;
}

703
static void ehci_queues_rip_unused(EHCIState *ehci, int async)
G
Gerd Hoffmann 已提交
704
{
705
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
706
    const char *warn = async ? "guest unlinked busy QH" : NULL;
G
Gerd Hoffmann 已提交
707
    uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
G
Gerd Hoffmann 已提交
708 709
    EHCIQueue *q, *tmp;

710
    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
G
Gerd Hoffmann 已提交
711 712
        if (q->seen) {
            q->seen = 0;
G
Gerd Hoffmann 已提交
713
            q->ts = ehci->last_run_ns;
G
Gerd Hoffmann 已提交
714 715
            continue;
        }
716
        if (ehci->last_run_ns < q->ts + maxage) {
G
Gerd Hoffmann 已提交
717 718
            continue;
        }
719
        ehci_free_queue(q, warn);
G
Gerd Hoffmann 已提交
720 721 722
    }
}

723 724 725 726 727 728 729 730 731 732 733 734
static void ehci_queues_rip_unseen(EHCIState *ehci, int async)
{
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
    EHCIQueue *q, *tmp;

    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
        if (!q->seen) {
            ehci_free_queue(q, NULL);
        }
    }
}

735
static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
736
{
737
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
738 739
    EHCIQueue *q, *tmp;

740
    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
741
        if (q->dev != dev) {
742 743
            continue;
        }
744
        ehci_free_queue(q, NULL);
745 746 747
    }
}

748
static void ehci_queues_rip_all(EHCIState *ehci, int async)
G
Gerd Hoffmann 已提交
749
{
750
    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
751
    const char *warn = async ? "guest stopped busy async schedule" : NULL;
G
Gerd Hoffmann 已提交
752 753
    EHCIQueue *q, *tmp;

754
    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
755
        ehci_free_queue(q, warn);
G
Gerd Hoffmann 已提交
756 757 758
    }
}

G
Gerd Hoffmann 已提交
759 760 761 762 763 764
/* Attach or detach a device on root hub */

static void ehci_attach(USBPort *port)
{
    EHCIState *s = port->opaque;
    uint32_t *portsc = &s->portsc[port->index];
G
Gerd Hoffmann 已提交
765
    const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
G
Gerd Hoffmann 已提交
766

G
Gerd Hoffmann 已提交
767
    trace_usb_ehci_port_attach(port->index, owner, port->dev->product_desc);
G
Gerd Hoffmann 已提交
768

769 770 771 772 773 774 775
    if (*portsc & PORTSC_POWNER) {
        USBPort *companion = s->companion_ports[port->index];
        companion->dev = port->dev;
        companion->ops->attach(companion);
        return;
    }

G
Gerd Hoffmann 已提交
776 777 778
    *portsc |= PORTSC_CONNECT;
    *portsc |= PORTSC_CSC;

779
    ehci_raise_irq(s, USBSTS_PCD);
G
Gerd Hoffmann 已提交
780 781 782 783 784 785
}

static void ehci_detach(USBPort *port)
{
    EHCIState *s = port->opaque;
    uint32_t *portsc = &s->portsc[port->index];
G
Gerd Hoffmann 已提交
786
    const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
G
Gerd Hoffmann 已提交
787

G
Gerd Hoffmann 已提交
788
    trace_usb_ehci_port_detach(port->index, owner);
G
Gerd Hoffmann 已提交
789

790 791 792 793
    if (*portsc & PORTSC_POWNER) {
        USBPort *companion = s->companion_ports[port->index];
        companion->ops->detach(companion);
        companion->dev = NULL;
794 795 796 797 798
        /*
         * EHCI spec 4.2.2: "When a disconnect occurs... On the event,
         * the port ownership is returned immediately to the EHCI controller."
         */
        *portsc &= ~PORTSC_POWNER;
799 800 801
        return;
    }

802 803
    ehci_queues_rip_device(s, port->dev, 0);
    ehci_queues_rip_device(s, port->dev, 1);
804

805
    *portsc &= ~(PORTSC_CONNECT|PORTSC_PED);
G
Gerd Hoffmann 已提交
806 807
    *portsc |= PORTSC_CSC;

808
    ehci_raise_irq(s, USBSTS_PCD);
G
Gerd Hoffmann 已提交
809 810
}

811 812 813
static void ehci_child_detach(USBPort *port, USBDevice *child)
{
    EHCIState *s = port->opaque;
814 815 816 817 818 819 820
    uint32_t portsc = s->portsc[port->index];

    if (portsc & PORTSC_POWNER) {
        USBPort *companion = s->companion_ports[port->index];
        companion->ops->child_detach(companion, child);
        return;
    }
821

822 823
    ehci_queues_rip_device(s, child, 0);
    ehci_queues_rip_device(s, child, 1);
824 825
}

826 827 828 829 830 831 832 833 834 835
static void ehci_wakeup(USBPort *port)
{
    EHCIState *s = port->opaque;
    uint32_t portsc = s->portsc[port->index];

    if (portsc & PORTSC_POWNER) {
        USBPort *companion = s->companion_ports[port->index];
        if (companion->ops->wakeup) {
            companion->ops->wakeup(companion);
        }
836
        return;
837
    }
838 839

    qemu_bh_schedule(s->async_bh);
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
}

static int ehci_register_companion(USBBus *bus, USBPort *ports[],
                                   uint32_t portcount, uint32_t firstport)
{
    EHCIState *s = container_of(bus, EHCIState, bus);
    uint32_t i;

    if (firstport + portcount > NB_PORTS) {
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport",
                      "firstport on masterbus");
        error_printf_unless_qmp(
            "firstport value of %u makes companion take ports %u - %u, which "
            "is outside of the valid range of 0 - %u\n", firstport, firstport,
            firstport + portcount - 1, NB_PORTS - 1);
        return -1;
    }

    for (i = 0; i < portcount; i++) {
        if (s->companion_ports[firstport + i]) {
            qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
                          "an USB masterbus");
            error_printf_unless_qmp(
                "port %u on masterbus %s already has a companion assigned\n",
                firstport + i, bus->qbus.name);
            return -1;
        }
    }

    for (i = 0; i < portcount; i++) {
        s->companion_ports[firstport + i] = ports[i];
        s->ports[firstport + i].speedmask |=
            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
        /* Ensure devs attached before the initial reset go to the companion */
        s->portsc[firstport + i] = PORTSC_POWNER;
    }

    s->companion_count++;
878
    s->caps[0x05] = (s->companion_count << 4) | portcount;
879 880 881 882

    return 0;
}

G
Gerd Hoffmann 已提交
883 884
static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
                                 unsigned int stream)
885 886 887 888 889 890 891 892 893 894 895 896
{
    EHCIState *s = container_of(bus, EHCIState, bus);
    uint32_t portsc = s->portsc[ep->dev->port->index];

    if (portsc & PORTSC_POWNER) {
        return;
    }

    s->periodic_sched_active = PERIODIC_ACTIVE;
    qemu_bh_schedule(s->async_bh);
}

897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
{
    USBDevice *dev;
    USBPort *port;
    int i;

    for (i = 0; i < NB_PORTS; i++) {
        port = &ehci->ports[i];
        if (!(ehci->portsc[i] & PORTSC_PED)) {
            DPRINTF("Port %d not enabled\n", i);
            continue;
        }
        dev = usb_find_device(port, addr);
        if (dev != NULL) {
            return dev;
        }
    }
    return NULL;
}

G
Gerd Hoffmann 已提交
917 918 919 920 921
/* 4.1 host controller initialization */
static void ehci_reset(void *opaque)
{
    EHCIState *s = opaque;
    int i;
922
    USBDevice *devs[NB_PORTS];
G
Gerd Hoffmann 已提交
923

G
Gerd Hoffmann 已提交
924
    trace_usb_ehci_reset();
G
Gerd Hoffmann 已提交
925

926 927 928 929 930 931
    /*
     * Do the detach before touching portsc, so that it correctly gets send to
     * us or to our companion based on PORTSC_POWNER before the reset.
     */
    for(i = 0; i < NB_PORTS; i++) {
        devs[i] = s->ports[i].dev;
932 933
        if (devs[i] && devs[i]->attached) {
            usb_detach(&s->ports[i]);
934 935 936
        }
    }

937 938
    memset(&s->opreg, 0x00, sizeof(s->opreg));
    memset(&s->portsc, 0x00, sizeof(s->portsc));
G
Gerd Hoffmann 已提交
939 940 941

    s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
    s->usbsts = USBSTS_HALT;
942 943
    s->usbsts_pending = 0;
    s->usbsts_frindex = 0;
G
Gerd Hoffmann 已提交
944 945 946 947 948

    s->astate = EST_INACTIVE;
    s->pstate = EST_INACTIVE;

    for(i = 0; i < NB_PORTS; i++) {
949 950 951 952 953
        if (s->companion_ports[i]) {
            s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
        } else {
            s->portsc[i] = PORTSC_PPOWER;
        }
954 955
        if (devs[i] && devs[i]->attached) {
            usb_attach(&s->ports[i]);
G
Gerd Hoffmann 已提交
956
            usb_device_reset(devs[i]);
G
Gerd Hoffmann 已提交
957 958
        }
    }
959 960
    ehci_queues_rip_all(s, 0);
    ehci_queues_rip_all(s, 1);
G
Gerd Hoffmann 已提交
961
    qemu_del_timer(s->frame_timer);
962
    qemu_bh_cancel(s->async_bh);
G
Gerd Hoffmann 已提交
963 964
}

A
Avi Kivity 已提交
965
static uint64_t ehci_caps_read(void *ptr, hwaddr addr,
966
                               unsigned size)
G
Gerd Hoffmann 已提交
967 968
{
    EHCIState *s = ptr;
969
    return s->caps[addr];
G
Gerd Hoffmann 已提交
970 971
}

A
Avi Kivity 已提交
972
static uint64_t ehci_opreg_read(void *ptr, hwaddr addr,
973
                                unsigned size)
G
Gerd Hoffmann 已提交
974 975 976 977
{
    EHCIState *s = ptr;
    uint32_t val;

978 979 980 981 982 983 984 985 986
    switch (addr) {
    case FRINDEX:
        /* Round down to mult of 8, else it can go backwards on migration */
        val = s->frindex & ~7;
        break;
    default:
        val = s->opreg[addr >> 2];
    }

987
    trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val);
G
Gerd Hoffmann 已提交
988 989 990
    return val;
}

A
Avi Kivity 已提交
991
static uint64_t ehci_port_read(void *ptr, hwaddr addr,
992
                               unsigned size)
G
Gerd Hoffmann 已提交
993 994 995 996
{
    EHCIState *s = ptr;
    uint32_t val;

997 998
    val = s->portsc[addr >> 2];
    trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val);
G
Gerd Hoffmann 已提交
999 1000 1001
    return val;
}

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
{
    USBDevice *dev = s->ports[port].dev;
    uint32_t *portsc = &s->portsc[port];
    uint32_t orig;

    if (s->companion_ports[port] == NULL)
        return;

    owner = owner & PORTSC_POWNER;
    orig  = *portsc & PORTSC_POWNER;

    if (!(owner ^ orig)) {
        return;
    }

1018 1019
    if (dev && dev->attached) {
        usb_detach(&s->ports[port]);
1020 1021 1022 1023 1024
    }

    *portsc &= ~PORTSC_POWNER;
    *portsc |= owner;

1025 1026
    if (dev && dev->attached) {
        usb_attach(&s->ports[port]);
1027 1028 1029
    }
}

A
Avi Kivity 已提交
1030
static void ehci_port_write(void *ptr, hwaddr addr,
1031
                            uint64_t val, unsigned size)
G
Gerd Hoffmann 已提交
1032
{
1033 1034
    EHCIState *s = ptr;
    int port = addr >> 2;
G
Gerd Hoffmann 已提交
1035
    uint32_t *portsc = &s->portsc[port];
1036
    uint32_t old = *portsc;
G
Gerd Hoffmann 已提交
1037 1038
    USBDevice *dev = s->ports[port].dev;

1039 1040
    trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val);

1041 1042 1043 1044
    /* Clear rwc bits */
    *portsc &= ~(val & PORTSC_RWC_MASK);
    /* The guest may clear, but not set the PED bit */
    *portsc &= val | ~PORTSC_PED;
1045 1046 1047
    /* POWNER is masked out by RO_MASK as it is RO when we've no companion */
    handle_port_owner_write(s, port, val);
    /* And finally apply RO_MASK */
G
Gerd Hoffmann 已提交
1048 1049 1050
    val &= PORTSC_RO_MASK;

    if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
G
Gerd Hoffmann 已提交
1051
        trace_usb_ehci_port_reset(port, 1);
G
Gerd Hoffmann 已提交
1052 1053 1054
    }

    if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
G
Gerd Hoffmann 已提交
1055
        trace_usb_ehci_port_reset(port, 0);
1056
        if (dev && dev->attached) {
G
Gerd Hoffmann 已提交
1057
            usb_port_reset(&s->ports[port]);
G
Gerd Hoffmann 已提交
1058 1059 1060
            *portsc &= ~PORTSC_CSC;
        }

1061 1062
        /*
         *  Table 2.16 Set the enable bit(and enable bit change) to indicate
G
Gerd Hoffmann 已提交
1063 1064
         *  to SW that this port has a high speed device attached
         */
1065
        if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
1066 1067
            val |= PORTSC_PED;
        }
G
Gerd Hoffmann 已提交
1068 1069 1070 1071
    }

    *portsc &= ~PORTSC_RO_MASK;
    *portsc |= val;
1072
    trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old);
G
Gerd Hoffmann 已提交
1073 1074
}

A
Avi Kivity 已提交
1075
static void ehci_opreg_write(void *ptr, hwaddr addr,
1076
                             uint64_t val, unsigned size)
G
Gerd Hoffmann 已提交
1077 1078
{
    EHCIState *s = ptr;
1079
    uint32_t *mmio = s->opreg + (addr >> 2);
G
Gerd Hoffmann 已提交
1080
    uint32_t old = *mmio;
G
Gerd Hoffmann 已提交
1081
    int i;
G
Gerd Hoffmann 已提交
1082

1083
    trace_usb_ehci_opreg_write(addr + s->opregbase, addr2str(addr), val);
G
Gerd Hoffmann 已提交
1084

1085
    switch (addr) {
G
Gerd Hoffmann 已提交
1086
    case USBCMD:
G
Gerd Hoffmann 已提交
1087 1088 1089 1090 1091 1092
        if (val & USBCMD_HCRESET) {
            ehci_reset(s);
            val = s->usbcmd;
            break;
        }

1093 1094 1095
        /* not supporting dynamic frame list size at the moment */
        if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
            fprintf(stderr, "attempt to set frame list size -- value %d\n",
1096
                    (int)val & USBCMD_FLS);
1097 1098 1099
            val &= ~USBCMD_FLS;
        }

1100 1101 1102 1103 1104 1105 1106
        if (val & USBCMD_IAAD) {
            /*
             * Process IAAD immediately, otherwise the Linux IAAD watchdog may
             * trigger and re-use a qh without us seeing the unlink.
             */
            s->async_stepdown = 0;
            qemu_bh_schedule(s->async_bh);
G
Gerd Hoffmann 已提交
1107
            trace_usb_ehci_doorbell_ring();
1108 1109
        }

G
Gerd Hoffmann 已提交
1110 1111
        if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
            ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) {
G
Gerd Hoffmann 已提交
1112
            if (s->pstate == EST_INACTIVE) {
G
Gerd Hoffmann 已提交
1113 1114
                SET_LAST_RUN_CLOCK(s);
            }
1115
            s->usbcmd = val; /* Set usbcmd for ehci_update_halt() */
G
Gerd Hoffmann 已提交
1116
            ehci_update_halt(s);
G
Gerd Hoffmann 已提交
1117
            s->async_stepdown = 0;
1118
            qemu_bh_schedule(s->async_bh);
G
Gerd Hoffmann 已提交
1119 1120 1121 1122
        }
        break;

    case USBSTS:
J
Jim Meyering 已提交
1123 1124
        val &= USBSTS_RO_MASK;              // bits 6 through 31 are RO
        ehci_clear_usbsts(s, val);          // bits 0 through 5 are R/WC
G
Gerd Hoffmann 已提交
1125
        val = s->usbsts;
1126
        ehci_update_irq(s);
G
Gerd Hoffmann 已提交
1127 1128 1129 1130
        break;

    case USBINTR:
        val &= USBINTR_MASK;
1131 1132 1133
        if (ehci_enabled(s) && (USBSTS_FLR & val)) {
            qemu_bh_schedule(s->async_bh);
        }
G
Gerd Hoffmann 已提交
1134 1135
        break;

1136
    case FRINDEX:
1137 1138
        val &= 0x00003fff; /* frindex is 14bits */
        s->usbsts_frindex = val;
1139 1140
        break;

G
Gerd Hoffmann 已提交
1141 1142 1143 1144
    case CONFIGFLAG:
        val &= 0x1;
        if (val) {
            for(i = 0; i < NB_PORTS; i++)
1145
                handle_port_owner_write(s, i, 0);
G
Gerd Hoffmann 已提交
1146 1147 1148 1149
        }
        break;

    case PERIODICLISTBASE:
1150
        if (ehci_periodic_enabled(s)) {
G
Gerd Hoffmann 已提交
1151 1152 1153 1154 1155 1156 1157
            fprintf(stderr,
              "ehci: PERIODIC list base register set while periodic schedule\n"
              "      is enabled and HC is enabled\n");
        }
        break;

    case ASYNCLISTADDR:
1158
        if (ehci_async_enabled(s)) {
G
Gerd Hoffmann 已提交
1159 1160 1161 1162 1163 1164 1165
            fprintf(stderr,
              "ehci: ASYNC list address register set while async schedule\n"
              "      is enabled and HC is enabled\n");
        }
        break;
    }

G
Gerd Hoffmann 已提交
1166
    *mmio = val;
1167 1168
    trace_usb_ehci_opreg_change(addr + s->opregbase, addr2str(addr),
                                *mmio, old);
G
Gerd Hoffmann 已提交
1169 1170
}

G
Gerd Hoffmann 已提交
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
/*
 *  Write the qh back to guest physical memory.  This step isn't
 *  in the EHCI spec but we need to do it since we don't share
 *  physical memory with our guest VM.
 *
 *  The first three dwords are read-only for the EHCI, so skip them
 *  when writing back the qh.
 */
static void ehci_flush_qh(EHCIQueue *q)
{
    uint32_t *qh = (uint32_t *) &q->qh;
    uint32_t dwords = sizeof(EHCIqh) >> 2;
    uint32_t addr = NLPTR_GET(q->qhaddr);

    put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
}

G
Gerd Hoffmann 已提交
1188 1189
// 4.10.2

G
Gerd Hoffmann 已提交
1190
static int ehci_qh_do_overlay(EHCIQueue *q)
G
Gerd Hoffmann 已提交
1191
{
G
Gerd Hoffmann 已提交
1192
    EHCIPacket *p = QTAILQ_FIRST(&q->packets);
G
Gerd Hoffmann 已提交
1193 1194 1195 1196 1197 1198
    int i;
    int dtoggle;
    int ping;
    int eps;
    int reload;

G
Gerd Hoffmann 已提交
1199 1200 1201
    assert(p != NULL);
    assert(p->qtdaddr == q->qtdaddr);

G
Gerd Hoffmann 已提交
1202 1203
    // remember values in fields to preserve in qh after overlay

G
Gerd Hoffmann 已提交
1204 1205
    dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
    ping    = q->qh.token & QTD_TOKEN_PING;
G
Gerd Hoffmann 已提交
1206

G
Gerd Hoffmann 已提交
1207 1208 1209 1210
    q->qh.current_qtd = p->qtdaddr;
    q->qh.next_qtd    = p->qtd.next;
    q->qh.altnext_qtd = p->qtd.altnext;
    q->qh.token       = p->qtd.token;
G
Gerd Hoffmann 已提交
1211 1212


G
Gerd Hoffmann 已提交
1213
    eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
G
Gerd Hoffmann 已提交
1214
    if (eps == EHCI_QH_EPS_HIGH) {
G
Gerd Hoffmann 已提交
1215 1216
        q->qh.token &= ~QTD_TOKEN_PING;
        q->qh.token |= ping;
G
Gerd Hoffmann 已提交
1217 1218
    }

G
Gerd Hoffmann 已提交
1219 1220
    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
    set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
G
Gerd Hoffmann 已提交
1221 1222

    for (i = 0; i < 5; i++) {
G
Gerd Hoffmann 已提交
1223
        q->qh.bufptr[i] = p->qtd.bufptr[i];
G
Gerd Hoffmann 已提交
1224 1225
    }

G
Gerd Hoffmann 已提交
1226
    if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
G
Gerd Hoffmann 已提交
1227
        // preserve QH DT bit
G
Gerd Hoffmann 已提交
1228 1229
        q->qh.token &= ~QTD_TOKEN_DTOGGLE;
        q->qh.token |= dtoggle;
G
Gerd Hoffmann 已提交
1230 1231
    }

G
Gerd Hoffmann 已提交
1232 1233
    q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
    q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
G
Gerd Hoffmann 已提交
1234

G
Gerd Hoffmann 已提交
1235
    ehci_flush_qh(q);
G
Gerd Hoffmann 已提交
1236 1237 1238 1239

    return 0;
}

G
Gerd Hoffmann 已提交
1240
static int ehci_init_transfer(EHCIPacket *p)
G
Gerd Hoffmann 已提交
1241
{
1242
    uint32_t cpage, offset, bytes, plen;
1243
    dma_addr_t page;
G
Gerd Hoffmann 已提交
1244

G
Gerd Hoffmann 已提交
1245 1246 1247
    cpage  = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
    bytes  = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
    offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
P
Paolo Bonzini 已提交
1248
    qemu_sglist_init(&p->sgl, 5, p->queue->ehci->as);
G
Gerd Hoffmann 已提交
1249

1250 1251 1252
    while (bytes > 0) {
        if (cpage > 4) {
            fprintf(stderr, "cpage out of range (%d)\n", cpage);
1253
            return -1;
1254
        }
G
Gerd Hoffmann 已提交
1255

G
Gerd Hoffmann 已提交
1256
        page  = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK;
1257 1258 1259 1260 1261 1262
        page += offset;
        plen  = bytes;
        if (plen > 4096 - offset) {
            plen = 4096 - offset;
            offset = 0;
            cpage++;
G
Gerd Hoffmann 已提交
1263 1264
        }

G
Gerd Hoffmann 已提交
1265
        qemu_sglist_add(&p->sgl, page, plen);
1266 1267 1268 1269
        bytes -= plen;
    }
    return 0;
}
G
Gerd Hoffmann 已提交
1270

1271
static void ehci_finish_transfer(EHCIQueue *q, int len)
1272 1273
{
    uint32_t cpage, offset;
G
Gerd Hoffmann 已提交
1274

1275
    if (len > 0) {
1276 1277 1278
        /* update cpage & offset */
        cpage  = get_field(q->qh.token, QTD_TOKEN_CPAGE);
        offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
G
Gerd Hoffmann 已提交
1279

1280
        offset += len;
1281 1282
        cpage  += offset >> QTD_BUFPTR_SH;
        offset &= ~QTD_BUFPTR_MASK;
G
Gerd Hoffmann 已提交
1283

1284 1285 1286 1287
        set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
        q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
        q->qh.bufptr[0] |= offset;
    }
G
Gerd Hoffmann 已提交
1288 1289
}

1290
static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
G
Gerd Hoffmann 已提交
1291
{
G
Gerd Hoffmann 已提交
1292
    EHCIPacket *p;
1293 1294 1295 1296 1297 1298 1299 1300
    EHCIState *s = port->opaque;
    uint32_t portsc = s->portsc[port->index];

    if (portsc & PORTSC_POWNER) {
        USBPort *companion = s->companion_ports[port->index];
        companion->ops->complete(companion, packet);
        return;
    }
G
Gerd Hoffmann 已提交
1301

G
Gerd Hoffmann 已提交
1302 1303
    p = container_of(packet, EHCIPacket, packet);
    assert(p->async == EHCI_ASYNC_INFLIGHT);
1304

1305
    if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
1306 1307 1308 1309 1310 1311
        trace_usb_ehci_packet_action(p->queue, p, "remove");
        ehci_free_packet(p);
        return;
    }

    trace_usb_ehci_packet_action(p->queue, p, "wakeup");
G
Gerd Hoffmann 已提交
1312
    p->async = EHCI_ASYNC_FINISHED;
1313

1314 1315
    if (!p->queue->async) {
        s->periodic_sched_active = PERIODIC_ACTIVE;
1316
    }
1317
    qemu_bh_schedule(s->async_bh);
G
Gerd Hoffmann 已提交
1318 1319
}

G
Gerd Hoffmann 已提交
1320
static void ehci_execute_complete(EHCIQueue *q)
G
Gerd Hoffmann 已提交
1321
{
G
Gerd Hoffmann 已提交
1322
    EHCIPacket *p = QTAILQ_FIRST(&q->packets);
1323
    uint32_t tbytes;
G
Gerd Hoffmann 已提交
1324 1325 1326

    assert(p != NULL);
    assert(p->qtdaddr == q->qtdaddr);
1327 1328
    assert(p->async == EHCI_ASYNC_INITIALIZED ||
           p->async == EHCI_ASYNC_FINISHED);
G
Gerd Hoffmann 已提交
1329

1330 1331 1332 1333
    DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, "
            "status %d, actual_length %d\n",
            q->qhaddr, q->qh.next, q->qtdaddr,
            p->packet.status, p->packet.actual_length);
G
Gerd Hoffmann 已提交
1334

1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
    switch (p->packet.status) {
    case USB_RET_SUCCESS:
        break;
    case USB_RET_IOERROR:
    case USB_RET_NODEV:
        q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
        set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
        ehci_raise_irq(q->ehci, USBSTS_ERRINT);
        break;
    case USB_RET_STALL:
        q->qh.token |= QTD_TOKEN_HALT;
        ehci_raise_irq(q->ehci, USBSTS_ERRINT);
        break;
    case USB_RET_NAK:
        set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
        return; /* We're not done yet with this transaction */
    case USB_RET_BABBLE:
        q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
        ehci_raise_irq(q->ehci, USBSTS_ERRINT);
        break;
    default:
        /* should not be triggerable */
        fprintf(stderr, "USB invalid response %d\n", p->packet.status);
        assert(0);
        break;
    }

    /* TODO check 4.12 for splits */
    tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
    if (tbytes && p->pid == USB_TOKEN_IN) {
        tbytes -= p->packet.actual_length;
        if (tbytes) {
            /* 4.15.1.2 must raise int on a short input packet */
            ehci_raise_irq(q->ehci, USBSTS_INT);
1369 1370 1371
            if (q->async) {
                q->ehci->int_req_by_async = true;
            }
G
Gerd Hoffmann 已提交
1372 1373
        }
    } else {
1374
        tbytes = 0;
G
Gerd Hoffmann 已提交
1375
    }
1376 1377 1378 1379
    DPRINTF("updating tbytes to %d\n", tbytes);
    set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);

    ehci_finish_transfer(q, p->packet.actual_length);
1380
    usb_packet_unmap(&p->packet, &p->sgl);
G
Gerd Hoffmann 已提交
1381
    qemu_sglist_destroy(&p->sgl);
1382
    p->async = EHCI_ASYNC_NONE;
G
Gerd Hoffmann 已提交
1383

G
Gerd Hoffmann 已提交
1384 1385
    q->qh.token ^= QTD_TOKEN_DTOGGLE;
    q->qh.token &= ~QTD_TOKEN_ACTIVE;
G
Gerd Hoffmann 已提交
1386

1387
    if (q->qh.token & QTD_TOKEN_IOC) {
1388
        ehci_raise_irq(q->ehci, USBSTS_INT);
1389 1390 1391
        if (q->async) {
            q->ehci->int_req_by_async = true;
        }
G
Gerd Hoffmann 已提交
1392 1393 1394
    }
}

1395
/* 4.10.3 returns "again" */
G
Gerd Hoffmann 已提交
1396
static int ehci_execute(EHCIPacket *p, const char *action)
G
Gerd Hoffmann 已提交
1397
{
1398
    USBEndpoint *ep;
G
Gerd Hoffmann 已提交
1399
    int endp;
1400
    bool spd;
G
Gerd Hoffmann 已提交
1401

1402 1403 1404
    assert(p->async == EHCI_ASYNC_NONE ||
           p->async == EHCI_ASYNC_INITIALIZED);

1405 1406
    if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
        fprintf(stderr, "Attempting to execute inactive qtd\n");
1407
        return -1;
G
Gerd Hoffmann 已提交
1408 1409
    }

1410
    if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) {
1411 1412
        ehci_trace_guest_bug(p->queue->ehci,
                             "guest requested more bytes than allowed");
1413
        return -1;
G
Gerd Hoffmann 已提交
1414 1415
    }

1416 1417 1418
    if (!ehci_verify_pid(p->queue, &p->qtd)) {
        ehci_queue_stopped(p->queue); /* Mark the ep in the prev dir stopped */
    }
1419
    p->pid = ehci_get_pid(&p->qtd);
1420
    p->queue->last_pid = p->pid;
1421
    endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
1422
    ep = usb_ep_get(p->queue->dev, p->pid, endp);
G
Gerd Hoffmann 已提交
1423

1424 1425
    if (p->async == EHCI_ASYNC_NONE) {
        if (ehci_init_transfer(p) != 0) {
1426
            return -1;
1427 1428
        }

1429
        spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
G
Gerd Hoffmann 已提交
1430
        usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd,
1431
                         (p->qtd.token & QTD_TOKEN_IOC) != 0);
1432 1433 1434
        usb_packet_map(&p->packet, &p->sgl);
        p->async = EHCI_ASYNC_INITIALIZED;
    }
1435

G
Gerd Hoffmann 已提交
1436
    trace_usb_ehci_packet_action(p->queue, p, action);
1437 1438 1439 1440 1441
    usb_handle_packet(p->queue->dev, &p->packet);
    DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x "
            "status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next,
            p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status,
            p->packet.actual_length);
G
Gerd Hoffmann 已提交
1442

1443
    if (p->packet.actual_length > BUFF_SIZE) {
G
Gerd Hoffmann 已提交
1444
        fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
1445
        return -1;
G
Gerd Hoffmann 已提交
1446 1447
    }

1448
    return 1;
G
Gerd Hoffmann 已提交
1449 1450 1451 1452 1453 1454
}

/*  4.7.2
 */

static int ehci_process_itd(EHCIState *ehci,
G
Gerd Hoffmann 已提交
1455 1456
                            EHCIitd *itd,
                            uint32_t addr)
G
Gerd Hoffmann 已提交
1457 1458
{
    USBDevice *dev;
1459
    USBEndpoint *ep;
1460
    uint32_t i, len, pid, dir, devaddr, endp;
G
Gerd Hoffmann 已提交
1461
    uint32_t pg, off, ptr1, ptr2, max, mult;
G
Gerd Hoffmann 已提交
1462

1463 1464
    ehci->periodic_sched_active = PERIODIC_ACTIVE;

G
Gerd Hoffmann 已提交
1465
    dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
G
Gerd Hoffmann 已提交
1466
    devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
G
Gerd Hoffmann 已提交
1467
    endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
G
Gerd Hoffmann 已提交
1468 1469
    max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
    mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
G
Gerd Hoffmann 已提交
1470 1471 1472

    for(i = 0; i < 8; i++) {
        if (itd->transact[i] & ITD_XACT_ACTIVE) {
G
Gerd Hoffmann 已提交
1473 1474 1475 1476 1477 1478 1479 1480 1481
            pg   = get_field(itd->transact[i], ITD_XACT_PGSEL);
            off  = itd->transact[i] & ITD_XACT_OFFSET_MASK;
            ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
            ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
            len  = get_field(itd->transact[i], ITD_XACT_LENGTH);

            if (len > max * mult) {
                len = max * mult;
            }
G
Gerd Hoffmann 已提交
1482 1483

            if (len > BUFF_SIZE) {
1484
                return -1;
G
Gerd Hoffmann 已提交
1485 1486
            }

P
Paolo Bonzini 已提交
1487
            qemu_sglist_init(&ehci->isgl, 2, ehci->as);
G
Gerd Hoffmann 已提交
1488 1489
            if (off + len > 4096) {
                /* transfer crosses page border */
1490 1491 1492 1493
                uint32_t len2 = off + len - 4096;
                uint32_t len1 = len - len2;
                qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
                qemu_sglist_add(&ehci->isgl, ptr2, len2);
G
Gerd Hoffmann 已提交
1494
            } else {
1495
                qemu_sglist_add(&ehci->isgl, ptr1 + off, len);
G
Gerd Hoffmann 已提交
1496
            }
G
Gerd Hoffmann 已提交
1497

1498
            pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
G
Gerd Hoffmann 已提交
1499

1500 1501
            dev = ehci_find_device(ehci, devaddr);
            ep = usb_ep_get(dev, pid, endp);
1502
            if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
G
Gerd Hoffmann 已提交
1503
                usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
1504
                                 (itd->transact[i] & ITD_XACT_IOC) != 0);
G
Gerd Hoffmann 已提交
1505
                usb_packet_map(&ehci->ipacket, &ehci->isgl);
1506
                usb_handle_packet(dev, &ehci->ipacket);
1507
                usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
G
Gerd Hoffmann 已提交
1508 1509
            } else {
                DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
1510 1511
                ehci->ipacket.status = USB_RET_NAK;
                ehci->ipacket.actual_length = 0;
G
Gerd Hoffmann 已提交
1512
            }
1513 1514
            qemu_sglist_destroy(&ehci->isgl);

1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
            switch (ehci->ipacket.status) {
            case USB_RET_SUCCESS:
                break;
            default:
                fprintf(stderr, "Unexpected iso usb result: %d\n",
                        ehci->ipacket.status);
                /* Fall through */
            case USB_RET_IOERROR:
            case USB_RET_NODEV:
                /* 3.3.2: XACTERR is only allowed on IN transactions */
                if (dir) {
                    itd->transact[i] |= ITD_XACT_XACTERR;
1527
                    ehci_raise_irq(ehci, USBSTS_ERRINT);
1528
                }
1529 1530 1531 1532 1533 1534 1535 1536 1537
                break;
            case USB_RET_BABBLE:
                itd->transact[i] |= ITD_XACT_BABBLE;
                ehci_raise_irq(ehci, USBSTS_ERRINT);
                break;
            case USB_RET_NAK:
                /* no data for us, so do a zero-length transfer */
                ehci->ipacket.actual_length = 0;
                break;
1538
            }
1539 1540 1541 1542 1543 1544
            if (!dir) {
                set_field(&itd->transact[i], len - ehci->ipacket.actual_length,
                          ITD_XACT_LENGTH); /* OUT */
            } else {
                set_field(&itd->transact[i], ehci->ipacket.actual_length,
                          ITD_XACT_LENGTH); /* IN */
G
Gerd Hoffmann 已提交
1545
            }
1546
            if (itd->transact[i] & ITD_XACT_IOC) {
1547
                ehci_raise_irq(ehci, USBSTS_INT);
1548
            }
G
Gerd Hoffmann 已提交
1549
            itd->transact[i] &= ~ITD_XACT_ACTIVE;
G
Gerd Hoffmann 已提交
1550 1551 1552 1553 1554
        }
    }
    return 0;
}

G
Gerd Hoffmann 已提交
1555

G
Gerd Hoffmann 已提交
1556 1557 1558
/*  This state is the entry point for asynchronous schedule
 *  processing.  Entry here consitutes a EHCI start event state (4.8.5)
 */
1559
static int ehci_state_waitlisthead(EHCIState *ehci,  int async)
G
Gerd Hoffmann 已提交
1560
{
G
Gerd Hoffmann 已提交
1561
    EHCIqh qh;
G
Gerd Hoffmann 已提交
1562 1563 1564 1565 1566 1567
    int i = 0;
    int again = 0;
    uint32_t entry = ehci->asynclistaddr;

    /* set reclamation flag at start event (4.8.6) */
    if (async) {
G
Gerd Hoffmann 已提交
1568
        ehci_set_usbsts(ehci, USBSTS_REC);
G
Gerd Hoffmann 已提交
1569 1570
    }

1571
    ehci_queues_rip_unused(ehci, async);
G
Gerd Hoffmann 已提交
1572

G
Gerd Hoffmann 已提交
1573 1574
    /*  Find the head of the list (4.9.1.1) */
    for(i = 0; i < MAX_QH; i++) {
G
Gerd Hoffmann 已提交
1575 1576 1577 1578
        if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
                       sizeof(EHCIqh) >> 2) < 0) {
            return 0;
        }
G
Gerd Hoffmann 已提交
1579
        ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
G
Gerd Hoffmann 已提交
1580

G
Gerd Hoffmann 已提交
1581
        if (qh.epchar & QH_EPCHAR_H) {
G
Gerd Hoffmann 已提交
1582 1583 1584 1585
            if (async) {
                entry |= (NLPTR_TYPE_QH << 1);
            }

G
Gerd Hoffmann 已提交
1586
            ehci_set_fetch_addr(ehci, async, entry);
1587
            ehci_set_state(ehci, async, EST_FETCHENTRY);
G
Gerd Hoffmann 已提交
1588 1589 1590 1591
            again = 1;
            goto out;
        }

G
Gerd Hoffmann 已提交
1592
        entry = qh.next;
G
Gerd Hoffmann 已提交
1593 1594 1595 1596 1597 1598 1599
        if (entry == ehci->asynclistaddr) {
            break;
        }
    }

    /* no head found for list. */

1600
    ehci_set_state(ehci, async, EST_ACTIVE);
G
Gerd Hoffmann 已提交
1601 1602 1603 1604 1605 1606 1607 1608 1609

out:
    return again;
}


/*  This state is the entry point for periodic schedule processing as
 *  well as being a continuation state for async processing.
 */
1610
static int ehci_state_fetchentry(EHCIState *ehci, int async)
G
Gerd Hoffmann 已提交
1611 1612
{
    int again = 0;
G
Gerd Hoffmann 已提交
1613
    uint32_t entry = ehci_get_fetch_addr(ehci, async);
G
Gerd Hoffmann 已提交
1614

1615
    if (NLPTR_TBIT(entry)) {
1616
        ehci_set_state(ehci, async, EST_ACTIVE);
G
Gerd Hoffmann 已提交
1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
        goto out;
    }

    /* section 4.8, only QH in async schedule */
    if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
        fprintf(stderr, "non queue head request in async schedule\n");
        return -1;
    }

    switch (NLPTR_TYPE_GET(entry)) {
    case NLPTR_TYPE_QH:
1628
        ehci_set_state(ehci, async, EST_FETCHQH);
G
Gerd Hoffmann 已提交
1629 1630 1631 1632
        again = 1;
        break;

    case NLPTR_TYPE_ITD:
1633
        ehci_set_state(ehci, async, EST_FETCHITD);
G
Gerd Hoffmann 已提交
1634 1635 1636
        again = 1;
        break;

G
Gerd Hoffmann 已提交
1637 1638 1639 1640 1641
    case NLPTR_TYPE_STITD:
        ehci_set_state(ehci, async, EST_FETCHSITD);
        again = 1;
        break;

G
Gerd Hoffmann 已提交
1642
    default:
G
Gerd Hoffmann 已提交
1643
        /* TODO: handle FSTN type */
G
Gerd Hoffmann 已提交
1644 1645 1646 1647 1648 1649 1650 1651 1652
        fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
                "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
        return -1;
    }

out:
    return again;
}

G
Gerd Hoffmann 已提交
1653
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
G
Gerd Hoffmann 已提交
1654
{
1655
    uint32_t entry;
G
Gerd Hoffmann 已提交
1656
    EHCIQueue *q;
1657
    EHCIqh qh;
G
Gerd Hoffmann 已提交
1658

G
Gerd Hoffmann 已提交
1659
    entry = ehci_get_fetch_addr(ehci, async);
1660
    q = ehci_find_queue_by_qh(ehci, entry, async);
G
Gerd Hoffmann 已提交
1661
    if (NULL == q) {
G
Gerd Hoffmann 已提交
1662
        q = ehci_alloc_queue(ehci, entry, async);
G
Gerd Hoffmann 已提交
1663 1664
    }

G
Gerd Hoffmann 已提交
1665
    q->seen++;
G
Gerd Hoffmann 已提交
1666 1667 1668 1669 1670 1671
    if (q->seen > 1) {
        /* we are going in circles -- stop processing */
        ehci_set_state(ehci, async, EST_ACTIVE);
        q = NULL;
        goto out;
    }
G
Gerd Hoffmann 已提交
1672

G
Gerd Hoffmann 已提交
1673 1674 1675 1676 1677
    if (get_dwords(ehci, NLPTR_GET(q->qhaddr),
                   (uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) {
        q = NULL;
        goto out;
    }
1678 1679 1680 1681 1682 1683
    ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);

    /*
     * The overlay area of the qh should never be changed by the guest,
     * except when idle, in which case the reset is a nop.
     */
1684
    if (!ehci_verify_qh(q, &qh)) {
G
Gerd Hoffmann 已提交
1685 1686 1687
        if (ehci_reset_queue(q) > 0) {
            ehci_trace_guest_bug(ehci, "guest updated active QH");
        }
1688 1689 1690
    }
    q->qh = qh;

1691 1692 1693 1694 1695
    q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT);
    if (q->transact_ctr == 0) { /* Guest bug in some versions of windows */
        q->transact_ctr = 4;
    }

1696
    if (q->dev == NULL) {
1697 1698
        q->dev = ehci_find_device(q->ehci,
                                  get_field(q->qh.epchar, QH_EPCHAR_DEVADDR));
1699 1700
    }

G
Gerd Hoffmann 已提交
1701
    if (async && (q->qh.epchar & QH_EPCHAR_H)) {
G
Gerd Hoffmann 已提交
1702 1703 1704

        /*  EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
        if (ehci->usbsts & USBSTS_REC) {
G
Gerd Hoffmann 已提交
1705
            ehci_clear_usbsts(ehci, USBSTS_REC);
G
Gerd Hoffmann 已提交
1706 1707
        } else {
            DPRINTF("FETCHQH:  QH 0x%08x. H-bit set, reclamation status reset"
G
Gerd Hoffmann 已提交
1708
                       " - done processing\n", q->qhaddr);
1709
            ehci_set_state(ehci, async, EST_ACTIVE);
G
Gerd Hoffmann 已提交
1710
            q = NULL;
G
Gerd Hoffmann 已提交
1711 1712 1713 1714 1715
            goto out;
        }
    }

#if EHCI_DEBUG
G
Gerd Hoffmann 已提交
1716
    if (q->qhaddr != q->qh.next) {
G
Gerd Hoffmann 已提交
1717
    DPRINTF("FETCHQH:  QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
G
Gerd Hoffmann 已提交
1718 1719 1720 1721 1722
               q->qhaddr,
               q->qh.epchar & QH_EPCHAR_H,
               q->qh.token & QTD_TOKEN_HALT,
               q->qh.token & QTD_TOKEN_ACTIVE,
               q->qh.next);
G
Gerd Hoffmann 已提交
1723 1724 1725
    }
#endif

G
Gerd Hoffmann 已提交
1726
    if (q->qh.token & QTD_TOKEN_HALT) {
1727
        ehci_set_state(ehci, async, EST_HORIZONTALQH);
G
Gerd Hoffmann 已提交
1728

1729 1730
    } else if ((q->qh.token & QTD_TOKEN_ACTIVE) &&
               (NLPTR_TBIT(q->qh.current_qtd) == 0)) {
G
Gerd Hoffmann 已提交
1731
        q->qtdaddr = q->qh.current_qtd;
1732
        ehci_set_state(ehci, async, EST_FETCHQTD);
G
Gerd Hoffmann 已提交
1733 1734 1735

    } else {
        /*  EHCI spec version 1.0 Section 4.10.2 */
1736
        ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
G
Gerd Hoffmann 已提交
1737 1738 1739
    }

out:
G
Gerd Hoffmann 已提交
1740
    return q;
G
Gerd Hoffmann 已提交
1741 1742
}

1743
static int ehci_state_fetchitd(EHCIState *ehci, int async)
G
Gerd Hoffmann 已提交
1744
{
G
Gerd Hoffmann 已提交
1745
    uint32_t entry;
G
Gerd Hoffmann 已提交
1746 1747
    EHCIitd itd;

G
Gerd Hoffmann 已提交
1748 1749 1750
    assert(!async);
    entry = ehci_get_fetch_addr(ehci, async);

G
Gerd Hoffmann 已提交
1751 1752 1753 1754
    if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
                   sizeof(EHCIitd) >> 2) < 0) {
        return -1;
    }
G
Gerd Hoffmann 已提交
1755
    ehci_trace_itd(ehci, entry, &itd);
G
Gerd Hoffmann 已提交
1756

G
Gerd Hoffmann 已提交
1757
    if (ehci_process_itd(ehci, &itd, entry) != 0) {
G
Gerd Hoffmann 已提交
1758 1759 1760
        return -1;
    }

1761 1762
    put_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
               sizeof(EHCIitd) >> 2);
G
Gerd Hoffmann 已提交
1763
    ehci_set_fetch_addr(ehci, async, itd.next);
1764
    ehci_set_state(ehci, async, EST_FETCHENTRY);
G
Gerd Hoffmann 已提交
1765 1766 1767 1768

    return 1;
}

G
Gerd Hoffmann 已提交
1769 1770 1771 1772 1773 1774 1775 1776
static int ehci_state_fetchsitd(EHCIState *ehci, int async)
{
    uint32_t entry;
    EHCIsitd sitd;

    assert(!async);
    entry = ehci_get_fetch_addr(ehci, async);

G
Gerd Hoffmann 已提交
1777 1778 1779 1780
    if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
                   sizeof(EHCIsitd) >> 2) < 0) {
        return 0;
    }
G
Gerd Hoffmann 已提交
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794
    ehci_trace_sitd(ehci, entry, &sitd);

    if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
        /* siTD is not active, nothing to do */;
    } else {
        /* TODO: split transfers are not implemented */
        fprintf(stderr, "WARNING: Skipping active siTD\n");
    }

    ehci_set_fetch_addr(ehci, async, sitd.next);
    ehci_set_state(ehci, async, EST_FETCHENTRY);
    return 1;
}

G
Gerd Hoffmann 已提交
1795
/* Section 4.10.2 - paragraph 3 */
1796
static int ehci_state_advqueue(EHCIQueue *q)
G
Gerd Hoffmann 已提交
1797 1798 1799 1800 1801 1802 1803
{
#if 0
    /* TO-DO: 4.10.2 - paragraph 2
     * if I-bit is set to 1 and QH is not active
     * go to horizontal QH
     */
    if (I-bit set) {
1804
        ehci_set_state(ehci, async, EST_HORIZONTALQH);
G
Gerd Hoffmann 已提交
1805 1806 1807 1808 1809 1810 1811
        goto out;
    }
#endif

    /*
     * want data and alt-next qTD is valid
     */
G
Gerd Hoffmann 已提交
1812 1813 1814
    if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
        (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
        q->qtdaddr = q->qh.altnext_qtd;
1815
        ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
G
Gerd Hoffmann 已提交
1816 1817 1818 1819

    /*
     *  next qTD is valid
     */
1820
    } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) {
G
Gerd Hoffmann 已提交
1821
        q->qtdaddr = q->qh.next_qtd;
1822
        ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
G
Gerd Hoffmann 已提交
1823 1824 1825 1826 1827

    /*
     *  no valid qTD, try next QH
     */
    } else {
1828
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
G
Gerd Hoffmann 已提交
1829 1830 1831 1832 1833 1834
    }

    return 1;
}

/* Section 4.10.2 - paragraph 4 */
1835
static int ehci_state_fetchqtd(EHCIQueue *q)
G
Gerd Hoffmann 已提交
1836
{
G
Gerd Hoffmann 已提交
1837 1838
    EHCIqtd qtd;
    EHCIPacket *p;
1839
    int again = 1;
G
Gerd Hoffmann 已提交
1840

G
Gerd Hoffmann 已提交
1841 1842 1843 1844
    if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
                   sizeof(EHCIqtd) >> 2) < 0) {
        return 0;
    }
G
Gerd Hoffmann 已提交
1845
    ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
G
Gerd Hoffmann 已提交
1846

G
Gerd Hoffmann 已提交
1847 1848
    p = QTAILQ_FIRST(&q->packets);
    if (p != NULL) {
1849
        if (!ehci_verify_qtd(p, &qtd)) {
1850
            ehci_cancel_queue(q);
1851 1852 1853
            if (qtd.token & QTD_TOKEN_ACTIVE) {
                ehci_trace_guest_bug(q->ehci, "guest updated active qTD");
            }
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863
            p = NULL;
        } else {
            p->qtd = qtd;
            ehci_qh_do_overlay(q);
        }
    }

    if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
    } else if (p != NULL) {
1864 1865
        switch (p->async) {
        case EHCI_ASYNC_NONE:
1866
        case EHCI_ASYNC_INITIALIZED:
1867
            /* Not yet executed (MULT), or previously nacked (int) packet */
1868 1869
            ehci_set_state(q->ehci, q->async, EST_EXECUTE);
            break;
1870
        case EHCI_ASYNC_INFLIGHT:
1871
            /* Check if the guest has added new tds to the queue */
1872
            again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head));
1873
            /* Unfinished async handled packet, go horizontal */
1874
            ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
1875 1876
            break;
        case EHCI_ASYNC_FINISHED:
1877
            /* Complete executing of the packet */
1878
            ehci_set_state(q->ehci, q->async, EST_EXECUTING);
1879
            break;
G
Gerd Hoffmann 已提交
1880
        }
1881
    } else {
G
Gerd Hoffmann 已提交
1882 1883 1884
        p = ehci_alloc_packet(q);
        p->qtdaddr = q->qtdaddr;
        p->qtd = qtd;
1885
        ehci_set_state(q->ehci, q->async, EST_EXECUTE);
G
Gerd Hoffmann 已提交
1886 1887 1888 1889 1890
    }

    return again;
}

1891
static int ehci_state_horizqh(EHCIQueue *q)
G
Gerd Hoffmann 已提交
1892 1893 1894
{
    int again = 0;

1895 1896 1897
    if (ehci_get_fetch_addr(q->ehci, q->async) != q->qh.next) {
        ehci_set_fetch_addr(q->ehci, q->async, q->qh.next);
        ehci_set_state(q->ehci, q->async, EST_FETCHENTRY);
G
Gerd Hoffmann 已提交
1898 1899
        again = 1;
    } else {
1900
        ehci_set_state(q->ehci, q->async, EST_ACTIVE);
G
Gerd Hoffmann 已提交
1901 1902 1903 1904 1905
    }

    return again;
}

1906
/* Returns "again" */
1907
static int ehci_fill_queue(EHCIPacket *p)
G
Gerd Hoffmann 已提交
1908
{
1909
    USBEndpoint *ep = p->packet.ep;
G
Gerd Hoffmann 已提交
1910 1911
    EHCIQueue *q = p->queue;
    EHCIqtd qtd = p->qtd;
1912
    uint32_t qtdaddr;
G
Gerd Hoffmann 已提交
1913 1914 1915 1916 1917 1918

    for (;;) {
        if (NLPTR_TBIT(qtd.next) != 0) {
            break;
        }
        qtdaddr = qtd.next;
1919 1920 1921 1922
        /*
         * Detect circular td lists, Windows creates these, counting on the
         * active bit going low after execution to make the queue stop.
         */
1923 1924 1925 1926
        QTAILQ_FOREACH(p, &q->packets, next) {
            if (p->qtdaddr == qtdaddr) {
                goto leave;
            }
1927
        }
G
Gerd Hoffmann 已提交
1928 1929 1930 1931
        if (get_dwords(q->ehci, NLPTR_GET(qtdaddr),
                       (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) {
            return -1;
        }
G
Gerd Hoffmann 已提交
1932 1933 1934 1935
        ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
        if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
            break;
        }
1936 1937 1938 1939
        if (!ehci_verify_pid(q, &qtd)) {
            ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid");
            break;
        }
G
Gerd Hoffmann 已提交
1940 1941 1942
        p = ehci_alloc_packet(q);
        p->qtdaddr = qtdaddr;
        p->qtd = qtd;
1943 1944
        if (ehci_execute(p, "queue") == -1) {
            return -1;
1945
        }
1946
        assert(p->packet.status == USB_RET_ASYNC);
G
Gerd Hoffmann 已提交
1947 1948
        p->async = EHCI_ASYNC_INFLIGHT;
    }
1949
leave:
1950 1951
    usb_device_flush_ep_queue(ep->dev, ep);
    return 1;
G
Gerd Hoffmann 已提交
1952 1953
}

1954
static int ehci_state_execute(EHCIQueue *q)
G
Gerd Hoffmann 已提交
1955
{
G
Gerd Hoffmann 已提交
1956
    EHCIPacket *p = QTAILQ_FIRST(&q->packets);
G
Gerd Hoffmann 已提交
1957 1958
    int again = 0;

G
Gerd Hoffmann 已提交
1959 1960 1961
    assert(p != NULL);
    assert(p->qtdaddr == q->qtdaddr);

G
Gerd Hoffmann 已提交
1962
    if (ehci_qh_do_overlay(q) != 0) {
G
Gerd Hoffmann 已提交
1963 1964 1965 1966 1967 1968
        return -1;
    }

    // TODO verify enough time remains in the uframe as in 4.4.1.1
    // TODO write back ptr to async list when done or out of time

1969 1970 1971 1972 1973
    /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
    if (!q->async && q->transact_ctr == 0) {
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
        again = 1;
        goto out;
G
Gerd Hoffmann 已提交
1974 1975
    }

1976
    if (q->async) {
G
Gerd Hoffmann 已提交
1977
        ehci_set_usbsts(q->ehci, USBSTS_REC);
G
Gerd Hoffmann 已提交
1978 1979
    }

1980 1981
    again = ehci_execute(p, "process");
    if (again == -1) {
G
Gerd Hoffmann 已提交
1982 1983
        goto out;
    }
1984
    if (p->packet.status == USB_RET_ASYNC) {
G
Gerd Hoffmann 已提交
1985
        ehci_flush_qh(q);
G
Gerd Hoffmann 已提交
1986
        trace_usb_ehci_packet_action(p->queue, p, "async");
G
Gerd Hoffmann 已提交
1987
        p->async = EHCI_ASYNC_INFLIGHT;
1988
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
1989
        if (q->async) {
1990
            again = ehci_fill_queue(p);
1991 1992 1993
        } else {
            again = 1;
        }
G
Gerd Hoffmann 已提交
1994
        goto out;
G
Gerd Hoffmann 已提交
1995 1996
    }

1997
    ehci_set_state(q->ehci, q->async, EST_EXECUTING);
G
Gerd Hoffmann 已提交
1998 1999
    again = 1;

G
Gerd Hoffmann 已提交
2000 2001 2002 2003
out:
    return again;
}

2004
static int ehci_state_executing(EHCIQueue *q)
G
Gerd Hoffmann 已提交
2005
{
G
Gerd Hoffmann 已提交
2006
    EHCIPacket *p = QTAILQ_FIRST(&q->packets);
G
Gerd Hoffmann 已提交
2007

G
Gerd Hoffmann 已提交
2008 2009 2010
    assert(p != NULL);
    assert(p->qtdaddr == q->qtdaddr);

G
Gerd Hoffmann 已提交
2011
    ehci_execute_complete(q);
G
Gerd Hoffmann 已提交
2012

2013 2014 2015
    /* 4.10.3 */
    if (!q->async && q->transact_ctr > 0) {
        q->transact_ctr--;
G
Gerd Hoffmann 已提交
2016 2017 2018
    }

    /* 4.10.5 */
2019
    if (p->packet.status == USB_RET_NAK) {
2020
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
G
Gerd Hoffmann 已提交
2021
    } else {
2022
        ehci_set_state(q->ehci, q->async, EST_WRITEBACK);
G
Gerd Hoffmann 已提交
2023 2024
    }

G
Gerd Hoffmann 已提交
2025
    ehci_flush_qh(q);
2026
    return 1;
G
Gerd Hoffmann 已提交
2027 2028 2029
}


2030
static int ehci_state_writeback(EHCIQueue *q)
G
Gerd Hoffmann 已提交
2031
{
G
Gerd Hoffmann 已提交
2032
    EHCIPacket *p = QTAILQ_FIRST(&q->packets);
G
Gerd Hoffmann 已提交
2033
    uint32_t *qtd, addr;
G
Gerd Hoffmann 已提交
2034 2035 2036
    int again = 0;

    /*  Write back the QTD from the QH area */
G
Gerd Hoffmann 已提交
2037 2038 2039 2040
    assert(p != NULL);
    assert(p->qtdaddr == q->qtdaddr);

    ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd);
G
Gerd Hoffmann 已提交
2041 2042 2043
    qtd = (uint32_t *) &q->qh.next_qtd;
    addr = NLPTR_GET(p->qtdaddr);
    put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 2);
G
Gerd Hoffmann 已提交
2044
    ehci_free_packet(p);
G
Gerd Hoffmann 已提交
2045

G
Gerd Hoffmann 已提交
2046 2047 2048 2049 2050 2051 2052
    /*
     * EHCI specs say go horizontal here.
     *
     * We can also advance the queue here for performance reasons.  We
     * need to take care to only take that shortcut in case we've
     * processed the qtd just written back without errors, i.e. halt
     * bit is clear.
G
Gerd Hoffmann 已提交
2053
     */
G
Gerd Hoffmann 已提交
2054
    if (q->qh.token & QTD_TOKEN_HALT) {
2055
        ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
G
Gerd Hoffmann 已提交
2056 2057
        again = 1;
    } else {
2058
        ehci_set_state(q->ehci, q->async, EST_ADVANCEQUEUE);
G
Gerd Hoffmann 已提交
2059
        again = 1;
G
Gerd Hoffmann 已提交
2060
    }
G
Gerd Hoffmann 已提交
2061 2062 2063 2064 2065 2066 2067
    return again;
}

/*
 * This is the state machine that is common to both async and periodic
 */

2068
static void ehci_advance_state(EHCIState *ehci, int async)
G
Gerd Hoffmann 已提交
2069
{
G
Gerd Hoffmann 已提交
2070
    EHCIQueue *q = NULL;
G
Gerd Hoffmann 已提交
2071 2072 2073
    int again;

    do {
2074
        switch(ehci_get_state(ehci, async)) {
G
Gerd Hoffmann 已提交
2075
        case EST_WAITLISTHEAD:
2076
            again = ehci_state_waitlisthead(ehci, async);
G
Gerd Hoffmann 已提交
2077 2078 2079
            break;

        case EST_FETCHENTRY:
2080
            again = ehci_state_fetchentry(ehci, async);
G
Gerd Hoffmann 已提交
2081 2082 2083
            break;

        case EST_FETCHQH:
G
Gerd Hoffmann 已提交
2084
            q = ehci_state_fetchqh(ehci, async);
2085 2086 2087 2088 2089 2090
            if (q != NULL) {
                assert(q->async == async);
                again = 1;
            } else {
                again = 0;
            }
G
Gerd Hoffmann 已提交
2091 2092 2093
            break;

        case EST_FETCHITD:
2094
            again = ehci_state_fetchitd(ehci, async);
G
Gerd Hoffmann 已提交
2095 2096
            break;

G
Gerd Hoffmann 已提交
2097 2098 2099 2100
        case EST_FETCHSITD:
            again = ehci_state_fetchsitd(ehci, async);
            break;

G
Gerd Hoffmann 已提交
2101
        case EST_ADVANCEQUEUE:
2102
            assert(q != NULL);
2103
            again = ehci_state_advqueue(q);
G
Gerd Hoffmann 已提交
2104 2105 2106
            break;

        case EST_FETCHQTD:
2107
            assert(q != NULL);
2108
            again = ehci_state_fetchqtd(q);
G
Gerd Hoffmann 已提交
2109 2110 2111
            break;

        case EST_HORIZONTALQH:
2112
            assert(q != NULL);
2113
            again = ehci_state_horizqh(q);
G
Gerd Hoffmann 已提交
2114 2115 2116
            break;

        case EST_EXECUTE:
2117
            assert(q != NULL);
2118
            again = ehci_state_execute(q);
G
Gerd Hoffmann 已提交
2119 2120 2121
            if (async) {
                ehci->async_stepdown = 0;
            }
G
Gerd Hoffmann 已提交
2122 2123 2124
            break;

        case EST_EXECUTING:
G
Gerd Hoffmann 已提交
2125
            assert(q != NULL);
G
Gerd Hoffmann 已提交
2126 2127 2128
            if (async) {
                ehci->async_stepdown = 0;
            }
2129
            again = ehci_state_executing(q);
G
Gerd Hoffmann 已提交
2130 2131 2132
            break;

        case EST_WRITEBACK:
G
Gerd Hoffmann 已提交
2133
            assert(q != NULL);
2134
            again = ehci_state_writeback(q);
2135 2136 2137
            if (!async) {
                ehci->periodic_sched_active = PERIODIC_ACTIVE;
            }
G
Gerd Hoffmann 已提交
2138 2139 2140 2141 2142
            break;

        default:
            fprintf(stderr, "Bad state!\n");
            again = -1;
G
Gerd Hoffmann 已提交
2143
            assert(0);
G
Gerd Hoffmann 已提交
2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157
            break;
        }

        if (again < 0) {
            fprintf(stderr, "processing error - resetting ehci HC\n");
            ehci_reset(ehci);
            again = 0;
        }
    }
    while (again);
}

static void ehci_advance_async_state(EHCIState *ehci)
{
2158
    const int async = 1;
G
Gerd Hoffmann 已提交
2159

2160
    switch(ehci_get_state(ehci, async)) {
G
Gerd Hoffmann 已提交
2161
    case EST_INACTIVE:
2162
        if (!ehci_async_enabled(ehci)) {
G
Gerd Hoffmann 已提交
2163 2164
            break;
        }
2165
        ehci_set_state(ehci, async, EST_ACTIVE);
G
Gerd Hoffmann 已提交
2166 2167 2168
        // No break, fall through to ACTIVE

    case EST_ACTIVE:
2169
        if (!ehci_async_enabled(ehci)) {
2170
            ehci_queues_rip_all(ehci, async);
2171
            ehci_set_state(ehci, async, EST_INACTIVE);
G
Gerd Hoffmann 已提交
2172 2173 2174
            break;
        }

2175
        /* make sure guest has acknowledged the doorbell interrupt */
G
Gerd Hoffmann 已提交
2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
        /* TO-DO: is this really needed? */
        if (ehci->usbsts & USBSTS_IAA) {
            DPRINTF("IAA status bit still set.\n");
            break;
        }

        /* check that address register has been set */
        if (ehci->asynclistaddr == 0) {
            break;
        }

2187 2188
        ehci_set_state(ehci, async, EST_WAITLISTHEAD);
        ehci_advance_state(ehci, async);
2189 2190 2191 2192 2193 2194 2195

        /* If the doorbell is set, the guest wants to make a change to the
         * schedule. The host controller needs to release cached data.
         * (section 4.8.2)
         */
        if (ehci->usbcmd & USBCMD_IAAD) {
            /* Remove all unseen qhs from the async qhs queue */
2196
            ehci_queues_rip_unseen(ehci, async);
G
Gerd Hoffmann 已提交
2197
            trace_usb_ehci_doorbell_ack();
2198
            ehci->usbcmd &= ~USBCMD_IAAD;
2199
            ehci_raise_irq(ehci, USBSTS_IAA);
2200
        }
G
Gerd Hoffmann 已提交
2201 2202 2203 2204 2205 2206
        break;

    default:
        /* this should only be due to a developer mistake */
        fprintf(stderr, "ehci: Bad asynchronous state %d. "
                "Resetting to active\n", ehci->astate);
G
Gerd Hoffmann 已提交
2207
        assert(0);
G
Gerd Hoffmann 已提交
2208 2209 2210 2211 2212 2213 2214
    }
}

static void ehci_advance_periodic_state(EHCIState *ehci)
{
    uint32_t entry;
    uint32_t list;
2215
    const int async = 0;
G
Gerd Hoffmann 已提交
2216 2217 2218

    // 4.6

2219
    switch(ehci_get_state(ehci, async)) {
G
Gerd Hoffmann 已提交
2220
    case EST_INACTIVE:
2221
        if (!(ehci->frindex & 7) && ehci_periodic_enabled(ehci)) {
2222
            ehci_set_state(ehci, async, EST_ACTIVE);
G
Gerd Hoffmann 已提交
2223 2224 2225 2226 2227
            // No break, fall through to ACTIVE
        } else
            break;

    case EST_ACTIVE:
2228
        if (!(ehci->frindex & 7) && !ehci_periodic_enabled(ehci)) {
2229
            ehci_queues_rip_all(ehci, async);
2230
            ehci_set_state(ehci, async, EST_INACTIVE);
G
Gerd Hoffmann 已提交
2231 2232 2233 2234 2235 2236 2237 2238 2239 2240
            break;
        }

        list = ehci->periodiclistbase & 0xfffff000;
        /* check that register has been set */
        if (list == 0) {
            break;
        }
        list |= ((ehci->frindex & 0x1ff8) >> 1);

G
Gerd Hoffmann 已提交
2241 2242 2243
        if (get_dwords(ehci, list, &entry, 1) < 0) {
            break;
        }
G
Gerd Hoffmann 已提交
2244 2245 2246

        DPRINTF("PERIODIC state adv fr=%d.  [%08X] -> %08X\n",
                ehci->frindex / 8, list, entry);
G
Gerd Hoffmann 已提交
2247
        ehci_set_fetch_addr(ehci, async,entry);
2248 2249
        ehci_set_state(ehci, async, EST_FETCHENTRY);
        ehci_advance_state(ehci, async);
2250
        ehci_queues_rip_unused(ehci, async);
G
Gerd Hoffmann 已提交
2251 2252 2253 2254 2255 2256
        break;

    default:
        /* this should only be due to a developer mistake */
        fprintf(stderr, "ehci: Bad periodic state %d. "
                "Resetting to active\n", ehci->pstate);
G
Gerd Hoffmann 已提交
2257
        assert(0);
G
Gerd Hoffmann 已提交
2258 2259 2260
    }
}

2261
static void ehci_update_frindex(EHCIState *ehci, int uframes)
G
Gerd Hoffmann 已提交
2262 2263 2264
{
    int i;

2265
    if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) {
G
Gerd Hoffmann 已提交
2266 2267 2268
        return;
    }

2269 2270
    for (i = 0; i < uframes; i++) {
        ehci->frindex++;
G
Gerd Hoffmann 已提交
2271 2272

        if (ehci->frindex == 0x00002000) {
2273
            ehci_raise_irq(ehci, USBSTS_FLR);
G
Gerd Hoffmann 已提交
2274 2275 2276
        }

        if (ehci->frindex == 0x00004000) {
2277
            ehci_raise_irq(ehci, USBSTS_FLR);
G
Gerd Hoffmann 已提交
2278
            ehci->frindex = 0;
2279
            if (ehci->usbsts_frindex >= 0x00004000) {
2280 2281 2282 2283
                ehci->usbsts_frindex -= 0x00004000;
            } else {
                ehci->usbsts_frindex = 0;
            }
G
Gerd Hoffmann 已提交
2284 2285 2286 2287
        }
    }
}

G
Gerd Hoffmann 已提交
2288 2289 2290
static void ehci_frame_timer(void *opaque)
{
    EHCIState *ehci = opaque;
2291
    int need_timer = 0;
G
Gerd Hoffmann 已提交
2292
    int64_t expire_time, t_now;
G
Gerd Hoffmann 已提交
2293
    uint64_t ns_elapsed;
2294
    int uframes, skipped_uframes;
G
Gerd Hoffmann 已提交
2295 2296 2297
    int i;

    t_now = qemu_get_clock_ns(vm_clock);
G
Gerd Hoffmann 已提交
2298
    ns_elapsed = t_now - ehci->last_run_ns;
2299
    uframes = ns_elapsed / UFRAME_TIMER_NS;
G
Gerd Hoffmann 已提交
2300

G
Gerd Hoffmann 已提交
2301
    if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) {
2302
        need_timer++;
G
Gerd Hoffmann 已提交
2303

2304 2305 2306 2307 2308 2309
        if (uframes > (ehci->maxframes * 8)) {
            skipped_uframes = uframes - (ehci->maxframes * 8);
            ehci_update_frindex(ehci, skipped_uframes);
            ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes;
            uframes -= skipped_uframes;
            DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes);
G
Gerd Hoffmann 已提交
2310 2311
        }

2312
        for (i = 0; i < uframes; i++) {
2313 2314 2315
            /*
             * If we're running behind schedule, we should not catch up
             * too fast, as that will make some guests unhappy:
2316
             * 1) We must process a minimum of MIN_UFR_PER_TICK frames,
2317 2318 2319
             *    otherwise we will never catch up
             * 2) Process frames until the guest has requested an irq (IOC)
             */
2320
            if (i >= MIN_UFR_PER_TICK) {
2321 2322 2323 2324 2325
                ehci_commit_irq(ehci);
                if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
                    break;
                }
            }
2326 2327 2328
            if (ehci->periodic_sched_active) {
                ehci->periodic_sched_active--;
            }
G
Gerd Hoffmann 已提交
2329
            ehci_update_frindex(ehci, 1);
2330 2331 2332 2333
            if ((ehci->frindex & 7) == 0) {
                ehci_advance_periodic_state(ehci);
            }
            ehci->last_run_ns += UFRAME_TIMER_NS;
G
Gerd Hoffmann 已提交
2334 2335
        }
    } else {
2336
        ehci->periodic_sched_active = 0;
2337 2338
        ehci_update_frindex(ehci, uframes);
        ehci->last_run_ns += UFRAME_TIMER_NS * uframes;
G
Gerd Hoffmann 已提交
2339 2340
    }

2341 2342 2343 2344 2345 2346
    if (ehci->periodic_sched_active) {
        ehci->async_stepdown = 0;
    } else if (ehci->async_stepdown < ehci->maxframes / 2) {
        ehci->async_stepdown++;
    }

G
Gerd Hoffmann 已提交
2347 2348 2349
    /*  Async is not inside loop since it executes everything it can once
     *  called
     */
G
Gerd Hoffmann 已提交
2350
    if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) {
2351
        need_timer++;
2352
        ehci_advance_async_state(ehci);
G
Gerd Hoffmann 已提交
2353
    }
G
Gerd Hoffmann 已提交
2354

2355 2356 2357 2358
    ehci_commit_irq(ehci);
    if (ehci->usbsts_pending) {
        need_timer++;
        ehci->async_stepdown = 0;
G
Gerd Hoffmann 已提交
2359
    }
2360

2361 2362 2363 2364
    if (ehci_enabled(ehci) && (ehci->usbintr & USBSTS_FLR)) {
        need_timer++;
    }

2365
    if (need_timer) {
2366 2367 2368
        /* If we've raised int, we speed up the timer, so that we quickly
         * notice any new packets queued up in response */
        if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) {
2369
            expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 4);
2370 2371 2372
            ehci->int_req_by_async = false;
        } else {
            expire_time = t_now + (get_ticks_per_sec()
2373
                               * (ehci->async_stepdown+1) / FRAME_TIMER_FREQ);
2374
        }
2375 2376
        qemu_mod_timer(ehci->frame_timer, expire_time);
    }
G
Gerd Hoffmann 已提交
2377 2378
}

2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
static const MemoryRegionOps ehci_mmio_caps_ops = {
    .read = ehci_caps_read,
    .valid.min_access_size = 1,
    .valid.max_access_size = 4,
    .impl.min_access_size = 1,
    .impl.max_access_size = 1,
    .endianness = DEVICE_LITTLE_ENDIAN,
};

static const MemoryRegionOps ehci_mmio_opreg_ops = {
    .read = ehci_opreg_read,
    .write = ehci_opreg_write,
    .valid.min_access_size = 4,
    .valid.max_access_size = 4,
    .endianness = DEVICE_LITTLE_ENDIAN,
};

static const MemoryRegionOps ehci_mmio_port_ops = {
    .read = ehci_port_read,
    .write = ehci_port_write,
    .valid.min_access_size = 4,
    .valid.max_access_size = 4,
A
Avi Kivity 已提交
2401
    .endianness = DEVICE_LITTLE_ENDIAN,
G
Gerd Hoffmann 已提交
2402 2403 2404 2405 2406
};

static USBPortOps ehci_port_ops = {
    .attach = ehci_attach,
    .detach = ehci_detach,
2407
    .child_detach = ehci_child_detach,
2408
    .wakeup = ehci_wakeup,
G
Gerd Hoffmann 已提交
2409 2410 2411
    .complete = ehci_async_complete_packet,
};

2412
static USBBusOps ehci_bus_ops = {
2413
    .register_companion = ehci_register_companion,
2414
    .wakeup_endpoint = ehci_wakeup_endpoint,
2415 2416
};

2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
static void usb_ehci_pre_save(void *opaque)
{
    EHCIState *ehci = opaque;
    uint32_t new_frindex;

    /* Round down frindex to a multiple of 8 for migration compatibility */
    new_frindex = ehci->frindex & ~7;
    ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS;
    ehci->frindex = new_frindex;
}

G
Gerd Hoffmann 已提交
2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447
static int usb_ehci_post_load(void *opaque, int version_id)
{
    EHCIState *s = opaque;
    int i;

    for (i = 0; i < NB_PORTS; i++) {
        USBPort *companion = s->companion_ports[i];
        if (companion == NULL) {
            continue;
        }
        if (s->portsc[i] & PORTSC_POWNER) {
            companion->dev = s->ports[i].dev;
        } else {
            companion->dev = NULL;
        }
    }

    return 0;
}

2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473
static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
{
    EHCIState *ehci = opaque;

    /*
     * We don't migrate the EHCIQueue-s, instead we rebuild them for the
     * schedule in guest memory. We must do the rebuilt ASAP, so that
     * USB-devices which have async handled packages have a packet in the
     * ep queue to match the completion with.
     */
    if (state == RUN_STATE_RUNNING) {
        ehci_advance_async_state(ehci);
    }

    /*
     * The schedule rebuilt from guest memory could cause the migration dest
     * to miss a QH unlink, and fail to cancel packets, since the unlinked QH
     * will never have existed on the destination. Therefor we must flush the
     * async schedule on savevm to catch any not yet noticed unlinks.
     */
    if (state == RUN_STATE_SAVE_VM) {
        ehci_advance_async_state(ehci);
        ehci_queues_rip_unseen(ehci, 1);
    }
}

2474
const VMStateDescription vmstate_ehci = {
P
Peter Crosthwaite 已提交
2475
    .name        = "ehci-core",
2476 2477
    .version_id  = 2,
    .minimum_version_id  = 1,
2478
    .pre_save    = usb_ehci_pre_save,
G
Gerd Hoffmann 已提交
2479 2480 2481 2482 2483
    .post_load   = usb_ehci_post_load,
    .fields      = (VMStateField[]) {
        /* mmio registers */
        VMSTATE_UINT32(usbcmd, EHCIState),
        VMSTATE_UINT32(usbsts, EHCIState),
2484 2485
        VMSTATE_UINT32_V(usbsts_pending, EHCIState, 2),
        VMSTATE_UINT32_V(usbsts_frindex, EHCIState, 2),
G
Gerd Hoffmann 已提交
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508
        VMSTATE_UINT32(usbintr, EHCIState),
        VMSTATE_UINT32(frindex, EHCIState),
        VMSTATE_UINT32(ctrldssegment, EHCIState),
        VMSTATE_UINT32(periodiclistbase, EHCIState),
        VMSTATE_UINT32(asynclistaddr, EHCIState),
        VMSTATE_UINT32(configflag, EHCIState),
        VMSTATE_UINT32(portsc[0], EHCIState),
        VMSTATE_UINT32(portsc[1], EHCIState),
        VMSTATE_UINT32(portsc[2], EHCIState),
        VMSTATE_UINT32(portsc[3], EHCIState),
        VMSTATE_UINT32(portsc[4], EHCIState),
        VMSTATE_UINT32(portsc[5], EHCIState),
        /* frame timer */
        VMSTATE_TIMER(frame_timer, EHCIState),
        VMSTATE_UINT64(last_run_ns, EHCIState),
        VMSTATE_UINT32(async_stepdown, EHCIState),
        /* schedule state */
        VMSTATE_UINT32(astate, EHCIState),
        VMSTATE_UINT32(pstate, EHCIState),
        VMSTATE_UINT32(a_fetch_addr, EHCIState),
        VMSTATE_UINT32(p_fetch_addr, EHCIState),
        VMSTATE_END_OF_LIST()
    }
G
Gerd Hoffmann 已提交
2509 2510
};

2511
void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
G
Gerd Hoffmann 已提交
2512 2513 2514
{
    int i;

2515
    /* 2.2 host controller interface version */
2516
    s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
2517 2518 2519 2520 2521 2522 2523 2524 2525 2526
    s->caps[0x01] = 0x00;
    s->caps[0x02] = 0x00;
    s->caps[0x03] = 0x01;        /* HC version */
    s->caps[0x04] = NB_PORTS;    /* Number of downstream ports */
    s->caps[0x05] = 0x00;        /* No companion ports at present */
    s->caps[0x06] = 0x00;
    s->caps[0x07] = 0x00;
    s->caps[0x08] = 0x80;        /* We can cache whole frame, no 64-bit */
    s->caps[0x0a] = 0x00;
    s->caps[0x0b] = 0x00;
G
Gerd Hoffmann 已提交
2527

P
Peter Crosthwaite 已提交
2528
    usb_bus_new(&s->bus, &ehci_bus_ops, dev);
G
Gerd Hoffmann 已提交
2529 2530 2531 2532 2533 2534 2535
    for(i = 0; i < NB_PORTS; i++) {
        usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
                          USB_SPEED_MASK_HIGH);
        s->ports[i].dev = 0;
    }

    s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
2536
    s->async_bh = qemu_bh_new(ehci_frame_timer, s);
2537 2538
    QTAILQ_INIT(&s->aqueues);
    QTAILQ_INIT(&s->pqueues);
2539
    usb_packet_init(&s->ipacket);
G
Gerd Hoffmann 已提交
2540 2541

    qemu_register_reset(ehci_reset, s);
2542
    qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
G
Gerd Hoffmann 已提交
2543

2544 2545
    memory_region_init(&s->mem, "ehci", MMIO_SIZE);
    memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
2546
                          "capabilities", CAPA_SIZE);
2547
    memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
2548
                          "operational", PORTSC_BEGIN);
2549 2550 2551
    memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s,
                          "ports", PORTSC_END - PORTSC_BEGIN);

2552 2553 2554 2555
    memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps);
    memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
    memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN,
                                &s->mem_ports);
P
Peter Crosthwaite 已提交
2556 2557
}

G
Gerd Hoffmann 已提交
2558 2559 2560
/*
 * vim: expandtab ts=4
 */