Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 Feb 2017 06:53:23 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r313415 - head/sys/dev/iwm
Message-ID:  <201702080653.v186rNVx013225@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Wed Feb  8 06:53:23 2017
New Revision: 313415
URL: https://svnweb.freebsd.org/changeset/base/313415

Log:
  [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.
  
  Taken-From: Linux iwlwifi
  
  Obtained from:	DragonflyBSD commit ce43f57f5308b579ea21e8a5a29969114ba2247d

Modified:
  head/sys/dev/iwm/if_iwm.c
  head/sys/dev/iwm/if_iwm_pcie_trans.c
  head/sys/dev/iwm/if_iwm_pcie_trans.h
  head/sys/dev/iwm/if_iwm_util.c
  head/sys/dev/iwm/if_iwmvar.h

Modified: head/sys/dev/iwm/if_iwm.c
==============================================================================
--- head/sys/dev/iwm/if_iwm.c	Wed Feb  8 06:50:59 2017	(r313414)
+++ head/sys/dev/iwm/if_iwm.c	Wed Feb  8 06:53:23 2017	(r313415)
@@ -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, 
 	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
@@ -3338,6 +3342,18 @@ iwm_cmd_done(struct iwm_softc *sc, struc
 		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
@@ -5580,9 +5596,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.
 	 * Seems like the hardware gets upset unless we align

Modified: head/sys/dev/iwm/if_iwm_pcie_trans.c
==============================================================================
--- head/sys/dev/iwm/if_iwm_pcie_trans.c	Wed Feb  8 06:50:59 2017	(r313414)
+++ head/sys/dev/iwm/if_iwm_pcie_trans.c	Wed Feb  8 06:53:23 2017	(r313415)
@@ -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);
 }
@@ -583,3 +589,55 @@ iwm_pcie_rx_stop(struct iwm_softc *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: head/sys/dev/iwm/if_iwm_pcie_trans.h
==============================================================================
--- head/sys/dev/iwm/if_iwm_pcie_trans.h	Wed Feb  8 06:50:59 2017	(r313414)
+++ head/sys/dev/iwm/if_iwm_pcie_trans.h	Wed Feb  8 06:53:23 2017	(r313415)
@@ -129,4 +129,7 @@ extern	int iwm_start_hw(struct iwm_softc
 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: head/sys/dev/iwm/if_iwm_util.c
==============================================================================
--- head/sys/dev/iwm/if_iwm_util.c	Wed Feb  8 06:50:59 2017	(r313414)
+++ head/sys/dev/iwm/if_iwm_util.c	Wed Feb  8 06:53:23 2017	(r313415)
@@ -305,17 +305,10 @@ iwm_send_cmd(struct iwm_softc *sc, struc
 	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: head/sys/dev/iwm/if_iwmvar.h
==============================================================================
--- head/sys/dev/iwm/if_iwmvar.h	Wed Feb  8 06:50:59 2017	(r313414)
+++ head/sys/dev/iwm/if_iwmvar.h	Wed Feb  8 06:53:23 2017	(r313415)
@@ -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 {
@@ -521,6 +524,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?201702080653.v186rNVx013225>