{"id":3196,"date":"2023-04-06T20:01:01","date_gmt":"2023-04-07T00:01:01","guid":{"rendered":"https:\/\/z-issue.com\/wp\/?p=3196"},"modified":"2023-04-06T20:03:55","modified_gmt":"2023-04-07T00:03:55","slug":"fixing-intel-wi-fi-6-ax200-latency-and-ping-spikes-in-linux","status":"publish","type":"post","link":"https:\/\/z-issue.com\/wp\/fixing-intel-wi-fi-6-ax200-latency-and-ping-spikes-in-linux\/","title":{"rendered":"Fixing Intel Wi-Fi 6 AX200 latency and ping spikes in Linux"},"content":{"rendered":"\n<p>Recently, I purchased a mini-PC with an embedded <a rel=\"noreferrer noopener\" href=\"https:\/\/www.intel.com\/content\/www\/us\/en\/products\/sku\/189347\/intel-wifi-6-ax200-gig\/specifications.html\" target=\"_blank\">Intel Wi-Fi 6 AX200<\/a> wireless chipset and installed <a rel=\"noreferrer noopener\" href=\"https:\/\/www.gentoo.org\/\" target=\"_blank\">Gentoo Linux<\/a> on it.  The reason I purchased the mini-PC was to replace my ageing music server (running <a rel=\"noreferrer noopener\" href=\"https:\/\/www.musicpd.org\/\" target=\"_blank\">MPD<\/a>), 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 <a rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Secure_Shell\" target=\"_blank\">SSH<\/a>.<\/p>\n\n\n\n<p>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 &gt;=5ms to be unacceptable and indicative of an underlying network problem:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ping -c 20 192.168.1.120\nPING 192.168.1.120 (192.168.1.120) 56(84) bytes of data.\n64 bytes from 192.168.1.120: icmp_seq=1 ttl=64 time=<font style=\"color:#FF0000\"><strong>214 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=2 ttl=64 time=30.7 ms\n64 bytes from 192.168.1.120: icmp_seq=3 ttl=64 time=54.4 ms\n64 bytes from 192.168.1.120: icmp_seq=4 ttl=64 time=75.1 ms\n64 bytes from 192.168.1.120: icmp_seq=5 ttl=64 time=97.8 ms\n64 bytes from 192.168.1.120: icmp_seq=6 ttl=64 time=<font style=\"color:#FF0000\"><strong>122 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=7 ttl=64 time=<font style=\"color:#FF0000\"><strong>142 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=8 ttl=64 time=2.46 ms\n64 bytes from 192.168.1.120: icmp_seq=9 ttl=64 time=2.30 ms\n64 bytes from 192.168.1.120: icmp_seq=10 ttl=64 time=4.72 ms\n64 bytes from 192.168.1.120: icmp_seq=11 ttl=64 time=26.3 ms\n64 bytes from 192.168.1.120: icmp_seq=12 ttl=64 time=2.30 ms\n64 bytes from 192.168.1.120: icmp_seq=13 ttl=64 time=71.7 ms\n64 bytes from 192.168.1.120: icmp_seq=14 ttl=64 time=94.6 ms\n64 bytes from 192.168.1.120: icmp_seq=15 ttl=64 time=<font style=\"color:#FF0000\"><strong>116 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=16 ttl=64 time=<font style=\"color:#FF0000\"><strong>139 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=17 ttl=64 time=<font style=\"color:#FF0000\"><strong>161 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=18 ttl=64 time=<font style=\"color:#FF0000\"><strong>184 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=19 ttl=64 time=<font style=\"color:#FF0000\"><strong>205 ms<\/strong><\/font>\n64 bytes from 192.168.1.120: icmp_seq=20 ttl=64 time=23.5 ms<\/code><\/pre>\n\n\n\n<p>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).<\/p>\n\n\n\n<p>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 <a rel=\"noreferrer noopener\" href=\"https:\/\/www.intel.com\/content\/www\/us\/en\/support\/articles\/000005511\/wireless.html\" target=\"_blank\">iwlwifi<\/a> driver, so I didn&#8217;t pay too much attention there.  That driver has two possible modules to use in conjunction:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>DVM (iwldvm)\n<ul class=\"wp-block-list\">\n<li>The module that supports the firmware for a specific group of (primarily) AGN chips<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>MVM (iwlmvm)\n<ul class=\"wp-block-list\">\n<li>The module that supports the firmware for a much broader scope of Intel wireless chips<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>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 <a rel=\"noreferrer noopener\" href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/firmware\/linux-firmware.git\/tree\/\" target=\"_blank\">linux-firmware<\/a> package contains all the various options for the <a rel=\"noreferrer noopener\" href=\"https:\/\/www.intel.com\/content\/www\/us\/en\/support\/articles\/000005511\/wireless.html\" target=\"_blank\">iwlwifi supporting firmware<\/a>, and from that table, I saw that the original firmware for the Intel Wi-Fi 6 AX200 was named:<\/p>\n\n\n\n<p>iwlwifi-cc-46.3cfab8da.0.ucode<\/p>\n\n\n\n<p>Looking at the current linux-firmware git tree (at the time of this writing), the relevant firmware packages were:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>iwlwifi-cc-a0-50.ucode<\/li>\n\n\n\n<li>iwlwifi-cc-a0-59.ucode<\/li>\n\n\n\n<li>iwlwifi-cc-a0-66.ucode<\/li>\n\n\n\n<li>iwlwifi-cc-a0-72.ucode<\/li>\n\n\n\n<li>iwlwifi-cc-a0-73.ucode<\/li>\n\n\n\n<li>iwlwifi-cc-a0-74.ucode<\/li>\n\n\n\n<li>iwlwifi-cc-a0-77.ucode<\/li>\n<\/ul>\n\n\n\n<p>Using my trial-and-error approach of rebooting and looking at the output of <code>dmesg | grep iwlwifi<\/code> 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&#8217;s firmware loader.<\/p>\n\n\n\n<p>After trying various options (such as switching from <a href=\"https:\/\/en.wikipedia.org\/wiki\/Wpa_supplicant\" target=\"_blank\" rel=\"noreferrer noopener\">wpa_supplicant<\/a> to <a href=\"https:\/\/wiki.gentoo.org\/wiki\/Iwd\" target=\"_blank\" rel=\"noreferrer noopener\">iwd<\/a>, and using an older firmware blob), I finally found the fix for the latency and ping spikes: power saving.  By issuing <code>iw wlan0 set power_save off<\/code>, and then starting a new ping test, I could immediately see that the problem was fixed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ping -c 20 192.168.1.120\nPING 192.168.1.120 (192.168.1.120) 56(84) bytes of data.\n64 bytes from 192.168.1.120: icmp_seq=1 ttl=64 time=2.90 ms\n64 bytes from 192.168.1.120: icmp_seq=2 ttl=64 time=1.68 ms\n64 bytes from 192.168.1.120: icmp_seq=3 ttl=64 time=2.43 ms\n64 bytes from 192.168.1.120: icmp_seq=4 ttl=64 time=2.68 ms\n64 bytes from 192.168.1.120: icmp_seq=5 ttl=64 time=3.08 ms\n64 bytes from 192.168.1.120: icmp_seq=6 ttl=64 time=2.80 ms\n64 bytes from 192.168.1.120: icmp_seq=7 ttl=64 time=3.25 ms\n64 bytes from 192.168.1.120: icmp_seq=8 ttl=64 time=3.17 ms\n64 bytes from 192.168.1.120: icmp_seq=9 ttl=64 time=2.83 ms\n64 bytes from 192.168.1.120: icmp_seq=10 ttl=64 time=3.01 ms\n64 bytes from 192.168.1.120: icmp_seq=11 ttl=64 time=2.77 ms\n64 bytes from 192.168.1.120: icmp_seq=12 ttl=64 time=2.80 ms\n64 bytes from 192.168.1.120: icmp_seq=13 ttl=64 time=3.37 ms\n64 bytes from 192.168.1.120: icmp_seq=14 ttl=64 time=2.52 ms\n64 bytes from 192.168.1.120: icmp_seq=15 ttl=64 time=2.71 ms\n64 bytes from 192.168.1.120: icmp_seq=16 ttl=64 time=2.83 ms\n64 bytes from 192.168.1.120: icmp_seq=17 ttl=64 time=3.25 ms\n64 bytes from 192.168.1.120: icmp_seq=18 ttl=64 time=2.78 ms\n64 bytes from 192.168.1.120: icmp_seq=19 ttl=64 time=2.48 ms\n64 bytes from 192.168.1.120: icmp_seq=20 ttl=64 time=3.37 ms\n\n--- 192.168.1.120 ping statistics ---\n20 packets transmitted, 20 received, 0% packet loss, time 19036ms\nrtt min\/avg\/max\/mdev = 1.679\/2.834\/3.371\/0.379 ms<\/code><\/pre>\n\n\n\n<p>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 <code>iw<\/code> command command into an <code>rc.local<\/code> 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 <code>\/etc\/modprobe.d\/iwlwifi.conf<\/code> with the following contents: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cat \/etc\/modprobe.d\/iwlwifi.conf \n\n## Has the same effect has running `iw wlan0 set power_save off`\n## Both options sets are needed as iwlmvm will override iwlwifi :(\noptions iwlwifi power_save=0\n## iwlmvm 1=always on, 2=balanced, 3=low-power\noptions iwlmvm power_scheme=1<\/code><\/pre>\n\n\n\n<p>As I mentioned in the comments there, <strong>BOTH<\/strong> 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 <code>iwlmvm power_scheme<\/code>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1 = always on<\/li>\n\n\n\n<li>2 = balanced<\/li>\n\n\n\n<li>3 = low-power<\/li>\n<\/ul>\n\n\n\n<p>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 <a rel=\"noreferrer noopener\" href=\"https:\/\/wiki.gentoo.org\/wiki\/OpenRC\" target=\"_blank\">OpenRC<\/a> init system that I choose to use, but they should be readily adaptable to other distributions and <a rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Init\" target=\"_blank\">init systems<\/a>.<\/p>\n\n\n\n<p>Cheers,\n<br>\nNathan Zachary<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <\/p>\n<p><a class=\"more-link btn\" href=\"https:\/\/z-issue.com\/wp\/fixing-intel-wi-fi-6-ax200-latency-and-ping-spikes-in-linux\/\">Continue reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,11],"tags":[139,71,54,39,37,59],"class_list":["post-3196","post","type-post","status-publish","format-standard","hentry","category-linux","category-technology","tag-code","tag-gentoo-linux","tag-hardware","tag-linux-tag","tag-networking","tag-software","item-wrap"],"_links":{"self":[{"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/posts\/3196","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/comments?post=3196"}],"version-history":[{"count":5,"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/posts\/3196\/revisions"}],"predecessor-version":[{"id":3202,"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/posts\/3196\/revisions\/3202"}],"wp:attachment":[{"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/media?parent=3196"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/categories?post=3196"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/z-issue.com\/wp\/wp-json\/wp\/v2\/tags?post=3196"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}