From a58e485d361984a7a93e564b1cabe72fbd2c9ff6 Mon Sep 17 00:00:00 2001 From: Prafulla Deuskar Date: Mon, 23 Dec 2002 19:11:23 +0000 Subject: [PATCH] - Move to array based indexing for TX/RX descriptor/buffer management - Added support for ITR (interrupt throttle register). This feature is available on adapters based on 82545 and above - Fixed problem with vlan support when traffic has priority bits set. (kern/45907) PR: kern/45907 MFC after: 1 week --- sys/dev/em/README | 6 +- sys/dev/em/if_em.c | 919 +++++++++++++++++++++------------------------ sys/dev/em/if_em.h | 122 +++--- 3 files changed, 514 insertions(+), 533 deletions(-) diff --git a/sys/dev/em/README b/sys/dev/em/README index 728807475aae..6ff12d78cbf5 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 ============================================================ -September 11, 2002 +November 12, 2002 Contents @@ -23,8 +23,8 @@ In This Release 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. +FreeBSD, version 4.7. As a new feature for this release, the driver is now +compiled by default into the FreeBSD 4.7 kernel. The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on all but the 82542-based adapters. For specific adapters, refer to the diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index e8f36725eec9..1503ea2779c6 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.4.7"; +char em_driver_version[] = "1.4.10"; /********************************************************************* @@ -65,25 +65,25 @@ char em_driver_version[] = "1.4.7"; *********************************************************************/ static em_vendor_info_t em_vendor_info_array[] = { - /* Intel(R) PRO/1000 Network Connection */ - { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0}, - { 0x8086, 0x100E, 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} + /* Intel(R) PRO/1000 Network Connection */ + { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, 0x100E, 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} }; /********************************************************************* @@ -129,18 +129,18 @@ static int em_allocate_receive_structures(struct adapter *); static int em_allocate_transmit_structures(struct adapter *); static void em_process_receive_interrupts(struct adapter *, int); static void em_receive_checksum(struct adapter *, - struct em_rx_desc * rx_desc, - struct mbuf *); + struct em_rx_desc * rx_desc, + struct mbuf *); static void em_transmit_checksum_setup(struct adapter *, - struct mbuf *, - u_int32_t *, - u_int32_t *); + struct mbuf *, + u_int32_t *, + u_int32_t *); static void em_set_promisc(struct adapter *); static void em_disable_promisc(struct adapter *); static void em_set_multi(struct adapter *); static void em_print_hw_stats(struct adapter *); static void em_print_link_status(struct adapter *); -static int em_get_buf(struct em_rx_buffer *, struct adapter *, +static int em_get_buf(int i, struct adapter *, struct mbuf *); static void em_enable_vlans(struct adapter *adapter); static int em_encap(struct adapter *adapter, struct mbuf *m_head); @@ -257,30 +257,33 @@ em_attach(device_t dev) /* Determine hardware revision */ em_identify_hardware(adapter); + + /* Parameters (to be read from user) */ + adapter->num_tx_desc = EM_MAX_TXD; + adapter->num_rx_desc = EM_MAX_RXD; + adapter->tx_int_delay = EM_TIDV; + adapter->tx_abs_int_delay = EM_TADV; + adapter->rx_int_delay = EM_RDTR; + adapter->rx_abs_int_delay = EM_RADV; + adapter->hw.autoneg = DO_AUTO_NEG; + adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; + adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; + adapter->hw.tbi_compatibility_en = TRUE; + adapter->rx_buffer_len = EM_RXBUFFER_2048; + + adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH; + adapter->hw.fc_low_water = FC_DEFAULT_LO_THRESH; + adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER; + adapter->hw.fc_send_xon = TRUE; + adapter->hw.fc = em_fc_full; - /* Parameters (to be read from user) */ - 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; - adapter->hw.tbi_compatibility_en = TRUE; - adapter->rx_buffer_len = EM_RXBUFFER_2048; - - adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH; - adapter->hw.fc_low_water = FC_DEFAULT_LO_THRESH; - adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER; - adapter->hw.fc_send_xon = TRUE; - adapter->hw.fc = em_fc_full; /* Set the max frame size assuming standard ethernet sized frames */ adapter->hw.max_frame_size = - ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; + ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; adapter->hw.min_frame_size = - MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; + MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; /* This controls when hardware reports transmit completion status. */ if ((EM_REPORT_TX_EARLY == 0) || (EM_REPORT_TX_EARLY == 1)) { @@ -300,7 +303,8 @@ em_attach(device_t dev) splx(s); return(ENXIO); } - + + tsize = EM_ROUNDUP(adapter->num_tx_desc * sizeof(struct em_tx_desc), 4096); @@ -398,7 +402,11 @@ em_detach(device_t dev) em_stop(adapter); em_phy_hw_reset(&adapter->hw); +#if __FreeBSD_version < 500000 + ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); +#else ether_ifdetach(&adapter->interface_data.ac_if); +#endif em_free_pci_resources(adapter); size = EM_ROUNDUP(adapter->num_tx_desc * @@ -437,8 +445,8 @@ em_detach(device_t dev) /********************************************************************* * * Shutdown entry point - * - **********************************************************************/ + * + **********************************************************************/ static int em_shutdown(device_t dev) @@ -448,6 +456,7 @@ em_shutdown(device_t dev) return(0); } + /********************************************************************* * Transmit entry point * @@ -461,35 +470,41 @@ em_shutdown(device_t dev) static void em_start(struct ifnet *ifp) { - int s; - struct mbuf *m_head; - struct adapter *adapter = ifp->if_softc; + int s; + struct mbuf *m_head; + struct adapter *adapter = ifp->if_softc; + + if (!adapter->link_active) + return; - if (!adapter->link_active) - return; + s = splimp(); + while (ifp->if_snd.ifq_head != NULL) { - s = splimp(); - while (ifp->if_snd.ifq_head != NULL) { - - IF_DEQUEUE(&ifp->if_snd, m_head); + IF_DEQUEUE(&ifp->if_snd, m_head); + + if (m_head == NULL) break; + + if (em_encap(adapter, m_head)) { + ifp->if_flags |= IFF_OACTIVE; + IF_PREPEND(&ifp->if_snd, m_head); + break; + } - if (m_head == NULL) break; - if (em_encap(adapter, m_head)) { - ifp->if_flags |= IFF_OACTIVE; - IF_PREPEND(&ifp->if_snd, m_head); - break; - } - - /* Send a copy of the frame to the BPF listener */ + /* Send a copy of the frame to the BPF listener */ +#if __FreeBSD_version < 500000 + if (ifp->if_bpf) + bpf_mtap(ifp, m_head); +#else BPF_MTAP(ifp, m_head); - - /* Set timeout in case hardware has problems transmitting */ - ifp->if_timer = EM_TX_TIMEOUT; - - } - splx(s); - return; +#endif + + /* Set timeout in case hardware has problems transmitting */ + ifp->if_timer = EM_TX_TIMEOUT; + + } + splx(s); + return; } /********************************************************************* @@ -526,23 +541,20 @@ em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) em_init(adapter); } break; - case SIOCSIFFLAGS: - IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); - if (ifp->if_flags & IFF_UP) { - /* - * init adapter if not running, then take care - * of possible changes in IFF_ALLMULTI and IFF_PROMISC - */ - if (!(ifp->if_flags & IFF_RUNNING)) - em_init(adapter); - em_disable_promisc(adapter); - em_set_promisc(adapter); - } else { - if (ifp->if_flags & IFF_RUNNING) { - em_stop(adapter); - } - } - break; + case SIOCSIFFLAGS: + IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_flags & IFF_RUNNING)) + em_init(adapter); + + em_disable_promisc(adapter); + em_set_promisc(adapter); + } else { + if (ifp->if_flags & IFF_RUNNING) { + em_stop(adapter); + } + } + break; case SIOCADDMULTI: case SIOCDELMULTI: IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI"); @@ -683,15 +695,15 @@ em_init(void *arg) adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); em_clear_hw_cntrs(&adapter->hw); #ifdef DEVICE_POLLING - /* - * Only enable interrupts if we are not polling, make sure - * they are off otherwise. - */ - if (ifp->if_ipending & IFF_POLLING) - em_disable_intr(adapter); - else + /* + * Only enable interrupts if we are not polling, make sure + * they are off otherwise. + */ + if (ifp->if_ipending & IFF_POLLING) + em_disable_intr(adapter); + else #endif /* DEVICE_POLLING */ - em_enable_intr(adapter); + em_enable_intr(adapter); splx(s); return; @@ -700,37 +712,36 @@ em_init(void *arg) #ifdef DEVICE_POLLING static poll_handler_t em_poll; -static void +static void em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { - struct adapter *adapter = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; + u_int32_t reg_icr; - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - em_enable_intr(adapter); - return; - } - if (cmd == POLL_AND_CHECK_STATUS) { - u_int32_t reg_icr = E1000_READ_REG(&adapter->hw, ICR); - - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - untimeout(em_local_timer, adapter, - adapter->timer_handle); - adapter->hw.get_link_status = 1; - em_check_for_link(&adapter->hw); - em_print_link_status(adapter); - adapter->timer_handle = timeout(em_local_timer, - adapter, 2*hz); - } - } - if (ifp->if_flags & IFF_RUNNING) { - em_process_receive_interrupts(adapter, count); - em_clean_transmit_interrupts(adapter); - } - if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) - em_start(ifp); + if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ + em_enable_intr(adapter); + return; + } + if (cmd == POLL_AND_CHECK_STATUS) { + reg_icr = E1000_READ_REG(&adapter->hw, ICR); + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + untimeout(em_local_timer, adapter, adapter->timer_handle); + adapter->hw.get_link_status = 1; + em_check_for_link(&adapter->hw); + em_print_link_status(adapter); + adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); + } + } + if (ifp->if_flags & IFF_RUNNING) { + em_process_receive_interrupts(adapter, count); + em_clean_transmit_interrupts(adapter); + } + if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) + em_start(ifp); } #endif /* DEVICE_POLLING */ + /********************************************************************* * * Interrupt Service routine @@ -748,16 +759,17 @@ em_intr(void *arg) ifp = &adapter->interface_data.ac_if; #ifdef DEVICE_POLLING - if (ifp->if_ipending & IFF_POLLING) - return; + if (ifp->if_ipending & IFF_POLLING) + return; - if (ether_poll_register(em_poll, ifp)) { - em_disable_intr(adapter); - em_poll(ifp, 0, 1); - return; - } + if (ether_poll_register(em_poll, ifp)) { + em_disable_intr(adapter); + em_poll(ifp, 0, 1); + return; + } #endif /* DEVICE_POLLING */ + em_disable_intr(adapter); while (loop_cnt > 0 && (reg_icr = E1000_READ_REG(&adapter->hw, ICR)) != 0) { @@ -912,7 +924,6 @@ em_media_change(struct ifnet *ifp) return(0); } - /********************************************************************* * * This routine maps the mbufs to tx descriptors. @@ -922,20 +933,23 @@ em_media_change(struct ifnet *ifp) 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 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; - struct m_tag *mtag; +{ + vm_offset_t virtual_addr; + u_int32_t txd_upper; + u_int32_t txd_lower; + int txd_used, i, txd_saved; + struct mbuf *mp; +#if __FreeBSD_version < 500000 + struct ifvlan *ifv = NULL; +#else + struct m_tag *mtag; +#endif - /* Force a cleanup if number of descriptors available hit the threshold */ + struct em_buffer *tx_buffer = NULL; + struct em_tx_desc *current_tx_desc = NULL; + struct ifnet *ifp = &adapter->interface_data.ac_if; + + /* Force a cleanup if number of TX descriptors available hits the threshold */ if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) em_clean_transmit_interrupts(adapter); @@ -944,101 +958,84 @@ em_encap(struct adapter *adapter, struct mbuf *m_head) 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; } + else + txd_upper = txd_lower = 0; /* Find out if we are in vlan mode */ +#if __FreeBSD_version < 500000 + if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && + m_head->m_pkthdr.rcvif != NULL && + m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) + ifv = m_head->m_pkthdr.rcvif->if_softc; +#else mtag = VLAN_OUTPUT_TAG(ifp, m_head); +#endif + i = adapter->next_avail_tx_desc; + txd_saved = i; 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; + + if (txd_used == adapter->num_tx_desc_avail) { + adapter->next_avail_tx_desc = txd_saved; + adapter->no_tx_desc_avail2++; return (ENOBUFS); } - current_tx_desc = adapter->next_avail_tx_desc; + tx_buffer = &adapter->tx_buffer_area[i]; + current_tx_desc = &adapter->tx_desc_base[i]; virtual_addr = mtod(mp, vm_offset_t); current_tx_desc->buffer_addr = vtophys(virtual_addr); current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower | mp->m_len); current_tx_desc->upper.data = (txd_upper); - if (current_tx_desc == adapter->last_tx_desc) - adapter->next_avail_tx_desc = - adapter->first_tx_desc; - else - adapter->next_avail_tx_desc++; + if (++i == adapter->num_tx_desc) + i = 0; + + tx_buffer->m_head = NULL; 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; + adapter->num_tx_desc_avail -= txd_used; + adapter->next_avail_tx_desc = i; + +#if __FreeBSD_version < 500000 + if (ifv != NULL) { + /* Set the vlan id */ + current_tx_desc->upper.fields.special = ifv->ifv_tag; +#else if (mtag != NULL) { - /* Tell hardware to add tag */ - current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; - /* Set the vlan id */ current_tx_desc->upper.fields.special = VLAN_TAG_VALUE(mtag); +#endif + /* Tell hardware to add tag */ + current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; } - /* 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; + + /* + * Last Descriptor of Packet needs End Of Packet (EOP) + */ + current_tx_desc->lower.data |= (E1000_TXD_CMD_EOP); /* * 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)); + E1000_WRITE_REG(&adapter->hw, TDT, i); - return(0); + return (0); } - static void em_set_promisc(struct adapter * adapter) { @@ -1085,55 +1082,55 @@ em_disable_promisc(struct adapter * adapter) 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); - } - + 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) { + 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; + 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++; + } - 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 (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); + } + } - 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; + return; } @@ -1194,6 +1191,7 @@ em_print_link_status(struct adapter * adapter) } + /********************************************************************* * * This routine disables all traffic on the adapter by issuing a @@ -1237,9 +1235,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); } @@ -1252,10 +1250,10 @@ em_identify_hardware(struct adapter * adapter) 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); + if (em_set_mac_type(&adapter->hw)) + printf("em%d: Unknown MAC Type\n", adapter->unit); - return; + return; } static int @@ -1425,13 +1423,21 @@ em_setup_interface(device_t dev, struct adapter * adapter) ifp->if_start = em_start; ifp->if_watchdog = em_watchdog; ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1; + +#if __FreeBSD_version < 500000 + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); +#else ether_ifattach(ifp, adapter->interface_data.ac_enaddr); +#endif if (adapter->hw.mac_type >= em_82543) { ifp->if_capabilities = IFCAP_HWCSUM; ifp->if_capenable = ifp->if_capabilities; } + +#if __FreeBSD_version >= 500000 ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; +#endif /* * Specify the media types supported by this adapter and register @@ -1479,7 +1485,7 @@ static int em_allocate_transmit_structures(struct adapter * adapter) { if (!(adapter->tx_buffer_area = - (struct em_tx_buffer *) malloc(sizeof(struct em_tx_buffer) * + (struct em_buffer *) malloc(sizeof(struct em_buffer) * adapter->num_tx_desc, M_DEVBUF, M_NOWAIT))) { printf("em%d: Unable to allocate tx_buffer memory\n", @@ -1488,7 +1494,7 @@ em_allocate_transmit_structures(struct adapter * adapter) } bzero(adapter->tx_buffer_area, - sizeof(struct em_tx_buffer) * adapter->num_tx_desc); + sizeof(struct em_buffer) * adapter->num_tx_desc); return 0; } @@ -1501,34 +1507,14 @@ em_allocate_transmit_structures(struct adapter * adapter) static int em_setup_transmit_structures(struct adapter * adapter) { - struct em_tx_buffer *tx_buffer; - int i; - if (em_allocate_transmit_structures(adapter)) return ENOMEM; - adapter->first_tx_desc = adapter->tx_desc_base; - adapter->last_tx_desc = - adapter->first_tx_desc + (adapter->num_tx_desc - 1); - - - STAILQ_INIT(&adapter->free_tx_buffer_list); - STAILQ_INIT(&adapter->used_tx_buffer_list); - - tx_buffer = adapter->tx_buffer_area; - - /* Setup the linked list of the tx_buffer's */ - for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { - bzero((void *) tx_buffer, sizeof(struct em_tx_buffer)); - STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list, - tx_buffer, em_tx_entry); - } - - bzero((void *) adapter->first_tx_desc, - (sizeof(struct em_tx_desc)) * adapter->num_tx_desc); - - /* Setup TX descriptor pointers */ - adapter->next_avail_tx_desc = adapter->first_tx_desc; + bzero((void *) adapter->tx_desc_base, + (sizeof(struct em_tx_desc)) * adapter->num_tx_desc); + + adapter->next_avail_tx_desc = 0; + adapter->oldest_used_tx_desc = 0; /* Set number of descriptors available */ adapter->num_tx_desc_avail = adapter->num_tx_desc; @@ -1593,6 +1579,8 @@ em_initialize_transmit_unit(struct adapter * adapter) } E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg); E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); + if(adapter->hw.mac_type >= em_82540) + E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay); /* Program the Transmit Control Register */ reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | @@ -1626,7 +1614,7 @@ em_initialize_transmit_unit(struct adapter * adapter) static void em_free_transmit_structures(struct adapter * adapter) { - struct em_tx_buffer *tx_buffer; + struct em_buffer *tx_buffer; int i; INIT_DEBUGOUT("free_transmit_structures: begin"); @@ -1654,14 +1642,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, 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; + struct em_buffer *tx_buffer; + int curr_txd; if (mp->m_pkthdr.csum_flags) { @@ -1694,43 +1682,41 @@ em_transmit_checksum_setup(struct adapter *adapter, /* If we reach this point, the checksum offload context * needs to be reset. */ - current_tx_desc = adapter->next_avail_tx_desc; - tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); + curr_txd = adapter->next_avail_tx_desc; + tx_buffer = &adapter->tx_buffer_area[curr_txd]; + TXD = (struct em_context_desc *) &adapter->tx_desc_base[curr_txd]; - 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); + ETHER_HDR_LEN + offsetof(struct ip, ip_sum); TXD->lower_setup.ip_fields.ipcse = - ETHER_HDR_LEN + sizeof(struct ip) - 1; + ETHER_HDR_LEN + sizeof(struct ip) - 1; TXD->upper_setup.tcp_fields.tucss = - ETHER_HDR_LEN + sizeof(struct ip); + ETHER_HDR_LEN + sizeof(struct ip); TXD->upper_setup.tcp_fields.tucse = 0; if (adapter->active_checksum_context == OFFLOAD_TCP_IP) { TXD->upper_setup.tcp_fields.tucso = - ETHER_HDR_LEN + sizeof(struct ip) + - offsetof(struct tcphdr, th_sum); + ETHER_HDR_LEN + sizeof(struct ip) + + offsetof(struct tcphdr, th_sum); } else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) { TXD->upper_setup.tcp_fields.tucso = - ETHER_HDR_LEN + sizeof(struct ip) + - offsetof(struct udphdr, uh_sum); + ETHER_HDR_LEN + sizeof(struct ip) + + offsetof(struct udphdr, uh_sum); } TXD->tcp_seg_setup.data = 0; TXD->cmd_and_length = (adapter->txd_cmd | E1000_TXD_CMD_DEXT); - if (current_tx_desc == adapter->last_tx_desc) - adapter->next_avail_tx_desc = adapter->first_tx_desc; - else - adapter->next_avail_tx_desc++; + tx_buffer->m_head = NULL; + + if (++curr_txd == adapter->num_tx_desc) + curr_txd = 0; adapter->num_tx_desc_avail--; + adapter->next_avail_tx_desc = curr_txd; - 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; } @@ -1738,114 +1724,109 @@ em_transmit_checksum_setup(struct adapter *adapter, * * 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. + * tx_buffer is put back on the free queue. * **********************************************************************/ static void em_clean_transmit_interrupts(struct adapter * adapter) { - struct em_tx_buffer *tx_buffer; + int s; + int i, num_avail; + struct em_buffer *tx_buffer; struct em_tx_desc *tx_desc; - int s; - struct ifnet *ifp; - s = splimp(); + if (adapter->num_tx_desc_avail == adapter->num_tx_desc) + return; + + s = splimp(); #ifdef DBG_STATS - adapter->clean_tx_interrupts++; + adapter->clean_tx_interrupts++; #endif + num_avail = adapter->num_tx_desc_avail; + i = adapter->oldest_used_tx_desc; - for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list); - tx_buffer; - tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) { + tx_buffer = &adapter->tx_buffer_area[i]; + tx_desc = &adapter->tx_desc_base[i]; - /* - * 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. - */ + while(tx_desc->upper.fields.status & E1000_TXD_STAT_DD) { - 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; + tx_desc->upper.data = 0; + num_avail++; + + if (tx_buffer->m_head) { + m_freem(tx_buffer->m_head); + tx_buffer->m_head = NULL; } - } /* end for each tx_buffer */ + + if (++i == adapter->num_tx_desc) + i = 0; - ifp = &adapter->interface_data.ac_if; + tx_buffer = &adapter->tx_buffer_area[i]; + tx_desc = &adapter->tx_desc_base[i]; + } - /* 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; + adapter->oldest_used_tx_desc = i; + + /* + * If we have enough room, clear IFF_OACTIVE to tell the stack + * that it is OK to send packets. + * If there are no pending descriptors, clear the timeout. Otherwise, + * if some descriptors have been freed, restart the timeout. + */ + if (num_avail > EM_TX_CLEANUP_THRESHOLD) { + struct ifnet *ifp = &adapter->interface_data.ac_if; + + ifp->if_flags &= ~IFF_OACTIVE; + if (num_avail == adapter->num_tx_desc) + ifp->if_timer = 0; + else if (num_avail == adapter->num_tx_desc_avail) + ifp->if_timer = EM_TX_TIMEOUT; + } + adapter->num_tx_desc_avail = num_avail; + splx(s); + return; } - /********************************************************************* * * Get a buffer from system mbuf buffer pool. * **********************************************************************/ static int -em_get_buf(struct em_rx_buffer *rx_buffer, struct adapter *adapter, - struct mbuf *mp) +em_get_buf(int i, struct adapter *adapter, + struct mbuf *nmp) { - struct mbuf *nmp; + register struct mbuf *mp = nmp; struct ifnet *ifp; ifp = &adapter->interface_data.ac_if; if (mp == NULL) { - MGETHDR(nmp, M_DONTWAIT, MT_DATA); - if (nmp == NULL) { + MGETHDR(mp, M_DONTWAIT, MT_DATA); + if (mp == NULL) { adapter->mbuf_alloc_failed++; return(ENOBUFS); } - MCLGET(nmp, M_DONTWAIT); - if ((nmp->m_flags & M_EXT) == 0) { - m_freem(nmp); + MCLGET(mp, M_DONTWAIT); + if ((mp->m_flags & M_EXT) == 0) { + m_freem(mp); adapter->mbuf_cluster_failed++; return(ENOBUFS); } - nmp->m_len = nmp->m_pkthdr.len = MCLBYTES; + mp->m_len = mp->m_pkthdr.len = MCLBYTES; } else { - nmp = mp; - nmp->m_len = nmp->m_pkthdr.len = MCLBYTES; - nmp->m_data = nmp->m_ext.ext_buf; - nmp->m_next = NULL; + mp->m_len = mp->m_pkthdr.len = MCLBYTES; + mp->m_data = mp->m_ext.ext_buf; + mp->m_next = NULL; } if (ifp->if_mtu <= ETHERMTU) { - m_adj(nmp, ETHER_ALIGN); + m_adj(mp, ETHER_ALIGN); } - - rx_buffer->m_head = nmp; - rx_buffer->buffer_addr = vtophys(mtod(nmp, vm_offset_t)); + + adapter->rx_buffer_area[i].m_head = mp; + adapter->rx_desc_base[i].buffer_addr = + vtophys(mtod(mp, vm_offset_t)); return(0); } @@ -1862,10 +1843,9 @@ static int em_allocate_receive_structures(struct adapter * adapter) { int i; - struct em_rx_buffer *rx_buffer; if (!(adapter->rx_buffer_area = - (struct em_rx_buffer *) malloc(sizeof(struct em_rx_buffer) * + (struct em_buffer *) malloc(sizeof(struct em_buffer) * adapter->num_rx_desc, M_DEVBUF, M_NOWAIT))) { printf("em%d: Unable to allocate rx_buffer memory\n", @@ -1874,13 +1854,12 @@ em_allocate_receive_structures(struct adapter * adapter) } bzero(adapter->rx_buffer_area, - sizeof(struct em_rx_buffer) * adapter->num_rx_desc); + sizeof(struct em_buffer) * adapter->num_rx_desc); - for (i = 0, rx_buffer = adapter->rx_buffer_area; - i < adapter->num_rx_desc; i++, rx_buffer++) { - - if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) { - rx_buffer->m_head = NULL; + for (i = 0; i < adapter->num_rx_desc; i++) { + if (em_get_buf(i, adapter, NULL) == ENOBUFS) { + adapter->rx_buffer_area[i].m_head = NULL; + adapter->rx_desc_base[i].buffer_addr = 0; return(ENOBUFS); } } @@ -1896,42 +1875,14 @@ em_allocate_receive_structures(struct adapter * adapter) static int em_setup_receive_structures(struct adapter * adapter) { - struct em_rx_buffer *rx_buffer; - struct em_rx_desc *rx_desc; - int i; + bzero((void *) adapter->rx_desc_base, + (sizeof(struct em_rx_desc)) * adapter->num_rx_desc); if (em_allocate_receive_structures(adapter)) return ENOMEM; - STAILQ_INIT(&adapter->rx_buffer_list); - - adapter->first_rx_desc = - (struct em_rx_desc *) adapter->rx_desc_base; - adapter->last_rx_desc = - adapter->first_rx_desc + (adapter->num_rx_desc - 1); - - rx_buffer = (struct em_rx_buffer *) adapter->rx_buffer_area; - - bzero((void *) adapter->first_rx_desc, - (sizeof(struct em_rx_desc)) * adapter->num_rx_desc); - - /* Build a linked list of rx_buffer's */ - for (i = 0, rx_desc = adapter->first_rx_desc; - i < adapter->num_rx_desc; - i++, rx_buffer++, rx_desc++) { - if (rx_buffer->m_head == NULL) - printf("em%d: Receive buffer memory not allocated", - adapter->unit); - else { - rx_desc->buffer_addr = rx_buffer->buffer_addr; - STAILQ_INSERT_TAIL(&adapter->rx_buffer_list, - rx_buffer, em_rx_entry); - } - } - /* Setup our descriptor pointers */ - adapter->next_rx_desc_to_check = adapter->first_rx_desc; - + adapter->next_rx_desc_to_check = 0; return(0); } @@ -1956,6 +1907,16 @@ em_initialize_receive_unit(struct adapter * adapter) E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay | E1000_RDT_FPDB); + if(adapter->hw.mac_type >= em_82540) { + E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); + + /* Set the interrupt throttling rate. Value is calculated + * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ +#define MAX_INTS_PER_SEC 8000 +#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) + E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR); + } + /* Setup the Base and Length of the Rx Descriptor Ring */ E1000_WRITE_REG(&adapter->hw, RDBAL, vtophys((vm_offset_t) adapter->rx_desc_base)); @@ -1965,9 +1926,7 @@ em_initialize_receive_unit(struct adapter * adapter) /* Setup the HW Rx Head and Tail Descriptor Pointers */ E1000_WRITE_REG(&adapter->hw, RDH, 0); - E1000_WRITE_REG(&adapter->hw, RDT, - (((uintptr_t) adapter->last_rx_desc - - (uintptr_t) adapter->first_rx_desc) >> 4)); + E1000_WRITE_REG(&adapter->hw, RDT, adapter->num_rx_desc - 1); /* Setup the Receive Control Register */ reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | @@ -2017,9 +1976,9 @@ em_initialize_receive_unit(struct adapter * adapter) * **********************************************************************/ static void -em_free_receive_structures(struct adapter * adapter) +em_free_receive_structures(struct adapter *adapter) { - struct em_rx_buffer *rx_buffer; + struct em_buffer *rx_buffer; int i; INIT_DEBUGOUT("free_receive_structures: begin"); @@ -2045,25 +2004,29 @@ em_free_receive_structures(struct adapter * adapter) * the mbufs in the descriptor and sends data which has been * dma'ed into host memory to upper layer. * + * We loop at most count times if count is > 0, or until done if + * count < 0. + * *********************************************************************/ static void em_process_receive_interrupts(struct adapter * adapter, int count) { - struct mbuf *mp; struct ifnet *ifp; - u_int16_t len; - u_int8_t last_byte; + struct mbuf *mp; +#if __FreeBSD_version < 500000 + struct ether_header *eh; +#endif u_int8_t accept_frame = 0; u_int8_t eop = 0; - u_int32_t pkt_len = 0; + u_int16_t len; + int i; /* Pointer to the receive descriptor being examined. */ struct em_rx_desc *current_desc; - struct em_rx_desc *last_desc_processed; - struct em_rx_buffer *rx_buffer; ifp = &adapter->interface_data.ac_if; - current_desc = adapter->next_rx_desc_to_check; + i = adapter->next_rx_desc_to_check; + current_desc = &adapter->rx_desc_base[i]; if (!((current_desc->status) & E1000_RXD_STAT_DD)) { #ifdef DBG_STATS @@ -2073,18 +2036,9 @@ em_process_receive_interrupts(struct adapter * adapter, int count) } while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) { + mp = adapter->rx_buffer_area[i].m_head; - /* Get a pointer to the actual receive buffer */ - rx_buffer = STAILQ_FIRST(&adapter->rx_buffer_list); - - if (rx_buffer == NULL) { - printf("em%d: Found null rx_buffer\n", adapter->unit); - return; - } - - mp = rx_buffer->m_head; accept_frame = 1; - if (current_desc->status & E1000_RXD_STAT_EOP) { count--; eop = 1; @@ -2095,15 +2049,14 @@ em_process_receive_interrupts(struct adapter * adapter, int count) } if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + u_int8_t last_byte; + u_int32_t pkt_len = current_desc->length; - /* Compute packet length for tbi_accept macro */ - pkt_len = current_desc->length; - if (adapter->fmp != NULL) { + if (adapter->fmp != NULL) pkt_len += adapter->fmp->m_pkthdr.len; - } - - last_byte = *(mtod(rx_buffer->m_head,caddr_t) + - current_desc->length - 1); + + last_byte = *(mtod(mp, caddr_t) + + current_desc->length - 1); if (TBI_ACCEPT(&adapter->hw, current_desc->status, current_desc->errors, @@ -2113,17 +2066,19 @@ em_process_receive_interrupts(struct adapter * adapter, int count) pkt_len, adapter->hw.mac_addr); len--; - } else { + } + else { accept_frame = 0; } } if (accept_frame) { - if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) { + if (em_get_buf(i, adapter, NULL) == ENOBUFS) { adapter->dropped_pkts++; - em_get_buf(rx_buffer, adapter, mp); - if (adapter->fmp != NULL) m_freem(adapter->fmp); + em_get_buf(i, adapter, mp); + if (adapter->fmp != NULL) + m_freem(adapter->fmp); adapter->fmp = NULL; adapter->lmp = NULL; break; @@ -2146,53 +2101,58 @@ em_process_receive_interrupts(struct adapter * adapter, int count) if (eop) { adapter->fmp->m_pkthdr.rcvif = ifp; + +#if __FreeBSD_version < 500000 + eh = mtod(adapter->fmp, struct ether_header *); + /* Remove ethernet header from mbuf */ + m_adj(adapter->fmp, sizeof(struct ether_header)); + em_receive_checksum(adapter, current_desc, + adapter->fmp); + if (current_desc->status & E1000_RXD_STAT_VP) + VLAN_INPUT_TAG(eh, adapter->fmp, + (current_desc->special & + E1000_RXD_SPC_VLAN_MASK)); + else + ether_input(ifp, eh, adapter->fmp); +#else + em_receive_checksum(adapter, current_desc, adapter->fmp); if (current_desc->status & E1000_RXD_STAT_VP) VLAN_INPUT_TAG(ifp, adapter->fmp, - current_desc->special, - adapter->fmp = NULL); + (current_desc->special & + E1000_RXD_SPC_VLAN_MASK), + adapter->fmp = NULL); + if (adapter->fmp != NULL) (*ifp->if_input)(ifp, adapter->fmp); - +#endif adapter->fmp = NULL; adapter->lmp = NULL; } } else { adapter->dropped_pkts++; - em_get_buf(rx_buffer, adapter, mp); - if (adapter->fmp != NULL) m_freem(adapter->fmp); + em_get_buf(i, adapter, mp); + if (adapter->fmp != NULL) + m_freem(adapter->fmp); adapter->fmp = NULL; adapter->lmp = NULL; } /* Zero out the receive descriptors status */ current_desc->status = 0; - - if (rx_buffer->m_head != NULL) { - current_desc->buffer_addr = rx_buffer->buffer_addr; - } - - /* Advance our pointers to the next descriptor (checking for wrap). */ - if (current_desc == adapter->last_rx_desc) - adapter->next_rx_desc_to_check = adapter->first_rx_desc; - else - ((adapter)->next_rx_desc_to_check)++; - - last_desc_processed = current_desc; - current_desc = adapter->next_rx_desc_to_check; - /* - * Put the buffer that we just indicated back at the end of our list - */ - STAILQ_REMOVE_HEAD(&adapter->rx_buffer_list, em_rx_entry); - STAILQ_INSERT_TAIL(&adapter->rx_buffer_list, - rx_buffer, em_rx_entry); - + /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ - E1000_WRITE_REG(&adapter->hw, RDT, - (((u_long) last_desc_processed - - (u_long) adapter->first_rx_desc) >> 4)); + E1000_WRITE_REG(&adapter->hw, RDT, i); + + /* Advance our pointers to the next descriptor */ + if (++i == adapter->num_rx_desc) { + i = 0; + current_desc = adapter->rx_desc_base; + } else + current_desc++; } + adapter->next_rx_desc_to_check = i; return; } @@ -2241,7 +2201,8 @@ em_receive_checksum(struct adapter *adapter, } -static void em_enable_vlans(struct adapter *adapter) +static void +em_enable_vlans(struct adapter *adapter) { uint32_t ctrl; @@ -2271,8 +2232,8 @@ em_disable_intr(struct adapter *adapter) void em_write_pci_cfg(struct em_hw *hw, - uint32_t reg, - uint16_t *value) + uint32_t reg, + uint16_t *value) { pci_write_config(((struct em_osdep *)hw->back)->dev, reg, *value, 2); @@ -2280,30 +2241,29 @@ em_write_pci_cfg(struct em_hw *hw, void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, - uint16_t *value) + uint16_t *value) { *value = pci_read_config(((struct em_osdep *)hw->back)->dev, reg, 2); return; } - void em_pci_set_mwi(struct em_hw *hw) { - pci_write_config(((struct em_osdep *)hw->back)->dev, - PCIR_COMMAND, - (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); - return; + pci_write_config(((struct em_osdep *)hw->back)->dev, + PCIR_COMMAND, + (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); + 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; + pci_write_config(((struct em_osdep *)hw->back)->dev, + PCIR_COMMAND, + (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2); + return; } uint32_t @@ -2319,7 +2279,6 @@ em_io_write(struct em_hw *hw, uint32_t port, uint32_t value) return; } - /********************************************************************** * * Update the board statistics counters. @@ -2449,16 +2408,10 @@ em_print_hw_stats(struct adapter *adapter) 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, - adapter->no_tx_buffer_avail2); printf("em%d: Std Mbuf Failed = %ld\n",unit, 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); diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h index 370e89105f26..6d7afac6a6ba 100644 --- a/sys/dev/em/if_em.h +++ b/sys/dev/em/if_em.h @@ -75,38 +75,38 @@ POSSIBILITY OF SUCH DAMAGE. #include -/* Tunables -- Begin */ - -/* +/* Tunables */ + +/* * 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. - */ + * 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 + * 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 @@ -120,7 +120,20 @@ POSSIBILITY OF SUCH DAMAGE. * 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 +#define EM_TIDV 64 + +/* + * TxAbsIntDelay (82540, 82545, and 82546-based adapters only) + * Valid Range: 0-65535 (0=off) + * Default Value: 64 + * This value, in units of 1.024 microseconds, limits the delay in which a + * transmit interrupt is generated. Useful only if TxIntDelay is non-zero, + * this value ensures that an interrupt is generated after the initial + * packet is sent on the wire within the set amount of time. Proper tuning, + * along with TxIntDelay, may improve traffic throughput in specific + * network conditions. + */ +#define EM_TADV 64 /* * RxIntDelay @@ -135,13 +148,26 @@ POSSIBILITY OF SUCH DAMAGE. * descriptors. * * CAUTION: When setting RxIntDelay to a value other than 0, adapters - * may hang (stop transmitting) under certain network conditions. + * 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 +#define EM_RDTR 0 + +/* + * RxAbsIntDelay (82540, 82545, and 82546-based adapters only) + * Valid Range: 0-65535 (0=off) + * Default Value: 64 + * This value, in units of 1.024 microseconds, limits the delay in which a + * receive interrupt is generated. Useful only if RxIntDelay is non-zero, + * this value ensures that an interrupt is generated after the initial + * packet is received within the set amount of time. Proper tuning, + * along with RxIntDelay, may improve traffic throughput in specific network + * conditions. + */ +#define EM_RADV 64 /* @@ -198,6 +224,7 @@ POSSIBILITY OF SUCH DAMAGE. #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)) @@ -207,9 +234,11 @@ POSSIBILITY OF SUCH DAMAGE. #define IOCTL_CMD_TYPE u_long #define MAX_NUM_MULTICAST_ADDRESSES 128 #define PCI_ANY_ID (~0U) + #ifndef ETHER_ALIGN #define ETHER_ALIGN 2 #endif + #define QTAG_TYPE 0x8100 /* Defines for printing debug information */ @@ -255,21 +284,10 @@ typedef struct _em_vendor_info_t { } em_vendor_info_t; -struct em_tx_buffer { - STAILQ_ENTRY(em_tx_buffer) em_tx_entry; +struct em_buffer { struct mbuf *m_head; - struct em_tx_desc *used_tx_desc; }; -/* ****************************************************************************** - * This structure stores information about the 2k aligned receive buffer - * into which the E1000 DMA's frames. - * ******************************************************************************/ -struct em_rx_buffer { - STAILQ_ENTRY(em_rx_buffer) em_rx_entry; - struct mbuf *m_head; - u_int64_t buffer_addr; -}; typedef enum _XSUM_CONTEXT_T { OFFLOAD_NONE, @@ -302,31 +320,43 @@ struct adapter { u_int16_t link_speed; u_int16_t link_duplex; u_int32_t tx_int_delay; + u_int32_t tx_abs_int_delay; u_int32_t rx_int_delay; + u_int32_t rx_abs_int_delay; XSUM_CONTEXT_T active_checksum_context; - /* Transmit definitions */ - 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 *tx_desc_base; - volatile u_int16_t num_tx_desc_avail; - u_int16_t num_tx_desc; - u_int32_t txd_cmd; - struct em_tx_buffer *tx_buffer_area; - STAILQ_HEAD(__em_tx_buffer_free, em_tx_buffer) free_tx_buffer_list; - STAILQ_HEAD(__em_tx_buffer_used, em_tx_buffer) used_tx_buffer_list; + /* + * Transmit definitions + * + * We have an array of num_tx_desc descriptors (handled + * by the controller) paired with an array of tx_buffers + * (at tx_buffer_area). + * The index of the next available descriptor is next_avail_tx_desc. + * The number of remaining tx_desc is num_tx_desc_avail. + */ + struct em_tx_desc *tx_desc_base; + u_int32_t next_avail_tx_desc; + u_int32_t oldest_used_tx_desc; + volatile u_int16_t num_tx_desc_avail; + u_int16_t num_tx_desc; + u_int32_t txd_cmd; + struct em_buffer *tx_buffer_area; + + /* + * Receive definitions + * + * we have an array of num_rx_desc rx_desc (handled by the + * controller), and paired with an array of rx_buffers + * (at rx_buffer_area). + * The next pair to check on receive is at offset next_rx_desc_to_check + */ + struct em_rx_desc *rx_desc_base; + u_int32_t next_rx_desc_to_check; + u_int16_t num_rx_desc; + u_int32_t rx_buffer_len; + struct em_buffer *rx_buffer_area; - /* Receive definitions */ - struct em_rx_desc *first_rx_desc; - struct em_rx_desc *last_rx_desc; - struct em_rx_desc *next_rx_desc_to_check; - struct em_rx_desc *rx_desc_base; - u_int16_t num_rx_desc; - u_int32_t rx_buffer_len; - struct em_rx_buffer *rx_buffer_area; - STAILQ_HEAD(__em_rx_buffer, em_rx_buffer) rx_buffer_list; /* Jumbo frame */ struct mbuf *fmp; @@ -339,8 +369,6 @@ struct adapter { unsigned long mbuf_cluster_failed; 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 unsigned long no_pkts_avail; unsigned long clean_tx_interrupts;