DM USB: xHCI: refine the emulation logic for BEI bit in the TRB

The Block Event Interrupt (BEI) bit in the TRB descriptor could
delay the triggering of interrupt. For most OSes, the native
driver for xHCI will use this bit to optimize the IO performence,
due to reduction of number of interrupts.

But in Linux, the native xHCI driver for Intel brand controller
doesn't use this bit. It is fine for the native scenario due to
most work is completed by hardware. But in virtualization scenario,
it is almost impossible to support heavy data IO such as high
resolution video recording (ISOC transfer).

Hence, this issue is solved by a 'quirk' when the intel hardware is
emulated (when vendor id is set as 0x8086). For other cases, a
virtal hardware called 'ACRN xHCI' is emulated, and both Linux and
Windows will use BEI bit by default.

Tracked-On: #3628
Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Xiaoguang Wu 2019-08-15 17:44:06 +08:00 committed by wenlingz
parent 685b1a7b66
commit 7cb45bc968
2 changed files with 38 additions and 13 deletions

View File

@ -419,6 +419,7 @@ struct pci_xhci_vdev {
*/
struct pci_xhci_native_port native_ports[XHCI_MAX_VIRT_PORTS];
struct timespec init_time;
uint32_t quirks;
};
/* portregs and devices arrays are set up to start from idx=1 */
@ -2862,16 +2863,15 @@ pci_xhci_handle_transfer(struct pci_xhci_vdev *xdev,
uint32_t ccs,
uint32_t streamid)
{
struct xhci_trb *setup_trb;
struct usb_xfer *xfer;
struct xhci_block hcb;
struct usb_block *xfer_block;
struct usb_block *prev_block;
uint64_t val;
uint32_t trbflags;
int do_intr, err;
int do_retry;
bool is_isoch = false;
struct xhci_trb *setup_trb;
struct usb_xfer *xfer;
struct xhci_block hcb;
struct usb_block *xfer_block;
struct usb_block *prev_block;
uint64_t val;
uint32_t trbflags;
int do_intr, err;
int do_retry;
ep_ctx->dwEpCtx0 = FIELD_REPLACE(ep_ctx->dwEpCtx0,
XHCI_ST_EPCTX_RUNNING, 0x7, 0);
@ -2956,7 +2956,6 @@ retry:
break;
case XHCI_TRB_TYPE_ISOCH:
is_isoch = true;
/* fall through */
case XHCI_TRB_TYPE_NORMAL:
@ -3043,8 +3042,14 @@ retry:
streamid, addr, ccs);
}
if (is_isoch == true || XHCI_TRB_3_TYPE_GET(trbflags) ==
XHCI_TRB_TYPE_EVENT_DATA /* win10 needs it */)
if (trbflags & XHCI_TRB_3_BEI_BIT)
continue;
if (xdev->quirks & XHCI_QUIRK_INTEL_ISOCH_NO_BEI)
continue;
/* win10 needs it */
if (XHCI_TRB_3_TYPE_GET(trbflags) == XHCI_TRB_TYPE_EVENT_DATA)
continue;
/* handle current batch that requires interrupt on complete */
@ -4026,6 +4031,7 @@ pci_xhci_parse_extcap(struct pci_xhci_vdev *xdev, char *opts)
if (!strncmp(cap, "apl", 3)) {
xdev->excap_write = pci_xhci_apl_drdregs_write;
xdev->excap_ptr = excap_group_apl;
xdev->quirks |= XHCI_QUIRK_INTEL_ISOCH_NO_BEI;
xdev->vid = PCI_INTEL_APL_XHCI_VID;
xdev->pid = PCI_INTEL_APL_XHCI_PID;
} else

View File

@ -366,6 +366,25 @@ struct xhci_trb {
#define XHCI_TRB_ERROR_SPLIT_XACT 0x24
} __aligned(8);
/*
* The Block Event Interrupt (BEI) bit in the TRB descriptor could
* delay the triggering of interrupt. For most OSes, the native
* driver for xHCI will use this bit to optimize the IO performence,
* due to reduction of number of interrupts.
*
* But in Linux, the native xHCI driver for Intel brand controller
* doesn't use this bit. It is fine for the native scenario due to
* most work is completed by hardware. But in virtualization scenario,
* it is almost impossible to support heavy data IO such as high
* resolution video recording (ISOC transfer).
*
* Hence, this issue is solved by a 'quirk' when the intel hardware is
* emulated (when vendor id is set as 0x8086). For other cases, a
* virtal hardware called 'ACRN xHCI' is emulated, and both Linux and
* Windows will use BEI bit by default.
*/
#define XHCI_QUIRK_INTEL_ISOCH_NO_BEI (1 << 0)
struct xhci_dev_endpoint_trbs {
struct xhci_trb trb[(XHCI_MAX_STREAMS *
XHCI_MAX_TRANSFERS) + XHCI_MAX_STREAMS];