I came across this by reading the code if_iwn.c and DPRINTFs on a kernel with IWN_DEBUG.
IWN_LSB() returns an index starting with 1, however the arrays used later on (noise and gain in iwn5000_set_gains()) start with 0. The current code accounts for this difference when setting the antenna gain by accessing cmd.gain[i - 1]. However the noise array is accessed with noise[i], the chainmask is as well checked against i and more importantly the overall for() loop iterates wrongly over the antennas by always starting with i=2 (the third antenna). One consequence is, that gain calibration never happens in case of only two antennas. Secondly, the final DPRINTF in iwn5000_set_gains() assumes a two-antenna setup. In my case three antennas are connected. I don't know if there are iwn setups with one antenna, but the DPRINTF wouldn't make sense there at all. Hence I propose to move this DPRINTF up where it makes more sense (and adjust it to the new place). My diff below fixes the said off-by-one and DPRINTF. Additionally it adds another DPRINTF which I felt useful while debugging and it extends a comment - those additions may be skipped of course. Here is few details of my laptop (cvs updated and kernel built today): $ dmesg | grep iwn0 iwn0 at pci2 dev 0 function 0 "Intel WiFi Link 5300" rev 0x00: msi, MIMO 3T3R, MoW, address 00:21:6a:56:2b:36 $ sysctl hw | grep -e machine -e model -e vendor -e product hw.machine=amd64 hw.model=Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz hw.vendor=Dell Inc. hw.product=Studio 1555 Let me know if you need a full dmesg or anything else. Regards Holger Index: if_iwn.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v retrieving revision 1.234 diff -u -p -u -r1.234 if_iwn.c --- if_iwn.c 10 Jul 2020 13:22:20 -0000 1.234 +++ if_iwn.c 17 Jul 2020 10:44:14 -0000 @@ -4596,22 +4596,27 @@ iwn5000_set_gains(struct iwn_softc *sc) cmd.code = sc->noise_gain; cmd.ngroups = 1; cmd.isvalid = 1; - /* Get first available RX antenna as referential. */ - ant = IWN_LSB(sc->rxchainmask); + /* Get first available RX antenna as referential. + * IWN_LSB() return values start with 1, but + * antenna gain array cmd.gain[] and noise array + * calib->noise[] start with 0. */ + ant = IWN_LSB(sc->rxchainmask) - 1; + /* Set differential gains for other antennas. */ for (i = ant + 1; i < 3; i++) { if (sc->chainmask & (1 << i)) { /* The delta is relative to antenna "ant". */ delta = ((int32_t)calib->noise[ant] - (int32_t)calib->noise[i]) / div; + DPRINTF(("Ant[%d] vs. Ant[%d]: delta %d\n", ant, i, delta)); /* Limit to [-4.5dB,+4.5dB]. */ - cmd.gain[i - 1] = MIN(abs(delta), 3); + cmd.gain[i] = MIN(abs(delta), 3); if (delta < 0) - cmd.gain[i - 1] |= 1 << 2; /* sign bit */ + cmd.gain[i] |= 1 << 2; /* sign bit */ + DPRINTF(("Setting differential gains for antenna %d: %x\n", + i, cmd.gain[i])); } } - DPRINTF(("setting differential gains: %x/%x (%x)\n", - cmd.gain[0], cmd.gain[1], sc->chainmask)); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); }