summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/if_em.c12
-rw-r--r--sys/dev/pci/if_em_hw.c214
-rw-r--r--sys/dev/pci/if_em_hw.h32
3 files changed, 249 insertions, 9 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c
index fc75b239b21..2c13e27faf0 100644
--- a/sys/dev/pci/if_em.c
+++ b/sys/dev/pci/if_em.c
@@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
-/* $OpenBSD: if_em.c,v 1.238 2010/06/21 21:11:52 jsg Exp $ */
+/* $OpenBSD: if_em.c,v 1.239 2010/06/27 20:13:04 jsg Exp $ */
/* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */
#include <dev/pci/if_em.h>
@@ -1533,9 +1533,6 @@ em_identify_hardware(struct em_softc *sc)
sc->hw.vendor_id = PCI_VENDOR(pa->pa_id);
sc->hw.device_id = PCI_PRODUCT(pa->pa_id);
- reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG);
- sc->hw.revision_id = PCI_REVISION(reg);
-
reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
sc->hw.subsystem_vendor_id = PCI_VENDOR(reg);
sc->hw.subsystem_id = PCI_PRODUCT(reg);
@@ -1544,6 +1541,13 @@ em_identify_hardware(struct em_softc *sc)
if (em_set_mac_type(&sc->hw))
printf("%s: Unknown MAC Type\n", sc->sc_dv.dv_xname);
+ if (sc->hw.mac_type == em_pchlan)
+ sc->hw.revision_id = PCI_PRODUCT(pa->pa_id) & 0x0f;
+ else {
+ reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG);
+ sc->hw.revision_id = PCI_REVISION(reg);
+ }
+
if (sc->hw.mac_type == em_82541 ||
sc->hw.mac_type == em_82541_rev_2 ||
sc->hw.mac_type == em_82547 ||
diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c
index 164e9b38a6e..68113cfbf69 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.50 2010/06/26 18:32:38 jsg Exp $ */
+/* $OpenBSD: if_em_hw.c,v 1.51 2010/06/27 20:13:04 jsg Exp $ */
/*
* if_em_hw.c Shared functions for accessing and configuring the MAC
*/
@@ -164,6 +164,9 @@ 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 *);
+void em_initialize_hw_bits_ich8lan(struct em_hw *);
+int32_t em_configure_k1_ich8lan(struct em_hw *, boolean_t);
/* IGP cable length table */
static const uint16_t
@@ -774,6 +777,11 @@ em_reset_hw(struct em_hw *hw)
E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
break;
}
+
+ if (hw->mac_type == em_pchlan) {
+ em_hv_phy_workarounds_ich8lan(hw);
+ }
+
/*
* After MAC reset, force reload of EEPROM to restore power-on
* settings to device. Later controllers reload the EEPROM
@@ -958,6 +966,9 @@ em_initialize_hardware_bits(struct em_hw *hw)
reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
reg_ctrl_ext |= 0x00400000; /* Set bit 22 */
+ /* Enable PHY low-power state when MAC is at D3 w/o WoL */
+ if (hw->mac_type >= em_pchlan)
+ reg_ctrl_ext |= E1000_CTRL_EXT_PHYPDEN;
E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
reg_tarc0 |= 0x0d800000; /* Set TARC0 bits 23,
@@ -1403,6 +1414,12 @@ em_setup_link(struct em_hw *hw)
E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
}
E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+ if (hw->phy_type == em_phy_82577) {
+ em_write_phy_reg(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27),
+ hw->fc_pause_time);
+ }
+
/*
* Set the flow control receive threshold registers. Normally, these
* registers will be set to a default threshold that may be adjusted
@@ -2115,11 +2132,20 @@ em_copper_link_82577_setup(struct em_hw *hw)
ret_val = em_write_phy_reg(hw, I82577_PHY_CFG_REG, phy_data);
if (ret_val)
return ret_val;
-
+
/* Wait 15ms for MAC to configure PHY from eeprom settings */
msec_delay(15);
led_ctl = hw->ledctl_mode1;
+
+ /* disable lplu d0 during driver init */
+ ret_val = em_set_lplu_state_pchlan(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D0\n");
+ return ret_val;
+ }
+
E1000_WRITE_REG(hw, LEDCTL, led_ctl);
+
return E1000_SUCCESS;
}
@@ -7489,7 +7515,7 @@ em_set_d0_lplu_state(struct em_hw *hw, boolean_t active)
* auto-neg as hw would do. D3 and D0 LPLU will call the same function
* since it configures the same bit.
**/
-STATIC int32_t
+int32_t
em_set_lplu_state_pchlan(struct em_hw *hw, boolean_t active)
{
int32_t ret_val = E1000_SUCCESS;
@@ -8915,7 +8941,8 @@ em_init_lcd_from_nvm(struct em_hw *hw)
/* Check if SW needs configure the PHY */
if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
- (hw->device_id == E1000_DEV_ID_ICH8_IGP_M))
+ (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
+ (hw->mac_type == em_pchlan))
sw_cfg_mask = FEXTNVM_SW_CONFIG_ICH8M;
else
sw_cfg_mask = FEXTNVM_SW_CONFIG;
@@ -9027,3 +9054,182 @@ out:
E1000_WRITE_REG(hw, GCR, gcr);
return ret_val;
}
+
+/**
+ * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
+ * @hw: pointer to the HW structure
+ **/
+static int32_t
+em_set_mdio_slow_mode_hv(struct em_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t data;
+
+ ret_val = em_read_phy_reg(hw, HV_KMRN_MODE_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= HV_KMRN_MDIO_SLOW;
+
+ ret_val = em_write_phy_reg(hw, HV_KMRN_MODE_CTRL, data);
+
+ return ret_val;
+}
+
+/**
+ * em_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ **/
+int32_t
+em_hv_phy_workarounds_ich8lan(struct em_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint16_t phy_data;
+ uint16_t swfw;
+
+ if (hw->mac_type != em_pchlan)
+ goto out;
+
+ swfw = E1000_SWFW_PHY0_SM;
+
+ /* Set MDIO slow mode before any other MDIO access */
+ if (hw->phy_type == em_phy_82577) {
+ ret_val = em_set_mdio_slow_mode_hv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Hanksville M Phy init for IEEE. */
+ if ((hw->revision_id == 2) &&
+ (hw->phy_type == em_phy_82577) &&
+ ((hw->phy_revision == 2) || (hw->phy_revision == 3))) {
+ em_write_phy_reg(hw, 0x10, 0x8823);
+ em_write_phy_reg(hw, 0x11, 0x0018);
+ em_write_phy_reg(hw, 0x10, 0x8824);
+ em_write_phy_reg(hw, 0x11, 0x0016);
+ em_write_phy_reg(hw, 0x10, 0x8825);
+ em_write_phy_reg(hw, 0x11, 0x001A);
+ em_write_phy_reg(hw, 0x10, 0x888C);
+ em_write_phy_reg(hw, 0x11, 0x0007);
+ em_write_phy_reg(hw, 0x10, 0x888D);
+ em_write_phy_reg(hw, 0x11, 0x0007);
+ em_write_phy_reg(hw, 0x10, 0x888E);
+ em_write_phy_reg(hw, 0x11, 0x0007);
+ em_write_phy_reg(hw, 0x10, 0x8827);
+ em_write_phy_reg(hw, 0x11, 0x0001);
+ em_write_phy_reg(hw, 0x10, 0x8835);
+ em_write_phy_reg(hw, 0x11, 0x0001);
+ em_write_phy_reg(hw, 0x10, 0x8834);
+ em_write_phy_reg(hw, 0x11, 0x0001);
+ em_write_phy_reg(hw, 0x10, 0x8833);
+ em_write_phy_reg(hw, 0x11, 0x0002);
+ }
+
+ if (((hw->phy_type == em_phy_82577) &&
+ ((hw->phy_revision == 1) || (hw->phy_revision == 2)))) {
+ /* Disable generation of early preamble */
+ ret_val = em_write_phy_reg(hw, PHY_REG(769, 25), 0x4431);
+ if (ret_val)
+ goto out;
+
+ /* Preamble tuning for SSC */
+ ret_val = em_write_phy_reg(hw, PHY_REG(770, 16), 0xA204);
+ if (ret_val)
+ goto out;
+ }
+
+ if ((hw->revision_id == 2) &&
+ (hw->phy_type == em_phy_82577) &&
+ ((hw->phy_revision == 2) || (hw->phy_revision == 3))) {
+ /*
+ * Workaround for OEM (GbE) not operating after reset -
+ * restart AN (twice)
+ */
+ ret_val = em_write_phy_reg(hw, PHY_REG(768, 25), 0x0400);
+ if (ret_val)
+ goto out;
+ ret_val = em_write_phy_reg(hw, PHY_REG(768, 25), 0x0400);
+ if (ret_val)
+ goto out;
+ }
+
+ /* Select page 0 */
+ ret_val = em_swfw_sync_acquire(hw, swfw);
+ if (ret_val)
+ goto out;
+
+ hw->phy_addr = 1;
+ ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+ em_swfw_sync_release(hw, swfw);
+ if (ret_val)
+ goto out;
+
+ /* Workaround for link disconnects on a busy hub in half duplex */
+ ret_val = em_read_phy_reg(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 17),
+ &phy_data);
+ if (ret_val)
+ goto release;
+ ret_val = em_write_phy_reg(hw,
+ PHY_REG(BM_PORT_CTRL_PAGE, 17),
+ phy_data & 0x00FF);
+release:
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_configure_k1_ich8lan - Configure K1 power state
+ * @hw: pointer to the HW structure
+ * @enable: K1 state to configure
+ *
+ * Configure the K1 power state based on the provided parameter.
+ * Assumes semaphore already acquired.
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ **/
+int32_t
+em_configure_k1_ich8lan(struct em_hw *hw, boolean_t k1_enable)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint32_t ctrl_reg = 0;
+ uint32_t ctrl_ext = 0;
+ uint32_t reg = 0;
+ uint16_t kmrn_reg = 0;
+
+ ret_val = em_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_K1_CONFIG,
+ &kmrn_reg);
+ if (ret_val)
+ goto out;
+
+ if (k1_enable)
+ kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
+ else
+ kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
+
+ ret_val = em_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_K1_CONFIG,
+ kmrn_reg);
+ if (ret_val)
+ goto out;
+
+ usec_delay(20);
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_reg = E1000_READ_REG(hw, CTRL);
+
+ reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ reg |= E1000_CTRL_FRCSPD;
+ E1000_WRITE_REG(hw, CTRL, reg);
+
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
+ usec_delay(20);
+ E1000_WRITE_REG(hw, CTRL, ctrl_reg);
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ usec_delay(20);
+
+out:
+ return ret_val;
+}
+
+
diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h
index 9eb68b848c4..74808fc2124 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.40 2010/06/26 18:32:38 jsg Exp $ */
+/* $OpenBSD: if_em_hw.h,v 1.41 2010/06/27 20:13:04 jsg Exp $ */
/* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */
/* if_em_hw.h
@@ -1546,6 +1546,7 @@ struct em_hw {
#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_EXT_PHYPDEN 0x00100000
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */
@@ -2646,6 +2647,7 @@ struct em_host_command_info {
#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */
#define BM_REG_BIAS1 29
#define BM_REG_BIAS2 30
+#define BM_PORT_CTRL_PAGE 769
#define IGP01E1000_IEEE_REGS_PAGE 0x0000
#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300
@@ -3480,4 +3482,32 @@ union ich8_hws_flash_regacc {
#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 */
+
+#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* InBand Parameters */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Loopback mode */
+#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
+#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002
+
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008
+#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16
+
+
#endif /* _EM_HW_H_ */