diff options
| author | John Baldwin <jhb@FreeBSD.org> | 2006-09-05 19:48:10 +0000 |
|---|---|---|
| committer | John Baldwin <jhb@FreeBSD.org> | 2006-09-05 19:48:10 +0000 |
| commit | 3289b92eeace0877fe47333900f09fe1280c1051 (patch) | |
| tree | 466af510c1f7e5cdd04b6a2f2bc95313007b5c49 /sys/dev | |
| parent | 610cad552e3ad043134ab281f1bd62e1cd0b095d (diff) | |
Notes
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/em/LICENSE | 4 | ||||
| -rw-r--r-- | sys/dev/em/README | 88 | ||||
| -rw-r--r-- | sys/dev/em/if_em.c | 3297 | ||||
| -rw-r--r-- | sys/dev/em/if_em.h | 344 | ||||
| -rw-r--r-- | sys/dev/em/if_em_hw.c | 3922 | ||||
| -rw-r--r-- | sys/dev/em/if_em_hw.h | 863 | ||||
| -rw-r--r-- | sys/dev/em/if_em_osdep.h | 95 |
7 files changed, 6134 insertions, 2479 deletions
diff --git a/sys/dev/em/LICENSE b/sys/dev/em/LICENSE index de8145e47a90..99b29da567da 100644 --- a/sys/dev/em/LICENSE +++ b/sys/dev/em/LICENSE @@ -1,5 +1,6 @@ $FreeBSD$ -Copyright (c) 2001-2003, Intel Corporation +/*- +Copyright (c) 2001-2005, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -27,3 +28,4 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/sys/dev/em/README b/sys/dev/em/README index 059f2bc8f29e..46c3cba632bb 100644 --- a/sys/dev/em/README +++ b/sys/dev/em/README @@ -2,7 +2,7 @@ $FreeBSD$ FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters ============================================================ -March 18, 2005 +May 2, 2006 Contents @@ -21,8 +21,8 @@ Contents Overview ======== -This file describes the FreeBSD* driver, version 2.1.x, for the Intel(R) -PRO/1000 Family of Adapters. +This file describes the FreeBSD* driver for the Intel(R) PRO/1000 Family of +Adapters. This driver has been developed for use with FreeBSD, Release 6.x. For questions related to hardware requirements, refer to the documentation supplied with your Intel PRO/1000 adapter. All hardware requirements listed @@ -35,16 +35,17 @@ Identifying Your Adapter For information on how to identify your adapter, go to the Adapter & Driver ID Guide at: -http://support.intel.com/support/network/adapter/pro100/21397.htm +http://support.intel.com/support/network/sb/cs-012904.htm For the latest Intel network drivers for FreeBSD, see: -http://appsr.intel.com/scripts-df/support_intel.asp +http://downloadfinder.intel.com/scripts-df-external/support_intel.aspx NOTE: Mobile adapters are not fully supported. - +NOTE: The Intel(R) 82562v 10/100 Network Connection only provides 10/100 +support. Building and Installation ========================= @@ -91,14 +92,14 @@ name of the driver tar file. cp Makefile.kernel /usr/src/sys/modules/em/Makefile - Edit the /usr/src/sys/conf/files.i386 file, and add the following lines only if + Edit the /usr/src/sys/conf/files file, and add the following lines only if they don't already exist: dev/em/if_em.c optional em dev/em/if_em_hw.c optional em - Remove the following lines from the /usr/src/sys/conf/files.i386 file, + Remove the following lines from the /usr/src/sys/conf/files file, if they exist: dev/em/if_em_fxhw.c optional em @@ -173,32 +174,69 @@ 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 +all but the 82542-based adapters. For specific adapters, refer to the Identifying Your Adapter section. Jumbo Frames ------------ - To enable Jumbo Frames, use the ifconfig utility to increase the MTU - beyond 1500 bytes. + To enable Jumbo Frames, use the ifconfig utility to set the Maximum + Transport Unit (MTU) frame size above its default of 1500 bytes. - NOTES: Only enable Jumbo Frames if your network infrastructure supports - them. + The Jumbo Frames MTU range for Intel Adapters is 1500 to 16110. To modify + the setting, enter the following: - The Jumbo Frames setting on the switch must be set to at least - 22 bytes larger than that of the MTU. + ifconfig em<interface_num> <hostname or IP address> mtu 9000 - The Intel PRO/1000 PM Network Connection does not support jumbo - frames. + To confirm the MTU used between two specific devices, use: + route get <destination_IP_address> - 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: + Notes: - ifconfig em<interface_num> <hostname or IP address> mtu 9000 + - Only enable Jumbo Frames if your network infrastructure supports them. - To confirm the MTU used between two specific devices, use: + - To enable Jumbo Frames, increase the MTU size on the interface beyond + 1500. + + - The Jumbo Frames setting on the switch must be set to at least 22 bytes + larger than that of the MTU. + + - The maximum MTU setting for Jumbo Frames is 16110. This value coincides + with the maximum Jumbo Frames size of 16128. + + - Some Intel gigabit adapters that support Jumbo Frames have a frame size + limit of 9238 bytes, with a corresponding MTU size limit of 9216 bytes. + The adapters with this limitation are based on the Intel(R) 82571EB, + 82572EI, 82573L and 80003ES2LAN controller. These correspond to the + following product names: + Intel(R) PRO/1000 PT Server Adapter + Intel(R) PRO/1000 PT Desktop Adapter + Intel(R) PRO/1000 PT Network Connection + Intel(R) PRO/1000 PT Dual Port Server Adapter + Intel(R) PRO/1000 PT Dual Port Network Connection + Intel(R) PRO/1000 PF Server Adapter + Intel(R) PRO/1000 PF Network Connection + Intel(R) PRO/1000 PF Dual Port Server Adapter + Intel(R) PRO/1000 PB Server Connection + Intel(R) PRO/1000 PL Network Connection + Intel(R) PRO/1000 EB Network Connection with I/O Acceleration + Intel(R) PRO/1000 EB Backplane Connection with I/O Acceleration + + - Adapters based on the Intel(R) 82542 and 82573V/E controller do not + support Jumbo Frames. These correspond to the following product names: + Intel(R) PRO/1000 Gigabit Server Adapter + Intel(R) PRO/1000 PM Network Connection + + - Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or + loss of link. + + - The following adapters do not support Jumbo Frames: + Intel(R) 82562V 10/100 Network Connection + Intel(R) 82566DM Gigabit Network Connection + Intel(R) 82566DC Gigabit Network Connection + Intel(R) 82566MM Gigabit Network Connection + Intel(R) 82566MC Gigabit Network Connection - route get <destination_IP_address> VLANs ----- @@ -223,6 +261,7 @@ Identifying Your Adapter section. ifconfig <vlan_name> destroy + Polling ------- NOTES: DEVICE POLLING is only valid for non-SMP kernels. @@ -239,7 +278,8 @@ Identifying Your Adapter section. At runtime use: sysctl kern.polling.enable=1 to turn polling on Use: - sysctl ker.polling.enable=0 to turn polling off + sysctl kern.polling.enable=0 to turn polling off + Checksum Offload ---------------- @@ -270,6 +310,7 @@ Identifying Your Adapter section. See the ifconfig man page for further information. + Known Limitations ================= @@ -317,6 +358,7 @@ For general information and support, go to the Intel support website at: If an issue is identified, support is through email only at: freebsdnic@mailbox.intel.com + License ======= diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index 046b055e2282..e66a3baa04cd 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -1,6 +1,6 @@ /************************************************************************** -Copyright (c) 2001-2003, Intel Corporation +Copyright (c) 2001-2006, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -33,25 +33,53 @@ POSSIBILITY OF SUCH DAMAGE. /*$FreeBSD$*/ -#include <dev/em/if_em.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> -/********************************************************************* - * Set this to one to display debug statistics - *********************************************************************/ -int em_display_debug_stats = 0; +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> -/********************************************************************* - * Linked list of board private structures for all NICs found - *********************************************************************/ +#include <net/bpf.h> +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_media.h> -struct adapter *em_adapter_list = NULL; +#include <net/if_types.h> +#include <net/if_vlan_var.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> + +#include <pci/pcivar.h> +#include <pci/pcireg.h> +#include <dev/em/if_em_hw.h> +#include <dev/em/if_em.h> + +/********************************************************************* + * Set this to one to display debug statistics + *********************************************************************/ +int em_display_debug_stats = 0; /********************************************************************* * Driver version *********************************************************************/ -char em_driver_version[] = "2.1.7"; +char em_driver_version[] = "Version - 6.1.4"; /********************************************************************* @@ -66,55 +94,80 @@ char em_driver_version[] = "2.1.7"; static em_vendor_info_t em_vendor_info_array[] = { - /* Intel(R) PRO/1000 Network Connection */ - { 0x8086, E1000_DEV_ID_82540EM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EM_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EP, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EP_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82540EP_LP, PCI_ANY_ID, PCI_ANY_ID, 0}, + /* Intel(R) PRO/1000 Network Connection */ + { 0x8086, E1000_DEV_ID_82540EM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EM_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EP, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EP_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82540EP_LP, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82541EI, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541ER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541ER_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541GI, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541GI_LF, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82541GI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, + + { 0x8086, E1000_DEV_ID_82542, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541EI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541ER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541GI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541GI_LF, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82541GI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82543GC_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82543GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82542, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82544EI_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82544EI_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82544GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82544GC_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82543GC_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82543GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545EM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545EM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545GM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545GM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82545GM_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82544EI_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82544EI_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82544GC_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82544GC_LOM, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546EB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_PCIE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3, + PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545EM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545EM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545GM_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545GM_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82545GM_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82547EI, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82547EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82547GI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546EB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_PCIE, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82546GB_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82571EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82571EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82571EB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82571EB_QUAD_COPPER, + PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82547EI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82547EI_MOBILE, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82547GI, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82572EI_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82572EI_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82572EI_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82572EI, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82573E, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, E1000_DEV_ID_82573E_IAMT, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82573E, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82573E_IAMT, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82573L, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_80003ES2LAN_COPPER_SPT, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_80003ES2LAN_SERDES_SPT, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_80003ES2LAN_COPPER_DPT, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_80003ES2LAN_SERDES_DPT, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IGP_AMT, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IGP_C, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IFE, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0}, - /* required last entry */ - { 0, 0, 0, 0, 0} + /* required last entry */ + { 0, 0, 0, 0, 0} }; /********************************************************************* @@ -126,74 +179,80 @@ static char *em_strings[] = { }; /********************************************************************* - * Function prototypes + * Function prototypes *********************************************************************/ -static int em_probe(device_t); -static int em_attach(device_t); -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 *, u_long, caddr_t); -static void em_watchdog(struct ifnet *); -static void em_init(void *); -static void em_stop(void *); -static void em_media_status(struct ifnet *, struct ifmediareq *); -static int em_media_change(struct ifnet *); -static void em_identify_hardware(struct adapter *); -static int em_allocate_pci_resources(struct adapter *); -static void em_free_pci_resources(struct adapter *); -static void em_local_timer(void *); -static int em_hardware_init(struct adapter *); -static void em_setup_interface(device_t, struct adapter *); -static int em_setup_transmit_structures(struct adapter *); -static void em_initialize_transmit_unit(struct adapter *); -static int em_setup_receive_structures(struct adapter *); -static void em_initialize_receive_unit(struct adapter *); -static void em_enable_intr(struct adapter *); -static void em_disable_intr(struct adapter *); -static void em_free_transmit_structures(struct adapter *); -static void em_free_receive_structures(struct adapter *); -static void em_update_stats_counters(struct adapter *); -static void em_clean_transmit_interrupts(struct adapter *); -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 *, - struct mbuf *); -static void em_transmit_checksum_setup(struct adapter *, - struct mbuf *, - u_int32_t *, - u_int32_t *); -static void em_set_promisc(struct adapter *); -static void em_disable_promisc(struct adapter *); -static void em_set_multi(struct adapter *); -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 *); -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); -static void em_print_debug_info(struct adapter *); -static int em_is_valid_ether_addr(u_int8_t *); -static int em_sysctl_stats(SYSCTL_HANDLER_ARGS); -static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); -static u_int32_t em_fill_descriptors (u_int64_t address, - u_int32_t length, - PDESC_ARRAY desc_array); -static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); -static void em_add_int_delay_sysctl(struct adapter *, const char *, - const char *, struct em_int_delay_info *, - int, int); +static int em_probe(device_t); +static int em_attach(device_t); +static int em_detach(device_t); +static int em_shutdown(device_t); +static int em_suspend(device_t); +static int em_resume(device_t); +static void em_start(struct ifnet *); +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 *); +static void em_media_status(struct ifnet *, struct ifmediareq *); +static int em_media_change(struct ifnet *); +static void em_identify_hardware(struct adapter *); +static int em_allocate_pci_resources(struct adapter *); +static int em_allocate_intr(struct adapter *); +static void em_free_intr(struct adapter *); +static void em_free_pci_resources(struct adapter *); +static void em_local_timer(void *); +static int em_hardware_init(struct adapter *); +static void em_setup_interface(device_t, struct adapter *); +static int em_setup_transmit_structures(struct adapter *); +static void em_initialize_transmit_unit(struct adapter *); +static int em_setup_receive_structures(struct adapter *); +static void em_initialize_receive_unit(struct adapter *); +static void em_enable_intr(struct adapter *); +static void em_disable_intr(struct adapter *); +static void em_free_transmit_structures(struct adapter *); +static void em_free_receive_structures(struct adapter *); +static void em_update_stats_counters(struct adapter *); +static void em_txeof(struct adapter *); +static int em_allocate_receive_structures(struct adapter *); +static int em_allocate_transmit_structures(struct adapter *); +static void em_rxeof(struct adapter *, int); +static void em_receive_checksum(struct adapter *, struct em_rx_desc *, + struct mbuf *); +static void em_transmit_checksum_setup(struct adapter *, struct mbuf *, + uint32_t *, uint32_t *); +static void em_set_promisc(struct adapter *); +static void em_disable_promisc(struct adapter *); +static void em_set_multi(struct adapter *); +static void em_print_hw_stats(struct adapter *); +static void em_update_link_status(struct adapter *); +static int em_get_buf(struct adapter *, int); +static void em_enable_vlans(struct adapter *); +static void em_disable_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); +static int em_dma_malloc(struct adapter *, bus_size_t, + struct em_dma_alloc *, int); +static void em_dma_free(struct adapter *, struct em_dma_alloc *); +static void em_print_debug_info(struct adapter *); +static int em_is_valid_ether_addr(uint8_t *); +static int em_sysctl_stats(SYSCTL_HANDLER_ARGS); +static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); +static uint32_t em_fill_descriptors (bus_addr_t address, uint32_t length, + PDESC_ARRAY desc_array); +static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); +static void em_add_int_delay_sysctl(struct adapter *, const char *, + const char *, struct em_int_delay_info *, int, int); + +#ifdef DEVICE_POLLING +static poll_handler_t em_poll; +#endif +static void em_intr(void *); /********************************************************************* - * FreeBSD Device Interface Entry Points + * FreeBSD Device Interface Entry Points *********************************************************************/ static device_method_t em_methods[] = { @@ -202,11 +261,13 @@ static device_method_t em_methods[] = { DEVMETHOD(device_attach, em_attach), DEVMETHOD(device_detach, em_detach), DEVMETHOD(device_shutdown, em_shutdown), + DEVMETHOD(device_suspend, em_suspend), + DEVMETHOD(device_resume, em_resume), {0, 0} }; static driver_t em_driver = { - "em", em_methods, sizeof(struct adapter ), + "em", em_methods, sizeof(struct adapter), }; static devclass_t em_devclass; @@ -216,31 +277,25 @@ DRIVER_MODULE(if_em, pci, em_driver, em_devclass, 0, 0); * Tunable default values. *********************************************************************/ -#define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) -#define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) +#define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) +#define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) static int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV); static int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR); static int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV); static int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV); +static int em_rxd = EM_DEFAULT_RXD; +static int em_txd = EM_DEFAULT_TXD; +static int em_smart_pwr_down = FALSE; TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt); TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt); TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt); +TUNABLE_INT("hw.em.rxd", &em_rxd); +TUNABLE_INT("hw.em.txd", &em_txd); +TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down); -/* sysctl vars */ -/* -SYSCTL_INT(_hw, OID_AUTO, em_tx_int_delay, CTLFLAG_RD, &em_tx_int_delay_dflt, 0, - "Transmit interrupt delay"); -SYSCTL_INT(_hw, OID_AUTO, em_rx_int_delay, CTLFLAG_RD, &em_rx_int_delay_dflt, 0, - "Receive interrupt delay"); -SYSCTL_INT(_hw, OID_AUTO, em_tx_abs_int_delay, CTLFLAG_RD, &em_tx_abs_int_delay_dflt, - 0, "Transmit absolute interrupt delay"); -SYSCTL_INT(_hw, OID_AUTO, em_rx_ans_int_delay, CTLFLAG_RD, &em_rx_abs_int_delay_dflt, - 0, - "Receive absolute interrupt delay"); -*/ /********************************************************************* * Device identification routine * @@ -253,19 +308,18 @@ SYSCTL_INT(_hw, OID_AUTO, em_rx_ans_int_delay, CTLFLAG_RD, &em_rx_abs_int_delay_ static int em_probe(device_t dev) { + char adapter_name[60]; + uint16_t pci_vendor_id = 0; + uint16_t pci_device_id = 0; + uint16_t pci_subvendor_id = 0; + uint16_t pci_subdevice_id = 0; em_vendor_info_t *ent; - u_int16_t pci_vendor_id = 0; - u_int16_t pci_device_id = 0; - u_int16_t pci_subvendor_id = 0; - u_int16_t pci_subdevice_id = 0; - char adapter_name[60]; - INIT_DEBUGOUT("em_probe: begin"); pci_vendor_id = pci_get_vendor(dev); if (pci_vendor_id != EM_VENDOR_ID) - return(ENXIO); + return (ENXIO); pci_device_id = pci_get_device(dev); pci_subvendor_id = pci_get_subvendor(dev); @@ -277,130 +331,122 @@ em_probe(device_t dev) (pci_device_id == ent->device_id) && ((pci_subvendor_id == ent->subvendor_id) || - (ent->subvendor_id == PCI_ANY_ID)) && + (ent->subvendor_id == PCI_ANY_ID)) && ((pci_subdevice_id == ent->subdevice_id) || - (ent->subdevice_id == PCI_ANY_ID))) { - sprintf(adapter_name, "%s, Version - %s", - em_strings[ent->index], + (ent->subdevice_id == PCI_ANY_ID))) { + sprintf(adapter_name, "%s %s", + em_strings[ent->index], em_driver_version); device_set_desc_copy(dev, adapter_name); - return(0); + return (0); } ent++; } - return(ENXIO); + return (ENXIO); } /********************************************************************* * Device initialization routine * * The attach entry point is called when the driver is being loaded. - * This routine identifies the type of hardware, allocates all resources - * and initializes the hardware. - * + * This routine identifies the type of hardware, allocates all resources + * and initializes the hardware. + * * return 0 on success, positive on failure *********************************************************************/ static int em_attach(device_t dev) { - struct adapter * adapter; - int s; - int tsize, rsize; - int error = 0; + struct adapter *adapter; + int tsize, rsize; + int error = 0; + int s; INIT_DEBUGOUT("em_attach: begin"); s = splimp(); - /* Allocate, clear, and link in our adapter structure */ - if (!(adapter = device_get_softc(dev))) { - printf("em: adapter structure allocation failed\n"); - splx(s); - return(ENOMEM); - } - bzero(adapter, sizeof(struct adapter )); - adapter->dev = dev; - adapter->osdep.dev = dev; - adapter->unit = device_get_unit(dev); - - if (em_adapter_list != NULL) - em_adapter_list->prev = adapter; - adapter->next = em_adapter_list; - em_adapter_list = adapter; + adapter = device_get_softc(dev); + adapter->dev = adapter->osdep.dev = dev; /* SYSCTL stuff */ - sysctl_ctx_init(&adapter->sysctl_ctx); - adapter->sysctl_tree = SYSCTL_ADD_NODE(&adapter->sysctl_ctx, - SYSCTL_STATIC_CHILDREN(_hw), - OID_AUTO, - device_get_nameunit(dev), - CTLFLAG_RD, - 0, ""); - if (adapter->sysctl_tree == NULL) { + sysctl_ctx_init(&adapter->sysctl_ctx); + adapter->sysctl_tree = SYSCTL_ADD_NODE(&adapter->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, device_get_nameunit(dev), + CTLFLAG_RD, 0, ""); + if (adapter->sysctl_tree == NULL) { error = EIO; goto err_sysctl; - } - - SYSCTL_ADD_PROC(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW, - (void *)adapter, 0, - em_sysctl_debug_info, "I", "Debug Information"); + } - SYSCTL_ADD_PROC(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, - (void *)adapter, 0, - em_sysctl_stats, "I", "Statistics"); + SYSCTL_ADD_PROC(&adapter->sysctl_ctx, + SYSCTL_CHILDREN(adapter->sysctl_tree), + OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, + em_sysctl_debug_info, "I", "Debug Information"); - callout_handle_init(&adapter->timer_handle); - callout_handle_init(&adapter->tx_fifo_timer_handle); + SYSCTL_ADD_PROC(&adapter->sysctl_ctx, + SYSCTL_CHILDREN(adapter->sysctl_tree), + OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, + em_sysctl_stats, "I", "Statistics"); + + callout_init(&adapter->timer); + callout_init(&adapter->tx_fifo_timer); /* Determine hardware revision */ em_identify_hardware(adapter); - + /* Set up some sysctls for the tunable interrupt delays */ - em_add_int_delay_sysctl(adapter, "rx_int_delay", - "receive interrupt delay in usecs", &adapter->rx_int_delay, - E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt); - em_add_int_delay_sysctl(adapter, "tx_int_delay", - "transmit interrupt delay in usecs", &adapter->tx_int_delay, - E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt); - if (adapter->hw.mac_type >= em_82540) { - em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", - "receive interrupt delay limit in usecs", - &adapter->rx_abs_int_delay, - E1000_REG_OFFSET(&adapter->hw, RADV), - em_rx_abs_int_delay_dflt); - em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", - "transmit interrupt delay limit in usecs", - &adapter->tx_abs_int_delay, - E1000_REG_OFFSET(&adapter->hw, TADV), - em_tx_abs_int_delay_dflt); - } + em_add_int_delay_sysctl(adapter, "rx_int_delay", + "receive interrupt delay in usecs", &adapter->rx_int_delay, + E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_int_delay", + "transmit interrupt delay in usecs", &adapter->tx_int_delay, + E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt); + if (adapter->hw.mac_type >= em_82540) { + em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", + "receive interrupt delay limit in usecs", + &adapter->rx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, RADV), + em_rx_abs_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", + "transmit interrupt delay limit in usecs", + &adapter->tx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, TADV), + em_tx_abs_int_delay_dflt); + } - /* Parameters (to be read from user) */ - adapter->num_tx_desc = EM_MAX_TXD; - adapter->num_rx_desc = EM_MAX_RXD; - adapter->hw.autoneg = DO_AUTO_NEG; - adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; - adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; - 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. + /* + * Validate number of transmit and receive descriptors. It + * must not exceed hardware maximum, and must be multiple + * of EM_DBA_ALIGN. */ - 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; - + if (((em_txd * sizeof(struct em_tx_desc)) % EM_DBA_ALIGN) != 0 || + (adapter->hw.mac_type >= em_82544 && em_txd > EM_MAX_TXD) || + (adapter->hw.mac_type < em_82544 && em_txd > EM_MAX_TXD_82543) || + (em_txd < EM_MIN_TXD)) { + device_printf(dev, "Using %d TX descriptors instead of %d!\n", + EM_DEFAULT_TXD, em_txd); + adapter->num_tx_desc = EM_DEFAULT_TXD; + } else + adapter->num_tx_desc = em_txd; + if (((em_rxd * sizeof(struct em_rx_desc)) % EM_DBA_ALIGN) != 0 || + (adapter->hw.mac_type >= em_82544 && em_rxd > EM_MAX_RXD) || + (adapter->hw.mac_type < em_82544 && em_rxd > EM_MAX_RXD_82543) || + (em_rxd < EM_MIN_RXD)) { + device_printf(dev, "Using %d RX descriptors instead of %d!\n", + EM_DEFAULT_RXD, em_rxd); + adapter->num_rx_desc = EM_DEFAULT_RXD; + } else + adapter->num_rx_desc = em_rxd; + + adapter->hw.autoneg = DO_AUTO_NEG; + adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; + adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; + adapter->hw.tbi_compatibility_en = TRUE; + adapter->rx_buffer_len = EM_RXBUFFER_2048; + adapter->hw.phy_init_script = 1; adapter->hw.phy_reset_disable = FALSE; @@ -409,131 +455,114 @@ em_attach(device_t dev) #else adapter->hw.master_slave = EM_MASTER_SLAVE; #endif + /* + * Set the max frame size assuming standard ethernet + * sized frames. + */ + adapter->hw.max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; - /* - * 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; + adapter->hw.min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; - /* - * This controls when hardware reports transmit completion - * status. + /* + * 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", - adapter->unit); + device_printf(dev, "Allocation of PCI resources failed\n"); error = ENXIO; goto err_pci; } - - em_init_eeprom_params(&adapter->hw); + + /* Initialize eeprom parameters */ + em_init_eeprom_params(&adapter->hw); - tsize = EM_ROUNDUP(adapter->num_tx_desc * - sizeof(struct em_tx_desc), 4096); + tsize = roundup2(adapter->num_tx_desc * sizeof(struct em_tx_desc), + EM_DBA_ALIGN); /* Allocate Transmit Descriptor ring */ - if (!(adapter->tx_desc_base = (struct em_tx_desc *) - contigmalloc(tsize, M_DEVBUF, M_NOWAIT, 0, ~0, - PAGE_SIZE, 0))) { - printf("em%d: Unable to allocate TxDescriptor memory\n", - adapter->unit); + if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) { + device_printf(dev, "Unable to allocate tx_desc memory\n"); error = ENOMEM; goto err_tx_desc; } + adapter->tx_desc_base = (struct em_tx_desc *)adapter->txdma.dma_vaddr; - rsize = EM_ROUNDUP(adapter->num_rx_desc * - sizeof(struct em_rx_desc), 4096); + rsize = roundup2(adapter->num_rx_desc * sizeof(struct em_rx_desc), + EM_DBA_ALIGN); /* Allocate Receive Descriptor ring */ - if (!(adapter->rx_desc_base = (struct em_rx_desc *) - contigmalloc(rsize, M_DEVBUF, M_NOWAIT, 0, ~0, - PAGE_SIZE, 0))) { - printf("em%d: Unable to allocate rx_desc memory\n", - adapter->unit); + if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) { + device_printf(dev, "Unable to allocate rx_desc memory\n"); error = ENOMEM; goto err_rx_desc; } + adapter->rx_desc_base = (struct em_rx_desc *)adapter->rxdma.dma_vaddr; /* Initialize the hardware */ if (em_hardware_init(adapter)) { - printf("em%d: Unable to initialize the hardware\n", - adapter->unit); + device_printf(dev, "Unable to initialize the hardware\n"); error = EIO; goto err_hw_init; } /* Copy the permanent MAC address out of the EEPROM */ if (em_read_mac_addr(&adapter->hw) < 0) { - printf("em%d: EEPROM read error while reading mac address\n", - adapter->unit); + device_printf(dev, "EEPROM read error while reading MAC" + " address\n"); error = EIO; - goto err_mac_addr; + goto err_hw_init; } if (!em_is_valid_ether_addr(adapter->hw.mac_addr)) { - printf("em%d: Invalid mac address\n", adapter->unit); + device_printf(dev, "Invalid MAC address\n"); error = EIO; - goto err_mac_addr; + goto err_hw_init; } - - bcopy(adapter->hw.mac_addr, adapter->interface_data.ac_enaddr, ETHER_ADDR_LEN); /* Setup OS specific network interface */ em_setup_interface(dev, adapter); + em_allocate_intr(adapter); + /* Initialize statistics */ em_clear_hw_cntrs(&adapter->hw); em_update_stats_counters(adapter); adapter->hw.get_link_status = 1; - em_check_for_link(&adapter->hw); + em_update_link_status(adapter); - /* Print the link status */ - if (adapter->link_active == 1) { - em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, - &adapter->link_duplex); - printf("em%d: Speed:%d Mbps Duplex:%s\n", - adapter->unit, - adapter->link_speed, - adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half"); - } else - printf("em%d: Speed:N/A Duplex:N/A\n", adapter->unit); + /* Indicate SOL/IDER usage */ + if (em_check_phy_reset_block(&adapter->hw)) + device_printf(dev, + "PHY reset is blocked due to SOL/IDER session.\n"); /* Identify 82544 on PCIX */ - em_get_bus_info(&adapter->hw); - if(adapter->hw.bus_type == em_bus_type_pcix && - adapter->hw.mac_type == em_82544) { - adapter->pcix_82544 = TRUE; - } - else { - adapter->pcix_82544 = FALSE; - } - INIT_DEBUGOUT("em_attach: end"); + em_get_bus_info(&adapter->hw); + if(adapter->hw.bus_type == em_bus_type_pcix && adapter->hw.mac_type == em_82544) + adapter->pcix_82544 = TRUE; + else + adapter->pcix_82544 = FALSE; + splx(s); - return(error); + INIT_DEBUGOUT("em_attach: end"); + return (0); -err_mac_addr: err_hw_init: - contigfree(adapter->rx_desc_base, rsize, M_DEVBUF); + em_dma_free(adapter, &adapter->rxdma); err_rx_desc: - contigfree(adapter->tx_desc_base, tsize, M_DEVBUF); + em_dma_free(adapter, &adapter->txdma); err_tx_desc: err_pci: + em_free_intr(adapter); em_free_pci_resources(adapter); sysctl_ctx_free(&adapter->sysctl_ctx); err_sysctl: - splx(s); - return(error); + splx(s); + + return (error); } /********************************************************************* @@ -542,59 +571,41 @@ err_sysctl: * The detach entry point is called when the driver is being removed. * This routine stops the adapter and deallocates all the resources * that were allocated for driver operation. - * + * * return 0 on success, positive on failure *********************************************************************/ static int em_detach(device_t dev) { - struct adapter * adapter = device_get_softc(dev); - struct ifnet *ifp = &adapter->interface_data.ac_if; - int s; - int size; + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = &adapter->interface_data.ac_if; + int s; INIT_DEBUGOUT("em_detach: begin"); s = splimp(); + em_free_intr(adapter); adapter->in_detach = 1; - em_stop(adapter); em_phy_hw_reset(&adapter->hw); -#if __FreeBSD_version < 500000 - ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); -#else - ether_ifdetach(&adapter->interface_data.ac_if); -#endif + ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); + em_free_pci_resources(adapter); bus_generic_detach(dev); - size = EM_ROUNDUP(adapter->num_tx_desc * - sizeof(struct em_tx_desc), 4096); - /* Free Transmit Descriptor ring */ if (adapter->tx_desc_base) { - contigfree(adapter->tx_desc_base, size, M_DEVBUF); + em_dma_free(adapter, &adapter->txdma); adapter->tx_desc_base = NULL; } - size = EM_ROUNDUP(adapter->num_rx_desc * - sizeof(struct em_rx_desc), 4096); - /* Free Receive Descriptor ring */ if (adapter->rx_desc_base) { - contigfree(adapter->rx_desc_base, size, M_DEVBUF); + em_dma_free(adapter, &adapter->rxdma); adapter->rx_desc_base = NULL; } - /* Remove from the adapter list */ - if (em_adapter_list == adapter) - em_adapter_list = adapter->next; - if (adapter->next != NULL) - adapter->next->prev = adapter->prev; - if (adapter->prev != NULL) - adapter->prev->next = adapter->next; - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ifp->if_timer = 0; @@ -602,21 +613,54 @@ em_detach(device_t dev) sysctl_ctx_free(&adapter->sysctl_ctx); splx(s); - return(0); + return (0); } /********************************************************************* * * Shutdown entry point * - **********************************************************************/ + **********************************************************************/ static int em_shutdown(device_t dev) { struct adapter *adapter = device_get_softc(dev); em_stop(adapter); - return(0); + return (0); +} + +/* + * Suspend/resume device methods. + */ +static int +em_suspend(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + int s; + + s = splimp(); + em_stop(adapter); + splx(s); + + return bus_generic_suspend(dev); +} + +static int +em_resume(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = &adapter->interface_data.ac_if; + int s; + + s = splimp(); + em_init(adapter); + if ((ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_RUNNING)) + em_start(ifp); + splx(s); + + return bus_generic_resume(dev); } @@ -633,40 +677,42 @@ em_shutdown(device_t dev) static void em_start(struct ifnet *ifp) { - int s; - struct mbuf *m_head; - struct adapter *adapter = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; + struct mbuf *m_head; + int s; - if (!adapter->link_active) - return; + if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != + IFF_RUNNING) + return; + if (!adapter->link_active) + return; - s = splimp(); - while (ifp->if_snd.ifq_head != NULL) { + s = splimp(); + while (ifp->if_snd.ifq_head != NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); - - if (m_head == NULL) break; - - if (em_encap(adapter, m_head)) { + IF_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + /* + * em_encap() can modify our pointer, and or make it NULL on + * failure. In that event, we can't requeue. + */ + if (em_encap(adapter, &m_head)) { + if (m_head == NULL) + break; ifp->if_flags |= IFF_OACTIVE; IF_PREPEND(&ifp->if_snd, m_head); break; - } + } /* Send a copy of the frame to the BPF listener */ -#if __FreeBSD_version < 500000 - if (ifp->if_bpf) - bpf_mtap(ifp, m_head); -#else - BPF_MTAP(ifp, m_head); -#endif - - /* Set timeout in case hardware has problems transmitting */ - ifp->if_timer = EM_TX_TIMEOUT; - - } - splx(s); - return; + if (ifp->if_bpf) + bpf_mtap(ifp, m_head); + + /* Set timeout in case hardware has problems transmitting. */ + ifp->if_timer = EM_TX_TIMEOUT; + } + splx(s); } /********************************************************************* @@ -681,13 +727,15 @@ em_start(struct ifnet *ifp) static int em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { - int s, mask, error = 0; - struct ifreq *ifr = (struct ifreq *) data; - struct adapter * adapter = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; + int s; s = splimp(); - if (adapter->in_detach) goto out; + if (adapter->in_detach) + goto out; switch (command) { case SIOCSIFADDR: @@ -696,24 +744,56 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) ether_ioctl(ifp, command, data); break; case SIOCSIFMTU: + { + int max_frame_size; + uint16_t eeprom_data = 0; + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)"); - if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN || \ - /* 82573 does not support jumbo frames */ - (adapter->hw.mac_type == em_82573 && ifr->ifr_mtu > ETHERMTU) ) { + + switch (adapter->hw.mac_type) { + case em_82573: + /* + * 82573 only supports jumbo frames + * if ASPM is disabled. + */ + em_read_eeprom(&adapter->hw, EEPROM_INIT_3GIO_3, 1, + &eeprom_data); + if (eeprom_data & EEPROM_WORD1A_ASPM_MASK) { + max_frame_size = ETHER_MAX_LEN; + break; + } + /* Allow Jumbo frames - fall thru */ + case em_82571: + case em_82572: + case em_80003es2lan: /* Limit Jumbo Frame size */ + max_frame_size = 9234; + break; + case em_ich8lan: + /* ICH8 does not support jumbo frames */ + max_frame_size = ETHER_MAX_LEN; + break; + default: + max_frame_size = MAX_JUMBO_FRAME_SIZE; + } + if (ifr->ifr_mtu > max_frame_size - ETHER_HDR_LEN - + ETHER_CRC_LEN) { error = EINVAL; - } else { - ifp->if_mtu = ifr->ifr_mtu; - adapter->hw.max_frame_size = - ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; - em_init(adapter); + break; } + + ifp->if_mtu = ifr->ifr_mtu; + adapter->hw.max_frame_size = + ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + 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 { @@ -743,17 +823,20 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); break; case SIOCSIFCAP: + { + int mask, reinit; + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)"); + reinit = 0; mask = ifr->ifr_reqcap ^ ifp->if_capenable; if (mask & IFCAP_HWCSUM) { - if (IFCAP_HWCSUM & ifp->if_capenable) - ifp->if_capenable &= ~IFCAP_HWCSUM; - else - ifp->if_capenable |= IFCAP_HWCSUM; - if (ifp->if_flags & IFF_RUNNING) - em_init(adapter); + ifp->if_capenable ^= IFCAP_HWCSUM; + reinit = 1; } + if (reinit && (ifp->if_flags & IFF_RUNNING)) + em_init(adapter); break; + } default: IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)", (int)command); error = EINVAL; @@ -761,7 +844,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) out: splx(s); - return(error); + return (error); } /********************************************************************* @@ -774,8 +857,7 @@ out: static void em_watchdog(struct ifnet *ifp) { - struct adapter * adapter; - adapter = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; /* If we are in this routine because of pause frames, then * don't reset the hardware. @@ -785,16 +867,13 @@ em_watchdog(struct ifnet *ifp) return; } - if (em_check_for_link(&adapter->hw)) - printf("em%d: watchdog timeout -- resetting\n", adapter->unit); + if (em_check_for_link(&adapter->hw) == 0) + device_printf(adapter->dev, "watchdog timeout -- resetting\n"); ifp->if_flags &= ~IFF_RUNNING; + adapter->watchdog_events++; - em_stop(adapter); em_init(adapter); - - ifp->if_oerrors++; - return; } /********************************************************************* @@ -802,7 +881,7 @@ em_watchdog(struct ifnet *ifp) * * This routine is used in two ways. It is used by the stack as * init entry point in network interface structure. It is also used - * by the driver as a hw/sw initialization routine to get to a + * by the driver as a hw/sw initialization routine to get to a * consistent state. * * return 0 on success, positive on failure @@ -811,10 +890,11 @@ em_watchdog(struct ifnet *ifp) static void em_init(void *arg) { - int s; + struct adapter *adapter = arg; + struct ifnet *ifp = &adapter->interface_data.ac_if; + device_t dev = adapter->dev; uint32_t pba; - struct ifnet *ifp; - struct adapter * adapter = arg; + int s; INIT_DEBUGOUT("em_init: begin"); @@ -822,7 +902,8 @@ em_init(void *arg) em_stop(adapter); - /* Packet Buffer Allocation (PBA) + /* + * Packet Buffer Allocation (PBA) * Writing PBA sets the receive portion of the buffer * the remainder is used for the transmit buffer. * @@ -832,23 +913,28 @@ em_init(void *arg) * Default allocation: PBA=30K for Rx, leaving 10K for Tx. * Note: default does not leave enough room for Jumbo Frame >10k. */ - switch (adapter->hw.mac_type) { - case em_82547: - case em_82547_rev_2: - /* Total Packet Buffer is 40K */ - if(adapter->hw.max_frame_size > EM_RXBUFFER_8192) { + case em_82547: + case em_82547_rev_2: /* 82547: Total Packet Buffer is 40K */ + if (adapter->hw.max_frame_size > EM_RXBUFFER_8192) pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */ - } else { - pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */ - } + else + pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */ adapter->tx_fifo_head = 0; adapter->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT; adapter->tx_fifo_size = (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT; - case em_82573: - /* Total Packet Buffer is 32K */ + break; + case em_80003es2lan: /* 80003es2lan: Total Packet Buffer is 48K */ + case em_82571: /* 82571: Total Packet Buffer is 48K */ + case em_82572: /* 82572: Total Packet Buffer is 48K */ + pba = E1000_PBA_32K; /* 32K for Rx, 16K for Tx */ + break; + case em_82573: /* 82573: Total Packet Buffer is 32K */ /* Jumbo frames not supported */ - pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */ + pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */ + break; + case em_ich8lan: + pba = E1000_PBA_8K; break; default: /* Devices before 82547 had a Packet Buffer of 64K. */ @@ -862,24 +948,22 @@ em_init(void *arg) E1000_WRITE_REG(&adapter->hw, PBA, pba); /* Get the latest mac address, User can use a LAA */ - bcopy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr, - ETHER_ADDR_LEN); + bcopy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr, ETHER_ADDR_LEN); /* Initialize the hardware */ if (em_hardware_init(adapter)) { - printf("em%d: Unable to initialize the hardware\n", - adapter->unit); + device_printf(dev, "Unable to initialize the hardware\n"); splx(s); return; } + em_update_link_status(adapter); em_enable_vlans(adapter); /* Prepare transmit descriptors and buffers */ if (em_setup_transmit_structures(adapter)) { - printf("em%d: Could not setup transmit structures\n", - adapter->unit); - em_stop(adapter); + device_printf(dev, "Could not setup transmit structures\n"); + em_stop(adapter); splx(s); return; } @@ -890,18 +974,16 @@ em_init(void *arg) /* Prepare receive descriptors and buffers */ if (em_setup_receive_structures(adapter)) { - printf("em%d: Could not setup receive structures\n", - adapter->unit); + device_printf(dev, "Could not setup receive structures\n"); em_stop(adapter); splx(s); return; } em_initialize_receive_unit(adapter); - - /* Don't loose promiscuous settings */ + + /* Don't lose promiscuous settings */ em_set_promisc(adapter); - ifp = &adapter->interface_data.ac_if; ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; @@ -912,117 +994,126 @@ em_init(void *arg) ifp->if_hwassist = 0; } - adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); + callout_reset(&adapter->timer, hz, em_local_timer, adapter); em_clear_hw_cntrs(&adapter->hw); #ifdef DEVICE_POLLING - /* - * Only enable interrupts if we are not polling, make sure - * they are off otherwise. - */ - if (ifp->if_ipending & IFF_POLLING) - em_disable_intr(adapter); - else + /* + * Only enable interrupts if we are not polling, make sure + * they are off otherwise. + */ + if (ifp->if_ipending & IFF_POLLING) + em_disable_intr(adapter); + else #endif /* DEVICE_POLLING */ - em_enable_intr(adapter); + em_enable_intr(adapter); /* Don't reset the phy next time init gets called */ adapter->hw.phy_reset_disable = TRUE; splx(s); - return; } #ifdef DEVICE_POLLING -static poll_handler_t em_poll; - -static void +/********************************************************************* + * + * Polling routine + * + *********************************************************************/ +static void em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { - struct adapter *adapter = ifp->if_softc; - u_int32_t reg_icr; + struct adapter *adapter = ifp->if_softc; + uint32_t reg_icr; - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - em_enable_intr(adapter); - return; - } - if (cmd == POLL_AND_CHECK_STATUS) { - reg_icr = E1000_READ_REG(&adapter->hw, ICR); - 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); - } - } - if (ifp->if_flags & IFF_RUNNING) { - 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); + if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ + em_enable_intr(adapter); + return; + } + + if (cmd == POLL_AND_CHECK_STATUS) { + reg_icr = E1000_READ_REG(&adapter->hw, ICR); + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + callout_stop(&adapter->timer); + adapter->hw.get_link_status = 1; + em_check_for_link(&adapter->hw); + em_update_link_status(adapter); + callout_reset(&adapter->timer, hz, em_local_timer, adapter); + } + } + if (!(ifp->if_flags & IFF_RUNNING)) + return; + + em_rxeof(adapter, count); + em_txeof(adapter); + + if (ifp->if_snd.ifq_head != NULL) + em_start(ifp); } -#endif /* DEVICE_POLLING */ +#endif /********************************************************************* * - * 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; + struct adapter *adapter = arg; + struct ifnet *ifp; + uint32_t reg_icr; - ifp = &adapter->interface_data.ac_if; + ifp = &adapter->interface_data.ac_if; #ifdef DEVICE_POLLING - if (ifp->if_ipending & IFF_POLLING) - return; - - if (ether_poll_register(em_poll, ifp)) { - em_disable_intr(adapter); - em_poll(ifp, 0, 1); - return; - } -#endif /* DEVICE_POLLING */ - - reg_icr = E1000_READ_REG(&adapter->hw, ICR); - if (!reg_icr) { + if (ifp->if_ipending & IFF_POLLING) return; - } - /* 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); + if (ether_poll_register(em_poll, ifp)) { + em_disable_intr(adapter); + em_poll(ifp, 0, 1); + return; } +#endif /* DEVICE_POLLING */ - while (loop_cnt > 0) { - if (ifp->if_flags & IFF_RUNNING) { - em_process_receive_interrupts(adapter, -1); - em_clean_transmit_interrupts(adapter); - } - loop_cnt--; - } + for (;;) { + reg_icr = E1000_READ_REG(&adapter->hw, ICR); + if (adapter->hw.mac_type >= em_82571 && + (reg_icr & E1000_ICR_INT_ASSERTED) == 0) + break; + else if (reg_icr == 0) + break; - if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) - em_start(ifp); + /* + * XXX: some laptops trigger several spurious interrupts + * on em(4) when in the resume cycle. The ICR register + * reports all-ones value in this case. Processing such + * interrupts would lead to a freeze. I don't know why. + */ + if (reg_icr == 0xffffffff) + break; - return; -} + if (ifp->if_flags & IFF_RUNNING) { + em_rxeof(adapter, -1); + em_txeof(adapter); + } + /* Link status change */ + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + callout_stop(&adapter->timer); + adapter->hw.get_link_status = 1; + em_check_for_link(&adapter->hw); + em_update_link_status(adapter); + callout_reset(&adapter->timer, hz, em_local_timer, adapter); + } + if (reg_icr & E1000_ICR_RXO) + adapter->rx_overruns++; + } + if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) + em_start(ifp); +} /********************************************************************* * @@ -1035,25 +1126,12 @@ em_intr(void *arg) static void em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) { - struct adapter * adapter = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; INIT_DEBUGOUT("em_media_status: begin"); em_check_for_link(&adapter->hw); - if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { - if (adapter->link_active == 0) { - em_get_speed_and_duplex(&adapter->hw, - &adapter->link_speed, - &adapter->link_duplex); - adapter->link_active = 1; - } - } else { - if (adapter->link_active == 1) { - adapter->link_speed = 0; - adapter->link_duplex = 0; - adapter->link_active = 0; - } - } + em_update_link_status(adapter); ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; @@ -1063,8 +1141,12 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) ifmr->ifm_status |= IFM_ACTIVE; - if (adapter->hw.media_type == em_media_type_fiber) { - ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; + if ((adapter->hw.media_type == em_media_type_fiber) || + (adapter->hw.media_type == em_media_type_internal_serdes)) { + if (adapter->hw.mac_type == em_82545) + ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; + else + ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; } else { switch (adapter->link_speed) { case 10: @@ -1074,11 +1156,7 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) ifmr->ifm_active |= IFM_100_TX; break; case 1000: -#if __FreeBSD_version < 500000 ifmr->ifm_active |= IFM_1000_TX; -#else - ifmr->ifm_active |= IFM_1000_T; -#endif break; } if (adapter->link_duplex == FULL_DUPLEX) @@ -1086,7 +1164,6 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) else ifmr->ifm_active |= IFM_HDX; } - return; } /********************************************************************* @@ -1100,25 +1177,22 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) static int em_media_change(struct ifnet *ifp) { - struct adapter * adapter = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; struct ifmedia *ifm = &adapter->media; INIT_DEBUGOUT("em_media_change: begin"); if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); + return (EINVAL); switch (IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO: adapter->hw.autoneg = DO_AUTO_NEG; adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; break; + case IFM_1000_LX: case IFM_1000_SX: -#if __FreeBSD_version < 500000 case IFM_1000_TX: -#else - case IFM_1000_T: -#endif adapter->hw.autoneg = DO_AUTO_NEG; adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; break; @@ -1128,7 +1202,7 @@ em_media_change(struct ifnet *ifp) if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) adapter->hw.forced_speed_duplex = em_100_full; else - adapter->hw.forced_speed_duplex = em_100_half; + adapter->hw.forced_speed_duplex = em_100_half; break; case IFM_10_T: adapter->hw.autoneg = FALSE; @@ -1136,10 +1210,10 @@ em_media_change(struct ifnet *ifp) if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) adapter->hw.forced_speed_duplex = em_10_full; else - adapter->hw.forced_speed_duplex = em_10_half; + adapter->hw.forced_speed_duplex = em_10_half; break; default: - printf("em%d: Unsupported media type\n", adapter->unit); + device_printf(adapter->dev, "Unsupported media type\n"); } /* As the speed/duplex settings my have changed we need to @@ -1149,7 +1223,7 @@ em_media_change(struct ifnet *ifp) em_init(adapter); - return(0); + return (0); } /********************************************************************* @@ -1159,181 +1233,274 @@ em_media_change(struct ifnet *ifp) * return 0 on success, positive on failure **********************************************************************/ +struct em_encap_arg { + bus_dma_segment_t *segs; + int nsegs; +}; + +static void +em_encap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t length, + int error) +{ + struct em_encap_arg *ea; + + if (error) + return; + ea = arg; + ea->nsegs = nsegs; + bcopy(segs, ea->segs, sizeof(bus_dma_segment_t) * nsegs); +} + static int -em_encap(struct adapter *adapter, struct mbuf *m_head) -{ - vm_offset_t virtual_addr; - u_int32_t txd_upper; - u_int32_t txd_lower; - int txd_used, i, txd_saved; - struct mbuf *mp; - u_int64_t address; +em_encap(struct adapter *adapter, struct mbuf **m_headp) +{ + struct ifnet *ifp = &adapter->interface_data.ac_if; + bus_dma_segment_t segs[EM_MAX_SCATTER]; + bus_dmamap_t map; + struct em_encap_arg ea; + struct em_buffer *tx_buffer, *tx_buffer_last; + struct em_tx_desc *current_tx_desc; + struct mbuf *m_head; + struct ifvlan *ifv = NULL; + uint32_t txd_upper, txd_lower, txd_used, txd_saved; + int nsegs, i, j; + int error; -/* For 82544 Workaround */ - DESC_ARRAY desc_array; - u_int32_t array_elements; - u_int32_t counter; + m_head = *m_headp; + current_tx_desc = NULL; + txd_used = txd_saved = 0; -#if __FreeBSD_version < 500000 - struct ifvlan *ifv = NULL; -#else - 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. + */ + if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { + em_txeof(adapter); + if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { + adapter->no_tx_desc_avail1++; + return (ENOBUFS); + } + } + + /* Find out if we are in vlan mode. */ + 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; - /* - * Force a cleanup if number of TX descriptors - * available hits the threshold + /* + * When operating in promiscuous mode, hardware encapsulation for + * packets is disabled. This means we have to add the vlan + * encapsulation in the driver, since it will have come down from the + * VLAN layer with a tag instead of a VLAN header. */ - if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) - em_clean_transmit_interrupts(adapter); + if (ifv != NULL && adapter->em_insert_vlan_header) { + struct ether_vlan_header *evl; + struct ether_header eh; - if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { - adapter->no_tx_desc_avail1++; - return (ENOBUFS); + m_head = m_pullup(m_head, sizeof(eh)); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + eh = *mtod(m_head, struct ether_header *); + + /* + * If it's already tagged don't add a new one. In 6.x and + * later this case is handled by removing the VLAN mtag + * once the vlan header is prepended. + */ + if (eh.ether_type == htons(ETHERTYPE_VLAN)) + goto tagged; + M_PREPEND(m_head, sizeof(*evl), M_DONTWAIT); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + m_head = m_pullup(m_head, sizeof(*evl)); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + evl = mtod(m_head, struct ether_vlan_header *); + bcopy(&eh, evl, sizeof(*evl)); + evl->evl_proto = evl->evl_encap_proto; + evl->evl_encap_proto = htons(ETHERTYPE_VLAN); + evl->evl_tag = htons(ifv->ifv_tag); +tagged: + ifv = NULL; + *m_headp = m_head; } - if (ifp->if_hwassist > 0) { - em_transmit_checksum_setup(adapter, m_head, - &txd_upper, &txd_lower); - } else - txd_upper = txd_lower = 0; + /* + * Map the packet for DMA. + */ + ea.segs = segs; + tx_buffer = &adapter->tx_buffer_area[adapter->next_avail_tx_desc]; + tx_buffer_last = tx_buffer; + map = tx_buffer->map; + error = bus_dmamap_load_mbuf(adapter->txtag, map, *m_headp, em_encap_cb, + &ea, BUS_DMA_NOWAIT); + if (error == EFBIG) { + struct mbuf *m; + m = m_defrag(*m_headp, M_DONTWAIT); + if (m == NULL) { + /* Assume m_defrag(9) used only m_get(9). */ + adapter->mbuf_alloc_failed++; + m_freem(*m_headp); + *m_headp = NULL; + return (ENOBUFS); + } + *m_headp = m; + error = bus_dmamap_load_mbuf(adapter->txtag, map, *m_headp, + em_encap_cb, &ea, BUS_DMA_NOWAIT); + if (error != 0) { + adapter->no_tx_dma_setup++; + m_freem(*m_headp); + *m_headp = NULL; + return (error); + } + } else if (error != 0) { + adapter->no_tx_dma_setup++; + return (error); + } + nsegs = ea.nsegs; + if (nsegs == 0) { + m_freem(*m_headp); + *m_headp = NULL; + return (EIO); + } - /* 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; -#else - mtag = VLAN_OUTPUT_TAG(ifp, m_head); -#endif + if (nsegs > adapter->num_tx_desc_avail) { + adapter->no_tx_desc_avail2++; + bus_dmamap_unload(adapter->txtag, map); + return (ENOBUFS); + } - i = adapter->next_avail_tx_desc; - txd_saved = i; - txd_used = 0; + m_head = *m_headp; + if (ifp->if_hwassist > 0) + em_transmit_checksum_setup(adapter, m_head, &txd_upper, &txd_lower); + else + txd_upper = txd_lower = 0; - for (mp = m_head; mp != NULL; mp = mp->m_next) { - if (mp->m_len == 0) - continue; - /* If adapter is 82544 and on PCIX bus */ - if(adapter->pcix_82544) { - array_elements = 0; - virtual_addr= mtod(mp, vm_offset_t); - address = vtophys(virtual_addr); - /* Check the Address and Length combination and split the data accordingly */ - array_elements = em_fill_descriptors( - address, - mp->m_len, - &desc_array); + i = adapter->next_avail_tx_desc; + if (adapter->pcix_82544) { + txd_saved = i; + txd_used = 0; + } + for (j = 0; j < nsegs; j++) { + /* If adapter is 82544 and on PCIX bus. */ + if(adapter->pcix_82544) { + DESC_ARRAY desc_array; + uint32_t array_elements, counter; + /* + * Check the Address and Length combination and + * split the data accordingly + */ + array_elements = em_fill_descriptors(segs[j].ds_addr, + segs[j].ds_len, &desc_array); for (counter = 0; counter < array_elements; counter++) { if (txd_used == adapter->num_tx_desc_avail) { - adapter->next_avail_tx_desc = txd_saved; - adapter->no_tx_desc_avail2++; - return (ENOBUFS); - } - + adapter->next_avail_tx_desc = txd_saved; + adapter->no_tx_desc_avail2++; + bus_dmamap_unload(adapter->txtag, map); + return (ENOBUFS); + } tx_buffer = &adapter->tx_buffer_area[i]; - current_tx_desc = &adapter->tx_desc_base[i]; - /* Put in the buffer address*/ - current_tx_desc->buffer_addr = desc_array.descriptor[counter].address; - /* Put in the length */ - current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower - | (u_int16_t)desc_array.descriptor[counter].length); - current_tx_desc->upper.data = (txd_upper); + current_tx_desc = &adapter->tx_desc_base[i]; + current_tx_desc->buffer_addr = htole64( + desc_array.descriptor[counter].address); + current_tx_desc->lower.data = htole32( + (adapter->txd_cmd | txd_lower | + (uint16_t)desc_array.descriptor[counter].length)); + current_tx_desc->upper.data = htole32((txd_upper)); if (++i == adapter->num_tx_desc) - i = 0; - tx_buffer->m_head = NULL; - txd_used++; - } - } else { - if (txd_used == adapter->num_tx_desc_avail) { - adapter->next_avail_tx_desc = txd_saved; - adapter->no_tx_desc_avail2++; - return (ENOBUFS); - } + i = 0; + tx_buffer->m_head = NULL; + txd_used++; + } + } else { tx_buffer = &adapter->tx_buffer_area[i]; current_tx_desc = &adapter->tx_desc_base[i]; - virtual_addr = mtod(mp, vm_offset_t); - current_tx_desc->buffer_addr = vtophys(virtual_addr); - current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower | mp->m_len); - current_tx_desc->upper.data = (txd_upper); + + current_tx_desc->buffer_addr = htole64(segs[j].ds_addr); + current_tx_desc->lower.data = htole32( + adapter->txd_cmd | txd_lower | segs[j].ds_len); + current_tx_desc->upper.data = htole32(txd_upper); if (++i == adapter->num_tx_desc) i = 0; tx_buffer->m_head = NULL; - - txd_used++; } } - adapter->num_tx_desc_avail -= txd_used; - 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; -#else - 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; - } + adapter->next_avail_tx_desc = i; + if (adapter->pcix_82544) + adapter->num_tx_desc_avail -= txd_used; + else + adapter->num_tx_desc_avail -= nsegs; + + if (ifv != NULL) { + /* Set the vlan id. */ + current_tx_desc->upper.fields.special = + htole16(ifv->ifv_tag); + + /* Tell hardware to add tag. */ + current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE); + } tx_buffer->m_head = m_head; - - /* - * Last Descriptor of Packet needs End Of Packet (EOP) + tx_buffer_last->map = tx_buffer->map; + tx_buffer->map = map; + bus_dmamap_sync(adapter->txtag, map, BUS_DMASYNC_PREWRITE); + + /* + * Last Descriptor of Packet needs End Of Packet (EOP). */ - current_tx_desc->lower.data |= (E1000_TXD_CMD_EOP); + current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_EOP); - /* + /* * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 * that this frame is available to transmit. */ - if (adapter->hw.mac_type == em_82547 && - adapter->link_duplex == HALF_DUPLEX) { + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + 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) { + 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 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. + * in this case. We do that only when FIFO is quiescent. * **********************************************************************/ 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; + int s; s = splimp(); + hw_tdt = E1000_READ_REG(&adapter->hw, TDT); sw_tdt = adapter->next_avail_tx_desc; @@ -1344,24 +1511,20 @@ em_82547_move_tail(void *arg) if(++hw_tdt == adapter->num_tx_desc) hw_tdt = 0; - if(eop) { + if (eop) { if (em_82547_fifo_workaround(adapter, length)) { adapter->tx_fifo_wrk_cnt++; - 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; + callout_reset(&adapter->tx_fifo_timer, 1, + em_82547_move_tail, adapter); + break; } + E1000_WRITE_REG(&adapter->hw, TDT, hw_tdt); + em_82547_update_fifo_head(adapter, length); + length = 0; } - } + } + splx(s); - return; } static int @@ -1369,36 +1532,32 @@ 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); + fifo_pkt_len = roundup2(len + EM_FIFO_HDR, EM_FIFO_HDR); if (adapter->link_duplex == HALF_DUPLEX) { fifo_space = adapter->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); - } + if (em_82547_tx_fifo_reset(adapter)) + return (0); + else + return (1); } } - return(0); + 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); + int fifo_pkt_len = roundup2(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 >= adapter->tx_fifo_size) { adapter->tx_fifo_head -= adapter->tx_fifo_size; } - - return; } @@ -1407,13 +1566,10 @@ 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)) { + 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); @@ -1432,48 +1588,43 @@ em_82547_tx_fifo_reset(struct adapter *adapter) adapter->tx_fifo_head = 0; adapter->tx_fifo_reset_cnt++; - return(TRUE); + return (TRUE); } else { - return(FALSE); + return (FALSE); } } static void -em_set_promisc(struct adapter * adapter) +em_set_promisc(struct adapter *adapter) { - - u_int32_t reg_rctl; - u_int32_t ctrl; - struct ifnet *ifp = &adapter->interface_data.ac_if; + struct ifnet *ifp = &adapter->interface_data.ac_if; + uint32_t reg_rctl; reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - ctrl = E1000_READ_REG(&adapter->hw, CTRL); if (ifp->if_flags & IFF_PROMISC) { reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - - /* Disable VLAN stripping in promiscous mode - * This enables bridging of vlan tagged frames to occur + /* Disable VLAN stripping in promiscous mode + * This enables bridging of vlan tagged frames to occur * and also allows vlan tags to be seen in tcpdump */ - ctrl &= ~E1000_CTRL_VME; - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); - + em_disable_vlans(adapter); + adapter->em_insert_vlan_header = 1; } else if (ifp->if_flags & IFF_ALLMULTI) { reg_rctl |= E1000_RCTL_MPE; reg_rctl &= ~E1000_RCTL_UPE; E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - } - - return; + adapter->em_insert_vlan_header = 0; + } else + adapter->em_insert_vlan_header = 0; } static void -em_disable_promisc(struct adapter * adapter) +em_disable_promisc(struct adapter *adapter) { - u_int32_t reg_rctl; + uint32_t reg_rctl; reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); @@ -1482,7 +1633,7 @@ em_disable_promisc(struct adapter * adapter) E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); em_enable_vlans(adapter); - return; + adapter->em_insert_vlan_header = 0; } @@ -1494,59 +1645,52 @@ em_disable_promisc(struct adapter * adapter) **********************************************************************/ static void -em_set_multi(struct adapter * adapter) +em_set_multi(struct adapter *adapter) { - u_int32_t reg_rctl = 0; - u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; - struct ifmultiaddr *ifma; - int mcnt = 0; - struct ifnet *ifp = &adapter->interface_data.ac_if; - - IOCTL_DEBUGOUT("em_set_multi: begin"); - - if (adapter->hw.mac_type == em_82542_rev2_0) { - reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { - em_pci_clear_mwi(&adapter->hw); - } - reg_rctl |= E1000_RCTL_RST; - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - msec_delay(5); - } - -#if __FreeBSD_version < 500000 - LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { -#else - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { -#endif - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break; + struct ifnet *ifp = &adapter->interface_data.ac_if; + struct ifmultiaddr *ifma; + uint32_t reg_rctl = 0; + uint8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; + int mcnt = 0; + + IOCTL_DEBUGOUT("em_set_multi: begin"); + + if (adapter->hw.mac_type == em_82542_rev2_0) { + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) + em_pci_clear_mwi(&adapter->hw); + reg_rctl |= E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + msec_delay(5); + } - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); - mcnt++; - } + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; - 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); - } else - em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1); + if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) + break; - if (adapter->hw.mac_type == em_82542_rev2_0) { - reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - reg_rctl &= ~E1000_RCTL_RST; - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - msec_delay(5); - if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { - em_pci_set_mwi(&adapter->hw); - } - } + 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) { + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + reg_rctl |= E1000_RCTL_MPE; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + } else + em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0, 1); - return; + if (adapter->hw.mac_type == em_82542_rev2_0) { + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + reg_rctl &= ~E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + msec_delay(5); + if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) + em_pci_set_mwi(&adapter->hw); + } } @@ -1560,83 +1704,88 @@ em_set_multi(struct adapter * adapter) static void em_local_timer(void *arg) { - int s; - struct ifnet *ifp; - struct adapter * adapter = arg; - ifp = &adapter->interface_data.ac_if; + struct adapter *adapter = arg; + struct ifnet *ifp = &adapter->interface_data.ac_if; + int s; s = splimp(); em_check_for_link(&adapter->hw); - em_print_link_status(adapter); - em_update_stats_counters(adapter); - if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { + em_update_link_status(adapter); + em_update_stats_counters(adapter); + 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); + callout_reset(&adapter->timer, hz, em_local_timer, adapter); splx(s); - return; } static void -em_print_link_status(struct adapter * adapter) +em_update_link_status(struct adapter *adapter) { + struct ifnet *ifp = &adapter->interface_data.ac_if; + device_t dev = adapter->dev; + if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { if (adapter->link_active == 0) { - em_get_speed_and_duplex(&adapter->hw, - &adapter->link_speed, - &adapter->link_duplex); - printf("em%d: Link is up %d Mbps %s\n", - adapter->unit, - adapter->link_speed, - ((adapter->link_duplex == FULL_DUPLEX) ? - "Full Duplex" : "Half Duplex")); + em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, + &adapter->link_duplex); + /* Check if we may set SPEED_MODE bit on PCI-E */ + if ((adapter->link_speed == SPEED_1000) && + ((adapter->hw.mac_type == em_82571) || + (adapter->hw.mac_type == em_82572))) { + int tarc0; + + tarc0 = E1000_READ_REG(&adapter->hw, TARC0); + tarc0 |= SPEED_MODE_BIT; + E1000_WRITE_REG(&adapter->hw, TARC0, tarc0); + } + if (bootverbose) + device_printf(dev, "Link is up %d Mbps %s\n", + adapter->link_speed, + ((adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex")); adapter->link_active = 1; adapter->smartspeed = 0; + ifp->if_baudrate = adapter->link_speed * 1000000; } } else { if (adapter->link_active == 1) { - adapter->link_speed = 0; + ifp->if_baudrate = adapter->link_speed = 0; adapter->link_duplex = 0; - printf("em%d: Link is Down\n", adapter->unit); + if (bootverbose) + device_printf(dev, "Link is Down\n"); adapter->link_active = 0; } } - - return; } /********************************************************************* * * This routine disables all traffic on the adapter by issuing a - * global reset on the MAC and deallocates TX/RX buffers. + * global reset on the MAC and deallocates TX/RX buffers. * **********************************************************************/ static void em_stop(void *arg) { - struct ifnet *ifp; - struct adapter * adapter = arg; - ifp = &adapter->interface_data.ac_if; + struct adapter *adapter = arg; + struct ifnet *ifp = &adapter->interface_data.ac_if; INIT_DEBUGOUT("em_stop: begin"); + em_disable_intr(adapter); em_reset_hw(&adapter->hw); - untimeout(em_local_timer, adapter, adapter->timer_handle); - untimeout(em_82547_move_tail, adapter, - adapter->tx_fifo_timer_handle); + callout_stop(&adapter->timer); + callout_stop(&adapter->tx_fifo_timer); em_free_transmit_structures(adapter); em_free_receive_structures(adapter); - /* Tell the stack that the interface is no longer active */ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; } @@ -1646,7 +1795,7 @@ em_stop(void *arg) * **********************************************************************/ static void -em_identify_hardware(struct adapter * adapter) +em_identify_hardware(struct adapter *adapter) { device_t dev = adapter->dev; @@ -1654,9 +1803,9 @@ em_identify_hardware(struct adapter * adapter) adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) && (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) { - printf("em%d: Memory Access and/or Bus Master bits were not set!\n", - adapter->unit); - adapter->hw.pci_cmd_word |= + device_printf(dev, "Memory Access and/or Bus Master bits " + "were not set!\n"); + adapter->hw.pci_cmd_word |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2); } @@ -1670,106 +1819,137 @@ em_identify_hardware(struct adapter * adapter) /* Identify the MAC */ if (em_set_mac_type(&adapter->hw)) - printf("em%d: Unknown MAC Type\n", adapter->unit); - - if(adapter->hw.mac_type == em_82541 || - adapter->hw.mac_type == em_82541_rev_2 || - adapter->hw.mac_type == em_82547 || - adapter->hw.mac_type == em_82547_rev_2) - adapter->hw.phy_init_script = TRUE; - - return; + device_printf(dev, "Unknown MAC Type\n"); + + if(adapter->hw.mac_type == em_82541 || adapter->hw.mac_type == em_82541_rev_2 || + adapter->hw.mac_type == em_82547 || adapter->hw.mac_type == em_82547_rev_2) + adapter->hw.phy_init_script = TRUE; } static int -em_allocate_pci_resources(struct adapter * adapter) +em_allocate_pci_resources(struct adapter *adapter) { - int i, val, rid; - device_t dev = adapter->dev; + device_t dev = adapter->dev; + int val, rid; - rid = EM_MMBA; + rid = PCIR_BAR(0); adapter->res_memory = bus_alloc_resource(dev, SYS_RES_MEMORY, - &rid, 0, ~0, 1, - RF_ACTIVE); - if (!(adapter->res_memory)) { - printf("em%d: Unable to allocate bus resource: memory\n", - adapter->unit); - return(ENXIO); + &rid, 0, ~0, 1, RF_ACTIVE); + if (adapter->res_memory == NULL) { + device_printf(dev, "Unable to allocate bus resource: memory\n"); + return (ENXIO); } - adapter->osdep.mem_bus_space_tag = + adapter->osdep.mem_bus_space_tag = rman_get_bustag(adapter->res_memory); - adapter->osdep.mem_bus_space_handle = - rman_get_bushandle(adapter->res_memory); + adapter->osdep.mem_bus_space_handle = rman_get_bushandle(adapter->res_memory); adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle; if (adapter->hw.mac_type > em_82543) { /* Figure our where our IO BAR is ? */ - rid = EM_MMBA; - for (i = 0; i < 5; i++) { + for (rid = PCIR_BAR(0); rid < PCIR_CARDBUSCIS;) { val = pci_read_config(dev, rid, 4); - if (val & 0x00000001) { + if (E1000_BAR_TYPE(val) == E1000_BAR_TYPE_IO) { adapter->io_rid = rid; break; } rid += 4; + /* check for 64bit BAR */ + if (E1000_BAR_MEM_TYPE(val) == E1000_BAR_MEM_TYPE_64BIT) + rid += 4; + } + if (rid >= PCIR_CARDBUSCIS) { + device_printf(dev, "Unable to locate IO BAR\n"); + return (ENXIO); } - adapter->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, - &adapter->io_rid, 0, ~0, 1, - RF_ACTIVE); - if (!(adapter->res_ioport)) { - printf("em%d: Unable to allocate bus resource: ioport\n", - adapter->unit); - return(ENXIO); + adapter->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, + &adapter->io_rid, 0, ~0, 1, RF_ACTIVE); + if (adapter->res_ioport == NULL) { + device_printf(dev, "Unable to allocate bus resource: " + "ioport\n"); + return (ENXIO); } + adapter->hw.io_base = 0; + adapter->osdep.io_bus_space_tag = rman_get_bustag(adapter->res_ioport); + adapter->osdep.io_bus_space_handle = + rman_get_bushandle(adapter->res_ioport); + } + + /* For ICH8 we need to find the flash memory. */ + if (adapter->hw.mac_type == em_ich8lan) { + rid = EM_FLASH; - adapter->hw.io_base = - rman_get_start(adapter->res_ioport); + adapter->flash_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + adapter->osdep.flash_bus_space_tag = rman_get_bustag(adapter->flash_mem); + adapter->osdep.flash_bus_space_handle = + rman_get_bushandle(adapter->flash_mem); } rid = 0x0; adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ, - &rid, 0, ~0, 1, - RF_SHAREABLE | RF_ACTIVE); - if (!(adapter->res_interrupt)) { - printf("em%d: Unable to allocate bus resource: interrupt\n", - adapter->unit); - return(ENXIO); - } - if (bus_setup_intr(dev, adapter->res_interrupt, INTR_TYPE_NET, - (void (*)(void *)) em_intr, adapter, - &adapter->int_handler_tag)) { - printf("em%d: Error registering interrupt handler!\n", - adapter->unit); - return(ENXIO); + &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); + if (adapter->res_interrupt == NULL) { + device_printf(dev, "Unable to allocate bus resource: " + "interrupt\n"); + return (ENXIO); } adapter->hw.back = &adapter->osdep; - return(0); + return (0); } -static void -em_free_pci_resources(struct adapter * adapter) +int +em_allocate_intr(struct adapter *adapter) { device_t dev = adapter->dev; + int error; - if (adapter->res_interrupt != NULL) { - bus_teardown_intr(dev, adapter->res_interrupt, - adapter->int_handler_tag); - bus_release_resource(dev, SYS_RES_IRQ, 0, - adapter->res_interrupt); - } - if (adapter->res_memory != NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA, - adapter->res_memory); + /* Manually turn off all interrupts */ + E1000_WRITE_REG(&adapter->hw, IMC, 0xffffffff); + + if (adapter->int_handler_tag == NULL && (error = bus_setup_intr(dev, + adapter->res_interrupt, INTR_TYPE_NET, em_intr, adapter, + &adapter->int_handler_tag)) != 0) { + device_printf(dev, "Failed to register interrupt handler"); + return (error); } - if (adapter->res_ioport != NULL) { - bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid, - adapter->res_ioport); + em_enable_intr(adapter); + return (0); +} + +static void +em_free_intr(struct adapter *adapter) +{ + device_t dev = adapter->dev; + + if (adapter->int_handler_tag != NULL) { + bus_teardown_intr(dev, adapter->res_interrupt, adapter->int_handler_tag); + adapter->int_handler_tag = NULL; } - return; +} + +static void +em_free_pci_resources(struct adapter *adapter) +{ + device_t dev = adapter->dev; + + if (adapter->res_interrupt != NULL) + bus_release_resource(dev, SYS_RES_IRQ, 0, adapter->res_interrupt); + + if (adapter->res_memory != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), + adapter->res_memory); + + if (adapter->flash_mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, EM_FLASH, + adapter->flash_mem); + + if (adapter->res_ioport != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid, + adapter->res_ioport); } /********************************************************************* @@ -1781,8 +1961,11 @@ em_free_pci_resources(struct adapter * adapter) * **********************************************************************/ static int -em_hardware_init(struct adapter * adapter) +em_hardware_init(struct adapter *adapter) { + device_t dev = adapter->dev; + uint16_t rx_buffer_size; + INIT_DEBUGOUT("em_hardware_init: begin"); /* Issue a global reset */ em_reset_hw(&adapter->hw); @@ -1792,39 +1975,61 @@ em_hardware_init(struct adapter * adapter) /* 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", - adapter->unit); - return(EIO); + device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); + return (EIO); } if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) { - printf("em%d: EEPROM read error while reading part number\n", - adapter->unit); - return(EIO); + device_printf(dev, "EEPROM read error while reading part " + "number\n"); + return (EIO); } - if (em_init_hw(&adapter->hw) < 0) { - printf("em%d: Hardware Initialization Failed", - adapter->unit); - return(EIO); + /* Set up smart power down as default off on newer adapters. */ + if (!em_smart_pwr_down && + (adapter->hw.mac_type == em_82571 || adapter->hw.mac_type == em_82572)) { + uint16_t phy_tmp = 0; + + /* Speed up time to link by disabling smart power down. */ + em_read_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT, &phy_tmp); + phy_tmp &= ~IGP02E1000_PM_SPD; + em_write_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT, phy_tmp); } - em_check_for_link(&adapter->hw); - if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) - adapter->link_active = 1; + /* + * These parameters control the automatic generation (Tx) and + * response (Rx) to Ethernet PAUSE frames. + * - High water mark should allow for at least two frames to be + * received after sending an XOFF. + * - Low water mark works best when it is very near the high water mark. + * This allows the receiver to restart by sending XON when it has + * drained a bit. Here we use an arbitary value of 1500 which will + * restart after one full frame is pulled from the buffer. There + * could be several smaller frames in the buffer and if so they will + * not trigger the XON until their total number reduces the buffer + * by 1500. + * - The pause time is fairly large at 1000 x 512ns = 512 usec. + */ + rx_buffer_size = ((E1000_READ_REG(&adapter->hw, PBA) & 0xffff) << 10 ); + + adapter->hw.fc_high_water = rx_buffer_size - + roundup2(adapter->hw.max_frame_size, 1024); + adapter->hw.fc_low_water = adapter->hw.fc_high_water - 1500; + if (adapter->hw.mac_type == em_80003es2lan) + adapter->hw.fc_pause_time = 0xFFFF; else - adapter->link_active = 0; + adapter->hw.fc_pause_time = 0x1000; + adapter->hw.fc_send_xon = TRUE; + adapter->hw.fc = em_fc_full; - if (adapter->link_active) { - em_get_speed_and_duplex(&adapter->hw, - &adapter->link_speed, - &adapter->link_duplex); - } else { - adapter->link_speed = 0; - adapter->link_duplex = 0; + if (em_init_hw(&adapter->hw) < 0) { + device_printf(dev, "Hardware Initialization Failed\n"); + return (EIO); } - return(0); + em_check_for_link(&adapter->hw); + + return (0); } /********************************************************************* @@ -1833,21 +2038,16 @@ em_hardware_init(struct adapter * adapter) * **********************************************************************/ static void -em_setup_interface(device_t dev, struct adapter * adapter) +em_setup_interface(device_t dev, struct adapter *adapter) { struct ifnet *ifp; INIT_DEBUGOUT("em_setup_interface: begin"); ifp = &adapter->interface_data.ac_if; -#if __FreeBSD_version >= 502000 - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); -#else - ifp->if_unit = adapter->unit; + ifp->if_unit = device_get_unit(dev); ifp->if_name = "em"; -#endif ifp->if_mtu = ETHERMTU; ifp->if_output = ether_output; - ifp->if_baudrate = 1000000000; ifp->if_init = em_init; ifp->if_softc = adapter; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; @@ -1856,59 +2056,52 @@ 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); -#else - ether_ifattach(ifp, adapter->interface_data.ac_enaddr); -#endif + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); + + ifp->if_capabilities = ifp->if_capenable = 0; if (adapter->hw.mac_type >= em_82543) { - ifp->if_capabilities = IFCAP_HWCSUM; - ifp->if_capenable = ifp->if_capabilities; + ifp->if_capabilities |= IFCAP_HWCSUM; + ifp->if_capenable |= IFCAP_HWCSUM; } - /* - * Tell the upper layer(s) we support long frames. - */ - ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); -#if __FreeBSD_version >= 500000 - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; -#endif - + /* + * Tell the upper layer(s) we support long frames. + */ + ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); - /* + /* * Specify the media types supported by this adapter and register * callbacks to update media and link information */ ifmedia_init(&adapter->media, IFM_IMASK, em_media_change, - em_media_status); - if (adapter->hw.media_type == em_media_type_fiber) { - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX, - 0, NULL); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, - 0, NULL); + em_media_status); + if ((adapter->hw.media_type == em_media_type_fiber) || + (adapter->hw.media_type == em_media_type_internal_serdes)) { + u_char fiber_type = IFM_1000_SX; /* default type; */ + + if (adapter->hw.mac_type == em_82545) + fiber_type = IFM_1000_LX; + ifmedia_add(&adapter->media, IFM_ETHER | fiber_type | IFM_FDX, + 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | fiber_type, 0, NULL); } else { ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX, - 0, NULL); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, + ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); -#if __FreeBSD_version < 500000 - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX, - 0, NULL); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL); -#else - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX, + ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); -#endif + if (adapter->hw.phy_type != em_phy_ife) { + ifmedia_add(&adapter->media, + IFM_ETHER | IFM_1000_TX | IFM_FDX, 0, NULL); + ifmedia_add(&adapter->media, + IFM_ETHER | IFM_1000_TX, 0, NULL); + } } ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); - - return; } @@ -1916,102 +2109,210 @@ 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)) + uint16_t phy_tmp; + + if (adapter->link_active || (adapter->hw.phy_type != em_phy_igp) || + adapter->hw.autoneg == 0 || + (adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL) == 0) 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) && + 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; + &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; +} + + +/* + * Manage DMA'able memory. + */ +static void +em_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + if (error) + return; + *(bus_addr_t *) arg = segs[0].ds_addr; +} + +static int +em_dma_malloc(struct adapter *adapter, bus_size_t size, struct em_dma_alloc *dma, + int mapflags) +{ + int error; + + error = bus_dma_tag_create(NULL, /* parent */ + EM_DBA_ALIGN, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + size, /* maxsize */ + 1, /* nsegments */ + size, /* maxsegsize */ + 0, /* flags */ + &dma->dma_tag); + if (error) { + device_printf(adapter->dev, "%s: bus_dma_tag_create failed: %d\n", + __func__, error); + goto fail_0; + } + + error = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr, + BUS_DMA_NOWAIT, &dma->dma_map); + if (error) { + device_printf(adapter->dev, "%s: bus_dmammem_alloc(%llu) failed: %d\n", + __func__, (unsigned long long)size, error); + goto fail_2; + } + + dma->dma_paddr = 0; + error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, + size, em_dmamap_cb, &dma->dma_paddr, mapflags | BUS_DMA_NOWAIT); + if (error || dma->dma_paddr == 0) { + device_printf(adapter->dev, "%s: bus_dmamap_load failed: %d\n", + __func__, error); + goto fail_3; + } - return; + return (0); + +fail_3: + bus_dmamap_unload(dma->dma_tag, dma->dma_map); +fail_2: + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); + bus_dma_tag_destroy(dma->dma_tag); +fail_0: + dma->dma_map = NULL; + dma->dma_tag = NULL; + + return (error); +} + +static void +em_dma_free(struct adapter *adapter, struct em_dma_alloc *dma) +{ + if (dma->dma_tag == NULL) + return; + if (dma->dma_map != NULL) { + bus_dmamap_sync(dma->dma_tag, dma->dma_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dma->dma_tag, dma->dma_map); + bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); + dma->dma_map = NULL; + } + bus_dma_tag_destroy(dma->dma_tag); + dma->dma_tag = NULL; } /********************************************************************* * - * Allocate memory for tx_buffer structures. The tx_buffer stores all - * the information needed to transmit a packet on the wire. + * Allocate memory for tx_buffer structures. The tx_buffer stores all + * the information needed to transmit a packet on the wire. * **********************************************************************/ static int -em_allocate_transmit_structures(struct adapter * adapter) +em_allocate_transmit_structures(struct adapter *adapter) { - if (!(adapter->tx_buffer_area = - (struct em_buffer *) malloc(sizeof(struct em_buffer) * - adapter->num_tx_desc, M_DEVBUF, - M_NOWAIT))) { - printf("em%d: Unable to allocate tx_buffer memory\n", - adapter->unit); - return ENOMEM; + adapter->tx_buffer_area = malloc(sizeof(struct em_buffer) * + adapter->num_tx_desc, M_DEVBUF, M_NOWAIT); + if (adapter->tx_buffer_area == NULL) { + device_printf(adapter->dev, "Unable to allocate tx_buffer memory\n"); + return (ENOMEM); } - bzero(adapter->tx_buffer_area, - sizeof(struct em_buffer) * adapter->num_tx_desc); + bzero(adapter->tx_buffer_area, sizeof(struct em_buffer) * adapter->num_tx_desc); - return 0; + return (0); } /********************************************************************* * - * Allocate and initialize transmit structures. + * Allocate and initialize transmit structures. * **********************************************************************/ static int -em_setup_transmit_structures(struct adapter * adapter) +em_setup_transmit_structures(struct adapter *adapter) { - if (em_allocate_transmit_structures(adapter)) - return ENOMEM; + device_t dev = adapter->dev; + struct em_buffer *tx_buffer; + bus_size_t size; + int error, i; - bzero((void *) adapter->tx_desc_base, - (sizeof(struct em_tx_desc)) * adapter->num_tx_desc); - - adapter->next_avail_tx_desc = 0; + /* + * Setup DMA descriptor areas. + */ + size = roundup2(adapter->hw.max_frame_size, MCLBYTES); + if ((error = bus_dma_tag_create(NULL, /* parent */ + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + size, /* maxsize */ + EM_MAX_SCATTER, /* nsegments */ + size, /* maxsegsize */ + 0, /* flags */ + &adapter->txtag)) != 0) { + device_printf(dev, "Unable to allocate TX DMA tag\n"); + goto fail; + } + + if ((error = em_allocate_transmit_structures(adapter)) != 0) + goto fail; + + bzero(adapter->tx_desc_base, (sizeof(struct em_tx_desc)) * adapter->num_tx_desc); + tx_buffer = adapter->tx_buffer_area; + for (i = 0; i < adapter->num_tx_desc; i++) { + error = bus_dmamap_create(adapter->txtag, 0, &tx_buffer->map); + if (error != 0) { + device_printf(dev, "Unable to create TX DMA map\n"); + goto fail; + } + tx_buffer++; + } + + adapter->next_avail_tx_desc = 0; adapter->oldest_used_tx_desc = 0; /* Set number of descriptors available */ @@ -2019,8 +2320,14 @@ em_setup_transmit_structures(struct adapter * adapter) /* Set checksum context */ adapter->active_checksum_context = OFFLOAD_NONE; + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + return (0); - return 0; +fail: + em_free_transmit_structures(adapter); + return (error); } /********************************************************************* @@ -2029,31 +2336,27 @@ em_setup_transmit_structures(struct adapter * adapter) * **********************************************************************/ static void -em_initialize_transmit_unit(struct adapter * adapter) +em_initialize_transmit_unit(struct adapter *adapter) { - u_int32_t reg_tctl; - u_int32_t reg_tipg = 0; - u_int64_t tdba = vtophys((vm_offset_t)adapter->tx_desc_base); - - INIT_DEBUGOUT("em_initialize_transmit_unit: begin"); + uint32_t reg_tctl, reg_tarc; + uint32_t reg_tipg = 0; + uint64_t bus_addr; + INIT_DEBUGOUT("em_initialize_transmit_unit: begin"); /* Setup the Base and Length of the Tx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, TDBAL, - (tdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32)); - E1000_WRITE_REG(&adapter->hw, TDLEN, - adapter->num_tx_desc * - sizeof(struct em_tx_desc)); + bus_addr = adapter->txdma.dma_paddr; + E1000_WRITE_REG(&adapter->hw, TDLEN, + adapter->num_tx_desc * sizeof(struct em_tx_desc)); + E1000_WRITE_REG(&adapter->hw, TDBAH, (uint32_t)(bus_addr >> 32)); + E1000_WRITE_REG(&adapter->hw, TDBAL, (uint32_t)bus_addr); /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG(&adapter->hw, TDH, 0); E1000_WRITE_REG(&adapter->hw, TDT, 0); + E1000_WRITE_REG(&adapter->hw, TDH, 0); - HW_DEBUGOUT2("Base = %x, Length = %x\n", - E1000_READ_REG(&adapter->hw, TDBAL), - E1000_READ_REG(&adapter->hw, TDLEN)); - + HW_DEBUGOUT2("Base = %x, Length = %x\n", E1000_READ_REG(&adapter->hw, TDBAL), + E1000_READ_REG(&adapter->hw, TDLEN)); /* Set the default values for the Tx Inter Packet Gap timer */ switch (adapter->hw.mac_type) { @@ -2063,8 +2366,14 @@ em_initialize_transmit_unit(struct adapter * adapter) reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; break; + case em_80003es2lan: + reg_tipg = DEFAULT_82543_TIPG_IPGR1; + reg_tipg |= DEFAULT_80003ES2LAN_TIPG_IPGR2 << + E1000_TIPG_IPGR2_SHIFT; + break; default: - if (adapter->hw.media_type == em_media_type_fiber) + if ((adapter->hw.media_type == em_media_type_fiber) || + (adapter->hw.media_type == em_media_type_internal_serdes)) reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER; else reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER; @@ -2077,25 +2386,42 @@ em_initialize_transmit_unit(struct adapter * adapter) if(adapter->hw.mac_type >= em_82540) E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay.value); + /* Do adapter specific tweaks before we enable the transmitter. */ + if (adapter->hw.mac_type == em_82571 || adapter->hw.mac_type == em_82572) { + reg_tarc = E1000_READ_REG(&adapter->hw, TARC0); + reg_tarc |= (1 << 25); + E1000_WRITE_REG(&adapter->hw, TARC0, reg_tarc); + reg_tarc = E1000_READ_REG(&adapter->hw, TARC1); + reg_tarc |= (1 << 25); + reg_tarc &= ~(1 << 28); + E1000_WRITE_REG(&adapter->hw, TARC1, reg_tarc); + } else if (adapter->hw.mac_type == em_80003es2lan) { + reg_tarc = E1000_READ_REG(&adapter->hw, TARC0); + reg_tarc |= 1; + E1000_WRITE_REG(&adapter->hw, TARC0, reg_tarc); + reg_tarc = E1000_READ_REG(&adapter->hw, TARC1); + reg_tarc |= 1; + E1000_WRITE_REG(&adapter->hw, TARC1, reg_tarc); + } + /* Program the Transmit Control Register */ reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); - if (adapter->hw.mac_type >= em_82573) + if (adapter->hw.mac_type >= em_82571) reg_tctl |= E1000_TCTL_MULR; - if (adapter->link_duplex == 1) { + if (adapter->link_duplex == FULL_DUPLEX) { reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; } else { reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; } + /* This write will effectively turn on the transmit unit. */ E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl); - /* Setup Transmit Descriptor Settings for this adapter */ + /* Setup Transmit Descriptor Settings for this adapter */ adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS; if (adapter->tx_int_delay.value > 0) adapter->txd_cmd |= E1000_TXD_CMD_IDE; - - return; } /********************************************************************* @@ -2104,26 +2430,41 @@ em_initialize_transmit_unit(struct adapter * adapter) * **********************************************************************/ static void -em_free_transmit_structures(struct adapter * adapter) +em_free_transmit_structures(struct adapter *adapter) { - struct em_buffer *tx_buffer; - int i; + struct em_buffer *tx_buffer; + int i; INIT_DEBUGOUT("free_transmit_structures: begin"); if (adapter->tx_buffer_area != NULL) { tx_buffer = adapter->tx_buffer_area; for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { - if (tx_buffer->m_head != NULL) + if (tx_buffer->m_head != NULL) { + bus_dmamap_sync(adapter->txtag, tx_buffer->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(adapter->txtag, + tx_buffer->map); m_freem(tx_buffer->m_head); - tx_buffer->m_head = NULL; + tx_buffer->m_head = NULL; + } else if (tx_buffer->map != NULL) + bus_dmamap_unload(adapter->txtag, + tx_buffer->map); + if (tx_buffer->map != NULL) { + bus_dmamap_destroy(adapter->txtag, + tx_buffer->map); + tx_buffer->map = NULL; + } } } if (adapter->tx_buffer_area != NULL) { free(adapter->tx_buffer_area, M_DEVBUF); adapter->tx_buffer_area = NULL; } - return; + if (adapter->txtag != NULL) { + bus_dma_tag_destroy(adapter->txtag); + adapter->txtag = NULL; + } } /********************************************************************* @@ -2134,10 +2475,8 @@ em_free_transmit_structures(struct adapter * adapter) * **********************************************************************/ static void -em_transmit_checksum_setup(struct adapter * adapter, - struct mbuf *mp, - u_int32_t *txd_upper, - u_int32_t *txd_lower) +em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, + uint32_t *txd_upper, uint32_t *txd_lower) { struct em_context_desc *TXD; struct em_buffer *tx_buffer; @@ -2179,27 +2518,27 @@ em_transmit_checksum_setup(struct adapter * adapter, TXD = (struct em_context_desc *) &adapter->tx_desc_base[curr_txd]; TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN; - TXD->lower_setup.ip_fields.ipcso = + TXD->lower_setup.ip_fields.ipcso = ETHER_HDR_LEN + offsetof(struct ip, ip_sum); - TXD->lower_setup.ip_fields.ipcse = - ETHER_HDR_LEN + sizeof(struct ip) - 1; + TXD->lower_setup.ip_fields.ipcse = + htole16(ETHER_HDR_LEN + sizeof(struct ip) - 1); - TXD->upper_setup.tcp_fields.tucss = + TXD->upper_setup.tcp_fields.tucss = ETHER_HDR_LEN + sizeof(struct ip); - TXD->upper_setup.tcp_fields.tucse = 0; + TXD->upper_setup.tcp_fields.tucse = htole16(0); if (adapter->active_checksum_context == OFFLOAD_TCP_IP) { - TXD->upper_setup.tcp_fields.tucso = - ETHER_HDR_LEN + sizeof(struct ip) + + TXD->upper_setup.tcp_fields.tucso = + ETHER_HDR_LEN + sizeof(struct ip) + offsetof(struct tcphdr, th_sum); } else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) { - TXD->upper_setup.tcp_fields.tucso = - ETHER_HDR_LEN + sizeof(struct ip) + + TXD->upper_setup.tcp_fields.tucso = + ETHER_HDR_LEN + sizeof(struct ip) + offsetof(struct udphdr, uh_sum); } - TXD->tcp_seg_setup.data = 0; - TXD->cmd_and_length = (adapter->txd_cmd | E1000_TXD_CMD_DEXT); + TXD->tcp_seg_setup.data = htole32(0); + TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT); tx_buffer->m_head = NULL; @@ -2208,8 +2547,6 @@ em_transmit_checksum_setup(struct adapter * adapter, adapter->num_tx_desc_avail--; adapter->next_avail_tx_desc = curr_txd; - - return; } /********************************************************************** @@ -2220,60 +2557,69 @@ em_transmit_checksum_setup(struct adapter * adapter, * **********************************************************************/ static void -em_clean_transmit_interrupts(struct adapter * adapter) +em_txeof(struct adapter *adapter) { - int s; - int i, num_avail; + int s; + int i, num_avail; struct em_buffer *tx_buffer; struct em_tx_desc *tx_desc; struct ifnet *ifp = &adapter->interface_data.ac_if; - if (adapter->num_tx_desc_avail == adapter->num_tx_desc) - return; + s = splimp(); - s = splimp(); - num_avail = adapter->num_tx_desc_avail; + if (adapter->num_tx_desc_avail == adapter->num_tx_desc) + goto out; + + num_avail = adapter->num_tx_desc_avail; i = adapter->oldest_used_tx_desc; tx_buffer = &adapter->tx_buffer_area[i]; tx_desc = &adapter->tx_desc_base[i]; + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_POSTREAD); while (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) { tx_desc->upper.data = 0; - num_avail++; + num_avail++; if (tx_buffer->m_head) { ifp->if_opackets++; + bus_dmamap_sync(adapter->txtag, tx_buffer->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(adapter->txtag, tx_buffer->map); + m_freem(tx_buffer->m_head); tx_buffer->m_head = NULL; } - - if (++i == adapter->num_tx_desc) - i = 0; + + if (++i == adapter->num_tx_desc) + i = 0; tx_buffer = &adapter->tx_buffer_area[i]; tx_desc = &adapter->tx_desc_base[i]; - } + } + bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); adapter->oldest_used_tx_desc = i; - /* - * If we have enough room, clear IFF_OACTIVE to tell the stack - * that it is OK to send packets. - * If there are no pending descriptors, clear the timeout. Otherwise, - * if some descriptors have been freed, restart the timeout. - */ - if (num_avail > EM_TX_CLEANUP_THRESHOLD) { - ifp->if_flags &= ~IFF_OACTIVE; - if (num_avail == adapter->num_tx_desc) - ifp->if_timer = 0; - else if (num_avail == adapter->num_tx_desc_avail) - ifp->if_timer = EM_TX_TIMEOUT; - } - adapter->num_tx_desc_avail = num_avail; - splx(s); - return; + /* + * If we have enough room, clear IFF_OACTIVE to tell the stack + * that it is OK to send packets. + * If there are no pending descriptors, clear the timeout. Otherwise, + * if some descriptors have been freed, restart the timeout. + */ + if (num_avail > EM_TX_CLEANUP_THRESHOLD) { + ifp->if_flags &= ~IFF_OACTIVE; + if (num_avail == adapter->num_tx_desc) + ifp->if_timer = 0; + else if (num_avail != adapter->num_tx_desc_avail) + ifp->if_timer = EM_TX_TIMEOUT; + } + adapter->num_tx_desc_avail = num_avail; +out: + splx(s); } /********************************************************************* @@ -2282,144 +2628,194 @@ em_clean_transmit_interrupts(struct adapter * adapter) * **********************************************************************/ static int -em_get_buf(int i, struct adapter *adapter, - struct mbuf *nmp) +em_get_buf(struct adapter *adapter, int i) { - register struct mbuf *mp = nmp; - struct ifnet *ifp; + struct mbuf *m; + bus_dma_segment_t segs[1]; + bus_dmamap_t map; + struct em_encap_arg ea; + struct em_buffer *rx_buffer; + int error, nsegs; - ifp = &adapter->interface_data.ac_if; - - if (mp == NULL) { - MGETHDR(mp, M_DONTWAIT, MT_DATA); - if (mp == NULL) { - adapter->mbuf_alloc_failed++; - return(ENOBUFS); - } - MCLGET(mp, M_DONTWAIT); - if ((mp->m_flags & M_EXT) == 0) { - m_freem(mp); - adapter->mbuf_cluster_failed++; - return(ENOBUFS); - } - mp->m_len = mp->m_pkthdr.len = MCLBYTES; - } else { - mp->m_len = mp->m_pkthdr.len = MCLBYTES; - mp->m_data = mp->m_ext.ext_buf; - mp->m_next = NULL; + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + adapter->mbuf_cluster_failed++; + return (ENOBUFS); } + m->m_len = m->m_pkthdr.len = MCLBYTES; + if (adapter->hw.max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + m_adj(m, ETHER_ALIGN); - if (ifp->if_mtu <= ETHERMTU) { - m_adj(mp, ETHER_ALIGN); + /* + * Using memory from the mbuf cluster pool, invoke the + * bus_dma machinery to arrange the memory mapping. + */ + ea.segs = segs; + error = bus_dmamap_load_mbuf(adapter->rxtag, adapter->rx_sparemap, + m, em_encap_cb, &ea, BUS_DMA_NOWAIT); + if (error != 0) { + m_free(m); + return (error); } - - adapter->rx_buffer_area[i].m_head = mp; - adapter->rx_desc_base[i].buffer_addr = - vtophys(mtod(mp, vm_offset_t)); + nsegs = ea.nsegs; + /* If nsegs is wrong then the stack is corrupt. */ + KASSERT(nsegs == 1, ("Too many segments returned!")); + + rx_buffer = &adapter->rx_buffer_area[i]; + if (rx_buffer->m_head != NULL) + bus_dmamap_unload(adapter->rxtag, rx_buffer->map); + + map = rx_buffer->map; + rx_buffer->map = adapter->rx_sparemap; + adapter->rx_sparemap = map; + bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD); + rx_buffer->m_head = m; + + adapter->rx_desc_base[i].buffer_addr = htole64(segs[0].ds_addr); - return(0); + return (0); } /********************************************************************* * - * Allocate memory for rx_buffer structures. Since we use one - * rx_buffer per received packet, the maximum number of rx_buffer's - * that we'll need is equal to the number of receive descriptors + * Allocate memory for rx_buffer structures. Since we use one + * rx_buffer per received packet, the maximum number of rx_buffer's + * that we'll need is equal to the number of receive descriptors * that we've allocated. * **********************************************************************/ static int -em_allocate_receive_structures(struct adapter * adapter) +em_allocate_receive_structures(struct adapter *adapter) { - int i; + device_t dev = adapter->dev; + struct em_buffer *rx_buffer; + int i, error; - if (!(adapter->rx_buffer_area = - (struct em_buffer *) malloc(sizeof(struct em_buffer) * - adapter->num_rx_desc, M_DEVBUF, - M_NOWAIT))) { - printf("em%d: Unable to allocate rx_buffer memory\n", - adapter->unit); - return(ENOMEM); + adapter->rx_buffer_area = malloc(sizeof(struct em_buffer) * adapter->num_rx_desc, + M_DEVBUF, M_NOWAIT); + if (adapter->rx_buffer_area == NULL) { + device_printf(dev, "Unable to allocate rx_buffer memory\n"); + return (ENOMEM); } - bzero(adapter->rx_buffer_area, - sizeof(struct em_buffer) * adapter->num_rx_desc); + bzero(adapter->rx_buffer_area, sizeof(struct em_buffer) * adapter->num_rx_desc); - for (i = 0; i < adapter->num_rx_desc; i++) { - if (em_get_buf(i, adapter, NULL) == ENOBUFS) { - adapter->rx_buffer_area[i].m_head = NULL; - adapter->rx_desc_base[i].buffer_addr = 0; - return(ENOBUFS); + error = bus_dma_tag_create(NULL, /* parent */ + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MCLBYTES, /* maxsize */ + 1, /* nsegments */ + MCLBYTES, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + &adapter->rxtag); + if (error) { + device_printf(dev, "%s: bus_dma_tag_create failed %d\n", + __func__, error); + goto fail; + } + + error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT, + &adapter->rx_sparemap); + if (error) { + device_printf(dev, "%s: bus_dmamap_create failed: %d\n", + __func__, error); + goto fail; + } + rx_buffer = adapter->rx_buffer_area; + for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { + error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT, + &rx_buffer->map); + if (error) { + device_printf(dev, "%s: bus_dmamap_create failed: %d\n", + __func__, error); + goto fail; } } - return(0); + for (i = 0; i < adapter->num_rx_desc; i++) { + error = em_get_buf(adapter, i); + if (error) + goto fail; + } + bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + return (0); + +fail: + em_free_receive_structures(adapter); + return (error); } /********************************************************************* * * Allocate and initialize receive structures. - * + * **********************************************************************/ static int -em_setup_receive_structures(struct adapter * adapter) +em_setup_receive_structures(struct adapter *adapter) { - bzero((void *) adapter->rx_desc_base, - (sizeof(struct em_rx_desc)) * adapter->num_rx_desc); + int error; - if (em_allocate_receive_structures(adapter)) - return ENOMEM; + bzero(adapter->rx_desc_base, (sizeof(struct em_rx_desc)) * adapter->num_rx_desc); + + if ((error = em_allocate_receive_structures(adapter)) != 0) + return (error); /* Setup our descriptor pointers */ - adapter->next_rx_desc_to_check = 0; - return(0); + adapter->next_rx_desc_to_check = 0; + + return (0); } /********************************************************************* * * Enable receive unit. - * + * **********************************************************************/ static void -em_initialize_receive_unit(struct adapter * adapter) +em_initialize_receive_unit(struct adapter *adapter) { - u_int32_t reg_rctl; - u_int32_t reg_rxcsum; - struct ifnet *ifp; - u_int64_t rdba = vtophys((vm_offset_t)adapter->rx_desc_base); + struct ifnet *ifp = &adapter->interface_data.ac_if; + uint64_t bus_addr; + uint32_t reg_rctl; + uint32_t reg_rxcsum; INIT_DEBUGOUT("em_initialize_receive_unit: begin"); - ifp = &adapter->interface_data.ac_if; - - /* Make sure receives are disabled while setting up the descriptor ring */ + /* + * Make sure receives are disabled while setting + * up the descriptor ring + */ E1000_WRITE_REG(&adapter->hw, RCTL, 0); /* Set the Receive Delay Timer Register */ - E1000_WRITE_REG(&adapter->hw, RDTR, - adapter->rx_int_delay.value | E1000_RDT_FPDB); + E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay.value | E1000_RDT_FPDB); if(adapter->hw.mac_type >= em_82540) { E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay.value); - /* Set the interrupt throttling rate. Value is calculated - * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ -#define MAX_INTS_PER_SEC 8000 -#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) - E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR); - } + /* + * Set the interrupt throttling rate. Value is calculated + * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) + */ +#define MAX_INTS_PER_SEC 8000 +#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) + E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR); + } /* Setup the Base and Length of the Rx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, RDBAL, - (rdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); - E1000_WRITE_REG(&adapter->hw, RDLEN, - adapter->num_rx_desc * + bus_addr = adapter->rxdma.dma_paddr; + E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc * sizeof(struct em_rx_desc)); + E1000_WRITE_REG(&adapter->hw, RDBAH, (uint32_t)(bus_addr >> 32)); + E1000_WRITE_REG(&adapter->hw, RDBAL, (uint32_t)bus_addr); /* Setup the HW Rx Head and Tail Descriptor Pointers */ - E1000_WRITE_REG(&adapter->hw, RDH, 0); E1000_WRITE_REG(&adapter->hw, RDT, adapter->num_rx_desc - 1); + E1000_WRITE_REG(&adapter->hw, RDH, 0); /* Setup the Receive Control Register */ reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | @@ -2437,7 +2833,7 @@ em_initialize_receive_unit(struct adapter * adapter) break; case EM_RXBUFFER_4096: reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; - break; + break; case EM_RXBUFFER_8192: reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; break; @@ -2450,7 +2846,7 @@ em_initialize_receive_unit(struct adapter * adapter) reg_rctl |= E1000_RCTL_LPE; /* Enable 82543 Receive Checksum Offload for TCP and UDP */ - if ((adapter->hw.mac_type >= em_82543) && + if ((adapter->hw.mac_type >= em_82543) && (ifp->if_capenable & IFCAP_RXCSUM)) { reg_rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM); reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL); @@ -2458,9 +2854,7 @@ em_initialize_receive_unit(struct adapter * adapter) } /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - - return; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); } /********************************************************************* @@ -2471,24 +2865,43 @@ em_initialize_receive_unit(struct adapter * adapter) static void em_free_receive_structures(struct adapter *adapter) { - struct em_buffer *rx_buffer; - int i; + struct em_buffer *rx_buffer; + int i; INIT_DEBUGOUT("free_receive_structures: begin"); + if (adapter->rx_sparemap) { + bus_dmamap_destroy(adapter->rxtag, adapter->rx_sparemap); + adapter->rx_sparemap = NULL; + } if (adapter->rx_buffer_area != NULL) { rx_buffer = adapter->rx_buffer_area; for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { - if (rx_buffer->m_head != NULL) + if (rx_buffer->m_head != NULL) { + bus_dmamap_sync(adapter->rxtag, rx_buffer->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(adapter->rxtag, + rx_buffer->map); m_freem(rx_buffer->m_head); - rx_buffer->m_head = NULL; + rx_buffer->m_head = NULL; + } else if (rx_buffer->map != NULL) + bus_dmamap_unload(adapter->rxtag, + rx_buffer->map); + if (rx_buffer->map != NULL) { + bus_dmamap_destroy(adapter->rxtag, + rx_buffer->map); + rx_buffer->map = NULL; + } } } if (adapter->rx_buffer_area != NULL) { free(adapter->rx_buffer_area, M_DEVBUF); adapter->rx_buffer_area = NULL; } - return; + if (adapter->rxtag != NULL) { + bus_dma_tag_destroy(adapter->rxtag); + adapter->rxtag = NULL; + } } /********************************************************************* @@ -2502,84 +2915,81 @@ em_free_receive_structures(struct adapter *adapter) * *********************************************************************/ static void -em_process_receive_interrupts(struct adapter * adapter, int count) +em_rxeof(struct adapter *adapter, int count) { - struct ifnet *ifp; - struct mbuf *mp; -#if __FreeBSD_version < 500000 - struct ether_header *eh; -#endif - u_int8_t accept_frame = 0; - u_int8_t eop = 0; - u_int16_t len, desc_len, prev_len_adj; - int i; + struct ifnet *ifp; + struct mbuf *mp; + struct ether_header *eh; + uint8_t accept_frame = 0; + uint8_t eop = 0; + uint16_t len, desc_len, prev_len_adj; + int i; /* Pointer to the receive descriptor being examined. */ struct em_rx_desc *current_desc; + uint8_t status; ifp = &adapter->interface_data.ac_if; i = adapter->next_rx_desc_to_check; - current_desc = &adapter->rx_desc_base[i]; + current_desc = &adapter->rx_desc_base[i]; + bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, + BUS_DMASYNC_POSTREAD); - if (!((current_desc->status) & E1000_RXD_STAT_DD)) { + if (!((current_desc->status) & E1000_RXD_STAT_DD)) return; - } - while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) { - + while ((current_desc->status & E1000_RXD_STAT_DD) && + (count != 0) && + (ifp->if_flags & IFF_RUNNING)) { + mp = adapter->rx_buffer_area[i].m_head; + /* + * Can't defer bus_dmamap_sync(9) because TBI_ACCEPT + * needs to access the last received byte in the mbuf. + */ + bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map, + BUS_DMASYNC_POSTREAD); accept_frame = 1; prev_len_adj = 0; - desc_len = current_desc->length; - if (current_desc->status & E1000_RXD_STAT_EOP) { + desc_len = le16toh(current_desc->length); + status = current_desc->status; + if (status & E1000_RXD_STAT_EOP) { count--; eop = 1; if (desc_len < ETHER_CRC_LEN) { len = 0; prev_len_adj = ETHER_CRC_LEN - desc_len; - } - else { + } else len = desc_len - ETHER_CRC_LEN; - } } else { eop = 0; len = desc_len; } if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { - u_int8_t last_byte; - u_int32_t pkt_len = desc_len; + uint8_t last_byte; + uint32_t pkt_len = desc_len; if (adapter->fmp != NULL) - pkt_len += adapter->fmp->m_pkthdr.len; - - last_byte = *(mtod(mp, caddr_t) + desc_len - 1); + pkt_len += adapter->fmp->m_pkthdr.len; - if (TBI_ACCEPT(&adapter->hw, current_desc->status, - current_desc->errors, - pkt_len, last_byte)) { - em_tbi_adjust_stats(&adapter->hw, - &adapter->stats, - pkt_len, - adapter->hw.mac_addr); - if (len > 0) len--; - } - else { + last_byte = *(mtod(mp, caddr_t) + desc_len - 1); + if (TBI_ACCEPT(&adapter->hw, status, + current_desc->errors, pkt_len, last_byte)) { + em_tbi_adjust_stats(&adapter->hw, + &adapter->stats, pkt_len, + adapter->hw.mac_addr); + if (len > 0) + len--; + } else accept_frame = 0; - } } if (accept_frame) { - - if (em_get_buf(i, adapter, NULL) == ENOBUFS) { - adapter->dropped_pkts++; - em_get_buf(i, adapter, mp); - if (adapter->fmp != NULL) - m_freem(adapter->fmp); - adapter->fmp = NULL; - adapter->lmp = NULL; - break; + if (em_get_buf(adapter, i) != 0) { + ifp->if_iqdrops++; + goto discard; } /* Assign correct length to the current fragment */ @@ -2587,92 +2997,89 @@ em_process_receive_interrupts(struct adapter * adapter, int count) if (adapter->fmp == NULL) { mp->m_pkthdr.len = len; - adapter->fmp = mp; /* Store the first mbuf */ + adapter->fmp = mp; /* Store the first mbuf */ adapter->lmp = mp; } else { /* Chain mbuf's together */ mp->m_flags &= ~M_PKTHDR; - /* - * Adjust length of previous mbuf in chain if we - * received less than 4 bytes in the last descriptor. + /* + * Adjust length of previous mbuf in chain if + * we received less than 4 bytes in the last + * descriptor. */ if (prev_len_adj > 0) { adapter->lmp->m_len -= prev_len_adj; - adapter->fmp->m_pkthdr.len -= prev_len_adj; + adapter->fmp->m_pkthdr.len -= + prev_len_adj; } adapter->lmp->m_next = mp; adapter->lmp = adapter->lmp->m_next; adapter->fmp->m_pkthdr.len += len; } - if (eop) { - adapter->fmp->m_pkthdr.rcvif = ifp; + if (eop) { + adapter->fmp->m_pkthdr.rcvif = ifp; ifp->if_ipackets++; -#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 + 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 (status & E1000_RXD_STAT_VP) + VLAN_INPUT_TAG(eh, adapter->fmp, + (le16toh(current_desc->special) & + E1000_RXD_SPC_VLAN_MASK)); + else + ether_input(ifp, eh, adapter->fmp); - 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); -#endif - adapter->fmp = NULL; - adapter->lmp = NULL; - } + adapter->fmp = NULL; + adapter->lmp = NULL; + } } else { - adapter->dropped_pkts++; - em_get_buf(i, adapter, mp); - if (adapter->fmp != NULL) + ifp->if_ierrors++; +discard: + /* Reuse loaded DMA map and just update mbuf chain */ + mp = adapter->rx_buffer_area[i].m_head; + mp->m_len = mp->m_pkthdr.len = MCLBYTES; + mp->m_data = mp->m_ext.ext_buf; + mp->m_next = NULL; + if (adapter->hw.max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + m_adj(mp, ETHER_ALIGN); + if (adapter->fmp != NULL) { m_freem(adapter->fmp); - adapter->fmp = NULL; - adapter->lmp = NULL; + adapter->fmp = NULL; + adapter->lmp = NULL; + } } - /* Zero out the receive descriptors status */ + /* Zero out the receive descriptors status. */ current_desc->status = 0; - - /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ - E1000_WRITE_REG(&adapter->hw, RDT, i); + bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - /* Advance our pointers to the next descriptor */ - if (++i == adapter->num_rx_desc) { - i = 0; - current_desc = adapter->rx_desc_base; - } else - current_desc++; + /* Advance our pointers to the next descriptor. */ + if (++i == adapter->num_rx_desc) + i = 0; + current_desc = &adapter->rx_desc_base[i]; } adapter->next_rx_desc_to_check = i; - return; + + /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ + if (--i < 0) + i = adapter->num_rx_desc - 1; + E1000_WRITE_REG(&adapter->hw, RDT, i); } /********************************************************************* * - * Verify that the hardware indicated that the checksum is valid. + * Verify that the hardware indicated that the checksum is valid. * Inform the stack about the status of checksum so that stack * doesn't spend time verifying the checksum. * *********************************************************************/ static void -em_receive_checksum(struct adapter *adapter, - struct em_rx_desc *rx_desc, +em_receive_checksum(struct adapter *adapter, struct em_rx_desc *rx_desc, struct mbuf *mp) { /* 82543 or newer only */ @@ -2696,19 +3103,17 @@ em_receive_checksum(struct adapter *adapter, } if (rx_desc->status & E1000_RXD_STAT_TCPCS) { - /* Did it pass? */ + /* Did it pass? */ if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) { - mp->m_pkthdr.csum_flags |= + mp->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); mp->m_pkthdr.csum_data = htons(0xffff); } } - - return; } -static void +static void em_enable_vlans(struct adapter *adapter) { uint32_t ctrl; @@ -2716,41 +3121,48 @@ em_enable_vlans(struct adapter *adapter) E1000_WRITE_REG(&adapter->hw, VET, ETHERTYPE_VLAN); ctrl = E1000_READ_REG(&adapter->hw, CTRL); - ctrl |= E1000_CTRL_VME; + ctrl |= E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); +} - return; +static void +em_disable_vlans(struct adapter *adapter) +{ + uint32_t ctrl; + + ctrl = E1000_READ_REG(&adapter->hw, CTRL); + ctrl &= ~E1000_CTRL_VME; + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); } static void -em_enable_intr(struct adapter * adapter) +em_enable_intr(struct adapter *adapter) { E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK)); - return; } static void em_disable_intr(struct adapter *adapter) { /* - * The first version of 82542 had an errata where when link was forced it - * would stay up even up even if the cable was disconnected. Sequence errors - * were used to detect the disconnect and then the driver would unforce the link. - * This code in the in the ISR. For this to work correctly the Sequence error - * interrupt had to be enabled all the time. + * The first version of 82542 had an errata where when link was forced + * it would stay up even up even if the cable was disconnected. + * Sequence errors were used to detect the disconnect and then the + * driver would unforce the link. This code in the in the ISR. For this + * to work correctly the Sequence error interrupt had to be enabled + * all the time. */ if (adapter->hw.mac_type == em_82542_rev2_0) - E1000_WRITE_REG(&adapter->hw, IMC, - (0xffffffff & ~E1000_IMC_RXSEQ)); + E1000_WRITE_REG(&adapter->hw, IMC, + (0xffffffff & ~E1000_IMC_RXSEQ)); else - E1000_WRITE_REG(&adapter->hw, IMC, - 0xffffffff); - return; + E1000_WRITE_REG(&adapter->hw, IMC, + 0xffffffff); } static int -em_is_valid_ether_addr(u_int8_t *addr) +em_is_valid_ether_addr(uint8_t *addr) { char zero_addr[6] = { 0, 0, 0, 0, 0, 0 }; @@ -2758,114 +3170,90 @@ em_is_valid_ether_addr(u_int8_t *addr) return (FALSE); } - return(TRUE); + return (TRUE); } -void -em_write_pci_cfg(struct em_hw *hw, - uint32_t reg, - uint16_t *value) +void +em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t *value) { - pci_write_config(((struct em_osdep *)hw->back)->dev, reg, - *value, 2); + pci_write_config(((struct em_osdep *)hw->back)->dev, reg, *value, 2); } -void -em_read_pci_cfg(struct em_hw *hw, uint32_t reg, - uint16_t *value) +void +em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t *value) { - *value = pci_read_config(((struct em_osdep *)hw->back)->dev, - reg, 2); - return; + *value = pci_read_config(((struct em_osdep *)hw->back)->dev, reg, 2); } void em_pci_set_mwi(struct em_hw *hw) { - pci_write_config(((struct em_osdep *)hw->back)->dev, - PCIR_COMMAND, - (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); - return; + pci_write_config(((struct em_osdep *)hw->back)->dev, PCIR_COMMAND, + (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); } void em_pci_clear_mwi(struct em_hw *hw) { - pci_write_config(((struct em_osdep *)hw->back)->dev, - PCIR_COMMAND, - (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2); - return; -} - -uint32_t -em_io_read(struct em_hw *hw, unsigned long port) -{ - return(inl(port)); -} - -void -em_io_write(struct em_hw *hw, unsigned long port, uint32_t value) -{ - outl(port, value); - return; + pci_write_config(((struct em_osdep *)hw->back)->dev, PCIR_COMMAND, + (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2); } /********************************************************************* -* 82544 Coexistence issue workaround. +* 82544 Coexistence issue workaround. * There are 2 issues. -* 1. Transmit Hang issue. +* 1. Transmit Hang issue. * To detect this issue, following equation can be used... -* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. -* If SUM[3:0] is in between 1 to 4, we will have this issue. +* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. +* If SUM[3:0] is in between 1 to 4, we will have this issue. * -* 2. DAC issue. +* 2. DAC issue. * To detect this issue, following equation can be used... -* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. -* If SUM[3:0] is in between 9 to c, we will have this issue. +* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. +* If SUM[3:0] is in between 9 to c, we will have this issue. * * * WORKAROUND: -* Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC) +* Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC) * *** *********************************************************************/ -static u_int32_t -em_fill_descriptors (u_int64_t address, - u_int32_t length, - PDESC_ARRAY desc_array) +static uint32_t +em_fill_descriptors (bus_addr_t address, uint32_t length, + PDESC_ARRAY desc_array) { /* Since issue is sensitive to length and address.*/ /* Let us first check the address...*/ - u_int32_t safe_terminator; + uint32_t safe_terminator; if (length <= 4) { desc_array->descriptor[0].address = address; - desc_array->descriptor[0].length = length; - desc_array->elements = 1; - return desc_array->elements; - } - safe_terminator = (u_int32_t)((((u_int32_t)address & 0x7) + (length & 0xF)) & 0xF); - /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */ + desc_array->descriptor[0].length = length; + desc_array->elements = 1; + return (desc_array->elements); + } + safe_terminator = (uint32_t)((((uint32_t)address & 0x7) + (length & 0xF)) & 0xF); + /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */ if (safe_terminator == 0 || - (safe_terminator > 4 && - safe_terminator < 9) || - (safe_terminator > 0xC && - safe_terminator <= 0xF)) { - desc_array->descriptor[0].address = address; - desc_array->descriptor[0].length = length; - desc_array->elements = 1; - return desc_array->elements; - } - + (safe_terminator > 4 && + safe_terminator < 9) || + (safe_terminator > 0xC && + safe_terminator <= 0xF)) { + desc_array->descriptor[0].address = address; + desc_array->descriptor[0].length = length; + desc_array->elements = 1; + return (desc_array->elements); + } + desc_array->descriptor[0].address = address; - desc_array->descriptor[0].length = length - 4; - desc_array->descriptor[1].address = address + (length - 4); - desc_array->descriptor[1].length = 4; - desc_array->elements = 2; - return desc_array->elements; + desc_array->descriptor[0].length = length - 4; + desc_array->descriptor[1].address = address + (length - 4); + desc_array->descriptor[1].length = 4; + desc_array->elements = 2; + return (desc_array->elements); } /********************************************************************** * - * Update the board statistics counters. + * Update the board statistics counters. * **********************************************************************/ static void @@ -2907,7 +3295,7 @@ em_update_stats_counters(struct adapter *adapter) /* For the 64-bit byte counters the low dword must be read first. */ /* Both registers clear on the read of the high dword */ - adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL); + adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL); adapter->stats.gorch += E1000_READ_REG(&adapter->hw, GORCH); adapter->stats.gotcl += E1000_READ_REG(&adapter->hw, GOTCL); adapter->stats.gotch += E1000_READ_REG(&adapter->hw, GOTCH); @@ -2935,39 +3323,25 @@ em_update_stats_counters(struct adapter *adapter) adapter->stats.bptc += E1000_READ_REG(&adapter->hw, BPTC); if (adapter->hw.mac_type >= em_82543) { - adapter->stats.algnerrc += - E1000_READ_REG(&adapter->hw, ALGNERRC); - adapter->stats.rxerrc += - E1000_READ_REG(&adapter->hw, RXERRC); - adapter->stats.tncrs += - E1000_READ_REG(&adapter->hw, TNCRS); - adapter->stats.cexterr += - E1000_READ_REG(&adapter->hw, CEXTERR); - adapter->stats.tsctc += - E1000_READ_REG(&adapter->hw, TSCTC); - adapter->stats.tsctfc += - E1000_READ_REG(&adapter->hw, TSCTFC); + adapter->stats.algnerrc += E1000_READ_REG(&adapter->hw, ALGNERRC); + adapter->stats.rxerrc += E1000_READ_REG(&adapter->hw, RXERRC); + adapter->stats.tncrs += E1000_READ_REG(&adapter->hw, TNCRS); + adapter->stats.cexterr += E1000_READ_REG(&adapter->hw, CEXTERR); + adapter->stats.tsctc += E1000_READ_REG(&adapter->hw, TSCTC); + adapter->stats.tsctfc += E1000_READ_REG(&adapter->hw, TSCTFC); } ifp = &adapter->interface_data.ac_if; - /* Fill out the OS statistics structure */ - ifp->if_ibytes = adapter->stats.gorcl; - ifp->if_obytes = adapter->stats.gotcl; - ifp->if_imcasts = adapter->stats.mprc; ifp->if_collisions = adapter->stats.colc; /* Rx Errors */ - ifp->if_ierrors = - adapter->dropped_pkts + - adapter->stats.rxerrc + - adapter->stats.crcerrs + - adapter->stats.algnerrc + - adapter->stats.rlec + adapter->stats.rnbc + - adapter->stats.mpc + adapter->stats.cexterr; + ifp->if_ierrors = adapter->stats.rxerrc + adapter->stats.crcerrs + + adapter->stats.algnerrc + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.mpc + adapter->stats.cexterr; /* Tx Errors */ - ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol; - + ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol + + adapter->watchdog_events; } @@ -2981,98 +3355,93 @@ em_update_stats_counters(struct adapter *adapter) static void em_print_debug_info(struct adapter *adapter) { - int unit = adapter->unit; + device_t dev = adapter->dev; uint8_t *hw_addr = adapter->hw.hw_addr; - printf("em%d: Adapter hardware address = %p \n", unit, hw_addr); - printf("em%d:CTRL = 0x%x\n", unit, - E1000_READ_REG(&adapter->hw, CTRL)); - printf("em%d:RCTL = 0x%x PS=(0x8402)\n", unit, - E1000_READ_REG(&adapter->hw, RCTL)); - printf("em%d:tx_int_delay = %d, tx_abs_int_delay = %d\n", unit, - E1000_READ_REG(&adapter->hw, TIDV), - E1000_READ_REG(&adapter->hw, TADV)); - printf("em%d:rx_int_delay = %d, rx_abs_int_delay = %d\n", unit, - E1000_READ_REG(&adapter->hw, RDTR), - E1000_READ_REG(&adapter->hw, RADV)); - printf("em%d: fifo workaround = %lld, fifo_reset = %lld\n", unit, - (long long)adapter->tx_fifo_wrk_cnt, - (long long)adapter->tx_fifo_reset_cnt); - 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: Num Tx descriptors avail = %d\n", unit, - adapter->num_tx_desc_avail); - 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 mbuf cluster failed = %ld\n", unit, - adapter->mbuf_cluster_failed); - printf("em%d: Driver dropped packets = %ld\n", unit, - adapter->dropped_pkts); - - return; + device_printf(dev, "Adapter hardware address = %p \n", hw_addr); + device_printf(dev, "CTRL = 0x%x RCTL = 0x%x \n", + E1000_READ_REG(&adapter->hw, CTRL), + E1000_READ_REG(&adapter->hw, RCTL)); + device_printf(dev, "Packet buffer = Tx=%dk Rx=%dk \n", + ((E1000_READ_REG(&adapter->hw, PBA) & 0xffff0000) >> 16),\ + (E1000_READ_REG(&adapter->hw, PBA) & 0xffff) ); + device_printf(dev, "Flow control watermarks high = %d low = %d\n", + adapter->hw.fc_high_water, + adapter->hw.fc_low_water); + device_printf(dev, "tx_int_delay = %d, tx_abs_int_delay = %d\n", + E1000_READ_REG(&adapter->hw, TIDV), + E1000_READ_REG(&adapter->hw, TADV)); + device_printf(dev, "rx_int_delay = %d, rx_abs_int_delay = %d\n", + E1000_READ_REG(&adapter->hw, RDTR), + E1000_READ_REG(&adapter->hw, RADV)); + device_printf(dev, "fifo workaround = %lld, fifo_reset_count = %lld\n", + (long long)adapter->tx_fifo_wrk_cnt, + (long long)adapter->tx_fifo_reset_cnt); + device_printf(dev, "hw tdh = %d, hw tdt = %d\n", + E1000_READ_REG(&adapter->hw, TDH), + E1000_READ_REG(&adapter->hw, TDT)); + device_printf(dev, "Num Tx descriptors avail = %d\n", + adapter->num_tx_desc_avail); + device_printf(dev, "Tx Descriptors not avail1 = %ld\n", + adapter->no_tx_desc_avail1); + device_printf(dev, "Tx Descriptors not avail2 = %ld\n", + adapter->no_tx_desc_avail2); + device_printf(dev, "Std mbuf failed = %ld\n", + adapter->mbuf_alloc_failed); + device_printf(dev, "Std mbuf cluster failed = %ld\n", + adapter->mbuf_cluster_failed); } static void em_print_hw_stats(struct adapter *adapter) { - int unit = adapter->unit; - - printf("em%d: Excessive collisions = %lld\n", unit, - (long long)adapter->stats.ecol); - printf("em%d: Symbol errors = %lld\n", unit, - (long long)adapter->stats.symerrs); - printf("em%d: Sequence errors = %lld\n", unit, - (long long)adapter->stats.sec); - printf("em%d: Defer count = %lld\n", unit, - (long long)adapter->stats.dc); + device_t dev = adapter->dev; - printf("em%d: Missed Packets = %lld\n", unit, - (long long)adapter->stats.mpc); - printf("em%d: Receive No Buffers = %lld\n", unit, - (long long)adapter->stats.rnbc); - printf("em%d: Receive length errors = %lld\n", unit, - (long long)adapter->stats.rlec); - printf("em%d: Receive errors = %lld\n", unit, - (long long)adapter->stats.rxerrc); - printf("em%d: Crc errors = %lld\n", unit, - (long long)adapter->stats.crcerrs); - printf("em%d: Alignment errors = %lld\n", unit, - (long long)adapter->stats.algnerrc); - printf("em%d: Carrier extension errors = %lld\n", unit, - (long long)adapter->stats.cexterr); + device_printf(dev, "Excessive collisions = %lld\n", + (long long)adapter->stats.ecol); + device_printf(dev, "Symbol errors = %lld\n", + (long long)adapter->stats.symerrs); + device_printf(dev, "Sequence errors = %lld\n", + (long long)adapter->stats.sec); + device_printf(dev, "Defer count = %lld\n", (long long)adapter->stats.dc); - printf("em%d: XON Rcvd = %lld\n", unit, - (long long)adapter->stats.xonrxc); - printf("em%d: XON Xmtd = %lld\n", unit, - (long long)adapter->stats.xontxc); - printf("em%d: XOFF Rcvd = %lld\n", unit, - (long long)adapter->stats.xoffrxc); - printf("em%d: XOFF Xmtd = %lld\n", unit, - (long long)adapter->stats.xofftxc); + device_printf(dev, "Missed Packets = %lld\n", (long long)adapter->stats.mpc); + device_printf(dev, "Receive No Buffers = %lld\n", + (long long)adapter->stats.rnbc); + /* RLEC is inaccurate on some hardware, calculate our own. */ + device_printf(dev, "Receive Length Errors = %lld\n", + ((long long)adapter->stats.roc + (long long)adapter->stats.ruc)); + device_printf(dev, "Receive errors = %lld\n", + (long long)adapter->stats.rxerrc); + device_printf(dev, "Crc errors = %lld\n", (long long)adapter->stats.crcerrs); + device_printf(dev, "Alignment errors = %lld\n", + (long long)adapter->stats.algnerrc); + device_printf(dev, "Carrier extension errors = %lld\n", + (long long)adapter->stats.cexterr); + device_printf(dev, "RX overruns = %ld\n", adapter->rx_overruns); + device_printf(dev, "watchdog timeouts = %ld\n", adapter->watchdog_events); - printf("em%d: Good Packets Rcvd = %lld\n", unit, - (long long)adapter->stats.gprc); - printf("em%d: Good Packets Xmtd = %lld\n", unit, - (long long)adapter->stats.gptc); + device_printf(dev, "XON Rcvd = %lld\n", (long long)adapter->stats.xonrxc); + device_printf(dev, "XON Xmtd = %lld\n", (long long)adapter->stats.xontxc); + device_printf(dev, "XOFF Rcvd = %lld\n", (long long)adapter->stats.xoffrxc); + device_printf(dev, "XOFF Xmtd = %lld\n", (long long)adapter->stats.xofftxc); - return; + device_printf(dev, "Good Packets Rcvd = %lld\n", + (long long)adapter->stats.gprc); + device_printf(dev, "Good Packets Xmtd = %lld\n", + (long long)adapter->stats.gptc); } static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS) { + struct adapter *adapter; int error; int result; - struct adapter *adapter; result = -1; error = sysctl_handle_int(oidp, &result, 0, req); - + if (error || !req->newptr) return (error); @@ -3081,20 +3450,20 @@ em_sysctl_debug_info(SYSCTL_HANDLER_ARGS) em_print_debug_info(adapter); } - return error; + return (error); } static int em_sysctl_stats(SYSCTL_HANDLER_ARGS) { + struct adapter *adapter; int error; int result; - struct adapter *adapter; - + result = -1; error = sysctl_handle_int(oidp, &result, 0, req); - + if (error || !req->newptr) return (error); @@ -3103,66 +3472,66 @@ em_sysctl_stats(SYSCTL_HANDLER_ARGS) em_print_hw_stats(adapter); } - return error; + return (error); } static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS) { - struct em_int_delay_info *info; - struct adapter *adapter; - u_int32_t regval; - int error; - int usecs; - int ticks; - int s; + struct em_int_delay_info *info; + struct adapter *adapter; + uint32_t regval; + int error; + int usecs; + int ticks; + int s; - info = (struct em_int_delay_info *)arg1; - adapter = info->adapter; - usecs = info->value; - error = sysctl_handle_int(oidp, &usecs, 0, req); - if (error != 0 || req->newptr == NULL) - return error; - if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535)) - return EINVAL; - info->value = usecs; - ticks = E1000_USECS_TO_TICKS(usecs); + info = (struct em_int_delay_info *)arg1; + usecs = info->value; + error = sysctl_handle_int(oidp, &usecs, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535)) + return (EINVAL); + info->value = usecs; + ticks = E1000_USECS_TO_TICKS(usecs); - s = splimp(); - regval = E1000_READ_OFFSET(&adapter->hw, info->offset); - regval = (regval & ~0xffff) | (ticks & 0xffff); - /* Handle a few special cases. */ - switch (info->offset) { - case E1000_RDTR: - case E1000_82542_RDTR: - regval |= E1000_RDT_FPDB; - break; - case E1000_TIDV: - case E1000_82542_TIDV: - if (ticks == 0) { - adapter->txd_cmd &= ~E1000_TXD_CMD_IDE; - /* Don't write 0 into the TIDV register. */ - regval++; - } else - adapter->txd_cmd |= E1000_TXD_CMD_IDE; - break; - } - E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval); - splx(s); - return 0; + adapter = info->adapter; + + s = splimp(); + regval = E1000_READ_OFFSET(&adapter->hw, info->offset); + regval = (regval & ~0xffff) | (ticks & 0xffff); + /* Handle a few special cases. */ + switch (info->offset) { + case E1000_RDTR: + case E1000_82542_RDTR: + regval |= E1000_RDT_FPDB; + break; + case E1000_TIDV: + case E1000_82542_TIDV: + if (ticks == 0) { + adapter->txd_cmd &= ~E1000_TXD_CMD_IDE; + /* Don't write 0 into the TIDV register. */ + regval++; + } else + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + break; + } + E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval); + splx(s); + return (0); } static void em_add_int_delay_sysctl(struct adapter *adapter, const char *name, - const char *description, struct em_int_delay_info *info, - int offset, int value) + const char *description, struct em_int_delay_info *info, + int offset, int value) { - info->adapter = adapter; - info->offset = offset; - info->value = value; - SYSCTL_ADD_PROC(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, - info, 0, em_sysctl_int_delay, "I", description); + info->adapter = adapter; + info->offset = offset; + info->value = value; + SYSCTL_ADD_PROC(&adapter->sysctl_ctx, + SYSCTL_CHILDREN(adapter->sysctl_tree), + OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, + info, 0, em_sysctl_int_delay, "I", description); } - diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h index bf32b162de6c..e3ce233ddac8 100644 --- a/sys/dev/em/if_em.h +++ b/sys/dev/em/if_em.h @@ -1,6 +1,6 @@ /************************************************************************** -Copyright (c) 2001-2003, Intel Corporation +Copyright (c) 2001-2006, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -36,67 +36,27 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef _EM_H_DEFINED_ #define _EM_H_DEFINED_ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/sockio.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#include <net/bpf.h> -#include <net/if_types.h> -#include <net/if_vlan_var.h> - -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> - -#include <sys/bus.h> -#include <machine/bus.h> -#include <sys/rman.h> -#include <machine/resource.h> -#include <vm/vm.h> -#include <vm/pmap.h> -#include <machine/clock.h> -#if __FreeBSD_version >= 502000 -#include <dev/pci/pcivar.h> -#include <dev/pci/pcireg.h> -#else -#include <pci/pcivar.h> -#include <pci/pcireg.h> -#endif -#include <sys/proc.h> -#include <sys/sysctl.h> -#include "opt_bdg.h" - -#include <dev/em/if_em_hw.h> - /* Tunables */ /* - * EM_MAX_TXD: Maximum number of Transmit Descriptors + * EM_TXD: Maximum number of Transmit Descriptors * Valid Range: 80-256 for 82542 and 82543-based adapters * 80-4096 for others * Default Value: 256 * This value is the number of transmit descriptors allocated by the driver. * Increasing this value allows the driver to queue more transmits. Each * descriptor is 16 bytes. + * Since TDLEN should be multiple of 128bytes, the number of transmit + * desscriptors should meet the following condition. + * (num_tx_desc * sizeof(struct em_tx_desc)) % 128 == 0 */ -#define EM_MAX_TXD 256 +#define EM_MIN_TXD 80 +#define EM_MAX_TXD_82543 256 +#define EM_MAX_TXD 4096 +#define EM_DEFAULT_TXD EM_MAX_TXD_82543 /* - * EM_MAX_RXD - Maximum number of receive Descriptors + * EM_RXD - Maximum number of receive Descriptors * Valid Range: 80-256 for 82542 and 82543-based adapters * 80-4096 for others * Default Value: 256 @@ -104,12 +64,17 @@ POSSIBILITY OF SUCH DAMAGE. * Increasing this value allows the driver to buffer more incoming packets. * Each descriptor is 16 bytes. A receive buffer is also allocated for each * descriptor. The maximum MTU size is 16110. - * + * Since TDLEN should be multiple of 128bytes, the number of transmit + * desscriptors should meet the following condition. + * (num_tx_desc * sizeof(struct em_tx_desc)) % 128 == 0 */ -#define EM_MAX_RXD 256 +#define EM_MIN_RXD 80 +#define EM_MAX_RXD_82543 256 +#define EM_MAX_RXD 4096 +#define EM_DEFAULT_RXD EM_MAX_RXD_82543 /* - * EM_TIDV - Transmit Interrupt Delay Value + * EM_TIDV - Transmit Interrupt Delay Value * Valid Range: 0-65535 (0=off) * Default Value: 64 * This value delays the generation of transmit interrupts in units of @@ -134,7 +99,7 @@ POSSIBILITY OF SUCH DAMAGE. #define EM_TADV 64 /* - * EM_RDTR - Receive Interrupt Delay Timer (Packet Timer) + * EM_RDTR - Receive Interrupt Delay Timer (Packet Timer) * Valid Range: 0-65535 (0=off) * Default Value: 0 * This value delays the generation of receive interrupts in units of 1.024 @@ -167,14 +132,6 @@ POSSIBILITY OF SUCH DAMAGE. */ #define EM_RADV 64 - -/* - * This parameter controls the maximum no of times the driver will loop - * in the isr. - * Minimum Value = 1 - */ -#define EM_MAX_INTR 3 - /* * Inform the stack about transmit checksum offload capabilities. */ @@ -189,7 +146,7 @@ POSSIBILITY OF SUCH DAMAGE. * This parameter controls when the driver calls the routine to reclaim * transmit descriptors. */ -#define EM_TX_CLEANUP_THRESHOLD EM_MAX_TXD / 8 +#define EM_TX_CLEANUP_THRESHOLD (adapter->num_tx_desc / 8) /* * This parameter controls whether or not autonegotation is enabled. @@ -208,15 +165,15 @@ POSSIBILITY OF SUCH DAMAGE. /* * EM_MASTER_SLAVE is only defined to enable a workaround for a known compatibility issue - * with 82541/82547 devices and some switches. See the "Known Limitations" section of + * with 82541/82547 devices and some switches. See the "Known Limitations" section of * the README file for a complete description and a list of affected switches. - * + * * 0 = Hardware default * 1 = Master mode * 2 = Slave mode * 3 = Auto master/slave - */ -/* #define EM_MASTER_SLAVE 2 */ + */ +/* #define EM_MASTER_SLAVE 2 */ /* Tunables -- End */ @@ -225,19 +182,26 @@ POSSIBILITY OF SUCH DAMAGE. ADVERTISE_1000_FULL) #define EM_VENDOR_ID 0x8086 -#define EM_MMBA 0x0010 /* Mem base address */ -#define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) +#define EM_FLASH 0x0014 /* Flash memory on ICH8 */ #define EM_JUMBO_PBA 0x00000028 #define EM_DEFAULT_PBA 0x00000030 #define EM_SMARTSPEED_DOWNSHIFT 3 #define EM_SMARTSPEED_MAX 15 - #define MAX_NUM_MULTICAST_ADDRESSES 128 #define PCI_ANY_ID (~0U) #define ETHER_ALIGN 2 +/* + * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be + * multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary. This will + * also optimize cache line size effect. H/W supports up to cache line size 128. + */ +#define EM_DBA_ALIGN 128 + +#define SPEED_MODE_BIT (1<<21) /* On PCI-E MACs only */ + /* Defines for printing debug information */ #define DEBUG_INIT 0 #define DEBUG_IOCTL 0 @@ -260,32 +224,7 @@ POSSIBILITY OF SUCH DAMAGE. #define EM_RXBUFFER_8192 8192 #define EM_RXBUFFER_16384 16384 - -#ifdef __alpha__ - #undef vtophys - #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va)) -#endif /* __alpha__ */ - -/* ****************************************************************************** - * vendor_info_array - * - * This array contains the list of Subvendor/Subdevice IDs on which the driver - * should load. - * - * ******************************************************************************/ -typedef struct _em_vendor_info_t { - unsigned int vendor_id; - unsigned int device_id; - unsigned int subvendor_id; - unsigned int subdevice_id; - unsigned int index; -} em_vendor_info_t; - - -struct em_buffer { - struct mbuf *m_head; -}; - +#define EM_MAX_SCATTER 64 typedef enum _XSUM_CONTEXT_T { OFFLOAD_NONE, @@ -293,124 +232,165 @@ typedef enum _XSUM_CONTEXT_T { OFFLOAD_UDP_IP } XSUM_CONTEXT_T; -struct adapter; +struct adapter; /* XXX: ugly forward declaration */ struct em_int_delay_info { - struct adapter *adapter; /* Back-pointer to the adapter struct */ - int offset; /* Register offset to read/write */ - int value; /* Current value in usecs */ + struct adapter *adapter; /* XXX: ugly pointer */ + int offset; /* Register offset to read/write */ + int value; /* Current value in usecs */ }; -/* For 82544 PCIX Workaround */ -typedef struct _ADDRESS_LENGTH_PAIR -{ - u_int64_t address; - u_int32_t length; -} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR; +/* + * Bus dma allocation structure used by + * em_dma_malloc() and em_dma_free(). + */ +struct em_dma_alloc { + bus_addr_t dma_paddr; + caddr_t dma_vaddr; + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; + bus_dma_segment_t dma_seg; + int dma_nseg; +}; -typedef struct _DESCRIPTOR_PAIR -{ - ADDRESS_LENGTH_PAIR descriptor[4]; - u_int32_t elements; -} DESC_ARRAY, *PDESC_ARRAY; - -/* Our adapter structure */ +/* Driver softc. */ struct adapter { struct arpcom interface_data; - struct adapter *next; - struct adapter *prev; - struct em_hw hw; + struct em_hw hw; - /* FreeBSD operating-system-specific structures */ + /* FreeBSD operating-system-specific structures. */ struct em_osdep osdep; - struct device *dev; + struct device *dev; struct resource *res_memory; - struct resource *res_ioport; - struct resource *res_interrupt; - 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; + struct resource *flash_mem; + struct resource *res_ioport; + struct resource *res_interrupt; + void *int_handler_tag; + struct ifmedia media; + struct callout timer; + struct callout tx_fifo_timer; + int io_rid; + int em_insert_vlan_header; /* Info about the board itself */ - u_int32_t part_num; - u_int8_t link_active; - u_int16_t link_speed; - u_int16_t link_duplex; - u_int32_t smartspeed; + uint32_t part_num; + uint8_t link_active; + uint16_t link_speed; + uint16_t link_duplex; + uint32_t smartspeed; struct em_int_delay_info tx_int_delay; - struct em_int_delay_info tx_abs_int_delay; - struct em_int_delay_info rx_int_delay; - struct em_int_delay_info rx_abs_int_delay; + struct em_int_delay_info tx_abs_int_delay; + struct em_int_delay_info rx_int_delay; + struct em_int_delay_info rx_abs_int_delay; XSUM_CONTEXT_T active_checksum_context; /* - * Transmit definitions - * - * We have an array of num_tx_desc descriptors (handled - * by the controller) paired with an array of tx_buffers - * (at tx_buffer_area). - * The index of the next available descriptor is next_avail_tx_desc. - * The number of remaining tx_desc is num_tx_desc_avail. - */ - struct em_tx_desc *tx_desc_base; - u_int32_t next_avail_tx_desc; - u_int32_t oldest_used_tx_desc; - volatile u_int16_t num_tx_desc_avail; - u_int16_t num_tx_desc; - u_int32_t txd_cmd; - struct em_buffer *tx_buffer_area; + * Transmit definitions + * + * We have an array of num_tx_desc descriptors (handled + * by the controller) paired with an array of tx_buffers + * (at tx_buffer_area). + * The index of the next available descriptor is next_avail_tx_desc. + * The number of remaining tx_desc is num_tx_desc_avail. + */ + struct em_dma_alloc txdma; /* bus_dma glue for tx desc */ + struct em_tx_desc *tx_desc_base; + uint32_t next_avail_tx_desc; + uint32_t oldest_used_tx_desc; + volatile uint16_t num_tx_desc_avail; + uint16_t num_tx_desc; + uint32_t txd_cmd; + struct em_buffer *tx_buffer_area; + bus_dma_tag_t txtag; /* dma tag for tx */ /* * Receive definitions - * - * we have an array of num_rx_desc rx_desc (handled by the - * controller), and paired with an array of rx_buffers - * (at rx_buffer_area). - * The next pair to check on receive is at offset next_rx_desc_to_check - */ - struct em_rx_desc *rx_desc_base; - u_int32_t next_rx_desc_to_check; - u_int16_t num_rx_desc; - u_int32_t rx_buffer_len; - struct em_buffer *rx_buffer_area; + * + * we have an array of num_rx_desc rx_desc (handled by the + * controller), and paired with an array of rx_buffers + * (at rx_buffer_area). + * The next pair to check on receive is at offset next_rx_desc_to_check + */ + struct em_dma_alloc rxdma; /* bus_dma glue for rx desc */ + struct em_rx_desc *rx_desc_base; + uint32_t next_rx_desc_to_check; + uint32_t rx_buffer_len; + uint16_t num_rx_desc; + struct em_buffer *rx_buffer_area; + bus_dma_tag_t rxtag; + bus_dmamap_t rx_sparemap; - /* Jumbo frame */ - struct mbuf *fmp; - struct mbuf *lmp; + /* First/last mbuf pointers, for collecting multisegment RX packets. */ + struct mbuf *fmp; + struct mbuf *lmp; - struct sysctl_ctx_list sysctl_ctx; - struct sysctl_oid *sysctl_tree; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; /* Misc stats maintained by the driver */ - unsigned long dropped_pkts; - unsigned long mbuf_alloc_failed; - unsigned long mbuf_cluster_failed; - unsigned long no_tx_desc_avail1; - unsigned long no_tx_desc_avail2; + unsigned long mbuf_alloc_failed; + unsigned long mbuf_cluster_failed; + unsigned long no_tx_desc_avail1; + unsigned long no_tx_desc_avail2; + unsigned long no_tx_map_avail; + unsigned long no_tx_dma_setup; + unsigned long watchdog_events; + unsigned long rx_overruns; /* Used in for 82547 10Mb Half workaround */ #define EM_PBA_BYTES_SHIFT 0xA #define EM_TX_HEAD_ADDR_SHIFT 7 #define EM_PBA_TX_MASK 0xFFFF0000 - #define EM_FIFO_HDR 0x10 + #define EM_FIFO_HDR 0x10 - #define EM_82547_PKT_THRESH 0x3e0 + #define EM_82547_PKT_THRESH 0x3e0 - u_int32_t tx_fifo_size; - u_int32_t tx_fifo_head; - u_int32_t tx_fifo_head_addr; - u_int64_t tx_fifo_reset_cnt; - u_int64_t tx_fifo_wrk_cnt; - u_int32_t tx_head_addr; + uint32_t tx_fifo_size; + uint32_t tx_fifo_head; + uint32_t tx_fifo_head_addr; + uint64_t tx_fifo_reset_cnt; + uint64_t tx_fifo_wrk_cnt; + uint32_t tx_head_addr; - /* For 82544 PCIX Workaround */ - boolean_t pcix_82544; - boolean_t in_detach; + /* For 82544 PCIX Workaround */ + boolean_t pcix_82544; + boolean_t in_detach; struct em_hw_stats stats; }; -#endif /* _EM_H_DEFINED_ */ +/* ****************************************************************************** + * vendor_info_array + * + * This array contains the list of Subvendor/Subdevice IDs on which the driver + * should load. + * + * ******************************************************************************/ +typedef struct _em_vendor_info_t { + unsigned int vendor_id; + unsigned int device_id; + unsigned int subvendor_id; + unsigned int subdevice_id; + unsigned int index; +} em_vendor_info_t; + + +struct em_buffer { + struct mbuf *m_head; + bus_dmamap_t map; /* bus_dma map for packet */ +}; + +/* For 82544 PCIX Workaround */ +typedef struct _ADDRESS_LENGTH_PAIR +{ + u_int64_t address; + u_int32_t length; +} ADDRESS_LENGTH_PAIR, *PADDRESS_LENGTH_PAIR; + +typedef struct _DESCRIPTOR_PAIR +{ + ADDRESS_LENGTH_PAIR descriptor[4]; + u_int32_t elements; +} DESC_ARRAY, *PDESC_ARRAY; + +#endif /* _EM_H_DEFINED_ */ diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c index 28fa6b142ecb..58716c56a81c 100644 --- a/sys/dev/em/if_em_hw.c +++ b/sys/dev/em/if_em_hw.c @@ -1,45 +1,46 @@ /******************************************************************************* +Copyright (c) 2001-2005, Intel Corporation +All rights reserved. - Copyright (c) 2001-2005, Intel Corporation - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ -/*$FreeBSD$*/ + /* if_em_hw.c * Shared functions for accessing and configuring the MAC */ -#include <dev/em/if_em_hw.h> +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -#ifndef NO_VERSION_CONTROL -#ident "@(#)$RCSfile: em_hw.c,v $$Revision: 1.271 $$Date: 2005/03/24 19:32:53 $" +#ifdef LM +#include "if_em_hw.h" +#else +#include <dev/em/if_em_hw.h> #endif static int32_t em_set_phy_type(struct em_hw *hw); @@ -78,6 +79,9 @@ static int32_t em_polarity_reversal_workaround(struct em_hw *hw); static int32_t em_set_phy_mode(struct em_hw *hw); static int32_t em_host_if_read_cookie(struct em_hw *hw, uint8_t *buffer); static uint8_t em_calculate_mng_checksum(char *buffer, uint32_t length); +static int32_t em_configure_kmrn_for_10_100(struct em_hw *hw, + uint16_t duplex); +static int32_t em_configure_kmrn_for_1000(struct em_hw *hw); /* IGP cable length table */ static const @@ -93,14 +97,14 @@ uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = static const uint16_t em_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = - { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, - 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58, - 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74, - 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90, - 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108, - 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124, - 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128, - 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, + 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, + 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, + 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, + 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, + 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, + 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, + 104, 109, 114, 118, 121, 124}; /****************************************************************************** @@ -113,10 +117,10 @@ em_set_phy_type(struct em_hw *hw) { DEBUGFUNC("em_set_phy_type"); - if(hw->mac_type == em_undefined) + if (hw->mac_type == em_undefined) return -E1000_ERR_PHY_TYPE; - switch(hw->phy_id) { + switch (hw->phy_id) { case M88E1000_E_PHY_ID: case M88E1000_I_PHY_ID: case M88E1011_I_PHY_ID: @@ -124,13 +128,26 @@ em_set_phy_type(struct em_hw *hw) hw->phy_type = em_phy_m88; break; case IGP01E1000_I_PHY_ID: - if(hw->mac_type == em_82541 || - hw->mac_type == em_82541_rev_2 || - hw->mac_type == em_82547 || - hw->mac_type == em_82547_rev_2) { + if (hw->mac_type == em_82541 || + hw->mac_type == em_82541_rev_2 || + hw->mac_type == em_82547 || + hw->mac_type == em_82547_rev_2) { hw->phy_type = em_phy_igp; break; } + case IGP03E1000_E_PHY_ID: + hw->phy_type = em_phy_igp_3; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + hw->phy_type = em_phy_ife; + break; + case GG82563_E_PHY_ID: + if (hw->mac_type == em_80003es2lan) { + hw->phy_type = em_phy_gg82563; + break; + } /* Fall Through */ default: /* Should never have loaded on this device */ @@ -141,6 +158,7 @@ em_set_phy_type(struct em_hw *hw) return E1000_SUCCESS; } + /****************************************************************************** * IGP phy init script - initializes the GbE PHY * @@ -154,7 +172,7 @@ em_phy_init_script(struct em_hw *hw) DEBUGFUNC("em_phy_init_script"); - if(hw->phy_init_script) { + if (hw->phy_init_script) { msec_delay(20); /* Save off the current value of register 0x2F5B to be restored at @@ -170,7 +188,7 @@ em_phy_init_script(struct em_hw *hw) msec_delay(5); - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82541: case em_82547: em_write_phy_reg(hw, 0x1F95, 0x0001); @@ -207,22 +225,22 @@ em_phy_init_script(struct em_hw *hw) /* Now enable the transmitter */ em_write_phy_reg(hw, 0x2F5B, phy_saved_data); - if(hw->mac_type == em_82547) { + if (hw->mac_type == em_82547) { uint16_t fused, fine, coarse; /* Move to analog registers page */ em_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused); - if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) { + if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) { em_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused); fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK; coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK; - if(coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) { + if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) { coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10; fine -= IGP01E1000_ANALOG_FUSE_FINE_1; - } else if(coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH) + } else if (coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH) fine -= IGP01E1000_ANALOG_FUSE_FINE_10; fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) | @@ -297,11 +315,12 @@ em_set_mac_type(struct em_hw *hw) case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82546GB_PCIE: case E1000_DEV_ID_82546GB_QUAD_COPPER: + case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: hw->mac_type = em_82546_rev_3; break; case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541ER_LOM: case E1000_DEV_ID_82541EI_MOBILE: + case E1000_DEV_ID_82541ER_LOM: hw->mac_type = em_82541; break; case E1000_DEV_ID_82541ER: @@ -317,16 +336,51 @@ em_set_mac_type(struct em_hw *hw) case E1000_DEV_ID_82547GI: hw->mac_type = em_82547_rev_2; break; + case E1000_DEV_ID_82571EB_COPPER: + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82571EB_QUAD_COPPER: + hw->mac_type = em_82571; + break; + case E1000_DEV_ID_82572EI_COPPER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82572EI_SERDES: + case E1000_DEV_ID_82572EI: + hw->mac_type = em_82572; + break; case E1000_DEV_ID_82573E: case E1000_DEV_ID_82573E_IAMT: + case E1000_DEV_ID_82573L: hw->mac_type = em_82573; break; + case E1000_DEV_ID_80003ES2LAN_COPPER_SPT: + case E1000_DEV_ID_80003ES2LAN_SERDES_SPT: + case E1000_DEV_ID_80003ES2LAN_COPPER_DPT: + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: + hw->mac_type = em_80003es2lan; + break; + case E1000_DEV_ID_ICH8_IGP_M_AMT: + case E1000_DEV_ID_ICH8_IGP_AMT: + case E1000_DEV_ID_ICH8_IGP_C: + case E1000_DEV_ID_ICH8_IFE: + case E1000_DEV_ID_ICH8_IGP_M: + hw->mac_type = em_ich8lan; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } - switch(hw->mac_type) { + switch (hw->mac_type) { + case em_ich8lan: + hw->swfwhw_semaphore_present = TRUE; + hw->asf_firmware_present = TRUE; + break; + case em_80003es2lan: + hw->swfw_sync_present = TRUE; + /* fall through */ + case em_82571: + case em_82572: case em_82573: hw->eeprom_semaphore_present = TRUE; /* fall through */ @@ -355,7 +409,7 @@ em_set_media_type(struct em_hw *hw) DEBUGFUNC("em_set_media_type"); - if(hw->mac_type != em_82543) { + if (hw->mac_type != em_82543) { /* tbi_compatibility is only valid on 82543 */ hw->tbi_compatibility_en = FALSE; } @@ -363,21 +417,34 @@ em_set_media_type(struct em_hw *hw) switch (hw->device_id) { case E1000_DEV_ID_82545GM_SERDES: case E1000_DEV_ID_82546GB_SERDES: + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82572EI_SERDES: + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: hw->media_type = em_media_type_internal_serdes; break; default: - if(hw->mac_type >= em_82543) { + switch (hw->mac_type) { + case em_82542_rev2_0: + case em_82542_rev2_1: + hw->media_type = em_media_type_fiber; + break; + case em_ich8lan: + case em_82573: + /* The STATUS_TBIMODE bit is reserved or reused for the this + * device. + */ + hw->media_type = em_media_type_copper; + break; + default: status = E1000_READ_REG(hw, STATUS); - if(status & E1000_STATUS_TBIMODE) { + if (status & E1000_STATUS_TBIMODE) { hw->media_type = em_media_type_fiber; /* tbi_compatibility not valid on fiber */ hw->tbi_compatibility_en = FALSE; } else { hw->media_type = em_media_type_copper; } - } else { - /* This is an 82542 (fiber only) */ - hw->media_type = em_media_type_fiber; + break; } } } @@ -402,16 +469,16 @@ em_reset_hw(struct em_hw *hw) DEBUGFUNC("em_reset_hw"); /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ - if(hw->mac_type == em_82542_rev2_0) { + if (hw->mac_type == em_82542_rev2_0) { DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); em_pci_clear_mwi(hw); } - if(hw->bus_type == em_bus_type_pci_express) { + if (hw->bus_type == em_bus_type_pci_express) { /* Prevent the PCI-E bus from sticking if there is no TLP connection * on the last TLP read/write transaction when MAC is reset. */ - if(em_disable_pciex_master(hw) != E1000_SUCCESS) { + if (em_disable_pciex_master(hw) != E1000_SUCCESS) { DEBUGOUT("PCI-E Master disable polling has failed.\n"); } } @@ -439,14 +506,14 @@ em_reset_hw(struct em_hw *hw) ctrl = E1000_READ_REG(hw, CTRL); /* Must reset the PHY before resetting the MAC */ - if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); msec_delay(5); } /* Must acquire the MDIO ownership before MAC reset. * Ownership defaults to firmware after a reset. */ - if(hw->mac_type == em_82573) { + if (hw->mac_type == em_82573) { timeout = 10; extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); @@ -456,14 +523,22 @@ em_reset_hw(struct em_hw *hw) E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); - if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) + if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) break; else extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; msec_delay(2); timeout--; - } while(timeout); + } while (timeout); + } + + /* Workaround for ICH8 bit corruption issue in FIFO memory */ + if (hw->mac_type == em_ich8lan) { + /* Set Tx and Rx buffer allocation to 8k apiece. */ + E1000_WRITE_REG(hw, PBA, E1000_PBA_8K); + /* Set Packet Buffer Size to 16k. */ + E1000_WRITE_REG(hw, PBS, E1000_PBS_16K); } /* Issue a global reset to the MAC. This will reset the chip's @@ -473,11 +548,13 @@ em_reset_hw(struct em_hw *hw) */ DEBUGOUT("Issuing a global reset to MAC\n"); - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82544: case em_82540: case em_82545: +#ifndef __arm__ case em_82546: +#endif case em_82541: case em_82541_rev_2: /* These controllers can't ack the 64-bit write when issuing the @@ -489,6 +566,20 @@ em_reset_hw(struct em_hw *hw) /* Reset is performed on a shadow of the control register */ E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST)); break; + case em_ich8lan: + if (!hw->phy_reset_disable && + em_check_phy_reset_block(hw) == E1000_SUCCESS) { + /* em_ich8lan PHY HW reset requires MAC CORE reset + * at the same time to make sure the interface between + * MAC and the external PHY is reset. + */ + ctrl |= E1000_CTRL_PHY_RST; + } + + em_get_software_flag(hw); + E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); + msec_delay(5); + break; default: E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); break; @@ -498,7 +589,7 @@ em_reset_hw(struct em_hw *hw) * device. Later controllers reload the EEPROM automatically, so just wait * for reload to complete. */ - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82542_rev2_0: case em_82542_rev2_1: case em_82543: @@ -520,14 +611,20 @@ em_reset_hw(struct em_hw *hw) msec_delay(20); break; case em_82573: - usec_delay(10); - ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_EE_RST; - E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); - E1000_WRITE_FLUSH(hw); + if (em_is_onboard_nvm_eeprom(hw) == FALSE) { + usec_delay(10); + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); + } /* fall through */ + case em_82571: + case em_82572: + case em_ich8lan: + case em_80003es2lan: ret_val = em_get_auto_rd_done(hw); - if(ret_val) + if (ret_val) /* We don't want to continue accessing MAC registers. */ return ret_val; break; @@ -538,13 +635,13 @@ em_reset_hw(struct em_hw *hw) } /* Disable HW ARPs on ASF enabled adapters */ - if(hw->mac_type >= em_82540 && hw->mac_type <= em_82547_rev_2) { + if (hw->mac_type >= em_82540 && hw->mac_type <= em_82547_rev_2) { 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)) { + if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { em_phy_init_script(hw); /* Configure activity LED after PHY reset */ @@ -562,11 +659,17 @@ em_reset_hw(struct em_hw *hw) icr = E1000_READ_REG(hw, ICR); /* If MWI was previously enabled, reenable it. */ - if(hw->mac_type == em_82542_rev2_0) { - if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) + if (hw->mac_type == em_82542_rev2_0) { + if (hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) em_pci_set_mwi(hw); } + if (hw->mac_type == em_ich8lan) { + uint32_t kab = E1000_READ_REG(hw, KABGTXD); + kab |= E1000_KABGTXD_BGSQLBIAS; + E1000_WRITE_REG(hw, KABGTXD, kab); + } + return E1000_SUCCESS; } @@ -592,12 +695,24 @@ em_init_hw(struct em_hw *hw) uint16_t cmd_mmrbc; uint16_t stat_mmrbc; uint32_t mta_size; + uint32_t reg_data; + uint32_t ctrl_ext; DEBUGFUNC("em_init_hw"); + if (hw->mac_type == em_ich8lan) { + reg_data = E1000_READ_REG(hw, TARC0); + reg_data |= 0x30000000; + E1000_WRITE_REG(hw, TARC0, reg_data); + + reg_data = E1000_READ_REG(hw, STATUS); + reg_data &= ~0x80000000; + E1000_WRITE_REG(hw, STATUS, reg_data); + } + /* Initialize Identification LED */ ret_val = em_id_led_init(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error Initializing Identification LED\n"); return ret_val; } @@ -607,12 +722,15 @@ em_init_hw(struct em_hw *hw) /* Disabling VLAN filtering. */ DEBUGOUT("Initializing the IEEE VLAN\n"); - if (hw->mac_type < em_82545_rev_3) - E1000_WRITE_REG(hw, VET, 0); - em_clear_vfta(hw); + /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */ + if (hw->mac_type != em_ich8lan) { + if (hw->mac_type < em_82545_rev_3) + E1000_WRITE_REG(hw, VET, 0); + em_clear_vfta(hw); + } /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ - if(hw->mac_type == em_82542_rev2_0) { + if (hw->mac_type == em_82542_rev2_0) { DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); em_pci_clear_mwi(hw); E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST); @@ -626,37 +744,43 @@ em_init_hw(struct em_hw *hw) em_init_rx_addrs(hw); /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ - if(hw->mac_type == em_82542_rev2_0) { + if (hw->mac_type == em_82542_rev2_0) { E1000_WRITE_REG(hw, RCTL, 0); E1000_WRITE_FLUSH(hw); msec_delay(1); - if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) + if (hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) em_pci_set_mwi(hw); } /* Zero out the Multicast HASH table */ DEBUGOUT("Zeroing the MTA\n"); mta_size = E1000_MC_TBL_SIZE; - for(i = 0; i < mta_size; i++) + if (hw->mac_type == em_ich8lan) + mta_size = E1000_MC_TBL_SIZE_ICH8LAN; + for (i = 0; i < mta_size; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); + /* use write flush to prevent Memory Write Block (MWB) from + * occuring when accessing our register space */ + E1000_WRITE_FLUSH(hw); + } /* Set the PCI priority bit correctly in the CTRL register. This * determines if the adapter gives priority to receives, or if it * gives equal priority to transmits and receives. Valid only on * 82542 and 82543 silicon. */ - if(hw->dma_fairness && hw->mac_type <= em_82543) { + if (hw->dma_fairness && hw->mac_type <= em_82543) { ctrl = E1000_READ_REG(hw, CTRL); E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR); } - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82545_rev_3: case em_82546_rev_3: break; default: /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */ - if(hw->bus_type == em_bus_type_pcix) { + if (hw->bus_type == em_bus_type_pcix) { em_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word); em_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word); @@ -664,9 +788,9 @@ em_init_hw(struct em_hw *hw) PCIX_COMMAND_MMRBC_SHIFT; stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> PCIX_STATUS_HI_MMRBC_SHIFT; - if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) + if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; - if(cmd_mmrbc > stat_mmrbc) { + if (cmd_mmrbc > stat_mmrbc) { pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; em_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, @@ -676,17 +800,25 @@ em_init_hw(struct em_hw *hw) break; } + /* More time needed for PHY to initialize */ + if (hw->mac_type == em_ich8lan) + msec_delay(15); + /* Call a subroutine to configure the link and setup flow control. */ ret_val = em_setup_link(hw); /* Set the transmit descriptor write-back policy */ - if(hw->mac_type > em_82544) { + if (hw->mac_type > em_82544) { ctrl = E1000_READ_REG(hw, TXDCTL); ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; switch (hw->mac_type) { default: break; + case em_82571: + case em_82572: case em_82573: + case em_ich8lan: + case em_80003es2lan: ctrl |= E1000_TXDCTL_COUNT_DESC; break; } @@ -694,10 +826,52 @@ em_init_hw(struct em_hw *hw) } if (hw->mac_type == em_82573) { - em_enable_tx_pkt_filtering(hw); + em_enable_tx_pkt_filtering(hw); + } + + switch (hw->mac_type) { + default: + break; + case em_80003es2lan: + /* Enable retransmit on late collisions */ + reg_data = E1000_READ_REG(hw, TCTL); + reg_data |= E1000_TCTL_RTLC; + E1000_WRITE_REG(hw, TCTL, reg_data); + + /* Configure Gigabit Carry Extend Padding */ + reg_data = E1000_READ_REG(hw, TCTL_EXT); + reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; + reg_data |= DEFAULT_80003ES2LAN_TCTL_EXT_GCEX; + E1000_WRITE_REG(hw, TCTL_EXT, reg_data); + + /* Configure Transmit Inter-Packet Gap */ + reg_data = E1000_READ_REG(hw, TIPG); + reg_data &= ~E1000_TIPG_IPGT_MASK; + reg_data |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000; + E1000_WRITE_REG(hw, TIPG, reg_data); + + reg_data = E1000_READ_REG_ARRAY(hw, FFLT, 0x0001); + reg_data &= ~0x00100000; + E1000_WRITE_REG_ARRAY(hw, FFLT, 0x0001, reg_data); + /* Fall through */ + case em_82571: + case em_82572: + case em_ich8lan: + ctrl = E1000_READ_REG(hw, TXDCTL1); + ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; + if (hw->mac_type >= em_82571) + ctrl |= E1000_TXDCTL_COUNT_DESC; + E1000_WRITE_REG(hw, TXDCTL1, ctrl); + break; } + if (hw->mac_type == em_82573) { + uint32_t gcr = E1000_READ_REG(hw, GCR); + gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + E1000_WRITE_REG(hw, GCR, gcr); + } + /* Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link * because the symbol error count will increment wildly if there @@ -705,6 +879,20 @@ em_init_hw(struct em_hw *hw) */ em_clear_hw_cntrs(hw); + /* ICH8 No-snoop bits are opposite polarity. + * Set to snoop by default after reset. */ + if (hw->mac_type == em_ich8lan) + em_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL); + + if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER || + hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) { + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + /* Relaxed ordering must be disabled to avoid a parity + * error crash in a PCI slot. */ + ctrl_ext |= E1000_CTRL_EXT_RO_DIS; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + } + return ret_val; } @@ -721,10 +909,10 @@ em_adjust_serdes_amplitude(struct em_hw *hw) DEBUGFUNC("em_adjust_serdes_amplitude"); - if(hw->media_type != em_media_type_internal_serdes) + if (hw->media_type != em_media_type_internal_serdes) return E1000_SUCCESS; - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82545_rev_3: case em_82546_rev_3: break; @@ -737,11 +925,11 @@ em_adjust_serdes_amplitude(struct em_hw *hw) return ret_val; } - if(eeprom_data != EEPROM_RESERVED_WORD) { + if (eeprom_data != EEPROM_RESERVED_WORD) { /* Adjust SERDES output amplitude only. */ - eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK; + eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK; ret_val = em_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data); - if(ret_val) + if (ret_val) return ret_val; } @@ -768,6 +956,11 @@ em_setup_link(struct em_hw *hw) DEBUGFUNC("em_setup_link"); + /* In the case of the phy reset being blocked, we already have a link. + * We do not have to set it up again. */ + if (em_check_phy_reset_block(hw)) + return E1000_SUCCESS; + /* Read and store word 0x0F of the EEPROM. This word contains bits * that determine the hardware's default PAUSE (flow control) mode, * a bit that determines whether the HW defaults to enabling or @@ -776,29 +969,38 @@ 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, 1, &eeprom_data)) { - DEBUGOUT("EEPROM Read Error\n"); - return -E1000_ERR_EEPROM; - } - - 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) == - EEPROM_WORD0F_ASM_DIR) - hw->fc = em_fc_tx_pause; - else + if (hw->fc == em_fc_default) { + switch (hw->mac_type) { + case em_ich8lan: + case em_82573: hw->fc = em_fc_full; + break; + default: + ret_val = em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, + 1, &eeprom_data); + if (ret_val) { + DEBUGOUT("EEPROM Read Error\n"); + return -E1000_ERR_EEPROM; + } + if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0) + hw->fc = em_fc_none; + else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == + EEPROM_WORD0F_ASM_DIR) + hw->fc = em_fc_tx_pause; + else + hw->fc = em_fc_full; + break; + } } /* We want to save off the original Flow Control configuration just * in case we get disconnected and then reconnected into a different * hub or switch with different Flow Control capabilities. */ - if(hw->mac_type == em_82542_rev2_0) + if (hw->mac_type == em_82542_rev2_0) hw->fc &= (~em_fc_tx_pause); - if((hw->mac_type < em_82543) && (hw->report_tx_early == 1)) + if ((hw->mac_type < em_82543) && (hw->report_tx_early == 1)) hw->fc &= (~em_fc_rx_pause); hw->original_fc = hw->fc; @@ -812,7 +1014,13 @@ em_setup_link(struct em_hw *hw) * signal detection. So this should be done before em_setup_pcs_link() * or em_phy_setup() is called. */ - if(hw->mac_type == em_82543) { + if (hw->mac_type == em_82543) { + ret_val = em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, + 1, &eeprom_data); + if (ret_val) { + DEBUGOUT("EEPROM Read Error\n"); + return -E1000_ERR_EEPROM; + } ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << SWDPIO__EXT_SHIFT); E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); @@ -830,9 +1038,12 @@ em_setup_link(struct em_hw *hw) */ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); - E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW); - E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH); - E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE); + /* FCAL/H and FCT are hardcoded to standard values in em_ich8lan. */ + if (hw->mac_type != em_ich8lan) { + E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW); + } E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time); @@ -842,14 +1053,14 @@ em_setup_link(struct em_hw *hw) * ability to transmit pause frames in not enabled, then these * registers will be set to 0. */ - if(!(hw->fc & em_fc_tx_pause)) { + if (!(hw->fc & em_fc_tx_pause)) { E1000_WRITE_REG(hw, FCRTL, 0); E1000_WRITE_REG(hw, FCRTH, 0); } else { /* We need to set up the Receive Threshold high and low water marks * as well as (optionally) enabling the transmission of XON frames. */ - if(hw->fc_send_xon) { + if (hw->fc_send_xon) { E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE)); E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water); } else { @@ -881,6 +1092,14 @@ em_setup_fiber_serdes_link(struct em_hw *hw) DEBUGFUNC("em_setup_fiber_serdes_link"); + /* On 82571 and 82572 Fiber connections, SerDes loopback mode persists + * until explicitly turned off or a power cycle is performed. A read to + * the register does not indicate its status. Therefore, we ensure + * loopback mode is disabled during initialization. + */ + if (hw->mac_type == em_82571 || hw->mac_type == em_82572) + E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK); + /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal. This applies to fiber media only. @@ -888,11 +1107,11 @@ em_setup_fiber_serdes_link(struct em_hw *hw) * the EEPROM. */ ctrl = E1000_READ_REG(hw, CTRL); - if(hw->media_type == em_media_type_fiber) + if (hw->media_type == em_media_type_fiber) signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0; ret_val = em_adjust_serdes_amplitude(hw); - if(ret_val) + if (ret_val) return ret_val; /* Take the link out of reset */ @@ -900,7 +1119,7 @@ em_setup_fiber_serdes_link(struct em_hw *hw) /* Adjust VCO speed to improve BER performance */ ret_val = em_set_vco_speed(hw); - if(ret_val) + if (ret_val) return ret_val; em_config_collision_dist(hw); @@ -971,15 +1190,15 @@ em_setup_fiber_serdes_link(struct em_hw *hw) * less than 500 milliseconds even if the other end is doing it in SW). * For internal serdes, we just assume a signal is present, then poll. */ - if(hw->media_type == em_media_type_internal_serdes || + if (hw->media_type == em_media_type_internal_serdes || (E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) { DEBUGOUT("Looking for Link\n"); - for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { + for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { msec_delay(10); status = E1000_READ_REG(hw, STATUS); - if(status & E1000_STATUS_LU) break; + if (status & E1000_STATUS_LU) break; } - if(i == (LINK_UP_TIMEOUT / 10)) { + if (i == (LINK_UP_TIMEOUT / 10)) { DEBUGOUT("Never got a valid link from auto-neg!!!\n"); hw->autoneg_failed = 1; /* AutoNeg failed to achieve a link, so we'll call @@ -988,7 +1207,7 @@ em_setup_fiber_serdes_link(struct em_hw *hw) * non-autonegotiating link partners. */ ret_val = em_check_for_link(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error while checking for link\n"); return ret_val; } @@ -1022,7 +1241,7 @@ em_copper_link_preconfig(struct em_hw *hw) * the PHY speed and duplex configuration is. In addition, we need to * perform a hardware reset on the PHY to take it out of reset. */ - if(hw->mac_type > em_82543) { + if (hw->mac_type > em_82543) { ctrl |= E1000_CTRL_SLU; ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); E1000_WRITE_REG(hw, CTRL, ctrl); @@ -1030,13 +1249,13 @@ em_copper_link_preconfig(struct em_hw *hw) ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); E1000_WRITE_REG(hw, CTRL, ctrl); ret_val = em_phy_hw_reset(hw); - if(ret_val) + if (ret_val) return ret_val; } /* Make sure we have a valid PHY */ ret_val = em_detect_gig_phy(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error, did not detect valid phy.\n"); return ret_val; } @@ -1044,19 +1263,19 @@ em_copper_link_preconfig(struct em_hw *hw) /* Set PHY to class A mode (if necessary) */ ret_val = em_set_phy_mode(hw); - if(ret_val) + if (ret_val) return ret_val; - if((hw->mac_type == em_82545_rev_3) || + if ((hw->mac_type == em_82545_rev_3) || (hw->mac_type == em_82546_rev_3)) { ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); phy_data |= 0x00000008; ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); } - if(hw->mac_type <= em_82543 || - hw->mac_type == em_82541 || hw->mac_type == em_82547 || - hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) + if (hw->mac_type <= em_82543 || + hw->mac_type == em_82541 || hw->mac_type == em_82547 || + hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) hw->phy_reset_disable = FALSE; return E1000_SUCCESS; @@ -1079,27 +1298,31 @@ em_copper_link_igp_setup(struct em_hw *hw) if (hw->phy_reset_disable) return E1000_SUCCESS; - + ret_val = em_phy_reset(hw); if (ret_val) { DEBUGOUT("Error Resetting the PHY\n"); return ret_val; } - /* Wait 10ms for MAC to configure PHY from eeprom settings */ + /* Wait 15ms for MAC to configure PHY from eeprom settings */ msec_delay(15); - + if (hw->mac_type != em_ich8lan) { /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } - /* disable lplu d3 during driver init */ - ret_val = em_set_d3_lplu_state(hw, FALSE); - if (ret_val) { - DEBUGOUT("Error Disabling LPLU D3\n"); - return ret_val; + /* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */ + if (hw->phy_type == em_phy_igp) { + /* disable lplu d3 during driver init */ + ret_val = em_set_d3_lplu_state(hw, FALSE); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D3\n"); + return ret_val; + } } /* disable lplu d0 during driver init */ @@ -1137,45 +1360,45 @@ em_copper_link_igp_setup(struct em_hw *hw) } } ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; /* set auto-master slave resolution settings */ - if(hw->autoneg) { + if (hw->autoneg) { em_ms_type phy_ms_setting = hw->master_slave; - if(hw->ffe_config_state == em_ffe_config_active) + if (hw->ffe_config_state == em_ffe_config_active) hw->ffe_config_state = em_ffe_config_enabled; - if(hw->dsp_config_state == em_dsp_config_activated) + if (hw->dsp_config_state == em_dsp_config_activated) hw->dsp_config_state = em_dsp_config_enabled; /* when autonegotiation advertisment is only 1000Mbps then we * should disable SmartSpeed and enable Auto MasterSlave * resolution as hardware default. */ - if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { + if (hw->autoneg_advertised == ADVERTISE_1000_FULL) { /* Disable SmartSpeed */ - ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); - if(ret_val) + ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data); + if (ret_val) return ret_val; phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = em_write_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - phy_data); - if(ret_val) + ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data); + if (ret_val) return ret_val; /* Set auto Master/Slave resolution process */ ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data &= ~CR_1000T_MS_ENABLE; ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; } ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; /* load defaults for future use */ @@ -1199,13 +1422,160 @@ em_copper_link_igp_setup(struct em_hw *hw) break; } ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; - } + } - return E1000_SUCCESS; + return E1000_SUCCESS; } +/******************************************************************** +* Copper link setup for em_phy_gg82563 series. +* +* hw - Struct containing variables accessed by shared code +*********************************************************************/ +static int32_t +em_copper_link_ggp_setup(struct em_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data; + uint32_t reg_data; + + DEBUGFUNC("em_copper_link_ggp_setup"); + + if (!hw->phy_reset_disable) { + + /* Enable CRS on TX for half-duplex operation. */ + ret_val = em_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + /* Use 25MHz for both link down and 1000BASE-T for Tx clock */ + phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ; + + ret_val = em_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + phy_data); + if (ret_val) + return ret_val; + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + ret_val = em_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + + switch (hw->mdix) { + case 1: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI; + break; + case 2: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; + break; + case 0: + default: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + if (hw->disable_polarity_correction == 1) + phy_data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + ret_val = em_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data); + + if (ret_val) + return ret_val; + + /* SW Reset the PHY so all changes take effect */ + ret_val = em_phy_reset(hw); + if (ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } + } /* phy_reset_disable */ + + if (hw->mac_type == em_80003es2lan) { + /* Bypass RX and TX FIFO's */ + ret_val = em_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL, + E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS | + E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS); + if (ret_val) + return ret_val; + + ret_val = em_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; + ret_val = em_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, phy_data); + + if (ret_val) + return ret_val; + + reg_data = E1000_READ_REG(hw, CTRL_EXT); + reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); + E1000_WRITE_REG(hw, CTRL_EXT, reg_data); + + ret_val = em_read_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* Do not init these registers when the HW is in IAMT mode, since the + * firmware will have already initialized them. We only initialize + * them if the HW is not in IAMT mode. + */ + if (em_check_mng_mode(hw) == FALSE) { + /* Enable Electrical Idle on the PHY */ + phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; + ret_val = em_write_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, + phy_data); + if (ret_val) + return ret_val; + + ret_val = em_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = em_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + phy_data); + + if (ret_val) + return ret_val; + } + + /* Workaround: Disable padding in Kumeran interface in the MAC + * and in the PHY to avoid CRC errors. + */ + ret_val = em_read_phy_reg(hw, GG82563_PHY_INBAND_CTRL, + &phy_data); + if (ret_val) + return ret_val; + phy_data |= GG82563_ICR_DIS_PADDING; + ret_val = em_write_phy_reg(hw, GG82563_PHY_INBAND_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + return E1000_SUCCESS; +} /******************************************************************** * Copper link setup for em_phy_m88 series. @@ -1220,12 +1590,12 @@ em_copper_link_mgp_setup(struct em_hw *hw) DEBUGFUNC("em_copper_link_mgp_setup"); - if(hw->phy_reset_disable) + if (hw->phy_reset_disable) return E1000_SUCCESS; - + /* Enable CRS on TX. This must be set for half-duplex operation. */ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; @@ -1262,35 +1632,47 @@ em_copper_link_mgp_setup(struct em_hw *hw) * 1 - Enabled */ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if(hw->disable_polarity_correction == 1) + if (hw->disable_polarity_correction == 1) phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if(ret_val) - return ret_val; - - /* Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); - if(ret_val) + ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) return ret_val; - phy_data |= M88E1000_EPSCR_TX_CLK_25; - if (hw->phy_revision < M88E1011_I_REV_4) { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if ((hw->phy_revision == E1000_REVISION_2) && + (hw->phy_id == M88E1111_I_PHY_ID)) { + /* Vidalia Phy, set the downshift counter to 5x */ + phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK); + phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; + ret_val = em_write_phy_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + } else { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); - if(ret_val) - return ret_val; + ret_val = em_write_phy_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + } } /* SW Reset the PHY so all changes take effect */ ret_val = em_phy_reset(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error Resetting the PHY\n"); return ret_val; } @@ -1320,12 +1702,16 @@ em_copper_link_autoneg(struct em_hw *hw) /* If autoneg_advertised is zero, we assume it was not defaulted * by the calling code so we set to advertise full capability. */ - if(hw->autoneg_advertised == 0) + if (hw->autoneg_advertised == 0) hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + /* IFE phy only supports 10/100 */ + if (hw->phy_type == em_phy_ife) + hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL; + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); ret_val = em_phy_setup_autoneg(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error Setting up Auto-Negotiation\n"); return ret_val; } @@ -1335,20 +1721,20 @@ em_copper_link_autoneg(struct em_hw *hw) * the Auto Neg Restart bit in the PHY control register. */ ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; /* Does the user want to wait for Auto-Neg to complete here, or * check at a later time (for example, callback routine). */ - if(hw->wait_autoneg_complete) { + if (hw->wait_autoneg_complete) { ret_val = em_wait_autoneg(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error while waiting for autoneg to complete\n"); return ret_val; } @@ -1359,7 +1745,6 @@ em_copper_link_autoneg(struct em_hw *hw) return E1000_SUCCESS; } - /****************************************************************************** * Config the MAC and the PHY after link is up. * 1) Set up the MAC to the current PHY speed/duplex @@ -1368,7 +1753,7 @@ em_copper_link_autoneg(struct em_hw *hw) * collision distance in the Transmit Control Register. * 2) Set up flow control on the MAC to that established with * the link partner. -* 3) Config DSP to improve Gigabit link quality for some PHY revisions. +* 3) Config DSP to improve Gigabit link quality for some PHY revisions. * * hw - Struct containing variables accessed by shared code ******************************************************************************/ @@ -1377,31 +1762,31 @@ em_copper_link_postconfig(struct em_hw *hw) { int32_t ret_val; DEBUGFUNC("em_copper_link_postconfig"); - - if(hw->mac_type >= em_82544) { + + if (hw->mac_type >= em_82544) { em_config_collision_dist(hw); } else { ret_val = em_config_mac_to_phy(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error configuring MAC to PHY settings\n"); return ret_val; } } ret_val = em_config_fc_after_link_up(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error Configuring Flow Control\n"); return ret_val; } /* Config DSP to improve Giga link quality */ - if(hw->phy_type == em_phy_igp) { + if (hw->phy_type == em_phy_igp) { ret_val = em_config_dsp_after_link_change(hw, TRUE); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error Configuring DSP after link up\n"); return ret_val; } } - + return E1000_SUCCESS; } @@ -1416,37 +1801,77 @@ em_setup_copper_link(struct em_hw *hw) int32_t ret_val; uint16_t i; uint16_t phy_data; + uint16_t reg_data; DEBUGFUNC("em_setup_copper_link"); + switch (hw->mac_type) { + case em_80003es2lan: + case em_ich8lan: + /* Set the mac to wait the maximum time between each + * iteration and increase the max iterations when + * polling the phy; this fixes erroneous timeouts at 10Mbps. */ + ret_val = em_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + if (ret_val) + return ret_val; + ret_val = em_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + if (ret_val) + return ret_val; + reg_data |= 0x3F; + ret_val = em_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + if (ret_val) + return ret_val; + default: + break; + } + /* Check if it is a valid PHY and set PHY mode if necessary. */ ret_val = em_copper_link_preconfig(hw); - if(ret_val) + if (ret_val) return ret_val; + switch (hw->mac_type) { + case em_80003es2lan: + /* Kumeran registers are written-only */ + reg_data = E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT; + reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING; + ret_val = em_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL, + reg_data); + if (ret_val) + return ret_val; + break; + default: + break; + } + if (hw->phy_type == em_phy_igp || + hw->phy_type == em_phy_igp_3 || hw->phy_type == em_phy_igp_2) { ret_val = em_copper_link_igp_setup(hw); - if(ret_val) + if (ret_val) return ret_val; } else if (hw->phy_type == em_phy_m88) { ret_val = em_copper_link_mgp_setup(hw); - if(ret_val) + if (ret_val) + return ret_val; + } else if (hw->phy_type == em_phy_gg82563) { + ret_val = em_copper_link_ggp_setup(hw); + if (ret_val) return ret_val; } - if(hw->autoneg) { - /* Setup autoneg and flow control advertisement - * and perform autonegotiation */ + if (hw->autoneg) { + /* Setup autoneg and flow control advertisement + * and perform autonegotiation */ ret_val = em_copper_link_autoneg(hw); - if(ret_val) - return ret_val; + if (ret_val) + return ret_val; } else { /* PHY will be set to 10H, 10F, 100H,or 100F * depending on value from forced_speed_duplex. */ DEBUGOUT("Forcing speed and duplex\n"); ret_val = em_phy_force_speed_duplex(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error Forcing Speed and Duplex\n"); return ret_val; } @@ -1455,20 +1880,20 @@ em_setup_copper_link(struct em_hw *hw) /* Check link status. Wait up to 100 microseconds for link to become * valid. */ - for(i = 0; i < 10; i++) { + for (i = 0; i < 10; i++) { ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - if(phy_data & MII_SR_LINK_STATUS) { + if (phy_data & MII_SR_LINK_STATUS) { /* Config the MAC and PHY after link is up */ ret_val = em_copper_link_postconfig(hw); - if(ret_val) + if (ret_val) return ret_val; - + DEBUGOUT("Valid link established!!!\n"); return E1000_SUCCESS; } @@ -1480,6 +1905,79 @@ em_setup_copper_link(struct em_hw *hw) } /****************************************************************************** +* Configure the MAC-to-PHY interface for 10/100Mbps +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +static int32_t +em_configure_kmrn_for_10_100(struct em_hw *hw, uint16_t duplex) +{ + int32_t ret_val = E1000_SUCCESS; + uint32_t tipg; + uint16_t reg_data; + + DEBUGFUNC("em_configure_kmrn_for_10_100"); + + reg_data = E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT; + ret_val = em_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100; + E1000_WRITE_REG(hw, TIPG, tipg); + + ret_val = em_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + + if (ret_val) + return ret_val; + + if (duplex == HALF_DUPLEX) + reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + else + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + + ret_val = em_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + + return ret_val; +} + +static int32_t +em_configure_kmrn_for_1000(struct em_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint16_t reg_data; + uint32_t tipg; + + DEBUGFUNC("em_configure_kmrn_for_1000"); + + reg_data = E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT; + ret_val = em_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000; + E1000_WRITE_REG(hw, TIPG, tipg); + + ret_val = em_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + + if (ret_val) + return ret_val; + + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = em_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + + return ret_val; +} + +/****************************************************************************** * Configures PHY autoneg and flow control advertisement settings * * hw - Struct containing variables accessed by shared code @@ -1495,13 +1993,16 @@ em_phy_setup_autoneg(struct em_hw *hw) /* Read the MII Auto-Neg Advertisement Register (Address 4). */ ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); - if(ret_val) + if (ret_val) return ret_val; + if (hw->phy_type != em_phy_ife) { /* Read the MII 1000Base-T Control Register (Address 9). */ ret_val = em_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); - if(ret_val) + if (ret_val) return ret_val; + } else + mii_1000t_ctrl_reg=0; /* Need to parse both autoneg_advertised and fc and set up * the appropriate PHY registers. First we will parse for @@ -1520,38 +2021,41 @@ em_phy_setup_autoneg(struct em_hw *hw) DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised); /* Do we want to advertise 10 Mb Half Duplex? */ - if(hw->autoneg_advertised & ADVERTISE_10_HALF) { + if (hw->autoneg_advertised & ADVERTISE_10_HALF) { DEBUGOUT("Advertise 10mb Half duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; } /* Do we want to advertise 10 Mb Full Duplex? */ - if(hw->autoneg_advertised & ADVERTISE_10_FULL) { + if (hw->autoneg_advertised & ADVERTISE_10_FULL) { DEBUGOUT("Advertise 10mb Full duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; } /* Do we want to advertise 100 Mb Half Duplex? */ - if(hw->autoneg_advertised & ADVERTISE_100_HALF) { + if (hw->autoneg_advertised & ADVERTISE_100_HALF) { DEBUGOUT("Advertise 100mb Half duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; } /* Do we want to advertise 100 Mb Full Duplex? */ - if(hw->autoneg_advertised & ADVERTISE_100_FULL) { + if (hw->autoneg_advertised & ADVERTISE_100_FULL) { DEBUGOUT("Advertise 100mb Full duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; } /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ - if(hw->autoneg_advertised & ADVERTISE_1000_HALF) { + if (hw->autoneg_advertised & ADVERTISE_1000_HALF) { DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n"); } /* Do we want to advertise 1000 Mb Full Duplex? */ - if(hw->autoneg_advertised & ADVERTISE_1000_FULL) { + if (hw->autoneg_advertised & ADVERTISE_1000_FULL) { DEBUGOUT("Advertise 1000mb Full duplex\n"); mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + if (hw->phy_type == em_phy_ife) { + DEBUGOUT("em_phy_ife is a 10/100 PHY. Gigabit speed is not supported.\n"); + } } /* Check for a software override of the flow control settings, and @@ -1608,14 +2112,16 @@ em_phy_setup_autoneg(struct em_hw *hw) } ret_val = em_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); - if(ret_val) + if (ret_val) return ret_val; DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); - if(ret_val) - return ret_val; + if (hw->phy_type != em_phy_ife) { + ret_val = em_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + } return E1000_SUCCESS; } @@ -1654,7 +2160,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Read the MII Control Register. */ ret_val = em_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg); - if(ret_val) + if (ret_val) return ret_val; /* We need to disable autoneg in order to force link and duplex. */ @@ -1662,8 +2168,8 @@ em_phy_force_speed_duplex(struct em_hw *hw) mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN; /* Are we forcing Full or Half Duplex? */ - if(hw->forced_speed_duplex == em_100_full || - hw->forced_speed_duplex == em_10_full) { + if (hw->forced_speed_duplex == em_100_full || + hw->forced_speed_duplex == em_10_full) { /* We want to force full duplex so we SET the full duplex bits in the * Device and MII Control Registers. */ @@ -1680,7 +2186,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) } /* Are we forcing 100Mbps??? */ - if(hw->forced_speed_duplex == em_100_full || + if (hw->forced_speed_duplex == em_100_full || hw->forced_speed_duplex == em_100_half) { /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */ ctrl |= E1000_CTRL_SPD_100; @@ -1700,9 +2206,10 @@ 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 ((hw->phy_type == em_phy_m88) || + (hw->phy_type == em_phy_gg82563)) { ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI @@ -1710,32 +2217,44 @@ em_phy_force_speed_duplex(struct em_hw *hw) */ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); /* Need to reset the PHY or these changes will be ignored */ mii_ctrl_reg |= MII_CR_RESET; + /* Disable MDI-X support for 10/100 */ + } else if (hw->phy_type == em_phy_ife) { + ret_val = em_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IFE_PMC_AUTO_MDIX; + phy_data &= ~IFE_PMC_FORCE_MDIX; + + ret_val = em_write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, phy_data); + if (ret_val) + return ret_val; } else { /* Clear Auto-Crossover to force MDI manually. IGP requires MDI * forced whenever speed or duplex are forced. */ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; } /* Write back the modified PHY MII control register. */ ret_val = em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg); - if(ret_val) + if (ret_val) return ret_val; usec_delay(1); @@ -1747,49 +2266,50 @@ em_phy_force_speed_duplex(struct em_hw *hw) * only if the user has set wait_autoneg_complete to 1, which is * the default. */ - if(hw->wait_autoneg_complete) { + if (hw->wait_autoneg_complete) { /* We will wait for autoneg to complete. */ DEBUGOUT("Waiting for forced speed/duplex link.\n"); mii_status_reg = 0; /* We will wait for autoneg to complete or 4.5 seconds to expire. */ - for(i = PHY_FORCE_TIME; i > 0; i--) { + for (i = PHY_FORCE_TIME; i > 0; i--) { /* Read the MII Status Register and wait for Auto-Neg Complete bit * to be set. */ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; - if(mii_status_reg & MII_SR_LINK_STATUS) break; + if (mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } - if((i == 0) && - (hw->phy_type == em_phy_m88)) { + if ((i == 0) && + ((hw->phy_type == em_phy_m88) || + (hw->phy_type == em_phy_gg82563))) { /* We didn't get link. Reset the DSP and wait again for link. */ ret_val = em_phy_reset_dsp(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; } } /* This loop will early-out if the link condition has been met. */ - for(i = PHY_FORCE_TIME; i > 0; i--) { - if(mii_status_reg & MII_SR_LINK_STATUS) break; + for (i = PHY_FORCE_TIME; i > 0; i--) { + if (mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); /* Read the MII Status Register and wait for Auto-Neg Complete bit * to be set. */ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; } } @@ -1800,34 +2320,54 @@ em_phy_force_speed_duplex(struct em_hw *hw) * defaults back to a 2.5MHz clock when the PHY is reset. */ ret_val = em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= M88E1000_EPSCR_TX_CLK_25; ret_val = em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; /* In addition, because of the s/w reset above, we need to enable CRS on * TX. This must be set for both full and half duplex operation. */ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; - if((hw->mac_type == em_82544 || hw->mac_type == em_82543) && - (!hw->autoneg) && - (hw->forced_speed_duplex == em_10_full || - hw->forced_speed_duplex == em_10_half)) { + if ((hw->mac_type == em_82544 || hw->mac_type == em_82543) && + (!hw->autoneg) && (hw->forced_speed_duplex == em_10_full || + hw->forced_speed_duplex == em_10_half)) { ret_val = em_polarity_reversal_workaround(hw); - if(ret_val) + if (ret_val) return ret_val; } + } else if (hw->phy_type == em_phy_gg82563) { + /* The TX_CLK of the Extended PHY Specific Control Register defaults + * to 2.5MHz on a reset. We need to re-force it back to 25MHz, if + * we're not in a forced 10/duplex configuration. */ + ret_val = em_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_MSCR_TX_CLK_MASK; + if ((hw->forced_speed_duplex == em_10_full) || + (hw->forced_speed_duplex == em_10_half)) + phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ; + else + phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ; + + /* Also due to the reset, we need to enable CRS on Tx. */ + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + + ret_val = em_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; } return E1000_SUCCESS; } @@ -1843,14 +2383,19 @@ em_phy_force_speed_duplex(struct em_hw *hw) void em_config_collision_dist(struct em_hw *hw) { - uint32_t tctl; + uint32_t tctl, coll_dist; DEBUGFUNC("em_config_collision_dist"); + if (hw->mac_type < em_82543) + coll_dist = E1000_COLLISION_DISTANCE_82542; + else + coll_dist = E1000_COLLISION_DISTANCE; + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_COLD; - tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; + tctl |= coll_dist << E1000_COLD_SHIFT; E1000_WRITE_REG(hw, TCTL, tctl); E1000_WRITE_FLUSH(hw); @@ -1874,7 +2419,7 @@ em_config_mac_to_phy(struct em_hw *hw) DEBUGFUNC("em_config_mac_to_phy"); - /* 82544 or newer MAC, Auto Speed Detection takes care of + /* 82544 or newer MAC, Auto Speed Detection takes care of * MAC speed/duplex configuration.*/ if (hw->mac_type >= em_82544) return E1000_SUCCESS; @@ -1890,12 +2435,12 @@ em_config_mac_to_phy(struct em_hw *hw) * registers depending on negotiated values. */ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - if(phy_data & M88E1000_PSSR_DPLX) + if (phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD; - else + else ctrl &= ~E1000_CTRL_FD; em_config_collision_dist(hw); @@ -1903,9 +2448,9 @@ em_config_mac_to_phy(struct em_hw *hw) /* Set up speed in the Device Control register depending on * negotiated values. */ - if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) ctrl |= E1000_CTRL_SPD_1000; - else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + 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. */ @@ -1973,7 +2518,7 @@ em_force_mac_fc(struct em_hw *hw) } /* Disable TX Flow Control for 82542 (rev 2.0) */ - if(hw->mac_type == em_82542_rev2_0) + if (hw->mac_type == em_82542_rev2_0) ctrl &= (~E1000_CTRL_TFCE); E1000_WRITE_REG(hw, CTRL, ctrl); @@ -2007,11 +2552,12 @@ em_config_fc_after_link_up(struct em_hw *hw) * so we had to force link. In this case, we need to force the * configuration of the MAC to match the "fc" parameter. */ - if(((hw->media_type == em_media_type_fiber) && (hw->autoneg_failed)) || - ((hw->media_type == em_media_type_internal_serdes) && (hw->autoneg_failed)) || - ((hw->media_type == em_media_type_copper) && (!hw->autoneg))) { + if (((hw->media_type == em_media_type_fiber) && (hw->autoneg_failed)) || + ((hw->media_type == em_media_type_internal_serdes) && + (hw->autoneg_failed)) || + ((hw->media_type == em_media_type_copper) && (!hw->autoneg))) { ret_val = em_force_mac_fc(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error forcing flow control settings\n"); return ret_val; } @@ -2022,19 +2568,19 @@ em_config_fc_after_link_up(struct em_hw *hw) * has completed, and if so, how the PHY and link partner has * flow control configured. */ - if((hw->media_type == em_media_type_copper) && hw->autoneg) { + if ((hw->media_type == em_media_type_copper) && hw->autoneg) { /* Read the MII Status Register and check to see if AutoNeg * has completed. We read this twice because this reg has * some "sticky" (latched) bits. */ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; - if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + if (mii_status_reg & MII_SR_AUTONEG_COMPLETE) { /* The AutoNeg process has completed, so we now need to * read both the Auto Negotiation Advertisement Register * (Address 4) and the Auto_Negotiation Base Page Ability @@ -2043,11 +2589,11 @@ em_config_fc_after_link_up(struct em_hw *hw) */ ret_val = em_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg); - if(ret_val) + if (ret_val) return ret_val; /* Two bits in the Auto Negotiation Advertisement Register @@ -2084,20 +2630,20 @@ em_config_fc_after_link_up(struct em_hw *hw) * 1 | DC | 1 | DC | em_fc_full * */ - if((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { /* Now we need to check if the user selected RX ONLY * of pause frames. In this case, we had to advertise * FULL flow control because we could not advertise RX * ONLY. Hence, we must now check to see if we need to * turn OFF the TRANSMISSION of PAUSE frames. */ - if(hw->original_fc == em_fc_full) { + if (hw->original_fc == em_fc_full) { hw->fc = em_fc_full; - DEBUGOUT("Flow Control = FULL.\r\n"); + DEBUGOUT("Flow Control = FULL.\n"); } else { hw->fc = em_fc_rx_pause; - DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + DEBUGOUT("Flow Control = RX PAUSE frames only.\n"); } } /* For receiving PAUSE frames ONLY. @@ -2108,12 +2654,12 @@ em_config_fc_after_link_up(struct em_hw *hw) * 0 | 1 | 1 | 1 | em_fc_tx_pause * */ - else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { hw->fc = em_fc_tx_pause; - DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); + DEBUGOUT("Flow Control = TX PAUSE frames only.\n"); } /* For transmitting PAUSE frames ONLY. * @@ -2123,12 +2669,12 @@ em_config_fc_after_link_up(struct em_hw *hw) * 1 | 1 | 0 | 1 | em_fc_rx_pause * */ - else if((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { hw->fc = em_fc_rx_pause; - DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + DEBUGOUT("Flow Control = RX PAUSE frames only.\n"); } /* Per the IEEE spec, at this point flow control should be * disabled. However, we want to consider that we could @@ -2150,14 +2696,14 @@ em_config_fc_after_link_up(struct em_hw *hw) * be asked to delay transmission of packets than asking * our link partner to pause transmission of frames. */ - else if((hw->original_fc == em_fc_none || - hw->original_fc == em_fc_tx_pause) || - hw->fc_strict_ieee) { + else if ((hw->original_fc == em_fc_none || + hw->original_fc == em_fc_tx_pause) || + hw->fc_strict_ieee) { hw->fc = em_fc_none; - DEBUGOUT("Flow Control = NONE.\r\n"); + DEBUGOUT("Flow Control = NONE.\n"); } else { hw->fc = em_fc_rx_pause; - DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + DEBUGOUT("Flow Control = RX PAUSE frames only.\n"); } /* Now we need to do one last check... If we auto- @@ -2165,24 +2711,24 @@ em_config_fc_after_link_up(struct em_hw *hw) * enabled per IEEE 802.3 spec. */ ret_val = em_get_speed_and_duplex(hw, &speed, &duplex); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error getting link speed and duplex\n"); return ret_val; } - if(duplex == HALF_DUPLEX) + if (duplex == HALF_DUPLEX) hw->fc = em_fc_none; /* Now we call a subroutine to actually force the MAC * controller to use the correct flow control settings. */ ret_val = em_force_mac_fc(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error forcing flow control settings\n"); return ret_val; } } else { - DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n"); + DEBUGOUT("Copper PHY and Auto Neg has not completed.\n"); } } return E1000_SUCCESS; @@ -2216,13 +2762,13 @@ em_check_for_link(struct em_hw *hw) * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal. This applies to fiber media only. */ - if((hw->media_type == em_media_type_fiber) || - (hw->media_type == em_media_type_internal_serdes)) { + if ((hw->media_type == em_media_type_fiber) || + (hw->media_type == em_media_type_internal_serdes)) { rxcw = E1000_READ_REG(hw, RXCW); - if(hw->media_type == em_media_type_fiber) { + if (hw->media_type == em_media_type_fiber) { signal = (hw->mac_type > em_82544) ? E1000_CTRL_SWDPIN1 : 0; - if(status & E1000_STATUS_LU) + if (status & E1000_STATUS_LU) hw->get_link_status = FALSE; } } @@ -2233,20 +2779,20 @@ em_check_for_link(struct em_hw *hw) * receive a Link Status Change interrupt or we have Rx Sequence * Errors. */ - if((hw->media_type == em_media_type_copper) && hw->get_link_status) { + if ((hw->media_type == em_media_type_copper) && hw->get_link_status) { /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex * of the PHY. * Read the register twice since the link bit is sticky. */ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - if(phy_data & MII_SR_LINK_STATUS) { + if (phy_data & MII_SR_LINK_STATUS) { hw->get_link_status = FALSE; /* Check if there was DownShift, must be checked immediately after * link-up */ @@ -2260,10 +2806,10 @@ em_check_for_link(struct em_hw *hw) * happen due to the execution of this workaround. */ - if((hw->mac_type == em_82544 || hw->mac_type == em_82543) && - (!hw->autoneg) && - (hw->forced_speed_duplex == em_10_full || - hw->forced_speed_duplex == em_10_half)) { + if ((hw->mac_type == em_82544 || hw->mac_type == em_82543) && + (!hw->autoneg) && + (hw->forced_speed_duplex == em_10_full || + hw->forced_speed_duplex == em_10_half)) { E1000_WRITE_REG(hw, IMC, 0xffffffff); ret_val = em_polarity_reversal_workaround(hw); icr = E1000_READ_REG(hw, ICR); @@ -2280,7 +2826,7 @@ em_check_for_link(struct em_hw *hw) /* If we are forcing speed/duplex, then we simply return since * we have already determined whether we have link or not. */ - if(!hw->autoneg) return -E1000_ERR_CONFIG; + if (!hw->autoneg) return -E1000_ERR_CONFIG; /* optimize the dsp settings for the igp phy */ em_config_dsp_after_link_change(hw, TRUE); @@ -2293,11 +2839,11 @@ em_check_for_link(struct em_hw *hw) * speed/duplex on the MAC to the current PHY speed/duplex * settings. */ - if(hw->mac_type >= em_82544) + if (hw->mac_type >= em_82544) em_config_collision_dist(hw); else { ret_val = em_config_mac_to_phy(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error configuring MAC to PHY settings\n"); return ret_val; } @@ -2308,7 +2854,7 @@ em_check_for_link(struct em_hw *hw) * have had to re-autoneg with a different link partner. */ ret_val = em_config_fc_after_link_up(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error configuring flow control\n"); return ret_val; } @@ -2320,14 +2866,18 @@ em_check_for_link(struct em_hw *hw) * at gigabit speed, then TBI compatibility is not needed. If we are * at gigabit speed, we turn on TBI compatibility. */ - if(hw->tbi_compatibility_en) { + if (hw->tbi_compatibility_en) { uint16_t speed, duplex; - em_get_speed_and_duplex(hw, &speed, &duplex); - if(speed != SPEED_1000) { + ret_val = em_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + DEBUGOUT("Error getting link speed and duplex\n"); + return ret_val; + } + if (speed != SPEED_1000) { /* If link speed is not set to gigabit speed, we do not need * to enable TBI compatibility. */ - if(hw->tbi_compatibility_on) { + if (hw->tbi_compatibility_on) { /* If we previously were in the mode, turn it off. */ rctl = E1000_READ_REG(hw, RCTL); rctl &= ~E1000_RCTL_SBP; @@ -2340,7 +2890,7 @@ em_check_for_link(struct em_hw *hw) * packets. Some frames have an additional byte on the end and * will look like CRC errors to to the hardware. */ - if(!hw->tbi_compatibility_on) { + if (!hw->tbi_compatibility_on) { hw->tbi_compatibility_on = TRUE; rctl = E1000_READ_REG(hw, RCTL); rctl |= E1000_RCTL_SBP; @@ -2356,16 +2906,16 @@ em_check_for_link(struct em_hw *hw) * auto-negotiation time to complete, in case the cable was just plugged * in. The autoneg_failed flag does this. */ - else if((((hw->media_type == em_media_type_fiber) && + else if ((((hw->media_type == em_media_type_fiber) && ((ctrl & E1000_CTRL_SWDPIN1) == signal)) || - (hw->media_type == em_media_type_internal_serdes)) && - (!(status & E1000_STATUS_LU)) && - (!(rxcw & E1000_RXCW_C))) { - if(hw->autoneg_failed == 0) { + (hw->media_type == em_media_type_internal_serdes)) && + (!(status & E1000_STATUS_LU)) && + (!(rxcw & E1000_RXCW_C))) { + if (hw->autoneg_failed == 0) { hw->autoneg_failed = 1; return 0; } - DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n"); + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); /* Disable auto-negotiation in the TXCW register */ E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE)); @@ -2377,7 +2927,7 @@ em_check_for_link(struct em_hw *hw) /* Configure Flow Control after forcing link up. */ ret_val = em_config_fc_after_link_up(hw); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error configuring flow control\n"); return ret_val; } @@ -2387,10 +2937,10 @@ em_check_for_link(struct em_hw *hw) * Device Control register in an attempt to auto-negotiate with our link * partner. */ - else if(((hw->media_type == em_media_type_fiber) || - (hw->media_type == em_media_type_internal_serdes)) && - (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); + else if (((hw->media_type == em_media_type_fiber) || + (hw->media_type == em_media_type_internal_serdes)) && + (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { + DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); @@ -2399,12 +2949,12 @@ em_check_for_link(struct em_hw *hw) /* If we force link for non-auto-negotiation switch, check link status * based on MAC synchronization for internal serdes media type. */ - else if((hw->media_type == em_media_type_internal_serdes) && - !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + else if ((hw->media_type == em_media_type_internal_serdes) && + !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { /* SYNCH bit and IV bit are sticky. */ usec_delay(10); - if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { - if(!(rxcw & E1000_RXCW_IV)) { + if (E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { + if (!(rxcw & E1000_RXCW_IV)) { hw->serdes_link_down = FALSE; DEBUGOUT("SERDES: Link is up.\n"); } @@ -2413,8 +2963,8 @@ em_check_for_link(struct em_hw *hw) DEBUGOUT("SERDES: Link is down.\n"); } } - if((hw->media_type == em_media_type_internal_serdes) && - (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + if ((hw->media_type == em_media_type_internal_serdes) && + (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS)); } return E1000_SUCCESS; @@ -2438,12 +2988,12 @@ em_get_speed_and_duplex(struct em_hw *hw, DEBUGFUNC("em_get_speed_and_duplex"); - if(hw->mac_type >= em_82543) { + if (hw->mac_type >= em_82543) { status = E1000_READ_REG(hw, STATUS); - if(status & E1000_STATUS_SPEED_1000) { + if (status & E1000_STATUS_SPEED_1000) { *speed = SPEED_1000; DEBUGOUT("1000 Mbs, "); - } else if(status & E1000_STATUS_SPEED_100) { + } else if (status & E1000_STATUS_SPEED_100) { *speed = SPEED_100; DEBUGOUT("100 Mbs, "); } else { @@ -2451,15 +3001,15 @@ em_get_speed_and_duplex(struct em_hw *hw, DEBUGOUT("10 Mbs, "); } - if(status & E1000_STATUS_FD) { + if (status & E1000_STATUS_FD) { *duplex = FULL_DUPLEX; - DEBUGOUT("Full Duplex\r\n"); + DEBUGOUT("Full Duplex\n"); } else { *duplex = HALF_DUPLEX; - DEBUGOUT(" Half Duplex\r\n"); + DEBUGOUT(" Half Duplex\n"); } } else { - DEBUGOUT("1000 Mbs, Full Duplex\r\n"); + DEBUGOUT("1000 Mbs, Full Duplex\n"); *speed = SPEED_1000; *duplex = FULL_DUPLEX; } @@ -2468,23 +3018,39 @@ em_get_speed_and_duplex(struct em_hw *hw, * if it is operating at half duplex. Here we set the duplex settings to * match the duplex in the link partner's capabilities. */ - if(hw->phy_type == em_phy_igp && hw->speed_downgraded) { + if (hw->phy_type == em_phy_igp && hw->speed_downgraded) { ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - if(!(phy_data & NWAY_ER_LP_NWAY_CAPS)) + if (!(phy_data & NWAY_ER_LP_NWAY_CAPS)) *duplex = HALF_DUPLEX; else { ret_val = em_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) || + if ((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) || (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS))) *duplex = HALF_DUPLEX; } } + if ((hw->mac_type == em_80003es2lan) && + (hw->media_type == em_media_type_copper)) { + if (*speed == SPEED_1000) + ret_val = em_configure_kmrn_for_1000(hw); + else + ret_val = em_configure_kmrn_for_10_100(hw, *duplex); + if (ret_val) + return ret_val; + } + + if ((hw->phy_type == em_phy_igp_3) && (*speed == SPEED_1000)) { + ret_val = em_kumeran_lock_loss_workaround(hw); + if (ret_val) + return ret_val; + } + return E1000_SUCCESS; } @@ -2504,17 +3070,17 @@ em_wait_autoneg(struct em_hw *hw) DEBUGOUT("Waiting for Auto-Neg to complete.\n"); /* We will wait for autoneg to complete or 4.5 seconds to expire. */ - for(i = PHY_AUTO_NEG_TIME; i > 0; i--) { + for (i = PHY_AUTO_NEG_TIME; i > 0; i--) { /* Read the MII Status Register and wait for Auto-Neg * Complete bit to be set. */ ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - if(phy_data & MII_SR_AUTONEG_COMPLETE) { + if (phy_data & MII_SR_AUTONEG_COMPLETE) { return E1000_SUCCESS; } msec_delay(100); @@ -2587,14 +3153,16 @@ em_shift_out_mdi_bits(struct em_hw *hw, /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */ ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); - while(mask) { + while (mask) { /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and * then raising and lowering the Management Data Clock. A "0" is * shifted out to the PHY by setting the MDIO bit to "0" and then * raising and lowering the clock. */ - if(data & mask) ctrl |= E1000_CTRL_MDIO; - else ctrl &= ~E1000_CTRL_MDIO; + if (data & mask) + ctrl |= E1000_CTRL_MDIO; + else + ctrl &= ~E1000_CTRL_MDIO; E1000_WRITE_REG(hw, CTRL, ctrl); E1000_WRITE_FLUSH(hw); @@ -2645,12 +3213,13 @@ em_shift_in_mdi_bits(struct em_hw *hw) em_raise_mdi_clk(hw, &ctrl); em_lower_mdi_clk(hw, &ctrl); - for(data = 0, i = 0; i < 16; i++) { + for (data = 0, i = 0; i < 16; i++) { data = data << 1; em_raise_mdi_clk(hw, &ctrl); ctrl = E1000_READ_REG(hw, CTRL); /* Check to see if we shifted in a "1". */ - if(ctrl & E1000_CTRL_MDIO) data |= 1; + if (ctrl & E1000_CTRL_MDIO) + data |= 1; em_lower_mdi_clk(hw, &ctrl); } @@ -2660,6 +3229,80 @@ em_shift_in_mdi_bits(struct em_hw *hw) return data; } +int32_t +em_swfw_sync_acquire(struct em_hw *hw, uint16_t mask) +{ + uint32_t swfw_sync = 0; + uint32_t swmask = mask; + uint32_t fwmask = mask << 16; + int32_t timeout = 200; + + DEBUGFUNC("em_swfw_sync_acquire"); + + if (hw->swfwhw_semaphore_present) + return em_get_software_flag(hw); + + if (!hw->swfw_sync_present) + return em_get_hw_eeprom_semaphore(hw); + + while (timeout) { + if (em_get_hw_eeprom_semaphore(hw)) + return -E1000_ERR_SWFW_SYNC; + + swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) { + break; + } + + /* firmware currently using resource (fwmask) */ + /* or other software thread currently using resource (swmask) */ + em_put_hw_eeprom_semaphore(hw); + msec_delay_irq(5); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); + return -E1000_ERR_SWFW_SYNC; + } + + swfw_sync |= swmask; + E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync); + + em_put_hw_eeprom_semaphore(hw); + return E1000_SUCCESS; +} + +void +em_swfw_sync_release(struct em_hw *hw, uint16_t mask) +{ + uint32_t swfw_sync; + uint32_t swmask = mask; + + DEBUGFUNC("em_swfw_sync_release"); + + if (hw->swfwhw_semaphore_present) { + em_release_software_flag(hw); + return; + } + + if (!hw->swfw_sync_present) { + em_put_hw_eeprom_semaphore(hw); + return; + } + + /* if (em_get_hw_eeprom_semaphore(hw)) + * return -E1000_ERR_SWFW_SYNC; */ + while (em_get_hw_eeprom_semaphore(hw) != E1000_SUCCESS); + /* empty */ + + swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC); + swfw_sync &= ~swmask; + E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync); + + em_put_hw_eeprom_semaphore(hw); +} + /***************************************************************************** * Reads the value from a PHY register, if the value is on a specific non zero * page, sets the page first. @@ -2672,22 +3315,56 @@ em_read_phy_reg(struct em_hw *hw, uint16_t *phy_data) { uint32_t ret_val; + uint16_t swfw; DEBUGFUNC("em_read_phy_reg"); - if((hw->phy_type == em_phy_igp || + if ((hw->mac_type == em_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (em_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + if ((hw->phy_type == em_phy_igp || + hw->phy_type == em_phy_igp_3 || hw->phy_type == em_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); - if(ret_val) { + if (ret_val) { + em_swfw_sync_release(hw, swfw); return ret_val; } + } else if (hw->phy_type == em_phy_gg82563) { + if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) || + (hw->mac_type == em_80003es2lan)) { + /* Select Configuration Page */ + if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + ret_val = em_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } else { + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + ret_val = em_write_phy_reg_ex(hw, + GG82563_PHY_PAGE_SELECT_ALT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } + + if (ret_val) { + em_swfw_sync_release(hw, swfw); + return ret_val; + } + } } ret_val = em_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr, phy_data); + em_swfw_sync_release(hw, swfw); return ret_val; } @@ -2702,12 +3379,12 @@ em_read_phy_reg_ex(struct em_hw *hw, DEBUGFUNC("em_read_phy_reg_ex"); - if(reg_addr > MAX_PHY_REG_ADDRESS) { + if (reg_addr > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); return -E1000_ERR_PARAM; } - if(hw->mac_type > em_82543) { + if (hw->mac_type > em_82543) { /* Set up Op-code, Phy Address, and register address in the MDI * Control register. The MAC will take care of interfacing with the * PHY to retrieve the desired data. @@ -2719,16 +3396,16 @@ em_read_phy_reg_ex(struct em_hw *hw, E1000_WRITE_REG(hw, MDIC, mdic); /* Poll the ready bit to see if the MDI read completed */ - for(i = 0; i < 64; i++) { + for (i = 0; i < 64; i++) { usec_delay(50); mdic = E1000_READ_REG(hw, MDIC); - if(mdic & E1000_MDIC_READY) break; + if (mdic & E1000_MDIC_READY) break; } - if(!(mdic & E1000_MDIC_READY)) { + if (!(mdic & E1000_MDIC_READY)) { DEBUGOUT("MDI Read did not complete\n"); return -E1000_ERR_PHY; } - if(mdic & E1000_MDIC_ERROR) { + if (mdic & E1000_MDIC_ERROR) { DEBUGOUT("MDI Error\n"); return -E1000_ERR_PHY; } @@ -2778,22 +3455,56 @@ em_write_phy_reg(struct em_hw *hw, uint16_t phy_data) { uint32_t ret_val; + uint16_t swfw; DEBUGFUNC("em_write_phy_reg"); - if((hw->phy_type == em_phy_igp || + if ((hw->mac_type == em_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (em_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + if ((hw->phy_type == em_phy_igp || + hw->phy_type == em_phy_igp_3 || hw->phy_type == em_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); - if(ret_val) { + if (ret_val) { + em_swfw_sync_release(hw, swfw); return ret_val; } + } else if (hw->phy_type == em_phy_gg82563) { + if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) || + (hw->mac_type == em_80003es2lan)) { + /* Select Configuration Page */ + if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + ret_val = em_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } else { + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + ret_val = em_write_phy_reg_ex(hw, + GG82563_PHY_PAGE_SELECT_ALT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } + + if (ret_val) { + em_swfw_sync_release(hw, swfw); + return ret_val; + } + } } ret_val = em_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr, phy_data); + em_swfw_sync_release(hw, swfw); return ret_val; } @@ -2808,12 +3519,12 @@ em_write_phy_reg_ex(struct em_hw *hw, DEBUGFUNC("em_write_phy_reg_ex"); - if(reg_addr > MAX_PHY_REG_ADDRESS) { + if (reg_addr > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); return -E1000_ERR_PARAM; } - if(hw->mac_type > em_82543) { + if (hw->mac_type > em_82543) { /* Set up Op-code, Phy Address, register address, and data intended * for the PHY register in the MDI Control register. The MAC will take * care of interfacing with the PHY to send the desired data. @@ -2826,12 +3537,12 @@ em_write_phy_reg_ex(struct em_hw *hw, E1000_WRITE_REG(hw, MDIC, mdic); /* Poll the ready bit to see if the MDI read completed */ - for(i = 0; i < 640; i++) { + for (i = 0; i < 641; i++) { usec_delay(5); mdic = E1000_READ_REG(hw, MDIC); - if(mdic & E1000_MDIC_READY) break; + if (mdic & E1000_MDIC_READY) break; } - if(!(mdic & E1000_MDIC_READY)) { + if (!(mdic & E1000_MDIC_READY)) { DEBUGOUT("MDI Write did not complete\n"); return -E1000_ERR_PHY; } @@ -2860,6 +3571,65 @@ em_write_phy_reg_ex(struct em_hw *hw, return E1000_SUCCESS; } +int32_t +em_read_kmrn_reg(struct em_hw *hw, + uint32_t reg_addr, + uint16_t *data) +{ + uint32_t reg_val; + uint16_t swfw; + DEBUGFUNC("em_read_kmrn_reg"); + + if ((hw->mac_type == em_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (em_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + /* Write register address */ + reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) & + E1000_KUMCTRLSTA_OFFSET) | + E1000_KUMCTRLSTA_REN; + E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val); + usec_delay(2); + + /* Read the data returned */ + reg_val = E1000_READ_REG(hw, KUMCTRLSTA); + *data = (uint16_t)reg_val; + + em_swfw_sync_release(hw, swfw); + return E1000_SUCCESS; +} + +int32_t +em_write_kmrn_reg(struct em_hw *hw, + uint32_t reg_addr, + uint16_t data) +{ + uint32_t reg_val; + uint16_t swfw; + DEBUGFUNC("em_write_kmrn_reg"); + + if ((hw->mac_type == em_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (em_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) & + E1000_KUMCTRLSTA_OFFSET) | data; + E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val); + usec_delay(2); + + em_swfw_sync_release(hw, swfw); + return E1000_SUCCESS; +} /****************************************************************************** * Returns the PHY to the power-on reset state @@ -2872,6 +3642,7 @@ em_phy_hw_reset(struct em_hw *hw) uint32_t ctrl, ctrl_ext; uint32_t led_ctrl; int32_t ret_val; + uint16_t swfw; DEBUGFUNC("em_phy_hw_reset"); @@ -2883,16 +3654,38 @@ em_phy_hw_reset(struct em_hw *hw) DEBUGOUT("Resetting Phy...\n"); - if(hw->mac_type > em_82543) { + if (hw->mac_type > em_82543) { + if ((hw->mac_type == em_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (em_swfw_sync_acquire(hw, swfw)) { + em_release_software_semaphore(hw); + return -E1000_ERR_SWFW_SYNC; + } /* Read the device control register and assert the E1000_CTRL_PHY_RST * bit. Then, take it out of reset. + * For pre-em_82571 hardware, we delay for 10ms between the assert + * and deassert. For em_82571 hardware and later, we instead delay + * for 50us between and 10ms after the deassertion. */ ctrl = E1000_READ_REG(hw, CTRL); E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST); E1000_WRITE_FLUSH(hw); - msec_delay(10); + + if (hw->mac_type < em_82571) + msec_delay(10); + else + usec_delay(100); + E1000_WRITE_REG(hw, CTRL, ctrl); E1000_WRITE_FLUSH(hw); + + if (hw->mac_type >= em_82571) + msec_delay_irq(10); + em_swfw_sync_release(hw, swfw); } else { /* Read the Extended Device Control Register, assert the PHY_RESET_DIR * bit to put the PHY into reset. Then, take it out of reset. @@ -2909,7 +3702,7 @@ em_phy_hw_reset(struct em_hw *hw) } usec_delay(150); - if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { + if ((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) { /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; @@ -2919,6 +3712,12 @@ em_phy_hw_reset(struct em_hw *hw) /* Wait for FW to finish PHY configuration. */ ret_val = em_get_phy_cfg_done(hw); + if (ret_val != E1000_SUCCESS) + return ret_val; + em_release_software_semaphore(hw); + + if ((hw->mac_type == em_ich8lan) && (hw->phy_type == em_phy_igp_3)) + ret_val = em_init_lcd_from_nvm(hw); return ret_val; } @@ -2946,31 +3745,144 @@ em_phy_reset(struct em_hw *hw) switch (hw->mac_type) { case em_82541_rev_2: + case em_82571: + case em_82572: + case em_ich8lan: ret_val = em_phy_hw_reset(hw); - if(ret_val) + if (ret_val) return ret_val; + break; default: ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= MII_CR_RESET; ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data); - if(ret_val) + if (ret_val) return ret_val; usec_delay(1); break; } - if(hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2) + if (hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2) em_phy_init_script(hw); return E1000_SUCCESS; } /****************************************************************************** +* Work-around for 82566 power-down: on D3 entry- +* 1) disable gigabit link +* 2) write VR power-down enable +* 3) read it back +* if successful continue, else issue LCD reset and repeat +* +* hw - struct containing variables accessed by shared code +******************************************************************************/ +void +em_phy_powerdown_workaround(struct em_hw *hw) +{ + int32_t reg; + uint16_t phy_data; + int32_t retry = 0; + + DEBUGFUNC("em_phy_powerdown_workaround"); + + if (hw->phy_type != em_phy_igp_3) + return; + + do { + /* Disable link */ + reg = E1000_READ_REG(hw, PHY_CTRL); + E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + + /* Write VR power-down enable */ + em_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data); + em_write_phy_reg(hw, IGP3_VR_CTRL, phy_data | + IGP3_VR_CTRL_MODE_SHUT); + + /* Read it back and test */ + em_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data); + if ((phy_data & IGP3_VR_CTRL_MODE_SHUT) || retry) + break; + + /* Issue PHY reset and repeat at most one more time */ + reg = E1000_READ_REG(hw, CTRL); + E1000_WRITE_REG(hw, CTRL, reg | E1000_CTRL_PHY_RST); + retry++; + } while (retry); + + return; + +} + +/****************************************************************************** +* Work-around for 82566 Kumeran PCS lock loss: +* On link status change (i.e. PCI reset, speed change) and link is up and +* speed is gigabit- +* 0) if workaround is optionally disabled do nothing +* 1) wait 1ms for Kumeran link to come up +* 2) check Kumeran Diagnostic register PCS lock loss bit +* 3) if not set the link is locked (all is good), otherwise... +* 4) reset the PHY +* 5) repeat up to 10 times +* Note: this is only called for IGP3 copper when speed is 1gb. +* +* hw - struct containing variables accessed by shared code +******************************************************************************/ +int32_t +em_kumeran_lock_loss_workaround(struct em_hw *hw) +{ + int32_t ret_val; + int32_t reg; + int32_t cnt; + uint16_t phy_data; + + if (hw->kmrn_lock_loss_workaround_disabled) + return E1000_SUCCESS; + + /* Make sure link is up before proceeding. If not just return. + * Attempting this while link is negotiating fouled up link + * stability */ + ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); + ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); + + if (phy_data & MII_SR_LINK_STATUS) { + for (cnt = 0; cnt < 10; cnt++) { + /* read once to clear */ + ret_val = em_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data); + if (ret_val) + return ret_val; + /* and again to get new status */ + ret_val = em_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data); + if (ret_val) + return ret_val; + + /* check for PCS lock */ + if (!(phy_data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) + return E1000_SUCCESS; + + /* Issue PHY reset */ + em_phy_hw_reset(hw); + msec_delay_irq(5); + } + /* Disable GigE link negotiation */ + reg = E1000_READ_REG(hw, PHY_CTRL); + E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + + /* unable to acquire PCS lock */ + return E1000_ERR_PHY; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** * Probes the expected PHY address for known PHY IDs * * hw - Struct containing variables accessed by shared code @@ -2984,42 +3896,70 @@ em_detect_gig_phy(struct em_hw *hw) DEBUGFUNC("em_detect_gig_phy"); + /* The 82571 firmware may still be configuring the PHY. In this + * case, we cannot access the PHY until the configuration is done. So + * we explicitly set the PHY values. */ + if (hw->mac_type == em_82571 || + hw->mac_type == em_82572) { + hw->phy_id = IGP01E1000_I_PHY_ID; + hw->phy_type = em_phy_igp_2; + return E1000_SUCCESS; + } + + /* ESB-2 PHY reads require em_phy_gg82563 to be set because of a work- + * around that forces PHY page 0 to be set or the reads fail. The rest of + * the code in this routine uses em_read_phy_reg to read the PHY ID. + * So for ESB-2 we need to have this set so our reads won't fail. If the + * attached PHY is not a em_phy_gg82563, the routines below will figure + * this out as well. */ + if (hw->mac_type == em_80003es2lan) + hw->phy_type = em_phy_gg82563; + /* Read the PHY ID Registers to identify which PHY is onboard. */ ret_val = em_read_phy_reg(hw, PHY_ID1, &phy_id_high); - if(ret_val) + if (ret_val) return ret_val; hw->phy_id = (uint32_t) (phy_id_high << 16); usec_delay(20); ret_val = em_read_phy_reg(hw, PHY_ID2, &phy_id_low); - if(ret_val) + if (ret_val) return ret_val; hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK); hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK; - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82543: - if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE; + if (hw->phy_id == M88E1000_E_PHY_ID) match = TRUE; break; case em_82544: - if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE; + if (hw->phy_id == M88E1000_I_PHY_ID) match = TRUE; break; case em_82540: case em_82545: case em_82545_rev_3: case em_82546: case em_82546_rev_3: - if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE; + if (hw->phy_id == M88E1011_I_PHY_ID) match = TRUE; break; case em_82541: case em_82541_rev_2: case em_82547: case em_82547_rev_2: - if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; + if (hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; break; case em_82573: - if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE; + if (hw->phy_id == M88E1111_I_PHY_ID) match = TRUE; + break; + case em_80003es2lan: + if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE; + break; + case em_ich8lan: + if (hw->phy_id == IGP03E1000_E_PHY_ID) match = TRUE; + if (hw->phy_id == IFE_E_PHY_ID) match = TRUE; + if (hw->phy_id == IFE_PLUS_E_PHY_ID) match = TRUE; + if (hw->phy_id == IFE_C_E_PHY_ID) match = TRUE; break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); @@ -3047,14 +3987,16 @@ em_phy_reset_dsp(struct em_hw *hw) DEBUGFUNC("em_phy_reset_dsp"); do { - ret_val = em_write_phy_reg(hw, 29, 0x001d); - if(ret_val) break; + if (hw->phy_type != em_phy_gg82563) { + ret_val = em_write_phy_reg(hw, 29, 0x001d); + if (ret_val) break; + } ret_val = em_write_phy_reg(hw, 30, 0x00c1); - if(ret_val) break; + if (ret_val) break; ret_val = em_write_phy_reg(hw, 30, 0x0000); - if(ret_val) break; + if (ret_val) break; ret_val = E1000_SUCCESS; - } while(0); + } while (0); return ret_val; } @@ -3086,23 +4028,23 @@ em_phy_igp_get_info(struct em_hw *hw, /* Check polarity status */ ret_val = em_check_polarity(hw, &polarity); - if(ret_val) + if (ret_val) return ret_val; phy_info->cable_polarity = polarity; ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >> IGP01E1000_PSSR_MDIX_SHIFT; - if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_1000MBPS) { /* Local/Remote Receiver Information are only valid at 1000 Mbps */ ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> @@ -3112,19 +4054,19 @@ em_phy_igp_get_info(struct em_hw *hw, /* Get cable length */ ret_val = em_get_cable_length(hw, &min_length, &max_length); - if(ret_val) + if (ret_val) return ret_val; /* Translate to old method */ average = (max_length + min_length) / 2; - if(average <= em_igp_cable_length_50) + if (average <= em_igp_cable_length_50) phy_info->cable_length = em_cable_length_50; - else if(average <= em_igp_cable_length_80) + 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) + 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) + 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; @@ -3134,6 +4076,53 @@ em_phy_igp_get_info(struct em_hw *hw, } /****************************************************************************** +* Get PHY information from various PHY registers for ife PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +em_phy_ife_get_info(struct em_hw *hw, + struct em_phy_info *phy_info) +{ + int32_t ret_val; + uint16_t phy_data, polarity; + + DEBUGFUNC("em_phy_ife_get_info"); + + phy_info->downshift = (em_downshift)hw->speed_downgraded; + phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_normal; + + ret_val = em_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data); + if (ret_val) + return ret_val; + phy_info->polarity_correction = + (phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >> + IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT; + + if (phy_info->polarity_correction == em_polarity_reversal_enabled) { + ret_val = em_check_polarity(hw, &polarity); + if (ret_val) + return ret_val; + } else { + /* Polarity is forced. */ + polarity = (phy_data & IFE_PSC_FORCE_POLARITY) >> + IFE_PSC_FORCE_POLARITY_SHIFT; + } + phy_info->cable_polarity = polarity; + + ret_val = em_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_info->mdix_mode = + (phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >> + IFE_PMC_MDIX_MODE_SHIFT; + + return E1000_SUCCESS; +} + +/****************************************************************************** * Get PHY information from various PHY registers fot m88 PHY only. * * hw - Struct containing variables accessed by shared code @@ -3153,7 +4142,7 @@ em_phy_m88_get_info(struct em_hw *hw, phy_info->downshift = (em_downshift)hw->speed_downgraded; ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_info->extended_10bt_distance = @@ -3165,12 +4154,12 @@ em_phy_m88_get_info(struct em_hw *hw, /* Check polarity status */ ret_val = em_check_polarity(hw, &polarity); - if(ret_val) - return ret_val; + if (ret_val) + return ret_val; phy_info->cable_polarity = polarity; ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> @@ -3180,11 +4169,20 @@ em_phy_m88_get_info(struct em_hw *hw, /* Cable Length Estimation and Local/Remote Receiver Information * are only valid at 1000 Mbps. */ - phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT); + if (hw->phy_type != em_phy_gg82563) { + phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + } else { + ret_val = em_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE, + &phy_data); + if (ret_val) + return ret_val; + + phy_info->cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH; + } ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> @@ -3221,27 +4219,30 @@ em_phy_get_info(struct em_hw *hw, phy_info->local_rx = em_1000t_rx_status_undefined; phy_info->remote_rx = em_1000t_rx_status_undefined; - if(hw->media_type != em_media_type_copper) { + if (hw->media_type != em_media_type_copper) { DEBUGOUT("PHY info is only valid for copper media\n"); return -E1000_ERR_CONFIG; } ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) { + if ((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) { DEBUGOUT("PHY info is only valid if link is up\n"); return -E1000_ERR_CONFIG; } - if(hw->phy_type == em_phy_igp || + if (hw->phy_type == em_phy_igp || + hw->phy_type == em_phy_igp_3 || hw->phy_type == em_phy_igp_2) return em_phy_igp_get_info(hw, phy_info); + else if (hw->phy_type == em_phy_ife) + return em_phy_ife_get_info(hw, phy_info); else return em_phy_m88_get_info(hw, phy_info); } @@ -3251,7 +4252,7 @@ em_validate_mdi_setting(struct em_hw *hw) { DEBUGFUNC("em_validate_mdi_settings"); - if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) { + if (!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) { DEBUGOUT("Invalid MDI setting detected\n"); hw->mdix = 1; return -E1000_ERR_CONFIG; @@ -3262,7 +4263,8 @@ em_validate_mdi_setting(struct em_hw *hw) /****************************************************************************** * Sets up eeprom variables in the hw struct. Must be called after mac_type - * is configured. + * is configured. Additionally, if this is ICH8, the flash controller GbE + * registers must be mapped, or this will crash. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ @@ -3297,7 +4299,7 @@ em_init_eeprom_params(struct em_hw *hw) eeprom->type = em_eeprom_microwire; eeprom->opcode_bits = 3; eeprom->delay_usec = 50; - if(eecd & E1000_EECD_SIZE) { + if (eecd & E1000_EECD_SIZE) { eeprom->word_size = 256; eeprom->address_bits = 8; } else { @@ -3337,6 +4339,21 @@ em_init_eeprom_params(struct em_hw *hw) eeprom->use_eerd = FALSE; eeprom->use_eewr = FALSE; break; + case em_82571: + case em_82572: + 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; + } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + break; case em_82573: eeprom->type = em_eeprom_spi; eeprom->opcode_bits = 8; @@ -3350,7 +4367,7 @@ em_init_eeprom_params(struct em_hw *hw) } eeprom->use_eerd = TRUE; eeprom->use_eewr = TRUE; - if(em_is_onboard_nvm_eeprom(hw) == FALSE) { + if (em_is_onboard_nvm_eeprom(hw) == FALSE) { eeprom->type = em_eeprom_flash; eeprom->word_size = 2048; @@ -3360,6 +4377,49 @@ em_init_eeprom_params(struct em_hw *hw) E1000_WRITE_REG(hw, EECD, eecd); } break; + case em_80003es2lan: + 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; + } + eeprom->use_eerd = TRUE; + eeprom->use_eewr = FALSE; + break; + case em_ich8lan: + { + int32_t i = 0; + uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG); + + eeprom->type = em_eeprom_ich8; + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + eeprom->word_size = E1000_SHADOW_RAM_WORDS; + + /* Zero the shadow RAM structure. But don't load it from NVM + * so as to save time for driver init */ + if (hw->eeprom_shadow_ram != NULL) { + for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { + hw->eeprom_shadow_ram[i].modified = FALSE; + hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF; + } + } + + hw->flash_base_addr = (flash_size & ICH8_GFPREG_BASE_MASK) * + ICH8_FLASH_SECTOR_SIZE; + + hw->flash_bank_size = ((flash_size >> 16) & ICH8_GFPREG_BASE_MASK) + 1; + hw->flash_bank_size -= (flash_size & ICH8_GFPREG_BASE_MASK); + hw->flash_bank_size *= ICH8_FLASH_SECTOR_SIZE; + hw->flash_bank_size /= 2 * sizeof(uint16_t); + + break; + } default: break; } @@ -3368,17 +4428,17 @@ em_init_eeprom_params(struct em_hw *hw) /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to * 32KB (incremented by powers of 2). */ - if(hw->mac_type <= em_82547_rev_2) { + if (hw->mac_type <= em_82547_rev_2) { /* Set to default value for initial eeprom read. */ eeprom->word_size = 64; ret_val = em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size); - if(ret_val) + if (ret_val) return ret_val; eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT; /* 256B eeprom size was not supported in earlier hardware, so we * bump eeprom_size up one to ensure that "1" (which maps to 256B) * is never the result used in the shifting logic below. */ - if(eeprom_size) + if (eeprom_size) eeprom_size++; } else { eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >> @@ -3463,7 +4523,7 @@ em_shift_out_ee_bits(struct em_hw *hw, */ eecd &= ~E1000_EECD_DI; - if(data & mask) + if (data & mask) eecd |= E1000_EECD_DI; E1000_WRITE_REG(hw, EECD, eecd); @@ -3476,7 +4536,7 @@ em_shift_out_ee_bits(struct em_hw *hw, mask = mask >> 1; - } while(mask); + } while (mask); /* We leave the "DI" bit set to "0" when we leave this routine. */ eecd &= ~E1000_EECD_DI; @@ -3508,14 +4568,14 @@ em_shift_in_ee_bits(struct em_hw *hw, eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); data = 0; - for(i = 0; i < count; i++) { + for (i = 0; i < count; i++) { data = data << 1; em_raise_ee_clk(hw, &eecd); eecd = E1000_READ_REG(hw, EECD); eecd &= ~(E1000_EECD_DI); - if(eecd & E1000_EECD_DO) + if (eecd & E1000_EECD_DO) data |= 1; em_lower_ee_clk(hw, &eecd); @@ -3540,31 +4600,31 @@ em_acquire_eeprom(struct em_hw *hw) DEBUGFUNC("em_acquire_eeprom"); - if(em_get_hw_eeprom_semaphore(hw)) - return -E1000_ERR_EEPROM; - + if (em_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM)) + return -E1000_ERR_SWFW_SYNC; eecd = E1000_READ_REG(hw, EECD); if (hw->mac_type != em_82573) { - /* 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; + /* Request EEPROM Access */ + if (hw->mac_type > em_82544) { + eecd |= E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; + 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"); + em_swfw_sync_release(hw, E1000_SWFW_EEP_SM); + return -E1000_ERR_EEPROM; + } } } - } /* Setup EEPROM for Read/Write */ @@ -3599,7 +4659,7 @@ em_standby_eeprom(struct em_hw *hw) eecd = E1000_READ_REG(hw, EECD); - if(eeprom->type == em_eeprom_microwire) { + if (eeprom->type == em_eeprom_microwire) { eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); @@ -3622,7 +4682,7 @@ em_standby_eeprom(struct em_hw *hw) E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); usec_delay(eeprom->delay_usec); - } else if(eeprom->type == em_eeprom_spi) { + } else if (eeprom->type == em_eeprom_spi) { /* Toggle CS to flush commands */ eecd |= E1000_EECD_CS; E1000_WRITE_REG(hw, EECD, eecd); @@ -3656,7 +4716,7 @@ em_release_eeprom(struct em_hw *hw) E1000_WRITE_REG(hw, EECD, eecd); usec_delay(hw->eeprom.delay_usec); - } else if(hw->eeprom.type == em_eeprom_microwire) { + } else if (hw->eeprom.type == em_eeprom_microwire) { /* cleanup eeprom */ /* CS on Microwire is active-high */ @@ -3678,12 +4738,12 @@ em_release_eeprom(struct em_hw *hw) } /* Stop requesting EEPROM access */ - if(hw->mac_type > em_82544) { + if (hw->mac_type > em_82544) { eecd &= ~E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); } - em_put_hw_eeprom_semaphore(hw); + em_swfw_sync_release(hw, E1000_SWFW_EEP_SM); } /****************************************************************************** @@ -3716,12 +4776,12 @@ em_spi_eeprom_ready(struct em_hw *hw) retry_count += 5; em_standby_eeprom(hw); - } while(retry_count < EEPROM_MAX_RETRY_SPI); + } 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) { + if (retry_count >= EEPROM_MAX_RETRY_SPI) { DEBUGOUT("SPI EEPROM Status error\n"); return -E1000_ERR_EEPROM; } @@ -3752,23 +4812,27 @@ em_read_eeprom(struct em_hw *hw, /* 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) || + if ((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) || (words == 0)) { DEBUGOUT("\"words\" parameter out of bounds\n"); return -E1000_ERR_EEPROM; } - /* FLASH reads without acquiring the semaphore are safe in 82573-based - * controllers. - */ - if ((em_is_onboard_nvm_eeprom(hw) == TRUE) || - (hw->mac_type != em_82573)) { - /* Prepare the EEPROM for reading */ - if(em_acquire_eeprom(hw) != E1000_SUCCESS) - return -E1000_ERR_EEPROM; + /* FLASH reads without acquiring the semaphore are safe */ + if (em_is_onboard_nvm_eeprom(hw) == TRUE && + hw->eeprom.use_eerd == FALSE) { + switch (hw->mac_type) { + case em_80003es2lan: + break; + default: + /* Prepare the EEPROM for reading */ + if (em_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; + break; + } } - if(eeprom->use_eerd == TRUE) { + if (eeprom->use_eerd == TRUE) { ret_val = em_read_eeprom_eerd(hw, offset, words, data); if ((em_is_onboard_nvm_eeprom(hw) == TRUE) || (hw->mac_type != em_82573)) @@ -3776,11 +4840,14 @@ em_read_eeprom(struct em_hw *hw, return ret_val; } - if(eeprom->type == em_eeprom_spi) { + if (eeprom->type == em_eeprom_ich8) + return em_read_eeprom_ich8(hw, offset, words, data); + + if (eeprom->type == em_eeprom_spi) { uint16_t word_in; uint8_t read_opcode = EEPROM_READ_OPCODE_SPI; - if(em_spi_eeprom_ready(hw)) { + if (em_spi_eeprom_ready(hw)) { em_release_eeprom(hw); return -E1000_ERR_EEPROM; } @@ -3788,7 +4855,7 @@ em_read_eeprom(struct em_hw *hw, em_standby_eeprom(hw); /* Some SPI eeproms use the 8th address bit embedded in the opcode */ - if((eeprom->address_bits == 8) && (offset >= 128)) + if ((eeprom->address_bits == 8) && (offset >= 128)) read_opcode |= EEPROM_A8_OPCODE_SPI; /* Send the READ command (opcode + addr) */ @@ -3804,7 +4871,7 @@ em_read_eeprom(struct em_hw *hw, word_in = em_shift_in_ee_bits(hw, 16); data[i] = (word_in >> 8) | (word_in << 8); } - } else if(eeprom->type == em_eeprom_microwire) { + } else if (eeprom->type == em_eeprom_microwire) { for (i = 0; i < words; i++) { /* Send the READ command (opcode + addr) */ em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE, @@ -3848,14 +4915,14 @@ em_read_eeprom_eerd(struct em_hw *hw, E1000_WRITE_REG(hw, EERD, eerd); error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ); - - if(error) { + + if (error) { break; } data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA); - + } - + return error; } @@ -3877,25 +4944,29 @@ em_write_eeprom_eewr(struct em_hw *hw, uint32_t i = 0; int32_t error = 0; + if (em_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM)) + return -E1000_ERR_SWFW_SYNC; + for (i = 0; i < words; i++) { - register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | - ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | + register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | + ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | E1000_EEPROM_RW_REG_START; error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE); - if(error) { + if (error) { break; - } + } E1000_WRITE_REG(hw, EEWR, register_value); - + error = em_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE); - - if(error) { + + if (error) { break; - } + } } - + + em_swfw_sync_release(hw, E1000_SWFW_EEP_SM); return error; } @@ -3911,13 +4982,13 @@ em_poll_eerd_eewr_done(struct em_hw *hw, int eerd) uint32_t i, reg = 0; int32_t done = E1000_ERR_EEPROM; - for(i = 0; i < attempts; i++) { - if(eerd == E1000_EEPROM_POLL_READ) + for (i = 0; i < attempts; i++) { + if (eerd == E1000_EEPROM_POLL_READ) reg = E1000_READ_REG(hw, EERD); - else + else reg = E1000_READ_REG(hw, EEWR); - if(reg & E1000_EEPROM_RW_REG_DONE) { + if (reg & E1000_EEPROM_RW_REG_DONE) { done = E1000_SUCCESS; break; } @@ -3937,14 +5008,19 @@ em_is_onboard_nvm_eeprom(struct em_hw *hw) { uint32_t eecd = 0; - if(hw->mac_type == em_82573) { + DEBUGFUNC("em_is_onboard_nvm_eeprom"); + + if (hw->mac_type == em_ich8lan) + return FALSE; + + if (hw->mac_type == em_82573) { eecd = E1000_READ_REG(hw, EECD); /* Isolate bits 15 & 16 */ eecd = ((eecd >> 15) & 0x03); /* If both bits are set, device is Flash type */ - if(eecd == 0x03) { + if (eecd == 0x03) { return FALSE; } } @@ -3987,15 +5063,29 @@ em_validate_eeprom_checksum(struct em_hw *hw) } } - for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { + if (hw->mac_type == em_ich8lan) { + /* Drivers must allocate the shadow ram structure for the + * EEPROM checksum to be updated. Otherwise, this bit as well + * as the checksum must both be set correctly for this + * validation to pass. + */ + em_read_eeprom(hw, 0x19, 1, &eeprom_data); + if ((eeprom_data & 0x40) == 0) { + eeprom_data |= 0x40; + em_write_eeprom(hw, 0x19, 1, &eeprom_data); + em_update_eeprom_checksum(hw); + } + } + + for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + if (em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } checksum += eeprom_data; } - if(checksum == (uint16_t) EEPROM_SUM) + if (checksum == (uint16_t) EEPROM_SUM) return E1000_SUCCESS; else { DEBUGOUT("EEPROM Checksum Invalid\n"); @@ -4014,24 +5104,33 @@ em_validate_eeprom_checksum(struct em_hw *hw) int32_t em_update_eeprom_checksum(struct em_hw *hw) { + uint32_t ctrl_ext; uint16_t checksum = 0; uint16_t i, eeprom_data; DEBUGFUNC("em_update_eeprom_checksum"); - for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { - if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { + for (i = 0; i < EEPROM_CHECKSUM_REG; i++) { + 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, 1, &checksum) < 0) { + if (em_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) { DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; } else if (hw->eeprom.type == em_eeprom_flash) { em_commit_shadow_ram(hw); + } else if (hw->eeprom.type == em_eeprom_ich8) { + em_commit_shadow_ram(hw); + /* Reload the EEPROM, or else modifications will not appear + * until after next adapter reset. */ + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + msec_delay(10); } return E1000_SUCCESS; } @@ -4061,21 +5160,24 @@ em_write_eeprom(struct em_hw *hw, /* 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) || + if ((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) || (words == 0)) { DEBUGOUT("\"words\" parameter out of bounds\n"); return -E1000_ERR_EEPROM; } - /* 82573 reads only through eerd */ - if(eeprom->use_eewr == TRUE) + /* 82573 writes only through eewr */ + if (eeprom->use_eewr == TRUE) return em_write_eeprom_eewr(hw, offset, words, data); + if (eeprom->type == em_eeprom_ich8) + return em_write_eeprom_ich8(hw, offset, words, data); + /* Prepare the EEPROM for writing */ if (em_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; - if(eeprom->type == em_eeprom_microwire) { + if (eeprom->type == em_eeprom_microwire) { status = em_write_eeprom_microwire(hw, offset, words, data); } else { status = em_write_eeprom_spi(hw, offset, words, data); @@ -4111,7 +5213,7 @@ em_write_eeprom_spi(struct em_hw *hw, while (widx < words) { uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI; - if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; + if (em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; em_standby_eeprom(hw); @@ -4122,7 +5224,7 @@ em_write_eeprom_spi(struct em_hw *hw, em_standby_eeprom(hw); /* Some SPI eeproms use the 8th address bit embedded in the opcode */ - if((eeprom->address_bits == 8) && (offset >= 128)) + if ((eeprom->address_bits == 8) && (offset >= 128)) write_opcode |= EEPROM_A8_OPCODE_SPI; /* Send the Write command (8-bit opcode + addr) */ @@ -4144,7 +5246,7 @@ em_write_eeprom_spi(struct em_hw *hw, * 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) { + if ((((offset + widx)*2) % eeprom->page_size) == 0) { em_standby_eeprom(hw); break; } @@ -4210,12 +5312,12 @@ em_write_eeprom_microwire(struct em_hw *hw, * 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++) { + for (i = 0; i < 200; i++) { eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_DO) break; + if (eecd & E1000_EECD_DO) break; usec_delay(50); } - if(i == 200) { + if (i == 200) { DEBUGOUT("EEPROM Write did not complete\n"); return -E1000_ERR_EEPROM; } @@ -4258,11 +5360,17 @@ em_commit_shadow_ram(struct em_hw *hw) uint32_t flop = 0; uint32_t i = 0; int32_t error = E1000_SUCCESS; - - /* The flop register will be used to determine if flash type is STM */ - flop = E1000_READ_REG(hw, FLOP); + uint32_t old_bank_offset = 0; + uint32_t new_bank_offset = 0; + uint32_t sector_retries = 0; + uint8_t low_byte = 0; + uint8_t high_byte = 0; + uint8_t temp_byte = 0; + boolean_t sector_write_failed = FALSE; if (hw->mac_type == em_82573) { + /* The flop register will be used to determine if flash type is STM */ + flop = E1000_READ_REG(hw, FLOP); for (i=0; i < attempts; i++) { eecd = E1000_READ_REG(hw, EECD); if ((eecd & E1000_EECD_FLUPD) == 0) { @@ -4275,7 +5383,7 @@ em_commit_shadow_ram(struct em_hw *hw) return -E1000_ERR_EEPROM; } - /* If STM opcode located in bits 15:8 of flop, reset firmware */ + /* If STM opcode located in bits 15:8 of flop, reset firmware */ if ((flop & 0xFF00) == E1000_STM_OPCODE) { E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET); } @@ -4283,7 +5391,7 @@ em_commit_shadow_ram(struct em_hw *hw) /* Perform the flash update */ E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD); - for (i=0; i < attempts; i++) { + for (i=0; i < attempts; i++) { eecd = E1000_READ_REG(hw, EECD); if ((eecd & E1000_EECD_FLUPD) == 0) { break; @@ -4296,6 +5404,106 @@ em_commit_shadow_ram(struct em_hw *hw) } } + if (hw->mac_type == em_ich8lan && hw->eeprom_shadow_ram != NULL) { + /* We're writing to the opposite bank so if we're on bank 1, + * write to bank 0 etc. We also need to erase the segment that + * is going to be written */ + if (!(E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL)) { + new_bank_offset = hw->flash_bank_size * 2; + old_bank_offset = 0; + em_erase_ich8_4k_segment(hw, 1); + } else { + old_bank_offset = hw->flash_bank_size * 2; + new_bank_offset = 0; + em_erase_ich8_4k_segment(hw, 0); + } + + do { + sector_write_failed = FALSE; + /* Loop for every byte in the shadow RAM, + * which is in units of words. */ + for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { + /* Determine whether to write the value stored + * in the other NVM bank or a modified value stored + * in the shadow RAM */ + if (hw->eeprom_shadow_ram[i].modified == TRUE) { + low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word; + em_read_ich8_byte(hw, (i << 1) + old_bank_offset, + &temp_byte); + usec_delay(100); + error = em_verify_write_ich8_byte(hw, + (i << 1) + new_bank_offset, + low_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + high_byte = + (uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8); + em_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1, + &temp_byte); + usec_delay(100); + } else { + em_read_ich8_byte(hw, (i << 1) + old_bank_offset, + &low_byte); + usec_delay(100); + error = em_verify_write_ich8_byte(hw, + (i << 1) + new_bank_offset, low_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + em_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1, + &high_byte); + } + + /* If the word is 0x13, then make sure the signature bits + * (15:14) are 11b until the commit has completed. + * This will allow us to write 10b which indicates the + * signature is valid. We want to do this after the write + * has completed so that we don't mark the segment valid + * while the write is still in progress */ + if (i == E1000_ICH8_NVM_SIG_WORD) + high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte; + + error = em_verify_write_ich8_byte(hw, + (i << 1) + new_bank_offset + 1, high_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + + if (sector_write_failed == FALSE) { + /* Clear the now not used entry in the cache */ + hw->eeprom_shadow_ram[i].modified = FALSE; + hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF; + } + } + + /* Don't bother writing the segment valid bits if sector + * programming failed. */ + if (sector_write_failed == FALSE) { + /* Finally validate the new segment by setting bit 15:14 + * to 10b in word 0x13 , this can be done without an + * erase as well since these bits are 11 to start with + * and we need to change bit 14 to 0b */ + em_read_ich8_byte(hw, + E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset, + &high_byte); + high_byte &= 0xBF; + error = em_verify_write_ich8_byte(hw, + E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset, + high_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + + /* And invalidate the previously valid segment by setting + * its signature word (0x13) high_byte to 0b. This can be + * done without an erase because flash erase sets all bits + * to 1's. We can write 1's to 0's without an erase */ + error = em_verify_write_ich8_byte(hw, + E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset, + 0); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + } + } while (++sector_retries < 10 && sector_write_failed == TRUE); + } + return error; } @@ -4315,7 +5523,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, 1, &eeprom_data) < 0) { + if (em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -4323,7 +5531,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, 1, &eeprom_data) < 0) { + if (em_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -4347,20 +5555,29 @@ em_read_mac_addr(struct em_hw * hw) DEBUGFUNC("em_read_mac_addr"); - for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) { + for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) { offset = i >> 1; - if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { + if (em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF); hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } - if(((hw->mac_type == em_82546) || (hw->mac_type == em_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + + switch (hw->mac_type) { + default: + break; + case em_82546: + case em_82546_rev_3: + case em_82571: + case em_80003es2lan: + if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) hw->perm_mac_addr[5] ^= 0x01; + break; + } - for(i = 0; i < NODE_ADDRESS_SIZE; i++) + for (i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; return E1000_SUCCESS; } @@ -4388,11 +5605,22 @@ em_init_rx_addrs(struct em_hw *hw) em_rar_set(hw, hw->mac_addr, 0); rar_num = E1000_RAR_ENTRIES; + + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == em_82571) && (hw->laa_is_present == TRUE)) + rar_num -= 1; + if (hw->mac_type == em_ich8lan) + rar_num = E1000_RAR_ENTRIES_ICH8LAN; + /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); - for(i = 1; i < rar_num; i++) { + for (i = 1; i < rar_num; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); + E1000_WRITE_FLUSH(hw); } } @@ -4421,7 +5649,7 @@ em_mc_addr_list_update(struct em_hw *hw, uint32_t i; uint32_t num_rar_entry; uint32_t num_mta_entry; - + DEBUGFUNC("em_mc_addr_list_update"); /* Set the new number of MC addresses that we are being requested to use. */ @@ -4430,20 +5658,33 @@ em_mc_addr_list_update(struct em_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); num_rar_entry = E1000_RAR_ENTRIES; - for(i = rar_used_count; i < num_rar_entry; i++) { + if (hw->mac_type == em_ich8lan) + num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN; + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == em_82571) && (hw->laa_is_present == TRUE)) + num_rar_entry -= 1; + + for (i = rar_used_count; i < num_rar_entry; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); + E1000_WRITE_FLUSH(hw); } /* Clear the MTA */ DEBUGOUT(" Clearing MTA\n"); num_mta_entry = E1000_NUM_MTA_REGISTERS; - for(i = 0; i < num_mta_entry; i++) { + if (hw->mac_type == em_ich8lan) + num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN; + for (i = 0; i < num_mta_entry; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); + E1000_WRITE_FLUSH(hw); } /* Add the new addresses */ - for(i = 0; i < mc_addr_count; i++) { + for (i = 0; i < mc_addr_count; i++) { DEBUGOUT(" Adding the multicast addresses:\n"); DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i, mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)], @@ -4495,24 +5736,46 @@ em_hash_mc_addr(struct em_hw *hw, * LSB MSB */ case 0: - /* [47:36] i.e. 0x563 for above example address */ - hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + if (hw->mac_type == em_ich8lan) { + /* [47:38] i.e. 0x158 for above example address */ + hash_value = ((mc_addr[4] >> 6) | (((uint16_t) mc_addr[5]) << 2)); + } else { + /* [47:36] i.e. 0x563 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + } break; case 1: - /* [46:35] i.e. 0xAC6 for above example address */ - hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + if (hw->mac_type == em_ich8lan) { + /* [46:37] i.e. 0x2B1 for above example address */ + hash_value = ((mc_addr[4] >> 5) | (((uint16_t) mc_addr[5]) << 3)); + } else { + /* [46:35] i.e. 0xAC6 for above example address */ + hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + } break; case 2: - /* [45:34] i.e. 0x5D8 for above example address */ - hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + if (hw->mac_type == em_ich8lan) { + /*[45:36] i.e. 0x163 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + } else { + /* [45:34] i.e. 0x5D8 for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + } break; case 3: - /* [43:32] i.e. 0x634 for above example address */ - hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + if (hw->mac_type == em_ich8lan) { + /* [43:34] i.e. 0x18D for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + } else { + /* [43:32] i.e. 0x634 for above example address */ + hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + } break; } hash_value &= 0xFFF; + if (hw->mac_type == em_ich8lan) + hash_value &= 0x3FF; return hash_value; } @@ -4540,6 +5803,8 @@ em_mta_set(struct em_hw *hw, * register are determined by the lower 5 bits of the value. */ hash_reg = (hash_value >> 5) & 0x7F; + if (hw->mac_type == em_ich8lan) + hash_reg &= 0x1F; hash_bit = hash_value & 0x1F; mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg); @@ -4550,12 +5815,15 @@ em_mta_set(struct em_hw *hw, * in the MTA, save off the previous entry before writing and * restore the old value after writing. */ - if((hw->mac_type == em_82544) && ((hash_reg & 0x1) == 1)) { + if ((hw->mac_type == em_82544) && ((hash_reg & 0x1) == 1)) { temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1)); E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp); + E1000_WRITE_FLUSH(hw); } else { E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); + E1000_WRITE_FLUSH(hw); } } @@ -4579,11 +5847,42 @@ em_rar_set(struct em_hw *hw, rar_low = ((uint32_t) addr[0] | ((uint32_t) addr[1] << 8) | ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24)); + rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8)); - rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV); + /* Disable Rx and flush all Rx frames before enabling RSS to avoid Rx + * unit hang. + * + * Description: + * If there are any Rx frames queued up or otherwise present in the HW + * before RSS is enabled, and then we enable RSS, the HW Rx unit will + * hang. To work around this issue, we have to disable receives and + * flush out all Rx frames before we enable RSS. To do so, we modify we + * redirect all Rx traffic to manageability and then reset the HW. + * This flushes away Rx frames, and (since the redirections to + * manageability persists across resets) keeps new ones from coming in + * while we work. Then, we clear the Address Valid AV bit for all MAC + * addresses and undo the re-direction to manageability. + * Now, frames are coming in again, but the MAC won't accept them, so + * far so good. We now proceed to initialize RSS (if necessary) and + * configure the Rx unit. Last, we re-enable the AV bits and continue + * on our merry way. + */ + switch (hw->mac_type) { + case em_82571: + case em_82572: + case em_80003es2lan: + if (hw->leave_av_bit_off == TRUE) + break; + default: + /* Indicate to hardware the Address is Valid. */ + rar_high |= E1000_RAH_AV; + break; + } E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high); + E1000_WRITE_FLUSH(hw); } /****************************************************************************** @@ -4600,12 +5899,18 @@ em_write_vfta(struct em_hw *hw, { uint32_t temp; - if((hw->mac_type == em_82544) && ((offset & 0x1) == 1)) { + if (hw->mac_type == em_ich8lan) + return; + + if ((hw->mac_type == em_82544) && ((offset & 0x1) == 1)) { temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1)); E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp); + E1000_WRITE_FLUSH(hw); } else { E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value); + E1000_WRITE_FLUSH(hw); } } @@ -4622,6 +5927,9 @@ em_clear_vfta(struct em_hw *hw) uint32_t vfta_offset = 0; uint32_t vfta_bit_in_reg = 0; + if (hw->mac_type == em_ich8lan) + return; + if (hw->mac_type == em_82573) { if (hw->mng_cookie.vlan_id != 0) { /* The VFTA is a 4096b bit-field, each identifying a single VLAN @@ -4641,6 +5949,7 @@ em_clear_vfta(struct em_hw *hw) * manageability unit */ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value); + E1000_WRITE_FLUSH(hw); } } @@ -4656,7 +5965,7 @@ em_id_led_init(struct em_hw * hw) DEBUGFUNC("em_id_led_init"); - if(hw->mac_type < em_82540) { + if (hw->mac_type < em_82540) { /* Nothing to do */ return E1000_SUCCESS; } @@ -4666,15 +5975,24 @@ em_id_led_init(struct em_hw * hw) hw->ledctl_mode1 = hw->ledctl_default; hw->ledctl_mode2 = hw->ledctl_default; - if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &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) || - (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT; - for(i = 0; i < 4; i++) { + + if ((hw->mac_type == em_82573) && + (eeprom_data == ID_LED_RESERVED_82573)) + eeprom_data = ID_LED_DEFAULT_82573; + else if ((eeprom_data == ID_LED_RESERVED_0000) || + (eeprom_data == ID_LED_RESERVED_FFFF)) { + if (hw->mac_type == em_ich8lan) + eeprom_data = ID_LED_DEFAULT_ICH8LAN; + else + eeprom_data = ID_LED_DEFAULT; + } + for (i = 0; i < 4; i++) { temp = (eeprom_data >> (i << 2)) & led_mask; - switch(temp) { + switch (temp) { case ID_LED_ON1_DEF2: case ID_LED_ON1_ON2: case ID_LED_ON1_OFF2: @@ -4691,7 +6009,7 @@ em_id_led_init(struct em_hw * hw) /* Do nothing */ break; } - switch(temp) { + switch (temp) { case ID_LED_DEF1_ON2: case ID_LED_ON1_ON2: case ID_LED_OFF1_ON2: @@ -4725,7 +6043,7 @@ em_setup_led(struct em_hw *hw) DEBUGFUNC("em_setup_led"); - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82542_rev2_0: case em_82542_rev2_1: case em_82543: @@ -4739,16 +6057,16 @@ em_setup_led(struct em_hw *hw) /* Turn off PHY Smart Power Down (if enabled) */ ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &hw->phy_spd_default); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, (uint16_t)(hw->phy_spd_default & ~IGP01E1000_GMII_SPD)); - if(ret_val) + if (ret_val) return ret_val; /* Fall Through */ default: - if(hw->media_type == em_media_type_fiber) { + if (hw->media_type == em_media_type_fiber) { ledctl = E1000_READ_REG(hw, LEDCTL); /* Save current LEDCTL settings */ hw->ledctl_default = ledctl; @@ -4759,7 +6077,7 @@ em_setup_led(struct em_hw *hw) ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT); E1000_WRITE_REG(hw, LEDCTL, ledctl); - } else if(hw->media_type == em_media_type_copper) + } else if (hw->media_type == em_media_type_copper) E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); break; } @@ -4767,6 +6085,45 @@ em_setup_led(struct em_hw *hw) return E1000_SUCCESS; } + +/****************************************************************************** + * Used on 82571 and later Si that has LED blink bits. + * Callers must use their own timer and should have already called + * em_id_led_init() + * Call em_cleanup led() to stop blinking + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +em_blink_led_start(struct em_hw *hw) +{ + int16_t i; + uint32_t ledctl_blink = 0; + + DEBUGFUNC("em_id_led_blink_on"); + + if (hw->mac_type < em_82571) { + /* Nothing to do */ + return E1000_SUCCESS; + } + if (hw->media_type == em_media_type_fiber) { + /* always blink LED0 for PCI-E fiber */ + ledctl_blink = E1000_LEDCTL_LED0_BLINK | + (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); + } else { + /* set the blink bit for each LED that's "on" (0x0E) in ledctl_mode2 */ + ledctl_blink = hw->ledctl_mode2; + for (i=0; i < 4; i++) + if (((hw->ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << (i * 8)); + } + + E1000_WRITE_REG(hw, LEDCTL, ledctl_blink); + + return E1000_SUCCESS; +} + /****************************************************************************** * Restores the saved state of the SW controlable LED. * @@ -4779,7 +6136,7 @@ em_cleanup_led(struct em_hw *hw) DEBUGFUNC("em_cleanup_led"); - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82542_rev2_0: case em_82542_rev2_1: case em_82543: @@ -4793,10 +6150,14 @@ em_cleanup_led(struct em_hw *hw) /* Turn on PHY Smart Power Down (if previously enabled) */ ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, hw->phy_spd_default); - if(ret_val) + if (ret_val) return ret_val; /* Fall Through */ default: + if (hw->phy_type == em_phy_ife) { + em_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); + break; + } /* Restore LEDCTL settings */ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default); break; @@ -4817,7 +6178,7 @@ em_led_on(struct em_hw *hw) DEBUGFUNC("em_led_on"); - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82542_rev2_0: case em_82542_rev2_1: case em_82543: @@ -4826,7 +6187,7 @@ em_led_on(struct em_hw *hw) ctrl |= E1000_CTRL_SWDPIO0; break; case em_82544: - if(hw->media_type == em_media_type_fiber) { + if (hw->media_type == em_media_type_fiber) { /* Set SW Defineable Pin 0 to turn on the LED */ ctrl |= E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; @@ -4837,11 +6198,14 @@ em_led_on(struct em_hw *hw) } break; default: - if(hw->media_type == em_media_type_fiber) { + if (hw->media_type == em_media_type_fiber) { /* Clear SW Defineable Pin 0 to turn on the LED */ ctrl &= ~E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; - } else if(hw->media_type == em_media_type_copper) { + } else if (hw->phy_type == em_phy_ife) { + em_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); + } else if (hw->media_type == em_media_type_copper) { E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2); return E1000_SUCCESS; } @@ -4865,7 +6229,7 @@ em_led_off(struct em_hw *hw) DEBUGFUNC("em_led_off"); - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82542_rev2_0: case em_82542_rev2_1: case em_82543: @@ -4874,7 +6238,7 @@ em_led_off(struct em_hw *hw) ctrl |= E1000_CTRL_SWDPIO0; break; case em_82544: - if(hw->media_type == em_media_type_fiber) { + if (hw->media_type == em_media_type_fiber) { /* Clear SW Defineable Pin 0 to turn off the LED */ ctrl &= ~E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; @@ -4885,11 +6249,14 @@ em_led_off(struct em_hw *hw) } break; default: - if(hw->media_type == em_media_type_fiber) { + if (hw->media_type == em_media_type_fiber) { /* Set SW Defineable Pin 0 to turn off the LED */ ctrl |= E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; - } else if(hw->media_type == em_media_type_copper) { + } else if (hw->phy_type == em_phy_ife) { + em_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); + } else if (hw->media_type == em_media_type_copper) { E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); return E1000_SUCCESS; } @@ -4927,12 +6294,16 @@ em_clear_hw_cntrs(struct em_hw *hw) temp = E1000_READ_REG(hw, XOFFRXC); temp = E1000_READ_REG(hw, XOFFTXC); temp = E1000_READ_REG(hw, FCRUC); + + if (hw->mac_type != em_ich8lan) { temp = E1000_READ_REG(hw, PRC64); temp = E1000_READ_REG(hw, PRC127); temp = E1000_READ_REG(hw, PRC255); temp = E1000_READ_REG(hw, PRC511); temp = E1000_READ_REG(hw, PRC1023); temp = E1000_READ_REG(hw, PRC1522); + } + temp = E1000_READ_REG(hw, GPRC); temp = E1000_READ_REG(hw, BPRC); temp = E1000_READ_REG(hw, MPRC); @@ -4952,16 +6323,20 @@ em_clear_hw_cntrs(struct em_hw *hw) temp = E1000_READ_REG(hw, TOTH); temp = E1000_READ_REG(hw, TPR); temp = E1000_READ_REG(hw, TPT); + + if (hw->mac_type != em_ich8lan) { temp = E1000_READ_REG(hw, PTC64); temp = E1000_READ_REG(hw, PTC127); temp = E1000_READ_REG(hw, PTC255); temp = E1000_READ_REG(hw, PTC511); temp = E1000_READ_REG(hw, PTC1023); temp = E1000_READ_REG(hw, PTC1522); + } + temp = E1000_READ_REG(hw, MPTC); temp = E1000_READ_REG(hw, BPTC); - if(hw->mac_type < em_82543) return; + if (hw->mac_type < em_82543) return; temp = E1000_READ_REG(hw, ALGNERRC); temp = E1000_READ_REG(hw, RXERRC); @@ -4970,16 +6345,19 @@ em_clear_hw_cntrs(struct em_hw *hw) temp = E1000_READ_REG(hw, TSCTC); temp = E1000_READ_REG(hw, TSCTFC); - if(hw->mac_type <= em_82544) return; + if (hw->mac_type <= em_82544) return; temp = E1000_READ_REG(hw, MGTPRC); temp = E1000_READ_REG(hw, MGTPDC); temp = E1000_READ_REG(hw, MGTPTC); - if(hw->mac_type <= em_82547_rev_2) return; + if (hw->mac_type <= em_82547_rev_2) return; temp = E1000_READ_REG(hw, IAC); temp = E1000_READ_REG(hw, ICRXOC); + + if (hw->mac_type == em_ich8lan) return; + temp = E1000_READ_REG(hw, ICRXPTC); temp = E1000_READ_REG(hw, ICRXATC); temp = E1000_READ_REG(hw, ICTXPTC); @@ -4987,7 +6365,6 @@ em_clear_hw_cntrs(struct em_hw *hw) temp = E1000_READ_REG(hw, ICTXQEC); temp = E1000_READ_REG(hw, ICTXQMTC); temp = E1000_READ_REG(hw, ICRXDMTC); - } /****************************************************************************** @@ -5005,8 +6382,8 @@ em_reset_adaptive(struct em_hw *hw) { DEBUGFUNC("em_reset_adaptive"); - if(hw->adaptive_ifs) { - if(!hw->ifs_params_forced) { + if (hw->adaptive_ifs) { + if (!hw->ifs_params_forced) { hw->current_ifs_val = 0; hw->ifs_min_val = IFS_MIN; hw->ifs_max_val = IFS_MAX; @@ -5033,12 +6410,12 @@ em_update_adaptive(struct em_hw *hw) { DEBUGFUNC("em_update_adaptive"); - if(hw->adaptive_ifs) { - if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) { - if(hw->tx_packet_delta > MIN_NUM_XMITS) { + if (hw->adaptive_ifs) { + if ((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) { + if (hw->tx_packet_delta > MIN_NUM_XMITS) { hw->in_ifs_mode = TRUE; - if(hw->current_ifs_val < hw->ifs_max_val) { - if(hw->current_ifs_val == 0) + if (hw->current_ifs_val < hw->ifs_max_val) { + if (hw->current_ifs_val == 0) hw->current_ifs_val = hw->ifs_min_val; else hw->current_ifs_val += hw->ifs_step_size; @@ -5046,7 +6423,7 @@ em_update_adaptive(struct em_hw *hw) } } } else { - if(hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) { + if (hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) { hw->current_ifs_val = 0; hw->in_ifs_mode = FALSE; E1000_WRITE_REG(hw, AIT, 0); @@ -5093,46 +6470,46 @@ em_tbi_adjust_stats(struct em_hw *hw, * This could be simplified if all environments supported * 64-bit integers. */ - if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) + 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 * a broadcast frame. */ - if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) + if ((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) /* Broadcast packet */ stats->bprc++; - else if(*mac_addr & 0x01) + else if (*mac_addr & 0x01) /* Multicast packet */ stats->mprc++; - if(frame_len == hw->max_frame_size) { + if (frame_len == hw->max_frame_size) { /* In this case, the hardware has overcounted the number of * oversize frames. */ - if(stats->roc > 0) + if (stats->roc > 0) stats->roc--; } /* Adjust the bin counters when the extra byte put the frame in the * wrong bin. Remember that the frame_len was adjusted above. */ - if(frame_len == 64) { + if (frame_len == 64) { stats->prc64++; stats->prc127--; - } else if(frame_len == 127) { + } else if (frame_len == 127) { stats->prc127++; stats->prc255--; - } else if(frame_len == 255) { + } else if (frame_len == 255) { stats->prc255++; stats->prc511--; - } else if(frame_len == 511) { + } else if (frame_len == 511) { stats->prc511++; stats->prc1023--; - } else if(frame_len == 1023) { + } else if (frame_len == 1023) { stats->prc1023++; stats->prc1522--; - } else if(frame_len == 1522) { + } else if (frame_len == 1522) { stats->prc1522++; } } @@ -5154,9 +6531,17 @@ em_get_bus_info(struct em_hw *hw) hw->bus_speed = em_bus_speed_unknown; hw->bus_width = em_bus_width_unknown; break; + case em_82572: case em_82573: hw->bus_type = em_bus_type_pci_express; hw->bus_speed = em_bus_speed_2500; + hw->bus_width = em_bus_width_pciex_1; + break; + case em_82571: + case em_ich8lan: + case em_80003es2lan: + hw->bus_type = em_bus_type_pci_express; + hw->bus_speed = em_bus_speed_2500; hw->bus_width = em_bus_width_pciex_4; break; default: @@ -5164,10 +6549,10 @@ em_get_bus_info(struct em_hw *hw) hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ? em_bus_type_pcix : em_bus_type_pci; - if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) { + if (hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) { hw->bus_speed = (hw->bus_type == em_bus_type_pci) ? em_bus_speed_66 : em_bus_speed_120; - } else if(hw->bus_type == em_bus_type_pci) { + } else if (hw->bus_type == em_bus_type_pci) { hw->bus_speed = (status & E1000_STATUS_PCI66) ? em_bus_speed_66 : em_bus_speed_33; } else { @@ -5252,7 +6637,6 @@ em_get_cable_length(struct em_hw *hw, { int32_t ret_val; uint16_t agc_value = 0; - uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; uint16_t i, phy_data; uint16_t cable_length; @@ -5261,11 +6645,11 @@ em_get_cable_length(struct em_hw *hw, *min_length = *max_length = 0; /* Use old method for Phy older than IGP */ - if(hw->phy_type == em_phy_m88) { + if (hw->phy_type == em_phy_m88) { ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; @@ -5296,36 +6680,66 @@ em_get_cable_length(struct em_hw *hw, return -E1000_ERR_PHY; break; } - } else if(hw->phy_type == em_phy_igp) { /* For IGP PHY */ + } else if (hw->phy_type == em_phy_gg82563) { + ret_val = em_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE, + &phy_data); + if (ret_val) + return ret_val; + cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH; + + switch (cable_length) { + case em_gg_cable_length_60: + *min_length = 0; + *max_length = em_igp_cable_length_60; + break; + case em_gg_cable_length_60_115: + *min_length = em_igp_cable_length_60; + *max_length = em_igp_cable_length_115; + break; + case em_gg_cable_length_115_150: + *min_length = em_igp_cable_length_115; + *max_length = em_igp_cable_length_150; + break; + case em_gg_cable_length_150: + *min_length = em_igp_cable_length_150; + *max_length = em_igp_cable_length_180; + break; + default: + return -E1000_ERR_PHY; + break; + } + } else if (hw->phy_type == em_phy_igp) { /* For IGP PHY */ + uint16_t cur_agc_value; + uint16_t min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE; uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {IGP01E1000_PHY_AGC_A, IGP01E1000_PHY_AGC_B, IGP01E1000_PHY_AGC_C, IGP01E1000_PHY_AGC_D}; /* Read the AGC registers for all channels */ - for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { + for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data); - if(ret_val) + if (ret_val) return ret_val; - cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; + cur_agc_value = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; - /* Array bound check. */ - if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || - (cur_agc == 0)) + /* Value bound check. */ + if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || + (cur_agc_value == 0)) return -E1000_ERR_PHY; - agc_value += cur_agc; + agc_value += cur_agc_value; /* Update minimal AGC value. */ - if(min_agc > cur_agc) - min_agc = cur_agc; + if (min_agc_value > cur_agc_value) + min_agc_value = cur_agc_value; } /* Remove the minimal AGC result for length < 50m */ - if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * em_igp_cable_length_50) { - agc_value -= min_agc; + if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * em_igp_cable_length_50) { + agc_value -= min_agc_value; /* Get the average length of the remaining 3 channels */ agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1); @@ -5341,6 +6755,51 @@ em_get_cable_length(struct em_hw *hw, IGP01E1000_AGC_RANGE) : 0; *max_length = em_igp_cable_length_table[agc_value] + IGP01E1000_AGC_RANGE; + } else if (hw->phy_type == em_phy_igp_2 || + hw->phy_type == em_phy_igp_3) { + uint16_t cur_agc_index, max_agc_index = 0; + uint16_t min_agc_index = IGP02E1000_AGC_LENGTH_TABLE_SIZE - 1; + uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = em_read_phy_reg(hw, agc_reg_array[i], &phy_data); + if (ret_val) + return ret_val; + + /* Getting bits 15:9, which represent the combination of course and + * fine gain values. The result is a number that can be put into + * the lookup table to obtain the approximate cable length. */ + cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Array index bound check. */ + if ((cur_agc_index >= IGP02E1000_AGC_LENGTH_TABLE_SIZE) || + (cur_agc_index == 0)) + return -E1000_ERR_PHY; + + /* Remove min & max AGC values from calculation. */ + if (em_igp_2_cable_length_table[min_agc_index] > + em_igp_2_cable_length_table[cur_agc_index]) + min_agc_index = cur_agc_index; + if (em_igp_2_cable_length_table[max_agc_index] < + em_igp_2_cable_length_table[cur_agc_index]) + max_agc_index = cur_agc_index; + + agc_value += em_igp_2_cable_length_table[cur_agc_index]; + } + + agc_value -= (em_igp_2_cable_length_table[min_agc_index] + + em_igp_2_cable_length_table[max_agc_index]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + *min_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + *max_length = agc_value + IGP02E1000_AGC_RANGE; } return E1000_SUCCESS; @@ -5371,31 +6830,33 @@ em_check_polarity(struct em_hw *hw, DEBUGFUNC("em_check_polarity"); - if(hw->phy_type == em_phy_m88) { + if ((hw->phy_type == em_phy_m88) || + (hw->phy_type == em_phy_gg82563)) { /* return the Polarity bit in the Status register. */ ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> M88E1000_PSSR_REV_POLARITY_SHIFT; - } else if(hw->phy_type == em_phy_igp || + } else if (hw->phy_type == em_phy_igp || + hw->phy_type == em_phy_igp_3 || hw->phy_type == em_phy_igp_2) { /* Read the Status register to check the speed */ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; /* 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) == + if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_1000MBPS) { /* Read the GIG initialization PCS register (0x00B4) */ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG, &phy_data); - if(ret_val) + if (ret_val) return ret_val; /* Check the polarity bits */ @@ -5405,6 +6866,13 @@ em_check_polarity(struct em_hw *hw, * 100 Mbps this bit is always 0) */ *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED; } + } else if (hw->phy_type == em_phy_ife) { + ret_val = em_read_phy_reg(hw, IFE_PHY_EXTENDED_STATUS_CONTROL, + &phy_data); + if (ret_val) + return ret_val; + *polarity = (phy_data & IFE_PESC_POLARITY_REVERSED) >> + IFE_PESC_POLARITY_REVERSED_SHIFT; } return E1000_SUCCESS; } @@ -5417,7 +6885,7 @@ em_check_polarity(struct em_hw *hw, * 1 - Downshift ocured. * * returns: - E1000_ERR_XXX - * E1000_SUCCESS + * E1000_SUCCESS * * For phy's older then IGP, this function reads the Downshift bit in the Phy * Specific Status register. For IGP phy's, it reads the Downgrade bit in the @@ -5432,22 +6900,27 @@ em_check_downshift(struct em_hw *hw) DEBUGFUNC("em_check_downshift"); - if(hw->phy_type == em_phy_igp || + if (hw->phy_type == em_phy_igp || + hw->phy_type == em_phy_igp_3 || hw->phy_type == em_phy_igp_2) { ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data); - if(ret_val) + if (ret_val) return ret_val; hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0; - } else if(hw->phy_type == em_phy_m88) { + } else if ((hw->phy_type == em_phy_m88) || + (hw->phy_type == em_phy_gg82563)) { ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> M88E1000_PSSR_DOWNSHIFT_SHIFT; + } else if (hw->phy_type == em_phy_ife) { + /* em_phy_ife supports 10/100 speed only */ + hw->speed_downgraded = FALSE; } return E1000_SUCCESS; @@ -5480,40 +6953,42 @@ em_config_dsp_after_link_change(struct em_hw *hw, DEBUGFUNC("em_config_dsp_after_link_change"); - if(hw->phy_type != em_phy_igp) + if (hw->phy_type != em_phy_igp) return E1000_SUCCESS; - if(link_up) { + if (link_up) { ret_val = em_get_speed_and_duplex(hw, &speed, &duplex); - if(ret_val) { + if (ret_val) { DEBUGOUT("Error getting link speed and duplex\n"); return ret_val; } - if(speed == SPEED_1000) { + if (speed == SPEED_1000) { - em_get_cable_length(hw, &min_length, &max_length); + ret_val = em_get_cable_length(hw, &min_length, &max_length); + if (ret_val) + return ret_val; - if((hw->dsp_config_state == em_dsp_config_enabled) && + if ((hw->dsp_config_state == em_dsp_config_enabled) && min_length >= em_igp_cable_length_50) { - for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { + for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { ret_val = em_read_phy_reg(hw, dsp_reg_array[i], &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; ret_val = em_write_phy_reg(hw, dsp_reg_array[i], phy_data); - if(ret_val) + if (ret_val) return ret_val; } hw->dsp_config_state = em_dsp_config_activated; } - if((hw->ffe_config_state == em_ffe_config_enabled) && + if ((hw->ffe_config_state == em_ffe_config_enabled) && (min_length < em_igp_cable_length_50)) { uint16_t ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20; @@ -5522,70 +6997,70 @@ em_config_dsp_after_link_change(struct em_hw *hw, /* clear previous idle error counts */ ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; - for(i = 0; i < ffe_idle_err_timeout; i++) { + for (i = 0; i < ffe_idle_err_timeout; i++) { usec_delay(1000); ret_val = em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); - if(ret_val) + if (ret_val) return ret_val; idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT); - if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) { + if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) { hw->ffe_config_state = em_ffe_config_active; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE, IGP01E1000_PHY_DSP_FFE_CM_CP); - if(ret_val) + if (ret_val) return ret_val; break; } - if(idle_errs) + if (idle_errs) ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_100; } } } } else { - if(hw->dsp_config_state == em_dsp_config_activated) { + if (hw->dsp_config_state == em_dsp_config_activated) { /* Save off the current value of register 0x2F5B to be restored at * the end of the routines. */ ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data); - if(ret_val) + if (ret_val) return ret_val; /* Disable the PHY transmitter */ ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003); - if(ret_val) + if (ret_val) return ret_val; msec_delay_irq(20); ret_val = em_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); - if(ret_val) + if (ret_val) return ret_val; - for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { + for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { ret_val = em_read_phy_reg(hw, dsp_reg_array[i], &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS; ret_val = em_write_phy_reg(hw,dsp_reg_array[i], phy_data); - if(ret_val) + if (ret_val) return ret_val; } ret_val = em_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_RESTART_AUTONEG); - if(ret_val) + if (ret_val) return ret_val; msec_delay_irq(20); @@ -5593,40 +7068,40 @@ em_config_dsp_after_link_change(struct em_hw *hw, /* Now enable the transmitter */ ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data); - if(ret_val) + if (ret_val) return ret_val; hw->dsp_config_state = em_dsp_config_enabled; } - if(hw->ffe_config_state == em_ffe_config_active) { + if (hw->ffe_config_state == em_ffe_config_active) { /* Save off the current value of register 0x2F5B to be restored at * the end of the routines. */ ret_val = em_read_phy_reg(hw, 0x2F5B, &phy_saved_data); - if(ret_val) + if (ret_val) return ret_val; /* Disable the PHY transmitter */ ret_val = em_write_phy_reg(hw, 0x2F5B, 0x0003); - if(ret_val) + if (ret_val) return ret_val; msec_delay_irq(20); ret_val = em_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE, IGP01E1000_PHY_DSP_FFE_DEFAULT); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_RESTART_AUTONEG); - if(ret_val) + if (ret_val) return ret_val; msec_delay_irq(20); @@ -5634,7 +7109,7 @@ em_config_dsp_after_link_change(struct em_hw *hw, /* Now enable the transmitter */ ret_val = em_write_phy_reg(hw, 0x2F5B, phy_saved_data); - if(ret_val) + if (ret_val) return ret_val; hw->ffe_config_state = em_ffe_config_enabled; @@ -5659,20 +7134,20 @@ em_set_phy_mode(struct em_hw *hw) DEBUGFUNC("em_set_phy_mode"); - if((hw->mac_type == em_82545_rev_3) && - (hw->media_type == em_media_type_copper)) { + if ((hw->mac_type == em_82545_rev_3) && + (hw->media_type == em_media_type_copper)) { ret_val = em_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data); - if(ret_val) { + if (ret_val) { return ret_val; } - if((eeprom_data != EEPROM_RESERVED_WORD) && - (eeprom_data & EEPROM_PHY_CLASS_A)) { + if ((eeprom_data != EEPROM_RESERVED_WORD) && + (eeprom_data & EEPROM_PHY_CLASS_A)) { ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104); - if(ret_val) + if (ret_val) return ret_val; hw->phy_reset_disable = FALSE; @@ -5700,39 +7175,51 @@ int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active) { + uint32_t phy_ctrl = 0; int32_t ret_val; uint16_t phy_data; DEBUGFUNC("em_set_d3_lplu_state"); - if(hw->phy_type != em_phy_igp && hw->phy_type != em_phy_igp_2) + if (hw->phy_type != em_phy_igp && hw->phy_type != em_phy_igp_2 + && hw->phy_type != em_phy_igp_3) return E1000_SUCCESS; /* During driver activity LPLU should not be used or it will attain link * from the lowest speeds starting from 10Mbps. The capability is used for * Dx transitions and states */ - if(hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) { + if (hw->mac_type == em_82541_rev_2 || hw->mac_type == em_82547_rev_2) { ret_val = em_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data); - if(ret_val) + if (ret_val) return ret_val; + } else if (hw->mac_type == em_ich8lan) { + /* MAC writes into PHY register based on the state transition + * and start auto-negotiation. SW driver can overwrite the settings + * in CSR PHY power control E1000_PHY_CTRL register. */ + phy_ctrl = E1000_READ_REG(hw, PHY_CTRL); } else { ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); - if(ret_val) + if (ret_val) return ret_val; } - if(!active) { - if(hw->mac_type == em_82541_rev_2 || - hw->mac_type == em_82547_rev_2) { + if (!active) { + if (hw->mac_type == em_82541_rev_2 || + hw->mac_type == em_82547_rev_2) { phy_data &= ~IGP01E1000_GMII_FLEX_SPD; ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); - if(ret_val) + if (ret_val) return ret_val; } else { + if (hw->mac_type == em_ich8lan) { + phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { phy_data &= ~IGP02E1000_PM_D3_LPLU; ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } } /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during @@ -5742,13 +7229,13 @@ em_set_d3_lplu_state(struct em_hw *hw, if (hw->smart_speed == em_smart_speed_on) { ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= IGP01E1000_PSCFR_SMART_SPEED; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); - if(ret_val) + if (ret_val) return ret_val; } else if (hw->smart_speed == em_smart_speed_off) { ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, @@ -5759,36 +7246,41 @@ em_set_d3_lplu_state(struct em_hw *hw, phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); - if(ret_val) + if (ret_val) return ret_val; } - } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) || - (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) || - (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) { + } else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) || + (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) || + (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) { - if(hw->mac_type == em_82541_rev_2 || - hw->mac_type == em_82547_rev_2) { + if (hw->mac_type == em_82541_rev_2 || + hw->mac_type == em_82547_rev_2) { phy_data |= IGP01E1000_GMII_FLEX_SPD; ret_val = em_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); - if(ret_val) + if (ret_val) return ret_val; } else { + if (hw->mac_type == em_ich8lan) { + phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { phy_data |= IGP02E1000_PM_D3_LPLU; ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } } /* When LPLU is enabled we should disable SmartSpeed */ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); - if(ret_val) + if (ret_val) return ret_val; } @@ -5813,22 +7305,32 @@ int32_t em_set_d0_lplu_state(struct em_hw *hw, boolean_t active) { + uint32_t phy_ctrl = 0; int32_t ret_val; uint16_t phy_data; DEBUGFUNC("em_set_d0_lplu_state"); - if(hw->mac_type <= em_82547_rev_2) + if (hw->mac_type <= em_82547_rev_2) return E1000_SUCCESS; + if (hw->mac_type == em_ich8lan) { + phy_ctrl = E1000_READ_REG(hw, PHY_CTRL); + } else { ret_val = em_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); - if(ret_val) + if (ret_val) return ret_val; + } if (!active) { + if (hw->mac_type == em_ich8lan) { + phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { phy_data &= ~IGP02E1000_PM_D0_LPLU; ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during * Dx states where the power conservation is most important. During @@ -5837,13 +7339,13 @@ em_set_d0_lplu_state(struct em_hw *hw, if (hw->smart_speed == em_smart_speed_on) { ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= IGP01E1000_PSCFR_SMART_SPEED; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); - if(ret_val) + if (ret_val) return ret_val; } else if (hw->smart_speed == em_smart_speed_off) { ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, @@ -5854,26 +7356,31 @@ em_set_d0_lplu_state(struct em_hw *hw, phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); - if(ret_val) + if (ret_val) return ret_val; } } else { - - phy_data |= IGP02E1000_PM_D0_LPLU; + + if (hw->mac_type == em_ich8lan) { + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { + phy_data |= IGP02E1000_PM_D0_LPLU; ret_val = em_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } /* When LPLU is enabled we should disable SmartSpeed */ ret_val = em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); - if(ret_val) + if (ret_val) return ret_val; } @@ -5894,7 +7401,7 @@ em_set_vco_speed(struct em_hw *hw) DEBUGFUNC("em_set_vco_speed"); - switch(hw->mac_type) { + switch (hw->mac_type) { case em_82545_rev_3: case em_82546_rev_3: break; @@ -5905,39 +7412,39 @@ em_set_vco_speed(struct em_hw *hw) /* Set PHY register 30, page 5, bit 8 to 0 */ ret_val = em_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, &default_page); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data &= ~M88E1000_PHY_VCO_REG_BIT8; ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data); - if(ret_val) + if (ret_val) return ret_val; /* Set PHY register 30, page 4, bit 11 to 1 */ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data); - if(ret_val) + if (ret_val) return ret_val; phy_data |= M88E1000_PHY_VCO_REG_BIT11; ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, default_page); - if(ret_val) + if (ret_val) return ret_val; return E1000_SUCCESS; @@ -5953,7 +7460,7 @@ int32_t em_host_if_read_cookie(struct em_hw * hw, uint8_t *buffer) { uint8_t i; - uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET; + uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET; uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH; length = (length >> 2); @@ -5972,7 +7479,7 @@ em_host_if_read_cookie(struct em_hw * hw, uint8_t *buffer) * and also checks whether the previous command is completed. * It busy waits in case of previous command is not completed. * - * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or + * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or * timeout * - E1000_SUCCESS for success. ****************************************************************************/ @@ -5996,7 +7503,7 @@ em_mng_enable_host_if(struct em_hw * hw) msec_delay_irq(1); } - if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { + if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { DEBUGOUT("Previous command timeout failed .\n"); return -E1000_ERR_HOST_INTERFACE_COMMAND; } @@ -6016,7 +7523,7 @@ em_mng_host_if_write(struct em_hw * hw, uint8_t *buffer, { uint8_t *tmp; uint8_t *bufptr = buffer; - uint32_t data; + uint32_t data = 0; uint16_t remaining, i, j, prev_bytes; /* sum = only sum of the data and it is not checksum */ @@ -6096,15 +7603,17 @@ em_mng_write_cmd_header(struct em_hw * hw, buffer = (uint8_t *) hdr; i = length; - while(i--) + while (i--) sum += buffer[i]; hdr->checksum = 0 - sum; length >>= 2; /* The device driver writes the relevant command block into the ram area. */ - for (i = 0; i < length; i++) + for (i = 0; i < length; i++) { E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i)); + E1000_WRITE_FLUSH(hw); + } return E1000_SUCCESS; } @@ -6117,8 +7626,7 @@ em_mng_write_cmd_header(struct em_hw * hw, * returns - E1000_SUCCESS for success. ****************************************************************************/ int32_t -em_mng_write_commit( - struct em_hw * hw) +em_mng_write_commit(struct em_hw * hw) { uint32_t hicr; @@ -6136,15 +7644,18 @@ em_mng_write_commit( * returns - TRUE when the mode is IAMT or FALSE. ****************************************************************************/ boolean_t -em_check_mng_mode( - struct em_hw *hw) +em_check_mng_mode(struct em_hw *hw) { uint32_t fwsm; fwsm = E1000_READ_REG(hw, FWSM); - if((fwsm & E1000_FWSM_MODE_MASK) == - (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) + if (hw->mac_type == em_ich8lan) { + if ((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) + return TRUE; + } else if ((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) return TRUE; return FALSE; @@ -6287,31 +7798,31 @@ em_polarity_reversal_workaround(struct em_hw *hw) /* Disable the transmitter on the PHY */ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000); - if(ret_val) + if (ret_val) return ret_val; /* This loop will early-out if the NO link condition has been met. */ - for(i = PHY_FORCE_TIME; i > 0; i--) { + for (i = PHY_FORCE_TIME; i > 0; i--) { /* Read the MII Status Register and wait for Link Status bit * to be clear. */ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; - if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break; + if ((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break; msec_delay_irq(100); } @@ -6321,40 +7832,40 @@ em_polarity_reversal_workaround(struct em_hw *hw) /* Now we will re-enable th transmitter on the PHY */ ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); - if(ret_val) + if (ret_val) return ret_val; msec_delay_irq(50); ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0); - if(ret_val) + if (ret_val) return ret_val; msec_delay_irq(50); ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00); - if(ret_val) + if (ret_val) return ret_val; msec_delay_irq(50); ret_val = em_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000); - if(ret_val) + if (ret_val) return ret_val; /* This loop will early-out if the link condition has been met. */ - for(i = PHY_FORCE_TIME; i > 0; i--) { + for (i = PHY_FORCE_TIME; i > 0; i--) { /* Read the MII Status Register and wait for Link Status bit * to be set. */ ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; ret_val = em_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); - if(ret_val) + if (ret_val) return ret_val; - if(mii_status_reg & MII_SR_LINK_STATUS) break; + if (mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay_irq(100); } return E1000_SUCCESS; @@ -6431,15 +7942,15 @@ em_disable_pciex_master(struct em_hw *hw) em_set_pci_express_master_disable(hw); - while(timeout) { - if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE)) + while (timeout) { + if (!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE)) break; else usec_delay(100); timeout--; } - if(!timeout) { + if (!timeout) { DEBUGOUT("Master requests are pending.\n"); return -E1000_ERR_MASTER_REQUESTS_PENDING; } @@ -6468,20 +7979,31 @@ em_get_auto_rd_done(struct em_hw *hw) default: msec_delay(5); break; + case em_82571: + case em_82572: case em_82573: - while(timeout) { - if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; + case em_80003es2lan: + case em_ich8lan: + while (timeout) { + if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) + break; else msec_delay(1); timeout--; } - if(!timeout) { + if (!timeout) { DEBUGOUT("Auto read by HW from EEPROM has not completed.\n"); return -E1000_ERR_RESET; } break; } + /* PHY configuration from NVM just starts after EECD_AUTO_RD sets to high. + * Need to wait for PHY configuration completion before accessing NVM + * and PHY. */ + if (hw->mac_type == em_82573) + msec_delay(25); + return E1000_SUCCESS; } @@ -6497,10 +8019,36 @@ em_get_auto_rd_done(struct em_hw *hw) int32_t em_get_phy_cfg_done(struct em_hw *hw) { + int32_t timeout = PHY_CFG_TIMEOUT; + uint32_t cfg_mask = E1000_EEPROM_CFG_DONE; + DEBUGFUNC("em_get_phy_cfg_done"); - /* Simply wait for 10ms */ - msec_delay(10); + switch (hw->mac_type) { + default: + msec_delay_irq(10); + break; + case em_80003es2lan: + /* Separate *_CFG_DONE_* bit for each port */ + if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) + cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1; + /* Fall Through */ + case em_82571: + case em_82572: + while (timeout) { + if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask) + break; + else + msec_delay(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + break; + } return E1000_SUCCESS; } @@ -6524,26 +8072,31 @@ em_get_hw_eeprom_semaphore(struct em_hw *hw) DEBUGFUNC("em_get_hw_eeprom_semaphore"); - if(!hw->eeprom_semaphore_present) + if (!hw->eeprom_semaphore_present) return E1000_SUCCESS; + if (hw->mac_type == em_80003es2lan) { + /* Get the SW semaphore. */ + if (em_get_software_semaphore(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; + } /* Get the FW semaphore. */ timeout = hw->eeprom.word_size + 1; - while(timeout) { + while (timeout) { swsm = E1000_READ_REG(hw, SWSM); swsm |= E1000_SWSM_SWESMBI; E1000_WRITE_REG(hw, SWSM, swsm); /* if we managed to set the bit we got the semaphore. */ swsm = E1000_READ_REG(hw, SWSM); - if(swsm & E1000_SWSM_SWESMBI) + if (swsm & E1000_SWSM_SWESMBI) break; usec_delay(50); timeout--; } - if(!timeout) { + if (!timeout) { /* Release semaphores */ em_put_hw_eeprom_semaphore(hw); DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n"); @@ -6568,12 +8121,76 @@ em_put_hw_eeprom_semaphore(struct em_hw *hw) DEBUGFUNC("em_put_hw_eeprom_semaphore"); - if(!hw->eeprom_semaphore_present) + if (!hw->eeprom_semaphore_present) + return; + + swsm = E1000_READ_REG(hw, SWSM); + if (hw->mac_type == em_80003es2lan) { + /* Release both semaphores. */ + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + } else + swsm &= ~(E1000_SWSM_SWESMBI); + E1000_WRITE_REG(hw, SWSM, swsm); +} + +/*************************************************************************** + * + * Obtaining software semaphore bit (SMBI) before resetting PHY. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_RESET if fail to obtain semaphore. + * E1000_SUCCESS at any other case. + * + ***************************************************************************/ +int32_t +em_get_software_semaphore(struct em_hw *hw) +{ + int32_t timeout = hw->eeprom.word_size + 1; + uint32_t swsm; + + DEBUGFUNC("em_get_software_semaphore"); + + if (hw->mac_type != em_80003es2lan) + return E1000_SUCCESS; + + while (timeout) { + swsm = E1000_READ_REG(hw, SWSM); + /* If SMBI bit cleared, it is now set and we hold the semaphore */ + if (!(swsm & E1000_SWSM_SMBI)) + break; + msec_delay_irq(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); + return -E1000_ERR_RESET; + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Release semaphore bit (SMBI). + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +void +em_release_software_semaphore(struct em_hw *hw) +{ + uint32_t swsm; + + DEBUGFUNC("em_release_software_semaphore"); + + if (hw->mac_type != em_80003es2lan) return; swsm = E1000_READ_REG(hw, SWSM); - /* Release both semaphores. */ - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + /* Release the SW semaphores.*/ + swsm &= ~E1000_SWSM_SMBI; E1000_WRITE_REG(hw, SWSM, swsm); } @@ -6592,7 +8209,15 @@ int32_t em_check_phy_reset_block(struct em_hw *hw) { uint32_t manc = 0; - if(hw->mac_type > em_82547_rev_2) + uint32_t fwsm = 0; + + if (hw->mac_type == em_ich8lan) { + fwsm = E1000_READ_REG(hw, FWSM); + return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS + : E1000_BLK_PHY_RESET; + } + + if (hw->mac_type > em_82547_rev_2) manc = E1000_READ_REG(hw, MANC); return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? E1000_BLK_PHY_RESET : E1000_SUCCESS; @@ -6609,11 +8234,16 @@ em_arc_subsystem_valid(struct em_hw *hw) * if this is the case. We read FWSM to determine the manageability mode. */ switch (hw->mac_type) { + case em_82571: + case em_82572: case em_82573: + case em_80003es2lan: fwsm = E1000_READ_REG(hw, FWSM); - if((fwsm & E1000_FWSM_MODE_MASK) != 0) + if ((fwsm & E1000_FWSM_MODE_MASK) != 0) return TRUE; break; + case em_ich8lan: + return TRUE; default: break; } @@ -6621,4 +8251,854 @@ em_arc_subsystem_valid(struct em_hw *hw) } +/****************************************************************************** + * Configure PCI-Ex no-snoop + * + * hw - Struct containing variables accessed by shared code. + * no_snoop - Bitmap of no-snoop events. + * + * returns: E1000_SUCCESS + * + *****************************************************************************/ +int32_t +em_set_pci_ex_no_snoop(struct em_hw *hw, uint32_t no_snoop) +{ + uint32_t gcr_reg = 0; + + DEBUGFUNC("em_set_pci_ex_no_snoop"); + + if (hw->bus_type == em_bus_type_unknown) + em_get_bus_info(hw); + + if (hw->bus_type != em_bus_type_pci_express) + return E1000_SUCCESS; + + if (no_snoop) { + gcr_reg = E1000_READ_REG(hw, GCR); + gcr_reg &= ~(PCI_EX_NO_SNOOP_ALL); + gcr_reg |= no_snoop; + E1000_WRITE_REG(hw, GCR, gcr_reg); + } + if (hw->mac_type == em_ich8lan) { + uint32_t ctrl_ext; + + E1000_WRITE_REG(hw, GCR, PCI_EX_82566_SNOOP_ALL); + + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_RO_DIS; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Get software semaphore FLAG bit (SWFLAG). + * SWFLAG is used to synchronize the access to all shared resource between + * SW, FW and HW. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +int32_t +em_get_software_flag(struct em_hw *hw) +{ + int32_t timeout = PHY_CFG_TIMEOUT; + uint32_t extcnf_ctrl; + + DEBUGFUNC("em_get_software_flag"); + + if (hw->mac_type == em_ich8lan) { + while (timeout) { + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + msec_delay_irq(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("FW or HW locks the resource too long.\n"); + return -E1000_ERR_CONFIG; + } + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Release software semaphore FLAG bit (SWFLAG). + * SWFLAG is used to synchronize the access to all shared resource between + * SW, FW and HW. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +void +em_release_software_flag(struct em_hw *hw) +{ + uint32_t extcnf_ctrl; + + DEBUGFUNC("em_release_software_flag"); + + if (hw->mac_type == em_ich8lan) { + extcnf_ctrl= E1000_READ_REG(hw, EXTCNF_CTRL); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); + } + + return; +} + +/*************************************************************************** + * + * Disable dynamic power down mode in ife PHY. + * It can be used to workaround band-gap problem. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +int32_t +em_ife_disable_dynamic_power_down(struct em_hw *hw) +{ + uint16_t phy_data; + int32_t ret_val = E1000_SUCCESS; + + DEBUGFUNC("em_ife_disable_dynamic_power_down"); + + if (hw->phy_type == em_phy_ife) { + ret_val = em_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN; + ret_val = em_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data); + } + + return ret_val; +} + +/*************************************************************************** + * + * Enable dynamic power down mode in ife PHY. + * It can be used to workaround band-gap problem. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +int32_t +em_ife_enable_dynamic_power_down(struct em_hw *hw) +{ + uint16_t phy_data; + int32_t ret_val = E1000_SUCCESS; + + DEBUGFUNC("em_ife_enable_dynamic_power_down"); + + if (hw->phy_type == em_phy_ife) { + ret_val = em_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN; + ret_val = em_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data); + } + + return ret_val; +} + +/****************************************************************************** + * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access + * register. + * + * hw - Struct containing variables accessed by shared code + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read + *****************************************************************************/ +int32_t +em_read_eeprom_ich8(struct em_hw *hw, uint16_t offset, uint16_t words, + uint16_t *data) +{ + int32_t error = E1000_SUCCESS; + uint32_t flash_bank = 0; + uint32_t act_offset = 0; + uint32_t bank_offset = 0; + uint16_t word = 0; + uint16_t i = 0; + + /* We need to know which is the valid flash bank. In the event + * that we didn't allocate eeprom_shadow_ram, we may not be + * managing flash_bank. So it cannot be trusted and needs + * to be updated with each read. + */ + /* Value of bit 22 corresponds to the flash bank we're on. */ + flash_bank = (E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL) ? 1 : 0; + + /* Adjust offset appropriately if we're on bank 1 - adjust for word size */ + bank_offset = flash_bank * (hw->flash_bank_size * 2); + + error = em_get_software_flag(hw); + if (error != E1000_SUCCESS) + return error; + + for (i = 0; i < words; i++) { + if (hw->eeprom_shadow_ram != NULL && + hw->eeprom_shadow_ram[offset+i].modified == TRUE) { + data[i] = hw->eeprom_shadow_ram[offset+i].eeprom_word; + } else { + /* The NVM part needs a byte offset, hence * 2 */ + act_offset = bank_offset + ((offset + i) * 2); + error = em_read_ich8_word(hw, act_offset, &word); + if (error != E1000_SUCCESS) + break; + data[i] = word; + } + } + + em_release_software_flag(hw); + + return error; +} + +/****************************************************************************** + * Writes a 16 bit word or words to the EEPROM using the ICH8's flash access + * register. Actually, writes are written to the shadow ram cache in the hw + * structure hw->em_shadow_ram. em_commit_shadow_ram flushes this to + * the NVM, which occurs when the NVM checksum is updated. + * + * hw - Struct containing variables accessed by shared code + * offset - offset of word in the EEPROM to write + * words - number of words to write + * data - words to write to the EEPROM + *****************************************************************************/ +int32_t +em_write_eeprom_ich8(struct em_hw *hw, uint16_t offset, uint16_t words, + uint16_t *data) +{ + uint32_t i = 0; + int32_t error = E1000_SUCCESS; + + error = em_get_software_flag(hw); + if (error != E1000_SUCCESS) + return error; + + /* A driver can write to the NVM only if it has eeprom_shadow_ram + * allocated. Subsequent reads to the modified words are read from + * this cached structure as well. Writes will only go into this + * cached structure unless it's followed by a call to + * em_update_eeprom_checksum() where it will commit the changes + * and clear the "modified" field. + */ + if (hw->eeprom_shadow_ram != NULL) { + for (i = 0; i < words; i++) { + if ((offset + i) < E1000_SHADOW_RAM_WORDS) { + hw->eeprom_shadow_ram[offset+i].modified = TRUE; + hw->eeprom_shadow_ram[offset+i].eeprom_word = data[i]; + } else { + error = -E1000_ERR_EEPROM; + break; + } + } + } else { + /* Drivers have the option to not allocate eeprom_shadow_ram as long + * as they don't perform any NVM writes. An attempt in doing so + * will result in this error. + */ + error = -E1000_ERR_EEPROM; + } + + em_release_software_flag(hw); + + return error; +} + +/****************************************************************************** + * This function does initial flash setup so that a new read/write/erase cycle + * can be started. + * + * hw - The pointer to the hw structure + ****************************************************************************/ +int32_t +em_ich8_cycle_init(struct em_hw *hw) +{ + union ich8_hws_flash_status hsfsts; + int32_t error = E1000_ERR_EEPROM; + int32_t i = 0; + + DEBUGFUNC("em_ich8_cycle_init"); + + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + + /* May be check the Flash Des Valid bit in Hw status */ + if (hsfsts.hsf_status.fldesvalid == 0) { + DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used."); + return error; + } + + /* Clear FCERR in Hw status by writing 1 */ + /* Clear DAEL in Hw status by writing a 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval); + + /* Either we should have a hardware SPI cycle in progress bit to check + * against, in order to start a new cycle or FDONE bit should be changed + * in the hardware so that it is 1 after harware reset, which can then be + * used as an indication whether a cycle is in progress or has been + * completed .. we should also have some software semaphore mechanism to + * guard FDONE or the cycle in progress bit so that two threads access to + * those bits can be sequentiallized or a way so that 2 threads dont + * start the cycle at the same time */ + + if (hsfsts.hsf_status.flcinprog == 0) { + /* There is no cycle running at present, so we can start a cycle */ + /* Begin by setting Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval); + error = E1000_SUCCESS; + } else { + /* otherwise poll for sometime so the current cycle has a chance + * to end before giving up. */ + for (i = 0; i < ICH8_FLASH_COMMAND_TIMEOUT; i++) { + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcinprog == 0) { + error = E1000_SUCCESS; + break; + } + usec_delay(1); + } + if (error == E1000_SUCCESS) { + /* Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval); + } else { + DEBUGOUT("Flash controller busy, cannot get access"); + } + } + return error; +} + +/****************************************************************************** + * This function starts a flash cycle and waits for its completion + * + * hw - The pointer to the hw structure + ****************************************************************************/ +int32_t +em_ich8_flash_cycle(struct em_hw *hw, uint32_t timeout) +{ + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + int32_t error = E1000_ERR_EEPROM; + uint32_t i = 0; + + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* wait till FDONE bit is set to 1 */ + do { + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + usec_delay(1); + i++; + } while (i < timeout); + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) { + error = E1000_SUCCESS; + } + return error; +} + +/****************************************************************************** + * Reads a byte or word from the NVM using the ICH8 flash access registers. + * + * hw - The pointer to the hw structure + * index - The index of the byte or word to read. + * size - Size of data to read, 1=byte 2=word + * data - Pointer to the word to store the value read. + *****************************************************************************/ +int32_t +em_read_ich8_data(struct em_hw *hw, uint32_t index, + uint32_t size, uint16_t* data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + uint32_t flash_linear_address; + uint32_t flash_data = 0; + int32_t error = -E1000_ERR_EEPROM; + int32_t count = 0; + + DEBUGFUNC("em_read_ich8_data"); + + if (size < 1 || size > 2 || data == 0x0 || + index > ICH8_FLASH_LINEAR_ADDR_MASK) + return error; + + flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) + + hw->flash_base_addr; + + do { + usec_delay(1); + /* Steps */ + error = em_ich8_cycle_init(hw); + if (error != E1000_SUCCESS) + break; + + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size - 1; + hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_READ; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of index into Flash Linear address field in + * Flash Address */ + /* TODO: TBD maybe check the index against the size of flash */ + + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address); + + error = em_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT); + + /* Check if FCERR is set to 1, if set to 1, clear it and try the whole + * sequence a few more times, else read in (shift in) the Flash Data0, + * the order is least significant byte first msb to lsb */ + if (error == E1000_SUCCESS) { + flash_data = E1000_READ_ICH8_REG(hw, ICH8_FLASH_FDATA0); + if (size == 1) { + *data = (uint8_t)(flash_data & 0x000000FF); + } else if (size == 2) { + *data = (uint16_t)(flash_data & 0x0000FFFF); + } + break; + } else { + /* If we've gotten here, then things are probably completely hosed, + * but if the error condition is detected, it won't hurt to give + * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + DEBUGOUT("Timeout error - flash cycle did not complete."); + break; + } + } + } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT); + + return error; +} + +/****************************************************************************** + * Writes One /two bytes to the NVM using the ICH8 flash access registers. + * + * hw - The pointer to the hw structure + * index - The index of the byte/word to read. + * size - Size of data to read, 1=byte 2=word + * data - The byte(s) to write to the NVM. + *****************************************************************************/ +int32_t +em_write_ich8_data(struct em_hw *hw, uint32_t index, uint32_t size, + uint16_t data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + uint32_t flash_linear_address; + uint32_t flash_data = 0; + int32_t error = -E1000_ERR_EEPROM; + int32_t count = 0; + + DEBUGFUNC("em_write_ich8_data"); + + if (size < 1 || size > 2 || data > size * 0xff || + index > ICH8_FLASH_LINEAR_ADDR_MASK) + return error; + + flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) + + hw->flash_base_addr; + + do { + usec_delay(1); + /* Steps */ + error = em_ich8_cycle_init(hw); + if (error != E1000_SUCCESS) + break; + + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size -1; + hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_WRITE; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of index into Flash Linear address field in + * Flash Address */ + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address); + + if (size == 1) + flash_data = (uint32_t)data & 0x00FF; + else + flash_data = (uint32_t)data; + + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FDATA0, flash_data); + + /* check if FCERR is set to 1 , if set to 1, clear it and try the whole + * sequence a few more times else done */ + error = em_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT); + if (error == E1000_SUCCESS) { + break; + } else { + /* If we're here, then things are most likely completely hosed, + * but if the error condition is detected, it won't hurt to give + * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + DEBUGOUT("Timeout error - flash cycle did not complete."); + break; + } + } + } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT); + + return error; +} + +/****************************************************************************** + * Reads a single byte from the NVM using the ICH8 flash access registers. + * + * hw - pointer to em_hw structure + * index - The index of the byte to read. + * data - Pointer to a byte to store the value read. + *****************************************************************************/ +int32_t +em_read_ich8_byte(struct em_hw *hw, uint32_t index, uint8_t* data) +{ + int32_t status = E1000_SUCCESS; + uint16_t word = 0; + + status = em_read_ich8_data(hw, index, 1, &word); + if (status == E1000_SUCCESS) { + *data = (uint8_t)word; + } + + return status; +} + +/****************************************************************************** + * Writes a single byte to the NVM using the ICH8 flash access registers. + * Performs verification by reading back the value and then going through + * a retry algorithm before giving up. + * + * hw - pointer to em_hw structure + * index - The index of the byte to write. + * byte - The byte to write to the NVM. + *****************************************************************************/ +int32_t +em_verify_write_ich8_byte(struct em_hw *hw, uint32_t index, uint8_t byte) +{ + int32_t error = E1000_SUCCESS; + int32_t program_retries; + uint8_t temp_byte; + + em_write_ich8_byte(hw, index, byte); + usec_delay(100); + + for (program_retries = 0; program_retries < 100; program_retries++) { + em_read_ich8_byte(hw, index, &temp_byte); + if (temp_byte == byte) + break; + usec_delay(10); + em_write_ich8_byte(hw, index, byte); + usec_delay(100); + } + if (program_retries == 100) + error = E1000_ERR_EEPROM; + + return error; +} + +/****************************************************************************** + * Writes a single byte to the NVM using the ICH8 flash access registers. + * + * hw - pointer to em_hw structure + * index - The index of the byte to read. + * data - The byte to write to the NVM. + *****************************************************************************/ +int32_t +em_write_ich8_byte(struct em_hw *hw, uint32_t index, uint8_t data) +{ + int32_t status = E1000_SUCCESS; + uint16_t word = (uint16_t)data; + + status = em_write_ich8_data(hw, index, 1, word); + + return status; +} + +/****************************************************************************** + * Reads a word from the NVM using the ICH8 flash access registers. + * + * hw - pointer to em_hw structure + * index - The starting byte index of the word to read. + * data - Pointer to a word to store the value read. + *****************************************************************************/ +int32_t +em_read_ich8_word(struct em_hw *hw, uint32_t index, uint16_t *data) +{ + int32_t status = E1000_SUCCESS; + status = em_read_ich8_data(hw, index, 2, data); + return status; +} + +/****************************************************************************** + * Writes a word to the NVM using the ICH8 flash access registers. + * + * hw - pointer to em_hw structure + * index - The starting byte index of the word to read. + * data - The word to write to the NVM. + *****************************************************************************/ +int32_t +em_write_ich8_word(struct em_hw *hw, uint32_t index, uint16_t data) +{ + int32_t status = E1000_SUCCESS; + status = em_write_ich8_data(hw, index, 2, data); + return status; +} + +/****************************************************************************** + * Erases the bank specified. Each bank is a 4k block. Segments are 0 based. + * segment N is 4096 * N + flash_reg_addr. + * + * hw - pointer to em_hw structure + * segment - 0 for first segment, 1 for second segment, etc. + *****************************************************************************/ +int32_t +em_erase_ich8_4k_segment(struct em_hw *hw, uint32_t segment) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + uint32_t flash_linear_address; + int32_t count = 0; + int32_t error = E1000_ERR_EEPROM; + int32_t iteration, seg_size; + int32_t sector_size; + int32_t j = 0; + int32_t error_flag = 0; + + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + + /* Determine HW Sector size: Read BERASE bits of Hw flash Status register */ + /* 00: The Hw sector is 256 bytes, hence we need to erase 16 + * consecutive sectors. The start index for the nth Hw sector can be + * calculated as = segment * 4096 + n * 256 + * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. + * The start index for the nth Hw sector can be calculated + * as = segment * 4096 + * 10: Error condition + * 11: The Hw sector size is much bigger than the size asked to + * erase...error condition */ + if (hsfsts.hsf_status.berasesz == 0x0) { + /* Hw sector size 256 */ + sector_size = seg_size = ICH8_FLASH_SEG_SIZE_256; + iteration = ICH8_FLASH_SECTOR_SIZE / ICH8_FLASH_SEG_SIZE_256; + } else if (hsfsts.hsf_status.berasesz == 0x1) { + sector_size = seg_size = ICH8_FLASH_SEG_SIZE_4K; + iteration = 1; + } else if (hsfsts.hsf_status.berasesz == 0x3) { + sector_size = seg_size = ICH8_FLASH_SEG_SIZE_64K; + iteration = 1; + } else { + return error; + } + + for (j = 0; j < iteration ; j++) { + do { + count++; + /* Steps */ + error = em_ich8_cycle_init(hw); + if (error != E1000_SUCCESS) { + error_flag = 1; + break; + } + + /* Write a value 11 (block Erase) in Flash Cycle field in Hw flash + * Control */ + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_ERASE; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of an index within the block into Flash + * Linear address field in Flash Address. This probably needs to + * be calculated here based off the on-chip segment size and the + * software segment size assumed (4K) */ + /* TBD */ + flash_linear_address = segment * sector_size + j * seg_size; + flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK; + flash_linear_address += hw->flash_base_addr; + + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address); + + error = em_ich8_flash_cycle(hw, 1000000); + /* Check if FCERR is set to 1. If 1, clear it and try the whole + * sequence a few more times else Done */ + if (error == E1000_SUCCESS) { + break; + } else { + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* repeat for some time before giving up */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + error_flag = 1; + break; + } + } + } while ((count < ICH8_FLASH_CYCLE_REPEAT_COUNT) && !error_flag); + if (error_flag == 1) + break; + } + if (error_flag != 1) + error = E1000_SUCCESS; + return error; +} + +/****************************************************************************** + * + * Reverse duplex setting without breaking the link. + * + * hw: Struct containing variables accessed by shared code + * + *****************************************************************************/ +int32_t +em_duplex_reversal(struct em_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data; + + if (hw->phy_type != em_phy_igp_3) + return E1000_SUCCESS; + + ret_val = em_read_phy_reg(hw, PHY_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data ^= MII_CR_FULL_DUPLEX; + + ret_val = em_write_phy_reg(hw, PHY_CTRL, phy_data); + if (ret_val) + return ret_val; + + ret_val = em_read_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= IGP3_PHY_MISC_DUPLEX_MANUAL_SET; + ret_val = em_write_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, phy_data); + + return ret_val; +} + +int32_t +em_init_lcd_from_nvm_config_region(struct em_hw *hw, + uint32_t cnf_base_addr, uint32_t cnf_size) +{ + uint32_t ret_val = E1000_SUCCESS; + uint16_t word_addr, reg_data, reg_addr; + uint16_t i; + + /* cnf_base_addr is in DWORD */ + word_addr = (uint16_t)(cnf_base_addr << 1); + + /* cnf_size is returned in size of dwords */ + for (i = 0; i < cnf_size; i++) { + ret_val = em_read_eeprom(hw, (word_addr + i*2), 1, ®_data); + if (ret_val) + return ret_val; + + ret_val = em_read_eeprom(hw, (word_addr + i*2 + 1), 1, ®_addr); + if (ret_val) + return ret_val; + + ret_val = em_get_software_flag(hw); + if (ret_val != E1000_SUCCESS) + return ret_val; + + ret_val = em_write_phy_reg_ex(hw, (uint32_t)reg_addr, reg_data); + + em_release_software_flag(hw); + } + + return ret_val; +} + + +/****************************************************************************** + * This function initializes the PHY from the NVM on ICH8 platforms. This + * is needed due to an issue where the NVM configuration is not properly + * autoloaded after power transitions. Therefore, after each PHY reset, we + * will load the configuration data out of the NVM manually. + * + * hw: Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +em_init_lcd_from_nvm(struct em_hw *hw) +{ + uint32_t reg_data, cnf_base_addr, cnf_size, ret_val, loop; + + if (hw->phy_type != em_phy_igp_3) + return E1000_SUCCESS; + + /* Check if SW needs configure the PHY */ + reg_data = E1000_READ_REG(hw, FEXTNVM); + if (!(reg_data & FEXTNVM_SW_CONFIG)) + return E1000_SUCCESS; + + /* Wait for basic configuration completes before proceeding*/ + loop = 0; + do { + reg_data = E1000_READ_REG(hw, STATUS) & E1000_STATUS_LAN_INIT_DONE; + usec_delay(100); + loop++; + } while ((!reg_data) && (loop < 50)); + + /* Clear the Init Done bit for the next init event */ + reg_data = E1000_READ_REG(hw, STATUS); + reg_data &= ~E1000_STATUS_LAN_INIT_DONE; + E1000_WRITE_REG(hw, STATUS, reg_data); + + /* Make sure HW does not configure LCD from PHY extended configuration + before SW configuration */ + reg_data = E1000_READ_REG(hw, EXTCNF_CTRL); + if ((reg_data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) == 0x0000) { + reg_data = E1000_READ_REG(hw, EXTCNF_SIZE); + cnf_size = reg_data & E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH; + cnf_size >>= 16; + if (cnf_size) { + reg_data = E1000_READ_REG(hw, EXTCNF_CTRL); + cnf_base_addr = reg_data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER; + /* cnf_base_addr is in DWORD */ + cnf_base_addr >>= 16; + + /* Configure LCD from extended configuration region. */ + ret_val = em_init_lcd_from_nvm_config_region(hw, cnf_base_addr, + cnf_size); + if (ret_val) + return ret_val; + } + } + + return E1000_SUCCESS; +} + + diff --git a/sys/dev/em/if_em_hw.h b/sys/dev/em/if_em_hw.h index 9e1a08c79636..d9ef97f02aae 100644 --- a/sys/dev/em/if_em_hw.h +++ b/sys/dev/em/if_em_hw.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright (c) 2001-2003, Intel Corporation + Copyright (c) 2001-2005, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -39,12 +39,13 @@ #ifndef _EM_HW_H_ #define _EM_HW_H_ +#ifdef LM +#include "if_em_osdep.h" +#else #include <dev/em/if_em_osdep.h> - -#ifndef NO_VERSION_CONTROL -#ident "@(#)$RCSfile: em_hw.h,v $$Revision: 1.178 $$Date: 2005/03/24 18:29:58 $" #endif + /* Forward declarations of structures used by the shared code */ struct em_hw; struct em_hw_stats; @@ -66,7 +67,11 @@ typedef enum { em_82541_rev_2, em_82547, em_82547_rev_2, + em_82571, + em_82572, em_82573, + em_80003es2lan, + em_ich8lan, em_num_macs } em_mac_type; @@ -75,6 +80,8 @@ typedef enum { em_eeprom_spi, em_eeprom_microwire, em_eeprom_flash, + em_eeprom_ich8, + em_eeprom_none, /* No NVM support */ em_num_eeprom_types } em_eeprom_type; @@ -102,6 +109,11 @@ typedef enum { em_fc_default = 0xFF } em_fc_type; +struct em_shadow_ram { + uint16_t eeprom_word; + boolean_t modified; +}; + /* PCI bus types */ typedef enum { em_bus_type_unknown = 0, @@ -129,6 +141,7 @@ typedef enum { em_bus_width_32, em_bus_width_64, em_bus_width_pciex_1, + em_bus_width_pciex_2, em_bus_width_pciex_4, em_bus_width_reserved } em_bus_width; @@ -144,6 +157,13 @@ typedef enum { } em_cable_length; typedef enum { + em_gg_cable_length_60 = 0, + em_gg_cable_length_60_115 = 1, + em_gg_cable_length_115_150 = 2, + em_gg_cable_length_150 = 4 +} em_gg_cable_length; + +typedef enum { em_igp_cable_length_10 = 10, em_igp_cable_length_20 = 20, em_igp_cable_length_30 = 30, @@ -155,6 +175,7 @@ typedef enum { em_igp_cable_length_90 = 90, em_igp_cable_length_100 = 100, em_igp_cable_length_110 = 110, + em_igp_cable_length_115 = 115, em_igp_cable_length_120 = 120, em_igp_cable_length_130 = 130, em_igp_cable_length_140 = 140, @@ -212,6 +233,9 @@ typedef enum { em_phy_m88 = 0, em_phy_igp, em_phy_igp_2, + em_phy_gg82563, + em_phy_igp_3, + em_phy_ife, em_phy_undefined = 0xFF } em_phy_type; @@ -285,6 +309,7 @@ typedef enum { #define E1000_ERR_MASTER_REQUESTS_PENDING 10 #define E1000_ERR_HOST_INTERFACE_COMMAND 11 #define E1000_BLK_PHY_RESET 12 +#define E1000_ERR_SWFW_SYNC 13 /* Function prototypes */ /* Initialization */ @@ -309,6 +334,11 @@ int32_t em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data) int32_t em_write_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data); int32_t em_phy_hw_reset(struct em_hw *hw); int32_t em_phy_reset(struct em_hw *hw); +void em_phy_powerdown_workaround(struct em_hw *hw); +int32_t em_kumeran_lock_loss_workaround(struct em_hw *hw); +int32_t em_duplex_reversal(struct em_hw *hw); +int32_t em_init_lcd_from_nvm_config_region(struct em_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size); +int32_t em_init_lcd_from_nvm(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); @@ -317,6 +347,8 @@ int32_t em_get_cable_length(struct em_hw *hw, uint16_t *min_length, uint16_t *ma 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); +int32_t em_read_kmrn_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *data); +int32_t em_write_kmrn_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data); /* EEPROM Functions */ int32_t em_init_eeprom_params(struct em_hw *hw); @@ -332,9 +364,10 @@ uint32_t em_enable_mng_pass_thru(struct em_hw *hw); #define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 /* Host Interface data length */ #define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 /* Time in ms to process MNG command */ -#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */ -#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */ -#define E1000_MNG_IAMT_MODE 0x3 +#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */ +#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */ +#define E1000_MNG_IAMT_MODE 0x3 +#define E1000_MNG_ICH_IAMT_MODE 0x2 #define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management Technology signature */ #define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */ @@ -355,18 +388,6 @@ struct em_host_mng_command_info { struct em_host_mng_command_header command_header; /* Command Head/Command Result Head has 4 bytes */ uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; /* Command data can length 0..0x658*/ }; -#ifdef __BIG_ENDIAN -struct em_host_mng_dhcp_cookie{ - uint32_t signature; - uint16_t vlan_id; - uint8_t reserved0; - uint8_t status; - uint32_t reserved1; - uint8_t checksum; - uint8_t reserved3; - uint16_t reserved2; -}; -#else struct em_host_mng_dhcp_cookie{ uint32_t signature; uint8_t status; @@ -377,16 +398,15 @@ struct em_host_mng_dhcp_cookie{ uint8_t reserved3; uint8_t checksum; }; -#endif -int32_t em_mng_write_dhcp_info(struct em_hw *hw, uint8_t *buffer, - uint16_t length); +int32_t em_mng_write_dhcp_info(struct em_hw *hw, uint8_t *buffer, + uint16_t length); boolean_t em_check_mng_mode(struct em_hw *hw); boolean_t em_enable_tx_pkt_filtering(struct em_hw *hw); int32_t em_mng_enable_host_if(struct em_hw *hw); int32_t em_mng_host_if_write(struct em_hw *hw, uint8_t *buffer, uint16_t length, uint16_t offset, uint8_t *sum); -int32_t em_mng_write_cmd_header(struct em_hw* hw, +int32_t em_mng_write_cmd_header(struct em_hw* hw, struct em_host_mng_command_header* hdr); int32_t em_mng_write_commit(struct em_hw *hw); @@ -399,6 +419,8 @@ int32_t em_read_part_num(struct em_hw *hw, uint32_t * part_num); int32_t em_read_mac_addr(struct em_hw * hw); int32_t em_swfw_sync_acquire(struct em_hw *hw, uint16_t mask); void em_swfw_sync_release(struct em_hw *hw, uint16_t mask); +void em_release_software_flag(struct em_hw *hw); +int32_t em_get_software_flag(struct em_hw *hw); /* Filters (multicast, vlan, receive) */ void em_init_rx_addrs(struct em_hw *hw); @@ -414,6 +436,7 @@ int32_t em_setup_led(struct em_hw *hw); int32_t em_cleanup_led(struct em_hw *hw); int32_t em_led_on(struct em_hw *hw); int32_t em_led_off(struct em_hw *hw); +int32_t em_blink_led_start(struct em_hw *hw); /* Adaptive IFS Functions */ @@ -428,9 +451,7 @@ void em_pci_clear_mwi(struct em_hw *hw); void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value); void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ -uint32_t em_io_read(struct em_hw *hw, unsigned long port); uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset); -void em_io_write(struct em_hw *hw, unsigned long port, uint32_t value); void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up); int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active); @@ -447,11 +468,49 @@ int32_t em_get_hw_eeprom_semaphore(struct em_hw *hw); void em_put_hw_eeprom_semaphore(struct em_hw *hw); int32_t em_commit_shadow_ram(struct em_hw *hw); uint8_t em_arc_subsystem_valid(struct em_hw *hw); +int32_t em_set_pci_ex_no_snoop(struct em_hw *hw, uint32_t no_snoop); + +int32_t em_read_ich8_byte(struct em_hw *hw, uint32_t index, + uint8_t *data); +int32_t em_verify_write_ich8_byte(struct em_hw *hw, uint32_t index, + uint8_t byte); +int32_t em_write_ich8_byte(struct em_hw *hw, uint32_t index, + uint8_t byte); +int32_t em_read_ich8_word(struct em_hw *hw, uint32_t index, + uint16_t *data); +int32_t em_write_ich8_word(struct em_hw *hw, uint32_t index, + uint16_t word); +int32_t em_read_ich8_data(struct em_hw *hw, uint32_t index, + uint32_t size, uint16_t *data); +int32_t em_write_ich8_data(struct em_hw *hw, uint32_t index, + uint32_t size, uint16_t data); +int32_t em_read_eeprom_ich8(struct em_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +int32_t em_write_eeprom_ich8(struct em_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +int32_t em_erase_ich8_4k_segment(struct em_hw *hw, uint32_t segment); +int32_t em_ich8_cycle_init(struct em_hw *hw); +int32_t em_ich8_flash_cycle(struct em_hw *hw, uint32_t timeout); +int32_t em_phy_ife_get_info(struct em_hw *hw, + struct em_phy_info *phy_info); +int32_t em_ife_disable_dynamic_power_down(struct em_hw *hw); +int32_t em_ife_enable_dynamic_power_down(struct em_hw *hw); +#define E1000_BAR_TYPE(v) ((v) & E1000_BAR_TYPE_MASK) +#define E1000_BAR_TYPE_MASK 0x00000001 +#define E1000_BAR_TYPE_MEM 0x00000000 +#define E1000_BAR_TYPE_IO 0x00000001 +#define E1000_BAR_MEM_TYPE(v) ((v) & E1000_BAR_MEM_TYPE_MASK) +#define E1000_BAR_MEM_TYPE_MASK 0x00000006 +#define E1000_BAR_MEM_TYPE_32BIT 0x00000000 +#define E1000_BAR_MEM_TYPE_64BIT 0x00000004 + +#ifndef E1000_READ_REG_IO #define E1000_READ_REG_IO(a, reg) \ em_read_reg_io((a), E1000_##reg) #define E1000_WRITE_REG_IO(a, reg, val) \ em_write_reg_io((a), E1000_##reg, val) +#endif /* PCI Device IDs */ #define E1000_DEV_ID_82542 0x1000 @@ -462,7 +521,6 @@ uint8_t em_arc_subsystem_valid(struct em_hw *hw); #define E1000_DEV_ID_82544GC_COPPER 0x100C #define E1000_DEV_ID_82544GC_LOM 0x100D #define E1000_DEV_ID_82540EM 0x100E -#define E1000_DEV_ID_82541ER_LOM 0x1014 #define E1000_DEV_ID_82540EM_LOM 0x1015 #define E1000_DEV_ID_82540EP_LOM 0x1016 #define E1000_DEV_ID_82540EP 0x1017 @@ -477,6 +535,7 @@ uint8_t em_arc_subsystem_valid(struct em_hw *hw); #define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D #define E1000_DEV_ID_82541EI 0x1013 #define E1000_DEV_ID_82541EI_MOBILE 0x1018 +#define E1000_DEV_ID_82541ER_LOM 0x1014 #define E1000_DEV_ID_82541ER 0x1078 #define E1000_DEV_ID_82547GI 0x1075 #define E1000_DEV_ID_82541GI 0x1076 @@ -486,12 +545,32 @@ uint8_t em_arc_subsystem_valid(struct em_hw *hw); #define E1000_DEV_ID_82546GB_FIBER 0x107A #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82546GB_PCIE 0x108A +#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define E1000_DEV_ID_82547EI 0x1019 #define E1000_DEV_ID_82547EI_MOBILE 0x101A +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F +#define E1000_DEV_ID_82572EI 0x10B9 #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A +#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 +#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 +#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA +#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB + +#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 +#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A +#define E1000_DEV_ID_ICH8_IGP_C 0x104B +#define E1000_DEV_ID_ICH8_IFE 0x104C +#define E1000_DEV_ID_ICH8_IGP_M 0x104D -#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -526,7 +605,7 @@ uint8_t em_arc_subsystem_valid(struct em_hw *hw); /* 802.1q VLAN Packet Sizes */ -#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */ +#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */ /* Ethertype field values */ #define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ @@ -559,8 +638,17 @@ uint8_t em_arc_subsystem_valid(struct em_hw *hw); E1000_IMS_TXDW | \ E1000_IMS_RXDMT0 | \ E1000_IMS_RXSEQ | \ + E1000_IMS_RXO | \ E1000_IMS_LSC) +/* Additional interrupts need to be handled for em_ich8lan: + DSW = The FW changed the status of the DISSW bit in FWSM + PHYINT = The LAN connected device generates an interrupt + EPRST = Manageability reset event */ +#define IMS_ICH8LAN_ENABLE_MASK (\ + E1000_IMS_DSW | \ + E1000_IMS_PHYINT | \ + E1000_IMS_EPRST) /* Number of high/low register pairs in the RAR. The RAR (Receive Address * Registers) holds the directed and multicast addresses that we monitor. We @@ -568,6 +656,7 @@ uint8_t em_arc_subsystem_valid(struct em_hw *hw); * E1000_RAR_ENTRIES - 1 multicast addresses. */ #define E1000_RAR_ENTRIES 15 +#define E1000_RAR_ENTRIES_ICH8LAN 7 #define MIN_NUMBER_OF_DESCRIPTORS 8 #define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 @@ -789,6 +878,9 @@ struct em_data_desc { #define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ #define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ +#define E1000_NUM_UNICAST_ICH8LAN 7 +#define E1000_MC_TBL_SIZE_ICH8LAN 32 + /* Receive Address Register */ struct em_rar { @@ -798,6 +890,7 @@ struct em_rar { /* Number of entries in the Multicast Table Array (MTA). */ #define E1000_NUM_MTA_REGISTERS 128 +#define E1000_NUM_MTA_REGISTERS_ICH8LAN 32 /* IPv4 Address Table Entry */ struct em_ipv4_at_entry { @@ -808,6 +901,7 @@ struct em_ipv4_at_entry { /* Four wakeup IP addresses are supported */ #define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4 #define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX +#define E1000_IP4AT_SIZE_ICH8LAN 3 #define E1000_IP6AT_SIZE 1 /* IPv6 Address Table Entry */ @@ -843,6 +937,8 @@ struct em_ffvt_entry { #define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX #define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_DISABLE_SERDES_LOOPBACK 0x0400 + /* Register Set. (82543, 82544) * * Registers are defined to be 32 bits and should be accessed as 32 bit values. @@ -863,6 +959,8 @@ struct em_ffvt_entry { #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ #define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_SCTL 0x00024 /* SerDes Control - RW */ +#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ @@ -874,16 +972,25 @@ struct em_ffvt_entry { #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ #define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ +#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ +#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */ +#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */ +#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ +#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ #define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ #define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */ #define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ #define E1000_TBT 0x00448 /* TX Burst Timer - RW */ #define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ #define E1000_LEDCTL 0x00E00 /* LED Control - RW */ #define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ #define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ +#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ +#define FEXTNVM_SW_CONFIG 0x0001 #define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ #define E1000_PBS 0x01008 /* Packet Buffer Size */ #define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ @@ -905,11 +1012,19 @@ struct em_ffvt_entry { #define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ #define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ #define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ -#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ +#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */ +#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */ +#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */ +#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ +#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ +#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ +#define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */ +#define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */ #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ #define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ #define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ #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 */ @@ -924,14 +1039,14 @@ struct em_ffvt_entry { #define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ #define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ #define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ -#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */ -#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */ -#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */ -#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */ -#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */ -#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */ -#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */ -#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */ +#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */ +#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */ +#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */ +#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */ +#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */ +#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */ +#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */ +#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */ #define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ #define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ #define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ @@ -990,15 +1105,15 @@ struct em_ffvt_entry { #define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ #define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ #define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ -#define E1000_IAC 0x4100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */ -#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */ -#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */ -#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */ -#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ -#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ -#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */ +#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ #define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ #define E1000_RFCTL 0x05008 /* Receive Filter Control*/ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ @@ -1018,6 +1133,11 @@ struct em_ffvt_entry { #define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ #define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ +#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */ +#define E1000_MDPHYA 0x0003C /* PHY address - RW */ +#define E1000_MANC2H 0x05860 /* Managment Control To Host - RW */ +#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ + #define E1000_GCR 0x05B00 /* PCI-Ex Control */ #define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ #define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ @@ -1028,6 +1148,14 @@ struct em_ffvt_entry { #define E1000_FWSM 0x05B54 /* FW Semaphore */ #define E1000_FFLT_DBG 0x05F04 /* Debug Register */ #define E1000_HICR 0x08F00 /* Host Inteface Control */ + +/* RSS registers */ +#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ +#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ +#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */ +#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */ +#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ +#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ /* Register Set (82542) * * Some of the 82542 registers are located at different offsets than they are @@ -1042,6 +1170,8 @@ struct em_ffvt_entry { #define E1000_82542_CTRL_EXT E1000_CTRL_EXT #define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_SCTL E1000_SCTL +#define E1000_82542_FEXTNVM E1000_FEXTNVM #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH #define E1000_82542_FCT E1000_FCT @@ -1059,6 +1189,31 @@ struct em_ffvt_entry { #define E1000_82542_RDLEN 0x00118 #define E1000_82542_RDH 0x00120 #define E1000_82542_RDT 0x00128 +#define E1000_82542_RDTR0 E1000_82542_RDTR +#define E1000_82542_RDBAL0 E1000_82542_RDBAL +#define E1000_82542_RDBAH0 E1000_82542_RDBAH +#define E1000_82542_RDLEN0 E1000_82542_RDLEN +#define E1000_82542_RDH0 E1000_82542_RDH +#define E1000_82542_RDT0 E1000_82542_RDT +#define E1000_82542_SRRCTL(_n) (0x280C + ((_n) << 8)) /* Split and Replication + * RX Control - RW */ +#define E1000_82542_DCA_RXCTRL(_n) (0x02814 + ((_n) << 8)) +#define E1000_82542_RDBAH3 0x02B04 /* RX Desc Base High Queue 3 - RW */ +#define E1000_82542_RDBAL3 0x02B00 /* RX Desc Low Queue 3 - RW */ +#define E1000_82542_RDLEN3 0x02B08 /* RX Desc Length Queue 3 - RW */ +#define E1000_82542_RDH3 0x02B10 /* RX Desc Head Queue 3 - RW */ +#define E1000_82542_RDT3 0x02B18 /* RX Desc Tail Queue 3 - RW */ +#define E1000_82542_RDBAL2 0x02A00 /* RX Desc Base Low Queue 2 - RW */ +#define E1000_82542_RDBAH2 0x02A04 /* RX Desc Base High Queue 2 - RW */ +#define E1000_82542_RDLEN2 0x02A08 /* RX Desc Length Queue 2 - RW */ +#define E1000_82542_RDH2 0x02A10 /* RX Desc Head Queue 2 - RW */ +#define E1000_82542_RDT2 0x02A18 /* RX Desc Tail Queue 2 - RW */ +#define E1000_82542_RDTR1 0x00130 +#define E1000_82542_RDBAL1 0x00138 +#define E1000_82542_RDBAH1 0x0013C +#define E1000_82542_RDLEN1 0x00140 +#define E1000_82542_RDH1 0x00148 +#define E1000_82542_RDT1 0x00150 #define E1000_82542_FCRTH 0x00160 #define E1000_82542_FCRTL 0x00168 #define E1000_82542_FCTTV E1000_FCTTV @@ -1066,6 +1221,7 @@ struct em_ffvt_entry { #define E1000_82542_RXCW E1000_RXCW #define E1000_82542_MTA 0x00200 #define E1000_82542_TCTL E1000_TCTL +#define E1000_82542_TCTL_EXT E1000_TCTL_EXT #define E1000_82542_TIPG E1000_TIPG #define E1000_82542_TDBAL 0x00420 #define E1000_82542_TDBAH 0x00424 @@ -1089,11 +1245,14 @@ struct em_ffvt_entry { #define E1000_82542_FLOP E1000_FLOP #define E1000_82542_EXTCNF_CTRL E1000_EXTCNF_CTRL #define E1000_82542_EXTCNF_SIZE E1000_EXTCNF_SIZE +#define E1000_82542_PHY_CTRL E1000_PHY_CTRL #define E1000_82542_ERT E1000_ERT #define E1000_82542_RXDCTL E1000_RXDCTL +#define E1000_82542_RXDCTL1 E1000_RXDCTL1 #define E1000_82542_RADV E1000_RADV #define E1000_82542_RSRPD E1000_RSRPD #define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_KABGTXD E1000_KABGTXD #define E1000_82542_TDFHS E1000_TDFHS #define E1000_82542_TDFTS E1000_TDFTS #define E1000_82542_TDFPC E1000_TDFPC @@ -1207,6 +1366,15 @@ struct em_ffvt_entry { #define E1000_82542_ICRXOC E1000_ICRXOC #define E1000_82542_HICR E1000_HICR +#define E1000_82542_CPUVEC E1000_CPUVEC +#define E1000_82542_MRQC E1000_MRQC +#define E1000_82542_RETA E1000_RETA +#define E1000_82542_RSSRK E1000_RSSRK +#define E1000_82542_RSSIM E1000_RSSIM +#define E1000_82542_RSSIR E1000_RSSIR +#define E1000_82542_KUMCTRLSTA E1000_KUMCTRLSTA +#define E1000_82542_SW_FW_SYNC E1000_SW_FW_SYNC + /* Statistics counters collected by the MAC */ struct em_hw_stats { uint64_t crcerrs; @@ -1287,6 +1455,9 @@ struct em_hw { uint32_t phy_init_script; em_media_type media_type; void *back; + struct em_shadow_ram *eeprom_shadow_ram; + uint32_t flash_bank_size; + uint32_t flash_base_addr; em_fc_type fc; em_bus_speed bus_speed; em_bus_width bus_width; @@ -1297,6 +1468,8 @@ struct em_hw { em_ffe_config ffe_config_state; uint32_t asf_firmware_present; uint32_t eeprom_semaphore_present; + uint32_t swfw_sync_present; + uint32_t swfwhw_semaphore_present; unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; @@ -1346,6 +1519,7 @@ struct em_hw { boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; + boolean_t laa_is_present; boolean_t phy_reset_disable; boolean_t fc_send_xon; boolean_t fc_strict_ieee; @@ -1354,6 +1528,8 @@ struct em_hw { boolean_t ifs_params_forced; boolean_t in_ifs_mode; boolean_t mng_reg_access_disabled; + boolean_t leave_av_bit_off; + boolean_t kmrn_lock_loss_workaround_disabled; }; @@ -1384,7 +1560,10 @@ struct em_hw { #define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ #define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ #define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ #define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ +#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ +#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ #define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ @@ -1399,6 +1578,7 @@ struct em_hw { #define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ #define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ #define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */ /* Device Status */ #define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ @@ -1413,6 +1593,8 @@ struct em_hw { #define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ #define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ #define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion + by EEPROM/Flash */ #define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ #define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ @@ -1421,6 +1603,16 @@ struct em_hw { #define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ #define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ #define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ +#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ +#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ +#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ +#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ +#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */ +#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ +#define E1000_STATUS_FUSE_8 0x04000000 +#define E1000_STATUS_FUSE_9 0x08000000 +#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ +#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ /* Constants used to intrepret the masked PCI-X bus speed. */ #define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ @@ -1456,9 +1648,14 @@ struct em_hw { #define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ #define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ #define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ +#define E1000_EECD_SECVAL_SHIFT 22 #define E1000_STM_OPCODE 0xDB00 #define E1000_HICR_FW_RESET 0xC0 +#define E1000_SHADOW_RAM_WORDS 2048 +#define E1000_ICH8_NVM_SIG_WORD 0x13 +#define E1000_ICH8_NVM_SIG_MASK 0xC0 + /* EEPROM Read */ #define E1000_EERD_START 0x00000001 /* Start Read */ #define E1000_EERD_DONE 0x00000010 /* Read Done */ @@ -1493,16 +1690,23 @@ struct em_hw { #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ #define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ #define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ +#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 #define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 #define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 +#define E1000_CTRL_EXT_LINK_MODE_SERDES 0x00C00000 #define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 #define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 #define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 #define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ +#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error detection enabled */ +#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity error detection enable */ +#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 /* MDI Control */ #define E1000_MDIC_DATA_MASK 0x0000FFFF @@ -1516,6 +1720,51 @@ struct em_hw { #define E1000_MDIC_INT_EN 0x20000000 #define E1000_MDIC_ERROR 0x40000000 +#define E1000_KUMCTRLSTA_MASK 0x0000FFFF +#define E1000_KUMCTRLSTA_OFFSET 0x001F0000 +#define E1000_KUMCTRLSTA_OFFSET_SHIFT 16 +#define E1000_KUMCTRLSTA_REN 0x00200000 + +#define E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL 0x00000000 +#define E1000_KUMCTRLSTA_OFFSET_CTRL 0x00000001 +#define E1000_KUMCTRLSTA_OFFSET_INB_CTRL 0x00000002 +#define E1000_KUMCTRLSTA_OFFSET_DIAG 0x00000003 +#define E1000_KUMCTRLSTA_OFFSET_TIMEOUTS 0x00000004 +#define E1000_KUMCTRLSTA_OFFSET_INB_PARAM 0x00000009 +#define E1000_KUMCTRLSTA_OFFSET_HD_CTRL 0x00000010 +#define E1000_KUMCTRLSTA_OFFSET_M2P_SERDES 0x0000001E +#define E1000_KUMCTRLSTA_OFFSET_M2P_MODES 0x0000001F + +/* FIFO Control */ +#define E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS 0x00000008 +#define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800 + +/* In-Band Control */ +#define E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT 0x00000500 +#define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010 + +/* Half-Duplex Control */ +#define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004 +#define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000 + +#define E1000_KUMCTRLSTA_OFFSET_K0S_CTRL 0x0000001E + +#define E1000_KUMCTRLSTA_DIAG_FELPBK 0x2000 +#define E1000_KUMCTRLSTA_DIAG_NELPBK 0x1000 + +#define E1000_KUMCTRLSTA_K0S_100_EN 0x2000 +#define E1000_KUMCTRLSTA_K0S_GBE_EN 0x1000 +#define E1000_KUMCTRLSTA_K0S_ENTRY_LATENCY_MASK 0x0003 + +#define E1000_KABGTXD_BGSQLBIAS 0x00050000 + +#define E1000_PHY_CTRL_SPD_EN 0x00000001 +#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 +#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 +#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 +#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 +#define E1000_PHY_CTRL_B2B_EN 0x00000080 + /* LED Control */ #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 @@ -1534,6 +1783,7 @@ struct em_hw { #define E1000_LEDCTL_LED2_BLINK 0x00800000 #define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 #define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 #define E1000_LEDCTL_LED3_IVRT 0x40000000 #define E1000_LEDCTL_LED3_BLINK 0x80000000 @@ -1577,6 +1827,16 @@ struct em_hw { #define E1000_ICR_MNG 0x00040000 /* Manageability event */ #define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ #define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ +#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */ +#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ +#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ +#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ +#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ +#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */ /* Interrupt Cause Set */ #define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1597,6 +1857,15 @@ struct em_hw { #define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICS_DSW E1000_ICR_DSW +#define E1000_ICS_PHYINT E1000_ICR_PHYINT +#define E1000_ICS_EPRST E1000_ICR_EPRST /* Interrupt Mask Set */ #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1617,6 +1886,15 @@ struct em_hw { #define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMS_DSW E1000_ICR_DSW +#define E1000_IMS_PHYINT E1000_ICR_PHYINT +#define E1000_IMS_EPRST E1000_ICR_EPRST /* Interrupt Mask Clear */ #define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1637,6 +1915,15 @@ struct em_hw { #define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMC_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMC_DSW E1000_ICR_DSW +#define E1000_IMC_PHYINT E1000_ICR_PHYINT +#define E1000_IMC_EPRST E1000_ICR_EPRST /* Receive Control */ #define E1000_RCTL_RST 0x00000001 /* Software reset */ @@ -1695,7 +1982,7 @@ struct em_hw { * value2 = [0..64512], default=4096 * value3 = [0..64512], default=0 */ - + #define E1000_PSRCTL_BSIZE0_MASK 0x0000007F #define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 #define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 @@ -1706,6 +1993,12 @@ struct em_hw { #define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ #define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ +/* SW_W_SYNC definitions */ +#define E1000_SWFW_EEP_SM 0x0001 +#define E1000_SWFW_PHY0_SM 0x0002 +#define E1000_SWFW_PHY1_SM 0x0004 +#define E1000_SWFW_MAC_CSR_SM 0x0008 + /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ #define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */ @@ -1751,7 +2044,6 @@ struct em_hw { #define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ #define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc. still to be processed. */ - /* Transmit Configuration Word */ #define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ #define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ @@ -1785,6 +2077,11 @@ struct em_hw { #define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ #define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ #define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ +/* Extended Transmit Control */ +#define E1000_TCTL_EXT_BST_MASK 0x000003FF /* Backoff Slot Time */ +#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ + +#define DEFAULT_80003ES2LAN_TCTL_EXT_GCEX 0x00010000 /* Receive Checksum Control */ #define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ @@ -1794,6 +2091,17 @@ struct em_hw { #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ +/* Multiple Receive Queue Control */ +#define E1000_MRQC_ENABLE_MASK 0x00000003 +#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 +#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 +#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 /* Definitions for power management and wakeup registers */ /* Wake Up Control */ @@ -1852,6 +2160,7 @@ struct em_hw { #define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ #define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ #define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ #define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ #define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address * filtering */ @@ -1860,7 +2169,7 @@ struct em_hw { #define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address * filtering */ #define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ -#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ +#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ #define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ #define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ #define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ @@ -1882,6 +2191,15 @@ struct em_hw { #define E1000_FWSM_MODE_SHIFT 1 #define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */ +#define E1000_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI reset */ +#define E1000_FWSM_DISSW 0x10000000 /* FW disable SW Write Access */ +#define E1000_FWSM_SKUSEL_MASK 0x60000000 /* LAN SKU select */ +#define E1000_FWSM_SKUEL_SHIFT 29 +#define E1000_FWSM_SKUSEL_EMB 0x0 /* Embedded SKU */ +#define E1000_FWSM_SKUSEL_CONS 0x1 /* Consumer SKU */ +#define E1000_FWSM_SKUSEL_PERF_100 0x2 /* Perf & Corp 10/100 SKU */ +#define E1000_FWSM_SKUSEL_PERF_GBE 0x3 /* Perf & Copr GbE SKU */ + /* FFLT Debug Register */ #define E1000_FFLT_DBG_INVC 0x00100000 /* Invalid /C/ code handling */ @@ -1937,7 +2255,26 @@ struct em_host_command_info { #define E1000_MDALIGN 4096 -#define E1000_GCR_BEM32 0x00400000 +/* PCI-Ex registers*/ + +/* PCI-Ex Control Register */ +#define E1000_GCR_RXD_NO_SNOOP 0x00000001 +#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 +#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 +#define E1000_GCR_TXD_NO_SNOOP 0x00000008 +#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 +#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 + +#define PCI_EX_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ + E1000_GCR_RXDSCW_NO_SNOOP | \ + E1000_GCR_RXDSCR_NO_SNOOP | \ + E1000_GCR_TXD_NO_SNOOP | \ + E1000_GCR_TXDSCW_NO_SNOOP | \ + E1000_GCR_TXDSCR_NO_SNOOP) + +#define PCI_EX_82566_SNOOP_ALL PCI_EX_NO_SNOOP_ALL + +#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 /* Function Active and Power State to MNG */ #define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003 #define E1000_FACTPS_LAN0_VALID 0x00000004 @@ -1970,7 +2307,7 @@ struct em_host_command_info { #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_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ #define EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */ #define EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */ #define EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ @@ -1990,23 +2327,36 @@ struct em_host_command_info { /* EEPROM Word Offsets */ #define EEPROM_COMPAT 0x0003 #define EEPROM_ID_LED_SETTINGS 0x0004 +#define EEPROM_VERSION 0x0005 #define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ #define EEPROM_PHY_CLASS_WORD 0x0007 #define EEPROM_INIT_CONTROL1_REG 0x000A #define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010 #define EEPROM_INIT_CONTROL3_PORT_B 0x0014 +#define EEPROM_INIT_3GIO_3 0x001A +#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020 #define EEPROM_INIT_CONTROL3_PORT_A 0x0024 #define EEPROM_CFG 0x0012 #define EEPROM_FLASH_VERSION 0x0032 #define EEPROM_CHECKSUM_REG 0x003F +#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ +#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */ + /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_0000 0x0000 #define ID_LED_RESERVED_FFFF 0xFFFF +#define ID_LED_RESERVED_82573 0xF746 +#define ID_LED_DEFAULT_82573 0x1811 #define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ (ID_LED_OFF1_OFF2 << 8) | \ (ID_LED_DEF1_DEF2 << 4) | \ (ID_LED_DEF1_DEF2)) +#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_DEF1_OFF2 << 8) | \ + (ID_LED_DEF1_ON2 << 4) | \ + (ID_LED_DEF1_DEF2)) #define ID_LED_DEF1_DEF2 0x1 #define ID_LED_DEF1_ON2 0x2 #define ID_LED_DEF1_OFF2 0x3 @@ -2041,6 +2391,14 @@ struct em_host_command_info { #define EEPROM_WORD0F_ASM_DIR 0x2000 #define EEPROM_WORD0F_ANE 0x0800 #define EEPROM_WORD0F_SWPDIO_EXT 0x00F0 +#define EEPROM_WORD0F_LPLU 0x0001 + +/* Mask bits for fields in Word 0x10/0x20 of the EEPROM */ +#define EEPROM_WORD1020_GIGA_DISABLE 0x0010 +#define EEPROM_WORD1020_GIGA_DISABLE_NON_D0A 0x0008 + +/* Mask bits for fields in Word 0x1a of the EEPROM */ +#define EEPROM_WORD1A_ASPM_MASK 0x000C /* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ #define EEPROM_SUM 0xBABA @@ -2057,7 +2415,10 @@ struct em_host_command_info { /* Collision related configuration parameters */ #define E1000_COLLISION_THRESHOLD 15 #define E1000_CT_SHIFT 4 -#define E1000_COLLISION_DISTANCE 64 +/* Collision distance is a 0-based value that applies to + * half-duplex-capable hardware only. */ +#define E1000_COLLISION_DISTANCE 63 +#define E1000_COLLISION_DISTANCE_82542 64 #define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE #define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE #define E1000_COLD_SHIFT 12 @@ -2081,8 +2442,11 @@ struct em_host_command_info { #define DEFAULT_82542_TIPG_IPGR2 10 #define DEFAULT_82543_TIPG_IPGR2 6 +#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 #define E1000_TIPG_IPGR2_SHIFT 20 +#define DEFAULT_80003ES2LAN_TIPG_IPGT_10_100 0x00000009 +#define DEFAULT_80003ES2LAN_TIPG_IPGT_1000 0x00000008 #define E1000_TXDMAC_DPP 0x00000001 /* Adaptive IFS defines */ @@ -2106,21 +2470,29 @@ struct em_host_command_info { #define E1000_EXTCNF_CTRL_D_UD_OWNER 0x00000010 #define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 #define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x1FFF0000 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x0FFF0000 #define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH 0x000000FF #define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH 0x0000FF00 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000 +#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 /* PBA constants */ +#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */ #define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */ #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_32K 0x0020 +#define E1000_PBA_34K 0x0022 +#define E1000_PBA_38K 0x0026 #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ +#define E1000_PBS_16K E1000_PBA_16K + /* Flow Control Constants */ #define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 #define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 @@ -2175,7 +2547,7 @@ struct em_host_command_info { /* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */ #define AUTO_READ_DONE_TIMEOUT 10 /* Number of milliseconds we wait for PHY configuration done after MAC reset */ -#define PHY_CFG_TIMEOUT 40 +#define PHY_CFG_TIMEOUT 100 #define E1000_TX_BUFFER_SIZE ((uint32_t)1514) @@ -2321,6 +2693,78 @@ struct em_host_command_info { #define IGP01E1000_ANALOG_REGS_PAGE 0x20C0 +/* Bits... + * 15-5: page + * 4-0: register offset + */ +#define GG82563_PAGE_SHIFT 5 +#define GG82563_REG(page, reg) \ + (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) +#define GG82563_MIN_ALT_REG 30 + +/* GG82563 Specific Registers */ +#define GG82563_PHY_SPEC_CTRL \ + GG82563_REG(0, 16) /* PHY Specific Control */ +#define GG82563_PHY_SPEC_STATUS \ + GG82563_REG(0, 17) /* PHY Specific Status */ +#define GG82563_PHY_INT_ENABLE \ + GG82563_REG(0, 18) /* Interrupt Enable */ +#define GG82563_PHY_SPEC_STATUS_2 \ + GG82563_REG(0, 19) /* PHY Specific Status 2 */ +#define GG82563_PHY_RX_ERR_CNTR \ + GG82563_REG(0, 21) /* Receive Error Counter */ +#define GG82563_PHY_PAGE_SELECT \ + GG82563_REG(0, 22) /* Page Select */ +#define GG82563_PHY_SPEC_CTRL_2 \ + GG82563_REG(0, 26) /* PHY Specific Control 2 */ +#define GG82563_PHY_PAGE_SELECT_ALT \ + GG82563_REG(0, 29) /* Alternate Page Select */ +#define GG82563_PHY_TEST_CLK_CTRL \ + GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */ + +#define GG82563_PHY_MAC_SPEC_CTRL \ + GG82563_REG(2, 21) /* MAC Specific Control Register */ +#define GG82563_PHY_MAC_SPEC_CTRL_2 \ + GG82563_REG(2, 26) /* MAC Specific Control 2 */ + +#define GG82563_PHY_DSP_DISTANCE \ + GG82563_REG(5, 26) /* DSP Distance */ + +/* Page 193 - Port Control Registers */ +#define GG82563_PHY_KMRN_MODE_CTRL \ + GG82563_REG(193, 16) /* Kumeran Mode Control */ +#define GG82563_PHY_PORT_RESET \ + GG82563_REG(193, 17) /* Port Reset */ +#define GG82563_PHY_REVISION_ID \ + GG82563_REG(193, 18) /* Revision ID */ +#define GG82563_PHY_DEVICE_ID \ + GG82563_REG(193, 19) /* Device ID */ +#define GG82563_PHY_PWR_MGMT_CTRL \ + GG82563_REG(193, 20) /* Power Management Control */ +#define GG82563_PHY_RATE_ADAPT_CTRL \ + GG82563_REG(193, 25) /* Rate Adaptation Control */ + +/* Page 194 - KMRN Registers */ +#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \ + GG82563_REG(194, 16) /* FIFO's Control/Status */ +#define GG82563_PHY_KMRN_CTRL \ + GG82563_REG(194, 17) /* Control */ +#define GG82563_PHY_INBAND_CTRL \ + GG82563_REG(194, 18) /* Inband Control */ +#define GG82563_PHY_KMRN_DIAGNOSTIC \ + GG82563_REG(194, 19) /* Diagnostic */ +#define GG82563_PHY_ACK_TIMEOUTS \ + GG82563_REG(194, 20) /* Acknowledge Timeouts */ +#define GG82563_PHY_ADV_ABILITY \ + GG82563_REG(194, 21) /* Advertised Ability */ +#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \ + GG82563_REG(194, 23) /* Link Partner Advertised Ability */ +#define GG82563_PHY_ADV_NEXT_PAGE \ + GG82563_REG(194, 24) /* Advertised Next Page */ +#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \ + GG82563_REG(194, 25) /* Link Partner Advertised Next page */ +#define GG82563_PHY_KMRN_MISC \ + GG82563_REG(194, 26) /* Misc. */ /* PHY Control Register */ #define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ @@ -2531,6 +2975,17 @@ struct em_host_command_info { #define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ #define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ +/* M88EC018 Rev 2 specific DownShift settings */ +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 + /* IGP01E1000 Specific Port Config Register - R/W */ #define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010 #define IGP01E1000_PSCFR_PRE_EN 0x0020 @@ -2602,11 +3057,11 @@ struct em_host_command_info { /* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */ #define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128 -#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128 +#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 113 /* The precision error of the cable length is +/- 10 meters */ #define IGP01E1000_AGC_RANGE 10 -#define IGP02E1000_AGC_RANGE 10 +#define IGP02E1000_AGC_RANGE 15 /* IGP01E1000 PCS Initialization register */ /* bits 3:6 in the PCS registers stores the channels polarity */ @@ -2634,6 +3089,113 @@ struct em_host_command_info { #define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080 #define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500 +/* GG82563 PHY Specific Status Register (Page 0, Register 16 */ +#define GG82563_PSCR_DISABLE_JABBER 0x0001 /* 1=Disable Jabber */ +#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Polarity Reversal Disabled */ +#define GG82563_PSCR_POWER_DOWN 0x0004 /* 1=Power Down */ +#define GG82563_PSCR_COPPER_TRANSMITER_DISABLE 0x0008 /* 1=Transmitter Disabled */ +#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060 +#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI configuration */ +#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX configuration */ +#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Automatic crossover */ +#define GG82563_PSCR_ENALBE_EXTENDED_DISTANCE 0x0080 /* 1=Enable Extended Distance */ +#define GG82563_PSCR_ENERGY_DETECT_MASK 0x0300 +#define GG82563_PSCR_ENERGY_DETECT_OFF 0x0000 /* 00,01=Off */ +#define GG82563_PSCR_ENERGY_DETECT_RX 0x0200 /* 10=Sense on Rx only (Energy Detect) */ +#define GG82563_PSCR_ENERGY_DETECT_RX_TM 0x0300 /* 11=Sense and Tx NLP */ +#define GG82563_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force Link Good */ +#define GG82563_PSCR_DOWNSHIFT_ENABLE 0x0800 /* 1=Enable Downshift */ +#define GG82563_PSCR_DOWNSHIFT_COUNTER_MASK 0x7000 +#define GG82563_PSCR_DOWNSHIFT_COUNTER_SHIFT 12 + +/* PHY Specific Status Register (Page 0, Register 17) */ +#define GG82563_PSSR_JABBER 0x0001 /* 1=Jabber */ +#define GG82563_PSSR_POLARITY 0x0002 /* 1=Polarity Reversed */ +#define GG82563_PSSR_LINK 0x0008 /* 1=Link is Up */ +#define GG82563_PSSR_ENERGY_DETECT 0x0010 /* 1=Sleep, 0=Active */ +#define GG82563_PSSR_DOWNSHIFT 0x0020 /* 1=Downshift */ +#define GG82563_PSSR_CROSSOVER_STATUS 0x0040 /* 1=MDIX, 0=MDI */ +#define GG82563_PSSR_RX_PAUSE_ENABLED 0x0100 /* 1=Receive Pause Enabled */ +#define GG82563_PSSR_TX_PAUSE_ENABLED 0x0200 /* 1=Transmit Pause Enabled */ +#define GG82563_PSSR_LINK_UP 0x0400 /* 1=Link Up */ +#define GG82563_PSSR_SPEED_DUPLEX_RESOLVED 0x0800 /* 1=Resolved */ +#define GG82563_PSSR_PAGE_RECEIVED 0x1000 /* 1=Page Received */ +#define GG82563_PSSR_DUPLEX 0x2000 /* 1-Full-Duplex */ +#define GG82563_PSSR_SPEED_MASK 0xC000 +#define GG82563_PSSR_SPEED_10MBPS 0x0000 /* 00=10Mbps */ +#define GG82563_PSSR_SPEED_100MBPS 0x4000 /* 01=100Mbps */ +#define GG82563_PSSR_SPEED_1000MBPS 0x8000 /* 10=1000Mbps */ + +/* PHY Specific Status Register 2 (Page 0, Register 19) */ +#define GG82563_PSSR2_JABBER 0x0001 /* 1=Jabber */ +#define GG82563_PSSR2_POLARITY_CHANGED 0x0002 /* 1=Polarity Changed */ +#define GG82563_PSSR2_ENERGY_DETECT_CHANGED 0x0010 /* 1=Energy Detect Changed */ +#define GG82563_PSSR2_DOWNSHIFT_INTERRUPT 0x0020 /* 1=Downshift Detected */ +#define GG82563_PSSR2_MDI_CROSSOVER_CHANGE 0x0040 /* 1=Crossover Changed */ +#define GG82563_PSSR2_FALSE_CARRIER 0x0100 /* 1=False Carrier */ +#define GG82563_PSSR2_SYMBOL_ERROR 0x0200 /* 1=Symbol Error */ +#define GG82563_PSSR2_LINK_STATUS_CHANGED 0x0400 /* 1=Link Status Changed */ +#define GG82563_PSSR2_AUTO_NEG_COMPLETED 0x0800 /* 1=Auto-Neg Completed */ +#define GG82563_PSSR2_PAGE_RECEIVED 0x1000 /* 1=Page Received */ +#define GG82563_PSSR2_DUPLEX_CHANGED 0x2000 /* 1=Duplex Changed */ +#define GG82563_PSSR2_SPEED_CHANGED 0x4000 /* 1=Speed Changed */ +#define GG82563_PSSR2_AUTO_NEG_ERROR 0x8000 /* 1=Auto-Neg Error */ + +/* PHY Specific Control Register 2 (Page 0, Register 26) */ +#define GG82563_PSCR2_10BT_POLARITY_FORCE 0x0002 /* 1=Force Negative Polarity */ +#define GG82563_PSCR2_1000MB_TEST_SELECT_MASK 0x000C +#define GG82563_PSCR2_1000MB_TEST_SELECT_NORMAL 0x0000 /* 00,01=Normal Operation */ +#define GG82563_PSCR2_1000MB_TEST_SELECT_112NS 0x0008 /* 10=Select 112ns Sequence */ +#define GG82563_PSCR2_1000MB_TEST_SELECT_16NS 0x000C /* 11=Select 16ns Sequence */ +#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 /* 1=Reverse Auto-Negotiation */ +#define GG82563_PSCR2_1000BT_DISABLE 0x4000 /* 1=Disable 1000BASE-T */ +#define GG82563_PSCR2_TRANSMITER_TYPE_MASK 0x8000 +#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_B 0x0000 /* 0=Class B */ +#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_A 0x8000 /* 1=Class A */ + +/* MAC Specific Control Register (Page 2, Register 21) */ +/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */ +#define GG82563_MSCR_TX_CLK_MASK 0x0007 +#define GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ 0x0004 +#define GG82563_MSCR_TX_CLK_100MBPS_25MHZ 0x0005 +#define GG82563_MSCR_TX_CLK_1000MBPS_2_5MHZ 0x0006 +#define GG82563_MSCR_TX_CLK_1000MBPS_25MHZ 0x0007 + +#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */ + +/* DSP Distance Register (Page 5, Register 26) */ +#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M; + 1 = 50-80M; + 2 = 80-110M; + 3 = 110-140M; + 4 = >140M */ + +/* Kumeran Mode Control Register (Page 193, Register 16) */ +#define GG82563_KMCR_PHY_LEDS_EN 0x0020 /* 1=PHY LEDs, 0=Kumeran Inband LEDs */ +#define GG82563_KMCR_FORCE_LINK_UP 0x0040 /* 1=Force Link Up */ +#define GG82563_KMCR_SUPPRESS_SGMII_EPD_EXT 0x0080 +#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT_MASK 0x0400 +#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT 0x0400 /* 1=6.25MHz, 0=0.8MHz */ +#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 + +/* Power Management Control Register (Page 193, Register 20) */ +#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 /* 1=Enalbe SERDES Electrical Idle */ +#define GG82563_PMCR_DISABLE_PORT 0x0002 /* 1=Disable Port */ +#define GG82563_PMCR_DISABLE_SERDES 0x0004 /* 1=Disable SERDES */ +#define GG82563_PMCR_REVERSE_AUTO_NEG 0x0008 /* 1=Enable Reverse Auto-Negotiation */ +#define GG82563_PMCR_DISABLE_1000_NON_D0 0x0010 /* 1=Disable 1000Mbps Auto-Neg in non D0 */ +#define GG82563_PMCR_DISABLE_1000 0x0020 /* 1=Disable 1000Mbps Auto-Neg Always */ +#define GG82563_PMCR_REVERSE_AUTO_NEG_D0A 0x0040 /* 1=Enable D0a Reverse Auto-Negotiation */ +#define GG82563_PMCR_FORCE_POWER_STATE 0x0080 /* 1=Force Power State */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_MASK 0x0300 +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_DR 0x0000 /* 00=Dr */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0U 0x0100 /* 01=D0u */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0A 0x0200 /* 10=D0a */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D3 0x0300 /* 11=D3 */ + +/* In-Band Control Register (Page 194, Register 18) */ +#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding Use */ + /* Bit definitions for valid PHY IDs. */ /* I = Integrated @@ -2648,6 +3210,195 @@ struct em_host_command_info { #define M88E1011_I_REV_4 0x04 #define M88E1111_I_PHY_ID 0x01410CC0 #define L1LXT971A_PHY_ID 0x001378E0 +#define GG82563_E_PHY_ID 0x01410CA0 + + +/* Bits... + * 15-5: page + * 4-0: register offset + */ +#define PHY_PAGE_SHIFT 5 +#define PHY_REG(page, reg) \ + (((page) << PHY_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) + +#define IGP3_PHY_PORT_CTRL \ + PHY_REG(769, 17) /* Port General Configuration */ +#define IGP3_PHY_RATE_ADAPT_CTRL \ + PHY_REG(769, 25) /* Rate Adapter Control Register */ + +#define IGP3_KMRN_FIFO_CTRL_STATS \ + PHY_REG(770, 16) /* KMRN FIFO's control/status register */ +#define IGP3_KMRN_POWER_MNG_CTRL \ + PHY_REG(770, 17) /* KMRN Power Management Control Register */ +#define IGP3_KMRN_INBAND_CTRL \ + PHY_REG(770, 18) /* KMRN Inband Control Register */ +#define IGP3_KMRN_DIAG \ + PHY_REG(770, 19) /* KMRN Diagnostic register */ +#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 /* RX PCS is not synced */ +#define IGP3_KMRN_ACK_TIMEOUT \ + PHY_REG(770, 20) /* KMRN Acknowledge Timeouts register */ + +#define IGP3_VR_CTRL \ + PHY_REG(776, 18) /* Voltage regulator control register */ +#define IGP3_VR_CTRL_MODE_SHUT 0x0200 /* Enter powerdown, shutdown VRs */ + +#define IGP3_CAPABILITY \ + PHY_REG(776, 19) /* IGP3 Capability Register */ + +/* Capabilities for SKU Control */ +#define IGP3_CAP_INITIATE_TEAM 0x0001 /* Able to initiate a team */ +#define IGP3_CAP_WFM 0x0002 /* Support WoL and PXE */ +#define IGP3_CAP_ASF 0x0004 /* Support ASF */ +#define IGP3_CAP_LPLU 0x0008 /* Support Low Power Link Up */ +#define IGP3_CAP_DC_AUTO_SPEED 0x0010 /* Support AC/DC Auto Link Speed */ +#define IGP3_CAP_SPD 0x0020 /* Support Smart Power Down */ +#define IGP3_CAP_MULT_QUEUE 0x0040 /* Support 2 tx & 2 rx queues */ +#define IGP3_CAP_RSS 0x0080 /* Support RSS */ +#define IGP3_CAP_8021PQ 0x0100 /* Support 802.1Q & 802.1p */ +#define IGP3_CAP_AMT_CB 0x0200 /* Support active manageability and circuit breaker */ + +#define IGP3_PPC_JORDAN_EN 0x0001 +#define IGP3_PPC_JORDAN_GIGA_SPEED 0x0002 + +#define IGP3_KMRN_PMC_EE_IDLE_LINK_DIS 0x0001 +#define IGP3_KMRN_PMC_K0S_ENTRY_LATENCY_MASK 0x001E +#define IGP3_KMRN_PMC_K0S_MODE1_EN_GIGA 0x0020 +#define IGP3_KMRN_PMC_K0S_MODE1_EN_100 0x0040 + +#define IGP3E1000_PHY_MISC_CTRL 0x1B /* Misc. Ctrl register */ +#define IGP3_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Duplex Manual Set */ + +#define IGP3_KMRN_EXT_CTRL PHY_REG(770, 18) +#define IGP3_KMRN_EC_DIS_INBAND 0x0080 + +#define IGP03E1000_E_PHY_ID 0x02A80390 +#define IFE_E_PHY_ID 0x02A80330 /* 10/100 PHY */ +#define IFE_PLUS_E_PHY_ID 0x02A80320 +#define IFE_C_E_PHY_ID 0x02A80310 + +#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 /* 100BaseTx Extended Status, Control and Address */ +#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY special control register */ +#define IFE_PHY_RCV_FALSE_CARRIER 0x13 /* 100BaseTx Receive False Carrier Counter */ +#define IFE_PHY_RCV_DISCONNECT 0x14 /* 100BaseTx Receive Disconnet Counter */ +#define IFE_PHY_RCV_ERROT_FRAME 0x15 /* 100BaseTx Receive Error Frame Counter */ +#define IFE_PHY_RCV_SYMBOL_ERR 0x16 /* Receive Symbol Error Counter */ +#define IFE_PHY_PREM_EOF_ERR 0x17 /* 100BaseTx Receive Premature End Of Frame Error Counter */ +#define IFE_PHY_RCV_EOF_ERR 0x18 /* 10BaseT Receive End Of Frame Error Counter */ +#define IFE_PHY_TX_JABBER_DETECT 0x19 /* 10BaseT Transmit Jabber Detect Counter */ +#define IFE_PHY_EQUALIZER 0x1A /* PHY Equalizer Control and Status */ +#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY special control and LED configuration */ +#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control register */ +#define IFE_PHY_HWI_CONTROL 0x1D /* Hardware Integrity Control (HWI) */ + +#define IFE_PESC_REDUCED_POWER_DOWN_DISABLE 0x2000 /* Defaut 1 = Disable auto reduced power down */ +#define IFE_PESC_100BTX_POWER_DOWN 0x0400 /* Indicates the power state of 100BASE-TX */ +#define IFE_PESC_10BTX_POWER_DOWN 0x0200 /* Indicates the power state of 10BASE-T */ +#define IFE_PESC_POLARITY_REVERSED 0x0100 /* Indicates 10BASE-T polarity */ +#define IFE_PESC_PHY_ADDR_MASK 0x007C /* Bit 6:2 for sampled PHY address */ +#define IFE_PESC_SPEED 0x0002 /* Auto-negotiation speed result 1=100Mbs, 0=10Mbs */ +#define IFE_PESC_DUPLEX 0x0001 /* Auto-negotiation duplex result 1=Full, 0=Half */ +#define IFE_PESC_POLARITY_REVERSED_SHIFT 8 + +#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 /* 1 = Dyanmic Power Down disabled */ +#define IFE_PSC_FORCE_POLARITY 0x0020 /* 1=Reversed Polarity, 0=Normal */ +#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 /* 1=Auto Polarity Disabled, 0=Enabled */ +#define IFE_PSC_JABBER_FUNC_DISABLE 0x0001 /* 1=Jabber Disabled, 0=Normal Jabber Operation */ +#define IFE_PSC_FORCE_POLARITY_SHIFT 5 +#define IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT 4 + +#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X feature, default 0=disabled */ +#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X, 0=force MDI */ +#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ +#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorthm is completed */ +#define IFE_PMC_MDIX_MODE_SHIFT 6 +#define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */ + +#define IFE_PHC_HWI_ENABLE 0x8000 /* Enable the HWI feature */ +#define IFE_PHC_ABILITY_CHECK 0x4000 /* 1= Test Passed, 0=failed */ +#define IFE_PHC_TEST_EXEC 0x2000 /* PHY launch test pulses on the wire */ +#define IFE_PHC_HIGHZ 0x0200 /* 1 = Open Circuit */ +#define IFE_PHC_LOWZ 0x0400 /* 1 = Short Circuit */ +#define IFE_PHC_LOW_HIGH_Z_MASK 0x0600 /* Mask for indication type of problem on the line */ +#define IFE_PHC_DISTANCE_MASK 0x01FF /* Mask for distance to the cable problem, in 80cm granularity */ +#define IFE_PHC_RESET_ALL_MASK 0x0000 /* Disable HWI */ +#define IFE_PSCL_PROBE_MODE 0x0020 /* LED Probe mode */ +#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ +#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ + +#define ICH8_FLASH_COMMAND_TIMEOUT 500 /* 500 ms , should be adjusted */ +#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles , should be adjusted */ +#define ICH8_FLASH_SEG_SIZE_256 256 +#define ICH8_FLASH_SEG_SIZE_4K 4096 +#define ICH8_FLASH_SEG_SIZE_64K 65536 + +#define ICH8_CYCLE_READ 0x0 +#define ICH8_CYCLE_RESERVED 0x1 +#define ICH8_CYCLE_WRITE 0x2 +#define ICH8_CYCLE_ERASE 0x3 + +#define ICH8_FLASH_GFPREG 0x0000 +#define ICH8_FLASH_HSFSTS 0x0004 +#define ICH8_FLASH_HSFCTL 0x0006 +#define ICH8_FLASH_FADDR 0x0008 +#define ICH8_FLASH_FDATA0 0x0010 +#define ICH8_FLASH_FRACC 0x0050 +#define ICH8_FLASH_FREG0 0x0054 +#define ICH8_FLASH_FREG1 0x0058 +#define ICH8_FLASH_FREG2 0x005C +#define ICH8_FLASH_FREG3 0x0060 +#define ICH8_FLASH_FPR0 0x0074 +#define ICH8_FLASH_FPR1 0x0078 +#define ICH8_FLASH_SSFSTS 0x0090 +#define ICH8_FLASH_SSFCTL 0x0092 +#define ICH8_FLASH_PREOP 0x0094 +#define ICH8_FLASH_OPTYPE 0x0096 +#define ICH8_FLASH_OPMENU 0x0098 + +#define ICH8_FLASH_REG_MAPSIZE 0x00A0 +#define ICH8_FLASH_SECTOR_SIZE 4096 +#define ICH8_GFPREG_BASE_MASK 0x1FFF +#define ICH8_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF + +/* ICH8 GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ +/* Offset 04h HSFSTS */ +union ich8_hws_flash_status { + struct ich8_hsfsts { + uint16_t flcdone :1; /* bit 0 Flash Cycle Done */ + uint16_t flcerr :1; /* bit 1 Flash Cycle Error */ + uint16_t dael :1; /* bit 2 Direct Access error Log */ + uint16_t berasesz :2; /* bit 4:3 Block/Sector Erase Size */ + uint16_t flcinprog :1; /* bit 5 flash SPI cycle in Progress */ + uint16_t reserved1 :2; /* bit 13:6 Reserved */ + uint16_t reserved2 :6; /* bit 13:6 Reserved */ + uint16_t fldesvalid :1; /* bit 14 Flash Descriptor Valid */ + uint16_t flockdn :1; /* bit 15 Flash Configuration Lock-Down */ + } hsf_status; + uint16_t regval; +}; + +/* ICH8 GbE Flash Hardware Sequencing Flash control Register bit breakdown */ +/* Offset 06h FLCTL */ +union ich8_hws_flash_ctrl { + struct ich8_hsflctl { + uint16_t flcgo :1; /* 0 Flash Cycle Go */ + uint16_t flcycle :2; /* 2:1 Flash Cycle */ + uint16_t reserved :5; /* 7:3 Reserved */ + uint16_t fldbcount :2; /* 9:8 Flash Data Byte Count */ + uint16_t flockdn :6; /* 15:10 Reserved */ + } hsf_ctrl; + uint16_t regval; +}; + +/* ICH8 Flash Region Access Permissions */ +union ich8_hws_flash_regacc { + struct ich8_flracc { + uint32_t grra :8; /* 0:7 GbE region Read Access */ + uint32_t grwa :8; /* 8:15 GbE region Write Access */ + uint32_t gmrag :8; /* 23:16 GbE Master Read Access Grant */ + uint32_t gmwag :8; /* 31:24 GbE Master Write Access Grant */ + } hsf_flregacc; + uint16_t regval; +}; /* Miscellaneous PHY bit definitions. */ #define PHY_PREAMBLE 0xFFFFFFFF diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h index ebd2c60d1742..94108dad0410 100644 --- a/sys/dev/em/if_em_osdep.h +++ b/sys/dev/em/if_em_osdep.h @@ -1,6 +1,6 @@ /************************************************************************** -Copyright (c) 2001-2005, Intel Corporation +Copyright (c) 2001-2006, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -36,40 +36,29 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef _FREEBSD_OS_H_ #define _FREEBSD_OS_H_ -#include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> +#include <sys/bus.h> #include <sys/mbuf.h> -#include <sys/protosw.h> -#include <sys/socket.h> #include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/bus.h> +#include <sys/socket.h> + #include <machine/bus.h> #include <sys/rman.h> #include <machine/resource.h> -#include <vm/vm.h> -#include <vm/pmap.h> + #include <machine/clock.h> -#if __FreeBSD_version >= 502000 -#include <dev/pci/pcivar.h> -#include <dev/pci/pcireg.h> -#else #include <pci/pcivar.h> #include <pci/pcireg.h> -#endif - -#define ASSERT(x) if(!(x)) panic("EM: x") - -/* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */ #define usec_delay(x) DELAY(x) #define msec_delay(x) DELAY(1000*(x)) +/* TODO: Should we be paranoid about delaying in interrupt context? */ #define msec_delay_irq(x) DELAY(1000*(x)) #define MSGOUT(S, A, B) printf(S "\n", A, B) #define DEBUGFUNC(F) DEBUGOUT(F); -#if DBG +#ifdef DBG #define DEBUGOUT(S) printf(S "\n") #define DEBUGOUT1(S,A) printf(S "\n",A) #define DEBUGOUT2(S,A,B) printf(S "\n",A,B) @@ -92,56 +81,98 @@ struct em_osdep { bus_space_tag_t mem_bus_space_tag; bus_space_handle_t mem_bus_space_handle; - struct device *dev; + bus_space_tag_t io_bus_space_tag; + bus_space_handle_t io_bus_space_handle; + bus_space_tag_t flash_bus_space_tag; + bus_space_handle_t flash_bus_space_handle; + device_t dev; }; -#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) +#define E1000_WRITE_FLUSH(hw) E1000_READ_REG(hw, STATUS) /* Read from an absolute offset in the adapter's memory space */ #define E1000_READ_OFFSET(hw, offset) \ bus_space_read_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ - offset) + ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, offset) /* Write to an absolute offset in the adapter's memory space */ #define E1000_WRITE_OFFSET(hw, offset, value) \ bus_space_write_4( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ - ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ - offset, \ - value) + ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, offset, value) /* Convert a register name to its offset in the adapter's memory space */ #define E1000_REG_OFFSET(hw, reg) \ ((hw)->mac_type >= em_82543 ? E1000_##reg : E1000_82542_##reg) +/* + * Register READ/WRITE macros. + * + * XXXGL: Due to define's namespace mangling in recent version of + * if_em_hw.*, we prepend "_" to the register name in all macros, + * to prevent reg from being substituted, and then, in E1000_REG_OFFSET() + * we prepend either "E1000" or "E1000_82542". + * + * P.S. The problematic defines are E1000_PHY_CTRL and PHY_CTRL. + * + * P.P.S. Intel has removed E1000_REG_OFFSET() and copy-pasted it to all + * macros. + */ +#define _E1000_REG_OFFSET(hw, reg) \ + ((hw)->mac_type >= em_82543 ? E1000##reg : E1000_82542##reg) + #define E1000_READ_REG(hw, reg) \ - E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg)) + E1000_READ_OFFSET(hw, _E1000_REG_OFFSET(hw, _##reg)) #define E1000_WRITE_REG(hw, reg, value) \ - E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg), value) + E1000_WRITE_OFFSET(hw, _E1000_REG_OFFSET(hw, _##reg), value) #define E1000_READ_REG_ARRAY(hw, reg, index) \ - E1000_READ_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2)) + E1000_READ_OFFSET(hw, _E1000_REG_OFFSET(hw, _##reg) + ((index) << 2)) #define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY #define E1000_WRITE_REG_ARRAY(hw, reg, index, value) \ - E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value) + E1000_WRITE_OFFSET(hw, _E1000_REG_OFFSET(hw, _##reg) + ((index) << 2), value) #define E1000_WRITE_REG_ARRAY_BYTE(hw, reg, index, value) \ bus_space_write_1( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ - E1000_REG_OFFSET(hw, reg) + (index), \ + _E1000_REG_OFFSET(hw, _##reg) + (index), \ value) #define E1000_WRITE_REG_ARRAY_WORD(hw, reg, index, value) \ bus_space_write_2( ((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \ ((struct em_osdep *)(hw)->back)->mem_bus_space_handle, \ - E1000_REG_OFFSET(hw, reg) + (index), \ + _E1000_REG_OFFSET(hw, _##reg) + (index), \ value) #define E1000_WRITE_REG_ARRAY_DWORD(hw, reg, index, value) \ - E1000_WRITE_OFFSET(hw, E1000_REG_OFFSET(hw, reg) + ((index) << 2), value) + E1000_WRITE_OFFSET(hw, _E1000_REG_OFFSET(hw, _##reg) + ((index) << 2), value) + +#define E1000_READ_ICH8_REG(hw, reg) \ + bus_space_read_4(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->flash_bus_space_handle, reg) + +#define E1000_READ_ICH8_REG16(hw, reg) \ + bus_space_read_2(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->flash_bus_space_handle, reg) + +#define E1000_WRITE_ICH8_REG(hw, reg, value) \ + bus_space_write_4(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->flash_bus_space_handle, reg, value) + +#define E1000_WRITE_ICH8_REG16(hw, reg, value) \ + bus_space_write_2(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->flash_bus_space_handle, reg, value) + +#define em_io_read(hw, port) \ + bus_space_read_4(((struct em_osdep *)(hw)->back)->io_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->io_bus_space_handle, (port)) + +#define em_io_write(hw, port, value) \ + bus_space_write_4(((struct em_osdep *)(hw)->back)->io_bus_space_tag, \ + ((struct em_osdep *)(hw)->back)->io_bus_space_handle, (port), \ + (value)) #endif /* _FREEBSD_OS_H_ */ |
