Workaround to fix Realtek USB Wi-Fi dongle

mydeardiary

2024-02-20T09:03:15+00:00

A little story

My self hosted webserver comes with a Realtek 8723a SDIO Wi-Fi card which doesn’t work with linux-image-current-rockchip that comes with Armbian. So instead of getting my hands dirty on fixing the 8723bs driver to support 8723a inside my box, I went out to buy a usb wi-fi dongle.

Luckily, the usb wi-fi dongle works on kernel 6.1.x with some limitation: the displayed signal strength status is not so great. So, I switch to enable Armbian beta apt repository to get more recent kernel for my box.

A bit of problem

Sometimes, or somewhat often, the wi-fi dongle doesn’t work after a system restart or a cold boot. The kernel message says that there is a failure during firmware loading of the usb wi-fi dongle.

In this situation, to access my box, I plugged in my Android phone and chose USB Tethering to access the box via ssh. I find the ip address of the box via ip neigh command and use the ip address shown to access the box via ssh. This is possible since there is NetworkManager running on Armbian and it is listening to hotplug event. When the USB Tethering is activated on Android, the udev subsystem of the linux kernel will inform NetworkManager and the daemon will issue a dhcp request to the Android host. The Android tethering host will respond with an ip address for the requesting client. This works very well for my recovery when the wi-fi dongle doesn’t come up, so I can still access my box without resorting to serial console or preparing a keyboard and monitor for pc like access.

A rough solution

When facing with this situation, I pulled the usb dongle from the box usb port, wait a few seconds, and put the dongle back in another port. I tried this a few times and sometimes the wi-fi dongle comes up. With the same trick on another occasion, the wi-fi dongle doesn’t come up as I intended.

With this rought treatment, I began to think that may be a usb port could get loose or getting degraded. So I began to think about solution to toggle the usb port power off and toggling back to on to simulate usb removal.

Meet uhubctl

There are ways to achieve this. The first is using kernel sysfs interface. The other is using a program that talks to usb devices, such as uhubctl.

So I installed uhubctl and tried to run it manually when the rtl8xxxu driver get a failure during firmware load.

until ip link | grep wl ; do
sudo uhubctl -s 0bda:8179 -a 2 ; sleep 3
done

The above command will run ip link command. If it doesn’t detect an interface with wl prefix, the usb port will be power-cycled. In this situation, I limit the action for the vendor id and device id of the usb wi-fi dongle (0bda:8179). After some tries, the wi-fi link comes up and connected to the wi-fi network that has been configured before.

Automating the action

Instead of resorting to USB tethering access, I created a systemd service to check for the presence of 0bda:8179 usb device (the wi-fi dongle) and perform power-cycle repeat when the wlan0 interface is not found.

Here is the /etc/systemd/system/toggle-usb-wifi-port.service file that performs the action described above.

[Unit]
Description=Reset USB port to load realtek wifi dongle
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh /usr/local/sbin/toggle-usb-port.sh

[Install]
WantedBy=multi-user.target

Here is the content of toggle-usb-port.sh script.

#!/bin/sh
WIFI_DEVICE="0bda:8179"
if ! uhubctl -s "$WIFI_DEVICE" ; then
echo "No Realtek Wi-Fi dongle is connected."
exit 0
fi
sleep 2
until ip link | grep wl ; do
uhubctl -s "$WIFI_DEVICE" -a 2 ; sleep 3
done

Afterwards, I enabled the systemd unit after reloading systemd.

sudo systemctl daemon reload
sudo systemctl enable toggle-usb-wifi-port.service

With this workaround, I feel somewhat confident that the wi-fi dongle will come up after a cold boot or after a system reboot.

Very convenient.

Integration with udev

I am thinking about integrating the action with udev so the link check will be performed even after the system is fully booted and the wi-fi is inserted later. The proposed /etc/udev/rules.d/99-realtek-dongle.rules is as follows.

SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="8179", RUN+="/usr/bin/systemctl start toggle-usb-wifi-port.service"

The udev integration is not tested, so it is not guaranteed to work. Update: I’ve added RemainAfterExit=yes property to the systemd unit so the toggle wi-fi script is not executed continuously to prevent race condition. The udev integration is an alternative to start the toggling process without enabling the toggle-usb-wifi.service.

Update: I removed the [Install] section of the systemd service and used the udev subsystem to trigger the usb toggling whenever the usb wifi dongle is detected. While it works, it took some time for the wireless interface to become available.

Finally

With these workarounds, I hope the self hosted webserver will be more reliable in case there is a need of a system reboot or coming up after an unplanned power outage. Feel free to follow this guide to fix similar issue with usb devices that needs replugging such as my Realtek usb wi-fi dongle.

Update: Got another problematic usb dongle from the same chipset manufacturer with similar workaround.

Thanks for reading this page.


Donate to the author

Back to main page