Date: Thu, 1 Mar 2018 05:53:13 +0000 (UTC) From: Eitan Adler <eadler@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r330175 - stable/11/sys/dev/iwm Message-ID: <201803010553.w215rDT7036738@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: eadler Date: Thu Mar 1 05:53:12 2018 New Revision: 330175 URL: https://svnweb.freebsd.org/changeset/base/330175 Log: MFC r313415: [iwm] Implement apmg_wake_up_wa workaround properly for 7000 family. * Add iwm_pcie_set_cmd_in_flight() and iwm_pcie_clear_cmd_in_flight() helper methods. * Use ring->queued tracking in the command queue to set/clear the cmd_hold_nic_awake bit at the right points. Modified: stable/11/sys/dev/iwm/if_iwm.c stable/11/sys/dev/iwm/if_iwm_pcie_trans.c stable/11/sys/dev/iwm/if_iwm_pcie_trans.h stable/11/sys/dev/iwm/if_iwm_util.c stable/11/sys/dev/iwm/if_iwmvar.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/iwm/if_iwm.c ============================================================================== --- stable/11/sys/dev/iwm/if_iwm.c Thu Mar 1 05:52:27 2018 (r330174) +++ stable/11/sys/dev/iwm/if_iwm.c Thu Mar 1 05:53:12 2018 (r330175) @@ -182,7 +182,8 @@ __FBSDID("$FreeBSD$"); #define IWM_DEVICE_7000_COMMON \ .device_family = IWM_DEVICE_FAMILY_7000, \ .eeprom_size = IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000, \ - .nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_7000 + .nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_7000, \ + .apmg_wake_up_wa = 1 const struct iwm_cfg iwm7260_cfg = { .fw_name = IWM7260_FW, @@ -1251,6 +1252,9 @@ iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; + + if (ring->qid == IWM_MVM_CMD_QUEUE && sc->cmd_hold_nic_awake) + iwm_pcie_clear_cmd_in_flight(sc); } static void @@ -3312,6 +3316,18 @@ iwm_cmd_done(struct iwm_softc *sc, struct iwm_rx_packe data->m = NULL; } wakeup(&ring->desc[pkt->hdr.idx]); + + if (((pkt->hdr.idx + ring->queued) % IWM_TX_RING_COUNT) != ring->cur) { + device_printf(sc->sc_dev, + "%s: Some HCMDs skipped?: idx=%d queued=%d cur=%d\n", + __func__, pkt->hdr.idx, ring->queued, ring->cur); + /* XXX call iwm_force_nmi() */ + } + + KASSERT(ring->queued > 0, ("ring->queued is empty?")); + ring->queued--; + if (ring->queued == 0) + iwm_pcie_clear_cmd_in_flight(sc); } #if 0 @@ -5553,9 +5569,6 @@ iwm_notif_intr(struct iwm_softc *sc) ADVANCE_RXQ(sc); } - - IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, - IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* * Tell the firmware what we have processed. Modified: stable/11/sys/dev/iwm/if_iwm_pcie_trans.c ============================================================================== --- stable/11/sys/dev/iwm/if_iwm_pcie_trans.c Thu Mar 1 05:52:27 2018 (r330174) +++ stable/11/sys/dev/iwm/if_iwm_pcie_trans.c Thu Mar 1 05:53:12 2018 (r330175) @@ -253,6 +253,9 @@ iwm_nic_lock(struct iwm_softc *sc) { int rv = 0; + if (sc->cmd_hold_nic_awake) + return 1; + IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -277,6 +280,9 @@ iwm_nic_lock(struct iwm_softc *sc) void iwm_nic_unlock(struct iwm_softc *sc) { + if (sc->cmd_hold_nic_awake) + return; + IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } @@ -582,4 +588,56 @@ iwm_pcie_rx_stop(struct iwm_softc *sc) iwm_nic_unlock(sc); } return ret; +} + +void +iwm_pcie_clear_cmd_in_flight(struct iwm_softc *sc) +{ + if (!sc->cfg->apmg_wake_up_wa) + return; + + if (!sc->cmd_hold_nic_awake) { + device_printf(sc->sc_dev, + "%s: cmd_hold_nic_awake not set\n", __func__); + return; + } + + sc->cmd_hold_nic_awake = 0; + IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} + +int +iwm_pcie_set_cmd_in_flight(struct iwm_softc *sc) +{ + int ret; + + /* + * wake up the NIC to make sure that the firmware will see the host + * command - we will let the NIC sleep once all the host commands + * returned. This needs to be done only on NICs that have + * apmg_wake_up_wa set. + */ + if (sc->cfg->apmg_wake_up_wa && + !sc->cmd_hold_nic_awake) { + + IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + ret = iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), + 15000); + if (ret == 0) { + IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + device_printf(sc->sc_dev, + "%s: Failed to wake NIC for hcmd\n", __func__); + return EIO; + } + sc->cmd_hold_nic_awake = 1; + } + + return 0; } Modified: stable/11/sys/dev/iwm/if_iwm_pcie_trans.h ============================================================================== --- stable/11/sys/dev/iwm/if_iwm_pcie_trans.h Thu Mar 1 05:52:27 2018 (r330174) +++ stable/11/sys/dev/iwm/if_iwm_pcie_trans.h Thu Mar 1 05:53:12 2018 (r330175) @@ -129,4 +129,7 @@ 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); +extern int iwm_pcie_set_cmd_in_flight(struct iwm_softc *sc); +extern void iwm_pcie_clear_cmd_in_flight(struct iwm_softc *sc); + #endif Modified: stable/11/sys/dev/iwm/if_iwm_util.c ============================================================================== --- stable/11/sys/dev/iwm/if_iwm_util.c Thu Mar 1 05:52:27 2018 (r330174) +++ stable/11/sys/dev/iwm/if_iwm_util.c Thu Mar 1 05:53:12 2018 (r330175) @@ -305,17 +305,10 @@ iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); - IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, - IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, - IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000)) { - device_printf(sc->sc_dev, - "%s: acquiring device failed\n", __func__); - error = EBUSY; + error = iwm_pcie_set_cmd_in_flight(sc); + if (error) goto out; - } + ring->queued++; #if 0 iwm_update_sched(sc, ring->qid, ring->cur, 0, 0); Modified: stable/11/sys/dev/iwm/if_iwmvar.h ============================================================================== --- stable/11/sys/dev/iwm/if_iwmvar.h Thu Mar 1 05:52:27 2018 (r330174) +++ stable/11/sys/dev/iwm/if_iwmvar.h Thu Mar 1 05:53:12 2018 (r330175) @@ -389,6 +389,8 @@ enum iwm_device_family { * @host_interrupt_operation_mode: device needs host interrupt operation * mode set * @nvm_hw_section_num: the ID of the HW NVM section + * @apmg_wake_up_wa: should the MAC access REQ be asserted when a command + * is in flight. This is due to a HW bug in 7260, 3160 and 7265. */ struct iwm_cfg { const char *fw_name; @@ -396,6 +398,7 @@ struct iwm_cfg { enum iwm_device_family device_family; int host_interrupt_operation_mode; uint8_t nvm_hw_section_num; + int apmg_wake_up_wa; }; struct iwm_softc { @@ -520,6 +523,8 @@ struct iwm_softc { int sc_max_rssi; struct iwm_notif_wait_data *sc_notif_wait; + + int cmd_hold_nic_awake; }; #define IWM_LOCK_INIT(_sc) \
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803010553.w215rDT7036738>