if_em.c revision 103895
189857Sobrien/************************************************************************** 289857Sobrien 389857SobrienCopyright (c) 2001-2002, Intel Corporation 489857SobrienAll rights reserved. 589857Sobrien 689857SobrienRedistribution and use in source and binary forms, with or without 777298Sobrienmodification, are permitted provided that the following conditions are met: 877298Sobrien 977298Sobrien 1. Redistributions of source code must retain the above copyright notice, 1077298Sobrien this list of conditions and the following disclaimer. 1177298Sobrien 1277298Sobrien 2. Redistributions in binary form must reproduce the above copyright 1377298Sobrien notice, this list of conditions and the following disclaimer in the 1477298Sobrien documentation and/or other materials provided with the distribution. 1577298Sobrien 1677298Sobrien 3. Neither the name of the Intel Corporation nor the names of its 1777298Sobrien contributors may be used to endorse or promote products derived from 1877298Sobrien this software without specific prior written permission. 1977298Sobrien 2077298SobrienTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2177298SobrienAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2277298SobrienIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2377298SobrienARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2477298SobrienLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2577298SobrienCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2677298SobrienSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2777298SobrienINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2877298SobrienCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2977298SobrienARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3077298SobrienPOSSIBILITY OF SUCH DAMAGE. 3177298Sobrien 3277298Sobrien***************************************************************************/ 3377298Sobrien 3477298Sobrien/*$FreeBSD: head/sys/dev/em/if_em.c 103895 2002-09-24 16:27:59Z pdeuskar $*/ 3577298Sobrien 3677298Sobrien#include <dev/em/if_em.h> 3777298Sobrien 3877298Sobrien/********************************************************************* 3977298Sobrien * Set this to one to display debug statistics 4077298Sobrien *********************************************************************/ 4177298Sobrienint em_display_debug_stats = 0; 4277298Sobrien 4377298Sobrien/********************************************************************* 4477298Sobrien * Linked list of board private structures for all NICs found 4577298Sobrien *********************************************************************/ 4677298Sobrien 4777298Sobrienstruct adapter *em_adapter_list = NULL; 4877298Sobrien 4977298Sobrien 5077298Sobrien/********************************************************************* 5177298Sobrien * Driver version 5277298Sobrien *********************************************************************/ 5377298Sobrien 5477298Sobrienchar em_driver_version[] = "1.3.14"; 5577298Sobrien 5677298Sobrien 5777298Sobrien/********************************************************************* 5877298Sobrien * PCI Device ID Table 5977298Sobrien * 6077298Sobrien * Used by probe to select devices to load on 6177298Sobrien * Last field stores an index into em_strings 6277298Sobrien * Last entry must be all 0s 6377298Sobrien * 6477298Sobrien * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 6577298Sobrien *********************************************************************/ 6677298Sobrienstatic em_vendor_info_t em_vendor_info_array[] = 6777298Sobrien{ 6877298Sobrien /* Intel(R) PRO/1000 Network Connection */ 6977298Sobrien { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0}, 7077298Sobrien { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0}, 7177298Sobrien { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0}, 7277298Sobrien { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0}, 7377298Sobrien { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0}, 7477298Sobrien { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0}, 7577298Sobrien { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0}, 7677298Sobrien { 0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0}, 7777298Sobrien { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0}, 7877298Sobrien { 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0}, 7977298Sobrien { 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0}, 8077298Sobrien { 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0}, 8177298Sobrien /* required last entry */ 8277298Sobrien { 0, 0, 0, 0, 0} 8377298Sobrien}; 8477298Sobrien 8577298Sobrien 8677298Sobrien/********************************************************************* 8777298Sobrien * Table of branding strings for all supported NICs. 8877298Sobrien *********************************************************************/ 8977298Sobrien 9077298Sobrienstatic char *em_strings[] = { 9177298Sobrien "Intel(R) PRO/1000 Network Connection" 9277298Sobrien}; 9377298Sobrien 9477298Sobrien/********************************************************************* 9577298Sobrien * Function prototypes 9677298Sobrien *********************************************************************/ 9777298Sobrienstatic int em_probe(device_t); 9877298Sobrienstatic int em_attach(device_t); 9977298Sobrienstatic int em_detach(device_t); 10077298Sobrienstatic int em_shutdown(device_t); 10177298Sobrienstatic void em_intr(void *); 10277298Sobrienstatic void em_start(struct ifnet *); 10377298Sobrienstatic int em_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t); 10477298Sobrienstatic void em_watchdog(struct ifnet *); 10577298Sobrienstatic void em_init(void *); 10677298Sobrienstatic void em_stop(void *); 10777298Sobrienstatic void em_media_status(struct ifnet *, struct ifmediareq *); 10877298Sobrienstatic int em_media_change(struct ifnet *); 10977298Sobrienstatic void em_identify_hardware(struct adapter *); 11077298Sobrienstatic int em_allocate_pci_resources(struct adapter *); 11177298Sobrienstatic void em_free_pci_resources(struct adapter *); 11277298Sobrienstatic void em_local_timer(void *); 11377298Sobrienstatic int em_hardware_init(struct adapter *); 11477298Sobrienstatic void em_setup_interface(device_t, struct adapter *); 11577298Sobrienstatic int em_setup_transmit_structures(struct adapter *); 11677298Sobrienstatic void em_initialize_transmit_unit(struct adapter *); 11777298Sobrienstatic int em_setup_receive_structures(struct adapter *); 11877298Sobrienstatic void em_initialize_receive_unit(struct adapter *); 11977298Sobrienstatic void em_enable_intr(struct adapter *); 12077298Sobrienstatic void em_disable_intr(struct adapter *); 12177298Sobrienstatic void em_free_transmit_structures(struct adapter *); 12277298Sobrienstatic void em_free_receive_structures(struct adapter *); 12377298Sobrienstatic void em_update_stats_counters(struct adapter *); 12477298Sobrienstatic void em_clean_transmit_interrupts(struct adapter *); 12577298Sobrienstatic int em_allocate_receive_structures(struct adapter *); 12677298Sobrienstatic int em_allocate_transmit_structures(struct adapter *); 12777298Sobrienstatic void em_process_receive_interrupts(struct adapter *); 12877298Sobrienstatic void em_receive_checksum(struct adapter *, 12977298Sobrien struct em_rx_desc * rx_desc, 13077298Sobrien struct mbuf *); 13177298Sobrienstatic void em_transmit_checksum_setup(struct adapter *, 13277298Sobrien struct mbuf *, 13377298Sobrien struct em_tx_buffer *, 13477298Sobrien u_int32_t *, 13577298Sobrien u_int32_t *); 13677298Sobrienstatic void em_set_promisc(struct adapter *); 13777298Sobrienstatic void em_disable_promisc(struct adapter *); 13877298Sobrienstatic void em_set_multi(struct adapter *); 13977298Sobrienstatic void em_print_hw_stats(struct adapter *); 14077298Sobrienstatic void em_print_link_status(struct adapter *); 14177298Sobrienstatic int em_get_buf(struct em_rx_buffer *, struct adapter *, 14277298Sobrien struct mbuf *); 14377298Sobrienstatic void em_enable_vlans(struct adapter *adapter); 14477298Sobrien 14577298Sobrien/********************************************************************* 14677298Sobrien * FreeBSD Device Interface Entry Points 14777298Sobrien *********************************************************************/ 14877298Sobrien 14977298Sobrienstatic device_method_t em_methods[] = { 15077298Sobrien /* Device interface */ 15177298Sobrien DEVMETHOD(device_probe, em_probe), 15277298Sobrien DEVMETHOD(device_attach, em_attach), 15377298Sobrien DEVMETHOD(device_detach, em_detach), 15477298Sobrien DEVMETHOD(device_shutdown, em_shutdown), 15577298Sobrien {0, 0} 15677298Sobrien}; 15777298Sobrien 15877298Sobrienstatic driver_t em_driver = { 15977298Sobrien "em", em_methods, sizeof(struct adapter ), 16077298Sobrien}; 16177298Sobrien 16277298Sobrienstatic devclass_t em_devclass; 16377298SobrienDRIVER_MODULE(if_em, pci, em_driver, em_devclass, 0, 0); 16477298Sobrien 16577298Sobrien/********************************************************************* 16677298Sobrien * Device identification routine 16777298Sobrien * 16877298Sobrien * em_probe determines if the driver should be loaded on 16977298Sobrien * adapter based on PCI vendor/device id of the adapter. 17077298Sobrien * 17177298Sobrien * return 0 on success, positive on failure 17277298Sobrien *********************************************************************/ 17377298Sobrien 17477298Sobrienstatic int 17577298Sobrienem_probe(device_t dev) 17677298Sobrien{ 17777298Sobrien em_vendor_info_t *ent; 17877298Sobrien 17977298Sobrien u_int16_t pci_vendor_id = 0; 18077298Sobrien u_int16_t pci_device_id = 0; 18177298Sobrien u_int16_t pci_subvendor_id = 0; 18277298Sobrien u_int16_t pci_subdevice_id = 0; 18389857Sobrien char adapter_name[60]; 18489857Sobrien 18577298Sobrien INIT_DEBUGOUT("em_probe: begin"); 18677298Sobrien 18777298Sobrien pci_vendor_id = pci_get_vendor(dev); 18877298Sobrien if (pci_vendor_id != EM_VENDOR_ID) 18977298Sobrien return(ENXIO); 19077298Sobrien 19177298Sobrien pci_device_id = pci_get_device(dev); 19277298Sobrien pci_subvendor_id = pci_get_subvendor(dev); 19377298Sobrien pci_subdevice_id = pci_get_subdevice(dev); 19477298Sobrien 19577298Sobrien ent = em_vendor_info_array; 19677298Sobrien while (ent->vendor_id != 0) { 19777298Sobrien if ((pci_vendor_id == ent->vendor_id) && 19877298Sobrien (pci_device_id == ent->device_id) && 19977298Sobrien 20077298Sobrien ((pci_subvendor_id == ent->subvendor_id) || 20177298Sobrien (ent->subvendor_id == PCI_ANY_ID)) && 20277298Sobrien 20377298Sobrien ((pci_subdevice_id == ent->subdevice_id) || 20477298Sobrien (ent->subdevice_id == PCI_ANY_ID))) { 20577298Sobrien sprintf(adapter_name, "%s, Version - %s", 20677298Sobrien em_strings[ent->index], 20777298Sobrien em_driver_version); 20877298Sobrien device_set_desc_copy(dev, adapter_name); 20977298Sobrien return(0); 21077298Sobrien } 21177298Sobrien ent++; 21277298Sobrien } 21377298Sobrien 21477298Sobrien return(ENXIO); 21577298Sobrien} 21677298Sobrien 21777298Sobrien/********************************************************************* 21877298Sobrien * Device initialization routine 21977298Sobrien * 22077298Sobrien * The attach entry point is called when the driver is being loaded. 22177298Sobrien * This routine identifies the type of hardware, allocates all resources 22277298Sobrien * and initializes the hardware. 22377298Sobrien * 22477298Sobrien * return 0 on success, positive on failure 22577298Sobrien *********************************************************************/ 22677298Sobrien 22777298Sobrienstatic int 22877298Sobrienem_attach(device_t dev) 22977298Sobrien{ 23077298Sobrien struct adapter * adapter; 23177298Sobrien int s; 23277298Sobrien int tsize, rsize; 23377298Sobrien 23477298Sobrien INIT_DEBUGOUT("em_attach: begin"); 23577298Sobrien s = splimp(); 23677298Sobrien 23777298Sobrien /* Allocate, clear, and link in our adapter structure */ 23877298Sobrien if (!(adapter = device_get_softc(dev))) { 23977298Sobrien printf("em: adapter structure allocation failed\n"); 24077298Sobrien splx(s); 24177298Sobrien return(ENOMEM); 24277298Sobrien } 24377298Sobrien bzero(adapter, sizeof(struct adapter )); 24477298Sobrien adapter->dev = dev; 24577298Sobrien adapter->osdep.dev = dev; 24677298Sobrien adapter->unit = device_get_unit(dev); 24777298Sobrien 24877298Sobrien if (em_adapter_list != NULL) 24977298Sobrien em_adapter_list->prev = adapter; 25077298Sobrien adapter->next = em_adapter_list; 25177298Sobrien em_adapter_list = adapter; 25277298Sobrien 25377298Sobrien callout_handle_init(&adapter->timer_handle); 25477298Sobrien 25577298Sobrien /* Determine hardware revision */ 25677298Sobrien em_identify_hardware(adapter); 25777298Sobrien 25877298Sobrien /* Parameters (to be read from user) */ 25977298Sobrien adapter->num_tx_desc = MAX_TXD; 26077298Sobrien adapter->num_rx_desc = MAX_RXD; 26177298Sobrien adapter->tx_int_delay = TIDV; 26277298Sobrien adapter->rx_int_delay = RIDV; 26377298Sobrien adapter->hw.autoneg = DO_AUTO_NEG; 26477298Sobrien adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; 26577298Sobrien adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; 26677298Sobrien adapter->hw.tbi_compatibility_en = TRUE; 26777298Sobrien adapter->rx_buffer_len = EM_RXBUFFER_2048; 26877298Sobrien 26977298Sobrien adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH; 27077298Sobrien adapter->hw.fc_low_water = FC_DEFAULT_LO_THRESH; 27177298Sobrien adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER; 27277298Sobrien adapter->hw.fc_send_xon = TRUE; 27377298Sobrien adapter->hw.fc = em_fc_full; 27477298Sobrien 27577298Sobrien /* Set the max frame size assuming standard ethernet sized frames */ 27677298Sobrien adapter->hw.max_frame_size = 27777298Sobrien ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; 27877298Sobrien 27977298Sobrien adapter->hw.min_frame_size = 28077298Sobrien MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; 28177298Sobrien 28277298Sobrien /* This controls when hardware reports transmit completion status. */ 28377298Sobrien if ((EM_REPORT_TX_EARLY == 0) || (EM_REPORT_TX_EARLY == 1)) { 28477298Sobrien adapter->hw.report_tx_early = EM_REPORT_TX_EARLY; 28577298Sobrien } else { 28677298Sobrien if (adapter->hw.mac_type < em_82543) { 28777298Sobrien adapter->hw.report_tx_early = 0; 28877298Sobrien } else { 28977298Sobrien adapter->hw.report_tx_early = 1; 29077298Sobrien } 29177298Sobrien } 29277298Sobrien 29377298Sobrien if (em_allocate_pci_resources(adapter)) { 29477298Sobrien printf("em%d: Allocation of PCI resources failed\n", 29577298Sobrien adapter->unit); 29677298Sobrien em_free_pci_resources(adapter); 29777298Sobrien splx(s); 29877298Sobrien return(ENXIO); 29977298Sobrien } 30077298Sobrien 30177298Sobrien tsize = EM_ROUNDUP(adapter->num_tx_desc * 30277298Sobrien sizeof(struct em_tx_desc), 4096); 30377298Sobrien 30477298Sobrien /* Allocate Transmit Descriptor ring */ 30577298Sobrien if (!(adapter->tx_desc_base = (struct em_tx_desc *) 30677298Sobrien contigmalloc(tsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) { 30777298Sobrien printf("em%d: Unable to allocate TxDescriptor memory\n", 30877298Sobrien adapter->unit); 30977298Sobrien em_free_pci_resources(adapter); 31077298Sobrien splx(s); 31177298Sobrien return(ENOMEM); 31277298Sobrien } 31377298Sobrien 31477298Sobrien rsize = EM_ROUNDUP(adapter->num_rx_desc * 31577298Sobrien sizeof(struct em_rx_desc), 4096); 31677298Sobrien 31777298Sobrien /* Allocate Receive Descriptor ring */ 31877298Sobrien if (!(adapter->rx_desc_base = (struct em_rx_desc *) 31977298Sobrien contigmalloc(rsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) { 32077298Sobrien printf("em%d: Unable to allocate rx_desc memory\n", 32177298Sobrien adapter->unit); 32277298Sobrien em_free_pci_resources(adapter); 32377298Sobrien contigfree(adapter->tx_desc_base, tsize, M_DEVBUF); 32477298Sobrien splx(s); 32577298Sobrien return(ENOMEM); 32677298Sobrien } 32777298Sobrien 32877298Sobrien /* Initialize the hardware */ 32977298Sobrien if (em_hardware_init(adapter)) { 33077298Sobrien printf("em%d: Unable to initialize the hardware\n", 33177298Sobrien adapter->unit); 33277298Sobrien em_free_pci_resources(adapter); 33377298Sobrien contigfree(adapter->tx_desc_base, tsize, M_DEVBUF); 33477298Sobrien contigfree(adapter->rx_desc_base, rsize, M_DEVBUF); 33577298Sobrien splx(s); 33677298Sobrien return(EIO); 33777298Sobrien } 33877298Sobrien 33977298Sobrien /* Copy the permanent MAC address out of the EEPROM */ 34077298Sobrien if (em_read_mac_addr(&adapter->hw) < 0) { 34177298Sobrien printf("em%d: EEPROM read error while reading mac address\n", 34277298Sobrien adapter->unit); 34377298Sobrien return(EIO); 34477298Sobrien } 34577298Sobrien 34677298Sobrien memcpy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr, 34777298Sobrien ETH_LENGTH_OF_ADDRESS); 34877298Sobrien 34977298Sobrien /* Setup OS specific network interface */ 35077298Sobrien em_setup_interface(dev, adapter); 35177298Sobrien 35277298Sobrien /* Initialize statistics */ 35377298Sobrien em_clear_hw_cntrs(&adapter->hw); 35477298Sobrien em_update_stats_counters(adapter); 35577298Sobrien adapter->hw.get_link_status = 1; 35677298Sobrien em_check_for_link(&adapter->hw); 35777298Sobrien 35877298Sobrien /* Print the link status */ 35977298Sobrien if (adapter->link_active == 1) { 36077298Sobrien em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, 36177298Sobrien &adapter->link_duplex); 36277298Sobrien printf("em%d: Speed:%d Mbps Duplex:%s\n", 36377298Sobrien adapter->unit, 36477298Sobrien adapter->link_speed, 36577298Sobrien adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half"); 36677298Sobrien } else 36777298Sobrien printf("em%d: Speed:N/A Duplex:N/A\n", adapter->unit); 36877298Sobrien 36977298Sobrien 37077298Sobrien INIT_DEBUGOUT("em_attach: end"); 37177298Sobrien splx(s); 37277298Sobrien return(0); 37377298Sobrien} 37477298Sobrien 37577298Sobrien/********************************************************************* 37677298Sobrien * Device removal routine 37777298Sobrien * 37877298Sobrien * The detach entry point is called when the driver is being removed. 37977298Sobrien * This routine stops the adapter and deallocates all the resources 38077298Sobrien * that were allocated for driver operation. 38177298Sobrien * 38277298Sobrien * return 0 on success, positive on failure 38377298Sobrien *********************************************************************/ 38477298Sobrien 38577298Sobrienstatic int 38677298Sobrienem_detach(device_t dev) 38777298Sobrien{ 38889857Sobrien struct adapter * adapter = device_get_softc(dev); 38977298Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 39077298Sobrien int s; 39177298Sobrien int size; 39277298Sobrien 39377298Sobrien INIT_DEBUGOUT("em_detach: begin"); 39477298Sobrien s = splimp(); 39577298Sobrien 39677298Sobrien em_stop(adapter); 39777298Sobrien em_phy_hw_reset(&adapter->hw); 39877298Sobrien ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); 39977298Sobrien em_free_pci_resources(adapter); 40077298Sobrien 40177298Sobrien size = EM_ROUNDUP(adapter->num_tx_desc * 40277298Sobrien sizeof(struct em_tx_desc), 4096); 40377298Sobrien 40477298Sobrien /* Free Transmit Descriptor ring */ 40577298Sobrien if (adapter->tx_desc_base) { 40677298Sobrien contigfree(adapter->tx_desc_base, size, M_DEVBUF); 40777298Sobrien adapter->tx_desc_base = NULL; 40877298Sobrien } 40977298Sobrien 41077298Sobrien size = EM_ROUNDUP(adapter->num_rx_desc * 41177298Sobrien sizeof(struct em_rx_desc), 4096); 41277298Sobrien 41377298Sobrien /* Free Receive Descriptor ring */ 41477298Sobrien if (adapter->rx_desc_base) { 41577298Sobrien contigfree(adapter->rx_desc_base, size, M_DEVBUF); 41677298Sobrien adapter->rx_desc_base = NULL; 41777298Sobrien } 41877298Sobrien 41977298Sobrien /* Remove from the adapter list */ 42077298Sobrien if (em_adapter_list == adapter) 42177298Sobrien em_adapter_list = adapter->next; 42277298Sobrien if (adapter->next != NULL) 42377298Sobrien adapter->next->prev = adapter->prev; 42477298Sobrien if (adapter->prev != NULL) 42577298Sobrien adapter->prev->next = adapter->next; 42677298Sobrien 42777298Sobrien ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 42877298Sobrien ifp->if_timer = 0; 42977298Sobrien 43077298Sobrien splx(s); 43177298Sobrien return(0); 43277298Sobrien} 43377298Sobrien 43477298Sobrienstatic int 43577298Sobrienem_shutdown(device_t dev) 43677298Sobrien{ 43777298Sobrien struct adapter *adapter = device_get_softc(dev); 43877298Sobrien em_stop(adapter); 43977298Sobrien return(0); 44077298Sobrien} 44177298Sobrien 44277298Sobrien 44377298Sobrien/********************************************************************* 44477298Sobrien * Transmit entry point 44577298Sobrien * 44677298Sobrien * em_start is called by the stack to initiate a transmit. 44777298Sobrien * The driver will remain in this routine as long as there are 44877298Sobrien * packets to transmit and transmit resources are available. 44977298Sobrien * In case resources are not available stack is notified and 45077298Sobrien * the packet is requeued. 45177298Sobrien **********************************************************************/ 45277298Sobrien 45377298Sobrienstatic void 45477298Sobrienem_start(struct ifnet *ifp) 45577298Sobrien{ 45677298Sobrien int s; 45777298Sobrien struct mbuf *m_head, *mp; 45877298Sobrien vm_offset_t virtual_addr; 45977298Sobrien u_int32_t txd_upper; 46077298Sobrien u_int32_t txd_lower; 46177298Sobrien struct em_tx_buffer *tx_buffer; 46277298Sobrien struct em_tx_desc *current_tx_desc = NULL; 46377298Sobrien struct adapter * adapter = ifp->if_softc; 46477298Sobrien 46577298Sobrien if (!adapter->link_active) 46677298Sobrien return; 46777298Sobrien 46877298Sobrien s = splimp(); 46977298Sobrien while (ifp->if_snd.ifq_head != NULL) { 47077298Sobrien struct ifvlan *ifv = NULL; 47177298Sobrien 47277298Sobrien IF_DEQUEUE(&ifp->if_snd, m_head); 47377298Sobrien 47477298Sobrien if (m_head == NULL) break; 47577298Sobrien 47677298Sobrien if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) 47777298Sobrien em_clean_transmit_interrupts(adapter); 47877298Sobrien 47977298Sobrien if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) { 48077298Sobrien ifp->if_flags |= IFF_OACTIVE; 48177298Sobrien IF_PREPEND(&ifp->if_snd, m_head); 48277298Sobrien adapter->no_tx_desc_avail++; 48377298Sobrien break; 48477298Sobrien } 48577298Sobrien 48677298Sobrien tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); 48777298Sobrien if (!tx_buffer) { 48877298Sobrien adapter->no_tx_buffer_avail1++; 48977298Sobrien /* 49077298Sobrien * OK so we should not get here but I've seen it so let 49177298Sobrien * us try to clean up and then try to get a tx_buffer 49277298Sobrien * again and only break if we still don't get one. 49377298Sobrien */ 49477298Sobrien em_clean_transmit_interrupts(adapter); 49577298Sobrien tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list); 49677298Sobrien if (!tx_buffer) { 49777298Sobrien ifp->if_flags |= IFF_OACTIVE; 49877298Sobrien IF_PREPEND(&ifp->if_snd, m_head); 49977298Sobrien adapter->no_tx_buffer_avail2++; 50077298Sobrien break; 50177298Sobrien } 50277298Sobrien } 50377298Sobrien STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry); 50477298Sobrien 50577298Sobrien tx_buffer->num_tx_desc_used = 0; 50677298Sobrien tx_buffer->m_head = m_head; 50777298Sobrien 50877298Sobrien if (ifp->if_hwassist > 0) { 50977298Sobrien em_transmit_checksum_setup(adapter, m_head, tx_buffer, 51077298Sobrien &txd_upper, &txd_lower); 51177298Sobrien } else { 51277298Sobrien txd_upper = 0; 51377298Sobrien txd_lower = 0; 51477298Sobrien } 51577298Sobrien 51677298Sobrien /* Find out if we are in vlan mode */ 51777298Sobrien if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && 51877298Sobrien m_head->m_pkthdr.rcvif != NULL && 51977298Sobrien m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) 52077298Sobrien ifv = m_head->m_pkthdr.rcvif->if_softc; 52177298Sobrien 52277298Sobrien 52377298Sobrien for (mp = m_head; mp != NULL; mp = mp->m_next) { 52477298Sobrien if (mp->m_len == 0) 52577298Sobrien continue; 52677298Sobrien current_tx_desc = adapter->next_avail_tx_desc; 52777298Sobrien virtual_addr = mtod(mp, vm_offset_t); 52877298Sobrien current_tx_desc->buffer_addr = vtophys(virtual_addr); 52977298Sobrien 53077298Sobrien current_tx_desc->lower.data = (txd_lower | mp->m_len); 53177298Sobrien current_tx_desc->upper.data = (txd_upper); 53277298Sobrien 53377298Sobrien if (current_tx_desc == adapter->last_tx_desc) 53477298Sobrien adapter->next_avail_tx_desc = 53577298Sobrien adapter->first_tx_desc; 53677298Sobrien else 53777298Sobrien adapter->next_avail_tx_desc++; 53877298Sobrien 53977298Sobrien adapter->num_tx_desc_avail--; 54077298Sobrien tx_buffer->num_tx_desc_used++; 54177298Sobrien } 54277298Sobrien 54377298Sobrien /* Put this tx_buffer at the end in the "in use" list */ 54477298Sobrien STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer, 54577298Sobrien em_tx_entry); 54677298Sobrien 54777298Sobrien if (ifv != NULL) { 54877298Sobrien /* Tell hardware to add tag */ 54977298Sobrien current_tx_desc->lower.data |= E1000_TXD_CMD_VLE; 55077298Sobrien 55177298Sobrien /* Set the vlan id */ 55277298Sobrien current_tx_desc->upper.fields.special = ifv->ifv_tag; 55377298Sobrien } 55477298Sobrien 55577298Sobrien /* 55677298Sobrien * Last Descriptor of Packet needs End Of Packet (EOP), Report Status 55777298Sobrien * (RS) and append Ethernet CRC (IFCS) bits set. 55877298Sobrien */ 55977298Sobrien current_tx_desc->lower.data |= (adapter->txd_cmd | E1000_TXD_CMD_EOP); 56077298Sobrien 56177298Sobrien /* Send a copy of the frame to the BPF listener */ 56277298Sobrien if (ifp->if_bpf) 56377298Sobrien bpf_mtap(ifp, m_head); 56477298Sobrien 56577298Sobrien /* 56677298Sobrien * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 56777298Sobrien * that this frame is available to transmit. 56877298Sobrien */ 56977298Sobrien E1000_WRITE_REG(&adapter->hw, TDT, 57077298Sobrien (((uintptr_t) adapter->next_avail_tx_desc - 57177298Sobrien (uintptr_t) adapter->first_tx_desc) >> 4)); 57277298Sobrien } /* end of while loop */ 57377298Sobrien 57477298Sobrien splx(s); 57577298Sobrien 57677298Sobrien /* Set timeout in case chip has problems transmitting */ 57777298Sobrien ifp->if_timer = EM_TX_TIMEOUT; 57877298Sobrien 57977298Sobrien return; 58077298Sobrien} 58177298Sobrien 58277298Sobrien/********************************************************************* 58377298Sobrien * Ioctl entry point 58477298Sobrien * 58577298Sobrien * em_ioctl is called when the user wants to configure the 58677298Sobrien * interface. 58777298Sobrien * 58877298Sobrien * return 0 on success, positive on failure 58977298Sobrien **********************************************************************/ 59077298Sobrien 59177298Sobrienstatic int 59277298Sobrienem_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) 59377298Sobrien{ 59477298Sobrien int s, mask, error = 0; 59577298Sobrien struct ifreq *ifr = (struct ifreq *) data; 59677298Sobrien struct adapter * adapter = ifp->if_softc; 59777298Sobrien 59877298Sobrien s = splimp(); 59977298Sobrien switch (command) { 60077298Sobrien case SIOCSIFADDR: 60177298Sobrien case SIOCGIFADDR: 60277298Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)"); 60377298Sobrien ether_ioctl(ifp, command, data); 60477298Sobrien break; 60577298Sobrien case SIOCSIFMTU: 60677298Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)"); 60777298Sobrien if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN) { 60877298Sobrien error = EINVAL; 60977298Sobrien } else { 61077298Sobrien ifp->if_mtu = ifr->ifr_mtu; 61177298Sobrien adapter->hw.max_frame_size = 61277298Sobrien ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 61377298Sobrien em_init(adapter); 61477298Sobrien } 61577298Sobrien break; 61677298Sobrien case SIOCSIFFLAGS: 61777298Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); 61877298Sobrien if (ifp->if_flags & IFF_UP) { 61977298Sobrien if (ifp->if_flags & IFF_RUNNING && 62077298Sobrien ifp->if_flags & IFF_PROMISC) { 62177298Sobrien em_set_promisc(adapter); 62277298Sobrien } else if (ifp->if_flags & IFF_RUNNING && 62377298Sobrien !(ifp->if_flags & IFF_PROMISC)) { 62477298Sobrien em_disable_promisc(adapter); 62577298Sobrien } else 62677298Sobrien em_init(adapter); 62777298Sobrien } else { 62877298Sobrien if (ifp->if_flags & IFF_RUNNING) { 62977298Sobrien em_stop(adapter); 63077298Sobrien } 63177298Sobrien } 63277298Sobrien break; 63377298Sobrien case SIOCADDMULTI: 63477298Sobrien case SIOCDELMULTI: 63577298Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI"); 63677298Sobrien if (ifp->if_flags & IFF_RUNNING) { 63777298Sobrien em_disable_intr(adapter); 63877298Sobrien em_set_multi(adapter); 63977298Sobrien if (adapter->hw.mac_type == em_82542_rev2_0) 64077298Sobrien em_initialize_receive_unit(adapter); 64177298Sobrien em_enable_intr(adapter); 64277298Sobrien } 64377298Sobrien break; 64477298Sobrien case SIOCSIFMEDIA: 64577298Sobrien case SIOCGIFMEDIA: 64677298Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)"); 64777298Sobrien error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); 64877298Sobrien break; 64977298Sobrien case SIOCSIFCAP: 65077298Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)"); 65177298Sobrien mask = ifr->ifr_reqcap ^ ifp->if_capenable; 65277298Sobrien if (mask & IFCAP_HWCSUM) { 65377298Sobrien if (IFCAP_HWCSUM & ifp->if_capenable) 65477298Sobrien ifp->if_capenable &= ~IFCAP_HWCSUM; 65577298Sobrien else 65677298Sobrien ifp->if_capenable |= IFCAP_HWCSUM; 65777298Sobrien if (ifp->if_flags & IFF_RUNNING) 65877298Sobrien em_init(adapter); 65977298Sobrien } 66077298Sobrien break; 66177298Sobrien default: 66277298Sobrien IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%d)\n", (int)command); 66377298Sobrien error = EINVAL; 66477298Sobrien } 66577298Sobrien 66677298Sobrien splx(s); 66777298Sobrien return(error); 66877298Sobrien} 66977298Sobrien 67077298Sobrienstatic void 67177298Sobrienem_set_promisc(struct adapter * adapter) 67277298Sobrien{ 67377298Sobrien 67477298Sobrien u_int32_t reg_rctl; 67577298Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 67677298Sobrien 67777298Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 67877298Sobrien 67977298Sobrien if (ifp->if_flags & IFF_PROMISC) { 68077298Sobrien reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); 68177298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 68277298Sobrien } else if (ifp->if_flags & IFF_ALLMULTI) { 68377298Sobrien reg_rctl |= E1000_RCTL_MPE; 68477298Sobrien reg_rctl &= ~E1000_RCTL_UPE; 68577298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 68677298Sobrien } 68777298Sobrien 68877298Sobrien return; 68977298Sobrien} 69077298Sobrien 69177298Sobrienstatic void 69277298Sobrienem_disable_promisc(struct adapter * adapter) 69377298Sobrien{ 69477298Sobrien u_int32_t reg_rctl; 69577298Sobrien 69677298Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 69777298Sobrien 69877298Sobrien reg_rctl &= (~E1000_RCTL_UPE); 69977298Sobrien reg_rctl &= (~E1000_RCTL_MPE); 70077298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 70177298Sobrien 70277298Sobrien return; 70377298Sobrien} 70477298Sobrien 70577298Sobrien 70677298Sobrien/********************************************************************* 70777298Sobrien * Multicast Update 70877298Sobrien * 70977298Sobrien * This routine is called whenever multicast address list is updated. 71077298Sobrien * 71177298Sobrien **********************************************************************/ 71277298Sobrien 71377298Sobrienstatic void 71477298Sobrienem_set_multi(struct adapter * adapter) 71577298Sobrien{ 71677298Sobrien u_int32_t reg_rctl = 0; 71777298Sobrien u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; 71877298Sobrien u_int16_t pci_cmd_word; 71977298Sobrien struct ifmultiaddr *ifma; 72077298Sobrien int mcnt = 0; 72177298Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 72277298Sobrien 72377298Sobrien IOCTL_DEBUGOUT("em_set_multi: begin"); 72477298Sobrien 72577298Sobrien if (adapter->hw.mac_type == em_82542_rev2_0) { 72677298Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 72777298Sobrien if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { 72877298Sobrien pci_cmd_word = adapter->hw.pci_cmd_word & 72977298Sobrien ~CMD_MEM_WRT_INVALIDATE; 73077298Sobrien pci_write_config(adapter->dev, PCIR_COMMAND, pci_cmd_word, 2); 73177298Sobrien } 73277298Sobrien reg_rctl |= E1000_RCTL_RST; 73377298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 73477298Sobrien msec_delay(5); 73577298Sobrien } 73677298Sobrien 73777298Sobrien#if __FreeBSD_version < 500000 73877298Sobrien LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 73977298Sobrien#else 74077298Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 74177298Sobrien#endif 74277298Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 74377298Sobrien continue; 74477298Sobrien 74577298Sobrien bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 74677298Sobrien &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); 74777298Sobrien mcnt++; 74877298Sobrien } 74977298Sobrien 75077298Sobrien if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) { 75177298Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 75277298Sobrien reg_rctl |= E1000_RCTL_MPE; 75377298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 75477298Sobrien } else 75577298Sobrien em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0); 75677298Sobrien 75777298Sobrien if (adapter->hw.mac_type == em_82542_rev2_0) { 75877298Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 75977298Sobrien reg_rctl &= ~E1000_RCTL_RST; 76077298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 76177298Sobrien msec_delay(5); 76277298Sobrien if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { 76377298Sobrien pci_write_config(adapter->dev, PCIR_COMMAND, 76477298Sobrien adapter->hw.pci_cmd_word, 2); 76577298Sobrien } 76677298Sobrien } 76777298Sobrien 76877298Sobrien return; 76977298Sobrien} 77077298Sobrien 77177298Sobrien/********************************************************************* 77277298Sobrien * Watchdog entry point 77377298Sobrien * 77477298Sobrien * This routine is called whenever hardware quits transmitting. 77577298Sobrien * 77677298Sobrien **********************************************************************/ 77777298Sobrien 77877298Sobrienstatic void 77977298Sobrienem_watchdog(struct ifnet *ifp) 78077298Sobrien{ 78177298Sobrien struct adapter * adapter; 78277298Sobrien adapter = ifp->if_softc; 78377298Sobrien 78477298Sobrien /* If we are in this routine because of pause frames, then 78577298Sobrien * don't reset the hardware. 78677298Sobrien */ 78777298Sobrien if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) { 78877298Sobrien ifp->if_timer = EM_TX_TIMEOUT; 78977298Sobrien return; 79077298Sobrien } 79177298Sobrien 79277298Sobrien printf("em%d: watchdog timeout -- resetting\n", adapter->unit); 79377298Sobrien 79477298Sobrien ifp->if_flags &= ~IFF_RUNNING; 79577298Sobrien 79677298Sobrien em_stop(adapter); 79777298Sobrien em_init(adapter); 79877298Sobrien 79977298Sobrien ifp->if_oerrors++; 80077298Sobrien return; 80177298Sobrien} 80277298Sobrien 80377298Sobrien/********************************************************************* 80477298Sobrien * Timer routine 80577298Sobrien * 80677298Sobrien * This routine checks for link status and updates statistics. 80777298Sobrien * 80877298Sobrien **********************************************************************/ 80977298Sobrien 81077298Sobrienstatic void 81177298Sobrienem_local_timer(void *arg) 81277298Sobrien{ 81377298Sobrien int s; 81477298Sobrien struct ifnet *ifp; 81577298Sobrien struct adapter * adapter = arg; 81677298Sobrien ifp = &adapter->interface_data.ac_if; 81777298Sobrien 81877298Sobrien s = splimp(); 81977298Sobrien 82077298Sobrien em_check_for_link(&adapter->hw); 82177298Sobrien em_print_link_status(adapter); 82277298Sobrien em_update_stats_counters(adapter); 82377298Sobrien if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { 82477298Sobrien em_print_hw_stats(adapter); 82577298Sobrien } 82677298Sobrien adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); 82777298Sobrien 82877298Sobrien splx(s); 82977298Sobrien return; 83077298Sobrien} 83177298Sobrien 83277298Sobrienstatic void 83377298Sobrienem_print_link_status(struct adapter * adapter) 83477298Sobrien{ 83577298Sobrien if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { 83677298Sobrien if (adapter->link_active == 0) { 83777298Sobrien em_get_speed_and_duplex(&adapter->hw, 83877298Sobrien &adapter->link_speed, 83977298Sobrien &adapter->link_duplex); 84077298Sobrien printf("em%d: Link is up %d Mbps %s\n", 84177298Sobrien adapter->unit, 84277298Sobrien adapter->link_speed, 84377298Sobrien ((adapter->link_duplex == FULL_DUPLEX) ? 84477298Sobrien "Full Duplex" : "Half Duplex")); 84577298Sobrien adapter->link_active = 1; 84677298Sobrien } 84777298Sobrien } else { 84877298Sobrien if (adapter->link_active == 1) { 84977298Sobrien adapter->link_speed = 0; 85077298Sobrien adapter->link_duplex = 0; 85177298Sobrien printf("em%d: Link is Down\n", adapter->unit); 85277298Sobrien adapter->link_active = 0; 85377298Sobrien } 85477298Sobrien } 85577298Sobrien 85677298Sobrien return; 85777298Sobrien} 85877298Sobrien 85977298Sobrien/********************************************************************* 86077298Sobrien * Init entry point 86177298Sobrien * 86277298Sobrien * This routine is used in two ways. It is used by the stack as 86377298Sobrien * init entry point in network interface structure. It is also used 86477298Sobrien * by the driver as a hw/sw initialization routine to get to a 86577298Sobrien * consistent state. 86677298Sobrien * 86777298Sobrien * return 0 on success, positive on failure 86877298Sobrien **********************************************************************/ 86977298Sobrien 87077298Sobrienstatic void 87177298Sobrienem_init(void *arg) 87277298Sobrien{ 87377298Sobrien int s; 87477298Sobrien struct ifnet *ifp; 87577298Sobrien struct adapter * adapter = arg; 87677298Sobrien 87777298Sobrien INIT_DEBUGOUT("em_init: begin"); 87877298Sobrien 87977298Sobrien s = splimp(); 88077298Sobrien 88177298Sobrien em_stop(adapter); 88277298Sobrien 88377298Sobrien /* Initialize the hardware */ 88477298Sobrien if (em_hardware_init(adapter)) { 88577298Sobrien printf("em%d: Unable to initialize the hardware\n", 88677298Sobrien adapter->unit); 88777298Sobrien splx(s); 88877298Sobrien return; 88977298Sobrien } 89077298Sobrien 89177298Sobrien em_enable_vlans(adapter); 89277298Sobrien 89377298Sobrien /* Prepare transmit descriptors and buffers */ 89477298Sobrien if (em_setup_transmit_structures(adapter)) { 89577298Sobrien printf("em%d: Could not setup transmit structures\n", 89677298Sobrien adapter->unit); 89777298Sobrien em_stop(adapter); 89877298Sobrien splx(s); 89977298Sobrien return; 90077298Sobrien } 90177298Sobrien em_initialize_transmit_unit(adapter); 90277298Sobrien 90377298Sobrien /* Setup Multicast table */ 90477298Sobrien em_set_multi(adapter); 90577298Sobrien 90677298Sobrien /* Prepare receive descriptors and buffers */ 90777298Sobrien if (em_setup_receive_structures(adapter)) { 90877298Sobrien printf("em%d: Could not setup receive structures\n", 90977298Sobrien adapter->unit); 91077298Sobrien em_stop(adapter); 91177298Sobrien splx(s); 91277298Sobrien return; 91377298Sobrien } 91477298Sobrien em_initialize_receive_unit(adapter); 91577298Sobrien 91677298Sobrien ifp = &adapter->interface_data.ac_if; 91777298Sobrien ifp->if_flags |= IFF_RUNNING; 91877298Sobrien ifp->if_flags &= ~IFF_OACTIVE; 91977298Sobrien 92077298Sobrien if (adapter->hw.mac_type >= em_82543) { 92177298Sobrien if (ifp->if_capenable & IFCAP_TXCSUM) 92277298Sobrien ifp->if_hwassist = EM_CHECKSUM_FEATURES; 92377298Sobrien else 92477298Sobrien ifp->if_hwassist = 0; 92577298Sobrien } 92677298Sobrien 92777298Sobrien adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz); 92877298Sobrien em_clear_hw_cntrs(&adapter->hw); 92977298Sobrien em_enable_intr(adapter); 93077298Sobrien 93177298Sobrien splx(s); 93277298Sobrien return; 93377298Sobrien} 93477298Sobrien 93577298Sobrien 93677298Sobrien/********************************************************************* 93777298Sobrien * 93877298Sobrien * This routine disables all traffic on the adapter by issuing a 93977298Sobrien * global reset on the MAC and deallocates TX/RX buffers. 94077298Sobrien * 94177298Sobrien **********************************************************************/ 94277298Sobrien 94377298Sobrienstatic void 94477298Sobrienem_stop(void *arg) 94577298Sobrien{ 94677298Sobrien struct ifnet *ifp; 94777298Sobrien struct adapter * adapter = arg; 94877298Sobrien ifp = &adapter->interface_data.ac_if; 94977298Sobrien 95077298Sobrien INIT_DEBUGOUT("em_stop: begin\n"); 95177298Sobrien em_disable_intr(adapter); 95277298Sobrien em_reset_hw(&adapter->hw); 95377298Sobrien untimeout(em_local_timer, adapter, adapter->timer_handle); 95477298Sobrien em_free_transmit_structures(adapter); 95577298Sobrien em_free_receive_structures(adapter); 95677298Sobrien 95777298Sobrien 95877298Sobrien /* Tell the stack that the interface is no longer active */ 95977298Sobrien ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 96077298Sobrien 96177298Sobrien return; 96277298Sobrien} 96377298Sobrien 96477298Sobrien/********************************************************************* 96577298Sobrien * 96677298Sobrien * Interrupt Service routine 96777298Sobrien * 96877298Sobrien **********************************************************************/ 96977298Sobrien 97077298Sobrienstatic void 97177298Sobrienem_intr(void *arg) 97277298Sobrien{ 97377298Sobrien u_int32_t loop_cnt = EM_MAX_INTR; 97477298Sobrien u_int32_t reg_icr; 97577298Sobrien struct ifnet *ifp; 97677298Sobrien struct adapter *adapter = arg; 97777298Sobrien 97877298Sobrien ifp = &adapter->interface_data.ac_if; 97977298Sobrien 98077298Sobrien em_disable_intr(adapter); 98177298Sobrien while (loop_cnt > 0 && 98277298Sobrien (reg_icr = E1000_READ_REG(&adapter->hw, ICR)) != 0) { 98377298Sobrien 98477298Sobrien /* Link status change */ 98577298Sobrien if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { 98677298Sobrien untimeout(em_local_timer, adapter, 98777298Sobrien adapter->timer_handle); 98877298Sobrien adapter->hw.get_link_status = 1; 98977298Sobrien em_check_for_link(&adapter->hw); 99077298Sobrien em_print_link_status(adapter); 99177298Sobrien adapter->timer_handle = 99277298Sobrien timeout(em_local_timer, adapter, 2*hz); 99377298Sobrien } 99477298Sobrien 99577298Sobrien if (ifp->if_flags & IFF_RUNNING) { 99677298Sobrien em_process_receive_interrupts(adapter); 99777298Sobrien em_clean_transmit_interrupts(adapter); 99877298Sobrien } 99977298Sobrien loop_cnt--; 100077298Sobrien } 100177298Sobrien 100277298Sobrien em_enable_intr(adapter); 100377298Sobrien 100477298Sobrien if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) 100577298Sobrien em_start(ifp); 100677298Sobrien 100777298Sobrien return; 100877298Sobrien} 100977298Sobrien 101077298Sobrien 101177298Sobrien/********************************************************************* 101277298Sobrien * 101377298Sobrien * Media Ioctl callback 101477298Sobrien * 101577298Sobrien * This routine is called whenever the user queries the status of 101677298Sobrien * the interface using ifconfig. 101777298Sobrien * 101877298Sobrien **********************************************************************/ 101977298Sobrienstatic void 102077298Sobrienem_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 102177298Sobrien{ 102277298Sobrien struct adapter * adapter = ifp->if_softc; 102377298Sobrien 102477298Sobrien INIT_DEBUGOUT("em_media_status: begin"); 102577298Sobrien 102677298Sobrien em_check_for_link(&adapter->hw); 102777298Sobrien if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { 102877298Sobrien if (adapter->link_active == 0) { 102977298Sobrien em_get_speed_and_duplex(&adapter->hw, 103077298Sobrien &adapter->link_speed, 103177298Sobrien &adapter->link_duplex); 103277298Sobrien adapter->link_active = 1; 103377298Sobrien } 103477298Sobrien } else { 103577298Sobrien if (adapter->link_active == 1) { 103677298Sobrien adapter->link_speed = 0; 103777298Sobrien adapter->link_duplex = 0; 103877298Sobrien adapter->link_active = 0; 103977298Sobrien } 104077298Sobrien } 104177298Sobrien 104277298Sobrien ifmr->ifm_status = IFM_AVALID; 104377298Sobrien ifmr->ifm_active = IFM_ETHER; 104477298Sobrien 104577298Sobrien if (!adapter->link_active) 104677298Sobrien return; 104777298Sobrien 104877298Sobrien ifmr->ifm_status |= IFM_ACTIVE; 104977298Sobrien 105077298Sobrien if (adapter->hw.media_type == em_media_type_fiber) { 105177298Sobrien ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 105277298Sobrien } else { 105377298Sobrien switch (adapter->link_speed) { 105477298Sobrien case 10: 105577298Sobrien ifmr->ifm_active |= IFM_10_T; 105677298Sobrien break; 105777298Sobrien case 100: 105877298Sobrien ifmr->ifm_active |= IFM_100_TX; 105977298Sobrien break; 106077298Sobrien case 1000: 106177298Sobrien#if __FreeBSD_version < 500000 106277298Sobrien ifmr->ifm_active |= IFM_1000_TX; 106377298Sobrien#else 106477298Sobrien ifmr->ifm_active |= IFM_1000_T; 106577298Sobrien#endif 106677298Sobrien break; 106777298Sobrien } 106877298Sobrien if (adapter->link_duplex == FULL_DUPLEX) 106977298Sobrien ifmr->ifm_active |= IFM_FDX; 107077298Sobrien else 107177298Sobrien ifmr->ifm_active |= IFM_HDX; 107277298Sobrien } 107377298Sobrien return; 107477298Sobrien} 107577298Sobrien 107677298Sobrien/********************************************************************* 107777298Sobrien * 107877298Sobrien * Media Ioctl callback 107977298Sobrien * 108077298Sobrien * This routine is called when the user changes speed/duplex using 108177298Sobrien * media/mediopt option with ifconfig. 108277298Sobrien * 108389857Sobrien **********************************************************************/ 108477298Sobrienstatic int 108577298Sobrienem_media_change(struct ifnet *ifp) 108689857Sobrien{ 108777298Sobrien struct adapter * adapter = ifp->if_softc; 108877298Sobrien struct ifmedia *ifm = &adapter->media; 108977298Sobrien 109077298Sobrien INIT_DEBUGOUT("em_media_change: begin"); 109177298Sobrien 109277298Sobrien if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 109377298Sobrien return(EINVAL); 109477298Sobrien 109577298Sobrien switch (IFM_SUBTYPE(ifm->ifm_media)) { 109677298Sobrien case IFM_AUTO: 109777298Sobrien adapter->hw.autoneg = DO_AUTO_NEG; 109877298Sobrien adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; 109977298Sobrien break; 110077298Sobrien case IFM_1000_SX: 110177298Sobrien#if __FreeBSD_version < 500000 110277298Sobrien case IFM_1000_TX: 110377298Sobrien#else 110477298Sobrien case IFM_1000_T: 110577298Sobrien#endif 110677298Sobrien adapter->hw.autoneg = DO_AUTO_NEG; 110777298Sobrien adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; 110889857Sobrien break; 110977298Sobrien case IFM_100_TX: 111077298Sobrien adapter->hw.autoneg = FALSE; 111177298Sobrien adapter->hw.autoneg_advertised = 0; 111277298Sobrien if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 111377298Sobrien adapter->hw.forced_speed_duplex = em_100_full; 111477298Sobrien else 111577298Sobrien adapter->hw.forced_speed_duplex = em_100_half; 111677298Sobrien break; 111777298Sobrien case IFM_10_T: 111877298Sobrien adapter->hw.autoneg = FALSE; 111977298Sobrien adapter->hw.autoneg_advertised = 0; 112077298Sobrien if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 112177298Sobrien adapter->hw.forced_speed_duplex = em_10_full; 112277298Sobrien else 112377298Sobrien adapter->hw.forced_speed_duplex = em_10_half; 112477298Sobrien break; 112577298Sobrien default: 112677298Sobrien printf("em%d: Unsupported media type\n", adapter->unit); 112777298Sobrien } 112877298Sobrien 112977298Sobrien em_init(adapter); 113077298Sobrien 113177298Sobrien return(0); 113277298Sobrien} 113377298Sobrien/* Section end: Other registered entry points */ 113477298Sobrien 113577298Sobrien 113677298Sobrien/********************************************************************* 113777298Sobrien * 113877298Sobrien * Determine hardware revision. 113977298Sobrien * 114077298Sobrien **********************************************************************/ 114177298Sobrienstatic void 114277298Sobrienem_identify_hardware(struct adapter * adapter) 114377298Sobrien{ 114477298Sobrien device_t dev = adapter->dev; 114577298Sobrien 114677298Sobrien /* Make sure our PCI config space has the necessary stuff set */ 114777298Sobrien adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 114877298Sobrien if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) && 114977298Sobrien (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) { 115077298Sobrien printf("em%d: Memory Access and/or Bus Master bits were not set!\n", 115177298Sobrien adapter->unit); 115277298Sobrien adapter->hw.pci_cmd_word |= 115377298Sobrien (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 115477298Sobrien pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2); 115577298Sobrien } 115677298Sobrien 115777298Sobrien /* Save off the information about this board */ 115877298Sobrien adapter->hw.vendor_id = pci_get_vendor(dev); 115977298Sobrien adapter->hw.device_id = pci_get_device(dev); 116077298Sobrien adapter->hw.revision_id = pci_read_config(dev, PCIR_REVID, 1); 116177298Sobrien adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2); 116277298Sobrien adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2); 116377298Sobrien 116477298Sobrien 116577298Sobrien /* Set MacType, etc. based on this PCI info */ 116677298Sobrien switch (adapter->hw.device_id) { 116777298Sobrien case E1000_DEV_ID_82542: 116877298Sobrien adapter->hw.mac_type = (adapter->hw.revision_id == 3) ? 116977298Sobrien em_82542_rev2_1 : em_82542_rev2_0; 117077298Sobrien break; 117177298Sobrien case E1000_DEV_ID_82543GC_FIBER: 117277298Sobrien case E1000_DEV_ID_82543GC_COPPER: 117377298Sobrien adapter->hw.mac_type = em_82543; 117477298Sobrien break; 117577298Sobrien case E1000_DEV_ID_82544EI_FIBER: 117677298Sobrien case E1000_DEV_ID_82544EI_COPPER: 117777298Sobrien case E1000_DEV_ID_82544GC_COPPER: 117877298Sobrien case E1000_DEV_ID_82544GC_LOM: 117977298Sobrien adapter->hw.mac_type = em_82544; 118077298Sobrien break; 118177298Sobrien case E1000_DEV_ID_82540EM: 118277298Sobrien adapter->hw.mac_type = em_82540; 118377298Sobrien break; 118477298Sobrien case E1000_DEV_ID_82545EM_FIBER: 118577298Sobrien case E1000_DEV_ID_82545EM_COPPER: 118677298Sobrien adapter->hw.mac_type = em_82545; 118777298Sobrien break; 118877298Sobrien case E1000_DEV_ID_82546EB_FIBER: 118977298Sobrien case E1000_DEV_ID_82546EB_COPPER: 119077298Sobrien adapter->hw.mac_type = em_82546; 119177298Sobrien break; 119277298Sobrien default: 119377298Sobrien INIT_DEBUGOUT1("Unknown device id 0x%x", adapter->hw.device_id); 119477298Sobrien } 119577298Sobrien return; 119677298Sobrien} 119777298Sobrien 119877298Sobrienstatic int 119977298Sobrienem_allocate_pci_resources(struct adapter * adapter) 120077298Sobrien{ 120177298Sobrien int i, val, rid; 120277298Sobrien device_t dev = adapter->dev; 120377298Sobrien 120477298Sobrien rid = EM_MMBA; 120577298Sobrien adapter->res_memory = bus_alloc_resource(dev, SYS_RES_MEMORY, 120677298Sobrien &rid, 0, ~0, 1, 120777298Sobrien RF_ACTIVE); 120877298Sobrien if (!(adapter->res_memory)) { 120977298Sobrien printf("em%d: Unable to allocate bus resource: memory\n", 121077298Sobrien adapter->unit); 121177298Sobrien return(ENXIO); 121277298Sobrien } 121377298Sobrien adapter->osdep.mem_bus_space_tag = 121477298Sobrien rman_get_bustag(adapter->res_memory); 121577298Sobrien adapter->osdep.mem_bus_space_handle = 121677298Sobrien rman_get_bushandle(adapter->res_memory); 121777298Sobrien adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle; 121877298Sobrien 121977298Sobrien 122077298Sobrien if (adapter->hw.mac_type > em_82543) { 122177298Sobrien /* Figure our where our IO BAR is ? */ 122277298Sobrien rid = EM_MMBA; 122377298Sobrien for (i = 0; i < 5; i++) { 122477298Sobrien val = pci_read_config(dev, rid, 4); 122577298Sobrien if (val & 0x00000001) { 122677298Sobrien adapter->io_rid = rid; 122777298Sobrien break; 122877298Sobrien } 122977298Sobrien rid += 4; 123077298Sobrien } 123177298Sobrien 123277298Sobrien adapter->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 123377298Sobrien &adapter->io_rid, 0, ~0, 1, 123477298Sobrien RF_ACTIVE); 123577298Sobrien if (!(adapter->res_ioport)) { 123677298Sobrien printf("em%d: Unable to allocate bus resource: ioport\n", 123777298Sobrien adapter->unit); 123877298Sobrien return(ENXIO); 123977298Sobrien } 124077298Sobrien 124177298Sobrien adapter->hw.io_base = 124277298Sobrien rman_get_start(adapter->res_ioport); 124377298Sobrien } 124477298Sobrien 124577298Sobrien rid = 0x0; 124677298Sobrien adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ, 124777298Sobrien &rid, 0, ~0, 1, 124877298Sobrien RF_SHAREABLE | RF_ACTIVE); 124977298Sobrien if (!(adapter->res_interrupt)) { 125077298Sobrien printf("em%d: Unable to allocate bus resource: interrupt\n", 125177298Sobrien adapter->unit); 125277298Sobrien return(ENXIO); 125377298Sobrien } 125477298Sobrien if (bus_setup_intr(dev, adapter->res_interrupt, INTR_TYPE_NET, 125577298Sobrien (void (*)(void *)) em_intr, adapter, 125677298Sobrien &adapter->int_handler_tag)) { 125777298Sobrien printf("em%d: Error registering interrupt handler!\n", 125877298Sobrien adapter->unit); 125977298Sobrien return(ENXIO); 126077298Sobrien } 126177298Sobrien 126277298Sobrien adapter->hw.back = &adapter->osdep; 126377298Sobrien 126477298Sobrien return(0); 126577298Sobrien} 126677298Sobrien 126777298Sobrienstatic void 126877298Sobrienem_free_pci_resources(struct adapter * adapter) 126977298Sobrien{ 127077298Sobrien device_t dev = adapter->dev; 127177298Sobrien 127277298Sobrien if (adapter->res_interrupt != NULL) { 127377298Sobrien bus_teardown_intr(dev, adapter->res_interrupt, 127477298Sobrien adapter->int_handler_tag); 127577298Sobrien bus_release_resource(dev, SYS_RES_IRQ, 0, 127677298Sobrien adapter->res_interrupt); 127777298Sobrien } 127877298Sobrien if (adapter->res_memory != NULL) { 127977298Sobrien bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA, 128077298Sobrien adapter->res_memory); 128177298Sobrien } 128277298Sobrien 128377298Sobrien if (adapter->res_ioport != NULL) { 128477298Sobrien bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid, 128577298Sobrien adapter->res_ioport); 128677298Sobrien } 128777298Sobrien return; 128877298Sobrien} 128977298Sobrien 129077298Sobrien/********************************************************************* 129177298Sobrien * 129277298Sobrien * Initialize the hardware to a configuration as specified by the 129377298Sobrien * adapter structure. The controller is reset, the EEPROM is 129477298Sobrien * verified, the MAC address is set, then the shared initialization 129577298Sobrien * routines are called. 129677298Sobrien * 129777298Sobrien **********************************************************************/ 129877298Sobrienstatic int 129977298Sobrienem_hardware_init(struct adapter * adapter) 130077298Sobrien{ 130177298Sobrien /* Issue a global reset */ 130277298Sobrien em_reset_hw(&adapter->hw); 130377298Sobrien 130477298Sobrien /* Make sure we have a good EEPROM before we read from it */ 130577298Sobrien if (em_validate_eeprom_checksum(&adapter->hw) < 0) { 130677298Sobrien printf("em%d: The EEPROM Checksum Is Not Valid\n", 130777298Sobrien adapter->unit); 130877298Sobrien return(EIO); 130977298Sobrien } 131077298Sobrien 131177298Sobrien if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) { 131277298Sobrien printf("em%d: EEPROM read error while reading part number\n", 131377298Sobrien adapter->unit); 131477298Sobrien return(EIO); 131577298Sobrien } 131677298Sobrien 131777298Sobrien if (em_init_hw(&adapter->hw) < 0) { 131877298Sobrien printf("em%d: Hardware Initialization Failed", 131977298Sobrien adapter->unit); 132077298Sobrien return(EIO); 132177298Sobrien } 132277298Sobrien 132377298Sobrien em_check_for_link(&adapter->hw); 132477298Sobrien if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) 132577298Sobrien adapter->link_active = 1; 132677298Sobrien else 132777298Sobrien adapter->link_active = 0; 132877298Sobrien 132977298Sobrien if (adapter->link_active) { 133077298Sobrien em_get_speed_and_duplex(&adapter->hw, 133177298Sobrien &adapter->link_speed, 133277298Sobrien &adapter->link_duplex); 133377298Sobrien } else { 133477298Sobrien adapter->link_speed = 0; 133577298Sobrien adapter->link_duplex = 0; 133677298Sobrien } 133777298Sobrien 133877298Sobrien return(0); 133977298Sobrien} 134077298Sobrien 134177298Sobrien/********************************************************************* 134277298Sobrien * 134377298Sobrien * Setup networking device structure and register an interface. 134477298Sobrien * 134577298Sobrien **********************************************************************/ 134677298Sobrienstatic void 134777298Sobrienem_setup_interface(device_t dev, struct adapter * adapter) 134877298Sobrien{ 134977298Sobrien struct ifnet *ifp; 135077298Sobrien INIT_DEBUGOUT("em_setup_interface: begin"); 135177298Sobrien 135277298Sobrien ifp = &adapter->interface_data.ac_if; 135377298Sobrien ifp->if_unit = adapter->unit; 135477298Sobrien ifp->if_name = "em"; 135577298Sobrien ifp->if_mtu = ETHERMTU; 135677298Sobrien ifp->if_output = ether_output; 135777298Sobrien ifp->if_baudrate = 1000000000; 135877298Sobrien ifp->if_init = em_init; 135977298Sobrien ifp->if_softc = adapter; 136077298Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 136177298Sobrien ifp->if_ioctl = em_ioctl; 136277298Sobrien ifp->if_start = em_start; 136377298Sobrien ifp->if_watchdog = em_watchdog; 136477298Sobrien ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1; 136577298Sobrien ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 136677298Sobrien 136777298Sobrien if (adapter->hw.mac_type >= em_82543) { 136877298Sobrien ifp->if_capabilities = IFCAP_HWCSUM; 136977298Sobrien ifp->if_capenable = ifp->if_capabilities; 137077298Sobrien } 137177298Sobrien 137277298Sobrien /* 137377298Sobrien * Specify the media types supported by this adapter and register 137477298Sobrien * callbacks to update media and link information 137577298Sobrien */ 137677298Sobrien ifmedia_init(&adapter->media, IFM_IMASK, em_media_change, 137777298Sobrien em_media_status); 137877298Sobrien if (adapter->hw.media_type == em_media_type_fiber) { 137977298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX, 138077298Sobrien 0, NULL); 138177298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 138277298Sobrien 0, NULL); 138377298Sobrien } else { 138477298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL); 138577298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX, 138677298Sobrien 0, NULL); 138777298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 138877298Sobrien 0, NULL); 138977298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 139077298Sobrien 0, NULL); 139177298Sobrien#if __FreeBSD_version < 500000 139277298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX, 139377298Sobrien 0, NULL); 139477298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL); 139577298Sobrien#else 139677298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 139777298Sobrien 0, NULL); 139877298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); 139977298Sobrien#endif 140077298Sobrien } 140177298Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 140277298Sobrien ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 140377298Sobrien 140477298Sobrien return; 140577298Sobrien} 140677298Sobrien 140777298Sobrien 140877298Sobrien/********************************************************************* 140977298Sobrien * 141077298Sobrien * Allocate memory for tx_buffer structures. The tx_buffer stores all 141177298Sobrien * the information needed to transmit a packet on the wire. 141277298Sobrien * 141377298Sobrien **********************************************************************/ 141477298Sobrienstatic int 141577298Sobrienem_allocate_transmit_structures(struct adapter * adapter) 141677298Sobrien{ 141777298Sobrien if (!(adapter->tx_buffer_area = 141877298Sobrien (struct em_tx_buffer *) malloc(sizeof(struct em_tx_buffer) * 141977298Sobrien adapter->num_tx_desc, M_DEVBUF, 142077298Sobrien M_NOWAIT))) { 142177298Sobrien printf("em%d: Unable to allocate tx_buffer memory\n", 142277298Sobrien adapter->unit); 142377298Sobrien return ENOMEM; 142477298Sobrien } 142577298Sobrien 142677298Sobrien bzero(adapter->tx_buffer_area, 142777298Sobrien sizeof(struct em_tx_buffer) * adapter->num_tx_desc); 142877298Sobrien 142977298Sobrien return 0; 143077298Sobrien} 143177298Sobrien 143277298Sobrien/********************************************************************* 143377298Sobrien * 143477298Sobrien * Allocate and initialize transmit structures. 143577298Sobrien * 143677298Sobrien **********************************************************************/ 143777298Sobrienstatic int 143877298Sobrienem_setup_transmit_structures(struct adapter * adapter) 143977298Sobrien{ 144077298Sobrien struct em_tx_buffer *tx_buffer; 144177298Sobrien int i; 144277298Sobrien 144377298Sobrien if (em_allocate_transmit_structures(adapter)) 144477298Sobrien return ENOMEM; 144577298Sobrien 144677298Sobrien adapter->first_tx_desc = adapter->tx_desc_base; 144777298Sobrien adapter->last_tx_desc = 144877298Sobrien adapter->first_tx_desc + (adapter->num_tx_desc - 1); 144977298Sobrien 145077298Sobrien 145177298Sobrien STAILQ_INIT(&adapter->free_tx_buffer_list); 145277298Sobrien STAILQ_INIT(&adapter->used_tx_buffer_list); 145377298Sobrien 145477298Sobrien tx_buffer = adapter->tx_buffer_area; 145577298Sobrien 145677298Sobrien /* Setup the linked list of the tx_buffer's */ 145777298Sobrien for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { 145877298Sobrien bzero((void *) tx_buffer, sizeof(struct em_tx_buffer)); 145977298Sobrien STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list, 146077298Sobrien tx_buffer, em_tx_entry); 146177298Sobrien } 146277298Sobrien 146377298Sobrien bzero((void *) adapter->first_tx_desc, 146477298Sobrien (sizeof(struct em_tx_desc)) * adapter->num_tx_desc); 146577298Sobrien 146677298Sobrien /* Setup TX descriptor pointers */ 146777298Sobrien adapter->next_avail_tx_desc = adapter->first_tx_desc; 146877298Sobrien adapter->oldest_used_tx_desc = adapter->first_tx_desc; 146977298Sobrien 147077298Sobrien /* Set number of descriptors available */ 147177298Sobrien adapter->num_tx_desc_avail = adapter->num_tx_desc; 147277298Sobrien 147377298Sobrien /* Set checksum context */ 147477298Sobrien adapter->active_checksum_context = OFFLOAD_NONE; 147577298Sobrien 147677298Sobrien return 0; 147777298Sobrien} 147877298Sobrien 147977298Sobrien/********************************************************************* 148077298Sobrien * 148177298Sobrien * Enable transmit unit. 148277298Sobrien * 148377298Sobrien **********************************************************************/ 148477298Sobrienstatic void 148577298Sobrienem_initialize_transmit_unit(struct adapter * adapter) 148677298Sobrien{ 148777298Sobrien u_int32_t reg_tctl; 148877298Sobrien u_int32_t reg_tipg = 0; 148977298Sobrien 149077298Sobrien /* Setup the Base and Length of the Tx Descriptor Ring */ 149177298Sobrien E1000_WRITE_REG(&adapter->hw, TDBAL, 149277298Sobrien vtophys((vm_offset_t) adapter->tx_desc_base)); 149377298Sobrien E1000_WRITE_REG(&adapter->hw, TDBAH, 0); 149477298Sobrien E1000_WRITE_REG(&adapter->hw, TDLEN, 149577298Sobrien adapter->num_tx_desc * 149677298Sobrien sizeof(struct em_tx_desc)); 149777298Sobrien 149877298Sobrien /* Setup the HW Tx Head and Tail descriptor pointers */ 149977298Sobrien E1000_WRITE_REG(&adapter->hw, TDH, 0); 150077298Sobrien E1000_WRITE_REG(&adapter->hw, TDT, 0); 150177298Sobrien 150277298Sobrien 150377298Sobrien HW_DEBUGOUT2("Base = %x, Length = %x\n", 150477298Sobrien E1000_READ_REG(&adapter->hw, TDBAL), 150577298Sobrien E1000_READ_REG(&adapter->hw, TDLEN)); 150677298Sobrien 150777298Sobrien 150877298Sobrien /* Set the default values for the Tx Inter Packet Gap timer */ 150977298Sobrien switch (adapter->hw.mac_type) { 151077298Sobrien case em_82543: 151177298Sobrien case em_82544: 151277298Sobrien case em_82540: 151377298Sobrien case em_82545: 151477298Sobrien case em_82546: 151577298Sobrien if (adapter->hw.media_type == em_media_type_fiber) 151677298Sobrien reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER; 151777298Sobrien else 151877298Sobrien reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER; 151977298Sobrien reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; 152077298Sobrien reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; 152177298Sobrien break; 152277298Sobrien case em_82542_rev2_0: 152377298Sobrien case em_82542_rev2_1: 152477298Sobrien reg_tipg = DEFAULT_82542_TIPG_IPGT; 152577298Sobrien reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; 152677298Sobrien reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; 152777298Sobrien break; 152877298Sobrien default: 152977298Sobrien printf("em%d: Invalid mac type detected\n", adapter->unit); 153077298Sobrien } 153177298Sobrien E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg); 153277298Sobrien E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); 153377298Sobrien 153477298Sobrien /* Program the Transmit Control Register */ 153577298Sobrien reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | 153677298Sobrien (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); 153777298Sobrien if (adapter->link_duplex == 1) { 153877298Sobrien reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; 153977298Sobrien } else { 154077298Sobrien reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; 154177298Sobrien } 154277298Sobrien E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl); 154377298Sobrien 154477298Sobrien /* Setup Transmit Descriptor Settings for this adapter */ 154577298Sobrien adapter->txd_cmd = E1000_TXD_CMD_IFCS; 154677298Sobrien 154777298Sobrien if (adapter->tx_int_delay > 0) 154877298Sobrien adapter->txd_cmd |= E1000_TXD_CMD_IDE; 154977298Sobrien 155077298Sobrien if (adapter->hw.report_tx_early == 1) 155177298Sobrien adapter->txd_cmd |= E1000_TXD_CMD_RS; 155277298Sobrien else 155377298Sobrien adapter->txd_cmd |= E1000_TXD_CMD_RPS; 155477298Sobrien 155577298Sobrien return; 155677298Sobrien} 155777298Sobrien 155877298Sobrien/********************************************************************* 155977298Sobrien * 156077298Sobrien * Free all transmit related data structures. 156177298Sobrien * 156277298Sobrien **********************************************************************/ 156377298Sobrienstatic void 156477298Sobrienem_free_transmit_structures(struct adapter * adapter) 156577298Sobrien{ 156677298Sobrien struct em_tx_buffer *tx_buffer; 156777298Sobrien int i; 156877298Sobrien 156977298Sobrien INIT_DEBUGOUT("free_transmit_structures: begin"); 157077298Sobrien 157177298Sobrien if (adapter->tx_buffer_area != NULL) { 157277298Sobrien tx_buffer = adapter->tx_buffer_area; 157377298Sobrien for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { 157477298Sobrien if (tx_buffer->m_head != NULL) 157577298Sobrien m_freem(tx_buffer->m_head); 157677298Sobrien tx_buffer->m_head = NULL; 157777298Sobrien } 157877298Sobrien } 157977298Sobrien if (adapter->tx_buffer_area != NULL) { 158077298Sobrien free(adapter->tx_buffer_area, M_DEVBUF); 158177298Sobrien adapter->tx_buffer_area = NULL; 158277298Sobrien } 158377298Sobrien return; 158477298Sobrien} 158577298Sobrien 158677298Sobrien/********************************************************************* 158777298Sobrien * 158877298Sobrien * The offload context needs to be set when we transfer the first 158977298Sobrien * packet of a particular protocol (TCP/UDP). We change the 159077298Sobrien * context only if the protocol type changes. 159177298Sobrien * 159277298Sobrien **********************************************************************/ 159377298Sobrienstatic void 159477298Sobrienem_transmit_checksum_setup(struct adapter * adapter, 159577298Sobrien struct mbuf *mp, 159677298Sobrien struct em_tx_buffer *tx_buffer, 159777298Sobrien u_int32_t *txd_upper, 159877298Sobrien u_int32_t *txd_lower) 159977298Sobrien{ 160077298Sobrien struct em_context_desc *TXD; 160177298Sobrien struct em_tx_desc * current_tx_desc; 160277298Sobrien 160377298Sobrien if (mp->m_pkthdr.csum_flags) { 160477298Sobrien 160577298Sobrien if (mp->m_pkthdr.csum_flags & CSUM_TCP) { 160677298Sobrien *txd_upper = E1000_TXD_POPTS_TXSM << 8; 160777298Sobrien *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; 160877298Sobrien if (adapter->active_checksum_context == OFFLOAD_TCP_IP) 160977298Sobrien return; 161077298Sobrien else 161177298Sobrien adapter->active_checksum_context = OFFLOAD_TCP_IP; 161277298Sobrien 161377298Sobrien } else if (mp->m_pkthdr.csum_flags & CSUM_UDP) { 161477298Sobrien *txd_upper = E1000_TXD_POPTS_TXSM << 8; 161577298Sobrien *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; 161677298Sobrien if (adapter->active_checksum_context == OFFLOAD_UDP_IP) 161777298Sobrien return; 161877298Sobrien else 161977298Sobrien adapter->active_checksum_context = OFFLOAD_UDP_IP; 162077298Sobrien } else { 162177298Sobrien *txd_upper = 0; 162277298Sobrien *txd_lower = 0; 162377298Sobrien return; 162477298Sobrien } 162577298Sobrien } else { 162677298Sobrien *txd_upper = 0; 162777298Sobrien *txd_lower = 0; 162877298Sobrien return; 162977298Sobrien } 163077298Sobrien 163177298Sobrien /* If we reach this point, the checksum offload context 163277298Sobrien * needs to be reset. 163377298Sobrien */ 163477298Sobrien current_tx_desc = adapter->next_avail_tx_desc; 163577298Sobrien TXD = (struct em_context_desc *)current_tx_desc; 163677298Sobrien 163777298Sobrien TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN; 163877298Sobrien TXD->lower_setup.ip_fields.ipcso = 163977298Sobrien ETHER_HDR_LEN + offsetof(struct ip, ip_sum); 164077298Sobrien TXD->lower_setup.ip_fields.ipcse = 164177298Sobrien ETHER_HDR_LEN + sizeof(struct ip) - 1; 164277298Sobrien 164377298Sobrien TXD->upper_setup.tcp_fields.tucss = 164477298Sobrien ETHER_HDR_LEN + sizeof(struct ip); 164577298Sobrien TXD->upper_setup.tcp_fields.tucse = 0; 164677298Sobrien 164777298Sobrien if (adapter->active_checksum_context == OFFLOAD_TCP_IP) { 164877298Sobrien TXD->upper_setup.tcp_fields.tucso = 164977298Sobrien ETHER_HDR_LEN + sizeof(struct ip) + 165077298Sobrien offsetof(struct tcphdr, th_sum); 165177298Sobrien } else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) { 165277298Sobrien TXD->upper_setup.tcp_fields.tucso = 165377298Sobrien ETHER_HDR_LEN + sizeof(struct ip) + 165477298Sobrien offsetof(struct udphdr, uh_sum); 165577298Sobrien } 165677298Sobrien 165777298Sobrien TXD->tcp_seg_setup.data = 0; 165877298Sobrien TXD->cmd_and_length = E1000_TXD_CMD_DEXT; 165977298Sobrien 166077298Sobrien if (current_tx_desc == adapter->last_tx_desc) 166177298Sobrien adapter->next_avail_tx_desc = adapter->first_tx_desc; 166277298Sobrien else 166377298Sobrien adapter->next_avail_tx_desc++; 166477298Sobrien 166577298Sobrien adapter->num_tx_desc_avail--; 166677298Sobrien 166777298Sobrien tx_buffer->num_tx_desc_used++; 166877298Sobrien return; 166977298Sobrien} 167077298Sobrien 167177298Sobrien 167277298Sobrien/********************************************************************* 167377298Sobrien * 167477298Sobrien * Get a buffer from system mbuf buffer pool. 167577298Sobrien * 167677298Sobrien **********************************************************************/ 167777298Sobrienstatic int 167877298Sobrienem_get_buf(struct em_rx_buffer *rx_buffer, struct adapter *adapter, 167989857Sobrien struct mbuf *mp) 168077298Sobrien{ 168189857Sobrien struct mbuf *nmp; 168277298Sobrien struct ifnet *ifp; 168377298Sobrien 168477298Sobrien ifp = &adapter->interface_data.ac_if; 168577298Sobrien 168677298Sobrien if (mp == NULL) { 168777298Sobrien MGETHDR(nmp, M_DONTWAIT, MT_DATA); 168877298Sobrien if (nmp == NULL) { 168977298Sobrien adapter->mbuf_alloc_failed++; 169077298Sobrien return(ENOBUFS); 169177298Sobrien } 169277298Sobrien MCLGET(nmp, M_DONTWAIT); 169377298Sobrien if ((nmp->m_flags & M_EXT) == 0) { 169477298Sobrien m_freem(nmp); 169577298Sobrien adapter->mbuf_cluster_failed++; 169677298Sobrien return(ENOBUFS); 169777298Sobrien } 169877298Sobrien nmp->m_len = nmp->m_pkthdr.len = MCLBYTES; 169977298Sobrien } else { 170077298Sobrien nmp = mp; 170177298Sobrien nmp->m_len = nmp->m_pkthdr.len = MCLBYTES; 170277298Sobrien nmp->m_data = nmp->m_ext.ext_buf; 170377298Sobrien nmp->m_next = NULL; 170477298Sobrien } 170577298Sobrien 170677298Sobrien if (ifp->if_mtu <= ETHERMTU) { 170777298Sobrien m_adj(nmp, ETHER_ALIGN); 170877298Sobrien } 170977298Sobrien 171077298Sobrien rx_buffer->m_head = nmp; 171177298Sobrien rx_buffer->buffer_addr = vtophys(mtod(nmp, vm_offset_t)); 171277298Sobrien 171377298Sobrien return(0); 171477298Sobrien} 171577298Sobrien 171677298Sobrien/********************************************************************* 171777298Sobrien * 171877298Sobrien * Allocate memory for rx_buffer structures. Since we use one 171977298Sobrien * rx_buffer per received packet, the maximum number of rx_buffer's 172077298Sobrien * that we'll need is equal to the number of receive descriptors 172177298Sobrien * that we've allocated. 172277298Sobrien * 172377298Sobrien **********************************************************************/ 172477298Sobrienstatic int 172577298Sobrienem_allocate_receive_structures(struct adapter * adapter) 172677298Sobrien{ 172777298Sobrien int i; 172877298Sobrien struct em_rx_buffer *rx_buffer; 172977298Sobrien 173077298Sobrien if (!(adapter->rx_buffer_area = 173177298Sobrien (struct em_rx_buffer *) malloc(sizeof(struct em_rx_buffer) * 173277298Sobrien adapter->num_rx_desc, M_DEVBUF, 173377298Sobrien M_NOWAIT))) { 173477298Sobrien printf("em%d: Unable to allocate rx_buffer memory\n", 173577298Sobrien adapter->unit); 173677298Sobrien return(ENOMEM); 173777298Sobrien } 173877298Sobrien 173977298Sobrien bzero(adapter->rx_buffer_area, 174077298Sobrien sizeof(struct em_rx_buffer) * adapter->num_rx_desc); 174177298Sobrien 174277298Sobrien for (i = 0, rx_buffer = adapter->rx_buffer_area; 174377298Sobrien i < adapter->num_rx_desc; i++, rx_buffer++) { 174477298Sobrien 174577298Sobrien if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) { 174677298Sobrien rx_buffer->m_head = NULL; 174777298Sobrien return(ENOBUFS); 174877298Sobrien } 174977298Sobrien } 175077298Sobrien 175177298Sobrien return(0); 175277298Sobrien} 175377298Sobrien 175477298Sobrien/********************************************************************* 175577298Sobrien * 175677298Sobrien * Allocate and initialize receive structures. 175777298Sobrien * 175877298Sobrien **********************************************************************/ 175977298Sobrienstatic int 176077298Sobrienem_setup_receive_structures(struct adapter * adapter) 176177298Sobrien{ 176277298Sobrien struct em_rx_buffer *rx_buffer; 176377298Sobrien struct em_rx_desc *rx_desc; 176477298Sobrien int i; 176577298Sobrien 176677298Sobrien if (em_allocate_receive_structures(adapter)) 176777298Sobrien return ENOMEM; 176877298Sobrien 176977298Sobrien STAILQ_INIT(&adapter->rx_buffer_list); 177077298Sobrien 177177298Sobrien adapter->first_rx_desc = 177277298Sobrien (struct em_rx_desc *) adapter->rx_desc_base; 177377298Sobrien adapter->last_rx_desc = 177477298Sobrien adapter->first_rx_desc + (adapter->num_rx_desc - 1); 177577298Sobrien 177677298Sobrien rx_buffer = (struct em_rx_buffer *) adapter->rx_buffer_area; 177777298Sobrien 177877298Sobrien bzero((void *) adapter->first_rx_desc, 177977298Sobrien (sizeof(struct em_rx_desc)) * adapter->num_rx_desc); 178077298Sobrien 178189857Sobrien /* Build a linked list of rx_buffer's */ 178277298Sobrien for (i = 0, rx_desc = adapter->first_rx_desc; 178377298Sobrien i < adapter->num_rx_desc; 178477298Sobrien i++, rx_buffer++, rx_desc++) { 178577298Sobrien if (rx_buffer->m_head == NULL) 178677298Sobrien printf("em%d: Receive buffer memory not allocated", 178777298Sobrien adapter->unit); 178877298Sobrien else { 178977298Sobrien rx_desc->buffer_addr = rx_buffer->buffer_addr; 179077298Sobrien STAILQ_INSERT_TAIL(&adapter->rx_buffer_list, 179189857Sobrien rx_buffer, em_rx_entry); 179277298Sobrien } 179377298Sobrien } 179477298Sobrien 179577298Sobrien /* Setup our descriptor pointers */ 179677298Sobrien adapter->next_rx_desc_to_check = adapter->first_rx_desc; 179777298Sobrien 179877298Sobrien return(0); 179977298Sobrien} 180077298Sobrien 180177298Sobrien/********************************************************************* 180277298Sobrien * 180377298Sobrien * Enable receive unit. 180477298Sobrien * 180577298Sobrien **********************************************************************/ 180677298Sobrienstatic void 180777298Sobrienem_initialize_receive_unit(struct adapter * adapter) 180877298Sobrien{ 180977298Sobrien u_int32_t reg_rctl; 181077298Sobrien u_int32_t reg_rxcsum; 181177298Sobrien struct ifnet *ifp; 181277298Sobrien 181377298Sobrien ifp = &adapter->interface_data.ac_if; 181489857Sobrien 181577298Sobrien /* Make sure receives are disabled while setting up the descriptor ring */ 181677298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, 0); 181777298Sobrien 181877298Sobrien /* Set the Receive Delay Timer Register */ 181977298Sobrien E1000_WRITE_REG(&adapter->hw, RDTR, 182077298Sobrien adapter->rx_int_delay | E1000_RDT_FPDB); 182177298Sobrien 182277298Sobrien /* Setup the Base and Length of the Rx Descriptor Ring */ 182377298Sobrien E1000_WRITE_REG(&adapter->hw, RDBAL, 182477298Sobrien vtophys((vm_offset_t) adapter->rx_desc_base)); 182577298Sobrien E1000_WRITE_REG(&adapter->hw, RDBAH, 0); 182677298Sobrien E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc * 182777298Sobrien sizeof(struct em_rx_desc)); 182877298Sobrien 182977298Sobrien /* Setup the HW Rx Head and Tail Descriptor Pointers */ 183077298Sobrien E1000_WRITE_REG(&adapter->hw, RDH, 0); 183177298Sobrien E1000_WRITE_REG(&adapter->hw, RDT, 183277298Sobrien (((uintptr_t) adapter->last_rx_desc - 183377298Sobrien (uintptr_t) adapter->first_rx_desc) >> 4)); 183477298Sobrien 183577298Sobrien /* Setup the Receive Control Register */ 183677298Sobrien reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | 183777298Sobrien E1000_RCTL_RDMTS_HALF | 183877298Sobrien (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); 183977298Sobrien 184077298Sobrien if (adapter->hw.tbi_compatibility_on == TRUE) 184177298Sobrien reg_rctl |= E1000_RCTL_SBP; 184277298Sobrien 184377298Sobrien 184477298Sobrien switch (adapter->rx_buffer_len) { 184577298Sobrien default: 184677298Sobrien case EM_RXBUFFER_2048: 184777298Sobrien reg_rctl |= E1000_RCTL_SZ_2048; 184877298Sobrien break; 184977298Sobrien case EM_RXBUFFER_4096: 185077298Sobrien reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; 185177298Sobrien break; 185277298Sobrien case EM_RXBUFFER_8192: 185377298Sobrien reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; 185477298Sobrien break; 185577298Sobrien case EM_RXBUFFER_16384: 185677298Sobrien reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; 185777298Sobrien break; 185877298Sobrien } 185977298Sobrien 186077298Sobrien if (ifp->if_mtu > ETHERMTU) 186177298Sobrien reg_rctl |= E1000_RCTL_LPE; 186277298Sobrien 186377298Sobrien /* Enable 82543 Receive Checksum Offload for TCP and UDP */ 186477298Sobrien if ((adapter->hw.mac_type >= em_82543) && 186577298Sobrien (ifp->if_capenable & IFCAP_RXCSUM)) { 186677298Sobrien reg_rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM); 186777298Sobrien reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL); 186877298Sobrien E1000_WRITE_REG(&adapter->hw, RXCSUM, reg_rxcsum); 186977298Sobrien } 187077298Sobrien 187177298Sobrien /* Enable Receives */ 187277298Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 187377298Sobrien 187477298Sobrien return; 187577298Sobrien} 187677298Sobrien 187777298Sobrien/********************************************************************* 187889857Sobrien * 187977298Sobrien * Free receive related data structures. 188077298Sobrien * 188177298Sobrien **********************************************************************/ 188289857Sobrienstatic void 188377298Sobrienem_free_receive_structures(struct adapter * adapter) 188477298Sobrien{ 188577298Sobrien struct em_rx_buffer *rx_buffer; 188677298Sobrien int i; 188777298Sobrien 188877298Sobrien INIT_DEBUGOUT("free_receive_structures: begin"); 188989857Sobrien 189077298Sobrien if (adapter->rx_buffer_area != NULL) { 189177298Sobrien rx_buffer = adapter->rx_buffer_area; 189277298Sobrien for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { 189377298Sobrien if (rx_buffer->m_head != NULL) 189477298Sobrien m_freem(rx_buffer->m_head); 189577298Sobrien rx_buffer->m_head = NULL; 189677298Sobrien } 189777298Sobrien } 189877298Sobrien if (adapter->rx_buffer_area != NULL) { 189977298Sobrien free(adapter->rx_buffer_area, M_DEVBUF); 190077298Sobrien adapter->rx_buffer_area = NULL; 190177298Sobrien } 190277298Sobrien return; 190377298Sobrien} 190477298Sobrien 190577298Sobrien/********************************************************************* 190689857Sobrien * 190777298Sobrien * This routine executes in interrupt context. It replenishes 190877298Sobrien * the mbufs in the descriptor and sends data which has been 190977298Sobrien * dma'ed into host memory to upper layer. 191089857Sobrien * 191177298Sobrien *********************************************************************/ 191277298Sobrienstatic void 191377298Sobrienem_process_receive_interrupts(struct adapter * adapter) 191477298Sobrien{ 191589857Sobrien struct mbuf *mp; 191677298Sobrien struct ifnet *ifp; 191777298Sobrien struct ether_header *eh; 191877298Sobrien u_int16_t len; 191977298Sobrien u_int8_t last_byte; 192077298Sobrien u_int8_t accept_frame = 0; 192177298Sobrien u_int8_t eop = 0; 192277298Sobrien u_int32_t pkt_len = 0; 192377298Sobrien 192477298Sobrien /* Pointer to the receive descriptor being examined. */ 192577298Sobrien struct em_rx_desc *current_desc; 192677298Sobrien struct em_rx_desc *last_desc_processed; 192777298Sobrien struct em_rx_buffer *rx_buffer; 192877298Sobrien 192977298Sobrien ifp = &adapter->interface_data.ac_if; 193077298Sobrien current_desc = adapter->next_rx_desc_to_check; 193177298Sobrien 193277298Sobrien if (!((current_desc->status) & E1000_RXD_STAT_DD)) { 193377298Sobrien#ifdef DBG_STATS 193477298Sobrien adapter->no_pkts_avail++; 193577298Sobrien#endif 193677298Sobrien return; 193777298Sobrien } 193877298Sobrien 193977298Sobrien while (current_desc->status & E1000_RXD_STAT_DD) { 194077298Sobrien 194177298Sobrien /* Get a pointer to the actual receive buffer */ 194277298Sobrien rx_buffer = STAILQ_FIRST(&adapter->rx_buffer_list); 194377298Sobrien 194477298Sobrien if (rx_buffer == NULL) { 194577298Sobrien printf("em%d: Found null rx_buffer\n", adapter->unit); 194677298Sobrien return; 194777298Sobrien } 194877298Sobrien 194977298Sobrien mp = rx_buffer->m_head; 195077298Sobrien accept_frame = 1; 195177298Sobrien 195277298Sobrien if (current_desc->status & E1000_RXD_STAT_EOP) { 195377298Sobrien eop = 1; 195477298Sobrien len = current_desc->length - ETHER_CRC_LEN; 195577298Sobrien } else { 195677298Sobrien eop = 0; 195777298Sobrien len = current_desc->length; 195877298Sobrien } 195977298Sobrien 196077298Sobrien if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { 196177298Sobrien 196277298Sobrien /* Compute packet length for tbi_accept macro */ 196377298Sobrien pkt_len = current_desc->length; 196477298Sobrien if (adapter->fmp != NULL) { 196577298Sobrien pkt_len += adapter->fmp->m_pkthdr.len; 196677298Sobrien } 196777298Sobrien 196877298Sobrien last_byte = *(mtod(rx_buffer->m_head,caddr_t) + 196977298Sobrien current_desc->length - 1); 197077298Sobrien 197177298Sobrien if (TBI_ACCEPT(&adapter->hw, current_desc->status, 197277298Sobrien current_desc->errors, 197377298Sobrien pkt_len, last_byte)) { 197477298Sobrien em_tbi_adjust_stats(&adapter->hw, 197577298Sobrien &adapter->stats, 197677298Sobrien pkt_len, 197777298Sobrien adapter->hw.mac_addr); 197877298Sobrien len--; 197977298Sobrien } else { 198077298Sobrien accept_frame = 0; 198177298Sobrien } 198277298Sobrien } 198377298Sobrien 198477298Sobrien if (accept_frame) { 198577298Sobrien 198677298Sobrien if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) { 198777298Sobrien adapter->dropped_pkts++; 198877298Sobrien em_get_buf(rx_buffer, adapter, mp); 198977298Sobrien if (adapter->fmp != NULL) m_freem(adapter->fmp); 199077298Sobrien adapter->fmp = NULL; 199177298Sobrien adapter->lmp = NULL; 199277298Sobrien break; 199377298Sobrien } 199477298Sobrien 199577298Sobrien /* Assign correct length to the current fragment */ 199677298Sobrien mp->m_len = len; 199777298Sobrien 199877298Sobrien if (adapter->fmp == NULL) { 199977298Sobrien mp->m_pkthdr.len = len; 200077298Sobrien adapter->fmp = mp; /* Store the first mbuf */ 200177298Sobrien adapter->lmp = mp; 200277298Sobrien } else { 200377298Sobrien /* Chain mbuf's together */ 200477298Sobrien mp->m_flags &= ~M_PKTHDR; 200577298Sobrien adapter->lmp->m_next = mp; 200677298Sobrien adapter->lmp = adapter->lmp->m_next; 200777298Sobrien adapter->fmp->m_pkthdr.len += len; 200877298Sobrien } 200977298Sobrien 201077298Sobrien if (eop) { 201177298Sobrien adapter->fmp->m_pkthdr.rcvif = ifp; 201277298Sobrien 201377298Sobrien eh = mtod(adapter->fmp, struct ether_header *); 201477298Sobrien 201577298Sobrien /* Remove ethernet header from mbuf */ 201677298Sobrien m_adj(adapter->fmp, sizeof(struct ether_header)); 201777298Sobrien em_receive_checksum(adapter, current_desc, 201877298Sobrien adapter->fmp); 201977298Sobrien if (current_desc->status & E1000_RXD_STAT_VP) 202077298Sobrien VLAN_INPUT_TAG(eh, adapter->fmp, 202177298Sobrien current_desc->special); 202277298Sobrien else 202377298Sobrien ether_input(ifp, eh, adapter->fmp); 202477298Sobrien 202577298Sobrien adapter->fmp = NULL; 202677298Sobrien adapter->lmp = NULL; 202777298Sobrien } 202877298Sobrien } else { 202977298Sobrien adapter->dropped_pkts++; 203077298Sobrien em_get_buf(rx_buffer, adapter, mp); 203177298Sobrien if (adapter->fmp != NULL) m_freem(adapter->fmp); 203277298Sobrien adapter->fmp = NULL; 203377298Sobrien adapter->lmp = NULL; 203477298Sobrien } 203577298Sobrien 203677298Sobrien /* Zero out the receive descriptors status */ 203777298Sobrien current_desc->status = 0; 203877298Sobrien 203977298Sobrien if (rx_buffer->m_head != NULL) { 204077298Sobrien current_desc->buffer_addr = rx_buffer->buffer_addr; 204177298Sobrien } 204277298Sobrien 204377298Sobrien /* Advance our pointers to the next descriptor (checking for wrap). */ 204477298Sobrien if (current_desc == adapter->last_rx_desc) 204577298Sobrien adapter->next_rx_desc_to_check = adapter->first_rx_desc; 204677298Sobrien else 204777298Sobrien ((adapter)->next_rx_desc_to_check)++; 204877298Sobrien 204977298Sobrien last_desc_processed = current_desc; 205077298Sobrien current_desc = adapter->next_rx_desc_to_check; 205177298Sobrien /* 205277298Sobrien * Put the buffer that we just indicated back at the end of our list 205377298Sobrien */ 205477298Sobrien STAILQ_REMOVE_HEAD(&adapter->rx_buffer_list, em_rx_entry); 205577298Sobrien STAILQ_INSERT_TAIL(&adapter->rx_buffer_list, 205677298Sobrien rx_buffer, em_rx_entry); 205777298Sobrien 205877298Sobrien /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ 205977298Sobrien E1000_WRITE_REG(&adapter->hw, RDT, 206077298Sobrien (((u_long) last_desc_processed - 206177298Sobrien (u_long) adapter->first_rx_desc) >> 4)); 206277298Sobrien } 206377298Sobrien return; 206477298Sobrien} 206577298Sobrien 206677298Sobrien/********************************************************************* 206777298Sobrien * 206877298Sobrien * Verify that the hardware indicated that the checksum is valid. 206977298Sobrien * Inform the stack about the status of checksum so that stack 207077298Sobrien * doesn't spend time verifying the checksum. 207177298Sobrien * 207277298Sobrien *********************************************************************/ 207377298Sobrienstatic void 207477298Sobrienem_receive_checksum(struct adapter *adapter, 207577298Sobrien struct em_rx_desc *rx_desc, 207677298Sobrien struct mbuf *mp) 207777298Sobrien{ 207877298Sobrien /* 82543 or newer only */ 207977298Sobrien if ((adapter->hw.mac_type < em_82543) || 208077298Sobrien /* Ignore Checksum bit is set */ 208177298Sobrien (rx_desc->status & E1000_RXD_STAT_IXSM)) { 208277298Sobrien mp->m_pkthdr.csum_flags = 0; 208377298Sobrien return; 208477298Sobrien } 208577298Sobrien 208677298Sobrien if (rx_desc->status & E1000_RXD_STAT_IPCS) { 208777298Sobrien /* Did it pass? */ 208877298Sobrien if (!(rx_desc->errors & E1000_RXD_ERR_IPE)) { 208977298Sobrien /* IP Checksum Good */ 209077298Sobrien mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; 209177298Sobrien mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; 209277298Sobrien 209377298Sobrien } else { 209477298Sobrien mp->m_pkthdr.csum_flags = 0; 209577298Sobrien } 209677298Sobrien } 209777298Sobrien 209877298Sobrien if (rx_desc->status & E1000_RXD_STAT_TCPCS) { 209977298Sobrien /* Did it pass? */ 210077298Sobrien if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) { 210177298Sobrien mp->m_pkthdr.csum_flags |= 210277298Sobrien (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 210377298Sobrien mp->m_pkthdr.csum_data = htons(0xffff); 210477298Sobrien } 210577298Sobrien } 210677298Sobrien 210777298Sobrien return; 210877298Sobrien} 210977298Sobrien 211077298Sobrien 211177298Sobrienstatic void em_enable_vlans(struct adapter *adapter) 211277298Sobrien{ 211377298Sobrien uint32_t ctrl; 211477298Sobrien 211577298Sobrien E1000_WRITE_REG(&adapter->hw, VET, QTAG_TYPE); 211677298Sobrien 211777298Sobrien ctrl = E1000_READ_REG(&adapter->hw, CTRL); 211877298Sobrien ctrl |= E1000_CTRL_VME; 211977298Sobrien E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); 212077298Sobrien 212177298Sobrien return; 212277298Sobrien} 212377298Sobrien 212477298Sobrienstatic void 212577298Sobrienem_enable_intr(struct adapter * adapter) 212677298Sobrien{ 212777298Sobrien E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK)); 212877298Sobrien return; 212977298Sobrien} 213077298Sobrien 213177298Sobrienstatic void 213277298Sobrienem_disable_intr(struct adapter *adapter) 213377298Sobrien{ 213477298Sobrien E1000_WRITE_REG(&adapter->hw, IMC, 213577298Sobrien (0xffffffff & ~E1000_IMC_RXSEQ)); 213677298Sobrien return; 213777298Sobrien} 213877298Sobrien 213977298Sobrienvoid em_write_pci_cfg(struct em_hw *hw, 214077298Sobrien uint32_t reg, 214177298Sobrien uint16_t *value) 214277298Sobrien{ 214377298Sobrien pci_write_config(((struct em_osdep *)hw->back)->dev, reg, 214477298Sobrien *value, 2); 214577298Sobrien} 214677298Sobrien 214777298Sobrienvoid em_read_pci_cfg(struct em_hw *hw, uint32_t reg, 214877298Sobrien uint16_t *value) 214977298Sobrien{ 215077298Sobrien *value = pci_read_config(((struct em_osdep *)hw->back)->dev, 215177298Sobrien reg, 2); 215277298Sobrien return; 215377298Sobrien} 215477298Sobrien 215577298Sobrienuint32_t em_io_read(struct em_hw *hw, uint32_t port) 215677298Sobrien{ 215777298Sobrien return(inl(port)); 215877298Sobrien} 215977298Sobrien 216077298Sobrienvoid em_io_write(struct em_hw *hw, uint32_t port, uint32_t value) 216177298Sobrien{ 216277298Sobrien outl(port, value); 216377298Sobrien return; 216477298Sobrien} 216577298Sobrien 216677298Sobrien/********************************************************************** 216777298Sobrien * 216877298Sobrien * Update the board statistics counters. 216977298Sobrien * 217077298Sobrien **********************************************************************/ 217177298Sobrienstatic void 217277298Sobrienem_update_stats_counters(struct adapter *adapter) 217377298Sobrien{ 217477298Sobrien struct ifnet *ifp; 217577298Sobrien 217677298Sobrien adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, CRCERRS); 217777298Sobrien adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS); 217877298Sobrien adapter->stats.mpc += E1000_READ_REG(&adapter->hw, MPC); 217977298Sobrien adapter->stats.scc += E1000_READ_REG(&adapter->hw, SCC); 218077298Sobrien adapter->stats.ecol += E1000_READ_REG(&adapter->hw, ECOL); 218177298Sobrien adapter->stats.mcc += E1000_READ_REG(&adapter->hw, MCC); 218277298Sobrien adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL); 218377298Sobrien adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC); 218477298Sobrien adapter->stats.dc += E1000_READ_REG(&adapter->hw, DC); 218577298Sobrien adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC); 218677298Sobrien adapter->stats.rlec += E1000_READ_REG(&adapter->hw, RLEC); 218777298Sobrien adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, XONRXC); 218877298Sobrien adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, XONTXC); 218977298Sobrien adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, XOFFRXC); 219077298Sobrien adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, XOFFTXC); 219177298Sobrien adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, FCRUC); 219277298Sobrien adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, PRC64); 219377298Sobrien adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, PRC127); 219477298Sobrien adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, PRC255); 219577298Sobrien adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, PRC511); 219677298Sobrien adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, PRC1023); 219777298Sobrien adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, PRC1522); 219877298Sobrien adapter->stats.gprc += E1000_READ_REG(&adapter->hw, GPRC); 219977298Sobrien adapter->stats.bprc += E1000_READ_REG(&adapter->hw, BPRC); 220077298Sobrien adapter->stats.mprc += E1000_READ_REG(&adapter->hw, MPRC); 220177298Sobrien adapter->stats.gptc += E1000_READ_REG(&adapter->hw, GPTC); 220277298Sobrien 220377298Sobrien /* For the 64-bit byte counters the low dword must be read first. */ 220477298Sobrien /* Both registers clear on the read of the high dword */ 220577298Sobrien 220677298Sobrien adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL); 220777298Sobrien adapter->stats.gorch += E1000_READ_REG(&adapter->hw, GORCH); 220877298Sobrien adapter->stats.gotcl += E1000_READ_REG(&adapter->hw, GOTCL); 220977298Sobrien adapter->stats.gotch += E1000_READ_REG(&adapter->hw, GOTCH); 221077298Sobrien 221177298Sobrien adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, RNBC); 221277298Sobrien adapter->stats.ruc += E1000_READ_REG(&adapter->hw, RUC); 221377298Sobrien adapter->stats.rfc += E1000_READ_REG(&adapter->hw, RFC); 221477298Sobrien adapter->stats.roc += E1000_READ_REG(&adapter->hw, ROC); 221577298Sobrien adapter->stats.rjc += E1000_READ_REG(&adapter->hw, RJC); 221677298Sobrien 221777298Sobrien adapter->stats.torl += E1000_READ_REG(&adapter->hw, TORL); 221877298Sobrien adapter->stats.torh += E1000_READ_REG(&adapter->hw, TORH); 221977298Sobrien adapter->stats.totl += E1000_READ_REG(&adapter->hw, TOTL); 222077298Sobrien adapter->stats.toth += E1000_READ_REG(&adapter->hw, TOTH); 222177298Sobrien 222277298Sobrien adapter->stats.tpr += E1000_READ_REG(&adapter->hw, TPR); 222377298Sobrien adapter->stats.tpt += E1000_READ_REG(&adapter->hw, TPT); 222477298Sobrien adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, PTC64); 222577298Sobrien adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, PTC127); 222677298Sobrien adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, PTC255); 222777298Sobrien adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, PTC511); 222877298Sobrien adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, PTC1023); 222977298Sobrien adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, PTC1522); 223077298Sobrien adapter->stats.mptc += E1000_READ_REG(&adapter->hw, MPTC); 223177298Sobrien adapter->stats.bptc += E1000_READ_REG(&adapter->hw, BPTC); 223277298Sobrien 223377298Sobrien if (adapter->hw.mac_type >= em_82543) { 223477298Sobrien adapter->stats.algnerrc += 223577298Sobrien E1000_READ_REG(&adapter->hw, ALGNERRC); 223677298Sobrien adapter->stats.rxerrc += 223777298Sobrien E1000_READ_REG(&adapter->hw, RXERRC); 223877298Sobrien adapter->stats.tncrs += 223977298Sobrien E1000_READ_REG(&adapter->hw, TNCRS); 224077298Sobrien adapter->stats.cexterr += 224177298Sobrien E1000_READ_REG(&adapter->hw, CEXTERR); 224277298Sobrien adapter->stats.tsctc += 224377298Sobrien E1000_READ_REG(&adapter->hw, TSCTC); 224477298Sobrien adapter->stats.tsctfc += 224577298Sobrien E1000_READ_REG(&adapter->hw, TSCTFC); 224677298Sobrien } 224777298Sobrien ifp = &adapter->interface_data.ac_if; 224877298Sobrien 224977298Sobrien /* Fill out the OS statistics structure */ 225077298Sobrien ifp->if_ipackets = adapter->stats.gprc; 225177298Sobrien ifp->if_opackets = adapter->stats.gptc; 225277298Sobrien ifp->if_ibytes = adapter->stats.gorcl; 225377298Sobrien ifp->if_obytes = adapter->stats.gotcl; 225477298Sobrien ifp->if_imcasts = adapter->stats.mprc; 225577298Sobrien ifp->if_collisions = adapter->stats.colc; 225677298Sobrien 225777298Sobrien /* Rx Errors */ 225877298Sobrien ifp->if_ierrors = 225977298Sobrien adapter->dropped_pkts + 226077298Sobrien adapter->stats.rxerrc + 226177298Sobrien adapter->stats.crcerrs + 226277298Sobrien adapter->stats.algnerrc + 226377298Sobrien adapter->stats.rlec + adapter->stats.rnbc + 226477298Sobrien adapter->stats.mpc + adapter->stats.cexterr; 226577298Sobrien 226677298Sobrien /* Tx Errors */ 226777298Sobrien ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol; 226877298Sobrien 226977298Sobrien} 227077298Sobrien 227177298Sobrien 227277298Sobrien/********************************************************************** 227377298Sobrien * 227477298Sobrien * This routine is called only when em_display_debug_stats is enabled. 227577298Sobrien * This routine provides a way to take a look at important statistics 227677298Sobrien * maintained by the driver and hardware. 227777298Sobrien * 227877298Sobrien **********************************************************************/ 227977298Sobrienstatic void 228077298Sobrienem_print_hw_stats(struct adapter *adapter) 228177298Sobrien{ 228277298Sobrien int unit = adapter->unit; 228377298Sobrien 228477298Sobrien#ifdef DBG_STATS 228577298Sobrien printf("em%d: Packets not Avail = %ld\n", unit, 228677298Sobrien adapter->no_pkts_avail); 228777298Sobrien printf("em%d: CleanTxInterrupts = %ld\n", unit, 228877298Sobrien adapter->clean_tx_interrupts); 228977298Sobrien#endif 229077298Sobrien 229177298Sobrien printf("em%d: Tx Descriptors not Avail = %ld\n", unit, 229277298Sobrien adapter->no_tx_desc_avail); 229377298Sobrien printf("em%d: Tx Buffer not avail1 = %ld\n", unit, 229477298Sobrien adapter->no_tx_buffer_avail1); 229577298Sobrien printf("em%d: Tx Buffer not avail2 = %ld\n", unit, 229677298Sobrien adapter->no_tx_buffer_avail2); 229777298Sobrien printf("em%d: Std Mbuf Failed = %ld\n",unit, 229877298Sobrien adapter->mbuf_alloc_failed); 229977298Sobrien printf("em%d: Std Cluster Failed = %ld\n",unit, 230077298Sobrien adapter->mbuf_cluster_failed); 230177298Sobrien 230277298Sobrien printf("em%d: Symbol errors = %lld\n", unit, 230377298Sobrien (long long)adapter->stats.symerrs); 230477298Sobrien printf("em%d: Sequence errors = %lld\n", unit, 230577298Sobrien (long long)adapter->stats.sec); 230677298Sobrien printf("em%d: Defer count = %lld\n", unit, 230777298Sobrien (long long)adapter->stats.dc); 230877298Sobrien 230977298Sobrien printf("em%d: Missed Packets = %lld\n", unit, 231077298Sobrien (long long)adapter->stats.mpc); 231177298Sobrien printf("em%d: Receive No Buffers = %lld\n", unit, 231277298Sobrien (long long)adapter->stats.rnbc); 231377298Sobrien printf("em%d: Receive length errors = %lld\n", unit, 231477298Sobrien (long long)adapter->stats.rlec); 231577298Sobrien printf("em%d: Receive errors = %lld\n", unit, 231677298Sobrien (long long)adapter->stats.rxerrc); 231777298Sobrien printf("em%d: Crc errors = %lld\n", unit, 231877298Sobrien (long long)adapter->stats.crcerrs); 231977298Sobrien printf("em%d: Alignment errors = %lld\n", unit, 232077298Sobrien (long long)adapter->stats.algnerrc); 232177298Sobrien printf("em%d: Carrier extension errors = %lld\n", unit, 232277298Sobrien (long long)adapter->stats.cexterr); 232377298Sobrien printf("em%d: Driver dropped packets = %ld\n", unit, 232477298Sobrien adapter->dropped_pkts); 232577298Sobrien 232677298Sobrien printf("em%d: XON Rcvd = %lld\n", unit, 232777298Sobrien (long long)adapter->stats.xonrxc); 232877298Sobrien printf("em%d: XON Xmtd = %lld\n", unit, 232977298Sobrien (long long)adapter->stats.xontxc); 233077298Sobrien printf("em%d: XOFF Rcvd = %lld\n", unit, 233177298Sobrien (long long)adapter->stats.xoffrxc); 233277298Sobrien printf("em%d: XOFF Xmtd = %lld\n", unit, 233377298Sobrien (long long)adapter->stats.xofftxc); 233477298Sobrien 233577298Sobrien printf("em%d: Good Packets Rcvd = %lld\n", unit, 233677298Sobrien (long long)adapter->stats.gprc); 233777298Sobrien printf("em%d: Good Packets Xmtd = %lld\n", unit, 233877298Sobrien (long long)adapter->stats.gptc); 233977298Sobrien 234077298Sobrien return; 234177298Sobrien} 234277298Sobrien 234377298Sobrien 234477298Sobrien/********************************************************************** 234577298Sobrien * 234677298Sobrien * Examine each tx_buffer in the used queue. If the hardware is done 234777298Sobrien * processing the packet then free associated resources. The 234877298Sobrien * tx_buffer is put back on the free queue. 234977298Sobrien * 235077298Sobrien **********************************************************************/ 235177298Sobrienstatic void 235277298Sobrienem_clean_transmit_interrupts(struct adapter * adapter) 235377298Sobrien{ 235477298Sobrien struct em_tx_buffer *tx_buffer; 235577298Sobrien struct em_tx_desc *tx_desc; 235677298Sobrien int s; 235777298Sobrien struct ifnet *ifp; 235877298Sobrien 235977298Sobrien s = splimp(); 236077298Sobrien#ifdef DBG_STATS 236177298Sobrien adapter->clean_tx_interrupts++; 236277298Sobrien#endif 236377298Sobrien 236477298Sobrien for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list); 236577298Sobrien tx_buffer; 236677298Sobrien tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) { 236777298Sobrien 236877298Sobrien /* 236977298Sobrien * Get hold of the next descriptor that the em will report status 237077298Sobrien * back to (this will be the last descriptor of a given tx_buffer). We 237177298Sobrien * only want to free the tx_buffer (and it resources) if the driver is 237277298Sobrien * done with ALL of the descriptors. If the driver is done with the 237377298Sobrien * last one then it is done with all of them. 237477298Sobrien */ 237577298Sobrien 237677298Sobrien tx_desc = adapter->oldest_used_tx_desc + 237777298Sobrien (tx_buffer->num_tx_desc_used - 1); 237877298Sobrien 237977298Sobrien /* Check for wrap case */ 238077298Sobrien if (tx_desc > adapter->last_tx_desc) 238177298Sobrien tx_desc -= adapter->num_tx_desc; 238277298Sobrien 238377298Sobrien 238477298Sobrien /* 238577298Sobrien * If the descriptor done bit is set free tx_buffer and associated 238677298Sobrien * resources 238777298Sobrien */ 238877298Sobrien if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) { 238977298Sobrien 239077298Sobrien STAILQ_REMOVE_HEAD(&adapter->used_tx_buffer_list, 239177298Sobrien em_tx_entry); 239277298Sobrien 239377298Sobrien if ((tx_desc == adapter->last_tx_desc)) 239477298Sobrien adapter->oldest_used_tx_desc = 239577298Sobrien adapter->first_tx_desc; 239677298Sobrien else 239777298Sobrien adapter->oldest_used_tx_desc = (tx_desc + 1); 239877298Sobrien 239977298Sobrien /* Make available the descriptors that were previously used */ 240077298Sobrien adapter->num_tx_desc_avail += 240177298Sobrien tx_buffer->num_tx_desc_used; 240277298Sobrien 240377298Sobrien tx_buffer->num_tx_desc_used = 0; 240477298Sobrien 240577298Sobrien if (tx_buffer->m_head) { 240677298Sobrien m_freem(tx_buffer->m_head); 240777298Sobrien tx_buffer->m_head = NULL; 240877298Sobrien } 240977298Sobrien /* Return this "Software packet" back to the "free" list */ 241077298Sobrien STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list, 241177298Sobrien tx_buffer, em_tx_entry); 241277298Sobrien } else { 241377298Sobrien /* 241477298Sobrien * Found a tx_buffer that the em is not done with then there is 241577298Sobrien * no reason to check the rest of the queue. 241677298Sobrien */ 241777298Sobrien break; 241877298Sobrien } 241977298Sobrien } /* end for each tx_buffer */ 242077298Sobrien 242177298Sobrien ifp = &adapter->interface_data.ac_if; 242277298Sobrien 242377298Sobrien /* Tell the stack that it is OK to send packets */ 242477298Sobrien if (adapter->num_tx_desc_avail > TX_CLEANUP_THRESHOLD) { 242577298Sobrien ifp->if_timer = 0; 242677298Sobrien ifp->if_flags &= ~IFF_OACTIVE; 242777298Sobrien } 242877298Sobrien splx(s); 242977298Sobrien return; 243077298Sobrien} 243177298Sobrien 243277298Sobrien