diff options
author | pdeuskar <pdeuskar@FreeBSD.org> | 2002-02-13 18:19:27 +0000 |
---|---|---|
committer | pdeuskar <pdeuskar@FreeBSD.org> | 2002-02-13 18:19:27 +0000 |
commit | 59699901cf6676124969480fe58eb1a8b64b7708 (patch) | |
tree | 459e47e9920416c2371f77bf0d6073cfb8870ac0 /sys/dev/em | |
parent | c34beebab28585cc95b625d661cf798297547504 (diff) | |
download | FreeBSD-src-59699901cf6676124969480fe58eb1a8b64b7708.zip FreeBSD-src-59699901cf6676124969480fe58eb1a8b64b7708.tar.gz |
- Added support for receive in multiple
descriptors. This simplifies code for jumbo frames.
- Cleaned up coding conventions to make code more unix-like.
- Cleaned up code in if_em_fxhw.c and if_em_phy.c.
Added relevant comments.
MFC after: 1 week
Diffstat (limited to 'sys/dev/em')
-rw-r--r-- | sys/dev/em/if_em.c | 1116 | ||||
-rw-r--r-- | sys/dev/em/if_em.h | 161 | ||||
-rw-r--r-- | sys/dev/em/if_em_fxhw.c | 3054 | ||||
-rw-r--r-- | sys/dev/em/if_em_fxhw.h | 2503 | ||||
-rw-r--r-- | sys/dev/em/if_em_osdep.h | 102 | ||||
-rw-r--r-- | sys/dev/em/if_em_phy.c | 2499 | ||||
-rw-r--r-- | sys/dev/em/if_em_phy.h | 750 |
7 files changed, 5234 insertions, 4951 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index 6073af5..8d08b5f 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -1,5 +1,4 @@ /************************************************************************** -************************************************************************** Copyright (c) 2001 Intel Corporation All rights reserved. @@ -32,11 +31,10 @@ 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$ -*************************************************************************** ***************************************************************************/ +/*$FreeBSD$*/ + #include <dev/em/if_em.h> /********************************************************************* @@ -55,7 +53,7 @@ struct adapter *em_adapter_list = NULL; * Driver version *********************************************************************/ -char em_driver_version[] = "1.0.7"; +char em_driver_version[] = "1.1.10"; /********************************************************************* @@ -126,7 +124,7 @@ 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 em_rx_desc * RxDescriptor, struct mbuf *)); static void em_transmit_checksum_setup __P((struct adapter *, struct mbuf *, @@ -140,14 +138,6 @@ 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 *********************************************************************/ @@ -249,6 +239,7 @@ em_attach(device_t dev) } bzero(Adapter, sizeof(struct adapter )); Adapter->dev = dev; + Adapter->osdep.dev = dev; Adapter->unit = device_get_unit(dev); if (em_adapter_list != NULL) @@ -266,32 +257,31 @@ em_attach(device_t dev) 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->shared.autoneg = DO_AUTO_NEG; + Adapter->shared.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; + Adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + Adapter->shared.tbi_compatibility_en = 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; + Adapter->shared.fc_high_water = FC_DEFAULT_HI_THRESH; + Adapter->shared.fc_low_water = FC_DEFAULT_LO_THRESH; + Adapter->shared.fc_pause_time = FC_DEFAULT_TX_TIMER; + Adapter->shared.fc_send_xon = TRUE; + Adapter->shared.fc = em_fc_full; /* Set the max frame size assuming standard ethernet sized frames */ - Adapter->MaxFrameSize = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; + Adapter->shared.max_frame_size = 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; + Adapter->shared.report_tx_early = EM_REPORT_TX_EARLY; } else { - if(Adapter->MacType < MAC_LIVENGOOD) { - Adapter->ReportTxEarly = 0; + if(Adapter->shared.mac_type < em_82543) { + Adapter->shared.report_tx_early = 0; } else { - Adapter->ReportTxEarly = 1; + Adapter->shared.report_tx_early = 1; } } @@ -303,10 +293,10 @@ em_attach(device_t dev) } tsize = EM_ROUNDUP(Adapter->NumTxDescriptors * - sizeof(E1000_TRANSMIT_DESCRIPTOR), 4096); + sizeof(struct em_tx_desc), 4096); /* Allocate Transmit Descriptor ring */ - if (!(Adapter->TxDescBase = (PE1000_TRANSMIT_DESCRIPTOR) + if (!(Adapter->TxDescBase = (struct em_tx_desc *) contigmalloc(tsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) { printf("em%d: Unable to allocate TxDescriptor memory\n", Adapter->unit); em_free_pci_resources(Adapter); @@ -315,10 +305,10 @@ em_attach(device_t dev) } rsize = EM_ROUNDUP(Adapter->NumRxDescriptors * - sizeof(E1000_RECEIVE_DESCRIPTOR), 4096); + sizeof(struct em_rx_desc), 4096); /* Allocate Receive Descriptor ring */ - if (!(Adapter->RxDescBase = (PE1000_RECEIVE_DESCRIPTOR) + if (!(Adapter->RxDescBase = (struct em_rx_desc *) 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); @@ -327,28 +317,12 @@ em_attach(device_t dev) 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); } @@ -357,17 +331,19 @@ em_attach(device_t dev) em_setup_interface(dev, Adapter); /* Initialize statistics */ - em_clear_hw_stats_counters(Adapter); + em_clear_hw_cntrs(&Adapter->shared); em_update_stats_counters(Adapter); - Adapter->GetLinkStatus = 1; - em_check_for_link(Adapter); + Adapter->shared.get_link_status = 1; + em_check_for_link(&Adapter->shared); /* Print the link status */ - if (Adapter->LinkIsActive == 1) + if (Adapter->LinkIsActive == 1) { + em_get_speed_and_duplex(&Adapter->shared, &Adapter->LineSpeed, &Adapter->FullDuplex); 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); @@ -399,12 +375,12 @@ em_detach(device_t dev) s = splimp(); em_stop(Adapter); - em_phy_hardware_reset(Adapter); + em_phy_hw_reset(&Adapter->shared); 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); + sizeof(struct em_tx_desc), 4096); /* Free Transmit Descriptor ring */ if (Adapter->TxDescBase) { @@ -413,7 +389,7 @@ em_detach(device_t dev) } size = EM_ROUNDUP(Adapter->NumRxDescriptors * - sizeof(E1000_RECEIVE_DESCRIPTOR), 4096); + sizeof(struct em_rx_desc), 4096); /* Free Receive Descriptor ring */ if (Adapter->RxDescBase) { @@ -421,21 +397,13 @@ em_detach(device_t dev) 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; + 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; @@ -450,7 +418,7 @@ em_shutdown(device_t dev) struct adapter * Adapter = device_get_softc(dev); /* Issue a global reset */ - em_adapter_stop(Adapter); + em_adapter_stop(&Adapter->shared); return(0); } @@ -475,7 +443,7 @@ em_start(struct ifnet *ifp) vm_offset_t VirtualAddress; u_int32_t txd_upper; u_int32_t txd_lower; - PE1000_TRANSMIT_DESCRIPTOR CurrentTxDescriptor = NULL; + struct em_tx_desc * CurrentTxDescriptor = NULL; struct adapter * Adapter = ifp->if_softc; TXRX_DEBUGOUT("em_start: begin"); @@ -539,12 +507,10 @@ em_start(struct ifnet *ifp) continue; CurrentTxDescriptor = Adapter->NextAvailTxDescriptor; VirtualAddress = mtod(mp, vm_offset_t); - CurrentTxDescriptor->BufferAddress.Hi32 = 0; - CurrentTxDescriptor->BufferAddress.Lo32 = - vtophys(VirtualAddress); + CurrentTxDescriptor->buffer_addr = vtophys(VirtualAddress); - CurrentTxDescriptor->Lower.DwordData = (txd_lower | mp->m_len); - CurrentTxDescriptor->Upper.DwordData = (txd_upper); + CurrentTxDescriptor->lower.data = (txd_lower | mp->m_len); + CurrentTxDescriptor->upper.data = (txd_upper); if (CurrentTxDescriptor == Adapter->LastTxDescriptor) Adapter->NextAvailTxDescriptor = @@ -562,7 +528,7 @@ em_start(struct ifnet *ifp) * 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); + CurrentTxDescriptor->lower.data |= (Adapter->TxdCmd | E1000_TXD_CMD_EOP); /* Send a copy of the frame to the BPF listener */ if (ifp->if_bpf) @@ -571,7 +537,7 @@ em_start(struct ifnet *ifp) * 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 - + E1000_WRITE_REG(&Adapter->shared, TDT, (((u_int32_t) Adapter->NextAvailTxDescriptor - (u_int32_t) Adapter->FirstTxDescriptor) >> 4)); } /* end of while loop */ @@ -609,40 +575,13 @@ em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t 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; + Adapter->shared.max_frame_size = 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)"); @@ -667,7 +606,7 @@ em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) if (ifp->if_flags & IFF_RUNNING) { DisableInterrupts(Adapter); em_set_multi(Adapter); - if(Adapter->MacType == MAC_WISEMAN_2_0) + if(Adapter->shared.mac_type == em_82542_rev2_0) em_initialize_receive_unit(Adapter); EnableInterrupts(Adapter); } @@ -693,16 +632,16 @@ 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); + reg_rctl = E1000_READ_REG(&Adapter->shared, RCTL); if(ifp->if_flags & IFF_PROMISC) { reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); - E1000_WRITE_REG(Rctl, reg_rctl); + E1000_WRITE_REG(&Adapter->shared, 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); + E1000_WRITE_REG(&Adapter->shared, RCTL, reg_rctl); } return; @@ -713,11 +652,11 @@ em_disable_promisc(struct adapter * Adapter) { u_int32_t reg_rctl; - reg_rctl = E1000_READ_REG(Rctl); + reg_rctl = E1000_READ_REG(&Adapter->shared, RCTL); reg_rctl &= (~E1000_RCTL_UPE); reg_rctl &= (~E1000_RCTL_MPE); - E1000_WRITE_REG(Rctl, reg_rctl); + E1000_WRITE_REG(&Adapter->shared, RCTL, reg_rctl); return; } @@ -736,53 +675,57 @@ 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 ifmultiaddr *ifma; + int mcnt = 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; + IOCTL_DEBUGOUT("em_set_multi: begin"); + + if(Adapter->shared.mac_type == em_82542_rev2_0) { + reg_rctl = E1000_READ_REG(&Adapter->shared, RCTL); + if(Adapter->shared.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + PciCommandWord = Adapter->shared.pci_cmd_word & ~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); + E1000_WRITE_REG(&Adapter->shared, RCTL, reg_rctl); + msec_delay(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 __FreeBSD_version < 500000 + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { +#else + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { +#endif + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); + mcnt++; } - if (multi_cnt > MAX_NUM_MULTICAST_ADDRESSES) { - reg_rctl = E1000_READ_REG(Rctl); + if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) { + reg_rctl = E1000_READ_REG(&Adapter->shared, RCTL); reg_rctl |= E1000_RCTL_MPE; - E1000_WRITE_REG(Rctl, reg_rctl); + E1000_WRITE_REG(&Adapter->shared, RCTL, reg_rctl); } else - em_multicast_address_list_update(Adapter, mta, multi_cnt, 0); + em_mc_addr_list_update(&Adapter->shared, mta, mcnt, 0); - if(Adapter->MacType == MAC_WISEMAN_2_0) { - reg_rctl = E1000_READ_REG(Rctl); + if(Adapter->shared.mac_type == em_82542_rev2_0) { + reg_rctl = E1000_READ_REG(&Adapter->shared, 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); + E1000_WRITE_REG(&Adapter->shared, RCTL, reg_rctl); + msec_delay(5); + if(Adapter->shared.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + pci_write_config(Adapter->dev, PCIR_COMMAND, Adapter->shared.pci_cmd_word, 2); } } - return; + return; } - /********************************************************************* * Watchdog entry point * @@ -799,7 +742,7 @@ em_watchdog(struct ifnet *ifp) /* If we are in this routine because of pause frames, then * don't reset the hardware. */ - if(E1000_READ_REG(Status) & E1000_STATUS_TXOFF) { + if(E1000_READ_REG(&Adapter->shared, STATUS) & E1000_STATUS_TXOFF) { ifp->if_timer = EM_TX_TIMEOUT; return; } @@ -832,7 +775,7 @@ em_local_timer(void *arg) s = splimp(); - em_check_for_link(Adapter); + em_check_for_link(&Adapter->shared); em_print_link_status(Adapter); em_update_stats_counters(Adapter); if(em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { @@ -847,9 +790,9 @@ em_local_timer(void *arg) static void em_print_link_status(struct adapter * Adapter) { - if(E1000_READ_REG(Status) & E1000_STATUS_LU) { + if(E1000_READ_REG(&Adapter->shared, STATUS) & E1000_STATUS_LU) { if(Adapter->LinkIsActive == 0) { - em_get_speed_and_duplex(Adapter, &Adapter->LineSpeed, &Adapter->FullDuplex); + em_get_speed_and_duplex(&Adapter->shared, &Adapter->LineSpeed, &Adapter->FullDuplex); printf("em%d: Link is up %d Mbps %s\n", Adapter->unit, Adapter->LineSpeed, @@ -899,7 +842,7 @@ em_init(void *arg) splx(s); return; } - Adapter->AdapterStopped = FALSE; + Adapter->shared.adapter_stopped = FALSE; /* Prepare transmit descriptors and buffers */ if (em_setup_transmit_structures(Adapter)) { @@ -926,11 +869,11 @@ em_init(void *arg) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - if(Adapter->MacType >= MAC_LIVENGOOD) + if(Adapter->shared.mac_type >= em_82543) ifp->if_hwassist = EM_CHECKSUM_FEATURES; Adapter->timer_handle = timeout(em_local_timer, Adapter, 2*hz); - em_clear_hw_stats_counters(Adapter); + em_clear_hw_cntrs(&Adapter->shared); EnableInterrupts(Adapter); splx(s); @@ -954,7 +897,7 @@ em_stop(void *arg) INIT_DEBUGOUT("em_stop: begin\n"); DisableInterrupts(Adapter); - em_adapter_stop(Adapter); + em_adapter_stop(&Adapter->shared); untimeout(em_local_timer, Adapter, Adapter->timer_handle); em_free_transmit_structures(Adapter); em_free_receive_structures(Adapter); @@ -983,13 +926,13 @@ em_intr(void *arg) ifp = &Adapter->interface_data.ac_if; DisableInterrupts(Adapter); - while(ProcessCount > 0 && (IcrContents = E1000_READ_REG(Icr)) != 0) { + while(ProcessCount > 0 && (IcrContents = E1000_READ_REG(&Adapter->shared, 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); + Adapter->shared.get_link_status = 1; + em_check_for_link(&Adapter->shared); em_print_link_status(Adapter); Adapter->timer_handle = timeout(em_local_timer, Adapter, 2*hz); } @@ -1025,10 +968,10 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) INIT_DEBUGOUT("em_media_status: begin"); - em_check_for_link(Adapter); - if(E1000_READ_REG(Status) & E1000_STATUS_LU) { + em_check_for_link(&Adapter->shared); + if(E1000_READ_REG(&Adapter->shared, STATUS) & E1000_STATUS_LU) { if(Adapter->LinkIsActive == 0) { - em_get_speed_and_duplex(Adapter, &Adapter->LineSpeed, &Adapter->FullDuplex); + em_get_speed_and_duplex(&Adapter->shared, &Adapter->LineSpeed, &Adapter->FullDuplex); Adapter->LinkIsActive = 1; } } @@ -1048,7 +991,7 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) ifmr->ifm_status |= IFM_ACTIVE; - if (Adapter->MediaType == MEDIA_TYPE_FIBER) { + if (Adapter->shared.media_type == em_media_type_fiber) { ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; } else { switch (Adapter->LineSpeed) { @@ -1091,33 +1034,33 @@ em_media_change(struct ifnet *ifp) switch(IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO: - if (Adapter->AutoNeg) + if (Adapter->shared.autoneg) return 0; else { - Adapter->AutoNeg = DO_AUTO_NEG; - Adapter->AutoNegAdvertised = AUTONEG_ADV_DEFAULT; + Adapter->shared.autoneg = DO_AUTO_NEG; + Adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; } break; case IFM_1000_SX: case IFM_1000_TX: - Adapter->AutoNeg = DO_AUTO_NEG; - Adapter->AutoNegAdvertised = ADVERTISE_1000_FULL; + Adapter->shared.autoneg = DO_AUTO_NEG; + Adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; break; case IFM_100_TX: - Adapter->AutoNeg = FALSE; - Adapter->AutoNegAdvertised = 0; + Adapter->shared.autoneg = FALSE; + Adapter->shared.autoneg_advertised = 0; if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) - Adapter->ForcedSpeedDuplex = FULL_100; + Adapter->shared.forced_speed_duplex = em_100_full; else - Adapter->ForcedSpeedDuplex = HALF_100; + Adapter->shared.forced_speed_duplex = em_100_half; break; case IFM_10_T: - Adapter->AutoNeg = FALSE; - Adapter->AutoNegAdvertised = 0; + Adapter->shared.autoneg = FALSE; + Adapter->shared.autoneg_advertised = 0; if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) - Adapter->ForcedSpeedDuplex = FULL_10; + Adapter->shared.forced_speed_duplex = em_10_full; else - Adapter->ForcedSpeedDuplex = HALF_10; + Adapter->shared.forced_speed_duplex = em_10_half; break; default: printf("em%d: Unsupported media type\n", Adapter->unit); @@ -1141,9 +1084,14 @@ 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); - Adapter->PciCommandWord |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); - pci_write_config(dev, PCIR_COMMAND, Adapter->PciCommandWord, 2); + Adapter->shared.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); + if (!((Adapter->shared.pci_cmd_word & PCIM_CMD_BUSMASTEREN) && + (Adapter->shared.pci_cmd_word & PCIM_CMD_MEMEN))) { + printf("em%d: Memory Access and/or Bus Master bits were not set!\n", + Adapter->unit); + Adapter->shared.pci_cmd_word |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); + pci_write_config(dev, PCIR_COMMAND, Adapter->shared.pci_cmd_word, 2); + } /* Save off the information about this board */ Adapter->VendorId = pci_get_vendor(dev); @@ -1157,18 +1105,18 @@ em_identify_hardware(struct adapter * Adapter) /* 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; + Adapter->shared.mac_type = (Adapter->RevId == 3) ? + em_82542_rev2_1 : em_82542_rev2_0; break; case PCI_DEVICE_ID_82543GC_FIBER: case PCI_DEVICE_ID_82543GC_COPPER: - Adapter->MacType = MAC_LIVENGOOD; + Adapter->shared.mac_type = em_82543; 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; + Adapter->shared.mac_type = em_82544; break; default: INIT_DEBUGOUT1("Unknown device id 0x%x", Adapter->DeviceId); @@ -1189,8 +1137,9 @@ em_allocate_pci_resources(struct adapter * Adapter) 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); + Adapter->osdep.bus_space_tag = rman_get_bustag(Adapter->res_memory); + Adapter->osdep.bus_space_handle = rman_get_bushandle(Adapter->res_memory); + Adapter->shared.hw_addr = (uint8_t *)Adapter->osdep.bus_space_handle; resource_id = 0x0; Adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ, @@ -1206,6 +1155,9 @@ em_allocate_pci_resources(struct adapter * Adapter) printf("em%d: Error registering interrupt handler!\n", Adapter->unit); return(ENXIO); } + + Adapter->shared.back = &Adapter->osdep; + return(0); } @@ -1236,33 +1188,34 @@ static int em_hardware_init(struct adapter * Adapter) { /* Issue a global reset */ - Adapter->AdapterStopped = FALSE; - em_adapter_stop(Adapter); - Adapter->AdapterStopped = FALSE; + Adapter->shared.adapter_stopped = FALSE; + em_adapter_stop(&Adapter->shared); + Adapter->shared.adapter_stopped = FALSE; /* Make sure we have a good EEPROM before we read from it */ - if (!em_validate_eeprom_checksum(Adapter)) { + if (!em_validate_eeprom_checksum(&Adapter->shared)) { 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, + memcpy(Adapter->shared.mac_addr, Adapter->interface_data.ac_enaddr, ETH_LENGTH_OF_ADDRESS); - em_read_part_number(Adapter, &(Adapter->PartNumber)); + em_read_part_num(&Adapter->shared, &(Adapter->PartNumber)); - if (!em_initialize_hardware(Adapter)) { + if (!em_init_hw(&Adapter->shared)) { printf("em%d: Hardware Initialization Failed", Adapter->unit); return EIO; } - em_check_for_link(Adapter); - if (E1000_READ_REG(Status) & E1000_STATUS_LU) + + em_check_for_link(&Adapter->shared); + if (E1000_READ_REG(&Adapter->shared, STATUS) & E1000_STATUS_LU) Adapter->LinkIsActive = 1; else Adapter->LinkIsActive = 0; if (Adapter->LinkIsActive) { - em_get_speed_and_duplex(Adapter, &Adapter->LineSpeed, &Adapter->FullDuplex); + em_get_speed_and_duplex(&Adapter->shared, &Adapter->LineSpeed, &Adapter->FullDuplex); } else { Adapter->LineSpeed = 0; Adapter->FullDuplex = 0; @@ -1279,7 +1232,7 @@ em_read_mac_address(struct adapter * Adapter, u_int8_t * NodeAddress) for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) { EepromWordValue = - em_read_eeprom_word(Adapter, EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); + em_read_eeprom(&Adapter->shared, EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); NodeAddress[i] = (uint8_t) (EepromWordValue & 0x00FF); NodeAddress[i + 1] = (uint8_t) (EepromWordValue >> 8); } @@ -1319,7 +1272,7 @@ em_setup_interface(device_t dev, struct adapter * Adapter) */ ifmedia_init(&Adapter->media, IFM_IMASK, em_media_change, em_media_status); - if (Adapter->MediaType == MEDIA_TYPE_FIBER) { + if (Adapter->shared.media_type == em_media_type_fiber) { ifmedia_add(&Adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX, 0, NULL); ifmedia_add(&Adapter->media, IFM_ETHER | IFM_1000_SX , 0, NULL); @@ -1396,7 +1349,7 @@ em_setup_transmit_structures(struct adapter * Adapter) } bzero((void *) Adapter->FirstTxDescriptor, - (sizeof(E1000_TRANSMIT_DESCRIPTOR)) * Adapter->NumTxDescriptors); + (sizeof(struct em_tx_desc)) * Adapter->NumTxDescriptors); /* Setup TX descriptor pointers */ Adapter->NextAvailTxDescriptor = Adapter->FirstTxDescriptor; @@ -1423,47 +1376,42 @@ em_initialize_transmit_unit(struct adapter * Adapter) 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)); + E1000_WRITE_REG(&Adapter->shared, TDBAL, vtophys((vm_offset_t) Adapter->TxDescBase)); + E1000_WRITE_REG(&Adapter->shared, TDBAH, 0); + E1000_WRITE_REG(&Adapter->shared, TDLEN, Adapter->NumTxDescriptors * + sizeof(struct em_tx_desc)); /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG(Tdh, 0); - E1000_WRITE_REG(Tdt, 0); - + E1000_WRITE_REG(&Adapter->shared, TDH, 0); + E1000_WRITE_REG(&Adapter->shared, TDT, 0); - HW_DEBUGOUT2("Base = %x, Length = %x\n", E1000_READ_REG(Tdbal), - E1000_READ_REG(Tdl)); + HW_DEBUGOUT2("Base = %x, Length = %x\n", E1000_READ_REG(&Adapter->shared, TDBAL), + E1000_READ_REG(&Adapter->shared, TDLEN)); - /* 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; + switch (Adapter->shared.mac_type) { + case em_82543: + case em_82544: + if (Adapter->shared.media_type == em_media_type_fiber) + reg_tipg = DEFAULT_82543_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; + reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER; + reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + reg_tipg |= DEFAULT_82543_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; + case em_82542_rev2_0: + case em_82542_rev2_1: + reg_tipg = DEFAULT_82542_TIPG_IPGT; + reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; break; + default: + printf("em%d: Invalid mac type detected\n", Adapter->unit); } - E1000_WRITE_REG(Tipg, reg_tipg); - E1000_WRITE_REG(Tidv, Adapter->TxIntDelay); + E1000_WRITE_REG(&Adapter->shared, TIPG, reg_tipg); + E1000_WRITE_REG(&Adapter->shared, TIDV, Adapter->TxIntDelay); /* Program the Transmit Control Register */ reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | @@ -1473,7 +1421,7 @@ em_initialize_transmit_unit(struct adapter * Adapter) } else { reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; } - E1000_WRITE_REG(Tctl, reg_tctl); + E1000_WRITE_REG(&Adapter->shared, TCTL, reg_tctl); /* Setup Transmit Descriptor Settings for this adapter */ Adapter->TxdCmd = E1000_TXD_CMD_IFCS; @@ -1481,7 +1429,7 @@ em_initialize_transmit_unit(struct adapter * Adapter) if(Adapter->TxIntDelay > 0) Adapter->TxdCmd |= E1000_TXD_CMD_IDE; - if(Adapter->ReportTxEarly == 1) + if(Adapter->shared.report_tx_early == 1) Adapter->TxdCmd |= E1000_TXD_CMD_RS; else Adapter->TxdCmd |= E1000_TXD_CMD_RPS; @@ -1531,8 +1479,8 @@ em_transmit_checksum_setup(struct adapter * Adapter, u_int32_t *txd_upper, u_int32_t *txd_lower) { - PE1000_TCPIP_CONTEXT_TRANSMIT_DESCRIPTOR TXD; - PE1000_TRANSMIT_DESCRIPTOR CurrentTxDescriptor; + struct em_context_desc *TXD; + struct em_tx_desc * CurrentTxDescriptor; if (mp->m_pkthdr.csum_flags) { @@ -1571,25 +1519,25 @@ em_transmit_checksum_setup(struct adapter * Adapter, * needs to be reset. */ CurrentTxDescriptor = Adapter->NextAvailTxDescriptor; - TXD = (PE1000_TCPIP_CONTEXT_TRANSMIT_DESCRIPTOR)CurrentTxDescriptor; + TXD = (struct em_context_desc *)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->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN; + TXD->lower_setup.ip_fields.ipcso = ETHER_HDR_LEN + offsetof(struct ip, ip_sum); + TXD->lower_setup.ip_fields.ipcse = ETHER_HDR_LEN + sizeof(struct ip) - 1; - TXD->UpperXsumSetup.TcpFields.Tucss = ETHER_HDR_LEN + sizeof(struct ip); - TXD->UpperXsumSetup.TcpFields.Tucse = 0; + TXD->upper_setup.tcp_fields.tucss = ETHER_HDR_LEN + sizeof(struct ip); + TXD->upper_setup.tcp_fields.tucse = 0; if(Adapter->ActiveChecksumContext == OFFLOAD_TCP_IP) { - TXD->UpperXsumSetup.TcpFields.Tucso = ETHER_HDR_LEN + sizeof(struct ip) + + TXD->upper_setup.tcp_fields.tucso = ETHER_HDR_LEN + sizeof(struct ip) + offsetof(struct tcphdr, th_sum); } else if (Adapter->ActiveChecksumContext == OFFLOAD_UDP_IP) { - TXD->UpperXsumSetup.TcpFields.Tucso = ETHER_HDR_LEN + sizeof(struct ip) + + TXD->upper_setup.tcp_fields.tucso = ETHER_HDR_LEN + sizeof(struct ip) + offsetof(struct udphdr, uh_sum); } - TXD->TcpSegSetup.DwordData = 0; - TXD->CmdAndLength = E1000_TXD_CMD_DEXT; + TXD->tcp_seg_setup.data = 0; + TXD->cmd_and_length = E1000_TXD_CMD_DEXT; if (CurrentTxDescriptor == Adapter->LastTxDescriptor) Adapter->NextAvailTxDescriptor = Adapter->FirstTxDescriptor; @@ -1605,63 +1553,17 @@ em_transmit_checksum_setup(struct adapter * Adapter, /********************************************************************* * - * 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) +em_get_buf(struct em_rx_buffer *rx_buffer, struct adapter *Adapter, + struct mbuf *mp) { struct mbuf *nmp; + struct ifnet *ifp; + + ifp = &Adapter->interface_data.ac_if; if (mp == NULL) { MGETHDR(nmp, M_DONTWAIT, MT_DATA); @@ -1682,11 +1584,12 @@ em_get_std_buf(struct em_rx_buffer *rx_buffer, struct adapter *Adapter, nmp = mp; nmp->m_len = nmp->m_pkthdr.len = MCLBYTES; nmp->m_data = nmp->m_ext.ext_buf; + nmp->m_next = NULL; } -#ifndef SUPPORTLARGEFRAME - m_adj(nmp, ETHER_ALIGN); -#endif + if (ifp->if_mtu <= ETHERMTU) { + m_adj(nmp, ETHER_ALIGN); + } rx_buffer->Packet = nmp; rx_buffer->LowPhysicalAddress = vtophys(mtod(nmp, vm_offset_t)); @@ -1697,25 +1600,6 @@ em_get_std_buf(struct em_rx_buffer *rx_buffer, struct adapter *Adapter, /********************************************************************* * - * 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 @@ -1760,7 +1644,7 @@ static int em_setup_receive_structures(struct adapter * Adapter) { struct em_rx_buffer *rx_buffer; - PE1000_RECEIVE_DESCRIPTOR RxDescriptorPtr; + struct em_rx_desc * RxDescriptorPtr; int i; if(em_allocate_receive_structures(Adapter)) @@ -1769,14 +1653,14 @@ em_setup_receive_structures(struct adapter * Adapter) STAILQ_INIT(&Adapter->RxSwPacketList); Adapter->FirstRxDescriptor = - (PE1000_RECEIVE_DESCRIPTOR) Adapter->RxDescBase; + (struct em_rx_desc *) 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); + (sizeof(struct em_rx_desc)) * Adapter->NumRxDescriptors); /* Build a linked list of rx_buffer's */ for (i = 0, RxDescriptorPtr = Adapter->FirstRxDescriptor; @@ -1785,10 +1669,7 @@ em_setup_receive_structures(struct adapter * Adapter) 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; + RxDescriptorPtr->buffer_addr = rx_buffer->LowPhysicalAddress; STAILQ_INSERT_TAIL(&Adapter->RxSwPacketList, rx_buffer, em_rx_entry); } } @@ -1811,45 +1692,32 @@ em_initialize_receive_unit(struct adapter * Adapter) u_int32_t reg_rxcsum; /* Make sure receives are disabled while setting up the descriptor ring */ - E1000_WRITE_REG(Rctl, 0); + E1000_WRITE_REG(&Adapter->shared, RCTL, 0); /* Set the Receive Delay Timer Register */ - E1000_WRITE_REG(Rdtr0, Adapter->RxIntDelay | E1000_RDT0_FPDB); + E1000_WRITE_REG(&Adapter->shared, RDTR, Adapter->RxIntDelay | E1000_RDT_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)); + E1000_WRITE_REG(&Adapter->shared, RDBAL, vtophys((vm_offset_t) Adapter->RxDescBase)); + E1000_WRITE_REG(&Adapter->shared, RDBAH, 0); + E1000_WRITE_REG(&Adapter->shared, RDLEN, Adapter->NumRxDescriptors * + sizeof(struct em_rx_desc)); /* Setup the HW Rx Head and Tail Descriptor Pointers */ - E1000_WRITE_REG(Rdh0, 0); - E1000_WRITE_REG(Rdt0, + E1000_WRITE_REG(&Adapter->shared, RDH, 0); + E1000_WRITE_REG(&Adapter->shared, RDT, (((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); + E1000_RCTL_RDMTS_HALF | + (Adapter->shared.mc_filter_type << E1000_RCTL_MO_SHIFT); - if (Adapter->TbiCompatibilityOn == TRUE) + if (Adapter->shared.tbi_compatibility_on == TRUE) reg_rctl |= E1000_RCTL_SBP; -#ifdef SUPPORTLARGEFRAME switch (Adapter->RxBufferLen) { case EM_RXBUFFER_2048: reg_rctl |= E1000_RCTL_SZ_2048 | E1000_RCTL_LPE; @@ -1866,34 +1734,16 @@ em_initialize_receive_unit(struct adapter * Adapter) 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); + if((Adapter->shared.mac_type >= em_82543) && (Adapter->RxChecksum == 1)) { + reg_rxcsum = E1000_READ_REG(&Adapter->shared, RXCSUM); reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL); - E1000_WRITE_REG(Rxcsum, reg_rxcsum); + E1000_WRITE_REG(&Adapter->shared, RXCSUM, reg_rxcsum); } /* Enable Receives */ - E1000_WRITE_REG(Rctl, reg_rctl); + E1000_WRITE_REG(&Adapter->shared, RCTL, reg_rctl); return; } @@ -1928,118 +1778,6 @@ em_free_receive_structures(struct adapter * Adapter) /********************************************************************* * - * 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. @@ -2048,19 +1786,18 @@ em_jfree(caddr_t buf, void *args) static void em_process_receive_interrupts(struct adapter * Adapter) { - struct mbuf *mp, *lmp; - struct mbuf *fmp = NULL; + struct mbuf *mp; 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; + u_int32_t PacketLength = 0; /* Pointer to the receive descriptor being examined. */ - PE1000_RECEIVE_DESCRIPTOR CurrentDescriptor; - PE1000_RECEIVE_DESCRIPTOR LastDescriptorProcessed; + struct em_rx_desc * CurrentDescriptor; + struct em_rx_desc * LastDescriptorProcessed; struct em_rx_buffer *rx_buffer; TXRX_DEBUGOUT("em_process_receive_interrupts: begin"); @@ -2068,14 +1805,14 @@ em_process_receive_interrupts(struct adapter * Adapter) ifp = &Adapter->interface_data.ac_if; CurrentDescriptor = Adapter->NextRxDescriptorToCheck; - if (!((CurrentDescriptor->ReceiveStatus) & E1000_RXD_STAT_DD)) { + if (!((CurrentDescriptor->status) & E1000_RXD_STAT_DD)) { #ifdef DBG_STATS Adapter->NoPacketsAvail++; #endif return; } - while (CurrentDescriptor->ReceiveStatus & E1000_RXD_STAT_DD) { + while (CurrentDescriptor->status & E1000_RXD_STAT_DD) { /* Get a pointer to the actual receive buffer */ rx_buffer = STAILQ_FIRST(&Adapter->RxSwPacketList); @@ -2088,21 +1825,29 @@ em_process_receive_interrupts(struct adapter * Adapter) mp = rx_buffer->Packet; AcceptFrame = 1; - if (CurrentDescriptor->ReceiveStatus & E1000_RXD_STAT_EOP) { + if (CurrentDescriptor->status & E1000_RXD_STAT_EOP) { EndOfPacket = 1; - Length = CurrentDescriptor->Length - ETHER_CRC_LEN; + Length = CurrentDescriptor->length - ETHER_CRC_LEN; } else { EndOfPacket = 0; - Length = CurrentDescriptor->Length; + Length = CurrentDescriptor->length; } - if(CurrentDescriptor->Errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + if(CurrentDescriptor->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + + /* Compute packet length for tbi_accept macro */ + PacketLength = CurrentDescriptor->length; + if (Adapter->fmp != NULL) { + PacketLength += Adapter->fmp->m_pkthdr.len; + } - LastByte = *(mtod(rx_buffer->Packet,caddr_t) + Length - 1); + LastByte = *(mtod(rx_buffer->Packet,caddr_t) + CurrentDescriptor->length - 1); - if (TBI_ACCEPT(CurrentDescriptor->Errors, LastByte, Length)) { - em_adjust_tbi_accepted_stats(Adapter, Length, Adapter->CurrentNetAddress); + if (TBI_ACCEPT(&Adapter->shared, 0, CurrentDescriptor->errors, + PacketLength, LastByte)) { + PacketLength = em_tbi_adjust_stats(&Adapter->shared, &Adapter->stats, + PacketLength, Adapter->shared.mac_addr); Length--; } else { AcceptFrame = 0; @@ -2111,189 +1856,59 @@ em_process_receive_interrupts(struct adapter * Adapter) if (AcceptFrame) { - /* Keep track of entire packet length */ - PacketLength += Length; + if (em_get_buf(rx_buffer, Adapter, NULL) == ENOBUFS) { + Adapter->DroppedPackets++; + em_get_buf(rx_buffer, Adapter, mp); + if(Adapter->fmp != NULL) m_freem(Adapter->fmp); + Adapter->fmp = NULL; + Adapter->lmp = NULL; + break; + } /* Assign correct length to the current fragment */ mp->m_len = Length; - if(fmp == NULL) { - fmp = mp; /* Store the first mbuf */ - lmp = fmp; + if(Adapter->fmp == NULL) { + mp->m_pkthdr.len = Length; + Adapter->fmp = mp; /* Store the first mbuf */ + Adapter->lmp = mp; } 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; + Adapter->lmp->m_next = mp; + Adapter->lmp = Adapter->lmp->m_next; + Adapter->fmp->m_pkthdr.len += Length; } if (EndOfPacket) { - fmp->m_pkthdr.rcvif = ifp; - fmp->m_pkthdr.len = PacketLength; + Adapter->fmp->m_pkthdr.rcvif = ifp; - eh = mtod(fmp, struct ether_header *); + eh = mtod(Adapter->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); + m_adj(Adapter->fmp, sizeof(struct ether_header)); + em_receive_checksum(Adapter, CurrentDescriptor, Adapter->fmp); + ether_input(ifp, eh, Adapter->fmp); - fmp = NULL; - lmp = NULL; - PacketLength = 0; + Adapter->fmp = NULL; + Adapter->lmp = NULL; } } else { Adapter->DroppedPackets++; em_get_buf(rx_buffer, Adapter, mp); - if(fmp != NULL) m_freem(fmp); - fmp = NULL; - lmp = NULL; - PacketLength = 0; + if(Adapter->fmp != NULL) m_freem(Adapter->fmp); + Adapter->fmp = NULL; + Adapter->lmp = NULL; } /* Zero out the receive descriptors status */ - CurrentDescriptor->ReceiveStatus = 0; + CurrentDescriptor->status = 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++; + CurrentDescriptor->buffer_addr = rx_buffer->LowPhysicalAddress; } - /* 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; @@ -2309,13 +1924,11 @@ em_process_receive_interrupts(struct adapter * Adapter) 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)); + E1000_WRITE_REG(&Adapter->shared, RDT, (((u_int32_t) LastDescriptorProcessed - + (u_int32_t) Adapter->FirstRxDescriptor) >> 4)); } return; } -#endif - /********************************************************************* * @@ -2326,21 +1939,21 @@ em_process_receive_interrupts(struct adapter * Adapter) *********************************************************************/ static void em_receive_checksum(struct adapter * Adapter, - PE1000_RECEIVE_DESCRIPTOR RxDescriptor, + struct em_rx_desc * RxDescriptor, struct mbuf *mp) { /* 82543 or newer only */ - if((Adapter->MacType < MAC_LIVENGOOD) || + if((Adapter->shared.mac_type < em_82543) || /* Ignore Checksum bit is set */ - (RxDescriptor->ReceiveStatus & E1000_RXD_STAT_IXSM)) { + (RxDescriptor->status & E1000_RXD_STAT_IXSM)) { RXCSUM_DEBUGOUT("Ignoring checksum"); mp->m_pkthdr.csum_flags = 0; return; } - if (RxDescriptor->ReceiveStatus & E1000_RXD_STAT_IPCS) { + if (RxDescriptor->status & E1000_RXD_STAT_IPCS) { /* Did it pass? */ - if (!(RxDescriptor->Errors & E1000_RXD_ERR_IPE)) { + if (!(RxDescriptor->errors & E1000_RXD_ERR_IPE)) { /* IP Checksum Good */ RXCSUM_DEBUGOUT("Good IP checksum"); mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; @@ -2356,9 +1969,9 @@ em_receive_checksum(struct adapter * Adapter, RXCSUM_DEBUGOUT("IP Checksum not verified"); } - if (RxDescriptor->ReceiveStatus & E1000_RXD_STAT_TCPCS) { + if (RxDescriptor->status & E1000_RXD_STAT_TCPCS) { /* Did it pass? */ - if (!(RxDescriptor->Errors & E1000_RXD_ERR_TCPE)) { + 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); @@ -2379,17 +1992,24 @@ em_receive_checksum(struct adapter * Adapter, static void EnableInterrupts(struct adapter * Adapter) { - E1000_WRITE_REG(Ims, (IMS_ENABLE_MASK)); + E1000_WRITE_REG(&Adapter->shared, IMS, (IMS_ENABLE_MASK)); return; } static void DisableInterrupts(struct adapter * Adapter) { - E1000_WRITE_REG(Imc, (0xffffffff & ~E1000_IMC_RXSEQ)); + E1000_WRITE_REG(&Adapter->shared, IMC, (0xffffffff & ~E1000_IMC_RXSEQ)); return; } +void em_write_pci_cfg(struct em_shared_adapter *Adapter, + uint32_t reg, + uint16_t * value) +{ + pci_write_config(((struct em_osdep *)Adapter->back)->dev, reg, *value, 2); +} + /********************************************************************** * @@ -2401,92 +2021,92 @@ 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); + Adapter->stats.crcerrs += E1000_READ_REG(&Adapter->shared, CRCERRS); + Adapter->stats.symerrs += E1000_READ_REG(&Adapter->shared, SYMERRS); + Adapter->stats.mpc += E1000_READ_REG(&Adapter->shared, MPC); + Adapter->stats.scc += E1000_READ_REG(&Adapter->shared, SCC); + Adapter->stats.ecol += E1000_READ_REG(&Adapter->shared, ECOL); + Adapter->stats.mcc += E1000_READ_REG(&Adapter->shared, MCC); + Adapter->stats.latecol += E1000_READ_REG(&Adapter->shared, LATECOL); + Adapter->stats.colc += E1000_READ_REG(&Adapter->shared, COLC); + Adapter->stats.dc += E1000_READ_REG(&Adapter->shared, DC); + Adapter->stats.sec += E1000_READ_REG(&Adapter->shared, SEC); + Adapter->stats.rlec += E1000_READ_REG(&Adapter->shared, RLEC); + Adapter->stats.xonrxc += E1000_READ_REG(&Adapter->shared, XONRXC); + Adapter->stats.xontxc += E1000_READ_REG(&Adapter->shared, XONTXC); + Adapter->stats.xoffrxc += E1000_READ_REG(&Adapter->shared, XOFFRXC); + Adapter->stats.xofftxc += E1000_READ_REG(&Adapter->shared, XOFFTXC); + Adapter->stats.fcruc += E1000_READ_REG(&Adapter->shared, FCRUC); + Adapter->stats.prc64 += E1000_READ_REG(&Adapter->shared, PRC64); + Adapter->stats.prc127 += E1000_READ_REG(&Adapter->shared, PRC127); + Adapter->stats.prc255 += E1000_READ_REG(&Adapter->shared, PRC255); + Adapter->stats.prc511 += E1000_READ_REG(&Adapter->shared, PRC511); + Adapter->stats.prc1023 += E1000_READ_REG(&Adapter->shared, PRC1023); + Adapter->stats.prc1522 += E1000_READ_REG(&Adapter->shared, PRC1522); + Adapter->stats.gprc += E1000_READ_REG(&Adapter->shared, GPRC); + Adapter->stats.bprc += E1000_READ_REG(&Adapter->shared, BPRC); + Adapter->stats.mprc += E1000_READ_REG(&Adapter->shared, MPRC); + Adapter->stats.gptc += E1000_READ_REG(&Adapter->shared, 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); + Adapter->stats.gorcl += E1000_READ_REG(&Adapter->shared, GORCL); + Adapter->stats.gorch += E1000_READ_REG(&Adapter->shared, GORCH); + Adapter->stats.gotcl += E1000_READ_REG(&Adapter->shared, GOTCL); + Adapter->stats.gotch += E1000_READ_REG(&Adapter->shared, GOTCH); + + Adapter->stats.rnbc += E1000_READ_REG(&Adapter->shared, RNBC); + Adapter->stats.ruc += E1000_READ_REG(&Adapter->shared, RUC); + Adapter->stats.rfc += E1000_READ_REG(&Adapter->shared, RFC); + Adapter->stats.roc += E1000_READ_REG(&Adapter->shared, ROC); + Adapter->stats.rjc += E1000_READ_REG(&Adapter->shared, RJC); + + Adapter->stats.torl += E1000_READ_REG(&Adapter->shared, TORL); + Adapter->stats.torh += E1000_READ_REG(&Adapter->shared, TORH); + Adapter->stats.totl += E1000_READ_REG(&Adapter->shared, TOTL); + Adapter->stats.toth += E1000_READ_REG(&Adapter->shared, TOTH); + + Adapter->stats.tpr += E1000_READ_REG(&Adapter->shared, TPR); + Adapter->stats.tpt += E1000_READ_REG(&Adapter->shared, TPT); + Adapter->stats.ptc64 += E1000_READ_REG(&Adapter->shared, PTC64); + Adapter->stats.ptc127 += E1000_READ_REG(&Adapter->shared, PTC127); + Adapter->stats.ptc255 += E1000_READ_REG(&Adapter->shared, PTC255); + Adapter->stats.ptc511 += E1000_READ_REG(&Adapter->shared, PTC511); + Adapter->stats.ptc1023 += E1000_READ_REG(&Adapter->shared, PTC1023); + Adapter->stats.ptc1522 += E1000_READ_REG(&Adapter->shared, PTC1522); + Adapter->stats.mptc += E1000_READ_REG(&Adapter->shared, MPTC); + Adapter->stats.bptc += E1000_READ_REG(&Adapter->shared, BPTC); + + if (Adapter->shared.mac_type >= em_82543) { + Adapter->stats.algnerrc += E1000_READ_REG(&Adapter->shared, ALGNERRC); + Adapter->stats.rxerrc += E1000_READ_REG(&Adapter->shared, RXERRC); + Adapter->stats.tncrs += E1000_READ_REG(&Adapter->shared, TNCRS); + Adapter->stats.cexterr += E1000_READ_REG(&Adapter->shared, CEXTERR); + Adapter->stats.tsctc += E1000_READ_REG(&Adapter->shared, TSCTC); + Adapter->stats.tsctfc += E1000_READ_REG(&Adapter->shared, TSCTFC); } 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; + ifp->if_ipackets = Adapter->stats.gprc; + ifp->if_opackets = Adapter->stats.gptc; + ifp->if_ibytes = Adapter->stats.gorcl; + ifp->if_obytes = Adapter->stats.gotcl; + ifp->if_imcasts = Adapter->stats.mprc; + ifp->if_collisions = Adapter->stats.colc; /* Rx Errors */ ifp->if_ierrors = Adapter->DroppedPackets + - Adapter->Rxerrc + - Adapter->Crcerrs + - Adapter->Algnerrc + - Adapter->Rlec + Adapter->Rnbc + Adapter->Mpc + Adapter->Cexterr; + Adapter->stats.rxerrc + + Adapter->stats.crcerrs + + Adapter->stats.algnerrc + + Adapter->stats.rlec + Adapter->stats.rnbc + + Adapter->stats.mpc + Adapter->stats.cexterr; /* Tx Errors */ - ifp->if_oerrors = Adapter->Ecol + Adapter->Tuc + Adapter->Latecol; + ifp->if_oerrors = Adapter->stats.ecol + Adapter->stats.latecol; } @@ -2516,26 +2136,26 @@ em_print_hw_stats(struct adapter * Adapter) 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: Symbol errors = %lld\n", unit, Adapter->stats.symerrs); + printf("em%d: Sequence errors = %lld\n", unit, Adapter->stats.sec); + printf("em%d: Defer count = %lld\n", unit, Adapter->stats.dc); + + printf("em%d: Missed Packets = %lld\n", unit, Adapter->stats.mpc); + printf("em%d: Receive No Buffers = %lld\n", unit, Adapter->stats.rnbc); + printf("em%d: Receive length errors = %lld\n", unit, Adapter->stats.rlec); + printf("em%d: Receive errors = %lld\n", unit, Adapter->stats.rxerrc); + printf("em%d: Crc errors = %lld\n", unit, Adapter->stats.crcerrs); + printf("em%d: Alignment errors = %lld\n", unit, Adapter->stats.algnerrc); + printf("em%d: Carrier extension errors = %lld\n", unit, Adapter->stats.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: XON Rcvd = %lld\n", unit, Adapter->stats.xonrxc); + printf("em%d: XON Xmtd = %lld\n", unit, Adapter->stats.xontxc); + printf("em%d: XOFF Rcvd = %lld\n", unit, Adapter->stats.xoffrxc); + printf("em%d: XOFF Xmtd = %lld\n", unit, Adapter->stats.xofftxc); - printf("em%d: Good Packets Rcvd = %ld\n", unit, Adapter->Gprc); - printf("em%d: Good Packets Xmtd = %ld\n", unit, Adapter->Gptc); + printf("em%d: Good Packets Rcvd = %lld\n", unit, Adapter->stats.gprc); + printf("em%d: Good Packets Xmtd = %lld\n", unit, Adapter->stats.gptc); } @@ -2550,7 +2170,7 @@ static void em_clean_transmit_interrupts(struct adapter * Adapter) { struct em_tx_buffer *tx_buffer; - volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor; + struct em_tx_desc *TransmitDescriptor; int s; struct ifnet *ifp; @@ -2583,7 +2203,7 @@ em_clean_transmit_interrupts(struct adapter * Adapter) * If the descriptor done bit is set free tx_buffer and associated * resources */ - if (TransmitDescriptor->Upper.Fields.TransmitStatus & + if (TransmitDescriptor->upper.fields.status & E1000_TXD_STAT_DD) { STAILQ_REMOVE_HEAD(&Adapter->UsedSwTxPacketList, em_tx_entry); diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h index 9a2c266..f840183 100644 --- a/sys/dev/em/if_em.h +++ b/sys/dev/em/if_em.h @@ -1,5 +1,4 @@ /************************************************************************** -************************************************************************** Copyright (c) 2001 Intel Corporation All rights reserved. @@ -32,10 +31,10 @@ 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$ -*************************************************************************** ***************************************************************************/ +/*$FreeBSD$*/ + #ifndef _EM_H_DEFINED_ #define _EM_H_DEFINED_ @@ -93,7 +92,6 @@ $FreeBSD$ #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 @@ -103,12 +101,9 @@ $FreeBSD$ #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 @@ -153,29 +148,6 @@ $FreeBSD$ #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 * @@ -222,10 +194,10 @@ struct adapter { struct arpcom interface_data; struct adapter *next; struct adapter *prev; + struct em_shared_adapter shared; /* FreeBSD operating-system-specific structures */ - bus_space_tag_t bus_space_tag; - bus_space_handle_t bus_space_handle; + struct em_osdep osdep; struct device *dev; struct resource *res_memory; struct resource *res_interrupt; @@ -240,65 +212,29 @@ struct adapter { 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; + struct em_tx_desc *FirstTxDescriptor; + struct em_tx_desc *LastTxDescriptor; + struct em_tx_desc *NextAvailTxDescriptor; + struct em_tx_desc *OldestUsedTxDescriptor; + struct em_tx_desc *TxDescBase; volatile u_int16_t NumTxDescriptorsAvail; u_int16_t NumTxDescriptors; u_int32_t TxdCmd; @@ -307,10 +243,10 @@ struct adapter { 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; + struct em_rx_desc *FirstRxDescriptor; + struct em_rx_desc *LastRxDescriptor; + struct em_rx_desc *NextRxDescriptorToCheck; + struct em_rx_desc *RxDescBase; u_int16_t NumRxDescriptors; u_int16_t NumRxDescriptorsEmpty; u_int16_t NextRxDescriptorToFill; @@ -319,11 +255,8 @@ struct adapter { 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; + struct mbuf *fmp; + struct mbuf *lmp; /* Misc stats maintained by the driver */ @@ -341,69 +274,7 @@ struct adapter { 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; - + struct em_shared_stats stats; }; -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 index 0fdde0f..04b6a72 100644 --- a/sys/dev/em/if_em_fxhw.c +++ b/sys/dev/em/if_em_fxhw.c @@ -1,1457 +1,2009 @@ -/************************************************************************* -************************************************************************** -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 -*/ +/******************************************************************************* + + 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$*/ +/* if_em_fxhw.c + * Shared functions for accessing and configuring the MAC + */ #include <dev/em/if_em_fxhw.h> #include <dev/em/if_em_phy.h> -static void em_shift_out_bits(struct adapter *Adapter, +/****************************************************************************** + * Raises the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +em_raise_clock(struct em_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Raise the clock input to the EEPROM (by setting the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg | E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} - 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); +/****************************************************************************** + * Lowers the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +em_lower_clock(struct em_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Lower the clock input to the EEPROM (by clearing the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg & ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} -void em_adapter_stop(struct adapter *Adapter) +/****************************************************************************** + * Shift data bits out to the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * data - data to send to the EEPROM + * count - number of bits to shift out + *****************************************************************************/ +static void +em_shift_out_bits(struct em_shared_adapter *shared, + uint16_t data, + uint16_t count) { + uint32_t eecd_reg; + uint32_t mask; + + /* We need to shift "count" bits out to the EEPROM. So, value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + */ + mask = 0x01 << (count - 1); + eecd_reg = E1000_READ_REG(shared, EECD); + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + do { + /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", + * and then raising and then lowering the clock (the SK bit controls + * the clock input to the EEPROM). A "0" is shifted out to the EEPROM + * by setting "DI" to "0" and then raising and then lowering the clock. + */ + eecd_reg &= ~E1000_EECD_DI; + + if(data & mask) + eecd_reg |= E1000_EECD_DI; + + E1000_WRITE_REG(shared, EECD, eecd_reg); + + usec_delay(50); + + em_raise_clock(shared, &eecd_reg); + em_lower_clock(shared, &eecd_reg); + + mask = mask >> 1; + + } while(mask); + + /* We leave the "DI" bit set to "0" when we leave this routine. */ + eecd_reg &= ~E1000_EECD_DI; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} - u32 IcrContents; +/****************************************************************************** + * Shift data bits in from the EEPROM + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static uint16_t +em_shift_in_bits(struct em_shared_adapter *shared) +{ + uint32_t eecd_reg; + uint32_t i; + uint16_t data; - u16 PciCommandWord; + /* In order to read a register from the EEPROM, we need to shift 16 bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the "DO" + * bit. During this "shifting in" process the "DI" bit should always be + * clear.. + */ - DEBUGFUNC("em_adapter_stop") + eecd_reg = E1000_READ_REG(shared, EECD); - if (Adapter->AdapterStopped) { - DEBUGOUT - ("Exiting because the adapter is already stopped!!!\n"); - return; - } + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; - Adapter->AdapterStopped = 1; + for(i = 0; i < 16; i++) { + data = data << 1; + em_raise_clock(shared, &eecd_reg); - if (Adapter->MacType == MAC_WISEMAN_2_0) { - if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { - DEBUGOUT - ("Disabling MWI on rev 2.0 Wiseman silicon\n"); + eecd_reg = E1000_READ_REG(shared, EECD); - PciCommandWord = - Adapter-> - PciCommandWord & ~CMD_MEM_WRT_INVALIDATE; + eecd_reg &= ~(E1000_EECD_DI); + if(eecd_reg & E1000_EECD_DO) + data |= 1; - WritePciConfigWord(PCI_COMMAND_REGISTER, - &PciCommandWord); - } - } + em_lower_clock(shared, &eecd_reg); + } - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(Imc, 0xffffffff); + return data; +} - E1000_WRITE_REG(Rctl, 0); - E1000_WRITE_REG(Tctl, 0); +/****************************************************************************** + * Prepares EEPROM for access + * + * shared - Struct containing variables accessed by shared code + * + * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This + * function should be called before issuing a command to the EEPROM. + *****************************************************************************/ +static void +em_setup_eeprom(struct em_shared_adapter *shared) +{ + uint32_t eecd_reg; - Adapter->TbiCompatibilityOn = 0; + eecd_reg = E1000_READ_REG(shared, EECD); - DelayInMilliseconds(10); + /* Clear SK and DI */ + eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI); + E1000_WRITE_REG(shared, EECD, eecd_reg); - DEBUGOUT("Issuing a global reset to MAC\n"); - E1000_WRITE_REG(Ctrl, E1000_CTRL_RST); + /* Set CS */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} - DelayInMilliseconds(10); +/****************************************************************************** + * Returns EEPROM to a "standby" state + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +em_standby_eeprom(struct em_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Deselct EEPROM */ + eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock high */ + eecd_reg |= E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Select EEPROM */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock low */ + eecd_reg &= ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + return; +} - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(Imc, 0xffffffff); +/****************************************************************************** + * Raises then lowers the EEPROM's clock pin + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +em_clock_eeprom(struct em_shared_adapter *shared) +{ + uint32_t eecd_reg; - IcrContents = E1000_READ_REG(Icr); + eecd_reg = E1000_READ_REG(shared, EECD); - if (Adapter->MacType == MAC_WISEMAN_2_0) { - if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { - WritePciConfigWord(PCI_COMMAND_REGISTER, - &Adapter->PciCommandWord); - } - } + /* Rising edge of clock */ + eecd_reg |= E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + /* Falling edge of clock */ + eecd_reg &= ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + return; } -u8 em_initialize_hardware(struct adapter *Adapter) - { - u32 i; - u16 PciCommandWord; - u8 Status; - u32 RegisterValue; - - DEBUGFUNC("em_initialize_hardware"); +/****************************************************************************** + * Terminates a command by lowering the EEPROM's chip select pin + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +em_cleanup_eeprom(struct em_shared_adapter *shared) +{ + uint32_t eecd_reg; - if (Adapter->MacType != MAC_LIVENGOOD) { + eecd_reg = E1000_READ_REG(shared, EECD); - Adapter->TbiCompatibilityEnable = 0; - } + eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_DI); - 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 { + E1000_WRITE_REG(shared, EECD, eecd_reg); - Adapter->MediaType = MEDIA_TYPE_FIBER; - } + em_clock_eeprom(shared); + return; +} - DEBUGOUT("Initializing the IEEE VLAN\n"); - E1000_WRITE_REG(Vet, 0); +/****************************************************************************** + * Waits for the EEPROM to finish the current command. + * + * shared - Struct containing variables accessed by shared code + * + * The command is done when the EEPROM's data out pin goes high. + *****************************************************************************/ +static uint16_t +em_wait_eeprom_command(struct em_shared_adapter *shared) +{ + uint32_t eecd_reg; + uint32_t i; - em_clear_vfta(Adapter); - if (Adapter->MacType == MAC_WISEMAN_2_0) { + /* Toggle the CS line. This in effect tells to EEPROM to actually execute + * the command in question. + */ + em_standby_eeprom(shared); - if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { - DEBUGOUT - ("Disabling MWI on rev 2.0 Wiseman silicon\n"); + /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will + * signal that the command has been completed by raising the DO signal. + * If DO does not go high in 10 milliseconds, then error out. + */ + for(i = 0; i < 200; i++) { + eecd_reg = E1000_READ_REG(shared, EECD); - PciCommandWord = - Adapter-> - PciCommandWord & ~CMD_MEM_WRT_INVALIDATE; + if(eecd_reg & E1000_EECD_DO) + return (TRUE); - WritePciConfigWord(PCI_COMMAND_REGISTER, - &PciCommandWord); - } + usec_delay(50); + } + ASSERT(0); + return (FALSE); +} - E1000_WRITE_REG(Rctl, E1000_RCTL_RST); +/****************************************************************************** + * Forces the MAC's flow control settings. + * + * shared - Struct containing variables accessed by shared code + * + * Sets the TFCE and RFCE bits in the device control register to reflect + * the adapter settings. TFCE and RFCE need to be explicitly set by + * software when a Copper PHY is used because autonegotiation is managed + * by the PHY rather than the MAC. Software must also configure these + * bits when link is forced on a fiber connection. + *****************************************************************************/ +static void +em_force_mac_fc(struct em_shared_adapter *shared) +{ + uint32_t ctrl_reg; - DelayInMilliseconds(5); - } + DEBUGFUNC("em_force_mac_fc"); - em_init_rx_addresses(Adapter); + /* Get the current configuration of the Device Control Register */ + ctrl_reg = E1000_READ_REG(shared, CTRL); - if (Adapter->MacType == MAC_WISEMAN_2_0) { - E1000_WRITE_REG(Rctl, 0); + /* Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "shared->fc" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ - DelayInMilliseconds(1); + switch (shared->fc) { + case em_fc_none: /* 0 */ - if (Adapter->PciCommandWord & CMD_MEM_WRT_INVALIDATE) { - WritePciConfigWord(PCI_COMMAND_REGISTER, - &Adapter->PciCommandWord); - } + ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; - } + case em_fc_rx_pause: /* 1 */ - DEBUGOUT("Zeroing the MTA\n"); - for (i = 0; i < E1000_MC_TBL_SIZE; i++) { - E1000_WRITE_REG(Mta[i], 0); - } + ctrl_reg &= (~E1000_CTRL_TFCE); + ctrl_reg |= E1000_CTRL_RFCE; + break; - Status = em_setup_flow_control_and_link(Adapter); + case em_fc_tx_pause: /* 2 */ - em_clear_hw_stats_counters(Adapter); + ctrl_reg &= (~E1000_CTRL_RFCE); + ctrl_reg |= E1000_CTRL_TFCE; + break; - return (Status); -} + case em_fc_full: /* 3 */ -void em_init_rx_addresses(struct adapter *Adapter) - { - u32 i; - u32 HwLowAddress; - u32 HwHighAddress; + ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; - DEBUGFUNC("em_init_rx_addresses") + default: - DEBUGOUT("Programming IA into RAR[0]\n"); - HwLowAddress = (Adapter->CurrentNetAddress[0] | - (Adapter->CurrentNetAddress[1] << 8) | - (Adapter->CurrentNetAddress[2] << 16) | - (Adapter->CurrentNetAddress[3] << 24)); + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); - HwHighAddress = (Adapter->CurrentNetAddress[4] | - (Adapter->CurrentNetAddress[5] << 8) | - E1000_RAH_AV); + break; + } - E1000_WRITE_REG(Rar[0].Low, HwLowAddress); - E1000_WRITE_REG(Rar[0].High, HwHighAddress); + /* Disable TX Flow Control for 82542 (rev 2.0) */ + if(shared->mac_type == em_82542_rev2_0) + ctrl_reg &= (~E1000_CTRL_TFCE); - 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; + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; } -void em_multicast_address_list_update(struct adapter *Adapter, - u8 * MulticastAddressList, - u32 MulticastAddressCount, - u32 Padding) +/****************************************************************************** + * Reset the transmit and receive units; mask and clear all interrupts. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_adapter_stop(struct em_shared_adapter *shared) { +#if DBG + uint32_t ctrl_reg; +#endif + uint32_t icr_reg; + uint16_t pci_cmd_word; + + DEBUGFUNC("em_shared_adapter_stop"); + + /* If we are stopped or resetting exit gracefully and wait to be + * started again before accessing the hardware. + */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is already stopped!!!\n"); + return; + } - u32 HashValue; - u32 i; - u32 RarUsedCount = 1; + /* Set the Adapter Stopped flag so other driver functions stop + * touching the Hardware. + */ + shared->adapter_stopped = TRUE; - DEBUGFUNC("em_multicast_address_list_update"); + /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ + if(shared->mac_type == em_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); - Adapter->NumberOfMcAddresses = MulticastAddressCount; + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; - 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); + em_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); } - - DEBUGOUT(" Clearing MTA\n"); - for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { - E1000_WRITE_REG(Mta[i], 0); + } + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Disable the Transmit and Receive units. Then delay to allow + * any pending transactions to complete before we hit the MAC with + * the global reset. + */ + E1000_WRITE_REG(shared, RCTL, 0); + E1000_WRITE_REG(shared, TCTL, 0); + + /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */ + shared->tbi_compatibility_on = FALSE; + + msec_delay(10); + + /* Issue a global reset to the MAC. This will reset the chip's + * transmit, receive, DMA, and link units. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + DEBUGOUT("Issuing a global reset to MAC\n"); + E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST); + + /* Delay a few ms just to allow the reset to complete */ + msec_delay(10); + +#if DBG + /* Make sure the self-clearing global reset bit did self clear */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ASSERT(!(ctrl_reg & E1000_CTRL_RST)); +#endif + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Clear any pending interrupt events. */ + icr_reg = E1000_READ_REG(shared, ICR); + + /* If MWI was previously enabled, reenable it. */ + if(shared->mac_type == em_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + em_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); } - - 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"); + } + return; } -u32 em_hash_multicast_address(struct adapter *Adapter, - u8 * MulticastAddress) - { - u32 HashValue = 0; +/****************************************************************************** + * Performs basic configuration of the adapter. + * + * shared - Struct containing variables accessed by shared code + * + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes the receive address registers, + * multicast table, and VLAN filter table. Calls routines to setup link + * configuration and flow control settings. Clears all on-chip counters. Leaves + * the transmit and receive units disabled and uninitialized. + *****************************************************************************/ +boolean_t +em_init_hw(struct em_shared_adapter *shared) +{ + uint32_t status_reg; + uint32_t i; + uint16_t pci_cmd_word; + boolean_t status; + + DEBUGFUNC("em_init_hw"); + + /* Set the Media Type and exit with error if it is not valid. */ + if(shared->mac_type != em_82543) { + /* tbi_compatibility is only valid on 82543 */ + shared->tbi_compatibility_en = FALSE; + } + + if(shared->mac_type >= em_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_TBIMODE) { + shared->media_type = em_media_type_fiber; + /* tbi_compatibility not valid on fiber */ + shared->tbi_compatibility_en = FALSE; + } else { + shared->media_type = em_media_type_copper; + } + } else { + /* This is an 82542 (fiber only) */ + shared->media_type = em_media_type_fiber; + } + + /* Disabling VLAN filtering. */ + DEBUGOUT("Initializing the IEEE VLAN\n"); + E1000_WRITE_REG(shared, VET, 0); + + em_clear_vfta(shared); + + /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ + if(shared->mac_type == em_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; + em_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); + } + E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST); - switch (Adapter->MulticastFilterType) { + msec_delay(5); + } - case 0: + /* Setup the receive address. This involves initializing all of the Receive + * Address Registers (RARs 0 - 15). + */ + em_init_rx_addrs(shared); - HashValue = ((MulticastAddress[4] >> 4) | - (((u16) MulticastAddress[5]) << 4)); + /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ + if(shared->mac_type == em_82542_rev2_0) { + E1000_WRITE_REG(shared, RCTL, 0); - break; + msec_delay(1); - case 1: - HashValue = ((MulticastAddress[4] >> 3) | - (((u16) MulticastAddress[5]) << 5)); + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + em_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); + } + } + + /* Zero out the Multicast HASH table */ + DEBUGOUT("Zeroing the MTA\n"); + for(i = 0; i < E1000_MC_TBL_SIZE; i++) + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + + /* Call a subroutine to configure the link and setup flow control. */ + status = em_setup_fc_and_link(shared); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + em_clear_hw_cntrs(shared); + + shared->large_eeprom = FALSE; + shared->low_profile = FALSE; + if(shared->mac_type == em_82544) { + i = em_read_eeprom(shared, E1000_EEPROM_LED_LOGIC); + if(i & E1000_EEPROM_SWDPIN0) + shared->low_profile = TRUE; + } + + return (status); +} - break; +/****************************************************************************** + * Initializes receive address filters. + * + * shared - Struct containing variables accessed by shared code + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive addresss registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + *****************************************************************************/ +void +em_init_rx_addrs(struct em_shared_adapter *shared) +{ + uint32_t i; + uint32_t addr_low; + uint32_t addr_high; - case 2: - HashValue = ((MulticastAddress[4] >> 2) | - (((u16) MulticastAddress[5]) << 6)); + DEBUGFUNC("em_init_rx_addrs"); - break; + /* Setup the receive address. */ + DEBUGOUT("Programming MAC Address into RAR[0]\n"); + addr_low = (shared->mac_addr[0] | + (shared->mac_addr[1] << 8) | + (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24)); - case 3: - HashValue = ((MulticastAddress[4]) | - (((u16) MulticastAddress[5]) << 8)); + addr_high = (shared->mac_addr[4] | + (shared->mac_addr[5] << 8) | E1000_RAH_AV); - break; - } + E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low); + E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high); - HashValue &= 0xFFF; - return (HashValue); + /* Zero out the other 15 receive addresses. */ + DEBUGOUT("Clearing RAR[1-15]\n"); + for(i = 1; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + return; } -void em_mta_set(struct adapter *Adapter, u32 HashValue) +/****************************************************************************** + * Updates the MAC's list of multicast addresses. + * + * shared - Struct containing variables accessed by shared code + * mc_addr_list - the list of new multicast addresses + * mc_addr_count - number of addresses + * pad - number of bytes between addresses in the list + * + * The given list replaces any existing list. Clears the last 15 receive + * address registers and the multicast table. Uses receive address registers + * for the first 15 multicast addresses, and hashes the rest into the + * multicast table. + *****************************************************************************/ +void +em_mc_addr_list_update(struct em_shared_adapter *shared, + uint8_t *mc_addr_list, + uint32_t mc_addr_count, + uint32_t pad) { - 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 & 0x1) == 1)) { - Temp = E1000_READ_REG(Mta[HashReg - 1]); - E1000_WRITE_REG(Mta[HashReg], HashValue); - E1000_WRITE_REG(Mta[HashReg - 1], Temp); + uint32_t hash_value; + uint32_t i; + uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ + + DEBUGFUNC("em_mc_addr_list_update"); + + /* Set the new number of MC addresses that we are being requested to use. */ + shared->num_mc_addrs = mc_addr_count; + + /* Clear RAR[1-15] */ + DEBUGOUT(" Clearing RAR[1-15]\n"); + for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + + /* Clear the MTA */ + DEBUGOUT(" Clearing MTA\n"); + for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + } + + /* Add the new addresses */ + for(i = 0; i < mc_addr_count; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i, + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]); + + hash_value = em_hash_mc_addr(shared, + mc_addr_list + + (i * (ETH_LENGTH_OF_ADDRESS + pad))); + + DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); + + /* Place this multicast address in the RAR if there is room, * + * else put it in the MTA + */ + if(rar_used_count < E1000_RAR_ENTRIES) { + em_rar_set(shared, + mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)), + rar_used_count); + rar_used_count++; } else { - E1000_WRITE_REG(Mta[HashReg], MtaRegisterValue); + em_mta_set(shared, hash_value); } + } + DEBUGOUT("MC Update Complete\n"); + return; } -void em_rar_set(struct adapter *Adapter, - u8 * MulticastAddress, u32 RarIndex) +/****************************************************************************** + * Hashes an address to determine its location in the multicast table + * + * shared - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + *****************************************************************************/ +uint32_t +em_hash_mc_addr(struct em_shared_adapter *shared, + uint8_t *mc_addr) { - 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); + uint32_t hash_value = 0; + + /* The portion of the address that is used for the hash table is + * determined by the mc_filter_type setting. + */ + switch (shared->mc_filter_type) { + /* [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB - According to H/W docs */ + case 0: + /* [47:36] i.e. 0x563 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + break; + case 1: /* [46:35] i.e. 0xAC6 for above example address */ + hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + break; + case 2: /* [45:34] i.e. 0x5D8 for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + break; + case 3: /* [43:32] i.e. 0x634 for above example address */ + hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + break; + } + + hash_value &= 0xFFF; + return (hash_value); } -void em_write_vfta(struct adapter *Adapter, u32 Offset, u32 Value) - { - u32 Temp; - - if ((Adapter->MacType == MAC_CORDOVA) && ((Offset & 0x1) == 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); - +/****************************************************************************** + * Sets the bit in the multicast table corresponding to the hash value. + * + * shared - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + *****************************************************************************/ +void +em_mta_set(struct em_shared_adapter *shared, + uint32_t hash_value) +{ + uint32_t hash_bit, hash_reg; + uint32_t mta_reg; + uint32_t temp; + + /* The MTA is a register array of 128 32-bit registers. + * It is treated like an array of 4096 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 5) & 0x7F; + hash_bit = hash_value & 0x1F; + + mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg); + + mta_reg |= (1 << hash_bit); + + /* If we are on an 82544 and we are trying to write an odd offset + * in the MTA, save off the previous entry before writing and + * restore the old value after writing. + */ + if((shared->mac_type == em_82544) && ((hash_reg & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1)); + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + } + return; } -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); +/****************************************************************************** + * Puts an ethernet address into a receive address register. + * + * shared - Struct containing variables accessed by shared code + * addr - Address to put into receive address register + * index - Receive address register to write + *****************************************************************************/ +void +em_rar_set(struct em_shared_adapter *shared, + uint8_t *addr, + uint32_t index) +{ + uint32_t rar_low, rar_high; - DEBUGOUT1("After fix-ups FlowControl is now = %x\n", - Adapter->FlowControl); + /* HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((uint32_t) addr[0] | + ((uint32_t) addr[1] << 8) | + ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24)); - if (Adapter->MacType >= MAC_LIVENGOOD) { - ExtDevControlReg = - ((TempEepromWord & EEPROM_WORD0F_SWPDIO_EXT) << - SWDPIO__EXT_SHIFT); - E1000_WRITE_REG(Exct, ExtDevControlReg); - } + rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV); - if (Adapter->MacType >= MAC_LIVENGOOD) { - if (Adapter->MediaType == MEDIA_TYPE_FIBER) { - Status = - em_setup_pcs_link(Adapter, DeviceControlReg); - - } else { + E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low); + E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high); + return; +} - Status = em_phy_setup(Adapter, DeviceControlReg); - } - } else { - Status = em_setup_pcs_link(Adapter, DeviceControlReg); - } +/****************************************************************************** + * Writes a value to the specified offset in the VLAN filter table. + * + * shared - Struct containing variables accessed by shared code + * offset - Offset in VLAN filer table to write + * value - Value to write into VLAN filter table + *****************************************************************************/ +void +em_write_vfta(struct em_shared_adapter *shared, + uint32_t offset, + uint32_t value) +{ + uint32_t temp; + + if((shared->mac_type == em_82544) && ((offset & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1)); + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + } + return; +} - DEBUGOUT - ("Initializing the Flow Control address, type and timer regs\n"); +/****************************************************************************** + * Clears the VLAN filer table + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_clear_vfta(struct em_shared_adapter *shared) +{ + uint32_t offset; - 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); + for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0); + return; +} - if (!(Adapter->FlowControl & FLOW_CONTROL_TRANSMIT_PAUSE)) { - E1000_WRITE_REG(Fcrtl, 0); - E1000_WRITE_REG(Fcrth, 0); +/****************************************************************************** + * Configures flow control and link settings. + * + * shared - Struct containing variables accessed by shared code + * + * Determines which flow control settings to use. Calls the apropriate media- + * specific link configuration function. Configures the flow control settings. + * Assuming the adapter has a valid link partner, a valid link should be + * established. Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + *****************************************************************************/ +boolean_t +em_setup_fc_and_link(struct em_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t eecd_reg; + uint32_t ctrl_ext_reg; + boolean_t status = TRUE; + + DEBUGFUNC("em_setup_fc_and_link"); + + /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the + * EEPROM. Store these bits in a variable that we will later write + * to the Device Control Register (CTRL). + */ + eecd_reg = em_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG); + + ctrl_reg = + (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) | + ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT)); + + /* Set the PCI priority bit correctly in the CTRL register. This + * determines if the adapter gives priority to receives, or if it + * gives equal priority to transmits and receives. + */ + if(shared->dma_fairness) + ctrl_reg |= E1000_CTRL_PRIOR; + + /* Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable shared->fc will + * be initialized based on a value in the EEPROM. + */ + eecd_reg = em_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG); + + if(shared->fc > em_fc_full) { + if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0) + shared->fc = em_fc_none; + else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) + shared->fc = em_fc_tx_pause; + else + shared->fc = em_fc_full; + } + + /* We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + shared->original_fc = shared->fc; + + if(shared->mac_type == em_82542_rev2_0) + shared->fc &= (~em_fc_tx_pause); + + if((shared->mac_type < em_82543) && (shared->report_tx_early == 1)) + shared->fc &= (~em_fc_rx_pause); + + DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc); + + /* Take the 4 bits from EEPROM word 0x0F that determine the initial + * polarity value for the SW controlled pins, and setup the + * Extended Device Control reg with that info. + * This is needed because one of the SW controlled pins is used for + * signal detection. So this should be done before em_setup_pcs_link() + * or em_phy_setup() is called. + */ + if(shared->mac_type >= em_82543) { + ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT) + << SWDPIO__EXT_SHIFT); + E1000_WRITE_REG(shared, CTRLEXT, ctrl_ext_reg); + } + + /* Call the necessary subroutine to configure the link. */ + if(shared->media_type == em_media_type_fiber) + status = em_setup_pcs_link(shared, ctrl_reg); + else + status = em_phy_setup(shared, ctrl_reg); + + /* Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); + + E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW); + E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time); + + /* Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames in not enabled, then these + * registers will be set to 0. + */ + if(!(shared->fc & em_fc_tx_pause)) { + E1000_WRITE_REG(shared, FCRTL, 0); + E1000_WRITE_REG(shared, FCRTH, 0); + } else { + /* We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of XON frames. + */ + if(shared->fc_send_xon) { + E1000_WRITE_REG(shared, FCRTL, + (shared->fc_low_water | E1000_FCRTL_XONE)); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); } 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); - } + E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); } - - return (Status); + } + 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); +/****************************************************************************** + * Sets up link for a fiber based adapter + * + * shared - Struct containing variables accessed by shared code + * ctrl_reg - Current value of the device control register + * + * Manipulates Physical Coding Sublayer functions in order to configure + * link. Assumes the hardware has been previously reset and the transmitter + * and receiver are not enabled. + *****************************************************************************/ +boolean_t +em_setup_pcs_link(struct em_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint32_t status_reg; + uint32_t tctl_reg; + uint32_t txcw_reg = 0; + uint32_t i; + + DEBUGFUNC("em_setup_pcs_link"); + + /* Setup the collsion distance. Since this is configuring the + * TBI it is assumed that we are in Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + i = E1000_FDX_COLLISION_DISTANCE; + i <<= E1000_COLD_SHIFT; + tctl_reg |= i; + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Check for a software override of the flow control settings, and + * setup the device accordingly. If auto-negotiation is enabled, + * then software will have to set the "PAUSE" bits to the correct + * value in the Tranmsit Config Word Register (TXCW) and re-start + * auto-negotiation. However, if auto-negotiation is disabled, + * then software will have to manually configure the two flow + * control enable bits in the CTRL register. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case em_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD); + break; + case em_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * we will disable the adapter's ability to send PAUSE + * frames. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + case em_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + break; + case em_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Since auto-negotiation is enabled, take the link out of reset. + * (the link will be in reset, because we previously reset the + * chip). This will restart auto-negotiation. If auto-neogtiation + * is successful then the link-up status bit will be set and the + * flow control enable bits (RFCE and TFCE) will be set according + * to their negotiated value. + */ + DEBUGOUT("Auto-negotiation enabled\n"); + + E1000_WRITE_REG(shared, TXCW, txcw_reg); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + shared->txcw_reg = txcw_reg; + msec_delay(1); + + /* If we have a signal then poll for a "Link-Up" indication in the + * Device Status Register. Time-out if a link isn't seen in 500 + * milliseconds seconds (Auto-negotiation should complete in less + * than 500 milliseconds even if the other end is doing it in SW). + */ + if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) { + + DEBUGOUT("Looking for Link\n"); + for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { + msec_delay(10); + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_LU) 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"); - } + if(i == (LINK_UP_TIMEOUT / 10)) { + /* AutoNeg failed to achieve a link, so we'll call the + * "CheckForLink" routine. This routine will force the link + * up if we have "signal-detect". This will allow us to + * communicate with non-autonegotiating link partners. + */ + DEBUGOUT("Never got a valid link from auto-neg!!!\n"); + + shared->autoneg_failed = 1; + em_check_for_link(shared); + shared->autoneg_failed = 0; } else { - DEBUGOUT("No Signal Detected\n"); + shared->autoneg_failed = 0; + DEBUGOUT("Valid Link Found\n"); } + } else { + DEBUGOUT("No Signal Detected\n"); + } - return (1); + return (TRUE); } -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); +/****************************************************************************** + * Configures flow control settings after link is established + * + * shared - Struct containing variables accessed by shared code + * + * Should be called immediately after a valid link has been established. + * Forces MAC flow control settings if link was forced. When in MII/GMII mode + * and autonegotiation is enabled, the MAC flow control settings will be set + * based on the flow control negotiated by the PHY. In TBI mode, the TFCE + * and RFCE bits will be automaticaly set to the negotiated flow control mode. + *****************************************************************************/ +void +em_config_fc_after_link_up(struct em_shared_adapter *shared) +{ + uint16_t mii_status_reg; + uint16_t mii_nway_adv_reg; + uint16_t mii_nway_lp_ability_reg; + uint16_t speed; + uint16_t duplex; + + DEBUGFUNC("em_config_fc_after_link_up"); + + /* Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if(((shared->media_type == em_media_type_fiber) + && (shared->autoneg_failed)) + || ((shared->media_type == em_media_type_copper) + && (!shared->autoneg))) { + em_force_mac_fc(shared); + } + + /* Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if((shared->media_type == em_media_type_copper) && shared->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement Register + * (Address 4) and the Auto_Negotiation Base Page Ability + * Register (Address 5) to determine how flow control was + * negotiated. + */ + mii_nway_adv_reg = em_read_phy_reg(shared, + PHY_AUTONEG_ADV); + mii_nway_lp_ability_reg = em_read_phy_reg(shared, + PHY_LP_ABILITY); + + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | em_fc_none + * 0 | 1 | 0 | DC | em_fc_none + * 0 | 1 | 1 | 0 | em_fc_none + * 0 | 1 | 1 | 1 | em_fc_tx_pause + * 1 | 0 | 0 | DC | em_fc_none + * 1 | DC | 1 | DC | em_fc_full + * 1 | 1 | 0 | 0 | em_fc_none + * 1 | 1 | 0 | 1 | em_fc_rx_pause + * + */ + /* Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | em_fc_full + * + */ + if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if(shared->original_fc == em_fc_full) { + shared->fc = em_fc_full; + DEBUGOUT("Flow Control = FULL.\r\n"); } else { - DEBUGOUT - ("Copper PHY and Auto Neg has not completed.\r\n"); + shared->fc = em_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); } + } + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | em_fc_tx_pause + * + */ + else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = em_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | em_fc_rx_pause + * + */ + else if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = em_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if(shared->original_fc == em_fc_none || + shared->original_fc == em_fc_tx_pause) { + shared->fc = em_fc_none; + DEBUGOUT("Flow Control = NONE.\r\n"); + } else { + shared->fc = em_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + em_get_speed_and_duplex(shared, &speed, &duplex); + + if(duplex == HALF_DUPLEX) + shared->fc = em_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + em_force_mac_fc(shared); + } else { + DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n"); } + } + return; } -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; +/****************************************************************************** + * Checks to see if the link status of the hardware has changed. + * + * shared - Struct containing variables accessed by shared code + * + * Called by any function that needs to check the link status of the adapter. + *****************************************************************************/ +void +em_check_for_link(struct em_shared_adapter *shared) +{ + uint32_t rxcw_reg; + uint32_t ctrl_reg; + uint32_t status_reg; + uint32_t rctl_reg; + uint16_t phy_data; + uint16_t lp_capability; + + DEBUGFUNC("em_check_for_link"); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + status_reg = E1000_READ_REG(shared, STATUS); + rxcw_reg = E1000_READ_REG(shared, RXCW); + + /* If we have a copper PHY then we only want to go out to the PHY + * registers to see if Auto-Neg has completed and/or if our link + * status has changed. The get_link_status flag will be set if we + * receive a Link Status Change interrupt or we have Rx Sequence + * Errors. + */ + if(shared->media_type == em_media_type_copper + && shared->get_link_status) { + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + * Read the register twice since the link bit is sticky. + */ + phy_data = em_read_phy_reg(shared, PHY_STATUS); + phy_data = em_read_phy_reg(shared, PHY_STATUS); + + if(phy_data & MII_SR_LINK_STATUS) { + shared->get_link_status = FALSE; + } else { + DEBUGOUT("**** CFL - No link detected. ****\r\n"); + return; } - 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; + /* If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if(!shared->autoneg) { + return; + } - default: - DEBUGOUT("CFL - Invalid PHY detected.\r\n"); + switch (shared->phy_id) { + case M88E1000_12_PHY_ID: + case M88E1000_14_PHY_ID: + case M88E1000_I_PHY_ID: + /* We have a M88E1000 PHY and Auto-Neg is enabled. If we + * have Si on board that is 82544 or newer, Auto + * Speed Detection takes care of MAC speed/duplex + * configuration. So we only need to configure Collision + * Distance in the MAC. Otherwise, we need to force + * speed/duplex on the MAC to the current PHY speed/duplex + * settings. + */ + if(shared->mac_type >= em_82544) { + DEBUGOUT("CFL - Auto-Neg complete."); + DEBUGOUT("Configuring Collision Distance."); + em_config_collision_dist(shared); + } else { + /* Read the Phy Specific Status register to get the + * resolved speed/duplex settings. Then call + * em_config_mac_to_phy which will retrieve + * PHY register information and configure the MAC to + * equal the negotiated speed/duplex. + */ + phy_data = em_read_phy_reg(shared, + M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("CFL - Auto-Neg complete. phy_data = %x\r\n", + phy_data); + em_config_mac_to_phy(shared, phy_data); + } + + /* Configure Flow Control now that Auto-Neg has completed. + * We need to first restore the users desired Flow + * Control setting since we may have had to re-autoneg + * with a different link partner. + */ + em_config_fc_after_link_up(shared); + break; + default: + DEBUGOUT("CFL - Invalid PHY detected.\r\n"); + + } /* end switch statement */ + + /* At this point we know that we are on copper, link is up, + * and we are auto-neg'd. These are pre-conditions for checking + * the link parter capabilities register. We use the link partner + * capabilities to determine if TBI Compatibility needs to be turned on + * or turned off. If the link partner advertises any speed in addition + * to Gigabit, then we assume that they are GMII-based and TBI + * compatibility is not needed. + * If no other speeds are advertised, then we assume the link partner + * is TBI-based and we turn on TBI Compatibility. + */ + if(shared->tbi_compatibility_en) { + lp_capability = em_read_phy_reg(shared, PHY_LP_ABILITY); + if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | + NWAY_LPAR_10T_FD_CAPS | + NWAY_LPAR_100TX_HD_CAPS | + NWAY_LPAR_100TX_FD_CAPS | + NWAY_LPAR_100T4_CAPS)) { + /* If our link partner advertises below Gig, then they do not + * need the special Tbi Compatibility mode. + */ + if(shared->tbi_compatibility_on) { + /* If we previously were in the mode, turn it off, now. */ + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg &= ~E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); + shared->tbi_compatibility_on = FALSE; } - - 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 the mode is was previously off, turn it on. + * For compatibility with a suspected Tbi link partners, + * we will store bad packets. + * (Certain frames have an additional byte on the end and will + * look like CRC errors to to the hardware). + */ + if(!shared->tbi_compatibility_on) { + shared->tbi_compatibility_on = TRUE; + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg |= E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); } + } } - - 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); - + } /* end if em_media_type_copper statement */ + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate) and the cable is plugged in since we don't + * have Loss-Of-Signal (we HAVE a signal) and our link partner is + * not trying to AutoNeg with us (we are receiving idles/data + * then we need to force our link to connect to a non + * auto-negotiating link partner. We also need to give + * auto-negotiation time to complete in case the cable was just + * plugged in. The autoneg_failed flag does this. + */ + else if((shared->media_type == em_media_type_fiber) && /* Fiber PHY */ + (!(status_reg & E1000_STATUS_LU)) && /* no link and */ + (!(ctrl_reg & E1000_CTRL_SWDPIN1)) && /* we have signal */ + (!(rxcw_reg & E1000_RXCW_C))) { /* and rxing idle/data */ + if(shared->autoneg_failed == 0) { /* given AutoNeg time */ + shared->autoneg_failed = 1; + return; } - 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"); + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n"); + + /* Disable auto-negotiation in the TXCW register */ + E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Configure Flow Control after forcing link up. */ + em_config_fc_after_link_up(shared); + + } else if((shared->media_type == em_media_type_fiber) && /* Fiber */ + (ctrl_reg & E1000_CTRL_SLU) && /* we have forced link */ + (rxcw_reg & E1000_RXCW_C)) { /* and Rxing /C/ ordered sets */ + /* If we are forcing link and we are receiving /C/ ordered sets, + * then re-enable auto-negotiation in the RXCW register and + * disable forced link in the Device Control register in an attempt + * to AutoNeg with our link partner. + */ + DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); + + /* Enable auto-negotiation in the TXCW register and stop + * forcing link. + */ + E1000_WRITE_REG(shared, TXCW, shared->txcw_reg); + + E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU)); + } + + return; +} /* CheckForLink */ + +/****************************************************************************** + * Clears all hardware statistics counters. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_clear_hw_cntrs(struct em_shared_adapter *shared) +{ + volatile uint32_t temp_reg; - E1000_WRITE_REG(Txcw, Adapter->TxcwRegValue); - - E1000_WRITE_REG(Ctrl, (CtrlRegValue & ~E1000_CTRL_SLU)); - } + DEBUGFUNC("em_clear_hw_cntrs"); + /* if we are stopped or resetting exit gracefully */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is stopped!!!\n"); + return; + } + + temp_reg = E1000_READ_REG(shared, CRCERRS); + temp_reg = E1000_READ_REG(shared, SYMERRS); + temp_reg = E1000_READ_REG(shared, MPC); + temp_reg = E1000_READ_REG(shared, SCC); + temp_reg = E1000_READ_REG(shared, ECOL); + temp_reg = E1000_READ_REG(shared, MCC); + temp_reg = E1000_READ_REG(shared, LATECOL); + temp_reg = E1000_READ_REG(shared, COLC); + temp_reg = E1000_READ_REG(shared, DC); + temp_reg = E1000_READ_REG(shared, SEC); + temp_reg = E1000_READ_REG(shared, RLEC); + temp_reg = E1000_READ_REG(shared, XONRXC); + temp_reg = E1000_READ_REG(shared, XONTXC); + temp_reg = E1000_READ_REG(shared, XOFFRXC); + temp_reg = E1000_READ_REG(shared, XOFFTXC); + temp_reg = E1000_READ_REG(shared, FCRUC); + temp_reg = E1000_READ_REG(shared, PRC64); + temp_reg = E1000_READ_REG(shared, PRC127); + temp_reg = E1000_READ_REG(shared, PRC255); + temp_reg = E1000_READ_REG(shared, PRC511); + temp_reg = E1000_READ_REG(shared, PRC1023); + temp_reg = E1000_READ_REG(shared, PRC1522); + temp_reg = E1000_READ_REG(shared, GPRC); + temp_reg = E1000_READ_REG(shared, BPRC); + temp_reg = E1000_READ_REG(shared, MPRC); + temp_reg = E1000_READ_REG(shared, GPTC); + temp_reg = E1000_READ_REG(shared, GORCL); + temp_reg = E1000_READ_REG(shared, GORCH); + temp_reg = E1000_READ_REG(shared, GOTCL); + temp_reg = E1000_READ_REG(shared, GOTCH); + temp_reg = E1000_READ_REG(shared, RNBC); + temp_reg = E1000_READ_REG(shared, RUC); + temp_reg = E1000_READ_REG(shared, RFC); + temp_reg = E1000_READ_REG(shared, ROC); + temp_reg = E1000_READ_REG(shared, RJC); + temp_reg = E1000_READ_REG(shared, TORL); + temp_reg = E1000_READ_REG(shared, TORH); + temp_reg = E1000_READ_REG(shared, TOTL); + temp_reg = E1000_READ_REG(shared, TOTH); + temp_reg = E1000_READ_REG(shared, TPR); + temp_reg = E1000_READ_REG(shared, TPT); + temp_reg = E1000_READ_REG(shared, PTC64); + temp_reg = E1000_READ_REG(shared, PTC127); + temp_reg = E1000_READ_REG(shared, PTC255); + temp_reg = E1000_READ_REG(shared, PTC511); + temp_reg = E1000_READ_REG(shared, PTC1023); + temp_reg = E1000_READ_REG(shared, PTC1522); + temp_reg = E1000_READ_REG(shared, MPTC); + temp_reg = E1000_READ_REG(shared, BPTC); + + if(shared->mac_type < em_82543) 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); + temp_reg = E1000_READ_REG(shared, ALGNERRC); + temp_reg = E1000_READ_REG(shared, RXERRC); + temp_reg = E1000_READ_REG(shared, TNCRS); + temp_reg = E1000_READ_REG(shared, CEXTERR); + temp_reg = E1000_READ_REG(shared, TSCTC); + temp_reg = E1000_READ_REG(shared, TSCTFC); + return; } -void em_get_speed_and_duplex(struct adapter *Adapter, - u16 * Speed, u16 * Duplex) - { - u32 DeviceStatusReg; +/****************************************************************************** + * Detects the current speed and duplex settings of the hardware. + * + * shared - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + *****************************************************************************/ +void +em_get_speed_and_duplex(struct em_shared_adapter *shared, + uint16_t *speed, + uint16_t *duplex) +{ + uint32_t status_reg; +#if DBG + uint16_t phy_data; +#endif - DEBUGFUNC("em_get_speed_and_duplex") + DEBUGFUNC("em_get_speed_and_duplex"); - if (Adapter->AdapterStopped) { - *Speed = 0; - *Duplex = 0; - return; + /* If the adapter is stopped we don't have a speed or duplex */ + if(shared->adapter_stopped) { + *speed = 0; + *duplex = 0; + return; + } + + if(shared->mac_type >= em_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + DEBUGOUT("1000 Mbs, "); + } else if(status_reg & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + DEBUGOUT("100 Mbs, "); + } else { + *speed = SPEED_10; + DEBUGOUT("10 Mbs, "); } - 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"); - } + if(status_reg & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + DEBUGOUT("Full Duplex\r\n"); } else { - DEBUGOUT("Wiseman MAC - 1000 Mbs, Full Duplex\r\n"); - *Speed = SPEED_1000; - *Duplex = FULL_DUPLEX; + *duplex = HALF_DUPLEX; + DEBUGOUT(" Half Duplex\r\n"); } - - 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); + } else { + DEBUGOUT("1000 Mbs, Full Duplex\r\n"); + *speed = SPEED_1000; + *duplex = FULL_DUPLEX; + } + +#if DBG + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID) { + /* read the phy specific status register */ + phy_data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data); + phy_data = em_read_phy_reg(shared, PHY_STATUS); + DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data); + DEBUGOUT1("Device Status Reg contents = %x\n", + E1000_READ_REG(shared, STATUS)); + /* DisplayMiiContents(Adapter, (uint8_t)Adapter->PhyAddress); */ + } +#endif + return; } -void em_standby_eeprom(struct adapter *Adapter) +/****************************************************************************** + * Reads a 16 bit word from the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * offset - offset of 16 bit word in the EEPROM to read + *****************************************************************************/ +uint16_t +em_read_eeprom(struct em_shared_adapter *shared, + uint16_t offset) { - u32 val; + uint16_t data; - val = E1000_READ_REG(Eecd); + + /* Prepare the EEPROM for reading */ + em_setup_eeprom(shared); - val &= ~(E1000_EECS | E1000_EESK); - E1000_WRITE_REG(Eecd, val); - DelayInMicroseconds(50); + /* Send the READ command (opcode + addr) */ + em_shift_out_bits(shared, EEPROM_READ_OPCODE, 3); + /* If we have a 256 word EEPROM, there are 8 address bits + * if we have a 64 word EEPROM, there are 6 address bits + */ + if(shared->large_eeprom) + em_shift_out_bits(shared, offset, 8); + else + em_shift_out_bits(shared, offset, 6); - val |= E1000_EESK; - E1000_WRITE_REG(Eecd, val); - DelayInMicroseconds(50); + /* Read the data */ + data = em_shift_in_bits(shared); - val |= E1000_EECS; - E1000_WRITE_REG(Eecd, val); - DelayInMicroseconds(50); + /* End this read operation */ + em_standby_eeprom(shared); - val &= ~E1000_EESK; - E1000_WRITE_REG(Eecd, val); - DelayInMicroseconds(50); + return (data); } -void em_clock_eeprom(struct adapter *Adapter) +/****************************************************************************** + * Verifies that the EEPROM has a valid checksum + * + * shared - Struct containing variables accessed by shared code + * + * Reads the first 64 16 bit words of the EEPROM and sums the values read. + * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is + * valid. + *****************************************************************************/ +boolean_t +em_validate_eeprom_checksum(struct em_shared_adapter *shared) { - u32 val; + uint16_t checksum = 0; + uint16_t i; - val = E1000_READ_REG(Eecd); + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) + checksum += em_read_eeprom(shared, i); - val |= E1000_EESK; - E1000_WRITE_REG(Eecd, val); - DelayInMicroseconds(50); - - val &= ~E1000_EESK; - E1000_WRITE_REG(Eecd, val); - DelayInMicroseconds(50); + if(checksum == (uint16_t) EEPROM_SUM) + return (TRUE); + else + return (FALSE); } -void em_cleanup_eeprom(struct adapter *Adapter) +/****************************************************************************** + * Calculates the EEPROM checksum and writes it to the EEPROM + * + * shared - Struct containing variables accessed by shared code + * + * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA. + * Writes the difference to word offset 63 of the EEPROM. + *****************************************************************************/ +void +em_update_eeprom_checksum(struct em_shared_adapter *shared) { - 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); + uint16_t checksum = 0; + uint16_t i; - EecdRegValue &= ~(E1000_EEDO | E1000_EEDI); - Data = 0; + for(i = 0; i < EEPROM_CHECKSUM_REG; i++) + checksum += em_read_eeprom(shared, i); - for (i = 0; i < 16; i++) { - Data = Data << 1; - em_raise_clock(Adapter, &EecdRegValue); + checksum = (uint16_t) EEPROM_SUM - checksum; - 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); + em_write_eeprom(shared, EEPROM_CHECKSUM_REG, checksum); + return; } -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); +/****************************************************************************** + * Writes a 16 bit word to a given offset in the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * data - 16 bit word to be writen to the EEPROM + * + * If em_update_eeprom_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. + *****************************************************************************/ +boolean_t +em_write_eeprom(struct em_shared_adapter *shared, + uint16_t offset, + uint16_t data) +{ - for (i = 0; i < 200; i++) { - EecdRegValue = E1000_READ_REG(Eecd); + /* Prepare the EEPROM for writing */ + em_setup_eeprom(shared); - if (EecdRegValue & E1000_EEDO) - return (1); + /* Send the 9-bit EWEN (write enable) command to the EEPROM (5-bit opcode + * plus 4-bit dummy). This puts the EEPROM into write/erase mode. + */ + em_shift_out_bits(shared, EEPROM_EWEN_OPCODE, 5); + em_shift_out_bits(shared, 0, 4); - DelayInMicroseconds(50); - } - ASSERT(0); - return (0); -} + /* Prepare the EEPROM */ + em_standby_eeprom(shared); -static void em_stand_by(struct adapter *Adapter) - { - u32 EecdRegValue; + /* Send the Write command (3-bit opcode + addr) */ + em_shift_out_bits(shared, EEPROM_WRITE_OPCODE, 3); + /* If we have a 256 word EEPROM, there are 8 address bits + * if we have a 64 word EEPROM, there are 6 address bits + */ + if(shared->large_eeprom) + em_shift_out_bits(shared, offset, 8); + else + em_shift_out_bits(shared, offset, 6); - EecdRegValue = E1000_READ_REG(Eecd); + /* Send the data */ + em_shift_out_bits(shared, data, 16); - EecdRegValue &= ~(E1000_EECS | E1000_EESK); + em_wait_eeprom_command(shared); - E1000_WRITE_REG(Eecd, EecdRegValue); + /* Recover from write */ + em_standby_eeprom(shared); - DelayInMicroseconds(5); + /* Send the 9-bit EWDS (write disable) command to the EEPROM (5-bit + * opcode plus 4-bit dummy). This takes the EEPROM out of write/erase + * mode. + */ + em_shift_out_bits(shared, EEPROM_EWDS_OPCODE, 5); + em_shift_out_bits(shared, 0, 4); - EecdRegValue |= E1000_EECS; + /* Done with writing */ + em_cleanup_eeprom(shared); - E1000_WRITE_REG(Eecd, EecdRegValue); + return (TRUE); } -u8 em_read_part_number(struct adapter *Adapter, u32 * PartNumber) +/****************************************************************************** + * Reads the adapter's part number from the EEPROM + * + * shared - Struct containing variables accessed by shared code + * part_num - Adapter's part number + *****************************************************************************/ +boolean_t +em_read_part_num(struct em_shared_adapter *shared, + uint32_t *part_num) { - 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; + uint16_t eeprom_word; - EepromWordValue = em_read_eeprom_word(Adapter, - (u16) (EEPROM_PBA_BYTE_1 + - 1)); + DEBUGFUNC("em_read_part_num"); - DEBUGOUT("Read second part number word\n"); + /* Don't read the EEPROM if we are stopped */ + if(shared->adapter_stopped) { + *part_num = 0; + return (FALSE); + } - *PartNumber |= EepromWordValue; + /* Get word 0 from EEPROM */ + eeprom_word = em_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1)); - return (1); + DEBUGOUT("Read first part number word\n"); -} - -void em_id_led_on(struct adapter *Adapter) -{ - u32 CtrlRegValue; + /* Save word 0 in upper half is PartNumber */ + *part_num = (uint32_t) eeprom_word; + *part_num = *part_num << 16; - if (Adapter->AdapterStopped) { - return; - } + /* Get word 1 from EEPROM */ + eeprom_word = + em_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1)); - CtrlRegValue = E1000_READ_REG(Ctrl); + DEBUGOUT("Read second part number word\n"); - CtrlRegValue |= E1000_CTRL_SWDPIO0; - - if (em_is_low_profile(Adapter)) { - CtrlRegValue &= ~E1000_CTRL_SWDPIN0; - } else { - CtrlRegValue |= E1000_CTRL_SWDPIN0; - } - - E1000_WRITE_REG(Ctrl, CtrlRegValue); + /* Save word 1 in lower half of PartNumber */ + *part_num |= eeprom_word; + /* read a valid part number */ + return (TRUE); } -void em_id_led_off(struct adapter *Adapter) +/****************************************************************************** + * Turns on the software controllable LED + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_led_on(struct em_shared_adapter *shared) { - u32 CtrlRegValue; + uint32_t ctrl_reg; - if (Adapter->AdapterStopped) { - return; - } + /* if we're stopped don't touch the hardware */ + if(shared->adapter_stopped) + return; - CtrlRegValue = E1000_READ_REG(Ctrl); + /* Read the content of the device control reg */ + ctrl_reg = E1000_READ_REG(shared, CTRL); - CtrlRegValue |= E1000_CTRL_SWDPIO0; + /* Set the LED control pin to an output */ + ctrl_reg |= E1000_CTRL_SWDPIO0; - if (em_is_low_profile(Adapter)) { - CtrlRegValue |= E1000_CTRL_SWDPIN0; - } else { - CtrlRegValue &= ~E1000_CTRL_SWDPIN0; - } + /* Drive it high on normal boards, low on low profile boards */ + if(shared->low_profile) + ctrl_reg &= ~E1000_CTRL_SWDPIN0; + else + ctrl_reg |= E1000_CTRL_SWDPIN0; - E1000_WRITE_REG(Ctrl, CtrlRegValue); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; } -void em_set_id_led_for_pc_ix(struct adapter *Adapter) +/****************************************************************************** + * Turns off the software controllable LED + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_led_off(struct em_shared_adapter *shared) { - u32 PciStatus; - - PciStatus = E1000_READ_REG(Status); - - if (PciStatus & E1000_STATUS_PCIX_MODE) { - em_id_led_on(Adapter); - } else { - em_id_led_off(Adapter); - } -} + uint32_t ctrl_reg; -u8 em_is_low_profile(struct adapter *Adapter) -{ - u16 LedLogicWord; - u8 ReturnValue = 0; + /* if we're stopped don't touch the hardware */ + if(shared->adapter_stopped) + return; - if (Adapter->MacType >= MAC_CORDOVA) { + /* Read the content of the device control reg */ + ctrl_reg = E1000_READ_REG(shared, CTRL); - LedLogicWord = - em_read_eeprom_word(Adapter, E1000_EEPROM_LED_LOGIC); + /* Set the LED control pin to an output */ + ctrl_reg |= E1000_CTRL_SWDPIO0; - if (LedLogicWord & E1000_EEPROM_SWDPIN0) - ReturnValue = 1; - else - ReturnValue = 0; - } + /* Drive it low on normal boards, high on low profile boards */ + if(shared->low_profile) + ctrl_reg |= E1000_CTRL_SWDPIN0; + else + ctrl_reg &= ~E1000_CTRL_SWDPIN0; - return ReturnValue; + /* Write the device control reg. back */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; } -void em_adjust_tbi_accepted_stats(struct adapter *Adapter, - u32 FrameLength, u8 * MacAddress) +/****************************************************************************** + * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT + * + * shared - Struct containing variables accessed by shared code + * frame_len - The length of the frame in question + * mac_addr - The Ethernet destination address of the frame in question + *****************************************************************************/ +uint32_t +em_tbi_adjust_stats(struct em_shared_adapter *shared, + struct em_shared_stats *stats, + uint32_t frame_len, + uint8_t *mac_addr) { - 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++; - } + uint64_t carry_bit; + + /* First adjust the frame length. */ + frame_len--; + /* We need to adjust the statistics counters, since the hardware + * counters overcount this packet as a CRC error and undercount + * the packet as a good packet + */ + /* This packet should not be counted as a CRC error. */ + stats->crcerrs--; + /* This packet does count as a Good Packet Received. */ + stats->gprc++; + + /* Adjust the Good Octets received counters */ + carry_bit = 0x80000000 & stats->gorcl; + stats->gorcl += frame_len; + /* If the high bit of Gorcl (the low 32 bits of the Good Octets + * Received Count) was one before the addition, + * AND it is zero after, then we lost the carry out, + * need to add one to Gorch (Good Octets Received Count High). + * This could be simplified if all environments supported + * 64-bit integers. + */ + if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) + stats->gorch++; + /* Is this a broadcast or multicast? Check broadcast first, + * since the test for a multicast frame will test positive on + * a broadcast frame. + */ + if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) + /* Broadcast packet */ + stats->bprc++; + else if(*mac_addr & 0x01) + /* Multicast packet */ + stats->mprc++; + + if(frame_len == shared->max_frame_size) { + /* In this case, the hardware has overcounted the number of + * oversize frames. + */ + if(stats->roc > 0) + stats->roc--; + } + + /* Adjust the bin counters when the extra byte put the frame in the + * wrong bin. Remember that the frame_len was adjusted above. + */ + if(frame_len == 64) { + stats->prc64++; + stats->prc127--; + } else if(frame_len == 127) { + stats->prc127++; + stats->prc255--; + } else if(frame_len == 255) { + stats->prc255++; + stats->prc511--; + } else if(frame_len == 511) { + stats->prc511++; + stats->prc1023--; + } else if(frame_len == 1023) { + stats->prc1023++; + stats->prc1522--; + } else if(frame_len == 1522) { + stats->prc1522++; + } + return frame_len; } -void em_get_bus_type_speed_width(struct adapter *Adapter) +/****************************************************************************** + * Gets the current PCI bus type, speed, and width of the hardware + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +em_get_bus_info(struct em_shared_adapter *shared) { - 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; + uint32_t status_reg; - 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; - } + if(shared->mac_type < em_82543) { + shared->bus_type = em_bus_type_unknown; + shared->bus_speed = em_bus_speed_unknown; + shared->bus_width = em_bus_width_unknown; + return; + } + + status_reg = E1000_READ_REG(shared, STATUS); + + shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ? + em_bus_type_pcix : em_bus_type_pci; + + if(shared->bus_type == em_bus_type_pci) { + shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ? + em_bus_speed_66 : em_bus_speed_33; + } else { + switch (status_reg & E1000_STATUS_PCIX_SPEED) { + case E1000_STATUS_PCIX_SPEED_66: + shared->bus_speed = em_bus_speed_66; + break; + case E1000_STATUS_PCIX_SPEED_100: + shared->bus_speed = em_bus_speed_100; + break; + case E1000_STATUS_PCIX_SPEED_133: + shared->bus_speed = em_bus_speed_133; + break; + default: + shared->bus_speed = em_bus_speed_reserved; + break; } + } - Adapter->BusWidth = (DeviceStatusReg & E1000_STATUS_BUS64) ? - E1000_BUS_WIDTH_64_BIT : E1000_BUS_WIDTH_32_BIT; + shared->bus_width = (status_reg & E1000_STATUS_BUS64) ? + em_bus_width_64 : em_bus_width_32; - return; + return; } diff --git a/sys/dev/em/if_em_fxhw.h b/sys/dev/em/if_em_fxhw.h index 86447e5..e31f3a6 100644 --- a/sys/dev/em/if_em_fxhw.h +++ b/sys/dev/em/if_em_fxhw.h @@ -1,1338 +1,1249 @@ -/************************************************************************* -************************************************************************** -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; +/******************************************************************************* + + 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$*/ +/* if_em_fxhw.h + * Structures, enums, and macros for the MAC + */ + +#ifndef _EM_MAC_H_ +#define _EM_MAC_H_ -typedef enum { - E1000_BUS_TYPE_UNKNOWN = 0, - E1000_BUS_TYPE_PCI, - E1000_BUS_TYPE_PCIX -} E1000_BUS_TYPE_ENUM; +#include <dev/em/if_em_osdep.h> -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; +/* Forward declarations of structures used by the shared code */ +struct em_shared_adapter; +struct em_shared_stats; +/* Enumerated types specific to the e1000 hardware */ +/* Media Access Controlers */ typedef enum { - E1000_BUS_WIDTH_UNKNOWN = 0, - E1000_BUS_WIDTH_32_BIT, - E1000_BUS_WIDTH_64_BIT -} E1000_BUS_WIDTH_ENUM; + em_82542_rev2_0 = 0, + em_82542_rev2_1, + em_82543, + em_82544, + em_num_macs +} em_mac_type; + +/* Media Types */ +typedef enum { + em_media_type_copper = 0, + em_media_type_fiber = 1, + em_num_media_types +} em_media_type; -#include <dev/em/if_em_osdep.h> +typedef enum { + em_10_half = 0, + em_10_full = 1, + em_100_half = 2, + em_100_full = 3 +} em_speed_duplex_type; -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); +/* Flow Control Settings */ +typedef enum { + em_fc_none = 0, + em_fc_rx_pause = 1, + em_fc_tx_pause = 2, + em_fc_full = 3, + em_fc_default = 0xFF +} em_fc_type; + +/* PCI bus types */ +typedef enum { + em_bus_type_unknown = 0, + em_bus_type_pci, + em_bus_type_pcix +} em_bus_type; +/* PCI bus speeds */ +typedef enum { + em_bus_speed_unknown = 0, + em_bus_speed_33, + em_bus_speed_66, + em_bus_speed_100, + em_bus_speed_133, + em_bus_speed_reserved +} em_bus_speed; + +/* PCI bus widths */ +typedef enum { + em_bus_width_unknown = 0, + em_bus_width_32, + em_bus_width_64 +} em_bus_width; + + + +/* Function prototypes */ +/* Setup */ +void em_adapter_stop(struct em_shared_adapter *shared); +boolean_t em_init_hw(struct em_shared_adapter *shared); +void em_init_rx_addrs(struct em_shared_adapter *shared); + +/* Filters (multicast, vlan, receive) */ +void em_mc_addr_list_update(struct em_shared_adapter *shared, + uint8_t * mc_addr_list, + uint32_t mc_addr_count, + uint32_t pad); +uint32_t em_hash_mc_addr(struct em_shared_adapter *shared, + uint8_t * mc_addr); +void em_mta_set(struct em_shared_adapter *shared, + uint32_t hash_value); +void em_rar_set(struct em_shared_adapter *shared, + uint8_t * mc_addr, + uint32_t rar_index); +void em_write_vfta(struct em_shared_adapter *shared, + uint32_t offset, + uint32_t value); +void em_clear_vfta(struct em_shared_adapter *shared); + +/* Link layer setup functions */ +boolean_t em_setup_fc_and_link(struct em_shared_adapter *shared); +boolean_t em_setup_pcs_link(struct em_shared_adapter *shared, + uint32_t dev_ctrl_reg); +void em_config_fc_after_link_up(struct em_shared_adapter *shared); +void em_check_for_link(struct em_shared_adapter *shared); +void em_get_speed_and_duplex(struct em_shared_adapter *shared, + uint16_t * speed, + uint16_t * duplex); + +/* EEPROM Functions */ +uint16_t em_read_eeprom(struct em_shared_adapter *shared, + uint16_t reg); +boolean_t em_validate_eeprom_checksum(struct em_shared_adapter *shared); +void em_update_eeprom_checksum(struct em_shared_adapter *shared); +boolean_t em_write_eeprom(struct em_shared_adapter *shared, + uint16_t reg, + uint16_t data); + +/* Everything else */ +void em_clear_hw_cntrs(struct em_shared_adapter *shared); +boolean_t em_read_part_num(struct em_shared_adapter *shared, + uint32_t * part_num); +void em_led_on(struct em_shared_adapter *shared); +void em_led_off(struct em_shared_adapter *shared); +void em_get_bus_info(struct em_shared_adapter *shared); +uint32_t em_tbi_adjust_stats(struct em_shared_adapter *shared, + struct em_shared_stats *stats, + uint32_t frame_len, + uint8_t * mac_addr); +void em_write_pci_cfg(struct em_shared_adapter *shared, + uint32_t reg, + uint16_t * value); + +#define E1000_DEV_ID_82542 0x1000 +#define E1000_DEV_ID_82543GC_FIBER 0x1001 +#define E1000_DEV_ID_82543GC_COPPER 0x1004 +#define E1000_DEV_ID_82544EI_COPPER 0x1008 +#define E1000_DEV_ID_82544EI_FIBER 0x1009 +#define E1000_DEV_ID_82544GC_COPPER 0x100C +#define E1000_DEV_ID_82544GC_LOM 0x100D + +#define NODE_ADDRESS_SIZE 6 +#define ETH_LENGTH_OF_ADDRESS 6 + +/* MAC decode size is 128K - This is the size of BAR0 */ #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_82542_2_0_REV_ID 2 +#define E1000_82542_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 + +/* The sizes (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */ +#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Without FCS */ +#define CRC_LENGTH 4 +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + + +/* 802.1q VLAN Packet Sizes */ +#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */ + +/* Ethertype field values */ +#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ +#define ETHERNET_IP_TYPE 0x0800 /* IP packets */ +#define ETHERNET_ARP_TYPE 0x0806 /* Address Resolution Protocol (ARP) */ + +/* Packet Header defines */ +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 0x11 + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + */ +#define POLL_IMS_ENABLE_MASK ( \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ) + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* The number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. We + * reserve one of these spots for our directed address, allowing us room for + * E1000_RAR_ENTRIES - 1 multicast addresses. + */ #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 MIN_NUMBER_OF_DESCRIPTORS 8 +#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 + +/* Receive Descriptor */ +struct em_rx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + uint16_t length; /* Length of data DMAed into data buffer */ + uint16_t csum; /* Packet checksum */ + uint8_t status; /* Descriptor status */ + uint8_t errors; /* Descriptor Errors */ + uint16_t special; +}; + +/* Receive Decriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define E1000_RXD_SPC_PRI_SHIFT 0x000D /* Priority is in upper 3 of 16 */ +#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define E1000_RXD_SPC_CFI_SHIFT 0x000C /* CFI is bit 12 */ + +/* mask to determine if packets should be dropped due to frame errors */ +#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) + +/* Transmit Descriptor */ +struct em_tx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t cso; /* Checksum offset */ + uint8_t cmd; /* Descriptor control */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t css; /* Checksum start */ + uint16_t special; + } fields; + } upper; +}; + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Offload Context Descriptor */ +struct em_context_desc { + union { + uint32_t ip_config; + struct { + uint8_t ipcss; /* IP checksum start */ + uint8_t ipcso; /* IP checksum offset */ + uint16_t ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + uint32_t tcp_config; + struct { + uint8_t tucss; /* TCP checksum start */ + uint8_t tucso; /* TCP checksum offset */ + uint16_t tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + uint32_t cmd_and_length; /* */ + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t hdr_len; /* Header length */ + uint16_t mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct em_data_desc { + uint64_t buffer_addr; /* Address of the descriptor's buffer address */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t typ_len_ext; /* */ + uint8_t cmd; /* */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t popts; /* Packet Options */ + uint16_t special; /* */ + } fields; + } upper; +}; + +/* Filters */ +#define E1000_NUM_UNICAST 16 /* Unicast filter entries */ +#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + + +/* Receive Address Register */ +struct em_rar { + volatile uint32_t low; /* receive address low */ + volatile uint32_t high; /* receive address high */ +}; + +/* The number of entries in the Multicast Table Array (MTA). */ #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 +/* IPv4 Address Table Entry */ +struct em_ipv4_at_entry { + volatile uint32_t ipv4_addr; /* IP Address (RW) */ + volatile uint32_t reserved; +}; + +/* Four wakeup IP addresses are supported */ +#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4 +#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX +#define E1000_IP6AT_SIZE 1 + +/* IPv6 Address Table Entry */ +struct em_ipv6_at_entry { + volatile uint8_t ipv6_addr[16]; +}; + +/* Flexible Filter Length Table Entry */ +struct em_fflt_entry { + volatile uint32_t length; /* Flexible Filter Length (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Mask Table Entry */ +struct em_ffmt_entry { + volatile uint32_t mask; /* Flexible Filter Mask (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Value Table Entry */ +struct em_ffvt_entry { + volatile uint32_t value; /* Flexible Filter Value (RW) */ + volatile uint32_t reserved; +}; + +/* Four Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 + +/* Each Flexible Filter is at most 128 (0x80) bytes in length */ +#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 + +/* Register Set. (82543, 82544) + * + * Registers are defined to be 32 bits and should be accessed as 32 bit values. + * These registers are physically located on the NIC, but are mapped into the + * host memory address space. + * + * RW - register is both readable and writable + * RO - register is read only + * WO - register is write only + * R/clr - register is read only and is cleared when read + * A - register array + */ +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_CTRLEXT 0x00018 /* Extended Device Control - RW */ +#define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ +#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FCT 0x00030 /* Flow Control Type - RW */ +#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ +#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ +#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ +#define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ +#define E1000_TBT 0x00448 /* TX Burst Timer - RW */ +#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ +#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ +#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ +#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ +#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ +#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ +#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ +#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ +#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ +#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ +#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ +#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ +#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ +#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ +#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ +#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define E1000_COLC 0x04028 /* Collision Count - R/clr */ +#define E1000_DC 0x04030 /* Defer Count - R/clr */ +#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ +#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ +#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ +#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ +#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ +#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ +#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ +#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ +#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ +#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ +#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ +#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ +#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ +#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ +#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ +#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ +#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ +#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ +#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ +#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ +#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ +#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ +#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ +#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ +#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ +#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ +#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ +#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ +#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ +#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ +#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ +#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ +#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ +#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ +#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ +#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ +#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ +#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ +#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ +#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ +#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ +#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ +#define E1000_WUC 0x05800 /* Wakeup Control - RW */ +#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ +#define E1000_WUS 0x05810 /* Wakeup Status - RO */ +#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ +#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ +#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ +#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ +#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ +#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ +#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ + +/* Register Set (82542) + * + * Some of the 82542 registers are located at different offsets than they are + * in more current versions of the 8254x. Despite the difference in location, + * the registers function in the same manner. + */ +#define E1000_82542_CTRL E1000_CTRL +#define E1000_82542_STATUS E1000_STATUS +#define E1000_82542_EECD E1000_EECD +#define E1000_82542_CTRLEXT E1000_CTRLEXT +#define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_FCAL E1000_FCAL +#define E1000_82542_FCAH E1000_FCAH +#define E1000_82542_FCT E1000_FCT +#define E1000_82542_VET E1000_VET +#define E1000_82542_RA 0x00040 +#define E1000_82542_ICR E1000_ICR +#define E1000_82542_ICS E1000_ICS +#define E1000_82542_IMS E1000_IMS +#define E1000_82542_IMC E1000_IMC +#define E1000_82542_RCTL E1000_RCTL +#define E1000_82542_RDTR 0x00108 +#define E1000_82542_RDBAL 0x00110 +#define E1000_82542_RDBAH 0x00114 +#define E1000_82542_RDLEN 0x00118 +#define E1000_82542_RDH 0x00120 +#define E1000_82542_RDT 0x00128 +#define E1000_82542_FCRTH 0x00160 +#define E1000_82542_FCRTL 0x00168 +#define E1000_82542_FCTTV E1000_FCTTV +#define E1000_82542_TXCW E1000_TXCW +#define E1000_82542_RXCW E1000_RXCW +#define E1000_82542_MTA 0x00200 +#define E1000_82542_TCTL E1000_TCTL +#define E1000_82542_TIPG E1000_TIPG +#define E1000_82542_TDBAL 0x00420 +#define E1000_82542_TDBAH 0x00424 +#define E1000_82542_TDLEN 0x00428 +#define E1000_82542_TDH 0x00430 +#define E1000_82542_TDT 0x00438 +#define E1000_82542_TIDV 0x00440 +#define E1000_82542_TBT E1000_TBT +#define E1000_82542_VFTA 0x00600 +#define E1000_82542_PBA E1000_PBA +#define E1000_82542_RXDCTL E1000_RXDCTL +#define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_TXDCTL E1000_TXDCTL +#define E1000_82542_TSPMT E1000_TSPMT +#define E1000_82542_CRCERRS E1000_CRCERRS +#define E1000_82542_ALGNERRC E1000_ALGNERRC +#define E1000_82542_SYMERRS E1000_SYMERRS +#define E1000_82542_RXERRC E1000_RXERRC +#define E1000_82542_MPC E1000_MPC +#define E1000_82542_SCC E1000_SCC +#define E1000_82542_ECOL E1000_ECOL +#define E1000_82542_MCC E1000_MCC +#define E1000_82542_LATECOL E1000_LATECOL +#define E1000_82542_COLC E1000_COLC +#define E1000_82542_DC E1000_DC +#define E1000_82542_TNCRS E1000_TNCRS +#define E1000_82542_SEC E1000_SEC +#define E1000_82542_CEXTERR E1000_CEXTERR +#define E1000_82542_RLEC E1000_RLEC +#define E1000_82542_XONRXC E1000_XONRXC +#define E1000_82542_XONTXC E1000_XONTXC +#define E1000_82542_XOFFRXC E1000_XOFFRXC +#define E1000_82542_XOFFTXC E1000_XOFFTXC +#define E1000_82542_FCRUC E1000_FCRUC +#define E1000_82542_PRC64 E1000_PRC64 +#define E1000_82542_PRC127 E1000_PRC127 +#define E1000_82542_PRC255 E1000_PRC255 +#define E1000_82542_PRC511 E1000_PRC511 +#define E1000_82542_PRC1023 E1000_PRC1023 +#define E1000_82542_PRC1522 E1000_PRC1522 +#define E1000_82542_GPRC E1000_GPRC +#define E1000_82542_BPRC E1000_BPRC +#define E1000_82542_MPRC E1000_MPRC +#define E1000_82542_GPTC E1000_GPTC +#define E1000_82542_GORCL E1000_GORCL +#define E1000_82542_GORCH E1000_GORCH +#define E1000_82542_GOTCL E1000_GOTCL +#define E1000_82542_GOTCH E1000_GOTCH +#define E1000_82542_RNBC E1000_RNBC +#define E1000_82542_RUC E1000_RUC +#define E1000_82542_RFC E1000_RFC +#define E1000_82542_ROC E1000_ROC +#define E1000_82542_RJC E1000_RJC +#define E1000_82542_TORL E1000_TORL +#define E1000_82542_TORH E1000_TORH +#define E1000_82542_TOTL E1000_TOTL +#define E1000_82542_TOTH E1000_TOTH +#define E1000_82542_TPR E1000_TPR +#define E1000_82542_TPT E1000_TPT +#define E1000_82542_PTC64 E1000_PTC64 +#define E1000_82542_PTC127 E1000_PTC127 +#define E1000_82542_PTC255 E1000_PTC255 +#define E1000_82542_PTC511 E1000_PTC511 +#define E1000_82542_PTC1023 E1000_PTC1023 +#define E1000_82542_PTC1522 E1000_PTC1522 +#define E1000_82542_MPTC E1000_MPTC +#define E1000_82542_BPTC E1000_BPTC +#define E1000_82542_TSCTC E1000_TSCTC +#define E1000_82542_TSCTFC E1000_TSCTFC +#define E1000_82542_RXCSUM E1000_RXCSUM +#define E1000_82542_WUC E1000_WUC +#define E1000_82542_WUFC E1000_WUFC +#define E1000_82542_WUS E1000_WUS +#define E1000_82542_IPAV E1000_IPAV +#define E1000_82542_IP4AT E1000_IP4AT +#define E1000_82542_WUPL E1000_WUPL +#define E1000_82542_WUPM E1000_WUPM +#define E1000_82542_FFLT E1000_FFLT +#define E1000_82542_FFMT E1000_FFMT +#define E1000_82542_FFVT E1000_FFVT + +/* Statistics counters collected by the MAC */ +struct em_shared_stats { + uint64_t crcerrs; + uint64_t algnerrc; + uint64_t symerrs; + uint64_t rxerrc; + uint64_t mpc; + uint64_t scc; + uint64_t ecol; + uint64_t mcc; + uint64_t latecol; + uint64_t colc; + uint64_t dc; + uint64_t tncrs; + uint64_t sec; + uint64_t cexterr; + uint64_t rlec; + uint64_t xonrxc; + uint64_t xontxc; + uint64_t xoffrxc; + uint64_t xofftxc; + uint64_t fcruc; + uint64_t prc64; + uint64_t prc127; + uint64_t prc255; + uint64_t prc511; + uint64_t prc1023; + uint64_t prc1522; + uint64_t gprc; + uint64_t bprc; + uint64_t mprc; + uint64_t gptc; + uint64_t gorcl; + uint64_t gorch; + uint64_t gotcl; + uint64_t gotch; + uint64_t rnbc; + uint64_t ruc; + uint64_t rfc; + uint64_t roc; + uint64_t rjc; + uint64_t mgprc; + uint64_t mgpdc; + uint64_t mgptc; + uint64_t torl; + uint64_t torh; + uint64_t totl; + uint64_t toth; + uint64_t tpr; + uint64_t tpt; + uint64_t ptc64; + uint64_t ptc127; + uint64_t ptc255; + uint64_t ptc511; + uint64_t ptc1023; + uint64_t ptc1522; + uint64_t mptc; + uint64_t bptc; + uint64_t tsctc; + uint64_t tsctfc; +}; + +/* Structure containing variables used by the shared code (em_mac.c and + * em_phy.c) + */ +struct em_shared_adapter { + uint8_t *hw_addr; + em_mac_type mac_type; + em_media_type media_type; + void *back; + em_fc_type fc; + em_bus_speed bus_speed; + em_bus_width bus_width; + em_bus_type bus_type; + uint32_t phy_id; + uint32_t phy_addr; + uint32_t original_fc; + uint32_t txcw_reg; + uint32_t autoneg_failed; + uint32_t max_frame_size; + uint32_t mc_filter_type; + uint32_t num_mc_addrs; + uint16_t autoneg_advertised; + uint16_t pci_cmd_word; + uint16_t fc_high_water; + uint16_t fc_low_water; + uint16_t fc_pause_time; + boolean_t disable_polarity_correction; + boolean_t get_link_status; + boolean_t tbi_compatibility_en; + boolean_t tbi_compatibility_on; + boolean_t adapter_stopped; + boolean_t fc_send_xon; + boolean_t report_tx_early; + boolean_t low_profile; + boolean_t large_eeprom; + uint8_t autoneg; + uint8_t mdix; + uint8_t forced_speed_duplex; + uint8_t wait_autoneg_complete; + uint8_t dma_fairness; + uint8_t mac_addr[NODE_ADDRESS_SIZE]; +}; + + +#define E1000_EEPROM_SWDPIN0 0x00000001 /* SWDPIN 0 EEPROM Value */ +#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ + +/* Register Bit Masks */ +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ +#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ +#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ +#define E1000_STATUS_SPEED_MASK 0x000000C0 +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ +#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ +#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ +#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ +#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ + +/* Constants used to intrepret the masked PCI-X bus speed. */ +#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ +#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ +#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */ + +/* EEPROM/Flash Control */ +#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ +#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ +#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ +#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define E1000_EECD_FWE_SHIFT 4 +#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ + +/* Extended Device Control */ +#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ +#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ +#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN +#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ +#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ +#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */ +#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */ +#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA +#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ +#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ +#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ +#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ +#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ + +/* MDI Control */ +#define E1000_MDIC_DATA_MASK 0x0000FFFF +#define E1000_MDIC_REG_MASK 0x001F0000 +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_MASK 0x03E00000 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_INT_EN 0x20000000 +#define E1000_MDIC_ERROR 0x40000000 + + +/* Receive Address */ +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ + +/* Interrupt Cause Set */ +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ + +/* Interrupt Mask Clear */ +#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ + +/* Receive Control */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ + +/* Receive Descriptor */ +#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ +#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */ +#define E1000_RDLEN_LEN 0x0007ff80 /* descriptor length */ +#define E1000_RDH_RDH 0x0000ffff /* receive descriptor head */ +#define E1000_RDT_RDT 0x0000ffff /* receive descriptor tail */ + +/* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Receive Descriptor Control */ +#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */ +#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */ +#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */ +#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */ + +/* Transmit Descriptor Control */ +#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */ +#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ +#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ +#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ +#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ +#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ +#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ +#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ +#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ +#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ +#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ +#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ +#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ +#define E1000_RXCW_CC 0x10000000 /* Receive config change */ +#define E1000_RXCW_C 0x20000000 /* Receive config */ +#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ +#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ + +/* Transmit Control */ +#define E1000_TCTL_RST 0x00000001 /* software reset */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ +#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ + +/* Receive Checksum Control */ +#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ +#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ +#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ +#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ +#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ +#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ +#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ +#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ +#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ +#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Wake Up Status */ +#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */ +#define E1000_WUS_MAG 0x00000002 /* Magic Packet Received */ +#define E1000_WUS_EX 0x00000004 /* Directed Exact Received */ +#define E1000_WUS_MC 0x00000008 /* Directed Multicast Received */ +#define E1000_WUS_BC 0x00000010 /* Broadcast Received */ +#define E1000_WUS_ARP 0x00000020 /* ARP Request Packet Received */ +#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */ +#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */ +#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */ +#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */ +#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */ +#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + + +/* Wake Up Packet Length */ +#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ + +#define E1000_MDALIGN 4096 + +/* EEPROM Commands */ +#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ +#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ +#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ +#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ +#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ + +/* EEPROM Word Offsets */ +#define EEPROM_INIT_CONTROL1_REG 0x000A +#define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_FLASH_VERSION 0x0032 +#define EEPROM_CHECKSUM_REG 0x003F + +/* Mask bits for fields in Word 0x0a of the EEPROM */ +#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 + +/* Mask bits for fields in Word 0x0f of the EEPROM */ +#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 + +/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ +#define EEPROM_SUM 0xBABA + +/* EEPROM Map defines (WORD OFFSETS)*/ +#define EEPROM_NODE_ADDRESS_BYTE_0 0 +#define EEPROM_PBA_BYTE_1 8 + +/* EEPROM Map Sizes (Byte Counts) */ +#define PBA_SIZE 4 + +/* Collision related configuration parameters */ +#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 E1000_COLD_SHIFT 12 +/* The number of Transmit and Receive Descriptors must be a multiple of 8 */ #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 +/* Default values for the transmit IPG register */ +#define DEFAULT_82542_TIPG_IPGT 10 +#define DEFAULT_82543_TIPG_IPGT_FIBER 6 +#define DEFAULT_82543_TIPG_IPGT_COPPER 8 -#define E1000_TIPG_IPGT_MASK 0x000003FF -#define E1000_TIPG_IPGR1_MASK 0x000FFC00 -#define E1000_TIPG_IPGR2_MASK 0x3FF00000 +#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_82542_TIPG_IPGR1 2 +#define DEFAULT_82543_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 DEFAULT_82542_TIPG_IPGR2 10 +#define DEFAULT_82543_TIPG_IPGR2 6 +#define E1000_TIPG_IPGR2_SHIFT 20 -#define E1000_TXDMAC_DPP 0x00000001 +#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) +/* PBA constants */ +#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_24K 0x0018 +#define E1000_PBA_40K 0x0028 +#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ -#define FLOW_CONTROL_ADDRESS_LOW (0x00C28001) -#define FLOW_CONTROL_ADDRESS_HIGH (0x00000100) -#define FLOW_CONTROL_TYPE (0x8808) +/* Flow Control Constants */ +#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) +/* The historical defaults for the flow control values are given below. */ +#define FC_DEFAULT_HI_THRESH (0x8000) /* 32KB */ +#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */ +#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */ + +/* The number of bits that we need to shift right to move the "pause" + * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field + * in the TXCW register + */ #define PAUSE_SHIFT 5 +/* The number of bits that we need to shift left to move the "SWDPIO" + * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field + * in the CTRL register + */ #define SWDPIO_SHIFT 17 +/* The number of bits that we need to shift left to move the "SWDPIO_EXT" + * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The + * Extended CTRL register. + * in the CTRL register + */ #define SWDPIO__EXT_SHIFT 4 +/* The number of bits that we need to shift left to move the "ILOS" + * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field + * in the CTRL register + */ #define ILOS_SHIFT 3 -#define MDI_REGADD_SHIFT 16 - -#define MDI_PHYADD_SHIFT 21 #define RECEIVE_BUFFER_ALIGN_SIZE (256) +/* The number of milliseconds we wait for auto-negotiation to complete */ #define LINK_UP_TIMEOUT 500 -#define E1000_TX_BUFFER_SIZE ((u32)1514) - -#define E1000_MIN_SIZE_OF_RECEIVE_BUFFERS (2048) +#define E1000_TX_BUFFER_SIZE ((uint32_t)1514) +/* The carrier extension symbol, as received by the NIC. */ #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_ */ - +/* TBI_ACCEPT macro definition: + * + * If Tbi Compatibility mode is turned-on, then we should accept frames with + * receive errors if and only if: + * 1) errors is equal to the CRC error bit. + * 2) The last byte is a Carrier extension (0x0F). + * 3) The frame length (as reported by Hardware) is greater than 64 (60 + * if a VLAN tag was stripped from the frame. + * 4) " " " " " " " <= max_frame_size+1. + * + * This macro requires: + * adapter = a pointer to struct em_shared_adapter + * special = the 16 bit special field of the RX descriptor with EOP set + * error = the 8 bit error field of the RX descriptor with EOP set + * length = the sum of all the length fields of the RX descriptors that + * make up the current frame + * last_byte = the last byte of the frame DMAed by the hardware + * max_frame_length = the maximum frame length we want to accept. + * THIS INCLUDES THE 4 BYTE ETHERNET CRC! + * + * This macro is a conditional that should be used in the interrupt + * handler's Rx processing routine when RxErrors have been detected. + * + * Typical use: + * ... + * if (TBI_ACCEPT) { + * accept_frame = TRUE; + * em_tbi_adjust_stats(adapter, MacAddress); + * frame_length--; + * } else { + * accept_frame = FALSE; + * } + * ... + */ + +#define TBI_ACCEPT(adapter, special, errors, length, last_byte) \ + ((adapter)->tbi_compatibility_on && \ + (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \ + ((last_byte) == CARRIER_EXTENSION) && \ + ((special == 0x0000) ? \ + ((length <= ((adapter)->max_frame_size + 1)) && \ + (length > 64)) : \ + ((length <= ((adapter)->max_frame_size - 3)) && \ + (length > 60)))) + + +#endif /* _EM_MAC_H_ */ diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h index 6097b51..9d4b923 100644 --- a/sys/dev/em/if_em_osdep.h +++ b/sys/dev/em/if_em_osdep.h @@ -1,5 +1,4 @@ /************************************************************************** -************************************************************************** Copyright (c) 2001 Intel Corporation All rights reserved. @@ -32,32 +31,37 @@ 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$ -*************************************************************************** ***************************************************************************/ +/*$FreeBSD$*/ + #ifndef _FREEBSD_OS_H_ #define _FREEBSD_OS_H_ #include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/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> + #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 usec_delay(x) DELAY(x) +#define msec_delay(x) DELAY(1000*(x)) #define MSGOUT(S, A, B) printf(S "\n", A, B) #define DEBUGFUNC(F) DEBUGOUT(F); @@ -75,21 +79,57 @@ typedef struct _E1000_64_BIT_PHYSICAL_ADDRESS { #define DEBUGOUT7(S,A,B,C,D,E,F,G) #endif +#define FALSE 0 +#define TRUE 1 +#define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */ +#define PCI_COMMAND_REGISTER PCIR_COMMAND + +struct em_osdep +{ + bus_space_tag_t bus_space_tag; + bus_space_handle_t bus_space_handle; + struct device *dev; +}; + +#define E1000_READ_REG(a, reg) (\ + ((a)->mac_type >= em_82543) ? \ + bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + E1000_##reg): \ + bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + E1000_82542_##reg)) + + +#define E1000_WRITE_REG(a, reg, value) (\ + ((a)->mac_type >= em_82543) ? \ + bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + E1000_##reg, value): \ + bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + E1000_82542_##reg, value)) + + +#define E1000_READ_REG_ARRAY(a, reg, offset) (\ + ((a)->mac_type >= em_82543) ? \ + bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + (E1000_##reg + ((offset) << 2))): \ + bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + (E1000_82542_##reg + ((offset) << 2)))) + + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) (\ + ((a)->mac_type >= em_82543) ? \ + bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + (E1000_##reg + ((offset) << 2)), value): \ + bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \ + ((struct em_osdep *)(a)->back)->bus_space_handle, \ + (E1000_82542_##reg + ((offset) << 2)), value)) -#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 index 470e516..d359b28 100644 --- a/sys/dev/em/if_em_phy.c +++ b/sys/dev/em/if_em_phy.c @@ -1,1223 +1,1544 @@ -/************************************************************************* -************************************************************************** -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 -*/ +/******************************************************************************* + + 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$*/ +/* if_em_phy.c + * Shared functions for accessing and configuring the PHY + */ #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; +/****************************************************************************** +* Raises the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +em_raise_mdc(struct em_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Raise the clock input to the Management Data Clock (by setting + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC)); + usec_delay(2); + 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); +/****************************************************************************** +* Lowers the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +em_lower_mdc(struct em_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Lower the clock input to the Management Data Clock (by clearing + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC)); + usec_delay(2); + return; } -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); +/****************************************************************************** +* Shifts data bits out to the PHY +* +* shared - Struct containing variables accessed by shared code +* data - Data to send out to the PHY +* count - Number of bits to shift out +* +* Bits are shifted out in MSB to LSB order. +******************************************************************************/ +static void +em_phy_shift_out(struct em_shared_adapter *shared, + uint32_t data, + uint16_t count) +{ + uint32_t ctrl_reg; + uint32_t mask; + + ASSERT(count <= 32); + + /* We need to shift "count" number of bits out to the PHY. So, the + * value in the "Data" parameter will be shifted out to the PHY + * one bit at a time. In order to do this, "Data" must be broken + * down into bits, which is what the "while" logic does below. + */ + mask = 0x01; + mask <<= (count - 1); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to + * be used as output pins. + */ + ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); + + while(mask) { + /* A "1" is shifted out to the PHY by setting the MDIO bit to + * "1" and then raising and lowering the Management Data Clock + * (MDC). A "0" is shifted out to the PHY by setting the MDIO + * bit to "0" and then raising and lowering the clock. + */ + if(data & mask) + ctrl_reg |= E1000_CTRL_MDIO; + else + ctrl_reg &= ~E1000_CTRL_MDIO; - DelayInMicroseconds(2); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); - em_raise_mdc_clock(Adapter, &CtrlRegValue); - em_lower_mdc_clock(Adapter, &CtrlRegValue); + usec_delay(2); - Mask = Mask >> 1; - } - - CtrlRegValue &= ~E1000_CTRL_MDIO; -} + em_raise_mdc(shared, &ctrl_reg); + em_lower_mdc(shared, &ctrl_reg); -static void em_raise_mdc_clock(struct adapter *Adapter, u32 * CtrlRegValue) - { + mask = mask >> 1; + } - E1000_WRITE_REG(Ctrl, (*CtrlRegValue | E1000_CTRL_MDC)); - - DelayInMicroseconds(2); + /* Clear the data bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + return; } -static void em_lower_mdc_clock(struct adapter *Adapter, u32 * CtrlRegValue) - { - - E1000_WRITE_REG(Ctrl, (*CtrlRegValue & ~E1000_CTRL_MDC)); - - DelayInMicroseconds(2); +/****************************************************************************** +* Shifts data bits in from the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Bits are shifted in in MSB to LSB order. +******************************************************************************/ +static uint16_t +em_phy_shift_in(struct em_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint16_t data = 0; + uint8_t i; + + /* In order to read a register from the PHY, we need to shift in a + * total of 18 bits from the PHY. The first two bit (TurnAround) + * times are used to avoid contention on the MDIO pin when a read + * operation is performed. These two bits are ignored by us and + * thrown away. Bits are "shifted in" by raising the clock input + * to the Management Data Clock (setting the MDC bit), and then + * reading the value of the MDIO bit. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as + * input. + */ + ctrl_reg &= ~E1000_CTRL_MDIO_DIR; + ctrl_reg &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Raise and Lower the clock before reading in the data. This + * accounts for the TurnAround bits. The first clock occurred + * when we clocked out the last bit of the Register Address. + */ + em_raise_mdc(shared, &ctrl_reg); + em_lower_mdc(shared, &ctrl_reg); + + for(data = 0, i = 0; i < 16; i++) { + data = data << 1; + em_raise_mdc(shared, &ctrl_reg); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Check to see if we shifted in a "1". */ + if(ctrl_reg & E1000_CTRL_MDIO) + data |= 1; + + em_lower_mdc(shared, &ctrl_reg); + } + + em_raise_mdc(shared, &ctrl_reg); + em_lower_mdc(shared, &ctrl_reg); + + /* Clear the MDIO bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + + return (data); } -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; +/****************************************************************************** +* Force PHY speed and duplex settings to shared->forced_speed_duplex +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +static void +em_phy_force_speed_duplex(struct em_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint32_t ctrl_reg; + uint32_t shift; + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_data; + uint16_t i; + + DEBUGFUNC("em_phy_force_speed_duplex"); + + /* Turn off Flow control if we are forcing speed and duplex. */ + shared->fc = em_fc_none; + + DEBUGOUT1("shared->fc = %d\n", shared->fc); + + /* Read the Device Control Register. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); - E1000_WRITE_REG(Exct, ExtCtrlRegValue); + /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */ + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); - DelayInMilliseconds(20); + /* Clear the Auto Speed Detect Enable bit. */ + ctrl_reg &= ~E1000_CTRL_ASDE; - ExtCtrlRegValue = E1000_READ_REG(Exct); + /* Read the MII Control Register. */ + mii_ctrl_reg = em_read_phy_reg(shared, PHY_CTRL); + + /* We need to disable Autoneg in order to force link and duplex. */ + + mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN; + + /* Are we forcing Full or Half Duplex? */ + if(shared->forced_speed_duplex == em_100_full || + shared->forced_speed_duplex == em_10_full) { + + /* We want to force full duplex so we SET the full duplex bits + * in the Device and MII Control Registers. + */ + ctrl_reg |= E1000_CTRL_FD; + mii_ctrl_reg |= MII_CR_FULL_DUPLEX; + + DEBUGOUT("Full Duplex\n"); + } else { + + /* We want to force half duplex so we CLEAR the full duplex + * bits in the Device and MII Control Registers. + */ + ctrl_reg &= ~E1000_CTRL_FD; + mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; /* Do this implies HALF */ + + DEBUGOUT("Half Duplex\n"); + } + + /* Are we forcing 100Mbps??? */ + if(shared->forced_speed_duplex == em_100_full || + shared->forced_speed_duplex == em_100_half) { + + /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */ + ctrl_reg |= E1000_CTRL_SPD_100; + mii_ctrl_reg |= MII_CR_SPEED_100; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + + DEBUGOUT("Forcing 100mb "); + } else { /* Force 10MB Full or Half */ + + /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */ + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + mii_ctrl_reg |= MII_CR_SPEED_10; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + + DEBUGOUT("Forcing 10mb "); + } + + /* Now we need to configure the Collision Distance. We need to read + * the Transmit Control Register to do this. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) { + + /* We are in Half Duplex mode so we need to set up our collision + * distance for 10/100. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Write the MII Control Register with the new PHY configuration. */ + phy_data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Clear Auto-Crossover to force MDI manually. + * M88E1000 requires MDI forced whenever speed/duplex is forced + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + em_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + + DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); + + /* Need to reset the PHY or these bits will get ignored. */ + mii_ctrl_reg |= MII_CR_RESET; + + em_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* The wait_autoneg_complete flag may be a little misleading here. + * Since we are forcing speed and duplex, Auto-Neg is not enabled. + * But we do want to delay for a period while forcing only so we + * don't generate false No Link messages. So we will wait here + * only if the user has set wait_autoneg_complete to 1, which is + * the default. + */ + if(shared->wait_autoneg_complete) { + /* We will wait for AutoNeg to complete. */ + DEBUGOUT("Waiting for forced speed/duplex link.\n"); + mii_status_reg = 0; + + /* We will wait for AutoNeg to complete or 4.5 seconds to expire. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_LINK_STATUS) + break; - ExtCtrlRegValue |= E1000_CTRL_PHY_RESET4; + msec_delay(100); + } /* end for loop */ - E1000_WRITE_REG(Exct, ExtCtrlRegValue); + if(i == 0) { /* We didn't get link */ - DelayInMilliseconds(20); + /* Reset the DSP and wait again for link. */ + em_phy_reset_dsp(shared); } - return; -} + /* This loop will early-out if the link condition has been met. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; -u8 em_phy_reset(struct adapter * Adapter) - { - u16 RegData; - u16 i; + msec_delay(100); + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); - DEBUGFUNC("em_phy_reset") + } /* end for loop */ + } /* end if wait_autoneg_complete */ + /* + * Because we reset the PHY above, we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock. This + * value defaults back to a 2.5MHz clock when the PHY is reset. + */ + phy_data = em_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); - RegData = em_read_phy_register(Adapter, - PHY_MII_CTRL_REG, - Adapter->PhyAddress); + phy_data |= M88E1000_EPSCR_TX_CLK_25; - RegData |= MII_CR_RESET; + em_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); - em_write_phy_register(Adapter, - PHY_MII_CTRL_REG, - Adapter->PhyAddress, RegData); + /* In addition, because of the s/w reset above, we need to enable + * CRS on TX. This must be set for both full and half duplex + * operation. + */ + phy_data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); - i = 0; - while ((RegData & MII_CR_RESET) && i++ < 500) { - RegData = em_read_phy_register(Adapter, - PHY_MII_CTRL_REG, - Adapter->PhyAddress); - DelayInMicroseconds(1); - } + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - if (i >= 500) { - DEBUGOUT("Timeout waiting for PHY to reset.\n"); - return 0; - } + em_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data); - return 1; + return; } -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; +/***************************************************************************** +* Reads the value from a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to read +******************************************************************************/ +uint16_t +em_read_phy_reg(struct em_shared_adapter *shared, + uint32_t reg_addr) +{ + uint32_t i; + uint32_t data = 0; + uint32_t command = 0; + + DEBUGFUNC("em_read_phy_reg"); + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > em_82543) { + /* Set up Op-code, Phy Address, and + * register address in the MDI Control register. The MAC will + * take care of interfacing with the PHY to retrieve the + * desired data. + */ + command = ((reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + DEBUGOUT1("Writing 0x%X to MDIC\n", command); + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 64; i++) { + usec_delay(10); + + data = E1000_READ_REG(shared, MDIC); + + DEBUGOUT1("Read 0x%X from MDIC\n", data); + if(data & E1000_MDIC_READY) 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); + } else { + /* We must first send a preamble through the MDIO pin to signal the + * beginning of an MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + em_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the next few fields that are required for a read + * operation. We use this method instead of calling the + * em_phy_shift_out routine five different times. The format of + * a MII read instruction consists of a shift out of 14 bits and is + * defined as follows: + * <Preamble><SOF><Op Code><Phy Addr><Reg Addr> + * followed by a shift in of 18 bits. This first two bits shifted + * in are TurnAround bits used to avoid contention on the MDIO pin + * when a READ operation is performed. These two bits are thrown + * away followed by a shift in of 16 bits which contains the + * desired data. + */ + command = ((reg_addr) | + (shared->phy_addr << 5) | + (PHY_OP_READ << 10) | (PHY_SOF << 12)); + + em_phy_shift_out(shared, command, 14); + + /* Now that we've shifted out the read command to the MII, we need + * to "shift in" the 16-bit value (18 total bits) of the requested + * PHY register address. + */ + data = (uint32_t) em_phy_shift_in(shared); + } + + ASSERT(!(data & E1000_MDIC_ERROR)); + + return ((uint16_t) data); } -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); +/****************************************************************************** +* Writes a value to a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to write +* data - data to write to the PHY +******************************************************************************/ +void +em_write_phy_reg(struct em_shared_adapter *shared, + uint32_t reg_addr, + uint16_t data) +{ + uint32_t i; + uint32_t command = 0; + uint32_t mdic_reg; + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > em_82543) { + /* Set up Op-code, Phy Address, register + * address, and data intended for the PHY register in the MDI + * Control register. The MAC will take care of interfacing + * with the PHY to send the desired data. + */ + command = (((uint32_t) data) | + (reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 10; i++) { + usec_delay(10); + + mdic_reg = E1000_READ_REG(shared, MDIC); + + if(mdic_reg & E1000_MDIC_READY) 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); + } else { + /* We'll need to use the SW defined pins to shift the write command + * out to the PHY. We first send a preamble to the PHY to signal the + * beginning of the MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + em_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the remaining required fields that will indicate + * a write operation. We use this method instead of calling the + * em_phy_shift_out routine for each field in the command. The + * format of a MII write instruction is as follows: + * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>. + */ + command = ((PHY_TURNAROUND) | + (reg_addr << 2) | + (shared->phy_addr << 7) | + (PHY_OP_WRITE << 12) | (PHY_SOF << 14)); + command <<= 16; + command |= ((uint32_t) data); + + em_phy_shift_out(shared, command, 32); + } + return; } -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; - } +/****************************************************************************** +* Returns the PHY to the power-on reset state +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +em_phy_hw_reset(struct em_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t ctrl_ext_reg; - E1000_WRITE_REG(Tctl, TctlReg); + DEBUGFUNC("em_phy_hw_reset"); - E1000_WRITE_REG(Ctrl, DeviceCtrlReg); + DEBUGOUT("Resetting Phy...\n"); - PhyData = em_read_phy_register(Adapter, - PXN_PHY_SPEC_CTRL_REG, - Adapter->PhyAddress); + if(shared->mac_type > em_82543) { + /* Read the device control register and assert the + * E1000_CTRL_PHY_RST bit. Hold for 20ms and then take it out + * of reset. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); - PhyData &= ~PXN_PSCR_AUTO_X_MODE; + ctrl_reg |= E1000_CTRL_PHY_RST; - em_write_phy_register(Adapter, - PXN_PHY_SPEC_CTRL_REG, - Adapter->PhyAddress, PhyData); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); - DEBUGOUT1("Paxson PSCR: %x \n", PhyData); + msec_delay(20); - MiiCtrlReg |= MII_CR_RESET; + ctrl_reg &= ~E1000_CTRL_PHY_RST; - em_write_phy_register(Adapter, - PHY_MII_CTRL_REG, - Adapter->PhyAddress, MiiCtrlReg); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); - if (Adapter->WaitAutoNegComplete) { + msec_delay(20); + } else { + /* Read the Extended Device Control Register, assert the + * PHY_RESET_DIR bit. Then clock it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRLEXT); - DEBUGOUT("Waiting for forced speed/duplex link.\n"); - MiiStatusReg = 0; + ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4; -#define PHY_WAIT_FOR_FORCED_TIME 20 + E1000_WRITE_REG(shared, CTRLEXT, ctrl_ext_reg); - for (i = 20; i > 0; i--) { + msec_delay(20); - MiiStatusReg = em_read_phy_register(Adapter, - PHY_MII_STATUS_REG, - Adapter-> - PhyAddress); + /* Set the reset bit in the device control register and clock + * it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRLEXT); - MiiStatusReg = em_read_phy_register(Adapter, - PHY_MII_STATUS_REG, - Adapter-> - PhyAddress); + ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4; - if (MiiStatusReg & MII_SR_LINK_STATUS) { - break; - } - DelayInMilliseconds(100); - } + E1000_WRITE_REG(shared, CTRLEXT, ctrl_ext_reg); - if (i == 0) { + msec_delay(20); - em_pxn_phy_reset_dsp(Adapter); - } + ctrl_ext_reg = E1000_READ_REG(shared, CTRLEXT); - for (i = 20; i > 0; i--) { - if (MiiStatusReg & MII_SR_LINK_STATUS) { - break; - } + ctrl_ext_reg |= E1000_CTRL_PHY_RESET4; - DelayInMilliseconds(100); + E1000_WRITE_REG(shared, CTRLEXT, ctrl_ext_reg); - MiiStatusReg = em_read_phy_register(Adapter, - PHY_MII_STATUS_REG, - Adapter-> - PhyAddress); + msec_delay(20); + } + return; +} - MiiStatusReg = em_read_phy_register(Adapter, - PHY_MII_STATUS_REG, - Adapter-> - PhyAddress); +/****************************************************************************** +* Resets the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Sets bit 15 of the MII Control regiser +******************************************************************************/ +boolean_t +em_phy_reset(struct em_shared_adapter *shared) +{ + uint16_t reg_data; + uint16_t i; + + DEBUGFUNC("em_phy_reset"); + + /* Read the MII control register, set the reset bit and write the + * value back by clocking it out to the PHY. + */ + reg_data = em_read_phy_reg(shared, PHY_CTRL); + + reg_data |= MII_CR_RESET; + + em_write_phy_reg(shared, PHY_CTRL, reg_data); + + /* Wait for bit 15 of the MII Control Register to be cleared + * indicating the PHY has been reset. + */ + i = 0; + while((reg_data & MII_CR_RESET) && i++ < 500) { + reg_data = em_read_phy_reg(shared, PHY_CTRL); + usec_delay(1); + } + + if(i >= 500) { + DEBUGOUT("Timeout waiting for PHY to reset.\n"); + return FALSE; + } + return TRUE; +} - } +/****************************************************************************** +* Detects which PHY is present and the speed and duplex +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - current value of the device control register +******************************************************************************/ +boolean_t +em_phy_setup(struct em_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + uint16_t i; + uint16_t data; + uint16_t autoneg_hw_setting; + uint16_t autoneg_fc_setting; + boolean_t restart_autoneg = FALSE; + boolean_t force_autoneg_restart = FALSE; + + DEBUGFUNC("em_phy_setup"); + + /* We want to enable the Auto-Speed Detection bit in the Device + * Control Register. When set to 1, the MAC automatically detects + * the resolved speed of the link and self-configures appropriately. + * The Set Link Up bit must also be set for this behavior work + * properly. + */ + /* Nothing but 82543 and newer */ + ASSERT(shared->mac_type >= em_82543); + + /* With 82543, we need to force speed/duplex + * on the MAC equal to what the PHY speed/duplex configuration is. + * In addition, on 82543, we need to perform a hardware reset + * on the PHY to take it out of reset. + */ + if(shared->mac_type >= em_82544) { + ctrl_reg |= (E1000_CTRL_ASDE | E1000_CTRL_SLU); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + } else { + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + if(shared->mac_type == em_82543) + em_phy_hw_reset(shared); + } + + if(!em_detect_gig_phy(shared)) { + /* No PHY detected, return FALSE */ + DEBUGOUT("PhySetup failure, did not detect valid phy.\n"); + return (FALSE); + } + + DEBUGOUT1("Phy ID = %x \n", shared->phy_id); + + /* Read the MII Control Register. */ + mii_ctrl_reg = em_read_phy_reg(shared, PHY_CTRL); + + DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg); + + /* Check to see if the Auto Neg Enable bit is set in the MII Control + * Register. If not, we could be in a situation where a driver was + * loaded previously and was forcing speed and duplex. Then the + * driver was unloaded but a em_phy_hw_reset was not performed, so + * link was still being forced and link was still achieved. Then + * the driver was reloaded with the intention to auto-negotiate, but + * since link is already established we end up not restarting + * auto-neg. So if the auto-neg bit is not enabled and the driver + * is being loaded with the desire to auto-neg, we set this flag to + * to ensure the restart of the auto-neg engine later in the logic. + */ + if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN)) + force_autoneg_restart = TRUE; + + /* Clear the isolate bit for normal operation and write it back to + * the MII Control Reg. Although the spec says this doesn't need + * to be done when the PHY address is not equal to zero, we do it + * anyway just to be safe. + */ + mii_ctrl_reg &= ~(MII_CR_ISOLATE); + + em_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + DEBUGOUT1("M88E1000 PSCR: %x \n", data); + + em_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data); + + data = em_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + data |= M88E1000_EPSCR_TX_CLK_25; + + em_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data); + + /* Certain PHYs will set the default of MII register 4 differently. + * We need to check this against our fc value. If it is + * different, we need to setup up register 4 correctly and restart + * autonegotiation. + */ + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = em_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Shift left to put 10T-Half bit in bit 0 + * Isolate the four bits for 100/10 Full/Half. + */ + autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF; + + /* Get the 1000T settings. */ + mii_1000t_ctrl_reg = em_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Isolate and OR in the 1000T settings. */ + autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4); + + /* mask all bits in the MII Auto-Neg Advertisement Register + * except for ASM_DIR and PAUSE and shift. This value + * will be used later to see if we need to restart Auto-Negotiation. + */ + autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10); + + /* Perform some bounds checking on the shared->autoneg_advertised + * parameter. If this variable is zero, then set it to the default. + */ + shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if(shared->autoneg_advertised == 0) + shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* We could be in the situation where Auto-Neg has already completed + * and the user has not indicated any overrides. In this case we + * simply need to call em_get_speed_and_duplex to obtain the Auto- + * Negotiated speed and duplex, then return. + */ + if(!force_autoneg_restart && shared->autoneg && + (shared->autoneg_advertised == autoneg_hw_setting) && + (shared->fc == autoneg_fc_setting)) { + + DEBUGOUT("No overrides - Reading MII Status Reg..\n"); + + /* Read the MII Status Register. We read this twice because + * certain bits are "sticky" and need to be read twice. + */ + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg); + + /* Do we have link now? (if so, auto-neg has completed) */ + if(mii_status_reg & MII_SR_LINK_STATUS) { + data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established + * with the link partner. + */ + if(shared->mac_type >= em_82544) + em_config_collision_dist(shared); + else + em_config_mac_to_phy(shared, data); + + em_config_fc_after_link_up(shared); + + return (TRUE); } + } + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_specific_ctrl_reg = em_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (shared->mdix) { + case 1: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + em_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_specific_ctrl_reg = em_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL; + + if(shared->disable_polarity_correction == 1) + phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL; + + em_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * autoneg = 1 (default) + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * autoneg = 0 + * PHY will be set to 10H, 10F, 100H, or 100F + * depending on value parsed from forced_speed_duplex. + */ + + /* Is AutoNeg enabled? This is enabled by default or by software + * override. If so, + * call PhySetupAutoNegAdvertisement routine to parse the + * autoneg_advertised and fc options. + * If AutoNeg is NOT enabled, then the user should have provided + * a Speed/Duplex override. If so, then call the + * PhyForceSpeedAndDuplex to parse and set this up. Otherwise, + * we are in an error situation and need to bail. + */ + if(shared->autoneg) { + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + restart_autoneg = em_phy_setup_autoneg(shared); + } else { + DEBUGOUT("Forcing speed and duplex\n"); + em_phy_force_speed_duplex(shared); + } + + /* Based on information parsed above, check the flag to indicate + * whether we need to restart Auto-Neg. + */ + if(restart_autoneg) { + DEBUGOUT("Restarting Auto-Neg\n"); + + /* Read the MII Control Register. */ + mii_ctrl_reg = em_read_phy_reg(shared, PHY_CTRL); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit. + */ + mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + + em_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if(shared->wait_autoneg_complete) + em_wait_autoneg(shared); + } /* end if restart_autoneg */ + + /* Read the MII Status Register. */ + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n", + mii_status_reg); + + /* Check link status. Wait up to 100 microseconds for link to + * become valid. + */ + for(i = 0; i < 10; i++) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + usec_delay(10); + DEBUGOUT(". "); + + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + } + + if(mii_status_reg & MII_SR_LINK_STATUS) { + /* Yes, so configure MAC to PHY settings as well as flow control + * registers. + */ + data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established with + * the link partner. + */ + if(shared->mac_type >= em_82544) + em_config_collision_dist(shared); + else + em_config_mac_to_phy(shared, data); - 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_config_fc_after_link_up(shared); - 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); + DEBUGOUT("Valid link established!!!\n"); + } else { + DEBUGOUT("Unable to establish link!!!\n"); + } - return; + return (TRUE); } -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; +/****************************************************************************** +* Configures PHY autoneg and flow control advertisement settings +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +em_phy_setup_autoneg(struct em_shared_adapter *shared) +{ + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + + DEBUGFUNC("em_phy_setup_autoneg"); + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = em_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = em_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~REG4_SPEED_MASK; + mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK; + + DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_HALF) { + DEBUGOUT("Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_FULL) { + DEBUGOUT("Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_HALF) { + DEBUGOUT("Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_FULL) { + DEBUGOUT("Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if(shared->autoneg_advertised & ADVERTISE_1000_HALF) { + DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n"); + } + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_1000_FULL) { + DEBUGOUT("Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADVERTISEMENT) and re-start + * auto-negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case em_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case em_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * (in em_config_fc_after_link_up) we will disable the + *shared's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case em_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case em_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Write the MII Auto-Neg Advertisement Register (Address 4). */ + em_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + + DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + /* Write the MII 1000Base-T Control Register (Address 9). */ + em_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + return (TRUE); +} - TctlReg &= ~E1000_TCTL_COLD; - Shift32 = E1000_FDX_COLLISION_DISTANCE; - Shift32 <<= E1000_COLD_SHIFT; - TctlReg |= Shift32; +/****************************************************************************** +* Sets MAC speed and duplex settings to reflect the those in the PHY +* +* shared - Struct containing variables accessed by shared code +* mii_reg - data to write to the MII control register +* +* The contents of the PHY register containing the needed information need to +* be passed in. +******************************************************************************/ +void +em_config_mac_to_phy(struct em_shared_adapter *shared, + uint16_t mii_reg) +{ + uint32_t ctrl_reg; + uint32_t tctl_reg; + uint32_t shift; + + DEBUGFUNC("em_config_mac_to_phy"); + + /* We need to read the Transmit Control register to configure the + * collision distance. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* Read the Device Control Register and set the bits to Force Speed + * and Duplex. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); + + DEBUGOUT1("MII Register Data = %x\r\n", mii_reg); + + /* Clear the ILOS bit. */ + ctrl_reg &= ~E1000_CTRL_ILOS; + + /* Set up duplex in the Device Control and Transmit Control + * registers depending on negotiated values. + */ + if(mii_reg & M88E1000_PSSR_DPLX) { + ctrl_reg |= E1000_CTRL_FD; + + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + ctrl_reg &= ~E1000_CTRL_FD; + + /* We are in Half Duplex mode. Our Half Duplex collision + * distance is different for Gigabit than for 10/100 so we will + * set accordingly. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + /* 1000Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ } 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; - } + /* 10/100Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; } + } - 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); + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + ctrl_reg |= E1000_CTRL_SPD_1000; + else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + ctrl_reg |= E1000_CTRL_SPD_100; + else + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); - E1000_WRITE_REG(Tctl, TctlReg); + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); - E1000_WRITE_REG(Ctrl, DeviceCtrlReg); + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); - return; + 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; - } +/****************************************************************************** +* Sets the collision distance in the Transmit Control register +* +* shared - Struct containing variables accessed by shared code +* +* Link should have been established previously. Reads the speed and duplex +* information from the Device Status register. +******************************************************************************/ +void +em_config_collision_dist(struct em_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint16_t speed; + uint16_t duplex; + uint32_t shift; + + DEBUGFUNC("em_config_collision_dist"); + + /* Get our current speed and duplex from the Device Status Register. */ + em_get_speed_and_duplex(shared, &speed, &duplex); + + /* We need to configure the Collision Distance for both Full or + * Half Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* mask the Collision Distance bits in the Transmit Control Reg. */ + tctl_reg &= ~E1000_TCTL_COLD; + + if(duplex == FULL_DUPLEX) { + /* We are in Full Duplex mode. Therefore, the collision distance + * is the same regardless of speed. + */ + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Half Duplex mode. Half Duplex collision distance is + * different for Gigabit vs. 10/100, so we will set accordingly. + */ + if(speed == SPEED_1000) { /* 1000Mbs HDX */ + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ + } else { /* 10/100Mbs HDX */ + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; } + } - E1000_WRITE_REG(Tctl, TctlReg); + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); - return; + 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); +#if DBG +/****************************************************************************** +* Displays the contents of all of the MII registers +* +* shared - Struct containing variables accessed by shared code +* +* For debugging. +******************************************************************************/ +void +em_display_mii(struct em_shared_adapter *shared) +{ + uint16_t data; + uint16_t phy_id_high; + uint16_t phy_id_low; + uint32_t phy_id; - DEBUGOUT1("Reg 8 contents = %x\n", Data); + DEBUGFUNC("em_display_mii"); - Data = em_read_phy_register(Adapter, - PHY_1000T_CTRL_REG, PhyAddress); + DEBUGOUT1("adapter Base Address = %p\n", shared->hw_addr); - DEBUGOUT1("Reg 9 contents = %x\n", Data); + /* This will read each PHY Reg address and display its contents. */ - Data = em_read_phy_register(Adapter, - PHY_1000T_STATUS_REG, PhyAddress); + data = em_read_phy_reg(shared, PHY_CTRL); + DEBUGOUT1("MII Ctrl Reg contents = %x\n", data); - DEBUGOUT1("Reg A contents = %x\n", Data); + data = em_read_phy_reg(shared, PHY_STATUS); + data = em_read_phy_reg(shared, PHY_STATUS); + DEBUGOUT1("MII Status Reg contents = %x\n", data); - Data = em_read_phy_register(Adapter, - PHY_IEEE_EXT_STATUS_REG, PhyAddress); + phy_id_high = em_read_phy_reg(shared, PHY_ID1); + usec_delay(2); + phy_id_low = em_read_phy_reg(shared, PHY_ID2); + phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK; + DEBUGOUT1("Phy ID = %x \n", phy_id); - DEBUGOUT1("Reg F contents = %x\n", Data); + data = em_read_phy_reg(shared, PHY_AUTONEG_ADV); + DEBUGOUT1("Reg 4 contents = %x\n", data); - Data = em_read_phy_register(Adapter, - PXN_PHY_SPEC_CTRL_REG, PhyAddress); + data = em_read_phy_reg(shared, PHY_LP_ABILITY); + DEBUGOUT1("Reg 5 contents = %x\n", data); - DEBUGOUT1("Paxson Specific Control Reg (0x10) = %x\n", Data); + data = em_read_phy_reg(shared, PHY_AUTONEG_EXP); + DEBUGOUT1("Reg 6 contents = %x\n", data); - Data = em_read_phy_register(Adapter, - PXN_PHY_SPEC_STAT_REG, PhyAddress); + data = em_read_phy_reg(shared, PHY_NEXT_PAGE_TX); + DEBUGOUT1("Reg 7 contents = %x\n", data); - DEBUGOUT1("Paxson Specific Status Reg (0x11) = %x\n", Data); + data = em_read_phy_reg(shared, PHY_LP_NEXT_PAGE); + DEBUGOUT1("Reg 8 contents = %x\n", data); - Data = em_read_phy_register(Adapter, - PXN_INT_ENABLE_REG, PhyAddress); + data = em_read_phy_reg(shared, PHY_1000T_CTRL); + DEBUGOUT1("Reg 9 contents = %x\n", data); - DEBUGOUT1("Paxson Interrupt Enable Reg (0x12) = %x\n", Data); + data = em_read_phy_reg(shared, PHY_1000T_STATUS); + DEBUGOUT1("Reg A contents = %x\n", data); - Data = em_read_phy_register(Adapter, - PXN_INT_STATUS_REG, PhyAddress); + data = em_read_phy_reg(shared, PHY_EXT_STATUS); + DEBUGOUT1("Reg F contents = %x\n", data); - DEBUGOUT1("Paxson Interrupt Status Reg (0x13) = %x\n", Data); + data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + DEBUGOUT1("M88E1000 Specific Control Reg (0x10) = %x\n", data); - Data = em_read_phy_register(Adapter, - PXN_EXT_PHY_SPEC_CTRL_REG, PhyAddress); + data = em_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Specific Status Reg (0x11) = %x\n", data); - DEBUGOUT1("Paxson Ext. Phy Specific Control (0x14) = %x\n", Data); + /* + * data = em_read_phy_reg(shared, M88E1000_INT_ENABLE_REG); + * DEBUGOUT1("M88E1000 Interrupt Enable Reg (0x12) = %x\n", data); + */ - Data = em_read_phy_register(Adapter, - PXN_RX_ERROR_COUNTER, PhyAddress); + /* + * data = em_read_phy_reg(shared, M88E1000_INT_STATUS_REG); + * DEBUGOUT1("M88E1000 Interrupt Status Reg (0x13) = %x\n", data); + */ + + data = em_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + DEBUGOUT1("M88E1000 Ext. Phy Specific Control (0x14) = %x\n", data); - DEBUGOUT1("Paxson Receive Error Counter (0x15) = %x\n", Data); + data = em_read_phy_reg(shared, M88E1000_RX_ERR_CNTR); + DEBUGOUT1("M88E1000 Receive Error Counter (0x15) = %x\n", data); - Data = em_read_phy_register(Adapter, PXN_LED_CTRL_REG, PhyAddress); + /* + * data = em_read_phy_reg(shared, M88E1000_LED_CTRL_REG); + * DEBUGOUT1("M88E1000 LED control reg (0x18) = %x\n", data); + */ - DEBUGOUT1("Paxson LED control reg (0x18) = %x\n", Data); + return; } - -u32 em_auto_detect_gigabit_phy(struct adapter *Adapter) +#endif // DBG + +/****************************************************************************** +* Probes the expected PHY address for known PHY IDs +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +em_detect_gig_phy(struct em_shared_adapter *shared) { - u32 PhyAddress = 1; - u32 PhyIDHi; - u16 PhyIDLo; - u8 GotOne = 0; + uint32_t phy_id_high; + uint16_t phy_id_low; - DEBUGFUNC("em_auto_detect_gigabit_phy") + DEBUGFUNC("em_detect_gig_phy"); - while ((!GotOne) && (PhyAddress <= MAX_PHY_REG_ADDRESS)) { + /* Read the PHY ID Registers to identify which PHY is onboard. */ + shared->phy_addr = 1; - PhyIDHi = em_read_phy_register(Adapter, - PHY_PHY_ID_REG1, - PhyAddress); + phy_id_high = em_read_phy_reg(shared, PHY_ID1); - DelayInMicroseconds(2); + usec_delay(2); - PhyIDLo = em_read_phy_register(Adapter, - PHY_PHY_ID_REG2, - PhyAddress); + phy_id_low = em_read_phy_reg(shared, PHY_ID2); - Adapter->PhyId = - (PhyIDLo | (PhyIDHi << 16)) & PHY_REVISION_MASK; + shared->phy_id = (phy_id_low | (phy_id_high << 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); + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID) { - GotOne = 1; - } else { - PhyAddress++; - } - - } - - if (PhyAddress > MAX_PHY_REG_ADDRESS) { - DEBUGOUT("Could not auto-detect Phy!\n"); - } - - return (PhyAddress); + DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n", + shared->phy_id, shared->phy_addr); + return (TRUE); + } else { + DEBUGOUT("Could not auto-detect Phy!\n"); + return (FALSE); + } } -void em_pxn_phy_reset_dsp(struct adapter *Adapter) +/****************************************************************************** +* Resets the PHY's DSP +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +em_phy_reset_dsp(struct em_shared_adapter *shared) { - 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); + em_write_phy_reg(shared, 29, 0x1d); + em_write_phy_reg(shared, 30, 0xc1); + em_write_phy_reg(shared, 30, 0x00); + return; } -u8 em_wait_for_auto_neg(struct adapter *Adapter) +/****************************************************************************** +* Blocks until autoneg completes or times out (~4.5 seconds) +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +em_wait_autoneg(struct em_shared_adapter *shared) { - u8 AutoNegComplete = 0; - u16 i; - u16 MiiStatusReg; + uint16_t i; + uint16_t mii_status_reg; + boolean_t autoneg_complete = FALSE; - DEBUGFUNC("em_wait_for_auto_neg"); + DEBUGFUNC("em_wait_autoneg"); - DEBUGOUT("Waiting for Auto-Neg to complete.\n"); - MiiStatusReg = 0; + /* We will wait for AutoNeg to complete. */ + DEBUGOUT("Waiting for Auto-Neg to complete.\n"); + mii_status_reg = 0; - for (i = PHY_AUTO_NEG_TIME; i > 0; i--) { + /* We will wait for AutoNeg to complete or 4.5 seconds to expire. */ - MiiStatusReg = em_read_phy_register(Adapter, - PHY_MII_STATUS_REG, - Adapter->PhyAddress); + for(i = PHY_AUTO_NEG_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = em_read_phy_reg(shared, PHY_STATUS); - MiiStatusReg = em_read_phy_register(Adapter, - PHY_MII_STATUS_REG, - Adapter->PhyAddress); + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + autoneg_complete = TRUE; + break; + } - if (MiiStatusReg & MII_SR_AUTONEG_COMPLETE) { - AutoNegComplete = 1; - break; - } + msec_delay(100); + } - DelayInMilliseconds(100); - } + return (autoneg_complete); +} - return (AutoNegComplete); +/****************************************************************************** +* Get PHY information from various PHY registers +* +* shared - Struct containing variables accessed by shared code +* phy_status_info - PHY information structure +******************************************************************************/ +boolean_t +em_phy_get_info(struct em_shared_adapter *shared, + struct em_phy_info *phy_status_info) +{ + uint16_t phy_mii_shatus_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t phy_specific_status_reg; + uint16_t phy_specific_ext_ctrl_reg; + uint16_t phy_1000t_stat_reg; + + phy_status_info->cable_length = em_cable_length_undefined; + phy_status_info->extended_10bt_distance = + em_10bt_ext_dist_enable_undefined; + phy_status_info->cable_polarity = em_rev_polarity_undefined; + phy_status_info->polarity_correction = em_polarity_reversal_undefined; + phy_status_info->link_reset = em_down_no_idle_undefined; + phy_status_info->mdix_mode = em_auto_x_mode_undefined; + phy_status_info->local_rx = em_1000t_rx_status_undefined; + phy_status_info->remote_rx = em_1000t_rx_status_undefined; + + /* PHY info only valid for copper media. */ + if(shared == NULL || shared->media_type != em_media_type_copper) + return FALSE; + + /* PHY info only valid for LINK UP. Read MII status reg + * back-to-back to get link status. + */ + phy_mii_shatus_reg = em_read_phy_reg(shared, PHY_STATUS); + phy_mii_shatus_reg = em_read_phy_reg(shared, PHY_STATUS); + if((phy_mii_shatus_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) + return FALSE; + + /* Read various PHY registers to get the PHY info. */ + phy_specific_ctrl_reg = em_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + phy_specific_status_reg = + em_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + phy_specific_ext_ctrl_reg = + em_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + phy_1000t_stat_reg = em_read_phy_reg(shared, PHY_1000T_STATUS); + + phy_status_info->cable_length = + ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + + phy_status_info->extended_10bt_distance = + (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> + M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + + phy_status_info->cable_polarity = + (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >> + M88E1000_PSSR_REV_POLARITY_SHIFT; + + phy_status_info->polarity_correction = + (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >> + M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + phy_status_info->link_reset = + (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >> + M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT; + + phy_status_info->mdix_mode = + (phy_specific_status_reg & M88E1000_PSSR_MDIX) >> + M88E1000_PSSR_MDIX_SHIFT; + + phy_status_info->local_rx = + (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + phy_status_info->remote_rx = + (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + return TRUE; } -u8 em_phy_get_status_info(struct adapter * Adapter, - phy_status_info_struct * PhyStatusInfo) +boolean_t +em_validate_mdi_setting(struct em_shared_adapter *shared) { - 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; + if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) { + shared->mdix = 1; + return FALSE; + } + return TRUE; } diff --git a/sys/dev/em/if_em_phy.h b/sys/dev/em/if_em_phy.h index 737f3b17..f2cc25f 100644 --- a/sys/dev/em/if_em_phy.h +++ b/sys/dev/em/if_em_phy.h @@ -1,418 +1,386 @@ -/************************************************************************* -************************************************************************** -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$ -*************************************************************************** -**************************************************************************/ +/******************************************************************************* + + 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$*/ +/* if_em_phy.h + * Structures, enums, and macros for the PHY + */ #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> +/* PHY status info structure and supporting enums */ 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; + em_cable_length_50 = 0, + em_cable_length_50_80, + em_cable_length_80_110, + em_cable_length_110_140, + em_cable_length_140, + em_cable_length_undefined = 0xFF +} em_cable_length; 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; + em_10bt_ext_dist_enable_normal = 0, + em_10bt_ext_dist_enable_lower, + em_10bt_ext_dist_enable_undefined = 0xFF +} em_10bt_ext_dist_enable; typedef enum { - PXN_PSSR_REV_POLARITY_NORMAL = 0, - PXN_PSSR_REV_POLARITY_REVERSED, - PXN_PSSR_REV_POLARITY_UNDEFINED = 0xFF -} PXN_PSSR_REV_POLARITY_ENUM; + em_rev_polarity_normal = 0, + em_rev_polarity_reversed, + em_rev_polarity_undefined = 0xFF +} em_rev_polarity; typedef enum { - PXN_PSCR_POLARITY_REVERSAL_ENABLED = 0, - PXN_PSCR_POLARITY_REVERSAL_DISABLED, - PXN_PSCR_POLARITY_REVERSAL_UNDEFINED = 0xFF -} PXN_PSCR_POLARITY_REVERSAL_ENUM; + em_polarity_reversal_enabled = 0, + em_polarity_reversal_disabled, + em_polarity_reversal_undefined = 0xFF +} em_polarity_reversal; 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; + em_down_no_idle_no_detect = 0, + em_down_no_idle_detect, + em_down_no_idle_undefined = 0xFF +} em_down_no_idle; 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; + em_auto_x_mode_manual_mdi = 0, + em_auto_x_mode_manual_mdix, + em_auto_x_mode_auto1, + em_auto_x_mode_auto2, + em_auto_x_mode_undefined = 0xFF +} em_auto_x_mode; 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); - + em_1000t_rx_status_not_ok = 0, + em_1000t_rx_status_ok, + em_1000t_rx_status_undefined = 0xFF +} em_1000t_rx_status; + +struct em_phy_info { + em_cable_length cable_length; + em_10bt_ext_dist_enable extended_10bt_distance; + em_rev_polarity cable_polarity; + em_polarity_reversal polarity_correction; + em_down_no_idle link_reset; + em_auto_x_mode mdix_mode; + em_1000t_rx_status local_rx; + em_1000t_rx_status remote_rx; +}; + +/* Function Prototypes */ +uint16_t em_read_phy_reg(struct em_shared_adapter *shared, + uint32_t reg_addr); +void em_write_phy_reg(struct em_shared_adapter *shared, + uint32_t reg_addr, + uint16_t data); +void em_phy_hw_reset(struct em_shared_adapter *shared); +boolean_t em_phy_reset(struct em_shared_adapter *shared); +boolean_t em_phy_setup(struct em_shared_adapter *shared, + uint32_t ctrl_reg); +boolean_t em_phy_setup_autoneg(struct em_shared_adapter *shared); +void em_config_mac_to_phy(struct em_shared_adapter *shared, + uint16_t mii_reg); +void em_config_collision_dist(struct em_shared_adapter *shared); +void em_display_mii(struct em_shared_adapter *shared); +boolean_t em_detect_gig_phy(struct em_shared_adapter *shared); +void em_phy_reset_dsp(struct em_shared_adapter *shared); +boolean_t em_wait_autoneg(struct em_shared_adapter *shared); +boolean_t em_phy_get_info(struct em_shared_adapter *shared, + struct em_phy_info *phy_status_info); +boolean_t em_validate_mdi_setting(struct em_shared_adapter * shared); + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ #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 +#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR +#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CTRL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ +#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ +#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ + +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register */ +#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */ + +/* Next Page TX Register */ +#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* Link Partner Next Page Register */ +#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ +#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */ +#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */ + +#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */ + /* (0=enable, 1=disable) */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, + * 0=CLK125 toggling + */ +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, + * 100BASE-TX/10BASE-T: + * MDI Mode + */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. + */ +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 + /* 1=Enable Extended 10BASE-T distance + * (Lower 10BASE-T RX Threshold) + * 0=Normal 10BASE-T RX Threshold */ +#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 + /* 1=5-Bit interface in 100BASE-TX + * 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5 +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; + * 3=110-140M;4=>140M */ +#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ +#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ +#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_REV_POLARITY_SHIFT 1 +#define M88E1000_PSSR_MDIX_SHIFT 6 +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* M88E1000 Extended PHY Specific Control Register */ +#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ +#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled. + * Will assert lost lock and bring + * link down if idle not seen + * within 1ms in 1000BASE-T + */ +#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + +#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15 + +/* Bit definitions for valid PHY IDs. */ +#define M88E1000_12_PHY_ID 0x01410C50 +#define M88E1000_14_PHY_ID 0x01410C40 +#define M88E1000_I_PHY_ID 0x01410C30 + +/* Miscellaneous PHY bit definitions. */ +#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 PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */ +#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 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ #endif /* _EM_PHY_H_ */ - |