summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/e1000g/e1000g_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/io/e1000g/e1000g_main.c')
-rw-r--r--usr/src/uts/common/io/e1000g/e1000g_main.c85
1 files changed, 75 insertions, 10 deletions
diff --git a/usr/src/uts/common/io/e1000g/e1000g_main.c b/usr/src/uts/common/io/e1000g/e1000g_main.c
index 514b4d8e7d..f08cde4525 100644
--- a/usr/src/uts/common/io/e1000g/e1000g_main.c
+++ b/usr/src/uts/common/io/e1000g/e1000g_main.c
@@ -25,7 +25,7 @@
/*
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright 2016 Joyent, Inc.
*/
/*
@@ -710,6 +710,17 @@ e1000g_regs_map(struct e1000g *Adapter)
goto regs_map_fail;
}
break;
+ case e1000_pch_spt:
+ /*
+ * On the SPT, the device flash is actually in BAR0, not a
+ * separate BAR. Therefore we end up setting the
+ * ich_flash_handle to be the same as the register handle.
+ * We mark the same to reduce the confusion in the other
+ * functions and macros. Though this does make the set up and
+ * tear-down path slightly more complicated.
+ */
+ osdep->ich_flash_handle = osdep->reg_handle;
+ hw->flash_address = hw->hw_addr;
default:
break;
}
@@ -769,7 +780,7 @@ e1000g_regs_map(struct e1000g *Adapter)
regs_map_fail:
if (osdep->reg_handle != NULL)
ddi_regs_map_free(&osdep->reg_handle);
- if (osdep->ich_flash_handle != NULL)
+ if (osdep->ich_flash_handle != NULL && hw->mac.type != e1000_pch_spt)
ddi_regs_map_free(&osdep->ich_flash_handle);
return (DDI_FAILURE);
}
@@ -897,6 +908,7 @@ e1000g_setup_max_mtu(struct e1000g *Adapter)
/* pch2 can do jumbo frames up to 9K */
case e1000_pch2lan:
case e1000_pch_lpt:
+ case e1000_pch_spt:
Adapter->max_mtu = MAXIMUM_MTU_9K;
break;
/* types with a special limit */
@@ -1129,7 +1141,8 @@ e1000g_unattach(dev_info_t *devinfo, struct e1000g *Adapter)
if (Adapter->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
if (Adapter->osdep.reg_handle != NULL)
ddi_regs_map_free(&Adapter->osdep.reg_handle);
- if (Adapter->osdep.ich_flash_handle != NULL)
+ if (Adapter->osdep.ich_flash_handle != NULL &&
+ Adapter->shared.mac.type != e1000_pch_spt)
ddi_regs_map_free(&Adapter->osdep.ich_flash_handle);
if (Adapter->osdep.io_reg_handle != NULL)
ddi_regs_map_free(&Adapter->osdep.io_reg_handle);
@@ -1461,6 +1474,8 @@ e1000g_init(struct e1000g *Adapter)
pba = E1000_PBA_26K;
} else if (hw->mac.type == e1000_pch_lpt) {
pba = E1000_PBA_26K;
+ } else if (hw->mac.type == e1000_pch_spt) {
+ pba = E1000_PBA_26K;
} else {
/*
* Total FIFO is 40K
@@ -1686,6 +1701,12 @@ e1000g_link_up(struct e1000g *Adapter)
switch (hw->phy.media_type) {
case e1000_media_type_copper:
if (hw->mac.get_link_status) {
+ /*
+ * SPT devices need a bit of extra time before we ask
+ * them.
+ */
+ if (hw->mac.type == e1000_pch_spt)
+ msec_delay(50);
(void) e1000_check_for_link(hw);
if ((E1000_READ_REG(hw, E1000_STATUS) &
E1000_STATUS_LU)) {
@@ -1942,6 +1963,41 @@ start_fail:
return (DDI_FAILURE);
}
+/*
+ * The I219 has the curious property that if the descriptor rings are not
+ * emptied before resetting the hardware or before changing the device state
+ * based on runtime power management, it'll cause the card to hang. This can
+ * then only be fixed by a PCI reset. As such, for the I219 and it alone, we
+ * have to flush the rings if we're in this state.
+ */
+static void
+e1000g_flush_desc_rings(struct e1000g *Adapter)
+{
+ struct e1000_hw *hw = &Adapter->shared;
+ 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_config_get16(Adapter->osdep.cfg_handle,
+ PCICFG_DESC_RING_STATUS);
+ if (!(hang_state & FLUSH_DESC_REQUIRED) || !tdlen)
+ return;
+ e1000g_flush_tx_ring(Adapter);
+
+ /* recheck, maybe the fault is caused by the rx ring */
+ hang_state = pci_config_get16(Adapter->osdep.cfg_handle,
+ PCICFG_DESC_RING_STATUS);
+ if (hang_state & FLUSH_DESC_REQUIRED)
+ e1000g_flush_rx_ring(Adapter);
+
+}
+
static void
e1000g_m_stop(void *arg)
{
@@ -2005,6 +2061,14 @@ e1000g_stop(struct e1000g *Adapter, boolean_t global)
/* Clean the pending rx jumbo packet fragment */
e1000g_rx_clean(Adapter);
+ /*
+ * The I219, eg. the pch_spt, has bugs such that we must ensure that
+ * rings are flushed before we do anything else. This must be done
+ * before we release DMA resources.
+ */
+ if (Adapter->shared.mac.type == e1000_pch_spt)
+ e1000g_flush_desc_rings(Adapter);
+
if (global) {
e1000g_release_dma_resources(Adapter);
@@ -2453,16 +2517,17 @@ e1000g_init_unicst(struct e1000g *Adapter)
/*
* The common code does not correctly calculate the number of
- * rar's that could be reserved by firmware for the pch_lpt
- * macs. The interface has one primary rar, and 11 additional
- * ones. Those 11 additional ones are not always available.
- * According to the datasheet, we need to check a few of the
- * bits set in the FWSM register. If the value is zero,
- * everything is available. If the value is 1, none of the
+ * rar's that could be reserved by firmware for the pch_lpt and
+ * pch_spt macs. The interface has one primary rar, and 11
+ * additional ones. Those 11 additional ones are not always
+ * available. According to the datasheet, we need to check a
+ * few of the bits set in the FWSM register. If the value is
+ * zero, everything is available. If the value is 1, none of the
* additional registers are available. If the value is 2-7, only
* that number are available.
*/
- if (hw->mac.type == e1000_pch_lpt) {
+ if (hw->mac.type == e1000_pch_lpt ||
+ hw->mac.type == e1000_pch_spt) {
uint32_t locked, rar;
locked = E1000_READ_REG(hw, E1000_FWSM) &