Force USB 3.0 Ports to USB 2.0 Mode on Linux
While BIOS settings are the preferred way to disable USB 3.0, you can also force USB 2.0 mode on a running Linux system by manipulating the xHCI controller’s port routing register directly using setpci.
How it works
Intel xHCI controllers use the XUSB2PR (xHC USB 2.0 Port Routing Register) at offset 0xd0. Setting this register to 0 routes USB 2.0 port pins to the EHCI controller instead of the xHCI controller, effectively downgrading the port to USB 2.0 speeds.
Automatic method
To force all USB controllers to USB 2.0 mode in one command:
sudo lspci -nn | grep USB | cut -d '[' -f3 | cut -d ']' -f1 | xargs -I@ sudo setpci -H1 -d @ d0.l=0
This command:
- Lists all USB controllers with their vendor and device IDs
- Extracts the IDs in
VENDOR:DEVICEformat - Passes each ID to
setpcito set register0xd0to0
Manual method
If you prefer explicit control or the automatic method doesn’t work, identify your controllers first:
lspci -nn | grep USB
Example output:
00:14.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB xHCI [8086:8c31] (rev 05)
00:1a.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB EHCI #2 [8086:8c2d] (rev 05)
00:1d.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB EHCI #1 [8086:8c26] (rev 05)
Then apply the register change to each controller:
sudo setpci -H1 -d 8086:8c31 d0.l=0
sudo setpci -H1 -d 8086:8c26 d0.l=0
sudo setpci -H1 -d 8086:8c2d d0.l=0
Verifying the change
Check dmesg for USB disconnect/reconnect events. Devices should now enumerate on the EHCI controller (USB 2.0):
dmesg | tail -20
Look for messages showing the device using ehci-pci instead of xhci_hcd:
usb 2-1.1: new full-speed USB device number 6 using ehci-pci
usb 2-1.1: New USB device found, idVendor=046d, idProduct=c52b
logitech-djreceiver 0003:046D:C52B.0013: hiddev0,hidraw0: USB HID v1.11 Device [Logitech USB Receiver] on usb-0000:00:1d.0-1.1/input2
The PCI path 00:1d.0 indicates EHCI controller usage (USB 2.0 mode).
Reverting to USB 3.0
To restore USB 3.0 mode, set the register back to 1:
sudo setpci -H1 -d 8086:8c31 d0.l=1
After reverting, dmesg should show devices reconnecting via xhci_hcd:
usb 3-1: new full-speed USB device number 9 using xhci_hcd
logitech-djreceiver 0003:046D:C52B.0017: hiddev0,hidraw0: USB HID v1.11 Device [Logitech USB Receiver] on usb-0000:00:14.0-1/input2
Important notes
- This method only works on Intel systems (chipsets with xHCI controllers). AMD and other manufacturers may use different register layouts.
- Changes don’t persist across reboot. Add the command to a systemd service or udev rule if persistence is needed.
- Requires root privileges to run
setpci. - This is a hardware-level change and doesn’t affect the kernel’s USB driver stack directly — it changes controller behavior.
- Some systems may not have this register implemented. If
setpcireturns an error, your chipset doesn’t support this method.
I had a faulty usb flash drive which thanks to your post I fixed it.
How can I use my USB 3.0 again?
You might try `d0.l=1` commands (I didn’t test this). Or simply reboot Linux..
If I do so and I try to use my v4l device (Hercules Webcam), I get this in dmesg:
[363965.965532] usb 3-1.2.1: new full-speed USB device number 10 using ehci-pci
[363966.075645] usb 3-1.2.1: New USB device found, idVendor=06f8, idProduct=3009
[363966.075647] usb 3-1.2.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[363966.202241] media: Linux media interface: v0.10
[363966.236743] Linux video capture interface: v2.00
[363966.275630] gspca_main: v2.14.0 registered
[363966.294248] gspca_main: gspca_pac7302-2.14.0 probing 06f8:3009
[363966.294791] input: gspca_pac7302 as /devices/pci0000:00/0000:00:1a.0/usb3/3-1/3-1.2/3-1.2.1/input/input24
[363966.294928] usbcore: registered new interface driver gspca_pac7302
[364011.422012] gspca_pac7302 3-1.2.1:1.0: alt 6 – bandwidth not wide enough, trying again
[364011.488262] gspca_pac7302 3-1.2.1:1.0: alt 5 – bandwidth not wide enough, trying again
[364030.522898] gspca_pac7302 3-1.2.1:1.0: alt 6 – bandwidth not wide enough, trying again
[364030.589523] gspca_pac7302 3-1.2.1:1.0: alt 5 – bandwidth not wide enough, trying again
[364321.331830] gspca_pac7302 3-1.2.1:1.0: alt 6 – bandwidth not wide enough, trying again
[364321.377832] gspca_pac7302: reg_w_page() failed i: 42 v: 00 error -32
[364321.456486] gspca_pac7302 3-1.2.1:1.0: URB error -71, resubmitting
[364321.552482] gspca_pac7302 3-1.2.1:1.0: URB error -71, resubmitting
[364321.648481] gspca_pac7302 3-1.2.1:1.0: URB error -71, resubmitting
[364321.744484] gspca_pac7302 3-1.2.1:1.0: URB error -71, resubmitting
[364321.840482] gspca_pac7302 3-1.2.1:1.0: URB error -71, resubmitting
[364321.936491] gspca_pac7302 3-1.2.1:1.0: URB error -71, resubmitting
The “bandwidth not wide enough, trying again” are new here, when I enable USB 3.0 again, I still got the URB error messages when I try to $ cat /dev/video0.
If you add the ‘-t’ parameter, the commands that xargs builds and runs will be echoed.
| xargs -t -I@ setpci -H1 -d @ d0.l=1
instead of
| xargs -I@ setpci -H1 -d @ d0.l=0
in my case on a Dell Latitude E7440
root@e7440:~# lspci -nn | grep USB | cut -d ‘[‘ -f3 | cut -d ‘]’ -f1 | xargs -t -I@ setpci -H1 -d @ d0.l=1
setpci -H1 -d 8086:9c31 d0.l=1
setpci -H1 -d 8086:9c26 d0.l=1
root@e7440:~#
The command seems not working on my Latitude E6440, any suggestion?
# lspci -nn | grep USB
00:14.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB xHCI [8086:8c31] (rev 04)
00:1a.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB EHCI #2 [8086:8c2d] (rev 04)
00:1d.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB EHCI #1 [8086:8c26] (rev 04)
# lspci -nn | grep USB | cut -d ‘[‘ -f3 | cut -d ‘]’ -f1 | xargs -t -I@ setpci -H1 -d @ d0.l=0
setpci -H1 -d 8086:8c31 d0.l=0
setpci -H1 -d 8086:8c2d d0.l=0
setpci -H1 -d 8086:8c26 d0.l=0
What OUTPUT/results do you get?
Thanks for the reply :)
What I am trying to do is making a usb hub only work in USB 2.0 mode.
I am trying to use an uhubctl (https://github.com/mvp/uhubctl) command to do per-port power switching with a usbhub, but the hub I have only support per-port power switching in USB 2.0 mode only. The hub is connecting on laptop which only has USB 3.0 port/
By running the command, it will show following information. After execute your command, I still see USB 3.0 “Current status for hub 4-6 [05e3:0617 GenesysLogic USB3.0 Hub, USB 3.00, 4 ports]”.
Is your command work on my scenario?
Hope you can get my point.
—
./uhubctl
Current status for hub 2-1 [8087:8000]
Port 1: 0100 power
…(omitted)
Port 8: 0103 power enable connect [0a5c:5801 Broadcom Corp 5880 0123456789ABCD]
Current status for hub 1-1.2 [05e3:0610 GenesysLogic USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
…(omitted)
Port 4: 0100 power
Current status for hub 1-1 [8087:8008]
Port 1: 0000 off
Port 2: 0507 power highspeed suspend enable connect [05e3:0610 GenesysLogic USB2.0 Hub, USB 2.10, 4 ports]
Port 3: 0000 off
Port 4: 0000 off
Port 5: 0507 power highspeed suspend enable connect [0c45:649d CNFCH52K195010002SI1 Laptop_Integrated_Webcam_HD]
Port 6: 0000 off
Current status for hub 4-6 [05e3:0617 GenesysLogic USB3.0 Hub, USB 3.00, 4 ports]
Port 1: 02a0 power 5gbps Rx.Detect
Port 2: 02a0 power 5gbps Rx.Detect
Port 3: 02a0 power 5gbps Rx.Detect
Port 4: 0203 power 5gbps U0 enable connect [0b95:1790 ASIX Elec. AX88179 0000051BD298C6]
Can you check whether your Linux is running on UEFI or BIOS boot mode? The method in this post may only work if your Linux is running in BIOS boot mode.
I just tried the method in a Ubuntu 18.04 Linux box running under BIOS. The result is as expected. I added the example `demsg` output I got in the post for your reference.
Is it possible to make this permanent? Or do we have to use @reboot cron?
In case anyone looks to do the same on an AMD APU SoC, I hacked up a small too to do this: https://git.sysmocom.de/sysmocom/apu-ehci
The command doesn’t work for AMD controllers, because that name is put into brackets
➜ ~ lspci -nn | grep USB
05:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Renoir/Cezanne USB 3.1 [1022:1639]
05:00.4 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Renoir/Cezanne USB 3.1 [1022:1639]
I’m having the following issue in Fedora 35, even as root:
[root@fedora nathan]# setpci -H1 -d 8086:9a13 d0.l=0
setpci: No permission to access I/O ports (you probably have to be root).
Do you have any idea how to fix this?
use “sudo ” command
If you are still getting this error even if you are root:
setpci: No permission to access I/O ports (you probably have to be root).
… and you are seeing “locked down from EFI Secure Boot mode; see man kernel_lockdown.7” messages in your dmesg, your problem may be because EFI Secure Boot is enabled. The OS restricts certain direct I/O calls in Secure Boot mode.
Solution: disable Secure Boot in your BIOS.