diff options
author | pdeuskar <pdeuskar@FreeBSD.org> | 2001-12-02 07:37:17 +0000 |
---|---|---|
committer | pdeuskar <pdeuskar@FreeBSD.org> | 2001-12-02 07:37:17 +0000 |
commit | e52687276867cfdb203948c2941ad2a43847b5dc (patch) | |
tree | 85eb0c8580aeca66d70261b776904dd348a68d0c | |
parent | e033cad08eaa75d199d027155a7cb92d9674aef5 (diff) | |
download | FreeBSD-src-e52687276867cfdb203948c2941ad2a43847b5dc.zip FreeBSD-src-e52687276867cfdb203948c2941ad2a43847b5dc.tar.gz |
This is the first commit of the Intel gigabit driver for
PRO/1000 cards.
Submitted by:Prafulla Deuskar
Reviewed by: Paul Saab
MFC after:1 week
-rw-r--r-- | sys/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/dev/em/if_em.c | 2632 | ||||
-rw-r--r-- | sys/dev/em/if_em.h | 410 | ||||
-rw-r--r-- | sys/dev/em/if_em_fxhw.c | 1457 | ||||
-rw-r--r-- | sys/dev/em/if_em_fxhw.h | 1338 | ||||
-rw-r--r-- | sys/dev/em/if_em_osdep.h | 95 | ||||
-rw-r--r-- | sys/dev/em/if_em_phy.c | 1223 | ||||
-rw-r--r-- | sys/dev/em/if_em_phy.h | 418 | ||||
-rw-r--r-- | sys/modules/Makefile | 1 | ||||
-rw-r--r-- | sys/modules/em/Makefile | 13 |
10 files changed, 7590 insertions, 0 deletions
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index ff9a9c0..4b827e3 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -401,3 +401,6 @@ netsmb/smb_smb.c optional netsmb netsmb/smb_subr.c optional netsmb netsmb/smb_trantcp.c optional netsmb netsmb/smb_usr.c optional netsmb +dev/em/if_em.c optional em +dev/em/if_em_fxhw.c optional em +dev/em/if_em_phy.c optional em diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c new file mode 100644 index 0000000..199e907 --- /dev/null +++ b/sys/dev/em/if_em.c @@ -0,0 +1,2632 @@ +/************************************************************************** +************************************************************************** + +Copyright (c) 2001 Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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$ +*************************************************************************** +***************************************************************************/ + +#include <dev/em/if_em.h> + +/********************************************************************* + * Set this to one to display debug statistics + *********************************************************************/ +int em_display_debug_stats = 0; + +/********************************************************************* + * Linked list of board private structures for all NICs found + *********************************************************************/ + +struct adapter *em_adapter_list = NULL; + + +/********************************************************************* + * Driver version + *********************************************************************/ + +char em_driver_version[] = "1.0.6"; + + +/********************************************************************* + * PCI Device ID Table + * + * Used by probe to select devices to load on + * Last field stores an index into em_strings + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } + *********************************************************************/ +static em_vendor_info_t em_vendor_info_array[] = +{ + /* Intel(R) PRO/1000 Network Connection */ + { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0 }, + { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0 }, + { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0 }, + { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0 }, + { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0 }, + { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0 }, + { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0 }, + /* required last entry */ + { 0, 0, 0, 0, 0} +}; + + +/********************************************************************* + * Table of branding strings for all supported NICs. + *********************************************************************/ + +static char *em_strings[] = { + "Intel(R) PRO/1000 Network Connection" +}; + +/********************************************************************* + * Function prototypes + *********************************************************************/ +static int em_probe __P((device_t)); +static int em_attach __P((device_t)); +static int em_detach __P((device_t)); +static int em_shutdown __P((device_t)); +static void em_intr __P((void *)); +static void em_start __P((struct ifnet *)); +static int em_ioctl __P((struct ifnet *, IOCTL_CMD_TYPE, caddr_t)); +static void em_watchdog __P((struct ifnet *)); +static void em_init __P((void *)); +static void em_stop __P((void *)); +static void em_media_status __P((struct ifnet *, struct ifmediareq *)); +static int em_media_change __P((struct ifnet *)); +static void em_identify_hardware __P((struct adapter *)); +static int em_allocate_pci_resources __P((struct adapter *)); +static void em_free_pci_resources __P((struct adapter *)); +static void em_local_timer __P((void *)); +static int em_hardware_init __P((struct adapter *)); +static void em_read_mac_address __P((struct adapter *, u_int8_t *)); +static void em_setup_interface __P((device_t, struct adapter *)); +static int em_setup_transmit_structures __P((struct adapter *)); +static void em_initialize_transmit_unit __P((struct adapter *)); +static int em_setup_receive_structures __P((struct adapter *)); +static void em_initialize_receive_unit __P((struct adapter *)); +static void EnableInterrupts __P((struct adapter *)); +static void DisableInterrupts __P((struct adapter *)); +static void em_free_transmit_structures __P((struct adapter *)); +static void em_free_receive_structures __P((struct adapter *)); +static void em_update_stats_counters __P((struct adapter *)); +static void em_clean_transmit_interrupts __P((struct adapter *)); +static int em_allocate_receive_structures __P((struct adapter *)); +static int em_allocate_transmit_structures __P((struct adapter *)); +static void em_process_receive_interrupts __P((struct adapter *)); +static void em_receive_checksum __P((struct adapter *, + PE1000_RECEIVE_DESCRIPTOR RxDescriptor, + struct mbuf *)); +static void em_transmit_checksum_setup __P((struct adapter *, + struct mbuf *, + struct em_tx_buffer *, + u_int32_t *, + u_int32_t *)); +static void em_set_promisc __P((struct adapter *)); +static void em_disable_promisc __P((struct adapter *)); +static void em_set_multi __P((struct adapter *)); +static void em_print_hw_stats __P((struct adapter *)); +static void em_print_link_status __P((struct adapter *)); +static int em_get_buf __P((struct em_rx_buffer *, struct adapter *, + struct mbuf *)); +static int em_get_std_buf __P((struct em_rx_buffer *, struct adapter *, + struct mbuf *)); +/* Jumbo Frame */ +static int em_alloc_jumbo_mem __P((struct adapter *)); +static void *em_jalloc __P((struct adapter *)); +static void em_jfree __P((caddr_t buf, void *args)); +static int em_get_jumbo_buf __P((struct em_rx_buffer *, struct adapter *, + struct mbuf *)); +/********************************************************************* + * FreeBSD Device Interface Entry Points + *********************************************************************/ + +static device_method_t em_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, em_probe), + DEVMETHOD(device_attach, em_attach), + DEVMETHOD(device_detach, em_detach), + DEVMETHOD(device_shutdown, em_shutdown), + {0, 0} +}; + +static driver_t em_driver = { + "em", em_methods, sizeof(struct adapter ), +}; + +static devclass_t em_devclass; +DRIVER_MODULE(if_em, pci, em_driver, em_devclass, 0, 0); + +/********************************************************************* + * Device identification routine + * + * em_probe determines if the driver should be loaded on + * adapter based on PCI vendor/device id of the adapter. + * + * return 0 on success, positive on failure + *********************************************************************/ + +static int +em_probe(device_t dev) +{ + 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); + + pci_device_id = pci_get_device(dev); + pci_subvendor_id = pci_get_subvendor(dev); + pci_subdevice_id = pci_get_subdevice(dev); + + ent = em_vendor_info_array; + while(ent->vendor_id != 0) { + if ((pci_vendor_id == ent->vendor_id) && + (pci_device_id == ent->device_id) && + + ((pci_subvendor_id == ent->subvendor_id) || + (ent->subvendor_id == PCI_ANY_ID)) && + + ((pci_subdevice_id == ent->subdevice_id) || + (ent->subdevice_id == PCI_ANY_ID))) { + INIT_DEBUGOUT1("em_probe: Found PRO/1000 (pci_device_id=0x%x)", + pci_device_id); + sprintf(adapter_name, "%s, Version - %s", em_strings[ent->index], + em_driver_version); + device_set_desc_copy(dev, adapter_name); + return(0); + } + ent++; + } + + 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. + * + * return 0 on success, positive on failure + *********************************************************************/ + +static int +em_attach(device_t dev) +{ + struct adapter * Adapter; + int s; + int tsize, rsize; + + 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->unit = device_get_unit(dev); + + if (em_adapter_list != NULL) + em_adapter_list->prev = Adapter; + Adapter->next = em_adapter_list; + em_adapter_list = Adapter; + + callout_handle_init(&Adapter->timer_handle); + + /* Determine hardware revision */ + em_identify_hardware(Adapter); + + /* Parameters (to be read from user) */ + Adapter->NumTxDescriptors = MAX_TXD; + Adapter->NumRxDescriptors = MAX_RXD; + Adapter->TxIntDelay = TIDV; + Adapter->RxIntDelay = RIDV; + Adapter->AutoNeg = DO_AUTO_NEG; + Adapter->WaitAutoNegComplete = WAIT_FOR_AUTO_NEG_DEFAULT; + Adapter->AutoNegAdvertised = AUTONEG_ADV_DEFAULT; + Adapter->TbiCompatibilityEnable = TRUE; + Adapter->RxBufferLen = EM_RXBUFFER_2048; + Adapter->RxChecksum = EM_ENABLE_RXCSUM_OFFLOAD; + Adapter->JumboEnable = EM_JUMBO_ENABLE_DEFAULT; + + Adapter->FlowControlHighWatermark = FC_DEFAULT_HI_THRESH; + Adapter->FlowControlLowWatermark = FC_DEFAULT_LO_THRESH; + Adapter->FlowControlPauseTime = FC_DEFAULT_TX_TIMER; + Adapter->FlowControlSendXon = TRUE; + Adapter->FlowControl = FLOW_CONTROL_FULL; + + + /* Set the max frame size assuming standard ethernet sized frames */ + Adapter->MaxFrameSize = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; + + /* This controls when hardware reports transmit completion status. */ + if ((EM_REPORT_TX_EARLY == 0) || (EM_REPORT_TX_EARLY == 1)) { + Adapter->ReportTxEarly = EM_REPORT_TX_EARLY; + } else { + if(Adapter->MacType < MAC_LIVENGOOD) { + Adapter->ReportTxEarly = 0; + } else { + Adapter->ReportTxEarly = 1; + } + } + + if (em_allocate_pci_resources(Adapter)) { + printf("em%d: Allocation of PCI resources failed\n", Adapter->unit); + em_free_pci_resources(Adapter); + splx(s); + return(ENXIO); + } + + tsize = EM_ROUNDUP(Adapter->NumTxDescriptors * + sizeof(E1000_TRANSMIT_DESCRIPTOR), 4096); + + /* Allocate Transmit Descriptor ring */ + if (!(Adapter->TxDescBase = (PE1000_TRANSMIT_DESCRIPTOR) + contigmalloc(tsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) { + printf("em%d: Unable to allocate TxDescriptor memory\n", Adapter->unit); + em_free_pci_resources(Adapter); + splx(s); + return(ENOMEM); + } + + rsize = EM_ROUNDUP(Adapter->NumRxDescriptors * + sizeof(E1000_RECEIVE_DESCRIPTOR), 4096); + + /* Allocate Receive Descriptor ring */ + if (!(Adapter->RxDescBase = (PE1000_RECEIVE_DESCRIPTOR) + contigmalloc(rsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) { + printf("em%d: Unable to allocate RxDescriptor memory\n", Adapter->unit); + em_free_pci_resources(Adapter); + contigfree(Adapter->TxDescBase, tsize, M_DEVBUF); + splx(s); + return(ENOMEM); + } + + /* Allocate memory for jumbo frame buffers. + * We don't support jumbo frames on 82542 based adapters. + */ + if (Adapter->MacType >= MAC_LIVENGOOD) { + if (em_alloc_jumbo_mem(Adapter)) { + printf("em%d: Unable to allocate Jumbo memory\n", Adapter->unit); + em_free_pci_resources(Adapter); + contigfree(Adapter->TxDescBase, tsize, M_DEVBUF); + contigfree(Adapter->RxDescBase, rsize, M_DEVBUF); + splx(s); + return(ENOMEM); + } + } + + /* Initialize the hardware */ + if (em_hardware_init(Adapter)) { + printf("em%d: Unable to initialize the hardware\n",Adapter->unit); + em_free_pci_resources(Adapter); + contigfree(Adapter->TxDescBase, tsize, M_DEVBUF); + contigfree(Adapter->RxDescBase, rsize, M_DEVBUF); + if (Adapter->MacType >= MAC_LIVENGOOD) + contigfree(Adapter->em_jumbo_buf, EM_JMEM, M_DEVBUF); + splx(s); + return(EIO); + } + + /* Setup OS specific network interface */ + em_setup_interface(dev, Adapter); + + /* Initialize statistics */ + em_clear_hw_stats_counters(Adapter); + em_update_stats_counters(Adapter); + Adapter->GetLinkStatus = 1; + em_check_for_link(Adapter); + + /* Print the link status */ + if (Adapter->LinkIsActive == 1) + printf("em%d: Speed:%d Mbps Duplex:%s\n", + Adapter->unit, + Adapter->LineSpeed, + Adapter->FullDuplex == FULL_DUPLEX ? "Full" : "Half"); + else + printf("em%d: Speed:N/A Duplex:N/A\n", Adapter->unit); + + + INIT_DEBUGOUT("em_attach: end"); + splx(s); + return(0); +} + +/********************************************************************* + * Device removal routine + * + * 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; + + INIT_DEBUGOUT("em_detach: begin"); + s = splimp(); + + em_stop(Adapter); + em_phy_hardware_reset(Adapter); + ether_ifdetach(&Adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); + em_free_pci_resources(Adapter); + + size = EM_ROUNDUP(Adapter->NumTxDescriptors * + sizeof(E1000_TRANSMIT_DESCRIPTOR), 4096); + + /* Free Transmit Descriptor ring */ + if (Adapter->TxDescBase) { + contigfree(Adapter->TxDescBase, size, M_DEVBUF); + Adapter->TxDescBase = NULL; + } + + size = EM_ROUNDUP(Adapter->NumRxDescriptors * + sizeof(E1000_RECEIVE_DESCRIPTOR), 4096); + + /* Free Receive Descriptor ring */ + if (Adapter->RxDescBase) { + contigfree(Adapter->RxDescBase, size, M_DEVBUF); + Adapter->RxDescBase = NULL; + } + + /* Free Jumbo Frame buffers */ + if (Adapter->MacType >= MAC_LIVENGOOD) { + if (Adapter->em_jumbo_buf) { + contigfree(Adapter->em_jumbo_buf, EM_JMEM, M_DEVBUF); + Adapter->em_jumbo_buf = 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; + + splx(s); + return(0); +} + +static int +em_shutdown(device_t dev) +{ + struct adapter * Adapter = device_get_softc(dev); + + /* Issue a global reset */ + em_adapter_stop(Adapter); + return(0); +} + + +/********************************************************************* + * Transmit entry point + * + * em_start is called by the stack to initiate a transmit. + * The driver will remain in this routine as long as there are + * packets to transmit and transmit resources are available. + * In case resources are not available stack is notified and + * the packet is requeued. + **********************************************************************/ + +static void +em_start(struct ifnet *ifp) +{ + int s; + struct em_tx_buffer *tx_buffer; + struct mbuf *m_head; + struct mbuf *mp; + vm_offset_t VirtualAddress; + u_int32_t txd_upper; + u_int32_t txd_lower; + PE1000_TRANSMIT_DESCRIPTOR CurrentTxDescriptor = NULL; + struct adapter * Adapter = ifp->if_softc; + + TXRX_DEBUGOUT("em_start: begin"); + + if (!Adapter->LinkIsActive) + return; + + s = splimp(); + while (ifp->if_snd.ifq_head != NULL) { + + IF_DEQUEUE(&ifp->if_snd, m_head); + + if(m_head == NULL) break; + + if (Adapter->NumTxDescriptorsAvail <= TX_CLEANUP_THRESHOLD) + em_clean_transmit_interrupts(Adapter); + + if (Adapter->NumTxDescriptorsAvail <= TX_CLEANUP_THRESHOLD) { + ifp->if_flags |= IFF_OACTIVE; + IF_PREPEND(&ifp->if_snd, m_head); +#ifdef DBG_STATS + Adapter->NoTxDescAvail++; +#endif + break; + } + + tx_buffer = STAILQ_FIRST(&Adapter->FreeSwTxPacketList); + if (!tx_buffer) { +#ifdef DBG_STATS + Adapter->NoTxBufferAvail1++; +#endif + /* + * OK so we should not get here but I've seen it so lets try to + * clean up and then try to get a SwPacket again and only break + * if we still don't get one + */ + em_clean_transmit_interrupts(Adapter); + tx_buffer = STAILQ_FIRST(&Adapter->FreeSwTxPacketList); + if (!tx_buffer) { + ifp->if_flags |= IFF_OACTIVE; + IF_PREPEND(&ifp->if_snd, m_head); +#ifdef DBG_STATS + Adapter->NoTxBufferAvail2++; +#endif + break; + } + } + STAILQ_REMOVE_HEAD(&Adapter->FreeSwTxPacketList, em_tx_entry); + tx_buffer->NumTxDescriptorsUsed = 0; + tx_buffer->Packet = m_head; + + if (ifp->if_hwassist > 0) { + em_transmit_checksum_setup(Adapter, m_head, tx_buffer, &txd_upper, &txd_lower); + } else { + txd_upper = 0; + txd_lower = 0; + } + + for (mp = m_head; mp != NULL; mp = mp->m_next) { + if (mp->m_len == 0) + continue; + CurrentTxDescriptor = Adapter->NextAvailTxDescriptor; + VirtualAddress = mtod(mp, vm_offset_t); + CurrentTxDescriptor->BufferAddress.Hi32 = 0; + CurrentTxDescriptor->BufferAddress.Lo32 = + vtophys(VirtualAddress); + + CurrentTxDescriptor->Lower.DwordData = (txd_lower | mp->m_len); + CurrentTxDescriptor->Upper.DwordData = (txd_upper); + + if (CurrentTxDescriptor == Adapter->LastTxDescriptor) + Adapter->NextAvailTxDescriptor = + Adapter->FirstTxDescriptor; + else + Adapter->NextAvailTxDescriptor++; + + Adapter->NumTxDescriptorsAvail--; + tx_buffer->NumTxDescriptorsUsed++; + } + /* Put this tx_buffer at the end in the "in use" list */ + STAILQ_INSERT_TAIL(&Adapter->UsedSwTxPacketList, tx_buffer, em_tx_entry); + + /* + * Last Descriptor of Packet needs End Of Packet (EOP), Report Status + * (RS) and append Ethernet CRC (IFCS) bits set. + */ + CurrentTxDescriptor->Lower.DwordData |= (Adapter->TxdCmd | E1000_TXD_CMD_EOP); + + /* Send a copy of the frame to the BPF listener */ + if (ifp->if_bpf) + bpf_mtap(ifp, m_head); + /* + * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 + * that this frame is available to transmit. + */ + E1000_WRITE_REG(Tdt, (((u_int32_t) Adapter->NextAvailTxDescriptor - + (u_int32_t) Adapter->FirstTxDescriptor) >> 4)); + } /* end of while loop */ + + splx(s); + + /* Set timeout in case chip has problems transmitting */ + ifp->if_timer = EM_TX_TIMEOUT; + + return; +} + +/********************************************************************* + * Ioctl entry point + * + * em_ioctl is called when the user wants to configure the + * interface. + * + * return 0 on success, positive on failure + **********************************************************************/ + +static int +em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) +{ + int s, + error = 0; + struct ifreq *ifr = (struct ifreq *) data; + struct adapter * Adapter = ifp->if_softc; + + s = splimp(); + switch (command) { + case SIOCSIFADDR: + case SIOCGIFADDR: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)"); + ether_ioctl(ifp, command, data); + break; + case SIOCSIFMTU: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)"); +#ifdef SUPPORTLARGEFRAME + if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN) { + error = EINVAL; + } else { + ifp->if_mtu = ifr->ifr_mtu; + Adapter->MaxFrameSize = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + em_init(Adapter); + } +#else + if (ifr->ifr_mtu > EM_JUMBO_MTU) { + error = EINVAL; + } else { + + if(ifr->ifr_mtu > ETHERMTU && + Adapter->MacType < MAC_LIVENGOOD) { + printf("Jumbo frames are not supported on 82542 based adapters\n"); + error = EINVAL; + } + else { + ifp->if_mtu = ifr->ifr_mtu; + if (ifp->if_mtu > ETHERMTU) { + Adapter->JumboEnable = 1; + Adapter->RxBufferLen = EM_RXBUFFER_16384; + } + else { + Adapter->JumboEnable = 0; + Adapter->RxBufferLen = EM_RXBUFFER_2048; + } + Adapter->MaxFrameSize = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + em_init(Adapter); + } + } +#endif + + break; + case SIOCSIFFLAGS: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING && + ifp->if_flags & IFF_PROMISC) { + em_set_promisc(Adapter); + } else if (ifp->if_flags & IFF_RUNNING && + !(ifp->if_flags & IFF_PROMISC)) { + em_disable_promisc(Adapter); + } else + em_init(Adapter); + } else { + if (ifp->if_flags & IFF_RUNNING) { + em_stop(Adapter); + } + } + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI"); + if (ifp->if_flags & IFF_RUNNING) { + DisableInterrupts(Adapter); + em_set_multi(Adapter); + if(Adapter->MacType == MAC_WISEMAN_2_0) + em_initialize_receive_unit(Adapter); + EnableInterrupts(Adapter); + } + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)"); + error = ifmedia_ioctl(ifp, ifr, &Adapter->media, command); + break; + default: + IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%d)\n", (int)command); + error = EINVAL; + } + + splx(s); + return(error); +} + +static void +em_set_promisc(struct adapter * Adapter) +{ + + u_int32_t reg_rctl; + struct ifnet *ifp = &Adapter->interface_data.ac_if; + + reg_rctl = E1000_READ_REG(Rctl); + + if(ifp->if_flags & IFF_PROMISC) { + reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + E1000_WRITE_REG(Rctl, reg_rctl); + } + else if (ifp->if_flags & IFF_ALLMULTI) { + reg_rctl |= E1000_RCTL_MPE; + reg_rctl &= ~E1000_RCTL_UPE; + E1000_WRITE_REG(Rctl, reg_rctl); + } + + return; +} + +static void +em_disable_promisc(struct adapter * Adapter) +{ + u_int32_t reg_rctl; + + reg_rctl = E1000_READ_REG(Rctl); + + reg_rctl &= (~E1000_RCTL_UPE); + reg_rctl &= (~E1000_RCTL_MPE); + E1000_WRITE_REG(Rctl, reg_rctl); + + return; +} + + +/********************************************************************* + * Multicast Update + * + * This routine is called whenever multicast address list is updated. + * + **********************************************************************/ + +static void +em_set_multi(struct adapter * Adapter) +{ + u_int32_t reg_rctl = 0; + u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; + u_int16_t PciCommandWord; + struct ifmultiaddr *ifma_ptr; + int i = 0; + int multi_cnt = 0; + struct ifnet *ifp = &Adapter->interface_data.ac_if; + + IOCTL_DEBUGOUT("em_set_multi: begin"); + + if(Adapter->MacType == MAC_WISEMAN_2_0) { + reg_rctl = E1000_READ_REG(Rctl); + if(Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { + PciCommandWord =Adapter->PciCommandWord & ~CMD_MEM_WRT_INVALIDATE; + pci_write_config(Adapter->dev, PCIR_COMMAND, PciCommandWord, 2); + } + reg_rctl |= E1000_RCTL_RST; + E1000_WRITE_REG(Rctl, reg_rctl); + DelayInMilliseconds(5); + } + + TAILQ_FOREACH(ifma_ptr, &ifp->if_multiaddrs, ifma_link) { + multi_cnt++; + bcopy(LLADDR((struct sockaddr_dl *)ifma_ptr->ifma_addr), + &mta[i*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); + i++; + } + + if (multi_cnt > MAX_NUM_MULTICAST_ADDRESSES) { + reg_rctl = E1000_READ_REG(Rctl); + reg_rctl |= E1000_RCTL_MPE; + E1000_WRITE_REG(Rctl, reg_rctl); + } + else + em_multicast_address_list_update(Adapter, mta, multi_cnt, 0); + + if(Adapter->MacType == MAC_WISEMAN_2_0) { + reg_rctl = E1000_READ_REG(Rctl); + reg_rctl &= ~E1000_RCTL_RST; + E1000_WRITE_REG(Rctl, reg_rctl); + DelayInMilliseconds(5); + if(Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { + pci_write_config(Adapter->dev, PCIR_COMMAND, Adapter->PciCommandWord, 2); + } + } + + return; +} + + +/********************************************************************* + * Watchdog entry point + * + * This routine is called whenever hardware quits transmitting. + * + **********************************************************************/ + +static void +em_watchdog(struct ifnet *ifp) +{ + struct adapter * Adapter; + Adapter = ifp->if_softc; + + /* If we are in this routine because of pause frames, then + * don't reset the hardware. + */ + if(E1000_READ_REG(Status) & E1000_STATUS_TXOFF) { + ifp->if_timer = EM_TX_TIMEOUT; + return; + } + + printf("em%d: watchdog timeout -- resetting\n", Adapter->unit); + + ifp->if_flags &= ~IFF_RUNNING; + + em_stop(Adapter); + em_init(Adapter); + + ifp->if_oerrors++; + return; +} + +/********************************************************************* + * Timer routine + * + * This routine checks for link status and updates statistics. + * + **********************************************************************/ + +static void +em_local_timer(void *arg) +{ + int s; + struct ifnet *ifp; + struct adapter * Adapter = arg; + ifp = &Adapter->interface_data.ac_if; + + s = splimp(); + + em_check_for_link(Adapter); + em_print_link_status(Adapter); + em_update_stats_counters(Adapter); + if(em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { + em_print_hw_stats(Adapter); + } + Adapter->timer_handle = timeout(em_local_timer, Adapter, 2*hz); + + splx(s); + return; +} + +static void +em_print_link_status(struct adapter * Adapter) +{ + if(E1000_READ_REG(Status) & E1000_STATUS_LU) { + if(Adapter->LinkIsActive == 0) { + em_get_speed_and_duplex(Adapter, &Adapter->LineSpeed, &Adapter->FullDuplex); + printf("em%d: Link is up %d Mbps %s\n", + Adapter->unit, + Adapter->LineSpeed, + ((Adapter->FullDuplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex")); + Adapter->LinkIsActive = 1; + } + } else { + if(Adapter->LinkIsActive == 1) { + Adapter->LineSpeed = 0; + Adapter->FullDuplex = 0; + printf("em%d: Link is Down\n", Adapter->unit); + Adapter->LinkIsActive = 0; + } + } + + return; +} + +/********************************************************************* + * Init entry point + * + * 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 + * consistent state. + * + * return 0 on success, positive on failure + **********************************************************************/ + +static void +em_init(void *arg) +{ + int s; + struct ifnet *ifp; + struct adapter * Adapter = arg; + + INIT_DEBUGOUT("em_init: begin"); + + s = splimp(); + + em_stop(Adapter); + + /* Initialize the hardware */ + if (em_hardware_init(Adapter)) { + printf("em%d: Unable to initialize the hardware\n", Adapter->unit); + splx(s); + return; + } + Adapter->AdapterStopped = FALSE; + + /* 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); + splx(s); + return; + } + em_initialize_transmit_unit(Adapter); + + /* Setup Multicast table */ + em_set_multi(Adapter); + + /* Prepare receive descriptors and buffers */ + if (em_setup_receive_structures(Adapter)) { + printf("em%d: Could not setup receive structures\n", Adapter->unit); + em_stop(Adapter); + splx(s); + return; + } + em_initialize_receive_unit(Adapter); + + ifp = &Adapter->interface_data.ac_if; + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + if(Adapter->MacType >= MAC_LIVENGOOD) + ifp->if_hwassist = EM_CHECKSUM_FEATURES; + + Adapter->timer_handle = timeout(em_local_timer, Adapter, 2*hz); + em_clear_hw_stats_counters(Adapter); + EnableInterrupts(Adapter); + + splx(s); + return; +} + + +/********************************************************************* + * + * This routine disables all traffic on the adapter by issuing a + * 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; + + INIT_DEBUGOUT("em_stop: begin\n"); + DisableInterrupts(Adapter); + em_adapter_stop(Adapter); + untimeout(em_local_timer, Adapter, Adapter->timer_handle); + 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; +} + +/********************************************************************* + * + * Interrupt Service routine + * + **********************************************************************/ + +static void +em_intr(void *arg) +{ + u_int32_t ProcessCount = EM_MAX_INTR; + u_int32_t IcrContents; + struct ifnet *ifp; + struct adapter *Adapter = arg; + + ifp = &Adapter->interface_data.ac_if; + + DisableInterrupts(Adapter); + while(ProcessCount > 0 && (IcrContents = E1000_READ_REG(Icr)) != 0) { + + /* Link status change */ + if(IcrContents & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + untimeout(em_local_timer, Adapter, Adapter->timer_handle); + Adapter->GetLinkStatus = 1; + em_check_for_link(Adapter); + 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); + em_clean_transmit_interrupts(Adapter); + } + ProcessCount--; + } + + EnableInterrupts(Adapter); + + if(ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) + em_start(ifp); + + return; +} + + +/********************************************************************* + * + * Media Ioctl callback + * + * This routine is called whenever the user queries the status of + * the interface using ifconfig. + * + **********************************************************************/ +static void +em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct adapter * Adapter = ifp->if_softc; + + INIT_DEBUGOUT("em_media_status: begin"); + + em_check_for_link(Adapter); + if(E1000_READ_REG(Status) & E1000_STATUS_LU) { + if(Adapter->LinkIsActive == 0) { + em_get_speed_and_duplex(Adapter, &Adapter->LineSpeed, &Adapter->FullDuplex); + Adapter->LinkIsActive = 1; + } + } + else { + if(Adapter->LinkIsActive == 1) { + Adapter->LineSpeed = 0; + Adapter->FullDuplex = 0; + Adapter->LinkIsActive = 0; + } + } + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!Adapter->LinkIsActive) + return; + + ifmr->ifm_status |= IFM_ACTIVE; + + if (Adapter->MediaType == MEDIA_TYPE_FIBER) { + ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; + } else { + switch (Adapter->LineSpeed) { + case 10: + ifmr->ifm_active |= IFM_10_T; + break; + case 100: + ifmr->ifm_active |= IFM_100_TX; + break; + case 1000: + ifmr->ifm_active |= IFM_1000_TX; + break; + } + if (Adapter->FullDuplex == FULL_DUPLEX) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + } + return; +} + +/********************************************************************* + * + * Media Ioctl callback + * + * This routine is called when the user changes speed/duplex using + * media/mediopt option with ifconfig. + * + **********************************************************************/ +static int +em_media_change(struct ifnet *ifp) +{ + 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); + + switch(IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + if (Adapter->AutoNeg) + return 0; + else { + Adapter->AutoNeg = DO_AUTO_NEG; + Adapter->AutoNegAdvertised = AUTONEG_ADV_DEFAULT; + } + break; + case IFM_1000_SX: + case IFM_1000_TX: + Adapter->AutoNeg = DO_AUTO_NEG; + Adapter->AutoNegAdvertised = ADVERTISE_1000_FULL; + break; + case IFM_100_TX: + Adapter->AutoNeg = FALSE; + Adapter->AutoNegAdvertised = 0; + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + Adapter->ForcedSpeedDuplex = FULL_100; + else + Adapter->ForcedSpeedDuplex = HALF_100; + break; + case IFM_10_T: + Adapter->AutoNeg = FALSE; + Adapter->AutoNegAdvertised = 0; + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + Adapter->ForcedSpeedDuplex = FULL_10; + else + Adapter->ForcedSpeedDuplex = HALF_10; + break; + default: + printf("em%d: Unsupported media type\n", Adapter->unit); + } + + em_init(Adapter); + + return(0); +} +/* Section end: Other registered entry points */ + + +/********************************************************************* + * + * Determine hardware revision. + * + **********************************************************************/ +static void +em_identify_hardware(struct adapter * Adapter) +{ + device_t dev = Adapter->dev; + + /* Make sure our PCI config space has the necessary stuff set */ + Adapter->PciCommandWord = pci_read_config(dev, PCIR_COMMAND, 2); + if (!(Adapter->PciCommandWord & (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN))) { + printf("em%d: Memory Access or Bus Master bits were not set!", + Adapter->unit); + Adapter->PciCommandWord |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); + pci_write_config(dev, PCIR_COMMAND, Adapter->PciCommandWord, 2); + } + + /* Save off the information about this board */ + Adapter->VendorId = pci_get_vendor(dev); + Adapter->DeviceId = pci_get_device(dev); + Adapter->RevId = pci_read_config(dev, PCIR_REVID, 1); + Adapter->SubVendorId = pci_read_config(dev, PCIR_SUBVEND_0, 2); + Adapter->SubSystemId = pci_read_config(dev, PCIR_SUBDEV_0, 2); + + INIT_DEBUGOUT2("device id = 0x%x, Revid = 0x%x", Adapter->DeviceId, Adapter->RevId); + + /* Set MacType, etc. based on this PCI info */ + switch (Adapter->DeviceId) { + case PCI_DEVICE_ID_82542: + Adapter->MacType = (Adapter->RevId == 3) ? + MAC_WISEMAN_2_1 : MAC_WISEMAN_2_0; + break; + case PCI_DEVICE_ID_82543GC_FIBER: + case PCI_DEVICE_ID_82543GC_COPPER: + Adapter->MacType = MAC_LIVENGOOD; + break; + case PCI_DEVICE_ID_82544EI_FIBER: + case PCI_DEVICE_ID_82544EI_COPPER: + case PCI_DEVICE_ID_82544GC_COPPER: + case PCI_DEVICE_ID_82544GC_STRG: + Adapter->MacType = MAC_CORDOVA; + break; + default: + INIT_DEBUGOUT1("Unknown device id 0x%x", Adapter->DeviceId); + } + return; +} + +static int +em_allocate_pci_resources(struct adapter * Adapter) +{ + int resource_id = EM_MMBA; + device_t dev = Adapter->dev; + + Adapter->res_memory = bus_alloc_resource(dev, SYS_RES_MEMORY, + &resource_id, 0, ~0, 1, + RF_ACTIVE); + if (!(Adapter->res_memory)) { + printf("em%d: Unable to allocate bus resource: memory\n", Adapter->unit); + return(ENXIO); + } + Adapter->bus_space_tag = rman_get_bustag(Adapter->res_memory); + Adapter->bus_space_handle = rman_get_bushandle(Adapter->res_memory); + + resource_id = 0x0; + Adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ, + &resource_id, 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); + } + return(0); +} + +static void +em_free_pci_resources(struct adapter * Adapter) +{ + device_t dev = Adapter->dev; + + 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); + } + return; +} + +/********************************************************************* + * + * Initialize the hardware to a configuration as specified by the + * Adapter structure. The controller is reset, the EEPROM is + * verified, the MAC address is set, then the shared initialization + * routines are called. + * + **********************************************************************/ +static int +em_hardware_init(struct adapter * Adapter) +{ + /* Issue a global reset */ + Adapter->AdapterStopped = FALSE; + em_adapter_stop(Adapter); + Adapter->AdapterStopped = FALSE; + + /* Make sure we have a good EEPROM before we read from it */ + if (!em_validate_eeprom_checksum(Adapter)) { + printf("em%d: The EEPROM Checksum Is Not Valid\n", Adapter->unit); + return EIO; + } + /* Copy the permanent MAC address and part number out of the EEPROM */ + em_read_mac_address(Adapter, Adapter->interface_data.ac_enaddr); + memcpy(Adapter->CurrentNetAddress, Adapter->interface_data.ac_enaddr, + ETH_LENGTH_OF_ADDRESS); + em_read_part_number(Adapter, &(Adapter->PartNumber)); + + if (!em_initialize_hardware(Adapter)) { + printf("em%d: Hardware Initialization Failed", Adapter->unit); + return EIO; + } + em_check_for_link(Adapter); + if (E1000_READ_REG(Status) & E1000_STATUS_LU) + Adapter->LinkIsActive = 1; + else + Adapter->LinkIsActive = 0; + + if (Adapter->LinkIsActive) { + em_get_speed_and_duplex(Adapter, &Adapter->LineSpeed, &Adapter->FullDuplex); + } else { + Adapter->LineSpeed = 0; + Adapter->FullDuplex = 0; + } + + return 0; +} + +static void +em_read_mac_address(struct adapter * Adapter, u_int8_t * NodeAddress) +{ + u_int16_t EepromWordValue; + int i; + + for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) { + EepromWordValue = + em_read_eeprom_word(Adapter, EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); + NodeAddress[i] = (uint8_t) (EepromWordValue & 0x00FF); + NodeAddress[i + 1] = (uint8_t) (EepromWordValue >> 8); + } + + return; +} + +/********************************************************************* + * + * Setup networking device structure and register an interface. + * + **********************************************************************/ +static void +em_setup_interface(device_t dev, struct adapter * Adapter) +{ + struct ifnet *ifp; + INIT_DEBUGOUT("em_setup_interface: begin"); + + ifp = &Adapter->interface_data.ac_if; + ifp->if_unit = Adapter->unit; + ifp->if_name = "em"; + 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; + ifp->if_ioctl = em_ioctl; + ifp->if_start = em_start; + ifp->if_watchdog = em_watchdog; + ifp->if_snd.ifq_maxlen = Adapter->NumTxDescriptors - 1; + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); + + /* + * 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->MediaType == 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); + } 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, 0, NULL); + ifmedia_add(&Adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, + NULL); + 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); + + INIT_DEBUGOUT("em_setup_interface: end"); + return; +} + + +/********************************************************************* + * + * 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) +{ + if (!(Adapter->tx_buffer_area = + (struct em_tx_buffer *) malloc(sizeof(struct em_tx_buffer) * + Adapter->NumTxDescriptors, M_DEVBUF, + M_NOWAIT))) { + printf("em%d: Unable to allocate tx_buffer memory\n", Adapter->unit); + return ENOMEM; + } + + bzero(Adapter->tx_buffer_area, + sizeof(struct em_tx_buffer) * Adapter->NumTxDescriptors); + + return 0; +} + +/********************************************************************* + * + * Allocate and initialize transmit structures. + * + **********************************************************************/ +static int +em_setup_transmit_structures(struct adapter * Adapter) +{ + struct em_tx_buffer *tx_buffer; + int i; + + if (em_allocate_transmit_structures(Adapter)) + return ENOMEM; + + Adapter->FirstTxDescriptor = Adapter->TxDescBase; + Adapter->LastTxDescriptor = + Adapter->FirstTxDescriptor + (Adapter->NumTxDescriptors - 1); + + + STAILQ_INIT(&Adapter->FreeSwTxPacketList); + STAILQ_INIT(&Adapter->UsedSwTxPacketList); + + tx_buffer = Adapter->tx_buffer_area; + + /* Setup the linked list of the tx_buffer's */ + for (i = 0; i < Adapter->NumTxDescriptors; i++, tx_buffer++) { + bzero((void *) tx_buffer, sizeof(struct em_tx_buffer)); + STAILQ_INSERT_TAIL(&Adapter->FreeSwTxPacketList, tx_buffer, em_tx_entry); + } + + bzero((void *) Adapter->FirstTxDescriptor, + (sizeof(E1000_TRANSMIT_DESCRIPTOR)) * Adapter->NumTxDescriptors); + + /* Setup TX descriptor pointers */ + Adapter->NextAvailTxDescriptor = Adapter->FirstTxDescriptor; + Adapter->OldestUsedTxDescriptor = Adapter->FirstTxDescriptor; + + /* Set number of descriptors available */ + Adapter->NumTxDescriptorsAvail = Adapter->NumTxDescriptors; + + /* Set checksum context */ + Adapter->ActiveChecksumContext = OFFLOAD_NONE; + + return 0; +} + +/********************************************************************* + * + * Enable transmit unit. + * + **********************************************************************/ +static void +em_initialize_transmit_unit(struct adapter * Adapter) +{ + u_int32_t reg_tctl; + u_int32_t reg_tipg = 0; + + /* Setup the Base and Length of the Tx Descriptor Ring */ + E1000_WRITE_REG(Tdbal, vtophys((vm_offset_t) Adapter->TxDescBase)); + E1000_WRITE_REG(Tdbah, 0); + E1000_WRITE_REG(Tdl, Adapter->NumTxDescriptors * + sizeof(E1000_TRANSMIT_DESCRIPTOR)); + + /* Setup the HW Tx Head and Tail descriptor pointers */ + E1000_WRITE_REG(Tdh, 0); + E1000_WRITE_REG(Tdt, 0); + + + HW_DEBUGOUT2("Base = %x, Length = %x\n", E1000_READ_REG(Tdbal), + E1000_READ_REG(Tdl)); + + + /* Zero out the 82542 Tx Queue State registers - we don't use them */ + if (Adapter->MacType < MAC_LIVENGOOD) { + E1000_WRITE_REG(Tqsal, 0); + E1000_WRITE_REG(Tqsah, 0); + } + + /* Set the default values for the Tx Inter Packet Gap timer */ + switch (Adapter->MacType) { + case MAC_LIVENGOOD: + case MAC_WAINWRIGHT: + case MAC_CORDOVA: + if (Adapter->MediaType == MEDIA_TYPE_FIBER) + reg_tipg = DEFAULT_LVGD_TIPG_IPGT_FIBER; + else + reg_tipg = DEFAULT_LVGD_TIPG_IPGT_COPPER; + reg_tipg |= DEFAULT_LVGD_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + reg_tipg |= DEFAULT_LVGD_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + break; + case MAC_WISEMAN_2_0: + case MAC_WISEMAN_2_1: + reg_tipg = DEFAULT_WSMN_TIPG_IPGT; + reg_tipg |= DEFAULT_WSMN_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + reg_tipg |= DEFAULT_WSMN_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + break; + } + E1000_WRITE_REG(Tipg, reg_tipg); + E1000_WRITE_REG(Tidv, Adapter->TxIntDelay); + + /* Program the Transmit Control Register */ + reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + if (Adapter->FullDuplex == 1) { + reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } else { + reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } + E1000_WRITE_REG(Tctl, reg_tctl); + + /* Setup Transmit Descriptor Settings for this adapter */ + Adapter->TxdCmd = E1000_TXD_CMD_IFCS; + + if(Adapter->TxIntDelay > 0) + Adapter->TxdCmd |= E1000_TXD_CMD_IDE; + + if(Adapter->ReportTxEarly == 1) + Adapter->TxdCmd |= E1000_TXD_CMD_RS; + else + Adapter->TxdCmd |= E1000_TXD_CMD_RPS; + + return; +} + +/********************************************************************* + * + * Free all transmit related data structures. + * + **********************************************************************/ +static void +em_free_transmit_structures(struct adapter * Adapter) +{ + struct em_tx_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->NumTxDescriptors; i++, tx_buffer++) { + if (tx_buffer->Packet != NULL) + m_freem(tx_buffer->Packet); + tx_buffer->Packet = NULL; + } + } + if (Adapter->tx_buffer_area != NULL) { + free(Adapter->tx_buffer_area, M_DEVBUF); + Adapter->tx_buffer_area = NULL; + } + return; +} + +/********************************************************************* + * + * The offload context needs to be set when we transfer the first + * packet of a particular protocol (TCP/UDP). We change the + * context only if the protocol type changes. + * + **********************************************************************/ +static void +em_transmit_checksum_setup(struct adapter * Adapter, + struct mbuf *mp, + struct em_tx_buffer *tx_buffer, + u_int32_t *txd_upper, + u_int32_t *txd_lower) +{ + PE1000_TCPIP_CONTEXT_TRANSMIT_DESCRIPTOR TXD; + PE1000_TRANSMIT_DESCRIPTOR CurrentTxDescriptor; + + if (mp->m_pkthdr.csum_flags) { + + if(mp->m_pkthdr.csum_flags & CSUM_TCP) { + TXCSUM_DEBUGOUT("Checksum TCP"); + *txd_upper = E1000_TXD_POPTS_TXSM << 8; + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + if(Adapter->ActiveChecksumContext == OFFLOAD_TCP_IP) + return; + else + Adapter->ActiveChecksumContext = OFFLOAD_TCP_IP; + + } else if(mp->m_pkthdr.csum_flags & CSUM_UDP) { + TXCSUM_DEBUGOUT("Checksum UDP"); + *txd_upper = E1000_TXD_POPTS_TXSM << 8; + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + if(Adapter->ActiveChecksumContext == OFFLOAD_UDP_IP) + return; + else + Adapter->ActiveChecksumContext = OFFLOAD_UDP_IP; + } else { + TXCSUM_DEBUGOUT("Invalid protocol for checksum calculation\n"); + *txd_upper = 0; + *txd_lower = 0; + return; + } + } + else { + TXCSUM_DEBUGOUT("No checksum detected\n"); + *txd_upper = 0; + *txd_lower = 0; + return; + } + + /* If we reach this point, the checksum offload context + * needs to be reset. + */ + CurrentTxDescriptor = Adapter->NextAvailTxDescriptor; + TXD = (PE1000_TCPIP_CONTEXT_TRANSMIT_DESCRIPTOR)CurrentTxDescriptor; + + TXD->LowerXsumSetup.IpFields.Ipcss = ETHER_HDR_LEN; + TXD->LowerXsumSetup.IpFields.Ipcso = ETHER_HDR_LEN + offsetof(struct ip, ip_sum); + TXD->LowerXsumSetup.IpFields.Ipcse = ETHER_HDR_LEN + sizeof(struct ip) - 1; + + TXD->UpperXsumSetup.TcpFields.Tucss = ETHER_HDR_LEN + sizeof(struct ip); + TXD->UpperXsumSetup.TcpFields.Tucse = 0; + + if(Adapter->ActiveChecksumContext == OFFLOAD_TCP_IP) { + TXD->UpperXsumSetup.TcpFields.Tucso = ETHER_HDR_LEN + sizeof(struct ip) + + offsetof(struct tcphdr, th_sum); + } else if (Adapter->ActiveChecksumContext == OFFLOAD_UDP_IP) { + TXD->UpperXsumSetup.TcpFields.Tucso = ETHER_HDR_LEN + sizeof(struct ip) + + offsetof(struct udphdr, uh_sum); + } + + TXD->TcpSegSetup.DwordData = 0; + TXD->CmdAndLength = E1000_TXD_CMD_DEXT; + + if (CurrentTxDescriptor == Adapter->LastTxDescriptor) + Adapter->NextAvailTxDescriptor = Adapter->FirstTxDescriptor; + else + Adapter->NextAvailTxDescriptor++; + + Adapter->NumTxDescriptorsAvail--; + + tx_buffer->NumTxDescriptorsUsed++; + return; +} + + +/********************************************************************* + * + * Get buffer from driver maintained free list for jumbo frames. + * + **********************************************************************/ +static int +em_get_jumbo_buf(struct em_rx_buffer *rx_buffer, struct adapter *Adapter, + struct mbuf *mp) +{ + struct mbuf *nmp; + + if (mp == NULL) { + caddr_t *buf = NULL; + MGETHDR(nmp, M_DONTWAIT, MT_DATA); + if (nmp == NULL) { + printf("em%d: Mbuf allocation failed\n", Adapter->unit); + Adapter->JumboMbufFailed++; + return (ENOBUFS); + } + + /* Allocate the jumbo buffer */ + buf = em_jalloc(Adapter); + if (buf == NULL) { + m_freem(nmp); + Adapter->JumboClusterFailed++; + return(ENOBUFS); + } + + /* Attach the buffer to the mbuf. */ + nmp->m_data = (void *)buf; + nmp->m_len = nmp->m_pkthdr.len = EM_JUMBO_FRAMELEN; + MEXTADD(nmp, buf, EM_JUMBO_FRAMELEN, em_jfree, + (struct adapter *)Adapter, 0, EXT_NET_DRV); + } else { + nmp = mp; + nmp->m_data = nmp->m_ext.ext_buf; + nmp->m_ext.ext_size = EM_JUMBO_FRAMELEN; + } + + m_adj(nmp, ETHER_ALIGN); + + rx_buffer->Packet = nmp; + rx_buffer->LowPhysicalAddress = vtophys(mtod(nmp, vm_offset_t)); + rx_buffer->HighPhysicalAddress = 0; + + return (0); +} + + +/********************************************************************* + * + * Get a buffer from system mbuf buffer pool. + * + **********************************************************************/ +static int +em_get_std_buf(struct em_rx_buffer *rx_buffer, struct adapter *Adapter, + struct mbuf *mp) +{ + struct mbuf *nmp; + + if (mp == NULL) { + MGETHDR(nmp, M_DONTWAIT, MT_DATA); + if (nmp == NULL) { + printf("em%d: Mbuf allocation failed\n", Adapter->unit); + Adapter->StdMbufFailed++; + return (ENOBUFS); + } + MCLGET(nmp, M_DONTWAIT); + if ((nmp->m_flags & M_EXT) == 0) { + m_freem(nmp); + printf("em%d: Mbuf cluster allocation failed\n", Adapter->unit); + Adapter->StdClusterFailed++; + return (ENOBUFS); + } + nmp->m_len = nmp->m_pkthdr.len = MCLBYTES; + } else { + nmp = mp; + nmp->m_len = nmp->m_pkthdr.len = MCLBYTES; + nmp->m_data = nmp->m_ext.ext_buf; + } + +#ifndef SUPPORTLARGEFRAME + m_adj(nmp, ETHER_ALIGN); +#endif + + rx_buffer->Packet = nmp; + rx_buffer->LowPhysicalAddress = vtophys(mtod(nmp, vm_offset_t)); + rx_buffer->HighPhysicalAddress = 0; + + return (0); +} + +/********************************************************************* + * + * Get buffer from system or driver maintained buffer freelist. + * + **********************************************************************/ +static int +em_get_buf(struct em_rx_buffer *rx_buffer, struct adapter * Adapter, + struct mbuf *mp) +{ + int error = 0; + + if(Adapter->JumboEnable == 1) + error = em_get_jumbo_buf(rx_buffer, Adapter, mp); + else + error = em_get_std_buf(rx_buffer, Adapter, mp); + + return error; +} + +/********************************************************************* + * + * 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) +{ + int i; + struct em_rx_buffer *rx_buffer; + + if (!(Adapter->rx_buffer_area = + (struct em_rx_buffer *) malloc(sizeof(struct em_rx_buffer) * + Adapter->NumRxDescriptors, M_DEVBUF, + M_NOWAIT))) { + printf("em%d: Unable to allocate rx_buffer memory\n", Adapter->unit); + return (ENOMEM); + } + + bzero(Adapter->rx_buffer_area, + sizeof(struct em_rx_buffer) * Adapter->NumRxDescriptors); + + for (i = 0, rx_buffer = Adapter->rx_buffer_area; + i < Adapter->NumRxDescriptors; i++, rx_buffer++) { + + if (em_get_buf(rx_buffer, Adapter, NULL) == ENOBUFS) { + rx_buffer->Packet = NULL; + return (ENOBUFS); + } + } + + return (0); +} + +/********************************************************************* + * + * Allocate and initialize receive structures. + * + **********************************************************************/ +static int +em_setup_receive_structures(struct adapter * Adapter) +{ + struct em_rx_buffer *rx_buffer; + PE1000_RECEIVE_DESCRIPTOR RxDescriptorPtr; + int i; + + if(em_allocate_receive_structures(Adapter)) + return ENOMEM; + + STAILQ_INIT(&Adapter->RxSwPacketList); + + Adapter->FirstRxDescriptor = + (PE1000_RECEIVE_DESCRIPTOR) Adapter->RxDescBase; + Adapter->LastRxDescriptor = + Adapter->FirstRxDescriptor + (Adapter->NumRxDescriptors - 1); + + rx_buffer = (struct em_rx_buffer *) Adapter->rx_buffer_area; + + bzero((void *) Adapter->FirstRxDescriptor, + (sizeof(E1000_RECEIVE_DESCRIPTOR)) * Adapter->NumRxDescriptors); + + /* Build a linked list of rx_buffer's */ + for (i = 0, RxDescriptorPtr = Adapter->FirstRxDescriptor; + i < Adapter->NumRxDescriptors; + i++, rx_buffer++, RxDescriptorPtr++) { + if (rx_buffer->Packet == NULL) + printf("em%d: Receive buffer memory not allocated", Adapter->unit); + else { + RxDescriptorPtr->BufferAddress.Lo32 = + rx_buffer->LowPhysicalAddress; + RxDescriptorPtr->BufferAddress.Hi32 = + rx_buffer->HighPhysicalAddress; + STAILQ_INSERT_TAIL(&Adapter->RxSwPacketList, rx_buffer, em_rx_entry); + } + } + + /* Setup our descriptor pointers */ + Adapter->NextRxDescriptorToCheck = Adapter->FirstRxDescriptor; + + return(0); +} + +/********************************************************************* + * + * Enable receive unit. + * + **********************************************************************/ +static void +em_initialize_receive_unit(struct adapter * Adapter) +{ + u_int32_t reg_rctl; + u_int32_t reg_rxcsum; + + /* Make sure receives are disabled while setting up the descriptor ring */ + E1000_WRITE_REG(Rctl, 0); + + /* Set the Receive Delay Timer Register */ + E1000_WRITE_REG(Rdtr0, Adapter->RxIntDelay | E1000_RDT0_FPDB); + + /* Setup the Base and Length of the Rx Descriptor Ring */ + E1000_WRITE_REG(Rdbal0, vtophys((vm_offset_t) Adapter->RxDescBase)); + E1000_WRITE_REG(Rdbah0, 0); + E1000_WRITE_REG(Rdlen0, Adapter->NumRxDescriptors * + sizeof(E1000_RECEIVE_DESCRIPTOR)); + + /* Setup the HW Rx Head and Tail Descriptor Pointers */ + E1000_WRITE_REG(Rdh0, 0); + E1000_WRITE_REG(Rdt0, + (((u_int32_t) Adapter->LastRxDescriptor - + (u_int32_t) Adapter->FirstRxDescriptor) >> 4)); + + /* + * Zero out the registers associated with the 82542 second receive + * descriptor ring - we don't use it + */ + if (Adapter->MacType < MAC_LIVENGOOD) { + E1000_WRITE_REG(Rdbal1, 0); + E1000_WRITE_REG(Rdbah1, 0); + E1000_WRITE_REG(Rdlen1, 0); + E1000_WRITE_REG(Rdh1, 0); + E1000_WRITE_REG(Rdt1, 0); + } + + /* Setup the Receive Control Register */ + reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | + E1000_RCTL_RDMTS0_HALF | + (Adapter->MulticastFilterType << E1000_RCTL_MO_SHIFT); + + if (Adapter->TbiCompatibilityOn == TRUE) + reg_rctl |= E1000_RCTL_SBP; + + +#ifdef SUPPORTLARGEFRAME + switch (Adapter->RxBufferLen) { + case EM_RXBUFFER_2048: + reg_rctl |= E1000_RCTL_SZ_2048 | E1000_RCTL_LPE; + break; + case EM_RXBUFFER_4096: + reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case EM_RXBUFFER_8192: + reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case EM_RXBUFFER_16384: + reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + default: + reg_rctl |= E1000_RCTL_SZ_2048; + } +#else + switch (Adapter->RxBufferLen) { + case EM_RXBUFFER_2048: + reg_rctl |= E1000_RCTL_SZ_2048; + break; + case EM_RXBUFFER_4096: + reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case EM_RXBUFFER_8192: + reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case EM_RXBUFFER_16384: + reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + default: + reg_rctl |= E1000_RCTL_SZ_2048; + } +#endif + + /* Enable 82543 Receive Checksum Offload for TCP and UDP */ + if((Adapter->MacType >= MAC_LIVENGOOD) && (Adapter->RxChecksum == 1)) { + reg_rxcsum = E1000_READ_REG(Rxcsum); + reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL); + E1000_WRITE_REG(Rxcsum, reg_rxcsum); + } + + /* Enable Receives */ + E1000_WRITE_REG(Rctl, reg_rctl); + + return; +} + +/********************************************************************* + * + * Free receive related data structures. + * + **********************************************************************/ +static void +em_free_receive_structures(struct adapter * Adapter) +{ + struct em_rx_buffer *rx_buffer; + int i; + + INIT_DEBUGOUT("free_receive_structures: begin"); + + if (Adapter->rx_buffer_area != NULL) { + rx_buffer = Adapter->rx_buffer_area; + for (i = 0; i < Adapter->NumRxDescriptors; i++, rx_buffer++) { + if (rx_buffer->Packet != NULL) + m_freem(rx_buffer->Packet); + rx_buffer->Packet = NULL; + } + } + if (Adapter->rx_buffer_area != NULL) { + free(Adapter->rx_buffer_area, M_DEVBUF); + Adapter->rx_buffer_area = NULL; + } + return; +} + +/********************************************************************* + * + * Allocate memory to be used for jumbo buffers + * + **********************************************************************/ +static int +em_alloc_jumbo_mem(struct adapter *Adapter) +{ + caddr_t ptr; + register int i; + struct em_jpool_entry *entry; + + + Adapter->em_jumbo_buf = contigmalloc(EM_JMEM, M_DEVBUF, + M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); + + if (Adapter->em_jumbo_buf == NULL) { + printf("em%d: No memory for jumbo buffers!\n", Adapter->unit); + return(ENOBUFS); + } + + SLIST_INIT(&Adapter->em_jfree_listhead); + SLIST_INIT(&Adapter->em_jinuse_listhead); + + /* + * Now divide it up into 9K pieces and save the addresses + * in an array. We use the the first few bytes in the buffer to hold + * the address of the adapter (softc) structure for this interface. + * This is because em_jfree() needs it, but it is called by the mbuf + * management code which will not pass it to us explicitly. + */ + + ptr = Adapter->em_jumbo_buf; + for (i = 0; i < EM_JSLOTS; i++) { + Adapter->em_jslots[i].em_buf = ptr; + ptr += EM_JLEN; + entry = malloc(sizeof(struct em_jpool_entry), + M_DEVBUF, M_NOWAIT); + if (entry == NULL) { + contigfree(Adapter->em_jumbo_buf, EM_JMEM, + M_DEVBUF); + Adapter->em_jumbo_buf = NULL; + printf("em%d: No memory for jumbo buffer queue!\n", Adapter->unit); + return(ENOBUFS); + } + entry->slot = i; + SLIST_INSERT_HEAD(&Adapter->em_jfree_listhead, entry, em_jpool_entries); + } + return(0); +} + + +/********************************************************************* + * + * Get Jumbo buffer from free list. + * + **********************************************************************/ +static void *em_jalloc(struct adapter *Adapter) +{ + struct em_jpool_entry *entry; + + entry = SLIST_FIRST(&Adapter->em_jfree_listhead); + + if (entry == NULL) { + Adapter->NoJumboBufAvail++; + return(NULL); + } + + SLIST_REMOVE_HEAD(&Adapter->em_jfree_listhead, em_jpool_entries); + SLIST_INSERT_HEAD(&Adapter->em_jinuse_listhead, entry, em_jpool_entries); + return(Adapter->em_jslots[entry->slot].em_buf); +} + + +/********************************************************************* + * + * Put the jumbo buffer back onto free list. + * + *********************************************************************/ +static void +em_jfree(caddr_t buf, void *args) +{ + struct adapter *Adapter; + int i; + struct em_jpool_entry *entry; + + /* Extract the adapter (softc) struct pointer. */ + Adapter = (struct adapter *)args; + + if (Adapter == NULL) + panic("em_jfree: Can't find softc pointer!"); + + /* Calculate the slot this buffer belongs to */ + i = ((vm_offset_t)buf + - (vm_offset_t)Adapter->em_jumbo_buf) / EM_JLEN; + + if ((i < 0) || (i >= EM_JSLOTS)) + panic("em_jfree: Asked to free buffer that we don't manage!"); + + entry = SLIST_FIRST(&Adapter->em_jinuse_listhead); + if (entry == NULL) + panic("em_jfree: Buffer not in use!"); + entry->slot = i; + SLIST_REMOVE_HEAD(&Adapter->em_jinuse_listhead, + em_jpool_entries); + SLIST_INSERT_HEAD(&Adapter->em_jfree_listhead, + entry, em_jpool_entries); + + return; +} + +#ifdef SUPPORTLARGEFRAME +/********************************************************************* + * + * This routine executes in interrupt context. It replenishes + * the mbufs in the descriptor and sends data which has been + * dma'ed into host memory to upper layer. + * + *********************************************************************/ +static void +em_process_receive_interrupts(struct adapter * Adapter) +{ + struct mbuf *mp, *lmp; + struct mbuf *fmp = NULL; + struct ifnet *ifp; + struct ether_header *eh; + u_int16_t Length; + u_int8_t LastByte; + u_int8_t AcceptFrame = 0; + u_int8_t EndOfPacket = 0; + u_int16_t PacketLength = 0; + + /* Pointer to the receive descriptor being examined. */ + PE1000_RECEIVE_DESCRIPTOR CurrentDescriptor; + PE1000_RECEIVE_DESCRIPTOR LastDescriptorProcessed; + struct em_rx_buffer *rx_buffer; + + TXRX_DEBUGOUT("em_process_receive_interrupts: begin"); + + ifp = &Adapter->interface_data.ac_if; + CurrentDescriptor = Adapter->NextRxDescriptorToCheck; + + if (!((CurrentDescriptor->ReceiveStatus) & E1000_RXD_STAT_DD)) { +#ifdef DBG_STATS + Adapter->NoPacketsAvail++; +#endif + return; + } + + while (CurrentDescriptor->ReceiveStatus & E1000_RXD_STAT_DD) { + + /* Get a pointer to the actual receive buffer */ + rx_buffer = STAILQ_FIRST(&Adapter->RxSwPacketList); + + if(rx_buffer == NULL) { + printf("em%d: Found null rx_buffer\n", Adapter->unit); + return; + } + + mp = rx_buffer->Packet; + AcceptFrame = 1; + + if (CurrentDescriptor->ReceiveStatus & E1000_RXD_STAT_EOP) { + EndOfPacket = 1; + Length = CurrentDescriptor->Length - ETHER_CRC_LEN; + } + else { + EndOfPacket = 0; + Length = CurrentDescriptor->Length; + } + + if(CurrentDescriptor->Errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + + LastByte = *(mtod(rx_buffer->Packet,caddr_t) + Length - 1); + + if (TBI_ACCEPT(CurrentDescriptor->Errors, LastByte, Length)) { + em_adjust_tbi_accepted_stats(Adapter, Length, Adapter->CurrentNetAddress); + Length--; + } else { + AcceptFrame = 0; + } + } + + if (AcceptFrame) { + + /* Keep track of entire packet length */ + PacketLength += Length; + + /* Assign correct length to the current fragment */ + mp->m_len = Length; + + if(fmp == NULL) { + fmp = mp; /* Store the first mbuf */ + lmp = fmp; + } + else { + /* Chain mbuf's together */ + mp->m_flags &= ~M_PKTHDR; + lmp->m_next = mp; + lmp = lmp->m_next; + lmp->m_next = NULL; + } + + if (em_get_buf(rx_buffer, Adapter, NULL) == ENOBUFS) { + Adapter->DroppedPackets++; + em_get_buf(rx_buffer, Adapter, mp); + if(fmp != NULL) m_freem(fmp); + fmp = NULL; + lmp = NULL; + PacketLength = 0; + break; + } + + if (EndOfPacket) { + fmp->m_pkthdr.rcvif = ifp; + fmp->m_pkthdr.len = PacketLength; + + eh = mtod(fmp, struct ether_header *); + + /* Remove ethernet header from mbuf */ + m_adj(fmp, sizeof(struct ether_header)); + em_receive_checksum(Adapter, CurrentDescriptor, fmp); + ether_input(ifp, eh, fmp); + + fmp = NULL; + lmp = NULL; + PacketLength = 0; + } + } else { + Adapter->DroppedPackets++; + em_get_buf(rx_buffer, Adapter, mp); + if(fmp != NULL) m_freem(fmp); + fmp = NULL; + lmp = NULL; + PacketLength = 0; + } + + /* Zero out the receive descriptors status */ + CurrentDescriptor->ReceiveStatus = 0; + + if (rx_buffer->Packet != NULL) { + CurrentDescriptor->BufferAddress.Lo32 = + rx_buffer->LowPhysicalAddress; + CurrentDescriptor->BufferAddress.Hi32 = + rx_buffer->HighPhysicalAddress; + } + /* Advance our pointers to the next descriptor (checking for wrap). */ + if (CurrentDescriptor == Adapter->LastRxDescriptor) + Adapter->NextRxDescriptorToCheck = Adapter->FirstRxDescriptor; + else + ((Adapter)->NextRxDescriptorToCheck)++; + + LastDescriptorProcessed = CurrentDescriptor; + CurrentDescriptor = Adapter->NextRxDescriptorToCheck; + /* + * Put the buffer that we just indicated back at the end of our list + */ + STAILQ_REMOVE_HEAD(&Adapter->RxSwPacketList, em_rx_entry); + STAILQ_INSERT_TAIL(&Adapter->RxSwPacketList, rx_buffer, em_rx_entry); + + /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ + E1000_WRITE_REG(Rdt0, (((u_int32_t) LastDescriptorProcessed - + (u_int32_t) Adapter->FirstRxDescriptor) >> 4)); + } + return; +} + +#else +/********************************************************************* + * + * This routine executes in interrupt context. It replenishes + * the mbufs in the descriptor and sends data which has been + * dma'ed into host memory to upper layer. + * + *********************************************************************/ +static void +em_process_receive_interrupts(struct adapter * Adapter) +{ + struct mbuf *mp; + struct ifnet *ifp; + struct ether_header *eh; + u_int16_t Length; + u_int8_t LastByte; + u_int8_t AcceptFrame; + + /* Pointer to the receive descriptor being examined. */ + PE1000_RECEIVE_DESCRIPTOR CurrentDescriptor; + PE1000_RECEIVE_DESCRIPTOR LastDescriptorProcessed; + struct em_rx_buffer *rx_buffer; + + TXRX_DEBUGOUT("em_process_receive_interrupts: begin"); + + ifp = &Adapter->interface_data.ac_if; + CurrentDescriptor = Adapter->NextRxDescriptorToCheck; + + if (!((CurrentDescriptor->ReceiveStatus) & E1000_RXD_STAT_DD)) { +#ifdef DBG_STATS + Adapter->NoPacketsAvail++; +#endif + return; + } + + while (CurrentDescriptor->ReceiveStatus & E1000_RXD_STAT_DD) { + + /* Get a pointer to the actual receive buffer */ + rx_buffer = STAILQ_FIRST(&Adapter->RxSwPacketList); + if(rx_buffer == NULL) return; + mp = rx_buffer->Packet; + + Length = CurrentDescriptor->Length; + + /* Make sure this is also the last descriptor in the packet. */ + if (CurrentDescriptor->ReceiveStatus & E1000_RXD_STAT_EOP) { + + AcceptFrame = 1; + + if(CurrentDescriptor->Errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + + LastByte = *(mtod(rx_buffer->Packet,caddr_t) + Length - 1); + + if (TBI_ACCEPT(CurrentDescriptor->Errors, LastByte, Length)) { + em_adjust_tbi_accepted_stats(Adapter, Length, Adapter->CurrentNetAddress); + Length--; + } else { + AcceptFrame = 0; + } + } + + if (AcceptFrame) { + if (em_get_buf(rx_buffer, Adapter, NULL) == ENOBUFS) { + Adapter->DroppedPackets++; + em_get_buf(rx_buffer, Adapter, mp); + break; + } + + mp->m_pkthdr.rcvif = ifp; + mp->m_pkthdr.len = mp->m_len = Length - ETHER_CRC_LEN; + eh = mtod(mp, struct ether_header *); + + /* Remove ethernet header from mbuf */ + m_adj(mp, sizeof(struct ether_header)); + em_receive_checksum(Adapter, CurrentDescriptor, mp); + ether_input(ifp, eh, mp); + + } else { + em_get_buf(rx_buffer, Adapter, mp); + Adapter->DroppedPackets++; + } + } else { + /* + * If the received packet has spanned multiple descriptors, ignore + * and discard all the packets that do not have EOP set and proceed + * to the next packet. + */ + printf("em%d: !Receive packet consumed multiple buffers\n", Adapter->unit); + em_get_buf(rx_buffer, Adapter, mp); + Adapter->DroppedPackets++; + } + + /* Zero out the receive descriptors status */ + CurrentDescriptor->ReceiveStatus = 0; + + if (rx_buffer->Packet != NULL) { + CurrentDescriptor->BufferAddress.Lo32 = + rx_buffer->LowPhysicalAddress; + CurrentDescriptor->BufferAddress.Hi32 = + rx_buffer->HighPhysicalAddress; + } + /* Advance our pointers to the next descriptor (checking for wrap). */ + if (CurrentDescriptor == Adapter->LastRxDescriptor) + Adapter->NextRxDescriptorToCheck = Adapter->FirstRxDescriptor; + else + ((Adapter)->NextRxDescriptorToCheck)++; + + LastDescriptorProcessed = CurrentDescriptor; + CurrentDescriptor = Adapter->NextRxDescriptorToCheck; + /* + * Put the buffer that we just indicated back at the end of our list + */ + STAILQ_REMOVE_HEAD(&Adapter->RxSwPacketList, em_rx_entry); + STAILQ_INSERT_TAIL(&Adapter->RxSwPacketList, rx_buffer, em_rx_entry); + + /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ + E1000_WRITE_REG(Rdt0, (((u_int32_t) LastDescriptorProcessed - + (u_int32_t) Adapter->FirstRxDescriptor) >> 4)); + } + return; +} +#endif + + +/********************************************************************* + * + * 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, + PE1000_RECEIVE_DESCRIPTOR RxDescriptor, + struct mbuf *mp) +{ + /* 82543 or newer only */ + if((Adapter->MacType < MAC_LIVENGOOD) || + /* Ignore Checksum bit is set */ + (RxDescriptor->ReceiveStatus & E1000_RXD_STAT_IXSM)) { + RXCSUM_DEBUGOUT("Ignoring checksum"); + mp->m_pkthdr.csum_flags = 0; + return; + } + + if (RxDescriptor->ReceiveStatus & E1000_RXD_STAT_IPCS) { + /* Did it pass? */ + if (!(RxDescriptor->Errors & E1000_RXD_ERR_IPE)) { + /* IP Checksum Good */ + RXCSUM_DEBUGOUT("Good IP checksum"); + mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; + mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; + + } + else { + RXCSUM_DEBUGOUT("Bad IP checksum"); + mp->m_pkthdr.csum_flags = 0; + } + } + else { + RXCSUM_DEBUGOUT("IP Checksum not verified"); + } + + if (RxDescriptor->ReceiveStatus & E1000_RXD_STAT_TCPCS) { + /* Did it pass? */ + if (!(RxDescriptor->Errors & E1000_RXD_ERR_TCPE)) { + RXCSUM_DEBUGOUT("Good TCP/UDP checksum"); + mp->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); + mp->m_pkthdr.csum_data = htons(0xffff); + } + else { + RXCSUM_DEBUGOUT("Bad TCP/UDP checksum"); + } + } + else { + RXCSUM_DEBUGOUT("TCP/UDP checksum not verified"); + } + + + return; +} + + +static void +EnableInterrupts(struct adapter * Adapter) +{ + E1000_WRITE_REG(Ims, (IMS_ENABLE_MASK)); + return; +} + +static void +DisableInterrupts(struct adapter * Adapter) +{ + E1000_WRITE_REG(Imc, (0xffffffff & ~E1000_IMC_RXSEQ)); + return; +} + + +/********************************************************************** + * + * Update the board statistics counters. + * + **********************************************************************/ +static void +em_update_stats_counters(struct adapter * Adapter) +{ + struct ifnet *ifp; + + Adapter->Crcerrs += E1000_READ_REG(Crcerrs); + Adapter->Crcerrs += E1000_READ_REG(Crcerrs); + Adapter->Symerrs += E1000_READ_REG(Symerrs); + Adapter->Mpc += E1000_READ_REG(Mpc); + Adapter->Scc += E1000_READ_REG(Scc); + Adapter->Ecol += E1000_READ_REG(Ecol); + Adapter->Mcc += E1000_READ_REG(Mcc); + Adapter->Latecol += E1000_READ_REG(Latecol); + Adapter->Colc += E1000_READ_REG(Colc); + Adapter->Dc += E1000_READ_REG(Dc); + Adapter->Sec += E1000_READ_REG(Sec); + Adapter->Rlec += E1000_READ_REG(Rlec); + Adapter->Xonrxc += E1000_READ_REG(Xonrxc); + Adapter->Xontxc += E1000_READ_REG(Xontxc); + Adapter->Xoffrxc += E1000_READ_REG(Xoffrxc); + Adapter->Xofftxc += E1000_READ_REG(Xofftxc); + Adapter->Fcruc += E1000_READ_REG(Fcruc); + Adapter->Prc64 += E1000_READ_REG(Prc64); + Adapter->Prc127 += E1000_READ_REG(Prc127); + Adapter->Prc255 += E1000_READ_REG(Prc255); + Adapter->Prc511 += E1000_READ_REG(Prc511); + Adapter->Prc1023 += E1000_READ_REG(Prc1023); + Adapter->Prc1522 += E1000_READ_REG(Prc1522); + Adapter->Gprc += E1000_READ_REG(Gprc); + Adapter->Bprc += E1000_READ_REG(Bprc); + Adapter->Mprc += E1000_READ_REG(Mprc); + Adapter->Gptc += E1000_READ_REG(Gptc); + + /* For the 64-bit byte counters the low dword must be read first. */ + /* Both registers clear on the read of the high dword */ + + Adapter->Gorcl += E1000_READ_REG(Gorl); + Adapter->Gorch += E1000_READ_REG(Gorh); + Adapter->Gotcl += E1000_READ_REG(Gotl); + Adapter->Gotch += E1000_READ_REG(Goth); + + Adapter->Rnbc += E1000_READ_REG(Rnbc); + Adapter->Ruc += E1000_READ_REG(Ruc); + Adapter->Rfc += E1000_READ_REG(Rfc); + Adapter->Roc += E1000_READ_REG(Roc); + Adapter->Rjc += E1000_READ_REG(Rjc); + + Adapter->Torcl += E1000_READ_REG(Torl); + Adapter->Torch += E1000_READ_REG(Torh); + Adapter->Totcl += E1000_READ_REG(Totl); + Adapter->Totch += E1000_READ_REG(Toth); + + Adapter->Tpr += E1000_READ_REG(Tpr); + Adapter->Tpt += E1000_READ_REG(Tpt); + Adapter->Ptc64 += E1000_READ_REG(Ptc64); + Adapter->Ptc127 += E1000_READ_REG(Ptc127); + Adapter->Ptc255 += E1000_READ_REG(Ptc255); + Adapter->Ptc511 += E1000_READ_REG(Ptc511); + Adapter->Ptc1023 += E1000_READ_REG(Ptc1023); + Adapter->Ptc1522 += E1000_READ_REG(Ptc1522); + Adapter->Mptc += E1000_READ_REG(Mptc); + Adapter->Bptc += E1000_READ_REG(Bptc); + + if (Adapter->MacType >= MAC_LIVENGOOD) { + Adapter->Algnerrc += E1000_READ_REG(Algnerrc); + Adapter->Rxerrc += E1000_READ_REG(Rxerrc); + Adapter->Tuc += E1000_READ_REG(Tuc); + Adapter->Tncrs += E1000_READ_REG(Tncrs); + Adapter->Cexterr += E1000_READ_REG(Cexterr); + Adapter->Rutec += E1000_READ_REG(Rutec); + } + ifp = &Adapter->interface_data.ac_if; + + /* Fill out the OS statistics structure */ + ifp->if_ipackets = Adapter->Gprc; + ifp->if_opackets = Adapter->Gptc; + ifp->if_ibytes = Adapter->Gorcl; + ifp->if_obytes = Adapter->Gotcl; + ifp->if_imcasts = Adapter->Mprc; + ifp->if_collisions = Adapter->Colc; + + /* Rx Errors */ + ifp->if_ierrors = + Adapter->DroppedPackets + + Adapter->Rxerrc + + Adapter->Crcerrs + + Adapter->Algnerrc + + Adapter->Rlec + Adapter->Rnbc + Adapter->Mpc + Adapter->Cexterr; + + /* Tx Errors */ + ifp->if_oerrors = Adapter->Ecol + Adapter->Tuc + Adapter->Latecol; + +} + + +/********************************************************************** + * + * This routine is called only when em_display_debug_stats is enabled. + * This routine provides a way to take a look at important statistics + * maintained by the driver and hardware. + * + **********************************************************************/ +static void +em_print_hw_stats(struct adapter * Adapter) +{ + int unit = Adapter->unit; + +#ifdef DBG_STATS + printf("em%d: Tx Descriptors not Avail = %ld\n", unit, Adapter->NoTxDescAvail); + printf("em%d: Packets not Avail = %ld\n", unit, Adapter->NoPacketsAvail); + printf("em%d: CleanTxInterrupts = %ld\n", unit, Adapter->CleanTxInterrupts); + printf("em%d: Tx Buffer not avail1 = %ld\n", unit, Adapter->NoTxBufferAvail1); + printf("em%d: Tx Buffer not avail2 = %ld\n", unit, Adapter->NoTxBufferAvail2); +#endif + printf("em%d: No Jumbo Buffer Avail = %ld\n",unit, Adapter->NoJumboBufAvail); + printf("em%d: Jumbo Mbuf Failed = %ld\n",unit, Adapter->JumboMbufFailed); + printf("em%d: Jumbo Cluster Failed = %ld\n",unit, Adapter->JumboClusterFailed); + printf("em%d: Std Mbuf Failed = %ld\n",unit, Adapter->StdMbufFailed); + printf("em%d: Std Cluster Failed = %ld\n",unit, Adapter->StdClusterFailed); + + printf("em%d: Symbol errors = %ld\n",unit, Adapter->Symerrs); + printf("em%d: Sequence errors = %ld\n", unit, Adapter->Sec); + printf("em%d: Defer count = %ld\n", unit, Adapter->Dc); + + printf("em%d: Missed Packets = %ld\n", unit, Adapter->Mpc); + printf("em%d: Receive No Buffers = %ld\n", unit, Adapter->Rnbc); + printf("em%d: Receive length errors = %ld\n", unit, Adapter->Rlec); + printf("em%d: Receive errors = %ld\n", unit, Adapter->Rxerrc); + printf("em%d: Crc errors = %ld\n", unit, Adapter->Crcerrs); + printf("em%d: Alignment errors = %ld\n", unit, Adapter->Algnerrc); + printf("em%d: Carrier extension errors = %ld\n", unit, Adapter->Cexterr); + printf("em%d: Driver dropped packets = %ld\n", unit, Adapter->DroppedPackets); + + printf("em%d: XON Rcvd = %ld\n", unit, Adapter->Xonrxc); + printf("em%d: XON Xmtd = %ld\n", unit, Adapter->Xontxc); + printf("em%d: XOFF Rcvd = %ld\n", unit, Adapter->Xoffrxc); + printf("em%d: XOFF Xmtd = %ld\n", unit, Adapter->Xofftxc); + + printf("em%d: Good Packets Rcvd = %ld\n", unit, Adapter->Gprc); + printf("em%d: Good Packets Xmtd = %ld\n", unit, Adapter->Gptc); +} + + +/********************************************************************** + * + * Examine each tx_buffer in the used queue. If the hardware is done + * processing the packet then free associated resources. The + * tx_buffer is put back on the free queue. + * + **********************************************************************/ +static void +em_clean_transmit_interrupts(struct adapter * Adapter) +{ + struct em_tx_buffer *tx_buffer; + volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor; + int s; + struct ifnet *ifp; + + s = splimp(); +#ifdef DBG_STATS + Adapter->CleanTxInterrupts++; +#endif + + for (tx_buffer = STAILQ_FIRST(&Adapter->UsedSwTxPacketList); + tx_buffer; + tx_buffer = STAILQ_FIRST(&Adapter->UsedSwTxPacketList)) { + + /* + * Get hold of the next descriptor that the em will report status + * back to (this will be the last descriptor of a given tx_buffer). We + * only want to free the tx_buffer (and it resources) if the driver is + * done with ALL of the descriptors. If the driver is done with the + * last one then it is done with all of them. + */ + + TransmitDescriptor = Adapter->OldestUsedTxDescriptor + + (tx_buffer->NumTxDescriptorsUsed - 1); + + /* Check for wrap case */ + if (TransmitDescriptor > Adapter->LastTxDescriptor) + TransmitDescriptor -= Adapter->NumTxDescriptors; + + + /* + * If the descriptor done bit is set free tx_buffer and associated + * resources + */ + if (TransmitDescriptor->Upper.Fields.TransmitStatus & + E1000_TXD_STAT_DD) { + + STAILQ_REMOVE_HEAD(&Adapter->UsedSwTxPacketList, em_tx_entry); + + if ((TransmitDescriptor == Adapter->LastTxDescriptor)) + Adapter->OldestUsedTxDescriptor = + Adapter->FirstTxDescriptor; + else + Adapter->OldestUsedTxDescriptor = (TransmitDescriptor + 1); + + /* Make available the descriptors that were previously used */ + Adapter->NumTxDescriptorsAvail += + tx_buffer->NumTxDescriptorsUsed; + + tx_buffer->NumTxDescriptorsUsed = 0; + + if (tx_buffer->Packet) { + m_freem(tx_buffer->Packet); + tx_buffer->Packet = NULL; + } + /* Return this "Software packet" back to the "free" list */ + STAILQ_INSERT_TAIL(&Adapter->FreeSwTxPacketList, tx_buffer, em_tx_entry); + } else { + /* + * Found a tx_buffer that the em is not done with then there is + * no reason to check the rest of the queue. + */ + break; + } + } /* end for each tx_buffer */ + + ifp = &Adapter->interface_data.ac_if; + + /* Tell the stack that it is OK to send packets */ + if (Adapter->NumTxDescriptorsAvail > TX_CLEANUP_THRESHOLD) { + ifp->if_timer = 0; + ifp->if_flags &= ~IFF_OACTIVE; + } + splx(s); + return; +} + diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h new file mode 100644 index 0000000..b1919cb --- /dev/null +++ b/sys/dev/em/if_em.h @@ -0,0 +1,410 @@ +/************************************************************************** +************************************************************************** + +Copyright (c) 2001 Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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$ +*************************************************************************** +***************************************************************************/ + +#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 <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/bpf.h> +#include <net/ethernet.h> +#include <net/if_arp.h> +#include <sys/sockio.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> +#include <pci/pcivar.h> +#include <pci/pcireg.h> +#include <stddef.h> + +#include "opt_bdg.h" + +#include <dev/em/if_em_fxhw.h> +#include <dev/em/if_em_phy.h> + +/* Tunables */ +#define MAX_TXD 256 +#define MAX_RXD 256 +#define TX_CLEANUP_THRESHOLD MAX_TXD / 8 +#define TIDV 128 +#define RIDV 28 +#define DO_AUTO_NEG 1 +#define WAIT_FOR_AUTO_NEG_DEFAULT 1 +#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) +#define EM_ENABLE_RXCSUM_OFFLOAD 1 +#define EM_REPORT_TX_EARLY 2 +#define EM_CHECKSUM_FEATURES (CSUM_TCP | CSUM_UDP) +#define EM_MAX_INTR 3 +#define EM_TX_TIMEOUT 5 /* set to 5 seconds */ +#define EM_JUMBO_ENABLE_DEFAULT 0 + + +#define EM_VENDOR_ID 0x8086 +#define EM_MMBA 0x0010 /* Mem base address */ +#define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) +#define EM_JUMBO_PBA 0x00000028 +#define EM_DEFAULT_PBA 0x00000030 + +#define IOCTL_CMD_TYPE u_long +#define ETH_LENGTH_OF_ADDRESS ETHER_ADDR_LEN +#define PCI_COMMAND_REGISTER PCIR_COMMAND +#define MAX_NUM_MULTICAST_ADDRESSES 128 +#define PCI_ANY_ID (~0U) +#define ETHER_ALIGN 2 +#define CMD_MEM_WRT_INVALIDATE 0x0010 + +/* Defines for printing debug information */ +#define DEBUG_INIT 0 +#define DEBUG_IOCTL 0 +#define DEBUG_HW 0 +#define DEBUG_TXRX 0 +#define DEBUG_RXCSUM 0 +#define DEBUG_TXCSUM 0 + +#define INIT_DEBUGOUT(S) if (DEBUG_INIT) printf(S "\n") +#define INIT_DEBUGOUT1(S, A) if (DEBUG_INIT) printf(S "\n", A) +#define INIT_DEBUGOUT2(S, A, B) if (DEBUG_INIT) printf(S "\n", A, B) +#define IOCTL_DEBUGOUT(S) if (DEBUG_IOCTL) printf(S "\n") +#define IOCTL_DEBUGOUT1(S, A) if (DEBUG_IOCTL) printf(S "\n", A) +#define IOCTL_DEBUGOUT2(S, A, B) if (DEBUG_IOCTL) printf(S "\n", A, B) +#define HW_DEBUGOUT(S) if (DEBUG_HW) printf(S "\n") +#define HW_DEBUGOUT1(S, A) if (DEBUG_HW) printf(S "\n", A) +#define HW_DEBUGOUT2(S, A, B) if (DEBUG_HW) printf(S "\n", A, B) +#define TXRX_DEBUGOUT(S) if (DEBUG_TXRX) printf(S "\n") +#define TXRX_DEBUGOUT1(S, A) if (DEBUG_TXRX) printf(S "\n", A) +#define TXRX_DEBUGOUT2(S, A, B) if (DEBUG_TXRX) printf(S "\n", A, B) +#define RXCSUM_DEBUGOUT(S) if (DEBUG_RXCSUM) printf(S "\n") +#define RXCSUM_DEBUGOUT1(S, A) if (DEBUG_RXCSUM) printf(S "\n", A) +#define RXCSUM_DEBUGOUT2(S, A, B) if (DEBUG_RXCSUM) printf(S "\n", A, B) +#define TXCSUM_DEBUGOUT(S) if (DEBUG_TXCSUM) printf(S "\n") +#define TXCSUM_DEBUGOUT1(S, A) if (DEBUG_TXCSUM) printf(S "\n", A) +#define TXCSUM_DEBUGOUT2(S, A, B) if (DEBUG_TXCSUM) printf(S "\n", A, B) + +/* Device ID defines */ +#define PCI_DEVICE_ID_82542 0x1000 +#define PCI_DEVICE_ID_82543GC_FIBER 0x1001 +#define PCI_DEVICE_ID_82543GC_COPPER 0x1004 +#define PCI_DEVICE_ID_82544EI_FIBER 0x1009 +#define PCI_DEVICE_ID_82544EI_COPPER 0x1008 +#define PCI_DEVICE_ID_82544GC_STRG 0x100C +#define PCI_DEVICE_ID_82544GC_COPPER 0x100D + +/* Supported RX Buffer Sizes */ +#define EM_RXBUFFER_2048 2048 +#define EM_RXBUFFER_4096 4096 +#define EM_RXBUFFER_8192 8192 +#define EM_RXBUFFER_16384 16384 + + +/* Jumbo Frame */ +#define EM_JSLOTS 384 +#define EM_JUMBO_FRAMELEN 9018 +#define EM_JUMBO_MTU (EM_JUMBO_FRAMELEN - ETHER_HDR_LEN - ETHER_CRC_LEN) +#define EM_JRAWLEN (EM_JUMBO_FRAMELEN + ETHER_ALIGN + sizeof(u_int64_t)) +#define EM_JLEN (EM_JRAWLEN + (sizeof(u_int64_t) - \ + (EM_JRAWLEN % sizeof(u_int64_t)))) +#define EM_JPAGESZ PAGE_SIZE +#define EM_RESID (EM_JPAGESZ - (EM_JLEN * EM_JSLOTS) % EM_JPAGESZ) +#define EM_JMEM ((EM_JLEN * EM_JSLOTS) + EM_RESID) + +struct em_jslot { + caddr_t em_buf; + int em_inuse; +}; + +struct em_jpool_entry { + int slot; + SLIST_ENTRY(em_jpool_entry) em_jpool_entries; +}; + + + +/* ****************************************************************************** + * 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_tx_buffer { + STAILQ_ENTRY(em_tx_buffer) em_tx_entry; + struct mbuf *Packet; + u_int32_t NumTxDescriptorsUsed; +}; + + +/* ****************************************************************************** + * This structure stores information about the 2k aligned receive buffer + * into which the E1000 DMA's frames. + * ******************************************************************************/ +struct em_rx_buffer { + STAILQ_ENTRY(em_rx_buffer) em_rx_entry; + struct mbuf *Packet; + u_int32_t LowPhysicalAddress; + u_int32_t HighPhysicalAddress; +}; + +typedef enum _XSUM_CONTEXT_T { + OFFLOAD_NONE, + OFFLOAD_TCP_IP, + OFFLOAD_UDP_IP +} XSUM_CONTEXT_T; + +/* Our adapter structure */ +struct adapter { + struct arpcom interface_data; + struct adapter *next; + struct adapter *prev; + + /* FreeBSD operating-system-specific structures */ + bus_space_tag_t bus_space_tag; + bus_space_handle_t bus_space_handle; + struct device *dev; + struct resource *res_memory; + struct resource *res_interrupt; + void *int_handler_tag; + struct ifmedia media; + struct callout_handle timer_handle; + u_int8_t unit; + + /* PCI Info */ + u_int16_t VendorId; + u_int16_t DeviceId; + u_int8_t RevId; + u_int16_t SubVendorId; + u_int16_t SubSystemId; + u_int16_t PciCommandWord; + + /* PCI Bus Info */ + E1000_BUS_TYPE_ENUM BusType; + E1000_BUS_SPEED_ENUM BusSpeed; + E1000_BUS_WIDTH_ENUM BusWidth; + + /* Info about the board itself */ + u_int8_t MacType; + u_int8_t MediaType; + u_int32_t PhyId; + u_int32_t PhyAddress; + uint8_t CurrentNetAddress[ETH_LENGTH_OF_ADDRESS]; + uint8_t PermNetAddress[ETH_LENGTH_OF_ADDRESS]; + u_int32_t PartNumber; + + u_int8_t AdapterStopped; + u_int8_t DmaFairness; + u_int8_t ReportTxEarly; + u_int32_t MulticastFilterType; + u_int32_t NumberOfMcAddresses; + u_int8_t MulticastAddressList[MAX_NUM_MULTICAST_ADDRESSES][ETH_LENGTH_OF_ADDRESS]; + + u_int8_t GetLinkStatus; + u_int8_t LinkStatusChanged; + u_int8_t LinkIsActive; + u_int32_t AutoNegFailed; + u_int8_t AutoNeg; + u_int16_t AutoNegAdvertised; + u_int8_t WaitAutoNegComplete; + u_int8_t ForcedSpeedDuplex; + u_int16_t LineSpeed; + u_int16_t FullDuplex; + u_int8_t TbiCompatibilityEnable; + u_int8_t TbiCompatibilityOn; + u_int32_t TxcwRegValue; + u_int32_t OriginalFlowControl; + u_int32_t FlowControl; + u_int16_t FlowControlHighWatermark; + u_int16_t FlowControlLowWatermark; + u_int16_t FlowControlPauseTime; + u_int8_t FlowControlSendXon; + + u_int32_t MaxFrameSize; + u_int32_t TxIntDelay; + u_int32_t RxIntDelay; + + u_int8_t RxChecksum; + XSUM_CONTEXT_T ActiveChecksumContext; + + u_int8_t MdiX; + u_int8_t DisablePolarityCorrection; + + /* Transmit definitions */ + struct _E1000_TRANSMIT_DESCRIPTOR *FirstTxDescriptor; + struct _E1000_TRANSMIT_DESCRIPTOR *LastTxDescriptor; + struct _E1000_TRANSMIT_DESCRIPTOR *NextAvailTxDescriptor; + struct _E1000_TRANSMIT_DESCRIPTOR *OldestUsedTxDescriptor; + struct _E1000_TRANSMIT_DESCRIPTOR *TxDescBase; + volatile u_int16_t NumTxDescriptorsAvail; + u_int16_t NumTxDescriptors; + u_int32_t TxdCmd; + struct em_tx_buffer *tx_buffer_area; + STAILQ_HEAD(__em_tx_buffer_free, em_tx_buffer) FreeSwTxPacketList; + STAILQ_HEAD(__em_tx_buffer_used, em_tx_buffer) UsedSwTxPacketList; + + /* Receive definitions */ + struct _E1000_RECEIVE_DESCRIPTOR *FirstRxDescriptor; + struct _E1000_RECEIVE_DESCRIPTOR *LastRxDescriptor; + struct _E1000_RECEIVE_DESCRIPTOR *NextRxDescriptorToCheck; + struct _E1000_RECEIVE_DESCRIPTOR *RxDescBase; + u_int16_t NumRxDescriptors; + u_int16_t NumRxDescriptorsEmpty; + u_int16_t NextRxDescriptorToFill; + u_int32_t RxBufferLen; + struct em_rx_buffer *rx_buffer_area; + STAILQ_HEAD(__em_rx_buffer, em_rx_buffer) RxSwPacketList; + + /* Jumbo frame */ + u_int8_t JumboEnable; + struct em_jslot em_jslots[EM_JSLOTS]; + void *em_jumbo_buf; + SLIST_HEAD(__em_jfreehead, em_jpool_entry) em_jfree_listhead; + SLIST_HEAD(__em_jinusehead, em_jpool_entry) em_jinuse_listhead; + + + /* Misc stats maintained by the driver */ + unsigned long DroppedPackets; + unsigned long NoJumboBufAvail; + unsigned long JumboMbufFailed; + unsigned long JumboClusterFailed; + unsigned long StdMbufFailed; + unsigned long StdClusterFailed; +#ifdef DBG_STATS + unsigned long NoTxDescAvail; + unsigned long NoPacketsAvail; + unsigned long CleanTxInterrupts; + unsigned long NoTxBufferAvail1; + unsigned long NoTxBufferAvail2; +#endif + + /* Statistics registers present in the 82542 */ + unsigned long Crcerrs; + unsigned long Symerrs; + unsigned long Mpc; + unsigned long Scc; + unsigned long Ecol; + unsigned long Mcc; + unsigned long Latecol; + unsigned long Colc; + unsigned long Dc; + unsigned long Sec; + unsigned long Rlec; + unsigned long Xonrxc; + unsigned long Xontxc; + unsigned long Xoffrxc; + unsigned long Xofftxc; + unsigned long Fcruc; + unsigned long Prc64; + unsigned long Prc127; + unsigned long Prc255; + unsigned long Prc511; + unsigned long Prc1023; + unsigned long Prc1522; + unsigned long Gprc; + unsigned long Bprc; + unsigned long Mprc; + unsigned long Gptc; + unsigned long Gorcl; + unsigned long Gorch; + unsigned long Gotcl; + unsigned long Gotch; + unsigned long Rnbc; + unsigned long Ruc; + unsigned long Rfc; + unsigned long Roc; + unsigned long Rjc; + unsigned long Torcl; + unsigned long Torch; + unsigned long Totcl; + unsigned long Totch; + unsigned long Tpr; + unsigned long Tpt; + unsigned long Ptc64; + unsigned long Ptc127; + unsigned long Ptc255; + unsigned long Ptc511; + unsigned long Ptc1023; + unsigned long Ptc1522; + unsigned long Mptc; + unsigned long Bptc; + /* Statistics registers added in the 82543 */ + unsigned long Algnerrc; + unsigned long Rxerrc; + unsigned long Tuc; + unsigned long Tncrs; + unsigned long Cexterr; + unsigned long Rutec; + unsigned long Tsctc; + unsigned long Tsctfc; + +}; + +extern void em_adjust_tbi_accepted_stats(struct adapter * Adapter, + u32 FrameLength, u8 * MacAddress); + +#endif /* _EM_H_DEFINED_ */ diff --git a/sys/dev/em/if_em_fxhw.c b/sys/dev/em/if_em_fxhw.c new file mode 100644 index 0000000..e49f8ab --- /dev/null +++ b/sys/dev/em/if_em_fxhw.c @@ -0,0 +1,1457 @@ +/************************************************************************* +************************************************************************** +Copyright (c) 2001 Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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$ +*************************************************************************** +**************************************************************************/ +/* +* Workfile: fxhw.c +* Date: 9/25/01 2:40p +* Revision: 48 +*/ + +#include <dev/em/if_em_fxhw.h> +#include <dev/em/if_em_phy.h> + +static void em_shift_out_bits(struct adapter *Adapter, + + u16 Data, u16 Count); +static void em_raise_clock(struct adapter *Adapter, u32 * EecdRegValue); +static void em_lower_clock(struct adapter *Adapter, u32 * EecdRegValue); +static u16 em_shift_in_bits(struct adapter *Adapter); +static void em_eeprom_cleanup(struct adapter *Adapter); +static u16 em_wait_eeprom_command_done(struct adapter *Adapter); +static void em_stand_by(struct adapter *Adapter); + +void em_adapter_stop(struct adapter *Adapter) +{ + + u32 IcrContents; + + u16 PciCommandWord; + + DEBUGFUNC("em_adapter_stop") + + if (Adapter->AdapterStopped) { + DEBUGOUT + ("Exiting because the adapter is already stopped!!!\n"); + return; + } + + Adapter->AdapterStopped = 1; + + if (Adapter->MacType == MAC_WISEMAN_2_0) { + if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT + ("Disabling MWI on rev 2.0 Wiseman silicon\n"); + + PciCommandWord = + Adapter-> + PciCommandWord & ~CMD_MEM_WRT_INVALIDATE; + + WritePciConfigWord(PCI_COMMAND_REGISTER, + &PciCommandWord); + } + } + + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(Imc, 0xffffffff); + + E1000_WRITE_REG(Rctl, 0); + E1000_WRITE_REG(Tctl, 0); + + Adapter->TbiCompatibilityOn = 0; + + DelayInMilliseconds(10); + + DEBUGOUT("Issuing a global reset to MAC\n"); + E1000_WRITE_REG(Ctrl, E1000_CTRL_RST); + + DelayInMilliseconds(10); + + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(Imc, 0xffffffff); + + IcrContents = E1000_READ_REG(Icr); + + if (Adapter->MacType == MAC_WISEMAN_2_0) { + if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { + WritePciConfigWord(PCI_COMMAND_REGISTER, + &Adapter->PciCommandWord); + } + } + +} + +u8 em_initialize_hardware(struct adapter *Adapter) + { + u32 i; + u16 PciCommandWord; + u8 Status; + u32 RegisterValue; + + DEBUGFUNC("em_initialize_hardware"); + + if (Adapter->MacType != MAC_LIVENGOOD) { + + Adapter->TbiCompatibilityEnable = 0; + } + + if (Adapter->MacType >= MAC_LIVENGOOD) { + RegisterValue = E1000_READ_REG(Status); + if (RegisterValue & E1000_STATUS_TBIMODE) { + Adapter->MediaType = MEDIA_TYPE_FIBER; + + Adapter->TbiCompatibilityEnable = 0; + } else { + Adapter->MediaType = MEDIA_TYPE_COPPER; + } + } else { + + Adapter->MediaType = MEDIA_TYPE_FIBER; + } + + DEBUGOUT("Initializing the IEEE VLAN\n"); + E1000_WRITE_REG(Vet, 0); + + em_clear_vfta(Adapter); + + if (Adapter->MacType == MAC_WISEMAN_2_0) { + + if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT + ("Disabling MWI on rev 2.0 Wiseman silicon\n"); + + PciCommandWord = + Adapter-> + PciCommandWord & ~CMD_MEM_WRT_INVALIDATE; + + WritePciConfigWord(PCI_COMMAND_REGISTER, + &PciCommandWord); + } + + E1000_WRITE_REG(Rctl, E1000_RCTL_RST); + + DelayInMilliseconds(5); + } + + em_init_rx_addresses(Adapter); + + if (Adapter->MacType == MAC_WISEMAN_2_0) { + E1000_WRITE_REG(Rctl, 0); + + DelayInMilliseconds(1); + + if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { + WritePciConfigWord(PCI_COMMAND_REGISTER, + &Adapter->PciCommandWord); + } + + } + + DEBUGOUT("Zeroing the MTA\n"); + for (i = 0; i < E1000_MC_TBL_SIZE; i++) { + E1000_WRITE_REG(Mta[i], 0); + } + + Status = em_setup_flow_control_and_link(Adapter); + + em_clear_hw_stats_counters(Adapter); + + return (Status); +} + +void em_init_rx_addresses(struct adapter *Adapter) + { + u32 i; + u32 HwLowAddress; + u32 HwHighAddress; + + DEBUGFUNC("em_init_rx_addresses") + + DEBUGOUT("Programming IA into RAR[0]\n"); + HwLowAddress = (Adapter->CurrentNetAddress[0] | + (Adapter->CurrentNetAddress[1] << 8) | + (Adapter->CurrentNetAddress[2] << 16) | + (Adapter->CurrentNetAddress[3] << 24)); + + HwHighAddress = (Adapter->CurrentNetAddress[4] | + (Adapter->CurrentNetAddress[5] << 8) | + E1000_RAH_AV); + + E1000_WRITE_REG(Rar[0].Low, HwLowAddress); + E1000_WRITE_REG(Rar[0].High, HwHighAddress); + + DEBUGOUT("Clearing RAR[1-15]\n"); + for (i = 1; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG(Rar[i].Low, 0); + E1000_WRITE_REG(Rar[i].High, 0); + } + + return; +} + +void em_multicast_address_list_update(struct adapter *Adapter, + u8 * MulticastAddressList, + u32 MulticastAddressCount, + u32 Padding) +{ + + u32 HashValue; + u32 i; + u32 RarUsedCount = 1; + + DEBUGFUNC("em_multicast_address_list_update"); + + Adapter->NumberOfMcAddresses = MulticastAddressCount; + + DEBUGOUT(" Clearing RAR[1-15]\n"); + for (i = RarUsedCount; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG(Rar[i].Low, 0); + E1000_WRITE_REG(Rar[i].High, 0); + } + + DEBUGOUT(" Clearing MTA\n"); + for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + E1000_WRITE_REG(Mta[i], 0); + } + + for (i = 0; i < MulticastAddressCount; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", + i, + MulticastAddressList[i * + (ETH_LENGTH_OF_ADDRESS + + Padding)], + MulticastAddressList[i * + (ETH_LENGTH_OF_ADDRESS + + Padding) + 1], + MulticastAddressList[i * + (ETH_LENGTH_OF_ADDRESS + + Padding) + 2], + MulticastAddressList[i * + (ETH_LENGTH_OF_ADDRESS + + Padding) + 3], + MulticastAddressList[i * + (ETH_LENGTH_OF_ADDRESS + + Padding) + 4], + MulticastAddressList[i * + (ETH_LENGTH_OF_ADDRESS + + Padding) + 5]); + + HashValue = em_hash_multicast_address(Adapter, + MulticastAddressList + + + (i * + (ETH_LENGTH_OF_ADDRESS + + Padding))); + + DEBUGOUT1(" Hash value = 0x%03X\n", HashValue); + + if (RarUsedCount < E1000_RAR_ENTRIES) { + em_rar_set(Adapter, + MulticastAddressList + + (i * (ETH_LENGTH_OF_ADDRESS + Padding)), + RarUsedCount); + RarUsedCount++; + } else { + em_mta_set(Adapter, HashValue); + } + + } + + DEBUGOUT("MC Update Complete\n"); +} + +u32 em_hash_multicast_address(struct adapter *Adapter, + u8 * MulticastAddress) + { + u32 HashValue = 0; + + switch (Adapter->MulticastFilterType) { + + case 0: + + HashValue = ((MulticastAddress[4] >> 4) | + (((u16) MulticastAddress[5]) << 4)); + + break; + + case 1: + HashValue = ((MulticastAddress[4] >> 3) | + (((u16) MulticastAddress[5]) << 5)); + + break; + + case 2: + HashValue = ((MulticastAddress[4] >> 2) | + (((u16) MulticastAddress[5]) << 6)); + + break; + + case 3: + HashValue = ((MulticastAddress[4]) | + (((u16) MulticastAddress[5]) << 8)); + + break; + } + + HashValue &= 0xFFF; + return (HashValue); + +} + +void em_mta_set(struct adapter *Adapter, u32 HashValue) +{ + u32 HashBit, HashReg; + u32 MtaRegisterValue; + u32 Temp; + + HashReg = (HashValue >> 5) & 0x7F; + HashBit = HashValue & 0x1F; + + MtaRegisterValue = E1000_READ_REG(Mta[(HashReg)]); + + MtaRegisterValue |= (1 << HashBit); + + if ((Adapter->MacType == MAC_CORDOVA) && ((HashReg & 0x0E) == 1)) { + Temp = E1000_READ_REG(Mta[HashReg - 1]); + E1000_WRITE_REG(Mta[HashReg], HashValue); + E1000_WRITE_REG(Mta[HashReg - 1], Temp); + } else { + E1000_WRITE_REG(Mta[HashReg], MtaRegisterValue); + } + +} + +void em_rar_set(struct adapter *Adapter, + u8 * MulticastAddress, u32 RarIndex) +{ + u32 RarLow, RarHigh; + + RarLow = ((u32) MulticastAddress[0] | + ((u32) MulticastAddress[1] << 8) | + ((u32) MulticastAddress[2] << 16) | + ((u32) MulticastAddress[3] << 24)); + + RarHigh = ((u32) MulticastAddress[4] | + ((u32) MulticastAddress[5] << 8) | E1000_RAH_AV); + + E1000_WRITE_REG(Rar[RarIndex].Low, RarLow); + E1000_WRITE_REG(Rar[RarIndex].High, RarHigh); +} + +void em_write_vfta(struct adapter *Adapter, u32 Offset, u32 Value) + { + u32 Temp; + + if ((Adapter->MacType == MAC_CORDOVA) && ((Offset & 0x0E) == 1)) { + Temp = E1000_READ_REG(Vfta[Offset - 1]); + E1000_WRITE_REG(Vfta[Offset], Value); + E1000_WRITE_REG(Vfta[Offset - 1], Temp); + } else { + E1000_WRITE_REG(Vfta[Offset], Value); + } +} + +void em_clear_vfta(struct adapter *Adapter) + { + u32 Offset; + + for (Offset = 0; Offset < E1000_VLAN_FILTER_TBL_SIZE; Offset++) + E1000_WRITE_REG(Vfta[Offset], 0); + +} + +u8 em_setup_flow_control_and_link(struct adapter *Adapter) + { + u32 TempEepromWord; + u32 DeviceControlReg; + u32 ExtDevControlReg; + u8 Status = 1; + + DEBUGFUNC("em_setup_flow_control_and_link") + + TempEepromWord = + em_read_eeprom_word(Adapter, EEPROM_INIT_CONTROL1_REG); + + DeviceControlReg = + (((TempEepromWord & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) | + ((TempEepromWord & EEPROM_WORD0A_ILOS) << ILOS_SHIFT)); + + if (Adapter->DmaFairness) + DeviceControlReg |= E1000_CTRL_PRIOR; + + TempEepromWord = + em_read_eeprom_word(Adapter, EEPROM_INIT_CONTROL2_REG); + + if (Adapter->FlowControl > FLOW_CONTROL_FULL) { + if ((TempEepromWord & EEPROM_WORD0F_PAUSE_MASK) == 0) + Adapter->FlowControl = FLOW_CONTROL_NONE; + else if ((TempEepromWord & EEPROM_WORD0F_PAUSE_MASK) == + EEPROM_WORD0F_ASM_DIR) Adapter->FlowControl = + FLOW_CONTROL_TRANSMIT_PAUSE; + else + Adapter->FlowControl = FLOW_CONTROL_FULL; + } + + Adapter->OriginalFlowControl = Adapter->FlowControl; + + if (Adapter->MacType == MAC_WISEMAN_2_0) + Adapter->FlowControl &= (~FLOW_CONTROL_TRANSMIT_PAUSE); + + if ((Adapter->MacType < MAC_LIVENGOOD) + && (Adapter->ReportTxEarly == 1)) + Adapter->FlowControl &= (~FLOW_CONTROL_RECEIVE_PAUSE); + + DEBUGOUT1("After fix-ups FlowControl is now = %x\n", + Adapter->FlowControl); + + if (Adapter->MacType >= MAC_LIVENGOOD) { + ExtDevControlReg = + ((TempEepromWord & EEPROM_WORD0F_SWPDIO_EXT) << + SWDPIO__EXT_SHIFT); + E1000_WRITE_REG(Exct, ExtDevControlReg); + } + + if (Adapter->MacType >= MAC_LIVENGOOD) { + if (Adapter->MediaType == MEDIA_TYPE_FIBER) { + Status = + em_setup_pcs_link(Adapter, DeviceControlReg); + + } else { + + Status = em_phy_setup(Adapter, DeviceControlReg); + } + } else { + Status = em_setup_pcs_link(Adapter, DeviceControlReg); + } + + DEBUGOUT + ("Initializing the Flow Control address, type and timer regs\n"); + + E1000_WRITE_REG(Fcal, FLOW_CONTROL_ADDRESS_LOW); + E1000_WRITE_REG(Fcah, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(Fct, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(Fcttv, Adapter->FlowControlPauseTime); + + if (!(Adapter->FlowControl & FLOW_CONTROL_TRANSMIT_PAUSE)) { + E1000_WRITE_REG(Fcrtl, 0); + E1000_WRITE_REG(Fcrth, 0); + } else { + + if (Adapter->FlowControlSendXon) { + E1000_WRITE_REG(Fcrtl, + (Adapter-> + FlowControlLowWatermark | + E1000_FCRTL_XONE)); + E1000_WRITE_REG(Fcrth, + Adapter->FlowControlHighWatermark); + } else { + E1000_WRITE_REG(Fcrtl, + Adapter->FlowControlLowWatermark); + E1000_WRITE_REG(Fcrth, + Adapter->FlowControlHighWatermark); + } + } + + return (Status); +} + +u8 em_setup_pcs_link(struct adapter * Adapter, u32 DeviceControlReg) + { + u32 i; + u32 StatusContents; + u32 TctlReg; + u32 TransmitConfigWord; + u32 Shift32; + + DEBUGFUNC("em_setup_pcs_link") + + TctlReg = E1000_READ_REG(Tctl); + Shift32 = E1000_FDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + E1000_WRITE_REG(Tctl, TctlReg); + + switch (Adapter->FlowControl) { + case FLOW_CONTROL_NONE: + + TransmitConfigWord = (E1000_TXCW_ANE | E1000_TXCW_FD); + + break; + + case FLOW_CONTROL_RECEIVE_PAUSE: + + TransmitConfigWord = + (E1000_TXCW_ANE | E1000_TXCW_FD | + E1000_TXCW_PAUSE_MASK); + + break; + + case FLOW_CONTROL_TRANSMIT_PAUSE: + + TransmitConfigWord = + (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + + break; + + case FLOW_CONTROL_FULL: + + TransmitConfigWord = + (E1000_TXCW_ANE | E1000_TXCW_FD | + E1000_TXCW_PAUSE_MASK); + + break; + + default: + + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + DEBUGOUT("Auto-negotiation enabled\n"); + + E1000_WRITE_REG(Txcw, TransmitConfigWord); + E1000_WRITE_REG(Ctrl, DeviceControlReg); + + Adapter->TxcwRegValue = TransmitConfigWord; + DelayInMilliseconds(1); + + if (!(E1000_READ_REG(Ctrl) & E1000_CTRL_SWDPIN1)) { + + DEBUGOUT("Looking for Link\n"); + for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { + DelayInMilliseconds(10); + + StatusContents = E1000_READ_REG(Status); + if (StatusContents & E1000_STATUS_LU) + break; + } + + if (i == (LINK_UP_TIMEOUT / 10)) { + + DEBUGOUT + ("Never got a valid link from auto-neg!!!\n"); + + Adapter->AutoNegFailed = 1; + em_check_for_link(Adapter); + Adapter->AutoNegFailed = 0; + } else { + Adapter->AutoNegFailed = 0; + DEBUGOUT("Valid Link Found\n"); + } + } else { + DEBUGOUT("No Signal Detected\n"); + } + + return (1); +} + +void em_config_flow_control_after_link_up(struct adapter *Adapter) + { + u16 MiiStatusReg, MiiNWayAdvertiseReg, MiiNWayBasePgAbleReg; + u16 Speed, Duplex; + + DEBUGFUNC("em_config_flow_control_after_link_up") + + if ( + ((Adapter->MediaType == MEDIA_TYPE_FIBER) + && (Adapter->AutoNegFailed)) + || ((Adapter->MediaType == MEDIA_TYPE_COPPER) + && (!Adapter->AutoNeg))) { + em_force_mac_flow_control_setting(Adapter); + } + + if ((Adapter->MediaType == MEDIA_TYPE_COPPER) && Adapter->AutoNeg) { + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + if (MiiStatusReg & MII_SR_AUTONEG_COMPLETE) { + + MiiNWayAdvertiseReg = em_read_phy_register(Adapter, + PHY_AUTONEG_ADVERTISEMENT, + Adapter-> + PhyAddress); + + MiiNWayBasePgAbleReg = + em_read_phy_register(Adapter, + PHY_AUTONEG_LP_BPA, + Adapter->PhyAddress); + + if ((MiiNWayAdvertiseReg & NWAY_AR_PAUSE) && + (MiiNWayBasePgAbleReg & NWAY_LPAR_PAUSE)) { + + if (Adapter->OriginalFlowControl == + FLOW_CONTROL_FULL) { + Adapter->FlowControl = + FLOW_CONTROL_FULL; + DEBUGOUT + ("Flow Control = FULL.\r\n"); + } else { + Adapter->FlowControl = + FLOW_CONTROL_RECEIVE_PAUSE; + DEBUGOUT + ("Flow Control = RX PAUSE frames only.\r\n"); + } + } + + else if (!(MiiNWayAdvertiseReg & NWAY_AR_PAUSE) && + (MiiNWayAdvertiseReg & NWAY_AR_ASM_DIR) && + (MiiNWayBasePgAbleReg & NWAY_LPAR_PAUSE) + && (MiiNWayBasePgAbleReg & + NWAY_LPAR_ASM_DIR)) { + Adapter->FlowControl = + FLOW_CONTROL_TRANSMIT_PAUSE; + DEBUGOUT + ("Flow Control = TX PAUSE frames only.\r\n"); + } + + else if ((MiiNWayAdvertiseReg & NWAY_AR_PAUSE) && + (MiiNWayAdvertiseReg & NWAY_AR_ASM_DIR) && + !(MiiNWayBasePgAbleReg & NWAY_LPAR_PAUSE) + && (MiiNWayBasePgAbleReg & + NWAY_LPAR_ASM_DIR)) { + Adapter->FlowControl = + FLOW_CONTROL_RECEIVE_PAUSE; + DEBUGOUT + ("Flow Control = RX PAUSE frames only.\r\n"); + } + + else if (Adapter->OriginalFlowControl == + FLOW_CONTROL_NONE + || Adapter->OriginalFlowControl == + FLOW_CONTROL_TRANSMIT_PAUSE) { + Adapter->FlowControl = FLOW_CONTROL_NONE; + DEBUGOUT("Flow Control = NONE.\r\n"); + } else { + Adapter->FlowControl = + FLOW_CONTROL_RECEIVE_PAUSE; + DEBUGOUT + ("Flow Control = RX PAUSE frames only.\r\n"); + } + + em_get_speed_and_duplex(Adapter, &Speed, &Duplex); + + if (Duplex == HALF_DUPLEX) + Adapter->FlowControl = FLOW_CONTROL_NONE; + + em_force_mac_flow_control_setting(Adapter); + } else { + DEBUGOUT + ("Copper PHY and Auto Neg has not completed.\r\n"); + } + } +} + +void em_force_mac_flow_control_setting(struct adapter *Adapter) + { + u32 CtrlRegValue; + + DEBUGFUNC("em_force_mac_flow_control_setting") + + CtrlRegValue = E1000_READ_REG(Ctrl); + + switch (Adapter->FlowControl) { + case FLOW_CONTROL_NONE: + + CtrlRegValue &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + + case FLOW_CONTROL_RECEIVE_PAUSE: + + CtrlRegValue &= (~E1000_CTRL_TFCE); + CtrlRegValue |= E1000_CTRL_RFCE; + break; + + case FLOW_CONTROL_TRANSMIT_PAUSE: + + CtrlRegValue &= (~E1000_CTRL_RFCE); + CtrlRegValue |= E1000_CTRL_TFCE; + break; + + case FLOW_CONTROL_FULL: + + CtrlRegValue |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + + default: + + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + + break; + } + + if (Adapter->MacType == MAC_WISEMAN_2_0) + CtrlRegValue &= (~E1000_CTRL_TFCE); + + E1000_WRITE_REG(Ctrl, CtrlRegValue); +} + +void em_check_for_link(struct adapter *Adapter) + { + u32 RxcwRegValue; + u32 CtrlRegValue; + u32 StatusRegValue; + u32 RctlRegValue; + u16 PhyData; + u16 LinkPartnerCapability; + + DEBUGFUNC("em_check_for_link") + + CtrlRegValue = E1000_READ_REG(Ctrl); + + StatusRegValue = E1000_READ_REG(Status); + + RxcwRegValue = E1000_READ_REG(Rxcw); + + if (Adapter->MediaType == MEDIA_TYPE_COPPER && + Adapter->GetLinkStatus) { + + PhyData = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + PhyData = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + if (PhyData & MII_SR_LINK_STATUS) { + Adapter->GetLinkStatus = 0; + } else { + DEBUGOUT("**** CFL - No link detected. ****\r\n"); + return; + } + + if (!Adapter->AutoNeg) { + return; + } + + switch (Adapter->PhyId) { + case PAXSON_PHY_88E1000: + case PAXSON_PHY_88E1000S: + case PAXSON_PHY_INTEGRATED: + + if (Adapter->MacType > MAC_WAINWRIGHT) { + DEBUGOUT + ("CFL - Auto-Neg complete. Configuring Collision Distance."); + em_configure_collision_distance(Adapter); + } else { + + PhyData = em_read_phy_register(Adapter, + PXN_PHY_SPEC_STAT_REG, + Adapter-> + PhyAddress); + + DEBUGOUT1 + ("CFL - Auto-Neg complete. PhyData = %x\r\n", + PhyData); + em_configure_mac_to_phy_settings(Adapter, + PhyData); + } + + em_config_flow_control_after_link_up(Adapter); + break; + + default: + DEBUGOUT("CFL - Invalid PHY detected.\r\n"); + + } + + if (Adapter->TbiCompatibilityEnable) { + LinkPartnerCapability = + em_read_phy_register(Adapter, + PHY_AUTONEG_LP_BPA, + Adapter->PhyAddress); + if (LinkPartnerCapability & + (NWAY_LPAR_10T_HD_CAPS | NWAY_LPAR_10T_FD_CAPS + | NWAY_LPAR_100TX_HD_CAPS | + NWAY_LPAR_100TX_FD_CAPS | + NWAY_LPAR_100T4_CAPS)) { + + if (Adapter->TbiCompatibilityOn) { + + RctlRegValue = + E1000_READ_REG(Rctl); + RctlRegValue &= ~E1000_RCTL_SBP; + E1000_WRITE_REG(Rctl, + RctlRegValue); + Adapter->TbiCompatibilityOn = 0; + } + } else { + + if (!Adapter->TbiCompatibilityOn) { + Adapter->TbiCompatibilityOn = 1; + RctlRegValue = + E1000_READ_REG(Rctl); + RctlRegValue |= E1000_RCTL_SBP; + E1000_WRITE_REG(Rctl, + RctlRegValue); + } + } + } + } + + else + if ((Adapter->MediaType == MEDIA_TYPE_FIBER) && + (!(StatusRegValue & E1000_STATUS_LU)) && + (!(CtrlRegValue & E1000_CTRL_SWDPIN1)) && + (!(RxcwRegValue & E1000_RXCW_C))) { + if (Adapter->AutoNegFailed == 0) { + Adapter->AutoNegFailed = 1; + return; + } + + DEBUGOUT + ("NOT RXing /C/, disable AutoNeg and force link.\r\n"); + + E1000_WRITE_REG(Txcw, + (Adapter->TxcwRegValue & ~E1000_TXCW_ANE)); + + CtrlRegValue = E1000_READ_REG(Ctrl); + CtrlRegValue |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(Ctrl, CtrlRegValue); + + em_config_flow_control_after_link_up(Adapter); + + } + else if ((Adapter->MediaType == MEDIA_TYPE_FIBER) && + (CtrlRegValue & E1000_CTRL_SLU) && + (RxcwRegValue & E1000_RXCW_C)) { + + DEBUGOUT + ("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); + + E1000_WRITE_REG(Txcw, Adapter->TxcwRegValue); + + E1000_WRITE_REG(Ctrl, (CtrlRegValue & ~E1000_CTRL_SLU)); + } + + return; +} + +void em_clear_hw_stats_counters(struct adapter *Adapter) + { + volatile u32 RegisterContents; + + DEBUGFUNC("em_clear_hw_stats_counters") + + if (Adapter->AdapterStopped) { + DEBUGOUT("Exiting because the adapter is stopped!!!\n"); + return; + } + + RegisterContents = E1000_READ_REG(Crcerrs); + RegisterContents = E1000_READ_REG(Symerrs); + RegisterContents = E1000_READ_REG(Mpc); + RegisterContents = E1000_READ_REG(Scc); + RegisterContents = E1000_READ_REG(Ecol); + RegisterContents = E1000_READ_REG(Mcc); + RegisterContents = E1000_READ_REG(Latecol); + RegisterContents = E1000_READ_REG(Colc); + RegisterContents = E1000_READ_REG(Dc); + RegisterContents = E1000_READ_REG(Sec); + RegisterContents = E1000_READ_REG(Rlec); + RegisterContents = E1000_READ_REG(Xonrxc); + RegisterContents = E1000_READ_REG(Xontxc); + RegisterContents = E1000_READ_REG(Xoffrxc); + RegisterContents = E1000_READ_REG(Xofftxc); + RegisterContents = E1000_READ_REG(Fcruc); + RegisterContents = E1000_READ_REG(Prc64); + RegisterContents = E1000_READ_REG(Prc127); + RegisterContents = E1000_READ_REG(Prc255); + RegisterContents = E1000_READ_REG(Prc511); + RegisterContents = E1000_READ_REG(Prc1023); + RegisterContents = E1000_READ_REG(Prc1522); + RegisterContents = E1000_READ_REG(Gprc); + RegisterContents = E1000_READ_REG(Bprc); + RegisterContents = E1000_READ_REG(Mprc); + RegisterContents = E1000_READ_REG(Gptc); + RegisterContents = E1000_READ_REG(Gorl); + RegisterContents = E1000_READ_REG(Gorh); + RegisterContents = E1000_READ_REG(Gotl); + RegisterContents = E1000_READ_REG(Goth); + RegisterContents = E1000_READ_REG(Rnbc); + RegisterContents = E1000_READ_REG(Ruc); + RegisterContents = E1000_READ_REG(Rfc); + RegisterContents = E1000_READ_REG(Roc); + RegisterContents = E1000_READ_REG(Rjc); + RegisterContents = E1000_READ_REG(Torl); + RegisterContents = E1000_READ_REG(Torh); + RegisterContents = E1000_READ_REG(Totl); + RegisterContents = E1000_READ_REG(Toth); + RegisterContents = E1000_READ_REG(Tpr); + RegisterContents = E1000_READ_REG(Tpt); + RegisterContents = E1000_READ_REG(Ptc64); + RegisterContents = E1000_READ_REG(Ptc127); + RegisterContents = E1000_READ_REG(Ptc255); + RegisterContents = E1000_READ_REG(Ptc511); + RegisterContents = E1000_READ_REG(Ptc1023); + RegisterContents = E1000_READ_REG(Ptc1522); + RegisterContents = E1000_READ_REG(Mptc); + RegisterContents = E1000_READ_REG(Bptc); + + if (Adapter->MacType < MAC_LIVENGOOD) + return; + + RegisterContents = E1000_READ_REG(Algnerrc); + RegisterContents = E1000_READ_REG(Rxerrc); + RegisterContents = E1000_READ_REG(Tuc); + RegisterContents = E1000_READ_REG(Tncrs); + RegisterContents = E1000_READ_REG(Cexterr); + RegisterContents = E1000_READ_REG(Rutec); + + RegisterContents = E1000_READ_REG(Tsctc); + RegisterContents = E1000_READ_REG(Tsctfc); + +} + +void em_get_speed_and_duplex(struct adapter *Adapter, + u16 * Speed, u16 * Duplex) + { + u32 DeviceStatusReg; + + DEBUGFUNC("em_get_speed_and_duplex") + + if (Adapter->AdapterStopped) { + *Speed = 0; + *Duplex = 0; + return; + } + + if (Adapter->MacType >= MAC_LIVENGOOD) { + DEBUGOUT("Livengood MAC\n"); + DeviceStatusReg = E1000_READ_REG(Status); + if (DeviceStatusReg & E1000_STATUS_SPEED_1000) { + *Speed = SPEED_1000; + DEBUGOUT(" 1000 Mbs\n"); + } else if (DeviceStatusReg & E1000_STATUS_SPEED_100) { + *Speed = SPEED_100; + DEBUGOUT(" 100 Mbs\n"); + } else { + *Speed = SPEED_10; + DEBUGOUT(" 10 Mbs\n"); + } + + if (DeviceStatusReg & E1000_STATUS_FD) { + *Duplex = FULL_DUPLEX; + DEBUGOUT(" Full Duplex\r\n"); + } else { + *Duplex = HALF_DUPLEX; + DEBUGOUT(" Half Duplex\r\n"); + } + } else { + DEBUGOUT("Wiseman MAC - 1000 Mbs, Full Duplex\r\n"); + *Speed = SPEED_1000; + *Duplex = FULL_DUPLEX; + } + + return; +} + +void em_setup_eeprom(struct adapter *Adapter) +{ + u32 val; + + val = E1000_READ_REG(Eecd); + + val &= ~(E1000_EESK | E1000_EEDI); + E1000_WRITE_REG(Eecd, val); + + val |= E1000_EECS; + E1000_WRITE_REG(Eecd, val); +} + +void em_standby_eeprom(struct adapter *Adapter) +{ + u32 val; + + val = E1000_READ_REG(Eecd); + + val &= ~(E1000_EECS | E1000_EESK); + E1000_WRITE_REG(Eecd, val); + DelayInMicroseconds(50); + + val |= E1000_EESK; + E1000_WRITE_REG(Eecd, val); + DelayInMicroseconds(50); + + val |= E1000_EECS; + E1000_WRITE_REG(Eecd, val); + DelayInMicroseconds(50); + + val &= ~E1000_EESK; + E1000_WRITE_REG(Eecd, val); + DelayInMicroseconds(50); +} + +void em_clock_eeprom(struct adapter *Adapter) +{ + u32 val; + + val = E1000_READ_REG(Eecd); + + val |= E1000_EESK; + E1000_WRITE_REG(Eecd, val); + DelayInMicroseconds(50); + + val &= ~E1000_EESK; + E1000_WRITE_REG(Eecd, val); + DelayInMicroseconds(50); +} + +void em_cleanup_eeprom(struct adapter *Adapter) +{ + u32 val; + + val = E1000_READ_REG(Eecd); + + val &= ~(E1000_EECS | E1000_EEDI); + + E1000_WRITE_REG(Eecd, val); + + em_clock_eeprom(Adapter); +} + +u16 em_read_eeprom_word(struct adapter *Adapter, u16 Reg) + { + u16 Data; + + ASSERT(Reg < EEPROM_WORD_SIZE); + + E1000_WRITE_REG(Eecd, E1000_EECS); + + em_shift_out_bits(Adapter, EEPROM_READ_OPCODE, 3); + em_shift_out_bits(Adapter, Reg, 6); + + Data = em_shift_in_bits(Adapter); + + em_eeprom_cleanup(Adapter); + return (Data); +} + +static void em_shift_out_bits(struct adapter *Adapter, u16 Data, u16 Count) + { + u32 EecdRegValue; + u32 Mask; + + Mask = 0x01 << (Count - 1); + + EecdRegValue = E1000_READ_REG(Eecd); + + EecdRegValue &= ~(E1000_EEDO | E1000_EEDI); + + do { + + EecdRegValue &= ~E1000_EEDI; + + if (Data & Mask) + EecdRegValue |= E1000_EEDI; + + E1000_WRITE_REG(Eecd, EecdRegValue); + + DelayInMicroseconds(50); + + em_raise_clock(Adapter, &EecdRegValue); + em_lower_clock(Adapter, &EecdRegValue); + + Mask = Mask >> 1; + + } while (Mask); + + EecdRegValue &= ~E1000_EEDI; + + E1000_WRITE_REG(Eecd, EecdRegValue); +} + +static void em_raise_clock(struct adapter *Adapter, u32 * EecdRegValue) + { + + *EecdRegValue = *EecdRegValue | E1000_EESK; + + E1000_WRITE_REG(Eecd, *EecdRegValue); + + DelayInMicroseconds(50); +} + +static void em_lower_clock(struct adapter *Adapter, u32 * EecdRegValue) + { + + *EecdRegValue = *EecdRegValue & ~E1000_EESK; + + E1000_WRITE_REG(Eecd, *EecdRegValue); + + DelayInMicroseconds(50); +} + +static u16 em_shift_in_bits(struct adapter *Adapter) + { + u32 EecdRegValue; + u32 i; + u16 Data; + + EecdRegValue = E1000_READ_REG(Eecd); + + EecdRegValue &= ~(E1000_EEDO | E1000_EEDI); + Data = 0; + + for (i = 0; i < 16; i++) { + Data = Data << 1; + em_raise_clock(Adapter, &EecdRegValue); + + EecdRegValue = E1000_READ_REG(Eecd); + + EecdRegValue &= ~(E1000_EEDI); + if (EecdRegValue & E1000_EEDO) + Data |= 1; + + em_lower_clock(Adapter, &EecdRegValue); + } + + return (Data); +} + +static void em_eeprom_cleanup(struct adapter *Adapter) + { + u32 EecdRegValue; + + EecdRegValue = E1000_READ_REG(Eecd); + + EecdRegValue &= ~(E1000_EECS | E1000_EEDI); + + E1000_WRITE_REG(Eecd, EecdRegValue); + + em_raise_clock(Adapter, &EecdRegValue); + em_lower_clock(Adapter, &EecdRegValue); +} + +u8 em_validate_eeprom_checksum(struct adapter *Adapter) + { + u16 Checksum = 0; + u16 Iteration; + + for (Iteration = 0; Iteration < (EEPROM_CHECKSUM_REG + 1); + Iteration++) + Checksum += em_read_eeprom_word(Adapter, Iteration); + + if (Checksum == (u16) EEPROM_SUM) + return (1); + else + return (0); +} + +void em_update_eeprom_checksum(struct adapter *Adapter) + { + u16 Checksum = 0; + u16 Iteration; + + for (Iteration = 0; Iteration < EEPROM_CHECKSUM_REG; Iteration++) + Checksum += em_read_eeprom_word(Adapter, Iteration); + + Checksum = (u16) EEPROM_SUM - Checksum; + + em_write_eeprom_word(Adapter, EEPROM_CHECKSUM_REG, Checksum); +} + +u8 em_write_eeprom_word(struct adapter *Adapter, u16 Reg, u16 Data) + { + + em_setup_eeprom(Adapter); + + em_shift_out_bits(Adapter, EEPROM_EWEN_OPCODE, 5); + em_shift_out_bits(Adapter, 0, 4); + + em_standby_eeprom(Adapter); + + em_shift_out_bits(Adapter, EEPROM_WRITE_OPCODE, 3); + em_shift_out_bits(Adapter, Reg, 6); + + em_shift_out_bits(Adapter, Data, 16); + + em_wait_eeprom_command_done(Adapter); + + em_standby_eeprom(Adapter); + + em_shift_out_bits(Adapter, EEPROM_EWDS_OPCODE, 5); + em_shift_out_bits(Adapter, 0, 4); + + em_cleanup_eeprom(Adapter); + + return (1); +} + +static u16 em_wait_eeprom_command_done(struct adapter *Adapter) + { + u32 EecdRegValue; + u32 i; + + em_stand_by(Adapter); + + for (i = 0; i < 200; i++) { + EecdRegValue = E1000_READ_REG(Eecd); + + if (EecdRegValue & E1000_EEDO) + return (1); + + DelayInMicroseconds(50); + } + ASSERT(0); + return (0); +} + +static void em_stand_by(struct adapter *Adapter) + { + u32 EecdRegValue; + + EecdRegValue = E1000_READ_REG(Eecd); + + EecdRegValue &= ~(E1000_EECS | E1000_EESK); + + E1000_WRITE_REG(Eecd, EecdRegValue); + + DelayInMicroseconds(5); + + EecdRegValue |= E1000_EECS; + + E1000_WRITE_REG(Eecd, EecdRegValue); +} + +u8 em_read_part_number(struct adapter *Adapter, u32 * PartNumber) +{ + u16 EepromWordValue; + + DEBUGFUNC("em_read_part_number") + + if (Adapter->AdapterStopped) { + *PartNumber = 0; + return (0); + } + + EepromWordValue = em_read_eeprom_word(Adapter, + (u16) (EEPROM_PBA_BYTE_1)); + + DEBUGOUT("Read first part number word\n"); + + *PartNumber = (u32) EepromWordValue; + *PartNumber = *PartNumber << 16; + + EepromWordValue = em_read_eeprom_word(Adapter, + (u16) (EEPROM_PBA_BYTE_1 + + 1)); + + DEBUGOUT("Read second part number word\n"); + + *PartNumber |= EepromWordValue; + + return (1); + +} + +void em_id_led_on(struct adapter *Adapter) +{ + u32 CtrlRegValue; + + if (Adapter->AdapterStopped) { + return; + } + + CtrlRegValue = E1000_READ_REG(Ctrl); + + CtrlRegValue |= E1000_CTRL_SWDPIO0; + + if (em_is_low_profile(Adapter)) { + CtrlRegValue &= ~E1000_CTRL_SWDPIN0; + } else { + CtrlRegValue |= E1000_CTRL_SWDPIN0; + } + + E1000_WRITE_REG(Ctrl, CtrlRegValue); + +} + +void em_id_led_off(struct adapter *Adapter) +{ + u32 CtrlRegValue; + + if (Adapter->AdapterStopped) { + return; + } + + CtrlRegValue = E1000_READ_REG(Ctrl); + + CtrlRegValue |= E1000_CTRL_SWDPIO0; + + if (em_is_low_profile(Adapter)) { + CtrlRegValue |= E1000_CTRL_SWDPIN0; + } else { + CtrlRegValue &= ~E1000_CTRL_SWDPIN0; + } + + E1000_WRITE_REG(Ctrl, CtrlRegValue); +} + +void em_set_id_led_for_pc_ix(struct adapter *Adapter) +{ + u32 PciStatus; + + PciStatus = E1000_READ_REG(Status); + + if (PciStatus & E1000_STATUS_PCIX_MODE) { + em_id_led_on(Adapter); + } else { + em_id_led_off(Adapter); + } +} + +u8 em_is_low_profile(struct adapter *Adapter) +{ + u16 LedLogicWord; + u8 ReturnValue = 0; + + if (Adapter->MacType >= MAC_CORDOVA) { + + LedLogicWord = + em_read_eeprom_word(Adapter, E1000_EEPROM_LED_LOGIC); + + if (LedLogicWord & E1000_EEPROM_SWDPIN0) + ReturnValue = 1; + else + ReturnValue = 0; + } + + return ReturnValue; +} + +void em_adjust_tbi_accepted_stats(struct adapter *Adapter, + u32 FrameLength, u8 * MacAddress) +{ + u32 CarryBit; + + FrameLength--; + + Adapter->Crcerrs--; + + Adapter->Gprc++; + + CarryBit = 0x80000000 & Adapter->Gorcl; + Adapter->Gorcl += FrameLength; + + if (CarryBit && ((Adapter->Gorcl & 0x80000000) == 0)) { + Adapter->Gorch++; + } + + if ((MacAddress[0] == (u8) 0xff) && (MacAddress[1] == (u8) 0xff)) { + + Adapter->Bprc++; + } else if (*MacAddress & 0x01) { + + Adapter->Mprc++; + } + if (FrameLength == Adapter->MaxFrameSize) { + + Adapter->Roc += E1000_READ_REG(Roc); + if (Adapter->Roc > 0) + Adapter->Roc--; + } + + if (FrameLength == 64) { + Adapter->Prc64++; + Adapter->Prc127--; + } else if (FrameLength == 127) { + Adapter->Prc127++; + Adapter->Prc255--; + } else if (FrameLength == 255) { + Adapter->Prc255++; + Adapter->Prc511--; + } else if (FrameLength == 511) { + Adapter->Prc511++; + Adapter->Prc1023--; + } else if (FrameLength == 1023) { + Adapter->Prc1023++; + Adapter->Prc1522--; + } else if (FrameLength == 1522) { + Adapter->Prc1522++; + } +} + +void em_get_bus_type_speed_width(struct adapter *Adapter) +{ + u32 DeviceStatusReg; + + if (Adapter->MacType < MAC_LIVENGOOD) { + Adapter->BusType = E1000_BUS_TYPE_UNKNOWN; + Adapter->BusSpeed = E1000_BUS_SPEED_UNKNOWN; + Adapter->BusWidth = E1000_BUS_WIDTH_UNKNOWN; + return; + } + + DeviceStatusReg = E1000_READ_REG(Status); + + Adapter->BusType = (DeviceStatusReg & E1000_STATUS_PCIX_MODE) ? + E1000_BUS_TYPE_PCIX : E1000_BUS_TYPE_PCI; + + if (Adapter->BusType == E1000_BUS_TYPE_PCI) { + Adapter->BusSpeed = + (DeviceStatusReg & E1000_STATUS_PCI66) ? + E1000_BUS_SPEED_PCI_66MHZ : E1000_BUS_SPEED_PCI_33MHZ; + } else { + switch (DeviceStatusReg & E1000_STATUS_PCIX_SPEED) { + case E1000_STATUS_PCIX_SPEED_66: + Adapter->BusSpeed = E1000_BUS_SPEED_PCIX_50_66MHZ; + break; + case E1000_STATUS_PCIX_SPEED_100: + Adapter->BusSpeed = E1000_BUS_SPEED_PCIX_66_100MHZ; + break; + case E1000_STATUS_PCIX_SPEED_133: + Adapter->BusSpeed = + E1000_BUS_SPEED_PCIX_100_133MHZ; + break; + default: + Adapter->BusSpeed = E1000_BUS_SPEED_PCIX_RESERVED; + break; + } + } + + Adapter->BusWidth = (DeviceStatusReg & E1000_STATUS_BUS64) ? + E1000_BUS_WIDTH_64_BIT : E1000_BUS_WIDTH_32_BIT; + + return; +} diff --git a/sys/dev/em/if_em_fxhw.h b/sys/dev/em/if_em_fxhw.h new file mode 100644 index 0000000..86447e5 --- /dev/null +++ b/sys/dev/em/if_em_fxhw.h @@ -0,0 +1,1338 @@ +/************************************************************************* +************************************************************************** +Copyright (c) 2001 Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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$ +*************************************************************************** +**************************************************************************/ + +#ifndef _EM_FXHW_H_ +#define _EM_FXHW_H_ + +/* +* Workfile: fxhw.h +* Date: 9/25/01 2:40p +* Revision: 43 +*/ + +#define _FXHW_ + +struct adapter; +struct _E1000_TRANSMIT_DESCRIPTOR; +struct _E1000_RECEIVE_DESCRIPTOR; +struct E1000_REGISTERS; + +typedef enum _MAC_TYPE { + MAC_WISEMAN_2_0 = 0, + MAC_WISEMAN_2_1, + MAC_LIVENGOOD, + MAC_WAINWRIGHT, + MAC_CORDOVA, + NUM_MACS +} MAC_TYPE, *PMAC_TYPE; + +typedef enum _GIGABIT_MEDIA_TYPE { + MEDIA_TYPE_COPPER = 0, + MEDIA_TYPE_FIBER = 1, + NUM_MEDIA_TYPES +} GIGABIT_MEDIA_TYPE, *PGIGABIT_MEDIA_TYPE; + +typedef enum _SPEED_DUPLEX_TYPE { + HALF_10 = 0, + FULL_10 = 1, + HALF_100 = 2, + FULL_100 = 3 +} SPEED_DUPLEX_TYPE, *PSPEED_DUPLEX_TYPE; + +typedef enum _FLOW_CONTROL_TYPE { + FLOW_CONTROL_NONE = 0, + FLOW_CONTROL_RECEIVE_PAUSE = 1, + FLOW_CONTROL_TRANSMIT_PAUSE = 2, + FLOW_CONTROL_FULL = 3, + FLOW_CONTROL_HW_DEFAULT = 0xFF +} FLOW_CONTROL_TYPE, *PFLOW_CONTROL_TYPE; + +typedef enum { + E1000_BUS_TYPE_UNKNOWN = 0, + E1000_BUS_TYPE_PCI, + E1000_BUS_TYPE_PCIX +} E1000_BUS_TYPE_ENUM; + +typedef enum { + E1000_BUS_SPEED_UNKNOWN = 0, + E1000_BUS_SPEED_PCI_33MHZ, + E1000_BUS_SPEED_PCI_66MHZ, + E1000_BUS_SPEED_PCIX_50_66MHZ, + E1000_BUS_SPEED_PCIX_66_100MHZ, + E1000_BUS_SPEED_PCIX_100_133MHZ, + E1000_BUS_SPEED_PCIX_RESERVED +} E1000_BUS_SPEED_ENUM; + +typedef enum { + E1000_BUS_WIDTH_UNKNOWN = 0, + E1000_BUS_WIDTH_32_BIT, + E1000_BUS_WIDTH_64_BIT +} E1000_BUS_WIDTH_ENUM; + +#include <dev/em/if_em_osdep.h> + +void em_adapter_stop(struct adapter *Adapter); +u8 em_initialize_hardware(struct adapter *Adapter); +void em_init_rx_addresses(struct adapter *Adapter); + +void em_multicast_address_list_update(struct adapter *Adapter, + u8 * MulticastAddressList, + u32 MulticastAddressCount, + + u32 Padding); +u32 em_hash_multicast_address(struct adapter *Adapter, + + u8 * MulticastAddress); +void em_mta_set(struct adapter *Adapter, u32 HashValue); +void em_rar_set(struct adapter *Adapter, + + u8 * MulticastAddress, u32 RarIndex); +void em_write_vfta(struct adapter *Adapter, u32 Offset, u32 Value); +void em_clear_vfta(struct adapter *Adapter); + +u8 em_setup_flow_control_and_link(struct adapter *Adapter); +u8 em_setup_pcs_link(struct adapter *Adapter, u32 DeviceControlReg); +void em_config_flow_control_after_link_up(struct adapter *Adapter); +void em_force_mac_flow_control_setting(struct adapter *Adapter); +void em_check_for_link(struct adapter *Adapter); +void em_get_speed_and_duplex(struct adapter *Adapter, + + u16 * Speed, u16 * Duplex); + +void em_cleanup_eeprom(struct adapter *Adapter); +void em_clock_eeprom(struct adapter *Adapter); +void em_setup_eeprom(struct adapter *Adapter); +void em_standby_eeprom(struct adapter *Adapter); +u16 em_read_eeprom_word(struct adapter *Adapter, u16 Reg); +u8 em_validate_eeprom_checksum(struct adapter *Adapter); +void em_update_eeprom_checksum(struct adapter *Adapter); +u8 em_write_eeprom_word(struct adapter *Adapter, u16 reg, u16 data); + +void em_clear_hw_stats_counters(struct adapter *Adapter); +u8 em_read_part_number(struct adapter *Adapter, u32 * PartNumber); +void em_id_led_on(struct adapter *Adapter); +void em_id_led_off(struct adapter *Adapter); +void em_set_id_led_for_pc_ix(struct adapter *Adapter); +u8 em_is_low_profile(struct adapter *Adapter); +void em_get_bus_type_speed_width(struct adapter *Adapter); + +#define MAC_DECODE_SIZE (128 * 1024) + +#define WISEMAN_2_0_REV_ID 2 +#define WISEMAN_2_1_REV_ID 3 + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 +#define MINIMUM_ETHERNET_PACKET_SIZE 60 +#define CRC_LENGTH 4 + +#define MAX_JUMBO_FRAME_SIZE (0x3F00) + +#define ISL_CRC_LENGTH 4 + +#define MAXIMUM_VLAN_ETHERNET_PACKET_SIZE 1514 +#define MINIMUM_VLAN_ETHERNET_PACKET_SIZE 60 +#define VLAN_TAG_SIZE 4 + +#define ETHERNET_IEEE_VLAN_TYPE 0x8100 +#define ETHERNET_IP_TYPE 0x0800 +#define ETHERNET_IPX_TYPE 0x8037 +#define ETHERNET_IPX_OLD_TYPE 0x8137 +#define MAX_802_3_LEN_FIELD 0x05DC + +#define ETHERNET_ARP_TYPE 0x0806 +#define ETHERNET_XNS_TYPE 0x0600 +#define ETHERNET_X25_TYPE 0x0805 +#define ETHERNET_BANYAN_TYPE 0x0BAD +#define ETHERNET_DECNET_TYPE 0x6003 +#define ETHERNET_APPLETALK_TYPE 0x809B +#define ETHERNET_SNA_TYPE 0x80D5 +#define ETHERNET_SNMP_TYPE 0x814C + +#define IP_OFF_MF_BIT 0x0002 +#define IP_OFF_OFFSET_MASK 0xFFF8 +#define IP_PROTOCOL_ICMP 1 +#define IP_PROTOCOL_IGMP 2 +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 0x11 +#define IP_PROTOCOL_IPRAW 0xFF + +#define POLL_IMS_ENABLE_MASK (E1000_IMS_RXDMT0 | E1000_IMS_RXSEQ) + +#define IMS_ENABLE_MASK (E1000_IMS_RXT0 | E1000_IMS_TXDW | E1000_IMS_RXDMT0 | E1000_IMS_RXSEQ | E1000_IMS_LSC) + +#define E1000_RAR_ENTRIES 16 + +typedef struct _E1000_RECEIVE_DESCRIPTOR { + E1000_64_BIT_PHYSICAL_ADDRESS BufferAddress; + + u16 Length; + u16 Csum; + u8 ReceiveStatus; + u8 Errors; + u16 Special; + +} E1000_RECEIVE_DESCRIPTOR, *PE1000_RECEIVE_DESCRIPTOR; + +#define MIN_NUMBER_OF_DESCRIPTORS (8) +#define MAX_NUMBER_OF_DESCRIPTORS (0xFFF8) + +#define E1000_RXD_STAT_DD (0x01) +#define E1000_RXD_STAT_EOP (0x02) + +#define E1000_RXD_STAT_ISL (0x04) +#define E1000_RXD_STAT_IXSM (0x04) +#define E1000_RXD_STAT_VP (0x08) +#define E1000_RXD_STAT_BPDU (0x10) +#define E1000_RXD_STAT_TCPCS (0x20) +#define E1000_RXD_STAT_IPCS (0x40) + +#define E1000_RXD_STAT_PIF (0x80) + +#define E1000_RXD_ERR_CE (0x01) +#define E1000_RXD_ERR_SE (0x02) +#define E1000_RXD_ERR_SEQ (0x04) + +#define E1000_RXD_ERR_ICE (0x08) + +#define E1000_RXD_ERR_CXE (0x10) + +#define E1000_RXD_ERR_TCPE (0x20) +#define E1000_RXD_ERR_IPE (0x40) + +#define E1000_RXD_ERR_RXE (0x80) + +#define E1000_RXD_ERR_FRAME_ERR_MASK (E1000_RXD_ERR_CE | E1000_RXD_ERR_SE | E1000_RXD_ERR_SEQ | E1000_RXD_ERR_CXE | E1000_RXD_ERR_RXE) + +#define E1000_RXD_SPC_VLAN_MASK (0x0FFF) +#define E1000_RXD_SPC_PRI_MASK (0xE000) +#define E1000_RXD_SPC_PRI_SHIFT (0x000D) +#define E1000_RXD_SPC_CFI_MASK (0x1000) +#define E1000_RXD_SPC_CFI_SHIFT (0x000C) + +#define E1000_TXD_DTYP_D (0x00100000) +#define E1000_TXD_DTYP_C (0x00000000) +#define E1000_TXD_POPTS_IXSM (0x01) +#define E1000_TXD_POPTS_TXSM (0x02) + +typedef struct _E1000_TRANSMIT_DESCRIPTOR { + E1000_64_BIT_PHYSICAL_ADDRESS BufferAddress; + + union { + u32 DwordData; + struct _TXD_FLAGS { + u16 Length; + u8 Cso; + u8 Cmd; + } Flags; + } Lower; + + union { + u32 DwordData; + struct _TXD_FIELDS { + u8 TransmitStatus; + u8 Css; + u16 Special; + } Fields; + } Upper; + +} E1000_TRANSMIT_DESCRIPTOR, *PE1000_TRANSMIT_DESCRIPTOR; + +typedef struct _E1000_TCPIP_CONTEXT_TRANSMIT_DESCRIPTOR { + union { + u32 IpXsumConfig; + struct _IP_XSUM_FIELDS { + u8 Ipcss; + u8 Ipcso; + u16 Ipcse; + } IpFields; + } LowerXsumSetup; + + union { + u32 TcpXsumConfig; + struct _TCP_XSUM_FIELDS { + u8 Tucss; + u8 Tucso; + u16 Tucse; + } TcpFields; + } UpperXsumSetup; + + u32 CmdAndLength; + + union { + u32 DwordData; + struct _TCP_SEG_FIELDS { + u8 Status; + u8 HdrLen; + u16 Mss; + } Fields; + } TcpSegSetup; + +} E1000_TCPIP_CONTEXT_TRANSMIT_DESCRIPTOR, + + *PE1000_TCPIP_CONTEXT_TRANSMIT_DESCRIPTOR; + +typedef struct _E1000_TCPIP_DATA_TRANSMIT_DESCRIPTOR { + E1000_64_BIT_PHYSICAL_ADDRESS BufferAddress; + + union { + u32 DwordData; + struct _TXD_OD_FLAGS { + u16 Length; + u8 TypLenExt; + u8 Cmd; + } Flags; + } Lower; + + union { + u32 DwordData; + struct _TXD_OD_FIELDS { + u8 TransmitStatus; + u8 Popts; + u16 Special; + } Fields; + } Upper; + +} E1000_TCPIP_DATA_TRANSMIT_DESCRIPTOR, + + *PE1000_TCPIP_DATA_TRANSMIT_DESCRIPTOR; + +#define E1000_TXD_CMD_EOP (0x01000000) +#define E1000_TXD_CMD_IFCS (0x02000000) + +#define E1000_TXD_CMD_IC (0x04000000) + +#define E1000_TXD_CMD_RS (0x08000000) +#define E1000_TXD_CMD_RPS (0x10000000) + +#define E1000_TXD_CMD_DEXT (0x20000000) +#define E1000_TXD_CMD_ISLVE (0x40000000) + +#define E1000_TXD_CMD_IDE (0x80000000) + +#define E1000_TXD_STAT_DD (0x00000001) +#define E1000_TXD_STAT_EC (0x00000002) +#define E1000_TXD_STAT_LC (0x00000004) +#define E1000_TXD_STAT_TU (0x00000008) + +#define E1000_TXD_CMD_TCP (0x01000000) +#define E1000_TXD_CMD_IP (0x02000000) +#define E1000_TXD_CMD_TSE (0x04000000) + +#define E1000_TXD_STAT_TC (0x00000004) + +#define E1000_NUM_UNICAST (16) +#define E1000_MC_TBL_SIZE (128) + +#define E1000_VLAN_FILTER_TBL_SIZE (128) + +typedef struct { + volatile u32 Low; + volatile u32 High; +} RECEIVE_ADDRESS_REGISTER_PAIR; + +#define E1000_NUM_MTA_REGISTERS 128 + +typedef struct { + volatile u32 IpAddress; + volatile u32 Reserved; +} IPAT_ENTRY; + +#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX (4) +#define E1000_IPAT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX + +typedef struct { + volatile u32 Length; + volatile u32 Reserved; +} FFLT_ENTRY; + +typedef struct { + volatile u32 Mask; + volatile u32 Reserved; +} FFMT_ENTRY; + +typedef struct { + volatile u32 Value; + volatile u32 Reserved; +} FFVT_ENTRY; + +#define E1000_FLEXIBLE_FILTER_COUNT_MAX (4) + +#define E1000_FLEXIBLE_FILTER_SIZE_MAX (128) + +#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX +#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX + +typedef struct _E1000_REGISTERS { + + volatile u32 Ctrl; + volatile u32 Pad1; + volatile u32 Status; + volatile u32 Pad2; + volatile u32 Eecd; + volatile u32 Pad3; + volatile u32 Exct; + volatile u32 Pad4; + volatile u32 Mdic; + volatile u32 Pad5; + volatile u32 Fcal; + volatile u32 Fcah; + volatile u32 Fct; + volatile u32 Pad6; + + volatile u32 Vet; + volatile u32 Pad7; + + RECEIVE_ADDRESS_REGISTER_PAIR Rar[16]; + + volatile u32 Icr; + volatile u32 Pad8; + volatile u32 Ics; + volatile u32 Pad9; + volatile u32 Ims; + volatile u32 Pad10; + volatile u32 Imc; + volatile u8 Pad11[0x24]; + + volatile u32 Rctl; + volatile u32 Pad12; + volatile u32 PadRdtr0; + volatile u32 Pad13; + volatile u32 PadRdbal0; + volatile u32 PadRdbah0; + volatile u32 PadRdlen0; + volatile u32 Pad14; + volatile u32 PadRdh0; + volatile u32 Pad15; + volatile u32 PadRdt0; + volatile u32 Pad16; + volatile u32 Rdtr1; + volatile u32 Pad17; + volatile u32 Rdbal1; + volatile u32 Rdbah1; + volatile u32 Rdlen1; + volatile u32 Pad18; + volatile u32 Rdh1; + volatile u32 Pad19; + volatile u32 Rdt1; + volatile u8 Pad20[0x0C]; + volatile u32 PadFcrth; + volatile u32 Pad21; + volatile u32 PadFcrtl; + volatile u32 Pad22; + volatile u32 Fcttv; + volatile u32 Pad23; + volatile u32 Txcw; + volatile u32 Pad24; + volatile u32 Rxcw; + volatile u8 Pad25[0x7C]; + volatile u32 Mta[(128)]; + + volatile u32 Tctl; + volatile u32 Pad26; + volatile u32 Tqsal; + volatile u32 Tqsah; + volatile u32 Tipg; + volatile u32 Pad27; + volatile u32 Tqc; + volatile u32 Pad28; + volatile u32 PadTdbal; + volatile u32 PadTdbah; + volatile u32 PadTdl; + volatile u32 Pad29; + volatile u32 PadTdh; + volatile u32 Pad30; + volatile u32 PadTdt; + volatile u32 Pad31; + volatile u32 PadTidv; + volatile u32 Pad32; + volatile u32 Tbt; + volatile u8 Pad33[0x0C]; + + volatile u32 Ait; + volatile u8 Pad34[0xA4]; + + volatile u32 Ftr[8]; + volatile u32 Fcr; + volatile u32 Pad35; + volatile u32 Trcr; + + volatile u8 Pad36[0xD4]; + + volatile u32 Vfta[(128)]; + volatile u8 Pad37[0x700]; + volatile u32 Circ; + volatile u8 Pad37a[0xFC]; + + volatile u32 Pba; + volatile u8 Pad38[0xFFC]; + + volatile u8 Pad39[0x8]; + volatile u32 Ert; + volatile u8 Pad40[0xf4]; + + volatile u8 Pad41[0x60]; + volatile u32 Fcrtl; + volatile u32 Pad42; + volatile u32 Fcrth; + volatile u8 Pad43[0x294]; + + volatile u8 Pad44[0x10]; + volatile u32 Rdfh; + volatile u32 Pad45; + volatile u32 Rdft; + volatile u32 Pad45a; + volatile u32 Rdfhs; + volatile u32 Pad45b; + volatile u32 Rdfts; + volatile u32 Pad45c; + volatile u32 Rdfpc; + volatile u8 Pad46[0x3cc]; + + volatile u32 Rdbal0; + volatile u32 Rdbah0; + volatile u32 Rdlen0; + volatile u32 Pad47; + volatile u32 Rdh0; + volatile u32 Pad48; + volatile u32 Rdt0; + volatile u32 Pad49; + volatile u32 Rdtr0; + volatile u32 Pad50; + volatile u32 Rxdctl; + volatile u32 Pad51; + volatile u32 Rddh0; + volatile u32 Pad52; + volatile u32 Rddt0; + volatile u8 Pad53[0x7C4]; + + volatile u32 Txdmac; + volatile u32 Pad54; + volatile u32 Ett; + volatile u8 Pad55[0x3f4]; + + volatile u8 Pad56[0x10]; + volatile u32 Tdfh; + volatile u32 Pad57; + volatile u32 Tdft; + volatile u32 Pad57a; + volatile u32 Tdfhs; + volatile u32 Pad57b; + volatile u32 Tdfts; + volatile u32 Pad57c; + volatile u32 Tdfpc; + volatile u8 Pad58[0x3cc]; + + volatile u32 Tdbal; + volatile u32 Tdbah; + volatile u32 Tdl; + volatile u32 Pad59; + volatile u32 Tdh; + volatile u32 Pad60; + volatile u32 Tdt; + volatile u32 Pad61; + volatile u32 Tidv; + volatile u32 Pad62; + volatile u32 Txdctl; + volatile u32 Pad63; + volatile u32 Tddh; + volatile u32 Pad64; + volatile u32 Tddt; + volatile u8 Pad65[0x7C4]; + + volatile u32 Crcerrs; + volatile u32 Algnerrc; + volatile u32 Symerrs; + volatile u32 Rxerrc; + volatile u32 Mpc; + volatile u32 Scc; + volatile u32 Ecol; + volatile u32 Mcc; + volatile u32 Latecol; + volatile u32 Pad66; + volatile u32 Colc; + volatile u32 Tuc; + volatile u32 Dc; + volatile u32 Tncrs; + volatile u32 Sec; + volatile u32 Cexterr; + volatile u32 Rlec; + volatile u32 Rutec; + volatile u32 Xonrxc; + volatile u32 Xontxc; + volatile u32 Xoffrxc; + volatile u32 Xofftxc; + volatile u32 Fcruc; + volatile u32 Prc64; + volatile u32 Prc127; + volatile u32 Prc255; + volatile u32 Prc511; + volatile u32 Prc1023; + volatile u32 Prc1522; + volatile u32 Gprc; + volatile u32 Bprc; + volatile u32 Mprc; + volatile u32 Gptc; + volatile u32 Pad67; + volatile u32 Gorl; + volatile u32 Gorh; + volatile u32 Gotl; + volatile u32 Goth; + volatile u8 Pad68[8]; + volatile u32 Rnbc; + volatile u32 Ruc; + volatile u32 Rfc; + volatile u32 Roc; + volatile u32 Rjc; + volatile u8 Pad69[0xC]; + volatile u32 Torl; + volatile u32 Torh; + volatile u32 Totl; + volatile u32 Toth; + volatile u32 Tpr; + volatile u32 Tpt; + volatile u32 Ptc64; + volatile u32 Ptc127; + volatile u32 Ptc255; + volatile u32 Ptc511; + volatile u32 Ptc1023; + volatile u32 Ptc1522; + volatile u32 Mptc; + volatile u32 Bptc; + + volatile u32 Tsctc; + volatile u32 Tsctfc; + volatile u8 Pad70[0x0F00]; + + volatile u32 Rxcsum; + volatile u8 Pad71[0x07FC]; + + volatile u32 Wuc; + volatile u32 Pad72; + volatile u32 Wufc; + volatile u32 Pad73; + volatile u32 Wus; + volatile u8 Pad74[0x24]; + volatile u32 Ipav; + volatile u32 Pad75; + IPAT_ENTRY Ipat[(4)]; + volatile u8 Pad76[0xA0]; + volatile u32 Wupl; + volatile u8 Pad77[0xFC]; + volatile u8 Wupm[0x80]; + volatile u8 Pad78[0x480]; + FFLT_ENTRY Fflt[(4)]; + volatile u8 Pad79[0x20E0]; + + volatile u32 PadRdfh; + volatile u32 Pad80; + volatile u32 PadRdft; + volatile u32 Pad81; + volatile u32 PadTdfh; + volatile u32 Pad82; + volatile u32 PadTdft; + volatile u8 Pad83[0xFE4]; + + FFMT_ENTRY Ffmt[(128)]; + volatile u8 Pad84[0x0400]; + FFVT_ENTRY Ffvt[(128)]; + + volatile u8 Pad85[0x6400]; + + volatile u32 Pbm[0x4000]; + +} E1000_REGISTERS, *PE1000_REGISTERS; + +typedef struct _OLD_REGISTERS { + + volatile u32 Ctrl; + volatile u32 Pad1; + volatile u32 Status; + volatile u32 Pad2; + volatile u32 Eecd; + volatile u32 Pad3; + volatile u32 Exct; + volatile u32 Pad4; + volatile u32 Mdic; + volatile u32 Pad5; + volatile u32 Fcal; + volatile u32 Fcah; + volatile u32 Fct; + volatile u32 Pad6; + + volatile u32 Vet; + volatile u32 Pad7; + + RECEIVE_ADDRESS_REGISTER_PAIR Rar[16]; + + volatile u32 Icr; + volatile u32 Pad8; + volatile u32 Ics; + volatile u32 Pad9; + volatile u32 Ims; + volatile u32 Pad10; + volatile u32 Imc; + volatile u8 Pad11[0x24]; + + volatile u32 Rctl; + volatile u32 Pad12; + volatile u32 Rdtr0; + volatile u32 Pad13; + volatile u32 Rdbal0; + volatile u32 Rdbah0; + volatile u32 Rdlen0; + volatile u32 Pad14; + volatile u32 Rdh0; + volatile u32 Pad15; + volatile u32 Rdt0; + volatile u32 Pad16; + volatile u32 Rdtr1; + volatile u32 Pad17; + volatile u32 Rdbal1; + volatile u32 Rdbah1; + volatile u32 Rdlen1; + volatile u32 Pad18; + volatile u32 Rdh1; + volatile u32 Pad19; + volatile u32 Rdt1; + volatile u8 Pad20[0x0C]; + volatile u32 Fcrth; + volatile u32 Pad21; + volatile u32 Fcrtl; + volatile u32 Pad22; + volatile u32 Fcttv; + volatile u32 Pad23; + volatile u32 Txcw; + volatile u32 Pad24; + volatile u32 Rxcw; + volatile u8 Pad25[0x7C]; + volatile u32 Mta[(128)]; + + volatile u32 Tctl; + volatile u32 Pad26; + volatile u32 Tqsal; + volatile u32 Tqsah; + volatile u32 Tipg; + volatile u32 Pad27; + volatile u32 Tqc; + volatile u32 Pad28; + volatile u32 Tdbal; + volatile u32 Tdbah; + volatile u32 Tdl; + volatile u32 Pad29; + volatile u32 Tdh; + volatile u32 Pad30; + volatile u32 Tdt; + volatile u32 Pad31; + volatile u32 Tidv; + volatile u32 Pad32; + volatile u32 Tbt; + volatile u8 Pad33[0x0C]; + + volatile u32 Ait; + volatile u8 Pad34[0xA4]; + + volatile u32 Ftr[8]; + volatile u32 Fcr; + volatile u32 Pad35; + volatile u32 Trcr; + + volatile u8 Pad36[0xD4]; + + volatile u32 Vfta[(128)]; + volatile u8 Pad37[0x700]; + volatile u32 Circ; + volatile u8 Pad37a[0xFC]; + + volatile u32 Pba; + volatile u8 Pad38[0xFFC]; + + volatile u8 Pad39[0x8]; + volatile u32 Ert; + volatile u8 Pad40[0x1C]; + volatile u32 Rxdctl; + volatile u8 Pad41[0xFD4]; + + volatile u32 Txdmac; + volatile u32 Pad42; + volatile u32 Ett; + volatile u8 Pad43[0x1C]; + volatile u32 Txdctl; + volatile u8 Pad44[0xFD4]; + + volatile u32 Crcerrs; + volatile u32 Algnerrc; + volatile u32 Symerrs; + volatile u32 Rxerrc; + volatile u32 Mpc; + volatile u32 Scc; + volatile u32 Ecol; + volatile u32 Mcc; + volatile u32 Latecol; + volatile u32 Pad45; + volatile u32 Colc; + volatile u32 Tuc; + volatile u32 Dc; + volatile u32 Tncrs; + volatile u32 Sec; + volatile u32 Cexterr; + volatile u32 Rlec; + volatile u32 Rutec; + volatile u32 Xonrxc; + volatile u32 Xontxc; + volatile u32 Xoffrxc; + volatile u32 Xofftxc; + volatile u32 Fcruc; + volatile u32 Prc64; + volatile u32 Prc127; + volatile u32 Prc255; + volatile u32 Prc511; + volatile u32 Prc1023; + volatile u32 Prc1522; + volatile u32 Gprc; + volatile u32 Bprc; + volatile u32 Mprc; + volatile u32 Gptc; + volatile u32 Pad46; + volatile u32 Gorl; + volatile u32 Gorh; + volatile u32 Gotl; + volatile u32 Goth; + volatile u8 Pad47[8]; + volatile u32 Rnbc; + volatile u32 Ruc; + volatile u32 Rfc; + volatile u32 Roc; + volatile u32 Rjc; + volatile u8 Pad48[0xC]; + volatile u32 Torl; + volatile u32 Torh; + volatile u32 Totl; + volatile u32 Toth; + volatile u32 Tpr; + volatile u32 Tpt; + volatile u32 Ptc64; + volatile u32 Ptc127; + volatile u32 Ptc255; + volatile u32 Ptc511; + volatile u32 Ptc1023; + volatile u32 Ptc1522; + volatile u32 Mptc; + volatile u32 Bptc; + + volatile u32 Tsctc; + volatile u32 Tsctfc; + volatile u8 Pad49[0x0F00]; + + volatile u32 Rxcsum; + volatile u8 Pad50[0x07FC]; + + volatile u32 Wuc; + volatile u32 Pad51; + volatile u32 Wufc; + volatile u32 Pad52; + volatile u32 Wus; + volatile u8 Pad53[0x24]; + volatile u32 Ipav; + volatile u32 Pad54; + IPAT_ENTRY Ipat[(4)]; + volatile u8 Pad55[0xA0]; + volatile u32 Wupl; + volatile u8 Pad56[0xFC]; + volatile u8 Wupm[0x80]; + volatile u8 Pad57[0x480]; + FFLT_ENTRY Fflt[(4)]; + volatile u8 Pad58[0x20E0]; + + volatile u32 Rdfh; + volatile u32 Pad59; + volatile u32 Rdft; + volatile u32 Pad60; + volatile u32 Tdfh; + volatile u32 Pad61; + volatile u32 Tdft; + volatile u32 Pad62; + volatile u32 Tdfhs; + volatile u32 Pad63; + volatile u32 Tdfts; + volatile u32 Pad64; + volatile u32 Tdfpc; + volatile u8 Pad65[0x0FCC]; + + FFMT_ENTRY Ffmt[(128)]; + volatile u8 Pad66[0x0400]; + FFVT_ENTRY Ffvt[(128)]; + + volatile u8 Pad67[0x6400]; + + volatile u32 Pbm[0x4000]; + +} OLD_REGISTERS, *POLD_REGISTERS; + +#define E1000_EEPROM_SWDPIN0 (0x00000001) +#define E1000_EEPROM_LED_LOGIC (0x0020) + +#define E1000_CTRL_FD (0x00000001) +#define E1000_CTRL_BEM (0x00000002) +#define E1000_CTRL_PRIOR (0x00000004) +#define E1000_CTRL_LRST (0x00000008) +#define E1000_CTRL_TME (0x00000010) +#define E1000_CTRL_SLE (0x00000020) +#define E1000_CTRL_ASDE (0x00000020) +#define E1000_CTRL_SLU (0x00000040) + +#define E1000_CTRL_ILOS (0x00000080) +#define E1000_CTRL_SPD_SEL (0x00000300) +#define E1000_CTRL_SPD_10 (0x00000000) +#define E1000_CTRL_SPD_100 (0x00000100) +#define E1000_CTRL_SPD_1000 (0x00000200) +#define E1000_CTRL_BEM32 (0x00000400) +#define E1000_CTRL_FRCSPD (0x00000800) +#define E1000_CTRL_FRCDPX (0x00001000) + +#define E1000_CTRL_SWDPIN0 (0x00040000) +#define E1000_CTRL_SWDPIN1 (0x00080000) +#define E1000_CTRL_SWDPIN2 (0x00100000) +#define E1000_CTRL_SWDPIN3 (0x00200000) +#define E1000_CTRL_SWDPIO0 (0x00400000) +#define E1000_CTRL_SWDPIO1 (0x00800000) +#define E1000_CTRL_SWDPIO2 (0x01000000) +#define E1000_CTRL_SWDPIO3 (0x02000000) +#define E1000_CTRL_RST (0x04000000) +#define E1000_CTRL_RFCE (0x08000000) +#define E1000_CTRL_TFCE (0x10000000) + +#define E1000_CTRL_RTE (0x20000000) +#define E1000_CTRL_VME (0x40000000) + +#define E1000_CTRL_PHY_RST (0x80000000) + +#define E1000_STATUS_FD (0x00000001) +#define E1000_STATUS_LU (0x00000002) +#define E1000_STATUS_TCKOK (0x00000004) +#define E1000_STATUS_RBCOK (0x00000008) +#define E1000_STATUS_TXOFF (0x00000010) +#define E1000_STATUS_TBIMODE (0x00000020) +#define E1000_STATUS_SPEED_10 (0x00000000) +#define E1000_STATUS_SPEED_100 (0x00000040) +#define E1000_STATUS_SPEED_1000 (0x00000080) +#define E1000_STATUS_ASDV (0x00000300) +#define E1000_STATUS_MTXCKOK (0x00000400) +#define E1000_STATUS_PCI66 (0x00000800) +#define E1000_STATUS_BUS64 (0x00001000) +#define E1000_STATUS_PCIX_MODE (0x00002000) +#define E1000_STATUS_PCIX_SPEED (0x0000C000) + +#define E1000_STATUS_PCIX_SPEED_66 (0x00000000) +#define E1000_STATUS_PCIX_SPEED_100 (0x00004000) +#define E1000_STATUS_PCIX_SPEED_133 (0x00008000) + +#define E1000_EESK (0x00000001) +#define E1000_EECS (0x00000002) +#define E1000_EEDI (0x00000004) +#define E1000_EEDO (0x00000008) +#define E1000_FLASH_WRITE_DIS (0x00000010) +#define E1000_FLASH_WRITE_EN (0x00000020) + +#define E1000_EXCTRL_GPI_EN0 (0x00000001) +#define E1000_EXCTRL_GPI_EN1 (0x00000002) +#define E1000_EXCTRL_GPI_EN2 (0x00000004) +#define E1000_EXCTRL_GPI_EN3 (0x00000008) +#define E1000_EXCTRL_SWDPIN4 (0x00000010) +#define E1000_EXCTRL_SWDPIN5 (0x00000020) +#define E1000_EXCTRL_SWDPIN6 (0x00000040) +#define E1000_EXCTRL_SWDPIN7 (0x00000080) +#define E1000_EXCTRL_SWDPIO4 (0x00000100) +#define E1000_EXCTRL_SWDPIO5 (0x00000200) +#define E1000_EXCTRL_SWDPIO6 (0x00000400) +#define E1000_EXCTRL_SWDPIO7 (0x00000800) +#define E1000_EXCTRL_ASDCHK (0x00001000) +#define E1000_EXCTRL_EE_RST (0x00002000) +#define E1000_EXCTRL_IPS (0x00004000) +#define E1000_EXCTRL_SPD_BYPS (0x00008000) + +#define E1000_MDI_WRITE (0x04000000) +#define E1000_MDI_READ (0x08000000) +#define E1000_MDI_READY (0x10000000) +#define E1000_MDI_INT (0x20000000) +#define E1000_MDI_ERR (0x40000000) + +#define E1000_RAH_RDR (0x40000000) +#define E1000_RAH_AV (0x80000000) + +#define E1000_ICR_TXDW (0x00000001) +#define E1000_ICR_TXQE (0x00000002) +#define E1000_ICR_LSC (0x00000004) +#define E1000_ICR_RXSEQ (0x00000008) +#define E1000_ICR_RXDMT0 (0x00000010) +#define E1000_ICR_RXDMT1 (0x00000020) +#define E1000_ICR_RXO (0x00000040) +#define E1000_ICR_RXT0 (0x00000080) +#define E1000_ICR_RXT1 (0x00000100) +#define E1000_ICR_MDAC (0x00000200) +#define E1000_ICR_RXCFG (0x00000400) +#define E1000_ICR_GPI_EN0 (0x00000800) +#define E1000_ICR_GPI_EN1 (0x00001000) +#define E1000_ICR_GPI_EN2 (0x00002000) +#define E1000_ICR_GPI_EN3 (0x00004000) + +#define E1000_ICS_TXDW E1000_ICR_TXDW +#define E1000_ICS_TXQE E1000_ICR_TXQE +#define E1000_ICS_LSC E1000_ICR_LSC +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 +#define E1000_ICS_RXDMT1 E1000_ICR_RXDMT1 +#define E1000_ICS_RXO E1000_ICR_RXO +#define E1000_ICS_RXT0 E1000_ICR_RXT0 +#define E1000_ICS_RXT1 E1000_ICR_RXT1 +#define E1000_ICS_MDAC E1000_ICR_MDAC +#define E1000_ICS_RXCFG E1000_ICR_RXCFG +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 + +#define E1000_IMS_TXDW E1000_ICR_TXDW +#define E1000_IMS_TXQE E1000_ICR_TXQE +#define E1000_IMS_LSC E1000_ICR_LSC +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 +#define E1000_IMS_RXDMT1 E1000_ICR_RXDMT1 +#define E1000_IMS_RXO E1000_ICR_RXO +#define E1000_IMS_RXT0 E1000_ICR_RXT0 +#define E1000_IMS_RXT1 E1000_ICR_RXT1 +#define E1000_IMS_MDAC E1000_ICR_MDAC +#define E1000_IMS_RXCFG E1000_ICR_RXCFG +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 + +#define E1000_IMC_TXDW E1000_ICR_TXDW +#define E1000_IMC_TXQE E1000_ICR_TXQE +#define E1000_IMC_LSC E1000_ICR_LSC +#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ +#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 +#define E1000_IMC_RXDMT1 E1000_ICR_RXDMT1 +#define E1000_IMC_RXO E1000_ICR_RXO +#define E1000_IMC_RXT0 E1000_ICR_RXT0 +#define E1000_IMC_RXT1 E1000_ICR_RXT1 +#define E1000_IMC_MDAC E1000_ICR_MDAC +#define E1000_IMC_RXCFG E1000_ICR_RXCFG +#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 +#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 +#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 +#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 + +#define E1000_TINT_RINT_PCI (E1000_TXDW|E1000_ICR_RXT0) +#define E1000_CAUSE_ERR (E1000_ICR_RXSEQ|E1000_ICR_RXO) + +#define E1000_RCTL_RST (0x00000001) +#define E1000_RCTL_EN (0x00000002) +#define E1000_RCTL_SBP (0x00000004) +#define E1000_RCTL_UPE (0x00000008) +#define E1000_RCTL_MPE (0x00000010) +#define E1000_RCTL_LPE (0x00000020) +#define E1000_RCTL_LBM_NO (0x00000000) +#define E1000_RCTL_LBM_MAC (0x00000040) +#define E1000_RCTL_LBM_SLP (0x00000080) +#define E1000_RCTL_LBM_TCVR (0x000000c0) +#define E1000_RCTL_RDMTS0_HALF (0x00000000) +#define E1000_RCTL_RDMTS0_QUAT (0x00000100) +#define E1000_RCTL_RDMTS0_EIGTH (0x00000200) +#define E1000_RCTL_RDMTS1_HALF (0x00000000) +#define E1000_RCTL_RDMTS1_QUAT (0x00000400) +#define E1000_RCTL_RDMTS1_EIGTH (0x00000800) +#define E1000_RCTL_MO_SHIFT 12 + +#define E1000_RCTL_MO_0 (0x00000000) +#define E1000_RCTL_MO_1 (0x00001000) +#define E1000_RCTL_MO_2 (0x00002000) +#define E1000_RCTL_MO_3 (0x00003000) + +#define E1000_RCTL_MDR (0x00004000) +#define E1000_RCTL_BAM (0x00008000) + +#define E1000_RCTL_SZ_2048 (0x00000000) +#define E1000_RCTL_SZ_1024 (0x00010000) +#define E1000_RCTL_SZ_512 (0x00020000) +#define E1000_RCTL_SZ_256 (0x00030000) + +#define E1000_RCTL_SZ_16384 (0x00010000) +#define E1000_RCTL_SZ_8192 (0x00020000) +#define E1000_RCTL_SZ_4096 (0x00030000) + +#define E1000_RCTL_VFE (0x00040000) + +#define E1000_RCTL_CFIEN (0x00080000) +#define E1000_RCTL_CFI (0x00100000) +#define E1000_RCTL_ISLE (0x00200000) + +#define E1000_RCTL_DPF (0x00400000) +#define E1000_RCTL_PMCF (0x00800000) + +#define E1000_RCTL_SISLH (0x01000000) + +#define E1000_RCTL_BSEX (0x02000000) +#define E1000_RDT0_DELAY (0x0000ffff) +#define E1000_RDT0_FPDB (0x80000000) + +#define E1000_RDT1_DELAY (0x0000ffff) +#define E1000_RDT1_FPDB (0x80000000) + +#define E1000_RDLEN0_LEN (0x0007ff80) + +#define E1000_RDLEN1_LEN (0x0007ff80) + +#define E1000_RDH0_RDH (0x0000ffff) + +#define E1000_RDH1_RDH (0x0000ffff) + +#define E1000_RDT0_RDT (0x0000ffff) + +#define E1000_FCRTH_RTH (0x0000FFF8) +#define E1000_FCRTH_XFCE (0x80000000) + +#define E1000_FCRTL_RTL (0x0000FFF8) +#define E1000_FCRTL_XONE (0x80000000) + +#define E1000_RXDCTL_PTHRESH 0x0000003F +#define E1000_RXDCTL_HTHRESH 0x00003F00 +#define E1000_RXDCTL_WTHRESH 0x003F0000 +#define E1000_RXDCTL_GRAN 0x01000000 + +#define E1000_TXDCTL_PTHRESH 0x000000FF +#define E1000_TXDCTL_HTHRESH 0x0000FF00 +#define E1000_TXDCTL_WTHRESH 0x00FF0000 +#define E1000_TXDCTL_GRAN 0x01000000 + +#define E1000_TXCW_FD (0x00000020) +#define E1000_TXCW_HD (0x00000040) +#define E1000_TXCW_PAUSE (0x00000080) +#define E1000_TXCW_ASM_DIR (0x00000100) +#define E1000_TXCW_PAUSE_MASK (0x00000180) +#define E1000_TXCW_RF (0x00003000) +#define E1000_TXCW_NP (0x00008000) +#define E1000_TXCW_CW (0x0000ffff) +#define E1000_TXCW_TXC (0x40000000) +#define E1000_TXCW_ANE (0x80000000) + +#define E1000_RXCW_CW (0x0000ffff) +#define E1000_RXCW_NC (0x04000000) +#define E1000_RXCW_IV (0x08000000) +#define E1000_RXCW_CC (0x10000000) +#define E1000_RXCW_C (0x20000000) +#define E1000_RXCW_SYNCH (0x40000000) +#define E1000_RXCW_ANC (0x80000000) + +#define E1000_TCTL_RST (0x00000001) +#define E1000_TCTL_EN (0x00000002) +#define E1000_TCTL_BCE (0x00000004) +#define E1000_TCTL_PSP (0x00000008) +#define E1000_TCTL_CT (0x00000ff0) +#define E1000_TCTL_COLD (0x003ff000) +#define E1000_TCTL_SWXOFF (0x00400000) +#define E1000_TCTL_PBE (0x00800000) +#define E1000_TCTL_RTLC (0x01000000) +#define E1000_TCTL_NRTU (0x02000000) + +#define E1000_TQSAL_TQSAL (0xffffffc0) +#define E1000_TQSAH_TQSAH (0xffffffff) + +#define E1000_TQC_SQ (0x00000001) +#define E1000_TQC_RQ (0x00000002) + +#define E1000_TDBAL_TDBAL (0xfffff000) +#define E1000_TDBAH_TDBAH (0xffffffff) + +#define E1000_TDL_LEN (0x0007ff80) + +#define E1000_TDH_TDH (0x0000ffff) + +#define E1000_TDT_TDT (0x0000ffff) + +#define E1000_RXCSUM_PCSS (0x000000ff) +#define E1000_RXCSUM_IPOFL (0x00000100) +#define E1000_RXCSUM_TUOFL (0x00000200) + +#define E1000_WUC_APME (0x00000001) +#define E1000_WUC_PME_EN (0x00000002) +#define E1000_WUC_PME_STATUS (0x00000004) +#define E1000_WUC_APMPME (0x00000008) + +#define E1000_WUFC_LNKC (0x00000001) +#define E1000_WUFC_MAG (0x00000002) +#define E1000_WUFC_EX (0x00000004) +#define E1000_WUFC_MC (0x00000008) +#define E1000_WUFC_BC (0x00000010) +#define E1000_WUFC_ARP (0x00000020) +#define E1000_WUFC_IP (0x00000040) +#define E1000_WUFC_FLX0 (0x00010000) +#define E1000_WUFC_FLX1 (0x00020000) +#define E1000_WUFC_FLX2 (0x00040000) +#define E1000_WUFC_FLX3 (0x00080000) +#define E1000_WUFC_ALL_FILTERS (0x000F007F) + +#define E1000_WUFC_FLX_OFFSET (16) +#define E1000_WUFC_FLX_FILTERS (0x000F0000) + +#define E1000_WUS_LNKC (0x00000001) +#define E1000_WUS_MAG (0x00000002) +#define E1000_WUS_EX (0x00000004) +#define E1000_WUS_MC (0x00000008) +#define E1000_WUS_BC (0x00000010) +#define E1000_WUS_ARP (0x00000020) +#define E1000_WUS_IP (0x00000040) +#define E1000_WUS_FLX0 (0x00010000) +#define E1000_WUS_FLX1 (0x00020000) +#define E1000_WUS_FLX2 (0x00040000) +#define E1000_WUS_FLX3 (0x00080000) +#define E1000_WUS_FLX_FILTERS (0x000F0000) + +#define E1000_WUPL_LENGTH_MASK (0x0FFF) + +#define E1000_MDALIGN (4096) + +#define EEPROM_READ_OPCODE (0x6) +#define EEPROM_WRITE_OPCODE (0x5) +#define EEPROM_ERASE_OPCODE (0x7) +#define EEPROM_EWEN_OPCODE (0x13) +#define EEPROM_EWDS_OPCODE (0x10) + +#define EEPROM_INIT_CONTROL1_REG (0x000A) +#define EEPROM_INIT_CONTROL2_REG (0x000F) +#define EEPROM_CHECKSUM_REG (0x003F) + +#define EEPROM_WORD0A_ILOS (0x0010) +#define EEPROM_WORD0A_SWDPIO (0x01E0) +#define EEPROM_WORD0A_LRST (0x0200) +#define EEPROM_WORD0A_FD (0x0400) +#define EEPROM_WORD0A_66MHZ (0x0800) + +#define EEPROM_WORD0F_PAUSE_MASK (0x3000) +#define EEPROM_WORD0F_PAUSE (0x1000) +#define EEPROM_WORD0F_ASM_DIR (0x2000) +#define EEPROM_WORD0F_ANE (0x0800) +#define EEPROM_WORD0F_SWPDIO_EXT (0x00F0) + +#define EEPROM_SUM (0xBABA) + +#define EEPROM_NODE_ADDRESS_BYTE_0 (0) +#define EEPROM_PBA_BYTE_1 (8) + +#define EEPROM_WORD_SIZE (64) + +#define NODE_ADDRESS_SIZE (6) +#define PBA_SIZE (4) + +#define E1000_COLLISION_THRESHOLD 16 +#define E1000_CT_SHIFT 4 + +#define E1000_FDX_COLLISION_DISTANCE 64 +#define E1000_HDX_COLLISION_DISTANCE 64 +#define E1000_GB_HDX_COLLISION_DISTANCE 512 +#define E1000_COLD_SHIFT 12 + +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +#define DEFAULT_WSMN_TIPG_IPGT 10 +#define DEFAULT_LVGD_TIPG_IPGT_FIBER 6 +#define DEFAULT_LVGD_TIPG_IPGT_COPPER 8 + +#define E1000_TIPG_IPGT_MASK 0x000003FF +#define E1000_TIPG_IPGR1_MASK 0x000FFC00 +#define E1000_TIPG_IPGR2_MASK 0x3FF00000 + +#define DEFAULT_WSMN_TIPG_IPGR1 2 +#define DEFAULT_LVGD_TIPG_IPGR1 8 +#define E1000_TIPG_IPGR1_SHIFT 10 + +#define DEFAULT_WSMN_TIPG_IPGR2 10 +#define DEFAULT_LVGD_TIPG_IPGR2 6 +#define E1000_TIPG_IPGR2_SHIFT 20 + +#define E1000_TXDMAC_DPP 0x00000001 + +#define E1000_PBA_16K (0x0010) +#define E1000_PBA_24K (0x0018) +#define E1000_PBA_40K (0x0028) +#define E1000_PBA_48K (0x0030) + +#define FLOW_CONTROL_ADDRESS_LOW (0x00C28001) +#define FLOW_CONTROL_ADDRESS_HIGH (0x00000100) +#define FLOW_CONTROL_TYPE (0x8808) + +#define FC_DEFAULT_HI_THRESH (0x8000) +#define FC_DEFAULT_LO_THRESH (0x4000) +#define FC_DEFAULT_TX_TIMER (0x100) + +#define PAUSE_SHIFT 5 + +#define SWDPIO_SHIFT 17 + +#define SWDPIO__EXT_SHIFT 4 + +#define ILOS_SHIFT 3 + +#define MDI_REGADD_SHIFT 16 + +#define MDI_PHYADD_SHIFT 21 + +#define RECEIVE_BUFFER_ALIGN_SIZE (256) + +#define LINK_UP_TIMEOUT 500 + +#define E1000_TX_BUFFER_SIZE ((u32)1514) + +#define E1000_MIN_SIZE_OF_RECEIVE_BUFFERS (2048) + +#define CARRIER_EXTENSION 0x0F + +#define TBI_ACCEPT(RxErrors, LastByteInFrame, HwFrameLength) (Adapter->TbiCompatibilityOn && (((RxErrors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE)&& ((LastByteInFrame) == CARRIER_EXTENSION) && ((HwFrameLength) > 64) && ((HwFrameLength) <= Adapter->MaxFrameSize+1)) + +#define E1000_WAIT_PERIOD 10 + +#endif /* _EM_FXHW_H_ */ + diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h new file mode 100644 index 0000000..6097b51 --- /dev/null +++ b/sys/dev/em/if_em_osdep.h @@ -0,0 +1,95 @@ +/************************************************************************** +************************************************************************** + +Copyright (c) 2001 Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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$ +*************************************************************************** +***************************************************************************/ + +#ifndef _FREEBSD_OS_H_ +#define _FREEBSD_OS_H_ + +#include <sys/types.h> + +#define ASSERT(x) if(!(x)) panic("EM: x") + +/* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */ +#define DelayInMicroseconds(x) DELAY(x) +#define DelayInMilliseconds(x) DELAY(1000*(x)) + +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +typedef struct _E1000_64_BIT_PHYSICAL_ADDRESS { + u32 Lo32; + u32 Hi32; +} E1000_64_BIT_PHYSICAL_ADDRESS, *PE1000_64_BIT_PHYSICAL_ADDRESS; + +#define IN +#define OUT +#define STATIC static + +#define MSGOUT(S, A, B) printf(S "\n", A, B) +#define DEBUGFUNC(F) DEBUGOUT(F); +#if 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) + #define DEBUGOUT3(S,A,B,C) printf(S "\n",A,B,C) + #define DEBUGOUT7(S,A,B,C,D,E,F,G) printf(S "\n",A,B,C,D,E,F,G) +#else + #define DEBUGOUT(S) + #define DEBUGOUT1(S,A) + #define DEBUGOUT2(S,A,B) + #define DEBUGOUT3(S,A,B,C) + #define DEBUGOUT7(S,A,B,C,D,E,F,G) +#endif + + +#define E1000_READ_REG(reg) \ + bus_space_read_4(Adapter->bus_space_tag, Adapter->bus_space_handle, \ + (Adapter->MacType >= MAC_LIVENGOOD)?offsetof(E1000_REGISTERS, reg): \ + offsetof(OLD_REGISTERS, reg)) + +#define E1000_WRITE_REG(reg, value) \ + bus_space_write_4(Adapter->bus_space_tag, Adapter->bus_space_handle, \ + (Adapter->MacType >= MAC_LIVENGOOD)?offsetof(E1000_REGISTERS, reg): \ + offsetof(OLD_REGISTERS, reg), value) + +#define WritePciConfigWord(Reg, PValue) pci_write_config(Adapter->dev, Reg, *PValue, 2); + + +#include <dev/em/if_em.h> + +#endif /* _FREEBSD_OS_H_ */ + diff --git a/sys/dev/em/if_em_phy.c b/sys/dev/em/if_em_phy.c new file mode 100644 index 0000000..470e516 --- /dev/null +++ b/sys/dev/em/if_em_phy.c @@ -0,0 +1,1223 @@ +/************************************************************************* +************************************************************************** +Copyright (c) 2001 Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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$ +*************************************************************************** +**************************************************************************/ +/* +* Workfile: phy.c +* Date: 9/25/01 2:40p +* Revision: 37 +*/ + +#include <dev/em/if_em_fxhw.h> +#include <dev/em/if_em_phy.h> + +static void em_mii_shift_out_phy_data(struct adapter *Adapter, + u32 Data, u16 Count); +static void em_raise_mdc_clock(struct adapter *Adapter, + + u32 * CtrlRegValue); +static void em_lower_mdc_clock(struct adapter *Adapter, + + u32 * CtrlRegValue); +static u16 em_mii_shift_in_phy_data(struct adapter *Adapter); +static u8 em_phy_setup_auto_neg_advertisement(struct adapter *Adapter); +static void em_phy_force_speed_and_duplex(struct adapter *Adapter); + +#define GOOD_MII_IF 0 + +u16 em_read_phy_register(struct adapter *Adapter, + u32 RegAddress, u32 PhyAddress) + { + u32 i; + u32 Data = 0; + u32 Command = 0; + + ASSERT(RegAddress <= MAX_PHY_REG_ADDRESS); + + if (Adapter->MacType > MAC_LIVENGOOD) { + + Command = ((RegAddress << MDI_REGADD_SHIFT) | + (PhyAddress << MDI_PHYADD_SHIFT) | + (E1000_MDI_READ)); + + E1000_WRITE_REG(Mdic, Command); + + for (i = 0; i < 32; i++) { + DelayInMicroseconds(10); + + Data = E1000_READ_REG(Mdic); + + if (Data & E1000_MDI_READY) + break; + } + } else { + + em_mii_shift_out_phy_data(Adapter, PHY_PREAMBLE, + PHY_PREAMBLE_SIZE); + + Command = ((RegAddress) | + (PhyAddress << 5) | + (PHY_OP_READ << 10) | (PHY_SOF << 12)); + + em_mii_shift_out_phy_data(Adapter, Command, 14); + + Data = (u32) em_mii_shift_in_phy_data(Adapter); + } + + ASSERT(!(Data & E1000_MDI_ERR)); + + return ((u16) Data); +} + +void em_write_phy_register(struct adapter *Adapter, + u32 RegAddress, u32 PhyAddress, u16 Data) + { + u32 i; + u32 Command = 0; + u32 MdicRegValue; + + ASSERT(RegAddress <= MAX_PHY_REG_ADDRESS); + + if (Adapter->MacType > MAC_LIVENGOOD) { + + Command = (((u32) Data) | + (RegAddress << MDI_REGADD_SHIFT) | + (PhyAddress << MDI_PHYADD_SHIFT) | + (E1000_MDI_WRITE)); + + E1000_WRITE_REG(Mdic, Command); + + for (i = 0; i < 10; i++) { + DelayInMicroseconds(10); + + MdicRegValue = E1000_READ_REG(Mdic); + + if (MdicRegValue & E1000_MDI_READY) + break; + } + + } else { + + em_mii_shift_out_phy_data(Adapter, PHY_PREAMBLE, + PHY_PREAMBLE_SIZE); + + Command = ((PHY_TURNAROUND) | + (RegAddress << 2) | + (PhyAddress << 7) | + (PHY_OP_WRITE << 12) | (PHY_SOF << 14)); + Command <<= 16; + Command |= ((u32) Data); + + em_mii_shift_out_phy_data(Adapter, Command, 32); + } + + return; +} + +static u16 em_mii_shift_in_phy_data(struct adapter *Adapter) + { + u32 CtrlRegValue; + u16 Data = 0; + u8 i; + + CtrlRegValue = E1000_READ_REG(Ctrl); + + CtrlRegValue &= ~E1000_CTRL_MDIO_DIR; + CtrlRegValue &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(Ctrl, CtrlRegValue); + + em_raise_mdc_clock(Adapter, &CtrlRegValue); + em_lower_mdc_clock(Adapter, &CtrlRegValue); + + for (Data = 0, i = 0; i < 16; i++) { + Data = Data << 1; + em_raise_mdc_clock(Adapter, &CtrlRegValue); + + CtrlRegValue = E1000_READ_REG(Ctrl); + + if (CtrlRegValue & E1000_CTRL_MDIO) + Data |= 1; + + em_lower_mdc_clock(Adapter, &CtrlRegValue); + } + + em_raise_mdc_clock(Adapter, &CtrlRegValue); + em_lower_mdc_clock(Adapter, &CtrlRegValue); + + CtrlRegValue &= ~E1000_CTRL_MDIO; + + return (Data); +} + +static void em_mii_shift_out_phy_data(struct adapter *Adapter, + u32 Data, u16 Count) + { + u32 CtrlRegValue; + u32 Mask; + + if (Count > 32) + ASSERT(0); + + Mask = 0x01; + Mask <<= (Count - 1); + + CtrlRegValue = E1000_READ_REG(Ctrl); + + CtrlRegValue |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); + + while (Mask) { + + if (Data & Mask) + CtrlRegValue |= E1000_CTRL_MDIO; + else + CtrlRegValue &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(Ctrl, CtrlRegValue); + + DelayInMicroseconds(2); + + em_raise_mdc_clock(Adapter, &CtrlRegValue); + em_lower_mdc_clock(Adapter, &CtrlRegValue); + + Mask = Mask >> 1; + } + + CtrlRegValue &= ~E1000_CTRL_MDIO; +} + +static void em_raise_mdc_clock(struct adapter *Adapter, u32 * CtrlRegValue) + { + + E1000_WRITE_REG(Ctrl, (*CtrlRegValue | E1000_CTRL_MDC)); + + DelayInMicroseconds(2); +} + +static void em_lower_mdc_clock(struct adapter *Adapter, u32 * CtrlRegValue) + { + + E1000_WRITE_REG(Ctrl, (*CtrlRegValue & ~E1000_CTRL_MDC)); + + DelayInMicroseconds(2); +} + +void em_phy_hardware_reset(struct adapter *Adapter) + { + u32 ExtCtrlRegValue, CtrlRegValue; + + DEBUGFUNC("em_phy_hardware_reset") + + DEBUGOUT("Resetting Phy...\n"); + + if (Adapter->MacType > MAC_LIVENGOOD) { + + CtrlRegValue = E1000_READ_REG(Ctrl); + + CtrlRegValue |= E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(Ctrl, CtrlRegValue); + + DelayInMilliseconds(20); + + CtrlRegValue &= ~E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(Ctrl, CtrlRegValue); + + DelayInMilliseconds(20); + } else { + + ExtCtrlRegValue = E1000_READ_REG(Exct); + + ExtCtrlRegValue |= E1000_CTRL_PHY_RESET_DIR4; + + E1000_WRITE_REG(Exct, ExtCtrlRegValue); + + DelayInMilliseconds(20); + + ExtCtrlRegValue = E1000_READ_REG(Exct); + + ExtCtrlRegValue &= ~E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(Exct, ExtCtrlRegValue); + + DelayInMilliseconds(20); + + ExtCtrlRegValue = E1000_READ_REG(Exct); + + ExtCtrlRegValue |= E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(Exct, ExtCtrlRegValue); + + DelayInMilliseconds(20); + } + + return; +} + +u8 em_phy_reset(struct adapter * Adapter) + { + u16 RegData; + u16 i; + + DEBUGFUNC("em_phy_reset") + + RegData = em_read_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress); + + RegData |= MII_CR_RESET; + + em_write_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress, RegData); + + i = 0; + while ((RegData & MII_CR_RESET) && i++ < 500) { + RegData = em_read_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress); + DelayInMicroseconds(1); + } + + if (i >= 500) { + DEBUGOUT("Timeout waiting for PHY to reset.\n"); + return 0; + } + + return 1; +} + +u8 em_phy_setup(struct adapter * Adapter, u32 DeviceControlReg) + { + u16 MiiCtrlReg, MiiStatusReg; + u16 PhySpecCtrlReg; + u16 MiiAutoNegAdvertiseReg, Mii1000TCtrlReg; + u16 i, Data; + u16 AutoNegHwSetting; + u16 AutoNegFCSetting; + u8 RestartAutoNeg = 0; + u8 ForceAutoNegRestart = 0; + + DEBUGFUNC("em_phy_setup") + + ASSERT(Adapter->MacType >= MAC_LIVENGOOD); + + if (Adapter->MacType > MAC_WAINWRIGHT) { + DeviceControlReg |= (E1000_CTRL_ASDE | E1000_CTRL_SLU); + E1000_WRITE_REG(Ctrl, DeviceControlReg); + } else { + DeviceControlReg |= (E1000_CTRL_FRCSPD | + E1000_CTRL_FRCDPX | E1000_CTRL_SLU); + E1000_WRITE_REG(Ctrl, DeviceControlReg); + + if (Adapter->MacType == MAC_LIVENGOOD) + em_phy_hardware_reset(Adapter); + } + + Adapter->PhyAddress = em_auto_detect_gigabit_phy(Adapter); + + if (Adapter->PhyAddress > MAX_PHY_REG_ADDRESS) { + + DEBUGOUT + ("em_phy_setup failure, did not detect valid phy.\n"); + return (0); + } + + DEBUGOUT1("Phy ID = %x \n", Adapter->PhyId); + + MiiCtrlReg = em_read_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress); + + DEBUGOUT1("MII Ctrl Reg contents = %x\n", MiiCtrlReg); + + if (!(MiiCtrlReg & MII_CR_AUTO_NEG_EN)) + ForceAutoNegRestart = 1; + + MiiCtrlReg &= ~(MII_CR_ISOLATE); + + em_write_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress, MiiCtrlReg); + + Data = em_read_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + + Data |= PXN_PSCR_ASSERT_CRS_ON_TX; + + DEBUGOUT1("Paxson PSCR: %x \n", Data); + + em_write_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress, Data); + + Data = em_read_phy_register(Adapter, + PXN_EXT_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + + Data |= PXN_EPSCR_TX_CLK_25; + + em_write_phy_register(Adapter, + PXN_EXT_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress, Data); + + MiiAutoNegAdvertiseReg = em_read_phy_register(Adapter, + PHY_AUTONEG_ADVERTISEMENT, + Adapter->PhyAddress); + + AutoNegHwSetting = (MiiAutoNegAdvertiseReg >> 5) & 0xF; + + Mii1000TCtrlReg = em_read_phy_register(Adapter, + PHY_1000T_CTRL_REG, + Adapter->PhyAddress); + + AutoNegHwSetting |= ((Mii1000TCtrlReg & 0x0300) >> 4); + + AutoNegFCSetting = ((MiiAutoNegAdvertiseReg & 0x0C00) >> 10); + + Adapter->AutoNegAdvertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; + + if (Adapter->AutoNegAdvertised == 0) + Adapter->AutoNegAdvertised = + AUTONEG_ADVERTISE_SPEED_DEFAULT; + + if (!ForceAutoNegRestart && Adapter->AutoNeg && + (Adapter->AutoNegAdvertised == AutoNegHwSetting) && + (Adapter->FlowControl == AutoNegFCSetting)) { + DEBUGOUT("No overrides - Reading MII Status Reg..\n"); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + DEBUGOUT1("MII Status Reg contents = %x\n", MiiStatusReg); + + if (MiiStatusReg & MII_SR_LINK_STATUS) { + Data = em_read_phy_register(Adapter, + PXN_PHY_SPEC_STAT_REG, + Adapter->PhyAddress); + DEBUGOUT1 + ("Paxson Phy Specific Status Reg contents = %x\n", + Data); + + if (Adapter->MacType > MAC_WAINWRIGHT) + em_configure_collision_distance(Adapter); + else + em_configure_mac_to_phy_settings(Adapter, + Data); + + em_config_flow_control_after_link_up(Adapter); + + return (1); + } + } + + PhySpecCtrlReg = em_read_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + + PhySpecCtrlReg &= ~PXN_PSCR_AUTO_X_MODE; + + switch (Adapter->MdiX) { + case 1: + PhySpecCtrlReg |= PXN_PSCR_MDI_MANUAL_MODE; + break; + case 2: + PhySpecCtrlReg |= PXN_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + PhySpecCtrlReg |= PXN_PSCR_AUTO_X_1000T; + break; + case 0: + default: + PhySpecCtrlReg |= PXN_PSCR_AUTO_X_MODE; + break; + } + + em_write_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress, PhySpecCtrlReg); + + PhySpecCtrlReg = em_read_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + + PhySpecCtrlReg &= ~PXN_PSCR_POLARITY_REVERSAL; + + if (Adapter->DisablePolarityCorrection == 1) + PhySpecCtrlReg |= PXN_PSCR_POLARITY_REVERSAL; + + em_write_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress, PhySpecCtrlReg); + + if (Adapter->AutoNeg) { + DEBUGOUT + ("Livengood - Reconfiguring auto-neg advertisement params\n"); + RestartAutoNeg = + em_phy_setup_auto_neg_advertisement(Adapter); + } else { + DEBUGOUT("Livengood - Forcing speed and duplex\n"); + em_phy_force_speed_and_duplex(Adapter); + } + + if (RestartAutoNeg) { + DEBUGOUT("Restarting Auto-Neg\n"); + + MiiCtrlReg = em_read_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress); + + MiiCtrlReg |= + (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + + em_write_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress, MiiCtrlReg); + + if (Adapter->WaitAutoNegComplete) + em_wait_for_auto_neg(Adapter); + + } + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + DEBUGOUT1 + ("Checking for link status - MII Status Reg contents = %x\n", + MiiStatusReg); + + for (i = 0; i < 10; i++) { + if (MiiStatusReg & MII_SR_LINK_STATUS) { + break; + } + DelayInMicroseconds(10); + DEBUGOUT(". "); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + } + + if (MiiStatusReg & MII_SR_LINK_STATUS) { + + Data = em_read_phy_register(Adapter, + PXN_PHY_SPEC_STAT_REG, + Adapter->PhyAddress); + + DEBUGOUT1("Paxson Phy Specific Status Reg contents = %x\n", + Data); + + if (Adapter->MacType > MAC_WAINWRIGHT) + em_configure_collision_distance(Adapter); + else + em_configure_mac_to_phy_settings(Adapter, Data); + + em_config_flow_control_after_link_up(Adapter); + + DEBUGOUT("Valid link established!!!\n"); + } else { + DEBUGOUT("Unable to establish link!!!\n"); + } + + return (1); +} + +u8 em_phy_setup_auto_neg_advertisement(struct adapter * Adapter) + { + u16 MiiAutoNegAdvertiseReg, Mii1000TCtrlReg; + + DEBUGFUNC("em_phy_setup_auto_neg_advertisement") + + MiiAutoNegAdvertiseReg = em_read_phy_register(Adapter, + PHY_AUTONEG_ADVERTISEMENT, + Adapter-> + PhyAddress); + + Mii1000TCtrlReg = em_read_phy_register(Adapter, + PHY_1000T_CTRL_REG, + Adapter->PhyAddress); + + MiiAutoNegAdvertiseReg &= ~REG4_SPEED_MASK; + Mii1000TCtrlReg &= ~REG9_SPEED_MASK; + + DEBUGOUT1("AutoNegAdvertised %x\n", Adapter->AutoNegAdvertised); + + if (Adapter->AutoNegAdvertised & ADVERTISE_10_HALF) { + DEBUGOUT("Advertise 10mb Half duplex\n"); + MiiAutoNegAdvertiseReg |= NWAY_AR_10T_HD_CAPS; + } + + if (Adapter->AutoNegAdvertised & ADVERTISE_10_FULL) { + DEBUGOUT("Advertise 10mb Full duplex\n"); + MiiAutoNegAdvertiseReg |= NWAY_AR_10T_FD_CAPS; + } + + if (Adapter->AutoNegAdvertised & ADVERTISE_100_HALF) { + DEBUGOUT("Advertise 100mb Half duplex\n"); + MiiAutoNegAdvertiseReg |= NWAY_AR_100TX_HD_CAPS; + } + + if (Adapter->AutoNegAdvertised & ADVERTISE_100_FULL) { + DEBUGOUT("Advertise 100mb Full duplex\n"); + MiiAutoNegAdvertiseReg |= NWAY_AR_100TX_FD_CAPS; + } + + if (Adapter->AutoNegAdvertised & ADVERTISE_1000_HALF) { + DEBUGOUT + ("Advertise 1000mb Half duplex requested, request denied!\n"); + } + + if (Adapter->AutoNegAdvertised & ADVERTISE_1000_FULL) { + DEBUGOUT("Advertise 1000mb Full duplex\n"); + Mii1000TCtrlReg |= CR_1000T_FD_CAPS; + } + + switch (Adapter->FlowControl) { + case FLOW_CONTROL_NONE: + + MiiAutoNegAdvertiseReg &= + ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + + break; + + case FLOW_CONTROL_RECEIVE_PAUSE: + + MiiAutoNegAdvertiseReg |= + (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + + break; + + case FLOW_CONTROL_TRANSMIT_PAUSE: + + MiiAutoNegAdvertiseReg |= NWAY_AR_ASM_DIR; + MiiAutoNegAdvertiseReg &= ~NWAY_AR_PAUSE; + + break; + + case FLOW_CONTROL_FULL: + + MiiAutoNegAdvertiseReg |= + (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + + break; + + default: + + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + em_write_phy_register(Adapter, + PHY_AUTONEG_ADVERTISEMENT, + Adapter->PhyAddress, MiiAutoNegAdvertiseReg); + + DEBUGOUT1("Auto-Neg Advertising %x\n", MiiAutoNegAdvertiseReg); + + em_write_phy_register(Adapter, + PHY_1000T_CTRL_REG, + Adapter->PhyAddress, Mii1000TCtrlReg); + return (1); +} + +static void em_phy_force_speed_and_duplex(struct adapter *Adapter) + { + u16 MiiCtrlReg; + u16 MiiStatusReg; + u16 PhyData; + u16 i; + u32 TctlReg; + u32 DeviceCtrlReg; + u32 Shift32; + + DEBUGFUNC("em_phy_force_speed_and_duplex") + + Adapter->FlowControl = FLOW_CONTROL_NONE; + + DEBUGOUT1("Adapter->FlowControl = %d\n", Adapter->FlowControl); + + DeviceCtrlReg = E1000_READ_REG(Ctrl); + + DeviceCtrlReg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + DeviceCtrlReg &= ~(DEVICE_SPEED_MASK); + + DeviceCtrlReg &= ~E1000_CTRL_ASDE; + + MiiCtrlReg = em_read_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress); + + MiiCtrlReg &= ~MII_CR_AUTO_NEG_EN; + + if (Adapter->ForcedSpeedDuplex == FULL_100 || + Adapter->ForcedSpeedDuplex == FULL_10) { + + DeviceCtrlReg |= E1000_CTRL_FD; + MiiCtrlReg |= MII_CR_FULL_DUPLEX; + + DEBUGOUT("Full Duplex\n"); + } else { + + DeviceCtrlReg &= ~E1000_CTRL_FD; + MiiCtrlReg &= ~MII_CR_FULL_DUPLEX; + + DEBUGOUT("Half Duplex\n"); + } + + if (Adapter->ForcedSpeedDuplex == FULL_100 || + Adapter->ForcedSpeedDuplex == HALF_100) { + + DeviceCtrlReg |= E1000_CTRL_SPD_100; + MiiCtrlReg |= MII_CR_SPEED_100; + MiiCtrlReg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + + DEBUGOUT("Forcing 100mb "); + } else { + + DeviceCtrlReg &= + ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + MiiCtrlReg |= MII_CR_SPEED_10; + MiiCtrlReg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + + DEBUGOUT("Forcing 10mb "); + } + + TctlReg = E1000_READ_REG(Tctl); + DEBUGOUT1("TctlReg = %x\n", TctlReg); + + if (!(MiiCtrlReg & MII_CR_FULL_DUPLEX)) { + + TctlReg &= ~E1000_TCTL_COLD; + Shift32 = E1000_HDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + } else { + + TctlReg &= ~E1000_TCTL_COLD; + Shift32 = E1000_FDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + } + + E1000_WRITE_REG(Tctl, TctlReg); + + E1000_WRITE_REG(Ctrl, DeviceCtrlReg); + + PhyData = em_read_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + + PhyData &= ~PXN_PSCR_AUTO_X_MODE; + + em_write_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress, PhyData); + + DEBUGOUT1("Paxson PSCR: %x \n", PhyData); + + MiiCtrlReg |= MII_CR_RESET; + + em_write_phy_register(Adapter, + PHY_MII_CTRL_REG, + Adapter->PhyAddress, MiiCtrlReg); + + if (Adapter->WaitAutoNegComplete) { + + DEBUGOUT("Waiting for forced speed/duplex link.\n"); + MiiStatusReg = 0; + +#define PHY_WAIT_FOR_FORCED_TIME 20 + + for (i = 20; i > 0; i--) { + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter-> + PhyAddress); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter-> + PhyAddress); + + if (MiiStatusReg & MII_SR_LINK_STATUS) { + break; + } + DelayInMilliseconds(100); + } + + if (i == 0) { + + em_pxn_phy_reset_dsp(Adapter); + } + + for (i = 20; i > 0; i--) { + if (MiiStatusReg & MII_SR_LINK_STATUS) { + break; + } + + DelayInMilliseconds(100); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter-> + PhyAddress); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter-> + PhyAddress); + + } + } + + PhyData = em_read_phy_register(Adapter, + PXN_EXT_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + + PhyData |= PXN_EPSCR_TX_CLK_25; + + em_write_phy_register(Adapter, + PXN_EXT_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress, PhyData); + + PhyData = em_read_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + + PhyData |= PXN_PSCR_ASSERT_CRS_ON_TX; + + em_write_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress, PhyData); + DEBUGOUT1("After force, Paxson Phy Specific Ctrl Reg = %4x\r\n", + PhyData); + + return; +} + +void em_configure_mac_to_phy_settings(struct adapter *Adapter, + u16 MiiRegisterData) + { + u32 DeviceCtrlReg, TctlReg; + u32 Shift32; + + DEBUGFUNC("em_configure_mac_to_phy_settings") + + TctlReg = E1000_READ_REG(Tctl); + DEBUGOUT1("TctlReg = %x\n", TctlReg); + + DeviceCtrlReg = E1000_READ_REG(Ctrl); + + DeviceCtrlReg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + DeviceCtrlReg &= ~(DEVICE_SPEED_MASK); + + DEBUGOUT1("MII Register Data = %x\r\n", MiiRegisterData); + + DeviceCtrlReg &= ~E1000_CTRL_ILOS; + + if (MiiRegisterData & PXN_PSSR_DPLX) { + DeviceCtrlReg |= E1000_CTRL_FD; + + TctlReg &= ~E1000_TCTL_COLD; + Shift32 = E1000_FDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + } else { + DeviceCtrlReg &= ~E1000_CTRL_FD; + + if ((MiiRegisterData & PXN_PSSR_SPEED) == PXN_PSSR_1000MBS) { + TctlReg &= ~E1000_TCTL_COLD; + Shift32 = E1000_GB_HDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + + TctlReg |= E1000_TCTL_PBE; + + } else { + TctlReg &= ~E1000_TCTL_COLD; + Shift32 = E1000_HDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + } + } + + if ((MiiRegisterData & PXN_PSSR_SPEED) == PXN_PSSR_1000MBS) + DeviceCtrlReg |= E1000_CTRL_SPD_1000; + else if ((MiiRegisterData & PXN_PSSR_SPEED) == PXN_PSSR_100MBS) + DeviceCtrlReg |= E1000_CTRL_SPD_100; + else + DeviceCtrlReg &= + ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + + E1000_WRITE_REG(Tctl, TctlReg); + + E1000_WRITE_REG(Ctrl, DeviceCtrlReg); + + return; +} + +void em_configure_collision_distance(struct adapter *Adapter) + { + u32 TctlReg; + u16 Speed; + u16 Duplex; + u32 Shift32; + + DEBUGFUNC("em_configure_collision_distance") + + em_get_speed_and_duplex(Adapter, &Speed, &Duplex); + + TctlReg = E1000_READ_REG(Tctl); + DEBUGOUT1("TctlReg = %x\n", TctlReg); + + TctlReg &= ~E1000_TCTL_COLD; + + if (Duplex == FULL_DUPLEX) { + + Shift32 = E1000_FDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + } else { + + if (Speed == SPEED_1000) { + Shift32 = E1000_GB_HDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + + TctlReg |= E1000_TCTL_PBE; + + } else { + Shift32 = E1000_HDX_COLLISION_DISTANCE; + Shift32 <<= E1000_COLD_SHIFT; + TctlReg |= Shift32; + } + } + + E1000_WRITE_REG(Tctl, TctlReg); + + return; +} + +void em_display_mii_contents(struct adapter *Adapter, u8 PhyAddress) + { + u16 Data, PhyIDHi, PhyIDLo; + u32 PhyID; + + DEBUGFUNC("em_display_mii_contents") + + DEBUGOUT1("Adapter Base Address = %x\n", + Adapter->HardwareVirtualAddress); + + Data = em_read_phy_register(Adapter, PHY_MII_CTRL_REG, PhyAddress); + + DEBUGOUT1("MII Ctrl Reg contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, PhyAddress); + + Data = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, PhyAddress); + + DEBUGOUT1("MII Status Reg contents = %x\n", Data); + + PhyIDHi = em_read_phy_register(Adapter, + PHY_PHY_ID_REG1, PhyAddress); + + DelayInMicroseconds(2); + + PhyIDLo = em_read_phy_register(Adapter, + PHY_PHY_ID_REG2, PhyAddress); + + PhyID = (PhyIDLo | (PhyIDHi << 16)) & PHY_REVISION_MASK; + + DEBUGOUT1("Phy ID = %x \n", PhyID); + + Data = em_read_phy_register(Adapter, + PHY_AUTONEG_ADVERTISEMENT, PhyAddress); + + DEBUGOUT1("Reg 4 contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_AUTONEG_LP_BPA, PhyAddress); + + DEBUGOUT1("Reg 5 contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_AUTONEG_EXPANSION_REG, PhyAddress); + + DEBUGOUT1("Reg 6 contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_AUTONEG_NEXT_PAGE_TX, PhyAddress); + + DEBUGOUT1("Reg 7 contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_AUTONEG_LP_RX_NEXT_PAGE, + PhyAddress); + + DEBUGOUT1("Reg 8 contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_1000T_CTRL_REG, PhyAddress); + + DEBUGOUT1("Reg 9 contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_1000T_STATUS_REG, PhyAddress); + + DEBUGOUT1("Reg A contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PHY_IEEE_EXT_STATUS_REG, PhyAddress); + + DEBUGOUT1("Reg F contents = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, PhyAddress); + + DEBUGOUT1("Paxson Specific Control Reg (0x10) = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PXN_PHY_SPEC_STAT_REG, PhyAddress); + + DEBUGOUT1("Paxson Specific Status Reg (0x11) = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PXN_INT_ENABLE_REG, PhyAddress); + + DEBUGOUT1("Paxson Interrupt Enable Reg (0x12) = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PXN_INT_STATUS_REG, PhyAddress); + + DEBUGOUT1("Paxson Interrupt Status Reg (0x13) = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PXN_EXT_PHY_SPEC_CTRL_REG, PhyAddress); + + DEBUGOUT1("Paxson Ext. Phy Specific Control (0x14) = %x\n", Data); + + Data = em_read_phy_register(Adapter, + PXN_RX_ERROR_COUNTER, PhyAddress); + + DEBUGOUT1("Paxson Receive Error Counter (0x15) = %x\n", Data); + + Data = em_read_phy_register(Adapter, PXN_LED_CTRL_REG, PhyAddress); + + DEBUGOUT1("Paxson LED control reg (0x18) = %x\n", Data); +} + +u32 em_auto_detect_gigabit_phy(struct adapter *Adapter) +{ + u32 PhyAddress = 1; + u32 PhyIDHi; + u16 PhyIDLo; + u8 GotOne = 0; + + DEBUGFUNC("em_auto_detect_gigabit_phy") + + while ((!GotOne) && (PhyAddress <= MAX_PHY_REG_ADDRESS)) { + + PhyIDHi = em_read_phy_register(Adapter, + PHY_PHY_ID_REG1, + PhyAddress); + + DelayInMicroseconds(2); + + PhyIDLo = em_read_phy_register(Adapter, + PHY_PHY_ID_REG2, + PhyAddress); + + Adapter->PhyId = + (PhyIDLo | (PhyIDHi << 16)) & PHY_REVISION_MASK; + + if (Adapter->PhyId == PAXSON_PHY_88E1000 || + Adapter->PhyId == PAXSON_PHY_88E1000S || + Adapter->PhyId == PAXSON_PHY_INTEGRATED) { + DEBUGOUT2("PhyId 0x%x detected at address 0x%x\n", + Adapter->PhyId, PhyAddress); + + GotOne = 1; + } else { + PhyAddress++; + } + + } + + if (PhyAddress > MAX_PHY_REG_ADDRESS) { + DEBUGOUT("Could not auto-detect Phy!\n"); + } + + return (PhyAddress); +} + +void em_pxn_phy_reset_dsp(struct adapter *Adapter) +{ + em_write_phy_register(Adapter, 29, Adapter->PhyAddress, 0x1d); + em_write_phy_register(Adapter, 30, Adapter->PhyAddress, 0xc1); + em_write_phy_register(Adapter, 30, Adapter->PhyAddress, 0x00); +} + +u8 em_wait_for_auto_neg(struct adapter *Adapter) +{ + u8 AutoNegComplete = 0; + u16 i; + u16 MiiStatusReg; + + DEBUGFUNC("em_wait_for_auto_neg"); + + DEBUGOUT("Waiting for Auto-Neg to complete.\n"); + MiiStatusReg = 0; + + for (i = PHY_AUTO_NEG_TIME; i > 0; i--) { + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + MiiStatusReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + + if (MiiStatusReg & MII_SR_AUTONEG_COMPLETE) { + AutoNegComplete = 1; + break; + } + + DelayInMilliseconds(100); + } + + return (AutoNegComplete); +} + +u8 em_phy_get_status_info(struct adapter * Adapter, + phy_status_info_struct * PhyStatusInfo) +{ + u16 PhyMIIStatReg; + u16 PhySpecCtrlReg; + u16 PhySpecStatReg; + u16 PhyExtSpecCtrlReg; + u16 Phy1000BTStatReg; + + PhyStatusInfo->CableLength = PXN_PSSR_CABLE_LENGTH_UNDEFINED; + PhyStatusInfo->Extended10BTDistance = + PXN_PSCR_10BT_EXT_DIST_ENABLE_UNDEFINED; + PhyStatusInfo->CablePolarity = PXN_PSSR_REV_POLARITY_UNDEFINED; + PhyStatusInfo->PolarityCorrection = + PXN_PSCR_POLARITY_REVERSAL_UNDEFINED; + PhyStatusInfo->LinkReset = PXN_EPSCR_DOWN_NO_IDLE_UNDEFINED; + PhyStatusInfo->MDIXMode = PXN_PSCR_AUTO_X_MODE_UNDEFINED; + PhyStatusInfo->LocalRx = SR_1000T_RX_STATUS_UNDEFINED; + PhyStatusInfo->RemoteRx = SR_1000T_RX_STATUS_UNDEFINED; + + if (Adapter == NULL || Adapter->MediaType != MEDIA_TYPE_COPPER) + return 0; + + PhyMIIStatReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + PhyMIIStatReg = em_read_phy_register(Adapter, + PHY_MII_STATUS_REG, + Adapter->PhyAddress); + if ((PhyMIIStatReg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) + return 0; + + PhySpecCtrlReg = em_read_phy_register(Adapter, + PXN_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + PhySpecStatReg = em_read_phy_register(Adapter, + PXN_PHY_SPEC_STAT_REG, + Adapter->PhyAddress); + PhyExtSpecCtrlReg = em_read_phy_register(Adapter, + PXN_EXT_PHY_SPEC_CTRL_REG, + Adapter->PhyAddress); + Phy1000BTStatReg = em_read_phy_register(Adapter, + PHY_1000T_STATUS_REG, + Adapter->PhyAddress); + + PhyStatusInfo->CableLength = (PXN_PSSR_CABLE_LENGTH_ENUM) + ((PhySpecStatReg & PXN_PSSR_CABLE_LENGTH) >> + PXN_PSSR_CABLE_LENGTH_SHIFT); + + PhyStatusInfo->Extended10BTDistance = + (PXN_PSCR_10BT_EXT_DIST_ENABLE_ENUM) (PhySpecCtrlReg & + PXN_PSCR_10BT_EXT_DIST_ENABLE) + >> PXN_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + + PhyStatusInfo->CablePolarity = (PXN_PSSR_REV_POLARITY_ENUM) + (PhySpecStatReg & PXN_PSSR_REV_POLARITY) >> + PXN_PSSR_REV_POLARITY_SHIFT; + + PhyStatusInfo->PolarityCorrection = + (PXN_PSCR_POLARITY_REVERSAL_ENUM) (PhySpecCtrlReg & + PXN_PSCR_POLARITY_REVERSAL) + >> PXN_PSCR_POLARITY_REVERSAL_SHIFT; + + PhyStatusInfo->LinkReset = (PXN_EPSCR_DOWN_NO_IDLE_ENUM) + (PhyExtSpecCtrlReg & PXN_EPSCR_DOWN_NO_IDLE) >> + PXN_EPSCR_DOWN_NO_IDLE_SHIFT; + + PhyStatusInfo->MDIXMode = (PXN_PSCR_AUTO_X_MODE_ENUM) + (PhySpecCtrlReg & PXN_PSCR_AUTO_X_MODE) >> + PXN_PSCR_AUTO_X_MODE_SHIFT; + + PhyStatusInfo->LocalRx = (SR_1000T_RX_STATUS_ENUM) + (Phy1000BTStatReg & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + PhyStatusInfo->RemoteRx = (SR_1000T_RX_STATUS_ENUM) + (Phy1000BTStatReg & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + return 1; +} diff --git a/sys/dev/em/if_em_phy.h b/sys/dev/em/if_em_phy.h new file mode 100644 index 0000000..737f3b17 --- /dev/null +++ b/sys/dev/em/if_em_phy.h @@ -0,0 +1,418 @@ +/************************************************************************* +************************************************************************** +Copyright (c) 2001 Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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$ +*************************************************************************** +**************************************************************************/ + +#ifndef _EM_PHY_H_ +#define _EM_PHY_H_ + +/* +* Workfile: phy.h +* Date: 9/25/01 2:40p +* Revision: 9 +*/ + +#define _PHY_ + +#include <dev/em/if_em_osdep.h> + +typedef enum { + PXN_PSSR_CABLE_LENGTH_50 = 0, + PXN_PSSR_CABLE_LENGTH_50_80, + PXN_PSSR_CABLE_LENGTH_80_110, + PXN_PSSR_CABLE_LENGTH_110_140, + PXN_PSSR_CABLE_LENGTH_140, + PXN_PSSR_CABLE_LENGTH_UNDEFINED = 0xFF +} PXN_PSSR_CABLE_LENGTH_ENUM; + +typedef enum { + PXN_PSCR_10BT_EXT_DIST_ENABLE_NORMAL = 0, + PXN_PSCR_10BT_EXT_DIST_ENABLE_LOWER, + PXN_PSCR_10BT_EXT_DIST_ENABLE_UNDEFINED = 0xFF +} PXN_PSCR_10BT_EXT_DIST_ENABLE_ENUM; + +typedef enum { + PXN_PSSR_REV_POLARITY_NORMAL = 0, + PXN_PSSR_REV_POLARITY_REVERSED, + PXN_PSSR_REV_POLARITY_UNDEFINED = 0xFF +} PXN_PSSR_REV_POLARITY_ENUM; + +typedef enum { + PXN_PSCR_POLARITY_REVERSAL_ENABLED = 0, + PXN_PSCR_POLARITY_REVERSAL_DISABLED, + PXN_PSCR_POLARITY_REVERSAL_UNDEFINED = 0xFF +} PXN_PSCR_POLARITY_REVERSAL_ENUM; + +typedef enum { + PXN_EPSCR_DOWN_NO_IDLE_NO_DETECT = 0, + PXN_EPSCR_DOWN_NO_IDLE_DETECT, + PXN_EPSCR_DOWN_NO_IDLE_UNDEFINED = 0xFF +} PXN_EPSCR_DOWN_NO_IDLE_ENUM; + +typedef enum { + PXN_PSCR_AUTO_X_MODE_MANUAL_MDI = 0, + PXN_PSCR_AUTO_X_MODE_MANUAL_MDIX, + PXN_PSCR_AUTO_X_MODE_AUTO_1, + PXN_PSCR_AUTO_X_MODE_AUTO_2, + PXN_PSCR_AUTO_X_MODE_UNDEFINED = 0xFF +} PXN_PSCR_AUTO_X_MODE_ENUM; + +typedef enum { + SR_1000T_RX_STATUS_NOT_OK = 0, + SR_1000T_RX_STATUS_OK, + SR_1000T_RX_STATUS_UNDEFINED = 0xFF +} SR_1000T_RX_STATUS_ENUM; + +typedef struct { + PXN_PSSR_CABLE_LENGTH_ENUM CableLength; + PXN_PSCR_10BT_EXT_DIST_ENABLE_ENUM Extended10BTDistance; + PXN_PSSR_REV_POLARITY_ENUM CablePolarity; + PXN_PSCR_POLARITY_REVERSAL_ENUM PolarityCorrection; + PXN_EPSCR_DOWN_NO_IDLE_ENUM LinkReset; + PXN_PSCR_AUTO_X_MODE_ENUM MDIXMode; + SR_1000T_RX_STATUS_ENUM LocalRx; + SR_1000T_RX_STATUS_ENUM RemoteRx; +} phy_status_info_struct; + +u16 em_read_phy_register(struct adapter *Adapter, + + u32 RegAddress, u32 PhyAddress); +void em_write_phy_register(struct adapter *Adapter, + u32 RegAddress, u32 PhyAddress, u16 Data); +void em_phy_hardware_reset(struct adapter *Adapter); +u8 em_phy_reset(struct adapter *Adapter); +u8 em_phy_setup(struct adapter *Adapter, u32 DeviceControlReg); +void em_configure_mac_to_phy_settings(struct adapter *Adapter, + + u16 MiiRegisterData); +void em_configure_collision_distance(struct adapter *Adapter); +void em_display_mii_contents(struct adapter *Adapter, u8 PhyAddress); +u32 em_auto_detect_gigabit_phy(struct adapter *Adapter); +void em_pxn_phy_reset_dsp(struct adapter *Adapter); +void PxnIntegratedPhyLoopback(struct adapter *Adapter, u16 Speed); +void PxnPhyEnableReceiver(struct adapter *Adapter); +void PxnPhyDisableReceiver(struct adapter *Adapter); +u8 em_wait_for_auto_neg(struct adapter *Adapter); +u8 em_phy_get_status_info(struct adapter *Adapter, + + phy_status_info_struct * PhyStatusInfo); + +#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 +#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 +#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 +#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 +#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 +#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 +#define E1000_CTRL_PHY_RESET_DIR4 E1000_EXCTRL_SWDPIO4 +#define E1000_CTRL_PHY_RESET4 E1000_EXCTRL_SWDPIN4 + +#define PHY_MII_CTRL_REG 0x00 +#define PHY_MII_STATUS_REG 0x01 +#define PHY_PHY_ID_REG1 0x02 +#define PHY_PHY_ID_REG2 0x03 +#define PHY_AUTONEG_ADVERTISEMENT 0x04 +#define PHY_AUTONEG_LP_BPA 0x05 +#define PHY_AUTONEG_EXPANSION_REG 0x06 +#define PHY_AUTONEG_NEXT_PAGE_TX 0x07 +#define PHY_AUTONEG_LP_RX_NEXT_PAGE 0x08 +#define PHY_1000T_CTRL_REG 0x09 +#define PHY_1000T_STATUS_REG 0x0A +#define PHY_IEEE_EXT_STATUS_REG 0x0F + +#define PXN_PHY_SPEC_CTRL_REG 0x10 +#define PXN_PHY_SPEC_STAT_REG 0x11 +#define PXN_INT_ENABLE_REG 0x12 +#define PXN_INT_STATUS_REG 0x13 +#define PXN_EXT_PHY_SPEC_CTRL_REG 0x14 +#define PXN_RX_ERROR_COUNTER 0x15 +#define PXN_LED_CTRL_REG 0x18 + +#define MAX_PHY_REG_ADDRESS 0x1F + +#define MII_CR_SPEED_SELECT_MSB 0x0040 +#define MII_CR_COLL_TEST_ENABLE 0x0080 +#define MII_CR_FULL_DUPLEX 0x0100 +#define MII_CR_RESTART_AUTO_NEG 0x0200 +#define MII_CR_ISOLATE 0x0400 +#define MII_CR_POWER_DOWN 0x0800 +#define MII_CR_AUTO_NEG_EN 0x1000 +#define MII_CR_SPEED_SELECT_LSB 0x2000 +#define MII_CR_LOOPBACK 0x4000 +#define MII_CR_RESET 0x8000 + +#define MII_SR_EXTENDED_CAPS 0x0001 +#define MII_SR_JABBER_DETECT 0x0002 +#define MII_SR_LINK_STATUS 0x0004 +#define MII_SR_AUTONEG_CAPS 0x0008 +#define MII_SR_REMOTE_FAULT 0x0010 +#define MII_SR_AUTONEG_COMPLETE 0x0020 +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 +#define MII_SR_EXTENDED_STATUS 0x0100 +#define MII_SR_100T2_HD_CAPS 0x0200 +#define MII_SR_100T2_FD_CAPS 0x0400 +#define MII_SR_10T_HD_CAPS 0x0800 +#define MII_SR_10T_FD_CAPS 0x1000 +#define MII_SR_100X_HD_CAPS 0x2000 +#define MII_SR_100X_FD_CAPS 0x4000 +#define MII_SR_100T4_CAPS 0x8000 + +#define NWAY_AR_SELECTOR_FIELD 0x0001 +#define NWAY_AR_10T_HD_CAPS 0x0020 +#define NWAY_AR_10T_FD_CAPS 0x0040 +#define NWAY_AR_100TX_HD_CAPS 0x0080 +#define NWAY_AR_100TX_FD_CAPS 0x0100 +#define NWAY_AR_100T4_CAPS 0x0200 +#define NWAY_AR_PAUSE 0x0400 +#define NWAY_AR_ASM_DIR 0x0800 +#define NWAY_AR_REMOTE_FAULT 0x2000 +#define NWAY_AR_NEXT_PAGE 0x8000 + +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 +#define NWAY_LPAR_10T_HD_CAPS 0x0020 +#define NWAY_LPAR_10T_FD_CAPS 0x0040 +#define NWAY_LPAR_100TX_HD_CAPS 0x0080 +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 +#define NWAY_LPAR_100T4_CAPS 0x0200 +#define NWAY_LPAR_PAUSE 0x0400 +#define NWAY_LPAR_ASM_DIR 0x0800 +#define NWAY_LPAR_REMOTE_FAULT 0x2000 +#define NWAY_LPAR_ACKNOWLEDGE 0x4000 +#define NWAY_LPAR_NEXT_PAGE 0x8000 + +#define NWAY_ER_LP_NWAY_CAPS 0x0001 +#define NWAY_ER_PAGE_RXD 0x0002 +#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 +#define NWAY_ER_PAR_DETECT_FAULT 0x0100 + +#define NPTX_MSG_CODE_FIELD 0x0001 +#define NPTX_TOGGLE 0x0800 + +#define NPTX_ACKNOWLDGE2 0x1000 + +#define NPTX_MSG_PAGE 0x2000 +#define NPTX_NEXT_PAGE 0x8000 + +#define LP_RNPR_MSG_CODE_FIELD 0x0001 +#define LP_RNPR_TOGGLE 0x0800 + +#define LP_RNPR_ACKNOWLDGE2 0x1000 + +#define LP_RNPR_MSG_PAGE 0x2000 +#define LP_RNPR_ACKNOWLDGE 0x4000 +#define LP_RNPR_NEXT_PAGE 0x8000 + +#define CR_1000T_ASYM_PAUSE 0x0080 +#define CR_1000T_HD_CAPS 0x0100 + +#define CR_1000T_FD_CAPS 0x0200 + +#define CR_1000T_REPEATER_DTE 0x0400 + +#define CR_1000T_MS_VALUE 0x0800 + +#define CR_1000T_MS_ENABLE 0x1000 + +#define CR_1000T_TEST_MODE_NORMAL 0x0000 +#define CR_1000T_TEST_MODE_1 0x2000 +#define CR_1000T_TEST_MODE_2 0x4000 +#define CR_1000T_TEST_MODE_3 0x6000 +#define CR_1000T_TEST_MODE_4 0x8000 + +#define SR_1000T_IDLE_ERROR_CNT 0x00FF +#define SR_1000T_ASYM_PAUSE_DIR 0x0100 +#define SR_1000T_LP_HD_CAPS 0x0400 + +#define SR_1000T_LP_FD_CAPS 0x0800 + +#define SR_1000T_REMOTE_RX_STATUS 0x1000 +#define SR_1000T_LOCAL_RX_STATUS 0x2000 +#define SR_1000T_MS_CONFIG_RES 0x4000 +#define SR_1000T_MS_CONFIG_FAULT 0x8000 + +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +#define IEEE_ESR_1000T_HD_CAPS 0x1000 + +#define IEEE_ESR_1000T_FD_CAPS 0x2000 + +#define IEEE_ESR_1000X_HD_CAPS 0x4000 + +#define IEEE_ESR_1000X_FD_CAPS 0x8000 + +#define PHY_TX_POLARITY_MASK 0x0100 +#define PHY_TX_NORMAL_POLARITY 0 + +#define AUTO_POLARITY_DISABLE 0x0010 + +#define PXN_PSCR_JABBER_DISABLE 0x0001 +#define PXN_PSCR_POLARITY_REVERSAL 0x0002 +#define PXN_PSCR_SQE_TEST 0x0004 +#define PXN_PSCR_INT_FIFO_DISABLE 0x0008 + +#define PXN_PSCR_CLK125_DISABLE 0x0010 +#define PXN_PSCR_MDI_MANUAL_MODE 0x0000 + +#define PXN_PSCR_MDIX_MANUAL_MODE 0x0020 +#define PXN_PSCR_AUTO_X_1000T 0x0040 +#define PXN_PSCR_AUTO_X_MODE 0x0060 +#define PXN_PSCR_10BT_EXT_DIST_ENABLE 0x0080 +#define PXN_PSCR_MII_5BIT_ENABLE 0x0100 +#define PXN_PSCR_SCRAMBLER_DISABLE 0x0200 +#define PXN_PSCR_FORCE_LINK_GOOD 0x0400 +#define PXN_PSCR_ASSERT_CRS_ON_TX 0x0800 +#define PXN_PSCR_RX_FIFO_DEPTH_6 0x0000 +#define PXN_PSCR_RX_FIFO_DEPTH_8 0x1000 +#define PXN_PSCR_RX_FIFO_DEPTH_10 0x2000 +#define PXN_PSCR_RX_FIFO_DEPTH_12 0x3000 + +#define PXN_PSCR_TXFR_FIFO_DEPTH_6 0x0000 +#define PXN_PSCR_TXFR_FIFO_DEPTH_8 0x4000 +#define PXN_PSCR_TXFR_FIFO_DEPTH_10 0x8000 +#define PXN_PSCR_TXFR_FIFO_DEPTH_12 0xC000 + +#define PXN_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define PXN_PSCR_AUTO_X_MODE_SHIFT 5 +#define PXN_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +#define PXN_PSSR_JABBER 0x0001 +#define PXN_PSSR_REV_POLARITY 0x0002 +#define PXN_PSSR_MDIX 0x0040 +#define PXN_PSSR_CABLE_LENGTH 0x0380 +#define PXN_PSSR_LINK 0x0400 +#define PXN_PSSR_SPD_DPLX_RESOLVED 0x0800 +#define PXN_PSSR_PAGE_RCVD 0x1000 +#define PXN_PSSR_DPLX 0x2000 +#define PXN_PSSR_SPEED 0xC000 +#define PXN_PSSR_10MBS 0x0000 +#define PXN_PSSR_100MBS 0x4000 +#define PXN_PSSR_1000MBS 0x8000 + +#define PXN_PSSR_REV_POLARITY_SHIFT 1 +#define PXN_PSSR_CABLE_LENGTH_SHIFT 7 + +#define PXN_IER_JABBER 0x0001 +#define PXN_IER_POLARITY_CHANGE 0x0002 +#define PXN_IER_MDIX_CHANGE 0x0040 +#define PXN_IER_FIFO_OVER_UNDERUN 0x0080 +#define PXN_IER_FALSE_CARRIER 0x0100 +#define PXN_IER_SYMBOL_ERROR 0x0200 +#define PXN_IER_LINK_STAT_CHANGE 0x0400 +#define PXN_IER_AUTO_NEG_COMPLETE 0x0800 +#define PXN_IER_PAGE_RECEIVED 0x1000 +#define PXN_IER_DUPLEX_CHANGED 0x2000 +#define PXN_IER_SPEED_CHANGED 0x4000 +#define PXN_IER_AUTO_NEG_ERR 0x8000 + +#define PXN_ISR_JABBER 0x0001 +#define PXN_ISR_POLARITY_CHANGE 0x0002 +#define PXN_ISR_MDIX_CHANGE 0x0040 +#define PXN_ISR_FIFO_OVER_UNDERUN 0x0080 +#define PXN_ISR_FALSE_CARRIER 0x0100 +#define PXN_ISR_SYMBOL_ERROR 0x0200 +#define PXN_ISR_LINK_STAT_CHANGE 0x0400 +#define PXN_ISR_AUTO_NEG_COMPLETE 0x0800 +#define PXN_ISR_PAGE_RECEIVED 0x1000 +#define PXN_ISR_DUPLEX_CHANGED 0x2000 +#define PXN_ISR_SPEED_CHANGED 0x4000 +#define PXN_ISR_AUTO_NEG_ERR 0x8000 + +#define PXN_EPSCR_FIBER_LOOPBACK 0x4000 +#define PXN_EPSCR_DOWN_NO_IDLE 0x8000 + +#define PXN_EPSCR_TX_CLK_2_5 0x0060 +#define PXN_EPSCR_TX_CLK_25 0x0070 +#define PXN_EPSCR_TX_CLK_0 0x0000 + +#define PXN_EPSCR_DOWN_NO_IDLE_SHIFT 15 + +#define PXN_LCR_LED_TX 0x0001 +#define PXN_LCR_LED_RX 0x0002 +#define PXN_LCR_LED_DUPLEX 0x0004 +#define PXN_LCR_LINK 0x0008 +#define PXN_LCR_BLINK_RATE_42MS 0x0000 +#define PXN_LCR_BLINK_RATE_84MS 0x0100 +#define PXN_LCR_BLINK_RATE_170MS 0x0200 +#define PXN_LCR_BLINK_RATE_340MS 0x0300 +#define PXN_LCR_BLINK_RATE_670MS 0x0400 + +#define PXN_LCR_PULSE_STRETCH_OFF 0x0000 +#define PXN_LCR_PULSE_STRETCH_21_42MS 0x1000 +#define PXN_LCR_PULSE_STRETCH_42_84MS 0x2000 +#define PXN_LCR_PULSE_STRETCH_84_170MS 0x3000 +#define PXN_LCR_PULSE_STRETCH_170_340MS 0x4000 +#define PXN_LCR_PULSE_STRETCH_340_670MS 0x5000 +#define PXN_LCR_PULSE_STRETCH_670_13S 0x6000 +#define PXN_LCR_PULSE_STRETCH_13_26S 0x7000 + +#define PHY_PREAMBLE 0xFFFFFFFF +#define PHY_SOF 0x01 +#define PHY_OP_READ 0x02 +#define PHY_OP_WRITE 0x01 +#define PHY_TURNAROUND 0x02 + +#define PHY_PREAMBLE_SIZE 32 + +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +#define E1000_PHY_ADDRESS 0x01 +#define E1000_10MB_PHY_ADDRESS 0x02 + +#define PHY_AUTO_NEG_TIME 45 + +#define PAXSON_PHY_88E1000 0x01410C50 +#define PAXSON_PHY_88E1000S 0x01410C40 +#define PAXSON_PHY_INTEGRATED 0x01410C30 + +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F + +#define DEVICE_SPEED_MASK 0x00000300 + +#define REG4_SPEED_MASK 0x01E0 +#define REG9_SPEED_MASK 0x0300 + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 +#define ADVERTISE_1000_FULL 0x0020 + +#endif /* _EM_PHY_H_ */ + diff --git a/sys/modules/Makefile b/sys/modules/Makefile index c423a4f..6987786 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -24,6 +24,7 @@ SUBDIR= 3dfx \ digi \ dummynet \ ed \ + em \ fdescfs \ fdc \ fs \ diff --git a/sys/modules/em/Makefile b/sys/modules/em/Makefile new file mode 100644 index 0000000..4a89fba --- /dev/null +++ b/sys/modules/em/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/em +KMOD = if_em +SRCS = device_if.h bus_if.h pci_if.h opt_bdg.h +SRCS += if_em.c if_em_fxhw.c if_em_phy.c + +clean: + rm -f opt_bdg.h device_if.h bus_if.h pci_if.h setdef* + rm -f *.o *.kld *.ko + rm -f @ machine + +.include <bsd.kmod.mk> |