Can't detect wireless adapter BCM43225 despite if_bwn and bwn_v4_ucode loaded

Hello.

I'm trying to get wifi working on my laptop Samsung 700Z3A with a broadcom wifi adapter.
Code:
sysctl net.wlan.devices
finds no adapters (and ifconfig doesn't find it either). So that's where my adventure starts.

Here's a list of what's given:
  • if_bwn is loaded
  • laptop's model is samsung 700Z3A
  • the adapter is BCM43225
  • FreeBSD 13.1-RELEASE

Observations
When I'm booting or reloading if_bwn, it gives the following error:
Code:
bwn0: <Broadcom 802.11 MAC/PHY/Radio, rev 23> mem 0x18001000-0x18001fff,0x18101000-0x18101fff irq 1 at core 1 on bhnd0
bwn0: bwn_phy_n_attach: BWN_GPL_PHY not in kernel config; no PHY-N support
bwn0: failed
device_attach: bwn0 attach returned 6
Attempt 1: build if_bwn with this flag and load it

So, for this I cloned the source tree into /usr/src and build the module:
Code:
su
cd /usr/src/sys/modules/bwn
env CFLAGS="-DVIMAGE -DBWN_GPL_PHY" make clean
env CFLAGS="-DVIMAGE -DBWN_GPL_PHY" make
kldunload if_bwn
kldload /usr/obj/usr/src/amd64.amd64/sys/modules/bwn/if_bwn.ko

However, kldload reports the following error into dmesg:
Code:
link_elf_obj: symbol bwn_nphy_op_allocate undefin
linker_load_file: /usr/obj/usr/src/amd64.amd64/sys/modules/bwn/if_bwn.ko - unsupported file type

Attempt 2: mess up with Makefile of if_bwn

Replaced these lines in Makefile of if_bwn
Code:
SRCS.BWN_GPL_PHY+=  if_bwn_radio_2055.c
SRCS.BWN_GPL_PHY+=  if_bwn_radio_2056.c
SRCS.BWN_GPL_PHY+=  if_bwn_radio_2057.c
SRCS.BWN_GPL_PHY+=  if_bwn_phy_n_sprom.c
SRCS.BWN_GPL_PHY+=  if_bwn_phy_n_tables.c
SRCS.BWN_GPL_PHY+=  if_bwn_phy_n_ppr.c
SRCS.BWN_GPL_PHY+=  if_bwn_phy_n_core.c
with
Code:
SRCS+=  if_bwn_radio_2055.c
SRCS+=  if_bwn_radio_2056.c
SRCS+=  if_bwn_radio_2057.c
SRCS+=  if_bwn_phy_n_sprom.c
SRCS+=  if_bwn_phy_n_tables.c
SRCS+=  if_bwn_phy_n_ppr.c
SRCS+=  if_bwn_phy_n_core.c

I know, it's rather a wild guess. This time when I built and loaded it, it gave this dmesg report (look at the blue lines), then it completely froze and crashed.

Attempt 3: install bwn-firmware-kmod

I obtained the ports and installed it
Code:
su
cd /usr/ports/net/bwn-firmware-kmod
make install clean
I then loaded the module
Code:
kldload bwn_v4_ucode
It loaded and reported nothing to dmesg, so I assume it loaded successfully. However,
Code:
sysctl net.wlan.devices
still detects nothing. I also tried both `if_bwn` OOTB and the one that I built - the same result (error about BWN_GPL_PHY not included for if_bwn (see Observations) and some linker error for if_bwn.ko that I built (see Attempt 1)).
 
The simplest, and most obvious, conclusion is that this card isn't supported by the bwn(4) driver.
 
Oh. But what about the build error in Attempt 1? Maybe if I can fix this, it will work, no?
How to know for sure if it is supported or not? And is it hard to add support myself?
 
Maybe if I can fix this, it will work, no?
No, it doesn't define if the card is recognized or not.

See these IDs here: https://cgit.freebsd.org/src/tree/sys/dev/bhnd/bhnd_ids.h#n121
Those correspond with the vendor, device, subvendor, etc. you see with pciconf -l. This is what defines if a driver attaches to a device. No ID means no driver will attach to the device.

And is it hard to add support myself?
Depends, sometimes it's just a matter of adding the right IDs. Other times you would need to add a bunch of quirks for your specific variant or a whole new driver for it.
 
There is my device. I did "pciconf -l | grep bwn" and got
Code:
bwn_pci0@pci0:2:0:0:    class=0x028000 rev=0x01 hdr=0x00 vendor=0x14e4 device=0x4357 subvendor=0x144f subdevice=0x7181
device=0x4357, which exists in the file you linked:
Code:
#define    PCI_DEVID_BCM43225_D11N2G    0x4357    /* 43225 802.11n 2.4GHz device */
 
you need to build a kernel with options BWN_GPL_PHY
when i hacked the driver to try to use my BCM43228 i was building with this script
Code:
#!/bin/sh
COPTS=-g DEBUG=1 DEBUG_FLAGS=-g make KERN_OPTS="BWN_GPL_PHY BWN_DEBUG" && \
make install  && \
cp /boot/modules/if_bwn.ko /boot/kernel/ && \
cp if_bwn.ko.debug /usr/lib/debug//boot/kernel/if_bwn.ko.debug
use this patch along with the build see if it works
mine worked in the end but with crappy performance like under 1MB/s
if it panics when you using wpa_supplicant it might be a bad DMA buffer alignment
which i fixed but it was not enough for my card
i used the linux open source driver do add the missing bits but my card works shitty on linux too (with the gpled driver)
Code:
--- bwn/if_bwn.c    2022-10-25 19:03:32.598598000 +0300
+++ xbwn/if_bwn.c    2022-10-25 19:10:31.697818000 +0300
@@ -97,7 +97,6 @@
 #include "bhnd_nvram_map.h"
 
 #include "gpio_if.h"
-
 static SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
     "Broadcom driver parameters");
 
@@ -111,6 +110,16 @@
     "Broadcom debugging printfs");
 #endif
 
+static int     bwn_hacks = 0; /* hack crappy rx on my bcm43228 */
+// bit 8   => set RX antenna using the code for PHY_TYPE_G
+// bit 9   => enable alternative values for retry counters
+// bit 0-3 => alternative value for short retries counter
+// bit 4-7 => alternative value for long retries counter
+SYSCTL_INT(_hw_bwn, OID_AUTO, bwn_hacks, CTLFLAG_RWTUN, &bwn_hacks, 0,
+    "uses hacks around bad RX");
+TUNABLE_INT("hw.bwn.bwn_hacks", &bwn_hacks);   
+
+
 static int    bwn_bfp = 0;        /* use "Bad Frames Preemption" */
 SYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
     "uses Bad Frames Preemption");
@@ -375,6 +384,14 @@
         { 2472, 13, 30 }, { 2484, 14, 30 } },
     .nchannels = 14
 };
+static const struct bwn_channelinfo bwn_chantable_bg_lim = {
+    .channels = {
+        { 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
+        { 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
+        { 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
+        { 2457, 10, 30 }, { 2462, 11, 30 }},
+    .nchannels = 11
+};
 
 static const struct bwn_channelinfo bwn_chantable_a = {
     .channels = {
@@ -394,6 +411,15 @@
     .nchannels = 37
 };
 
+static const struct bwn_channelinfo bwn_chantable_a_lim = {
+    .channels = {
+        { 5180,  36, 30 }, { 5200,  40, 30 }, { 5220,  44, 30 },
+        { 5240,  48, 30 }, { 5745, 149, 30 }, { 5765, 153, 30 },
+        { 5785, 157, 30 }, { 5805, 161, 30 }, { 5825, 165, 30 }
+        },
+    .nchannels = 9
+};
+
 #if 0
 static const struct bwn_channelinfo bwn_chantable_n = {
     .channels = {
@@ -498,6 +524,7 @@
 static const struct bhnd_device bwn_devices[] = {
     BWN_DEV(HWREV_RANGE(5, 16)),
     BWN_DEV(HWREV_EQ(23)),
+    BWN_DEV(HWREV_EQ(30)),   
     BHND_DEVICE_END
 };
 
@@ -1355,6 +1382,10 @@
     if (error)
         goto fail;
 
+    if(mac->mac_phy.type == BWN_PHYTYPE_LCNXN) {
+          mac->mac_phy.type = BWN_PHYTYPE_N;
+          mac->mac_phy.rev += 16;
+          }
     /*
      * This is the whitelist of devices which we "believe"
      * the SPROM PHY config from.  The rest are "guessed".
@@ -1364,7 +1395,9 @@
         sc->sc_board_info.board_devid != PCI_DEVID_BCM4318_D11DUAL &&
         sc->sc_board_info.board_devid != PCI_DEVID_BCM4306_D11DUAL &&
         sc->sc_board_info.board_devid != PCI_DEVID_BCM4321_D11N &&
-        sc->sc_board_info.board_devid != PCI_DEVID_BCM4322_D11N) {
+        sc->sc_board_info.board_devid != PCI_DEVID_BCM4322_D11N &&
+        sc->sc_board_info.board_devid != PCI_DEVID_BCM43228_D11N
+        ) {
         have_a = have_bg = 0;
         if (mac->mac_phy.type == BWN_PHYTYPE_A)
             have_a = 1;
@@ -1443,7 +1476,7 @@
         mac->mac_phy.switch_analog = bwn_phy_n_switch_analog;
         mac->mac_phy.switch_channel = bwn_phy_n_switch_channel;
         mac->mac_phy.get_default_chan = bwn_phy_n_get_default_chan;
-        mac->mac_phy.set_antenna = bwn_phy_n_set_antenna;
+        mac->mac_phy.set_antenna = (bwn_hacks & 0x100) ? bwn_phy_g_set_antenna : bwn_phy_n_set_antenna;
         mac->mac_phy.set_im = bwn_phy_n_im;
         mac->mac_phy.recalc_txpwr = bwn_phy_n_recalc_txpwr;
         mac->mac_phy.set_txpwr = bwn_phy_n_set_txpwr;
@@ -1574,11 +1607,15 @@
     phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
     phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
     phy->rev = (tmp & BWN_PHYVER_VERSION);
+    if(phy->type == BWN_PHYTYPE_LCNXN) {
+         phy->type = BWN_PHYTYPE_N;
+         phy->rev += 16;
+         }
     if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
         (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
         phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
         (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
-        (phy->type == BWN_PHYTYPE_N && phy->rev > 6) ||
+        (phy->type == BWN_PHYTYPE_N && phy->rev > 19) ||
         (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
         goto unsupphy;
 
@@ -1605,7 +1642,7 @@
         (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
         (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
         (phy->type == BWN_PHYTYPE_N &&
-         phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
+         phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056 && phy->rf_ver != 0x2057) ||
         (phy->type == BWN_PHYTYPE_LP &&
          phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
         goto unsupradio;
@@ -1672,8 +1709,14 @@
 {
     struct bwn_softc *sc = mac->mac_sc;
     struct ieee80211com *ic = &sc->sc_ic;
-    uint8_t bands[IEEE80211_MODE_BYTES];
+    struct bwn_phy *phy = &mac->mac_phy;
+    uint8_t bands[IEEE80211_MODE_BYTES], limited_2g, limited_5g;
        
+        limited_2g = phy->rf_ver == 0x2057 &&
+             (phy->rf_rev == 9 || phy->rf_rev == 14);
+   
+    limited_5g = phy->rf_ver == 0x2057 && phy->rf_rev == 9;
+
     memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
     ic->ic_nchans = 0;
 
@@ -1687,14 +1730,18 @@
         setbit(bands, IEEE80211_MODE_11B);
         setbit(bands, IEEE80211_MODE_11G);
         bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
-            &ic->ic_nchans, &bwn_chantable_bg, bands);
+            &ic->ic_nchans,
+            limited_2g ? &bwn_chantable_bg_lim :  &bwn_chantable_bg,
+            bands);
     }
 
     if (have_a) {
         memset(bands, 0, sizeof(bands));
         setbit(bands, IEEE80211_MODE_11A);
         bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
-            &ic->ic_nchans, &bwn_chantable_a, bands);
+            &ic->ic_nchans,
+            limited_5g ? &bwn_chantable_a_lim : &bwn_chantable_a,
+            bands);
     }
 
     mac->mac_phy.supports_2ghz = have_bg;
@@ -1971,7 +2018,8 @@
     if (error)
         goto fail;
     bwn_mac_suspend(mac);
-    bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
+    bwn_set_txretry(mac, (bwn_hacks & 0x200) ? bwn_hacks & 0xF : BWN_RETRY_SHORT,
+                 (bwn_hacks & 0x200) ? (bwn_hacks & 0xF0) >> 4 : BWN_RETRY_LONG);
     chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
     if (chan != phy->chan)
         bwn_switch_channel(mac, chan);
@@ -2287,12 +2335,11 @@
         bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_MACHW_H,
             (cap >> 16) & 0xffff);
     }
-
-    bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
+    bwn_set_txretry(mac, (bwn_hacks & 0x200) ? bwn_hacks & 0xF : BWN_RETRY_SHORT,
+                 (bwn_hacks & 0x200) ? (bwn_hacks & 0xF0) >> 4 : BWN_RETRY_LONG);                 
     bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
     bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
     bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
-
     bwn_rate_init(mac);
     bwn_set_phytxctl(mac);
 
@@ -2414,7 +2461,15 @@
     error = bwn_fw_loaducode(mac);
     if (error)
         return (error);
-
+/*       
+    mac->asi = bwn_c_antsel_attach(mac);
+    if (!mac->asi) {
+     device_printf(sc->sc_dev, "Cant figure out antenna\n");
+                return (ENXIO);
+     } else {
+       device_printf(sc->sc_dev, "Antenna attached\n");
+      }     
+*/     
     error = bwn_gpio_init(mac);
     if (error)
         return (error);
@@ -2481,6 +2536,8 @@
     }
    
     BWN_WRITE_2(mac, BWN_POWERUP_DELAY, delay);
+
+
     return (0);
 }
 
@@ -2991,6 +3048,7 @@
     return (dr);
 
 fail2:
+      device_printf(sc->sc_dev,"F2 DMA RING SETUP CI=%d TX=%d\n",controller_index,for_tx);
     if (dr->dr_txhdr_cache != NULL) {
         contigfree(dr->dr_txhdr_cache,
             (dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
@@ -3009,7 +3067,6 @@
 
     if (dr == NULL)
         return;
-
     bwn_dma_free_descbufs(*dr);
     bwn_dma_free_ringmemory(*dr);
 
@@ -3230,11 +3287,12 @@
     int error;
 
     error = bus_dma_tag_create(dma->parent_dtag,
-                BWN_ALIGN, 0,
+                mac->mac_dmatype == BHND_DMA_ADDR_64BIT ? 2 * BWN_ALIGN : BWN_ALIGN,
+                0,
                 BUS_SPACE_MAXADDR,
                 BUS_SPACE_MAXADDR,
                 NULL, NULL,
-                BWN_DMA_RINGMEMSIZE,
+                mac->mac_dmatype == BHND_DMA_ADDR_64BIT ? 2 * BWN_DMA_RINGMEMSIZE : BWN_DMA_RINGMEMSIZE,
                 1,
                 BUS_SPACE_MAXSIZE_32BIT,
                 0,
@@ -3255,7 +3313,8 @@
         return (-1);
     }
     error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
-        dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
+        dr->dr_ring_descbase,
+        mac->mac_dmatype == BHND_DMA_ADDR_64BIT ? 2 * BWN_DMA_RINGMEMSIZE : BWN_DMA_RINGMEMSIZE,
         bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
     if (error) {
         device_printf(sc->sc_dev,
@@ -3287,7 +3346,7 @@
 
     if (dr->dr_tx) {
         dr->dr_curslot = -1;
-
+        dr->dr_usedslot = 0;
         if (dr->dr_type == BHND_DMA_ADDR_64BIT) {
             value = BWN_DMA64_TXENABLE;
             value |= BWN_DMA64_TXPARITY_DISABLE;
@@ -3640,7 +3699,6 @@
 bwn_fw_fillinfo(struct bwn_mac *mac)
 {
     int error;
-
     error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
     if (error == 0)
         return (0);
@@ -4040,7 +4098,7 @@
 {
     struct bwn_softc *sc = mac->mac_sc;
     struct bwn_fw *fw = &mac->mac_fw;
-    const uint8_t rev = bhnd_get_hwrev(sc->sc_dev);
+     uint8_t rev = bhnd_get_hwrev(sc->sc_dev);
     const char *filename;
     uint16_t iost;
     int error;
@@ -5082,7 +5140,6 @@
     struct bwn_softc *sc = mac->mac_sc;
     uint32_t merged = 0;
     int i, tx = 0, rx = 0;
-
     BWN_LOCK(sc);
     if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
         (sc->sc_flags & BWN_FLAG_INVALID)) {
@@ -6148,8 +6205,7 @@
     struct bwn_dmadesc_generic *desc;
     struct bwn_dmadesc_meta *meta;
     struct bwn_softc *sc = mac->mac_sc;
-    int slot;
-
+    int slot,firstused;
     BWN_ASSERT_LOCKED(sc);
 
     dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
@@ -6157,8 +6213,21 @@
         device_printf(sc->sc_dev, "failed to parse cookie\n");
         return;
     }
+    if (dr->dr_usedslot <= 0) {
+        device_printf(sc->sc_dev, "handle txeof fXXX no slots used\n");
+        goto _dexit;
+    }
     KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
 
+    firstused = dr->dr_curslot - dr->dr_usedslot + 1;
+    if (firstused < 0)
+        firstused = dr->dr_numslots + firstused;   
+    if(firstused != slot) {
+        device_printf(sc->sc_dev,"DMA %s S=%d ring=%d cur=%d used=%d TX=1 F=%d\n",
+            firstused != slot ? "XXX" : "   ",
+            slot,dr->dr_index,dr->dr_curslot,dr->dr_usedslot,firstused);
+         }
+
     while (1) {
         KASSERT(slot >= 0 && slot < dr->dr_numslots,
             ("%s:%d: fail", __func__, __LINE__));
@@ -6172,7 +6241,12 @@
         if (meta->mt_islast) {
             KASSERT(meta->mt_m != NULL,
                 ("%s:%d: fail", __func__, __LINE__));
-
+                        if(!meta->mt_ni) {
+                        device_printf(sc->sc_dev,"TX status unexpected NULL meta->mt_ni "
+                       "at slot %d (first=%d) on ring %d\n",
+                       slot, firstused, dr->dr_index);
+            break;           
+                         }
             bwn_ratectl_tx_complete(meta->mt_ni, status);
             ieee80211_tx_complete(meta->mt_ni, meta->mt_m, 0);
             meta->mt_ni = NULL;
@@ -6186,6 +6260,7 @@
             break;
         slot = bwn_dma_nextslot(dr, slot);
     }
+_dexit:   
     sc->sc_watchdog_timer = 0;
     if (dr->dr_stop) {
         KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
 
Thanks. I feel like your scripts are a bit outdated, but let me try to reshape it. So first, `make install` should now be `make buildkernel` and `make installkernel`? As here

Also, the patch doesn't apply. 26 out of 27 hunks were rejected. I guess the patch is just a bit too old
 
the diff is against 13.1-RELEASE
the shell script was used to build only the module without a kernel configuration file (forced the the n phy option)
i also have newer firmware then the ports provided back then but it had no improvement
i hacked the bcm firmware cutter to support a newer firmware image from bcm
the freebsd driver is a rewrite of the linux gpl driver with some shortcuts (or at least this is my opinion)
again if the kernel panics and reboots in the ifconfig / wpa_supplicant stage is probably a non aligned dma problem
so you may need the patch lines containing mac->mac_dmatype
 
The Wi-Fi module is finally detected! What I did is, I added "options BWN_GPL_PHY" line to the kernel config (/usr/src/sys/dev/amd64/conf/MYCONFIG), built and installed the kernel by specifying my config. Now it's enabled

As for now, even ifconfig was able to detect it, and networkmgr has button "Enable wifi 1". Though at the moment I have a slight issue because it deadly freezes when I press "enable wifi". I will tinker around kernel modules and let you know if I make it work completely.

However, the main problem of this post is solved, thank you so much!
 
Finally... it works. Let me describe a detailed instruction for anyone in the same situation.

1-2 aren't needed if your install includes source tree

1. Download sources

I downloaded src.txz from here. (you can check the integrity using sha256sum built-in command)
2. Unpack

Code:
tar xf src.txz
su
rm -r /usr/src
mv ./usr/src /usr

3. Create kernel config

Code:
cd /usr/src/sys/amd64/conf
cp GENERIC GENERICWITHPHY
echo 'options BWN_GPL_PHY' >> GENERICWITHPHY

4. Install kernel

Code:
cd /usr/src
make buildkernel KERNCONF=GENERICWITHPHY
make installkernel KERNCONF=GENERICWITHPHY
reboot

5. Add modules to loader.conf

Open /boot/loader.conf with your favourite editor and add/make sure it has:
Code:
hw.bwn_pci.preferred="1"
if_bwn_pci_load="YES"
bwn_v4_ucode_load="YES"
bwn_v4_n_ucode_load="YES"
bwn_v4_lp_ucode_load="YES"

6. Add interface creation to rc.conf

Open /etc/rc.conf with your favourite editor and add/make sure it has:
Code:
wlans_bwn0="wlan"
ifconfig_wlan0="WPA SYNCDHCP"

Reboot. If Wi-Fi doesn't connect, here are two bonus steps.

7. Create wpa_supplicant file

Open /etc/wpa_supplicant.conf file and add your wifi configuration
Code:
network={    
ssid="your wifi name"    
proto=WPA RSN   # idk what it does, don't quote me on that
key_mgmt=WPA-PSK    
psk="your password" 
}

8. Restart the network

Code:
/etc/rc.d/netif restart
 
Back
Top