Support a new time quota command required for newer iwm(4) firmware.
authorstsp <stsp@openbsd.org>
Wed, 7 Jul 2021 08:05:11 +0000 (08:05 +0000)
committerstsp <stsp@openbsd.org>
Wed, 7 Jul 2021 08:05:11 +0000 (08:05 +0000)
sys/dev/pci/if_iwm.c
sys/dev/pci/if_iwmreg.h

index a3bf3f8..59bdeb8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwm.c,v 1.333 2021/06/30 09:45:47 stsp Exp $       */
+/*     $OpenBSD: if_iwm.c,v 1.334 2021/07/07 08:05:11 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -462,6 +462,7 @@ void        iwm_mac_ctxt_cmd_common(struct iwm_softc *, struct iwm_node *,
 void   iwm_mac_ctxt_cmd_fill_sta(struct iwm_softc *, struct iwm_node *,
            struct iwm_mac_data_sta *, int);
 int    iwm_mac_ctxt_cmd(struct iwm_softc *, struct iwm_node *, uint32_t, int);
+int    iwm_update_quotas_v1(struct iwm_softc *, struct iwm_node *, int);
 int    iwm_update_quotas(struct iwm_softc *, struct iwm_node *, int);
 void   iwm_add_task(struct iwm_softc *, struct taskq *, struct task *);
 void   iwm_del_task(struct iwm_softc *, struct taskq *, struct task *);
@@ -7761,6 +7762,67 @@ iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action,
        return iwm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, 0, sizeof(cmd), &cmd);
 }
 
+int
+iwm_update_quotas_v1(struct iwm_softc *sc, struct iwm_node *in, int running)
+{
+       struct iwm_time_quota_cmd_v1 cmd;
+       int i, idx, num_active_macs, quota, quota_rem;
+       int colors[IWM_MAX_BINDINGS] = { -1, -1, -1, -1, };
+       int n_ifs[IWM_MAX_BINDINGS] = {0, };
+       uint16_t id;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       /* currently, PHY ID == binding ID */
+       if (in && in->in_phyctxt) {
+               id = in->in_phyctxt->id;
+               KASSERT(id < IWM_MAX_BINDINGS);
+               colors[id] = in->in_phyctxt->color;
+               if (running)
+                       n_ifs[id] = 1;
+       }
+
+       /*
+        * The FW's scheduling session consists of
+        * IWM_MAX_QUOTA fragments. Divide these fragments
+        * equally between all the bindings that require quota
+        */
+       num_active_macs = 0;
+       for (i = 0; i < IWM_MAX_BINDINGS; i++) {
+               cmd.quotas[i].id_and_color = htole32(IWM_FW_CTXT_INVALID);
+               num_active_macs += n_ifs[i];
+       }
+
+       quota = 0;
+       quota_rem = 0;
+       if (num_active_macs) {
+               quota = IWM_MAX_QUOTA / num_active_macs;
+               quota_rem = IWM_MAX_QUOTA % num_active_macs;
+       }
+
+       for (idx = 0, i = 0; i < IWM_MAX_BINDINGS; i++) {
+               if (colors[i] < 0)
+                       continue;
+
+               cmd.quotas[idx].id_and_color =
+                       htole32(IWM_FW_CMD_ID_AND_COLOR(i, colors[i]));
+
+               if (n_ifs[i] <= 0) {
+                       cmd.quotas[idx].quota = htole32(0);
+                       cmd.quotas[idx].max_duration = htole32(0);
+               } else {
+                       cmd.quotas[idx].quota = htole32(quota * n_ifs[i]);
+                       cmd.quotas[idx].max_duration = htole32(0);
+               }
+               idx++;
+       }
+
+       /* Give the remainder of the session to the first binding */
+       cmd.quotas[0].quota = htole32(le32toh(cmd.quotas[0].quota) + quota_rem);
+
+       return iwm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd);
+}
+
 int
 iwm_update_quotas(struct iwm_softc *sc, struct iwm_node *in, int running)
 {
@@ -7770,6 +7832,9 @@ iwm_update_quotas(struct iwm_softc *sc, struct iwm_node *in, int running)
        int n_ifs[IWM_MAX_BINDINGS] = {0, };
        uint16_t id;
 
+       if (!isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_QUOTA_LOW_LATENCY))
+               return iwm_update_quotas_v1(sc, in, running);
+
        memset(&cmd, 0, sizeof(cmd));
 
        /* currently, PHY ID == binding ID */
@@ -7819,8 +7884,7 @@ iwm_update_quotas(struct iwm_softc *sc, struct iwm_node *in, int running)
        /* Give the remainder of the session to the first binding */
        cmd.quotas[0].quota = htole32(le32toh(cmd.quotas[0].quota) + quota_rem);
 
-       return iwm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, 0,
-           sizeof(cmd), &cmd);
+       return iwm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd);
 }
 
 void
@@ -8235,11 +8299,13 @@ iwm_run(struct iwm_softc *sc)
                return err;
        }
 
-       err = iwm_update_quotas(sc, in, 1);
-       if (err) {
-               printf("%s: could not update quotas (error %d)\n",
-                   DEVNAME(sc), err);
-               return err;
+       if (!isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) {
+               err = iwm_update_quotas(sc, in, 1);
+               if (err) {
+                       printf("%s: could not update quotas (error %d)\n",
+                           DEVNAME(sc), err);
+                       return err;
+               }
        }
 
        ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
@@ -8279,11 +8345,13 @@ iwm_run_stop(struct iwm_softc *sc)
 
        iwm_disable_beacon_filter(sc);
 
-       err = iwm_update_quotas(sc, in, 0);
-       if (err) {
-               printf("%s: could not update quotas (error %d)\n",
-                   DEVNAME(sc), err);
-               return err;
+       if (!isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) {
+               err = iwm_update_quotas(sc, in, 0);
+               if (err) {
+                       printf("%s: could not update quotas (error %d)\n",
+                           DEVNAME(sc), err);
+                       return err;
+               }
        }
 
        err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 0);
index a506216..f93355f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwmreg.h,v 1.53 2021/06/30 09:45:47 stsp Exp $     */
+/*     $OpenBSD: if_iwmreg.h,v 1.54 2021/07/07 08:05:11 stsp Exp $     */
 
 /******************************************************************************
  *
@@ -825,6 +825,7 @@ enum msix_ivar_for_cause {
 #define IWM_UCODE_TLV_API_NAN2_VER2            31
 #define IWM_UCODE_TLV_API_ADAPTIVE_DWELL       32
 #define IWM_UCODE_TLV_API_NEW_RX_STATS         35
+#define IWM_UCODE_TLV_API_QUOTA_LOW_LATENCY    38
 #define IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2    42
 #define IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER    58
 #define IWM_NUM_UCODE_TLV_API                  128
@@ -915,6 +916,7 @@ enum msix_ivar_for_cause {
 #define IWM_UCODE_TLV_CAPA_GSCAN_SUPPORT               31
 #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_EXTENDED_DTS_MEASURE                64
 #define IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS           65
 #define IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT            67
@@ -2867,7 +2869,7 @@ struct iwm_binding_cmd {
  *     remainig quota (after Time Events) according to this quota.
  * @max_duration: max uninterrupted context duration in TU
  */
-struct iwm_time_quota_data {
+struct iwm_time_quota_data_v1 {
        uint32_t id_and_color;
        uint32_t quota;
        uint32_t max_duration;
@@ -2878,9 +2880,40 @@ struct iwm_time_quota_data {
  * ( IWM_TIME_QUOTA_CMD = 0x2c )
  * @quotas: allocations per binding
  */
+struct iwm_time_quota_cmd_v1 {
+       struct iwm_time_quota_data_v1 quotas[IWM_MAX_BINDINGS];
+} __packed; /* IWM_TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */
+
+#define IWM_QUOTA_LOW_LATENCY_NONE     0
+#define IWM_QUOTA_LOW_LATENCY_TX       (1 << 0)
+#define IWM_QUOTA_LOW_LATENCY_RX       (1 << 1)
+
+/**
+ * struct iwm_time_quota_data - configuration of time quota per binding
+ * @id_and_color: ID and color of the relevant Binding.
+ * @quota: absolute time quota in TU. The scheduler will try to divide the
+ *     remainig quota (after Time Events) according to this quota.
+ * @max_duration: max uninterrupted context duration in TU
+ * @low_latency: low latency status IWM_QUOTA_LOW_LATENCY_*
+ */
+struct iwm_time_quota_data {
+       uint32_t id_and_color;
+       uint32_t quota;
+       uint32_t max_duration;
+       uint32_t low_latency;
+}; /* TIME_QUOTA_DATA_API_S_VER_2 */
+
+/**
+ * struct iwm_time_quota_cmd - configuration of time quota between bindings
+ * ( TIME_QUOTA_CMD = 0x2c )
+ * Note: on non-CDB the fourth one is the auxilary mac and is essentially zero.
+ * On CDB the fourth one is a regular binding.
+ *
+ * @quotas: allocations per binding
+ */
 struct iwm_time_quota_cmd {
        struct iwm_time_quota_data quotas[IWM_MAX_BINDINGS];
-} __packed; /* IWM_TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */
+}; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_2 */
 
 
 /* PHY context */