aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBALATON Zoltan <balaton@eik.bme.hu>2022-01-25 14:33:20 +0100
committerGerd Hoffmann <kraxel@redhat.com>2022-03-04 09:34:21 +0100
commit3a4d06f26f2606dd5029b05b4aff97f198455249 (patch)
tree8b99780239b47308e2a9dbb3f282286d66c72822
parentb6b0c066f5750c3c977b647509f225ba06038b60 (diff)
downloadqemu-3a4d06f26f2606dd5029b05b4aff97f198455249.zip
qemu-3a4d06f26f2606dd5029b05b4aff97f198455249.tar.gz
qemu-3a4d06f26f2606dd5029b05b4aff97f198455249.tar.bz2
usb/ohci: Don't use packet from OHCIState for isochronous transfers
Since isochronous transfers cannot be handled async (the function returns error in that case) we don't need to remember the packet. Avoid using the usb_packet field in OHCIState (as that can be a waiting async packet on another endpoint) and allocate and use a local USBPacket for the iso transfer instead. After this we don't have to care if we're called from a completion callback or not so we can drop that parameter as well. Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Message-Id: <bf523d40f8088a84383cb00ffd2e6e82fa47790d.1643117600.git.balaton@eik.bme.hu> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-rw-r--r--hw/usb/hcd-ohci.c71
1 files changed, 38 insertions, 33 deletions
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 09d0736..895b29f 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -548,8 +548,7 @@ static int ohci_copy_iso_td(OHCIState *ohci,
#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
-static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
- int completion)
+static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed)
{
int dir;
size_t len = 0;
@@ -559,6 +558,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
int i;
USBDevice *dev;
USBEndpoint *ep;
+ USBPacket *pkt;
+ uint8_t buf[8192];
+ bool int_req;
struct ohci_iso_td iso_td;
uint32_t addr;
uint16_t starting_frame;
@@ -693,40 +695,42 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
} else {
len = end_addr - start_addr + 1;
}
- if (len > sizeof(ohci->usb_buf)) {
- len = sizeof(ohci->usb_buf);
+ if (len > sizeof(buf)) {
+ len = sizeof(buf);
}
if (len && dir != OHCI_TD_DIR_IN) {
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len,
+ if (ohci_copy_iso_td(ohci, start_addr, end_addr, buf, len,
DMA_DIRECTION_TO_DEVICE)) {
ohci_die(ohci);
return 1;
}
}
- if (!completion) {
- bool int_req = relative_frame_number == frame_count &&
- OHCI_BM(iso_td.flags, TD_DI) == 0;
- dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
- if (dev == NULL) {
- trace_usb_ohci_td_dev_error();
- return 1;
- }
- ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
- usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
- usb_handle_packet(dev, &ohci->usb_packet);
- if (ohci->usb_packet.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, ep);
- return 1;
- }
+ dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
+ if (dev == NULL) {
+ trace_usb_ohci_td_dev_error();
+ return 1;
}
- if (ohci->usb_packet.status == USB_RET_SUCCESS) {
- ret = ohci->usb_packet.actual_length;
+ ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
+ pkt = g_new0(USBPacket, 1);
+ usb_packet_init(pkt);
+ int_req = relative_frame_number == frame_count &&
+ OHCI_BM(iso_td.flags, TD_DI) == 0;
+ usb_packet_setup(pkt, pid, ep, 0, addr, false, int_req);
+ usb_packet_addbuf(pkt, buf, len);
+ usb_handle_packet(dev, pkt);
+ if (pkt->status == USB_RET_ASYNC) {
+ usb_device_flush_ep_queue(dev, ep);
+ g_free(pkt);
+ return 1;
+ }
+ if (pkt->status == USB_RET_SUCCESS) {
+ ret = pkt->actual_length;
} else {
- ret = ohci->usb_packet.status;
+ ret = pkt->status;
}
+ g_free(pkt);
trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr,
str, len, ret);
@@ -734,7 +738,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
/* Writeback */
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
/* IN transfer succeeded */
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret,
+ if (ohci_copy_iso_td(ohci, start_addr, end_addr, buf, ret,
DMA_DIRECTION_FROM_DEVICE)) {
ohci_die(ohci);
return 1;
@@ -1057,7 +1061,7 @@ exit_no_retire:
}
/* Service an endpoint list. Returns nonzero if active TD were found. */
-static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
+static int ohci_service_ed_list(OHCIState *ohci, uint32_t head)
{
struct ohci_ed ed;
uint32_t next_ed;
@@ -1108,8 +1112,9 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
break;
} else {
/* Handle isochronous endpoints */
- if (ohci_service_iso_td(ohci, &ed, completion))
+ if (ohci_service_iso_td(ohci, &ed)) {
break;
+ }
}
}
@@ -1136,20 +1141,20 @@ static void ohci_sof(OHCIState *ohci)
}
/* Process Control and Bulk lists. */
-static void ohci_process_lists(OHCIState *ohci, int completion)
+static void ohci_process_lists(OHCIState *ohci)
{
if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur);
}
- if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
+ if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) {
ohci->ctrl_cur = 0;
ohci->status &= ~OHCI_STATUS_CLF;
}
}
if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
- if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
+ if (!ohci_service_ed_list(ohci, ohci->bulk_head)) {
ohci->bulk_cur = 0;
ohci->status &= ~OHCI_STATUS_BLF;
}
@@ -1173,7 +1178,7 @@ static void ohci_frame_boundary(void *opaque)
int n;
n = ohci->frame_number & 0x1f;
- ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
+ ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]));
}
/* Cancel all pending packets if either of the lists has been disabled. */
@@ -1181,7 +1186,7 @@ static void ohci_frame_boundary(void *opaque)
ohci_stop_endpoints(ohci);
}
ohci->old_ctl = ohci->ctl;
- ohci_process_lists(ohci, 0);
+ ohci_process_lists(ohci);
/* Stop if UnrecoverableError happened or ohci_sof will crash */
if (ohci->intr_status & OHCI_INTR_UE) {
@@ -1794,7 +1799,7 @@ static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
trace_usb_ohci_async_complete();
ohci->async_complete = true;
- ohci_process_lists(ohci, 1);
+ ohci_process_lists(ohci);
}
static USBPortOps ohci_port_ops = {