I'd like to know if this diff helps with iwm(4) performance issues some people have been reporting.
This is not done yet and some details don't really make sense, especially the #if 0 hiding of what should be correct code -- yet, enabling that code makes the problem come back. But hopefully this is generally going in the right direction. Thank you, Edward Wandasiewicz, for pointing out that reverting if_iwm.c r1.85 restores performance. That was the door to this rabbit hole :-) Index: dev/pci/if_iwm.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v retrieving revision 1.132 diff -u -p -r1.132 if_iwm.c --- dev/pci/if_iwm.c 12 Sep 2016 10:18:26 -0000 1.132 +++ dev/pci/if_iwm.c 20 Sep 2016 00:17:38 -0000 @@ -402,10 +402,8 @@ int iwm_config_umac_scan(struct iwm_soft int iwm_umac_scan(struct iwm_softc *); void iwm_ack_rates(struct iwm_softc *, struct iwm_node *, int *, int *); void iwm_mac_ctxt_cmd_common(struct iwm_softc *, struct iwm_node *, - struct iwm_mac_ctx_cmd *, uint32_t); -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); + struct iwm_mac_ctx_cmd *, uint32_t, int); +int iwm_mac_ctxt_cmd(struct iwm_softc *, struct iwm_node *, uint32_t, int); int iwm_update_quotas(struct iwm_softc *, struct iwm_node *); int iwm_auth(struct iwm_softc *); int iwm_assoc(struct iwm_softc *); @@ -2428,7 +2426,7 @@ iwm_htprot_task(void *arg) int err; /* This call updates HT protection based on in->in_ni.ni_htop1. */ - err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY); + err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1); if (err) printf("%s: could not change HT protection: error %d\n", DEVNAME(sc), err); @@ -4203,14 +4201,15 @@ void iwm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in, struct iwm_mac_power_cmd *cmd) { - struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; - int dtimper, dtimper_msec; - int keep_alive; + int dtim_period, dtim_msec, keep_alive; cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); - dtimper = ic->ic_dtim_period ?: 1; + if (ni->ni_dtimperiod) + dtim_period = ni->ni_dtimperiod; + else + dtim_period = 1; /* * Regardless of power management state the driver must set @@ -4218,9 +4217,8 @@ iwm_power_build_cmd(struct iwm_softc *sc * immediately after association. Check that keep alive period * is at least 3 * DTIM. */ - dtimper_msec = dtimper * ni->ni_intval; - keep_alive - = MAX(3 * dtimper_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC); + dtim_msec = dtim_period * ni->ni_intval * IEEE80211_DUR_TU; + keep_alive = MAX(3 * dtim_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC); keep_alive = roundup(keep_alive, 1000) / 1000; cmd->keep_alive_seconds = htole16(keep_alive); } @@ -4249,14 +4247,12 @@ iwm_power_mac_update_mode(struct iwm_sof int iwm_power_update_device(struct iwm_softc *sc) { - struct iwm_device_power_cmd cmd = { - .flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), - }; + struct iwm_device_power_cmd cmd; if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) return 0; - cmd.flags |= htole16(IWM_DEVICE_POWER_FLAGS_CAM_MSK); + cmd.flags = htole16(IWM_DEVICE_POWER_FLAGS_CAM_MSK); return iwm_send_cmd_pdu(sc, IWM_POWER_TABLE_CMD, 0, sizeof(cmd), &cmd); @@ -4975,7 +4971,7 @@ iwm_ack_rates(struct iwm_softc *sc, stru void iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in, - struct iwm_mac_ctx_cmd *cmd, uint32_t action) + struct iwm_mac_ctx_cmd *cmd, uint32_t action, int assoc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; @@ -4987,14 +4983,17 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc cmd->action = htole32(action); cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA); - cmd->tsf_id = htole32(in->in_tsfid); + cmd->tsf_id = htole32(IWM_TSF_ID_A); IEEE80211_ADDR_COPY(cmd->node_addr, ic->ic_myaddr); - if (in->in_assoc) { + +#if 0 /* For some reason setting our BSSID here causes Rx problems. */ + if (assoc) IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid); - } else { + else +#endif IEEE80211_ADDR_COPY(cmd->bssid_addr, etherbroadcastaddr); - } + iwm_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates); cmd->cck_rates = htole32(cck_ack_rates); cmd->ofdm_rates = htole32(ofdm_ack_rates); @@ -5040,47 +5039,44 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc if (ic->ic_flags & IEEE80211_F_USEPROT) cmd->protection_flags |= htole32(IWM_MAC_PROT_FLG_TGG_PROTECT); - cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP); -} - -void -iwm_mac_ctxt_cmd_fill_sta(struct iwm_softc *sc, struct iwm_node *in, - struct iwm_mac_data_sta *ctxt_sta, int force_assoc_off) -{ - struct ieee80211_node *ni = &in->in_ni; - struct ieee80211com *ic = &sc->sc_ic; - - ctxt_sta->is_assoc = htole32(0); - ctxt_sta->bi = htole32(ni->ni_intval); - ctxt_sta->bi_reciprocal = htole32(iwm_reciprocal(ni->ni_intval)); - ctxt_sta->dtim_interval = htole32(ni->ni_intval * ic->ic_dtim_period); - ctxt_sta->dtim_reciprocal = - htole32(iwm_reciprocal(ni->ni_intval * ic->ic_dtim_period)); - - /* 10 = CONN_MAX_LISTEN_INTERVAL */ - ctxt_sta->listen_interval = htole32(10); - ctxt_sta->assoc_id = htole32(ni->ni_associd); + cmd->filter_flags |= htole32(IWM_MAC_FILTER_ACCEPT_GRP); } int -iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action) +iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action, + int assoc) { + struct ieee80211_node *ni = &in->in_ni; struct iwm_mac_ctx_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - iwm_mac_ctxt_cmd_common(sc, in, &cmd, action); + iwm_mac_ctxt_cmd_common(sc, in, &cmd, action, assoc); - /* Allow beacons to pass through as long as we are not associated or we - * do not have dtim period information */ - if (!in->in_assoc || !sc->sc_ic.ic_dtim_period) + /* Allow beacons to pass through as long as we are not associated + * or we do not have dtim period information */ + if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod) { cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON); - else - cmd.filter_flags &= ~htole32(IWM_MAC_FILTER_IN_BEACON); - - /* Fill the data specific for station mode */ - iwm_mac_ctxt_cmd_fill_sta(sc, in, - &cmd.sta, action == IWM_FW_CTXT_ACTION_ADD); + } else { + /* Fill in the data specific for station mode. */ + uint32_t dtim_off; + uint64_t tsf; + + dtim_off = ni->ni_nextdtim * ni->ni_intval * IEEE80211_DUR_TU; + cmd.sta.dtim_time = htole32(ni->ni_rstamp + dtim_off); + memcpy(&tsf, ni->ni_tstamp, sizeof(ni->ni_tstamp)); + tsf = letoh64(tsf); + cmd.sta.dtim_tsf = htole64(tsf + dtim_off); + cmd.sta.bi = htole32(ni->ni_intval); + cmd.sta.bi_reciprocal = htole32(iwm_reciprocal(ni->ni_intval)); + cmd.sta.dtim_interval = + htole32(ni->ni_intval * ni->ni_dtimperiod); + cmd.sta.dtim_reciprocal = + htole32(iwm_reciprocal(ni->ni_intval * ni->ni_dtimperiod)); + cmd.sta.is_assoc = htole32(1); + cmd.sta.listen_interval = htole32(10); + cmd.sta.assoc_id = htole32(ni->ni_associd); + } return iwm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, 0, sizeof(cmd), &cmd); @@ -5157,8 +5153,6 @@ iwm_auth(struct iwm_softc *sc) uint32_t duration; int err; - in->in_assoc = 0; - err = iwm_sf_config(sc, IWM_SF_FULL_ON); if (err) return err; @@ -5182,7 +5176,7 @@ iwm_auth(struct iwm_softc *sc) if (err) return err; - err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY); + err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 0); if (err) { printf("%s: failed to update MAC\n", DEVNAME(sc)); return err; @@ -5211,14 +5205,6 @@ iwm_assoc(struct iwm_softc *sc) if (err) return err; - in->in_assoc = 1; - - err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY); - if (err) { - printf("%s: failed to update MAC\n", DEVNAME(sc)); - return err; - } - return 0; } @@ -5422,10 +5408,6 @@ iwm_newstate_task(void *psc) /* Reset the device if moving out of AUTH, ASSOC, or RUN. */ /* XXX Is there a way to switch states without a full reset? */ if (ostate > IEEE80211_S_SCAN && nstate < ostate) { - in = (struct iwm_node *)ic->ic_bss; - if (in) - in->in_assoc = 0; - iwm_stop_device(sc); iwm_init_hw(sc); @@ -5479,7 +5461,13 @@ iwm_newstate_task(void *psc) case IEEE80211_S_RUN: in = (struct iwm_node *)ic->ic_bss; - iwm_power_mac_update_mode(sc, in); + + err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1); + if (err) { + printf("%s: failed to update MAC\n", DEVNAME(sc)); + return; + } + #ifdef notyet /* * Disabled for now. Default beacon filter settings @@ -5487,6 +5475,7 @@ iwm_newstate_task(void *psc) * updates from beacons. */ iwm_enable_beacon_filter(sc, in); + iwm_power_mac_update_mode(sc, in); #endif iwm_update_quotas(sc, in); @@ -5853,7 +5842,7 @@ iwm_init_hw(struct iwm_softc *sc) } } - err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD); + err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD, 0); if (err) { printf("%s: could not add MAC context (error %d)\n", DEVNAME(sc), err); @@ -6009,7 +5998,6 @@ iwm_stop(struct ifnet *ifp, int disable) ifq_clr_oactive(&ifp->if_snd); in->in_phyctxt = NULL; - in->in_assoc = 0; task_del(systq, &sc->init_task); task_del(sc->sc_nswq, &sc->newstate_task); Index: dev/pci/if_iwmreg.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwmreg.h,v retrieving revision 1.18 diff -u -p -r1.18 if_iwmreg.h --- dev/pci/if_iwmreg.h 10 Sep 2016 09:32:33 -0000 1.18 +++ dev/pci/if_iwmreg.h 19 Sep 2016 22:41:13 -0000 @@ -3503,7 +3503,7 @@ struct iwm_ac_qos { * @id_and_color: ID and color of the MAC * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @mac_type: one of IWM_FW_MAC_TYPE_* - * @tsd_id: TSF HW timer, one of IWM_TSF_ID_* + * @tsf_id: TSF HW timer, one of IWM_TSF_ID_* * @node_addr: MAC address * @bssid_addr: BSSID * @cck_rates: basic rates available for CCK Index: dev/pci/if_iwmvar.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwmvar.h,v retrieving revision 1.23 diff -u -p -r1.23 if_iwmvar.h --- dev/pci/if_iwmvar.h 12 Sep 2016 10:18:26 -0000 1.23 +++ dev/pci/if_iwmvar.h 19 Sep 2016 22:41:13 -0000 @@ -501,10 +501,6 @@ struct iwm_node { uint16_t in_id; uint16_t in_color; - int in_tsfid; - - /* status "bits" */ - int in_assoc; struct iwm_lq_cmd in_lq; struct ieee80211_amrr_node in_amn; Index: net80211/ieee80211_input.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v retrieving revision 1.178 diff -u -p -r1.178 ieee80211_input.c --- net80211/ieee80211_input.c 18 May 2016 08:15:28 -0000 1.178 +++ net80211/ieee80211_input.c 19 Sep 2016 22:41:25 -0000 @@ -1393,7 +1393,7 @@ ieee80211_recv_probe_resp(struct ieee802 const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie; const u_int8_t *rsnie, *wpaie, *htcaps, *htop; u_int16_t capinfo, bintval; - u_int8_t chan, bchan, erp; + u_int8_t chan, bchan, erp, dtim_count, dtim_period; int is_new; /* @@ -1436,6 +1436,7 @@ ieee80211_recv_probe_resp(struct ieee802 bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); chan = bchan; erp = 0; + dtim_count = dtim_period = 0; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) { ic->ic_stats.is_rx_elem_toosmall++; @@ -1477,6 +1478,12 @@ ieee80211_recv_probe_resp(struct ieee802 case IEEE80211_ELEMID_HTOP: htop = frm; break; + case IEEE80211_ELEMID_TIM: + if (frm[1] > 2) { + dtim_count = frm[2]; + dtim_period = frm[3]; + } + break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) { ic->ic_stats.is_rx_elem_toosmall++; @@ -1567,6 +1574,9 @@ ieee80211_recv_probe_resp(struct ieee802 ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]); if (htop && !ieee80211_setup_htop(ni, htop + 2, htop[1])) htop = NULL; /* invalid HTOP */ + + ni->ni_dtimperiod = dtim_period; + ni->ni_nextdtim = dtim_count; /* * When operating in station mode, check for state updates Index: net80211/ieee80211_node.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_node.h,v retrieving revision 1.60 diff -u -p -r1.60 ieee80211_node.h --- net80211/ieee80211_node.h 28 Apr 2016 08:18:10 -0000 1.60 +++ net80211/ieee80211_node.h 19 Sep 2016 22:41:25 -0000 @@ -188,7 +188,6 @@ struct ieee80211_node { struct ieee80211_channel *ni_chan; u_int8_t ni_erp; /* 11g only */ -#ifdef notyet /* DTIM and contention free period (CFP) */ u_int8_t ni_dtimperiod; u_int8_t ni_cfpperiod; /* # of DTIMs between CFPs */ @@ -196,7 +195,6 @@ struct ieee80211_node { u_int16_t ni_cfpmaxduration;/* max CFP duration in TU */ u_int16_t ni_nextdtim; /* time to next DTIM */ u_int16_t ni_timoffset; -#endif /* power saving mode */ u_int8_t ni_pwrsave;