From: Matthew Dillon Date: Wed, 17 Mar 2004 04:59:41 +0000 (+0000) Subject: Update the 825xx GigE support. Add a large number of new device id's and X-Git-Tag: v2.0.1~11757 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/0d366ee792bcfc422fe063addc28aa3ca559501c Update the 825xx GigE support. Add a large number of new device id's and support for the 82541 (e.g. Intel PRO/1000 MT DESKTOP ADAPTER) and 82544. Also add sysctl support for various interrupt related delay parameters, and add workarounds for chip issues. In-Discussion-With: "Peter Avalos" Submitted-by: Hiten Pandya Adapted-from: FreeBSD-5 --- diff --git a/sys/dev/netif/em/LICENSE b/sys/dev/netif/em/LICENSE index 43f78ab6ad..fca1b9bc9b 100644 --- a/sys/dev/netif/em/LICENSE +++ b/sys/dev/netif/em/LICENSE @@ -1,5 +1,5 @@ $FreeBSD: src/sys/dev/em/LICENSE,v 1.1.2.2 2003/04/04 18:39:28 pdeuskar Exp $ -$DragonFly: src/sys/dev/netif/em/LICENSE,v 1.2 2003/06/17 04:28:24 dillon Exp $ +$DragonFly: src/sys/dev/netif/em/LICENSE,v 1.3 2004/03/17 04:59:41 dillon Exp $ Copyright (c) 2001-2003, Intel Corporation All rights reserved. diff --git a/sys/dev/netif/em/README b/sys/dev/netif/em/README index 7c29dd9c1c..35b64fa6d2 100644 --- a/sys/dev/netif/em/README +++ b/sys/dev/netif/em/README @@ -1,9 +1,9 @@ $FreeBSD: src/sys/dev/em/README,v 1.1.2.7 2003/06/09 21:43:41 pdeuskar Exp $ -$DragonFly: src/sys/dev/netif/em/README,v 1.2 2003/06/17 04:28:24 dillon Exp $ +$DragonFly: src/sys/dev/netif/em/README,v 1.3 2004/03/17 04:59:41 dillon Exp $ FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters ============================================================ -April 13, 2003 +July 24, 2003 Contents @@ -22,7 +22,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. @@ -52,9 +52,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 @@ -68,6 +69,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 @@ -282,8 +284,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/netif/em/if_em.c b/sys/dev/netif/em/if_em.c index 240c088d33..a2e61b5fda 100644 --- a/sys/dev/netif/em/if_em.c +++ b/sys/dev/netif/em/if_em.c @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ /*$FreeBSD: src/sys/dev/em/if_em.c,v 1.2.2.15 2003/06/09 22:10:15 pdeuskar Exp $*/ -/*$DragonFly: src/sys/dev/netif/em/if_em.c,v 1.7 2004/03/14 15:36:49 joerg Exp $*/ +/*$DragonFly: src/sys/dev/netif/em/if_em.c,v 1.8 2004/03/17 04:59:41 dillon Exp $*/ #include "if_em.h" @@ -52,7 +52,7 @@ struct adapter *em_adapter_list = NULL; * Driver version *********************************************************************/ -char em_driver_version[] = "1.6.6"; +char em_driver_version[] = "1.7.25"; /********************************************************************* @@ -88,8 +88,18 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0}, { 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, 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} }; @@ -161,6 +171,13 @@ 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 *, + int, int); /********************************************************************* * FreeBSD Device Interface Entry Points @@ -184,6 +201,36 @@ static devclass_t em_devclass; DECLARE_DUMMY_MODULE(if_em); DRIVER_MODULE(if_em, pci, em_driver, em_devclass, 0, 0); +/********************************************************************* + * Tunable default values. + *********************************************************************/ + +#define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) +#define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) + +static int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV); +static int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR); +static int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV); +static int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV); + +TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); +TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt); +TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt); +TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt); + +/* sysctl vars */ +/* +SYSCTL_INT(_hw, OID_AUTO, em_tx_int_delay, CTLFLAG_RD, &em_tx_int_delay_dflt, 0, + "Transmit interrupt delay"); +SYSCTL_INT(_hw, OID_AUTO, em_rx_int_delay, CTLFLAG_RD, &em_rx_int_delay_dflt, 0, + "Receive interrupt delay"); +SYSCTL_INT(_hw, OID_AUTO, em_tx_abs_int_delay, CTLFLAG_RD, &em_tx_abs_int_delay_dflt, + 0, "Transmit absolute interrupt delay"); +SYSCT_INT(_hw, OID_AUTO, em_rx_ans_int_delay, CTLFLAG_RD, &em_rx_abs_int_delay_dflt, + 0, + "Receive absolute interrupt delay"); +*/ + /********************************************************************* * Device identification routine * @@ -281,6 +328,7 @@ em_attach(device_t dev) device_get_nameunit(dev), CTLFLAG_RD, 0, ""); + if (adapter->sysctl_tree == NULL) { error = EIO; goto err_sysctl; @@ -303,14 +351,30 @@ em_attach(device_t dev) /* Determine hardware revision */ em_identify_hardware(adapter); - + + /* Set up some sysctls for the tunable interrupt delays */ + em_add_int_delay_sysctl(adapter, "rx_int_delay", + "receive interrupt delay in usecs", &adapter->rx_int_delay, + E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_int_delay", + "transmit interrupt delay in usecs", &adapter->tx_int_delay, + E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt); + if (adapter->hw.mac_type >= em_82540) { + em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", + "receive interrupt delay limit in usecs", + &adapter->rx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, RADV), + em_rx_abs_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", + "transmit interrupt delay limit in usecs", + &adapter->tx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, TADV), + em_tx_abs_int_delay_dflt); + } + /* Parameters (to be read from user) */ adapter->num_tx_desc = EM_MAX_TXD; adapter->num_rx_desc = EM_MAX_RXD; - adapter->tx_int_delay = EM_TIDV; - adapter->tx_abs_int_delay = EM_TADV; - adapter->rx_int_delay = EM_RDTR; - adapter->rx_abs_int_delay = EM_RADV; adapter->hw.autoneg = DO_AUTO_NEG; adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; @@ -328,6 +392,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 @@ -427,6 +498,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(error); @@ -467,10 +547,13 @@ em_detach(device_t dev) INIT_DEBUGOUT("em_detach: begin"); s = splimp(); + adapter->in_detach = 1; + em_stop(adapter); em_phy_hw_reset(&adapter->hw); ether_ifdetach(&adapter->interface_data.ac_if); em_free_pci_resources(adapter); + bus_generic_detach(dev); size = EM_ROUNDUP(adapter->num_tx_desc * sizeof(struct em_tx_desc), 4096); @@ -504,6 +587,9 @@ em_detach(device_t dev) adapter->sysctl_tree = NULL; sysctl_ctx_free(&adapter->sysctl_ctx); + adapter->sysctl_tree = NULL; + sysctl_ctx_free(&adapter->sysctl_ctx); + splx(s); return(0); } @@ -589,6 +675,9 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) struct adapter * adapter = ifp->if_softc; s = splimp(); + + if (adapter->in_detach) goto out; + switch (command) { case SIOCSIFADDR: case SIOCGIFADDR: @@ -609,9 +698,9 @@ 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)) { em_init(adapter); - + } em_disable_promisc(adapter); em_set_promisc(adapter); } else { @@ -630,7 +719,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) em_initialize_receive_unit(adapter); } #ifdef DEVICE_POLLING - if (!(ifp->if_ipending & IFF_POLLING)) + if (!(ifp->if_flags & IFF_POLLING)) #endif em_enable_intr(adapter); } @@ -653,10 +742,11 @@ 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; } +out: splx(s); return(error); } @@ -682,7 +772,8 @@ em_watchdog(struct ifnet *ifp) return; } - printf("em%d: watchdog timeout -- resetting\n", adapter->unit); + if (em_check_for_link(&adapter->hw)) + printf("em%d: watchdog timeout -- resetting\n", adapter->unit); ifp->if_flags &= ~IFF_RUNNING; @@ -717,6 +808,10 @@ em_init(void *arg) em_stop(adapter); + /* Get the latest mac address, User can use a LAA */ + bcopy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr, + ETHER_ADDR_LEN); + /* Initialize the hardware */ if (em_hardware_init(adapter)) { printf("em%d: Unable to initialize the hardware\n", @@ -749,6 +844,9 @@ em_init(void *arg) return; } em_initialize_receive_unit(adapter); + + /* Don't loose promiscuous settings */ + em_set_promisc(adapter); ifp = &adapter->interface_data.ac_if; ifp->if_flags |= IFF_RUNNING; @@ -772,7 +870,10 @@ em_init(void *arg) em_disable_intr(adapter); else #endif /* DEVICE_POLLING */ - em_enable_intr(adapter); + em_enable_intr(adapter); + + /* Don't reset the phy next time init gets called */ + adapter->hw.phy_reset_disable = TRUE; splx(s); return; @@ -987,6 +1088,10 @@ em_media_change(struct ifnet *ifp) default: printf("em%d: Unsupported media type\n", adapter->unit); } + /* As the speed/duplex settings my have changed we nee to + * reset the PHY. + */ + adapter->hw.phy_reset_disable = FALSE; em_init(adapter); @@ -1012,6 +1117,12 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) u_int32_t txd_lower; int txd_used, i, txd_saved; struct mbuf *mp; + u_int64_t address; + +/* For 82544 Workaround */ + DESC_ARRAY desc_array; + u_int32_t array_elements; + u_int32_t counter; #if defined(__DragonFly__) || __FreeBSD_version < 500000 struct ifvlan *ifv = NULL; @@ -1058,29 +1169,61 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) for (mp = m_head; mp != NULL; mp = mp->m_next) { if (mp->m_len == 0) continue; + /* If adapter is 82544 and on PCIX bus */ + if(adapter->pcix_82544) { + array_elements = 0; + virtual_addr= mtod(mp, vm_offset_t); + address = vtophys(virtual_addr); + /* Check the Address and Length combination and split the data accordingly */ + array_elements = em_fill_descriptors( + address, + mp->m_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++; + return (ENOBUFS); + } + + tx_buffer = &adapter->tx_buffer_area[i]; + current_tx_desc = &adapter->tx_desc_base[i]; + /* Put in the buffer address*/ + current_tx_desc->buffer_addr = desc_array.descriptor[counter].address; + /* Put in the length */ + current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower + | (u_int16_t)desc_array.descriptor[counter].length); + current_tx_desc->upper.data = (txd_upper); + if (++i == adapter->num_tx_desc) + i = 0; + tx_buffer->m_head = NULL; + txd_used++; + } + } + else { + if (txd_used == adapter->num_tx_desc_avail) { + adapter->next_avail_tx_desc = txd_saved; + adapter->no_tx_desc_avail2++; + return (ENOBUFS); + } - if (txd_used == adapter->num_tx_desc_avail) { - adapter->next_avail_tx_desc = txd_saved; - adapter->no_tx_desc_avail2++; - return (ENOBUFS); - } - - tx_buffer = &adapter->tx_buffer_area[i]; - current_tx_desc = &adapter->tx_desc_base[i]; - virtual_addr = mtod(mp, vm_offset_t); - current_tx_desc->buffer_addr = vtophys(virtual_addr); - - current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower | mp->m_len); - current_tx_desc->upper.data = (txd_upper); - - if (++i == adapter->num_tx_desc) - i = 0; + tx_buffer = &adapter->tx_buffer_area[i]; + current_tx_desc = &adapter->tx_desc_base[i]; + virtual_addr = mtod(mp, vm_offset_t); + current_tx_desc->buffer_addr = vtophys(virtual_addr); + + current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower | mp->m_len); + current_tx_desc->upper.data = (txd_upper); - tx_buffer->m_head = NULL; + if (++i == adapter->num_tx_desc) + i = 0; - txd_used++; + tx_buffer->m_head = NULL; + + txd_used++; + } } - adapter->num_tx_desc_avail -= txd_used; adapter->next_avail_tx_desc = i; @@ -1332,7 +1475,7 @@ em_set_multi(struct adapter * adapter) reg_rctl |= E1000_RCTL_MPE; E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); } else - em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0); + em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1); if (adapter->hw.mac_type == em_82542_rev2_0) { reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); @@ -1421,7 +1564,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); @@ -1467,8 +1610,13 @@ em_identify_hardware(struct adapter * adapter) adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2); /* Identify the MAC */ - if (em_set_mac_type(&adapter->hw)) - printf("em%d: Unknown MAC Type\n", adapter->unit); + 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; } @@ -1494,7 +1642,6 @@ em_allocate_pci_resources(struct adapter * adapter) rman_get_bushandle(adapter->res_memory); adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle; - if (adapter->hw.mac_type > em_82543) { /* Figure our where our IO BAR is ? */ rid = EM_MMBA; @@ -1576,6 +1723,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); @@ -1854,9 +2002,9 @@ em_initialize_transmit_unit(struct adapter * adapter) } E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg); - E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); + E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay.value); if(adapter->hw.mac_type >= em_82540) - E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay); + E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay.value); /* Program the Transmit Control Register */ reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | @@ -1871,7 +2019,7 @@ em_initialize_transmit_unit(struct adapter * adapter) /* Setup Transmit Descriptor Settings for this adapter */ adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS; - if (adapter->tx_int_delay > 0) + if (adapter->tx_int_delay.value > 0) adapter->txd_cmd |= E1000_TXD_CMD_IDE; return; @@ -2177,10 +2325,10 @@ em_initialize_receive_unit(struct adapter * adapter) /* Set the Receive Delay Timer Register */ E1000_WRITE_REG(&adapter->hw, RDTR, - adapter->rx_int_delay | E1000_RDT_FPDB); + adapter->rx_int_delay.value | E1000_RDT_FPDB); if(adapter->hw.mac_type >= em_82540) { - E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); + E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay.value); /* Set the interrupt throttling rate. Value is calculated * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ @@ -2238,7 +2386,7 @@ em_initialize_receive_unit(struct adapter * adapter) } /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); return; } @@ -2291,7 +2439,7 @@ em_process_receive_interrupts(struct adapter * adapter, int count) #endif u_int8_t accept_frame = 0; u_int8_t eop = 0; - u_int16_t len; + u_int16_t len, desc_len, prev_len_adj; int i; /* Pointer to the receive descriptor being examined. */ @@ -2307,16 +2455,23 @@ em_process_receive_interrupts(struct adapter * adapter, int count) #endif return; } - while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) { mp = adapter->rx_buffer_area[i].m_head; accept_frame = 1; + prev_len_adj = 0; + desc_len = current_desc->length; if (current_desc->status & E1000_RXD_STAT_EOP) { count--; eop = 1; - len = current_desc->length - ETHER_CRC_LEN; + if (desc_len < ETHER_CRC_LEN) { + len = 0; + prev_len_adj = ETHER_CRC_LEN - desc_len; + } + else { + len = desc_len - ETHER_CRC_LEN; + } } else { eop = 0; len = current_desc->length; @@ -2339,7 +2494,7 @@ em_process_receive_interrupts(struct adapter * adapter, int count) &adapter->stats, pkt_len, adapter->hw.mac_addr); - len--; + if (len > 0) len--; } else { accept_frame = 0; @@ -2368,6 +2523,14 @@ em_process_receive_interrupts(struct adapter * adapter, int count) } else { /* Chain mbuf's together */ mp->m_flags &= ~M_PKTHDR; + /* + * Adjust length of previous mbuf in chain if we + * received less than 4 bytes in the last descriptor. + */ + if (prev_len_adj > 0) { + adapter->lmp->m_len -= prev_len_adj; + adapter->fmp->m_pkthdr.len -= prev_len_adj; + } adapter->lmp->m_next = mp; adapter->lmp = adapter->lmp->m_next; adapter->fmp->m_pkthdr.len += len; @@ -2566,7 +2729,62 @@ 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. @@ -2577,8 +2795,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); @@ -2587,7 +2809,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); @@ -2683,7 +2904,15 @@ static void em_print_debug_info(struct adapter *adapter) { int unit = adapter->unit; - + uint8_t *hw_addr = adapter->hw.hw_addr; + + printf("em%d: Adapter hardware address = %p \n", unit, hw_addr); + printf("em%d:tx_int_delay = %d, tx_abs_int_delay = %d\n", unit, + E1000_READ_REG(&adapter->hw, TIDV), + E1000_READ_REG(&adapter->hw, TADV)); + printf("em%d:rx_int_delay = %d, rx_abs_int_delay = %d\n", unit, + E1000_READ_REG(&adapter->hw, RDTR), + E1000_READ_REG(&adapter->hw, RADV)); #ifdef DBG_STATS printf("em%d: Packets not Avail = %ld\n", unit, adapter->no_pkts_avail); @@ -2801,3 +3030,63 @@ em_sysctl_stats(SYSCTL_HANDLER_ARGS) return error; } +static int +em_sysctl_int_delay(SYSCTL_HANDLER_ARGS) +{ + struct em_int_delay_info *info; + struct adapter *adapter; + u_int32_t regval; + int error; + int usecs; + int ticks; + int s; + + info = (struct em_int_delay_info *)arg1; + adapter = info->adapter; + usecs = info->value; + error = sysctl_handle_int(oidp, &usecs, 0, req); + if (error != 0 || req->newptr == NULL) + return error; + if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535)) + return EINVAL; + info->value = usecs; + ticks = E1000_USECS_TO_TICKS(usecs); + + s = splimp(); + regval = E1000_READ_OFFSET(&adapter->hw, info->offset); + regval = (regval & ~0xffff) | (ticks & 0xffff); + /* Handle a few special cases. */ + switch (info->offset) { + case E1000_RDTR: + case E1000_82542_RDTR: + regval |= E1000_RDT_FPDB; + break; + case E1000_TIDV: + case E1000_82542_TIDV: + if (ticks == 0) { + adapter->txd_cmd &= ~E1000_TXD_CMD_IDE; + /* Don't write 0 into the TIDV register. */ + regval++; + } else + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + break; + } + E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval); + splx(s); + return 0; +} + +static void +em_add_int_delay_sysctl(struct adapter *adapter, const char *name, + const char *description, struct em_int_delay_info *info, + int offset, int value) +{ + info->adapter = adapter; + info->offset = offset; + info->value = value; + SYSCTL_ADD_PROC(&adapter->sysctl_ctx, + SYSCTL_CHILDREN(adapter->sysctl_tree), + OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, + info, 0, em_sysctl_int_delay, "I", description); +} + diff --git a/sys/dev/netif/em/if_em.h b/sys/dev/netif/em/if_em.h index 628dcc1cf7..4b09ca1790 100644 --- a/sys/dev/netif/em/if_em.h +++ b/sys/dev/netif/em/if_em.h @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ /*$FreeBSD: src/sys/dev/em/if_em.h,v 1.1.2.13 2003/06/09 21:43:41 pdeuskar Exp $*/ -/*$DragonFly: src/sys/dev/netif/em/if_em.h,v 1.3 2003/08/07 21:17:01 dillon Exp $*/ +/*$DragonFly: src/sys/dev/netif/em/if_em.h,v 1.4 2004/03/17 04:59:41 dillon Exp $*/ #ifndef _EM_H_DEFINED_ #define _EM_H_DEFINED_ @@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include @@ -81,7 +82,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 +93,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 +106,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 +118,20 @@ POSSIBILITY OF SUCH DAMAGE. #define EM_TIDV 64 /* - * TxAbsIntDelay (Not valid for 82542 and 82543) + * 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 +142,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 and 82543) + * 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 +203,17 @@ POSSIBILITY OF SUCH DAMAGE. */ #define WAIT_FOR_AUTO_NEG_DEFAULT 1 +/* + * 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 */ @@ -277,6 +289,26 @@ typedef enum _XSUM_CONTEXT_T { OFFLOAD_UDP_IP } XSUM_CONTEXT_T; +struct adapter; +struct em_int_delay_info { + struct adapter *adapter; /* Back-pointer to the adapter struct */ + int offset; /* Register offset to read/write */ + 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; @@ -303,10 +335,10 @@ struct adapter { u_int16_t link_speed; u_int16_t link_duplex; u_int32_t smartspeed; - u_int32_t tx_int_delay; - u_int32_t tx_abs_int_delay; - u_int32_t rx_int_delay; - u_int32_t rx_abs_int_delay; + struct em_int_delay_info tx_int_delay; + struct em_int_delay_info tx_abs_int_delay; + struct em_int_delay_info rx_int_delay; + struct em_int_delay_info rx_abs_int_delay; XSUM_CONTEXT_T active_checksum_context; @@ -358,6 +390,10 @@ struct adapter { unsigned long no_tx_desc_avail2; u_int64_t tx_fifo_reset; u_int64_t tx_fifo_wrk; + + /* For 82544 PCIX Workaround */ + boolean_t pcix_82544; + boolean_t in_detach; #ifdef DBG_STATS unsigned long no_pkts_avail; diff --git a/sys/dev/netif/em/if_em_hw.c b/sys/dev/netif/em/if_em_hw.c index 405159dc19..26709963c5 100644 --- a/sys/dev/netif/em/if_em_hw.c +++ b/sys/dev/netif/em/if_em_hw.c @@ -32,7 +32,7 @@ *******************************************************************************/ /*$FreeBSD: src/sys/dev/em/if_em_hw.c,v 1.1.2.8 2003/06/09 21:43:41 pdeuskar Exp $*/ -/*$DragonFly: src/sys/dev/netif/em/if_em_hw.c,v 1.3 2003/08/07 21:17:01 dillon Exp $*/ +/*$DragonFly: src/sys/dev/netif/em/if_em_hw.c,v 1.4 2004/03/17 04:59:41 dillon Exp $*/ /* if_em_hw.c * Shared functions for accessing and configuring the MAC */ @@ -41,14 +41,15 @@ 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, @@ -59,13 +60,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}; /****************************************************************************** @@ -85,8 +103,14 @@ em_set_phy_type(struct em_hw *hw) hw->phy_type = em_phy_m88; break; case IGP01E1000_I_PHY_ID: - hw->phy_type = em_phy_igp; - break; + if(hw->mac_type == em_82541 || + hw->mac_type == em_82541_rev_2 || + hw->mac_type == em_82547 || + hw->mac_type == em_82547_rev_2) { + hw->phy_type = em_phy_igp; + break; + } + /* Fall Through */ default: /* Should never have loaded on this device */ hw->phy_type = em_phy_undefined; @@ -107,41 +131,63 @@ 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, 0x1F31, 0x0014); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79); - em_write_phy_reg(hw,0x0019,0x0018); + em_write_phy_reg(hw, 0x1F32, 0x161C); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30); - em_write_phy_reg(hw,0x0010,0x1600); + em_write_phy_reg(hw, 0x1F94, 0x0003); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31); - em_write_phy_reg(hw,0x0011,0x0014); + em_write_phy_reg(hw, 0x1F96, 0x003F); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32); - em_write_phy_reg(hw,0x0012,0x161C); + em_write_phy_reg(hw, 0x2010, 0x0008); + } else { + em_write_phy_reg(hw, 0x1F73, 0x0099); + } + + em_write_phy_reg(hw, 0x0000, 0x3300); + + if(hw->mac_type == em_82547) { + uint16_t fused, fine, coarse; - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94); - em_write_phy_reg(hw,0x0014,0x0003); + /* Move to analog registers page */ + em_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96); - em_write_phy_reg(hw,0x0016,0x003F); + if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) { + em_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused); - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010); - em_write_phy_reg(hw,0x0010,0x0008); + fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK; + coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK; - em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); - em_write_phy_reg(hw,0x0000,0x3300); + 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); + } + } } } @@ -190,32 +236,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; @@ -252,49 +355,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); @@ -322,6 +451,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; } /****************************************************************************** @@ -338,7 +469,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; @@ -349,31 +480,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"); @@ -418,21 +531,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. */ @@ -455,6 +577,46 @@ em_init_hw(struct em_hw *hw) return ret_val; } +/****************************************************************************** + * 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. * @@ -526,9 +688,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 @@ -567,7 +729,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 * @@ -576,28 +738,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 @@ -664,8 +835,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); @@ -673,15 +846,14 @@ em_setup_fiber_link(struct em_hw *hw) if(status & E1000_STATUS_LU) break; } if(i == (LINK_UP_TIMEOUT / 10)) { + DEBUGOUT("Never got a valid link from auto-neg!!!\n"); + hw->autoneg_failed = 1; /* 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 + * 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) { + if((ret_val = em_check_for_link(hw))) { DEBUGOUT("Error while checking for link\n"); return ret_val; } @@ -693,7 +865,7 @@ em_setup_fiber_link(struct em_hw *hw) } else { DEBUGOUT("No Signal Detected\n"); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -728,235 +900,283 @@ 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(phy_data & MII_SR_LINK_STATUS) { - /* We have link, so we need to finish the config process: + 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 * if we are on 82543. If we * are on newer silicon, we only need to configure @@ -967,25 +1187,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; } /****************************************************************************** @@ -996,22 +1222,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 @@ -1117,18 +1341,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; } /****************************************************************************** @@ -1164,10 +1386,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. */ @@ -1213,19 +1433,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 */ @@ -1234,25 +1453,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. @@ -1272,22 +1488,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((i == 0) && (hw->phy_type == em_phy_m88)) { + /* We didn't get link. Reset the DSP and wait again for link. */ + if((ret_val = em_phy_reset_dsp(hw))) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; } @@ -1299,14 +1511,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; } } @@ -1315,30 +1524,48 @@ 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; + + /* Polarity reversal workaround for forced 10F/10H links. */ + if(hw->mac_type <= em_82544 && + (hw->forced_speed_duplex == em_10_full || + hw->forced_speed_duplex == em_10_half)) { + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F0F))) + return ret_val; + /* IEEE requirement is 150ms */ + msec_delay(200); + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F00))) + return ret_val; } } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1378,6 +1605,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"); @@ -1393,10 +1621,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; @@ -1412,10 +1640,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; @@ -1431,7 +1659,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; } /****************************************************************************** @@ -1445,7 +1673,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; @@ -1498,7 +1726,7 @@ em_force_mac_fc(struct em_hw *hw) ctrl &= (~E1000_CTRL_TFCE); E1000_WRITE_REG(hw, CTRL, ctrl); - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -1529,9 +1757,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; } @@ -1547,14 +1775,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 @@ -1563,14 +1787,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 @@ -1672,8 +1894,9 @@ em_config_fc_after_link_up(struct em_hw *hw) * be asked to delay transmission of packets than asking * our link partner to pause transmission of frames. */ - else if(hw->original_fc == em_fc_none || - hw->original_fc == em_fc_tx_pause) { + else if((hw->original_fc == em_fc_none || + hw->original_fc == em_fc_tx_pause) || + hw->fc_strict_ieee) { hw->fc = em_fc_none; DEBUGOUT("Flow Control = NONE.\r\n"); } else { @@ -1685,7 +1908,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; @@ -1693,16 +1919,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; } /****************************************************************************** @@ -1719,19 +1944,18 @@ 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); @@ -1749,14 +1973,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; @@ -1766,6 +1986,7 @@ em_check_for_link(struct em_hw *hw) } else { /* No link detected */ + em_config_dsp_after_link_change(hw, FALSE); return 0; } @@ -1774,6 +1995,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 @@ -1785,8 +2009,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; } @@ -1796,33 +2019,24 @@ 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; } /* At this point we know that we are on copper and we have * auto-negotiated link. These are conditions for checking the link - * parter capability register. We use the link partner capability to - * determine if TBI Compatibility needs to be turned on or off. If - * the link partner advertises any speed in addition to Gigabit, then - * we assume that they are GMII-based, and TBI compatibility is not - * needed. If no other speeds are advertised, we assume the link - * partner is TBI-based, and we turn on TBI Compatibility. + * partner capability register. We use the link speed to determine if + * TBI compatibility needs to be turned on or off. If the link is not + * at gigabit speed, then TBI compatibility is not needed. If we are + * at gigabit speed, 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(lp_capability & (NWAY_LPAR_10T_HD_CAPS | - NWAY_LPAR_10T_FD_CAPS | - NWAY_LPAR_100TX_HD_CAPS | - NWAY_LPAR_100TX_FD_CAPS | - NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to - * gigabit, we do not need to enable TBI compatibility. + if(hw->tbi_compatibility_en) { + uint16_t speed, duplex; + em_get_speed_and_duplex(hw, &speed, &duplex); + if(speed != SPEED_1000) { + /* If link speed is not set to gigabit speed, we do not need + * to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { /* If we previously were in the mode, turn it off. */ @@ -1853,9 +2067,10 @@ em_check_for_link(struct em_hw *hw) * auto-negotiation time to complete, in case the cable was just plugged * in. The autoneg_failed flag does this. */ - else if((hw->media_type == em_media_type_fiber) && + else if((((hw->media_type == em_media_type_fiber) && + ((ctrl & E1000_CTRL_SWDPIN1) == signal)) || + (hw->media_type == em_media_type_internal_serdes)) && (!(status & E1000_STATUS_LU)) && - ((ctrl & E1000_CTRL_SWDPIN1) == signal) && (!(rxcw & E1000_RXCW_C))) { if(hw->autoneg_failed == 0) { hw->autoneg_failed = 1; @@ -1872,8 +2087,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; } @@ -1883,14 +2097,38 @@ em_check_for_link(struct em_hw *hw) * Device Control register in an attempt to auto-negotiate with our link * partner. */ - else if((hw->media_type == em_media_type_fiber) && + else if(((hw->media_type == em_media_type_fiber) || + (hw->media_type == em_media_type_internal_serdes)) && (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); + + hw->serdes_link_down = FALSE; + } + /* If we force link for non-auto-negotiation switch, check link status + * based on MAC synchronization for internal serdes media type. + */ + else if((hw->media_type == em_media_type_internal_serdes) && + !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + /* SYNCH bit and IV bit are sticky. */ + usec_delay(10); + if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { + if(!(rxcw & E1000_RXCW_IV)) { + hw->serdes_link_down = FALSE; + DEBUGOUT("SERDES: Link is up.\n"); + } + } else { + hw->serdes_link_down = TRUE; + DEBUGOUT("SERDES: Link is down.\n"); + } } - return 0; + if((hw->media_type == em_media_type_internal_serdes) && + (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS)); + } + return E1000_SUCCESS; } /****************************************************************************** @@ -1900,12 +2138,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"); @@ -1934,6 +2174,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; } /****************************************************************************** @@ -1944,6 +2205,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; @@ -1955,20 +2217,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; } /****************************************************************************** @@ -1982,11 +2240,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); } /****************************************************************************** @@ -2000,11 +2258,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); } /****************************************************************************** @@ -2048,7 +2306,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); @@ -2110,8 +2368,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 ******************************************************************************/ @@ -2119,12 +2377,34 @@ int32_t 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); @@ -2144,7 +2424,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; } @@ -2186,7 +2466,7 @@ em_read_phy_reg(struct em_hw *hw, */ *phy_data = em_shift_in_mdi_bits(hw); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -2200,12 +2480,34 @@ int32_t 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); @@ -2225,8 +2527,8 @@ em_write_phy_reg(struct em_hw *hw, E1000_WRITE_REG(hw, MDIC, mdic); /* Poll the ready bit to see if the MDI read completed */ - for(i = 0; i < 64; i++) { - usec_delay(10); + for(i = 0; i < 640; i++) { + usec_delay(5); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -2256,7 +2558,7 @@ em_write_phy_reg(struct em_hw *hw, em_shift_out_mdi_bits(hw, mdic, 32); } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -2301,11 +2603,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; @@ -2324,24 +2621,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; } /****************************************************************************** @@ -2352,23 +2651,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; @@ -2381,11 +2678,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: @@ -2396,7 +2697,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; @@ -2410,17 +2711,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; } @@ -2431,8 +2731,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"); @@ -2448,13 +2750,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; @@ -2462,8 +2765,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; @@ -2471,8 +2774,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; @@ -2499,8 +2802,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"); @@ -2509,8 +2814,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) >> @@ -2520,13 +2825,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; @@ -2538,8 +2843,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; @@ -2561,6 +2866,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"); @@ -2579,20 +2885,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); @@ -2608,7 +2912,7 @@ em_validate_mdi_setting(struct em_hw *hw) hw->mdix = 1; return -E1000_ERR_CONFIG; } - return 0; + return E1000_SUCCESS; } @@ -2640,7 +2944,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; @@ -2653,8 +2959,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; @@ -2679,6 +2986,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) { @@ -2687,28 +3006,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; } } } @@ -2813,7 +3132,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; @@ -3073,13 +3393,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); @@ -3090,30 +3414,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; } /****************************************************************************** @@ -3141,9 +3470,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; } @@ -3177,7 +3506,7 @@ em_update_eeprom_checksum(struct em_hw *hw) DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3215,10 +3544,12 @@ em_write_eeprom(struct em_hw *hw, if (em_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; - if(eeprom->type == em_eeprom_microwire) + if(eeprom->type == em_eeprom_microwire) { status = em_write_eeprom_microwire(hw, offset, words, data); - else + } else { status = em_write_eeprom_spi(hw, offset, words, data); + msec_delay(10); + } /* Done with writing */ em_release_eeprom(hw); @@ -3375,7 +3706,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; } /****************************************************************************** @@ -3409,7 +3740,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; } /****************************************************************************** @@ -3435,16 +3766,13 @@ 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) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { - if(hw->perm_mac_addr[5] & 0x01) - hw->perm_mac_addr[5] &= ~(0x01); - else - hw->perm_mac_addr[5] |= 0x01; - } + if(((hw->mac_type == em_82546) || (hw->mac_type == em_82546_rev_3)) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + hw->perm_mac_addr[5] ^= 0x01; + for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3460,22 +3788,13 @@ void em_init_rx_addrs(struct em_hw *hw) { uint32_t i; - uint32_t addr_low; - uint32_t addr_high; DEBUGFUNC("em_init_rx_addrs"); /* Setup the receive address. */ DEBUGOUT("Programming MAC Address into RAR[0]\n"); - addr_low = (hw->mac_addr[0] | - (hw->mac_addr[1] << 8) | - (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24)); - - addr_high = (hw->mac_addr[4] | - (hw->mac_addr[5] << 8) | E1000_RAH_AV); - E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low); - E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high); + em_rar_set(hw, hw->mac_addr, 0); /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); @@ -3492,6 +3811,7 @@ em_init_rx_addrs(struct em_hw *hw) * mc_addr_list - the list of new multicast addresses * mc_addr_count - number of addresses * pad - number of bytes between addresses in the list + * rar_used_count - offset where to start adding mc addresses into the RAR's * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers @@ -3502,11 +3822,11 @@ void em_mc_addr_list_update(struct em_hw *hw, uint8_t *mc_addr_list, uint32_t mc_addr_count, - uint32_t pad) + uint32_t pad, + uint32_t rar_used_count) { uint32_t hash_value; uint32_t i; - uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ DEBUGFUNC("em_mc_addr_list_update"); @@ -3720,7 +4040,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); @@ -3771,7 +4091,7 @@ em_id_led_init(struct em_hw * hw) break; } } - return 0; + return E1000_SUCCESS; } /****************************************************************************** @@ -3783,49 +4103,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; } /****************************************************************************** @@ -3836,39 +4155,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; } /****************************************************************************** @@ -3879,50 +4192,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; } /****************************************************************************** @@ -3933,50 +4240,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; } /****************************************************************************** @@ -4099,8 +4400,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) { @@ -4112,8 +4412,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); @@ -4261,8 +4560,8 @@ uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; em_io_write(hw, io_addr, offset); return em_io_read(hw, io_data); @@ -4281,8 +4580,8 @@ em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; em_io_write(hw, io_addr, offset); em_io_write(hw, io_data, value); @@ -4296,7 +4595,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 @@ -4304,9 +4604,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; @@ -4317,8 +4619,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) >> @@ -4348,19 +4651,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; @@ -4376,20 +4676,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. */ @@ -4411,7 +4706,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 @@ -4420,22 +4716,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 */ @@ -4443,18 +4743,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; @@ -4474,7 +4765,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 @@ -4484,25 +4776,287 @@ 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; } +/***************************************************************************** + * + * 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/netif/em/if_em_hw.h b/sys/dev/netif/em/if_em_hw.h index 18ac224e75..468b664706 100644 --- a/sys/dev/netif/em/if_em_hw.h +++ b/sys/dev/netif/em/if_em_hw.h @@ -32,7 +32,7 @@ *******************************************************************************/ /*$FreeBSD: src/sys/dev/em/if_em_hw.h,v 1.1.2.8 2003/06/09 21:43:41 pdeuskar Exp $*/ -/*$DragonFly: src/sys/dev/netif/em/if_em_hw.h,v 1.3 2003/08/07 21:17:01 dillon Exp $*/ +/*$DragonFly: src/sys/dev/netif/em/if_em_hw.h,v 1.4 2004/03/17 04:59:41 dillon Exp $*/ /* if_em_hw.h * Structures, enums, and macros for the MAC */ @@ -42,6 +42,7 @@ #include "if_em_osdep.h" + /* Forward declarations of structures used by the shared code */ struct em_hw; struct em_hw_stats; @@ -56,9 +57,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; @@ -73,6 +78,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; @@ -96,7 +102,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 */ @@ -114,7 +121,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 */ @@ -192,6 +200,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; @@ -230,9 +258,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); @@ -240,8 +269,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); @@ -268,7 +298,7 @@ int32_t em_read_mac_addr(struct em_hw * hw); /* Filters (multicast, vlan, receive) */ void em_init_rx_addrs(struct em_hw *hw); -void em_mc_addr_list_update(struct em_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +void em_mc_addr_list_update(struct em_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t em_hash_mc_addr(struct em_hw *hw, uint8_t * mc_addr); void em_mta_set(struct em_hw *hw, uint32_t hash_value); void em_rar_set(struct em_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -298,6 +328,8 @@ 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); #define E1000_READ_REG_IO(a, reg) \ em_read_reg_io((a), E1000_##reg) @@ -319,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 @@ -391,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. @@ -545,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 */ @@ -605,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 */ @@ -940,7 +982,10 @@ struct em_hw { em_bus_width bus_width; em_bus_type bus_type; struct em_eeprom_info eeprom; - uint32_t io_base; + em_ms_type master_slave; + em_ms_type original_master_slave; + em_ffe_config ffe_config_state; + unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; uint32_t phy_addr; @@ -956,6 +1001,7 @@ struct em_hw { uint32_t ledctl_default; uint32_t ledctl_mode1; uint32_t ledctl_mode2; + uint16_t phy_spd_default; uint16_t autoneg_advertised; uint16_t pci_cmd_word; uint16_t fc_high_water; @@ -980,10 +1026,14 @@ struct em_hw { uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; boolean_t disable_polarity_correction; boolean_t speed_downgraded; + em_dsp_config dsp_config_state; boolean_t get_link_status; + boolean_t serdes_link_down; 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; @@ -1065,7 +1115,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 */ @@ -1127,22 +1177,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 @@ -1165,109 +1215,110 @@ 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 */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ @@ -1432,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 @@ -1464,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 @@ -1485,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 @@ -1496,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 @@ -1563,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) @@ -1674,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 */ @@ -1689,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 */ @@ -1812,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 */ @@ -1905,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 @@ -1956,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 */ @@ -1966,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 @@ -1987,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 @@ -2020,5 +2114,7 @@ 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*/ #endif /* _EM_HW_H_ */ diff --git a/sys/dev/netif/em/if_em_osdep.h b/sys/dev/netif/em/if_em_osdep.h index f98b530621..9ac067c72f 100644 --- a/sys/dev/netif/em/if_em_osdep.h +++ b/sys/dev/netif/em/if_em_osdep.h @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ /*$FreeBSD: src/sys/dev/em/if_em_osdep.h,v 1.1.2.11 2003/06/09 21:43:41 pdeuskar Exp $*/ -/*$DragonFly: src/sys/dev/netif/em/if_em_osdep.h,v 1.3 2003/08/07 21:17:01 dillon Exp $*/ +/*$DragonFly: src/sys/dev/netif/em/if_em_osdep.h,v 1.4 2004/03/17 04:59:41 dillon Exp $*/ #ifndef _FREEBSD_OS_H_ #define _FREEBSD_OS_H_ @@ -92,35 +92,34 @@ struct em_osdep #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) -#define E1000_READ_REG(a, reg) (\ - bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - ((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg)) - -#define E1000_WRITE_REG(a, reg, value) (\ - bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - ((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg, \ - value)) - -#define E1000_READ_REG_ARRAY(a, reg, offset) (\ - ((a)->mac_type >= em_82543) ? \ - bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_##reg + ((offset) << 2))): \ - bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_82542_##reg + ((offset) << 2)))) - - -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) (\ - ((a)->mac_type >= em_82543) ? \ - bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_##reg + ((offset) << 2)), value): \ - bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \ - (E1000_82542_##reg + ((offset) << 2)), value)) +/* Read from an absolute offset in the adapter's memory space */ +#define E1000_READ_OFFSET(hw, offset) \ + bus_space_read_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ + offset) + +/* Write to an absolute offset in the adapter's memory space */ +#define E1000_WRITE_OFFSET(hw, offset, value) \ + bus_space_write_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ + offset, \ + value) + +/* Convert a register name to its offset in the adapter's memory space */ +#define E1000_REG_OFFSET(hw, reg) \ + ((hw)->mac_type >= em_82543 ? E1000_##reg : E1000_82542_##reg) + +#define E1000_READ_REG(hw, reg) \ + E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg)) + +#define E1000_WRITE_REG(hw, reg, value) \ + E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg), value) + +#define E1000_READ_REG_ARRAY(hw, reg, index) \ + E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2)) + +#define E1000_WRITE_REG_ARRAY(hw, reg, index, value) \ + E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value) #endif /* _FREEBSD_OS_H_ */