diff options
author | pdeuskar <pdeuskar@FreeBSD.org> | 2003-03-21 21:47:31 +0000 |
---|---|---|
committer | pdeuskar <pdeuskar@FreeBSD.org> | 2003-03-21 21:47:31 +0000 |
commit | a56305572587eb0a4e0d7793a845b70c41bafa8c (patch) | |
tree | d20e66c9988dbf11f5c7af5d38ff1994edbc7898 /sys | |
parent | 38bdc5fff0d6cc0edd89dcfd2a0e6c5388c6a00a (diff) | |
download | FreeBSD-src-a56305572587eb0a4e0d7793a845b70c41bafa8c.zip FreeBSD-src-a56305572587eb0a4e0d7793a845b70c41bafa8c.tar.gz |
Added support for 82541 and 82547 based adapters.
- These have Intel gigabit PHY
- 82547 uses CSA interface
MFC after: 1 week
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/em/LICENSE | 2 | ||||
-rw-r--r-- | sys/dev/em/README | 186 | ||||
-rw-r--r-- | sys/dev/em/if_em.c | 535 | ||||
-rw-r--r-- | sys/dev/em/if_em.h | 43 | ||||
-rw-r--r-- | sys/dev/em/if_em_hw.c | 1517 | ||||
-rw-r--r-- | sys/dev/em/if_em_hw.h | 297 | ||||
-rw-r--r-- | sys/dev/em/if_em_osdep.h | 17 |
7 files changed, 1974 insertions, 623 deletions
diff --git a/sys/dev/em/LICENSE b/sys/dev/em/LICENSE index c47baa0..de8145e 100644 --- a/sys/dev/em/LICENSE +++ b/sys/dev/em/LICENSE @@ -1,5 +1,5 @@ $FreeBSD$ -Copyright (c) 2001-2002, Intel Corporation +Copyright (c) 2001-2003, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/em/README b/sys/dev/em/README index 6ff12d7..dd47ac5 100644 --- a/sys/dev/em/README +++ b/sys/dev/em/README @@ -2,13 +2,13 @@ $FreeBSD$ FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters ============================================================ -November 12, 2002 +February 5, 2003 Contents ======== -- In This Release +- Overview - Supported Adapters - Building and Installation - Speed and Duplex Configuration @@ -18,17 +18,12 @@ Contents - License -In This Release -=============== +Overview +======== -This file describes the FreeBSD* driver, version 1.4.x, for the Intel(R) +This file describes the FreeBSD* driver, version 1.5.x, for the Intel(R) PRO/1000 Family of Adapters. This driver has been developed for use with -FreeBSD, version 4.7. As a new feature for this release, the driver is now -compiled by default into the FreeBSD 4.7 kernel. - -The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on -all but the 82542-based adapters. For specific adapters, refer to the -Supported Adapters section below. +FreeBSD, version 4.7. For questions related to hardware requirements, refer to the documentation supplied with your Intel PRO/1000 adapter. All hardware requirements listed @@ -56,8 +51,9 @@ release: 82544 PRO/1000 XF Server Adapter A50484-xxx 82544 PRO/1000 T Desktop Adapter A62947-xxx - - 82540 PRO/1000 MT Desktop Adapter A78708-xxx + + 82540 PRO/1000 MT Desktop Adapter A78408-xxx + 82541 C91016-xxx 82545 PRO/1000 MT Server Adapter A92165-xxx @@ -70,6 +66,7 @@ release: 82546 PRO/1000 MF Dual Port Server Adapter A91620-xxx + To verify your Intel adapter is supported, find the board ID number on the adapter. Look for a label that has a barcode and a number in the format of 123456-001 (six digits hyphen three digits). Match this to the list of @@ -88,77 +85,90 @@ For the latest Intel network drivers for FreeBSD, see: Building and Installation ========================= -NOTE: You must have kernel sources installed in order to compile the driver - module. - - In the instructions below, x.x.x is the driver version as indicated in - the name of the driver tar. +NOTE: The driver can be installed as a dynamic loadable kernel module or + compiled into the kernel. You must have kernel sources installed in + order to compile the driver module. +In the instructions below, x.x.x is the driver version as indicated in the +name of the driver tar file. 1. Move the base driver tar file to the directory of your choice. For example, use /home/username/em or /usr/local/src/em. 2. Untar/unzip the archive: - tar xfz em-x.x.x.tar.gz + tar xvfz em-x.x.x.tar.gz -3. To load the driver onto a running system: + This will create an em-x.x.x directory. - cd em-x.x.x/modules - kldload ./if_em.ko +3. To create a loadable module, perform the following steps. + NOTE: To compile the driver into the kernel, go directly to step 4. -4. To assign an IP address to the interface, enter the following: + a. To compile the module - ifconfig em<interface_num> <IP_address> + cd em-x.x.x + make -5. Verify that the interface works. Enter the following, where <IP_address> - is the IP address for another machine on the same subnet as the interface - that is being tested: + b. To install the compiled module in system directory: + + make install + + c. If you want the driver to load automatically when the system is booted: - ping <IP_address> + 1. Follow steps a, and b above to compile and install the module + 2. Edit /boot/loader.conf, and add the following line: -6. If you want the driver to load automatically when the system is booted: + if_em_load="YES" - cd em-x.x.x/modules - cp if_em.ko /modules - - Edit /boot/loader.conf, and add the following line: - - if_em_load="YES" +4. To compile the driver into the kernel: - OR + cd em-x.x.x/src - compile the driver into the kernel (see item 7). + cp if_em* /usr/src/sys/dev/em + cp Makefile /usr/src/sys/modules/em - Edit /etc/rc.conf, and create the appropriate ifconfig_em<interface_num> - entry: + Edit the /usr/src/sys/conf/files.i386 file, and add the following lines: - ifconfig_em<interface_num>="<ifconfig_settings>" + dev/em/if_em.c optional em - Example usage: + dev/em/if_em_hw.c optional em - ifconfig_em0="inet 192.168.10.1 netmask 255.255.255.0" + Remove the following lines from the /usr/src/sys/conf/files.i386 file, + if they exist: - NOTE: For assistance, see the ifconfig man page. + dev/em/if_em_fxhw.c optional em + dev/em/if_em_phy.c optional em -7. If you want to compile the driver into the kernel, enter: + Edit the kernel configuration file (i.e., GENERIC or MYKERNEL) in + /usr/src/sys/i386/conf, and ensure the following line is present: - cd em-x.x.x/src - cp if_em* /usr/src/sys/dev/em - cp Makefile /usr/src/sys/modules/em + device em + + Compile and install the kernel. The system must be rebooted for the kernel + updates to take effect. For additional information on compiling the + kernel, consult the FreeBSD operating system documentation. + +5. To assign an IP address to the interface, enter the following: + + ifconfig em<interface_num> <IP_address> - Edit the /usr/src/sys/conf/files.i386 file, and add the following line: +6. Verify that the interface works. Enter the following, where <IP_address> + is the IP address for another machine on the same subnet as the interface + that is being tested: - dev/em/if_em_hw.c optional em + ping <IP_address> - Remove the following lines from the /usr/src/sys/conf/files.i386 file, if - they exist: +7. To configure the IP address to remain after reboot, edit /etc/rc.conf, + and create the appropriate ifconfig_em<interface_num> entry: - /dev/em/if_em_fx_hw.c optional em - /dev/em/if_em_phy.c optional em + ifconfig_em<interface_num>="<ifconfig_settings>" - Compile and install the kernel. + Example usage: + + ifconfig_em0="inet 192.168.10.1 netmask 255.255.255.0" + + NOTE: For assistance, see the ifconfig man page. Speed and Duplex Configuration @@ -198,47 +208,79 @@ For more information on the ifconfig utility, see the ifconfig man page. Additional Configurations ========================= +The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on +all but the 82542-based adapters. For specific adapters, refer to the +Supported Adapters section. + Jumbo Frames ------------ - To enable Jumbo Frames, use the ifconfig utility to increase the MTU beyond 1500 bytes. - NOTE: Only enable Jumbo Frames if your network infrastructure supports - them. + NOTES: Only enable Jumbo Frames if your network infrastructure supports + them. + + The Jumbo Frames setting on the switch must be set to at least + 22 bytes larger than that of the adapter. + + The Jumbo Frames MTU range for Intel Adapters is 1500 to 16114. The default + MTU range is 1500. To modify the setting, enter the following: + + ifconfig em<interface_num> <hostname or IP address> mtu 9000 - The MTU range for Jumbo Frames is 1500 to 16114. For example, enter the - following: + To confirm an interface's MTU value, use the ifconfig command. To confirm + the MTU used between two specific devices, use: - ifconfig em<interface_num> mtu 9000 + route get <destination_IP_address> VLANs ----- + To create a new VLAN pseudo-interface: + + ifconfig <vlan_name> create + + To associate the VLAN pseudo-interface with a physical interface and + assign a VLAN ID, IP address, and netmask: + + ifconfig <vlan_name> <ip_address> netmask <subnet_mask> vlan + <vlan_id> vlandev <physical_interface> + + Example: + + ifconfig vlan10 10.0.0.1 netmask 255.255.255.0 vlan10 vlandev em0 + + In this example, all packets will be marked on egress with 802.1Q VLAN + tags, specifying a VLAN ID of 10. + + To remove a VLAN pseudo-interface: - To enable VLANs in the kernel, modify the config file as follows: + ifconfig <vlan_name> destroy - pseudo-device vlan <num_VLANs> + Polling + ------- + To enable polling in the driver, add the following options to the kernel + configuration, and then recompile the kernel: - Then, recompile the kernel and reboot. + options DEVICE_POLLING + options HZ=1000 - To see the VLAN device entries, use ifconfig. + At runtime, use the following command to turn on polling mode. Similarly, + turn off polling mode by setting the variable to 0: - To attach a VLAN to the driver enter the following: + sysctl kern.polling.enable=1 - ifconfig vlan0 inet 10.0.0.1 netmask 255.255.255.0 vlan 1 vlandev - em0 mtu 1500 up - Also, bring the driver up by entering: + NOTES: DEVICE POLLING is only valid for non-SMP kernels. - ifconfig em0 up + The driver has to be built into the kernel for DEVICE POLLING to be + enabled in the driver. Known Limitations ================= -There are known performance problems 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. Support diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index 1503ea2..7554120 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -1,6 +1,6 @@ /************************************************************************** -Copyright (c) 2001-2002, Intel Corporation +Copyright (c) 2001-2003, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -51,7 +51,7 @@ struct adapter *em_adapter_list = NULL; * Driver version *********************************************************************/ -char em_driver_version[] = "1.4.10"; +char em_driver_version[] = "1.5.31"; /********************************************************************* @@ -63,6 +63,7 @@ char em_driver_version[] = "1.4.10"; * * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } *********************************************************************/ + static em_vendor_info_t em_vendor_info_array[] = { /* Intel(R) PRO/1000 Network Connection */ @@ -78,10 +79,15 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 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, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} }; @@ -103,7 +109,7 @@ static int em_detach(device_t); static int em_shutdown(device_t); static void em_intr(void *); static void em_start(struct ifnet *); -static int em_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t); +static int em_ioctl(struct ifnet *, u_long, caddr_t); static void em_watchdog(struct ifnet *); static void em_init(void *); static void em_stop(void *); @@ -129,7 +135,7 @@ static int em_allocate_receive_structures(struct adapter *); static int em_allocate_transmit_structures(struct adapter *); static void em_process_receive_interrupts(struct adapter *, int); static void em_receive_checksum(struct adapter *, - struct em_rx_desc * rx_desc, + struct em_rx_desc *, struct mbuf *); static void em_transmit_checksum_setup(struct adapter *, struct mbuf *, @@ -142,8 +148,13 @@ static void em_print_hw_stats(struct adapter *); static void em_print_link_status(struct adapter *); static int em_get_buf(int i, struct adapter *, struct mbuf *); -static void em_enable_vlans(struct adapter *adapter); -static int em_encap(struct adapter *adapter, struct mbuf *m_head); +static void em_enable_vlans(struct adapter *); +static int em_encap(struct adapter *, struct mbuf *); +static void em_smartspeed(struct adapter *); +static int em_82547_fifo_workaround(struct adapter *, int); +static void em_82547_update_fifo_head(struct adapter *, int); +static int em_82547_tx_fifo_reset(struct adapter *); +static void em_82547_move_tail(void *arg); /********************************************************************* * FreeBSD Device Interface Entry Points @@ -254,6 +265,7 @@ em_attach(device_t dev) em_adapter_list = adapter; callout_handle_init(&adapter->timer_handle); + callout_handle_init(&adapter->tx_fifo_timer_handle); /* Determine hardware revision */ em_identify_hardware(adapter); @@ -271,30 +283,33 @@ em_attach(device_t dev) adapter->hw.tbi_compatibility_en = TRUE; adapter->rx_buffer_len = EM_RXBUFFER_2048; + /* These parameters control the automatic generation(Tx) and + * response(Rx) to Ethernet PAUSE frames. + */ adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH; adapter->hw.fc_low_water = FC_DEFAULT_LO_THRESH; adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER; adapter->hw.fc_send_xon = TRUE; adapter->hw.fc = em_fc_full; + adapter->hw.phy_init_script = 1; - /* Set the max frame size assuming standard ethernet sized frames */ + /* + * Set the max frame size assuming standard ethernet + * sized frames + */ adapter->hw.max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; adapter->hw.min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; - /* This controls when hardware reports transmit completion status. */ - if ((EM_REPORT_TX_EARLY == 0) || (EM_REPORT_TX_EARLY == 1)) { - adapter->hw.report_tx_early = EM_REPORT_TX_EARLY; - } else { - if (adapter->hw.mac_type < em_82543) { - adapter->hw.report_tx_early = 0; - } else { - adapter->hw.report_tx_early = 1; - } - } + /* + * This controls when hardware reports transmit completion + * status. + */ + adapter->hw.report_tx_early = 1; + if (em_allocate_pci_resources(adapter)) { printf("em%d: Allocation of PCI resources failed\n", @@ -305,6 +320,9 @@ em_attach(device_t dev) } + /* Initialize eeprom parameters */ + em_init_eeprom_params(&adapter->hw); + tsize = EM_ROUNDUP(adapter->num_tx_desc * sizeof(struct em_tx_desc), 4096); @@ -347,11 +365,15 @@ em_attach(device_t dev) if (em_read_mac_addr(&adapter->hw) < 0) { printf("em%d: EEPROM read error while reading mac address\n", adapter->unit); + em_free_pci_resources(adapter); + contigfree(adapter->tx_desc_base, tsize, M_DEVBUF); + contigfree(adapter->rx_desc_base, rsize, M_DEVBUF); + splx(s); return(EIO); } - memcpy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr, - ETH_LENGTH_OF_ADDRESS); + bcopy(adapter->hw.mac_addr, adapter->interface_data.ac_enaddr, + ETHER_ADDR_LEN); /* Setup OS specific network interface */ em_setup_interface(dev, adapter); @@ -373,7 +395,6 @@ em_attach(device_t dev) } else printf("em%d: Speed:N/A Duplex:N/A\n", adapter->unit); - INIT_DEBUGOUT("em_attach: end"); splx(s); return(0); @@ -403,9 +424,9 @@ em_detach(device_t dev) em_stop(adapter); em_phy_hw_reset(&adapter->hw); #if __FreeBSD_version < 500000 - ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); + ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); #else - ether_ifdetach(&adapter->interface_data.ac_if); + ether_ifdetach(&adapter->interface_data.ac_if); #endif em_free_pci_resources(adapter); @@ -470,10 +491,10 @@ em_shutdown(device_t dev) static void em_start(struct ifnet *ifp) { - int s; + int s; struct mbuf *m_head; struct adapter *adapter = ifp->if_softc; - + if (!adapter->link_active) return; @@ -484,14 +505,13 @@ em_start(struct ifnet *ifp) if (m_head == NULL) break; - if (em_encap(adapter, m_head)) { - ifp->if_flags |= IFF_OACTIVE; - IF_PREPEND(&ifp->if_snd, m_head); - break; + if (em_encap(adapter, m_head)) { + ifp->if_flags |= IFF_OACTIVE; + IF_PREPEND(&ifp->if_snd, m_head); + break; } - - /* Send a copy of the frame to the BPF listener */ + /* Send a copy of the frame to the BPF listener */ #if __FreeBSD_version < 500000 if (ifp->if_bpf) bpf_mtap(ifp, m_head); @@ -517,7 +537,7 @@ em_start(struct ifnet *ifp) **********************************************************************/ static int -em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) +em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { int s, mask, error = 0; struct ifreq *ifr = (struct ifreq *) data; @@ -541,20 +561,20 @@ em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) em_init(adapter); } break; - case SIOCSIFFLAGS: - IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); - if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_flags & IFF_RUNNING)) - em_init(adapter); - - em_disable_promisc(adapter); - em_set_promisc(adapter); - } else { - if (ifp->if_flags & IFF_RUNNING) { - em_stop(adapter); - } - } - break; + case SIOCSIFFLAGS: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_flags & IFF_RUNNING)) + em_init(adapter); + + em_disable_promisc(adapter); + em_set_promisc(adapter); + } else { + if (ifp->if_flags & IFF_RUNNING) { + em_stop(adapter); + } + } + break; case SIOCADDMULTI: case SIOCDELMULTI: IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI"); @@ -703,16 +723,17 @@ em_init(void *arg) em_disable_intr(adapter); else #endif /* DEVICE_POLLING */ - em_enable_intr(adapter); + em_enable_intr(adapter); splx(s); return; } + #ifdef DEVICE_POLLING static poll_handler_t em_poll; - -static void + +static void em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct adapter *adapter = ifp->if_softc; @@ -736,27 +757,26 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) em_process_receive_interrupts(adapter, count); em_clean_transmit_interrupts(adapter); } + if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) em_start(ifp); } #endif /* DEVICE_POLLING */ - /********************************************************************* * - * Interrupt Service routine + * Interrupt Service routine * **********************************************************************/ - static void em_intr(void *arg) { - u_int32_t loop_cnt = EM_MAX_INTR; - u_int32_t reg_icr; - struct ifnet *ifp; - struct adapter *adapter = arg; + u_int32_t loop_cnt = EM_MAX_INTR; + u_int32_t reg_icr; + struct ifnet *ifp; + struct adapter *adapter = arg; - ifp = &adapter->interface_data.ac_if; + ifp = &adapter->interface_data.ac_if; #ifdef DEVICE_POLLING if (ifp->if_ipending & IFF_POLLING) @@ -770,37 +790,38 @@ em_intr(void *arg) #endif /* DEVICE_POLLING */ - em_disable_intr(adapter); - while (loop_cnt > 0 && - (reg_icr = E1000_READ_REG(&adapter->hw, ICR)) != 0) { - - /* Link status change */ - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - untimeout(em_local_timer, adapter, - adapter->timer_handle); - adapter->hw.get_link_status = 1; - em_check_for_link(&adapter->hw); - em_print_link_status(adapter); - adapter->timer_handle = - timeout(em_local_timer, adapter, 2*hz); - } + em_disable_intr(adapter); + while (loop_cnt > 0 && + (reg_icr = E1000_READ_REG(&adapter->hw, ICR)) != 0) { - if (ifp->if_flags & IFF_RUNNING) { - em_process_receive_interrupts(adapter, -1); - em_clean_transmit_interrupts(adapter); - } - loop_cnt--; - } + /* Link status change */ + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + untimeout(em_local_timer, adapter, + adapter->timer_handle); + adapter->hw.get_link_status = 1; + em_check_for_link(&adapter->hw); + em_print_link_status(adapter); + adapter->timer_handle = + timeout(em_local_timer, adapter, 2*hz); + } - em_enable_intr(adapter); + if (ifp->if_flags & IFF_RUNNING) { + em_process_receive_interrupts(adapter, -1); + em_clean_transmit_interrupts(adapter); + } + loop_cnt--; + } - if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) - em_start(ifp); + em_enable_intr(adapter); - return; + if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) + em_start(ifp); + + return; } + /********************************************************************* * * Media Ioctl callback @@ -924,6 +945,10 @@ em_media_change(struct ifnet *ifp) return(0); } +#define EM_FIFO_HDR 0x10 +#define EM_82547_PKT_THRESH 0x3e0 +#define EM_82547_TX_FIFO_SIZE 0x2800 +#define EM_82547_TX_FIFO_BEGIN 0xf00 /********************************************************************* * * This routine maps the mbufs to tx descriptors. @@ -939,17 +964,20 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) u_int32_t txd_lower; int txd_used, i, txd_saved; struct mbuf *mp; + #if __FreeBSD_version < 500000 struct ifvlan *ifv = NULL; #else - struct m_tag *mtag; + struct m_tag *mtag; #endif - struct em_buffer *tx_buffer = NULL; struct em_tx_desc *current_tx_desc = NULL; struct ifnet *ifp = &adapter->interface_data.ac_if; - /* Force a cleanup if number of TX descriptors available hits the threshold */ + /* + * Force a cleanup if number of TX descriptors + * available hits the threshold + */ if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) em_clean_transmit_interrupts(adapter); @@ -965,12 +993,13 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) else txd_upper = txd_lower = 0; - /* Find out if we are in vlan mode */ + + /* Find out if we are in vlan mode */ #if __FreeBSD_version < 500000 - if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && - m_head->m_pkthdr.rcvif != NULL && - m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) - ifv = m_head->m_pkthdr.rcvif->if_softc; + if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && + m_head->m_pkthdr.rcvif != NULL && + m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) + ifv = m_head->m_pkthdr.rcvif->if_softc; #else mtag = VLAN_OUTPUT_TAG(ifp, m_head); #endif @@ -1008,17 +1037,17 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) adapter->next_avail_tx_desc = i; #if __FreeBSD_version < 500000 - if (ifv != NULL) { - /* Set the vlan id */ - current_tx_desc->upper.fields.special = ifv->ifv_tag; + if (ifv != NULL) { + /* Set the vlan id */ + current_tx_desc->upper.fields.special = ifv->ifv_tag; #else - if (mtag != NULL) { - /* Set the vlan id */ - current_tx_desc->upper.fields.special = VLAN_TAG_VALUE(mtag); + if (mtag != NULL) { + /* Set the vlan id */ + current_tx_desc->upper.fields.special = VLAN_TAG_VALUE(mtag); #endif - /* Tell hardware to add tag */ - current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; - } + /* Tell hardware to add tag */ + current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; + } tx_buffer->m_head = m_head; @@ -1031,11 +1060,146 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 * that this frame is available to transmit. */ - E1000_WRITE_REG(&adapter->hw, TDT, i); + if (adapter->hw.mac_type == em_82547 && + adapter->link_duplex == HALF_DUPLEX) { + em_82547_move_tail(adapter); + } + else { + E1000_WRITE_REG(&adapter->hw, TDT, i); + if (adapter->hw.mac_type == em_82547) { + em_82547_update_fifo_head(adapter, m_head->m_pkthdr.len); + } + } return (0); } + +/********************************************************************* + * + * 82547 workaround to avoid controller hang in half-duplex environment. + * The workaround is to avoid queuing a large packet that would span + * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers + * in this case. We do that only when FIFO is queiced. + * + **********************************************************************/ +static void +em_82547_move_tail(void *arg) +{ + int s; + struct adapter *adapter = arg; + uint16_t hw_tdt; + uint16_t sw_tdt; + struct em_tx_desc *tx_desc; + uint16_t length = 0; + boolean_t eop = 0; + + s = splimp(); + hw_tdt = E1000_READ_REG(&adapter->hw, TDT); + sw_tdt = adapter->next_avail_tx_desc; + + while (hw_tdt != sw_tdt) { + tx_desc = &adapter->tx_desc_base[hw_tdt]; + length += tx_desc->lower.flags.length; + eop = tx_desc->lower.data & E1000_TXD_CMD_EOP; + if(++hw_tdt == adapter->num_tx_desc) + hw_tdt = 0; + + if(eop) { + if (em_82547_fifo_workaround(adapter, length)) { + adapter->tx_fifo_wrk++; + adapter->tx_fifo_timer_handle = + timeout(em_82547_move_tail, + adapter, 1); + splx(s); + return; + } + else { + E1000_WRITE_REG(&adapter->hw, TDT, hw_tdt); + em_82547_update_fifo_head(adapter, length); + length = 0; + } + } + } + splx(s); + return; +} + +static int +em_82547_fifo_workaround(struct adapter *adapter, int len) +{ + int fifo_space, fifo_pkt_len; + + fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR); + + if (adapter->link_duplex == HALF_DUPLEX) { + fifo_space = EM_82547_TX_FIFO_SIZE - adapter->tx_fifo_head; + + if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) { + if (em_82547_tx_fifo_reset(adapter)) { + return(0); + } + else { + return(1); + } + } + } + + return(0); +} + +static void +em_82547_update_fifo_head(struct adapter *adapter, int len) +{ + int fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR); + + /* tx_fifo_head is always 16 byte aligned */ + adapter->tx_fifo_head += fifo_pkt_len; + if (adapter->tx_fifo_head >= EM_82547_TX_FIFO_SIZE) { + adapter->tx_fifo_head -= EM_82547_TX_FIFO_SIZE; + } + + return; +} + + +static int +em_82547_tx_fifo_reset(struct adapter *adapter) +{ + uint32_t tctl; + + if ( (E1000_READ_REG(&adapter->hw, TDT) == + E1000_READ_REG(&adapter->hw, TDH)) && + (E1000_READ_REG(&adapter->hw, TDFT) == + E1000_READ_REG(&adapter->hw, TDFH)) && + (E1000_READ_REG(&adapter->hw, TDFTS) == + E1000_READ_REG(&adapter->hw, TDFHS)) && + (E1000_READ_REG(&adapter->hw, TDFPC) == 0)) { + + /* Disable TX unit */ + tctl = E1000_READ_REG(&adapter->hw, TCTL); + E1000_WRITE_REG(&adapter->hw, TCTL, tctl & ~E1000_TCTL_EN); + + /* Reset FIFO pointers */ + E1000_WRITE_REG(&adapter->hw, TDFT, EM_82547_TX_FIFO_BEGIN); + E1000_WRITE_REG(&adapter->hw, TDFH, EM_82547_TX_FIFO_BEGIN); + E1000_WRITE_REG(&adapter->hw, TDFTS, EM_82547_TX_FIFO_BEGIN); + E1000_WRITE_REG(&adapter->hw, TDFHS, EM_82547_TX_FIFO_BEGIN); + + /* Re-enable TX unit */ + E1000_WRITE_REG(&adapter->hw, TCTL, tctl); + E1000_WRITE_FLUSH(&adapter->hw); + + adapter->tx_fifo_head = 0; + adapter->tx_fifo_reset++; + + return(TRUE); + } + else { + return(FALSE); + } +} + static void em_set_promisc(struct adapter * adapter) { @@ -1108,12 +1272,14 @@ em_set_multi(struct adapter * adapter) if (ifma->ifma_addr->sa_family != AF_LINK) continue; + if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break; + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); mcnt++; } - if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) { + if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) { reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); reg_rctl |= E1000_RCTL_MPE; E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); @@ -1157,6 +1323,8 @@ em_local_timer(void *arg) if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { em_print_hw_stats(adapter); } + em_smartspeed(adapter); + adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); splx(s); @@ -1177,6 +1345,7 @@ em_print_link_status(struct adapter * adapter) ((adapter->link_duplex == FULL_DUPLEX) ? "Full Duplex" : "Half Duplex")); adapter->link_active = 1; + adapter->smartspeed = 0; } } else { if (adapter->link_active == 1) { @@ -1190,8 +1359,6 @@ em_print_link_status(struct adapter * adapter) return; } - - /********************************************************************* * * This routine disables all traffic on the adapter by issuing a @@ -1209,7 +1376,9 @@ em_stop(void *arg) INIT_DEBUGOUT("em_stop: begin\n"); em_disable_intr(adapter); em_reset_hw(&adapter->hw); - untimeout(em_local_timer, adapter, adapter->timer_handle); + untimeout(em_local_timer, adapter, adapter->timer_handle); + untimeout(em_82547_move_tail, adapter, + adapter->tx_fifo_timer_handle); em_free_transmit_structures(adapter); em_free_receive_structures(adapter); @@ -1362,6 +1531,9 @@ em_hardware_init(struct adapter * adapter) /* Issue a global reset */ em_reset_hw(&adapter->hw); + /* When hardware is reset, fifo_head is also reset */ + adapter->tx_fifo_head = 0; + /* Make sure we have a good EEPROM before we read from it */ if (em_validate_eeprom_checksum(&adapter->hw) < 0) { printf("em%d: The EEPROM Checksum Is Not Valid\n", @@ -1424,10 +1596,10 @@ em_setup_interface(device_t dev, struct adapter * adapter) ifp->if_watchdog = em_watchdog; ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1; -#if __FreeBSD_version < 500000 - ether_ifattach(ifp, ETHER_BPF_SUPPORTED); +#if __FreeBSD_version < 500000 + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); #else - ether_ifattach(ifp, adapter->interface_data.ac_enaddr); + ether_ifattach(ifp, adapter->interface_data.ac_enaddr); #endif if (adapter->hw.mac_type >= em_82543) { @@ -1435,10 +1607,11 @@ em_setup_interface(device_t dev, struct adapter * adapter) ifp->if_capenable = ifp->if_capabilities; } -#if __FreeBSD_version >= 500000 - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; +#if __FreeBSD_version >= 500000 + ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; #endif + /* * Specify the media types supported by this adapter and register * callbacks to update media and link information @@ -1477,6 +1650,67 @@ em_setup_interface(device_t dev, struct adapter * adapter) /********************************************************************* * + * Workaround for SmartSpeed on 82541 and 82547 controllers + * + **********************************************************************/ +static void +em_smartspeed(struct adapter *adapter) +{ + uint16_t phy_tmp; + + if(adapter->link_active || (adapter->hw.phy_type != em_phy_igp) || + !adapter->hw.autoneg || !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL)) + return; + + if(adapter->smartspeed == 0) { + /* If Master/Slave config fault is asserted twice, + * we assume back-to-back */ + em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); + if(!(phy_tmp & SR_1000T_MS_CONFIG_FAULT)) return; + em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); + if(phy_tmp & SR_1000T_MS_CONFIG_FAULT) { + em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, + &phy_tmp); + if(phy_tmp & CR_1000T_MS_ENABLE) { + phy_tmp &= ~CR_1000T_MS_ENABLE; + em_write_phy_reg(&adapter->hw, + PHY_1000T_CTRL, phy_tmp); + adapter->smartspeed++; + if(adapter->hw.autoneg && + !em_phy_setup_autoneg(&adapter->hw) && + !em_read_phy_reg(&adapter->hw, PHY_CTRL, + &phy_tmp)) { + phy_tmp |= (MII_CR_AUTO_NEG_EN | + MII_CR_RESTART_AUTO_NEG); + em_write_phy_reg(&adapter->hw, + PHY_CTRL, phy_tmp); + } + } + } + return; + } else if(adapter->smartspeed == EM_SMARTSPEED_DOWNSHIFT) { + /* If still no link, perhaps using 2/3 pair cable */ + em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp); + phy_tmp |= CR_1000T_MS_ENABLE; + em_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp); + if(adapter->hw.autoneg && + !em_phy_setup_autoneg(&adapter->hw) && + !em_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_tmp)) { + phy_tmp |= (MII_CR_AUTO_NEG_EN | + MII_CR_RESTART_AUTO_NEG); + em_write_phy_reg(&adapter->hw, PHY_CTRL, phy_tmp); + } + } + /* Restart process after EM_SMARTSPEED_MAX iterations */ + if(adapter->smartspeed++ == EM_SMARTSPEED_MAX) + adapter->smartspeed = 0; + + return; +} + + +/********************************************************************* + * * Allocate memory for tx_buffer structures. The tx_buffer stores all * the information needed to transmit a packet on the wire. * @@ -1561,6 +1795,8 @@ em_initialize_transmit_unit(struct adapter * adapter) case em_82540: case em_82545: case em_82546: + case em_82541: + case em_82547: if (adapter->hw.media_type == em_media_type_fiber) reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER; else @@ -1593,16 +1829,11 @@ em_initialize_transmit_unit(struct adapter * adapter) E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl); /* Setup Transmit Descriptor Settings for this adapter */ - adapter->txd_cmd = E1000_TXD_CMD_IFCS; + adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS; if (adapter->tx_int_delay > 0) adapter->txd_cmd |= E1000_TXD_CMD_IDE; - if (adapter->hw.report_tx_early == 1) - adapter->txd_cmd |= E1000_TXD_CMD_RS; - else - adapter->txd_cmd |= E1000_TXD_CMD_RPS; - return; } @@ -2013,12 +2244,12 @@ em_process_receive_interrupts(struct adapter * adapter, int count) { struct ifnet *ifp; struct mbuf *mp; -#if __FreeBSD_version < 500000 - struct ether_header *eh; +#if __FreeBSD_version < 500000 + struct ether_header *eh; #endif u_int8_t accept_frame = 0; - u_int8_t eop = 0; - u_int16_t len; + u_int8_t eop = 0; + u_int16_t len; int i; /* Pointer to the receive descriptor being examined. */ @@ -2036,6 +2267,7 @@ em_process_receive_interrupts(struct adapter * adapter, int count) } while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) { + mp = adapter->rx_buffer_area[i].m_head; accept_frame = 1; @@ -2099,37 +2331,37 @@ em_process_receive_interrupts(struct adapter * adapter, int count) adapter->fmp->m_pkthdr.len += len; } - if (eop) { - adapter->fmp->m_pkthdr.rcvif = ifp; + if (eop) { + adapter->fmp->m_pkthdr.rcvif = ifp; -#if __FreeBSD_version < 500000 - eh = mtod(adapter->fmp, struct ether_header *); - /* Remove ethernet header from mbuf */ - m_adj(adapter->fmp, sizeof(struct ether_header)); - em_receive_checksum(adapter, current_desc, - adapter->fmp); - if (current_desc->status & E1000_RXD_STAT_VP) - VLAN_INPUT_TAG(eh, adapter->fmp, - (current_desc->special & +#if __FreeBSD_version < 500000 + eh = mtod(adapter->fmp, struct ether_header *); + /* Remove ethernet header from mbuf */ + m_adj(adapter->fmp, sizeof(struct ether_header)); + em_receive_checksum(adapter, current_desc, + adapter->fmp); + if (current_desc->status & E1000_RXD_STAT_VP) + VLAN_INPUT_TAG(eh, adapter->fmp, + (current_desc->special & E1000_RXD_SPC_VLAN_MASK)); - else - ether_input(ifp, eh, adapter->fmp); + else + ether_input(ifp, eh, adapter->fmp); #else - em_receive_checksum(adapter, current_desc, - adapter->fmp); - if (current_desc->status & E1000_RXD_STAT_VP) - VLAN_INPUT_TAG(ifp, adapter->fmp, - (current_desc->special & - E1000_RXD_SPC_VLAN_MASK), + em_receive_checksum(adapter, current_desc, + adapter->fmp); + if (current_desc->status & E1000_RXD_STAT_VP) + VLAN_INPUT_TAG(ifp, adapter->fmp, + (current_desc->special & + E1000_RXD_SPC_VLAN_MASK), adapter->fmp = NULL); - - if (adapter->fmp != NULL) - (*ifp->if_input)(ifp, adapter->fmp); + + if (adapter->fmp != NULL) + (*ifp->if_input)(ifp, adapter->fmp); #endif - adapter->fmp = NULL; - adapter->lmp = NULL; - } + adapter->fmp = NULL; + adapter->lmp = NULL; + } } else { adapter->dropped_pkts++; em_get_buf(i, adapter, mp); @@ -2206,7 +2438,7 @@ em_enable_vlans(struct adapter *adapter) { uint32_t ctrl; - E1000_WRITE_REG(&adapter->hw, VET, QTAG_TYPE); + E1000_WRITE_REG(&adapter->hw, VET, ETHERTYPE_VLAN); ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl |= E1000_CTRL_VME; @@ -2277,7 +2509,7 @@ em_io_write(struct em_hw *hw, uint32_t port, uint32_t value) { outl(port, value); return; -} +} /********************************************************************** * @@ -2294,6 +2526,7 @@ em_update_stats_counters(struct adapter *adapter) 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); + adapter->stats.mcc += E1000_READ_REG(&adapter->hw, MCC); adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL); adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC); @@ -2404,14 +2637,18 @@ em_print_hw_stats(struct adapter *adapter) adapter->clean_tx_interrupts); #endif + printf("em%d: fifo workaround = %lld, fifo_reset = %lld\n", unit, + (long long)adapter->tx_fifo_wrk, + (long long)adapter->tx_fifo_reset); + printf("em%d: hw tdh = %d, hw tdt = %d\n", unit, + E1000_READ_REG(&adapter->hw, TDH), + E1000_READ_REG(&adapter->hw, TDT)); + printf("em%d: Excessive collisions = %lld\n", unit, + (long long)adapter->stats.ecol); printf("em%d: Tx Descriptors not avail1 = %ld\n", unit, adapter->no_tx_desc_avail1); printf("em%d: Tx Descriptors not avail2 = %ld\n", unit, adapter->no_tx_desc_avail2); - printf("em%d: Std Mbuf Failed = %ld\n",unit, - adapter->mbuf_alloc_failed); - printf("em%d: Std Cluster Failed = %ld\n",unit, - adapter->mbuf_cluster_failed); printf("em%d: Symbol errors = %lld\n", unit, (long long)adapter->stats.symerrs); diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h index 6d7afac..664dcbf 100644 --- a/sys/dev/em/if_em.h +++ b/sys/dev/em/if_em.h @@ -1,6 +1,6 @@ /************************************************************************** -Copyright (c) 2001-2002, Intel Corporation +Copyright (c) 2001-2003, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -78,15 +78,6 @@ POSSIBILITY OF SUCH DAMAGE. /* Tunables */ /* - * FlowControl - * Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx) - * Default: Read flow control settings from the EEPROM - * This parameter controls the automatic generation(Tx) and response(Rx) to - * Ethernet PAUSE frames. - */ - - -/* * TxDescriptors * Valid Range: 80-256 for 82542 and 82543-based adapters * 80-4096 for 82540, 82544, 82545, and 82546-based adapters @@ -177,16 +168,6 @@ POSSIBILITY OF SUCH DAMAGE. */ #define EM_MAX_INTR 3 - -/* - * This parameter determines when the hardware will report that it is - * done with the packet. - * 0 - "Done" is reported when the packet has been sent on the wire - * 1 - "Done" is reported when the packet has been DMA'ed and is on chip. - * 2 - Determine the best method. - */ -#define EM_REPORT_TX_EARLY 2 - /* * Inform the stack about transmit checksum offload capabilities. */ @@ -228,18 +209,16 @@ POSSIBILITY OF SUCH DAMAGE. #define EM_VENDOR_ID 0x8086 #define EM_MMBA 0x0010 /* Mem base address */ #define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) + #define EM_JUMBO_PBA 0x00000028 #define EM_DEFAULT_PBA 0x00000030 +#define EM_SMARTSPEED_DOWNSHIFT 3 +#define EM_SMARTSPEED_MAX 15 + -#define IOCTL_CMD_TYPE u_long #define MAX_NUM_MULTICAST_ADDRESSES 128 #define PCI_ANY_ID (~0U) - -#ifndef ETHER_ALIGN #define ETHER_ALIGN 2 -#endif - -#define QTAG_TYPE 0x8100 /* Defines for printing debug information */ #define DEBUG_INIT 0 @@ -311,6 +290,7 @@ struct adapter { void *int_handler_tag; struct ifmedia media; struct callout_handle timer_handle; + struct callout_handle tx_fifo_timer_handle; int io_rid; u_int8_t unit; @@ -319,6 +299,7 @@ struct adapter { u_int8_t link_active; 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; @@ -357,11 +338,11 @@ struct adapter { u_int32_t rx_buffer_len; struct em_buffer *rx_buffer_area; - /* Jumbo frame */ - struct mbuf *fmp; - struct mbuf *lmp; + struct mbuf *fmp; + struct mbuf *lmp; + u_int16_t tx_fifo_head; /* Misc stats maintained by the driver */ unsigned long dropped_pkts; @@ -369,12 +350,14 @@ struct adapter { unsigned long mbuf_cluster_failed; unsigned long no_tx_desc_avail1; unsigned long no_tx_desc_avail2; + u_int64_t tx_fifo_reset; + u_int64_t tx_fifo_wrk; + #ifdef DBG_STATS unsigned long no_pkts_avail; unsigned long clean_tx_interrupts; #endif - struct em_hw_stats stats; }; diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c index 88bf617..6803fd8 100644 --- a/sys/dev/em/if_em_hw.c +++ b/sys/dev/em/if_em_hw.c @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright (c) 2001-2002, Intel Corporation + Copyright (c) 2001-2003, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -35,9 +35,11 @@ /* if_em_hw.c * Shared functions for accessing and configuring the MAC */ - + #include <dev/em/if_em_hw.h> +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_phy_force_speed_duplex(struct em_hw *hw); @@ -48,22 +50,103 @@ 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 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, + uint16_t words, uint16_t *data); +static int32_t em_write_eeprom_microwire(struct em_hw *hw, + uint16_t offset, uint16_t words, + uint16_t *data); +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 uint16_t em_shift_in_ee_bits(struct em_hw *hw); -static void em_setup_eeprom(struct em_hw *hw); -static void em_clock_eeprom(struct em_hw *hw); -static void em_cleanup_eeprom(struct em_hw *hw); +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); +/****************************************************************************** + * Set the phy type member in the hw struct. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +em_set_phy_type(struct em_hw *hw) +{ + DEBUGFUNC("em_set_phy_type"); + + switch(hw->phy_id) { + case M88E1000_E_PHY_ID: + case M88E1000_I_PHY_ID: + case M88E1011_I_PHY_ID: + hw->phy_type = em_phy_m88; + break; + case IGP01E1000_I_PHY_ID: + hw->phy_type = em_phy_igp; + break; + default: + /* Should never have loaded on this device */ + hw->phy_type = em_phy_undefined; + return -E1000_ERR_PHY_TYPE; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** + * IGP phy init script - initializes the GbE PHY + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +em_phy_init_script(struct em_hw *hw) +{ + DEBUGFUNC("em_phy_init_script"); + + if(hw->phy_init_script) { + msec_delay(10); + + 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); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79); + em_write_phy_reg(hw,0x0019,0x0018); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30); + em_write_phy_reg(hw,0x0010,0x1600); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31); + em_write_phy_reg(hw,0x0011,0x0014); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32); + em_write_phy_reg(hw,0x0012,0x161C); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94); + em_write_phy_reg(hw,0x0014,0x0003); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96); + em_write_phy_reg(hw,0x0016,0x003F); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010); + em_write_phy_reg(hw,0x0010,0x0008); + + em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); + em_write_phy_reg(hw,0x0000,0x3300); + } +} /****************************************************************************** * Set the mac type member in the hw struct. - * + * * hw - Struct containing variables accessed by shared code *****************************************************************************/ int32_t @@ -110,6 +193,13 @@ em_set_mac_type(struct em_hw *hw) case E1000_DEV_ID_82546EB_FIBER: hw->mac_type = em_82546; break; + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + hw->mac_type = em_82541; + break; + case E1000_DEV_ID_82547EI: + hw->mac_type = em_82547; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; @@ -130,9 +220,10 @@ em_reset_hw(struct em_hw *hw) uint32_t ctrl_ext; uint32_t icr; uint32_t manc; + uint32_t led_ctrl; DEBUGFUNC("em_reset_hw"); - + /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ if(hw->mac_type == em_82542_rev2_0) { DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); @@ -156,7 +247,7 @@ em_reset_hw(struct em_hw *hw) /* Delay to allow any outstanding PCI transactions to complete before * resetting the device - */ + */ msec_delay(10); /* Issue a global reset to the MAC. This will reset the chip's @@ -167,7 +258,13 @@ em_reset_hw(struct em_hw *hw) DEBUGOUT("Issuing a global reset to MAC\n"); ctrl = E1000_READ_REG(hw, CTRL); - if(hw->mac_type > em_82543) + /* Must reset the PHY before resetting the MAC */ + if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); + msec_delay(5); + } + + if((hw->mac_type > em_82543) && (hw->mac_type != em_82547)) E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST)); else E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); @@ -184,13 +281,25 @@ em_reset_hw(struct em_hw *hw) msec_delay(2); } else { /* Wait for EEPROM reload (it happens automatically) */ - msec_delay(4); + msec_delay(5); /* Dissable HW ARPs on ASF enabled adapters */ manc = E1000_READ_REG(hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(hw, MANC, manc); } - + + if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + em_phy_init_script(hw); + + /* 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; + if(hw->mac_type == em_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } + /* Clear interrupt mask to stop board from generating interrupts */ DEBUGOUT("Masking off all interrupts\n"); E1000_WRITE_REG(hw, IMC, 0xffffffff); @@ -209,8 +318,8 @@ em_reset_hw(struct em_hw *hw) * Performs basic configuration of the adapter. * * hw - Struct containing variables accessed by shared code - * - * Assumes that the controller has previously been reset and is in a + * + * Assumes that the controller has previously been reset and is in a * post-reset uninitialized state. Initializes the receive address registers, * multicast table, and VLAN filter table. Calls routines to setup link * configuration and flow control settings. Clears all on-chip counters. Leaves @@ -235,7 +344,7 @@ em_init_hw(struct em_hw *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 */ @@ -338,13 +447,13 @@ em_init_hw(struct em_hw *hw) /****************************************************************************** * Configures flow control and link settings. - * + * * hw - Struct containing variables accessed by shared code - * + * * Determines which flow control settings to use. Calls the apropriate media- * specific link configuration function. Configures the flow control settings. * Assuming the adapter has a valid link partner, a valid link should be - * established. Assumes the hardware has previously been reset and the + * established. Assumes the hardware has previously been reset and the * transmitter and receiver are not enabled. *****************************************************************************/ int32_t @@ -364,7 +473,7 @@ em_setup_link(struct em_hw *hw) * control setting, then the variable hw->fc will * be initialized based on a value in the EEPROM. */ - if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) { + if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -372,7 +481,7 @@ em_setup_link(struct em_hw *hw) if(hw->fc == em_fc_default) { if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0) hw->fc = em_fc_none; - else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == + else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) hw->fc = em_fc_tx_pause; else @@ -401,7 +510,7 @@ em_setup_link(struct em_hw *hw) * or em_phy_setup() is called. */ if(hw->mac_type == em_82543) { - ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << + ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << SWDPIO__EXT_SHIFT); E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); } @@ -427,7 +536,7 @@ em_setup_link(struct em_hw *hw) * these registers will be set to a default threshold that may be * adjusted later by the driver's runtime code. However, if the * ability to transmit pause frames in not enabled, then these - * registers will be set to 0. + * registers will be set to 0. */ if(!(hw->fc & em_fc_tx_pause)) { E1000_WRITE_REG(hw, FCRTL, 0); @@ -456,7 +565,7 @@ em_setup_link(struct em_hw *hw) * link. Assumes the hardware has been previously reset and the transmitter * and receiver are not enabled. *****************************************************************************/ -static int32_t +static int32_t em_setup_fiber_link(struct em_hw *hw) { uint32_t ctrl; @@ -468,29 +577,29 @@ em_setup_fiber_link(struct em_hw *hw) DEBUGFUNC("em_setup_fiber_link"); - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be - * set when the optics detect a signal. On older adapters, it will be + /* On adapters with a MAC newer that 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 */ ctrl = E1000_READ_REG(hw, CTRL); if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1; else signal = 0; - + /* Take the link out of reset */ ctrl &= ~(E1000_CTRL_LRST); - + em_config_collision_dist(hw); /* Check for a software override of the flow control settings, and setup * the device accordingly. If auto-negotiation is enabled, then software * will have to set the "PAUSE" bits to the correct value in the Tranmsit * Config Word Register (TXCW) and re-start auto-negotiation. However, if - * auto-negotiation is disabled, then software will have to manually + * auto-negotiation is disabled, then software will have to manually * configure the two flow control enable bits in the CTRL register. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, but + * 1: Rx flow control is enabled (we can receive pause frames, but * not send pause frames). * 2: Tx flow control is enabled (we can send pause frames but we do * not support receiving pause frames). @@ -502,8 +611,8 @@ em_setup_fiber_link(struct em_hw *hw) txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); break; case em_fc_rx_pause: - /* RX Flow control is enabled and TX Flow control is disabled by a - * software over-ride. Since there really isn't a way to advertise + /* RX Flow control is enabled and TX Flow control is disabled by a + * software over-ride. Since there really isn't a way to advertise * that we are capable of RX Pause ONLY, we will advertise that we * support both symmetric and asymmetric RX PAUSE. Later, we will * disable the adapter's ability to send PAUSE frames. @@ -511,7 +620,7 @@ em_setup_fiber_link(struct em_hw *hw) txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); break; case em_fc_tx_pause: - /* TX Flow control is enabled, and RX Flow control is disabled, by a + /* TX Flow control is enabled, and RX Flow control is disabled, by a * software over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); @@ -542,8 +651,8 @@ em_setup_fiber_link(struct em_hw *hw) msec_delay(1); /* If we have a signal (the cable is plugged in) then poll for a "Link-Up" - * indication in the Device Status Register. Time-out if a link isn't - * seen in 500 milliseconds seconds (Auto-negotiation should complete in + * 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). */ if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) { @@ -554,7 +663,7 @@ em_setup_fiber_link(struct em_hw *hw) if(status & E1000_STATUS_LU) break; } if(i == (LINK_UP_TIMEOUT / 10)) { - /* AutoNeg failed to achieve a link, so we'll call + /* AutoNeg failed to achieve a link, so we'll call * em_check_for_link. This routine will force the link up if we * detect a signal. This will allow us to communicate with * non-autonegotiating link partners. @@ -582,10 +691,10 @@ em_setup_fiber_link(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -static int32_t +static int32_t em_setup_copper_link(struct em_hw *hw) { - uint32_t ctrl; + uint32_t ctrl, led_ctrl; int32_t ret_val; uint16_t i; uint16_t phy_data; @@ -615,6 +724,69 @@ em_setup_copper_link(struct em_hw *hw) } DEBUGOUT1("Phy ID = %x \n", hw->phy_id); +if (hw->phy_type == em_phy_igp) { + + ret_val = em_phy_reset(hw); + if(ret_val < 0) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } + + /* Wait 10ms for MAC to configure PHY from eeprom settings */ + msec_delay(15); + + if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + + /* 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; + if(hw->mac_type == em_82547) + led_ctrl |= 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; + } + 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; + } + } + + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + + /* Force MDI for IGP PHY */ + phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX); + + hw->mdix = 1; + + if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + +} 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"); @@ -688,7 +860,8 @@ em_setup_copper_link(struct em_hw *hw) DEBUGOUT("Error Resetting the PHY\n"); return ret_val; } - +} + /* Options: * autoneg = 1 (default) * PHY will advertise value(s) parsed from @@ -747,6 +920,7 @@ em_setup_copper_link(struct em_hw *hw) return ret_val; } } + hw->get_link_status = TRUE; } else { DEBUGOUT("Forcing speed and duplex\n"); ret_val = em_phy_force_speed_duplex(hw); @@ -1025,6 +1199,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Write the configured values back to the Device Control Reg. */ 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; @@ -1042,6 +1217,23 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Need to reset the PHY or these changes will be ignored */ mii_ctrl_reg |= MII_CR_RESET; +} else { + /* 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; + } + + 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; + } +} /* Write back the modified PHY MII control register. */ if(em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) { @@ -1080,7 +1272,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) } 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) { DEBUGOUT("Error Resetting PHY DSP\n"); @@ -1104,7 +1296,8 @@ em_phy_force_speed_duplex(struct em_hw *hw) } } } - + +if (hw->phy_type == em_phy_m88) { /* Because we reset the PHY above, we need to re-force TX_CLK in the * Extended PHY Specific Control Register to 25MHz clock. This value * defaults back to a 2.5MHz clock when the PHY is reset. @@ -1131,6 +1324,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } +} return 0; } @@ -1147,6 +1341,8 @@ em_config_collision_dist(struct em_hw *hw) { uint32_t tctl; + DEBUGFUNC("em_config_collision_dist"); + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_COLD; @@ -1183,6 +1379,26 @@ em_config_mac_to_phy(struct em_hw *hw) /* Set up duplex in the Device Control and Transmit Control * 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(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD; + else ctrl &= ~E1000_CTRL_FD; + + em_config_collision_dist(hw); + + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) + ctrl |= E1000_CTRL_SPD_1000; + else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + 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; @@ -1199,6 +1415,7 @@ em_config_mac_to_phy(struct em_hw *hw) ctrl |= E1000_CTRL_SPD_1000; else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) ctrl |= E1000_CTRL_SPD_100; +} /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); return 0; @@ -1206,7 +1423,7 @@ em_config_mac_to_phy(struct em_hw *hw) /****************************************************************************** * Forces the MAC's flow control settings. - * + * * hw - Struct containing variables accessed by shared code * * Sets the TFCE and RFCE bits in the device control register to reflect @@ -1273,7 +1490,7 @@ em_force_mac_fc(struct em_hw *hw) /****************************************************************************** * Configures flow control settings after link is established - * + * * hw - Struct containing variables accessed by shared code * * Should be called immediately after a valid link has been established. @@ -1495,9 +1712,9 @@ em_check_for_link(struct em_hw *hw) uint16_t lp_capability; DEBUGFUNC("em_check_for_link"); - - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be - * set when the optics detect a signal. On older adapters, it will be + + /* On adapters with a MAC newer that 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 */ if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1; @@ -1530,6 +1747,10 @@ em_check_for_link(struct em_hw *hw) if(phy_data & MII_SR_LINK_STATUS) { hw->get_link_status = FALSE; + /* Check if there was DownShift, must be checked immediately after + * link-up */ + em_check_downshift(hw); + } else { /* No link detected */ return 0; @@ -1558,7 +1779,7 @@ em_check_for_link(struct em_hw *hw) } } - /* Configure Flow Control now that Auto-Neg has completed. First, we + /* Configure Flow Control now that Auto-Neg has completed. First, we * need to restore the desired flow control settings because we may * have had to re-autoneg with a different link partner. */ @@ -1587,7 +1808,7 @@ em_check_for_link(struct em_hw *hw) NWAY_LPAR_100TX_HD_CAPS | NWAY_LPAR_100TX_FD_CAPS | NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to + /* If our link partner advertises anything in addition to * gigabit, we do not need to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { @@ -1791,7 +2012,7 @@ em_shift_out_mdi_bits(struct em_hw *hw, uint32_t mask; /* We need to shift "count" number of bits out to the PHY. So, the value - * in the "data" parameter will be shifted out to the PHY one bit at a + * in the "data" parameter will be shifted out to the PHY one bit at a * time. In order to do this, "data" must be broken down into bits. */ mask = 0x01; @@ -1828,7 +2049,7 @@ em_shift_out_mdi_bits(struct em_hw *hw, * * hw - Struct containing variables accessed by shared code * -* Bits are shifted in in MSB to LSB order. +* Bits are shifted in in MSB to LSB order. ******************************************************************************/ static uint16_t em_shift_in_mdi_bits(struct em_hw *hw) @@ -1843,7 +2064,7 @@ em_shift_in_mdi_bits(struct em_hw *hw) * These two bits are ignored by us and thrown away. Bits are "shifted in" * by raising the input to the Management Data Clock (setting the MDC bit), * and then reading the value of the MDIO bit. - */ + */ ctrl = E1000_READ_REG(hw, CTRL); /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */ @@ -1903,7 +2124,7 @@ em_read_phy_reg(struct em_hw *hw, * PHY to retrieve the desired data. */ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) | - (phy_addr << E1000_MDIC_PHY_SHIFT) | + (phy_addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_READ)); E1000_WRITE_REG(hw, MDIC, mdic); @@ -1941,7 +2162,7 @@ em_read_phy_reg(struct em_hw *hw, * READ operation is performed. These two bits are thrown away * followed by a shift in of 16 bits which contains the desired data. */ - mdic = ((reg_addr) | (phy_addr << 5) | + mdic = ((reg_addr) | (phy_addr << 5) | (PHY_OP_READ << 10) | (PHY_SOF << 12)); em_shift_out_mdi_bits(hw, mdic, 14); @@ -1985,7 +2206,7 @@ em_write_phy_reg(struct em_hw *hw, */ mdic = (((uint32_t) phy_data) | (reg_addr << E1000_MDIC_REG_SHIFT) | - (phy_addr << E1000_MDIC_PHY_SHIFT) | + (phy_addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_WRITE)); E1000_WRITE_REG(hw, MDIC, mdic); @@ -2003,12 +2224,12 @@ em_write_phy_reg(struct em_hw *hw, } else { /* We'll need to use the SW defined pins to shift the write command * out to the PHY. We first send a preamble to the PHY to signal the - * beginning of the MII instruction. This is done by sending 32 + * beginning of the MII instruction. This is done by sending 32 * consecutive "1" bits. */ em_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); - /* Now combine the remaining required fields that will indicate a + /* Now combine the remaining required fields that will indicate a * write operation. We use this method instead of calling the * em_shift_out_mdi_bits routine for each field in the command. The * format of a MII write instruction is as follows: @@ -2021,6 +2242,7 @@ em_write_phy_reg(struct em_hw *hw, em_shift_out_mdi_bits(hw, mdic, 32); } + return 0; } @@ -2032,8 +2254,7 @@ em_write_phy_reg(struct em_hw *hw, void em_phy_hw_reset(struct em_hw *hw) { - uint32_t ctrl; - uint32_t ctrl_ext; + uint32_t ctrl, ctrl_ext, led_ctrl; DEBUGFUNC("em_phy_hw_reset"); @@ -2064,6 +2285,21 @@ em_phy_hw_reset(struct em_hw *hw) E1000_WRITE_FLUSH(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; + led_ctrl |= IGP_ACTIVITY_LED_ENABLE; + if(hw->mac_type == em_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } } /****************************************************************************** @@ -2090,6 +2326,9 @@ em_phy_reset(struct em_hw *hw) return -E1000_ERR_PHY; } usec_delay(1); + if (hw->phy_type == em_phy_igp) { + em_phy_init_script(hw); + } return 0; } @@ -2103,6 +2342,7 @@ em_detect_gig_phy(struct em_hw *hw) { uint16_t phy_id_high, phy_id_low; boolean_t match = FALSE; + int32_t phy_init_status; DEBUGFUNC("em_detect_gig_phy"); @@ -2112,7 +2352,11 @@ em_detect_gig_phy(struct em_hw *hw) return -E1000_ERR_PHY; } hw->phy_id = (uint32_t) (phy_id_high << 16); - usec_delay(2); +#ifdef MPW3 + /* Tabor/Mpw - changed from 2 to 20 since it did not read the low word in + * the mpw, might be fixed in A0 */ +#endif + usec_delay(20); if(em_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; @@ -2120,23 +2364,39 @@ em_detect_gig_phy(struct em_hw *hw) hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK); hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK; +#ifdef MPW3 /* Tabor MPW3 workaround, expect to be removed in Tabor A0 */ + /* workaround for MPW - IGP PHYID is incorrect! */ + if(hw->phy_id == 0x02A80400) + hw->phy_id = 0x02A80380; + +#endif switch(hw->mac_type) { case em_82543: if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE; break; case em_82544: if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE; +#ifdef MPW3 /* MPW3 only, expected to be removed in Tabor A0 */ + /* MPW driver only - IGP should work with Cordova */ + if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; +#endif break; case em_82540: case em_82545: case em_82546: if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE; break; + case em_82541: + case em_82547: + if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; } - if(match) { + phy_init_status = em_set_phy_type(hw); + + if ((match) && (phy_init_status == E1000_SUCCESS)) { DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id); return 0; } @@ -2154,7 +2414,7 @@ em_phy_reset_dsp(struct em_hw *hw) { int32_t ret_val = -E1000_ERR_PHY; 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; @@ -2167,6 +2427,133 @@ em_phy_reset_dsp(struct em_hw *hw) } /****************************************************************************** +* Get PHY information from various PHY registers for igp PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info) +{ + uint16_t phy_data, polarity, min_length, max_length, average; + + DEBUGFUNC("em_phy_igp_get_info"); + + /* The downshift status is checked only once, after link is established, + * and it stored in the hw->speed_downgraded parameter. */ + phy_info->downshift = hw->speed_downgraded; + + /* IGP01E1000 does not need to support it. */ + phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_normal; + + /* IGP01E1000 always correct polarity reversal */ + phy_info->polarity_correction = em_polarity_reversal_enabled; + + /* Check polarity status */ + if(em_check_polarity(hw, &polarity) < 0) + return -E1000_ERR_PHY; + + phy_info->cable_polarity = polarity; + + if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >> + IGP01E1000_PSSR_MDIX_SHIFT; + + 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; + + phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + /* Get cable length */ + if(em_get_cable_length(hw, &min_length, &max_length) < 0) + return -E1000_ERR_PHY; + + /* transalte to old method */ + average = (max_length + min_length) / 2; + + if(average <= em_igp_cable_length_50) + phy_info->cable_length = em_cable_length_50; + else if(average <= em_igp_cable_length_80) + phy_info->cable_length = em_cable_length_50_80; + else if(average <= em_igp_cable_length_110) + phy_info->cable_length = em_cable_length_80_110; + else if(average <= em_igp_cable_length_140) + phy_info->cable_length = em_cable_length_110_140; + else + phy_info->cable_length = em_cable_length_140; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** +* Get PHY information from various PHY registers fot m88 PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info) +{ + uint16_t phy_data, polarity; + + DEBUGFUNC("em_phy_m88_get_info"); + + /* The downshift status is checked only once, after link is established, + * 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; + + phy_info->extended_10bt_distance = + (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> + M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + phy_info->polarity_correction = + (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >> + M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + /* Check polarity status */ + if(em_check_polarity(hw, &polarity) < 0) + return -E1000_ERR_PHY; + + phy_info->cable_polarity = polarity; + + if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> + M88E1000_PSSR_MDIX_SHIFT; + + if(phy_data & M88E1000_PSSR_1000MBS) { + /* Cable Length Estimation and Local/Remote Receiver Informatoion + * are only valid at 1000 Mbps + */ + 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; + + phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** * Get PHY information from various PHY registers * * hw - Struct containing variables accessed by shared code @@ -2176,7 +2563,6 @@ int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info) { - int32_t ret_val = -E1000_ERR_PHY; uint16_t phy_data; DEBUGFUNC("em_phy_get_info"); @@ -2184,6 +2570,7 @@ em_phy_get_info(struct em_hw *hw, phy_info->cable_length = em_cable_length_undefined; phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_undefined; phy_info->cable_polarity = em_rev_polarity_undefined; + phy_info->downshift = em_downshift_undefined; phy_info->polarity_correction = em_polarity_reversal_undefined; phy_info->mdix_mode = em_auto_x_mode_undefined; phy_info->local_rx = em_1000t_rx_status_undefined; @@ -2194,47 +2581,23 @@ em_phy_get_info(struct em_hw *hw, return -E1000_ERR_CONFIG; } - do { - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break; - if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break; - 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(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) - break; - phy_info->extended_10bt_distance = - (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> - M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; - phy_info->polarity_correction = - (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >> - M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; - - if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) - break; - phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> - M88E1000_PSSR_REV_POLARITY_SHIFT; - phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> - M88E1000_PSSR_MDIX_SHIFT; - if(phy_data & M88E1000_PSSR_1000MBS) { - /* Cable Length Estimation and Local/Remote Receiver Informatoion - * are only valid at 1000 Mbps - */ - 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) - break; - phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> - SR_1000T_LOCAL_RX_STATUS_SHIFT; - phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> - SR_1000T_REMOTE_RX_STATUS_SHIFT; - } - ret_val = 0; - } while(0); + 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) != MII_SR_LINK_STATUS) { + DEBUGOUT("PHY info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } - if(ret_val < 0) DEBUGOUT("PHY Read Error\n"); - return ret_val; + 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); } int32_t @@ -2251,6 +2614,107 @@ em_validate_mdi_setting(struct em_hw *hw) } +/****************************************************************************** + * Sets up eeprom variables in the hw struct. Must be called after mac_type + * is configured. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_init_eeprom_params(struct em_hw *hw) +{ + struct em_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd = E1000_READ_REG(hw, EECD); + uint16_t eeprom_size; + + DEBUGFUNC("em_init_eeprom_params"); + + switch (hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + case em_82543: + case em_82544: + eeprom->type = em_eeprom_microwire; + eeprom->word_size = 64; + eeprom->opcode_bits = 3; + eeprom->address_bits = 6; + eeprom->delay_usec = 50; + break; + case em_82540: + case em_82545: + case em_82546: + eeprom->type = em_eeprom_microwire; + eeprom->opcode_bits = 3; + eeprom->delay_usec = 50; + if(eecd & E1000_EECD_SIZE) { + eeprom->word_size = 256; + eeprom->address_bits = 8; + } else { + eeprom->word_size = 64; + eeprom->address_bits = 6; + } + break; + case em_82541: + case em_82547: + default: + if (eecd & E1000_EECD_TYPE) { + 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; + } + } else { + eeprom->type = em_eeprom_microwire; + eeprom->opcode_bits = 3; + eeprom->delay_usec = 50; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->word_size = 256; + eeprom->address_bits = 8; + } else { + eeprom->word_size = 64; + eeprom->address_bits = 6; + } + } + break; + } + + if (eeprom->type == em_eeprom_spi) { + eeprom->word_size = 64; + if (em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) { + 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; + } + } + } +} /****************************************************************************** * Raises the EEPROM's clock input. @@ -2268,26 +2732,26 @@ em_raise_ee_clk(struct em_hw *hw, *eecd = *eecd | E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + usec_delay(hw->eeprom.delay_usec); } /****************************************************************************** * Lowers the EEPROM's clock input. * - * hw - Struct containing variables accessed by shared code + * hw - Struct containing variables accessed by shared code * eecd - EECD's current value *****************************************************************************/ static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd) { - /* Lower the clock input to the EEPROM (by clearing the SK bit), and then - * wait 50 microseconds. + /* Lower the clock input to the EEPROM (by clearing the SK bit), and then + * wait 50 microseconds. */ *eecd = *eecd & ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + usec_delay(hw->eeprom.delay_usec); } /****************************************************************************** @@ -2302,16 +2766,21 @@ em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, uint16_t count) { + struct em_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; uint32_t mask; /* We need to shift "count" bits out to the EEPROM. So, value in the * "data" parameter will be shifted out to the EEPROM one bit at a time. - * In order to do this, "data" must be broken down into bits. + * In order to do this, "data" must be broken down into bits. */ mask = 0x01 << (count - 1); eecd = E1000_READ_REG(hw, EECD); - eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); + if (eeprom->type == em_eeprom_microwire) { + eecd &= ~E1000_EECD_DO; + } else if (eeprom->type == em_eeprom_spi) { + eecd |= E1000_EECD_DO; + } do { /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", * and then raising and then lowering the clock (the SK bit controls @@ -2326,7 +2795,7 @@ em_shift_out_ee_bits(struct em_hw *hw, E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - usec_delay(50); + usec_delay(eeprom->delay_usec); em_raise_ee_clk(hw, &eecd); em_lower_ee_clk(hw, &eecd); @@ -2346,7 +2815,7 @@ 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) +em_shift_in_ee_bits(struct em_hw *hw, uint16_t count) { uint32_t eecd; uint32_t i; @@ -2364,7 +2833,7 @@ em_shift_in_ee_bits(struct em_hw *hw) eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); data = 0; - for(i = 0; i < 16; i++) { + for(i = 0; i < count; i++) { data = data << 1; em_raise_ee_clk(hw, &eecd); @@ -2385,104 +2854,196 @@ em_shift_in_ee_bits(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code * - * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This + * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This * function should be called before issuing a command to the EEPROM. *****************************************************************************/ -static void -em_setup_eeprom(struct em_hw *hw) +static int32_t +em_acquire_eeprom(struct em_hw *hw) { - uint32_t eecd; + struct em_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd, i=0; + + DEBUGFUNC("em_acquire_eeprom"); eecd = E1000_READ_REG(hw, EECD); - /* Clear SK and DI */ - eecd &= ~(E1000_EECD_SK | E1000_EECD_DI); - E1000_WRITE_REG(hw, EECD, eecd); + /* Request EEPROM Access */ + if(hw->mac_type > em_82544) { + eecd |= E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + eecd = E1000_READ_REG(hw, EECD); + while((!(eecd & E1000_EECD_GNT)) && + (i < E1000_EEPROM_GRANT_ATTEMPTS)) { + i++; + usec_delay(5); + eecd = E1000_READ_REG(hw, EECD); + } + if(!(eecd & E1000_EECD_GNT)) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + DEBUGOUT("Could not acquire EEPROM grant\n"); + return -E1000_ERR_EEPROM; + } + } - /* Set CS */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, EECD, eecd); + /* Setup EEPROM for Read/Write */ + + if (eeprom->type == em_eeprom_microwire) { + /* Clear SK and DI */ + eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + + /* Set CS */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + } else if (eeprom->type == em_eeprom_spi) { + /* Clear SK and CS */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + usec_delay(1); + } + + return E1000_SUCCESS; } /****************************************************************************** * Returns EEPROM to a "standby" state - * + * * hw - Struct containing variables accessed by shared code *****************************************************************************/ static void em_standby_eeprom(struct em_hw *hw) { + struct em_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; eecd = E1000_READ_REG(hw, EECD); - /* Deselct EEPROM */ - eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + if(eeprom->type == em_eeprom_microwire) { + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); - /* Clock high */ - eecd |= E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + /* Clock high */ + eecd |= E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); - /* Select EEPROM */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + /* Select EEPROM */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); - /* Clock low */ - eecd &= ~E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + /* Clock low */ + eecd &= ~E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); + } else if(eeprom->type == em_eeprom_spi) { + /* Toggle CS to flush commands */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); + eecd &= ~E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(eeprom->delay_usec); + } } /****************************************************************************** - * Raises then lowers the EEPROM's clock pin + * Terminates a command by inverting the EEPROM's chip select pin * * hw - Struct containing variables accessed by shared code *****************************************************************************/ static void -em_clock_eeprom(struct em_hw *hw) +em_release_eeprom(struct em_hw *hw) { uint32_t eecd; + DEBUGFUNC("em_release_eeprom"); + eecd = E1000_READ_REG(hw, EECD); - /* Rising edge of clock */ - eecd |= E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + if (hw->eeprom.type == em_eeprom_spi) { + eecd |= E1000_EECD_CS; /* Pull CS high */ + eecd &= ~E1000_EECD_SK; /* Lower SCK */ - /* Falling edge of clock */ - eecd &= ~E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(50); + E1000_WRITE_REG(hw, EECD, eecd); + + usec_delay(hw->eeprom.delay_usec); + } else if(hw->eeprom.type == em_eeprom_microwire) { + /* cleanup eeprom */ + + /* CS on Microwire is active-high */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + + E1000_WRITE_REG(hw, EECD, eecd); + + /* Rising edge of clock */ + eecd |= E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(hw->eeprom.delay_usec); + + /* Falling edge of clock */ + eecd &= ~E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(hw->eeprom.delay_usec); + } + + /* Stop requesting EEPROM access */ + if(hw->mac_type > em_82544) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + } } /****************************************************************************** - * Terminates a command by lowering the EEPROM's chip select pin + * Reads a 16 bit word from the EEPROM. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -static void -em_cleanup_eeprom(struct em_hw *hw) +int32_t +em_spi_eeprom_ready(struct em_hw *hw) { - uint32_t eecd; + uint16_t retry_count = 0; + uint8_t spi_stat_reg; - eecd = E1000_READ_REG(hw, EECD); + DEBUGFUNC("em_spi_eeprom_ready"); - eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + /* Read "Status Register" repeatedly until the LSB is cleared. The + * EEPROM will signal that the command has been completed by clearing + * bit 0 of the internal status register. If it's not cleared within + * 5 milliseconds, then error out. + */ + retry_count = 0; + do { + em_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI, + hw->eeprom.opcode_bits); + spi_stat_reg = (uint8_t)em_shift_in_ee_bits(hw, 8); + if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI)) + break; - E1000_WRITE_REG(hw, EECD, eecd); + usec_delay(5); + retry_count += 5; + + } while(retry_count < EEPROM_MAX_RETRY_SPI); + + /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and + * only 0-5mSec on 5V devices) + */ + if(retry_count >= EEPROM_MAX_RETRY_SPI) { + DEBUGOUT("SPI EEPROM Status error\n"); + return -E1000_ERR_EEPROM; + } - em_clock_eeprom(hw); + return E1000_SUCCESS; } /****************************************************************************** @@ -2490,71 +3051,76 @@ em_cleanup_eeprom(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code * offset - offset of word in the EEPROM to read - * data - word read from the EEPROM + * data - word read from the EEPROM + * words - number of words to read *****************************************************************************/ int32_t em_read_eeprom(struct em_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data) { - uint32_t eecd; + struct em_eeprom_info *eeprom = &hw->eeprom; uint32_t i = 0; - boolean_t large_eeprom = FALSE; DEBUGFUNC("em_read_eeprom"); - /* Request EEPROM Access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE; - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { - i++; - usec_delay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; - } + /* A check for invalid values: offset too large, too many words, and not + * enough words. + */ + if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) || + (words == 0)) { + DEBUGOUT("\"words\" parameter out of bounds\n"); + return -E1000_ERR_EEPROM; } - /* Prepare the EEPROM for reading */ - em_setup_eeprom(hw); + /* Prepare the EEPROM for reading */ + if (em_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; - /* Send the READ command (opcode + addr) */ - em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3); - if(large_eeprom) { - /* If we have a 256 word EEPROM, there are 8 address bits */ - em_shift_out_ee_bits(hw, offset, 8); - } else { - /* If we have a 64 word EEPROM, there are 6 address bits */ - em_shift_out_ee_bits(hw, offset, 6); - } + if(eeprom->type == em_eeprom_spi) { + uint8_t read_opcode = EEPROM_READ_OPCODE_SPI; - /* Read the data */ - *data = em_shift_in_ee_bits(hw); + if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; - /* End this read operation */ - em_standby_eeprom(hw); + em_standby_eeprom(hw); - /* Stop requesting EEPROM access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); + /* Some SPI eeproms use the 8th address bit embedded in the opcode */ + if((eeprom->address_bits == 8) && (offset >= 128)) + read_opcode |= EEPROM_A8_OPCODE_SPI; + + /* 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; + } + + /* End this read operation */ + em_release_eeprom(hw); + return 0; } /****************************************************************************** * Verifies that the EEPROM has a valid checksum - * + * * hw - Struct containing variables accessed by shared code * * Reads the first 64 16 bit words of the EEPROM and sums the values read. @@ -2570,7 +3136,7 @@ em_validate_eeprom_checksum(struct em_hw *hw) DEBUGFUNC("em_validate_eeprom_checksum"); for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if(em_read_eeprom(hw, i, &eeprom_data) < 0) { + if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2580,7 +3146,7 @@ em_validate_eeprom_checksum(struct em_hw *hw) if(checksum == (uint16_t) EEPROM_SUM) { return 0; } else { - DEBUGOUT("EEPROM Checksum Invalid\n"); + DEBUGOUT("EEPROM Checksum Invalid\n"); return -E1000_ERR_EEPROM; } } @@ -2602,14 +3168,14 @@ em_update_eeprom_checksum(struct em_hw *hw) DEBUGFUNC("em_update_eeprom_checksum"); for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { - if(em_read_eeprom(hw, i, &eeprom_data) < 0) { + if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } checksum += eeprom_data; } checksum = (uint16_t) EEPROM_SUM - checksum; - if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) { + if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) { DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; } @@ -2617,118 +3183,201 @@ em_update_eeprom_checksum(struct em_hw *hw) } /****************************************************************************** - * Writes a 16 bit word to a given offset in the EEPROM. + * Parent function for writing words to the different EEPROM types. * * hw - Struct containing variables accessed by shared code * offset - offset within the EEPROM to be written to - * data - 16 bit word to be writen to the EEPROM + * words - number of words to write + * data - 16 bit word to be written to the EEPROM * - * If em_update_eeprom_checksum is not called after this function, the + * If em_update_eeprom_checksum is not called after this function, the * EEPROM will most likely contain an invalid checksum. *****************************************************************************/ int32_t em_write_eeprom(struct em_hw *hw, uint16_t offset, - uint16_t data) + uint16_t words, + uint16_t *data) { - uint32_t eecd; - uint32_t i = 0; + struct em_eeprom_info *eeprom = &hw->eeprom; int32_t status = 0; - boolean_t large_eeprom = FALSE; DEBUGFUNC("em_write_eeprom"); - /* Request EEPROM Access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE; - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { - i++; - usec_delay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; - } + /* A check for invalid values: offset too large, too many words, and not + * enough words. + */ + if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) || + (words == 0)) { + DEBUGOUT("\"words\" parameter out of bounds\n"); + return -E1000_ERR_EEPROM; } /* Prepare the EEPROM for writing */ - em_setup_eeprom(hw); + if (em_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; - /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command - * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM - * into write/erase mode. - */ - em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5); - if(large_eeprom) - em_shift_out_ee_bits(hw, 0, 6); + if(eeprom->type == em_eeprom_microwire) + status = em_write_eeprom_microwire(hw, offset, words, data); else - em_shift_out_ee_bits(hw, 0, 4); + status = em_write_eeprom_spi(hw, offset, words, data); - /* Prepare the EEPROM */ - em_standby_eeprom(hw); + /* Done with writing */ + em_release_eeprom(hw); - /* Send the Write command (3-bit opcode + addr) */ - em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3); - if(large_eeprom) - /* If we have a 256 word EEPROM, there are 8 address bits */ - em_shift_out_ee_bits(hw, offset, 8); - else - /* If we have a 64 word EEPROM, there are 6 address bits */ - em_shift_out_ee_bits(hw, offset, 6); + return status; +} + +/****************************************************************************** + * Writes a 16 bit word to a given offset in an SPI EEPROM. + * + * hw - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * words - number of words to write + * data - pointer to array of 8 bit words to be written to the EEPROM + * + *****************************************************************************/ +int32_t +em_write_eeprom_spi(struct em_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) +{ + struct em_eeprom_info *eeprom = &hw->eeprom; + uint16_t widx = 0; - /* Send the data */ - em_shift_out_ee_bits(hw, data, 16); + DEBUGFUNC("em_write_eeprom_spi"); - /* Toggle the CS line. This in effect tells to EEPROM to actually execute - * the command in question. - */ - em_standby_eeprom(hw); + while (widx < words) { + uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI; - /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will - * signal that the command has been completed by raising the DO signal. - * If DO does not go high in 10 milliseconds, then error out. - */ - for(i = 0; i < 200; i++) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_DO) break; - usec_delay(50); - } - if(i == 200) { - DEBUGOUT("EEPROM Write did not complete\n"); - status = -E1000_ERR_EEPROM; + if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; + + em_standby_eeprom(hw); + + /* Send the WRITE ENABLE command (8 bit opcode ) */ + em_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI, + eeprom->opcode_bits); + + em_standby_eeprom(hw); + + /* Some SPI eeproms use the 8th address bit embedded in the opcode */ + if((eeprom->address_bits == 8) && (offset >= 128)) + write_opcode |= EEPROM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + em_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits); + + em_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2), + eeprom->address_bits); + + /* Send the data */ + + /* Loop to allow for up to whole page write (32 bytes) of eeprom */ + while (widx < words) { + uint16_t word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); + em_shift_out_ee_bits(hw, word_out, 16); + widx++; + + /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE + * operation, while the smaller eeproms are capable of an 8-byte + * PAGE WRITE operation. Break the inner loop to pass new address + */ + if((((offset + widx)*2) % eeprom->page_size) == 0) { + em_standby_eeprom(hw); + break; + } + } } - /* Recover from write */ - em_standby_eeprom(hw); + return E1000_SUCCESS; +} - /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command - * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM - * out of write/erase mode. +/****************************************************************************** + * Writes a 16 bit word to a given offset in a Microwire EEPROM. + * + * hw - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * words - number of words to write + * data - pointer to array of 16 bit words to be written to the EEPROM + * + *****************************************************************************/ +int32_t +em_write_eeprom_microwire(struct em_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) +{ + struct em_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd; + uint16_t words_written = 0; + uint16_t i = 0; + + DEBUGFUNC("em_write_eeprom_microwire"); + + /* Send the write enable command to the EEPROM (3-bit opcode plus + * 6/8-bit dummy address beginning with 11). It's less work to include + * the 11 of the dummy address as part of the opcode than it is to shift + * it over the correct number of bits for the address. This puts the + * EEPROM into write/erase mode. */ - em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5); - if(large_eeprom) - em_shift_out_ee_bits(hw, 0, 6); - else - em_shift_out_ee_bits(hw, 0, 4); + em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE, + (uint16_t)(eeprom->opcode_bits + 2)); - /* Done with writing */ - em_cleanup_eeprom(hw); + em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2)); - /* Stop requesting EEPROM access */ - if(hw->mac_type > em_82544) { - eecd = E1000_READ_REG(hw, EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); + /* Prepare the EEPROM */ + em_standby_eeprom(hw); + + while (words_written < words) { + /* Send the Write command (3-bit opcode + addr) */ + em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE, + eeprom->opcode_bits); + + em_shift_out_ee_bits(hw, (uint16_t)(offset + words_written), + eeprom->address_bits); + + /* Send the data */ + em_shift_out_ee_bits(hw, data[words_written], 16); + + /* Toggle the CS line. This in effect tells the EEPROM to execute + * the previous command. + */ + em_standby_eeprom(hw); + + /* Read DO repeatedly until it is high (equal to '1'). The EEPROM will + * signal that the command has been completed by raising the DO signal. + * If DO does not go high in 10 milliseconds, then error out. + */ + for(i = 0; i < 200; i++) { + eecd = E1000_READ_REG(hw, EECD); + if(eecd & E1000_EECD_DO) break; + usec_delay(50); + } + if(i == 200) { + DEBUGOUT("EEPROM Write did not complete\n"); + return -E1000_ERR_EEPROM; + } + + /* Recover from write */ + em_standby_eeprom(hw); + + words_written++; } - return status; + /* Send the write disable command to the EEPROM (3-bit opcode plus + * 6/8-bit dummy address beginning with 10). It's less work to include + * the 10 of the dummy address as part of the opcode than it is to shift + * it over the correct number of bits for the address. This takes the + * EEPROM out of write/erase mode. + */ + em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE, + (uint16_t)(eeprom->opcode_bits + 2)); + + em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2)); + + return 0; } /****************************************************************************** @@ -2747,7 +3396,7 @@ em_read_part_num(struct em_hw *hw, DEBUGFUNC("em_read_part_num"); /* Get word 0 from EEPROM */ - if(em_read_eeprom(hw, offset, &eeprom_data) < 0) { + if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2755,7 +3404,7 @@ em_read_part_num(struct em_hw *hw, *part_num = (uint32_t) (eeprom_data << 16); /* Get word 1 from EEPROM */ - if(em_read_eeprom(hw, ++offset, &eeprom_data) < 0) { + if(em_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2781,7 +3430,7 @@ em_read_mac_addr(struct em_hw * hw) for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) { offset = i >> 1; - if(em_read_eeprom(hw, offset, &eeprom_data) < 0) { + if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2803,7 +3452,7 @@ em_read_mac_addr(struct em_hw * hw) /****************************************************************************** * Initializes receive address filters. * - * hw - Struct containing variables accessed by shared code + * hw - Struct containing variables accessed by shared code * * Places the MAC address in receive address register 0 and clears the rest * of the receive addresss registers. Clears the multicast table. Assumes @@ -2848,7 +3497,7 @@ em_init_rx_addrs(struct em_hw *hw) * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers - * for the first 15 multicast addresses, and hashes the rest into the + * for the first 15 multicast addresses, and hashes the rest into the * multicast table. *****************************************************************************/ void @@ -2897,7 +3546,7 @@ em_mc_addr_list_update(struct em_hw *hw, DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); /* Place this multicast address in the RAR if there is room, * - * else put it in the MTA + * else put it in the MTA */ if(rar_used_count < E1000_RAR_ENTRIES) { em_rar_set(hw, @@ -2915,7 +3564,7 @@ em_mc_addr_list_update(struct em_hw *hw, * Hashes an address to determine its location in the multicast table * * hw - Struct containing variables accessed by shared code - * mc_addr - the multicast address to hash + * mc_addr - the multicast address to hash *****************************************************************************/ uint32_t em_hash_mc_addr(struct em_hw *hw, @@ -2924,7 +3573,7 @@ em_hash_mc_addr(struct em_hw *hw, uint32_t hash_value = 0; /* The portion of the address that is used for the hash table is - * determined by the mc_filter_type setting. + * determined by the mc_filter_type setting. */ switch (hw->mc_filter_type) { /* [0] [1] [2] [3] [4] [5] @@ -2967,12 +3616,12 @@ em_mta_set(struct em_hw *hw, uint32_t mta; uint32_t temp; - /* The MTA is a register array of 128 32-bit registers. - * It is treated like an array of 4096 bits. We want to set + /* The MTA is a register array of 128 32-bit registers. + * It is treated like an array of 4096 bits. We want to set * bit BitArray[hash_value]. So we figure out what register * the bit is in, read it, OR in the new bit, then write - * back the new value. The register is determined by the - * upper 7 bits of the hash value and the bit within that + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that * register are determined by the lower 5 bits of the value. */ hash_reg = (hash_value >> 5) & 0x7F; @@ -3010,7 +3659,7 @@ em_rar_set(struct em_hw *hw, uint32_t rar_low, rar_high; /* HW expects these in little endian so we reverse the byte order - * from network order (big endian) to little endian + * from network order (big endian) to little endian */ rar_low = ((uint32_t) addr[0] | ((uint32_t) addr[1] << 8) | @@ -3068,24 +3717,24 @@ em_id_led_init(struct em_hw * hw) const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF; uint16_t eeprom_data, i, temp; const uint16_t led_mask = 0x0F; - + DEBUGFUNC("em_id_led_init"); - + if(hw->mac_type < em_82540) { /* Nothing to do */ return 0; } - + ledctl = E1000_READ_REG(hw, LEDCTL); hw->ledctl_default = ledctl; hw->ledctl_mode1 = hw->ledctl_default; hw->ledctl_mode2 = hw->ledctl_default; - - if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) { + + if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } - if((eeprom_data== ID_LED_RESERVED_0000) || + if((eeprom_data== ID_LED_RESERVED_0000) || (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT; for(i = 0; i < 4; i++) { temp = (eeprom_data >> (i << 2)) & led_mask; @@ -3136,9 +3785,9 @@ int32_t em_setup_led(struct em_hw *hw) { uint32_t ledctl; - + DEBUGFUNC("em_setup_led"); - + switch(hw->device_id) { case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: @@ -3156,7 +3805,7 @@ em_setup_led(struct em_hw *hw) hw->ledctl_default = ledctl; /* Turn off LED0 */ ledctl &= ~(E1000_LEDCTL_LED0_IVRT | - E1000_LEDCTL_LED0_BLINK | + 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); @@ -3168,6 +3817,9 @@ em_setup_led(struct em_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_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; default: @@ -3206,6 +3858,9 @@ em_cleanup_led(struct em_hw *hw) case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: /* Restore LEDCTL settings */ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default); break; @@ -3215,7 +3870,7 @@ em_cleanup_led(struct em_hw *hw) } return 0; } - + /****************************************************************************** * Turns on the software controllable LED * @@ -3257,6 +3912,9 @@ em_led_on(struct em_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2); break; default: @@ -3307,6 +3965,9 @@ em_led_off(struct em_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_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; default: @@ -3317,7 +3978,7 @@ em_led_off(struct em_hw *hw) } /****************************************************************************** - * Clears all hardware statistics counters. + * Clears all hardware statistics counters. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ @@ -3436,7 +4097,7 @@ em_update_adaptive(struct em_hw *hw) DEBUGFUNC("em_update_adaptive"); if(hw->adaptive_ifs) { - if((hw->collision_delta * hw->ifs_ratio) > + if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) { if(hw->tx_packet_delta > MIN_NUM_XMITS) { hw->in_ifs_mode = TRUE; @@ -3449,7 +4110,7 @@ em_update_adaptive(struct em_hw *hw) } } } else { - if((hw->in_ifs_mode == TRUE) && + if((hw->in_ifs_mode == TRUE) && (hw->tx_packet_delta <= MIN_NUM_XMITS)) { hw->current_ifs_val = 0; hw->in_ifs_mode = FALSE; @@ -3463,7 +4124,7 @@ em_update_adaptive(struct em_hw *hw) /****************************************************************************** * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT - * + * * hw - Struct containing variables accessed by shared code * frame_len - The length of the frame in question * mac_addr - The Ethernet destination address of the frame in question @@ -3491,16 +4152,16 @@ em_tbi_adjust_stats(struct em_hw *hw, carry_bit = 0x80000000 & stats->gorcl; stats->gorcl += frame_len; /* If the high bit of Gorcl (the low 32 bits of the Good Octets - * Received Count) was one before the addition, - * AND it is zero after, then we lost the carry out, + * Received Count) was one before the addition, + * AND it is zero after, then we lost the carry out, * need to add one to Gorch (Good Octets Received Count High). - * This could be simplified if all environments supported + * This could be simplified if all environments supported * 64-bit integers. */ if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) stats->gorch++; /* Is this a broadcast or multicast? Check broadcast first, - * since the test for a multicast frame will test positive on + * since the test for a multicast frame will test positive on * a broadcast frame. */ if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) @@ -3621,3 +4282,221 @@ em_write_reg_io(struct em_hw *hw, em_io_write(hw, io_data, value); } + +/****************************************************************************** + * Estimates the cable length. + * + * hw - Struct containing variables accessed by shared code + * min_length - The estimated minimum length + * max_length - The estimated maximum length + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * This function always returns a ranged length (minimum & maximum). + * So for M88 phy's, this function interprets the one value returned from the + * register to the minimum and maximum range. + * 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, + uint16_t *max_length) +{ + uint16_t agc_value = 0; + uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; + uint16_t i, phy_data; + + DEBUGFUNC("em_get_cable_length"); + + *min_length = *max_length = 0; + + /* 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; + + /* Convert the enum value to ranged values */ + switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT) { + case em_cable_length_50: + *min_length = 0; + *max_length = em_igp_cable_length_50; + break; + case em_cable_length_50_80: + *min_length = em_igp_cable_length_50; + *max_length = em_igp_cable_length_80; + break; + case em_cable_length_80_110: + *min_length = em_igp_cable_length_80; + *max_length = em_igp_cable_length_110; + break; + case em_cable_length_110_140: + *min_length = em_igp_cable_length_110; + *max_length = em_igp_cable_length_140; + break; + case em_cable_length_140: + *min_length = em_igp_cable_length_140; + *max_length = em_igp_cable_length_170; + break; + default: + return -E1000_ERR_PHY; + 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, + 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; + + cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; + + /* Array bound check. */ + if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || + (cur_agc == 0)) + return -E1000_ERR_PHY; + + agc_value += cur_agc; + + /* Update minimal AGC value. */ + if(min_agc > cur_agc) + 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) { + agc_value -= min_agc; + + /* Get the average length of the remaining 3 channels */ + agc_value /= (IGP01E1000_PHY_AGC_NUM - 1); + } else { + /* Get the average length of all the 4 channels. */ + agc_value /= IGP01E1000_PHY_AGC_NUM; + } + + /* Set the range of the calculated length. */ + *min_length = ((em_igp_cable_length_table[agc_value] - + IGP01E1000_AGC_RANGE) > 0) ? + (em_igp_cable_length_table[agc_value] - + IGP01E1000_AGC_RANGE) : 0; + *max_length = em_igp_cable_length_table[agc_value] + + IGP01E1000_AGC_RANGE; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** + * Check the cable polarity + * + * hw - Struct containing variables accessed by shared code + * polarity - output parameter : 0 - Polarity is not reversed + * 1 - Polarity is reversed. + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * 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 + * 10 Mbps. If the link speed is 100 Mbps there is no polarity so this bit will + * return 0. If the link speed is 1000 Mbps the polarity status is in the + * IGP01E1000_PHY_PCS_INIT_REG. + *****************************************************************************/ +int32_t +em_check_polarity(struct em_hw *hw, uint16_t *polarity) +{ + 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; + *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 speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to + * find the polarity status */ + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + 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; + + /* Check the polarity bits */ + *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0; + } else { + /* For 10 Mbps, read the polarity bit in the status register. (for + * 100 Mbps this bit is always 0) */ + *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED; + } + } + return E1000_SUCCESS; +} + +/****************************************************************************** + * Check if Downshift occured + * + * hw - Struct containing variables accessed by shared code + * downshift - output parameter : 0 - No Downshift ocured. + * 1 - Downshift ocured. + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * 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 + * Link Health register. In IGP this bit is latched high, so the driver must + * read it immediately after link is established. + *****************************************************************************/ +int32_t +em_check_downshift(struct em_hw *hw) +{ + 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; + } + 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; + } + hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> + M88E1000_PSSR_DOWNSHIFT_SHIFT; + } + return E1000_SUCCESS; +} + diff --git a/sys/dev/em/if_em_hw.h b/sys/dev/em/if_em_hw.h index 6f1874c..fe50c9a 100644 --- a/sys/dev/em/if_em_hw.h +++ b/sys/dev/em/if_em_hw.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright (c) 2001-2002, Intel Corporation + Copyright (c) 2001-2003, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -56,9 +56,17 @@ typedef enum { em_82540, em_82545, em_82546, + em_82541, + em_82547, em_num_macs } em_mac_type; +typedef enum { + em_eeprom_uninitialized = 0, + em_eeprom_spi, + em_eeprom_microwire, + em_num_eeprom_types +} em_eeprom_type; /* Media Types */ typedef enum { @@ -118,6 +126,27 @@ typedef enum { } em_cable_length; typedef enum { + em_igp_cable_length_10 = 10, + em_igp_cable_length_20 = 20, + em_igp_cable_length_30 = 30, + em_igp_cable_length_40 = 40, + em_igp_cable_length_50 = 50, + em_igp_cable_length_60 = 60, + em_igp_cable_length_70 = 70, + em_igp_cable_length_80 = 80, + em_igp_cable_length_90 = 90, + em_igp_cable_length_100 = 100, + em_igp_cable_length_110 = 110, + em_igp_cable_length_120 = 120, + em_igp_cable_length_130 = 130, + em_igp_cable_length_140 = 140, + em_igp_cable_length_150 = 150, + em_igp_cable_length_160 = 160, + em_igp_cable_length_170 = 170, + em_igp_cable_length_180 = 180 +} em_igp_cable_length; + +typedef enum { em_10bt_ext_dist_enable_normal = 0, em_10bt_ext_dist_enable_lower, em_10bt_ext_dist_enable_undefined = 0xFF @@ -129,6 +158,11 @@ typedef enum { em_rev_polarity_undefined = 0xFF } em_rev_polarity; +typedef enum { + em_downshift_normal = 0, + em_downshift_activated, + em_downshift_undefined = 0xFF +} em_downshift; typedef enum { em_polarity_reversal_enabled = 0, @@ -150,11 +184,17 @@ typedef enum { em_1000t_rx_status_undefined = 0xFF } em_1000t_rx_status; +typedef enum { + em_phy_m88 = 0, + em_phy_igp, + em_phy_undefined = 0xFF +} em_phy_type; struct em_phy_info { em_cable_length cable_length; em_10bt_ext_dist_enable extended_10bt_distance; em_rev_polarity cable_polarity; + em_downshift downshift; em_polarity_reversal polarity_correction; em_auto_x_mode mdix_mode; em_1000t_rx_status local_rx; @@ -166,6 +206,15 @@ struct em_phy_stats { uint32_t receive_errors; }; +struct em_eeprom_info { + em_eeprom_type type; + uint16_t word_size; + uint16_t opcode_bits; + uint16_t address_bits; + uint16_t delay_usec; + uint16_t page_size; +}; + /* Error Codes */ @@ -175,6 +224,7 @@ struct em_phy_stats { #define E1000_ERR_CONFIG 3 #define E1000_ERR_PARAM 4 #define E1000_ERR_MAC_TYPE 5 +#define E1000_ERR_PHY_TYPE 6 /* Function prototypes */ /* Initialization */ @@ -198,13 +248,19 @@ void em_phy_hw_reset(struct em_hw *hw); int32_t em_phy_reset(struct em_hw *hw); int32_t em_detect_gig_phy(struct em_hw *hw); int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info); +int32_t em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info); +int32_t em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info); +int32_t em_get_cable_length(struct em_hw *hw, uint16_t *min_length, uint16_t *max_length); +int32_t em_check_polarity(struct em_hw *hw, uint16_t *polarity); +int32_t em_check_downshift(struct em_hw *hw); int32_t em_validate_mdi_setting(struct em_hw *hw); /* EEPROM Functions */ -int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t *data); +void em_init_eeprom_params(struct em_hw *hw); +int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t em_validate_eeprom_checksum(struct em_hw *hw); int32_t em_update_eeprom_checksum(struct em_hw *hw); -int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t data); +int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t em_read_part_num(struct em_hw *hw, uint32_t * part_num); int32_t em_read_mac_addr(struct em_hw * hw); @@ -263,7 +319,10 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); #define E1000_DEV_ID_82545EM_FIBER 0x1011 #define E1000_DEV_ID_82546EB_COPPER 0x1010 #define E1000_DEV_ID_82546EB_FIBER 0x1012 -#define NUM_DEV_IDS 16 +#define E1000_DEV_ID_82541EI 0x1013 +#define E1000_DEV_ID_82541EP 0x1018 +#define E1000_DEV_ID_82547EI 0x1019 +#define NUM_DEV_IDS 19 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -280,7 +339,7 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); #define HALF_DUPLEX 1 #define FULL_DUPLEX 2 -/* The sizes (in bytes) of an ethernet packet */ +/* The sizes (in bytes) of a ethernet packet */ #define ENET_HEADER_SIZE 14 #define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */ #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ @@ -308,7 +367,7 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); /* This defines the bits that are set in the Interrupt Mask * Set/Read Register. Each bit is documented below: * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error + * o RXSEQ = Receive Sequence Error */ #define POLL_IMS_ENABLE_MASK ( \ E1000_IMS_RXDMT0 | \ @@ -332,9 +391,9 @@ void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); /* The 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. + * E1000_RAR_ENTRIES - 1 multicast addresses. */ -#define E1000_RAR_ENTRIES 16 +#define E1000_RAR_ENTRIES 15 #define MIN_NUMBER_OF_DESCRIPTORS 8 #define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 @@ -533,7 +592,7 @@ struct em_ffvt_entry { /* Register Set. (82543, 82544) * * Registers are defined to be 32 bits and should be accessed as 32 bit values. - * These registers are physically located on the NIC, but are mapped into the + * These registers are physically located on the NIC, but are mapped into the * host memory address space. * * RW - register is both readable and writable @@ -547,6 +606,7 @@ struct em_ffvt_entry { #define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ #define E1000_EERD 0x00014 /* EEPROM Read - RW */ #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_FLA 0x0001C /* Flash Access Register - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ @@ -579,6 +639,11 @@ struct em_ffvt_entry { #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ #define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ +#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ +#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ +#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */ +#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */ #define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ #define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ #define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ @@ -674,6 +739,7 @@ struct em_ffvt_entry { #define E1000_82542_EECD E1000_EECD #define E1000_82542_EERD E1000_EERD #define E1000_82542_CTRL_EXT E1000_CTRL_EXT +#define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH @@ -715,6 +781,9 @@ struct em_ffvt_entry { #define E1000_82542_RADV E1000_RADV #define E1000_82542_RSRPD E1000_RSRPD #define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_TDFHS E1000_TDFHS +#define E1000_82542_TDFTS E1000_TDFTS +#define E1000_82542_TDFPC E1000_TDFPC #define E1000_82542_TXDCTL E1000_TXDCTL #define E1000_82542_TADV E1000_TADV #define E1000_82542_TSPMT E1000_TSPMT @@ -787,6 +856,8 @@ struct em_ffvt_entry { #define E1000_82542_WUPL E1000_WUPL #define E1000_82542_WUPM E1000_WUPM #define E1000_82542_FFLT E1000_FFLT +#define E1000_82542_TDFH 0x08010 +#define E1000_82542_TDFT 0x08018 #define E1000_82542_FFMT E1000_FFMT #define E1000_82542_FFVT E1000_FFVT @@ -856,12 +927,15 @@ struct em_hw_stats { struct em_hw { uint8_t *hw_addr; em_mac_type mac_type; + em_phy_type phy_type; + uint32_t phy_init_script; em_media_type media_type; void *back; em_fc_type fc; em_bus_speed bus_speed; em_bus_width bus_width; em_bus_type bus_type; + struct em_eeprom_info eeprom; uint32_t io_base; uint32_t phy_id; uint32_t phy_revision; @@ -901,6 +975,7 @@ struct em_hw { uint8_t mac_addr[NODE_ADDRESS_SIZE]; uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; boolean_t disable_polarity_correction; + boolean_t speed_downgraded; boolean_t get_link_status; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; @@ -977,14 +1052,20 @@ struct em_hw { #define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ #define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ #define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ -#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_MASK 0x00000030 #define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ #define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ #define E1000_EECD_FWE_SHIFT 4 -#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ #define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ #define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ #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) */ +#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 */ +#endif /* EEPROM Read */ #define E1000_EERD_START 0x00000001 /* Start Read */ @@ -994,9 +1075,15 @@ struct em_hw { #define E1000_EERD_DATA_SHIFT 16 #define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */ +/* SPI EEPROM Status Register */ +#define EEPROM_STATUS_RDY_SPI 0x01 +#define EEPROM_STATUS_WEN_SPI 0x02 +#define EEPROM_STATUS_BP0_SPI 0x04 +#define EEPROM_STATUS_BP1_SPI 0x08 +#define EEPROM_STATUS_WPEN_SPI 0x80 /* Extended Device Control */ -#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ +#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ #define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ #define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN #define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ @@ -1250,6 +1337,7 @@ struct em_hw { #define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ #define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ #define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ +#define E1000_WUC_SPM 0x80000000 /* Enable SPM */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ @@ -1293,7 +1381,7 @@ struct em_hw { #define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ #define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ #define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ -#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery +#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery * Filtering */ #define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ #define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ @@ -1313,18 +1401,40 @@ struct em_hw { #define E1000_MDALIGN 4096 -/* EEPROM Commands */ -#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ -#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ -#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ -#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ -#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ +/* EEPROM Commands - Microwire */ +#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */ +#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */ +#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */ +#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */ +#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */ + +/* EEPROM Commands - SPI */ +#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ +#define EEPROM_READ_OPCODE_SPI 0x3 /* EEPROM read opcode */ +#define EEPROM_WRITE_OPCODE_SPI 0x2 /* EEPROM write opcode */ +#define EEPROM_A8_OPCODE_SPI 0x8 /* opcode bit-3 = address bit-8 */ +#define EEPROM_WREN_OPCODE_SPI 0x6 /* EEPROM set Write Enable latch */ +#define EEPROM_WRDI_OPCODE_SPI 0x4 /* EEPROM reset Write Enable latch */ +#define EEPROM_RDSR_OPCODE_SPI 0x5 /* EEPROM read Status register */ +#define EEPROM_WRSR_OPCODE_SPI 0x1 /* EEPROM write Status register */ + +/* EEPROM Size definitions */ +#define EEPROM_SIZE_16KB 0x1800 +#define EEPROM_SIZE_8KB 0x1400 +#define EEPROM_SIZE_4KB 0x1000 +#define EEPROM_SIZE_2KB 0x0C00 +#define EEPROM_SIZE_1KB 0x0800 +#define EEPROM_SIZE_512B 0x0400 +#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 @@ -1345,9 +1455,10 @@ struct em_hw { #define ID_LED_OFF1_ON2 0x8 #define ID_LED_OFF1_OFF2 0x9 -/* Mask bits for fields in Word 0x03 of the EEPROM */ -#define EEPROM_COMPAT_SERVER 0x0400 -#define EEPROM_COMPAT_CLIENT 0x0200 +#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF +#define IGP_ACTIVITY_LED_ENABLE 0x0300 +#define IGP_LED3_MODE 0x07000000 + /* Mask bits for fields in Word 0x0a of the EEPROM */ #define EEPROM_WORD0A_ILOS 0x0010 @@ -1420,7 +1531,9 @@ struct em_hw { /* PBA constants */ #define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 +#define E1000_PBA_30K 0x001E #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ @@ -1449,26 +1562,26 @@ struct em_hw { /* 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 + * 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 + * 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 + * in the 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 + * in the CTRL register */ #define ILOS_SHIFT 3 @@ -1486,7 +1599,7 @@ struct em_hw { /* TBI_ACCEPT macro definition: * * This macro requires: - * adapter = a pointer to struct em_hw + * adapter = a pointer to struct em_hw * status = the 8 bit status field of the RX descriptor with EOP set * error = the 8 bit error field of the RX descriptor with EOP set * length = the sum of all the length fields of the RX descriptors that @@ -1495,7 +1608,7 @@ struct em_hw { * max_frame_length = the maximum frame length we want to accept. * min_frame_length = the minimum frame length we want to accept. * - * This macro is a conditional that should be used in the interrupt + * This macro is a conditional that should be used in the interrupt * handler's Rx processing routine when RxErrors have been detected. * * Typical use: @@ -1558,6 +1671,28 @@ struct em_hw { #define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ #define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ +/* IGP01E1000 Specific Registers */ +#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */ +#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */ +#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */ +#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */ +#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */ +#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */ +#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */ + +/* IGP01E1000 AGC Registers - stores the cable length values*/ +#define IGP01E1000_PHY_AGC_A 0x1172 +#define IGP01E1000_PHY_AGC_B 0x1272 +#define IGP01E1000_PHY_AGC_C 0x1472 +#define IGP01E1000_PHY_AGC_D 0x1872 + +/* Number of AGC registers */ +#define IGP01E1000_PHY_AGC_NUM 4 + +/* IGP01E1000 PCS Initialization register - stores the polarity status when + * speed = 1000 Mbps. */ +#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 + #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ @@ -1620,7 +1755,7 @@ struct em_hw { #define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ #define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ #define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ -#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ /* Next Page TX Register */ #define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ @@ -1631,7 +1766,7 @@ struct em_hw { * 0 = cannot comply with msg */ #define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ -#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow +#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow * 0 = sending last NP */ @@ -1640,13 +1775,13 @@ struct em_hw { #define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges * of different NP */ -#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg +#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg * 0 = cannot comply with msg */ #define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ #define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ #define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow - * 0 = sending last NP + * 0 = sending last NP */ /* 1000BASE-T Control Register */ @@ -1693,20 +1828,20 @@ struct em_hw { #define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ #define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ #define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ -#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, +#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, * 0=CLK125 toggling */ #define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ /* Manual MDI configuration */ #define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ #define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, - * 100BASE-TX/10BASE-T: + * 100BASE-TX/10BASE-T: * MDI Mode */ -#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled - * all speeds. +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. */ -#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance * (Lower 10BASE-T RX Threshold) * 0=Normal 10BASE-T RX Threshold */ @@ -1724,6 +1859,7 @@ struct em_hw { /* M88E1000 PHY Specific Status Register */ #define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ #define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ #define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ #define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; * 3=110-140M;4=>140M */ @@ -1737,6 +1873,7 @@ struct em_hw { #define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ #define M88E1000_PSSR_REV_POLARITY_SHIFT 1 +#define M88E1000_PSSR_DOWNSHIFT_SHIFT 5 #define M88E1000_PSSR_MDIX_SHIFT 6 #define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 @@ -1745,12 +1882,12 @@ struct em_hw { #define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled. * Will assert lost lock and bring * link down if idle not seen - * within 1ms in 1000BASE-T + * within 1ms in 1000BASE-T */ /* Number of times we will attempt to autonegotiate before downshifting if we * are the master */ #define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00 @@ -1766,10 +1903,92 @@ struct em_hw { #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 +#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 +#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK 0x0100 +#define IGP01E1000_PSCFR_DISABLE_JABBER 0x0400 +#define IGP01E1000_PSCFR_DISABLE_TRANSMIT 0x2000 + +/* IGP01E1000 Specific Port Status Register - R/O */ +#define IGP01E1000_PSSR_AUTONEG_FAILED 0x0001 /* RO LH SC */ +#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 +#define IGP01E1000_PSSR_CABLE_LENGTH 0x007C +#define IGP01E1000_PSSR_FULL_DUPLEX 0x0200 +#define IGP01E1000_PSSR_LINK_UP 0x0400 +#define IGP01E1000_PSSR_MDIX 0x0800 +#define IGP01E1000_PSSR_SPEED_MASK 0xC000 /* speed bits mask */ +#define IGP01E1000_PSSR_SPEED_10MBPS 0x4000 +#define IGP01E1000_PSSR_SPEED_100MBPS 0x8000 +#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 +#define IGP01E1000_PSSR_CABLE_LENGTH_SHIFT 0x0002 /* shift right 2 */ +#define IGP01E1000_PSSR_MDIX_SHIFT 0x000B /* shift right 11 */ + +/* IGP01E1000 Specific Port Control Register - R/W */ +#define IGP01E1000_PSCR_TP_LOOPBACK 0x0001 +#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR 0x0200 +#define IGP01E1000_PSCR_TEN_CRS_SELECT 0x0400 +#define IGP01E1000_PSCR_FLIP_CHIP 0x0800 +#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 +#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0-MDI, 1-MDIX */ + +/* IGP01E1000 Specific Port Link Health Register */ +#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 +#define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR 0x4000 +#define IGP01E1000_PLHR_GIG_REM_RCVR_NOK 0x0800 /* LH */ +#define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW 0x0400 /* LH */ +#define IGP01E1000_PLHR_DATA_ERR_1 0x0200 /* LH */ +#define IGP01E1000_PLHR_DATA_ERR_0 0x0100 +#define IGP01E1000_PLHR_AUTONEG_FAULT 0x0010 +#define IGP01E1000_PLHR_AUTONEG_ACTIVE 0x0008 +#define IGP01E1000_PLHR_VALID_CHANNEL_D 0x0004 +#define IGP01E1000_PLHR_VALID_CHANNEL_C 0x0002 +#define IGP01E1000_PLHR_VALID_CHANNEL_B 0x0001 +#define IGP01E1000_PLHR_VALID_CHANNEL_A 0x0000 + +/* IGP01E1000 Channel Quality Register */ +#define IGP01E1000_MSE_CHANNEL_D 0x000F +#define IGP01E1000_MSE_CHANNEL_C 0x00F0 +#define IGP01E1000_MSE_CHANNEL_B 0x0F00 +#define IGP01E1000_MSE_CHANNEL_A 0xF000 + +/* IGP01E1000 AGC Registers */ + +#define IGP01E1000_AGC_LENGTH_SHIFT 7 /* Coarse - 13:11, Fine - 10:7 */ + +/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */ +#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128 + +/* 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 + +/* IGP01E1000 GMII FIFO Register */ +#define IGP01E1000_GMII_FLEX_SPD 0x10 /* Enable flexible speed + * on Link-Up */ +#define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */ + /* Bit definitions for valid PHY IDs. */ #define M88E1000_E_PHY_ID 0x01410C50 #define M88E1000_I_PHY_ID 0x01410C30 #define M88E1011_I_PHY_ID 0x01410C20 +#define IGP01E1000_I_PHY_ID 0x02A80380 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID #define M88E1011_I_REV_4 0x04 diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h index 2a50b5a..f18f446 100644 --- a/sys/dev/em/if_em_osdep.h +++ b/sys/dev/em/if_em_osdep.h @@ -1,6 +1,6 @@ /************************************************************************** -Copyright (c) 2001-2002, Intel Corporation +Copyright (c) 2001-2003, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -92,24 +92,15 @@ struct em_osdep #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) #define E1000_READ_REG(a, reg) (\ - ((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): \ - 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)) - + ((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg)) #define E1000_WRITE_REG(a, reg, 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, 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, value)) - + ((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg, \ + value)) #define E1000_READ_REG_ARRAY(a, reg, offset) (\ ((a)->mac_type >= em_82543) ? \ |