summaryrefslogtreecommitdiffstats
path: root/sys/dev/em/if_em_fxhw.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/em/if_em_fxhw.c')
-rw-r--r--sys/dev/em/if_em_fxhw.c196
1 files changed, 121 insertions, 75 deletions
diff --git a/sys/dev/em/if_em_fxhw.c b/sys/dev/em/if_em_fxhw.c
index 04b6a72..71b7942 100644
--- a/sys/dev/em/if_em_fxhw.c
+++ b/sys/dev/em/if_em_fxhw.c
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright (c) 2001 Intel Corporation
+ Copyright (c) 2001-2002 Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms of the Software, with or
@@ -52,7 +52,7 @@ em_raise_clock(struct em_shared_adapter *shared,
uint32_t *eecd_reg)
{
/* Raise the clock input to the EEPROM (by setting the SK bit), and then
- * wait 50 microseconds.
+ * wait 50 microseconds.
*/
*eecd_reg = *eecd_reg | E1000_EECD_SK;
E1000_WRITE_REG(shared, EECD, *eecd_reg);
@@ -184,11 +184,11 @@ em_setup_eeprom(struct em_shared_adapter *shared)
eecd_reg = E1000_READ_REG(shared, EECD);
- /* Clear SK and DI */
+ /* Clear SK and DI */
eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI);
E1000_WRITE_REG(shared, EECD, eecd_reg);
- /* Set CS */
+ /* Set CS */
eecd_reg |= E1000_EECD_CS;
E1000_WRITE_REG(shared, EECD, eecd_reg);
return;
@@ -206,22 +206,22 @@ em_standby_eeprom(struct em_shared_adapter *shared)
eecd_reg = E1000_READ_REG(shared, EECD);
- /* Deselct EEPROM */
+ /* Deselct EEPROM */
eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK);
E1000_WRITE_REG(shared, EECD, eecd_reg);
usec_delay(50);
- /* Clock high */
+ /* Clock high */
eecd_reg |= E1000_EECD_SK;
E1000_WRITE_REG(shared, EECD, eecd_reg);
usec_delay(50);
- /* Select EEPROM */
+ /* Select EEPROM */
eecd_reg |= E1000_EECD_CS;
E1000_WRITE_REG(shared, EECD, eecd_reg);
usec_delay(50);
- /* Clock low */
+ /* Clock low */
eecd_reg &= ~E1000_EECD_SK;
E1000_WRITE_REG(shared, EECD, eecd_reg);
usec_delay(50);
@@ -240,12 +240,12 @@ em_clock_eeprom(struct em_shared_adapter *shared)
eecd_reg = E1000_READ_REG(shared, EECD);
- /* Rising edge of clock */
+ /* Rising edge of clock */
eecd_reg |= E1000_EECD_SK;
E1000_WRITE_REG(shared, EECD, eecd_reg);
usec_delay(50);
- /* Falling edge of clock */
+ /* Falling edge of clock */
eecd_reg &= ~E1000_EECD_SK;
E1000_WRITE_REG(shared, EECD, eecd_reg);
usec_delay(50);
@@ -347,33 +347,23 @@ em_force_mac_fc(struct em_shared_adapter *shared)
*/
switch (shared->fc) {
- case em_fc_none: /* 0 */
-
+ case em_fc_none:
ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
break;
-
- case em_fc_rx_pause: /* 1 */
-
+ case em_fc_rx_pause:
ctrl_reg &= (~E1000_CTRL_TFCE);
ctrl_reg |= E1000_CTRL_RFCE;
break;
-
- case em_fc_tx_pause: /* 2 */
-
+ case em_fc_tx_pause:
ctrl_reg &= (~E1000_CTRL_RFCE);
ctrl_reg |= E1000_CTRL_TFCE;
break;
-
- case em_fc_full: /* 3 */
-
+ case em_fc_full:
ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
break;
-
default:
-
DEBUGOUT("Flow control param set incorrectly\n");
ASSERT(0);
-
break;
}
@@ -397,6 +387,7 @@ em_adapter_stop(struct em_shared_adapter *shared)
#if DBG
uint32_t ctrl_reg;
#endif
+ uint32_t ctrl_ext_reg;
uint32_t icr_reg;
uint16_t pci_cmd_word;
@@ -435,7 +426,7 @@ em_adapter_stop(struct em_shared_adapter *shared)
* the global reset.
*/
E1000_WRITE_REG(shared, RCTL, 0);
- E1000_WRITE_REG(shared, TCTL, 0);
+ E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
/* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
shared->tbi_compatibility_on = FALSE;
@@ -460,6 +451,12 @@ em_adapter_stop(struct em_shared_adapter *shared)
ASSERT(!(ctrl_reg & E1000_CTRL_RST));
#endif
+ /* Force a reload from the EEPROM */
+ ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
+ ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
+ msec_delay(2);
+
/* Clear interrupt mask to stop board from generating interrupts */
DEBUGOUT("Masking off all interrupts\n");
E1000_WRITE_REG(shared, IMC, 0xffffffff);
@@ -567,12 +564,11 @@ em_init_hw(struct em_shared_adapter *shared)
* is no link.
*/
em_clear_hw_cntrs(shared);
-
- shared->large_eeprom = FALSE;
+
shared->low_profile = FALSE;
if(shared->mac_type == em_82544) {
- i = em_read_eeprom(shared, E1000_EEPROM_LED_LOGIC);
- if(i & E1000_EEPROM_SWDPIN0)
+ if(em_read_eeprom(shared, E1000_EEPROM_LED_LOGIC) &
+ E1000_EEPROM_SWDPIN0)
shared->low_profile = TRUE;
}
@@ -920,10 +916,10 @@ em_setup_fc_and_link(struct em_shared_adapter *shared)
* signal detection. So this should be done before em_setup_pcs_link()
* or em_phy_setup() is called.
*/
- if(shared->mac_type >= em_82543) {
+ if(shared->mac_type == em_82543) {
ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT)
<< SWDPIO__EXT_SHIFT);
- E1000_WRITE_REG(shared, CTRLEXT, ctrl_ext_reg);
+ E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
}
/* Call the necessary subroutine to configure the link. */
@@ -954,9 +950,9 @@ em_setup_fc_and_link(struct em_shared_adapter *shared)
E1000_WRITE_REG(shared, FCRTL, 0);
E1000_WRITE_REG(shared, FCRTH, 0);
} else {
- /* We need to set up the Receive Threshold high and low water
- * marks as well as (optionally) enabling the transmission of XON frames.
- */
+ /* We need to set up the Receive Threshold high and low water marks
+ * as well as (optionally) enabling the transmission of XON frames.
+ */
if(shared->fc_send_xon) {
E1000_WRITE_REG(shared, FCRTL,
(shared->fc_low_water | E1000_FCRTL_XONE));
@@ -1351,25 +1347,26 @@ em_check_for_link(struct em_shared_adapter *shared)
case M88E1000_12_PHY_ID:
case M88E1000_14_PHY_ID:
case M88E1000_I_PHY_ID:
- /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
- * have Si on board that is 82544 or newer, Auto
- * Speed Detection takes care of MAC speed/duplex
- * configuration. So we only need to configure Collision
- * Distance in the MAC. Otherwise, we need to force
- * speed/duplex on the MAC to the current PHY speed/duplex
- * settings.
- */
+ case M88E1011_I_PHY_ID:
+ /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
+ * have Si on board that is 82544 or newer, Auto
+ * Speed Detection takes care of MAC speed/duplex
+ * configuration. So we only need to configure Collision
+ * Distance in the MAC. Otherwise, we need to force
+ * speed/duplex on the MAC to the current PHY speed/duplex
+ * settings.
+ */
if(shared->mac_type >= em_82544) {
DEBUGOUT("CFL - Auto-Neg complete.");
DEBUGOUT("Configuring Collision Distance.");
em_config_collision_dist(shared);
} else {
- /* Read the Phy Specific Status register to get the
- * resolved speed/duplex settings. Then call
- * em_config_mac_to_phy which will retrieve
- * PHY register information and configure the MAC to
- * equal the negotiated speed/duplex.
- */
+ /* Read the Phy Specific Status register to get the
+ * resolved speed/duplex settings. Then call
+ * em_config_mac_to_phy which will retrieve
+ * PHY register information and configure the MAC to
+ * equal the negotiated speed/duplex.
+ */
phy_data = em_read_phy_reg(shared,
M88E1000_PHY_SPEC_STATUS);
@@ -1378,18 +1375,18 @@ em_check_for_link(struct em_shared_adapter *shared)
em_config_mac_to_phy(shared, phy_data);
}
- /* Configure Flow Control now that Auto-Neg has completed.
- * We need to first restore the users desired Flow
- * Control setting since we may have had to re-autoneg
- * with a different link partner.
- */
+ /* Configure Flow Control now that Auto-Neg has completed.
+ * We need to first restore the users desired Flow
+ * Control setting since we may have had to re-autoneg
+ * with a different link partner.
+ */
em_config_fc_after_link_up(shared);
break;
default:
DEBUGOUT("CFL - Invalid PHY detected.\r\n");
- } /* end switch statement */
+ } /* end switch statement */
/* At this point we know that we are on copper, link is up,
* and we are auto-neg'd. These are pre-conditions for checking
@@ -1484,7 +1481,7 @@ em_check_for_link(struct em_shared_adapter *shared)
}
return;
-} /* CheckForLink */
+}
/******************************************************************************
* Clears all hardware statistics counters.
@@ -1621,7 +1618,8 @@ em_get_speed_and_duplex(struct em_shared_adapter *shared,
#if DBG
if(shared->phy_id == M88E1000_12_PHY_ID ||
shared->phy_id == M88E1000_14_PHY_ID ||
- shared->phy_id == M88E1000_I_PHY_ID) {
+ shared->phy_id == M88E1000_I_PHY_ID ||
+ shared->phy_id == M88E1011_I_PHY_ID) {
/* read the phy specific status register */
phy_data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data);
@@ -1629,7 +1627,6 @@ em_get_speed_and_duplex(struct em_shared_adapter *shared,
DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data);
DEBUGOUT1("Device Status Reg contents = %x\n",
E1000_READ_REG(shared, STATUS));
- /* DisplayMiiContents(Adapter, (uint8_t)Adapter->PhyAddress); */
}
#endif
return;
@@ -1645,9 +1642,26 @@ uint16_t
em_read_eeprom(struct em_shared_adapter *shared,
uint16_t offset)
{
+ boolean_t large_eeprom = FALSE;
uint16_t data;
+ uint32_t eecd_reg;
+ uint32_t tmp = 0;
+ if((shared->mac_type > em_82544) &&
+ (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE;
+ /* Request EEPROM Access */
+ if(shared->mac_type > em_82544) {
+ E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ);
+ eecd_reg = E1000_READ_REG(shared, EECD);
+ while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) {
+ tmp++;
+ usec_delay(5);
+ eecd_reg = E1000_READ_REG(shared, EECD);
+ }
+ if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE);
+ }
+
/* Prepare the EEPROM for reading */
em_setup_eeprom(shared);
@@ -1656,17 +1670,21 @@ em_read_eeprom(struct em_shared_adapter *shared,
/* If we have a 256 word EEPROM, there are 8 address bits
* if we have a 64 word EEPROM, there are 6 address bits
*/
- if(shared->large_eeprom)
+ if(large_eeprom)
em_shift_out_bits(shared, offset, 8);
else
em_shift_out_bits(shared, offset, 6);
- /* Read the data */
+ /* Read the data */
data = em_shift_in_bits(shared);
- /* End this read operation */
+ /* End this read operation */
em_standby_eeprom(shared);
+ /* Stop requestiong EEPROM access */
+ if(shared->mac_type > em_82544)
+ E1000_WRITE_REG(shared, EECD, (uint32_t) 0);
+
return (data);
}
@@ -1732,47 +1750,75 @@ em_write_eeprom(struct em_shared_adapter *shared,
uint16_t offset,
uint16_t data)
{
+ boolean_t large_eeprom = FALSE;
+ uint32_t eecd_reg;
+ uint32_t tmp = 0;
+
+ if((shared->mac_type > em_82544) &&
+ (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE;
+
+ /* Request EEPROM Access */
+ if(shared->mac_type > em_82544) {
+ E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ);
+ eecd_reg = E1000_READ_REG(shared, EECD);
+ while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) {
+ tmp++;
+ usec_delay(5);
+ eecd_reg = E1000_READ_REG(shared, EECD);
+ }
+ if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE);
+ }
- /* Prepare the EEPROM for writing */
+ /* Prepare the EEPROM for writing */
em_setup_eeprom(shared);
- /* Send the 9-bit EWEN (write enable) command to the EEPROM (5-bit opcode
- * plus 4-bit dummy). This puts the EEPROM into write/erase mode.
+ /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable)
+ * command to the EEPROM (5-bit opcode plus 4/6-bit dummy).
+ * This puts the EEPROM into write/erase mode.
*/
em_shift_out_bits(shared, EEPROM_EWEN_OPCODE, 5);
- em_shift_out_bits(shared, 0, 4);
+ if(large_eeprom)
+ em_shift_out_bits(shared, 0, 6);
+ else
+ em_shift_out_bits(shared, 0, 4);
- /* Prepare the EEPROM */
+ /* Prepare the EEPROM */
em_standby_eeprom(shared);
- /* Send the Write command (3-bit opcode + addr) */
+ /* Send the Write command (3-bit opcode + addr) */
em_shift_out_bits(shared, EEPROM_WRITE_OPCODE, 3);
/* If we have a 256 word EEPROM, there are 8 address bits
* if we have a 64 word EEPROM, there are 6 address bits
*/
- if(shared->large_eeprom)
+ if(large_eeprom)
em_shift_out_bits(shared, offset, 8);
else
em_shift_out_bits(shared, offset, 6);
- /* Send the data */
+ /* Send the data */
em_shift_out_bits(shared, data, 16);
-
em_wait_eeprom_command(shared);
- /* Recover from write */
+ /* Recover from write */
em_standby_eeprom(shared);
- /* Send the 9-bit EWDS (write disable) command to the EEPROM (5-bit
- * opcode plus 4-bit dummy). This takes the EEPROM out of write/erase
- * mode.
+ /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable)
+ * command to the EEPROM (5-bit opcode plus 4/6-bit dummy).
+ * This takes the EEPROM out of write/erase mode.
*/
em_shift_out_bits(shared, EEPROM_EWDS_OPCODE, 5);
- em_shift_out_bits(shared, 0, 4);
+ if(large_eeprom)
+ em_shift_out_bits(shared, 0, 6);
+ else
+ em_shift_out_bits(shared, 0, 4);
- /* Done with writing */
+ /* Done with writing */
em_cleanup_eeprom(shared);
+ /* Stop requestiong EEPROM access */
+ if(shared->mac_type > em_82544)
+ E1000_WRITE_REG(shared, EECD, (uint32_t) 0);
+
return (TRUE);
}
OpenPOWER on IntegriCloud