qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

OHCI/usb pass through


From: BALATON Zoltan
Subject: OHCI/usb pass through
Date: Fri, 1 Oct 2021 03:31:11 +0200 (CEST)

Hello,

We're trying to find out why passing through an usb sound card fails with MacOS/OS X on mac99 and came across some things in OHCI that I don't understand so some help from those who know more about USB handling in QEMU or OHCI would be needed.

From traces Howard collected we see that a packet is submitted to libusb
which does not complete immediately so it gets recorded as async but never seems to complete afterwards. Meanwhile some isochronous traffic is happening on a different endpoint but it is then rejected with too many pending packets due to the waiting async packet and things seem to stop at this point.

There is a comment in hw/usb/hcd-ohci.c:1031 in ohci_service_td() that says this is something that is not modelled correctly as it should allow active packets per endpoint while we only have one packet per controller (but maybe there are other problems than this too). The problem seems to be that currently we have this active packet recorded in OHCIState in these fields:

[...]
    /* Active packets.  */
    uint32_t old_ctl;
    USBPacket usb_packet;
    uint8_t usb_buf[8192];
    uint32_t async_td;
    bool async_complete;

    void (*ohci_die)(struct OHCIState *ohci);
} OHCIState;

Then everything in hcd-ohci seems to reuse ohci->usb_packet and I wonder if it can happen that it's overwritten while an async packet is still using it. It seems to be reset calling usb_packet_setup() in two places: ohci_service_td() and ohci_service_iso_td(). While ohci_service_td() checks for ohci->async_td, ohci_service_iso_td() doesn't seem to so maybe it can break the pending async packet if an isochronous request comes in while the other endpoint is waiting for the async packet. If so maybe when the completion is called it won't notice because ohci->usb_packet is already a different packet overwritten by ohci_service_iso_td(). Did I miss some other checks elsewhere that prevent this from happening? (I don't know how USB is handled in QEMU or how OHCI works so it could be I'm not understing this correctly.)

In any case to both fix the device model and to avoid this possible problem described above it seems we would need to ditch the packet and async_td fields from OHCIState and move them to the endpoint to allow one active packet per endpoint. We can get the endpoint from a packet and from ohci so I wonder if we can get the active packet from ep->queue (and how to do that) and then can we find out if it's waiting by checking if this packet's status is USB_PACKET_ASYNC so we don't need to keep track of these in OHCIState. I don't understand this code enough to try to do it but maybe some hints could help.

Thanks,
BALATON Zoltan



reply via email to

[Prev in Thread] Current Thread [Next in Thread]