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);
 }
 

Reply via email to