1f1ae32a1SGerd Hoffmann /*
2f1ae32a1SGerd Hoffmann * USB UHCI controller emulation
3f1ae32a1SGerd Hoffmann *
4f1ae32a1SGerd Hoffmann * Copyright (c) 2005 Fabrice Bellard
5f1ae32a1SGerd Hoffmann *
6f1ae32a1SGerd Hoffmann * Copyright (c) 2008 Max Krasnyansky
7f1ae32a1SGerd Hoffmann * Magor rewrite of the UHCI data structures parser and frame processor
8f1ae32a1SGerd Hoffmann * Support for fully async operation and multiple outstanding transactions
9f1ae32a1SGerd Hoffmann *
10f1ae32a1SGerd Hoffmann * Permission is hereby granted, free of charge, to any person obtaining a copy
11f1ae32a1SGerd Hoffmann * of this software and associated documentation files (the "Software"), to deal
12f1ae32a1SGerd Hoffmann * in the Software without restriction, including without limitation the rights
13f1ae32a1SGerd Hoffmann * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14f1ae32a1SGerd Hoffmann * copies of the Software, and to permit persons to whom the Software is
15f1ae32a1SGerd Hoffmann * furnished to do so, subject to the following conditions:
16f1ae32a1SGerd Hoffmann *
17f1ae32a1SGerd Hoffmann * The above copyright notice and this permission notice shall be included in
18f1ae32a1SGerd Hoffmann * all copies or substantial portions of the Software.
19f1ae32a1SGerd Hoffmann *
20f1ae32a1SGerd Hoffmann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21f1ae32a1SGerd Hoffmann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22f1ae32a1SGerd Hoffmann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23f1ae32a1SGerd Hoffmann * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24f1ae32a1SGerd Hoffmann * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25f1ae32a1SGerd Hoffmann * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26f1ae32a1SGerd Hoffmann * THE SOFTWARE.
27f1ae32a1SGerd Hoffmann */
280b8fa32fSMarkus Armbruster
29e532b2e0SPeter Maydell #include "qemu/osdep.h"
30f1ae32a1SGerd Hoffmann #include "hw/usb.h"
319a1d111eSGerd Hoffmann #include "hw/usb/uhci-regs.h"
32d6454270SMarkus Armbruster #include "migration/vmstate.h"
33e4f5b939SBALATON Zoltan #include "hw/irq.h"
34a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
35da34e65cSMarkus Armbruster #include "qapi/error.h"
361de7afc9SPaolo Bonzini #include "qemu/timer.h"
371de7afc9SPaolo Bonzini #include "qemu/iov.h"
389c17d615SPaolo Bonzini #include "sysemu/dma.h"
3950dcc0f8SGerd Hoffmann #include "trace.h"
406a1751b7SAlex Bligh #include "qemu/main-loop.h"
410b8fa32fSMarkus Armbruster #include "qemu/module.h"
42db1015e9SEduardo Habkost #include "qom/object.h"
439a4e12a6SPhilippe Mathieu-Daudé #include "hcd-uhci.h"
44f1ae32a1SGerd Hoffmann
45f1ae32a1SGerd Hoffmann #define FRAME_TIMER_FREQ 1000
46f1ae32a1SGerd Hoffmann
47f1ae32a1SGerd Hoffmann #define FRAME_MAX_LOOPS 256
48f1ae32a1SGerd Hoffmann
49475443cfSHans de Goede /* Must be large enough to handle 10 frame delay for initial isoc requests */
50475443cfSHans de Goede #define QH_VALID 32
51475443cfSHans de Goede
52f8f48b69SHans de Goede #define MAX_FRAMES_PER_TICK (QH_VALID / 2)
53f8f48b69SHans de Goede
5460e1b2a6SGerd Hoffmann enum {
550cd178caSGerd Hoffmann TD_RESULT_STOP_FRAME = 10,
560cd178caSGerd Hoffmann TD_RESULT_COMPLETE,
570cd178caSGerd Hoffmann TD_RESULT_NEXT_QH,
584efe4ef3SGerd Hoffmann TD_RESULT_ASYNC_START,
594efe4ef3SGerd Hoffmann TD_RESULT_ASYNC_CONT,
6060e1b2a6SGerd Hoffmann };
6160e1b2a6SGerd Hoffmann
62f1ae32a1SGerd Hoffmann typedef struct UHCIAsync UHCIAsync;
632c2e8525SGerd Hoffmann
64f1ae32a1SGerd Hoffmann /*
65f1ae32a1SGerd Hoffmann * Pending async transaction.
66f1ae32a1SGerd Hoffmann * 'packet' must be the first field because completion
67f1ae32a1SGerd Hoffmann * handler does "(UHCIAsync *) pkt" cast.
68f1ae32a1SGerd Hoffmann */
69f1ae32a1SGerd Hoffmann
70f1ae32a1SGerd Hoffmann struct UHCIAsync {
71f1ae32a1SGerd Hoffmann USBPacket packet;
729822261cSHans de Goede uint8_t static_buf[64]; /* 64 bytes is enough, except for isoc packets */
739822261cSHans de Goede uint8_t *buf;
74f1ae32a1SGerd Hoffmann UHCIQueue *queue;
75f1ae32a1SGerd Hoffmann QTAILQ_ENTRY(UHCIAsync) next;
761f250cc7SHans de Goede uint32_t td_addr;
77f1ae32a1SGerd Hoffmann uint8_t done;
78f1ae32a1SGerd Hoffmann };
79f1ae32a1SGerd Hoffmann
80f1ae32a1SGerd Hoffmann struct UHCIQueue {
8166a08cbeSHans de Goede uint32_t qh_addr;
82f1ae32a1SGerd Hoffmann uint32_t token;
83f1ae32a1SGerd Hoffmann UHCIState *uhci;
8411d15e40SHans de Goede USBEndpoint *ep;
85f1ae32a1SGerd Hoffmann QTAILQ_ENTRY(UHCIQueue) next;
86eae3eb3eSPaolo Bonzini QTAILQ_HEAD(, UHCIAsync) asyncs;
87f1ae32a1SGerd Hoffmann int8_t valid;
88f1ae32a1SGerd Hoffmann };
89f1ae32a1SGerd Hoffmann
90f1ae32a1SGerd Hoffmann typedef struct UHCI_TD {
91f1ae32a1SGerd Hoffmann uint32_t link;
92f1ae32a1SGerd Hoffmann uint32_t ctrl; /* see TD_CTRL_xxx */
93f1ae32a1SGerd Hoffmann uint32_t token;
94f1ae32a1SGerd Hoffmann uint32_t buffer;
95f1ae32a1SGerd Hoffmann } UHCI_TD;
96f1ae32a1SGerd Hoffmann
97f1ae32a1SGerd Hoffmann typedef struct UHCI_QH {
98f1ae32a1SGerd Hoffmann uint32_t link;
99f1ae32a1SGerd Hoffmann uint32_t el_link;
100f1ae32a1SGerd Hoffmann } UHCI_QH;
101f1ae32a1SGerd Hoffmann
10240507377SHans de Goede static void uhci_async_cancel(UHCIAsync *async);
10311d15e40SHans de Goede static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td);
1049f0f1a0cSGerd Hoffmann static void uhci_resume(void *opaque);
10540507377SHans de Goede
uhci_queue_token(UHCI_TD * td)106f1ae32a1SGerd Hoffmann static inline int32_t uhci_queue_token(UHCI_TD *td)
107f1ae32a1SGerd Hoffmann {
1086fe30910SHans de Goede if ((td->token & (0xf << 15)) == 0) {
1096fe30910SHans de Goede /* ctrl ep, cover ep and dev, not pid! */
1106fe30910SHans de Goede return td->token & 0x7ff00;
1116fe30910SHans de Goede } else {
112f1ae32a1SGerd Hoffmann /* covers ep, dev, pid -> identifies the endpoint */
113f1ae32a1SGerd Hoffmann return td->token & 0x7ffff;
114f1ae32a1SGerd Hoffmann }
1156fe30910SHans de Goede }
116f1ae32a1SGerd Hoffmann
uhci_queue_new(UHCIState * s,uint32_t qh_addr,UHCI_TD * td,USBEndpoint * ep)11766a08cbeSHans de Goede static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td,
11866a08cbeSHans de Goede USBEndpoint *ep)
119f1ae32a1SGerd Hoffmann {
120f1ae32a1SGerd Hoffmann UHCIQueue *queue;
121f1ae32a1SGerd Hoffmann
122f1ae32a1SGerd Hoffmann queue = g_new0(UHCIQueue, 1);
123f1ae32a1SGerd Hoffmann queue->uhci = s;
12466a08cbeSHans de Goede queue->qh_addr = qh_addr;
12566a08cbeSHans de Goede queue->token = uhci_queue_token(td);
12611d15e40SHans de Goede queue->ep = ep;
127f1ae32a1SGerd Hoffmann QTAILQ_INIT(&queue->asyncs);
128f1ae32a1SGerd Hoffmann QTAILQ_INSERT_HEAD(&s->queues, queue, next);
129475443cfSHans de Goede queue->valid = QH_VALID;
13050dcc0f8SGerd Hoffmann trace_usb_uhci_queue_add(queue->token);
131f1ae32a1SGerd Hoffmann return queue;
132f1ae32a1SGerd Hoffmann }
133f1ae32a1SGerd Hoffmann
uhci_queue_free(UHCIQueue * queue,const char * reason)13466a08cbeSHans de Goede static void uhci_queue_free(UHCIQueue *queue, const char *reason)
135f1ae32a1SGerd Hoffmann {
136f1ae32a1SGerd Hoffmann UHCIState *s = queue->uhci;
13740507377SHans de Goede UHCIAsync *async;
13840507377SHans de Goede
13940507377SHans de Goede while (!QTAILQ_EMPTY(&queue->asyncs)) {
14040507377SHans de Goede async = QTAILQ_FIRST(&queue->asyncs);
14140507377SHans de Goede uhci_async_cancel(async);
14240507377SHans de Goede }
143f79738b0SHans de Goede usb_device_ep_stopped(queue->ep->dev, queue->ep);
144f1ae32a1SGerd Hoffmann
14566a08cbeSHans de Goede trace_usb_uhci_queue_del(queue->token, reason);
146f1ae32a1SGerd Hoffmann QTAILQ_REMOVE(&s->queues, queue, next);
147f1ae32a1SGerd Hoffmann g_free(queue);
148f1ae32a1SGerd Hoffmann }
149f1ae32a1SGerd Hoffmann
uhci_queue_find(UHCIState * s,UHCI_TD * td)15066a08cbeSHans de Goede static UHCIQueue *uhci_queue_find(UHCIState *s, UHCI_TD *td)
15166a08cbeSHans de Goede {
15266a08cbeSHans de Goede uint32_t token = uhci_queue_token(td);
15366a08cbeSHans de Goede UHCIQueue *queue;
15466a08cbeSHans de Goede
15566a08cbeSHans de Goede QTAILQ_FOREACH(queue, &s->queues, next) {
15666a08cbeSHans de Goede if (queue->token == token) {
15766a08cbeSHans de Goede return queue;
15866a08cbeSHans de Goede }
15966a08cbeSHans de Goede }
16066a08cbeSHans de Goede return NULL;
16166a08cbeSHans de Goede }
16266a08cbeSHans de Goede
uhci_queue_verify(UHCIQueue * queue,uint32_t qh_addr,UHCI_TD * td,uint32_t td_addr,bool queuing)16366a08cbeSHans de Goede static bool uhci_queue_verify(UHCIQueue *queue, uint32_t qh_addr, UHCI_TD *td,
16466a08cbeSHans de Goede uint32_t td_addr, bool queuing)
16566a08cbeSHans de Goede {
16666a08cbeSHans de Goede UHCIAsync *first = QTAILQ_FIRST(&queue->asyncs);
167c348e481SGerd Hoffmann uint32_t queue_token_addr = (queue->token >> 8) & 0x7f;
16866a08cbeSHans de Goede
16966a08cbeSHans de Goede return queue->qh_addr == qh_addr &&
17066a08cbeSHans de Goede queue->token == uhci_queue_token(td) &&
171c348e481SGerd Hoffmann queue_token_addr == queue->ep->dev->addr &&
17266a08cbeSHans de Goede (queuing || !(td->ctrl & TD_CTRL_ACTIVE) || first == NULL ||
17366a08cbeSHans de Goede first->td_addr == td_addr);
17466a08cbeSHans de Goede }
17566a08cbeSHans de Goede
uhci_async_alloc(UHCIQueue * queue,uint32_t td_addr)1761f250cc7SHans de Goede static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr)
177f1ae32a1SGerd Hoffmann {
178f1ae32a1SGerd Hoffmann UHCIAsync *async = g_new0(UHCIAsync, 1);
179f1ae32a1SGerd Hoffmann
180f1ae32a1SGerd Hoffmann async->queue = queue;
1811f250cc7SHans de Goede async->td_addr = td_addr;
182f1ae32a1SGerd Hoffmann usb_packet_init(&async->packet);
1831f250cc7SHans de Goede trace_usb_uhci_packet_add(async->queue->token, async->td_addr);
184f1ae32a1SGerd Hoffmann
185f1ae32a1SGerd Hoffmann return async;
186f1ae32a1SGerd Hoffmann }
187f1ae32a1SGerd Hoffmann
uhci_async_free(UHCIAsync * async)188f1ae32a1SGerd Hoffmann static void uhci_async_free(UHCIAsync *async)
189f1ae32a1SGerd Hoffmann {
1901f250cc7SHans de Goede trace_usb_uhci_packet_del(async->queue->token, async->td_addr);
191f1ae32a1SGerd Hoffmann usb_packet_cleanup(&async->packet);
1929822261cSHans de Goede if (async->buf != async->static_buf) {
1939822261cSHans de Goede g_free(async->buf);
1949822261cSHans de Goede }
195f1ae32a1SGerd Hoffmann g_free(async);
196f1ae32a1SGerd Hoffmann }
197f1ae32a1SGerd Hoffmann
uhci_async_link(UHCIAsync * async)198f1ae32a1SGerd Hoffmann static void uhci_async_link(UHCIAsync *async)
199f1ae32a1SGerd Hoffmann {
200f1ae32a1SGerd Hoffmann UHCIQueue *queue = async->queue;
201f1ae32a1SGerd Hoffmann QTAILQ_INSERT_TAIL(&queue->asyncs, async, next);
2021f250cc7SHans de Goede trace_usb_uhci_packet_link_async(async->queue->token, async->td_addr);
203f1ae32a1SGerd Hoffmann }
204f1ae32a1SGerd Hoffmann
uhci_async_unlink(UHCIAsync * async)205f1ae32a1SGerd Hoffmann static void uhci_async_unlink(UHCIAsync *async)
206f1ae32a1SGerd Hoffmann {
207f1ae32a1SGerd Hoffmann UHCIQueue *queue = async->queue;
208f1ae32a1SGerd Hoffmann QTAILQ_REMOVE(&queue->asyncs, async, next);
2091f250cc7SHans de Goede trace_usb_uhci_packet_unlink_async(async->queue->token, async->td_addr);
210f1ae32a1SGerd Hoffmann }
211f1ae32a1SGerd Hoffmann
uhci_async_cancel(UHCIAsync * async)212f1ae32a1SGerd Hoffmann static void uhci_async_cancel(UHCIAsync *async)
213f1ae32a1SGerd Hoffmann {
2142f2ee268SHans de Goede uhci_async_unlink(async);
2151f250cc7SHans de Goede trace_usb_uhci_packet_cancel(async->queue->token, async->td_addr,
2161f250cc7SHans de Goede async->done);
217fc83c4c9SGuenter Roeck if (!async->done) {
218f1ae32a1SGerd Hoffmann usb_cancel_packet(&async->packet);
219fc83c4c9SGuenter Roeck }
220f1ae32a1SGerd Hoffmann uhci_async_free(async);
221f1ae32a1SGerd Hoffmann }
222f1ae32a1SGerd Hoffmann
223f1ae32a1SGerd Hoffmann /*
224f1ae32a1SGerd Hoffmann * Mark all outstanding async packets as invalid.
225f1ae32a1SGerd Hoffmann * This is used for canceling them when TDs are removed by the HCD.
226f1ae32a1SGerd Hoffmann */
uhci_async_validate_begin(UHCIState * s)227f1ae32a1SGerd Hoffmann static void uhci_async_validate_begin(UHCIState *s)
228f1ae32a1SGerd Hoffmann {
229f1ae32a1SGerd Hoffmann UHCIQueue *queue;
230f1ae32a1SGerd Hoffmann
231f1ae32a1SGerd Hoffmann QTAILQ_FOREACH(queue, &s->queues, next) {
232f1ae32a1SGerd Hoffmann queue->valid--;
233f1ae32a1SGerd Hoffmann }
234f1ae32a1SGerd Hoffmann }
235f1ae32a1SGerd Hoffmann
236f1ae32a1SGerd Hoffmann /*
237f1ae32a1SGerd Hoffmann * Cancel async packets that are no longer valid
238f1ae32a1SGerd Hoffmann */
uhci_async_validate_end(UHCIState * s)239f1ae32a1SGerd Hoffmann static void uhci_async_validate_end(UHCIState *s)
240f1ae32a1SGerd Hoffmann {
241f1ae32a1SGerd Hoffmann UHCIQueue *queue, *n;
242f1ae32a1SGerd Hoffmann
243f1ae32a1SGerd Hoffmann QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
24440507377SHans de Goede if (!queue->valid) {
24566a08cbeSHans de Goede uhci_queue_free(queue, "validate-end");
246f1ae32a1SGerd Hoffmann }
247f1ae32a1SGerd Hoffmann }
24840507377SHans de Goede }
249f1ae32a1SGerd Hoffmann
uhci_async_cancel_device(UHCIState * s,USBDevice * dev)250f1ae32a1SGerd Hoffmann static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
251f1ae32a1SGerd Hoffmann {
2525ad23e87SHans de Goede UHCIQueue *queue, *n;
253f1ae32a1SGerd Hoffmann
2545ad23e87SHans de Goede QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
2555ad23e87SHans de Goede if (queue->ep->dev == dev) {
2565ad23e87SHans de Goede uhci_queue_free(queue, "cancel-device");
257f1ae32a1SGerd Hoffmann }
258f1ae32a1SGerd Hoffmann }
259f1ae32a1SGerd Hoffmann }
260f1ae32a1SGerd Hoffmann
uhci_async_cancel_all(UHCIState * s)261f1ae32a1SGerd Hoffmann static void uhci_async_cancel_all(UHCIState *s)
262f1ae32a1SGerd Hoffmann {
26377fa9aeeSGerd Hoffmann UHCIQueue *queue, *nq;
264f1ae32a1SGerd Hoffmann
26577fa9aeeSGerd Hoffmann QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
26666a08cbeSHans de Goede uhci_queue_free(queue, "cancel-all");
267f1ae32a1SGerd Hoffmann }
268f1ae32a1SGerd Hoffmann }
269f1ae32a1SGerd Hoffmann
uhci_async_find_td(UHCIState * s,uint32_t td_addr)2708c75a899SHans de Goede static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t td_addr)
271f1ae32a1SGerd Hoffmann {
272f1ae32a1SGerd Hoffmann UHCIQueue *queue;
273f1ae32a1SGerd Hoffmann UHCIAsync *async;
274f1ae32a1SGerd Hoffmann
275f1ae32a1SGerd Hoffmann QTAILQ_FOREACH(queue, &s->queues, next) {
276f1ae32a1SGerd Hoffmann QTAILQ_FOREACH(async, &queue->asyncs, next) {
2771f250cc7SHans de Goede if (async->td_addr == td_addr) {
278f1ae32a1SGerd Hoffmann return async;
279f1ae32a1SGerd Hoffmann }
280f1ae32a1SGerd Hoffmann }
2818c75a899SHans de Goede }
282f1ae32a1SGerd Hoffmann return NULL;
283f1ae32a1SGerd Hoffmann }
284f1ae32a1SGerd Hoffmann
uhci_update_irq(UHCIState * s)285f1ae32a1SGerd Hoffmann static void uhci_update_irq(UHCIState *s)
286f1ae32a1SGerd Hoffmann {
287d3647ef1SBALATON Zoltan int level = 0;
288f1ae32a1SGerd Hoffmann if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
289f1ae32a1SGerd Hoffmann ((s->status2 & 2) && (s->intr & (1 << 3))) ||
290f1ae32a1SGerd Hoffmann ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
291f1ae32a1SGerd Hoffmann ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
292f1ae32a1SGerd Hoffmann (s->status & UHCI_STS_HSERR) ||
293f1ae32a1SGerd Hoffmann (s->status & UHCI_STS_HCPERR)) {
294f1ae32a1SGerd Hoffmann level = 1;
295f1ae32a1SGerd Hoffmann }
296e4f5b939SBALATON Zoltan qemu_set_irq(s->irq, level);
297f1ae32a1SGerd Hoffmann }
298f1ae32a1SGerd Hoffmann
uhci_state_reset(UHCIState * s)29927af7e00SGuenter Roeck void uhci_state_reset(UHCIState *s)
300f1ae32a1SGerd Hoffmann {
301f1ae32a1SGerd Hoffmann int i;
302f1ae32a1SGerd Hoffmann UHCIPort *port;
303f1ae32a1SGerd Hoffmann
30450dcc0f8SGerd Hoffmann trace_usb_uhci_reset();
305f1ae32a1SGerd Hoffmann
306f1ae32a1SGerd Hoffmann s->cmd = 0;
307ca5a21c4SGerd Hoffmann s->status = UHCI_STS_HCHALTED;
308f1ae32a1SGerd Hoffmann s->status2 = 0;
309f1ae32a1SGerd Hoffmann s->intr = 0;
310f1ae32a1SGerd Hoffmann s->fl_base_addr = 0;
311f1ae32a1SGerd Hoffmann s->sof_timing = 64;
312f1ae32a1SGerd Hoffmann
313fe693e32SPhilippe Mathieu-Daudé for (i = 0; i < UHCI_PORTS; i++) {
314f1ae32a1SGerd Hoffmann port = &s->ports[i];
315f1ae32a1SGerd Hoffmann port->ctrl = 0x0080;
316f1ae32a1SGerd Hoffmann if (port->port.dev && port->port.dev->attached) {
317f1ae32a1SGerd Hoffmann usb_port_reset(&port->port);
318f1ae32a1SGerd Hoffmann }
319f1ae32a1SGerd Hoffmann }
320f1ae32a1SGerd Hoffmann
321f1ae32a1SGerd Hoffmann uhci_async_cancel_all(s);
3229a16c595SGerd Hoffmann qemu_bh_cancel(s->bh);
323aba1f242SGerd Hoffmann uhci_update_irq(s);
324f1ae32a1SGerd Hoffmann }
325f1ae32a1SGerd Hoffmann
uhci_reset(UHCIState * s)32627af7e00SGuenter Roeck static void uhci_reset(UHCIState *s)
32727af7e00SGuenter Roeck {
32827af7e00SGuenter Roeck s->uhci_reset(s);
32927af7e00SGuenter Roeck }
33027af7e00SGuenter Roeck
331f1ae32a1SGerd Hoffmann static const VMStateDescription vmstate_uhci_port = {
332f1ae32a1SGerd Hoffmann .name = "uhci port",
333f1ae32a1SGerd Hoffmann .version_id = 1,
334f1ae32a1SGerd Hoffmann .minimum_version_id = 1,
3353abedf29SRichard Henderson .fields = (const VMStateField[]) {
336f1ae32a1SGerd Hoffmann VMSTATE_UINT16(ctrl, UHCIPort),
337f1ae32a1SGerd Hoffmann VMSTATE_END_OF_LIST()
338f1ae32a1SGerd Hoffmann }
339f1ae32a1SGerd Hoffmann };
340f1ae32a1SGerd Hoffmann
uhci_post_load(void * opaque,int version_id)34175f151cdSGerd Hoffmann static int uhci_post_load(void *opaque, int version_id)
34275f151cdSGerd Hoffmann {
34375f151cdSGerd Hoffmann UHCIState *s = opaque;
34475f151cdSGerd Hoffmann
34575f151cdSGerd Hoffmann if (version_id < 2) {
346bc72ad67SAlex Bligh s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
34773bcb24dSRutuja Shah (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ);
34875f151cdSGerd Hoffmann }
34975f151cdSGerd Hoffmann return 0;
35075f151cdSGerd Hoffmann }
35175f151cdSGerd Hoffmann
35227af7e00SGuenter Roeck const VMStateDescription vmstate_uhci_state = {
353f1ae32a1SGerd Hoffmann .name = "uhci",
35427af7e00SGuenter Roeck .version_id = 4,
355f1ae32a1SGerd Hoffmann .minimum_version_id = 1,
35675f151cdSGerd Hoffmann .post_load = uhci_post_load,
3573abedf29SRichard Henderson .fields = (const VMStateField[]) {
358d2164ad3SHalil Pasic VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState, NULL),
359fe693e32SPhilippe Mathieu-Daudé VMSTATE_STRUCT_ARRAY(ports, UHCIState, UHCI_PORTS, 1,
360f1ae32a1SGerd Hoffmann vmstate_uhci_port, UHCIPort),
361f1ae32a1SGerd Hoffmann VMSTATE_UINT16(cmd, UHCIState),
362f1ae32a1SGerd Hoffmann VMSTATE_UINT16(status, UHCIState),
363f1ae32a1SGerd Hoffmann VMSTATE_UINT16(intr, UHCIState),
364f1ae32a1SGerd Hoffmann VMSTATE_UINT16(frnum, UHCIState),
365f1ae32a1SGerd Hoffmann VMSTATE_UINT32(fl_base_addr, UHCIState),
366f1ae32a1SGerd Hoffmann VMSTATE_UINT8(sof_timing, UHCIState),
367f1ae32a1SGerd Hoffmann VMSTATE_UINT8(status2, UHCIState),
368e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(frame_timer, UHCIState),
369f1ae32a1SGerd Hoffmann VMSTATE_INT64_V(expire_time, UHCIState, 2),
370ecfdc15fSHans de Goede VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3),
371f1ae32a1SGerd Hoffmann VMSTATE_END_OF_LIST()
372f1ae32a1SGerd Hoffmann }
373f1ae32a1SGerd Hoffmann };
374f1ae32a1SGerd Hoffmann
uhci_port_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)37589eb147cSGerd Hoffmann static void uhci_port_write(void *opaque, hwaddr addr,
37689eb147cSGerd Hoffmann uint64_t val, unsigned size)
377f1ae32a1SGerd Hoffmann {
378f1ae32a1SGerd Hoffmann UHCIState *s = opaque;
379f1ae32a1SGerd Hoffmann
38050dcc0f8SGerd Hoffmann trace_usb_uhci_mmio_writew(addr, val);
381f1ae32a1SGerd Hoffmann
382f1ae32a1SGerd Hoffmann switch (addr) {
3831acf0e50SGuenter Roeck case UHCI_USBCMD:
384f1ae32a1SGerd Hoffmann if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
385f1ae32a1SGerd Hoffmann /* start frame processing */
38650dcc0f8SGerd Hoffmann trace_usb_uhci_schedule_start();
387bc72ad67SAlex Bligh s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
38873bcb24dSRutuja Shah (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ);
389bc72ad67SAlex Bligh timer_mod(s->frame_timer, s->expire_time);
390f1ae32a1SGerd Hoffmann s->status &= ~UHCI_STS_HCHALTED;
391f1ae32a1SGerd Hoffmann } else if (!(val & UHCI_CMD_RS)) {
392f1ae32a1SGerd Hoffmann s->status |= UHCI_STS_HCHALTED;
393f1ae32a1SGerd Hoffmann }
394f1ae32a1SGerd Hoffmann if (val & UHCI_CMD_GRESET) {
395f1ae32a1SGerd Hoffmann UHCIPort *port;
396f1ae32a1SGerd Hoffmann int i;
397f1ae32a1SGerd Hoffmann
398f1ae32a1SGerd Hoffmann /* send reset on the USB bus */
399fe693e32SPhilippe Mathieu-Daudé for (i = 0; i < UHCI_PORTS; i++) {
400f1ae32a1SGerd Hoffmann port = &s->ports[i];
401f1ae32a1SGerd Hoffmann usb_device_reset(port->port.dev);
402f1ae32a1SGerd Hoffmann }
40327af7e00SGuenter Roeck uhci_reset(s);
404f1ae32a1SGerd Hoffmann return;
405f1ae32a1SGerd Hoffmann }
406f1ae32a1SGerd Hoffmann if (val & UHCI_CMD_HCRESET) {
40727af7e00SGuenter Roeck uhci_reset(s);
408f1ae32a1SGerd Hoffmann return;
409f1ae32a1SGerd Hoffmann }
410f1ae32a1SGerd Hoffmann s->cmd = val;
4119f0f1a0cSGerd Hoffmann if (val & UHCI_CMD_EGSM) {
4129f0f1a0cSGerd Hoffmann if ((s->ports[0].ctrl & UHCI_PORT_RD) ||
4139f0f1a0cSGerd Hoffmann (s->ports[1].ctrl & UHCI_PORT_RD)) {
4149f0f1a0cSGerd Hoffmann uhci_resume(s);
4159f0f1a0cSGerd Hoffmann }
4169f0f1a0cSGerd Hoffmann }
417f1ae32a1SGerd Hoffmann break;
4181acf0e50SGuenter Roeck case UHCI_USBSTS:
419f1ae32a1SGerd Hoffmann s->status &= ~val;
420fc83c4c9SGuenter Roeck /*
421fc83c4c9SGuenter Roeck * XXX: the chip spec is not coherent, so we add a hidden
422fc83c4c9SGuenter Roeck * register to distinguish between IOC and SPD
423fc83c4c9SGuenter Roeck */
424fc83c4c9SGuenter Roeck if (val & UHCI_STS_USBINT) {
425f1ae32a1SGerd Hoffmann s->status2 = 0;
426fc83c4c9SGuenter Roeck }
427f1ae32a1SGerd Hoffmann uhci_update_irq(s);
428f1ae32a1SGerd Hoffmann break;
4291acf0e50SGuenter Roeck case UHCI_USBINTR:
430f1ae32a1SGerd Hoffmann s->intr = val;
431f1ae32a1SGerd Hoffmann uhci_update_irq(s);
432f1ae32a1SGerd Hoffmann break;
4331acf0e50SGuenter Roeck case UHCI_USBFRNUM:
434fc83c4c9SGuenter Roeck if (s->status & UHCI_STS_HCHALTED) {
435f1ae32a1SGerd Hoffmann s->frnum = val & 0x7ff;
436fc83c4c9SGuenter Roeck }
437f1ae32a1SGerd Hoffmann break;
4381acf0e50SGuenter Roeck case UHCI_USBFLBASEADD:
43989eb147cSGerd Hoffmann s->fl_base_addr &= 0xffff0000;
44089eb147cSGerd Hoffmann s->fl_base_addr |= val & ~0xfff;
44189eb147cSGerd Hoffmann break;
4421acf0e50SGuenter Roeck case UHCI_USBFLBASEADD + 2:
44389eb147cSGerd Hoffmann s->fl_base_addr &= 0x0000ffff;
44489eb147cSGerd Hoffmann s->fl_base_addr |= (val << 16);
44589eb147cSGerd Hoffmann break;
4461acf0e50SGuenter Roeck case UHCI_USBSOF:
44789eb147cSGerd Hoffmann s->sof_timing = val & 0xff;
44889eb147cSGerd Hoffmann break;
4491acf0e50SGuenter Roeck case UHCI_USBPORTSC1 ... UHCI_USBPORTSC4:
450f1ae32a1SGerd Hoffmann {
451f1ae32a1SGerd Hoffmann UHCIPort *port;
452f1ae32a1SGerd Hoffmann USBDevice *dev;
453f1ae32a1SGerd Hoffmann int n;
454f1ae32a1SGerd Hoffmann
455f1ae32a1SGerd Hoffmann n = (addr >> 1) & 7;
456fe693e32SPhilippe Mathieu-Daudé if (n >= UHCI_PORTS) {
457f1ae32a1SGerd Hoffmann return;
458455177ffSPhilippe Mathieu-Daudé }
459f1ae32a1SGerd Hoffmann port = &s->ports[n];
460f1ae32a1SGerd Hoffmann dev = port->port.dev;
461f1ae32a1SGerd Hoffmann if (dev && dev->attached) {
462f1ae32a1SGerd Hoffmann /* port reset */
463f1ae32a1SGerd Hoffmann if ((val & UHCI_PORT_RESET) &&
464f1ae32a1SGerd Hoffmann !(port->ctrl & UHCI_PORT_RESET)) {
465f1ae32a1SGerd Hoffmann usb_device_reset(dev);
466f1ae32a1SGerd Hoffmann }
467f1ae32a1SGerd Hoffmann }
468f1ae32a1SGerd Hoffmann port->ctrl &= UHCI_PORT_READ_ONLY;
4691cbdde90SHans de Goede /* enabled may only be set if a device is connected */
4701cbdde90SHans de Goede if (!(port->ctrl & UHCI_PORT_CCS)) {
4711cbdde90SHans de Goede val &= ~UHCI_PORT_EN;
4721cbdde90SHans de Goede }
473f1ae32a1SGerd Hoffmann port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
474f1ae32a1SGerd Hoffmann /* some bits are reset when a '1' is written to them */
475f1ae32a1SGerd Hoffmann port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
476f1ae32a1SGerd Hoffmann }
477f1ae32a1SGerd Hoffmann break;
478f1ae32a1SGerd Hoffmann }
479f1ae32a1SGerd Hoffmann }
480f1ae32a1SGerd Hoffmann
uhci_port_read(void * opaque,hwaddr addr,unsigned size)48189eb147cSGerd Hoffmann static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size)
482f1ae32a1SGerd Hoffmann {
483f1ae32a1SGerd Hoffmann UHCIState *s = opaque;
484f1ae32a1SGerd Hoffmann uint32_t val;
485f1ae32a1SGerd Hoffmann
486f1ae32a1SGerd Hoffmann switch (addr) {
4871acf0e50SGuenter Roeck case UHCI_USBCMD:
488f1ae32a1SGerd Hoffmann val = s->cmd;
489f1ae32a1SGerd Hoffmann break;
4901acf0e50SGuenter Roeck case UHCI_USBSTS:
491f1ae32a1SGerd Hoffmann val = s->status;
492f1ae32a1SGerd Hoffmann break;
4931acf0e50SGuenter Roeck case UHCI_USBINTR:
494f1ae32a1SGerd Hoffmann val = s->intr;
495f1ae32a1SGerd Hoffmann break;
4961acf0e50SGuenter Roeck case UHCI_USBFRNUM:
497f1ae32a1SGerd Hoffmann val = s->frnum;
498f1ae32a1SGerd Hoffmann break;
4991acf0e50SGuenter Roeck case UHCI_USBFLBASEADD:
50089eb147cSGerd Hoffmann val = s->fl_base_addr & 0xffff;
50189eb147cSGerd Hoffmann break;
5021acf0e50SGuenter Roeck case UHCI_USBFLBASEADD + 2:
50389eb147cSGerd Hoffmann val = (s->fl_base_addr >> 16) & 0xffff;
50489eb147cSGerd Hoffmann break;
5051acf0e50SGuenter Roeck case UHCI_USBSOF:
50689eb147cSGerd Hoffmann val = s->sof_timing;
50789eb147cSGerd Hoffmann break;
5081acf0e50SGuenter Roeck case UHCI_USBPORTSC1 ... UHCI_USBPORTSC4:
509f1ae32a1SGerd Hoffmann {
510f1ae32a1SGerd Hoffmann UHCIPort *port;
511f1ae32a1SGerd Hoffmann int n;
512f1ae32a1SGerd Hoffmann n = (addr >> 1) & 7;
513fe693e32SPhilippe Mathieu-Daudé if (n >= UHCI_PORTS) {
514f1ae32a1SGerd Hoffmann goto read_default;
515455177ffSPhilippe Mathieu-Daudé }
516f1ae32a1SGerd Hoffmann port = &s->ports[n];
517f1ae32a1SGerd Hoffmann val = port->ctrl;
518f1ae32a1SGerd Hoffmann }
519f1ae32a1SGerd Hoffmann break;
520f1ae32a1SGerd Hoffmann default:
521f1ae32a1SGerd Hoffmann read_default:
522f1ae32a1SGerd Hoffmann val = 0xff7f; /* disabled port */
523f1ae32a1SGerd Hoffmann break;
524f1ae32a1SGerd Hoffmann }
525f1ae32a1SGerd Hoffmann
52650dcc0f8SGerd Hoffmann trace_usb_uhci_mmio_readw(addr, val);
527f1ae32a1SGerd Hoffmann
528f1ae32a1SGerd Hoffmann return val;
529f1ae32a1SGerd Hoffmann }
530f1ae32a1SGerd Hoffmann
531f1ae32a1SGerd Hoffmann /* signal resume if controller suspended */
uhci_resume(void * opaque)532f1ae32a1SGerd Hoffmann static void uhci_resume(void *opaque)
533f1ae32a1SGerd Hoffmann {
534f1ae32a1SGerd Hoffmann UHCIState *s = (UHCIState *)opaque;
535f1ae32a1SGerd Hoffmann
536fc83c4c9SGuenter Roeck if (!s) {
537f1ae32a1SGerd Hoffmann return;
538fc83c4c9SGuenter Roeck }
539f1ae32a1SGerd Hoffmann
540f1ae32a1SGerd Hoffmann if (s->cmd & UHCI_CMD_EGSM) {
541f1ae32a1SGerd Hoffmann s->cmd |= UHCI_CMD_FGR;
542f1ae32a1SGerd Hoffmann s->status |= UHCI_STS_RD;
543f1ae32a1SGerd Hoffmann uhci_update_irq(s);
544f1ae32a1SGerd Hoffmann }
545f1ae32a1SGerd Hoffmann }
546f1ae32a1SGerd Hoffmann
uhci_attach(USBPort * port1)547f1ae32a1SGerd Hoffmann static void uhci_attach(USBPort *port1)
548f1ae32a1SGerd Hoffmann {
549f1ae32a1SGerd Hoffmann UHCIState *s = port1->opaque;
550f1ae32a1SGerd Hoffmann UHCIPort *port = &s->ports[port1->index];
551f1ae32a1SGerd Hoffmann
552f1ae32a1SGerd Hoffmann /* set connect status */
553f1ae32a1SGerd Hoffmann port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
554f1ae32a1SGerd Hoffmann
555f1ae32a1SGerd Hoffmann /* update speed */
556f1ae32a1SGerd Hoffmann if (port->port.dev->speed == USB_SPEED_LOW) {
557f1ae32a1SGerd Hoffmann port->ctrl |= UHCI_PORT_LSDA;
558f1ae32a1SGerd Hoffmann } else {
559f1ae32a1SGerd Hoffmann port->ctrl &= ~UHCI_PORT_LSDA;
560f1ae32a1SGerd Hoffmann }
561f1ae32a1SGerd Hoffmann
562f1ae32a1SGerd Hoffmann uhci_resume(s);
563f1ae32a1SGerd Hoffmann }
564f1ae32a1SGerd Hoffmann
uhci_detach(USBPort * port1)565f1ae32a1SGerd Hoffmann static void uhci_detach(USBPort *port1)
566f1ae32a1SGerd Hoffmann {
567f1ae32a1SGerd Hoffmann UHCIState *s = port1->opaque;
568f1ae32a1SGerd Hoffmann UHCIPort *port = &s->ports[port1->index];
569f1ae32a1SGerd Hoffmann
570f1ae32a1SGerd Hoffmann uhci_async_cancel_device(s, port1->dev);
571f1ae32a1SGerd Hoffmann
572f1ae32a1SGerd Hoffmann /* set connect status */
573f1ae32a1SGerd Hoffmann if (port->ctrl & UHCI_PORT_CCS) {
574f1ae32a1SGerd Hoffmann port->ctrl &= ~UHCI_PORT_CCS;
575f1ae32a1SGerd Hoffmann port->ctrl |= UHCI_PORT_CSC;
576f1ae32a1SGerd Hoffmann }
577f1ae32a1SGerd Hoffmann /* disable port */
578f1ae32a1SGerd Hoffmann if (port->ctrl & UHCI_PORT_EN) {
579f1ae32a1SGerd Hoffmann port->ctrl &= ~UHCI_PORT_EN;
580f1ae32a1SGerd Hoffmann port->ctrl |= UHCI_PORT_ENC;
581f1ae32a1SGerd Hoffmann }
582f1ae32a1SGerd Hoffmann
583f1ae32a1SGerd Hoffmann uhci_resume(s);
584f1ae32a1SGerd Hoffmann }
585f1ae32a1SGerd Hoffmann
uhci_child_detach(USBPort * port1,USBDevice * child)586f1ae32a1SGerd Hoffmann static void uhci_child_detach(USBPort *port1, USBDevice *child)
587f1ae32a1SGerd Hoffmann {
588f1ae32a1SGerd Hoffmann UHCIState *s = port1->opaque;
589f1ae32a1SGerd Hoffmann
590f1ae32a1SGerd Hoffmann uhci_async_cancel_device(s, child);
591f1ae32a1SGerd Hoffmann }
592f1ae32a1SGerd Hoffmann
uhci_wakeup(USBPort * port1)593f1ae32a1SGerd Hoffmann static void uhci_wakeup(USBPort *port1)
594f1ae32a1SGerd Hoffmann {
595f1ae32a1SGerd Hoffmann UHCIState *s = port1->opaque;
596f1ae32a1SGerd Hoffmann UHCIPort *port = &s->ports[port1->index];
597f1ae32a1SGerd Hoffmann
598f1ae32a1SGerd Hoffmann if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
599f1ae32a1SGerd Hoffmann port->ctrl |= UHCI_PORT_RD;
600f1ae32a1SGerd Hoffmann uhci_resume(s);
601f1ae32a1SGerd Hoffmann }
602f1ae32a1SGerd Hoffmann }
603f1ae32a1SGerd Hoffmann
uhci_find_device(UHCIState * s,uint8_t addr)604f1ae32a1SGerd Hoffmann static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
605f1ae32a1SGerd Hoffmann {
606f1ae32a1SGerd Hoffmann USBDevice *dev;
607f1ae32a1SGerd Hoffmann int i;
608f1ae32a1SGerd Hoffmann
609fe693e32SPhilippe Mathieu-Daudé for (i = 0; i < UHCI_PORTS; i++) {
610f1ae32a1SGerd Hoffmann UHCIPort *port = &s->ports[i];
611f1ae32a1SGerd Hoffmann if (!(port->ctrl & UHCI_PORT_EN)) {
612f1ae32a1SGerd Hoffmann continue;
613f1ae32a1SGerd Hoffmann }
614f1ae32a1SGerd Hoffmann dev = usb_find_device(&port->port, addr);
615f1ae32a1SGerd Hoffmann if (dev != NULL) {
616f1ae32a1SGerd Hoffmann return dev;
617f1ae32a1SGerd Hoffmann }
618f1ae32a1SGerd Hoffmann }
619f1ae32a1SGerd Hoffmann return NULL;
620f1ae32a1SGerd Hoffmann }
621f1ae32a1SGerd Hoffmann
uhci_dma_read(UHCIState * s,dma_addr_t addr,void * buf,dma_addr_t len)62227af7e00SGuenter Roeck static void uhci_dma_read(UHCIState *s, dma_addr_t addr, void *buf,
62327af7e00SGuenter Roeck dma_addr_t len)
62427af7e00SGuenter Roeck {
62527af7e00SGuenter Roeck dma_memory_read(s->as, addr, buf, len, MEMTXATTRS_UNSPECIFIED);
62627af7e00SGuenter Roeck }
62727af7e00SGuenter Roeck
uhci_dma_write(UHCIState * s,dma_addr_t addr,void * buf,dma_addr_t len)62827af7e00SGuenter Roeck static void uhci_dma_write(UHCIState *s, dma_addr_t addr, void *buf,
62927af7e00SGuenter Roeck dma_addr_t len)
63027af7e00SGuenter Roeck {
63127af7e00SGuenter Roeck dma_memory_write(s->as, addr, buf, len, MEMTXATTRS_UNSPECIFIED);
63227af7e00SGuenter Roeck }
63327af7e00SGuenter Roeck
uhci_read_td(UHCIState * s,UHCI_TD * td,uint32_t link)634963a68b5SHans de Goede static void uhci_read_td(UHCIState *s, UHCI_TD *td, uint32_t link)
635963a68b5SHans de Goede {
63627af7e00SGuenter Roeck uhci_dma_read(s, link & ~0xf, td, sizeof(*td));
637963a68b5SHans de Goede le32_to_cpus(&td->link);
638963a68b5SHans de Goede le32_to_cpus(&td->ctrl);
639963a68b5SHans de Goede le32_to_cpus(&td->token);
640963a68b5SHans de Goede le32_to_cpus(&td->buffer);
641963a68b5SHans de Goede }
642963a68b5SHans de Goede
uhci_handle_td_error(UHCIState * s,UHCI_TD * td,uint32_t td_addr,int status,uint32_t * int_mask)643faccca00SHans de Goede static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr,
644faccca00SHans de Goede int status, uint32_t *int_mask)
645faccca00SHans de Goede {
646faccca00SHans de Goede uint32_t queue_token = uhci_queue_token(td);
647faccca00SHans de Goede int ret;
648faccca00SHans de Goede
649faccca00SHans de Goede switch (status) {
650faccca00SHans de Goede case USB_RET_NAK:
651faccca00SHans de Goede td->ctrl |= TD_CTRL_NAK;
652faccca00SHans de Goede return TD_RESULT_NEXT_QH;
653faccca00SHans de Goede
654faccca00SHans de Goede case USB_RET_STALL:
655faccca00SHans de Goede td->ctrl |= TD_CTRL_STALL;
656faccca00SHans de Goede trace_usb_uhci_packet_complete_stall(queue_token, td_addr);
657faccca00SHans de Goede ret = TD_RESULT_NEXT_QH;
658faccca00SHans de Goede break;
659faccca00SHans de Goede
660faccca00SHans de Goede case USB_RET_BABBLE:
661faccca00SHans de Goede td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
662faccca00SHans de Goede /* frame interrupted */
663faccca00SHans de Goede trace_usb_uhci_packet_complete_babble(queue_token, td_addr);
664faccca00SHans de Goede ret = TD_RESULT_STOP_FRAME;
665faccca00SHans de Goede break;
666faccca00SHans de Goede
667faccca00SHans de Goede case USB_RET_IOERROR:
668faccca00SHans de Goede case USB_RET_NODEV:
669faccca00SHans de Goede default:
670faccca00SHans de Goede td->ctrl |= TD_CTRL_TIMEOUT;
671faccca00SHans de Goede td->ctrl &= ~(3 << TD_CTRL_ERROR_SHIFT);
672faccca00SHans de Goede trace_usb_uhci_packet_complete_error(queue_token, td_addr);
673faccca00SHans de Goede ret = TD_RESULT_NEXT_QH;
674faccca00SHans de Goede break;
675faccca00SHans de Goede }
676faccca00SHans de Goede
677faccca00SHans de Goede td->ctrl &= ~TD_CTRL_ACTIVE;
678faccca00SHans de Goede s->status |= UHCI_STS_USBERR;
679faccca00SHans de Goede if (td->ctrl & TD_CTRL_IOC) {
680faccca00SHans de Goede *int_mask |= 0x01;
681faccca00SHans de Goede }
682faccca00SHans de Goede uhci_update_irq(s);
683faccca00SHans de Goede return ret;
684faccca00SHans de Goede }
685faccca00SHans de Goede
uhci_complete_td(UHCIState * s,UHCI_TD * td,UHCIAsync * async,uint32_t * int_mask)686fc83c4c9SGuenter Roeck static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async,
687fc83c4c9SGuenter Roeck uint32_t *int_mask)
688f1ae32a1SGerd Hoffmann {
6899a77a0f5SHans de Goede int len = 0, max_len;
690f1ae32a1SGerd Hoffmann uint8_t pid;
691f1ae32a1SGerd Hoffmann
692f1ae32a1SGerd Hoffmann max_len = ((td->token >> 21) + 1) & 0x7ff;
693f1ae32a1SGerd Hoffmann pid = td->token & 0xff;
694f1ae32a1SGerd Hoffmann
695fc83c4c9SGuenter Roeck if (td->ctrl & TD_CTRL_IOS) {
696f1ae32a1SGerd Hoffmann td->ctrl &= ~TD_CTRL_ACTIVE;
697fc83c4c9SGuenter Roeck }
698f1ae32a1SGerd Hoffmann
6999a77a0f5SHans de Goede if (async->packet.status != USB_RET_SUCCESS) {
7009a77a0f5SHans de Goede return uhci_handle_td_error(s, td, async->td_addr,
7019a77a0f5SHans de Goede async->packet.status, int_mask);
702faccca00SHans de Goede }
703f1ae32a1SGerd Hoffmann
7049a77a0f5SHans de Goede len = async->packet.actual_length;
705f1ae32a1SGerd Hoffmann td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
706f1ae32a1SGerd Hoffmann
707fc83c4c9SGuenter Roeck /*
708fc83c4c9SGuenter Roeck * The NAK bit may have been set by a previous frame, so clear it
709fc83c4c9SGuenter Roeck * here. The docs are somewhat unclear, but win2k relies on this
710fc83c4c9SGuenter Roeck * behavior.
711fc83c4c9SGuenter Roeck */
712f1ae32a1SGerd Hoffmann td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
713fc83c4c9SGuenter Roeck if (td->ctrl & TD_CTRL_IOC) {
714f1ae32a1SGerd Hoffmann *int_mask |= 0x01;
715fc83c4c9SGuenter Roeck }
716f1ae32a1SGerd Hoffmann
717f1ae32a1SGerd Hoffmann if (pid == USB_TOKEN_IN) {
71827af7e00SGuenter Roeck uhci_dma_write(s, td->buffer, async->buf, len);
719f1ae32a1SGerd Hoffmann if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
720f1ae32a1SGerd Hoffmann *int_mask |= 0x02;
721f1ae32a1SGerd Hoffmann /* short packet: do not update QH */
72250dcc0f8SGerd Hoffmann trace_usb_uhci_packet_complete_shortxfer(async->queue->token,
7231f250cc7SHans de Goede async->td_addr);
72460e1b2a6SGerd Hoffmann return TD_RESULT_NEXT_QH;
725f1ae32a1SGerd Hoffmann }
726f1ae32a1SGerd Hoffmann }
727f1ae32a1SGerd Hoffmann
728f1ae32a1SGerd Hoffmann /* success */
7291f250cc7SHans de Goede trace_usb_uhci_packet_complete_success(async->queue->token,
7301f250cc7SHans de Goede async->td_addr);
73160e1b2a6SGerd Hoffmann return TD_RESULT_COMPLETE;
732f1ae32a1SGerd Hoffmann }
733f1ae32a1SGerd Hoffmann
uhci_handle_td(UHCIState * s,UHCIQueue * q,uint32_t qh_addr,UHCI_TD * td,uint32_t td_addr,uint32_t * int_mask)73466a08cbeSHans de Goede static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
735a4f30cd7SHans de Goede UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask)
736f1ae32a1SGerd Hoffmann {
7379a77a0f5SHans de Goede int ret, max_len;
7386ba43f1fSHans de Goede bool spd;
739a4f30cd7SHans de Goede bool queuing = (q != NULL);
74011d15e40SHans de Goede uint8_t pid = td->token & 0xff;
7415f77e06bSGonglei UHCIAsync *async;
7428c75a899SHans de Goede
7435f77e06bSGonglei async = uhci_async_find_td(s, td_addr);
7448c75a899SHans de Goede if (async) {
7458c75a899SHans de Goede if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
7468c75a899SHans de Goede assert(q == NULL || q == async->queue);
7478c75a899SHans de Goede q = async->queue;
7488c75a899SHans de Goede } else {
7498c75a899SHans de Goede uhci_queue_free(async->queue, "guest re-used pending td");
7508c75a899SHans de Goede async = NULL;
7518c75a899SHans de Goede }
7528c75a899SHans de Goede }
753f1ae32a1SGerd Hoffmann
75466a08cbeSHans de Goede if (q == NULL) {
75566a08cbeSHans de Goede q = uhci_queue_find(s, td);
75666a08cbeSHans de Goede if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) {
75766a08cbeSHans de Goede uhci_queue_free(q, "guest re-used qh");
75866a08cbeSHans de Goede q = NULL;
75966a08cbeSHans de Goede }
76066a08cbeSHans de Goede }
76166a08cbeSHans de Goede
7623905097eSHans de Goede if (q) {
763475443cfSHans de Goede q->valid = QH_VALID;
7643905097eSHans de Goede }
7653905097eSHans de Goede
766f1ae32a1SGerd Hoffmann /* Is active ? */
767883bca77SHans de Goede if (!(td->ctrl & TD_CTRL_ACTIVE)) {
768420ca987SHans de Goede if (async) {
769420ca987SHans de Goede /* Guest marked a pending td non-active, cancel the queue */
770420ca987SHans de Goede uhci_queue_free(async->queue, "pending td non-active");
771420ca987SHans de Goede }
772883bca77SHans de Goede /*
773883bca77SHans de Goede * ehci11d spec page 22: "Even if the Active bit in the TD is already
774883bca77SHans de Goede * cleared when the TD is fetched ... an IOC interrupt is generated"
775883bca77SHans de Goede */
776883bca77SHans de Goede if (td->ctrl & TD_CTRL_IOC) {
777883bca77SHans de Goede *int_mask |= 0x01;
778883bca77SHans de Goede }
77960e1b2a6SGerd Hoffmann return TD_RESULT_NEXT_QH;
780883bca77SHans de Goede }
781f1ae32a1SGerd Hoffmann
782f419a626SGerd Hoffmann switch (pid) {
783f419a626SGerd Hoffmann case USB_TOKEN_OUT:
784f419a626SGerd Hoffmann case USB_TOKEN_SETUP:
785f419a626SGerd Hoffmann case USB_TOKEN_IN:
786f419a626SGerd Hoffmann break;
787f419a626SGerd Hoffmann default:
788f419a626SGerd Hoffmann /* invalid pid : frame interrupted */
789f419a626SGerd Hoffmann s->status |= UHCI_STS_HCPERR;
790f419a626SGerd Hoffmann s->cmd &= ~UHCI_CMD_RS;
791f419a626SGerd Hoffmann uhci_update_irq(s);
792f419a626SGerd Hoffmann return TD_RESULT_STOP_FRAME;
793f419a626SGerd Hoffmann }
794f419a626SGerd Hoffmann
795f1ae32a1SGerd Hoffmann if (async) {
796ee008ba6SGerd Hoffmann if (queuing) {
797fc83c4c9SGuenter Roeck /*
798fc83c4c9SGuenter Roeck * we are busy filling the queue, we are not prepared
799fc83c4c9SGuenter Roeck * to consume completed packages then, just leave them
800fc83c4c9SGuenter Roeck * in async state
801fc83c4c9SGuenter Roeck */
802ee008ba6SGerd Hoffmann return TD_RESULT_ASYNC_CONT;
803ee008ba6SGerd Hoffmann }
8048928c9c4SHans de Goede if (!async->done) {
8058928c9c4SHans de Goede UHCI_TD last_td;
806eae3eb3eSPaolo Bonzini UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs);
8078928c9c4SHans de Goede /*
8088928c9c4SHans de Goede * While we are waiting for the current td to complete, the guest
8098928c9c4SHans de Goede * may have added more tds to the queue. Note we re-read the td
8108928c9c4SHans de Goede * rather then caching it, as we want to see guest made changes!
8118928c9c4SHans de Goede */
8128928c9c4SHans de Goede uhci_read_td(s, &last_td, last->td_addr);
8138928c9c4SHans de Goede uhci_queue_fill(async->queue, &last_td);
814f1ae32a1SGerd Hoffmann
8158928c9c4SHans de Goede return TD_RESULT_ASYNC_CONT;
8168928c9c4SHans de Goede }
817f1ae32a1SGerd Hoffmann uhci_async_unlink(async);
818f1ae32a1SGerd Hoffmann goto done;
819f1ae32a1SGerd Hoffmann }
820f1ae32a1SGerd Hoffmann
82188793816SHans de Goede if (s->completions_only) {
82288793816SHans de Goede return TD_RESULT_ASYNC_CONT;
82388793816SHans de Goede }
82488793816SHans de Goede
825f1ae32a1SGerd Hoffmann /* Allocate new packet */
826a4f30cd7SHans de Goede if (q == NULL) {
827ff668537SLiam Merwick USBDevice *dev;
828ff668537SLiam Merwick USBEndpoint *ep;
8297f102ebeSHans de Goede
830ff668537SLiam Merwick dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
831ff668537SLiam Merwick if (dev == NULL) {
8327f102ebeSHans de Goede return uhci_handle_td_error(s, td, td_addr, USB_RET_NODEV,
8337f102ebeSHans de Goede int_mask);
8347f102ebeSHans de Goede }
835ff668537SLiam Merwick ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
83666a08cbeSHans de Goede q = uhci_queue_new(s, qh_addr, td, ep);
837a4f30cd7SHans de Goede }
838a4f30cd7SHans de Goede async = uhci_async_alloc(q, td_addr);
839f1ae32a1SGerd Hoffmann
840f1ae32a1SGerd Hoffmann max_len = ((td->token >> 21) + 1) & 0x7ff;
8416ba43f1fSHans de Goede spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
8428550a02dSGerd Hoffmann usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
843a6fb2ddbSHans de Goede (td->ctrl & TD_CTRL_IOC) != 0);
8449822261cSHans de Goede if (max_len <= sizeof(async->static_buf)) {
8459822261cSHans de Goede async->buf = async->static_buf;
8469822261cSHans de Goede } else {
8479822261cSHans de Goede async->buf = g_malloc(max_len);
8489822261cSHans de Goede }
8499822261cSHans de Goede usb_packet_addbuf(&async->packet, async->buf, max_len);
850f1ae32a1SGerd Hoffmann
851f1ae32a1SGerd Hoffmann switch (pid) {
852f1ae32a1SGerd Hoffmann case USB_TOKEN_OUT:
853f1ae32a1SGerd Hoffmann case USB_TOKEN_SETUP:
85427af7e00SGuenter Roeck uhci_dma_read(s, td->buffer, async->buf, max_len);
8559a77a0f5SHans de Goede usb_handle_packet(q->ep->dev, &async->packet);
8569a77a0f5SHans de Goede if (async->packet.status == USB_RET_SUCCESS) {
8579a77a0f5SHans de Goede async->packet.actual_length = max_len;
8589a77a0f5SHans de Goede }
859f1ae32a1SGerd Hoffmann break;
860f1ae32a1SGerd Hoffmann
861f1ae32a1SGerd Hoffmann case USB_TOKEN_IN:
8629a77a0f5SHans de Goede usb_handle_packet(q->ep->dev, &async->packet);
863f1ae32a1SGerd Hoffmann break;
864f1ae32a1SGerd Hoffmann
865f1ae32a1SGerd Hoffmann default:
8665f77e06bSGonglei abort(); /* Never to execute */
867f1ae32a1SGerd Hoffmann }
868f1ae32a1SGerd Hoffmann
8699a77a0f5SHans de Goede if (async->packet.status == USB_RET_ASYNC) {
870f1ae32a1SGerd Hoffmann uhci_async_link(async);
871a4f30cd7SHans de Goede if (!queuing) {
87211d15e40SHans de Goede uhci_queue_fill(q, td);
873a4f30cd7SHans de Goede }
8744efe4ef3SGerd Hoffmann return TD_RESULT_ASYNC_START;
875f1ae32a1SGerd Hoffmann }
876f1ae32a1SGerd Hoffmann
877f1ae32a1SGerd Hoffmann done:
8789a77a0f5SHans de Goede ret = uhci_complete_td(s, td, async, int_mask);
879f1ae32a1SGerd Hoffmann uhci_async_free(async);
8809a77a0f5SHans de Goede return ret;
881f1ae32a1SGerd Hoffmann }
882f1ae32a1SGerd Hoffmann
uhci_async_complete(USBPort * port,USBPacket * packet)883f1ae32a1SGerd Hoffmann static void uhci_async_complete(USBPort *port, USBPacket *packet)
884f1ae32a1SGerd Hoffmann {
885f1ae32a1SGerd Hoffmann UHCIAsync *async = container_of(packet, UHCIAsync, packet);
886f1ae32a1SGerd Hoffmann UHCIState *s = async->queue->uhci;
887f1ae32a1SGerd Hoffmann
8889a77a0f5SHans de Goede if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
8890cae7b1aSHans de Goede uhci_async_cancel(async);
8900cae7b1aSHans de Goede return;
8910cae7b1aSHans de Goede }
8920cae7b1aSHans de Goede
893f1ae32a1SGerd Hoffmann async->done = 1;
89488793816SHans de Goede /* Force processing of this packet *now*, needed for migration */
89588793816SHans de Goede s->completions_only = true;
8969a16c595SGerd Hoffmann qemu_bh_schedule(s->bh);
8979a16c595SGerd Hoffmann }
898f1ae32a1SGerd Hoffmann
is_valid(uint32_t link)899f1ae32a1SGerd Hoffmann static int is_valid(uint32_t link)
900f1ae32a1SGerd Hoffmann {
901f1ae32a1SGerd Hoffmann return (link & 1) == 0;
902f1ae32a1SGerd Hoffmann }
903f1ae32a1SGerd Hoffmann
is_qh(uint32_t link)904f1ae32a1SGerd Hoffmann static int is_qh(uint32_t link)
905f1ae32a1SGerd Hoffmann {
906f1ae32a1SGerd Hoffmann return (link & 2) != 0;
907f1ae32a1SGerd Hoffmann }
908f1ae32a1SGerd Hoffmann
depth_first(uint32_t link)909f1ae32a1SGerd Hoffmann static int depth_first(uint32_t link)
910f1ae32a1SGerd Hoffmann {
911f1ae32a1SGerd Hoffmann return (link & 4) != 0;
912f1ae32a1SGerd Hoffmann }
913f1ae32a1SGerd Hoffmann
914f1ae32a1SGerd Hoffmann /* QH DB used for detecting QH loops */
915f1ae32a1SGerd Hoffmann #define UHCI_MAX_QUEUES 128
916f1ae32a1SGerd Hoffmann typedef struct {
917f1ae32a1SGerd Hoffmann uint32_t addr[UHCI_MAX_QUEUES];
918f1ae32a1SGerd Hoffmann int count;
919f1ae32a1SGerd Hoffmann } QhDb;
920f1ae32a1SGerd Hoffmann
qhdb_reset(QhDb * db)921f1ae32a1SGerd Hoffmann static void qhdb_reset(QhDb *db)
922f1ae32a1SGerd Hoffmann {
923f1ae32a1SGerd Hoffmann db->count = 0;
924f1ae32a1SGerd Hoffmann }
925f1ae32a1SGerd Hoffmann
926f1ae32a1SGerd Hoffmann /* Add QH to DB. Returns 1 if already present or DB is full. */
qhdb_insert(QhDb * db,uint32_t addr)927f1ae32a1SGerd Hoffmann static int qhdb_insert(QhDb *db, uint32_t addr)
928f1ae32a1SGerd Hoffmann {
929f1ae32a1SGerd Hoffmann int i;
930fc83c4c9SGuenter Roeck for (i = 0; i < db->count; i++) {
931fc83c4c9SGuenter Roeck if (db->addr[i] == addr) {
932f1ae32a1SGerd Hoffmann return 1;
933fc83c4c9SGuenter Roeck }
934fc83c4c9SGuenter Roeck }
935f1ae32a1SGerd Hoffmann
936fc83c4c9SGuenter Roeck if (db->count >= UHCI_MAX_QUEUES) {
937f1ae32a1SGerd Hoffmann return 1;
938fc83c4c9SGuenter Roeck }
939f1ae32a1SGerd Hoffmann
940f1ae32a1SGerd Hoffmann db->addr[db->count++] = addr;
941f1ae32a1SGerd Hoffmann return 0;
942f1ae32a1SGerd Hoffmann }
943f1ae32a1SGerd Hoffmann
uhci_queue_fill(UHCIQueue * q,UHCI_TD * td)94411d15e40SHans de Goede static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td)
945f1ae32a1SGerd Hoffmann {
946f1ae32a1SGerd Hoffmann uint32_t int_mask = 0;
947f1ae32a1SGerd Hoffmann uint32_t plink = td->link;
948f1ae32a1SGerd Hoffmann UHCI_TD ptd;
949f1ae32a1SGerd Hoffmann int ret;
950f1ae32a1SGerd Hoffmann
9516ba43f1fSHans de Goede while (is_valid(plink)) {
952a4f30cd7SHans de Goede uhci_read_td(q->uhci, &ptd, plink);
953f1ae32a1SGerd Hoffmann if (!(ptd.ctrl & TD_CTRL_ACTIVE)) {
954f1ae32a1SGerd Hoffmann break;
955f1ae32a1SGerd Hoffmann }
956a4f30cd7SHans de Goede if (uhci_queue_token(&ptd) != q->token) {
957f1ae32a1SGerd Hoffmann break;
958f1ae32a1SGerd Hoffmann }
95950dcc0f8SGerd Hoffmann trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
96066a08cbeSHans de Goede ret = uhci_handle_td(q->uhci, q, q->qh_addr, &ptd, plink, &int_mask);
96152b0fecdSGerd Hoffmann if (ret == TD_RESULT_ASYNC_CONT) {
96252b0fecdSGerd Hoffmann break;
96352b0fecdSGerd Hoffmann }
9644efe4ef3SGerd Hoffmann assert(ret == TD_RESULT_ASYNC_START);
965f1ae32a1SGerd Hoffmann assert(int_mask == 0);
966f1ae32a1SGerd Hoffmann plink = ptd.link;
967f1ae32a1SGerd Hoffmann }
96811d15e40SHans de Goede usb_device_flush_ep_queue(q->ep->dev, q->ep);
969f1ae32a1SGerd Hoffmann }
970f1ae32a1SGerd Hoffmann
uhci_process_frame(UHCIState * s)971f1ae32a1SGerd Hoffmann static void uhci_process_frame(UHCIState *s)
972f1ae32a1SGerd Hoffmann {
973f1ae32a1SGerd Hoffmann uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
9744aed20e2SGerd Hoffmann uint32_t curr_qh, td_count = 0;
975f1ae32a1SGerd Hoffmann int cnt, ret;
976f1ae32a1SGerd Hoffmann UHCI_TD td;
977f1ae32a1SGerd Hoffmann UHCI_QH qh;
978f1ae32a1SGerd Hoffmann QhDb qhdb;
979f1ae32a1SGerd Hoffmann
980f1ae32a1SGerd Hoffmann frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
981f1ae32a1SGerd Hoffmann
98227af7e00SGuenter Roeck uhci_dma_read(s, frame_addr, &link, 4);
983f1ae32a1SGerd Hoffmann le32_to_cpus(&link);
984f1ae32a1SGerd Hoffmann
985f1ae32a1SGerd Hoffmann int_mask = 0;
986f1ae32a1SGerd Hoffmann curr_qh = 0;
987f1ae32a1SGerd Hoffmann
988f1ae32a1SGerd Hoffmann qhdb_reset(&qhdb);
989f1ae32a1SGerd Hoffmann
990f1ae32a1SGerd Hoffmann for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
99188793816SHans de Goede if (!s->completions_only && s->frame_bytes >= s->frame_bandwidth) {
992fc83c4c9SGuenter Roeck /*
993fc83c4c9SGuenter Roeck * We've reached the usb 1.1 bandwidth, which is
994fc83c4c9SGuenter Roeck * 1280 bytes/frame, stop processing
995fc83c4c9SGuenter Roeck */
9964aed20e2SGerd Hoffmann trace_usb_uhci_frame_stop_bandwidth();
9974aed20e2SGerd Hoffmann break;
9984aed20e2SGerd Hoffmann }
999f1ae32a1SGerd Hoffmann if (is_qh(link)) {
1000f1ae32a1SGerd Hoffmann /* QH */
100150dcc0f8SGerd Hoffmann trace_usb_uhci_qh_load(link & ~0xf);
1002f1ae32a1SGerd Hoffmann
1003f1ae32a1SGerd Hoffmann if (qhdb_insert(&qhdb, link)) {
1004f1ae32a1SGerd Hoffmann /*
1005f1ae32a1SGerd Hoffmann * We're going in circles. Which is not a bug because
1006f1ae32a1SGerd Hoffmann * HCD is allowed to do that as part of the BW management.
1007f1ae32a1SGerd Hoffmann *
10084aed20e2SGerd Hoffmann * Stop processing here if no transaction has been done
10094aed20e2SGerd Hoffmann * since we've been here last time.
1010f1ae32a1SGerd Hoffmann */
1011f1ae32a1SGerd Hoffmann if (td_count == 0) {
101250dcc0f8SGerd Hoffmann trace_usb_uhci_frame_loop_stop_idle();
1013f1ae32a1SGerd Hoffmann break;
1014f1ae32a1SGerd Hoffmann } else {
101550dcc0f8SGerd Hoffmann trace_usb_uhci_frame_loop_continue();
1016f1ae32a1SGerd Hoffmann td_count = 0;
1017f1ae32a1SGerd Hoffmann qhdb_reset(&qhdb);
1018f1ae32a1SGerd Hoffmann qhdb_insert(&qhdb, link);
1019f1ae32a1SGerd Hoffmann }
1020f1ae32a1SGerd Hoffmann }
1021f1ae32a1SGerd Hoffmann
102227af7e00SGuenter Roeck uhci_dma_read(s, link & ~0xf, &qh, sizeof(qh));
1023f1ae32a1SGerd Hoffmann le32_to_cpus(&qh.link);
1024f1ae32a1SGerd Hoffmann le32_to_cpus(&qh.el_link);
1025f1ae32a1SGerd Hoffmann
1026f1ae32a1SGerd Hoffmann if (!is_valid(qh.el_link)) {
1027f1ae32a1SGerd Hoffmann /* QH w/o elements */
1028f1ae32a1SGerd Hoffmann curr_qh = 0;
1029f1ae32a1SGerd Hoffmann link = qh.link;
1030f1ae32a1SGerd Hoffmann } else {
1031f1ae32a1SGerd Hoffmann /* QH with elements */
1032f1ae32a1SGerd Hoffmann curr_qh = link;
1033f1ae32a1SGerd Hoffmann link = qh.el_link;
1034f1ae32a1SGerd Hoffmann }
1035f1ae32a1SGerd Hoffmann continue;
1036f1ae32a1SGerd Hoffmann }
1037f1ae32a1SGerd Hoffmann
1038f1ae32a1SGerd Hoffmann /* TD */
1039963a68b5SHans de Goede uhci_read_td(s, &td, link);
104050dcc0f8SGerd Hoffmann trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
1041f1ae32a1SGerd Hoffmann
1042f1ae32a1SGerd Hoffmann old_td_ctrl = td.ctrl;
104366a08cbeSHans de Goede ret = uhci_handle_td(s, NULL, curr_qh, &td, link, &int_mask);
1044f1ae32a1SGerd Hoffmann if (old_td_ctrl != td.ctrl) {
1045f1ae32a1SGerd Hoffmann /* update the status bits of the TD */
1046f1ae32a1SGerd Hoffmann val = cpu_to_le32(td.ctrl);
104727af7e00SGuenter Roeck uhci_dma_write(s, (link & ~0xf) + 4, &val, sizeof(val));
1048f1ae32a1SGerd Hoffmann }
1049f1ae32a1SGerd Hoffmann
1050f1ae32a1SGerd Hoffmann switch (ret) {
105160e1b2a6SGerd Hoffmann case TD_RESULT_STOP_FRAME: /* interrupted frame */
1052f1ae32a1SGerd Hoffmann goto out;
1053f1ae32a1SGerd Hoffmann
105460e1b2a6SGerd Hoffmann case TD_RESULT_NEXT_QH:
10554efe4ef3SGerd Hoffmann case TD_RESULT_ASYNC_CONT:
105650dcc0f8SGerd Hoffmann trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf);
1057f1ae32a1SGerd Hoffmann link = curr_qh ? qh.link : td.link;
1058f1ae32a1SGerd Hoffmann continue;
1059f1ae32a1SGerd Hoffmann
10604efe4ef3SGerd Hoffmann case TD_RESULT_ASYNC_START:
106150dcc0f8SGerd Hoffmann trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
1062f1ae32a1SGerd Hoffmann link = curr_qh ? qh.link : td.link;
1063f1ae32a1SGerd Hoffmann continue;
1064f1ae32a1SGerd Hoffmann
106560e1b2a6SGerd Hoffmann case TD_RESULT_COMPLETE:
106650dcc0f8SGerd Hoffmann trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf);
1067f1ae32a1SGerd Hoffmann link = td.link;
1068f1ae32a1SGerd Hoffmann td_count++;
10694aed20e2SGerd Hoffmann s->frame_bytes += (td.ctrl & 0x7ff) + 1;
1070f1ae32a1SGerd Hoffmann
1071f1ae32a1SGerd Hoffmann if (curr_qh) {
1072f1ae32a1SGerd Hoffmann /* update QH element link */
1073f1ae32a1SGerd Hoffmann qh.el_link = link;
1074f1ae32a1SGerd Hoffmann val = cpu_to_le32(qh.el_link);
107527af7e00SGuenter Roeck uhci_dma_write(s, (curr_qh & ~0xf) + 4, &val, sizeof(val));
1076f1ae32a1SGerd Hoffmann
1077f1ae32a1SGerd Hoffmann if (!depth_first(link)) {
1078f1ae32a1SGerd Hoffmann /* done with this QH */
1079f1ae32a1SGerd Hoffmann curr_qh = 0;
1080f1ae32a1SGerd Hoffmann link = qh.link;
1081f1ae32a1SGerd Hoffmann }
1082f1ae32a1SGerd Hoffmann }
1083f1ae32a1SGerd Hoffmann break;
1084f1ae32a1SGerd Hoffmann
1085f1ae32a1SGerd Hoffmann default:
1086f1ae32a1SGerd Hoffmann assert(!"unknown return code");
1087f1ae32a1SGerd Hoffmann }
1088f1ae32a1SGerd Hoffmann
1089f1ae32a1SGerd Hoffmann /* go to the next entry */
1090f1ae32a1SGerd Hoffmann }
1091f1ae32a1SGerd Hoffmann
1092f1ae32a1SGerd Hoffmann out:
1093f1ae32a1SGerd Hoffmann s->pending_int_mask |= int_mask;
1094f1ae32a1SGerd Hoffmann }
1095f1ae32a1SGerd Hoffmann
uhci_bh(void * opaque)10969a16c595SGerd Hoffmann static void uhci_bh(void *opaque)
10979a16c595SGerd Hoffmann {
10989a16c595SGerd Hoffmann UHCIState *s = opaque;
10999a16c595SGerd Hoffmann uhci_process_frame(s);
11009a16c595SGerd Hoffmann }
11019a16c595SGerd Hoffmann
uhci_frame_timer(void * opaque)1102f1ae32a1SGerd Hoffmann static void uhci_frame_timer(void *opaque)
1103f1ae32a1SGerd Hoffmann {
1104f1ae32a1SGerd Hoffmann UHCIState *s = opaque;
1105f8f48b69SHans de Goede uint64_t t_now, t_last_run;
1106f8f48b69SHans de Goede int i, frames;
110773bcb24dSRutuja Shah const uint64_t frame_t = NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ;
1108f1ae32a1SGerd Hoffmann
110988793816SHans de Goede s->completions_only = false;
11109a16c595SGerd Hoffmann qemu_bh_cancel(s->bh);
1111f1ae32a1SGerd Hoffmann
1112f1ae32a1SGerd Hoffmann if (!(s->cmd & UHCI_CMD_RS)) {
1113f1ae32a1SGerd Hoffmann /* Full stop */
111450dcc0f8SGerd Hoffmann trace_usb_uhci_schedule_stop();
1115bc72ad67SAlex Bligh timer_del(s->frame_timer);
1116d9a528dbSGerd Hoffmann uhci_async_cancel_all(s);
1117f1ae32a1SGerd Hoffmann /* set hchalted bit in status - UHCI11D 2.1.2 */
1118f1ae32a1SGerd Hoffmann s->status |= UHCI_STS_HCHALTED;
1119f1ae32a1SGerd Hoffmann return;
1120f1ae32a1SGerd Hoffmann }
1121f1ae32a1SGerd Hoffmann
1122f8f48b69SHans de Goede /* We still store expire_time in our state, for migration */
1123f8f48b69SHans de Goede t_last_run = s->expire_time - frame_t;
1124bc72ad67SAlex Bligh t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1125f8f48b69SHans de Goede
1126f8f48b69SHans de Goede /* Process up to MAX_FRAMES_PER_TICK frames */
1127f8f48b69SHans de Goede frames = (t_now - t_last_run) / frame_t;
11289fdf7027SHans de Goede if (frames > s->maxframes) {
11299fdf7027SHans de Goede int skipped = frames - s->maxframes;
11309fdf7027SHans de Goede s->expire_time += skipped * frame_t;
11319fdf7027SHans de Goede s->frnum = (s->frnum + skipped) & 0x7ff;
11329fdf7027SHans de Goede frames -= skipped;
11339fdf7027SHans de Goede }
1134f8f48b69SHans de Goede if (frames > MAX_FRAMES_PER_TICK) {
1135f8f48b69SHans de Goede frames = MAX_FRAMES_PER_TICK;
1136f8f48b69SHans de Goede }
1137f8f48b69SHans de Goede
1138f8f48b69SHans de Goede for (i = 0; i < frames; i++) {
1139f8f48b69SHans de Goede s->frame_bytes = 0;
114050dcc0f8SGerd Hoffmann trace_usb_uhci_frame_start(s->frnum);
1141f1ae32a1SGerd Hoffmann uhci_async_validate_begin(s);
1142f1ae32a1SGerd Hoffmann uhci_process_frame(s);
1143f1ae32a1SGerd Hoffmann uhci_async_validate_end(s);
1144fc83c4c9SGuenter Roeck /*
1145fc83c4c9SGuenter Roeck * The spec says frnum is the frame currently being processed, and
1146fc83c4c9SGuenter Roeck * the guest must look at frnum - 1 on interrupt, so inc frnum now
1147fc83c4c9SGuenter Roeck */
1148719c130dSHans de Goede s->frnum = (s->frnum + 1) & 0x7ff;
1149f8f48b69SHans de Goede s->expire_time += frame_t;
1150f8f48b69SHans de Goede }
1151719c130dSHans de Goede
1152f8f48b69SHans de Goede /* Complete the previous frame(s) */
1153719c130dSHans de Goede if (s->pending_int_mask) {
1154719c130dSHans de Goede s->status2 |= s->pending_int_mask;
1155719c130dSHans de Goede s->status |= UHCI_STS_USBINT;
1156719c130dSHans de Goede uhci_update_irq(s);
1157719c130dSHans de Goede }
1158719c130dSHans de Goede s->pending_int_mask = 0;
1159719c130dSHans de Goede
1160bc72ad67SAlex Bligh timer_mod(s->frame_timer, t_now + frame_t);
1161f1ae32a1SGerd Hoffmann }
1162f1ae32a1SGerd Hoffmann
1163f1ae32a1SGerd Hoffmann static const MemoryRegionOps uhci_ioport_ops = {
116489eb147cSGerd Hoffmann .read = uhci_port_read,
116589eb147cSGerd Hoffmann .write = uhci_port_write,
116689eb147cSGerd Hoffmann .valid.min_access_size = 1,
116789eb147cSGerd Hoffmann .valid.max_access_size = 4,
116889eb147cSGerd Hoffmann .impl.min_access_size = 2,
116989eb147cSGerd Hoffmann .impl.max_access_size = 2,
117089eb147cSGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN,
1171f1ae32a1SGerd Hoffmann };
1172f1ae32a1SGerd Hoffmann
1173f1ae32a1SGerd Hoffmann static USBPortOps uhci_port_ops = {
1174f1ae32a1SGerd Hoffmann .attach = uhci_attach,
1175f1ae32a1SGerd Hoffmann .detach = uhci_detach,
1176f1ae32a1SGerd Hoffmann .child_detach = uhci_child_detach,
1177f1ae32a1SGerd Hoffmann .wakeup = uhci_wakeup,
1178f1ae32a1SGerd Hoffmann .complete = uhci_async_complete,
1179f1ae32a1SGerd Hoffmann };
1180f1ae32a1SGerd Hoffmann
1181f1ae32a1SGerd Hoffmann static USBBusOps uhci_bus_ops = {
1182f1ae32a1SGerd Hoffmann };
1183f1ae32a1SGerd Hoffmann
usb_uhci_init(UHCIState * s,DeviceState * dev,Error ** errp)118427af7e00SGuenter Roeck void usb_uhci_init(UHCIState *s, DeviceState *dev, Error **errp)
1185f1ae32a1SGerd Hoffmann {
1186f4bbaaf5SMarkus Armbruster Error *err = NULL;
1187f1ae32a1SGerd Hoffmann int i;
1188f1ae32a1SGerd Hoffmann
1189f1ae32a1SGerd Hoffmann if (s->masterbus) {
1190fe693e32SPhilippe Mathieu-Daudé USBPort *ports[UHCI_PORTS];
1191fe693e32SPhilippe Mathieu-Daudé for (i = 0; i < UHCI_PORTS; i++) {
1192f1ae32a1SGerd Hoffmann ports[i] = &s->ports[i].port;
1193f1ae32a1SGerd Hoffmann }
1194fe693e32SPhilippe Mathieu-Daudé usb_register_companion(s->masterbus, ports, UHCI_PORTS,
1195f1ae32a1SGerd Hoffmann s->firstport, s, &uhci_port_ops,
1196f4bbaaf5SMarkus Armbruster USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL,
1197f4bbaaf5SMarkus Armbruster &err);
1198f4bbaaf5SMarkus Armbruster if (err) {
119963216dc7SMarkus Armbruster error_propagate(errp, err);
120063216dc7SMarkus Armbruster return;
1201f1ae32a1SGerd Hoffmann }
1202f1ae32a1SGerd Hoffmann } else {
1203c889b3a5SAndreas Färber usb_bus_new(&s->bus, sizeof(s->bus), &uhci_bus_ops, DEVICE(dev));
1204fe693e32SPhilippe Mathieu-Daudé for (i = 0; i < UHCI_PORTS; i++) {
1205f1ae32a1SGerd Hoffmann usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
1206f1ae32a1SGerd Hoffmann USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
1207f1ae32a1SGerd Hoffmann }
1208f1ae32a1SGerd Hoffmann }
120927af7e00SGuenter Roeck s->bh = qemu_bh_new_guarded(uhci_bh, s, &dev->mem_reentrancy_guard);
1210bc72ad67SAlex Bligh s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, uhci_frame_timer, s);
1211fe693e32SPhilippe Mathieu-Daudé s->num_ports_vmstate = UHCI_PORTS;
1212f1ae32a1SGerd Hoffmann QTAILQ_INIT(&s->queues);
1213f1ae32a1SGerd Hoffmann
121427af7e00SGuenter Roeck memory_region_init_io(&s->mem, OBJECT(s), &uhci_ioport_ops, s,
1215*521120b9SGuenter Roeck "uhci", 0x100);
1216f1ae32a1SGerd Hoffmann }
1217f1ae32a1SGerd Hoffmann
usb_uhci_exit(UHCIState * s)121827af7e00SGuenter Roeck void usb_uhci_exit(UHCIState *s)
12193a3464b0SGonglei {
1220d733f74cSGonglei trace_usb_uhci_exit();
1221d733f74cSGonglei
12223a3464b0SGonglei if (s->frame_timer) {
12233a3464b0SGonglei timer_free(s->frame_timer);
12243a3464b0SGonglei s->frame_timer = NULL;
12253a3464b0SGonglei }
12263a3464b0SGonglei
12273a3464b0SGonglei if (s->bh) {
12283a3464b0SGonglei qemu_bh_delete(s->bh);
12293a3464b0SGonglei }
12303a3464b0SGonglei
12313a3464b0SGonglei uhci_async_cancel_all(s);
12323a3464b0SGonglei
12333a3464b0SGonglei if (!s->masterbus) {
12343a3464b0SGonglei usb_bus_release(&s->bus);
12353a3464b0SGonglei }
12363a3464b0SGonglei }
1237