The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v2] usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits
@ 2026-06-29  2:48 Xincheng Zhang
  2026-06-29  5:09 ` Michal Pecio
  0 siblings, 1 reply; 3+ messages in thread
From: Xincheng Zhang @ 2026-06-29  2:48 UTC (permalink / raw)
  To: Mathias Nyman, Greg Kroah-Hartman
  Cc: Michal Pecio, Forest Crossman, linux-usb, linux-kernel,
	Xincheng Zhang

The VIA VL805/806 xHCI controller advertises AC64, but fails to handle
DMA addresses at or above 0x1000000000. On systems with large amounts of
RAM, this can cause USB device failures when the controller is given DMA
addresses beyond its usable address width.

Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears
the cached AC64 capability and limits DMA to 32 bits, causing unnecessary
bouncing for addresses between 4GiB and 64GiB and hiding the controller's
real AC64 capability from code that may need to distinguish register
access width from usable DMA address width.

Add a separate xHCI quirk for controllers whose usable DMA address width
is limited to 36 bits, and apply it to VIA VL805/806. This keeps AC64
visible while restricting the DMA mask to exactly the range that the
controller can handle.

Cc: stable@vger.kernel.org
Signed-off-by: Xincheng Zhang <zhangxincheng@ultrarisc.com>
---
Changes in v2:
- Replace XHCI_NO_64BIT_SUPPORT with a dedicated 36-bit DMA mask quirk.
- Preserve HCCPARAMS1.AC64 instead of clearing it for VL805/806.
- Limit VL805/806 DMA to DMA_BIT_MASK(36) instead of 32-bit.
- Add a stable Cc trailer.
- Link to v1: https://lore.kernel.org/all/20260623-xhci-via-dma-fix-v1-1-3f12c81a1cf8@ultrarisc.com/
---
 drivers/usb/host/xhci-pci.c |  1 +
 drivers/usb/host/xhci.c     | 30 ++++++++++++++++++++++++------
 drivers/usb/host/xhci.h     |  1 +
 3 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 039c26b241d0..e5618551e022 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
 		xhci->quirks |= XHCI_LPM_SUPPORT;
 		xhci->quirks |= XHCI_TRB_OVERFETCH;
+		xhci->quirks |= XHCI_LIMIT_36BIT_DMA;
 	}
 
 	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6922cc5496c1..fa546e5cd300 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5506,13 +5506,31 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	if (xhci->quirks & XHCI_NO_64BIT_SUPPORT)
 		xhci->hcc_params &= ~BIT(0);
 
-	/* Set dma_mask and coherent_dma_mask to 64-bits,
-	 * if xHC supports 64-bit addressing */
-	if ((xhci->hcc_params & HCC_64BIT_ADDR) &&
-			!dma_set_mask(dev, DMA_BIT_MASK(64))) {
-		xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
+	/*
+	 * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports
+	 * 64-bit addressing, unless a controller-specific quirk limits the
+	 * usable address width.
+	 */
+	if (xhci->hcc_params & HCC_64BIT_ADDR) {
+		u64 dma_mask = DMA_BIT_MASK(64);
+		unsigned int dma_bits = 64;
+
+		if (xhci->quirks & XHCI_LIMIT_36BIT_DMA) {
+			dma_mask = DMA_BIT_MASK(36);
+			dma_bits = 36;
+		}
+
+		retval = dma_set_mask(dev, dma_mask);
+		if (!retval) {
+			xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n",
+				 dma_bits);
+			dma_set_coherent_mask(dev, dma_mask);
+		}
 	} else {
+		retval = -ENODEV;
+	}
+
+	if (retval) {
 		/*
 		 * This is to avoid error in cases where a 32-bit USB
 		 * controller is used on a 64-bit capable system.
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index d02046a573e4..e737ab36d0a3 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1647,6 +1647,7 @@ struct xhci_hcd {
 #define XHCI_CDNS_SCTX_QUIRK	BIT_ULL(48)
 #define XHCI_ETRON_HOST	BIT_ULL(49)
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_9 BIT_ULL(50)
+#define XHCI_LIMIT_36BIT_DMA	BIT_ULL(51)
 
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;

---
base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
change-id: 20260623-xhci-via-dma-fix-c563b889ea54

Best regards,
--  
Xincheng Zhang <zhangxincheng@ultrarisc.com>


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits
  2026-06-29  2:48 [PATCH v2] usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits Xincheng Zhang
@ 2026-06-29  5:09 ` Michal Pecio
  2026-06-29  7:28   ` Xincheng Zhang
  0 siblings, 1 reply; 3+ messages in thread
From: Michal Pecio @ 2026-06-29  5:09 UTC (permalink / raw)
  To: Xincheng Zhang
  Cc: Mathias Nyman, Greg Kroah-Hartman, Forest Crossman, linux-usb,
	linux-kernel

On Mon, 29 Jun 2026 10:48:13 +0800, Xincheng Zhang wrote:
> The VIA VL805/806 xHCI controller advertises AC64, but fails to handle
> DMA addresses at or above 0x1000000000. On systems with large amounts of
> RAM, this can cause USB device failures when the controller is given DMA
> addresses beyond its usable address width.
> 
> Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears
> the cached AC64 capability and limits DMA to 32 bits, causing unnecessary
> bouncing for addresses between 4GiB and 64GiB and hiding the controller's
> real AC64 capability from code that may need to distinguish register
> access width from usable DMA address width.
> 
> Add a separate xHCI quirk for controllers whose usable DMA address width
> is limited to 36 bits, and apply it to VIA VL805/806. This keeps AC64
> visible while restricting the DMA mask to exactly the range that the
> controller can handle.

This may turn into multiple quirks differing only in the number at the
end. For example, ASMedia chips appear to be limited to 48 bits and we
don't even know if these two are the only bad vendors. I briefly tested
Etron and NEC/Renesas, they seem to be OK, but there are others. 

The driver is getting dangerously close to filling quirks bitmap and
needing changes to support more than 64 quirks.

Alternatively, I think your 'dma_bits' variable could be allocated at
the beginning and initialized to 64, then passed by reference to
get_quirks() so it can tweak it, and lastly clamped to 32 if the AC64
capability is absent or disabled by quirk.

> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Xincheng Zhang <zhangxincheng@ultrarisc.com>
> ---
> Changes in v2:
> - Replace XHCI_NO_64BIT_SUPPORT with a dedicated 36-bit DMA mask quirk.
> - Preserve HCCPARAMS1.AC64 instead of clearing it for VL805/806.
> - Limit VL805/806 DMA to DMA_BIT_MASK(36) instead of 32-bit.
> - Add a stable Cc trailer.
> - Link to v1: https://lore.kernel.org/all/20260623-xhci-via-dma-fix-v1-1-3f12c81a1cf8@ultrarisc.com/
> ---
>  drivers/usb/host/xhci-pci.c |  1 +
>  drivers/usb/host/xhci.c     | 30 ++++++++++++++++++++++++------
>  drivers/usb/host/xhci.h     |  1 +
>  3 files changed, 26 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index 039c26b241d0..e5618551e022 100644
> --- a/drivers/usb/host/xhci-pci.c
> +++ b/drivers/usb/host/xhci-pci.c
> @@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
>  	if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
>  		xhci->quirks |= XHCI_LPM_SUPPORT;
>  		xhci->quirks |= XHCI_TRB_OVERFETCH;
> +		xhci->quirks |= XHCI_LIMIT_36BIT_DMA;
>  	}
>  
>  	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index 6922cc5496c1..fa546e5cd300 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -5506,13 +5506,31 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
>  	if (xhci->quirks & XHCI_NO_64BIT_SUPPORT)
>  		xhci->hcc_params &= ~BIT(0);
>  
> -	/* Set dma_mask and coherent_dma_mask to 64-bits,
> -	 * if xHC supports 64-bit addressing */
> -	if ((xhci->hcc_params & HCC_64BIT_ADDR) &&
> -			!dma_set_mask(dev, DMA_BIT_MASK(64))) {
> -		xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
> -		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
> +	/*
> +	 * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports
> +	 * 64-bit addressing, unless a controller-specific quirk limits the
> +	 * usable address width.
> +	 */
> +	if (xhci->hcc_params & HCC_64BIT_ADDR) {
> +		u64 dma_mask = DMA_BIT_MASK(64);
> +		unsigned int dma_bits = 64;
> +
> +		if (xhci->quirks & XHCI_LIMIT_36BIT_DMA) {
> +			dma_mask = DMA_BIT_MASK(36);
> +			dma_bits = 36;
> +		}
> +
> +		retval = dma_set_mask(dev, dma_mask);
> +		if (!retval) {
> +			xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n",
> +				 dma_bits);
> +			dma_set_coherent_mask(dev, dma_mask);
> +		}
>  	} else {
> +		retval = -ENODEV;
> +	}
> +
> +	if (retval) {
>  		/*
>  		 * This is to avoid error in cases where a 32-bit USB
>  		 * controller is used on a 64-bit capable system.

I'm not sure if we really need this second call to dma_set_mask() below
when the first call fails? This code was added by fda182d80a0bf and it
really should have been an 'else' to the check for AC64 capbality, not
to the capability *and* having successfully enabled 64 bit DMA.

OTOH, one could argue against cleaning this up in a stable patch.

> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index d02046a573e4..e737ab36d0a3 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1647,6 +1647,7 @@ struct xhci_hcd {
>  #define XHCI_CDNS_SCTX_QUIRK	BIT_ULL(48)
>  #define XHCI_ETRON_HOST	BIT_ULL(49)
>  #define XHCI_LIMIT_ENDPOINT_INTERVAL_9 BIT_ULL(50)
> +#define XHCI_LIMIT_36BIT_DMA	BIT_ULL(51)
>  
>  	unsigned int		num_active_eps;
>  	unsigned int		limit_active_eps;
> 
> ---
> base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
> change-id: 20260623-xhci-via-dma-fix-c563b889ea54
> 
> Best regards,
> --  
> Xincheng Zhang <zhangxincheng@ultrarisc.com>
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits
  2026-06-29  5:09 ` Michal Pecio
@ 2026-06-29  7:28   ` Xincheng Zhang
  0 siblings, 0 replies; 3+ messages in thread
From: Xincheng Zhang @ 2026-06-29  7:28 UTC (permalink / raw)
  To: Michal Pecio
  Cc: Xincheng Zhang, Mathias Nyman, Greg Kroah-Hartman,
	Forest Crossman, linux-usb, linux-kernel

Hi Michal,

On Mon, Jun 29, 2026 at 07:09:06AM +0200, Michal Pecio wrote:
> This may turn into multiple quirks differing only in the number at the
> end. For example, ASMedia chips appear to be limited to 48 bits and we
> don't even know if these two are the only bad vendors. I briefly tested
> Etron and NEC/Renesas, they seem to be OK, but there are others.
>
> The driver is getting dangerously close to filling quirks bitmap and
> needing changes to support more than 64 quirks.
>
> Alternatively, I think your 'dma_bits' variable could be allocated at
> the beginning and initialized to 64, then passed by reference to
> get_quirks() so it can tweak it, and lastly clamped to 32 if the AC64
> capability is absent or disabled by quirk.

Thanks, this makes sense.

I reworked v3 to avoid consuming a new xHCI quirk bit for each possible
DMA address width. Instead, struct xhci_hcd now has a generic
dma_mask_bits field. xhci_gen_setup() initializes it to 64 before
calling get_quirks(), and the VIA VL805/806 PCI quirk sets it to 36.

The DMA mask setup then uses DMA_BIT_MASK(xhci->dma_mask_bits), while
still preserving HCCPARAMS1.AC64 for VL805/806.

> I'm not sure if we really need this second call to dma_set_mask() below
> when the first call fails? This code was added by fda182d80a0bf and it
> really should have been an 'else' to the check for AC64 capbality, not
> to the capability *and* having successfully enabled 64 bit DMA.
>
> OTOH, one could argue against cleaning this up in a stable patch.

I left the existing 32-bit fallback behavior unchanged in v3, since this
patch is intended to stay narrowly scoped for stable.

Thanks,
Xincheng


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-06-29  7:28 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-29  2:48 [PATCH v2] usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits Xincheng Zhang
2026-06-29  5:09 ` Michal Pecio
2026-06-29  7:28   ` Xincheng Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox