Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 4 Sep 2015 17:21:56 +0000 (UTC)
From:      Sean Bruno <sbruno@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r287469 - head/sys/dev/e1000
Message-ID:  <201509041721.t84HLu6W063410@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sbruno
Date: Fri Sep  4 17:21:55 2015
New Revision: 287469
URL: https://svnweb.freebsd.org/changeset/base/287469

Log:
  em(4): Add Skylake/I219 support.
  - driver rev 7.5.2
  - use new functions em_flush* for i219 devices
  
  Differential Revision:	https://reviews.freebsd.org/D3163
  Submitted by:	erj jfv
  Reviewed by:	jfv
  MFC after:	1 month
  Relnotes:	Yes
  Sponsored by:	Intel Corporation

Modified:
  head/sys/dev/e1000/if_em.c
  head/sys/dev/e1000/if_em.h

Modified: head/sys/dev/e1000/if_em.c
==============================================================================
--- head/sys/dev/e1000/if_em.c	Fri Sep  4 16:59:01 2015	(r287468)
+++ head/sys/dev/e1000/if_em.c	Fri Sep  4 17:21:55 2015	(r287469)
@@ -103,7 +103,7 @@ int	em_display_debug_stats = 0;
 /*********************************************************************
  *  Driver version:
  *********************************************************************/
-char em_driver_version[] = "7.4.2";
+char em_driver_version[] = "7.5.2";
 
 /*********************************************************************
  *  PCI Device ID Table
@@ -191,6 +191,11 @@ static em_vendor_info_t em_vendor_info_a
 	{ 0x8086, E1000_DEV_ID_PCH_I218_V2,	PCI_ANY_ID, PCI_ANY_ID, 0},
 	{ 0x8086, E1000_DEV_ID_PCH_I218_LM3,	PCI_ANY_ID, PCI_ANY_ID, 0},
 	{ 0x8086, E1000_DEV_ID_PCH_I218_V3,	PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_PCH_SPT_I219_LM, PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_PCH_SPT_I219_V,  PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_PCH_SPT_I219_LM2,
+                                                PCI_ANY_ID, PCI_ANY_ID, 0},
+	{ 0x8086, E1000_DEV_ID_PCH_SPT_I219_V2, PCI_ANY_ID, PCI_ANY_ID, 0},
 	/* required last entry */
 	{ 0, 0, 0, 0, 0}
 };
@@ -238,6 +243,7 @@ static void	em_free_pci_resources(struct
 static void	em_local_timer(void *);
 static void	em_reset(struct adapter *);
 static int	em_setup_interface(device_t, struct adapter *);
+static void	em_flush_desc_rings(struct adapter *);
 
 static void	em_setup_transmit_structures(struct adapter *);
 static void	em_initialize_transmit_unit(struct adapter *);
@@ -584,6 +590,20 @@ em_attach(device_t dev)
 	}
 
 	/*
+	** In the new SPT device flash is not  a
+	** separate BAR, rather it is also in BAR0,
+	** so use the same tag and handle for the
+	** FLASH read/write macros in the shared
+	** code.
+	*/
+	if (hw->mac.type == e1000_pch_spt) {
+		adapter->osdep.flash_bus_space_tag =
+		    adapter->osdep.mem_bus_space_tag;
+		adapter->osdep.flash_bus_space_handle =
+		    adapter->osdep.mem_bus_space_handle;
+	}
+
+	/*
 	 * Setup MSI/X or MSI if PCI Express
 	 */
 	adapter->msix = em_setup_msix(adapter);
@@ -1168,6 +1188,7 @@ em_ioctl(if_t ifp, u_long command, caddr
 		case e1000_ich10lan:
 		case e1000_pch2lan:
 		case e1000_pch_lpt:
+		case e1000_pch_spt:
 		case e1000_82574:
 		case e1000_82583:
 		case e1000_80003es2lan:	/* 9K Jumbo Frame size */
@@ -1369,8 +1390,15 @@ em_init_locked(struct adapter *adapter)
 	if_clearhwassist(ifp);
 	if (if_getcapenable(ifp) & IFCAP_TXCSUM)
 		if_sethwassistbits(ifp, CSUM_TCP | CSUM_UDP, 0);
-	if (if_getcapenable(ifp) & IFCAP_TSO4)
-		if_sethwassistbits(ifp, CSUM_TSO, 0);
+	/* 
+	** There have proven to be problems with TSO when not
+	** at full gigabit speed, so disable the assist automatically
+	** when at lower speeds.  -jfv
+	*/
+	if (if_getcapenable(ifp) & IFCAP_TSO4) {
+		if (adapter->link_speed == SPEED_1000)
+			if_sethwassistbits(ifp, CSUM_TSO, 0);
+	}
 
 	/* Configure for OS presence */
 	em_init_manageability(adapter);
@@ -2350,6 +2378,8 @@ em_update_link_status(struct adapter *ad
 	switch (hw->phy.media_type) {
 	case e1000_media_type_copper:
 		if (hw->mac.get_link_status) {
+			if (hw->mac.type == e1000_pch_spt)
+				msec_delay(50);
 			/* Do the work to read phy */
 			e1000_check_for_link(hw);
 			link_check = !hw->mac.get_link_status;
@@ -2441,6 +2471,10 @@ em_stop(void *arg)
 		EM_TX_UNLOCK(txr);
 	}
 
+	/* I219 needs some special flushing to avoid hangs */
+	if (adapter->hw.mac.type == e1000_pch_spt)
+		em_flush_desc_rings(adapter);
+
 	e1000_reset_hw(&adapter->hw);
 	E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0);
 
@@ -2860,6 +2894,116 @@ msi:
 }
 
 
+/*
+** The 3 following flush routines are used as a workaround in the
+** I219 client parts and only for them.
+**
+** em_flush_tx_ring - remove all descriptors from the tx_ring
+**
+** We want to clear all pending descriptors from the TX ring.
+** zeroing happens when the HW reads the regs. We  assign the ring itself as
+** the data of the next descriptor. We don't care about the data we are about
+** to reset the HW.
+*/
+static void
+em_flush_tx_ring(struct adapter *adapter)
+{
+	struct e1000_hw		*hw = &adapter->hw;
+	struct tx_ring		*txr = adapter->tx_rings;
+	struct e1000_tx_desc	*txd;
+	u32			tctl, txd_lower = E1000_TXD_CMD_IFCS;
+	u16			size = 512;
+
+	tctl = E1000_READ_REG(hw, E1000_TCTL);
+	E1000_WRITE_REG(hw, E1000_TCTL, tctl | E1000_TCTL_EN);
+
+	txd = &txr->tx_base[txr->next_avail_desc++];
+	if (txr->next_avail_desc == adapter->num_tx_desc)
+		txr->next_avail_desc = 0;
+
+	/* Just use the ring as a dummy buffer addr */
+	txd->buffer_addr = txr->txdma.dma_paddr;
+	txd->lower.data = htole32(txd_lower | size);
+	txd->upper.data = 0;
+
+	/* flush descriptors to memory before notifying the HW */
+	wmb();
+
+	E1000_WRITE_REG(hw, E1000_TDT(0), txr->next_avail_desc);
+	mb();
+	usec_delay(250);
+}
+
+/*
+** em_flush_rx_ring - remove all descriptors from the rx_ring
+**
+** Mark all descriptors in the RX ring as consumed and disable the rx ring
+*/
+static void
+em_flush_rx_ring(struct adapter *adapter)
+{
+	struct e1000_hw	*hw = &adapter->hw;
+	u32		rctl, rxdctl;
+
+	rctl = E1000_READ_REG(hw, E1000_RCTL);
+	E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(150);
+
+	rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
+	/* zero the lower 14 bits (prefetch and host thresholds) */
+	rxdctl &= 0xffffc000;
+	/*
+	 * update thresholds: prefetch threshold to 31, host threshold to 1
+	 * and make sure the granularity is "descriptors" and not "cache lines"
+	 */
+	rxdctl |= (0x1F | (1 << 8) | E1000_RXDCTL_THRESH_UNIT_DESC);
+	E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl);
+
+	/* momentarily enable the RX ring for the changes to take effect */
+	E1000_WRITE_REG(hw, E1000_RCTL, rctl | E1000_RCTL_EN);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(150);
+	E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
+}
+
+/*
+** em_flush_desc_rings - remove all descriptors from the descriptor rings
+**
+** In i219, the descriptor rings must be emptied before resetting the HW
+** or before changing the device state to D3 during runtime (runtime PM).
+**
+** Failure to do this will cause the HW to enter a unit hang state which can
+** only be released by PCI reset on the device
+**
+*/
+static void
+em_flush_desc_rings(struct adapter *adapter)
+{
+	struct e1000_hw	*hw = &adapter->hw;
+	device_t	dev = adapter->dev;
+	u16		hang_state;
+	u32		fext_nvm11, tdlen;
+ 
+	/* First, disable MULR fix in FEXTNVM11 */
+	fext_nvm11 = E1000_READ_REG(hw, E1000_FEXTNVM11);
+	fext_nvm11 |= E1000_FEXTNVM11_DISABLE_MULR_FIX;
+	E1000_WRITE_REG(hw, E1000_FEXTNVM11, fext_nvm11);
+        
+	/* do nothing if we're not in faulty state, or if the queue is empty */
+	tdlen = E1000_READ_REG(hw, E1000_TDLEN(0));
+	hang_state = pci_read_config(dev, PCICFG_DESC_RING_STATUS, 2);
+	if (!(hang_state & FLUSH_DESC_REQUIRED) || !tdlen)
+		return;
+	em_flush_tx_ring(adapter);
+
+	/* recheck, maybe the fault is caused by the rx ring */
+	hang_state = pci_read_config(dev, PCICFG_DESC_RING_STATUS, 2);
+	if (hang_state & FLUSH_DESC_REQUIRED)
+		em_flush_rx_ring(adapter);
+}
+
+
 /*********************************************************************
  *
  *  Initialize the hardware to a configuration
@@ -2921,6 +3065,7 @@ em_reset(struct adapter *adapter)
 	case e1000_pchlan:
 	case e1000_pch2lan:
 	case e1000_pch_lpt:
+	case e1000_pch_spt:
 		pba = E1000_PBA_26K;
 		break;
 	default:
@@ -2979,6 +3124,7 @@ em_reset(struct adapter *adapter)
 		break;
 	case e1000_pch2lan:
 	case e1000_pch_lpt:
+	case e1000_pch_spt:
 		hw->fc.high_water = 0x5C20;
 		hw->fc.low_water = 0x5048;
 		hw->fc.pause_time = 0x0650;
@@ -3003,6 +3149,10 @@ em_reset(struct adapter *adapter)
 		break;
 	}
 
+	/* I219 needs some special flushing to avoid hangs */
+	if (hw->mac.type == e1000_pch_spt)
+		em_flush_desc_rings(adapter);
+
 	/* Issue a global reset */
 	e1000_reset_hw(hw);
 	E1000_WRITE_REG(hw, E1000_WUC, 0);
@@ -3599,6 +3749,15 @@ em_initialize_transmit_unit(struct adapt
 	/* This write will effectively turn on the transmit unit. */
 	E1000_WRITE_REG(&adapter->hw, E1000_TCTL, tctl);
 
+	if (hw->mac.type == e1000_pch_spt) {
+		u32 reg;
+		reg = E1000_READ_REG(hw, E1000_IOSFPC);
+		reg |= E1000_RCTL_RDMTS_HEX;
+		E1000_WRITE_REG(hw, E1000_IOSFPC, reg);
+		reg = E1000_READ_REG(hw, E1000_TARC(0));
+		reg |= E1000_TARC0_CB_MULTIQ_3_REQ;
+		E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+	}
 }
 
 

Modified: head/sys/dev/e1000/if_em.h
==============================================================================
--- head/sys/dev/e1000/if_em.h	Fri Sep  4 16:59:01 2015	(r287468)
+++ head/sys/dev/e1000/if_em.h	Fri Sep  4 17:21:55 2015	(r287469)
@@ -218,6 +218,9 @@
 #define EM_TX_HUNG			0x80000000
 #define EM_TX_MAXTRIES			10
 
+#define PCICFG_DESC_RING_STATUS		0xe4
+#define FLUSH_DESC_REQUIRED		0x100
+
 /*
  * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
  * multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary. This will



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509041721.t84HLu6W063410>