diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index d516979b0681fa..25f2cf049ca99d 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -231,6 +231,16 @@ properties: description: When set, disable u2mac linestate check during HS transmit type: boolean + snps,enhanced-nak-fs-quirk: + description: + When set, the controller schedules many more handshakes to Async FS + endpoints, improving throughput when they frequently respond with NAKs. + + snps,enhanced-nak-hs-quirk: + description: + When set, the controller schedules many more handshakes to Async HS + endpoints, improving throughput when they frequently respond with NAKs. + snps,parkmode-disable-ss-quirk: description: When set, disable park mode for all Superspeed bus instances. diff --git a/arch/arm64/boot/dts/broadcom/rp1.dtsi b/arch/arm64/boot/dts/broadcom/rp1.dtsi index 1f60f3f03a1004..920a3a00d3384c 100644 --- a/arch/arm64/boot/dts/broadcom/rp1.dtsi +++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi @@ -1077,6 +1077,7 @@ usb3-lpm-capable; snps,axi-pipe-limit = /bits/ 8 <8>; snps,dis_rxdet_inp3_quirk; + snps,enhanced-nak-fs-quirk; snps,parkmode-disable-ss-quirk; snps,parkmode-disable-hs-quirk; snps,parkmode-disable-fsls-quirk; @@ -1093,6 +1094,7 @@ usb3-lpm-capable; snps,axi-pipe-limit = /bits/ 8 <8>; snps,dis_rxdet_inp3_quirk; + snps,enhanced-nak-fs-quirk; snps,parkmode-disable-ss-quirk; snps,parkmode-disable-hs-quirk; snps,parkmode-disable-fsls-quirk; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c3c5711316d2e3..545cc4a9b440b1 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1366,6 +1366,12 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->dis_tx_ipgap_linecheck_quirk) reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; + if (dwc->enh_nak_fs_quirk) + reg |= DWC3_GUCTL1_NAK_PER_ENH_FS; + + if (dwc->enh_nak_hs_quirk) + reg |= DWC3_GUCTL1_NAK_PER_ENH_HS; + if (dwc->parkmode_disable_ss_quirk) reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; @@ -1669,6 +1675,10 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,resume-hs-terminations"); dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev, "snps,ulpi-ext-vbus-drv"); + dwc->enh_nak_fs_quirk = device_property_read_bool(dev, + "snps,enhanced-nak-fs-quirk"); + dwc->enh_nak_hs_quirk = device_property_read_bool(dev, + "snps,enhanced-nak-hs-quirk"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, "snps,parkmode-disable-ss-quirk"); dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev, diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 1338b30466af74..0bc9d4a544f882 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -269,6 +269,8 @@ #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) #define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) +#define DWC3_GUCTL1_NAK_PER_ENH_FS BIT(19) +#define DWC3_GUCTL1_NAK_PER_ENH_HS BIT(18) #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) #define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16) #define DWC3_GUCTL1_PARKMODE_DISABLE_FSLS BIT(15) @@ -1117,6 +1119,8 @@ struct dwc3_scratchpad_array { * generation after resume from suspend. * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin * VBUS with an external supply. + * @enh_nak_fs_quirk: Set to schedule more handshakes to Async FS endpoints. + * @enh_nak_hs_quirk: Set to schedule more handshakes to Async HS endpoints. * @parkmode_disable_ss_quirk: If set, disable park mode feature for all * Superspeed instances. * @parkmode_disable_hs_quirk: If set, disable park mode feature for all @@ -1347,6 +1351,8 @@ struct dwc3 { unsigned dis_tx_ipgap_linecheck_quirk:1; unsigned resume_hs_terminations:1; unsigned ulpi_ext_vbus_drv:1; + unsigned enh_nak_fs_quirk:1; + unsigned enh_nak_hs_quirk:1; unsigned parkmode_disable_ss_quirk:1; unsigned parkmode_disable_hs_quirk:1; unsigned parkmode_disable_fsls_quirk:1; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 46268b208e88fa..a9af54cf36d6f1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -505,6 +505,19 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, trace_xhci_ring_ep_doorbell(slot_id, DB_VALUE(ep_index, stream_id)); + /* + * For non-coherent systems with PCIe DMA (such as Pi 4, Pi 5) there + * is a theoretical race between the TRB write and barrier, which + * is reported complete as soon as the write leaves the CPU domain, + * the doorbell write, which may be reported as complete by the RC + * at some arbitrary point, and the visibility of new TRBs in system + * RAM by the endpoint DMA engine. + * + * This read before the write positively serialises the CPU state + * by incurring a round-trip across the link. + */ + readl(db_addr); + writel(DB_VALUE(ep_index, stream_id), db_addr); /* flush the write */ readl(db_addr);