diff options
author | pdeuskar <pdeuskar@FreeBSD.org> | 2003-08-27 21:52:37 +0000 |
---|---|---|
committer | pdeuskar <pdeuskar@FreeBSD.org> | 2003-08-27 21:52:37 +0000 |
commit | a6edff558778b89807d7ea0cbdeca912d30c0947 (patch) | |
tree | ce908ffb0bfff042753843ad1101e8dac4bc56f9 /sys/dev/em | |
parent | 4b97db330469200d4110c50337c8cbede767ba90 (diff) | |
download | FreeBSD-src-a6edff558778b89807d7ea0cbdeca912d30c0947.zip FreeBSD-src-a6edff558778b89807d7ea0cbdeca912d30c0947.tar.gz |
Add support for new devices.
Bug Fixes:
- Allow users to use LAA
- Remember promiscuous mode settings while bridging
- Allow gratuitous arp's to be sent
PR: 52966/54488
MFC after: 1 week
Diffstat (limited to 'sys/dev/em')
-rw-r--r-- | sys/dev/em/README | 52 | ||||
-rw-r--r-- | sys/dev/em/if_em.c | 187 | ||||
-rw-r--r-- | sys/dev/em/if_em.h | 51 | ||||
-rw-r--r-- | sys/dev/em/if_em_hw.c | 2116 | ||||
-rw-r--r-- | sys/dev/em/if_em_hw.h | 422 |
5 files changed, 1871 insertions, 957 deletions
diff --git a/sys/dev/em/README b/sys/dev/em/README index 2f0556e..5f4f715 100644 --- a/sys/dev/em/README +++ b/sys/dev/em/README @@ -2,7 +2,7 @@ $FreeBSD$ FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters ============================================================ -April 13, 2003 +July 24, 2003 Contents @@ -21,7 +21,7 @@ Contents Overview ======== -This file describes the FreeBSD* driver, version 1.5.x, for the Intel(R) +This file describes the FreeBSD* driver, version 1.7.x, for the Intel(R) PRO/1000 Family of Adapters. This driver has been developed for use with FreeBSD, version 4.7. @@ -51,9 +51,10 @@ release: 82544 PRO/1000 XF Server Adapter A50484-xxx 82544 PRO/1000 T Desktop Adapter A62947-xxx - + 82540 PRO/1000 MT Desktop Adapter A78408-xxx - 82541 C91016-xxx + + 82541 PRO/1000 MT Desktop Adapter C91016-xxx 82545 PRO/1000 MT Server Adapter A92165-xxx @@ -67,6 +68,7 @@ release: 82546EB PRO/1000 MT Quad Port Server Adapter C11227-xxx + 82547 PRO/1000 CT Network Connection To verify your Intel adapter is supported, find the board ID number on the @@ -281,8 +283,46 @@ Supported Adapters section. Known Limitations ================= -There are known performance issues with this driver when running UDP traffic -with Jumbo Frames. Intel recommends not using Jumbo Frames for UDP traffic. + There are known performance issues with this driver when running UDP traffic + with Jumbo Frames. Intel recommends not using Jumbo Frames for UDP traffic. + + + 82541/82547 can't link or is slow to link with some link partners + ----------------------------------------------------------------- + + There is a known compatibility issue with 82541/82547 and some switches + where link will not be established, or will be slow to establish. In + particular, these switches are known to be incompatible with 82541/82547: + + Planex FXG-08TE + I-O Data ETG-SH8 + + To workaround the issue, the driver can be compiled with an override of the + PHY's master/slave setting. Forcing master or forcing slave mode will + improve time-to-link. + + Edit ./em.x.x.x/src/if_em.h to remove the #define EM_MASTER_SLAVE + from within the comments. + + /* #define EM_MASTER_SLAVE 2 */ + #define EM_MASTER_SLAVE 2 + + Use one of the following options. + 0 = Hardware default + 1 = Master mode + 2 = Slave mode + 3 = Auto master/slave + + Recompile the module (refer to step 3 above) + a. To compile the module + + cd em-x.x.x + make clean + make + + b. To install the compiled module in system directory: + + make install Support diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index dd89589..984f757 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -51,7 +51,7 @@ struct adapter *em_adapter_list = NULL; * Driver version *********************************************************************/ -char em_driver_version[] = "1.6.6"; +char em_driver_version[] = "1.7.16"; /********************************************************************* @@ -89,6 +89,16 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, 0x101A, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} }; @@ -163,6 +173,9 @@ static void em_print_debug_info(struct adapter *); static int em_is_valid_ether_addr(u_int8_t *); static int em_sysctl_stats(SYSCTL_HANDLER_ARGS); static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); +static u_int32_t em_fill_descriptors (u_int64_t address, + u_int32_t length, + PDESC_ARRAY desc_array); static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); static void em_add_int_delay_sysctl(struct adapter *, const char *, const char *, struct em_int_delay_info *, @@ -367,7 +380,13 @@ em_attach(device_t dev) adapter->hw.fc = em_fc_full; adapter->hw.phy_init_script = 1; + adapter->hw.phy_reset_disable = FALSE; +#ifndef EM_MASTER_SLAVE + adapter->hw.master_slave = em_ms_hw_default; +#else + adapter->hw.master_slave = EM_MASTER_SLAVE; +#endif /* * Set the max frame size assuming standard ethernet * sized frames @@ -465,6 +484,15 @@ em_attach(device_t dev) } else printf("em%d: Speed:N/A Duplex:N/A\n", adapter->unit); + /* Identify 82544 on PCIX */ + em_get_bus_info(&adapter->hw); + if(adapter->hw.bus_type == em_bus_type_pcix && + adapter->hw.mac_type == em_82544) { + adapter->pcix_82544 = TRUE; + } + else { + adapter->pcix_82544 = FALSE; + } INIT_DEBUGOUT("em_attach: end"); splx(s); return(0); @@ -525,6 +553,9 @@ em_detach(device_t dev) adapter->rx_desc_base = NULL; } + /* Free the sysctl tree */ + sysctl_ctx_free(&adapter->sysctl_ctx); + /* Remove from the adapter list */ if (em_adapter_list == adapter) em_adapter_list = adapter->next; @@ -641,8 +672,11 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) case SIOCSIFFLAGS: IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_flags & IFF_RUNNING)) + if (!(ifp->if_flags & IFF_RUNNING)) { + bcopy(IF_LLADDR(ifp), adapter->hw.mac_addr, + ETHER_ADDR_LEN); em_init(adapter); + } em_disable_promisc(adapter); em_set_promisc(adapter); @@ -685,7 +719,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } break; default: - IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%d)\n", (int)command); + IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)\n", (int)command); error = EINVAL; } @@ -1052,9 +1086,15 @@ static int em_encap(struct adapter *adapter, struct mbuf *m_head) { u_int32_t txd_upper; - u_int32_t txd_lower; + u_int32_t txd_lower, txd_used = 0, txd_saved = 0; int i, j, error; - + u_int64_t address; + + /* For 82544 Workaround */ + DESC_ARRAY desc_array; + u_int32_t array_elements; + u_int32_t counter; + #if __FreeBSD_version < 500000 struct ifvlan *ifv = NULL; #else @@ -1118,23 +1158,66 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) #endif i = adapter->next_avail_tx_desc; + if (adapter->pcix_82544) { + txd_saved = i; + txd_used = 0; + } for (j = 0; j < q.nsegs; j++) { - tx_buffer = &adapter->tx_buffer_area[i]; - current_tx_desc = &adapter->tx_desc_base[i]; + /* If adapter is 82544 and on PCIX bus */ + if(adapter->pcix_82544) { + array_elements = 0; + address = htole64(q.segs[j].ds_addr); + /* + * Check the Address and Length combination and + * split the data accordingly + */ + array_elements = em_fill_descriptors(address, + htole32(q.segs[j].ds_len), + &desc_array); + for (counter = 0; counter < array_elements; counter++) { + if (txd_used == adapter->num_tx_desc_avail) { + adapter->next_avail_tx_desc = txd_saved; + adapter->no_tx_desc_avail2++; + bus_dmamap_destroy(adapter->txtag, q.map); + return (ENOBUFS); + } + tx_buffer = &adapter->tx_buffer_area[i]; + current_tx_desc = &adapter->tx_desc_base[i]; + current_tx_desc->buffer_addr = htole64( + desc_array.descriptor[counter].address); + current_tx_desc->lower.data = htole32( + (adapter->txd_cmd | txd_lower | + (u_int16_t)desc_array.descriptor[counter].length)); + current_tx_desc->upper.data = htole32((txd_upper)); + if (++i == adapter->num_tx_desc) + i = 0; + + tx_buffer->m_head = NULL; + txd_used++; + } + } else { + tx_buffer = &adapter->tx_buffer_area[i]; + current_tx_desc = &adapter->tx_desc_base[i]; - current_tx_desc->buffer_addr = htole64(q.segs[j].ds_addr); - current_tx_desc->lower.data = htole32( - adapter->txd_cmd | txd_lower | q.segs[j].ds_len); - current_tx_desc->upper.data = htole32(txd_upper); + current_tx_desc->buffer_addr = htole64(q.segs[j].ds_addr); + current_tx_desc->lower.data = htole32( + adapter->txd_cmd | txd_lower | q.segs[j].ds_len); + current_tx_desc->upper.data = htole32(txd_upper); - if (++i == adapter->num_tx_desc) - i = 0; + if (++i == adapter->num_tx_desc) + i = 0; - tx_buffer->m_head = NULL; + tx_buffer->m_head = NULL; + } } - adapter->num_tx_desc_avail -= q.nsegs; - adapter->next_avail_tx_desc = i; + adapter->next_avail_tx_desc = i; + if (adapter->pcix_82544) { + adapter->num_tx_desc_avail -= txd_used; + } + else { + adapter->num_tx_desc_avail -= q.nsegs; + } #if __FreeBSD_version < 500000 if (ifv != NULL) { @@ -1474,7 +1557,7 @@ em_stop(void *arg) struct adapter * adapter = arg; ifp = &adapter->interface_data.ac_if; - INIT_DEBUGOUT("em_stop: begin\n"); + INIT_DEBUGOUT("em_stop: begin"); em_disable_intr(adapter); em_reset_hw(&adapter->hw); untimeout(em_local_timer, adapter, adapter->timer_handle); @@ -1522,6 +1605,12 @@ em_identify_hardware(struct adapter * adapter) /* Identify the MAC */ if (em_set_mac_type(&adapter->hw)) printf("em%d: Unknown MAC Type\n", adapter->unit); + + if(adapter->hw.mac_type == em_82541 || + adapter->hw.mac_type == em_82541_rev_2 || + adapter->hw.mac_type == em_82547 || + adapter->hw.mac_type == em_82547_rev_2) + adapter->hw.phy_init_script = TRUE; return; } @@ -1629,6 +1718,7 @@ em_free_pci_resources(struct adapter * adapter) static int em_hardware_init(struct adapter * adapter) { + INIT_DEBUGOUT("em_hardware_init: begin"); /* Issue a global reset */ em_reset_hw(&adapter->hw); @@ -1984,6 +2074,7 @@ em_initialize_transmit_unit(struct adapter * adapter) u_int32_t reg_tipg = 0; u_int64_t bus_addr; + INIT_DEBUGOUT("em_initialize_transmit_unit: begin"); /* Setup the Base and Length of the Tx Descriptor Ring */ bus_addr = adapter->txdma.dma_paddr; E1000_WRITE_REG(&adapter->hw, TDBAL, (u_int32_t)bus_addr); @@ -2399,6 +2490,7 @@ em_initialize_receive_unit(struct adapter * adapter) struct ifnet *ifp; u_int64_t bus_addr; + INIT_DEBUGOUT("em_initialize_receive_unit: begin"); ifp = &adapter->interface_data.ac_if; /* Make sure receives are disabled while setting up the descriptor ring */ @@ -2469,6 +2561,7 @@ em_initialize_receive_unit(struct adapter * adapter) /* Enable Receives */ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + em_set_promisc(adapter); return; } @@ -2805,6 +2898,59 @@ em_io_write(struct em_hw *hw, uint32_t port, uint32_t value) return; } +/********************************************************************* +* 82544 Coexistence issue workaround. +* There are 2 issues. +* 1. Transmit Hang issue. +* To detect this issue, following equation can be used... +* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. +* If SUM[3:0] is in between 1 to 4, we will have this issue. +* +* 2. DAC issue. +* To detect this issue, following equation can be used... +* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. +* If SUM[3:0] is in between 9 to c, we will have this issue. +* +* +* WORKAROUND: +* Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC) +* +*** *********************************************************************/ +static u_int32_t +em_fill_descriptors (u_int64_t address, + u_int32_t length, + PDESC_ARRAY desc_array) +{ + /* Since issue is sensitive to length and address.*/ + /* Let us first check the address...*/ + u_int32_t safe_terminator; + if (length <= 4) { + desc_array->descriptor[0].address = address; + desc_array->descriptor[0].length = length; + desc_array->elements = 1; + return desc_array->elements; + } + safe_terminator = (u_int32_t)((((u_int32_t)address & 0x7) + (length & 0xF)) & 0xF); + /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */ + if (safe_terminator == 0 || + (safe_terminator > 4 && + safe_terminator < 9) || + (safe_terminator > 0xC && + safe_terminator <= 0xF)) { + desc_array->descriptor[0].address = address; + desc_array->descriptor[0].length = length; + desc_array->elements = 1; + return desc_array->elements; + } + + desc_array->descriptor[0].address = address; + desc_array->descriptor[0].length = length - 4; + desc_array->descriptor[1].address = address + (length - 4); + desc_array->descriptor[1].length = 4; + desc_array->elements = 2; + return desc_array->elements; +} + /********************************************************************** * * Update the board statistics counters. @@ -2815,8 +2961,12 @@ em_update_stats_counters(struct adapter *adapter) { struct ifnet *ifp; + if(adapter->hw.media_type == em_media_type_copper || + (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { + adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS); + adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC); + } adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, CRCERRS); - adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS); adapter->stats.mpc += E1000_READ_REG(&adapter->hw, MPC); adapter->stats.scc += E1000_READ_REG(&adapter->hw, SCC); adapter->stats.ecol += E1000_READ_REG(&adapter->hw, ECOL); @@ -2825,7 +2975,6 @@ em_update_stats_counters(struct adapter *adapter) adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL); adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC); adapter->stats.dc += E1000_READ_REG(&adapter->hw, DC); - adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC); adapter->stats.rlec += E1000_READ_REG(&adapter->hw, RLEC); adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, XONRXC); adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, XONTXC); diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h index 7ed3ef3..10183ab 100644 --- a/sys/dev/em/if_em.h +++ b/sys/dev/em/if_em.h @@ -81,7 +81,7 @@ POSSIBILITY OF SUCH DAMAGE. /* Tunables */ /* - * TxDescriptors + * EM_MAX_TXD: Maximum number of Transmit Descriptors * Valid Range: 80-256 for 82542 and 82543-based adapters * 80-4096 for others * Default Value: 256 @@ -92,7 +92,7 @@ POSSIBILITY OF SUCH DAMAGE. #define EM_MAX_TXD 256 /* - * RxDescriptors + * EM_MAX_RXD - Maximum number of receive Descriptors * Valid Range: 80-256 for 82542 and 82543-based adapters * 80-4096 for others * Default Value: 256 @@ -105,7 +105,7 @@ POSSIBILITY OF SUCH DAMAGE. #define EM_MAX_RXD 256 /* - * TxIntDelay + * EM_TIDV - Transmit Interrupt Delay Value * Valid Range: 0-65535 (0=off) * Default Value: 64 * This value delays the generation of transmit interrupts in units of @@ -117,20 +117,20 @@ POSSIBILITY OF SUCH DAMAGE. #define EM_TIDV 64 /* - * TxAbsIntDelay (Not valid for 82542/82543/82544) + * EM_TADV - Transmit Absolute Interrupt Delay Value (Not valid for 82542/82543/82544) * Valid Range: 0-65535 (0=off) * Default Value: 64 * This value, in units of 1.024 microseconds, limits the delay in which a - * transmit interrupt is generated. Useful only if TxIntDelay is non-zero, + * transmit interrupt is generated. Useful only if EM_TIDV is non-zero, * this value ensures that an interrupt is generated after the initial * packet is sent on the wire within the set amount of time. Proper tuning, - * along with TxIntDelay, may improve traffic throughput in specific + * along with EM_TIDV, may improve traffic throughput in specific * network conditions. */ #define EM_TADV 64 /* - * RxIntDelay + * EM_RDTR - Receive Interrupt Delay Timer (Packet Timer) * Valid Range: 0-65535 (0=off) * Default Value: 0 * This value delays the generation of receive interrupts in units of 1.024 @@ -141,24 +141,24 @@ POSSIBILITY OF SUCH DAMAGE. * may be set too high, causing the driver to run out of available receive * descriptors. * - * CAUTION: When setting RxIntDelay to a value other than 0, adapters + * CAUTION: When setting EM_RDTR to a value other than 0, adapters * may hang (stop transmitting) under certain network conditions. * If this occurs a WATCHDOG message is logged in the system event log. * In addition, the controller is automatically reset, restoring the * network connection. To eliminate the potential for the hang - * ensure that RxIntDelay is set to 0. + * ensure that EM_RDTR is set to 0. */ #define EM_RDTR 0 /* - * RxAbsIntDelay (Not valid for 82542/82543/82544) + * Receive Interrupt Absolute Delay Timer (Not valid for 82542/82543/82544) * Valid Range: 0-65535 (0=off) * Default Value: 64 * This value, in units of 1.024 microseconds, limits the delay in which a - * receive interrupt is generated. Useful only if RxIntDelay is non-zero, + * receive interrupt is generated. Useful only if EM_RDTR is non-zero, * this value ensures that an interrupt is generated after the initial * packet is received within the set amount of time. Proper tuning, - * along with RxIntDelay, may improve traffic throughput in specific network + * along with EM_RDTR, may improve traffic throughput in specific network * conditions. */ #define EM_RADV 64 @@ -202,6 +202,17 @@ POSSIBILITY OF SUCH DAMAGE. */ #define WAIT_FOR_AUTO_NEG_DEFAULT 0 +/* + * EM_MASTER_SLAVE is only defined to enable a workaround for a known compatibility issue + * with 82541/82547 devices and some switches. See the "Known Limitations" section of + * the README file for a complete description and a list of affected switches. + * + * 0 = Hardware default + * 1 = Master mode + * 2 = Slave mode + * 3 = Auto master/slave + */ +/* #define EM_MASTER_SLAVE 2 */ /* Tunables -- End */ @@ -301,6 +312,19 @@ struct em_int_delay_info { int value; /* Current value in usecs */ }; +/* For 82544 PCIX Workaround */ +typedef struct _ADDRESS_LENGTH_PAIR +{ + u_int64_t address; + u_int32_t length; +} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR; + +typedef struct _DESCRIPTOR_PAIR +{ + ADDRESS_LENGTH_PAIR descriptor[4]; + u_int32_t elements; +} DESC_ARRAY, *PDESC_ARRAY; + /* Our adapter structure */ struct adapter { struct arpcom interface_data; @@ -389,6 +413,9 @@ struct adapter { u_int64_t tx_fifo_reset; u_int64_t tx_fifo_wrk; + /* For 82544 PCIX Workaround */ + boolean_t pcix_82544; + #ifdef DBG_STATS unsigned long no_pkts_avail; unsigned long clean_tx_interrupts; diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c index 361c777..2bee94f 100644 --- a/sys/dev/em/if_em_hw.c +++ b/sys/dev/em/if_em_hw.c @@ -42,14 +42,15 @@ __FBSDID("$FreeBSD$"); static int32_t em_set_phy_type(struct em_hw *hw); static void em_phy_init_script(struct em_hw *hw); -static int32_t em_setup_fiber_link(struct em_hw *hw); static int32_t em_setup_copper_link(struct em_hw *hw); +static int32_t em_setup_fiber_serdes_link(struct em_hw *hw); +static int32_t em_adjust_serdes_amplitude(struct em_hw *hw); static int32_t em_phy_force_speed_duplex(struct em_hw *hw); static int32_t em_config_mac_to_phy(struct em_hw *hw); -static int32_t em_force_mac_fc(struct em_hw *hw); static void em_raise_mdi_clk(struct em_hw *hw, uint32_t *ctrl); static void em_lower_mdi_clk(struct em_hw *hw, uint32_t *ctrl); -static void em_shift_out_mdi_bits(struct em_hw *hw, uint32_t data, uint16_t count); +static void em_shift_out_mdi_bits(struct em_hw *hw, uint32_t data, + uint16_t count); static uint16_t em_shift_in_mdi_bits(struct em_hw *hw); static int32_t em_phy_reset_dsp(struct em_hw *hw); static int32_t em_write_eeprom_spi(struct em_hw *hw, uint16_t offset, @@ -60,13 +61,30 @@ static int32_t em_write_eeprom_microwire(struct em_hw *hw, static int32_t em_spi_eeprom_ready(struct em_hw *hw); static void em_raise_ee_clk(struct em_hw *hw, uint32_t *eecd); static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd); -static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, uint16_t count); +static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, + uint16_t count); +static int32_t em_write_phy_reg_ex(struct em_hw *hw, uint32_t reg_addr, + uint16_t phy_data); +static int32_t em_read_phy_reg_ex(struct em_hw *hw,uint32_t reg_addr, + uint16_t *phy_data); static uint16_t em_shift_in_ee_bits(struct em_hw *hw, uint16_t count); static int32_t em_acquire_eeprom(struct em_hw *hw); static void em_release_eeprom(struct em_hw *hw); static void em_standby_eeprom(struct em_hw *hw); static int32_t em_id_led_init(struct em_hw * hw); +static int32_t em_set_vco_speed(struct em_hw *hw); +/* IGP cable length table */ +static const +uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = + { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25, + 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 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}; /****************************************************************************** @@ -108,41 +126,64 @@ em_phy_init_script(struct em_hw *hw) DEBUGFUNC("em_phy_init_script"); if(hw->phy_init_script) { - msec_delay(10); + msec_delay(20); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); em_write_phy_reg(hw,0x0000,0x0140); msec_delay(5); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F95); - em_write_phy_reg(hw,0x0015,0x0001); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F71); - em_write_phy_reg(hw,0x0011,0xBD21); + if(hw->mac_type == em_82541 || hw->mac_type == em_82547) { + em_write_phy_reg(hw, 0x1F95, 0x0001); + + em_write_phy_reg(hw, 0x1F71, 0xBD21); + + em_write_phy_reg(hw, 0x1F79, 0x0018); + + em_write_phy_reg(hw, 0x1F30, 0x1600); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79); - em_write_phy_reg(hw,0x0019,0x0018); + em_write_phy_reg(hw, 0x1F31, 0x0014); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30); - em_write_phy_reg(hw,0x0010,0x1600); + em_write_phy_reg(hw, 0x1F32, 0x161C); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31); - em_write_phy_reg(hw,0x0011,0x0014); + em_write_phy_reg(hw, 0x1F94, 0x0003); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32); - em_write_phy_reg(hw,0x0012,0x161C); + em_write_phy_reg(hw, 0x1F96, 0x003F); + + em_write_phy_reg(hw, 0x2010, 0x0008); + } else { + em_write_phy_reg(hw, 0x1F73, 0x0099); + } - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94); - em_write_phy_reg(hw,0x0014,0x0003); + em_write_phy_reg(hw, 0x0000, 0x3300); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96); - em_write_phy_reg(hw,0x0016,0x003F); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010); - em_write_phy_reg(hw,0x0010,0x0008); + if(hw->mac_type == em_82547) { + uint16_t fused, fine, coarse; - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); - em_write_phy_reg(hw,0x0000,0x3300); + /* Move to analog registers page */ + em_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused); + + if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) { + em_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused); + + fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK; + coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK; + + if(coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) { + coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10; + fine -= IGP01E1000_ANALOG_FUSE_FINE_1; + } else if(coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH) + fine -= IGP01E1000_ANALOG_FUSE_FINE_10; + + fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) | + (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) | + (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK); + + em_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_CONTROL, fused); + em_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_BYPASS, + IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL); + } + } } } @@ -191,32 +232,89 @@ em_set_mac_type(struct em_hw *hw) case E1000_DEV_ID_82545EM_FIBER: hw->mac_type = em_82545; break; + case E1000_DEV_ID_82545GM_COPPER: + case E1000_DEV_ID_82545GM_FIBER: + case E1000_DEV_ID_82545GM_SERDES: + hw->mac_type = em_82545_rev_3; + break; case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546EB_QUAD_COPPER: hw->mac_type = em_82546; break; + case E1000_DEV_ID_82546GB_COPPER: + case E1000_DEV_ID_82546GB_FIBER: + case E1000_DEV_ID_82546GB_SERDES: + hw->mac_type = em_82546_rev_3; + break; case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82541EI_MOBILE: hw->mac_type = em_82541; break; + case E1000_DEV_ID_82541ER: + case E1000_DEV_ID_82541GI: + case E1000_DEV_ID_82541GI_MOBILE: + hw->mac_type = em_82541_rev_2; + break; case E1000_DEV_ID_82547EI: hw->mac_type = em_82547; break; + case E1000_DEV_ID_82547GI: + hw->mac_type = em_82547_rev_2; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } - return E1000_SUCCESS; } + +/***************************************************************************** + * Set media type and TBI compatibility. + * + * hw - Struct containing variables accessed by shared code + * **************************************************************************/ +void +em_set_media_type(struct em_hw *hw) +{ + uint32_t status; + + DEBUGFUNC("em_set_media_type"); + + if(hw->mac_type != em_82543) { + /* tbi_compatibility is only valid on 82543 */ + hw->tbi_compatibility_en = FALSE; + } + + switch (hw->device_id) { + case E1000_DEV_ID_82545GM_SERDES: + case E1000_DEV_ID_82546GB_SERDES: + hw->media_type = em_media_type_internal_serdes; + break; + default: + if(hw->mac_type >= em_82543) { + status = E1000_READ_REG(hw, STATUS); + if(status & E1000_STATUS_TBIMODE) { + hw->media_type = em_media_type_fiber; + /* tbi_compatibility not valid on fiber */ + hw->tbi_compatibility_en = FALSE; + } else { + hw->media_type = em_media_type_copper; + } + } else { + /* This is an 82542 (fiber only) */ + hw->media_type = em_media_type_fiber; + } + } +} + /****************************************************************************** * Reset the transmit and receive units; mask and clear all interrupts. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -void +int32_t em_reset_hw(struct em_hw *hw) { uint32_t ctrl; @@ -253,49 +351,75 @@ em_reset_hw(struct em_hw *hw) */ msec_delay(10); - /* 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- - * clearing, and should clear within a microsecond. - */ - DEBUGOUT("Issuing a global reset to MAC\n"); ctrl = E1000_READ_REG(hw, CTRL); /* Must reset the PHY before resetting the MAC */ if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); - msec_delay(5); + msec_delay(5); } + /* 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- + * clearing, and should clear within a microsecond. + */ + DEBUGOUT("Issuing a global reset to MAC\n"); + switch(hw->mac_type) { case em_82544: case em_82540: case em_82545: case em_82546: case em_82541: + case em_82541_rev_2: /* These controllers can't ack the 64-bit write when issuing the * reset, so use IO-mapping as a workaround to issue the reset */ E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST)); break; + case em_82545_rev_3: + case em_82546_rev_3: + /* Reset is performed on a shadow of the control register */ + E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST)); + break; default: E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); break; } - /* Force a reload from the EEPROM if necessary */ - if(hw->mac_type < em_82540) { - /* Wait for reset to complete */ - usec_delay(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); - /* Wait for EEPROM reload */ - msec_delay(2); - } else { - /* Wait for EEPROM reload (it happens automatically) */ - msec_delay(5); - /* Dissable HW ARPs on ASF enabled adapters */ + /* After MAC reset, force reload of EEPROM to restore power-on settings to + * device. Later controllers reload the EEPROM automatically, so just wait + * for reload to complete. + */ + switch(hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + case em_82543: + case em_82544: + /* Wait for reset to complete */ + usec_delay(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); + /* Wait for EEPROM reload */ + msec_delay(2); + break; + case em_82541: + case em_82541_rev_2: + case em_82547: + case em_82547_rev_2: + /* Wait for EEPROM reload */ + msec_delay(20); + break; + default: + /* Wait for EEPROM reload (it happens automatically) */ + msec_delay(5); + break; + } + + /* Disable HW ARPs on ASF enabled adapters */ + if(hw->mac_type >= em_82540) { manc = E1000_READ_REG(hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(hw, MANC, manc); @@ -323,6 +447,8 @@ em_reset_hw(struct em_hw *hw) if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) em_pci_set_mwi(hw); } + + return E1000_SUCCESS; } /****************************************************************************** @@ -339,7 +465,7 @@ em_reset_hw(struct em_hw *hw) int32_t em_init_hw(struct em_hw *hw) { - uint32_t ctrl, status; + uint32_t ctrl; uint32_t i; int32_t ret_val; uint16_t pcix_cmd_word; @@ -350,31 +476,13 @@ em_init_hw(struct em_hw *hw) DEBUGFUNC("em_init_hw"); /* Initialize Identification LED */ - ret_val = em_id_led_init(hw); - if(ret_val < 0) { + if((ret_val = em_id_led_init(hw))) { DEBUGOUT("Error Initializing Identification LED\n"); return ret_val; } - /* Set the Media Type and exit with error if it is not valid. */ - if(hw->mac_type != em_82543) { - /* tbi_compatibility is only valid on 82543 */ - hw->tbi_compatibility_en = FALSE; - } - - if(hw->mac_type >= em_82543) { - status = E1000_READ_REG(hw, STATUS); - if(status & E1000_STATUS_TBIMODE) { - hw->media_type = em_media_type_fiber; - /* tbi_compatibility not valid on fiber */ - hw->tbi_compatibility_en = FALSE; - } else { - hw->media_type = em_media_type_copper; - } - } else { - /* This is an 82542 (fiber only) */ - hw->media_type = em_media_type_fiber; - } + /* Set the media type and TBI compatibility */ + em_set_media_type(hw); /* Disabling VLAN filtering. */ DEBUGOUT("Initializing the IEEE VLAN\n"); @@ -419,21 +527,30 @@ em_init_hw(struct em_hw *hw) E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR); } - /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */ - if(hw->bus_type == em_bus_type_pcix) { - em_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word); - em_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word); - cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >> - PCIX_COMMAND_MMRBC_SHIFT; - stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> - PCIX_STATUS_HI_MMRBC_SHIFT; - if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) - stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; - if(cmd_mmrbc > stat_mmrbc) { - pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; - pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; - em_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word); + switch(hw->mac_type) { + case em_82545_rev_3: + case em_82546_rev_3: + break; + default: + /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */ + if(hw->bus_type == em_bus_type_pcix) { + em_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word); + em_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, + &pcix_stat_hi_word); + cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >> + PCIX_COMMAND_MMRBC_SHIFT; + stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> + PCIX_STATUS_HI_MMRBC_SHIFT; + if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) + stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; + if(cmd_mmrbc > stat_mmrbc) { + pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; + pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; + em_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, + &pcix_cmd_word); + } } + break; } /* Call a subroutine to configure the link and setup flow control. */ @@ -457,6 +574,46 @@ em_init_hw(struct em_hw *hw) } /****************************************************************************** + * Adjust SERDES output amplitude based on EEPROM setting. + * + * hw - Struct containing variables accessed by shared code. + *****************************************************************************/ +static int32_t +em_adjust_serdes_amplitude(struct em_hw *hw) +{ + uint16_t eeprom_data; + int32_t ret_val; + + DEBUGFUNC("em_adjust_serdes_amplitude"); + + if(hw->media_type != em_media_type_internal_serdes) + return E1000_SUCCESS; + + switch(hw->mac_type) { + case em_82545_rev_3: + case em_82546_rev_3: + break; + default: + return E1000_SUCCESS; + } + + if ((ret_val = em_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1, + &eeprom_data))) { + return ret_val; + } + + if(eeprom_data != EEPROM_RESERVED_WORD) { + /* Adjust SERDES output amplitude only. */ + eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, + eeprom_data))) + return ret_val; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** * Configures flow control and link settings. * * hw - Struct containing variables accessed by shared code @@ -527,9 +684,9 @@ em_setup_link(struct em_hw *hw) } /* Call the necessary subroutine to configure the link. */ - ret_val = (hw->media_type == em_media_type_fiber) ? - em_setup_fiber_link(hw) : - em_setup_copper_link(hw); + ret_val = (hw->media_type == em_media_type_copper) ? + em_setup_copper_link(hw) : + em_setup_fiber_serdes_link(hw); /* Initialize the flow control address, type, and PAUSE timer * registers to their default values. This is done even if flow @@ -568,7 +725,7 @@ em_setup_link(struct em_hw *hw) } /****************************************************************************** - * Sets up link for a fiber based adapter + * Sets up link for a fiber based or serdes based adapter * * hw - Struct containing variables accessed by shared code * @@ -577,28 +734,37 @@ em_setup_link(struct em_hw *hw) * and receiver are not enabled. *****************************************************************************/ static int32_t -em_setup_fiber_link(struct em_hw *hw) +em_setup_fiber_serdes_link(struct em_hw *hw) { uint32_t ctrl; uint32_t status; uint32_t txcw = 0; uint32_t i; - uint32_t signal; + uint32_t signal = 0; int32_t ret_val; - DEBUGFUNC("em_setup_fiber_link"); + DEBUGFUNC("em_setup_fiber_serdes_link"); - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be + /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be * set when the optics detect a signal. On older adapters, it will be - * cleared when there is a signal + * cleared when there is a signal. This applies to fiber media only. + * If we're on serdes media, adjust the output amplitude to value set in + * the EEPROM. */ ctrl = E1000_READ_REG(hw, CTRL); - if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1; - else signal = 0; + if(hw->media_type == em_media_type_fiber) + signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0; + + if((ret_val = em_adjust_serdes_amplitude(hw))) + return ret_val; /* Take the link out of reset */ ctrl &= ~(E1000_CTRL_LRST); + /* Adjust VCO speed to improve BER performance */ + if((ret_val = em_set_vco_speed(hw))) + return ret_val; + em_config_collision_dist(hw); /* Check for a software override of the flow control settings, and setup @@ -665,8 +831,10 @@ em_setup_fiber_link(struct em_hw *hw) * indication in the Device Status Register. Time-out if a link isn't * seen in 500 milliseconds seconds (Auto-negotiation should complete in * less than 500 milliseconds even if the other end is doing it in SW). + * For internal serdes, we just assume a signal is present, then poll. */ - if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) { + if(hw->media_type == em_media_type_internal_serdes || + (E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) { DEBUGOUT("Looking for Link\n"); for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { msec_delay(10); @@ -674,19 +842,20 @@ em_setup_fiber_link(struct em_hw *hw) if(status & E1000_STATUS_LU) break; } if(i == (LINK_UP_TIMEOUT / 10)) { - /* AutoNeg failed to achieve a link, so we'll call - * em_check_for_link. This routine will force the link up if we - * detect a signal. This will allow us to communicate with - * non-autonegotiating link partners. - */ DEBUGOUT("Never got a valid link from auto-neg!!!\n"); hw->autoneg_failed = 1; - ret_val = em_check_for_link(hw); - if(ret_val < 0) { - DEBUGOUT("Error while checking for link\n"); - return ret_val; + if(hw->media_type == em_media_type_fiber) { + /* AutoNeg failed to achieve a link, so we'll call + * em_check_for_link. This routine will force the link up if + * we detect a signal. This will allow us to communicate with + * non-autonegotiating link partners. + */ + if((ret_val = em_check_for_link(hw))) { + DEBUGOUT("Error while checking for link\n"); + return ret_val; + } + hw->autoneg_failed = 0; } - hw->autoneg_failed = 0; } else { hw->autoneg_failed = 0; DEBUGOUT("Valid Link Found\n"); @@ -694,7 +863,7 @@ em_setup_fiber_link(struct em_hw *hw) } else { DEBUGOUT("No Signal Detected\n"); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -729,233 +898,281 @@ em_setup_copper_link(struct em_hw *hw) } /* Make sure we have a valid PHY */ - ret_val = em_detect_gig_phy(hw); - if(ret_val < 0) { + if((ret_val = em_detect_gig_phy(hw))) { DEBUGOUT("Error, did not detect valid phy.\n"); return ret_val; } DEBUGOUT1("Phy ID = %x \n", hw->phy_id); - if (hw->phy_type == em_phy_igp) { + if(hw->mac_type <= em_82543 || + hw->mac_type == em_82541 || hw->mac_type == em_82547 || + hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) + hw->phy_reset_disable = FALSE; - ret_val = em_phy_reset(hw); - if(ret_val < 0) { - DEBUGOUT("Error Resetting the PHY\n"); - return ret_val; - } + if(!hw->phy_reset_disable) { + if (hw->phy_type == em_phy_igp) { - /* Wait 10ms for MAC to configure PHY from eeprom settings */ - msec_delay(15); + if((ret_val = em_phy_reset(hw))) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } - if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + /* Wait 10ms for MAC to configure PHY from eeprom settings */ + msec_delay(15); - /* 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); + /* 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->autoneg_advertised == ADVERTISE_1000_FULL) { - /* Disable SmartSpeed */ - if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; - if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } - /* Set auto Master/Slave resolution process */ - if(em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; + /* disable lplu d3 during driver init */ + if((ret_val = em_set_d3_lplu_state(hw, FALSE))) { + DEBUGOUT("Error Disabling LPLU D3\n"); + return ret_val; } - phy_data &= ~CR_1000T_MS_ENABLE; - if(em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; + + /* Configure mdi-mdix settings */ + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, + &phy_data))) + return ret_val; + + if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + hw->dsp_config_state = em_dsp_config_disabled; + /* Force MDI for IGP B-0 PHY */ + phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | + IGP01E1000_PSCR_FORCE_MDI_MDIX); + hw->mdix = 1; + + } else { + hw->dsp_config_state = em_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; + } } - } + if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, + phy_data))) + return ret_val; - if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + /* set auto-master slave resolution settings */ + if(hw->autoneg) { + em_ms_type phy_ms_setting = hw->master_slave; + + if(hw->ffe_config_state == em_ffe_config_active) + hw->ffe_config_state = em_ffe_config_enabled; + + if(hw->dsp_config_state == em_dsp_config_activated) + hw->dsp_config_state = em_dsp_config_enabled; + + /* 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 */ + if((ret_val = em_read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &phy_data))) + return ret_val; + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + if((ret_val = em_write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + phy_data))) + return ret_val; + /* Set auto Master/Slave resolution process */ + if((ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, + &phy_data))) + return ret_val; + phy_data &= ~CR_1000T_MS_ENABLE; + if((ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, + phy_data))) + return ret_val; + } - /* Force MDI for IGP PHY */ - phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | - IGP01E1000_PSCR_FORCE_MDI_MDIX); + if((ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, + &phy_data))) + return ret_val; - hw->mdix = 1; + /* load defaults for future use */ + hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ? + ((phy_data & CR_1000T_MS_VALUE) ? + em_ms_force_master : + em_ms_force_slave) : + em_ms_auto; - if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + switch (phy_ms_setting) { + case em_ms_force_master: + phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case em_ms_force_slave: + phy_data |= CR_1000T_MS_ENABLE; + phy_data &= ~(CR_1000T_MS_VALUE); + break; + case em_ms_auto: + phy_data &= ~CR_1000T_MS_ENABLE; + default: + break; + } + if((ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, + phy_data))) + return ret_val; + } + } else { + /* Enable CRS on TX. This must be set for half-duplex operation. */ + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data))) + return ret_val; - } else { - /* Enable CRS on TX. This must be set for half-duplex operation. */ - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - /* 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; + /* 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; - 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; - } + 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 - */ - phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if(hw->disable_polarity_correction == 1) - phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + /* 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; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + phy_data))) + return ret_val; - /* Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - if(em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= M88E1000_EPSCR_TX_CLK_25; + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + if((ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data))) + 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); - if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; + 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); + if((ret_val = em_write_phy_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, + phy_data))) + return ret_val; } - } - /* SW Reset the PHY so all changes take effect */ - ret_val = em_phy_reset(hw); - if(ret_val < 0) { - DEBUGOUT("Error Resetting the PHY\n"); - return ret_val; + /* SW Reset the PHY so all changes take effect */ + if((ret_val = em_phy_reset(hw))) { + DEBUGOUT("Error Resetting the PHY\n"); + 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. - */ - /* Is autoneg enabled? This is enabled by default or by software override. - * If so, call em_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 - * em_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. + /* 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. */ - 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. + /* Is autoneg enabled? This is enabled by default or by software + * override. If so, call em_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 em_phy_force_speed_duplex to parse and set this up. */ - if(hw->autoneg_advertised == 0) - hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + 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; - DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); - ret_val = em_phy_setup_autoneg(hw); - if(ret_val < 0) { - DEBUGOUT("Error Setting up Auto-Negotiation\n"); - return ret_val; - } - DEBUGOUT("Restarting Auto-Neg\n"); + /* 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; - /* Restart auto-negotiation by setting the Auto Neg Enable bit and - * the Auto Neg Restart bit in the PHY control register. - */ - if(em_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); - if(em_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + if((ret_val = em_phy_setup_autoneg(hw))) { + DEBUGOUT("Error Setting up Auto-Negotiation\n"); + return ret_val; + } + DEBUGOUT("Restarting Auto-Neg\n"); - /* 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 = em_wait_autoneg(hw); - if(ret_val < 0) { - DEBUGOUT("Error while waiting for autoneg to complete\n"); + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + if((ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data))) + return ret_val; + + phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + if((ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data))) + return ret_val; + + /* 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) { + if((ret_val = em_wait_autoneg(hw))) { + DEBUGOUT("Error while waiting for autoneg to complete\n"); + return ret_val; + } + } + hw->get_link_status = TRUE; + } else { + DEBUGOUT("Forcing speed and duplex\n"); + if((ret_val = em_phy_force_speed_duplex(hw))) { + DEBUGOUT("Error Forcing Speed and Duplex\n"); return ret_val; } } - hw->get_link_status = TRUE; - } else { - DEBUGOUT("Forcing speed and duplex\n"); - ret_val = em_phy_force_speed_duplex(hw); - if(ret_val < 0) { - DEBUGOUT("Error Forcing Speed and Duplex\n"); - return ret_val; - } - } + } /* !hw->phy_reset_disable */ /* Check link status. Wait up to 100 microseconds for link to become * valid. */ for(i = 0; i < 10; i++) { - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + 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 @@ -968,25 +1185,31 @@ em_setup_copper_link(struct em_hw *hw) if(hw->mac_type >= em_82544) { em_config_collision_dist(hw); } else { - ret_val = em_config_mac_to_phy(hw); - if(ret_val < 0) { + if((ret_val = em_config_mac_to_phy(hw))) { DEBUGOUT("Error configuring MAC to PHY settings\n"); return ret_val; - } + } } - ret_val = em_config_fc_after_link_up(hw); - if(ret_val < 0) { + if((ret_val = em_config_fc_after_link_up(hw))) { DEBUGOUT("Error Configuring Flow Control\n"); return ret_val; } DEBUGOUT("Valid link established!!!\n"); - return 0; + + if(hw->phy_type == em_phy_igp) { + if((ret_val = em_config_dsp_after_link_change(hw, TRUE))) { + DEBUGOUT("Error Configuring DSP after link up\n"); + return ret_val; + } + } + DEBUGOUT("Valid link established!!!\n"); + return E1000_SUCCESS; } usec_delay(10); } DEBUGOUT("Unable to establish link!!!\n"); - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -997,22 +1220,20 @@ em_setup_copper_link(struct em_hw *hw) int32_t em_phy_setup_autoneg(struct em_hw *hw) { + int32_t ret_val; uint16_t mii_autoneg_adv_reg; uint16_t mii_1000t_ctrl_reg; DEBUGFUNC("em_phy_setup_autoneg"); /* Read the MII Auto-Neg Advertisement Register (Address 4). */ - if(em_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV, + &mii_autoneg_adv_reg))) + return ret_val; /* Read the MII 1000Base-T Control Register (Address 9). */ - if(em_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg))) + return ret_val; /* Need to parse both autoneg_advertised and fc and set up * the appropriate PHY registers. First we will parse for @@ -1118,18 +1339,16 @@ em_phy_setup_autoneg(struct em_hw *hw) return -E1000_ERR_CONFIG; } - if(em_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_write_phy_reg(hw, PHY_AUTONEG_ADV, + mii_autoneg_adv_reg))) + return ret_val; DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - if(em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } - return 0; + if((ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg))) + return ret_val; + + return E1000_SUCCESS; } /****************************************************************************** @@ -1165,10 +1384,8 @@ em_phy_force_speed_duplex(struct em_hw *hw) ctrl &= ~E1000_CTRL_ASDE; /* Read the MII Control Register. */ - if(em_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg))) + return ret_val; /* We need to disable autoneg in order to force link and duplex. */ @@ -1214,19 +1431,18 @@ em_phy_force_speed_duplex(struct em_hw *hw) E1000_WRITE_REG(hw, CTRL, ctrl); if (hw->phy_type == em_phy_m88) { - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data))) + return ret_val; /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI * forced whenever speed are duplex are forced. */ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + phy_data))) + return ret_val; + DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); /* Need to reset the PHY or these changes will be ignored */ @@ -1235,25 +1451,22 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Clear Auto-Crossover to force MDI manually. IGP requires MDI * forced whenever speed or duplex are forced. */ - if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, + &phy_data))) + return ret_val; phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, + phy_data))) + return ret_val; } /* Write back the modified PHY MII control register. */ - if(em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg))) + return ret_val; + usec_delay(1); /* The wait_autoneg_complete flag may be a little misleading here. @@ -1273,22 +1486,18 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Read the MII Status Register and wait for Auto-Neg Complete bit * to be set. */ - if(em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg))) + return ret_val; + + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg))) + return ret_val; + if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } if(i == 0) { /* We didn't get link */ /* Reset the DSP and wait again for link. */ - - ret_val = em_phy_reset_dsp(hw); - if(ret_val < 0) { + if((ret_val = em_phy_reset_dsp(hw))) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; } @@ -1300,14 +1509,11 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Read the MII Status Register and wait for Auto-Neg Complete bit * to be set. */ - if(em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg))) + return ret_val; + + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg))) + return ret_val; } } @@ -1316,30 +1522,29 @@ em_phy_force_speed_duplex(struct em_hw *hw) * Extended PHY Specific Control Register to 25MHz clock. This value * defaults back to a 2.5MHz clock when the PHY is reset. */ - if(em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data))) + return ret_val; + phy_data |= M88E1000_EPSCR_TX_CLK_25; - if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data))) + return ret_val; /* In addition, because of the s/w reset above, we need to enable CRS on * TX. This must be set for both full and half duplex operation. */ - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data))) + return ret_val; + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + phy_data))) + return ret_val; + } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1379,6 +1584,7 @@ static int32_t em_config_mac_to_phy(struct em_hw *hw) { uint32_t ctrl; + int32_t ret_val; uint16_t phy_data; DEBUGFUNC("em_config_mac_to_phy"); @@ -1394,10 +1600,10 @@ em_config_mac_to_phy(struct em_hw *hw) * registers depending on negotiated values. */ if (hw->phy_type == em_phy_igp) { - if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, + &phy_data))) + return ret_val; + if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD; else ctrl &= ~E1000_CTRL_FD; @@ -1413,10 +1619,10 @@ em_config_mac_to_phy(struct em_hw *hw) IGP01E1000_PSSR_SPEED_100MBPS) ctrl |= E1000_CTRL_SPD_100; } else { - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data))) + return ret_val; + if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD; else ctrl &= ~E1000_CTRL_FD; @@ -1432,7 +1638,7 @@ em_config_mac_to_phy(struct em_hw *hw) } /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1446,7 +1652,7 @@ em_config_mac_to_phy(struct em_hw *hw) * by the PHY rather than the MAC. Software must also configure these * bits when link is forced on a fiber connection. *****************************************************************************/ -static int32_t +int32_t em_force_mac_fc(struct em_hw *hw) { uint32_t ctrl; @@ -1499,7 +1705,7 @@ em_force_mac_fc(struct em_hw *hw) ctrl &= (~E1000_CTRL_TFCE); E1000_WRITE_REG(hw, CTRL, ctrl); - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1530,9 +1736,9 @@ em_config_fc_after_link_up(struct em_hw *hw) * configuration of the MAC to match the "fc" parameter. */ if(((hw->media_type == em_media_type_fiber) && (hw->autoneg_failed)) || + ((hw->media_type == em_media_type_internal_serdes) && (hw->autoneg_failed)) || ((hw->media_type == em_media_type_copper) && (!hw->autoneg))) { - ret_val = em_force_mac_fc(hw); - if(ret_val < 0) { + if((ret_val = em_force_mac_fc(hw))) { DEBUGOUT("Error forcing flow control settings\n"); return ret_val; } @@ -1548,14 +1754,10 @@ em_config_fc_after_link_up(struct em_hw *hw) * has completed. We read this twice because this reg has * some "sticky" (latched) bits. */ - if(em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error \n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error \n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg))) + return ret_val; + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg))) + return ret_val; if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { /* The AutoNeg process has completed, so we now need to @@ -1564,14 +1766,12 @@ em_config_fc_after_link_up(struct em_hw *hw) * Register (Address 5) to determine how flow control was * negotiated. */ - if(em_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV, + &mii_nway_adv_reg))) + return ret_val; + if((ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, + &mii_nway_lp_ability_reg))) + return ret_val; /* Two bits in the Auto Negotiation Advertisement Register * (Address 4) and two bits in the Auto Negotiation Base @@ -1677,7 +1877,7 @@ em_config_fc_after_link_up(struct em_hw *hw) hw->original_fc == em_fc_tx_pause) { hw->fc = em_fc_none; DEBUGOUT("Flow Control = NONE.\r\n"); - } else { + } else if(!hw->fc_strict_ieee) { hw->fc = em_fc_rx_pause; DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); } @@ -1686,7 +1886,10 @@ em_config_fc_after_link_up(struct em_hw *hw) * negotiated to HALF DUPLEX, flow control should not be * enabled per IEEE 802.3 spec. */ - em_get_speed_and_duplex(hw, &speed, &duplex); + if((ret_val = em_get_speed_and_duplex(hw, &speed, &duplex))) { + DEBUGOUT("Error getting link speed and duplex\n"); + return ret_val; + } if(duplex == HALF_DUPLEX) hw->fc = em_fc_none; @@ -1694,16 +1897,15 @@ em_config_fc_after_link_up(struct em_hw *hw) /* Now we call a subroutine to actually force the MAC * controller to use the correct flow control settings. */ - ret_val = em_force_mac_fc(hw); - if(ret_val < 0) { + if((ret_val = em_force_mac_fc(hw))) { DEBUGOUT("Error forcing flow control settings\n"); return ret_val; - } + } } else { DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n"); } } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1720,19 +1922,19 @@ em_check_for_link(struct em_hw *hw) uint32_t ctrl; uint32_t status; uint32_t rctl; - uint32_t signal; + uint32_t signal = 0; int32_t ret_val; uint16_t phy_data; uint16_t lp_capability; DEBUGFUNC("em_check_for_link"); - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be + /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be * set when the optics detect a signal. On older adapters, it will be - * cleared when there is a signal + * cleared when there is a signal. This applies to fiber media only. */ - if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1; - else signal = 0; + if(hw->media_type == em_media_type_fiber) + signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0; ctrl = E1000_READ_REG(hw, CTRL); status = E1000_READ_REG(hw, STATUS); @@ -1750,14 +1952,10 @@ em_check_for_link(struct em_hw *hw) * of the PHY. * Read the register twice since the link bit is sticky. */ - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; if(phy_data & MII_SR_LINK_STATUS) { hw->get_link_status = FALSE; @@ -1767,6 +1965,7 @@ em_check_for_link(struct em_hw *hw) } else { /* No link detected */ + em_config_dsp_after_link_change(hw, FALSE); return 0; } @@ -1775,6 +1974,9 @@ em_check_for_link(struct em_hw *hw) */ if(!hw->autoneg) return -E1000_ERR_CONFIG; + /* optimize the dsp settings for the igp phy */ + em_config_dsp_after_link_change(hw, TRUE); + /* 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 @@ -1786,8 +1988,7 @@ em_check_for_link(struct em_hw *hw) if(hw->mac_type >= em_82544) em_config_collision_dist(hw); else { - ret_val = em_config_mac_to_phy(hw); - if(ret_val < 0) { + if((ret_val = em_config_mac_to_phy(hw))) { DEBUGOUT("Error configuring MAC to PHY settings\n"); return ret_val; } @@ -1797,8 +1998,7 @@ em_check_for_link(struct em_hw *hw) * need to restore the desired flow control settings because we may * have had to re-autoneg with a different link partner. */ - ret_val = em_config_fc_after_link_up(hw); - if(ret_val < 0) { + if((ret_val = em_config_fc_after_link_up(hw))) { DEBUGOUT("Error configuring flow control\n"); return ret_val; } @@ -1813,10 +2013,9 @@ em_check_for_link(struct em_hw *hw) * partner is TBI-based, and we turn on TBI Compatibility. */ if(hw->tbi_compatibility_en) { - if(em_read_phy_reg(hw, PHY_LP_ABILITY, &lp_capability) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, + &lp_capability))) + return ret_val; if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | NWAY_LPAR_10T_FD_CAPS | NWAY_LPAR_100TX_HD_CAPS | @@ -1873,8 +2072,7 @@ em_check_for_link(struct em_hw *hw) E1000_WRITE_REG(hw, CTRL, ctrl); /* Configure Flow Control after forcing link up. */ - ret_val = em_config_fc_after_link_up(hw); - if(ret_val < 0) { + if((ret_val = em_config_fc_after_link_up(hw))) { DEBUGOUT("Error configuring flow control\n"); return ret_val; } @@ -1891,7 +2089,7 @@ em_check_for_link(struct em_hw *hw) E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1901,12 +2099,14 @@ em_check_for_link(struct em_hw *hw) * speed - Speed of the connection * duplex - Duplex setting of the connection *****************************************************************************/ -void +int32_t em_get_speed_and_duplex(struct em_hw *hw, uint16_t *speed, uint16_t *duplex) { uint32_t status; + int32_t ret_val; + uint16_t phy_data; DEBUGFUNC("em_get_speed_and_duplex"); @@ -1935,6 +2135,27 @@ em_get_speed_and_duplex(struct em_hw *hw, *speed = SPEED_1000; *duplex = FULL_DUPLEX; } + + /* IGP01 PHY may advertise full duplex operation after speed downgrade even + * if it is operating at half duplex. Here we set the duplex settings to + * match the duplex in the link partner's capabilities. + */ + if(hw->phy_type == em_phy_igp && hw->speed_downgraded) { + if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data))) + return ret_val; + + if(!(phy_data & NWAY_ER_LP_NWAY_CAPS)) + *duplex = HALF_DUPLEX; + else { + if((ret_val == em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data))) + return ret_val; + if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) || + (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS))) + *duplex = HALF_DUPLEX; + } + } + + return E1000_SUCCESS; } /****************************************************************************** @@ -1945,6 +2166,7 @@ em_get_speed_and_duplex(struct em_hw *hw, int32_t em_wait_autoneg(struct em_hw *hw) { + int32_t ret_val; uint16_t i; uint16_t phy_data; @@ -1956,20 +2178,16 @@ em_wait_autoneg(struct em_hw *hw) /* Read the MII Status Register and wait for Auto-Neg * Complete bit to be set. */ - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; if(phy_data & MII_SR_AUTONEG_COMPLETE) { - return 0; + return E1000_SUCCESS; } msec_delay(100); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1983,11 +2201,11 @@ em_raise_mdi_clk(struct em_hw *hw, uint32_t *ctrl) { /* Raise the clock input to the Management Data Clock (by setting the MDC - * bit), and then delay 2 microseconds. + * bit), and then delay 10 microseconds. */ E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC)); E1000_WRITE_FLUSH(hw); - usec_delay(2); + usec_delay(10); } /****************************************************************************** @@ -2001,11 +2219,11 @@ em_lower_mdi_clk(struct em_hw *hw, uint32_t *ctrl) { /* Lower the clock input to the Management Data Clock (by clearing the MDC - * bit), and then delay 2 microseconds. + * bit), and then delay 10 microseconds. */ E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC)); E1000_WRITE_FLUSH(hw); - usec_delay(2); + usec_delay(10); } /****************************************************************************** @@ -2049,7 +2267,7 @@ em_shift_out_mdi_bits(struct em_hw *hw, E1000_WRITE_REG(hw, CTRL, ctrl); E1000_WRITE_FLUSH(hw); - usec_delay(2); + usec_delay(10); em_raise_mdi_clk(hw, &ctrl); em_lower_mdi_clk(hw, &ctrl); @@ -2111,8 +2329,8 @@ em_shift_in_mdi_bits(struct em_hw *hw) } /***************************************************************************** -* Reads the value from a PHY register -* +* Reads the value from a PHY register, if the value is on a specific non zero +* page, sets the page first. * hw - Struct containing variables accessed by shared code * reg_addr - address of the PHY register to read ******************************************************************************/ @@ -2121,11 +2339,33 @@ em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data) { + uint32_t ret_val; + + DEBUGFUNC("em_read_phy_reg"); + + if(hw->phy_type == em_phy_igp && + (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { + if((ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, + (uint16_t)reg_addr))) + return ret_val; + } + + ret_val = em_read_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr, + phy_data); + + return ret_val; +} + +int32_t +em_read_phy_reg_ex(struct em_hw *hw, + uint32_t reg_addr, + uint16_t *phy_data) +{ uint32_t i; uint32_t mdic = 0; const uint32_t phy_addr = 1; - DEBUGFUNC("em_read_phy_reg"); + DEBUGFUNC("em_read_phy_reg_ex"); if(reg_addr > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); @@ -2145,7 +2385,7 @@ em_read_phy_reg(struct em_hw *hw, /* Poll the ready bit to see if the MDI read completed */ for(i = 0; i < 64; i++) { - usec_delay(10); + usec_delay(50); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -2187,7 +2427,7 @@ em_read_phy_reg(struct em_hw *hw, */ *phy_data = em_shift_in_mdi_bits(hw); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -2202,11 +2442,33 @@ em_write_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t phy_data) { + uint32_t ret_val; + + DEBUGFUNC("em_write_phy_reg"); + + if(hw->phy_type == em_phy_igp && + (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { + if((ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, + (uint16_t)reg_addr))) + return ret_val; + } + + ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr, + phy_data); + + return ret_val; +} + +int32_t +em_write_phy_reg_ex(struct em_hw *hw, + uint32_t reg_addr, + uint16_t phy_data) +{ uint32_t i; uint32_t mdic = 0; const uint32_t phy_addr = 1; - DEBUGFUNC("em_write_phy_reg"); + DEBUGFUNC("em_write_phy_reg_ex"); if(reg_addr > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); @@ -2227,7 +2489,7 @@ em_write_phy_reg(struct em_hw *hw, /* Poll the ready bit to see if the MDI read completed */ for(i = 0; i < 64; i++) { - usec_delay(10); + usec_delay(50); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -2257,7 +2519,7 @@ em_write_phy_reg(struct em_hw *hw, em_shift_out_mdi_bits(hw, mdic, 32); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -2302,11 +2564,6 @@ em_phy_hw_reset(struct em_hw *hw) usec_delay(150); if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { - if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { - DEBUGOUT("PHY Write Error\n"); - return; - } - /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; @@ -2325,24 +2582,26 @@ em_phy_hw_reset(struct em_hw *hw) int32_t em_phy_reset(struct em_hw *hw) { + int32_t ret_val; uint16_t phy_data; DEBUGFUNC("em_phy_reset"); - if(em_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= MII_CR_RESET; - if(em_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } - usec_delay(1); - if (hw->phy_type == em_phy_igp) { + if(hw->mac_type != em_82541_rev_2) { + if((ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data))) + return ret_val; + + phy_data |= MII_CR_RESET; + if((ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data))) + return ret_val; + + usec_delay(1); + } else em_phy_hw_reset(hw); + + if(hw->phy_type == em_phy_igp) em_phy_init_script(hw); - } - return 0; + + return E1000_SUCCESS; } /****************************************************************************** @@ -2353,23 +2612,21 @@ em_phy_reset(struct em_hw *hw) int32_t em_detect_gig_phy(struct em_hw *hw) { + int32_t phy_init_status, ret_val; uint16_t phy_id_high, phy_id_low; boolean_t match = FALSE; - int32_t phy_init_status; DEBUGFUNC("em_detect_gig_phy"); /* Read the PHY ID Registers to identify which PHY is onboard. */ - if(em_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_ID1, &phy_id_high))) + return ret_val; + hw->phy_id = (uint32_t) (phy_id_high << 16); usec_delay(20); - if(em_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_ID2, &phy_id_low))) + return ret_val; + hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK); hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK; @@ -2382,11 +2639,15 @@ em_detect_gig_phy(struct em_hw *hw) break; case em_82540: case em_82545: + case em_82545_rev_3: case em_82546: + case em_82546_rev_3: if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE; break; case em_82541: + case em_82541_rev_2: case em_82547: + case em_82547_rev_2: if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; break; default: @@ -2397,7 +2658,7 @@ em_detect_gig_phy(struct em_hw *hw) if ((match) && (phy_init_status == E1000_SUCCESS)) { DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id); - return 0; + return E1000_SUCCESS; } DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id); return -E1000_ERR_PHY; @@ -2411,17 +2672,16 @@ em_detect_gig_phy(struct em_hw *hw) static int32_t em_phy_reset_dsp(struct em_hw *hw) { - int32_t ret_val = -E1000_ERR_PHY; + int32_t ret_val; DEBUGFUNC("em_phy_reset_dsp"); do { - if(em_write_phy_reg(hw, 29, 0x001d) < 0) break; - if(em_write_phy_reg(hw, 30, 0x00c1) < 0) break; - if(em_write_phy_reg(hw, 30, 0x0000) < 0) break; - ret_val = 0; + if((ret_val = em_write_phy_reg(hw, 29, 0x001d))) break; + if((ret_val = em_write_phy_reg(hw, 30, 0x00c1))) break; + if((ret_val = em_write_phy_reg(hw, 30, 0x0000))) break; + ret_val = E1000_SUCCESS; } while(0); - if(ret_val < 0) DEBUGOUT("PHY Write Error\n"); return ret_val; } @@ -2432,8 +2692,10 @@ em_phy_reset_dsp(struct em_hw *hw) * phy_info - PHY information structure ******************************************************************************/ int32_t -em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info) +em_phy_igp_get_info(struct em_hw *hw, + struct em_phy_info *phy_info) { + int32_t ret_val; uint16_t phy_data, polarity, min_length, max_length, average; DEBUGFUNC("em_phy_igp_get_info"); @@ -2449,13 +2711,14 @@ em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info) phy_info->polarity_correction = em_polarity_reversal_enabled; /* Check polarity status */ - if(em_check_polarity(hw, &polarity) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_check_polarity(hw, &polarity))) + return ret_val; phy_info->cable_polarity = polarity; - if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, + &phy_data))) + return ret_val; phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >> IGP01E1000_PSSR_MDIX_SHIFT; @@ -2463,8 +2726,8 @@ em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info) if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_1000MBPS) { /* Local/Remote Receiver Information are only valid at 1000 Mbps */ - if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data))) + return ret_val; phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> SR_1000T_LOCAL_RX_STATUS_SHIFT; @@ -2472,8 +2735,8 @@ em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info) SR_1000T_REMOTE_RX_STATUS_SHIFT; /* Get cable length */ - if(em_get_cable_length(hw, &min_length, &max_length) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_get_cable_length(hw, &min_length, &max_length))) + return ret_val; /* transalte to old method */ average = (max_length + min_length) / 2; @@ -2500,8 +2763,10 @@ em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info) * phy_info - PHY information structure ******************************************************************************/ int32_t -em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info) +em_phy_m88_get_info(struct em_hw *hw, + struct em_phy_info *phy_info) { + int32_t ret_val; uint16_t phy_data, polarity; DEBUGFUNC("em_phy_m88_get_info"); @@ -2510,8 +2775,8 @@ em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info) * and it stored in the hw->speed_downgraded parameter. */ phy_info->downshift = hw->speed_downgraded; - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data))) + return ret_val; phy_info->extended_10bt_distance = (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> @@ -2521,13 +2786,13 @@ em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info) M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; /* Check polarity status */ - if(em_check_polarity(hw, &polarity) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_check_polarity(hw, &polarity))) + return ret_val; phy_info->cable_polarity = polarity; - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data))) + return ret_val; phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> M88E1000_PSSR_MDIX_SHIFT; @@ -2539,8 +2804,8 @@ em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info) phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT); - if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data))) + return ret_val; phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> SR_1000T_LOCAL_RX_STATUS_SHIFT; @@ -2562,6 +2827,7 @@ int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info) { + int32_t ret_val; uint16_t phy_data; DEBUGFUNC("em_phy_get_info"); @@ -2580,20 +2846,18 @@ em_phy_get_info(struct em_hw *hw, return -E1000_ERR_CONFIG; } - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; + + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; + if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) { DEBUGOUT("PHY info is only valid if link is up\n"); return -E1000_ERR_CONFIG; } - if (hw->phy_type == em_phy_igp) + if(hw->phy_type == em_phy_igp) return em_phy_igp_get_info(hw, phy_info); else return em_phy_m88_get_info(hw, phy_info); @@ -2609,7 +2873,7 @@ em_validate_mdi_setting(struct em_hw *hw) hw->mdix = 1; return -E1000_ERR_CONFIG; } - return 0; + return E1000_SUCCESS; } @@ -2641,7 +2905,9 @@ em_init_eeprom_params(struct em_hw *hw) break; case em_82540: case em_82545: + case em_82545_rev_3: case em_82546: + case em_82546_rev_3: eeprom->type = em_eeprom_microwire; eeprom->opcode_bits = 3; eeprom->delay_usec = 50; @@ -2654,8 +2920,9 @@ em_init_eeprom_params(struct em_hw *hw) } break; case em_82541: + case em_82541_rev_2: case em_82547: - default: + case em_82547_rev_2: if (eecd & E1000_EECD_TYPE) { eeprom->type = em_eeprom_spi; eeprom->opcode_bits = 8; @@ -2680,6 +2947,18 @@ em_init_eeprom_params(struct em_hw *hw) } } break; + default: + eeprom->type = em_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; + } + break; } if (eeprom->type == em_eeprom_spi) { @@ -2688,28 +2967,28 @@ em_init_eeprom_params(struct em_hw *hw) 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; + 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; } } } @@ -2814,7 +3093,8 @@ em_shift_out_ee_bits(struct em_hw *hw, * hw - Struct containing variables accessed by shared code *****************************************************************************/ static uint16_t -em_shift_in_ee_bits(struct em_hw *hw, uint16_t count) +em_shift_in_ee_bits(struct em_hw *hw, + uint16_t count) { uint32_t eecd; uint32_t i; @@ -3074,13 +3354,17 @@ em_read_eeprom(struct em_hw *hw, } /* Prepare the EEPROM for reading */ - if (em_acquire_eeprom(hw) != E1000_SUCCESS) + if(em_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; if(eeprom->type == em_eeprom_spi) { + uint16_t word_in; uint8_t read_opcode = EEPROM_READ_OPCODE_SPI; - if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; + if(em_spi_eeprom_ready(hw)) { + em_release_eeprom(hw); + return -E1000_ERR_EEPROM; + } em_standby_eeprom(hw); @@ -3091,30 +3375,35 @@ em_read_eeprom(struct em_hw *hw, /* Send the READ command (opcode + addr) */ em_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits); em_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits); - } - else if(eeprom->type == em_eeprom_microwire) { - /* Send the READ command (opcode + addr) */ - em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE, - eeprom->opcode_bits); - em_shift_out_ee_bits(hw, offset, eeprom->address_bits); - } - /* Read the data. The address of the eeprom internally increments with - * each word (microwire) or byte (spi) being read, saving on the overhead - * of eeprom setup and tear-down. The address counter will roll over if - * reading beyond the size of the eeprom, thus allowing the entire memory - * to be read starting from any offset. */ - for (i = 0; i < words; i++) { - uint16_t word_in = em_shift_in_ee_bits(hw, 16); - if (eeprom->type == em_eeprom_spi) - word_in = (word_in >> 8) | (word_in << 8); - data[i] = word_in; + /* Read the data. The address of the eeprom internally increments with + * each byte (spi) being read, saving on the overhead of eeprom setup + * and tear-down. The address counter will roll over if reading beyond + * the size of the eeprom, thus allowing the entire memory to be read + * starting from any offset. */ + for (i = 0; i < words; i++) { + word_in = em_shift_in_ee_bits(hw, 16); + data[i] = (word_in >> 8) | (word_in << 8); + } + } else if(eeprom->type == em_eeprom_microwire) { + for (i = 0; i < words; i++) { + /* Send the READ command (opcode + addr) */ + em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE, + eeprom->opcode_bits); + em_shift_out_ee_bits(hw, (uint16_t)(offset + i), + eeprom->address_bits); + + /* Read the data. For microwire, each word requires the overhead + * of eeprom setup and tear-down. */ + data[i] = em_shift_in_ee_bits(hw, 16); + em_standby_eeprom(hw); + } } /* End this read operation */ em_release_eeprom(hw); - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3142,9 +3431,9 @@ em_validate_eeprom_checksum(struct em_hw *hw) checksum += eeprom_data; } - if(checksum == (uint16_t) EEPROM_SUM) { - return 0; - } else { + if(checksum == (uint16_t) EEPROM_SUM) + return E1000_SUCCESS; + else { DEBUGOUT("EEPROM Checksum Invalid\n"); return -E1000_ERR_EEPROM; } @@ -3178,7 +3467,7 @@ em_update_eeprom_checksum(struct em_hw *hw) DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3376,7 +3665,7 @@ em_write_eeprom_microwire(struct em_hw *hw, em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2)); - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3410,7 +3699,7 @@ em_read_part_num(struct em_hw *hw, /* Save word 1 in lower half of part_num */ *part_num |= eeprom_data; - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3436,7 +3725,7 @@ em_read_mac_addr(struct em_hw * hw) hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF); hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } - if((hw->mac_type == em_82546) && + if(((hw->mac_type == em_82546) || (hw->mac_type == em_82546_rev_3)) && (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { if(hw->perm_mac_addr[5] & 0x01) hw->perm_mac_addr[5] &= ~(0x01); @@ -3445,7 +3734,7 @@ em_read_mac_addr(struct em_hw * hw) } for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3721,7 +4010,7 @@ em_id_led_init(struct em_hw * hw) if(hw->mac_type < em_82540) { /* Nothing to do */ - return 0; + return E1000_SUCCESS; } ledctl = E1000_READ_REG(hw, LEDCTL); @@ -3772,7 +4061,7 @@ em_id_led_init(struct em_hw * hw) break; } } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3784,49 +4073,48 @@ int32_t em_setup_led(struct em_hw *hw) { uint32_t ledctl; + int32_t ret_val = E1000_SUCCESS; DEBUGFUNC("em_setup_led"); - switch(hw->device_id) { - case E1000_DEV_ID_82542: - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544EI_FIBER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: + switch(hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + case em_82543: + case em_82544: /* No setup necessary */ break; - case E1000_DEV_ID_82545EM_FIBER: - case E1000_DEV_ID_82546EB_FIBER: - ledctl = E1000_READ_REG(hw, LEDCTL); - /* Save current LEDCTL settings */ - hw->ledctl_default = ledctl; - /* Turn off LED0 */ - ledctl &= ~(E1000_LEDCTL_LED0_IVRT | - E1000_LEDCTL_LED0_BLINK | - E1000_LEDCTL_LED0_MODE_MASK); - ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT); - E1000_WRITE_REG(hw, LEDCTL, ledctl); - break; - case E1000_DEV_ID_82540EP: - case E1000_DEV_ID_82540EP_LOM: - case E1000_DEV_ID_82540EP_LP: - case E1000_DEV_ID_82540EM: - case E1000_DEV_ID_82540EM_LOM: - case E1000_DEV_ID_82545EM_COPPER: - case E1000_DEV_ID_82546EB_COPPER: - case E1000_DEV_ID_82546EB_QUAD_COPPER: - case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541EP: - case E1000_DEV_ID_82547EI: - E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); - break; + case em_82541: + case em_82547: + case em_82541_rev_2: + case em_82547_rev_2: + /* Turn off PHY Smart Power Down (if enabled) */ + if((ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, + &hw->phy_spd_default))) + return ret_val; + if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, + (uint16_t)(hw->phy_spd_default & + ~IGP01E1000_GMII_SPD)))) + return ret_val; + /* Fall Through */ default: - DEBUGOUT("Invalid device ID\n"); - return -E1000_ERR_CONFIG; + if(hw->media_type == em_media_type_fiber) { + ledctl = E1000_READ_REG(hw, LEDCTL); + /* Save current LEDCTL settings */ + hw->ledctl_default = ledctl; + /* Turn off LED0 */ + ledctl &= ~(E1000_LEDCTL_LED0_IVRT | + E1000_LEDCTL_LED0_BLINK | + E1000_LEDCTL_LED0_MODE_MASK); + ledctl |= (E1000_LEDCTL_MODE_LED_OFF << + E1000_LEDCTL_LED0_MODE_SHIFT); + E1000_WRITE_REG(hw, LEDCTL, ledctl); + } else if(hw->media_type == em_media_type_copper) + E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); + break; } - return 0; + + return E1000_SUCCESS; } /****************************************************************************** @@ -3837,39 +4125,33 @@ em_setup_led(struct em_hw *hw) int32_t em_cleanup_led(struct em_hw *hw) { + int32_t ret_val = E1000_SUCCESS; + DEBUGFUNC("em_cleanup_led"); - switch(hw->device_id) { - case E1000_DEV_ID_82542: - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544EI_FIBER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: + switch(hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + case em_82543: + case em_82544: /* No cleanup necessary */ break; - case E1000_DEV_ID_82540EP: - case E1000_DEV_ID_82540EP_LOM: - case E1000_DEV_ID_82540EP_LP: - case E1000_DEV_ID_82540EM: - case E1000_DEV_ID_82540EM_LOM: - case E1000_DEV_ID_82545EM_COPPER: - case E1000_DEV_ID_82545EM_FIBER: - case E1000_DEV_ID_82546EB_COPPER: - case E1000_DEV_ID_82546EB_FIBER: - case E1000_DEV_ID_82546EB_QUAD_COPPER: - case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541EP: - case E1000_DEV_ID_82547EI: + case em_82541: + case em_82547: + case em_82541_rev_2: + case em_82547_rev_2: + /* Turn on PHY Smart Power Down (if previously enabled) */ + if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, + hw->phy_spd_default))) + return ret_val; + /* Fall Through */ + default: /* Restore LEDCTL settings */ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default); break; - default: - DEBUGOUT("Invalid device ID\n"); - return -E1000_ERR_CONFIG; } - return 0; + + return E1000_SUCCESS; } /****************************************************************************** @@ -3880,50 +4162,44 @@ em_cleanup_led(struct em_hw *hw) int32_t em_led_on(struct em_hw *hw) { - uint32_t ctrl; + uint32_t ctrl = E1000_READ_REG(hw, CTRL); DEBUGFUNC("em_led_on"); - switch(hw->device_id) { - case E1000_DEV_ID_82542: - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - case E1000_DEV_ID_82544EI_FIBER: - ctrl = E1000_READ_REG(hw, CTRL); + switch(hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + case em_82543: /* Set SW Defineable Pin 0 to turn on the LED */ ctrl |= E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, CTRL, ctrl); - break; - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: - case E1000_DEV_ID_82545EM_FIBER: - case E1000_DEV_ID_82546EB_FIBER: - ctrl = E1000_READ_REG(hw, CTRL); - /* Clear SW Defineable Pin 0 to turn on the LED */ - ctrl &= ~E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, CTRL, ctrl); break; - case E1000_DEV_ID_82540EP: - case E1000_DEV_ID_82540EP_LOM: - case E1000_DEV_ID_82540EP_LP: - case E1000_DEV_ID_82540EM: - case E1000_DEV_ID_82540EM_LOM: - case E1000_DEV_ID_82545EM_COPPER: - case E1000_DEV_ID_82546EB_COPPER: - case E1000_DEV_ID_82546EB_QUAD_COPPER: - case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541EP: - case E1000_DEV_ID_82547EI: - E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2); + case em_82544: + if(hw->media_type == em_media_type_fiber) { + /* Set SW Defineable Pin 0 to turn on the LED */ + ctrl |= E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + } else { + /* Clear SW Defineable Pin 0 to turn on the LED */ + ctrl &= ~E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + } break; default: - DEBUGOUT("Invalid device ID\n"); - return -E1000_ERR_CONFIG; + if(hw->media_type == em_media_type_fiber) { + /* Clear SW Defineable Pin 0 to turn on the LED */ + ctrl &= ~E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + } else if(hw->media_type == em_media_type_copper) { + E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2); + return E1000_SUCCESS; + } + break; } - return 0; + + E1000_WRITE_REG(hw, CTRL, ctrl); + + return E1000_SUCCESS; } /****************************************************************************** @@ -3934,50 +4210,44 @@ em_led_on(struct em_hw *hw) int32_t em_led_off(struct em_hw *hw) { - uint32_t ctrl; + uint32_t ctrl = E1000_READ_REG(hw, CTRL); DEBUGFUNC("em_led_off"); - switch(hw->device_id) { - case E1000_DEV_ID_82542: - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - case E1000_DEV_ID_82544EI_FIBER: - ctrl = E1000_READ_REG(hw, CTRL); + switch(hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + case em_82543: /* Clear SW Defineable Pin 0 to turn off the LED */ ctrl &= ~E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, CTRL, ctrl); - break; - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: - case E1000_DEV_ID_82545EM_FIBER: - case E1000_DEV_ID_82546EB_FIBER: - ctrl = E1000_READ_REG(hw, CTRL); - /* Set SW Defineable Pin 0 to turn off the LED */ - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, CTRL, ctrl); break; - case E1000_DEV_ID_82540EP: - case E1000_DEV_ID_82540EP_LOM: - case E1000_DEV_ID_82540EP_LP: - case E1000_DEV_ID_82540EM: - case E1000_DEV_ID_82540EM_LOM: - case E1000_DEV_ID_82545EM_COPPER: - case E1000_DEV_ID_82546EB_COPPER: - case E1000_DEV_ID_82546EB_QUAD_COPPER: - case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541EP: - case E1000_DEV_ID_82547EI: - E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); + case em_82544: + if(hw->media_type == em_media_type_fiber) { + /* Clear SW Defineable Pin 0 to turn off the LED */ + ctrl &= ~E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + } else { + /* Set SW Defineable Pin 0 to turn off the LED */ + ctrl |= E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + } break; default: - DEBUGOUT("Invalid device ID\n"); - return -E1000_ERR_CONFIG; + if(hw->media_type == em_media_type_fiber) { + /* Set SW Defineable Pin 0 to turn off the LED */ + ctrl |= E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + } else if(hw->media_type == em_media_type_copper) { + E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); + return E1000_SUCCESS; + } + break; } - return 0; + + E1000_WRITE_REG(hw, CTRL, ctrl); + + return E1000_SUCCESS; } /****************************************************************************** @@ -4100,8 +4370,7 @@ em_update_adaptive(struct em_hw *hw) DEBUGFUNC("em_update_adaptive"); if(hw->adaptive_ifs) { - if((hw->collision_delta * hw->ifs_ratio) > - hw->tx_packet_delta) { + if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) { if(hw->tx_packet_delta > MIN_NUM_XMITS) { hw->in_ifs_mode = TRUE; if(hw->current_ifs_val < hw->ifs_max_val) { @@ -4113,8 +4382,7 @@ em_update_adaptive(struct em_hw *hw) } } } else { - if((hw->in_ifs_mode == TRUE) && - (hw->tx_packet_delta <= MIN_NUM_XMITS)) { + if(hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) { hw->current_ifs_val = 0; hw->in_ifs_mode = FALSE; E1000_WRITE_REG(hw, AIT, 0); @@ -4297,7 +4565,8 @@ em_write_reg_io(struct em_hw *hw, * min_length - The estimated minimum length * max_length - The estimated maximum length * - * returns: E1000_SUCCESS / -E1000_ERR_XXX + * returns: - E1000_ERR_XXX + * E1000_SUCCESS * * This function always returns a ranged length (minimum & maximum). * So for M88 phy's, this function interprets the one value returned from the @@ -4305,9 +4574,11 @@ em_write_reg_io(struct em_hw *hw, * For IGP phy's, the function calculates the range by the AGC registers. *****************************************************************************/ int32_t -em_get_cable_length(struct em_hw *hw, uint16_t *min_length, +em_get_cable_length(struct em_hw *hw, + uint16_t *min_length, uint16_t *max_length) { + int32_t ret_val; uint16_t agc_value = 0; uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; uint16_t i, phy_data; @@ -4318,8 +4589,9 @@ em_get_cable_length(struct em_hw *hw, uint16_t *min_length, /* Use old method for Phy older than IGP */ if(hw->phy_type == em_phy_m88) { - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data))) + return ret_val; /* Convert the enum value to ranged values */ switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> @@ -4349,19 +4621,16 @@ em_get_cable_length(struct em_hw *hw, uint16_t *min_length, break; } } else if(hw->phy_type == em_phy_igp) { /* For IGP PHY */ - uint16_t agc_reg_array[IGP01E1000_PHY_AGC_NUM] = {IGP01E1000_PHY_AGC_A, + uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = + {IGP01E1000_PHY_AGC_A, IGP01E1000_PHY_AGC_B, IGP01E1000_PHY_AGC_C, IGP01E1000_PHY_AGC_D}; /* Read the AGC registers for all channels */ - for(i = 0; i < IGP01E1000_PHY_AGC_NUM; i++) { - if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, - agc_reg_array[i]) != E1000_SUCCESS) - return -E1000_ERR_PHY; - if(em_read_phy_reg(hw, agc_reg_array[i] & - IGP01E1000_PHY_PAGE_SELECT, &phy_data) != - E1000_SUCCESS) - return -E1000_ERR_PHY; + for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { + + if((ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data))) + return ret_val; cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; @@ -4377,20 +4646,15 @@ em_get_cable_length(struct em_hw *hw, uint16_t *min_length, min_agc = cur_agc; } - /* Return to page 0 */ - if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) != - E1000_SUCCESS) - return -E1000_ERR_PHY; - /* Remove the minimal AGC result for length < 50m */ - if(agc_value < IGP01E1000_PHY_AGC_NUM * em_igp_cable_length_50) { + if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * em_igp_cable_length_50) { agc_value -= min_agc; /* Get the average length of the remaining 3 channels */ - agc_value /= (IGP01E1000_PHY_AGC_NUM - 1); + agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1); } else { /* Get the average length of all the 4 channels. */ - agc_value /= IGP01E1000_PHY_AGC_NUM; + agc_value /= IGP01E1000_PHY_CHANNEL_NUM; } /* Set the range of the calculated length. */ @@ -4412,7 +4676,8 @@ em_get_cable_length(struct em_hw *hw, uint16_t *min_length, * polarity - output parameter : 0 - Polarity is not reversed * 1 - Polarity is reversed. * - * returns: E1000_SUCCESS / -E1000_ERR_XXX + * returns: - E1000_ERR_XXX + * E1000_SUCCESS * * For phy's older then IGP, this function simply reads the polarity bit in the * Phy Status register. For IGP phy's, this bit is valid only if link speed is @@ -4421,22 +4686,26 @@ em_get_cable_length(struct em_hw *hw, uint16_t *min_length, * IGP01E1000_PHY_PCS_INIT_REG. *****************************************************************************/ int32_t -em_check_polarity(struct em_hw *hw, uint16_t *polarity) +em_check_polarity(struct em_hw *hw, + uint16_t *polarity) { + int32_t ret_val; uint16_t phy_data; DEBUGFUNC("em_check_polarity"); if(hw->phy_type == em_phy_m88) { /* return the Polarity bit in the Status register. */ - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data))) + return ret_val; *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> M88E1000_PSSR_REV_POLARITY_SHIFT; } else if(hw->phy_type == em_phy_igp) { /* Read the Status register to check the speed */ - if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, + &phy_data))) + return ret_val; /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to * find the polarity status */ @@ -4444,18 +4713,9 @@ em_check_polarity(struct em_hw *hw, uint16_t *polarity) IGP01E1000_PSSR_SPEED_1000MBPS) { /* Read the GIG initialization PCS register (0x00B4) */ - if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, - IGP01E1000_PHY_PCS_INIT_REG) < 0) - return -E1000_ERR_PHY; - - if(em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG & - IGP01E1000_PHY_PAGE_SELECT, &phy_data) < 0) - return -E1000_ERR_PHY; - - /* Return to page 0 */ - if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) != - E1000_SUCCESS) - return -E1000_ERR_PHY; + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG, + &phy_data))) + return ret_val; /* Check the polarity bits */ *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0; @@ -4475,7 +4735,8 @@ em_check_polarity(struct em_hw *hw, uint16_t *polarity) * downshift - output parameter : 0 - No Downshift ocured. * 1 - Downshift ocured. * - * returns: E1000_SUCCESS / -E1000_ERR_XXX + * returns: - E1000_ERR_XXX + * E1000_SUCCESS * * For phy's older then IGP, this function reads the Downshift bit in the Phy * Specific Status register. For IGP phy's, it reads the Downgrade bit in the @@ -4485,25 +4746,358 @@ em_check_polarity(struct em_hw *hw, uint16_t *polarity) int32_t em_check_downshift(struct em_hw *hw) { + int32_t ret_val; uint16_t phy_data; DEBUGFUNC("em_check_downshift"); if(hw->phy_type == em_phy_igp) { - if(em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, + &phy_data))) + return ret_val; + hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0; } else if(hw->phy_type == em_phy_m88) { - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data))) + return ret_val; + hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> - M88E1000_PSSR_DOWNSHIFT_SHIFT; + M88E1000_PSSR_DOWNSHIFT_SHIFT; } return E1000_SUCCESS; } +/***************************************************************************** + * + * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a + * gigabit link is achieved to improve link quality. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_PHY if fail to read/write the PHY + * E1000_SUCCESS at any other case. + * + ****************************************************************************/ + +int32_t +em_config_dsp_after_link_change(struct em_hw *hw, + boolean_t link_up) +{ + int32_t ret_val; + uint16_t phy_data, speed, duplex, i; + uint16_t dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = + {IGP01E1000_PHY_AGC_PARAM_A, + IGP01E1000_PHY_AGC_PARAM_B, + IGP01E1000_PHY_AGC_PARAM_C, + IGP01E1000_PHY_AGC_PARAM_D}; + uint16_t min_length, max_length; + + DEBUGFUNC("em_config_dsp_after_link_change"); + + if(hw->phy_type != em_phy_igp) + return E1000_SUCCESS; + + if(link_up) { + if((ret_val = em_get_speed_and_duplex(hw, &speed, &duplex))) { + DEBUGOUT("Error getting link speed and duplex\n"); + return ret_val; + } + + if(speed == SPEED_1000) { + + em_get_cable_length(hw, &min_length, &max_length); + + if((hw->dsp_config_state == em_dsp_config_enabled) && + min_length >= em_igp_cable_length_50) { + + for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { + if((ret_val = em_read_phy_reg(hw, dsp_reg_array[i], + &phy_data))) + return ret_val; + + phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; + + if((ret_val = em_write_phy_reg(hw, dsp_reg_array[i], + phy_data))) + return ret_val; + } + hw->dsp_config_state = em_dsp_config_activated; + } + + if((hw->ffe_config_state == em_ffe_config_enabled) && + (min_length < em_igp_cable_length_50)) { + + uint16_t ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20; + uint32_t idle_errs = 0; + + /* clear previous idle error counts */ + if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, + &phy_data))) + return ret_val; + + for(i = 0; i < ffe_idle_err_timeout; i++) { + usec_delay(1000); + if((ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, + &phy_data))) + return ret_val; + + idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT); + if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) { + hw->ffe_config_state = em_ffe_config_active; + + if((ret_val = em_write_phy_reg(hw, + IGP01E1000_PHY_DSP_FFE, + IGP01E1000_PHY_DSP_FFE_CM_CP))) + return ret_val; + break; + } + + if(idle_errs) + ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_100; + } + } + } + } else { + if(hw->dsp_config_state == em_dsp_config_activated) { + if((ret_val = em_write_phy_reg(hw, 0x0000, + IGP01E1000_IEEE_FORCE_GIGA))) + return ret_val; + for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { + if((ret_val = em_read_phy_reg(hw, dsp_reg_array[i], + &phy_data))) + return ret_val; + + phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; + phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS; + + if((ret_val = em_write_phy_reg(hw,dsp_reg_array[i], + phy_data))) + return ret_val; + } + + if((ret_val = em_write_phy_reg(hw, 0x0000, + IGP01E1000_IEEE_RESTART_AUTONEG))) + return ret_val; + + hw->dsp_config_state = em_dsp_config_enabled; + } + + if(hw->ffe_config_state == em_ffe_config_active) { + if((ret_val = em_write_phy_reg(hw, 0x0000, + IGP01E1000_IEEE_FORCE_GIGA))) + return ret_val; + if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE, + IGP01E1000_PHY_DSP_FFE_DEFAULT))) + return ret_val; + + if((ret_val = em_write_phy_reg(hw, 0x0000, + IGP01E1000_IEEE_RESTART_AUTONEG))) + return ret_val; + hw->ffe_config_state = em_ffe_config_enabled; + } + } + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Workaround for the 82547 long TTL on noisy 100HD hubs. + * + * This function, specific to 82547 hardware only, needs to be called every + * second. It checks if a parallel detect fault has occurred. If a fault + * occurred, disable/enable the DSP reset mechanism up to 5 times (once per + * second). If link is established, stop the workaround and ensure the DSP + * reset is enabled. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_PHY if fail to read/write the PHY + * E1000_SUCCESS in any other case + * + ****************************************************************************/ +int32_t +em_igp_ttl_workaround(struct em_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data = 0; + uint16_t dsp_value = DSP_RESET_ENABLE; + + if(((hw->mac_type != em_82541) && (hw->mac_type != em_82547)) || + (!hw->ttl_wa_activation)) { + return E1000_SUCCESS; + } + + /* Check for link first */ + if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data))) + return ret_val; + + if(phy_data & MII_SR_LINK_STATUS) { + /* If link is established during the workaround, the DSP mechanism must + * be enabled. */ + if(hw->dsp_reset_counter) { + hw->dsp_reset_counter = 0; + dsp_value = DSP_RESET_ENABLE; + } else + return E1000_SUCCESS; + } else { + if(hw->dsp_reset_counter == 0) { + /* Workaround not activated, check if it needs activation */ + if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data))) + return ret_val; + /* Activate the workaround if there was a parallel detect fault */ + if(phy_data & NWAY_ER_PAR_DETECT_FAULT) + hw->dsp_reset_counter++; + else + return E1000_SUCCESS; + } + + if(hw->dsp_reset_counter) { + /* After 5 times, stop the workaround */ + if(hw->dsp_reset_counter > E1000_MAX_DSP_RESETS) { + hw->dsp_reset_counter = 0; + dsp_value = DSP_RESET_ENABLE; + } else { + dsp_value = (hw->dsp_reset_counter & 1) ? DSP_RESET_DISABLE : + DSP_RESET_ENABLE; + hw->dsp_reset_counter++; + } + } + } + + if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value))) + return ret_val; + + return E1000_SUCCESS; +} + +/***************************************************************************** + * + * This function sets the lplu 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 +em_set_d3_lplu_state(struct em_hw *hw, + boolean_t active) +{ + int32_t ret_val; + uint16_t phy_data; + DEBUGFUNC("em_set_d3_lplu_state"); + + if(!((hw->mac_type == em_82541_rev_2) || + (hw->mac_type == em_82547_rev_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 */ + if((ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data))) + return ret_val; + + if(!active) { + phy_data &= ~IGP01E1000_GMII_FLEX_SPD; + if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data))) + 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((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data))) + return ret_val; + + phy_data |= IGP01E1000_PSCFR_SMART_SPEED; + if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data))) + return ret_val; + + } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) || + (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) || + (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) { + + phy_data |= IGP01E1000_GMII_FLEX_SPD; + if((ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data))) + return ret_val; + + /* When LPLU is enabled we should disable SmartSpeed */ + if((ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data))) + return ret_val; + + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data))) + return ret_val; + + } + return E1000_SUCCESS; +} + +/****************************************************************************** + * Change VCO speed register to improve Bit Error Rate performance of SERDES. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +static int32_t +em_set_vco_speed(struct em_hw *hw) +{ + int32_t ret_val; + uint16_t default_page = 0; + uint16_t phy_data; + + DEBUGFUNC("em_set_vco_speed"); + + switch(hw->mac_type) { + case em_82545_rev_3: + case em_82546_rev_3: + break; + default: + return E1000_SUCCESS; + } + + /* Set PHY register 30, page 5, bit 8 to 0 */ + + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + &default_page))) + return ret_val; + + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005))) + return ret_val; + + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data))) + return ret_val; + + phy_data &= ~M88E1000_PHY_VCO_REG_BIT8; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data))) + return ret_val; + + /* Set PHY register 30, page 4, bit 11 to 1 */ + + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004))) + return ret_val; + + if((ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data))) + return ret_val; + + phy_data |= M88E1000_PHY_VCO_REG_BIT11; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data))) + return ret_val; + + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + default_page))) + return ret_val; + + return E1000_SUCCESS; +} + diff --git a/sys/dev/em/if_em_hw.h b/sys/dev/em/if_em_hw.h index 7258599..d187e7b 100644 --- a/sys/dev/em/if_em_hw.h +++ b/sys/dev/em/if_em_hw.h @@ -41,6 +41,7 @@ #include <dev/em/if_em_osdep.h> + /* Forward declarations of structures used by the shared code */ struct em_hw; struct em_hw_stats; @@ -55,9 +56,13 @@ typedef enum { em_82544, em_82540, em_82545, + em_82545_rev_3, em_82546, + em_82546_rev_3, em_82541, + em_82541_rev_2, em_82547, + em_82547_rev_2, em_num_macs } em_mac_type; @@ -72,6 +77,7 @@ typedef enum { typedef enum { em_media_type_copper = 0, em_media_type_fiber = 1, + em_media_type_internal_serdes = 2, em_num_media_types } em_media_type; @@ -95,7 +101,8 @@ typedef enum { typedef enum { em_bus_type_unknown = 0, em_bus_type_pci, - em_bus_type_pcix + em_bus_type_pcix, + em_bus_type_reserved } em_bus_type; /* PCI bus speeds */ @@ -113,7 +120,8 @@ typedef enum { typedef enum { em_bus_width_unknown = 0, em_bus_width_32, - em_bus_width_64 + em_bus_width_64, + em_bus_width_reserved } em_bus_width; /* PHY status info structure and supporting enums */ @@ -191,6 +199,26 @@ typedef enum { em_phy_undefined = 0xFF } em_phy_type; +typedef enum { + em_ms_hw_default = 0, + em_ms_force_master, + em_ms_force_slave, + em_ms_auto +} em_ms_type; + +typedef enum { + em_ffe_config_enabled = 0, + em_ffe_config_active, + em_ffe_config_blocked +} em_ffe_config; + +typedef enum { + em_dsp_config_disabled = 0, + em_dsp_config_enabled, + em_dsp_config_activated, + em_dsp_config_undefined = 0xFF +} em_dsp_config; + struct em_phy_info { em_cable_length cable_length; em_10bt_ext_dist_enable extended_10bt_distance; @@ -229,9 +257,10 @@ struct em_eeprom_info { /* Function prototypes */ /* Initialization */ -void em_reset_hw(struct em_hw *hw); +int32_t em_reset_hw(struct em_hw *hw); int32_t em_init_hw(struct em_hw *hw); int32_t em_set_mac_type(struct em_hw *hw); +void em_set_media_type(struct em_hw *hw); /* Link Configuration */ int32_t em_setup_link(struct em_hw *hw); @@ -239,8 +268,9 @@ int32_t em_phy_setup_autoneg(struct em_hw *hw); void em_config_collision_dist(struct em_hw *hw); int32_t em_config_fc_after_link_up(struct em_hw *hw); int32_t em_check_for_link(struct em_hw *hw); -void em_get_speed_and_duplex(struct em_hw *hw, uint16_t * speed, uint16_t * duplex); +int32_t em_get_speed_and_duplex(struct em_hw *hw, uint16_t * speed, uint16_t * duplex); int32_t em_wait_autoneg(struct em_hw *hw); +int32_t em_force_mac_fc(struct em_hw *hw); /* PHY */ int32_t em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data); @@ -297,6 +327,9 @@ uint32_t em_io_read(struct em_hw *hw, uint32_t port); uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset); void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value); void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); +int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up); +int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active); +int32_t em_igp_ttl_workaround(struct em_hw *hw); #define E1000_READ_REG_IO(a, reg) \ em_read_reg_io((a), E1000_##reg) @@ -318,13 +351,22 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); #define E1000_DEV_ID_82540EP_LP 0x101E #define E1000_DEV_ID_82545EM_COPPER 0x100F #define E1000_DEV_ID_82545EM_FIBER 0x1011 +#define E1000_DEV_ID_82545GM_COPPER 0x1026 +#define E1000_DEV_ID_82545GM_FIBER 0x1027 +#define E1000_DEV_ID_82545GM_SERDES 0x1028 #define E1000_DEV_ID_82546EB_COPPER 0x1010 #define E1000_DEV_ID_82546EB_FIBER 0x1012 #define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D #define E1000_DEV_ID_82541EI 0x1013 -#define E1000_DEV_ID_82541EP 0x1018 +#define E1000_DEV_ID_82541EI_MOBILE 0x1018 +#define E1000_DEV_ID_82541ER 0x1078 +#define E1000_DEV_ID_82547GI 0x1075 +#define E1000_DEV_ID_82541GI 0x1076 +#define E1000_DEV_ID_82541GI_MOBILE 0x1077 +#define E1000_DEV_ID_82546GB_COPPER 0x1079 +#define E1000_DEV_ID_82546GB_FIBER 0x107A +#define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82547EI 0x1019 -#define NUM_DEV_IDS 20 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -390,7 +432,7 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); E1000_IMS_RXSEQ | \ E1000_IMS_LSC) -/* The number of high/low register pairs in the RAR. The RAR (Receive Address +/* Number of high/low register pairs in the RAR. The RAR (Receive Address * Registers) holds the directed and multicast addresses that we monitor. We * reserve one of these spots for our directed address, allowing us room for * E1000_RAR_ENTRIES - 1 multicast addresses. @@ -544,7 +586,7 @@ struct em_rar { volatile uint32_t high; /* receive address high */ }; -/* The number of entries in the Multicast Table Array (MTA). */ +/* Number of entries in the Multicast Table Array (MTA). */ #define E1000_NUM_MTA_REGISTERS 128 /* IPv4 Address Table Entry */ @@ -604,6 +646,7 @@ struct em_ffvt_entry { * A - register array */ #define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ #define E1000_STATUS 0x00008 /* Device Status - RO */ #define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ #define E1000_EERD 0x00014 /* EEPROM Read - RW */ @@ -939,6 +982,9 @@ struct em_hw { em_bus_width bus_width; em_bus_type bus_type; struct em_eeprom_info eeprom; + em_ms_type master_slave; + em_ms_type original_master_slave; + em_ffe_config ffe_config_state; uint32_t io_base; uint32_t phy_id; uint32_t phy_revision; @@ -955,6 +1001,8 @@ struct em_hw { uint32_t ledctl_default; uint32_t ledctl_mode1; uint32_t ledctl_mode2; + uint16_t phy_spd_default; + uint16_t dsp_reset_counter; uint16_t autoneg_advertised; uint16_t pci_cmd_word; uint16_t fc_high_water; @@ -979,10 +1027,14 @@ struct em_hw { uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; boolean_t disable_polarity_correction; boolean_t speed_downgraded; + boolean_t ttl_wa_activation; + em_dsp_config dsp_config_state; boolean_t get_link_status; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; + boolean_t phy_reset_disable; boolean_t fc_send_xon; + boolean_t fc_strict_ieee; boolean_t report_tx_early; boolean_t adaptive_ifs; boolean_t ifs_params_forced; @@ -1064,7 +1116,7 @@ struct em_hw { #define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ #define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ #define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type - * (0-small, 1-large) */ + * (0-small, 1-large) */ #define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */ #ifndef E1000_EEPROM_GRANT_ATTEMPTS #define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ @@ -1126,22 +1178,22 @@ struct em_hw { #define E1000_MDIC_ERROR 0x40000000 /* LED Control */ -#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F -#define E1000_LEDCTL_LED0_MODE_SHIFT 0 -#define E1000_LEDCTL_LED0_IVRT 0x00000040 -#define E1000_LEDCTL_LED0_BLINK 0x00000080 -#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 -#define E1000_LEDCTL_LED1_MODE_SHIFT 8 -#define E1000_LEDCTL_LED1_IVRT 0x00004000 -#define E1000_LEDCTL_LED1_BLINK 0x00008000 -#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 -#define E1000_LEDCTL_LED2_MODE_SHIFT 16 -#define E1000_LEDCTL_LED2_IVRT 0x00400000 -#define E1000_LEDCTL_LED2_BLINK 0x00800000 -#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 -#define E1000_LEDCTL_LED3_MODE_SHIFT 24 -#define E1000_LEDCTL_LED3_IVRT 0x40000000 -#define E1000_LEDCTL_LED3_BLINK 0x80000000 +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 +#define E1000_LEDCTL_LED1_MODE_SHIFT 8 +#define E1000_LEDCTL_LED1_IVRT 0x00004000 +#define E1000_LEDCTL_LED1_BLINK 0x00008000 +#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 +#define E1000_LEDCTL_LED2_MODE_SHIFT 16 +#define E1000_LEDCTL_LED2_IVRT 0x00400000 +#define E1000_LEDCTL_LED2_BLINK 0x00800000 +#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 +#define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_IVRT 0x40000000 +#define E1000_LEDCTL_LED3_BLINK 0x80000000 #define E1000_LEDCTL_MODE_LINK_10_1000 0x0 #define E1000_LEDCTL_MODE_LINK_100_1000 0x1 @@ -1164,109 +1216,109 @@ struct em_hw { #define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ /* Interrupt Cause Read */ -#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ -#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ -#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ -#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ -#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ -#define E1000_ICR_RXO 0x00000040 /* rx overrun */ -#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ -#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ -#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ -#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ -#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ -#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ -#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ -#define E1000_ICR_TXD_LOW 0x00008000 -#define E1000_ICR_SRPD 0x00010000 +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 /* Interrupt Cause Set */ -#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ -#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ -#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_ICS_SRPD E1000_ICR_SRPD +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_ICS_SRPD E1000_ICR_SRPD /* Interrupt Mask Set */ -#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ -#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ -#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_IMS_SRPD E1000_ICR_SRPD +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMS_SRPD E1000_ICR_SRPD /* Interrupt Mask Clear */ -#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ -#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ -#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_IMC_SRPD E1000_ICR_SRPD +#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMC_SRPD E1000_ICR_SRPD /* Receive Control */ -#define E1000_RCTL_RST 0x00000001 /* Software reset */ -#define E1000_RCTL_EN 0x00000002 /* enable */ -#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ -#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ -#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ -#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ -#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ -#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ -#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ -#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ -#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ -#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ -#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ -#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ -#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ -#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ -#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ -#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ -#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ -#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ /* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ -#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ -#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ -#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ -#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ /* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ -#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ -#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ -#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ -#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ -#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ -#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ -#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ -#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ -#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ @@ -1431,15 +1483,17 @@ struct em_hw { #define EEPROM_SIZE_128B 0x0000 #define EEPROM_SIZE_MASK 0x1C00 - /* EEPROM Word Offsets */ -#define EEPROM_COMPAT 0x0003 -#define EEPROM_ID_LED_SETTINGS 0x0004 -#define EEPROM_INIT_CONTROL1_REG 0x000A -#define EEPROM_INIT_CONTROL2_REG 0x000F -#define EEPROM_CFG 0x0012 -#define EEPROM_FLASH_VERSION 0x0032 -#define EEPROM_CHECKSUM_REG 0x003F +#define EEPROM_COMPAT 0x0003 +#define EEPROM_ID_LED_SETTINGS 0x0004 +#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ +#define EEPROM_INIT_CONTROL1_REG 0x000A +#define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_INIT_CONTROL3_PORT_B 0x0014 +#define EEPROM_INIT_CONTROL3_PORT_A 0x0024 +#define EEPROM_CFG 0x0012 +#define EEPROM_FLASH_VERSION 0x0032 +#define EEPROM_CHECKSUM_REG 0x003F /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_0000 0x0000 @@ -1463,6 +1517,9 @@ struct em_hw { #define IGP_LED3_MODE 0x07000000 +/* Mask bits for SERDES amplitude adjustment in Word 6 of the EEPROM */ +#define EEPROM_SERDES_AMPLITUDE_MASK 0x000F + /* Mask bits for fields in Word 0x0a of the EEPROM */ #define EEPROM_WORD0A_ILOS 0x0010 #define EEPROM_WORD0A_SWDPIO 0x01E0 @@ -1484,6 +1541,8 @@ struct em_hw { #define EEPROM_NODE_ADDRESS_BYTE_0 0 #define EEPROM_PBA_BYTE_1 8 +#define EEPROM_RESERVED_WORD 0xFFFF + /* EEPROM Map Sizes (Byte Counts) */ #define PBA_SIZE 4 @@ -1495,7 +1554,7 @@ struct em_hw { #define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE #define E1000_COLD_SHIFT 12 -/* The number of Transmit and Receive Descriptors must be a multiple of 8 */ +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ #define REQ_TX_DESCRIPTOR_MULTIPLE 8 #define REQ_RX_DESCRIPTOR_MULTIPLE 8 @@ -1562,35 +1621,30 @@ struct em_hw { #define PCIX_STATUS_HI_MMRBC_2K 0x2 -/* The number of bits that we need to shift right to move the "pause" - * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field - * in the TXCW register +/* Number of bits required to shift right the "pause" bits from the + * EEPROM (bits 13:12) to the "pause" (bits 8:7) field in the TXCW register. */ #define PAUSE_SHIFT 5 -/* The number of bits that we need to shift left to move the "SWDPIO" - * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field - * in the CTRL register +/* Number of bits required to shift left the "SWDPIO" bits from the + * EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field in the CTRL register. */ #define SWDPIO_SHIFT 17 -/* The number of bits that we need to shift left to move the "SWDPIO_EXT" - * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The - * Extended CTRL register. - * in the CTRL register +/* Number of bits required to shift left the "SWDPIO_EXT" bits from the + * EEPROM word F (bits 7:4) to the bits 11:8 of The Extended CTRL register. */ #define SWDPIO__EXT_SHIFT 4 -/* The number of bits that we need to shift left to move the "ILOS" - * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field - * in the CTRL register +/* Number of bits required to shift left the "ILOS" bit from the EEPROM + * (bit 4) to the "ILOS" (bit 7) field in the CTRL register. */ #define ILOS_SHIFT 3 #define RECEIVE_BUFFER_ALIGN_SIZE (256) -/* The number of milliseconds we wait for auto-negotiation to complete */ +/* Number of milliseconds we wait for auto-negotiation to complete */ #define LINK_UP_TIMEOUT 500 #define E1000_TX_BUFFER_SIZE ((uint32_t)1514) @@ -1673,6 +1727,16 @@ struct em_hw { #define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ #define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ +#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ +#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ +#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ +#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ +#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ + +#define IGP01E1000_IEEE_REGS_PAGE 0x0000 +#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300 +#define IGP01E1000_IEEE_FORCE_GIGA 0x0140 + /* IGP01E1000 Specific Registers */ #define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */ #define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */ @@ -1688,16 +1752,35 @@ struct em_hw { #define IGP01E1000_PHY_AGC_C 0x1472 #define IGP01E1000_PHY_AGC_D 0x1872 -/* Number of AGC registers */ -#define IGP01E1000_PHY_AGC_NUM 4 +/* IGP01E1000 DSP Reset Register */ +#define IGP01E1000_PHY_DSP_RESET 0x1F33 +#define IGP01E1000_PHY_DSP_SET 0x1F71 +#define IGP01E1000_PHY_DSP_FFE 0x1F35 + +#define IGP01E1000_PHY_CHANNEL_NUM 4 +#define IGP01E1000_PHY_AGC_PARAM_A 0x1171 +#define IGP01E1000_PHY_AGC_PARAM_B 0x1271 +#define IGP01E1000_PHY_AGC_PARAM_C 0x1471 +#define IGP01E1000_PHY_AGC_PARAM_D 0x1871 + +#define IGP01E1000_PHY_EDAC_MU_INDEX 0xC000 +#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS 0x8000 +#define IGP01E1000_PHY_ANALOG_TX_STATE 0x2890 +#define IGP01E1000_PHY_ANALOG_CLASS_A 0x2000 +#define IGP01E1000_PHY_FORCE_ANALOG_ENABLE 0x0004 +#define IGP01E1000_PHY_DSP_FFE_CM_CP 0x0069 + +#define IGP01E1000_PHY_DSP_FFE_DEFAULT 0x002A /* IGP01E1000 PCS Initialization register - stores the polarity status when * speed = 1000 Mbps. */ #define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 +#define IGP01E1000_PHY_PCS_CTRL_REG 0x00B5 +#define IGP01E1000_ANALOG_REGS_PAGE 0x20C0 #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ - +#define MAX_PHY_MULTI_PAGE_REG 0xF /*Registers that are equal on all pages*/ /* PHY Control Register */ #define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ #define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ @@ -1811,8 +1894,11 @@ struct em_hw { #define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ #define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ #define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ -#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 -#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 +#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_20 20 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_100 100 /* Extended Status Register */ #define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ @@ -1904,7 +1990,6 @@ struct em_hw { #define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ #define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ - /* IGP01E1000 Specific Port Config Register - R/W */ #define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010 #define IGP01E1000_PSCFR_PRE_EN 0x0020 @@ -1955,6 +2040,11 @@ struct em_hw { #define IGP01E1000_MSE_CHANNEL_B 0x0F00 #define IGP01E1000_MSE_CHANNEL_A 0xF000 +/* IGP01E1000 DSP reset macros */ +#define DSP_RESET_ENABLE 0x0 +#define DSP_RESET_DISABLE 0x2 +#define E1000_MAX_DSP_RESETS 10 + /* IGP01E1000 AGC Registers */ #define IGP01E1000_AGC_LENGTH_SHIFT 7 /* Coarse - 13:11, Fine - 10:7 */ @@ -1965,18 +2055,6 @@ struct em_hw { /* The precision of the length is +/- 10 meters */ #define IGP01E1000_AGC_RANGE 10 -/* IGP cable length table */ -static const -uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = - { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25, - 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90, - 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, - 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}; - /* IGP01E1000 PCS Initialization register */ /* bits 3:6 in the PCS registers stores the channels polarity */ #define IGP01E1000_PHY_POLARITY_MASK 0x0078 @@ -1986,6 +2064,23 @@ uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = * on Link-Up */ #define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */ +/* IGP01E1000 Analog Register */ +#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS 0x20D1 +#define IGP01E1000_ANALOG_FUSE_STATUS 0x20D0 +#define IGP01E1000_ANALOG_FUSE_CONTROL 0x20DC +#define IGP01E1000_ANALOG_FUSE_BYPASS 0x20DE + +#define IGP01E1000_ANALOG_FUSE_POLY_MASK 0xF000 +#define IGP01E1000_ANALOG_FUSE_FINE_MASK 0x0F80 +#define IGP01E1000_ANALOG_FUSE_COARSE_MASK 0x0070 +#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED 0x0100 +#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002 + +#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH 0x0040 +#define IGP01E1000_ANALOG_FUSE_COARSE_10 0x0010 +#define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080 +#define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500 + /* Bit definitions for valid PHY IDs. */ #define M88E1000_E_PHY_ID 0x01410C50 #define M88E1000_I_PHY_ID 0x01410C30 @@ -2019,5 +2114,14 @@ uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = #define ADVERTISE_1000_HALF 0x0010 #define ADVERTISE_1000_FULL 0x0020 #define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ +#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds*/ +#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds*/ + +#define TANAX_TTL_WA_RESET(hw) { \ + if((hw)->dsp_reset_counter) { \ + em_write_phy_reg((hw), IGP01E1000_PHY_DSP_RESET, 0x0000); \ + (hw)->dsp_reset_counter = 0; \ + } \ +} #endif /* _EM_HW_H_ */ |