From: Laszlo Ersek <lersek@redhat.com>
To: Peter Maydell <peter.maydell@linaro.org>
Cc: Alexander Graf <agraf@suse.de>, Gerd Hoffmann <kraxel@redhat.com>,
qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PULL 1/1] xhci: generate a Transfer Event for each Transfer TRB with the IOC bit set
Date: Wed, 04 Mar 2015 10:03:32 +0100 [thread overview]
Message-ID: <54F6CA64.7030801@redhat.com> (raw)
In-Reply-To: <1425370469-15755-2-git-send-email-kraxel@redhat.com>
Hi Peter,
sorry about poking you -- I'm aware you've been on vacation, but in
<http://lists.nongnu.org/archive/html/qemu-devel/2015-03/msg00174.html>
you said you still inteded to pull stuff.
So, can you please pull this? :) I'd like to enable the XHCI driver in
both OVMF and AAVMF, and I'd like to reference the qemu commit in the
edk2 commit messages.
Thanks!
Laszlo
On 03/03/15 09:14, Gerd Hoffmann wrote:
> From: Laszlo Ersek <lersek@redhat.com>
>
> At the moment, when the XHCI driver in edk2
> (MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf) runs on QEMU, with the options
>
> -device nec-usb-xhci -device usb-kbd
>
> it crashes with:
>
> ASSERT MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c(1759):
> TrsRing != ((void*) 0)
>
> The crash hits in the following edk2 call sequence (all files under
> MdeModulePkg/Bus/):
>
> UsbEnumerateNewDev() [Usb/UsbBusDxe/UsbEnumer.c]
> UsbBuildDescTable() [Usb/UsbBusDxe/UsbDesc.c]
> UsbGetDevDesc() [Usb/UsbBusDxe/UsbDesc.c]
> UsbCtrlGetDesc(USB_REQ_GET_DESCRIPTOR) [Usb/UsbBusDxe/UsbDesc.c]
> UsbCtrlRequest() [Usb/UsbBusDxe/UsbDesc.c]
> UsbHcControlTransfer() [Usb/UsbBusDxe/UsbUtility.c]
> XhcControlTransfer() [Pci/XhciDxe/Xhci.c]
> XhcCreateUrb() [Pci/XhciDxe/XhciSched.c]
> XhcCreateTransferTrb() [Pci/XhciDxe/XhciSched.c]
> XhcExecTransfer() [Pci/XhciDxe/XhciSched.c]
> XhcCheckUrbResult() [Pci/XhciDxe/XhciSched.c]
> //
> // look for TRB_TYPE_DATA_STAGE event [1]
> //
> //
> // Store a copy of the device descriptor, as the hub device
> // needs this info to configure endpoint. [2]
> //
> UsbSetConfig() [Usb/UsbBusDxe/UsbDesc.c]
> UsbCtrlRequest(USB_REQ_SET_CONFIG) [Usb/UsbBusDxe/UsbDesc.c]
> UsbHcControlTransfer() [Usb/UsbBusDxe/UsbUtility.c]
> XhcControlTransfer() [Pci/XhciDxe/Xhci.c]
> XhcSetConfigCmd() [Pci/XhciDxe/XhciSched.c]
> XhcInitializeEndpointContext() [Pci/XhciDxe/XhciSched.c]
> //
> // allocate transfer ring for the endpoint [3]
> //
>
> USBKeyboardDriverBindingStart() [Usb/UsbKbDxe/EfiKey.c]
> UsbIoAsyncInterruptTransfer() [Usb/UsbBusDxe/UsbBus.c]
> UsbHcAsyncInterruptTransfer() [Usb/UsbBusDxe/UsbUtility.c]
> XhcAsyncInterruptTransfer() [Pci/XhciDxe/Xhci.c]
> XhcCreateUrb() [Pci/XhciDxe/Xhci.c]
> XhcCreateTransferTrb() [Pci/XhciDxe/XhciSched.c]
> XhcSyncTrsRing() [Pci/XhciDxe/XhciSched.c]
> ASSERT (TrsRing != NULL) [4]
>
> UsbEnumerateNewDev() in the USB bus driver issues a GET_DESCRIPTOR
> request, in order to determine the number of configurations that the
> endpoint supports. The requests consists of three stages (three TRBs),
> setup, data, and status. The length of the response is determined in [1],
> namely from the transfer event that the host controller generates in
> response to the request's middle stage (ie. the data stage).
>
> If the length of the answer is correct (a full GET_DESCRIPTOR request
> takes 18 bytes), then the XHCI driver that underlies the USB bus driver
> "snoops" (caches) the descriptor data for later [2].
>
> Later, the USB bus driver sends a SET_CONFIG request. The underlying XHCI
> driver allocates a transfer ring for the endpoint, relying on the data
> snooped and cached in step [2].
>
> Finally, the USB keyboard driver submits an asynchronous interrupt
> transfer to manage the keyboard. As part of this it asserts [4] that the
> ring has been allocated in step [3].
>
> And this ASSERT() fires. The root cause can be found in the way QEMU
> handles the initial GET_DESCRIPTOR request.
>
> Again, that request consists of three stages (TRBs, Transfer Request
> Blocks), "setup", "data", and "status". The XhcCreateTransferTrb()
> function sets the IOC ("Interrupt on Completion") flag in each of these
> TRBs.
>
> According to the XHCI specification, the host controller shall generate a
> Transfer Event in response to *each* individual TRB of the request that
> had the IOC flag set. This means that QEMU should queue three events:
> setup, data, and status, for edk2's XHCI driver.
>
> However, QEMU only generates two events:
> - one for the setup (ie. 1st) stage,
> - another for the status (ie. 3rd) stage.
>
> No event is generated for the middle (ie. data) stage. The loop in QEMU's
> xhci_xfer_report() function runs three times, but due to the "reported"
> variable, only the first and the last TRBs elicit events, the middle (data
> stage) results in no event queued.
>
> As a consequence:
> - When handling the GET_DESCRIPTOR request, XhcCheckUrbResult() in [1]
> does not update the response length from zero.
>
> - XhcControlTransfer() thinks that the response is invalid (it has zero
> length payload instead of 18 bytes), hence [2] is not reached; the
> device descriptor is not stashed for later, and the number of possible
> configurations is left at zero.
>
> - When handling the SET_CONFIG request, (NumConfigurations == 0) from
> above prevents the allocation of the endpoint's transfer ring.
>
> - When the keyboard driver tries to use the endpoint, the ASSERT() blows
> up.
>
> The solution is to correct the emulation in QEMU, and to generate a
> transfer event whenever IOC is set in a TRB.
>
> The patch replaces
>
> !reported && (IOC || foo) == !reported && IOC ||
> !reported && foo
>
> with
>
> IOC || (!reported && foo) == IOC ||
> !reported && foo
>
> which only changes how
>
> reported && IOC
>
> is handled. (Namely, it now generates an event.)
>
> Tested with edk2 built for "qemu-system-aarch64 -M virt" (ie.
> "ArmVirtualizationQemu.dsc", aka "AAVMF"), and guest Linux.
>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> hw/usb/hcd-xhci.c | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
> index 776699b..828c2a7 100644
> --- a/hw/usb/hcd-xhci.c
> +++ b/hw/usb/hcd-xhci.c
> @@ -1767,9 +1767,18 @@ static void xhci_xfer_report(XHCITransfer *xfer)
> break;
> }
>
> - if (!reported && ((trb->control & TRB_TR_IOC) ||
> - (shortpkt && (trb->control & TRB_TR_ISP)) ||
> - (xfer->status != CC_SUCCESS && left == 0))) {
> + /*
> + * XHCI 1.1, 4.11.3.1 Transfer Event TRB -- "each Transfer TRB
> + * encountered with its IOC flag set to '1' shall generate a Transfer
> + * Event."
> + *
> + * Otherwise, longer transfers can have multiple data TRBs (for scatter
> + * gather). Short transfers and errors should be reported once per
> + * transfer only.
> + */
> + if ((trb->control & TRB_TR_IOC) ||
> + (!reported && ((shortpkt && (trb->control & TRB_TR_ISP)) ||
> + (xfer->status != CC_SUCCESS && left == 0)))) {
> event.slotid = xfer->slotid;
> event.epid = xfer->epid;
> event.length = (trb->status & 0x1ffff) - chunk;
>
next prev parent reply other threads:[~2015-03-04 9:03 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-03 8:14 [Qemu-devel] [PULL 0/1] xhci: generate a Transfer Event for each Transfer TRB with the IOC bit set Gerd Hoffmann
2015-03-03 8:14 ` [Qemu-devel] [PULL 1/1] " Gerd Hoffmann
2015-03-04 9:03 ` Laszlo Ersek [this message]
2015-03-04 11:02 ` Gerd Hoffmann
2015-03-04 14:10 ` Peter Maydell
2015-03-04 15:51 ` Laszlo Ersek
2015-03-08 8:36 ` [Qemu-devel] [PULL 0/1] " Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54F6CA64.7030801@redhat.com \
--to=lersek@redhat.com \
--cc=agraf@suse.de \
--cc=kraxel@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).