aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/drivers/net/e1000/e1000_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/drivers/net/e1000/e1000_hw.c')
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_hw.c156
1 files changed, 140 insertions, 16 deletions
diff --git a/gpxe/src/drivers/net/e1000/e1000_hw.c b/gpxe/src/drivers/net/e1000/e1000_hw.c
index 1054b90a..1871dfc9 100644
--- a/gpxe/src/drivers/net/e1000/e1000_hw.c
+++ b/gpxe/src/drivers/net/e1000/e1000_hw.c
@@ -26,6 +26,8 @@
*******************************************************************************/
+FILE_LICENCE ( GPL2_ONLY );
+
/* e1000_hw.c
* Shared functions for accessing and configuring the MAC
*/
@@ -417,6 +419,9 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_ICH8_IGP_M:
hw->mac_type = e1000_ich8lan;
break;
+ case E1000_DEV_ID_82576:
+ hw->mac_type = e1000_82576;
+ break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
@@ -424,6 +429,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
switch (hw->mac_type) {
case e1000_ich8lan:
+ case e1000_82576:
hw->swfwhw_semaphore_present = TRUE;
hw->asf_firmware_present = TRUE;
break;
@@ -502,6 +508,7 @@ e1000_set_media_type(struct e1000_hw *hw)
break;
case e1000_ich8lan:
case e1000_82573:
+ case e1000_82576:
/* The STATUS_TBIMODE bit is reserved or reused for the this
* device.
*/
@@ -721,6 +728,17 @@ e1000_reset_hw(struct e1000_hw *hw)
/* Clear any pending interrupt events. */
icr = E1000_READ_REG(hw, ICR);
+ if (hw->mac_type == e1000_82571 && hw->laa_is_present == TRUE) {
+ /*
+ * Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed, the actual LAA is in one of the RARs and no
+ * incoming packets directed to this port are dropped.
+ * Eventually the LAA will be in RAR[0] and RAR[14].
+ */
+ e1000_rar_set(hw, hw->mac_addr, E1000_RAR_ENTRIES - 1);
+ }
+
/* If MWI was previously enabled, reenable it. */
if (hw->mac_type == e1000_82542_rev2_0) {
if (hw->pci_cmd_word & PCI_COMMAND_INVALIDATE)
@@ -748,7 +766,8 @@ e1000_reset_hw(struct e1000_hw *hw)
static void
e1000_initialize_hardware_bits(struct e1000_hw *hw)
{
- if ((hw->mac_type >= e1000_82571) && (!hw->initialize_hw_bits_disable)) {
+ if ((hw->mac_type >= e1000_82571 && hw->mac_type < e1000_82576) &&
+ (!hw->initialize_hw_bits_disable)) {
/* Settings common to all PCI-express silicon */
uint32_t reg_ctrl, reg_ctrl_ext;
uint32_t reg_tarc0, reg_tarc1;
@@ -905,11 +924,27 @@ e1000_init_hw(struct e1000_hw *hw)
/* Disabling VLAN filtering. */
DEBUGOUT("Initializing the IEEE VLAN\n");
- /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
- if (hw->mac_type != e1000_ich8lan) {
+ switch (hw->mac_type) {
+ case e1000_ich8lan:
+ /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+ break;
+ case e1000_82576:
+ /* There is no need to clear vfta on 82576 if VLANs are not used.
+ * - IntelĀ® 82576 Gigabit Ethernet Controller Datasheet r2.41
+ * Section 8.10.19 Table Array - VFTA
+ *
+ * Setting VET may also be unnecessary, however the documentation
+ * isn't specific on this point. The value used here is as advised in
+ * - IntelĀ® 82576 Gigabit Ethernet Controller Datasheet r2.41
+ * Section 8.2.7 VLAN Ether Type - VET
+ */
+ E1000_WRITE_REG(hw, VET, ETHERNET_IEEE_VLAN_TYPE);
+ break;
+ default:
if (hw->mac_type < e1000_82545_rev_3)
E1000_WRITE_REG(hw, VET, 0);
e1000_clear_vfta(hw);
+ break;
}
/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
@@ -1475,9 +1510,13 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
return ret_val;
}
- /* Wait 15ms for MAC to configure PHY from eeprom settings */
- msleep(15);
- if (hw->mac_type != e1000_ich8lan) {
+ /*
+ * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+ * timeout issues when LFS is enabled.
+ */
+ msleep(100);
+
+ if (hw->mac_type != e1000_ich8lan && hw->mac_type != e1000_82576) {
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
@@ -3491,7 +3530,7 @@ e1000_read_phy_reg(struct e1000_hw *hw,
DEBUGFUNC("e1000_read_phy_reg");
- if ((hw->mac_type == e1000_80003es2lan) &&
+ if ((hw->mac_type == e1000_80003es2lan || hw->mac_type == e1000_82576) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
} else {
@@ -3629,7 +3668,7 @@ e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
DEBUGFUNC("e1000_write_phy_reg");
- if ((hw->mac_type == e1000_80003es2lan) &&
+ if ((hw->mac_type == e1000_80003es2lan || hw->mac_type == e1000_82576) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
} else {
@@ -3749,7 +3788,7 @@ e1000_read_kmrn_reg(struct e1000_hw *hw,
uint16_t swfw;
DEBUGFUNC("e1000_read_kmrn_reg");
- if ((hw->mac_type == e1000_80003es2lan) &&
+ if ((hw->mac_type == e1000_80003es2lan || hw->mac_type == e1000_82576) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
} else {
@@ -3782,7 +3821,7 @@ e1000_write_kmrn_reg(struct e1000_hw *hw,
uint16_t swfw;
DEBUGFUNC("e1000_write_kmrn_reg");
- if ((hw->mac_type == e1000_80003es2lan) &&
+ if ((hw->mac_type == e1000_80003es2lan || hw->mac_type == e1000_82576) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
} else {
@@ -3824,7 +3863,8 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
DEBUGOUT("Resetting Phy...\n");
if (hw->mac_type > e1000_82543) {
- if ((hw->mac_type == e1000_80003es2lan) &&
+ if ((hw->mac_type == e1000_80003es2lan ||
+ hw->mac_type == e1000_82576) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
} else {
@@ -4134,6 +4174,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
if (hw->phy_id == IFE_PLUS_E_PHY_ID) match = TRUE;
if (hw->phy_id == IFE_C_E_PHY_ID) match = TRUE;
break;
+ case e1000_82576:
+ match = TRUE;
+ break;
default:
DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
@@ -4607,6 +4650,38 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
break;
}
+ case e1000_82576:
+ {
+ uint16_t size;
+
+ 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 = FALSE;
+
+ size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ /*
+ * Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += EEPROM_WORD_SIZE_SHIFT;
+
+ /* EEPROM access above 16k is unsupported */
+ if (size > 14)
+ size = 14;
+ eeprom->word_size = 1 << size;
+
+ break;
+ }
default:
break;
}
@@ -5012,8 +5087,7 @@ e1000_read_eeprom(struct e1000_hw *hw,
* directly. In this case, we need to acquire the EEPROM so that
* FW or other port software does not interrupt.
*/
- if (e1000_is_onboard_nvm_eeprom(hw) == TRUE &&
- hw->eeprom.use_eerd == FALSE) {
+ if (hw->eeprom.use_eerd == FALSE && e1000_is_onboard_nvm_eeprom(hw)) {
/* Prepare the EEPROM for bit-bang reading */
if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
return -E1000_ERR_EEPROM;
@@ -5196,6 +5270,8 @@ e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
DEBUGFUNC("e1000_is_onboard_nvm_eeprom");
+ assert(hw->mac_type != e1000_82576);
+
if (hw->mac_type == e1000_ich8lan)
return FALSE;
@@ -5709,13 +5785,48 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
int32_t
e1000_read_mac_addr(struct e1000_hw * hw)
{
- uint16_t offset;
+ uint16_t offset, mac_addr_offset = 0;
uint16_t eeprom_data, i;
+ int32_t ret_val;
DEBUGFUNC("e1000_read_mac_addr");
+ if (hw->mac_type == e1000_82571) {
+ /* Check for an alternate MAC address. An alternate MAC
+ * address can be setup by pre-boot software and must be
+ * treated like a permanent address and must override the
+ * actual permanent MAC address.*/
+ ret_val = e1000_read_eeprom(hw, EEPROM_ALT_MAC_ADDR_PTR, 1,
+ &mac_addr_offset);
+ if (ret_val) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ if (mac_addr_offset == 0xFFFF)
+ mac_addr_offset = 0;
+
+ if (mac_addr_offset) {
+ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+ mac_addr_offset += NODE_ADDRESS_SIZE/sizeof(u16);
+
+ /* make sure we have a valid mac address here
+ * before using it */
+ ret_val = e1000_read_eeprom(hw, mac_addr_offset, 1,
+ &eeprom_data);
+ if (ret_val) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ if (eeprom_data & 0x0001)
+ mac_addr_offset = 0;
+ }
+
+ if (mac_addr_offset)
+ hw->laa_is_present = TRUE;
+ }
+
for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
- offset = i >> 1;
+ offset = mac_addr_offset + (i >> 1);
if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
@@ -5730,8 +5841,10 @@ e1000_read_mac_addr(struct e1000_hw * hw)
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82571:
+ case e1000_82576:
case e1000_80003es2lan:
- if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+ if (!mac_addr_offset &&
+ E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
hw->perm_mac_addr[5] ^= 0x01;
break;
}
@@ -5942,6 +6055,13 @@ e1000_rar_set(struct e1000_hw *hw,
case e1000_80003es2lan:
if (hw->leave_av_bit_off == TRUE)
break;
+ case e1000_82576:
+ /* If MAC address zero, no need to set the AV bit */
+ if (rar_low || rar_high)
+ rar_high |= E1000_RAH_AV;
+ // Only neded when Multiple Receive Queues are enabmed in MRQC
+ rar_high |= E1000_RAH_POOL_1;
+ break;
default:
/* Indicate to hardware the Address is Valid. */
rar_high |= E1000_RAH_AV;
@@ -6607,6 +6727,7 @@ e1000_get_bus_info(struct e1000_hw *hw)
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
+ case e1000_82576:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
ret_val = e1000_read_pcie_cap_reg(hw,
@@ -8025,6 +8146,7 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
case e1000_82573:
case e1000_80003es2lan:
case e1000_ich8lan:
+ case e1000_82576:
while (timeout) {
if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD)
break;
@@ -8070,6 +8192,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw)
mdelay(10);
break;
case e1000_80003es2lan:
+ case e1000_82576:
/* Separate *_CFG_DONE_* bit for each port */
if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1;
@@ -8280,6 +8403,7 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
+ case e1000_82576:
fwsm = E1000_READ_REG(hw, FWSM);
if ((fwsm & E1000_FWSM_MODE_MASK) != 0)
return TRUE;