From 2d7edb923a823660b081bd4c660300ee19adca8d Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:43:52 -0700 Subject: [PATCH] e1000:82573 specific code & packet split code 82573 specific code & packet split code Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000.h net-drivers-2.6/drivers/net/e1000.new/e1000.h --- drivers/net/e1000/e1000_hw.c | 2132 +++++++++++++++++++++++++++++++++--------- 1 file changed, 1670 insertions(+), 462 deletions(-) (limited to 'drivers/net/e1000/e1000_hw.c') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 786a9b935659..b7a7ceb67f47 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -63,10 +63,11 @@ static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count); static int32_t e1000_acquire_eeprom(struct e1000_hw *hw); static void e1000_release_eeprom(struct e1000_hw *hw); static void e1000_standby_eeprom(struct e1000_hw *hw); -static int32_t e1000_id_led_init(struct e1000_hw * hw); static int32_t e1000_set_vco_speed(struct e1000_hw *hw); static int32_t e1000_polarity_reversal_workaround(struct e1000_hw *hw); static int32_t e1000_set_phy_mode(struct e1000_hw *hw); +static int32_t e1000_host_if_read_cookie(struct e1000_hw *hw, uint8_t *buffer); +static uint8_t e1000_calculate_mng_checksum(char *buffer, uint32_t length); /* IGP cable length table */ static const @@ -80,6 +81,17 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120}; +static const +uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = + { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, + 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58, + 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74, + 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90, + 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108, + 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124, + 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128, + 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; + /****************************************************************************** * Set the phy type member in the hw struct. @@ -91,10 +103,14 @@ e1000_set_phy_type(struct e1000_hw *hw) { DEBUGFUNC("e1000_set_phy_type"); + if(hw->mac_type == e1000_undefined) + return -E1000_ERR_PHY_TYPE; + switch(hw->phy_id) { case M88E1000_E_PHY_ID: case M88E1000_I_PHY_ID: case M88E1011_I_PHY_ID: + case M88E1111_I_PHY_ID: hw->phy_type = e1000_phy_m88; break; case IGP01E1000_I_PHY_ID: @@ -271,6 +287,7 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82546GB_PCIE: + case E1000_DEV_ID_82546GB_QUAD_COPPER: hw->mac_type = e1000_82546_rev_3; break; case E1000_DEV_ID_82541EI: @@ -289,12 +306,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82547GI: hw->mac_type = e1000_82547_rev_2; break; + case E1000_DEV_ID_82573E: + case E1000_DEV_ID_82573E_IAMT: + hw->mac_type = e1000_82573; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } switch(hw->mac_type) { + case e1000_82573: + hw->eeprom_semaphore_present = TRUE; + /* fall through */ case e1000_82541: case e1000_82547: case e1000_82541_rev_2: @@ -360,6 +384,9 @@ e1000_reset_hw(struct e1000_hw *hw) uint32_t icr; uint32_t manc; uint32_t led_ctrl; + uint32_t timeout; + uint32_t extcnf_ctrl; + int32_t ret_val; DEBUGFUNC("e1000_reset_hw"); @@ -369,6 +396,15 @@ e1000_reset_hw(struct e1000_hw *hw) e1000_pci_clear_mwi(hw); } + if(hw->bus_type == e1000_bus_type_pci_express) { + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + if(e1000_disable_pciex_master(hw) != E1000_SUCCESS) { + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + } + /* Clear interrupt mask to stop board from generating interrupts */ DEBUGOUT("Masking off all interrupts\n"); E1000_WRITE_REG(hw, IMC, 0xffffffff); @@ -393,10 +429,32 @@ e1000_reset_hw(struct e1000_hw *hw) /* Must reset the PHY before resetting the MAC */ if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { - E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); + E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); msec_delay(5); } + /* Must acquire the MDIO ownership before MAC reset. + * Ownership defaults to firmware after a reset. */ + if(hw->mac_type == e1000_82573) { + timeout = 10; + + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + do { + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + + if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) + break; + else + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + msec_delay(2); + timeout--; + } while(timeout); + } + /* Issue a global reset to the MAC. This will reset the chip's * transmit, receive, DMA, and link units. It will not effect * the current PCI configuration. The global reset bit is self- @@ -450,6 +508,18 @@ e1000_reset_hw(struct e1000_hw *hw) /* Wait for EEPROM reload */ msec_delay(20); break; + case e1000_82573: + udelay(10); + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); + /* fall through */ + ret_val = e1000_get_auto_rd_done(hw); + if(ret_val) + /* We don't want to continue accessing MAC registers. */ + return ret_val; + break; default: /* Wait for EEPROM reload (it happens automatically) */ msec_delay(5); @@ -457,7 +527,7 @@ e1000_reset_hw(struct e1000_hw *hw) } /* Disable HW ARPs on ASF enabled adapters */ - if(hw->mac_type >= e1000_82540) { + if(hw->mac_type >= e1000_82540 && hw->mac_type <= e1000_82547_rev_2) { manc = E1000_READ_REG(hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(hw, MANC, manc); @@ -510,6 +580,8 @@ e1000_init_hw(struct e1000_hw *hw) uint16_t pcix_stat_hi_word; uint16_t cmd_mmrbc; uint16_t stat_mmrbc; + uint32_t mta_size; + DEBUGFUNC("e1000_init_hw"); /* Initialize Identification LED */ @@ -524,8 +596,8 @@ e1000_init_hw(struct e1000_hw *hw) /* Disabling VLAN filtering. */ DEBUGOUT("Initializing the IEEE VLAN\n"); - E1000_WRITE_REG(hw, VET, 0); - + if (hw->mac_type < e1000_82545_rev_3) + E1000_WRITE_REG(hw, VET, 0); e1000_clear_vfta(hw); /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ @@ -553,14 +625,16 @@ e1000_init_hw(struct e1000_hw *hw) /* Zero out the Multicast HASH table */ DEBUGOUT("Zeroing the MTA\n"); - for(i = 0; i < E1000_MC_TBL_SIZE; i++) + mta_size = E1000_MC_TBL_SIZE; + for(i = 0; i < mta_size; i++) E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); /* Set the PCI priority bit correctly in the CTRL register. This * determines if the adapter gives priority to receives, or if it - * gives equal priority to transmits and receives. + * gives equal priority to transmits and receives. Valid only on + * 82542 and 82543 silicon. */ - if(hw->dma_fairness) { + if(hw->dma_fairness && hw->mac_type <= e1000_82543) { ctrl = E1000_READ_REG(hw, CTRL); E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR); } @@ -598,9 +672,21 @@ e1000_init_hw(struct e1000_hw *hw) if(hw->mac_type > e1000_82544) { ctrl = E1000_READ_REG(hw, TXDCTL); ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; + switch (hw->mac_type) { + default: + break; + case e1000_82573: + ctrl |= E1000_TXDCTL_COUNT_DESC; + break; + } E1000_WRITE_REG(hw, TXDCTL, ctrl); } + if (hw->mac_type == e1000_82573) { + e1000_enable_tx_pkt_filtering(hw); + } + + /* Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link * because the symbol error count will increment wildly if there @@ -679,7 +765,7 @@ e1000_setup_link(struct e1000_hw *hw) * control setting, then the variable hw->fc will * be initialized based on a value in the EEPROM. */ - if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data)) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -736,6 +822,7 @@ e1000_setup_link(struct e1000_hw *hw) E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW); E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH); E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time); /* Set the flow control receive threshold registers. Normally, @@ -906,20 +993,18 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw) } /****************************************************************************** -* Detects which PHY is present and the speed and duplex +* Make sure we have a valid PHY and change PHY mode before link setup. * * hw - Struct containing variables accessed by shared code ******************************************************************************/ static int32_t -e1000_setup_copper_link(struct e1000_hw *hw) +e1000_copper_link_preconfig(struct e1000_hw *hw) { uint32_t ctrl; - uint32_t led_ctrl; int32_t ret_val; - uint16_t i; uint16_t phy_data; - DEBUGFUNC("e1000_setup_copper_link"); + DEBUGFUNC("e1000_copper_link_preconfig"); ctrl = E1000_READ_REG(hw, CTRL); /* With 82543, we need to force speed and duplex on the MAC equal to what @@ -933,7 +1018,9 @@ e1000_setup_copper_link(struct e1000_hw *hw) } else { ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); E1000_WRITE_REG(hw, CTRL, ctrl); - e1000_phy_hw_reset(hw); + ret_val = e1000_phy_hw_reset(hw); + if(ret_val) + return ret_val; } /* Make sure we have a valid PHY */ @@ -961,354 +1048,452 @@ e1000_setup_copper_link(struct e1000_hw *hw) hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) hw->phy_reset_disable = FALSE; - if(!hw->phy_reset_disable) { - if (hw->phy_type == e1000_phy_igp) { - - ret_val = e1000_phy_reset(hw); - if(ret_val) { - DEBUGOUT("Error Resetting the PHY\n"); - return ret_val; - } - - /* Wait 10ms for MAC to configure PHY from eeprom settings */ - msec_delay(15); + return E1000_SUCCESS; +} - /* Configure activity LED after PHY reset */ - led_ctrl = E1000_READ_REG(hw, LEDCTL); - led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - E1000_WRITE_REG(hw, LEDCTL, led_ctrl); - /* disable lplu d3 during driver init */ - ret_val = e1000_set_d3_lplu_state(hw, FALSE); - if(ret_val) { - DEBUGOUT("Error Disabling LPLU D3\n"); - return ret_val; - } +/******************************************************************** +* Copper link setup for e1000_phy_igp series. +* +* hw - Struct containing variables accessed by shared code +*********************************************************************/ +static int32_t +e1000_copper_link_igp_setup(struct e1000_hw *hw) +{ + uint32_t led_ctrl; + int32_t ret_val; + uint16_t phy_data; - /* Configure mdi-mdix settings */ - ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, - &phy_data); - if(ret_val) - return ret_val; + DEBUGFUNC("e1000_copper_link_igp_setup"); - if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { - hw->dsp_config_state = e1000_dsp_config_disabled; - /* Force MDI for earlier revs of the IGP PHY */ - phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | - IGP01E1000_PSCR_FORCE_MDI_MDIX); - hw->mdix = 1; + if (hw->phy_reset_disable) + return E1000_SUCCESS; + + ret_val = e1000_phy_reset(hw); + if (ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } - } else { - hw->dsp_config_state = e1000_dsp_config_enabled; - phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; - - switch (hw->mdix) { - case 1: - phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 2: - phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 0: - default: - phy_data |= IGP01E1000_PSCR_AUTO_MDIX; - break; - } - } - ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, - phy_data); - if(ret_val) - return ret_val; + /* Wait 10ms for MAC to configure PHY from eeprom settings */ + msec_delay(15); - /* set auto-master slave resolution settings */ - if(hw->autoneg) { - e1000_ms_type phy_ms_setting = hw->master_slave; + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); - if(hw->ffe_config_state == e1000_ffe_config_active) - hw->ffe_config_state = e1000_ffe_config_enabled; + /* disable lplu d3 during driver init */ + ret_val = e1000_set_d3_lplu_state(hw, FALSE); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D3\n"); + return ret_val; + } - if(hw->dsp_config_state == e1000_dsp_config_activated) - hw->dsp_config_state = e1000_dsp_config_enabled; + /* disable lplu d0 during driver init */ + ret_val = e1000_set_d0_lplu_state(hw, FALSE); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D0\n"); + return ret_val; + } + /* Configure mdi-mdix settings */ + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); + if (ret_val) + return ret_val; - /* when autonegotiation advertisment is only 1000Mbps then we - * should disable SmartSpeed and enable Auto MasterSlave - * resolution as hardware default. */ - if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { - /* Disable SmartSpeed */ - ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - &phy_data); - if(ret_val) - return ret_val; - phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1000_write_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - phy_data); - if(ret_val) - return ret_val; - /* Set auto Master/Slave resolution process */ - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); - if(ret_val) - return ret_val; - phy_data &= ~CR_1000T_MS_ENABLE; - ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); - if(ret_val) - return ret_val; - } + if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { + hw->dsp_config_state = e1000_dsp_config_disabled; + /* Force MDI for earlier revs of the IGP PHY */ + phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX); + hw->mdix = 1; - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); - if(ret_val) - return ret_val; + } else { + hw->dsp_config_state = e1000_dsp_config_enabled; + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; - /* load defaults for future use */ - hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ? - ((phy_data & CR_1000T_MS_VALUE) ? - e1000_ms_force_master : - e1000_ms_force_slave) : - e1000_ms_auto; - - switch (phy_ms_setting) { - case e1000_ms_force_master: - phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); - break; - case e1000_ms_force_slave: - phy_data |= CR_1000T_MS_ENABLE; - phy_data &= ~(CR_1000T_MS_VALUE); - break; - case e1000_ms_auto: - phy_data &= ~CR_1000T_MS_ENABLE; - default: - break; - } - ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); - if(ret_val) - return ret_val; - } - } else { - /* Enable CRS on TX. This must be set for half-duplex operation. */ - ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, - &phy_data); - if(ret_val) - return ret_val; + switch (hw->mdix) { + case 1: + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 2: + phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 0: + default: + phy_data |= IGP01E1000_PSCR_AUTO_MDIX; + break; + } + } + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); + if(ret_val) + return ret_val; - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + /* set auto-master slave resolution settings */ + if(hw->autoneg) { + e1000_ms_type phy_ms_setting = hw->master_slave; - /* Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + if(hw->ffe_config_state == e1000_ffe_config_active) + hw->ffe_config_state = e1000_ffe_config_enabled; - switch (hw->mdix) { - case 1: - phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; - break; - case 2: - phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; - break; - case 3: - phy_data |= M88E1000_PSCR_AUTO_X_1000T; - break; - case 0: - default: - phy_data |= M88E1000_PSCR_AUTO_X_MODE; - break; - } + if(hw->dsp_config_state == e1000_dsp_config_activated) + hw->dsp_config_state = e1000_dsp_config_enabled; - /* Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if(hw->disable_polarity_correction == 1) - phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, - phy_data); + /* when autonegotiation advertisment is only 1000Mbps then we + * should disable SmartSpeed and enable Auto MasterSlave + * resolution as hardware default. */ + if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); if(ret_val) return ret_val; - - /* Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - &phy_data); + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + phy_data); if(ret_val) return ret_val; + /* Set auto Master/Slave resolution process */ + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); + if(ret_val) + return ret_val; + phy_data &= ~CR_1000T_MS_ENABLE; + ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); + if(ret_val) + return ret_val; + } - phy_data |= M88E1000_EPSCR_TX_CLK_25; + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); + if(ret_val) + return ret_val; - if (hw->phy_revision < M88E1011_I_REV_4) { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - phy_data); - if(ret_val) - return ret_val; - } + /* load defaults for future use */ + hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ? + ((phy_data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : + e1000_ms_auto; - /* SW Reset the PHY so all changes take effect */ - ret_val = e1000_phy_reset(hw); - if(ret_val) { - DEBUGOUT("Error Resetting the PHY\n"); - return ret_val; - } + switch (phy_ms_setting) { + case e1000_ms_force_master: + phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + phy_data |= CR_1000T_MS_ENABLE; + phy_data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + phy_data &= ~CR_1000T_MS_ENABLE; + default: + break; + } + ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); + if(ret_val) + return ret_val; } - /* Options: - * autoneg = 1 (default) - * PHY will advertise value(s) parsed from - * autoneg_advertised and fc - * autoneg = 0 - * PHY will be set to 10H, 10F, 100H, or 100F - * depending on value parsed from forced_speed_duplex. - */ + return E1000_SUCCESS; +} - /* Is autoneg enabled? This is enabled by default or by software - * override. If so, call e1000_phy_setup_autoneg routine to parse the - * autoneg_advertised and fc options. If autoneg is NOT enabled, then - * the user should have provided a speed/duplex override. If so, then - * call e1000_phy_force_speed_duplex to parse and set this up. - */ - if(hw->autoneg) { - /* Perform some bounds checking on the hw->autoneg_advertised - * parameter. If this variable is zero, then set it to the default. - */ - hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; - /* If autoneg_advertised is zero, we assume it was not defaulted - * by the calling code so we set to advertise full capability. - */ - if(hw->autoneg_advertised == 0) - hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; +/******************************************************************** +* Copper link setup for e1000_phy_m88 series. +* +* hw - Struct containing variables accessed by shared code +*********************************************************************/ +static int32_t +e1000_copper_link_mgp_setup(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data; - DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); - ret_val = e1000_phy_setup_autoneg(hw); - if(ret_val) { - DEBUGOUT("Error Setting up Auto-Negotiation\n"); - return ret_val; - } - DEBUGOUT("Restarting Auto-Neg\n"); + DEBUGFUNC("e1000_copper_link_mgp_setup"); - /* Restart auto-negotiation by setting the Auto Neg Enable bit and - * the Auto Neg Restart bit in the PHY control register. - */ - ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); - if(ret_val) - return ret_val; + if(hw->phy_reset_disable) + return E1000_SUCCESS; + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if(ret_val) + return ret_val; - phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); - ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data); - if(ret_val) - return ret_val; + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - /* Does the user want to wait for Auto-Neg to complete here, or - * check at a later time (for example, callback routine). - */ - if(hw->wait_autoneg_complete) { - ret_val = e1000_wait_autoneg(hw); - if(ret_val) { - DEBUGOUT("Error while waiting for autoneg to complete\n"); - return ret_val; - } - } - hw->get_link_status = TRUE; - } else { - DEBUGOUT("Forcing speed and duplex\n"); - ret_val = e1000_phy_force_speed_duplex(hw); - if(ret_val) { - DEBUGOUT("Error Forcing Speed and Duplex\n"); - return ret_val; - } - } - } /* !hw->phy_reset_disable */ + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - /* Check link status. Wait up to 100 microseconds for link to become - * valid. + switch (hw->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled */ - for(i = 0; i < 10; i++) { - ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if(hw->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; - ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if(ret_val) + return ret_val; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if (hw->phy_revision < M88E1011_I_REV_4) { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; + } - if(phy_data & MII_SR_LINK_STATUS) { - /* We have link, so we need to finish the config process: - * 1) Set up the MAC to the current PHY speed/duplex - * if we are on 82543. If we - * are on newer silicon, we only need to configure - * collision distance in the Transmit Control Register. - * 2) Set up flow control on the MAC to that established with - * the link partner. - */ - if(hw->mac_type >= e1000_82544) { - e1000_config_collision_dist(hw); - } else { - ret_val = e1000_config_mac_to_phy(hw); - if(ret_val) { - DEBUGOUT("Error configuring MAC to PHY settings\n"); - return ret_val; - } - } - ret_val = e1000_config_fc_after_link_up(hw); - if(ret_val) { - DEBUGOUT("Error Configuring Flow Control\n"); - return ret_val; - } - DEBUGOUT("Valid link established!!!\n"); - - if(hw->phy_type == e1000_phy_igp) { - ret_val = e1000_config_dsp_after_link_change(hw, TRUE); - if(ret_val) { - DEBUGOUT("Error Configuring DSP after link up\n"); - return ret_val; - } - } - DEBUGOUT("Valid link established!!!\n"); - return E1000_SUCCESS; - } - udelay(10); + /* SW Reset the PHY so all changes take effect */ + ret_val = e1000_phy_reset(hw); + if(ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; } - DEBUGOUT("Unable to establish link!!!\n"); - return E1000_SUCCESS; + return E1000_SUCCESS; } -/****************************************************************************** -* Configures PHY autoneg and flow control advertisement settings +/******************************************************************** +* Setup auto-negotiation and flow control advertisements, +* and then perform auto-negotiation. * * hw - Struct containing variables accessed by shared code -******************************************************************************/ -int32_t -e1000_phy_setup_autoneg(struct e1000_hw *hw) +*********************************************************************/ +static int32_t +e1000_copper_link_autoneg(struct e1000_hw *hw) { int32_t ret_val; - uint16_t mii_autoneg_adv_reg; - uint16_t mii_1000t_ctrl_reg; + uint16_t phy_data; - DEBUGFUNC("e1000_phy_setup_autoneg"); + DEBUGFUNC("e1000_copper_link_autoneg"); - /* Read the MII Auto-Neg Advertisement Register (Address 4). */ - ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + /* Perform some bounds checking on the hw->autoneg_advertised + * parameter. If this variable is zero, then set it to the default. + */ + hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if(hw->autoneg_advertised == 0) + hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + ret_val = e1000_phy_setup_autoneg(hw); + if(ret_val) { + DEBUGOUT("Error Setting up Auto-Negotiation\n"); + return ret_val; + } + DEBUGOUT("Restarting Auto-Neg\n"); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); if(ret_val) return ret_val; - /* Read the MII 1000Base-T Control Register (Address 9). */ - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data); if(ret_val) return ret_val; - /* Need to parse both autoneg_advertised and fc and set up - * the appropriate PHY registers. First we will parse for + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if(hw->wait_autoneg_complete) { + ret_val = e1000_wait_autoneg(hw); + if(ret_val) { + DEBUGOUT("Error while waiting for autoneg to complete\n"); + return ret_val; + } + } + + hw->get_link_status = TRUE; + + return E1000_SUCCESS; +} + + +/****************************************************************************** +* Config the MAC and the PHY after link is up. +* 1) Set up the MAC to the current PHY speed/duplex +* if we are on 82543. If we +* are on newer silicon, we only need to configure +* collision distance in the Transmit Control Register. +* 2) Set up flow control on the MAC to that established with +* the link partner. +* 3) Config DSP to improve Gigabit link quality for some PHY revisions. +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +static int32_t +e1000_copper_link_postconfig(struct e1000_hw *hw) +{ + int32_t ret_val; + DEBUGFUNC("e1000_copper_link_postconfig"); + + if(hw->mac_type >= e1000_82544) { + e1000_config_collision_dist(hw); + } else { + ret_val = e1000_config_mac_to_phy(hw); + if(ret_val) { + DEBUGOUT("Error configuring MAC to PHY settings\n"); + return ret_val; + } + } + ret_val = e1000_config_fc_after_link_up(hw); + if(ret_val) { + DEBUGOUT("Error Configuring Flow Control\n"); + return ret_val; + } + + /* Config DSP to improve Giga link quality */ + if(hw->phy_type == e1000_phy_igp) { + ret_val = e1000_config_dsp_after_link_change(hw, TRUE); + if(ret_val) { + DEBUGOUT("Error Configuring DSP after link up\n"); + return ret_val; + } + } + + return E1000_SUCCESS; +} + +/****************************************************************************** +* Detects which PHY is present and setup the speed and duplex +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +static int32_t +e1000_setup_copper_link(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t i; + uint16_t phy_data; + + DEBUGFUNC("e1000_setup_copper_link"); + + /* Check if it is a valid PHY and set PHY mode if necessary. */ + ret_val = e1000_copper_link_preconfig(hw); + if(ret_val) + return ret_val; + + if (hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) { + ret_val = e1000_copper_link_igp_setup(hw); + if(ret_val) + return ret_val; + } else if (hw->phy_type == e1000_phy_m88) { + ret_val = e1000_copper_link_mgp_setup(hw); + if(ret_val) + return ret_val; + } + + if(hw->autoneg) { + /* Setup autoneg and flow control advertisement + * and perform autonegotiation */ + ret_val = e1000_copper_link_autoneg(hw); + if(ret_val) + return ret_val; + } else { + /* PHY will be set to 10H, 10F, 100H,or 100F + * depending on value from forced_speed_duplex. */ + DEBUGOUT("Forcing speed and duplex\n"); + ret_val = e1000_phy_force_speed_duplex(hw); + if(ret_val) { + DEBUGOUT("Error Forcing Speed and Duplex\n"); + return ret_val; + } + } + + /* Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + for(i = 0; i < 10; i++) { + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + if(ret_val) + return ret_val; + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + if(ret_val) + return ret_val; + + if(phy_data & MII_SR_LINK_STATUS) { + /* Config the MAC and PHY after link is up */ + ret_val = e1000_copper_link_postconfig(hw); + if(ret_val) + return ret_val; + + DEBUGOUT("Valid link established!!!\n"); + return E1000_SUCCESS; + } + udelay(10); + } + + DEBUGOUT("Unable to establish link!!!\n"); + return E1000_SUCCESS; +} + +/****************************************************************************** +* Configures PHY autoneg and flow control advertisement settings +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +int32_t +e1000_phy_setup_autoneg(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + + DEBUGFUNC("e1000_phy_setup_autoneg"); + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + if(ret_val) + return ret_val; + + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + if(ret_val) + return ret_val; + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for * autoneg_advertised software override. Since we can advertise * a plethora of combinations, we need to check each bit * individually. @@ -1417,7 +1602,7 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); if(ret_val) return ret_val; @@ -1678,6 +1863,11 @@ e1000_config_mac_to_phy(struct e1000_hw *hw) DEBUGFUNC("e1000_config_mac_to_phy"); + /* 82544 or newer MAC, Auto Speed Detection takes care of + * MAC speed/duplex configuration.*/ + if (hw->mac_type >= e1000_82544) + return E1000_SUCCESS; + /* Read the Device Control Register and set the bits to Force Speed * and Duplex. */ @@ -1688,45 +1878,25 @@ e1000_config_mac_to_phy(struct e1000_hw *hw) /* Set up duplex in the Device Control and Transmit Control * registers depending on negotiated values. */ - if (hw->phy_type == e1000_phy_igp) { - ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, - &phy_data); - if(ret_val) - return ret_val; - - if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD; - else ctrl &= ~E1000_CTRL_FD; - - e1000_config_collision_dist(hw); + ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if(ret_val) + return ret_val; - /* Set up speed in the Device Control register depending on - * negotiated values. - */ - if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) - ctrl |= E1000_CTRL_SPD_1000; - else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_100MBPS) - ctrl |= E1000_CTRL_SPD_100; - } else { - ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, - &phy_data); - if(ret_val) - return ret_val; + if(phy_data & M88E1000_PSSR_DPLX) + ctrl |= E1000_CTRL_FD; + else + ctrl &= ~E1000_CTRL_FD; - if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD; - else ctrl &= ~E1000_CTRL_FD; + e1000_config_collision_dist(hw); - e1000_config_collision_dist(hw); + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + ctrl |= E1000_CTRL_SPD_1000; + else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + ctrl |= E1000_CTRL_SPD_100; - /* Set up speed in the Device Control register depending on - * negotiated values. - */ - if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) - ctrl |= E1000_CTRL_SPD_1000; - else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) - ctrl |= E1000_CTRL_SPD_100; - } /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); return E1000_SUCCESS; @@ -2494,8 +2664,8 @@ e1000_read_phy_reg(struct e1000_hw *hw, DEBUGFUNC("e1000_read_phy_reg"); - - if(hw->phy_type == e1000_phy_igp && + if((hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); @@ -2600,8 +2770,8 @@ e1000_write_phy_reg(struct e1000_hw *hw, DEBUGFUNC("e1000_write_phy_reg"); - - if(hw->phy_type == e1000_phy_igp && + if((hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); @@ -2679,19 +2849,27 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, return E1000_SUCCESS; } + /****************************************************************************** * Returns the PHY to the power-on reset state * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -void +int32_t e1000_phy_hw_reset(struct e1000_hw *hw) { uint32_t ctrl, ctrl_ext; uint32_t led_ctrl; + int32_t ret_val; DEBUGFUNC("e1000_phy_hw_reset"); + /* In the case of the phy reset being blocked, it's not an error, we + * simply return success without performing the reset. */ + ret_val = e1000_check_phy_reset_block(hw); + if (ret_val) + return E1000_SUCCESS; + DEBUGOUT("Resetting Phy...\n"); if(hw->mac_type > e1000_82543) { @@ -2727,6 +2905,11 @@ e1000_phy_hw_reset(struct e1000_hw *hw) led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); } + + /* Wait for FW to finish PHY configuration. */ + ret_val = e1000_get_phy_cfg_done(hw); + + return ret_val; } /****************************************************************************** @@ -2744,7 +2927,19 @@ e1000_phy_reset(struct e1000_hw *hw) DEBUGFUNC("e1000_phy_reset"); - if(hw->mac_type != e1000_82541_rev_2) { + /* In the case of the phy reset being blocked, it's not an error, we + * simply return success without performing the reset. */ + ret_val = e1000_check_phy_reset_block(hw); + if (ret_val) + return E1000_SUCCESS; + + switch (hw->mac_type) { + case e1000_82541_rev_2: + ret_val = e1000_phy_hw_reset(hw); + if(ret_val) + return ret_val; + break; + default: ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); if(ret_val) return ret_val; @@ -2755,9 +2950,10 @@ e1000_phy_reset(struct e1000_hw *hw) return ret_val; udelay(1); - } else e1000_phy_hw_reset(hw); + break; + } - if(hw->phy_type == e1000_phy_igp) + if(hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) e1000_phy_init_script(hw); return E1000_SUCCESS; @@ -2811,6 +3007,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw) case e1000_82547_rev_2: if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; break; + case e1000_82573: + if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; @@ -2866,7 +3065,7 @@ e1000_phy_igp_get_info(struct e1000_hw *hw, /* The downshift status is checked only once, after link is established, * and it stored in the hw->speed_downgraded parameter. */ - phy_info->downshift = hw->speed_downgraded; + phy_info->downshift = (e1000_downshift)hw->speed_downgraded; /* IGP01E1000 does not need to support it. */ phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal; @@ -2905,7 +3104,7 @@ e1000_phy_igp_get_info(struct e1000_hw *hw, if(ret_val) return ret_val; - /* transalte to old method */ + /* Translate to old method */ average = (max_length + min_length) / 2; if(average <= e1000_igp_cable_length_50) @@ -2940,7 +3139,7 @@ e1000_phy_m88_get_info(struct e1000_hw *hw, /* The downshift status is checked only once, after link is established, * and it stored in the hw->speed_downgraded parameter. */ - phy_info->downshift = hw->speed_downgraded; + phy_info->downshift = (e1000_downshift)hw->speed_downgraded; ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if(ret_val) @@ -3029,7 +3228,8 @@ e1000_phy_get_info(struct e1000_hw *hw, return -E1000_ERR_CONFIG; } - if(hw->phy_type == e1000_phy_igp) + if(hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) return e1000_phy_igp_get_info(hw, phy_info); else return e1000_phy_m88_get_info(hw, phy_info); @@ -3055,11 +3255,12 @@ e1000_validate_mdi_setting(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -void +int32_t e1000_init_eeprom_params(struct e1000_hw *hw) { struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd = E1000_READ_REG(hw, EECD); + int32_t ret_val = E1000_SUCCESS; uint16_t eeprom_size; DEBUGFUNC("e1000_init_eeprom_params"); @@ -3074,6 +3275,8 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->opcode_bits = 3; eeprom->address_bits = 6; eeprom->delay_usec = 50; + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; break; case e1000_82540: case e1000_82545: @@ -3090,6 +3293,8 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->word_size = 64; eeprom->address_bits = 6; } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; break; case e1000_82541: case e1000_82541_rev_2: @@ -3118,42 +3323,60 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->address_bits = 6; } } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + break; + case e1000_82573: + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + eeprom->use_eerd = TRUE; + eeprom->use_eewr = TRUE; + if(e1000_is_onboard_nvm_eeprom(hw) == FALSE) { + eeprom->type = e1000_eeprom_flash; + eeprom->word_size = 2048; + + /* Ensure that the Autonomous FLASH update bit is cleared due to + * Flash update issue on parts which use a FLASH for NVM. */ + eecd &= ~E1000_EECD_AUPDEN; + E1000_WRITE_REG(hw, EECD, eecd); + } break; default: break; } if (eeprom->type == e1000_eeprom_spi) { - eeprom->word_size = 64; - if (e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) { - eeprom_size &= EEPROM_SIZE_MASK; - - switch (eeprom_size) { - case EEPROM_SIZE_16KB: - eeprom->word_size = 8192; - break; - case EEPROM_SIZE_8KB: - eeprom->word_size = 4096; - break; - case EEPROM_SIZE_4KB: - eeprom->word_size = 2048; - break; - case EEPROM_SIZE_2KB: - eeprom->word_size = 1024; - break; - case EEPROM_SIZE_1KB: - eeprom->word_size = 512; - break; - case EEPROM_SIZE_512B: - eeprom->word_size = 256; - break; - case EEPROM_SIZE_128B: - default: - eeprom->word_size = 64; - break; - } + /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to + * 32KB (incremented by powers of 2). + */ + if(hw->mac_type <= e1000_82547_rev_2) { + /* Set to default value for initial eeprom read. */ + eeprom->word_size = 64; + ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size); + if(ret_val) + return ret_val; + eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT; + /* 256B eeprom size was not supported in earlier hardware, so we + * bump eeprom_size up one to ensure that "1" (which maps to 256B) + * is never the result used in the shifting logic below. */ + if(eeprom_size) + eeprom_size++; + } else { + eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); } + + eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT); } + return ret_val; } /****************************************************************************** @@ -3306,8 +3529,12 @@ e1000_acquire_eeprom(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_eeprom"); + if(e1000_get_hw_eeprom_semaphore(hw)) + return -E1000_ERR_EEPROM; + eecd = E1000_READ_REG(hw, EECD); + if (hw->mac_type != e1000_82573) { /* Request EEPROM Access */ if(hw->mac_type > e1000_82544) { eecd |= E1000_EECD_REQ; @@ -3326,6 +3553,7 @@ e1000_acquire_eeprom(struct e1000_hw *hw) return -E1000_ERR_EEPROM; } } + } /* Setup EEPROM for Read/Write */ @@ -3443,6 +3671,8 @@ e1000_release_eeprom(struct e1000_hw *hw) eecd &= ~E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); } + + e1000_put_hw_eeprom_semaphore(hw); } /****************************************************************************** @@ -3504,8 +3734,10 @@ e1000_read_eeprom(struct e1000_hw *hw, { struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t i = 0; + int32_t ret_val; DEBUGFUNC("e1000_read_eeprom"); + /* A check for invalid values: offset too large, too many words, and not * enough words. */ @@ -3515,9 +3747,23 @@ e1000_read_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } - /* Prepare the EEPROM for reading */ - if(e1000_acquire_eeprom(hw) != E1000_SUCCESS) - return -E1000_ERR_EEPROM; + /* FLASH reads without acquiring the semaphore are safe in 82573-based + * controllers. + */ + if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) || + (hw->mac_type != e1000_82573)) { + /* Prepare the EEPROM for reading */ + if(e1000_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; + } + + if(eeprom->use_eerd == TRUE) { + ret_val = e1000_read_eeprom_eerd(hw, offset, words, data); + if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) || + (hw->mac_type != e1000_82573)) + e1000_release_eeprom(hw); + return ret_val; + } if(eeprom->type == e1000_eeprom_spi) { uint16_t word_in; @@ -3569,65 +3815,212 @@ e1000_read_eeprom(struct e1000_hw *hw, } /****************************************************************************** - * Verifies that the EEPROM has a valid checksum + * Reads a 16 bit word from the EEPROM using the EERD register. * * hw - Struct containing variables accessed by shared code - * - * Reads the first 64 16 bit words of the EEPROM and sums the values read. - * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is - * valid. + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read *****************************************************************************/ int32_t -e1000_validate_eeprom_checksum(struct e1000_hw *hw) +e1000_read_eeprom_eerd(struct e1000_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) { - uint16_t checksum = 0; - uint16_t i, eeprom_data; + uint32_t i, eerd = 0; + int32_t error = 0; - DEBUGFUNC("e1000_validate_eeprom_checksum"); + for (i = 0; i < words; i++) { + eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) + + E1000_EEPROM_RW_REG_START; - for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { - DEBUGOUT("EEPROM Read Error\n"); - return -E1000_ERR_EEPROM; + E1000_WRITE_REG(hw, EERD, eerd); + error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ); + + if(error) { + break; } - checksum += eeprom_data; - } - - if(checksum == (uint16_t) EEPROM_SUM) - return E1000_SUCCESS; - else { - DEBUGOUT("EEPROM Checksum Invalid\n"); - return -E1000_ERR_EEPROM; + data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA); + } + + return error; } /****************************************************************************** - * Calculates the EEPROM checksum and writes it to the EEPROM + * Writes a 16 bit word from the EEPROM using the EEWR register. * * hw - Struct containing variables accessed by shared code - * - * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA. - * Writes the difference to word offset 63 of the EEPROM. + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read *****************************************************************************/ int32_t -e1000_update_eeprom_checksum(struct e1000_hw *hw) +e1000_write_eeprom_eewr(struct e1000_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) { - uint16_t checksum = 0; - uint16_t i, eeprom_data; + uint32_t register_value = 0; + uint32_t i = 0; + int32_t error = 0; - DEBUGFUNC("e1000_update_eeprom_checksum"); + for (i = 0; i < words; i++) { + register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | + ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | + E1000_EEPROM_RW_REG_START; - for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { - if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { - DEBUGOUT("EEPROM Read Error\n"); - return -E1000_ERR_EEPROM; - } - checksum += eeprom_data; - } - checksum = (uint16_t) EEPROM_SUM - checksum; + error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE); + if(error) { + break; + } + + E1000_WRITE_REG(hw, EEWR, register_value); + + error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE); + + if(error) { + break; + } + } + + return error; +} + +/****************************************************************************** + * Polls the status bit (bit 1) of the EERD to determine when the read is done. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd) +{ + uint32_t attempts = 100000; + uint32_t i, reg = 0; + int32_t done = E1000_ERR_EEPROM; + + for(i = 0; i < attempts; i++) { + if(eerd == E1000_EEPROM_POLL_READ) + reg = E1000_READ_REG(hw, EERD); + else + reg = E1000_READ_REG(hw, EEWR); + + if(reg & E1000_EEPROM_RW_REG_DONE) { + done = E1000_SUCCESS; + break; + } + udelay(5); + } + + return done; +} + +/*************************************************************************** +* Description: Determines if the onboard NVM is FLASH or EEPROM. +* +* hw - Struct containing variables accessed by shared code +****************************************************************************/ +boolean_t +e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw) +{ + uint32_t eecd = 0; + + if(hw->mac_type == e1000_82573) { + eecd = E1000_READ_REG(hw, EECD); + + /* Isolate bits 15 & 16 */ + eecd = ((eecd >> 15) & 0x03); + + /* If both bits are set, device is Flash type */ + if(eecd == 0x03) { + return FALSE; + } + } + return TRUE; +} + +/****************************************************************************** + * Verifies that the EEPROM has a valid checksum + * + * hw - Struct containing variables accessed by shared code + * + * Reads the first 64 16 bit words of the EEPROM and sums the values read. + * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is + * valid. + *****************************************************************************/ +int32_t +e1000_validate_eeprom_checksum(struct e1000_hw *hw) +{ + uint16_t checksum = 0; + uint16_t i, eeprom_data; + + DEBUGFUNC("e1000_validate_eeprom_checksum"); + + if ((hw->mac_type == e1000_82573) && + (e1000_is_onboard_nvm_eeprom(hw) == FALSE)) { + /* Check bit 4 of word 10h. If it is 0, firmware is done updating + * 10h-12h. Checksum may need to be fixed. */ + e1000_read_eeprom(hw, 0x10, 1, &eeprom_data); + if ((eeprom_data & 0x10) == 0) { + /* Read 0x23 and check bit 15. This bit is a 1 when the checksum + * has already been fixed. If the checksum is still wrong and this + * bit is a 1, we need to return bad checksum. Otherwise, we need + * to set this bit to a 1 and update the checksum. */ + e1000_read_eeprom(hw, 0x23, 1, &eeprom_data); + if ((eeprom_data & 0x8000) == 0) { + eeprom_data |= 0x8000; + e1000_write_eeprom(hw, 0x23, 1, &eeprom_data); + e1000_update_eeprom_checksum(hw); + } + } + } + + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { + DEBUGOUT("EEPROM Read Error\n"); + return -E1000_ERR_EEPROM; + } + checksum += eeprom_data; + } + + if(checksum == (uint16_t) EEPROM_SUM) + return E1000_SUCCESS; + else { + DEBUGOUT("EEPROM Checksum Invalid\n"); + return -E1000_ERR_EEPROM; + } +} + +/****************************************************************************** + * Calculates the EEPROM checksum and writes it to the EEPROM + * + * hw - Struct containing variables accessed by shared code + * + * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA. + * Writes the difference to word offset 63 of the EEPROM. + *****************************************************************************/ +int32_t +e1000_update_eeprom_checksum(struct e1000_hw *hw) +{ + uint16_t checksum = 0; + uint16_t i, eeprom_data; + + DEBUGFUNC("e1000_update_eeprom_checksum"); + + for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { + if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { + DEBUGOUT("EEPROM Read Error\n"); + return -E1000_ERR_EEPROM; + } + checksum += eeprom_data; + } + checksum = (uint16_t) EEPROM_SUM - checksum; if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) { DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; + } else if (hw->eeprom.type == e1000_eeprom_flash) { + e1000_commit_shadow_ram(hw); } return E1000_SUCCESS; } @@ -3663,6 +4056,10 @@ e1000_write_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } + /* 82573 reads only through eerd */ + if(eeprom->use_eewr == TRUE) + return e1000_write_eeprom_eewr(hw, offset, words, data); + /* Prepare the EEPROM for writing */ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; @@ -3832,6 +4229,65 @@ e1000_write_eeprom_microwire(struct e1000_hw *hw, return E1000_SUCCESS; } +/****************************************************************************** + * Flushes the cached eeprom to NVM. This is done by saving the modified values + * in the eeprom cache and the non modified values in the currently active bank + * to the new bank. + * + * hw - Struct containing variables accessed by shared code + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read + *****************************************************************************/ +int32_t +e1000_commit_shadow_ram(struct e1000_hw *hw) +{ + uint32_t attempts = 100000; + uint32_t eecd = 0; + uint32_t flop = 0; + uint32_t i = 0; + int32_t error = E1000_SUCCESS; + + /* The flop register will be used to determine if flash type is STM */ + flop = E1000_READ_REG(hw, FLOP); + + if (hw->mac_type == e1000_82573) { + for (i=0; i < attempts; i++) { + eecd = E1000_READ_REG(hw, EECD); + if ((eecd & E1000_EECD_FLUPD) == 0) { + break; + } + udelay(5); + } + + if (i == attempts) { + return -E1000_ERR_EEPROM; + } + + /* If STM opcode located in bits 15:8 of flop, reset firmware */ + if ((flop & 0xFF00) == E1000_STM_OPCODE) { + E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET); + } + + /* Perform the flash update */ + E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD); + + for (i=0; i < attempts; i++) { + eecd = E1000_READ_REG(hw, EECD); + if ((eecd & E1000_EECD_FLUPD) == 0) { + break; + } + udelay(5); + } + + if (i == attempts) { + return -E1000_ERR_EEPROM; + } + } + + return error; +} + /****************************************************************************** * Reads the adapter's part number from the EEPROM * @@ -3911,6 +4367,7 @@ void e1000_init_rx_addrs(struct e1000_hw *hw) { uint32_t i; + uint32_t rar_num; DEBUGFUNC("e1000_init_rx_addrs"); @@ -3919,9 +4376,10 @@ e1000_init_rx_addrs(struct e1000_hw *hw) e1000_rar_set(hw, hw->mac_addr, 0); + rar_num = E1000_RAR_ENTRIES; /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); - for(i = 1; i < E1000_RAR_ENTRIES; i++) { + for(i = 1; i < rar_num; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); } @@ -3950,7 +4408,9 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, { uint32_t hash_value; uint32_t i; - + uint32_t num_rar_entry; + uint32_t num_mta_entry; + DEBUGFUNC("e1000_mc_addr_list_update"); /* Set the new number of MC addresses that we are being requested to use. */ @@ -3958,14 +4418,16 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); - for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) { + num_rar_entry = E1000_RAR_ENTRIES; + for(i = rar_used_count; i < num_rar_entry; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); } /* Clear the MTA */ DEBUGOUT(" Clearing MTA\n"); - for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + num_mta_entry = E1000_NUM_MTA_REGISTERS; + for(i = 0; i < num_mta_entry; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); } @@ -3989,7 +4451,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Place this multicast address in the RAR if there is room, * * else put it in the MTA */ - if(rar_used_count < E1000_RAR_ENTRIES) { + if (rar_used_count < num_rar_entry) { e1000_rar_set(hw, mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)), rar_used_count); @@ -4040,6 +4502,7 @@ e1000_hash_mc_addr(struct e1000_hw *hw, } hash_value &= 0xFFF; + return hash_value; } @@ -4144,12 +4607,33 @@ void e1000_clear_vfta(struct e1000_hw *hw) { uint32_t offset; - - for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) - E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0); + uint32_t vfta_value = 0; + uint32_t vfta_offset = 0; + uint32_t vfta_bit_in_reg = 0; + + if (hw->mac_type == e1000_82573) { + if (hw->mng_cookie.vlan_id != 0) { + /* The VFTA is a 4096b bit-field, each identifying a single VLAN + * ID. The following operations determine which 32b entry + * (i.e. offset) into the array we want to set the VLAN ID + * (i.e. bit) of the manageability unit. */ + vfta_offset = (hw->mng_cookie.vlan_id >> + E1000_VFTA_ENTRY_SHIFT) & + E1000_VFTA_ENTRY_MASK; + vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & + E1000_VFTA_ENTRY_BIT_SHIFT_MASK); + } + } + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + /* If the offset we want to clear is the same offset of the + * manageability VLAN ID, then clear all bits except that of the + * manageability unit */ + vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; + E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value); + } } -static int32_t +int32_t e1000_id_led_init(struct e1000_hw * hw) { uint32_t ledctl; @@ -4480,6 +4964,19 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, MGTPRC); temp = E1000_READ_REG(hw, MGTPDC); temp = E1000_READ_REG(hw, MGTPTC); + + if(hw->mac_type <= e1000_82547_rev_2) return; + + temp = E1000_READ_REG(hw, IAC); + temp = E1000_READ_REG(hw, ICRXOC); + temp = E1000_READ_REG(hw, ICRXPTC); + temp = E1000_READ_REG(hw, ICRXATC); + temp = E1000_READ_REG(hw, ICTXPTC); + temp = E1000_READ_REG(hw, ICTXATC); + temp = E1000_READ_REG(hw, ICTXQEC); + temp = E1000_READ_REG(hw, ICTXQMTC); + temp = E1000_READ_REG(hw, ICRXDMTC); + } /****************************************************************************** @@ -4646,6 +5143,11 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_speed = e1000_bus_speed_unknown; hw->bus_width = e1000_bus_width_unknown; break; + case e1000_82573: + hw->bus_type = e1000_bus_type_pci_express; + hw->bus_speed = e1000_bus_speed_2500; + hw->bus_width = e1000_bus_width_pciex_4; + break; default: status = E1000_READ_REG(hw, STATUS); hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ? @@ -4749,6 +5251,7 @@ e1000_get_cable_length(struct e1000_hw *hw, /* Use old method for Phy older than IGP */ if(hw->phy_type == e1000_phy_m88) { + ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if(ret_val) @@ -4865,7 +5368,8 @@ e1000_check_polarity(struct e1000_hw *hw, return ret_val; *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> M88E1000_PSSR_REV_POLARITY_SHIFT; - } else if(hw->phy_type == e1000_phy_igp) { + } else if(hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) { /* Read the Status register to check the speed */ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data); @@ -4917,7 +5421,8 @@ e1000_check_downshift(struct e1000_hw *hw) DEBUGFUNC("e1000_check_downshift"); - if(hw->phy_type == e1000_phy_igp) { + if(hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) { ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data); if(ret_val) @@ -4933,6 +5438,7 @@ e1000_check_downshift(struct e1000_hw *hw) hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> M88E1000_PSSR_DOWNSHIFT_SHIFT; } + return E1000_SUCCESS; } @@ -5047,7 +5553,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); ret_val = e1000_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); @@ -5071,7 +5577,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); /* Now enable the transmitter */ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data); @@ -5096,7 +5602,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); ret_val = e1000_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); @@ -5112,7 +5618,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); /* Now enable the transmitter */ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data); @@ -5187,22 +5693,36 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw, uint16_t phy_data; DEBUGFUNC("e1000_set_d3_lplu_state"); - if(!((hw->mac_type == e1000_82541_rev_2) || - (hw->mac_type == e1000_82547_rev_2))) + if(hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2) return E1000_SUCCESS; /* During driver activity LPLU should not be used or it will attain link * from the lowest speeds starting from 10Mbps. The capability is used for * Dx transitions and states */ - ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data); - if(ret_val) - return ret_val; - - if(!active) { - phy_data &= ~IGP01E1000_GMII_FLEX_SPD; - ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) { + ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data); + if(ret_val) + return ret_val; + } else { + ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); if(ret_val) return ret_val; + } + + if(!active) { + if(hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547_rev_2) { + phy_data &= ~IGP01E1000_GMII_FLEX_SPD; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(ret_val) + return ret_val; + } else { + phy_data &= ~IGP02E1000_PM_D3_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + phy_data); + if (ret_val) + return ret_val; + } /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during * Dx states where the power conservation is most important. During @@ -5236,11 +5756,105 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw, (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) || (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) { - phy_data |= IGP01E1000_GMII_FLEX_SPD; - ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547_rev_2) { + phy_data |= IGP01E1000_GMII_FLEX_SPD; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(ret_val) + return ret_val; + } else { + phy_data |= IGP02E1000_PM_D3_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + phy_data); + if (ret_val) + return ret_val; + } + + /* When LPLU is enabled we should disable SmartSpeed */ + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); + if(ret_val) + return ret_val; + + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); + if(ret_val) + return ret_val; + + } + return E1000_SUCCESS; +} + +/***************************************************************************** + * + * This function sets the lplu d0 state according to the active flag. When + * activating lplu this function also disables smart speed and vise versa. + * lplu will not be activated unless the device autonegotiation advertisment + * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes. + * hw: Struct containing variables accessed by shared code + * active - true to enable lplu false to disable lplu. + * + * returns: - E1000_ERR_PHY if fail to read/write the PHY + * E1000_SUCCESS at any other case. + * + ****************************************************************************/ + +int32_t +e1000_set_d0_lplu_state(struct e1000_hw *hw, + boolean_t active) +{ + int32_t ret_val; + uint16_t phy_data; + DEBUGFUNC("e1000_set_d0_lplu_state"); + + if(hw->mac_type <= e1000_82547_rev_2) + return E1000_SUCCESS; + + ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); if(ret_val) return ret_val; + if (!active) { + phy_data &= ~IGP02E1000_PM_D0_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); + if (ret_val) + return ret_val; + + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during + * Dx states where the power conservation is most important. During + * driver activity we should enable SmartSpeed, so performance is + * maintained. */ + if (hw->smart_speed == e1000_smart_speed_on) { + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data); + if(ret_val) + return ret_val; + + phy_data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data); + if(ret_val) + return ret_val; + } else if (hw->smart_speed == e1000_smart_speed_off) { + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data); + if(ret_val) + return ret_val; + } + + + } else { + + phy_data |= IGP02E1000_PM_D0_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); + if (ret_val) + return ret_val; + /* When LPLU is enabled we should disable SmartSpeed */ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); if(ret_val) @@ -5318,18 +5932,350 @@ e1000_set_vco_speed(struct e1000_hw *hw) return E1000_SUCCESS; } -static int32_t -e1000_polarity_reversal_workaround(struct e1000_hw *hw) -{ - int32_t ret_val; - uint16_t mii_status_reg; - uint16_t i; - /* Polarity reversal workaround for forced 10F/10H links. */ +/***************************************************************************** + * This function reads the cookie from ARC ram. + * + * returns: - E1000_SUCCESS . + ****************************************************************************/ +int32_t +e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer) +{ + uint8_t i; + uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET; + uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH; - /* Disable the transmitter on the PHY */ + length = (length >> 2); + offset = (offset >> 2); - ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); + for (i = 0; i < length; i++) { + *((uint32_t *) buffer + i) = + E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset + i); + } + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function checks whether the HOST IF is enabled for command operaton + * and also checks whether the previous command is completed. + * It busy waits in case of previous command is not completed. + * + * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or + * timeout + * - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_enable_host_if(struct e1000_hw * hw) +{ + uint32_t hicr; + uint8_t i; + + /* Check that the host interface is enabled. */ + hicr = E1000_READ_REG(hw, HICR); + if ((hicr & E1000_HICR_EN) == 0) { + DEBUGOUT("E1000_HOST_EN bit disabled.\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + /* check the previous command is completed */ + for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { + hicr = E1000_READ_REG(hw, HICR); + if (!(hicr & E1000_HICR_C)) + break; + msec_delay_irq(1); + } + + if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { + DEBUGOUT("Previous command timeout failed .\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + return E1000_SUCCESS; +} + +/***************************************************************************** + * This function writes the buffer content at the offset given on the host if. + * It also does alignment considerations to do the writes in most efficient way. + * Also fills up the sum of the buffer in *buffer parameter. + * + * returns - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_host_if_write(struct e1000_hw * hw, uint8_t *buffer, + uint16_t length, uint16_t offset, uint8_t *sum) +{ + uint8_t *tmp; + uint8_t *bufptr = buffer; + uint32_t data; + uint16_t remaining, i, j, prev_bytes; + + /* sum = only sum of the data and it is not checksum */ + + if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { + return -E1000_ERR_PARAM; + } + + tmp = (uint8_t *)&data; + prev_bytes = offset & 0x3; + offset &= 0xFFFC; + offset >>= 2; + + if (prev_bytes) { + data = E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset); + for (j = prev_bytes; j < sizeof(uint32_t); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset, data); + length -= j - prev_bytes; + offset++; + } + + remaining = length & 0x3; + length -= remaining; + + /* Calculate length in DWORDs */ + length >>= 2; + + /* The device driver writes the relevant command block into the + * ram area. */ + for (i = 0; i < length; i++) { + for (j = 0; j < sizeof(uint32_t); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data); + } + if (remaining) { + for (j = 0; j < sizeof(uint32_t); j++) { + if (j < remaining) + *(tmp + j) = *bufptr++; + else + *(tmp + j) = 0; + + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data); + } + + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function writes the command header after does the checksum calculation. + * + * returns - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_write_cmd_header(struct e1000_hw * hw, + struct e1000_host_mng_command_header * hdr) +{ + uint16_t i; + uint8_t sum; + uint8_t *buffer; + + /* Write the whole command header structure which includes sum of + * the buffer */ + + uint16_t length = sizeof(struct e1000_host_mng_command_header); + + sum = hdr->checksum; + hdr->checksum = 0; + + buffer = (uint8_t *) hdr; + i = length; + while(i--) + sum += buffer[i]; + + hdr->checksum = 0 - sum; + + length >>= 2; + /* The device driver writes the relevant command block into the ram area. */ + for (i = 0; i < length; i++) + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i)); + + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function indicates to ARC that a new command is pending which completes + * one write operation by the driver. + * + * returns - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_write_commit( + struct e1000_hw * hw) +{ + uint32_t hicr; + + hicr = E1000_READ_REG(hw, HICR); + /* Setting this bit tells the ARC that a new command is pending. */ + E1000_WRITE_REG(hw, HICR, hicr | E1000_HICR_C); + + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function checks the mode of the firmware. + * + * returns - TRUE when the mode is IAMT or FALSE. + ****************************************************************************/ +boolean_t +e1000_check_mng_mode( + struct e1000_hw *hw) +{ + uint32_t fwsm; + + fwsm = E1000_READ_REG(hw, FWSM); + + if((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) + return TRUE; + + return FALSE; +} + + +/***************************************************************************** + * This function writes the dhcp info . + ****************************************************************************/ +int32_t +e1000_mng_write_dhcp_info(struct e1000_hw * hw, uint8_t *buffer, + uint16_t length) +{ + int32_t ret_val; + struct e1000_host_mng_command_header hdr; + + hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; + hdr.command_length = length; + hdr.reserved1 = 0; + hdr.reserved2 = 0; + hdr.checksum = 0; + + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val == E1000_SUCCESS) { + ret_val = e1000_mng_host_if_write(hw, buffer, length, sizeof(hdr), + &(hdr.checksum)); + if (ret_val == E1000_SUCCESS) { + ret_val = e1000_mng_write_cmd_header(hw, &hdr); + if (ret_val == E1000_SUCCESS) + ret_val = e1000_mng_write_commit(hw); + } + } + return ret_val; +} + + +/***************************************************************************** + * This function calculates the checksum. + * + * returns - checksum of buffer contents. + ****************************************************************************/ +uint8_t +e1000_calculate_mng_checksum(char *buffer, uint32_t length) +{ + uint8_t sum = 0; + uint32_t i; + + if (!buffer) + return 0; + + for (i=0; i < length; i++) + sum += buffer[i]; + + return (uint8_t) (0 - sum); +} + +/***************************************************************************** + * This function checks whether tx pkt filtering needs to be enabled or not. + * + * returns - TRUE for packet filtering or FALSE. + ****************************************************************************/ +boolean_t +e1000_enable_tx_pkt_filtering(struct e1000_hw *hw) +{ + /* called in init as well as watchdog timer functions */ + + int32_t ret_val, checksum; + boolean_t tx_filter = FALSE; + struct e1000_host_mng_dhcp_cookie *hdr = &(hw->mng_cookie); + uint8_t *buffer = (uint8_t *) &(hw->mng_cookie); + + if (e1000_check_mng_mode(hw)) { + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val == E1000_SUCCESS) { + ret_val = e1000_host_if_read_cookie(hw, buffer); + if (ret_val == E1000_SUCCESS) { + checksum = hdr->checksum; + hdr->checksum = 0; + if ((hdr->signature == E1000_IAMT_SIGNATURE) && + checksum == e1000_calculate_mng_checksum((char *)buffer, + E1000_MNG_DHCP_COOKIE_LENGTH)) { + if (hdr->status & + E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT) + tx_filter = TRUE; + } else + tx_filter = TRUE; + } else + tx_filter = TRUE; + } + } + + hw->tx_pkt_filtering = tx_filter; + return tx_filter; +} + +/****************************************************************************** + * Verifies the hardware needs to allow ARPs to be processed by the host + * + * hw - Struct containing variables accessed by shared code + * + * returns: - TRUE/FALSE + * + *****************************************************************************/ +uint32_t +e1000_enable_mng_pass_thru(struct e1000_hw *hw) +{ + uint32_t manc; + uint32_t fwsm, factps; + + if (hw->asf_firmware_present) { + manc = E1000_READ_REG(hw, MANC); + + if (!(manc & E1000_MANC_RCV_TCO_EN) || + !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + return FALSE; + if (e1000_arc_subsystem_valid(hw) == TRUE) { + fwsm = E1000_READ_REG(hw, FWSM); + factps = E1000_READ_REG(hw, FACTPS); + + if (((fwsm & E1000_FWSM_MODE_MASK) == + (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) && + (factps & E1000_FACTPS_MNGCG)) + return TRUE; + } else + if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN)) + return TRUE; + } + return FALSE; +} + +static int32_t +e1000_polarity_reversal_workaround(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t mii_status_reg; + uint16_t i; + + /* Polarity reversal workaround for forced 10F/10H links. */ + + /* Disable the transmitter on the PHY */ + + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); if(ret_val) return ret_val; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF); @@ -5403,3 +6349,265 @@ e1000_polarity_reversal_workaround(struct e1000_hw *hw) return E1000_SUCCESS; } +/*************************************************************************** + * + * Disables PCI-Express master access. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - none. + * + ***************************************************************************/ +void +e1000_set_pci_express_master_disable(struct e1000_hw *hw) +{ + uint32_t ctrl; + + DEBUGFUNC("e1000_set_pci_express_master_disable"); + + if (hw->bus_type != e1000_bus_type_pci_express) + return; + + ctrl = E1000_READ_REG(hw, CTRL); + ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; + E1000_WRITE_REG(hw, CTRL, ctrl); +} + +/*************************************************************************** + * + * Enables PCI-Express master access. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - none. + * + ***************************************************************************/ +void +e1000_enable_pciex_master(struct e1000_hw *hw) +{ + uint32_t ctrl; + + DEBUGFUNC("e1000_enable_pciex_master"); + + if (hw->bus_type != e1000_bus_type_pci_express) + return; + + ctrl = E1000_READ_REG(hw, CTRL); + ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE; + E1000_WRITE_REG(hw, CTRL, ctrl); +} + +/******************************************************************************* + * + * Disables PCI-Express master access and verifies there are no pending requests + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_MASTER_REQUESTS_PENDING if master disable bit hasn't + * caused the master requests to be disabled. + * E1000_SUCCESS master requests disabled. + * + ******************************************************************************/ +int32_t +e1000_disable_pciex_master(struct e1000_hw *hw) +{ + int32_t timeout = MASTER_DISABLE_TIMEOUT; /* 80ms */ + + DEBUGFUNC("e1000_disable_pciex_master"); + + if (hw->bus_type != e1000_bus_type_pci_express) + return E1000_SUCCESS; + + e1000_set_pci_express_master_disable(hw); + + while(timeout) { + if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE)) + break; + else + udelay(100); + timeout--; + } + + if(!timeout) { + DEBUGOUT("Master requests are pending.\n"); + return -E1000_ERR_MASTER_REQUESTS_PENDING; + } + + return E1000_SUCCESS; +} + +/******************************************************************************* + * + * Check for EEPROM Auto Read bit done. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_RESET if fail to reset MAC + * E1000_SUCCESS at any other case. + * + ******************************************************************************/ +int32_t +e1000_get_auto_rd_done(struct e1000_hw *hw) +{ + int32_t timeout = AUTO_READ_DONE_TIMEOUT; + + DEBUGFUNC("e1000_get_auto_rd_done"); + + switch (hw->mac_type) { + default: + msec_delay(5); + break; + case e1000_82573: + while(timeout) { + if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; + else msec_delay(1); + timeout--; + } + + if(!timeout) { + DEBUGOUT("Auto read by HW from EEPROM has not completed.\n"); + return -E1000_ERR_RESET; + } + break; + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * Checks if the PHY configuration is done + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_RESET if fail to reset MAC + * E1000_SUCCESS at any other case. + * + ***************************************************************************/ +int32_t +e1000_get_phy_cfg_done(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_get_phy_cfg_done"); + + /* Simply wait for 10ms */ + msec_delay(10); + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Using the combination of SMBI and SWESMBI semaphore bits when resetting + * adapter or Eeprom access. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_EEPROM if fail to access EEPROM. + * E1000_SUCCESS at any other case. + * + ***************************************************************************/ +int32_t +e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) +{ + int32_t timeout; + uint32_t swsm; + + DEBUGFUNC("e1000_get_hw_eeprom_semaphore"); + + if(!hw->eeprom_semaphore_present) + return E1000_SUCCESS; + + + /* Get the FW semaphore. */ + timeout = hw->eeprom.word_size + 1; + while(timeout) { + swsm = E1000_READ_REG(hw, SWSM); + swsm |= E1000_SWSM_SWESMBI; + E1000_WRITE_REG(hw, SWSM, swsm); + /* if we managed to set the bit we got the semaphore. */ + swsm = E1000_READ_REG(hw, SWSM); + if(swsm & E1000_SWSM_SWESMBI) + break; + + udelay(50); + timeout--; + } + + if(!timeout) { + /* Release semaphores */ + e1000_put_hw_eeprom_semaphore(hw); + DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n"); + return -E1000_ERR_EEPROM; + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * This function clears HW semaphore bits. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - None. + * + ***************************************************************************/ +void +e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) +{ + uint32_t swsm; + + DEBUGFUNC("e1000_put_hw_eeprom_semaphore"); + + if(!hw->eeprom_semaphore_present) + return; + + swsm = E1000_READ_REG(hw, SWSM); + /* Release both semaphores. */ + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + E1000_WRITE_REG(hw, SWSM, swsm); +} + +/****************************************************************************** + * Checks if PHY reset is blocked due to SOL/IDER session, for example. + * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to + * the caller to figure out how to deal with it. + * + * hw - Struct containing variables accessed by shared code + * + * returns: - E1000_BLK_PHY_RESET + * E1000_SUCCESS + * + *****************************************************************************/ +int32_t +e1000_check_phy_reset_block(struct e1000_hw *hw) +{ + uint32_t manc = 0; + if(hw->mac_type > e1000_82547_rev_2) + manc = E1000_READ_REG(hw, MANC); + return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? + E1000_BLK_PHY_RESET : E1000_SUCCESS; +} + +uint8_t +e1000_arc_subsystem_valid(struct e1000_hw *hw) +{ + uint32_t fwsm; + + /* On 8257x silicon, registers in the range of 0x8800 - 0x8FFC + * may not be provided a DMA clock when no manageability features are + * enabled. We do not want to perform any reads/writes to these registers + * if this is the case. We read FWSM to determine the manageability mode. + */ + switch (hw->mac_type) { + case e1000_82573: + fwsm = E1000_READ_REG(hw, FWSM); + if((fwsm & E1000_FWSM_MODE_MASK) != 0) + return TRUE; + break; + default: + break; + } + return FALSE; +} + + + -- cgit v1.2.2