diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index dfc84fc17..940e0f830 100644 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -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 diff --git a/devicemodel/include/xhci.h b/devicemodel/include/xhci.h index 2384c6bbd..4220fcad0 100755 --- a/devicemodel/include/xhci.h +++ b/devicemodel/include/xhci.h @@ -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];