Enabling Automatic Channel Selection (ACS) on the Sona MT320

Introduction

This guide describes how to configure and enable Automatic Channel Selection (ACS) using hostapd on the MediaTek MT320 platform running Linux under the mt76 driver architecture.
This guide was done using the Ezurio Tungsten 510 SMARC SOM platform. This came with the optional Sona MT320 m.2 1420 solder-down module with two MHF4L antenna ports (453-00176) installed. This guide will also work with the m.2 1420 RF trace variant (453-00177) or the m.2 2230 variant (453-00178) connected to a MediaTek EVK.

Requirements

  • Tungsten510 SMARC with MT320 (T510_SMARC_SOM_8r16e_MT320_2M)
  • Universal SMARC Carrier Board Kit (SMARC_CAR)
  • Development PC with Yocto build environment
  • Terminal Software to communicate with the SOM
  • Wireless network to confirm ACS is working
  • Wireless client to confirm that ACS is working

Initial Setup

Please follow this guide to setup the yocto environment and download the code and setup the environment: https://www.ezurio.com/documentation/yocto-scarthgap-v25-1-release-for-tungsten-platforms#section-4

Note: You can stop after you setup the environment for building

ACS Setup

What is ACS

Automatic Channel Selection (ACS) is a function inside of hostapd that will scan all the available channels in a given frequency band and pick the best channel to operate on.

How ACS works

When channel=0 or acs_num_scans is specified in hostapd.conf, hostapd requests channel survey data from the kernel via nl80211. It evaluates noise floor, channel busy time, and receive time across all allowed frequencies to calculate a channel interference matrix before selecting the optimal channel.

Building Yocto Image

Driver Changes

It is possible that hostapd may fail to complete the ACS scan sequence, cycling continuously with the following error:

ACS: Survey analysis failed
ACS: Failed to start
wlan0: Interface initialization failed

The upstream mt76 driver calculates noise floor data (SURVEY_INFO_NOISE_DBM) conditionally based on internal MAC status registers (state->noise). This may evaluate as false during background channel scanning for all the channels. When hostapd receives survey results missing the SURVEY_INFO_NOISE_DBM flag, it discards the channel evaluation data as invalid and ACS will fail.

To ensure hostapd consistently receives valid telemetry during the survey scan, we inject a fallback noise floor directly before the survey structure is committed back to the netlink interface.

Source Location
File: drivers/net/wireless/mediatek/mt76/mac80211.c

Function: mt76_get_survey()

Patch Modification
Apply the following fallback logic inside mac80211.c:

--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -1002,6 +1002,10 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
        survey->time_busy = div_u64(state->cc_busy, 1000);
        survey->time_rx = div_u64(state->cc_rx, 1000);
        survey->time = div_u64(state->cc_active, 1000);

+       /* Force fallback noise floor if driver fails to populate SURVEY_INFO_NOISE_DBM */
+       survey->noise = -95;
+       survey->filled |= SURVEY_INFO_NOISE_DBM;

        spin_lock_bh(&dev->cc_lock);
        survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
        survey->time_tx = div_u64(state->cc_tx, 1000);

Yocto Build System Integration

To ensure this patch persists across clean builds, add it to your custom kernel meta-layer.

  1. Save the patch as 0001-mt76-mac80211-inject-fallback-acs-noise-floor.patch inside your kernel recipe directory: meta-your-custom-layer/recipes-kernel/linux/files/
  2. Append your local kernel recipe (linux-mtk_%.bbappend):
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI += " \
    file://0001-mt76-mac80211-inject-fallback-acs-noise-floor.patch \
"

Now from this guide: https://www.ezurio.com/documentation/yocto-scarthgap-v25-1-release-for-tungsten-platforms#section-4 you can start at the section that starts "Finally, set the Tungsten MACHINE"... within the Build Procedure chapter.

Note: Replace MACHINE=tungsten-700-smarc with MACHINE = "tungsten-510-smarc"

Flashing the SOM

Once the image has finished building, you can follow these instructions to flash the image to your SOM:

Connect from your machine a serial-to-USB adapter to the "SERIAL" header and a USB-C cable to "J25" on the carrier board.

First you need to enter fastboot mode from U-Boot prompt:

=> fastboot 0

If you are unable to get into fastboot mode from U-Boot, you can follow the this blog to recover your Tungsten platform.

Flash the images:
Flash bl2.img to mmc0boot0 partition:

~/Tungsten-Yocto$ fastboot flash mmc0boot0 bl2.img

Flash wic.img to mmc0 partition:

~/Tungsten-Yocto$ fastboot flash mmc0 rity-*-image-tungsten-*-smarc.wic
Note: Ensure u-boot-tools or fastboot on the host PC has permission to write to mmc0. Replace the wildcard * with your specific build timestamp or image name.

Verification and Testing

ACS Configuration

This is a basic configuration of hostapd with ACS. It is located in /etc/hostapd-acs.conf

# --- Basic Hardware Config ---
interface=wlan0
driver=nl80211
ssid=MT320-ACS-Test
hw_mode=a
#
# # --- The ACS Trigger ---
channel=0
#
# # --- Regulatory Setting ---
country_code=US

Stop background processes

systemctl stop NetworkManager wpa_supplicant connman 2>/dev/null
killall NetworkManager wpa_supplicant connman 2>/dev/null

# Cycle the interface to reset driver state
ip link set wlan0 down
ip link set wlan0 up

Launch hostapd

Launch hostapd in debug mode:

hostapd -B /etc/hostapd-acs.conf
Note: You can launch hostapd -dd /etc/hostapd-acs.conf (without -B) to watch the ACS channel survey calculation in real-time before daemonizing.

Confirmation

Confirm successful completion by using the iw command:

root@tungsten-510-smarc:/etc# iw dev
phy#0
        Interface wlan0
                ifindex 4
                wdev 0x1
                addr e8:cb:f5:00:01:8e
                ssid MT320-ACS-Test
                type AP
                channel 36 (5180 MHz), width: 20 MHz (no HT), center1: 5180 MHz
                txpower 3.00 dBm
                multicast TXQ:
                        qsz-byt qsz-pkt flows   drops   marks   overlmt hashcol tx-bytes        tx-packets
                        0       0       0       0       0       0       0       0               0
root@tungsten-510-smarc:/etc#