Support the larger phy context command required by newer iwm(4) firmware.
authorstsp <stsp@openbsd.org>
Wed, 7 Jul 2021 08:21:31 +0000 (08:21 +0000)
committerstsp <stsp@openbsd.org>
Wed, 7 Jul 2021 08:21:31 +0000 (08:21 +0000)
sys/dev/pci/if_iwm.c
sys/dev/pci/if_iwmreg.h

index ed8f3c7..ac4d352 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwm.c,v 1.335 2021/07/07 08:13:37 stsp Exp $       */
+/*     $OpenBSD: if_iwm.c,v 1.336 2021/07/07 08:21:31 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -402,6 +402,8 @@ void        iwm_rx_compressed_ba(struct iwm_softc *, struct iwm_rx_packet *,
 void   iwm_rx_bmiss(struct iwm_softc *, struct iwm_rx_packet *,
            struct iwm_rx_data *);
 int    iwm_binding_cmd(struct iwm_softc *, struct iwm_node *, uint32_t);
+int    iwm_phy_ctxt_cmd_uhb(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
+           uint8_t, uint32_t, uint32_t);
 void   iwm_phy_ctxt_cmd_hdr(struct iwm_softc *, struct iwm_phy_ctxt *,
            struct iwm_phy_context_cmd *, uint32_t, uint32_t);
 void   iwm_phy_ctxt_cmd_data(struct iwm_softc *, struct iwm_phy_context_cmd *,
@@ -5742,6 +5744,40 @@ iwm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm_phy_context_cmd *cmd,
        cmd->txchain_info = htole32(iwm_fw_valid_tx_ant(sc));
 }
 
+int
+iwm_phy_ctxt_cmd_uhb(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
+    uint8_t chains_static, uint8_t chains_dynamic, uint32_t action,
+    uint32_t apply_time)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct iwm_phy_context_cmd_uhb cmd;
+       uint8_t active_cnt, idle_cnt;
+       struct ieee80211_channel *chan = ctxt->channel;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ctxt->id,
+           ctxt->color));
+       cmd.action = htole32(action);
+       cmd.apply_time = htole32(apply_time);
+
+       cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
+           IWM_PHY_BAND_24 : IWM_PHY_BAND_5;
+       cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan));
+       cmd.ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
+       cmd.ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+
+       idle_cnt = chains_static;
+       active_cnt = chains_dynamic;
+       cmd.rxchain_info = htole32(iwm_fw_valid_rx_ant(sc) <<
+                                       IWM_PHY_RX_CHAIN_VALID_POS);
+       cmd.rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS);
+       cmd.rxchain_info |= htole32(active_cnt <<
+           IWM_PHY_RX_CHAIN_MIMO_CNT_POS);
+       cmd.txchain_info = htole32(iwm_fw_valid_tx_ant(sc));
+
+       return iwm_send_cmd_pdu(sc, IWM_PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd);
+}
+
 int
 iwm_phy_ctxt_cmd(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
     uint8_t chains_static, uint8_t chains_dynamic, uint32_t action,
@@ -5749,6 +5785,17 @@ iwm_phy_ctxt_cmd(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
 {
        struct iwm_phy_context_cmd cmd;
 
+       /*
+        * Intel increased the size of the fw_channel_info struct and neglected
+        * to bump the phy_context_cmd struct, which contains an fw_channel_info
+        * member in the middle.
+        * To keep things simple we use a separate function to handle the larger
+        * variant of the phy context command.
+        */
+       if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS))
+               return iwm_phy_ctxt_cmd_uhb(sc, ctxt, chains_static,
+                   chains_dynamic, action, apply_time);
+
        iwm_phy_ctxt_cmd_hdr(sc, ctxt, &cmd, action, apply_time);
 
        iwm_phy_ctxt_cmd_data(sc, &cmd, ctxt->channel,
index e2348d4..c396eec 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwmreg.h,v 1.55 2021/07/07 08:13:37 stsp Exp $     */
+/*     $OpenBSD: if_iwmreg.h,v 1.56 2021/07/07 08:21:31 stsp Exp $     */
 
 /******************************************************************************
  *
@@ -917,6 +917,7 @@ enum msix_ivar_for_cause {
 #define IWM_UCODE_TLV_CAPA_NAN_SUPPORT                 34
 #define IWM_UCODE_TLV_CAPA_UMAC_UPLOAD                 35
 #define IWM_UCODE_TLV_CAPA_DYNAMIC_QUOTA                44
+#define IWM_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS           48
 #define IWM_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE                64
 #define IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS           65
 #define IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT            67
@@ -2966,12 +2967,29 @@ struct iwm_time_quota_cmd {
  * @width: PHY_[VHT|LEGACY]_CHANNEL_*
  * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_*
  */
-struct iwm_fw_channel_info {
+struct iwm_fw_channel_info_v1 {
        uint8_t band;
        uint8_t channel;
        uint8_t width;
        uint8_t ctrl_pos;
-} __packed;
+} __packed; /* CHANNEL_CONFIG_API_S_VER_1 */
+
+/*
+ * struct iwm_fw_channel_info - channel information
+ *
+ * @channel: channel number
+ * @band: PHY_BAND_*
+ * @width: PHY_[VHT|LEGACY]_CHANNEL_*
+ * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_*
+ * @reserved: for future use and alignment
+ */
+struct iwm_fw_channel_info {
+       uint32_t channel;
+       uint8_t band;
+       uint8_t width;
+       uint8_t ctrl_pos;
+       uint8_t reserved;
+} __packed; /* CHANNEL_CONFIG_API_S_VER_2 */
 
 #define IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS      (0)
 #define IWM_PHY_RX_CHAIN_DRIVER_FORCE_MSK \
@@ -3013,7 +3031,15 @@ struct iwm_fw_channel_info {
  * @acquisition_data: ???
  * @dsp_cfg_flags: set to 0
  */
-struct iwm_phy_context_cmd {
+/*
+ * XXX Intel forgot to bump the PHY_CONTEXT command API when they increased
+ * the size of fw_channel_info from v1 to v2.
+ * To keep things simple we define two versions of this struct, and both
+ * are labled as CMD_API_VER_1. (The Linux iwlwifi driver performs dark
+ * magic with pointers to struct members instead.)
+ */
+/* This version must be used if IWM_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS is set: */
+struct iwm_phy_context_cmd_uhb {
        /* COMMON_INDEX_HDR_API_S_VER_1 */
        uint32_t id_and_color;
        uint32_t action;
@@ -3026,6 +3052,20 @@ struct iwm_phy_context_cmd {
        uint32_t acquisition_data;
        uint32_t dsp_cfg_flags;
 } __packed; /* IWM_PHY_CONTEXT_CMD_API_VER_1 */
+/* This version must be used otherwise: */
+struct iwm_phy_context_cmd {
+       /* COMMON_INDEX_HDR_API_S_VER_1 */
+       uint32_t id_and_color;
+       uint32_t action;
+       /* IWM_PHY_CONTEXT_DATA_API_S_VER_1 */
+       uint32_t apply_time;
+       uint32_t tx_param_color;
+       struct iwm_fw_channel_info_v1 ci;
+       uint32_t txchain_info;
+       uint32_t rxchain_info;
+       uint32_t acquisition_data;
+       uint32_t dsp_cfg_flags;
+} __packed; /* IWM_PHY_CONTEXT_CMD_API_VER_1 */
 
 #define IWM_RX_INFO_PHY_CNT 8
 #define IWM_RX_INFO_ENERGY_ANT_ABC_IDX 1