Replacing the Framework Laptop's Intel AX210 wireless with the Atheros AR9462 (FreeBSD)

Author: Jonathan Vasquez <jon@xyinn.org>
Last Updated: 2023-05-16-1830
Running On: FreeBSD 13.2-RELEASE (releng/13.2-n254617-525ecfdad597/GENERIC/amd64)

Preface

As you are all already aware, I've been having issues with the Intel AX210 on FreeBSD for a while. The FreeBSD iwlwifi driver is still a work in progress and isn't production ready yet. It is currently only limited for 802.11g speeds, and due to crashes, it will cause the system to crash when resuming, which means you basically don't have sleep. There may also be other issues/crashes. The workaround is to use wifibox which essentially means you will be running a small Linux VM through bhyve, and you'll pass the wireless device into it. Allowing you to get full speeds via Linux. However doing this also brings its own set of issues, especially if you are trying to seamlessly access network resources on the same network, or mess around with your machine's firewall. On my laptop, I've also been experiencing a bug where after resuming from sleep, the bhyve vm will no longer see the wireless interface, which means that the only way to restore it is to reboot the machine.

After living with all of these things for about a year, I luckily found a comment online where someone mentioned that they have their wireless card working flawlessly on FreeBSD on their Framework Laptop using the Atheros AR9462 M.2 2230 (NGFF) E Key Card sold by ThinkPenguin. The Framework Laptop supports both, the M.2 E slot, and also A+E slot. After a few days of waiting in the mail, I received it and immediately replaced my card. I still need more time to test it but so far it's been working amazingly well. FreeBSD 13.2-RELEASE picked it up immediately and I pretty much just added the ath0 interface to /etc/rc.conf, told it to use DHCP, and used my previously backed up /etc/wpa_supplicant.conf. It connected immediately. The nice thing was that since I feel much more confident about the ath9k driver in FreeBSD not having many bugs, I was able to figure out another weird wireless problem I was experiencing which basically allowed my laptop (on both the Intel AX210 and the AR9462) to associate to my AP on the 5 Ghz frequency (it seems), but it pretty much always failed to get a DHCP address. Even assigning a static IP didn't seem to help. The long story short is that the router that I was using for years, the Linksys WRT3200ACM (flashed with DD-WRT), is actually a very buggy router when it comes to wifi. Despite me using it for years and not experiencing any noticable issues on any of my devices (including the framework laptop with the AX210 when I had Windows/Linux on it), using it on FreeBSD for whatever reason, even with the Atheros card, just didn't work well. I finally replaced the the WRT3200ACM with a brand new ASUS RT-AX88U PRO and flashed ASUSWRT-Merlin (version 388.2_2) on it, it's been working amazingly well. The AR9462 on FreeBSD had no issues connecting to it on both, 2.4 and 5 ghz frequencies, and was able to get DHCPOFFERS/DHCPACKs back to back, successfully, 100% of the time. I also tested the laptop at my mom's house when I went over there for Mother's Day (US), and her combined modem/router allowed me to associate with no issues, and offered the IP over dhcp 100% of the time.

So with that said, so far, sleep/resume is working, wifi is associating and getting a DHCP license perfectly fine, it connected to my network using the 5 Ghz frequency from what we can see below, and speeds are not bad. Transferring a 2 GB ISO from my server over Wifi 5 GHz transferred relatively quickly with a sustained transfer speed of 14.1 MB/s (sometimes it went to 14.2 MB/s). This is now faster than my ethernet expansion card which is capped at 10 Mbps, and I'm guessing its due to the Type C port and FreeBSD not having Thunderbolt / USB 4. That's causing a whole other set of issues, but luckily I've worked around most of that. Anyways, this was meant to be an update on this whole framework wifi issue.

Overall, if you are in the market to get a FreeBSD compatible M.2 card, I highly recommend this one from ThinkPenguin. Make sure that you are also using a router that's not going to give you wifi issues >.<.

Below you can find some of the system output:

// These commands are just for debugging purposes. Wifi interface creation, association,
// and IP retrieval is normally automated in /etc/rc.conf:

// Clean start
root@leslie:~ # ifconfig wlan0 destroy ; killall dhclient ; killall wpa_supplicant ; rm /var/db/dhclient.leases.

// Create interface and associate (5 GHz Frequency - frequency selection is done using the `bssid` tag for the particular ssid & antenna I want and written in `/etc/wpa_supplicant.conf`:
root@leslie:~ # ifconfig wlan0 create wlandev ath0 && ifconfig wlan0 up && wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf

Successfully initialized wpa_supplicant
ioctl[SIOCS80211, op=20, val=0, arg_len=7]: Invalid argument
ioctl[SIOCS80211, op=20, val=0, arg_len=7]: Invalid argument
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
wlan0: Trying to associate with YY:YY:YY:YY:YY:YY (SSID='SSID' freq=5200 MHz)
wlan0: Associated with YY:YY:YY:YY:YY:YY
wlan0: WPA: Key negotiation completed with YY:YY:YY:YY:YY:YY [PTK=CCMP GTK=CCMP]
wlan0: CTRL-EVENT-CONNECTED - Connection to YY:YY:YY:YY:YY:YY completed [id=0 id_str=]

// Request IP from DHCP Server
root@leslie:~ # dhclient wlan0
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 4
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 11
DHCPOFFER from 192.168.1.1
DHCPREQUEST on wlan0 to 255.255.255.255 port 67
DHCPACK from 192.168.1.1
bound to 192.168.1.232 -- renewal in 43200 seconds.
root@leslie:~ # ping google.com
PING google.com (142.250.72.110): 56 data bytes
64 bytes from 142.250.72.110: icmp_seq=0 ttl=116 time=13.792 ms
64 bytes from 142.250.72.110: icmp_seq=1 ttl=116 time=13.365 ms

// Interface info on 5 GHz Frequency
root@leslie:~ # ifconfig wlan0
        wlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether XX:XX:XX:XX:XX:XX
        groups: wlan
        ssid SSID channel 40 (5200 MHz 11a ht/40-) bssid YY:YY:YY:YY:YY:YY
        regdomain 105 indoor ecm authmode WPA2/802.11i privacy ON
        deftxkey UNDEF AES-CCM 2:128-bit txpower 30 bmiss 7 mcastrate 6
        mgmtrate 6 scanvalid 60 ampdulimit 64k ampdudensity 4 shortgi -uapsd
        wme burst roaming MANUAL
        parent interface: ath0
        media: IEEE 802.11 Wireless Ethernet OFDM/6Mbps mode 11na
        status: associated
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

// Create interface and associate (2.4 GHz Frequency)
root@leslie:~ # ifconfig wlan0 create wlandev ath0 && ifconfig wlan0 up && wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf
Successfully initialized wpa_supplicant
ioctl[SIOCS80211, op=20, val=0, arg_len=7]: Invalid argument
ioctl[SIOCS80211, op=20, val=0, arg_len=7]: Invalid argument
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
ioctl[SIOCS80211, op=103, val=0, arg_len=128]: Operation now in progress
wlan0: CTRL-EVENT-SCAN-FAILED ret=-1 retry=1
wlan0: Trying to associate with YY:YY:YY:YY:YY:YY (SSID='SSID' freq=2432 MHz)
wlan0: Associated with YY:YY:YY:YY:YY:YY
wlan0: WPA: Key negotiation completed with YY:YY:YY:YY:YY:YY [PTK=CCMP GTK=CCMP]
wlan0: CTRL-EVENT-CONNECTED - Connection to YY:YY:YY:YY:YY:YY completed [id=0 id_str=]

// Request IP from DHCP Server
root@leslie:~ # dhclient wlan0
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 4
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 4
DHCPOFFER from 192.168.1.1
DHCPREQUEST on wlan0 to 255.255.255.255 port 67
DHCPACK from 192.168.1.1
bound to 192.168.1.232 -- renewal in 43200 seconds.

// Interface info on 2.4 GHz Frequency
root@leslie:~ # ifconfig wlan0
wlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether XX:XX:XX:XX:XX:XX
        inet 192.168.1.232 netmask 0xffffff00 broadcast 192.168.1.255
        groups: wlan
        ssid SSID channel 5 (2432 MHz 11g ht/20) bssid YY:YY:YY:YY:YY:YY
        regdomain 105 indoor ecm authmode WPA2/802.11i privacy ON
        deftxkey UNDEF AES-CCM 2:128-bit txpower 20 bmiss 7 scanvalid 60
        protmode CTS ampdulimit 64k ampdudensity 4 shortgi -uapsd wme burst
        roaming MANUAL
        parent interface: ath0
        media: IEEE 802.11 Wireless Ethernet MCS mode 11ng
        status: associated
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
root@leslie:~ # dmesg | grep ath
ath0: <Atheros AR946x/AR948x> mem 0x7a200000-0x7a27ffff at device 0.0 on pci2
ath0: [HT] enabling HT modes
ath0: [HT] enabling short-GI in 20MHz mode
ath0: [HT] 1 stream STBC receive enabled
ath0: [HT] 1 stream STBC transmit enabled
ath0: [HT] LDPC transmit/receive enabled
ath0: [HT] 2 RX streams; 2 TX streams
ath0: AR9460 mac 640.3 RF5110 phy 0.0
ath0: 2GHz radio: 0x0000; 5GHz radio: 0x0000
ath0@pci0:170:0:0:  class=0x028000 rev=0x01 hdr=0x00 vendor=0x168c device=0x0034 subvendor=0x105b subdevice=0xe07d
    vendor     = 'Qualcomm Atheros'
    device     = 'AR9462 Wireless Network Adapter'
    class      = network

Speed Test on the AR9462 (5 GHz, ASUS RT-AX88U PRO w/ ASUSWRT-Merlin)

For comparison, this is my Windows gaming computer with a wired connection:

My Intel AX210

Since I ended up breaking the little circular holder on the AX210's Main connector when I first got the laptop in 2021, I had to use some electrical tape and a little piece of cardboard to maintain contain. Luckily the card worked with no hardware issues (from what I can tell) all this time.

The broken Intel AX210 Main Connector

You can see the missing circular piece on the Main connector.

Atheros AR9462 M.2 E Key from ThinkPenguin

Framework Laptop Wifi Slot (Shows Intel AX210 A+E)

Since I had to research a good amount to make sure that the AR9462 E Key was compatible with this machine (and wasn't actually 100% sure even though some people said it was), I took a chance, luckily it was ok. This picture shows the Intel AX210 A+E Key, and the connector itself on the mainboard. You can see that there is indeed enough room for the E key as well.

Side by side (Intel AX210 A+E Key and Atheros AR9462 M.2 E Key)

Replacing the Card

When replacing the card, I would recommend actually putting the card inside the mainboard first, then holding it with one finger, and slowly, and gently, placing each connector properly. I know that the instructions a while ago mentioned placing the cables outside, but I feel part of the reason my thing broke was because of that.. if you are holding the cables connected to the chip before you even insert the chip, when you do insert it, the cables will bend at a particular angle given the "elevation" change, which could damage it. I feel it's better for me to place it all in first, keep a steady grip on the flat surface, and then just connect it and lock it all in.