2 * QEMU USB packet combining code (for input pipelining)
4 * Copyright(c) 2012 Red Hat, Inc.
7 * Hans de Goede <hdegoede@redhat.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or(at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "qemu-common.h"
27 static void usb_combined_packet_add(USBCombinedPacket
*combined
, USBPacket
*p
)
29 qemu_iovec_concat(&combined
->iov
, &p
->iov
, 0, p
->iov
.size
);
30 QTAILQ_INSERT_TAIL(&combined
->packets
, p
, combined_entry
);
31 p
->combined
= combined
;
34 /* Note will free combined when the last packet gets removed */
35 static void usb_combined_packet_remove(USBCombinedPacket
*combined
,
38 assert(p
->combined
== combined
);
40 QTAILQ_REMOVE(&combined
->packets
, p
, combined_entry
);
41 if (QTAILQ_EMPTY(&combined
->packets
)) {
46 /* Also handles completion of non combined packets for pipelined input eps */
47 void usb_combined_input_packet_complete(USBDevice
*dev
, USBPacket
*p
)
49 USBCombinedPacket
*combined
= p
->combined
;
50 USBEndpoint
*ep
= p
->ep
;
52 int status
, actual_length
;
53 bool short_not_ok
, done
= false;
55 if (combined
== NULL
) {
56 usb_packet_complete_one(dev
, p
);
60 assert(combined
->first
== p
&& p
== QTAILQ_FIRST(&combined
->packets
));
62 status
= combined
->first
->status
;
63 actual_length
= combined
->first
->actual_length
;
64 short_not_ok
= QTAILQ_LAST(&combined
->packets
, packets_head
)->short_not_ok
;
66 QTAILQ_FOREACH_SAFE(p
, &combined
->packets
, combined_entry
, next
) {
68 /* Distribute data over uncombined packets */
69 if (actual_length
>= p
->iov
.size
) {
70 p
->actual_length
= p
->iov
.size
;
72 /* Send short or error packet to complete the transfer */
73 p
->actual_length
= actual_length
;
76 /* Report status on the last packet */
77 if (done
|| next
== NULL
) {
80 p
->status
= USB_RET_SUCCESS
;
82 p
->short_not_ok
= short_not_ok
;
83 /* Note will free combined when the last packet gets removed! */
84 usb_combined_packet_remove(combined
, p
);
85 usb_packet_complete_one(dev
, p
);
86 actual_length
-= p
->actual_length
;
88 /* Remove any leftover packets from the queue */
89 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
90 /* Note will free combined on the last packet! */
91 dev
->port
->ops
->complete(dev
->port
, p
);
94 /* Do not use combined here, it has been freed! */
96 /* Check if there are packets in the queue waiting for our completion */
97 usb_ep_combine_input_packets(ep
);
100 /* May only be called for combined packets! */
101 void usb_combined_packet_cancel(USBDevice
*dev
, USBPacket
*p
)
103 USBCombinedPacket
*combined
= p
->combined
;
104 assert(combined
!= NULL
);
105 USBPacket
*first
= p
->combined
->first
;
107 /* Note will free combined on the last packet! */
108 usb_combined_packet_remove(combined
, p
);
110 usb_device_cancel_packet(dev
, p
);
115 * Large input transfers can get split into multiple input packets, this
116 * function recombines them, removing the short_not_ok checks which all but
117 * the last packet of such splits transfers have, thereby allowing input
118 * transfer pipelining (which we cannot do on short_not_ok transfers)
120 void usb_ep_combine_input_packets(USBEndpoint
*ep
)
122 USBPacket
*p
, *u
, *next
, *prev
= NULL
, *first
= NULL
;
123 USBPort
*port
= ep
->dev
->port
;
126 assert(ep
->pipeline
);
127 assert(ep
->pid
== USB_TOKEN_IN
);
129 QTAILQ_FOREACH_SAFE(p
, &ep
->queue
, queue
, next
) {
130 /* Empty the queue on a halt */
132 p
->status
= USB_RET_REMOVE_FROM_QUEUE
;
133 port
->ops
->complete(port
, p
);
137 /* Skip packets already submitted to the device */
138 if (p
->state
== USB_PACKET_ASYNC
) {
142 usb_packet_check_state(p
, USB_PACKET_QUEUED
);
145 * If the previous (combined) packet has the short_not_ok flag set
146 * stop, as we must not submit packets to the device after a transfer
147 * ending with short_not_ok packet.
149 if (prev
&& prev
->short_not_ok
) {
154 if (first
->combined
== NULL
) {
155 USBCombinedPacket
*combined
= g_new0(USBCombinedPacket
, 1);
157 combined
->first
= first
;
158 QTAILQ_INIT(&combined
->packets
);
159 qemu_iovec_init(&combined
->iov
, 2);
160 usb_combined_packet_add(combined
, first
);
162 usb_combined_packet_add(first
->combined
, p
);
167 /* Is this packet the last one of a (combined) transfer? */
168 totalsize
= (p
->combined
) ? p
->combined
->iov
.size
: p
->iov
.size
;
169 if ((p
->iov
.size
% ep
->max_packet_size
) != 0 || !p
->short_not_ok
||
171 /* Work around for Linux usbfs bulk splitting + migration */
172 (totalsize
== 16348 && p
->int_req
)) {
173 usb_device_handle_data(ep
->dev
, first
);
174 assert(first
->status
== USB_RET_ASYNC
);
175 if (first
->combined
) {
176 QTAILQ_FOREACH(u
, &first
->combined
->packets
, combined_entry
) {
177 usb_packet_set_state(u
, USB_PACKET_ASYNC
);
180 usb_packet_set_state(first
, USB_PACKET_ASYNC
);