R7500v2 (ath10k 9980) netperf observations, firmware/board-2.bin files, and other wifi issues

A worked example to create your own 99X0 ath10k "firmware-5.bin" and "board-2.bin" files from "stock Netgear" firmware.

First a few caveats. At the time this post was written, it seems there is no "redistribution licence" for a "board-2.bin" one might create themselves.

As I'm not aware that anything has changed since then and I expect the same is true for a "firmware-5.bin," I will not "redistribute" any such files here or elsewhere. I do not recommend anyone else redistribute any such files they might make for their own use unless an applicable redistribution license for such files exits. (The 99X0 board-2.bin file currently in use by openwrt comes from here - and is possibly covered by this license.)

I consider this example moderately difficult so if you are new to openwrt/linux, consider giving yourself some time to get acclimated before trying this. Also this is not likely to improve your wifi performance - it's "just for fun" I'm using Ubuntu 20.04.1 LTS for this example. That said, the risk that you will irreversibly break something here is small.

Download a recent Netgear image:
wget https://www.downloads.netgear.com/files/GDC/R7500v2/R7500v2-V1.0.3.48.zip

Unzip the firmware and use binwalk to extract the image:

$ unzip R7500v2-V1.0.3.48.zip 
Archive:  R7500v2-V1.0.3.48.zip
  inflating: R7500v2-V1.0.3.48.img   
  inflating: R7500v2-V1.0.3.48_Release_Notes.html  

$ binwalk -e R7500v2-V1.0.3.48.img 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
128           0x80            uImage header, header size: 64 bytes, header CRC: 0x4197B40F, created: 2020-08-17 07:42:56, image size: 2152600 bytes, Data Address: 0x41508000, Entry Point: 0x41508000, data CRC: 0xC47E45C9, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: "Linux-3.4.103"
192           0xC0            Linux kernel ARM boot executable zImage (little-endian)
15124         0x3B14          xz compressed data
15356         0x3BFC          xz compressed data
2228288       0x220040        uImage header, header size: 64 bytes, header CRC: 0xC2A155AD, created: 2020-08-17 07:43:04, image size: 23547904 bytes, Data Address: 0x40908000, Entry Point: 0x40908000, data CRC: 0x69A6711, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: lzma, image name: "Linux-3.4.103"
2228352       0x220080        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 23546438 bytes, 3631 inodes, blocksize: 262144 bytes, created: 2020-08-17 07:43:04

Change to the directory holding the ath10k firmware and board files:

$ cd _R7500v2-V1.0.3.48.img.extracted/squashfs-root/lib/firmware/AR900B/hw.2/
$ ls -al
total 1228
drwxr-xr-x 2 ul ul   4096 Aug 17 03:39 .
drwxr-xr-x 3 ul ul   4096 Aug 17 03:39 ..
-rw-r--r-- 1 ul ul 355234 Oct 20  2016 athwlan.bin
-rw-r--r-- 1 ul ul 106493 Oct 20  2016 athwlan.codeswap.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boarddata_0.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boarddata_1.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS238_5GMipiHigh_v2_004.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS238_5GMipiHigh_v2_CTL.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS238_5GMipiMed_v2_003.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS239_5G_3x3_v2_001.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boardData_AR900B_CUS239_5G_v2_001.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boardData_AR900B_CUS239_5G_v2_CE_001.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS239_5G_v2_ch144.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS239_5G_v2_CTL.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boardData_AR900B_CUS239_5G_v2_MAX_001.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boardData_AR900B_CUS239_5G_v2_NEW_FCC_001.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS239_negative_pwr_offset_5G_v2_007.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS240_2GMipiHigh_v2_006.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS240_2GMipiHigh_v2_CTL.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS240_2GMipiMed_v2_005.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS260_2G_3x3_v2_002.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boardData_AR900B_CUS260_2G_v2_002.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS260_2G_v2_CTL.bin
-rwxr-xr-x 1 ul ul  12064 Aug 17 03:25 boardData_AR900B_CUS260_2G_v2_MAX_002.bin
-rwxr-xr-x 1 ul ul  12064 Oct 20  2016 boardData_AR900B_CUS260_negative_pwr_offset_2G_v2_008.bin
-rwxr-xr-x 1 ul ul    374 Oct 20  2016 .filenames
-rw-r--r-- 1 ul ul  11065 Oct 20  2016 otp.bin
-rw-r--r-- 1 ul ul 303932 Oct 20  2016 utf.bin
-rw-r--r-- 1 ul ul 100417 Oct 20  2016 utf.codeswap.bin
-rw-r--r-- 1 ul ul  98701 Oct 20  2016 waltest.codeswap.bin

To create a "firmware-x.bin" and/or a "board-2.bin" container file from these files, you will need the ath10k-fwencoder and ath10k-bdencoder python scripts from the qca-swiss-army-knife.

You will also need to know which of the files above to use. In this case, reading the output from ath10k-fwencoder --help and ath10k-bdencoder --help is informative. From the ath10k-fwencoder script help output, it looks like I need the athwlan.bin, athwlan.codeswap.bin, and the otp.bin files to create a functional firmware. Also really helpful and fun is the ath10k-fwencoder --dump-cmdline /path/to/ct-firmware-5.bin (what exactly is in that ct firmware anyway? Could I mix and match otp.bin files and still have a functional firmware? Probalby not...).

Note the 2016 date of the athwlan*.bin and opt.bin files above... newer than 5 years old but not a great improvment. It looks like these files stoped changing after Netgear's R7500v2-V1.0.3.16.zip firmware. Note, the crc32 checksum reported by ath10k-fwencoder for the individual *.bin files are not the same "inside" a *.bin file vs extracted. Extract the files from a firmware-x.bin file and use md5sum on each extracted file if you want to check for changes (bdencoder will give you consistent md5sum checksums regardless of extraction).

Create a "firmware-5.bin" container:

$ ath10k-fwencoder --create \
--firmware-version=12.34.5-6 \
--features=no-p2p \
--firmware=athwlan.bin \
--otp=otp.bin \
--set-wmi-op-version=10.4 \
--set-htt-op-version=10.4 \
--firmware-codeswap=athwlan.codeswap.bin
firmware-4.bin created: 472904 B
$ mv firmware-4.bin firmware-5.bin

So now what about those board files? Looking around at firmware from dd-wrt, openwrt, notes from ct firmware www site, and most importantly dmesg output, my guess is that only boardData_AR900B_CUS239_5G_v2_001.bin is needed for the 5 GHz band and boardData_AR900B_CUS260_2G_v2_002.bin is needed for the 2 GHz band. Using the openwrt board-2.bin file to create a "board.json" via
ath10k-bdencoder --extract board-2.bin and editing the resulting *.json file to look like:

$ cat board-2.json
[
    {
        "data": "boardData_AR900B_CUS239_5G_v2_001.bin", 
        "names": [
            "bus=pci,bmi-chip-id=1,bmi-board-id=1"
        ]
    }, 
    {
        "data": "boardData_AR900B_CUS260_2G_v2_002.bin", 
        "names": [
            "bus=pci,bmi-chip-id=1,bmi-board-id=2"
        ]
    }
]

I made guesses about the bmi-chip-id, bmi-board-id, and which wifi band corresponds to which board file from dmesg output on my r7500v2 (left as an exercise for the reader). Note many of the Netgear board files where updated August 17, 2020...

$ ath10k-bdencoder --create board-2.json 
board binary file 'board-2.bin' is created
$ ath10k-bdencoder --info board-2.bin
FileSize: 24268
FileCRC32: cb100cc3
FileMD5: b05b549a62e246b70f54354c82ddca53
BoardNames[0]: 'bus=pci,bmi-chip-id=1,bmi-board-id=1'
BoardLength[0]: 12064
BoardCRC32[0]: a0a1ad69
BoardMD5[0]: e8b77aec3f913f592b44360d5545e032
BoardNames[1]: 'bus=pci,bmi-chip-id=1,bmi-board-id=2'
BoardLength[1]: 12064
BoardCRC32[1]: aa572ad1
BoardMD5[1]: f495c23de5be19a81aab70ecb757ebd8

So what about those other board files? Well that could be interesting. I can only speculate but the file names might be revealing. One guess is that the propietary ath10k drivers can load a board file based on what they think is needed... It could be fun to experiment here (i.e. want to tune for 5 GHz 3x3 clients?).

BTW don't mess with your "pre-calibration" data (not otherwise mentioned in this post). This is likely specific to your device and if you lose it, you probably will permanently lose wifi. Nothing in this example will change the pre-calibration data that is used in combination with the board files.

At this point, I copied my DIY firmware-5.bin and board-2.bin files to my router and tried them out. First I tried the board-2.bin file with the ath10k-ct driver and ct firmware on a snapshot image:

r7500v2 # cp ~/tmp/board-2.bin /lib/firmware/ath10k/QCA99X0/hw2.0/board-2.bin
r7500v2 # reboot

After a reboot, check your dmesg to see that the new board-2.bin loaded ok and wifi functions... mine did. Note the original board-2.bin file can be restored via
r7500v2 # cp /rom/lib/firmware/ath10k/QCA99X0/hw2.0/board-2.bin /lib/firmware/ath10k/QCA99X0/hw2.0/board-2.bin

I didn't do extensive testing, there might have been a slight improvement but nothing likley to make you think it was worth the effort above. Your doing this for the fun of it, right? And maybe one of those other board files will make a difference...

Next I tried the DIY firmware-5.bin file (in combination with the ath10k-ct driver) with the DIY board-2.bin file:

r7500v2 # cp ~/tmp/firmware-5.bin /lib/firmware/ath10k/QCA99X0/hw2.0/ct-firmware-5.bin
r7500v2 # reboot

Again check your dmesg to see that your DIY firmware got loaded. Note the original ct-firmware-5.bin file can be restored via
r7500v2 # cp /rom/lib/firmware/ath10k/QCA99X0/hw2.0/ct-firmware-5.bin /lib/firmware/ath10k/QCA99X0/hw2.0/ct-firmware-5.bin

I ran with this DIY combo for about 12 hrs. Nothing crashed and wifi did function - just not nearly as well as the original ct-firmware. Throughput dropped on both bands by about 2-3x and I still observed the same netperf behavior for which I started this thread. Perhaps using such a DIY firmware will help someone else or using the non-ct ath10k driver with a DIY firmware will function better. Regardless, it looks like I did this for the fun of it.

EDIT: I'll likely be making more edits to this post - I just need to be careful about what button I push.

4 Likes