diff options
Diffstat (limited to 'drivers/net/e1000.c')
-rw-r--r-- | drivers/net/e1000.c | 294 |
1 files changed, 274 insertions, 20 deletions
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 875682b1b89..8316854bc17 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -150,6 +150,7 @@ static int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #ifndef CONFIG_E1000_NO_NVM static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw); +static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw); static int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data); @@ -861,6 +862,174 @@ e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, return E1000_SUCCESS; } +#ifndef CONFIG_DM_ETH +/****************************************************************************** + * e1000_write_eeprom_srwr - Write to Shadow Ram using EEWR + * @hw: pointer to the HW structure + * @offset: offset within the Shadow Ram to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the Shadow Ram + * + * Writes data to Shadow Ram at offset using EEWR register. + * + * If e1000_update_eeprom_checksum_i210 is not called after this function, the + * Shadow Ram will most likely contain an invalid checksum. + *****************************************************************************/ +static int32_t e1000_write_eeprom_srwr(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data) +{ + struct e1000_eeprom_info *eeprom = &hw->eeprom; + uint32_t i, k, eewr = 0; + uint32_t attempts = 100000; + int32_t ret_val = 0; + + /* A check for invalid values: offset too large, too many words, + * too many words for the offset, and not enough words. + */ + if ((offset >= eeprom->word_size) || + (words > (eeprom->word_size - offset)) || (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_EEPROM; + goto out; + } + + for (i = 0; i < words; i++) { + eewr = ((offset + i) << E1000_EEPROM_RW_ADDR_SHIFT) + | (data[i] << E1000_EEPROM_RW_REG_DATA) | + E1000_EEPROM_RW_REG_START; + + E1000_WRITE_REG(hw, I210_EEWR, eewr); + + for (k = 0; k < attempts; k++) { + if (E1000_EEPROM_RW_REG_DONE & + E1000_READ_REG(hw, I210_EEWR)) { + ret_val = 0; + break; + } + udelay(5); + } + + if (ret_val) { + DEBUGOUT("Shadow RAM write EEWR timed out\n"); + break; + } + } + +out: + return ret_val; +} + +/****************************************************************************** + * e1000_pool_flash_update_done_i210 - Pool FLUDONE status. + * @hw: pointer to the HW structure + * + *****************************************************************************/ +static int32_t e1000_pool_flash_update_done_i210(struct e1000_hw *hw) +{ + int32_t ret_val = -E1000_ERR_EEPROM; + uint32_t i, reg; + + for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) { + reg = E1000_READ_REG(hw, EECD); + if (reg & E1000_EECD_FLUDONE_I210) { + ret_val = 0; + break; + } + udelay(5); + } + + return ret_val; +} + +/****************************************************************************** + * e1000_update_flash_i210 - Commit EEPROM to the flash + * @hw: pointer to the HW structure + * + *****************************************************************************/ +static int32_t e1000_update_flash_i210(struct e1000_hw *hw) +{ + int32_t ret_val = 0; + uint32_t flup; + + ret_val = e1000_pool_flash_update_done_i210(hw); + if (ret_val == -E1000_ERR_EEPROM) { + DEBUGOUT("Flash update time out\n"); + goto out; + } + + flup = E1000_READ_REG(hw, EECD) | E1000_EECD_FLUPD_I210; + E1000_WRITE_REG(hw, EECD, flup); + + ret_val = e1000_pool_flash_update_done_i210(hw); + if (ret_val) + DEBUGOUT("Flash update time out\n"); + else + DEBUGOUT("Flash update complete\n"); + +out: + return ret_val; +} + +/****************************************************************************** + * e1000_update_eeprom_checksum_i210 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. Next commit EEPROM data onto the Flash. + *****************************************************************************/ +static int32_t e1000_update_eeprom_checksum_i210(struct e1000_hw *hw) +{ + int32_t ret_val = 0; + uint16_t checksum = 0; + uint16_t i, nvm_data; + + /* Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + ret_val = e1000_read_eeprom_eerd(hw, 0, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("EEPROM read failed\n"); + goto out; + } + + if (!(e1000_get_hw_eeprom_semaphore(hw))) { + /* Do not use hw->nvm.ops.write, hw->nvm.ops.read + * because we do not want to take the synchronization + * semaphores twice here. + */ + + for (i = 0; i < EEPROM_CHECKSUM_REG; i++) { + ret_val = e1000_read_eeprom_eerd(hw, i, 1, &nvm_data); + if (ret_val) { + e1000_put_hw_eeprom_semaphore(hw); + DEBUGOUT("EEPROM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (uint16_t)EEPROM_SUM - checksum; + ret_val = e1000_write_eeprom_srwr(hw, EEPROM_CHECKSUM_REG, 1, + &checksum); + if (ret_val) { + e1000_put_hw_eeprom_semaphore(hw); + DEBUGOUT("EEPROM Write Error while updating checksum.\n"); + goto out; + } + + e1000_put_hw_eeprom_semaphore(hw); + + ret_val = e1000_update_flash_i210(hw); + } else { + ret_val = -E1000_ERR_SWFW_SYNC; + } + +out: + return ret_val; +} +#endif + /****************************************************************************** * Verifies that the EEPROM has a valid checksum * @@ -970,7 +1139,7 @@ e1000_get_software_semaphore(struct e1000_hw *hw) DEBUGFUNC(); - if (hw->mac_type != e1000_80003es2lan) + if (hw->mac_type != e1000_80003es2lan && hw->mac_type != e1000_igb) return E1000_SUCCESS; while (timeout) { @@ -1044,7 +1213,7 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) if (!hw->eeprom_semaphore_present) return E1000_SUCCESS; - if (hw->mac_type == e1000_80003es2lan) { + if (hw->mac_type == e1000_80003es2lan || hw->mac_type == e1000_igb) { /* Get the SW semaphore. */ if (e1000_get_software_semaphore(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; @@ -1144,33 +1313,21 @@ static bool e1000_is_second_port(struct e1000_hw *hw) #ifndef CONFIG_E1000_NO_NVM /****************************************************************************** - * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the - * second function of dual function devices + * Reads the adapter's MAC address from the EEPROM * - * nic - Struct containing variables accessed by shared code + * hw - Struct containing variables accessed by shared code + * enetaddr - buffering where the MAC address will be stored *****************************************************************************/ -static int -e1000_read_mac_addr(struct e1000_hw *hw, unsigned char enetaddr[6]) +static int e1000_read_mac_addr_from_eeprom(struct e1000_hw *hw, + unsigned char enetaddr[6]) { uint16_t offset; uint16_t eeprom_data; - uint32_t reg_data = 0; int i; - DEBUGFUNC(); - for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) { offset = i >> 1; - if (hw->mac_type == e1000_igb) { - /* i210 preloads MAC address into RAL/RAH registers */ - if (offset == 0) - reg_data = E1000_READ_REG_ARRAY(hw, RA, 0); - else if (offset == 1) - reg_data >>= 16; - else if (offset == 2) - reg_data = E1000_READ_REG_ARRAY(hw, RA, 1); - eeprom_data = reg_data & 0xffff; - } else if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { + if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -1178,6 +1335,63 @@ e1000_read_mac_addr(struct e1000_hw *hw, unsigned char enetaddr[6]) enetaddr[i + 1] = (eeprom_data >> 8) & 0xff; } + return 0; +} + +/****************************************************************************** + * Reads the adapter's MAC address from the RAL/RAH registers + * + * hw - Struct containing variables accessed by shared code + * enetaddr - buffering where the MAC address will be stored + *****************************************************************************/ +static int e1000_read_mac_addr_from_regs(struct e1000_hw *hw, + unsigned char enetaddr[6]) +{ + uint16_t offset, tmp; + uint32_t reg_data = 0; + int i; + + if (hw->mac_type != e1000_igb) + return -E1000_ERR_MAC_TYPE; + + for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) { + offset = i >> 1; + + if (offset == 0) + reg_data = E1000_READ_REG_ARRAY(hw, RA, 0); + else if (offset == 1) + reg_data >>= 16; + else if (offset == 2) + reg_data = E1000_READ_REG_ARRAY(hw, RA, 1); + tmp = reg_data & 0xffff; + + enetaddr[i] = tmp & 0xff; + enetaddr[i + 1] = (tmp >> 8) & 0xff; + } + + return 0; +} + +/****************************************************************************** + * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the + * second function of dual function devices + * + * hw - Struct containing variables accessed by shared code + * enetaddr - buffering where the MAC address will be stored + *****************************************************************************/ +static int e1000_read_mac_addr(struct e1000_hw *hw, unsigned char enetaddr[6]) +{ + int ret_val; + + if (hw->mac_type == e1000_igb) { + /* i210 preloads MAC address into RAL/RAH registers */ + ret_val = e1000_read_mac_addr_from_regs(hw, enetaddr); + } else { + ret_val = e1000_read_mac_addr_from_eeprom(hw, enetaddr); + } + if (ret_val) + return ret_val; + /* Invert the last bit if this is the second device */ if (e1000_is_second_port(hw)) enetaddr[5] ^= 1; @@ -5435,6 +5649,45 @@ e1000_poll(struct eth_device *nic) return len ? 1 : 0; } +static int e1000_write_hwaddr(struct eth_device *dev) +{ +#ifndef CONFIG_E1000_NO_NVM + unsigned char *mac = dev->enetaddr; + unsigned char current_mac[6]; + struct e1000_hw *hw = dev->priv; + uint16_t data[3]; + int ret_val, i; + + DEBUGOUT("%s: mac=%pM\n", __func__, mac); + + memset(current_mac, 0, 6); + + /* Read from EEPROM, not from registers, to make sure + * the address is persistently configured + */ + ret_val = e1000_read_mac_addr_from_eeprom(hw, current_mac); + DEBUGOUT("%s: current mac=%pM\n", __func__, current_mac); + + /* Only write to EEPROM if the given address is different or + * reading the current address failed + */ + if (!ret_val && memcmp(current_mac, mac, 6) == 0) + return 0; + + for (i = 0; i < 3; ++i) + data[i] = mac[i * 2 + 1] << 8 | mac[i * 2]; + + ret_val = e1000_write_eeprom_srwr(hw, 0x0, 3, data); + + if (!ret_val) + ret_val = e1000_update_eeprom_checksum_i210(hw); + + return ret_val; +#else + return 0; +#endif +} + /************************************************************************** PROBE - Look for an adapter, this routine's visible to the outside You should omit the last argument struct pci_device * for a non-PCI NIC @@ -5484,6 +5737,7 @@ e1000_initialize(bd_t * bis) nic->recv = e1000_poll; nic->send = e1000_transmit; nic->halt = e1000_disable; + nic->write_hwaddr = e1000_write_hwaddr; eth_register(nic); } |