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;