From 9918575c8a3c567575e9ef1744c2464690eb828e Mon Sep 17 00:00:00 2001 From: pdeuskar Date: Fri, 8 Nov 2002 18:14:17 +0000 Subject: - Set RS (Report Status) bit on all descriptors of a packet instead of just the last one. - Set RDTR to zero by default instead of 28. - Fixed a problem with TX hangs with jumbo frames when number of fragments in the mbuf chain is large. - Added support for 82540EP based cards. MFC after: 3 days --- sys/dev/em/README | 6 +- sys/dev/em/if_em.c | 1050 ++++++++++++++++++++++++---------------------- sys/dev/em/if_em.h | 141 ++++++- sys/dev/em/if_em_hw.c | 175 ++++++-- sys/dev/em/if_em_hw.h | 60 ++- sys/dev/em/if_em_osdep.h | 2 + 6 files changed, 841 insertions(+), 593 deletions(-) (limited to 'sys') diff --git a/sys/dev/em/README b/sys/dev/em/README index 4603056..7288074 100644 --- a/sys/dev/em/README +++ b/sys/dev/em/README @@ -2,7 +2,7 @@ $FreeBSD$ FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters ============================================================ -July 2, 2002 +September 11, 2002 Contents @@ -21,7 +21,7 @@ Contents In This Release =============== -This file describes the FreeBSD* driver, version 1.3.x, for the Intel(R) +This file describes the FreeBSD* driver, version 1.4.x, for the Intel(R) PRO/1000 Family of Adapters. This driver has been developed for use with FreeBSD, version 4.6. As a new feature for this release, the driver is now compiled by default into the FreeBSD 4.6 kernel. @@ -155,7 +155,7 @@ NOTE: You must have kernel sources installed in order to compile the driver Remove the following lines from the /usr/src/sys/conf/files.i386 file, if they exist: - /dev/em/if_em_fxhw.c optional em + /dev/em/if_em_fx_hw.c optional em /dev/em/if_em_phy.c optional em Compile and install the kernel. diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index 8859b88..1915e91 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -51,7 +51,7 @@ struct adapter *em_adapter_list = NULL; * Driver version *********************************************************************/ -char em_driver_version[] = "1.3.14"; +char em_driver_version[] = "1.4.7"; /********************************************************************* @@ -74,15 +74,18 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} }; - /********************************************************************* * Table of branding strings for all supported NICs. *********************************************************************/ @@ -130,7 +133,6 @@ static void em_receive_checksum(struct adapter *, struct mbuf *); static void em_transmit_checksum_setup(struct adapter *, struct mbuf *, - struct em_tx_buffer *, u_int32_t *, u_int32_t *); static void em_set_promisc(struct adapter *); @@ -139,8 +141,9 @@ static void em_set_multi(struct adapter *); static void em_print_hw_stats(struct adapter *); static void em_print_link_status(struct adapter *); static int em_get_buf(struct em_rx_buffer *, struct adapter *, - struct mbuf *); + struct mbuf *); static void em_enable_vlans(struct adapter *adapter); +static int em_encap(struct adapter *adapter, struct mbuf *m_head); /********************************************************************* * FreeBSD Device Interface Entry Points @@ -256,10 +259,10 @@ em_attach(device_t dev) em_identify_hardware(adapter); /* Parameters (to be read from user) */ - adapter->num_tx_desc = MAX_TXD; - adapter->num_rx_desc = MAX_RXD; - adapter->tx_int_delay = TIDV; - adapter->rx_int_delay = RIDV; + adapter->num_tx_desc = EM_MAX_TXD; + adapter->num_rx_desc = EM_MAX_RXD; + adapter->tx_int_delay = EM_TIDV; + adapter->rx_int_delay = EM_RDTR; adapter->hw.autoneg = DO_AUTO_NEG; adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; @@ -431,6 +434,12 @@ em_detach(device_t dev) return(0); } +/********************************************************************* + * + * Shutdown entry point + * + **********************************************************************/ + static int em_shutdown(device_t dev) { @@ -439,7 +448,6 @@ em_shutdown(device_t dev) return(0); } - /********************************************************************* * Transmit entry point * @@ -454,128 +462,34 @@ static void em_start(struct ifnet *ifp) { int s; - struct mbuf *m_head, *mp; - vm_offset_t virtual_addr; - u_int32_t txd_upper; - u_int32_t txd_lower; - struct em_tx_buffer *tx_buffer; - struct em_tx_desc *current_tx_desc = NULL; - struct adapter * adapter = ifp->if_softc; + struct mbuf *m_head; + struct adapter *adapter = ifp->if_softc; if (!adapter->link_active) return; s = splimp(); while (ifp->if_snd.ifq_head != NULL) { - struct ifvlan *ifv = NULL; - + IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; - if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) - em_clean_transmit_interrupts(adapter); - - if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) { + if (em_encap(adapter, m_head)) { ifp->if_flags |= IFF_OACTIVE; IF_PREPEND(&ifp->if_snd, m_head); - adapter->no_tx_desc_avail++; break; } - tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); - if (!tx_buffer) { - adapter->no_tx_buffer_avail1++; - /* - * OK so we should not get here but I've seen it so let - * us try to clean up and then try to get a tx_buffer - * again and only break if we still don't get one. - */ - em_clean_transmit_interrupts(adapter); - tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); - if (!tx_buffer) { - ifp->if_flags |= IFF_OACTIVE; - IF_PREPEND(&ifp->if_snd, m_head); - adapter->no_tx_buffer_avail2++; - break; - } - } - STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry); - - tx_buffer->num_tx_desc_used = 0; - tx_buffer->m_head = m_head; - - if (ifp->if_hwassist > 0) { - em_transmit_checksum_setup(adapter, m_head, tx_buffer, - &txd_upper, &txd_lower); - } else { - txd_upper = 0; - txd_lower = 0; - } - - /* Find out if we are in vlan mode */ - if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && - m_head->m_pkthdr.rcvif != NULL && - m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) - ifv = m_head->m_pkthdr.rcvif->if_softc; - - - for (mp = m_head; mp != NULL; mp = mp->m_next) { - if (mp->m_len == 0) - continue; - current_tx_desc = adapter->next_avail_tx_desc; - virtual_addr = mtod(mp, vm_offset_t); - current_tx_desc->buffer_addr = vtophys(virtual_addr); - - current_tx_desc->lower.data = (txd_lower | mp->m_len); - current_tx_desc->upper.data = (txd_upper); - - if (current_tx_desc == adapter->last_tx_desc) - adapter->next_avail_tx_desc = - adapter->first_tx_desc; - else - adapter->next_avail_tx_desc++; - - adapter->num_tx_desc_avail--; - tx_buffer->num_tx_desc_used++; - } - - /* Put this tx_buffer at the end in the "in use" list */ - STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer, - em_tx_entry); - - if (ifv != NULL) { - /* Tell hardware to add tag */ - current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; - - /* Set the vlan id */ - current_tx_desc->upper.fields.special = ifv->ifv_tag; - } - - /* - * Last Descriptor of Packet needs End Of Packet (EOP), Report Status - * (RS) and append Ethernet CRC (IFCS) bits set. - */ - current_tx_desc->lower.data |= (adapter->txd_cmd | E1000_TXD_CMD_EOP); - /* Send a copy of the frame to the BPF listener */ if (ifp->if_bpf) bpf_mtap(ifp, m_head); - /* - * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 - * that this frame is available to transmit. - */ - E1000_WRITE_REG(&adapter->hw, TDT, - (((uintptr_t) adapter->next_avail_tx_desc - - (uintptr_t) adapter->first_tx_desc) >> 4)); - } /* end of while loop */ + /* Set timeout in case hardware has problems transmitting */ + ifp->if_timer = EM_TX_TIMEOUT; + } splx(s); - - /* Set timeout in case chip has problems transmitting */ - ifp->if_timer = EM_TX_TIMEOUT; - return; } @@ -667,107 +581,6 @@ em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) return(error); } -static void -em_set_promisc(struct adapter * adapter) -{ - - u_int32_t reg_rctl; - struct ifnet *ifp = &adapter->interface_data.ac_if; - - reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - - if (ifp->if_flags & IFF_PROMISC) { - reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - } else if (ifp->if_flags & IFF_ALLMULTI) { - reg_rctl |= E1000_RCTL_MPE; - reg_rctl &= ~E1000_RCTL_UPE; - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - } - - return; -} - -static void -em_disable_promisc(struct adapter * adapter) -{ - u_int32_t reg_rctl; - - reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - - reg_rctl &= (~E1000_RCTL_UPE); - reg_rctl &= (~E1000_RCTL_MPE); - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - - return; -} - - -/********************************************************************* - * Multicast Update - * - * This routine is called whenever multicast address list is updated. - * - **********************************************************************/ - -static void -em_set_multi(struct adapter * adapter) -{ - u_int32_t reg_rctl = 0; - u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; - u_int16_t pci_cmd_word; - struct ifmultiaddr *ifma; - int mcnt = 0; - struct ifnet *ifp = &adapter->interface_data.ac_if; - - IOCTL_DEBUGOUT("em_set_multi: begin"); - - if (adapter->hw.mac_type == em_82542_rev2_0) { - reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { - pci_cmd_word = adapter->hw.pci_cmd_word & - ~CMD_MEM_WRT_INVALIDATE; - pci_write_config(adapter->dev, PCIR_COMMAND, pci_cmd_word, 2); - } - reg_rctl |= E1000_RCTL_RST; - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - msec_delay(5); - } - -#if __FreeBSD_version < 500000 - LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { -#else - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { -#endif - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); - mcnt++; - } - - if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) { - reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - reg_rctl |= E1000_RCTL_MPE; - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - } else - em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0); - - if (adapter->hw.mac_type == em_82542_rev2_0) { - reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); - reg_rctl &= ~E1000_RCTL_RST; - E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - msec_delay(5); - if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { - pci_write_config(adapter->dev, PCIR_COMMAND, - adapter->hw.pci_cmd_word, 2); - } - } - - return; -} - /********************************************************************* * Watchdog entry point * @@ -801,62 +614,6 @@ em_watchdog(struct ifnet *ifp) } /********************************************************************* - * Timer routine - * - * This routine checks for link status and updates statistics. - * - **********************************************************************/ - -static void -em_local_timer(void *arg) -{ - int s; - struct ifnet *ifp; - struct adapter * adapter = arg; - ifp = &adapter->interface_data.ac_if; - - s = splimp(); - - em_check_for_link(&adapter->hw); - em_print_link_status(adapter); - em_update_stats_counters(adapter); - if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { - em_print_hw_stats(adapter); - } - adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); - - splx(s); - return; -} - -static void -em_print_link_status(struct adapter * adapter) -{ - if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { - if (adapter->link_active == 0) { - em_get_speed_and_duplex(&adapter->hw, - &adapter->link_speed, - &adapter->link_duplex); - printf("em%d: Link is up %d Mbps %s\n", - adapter->unit, - adapter->link_speed, - ((adapter->link_duplex == FULL_DUPLEX) ? - "Full Duplex" : "Half Duplex")); - adapter->link_active = 1; - } - } else { - if (adapter->link_active == 1) { - adapter->link_speed = 0; - adapter->link_duplex = 0; - printf("em%d: Link is Down\n", adapter->unit); - adapter->link_active = 0; - } - } - - return; -} - -/********************************************************************* * Init entry point * * This routine is used in two ways. It is used by the stack as @@ -932,35 +689,6 @@ em_init(void *arg) return; } - -/********************************************************************* - * - * This routine disables all traffic on the adapter by issuing a - * global reset on the MAC and deallocates TX/RX buffers. - * - **********************************************************************/ - -static void -em_stop(void *arg) -{ - struct ifnet *ifp; - struct adapter * adapter = arg; - ifp = &adapter->interface_data.ac_if; - - INIT_DEBUGOUT("em_stop: begin\n"); - em_disable_intr(adapter); - em_reset_hw(&adapter->hw); - untimeout(em_local_timer, adapter, adapter->timer_handle); - em_free_transmit_structures(adapter); - em_free_receive_structures(adapter); - - - /* Tell the stack that the interface is no longer active */ - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; -} - /********************************************************************* * * Interrupt Service routine @@ -1039,98 +767,411 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) } } - ifmr->ifm_status = IFM_AVALID; - ifmr->ifm_active = IFM_ETHER; - - if (!adapter->link_active) - return; - - ifmr->ifm_status |= IFM_ACTIVE; - - if (adapter->hw.media_type == em_media_type_fiber) { - ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; - } else { - switch (adapter->link_speed) { - case 10: - ifmr->ifm_active |= IFM_10_T; - break; - case 100: - ifmr->ifm_active |= IFM_100_TX; - break; - case 1000: -#if __FreeBSD_version < 500000 - ifmr->ifm_active |= IFM_1000_TX; -#else - ifmr->ifm_active |= IFM_1000_T; -#endif - break; - } - if (adapter->link_duplex == FULL_DUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - } + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!adapter->link_active) + return; + + ifmr->ifm_status |= IFM_ACTIVE; + + if (adapter->hw.media_type == em_media_type_fiber) { + ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; + } else { + switch (adapter->link_speed) { + case 10: + ifmr->ifm_active |= IFM_10_T; + break; + case 100: + ifmr->ifm_active |= IFM_100_TX; + break; + case 1000: +#if __FreeBSD_version < 500000 + ifmr->ifm_active |= IFM_1000_TX; +#else + ifmr->ifm_active |= IFM_1000_T; +#endif + break; + } + if (adapter->link_duplex == FULL_DUPLEX) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + } + return; +} + +/********************************************************************* + * + * Media Ioctl callback + * + * This routine is called when the user changes speed/duplex using + * media/mediopt option with ifconfig. + * + **********************************************************************/ +static int +em_media_change(struct ifnet *ifp) +{ + struct adapter * adapter = ifp->if_softc; + struct ifmedia *ifm = &adapter->media; + + INIT_DEBUGOUT("em_media_change: begin"); + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return(EINVAL); + + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + adapter->hw.autoneg = DO_AUTO_NEG; + adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; + break; + case IFM_1000_SX: +#if __FreeBSD_version < 500000 + case IFM_1000_TX: +#else + case IFM_1000_T: +#endif + adapter->hw.autoneg = DO_AUTO_NEG; + adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case IFM_100_TX: + adapter->hw.autoneg = FALSE; + adapter->hw.autoneg_advertised = 0; + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + adapter->hw.forced_speed_duplex = em_100_full; + else + adapter->hw.forced_speed_duplex = em_100_half; + break; + case IFM_10_T: + adapter->hw.autoneg = FALSE; + adapter->hw.autoneg_advertised = 0; + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + adapter->hw.forced_speed_duplex = em_10_full; + else + adapter->hw.forced_speed_duplex = em_10_half; + break; + default: + printf("em%d: Unsupported media type\n", adapter->unit); + } + + em_init(adapter); + + return(0); +} + + +/********************************************************************* + * + * This routine maps the mbufs to tx descriptors. + * + * return 0 on success, positive on failure + **********************************************************************/ + +static int +em_encap(struct adapter *adapter, struct mbuf *m_head) +{ + vm_offset_t virtual_addr; + u_int32_t txd_upper; + u_int32_t txd_lower; + u_int16_t txd_used, count; + + struct mbuf *mp; + struct ifvlan *ifv = NULL; + struct em_tx_buffer *tx_buffer; + struct em_tx_desc *saved_tx_desc = NULL; + struct em_tx_desc *current_tx_desc = NULL; + struct ifnet *ifp = &adapter->interface_data.ac_if; + + /* Force a cleanup if number of descriptors available hit the threshold */ + if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) + em_clean_transmit_interrupts(adapter); + + if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { + adapter->no_tx_desc_avail1++; + return (ENOBUFS); + } + + /* Find out number of fragments in a mbuf chain */ + count = 0; + for (mp = m_head; mp != NULL; mp = mp->m_next) { + if (mp->m_len == 0) + continue; + count++; + } + + /* Bail out if we don't have enough descriptors */ + if (adapter->num_tx_desc_avail <= count) { + em_clean_transmit_interrupts(adapter); + adapter->no_tx_desc_avail2++; + return (ENOBUFS); + } + + tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); + if (!tx_buffer) { + adapter->no_tx_buffer_avail1++; + return (ENOBUFS); + } + + /* Setup checksum context */ + if (ifp->if_hwassist > 0) { + em_transmit_checksum_setup(adapter, m_head, + &txd_upper, &txd_lower); + } else { + txd_upper = 0; + txd_lower = 0; + } + + /* Find out if we are in vlan mode */ + if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && + m_head->m_pkthdr.rcvif != NULL && + m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) + ifv = m_head->m_pkthdr.rcvif->if_softc; + + + txd_used = 0; + saved_tx_desc = adapter->next_avail_tx_desc; + for (mp = m_head; mp != NULL; mp = mp->m_next) { + if (mp->m_len == 0) + continue; + + tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); + if (!tx_buffer) { + adapter->no_tx_buffer_avail2++; + adapter->next_avail_tx_desc = saved_tx_desc; + return (ENOBUFS); + } + + current_tx_desc = adapter->next_avail_tx_desc; + virtual_addr = mtod(mp, vm_offset_t); + current_tx_desc->buffer_addr = vtophys(virtual_addr); + + current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower | mp->m_len); + current_tx_desc->upper.data = (txd_upper); + + if (current_tx_desc == adapter->last_tx_desc) + adapter->next_avail_tx_desc = + adapter->first_tx_desc; + else + adapter->next_avail_tx_desc++; + + txd_used++; + + tx_buffer->m_head = NULL; + tx_buffer->used_tx_desc = current_tx_desc; + STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry); + STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer, + em_tx_entry); + } + adapter->num_tx_desc_avail-= txd_used; + + if (ifv != NULL) { + /* Tell hardware to add tag */ + current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; + + /* Set the vlan id */ + current_tx_desc->upper.fields.special = ifv->ifv_tag; + } + + /* Last Descriptor of Packet needs End Of Packet (EOP) bit set. */ + current_tx_desc->lower.data |= E1000_TXD_CMD_EOP; + + /* Save mbuf chain so that we can free it during transmit cleanup */ + tx_buffer->m_head = m_head; + + /* + * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 + * that this frame is available to transmit. + */ + E1000_WRITE_REG(&adapter->hw, TDT, + (((uintptr_t) adapter->next_avail_tx_desc - + (uintptr_t) adapter->first_tx_desc) >> 4)); + + return(0); +} + + +static void +em_set_promisc(struct adapter * adapter) +{ + + u_int32_t reg_rctl; + struct ifnet *ifp = &adapter->interface_data.ac_if; + + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + + if (ifp->if_flags & IFF_PROMISC) { + reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + } else if (ifp->if_flags & IFF_ALLMULTI) { + reg_rctl |= E1000_RCTL_MPE; + reg_rctl &= ~E1000_RCTL_UPE; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + } + + return; +} + +static void +em_disable_promisc(struct adapter * adapter) +{ + u_int32_t reg_rctl; + + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + + reg_rctl &= (~E1000_RCTL_UPE); + reg_rctl &= (~E1000_RCTL_MPE); + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + + return; +} + + +/********************************************************************* + * Multicast Update + * + * This routine is called whenever multicast address list is updated. + * + **********************************************************************/ + +static void +em_set_multi(struct adapter * adapter) +{ + u_int32_t reg_rctl = 0; + u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; + struct ifmultiaddr *ifma; + int mcnt = 0; + struct ifnet *ifp = &adapter->interface_data.ac_if; + + IOCTL_DEBUGOUT("em_set_multi: begin"); + + if (adapter->hw.mac_type == em_82542_rev2_0) { + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + em_pci_clear_mwi(&adapter->hw); + } + reg_rctl |= E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + msec_delay(5); + } + +#if __FreeBSD_version < 500000 + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { +#else + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { +#endif + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); + mcnt++; + } + + if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) { + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + reg_rctl |= E1000_RCTL_MPE; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + } else + em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0); + + if (adapter->hw.mac_type == em_82542_rev2_0) { + reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); + reg_rctl &= ~E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); + msec_delay(5); + if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + em_pci_set_mwi(&adapter->hw); + } + } + + return; +} + + +/********************************************************************* + * Timer routine + * + * This routine checks for link status and updates statistics. + * + **********************************************************************/ + +static void +em_local_timer(void *arg) +{ + int s; + struct ifnet *ifp; + struct adapter * adapter = arg; + ifp = &adapter->interface_data.ac_if; + + s = splimp(); + + em_check_for_link(&adapter->hw); + em_print_link_status(adapter); + em_update_stats_counters(adapter); + if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { + em_print_hw_stats(adapter); + } + adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); + + splx(s); + return; +} + +static void +em_print_link_status(struct adapter * adapter) +{ + if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { + if (adapter->link_active == 0) { + em_get_speed_and_duplex(&adapter->hw, + &adapter->link_speed, + &adapter->link_duplex); + printf("em%d: Link is up %d Mbps %s\n", + adapter->unit, + adapter->link_speed, + ((adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex")); + adapter->link_active = 1; + } + } else { + if (adapter->link_active == 1) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + printf("em%d: Link is Down\n", adapter->unit); + adapter->link_active = 0; + } + } + return; } + /********************************************************************* * - * Media Ioctl callback - * - * This routine is called when the user changes speed/duplex using - * media/mediopt option with ifconfig. + * This routine disables all traffic on the adapter by issuing a + * global reset on the MAC and deallocates TX/RX buffers. * **********************************************************************/ -static int -em_media_change(struct ifnet *ifp) -{ - struct adapter * adapter = ifp->if_softc; - struct ifmedia *ifm = &adapter->media; - INIT_DEBUGOUT("em_media_change: begin"); +static void +em_stop(void *arg) +{ + struct ifnet *ifp; + struct adapter * adapter = arg; + ifp = &adapter->interface_data.ac_if; - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); + INIT_DEBUGOUT("em_stop: begin\n"); + em_disable_intr(adapter); + em_reset_hw(&adapter->hw); + untimeout(em_local_timer, adapter, adapter->timer_handle); + em_free_transmit_structures(adapter); + em_free_receive_structures(adapter); - switch (IFM_SUBTYPE(ifm->ifm_media)) { - case IFM_AUTO: - adapter->hw.autoneg = DO_AUTO_NEG; - adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; - break; - case IFM_1000_SX: -#if __FreeBSD_version < 500000 - case IFM_1000_TX: -#else - case IFM_1000_T: -#endif - adapter->hw.autoneg = DO_AUTO_NEG; - adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; - break; - case IFM_100_TX: - adapter->hw.autoneg = FALSE; - adapter->hw.autoneg_advertised = 0; - if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) - adapter->hw.forced_speed_duplex = em_100_full; - else - adapter->hw.forced_speed_duplex = em_100_half; - break; - case IFM_10_T: - adapter->hw.autoneg = FALSE; - adapter->hw.autoneg_advertised = 0; - if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) - adapter->hw.forced_speed_duplex = em_10_full; - else - adapter->hw.forced_speed_duplex = em_10_half; - break; - default: - printf("em%d: Unsupported media type\n", adapter->unit); - } - em_init(adapter); + /* Tell the stack that the interface is no longer active */ + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - return(0); + return; } -/* Section end: Other registered entry points */ /********************************************************************* @@ -1147,9 +1188,9 @@ em_identify_hardware(struct adapter * adapter) adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) && (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) { - printf("em%d: Memory Access and/or Bus Master bits were not set!\n", + printf("em%d: Memory Access and/or Bus Master bits were not set!\n", adapter->unit); - adapter->hw.pci_cmd_word |= + adapter->hw.pci_cmd_word |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2); } @@ -1161,37 +1202,10 @@ em_identify_hardware(struct adapter * adapter) adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2); adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2); + /* Identify the MAC */ + if (em_set_mac_type(&adapter->hw)) + printf("em%d: Unknown MAC Type\n", adapter->unit); - /* Set MacType, etc. based on this PCI info */ - switch (adapter->hw.device_id) { - case E1000_DEV_ID_82542: - adapter->hw.mac_type = (adapter->hw.revision_id == 3) ? - em_82542_rev2_1 : em_82542_rev2_0; - break; - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - adapter->hw.mac_type = em_82543; - break; - case E1000_DEV_ID_82544EI_FIBER: - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: - adapter->hw.mac_type = em_82544; - break; - case E1000_DEV_ID_82540EM: - adapter->hw.mac_type = em_82540; - break; - case E1000_DEV_ID_82545EM_FIBER: - case E1000_DEV_ID_82545EM_COPPER: - adapter->hw.mac_type = em_82545; - break; - case E1000_DEV_ID_82546EB_FIBER: - case E1000_DEV_ID_82546EB_COPPER: - adapter->hw.mac_type = em_82546; - break; - default: - INIT_DEBUGOUT1("Unknown device id 0x%x", adapter->hw.device_id); - } return; } @@ -1465,7 +1479,6 @@ em_setup_transmit_structures(struct adapter * adapter) /* Setup TX descriptor pointers */ adapter->next_avail_tx_desc = adapter->first_tx_desc; - adapter->oldest_used_tx_desc = adapter->first_tx_desc; /* Set number of descriptors available */ adapter->num_tx_desc_avail = adapter->num_tx_desc; @@ -1591,14 +1604,14 @@ em_free_transmit_structures(struct adapter * adapter) * **********************************************************************/ static void -em_transmit_checksum_setup(struct adapter * adapter, +em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, - struct em_tx_buffer *tx_buffer, u_int32_t *txd_upper, u_int32_t *txd_lower) { struct em_context_desc *TXD; struct em_tx_desc * current_tx_desc; + struct em_tx_buffer *tx_buffer; if (mp->m_pkthdr.csum_flags) { @@ -1632,8 +1645,9 @@ em_transmit_checksum_setup(struct adapter * adapter, * needs to be reset. */ current_tx_desc = adapter->next_avail_tx_desc; - TXD = (struct em_context_desc *)current_tx_desc; + tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); + TXD = (struct em_context_desc *)current_tx_desc; TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN; TXD->lower_setup.ip_fields.ipcso = ETHER_HDR_LEN + offsetof(struct ip, ip_sum); @@ -1655,7 +1669,7 @@ em_transmit_checksum_setup(struct adapter * adapter, } TXD->tcp_seg_setup.data = 0; - TXD->cmd_and_length = E1000_TXD_CMD_DEXT; + TXD->cmd_and_length = (adapter->txd_cmd | E1000_TXD_CMD_DEXT); if (current_tx_desc == adapter->last_tx_desc) adapter->next_avail_tx_desc = adapter->first_tx_desc; @@ -1664,7 +1678,80 @@ em_transmit_checksum_setup(struct adapter * adapter, adapter->num_tx_desc_avail--; - tx_buffer->num_tx_desc_used++; + tx_buffer->used_tx_desc = current_tx_desc; + STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry); + STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer, em_tx_entry); + return; +} + +/********************************************************************** + * + * Examine each tx_buffer in the used queue. If the hardware is done + * processing the packet then free associated resources. The + * tx_buffer is put back on the free queue. + * + **********************************************************************/ +static void +em_clean_transmit_interrupts(struct adapter * adapter) +{ + struct em_tx_buffer *tx_buffer; + struct em_tx_desc *tx_desc; + int s; + struct ifnet *ifp; + + s = splimp(); +#ifdef DBG_STATS + adapter->clean_tx_interrupts++; +#endif + + for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list); + tx_buffer; + tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) { + + /* + * Get hold of the next descriptor that the hardware will report status + * back to. There is 1/1 correspondence between a tx descriptor + * and tx_buffer. + */ + + tx_desc = tx_buffer->used_tx_desc; + + /* + * If the descriptor done bit is set, free tx_buffer and associated + * resources + */ + if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) { + + tx_desc->upper.data = 0; + adapter->num_tx_desc_avail++; + + if (tx_buffer->m_head) { + m_freem(tx_buffer->m_head); + tx_buffer->m_head = NULL; + } + + STAILQ_REMOVE_HEAD(&adapter->used_tx_buffer_list, + em_tx_entry); + /* Return this tx_buffer back to the "free" list */ + STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list, + tx_buffer, em_tx_entry); + } else { + /* + * Found a tx_buffer that the em is not done with then there is + * no reason to check the rest of the queue. + */ + break; + } + } /* end for each tx_buffer */ + + ifp = &adapter->interface_data.ac_if; + + /* Tell the stack that it is OK to send packets */ + if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) { + ifp->if_timer = 0; + ifp->if_flags &= ~IFF_OACTIVE; + } + splx(s); return; } @@ -2136,33 +2223,57 @@ em_disable_intr(struct adapter *adapter) return; } -void em_write_pci_cfg(struct em_hw *hw, - uint32_t reg, - uint16_t *value) +void +em_write_pci_cfg(struct em_hw *hw, + uint32_t reg, + uint16_t *value) { pci_write_config(((struct em_osdep *)hw->back)->dev, reg, *value, 2); } -void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, - uint16_t *value) +void +em_read_pci_cfg(struct em_hw *hw, uint32_t reg, + uint16_t *value) { *value = pci_read_config(((struct em_osdep *)hw->back)->dev, reg, 2); return; } -uint32_t em_io_read(struct em_hw *hw, uint32_t port) + +void +em_pci_set_mwi(struct em_hw *hw) +{ + pci_write_config(((struct em_osdep *)hw->back)->dev, + PCIR_COMMAND, + (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); + return; +} + +void +em_pci_clear_mwi(struct em_hw *hw) +{ + pci_write_config(((struct em_osdep *)hw->back)->dev, + PCIR_COMMAND, + (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2); + return; +} + +uint32_t +em_io_read(struct em_hw *hw, uint32_t port) { return(inl(port)); } -void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value) +void +em_io_write(struct em_hw *hw, uint32_t port, uint32_t value) { outl(port, value); return; } + /********************************************************************** * * Update the board statistics counters. @@ -2288,8 +2399,10 @@ em_print_hw_stats(struct adapter *adapter) adapter->clean_tx_interrupts); #endif - printf("em%d: Tx Descriptors not Avail = %ld\n", unit, - adapter->no_tx_desc_avail); + printf("em%d: Tx Descriptors not avail1 = %ld\n", unit, + adapter->no_tx_desc_avail1); + printf("em%d: Tx Descriptors not avail2 = %ld\n", unit, + adapter->no_tx_desc_avail2); printf("em%d: Tx Buffer not avail1 = %ld\n", unit, adapter->no_tx_buffer_avail1); printf("em%d: Tx Buffer not avail2 = %ld\n", unit, @@ -2298,6 +2411,8 @@ em_print_hw_stats(struct adapter *adapter) adapter->mbuf_alloc_failed); printf("em%d: Std Cluster Failed = %ld\n",unit, adapter->mbuf_cluster_failed); + printf("em%d: Number of TX desc avail = %d\n", unit, + adapter->num_tx_desc_avail); printf("em%d: Symbol errors = %lld\n", unit, (long long)adapter->stats.symerrs); @@ -2340,92 +2455,3 @@ em_print_hw_stats(struct adapter *adapter) return; } - -/********************************************************************** - * - * Examine each tx_buffer in the used queue. If the hardware is done - * processing the packet then free associated resources. The - * tx_buffer is put back on the free queue. - * - **********************************************************************/ -static void -em_clean_transmit_interrupts(struct adapter * adapter) -{ - struct em_tx_buffer *tx_buffer; - struct em_tx_desc *tx_desc; - int s; - struct ifnet *ifp; - - s = splimp(); -#ifdef DBG_STATS - adapter->clean_tx_interrupts++; -#endif - - for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list); - tx_buffer; - tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) { - - /* - * Get hold of the next descriptor that the em will report status - * back to (this will be the last descriptor of a given tx_buffer). We - * only want to free the tx_buffer (and it resources) if the driver is - * done with ALL of the descriptors. If the driver is done with the - * last one then it is done with all of them. - */ - - tx_desc = adapter->oldest_used_tx_desc + - (tx_buffer->num_tx_desc_used - 1); - - /* Check for wrap case */ - if (tx_desc > adapter->last_tx_desc) - tx_desc -= adapter->num_tx_desc; - - - /* - * If the descriptor done bit is set free tx_buffer and associated - * resources - */ - if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) { - - STAILQ_REMOVE_HEAD(&adapter->used_tx_buffer_list, - em_tx_entry); - - if ((tx_desc == adapter->last_tx_desc)) - adapter->oldest_used_tx_desc = - adapter->first_tx_desc; - else - adapter->oldest_used_tx_desc = (tx_desc + 1); - - /* Make available the descriptors that were previously used */ - adapter->num_tx_desc_avail += - tx_buffer->num_tx_desc_used; - - tx_buffer->num_tx_desc_used = 0; - - if (tx_buffer->m_head) { - m_freem(tx_buffer->m_head); - tx_buffer->m_head = NULL; - } - /* Return this "Software packet" back to the "free" list */ - STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list, - tx_buffer, em_tx_entry); - } else { - /* - * Found a tx_buffer that the em is not done with then there is - * no reason to check the rest of the queue. - */ - break; - } - } /* end for each tx_buffer */ - - ifp = &adapter->interface_data.ac_if; - - /* Tell the stack that it is OK to send packets */ - if (adapter->num_tx_desc_avail > TX_CLEANUP_THRESHOLD) { - ifp->if_timer = 0; - ifp->if_flags &= ~IFF_OACTIVE; - } - splx(s); - return; -} - diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h index f292966..d280837 100644 --- a/sys/dev/em/if_em.h +++ b/sys/dev/em/if_em.h @@ -75,23 +75,129 @@ POSSIBILITY OF SUCH DAMAGE. #include -/* Tunables */ -#define MAX_TXD 256 -#define MAX_RXD 256 -#define TX_CLEANUP_THRESHOLD MAX_TXD / 8 -#define TIDV 128 -#define RIDV 28 -#define DO_AUTO_NEG 1 -#define WAIT_FOR_AUTO_NEG_DEFAULT 1 -#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ - ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ - ADVERTISE_1000_FULL) +/* Tunables -- Begin */ + +/* + * FlowControl + * Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx) + * Default: Read flow control settings from the EEPROM + * This parameter controls the automatic generation(Tx) and response(Rx) to + * Ethernet PAUSE frames. + */ + + +/* + * TxDescriptors + * Valid Range: 80-256 for 82542 and 82543-based adapters + * 80-4096 for 82540, 82544, 82545, and 82546-based adapters + * Default Value: 256 + * This value is the number of transmit descriptors allocated by the driver. + * Increasing this value allows the driver to queue more transmits. Each + * descriptor is 16 bytes. + */ +#define EM_MAX_TXD 256 + +/* + * RxDescriptors + * Valid Range: 80-256 for 82542 and 82543-based adapters + * 80-4096 for 82540, 82544, 82545, and 82546-based adapters + * Default Value: 256 + * This value is the number of receive descriptors allocated by the driver. + * Increasing this value allows the driver to buffer more incoming packets. + * Each descriptor is 16 bytes. A receive buffer is also allocated for each + * descriptor. The maximum MTU size is 16110. + * + */ +#define EM_MAX_RXD 256 + +/* + * TxIntDelay + * Valid Range: 0-65535 (0=off) + * Default Value: 64 + * This value delays the generation of transmit interrupts in units of + * 1.024 microseconds. Transmit interrupt reduction can improve CPU + * efficiency if properly tuned for specific network traffic. If the + * system is reporting dropped transmits, this value may be set too high + * causing the driver to run out of available transmit descriptors. + */ +#define EM_TIDV 128 + +/* + * RxIntDelay + * Valid Range: 0-65535 (0=off) + * Default Value: 0 + * This value delays the generation of receive interrupts in units of 1.024 + * microseconds. Receive interrupt reduction can improve CPU efficiency if + * properly tuned for specific network traffic. Increasing this value adds + * extra latency to frame reception and can end up decreasing the throughput + * of TCP traffic. If the system is reporting dropped receives, this value + * may be set too high, causing the driver to run out of available receive + * descriptors. + * + * CAUTION: When setting RxIntDelay to a value other than 0, adapters + * may hang (stop transmitting) under certain network conditions. + * If this occurs a WATCHDOG message is logged in the system event log. + * In addition, the controller is automatically reset, restoring the + * network connection. To eliminate the potential for the hang + * ensure that RxIntDelay is set to 0. + */ +#define EM_RDTR 0 + + +/* + * This parameter controls the maximum no of times the driver will loop + * in the isr. + * Minimum Value = 1 + */ +#define EM_MAX_INTR 3 + + +/* + * This parameter determines when the hardware will report that it is + * done with the packet. + * 0 - "Done" is reported when the packet has been sent on the wire + * 1 - "Done" is reported when the packet has been DMA'ed and is on chip. + * 2 - Determine the best method. + */ #define EM_REPORT_TX_EARLY 2 + +/* + * Inform the stack about transmit checksum offload capabilities. + */ #define EM_CHECKSUM_FEATURES (CSUM_TCP | CSUM_UDP) -#define EM_MAX_INTR 3 + +/* + * This parameter controls the duration of transmit watchdog timer. + */ #define EM_TX_TIMEOUT 5 /* set to 5 seconds */ +/* + * This parameter controls when the driver calls the routine to reclaim + * transmit descriptors. + */ +#define EM_TX_CLEANUP_THRESHOLD EM_MAX_TXD / 8 + +/* + * This parameter controls whether or not autonegotation is enabled. + * 0 - Disable autonegotiation + * 1 - Enable autonegotiation + */ +#define DO_AUTO_NEG 1 + +/* + * This parameter control whether or not the driver will wait for + * autonegotiation to complete. + * 1 - Wait for autonegotiation to complete + * 0 - Don't wait for autonegotiation to complete + */ +#define WAIT_FOR_AUTO_NEG_DEFAULT 1 + + +/* Tunables -- End */ +#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) #define EM_VENDOR_ID 0x8086 #define EM_MMBA 0x0010 /* Mem base address */ #define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) @@ -138,8 +244,7 @@ POSSIBILITY OF SUCH DAMAGE. * should load. * * ******************************************************************************/ -typedef struct _em_vendor_info_t -{ +typedef struct _em_vendor_info_t { unsigned int vendor_id; unsigned int device_id; unsigned int subvendor_id; @@ -151,10 +256,9 @@ typedef struct _em_vendor_info_t struct em_tx_buffer { STAILQ_ENTRY(em_tx_buffer) em_tx_entry; struct mbuf *m_head; - u_int32_t num_tx_desc_used; + struct em_tx_desc *used_tx_desc; }; - /* ****************************************************************************** * This structure stores information about the 2k aligned receive buffer * into which the E1000 DMA's frames. @@ -204,7 +308,6 @@ struct adapter { struct em_tx_desc *first_tx_desc; struct em_tx_desc *last_tx_desc; struct em_tx_desc *next_avail_tx_desc; - struct em_tx_desc *oldest_used_tx_desc; struct em_tx_desc *tx_desc_base; volatile u_int16_t num_tx_desc_avail; u_int16_t num_tx_desc; @@ -232,8 +335,8 @@ struct adapter { unsigned long dropped_pkts; unsigned long mbuf_alloc_failed; unsigned long mbuf_cluster_failed; - unsigned long xmit_pullup; - unsigned long no_tx_desc_avail; + unsigned long no_tx_desc_avail1; + unsigned long no_tx_desc_avail2; unsigned long no_tx_buffer_avail1; unsigned long no_tx_buffer_avail2; #ifdef DBG_STATS diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c index 165e317..88bf617 100644 --- a/sys/dev/em/if_em_hw.c +++ b/sys/dev/em/if_em_hw.c @@ -53,9 +53,71 @@ static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd); static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, uint16_t count); static uint16_t em_shift_in_ee_bits(struct em_hw *hw); static void em_setup_eeprom(struct em_hw *hw); +static void em_clock_eeprom(struct em_hw *hw); +static void em_cleanup_eeprom(struct em_hw *hw); static void em_standby_eeprom(struct em_hw *hw); static int32_t em_id_led_init(struct em_hw * hw); + + + +/****************************************************************************** + * Set the mac type member in the hw struct. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +em_set_mac_type(struct em_hw *hw) +{ + DEBUGFUNC("em_set_mac_type"); + + switch (hw->device_id) { + case E1000_DEV_ID_82542: + switch (hw->revision_id) { + case E1000_82542_2_0_REV_ID: + hw->mac_type = em_82542_rev2_0; + break; + case E1000_82542_2_1_REV_ID: + hw->mac_type = em_82542_rev2_1; + break; + default: + /* Invalid 82542 revision ID */ + return -E1000_ERR_MAC_TYPE; + } + break; + case E1000_DEV_ID_82543GC_FIBER: + case E1000_DEV_ID_82543GC_COPPER: + hw->mac_type = em_82543; + break; + case E1000_DEV_ID_82544EI_COPPER: + case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82544GC_COPPER: + case E1000_DEV_ID_82544GC_LOM: + hw->mac_type = em_82544; + break; + case E1000_DEV_ID_82540EM: + case E1000_DEV_ID_82540EM_LOM: + case E1000_DEV_ID_82540EP: + case E1000_DEV_ID_82540EP_LOM: + case E1000_DEV_ID_82540EP_LP: + hw->mac_type = em_82540; + break; + case E1000_DEV_ID_82545EM_COPPER: + case E1000_DEV_ID_82545EM_FIBER: + hw->mac_type = em_82545; + break; + case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_FIBER: + hw->mac_type = em_82546; + break; + default: + /* Should never have loaded on this device */ + return -E1000_ERR_MAC_TYPE; + } + + + return E1000_SUCCESS; +} /****************************************************************************** * Reset the transmit and receive units; mask and clear all interrupts. * @@ -68,17 +130,13 @@ em_reset_hw(struct em_hw *hw) uint32_t ctrl_ext; uint32_t icr; uint32_t manc; - uint16_t pci_cmd_word; DEBUGFUNC("em_reset_hw"); /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ if(hw->mac_type == em_82542_rev2_0) { - if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { - DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); - pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; - em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word); - } + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + em_pci_clear_mwi(hw); } /* Clear interrupt mask to stop board from generating interrupts */ @@ -91,6 +149,7 @@ em_reset_hw(struct em_hw *hw) */ E1000_WRITE_REG(hw, RCTL, 0); E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP); + E1000_WRITE_FLUSH(hw); /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */ hw->tbi_compatibility_on = FALSE; @@ -120,6 +179,7 @@ em_reset_hw(struct em_hw *hw) ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); ctrl_ext |= E1000_CTRL_EXT_EE_RST; E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); /* Wait for EEPROM reload */ msec_delay(2); } else { @@ -141,7 +201,7 @@ em_reset_hw(struct em_hw *hw) /* If MWI was previously enabled, reenable it. */ if(hw->mac_type == em_82542_rev2_0) { if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) - em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word); + em_pci_set_mwi(hw); } } @@ -162,7 +222,6 @@ em_init_hw(struct em_hw *hw) uint32_t ctrl, status; uint32_t i; int32_t ret_val; - uint16_t pci_cmd_word; uint16_t pcix_cmd_word; uint16_t pcix_stat_hi_word; uint16_t cmd_mmrbc; @@ -205,12 +264,10 @@ em_init_hw(struct em_hw *hw) /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ if(hw->mac_type == em_82542_rev2_0) { - if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { - DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); - pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; - em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word); - } + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + em_pci_clear_mwi(hw); E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST); + E1000_WRITE_FLUSH(hw); msec_delay(5); } @@ -222,9 +279,10 @@ em_init_hw(struct em_hw *hw) /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ if(hw->mac_type == em_82542_rev2_0) { E1000_WRITE_REG(hw, RCTL, 0); + E1000_WRITE_FLUSH(hw); msec_delay(1); if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) - em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word); + em_pci_set_mwi(hw); } /* Zero out the Multicast HASH table */ @@ -249,6 +307,8 @@ em_init_hw(struct em_hw *hw) PCIX_COMMAND_MMRBC_SHIFT; stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> PCIX_STATUS_HI_MMRBC_SHIFT; + if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) + stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; if(cmd_mmrbc > stat_mmrbc) { pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; @@ -259,6 +319,13 @@ em_init_hw(struct em_hw *hw) /* Call a subroutine to configure the link and setup flow control. */ ret_val = em_setup_link(hw); + /* Set the transmit descriptor write-back policy */ + if(hw->mac_type > em_82544) { + ctrl = E1000_READ_REG(hw, TXDCTL); + ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; + E1000_WRITE_REG(hw, TXDCTL, ctrl); + } + /* 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 @@ -384,7 +451,6 @@ em_setup_link(struct em_hw *hw) * Sets up link for a fiber based adapter * * hw - Struct containing variables accessed by shared code - * ctrl - 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 @@ -470,6 +536,7 @@ em_setup_fiber_link(struct em_hw *hw) E1000_WRITE_REG(hw, TXCW, txcw); E1000_WRITE_REG(hw, CTRL, ctrl); + E1000_WRITE_FLUSH(hw); hw->txcw = txcw; msec_delay(1); @@ -514,7 +581,6 @@ em_setup_fiber_link(struct em_hw *hw) * Detects which PHY is present and the speed and duplex * * hw - Struct containing variables accessed by shared code -* ctrl - current value of the device control register ******************************************************************************/ static int32_t em_setup_copper_link(struct em_hw *hw) @@ -603,14 +669,17 @@ em_setup_copper_link(struct em_hw *hw) return -E1000_ERR_PHY; } phy_data |= M88E1000_EPSCR_TX_CLK_25; - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; + + if (hw->phy_revision < M88E1011_I_REV_4) { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } } /* SW Reset the PHY so all changes take effect */ @@ -956,7 +1025,6 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); - /* Write the MII Control Register with the new PHY configuration. */ if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; @@ -971,9 +1039,11 @@ em_phy_force_speed_duplex(struct em_hw *hw) return -E1000_ERR_PHY; } DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); - + /* Need to reset the PHY or these changes will be ignored */ mii_ctrl_reg |= MII_CR_RESET; + + /* Write back the modified PHY MII control register. */ if(em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; @@ -1083,6 +1153,7 @@ em_config_collision_dist(struct em_hw *hw) tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; E1000_WRITE_REG(hw, TCTL, tctl); + E1000_WRITE_FLUSH(hw); } /****************************************************************************** @@ -1680,6 +1751,7 @@ em_raise_mdi_clk(struct em_hw *hw, * bit), and then delay 2 microseconds. */ E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC)); + E1000_WRITE_FLUSH(hw); usec_delay(2); } @@ -1697,6 +1769,7 @@ em_lower_mdi_clk(struct em_hw *hw, * bit), and then delay 2 microseconds. */ E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC)); + E1000_WRITE_FLUSH(hw); usec_delay(2); } @@ -1739,6 +1812,7 @@ em_shift_out_mdi_bits(struct em_hw *hw, else ctrl &= ~E1000_CTRL_MDIO; E1000_WRITE_REG(hw, CTRL, ctrl); + E1000_WRITE_FLUSH(hw); usec_delay(2); @@ -1747,9 +1821,6 @@ em_shift_out_mdi_bits(struct em_hw *hw, mask = mask >> 1; } - - /* Clear the data bit just before leaving this routine. */ - ctrl &= ~E1000_CTRL_MDIO; } /****************************************************************************** @@ -1780,6 +1851,7 @@ em_shift_in_mdi_bits(struct em_hw *hw) ctrl &= ~E1000_CTRL_MDIO; E1000_WRITE_REG(hw, CTRL, ctrl); + E1000_WRITE_FLUSH(hw); /* 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 @@ -1800,9 +1872,6 @@ em_shift_in_mdi_bits(struct em_hw *hw) em_raise_mdi_clk(hw, &ctrl); em_lower_mdi_clk(hw, &ctrl); - /* Clear the MDIO bit just before leaving this routine. */ - ctrl &= ~E1000_CTRL_MDIO; - return data; } @@ -1976,8 +2045,10 @@ em_phy_hw_reset(struct em_hw *hw) */ ctrl = E1000_READ_REG(hw, CTRL); E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST); + E1000_WRITE_FLUSH(hw); msec_delay(10); E1000_WRITE_REG(hw, CTRL, ctrl); + E1000_WRITE_FLUSH(hw); } else { /* Read the Extended Device Control Register, assert the PHY_RESET_DIR * bit to put the PHY into reset. Then, take it out of reset. @@ -1986,9 +2057,11 @@ em_phy_hw_reset(struct em_hw *hw) ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR; ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA; E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); msec_delay(10); ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA; E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); } usec_delay(150); } @@ -2045,7 +2118,8 @@ em_detect_gig_phy(struct em_hw *hw) return -E1000_ERR_PHY; } hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK); - + hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK; + switch(hw->mac_type) { case em_82543: if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE; @@ -2176,6 +2250,8 @@ em_validate_mdi_setting(struct em_hw *hw) return 0; } + + /****************************************************************************** * Raises the EEPROM's clock input. * @@ -2187,10 +2263,11 @@ em_raise_ee_clk(struct em_hw *hw, uint32_t *eecd) { /* Raise the clock input to the EEPROM (by setting the SK bit), and then - * wait 50 microseconds. + * wait microseconds. */ *eecd = *eecd | E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); } @@ -2209,6 +2286,7 @@ em_lower_ee_clk(struct em_hw *hw, */ *eecd = *eecd & ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); } @@ -2246,6 +2324,7 @@ em_shift_out_ee_bits(struct em_hw *hw, eecd |= E1000_EECD_DI; E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); @@ -2273,11 +2352,11 @@ em_shift_in_ee_bits(struct em_hw *hw) uint32_t i; uint16_t data; - /* 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.. + /* In order to read a register from the EEPROM, we need to shift 'count' + * 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. */ eecd = E1000_READ_REG(hw, EECD); @@ -2340,21 +2419,25 @@ em_standby_eeprom(struct em_hw *hw) /* Deselct EEPROM */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); /* Clock high */ eecd |= E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); /* Select EEPROM */ eecd |= E1000_EECD_CS; E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); /* Clock low */ eecd &= ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); } @@ -2373,11 +2456,13 @@ em_clock_eeprom(struct em_hw *hw) /* Rising edge of clock */ eecd |= E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); /* Falling edge of clock */ eecd &= ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); usec_delay(50); } @@ -3076,6 +3161,9 @@ em_setup_led(struct em_hw *hw) ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT); E1000_WRITE_REG(hw, LEDCTL, ledctl); break; + case E1000_DEV_ID_82540EP: + case E1000_DEV_ID_82540EP_LOM: + case E1000_DEV_ID_82540EP_LP: case E1000_DEV_ID_82540EM: case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: @@ -3109,6 +3197,9 @@ em_cleanup_led(struct em_hw *hw) case E1000_DEV_ID_82544GC_LOM: /* No cleanup necessary */ break; + case E1000_DEV_ID_82540EP: + case E1000_DEV_ID_82540EP_LOM: + case E1000_DEV_ID_82540EP_LP: case E1000_DEV_ID_82540EM: case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: @@ -3159,6 +3250,9 @@ em_led_on(struct em_hw *hw) ctrl |= E1000_CTRL_SWDPIO0; E1000_WRITE_REG(hw, CTRL, ctrl); break; + case E1000_DEV_ID_82540EP: + case E1000_DEV_ID_82540EP_LOM: + case E1000_DEV_ID_82540EP_LP: case E1000_DEV_ID_82540EM: case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: @@ -3206,6 +3300,9 @@ em_led_off(struct em_hw *hw) ctrl |= E1000_CTRL_SWDPIO0; E1000_WRITE_REG(hw, CTRL, ctrl); break; + case E1000_DEV_ID_82540EP: + case E1000_DEV_ID_82540EP_LOM: + case E1000_DEV_ID_82540EP_LP: case E1000_DEV_ID_82540EM: case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: diff --git a/sys/dev/em/if_em_hw.h b/sys/dev/em/if_em_hw.h index 662508f..9e6172d 100644 --- a/sys/dev/em/if_em_hw.h +++ b/sys/dev/em/if_em_hw.h @@ -48,7 +48,8 @@ struct em_hw_stats; /* Enumerated types specific to the e1000 hardware */ /* Media Access Controlers */ typedef enum { - em_82542_rev2_0 = 0, + em_undefined = 0, + em_82542_rev2_0, em_82542_rev2_1, em_82543, em_82544, @@ -58,6 +59,7 @@ typedef enum { em_num_macs } em_mac_type; + /* Media Types */ typedef enum { em_media_type_copper = 0, @@ -127,6 +129,7 @@ typedef enum { em_rev_polarity_undefined = 0xFF } em_rev_polarity; + typedef enum { em_polarity_reversal_enabled = 0, em_polarity_reversal_disabled, @@ -147,6 +150,7 @@ typedef enum { 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; @@ -165,16 +169,18 @@ struct em_phy_stats { /* Error Codes */ -#define E1000_SUCCESS 0 -#define E1000_ERR_EEPROM 1 -#define E1000_ERR_PHY 2 -#define E1000_ERR_CONFIG 3 -#define E1000_ERR_PARAM 4 +#define E1000_SUCCESS 0 +#define E1000_ERR_EEPROM 1 +#define E1000_ERR_PHY 2 +#define E1000_ERR_CONFIG 3 +#define E1000_ERR_PARAM 4 +#define E1000_ERR_MAC_TYPE 5 /* Function prototypes */ /* Initialization */ void em_reset_hw(struct em_hw *hw); int32_t em_init_hw(struct em_hw *hw); +int32_t em_set_mac_type(struct em_hw *hw); /* Link Configuration */ int32_t em_setup_link(struct em_hw *hw); @@ -225,6 +231,8 @@ void em_reset_adaptive(struct em_hw *hw); void em_update_adaptive(struct em_hw *hw); void em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr); void em_get_bus_info(struct em_hw *hw); +void em_pci_set_mwi(struct em_hw *hw); +void em_pci_clear_mwi(struct em_hw *hw); void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value); void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ @@ -232,26 +240,30 @@ uint32_t em_io_read(struct em_hw *hw, uint32_t port); uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset); void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value); void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value); + #define E1000_READ_REG_IO(a, reg) \ em_read_reg_io((a), E1000_##reg) #define E1000_WRITE_REG_IO(a, reg, val) \ em_write_reg_io((a), E1000_##reg, val) /* PCI Device IDs */ -#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 E1000_DEV_ID_82540EM 0x100E -#define E1000_DEV_ID_82540EM_LOM 0x1015 -#define E1000_DEV_ID_82545EM_COPPER 0x100F -#define E1000_DEV_ID_82545EM_FIBER 0x1011 -#define E1000_DEV_ID_82546EB_COPPER 0x1010 -#define E1000_DEV_ID_82546EB_FIBER 0x1012 -#define NUM_DEV_IDS 13 +#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 E1000_DEV_ID_82540EM 0x100E +#define E1000_DEV_ID_82540EM_LOM 0x1015 +#define E1000_DEV_ID_82540EP_LOM 0x1016 +#define E1000_DEV_ID_82540EP 0x1017 +#define E1000_DEV_ID_82540EP_LP 0x101E +#define E1000_DEV_ID_82545EM_COPPER 0x100F +#define E1000_DEV_ID_82545EM_FIBER 0x1011 +#define E1000_DEV_ID_82546EB_COPPER 0x1010 +#define E1000_DEV_ID_82546EB_FIBER 0x1012 +#define NUM_DEV_IDS 16 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -852,6 +864,7 @@ struct em_hw { em_bus_type bus_type; uint32_t io_base; uint32_t phy_id; + uint32_t phy_revision; uint32_t phy_addr; uint32_t original_fc; uint32_t txcw; @@ -981,6 +994,7 @@ struct em_hw { #define E1000_EERD_DATA_SHIFT 16 #define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */ + /* 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 */ @@ -1189,6 +1203,7 @@ struct em_hw { #define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ #define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ +#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ /* Transmit Configuration Word */ #define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ @@ -1428,6 +1443,8 @@ struct em_hw { #define PCIX_COMMAND_MMRBC_SHIFT 0x2 #define PCIX_STATUS_HI_MMRBC_MASK 0x0060 #define PCIX_STATUS_HI_MMRBC_SHIFT 0x5 +#define PCIX_STATUS_HI_MMRBC_4K 0x3 +#define PCIX_STATUS_HI_MMRBC_2K 0x2 /* The number of bits that we need to shift right to move the "pause" @@ -1541,6 +1558,7 @@ struct em_hw { #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 */ @@ -1747,12 +1765,14 @@ struct em_hw { #define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ #define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + /* Bit definitions for valid PHY IDs. */ #define M88E1000_E_PHY_ID 0x01410C50 #define M88E1000_I_PHY_ID 0x01410C30 #define M88E1011_I_PHY_ID 0x01410C20 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID +#define M88E1011_I_REV_4 0x04 /* Miscellaneous PHY bit definitions. */ #define PHY_PREAMBLE 0xFFFFFFFF diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h index b75eea8..2a50b5a 100644 --- a/sys/dev/em/if_em_osdep.h +++ b/sys/dev/em/if_em_osdep.h @@ -89,6 +89,8 @@ struct em_osdep struct device *dev; }; +#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) + #define E1000_READ_REG(a, reg) (\ ((a)->mac_type >= em_82543) ? \ bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \ -- cgit v1.1