I noticed that iwm(4) is overwriting the entire HW_IF_CONFIG register
with a hardcoded value, while Linux does a "read + clear some bits +
set some bits + write" operation instead (see iwl_mvm_nic_config() in
the Linux source file drivers/net/wireless/intel/iwlwifi/mvm/ops.c).

Our old code wrote 0xff0f, on my hardware this new code writes 0x18089000
like Linux does, though the exact value written will depend on what the
hardware returns when we read this register.

This register is documented as "hardware interface config". It's unclear
what all these bits are really doing but our current code is clearly wrong.

Please test for regressions.

diff 417cf047a3f739a26c23a52ee0780853d1afaa1e /usr/src
blob - dff9f8047f5c0300a4ddde4d9b090f58c28dd8f9
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -1975,7 +1975,7 @@ void
 iwm_nic_config(struct iwm_softc *sc)
 {
        uint8_t radio_cfg_type, radio_cfg_step, radio_cfg_dash;
-       uint32_t reg_val = 0;
+       uint32_t mask, val, reg_val = 0;
 
        radio_cfg_type = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_TYPE) >>
            IWM_FW_PHY_CFG_RADIO_TYPE_POS;
@@ -1994,15 +1994,18 @@ iwm_nic_config(struct iwm_softc *sc)
        reg_val |= radio_cfg_step << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP;
        reg_val |= radio_cfg_dash << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
 
-       IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG,
-           IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
+       mask = IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
            IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP |
            IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
            IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH |
            IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
            IWM_CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
-           IWM_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI |
-           reg_val);
+           IWM_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
+
+       val = IWM_READ(sc, IWM_CSR_HW_IF_CONFIG_REG);
+       val &= ~mask;
+       val |= reg_val;
+       IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG, val);
 
        /*
         * W/A : NIC is stuck in a reset state after Early PCIe power off

Reply via email to