Fixing Intel Wi-Fi 6 AX200 latency and ping spikes in Linux

Recently, I purchased a mini-PC with an embedded Intel Wi-Fi 6 AX200 wireless chipset and installed Gentoo Linux on it. The reason I purchased the mini-PC was to replace my ageing music server (running MPD), but I also wanted to use it for playing retro video games through my entertainment centre. Everything went well with the OS installation, but during that time, I had it plugged into my router via a wired connection. Once I moved the mini-PC into place in my sitting room and started using the wireless connection, I noticed that there was substantial lag even when doing something simple like typing in a terminal via SSH.

A quick ping test showed that there was clearly a problem with the wireless. For my home network, I consider any ping response time of >=5ms to be unacceptable and indicative of an underlying network problem:

$ ping -c 20 192.168.1.120
PING 192.168.1.120 (192.168.1.120) 56(84) bytes of data.
64 bytes from 192.168.1.120: icmp_seq=1 ttl=64 time=214 ms
64 bytes from 192.168.1.120: icmp_seq=2 ttl=64 time=30.7 ms
64 bytes from 192.168.1.120: icmp_seq=3 ttl=64 time=54.4 ms
64 bytes from 192.168.1.120: icmp_seq=4 ttl=64 time=75.1 ms
64 bytes from 192.168.1.120: icmp_seq=5 ttl=64 time=97.8 ms
64 bytes from 192.168.1.120: icmp_seq=6 ttl=64 time=122 ms
64 bytes from 192.168.1.120: icmp_seq=7 ttl=64 time=142 ms
64 bytes from 192.168.1.120: icmp_seq=8 ttl=64 time=2.46 ms
64 bytes from 192.168.1.120: icmp_seq=9 ttl=64 time=2.30 ms
64 bytes from 192.168.1.120: icmp_seq=10 ttl=64 time=4.72 ms
64 bytes from 192.168.1.120: icmp_seq=11 ttl=64 time=26.3 ms
64 bytes from 192.168.1.120: icmp_seq=12 ttl=64 time=2.30 ms
64 bytes from 192.168.1.120: icmp_seq=13 ttl=64 time=71.7 ms
64 bytes from 192.168.1.120: icmp_seq=14 ttl=64 time=94.6 ms
64 bytes from 192.168.1.120: icmp_seq=15 ttl=64 time=116 ms
64 bytes from 192.168.1.120: icmp_seq=16 ttl=64 time=139 ms
64 bytes from 192.168.1.120: icmp_seq=17 ttl=64 time=161 ms
64 bytes from 192.168.1.120: icmp_seq=18 ttl=64 time=184 ms
64 bytes from 192.168.1.120: icmp_seq=19 ttl=64 time=205 ms
64 bytes from 192.168.1.120: icmp_seq=20 ttl=64 time=23.5 ms

Though 4 of the 20 ping response times were under my 5-millisecond threshold, the other 16 were not only above it, but many of them were nonsensically high for a small home network (e.g. 214ms).

In this type of scenario, the first thing that I consider is the driver and/or firmware for the wireless adapter (namely, the Intel Wi-Fi 6 AX200). For nearly all modern Intel wireless chips the Linux driver is the in-kernel iwlwifi driver, so I didn’t pay too much attention there. That driver has two possible modules to use in conjunction:

  • DVM (iwldvm)
    • The module that supports the firmware for a specific group of (primarily) AGN chips
  • MVM (iwlmvm)
    • The module that supports the firmware for a much broader scope of Intel wireless chips

I had chosen the iwlmvm module and built it into my kernel for convenience. I also then chose to load the corresponding firmware directly into the kernel as well. The gigantic linux-firmware package contains all the various options for the iwlwifi supporting firmware, and from that table, I saw that the original firmware for the Intel Wi-Fi 6 AX200 was named:

iwlwifi-cc-46.3cfab8da.0.ucode

Looking at the current linux-firmware git tree (at the time of this writing), the relevant firmware packages were:

  • iwlwifi-cc-a0-50.ucode
  • iwlwifi-cc-a0-59.ucode
  • iwlwifi-cc-a0-66.ucode
  • iwlwifi-cc-a0-72.ucode
  • iwlwifi-cc-a0-73.ucode
  • iwlwifi-cc-a0-74.ucode
  • iwlwifi-cc-a0-77.ucode

Using my trial-and-error approach of rebooting and looking at the output of dmesg | grep iwlwifi to find the first version the kernel attempted (but failed) to load, I found that the correct version was iwl-cc-a0-72.ucode, and passed via the kernel’s firmware loader.

After trying various options (such as switching from wpa_supplicant to iwd, and using an older firmware blob), I finally found the fix for the latency and ping spikes: power saving. By issuing iw wlan0 set power_save off, and then starting a new ping test, I could immediately see that the problem was fixed:

$ ping -c 20 192.168.1.120
PING 192.168.1.120 (192.168.1.120) 56(84) bytes of data.
64 bytes from 192.168.1.120: icmp_seq=1 ttl=64 time=2.90 ms
64 bytes from 192.168.1.120: icmp_seq=2 ttl=64 time=1.68 ms
64 bytes from 192.168.1.120: icmp_seq=3 ttl=64 time=2.43 ms
64 bytes from 192.168.1.120: icmp_seq=4 ttl=64 time=2.68 ms
64 bytes from 192.168.1.120: icmp_seq=5 ttl=64 time=3.08 ms
64 bytes from 192.168.1.120: icmp_seq=6 ttl=64 time=2.80 ms
64 bytes from 192.168.1.120: icmp_seq=7 ttl=64 time=3.25 ms
64 bytes from 192.168.1.120: icmp_seq=8 ttl=64 time=3.17 ms
64 bytes from 192.168.1.120: icmp_seq=9 ttl=64 time=2.83 ms
64 bytes from 192.168.1.120: icmp_seq=10 ttl=64 time=3.01 ms
64 bytes from 192.168.1.120: icmp_seq=11 ttl=64 time=2.77 ms
64 bytes from 192.168.1.120: icmp_seq=12 ttl=64 time=2.80 ms
64 bytes from 192.168.1.120: icmp_seq=13 ttl=64 time=3.37 ms
64 bytes from 192.168.1.120: icmp_seq=14 ttl=64 time=2.52 ms
64 bytes from 192.168.1.120: icmp_seq=15 ttl=64 time=2.71 ms
64 bytes from 192.168.1.120: icmp_seq=16 ttl=64 time=2.83 ms
64 bytes from 192.168.1.120: icmp_seq=17 ttl=64 time=3.25 ms
64 bytes from 192.168.1.120: icmp_seq=18 ttl=64 time=2.78 ms
64 bytes from 192.168.1.120: icmp_seq=19 ttl=64 time=2.48 ms
64 bytes from 192.168.1.120: icmp_seq=20 ttl=64 time=3.37 ms

--- 192.168.1.120 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19036ms
rtt min/avg/max/mdev = 1.679/2.834/3.371/0.379 ms

Now that I had found the solution to the problem, the next task was to make the changes persistent across reboots. Of course, I could throw that iw command command into an rc.local script or something like that, but that seemed hackish to me. Instead, I decided to change my approach for loading the iwlwifi driver and firmware. Rather than having both the driver and the firmware built-in to the kernel, I chose to load them as kernel modules. Doing so allowed me to pass configuration options to the modules when they load. I made a configuration file at /etc/modprobe.d/iwlwifi.conf with the following contents:

$ cat /etc/modprobe.d/iwlwifi.conf 

## Has the same effect has running `iw wlan0 set power_save off`
## Both options sets are needed as iwlmvm will override iwlwifi :(
options iwlwifi power_save=0
## iwlmvm 1=always on, 2=balanced, 3=low-power
options iwlmvm power_scheme=1

As I mentioned in the comments there, BOTH options need to be set: one option passed to the iwlwifi module and the other option passed to the iwlmvm module. Also note the available parameters for the iwlmvm power_scheme:

  • 1 = always on
  • 2 = balanced
  • 3 = low-power

I have validated that these settings work across reboots, and that I no longer see the latency or ping spikes when connecting to this mini-PC over the Intel Wi-Fi 6 AX200. Some of these instructions may be specific to Gentoo and/or the OpenRC init system that I choose to use, but they should be readily adaptable to other distributions and init systems.

Cheers,
Nathan Zachary

14 comments

Skip to comment form

    • Anders on Monday, 21 October 2024 at 16:23
    • Reply

    Thanks so much for sharing this Nathan! Most appreciated!

      • Zach on Monday, 21 October 2024 at 16:43
        Author
      • Reply

      You’re welcome, Anders. I’m glad that the article helped you. 🙂

  1. ssh sessions to my old Dell laptop were driving me mad with this, also Gentoo. Your suggested iwlwifi.conf immediately solved the problem thank you. You should stick this on the Gentoo wiki!

      • Zach on Tuesday, 14 May 2024 at 14:56
        Author
      • Reply

      I’m glad that the article helped you, Ninpo. The article is actually already referenced in the Gentoo Wiki for iwlwifi:

      https://wiki.gentoo.org/wiki/Iwlwifi#External_resources

      Cheers,
      Nathan Zachary

    • Weifan on Friday, 5 April 2024 at 05:41
    • Reply

    Awesome! You saved me!

      • Zach on Friday, 5 April 2024 at 10:18
        Author
      • Reply

      Glad that the article helped you, Weifan!

    • tsingkong on Monday, 4 March 2024 at 03:39
    • Reply

    I struggled with the exact same issue and your post helped me a lot too. Thank you!

      • Zach on Monday, 4 March 2024 at 11:18
        Author
      • Reply

      I’m glad that the article helped you fix your problem.

    • Kirill on Sunday, 25 February 2024 at 07:54
    • Reply

    Thanks Man!
    It does help!!!

      • Zach on Monday, 26 February 2024 at 11:18
        Author
      • Reply

      You’re welcome, Kirill. I’m glad that it helped.

      Cheers,
      Nathan Zachary

    • person on Friday, 9 February 2024 at 13:27
    • Reply

    This along with adding disable_11x=Y in the iwlwifi.conf helped!!

    Thank you so much

      • Zach on Friday, 9 February 2024 at 14:16
        Author
      • Reply

      I’m glad that it helped you! 🙂

      Cheers,
      Zach

    • 1v0dev on Saturday, 8 July 2023 at 02:46
    • Reply

    I struggled with the exact same issue and your post helped me a lot. Thank you!

      • Zach on Saturday, 8 July 2023 at 14:10
        Author
      • Reply

      Very glad that it helped you fix the problem. Thank you for taking the time to comment. 🙂

Leave a Reply

Your email address will not be published.