[BPI-R4] BE14 NIC Module Driver code trace (6dBm as example)

When I use BE14 NIC Module, I got some issues and need patch driver.
These patches are available in the discussion, but how is it used and effective?
Therefore, I tried to write an article on how to trace the code, which may allow more people to participate and understand the BE14 driver.
This article introduces how to build a code tracing environment for BE14 drivers.

Step 1.
First of all, we need to know what the hardware of BE14 is?

Referance:
BE14 NIC Hardware Introduction
MediaTek Wireless chipsets specifications

The BE14 NIC consists of three chips: MT7995, MT7976C, and MT7977IA.
MT7976C support abgn+ac+ax(+be) (IQ RF AFE interface)
MT7977IA support an+ac+ax+be (RF AFE interface)
MT7995 support abgn+ac+ax+be (PCIe interface)
The first two are RF chips, one for 2.4GHz and 5GHz, and the other for 6GHz.
MT7995 uses the PCI-E interface and should be the main control chip.

Step 2.
Find the related Linux Driver.

We refer to frank-w mt76 driver.
In the driver, we can see mt7996, mt7925, mt7921, mt7915, mt76x2, mt76x0… etc., but no mt7995.
Depending on the last modification time and the mt7995 specifications, the mt7995 and mt7996 may share the same driver.
The driver we locked is mt7996.

Step 3.
Prepare the environment for tracing code.

A graphical Linux, I prefer Debian + MATE Desktop Environment.
Install 2 necessary programs, Eclipse and meld.

We install meld directly using the apt command.
We download and install Eclipse C/C++ from the website.

Step 4.
Download frank-w mt76 and import code project.

git clone https://github.com/frank-w/mt76

Use Eclipse to import mt76.





Step 5.
Start to trace.
There are two tips for tracking code:
One is to find the entry point.
Another is to follow the breadcrumbs(call function) and find the inside or the outside.

In the mt7996 folder, we see the init.c program file name, which may be the entry point.

Step 6.
Find the entry point.
We open init.c, and after opening init.c, we first fold all the code.

In C programming rules, function calls have a sequence, and they must be defined before they can be called.
Therefore, the entry point is usually at the bottom of the code.

In the Linux Kernel module, the entry point for loading a driver is usually called register, and the entry point for unloading a driver is usually called unregister.


Let's expand mt7996_register_device() and take a look.

Step 7.
The code flow of loading driver.

First of all, mutex and spinlock are both related to lock, so we skip them.
init_waitqueue_head() is related to initialize the head of the queue, so we skip it.
INIT_oooo_oooo seems to be related to variable, structure, and indicator initialization, so we skip it.

Now we record the remaining function calls as follows:

  1. mt7996_init_hardware
  2. mt7996_init_wiphy
  3. mt76_register_device
  4. mt7996_thermal_init
  5. a. mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
    b. mt7996_register_phy(dev, mt7996_phy3(dev), MT_BAND2);
  6. ieee80211_queue_work
  7. vow? if(vow enable) mt7996_vow_init

    mt7996_init_debugfs
    mt7996_coredump_register

At this point, we know the driver loading process.

6 dBm issue?
My BE14 NIC has a maximum power of only 6 dBm.
The main discussion references:
wifi txpower value is very low #17489

We use this to practice trace code.

Fridtjof said that the power level is read from the offset address of the EEPROM.
image
Let’s look at the code.



We execute command to check eeprom.

xxd /sys/kernel/debug/ieee80211/phy0/mt76/eeprom | grep -A1 00001300


The xxd command prints the file in HEX format.
Since the address is 0x1300, the grep command directly displays the value of the address 0x1300.

WoW, exactly the same, it’s awesome.

It was mentioned in the discussion that Yukariin has a patched version that works fine.
It is also mentioned that the patch is in eeprom.c.
We use meld program to compare Yukariin mt76 eeprom.c and OpenWRT version of mt76 eeprom.c.

As mentioned in the discussion, if use_default = true, then it will be read from the file.

Finally, where is eeprom.c called?
We can search through Eclipse’s Search function and find it in mt7996_eeprom_init().

we expand mt7996_init_hardware() and record the function calls inside.

  1. mt7996_get_chip_sku
  2. mt7996_dma_init
  3. mt7996_eeprom_check_fw_mode
  4. mt7996_mcu_init
  5. mt7996_wed_rro_init
  6. mt7996_eeprom_init
  7. if (dev->flash_mode)? mt7996_mcu_apply_group_cal(dev);
  8. mt76_wcid_alloc (Beacon and mgmt frames should occupy wcid 0)
1 Like

My mt76 repo is an older fork of the openwrt mt76. You should refer to this or the mt76 version of any LTS linux kernel (drivers/net/wireless/mediatek/mt76).

But very good idea explaining the driver so that we know all where the issue is located and how to find code position.

1 Like