From 245b2a48f19fcdcfe186ddfc30916774fc5e6f9b Mon Sep 17 00:00:00 2001 From: stsp Date: Wed, 7 Jul 2021 08:05:11 +0000 Subject: [PATCH] Support a new time quota command required for newer iwm(4) firmware. --- sys/dev/pci/if_iwm.c | 94 +++++++++++++++++++++++++++++++++++------ sys/dev/pci/if_iwmreg.h | 39 +++++++++++++++-- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c index a3bf3f8ac47..59bdeb8dfe1 100644 --- a/sys/dev/pci/if_iwm.c +++ b/sys/dev/pci/if_iwm.c @@ -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 @@ -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); diff --git a/sys/dev/pci/if_iwmreg.h b/sys/dev/pci/if_iwmreg.h index a5062160551..f93355f9a61 100644 --- a/sys/dev/pci/if_iwmreg.h +++ b/sys/dev/pci/if_iwmreg.h @@ -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 */ -- 2.20.1