summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2010-06-29 19:14:10 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2010-06-29 19:14:10 +0000
commita414260538ba5ae94fcb51aa97991f7e7b115e49 (patch)
tree617c0e40fcfe3aef8780e79d908aa6c2e7c65fc9
parent445287faf73687367ac7927cc5c65871207ba6bf (diff)
More workarounds adapted from FreeBSD to make the 82577/82578 happy,
from Mike Belopuhov and me. looks good reyk@ ok claudio@
-rw-r--r--sys/dev/pci/if_em_hw.c421
-rw-r--r--sys/dev/pci/if_em_hw.h89
2 files changed, 489 insertions, 21 deletions
diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c
index 72abebe9b73..5a483ccc5e2 100644
--- a/sys/dev/pci/if_em_hw.c
+++ b/sys/dev/pci/if_em_hw.c
@@ -31,7 +31,7 @@
*******************************************************************************/
-/* $OpenBSD: if_em_hw.c,v 1.52 2010/06/28 20:24:39 jsg Exp $ */
+/* $OpenBSD: if_em_hw.c,v 1.53 2010/06/29 19:14:09 jsg Exp $ */
/*
* if_em_hw.c Shared functions for accessing and configuring the MAC
*/
@@ -164,8 +164,18 @@ static uint8_t em_calculate_mng_checksum(char *, uint32_t);
static int32_t em_configure_kmrn_for_10_100(struct em_hw *, uint16_t);
static int32_t em_configure_kmrn_for_1000(struct em_hw *);
static int32_t em_set_pciex_completion_timeout(struct em_hw *hw);
-int32_t em_hv_phy_workarounds_ich8lan(struct em_hw *);
-int32_t em_configure_k1_ich8lan(struct em_hw *, boolean_t);
+static int32_t em_set_mdio_slow_mode_hv(struct em_hw *);
+int32_t em_hv_phy_workarounds_ich8lan(struct em_hw *);
+int32_t em_link_stall_workaround_hv(struct em_hw *);
+int32_t em_configure_k1_ich8lan(struct em_hw *, boolean_t);
+int32_t em_access_phy_wakeup_reg_bm(struct em_hw *, uint32_t,
+ uint16_t *, boolean_t);
+int32_t em_access_phy_debug_regs_hv(struct em_hw *, uint32_t,
+ uint16_t *, boolean_t);
+int32_t em_access_phy_reg_hv(struct em_hw *, uint32_t, uint16_t *,
+ boolean_t);
+int32_t em_oem_bits_config_pchlan(struct em_hw *, boolean_t);
+
/* IGP cable length table */
static const uint16_t
@@ -1034,6 +1044,39 @@ em_init_hw(struct em_hw *hw)
reg_data &= ~0x80000000;
E1000_WRITE_REG(hw, STATUS, reg_data);
}
+
+ if (hw->mac_type == em_pchlan) {
+ /*
+ * The MAC-PHY interconnect may still be in SMBus mode
+ * after Sx->S0. Toggle the LANPHYPC Value bit to force
+ * the interconnect to PCIe mode, but only if there is no
+ * firmware present otherwise firmware will have done it.
+ */
+ if ((E1000_READ_REG(hw, FWSM) & E1000_FWSM_FW_VALID) == 0) {
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
+ ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ usec_delay(10);
+ ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ msec_delay(50);
+ }
+ /*
+ * Reset the PHY before any acccess to it. Doing so,
+ * ensures that the PHY is in a known good state before
+ * we read/write PHY registers. The generic reset is
+ * sufficient here, because we haven't determined
+ * the PHY type yet.
+ */
+ em_phy_reset(hw);
+
+ /* Set MDIO slow mode before any other MDIO access */
+ ret_val = em_set_mdio_slow_mode_hv(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
/* Initialize Identification LED */
ret_val = em_id_led_init(hw);
if (ret_val) {
@@ -1145,6 +1188,19 @@ em_init_hw(struct em_hw *hw)
hw->mac_type == em_pchlan)
msec_delay(15);
+ /*
+ * The 82578 Rx buffer will stall if wakeup is enabled in host and
+ * the ME. Reading the BM_WUC register will clear the host wakeup bit.
+ * Reset the phy after disabling host wakeup to reset the Rx buffer.
+ */
+ if (hw->phy_type == em_phy_82578) {
+ em_read_phy_reg(hw, PHY_REG(BM_WUC_PAGE, 1),
+ (uint16_t *)&reg_data);
+ ret_val = em_phy_reset(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
/* Call a subroutine to configure the link and setup flow control. */
ret_val = em_setup_link(hw);
@@ -1421,6 +1477,7 @@ em_setup_link(struct em_hw *hw)
if (hw->phy_type == em_phy_82577 ||
hw->phy_type == em_phy_82578) {
+ E1000_WRITE_REG(hw, FCRTV_PCH, 0x1000);
em_write_phy_reg(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27),
hw->fc_pause_time);
}
@@ -3366,6 +3423,12 @@ em_check_for_link(struct em_hw *hw)
hw->icp_xxxx_is_link_up = (phy_data & MII_SR_LINK_STATUS) != 0;
+ if (hw->phy_type == em_phy_82578) {
+ ret_val = em_link_stall_workaround_hv(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
if (phy_data & MII_SR_LINK_STATUS) {
hw->get_link_status = FALSE;
/*
@@ -3898,6 +3961,201 @@ em_swfw_sync_release(struct em_hw *hw, uint16_t mask)
em_put_hw_eeprom_semaphore(hw);
}
+
+int32_t
+em_access_phy_wakeup_reg_bm(struct em_hw *hw, uint32_t reg_addr,
+ uint16_t *phy_data, boolean_t read)
+{
+ int32_t ret_val;
+ uint16_t reg = BM_PHY_REG_NUM(reg_addr);
+ uint16_t phy_reg = 0;
+
+ /* Gig must be disabled for MDIO accesses to page 800 */
+ if ((hw->mac_type == em_pchlan) &&
+ (!(E1000_READ_REG(hw, PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
+ printf("Attempting to access page 800 while gig enabled.\n");
+
+ /* All operations in this function are phy address 1 */
+ hw->phy_addr = 1;
+
+ /* Set page 769 */
+ em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << PHY_PAGE_SHIFT));
+
+ ret_val = em_read_phy_reg_ex(hw, BM_WUC_ENABLE_REG, &phy_reg);
+ if (ret_val) {
+ printf("Could not read PHY page 769\n");
+ goto out;
+ }
+
+ /* First clear bit 4 to avoid a power state change */
+ phy_reg &= ~(BM_WUC_HOST_WU_BIT);
+ ret_val = em_write_phy_reg_ex(hw, BM_WUC_ENABLE_REG, phy_reg);
+ if (ret_val) {
+ printf("Could not clear PHY page 769 bit 4\n");
+ goto out;
+ }
+
+ /* Write bit 2 = 1, and clear bit 4 to 769_17 */
+ ret_val = em_write_phy_reg_ex(hw, BM_WUC_ENABLE_REG,
+ phy_reg | BM_WUC_ENABLE_BIT);
+ if (ret_val) {
+ printf("Could not write PHY page 769 bit 2\n");
+ goto out;
+ }
+
+ /* Select page 800 */
+ ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_PAGE << PHY_PAGE_SHIFT));
+
+ /* Write the page 800 offset value using opcode 0x11 */
+ ret_val = em_write_phy_reg_ex(hw, BM_WUC_ADDRESS_OPCODE, reg);
+ if (ret_val) {
+ printf("Could not write address opcode to page 800\n");
+ goto out;
+ }
+
+ if (read)
+ /* Read the page 800 value using opcode 0x12 */
+ ret_val = em_read_phy_reg_ex(hw, BM_WUC_DATA_OPCODE,
+ phy_data);
+ else
+ /* Write the page 800 value using opcode 0x12 */
+ ret_val = em_write_phy_reg_ex(hw, BM_WUC_DATA_OPCODE,
+ *phy_data);
+
+ if (ret_val) {
+ printf("Could not access data value from page 800\n");
+ goto out;
+ }
+
+ /*
+ * Restore 769_17.2 to its original value
+ * Set page 769
+ */
+ em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << PHY_PAGE_SHIFT));
+
+ /* Clear 769_17.2 */
+ ret_val = em_write_phy_reg_ex(hw, BM_WUC_ENABLE_REG, phy_reg);
+ if (ret_val) {
+ printf("Could not clear PHY page 769 bit 2\n");
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+int32_t
+em_access_phy_debug_regs_hv(struct em_hw *hw, uint32_t reg_addr,
+ uint16_t *phy_data, boolean_t read)
+{
+ int32_t ret_val;
+ uint32_t addr_reg = 0;
+ uint32_t data_reg = 0;
+
+ /* This takes care of the difference with desktop vs mobile phy */
+ addr_reg = (hw->phy_type == em_phy_82578) ?
+ I82578_PHY_ADDR_REG : I82577_PHY_ADDR_REG;
+ data_reg = addr_reg + 1;
+
+ /* All operations in this function are phy address 2 */
+ hw->phy_addr = 2;
+
+ /* masking with 0x3F to remove the page from offset */
+ ret_val = em_write_phy_reg_ex(hw, addr_reg, (uint16_t)reg_addr & 0x3F);
+ if (ret_val) {
+ printf("Could not write PHY the HV address register\n");
+ goto out;
+ }
+
+ /* Read or write the data value next */
+ if (read)
+ ret_val = em_read_phy_reg_ex(hw, data_reg, phy_data);
+ else
+ ret_val = em_write_phy_reg_ex(hw, data_reg, *phy_data);
+
+ if (ret_val) {
+ printf("Could not read data value from HV data register\n");
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/******************************************************************************
+ * Reads or writes the value from a PHY register, if the value is on a specific
+ * non zero page, sets the page first.
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ *****************************************************************************/
+int32_t
+em_access_phy_reg_hv(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data,
+ boolean_t read)
+{
+ uint32_t ret_val;
+ uint16_t swfw;
+ uint16_t page = BM_PHY_REG_PAGE(reg_addr);
+ uint16_t reg = BM_PHY_REG_NUM(reg_addr);
+
+ DEBUGFUNC("em_access_phy_reg_hv");
+
+ swfw = E1000_SWFW_PHY0_SM;
+
+ if (em_swfw_sync_acquire(hw, swfw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ if (page == BM_WUC_PAGE) {
+ ret_val = em_access_phy_wakeup_reg_bm(hw, reg_addr,
+ phy_data, read);
+ goto release;
+ }
+
+ if (page >= HV_INTC_FC_PAGE_START)
+ hw->phy_addr = 1;
+ else
+ hw->phy_addr = 2;
+
+ if (page == HV_INTC_FC_PAGE_START)
+ page = 0;
+
+ /*
+ * Workaround MDIO accesses being disabled after entering IEEE Power
+ * Down (whenever bit 11 of the PHY Control register is set)
+ */
+ if (!read &&
+ (hw->phy_type == em_phy_82578) &&
+ (hw->phy_revision >= 1) &&
+ (hw->phy_addr == 2) &&
+ ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
+ (*phy_data & (1 << 11))) {
+ uint16_t data2 = 0x7EFF;
+
+ ret_val = em_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
+ &data2, FALSE);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if (reg_addr > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (page << PHY_PAGE_SHIFT));
+ if (ret_val)
+ return ret_val;
+ }
+ if (read)
+ ret_val = em_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg,
+ phy_data);
+ else
+ ret_val = em_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg,
+ *phy_data);
+release:
+ em_swfw_sync_release(hw, swfw);
+ return ret_val;
+}
+
/******************************************************************************
* Reads the value from a PHY register, if the value is on a specific non zero
* page, sets the page first.
@@ -3911,6 +4169,9 @@ em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data)
uint16_t swfw;
DEBUGFUNC("em_read_phy_reg");
+ if (hw->mac_type == em_pchlan)
+ return (em_access_phy_reg_hv(hw, reg_addr, phy_data, TRUE));
+
if ((hw->mac_type == em_80003es2lan) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
@@ -4068,6 +4329,9 @@ em_write_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t phy_data)
uint16_t swfw;
DEBUGFUNC("em_write_phy_reg");
+ if (hw->mac_type == em_pchlan)
+ return (em_access_phy_reg_hv(hw, reg_addr, &phy_data, FALSE));
+
if ((hw->mac_type == em_80003es2lan) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
@@ -4354,6 +4618,63 @@ em_phy_hw_reset(struct em_hw *hw)
return ret_val;
}
+
+int32_t
+em_oem_bits_config_pchlan(struct em_hw *hw, boolean_t d0_state)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint32_t mac_reg;
+ uint16_t oem_reg;
+ uint16_t swfw = E1000_SWFW_PHY0_SM;
+
+ if (hw->mac_type != em_pchlan)
+ return ret_val;
+
+ ret_val = em_swfw_sync_acquire(hw, swfw);
+ if (ret_val)
+ return ret_val;
+
+ mac_reg = E1000_READ_REG(hw, EXTCNF_CTRL);
+ if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+ goto out;
+
+ mac_reg = E1000_READ_REG(hw, FEXTNVM);
+ if (!(mac_reg & FEXTNVM_SW_CONFIG_ICH8M))
+ goto out;
+
+ mac_reg = E1000_READ_REG(hw, PHY_CTRL);
+
+ ret_val = em_read_phy_reg(hw, HV_OEM_BITS, &oem_reg);
+ if (ret_val)
+ goto out;
+
+ oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
+
+ if (d0_state) {
+ if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
+ oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+ if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ } else {
+ if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
+ oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+ if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ }
+ /* Restart auto-neg to activate the bits */
+ if (!em_check_phy_reset_block(hw))
+ oem_reg |= HV_OEM_BITS_RESTART_AN;
+ ret_val = em_write_phy_reg(hw, HV_OEM_BITS, oem_reg);
+
+out:
+ em_swfw_sync_release(hw, swfw);
+
+ return ret_val;
+}
+
+
/******************************************************************************
* Resets the PHY
*
@@ -4398,8 +4719,20 @@ em_phy_reset(struct em_hw *hw)
break;
}
+ /* Allow time for h/w to get to a quiescent state after reset */
+ msec_delay(10);
+
if (hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2)
em_phy_init_script(hw);
+ else if (hw->mac_type == em_pchlan) {
+ ret_val = em_hv_phy_workarounds_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = em_oem_bits_config_pchlan(hw, TRUE);
+ if (ret_val)
+ return ret_val;
+ }
return E1000_SUCCESS;
}
@@ -6602,6 +6935,26 @@ em_clear_hw_cntrs(struct em_hw *hw)
temp = E1000_READ_REG(hw, IAC);
temp = E1000_READ_REG(hw, ICRXOC);
+ if (hw->phy_type == em_phy_82577 ||
+ hw->phy_type == em_phy_82578) {
+ uint16_t phy_data;
+
+ em_read_phy_reg(hw, HV_SCC_UPPER, &phy_data);
+ em_read_phy_reg(hw, HV_SCC_LOWER, &phy_data);
+ em_read_phy_reg(hw, HV_ECOL_UPPER, &phy_data);
+ em_read_phy_reg(hw, HV_ECOL_LOWER, &phy_data);
+ em_read_phy_reg(hw, HV_MCC_UPPER, &phy_data);
+ em_read_phy_reg(hw, HV_MCC_LOWER, &phy_data);
+ em_read_phy_reg(hw, HV_LATECOL_UPPER, &phy_data);
+ em_read_phy_reg(hw, HV_LATECOL_LOWER, &phy_data);
+ em_read_phy_reg(hw, HV_COLC_UPPER, &phy_data);
+ em_read_phy_reg(hw, HV_COLC_LOWER, &phy_data);
+ em_read_phy_reg(hw, HV_DC_UPPER, &phy_data);
+ em_read_phy_reg(hw, HV_DC_LOWER, &phy_data);
+ em_read_phy_reg(hw, HV_TNCRS_UPPER, &phy_data);
+ em_read_phy_reg(hw, HV_TNCRS_LOWER, &phy_data);
+ }
+
if (hw->mac_type == em_ich8lan ||
hw->mac_type == em_ich9lan ||
hw->mac_type == em_ich10lan ||
@@ -9122,7 +9475,8 @@ em_hv_phy_workarounds_ich8lan(struct em_hw *hw)
swfw = E1000_SWFW_PHY0_SM;
/* Set MDIO slow mode before any other MDIO access */
- if (hw->phy_type == em_phy_82577) {
+ if (hw->phy_type == em_phy_82577 ||
+ hw->phy_type == em_phy_82578) {
ret_val = em_set_mdio_slow_mode_hv(hw);
if (ret_val)
goto out;
@@ -9200,10 +9554,10 @@ em_hv_phy_workarounds_ich8lan(struct em_hw *hw)
* Workaround for OEM (GbE) not operating after reset -
* restart AN (twice)
*/
- ret_val = em_write_phy_reg(hw, PHY_REG(768, 25), 0x0400);
+ ret_val = em_write_phy_reg(hw, PHY_REG(0, 25), 0x0400);
if (ret_val)
goto out;
- ret_val = em_write_phy_reg(hw, PHY_REG(768, 25), 0x0400);
+ ret_val = em_write_phy_reg(hw, PHY_REG(0, 25), 0x0400);
if (ret_val)
goto out;
}
@@ -9233,6 +9587,61 @@ out:
return ret_val;
}
+
+/**
+ * em_link_stall_workaround_hv - Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * This function works around a Si bug where the link partner can get
+ * a link up indication before the PHY does. If small packets are sent
+ * by the link partner they can be placed in the packet buffer without
+ * being properly accounted for by the PHY and will stall preventing
+ * further packets from being received. The workaround is to clear the
+ * packet buffer after the PHY detects link up.
+ **/
+int32_t
+em_link_stall_workaround_hv(struct em_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t phy_data;
+
+ if (hw->phy_type != em_phy_82578)
+ goto out;
+
+ /* Do not apply workaround if in PHY loopback bit 14 set */
+ em_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (phy_data & E1000_PHY_CTRL_LOOPBACK)
+ goto out;
+
+ /* check if link is up and at 1Gbps */
+ ret_val = em_read_phy_reg(hw, BM_CS_STATUS, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK;
+
+ if (phy_data != (BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_1000))
+ goto out;
+
+ msec_delay(200);
+
+ /* flush the packets in the fifo buffer */
+ ret_val = em_write_phy_reg(hw, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC | HV_MUX_DATA_CTRL_FORCE_SPEED);
+ if (ret_val)
+ goto out;
+
+ ret_val = em_write_phy_reg(hw, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC);
+
+out:
+ return ret_val;
+}
+
/**
* e1000_configure_k1_ich8lan - Configure K1 power state
* @hw: pointer to the HW structure
diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h
index 28dc1146276..df22cb378c8 100644
--- a/sys/dev/pci/if_em_hw.h
+++ b/sys/dev/pci/if_em_hw.h
@@ -31,7 +31,7 @@
*******************************************************************************/
-/* $OpenBSD: if_em_hw.h,v 1.42 2010/06/28 20:24:39 jsg Exp $ */
+/* $OpenBSD: if_em_hw.h,v 1.43 2010/06/29 19:14:09 jsg Exp $ */
/* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */
/* if_em_hw.h
@@ -1107,6 +1107,7 @@ struct em_ffvt_entry {
#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
+#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */
#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset Register */
#define E1000_HOST_IF 0x08800 /* Host Interface */
#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
@@ -1307,6 +1308,7 @@ struct em_ffvt_entry {
#define E1000_82542_WUPL E1000_WUPL
#define E1000_82542_WUPM E1000_WUPM
#define E1000_82542_FFLT E1000_FFLT
+#define E1000_82542_FCRTV_PCH E1000_FCRTV_PCH
#define E1000_82542_TDFH 0x08010
#define E1000_82542_TDFT 0x08018
#define E1000_82542_FFMT E1000_FFMT
@@ -1546,7 +1548,8 @@ struct em_hw {
#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */
#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
-#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
+#define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */
+#define E1000_CTRL_LANPHYPC_VALUE 0x00020000 /* SW value of LANPHYPC */
#define E1000_CTRL_EXT_PHYPDEN 0x00100000
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
@@ -1749,6 +1752,7 @@ struct em_hw {
#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
#define E1000_PHY_CTRL_B2B_EN 0x00000080
+#define E1000_PHY_CTRL_LOOPBACK 0x00004000
/* LED Control */
#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
@@ -2787,6 +2791,13 @@ struct em_host_command_info {
#define I82577_PHY_CFG_ENABLE_CRS_ON_TX (1 << 15)
#define I82577_PHY_CFG_ENABLE_DOWNSHIFT ((1 << 10) + (1 << 11))
+/* I82578 Specific Registers */
+#define I82578_PHY_ADDR_REG 29
+
+/* I82578 Downshift settings (Extended PHY Specific Control Register) */
+#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020
+#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C
+
/* PHY Control Register */
#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
@@ -3011,10 +3022,6 @@ struct em_host_command_info {
#define M88E1000_EPSCR_TX_TIME_CTRL 0x0002 /* Add Delay */
#define M88E1000_EPSCR_RX_TIME_CTRL 0x0080 /* Add Delay */
-/* I82578 specific */
-#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020
-#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C
-
/* IGP01E1000 Specific Port Config Register - R/W */
#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010
#define IGP01E1000_PSCFR_PRE_EN 0x0020
@@ -3481,15 +3488,6 @@ union ich8_hws_flash_regacc {
#define E1000_82542_IMC1 E1000_IMC1
#define E1000_82542_IMC2 E1000_IMC2
-/* OEM Bits Phy Register */
-#define HV_OEM_BITS PHY_REG(768, 25)
-#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */
-#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */
-#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
-
-#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
-#define HV_KMRN_MDIO_SLOW 0x0400
-
#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */
@@ -3514,5 +3512,66 @@ union ich8_hws_flash_regacc {
#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16
+/* Hanksville definitions */
+#define HV_INTC_FC_PAGE_START 768
+
+#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */
+#define HV_SCC_LOWER PHY_REG(778, 17)
+#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */
+#define HV_ECOL_LOWER PHY_REG(778, 19)
+#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */
+#define HV_MCC_LOWER PHY_REG(778, 21)
+#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */
+#define HV_LATECOL_LOWER PHY_REG(778, 24)
+#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */
+#define HV_COLC_LOWER PHY_REG(778, 26)
+#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */
+#define HV_DC_LOWER PHY_REG(778, 28)
+#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */
+#define HV_TNCRS_LOWER PHY_REG(778, 30)
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */
+#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */
+#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
+
+#define HV_MUX_DATA_CTRL PHY_REG(776, 16)
+#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400
+#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004
+
+#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
+#define HV_KMRN_MDIO_SLOW 0x0400
+
+/* BM/HV Specific Registers */
+#define BM_PORT_CTRL_PAGE 769
+#define BM_PCIE_PAGE 770
+#define BM_WUC_PAGE 800
+#define BM_WUC_ADDRESS_OPCODE 0x11
+#define BM_WUC_DATA_OPCODE 0x12
+#define BM_WUC_ENABLE_PAGE BM_PORT_CTRL_PAGE
+#define BM_WUC_ENABLE_REG 17
+#define BM_WUC_ENABLE_BIT (1 << 2)
+#define BM_WUC_HOST_WU_BIT (1 << 4)
+
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS 17
+#define BM_CS_STATUS_ENERGY_DETECT 0x0010 /* Energy Detect Status */
+#define BM_CS_STATUS_LINK_UP 0x0400
+#define BM_CS_STATUS_RESOLVED 0x0800
+#define BM_CS_STATUS_SPEED_MASK 0xC000
+#define BM_CS_STATUS_SPEED_1000 0x8000
+
+#define PHY_UPPER_SHIFT 21
+#define BM_PHY_REG(page, reg) \
+ (((reg) & MAX_PHY_REG_ADDRESS) |\
+ (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+ (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+#define BM_PHY_REG_PAGE(offset) \
+ ((uint16_t)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define BM_PHY_REG_NUM(offset) \
+ ((uint16_t)(((offset) & MAX_PHY_REG_ADDRESS) |\
+ (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+ ~MAX_PHY_REG_ADDRESS)))
#endif /* _EM_HW_H_ */