The resume code path of iwx(4) was improved during the k2k21 hackathon.
This patch merges the corresponding changes to iwm(4), such that iwm(4)
resumes directly in DVACT_WAKEUP instead of using the init task.
Tested by me on an 8265 device.
ok?
diff 02c3ac519701a4fe198f8ee3de592b34a39ee6f7
d18bc0f805b2b0ec7e08f833f15080cb1614e08c
blob - 92f77754c4dd9d8a340a24bc2ce6f89ca77e0f84
blob + 2410b7d65756166edd8e68fed251c681eddb8851
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -550,7 +550,8 @@ void iwm_attach_hook(struct device *);
void iwm_attach(struct device *, struct device *, void *);
void iwm_init_task(void *);
int iwm_activate(struct device *, int);
-int iwm_resume(struct iwm_softc *);
+void iwm_resume(struct iwm_softc *);
+int iwm_wakeup(struct iwm_softc *);
#if NBPFILTER > 0
void iwm_radiotap_attach(struct iwm_softc *);
@@ -1554,11 +1555,8 @@ int
iwm_check_rfkill(struct iwm_softc *sc)
{
uint32_t v;
- int s;
int rv;
- s = splnet();
-
/*
* "documentation" is not really helpful here:
* 27: HW_RF_KILL_SW
@@ -1574,7 +1572,6 @@ iwm_check_rfkill(struct iwm_softc *sc)
sc->sc_flags &= ~IWM_FLAG_RFKILL;
}
- splx(s);
return rv;
}
@@ -1622,8 +1619,6 @@ iwm_restore_interrupts(struct iwm_softc *sc)
void
iwm_disable_interrupts(struct iwm_softc *sc)
{
- int s = splnet();
-
if (!sc->sc_msix) {
IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
@@ -1636,8 +1631,6 @@ iwm_disable_interrupts(struct iwm_softc *sc)
IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD,
sc->sc_hw_init_mask);
}
-
- splx(s);
}
void
@@ -9679,18 +9672,8 @@ int
iwm_init_hw(struct iwm_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- int err, i, ac, qid;
+ int err, i, ac, qid, s;
- err = iwm_preinit(sc);
- if (err)
- return err;
-
- err = iwm_start_hw(sc);
- if (err) {
- printf("%s: could not initialize hardware\n", DEVNAME(sc));
- return err;
- }
-
err = iwm_run_init_mvm_ucode(sc, 0);
if (err)
return err;
@@ -9704,14 +9687,18 @@ iwm_init_hw(struct iwm_softc *sc)
}
/* Restart, this time with the regular firmware */
+ s = splnet();
err = iwm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_REGULAR);
if (err) {
printf("%s: could not load firmware\n", DEVNAME(sc));
- goto err;
+ splx(s);
+ return err;
}
- if (!iwm_nic_lock(sc))
+ if (!iwm_nic_lock(sc)) {
+ splx(s);
return EBUSY;
+ }
err = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc));
if (err) {
@@ -9738,20 +9725,20 @@ iwm_init_hw(struct iwm_softc *sc)
if (err) {
printf("%s: could not init bt coex (error %d)\n",
DEVNAME(sc), err);
- return err;
+ goto err;
}
if (isset(sc->sc_enabled_capa,
IWM_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT)) {
err = iwm_send_soc_conf(sc);
if (err)
- return err;
+ goto err;
}
if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) {
err = iwm_send_dqa_cmd(sc);
if (err)
- return err;
+ goto err;
}
/* Add auxiliary station for scanning */
@@ -9859,6 +9846,7 @@ iwm_init_hw(struct iwm_softc *sc)
err:
iwm_nic_unlock(sc);
+ splx(s);
return err;
}
@@ -9902,6 +9890,16 @@ iwm_init(struct ifnet *ifp)
KASSERT(sc->task_refs.refs == 0);
refcnt_init(&sc->task_refs);
+ err = iwm_preinit(sc);
+ if (err)
+ return err;
+
+ err = iwm_start_hw(sc);
+ if (err) {
+ printf("%s: could not initialize hardware\n", DEVNAME(sc));
+ return err;
+ }
+
err = iwm_init_hw(sc);
if (err) {
if (generation == sc->sc_generation)
@@ -11180,7 +11178,10 @@ iwm_attach(struct device *parent, struct device *self,
return;
}
- /* Clear device-specific "PCI retry timeout" register (41h). */
+ /*
+ * We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state.
+ */
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
@@ -11576,12 +11577,15 @@ iwm_init_task(void *arg1)
splx(s);
}
-int
+void
iwm_resume(struct iwm_softc *sc)
{
pcireg_t reg;
- /* Clear device-specific "PCI retry timeout" register (41h). */
+ /*
+ * We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state.
+ */
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
@@ -11596,8 +11600,34 @@ iwm_resume(struct iwm_softc *sc)
}
iwm_disable_interrupts(sc);
+}
- return iwm_start_hw(sc);
+int
+iwm_wakeup(struct iwm_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ int err;
+
+ refcnt_init(&sc->task_refs);
+
+ err = iwm_start_hw(sc);
+ if (err)
+ return err;
+
+ err = iwm_init_hw(sc);
+ if (err)
+ return err;
+
+ ifq_clr_oactive(&ifp->if_snd);
+ ifp->if_flags |= IFF_RUNNING;
+
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ else
+ ieee80211_begin_scan(ifp);
+
+ return 0;
}
int
@@ -11616,15 +11646,15 @@ iwm_activate(struct device *self, int act)
}
break;
case DVACT_RESUME:
- err = iwm_resume(sc);
- if (err)
- printf("%s: could not initialize hardware\n",
- DEVNAME(sc));
+ iwm_resume(sc);
break;
case DVACT_WAKEUP:
- /* Hardware should be up at this point. */
- if (iwm_set_hw_ready(sc))
- task_add(systq, &sc->init_task);
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) {
+ err = iwm_wakeup(sc);
+ if (err)
+ printf("%s: could not initialize hardware\n",
+ DEVNAME(sc));
+ }
break;
}