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) \
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to