if_em.c revision 121816
184865Sobrien/************************************************************************** 2218822Sdim 384865SobrienCopyright (c) 2001-2003, Intel Corporation 4218822SdimAll rights reserved. 584865Sobrien 684865SobrienRedistribution and use in source and binary forms, with or without 784865Sobrienmodification, are permitted provided that the following conditions are met: 884865Sobrien 984865Sobrien 1. Redistributions of source code must retain the above copyright notice, 1084865Sobrien this list of conditions and the following disclaimer. 1184865Sobrien 1284865Sobrien 2. Redistributions in binary form must reproduce the above copyright 1384865Sobrien notice, this list of conditions and the following disclaimer in the 1484865Sobrien documentation and/or other materials provided with the distribution. 1584865Sobrien 1684865Sobrien 3. Neither the name of the Intel Corporation nor the names of its 1784865Sobrien contributors may be used to endorse or promote products derived from 1884865Sobrien this software without specific prior written permission. 1984865Sobrien 2084865SobrienTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2184865SobrienAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22218822SdimIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2384865SobrienARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24218822SdimLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2584865SobrienCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2689857SobrienSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2784865SobrienINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2884865SobrienCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2989857SobrienARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3084865SobrienPOSSIBILITY OF SUCH DAMAGE. 3184865Sobrien 3289857Sobrien***************************************************************************/ 3384865Sobrien 34130561Sobrien/*$FreeBSD: head/sys/dev/em/if_em.c 121816 2003-10-31 18:32:15Z brooks $*/ 35130561Sobrien 36130561Sobrien#include <dev/em/if_em.h> 37130561Sobrien 38130561Sobrien/********************************************************************* 39130561Sobrien * Set this to one to display debug statistics 4089857Sobrien *********************************************************************/ 4189857Sobrienint em_display_debug_stats = 0; 42130561Sobrien 43130561Sobrien/********************************************************************* 44130561Sobrien * Linked list of board private structures for all NICs found 45130561Sobrien *********************************************************************/ 46130561Sobrien 47130561Sobrienstruct adapter *em_adapter_list = NULL; 48130561Sobrien 49130561Sobrien 50130561Sobrien/********************************************************************* 51130561Sobrien * Driver version 52130561Sobrien *********************************************************************/ 5389857Sobrien 54130561Sobrienchar em_driver_version[] = "1.7.16"; 55130561Sobrien 56130561Sobrien 57218822Sdim/********************************************************************* 58130561Sobrien * PCI Device ID Table 59130561Sobrien * 60130561Sobrien * Used by probe to select devices to load on 61130561Sobrien * Last field stores an index into em_strings 62130561Sobrien * Last entry must be all 0s 63130561Sobrien * 64130561Sobrien * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 65130561Sobrien *********************************************************************/ 66130561Sobrien 67130561Sobrienstatic em_vendor_info_t em_vendor_info_array[] = 68130561Sobrien{ 69130561Sobrien /* Intel(R) PRO/1000 Network Connection */ 7089857Sobrien { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0}, 71104834Sobrien { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0}, 72130561Sobrien { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0}, 73130561Sobrien { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0}, 7489857Sobrien { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0}, 7589857Sobrien { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0}, 7689857Sobrien { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0}, 7789857Sobrien { 0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0}, 7889857Sobrien { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0}, 7989857Sobrien { 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0}, 8089857Sobrien { 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0}, 8189857Sobrien { 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0}, 8289857Sobrien { 0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0}, 8389857Sobrien { 0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0}, 8489857Sobrien { 0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0}, 8589857Sobrien { 0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0}, 8689857Sobrien { 0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0}, 8789857Sobrien { 0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0}, 8889857Sobrien { 0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0}, 8989857Sobrien { 0x8086, 0x101A, PCI_ANY_ID, PCI_ANY_ID, 0}, 9089857Sobrien { 0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0}, 91104834Sobrien { 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0}, 9289857Sobrien { 0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0}, 9389857Sobrien { 0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0}, 9489857Sobrien { 0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0}, 9589857Sobrien { 0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0}, 96218822Sdim { 0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0}, 9789857Sobrien { 0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0}, 98130561Sobrien { 0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0}, 99130561Sobrien { 0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0}, 100130561Sobrien { 0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0}, 101104834Sobrien { 0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0}, 102130561Sobrien /* required last entry */ 103130561Sobrien { 0, 0, 0, 0, 0} 104130561Sobrien}; 105130561Sobrien 10689857Sobrien/********************************************************************* 10789857Sobrien * Table of branding strings for all supported NICs. 10889857Sobrien *********************************************************************/ 10989857Sobrien 11089857Sobrienstatic char *em_strings[] = { 11189857Sobrien "Intel(R) PRO/1000 Network Connection" 11289857Sobrien}; 11389857Sobrien 11489857Sobrien/********************************************************************* 11589857Sobrien * Function prototypes 11689857Sobrien *********************************************************************/ 11789857Sobrienstatic int em_probe(device_t); 11889857Sobrienstatic int em_attach(device_t); 11989857Sobrienstatic int em_detach(device_t); 12089857Sobrienstatic int em_shutdown(device_t); 12189857Sobrienstatic void em_intr(void *); 12289857Sobrienstatic void em_start(struct ifnet *); 12389857Sobrienstatic int em_ioctl(struct ifnet *, u_long, caddr_t); 12489857Sobrienstatic void em_watchdog(struct ifnet *); 12589857Sobrienstatic void em_init(void *); 126104834Sobrienstatic void em_init_locked(struct adapter *); 127104834Sobrienstatic void em_stop(void *); 128104834Sobrienstatic void em_media_status(struct ifnet *, struct ifmediareq *); 12989857Sobrienstatic int em_media_change(struct ifnet *); 13089857Sobrienstatic void em_identify_hardware(struct adapter *); 13189857Sobrienstatic int em_allocate_pci_resources(struct adapter *); 13284865Sobrienstatic void em_free_pci_resources(struct adapter *); 13384865Sobrienstatic void em_local_timer(void *); 134130561Sobrienstatic int em_hardware_init(struct adapter *); 135130561Sobrienstatic void em_setup_interface(device_t, struct adapter *); 136130561Sobrienstatic int em_setup_transmit_structures(struct adapter *); 13789857Sobrienstatic void em_initialize_transmit_unit(struct adapter *); 138130561Sobrienstatic int em_setup_receive_structures(struct adapter *); 13989857Sobrienstatic void em_initialize_receive_unit(struct adapter *); 140130561Sobrienstatic void em_enable_intr(struct adapter *); 141130561Sobrienstatic void em_disable_intr(struct adapter *); 142130561Sobrienstatic void em_free_transmit_structures(struct adapter *); 143130561Sobrienstatic void em_free_receive_structures(struct adapter *); 14489857Sobrienstatic void em_update_stats_counters(struct adapter *); 14589857Sobrienstatic void em_clean_transmit_interrupts(struct adapter *); 14689857Sobrienstatic int em_allocate_receive_structures(struct adapter *); 14789857Sobrienstatic int em_allocate_transmit_structures(struct adapter *); 14889857Sobrienstatic void em_process_receive_interrupts(struct adapter *, int); 14989857Sobrienstatic void em_receive_checksum(struct adapter *, 15089857Sobrien struct em_rx_desc *, 15189857Sobrien struct mbuf *); 15289857Sobrienstatic void em_transmit_checksum_setup(struct adapter *, 15389857Sobrien struct mbuf *, 15489857Sobrien u_int32_t *, 15589857Sobrien u_int32_t *); 156130561Sobrienstatic void em_set_promisc(struct adapter *); 15789857Sobrienstatic void em_disable_promisc(struct adapter *); 15889857Sobrienstatic void em_set_multi(struct adapter *); 159130561Sobrienstatic void em_print_hw_stats(struct adapter *); 16089857Sobrienstatic void em_print_link_status(struct adapter *); 16189857Sobrienstatic int em_get_buf(int i, struct adapter *, 16289857Sobrien struct mbuf *); 16389857Sobrienstatic void em_enable_vlans(struct adapter *); 164130561Sobrienstatic int em_encap(struct adapter *, struct mbuf *); 165130561Sobrienstatic void em_smartspeed(struct adapter *); 166130561Sobrienstatic int em_82547_fifo_workaround(struct adapter *, int); 167130561Sobrienstatic void em_82547_update_fifo_head(struct adapter *, int); 16889857Sobrienstatic int em_82547_tx_fifo_reset(struct adapter *); 16989857Sobrienstatic void em_82547_move_tail(void *arg); 17089857Sobrienstatic void em_82547_move_tail_locked(struct adapter *); 17189857Sobrienstatic int em_dma_malloc(struct adapter *, bus_size_t, 172130561Sobrien struct em_dma_alloc *, int); 173130561Sobrienstatic void em_dma_free(struct adapter *, struct em_dma_alloc *); 174130561Sobrienstatic void em_print_debug_info(struct adapter *); 175130561Sobrienstatic int em_is_valid_ether_addr(u_int8_t *); 176130561Sobrienstatic int em_sysctl_stats(SYSCTL_HANDLER_ARGS); 177130561Sobrienstatic int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); 178130561Sobrienstatic u_int32_t em_fill_descriptors (u_int64_t address, 179218822Sdim u_int32_t length, 18084865Sobrien PDESC_ARRAY desc_array); 181104834Sobrienstatic int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); 182130561Sobrienstatic void em_add_int_delay_sysctl(struct adapter *, const char *, 183130561Sobrien const char *, struct em_int_delay_info *, 18489857Sobrien int, int); 185130561Sobrien 186104834Sobrien/********************************************************************* 187130561Sobrien * FreeBSD Device Interface Entry Points 188104834Sobrien *********************************************************************/ 189130561Sobrien 190104834Sobrienstatic device_method_t em_methods[] = { 191130561Sobrien /* Device interface */ 192104834Sobrien DEVMETHOD(device_probe, em_probe), 193104834Sobrien DEVMETHOD(device_attach, em_attach), 194130561Sobrien DEVMETHOD(device_detach, em_detach), 195104834Sobrien DEVMETHOD(device_shutdown, em_shutdown), 196104834Sobrien {0, 0} 197130561Sobrien}; 198130561Sobrien 199130561Sobrienstatic driver_t em_driver = { 200130561Sobrien "em", em_methods, sizeof(struct adapter ), 201104834Sobrien}; 202130561Sobrien 203130561Sobrienstatic devclass_t em_devclass; 204130561SobrienDRIVER_MODULE(em, pci, em_driver, em_devclass, 0, 0); 205130561SobrienMODULE_DEPEND(em, pci, 1, 1, 1); 206130561SobrienMODULE_DEPEND(em, ether, 1, 1, 1); 207130561Sobrien 208130561Sobrien/********************************************************************* 209130561Sobrien * Tunable default values. 210130561Sobrien *********************************************************************/ 211130561Sobrien 212104834Sobrien#define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) 213130561Sobrien#define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) 214130561Sobrien 215130561Sobrienstatic int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV); 216130561Sobrienstatic int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR); 217104834Sobrienstatic int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV); 218104834Sobrienstatic int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV); 219130561Sobrien 220104834SobrienTUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); 221130561SobrienTUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt); 222130561SobrienTUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt); 223130561SobrienTUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt); 224130561Sobrien 225104834Sobrien/********************************************************************* 226104834Sobrien * Device identification routine 227130561Sobrien * 228104834Sobrien * em_probe determines if the driver should be loaded on 229104834Sobrien * adapter based on PCI vendor/device id of the adapter. 230104834Sobrien * 231104834Sobrien * return 0 on success, positive on failure 232104834Sobrien *********************************************************************/ 233104834Sobrien 234104834Sobrienstatic int 235104834Sobrienem_probe(device_t dev) 23684865Sobrien{ 23784865Sobrien em_vendor_info_t *ent; 23884865Sobrien 239130561Sobrien u_int16_t pci_vendor_id = 0; 24084865Sobrien u_int16_t pci_device_id = 0; 24184865Sobrien u_int16_t pci_subvendor_id = 0; 24284865Sobrien u_int16_t pci_subdevice_id = 0; 24384865Sobrien char adapter_name[60]; 24489857Sobrien 24584865Sobrien INIT_DEBUGOUT("em_probe: begin"); 24689857Sobrien 24784865Sobrien pci_vendor_id = pci_get_vendor(dev); 248130561Sobrien if (pci_vendor_id != EM_VENDOR_ID) 24984865Sobrien return(ENXIO); 25084865Sobrien 25184865Sobrien pci_device_id = pci_get_device(dev); 25284865Sobrien pci_subvendor_id = pci_get_subvendor(dev); 25384865Sobrien pci_subdevice_id = pci_get_subdevice(dev); 25484865Sobrien 25584865Sobrien ent = em_vendor_info_array; 25684865Sobrien while (ent->vendor_id != 0) { 25784865Sobrien if ((pci_vendor_id == ent->vendor_id) && 25884865Sobrien (pci_device_id == ent->device_id) && 25984865Sobrien 26084865Sobrien ((pci_subvendor_id == ent->subvendor_id) || 26184865Sobrien (ent->subvendor_id == PCI_ANY_ID)) && 26284865Sobrien 26384865Sobrien ((pci_subdevice_id == ent->subdevice_id) || 26489857Sobrien (ent->subdevice_id == PCI_ANY_ID))) { 265104834Sobrien sprintf(adapter_name, "%s, Version - %s", 26689857Sobrien em_strings[ent->index], 267130561Sobrien em_driver_version); 26884865Sobrien device_set_desc_copy(dev, adapter_name); 26984865Sobrien return(0); 27084865Sobrien } 27184865Sobrien ent++; 272130561Sobrien } 27384865Sobrien 27484865Sobrien return(ENXIO); 27584865Sobrien} 27684865Sobrien 27784865Sobrien/********************************************************************* 27884865Sobrien * Device initialization routine 27984865Sobrien * 28084865Sobrien * The attach entry point is called when the driver is being loaded. 281130561Sobrien * This routine identifies the type of hardware, allocates all resources 28284865Sobrien * and initializes the hardware. 28384865Sobrien * 28484865Sobrien * return 0 on success, positive on failure 28584865Sobrien *********************************************************************/ 28684865Sobrien 28784865Sobrienstatic int 28884865Sobrienem_attach(device_t dev) 28984865Sobrien{ 29084865Sobrien struct adapter * adapter; 29184865Sobrien int tsize, rsize; 29284865Sobrien int error = 0; 29384865Sobrien 29484865Sobrien INIT_DEBUGOUT("em_attach: begin"); 29584865Sobrien 29684865Sobrien /* Allocate, clear, and link in our adapter structure */ 29784865Sobrien if (!(adapter = device_get_softc(dev))) { 29884865Sobrien printf("em: adapter structure allocation failed\n"); 29984865Sobrien return(ENOMEM); 30084865Sobrien } 30184865Sobrien bzero(adapter, sizeof(struct adapter )); 30284865Sobrien adapter->dev = dev; 30384865Sobrien adapter->osdep.dev = dev; 30484865Sobrien adapter->unit = device_get_unit(dev); 30584865Sobrien EM_LOCK_INIT(adapter, device_get_nameunit(dev)); 306104834Sobrien 307104834Sobrien if (em_adapter_list != NULL) 30884865Sobrien em_adapter_list->prev = adapter; 30984865Sobrien adapter->next = em_adapter_list; 31084865Sobrien em_adapter_list = adapter; 31184865Sobrien 312130561Sobrien /* SYSCTL stuff */ 31384865Sobrien sysctl_ctx_init(&adapter->sysctl_ctx); 31484865Sobrien adapter->sysctl_tree = SYSCTL_ADD_NODE(&adapter->sysctl_ctx, 31584865Sobrien SYSCTL_STATIC_CHILDREN(_hw), 31684865Sobrien OID_AUTO, 31784865Sobrien device_get_nameunit(dev), 31884865Sobrien CTLFLAG_RD, 31984865Sobrien 0, ""); 320130561Sobrien if (adapter->sysctl_tree == NULL) { 32184865Sobrien error = EIO; 32284865Sobrien goto err_sysctl; 32384865Sobrien } 32484865Sobrien 325130561Sobrien SYSCTL_ADD_PROC(&adapter->sysctl_ctx, 32684865Sobrien SYSCTL_CHILDREN(adapter->sysctl_tree), 32784865Sobrien OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW, 32884865Sobrien (void *)adapter, 0, 32984865Sobrien em_sysctl_debug_info, "I", "Debug Information"); 330130561Sobrien 33184865Sobrien SYSCTL_ADD_PROC(&adapter->sysctl_ctx, 33284865Sobrien SYSCTL_CHILDREN(adapter->sysctl_tree), 33384865Sobrien OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, 33484865Sobrien (void *)adapter, 0, 33589857Sobrien em_sysctl_stats, "I", "Statistics"); 33684865Sobrien 33784865Sobrien callout_init(&adapter->timer, CALLOUT_MPSAFE); 33884865Sobrien callout_init(&adapter->tx_fifo_timer, CALLOUT_MPSAFE); 339130561Sobrien 34084865Sobrien /* Determine hardware revision */ 34184865Sobrien em_identify_hardware(adapter); 34284865Sobrien 34384865Sobrien /* Set up some sysctls for the tunable interrupt delays */ 34489857Sobrien em_add_int_delay_sysctl(adapter, "rx_int_delay", 34584865Sobrien "receive interrupt delay in usecs", &adapter->rx_int_delay, 34684865Sobrien E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt); 34789857Sobrien em_add_int_delay_sysctl(adapter, "tx_int_delay", 34889857Sobrien "transmit interrupt delay in usecs", &adapter->tx_int_delay, 34989857Sobrien E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt); 35089857Sobrien if (adapter->hw.mac_type >= em_82540) { 35189857Sobrien em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", 35284865Sobrien "receive interrupt delay limit in usecs", 35384865Sobrien &adapter->rx_abs_int_delay, 35484865Sobrien E1000_REG_OFFSET(&adapter->hw, RADV), 35584865Sobrien em_rx_abs_int_delay_dflt); 356130561Sobrien em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", 357130561Sobrien "transmit interrupt delay limit in usecs", 358130561Sobrien &adapter->tx_abs_int_delay, 35984865Sobrien E1000_REG_OFFSET(&adapter->hw, TADV), 36084865Sobrien em_tx_abs_int_delay_dflt); 36184865Sobrien } 36284865Sobrien 36384865Sobrien /* Parameters (to be read from user) */ 36484865Sobrien adapter->num_tx_desc = EM_MAX_TXD; 365130561Sobrien adapter->num_rx_desc = EM_MAX_RXD; 36684865Sobrien adapter->hw.autoneg = DO_AUTO_NEG; 36784865Sobrien adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; 36884865Sobrien adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; 36989857Sobrien adapter->hw.tbi_compatibility_en = TRUE; 37089857Sobrien adapter->rx_buffer_len = EM_RXBUFFER_2048; 37184865Sobrien 37284865Sobrien /* 37389857Sobrien * These parameters control the automatic generation(Tx) and 37489857Sobrien * response(Rx) to Ethernet PAUSE frames. 37589857Sobrien */ 37689857Sobrien adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH; 37789857Sobrien adapter->hw.fc_low_water = FC_DEFAULT_LO_THRESH; 37884865Sobrien adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER; 37984865Sobrien adapter->hw.fc_send_xon = TRUE; 38084865Sobrien adapter->hw.fc = em_fc_full; 38184865Sobrien 38284865Sobrien adapter->hw.phy_init_script = 1; 383130561Sobrien adapter->hw.phy_reset_disable = FALSE; 384130561Sobrien 385130561Sobrien#ifndef EM_MASTER_SLAVE 386130561Sobrien adapter->hw.master_slave = em_ms_hw_default; 387130561Sobrien#else 388130561Sobrien adapter->hw.master_slave = EM_MASTER_SLAVE; 389130561Sobrien#endif 39084865Sobrien /* 39189857Sobrien * Set the max frame size assuming standard ethernet 39284865Sobrien * sized frames 39384865Sobrien */ 39489857Sobrien adapter->hw.max_frame_size = 39589857Sobrien ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; 39684865Sobrien 39789857Sobrien adapter->hw.min_frame_size = 39889857Sobrien MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; 39984865Sobrien 40084865Sobrien /* 40189857Sobrien * This controls when hardware reports transmit completion 40289857Sobrien * status. 40389857Sobrien */ 40489857Sobrien adapter->hw.report_tx_early = 1; 40589857Sobrien 40689857Sobrien 40789857Sobrien if (em_allocate_pci_resources(adapter)) { 40889857Sobrien printf("em%d: Allocation of PCI resources failed\n", 40989857Sobrien adapter->unit); 41089857Sobrien error = ENXIO; 41189857Sobrien goto err_pci; 41289857Sobrien } 41389857Sobrien 41489857Sobrien 41589857Sobrien /* Initialize eeprom parameters */ 41684865Sobrien em_init_eeprom_params(&adapter->hw); 41784865Sobrien 41884865Sobrien tsize = EM_ROUNDUP(adapter->num_tx_desc * 41984865Sobrien sizeof(struct em_tx_desc), 4096); 42084865Sobrien 42184865Sobrien /* Allocate Transmit Descriptor ring */ 42284865Sobrien if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) { 42389857Sobrien printf("em%d: Unable to allocate tx_desc memory\n", 42489857Sobrien adapter->unit); 42589857Sobrien error = ENOMEM; 42684865Sobrien goto err_tx_desc; 42784865Sobrien } 42884865Sobrien adapter->tx_desc_base = (struct em_tx_desc *) adapter->txdma.dma_vaddr; 42989857Sobrien 43089857Sobrien rsize = EM_ROUNDUP(adapter->num_rx_desc * 43189857Sobrien sizeof(struct em_rx_desc), 4096); 43289857Sobrien 43384865Sobrien /* Allocate Receive Descriptor ring */ 43484865Sobrien if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) { 43584865Sobrien printf("em%d: Unable to allocate rx_desc memory\n", 43684865Sobrien adapter->unit); 43784865Sobrien error = ENOMEM; 43884865Sobrien goto err_rx_desc; 43984865Sobrien } 44089857Sobrien adapter->rx_desc_base = (struct em_rx_desc *) adapter->rxdma.dma_vaddr; 44189857Sobrien 44289857Sobrien /* Initialize the hardware */ 44389857Sobrien if (em_hardware_init(adapter)) { 44489857Sobrien printf("em%d: Unable to initialize the hardware\n", 44584865Sobrien adapter->unit); 446130561Sobrien error = EIO; 44784865Sobrien goto err_hw_init; 44884865Sobrien } 44984865Sobrien 45084865Sobrien /* Copy the permanent MAC address out of the EEPROM */ 45184865Sobrien if (em_read_mac_addr(&adapter->hw) < 0) { 45284865Sobrien printf("em%d: EEPROM read error while reading mac address\n", 45384865Sobrien adapter->unit); 45484865Sobrien error = EIO; 45584865Sobrien goto err_mac_addr; 45689857Sobrien } 45789857Sobrien 45884865Sobrien if (!em_is_valid_ether_addr(adapter->hw.mac_addr)) { 45984865Sobrien printf("em%d: Invalid mac address\n", adapter->unit); 46084865Sobrien error = EIO; 46189857Sobrien goto err_mac_addr; 46289857Sobrien } 46389857Sobrien 46489857Sobrien bcopy(adapter->hw.mac_addr, adapter->interface_data.ac_enaddr, 46584865Sobrien ETHER_ADDR_LEN); 46684865Sobrien 46784865Sobrien /* Setup OS specific network interface */ 46884865Sobrien em_setup_interface(dev, adapter); 46989857Sobrien 47084865Sobrien /* Initialize statistics */ 47189857Sobrien em_clear_hw_cntrs(&adapter->hw); 47284865Sobrien em_update_stats_counters(adapter); 47389857Sobrien adapter->hw.get_link_status = 1; 47484865Sobrien em_check_for_link(&adapter->hw); 47589857Sobrien 47684865Sobrien /* Print the link status */ 47784865Sobrien if (adapter->link_active == 1) { 47889857Sobrien em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, 47989857Sobrien &adapter->link_duplex); 48089857Sobrien printf("em%d: Speed:%d Mbps Duplex:%s\n", 48189857Sobrien adapter->unit, 48289857Sobrien adapter->link_speed, 48389857Sobrien adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half"); 48489857Sobrien } else 48589857Sobrien printf("em%d: Speed:N/A Duplex:N/A\n", adapter->unit); 48689857Sobrien 48789857Sobrien /* Identify 82544 on PCIX */ 48889857Sobrien em_get_bus_info(&adapter->hw); 48989857Sobrien if(adapter->hw.bus_type == em_bus_type_pcix && 49089857Sobrien adapter->hw.mac_type == em_82544) { 49189857Sobrien adapter->pcix_82544 = TRUE; 49284865Sobrien } 49384865Sobrien else { 49484865Sobrien adapter->pcix_82544 = FALSE; 49589857Sobrien } 496130561Sobrien INIT_DEBUGOUT("em_attach: end"); 497130561Sobrien return(0); 49889857Sobrien 49984865Sobrienerr_mac_addr: 50084865Sobrienerr_hw_init: 50189857Sobrien em_dma_free(adapter, &adapter->rxdma); 50289857Sobrienerr_rx_desc: 50384865Sobrien em_dma_free(adapter, &adapter->txdma); 50484865Sobrienerr_tx_desc: 50584865Sobrienerr_pci: 50684865Sobrien em_free_pci_resources(adapter); 50789857Sobrien sysctl_ctx_free(&adapter->sysctl_ctx); 50884865Sobrienerr_sysctl: 50984865Sobrien return(error); 51084865Sobrien 51184865Sobrien} 512130561Sobrien 51384865Sobrien/********************************************************************* 51484865Sobrien * Device removal routine 51589857Sobrien * 51689857Sobrien * The detach entry point is called when the driver is being removed. 51789857Sobrien * This routine stops the adapter and deallocates all the resources 51889857Sobrien * that were allocated for driver operation. 51989857Sobrien * 52089857Sobrien * return 0 on success, positive on failure 52189857Sobrien *********************************************************************/ 52289857Sobrien 52389857Sobrienstatic int 52489857Sobrienem_detach(device_t dev) 52589857Sobrien{ 52684865Sobrien struct adapter * adapter = device_get_softc(dev); 52789857Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 52889857Sobrien 52989857Sobrien INIT_DEBUGOUT("em_detach: begin"); 53089857Sobrien 53189857Sobrien EM_LOCK(adapter); 53289857Sobrien em_stop(adapter); 53389857Sobrien em_phy_hw_reset(&adapter->hw); 53489857Sobrien EM_UNLOCK(adapter); 53589857Sobrien#if __FreeBSD_version < 500000 53689857Sobrien ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED); 53789857Sobrien#else 53889857Sobrien ether_ifdetach(&adapter->interface_data.ac_if); 53989857Sobrien#endif 54089857Sobrien em_free_pci_resources(adapter); 54189857Sobrien 54289857Sobrien /* Free Transmit Descriptor ring */ 54389857Sobrien if (adapter->tx_desc_base) { 54489857Sobrien em_dma_free(adapter, &adapter->txdma); 54584865Sobrien adapter->tx_desc_base = NULL; 54689857Sobrien } 54789857Sobrien 54889857Sobrien /* Free Receive Descriptor ring */ 54989857Sobrien if (adapter->rx_desc_base) { 55089857Sobrien em_dma_free(adapter, &adapter->rxdma); 55189857Sobrien adapter->rx_desc_base = NULL; 55289857Sobrien } 55389857Sobrien 55489857Sobrien /* Free the sysctl tree */ 55589857Sobrien sysctl_ctx_free(&adapter->sysctl_ctx); 55689857Sobrien 55784865Sobrien /* Remove from the adapter list */ 55884865Sobrien if (em_adapter_list == adapter) 55989857Sobrien em_adapter_list = adapter->next; 56089857Sobrien if (adapter->next != NULL) 56184865Sobrien adapter->next->prev = adapter->prev; 56284865Sobrien if (adapter->prev != NULL) 56384865Sobrien adapter->prev->next = adapter->next; 56489857Sobrien 56589857Sobrien EM_LOCK_DESTROY(adapter); 56689857Sobrien 56789857Sobrien ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 56884865Sobrien ifp->if_timer = 0; 56984865Sobrien 57084865Sobrien return(0); 57189857Sobrien} 57289857Sobrien 57389857Sobrien/********************************************************************* 57489857Sobrien * 57589857Sobrien * Shutdown entry point 57689857Sobrien * 57789857Sobrien **********************************************************************/ 57889857Sobrien 57984865Sobrienstatic int 58084865Sobrienem_shutdown(device_t dev) 58184865Sobrien{ 58289857Sobrien struct adapter *adapter = device_get_softc(dev); 58384865Sobrien EM_LOCK(adapter); 58484865Sobrien em_stop(adapter); 58589857Sobrien EM_UNLOCK(adapter); 58689857Sobrien return(0); 58789857Sobrien} 58889857Sobrien 58984865Sobrien 59084865Sobrien/********************************************************************* 59184865Sobrien * Transmit entry point 59284865Sobrien * 59384865Sobrien * em_start is called by the stack to initiate a transmit. 59489857Sobrien * The driver will remain in this routine as long as there are 59589857Sobrien * packets to transmit and transmit resources are available. 59684865Sobrien * In case resources are not available stack is notified and 59784865Sobrien * the packet is requeued. 59884865Sobrien **********************************************************************/ 59984865Sobrien 60084865Sobrienstatic void 60184865Sobrienem_start_locked(struct ifnet *ifp) 60284865Sobrien{ 60384865Sobrien struct mbuf *m_head; 60484865Sobrien struct adapter *adapter = ifp->if_softc; 60584865Sobrien 60684865Sobrien mtx_assert(&adapter->mtx, MA_OWNED); 607130561Sobrien 608130561Sobrien if (!adapter->link_active) 609130561Sobrien return; 610130561Sobrien 611130561Sobrien while (ifp->if_snd.ifq_head != NULL) { 612130561Sobrien 61384865Sobrien IF_DEQUEUE(&ifp->if_snd, m_head); 614130561Sobrien 615130561Sobrien if (m_head == NULL) break; 616130561Sobrien 617130561Sobrien if (em_encap(adapter, m_head)) { 618130561Sobrien ifp->if_flags |= IFF_OACTIVE; 619130561Sobrien IF_PREPEND(&ifp->if_snd, m_head); 62084865Sobrien break; 62184865Sobrien } 622130561Sobrien 623130561Sobrien /* Send a copy of the frame to the BPF listener */ 624130561Sobrien#if __FreeBSD_version < 500000 625130561Sobrien if (ifp->if_bpf) 626130561Sobrien bpf_mtap(ifp, m_head); 627130561Sobrien#else 62884865Sobrien BPF_MTAP(ifp, m_head); 629130561Sobrien#endif 630130561Sobrien 631130561Sobrien /* Set timeout in case hardware has problems transmitting */ 632130561Sobrien ifp->if_timer = EM_TX_TIMEOUT; 633130561Sobrien 634130561Sobrien } 63584865Sobrien return; 63684865Sobrien} 637130561Sobrien 638130561Sobrienstatic void 639130561Sobrienem_start(struct ifnet *ifp) 640130561Sobrien{ 641130561Sobrien struct adapter *adapter = ifp->if_softc; 642130561Sobrien 64384865Sobrien EM_LOCK(adapter); 644130561Sobrien em_start_locked(ifp); 645130561Sobrien EM_UNLOCK(adapter); 646130561Sobrien return; 647130561Sobrien} 648130561Sobrien 649130561Sobrien/********************************************************************* 65084865Sobrien * Ioctl entry point 65184865Sobrien * 652130561Sobrien * em_ioctl is called when the user wants to configure the 653130561Sobrien * interface. 654130561Sobrien * 655130561Sobrien * return 0 on success, positive on failure 656130561Sobrien **********************************************************************/ 657130561Sobrien 65884865Sobrienstatic int 659130561Sobrienem_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 660130561Sobrien{ 661130561Sobrien int mask, error = 0; 662130561Sobrien struct ifreq *ifr = (struct ifreq *) data; 663130561Sobrien struct adapter * adapter = ifp->if_softc; 664130561Sobrien 66584865Sobrien switch (command) { 66684865Sobrien case SIOCSIFADDR: 667130561Sobrien case SIOCGIFADDR: 668130561Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)"); 669130561Sobrien ether_ioctl(ifp, command, data); 670130561Sobrien break; 671130561Sobrien case SIOCSIFMTU: 672130561Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)"); 67384865Sobrien if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN) { 674130561Sobrien error = EINVAL; 675130561Sobrien } else { 676130561Sobrien EM_LOCK(adapter); 677130561Sobrien ifp->if_mtu = ifr->ifr_mtu; 678130561Sobrien adapter->hw.max_frame_size = 679130561Sobrien ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 68084865Sobrien em_init_locked(adapter); 68184865Sobrien EM_UNLOCK(adapter); 682130561Sobrien } 683130561Sobrien break; 684104834Sobrien case SIOCSIFFLAGS: 685130561Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); 686130561Sobrien EM_LOCK(adapter); 687130561Sobrien if (ifp->if_flags & IFF_UP) { 68884865Sobrien if (!(ifp->if_flags & IFF_RUNNING)) { 689130561Sobrien bcopy(IF_LLADDR(ifp), adapter->hw.mac_addr, 690130561Sobrien ETHER_ADDR_LEN); 691130561Sobrien em_init_locked(adapter); 692130561Sobrien } 693130561Sobrien 694130561Sobrien em_disable_promisc(adapter); 69584865Sobrien em_set_promisc(adapter); 696130561Sobrien } else { 697130561Sobrien if (ifp->if_flags & IFF_RUNNING) { 698130561Sobrien em_stop(adapter); 699104834Sobrien } 700130561Sobrien } 701130561Sobrien EM_UNLOCK(adapter); 702130561Sobrien break; 70384865Sobrien case SIOCADDMULTI: 704130561Sobrien case SIOCDELMULTI: 705130561Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI"); 706130561Sobrien if (ifp->if_flags & IFF_RUNNING) { 707130561Sobrien EM_LOCK(adapter); 708130561Sobrien em_disable_intr(adapter); 709130561Sobrien em_set_multi(adapter); 71084865Sobrien if (adapter->hw.mac_type == em_82542_rev2_0) { 71184865Sobrien em_initialize_receive_unit(adapter); 71284865Sobrien } 71384865Sobrien#ifdef DEVICE_POLLING 714130561Sobrien if (!(ifp->if_ipending & IFF_POLLING)) 715130561Sobrien#endif 716130561Sobrien em_enable_intr(adapter); 717130561Sobrien EM_UNLOCK(adapter); 718130561Sobrien } 719130561Sobrien break; 72084865Sobrien case SIOCSIFMEDIA: 721130561Sobrien case SIOCGIFMEDIA: 722130561Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)"); 723130561Sobrien error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); 724104834Sobrien break; 725104834Sobrien case SIOCSIFCAP: 726130561Sobrien IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)"); 72784865Sobrien mask = ifr->ifr_reqcap ^ ifp->if_capenable; 72884865Sobrien if (mask & IFCAP_HWCSUM) { 72984865Sobrien if (IFCAP_HWCSUM & ifp->if_capenable) 73084865Sobrien ifp->if_capenable &= ~IFCAP_HWCSUM; 731130561Sobrien else 732130561Sobrien ifp->if_capenable |= IFCAP_HWCSUM; 733130561Sobrien if (ifp->if_flags & IFF_RUNNING) 734130561Sobrien em_init(adapter); 735130561Sobrien } 736130561Sobrien break; 73784865Sobrien default: 738130561Sobrien IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)\n", (int)command); 739130561Sobrien error = EINVAL; 740130561Sobrien } 741130561Sobrien 742130561Sobrien return(error); 743130561Sobrien} 74484865Sobrien 74584865Sobrien/********************************************************************* 74684865Sobrien * Watchdog entry point 74784865Sobrien * 748130561Sobrien * This routine is called whenever hardware quits transmitting. 749130561Sobrien * 750104834Sobrien **********************************************************************/ 751130561Sobrien 752130561Sobrienstatic void 753130561Sobrienem_watchdog(struct ifnet *ifp) 75484865Sobrien{ 755130561Sobrien struct adapter * adapter; 756130561Sobrien adapter = ifp->if_softc; 757130561Sobrien 758130561Sobrien /* If we are in this routine because of pause frames, then 759130561Sobrien * don't reset the hardware. 760130561Sobrien */ 76184865Sobrien if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) { 76284865Sobrien ifp->if_timer = EM_TX_TIMEOUT; 763130561Sobrien return; 764130561Sobrien } 765104834Sobrien 766130561Sobrien printf("em%d: watchdog timeout -- resetting\n", adapter->unit); 767130561Sobrien 768130561Sobrien ifp->if_flags &= ~IFF_RUNNING; 76984865Sobrien 770130561Sobrien em_stop(adapter); 771130561Sobrien em_init(adapter); 772130561Sobrien 773130561Sobrien ifp->if_oerrors++; 774130561Sobrien return; 775130561Sobrien} 77684865Sobrien 77784865Sobrien/********************************************************************* 77884865Sobrien * Init entry point 77984865Sobrien * 780130561Sobrien * This routine is used in two ways. It is used by the stack as 781130561Sobrien * init entry point in network interface structure. It is also used 782130561Sobrien * by the driver as a hw/sw initialization routine to get to a 783130561Sobrien * consistent state. 784130561Sobrien * 785130561Sobrien * return 0 on success, positive on failure 786104834Sobrien **********************************************************************/ 787130561Sobrien 788130561Sobrienstatic void 789130561Sobrienem_init_locked(struct adapter * adapter) 790130561Sobrien{ 791130561Sobrien struct ifnet *ifp; 792130561Sobrien 79384865Sobrien INIT_DEBUGOUT("em_init: begin"); 79484865Sobrien 79584865Sobrien mtx_assert(&adapter->mtx, MA_OWNED); 79684865Sobrien 79784865Sobrien em_stop(adapter); 798130561Sobrien 799130561Sobrien /* Initialize the hardware */ 800104834Sobrien if (em_hardware_init(adapter)) { 801130561Sobrien printf("em%d: Unable to initialize the hardware\n", 802130561Sobrien adapter->unit); 803130561Sobrien return; 80484865Sobrien } 805130561Sobrien 806130561Sobrien em_enable_vlans(adapter); 807130561Sobrien 808130561Sobrien /* Prepare transmit descriptors and buffers */ 809130561Sobrien if (em_setup_transmit_structures(adapter)) { 810130561Sobrien printf("em%d: Could not setup transmit structures\n", 81184865Sobrien adapter->unit); 81284865Sobrien em_stop(adapter); 813130561Sobrien return; 814130561Sobrien } 815104834Sobrien em_initialize_transmit_unit(adapter); 816130561Sobrien 817130561Sobrien /* Setup Multicast table */ 818130561Sobrien em_set_multi(adapter); 81984865Sobrien 820130561Sobrien /* Prepare receive descriptors and buffers */ 821130561Sobrien if (em_setup_receive_structures(adapter)) { 822130561Sobrien printf("em%d: Could not setup receive structures\n", 823130561Sobrien adapter->unit); 824130561Sobrien em_stop(adapter); 825130561Sobrien return; 82684865Sobrien } 82784865Sobrien em_initialize_receive_unit(adapter); 828130561Sobrien 829130561Sobrien ifp = &adapter->interface_data.ac_if; 830130561Sobrien ifp->if_flags |= IFF_RUNNING; 831130561Sobrien ifp->if_flags &= ~IFF_OACTIVE; 832130561Sobrien 833130561Sobrien if (adapter->hw.mac_type >= em_82543) { 83484865Sobrien if (ifp->if_capenable & IFCAP_TXCSUM) 835130561Sobrien ifp->if_hwassist = EM_CHECKSUM_FEATURES; 836130561Sobrien else 837130561Sobrien ifp->if_hwassist = 0; 838130561Sobrien } 839130561Sobrien 840130561Sobrien callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter); 84184865Sobrien em_clear_hw_cntrs(&adapter->hw); 84284865Sobrien#ifdef DEVICE_POLLING 843130561Sobrien /* 844130561Sobrien * Only enable interrupts if we are not polling, make sure 845130561Sobrien * they are off otherwise. 846130561Sobrien */ 847130561Sobrien if (ifp->if_ipending & IFF_POLLING) 848130561Sobrien em_disable_intr(adapter); 84984865Sobrien else 850130561Sobrien#endif /* DEVICE_POLLING */ 851130561Sobrien em_enable_intr(adapter); 852130561Sobrien 853130561Sobrien return; 854130561Sobrien} 855130561Sobrien 85684865Sobrienstatic void 85784865Sobrienem_init(void *arg) 858130561Sobrien{ 859130561Sobrien struct adapter * adapter = arg; 860104834Sobrien 861130561Sobrien EM_LOCK(adapter); 862130561Sobrien em_init_locked(adapter); 863130561Sobrien EM_UNLOCK(adapter); 86484865Sobrien return; 865130561Sobrien} 866130561Sobrien 867130561Sobrien 868130561Sobrien#ifdef DEVICE_POLLING 869130561Sobrienstatic poll_handler_t em_poll; 870130561Sobrien 87184865Sobrienstatic void 87284865Sobrienem_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 873130561Sobrien{ 874130561Sobrien struct adapter *adapter = ifp->if_softc; 875104834Sobrien u_int32_t reg_icr; 876130561Sobrien 877130561Sobrien mtx_assert(&adapter->mtx, MA_OWNED); 878130561Sobrien 87984865Sobrien if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ 880130561Sobrien em_enable_intr(adapter); 881130561Sobrien return; 882130561Sobrien } 883130561Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 884130561Sobrien reg_icr = E1000_READ_REG(&adapter->hw, ICR); 885130561Sobrien if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { 88684865Sobrien callout_stop(&adapter->timer); 88784865Sobrien adapter->hw.get_link_status = 1; 888130561Sobrien em_check_for_link(&adapter->hw); 889130561Sobrien em_print_link_status(adapter); 890130561Sobrien callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter); 891130561Sobrien } 892130561Sobrien } 893130561Sobrien if (ifp->if_flags & IFF_RUNNING) { 89484865Sobrien em_process_receive_interrupts(adapter, count); 895130561Sobrien em_clean_transmit_interrupts(adapter); 896130561Sobrien } 897130561Sobrien 898104834Sobrien if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) 899104834Sobrien em_start_locked(ifp); 900130561Sobrien} 90184865Sobrien 90284865Sobrienstatic void 903130561Sobrienem_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 904130561Sobrien{ 905130561Sobrien struct adapter *adapter = ifp->if_softc; 906130561Sobrien 907130561Sobrien EM_LOCK(adapter); 908130561Sobrien em_poll_locked(ifp, cmd, count); 90984865Sobrien EM_UNLOCK(adapter); 910130561Sobrien} 911130561Sobrien#endif /* DEVICE_POLLING */ 912130561Sobrien 913104834Sobrien/********************************************************************* 914104834Sobrien * 915130561Sobrien * Interrupt Service routine 91684865Sobrien * 91784865Sobrien **********************************************************************/ 918130561Sobrienstatic void 919130561Sobrienem_intr(void *arg) 920130561Sobrien{ 921130561Sobrien u_int32_t loop_cnt = EM_MAX_INTR; 922130561Sobrien u_int32_t reg_icr; 923130561Sobrien struct ifnet *ifp; 92484865Sobrien struct adapter *adapter = arg; 925130561Sobrien 926130561Sobrien EM_LOCK(adapter); 927130561Sobrien 928104834Sobrien ifp = &adapter->interface_data.ac_if; 929104834Sobrien 930130561Sobrien#ifdef DEVICE_POLLING 93184865Sobrien if (ifp->if_ipending & IFF_POLLING) { 93284865Sobrien EM_UNLOCK(adapter); 933130561Sobrien return; 934130561Sobrien } 935104834Sobrien 936130561Sobrien if (ether_poll_register(em_poll, ifp)) { 937130561Sobrien em_disable_intr(adapter); 938130561Sobrien em_poll_locked(ifp, 0, 1); 93984865Sobrien EM_UNLOCK(adapter); 940130561Sobrien return; 941130561Sobrien } 942130561Sobrien#endif /* DEVICE_POLLING */ 943130561Sobrien 944130561Sobrien reg_icr = E1000_READ_REG(&adapter->hw, ICR); 945130561Sobrien if (!reg_icr) { 94689857Sobrien EM_UNLOCK(adapter); 947104834Sobrien return; 948130561Sobrien } 949130561Sobrien 950130561Sobrien /* Link status change */ 951130561Sobrien if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { 952130561Sobrien callout_stop(&adapter->timer); 953130561Sobrien adapter->hw.get_link_status = 1; 954104834Sobrien em_check_for_link(&adapter->hw); 955130561Sobrien em_print_link_status(adapter); 956130561Sobrien callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter); 957130561Sobrien } 958130561Sobrien 959130561Sobrien while (loop_cnt > 0) { 960130561Sobrien if (ifp->if_flags & IFF_RUNNING) { 96184865Sobrien em_process_receive_interrupts(adapter, -1); 962104834Sobrien em_clean_transmit_interrupts(adapter); 963130561Sobrien } 964130561Sobrien loop_cnt--; 965130561Sobrien } 966130561Sobrien 967130561Sobrien if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) 968130561Sobrien em_start_locked(ifp); 969104834Sobrien 970130561Sobrien EM_UNLOCK(adapter); 971130561Sobrien return; 972130561Sobrien} 973130561Sobrien 974130561Sobrien 975130561Sobrien 976104834Sobrien/********************************************************************* 977104834Sobrien * 978130561Sobrien * Media Ioctl callback 979130561Sobrien * 980130561Sobrien * This routine is called whenever the user queries the status of 981130561Sobrien * the interface using ifconfig. 982130561Sobrien * 983130561Sobrien **********************************************************************/ 984104834Sobrienstatic void 985130561Sobrienem_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 986130561Sobrien{ 987130561Sobrien struct adapter * adapter = ifp->if_softc; 988130561Sobrien 989130561Sobrien INIT_DEBUGOUT("em_media_status: begin"); 990130561Sobrien 991104834Sobrien em_check_for_link(&adapter->hw); 99284865Sobrien if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { 99384865Sobrien if (adapter->link_active == 0) { 99484865Sobrien em_get_speed_and_duplex(&adapter->hw, 995104834Sobrien &adapter->link_speed, 99684865Sobrien &adapter->link_duplex); 99784865Sobrien adapter->link_active = 1; 99884865Sobrien } 999104834Sobrien } else { 100089857Sobrien if (adapter->link_active == 1) { 100184865Sobrien adapter->link_speed = 0; 1002104834Sobrien adapter->link_duplex = 0; 1003104834Sobrien adapter->link_active = 0; 1004130561Sobrien } 1005130561Sobrien } 1006104834Sobrien 1007104834Sobrien ifmr->ifm_status = IFM_AVALID; 1008130561Sobrien ifmr->ifm_active = IFM_ETHER; 1009104834Sobrien 1010130561Sobrien if (!adapter->link_active) 1011104834Sobrien return; 1012130561Sobrien 1013104834Sobrien ifmr->ifm_status |= IFM_ACTIVE; 1014104834Sobrien 1015130561Sobrien if (adapter->hw.media_type == em_media_type_fiber) { 101684865Sobrien ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; 101784865Sobrien } else { 101884865Sobrien switch (adapter->link_speed) { 101984865Sobrien case 10: 102084865Sobrien ifmr->ifm_active |= IFM_10_T; 102184865Sobrien break; 102284865Sobrien case 100: 1023104834Sobrien ifmr->ifm_active |= IFM_100_TX; 102484865Sobrien break; 102584865Sobrien case 1000: 102684865Sobrien#if __FreeBSD_version < 500000 102784865Sobrien ifmr->ifm_active |= IFM_1000_TX; 102884865Sobrien#else 102984865Sobrien ifmr->ifm_active |= IFM_1000_T; 103084865Sobrien#endif 103184865Sobrien break; 103284865Sobrien } 103384865Sobrien if (adapter->link_duplex == FULL_DUPLEX) 103484865Sobrien ifmr->ifm_active |= IFM_FDX; 103584865Sobrien else 1036104834Sobrien ifmr->ifm_active |= IFM_HDX; 1037104834Sobrien } 103884865Sobrien return; 103984865Sobrien} 104084865Sobrien 104184865Sobrien/********************************************************************* 104284865Sobrien * 104384865Sobrien * Media Ioctl callback 104484865Sobrien * 104584865Sobrien * This routine is called when the user changes speed/duplex using 104684865Sobrien * media/mediopt option with ifconfig. 104784865Sobrien * 104884865Sobrien **********************************************************************/ 104989857Sobrienstatic int 1050218822Sdimem_media_change(struct ifnet *ifp) 1051218822Sdim{ 1052218822Sdim struct adapter * adapter = ifp->if_softc; 1053218822Sdim struct ifmedia *ifm = &adapter->media; 1054218822Sdim 1055218822Sdim INIT_DEBUGOUT("em_media_change: begin"); 1056218822Sdim 1057218822Sdim if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1058218822Sdim return(EINVAL); 1059218822Sdim 1060218822Sdim switch (IFM_SUBTYPE(ifm->ifm_media)) { 1061218822Sdim case IFM_AUTO: 1062218822Sdim adapter->hw.autoneg = DO_AUTO_NEG; 1063218822Sdim adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; 1064218822Sdim break; 106584865Sobrien case IFM_1000_SX: 106684865Sobrien#if __FreeBSD_version < 500000 106784865Sobrien case IFM_1000_TX: 106884865Sobrien#else 106984865Sobrien case IFM_1000_T: 107084865Sobrien#endif 107184865Sobrien adapter->hw.autoneg = DO_AUTO_NEG; 107284865Sobrien adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; 107384865Sobrien break; 107484865Sobrien case IFM_100_TX: 107584865Sobrien adapter->hw.autoneg = FALSE; 107684865Sobrien adapter->hw.autoneg_advertised = 0; 107784865Sobrien if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 107884865Sobrien adapter->hw.forced_speed_duplex = em_100_full; 107984865Sobrien else 108084865Sobrien adapter->hw.forced_speed_duplex = em_100_half; 108184865Sobrien break; 108284865Sobrien case IFM_10_T: 108384865Sobrien adapter->hw.autoneg = FALSE; 108484865Sobrien adapter->hw.autoneg_advertised = 0; 108584865Sobrien if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 108684865Sobrien adapter->hw.forced_speed_duplex = em_10_full; 108784865Sobrien else 108884865Sobrien adapter->hw.forced_speed_duplex = em_10_half; 108984865Sobrien break; 109084865Sobrien default: 109184865Sobrien printf("em%d: Unsupported media type\n", adapter->unit); 109284865Sobrien } 109384865Sobrien 109484865Sobrien em_init(adapter); 109584865Sobrien 109684865Sobrien return(0); 109784865Sobrien} 109884865Sobrien 109984865Sobrienstatic void 110084865Sobrienem_tx_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int error) 110184865Sobrien{ 110284865Sobrien struct em_q *q = arg; 110384865Sobrien 110484865Sobrien if (error) 110584865Sobrien return; 110684865Sobrien KASSERT(nsegs <= EM_MAX_SCATTER, 110784865Sobrien ("Too many DMA segments returned when mapping tx packet")); 110884865Sobrien q->nsegs = nsegs; 110984865Sobrien bcopy(seg, q->segs, nsegs * sizeof(seg[0])); 111084865Sobrien} 1111104834Sobrien 111284865Sobrien#define EM_FIFO_HDR 0x10 1113130561Sobrien#define EM_82547_PKT_THRESH 0x3e0 1114104834Sobrien#define EM_82547_TX_FIFO_SIZE 0x2800 1115104834Sobrien#define EM_82547_TX_FIFO_BEGIN 0xf00 1116104834Sobrien/********************************************************************* 1117104834Sobrien * 1118104834Sobrien * This routine maps the mbufs to tx descriptors. 1119130561Sobrien * 1120104834Sobrien * return 0 on success, positive on failure 1121104834Sobrien **********************************************************************/ 112284865Sobrienstatic int 112384865Sobrienem_encap(struct adapter *adapter, struct mbuf *m_head) 112484865Sobrien{ 1125130561Sobrien u_int32_t txd_upper; 112684865Sobrien u_int32_t txd_lower, txd_used = 0, txd_saved = 0; 112784865Sobrien int i, j, error; 112884865Sobrien u_int64_t address; 112984865Sobrien 113084865Sobrien /* For 82544 Workaround */ 113184865Sobrien DESC_ARRAY desc_array; 113284865Sobrien u_int32_t array_elements; 113384865Sobrien u_int32_t counter; 113484865Sobrien 113584865Sobrien#if __FreeBSD_version < 500000 113684865Sobrien struct ifvlan *ifv = NULL; 113784865Sobrien#else 113884865Sobrien struct m_tag *mtag; 1139130561Sobrien#endif 1140130561Sobrien struct em_q q; 114184865Sobrien struct em_buffer *tx_buffer = NULL; 114284865Sobrien struct em_tx_desc *current_tx_desc = NULL; 114384865Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 114484865Sobrien 114584865Sobrien /* 114684865Sobrien * Force a cleanup if number of TX descriptors 114784865Sobrien * available hits the threshold 114884865Sobrien */ 114984865Sobrien if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { 115084865Sobrien em_clean_transmit_interrupts(adapter); 1151130561Sobrien if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) { 1152130561Sobrien adapter->no_tx_desc_avail1++; 115384865Sobrien return(ENOBUFS); 115484865Sobrien } 115584865Sobrien } 1156130561Sobrien 115784865Sobrien /* 115884865Sobrien * Map the packet for DMA. 115989857Sobrien */ 116089857Sobrien if (bus_dmamap_create(adapter->txtag, BUS_DMA_NOWAIT, &q.map)) { 1161130561Sobrien adapter->no_tx_map_avail++; 116284865Sobrien return (ENOMEM); 116384865Sobrien } 116484865Sobrien error = bus_dmamap_load_mbuf(adapter->txtag, q.map, 116589857Sobrien m_head, em_tx_cb, &q, BUS_DMA_NOWAIT); 116689857Sobrien if (error != 0) { 1167130561Sobrien adapter->no_tx_dma_setup++; 116884865Sobrien bus_dmamap_destroy(adapter->txtag, q.map); 116984865Sobrien return (error); 117084865Sobrien } 117184865Sobrien KASSERT(q.nsegs != 0, ("em_encap: empty packet")); 117284865Sobrien 117384865Sobrien if (q.nsegs > adapter->num_tx_desc_avail) { 1174130561Sobrien adapter->no_tx_desc_avail2++; 117589857Sobrien bus_dmamap_destroy(adapter->txtag, q.map); 1176130561Sobrien return (ENOBUFS); 117784865Sobrien } 117884865Sobrien 117989857Sobrien 118084865Sobrien if (ifp->if_hwassist > 0) { 118184865Sobrien em_transmit_checksum_setup(adapter, m_head, 118284865Sobrien &txd_upper, &txd_lower); 118384865Sobrien } else 1184130561Sobrien txd_upper = txd_lower = 0; 118584865Sobrien 118684865Sobrien 118789857Sobrien /* Find out if we are in vlan mode */ 118889857Sobrien#if __FreeBSD_version < 500000 118984865Sobrien if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && 1190130561Sobrien m_head->m_pkthdr.rcvif != NULL && 119184865Sobrien m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) 119284865Sobrien ifv = m_head->m_pkthdr.rcvif->if_softc; 119384865Sobrien#else 119484865Sobrien mtag = VLAN_OUTPUT_TAG(ifp, m_head); 119584865Sobrien#endif 119689857Sobrien 119784865Sobrien i = adapter->next_avail_tx_desc; 119884865Sobrien if (adapter->pcix_82544) { 119984865Sobrien txd_saved = i; 120084865Sobrien txd_used = 0; 120184865Sobrien } 120284865Sobrien for (j = 0; j < q.nsegs; j++) { 120384865Sobrien /* If adapter is 82544 and on PCIX bus */ 120484865Sobrien if(adapter->pcix_82544) { 120584865Sobrien array_elements = 0; 1206130561Sobrien address = htole64(q.segs[j].ds_addr); 1207130561Sobrien /* 120884865Sobrien * Check the Address and Length combination and 120984865Sobrien * split the data accordingly 121084865Sobrien */ 1211130561Sobrien array_elements = em_fill_descriptors(address, 121284865Sobrien htole32(q.segs[j].ds_len), 121384865Sobrien &desc_array); 121489857Sobrien for (counter = 0; counter < array_elements; counter++) { 121584865Sobrien if (txd_used == adapter->num_tx_desc_avail) { 1216130561Sobrien adapter->next_avail_tx_desc = txd_saved; 121784865Sobrien adapter->no_tx_desc_avail2++; 121884865Sobrien bus_dmamap_destroy(adapter->txtag, q.map); 121984865Sobrien return (ENOBUFS); 122089857Sobrien } 122189857Sobrien tx_buffer = &adapter->tx_buffer_area[i]; 1222130561Sobrien current_tx_desc = &adapter->tx_desc_base[i]; 122384865Sobrien current_tx_desc->buffer_addr = htole64( 122484865Sobrien desc_array.descriptor[counter].address); 122584865Sobrien current_tx_desc->lower.data = htole32( 122684865Sobrien (adapter->txd_cmd | txd_lower | 122784865Sobrien (u_int16_t)desc_array.descriptor[counter].length)); 122884865Sobrien current_tx_desc->upper.data = htole32((txd_upper)); 122984865Sobrien if (++i == adapter->num_tx_desc) 123084865Sobrien i = 0; 123184865Sobrien 1232130561Sobrien tx_buffer->m_head = NULL; 123389857Sobrien txd_used++; 1234130561Sobrien } 123584865Sobrien } else { 123684865Sobrien tx_buffer = &adapter->tx_buffer_area[i]; 123789857Sobrien current_tx_desc = &adapter->tx_desc_base[i]; 123884865Sobrien 123984865Sobrien current_tx_desc->buffer_addr = htole64(q.segs[j].ds_addr); 124084865Sobrien current_tx_desc->lower.data = htole32( 124184865Sobrien adapter->txd_cmd | txd_lower | q.segs[j].ds_len); 1242130561Sobrien current_tx_desc->upper.data = htole32(txd_upper); 124384865Sobrien 124484865Sobrien if (++i == adapter->num_tx_desc) 124589857Sobrien i = 0; 124689857Sobrien 124784865Sobrien tx_buffer->m_head = NULL; 1248130561Sobrien } 124984865Sobrien } 125084865Sobrien 125184865Sobrien adapter->next_avail_tx_desc = i; 125284865Sobrien if (adapter->pcix_82544) { 125384865Sobrien adapter->num_tx_desc_avail -= txd_used; 125489857Sobrien } 125584865Sobrien else { 125684865Sobrien adapter->num_tx_desc_avail -= q.nsegs; 125784865Sobrien } 125884865Sobrien 125984865Sobrien#if __FreeBSD_version < 500000 126084865Sobrien if (ifv != NULL) { 126184865Sobrien /* Set the vlan id */ 126284865Sobrien current_tx_desc->upper.fields.special = htole16(ifv->ifv_tag); 126384865Sobrien#else 126484865Sobrien if (mtag != NULL) { 126584865Sobrien /* Set the vlan id */ 1266130561Sobrien current_tx_desc->upper.fields.special = htole16(VLAN_TAG_VALUE(mtag)); 126784865Sobrien#endif 126884865Sobrien 126984865Sobrien /* Tell hardware to add tag */ 127084865Sobrien current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE); 127184865Sobrien } 1272130561Sobrien 127384865Sobrien tx_buffer->m_head = m_head; 1274130561Sobrien tx_buffer->map = q.map; 127584865Sobrien bus_dmamap_sync(adapter->txtag, q.map, BUS_DMASYNC_PREWRITE); 127684865Sobrien 127784865Sobrien /* 127884865Sobrien * Last Descriptor of Packet needs End Of Packet (EOP) 127984865Sobrien */ 128084865Sobrien current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_EOP); 128184865Sobrien 128284865Sobrien /* 1283104834Sobrien * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000 128484865Sobrien * that this frame is available to transmit. 1285104834Sobrien */ 128684865Sobrien if (adapter->hw.mac_type == em_82547 && 1287104834Sobrien adapter->link_duplex == HALF_DUPLEX) { 128884865Sobrien em_82547_move_tail_locked(adapter); 128984865Sobrien } else { 129084865Sobrien E1000_WRITE_REG(&adapter->hw, TDT, i); 129184865Sobrien if (adapter->hw.mac_type == em_82547) { 129284865Sobrien em_82547_update_fifo_head(adapter, m_head->m_pkthdr.len); 129384865Sobrien } 129484865Sobrien } 129584865Sobrien 129684865Sobrien return(0); 129784865Sobrien} 129884865Sobrien 129984865Sobrien/********************************************************************* 130084865Sobrien * 1301104834Sobrien * 82547 workaround to avoid controller hang in half-duplex environment. 1302104834Sobrien * The workaround is to avoid queuing a large packet that would span 130389857Sobrien * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers 1304104834Sobrien * in this case. We do that only when FIFO is quiescent. 130584865Sobrien * 1306104834Sobrien **********************************************************************/ 130784865Sobrienstatic void 1308218822Sdimem_82547_move_tail_locked(struct adapter *adapter) 1309218822Sdim{ 1310218822Sdim uint16_t hw_tdt; 1311218822Sdim uint16_t sw_tdt; 1312218822Sdim struct em_tx_desc *tx_desc; 1313218822Sdim uint16_t length = 0; 131484865Sobrien boolean_t eop = 0; 131584865Sobrien 131684865Sobrien EM_LOCK_ASSERT(adapter); 131784865Sobrien 131884865Sobrien hw_tdt = E1000_READ_REG(&adapter->hw, TDT); 131984865Sobrien sw_tdt = adapter->next_avail_tx_desc; 132084865Sobrien 132184865Sobrien while (hw_tdt != sw_tdt) { 132284865Sobrien tx_desc = &adapter->tx_desc_base[hw_tdt]; 132384865Sobrien length += tx_desc->lower.flags.length; 132484865Sobrien eop = tx_desc->lower.data & E1000_TXD_CMD_EOP; 1325104834Sobrien if(++hw_tdt == adapter->num_tx_desc) 1326104834Sobrien hw_tdt = 0; 132784865Sobrien 132884865Sobrien if(eop) { 132984865Sobrien if (em_82547_fifo_workaround(adapter, length)) { 1330104834Sobrien adapter->tx_fifo_wrk++; 133184865Sobrien callout_reset(&adapter->tx_fifo_timer, 1, 133284865Sobrien em_82547_move_tail, adapter); 133384865Sobrien break; 133484865Sobrien } 133584865Sobrien E1000_WRITE_REG(&adapter->hw, TDT, hw_tdt); 133689857Sobrien em_82547_update_fifo_head(adapter, length); 133789857Sobrien length = 0; 133884865Sobrien } 1339104834Sobrien } 134084865Sobrien return; 134184865Sobrien} 134284865Sobrien 134384865Sobrienstatic void 134484865Sobrienem_82547_move_tail(void *arg) 134584865Sobrien{ 134684865Sobrien struct adapter *adapter = arg; 134784865Sobrien 134884865Sobrien EM_LOCK(adapter); 134984865Sobrien em_82547_move_tail_locked(adapter); 135084865Sobrien EM_UNLOCK(adapter); 135184865Sobrien} 1352104834Sobrien 1353104834Sobrienstatic int 135484865Sobrienem_82547_fifo_workaround(struct adapter *adapter, int len) 135584865Sobrien{ 135684865Sobrien int fifo_space, fifo_pkt_len; 1357104834Sobrien 135884865Sobrien fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR); 135984865Sobrien 1360104834Sobrien if (adapter->link_duplex == HALF_DUPLEX) { 1361104834Sobrien fifo_space = EM_82547_TX_FIFO_SIZE - adapter->tx_fifo_head; 1362104834Sobrien 136384865Sobrien if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) { 136489857Sobrien if (em_82547_tx_fifo_reset(adapter)) { 136589857Sobrien return(0); 136684865Sobrien } 1367104834Sobrien else { 136884865Sobrien return(1); 136984865Sobrien } 137084865Sobrien } 137184865Sobrien } 137284865Sobrien 137384865Sobrien return(0); 1374104834Sobrien} 137584865Sobrien 1376104834Sobrienstatic void 1377104834Sobrienem_82547_update_fifo_head(struct adapter *adapter, int len) 137884865Sobrien{ 137984865Sobrien int fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR); 138084865Sobrien 138184865Sobrien /* tx_fifo_head is always 16 byte aligned */ 138284865Sobrien adapter->tx_fifo_head += fifo_pkt_len; 138384865Sobrien if (adapter->tx_fifo_head >= EM_82547_TX_FIFO_SIZE) { 138484865Sobrien adapter->tx_fifo_head -= EM_82547_TX_FIFO_SIZE; 138584865Sobrien } 138684865Sobrien 138784865Sobrien return; 138884865Sobrien} 138984865Sobrien 139089857Sobrien 139184865Sobrienstatic int 139289857Sobrienem_82547_tx_fifo_reset(struct adapter *adapter) 139384865Sobrien{ 139489857Sobrien uint32_t tctl; 139584865Sobrien 139684865Sobrien if ( (E1000_READ_REG(&adapter->hw, TDT) == 139784865Sobrien E1000_READ_REG(&adapter->hw, TDH)) && 139884865Sobrien (E1000_READ_REG(&adapter->hw, TDFT) == 139984865Sobrien E1000_READ_REG(&adapter->hw, TDFH)) && 140084865Sobrien (E1000_READ_REG(&adapter->hw, TDFTS) == 140184865Sobrien E1000_READ_REG(&adapter->hw, TDFHS)) && 140284865Sobrien (E1000_READ_REG(&adapter->hw, TDFPC) == 0)) { 140389857Sobrien 140489857Sobrien /* Disable TX unit */ 140584865Sobrien tctl = E1000_READ_REG(&adapter->hw, TCTL); 140684865Sobrien E1000_WRITE_REG(&adapter->hw, TCTL, tctl & ~E1000_TCTL_EN); 140784865Sobrien 140884865Sobrien /* Reset FIFO pointers */ 140984865Sobrien E1000_WRITE_REG(&adapter->hw, TDFT, EM_82547_TX_FIFO_BEGIN); 141084865Sobrien E1000_WRITE_REG(&adapter->hw, TDFH, EM_82547_TX_FIFO_BEGIN); 141189857Sobrien E1000_WRITE_REG(&adapter->hw, TDFTS, EM_82547_TX_FIFO_BEGIN); 141289857Sobrien E1000_WRITE_REG(&adapter->hw, TDFHS, EM_82547_TX_FIFO_BEGIN); 141384865Sobrien 141484865Sobrien /* Re-enable TX unit */ 141584865Sobrien E1000_WRITE_REG(&adapter->hw, TCTL, tctl); 141684865Sobrien E1000_WRITE_FLUSH(&adapter->hw); 141784865Sobrien 141884865Sobrien adapter->tx_fifo_head = 0; 141989857Sobrien adapter->tx_fifo_reset++; 142084865Sobrien 142184865Sobrien return(TRUE); 142284865Sobrien } 142384865Sobrien else { 142484865Sobrien return(FALSE); 142584865Sobrien } 142684865Sobrien} 142784865Sobrien 142884865Sobrienstatic void 142984865Sobrienem_set_promisc(struct adapter * adapter) 143084865Sobrien{ 143184865Sobrien 143284865Sobrien u_int32_t reg_rctl; 143384865Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 143484865Sobrien 143589857Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 143684865Sobrien 143784865Sobrien if (ifp->if_flags & IFF_PROMISC) { 143884865Sobrien reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); 143984865Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 144084865Sobrien } else if (ifp->if_flags & IFF_ALLMULTI) { 144184865Sobrien reg_rctl |= E1000_RCTL_MPE; 144284865Sobrien reg_rctl &= ~E1000_RCTL_UPE; 144389857Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 144489857Sobrien } 144584865Sobrien 144684865Sobrien return; 144784865Sobrien} 144884865Sobrien 144984865Sobrienstatic void 145084865Sobrienem_disable_promisc(struct adapter * adapter) 145189857Sobrien{ 145284865Sobrien u_int32_t reg_rctl; 145384865Sobrien 145484865Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 145584865Sobrien 145684865Sobrien reg_rctl &= (~E1000_RCTL_UPE); 145784865Sobrien reg_rctl &= (~E1000_RCTL_MPE); 145884865Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 145984865Sobrien 146084865Sobrien return; 146184865Sobrien} 146284865Sobrien 146384865Sobrien 146484865Sobrien/********************************************************************* 146584865Sobrien * Multicast Update 146684865Sobrien * 146789857Sobrien * This routine is called whenever multicast address list is updated. 146884865Sobrien * 146984865Sobrien **********************************************************************/ 147084865Sobrien 147184865Sobrienstatic void 147284865Sobrienem_set_multi(struct adapter * adapter) 147384865Sobrien{ 147484865Sobrien u_int32_t reg_rctl = 0; 147584865Sobrien u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; 147684865Sobrien struct ifmultiaddr *ifma; 147784865Sobrien int mcnt = 0; 147884865Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 147984865Sobrien 148084865Sobrien IOCTL_DEBUGOUT("em_set_multi: begin"); 148184865Sobrien 148284865Sobrien if (adapter->hw.mac_type == em_82542_rev2_0) { 148384865Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 148484865Sobrien if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { 148584865Sobrien em_pci_clear_mwi(&adapter->hw); 148684865Sobrien } 148784865Sobrien reg_rctl |= E1000_RCTL_RST; 148884865Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 148984865Sobrien msec_delay(5); 149084865Sobrien } 149184865Sobrien 149284865Sobrien#if __FreeBSD_version < 500000 149384865Sobrien LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 149484865Sobrien#else 149584865Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 149684865Sobrien#endif 149784865Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 149884865Sobrien continue; 149984865Sobrien 150084865Sobrien if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break; 150184865Sobrien 150284865Sobrien bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 150384865Sobrien &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS); 150484865Sobrien mcnt++; 150584865Sobrien } 150684865Sobrien 150784865Sobrien if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) { 150884865Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 150984865Sobrien reg_rctl |= E1000_RCTL_MPE; 151084865Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 151184865Sobrien } else 151284865Sobrien em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0); 151384865Sobrien 151484865Sobrien if (adapter->hw.mac_type == em_82542_rev2_0) { 151584865Sobrien reg_rctl = E1000_READ_REG(&adapter->hw, RCTL); 151684865Sobrien reg_rctl &= ~E1000_RCTL_RST; 151784865Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 151884865Sobrien msec_delay(5); 151984865Sobrien if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { 152084865Sobrien em_pci_set_mwi(&adapter->hw); 152184865Sobrien } 152284865Sobrien } 152384865Sobrien 152484865Sobrien return; 152584865Sobrien} 152684865Sobrien 152784865Sobrien 152884865Sobrien/********************************************************************* 152984865Sobrien * Timer routine 153084865Sobrien * 153184865Sobrien * This routine checks for link status and updates statistics. 153284865Sobrien * 153384865Sobrien **********************************************************************/ 153484865Sobrien 153584865Sobrienstatic void 153684865Sobrienem_local_timer(void *arg) 153792828Sobrien{ 153884865Sobrien struct ifnet *ifp; 153984865Sobrien struct adapter * adapter = arg; 154084865Sobrien ifp = &adapter->interface_data.ac_if; 154184865Sobrien 154284865Sobrien EM_LOCK(adapter); 154384865Sobrien 154484865Sobrien em_check_for_link(&adapter->hw); 154584865Sobrien em_print_link_status(adapter); 154684865Sobrien em_update_stats_counters(adapter); 154792828Sobrien if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) { 154884865Sobrien em_print_hw_stats(adapter); 154984865Sobrien } 155084865Sobrien em_smartspeed(adapter); 1551251227Spfg 155284865Sobrien callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter); 155384865Sobrien 155484865Sobrien EM_UNLOCK(adapter); 155584865Sobrien return; 155684865Sobrien} 155784865Sobrien 155884865Sobrienstatic void 155984865Sobrienem_print_link_status(struct adapter * adapter) 156084865Sobrien{ 1561251227Spfg if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { 156284865Sobrien if (adapter->link_active == 0) { 156384865Sobrien em_get_speed_and_duplex(&adapter->hw, 156484865Sobrien &adapter->link_speed, 156584865Sobrien &adapter->link_duplex); 156684865Sobrien printf("em%d: Link is up %d Mbps %s\n", 156784865Sobrien adapter->unit, 156884865Sobrien adapter->link_speed, 156984865Sobrien ((adapter->link_duplex == FULL_DUPLEX) ? 157084865Sobrien "Full Duplex" : "Half Duplex")); 157184865Sobrien adapter->link_active = 1; 157284865Sobrien adapter->smartspeed = 0; 157384865Sobrien } 157484865Sobrien } else { 157584865Sobrien if (adapter->link_active == 1) { 157684865Sobrien adapter->link_speed = 0; 157784865Sobrien adapter->link_duplex = 0; 157884865Sobrien printf("em%d: Link is Down\n", adapter->unit); 157984865Sobrien adapter->link_active = 0; 158084865Sobrien } 158184865Sobrien } 158284865Sobrien 158384865Sobrien return; 158484865Sobrien} 158584865Sobrien 158684865Sobrien/********************************************************************* 158784865Sobrien * 158884865Sobrien * This routine disables all traffic on the adapter by issuing a 158984865Sobrien * global reset on the MAC and deallocates TX/RX buffers. 159084865Sobrien * 1591130561Sobrien **********************************************************************/ 159284865Sobrien 159384865Sobrienstatic void 159484865Sobrienem_stop(void *arg) 159584865Sobrien{ 159684865Sobrien struct ifnet *ifp; 159784865Sobrien struct adapter * adapter = arg; 159884865Sobrien ifp = &adapter->interface_data.ac_if; 159984865Sobrien 160084865Sobrien mtx_assert(&adapter->mtx, MA_OWNED); 160184865Sobrien 160284865Sobrien INIT_DEBUGOUT("em_stop: begin"); 160384865Sobrien em_disable_intr(adapter); 160484865Sobrien em_reset_hw(&adapter->hw); 160584865Sobrien callout_stop(&adapter->timer); 160684865Sobrien callout_stop(&adapter->tx_fifo_timer); 160784865Sobrien em_free_transmit_structures(adapter); 160884865Sobrien em_free_receive_structures(adapter); 160989857Sobrien 161084865Sobrien 161184865Sobrien /* Tell the stack that the interface is no longer active */ 161284865Sobrien ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 161384865Sobrien 161484865Sobrien return; 161584865Sobrien} 161684865Sobrien 161784865Sobrien 161884865Sobrien/********************************************************************* 161984865Sobrien * 162084865Sobrien * Determine hardware revision. 162189857Sobrien * 162289857Sobrien **********************************************************************/ 162389857Sobrienstatic void 162489857Sobrienem_identify_hardware(struct adapter * adapter) 1625130561Sobrien{ 162684865Sobrien device_t dev = adapter->dev; 162789857Sobrien 162889857Sobrien /* Make sure our PCI config space has the necessary stuff set */ 1629130561Sobrien adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); 163084865Sobrien if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) && 163184865Sobrien (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) { 163284865Sobrien printf("em%d: Memory Access and/or Bus Master bits were not set!\n", 163384865Sobrien adapter->unit); 163484865Sobrien adapter->hw.pci_cmd_word |= 163584865Sobrien (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 163684865Sobrien pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2); 163784865Sobrien } 163889857Sobrien 163984865Sobrien /* Save off the information about this board */ 164089857Sobrien adapter->hw.vendor_id = pci_get_vendor(dev); 164189857Sobrien adapter->hw.device_id = pci_get_device(dev); 1642130561Sobrien adapter->hw.revision_id = pci_read_config(dev, PCIR_REVID, 1); 164384865Sobrien adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2); 164484865Sobrien adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2); 164584865Sobrien 164689857Sobrien /* Identify the MAC */ 164784865Sobrien if (em_set_mac_type(&adapter->hw)) 164884865Sobrien printf("em%d: Unknown MAC Type\n", adapter->unit); 164984865Sobrien 165084865Sobrien if(adapter->hw.mac_type == em_82541 || 165184865Sobrien adapter->hw.mac_type == em_82541_rev_2 || 1652218822Sdim adapter->hw.mac_type == em_82547 || 165384865Sobrien adapter->hw.mac_type == em_82547_rev_2) 165484865Sobrien adapter->hw.phy_init_script = TRUE; 165584865Sobrien 165684865Sobrien return; 165784865Sobrien} 165884865Sobrien 165984865Sobrienstatic int 166084865Sobrienem_allocate_pci_resources(struct adapter * adapter) 166184865Sobrien{ 166289857Sobrien int i, val, rid; 1663130561Sobrien device_t dev = adapter->dev; 166484865Sobrien 166584865Sobrien rid = EM_MMBA; 166684865Sobrien adapter->res_memory = bus_alloc_resource(dev, SYS_RES_MEMORY, 166784865Sobrien &rid, 0, ~0, 1, 166884865Sobrien RF_ACTIVE); 166984865Sobrien if (!(adapter->res_memory)) { 167084865Sobrien printf("em%d: Unable to allocate bus resource: memory\n", 167189857Sobrien adapter->unit); 1672130561Sobrien return(ENXIO); 167384865Sobrien } 167484865Sobrien adapter->osdep.mem_bus_space_tag = 1675130561Sobrien rman_get_bustag(adapter->res_memory); 167684865Sobrien adapter->osdep.mem_bus_space_handle = 167784865Sobrien rman_get_bushandle(adapter->res_memory); 167889857Sobrien adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle; 167989857Sobrien 168089857Sobrien 168189857Sobrien if (adapter->hw.mac_type > em_82543) { 168289857Sobrien /* Figure our where our IO BAR is ? */ 168389857Sobrien rid = EM_MMBA; 168489857Sobrien for (i = 0; i < 5; i++) { 168589857Sobrien val = pci_read_config(dev, rid, 4); 168689857Sobrien if (val & 0x00000001) { 168789857Sobrien adapter->io_rid = rid; 168889857Sobrien break; 1689130561Sobrien } 169089857Sobrien rid += 4; 169189857Sobrien } 169289857Sobrien 169389857Sobrien adapter->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, 169489857Sobrien &adapter->io_rid, 0, ~0, 1, 169589857Sobrien RF_ACTIVE); 169689857Sobrien if (!(adapter->res_ioport)) { 1697130561Sobrien printf("em%d: Unable to allocate bus resource: ioport\n", 169889857Sobrien adapter->unit); 169989857Sobrien return(ENXIO); 170089857Sobrien } 170189857Sobrien 170289857Sobrien adapter->hw.io_base = 170389857Sobrien rman_get_start(adapter->res_ioport); 1704130561Sobrien } 1705104834Sobrien 1706104834Sobrien rid = 0x0; 1707104834Sobrien adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ, 1708104834Sobrien &rid, 0, ~0, 1, 1709104834Sobrien RF_SHAREABLE | RF_ACTIVE); 1710104834Sobrien if (!(adapter->res_interrupt)) { 1711104834Sobrien printf("em%d: Unable to allocate bus resource: interrupt\n", 1712104834Sobrien adapter->unit); 1713130561Sobrien return(ENXIO); 1714104834Sobrien } 1715104834Sobrien if (bus_setup_intr(dev, adapter->res_interrupt, 1716104834Sobrien INTR_TYPE_NET | INTR_MPSAFE, 1717130561Sobrien (void (*)(void *)) em_intr, adapter, 1718104834Sobrien &adapter->int_handler_tag)) { 1719130561Sobrien printf("em%d: Error registering interrupt handler!\n", 1720104834Sobrien adapter->unit); 1721104834Sobrien return(ENXIO); 1722130561Sobrien } 1723104834Sobrien 1724104834Sobrien adapter->hw.back = &adapter->osdep; 1725104834Sobrien 1726104834Sobrien return(0); 1727104834Sobrien} 1728104834Sobrien 1729104834Sobrienstatic void 1730104834Sobrienem_free_pci_resources(struct adapter * adapter) 1731130561Sobrien{ 1732104834Sobrien device_t dev = adapter->dev; 1733104834Sobrien 1734104834Sobrien if (adapter->res_interrupt != NULL) { 1735104834Sobrien bus_teardown_intr(dev, adapter->res_interrupt, 1736104834Sobrien adapter->int_handler_tag); 1737104834Sobrien bus_release_resource(dev, SYS_RES_IRQ, 0, 1738104834Sobrien adapter->res_interrupt); 1739130561Sobrien } 1740104834Sobrien if (adapter->res_memory != NULL) { 1741104834Sobrien bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA, 1742104834Sobrien adapter->res_memory); 1743104834Sobrien } 1744104834Sobrien 1745104834Sobrien if (adapter->res_ioport != NULL) { 1746130561Sobrien bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid, 1747104834Sobrien adapter->res_ioport); 1748130561Sobrien } 1749104834Sobrien return; 1750104834Sobrien} 1751130561Sobrien 1752104834Sobrien/********************************************************************* 1753104834Sobrien * 1754130561Sobrien * Initialize the hardware to a configuration as specified by the 1755104834Sobrien * adapter structure. The controller is reset, the EEPROM is 1756104834Sobrien * verified, the MAC address is set, then the shared initialization 1757104834Sobrien * routines are called. 1758218822Sdim * 1759104834Sobrien **********************************************************************/ 1760104834Sobrienstatic int 1761104834Sobrienem_hardware_init(struct adapter * adapter) 1762104834Sobrien{ 1763104834Sobrien INIT_DEBUGOUT("em_hardware_init: begin"); 1764104834Sobrien /* Issue a global reset */ 1765104834Sobrien em_reset_hw(&adapter->hw); 1766104834Sobrien 1767104834Sobrien /* When hardware is reset, fifo_head is also reset */ 1768104834Sobrien adapter->tx_fifo_head = 0; 1769104834Sobrien 1770104834Sobrien /* Make sure we have a good EEPROM before we read from it */ 1771104834Sobrien if (em_validate_eeprom_checksum(&adapter->hw) < 0) { 1772104834Sobrien printf("em%d: The EEPROM Checksum Is Not Valid\n", 1773104834Sobrien adapter->unit); 1774130561Sobrien return(EIO); 1775104834Sobrien } 1776104834Sobrien 1777104834Sobrien if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) { 1778104834Sobrien printf("em%d: EEPROM read error while reading part number\n", 1779130561Sobrien adapter->unit); 1780104834Sobrien return(EIO); 1781104834Sobrien } 1782130561Sobrien 178389857Sobrien if (em_init_hw(&adapter->hw) < 0) { 178484865Sobrien printf("em%d: Hardware Initialization Failed", 178589857Sobrien adapter->unit); 178684865Sobrien return(EIO); 178784865Sobrien } 178889857Sobrien 178984865Sobrien em_check_for_link(&adapter->hw); 179089857Sobrien if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) 179189857Sobrien adapter->link_active = 1; 179284865Sobrien else 179389857Sobrien adapter->link_active = 0; 179489857Sobrien 1795218822Sdim if (adapter->link_active) { 1796130561Sobrien em_get_speed_and_duplex(&adapter->hw, 179789857Sobrien &adapter->link_speed, 179889857Sobrien &adapter->link_duplex); 179989857Sobrien } else { 180084865Sobrien adapter->link_speed = 0; 180189857Sobrien adapter->link_duplex = 0; 180289857Sobrien } 180389857Sobrien 180489857Sobrien return(0); 180589857Sobrien} 180689857Sobrien 180789857Sobrien/********************************************************************* 180889857Sobrien * 180989857Sobrien * Setup networking device structure and register an interface. 181084865Sobrien * 181189857Sobrien **********************************************************************/ 181289857Sobrienstatic void 181389857Sobrienem_setup_interface(device_t dev, struct adapter * adapter) 181489857Sobrien{ 181589857Sobrien struct ifnet *ifp; 181689857Sobrien INIT_DEBUGOUT("em_setup_interface: begin"); 181789857Sobrien 181889857Sobrien ifp = &adapter->interface_data.ac_if; 181989857Sobrien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 182089857Sobrien ifp->if_mtu = ETHERMTU; 182189857Sobrien ifp->if_output = ether_output; 182289857Sobrien ifp->if_baudrate = 1000000000; 1823218822Sdim ifp->if_init = em_init; 182489857Sobrien ifp->if_softc = adapter; 182589857Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 182689857Sobrien ifp->if_ioctl = em_ioctl; 182784865Sobrien ifp->if_start = em_start; 182889857Sobrien ifp->if_watchdog = em_watchdog; 182989857Sobrien ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1; 183089857Sobrien 183189857Sobrien#if __FreeBSD_version < 500000 183284865Sobrien ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 183389857Sobrien#else 183484865Sobrien ether_ifattach(ifp, adapter->interface_data.ac_enaddr); 183589857Sobrien#endif 183689857Sobrien 183789857Sobrien if (adapter->hw.mac_type >= em_82543) { 183884865Sobrien ifp->if_capabilities = IFCAP_HWCSUM; 183989857Sobrien ifp->if_capenable = ifp->if_capabilities; 184089857Sobrien } 1841130561Sobrien 1842130561Sobrien /* 1843130561Sobrien * Tell the upper layer(s) we support long frames. 184489857Sobrien */ 1845130561Sobrien ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1846130561Sobrien#if __FreeBSD_version >= 500000 1847130561Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 1848130561Sobrien#endif 1849130561Sobrien 1850130561Sobrien 1851130561Sobrien /* 1852130561Sobrien * Specify the media types supported by this adapter and register 1853130561Sobrien * callbacks to update media and link information 1854130561Sobrien */ 1855130561Sobrien ifmedia_init(&adapter->media, IFM_IMASK, em_media_change, 1856130561Sobrien em_media_status); 1857130561Sobrien if (adapter->hw.media_type == em_media_type_fiber) { 1858130561Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX, 1859130561Sobrien 0, NULL); 186089857Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 186189857Sobrien 0, NULL); 1862130561Sobrien } else { 186384865Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL); 186489857Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX, 1865218822Sdim 0, NULL); 1866218822Sdim ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 186789857Sobrien 0, NULL); 186884865Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 1869130561Sobrien 0, NULL); 187089857Sobrien#if __FreeBSD_version < 500000 187189857Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX, 1872130561Sobrien 0, NULL); 1873130561Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL); 187489857Sobrien#else 187589857Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 1876218822Sdim 0, NULL); 187789857Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); 1878130561Sobrien#endif 187989857Sobrien } 188089857Sobrien ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1881130561Sobrien ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 188289857Sobrien 1883130561Sobrien return; 188489857Sobrien} 188589857Sobrien 188684865Sobrien 188789857Sobrien/********************************************************************* 188884865Sobrien * 188989857Sobrien * Workaround for SmartSpeed on 82541 and 82547 controllers 189089857Sobrien * 189189857Sobrien **********************************************************************/ 189289857Sobrienstatic void 189389857Sobrienem_smartspeed(struct adapter *adapter) 189489857Sobrien{ 189584865Sobrien uint16_t phy_tmp; 189689857Sobrien 189789857Sobrien if(adapter->link_active || (adapter->hw.phy_type != em_phy_igp) || 189889857Sobrien !adapter->hw.autoneg || !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL)) 189984865Sobrien return; 190089857Sobrien 190189857Sobrien if(adapter->smartspeed == 0) { 1902130561Sobrien /* If Master/Slave config fault is asserted twice, 190389857Sobrien * we assume back-to-back */ 190489857Sobrien em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); 190589857Sobrien if(!(phy_tmp & SR_1000T_MS_CONFIG_FAULT)) return; 190689857Sobrien em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp); 190789857Sobrien if(phy_tmp & SR_1000T_MS_CONFIG_FAULT) { 190889857Sobrien em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, 190989857Sobrien &phy_tmp); 191089857Sobrien if(phy_tmp & CR_1000T_MS_ENABLE) { 191189857Sobrien phy_tmp &= ~CR_1000T_MS_ENABLE; 191289857Sobrien em_write_phy_reg(&adapter->hw, 191389857Sobrien PHY_1000T_CTRL, phy_tmp); 191489857Sobrien adapter->smartspeed++; 191589857Sobrien if(adapter->hw.autoneg && 191689857Sobrien !em_phy_setup_autoneg(&adapter->hw) && 191789857Sobrien !em_read_phy_reg(&adapter->hw, PHY_CTRL, 191889857Sobrien &phy_tmp)) { 191989857Sobrien phy_tmp |= (MII_CR_AUTO_NEG_EN | 192089857Sobrien MII_CR_RESTART_AUTO_NEG); 192189857Sobrien em_write_phy_reg(&adapter->hw, 192289857Sobrien PHY_CTRL, phy_tmp); 192389857Sobrien } 192489857Sobrien } 192589857Sobrien } 192689857Sobrien return; 1927218822Sdim } else if(adapter->smartspeed == EM_SMARTSPEED_DOWNSHIFT) { 192889857Sobrien /* If still no link, perhaps using 2/3 pair cable */ 192989857Sobrien em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp); 193089857Sobrien phy_tmp |= CR_1000T_MS_ENABLE; 193184865Sobrien em_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp); 193289857Sobrien if(adapter->hw.autoneg && 193389857Sobrien !em_phy_setup_autoneg(&adapter->hw) && 193489857Sobrien !em_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_tmp)) { 193589857Sobrien phy_tmp |= (MII_CR_AUTO_NEG_EN | 193689857Sobrien MII_CR_RESTART_AUTO_NEG); 193789857Sobrien em_write_phy_reg(&adapter->hw, PHY_CTRL, phy_tmp); 193889857Sobrien } 193989857Sobrien } 194089857Sobrien /* Restart process after EM_SMARTSPEED_MAX iterations */ 194189857Sobrien if(adapter->smartspeed++ == EM_SMARTSPEED_MAX) 194289857Sobrien adapter->smartspeed = 0; 194389857Sobrien 194489857Sobrien return; 194589857Sobrien} 194689857Sobrien 194789857Sobrien 1948218822Sdim/* 194989857Sobrien * Manage DMA'able memory. 195089857Sobrien */ 195189857Sobrienstatic void 195284865Sobrienem_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 195389857Sobrien{ 195489857Sobrien if (error) 195589857Sobrien return; 195689857Sobrien *(bus_addr_t*) arg = segs->ds_addr; 195789857Sobrien return; 195889857Sobrien} 195984865Sobrien 1960130561Sobrienstatic int 196189857Sobrienem_dma_malloc(struct adapter *adapter, bus_size_t size, 1962130561Sobrien struct em_dma_alloc *dma, int mapflags) 1963130561Sobrien{ 196484865Sobrien int r; 196589857Sobrien 1966218822Sdim r = bus_dma_tag_create(NULL, /* parent */ 1967218822Sdim PAGE_SIZE, 0, /* alignment, bounds */ 196889857Sobrien BUS_SPACE_MAXADDR, /* lowaddr */ 196984865Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 1970130561Sobrien NULL, NULL, /* filter, filterarg */ 197189857Sobrien size, /* maxsize */ 197289857Sobrien 1, /* nsegments */ 1973130561Sobrien size, /* maxsegsize */ 1974130561Sobrien BUS_DMA_ALLOCNOW, /* flags */ 197589857Sobrien NULL, /* lockfunc */ 197689857Sobrien NULL, /* lockarg */ 1977218822Sdim &dma->dma_tag); 197889857Sobrien if (r != 0) { 1979130561Sobrien printf("em%d: em_dma_malloc: bus_dma_tag_create failed; " 198084865Sobrien "error %u\n", adapter->unit, r); 198189857Sobrien goto fail_0; 198284865Sobrien } 198389857Sobrien 198489857Sobrien r = bus_dmamap_create(dma->dma_tag, BUS_DMA_NOWAIT, &dma->dma_map); 198589857Sobrien if (r != 0) { 198689857Sobrien printf("em%d: em_dma_malloc: bus_dmamap_create failed; " 198789857Sobrien "error %u\n", adapter->unit, r); 198889857Sobrien goto fail_1; 198989857Sobrien } 199089857Sobrien 199184865Sobrien r = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr, 199289857Sobrien BUS_DMA_NOWAIT, &dma->dma_map); 199389857Sobrien if (r != 0) { 199489857Sobrien printf("em%d: em_dma_malloc: bus_dmammem_alloc failed; " 199589857Sobrien "size %ju, error %d\n", adapter->unit, 199689857Sobrien (uintmax_t)size, r); 199789857Sobrien goto fail_2; 1998130561Sobrien } 199989857Sobrien 200089857Sobrien r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, 200189857Sobrien size, 200289857Sobrien em_dmamap_cb, 200389857Sobrien &dma->dma_paddr, 200489857Sobrien mapflags | BUS_DMA_NOWAIT); 200589857Sobrien if (r != 0) { 200684865Sobrien printf("em%d: em_dma_malloc: bus_dmamap_load failed; " 200789857Sobrien "error %u\n", adapter->unit, r); 200889857Sobrien goto fail_3; 200989857Sobrien } 201089857Sobrien 201189857Sobrien dma->dma_size = size; 201289857Sobrien return (0); 201389857Sobrien 201489857Sobrienfail_3: 201589857Sobrien bus_dmamap_unload(dma->dma_tag, dma->dma_map); 201689857Sobrienfail_2: 201789857Sobrien bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); 201889857Sobrienfail_1: 201989857Sobrien bus_dmamap_destroy(dma->dma_tag, dma->dma_map); 202089857Sobrien bus_dma_tag_destroy(dma->dma_tag); 202189857Sobrienfail_0: 202289857Sobrien dma->dma_map = NULL; 2023218822Sdim dma->dma_tag = NULL; 202489857Sobrien return (r); 202589857Sobrien} 202684865Sobrien 202789857Sobrienstatic void 202889857Sobrienem_dma_free(struct adapter *adapter, struct em_dma_alloc *dma) 202989857Sobrien{ 203089857Sobrien bus_dmamap_unload(dma->dma_tag, dma->dma_map); 203189857Sobrien bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); 203289857Sobrien bus_dmamap_destroy(dma->dma_tag, dma->dma_map); 203389857Sobrien bus_dma_tag_destroy(dma->dma_tag); 203484865Sobrien} 203589857Sobrien 203689857Sobrien 203789857Sobrien/********************************************************************* 203889857Sobrien * 203989857Sobrien * Allocate memory for tx_buffer structures. The tx_buffer stores all 204089857Sobrien * the information needed to transmit a packet on the wire. 204189857Sobrien * 204289857Sobrien **********************************************************************/ 204389857Sobrienstatic int 2044218822Sdimem_allocate_transmit_structures(struct adapter * adapter) 204589857Sobrien{ 204689857Sobrien if (!(adapter->tx_buffer_area = 204784865Sobrien (struct em_buffer *) malloc(sizeof(struct em_buffer) * 204884865Sobrien adapter->num_tx_desc, M_DEVBUF, 204989857Sobrien M_NOWAIT))) { 205084865Sobrien printf("em%d: Unable to allocate tx_buffer memory\n", 205189857Sobrien adapter->unit); 205289857Sobrien return ENOMEM; 205389857Sobrien } 205489857Sobrien 2055130561Sobrien bzero(adapter->tx_buffer_area, 205689857Sobrien sizeof(struct em_buffer) * adapter->num_tx_desc); 2057130561Sobrien 2058130561Sobrien return 0; 205984865Sobrien} 206084865Sobrien 2061130561Sobrien/********************************************************************* 206284865Sobrien * 206384865Sobrien * Allocate and initialize transmit structures. 206484865Sobrien * 206584865Sobrien **********************************************************************/ 206684865Sobrienstatic int 206784865Sobrienem_setup_transmit_structures(struct adapter * adapter) 206884865Sobrien{ 206984865Sobrien /* 207084865Sobrien * Setup DMA descriptor areas. 207184865Sobrien */ 207284865Sobrien if (bus_dma_tag_create(NULL, /* parent */ 207384865Sobrien PAGE_SIZE, 0, /* alignment, bounds */ 207484865Sobrien BUS_SPACE_MAXADDR, /* lowaddr */ 207584865Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 207684865Sobrien NULL, NULL, /* filter, filterarg */ 207784865Sobrien MCLBYTES * 8, /* maxsize */ 2078130561Sobrien EM_MAX_SCATTER, /* nsegments */ 207984865Sobrien MCLBYTES * 8, /* maxsegsize */ 208084865Sobrien BUS_DMA_ALLOCNOW, /* flags */ 208184865Sobrien NULL, /* lockfunc */ 208284865Sobrien NULL, /* lockarg */ 208389857Sobrien &adapter->txtag)) { 208489857Sobrien printf("em%d: Unable to allocate TX DMA tag\n", adapter->unit); 208584865Sobrien return (ENOMEM); 2086130561Sobrien } 2087130561Sobrien 2088218822Sdim if (em_allocate_transmit_structures(adapter)) 208984865Sobrien return (ENOMEM); 209089857Sobrien 209184865Sobrien bzero((void *) adapter->tx_desc_base, 209284865Sobrien (sizeof(struct em_tx_desc)) * adapter->num_tx_desc); 209384865Sobrien 209489857Sobrien adapter->next_avail_tx_desc = 0; 209584865Sobrien adapter->oldest_used_tx_desc = 0; 209684865Sobrien 2097218822Sdim /* Set number of descriptors available */ 209884865Sobrien adapter->num_tx_desc_avail = adapter->num_tx_desc; 209984865Sobrien 210084865Sobrien /* Set checksum context */ 210184865Sobrien adapter->active_checksum_context = OFFLOAD_NONE; 210284865Sobrien 2103218822Sdim return (0); 210484865Sobrien} 210584865Sobrien 210684865Sobrien/********************************************************************* 210784865Sobrien * 210884865Sobrien * Enable transmit unit. 210984865Sobrien * 2110130561Sobrien **********************************************************************/ 211184865Sobrienstatic void 211289857Sobrienem_initialize_transmit_unit(struct adapter * adapter) 2113130561Sobrien{ 211484865Sobrien u_int32_t reg_tctl; 211584865Sobrien u_int32_t reg_tipg = 0; 2116130561Sobrien u_int64_t bus_addr; 211784865Sobrien 211884865Sobrien INIT_DEBUGOUT("em_initialize_transmit_unit: begin"); 2119218822Sdim /* Setup the Base and Length of the Tx Descriptor Ring */ 2120218822Sdim bus_addr = adapter->txdma.dma_paddr; 2121218822Sdim E1000_WRITE_REG(&adapter->hw, TDBAL, (u_int32_t)bus_addr); 212284865Sobrien E1000_WRITE_REG(&adapter->hw, TDBAH, (u_int32_t)(bus_addr >> 32)); 212384865Sobrien E1000_WRITE_REG(&adapter->hw, TDLEN, 212489857Sobrien adapter->num_tx_desc * 212584865Sobrien sizeof(struct em_tx_desc)); 212684865Sobrien 212784865Sobrien /* Setup the HW Tx Head and Tail descriptor pointers */ 212884865Sobrien E1000_WRITE_REG(&adapter->hw, TDH, 0); 212984865Sobrien E1000_WRITE_REG(&adapter->hw, TDT, 0); 213084865Sobrien 2131130561Sobrien 213284865Sobrien HW_DEBUGOUT2("Base = %x, Length = %x\n", 213384865Sobrien E1000_READ_REG(&adapter->hw, TDBAL), 213484865Sobrien E1000_READ_REG(&adapter->hw, TDLEN)); 213584865Sobrien 213684865Sobrien /* Set the default values for the Tx Inter Packet Gap timer */ 213784865Sobrien switch (adapter->hw.mac_type) { 213884865Sobrien case em_82542_rev2_0: 213984865Sobrien case em_82542_rev2_1: 214084865Sobrien reg_tipg = DEFAULT_82542_TIPG_IPGT; 214184865Sobrien reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; 214284865Sobrien reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; 214384865Sobrien break; 214484865Sobrien default: 214584865Sobrien if (adapter->hw.media_type == em_media_type_fiber) 214684865Sobrien reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER; 214784865Sobrien else 214884865Sobrien reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER; 214984865Sobrien reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; 215084865Sobrien reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; 2151130561Sobrien } 215284865Sobrien 215384865Sobrien E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg); 215484865Sobrien E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay.value); 2155251227Spfg if(adapter->hw.mac_type >= em_82540) 215684865Sobrien E1000_WRITE_REG(&adapter->hw, TADV, 215784865Sobrien adapter->tx_abs_int_delay.value); 215884865Sobrien 215984865Sobrien /* Program the Transmit Control Register */ 216084865Sobrien reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN | 216184865Sobrien (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); 216289857Sobrien if (adapter->link_duplex == 1) { 216389857Sobrien reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; 216484865Sobrien } else { 2165130561Sobrien reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; 216684865Sobrien } 216784865Sobrien E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl); 216884865Sobrien 216984865Sobrien /* Setup Transmit Descriptor Settings for this adapter */ 217084865Sobrien adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS; 217184865Sobrien 217284865Sobrien if (adapter->tx_int_delay.value > 0) 217384865Sobrien adapter->txd_cmd |= E1000_TXD_CMD_IDE; 217484865Sobrien 2175130561Sobrien return; 217689857Sobrien} 217784865Sobrien 217884865Sobrien/********************************************************************* 217984865Sobrien * 218084865Sobrien * Free all transmit related data structures. 218184865Sobrien * 218284865Sobrien **********************************************************************/ 218384865Sobrienstatic void 218484865Sobrienem_free_transmit_structures(struct adapter * adapter) 218584865Sobrien{ 218684865Sobrien struct em_buffer *tx_buffer; 218784865Sobrien int i; 218884865Sobrien 218984865Sobrien INIT_DEBUGOUT("free_transmit_structures: begin"); 219084865Sobrien 219184865Sobrien if (adapter->tx_buffer_area != NULL) { 219284865Sobrien tx_buffer = adapter->tx_buffer_area; 219384865Sobrien for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) { 219484865Sobrien if (tx_buffer->m_head != NULL) { 219584865Sobrien bus_dmamap_unload(adapter->txtag, tx_buffer->map); 219684865Sobrien bus_dmamap_destroy(adapter->txtag, tx_buffer->map); 219784865Sobrien m_freem(tx_buffer->m_head); 219889857Sobrien } 219989857Sobrien tx_buffer->m_head = NULL; 2200130561Sobrien } 2201130561Sobrien } 2202130561Sobrien if (adapter->tx_buffer_area != NULL) { 2203130561Sobrien free(adapter->tx_buffer_area, M_DEVBUF); 220484865Sobrien adapter->tx_buffer_area = NULL; 220584865Sobrien } 2206130561Sobrien if (adapter->txtag != NULL) { 220784865Sobrien bus_dma_tag_destroy(adapter->txtag); 2208104834Sobrien adapter->txtag = NULL; 2209130561Sobrien } 2210130561Sobrien return; 2211104834Sobrien} 2212130561Sobrien 221384865Sobrien/********************************************************************* 221484865Sobrien * 221584865Sobrien * The offload context needs to be set when we transfer the first 221684865Sobrien * packet of a particular protocol (TCP/UDP). We change the 221784865Sobrien * context only if the protocol type changes. 221884865Sobrien * 221984865Sobrien **********************************************************************/ 222084865Sobrienstatic void 222184865Sobrienem_transmit_checksum_setup(struct adapter * adapter, 222284865Sobrien struct mbuf *mp, 2223104834Sobrien u_int32_t *txd_upper, 2224104834Sobrien u_int32_t *txd_lower) 2225104834Sobrien{ 222684865Sobrien struct em_context_desc *TXD; 222784865Sobrien struct em_buffer *tx_buffer; 222884865Sobrien int curr_txd; 222984865Sobrien 223084865Sobrien if (mp->m_pkthdr.csum_flags) { 223184865Sobrien 223284865Sobrien if (mp->m_pkthdr.csum_flags & CSUM_TCP) { 223384865Sobrien *txd_upper = E1000_TXD_POPTS_TXSM << 8; 223489857Sobrien *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; 223589857Sobrien if (adapter->active_checksum_context == OFFLOAD_TCP_IP) 223684865Sobrien return; 223784865Sobrien else 223884865Sobrien adapter->active_checksum_context = OFFLOAD_TCP_IP; 223984865Sobrien 224084865Sobrien } else if (mp->m_pkthdr.csum_flags & CSUM_UDP) { 224184865Sobrien *txd_upper = E1000_TXD_POPTS_TXSM << 8; 224284865Sobrien *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; 224384865Sobrien if (adapter->active_checksum_context == OFFLOAD_UDP_IP) 224484865Sobrien return; 224584865Sobrien else 224684865Sobrien adapter->active_checksum_context = OFFLOAD_UDP_IP; 224784865Sobrien } else { 224884865Sobrien *txd_upper = 0; 224984865Sobrien *txd_lower = 0; 225084865Sobrien return; 225184865Sobrien } 225289857Sobrien } else { 225389857Sobrien *txd_upper = 0; 225489857Sobrien *txd_lower = 0; 225584865Sobrien return; 2256130561Sobrien } 225784865Sobrien 225884865Sobrien /* If we reach this point, the checksum offload context 225989857Sobrien * needs to be reset. 226089857Sobrien */ 2261130561Sobrien curr_txd = adapter->next_avail_tx_desc; 226289857Sobrien tx_buffer = &adapter->tx_buffer_area[curr_txd]; 226384865Sobrien TXD = (struct em_context_desc *) &adapter->tx_desc_base[curr_txd]; 226484865Sobrien 2265130561Sobrien TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN; 226689857Sobrien TXD->lower_setup.ip_fields.ipcso = 2267130561Sobrien ETHER_HDR_LEN + offsetof(struct ip, ip_sum); 226884865Sobrien TXD->lower_setup.ip_fields.ipcse = 2269218822Sdim htole16(ETHER_HDR_LEN + sizeof(struct ip) - 1); 227084865Sobrien 227184865Sobrien TXD->upper_setup.tcp_fields.tucss = 227289857Sobrien ETHER_HDR_LEN + sizeof(struct ip); 227384865Sobrien TXD->upper_setup.tcp_fields.tucse = htole16(0); 227484865Sobrien 227584865Sobrien if (adapter->active_checksum_context == OFFLOAD_TCP_IP) { 227689857Sobrien TXD->upper_setup.tcp_fields.tucso = 2277130561Sobrien ETHER_HDR_LEN + sizeof(struct ip) + 227884865Sobrien offsetof(struct tcphdr, th_sum); 227984865Sobrien } else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) { 2280104834Sobrien TXD->upper_setup.tcp_fields.tucso = 2281130561Sobrien ETHER_HDR_LEN + sizeof(struct ip) + 228284865Sobrien offsetof(struct udphdr, uh_sum); 228384865Sobrien } 228484865Sobrien 228584865Sobrien TXD->tcp_seg_setup.data = htole32(0); 228684865Sobrien TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT); 228784865Sobrien 228884865Sobrien tx_buffer->m_head = NULL; 228984865Sobrien 229084865Sobrien if (++curr_txd == adapter->num_tx_desc) 229184865Sobrien curr_txd = 0; 2292130561Sobrien 229384865Sobrien adapter->num_tx_desc_avail--; 229484865Sobrien adapter->next_avail_tx_desc = curr_txd; 229584865Sobrien 229684865Sobrien return; 229784865Sobrien} 229884865Sobrien 229984865Sobrien/********************************************************************** 230084865Sobrien * 230184865Sobrien * Examine each tx_buffer in the used queue. If the hardware is done 230284865Sobrien * processing the packet then free associated resources. The 230389857Sobrien * tx_buffer is put back on the free queue. 230489857Sobrien * 2305130561Sobrien **********************************************************************/ 230684865Sobrienstatic void 2307130561Sobrienem_clean_transmit_interrupts(struct adapter * adapter) 230884865Sobrien{ 230984865Sobrien int i, num_avail; 2310130561Sobrien struct em_buffer *tx_buffer; 231184865Sobrien struct em_tx_desc *tx_desc; 231284865Sobrien struct ifnet *ifp = &adapter->interface_data.ac_if; 231384865Sobrien 231484865Sobrien mtx_assert(&adapter->mtx, MA_OWNED); 231589857Sobrien 231689857Sobrien if (adapter->num_tx_desc_avail == adapter->num_tx_desc) 231784865Sobrien return; 2318130561Sobrien 2319130561Sobrien#ifdef DBG_STATS 2320218822Sdim adapter->clean_tx_interrupts++; 232189857Sobrien#endif 232289857Sobrien num_avail = adapter->num_tx_desc_avail; 232389857Sobrien i = adapter->oldest_used_tx_desc; 232484865Sobrien 2325218822Sdim tx_buffer = &adapter->tx_buffer_area[i]; 232689857Sobrien tx_desc = &adapter->tx_desc_base[i]; 232784865Sobrien 2328104834Sobrien while (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) { 232989857Sobrien 233084865Sobrien tx_desc->upper.data = 0; 2331104834Sobrien num_avail++; 2332130561Sobrien 2333130561Sobrien if (tx_buffer->m_head) { 2334104834Sobrien ifp->if_opackets++; 2335104834Sobrien bus_dmamap_sync(adapter->txtag, tx_buffer->map, 2336130561Sobrien BUS_DMASYNC_POSTWRITE); 2337130561Sobrien bus_dmamap_unload(adapter->txtag, tx_buffer->map); 2338130561Sobrien bus_dmamap_destroy(adapter->txtag, tx_buffer->map); 2339218822Sdim 2340104834Sobrien m_freem(tx_buffer->m_head); 2341104834Sobrien tx_buffer->m_head = NULL; 234289857Sobrien } 2343104834Sobrien 2344104834Sobrien if (++i == adapter->num_tx_desc) 2345104834Sobrien i = 0; 2346130561Sobrien 2347104834Sobrien tx_buffer = &adapter->tx_buffer_area[i]; 2348104834Sobrien tx_desc = &adapter->tx_desc_base[i]; 234989857Sobrien } 235089857Sobrien 235184865Sobrien adapter->oldest_used_tx_desc = i; 235289857Sobrien 235389857Sobrien /* 2354130561Sobrien * If we have enough room, clear IFF_OACTIVE to tell the stack 235584865Sobrien * that it is OK to send packets. 235684865Sobrien * If there are no pending descriptors, clear the timeout. Otherwise, 235784865Sobrien * if some descriptors have been freed, restart the timeout. 235884865Sobrien */ 2359130561Sobrien if (num_avail > EM_TX_CLEANUP_THRESHOLD) { 2360130561Sobrien ifp->if_flags &= ~IFF_OACTIVE; 2361218822Sdim if (num_avail == adapter->num_tx_desc) 236284865Sobrien ifp->if_timer = 0; 236384865Sobrien else if (num_avail == adapter->num_tx_desc_avail) 236489857Sobrien ifp->if_timer = EM_TX_TIMEOUT; 236584865Sobrien } 236684865Sobrien adapter->num_tx_desc_avail = num_avail; 236784865Sobrien return; 236889857Sobrien} 236984865Sobrien 237084865Sobrien/********************************************************************* 237189857Sobrien * 237289857Sobrien * Get a buffer from system mbuf buffer pool. 237384865Sobrien * 237484865Sobrien **********************************************************************/ 237584865Sobrienstatic int 237684865Sobrienem_get_buf(int i, struct adapter *adapter, 237784865Sobrien struct mbuf *nmp) 237884865Sobrien{ 237984865Sobrien register struct mbuf *mp = nmp; 238084865Sobrien struct em_buffer *rx_buffer; 238184865Sobrien struct ifnet *ifp; 2382130561Sobrien bus_addr_t paddr; 238389857Sobrien int error; 238489857Sobrien 238584865Sobrien ifp = &adapter->interface_data.ac_if; 238684865Sobrien 2387130561Sobrien if (mp == NULL) { 238884865Sobrien mp = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 238984865Sobrien if (mp == NULL) { 239089857Sobrien adapter->mbuf_cluster_failed++; 2391251227Spfg return(ENOBUFS); 239289857Sobrien } 239389857Sobrien mp->m_len = mp->m_pkthdr.len = MCLBYTES; 239489857Sobrien } else { 239584865Sobrien mp->m_len = mp->m_pkthdr.len = MCLBYTES; 239689857Sobrien mp->m_data = mp->m_ext.ext_buf; 239784865Sobrien mp->m_next = NULL; 239889857Sobrien } 239989857Sobrien 240089857Sobrien if (ifp->if_mtu <= ETHERMTU) { 2401130561Sobrien m_adj(mp, ETHER_ALIGN); 240284865Sobrien } 240384865Sobrien 240489857Sobrien rx_buffer = &adapter->rx_buffer_area[i]; 240584865Sobrien 240684865Sobrien /* 240789857Sobrien * Using memory from the mbuf cluster pool, invoke the 240889857Sobrien * bus_dma machinery to arrange the memory mapping. 240984865Sobrien */ 241084865Sobrien error = bus_dmamap_load(adapter->rxtag, rx_buffer->map, 2411130561Sobrien mtod(mp, void *), mp->m_len, 241289857Sobrien em_dmamap_cb, &paddr, 0); 241384865Sobrien if (error) { 241489857Sobrien m_free(mp); 241584865Sobrien return(error); 241684865Sobrien } 241784865Sobrien rx_buffer->m_head = mp; 241884865Sobrien adapter->rx_desc_base[i].buffer_addr = htole64(paddr); 241984865Sobrien bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD); 242084865Sobrien 242184865Sobrien return(0); 2422104834Sobrien} 2423104834Sobrien 2424104834Sobrien/********************************************************************* 2425104834Sobrien * 2426130561Sobrien * Allocate memory for rx_buffer structures. Since we use one 2427104834Sobrien * rx_buffer per received packet, the maximum number of rx_buffer's 2428130561Sobrien * that we'll need is equal to the number of receive descriptors 2429104834Sobrien * that we've allocated. 243084865Sobrien * 243184865Sobrien **********************************************************************/ 243284865Sobrienstatic int 243384865Sobrienem_allocate_receive_structures(struct adapter * adapter) 243484865Sobrien{ 243589857Sobrien int i, error; 243684865Sobrien struct em_buffer *rx_buffer; 243789857Sobrien 243889857Sobrien if (!(adapter->rx_buffer_area = 243989857Sobrien (struct em_buffer *) malloc(sizeof(struct em_buffer) * 2440130561Sobrien adapter->num_rx_desc, M_DEVBUF, 244189857Sobrien M_NOWAIT))) { 2442130561Sobrien printf("em%d: Unable to allocate rx_buffer memory\n", 244384865Sobrien adapter->unit); 244489857Sobrien return(ENOMEM); 2445130561Sobrien } 244684865Sobrien 2447104834Sobrien bzero(adapter->rx_buffer_area, 2448130561Sobrien sizeof(struct em_buffer) * adapter->num_rx_desc); 2449130561Sobrien 2450104834Sobrien error = bus_dma_tag_create(NULL, /* parent */ 2451130561Sobrien PAGE_SIZE, 0, /* alignment, bounds */ 2452104834Sobrien BUS_SPACE_MAXADDR, /* lowaddr */ 245384865Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 2454104834Sobrien NULL, NULL, /* filter, filterarg */ 2455104834Sobrien MCLBYTES, /* maxsize */ 2456104834Sobrien 1, /* nsegments */ 2457104834Sobrien MCLBYTES, /* maxsegsize */ 245884865Sobrien BUS_DMA_ALLOCNOW, /* flags */ 245984865Sobrien NULL, /* lockfunc */ 2460130561Sobrien NULL, /* lockarg */ 2461130561Sobrien &adapter->rxtag); 246284865Sobrien if (error != 0) { 246389857Sobrien printf("em%d: em_allocate_receive_structures: " 2464130561Sobrien "bus_dma_tag_create failed; error %u\n", 2465130561Sobrien adapter->unit, error); 2466130561Sobrien goto fail_0; 2467130561Sobrien } 2468130561Sobrien 2469130561Sobrien rx_buffer = adapter->rx_buffer_area; 2470130561Sobrien for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { 2471130561Sobrien error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT, 2472130561Sobrien &rx_buffer->map); 247389857Sobrien if (error != 0) { 2474130561Sobrien printf("em%d: em_allocate_receive_structures: " 2475130561Sobrien "bus_dmamap_create failed; error %u\n", 2476130561Sobrien adapter->unit, error); 2477130561Sobrien goto fail_1; 2478130561Sobrien } 247989857Sobrien } 248089857Sobrien 248184865Sobrien for (i = 0; i < adapter->num_rx_desc; i++) { 248284865Sobrien error = em_get_buf(i, adapter, NULL); 248389857Sobrien if (error != 0) { 248489857Sobrien adapter->rx_buffer_area[i].m_head = NULL; 248589857Sobrien adapter->rx_desc_base[i].buffer_addr = 0; 248689857Sobrien return(error); 248789857Sobrien } 248884865Sobrien } 248989857Sobrien 2490218822Sdim return(0); 249189857Sobrien 2492130561Sobrienfail_1: 249384865Sobrien bus_dma_tag_destroy(adapter->rxtag); 249489857Sobrienfail_0: 249584865Sobrien adapter->rxtag = NULL; 2496104834Sobrien free(adapter->rx_buffer_area, M_DEVBUF); 2497104834Sobrien adapter->rx_buffer_area = NULL; 2498104834Sobrien return (error); 2499130561Sobrien} 250089857Sobrien 250184865Sobrien/********************************************************************* 250289857Sobrien * 250389857Sobrien * Allocate and initialize receive structures. 250489857Sobrien * 250589857Sobrien **********************************************************************/ 250689857Sobrienstatic int 250789857Sobrienem_setup_receive_structures(struct adapter * adapter) 250889857Sobrien{ 2509130561Sobrien bzero((void *) adapter->rx_desc_base, 251089857Sobrien (sizeof(struct em_rx_desc)) * adapter->num_rx_desc); 251189857Sobrien 251289857Sobrien if (em_allocate_receive_structures(adapter)) 251384865Sobrien return ENOMEM; 251489857Sobrien 251589857Sobrien /* Setup our descriptor pointers */ 251689857Sobrien adapter->next_rx_desc_to_check = 0; 251789857Sobrien return(0); 251889857Sobrien} 251989857Sobrien 252089857Sobrien/********************************************************************* 252184865Sobrien * 2522130561Sobrien * Enable receive unit. 252384865Sobrien * 252489857Sobrien **********************************************************************/ 252589857Sobrienstatic void 252684865Sobrienem_initialize_receive_unit(struct adapter * adapter) 252789857Sobrien{ 2528218822Sdim u_int32_t reg_rctl; 2529218822Sdim u_int32_t reg_rxcsum; 2530218822Sdim struct ifnet *ifp; 253184865Sobrien u_int64_t bus_addr; 253284865Sobrien 253384865Sobrien INIT_DEBUGOUT("em_initialize_receive_unit: begin"); 253484865Sobrien ifp = &adapter->interface_data.ac_if; 253589857Sobrien 2536130561Sobrien /* Make sure receives are disabled while setting up the descriptor ring */ 253789857Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, 0); 253884865Sobrien 2539130561Sobrien /* Set the Receive Delay Timer Register */ 254089857Sobrien E1000_WRITE_REG(&adapter->hw, RDTR, 2541130561Sobrien adapter->rx_int_delay.value | E1000_RDT_FPDB); 254284865Sobrien 254389857Sobrien if(adapter->hw.mac_type >= em_82540) { 254484865Sobrien E1000_WRITE_REG(&adapter->hw, RADV, 254589857Sobrien adapter->rx_abs_int_delay.value); 254689857Sobrien 254789857Sobrien /* Set the interrupt throttling rate. Value is calculated 254889857Sobrien * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ 254989857Sobrien#define MAX_INTS_PER_SEC 8000 255084865Sobrien#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) 255184865Sobrien E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR); 2552130561Sobrien } 255389857Sobrien 255484865Sobrien /* Setup the Base and Length of the Rx Descriptor Ring */ 255584865Sobrien bus_addr = adapter->rxdma.dma_paddr; 255684865Sobrien E1000_WRITE_REG(&adapter->hw, RDBAL, (u_int32_t)bus_addr); 255789857Sobrien E1000_WRITE_REG(&adapter->hw, RDBAH, (u_int32_t)(bus_addr >> 32)); 255889857Sobrien E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc * 255989857Sobrien sizeof(struct em_rx_desc)); 2560130561Sobrien 256184865Sobrien /* Setup the HW Rx Head and Tail Descriptor Pointers */ 256284865Sobrien E1000_WRITE_REG(&adapter->hw, RDH, 0); 2563130561Sobrien E1000_WRITE_REG(&adapter->hw, RDT, adapter->num_rx_desc - 1); 256484865Sobrien 256584865Sobrien /* Setup the Receive Control Register */ 256684865Sobrien reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | 256784865Sobrien E1000_RCTL_RDMTS_HALF | 256884865Sobrien (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); 2569130561Sobrien 257089857Sobrien if (adapter->hw.tbi_compatibility_on == TRUE) 2571130561Sobrien reg_rctl |= E1000_RCTL_SBP; 2572130561Sobrien 2573130561Sobrien 257484865Sobrien switch (adapter->rx_buffer_len) { 257584865Sobrien default: 2576130561Sobrien case EM_RXBUFFER_2048: 257784865Sobrien reg_rctl |= E1000_RCTL_SZ_2048; 257884865Sobrien break; 257984865Sobrien case EM_RXBUFFER_4096: 258084865Sobrien reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; 258184865Sobrien break; 258284865Sobrien case EM_RXBUFFER_8192: 258384865Sobrien reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; 258484865Sobrien break; 258584865Sobrien case EM_RXBUFFER_16384: 258684865Sobrien reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; 258784865Sobrien break; 258884865Sobrien } 258984865Sobrien 2590218822Sdim if (ifp->if_mtu > ETHERMTU) 2591218822Sdim reg_rctl |= E1000_RCTL_LPE; 259284865Sobrien 259384865Sobrien /* Enable 82543 Receive Checksum Offload for TCP and UDP */ 259484865Sobrien if ((adapter->hw.mac_type >= em_82543) && 259584865Sobrien (ifp->if_capenable & IFCAP_RXCSUM)) { 259684865Sobrien reg_rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM); 259784865Sobrien reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL); 259884865Sobrien E1000_WRITE_REG(&adapter->hw, RXCSUM, reg_rxcsum); 259984865Sobrien } 260084865Sobrien 260184865Sobrien /* Enable Receives */ 260284865Sobrien E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); 260389857Sobrien 260489857Sobrien em_set_promisc(adapter); 260589857Sobrien return; 260689857Sobrien} 260789857Sobrien 260889857Sobrien/********************************************************************* 260989857Sobrien * 261089857Sobrien * Free receive related data structures. 261189857Sobrien * 261289857Sobrien **********************************************************************/ 261389857Sobrienstatic void 261489857Sobrienem_free_receive_structures(struct adapter *adapter) 261589857Sobrien{ 261689857Sobrien struct em_buffer *rx_buffer; 261789857Sobrien int i; 261889857Sobrien 261989857Sobrien INIT_DEBUGOUT("free_receive_structures: begin"); 262089857Sobrien 262189857Sobrien if (adapter->rx_buffer_area != NULL) { 262289857Sobrien rx_buffer = adapter->rx_buffer_area; 262389857Sobrien for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) { 262489857Sobrien if (rx_buffer->map != NULL) { 262589857Sobrien bus_dmamap_unload(adapter->rxtag, rx_buffer->map); 262689857Sobrien bus_dmamap_destroy(adapter->rxtag, rx_buffer->map); 262789857Sobrien } 262889857Sobrien if (rx_buffer->m_head != NULL) 262989857Sobrien m_freem(rx_buffer->m_head); 263089857Sobrien rx_buffer->m_head = NULL; 263189857Sobrien } 263289857Sobrien } 263389857Sobrien if (adapter->rx_buffer_area != NULL) { 263489857Sobrien free(adapter->rx_buffer_area, M_DEVBUF); 263589857Sobrien adapter->rx_buffer_area = NULL; 263689857Sobrien } 263789857Sobrien if (adapter->rxtag != NULL) { 263889857Sobrien bus_dma_tag_destroy(adapter->rxtag); 263989857Sobrien adapter->rxtag = NULL; 264089857Sobrien } 264189857Sobrien return; 264289857Sobrien} 264389857Sobrien 264489857Sobrien/********************************************************************* 264589857Sobrien * 264689857Sobrien * This routine executes in interrupt context. It replenishes 264789857Sobrien * the mbufs in the descriptor and sends data which has been 264889857Sobrien * dma'ed into host memory to upper layer. 264989857Sobrien * 265089857Sobrien * We loop at most count times if count is > 0, or until done if 265189857Sobrien * count < 0. 265289857Sobrien * 265389857Sobrien *********************************************************************/ 265489857Sobrienstatic void 265589857Sobrienem_process_receive_interrupts(struct adapter * adapter, int count) 265689857Sobrien{ 265789857Sobrien struct ifnet *ifp; 265889857Sobrien struct mbuf *mp; 265989857Sobrien#if __FreeBSD_version < 500000 266089857Sobrien struct ether_header *eh; 266189857Sobrien#endif 266289857Sobrien u_int8_t accept_frame = 0; 266389857Sobrien u_int8_t eop = 0; 266489857Sobrien u_int16_t len, desc_len; 266589857Sobrien int i; 266689857Sobrien 266789857Sobrien /* Pointer to the receive descriptor being examined. */ 266889857Sobrien struct em_rx_desc *current_desc; 266989857Sobrien 267089857Sobrien mtx_assert(&adapter->mtx, MA_OWNED); 267189857Sobrien 267289857Sobrien ifp = &adapter->interface_data.ac_if; 267389857Sobrien i = adapter->next_rx_desc_to_check; 267489857Sobrien current_desc = &adapter->rx_desc_base[i]; 267589857Sobrien 267689857Sobrien if (!((current_desc->status) & E1000_RXD_STAT_DD)) { 267789857Sobrien#ifdef DBG_STATS 267889857Sobrien adapter->no_pkts_avail++; 267989857Sobrien#endif 268089857Sobrien return; 268189857Sobrien } 268289857Sobrien 268389857Sobrien while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) { 268489857Sobrien 268589857Sobrien mp = adapter->rx_buffer_area[i].m_head; 268689857Sobrien bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map, 268789857Sobrien BUS_DMASYNC_POSTREAD); 268889857Sobrien 268989857Sobrien accept_frame = 1; 269089857Sobrien desc_len = le16toh(current_desc->length); 269189857Sobrien if (current_desc->status & E1000_RXD_STAT_EOP) { 269289857Sobrien count--; 269389857Sobrien eop = 1; 269489857Sobrien len = desc_len - ETHER_CRC_LEN; 269589857Sobrien } else { 269689857Sobrien eop = 0; 269789857Sobrien len = desc_len; 269889857Sobrien } 2699104834Sobrien 2700104834Sobrien if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { 2701104834Sobrien u_int8_t last_byte; 2702104834Sobrien u_int32_t pkt_len = desc_len; 2703104834Sobrien 2704104834Sobrien if (adapter->fmp != NULL) 2705104834Sobrien pkt_len += adapter->fmp->m_pkthdr.len; 2706104834Sobrien 2707104834Sobrien last_byte = *(mtod(mp, caddr_t) + desc_len - 1); 2708104834Sobrien 2709104834Sobrien if (TBI_ACCEPT(&adapter->hw, current_desc->status, 2710104834Sobrien current_desc->errors, 2711104834Sobrien pkt_len, last_byte)) { 2712104834Sobrien em_tbi_adjust_stats(&adapter->hw, 2713104834Sobrien &adapter->stats, 2714104834Sobrien pkt_len, 2715104834Sobrien adapter->hw.mac_addr); 2716104834Sobrien len--; 2717104834Sobrien } 2718104834Sobrien else { 2719104834Sobrien accept_frame = 0; 2720104834Sobrien } 2721104834Sobrien } 2722104834Sobrien 2723104834Sobrien if (accept_frame) { 2724104834Sobrien 2725104834Sobrien if (em_get_buf(i, adapter, NULL) == ENOBUFS) { 2726104834Sobrien adapter->dropped_pkts++; 2727104834Sobrien em_get_buf(i, adapter, mp); 2728104834Sobrien if (adapter->fmp != NULL) 2729104834Sobrien m_freem(adapter->fmp); 2730104834Sobrien adapter->fmp = NULL; 2731104834Sobrien adapter->lmp = NULL; 2732104834Sobrien break; 273389857Sobrien } 273489857Sobrien 273589857Sobrien /* Assign correct length to the current fragment */ 273689857Sobrien mp->m_len = len; 273789857Sobrien 273889857Sobrien if (adapter->fmp == NULL) { 273989857Sobrien mp->m_pkthdr.len = len; 274089857Sobrien adapter->fmp = mp; /* Store the first mbuf */ 274189857Sobrien adapter->lmp = mp; 274289857Sobrien } else { 274389857Sobrien /* Chain mbuf's together */ 274489857Sobrien mp->m_flags &= ~M_PKTHDR; 274589857Sobrien adapter->lmp->m_next = mp; 274689857Sobrien adapter->lmp = adapter->lmp->m_next; 274789857Sobrien adapter->fmp->m_pkthdr.len += len; 274889857Sobrien } 274989857Sobrien 275089857Sobrien if (eop) { 275189857Sobrien adapter->fmp->m_pkthdr.rcvif = ifp; 275289857Sobrien ifp->if_ipackets++; 275389857Sobrien 275489857Sobrien#if __FreeBSD_version < 500000 275589857Sobrien eh = mtod(adapter->fmp, struct ether_header *); 275689857Sobrien /* Remove ethernet header from mbuf */ 275789857Sobrien m_adj(adapter->fmp, sizeof(struct ether_header)); 275889857Sobrien em_receive_checksum(adapter, current_desc, 275989857Sobrien adapter->fmp); 276089857Sobrien if (current_desc->status & E1000_RXD_STAT_VP) 276189857Sobrien VLAN_INPUT_TAG(eh, adapter->fmp, 276289857Sobrien (current_desc->special & 276389857Sobrien E1000_RXD_SPC_VLAN_MASK)); 276489857Sobrien else 276589857Sobrien ether_input(ifp, eh, adapter->fmp); 2766130561Sobrien#else 2767130561Sobrien 2768104834Sobrien em_receive_checksum(adapter, current_desc, 2769104834Sobrien adapter->fmp); 2770104834Sobrien if (current_desc->status & E1000_RXD_STAT_VP) 2771104834Sobrien VLAN_INPUT_TAG(ifp, adapter->fmp, 2772104834Sobrien (current_desc->special & 2773104834Sobrien E1000_RXD_SPC_VLAN_MASK), 2774104834Sobrien adapter->fmp = NULL); 2775104834Sobrien 2776104834Sobrien if (adapter->fmp != NULL) { 2777104834Sobrien EM_UNLOCK(adapter); 2778104834Sobrien (*ifp->if_input)(ifp, adapter->fmp); 2779104834Sobrien EM_LOCK(adapter); 2780130561Sobrien } 2781104834Sobrien#endif 278289857Sobrien adapter->fmp = NULL; 2783130561Sobrien adapter->lmp = NULL; 2784130561Sobrien } 2785104834Sobrien } else { 2786104834Sobrien adapter->dropped_pkts++; 2787104834Sobrien em_get_buf(i, adapter, mp); 2788104834Sobrien if (adapter->fmp != NULL) 2789104834Sobrien m_freem(adapter->fmp); 2790104834Sobrien adapter->fmp = NULL; 2791104834Sobrien adapter->lmp = NULL; 2792104834Sobrien } 2793104834Sobrien 2794104834Sobrien /* Zero out the receive descriptors status */ 2795104834Sobrien current_desc->status = 0; 2796104834Sobrien 2797104834Sobrien /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ 2798104834Sobrien E1000_WRITE_REG(&adapter->hw, RDT, i); 2799104834Sobrien 2800104834Sobrien /* Advance our pointers to the next descriptor */ 2801130561Sobrien if (++i == adapter->num_rx_desc) { 2802104834Sobrien i = 0; 2803104834Sobrien current_desc = adapter->rx_desc_base; 2804130561Sobrien } else 2805130561Sobrien current_desc++; 2806104834Sobrien } 2807104834Sobrien adapter->next_rx_desc_to_check = i; 2808104834Sobrien return; 2809104834Sobrien} 2810104834Sobrien 2811104834Sobrien/********************************************************************* 2812104834Sobrien * 2813104834Sobrien * Verify that the hardware indicated that the checksum is valid. 2814104834Sobrien * Inform the stack about the status of checksum so that stack 2815104834Sobrien * doesn't spend time verifying the checksum. 2816104834Sobrien * 2817104834Sobrien *********************************************************************/ 2818104834Sobrienstatic void 2819130561Sobrienem_receive_checksum(struct adapter *adapter, 2820104834Sobrien struct em_rx_desc *rx_desc, 2821104834Sobrien struct mbuf *mp) 2822130561Sobrien{ 2823130561Sobrien /* 82543 or newer only */ 2824104834Sobrien if ((adapter->hw.mac_type < em_82543) || 2825104834Sobrien /* Ignore Checksum bit is set */ 2826104834Sobrien (rx_desc->status & E1000_RXD_STAT_IXSM)) { 2827104834Sobrien mp->m_pkthdr.csum_flags = 0; 2828104834Sobrien return; 2829104834Sobrien } 2830104834Sobrien 2831104834Sobrien if (rx_desc->status & E1000_RXD_STAT_IPCS) { 2832104834Sobrien /* Did it pass? */ 2833104834Sobrien if (!(rx_desc->errors & E1000_RXD_ERR_IPE)) { 2834104834Sobrien /* IP Checksum Good */ 2835104834Sobrien mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; 2836104834Sobrien mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2837130561Sobrien 2838104834Sobrien } else { 2839104834Sobrien mp->m_pkthdr.csum_flags = 0; 2840130561Sobrien } 2841130561Sobrien } 2842104834Sobrien 2843104834Sobrien if (rx_desc->status & E1000_RXD_STAT_TCPCS) { 2844104834Sobrien /* Did it pass? */ 2845104834Sobrien if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) { 2846104834Sobrien mp->m_pkthdr.csum_flags |= 2847104834Sobrien (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 2848104834Sobrien mp->m_pkthdr.csum_data = htons(0xffff); 2849104834Sobrien } 2850104834Sobrien } 2851104834Sobrien 2852104834Sobrien return; 2853104834Sobrien} 2854130561Sobrien 2855104834Sobrien 2856104834Sobrienstatic void 2857104834Sobrienem_enable_vlans(struct adapter *adapter) 2858104834Sobrien{ 2859104834Sobrien uint32_t ctrl; 2860104834Sobrien 2861104834Sobrien E1000_WRITE_REG(&adapter->hw, VET, ETHERTYPE_VLAN); 2862130561Sobrien 2863104834Sobrien ctrl = E1000_READ_REG(&adapter->hw, CTRL); 2864104834Sobrien ctrl |= E1000_CTRL_VME; 2865130561Sobrien E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); 2866130561Sobrien 2867104834Sobrien return; 2868104834Sobrien} 2869104834Sobrien 2870104834Sobrienstatic void 2871104834Sobrienem_enable_intr(struct adapter * adapter) 2872104834Sobrien{ 2873104834Sobrien E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK)); 2874104834Sobrien return; 2875104834Sobrien} 2876104834Sobrien 2877104834Sobrienstatic void 2878104834Sobrienem_disable_intr(struct adapter *adapter) 2879104834Sobrien{ 2880104834Sobrien E1000_WRITE_REG(&adapter->hw, IMC, 2881130561Sobrien (0xffffffff & ~E1000_IMC_RXSEQ)); 2882130561Sobrien return; 2883104834Sobrien} 2884104834Sobrien 2885104834Sobrienstatic int 2886104834Sobrienem_is_valid_ether_addr(u_int8_t *addr) 2887104834Sobrien{ 2888104834Sobrien char zero_addr[6] = { 0, 0, 0, 0, 0, 0 }; 2889104834Sobrien 2890104834Sobrien if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) { 2891104834Sobrien return (FALSE); 2892104834Sobrien } 2893104834Sobrien 2894104834Sobrien return(TRUE); 2895130561Sobrien} 2896104834Sobrien 2897130561Sobrienvoid 2898104834Sobrienem_write_pci_cfg(struct em_hw *hw, 2899104834Sobrien uint32_t reg, 2900104834Sobrien uint16_t *value) 2901104834Sobrien{ 2902130561Sobrien pci_write_config(((struct em_osdep *)hw->back)->dev, reg, 2903104834Sobrien *value, 2); 2904104834Sobrien} 2905130561Sobrien 2906104834Sobrienvoid 2907104834Sobrienem_read_pci_cfg(struct em_hw *hw, uint32_t reg, 2908130561Sobrien uint16_t *value) 2909130561Sobrien{ 2910104834Sobrien *value = pci_read_config(((struct em_osdep *)hw->back)->dev, 2911104834Sobrien reg, 2); 2912104834Sobrien return; 2913104834Sobrien} 2914104834Sobrien 2915104834Sobrienvoid 2916104834Sobrienem_pci_set_mwi(struct em_hw *hw) 2917104834Sobrien{ 2918104834Sobrien pci_write_config(((struct em_osdep *)hw->back)->dev, 2919104834Sobrien PCIR_COMMAND, 2920104834Sobrien (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); 2921104834Sobrien return; 2922104834Sobrien} 2923104834Sobrien 2924104834Sobrienvoid 2925104834Sobrienem_pci_clear_mwi(struct em_hw *hw) 2926104834Sobrien{ 2927130561Sobrien pci_write_config(((struct em_osdep *)hw->back)->dev, 2928104834Sobrien PCIR_COMMAND, 2929104834Sobrien (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2); 2930130561Sobrien return; 2931130561Sobrien} 2932104834Sobrien 2933104834Sobrienuint32_t 2934104834Sobrienem_io_read(struct em_hw *hw, uint32_t port) 2935104834Sobrien{ 2936104834Sobrien return(inl(port)); 2937104834Sobrien} 2938104834Sobrien 2939104834Sobrienvoid 2940104834Sobrienem_io_write(struct em_hw *hw, uint32_t port, uint32_t value) 2941104834Sobrien{ 2942104834Sobrien outl(port, value); 2943104834Sobrien return; 2944104834Sobrien} 2945104834Sobrien 2946130561Sobrien/********************************************************************* 2947130561Sobrien* 82544 Coexistence issue workaround. 2948104834Sobrien* There are 2 issues. 2949104834Sobrien* 1. Transmit Hang issue. 2950104834Sobrien* To detect this issue, following equation can be used... 2951104834Sobrien* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. 2952104834Sobrien* If SUM[3:0] is in between 1 to 4, we will have this issue. 2953104834Sobrien* 2954104834Sobrien* 2. DAC issue. 2955104834Sobrien* To detect this issue, following equation can be used... 2956104834Sobrien* SIZE[3:0] + ADDR[2:0] = SUM[3:0]. 2957104834Sobrien* If SUM[3:0] is in between 9 to c, we will have this issue. 2958130561Sobrien* 2959130561Sobrien* 2960218822Sdim* WORKAROUND: 2961104834Sobrien* Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC) 2962104834Sobrien* 2963104834Sobrien*** *********************************************************************/ 2964130561Sobrienstatic u_int32_t 2965104834Sobrienem_fill_descriptors (u_int64_t address, 2966104834Sobrien u_int32_t length, 2967130561Sobrien PDESC_ARRAY desc_array) 2968104834Sobrien{ 2969104834Sobrien /* Since issue is sensitive to length and address.*/ 2970104834Sobrien /* Let us first check the address...*/ 2971104834Sobrien u_int32_t safe_terminator; 2972130561Sobrien if (length <= 4) { 2973130561Sobrien desc_array->descriptor[0].address = address; 2974130561Sobrien desc_array->descriptor[0].length = length; 2975130561Sobrien desc_array->elements = 1; 2976130561Sobrien return desc_array->elements; 2977104834Sobrien } 2978104834Sobrien safe_terminator = (u_int32_t)((((u_int32_t)address & 0x7) + (length & 0xF)) & 0xF); 2979130561Sobrien /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */ 2980130561Sobrien if (safe_terminator == 0 || 2981130561Sobrien (safe_terminator > 4 && 2982130561Sobrien safe_terminator < 9) || 2983130561Sobrien (safe_terminator > 0xC && 2984130561Sobrien safe_terminator <= 0xF)) { 2985104834Sobrien desc_array->descriptor[0].address = address; 2986104834Sobrien desc_array->descriptor[0].length = length; 2987104834Sobrien desc_array->elements = 1; 2988130561Sobrien return desc_array->elements; 2989104834Sobrien } 2990130561Sobrien 2991104834Sobrien desc_array->descriptor[0].address = address; 2992130561Sobrien desc_array->descriptor[0].length = length - 4; 2993104834Sobrien desc_array->descriptor[1].address = address + (length - 4); 2994104834Sobrien desc_array->descriptor[1].length = 4; 2995130561Sobrien desc_array->elements = 2; 2996130561Sobrien return desc_array->elements; 2997104834Sobrien} 2998104834Sobrien 2999104834Sobrien/********************************************************************** 3000104834Sobrien * 3001104834Sobrien * Update the board statistics counters. 3002130561Sobrien * 3003104834Sobrien **********************************************************************/ 3004104834Sobrienstatic void 3005104834Sobrienem_update_stats_counters(struct adapter *adapter) 3006130561Sobrien{ 3007104834Sobrien struct ifnet *ifp; 3008104834Sobrien 3009130561Sobrien if(adapter->hw.media_type == em_media_type_copper || 3010130561Sobrien (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { 3011104834Sobrien adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS); 3012104834Sobrien adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC); 3013104834Sobrien } 3014104834Sobrien adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, CRCERRS); 3015104834Sobrien adapter->stats.mpc += E1000_READ_REG(&adapter->hw, MPC); 3016104834Sobrien adapter->stats.scc += E1000_READ_REG(&adapter->hw, SCC); 3017104834Sobrien adapter->stats.ecol += E1000_READ_REG(&adapter->hw, ECOL); 3018104834Sobrien 3019104834Sobrien adapter->stats.mcc += E1000_READ_REG(&adapter->hw, MCC); 3020104834Sobrien adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL); 3021104834Sobrien adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC); 3022104834Sobrien adapter->stats.dc += E1000_READ_REG(&adapter->hw, DC); 3023130561Sobrien adapter->stats.rlec += E1000_READ_REG(&adapter->hw, RLEC); 3024104834Sobrien adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, XONRXC); 3025104834Sobrien adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, XONTXC); 3026104834Sobrien adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, XOFFRXC); 3027104834Sobrien adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, XOFFTXC); 3028104834Sobrien adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, FCRUC); 3029104834Sobrien adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, PRC64); 3030104834Sobrien adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, PRC127); 3031104834Sobrien adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, PRC255); 3032104834Sobrien adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, PRC511); 3033130561Sobrien adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, PRC1023); 3034104834Sobrien adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, PRC1522); 3035104834Sobrien adapter->stats.gprc += E1000_READ_REG(&adapter->hw, GPRC); 3036130561Sobrien adapter->stats.bprc += E1000_READ_REG(&adapter->hw, BPRC); 3037130561Sobrien adapter->stats.mprc += E1000_READ_REG(&adapter->hw, MPRC); 3038104834Sobrien adapter->stats.gptc += E1000_READ_REG(&adapter->hw, GPTC); 3039104834Sobrien 3040104834Sobrien /* For the 64-bit byte counters the low dword must be read first. */ 3041104834Sobrien /* Both registers clear on the read of the high dword */ 3042104834Sobrien 3043130561Sobrien adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL); 3044104834Sobrien adapter->stats.gorch += E1000_READ_REG(&adapter->hw, GORCH); 3045104834Sobrien adapter->stats.gotcl += E1000_READ_REG(&adapter->hw, GOTCL); 3046130561Sobrien adapter->stats.gotch += E1000_READ_REG(&adapter->hw, GOTCH); 3047130561Sobrien 3048104834Sobrien adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, RNBC); 3049104834Sobrien adapter->stats.ruc += E1000_READ_REG(&adapter->hw, RUC); 3050104834Sobrien adapter->stats.rfc += E1000_READ_REG(&adapter->hw, RFC); 3051130561Sobrien adapter->stats.roc += E1000_READ_REG(&adapter->hw, ROC); 3052104834Sobrien adapter->stats.rjc += E1000_READ_REG(&adapter->hw, RJC); 3053104834Sobrien 3054104834Sobrien adapter->stats.torl += E1000_READ_REG(&adapter->hw, TORL); 3055130561Sobrien adapter->stats.torh += E1000_READ_REG(&adapter->hw, TORH); 3056104834Sobrien adapter->stats.totl += E1000_READ_REG(&adapter->hw, TOTL); 3057104834Sobrien adapter->stats.toth += E1000_READ_REG(&adapter->hw, TOTH); 3058104834Sobrien 3059104834Sobrien adapter->stats.tpr += E1000_READ_REG(&adapter->hw, TPR); 3060104834Sobrien adapter->stats.tpt += E1000_READ_REG(&adapter->hw, TPT); 3061104834Sobrien adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, PTC64); 3062104834Sobrien adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, PTC127); 3063104834Sobrien adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, PTC255); 3064104834Sobrien adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, PTC511); 3065104834Sobrien adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, PTC1023); 3066104834Sobrien adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, PTC1522); 3067104834Sobrien adapter->stats.mptc += E1000_READ_REG(&adapter->hw, MPTC); 3068104834Sobrien adapter->stats.bptc += E1000_READ_REG(&adapter->hw, BPTC); 3069104834Sobrien 3070104834Sobrien if (adapter->hw.mac_type >= em_82543) { 3071130561Sobrien adapter->stats.algnerrc += 3072104834Sobrien E1000_READ_REG(&adapter->hw, ALGNERRC); 3073104834Sobrien adapter->stats.rxerrc += 3074104834Sobrien E1000_READ_REG(&adapter->hw, RXERRC); 3075104834Sobrien adapter->stats.tncrs += 3076104834Sobrien E1000_READ_REG(&adapter->hw, TNCRS); 3077104834Sobrien adapter->stats.cexterr += 3078104834Sobrien E1000_READ_REG(&adapter->hw, CEXTERR); 3079104834Sobrien adapter->stats.tsctc += 3080104834Sobrien E1000_READ_REG(&adapter->hw, TSCTC); 3081104834Sobrien adapter->stats.tsctfc += 3082104834Sobrien E1000_READ_REG(&adapter->hw, TSCTFC); 3083130561Sobrien } 3084104834Sobrien ifp = &adapter->interface_data.ac_if; 3085104834Sobrien 3086104834Sobrien /* Fill out the OS statistics structure */ 3087104834Sobrien ifp->if_ibytes = adapter->stats.gorcl; 3088104834Sobrien ifp->if_obytes = adapter->stats.gotcl; 3089104834Sobrien ifp->if_imcasts = adapter->stats.mprc; 3090104834Sobrien ifp->if_collisions = adapter->stats.colc; 3091104834Sobrien 3092104834Sobrien /* Rx Errors */ 3093104834Sobrien ifp->if_ierrors = 3094130561Sobrien adapter->dropped_pkts + 3095104834Sobrien adapter->stats.rxerrc + 3096104834Sobrien adapter->stats.crcerrs + 3097130561Sobrien adapter->stats.algnerrc + 3098104834Sobrien adapter->stats.rlec + adapter->stats.rnbc + 3099130561Sobrien adapter->stats.mpc + adapter->stats.cexterr; 3100104834Sobrien 3101104834Sobrien /* Tx Errors */ 3102104834Sobrien ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol; 3103104834Sobrien 3104104834Sobrien} 3105104834Sobrien 3106104834Sobrien 3107130561Sobrien/********************************************************************** 3108130561Sobrien * 3109104834Sobrien * This routine is called only when em_display_debug_stats is enabled. 3110104834Sobrien * This routine provides a way to take a look at important statistics 3111104834Sobrien * maintained by the driver and hardware. 3112104834Sobrien * 3113104834Sobrien **********************************************************************/ 3114104834Sobrienstatic void 3115104834Sobrienem_print_debug_info(struct adapter *adapter) 3116130561Sobrien{ 3117104834Sobrien int unit = adapter->unit; 3118130561Sobrien 3119130561Sobrien#ifdef DBG_STATS 3120104834Sobrien printf("em%d: Packets not Avail = %ld\n", unit, 3121104834Sobrien adapter->no_pkts_avail); 3122130561Sobrien printf("em%d: CleanTxInterrupts = %ld\n", unit, 3123130561Sobrien adapter->clean_tx_interrupts); 3124104834Sobrien#endif 3125104834Sobrien printf("em%d: fifo workaround = %lld, fifo_reset = %lld\n", unit, 3126104834Sobrien (long long)adapter->tx_fifo_wrk, 3127104834Sobrien (long long)adapter->tx_fifo_reset); 3128104834Sobrien printf("em%d: hw tdh = %d, hw tdt = %d\n", unit, 3129104834Sobrien E1000_READ_REG(&adapter->hw, TDH), 3130104834Sobrien E1000_READ_REG(&adapter->hw, TDT)); 3131130561Sobrien printf("em%d: Num Tx descriptors avail = %d\n", unit, 3132104834Sobrien adapter->num_tx_desc_avail); 3133104834Sobrien printf("em%d: Tx Descriptors not avail1 = %ld\n", unit, 3134104834Sobrien adapter->no_tx_desc_avail1); 3135104834Sobrien printf("em%d: Tx Descriptors not avail2 = %ld\n", unit, 3136104834Sobrien adapter->no_tx_desc_avail2); 3137104834Sobrien printf("em%d: Std mbuf failed = %ld\n", unit, 3138104834Sobrien adapter->mbuf_alloc_failed); 3139104834Sobrien printf("em%d: Std mbuf cluster failed = %ld\n", unit, 3140104834Sobrien adapter->mbuf_cluster_failed); 3141104834Sobrien printf("em%d: Driver dropped packets = %ld\n", unit, 3142130561Sobrien adapter->dropped_pkts); 3143104834Sobrien 3144104834Sobrien return; 3145104834Sobrien} 3146104834Sobrien 3147104834Sobrienstatic void 3148104834Sobrienem_print_hw_stats(struct adapter *adapter) 3149130561Sobrien{ 3150130561Sobrien int unit = adapter->unit; 3151104834Sobrien 3152104834Sobrien printf("em%d: Excessive collisions = %lld\n", unit, 3153104834Sobrien (long long)adapter->stats.ecol); 3154104834Sobrien printf("em%d: Symbol errors = %lld\n", unit, 3155104834Sobrien (long long)adapter->stats.symerrs); 3156104834Sobrien printf("em%d: Sequence errors = %lld\n", unit, 3157104834Sobrien (long long)adapter->stats.sec); 3158104834Sobrien printf("em%d: Defer count = %lld\n", unit, 3159104834Sobrien (long long)adapter->stats.dc); 3160104834Sobrien 3161104834Sobrien printf("em%d: Missed Packets = %lld\n", unit, 3162104834Sobrien (long long)adapter->stats.mpc); 3163130561Sobrien printf("em%d: Receive No Buffers = %lld\n", unit, 3164104834Sobrien (long long)adapter->stats.rnbc); 3165130561Sobrien printf("em%d: Receive length errors = %lld\n", unit, 3166104834Sobrien (long long)adapter->stats.rlec); 3167104834Sobrien printf("em%d: Receive errors = %lld\n", unit, 3168130561Sobrien (long long)adapter->stats.rxerrc); 3169104834Sobrien printf("em%d: Crc errors = %lld\n", unit, 3170104834Sobrien (long long)adapter->stats.crcerrs); 3171104834Sobrien printf("em%d: Alignment errors = %lld\n", unit, 3172104834Sobrien (long long)adapter->stats.algnerrc); 3173104834Sobrien printf("em%d: Carrier extension errors = %lld\n", unit, 3174104834Sobrien (long long)adapter->stats.cexterr); 3175104834Sobrien 3176104834Sobrien printf("em%d: XON Rcvd = %lld\n", unit, 3177104834Sobrien (long long)adapter->stats.xonrxc); 3178104834Sobrien printf("em%d: XON Xmtd = %lld\n", unit, 3179130561Sobrien (long long)adapter->stats.xontxc); 3180130561Sobrien printf("em%d: XOFF Rcvd = %lld\n", unit, 3181130561Sobrien (long long)adapter->stats.xoffrxc); 3182104834Sobrien printf("em%d: XOFF Xmtd = %lld\n", unit, 3183104834Sobrien (long long)adapter->stats.xofftxc); 3184130561Sobrien 3185130561Sobrien printf("em%d: Good Packets Rcvd = %lld\n", unit, 3186104834Sobrien (long long)adapter->stats.gprc); 3187104834Sobrien printf("em%d: Good Packets Xmtd = %lld\n", unit, 3188104834Sobrien (long long)adapter->stats.gptc); 3189130561Sobrien 3190104834Sobrien return; 3191104834Sobrien} 3192104834Sobrien 3193130561Sobrienstatic int 3194104834Sobrienem_sysctl_debug_info(SYSCTL_HANDLER_ARGS) 3195104834Sobrien{ 3196104834Sobrien int error; 3197104834Sobrien int result; 3198104834Sobrien struct adapter *adapter; 3199104834Sobrien 3200104834Sobrien result = -1; 3201104834Sobrien error = sysctl_handle_int(oidp, &result, 0, req); 3202104834Sobrien 3203104834Sobrien if (error || !req->newptr) 3204104834Sobrien return (error); 3205104834Sobrien 3206104834Sobrien if (result == 1) { 3207104834Sobrien adapter = (struct adapter *)arg1; 3208104834Sobrien em_print_debug_info(adapter); 3209104834Sobrien } 3210104834Sobrien 3211104834Sobrien return error; 3212104834Sobrien} 3213104834Sobrien 3214104834Sobrien 3215104834Sobrienstatic int 3216104834Sobrienem_sysctl_stats(SYSCTL_HANDLER_ARGS) 3217104834Sobrien{ 3218130561Sobrien int error; 3219130561Sobrien int result; 3220130561Sobrien struct adapter *adapter; 3221104834Sobrien 3222104834Sobrien result = -1; 322389857Sobrien error = sysctl_handle_int(oidp, &result, 0, req); 322489857Sobrien 3225130561Sobrien if (error || !req->newptr) 322689857Sobrien return (error); 3227104834Sobrien 3228104834Sobrien if (result == 1) { 3229104834Sobrien adapter = (struct adapter *)arg1; 3230104834Sobrien em_print_hw_stats(adapter); 3231130561Sobrien } 3232104834Sobrien 3233130561Sobrien return error; 3234104834Sobrien} 3235104834Sobrien 3236104834Sobrienstatic int 3237104834Sobrienem_sysctl_int_delay(SYSCTL_HANDLER_ARGS) 3238130561Sobrien{ 3239104834Sobrien struct em_int_delay_info *info; 3240104834Sobrien struct adapter *adapter; 3241104834Sobrien u_int32_t regval; 3242104834Sobrien int error; 3243130561Sobrien int usecs; 3244104834Sobrien int ticks; 3245104834Sobrien int s; 3246104834Sobrien 3247104834Sobrien info = (struct em_int_delay_info *)arg1; 3248104834Sobrien adapter = info->adapter; 3249104834Sobrien usecs = info->value; 3250104834Sobrien error = sysctl_handle_int(oidp, &usecs, 0, req); 3251130561Sobrien if (error != 0 || req->newptr == NULL) 3252104834Sobrien return error; 3253104834Sobrien if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535)) 3254104834Sobrien return EINVAL; 3255104834Sobrien info->value = usecs; 3256104834Sobrien ticks = E1000_USECS_TO_TICKS(usecs); 3257104834Sobrien 3258104834Sobrien s = splimp(); 3259104834Sobrien regval = E1000_READ_OFFSET(&adapter->hw, info->offset); 3260104834Sobrien regval = (regval & ~0xffff) | (ticks & 0xffff); 3261104834Sobrien /* Handle a few special cases. */ 3262104834Sobrien switch (info->offset) { 3263104834Sobrien case E1000_RDTR: 3264104834Sobrien case E1000_82542_RDTR: 3265104834Sobrien regval |= E1000_RDT_FPDB; 3266104834Sobrien break; 3267104834Sobrien case E1000_TIDV: 3268104834Sobrien case E1000_82542_TIDV: 3269130561Sobrien if (ticks == 0) { 3270104834Sobrien adapter->txd_cmd &= ~E1000_TXD_CMD_IDE; 3271104834Sobrien /* Don't write 0 into the TIDV register. */ 3272104834Sobrien regval++; 3273130561Sobrien } else 3274104834Sobrien adapter->txd_cmd |= E1000_TXD_CMD_IDE; 3275104834Sobrien break; 3276104834Sobrien } 3277104834Sobrien E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval); 3278130561Sobrien splx(s); 3279104834Sobrien return 0; 3280104834Sobrien} 3281104834Sobrien 3282104834Sobrienstatic void 3283104834Sobrienem_add_int_delay_sysctl(struct adapter *adapter, const char *name, 3284104834Sobrien const char *description, struct em_int_delay_info *info, 3285104834Sobrien int offset, int value) 3286104834Sobrien{ 3287104834Sobrien info->adapter = adapter; 3288130561Sobrien info->offset = offset; 3289104834Sobrien info->value = value; 3290104834Sobrien SYSCTL_ADD_PROC(&adapter->sysctl_ctx, 3291104834Sobrien SYSCTL_CHILDREN(adapter->sysctl_tree), 3292104834Sobrien OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, 3293130561Sobrien info, 0, em_sysctl_int_delay, "I", description); 3294130561Sobrien} 3295104834Sobrien