The branch main has been updated by adrian:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=f981fa12b760a5f0983eeec8065a4dec5295ab24

commit f981fa12b760a5f0983eeec8065a4dec5295ab24
Author:     Abdelkader Boudih <[email protected]>
AuthorDate: 2026-06-17 14:30:21 +0000
Commit:     Adrian Chadd <[email protected]>
CommitDate: 2026-06-17 14:39:09 +0000

    mtw: Fix firmware loading and memory leaks
    
    - Skip firmware reload if MCU already initialized
    - Fix firmware_put() memory leaks on error paths
    - Increase MCU init timeout to 15 seconds
    - Use debug macros instead of device_printf for verbose output
    - Remove unused 'ret' variable
    - Fix space indentation to tabs per style(9)
    
    Reviewed by:    adrian
    Differential Revision:  https://reviews.freebsd.org/D57597
---
 sys/dev/usb/wlan/if_mtw.c | 103 +++++++++++++++++++++++++++-------------------
 1 file changed, 60 insertions(+), 43 deletions(-)

diff --git a/sys/dev/usb/wlan/if_mtw.c b/sys/dev/usb/wlan/if_mtw.c
index 9d256056f6b2..5eaa31267b42 100644
--- a/sys/dev/usb/wlan/if_mtw.c
+++ b/sys/dev/usb/wlan/if_mtw.c
@@ -125,6 +125,11 @@ enum {
 #define MTW_MAX_TXSZ \
        (sizeof(struct mtw_txd) + sizeof(struct mtw_txwi) + MCLBYTES + 11)
 
+#define        MTW_FW_READY_RETRIES    500
+#define        MTW_FW_READY_DELAY_MS   30
+#define        MTW_FWLOAD_TIMEOUT      \
+       (((MTW_FW_READY_RETRIES * MTW_FW_READY_DELAY_MS) / 1000 + 5) * hz)
+
 /*
  * Because of LOR in mtw_key_delete(), use atomic instead.
  * '& MTW_CMDQ_MASQ' is to loop cmdq[].
@@ -516,7 +521,7 @@ mtw_attach(device_t self)
        struct usb_attach_arg *uaa = device_get_ivars(self);
        struct ieee80211com *ic = &sc->sc_ic;
        uint32_t ver;
-       int i, ret;
+       int i;
        uint32_t tmp;
        uint8_t iface_index;
        int ntries, error;
@@ -536,7 +541,7 @@ mtw_attach(device_t self)
        DELAY(100000);  /* 100ms settle time */
 
        mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
-                 MTX_NETWORK_LOCK, MTX_DEF);
+           MTX_NETWORK_LOCK, MTX_DEF);
 
        iface_index = 0;
 
@@ -595,8 +600,10 @@ mtw_attach(device_t self)
        sc->mac_rev = tmp & 0xffff;
 
        mtw_load_microcode(sc);
-       ret = msleep(&sc->fwloading, &sc->sc_mtx, 0, "fwload", 10 * hz);
-       if (ret == EWOULDBLOCK || sc->fwloading != 1) {
+       if (sc->fwloading != 1)
+               (void)msleep(&sc->fwloading, &sc->sc_mtx, 0, "fwload",
+                   MTW_FWLOAD_TIMEOUT);
+       if (sc->fwloading != 1) {
                device_printf(sc->sc_dev,
                    "timeout waiting for MCU to initialize\n");
                goto detach;
@@ -633,11 +640,11 @@ mtw_attach(device_t self)
                IEEE80211_C_WME |             /* WME */
                IEEE80211_C_WPA;             /* WPA1|WPA2(RSN) */
            device_printf(sc->sc_dev, "[HT] Enabling 802.11n\n");
-           ic->ic_htcaps =       IEEE80211_HTC_HT
-            | IEEE80211_HTC_AMPDU
-            | IEEE80211_HTC_AMSDU
-            | IEEE80211_HTCAP_MAXAMSDU_3839
-            | IEEE80211_HTCAP_SMPS_OFF;
+           ic->ic_htcaps = IEEE80211_HTC_HT
+               | IEEE80211_HTC_AMPDU
+               | IEEE80211_HTC_AMSDU
+               | IEEE80211_HTCAP_MAXAMSDU_3839
+               | IEEE80211_HTCAP_SMPS_OFF;
 
        ic->ic_rxstream = sc->nrxchains;
        ic->ic_txstream = sc->ntxchains;
@@ -1107,6 +1114,7 @@ mtw_load_microcode(void *arg)
 
        struct mtw_softc *sc = (struct mtw_softc *)arg;
        const struct mtw_ucode_hdr *hdr;
+       const struct firmware *firmware_rom = NULL, *firmware = NULL;
        // onst struct mtw_ucode *fw = NULL;
        const char *fwname;
        size_t size;
@@ -1114,47 +1122,43 @@ mtw_load_microcode(void *arg)
        uint32_t tmp, iofs = 0x40;
        //      int ntries;
        int dlen, ilen;
-       device_printf(sc->sc_dev, "version:0x%hx\n", sc->asic_ver);
-       /*
-        * Firmware may still be running from a previous warm reboot.
-        * Force a reset of the MCU to ensure a clean state.
-        */
+       MTW_DPRINTF(sc, MTW_DEBUG_FIRMWARE, "version:0x%hx\n", sc->asic_ver);
+       /* Check if MCU is already initialized and skip firmware reload */
        mtw_read_cfg(sc, MTW_MCU_DMA_ADDR, &tmp);
        if (tmp == MTW_MCU_READY) {
-               device_printf(sc->sc_dev, "MCU already running, resetting\n");
-               mtw_write(sc, MTW_MCU_RESET_CTL, MTW_RESET);
-               DELAY(10000);
-               mtw_write(sc, MTW_MCU_RESET_CTL, 0);
-               DELAY(10000);
-               /* Clear ready flag */
-               mtw_write_cfg(sc, MTW_MCU_DMA_ADDR, 0);
-               DELAY(1000);
+               MTW_DPRINTF(sc, MTW_DEBUG_FIRMWARE,
+                   "MCU already running, skipping firmware reload\n");
+               sc->fwloading = 1;
+               wakeup(&sc->fwloading);
+               return;
        }
 
        if (sc->asic_ver == 0x7612) {
                fwname = "mtw-mt7662u_rom_patch";
 
-               const struct firmware *firmware = 
firmware_get_flags(fwname,FIRMWARE_GET_NOWARN);
-               if (firmware == NULL) {
+               firmware_rom = firmware_get_flags(fwname, FIRMWARE_GET_NOWARN);
+               if (firmware_rom == NULL) {
                        device_printf(sc->sc_dev,
-                           "failed loadfirmware of file %s (error %d)\n",
-                           fwname, error);
+                           "failed to load firmware file %s\n",
+                           fwname);
                        return;
                }
-               size = firmware->datasize;
+               size = firmware_rom->datasize;
 
                const struct mtw_ucode *fw = (const struct mtw_ucode *)
-                                                firmware->data;
+                   firmware_rom->data;
                hdr = (const struct mtw_ucode_hdr *)&fw->hdr;
-               // memcpy(fw,(const unsigned char*)firmware->data +
-               // 0x1e,size-0x1e);
+               // memcpy(fw,(const unsigned char*)firmware_rom->data +
+               //    0x1e,size-0x1e);
                ilen = size - 0x1e;
 
                mtw_ucode_setup(sc);
 
-               if ((error = mtw_ucode_write(sc, firmware->data, fw->ivb, ilen,
-                        0x90000)) != 0) {
-                       goto fail;
+               if ((error = mtw_ucode_write(sc, firmware_rom->data, fw->ivb,
+                   ilen, 0x90000)) != 0) {
+                       device_printf(sc->sc_dev,
+                           "Could not write ROM patch\n");
+                       goto fail_rom;
                }
                mtw_usb_dma_write(sc, 0x00e41814);
        }
@@ -1171,13 +1175,15 @@ mtw_load_microcode(void *arg)
                // dofs = 0x80000;
        }
        MTW_UNLOCK(sc);
-       const struct firmware *firmware = firmware_get_flags(fwname, 
FIRMWARE_GET_NOWARN);
+       firmware = firmware_get_flags(fwname, FIRMWARE_GET_NOWARN);
 
        if (firmware == NULL) {
                device_printf(sc->sc_dev,
-                   "failed loadfirmware of file %s (error %d)\n", fwname,
-                   error);
+                   "failed to load firmware file %s\n",
+                   fwname);
                MTW_LOCK(sc);
+               if (firmware_rom != NULL)
+                       firmware_put(firmware_rom, FIRMWARE_UNLOAD);
                return;
        }
        MTW_LOCK(sc);
@@ -1214,11 +1220,21 @@ mtw_load_microcode(void *arg)
                device_printf(sc->sc_dev, "Could not write ucode errro=%d\n",
                    error);
 
-       device_printf(sc->sc_dev, "loaded firmware ver %.8x %.8x %s\n",
+       MTW_DPRINTF(sc, MTW_DEBUG_FIRMWARE,
+           "loaded firmware ver %.8x %.8x %s\n",
            le32toh(hdr->fw_ver), le32toh(hdr->build_ver), hdr->build_time);
 
+       /* Release firmware objects */
+       firmware_put(firmware, FIRMWARE_UNLOAD);
+       if (firmware_rom != NULL)
+               firmware_put(firmware_rom, FIRMWARE_UNLOAD);
        return;
+
 fail:
+       firmware_put(firmware, FIRMWARE_UNLOAD);
+fail_rom:
+       if (firmware_rom != NULL)
+               firmware_put(firmware_rom, FIRMWARE_UNLOAD);
        return;
 }
 static usb_error_t
@@ -2877,12 +2893,13 @@ mtw_fw_callback(struct usb_xfer *xfer, usb_error_t 
error)
                        }
 
                        mtw_delay(sc, 10);
-                       for (ntries = 0; ntries < 300; ntries++) {
+                       for (ntries = 0; ntries < MTW_FW_READY_RETRIES;
+                           ntries++) {
                                if ((error = mtw_read_cfg(sc, MTW_MCU_DMA_ADDR,
-                                        &tmp)) != 0) {
+                                   &tmp)) != 0) {
                                        device_printf(sc->sc_dev,
-                                   "Could not read cfg error:  %d\n", error);
-
+                                           "Could not read cfg error:  %d\n",
+                                           error);
                                }
                                if (tmp == MTW_MCU_READY) {
                                        MTW_DPRINTF(sc, MTW_DEBUG_FIRMWARE,
@@ -2891,9 +2908,9 @@ mtw_fw_callback(struct usb_xfer *xfer, usb_error_t error)
                                        break;
                                }
 
-                               mtw_delay(sc, 30);
+                               mtw_delay(sc, MTW_FW_READY_DELAY_MS);
                        }
-                       if (ntries == 300)
+                       if (ntries == MTW_FW_READY_RETRIES)
                                sc->fwloading = 0;
                        wakeup(&sc->fwloading);
                        return;

Reply via email to