On Tue, Nov 19, 2013 at 01:09:32AM +1100, Jonathan Gray wrote:
> On Sat, Nov 16, 2013 at 10:42:05AM +0100, Markus Hennecke wrote:
> > On Sat, 9 Nov 2013, Jonathan Gray wrote:
> > 
> > > This adds the initial bits for the i217/i218 PHY and the
> > > Lynx Point PCH found in Haswell systems.
> > > 
> > > Doesn't include the new workarounds yet and follows
> > > the pch2/82579 paths for now but this seems to be enough
> > > to make a desktop machine with I217-LM work
> > 
> > This fails for the I217-V with an EEPROM invalid checksum error:
> 
> Here is a revised diff with different eeprom bank logic
> from FreeBSD as suggested by Masanobu SAITOH:

And here is a version that should fix gigabit autoneg:

Index: if_em.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.c,v
retrieving revision 1.271
diff -u -p -r1.271 if_em.c
--- if_em.c     15 Nov 2013 14:53:03 -0000      1.271
+++ if_em.c     16 Nov 2013 09:35:41 -0000
@@ -130,6 +130,10 @@ const struct pci_matchid em_devices[] = 
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82578DM },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82579LM },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82579V },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I217_LM },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I217_V },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I218_LM },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I218_V },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_COPPER },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_FIBER },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_SERDES },
@@ -788,6 +792,7 @@ em_init(void *arg)
                break;
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                pba = E1000_PBA_26K;
                break;
        default:
@@ -1626,7 +1631,8 @@ em_allocate_pci_resources(struct em_soft
            sc->hw.mac_type == em_ich9lan ||
            sc->hw.mac_type == em_ich10lan ||
            sc->hw.mac_type == em_pchlan ||
-           sc->hw.mac_type == em_pch2lan) {
+           sc->hw.mac_type == em_pch2lan ||
+           sc->hw.mac_type == em_pch_lpt) {
                val = pci_conf_read(pa->pa_pc, pa->pa_tag, EM_FLASH);
                if (PCI_MAPREG_TYPE(val) != PCI_MAPREG_TYPE_MEM) {
                        printf(": flash is not mem space\n");
Index: if_em_hw.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.c,v
retrieving revision 1.73
diff -u -p -r1.73 if_em_hw.c
--- if_em_hw.c  7 Aug 2013 01:06:34 -0000       1.73
+++ if_em_hw.c  20 Nov 2013 03:32:03 -0000
@@ -179,6 +179,7 @@ int32_t             em_get_pcs_speed_and_duplex_825
     uint16_t *);
 int32_t                em_set_eee_i350(struct em_hw *);
 int32_t                em_set_eee_pchlan(struct em_hw *);
+int32_t                em_valid_nvm_bank_detect_ich8lan(struct em_hw *, 
uint32_t *);
 
 
 /* IGP cable length table */
@@ -255,6 +256,9 @@ em_set_phy_type(struct em_hw *hw)
        case I82579_E_PHY_ID:
                hw->phy_type = em_phy_82579;
                break;
+       case I217_E_PHY_ID:
+               hw->phy_type = em_phy_i217;
+               break;
        case I82580_I_PHY_ID:
        case I350_I_PHY_ID:
                hw->phy_type = em_phy_82580;
@@ -568,6 +572,12 @@ em_set_mac_type(struct em_hw *hw)
        case E1000_DEV_ID_PCH2_LV_V:
                hw->mac_type = em_pch2lan;
                break;
+       case E1000_DEV_ID_PCH_LPT_I217_LM:
+       case E1000_DEV_ID_PCH_LPT_I217_V:
+       case E1000_DEV_ID_PCH_LPTLP_I218_LM:
+       case E1000_DEV_ID_PCH_LPTLP_I218_V:
+               hw->mac_type = em_pch_lpt;
+               break;
        case E1000_DEV_ID_EP80579_LAN_1:
                hw->mac_type = em_icp_xxxx;
                hw->icp_xxxx_port_num = 0;
@@ -591,6 +601,7 @@ em_set_mac_type(struct em_hw *hw)
        case em_ich10lan:
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                hw->swfwhw_semaphore_present = TRUE;
                hw->asf_firmware_present = TRUE;
                break;
@@ -682,6 +693,7 @@ em_set_media_type(struct em_hw *hw)
                case em_ich10lan:
                case em_pchlan:
                case em_pch2lan:
+               case em_pch_lpt:
                case em_82573:
                case em_82574:
                        /*
@@ -838,6 +850,7 @@ em_reset_hw(struct em_hw *hw)
        case em_ich10lan:
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                if (!hw->phy_reset_disable &&
                    em_check_phy_reset_block(hw) == E1000_SUCCESS) {
                        /*
@@ -973,7 +986,8 @@ em_reset_hw(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                uint32_t kab = E1000_READ_REG(hw, KABGTXD);
                kab |= E1000_KABGTXD_BGSQLBIAS;
                E1000_WRITE_REG(hw, KABGTXD, kab);
@@ -1089,6 +1103,7 @@ em_initialize_hardware_bits(struct em_hw
                case em_ich10lan:
                case em_pchlan:
                case em_pch2lan:
+               case em_pch_lpt:
                        if (hw->mac_type == em_ich8lan)
                                /* Set TARC0 bits 29 and 28 */
                                reg_tarc0 |= 0x30000000;
@@ -1162,7 +1177,8 @@ em_init_hw(struct em_hw *hw)
        }
 
        if (hw->mac_type == em_pchlan ||
-               hw->mac_type == em_pch2lan) {
+               hw->mac_type == em_pch2lan ||
+               hw->mac_type == em_pch_lpt) {
                /*
                 * The MAC-PHY interconnect may still be in SMBus mode
                 * after Sx->S0.  Toggle the LANPHYPC Value bit to force
@@ -1224,7 +1240,8 @@ em_init_hw(struct em_hw *hw)
            hw->mac_type != em_ich9lan &&
            hw->mac_type != em_ich10lan &&
            hw->mac_type != em_pchlan &&
-           hw->mac_type != em_pch2lan) {
+           hw->mac_type != em_pch2lan &&
+           hw->mac_type != em_pch_lpt) {
                if (hw->mac_type < em_82545_rev_3)
                        E1000_WRITE_REG(hw, VET, 0);
                if (hw->mac_type == em_i350)
@@ -1261,7 +1278,8 @@ em_init_hw(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
        for (i = 0; i < mta_size; i++) {
                E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
@@ -1319,7 +1337,8 @@ em_init_hw(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                msec_delay(15);
 
         /*
@@ -1383,6 +1402,7 @@ em_init_hw(struct em_hw *hw)
        case em_ich10lan:
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                ctrl = E1000_READ_REG(hw, TXDCTL1);
                ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | 
                    E1000_TXDCTL_FULL_TX_DESC_WB;
@@ -1410,7 +1430,8 @@ em_init_hw(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                if (hw->mac_type == em_ich8lan)
                        snoop = PCI_EX_82566_SNOOP_ALL;
                else
@@ -1517,6 +1538,7 @@ em_setup_link(struct em_hw *hw)
                case em_ich10lan:
                case em_pchlan:
                case em_pch2lan:
+               case em_pch_lpt:
                case em_82573:
                case em_82574:
                        hw->fc = E1000_FC_FULL;
@@ -1609,7 +1631,8 @@ em_setup_link(struct em_hw *hw)
            hw->mac_type != em_ich9lan &&
            hw->mac_type != em_ich10lan &&
            hw->mac_type != em_pchlan &&
-           hw->mac_type != em_pch2lan) {
+           hw->mac_type != em_pch2lan &&
+           hw->mac_type != em_pch_lpt) {
                E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
                E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
                E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
@@ -1618,7 +1641,8 @@ em_setup_link(struct em_hw *hw)
 
        if (hw->phy_type == em_phy_82577 ||
            hw->phy_type == em_phy_82578 ||
-           hw->phy_type == em_phy_82579) {
+           hw->phy_type == em_phy_82579 ||
+           hw->phy_type == em_phy_i217) {
                E1000_WRITE_REG(hw, FCRTV_PCH, 0x1000);
                em_write_phy_reg(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27),
                    hw->fc_pause_time);
@@ -1969,7 +1993,8 @@ em_copper_link_igp_setup(struct em_hw *h
        }
        /* disable lplu d0 during driver init */
        if (hw->mac_type == em_pchlan ||
-               hw->mac_type == em_pch2lan)
+               hw->mac_type == em_pch2lan ||
+               hw->mac_type == em_pch_lpt)
                ret_val = em_set_lplu_state_pchlan(hw, FALSE);
        else
                ret_val = em_set_d0_lplu_state(hw, FALSE);
@@ -2240,7 +2265,8 @@ em_copper_link_mgp_setup(struct em_hw *h
 
        /* disable lplu d0 during driver init */
        if (hw->mac_type == em_pchlan ||
-               hw->mac_type == em_pch2lan)
+               hw->mac_type == em_pch2lan ||
+               hw->mac_type == em_pch_lpt)
                ret_val = em_set_lplu_state_pchlan(hw, FALSE);
 
        /* Enable CRS on TX. This must be set for half-duplex operation. */
@@ -2582,6 +2608,7 @@ em_setup_copper_link(struct em_hw *hw)
        case em_ich10lan:
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                /*
                 * Set the mac to wait the maximum time between each
                 * iteration and increase the max iterations when polling the
@@ -2641,7 +2668,8 @@ em_setup_copper_link(struct em_hw *hw)
                if (ret_val)
                        return ret_val;
        } else if (hw->phy_type == em_phy_82577 ||
-               hw->phy_type == em_phy_82579) {
+               hw->phy_type == em_phy_82579 ||
+               hw->phy_type == em_phy_i217) {
                ret_val = em_copper_link_82577_setup(hw);
                if (ret_val)
                        return ret_val;
@@ -3692,7 +3720,8 @@ em_check_for_link(struct em_hw *hw)
                        em_check_downshift(hw);
 
                        /* Enable/Disable EEE after link up */
-                       if (hw->mac_type == em_pch2lan) {
+                       if (hw->mac_type == em_pch2lan ||
+                           hw->mac_type == em_pch_lpt) {
                                ret_val = em_set_eee_pchlan(hw);
                                if (ret_val)
                                        return ret_val;
@@ -4476,7 +4505,8 @@ em_read_phy_reg(struct em_hw *hw, uint32
        DEBUGFUNC("em_read_phy_reg");
 
        if (hw->mac_type == em_pchlan ||
-               hw->mac_type == em_pch2lan)
+               hw->mac_type == em_pch2lan ||
+               hw->mac_type == em_pch_lpt)
                return (em_access_phy_reg_hv(hw, reg_addr, phy_data, TRUE));
 
        if (((hw->mac_type == em_80003es2lan) || (hw->mac_type == em_82575)) &&
@@ -4589,7 +4619,7 @@ em_read_phy_reg_ex(struct em_hw *hw, uin
                }
                *phy_data = (uint16_t) mdic;
 
-               if (hw->mac_type == em_pch2lan)
+               if (hw->mac_type == em_pch2lan || hw->mac_type == em_pch_lpt)
                        usec_delay(100);
        } else {
                /*
@@ -4639,7 +4669,8 @@ em_write_phy_reg(struct em_hw *hw, uint3
        DEBUGFUNC("em_write_phy_reg");
 
        if (hw->mac_type == em_pchlan ||
-               hw->mac_type == em_pch2lan)
+               hw->mac_type == em_pch2lan ||
+               hw->mac_type == em_pch_lpt)
                return (em_access_phy_reg_hv(hw, reg_addr, &phy_data, FALSE));
 
        if (em_swfw_sync_acquire(hw, hw->swfw))
@@ -4739,7 +4770,7 @@ em_write_phy_reg_ex(struct em_hw *hw, ui
                        return -E1000_ERR_PHY;
                }
 
-               if (hw->mac_type == em_pch2lan)
+               if (hw->mac_type == em_pch2lan || hw->mac_type == em_pch_lpt)
                        usec_delay(100);
        } else {
                /*
@@ -4918,14 +4949,14 @@ em_oem_bits_config_pchlan(struct em_hw *
        uint16_t oem_reg;
        uint16_t swfw = E1000_SWFW_PHY0_SM;
 
-       if ((hw->mac_type != em_pchlan) && (hw->mac_type != em_pch2lan))
+       if (hw->mac_type < em_pchlan)
                return ret_val;
 
        ret_val = em_swfw_sync_acquire(hw, swfw);
        if (ret_val)
                return ret_val;
 
-       if (hw->mac_type != em_pch2lan) {
+       if (hw->mac_type == em_pchlan) {
                mac_reg = E1000_READ_REG(hw, EXTCNF_CTRL);
                if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
                        goto out;
@@ -5019,31 +5050,30 @@ em_phy_reset(struct em_hw *hw)
        /* Allow time for h/w to get to a quiescent state after reset */
        msec_delay(10);
 
-       if (hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2) {
+       if (hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2)
                em_phy_init_script(hw);
-       } else if (hw->mac_type == em_pchlan) {
-               ret_val = em_hv_phy_workarounds_ich8lan(hw);
-               if (ret_val)
-                       return ret_val;
 
-               ret_val = em_oem_bits_config_pchlan(hw, TRUE);
+       if (hw->mac_type == em_pchlan) {
+               ret_val = em_hv_phy_workarounds_ich8lan(hw);
                if (ret_val)
                        return ret_val;
-
        } else if (hw->mac_type == em_pch2lan) {
                ret_val = em_lv_phy_workarounds_ich8lan(hw);
                if (ret_val)
                        return ret_val;
-
+       }
+       
+       if (hw->mac_type >= em_pchlan) {
                ret_val = em_oem_bits_config_pchlan(hw, TRUE);
                if (ret_val)
                        return ret_val;
+       }
 
-               /* Ungate automatic PHY configuration on non-managed 82579 */
-               if  (!(E1000_READ_REG(hw, FWSM) & E1000_FWSM_FW_VALID)) {
-                       msec_delay(10);
-                       em_gate_hw_phy_config_ich8lan(hw, FALSE);
-               }
+       /* Ungate automatic PHY configuration on non-managed 82579 */
+       if ((hw->mac_type == em_pch2lan) &&
+           !(E1000_READ_REG(hw, FWSM) & E1000_FWSM_FW_VALID)) {
+               msec_delay(10);
+               em_gate_hw_phy_config_ich8lan(hw, FALSE);
        }
 
        return E1000_SUCCESS;
@@ -5215,6 +5245,10 @@ em_match_gig_phy(struct em_hw *hw)
                if (hw->phy_id == I82579_E_PHY_ID)
                        match = TRUE;
                break;
+       case em_pch_lpt:
+               if (hw->phy_id == I217_E_PHY_ID)
+                       match = TRUE;
+               break;
        case em_icp_xxxx:
                if (hw->phy_id == M88E1141_E_PHY_ID)
                        match = TRUE;
@@ -5495,6 +5529,7 @@ em_init_eeprom_params(struct em_hw *hw)
        case em_ich10lan:
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                {
                int32_t         i = 0;
                uint32_t        flash_size = 
@@ -6119,7 +6154,8 @@ em_is_onboard_nvm_eeprom(struct em_hw *h
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                return FALSE;
 
        if ((hw->mac_type == em_82573) || (hw->mac_type == em_82574)) {
@@ -6184,17 +6220,31 @@ em_validate_eeprom_checksum(struct em_hw
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
+               uint16_t word;
+               uint16_t valid_csum_mask;
+               
                /*
                 * Drivers must allocate the shadow ram structure for the
                 * EEPROM checksum to be updated.  Otherwise, this bit as
                 * well as the checksum must both be set correctly for this
                 * validation to pass.
                 */
-               em_read_eeprom(hw, 0x19, 1, &eeprom_data);
-               if ((eeprom_data & 0x40) == 0) {
-                       eeprom_data |= 0x40;
-                       em_write_eeprom(hw, 0x19, 1, &eeprom_data);
+               switch (hw->mac_type) {
+               case em_pch_lpt:
+                       word = EEPROM_COMPAT;
+                       valid_csum_mask = EEPROM_COMPAT_VALID_CSUM;
+                       break;
+               default:
+                       word = EEPROM_FUTURE_INIT_WORD1;
+                       valid_csum_mask = EEPROM_FUTURE_INIT_WORD1_VALID_CSUM;
+                       break;
+               }
+               em_read_eeprom(hw, word, 1, &eeprom_data);
+               if ((eeprom_data & valid_csum_mask) == 0) {
+                       eeprom_data |= valid_csum_mask;
+                       em_write_eeprom(hw, word, 1, &eeprom_data);
                        em_update_eeprom_checksum(hw);
                }
        }
@@ -6602,7 +6652,7 @@ em_commit_shadow_ram(struct em_hw *hw)
                                 * in progress
                                 */
                                if (i == E1000_ICH_NVM_SIG_WORD)
-                                       high_byte = E1000_ICH_NVM_SIG_MASK |
+                                       high_byte = 
E1000_ICH_NVM_VALID_SIG_MASK |
                                            high_byte;
 
                                error = em_verify_write_ich8_byte(hw, (i << 1)
@@ -6771,7 +6821,8 @@ em_init_rx_addrs(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                rar_num = E1000_RAR_ENTRIES_ICH8LAN;
        if (hw->mac_type == em_ich8lan)
                rar_num -= 1;
@@ -6826,7 +6877,8 @@ em_mc_addr_list_update(struct em_hw *hw,
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN;
        if (hw->mac_type == em_ich8lan)
                num_rar_entry -= 1;
@@ -6852,7 +6904,8 @@ em_mc_addr_list_update(struct em_hw *hw,
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN;
 
        for (i = 0; i < num_mta_entry; i++) {
@@ -6915,7 +6968,8 @@ em_hash_mc_addr(struct em_hw *hw, uint8_
                    hw->mac_type == em_ich9lan ||
                    hw->mac_type == em_ich10lan ||
                    hw->mac_type == em_pchlan ||
-                   hw->mac_type == em_pch2lan) {
+                   hw->mac_type == em_pch2lan ||
+                   hw->mac_type == em_pch_lpt) {
                        /* [47:38] i.e. 0x158 for above example address */
                        hash_value = ((mc_addr[4] >> 6) | 
                            (((uint16_t) mc_addr[5]) << 2));
@@ -6930,7 +6984,8 @@ em_hash_mc_addr(struct em_hw *hw, uint8_
                    hw->mac_type == em_ich9lan ||
                    hw->mac_type == em_ich10lan ||
                    hw->mac_type == em_pchlan ||
-                   hw->mac_type == em_pch2lan) {
+                   hw->mac_type == em_pch2lan ||
+                   hw->mac_type == em_pch_lpt) {
                        /* [46:37] i.e. 0x2B1 for above example address */
                        hash_value = ((mc_addr[4] >> 5) |
                            (((uint16_t) mc_addr[5]) << 3));
@@ -6945,7 +7000,8 @@ em_hash_mc_addr(struct em_hw *hw, uint8_
                    hw->mac_type == em_ich9lan ||
                    hw->mac_type == em_ich10lan ||
                    hw->mac_type == em_pchlan ||
-                   hw->mac_type == em_pch2lan) {
+                   hw->mac_type == em_pch2lan ||
+                   hw->mac_type == em_pch_lpt) {
                        /* [45:36] i.e. 0x163 for above example address */
                        hash_value = ((mc_addr[4] >> 4) |
                            (((uint16_t) mc_addr[5]) << 4));
@@ -6960,7 +7016,8 @@ em_hash_mc_addr(struct em_hw *hw, uint8_
                    hw->mac_type == em_ich9lan ||
                    hw->mac_type == em_ich10lan ||
                    hw->mac_type == em_pchlan ||
-                   hw->mac_type == em_pch2lan) {
+                   hw->mac_type == em_pch2lan ||
+                   hw->mac_type == em_pch_lpt) {
                        /* [43:34] i.e. 0x18D for above example address */
                        hash_value = ((mc_addr[4] >> 2) |
                            (((uint16_t) mc_addr[5]) << 6));
@@ -6977,7 +7034,8 @@ em_hash_mc_addr(struct em_hw *hw, uint8_
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                hash_value &= 0x3FF;
 
        return hash_value;
@@ -7009,7 +7067,8 @@ em_mta_set(struct em_hw *hw, uint32_t ha
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                hash_reg &= 0x1F;
 
        hash_bit = hash_value & 0x1F;
@@ -7104,7 +7163,8 @@ em_clear_vfta(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                return;
 
        if ((hw->mac_type == em_82573) || (hw->mac_type == em_82574)) {
@@ -7259,7 +7319,8 @@ em_clear_hw_cntrs(struct em_hw *hw)
            hw->mac_type != em_ich9lan &&
            hw->mac_type != em_ich10lan &&
            hw->mac_type != em_pchlan &&
-           hw->mac_type != em_pch2lan) {
+           hw->mac_type != em_pch2lan &&
+           hw->mac_type != em_pch_lpt) {
                temp = E1000_READ_REG(hw, PRC64);
                temp = E1000_READ_REG(hw, PRC127);
                temp = E1000_READ_REG(hw, PRC255);
@@ -7291,7 +7352,8 @@ em_clear_hw_cntrs(struct em_hw *hw)
            hw->mac_type != em_ich9lan &&
            hw->mac_type != em_ich10lan &&
            hw->mac_type != em_pchlan &&
-           hw->mac_type != em_pch2lan) {
+           hw->mac_type != em_pch2lan &&
+           hw->mac_type != em_pch_lpt) {
                temp = E1000_READ_REG(hw, PTC64);
                temp = E1000_READ_REG(hw, PTC127);
                temp = E1000_READ_REG(hw, PTC255);
@@ -7328,7 +7390,8 @@ em_clear_hw_cntrs(struct em_hw *hw)
 
        if (hw->phy_type == em_phy_82577 ||
            hw->phy_type == em_phy_82578 ||
-           hw->phy_type == em_phy_82579) {
+           hw->phy_type == em_phy_82579 ||
+           hw->phy_type == em_phy_i217) {
                uint16_t phy_data;
 
                em_read_phy_reg(hw, HV_SCC_UPPER, &phy_data);
@@ -7351,7 +7414,7 @@ em_clear_hw_cntrs(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type != em_pch2lan)
+           (hw->mac_type != em_pch2lan && hw->mac_type != em_pch_lpt))
                return;
 
        temp = E1000_READ_REG(hw, ICRXPTC);
@@ -7491,6 +7554,7 @@ em_get_bus_info(struct em_hw *hw)
        case em_ich10lan:
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                hw->bus_type = em_bus_type_pci_express;
                hw->bus_speed = em_bus_speed_2500;
                hw->bus_width = em_bus_width_pciex_1;
@@ -8066,7 +8130,8 @@ em_set_d3_lplu_state(struct em_hw *hw, b
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                /*
                 * MAC writes into PHY register based on the state transition
                 * and start auto-negotiation. SW driver can overwrite the
@@ -8093,7 +8158,8 @@ em_set_d3_lplu_state(struct em_hw *hw, b
                            hw->mac_type == em_ich9lan ||
                            hw->mac_type == em_ich10lan ||
                            hw->mac_type == em_pchlan ||
-                           hw->mac_type == em_pch2lan) {
+                           hw->mac_type == em_pch2lan ||
+                           hw->mac_type == em_pch_lpt) {
                                phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
                                E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
                        } else {
@@ -8149,7 +8215,8 @@ em_set_d3_lplu_state(struct em_hw *hw, b
                            hw->mac_type == em_ich9lan ||
                            hw->mac_type == em_ich10lan ||
                            hw->mac_type == em_pchlan ||
-                           hw->mac_type == em_pch2lan) {
+                           hw->mac_type == em_pch2lan ||
+                           hw->mac_type == em_pch_lpt) {
                                phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
                                E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
                        } else {
@@ -8205,7 +8272,8 @@ em_set_d0_lplu_state(struct em_hw *hw, b
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
        } else {
                ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
@@ -8219,7 +8287,8 @@ em_set_d0_lplu_state(struct em_hw *hw, b
                    hw->mac_type == em_ich9lan ||
                    hw->mac_type == em_ich10lan ||
                    hw->mac_type == em_pchlan ||
-                   hw->mac_type == em_pch2lan) {
+                   hw->mac_type == em_pch2lan ||
+                   hw->mac_type == em_pch_lpt) {
                        phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
                        E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
                } else {
@@ -8263,7 +8332,8 @@ em_set_d0_lplu_state(struct em_hw *hw, b
                    hw->mac_type == em_ich9lan ||
                    hw->mac_type == em_ich10lan ||
                    hw->mac_type == em_pchlan ||
-                   hw->mac_type == em_pch2lan) {
+                   hw->mac_type == em_pch2lan ||
+                   hw->mac_type == em_pch_lpt) {
                        phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
                        E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
                } else {
@@ -8456,7 +8526,8 @@ em_check_mng_mode(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                if ((fwsm & E1000_FWSM_MODE_MASK) ==
                    (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
                        return TRUE;
@@ -8705,6 +8776,7 @@ em_get_auto_rd_done(struct em_hw *hw)
        case em_ich10lan:
        case em_pchlan:
        case em_pch2lan:
+       case em_pch_lpt:
                while (timeout) {
                        if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD)
                                break;
@@ -8944,7 +9016,8 @@ em_check_phy_reset_block(struct em_hw *h
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                fwsm = E1000_READ_REG(hw, FWSM);
                return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS :
                    E1000_BLK_PHY_RESET;
@@ -8986,7 +9059,8 @@ em_set_pci_ex_no_snoop(struct em_hw *hw,
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                uint32_t ctrl_ext;
                ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
                ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
@@ -9015,7 +9089,8 @@ em_get_software_flag(struct em_hw *hw)
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                while (timeout) {
                        extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
                        extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
@@ -9055,7 +9130,8 @@ em_release_software_flag(struct em_hw *h
            hw->mac_type == em_ich9lan ||
            hw->mac_type == em_ich10lan ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan) {
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt) {
                extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
                extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
                E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
@@ -9063,6 +9139,72 @@ em_release_software_flag(struct em_hw *h
        return;
 }
 
+/**
+ *  em_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
+ *  @hw: pointer to the HW structure
+ *  @bank:  pointer to the variable that returns the active bank
+ *
+ *  Reads signature byte from the NVM using the flash access registers.
+ *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
+ **/
+int32_t
+em_valid_nvm_bank_detect_ich8lan(struct em_hw *hw, uint32_t *bank)
+{
+       uint32_t eecd;
+       uint32_t bank1_offset = hw->flash_bank_size * sizeof(uint16_t);
+       uint32_t act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+       uint8_t sig_byte = 0;
+       int32_t ret_val;
+
+       DEBUGFUNC("em_valid_nvm_bank_detect_ich8lan");
+
+       switch (hw->mac_type) {
+       case em_ich8lan:
+       case em_ich9lan:
+               eecd = E1000_READ_REG(hw, EECD);
+               if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
+                   E1000_EECD_SEC1VAL_VALID_MASK) {
+                       if (eecd & E1000_EECD_SEC1VAL)
+                               *bank = 1;
+                       else
+                               *bank = 0;
+
+                       return E1000_SUCCESS;
+               }
+               DEBUGOUT("Unable to determine valid NVM bank via EEC - reading 
flash signature\n");
+               /* fall-thru */
+       default:
+               /* set bank to 0 in case flash read fails */
+               *bank = 0;
+
+               /* Check bank 0 */
+               ret_val = em_read_ich8_byte(hw, act_offset,
+                                                       &sig_byte);
+               if (ret_val)
+                       return ret_val;
+               if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+                   E1000_ICH_NVM_SIG_VALUE) {
+                       *bank = 0;
+                       return E1000_SUCCESS;
+               }
+
+               /* Check bank 1 */
+               ret_val = em_read_ich8_byte(hw, act_offset +
+                                                       bank1_offset,
+                                                       &sig_byte);
+               if (ret_val)
+                       return ret_val;
+               if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+                   E1000_ICH_NVM_SIG_VALUE) {
+                       *bank = 1;
+                       return E1000_SUCCESS;
+               }
+
+               DEBUGOUT("ERROR: No valid NVM bank present\n");
+               return -1;
+       }
+}
+
 /******************************************************************************
  * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
  * register.
@@ -9088,18 +9230,23 @@ em_read_eeprom_ich8(struct em_hw *hw, ui
         * flash_bank.  So it cannot be trusted and needs to be updated with
         * each read.
         */
-       /* Value of bit 22 corresponds to the flash bank we're on. */
-       flash_bank = (E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL) ? 1 : 0;
+
+       error = em_get_software_flag(hw);
+       if (error != E1000_SUCCESS)
+               return error;
+
+       error = em_valid_nvm_bank_detect_ich8lan(hw, &flash_bank);
+       if (error != E1000_SUCCESS) {
+               DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+               flash_bank = 0;
+       }
+
        /*
         * Adjust offset appropriately if we're on bank 1 - adjust for word
         * size
         */
        bank_offset = flash_bank * (hw->flash_bank_size * 2);
 
-       error = em_get_software_flag(hw);
-       if (error != E1000_SUCCESS)
-               return error;
-
        for (i = 0; i < words; i++) {
                if (hw->eeprom_shadow_ram != NULL &&
                    hw->eeprom_shadow_ram[offset + i].modified == TRUE) {
@@ -9744,7 +9891,8 @@ em_init_lcd_from_nvm(struct em_hw *hw)
        if (hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT ||
            hw->device_id == E1000_DEV_ID_ICH8_IGP_M ||
            hw->mac_type == em_pchlan ||
-           hw->mac_type == em_pch2lan)
+           hw->mac_type == em_pch2lan ||
+           hw->mac_type == em_pch_lpt)
                sw_cfg_mask = FEXTNVM_SW_CONFIG_ICH8M;
        else
                sw_cfg_mask = FEXTNVM_SW_CONFIG;
@@ -10321,7 +10469,8 @@ em_set_eee_pchlan(struct em_hw *hw)
 
        DEBUGFUNC("em_set_eee_pchlan");
 
-       if (hw->phy_type != em_phy_82579)
+       if (hw->phy_type != em_phy_82579 &&
+          hw->phy_type != em_phy_i217)
                goto out;
 
        ret_val = em_read_phy_reg(hw, I82579_LPI_CTRL, &phy_reg);
Index: if_em_hw.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.h,v
retrieving revision 1.54
diff -u -p -r1.54 if_em_hw.h
--- if_em_hw.h  26 Nov 2012 01:17:41 -0000      1.54
+++ if_em_hw.h  18 Nov 2013 13:37:19 -0000
@@ -78,6 +78,7 @@ typedef enum {
     em_ich10lan,
     em_pchlan,
     em_pch2lan,
+    em_pch_lpt,
     em_num_macs
 } em_mac_type;
 
@@ -242,6 +243,7 @@ typedef enum {
     em_phy_82577,
     em_phy_82578,
     em_phy_82579,
+    em_phy_i217,
     em_phy_82580,
     em_phy_undefined = 0xFF
 } em_phy_type;
@@ -536,6 +538,10 @@ int32_t em_check_phy_reset_block(struct 
 #define E1000_DEV_ID_PCH_D_HV_DC         0x10F0
 #define E1000_DEV_ID_PCH2_LV_LM          0x1502
 #define E1000_DEV_ID_PCH2_LV_V           0x1503
+#define E1000_DEV_ID_PCH_LPT_I217_LM     0x153A
+#define E1000_DEV_ID_PCH_LPT_I217_V      0x153B
+#define E1000_DEV_ID_PCH_LPTLP_I218_LM   0x155A
+#define E1000_DEV_ID_PCH_LPTLP_I218_V    0x1559
 #define E1000_DEV_ID_82575EB_PT          0x10A7
 #define E1000_DEV_ID_82575EB_PF          0x10A9
 #define E1000_DEV_ID_82575GB_QP          0x10D6
@@ -1698,13 +1704,16 @@ struct em_hw {
 #define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
 #define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
 #define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SEC1VAL_VALID_MASK   (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
 #define E1000_EECD_SECVAL_SHIFT      22
 #define E1000_STM_OPCODE     0xDB00
 #define E1000_HICR_FW_RESET  0xC0
 
-#define E1000_SHADOW_RAM_WORDS     2048
-#define E1000_ICH_NVM_SIG_WORD     0x13
-#define E1000_ICH_NVM_SIG_MASK     0xC0
+#define E1000_SHADOW_RAM_WORDS         2048
+#define E1000_ICH_NVM_SIG_WORD         0x13
+#define E1000_ICH_NVM_SIG_MASK         0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK   0xC0
+#define E1000_ICH_NVM_SIG_VALUE                0x80
 
 /* EEPROM Read */
 #define E1000_EERD_START      0x00000001 /* Start Read */
@@ -2443,6 +2452,10 @@ struct em_host_command_info {
 #define EEPROM_FLASH_VERSION          0x0032
 #define EEPROM_CHECKSUM_REG           0x003F
 
+#define EEPROM_COMPAT_VALID_CSUM      0x0001
+#define EEPROM_FUTURE_INIT_WORD1      0x0019
+#define EEPROM_FUTURE_INIT_WORD1_VALID_CSUM     0x0040
+
 #define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
 #define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
 #define E1000_NVM_CFG_DONE_PORT_2  0x100000 /* ...for third port */
@@ -3360,6 +3373,7 @@ struct em_host_command_info {
 #define I82577_E_PHY_ID      0x01540050
 #define I82578_E_PHY_ID      0x004DD040
 #define I82579_E_PHY_ID      0x01540090
+#define I217_E_PHY_ID        0x015400A0
 #define I82580_I_PHY_ID      0x015403A0
 #define I350_I_PHY_ID        0x015403B0
 #define IGP04E1000_E_PHY_ID  0x02A80391

Reply via email to