Add Intel Skylake/I219 Support
- New em(4) device in currently shipping products Differential Revision: https://reviews.freebsd.org/D3163 Submitted by: erj@freebsd.org Reviewed by: jfv@freebsd.org MFC after: 2 weeks Sponsored by: Intel Corporation
This commit is contained in:
parent
042e9bdc41
commit
25fd5dd9a0
@ -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_array[] =
|
||||
{ 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 adapter *);
|
||||
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 *);
|
||||
@ -583,6 +589,20 @@ em_attach(device_t dev)
|
||||
goto err_pci;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
*/
|
||||
@ -1168,6 +1188,7 @@ em_ioctl(if_t ifp, u_long command, caddr_t data)
|
||||
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 *adapter)
|
||||
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 adapter *adapter)
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user