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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.