summaryrefslogtreecommitdiffstats
path: root/sys/dev/em
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/em')
-rw-r--r--sys/dev/em/if_em.c2632
-rw-r--r--sys/dev/em/if_em.h410
-rw-r--r--sys/dev/em/if_em_fxhw.c1457
-rw-r--r--sys/dev/em/if_em_fxhw.h1338
-rw-r--r--sys/dev/em/if_em_osdep.h95
-rw-r--r--sys/dev/em/if_em_phy.c1223
-rw-r--r--sys/dev/em/if_em_phy.h418
7 files changed, 7573 insertions, 0 deletions
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_ */
+
OpenPOWER on IntegriCloud