From nobody Mon Oct 12 02:51:38 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4j326f665Gz6vDZF for ; Mon, 12 Oct 2026 02:51:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4j326f3mNVz4Tst for ; Mon, 12 Oct 2026 02:51:38 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791773498; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sk2p+WM2fG3EGpZG5zPghyJyGFO8UqGxt18X0X1Cgwo=; b=UDlQzx/sIBpxfOa77xlynaz++MnwBDU9qbOitJMjHPcGvVPko4osXx0E5Y96KGvHCetfzk zY5uiAMfSan9xJQVN3SCjB/RwzS3oOiWoUQOJl3FJ9NAWqVw+D4tlkB2NgjlwXQF3d856O WG00LVhm8zTYnbQ8DtdHXIhppurAyP7f+wc7OBA7D08tk18M2c7Hju9UjRC3DPtjwn2EV9 DegmMLKG+/eNeow8yc1eT/hPKbbLfZ92BJeApv7dEEpgXolsjDSADbRvU+flRXCYNB9jnw OYk9H2XbYHMlymJUfc/XH3hS7QyeHHso1gu4P/hszcHBE/VGFZn4mP7yhBFACg== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1791773498; b=bDs6PsIpfleqffbDVdzvl6XrsJObUXxQuLR/bsFE7PQRflJVDoW4y875zD9SKAw+8P+Pt+ a60CO5XJbx1TSnNOYaEx7+SM+YonZo2Gtnwm4kstITmm6aFLpQhZ3xkWsqW59cPoYRy62U NoHKP3t2WzfosBMw+5QV39t5tOK2fHXewb5I8nEtmZINswH5KTkHwKnOaZITTN6xJjoLNQ HOiYNjB6HnX8grHCLG+aymcOcUJe6N64aN99YDcLJWgwNi8YGICN6lRhcMd/kFmrDNRUmS 6zwuGZ4bAqNKVQH7LI49W0IXBqPkSLgRho8ISPfvzaV31OXoJqcMIhG350/wtA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791773498; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=sk2p+WM2fG3EGpZG5zPghyJyGFO8UqGxt18X0X1Cgwo=; b=N7+kXfkhETqbKaEf5NtUGSjBZ+4S1G35g9pqnSXUD+hKqeovEScqeW7fkxymw+hRCD2mFr Y6lV+Pe8WDsAYc0hwAQEac9UDWWS9mAqr3XRzKODo+QN1iqIzHGk+dkcfvFkJ+aOm7h81Q /hqpXlRgNzpud1jXabM9DzFgoMTxitBDhzI/Z/I+p0y9e1n/YqtpicSlsZjqYNN0N482tQ YD5wqmgvlUCXStw3X9EfXmxnAU2BuEYZFl+jzOIHHMt/mH8TOkLBuwa9YMlfFZXUPkG/Cy mHwtwQg24PcteExzXce7Rj6EGt/CcFm0ZkNK+o5uEQtRbVICHsidnq0dB/o/Nw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4j326f2qnsz189Z for ; Mon, 12 Oct 2026 02:51:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 42d5c by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 12 Oct 2026 02:51:38 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Adrian Chadd Subject: git: 8f93ad70078a - main - iwm: add MSI-X support List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: Commit messages for the main branch of the src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: adrian X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 8f93ad70078a88710d34b371a4076191cfebc4f6 Auto-Submitted: auto-generated Date: Mon, 12 Oct 2026 02:51:38 +0000 Message-Id: <6acc4b3a.42d5c.3b1f3711@gitrepo.freebsd.org> The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=8f93ad70078a88710d34b371a4076191cfebc4f6 commit 8f93ad70078a88710d34b371a4076191cfebc4f6 Author: Adrian Chadd AuthorDate: 2026-10-12 02:50:57 +0000 Commit: Adrian Chadd CommitDate: 2026-10-12 02:50:57 +0000 iwm: add MSI-X support This brings over the MSI-X support from OpenBSD. It's mostly untested at this point. Locally tested: * Intel 7260, STA mode (but I don't know yet if it used msi-x) Obtained from: OpenBSD a6e25c727a2214219715b51ba6af2221d7e0d674 Differential Revision: https://reviews.freebsd.org/D60079 --- sys/dev/iwm/if_iwm.c | 155 +++++++++++++++++++++++++++++++++++++--- sys/dev/iwm/if_iwm_pcie_trans.c | 123 +++++++++++++++++++++++++++++-- sys/dev/iwm/if_iwm_pcie_trans.h | 2 + sys/dev/iwm/if_iwmvar.h | 7 ++ 4 files changed, 269 insertions(+), 18 deletions(-) diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index ed5949e3df6b..ddf781d247b6 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -402,6 +402,7 @@ static void iwm_nic_umac_error(struct iwm_softc *); static void iwm_handle_rxb(struct iwm_softc *, struct mbuf *); static void iwm_notif_intr(struct iwm_softc *); static void iwm_intr(void *); +static void iwm_intr_msix(void *); static int iwm_attach(device_t); static int iwm_is_valid_ether_addr(uint8_t *); static void iwm_preinit(void *); @@ -1266,8 +1267,21 @@ iwm_free_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring) static void iwm_enable_interrupts(struct iwm_softc *sc) { - sc->sc_intmask = IWM_CSR_INI_SET_MASK; - IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); + if (!sc->sc_msix) { + sc->sc_intmask = IWM_CSR_INI_SET_MASK; + IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); + } else { + /* + * fh/hw_mask keeps all the unmasked causes. + * Unlike msi, in msix cause is enabled when it is unset. + */ + sc->sc_hw_mask = sc->sc_hw_init_mask; + sc->sc_fh_mask = sc->sc_fh_init_mask; + IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, + ~sc->sc_fh_mask); + IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, + ~sc->sc_hw_mask); + } } static void @@ -1279,12 +1293,19 @@ iwm_restore_interrupts(struct iwm_softc *sc) static void iwm_disable_interrupts(struct iwm_softc *sc) { - /* disable interrupts */ - IWM_WRITE(sc, IWM_CSR_INT_MASK, 0); + if (!sc->sc_msix) { + /* disable interrupts */ + IWM_WRITE(sc, IWM_CSR_INT_MASK, 0); - /* acknowledge all interrupts */ - IWM_WRITE(sc, IWM_CSR_INT, ~0); - IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, ~0); + /* acknowledge all interrupts */ + IWM_WRITE(sc, IWM_CSR_INT, ~0); + IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, ~0); + } else { + IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, + sc->sc_fh_init_mask); + IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, + sc->sc_hw_init_mask); + } } static void @@ -1398,8 +1419,18 @@ iwm_stop_device(struct iwm_softc *sc) IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET); DELAY(5000); + /* + * Upon stop, the IVAR table gets erased, so msi-x won't + * work. This causes a bug in RF-KILL flows, since the interrupt + * that enables radio won't fire on the correct irq, and the + * driver won't be able to handle the interrupt. + * Configure the IVAR table again after reset. + */ + iwm_conf_msix_hw(sc, 1); + /* * Upon stop, the APM issues an interrupt if HW RF kill is set. + * Clear the interrupt again. */ iwm_disable_interrupts(sc); @@ -2709,8 +2740,17 @@ static inline void iwm_enable_fw_load_int(struct iwm_softc *sc) { IWM_DPRINTF(sc, IWM_DEBUG_INTR, "Enabling FW load interrupt\n"); - sc->sc_intmask = IWM_CSR_INT_BIT_FH_TX; - IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); + + if (!sc->sc_msix) { + sc->sc_intmask = IWM_CSR_INT_BIT_FH_TX; + IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); + } else { + IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, + sc->sc_hw_init_mask); + IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, + ~IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM); + sc->sc_fh_mask = IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM; + } } /* XXX Add proper rfkill support code */ @@ -5957,6 +5997,95 @@ iwm_intr(void *arg) return; } +static void +iwm_intr_msix(void *arg) +{ + struct iwm_softc *sc = arg; + uint32_t inta_fh, inta_hw; + int vector = 0; + + IWM_LOCK(sc); + + inta_fh = IWM_READ(sc, IWM_CSR_MSIX_FH_INT_CAUSES_AD); + inta_hw = IWM_READ(sc, IWM_CSR_MSIX_HW_INT_CAUSES_AD); + /* acknowledge all interrupts */ + IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_CAUSES_AD, inta_fh); + IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); + inta_fh &= sc->sc_fh_mask; + inta_hw &= sc->sc_hw_mask; + + if (inta_fh & IWM_MSIX_FH_INT_CAUSES_Q0 || + inta_fh & IWM_MSIX_FH_INT_CAUSES_Q1) + iwm_notif_intr(sc); + + /* firmware chunk loaded */ + if (inta_fh & IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM) { + sc->sc_fw_chunk_done = 1; + wakeup(&sc->sc_fw); + } + + if ((inta_fh & IWM_MSIX_FH_INT_CAUSES_FH_ERR) || + (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR) || + (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR_V2)) { + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap; + int i; + +#ifdef IWM_DEBUG + iwm_nic_error(sc); +#endif + /* Dump driver status (TX and RX rings) while we're here. */ + device_printf(sc->sc_dev, "driver status:\n"); + for (i = 0; i < IWM_MAX_QUEUES; i++) { + struct iwm_tx_ring *ring = &sc->txq[i]; + device_printf(sc->sc_dev, + " tx ring %2d: qid=%-2d cur=%-3d " + "queued=%-3d\n", + i, ring->qid, ring->cur, ring->queued); + } + device_printf(sc->sc_dev, " rx ring: cur=%d\n", sc->rxq.cur); + + /* Reset our firmware state tracking. */ + sc->sc_firmware_state = 0; + IWM_UNLOCK(sc); + + vap = TAILQ_FIRST(&ic->ic_vaps); + if (vap == NULL) { + printf("%s: null vap\n", __func__); + return; + } + + device_printf(sc->sc_dev, + "%s: controller panicked, iv_state = %d; restarting\n", + __func__, vap->iv_state); + + ieee80211_restart_all(ic); + return; + } + + if (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL) + taskqueue_enqueue(sc->sc_tq, &sc->sc_rftoggle_task); + + if (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_HW_ERR) { + device_printf(sc->sc_dev, "hardware error, stopping device\n"); + iwm_stop(sc); + goto out; + } + + /* + * Before sending the interrupt the HW disables it to prevent + * a nested interrupt. This is done by writing 1 to the + * corresponding bit in the mask register. After handling the + * interrupt, it should be re-enabled by clearing this bit. + * This register is defined as a write 1 clear (W1C) register, + * meaning that it's being cleared by writing 1 to the bit. + */ + IWM_WRITE(sc, IWM_CSR_MSIX_AUTOMASK_ST_AD, 1 << vector); + + out: + IWM_UNLOCK(sc); +} + /* * Autoconf glue-sniffing */ @@ -6074,8 +6203,12 @@ iwm_pci_attach(device_t dev) /* Install interrupt handler. */ count = 1; rid = 0; - if (pci_alloc_msi(dev, &count) == 0) + if (pci_alloc_msix(dev, &count) == 0) { rid = 1; + sc->sc_msix = 1; + } else if (pci_alloc_msi(dev, &count) == 0) { + rid = 1; + } sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); if (sc->sc_irq == NULL) { @@ -6083,7 +6216,7 @@ iwm_pci_attach(device_t dev) return (ENXIO); } error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE, - NULL, iwm_intr, sc, &sc->sc_ih); + NULL, sc->sc_msix ? iwm_intr_msix : iwm_intr, sc, &sc->sc_ih); if (error != 0) { device_printf(dev, "can't establish interrupt"); return (error); diff --git a/sys/dev/iwm/if_iwm_pcie_trans.c b/sys/dev/iwm/if_iwm_pcie_trans.c index ce7526b0377d..39b96f66fbde 100644 --- a/sys/dev/iwm/if_iwm_pcie_trans.c +++ b/sys/dev/iwm/if_iwm_pcie_trans.c @@ -342,10 +342,20 @@ iwm_clear_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits) void iwm_enable_rfkill_int(struct iwm_softc *sc) { - sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL; - IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); - IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, - IWM_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); + if (!sc->sc_msix) { + sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL; + IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); + } else { + IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, + sc->sc_fh_init_mask); + IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, + ~IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL); + sc->sc_hw_mask = IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL; + } + + if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_9000) + IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); } int @@ -640,6 +650,107 @@ iwm_clear_persistence_bit(struct iwm_softc *sc) return 0; } +void +iwm_init_msix_hw(struct iwm_softc *sc) +{ + iwm_conf_msix_hw(sc, 0); + + if (!sc->sc_msix) + return; + + sc->sc_fh_init_mask = ~IWM_READ(sc, IWM_CSR_MSIX_FH_INT_MASK_AD); + sc->sc_fh_mask = sc->sc_fh_init_mask; + sc->sc_hw_init_mask = ~IWM_READ(sc, IWM_CSR_MSIX_HW_INT_MASK_AD); + sc->sc_hw_mask = sc->sc_hw_init_mask; +} + +void +iwm_conf_msix_hw(struct iwm_softc *sc, int stopped) +{ + int vector = 0; + + if (!sc->sc_msix) { + /* Newer chips default to MSIX. */ + if (sc->cfg->mqrx_supported && !stopped && iwm_nic_lock(sc)) { + iwm_write_prph(sc, IWM_UREG_CHICK, + IWM_UREG_CHICK_MSI_ENABLE); + iwm_nic_unlock(sc); + } + return; + } + + if (!stopped && iwm_nic_lock(sc)) { + iwm_write_prph(sc, IWM_UREG_CHICK, IWM_UREG_CHICK_MSIX_ENABLE); + iwm_nic_unlock(sc); + } + + /* Disable all interrupts */ + IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, ~0); + IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, ~0); + + /* Map fallback-queue (command/mgmt) to a single vector */ + IWM_WRITE_1(sc, IWM_CSR_MSIX_RX_IVAR(0), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + /* Map RSS queue (data) to the same vector */ + IWM_WRITE_1(sc, IWM_CSR_MSIX_RX_IVAR(1), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + + /* Enable the RX queues cause interrupts */ + IWM_CLRBITS(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, + IWM_MSIX_FH_INT_CAUSES_Q0 | IWM_MSIX_FH_INT_CAUSES_Q1); + + /* Map non-RX causes to the same vector */ + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_D2S_CH0_NUM), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_D2S_CH1_NUM), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_S2D), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_FH_ERR), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_ALIVE), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_WAKEUP), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_IML), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_CT_KILL), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_RF_KILL), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_PERIODIC), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_SW_ERR), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_SCD), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_FH_TX), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_HW_ERR), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_HAP), + vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); + + /* Enable non-RX causes interrupts */ + IWM_CLRBITS(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, + IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM | + IWM_MSIX_FH_INT_CAUSES_D2S_CH1_NUM | + IWM_MSIX_FH_INT_CAUSES_S2D | + IWM_MSIX_FH_INT_CAUSES_FH_ERR); + IWM_CLRBITS(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, + IWM_MSIX_HW_INT_CAUSES_REG_ALIVE | + IWM_MSIX_HW_INT_CAUSES_REG_WAKEUP | + IWM_MSIX_HW_INT_CAUSES_REG_IML | + IWM_MSIX_HW_INT_CAUSES_REG_CT_KILL | + IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL | + IWM_MSIX_HW_INT_CAUSES_REG_PERIODIC | + IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR | + IWM_MSIX_HW_INT_CAUSES_REG_SCD | + IWM_MSIX_HW_INT_CAUSES_REG_FH_TX | + IWM_MSIX_HW_INT_CAUSES_REG_HW_ERR | + IWM_MSIX_HW_INT_CAUSES_REG_HAP); +} + /* iwlwifi pcie/trans.c */ int iwm_start_hw(struct iwm_softc *sc) @@ -661,9 +772,7 @@ iwm_start_hw(struct iwm_softc *sc) if ((error = iwm_apm_init(sc)) != 0) return error; - /* On newer chipsets MSI is disabled by default. */ - if (sc->cfg->mqrx_supported) - iwm_write_prph(sc, IWM_UREG_CHICK, IWM_UREG_CHICK_MSI_ENABLE); + iwm_init_msix_hw(sc); iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); diff --git a/sys/dev/iwm/if_iwm_pcie_trans.h b/sys/dev/iwm/if_iwm_pcie_trans.h index f55707e1c96f..a236009802a6 100644 --- a/sys/dev/iwm/if_iwm_pcie_trans.h +++ b/sys/dev/iwm/if_iwm_pcie_trans.h @@ -129,6 +129,8 @@ extern void iwm_apm_config(struct iwm_softc *sc); extern int iwm_apm_init(struct iwm_softc *sc); extern void iwm_apm_stop(struct iwm_softc *sc); extern int iwm_clear_persistence_bit(struct iwm_softc *sc); +extern void iwm_conf_msix_hw(struct iwm_softc *sc, int stopped); +extern void iwm_init_msix_hw(struct iwm_softc *sc); extern int iwm_start_hw(struct iwm_softc *sc); extern void iwm_set_pwr(struct iwm_softc *sc); extern int iwm_pcie_rx_stop(struct iwm_softc *sc); diff --git a/sys/dev/iwm/if_iwmvar.h b/sys/dev/iwm/if_iwmvar.h index 424587ad88a2..4231b394cfe4 100644 --- a/sys/dev/iwm/if_iwmvar.h +++ b/sys/dev/iwm/if_iwmvar.h @@ -475,6 +475,13 @@ struct iwm_softc { int sc_intmask; + /* MSIX support */ + int sc_msix; + uint32_t sc_fh_init_mask; + uint32_t sc_fh_mask; + uint32_t sc_hw_init_mask; + uint32_t sc_hw_mask; + /* * So why do we need a separate stopped flag and a generation? * the former protects the device from issuing commands when it's