1*4cceae0fSdlg /* $OpenBSD: if_igc.c,v 1.27 2024/08/11 01:02:10 dlg Exp $ */ 283306792Spatrick /*- 383306792Spatrick * SPDX-License-Identifier: BSD-2-Clause 483306792Spatrick * 583306792Spatrick * Copyright (c) 2016 Nicole Graziano <nicole@nextbsd.org> 683306792Spatrick * All rights reserved. 783306792Spatrick * Copyright (c) 2021 Rubicon Communications, LLC (Netgate) 883306792Spatrick * 983306792Spatrick * Redistribution and use in source and binary forms, with or without 1083306792Spatrick * modification, are permitted provided that the following conditions 1183306792Spatrick * are met: 1283306792Spatrick * 1. Redistributions of source code must retain the above copyright 1383306792Spatrick * notice, this list of conditions and the following disclaimer. 1483306792Spatrick * 2. Redistributions in binary form must reproduce the above copyright 1583306792Spatrick * notice, this list of conditions and the following disclaimer in the 1683306792Spatrick * documentation and/or other materials provided with the distribution. 1783306792Spatrick * 1883306792Spatrick * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1983306792Spatrick * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2083306792Spatrick * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2183306792Spatrick * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2283306792Spatrick * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2383306792Spatrick * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2483306792Spatrick * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2583306792Spatrick * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2683306792Spatrick * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2783306792Spatrick * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2883306792Spatrick * SUCH DAMAGE. 2983306792Spatrick */ 3083306792Spatrick 3183306792Spatrick #include "bpfilter.h" 3283306792Spatrick #include "vlan.h" 33bf6ccf13Sdlg #include "kstat.h" 3483306792Spatrick 3583306792Spatrick #include <sys/param.h> 3683306792Spatrick #include <sys/systm.h> 3783306792Spatrick #include <sys/sockio.h> 3883306792Spatrick #include <sys/mbuf.h> 3983306792Spatrick #include <sys/malloc.h> 4083306792Spatrick #include <sys/socket.h> 4183306792Spatrick #include <sys/device.h> 4283306792Spatrick #include <sys/endian.h> 4383306792Spatrick #include <sys/intrmap.h> 44bf6ccf13Sdlg #include <sys/kstat.h> 4583306792Spatrick 4683306792Spatrick #include <net/if.h> 4783306792Spatrick #include <net/if_media.h> 482011187aSmbuhl #include <net/route.h> 4983306792Spatrick #include <net/toeplitz.h> 5083306792Spatrick 5183306792Spatrick #include <netinet/in.h> 5283306792Spatrick #include <netinet/if_ether.h> 532011187aSmbuhl #include <netinet/tcp.h> 542011187aSmbuhl #include <netinet/tcp_timer.h> 552011187aSmbuhl #include <netinet/tcp_var.h> 5683306792Spatrick 5783306792Spatrick #if NBPFILTER > 0 5883306792Spatrick #include <net/bpf.h> 5983306792Spatrick #endif 6083306792Spatrick 6183306792Spatrick #include <machine/bus.h> 6283306792Spatrick #include <machine/intr.h> 6383306792Spatrick 6483306792Spatrick #include <dev/pci/pcivar.h> 6583306792Spatrick #include <dev/pci/pcireg.h> 6683306792Spatrick #include <dev/pci/pcidevs.h> 6783306792Spatrick #include <dev/pci/if_igc.h> 6883306792Spatrick #include <dev/pci/igc_hw.h> 6983306792Spatrick 7083306792Spatrick const struct pci_matchid igc_devices[] = { 7183306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I220_V }, 7283306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I221_V }, 7383306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_BLANK_NVM }, 7483306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_I }, 7583306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_IT }, 7683306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_K }, 7783306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_K2 }, 7883306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_LM }, 7983306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_LMVP }, 8083306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I225_V }, 8183306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I226_BLANK_NVM }, 8283306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I226_IT }, 8383306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I226_LM }, 8483306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I226_K }, 8583306792Spatrick { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I226_V } 8683306792Spatrick }; 8783306792Spatrick 8883306792Spatrick /********************************************************************* 8983306792Spatrick * Function Prototypes 9083306792Spatrick *********************************************************************/ 9183306792Spatrick int igc_match(struct device *, void *, void *); 9283306792Spatrick void igc_attach(struct device *, struct device *, void *); 9383306792Spatrick int igc_detach(struct device *, int); 9483306792Spatrick 9583306792Spatrick void igc_identify_hardware(struct igc_softc *); 9683306792Spatrick int igc_allocate_pci_resources(struct igc_softc *); 9783306792Spatrick int igc_allocate_queues(struct igc_softc *); 9883306792Spatrick void igc_free_pci_resources(struct igc_softc *); 9983306792Spatrick void igc_reset(struct igc_softc *); 10083306792Spatrick void igc_init_dmac(struct igc_softc *, uint32_t); 10183306792Spatrick int igc_allocate_msix(struct igc_softc *); 10283306792Spatrick void igc_setup_msix(struct igc_softc *); 10383306792Spatrick int igc_dma_malloc(struct igc_softc *, bus_size_t, struct igc_dma_alloc *); 10483306792Spatrick void igc_dma_free(struct igc_softc *, struct igc_dma_alloc *); 10583306792Spatrick void igc_setup_interface(struct igc_softc *); 10683306792Spatrick 10783306792Spatrick void igc_init(void *); 10883306792Spatrick void igc_start(struct ifqueue *); 109fb54a5a4Sbluhm int igc_txeof(struct igc_txring *); 11083306792Spatrick void igc_stop(struct igc_softc *); 11183306792Spatrick int igc_ioctl(struct ifnet *, u_long, caddr_t); 11283306792Spatrick int igc_rxrinfo(struct igc_softc *, struct if_rxrinfo *); 113fb54a5a4Sbluhm int igc_rxfill(struct igc_rxring *); 11483306792Spatrick void igc_rxrefill(void *); 115fb54a5a4Sbluhm int igc_rxeof(struct igc_rxring *); 11683306792Spatrick void igc_rx_checksum(uint32_t, struct mbuf *, uint32_t); 11783306792Spatrick void igc_watchdog(struct ifnet *); 11883306792Spatrick void igc_media_status(struct ifnet *, struct ifmediareq *); 11983306792Spatrick int igc_media_change(struct ifnet *); 12083306792Spatrick void igc_iff(struct igc_softc *); 12183306792Spatrick void igc_update_link_status(struct igc_softc *); 122fb54a5a4Sbluhm int igc_get_buf(struct igc_rxring *, int); 123fb54a5a4Sbluhm int igc_tx_ctx_setup(struct igc_txring *, struct mbuf *, int, uint32_t *, 1242dad3cbaSmbuhl uint32_t *); 12583306792Spatrick 12683306792Spatrick void igc_configure_queues(struct igc_softc *); 12783306792Spatrick void igc_set_queues(struct igc_softc *, uint32_t, uint32_t, int); 12883306792Spatrick void igc_enable_queue(struct igc_softc *, uint32_t); 12983306792Spatrick void igc_enable_intr(struct igc_softc *); 13083306792Spatrick void igc_disable_intr(struct igc_softc *); 13183306792Spatrick int igc_intr_link(void *); 13283306792Spatrick int igc_intr_queue(void *); 13383306792Spatrick 134fb54a5a4Sbluhm int igc_allocate_transmit_buffers(struct igc_txring *); 13583306792Spatrick int igc_setup_transmit_structures(struct igc_softc *); 136fb54a5a4Sbluhm int igc_setup_transmit_ring(struct igc_txring *); 13783306792Spatrick void igc_initialize_transmit_unit(struct igc_softc *); 13883306792Spatrick void igc_free_transmit_structures(struct igc_softc *); 139fb54a5a4Sbluhm void igc_free_transmit_buffers(struct igc_txring *); 140fb54a5a4Sbluhm int igc_allocate_receive_buffers(struct igc_rxring *); 14183306792Spatrick int igc_setup_receive_structures(struct igc_softc *); 142fb54a5a4Sbluhm int igc_setup_receive_ring(struct igc_rxring *); 14383306792Spatrick void igc_initialize_receive_unit(struct igc_softc *); 14483306792Spatrick void igc_free_receive_structures(struct igc_softc *); 145fb54a5a4Sbluhm void igc_free_receive_buffers(struct igc_rxring *); 14683306792Spatrick void igc_initialize_rss_mapping(struct igc_softc *); 14783306792Spatrick 14883306792Spatrick void igc_get_hw_control(struct igc_softc *); 14983306792Spatrick void igc_release_hw_control(struct igc_softc *); 15083306792Spatrick int igc_is_valid_ether_addr(uint8_t *); 15183306792Spatrick 152bf6ccf13Sdlg #if NKSTAT > 0 153bf6ccf13Sdlg void igc_kstat_attach(struct igc_softc *); 154bf6ccf13Sdlg #endif 155bf6ccf13Sdlg 15683306792Spatrick /********************************************************************* 15783306792Spatrick * OpenBSD Device Interface Entry Points 15883306792Spatrick *********************************************************************/ 15983306792Spatrick 16083306792Spatrick struct cfdriver igc_cd = { 16183306792Spatrick NULL, "igc", DV_IFNET 16283306792Spatrick }; 16383306792Spatrick 164471aeecfSnaddy const struct cfattach igc_ca = { 16583306792Spatrick sizeof(struct igc_softc), igc_match, igc_attach, igc_detach 16683306792Spatrick }; 16783306792Spatrick 16883306792Spatrick /********************************************************************* 16983306792Spatrick * Device identification routine 17083306792Spatrick * 17183306792Spatrick * igc_match determines if the driver should be loaded on 17283306792Spatrick * adapter based on PCI vendor/device id of the adapter. 17383306792Spatrick * 17483306792Spatrick * return 0 on success, positive on failure 17583306792Spatrick *********************************************************************/ 17683306792Spatrick int 17783306792Spatrick igc_match(struct device *parent, void *match, void *aux) 17883306792Spatrick { 17983306792Spatrick return pci_matchbyid((struct pci_attach_args *)aux, igc_devices, 18083306792Spatrick nitems(igc_devices)); 18183306792Spatrick } 18283306792Spatrick 18383306792Spatrick /********************************************************************* 18483306792Spatrick * Device initialization routine 18583306792Spatrick * 18683306792Spatrick * The attach entry point is called when the driver is being loaded. 18783306792Spatrick * This routine identifies the type of hardware, allocates all resources 18883306792Spatrick * and initializes the hardware. 18983306792Spatrick * 19083306792Spatrick * return 0 on success, positive on failure 19183306792Spatrick *********************************************************************/ 19283306792Spatrick void 19383306792Spatrick igc_attach(struct device *parent, struct device *self, void *aux) 19483306792Spatrick { 19583306792Spatrick struct pci_attach_args *pa = (struct pci_attach_args *)aux; 19683306792Spatrick struct igc_softc *sc = (struct igc_softc *)self; 19783306792Spatrick struct igc_hw *hw = &sc->hw; 19883306792Spatrick 19983306792Spatrick sc->osdep.os_sc = sc; 20083306792Spatrick sc->osdep.os_pa = *pa; 20183306792Spatrick 20283306792Spatrick /* Determine hardware and mac info */ 20383306792Spatrick igc_identify_hardware(sc); 20483306792Spatrick 205*4cceae0fSdlg sc->rx_mbuf_sz = MCLBYTES; 20683306792Spatrick sc->num_tx_desc = IGC_DEFAULT_TXD; 20783306792Spatrick sc->num_rx_desc = IGC_DEFAULT_RXD; 20883306792Spatrick 20983306792Spatrick /* Setup PCI resources */ 21083306792Spatrick if (igc_allocate_pci_resources(sc)) 21183306792Spatrick goto err_pci; 21283306792Spatrick 21383306792Spatrick /* Allocate TX/RX queues */ 21483306792Spatrick if (igc_allocate_queues(sc)) 21583306792Spatrick goto err_pci; 21683306792Spatrick 21783306792Spatrick /* Do shared code initialization */ 21883306792Spatrick if (igc_setup_init_funcs(hw, true)) { 21983306792Spatrick printf(": Setup of shared code failed\n"); 22083306792Spatrick goto err_pci; 22183306792Spatrick } 22283306792Spatrick 22383306792Spatrick hw->mac.autoneg = DO_AUTO_NEG; 22483306792Spatrick hw->phy.autoneg_wait_to_complete = false; 22583306792Spatrick hw->phy.autoneg_advertised = AUTONEG_ADV_DEFAULT; 22683306792Spatrick 22783306792Spatrick /* Copper options. */ 22883306792Spatrick if (hw->phy.media_type == igc_media_type_copper) 22983306792Spatrick hw->phy.mdix = AUTO_ALL_MODES; 23083306792Spatrick 23183306792Spatrick /* Set the max frame size. */ 23283306792Spatrick sc->hw.mac.max_frame_size = 9234; 23383306792Spatrick 23483306792Spatrick /* Allocate multicast array memory. */ 23583306792Spatrick sc->mta = mallocarray(ETHER_ADDR_LEN, MAX_NUM_MULTICAST_ADDRESSES, 23683306792Spatrick M_DEVBUF, M_NOWAIT); 23783306792Spatrick if (sc->mta == NULL) { 23883306792Spatrick printf(": Can not allocate multicast setup array\n"); 23983306792Spatrick goto err_late; 24083306792Spatrick } 24183306792Spatrick 24283306792Spatrick /* Check SOL/IDER usage. */ 24383306792Spatrick if (igc_check_reset_block(hw)) 24483306792Spatrick printf(": PHY reset is blocked due to SOL/IDER session\n"); 24583306792Spatrick 246eb7cd003Schris /* Disable Energy Efficient Ethernet. */ 24783306792Spatrick sc->hw.dev_spec._i225.eee_disable = true; 24883306792Spatrick 24983306792Spatrick igc_reset_hw(hw); 25083306792Spatrick 25183306792Spatrick /* Make sure we have a good EEPROM before we read from it. */ 25283306792Spatrick if (igc_validate_nvm_checksum(hw) < 0) { 25383306792Spatrick /* 25483306792Spatrick * Some PCI-E parts fail the first check due to 25583306792Spatrick * the link being in sleep state, call it again, 25683306792Spatrick * if it fails a second time its a real issue. 25783306792Spatrick */ 25883306792Spatrick if (igc_validate_nvm_checksum(hw) < 0) { 25983306792Spatrick printf(": The EEPROM checksum is not valid\n"); 26083306792Spatrick goto err_late; 26183306792Spatrick } 26283306792Spatrick } 26383306792Spatrick 26483306792Spatrick /* Copy the permanent MAC address out of the EEPROM. */ 26583306792Spatrick if (igc_read_mac_addr(hw) < 0) { 26683306792Spatrick printf(": EEPROM read error while reading MAC address\n"); 26783306792Spatrick goto err_late; 26883306792Spatrick } 26983306792Spatrick 27083306792Spatrick if (!igc_is_valid_ether_addr(hw->mac.addr)) { 27183306792Spatrick printf(": Invalid MAC address\n"); 27283306792Spatrick goto err_late; 27383306792Spatrick } 27483306792Spatrick 27583306792Spatrick memcpy(sc->sc_ac.ac_enaddr, sc->hw.mac.addr, ETHER_ADDR_LEN); 27683306792Spatrick 27783306792Spatrick if (igc_allocate_msix(sc)) 27883306792Spatrick goto err_late; 27983306792Spatrick 28083306792Spatrick /* Setup OS specific network interface. */ 28183306792Spatrick igc_setup_interface(sc); 28283306792Spatrick 28383306792Spatrick igc_reset(sc); 28483306792Spatrick hw->mac.get_link_status = true; 28583306792Spatrick igc_update_link_status(sc); 28683306792Spatrick 28783306792Spatrick /* The driver can now take control from firmware. */ 28883306792Spatrick igc_get_hw_control(sc); 28983306792Spatrick 29083306792Spatrick printf(", address %s\n", ether_sprintf(sc->hw.mac.addr)); 291bf6ccf13Sdlg 292bf6ccf13Sdlg #if NKSTAT > 0 293bf6ccf13Sdlg igc_kstat_attach(sc); 294bf6ccf13Sdlg #endif 29583306792Spatrick return; 29683306792Spatrick 29783306792Spatrick err_late: 29883306792Spatrick igc_release_hw_control(sc); 29983306792Spatrick err_pci: 30083306792Spatrick igc_free_pci_resources(sc); 30183306792Spatrick free(sc->mta, M_DEVBUF, ETHER_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES); 30283306792Spatrick } 30383306792Spatrick 30483306792Spatrick /********************************************************************* 30583306792Spatrick * Device removal routine 30683306792Spatrick * 30783306792Spatrick * The detach entry point is called when the driver is being removed. 30883306792Spatrick * This routine stops the adapter and deallocates all the resources 30983306792Spatrick * that were allocated for driver operation. 31083306792Spatrick * 31183306792Spatrick * return 0 on success, positive on failure 31283306792Spatrick *********************************************************************/ 31383306792Spatrick int 31483306792Spatrick igc_detach(struct device *self, int flags) 31583306792Spatrick { 31683306792Spatrick struct igc_softc *sc = (struct igc_softc *)self; 31783306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 31883306792Spatrick 31983306792Spatrick igc_stop(sc); 32083306792Spatrick 32183306792Spatrick igc_phy_hw_reset(&sc->hw); 32283306792Spatrick igc_release_hw_control(sc); 32383306792Spatrick 32483306792Spatrick ether_ifdetach(ifp); 32583306792Spatrick if_detach(ifp); 32683306792Spatrick 32783306792Spatrick igc_free_pci_resources(sc); 32883306792Spatrick 32983306792Spatrick igc_free_transmit_structures(sc); 33083306792Spatrick igc_free_receive_structures(sc); 33183306792Spatrick free(sc->mta, M_DEVBUF, ETHER_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES); 33283306792Spatrick 33383306792Spatrick return 0; 33483306792Spatrick } 33583306792Spatrick 33683306792Spatrick void 33783306792Spatrick igc_identify_hardware(struct igc_softc *sc) 33883306792Spatrick { 33983306792Spatrick struct igc_osdep *os = &sc->osdep; 34083306792Spatrick struct pci_attach_args *pa = &os->os_pa; 34183306792Spatrick 34283306792Spatrick /* Save off the information about this board. */ 34383306792Spatrick sc->hw.device_id = PCI_PRODUCT(pa->pa_id); 34483306792Spatrick 34583306792Spatrick /* Do shared code init and setup. */ 34683306792Spatrick if (igc_set_mac_type(&sc->hw)) { 34783306792Spatrick printf(": Setup init failure\n"); 34883306792Spatrick return; 34983306792Spatrick } 35083306792Spatrick } 35183306792Spatrick 35283306792Spatrick int 35383306792Spatrick igc_allocate_pci_resources(struct igc_softc *sc) 35483306792Spatrick { 35583306792Spatrick struct igc_osdep *os = &sc->osdep; 35683306792Spatrick struct pci_attach_args *pa = &os->os_pa; 35783306792Spatrick pcireg_t memtype; 35883306792Spatrick 35983306792Spatrick memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, IGC_PCIREG); 36083306792Spatrick if (pci_mapreg_map(pa, IGC_PCIREG, memtype, 0, &os->os_memt, 36183306792Spatrick &os->os_memh, &os->os_membase, &os->os_memsize, 0)) { 36283306792Spatrick printf(": unable to map registers\n"); 36383306792Spatrick return ENXIO; 36483306792Spatrick } 36583306792Spatrick sc->hw.hw_addr = (uint8_t *)os->os_membase; 36683306792Spatrick sc->hw.back = os; 36783306792Spatrick 36883306792Spatrick igc_setup_msix(sc); 36983306792Spatrick 37083306792Spatrick return 0; 37183306792Spatrick } 37283306792Spatrick 37383306792Spatrick int 37483306792Spatrick igc_allocate_queues(struct igc_softc *sc) 37583306792Spatrick { 37683306792Spatrick struct igc_queue *iq; 377fb54a5a4Sbluhm struct igc_txring *txr; 378fb54a5a4Sbluhm struct igc_rxring *rxr; 37983306792Spatrick int i, rsize, rxconf, tsize, txconf; 38083306792Spatrick 38183306792Spatrick /* Allocate the top level queue structs. */ 38283306792Spatrick sc->queues = mallocarray(sc->sc_nqueues, sizeof(struct igc_queue), 38383306792Spatrick M_DEVBUF, M_NOWAIT | M_ZERO); 38483306792Spatrick if (sc->queues == NULL) { 38583306792Spatrick printf("%s: unable to allocate queue\n", DEVNAME(sc)); 38683306792Spatrick goto fail; 38783306792Spatrick } 38883306792Spatrick 38983306792Spatrick /* Allocate the TX ring. */ 390fb54a5a4Sbluhm sc->tx_rings = mallocarray(sc->sc_nqueues, sizeof(struct igc_txring), 39183306792Spatrick M_DEVBUF, M_NOWAIT | M_ZERO); 39283306792Spatrick if (sc->tx_rings == NULL) { 39383306792Spatrick printf("%s: unable to allocate TX ring\n", DEVNAME(sc)); 39483306792Spatrick goto fail; 39583306792Spatrick } 39683306792Spatrick 39783306792Spatrick /* Allocate the RX ring. */ 398fb54a5a4Sbluhm sc->rx_rings = mallocarray(sc->sc_nqueues, sizeof(struct igc_rxring), 39983306792Spatrick M_DEVBUF, M_NOWAIT | M_ZERO); 40083306792Spatrick if (sc->rx_rings == NULL) { 40183306792Spatrick printf("%s: unable to allocate RX ring\n", DEVNAME(sc)); 40283306792Spatrick goto rx_fail; 40383306792Spatrick } 40483306792Spatrick 40583306792Spatrick txconf = rxconf = 0; 40683306792Spatrick 40783306792Spatrick /* Set up the TX queues. */ 40883306792Spatrick tsize = roundup2(sc->num_tx_desc * sizeof(union igc_adv_tx_desc), 40983306792Spatrick IGC_DBA_ALIGN); 41083306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, txconf++) { 41183306792Spatrick txr = &sc->tx_rings[i]; 41283306792Spatrick txr->sc = sc; 41383306792Spatrick txr->me = i; 41483306792Spatrick 41583306792Spatrick if (igc_dma_malloc(sc, tsize, &txr->txdma)) { 41683306792Spatrick printf("%s: unable to allocate TX descriptor\n", 41783306792Spatrick DEVNAME(sc)); 41883306792Spatrick goto err_tx_desc; 41983306792Spatrick } 42083306792Spatrick txr->tx_base = (union igc_adv_tx_desc *)txr->txdma.dma_vaddr; 42183306792Spatrick bzero((void *)txr->tx_base, tsize); 42283306792Spatrick } 42383306792Spatrick 42483306792Spatrick /* Set up the RX queues. */ 42583306792Spatrick rsize = roundup2(sc->num_rx_desc * sizeof(union igc_adv_rx_desc), 42683306792Spatrick IGC_DBA_ALIGN); 42783306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, rxconf++) { 42883306792Spatrick rxr = &sc->rx_rings[i]; 42983306792Spatrick rxr->sc = sc; 43083306792Spatrick rxr->me = i; 43183306792Spatrick timeout_set(&rxr->rx_refill, igc_rxrefill, rxr); 43283306792Spatrick 43383306792Spatrick if (igc_dma_malloc(sc, rsize, &rxr->rxdma)) { 43483306792Spatrick printf("%s: unable to allocate RX descriptor\n", 43583306792Spatrick DEVNAME(sc)); 43683306792Spatrick goto err_rx_desc; 43783306792Spatrick } 43883306792Spatrick rxr->rx_base = (union igc_adv_rx_desc *)rxr->rxdma.dma_vaddr; 43983306792Spatrick bzero((void *)rxr->rx_base, rsize); 44083306792Spatrick } 44183306792Spatrick 44283306792Spatrick /* Set up the queue holding structs. */ 44383306792Spatrick for (i = 0; i < sc->sc_nqueues; i++) { 44483306792Spatrick iq = &sc->queues[i]; 44583306792Spatrick iq->sc = sc; 44683306792Spatrick iq->txr = &sc->tx_rings[i]; 44783306792Spatrick iq->rxr = &sc->rx_rings[i]; 44883306792Spatrick snprintf(iq->name, sizeof(iq->name), "%s:%d", DEVNAME(sc), i); 44983306792Spatrick } 45083306792Spatrick 45183306792Spatrick return 0; 45283306792Spatrick 45383306792Spatrick err_rx_desc: 45483306792Spatrick for (rxr = sc->rx_rings; rxconf > 0; rxr++, rxconf--) 45583306792Spatrick igc_dma_free(sc, &rxr->rxdma); 45683306792Spatrick err_tx_desc: 45783306792Spatrick for (txr = sc->tx_rings; txconf > 0; txr++, txconf--) 45883306792Spatrick igc_dma_free(sc, &txr->txdma); 459fb54a5a4Sbluhm free(sc->rx_rings, M_DEVBUF, 460fb54a5a4Sbluhm sc->sc_nqueues * sizeof(struct igc_rxring)); 46183306792Spatrick sc->rx_rings = NULL; 46283306792Spatrick rx_fail: 463fb54a5a4Sbluhm free(sc->tx_rings, M_DEVBUF, 464fb54a5a4Sbluhm sc->sc_nqueues * sizeof(struct igc_txring)); 46583306792Spatrick sc->tx_rings = NULL; 46683306792Spatrick fail: 46783306792Spatrick return ENOMEM; 46883306792Spatrick } 46983306792Spatrick 47083306792Spatrick void 47183306792Spatrick igc_free_pci_resources(struct igc_softc *sc) 47283306792Spatrick { 47383306792Spatrick struct igc_osdep *os = &sc->osdep; 47483306792Spatrick struct pci_attach_args *pa = &os->os_pa; 47583306792Spatrick struct igc_queue *iq = sc->queues; 47683306792Spatrick int i; 47783306792Spatrick 47883306792Spatrick /* Release all msix queue resources. */ 47983306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, iq++) { 48083306792Spatrick if (iq->tag) 48183306792Spatrick pci_intr_disestablish(pa->pa_pc, iq->tag); 48283306792Spatrick iq->tag = NULL; 48383306792Spatrick } 48483306792Spatrick 48583306792Spatrick if (sc->tag) 48683306792Spatrick pci_intr_disestablish(pa->pa_pc, sc->tag); 48783306792Spatrick sc->tag = NULL; 48883306792Spatrick if (os->os_membase != 0) 48983306792Spatrick bus_space_unmap(os->os_memt, os->os_memh, os->os_memsize); 49083306792Spatrick os->os_membase = 0; 49183306792Spatrick } 49283306792Spatrick 49383306792Spatrick /********************************************************************* 49483306792Spatrick * 49583306792Spatrick * Initialize the hardware to a configuration as specified by the 49683306792Spatrick * adapter structure. 49783306792Spatrick * 49883306792Spatrick **********************************************************************/ 49983306792Spatrick void 50083306792Spatrick igc_reset(struct igc_softc *sc) 50183306792Spatrick { 50283306792Spatrick struct igc_hw *hw = &sc->hw; 50383306792Spatrick uint32_t pba; 50483306792Spatrick uint16_t rx_buffer_size; 50583306792Spatrick 50683306792Spatrick /* Let the firmware know the OS is in control */ 50783306792Spatrick igc_get_hw_control(sc); 50883306792Spatrick 50983306792Spatrick /* 51083306792Spatrick * Packet Buffer Allocation (PBA) 51183306792Spatrick * Writing PBA sets the receive portion of the buffer 51283306792Spatrick * the remainder is used for the transmit buffer. 51383306792Spatrick */ 51483306792Spatrick pba = IGC_PBA_34K; 51583306792Spatrick 51683306792Spatrick /* 51783306792Spatrick * These parameters control the automatic generation (Tx) and 51883306792Spatrick * response (Rx) to Ethernet PAUSE frames. 51983306792Spatrick * - High water mark should allow for at least two frames to be 52083306792Spatrick * received after sending an XOFF. 52183306792Spatrick * - Low water mark works best when it is very near the high water mark. 52283306792Spatrick * This allows the receiver to restart by sending XON when it has 52383306792Spatrick * drained a bit. Here we use an arbitrary value of 1500 which will 52483306792Spatrick * restart after one full frame is pulled from the buffer. There 52583306792Spatrick * could be several smaller frames in the buffer and if so they will 52683306792Spatrick * not trigger the XON until their total number reduces the buffer 52783306792Spatrick * by 1500. 52883306792Spatrick * - The pause time is fairly large at 1000 x 512ns = 512 usec. 52983306792Spatrick */ 53083306792Spatrick rx_buffer_size = (pba & 0xffff) << 10; 53183306792Spatrick hw->fc.high_water = rx_buffer_size - 53283306792Spatrick roundup2(sc->hw.mac.max_frame_size, 1024); 53383306792Spatrick /* 16-byte granularity */ 53483306792Spatrick hw->fc.low_water = hw->fc.high_water - 16; 53583306792Spatrick 53683306792Spatrick if (sc->fc) /* locally set flow control value? */ 53783306792Spatrick hw->fc.requested_mode = sc->fc; 53883306792Spatrick else 53983306792Spatrick hw->fc.requested_mode = igc_fc_full; 54083306792Spatrick 54183306792Spatrick hw->fc.pause_time = IGC_FC_PAUSE_TIME; 54283306792Spatrick 54383306792Spatrick hw->fc.send_xon = true; 54483306792Spatrick 54583306792Spatrick /* Issue a global reset */ 54683306792Spatrick igc_reset_hw(hw); 54783306792Spatrick IGC_WRITE_REG(hw, IGC_WUC, 0); 54883306792Spatrick 54983306792Spatrick /* and a re-init */ 55083306792Spatrick if (igc_init_hw(hw) < 0) { 55183306792Spatrick printf(": Hardware Initialization Failed\n"); 55283306792Spatrick return; 55383306792Spatrick } 55483306792Spatrick 55583306792Spatrick /* Setup DMA Coalescing */ 55683306792Spatrick igc_init_dmac(sc, pba); 55783306792Spatrick 55883306792Spatrick IGC_WRITE_REG(hw, IGC_VET, ETHERTYPE_VLAN); 55983306792Spatrick igc_get_phy_info(hw); 56083306792Spatrick igc_check_for_link(hw); 56183306792Spatrick } 56283306792Spatrick 56383306792Spatrick /********************************************************************* 56483306792Spatrick * 56583306792Spatrick * Initialize the DMA Coalescing feature 56683306792Spatrick * 56783306792Spatrick **********************************************************************/ 56883306792Spatrick void 56983306792Spatrick igc_init_dmac(struct igc_softc *sc, uint32_t pba) 57083306792Spatrick { 57183306792Spatrick struct igc_hw *hw = &sc->hw; 57283306792Spatrick uint32_t dmac, reg = ~IGC_DMACR_DMAC_EN; 57383306792Spatrick uint16_t hwm, max_frame_size; 57483306792Spatrick int status; 57583306792Spatrick 57683306792Spatrick max_frame_size = sc->hw.mac.max_frame_size; 57783306792Spatrick 57883306792Spatrick if (sc->dmac == 0) { /* Disabling it */ 57983306792Spatrick IGC_WRITE_REG(hw, IGC_DMACR, reg); 58083306792Spatrick return; 58183306792Spatrick } else 58283306792Spatrick printf(": DMA Coalescing enabled\n"); 58383306792Spatrick 58483306792Spatrick /* Set starting threshold */ 58583306792Spatrick IGC_WRITE_REG(hw, IGC_DMCTXTH, 0); 58683306792Spatrick 58783306792Spatrick hwm = 64 * pba - max_frame_size / 16; 58883306792Spatrick if (hwm < 64 * (pba - 6)) 58983306792Spatrick hwm = 64 * (pba - 6); 59083306792Spatrick reg = IGC_READ_REG(hw, IGC_FCRTC); 59183306792Spatrick reg &= ~IGC_FCRTC_RTH_COAL_MASK; 59283306792Spatrick reg |= ((hwm << IGC_FCRTC_RTH_COAL_SHIFT) 59383306792Spatrick & IGC_FCRTC_RTH_COAL_MASK); 59483306792Spatrick IGC_WRITE_REG(hw, IGC_FCRTC, reg); 59583306792Spatrick 59683306792Spatrick dmac = pba - max_frame_size / 512; 59783306792Spatrick if (dmac < pba - 10) 59883306792Spatrick dmac = pba - 10; 59983306792Spatrick reg = IGC_READ_REG(hw, IGC_DMACR); 60083306792Spatrick reg &= ~IGC_DMACR_DMACTHR_MASK; 60183306792Spatrick reg |= ((dmac << IGC_DMACR_DMACTHR_SHIFT) 60283306792Spatrick & IGC_DMACR_DMACTHR_MASK); 60383306792Spatrick 60483306792Spatrick /* transition to L0x or L1 if available..*/ 60583306792Spatrick reg |= (IGC_DMACR_DMAC_EN | IGC_DMACR_DMAC_LX_MASK); 60683306792Spatrick 60783306792Spatrick /* Check if status is 2.5Gb backplane connection 60883306792Spatrick * before configuration of watchdog timer, which is 60983306792Spatrick * in msec values in 12.8usec intervals 61083306792Spatrick * watchdog timer= msec values in 32usec intervals 61183306792Spatrick * for non 2.5Gb connection 61283306792Spatrick */ 61383306792Spatrick status = IGC_READ_REG(hw, IGC_STATUS); 61483306792Spatrick if ((status & IGC_STATUS_2P5_SKU) && 61583306792Spatrick (!(status & IGC_STATUS_2P5_SKU_OVER))) 61683306792Spatrick reg |= ((sc->dmac * 5) >> 6); 61783306792Spatrick else 61883306792Spatrick reg |= (sc->dmac >> 5); 61983306792Spatrick 62083306792Spatrick IGC_WRITE_REG(hw, IGC_DMACR, reg); 62183306792Spatrick 62283306792Spatrick IGC_WRITE_REG(hw, IGC_DMCRTRH, 0); 62383306792Spatrick 62483306792Spatrick /* Set the interval before transition */ 62583306792Spatrick reg = IGC_READ_REG(hw, IGC_DMCTLX); 62683306792Spatrick reg |= IGC_DMCTLX_DCFLUSH_DIS; 62783306792Spatrick 62883306792Spatrick /* 62983306792Spatrick ** in 2.5Gb connection, TTLX unit is 0.4 usec 63083306792Spatrick ** which is 0x4*2 = 0xA. But delay is still 4 usec 63183306792Spatrick */ 63283306792Spatrick status = IGC_READ_REG(hw, IGC_STATUS); 63383306792Spatrick if ((status & IGC_STATUS_2P5_SKU) && 63483306792Spatrick (!(status & IGC_STATUS_2P5_SKU_OVER))) 63583306792Spatrick reg |= 0xA; 63683306792Spatrick else 63783306792Spatrick reg |= 0x4; 63883306792Spatrick 63983306792Spatrick IGC_WRITE_REG(hw, IGC_DMCTLX, reg); 64083306792Spatrick 64183306792Spatrick /* free space in tx packet buffer to wake from DMA coal */ 64283306792Spatrick IGC_WRITE_REG(hw, IGC_DMCTXTH, (IGC_TXPBSIZE - 64383306792Spatrick (2 * max_frame_size)) >> 6); 64483306792Spatrick 64583306792Spatrick /* make low power state decision controlled by DMA coal */ 64683306792Spatrick reg = IGC_READ_REG(hw, IGC_PCIEMISC); 64783306792Spatrick reg &= ~IGC_PCIEMISC_LX_DECISION; 64883306792Spatrick IGC_WRITE_REG(hw, IGC_PCIEMISC, reg); 64983306792Spatrick } 65083306792Spatrick 65183306792Spatrick int 65283306792Spatrick igc_allocate_msix(struct igc_softc *sc) 65383306792Spatrick { 65483306792Spatrick struct igc_osdep *os = &sc->osdep; 65583306792Spatrick struct pci_attach_args *pa = &os->os_pa; 65683306792Spatrick struct igc_queue *iq; 65783306792Spatrick pci_intr_handle_t ih; 65883306792Spatrick int i, error = 0; 65983306792Spatrick 66083306792Spatrick for (i = 0, iq = sc->queues; i < sc->sc_nqueues; i++, iq++) { 66183306792Spatrick if (pci_intr_map_msix(pa, i, &ih)) { 66283306792Spatrick printf("%s: unable to map msi-x vector %d\n", 66383306792Spatrick DEVNAME(sc), i); 66483306792Spatrick error = ENOMEM; 66583306792Spatrick goto fail; 66683306792Spatrick } 66783306792Spatrick 66883306792Spatrick iq->tag = pci_intr_establish_cpu(pa->pa_pc, ih, 66983306792Spatrick IPL_NET | IPL_MPSAFE, intrmap_cpu(sc->sc_intrmap, i), 67083306792Spatrick igc_intr_queue, iq, iq->name); 67183306792Spatrick if (iq->tag == NULL) { 67283306792Spatrick printf("%s: unable to establish interrupt %d\n", 67383306792Spatrick DEVNAME(sc), i); 67483306792Spatrick error = ENOMEM; 67583306792Spatrick goto fail; 67683306792Spatrick } 67783306792Spatrick 67883306792Spatrick iq->msix = i; 67983306792Spatrick iq->eims = 1 << i; 68083306792Spatrick } 68183306792Spatrick 68283306792Spatrick /* Now the link status/control last MSI-X vector. */ 68383306792Spatrick if (pci_intr_map_msix(pa, i, &ih)) { 68483306792Spatrick printf("%s: unable to map link vector\n", DEVNAME(sc)); 68583306792Spatrick error = ENOMEM; 68683306792Spatrick goto fail; 68783306792Spatrick } 68883306792Spatrick 68983306792Spatrick sc->tag = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE, 69083306792Spatrick igc_intr_link, sc, sc->sc_dev.dv_xname); 69183306792Spatrick if (sc->tag == NULL) { 69283306792Spatrick printf("%s: unable to establish link interrupt\n", DEVNAME(sc)); 69383306792Spatrick error = ENOMEM; 69483306792Spatrick goto fail; 69583306792Spatrick } 69683306792Spatrick 69783306792Spatrick sc->linkvec = i; 69883306792Spatrick printf(", %s, %d queue%s", pci_intr_string(pa->pa_pc, ih), 69983306792Spatrick i, (i > 1) ? "s" : ""); 70083306792Spatrick 70183306792Spatrick return 0; 70283306792Spatrick fail: 70383306792Spatrick for (iq = sc->queues; i > 0; i--, iq++) { 70483306792Spatrick if (iq->tag == NULL) 70583306792Spatrick continue; 70683306792Spatrick pci_intr_disestablish(pa->pa_pc, iq->tag); 70783306792Spatrick iq->tag = NULL; 70883306792Spatrick } 70983306792Spatrick 71083306792Spatrick return error; 71183306792Spatrick } 71283306792Spatrick 71383306792Spatrick void 71483306792Spatrick igc_setup_msix(struct igc_softc *sc) 71583306792Spatrick { 71683306792Spatrick struct igc_osdep *os = &sc->osdep; 71783306792Spatrick struct pci_attach_args *pa = &os->os_pa; 71883306792Spatrick int nmsix; 71983306792Spatrick 72083306792Spatrick nmsix = pci_intr_msix_count(pa); 72183306792Spatrick if (nmsix <= 1) 72283306792Spatrick printf(": not enough msi-x vectors\n"); 72383306792Spatrick 72483306792Spatrick /* Give one vector to events. */ 72583306792Spatrick nmsix--; 72683306792Spatrick 72783306792Spatrick sc->sc_intrmap = intrmap_create(&sc->sc_dev, nmsix, IGC_MAX_VECTORS, 72883306792Spatrick INTRMAP_POWEROF2); 72983306792Spatrick sc->sc_nqueues = intrmap_count(sc->sc_intrmap); 73083306792Spatrick } 73183306792Spatrick 73283306792Spatrick int 73383306792Spatrick igc_dma_malloc(struct igc_softc *sc, bus_size_t size, struct igc_dma_alloc *dma) 73483306792Spatrick { 73583306792Spatrick struct igc_osdep *os = &sc->osdep; 73683306792Spatrick 73783306792Spatrick dma->dma_tag = os->os_pa.pa_dmat; 73883306792Spatrick 73983306792Spatrick if (bus_dmamap_create(dma->dma_tag, size, 1, size, 0, BUS_DMA_NOWAIT, 74083306792Spatrick &dma->dma_map)) 74183306792Spatrick return 1; 74283306792Spatrick if (bus_dmamem_alloc(dma->dma_tag, size, PAGE_SIZE, 0, &dma->dma_seg, 74383306792Spatrick 1, &dma->dma_nseg, BUS_DMA_NOWAIT)) 74483306792Spatrick goto destroy; 74583306792Spatrick if (bus_dmamem_map(dma->dma_tag, &dma->dma_seg, dma->dma_nseg, size, 746b7fccf02Skevlo &dma->dma_vaddr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) 74783306792Spatrick goto free; 74883306792Spatrick if (bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size, 74983306792Spatrick NULL, BUS_DMA_NOWAIT)) 75083306792Spatrick goto unmap; 75183306792Spatrick 75283306792Spatrick dma->dma_size = size; 75383306792Spatrick 75483306792Spatrick return 0; 75583306792Spatrick unmap: 75683306792Spatrick bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size); 75783306792Spatrick free: 75883306792Spatrick bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg); 75983306792Spatrick destroy: 76083306792Spatrick bus_dmamap_destroy(dma->dma_tag, dma->dma_map); 76183306792Spatrick dma->dma_map = NULL; 76283306792Spatrick dma->dma_tag = NULL; 76383306792Spatrick return 1; 76483306792Spatrick } 76583306792Spatrick 76683306792Spatrick void 76783306792Spatrick igc_dma_free(struct igc_softc *sc, struct igc_dma_alloc *dma) 76883306792Spatrick { 76983306792Spatrick if (dma->dma_tag == NULL) 77083306792Spatrick return; 77183306792Spatrick 77283306792Spatrick if (dma->dma_map != NULL) { 77383306792Spatrick bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, 77483306792Spatrick dma->dma_map->dm_mapsize, 77583306792Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 77683306792Spatrick bus_dmamap_unload(dma->dma_tag, dma->dma_map); 77783306792Spatrick bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, dma->dma_size); 77883306792Spatrick bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg); 77983306792Spatrick bus_dmamap_destroy(dma->dma_tag, dma->dma_map); 78083306792Spatrick dma->dma_map = NULL; 78183306792Spatrick } 78283306792Spatrick } 78383306792Spatrick 78483306792Spatrick /********************************************************************* 78583306792Spatrick * 78683306792Spatrick * Setup networking device structure and register an interface. 78783306792Spatrick * 78883306792Spatrick **********************************************************************/ 78983306792Spatrick void 79083306792Spatrick igc_setup_interface(struct igc_softc *sc) 79183306792Spatrick { 79283306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 79383306792Spatrick int i; 79483306792Spatrick 79583306792Spatrick ifp->if_softc = sc; 79683306792Spatrick strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 79783306792Spatrick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 79883306792Spatrick ifp->if_xflags = IFXF_MPSAFE; 79983306792Spatrick ifp->if_ioctl = igc_ioctl; 80083306792Spatrick ifp->if_qstart = igc_start; 80183306792Spatrick ifp->if_watchdog = igc_watchdog; 80283306792Spatrick ifp->if_hardmtu = sc->hw.mac.max_frame_size - ETHER_HDR_LEN - 80383306792Spatrick ETHER_CRC_LEN; 804cf96265bSbluhm ifq_init_maxlen(&ifp->if_snd, sc->num_tx_desc - 1); 80583306792Spatrick 80683306792Spatrick ifp->if_capabilities = IFCAP_VLAN_MTU; 80783306792Spatrick 80883306792Spatrick #if NVLAN > 0 80983306792Spatrick ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 81083306792Spatrick #endif 81183306792Spatrick 8125a60fbd4Smbuhl ifp->if_capabilities |= IFCAP_CSUM_IPv4; 8135a60fbd4Smbuhl ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; 8145a60fbd4Smbuhl ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6; 8152011187aSmbuhl ifp->if_capabilities |= IFCAP_TSOv4 | IFCAP_TSOv6; 8165a60fbd4Smbuhl 81783306792Spatrick /* Initialize ifmedia structures. */ 81883306792Spatrick ifmedia_init(&sc->media, IFM_IMASK, igc_media_change, igc_media_status); 81983306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_10_T, 0, NULL); 82083306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); 82183306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_100_TX, 0, NULL); 82283306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); 82383306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 82483306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_T, 0, NULL); 82583306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_2500_T, 0, NULL); 82683306792Spatrick 82783306792Spatrick ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 82883306792Spatrick ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 82983306792Spatrick 83083306792Spatrick if_attach(ifp); 83183306792Spatrick ether_ifattach(ifp); 83283306792Spatrick 83383306792Spatrick if_attach_queues(ifp, sc->sc_nqueues); 83483306792Spatrick if_attach_iqueues(ifp, sc->sc_nqueues); 83583306792Spatrick for (i = 0; i < sc->sc_nqueues; i++) { 83683306792Spatrick struct ifqueue *ifq = ifp->if_ifqs[i]; 83783306792Spatrick struct ifiqueue *ifiq = ifp->if_iqs[i]; 838fb54a5a4Sbluhm struct igc_txring *txr = &sc->tx_rings[i]; 839fb54a5a4Sbluhm struct igc_rxring *rxr = &sc->rx_rings[i]; 84083306792Spatrick 84183306792Spatrick ifq->ifq_softc = txr; 84283306792Spatrick txr->ifq = ifq; 84383306792Spatrick 84483306792Spatrick ifiq->ifiq_softc = rxr; 84583306792Spatrick rxr->ifiq = ifiq; 84683306792Spatrick } 84783306792Spatrick } 84883306792Spatrick 84983306792Spatrick void 85083306792Spatrick igc_init(void *arg) 85183306792Spatrick { 85283306792Spatrick struct igc_softc *sc = (struct igc_softc *)arg; 85383306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 854fb54a5a4Sbluhm struct igc_rxring *rxr; 85583306792Spatrick uint32_t ctrl = 0; 85683306792Spatrick int i, s; 85783306792Spatrick 85883306792Spatrick s = splnet(); 85983306792Spatrick 86083306792Spatrick igc_stop(sc); 86183306792Spatrick 86283306792Spatrick /* Get the latest mac address, user can use a LAA. */ 86383306792Spatrick bcopy(sc->sc_ac.ac_enaddr, sc->hw.mac.addr, ETHER_ADDR_LEN); 86483306792Spatrick 86583306792Spatrick /* Put the address into the receive address array. */ 86683306792Spatrick igc_rar_set(&sc->hw, sc->hw.mac.addr, 0); 86783306792Spatrick 86883306792Spatrick /* Initialize the hardware. */ 86983306792Spatrick igc_reset(sc); 87083306792Spatrick igc_update_link_status(sc); 87183306792Spatrick 87283306792Spatrick /* Setup VLAN support, basic and offload if available. */ 87383306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_VET, ETHERTYPE_VLAN); 87483306792Spatrick 87583306792Spatrick /* Prepare transmit descriptors and buffers. */ 87683306792Spatrick if (igc_setup_transmit_structures(sc)) { 87783306792Spatrick printf("%s: Could not setup transmit structures\n", 87883306792Spatrick DEVNAME(sc)); 87983306792Spatrick igc_stop(sc); 88083306792Spatrick splx(s); 88183306792Spatrick return; 88283306792Spatrick } 88383306792Spatrick igc_initialize_transmit_unit(sc); 88483306792Spatrick 88583306792Spatrick /* Prepare receive descriptors and buffers. */ 88683306792Spatrick if (igc_setup_receive_structures(sc)) { 88783306792Spatrick printf("%s: Could not setup receive structures\n", 88883306792Spatrick DEVNAME(sc)); 88983306792Spatrick igc_stop(sc); 89083306792Spatrick splx(s); 89183306792Spatrick return; 89283306792Spatrick } 89383306792Spatrick igc_initialize_receive_unit(sc); 89483306792Spatrick 89583306792Spatrick if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) { 89683306792Spatrick ctrl = IGC_READ_REG(&sc->hw, IGC_CTRL); 89783306792Spatrick ctrl |= IGC_CTRL_VME; 89883306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_CTRL, ctrl); 89983306792Spatrick } 90083306792Spatrick 90183306792Spatrick /* Setup multicast table. */ 90283306792Spatrick igc_iff(sc); 90383306792Spatrick 90483306792Spatrick igc_clear_hw_cntrs_base_generic(&sc->hw); 90583306792Spatrick 90683306792Spatrick igc_configure_queues(sc); 90783306792Spatrick 90883306792Spatrick /* This clears any pending interrupts */ 90983306792Spatrick IGC_READ_REG(&sc->hw, IGC_ICR); 91083306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_ICS, IGC_ICS_LSC); 91183306792Spatrick 91283306792Spatrick /* The driver can now take control from firmware. */ 91383306792Spatrick igc_get_hw_control(sc); 91483306792Spatrick 91583306792Spatrick /* Set Energy Efficient Ethernet. */ 91683306792Spatrick igc_set_eee_i225(&sc->hw, true, true, true); 91783306792Spatrick 918b88bced1Spatrick for (i = 0; i < sc->sc_nqueues; i++) { 919b88bced1Spatrick rxr = &sc->rx_rings[i]; 920b88bced1Spatrick igc_rxfill(rxr); 921b88bced1Spatrick if (if_rxr_inuse(&rxr->rx_ring) == 0) { 922b88bced1Spatrick printf("%s: Unable to fill any rx descriptors\n", 923b88bced1Spatrick DEVNAME(sc)); 924b88bced1Spatrick igc_stop(sc); 925b88bced1Spatrick splx(s); 926b88bced1Spatrick } 927b88bced1Spatrick IGC_WRITE_REG(&sc->hw, IGC_RDT(i), 928b88bced1Spatrick (rxr->last_desc_filled + 1) % sc->num_rx_desc); 929b88bced1Spatrick } 930b88bced1Spatrick 93183306792Spatrick igc_enable_intr(sc); 93283306792Spatrick 93383306792Spatrick ifp->if_flags |= IFF_RUNNING; 93483306792Spatrick for (i = 0; i < sc->sc_nqueues; i++) 93583306792Spatrick ifq_clr_oactive(ifp->if_ifqs[i]); 93683306792Spatrick 93783306792Spatrick splx(s); 93883306792Spatrick } 93983306792Spatrick 94040350728Spatrick static inline int 94140350728Spatrick igc_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m) 94240350728Spatrick { 94340350728Spatrick int error; 94440350728Spatrick 94540350728Spatrick error = bus_dmamap_load_mbuf(dmat, map, m, 94640350728Spatrick BUS_DMA_STREAMING | BUS_DMA_NOWAIT); 94740350728Spatrick if (error != EFBIG) 94840350728Spatrick return (error); 94940350728Spatrick 95040350728Spatrick error = m_defrag(m, M_DONTWAIT); 95140350728Spatrick if (error != 0) 95240350728Spatrick return (error); 95340350728Spatrick 95440350728Spatrick return (bus_dmamap_load_mbuf(dmat, map, m, 95540350728Spatrick BUS_DMA_STREAMING | BUS_DMA_NOWAIT)); 95640350728Spatrick } 95740350728Spatrick 95883306792Spatrick void 95983306792Spatrick igc_start(struct ifqueue *ifq) 96083306792Spatrick { 96183306792Spatrick struct ifnet *ifp = ifq->ifq_if; 96283306792Spatrick struct igc_softc *sc = ifp->if_softc; 963fb54a5a4Sbluhm struct igc_txring *txr = ifq->ifq_softc; 96440350728Spatrick union igc_adv_tx_desc *txdesc; 96540350728Spatrick struct igc_tx_buf *txbuf; 96640350728Spatrick bus_dmamap_t map; 96740350728Spatrick struct mbuf *m; 96840350728Spatrick unsigned int prod, free, last, i; 96940350728Spatrick unsigned int mask; 97040350728Spatrick uint32_t cmd_type_len; 97140350728Spatrick uint32_t olinfo_status; 97240350728Spatrick int post = 0; 97340350728Spatrick #if NBPFILTER > 0 97440350728Spatrick caddr_t if_bpf; 97540350728Spatrick #endif 97683306792Spatrick 97740350728Spatrick if (!sc->link_active) { 97840350728Spatrick ifq_purge(ifq); 97983306792Spatrick return; 98083306792Spatrick } 98183306792Spatrick 98240350728Spatrick prod = txr->next_avail_desc; 98340350728Spatrick free = txr->next_to_clean; 98440350728Spatrick if (free <= prod) 98540350728Spatrick free += sc->num_tx_desc; 98640350728Spatrick free -= prod; 98740350728Spatrick 98840350728Spatrick bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 0, 98940350728Spatrick txr->txdma.dma_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 99040350728Spatrick 99140350728Spatrick mask = sc->num_tx_desc - 1; 99240350728Spatrick 99340350728Spatrick for (;;) { 9941dfd2c79Smbuhl if (free <= IGC_MAX_SCATTER + 1) { 99540350728Spatrick ifq_set_oactive(ifq); 99640350728Spatrick break; 99740350728Spatrick } 99840350728Spatrick 99940350728Spatrick m = ifq_dequeue(ifq); 100040350728Spatrick if (m == NULL) 100140350728Spatrick break; 100240350728Spatrick 100340350728Spatrick txbuf = &txr->tx_buffers[prod]; 100440350728Spatrick map = txbuf->map; 100540350728Spatrick 100640350728Spatrick if (igc_load_mbuf(txr->txdma.dma_tag, map, m) != 0) { 100740350728Spatrick ifq->ifq_errors++; 100840350728Spatrick m_freem(m); 100940350728Spatrick continue; 101040350728Spatrick } 101140350728Spatrick 101240350728Spatrick olinfo_status = m->m_pkthdr.len << IGC_ADVTXD_PAYLEN_SHIFT; 101340350728Spatrick 101440350728Spatrick bus_dmamap_sync(txr->txdma.dma_tag, map, 0, 101540350728Spatrick map->dm_mapsize, BUS_DMASYNC_PREWRITE); 101640350728Spatrick 10172dad3cbaSmbuhl cmd_type_len = IGC_ADVTXD_DCMD_IFCS | IGC_ADVTXD_DTYP_DATA | 10182dad3cbaSmbuhl IGC_ADVTXD_DCMD_DEXT; 10192dad3cbaSmbuhl 10202dad3cbaSmbuhl if (igc_tx_ctx_setup(txr, m, prod, &cmd_type_len, 10212dad3cbaSmbuhl &olinfo_status)) { 10225a60fbd4Smbuhl /* Consume the first descriptor */ 10235a60fbd4Smbuhl prod++; 10245a60fbd4Smbuhl prod &= mask; 10251dfd2c79Smbuhl free--; 10265a60fbd4Smbuhl } 10275a60fbd4Smbuhl 102840350728Spatrick for (i = 0; i < map->dm_nsegs; i++) { 102940350728Spatrick txdesc = &txr->tx_base[prod]; 103040350728Spatrick 10312dad3cbaSmbuhl CLR(cmd_type_len, IGC_ADVTXD_DTALEN_MASK); 10322dad3cbaSmbuhl cmd_type_len |= map->dm_segs[i].ds_len; 103340350728Spatrick if (i == map->dm_nsegs - 1) 103440350728Spatrick cmd_type_len |= IGC_ADVTXD_DCMD_EOP | 103540350728Spatrick IGC_ADVTXD_DCMD_RS; 103640350728Spatrick 10372dad3cbaSmbuhl htolem64(&txdesc->read.buffer_addr, 10382dad3cbaSmbuhl map->dm_segs[i].ds_addr); 103940350728Spatrick htolem32(&txdesc->read.cmd_type_len, cmd_type_len); 104040350728Spatrick htolem32(&txdesc->read.olinfo_status, olinfo_status); 104140350728Spatrick 104240350728Spatrick last = prod; 104340350728Spatrick 104440350728Spatrick prod++; 104540350728Spatrick prod &= mask; 104640350728Spatrick } 104740350728Spatrick 104840350728Spatrick txbuf->m_head = m; 104940350728Spatrick txbuf->eop_index = last; 105040350728Spatrick 105140350728Spatrick #if NBPFILTER > 0 105240350728Spatrick if_bpf = ifp->if_bpf; 105340350728Spatrick if (if_bpf) 105440350728Spatrick bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT); 105540350728Spatrick #endif 105640350728Spatrick 105740350728Spatrick free -= i; 105840350728Spatrick post = 1; 105940350728Spatrick } 106040350728Spatrick 106140350728Spatrick bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 0, 106240350728Spatrick txr->txdma.dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE); 106340350728Spatrick 106440350728Spatrick if (post) { 106540350728Spatrick txr->next_avail_desc = prod; 106640350728Spatrick IGC_WRITE_REG(&sc->hw, IGC_TDT(txr->me), prod); 106740350728Spatrick } 106840350728Spatrick } 106940350728Spatrick 107040350728Spatrick int 1071fb54a5a4Sbluhm igc_txeof(struct igc_txring *txr) 107240350728Spatrick { 107340350728Spatrick struct igc_softc *sc = txr->sc; 107440350728Spatrick struct ifqueue *ifq = txr->ifq; 107540350728Spatrick union igc_adv_tx_desc *txdesc; 107640350728Spatrick struct igc_tx_buf *txbuf; 107740350728Spatrick bus_dmamap_t map; 107840350728Spatrick unsigned int cons, prod, last; 107940350728Spatrick unsigned int mask; 108040350728Spatrick int done = 0; 108140350728Spatrick 108240350728Spatrick prod = txr->next_avail_desc; 108340350728Spatrick cons = txr->next_to_clean; 108440350728Spatrick 108540350728Spatrick if (cons == prod) 108640350728Spatrick return (0); 108740350728Spatrick 108840350728Spatrick bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 0, 108940350728Spatrick txr->txdma.dma_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 109040350728Spatrick 109140350728Spatrick mask = sc->num_tx_desc - 1; 109240350728Spatrick 109340350728Spatrick do { 109440350728Spatrick txbuf = &txr->tx_buffers[cons]; 109540350728Spatrick last = txbuf->eop_index; 109640350728Spatrick txdesc = &txr->tx_base[last]; 109740350728Spatrick 109840350728Spatrick if (!(txdesc->wb.status & htole32(IGC_TXD_STAT_DD))) 109940350728Spatrick break; 110040350728Spatrick 110140350728Spatrick map = txbuf->map; 110240350728Spatrick 110340350728Spatrick bus_dmamap_sync(txr->txdma.dma_tag, map, 0, map->dm_mapsize, 110440350728Spatrick BUS_DMASYNC_POSTWRITE); 110540350728Spatrick bus_dmamap_unload(txr->txdma.dma_tag, map); 110640350728Spatrick m_freem(txbuf->m_head); 110740350728Spatrick 110840350728Spatrick txbuf->m_head = NULL; 110940350728Spatrick txbuf->eop_index = -1; 111040350728Spatrick 111140350728Spatrick cons = last + 1; 111240350728Spatrick cons &= mask; 111340350728Spatrick 111440350728Spatrick done = 1; 111540350728Spatrick } while (cons != prod); 111640350728Spatrick 111740350728Spatrick bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 0, 111840350728Spatrick txr->txdma.dma_map->dm_mapsize, BUS_DMASYNC_PREREAD); 111940350728Spatrick 112040350728Spatrick txr->next_to_clean = cons; 112140350728Spatrick 112240350728Spatrick if (ifq_is_oactive(ifq)) 112340350728Spatrick ifq_restart(ifq); 112440350728Spatrick 112540350728Spatrick return (done); 112640350728Spatrick } 112740350728Spatrick 112883306792Spatrick /********************************************************************* 112983306792Spatrick * 113083306792Spatrick * This routine disables all traffic on the adapter by issuing a 113183306792Spatrick * global reset on the MAC. 113283306792Spatrick * 113383306792Spatrick **********************************************************************/ 113483306792Spatrick void 113583306792Spatrick igc_stop(struct igc_softc *sc) 113683306792Spatrick { 113783306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 113883306792Spatrick int i; 113983306792Spatrick 114083306792Spatrick /* Tell the stack that the interface is no longer active. */ 114183306792Spatrick ifp->if_flags &= ~IFF_RUNNING; 114283306792Spatrick 114383306792Spatrick igc_disable_intr(sc); 114483306792Spatrick 114583306792Spatrick igc_reset_hw(&sc->hw); 114683306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_WUC, 0); 114783306792Spatrick 114883306792Spatrick intr_barrier(sc->tag); 114983306792Spatrick for (i = 0; i < sc->sc_nqueues; i++) { 115083306792Spatrick struct ifqueue *ifq = ifp->if_ifqs[i]; 115183306792Spatrick ifq_barrier(ifq); 115283306792Spatrick ifq_clr_oactive(ifq); 115383306792Spatrick 115483306792Spatrick if (sc->queues[i].tag != NULL) 115583306792Spatrick intr_barrier(sc->queues[i].tag); 115683306792Spatrick timeout_del(&sc->rx_rings[i].rx_refill); 115783306792Spatrick } 115883306792Spatrick 115983306792Spatrick igc_free_transmit_structures(sc); 116083306792Spatrick igc_free_receive_structures(sc); 116183306792Spatrick 116283306792Spatrick igc_update_link_status(sc); 116383306792Spatrick } 116483306792Spatrick 116583306792Spatrick /********************************************************************* 116683306792Spatrick * Ioctl entry point 116783306792Spatrick * 116883306792Spatrick * igc_ioctl is called when the user wants to configure the 116983306792Spatrick * interface. 117083306792Spatrick * 117183306792Spatrick * return 0 on success, positive on failure 117283306792Spatrick **********************************************************************/ 117383306792Spatrick int 117483306792Spatrick igc_ioctl(struct ifnet * ifp, u_long cmd, caddr_t data) 117583306792Spatrick { 117683306792Spatrick struct igc_softc *sc = ifp->if_softc; 117783306792Spatrick struct ifreq *ifr = (struct ifreq *)data; 117883306792Spatrick int s, error = 0; 117983306792Spatrick 118083306792Spatrick s = splnet(); 118183306792Spatrick 118283306792Spatrick switch (cmd) { 118383306792Spatrick case SIOCSIFADDR: 118483306792Spatrick ifp->if_flags |= IFF_UP; 118583306792Spatrick if (!(ifp->if_flags & IFF_RUNNING)) 118683306792Spatrick igc_init(sc); 118783306792Spatrick break; 118883306792Spatrick case SIOCSIFFLAGS: 118983306792Spatrick if (ifp->if_flags & IFF_UP) { 119083306792Spatrick if (ifp->if_flags & IFF_RUNNING) 119183306792Spatrick error = ENETRESET; 119283306792Spatrick else 119383306792Spatrick igc_init(sc); 119483306792Spatrick } else { 119583306792Spatrick if (ifp->if_flags & IFF_RUNNING) 119683306792Spatrick igc_stop(sc); 119783306792Spatrick } 119883306792Spatrick break; 119983306792Spatrick case SIOCSIFMEDIA: 120083306792Spatrick case SIOCGIFMEDIA: 120183306792Spatrick error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); 120283306792Spatrick break; 120383306792Spatrick case SIOCGIFRXR: 120483306792Spatrick error = igc_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data); 120583306792Spatrick break; 120683306792Spatrick default: 120783306792Spatrick error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 120883306792Spatrick } 120983306792Spatrick 121083306792Spatrick if (error == ENETRESET) { 121183306792Spatrick if (ifp->if_flags & IFF_RUNNING) { 121283306792Spatrick igc_disable_intr(sc); 121383306792Spatrick igc_iff(sc); 121483306792Spatrick igc_enable_intr(sc); 121583306792Spatrick } 121683306792Spatrick error = 0; 121783306792Spatrick } 121883306792Spatrick 121983306792Spatrick splx(s); 122083306792Spatrick return error; 122183306792Spatrick } 122283306792Spatrick 122383306792Spatrick int 122483306792Spatrick igc_rxrinfo(struct igc_softc *sc, struct if_rxrinfo *ifri) 122583306792Spatrick { 12264c58e589Spatrick struct if_rxring_info *ifr; 1227fb54a5a4Sbluhm struct igc_rxring *rxr; 122883306792Spatrick int error, i, n = 0; 122983306792Spatrick 123058721d3bSbluhm ifr = mallocarray(sc->sc_nqueues, sizeof(*ifr), M_DEVBUF, 123158721d3bSbluhm M_WAITOK | M_ZERO); 123283306792Spatrick 123383306792Spatrick for (i = 0; i < sc->sc_nqueues; i++) { 123483306792Spatrick rxr = &sc->rx_rings[i]; 1235*4cceae0fSdlg ifr[n].ifr_size = sc->rx_mbuf_sz; 123683306792Spatrick snprintf(ifr[n].ifr_name, sizeof(ifr[n].ifr_name), "%d", i); 123783306792Spatrick ifr[n].ifr_info = rxr->rx_ring; 123883306792Spatrick n++; 123983306792Spatrick } 124083306792Spatrick 124183306792Spatrick error = if_rxr_info_ioctl(ifri, sc->sc_nqueues, ifr); 124283306792Spatrick free(ifr, M_DEVBUF, sc->sc_nqueues * sizeof(*ifr)); 124383306792Spatrick 124483306792Spatrick return error; 124583306792Spatrick } 124683306792Spatrick 124783306792Spatrick int 1248fb54a5a4Sbluhm igc_rxfill(struct igc_rxring *rxr) 124983306792Spatrick { 125083306792Spatrick struct igc_softc *sc = rxr->sc; 125183306792Spatrick int i, post = 0; 125283306792Spatrick u_int slots; 125383306792Spatrick 125483306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 0, 125583306792Spatrick rxr->rxdma.dma_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 125683306792Spatrick 125783306792Spatrick i = rxr->last_desc_filled; 125883306792Spatrick for (slots = if_rxr_get(&rxr->rx_ring, sc->num_rx_desc); slots > 0; 125983306792Spatrick slots--) { 126083306792Spatrick if (++i == sc->num_rx_desc) 126183306792Spatrick i = 0; 126283306792Spatrick 126383306792Spatrick if (igc_get_buf(rxr, i) != 0) 126483306792Spatrick break; 126583306792Spatrick 126683306792Spatrick rxr->last_desc_filled = i; 126783306792Spatrick post = 1; 126883306792Spatrick } 126983306792Spatrick 127083306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 0, 127183306792Spatrick rxr->rxdma.dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE); 127283306792Spatrick 127383306792Spatrick if_rxr_put(&rxr->rx_ring, slots); 127483306792Spatrick 127583306792Spatrick return post; 127683306792Spatrick } 127783306792Spatrick 127883306792Spatrick void 127983306792Spatrick igc_rxrefill(void *xrxr) 128083306792Spatrick { 1281fb54a5a4Sbluhm struct igc_rxring *rxr = xrxr; 128283306792Spatrick struct igc_softc *sc = rxr->sc; 128383306792Spatrick 1284b88bced1Spatrick if (igc_rxfill(rxr)) { 1285b88bced1Spatrick IGC_WRITE_REG(&sc->hw, IGC_RDT(rxr->me), 1286b88bced1Spatrick (rxr->last_desc_filled + 1) % sc->num_rx_desc); 1287b88bced1Spatrick } 128883306792Spatrick else if (if_rxr_inuse(&rxr->rx_ring) == 0) 128983306792Spatrick timeout_add(&rxr->rx_refill, 1); 129083306792Spatrick } 129183306792Spatrick 129283306792Spatrick /********************************************************************* 129383306792Spatrick * 129483306792Spatrick * This routine executes in interrupt context. It replenishes 129583306792Spatrick * the mbufs in the descriptor and sends data which has been 129683306792Spatrick * dma'ed into host memory to upper layer. 129783306792Spatrick * 129883306792Spatrick *********************************************************************/ 129983306792Spatrick int 1300fb54a5a4Sbluhm igc_rxeof(struct igc_rxring *rxr) 130183306792Spatrick { 130283306792Spatrick struct igc_softc *sc = rxr->sc; 130383306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 130483306792Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 130583306792Spatrick struct mbuf *mp, *m; 130683306792Spatrick struct igc_rx_buf *rxbuf, *nxbuf; 130783306792Spatrick union igc_adv_rx_desc *rxdesc; 130883306792Spatrick uint32_t ptype, staterr = 0; 130983306792Spatrick uint16_t len, vtag; 131083306792Spatrick uint8_t eop = 0; 13117a97ce60Sjsg int i, nextp; 131283306792Spatrick 131383306792Spatrick if (!ISSET(ifp->if_flags, IFF_RUNNING)) 131483306792Spatrick return 0; 131583306792Spatrick 131683306792Spatrick i = rxr->next_to_check; 131783306792Spatrick while (if_rxr_inuse(&rxr->rx_ring) > 0) { 131883306792Spatrick uint32_t hash; 131983306792Spatrick uint16_t hashtype; 132083306792Spatrick 132183306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 132283306792Spatrick i * sizeof(union igc_adv_rx_desc), 132383306792Spatrick sizeof(union igc_adv_rx_desc), BUS_DMASYNC_POSTREAD); 132483306792Spatrick 132583306792Spatrick rxdesc = &rxr->rx_base[i]; 132683306792Spatrick staterr = letoh32(rxdesc->wb.upper.status_error); 132783306792Spatrick if (!ISSET(staterr, IGC_RXD_STAT_DD)) { 132883306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 132983306792Spatrick i * sizeof(union igc_adv_rx_desc), 133083306792Spatrick sizeof(union igc_adv_rx_desc), BUS_DMASYNC_PREREAD); 133183306792Spatrick break; 133283306792Spatrick } 133383306792Spatrick 133483306792Spatrick /* Zero out the receive descriptors status. */ 133583306792Spatrick rxdesc->wb.upper.status_error = 0; 133683306792Spatrick rxbuf = &rxr->rx_buffers[i]; 133783306792Spatrick 133883306792Spatrick /* Pull the mbuf off the ring. */ 133983306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxbuf->map, 0, 134083306792Spatrick rxbuf->map->dm_mapsize, BUS_DMASYNC_POSTREAD); 134183306792Spatrick bus_dmamap_unload(rxr->rxdma.dma_tag, rxbuf->map); 134283306792Spatrick 134383306792Spatrick mp = rxbuf->buf; 134483306792Spatrick len = letoh16(rxdesc->wb.upper.length); 134583306792Spatrick vtag = letoh16(rxdesc->wb.upper.vlan); 134683306792Spatrick eop = ((staterr & IGC_RXD_STAT_EOP) == IGC_RXD_STAT_EOP); 134783306792Spatrick ptype = letoh32(rxdesc->wb.lower.lo_dword.data) & 134883306792Spatrick IGC_PKTTYPE_MASK; 134983306792Spatrick hash = letoh32(rxdesc->wb.lower.hi_dword.rss); 135083306792Spatrick hashtype = le16toh(rxdesc->wb.lower.lo_dword.hs_rss.pkt_info) & 135183306792Spatrick IGC_RXDADV_RSSTYPE_MASK; 135283306792Spatrick 135383306792Spatrick if (staterr & IGC_RXDEXT_STATERR_RXE) { 135483306792Spatrick if (rxbuf->fmp) { 135583306792Spatrick m_freem(rxbuf->fmp); 135683306792Spatrick rxbuf->fmp = NULL; 135783306792Spatrick } 135883306792Spatrick 135983306792Spatrick m_freem(mp); 136083306792Spatrick rxbuf->buf = NULL; 136183306792Spatrick goto next_desc; 136283306792Spatrick } 136383306792Spatrick 136483306792Spatrick if (mp == NULL) { 136583306792Spatrick panic("%s: igc_rxeof: NULL mbuf in slot %d " 136683306792Spatrick "(nrx %d, filled %d)", DEVNAME(sc), i, 136783306792Spatrick if_rxr_inuse(&rxr->rx_ring), rxr->last_desc_filled); 136883306792Spatrick } 136983306792Spatrick 13707a97ce60Sjsg if (!eop) { 13717a97ce60Sjsg /* 13727a97ce60Sjsg * Figure out the next descriptor of this frame. 13737a97ce60Sjsg */ 13747a97ce60Sjsg nextp = i + 1; 13757a97ce60Sjsg if (nextp == sc->num_rx_desc) 13767a97ce60Sjsg nextp = 0; 13777a97ce60Sjsg nxbuf = &rxr->rx_buffers[nextp]; 13787a97ce60Sjsg /* prefetch(nxbuf); */ 13797a97ce60Sjsg } 13807a97ce60Sjsg 138183306792Spatrick mp->m_len = len; 138283306792Spatrick 138383306792Spatrick m = rxbuf->fmp; 138483306792Spatrick rxbuf->buf = rxbuf->fmp = NULL; 138583306792Spatrick 138683306792Spatrick if (m != NULL) 138783306792Spatrick m->m_pkthdr.len += mp->m_len; 138883306792Spatrick else { 138983306792Spatrick m = mp; 139083306792Spatrick m->m_pkthdr.len = mp->m_len; 139183306792Spatrick #if NVLAN > 0 139283306792Spatrick if (staterr & IGC_RXD_STAT_VP) { 139383306792Spatrick m->m_pkthdr.ether_vtag = vtag; 139483306792Spatrick m->m_flags |= M_VLANTAG; 139583306792Spatrick } 139683306792Spatrick #endif 139783306792Spatrick } 139883306792Spatrick 139983306792Spatrick /* Pass the head pointer on */ 140083306792Spatrick if (eop == 0) { 140183306792Spatrick nxbuf->fmp = m; 140283306792Spatrick m = NULL; 140383306792Spatrick mp->m_next = nxbuf->buf; 140483306792Spatrick } else { 140583306792Spatrick igc_rx_checksum(staterr, m, ptype); 140683306792Spatrick 140783306792Spatrick if (hashtype != IGC_RXDADV_RSSTYPE_NONE) { 140883306792Spatrick m->m_pkthdr.ph_flowid = hash; 140983306792Spatrick SET(m->m_pkthdr.csum_flags, M_FLOWID); 141083306792Spatrick } 141183306792Spatrick 141283306792Spatrick ml_enqueue(&ml, m); 141383306792Spatrick } 141483306792Spatrick next_desc: 141583306792Spatrick if_rxr_put(&rxr->rx_ring, 1); 141683306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 141783306792Spatrick i * sizeof(union igc_adv_rx_desc), 141883306792Spatrick sizeof(union igc_adv_rx_desc), BUS_DMASYNC_PREREAD); 141983306792Spatrick 142083306792Spatrick /* Advance our pointers to the next descriptor. */ 142183306792Spatrick if (++i == sc->num_rx_desc) 142283306792Spatrick i = 0; 142383306792Spatrick } 142483306792Spatrick rxr->next_to_check = i; 142583306792Spatrick 142683306792Spatrick if (ifiq_input(rxr->ifiq, &ml)) 142783306792Spatrick if_rxr_livelocked(&rxr->rx_ring); 142883306792Spatrick 142983306792Spatrick if (!(staterr & IGC_RXD_STAT_DD)) 143083306792Spatrick return 0; 143183306792Spatrick 143283306792Spatrick return 1; 143383306792Spatrick } 143483306792Spatrick 143583306792Spatrick /********************************************************************* 143683306792Spatrick * 143783306792Spatrick * Verify that the hardware indicated that the checksum is valid. 143883306792Spatrick * Inform the stack about the status of checksum so that stack 143983306792Spatrick * doesn't spend time verifying the checksum. 144083306792Spatrick * 144183306792Spatrick *********************************************************************/ 144283306792Spatrick void 144383306792Spatrick igc_rx_checksum(uint32_t staterr, struct mbuf *m, uint32_t ptype) 144483306792Spatrick { 144583306792Spatrick uint16_t status = (uint16_t)staterr; 144683306792Spatrick uint8_t errors = (uint8_t)(staterr >> 24); 144783306792Spatrick 144883306792Spatrick if (status & IGC_RXD_STAT_IPCS) { 144983306792Spatrick if (!(errors & IGC_RXD_ERR_IPE)) { 145083306792Spatrick /* IP Checksum Good */ 145183306792Spatrick m->m_pkthdr.csum_flags = M_IPV4_CSUM_IN_OK; 145283306792Spatrick } else 145383306792Spatrick m->m_pkthdr.csum_flags = 0; 145483306792Spatrick } 145583306792Spatrick 145683306792Spatrick if (status & (IGC_RXD_STAT_TCPCS | IGC_RXD_STAT_UDPCS)) { 145783306792Spatrick if (!(errors & IGC_RXD_ERR_TCPE)) 145883306792Spatrick m->m_pkthdr.csum_flags |= 145983306792Spatrick M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK; 146083306792Spatrick } 146183306792Spatrick } 146283306792Spatrick 146383306792Spatrick void 146483306792Spatrick igc_watchdog(struct ifnet * ifp) 146583306792Spatrick { 146683306792Spatrick } 146783306792Spatrick 146883306792Spatrick /********************************************************************* 146983306792Spatrick * 147083306792Spatrick * Media Ioctl callback 147183306792Spatrick * 147283306792Spatrick * This routine is called whenever the user queries the status of 147383306792Spatrick * the interface using ifconfig. 147483306792Spatrick * 147583306792Spatrick **********************************************************************/ 147683306792Spatrick void 147783306792Spatrick igc_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 147883306792Spatrick { 147983306792Spatrick struct igc_softc *sc = ifp->if_softc; 148083306792Spatrick 148183306792Spatrick igc_update_link_status(sc); 148283306792Spatrick 148383306792Spatrick ifmr->ifm_status = IFM_AVALID; 148483306792Spatrick ifmr->ifm_active = IFM_ETHER; 148583306792Spatrick 148683306792Spatrick if (!sc->link_active) { 148783306792Spatrick ifmr->ifm_active |= IFM_NONE; 148883306792Spatrick return; 148983306792Spatrick } 149083306792Spatrick 149183306792Spatrick ifmr->ifm_status |= IFM_ACTIVE; 149283306792Spatrick 149383306792Spatrick switch (sc->link_speed) { 149483306792Spatrick case 10: 149583306792Spatrick ifmr->ifm_active |= IFM_10_T; 149683306792Spatrick break; 149783306792Spatrick case 100: 149883306792Spatrick ifmr->ifm_active |= IFM_100_TX; 149983306792Spatrick break; 150083306792Spatrick case 1000: 150183306792Spatrick ifmr->ifm_active |= IFM_1000_T; 150283306792Spatrick break; 150383306792Spatrick case 2500: 150483306792Spatrick ifmr->ifm_active |= IFM_2500_T; 150583306792Spatrick break; 150683306792Spatrick } 150783306792Spatrick 150883306792Spatrick if (sc->link_duplex == FULL_DUPLEX) 150983306792Spatrick ifmr->ifm_active |= IFM_FDX; 151083306792Spatrick else 151183306792Spatrick ifmr->ifm_active |= IFM_HDX; 1512b4e446e2Skevlo 1513b4e446e2Skevlo switch (sc->hw.fc.current_mode) { 1514b4e446e2Skevlo case igc_fc_tx_pause: 1515b4e446e2Skevlo ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE; 1516b4e446e2Skevlo break; 1517b4e446e2Skevlo case igc_fc_rx_pause: 1518b4e446e2Skevlo ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE; 1519b4e446e2Skevlo break; 1520b4e446e2Skevlo case igc_fc_full: 1521b4e446e2Skevlo ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE | 1522b4e446e2Skevlo IFM_ETH_TXPAUSE; 1523b4e446e2Skevlo break; 1524b4e446e2Skevlo default: 1525b4e446e2Skevlo ifmr->ifm_active &= ~(IFM_FLOW | IFM_ETH_RXPAUSE | 1526b4e446e2Skevlo IFM_ETH_TXPAUSE); 1527b4e446e2Skevlo break; 1528b4e446e2Skevlo } 152983306792Spatrick } 153083306792Spatrick 153183306792Spatrick /********************************************************************* 153283306792Spatrick * 153383306792Spatrick * Media Ioctl callback 153483306792Spatrick * 153583306792Spatrick * This routine is called when the user changes speed/duplex using 153683306792Spatrick * media/mediopt option with ifconfig. 153783306792Spatrick * 153883306792Spatrick **********************************************************************/ 153983306792Spatrick int 154083306792Spatrick igc_media_change(struct ifnet *ifp) 154183306792Spatrick { 154283306792Spatrick struct igc_softc *sc = ifp->if_softc; 154383306792Spatrick struct ifmedia *ifm = &sc->media; 154483306792Spatrick 154583306792Spatrick if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 154683306792Spatrick return (EINVAL); 154783306792Spatrick 154883306792Spatrick sc->hw.mac.autoneg = DO_AUTO_NEG; 154983306792Spatrick 155083306792Spatrick switch (IFM_SUBTYPE(ifm->ifm_media)) { 155183306792Spatrick case IFM_AUTO: 155283306792Spatrick sc->hw.phy.autoneg_advertised = AUTONEG_ADV_DEFAULT; 155383306792Spatrick break; 155483306792Spatrick case IFM_2500_T: 155583306792Spatrick sc->hw.phy.autoneg_advertised = ADVERTISE_2500_FULL; 155683306792Spatrick break; 155783306792Spatrick case IFM_1000_T: 155883306792Spatrick sc->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL; 155983306792Spatrick break; 156083306792Spatrick case IFM_100_TX: 1561cbab2262Skevlo if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 156283306792Spatrick sc->hw.phy.autoneg_advertised = ADVERTISE_100_FULL; 1563cbab2262Skevlo else 1564cbab2262Skevlo sc->hw.phy.autoneg_advertised = ADVERTISE_100_HALF; 156583306792Spatrick break; 156683306792Spatrick case IFM_10_T: 1567cbab2262Skevlo if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 156883306792Spatrick sc->hw.phy.autoneg_advertised = ADVERTISE_10_FULL; 1569cbab2262Skevlo else 1570cbab2262Skevlo sc->hw.phy.autoneg_advertised = ADVERTISE_10_HALF; 157183306792Spatrick break; 157283306792Spatrick default: 157383306792Spatrick return EINVAL; 157483306792Spatrick } 157583306792Spatrick 157683306792Spatrick igc_init(sc); 157783306792Spatrick 157883306792Spatrick return 0; 157983306792Spatrick } 158083306792Spatrick 158183306792Spatrick void 158283306792Spatrick igc_iff(struct igc_softc *sc) 158383306792Spatrick { 158483306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 158583306792Spatrick struct arpcom *ac = &sc->sc_ac; 158683306792Spatrick struct ether_multi *enm; 158783306792Spatrick struct ether_multistep step; 158883306792Spatrick uint32_t reg_rctl = 0; 158983306792Spatrick uint8_t *mta; 159083306792Spatrick int mcnt = 0; 159183306792Spatrick 159283306792Spatrick mta = sc->mta; 159383306792Spatrick bzero(mta, sizeof(uint8_t) * ETHER_ADDR_LEN * 159483306792Spatrick MAX_NUM_MULTICAST_ADDRESSES); 159583306792Spatrick 159683306792Spatrick reg_rctl = IGC_READ_REG(&sc->hw, IGC_RCTL); 159783306792Spatrick reg_rctl &= ~(IGC_RCTL_UPE | IGC_RCTL_MPE); 159883306792Spatrick ifp->if_flags &= ~IFF_ALLMULTI; 159983306792Spatrick 160083306792Spatrick if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0 || 160183306792Spatrick ac->ac_multicnt > MAX_NUM_MULTICAST_ADDRESSES) { 160283306792Spatrick ifp->if_flags |= IFF_ALLMULTI; 160383306792Spatrick reg_rctl |= IGC_RCTL_MPE; 160483306792Spatrick if (ifp->if_flags & IFF_PROMISC) 160583306792Spatrick reg_rctl |= IGC_RCTL_UPE; 160683306792Spatrick } else { 160783306792Spatrick ETHER_FIRST_MULTI(step, ac, enm); 160883306792Spatrick while (enm != NULL) { 160983306792Spatrick bcopy(enm->enm_addrlo, 161083306792Spatrick &mta[mcnt * ETHER_ADDR_LEN], ETHER_ADDR_LEN); 161183306792Spatrick mcnt++; 161283306792Spatrick 161383306792Spatrick ETHER_NEXT_MULTI(step, enm); 161483306792Spatrick } 161583306792Spatrick 161683306792Spatrick igc_update_mc_addr_list(&sc->hw, mta, mcnt); 161783306792Spatrick } 161883306792Spatrick 161983306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_RCTL, reg_rctl); 162083306792Spatrick } 162183306792Spatrick 162283306792Spatrick void 162383306792Spatrick igc_update_link_status(struct igc_softc *sc) 162483306792Spatrick { 162583306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 162683306792Spatrick struct igc_hw *hw = &sc->hw; 162783306792Spatrick int link_state; 162883306792Spatrick 1629b4e446e2Skevlo if (hw->mac.get_link_status == true) 1630b4e446e2Skevlo igc_check_for_link(hw); 1631b4e446e2Skevlo 163283306792Spatrick if (IGC_READ_REG(&sc->hw, IGC_STATUS) & IGC_STATUS_LU) { 163383306792Spatrick if (sc->link_active == 0) { 163483306792Spatrick igc_get_speed_and_duplex(hw, &sc->link_speed, 163583306792Spatrick &sc->link_duplex); 163683306792Spatrick sc->link_active = 1; 163783306792Spatrick ifp->if_baudrate = IF_Mbps(sc->link_speed); 163883306792Spatrick } 163983306792Spatrick link_state = (sc->link_duplex == FULL_DUPLEX) ? 164083306792Spatrick LINK_STATE_FULL_DUPLEX : LINK_STATE_HALF_DUPLEX; 164183306792Spatrick } else { 164283306792Spatrick if (sc->link_active == 1) { 164383306792Spatrick ifp->if_baudrate = sc->link_speed = 0; 164483306792Spatrick sc->link_duplex = 0; 164583306792Spatrick sc->link_active = 0; 164683306792Spatrick } 164783306792Spatrick link_state = LINK_STATE_DOWN; 164883306792Spatrick } 164983306792Spatrick if (ifp->if_link_state != link_state) { 165083306792Spatrick ifp->if_link_state = link_state; 165183306792Spatrick if_link_state_change(ifp); 165283306792Spatrick } 165383306792Spatrick } 165483306792Spatrick 165583306792Spatrick /********************************************************************* 165683306792Spatrick * 165783306792Spatrick * Get a buffer from system mbuf buffer pool. 165883306792Spatrick * 165983306792Spatrick **********************************************************************/ 166083306792Spatrick int 1661fb54a5a4Sbluhm igc_get_buf(struct igc_rxring *rxr, int i) 166283306792Spatrick { 166383306792Spatrick struct igc_softc *sc = rxr->sc; 166483306792Spatrick struct igc_rx_buf *rxbuf; 166583306792Spatrick struct mbuf *m; 166683306792Spatrick union igc_adv_rx_desc *rxdesc; 166783306792Spatrick int error; 166883306792Spatrick 166983306792Spatrick rxbuf = &rxr->rx_buffers[i]; 167083306792Spatrick rxdesc = &rxr->rx_base[i]; 167183306792Spatrick if (rxbuf->buf) { 167283306792Spatrick printf("%s: slot %d already has an mbuf\n", DEVNAME(sc), i); 167383306792Spatrick return ENOBUFS; 167483306792Spatrick } 167583306792Spatrick 1676*4cceae0fSdlg m = MCLGETL(NULL, M_DONTWAIT, sc->rx_mbuf_sz + ETHER_ALIGN); 167783306792Spatrick if (!m) 167883306792Spatrick return ENOBUFS; 167983306792Spatrick 1680*4cceae0fSdlg m->m_data += ETHER_ALIGN; 168183306792Spatrick m->m_len = m->m_pkthdr.len = sc->rx_mbuf_sz; 168283306792Spatrick 168383306792Spatrick error = bus_dmamap_load_mbuf(rxr->rxdma.dma_tag, rxbuf->map, m, 168483306792Spatrick BUS_DMA_NOWAIT); 168583306792Spatrick if (error) { 168683306792Spatrick m_freem(m); 168783306792Spatrick return error; 168883306792Spatrick } 168983306792Spatrick 169083306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxbuf->map, 0, 169183306792Spatrick rxbuf->map->dm_mapsize, BUS_DMASYNC_PREREAD); 169283306792Spatrick rxbuf->buf = m; 169383306792Spatrick 169483306792Spatrick rxdesc->read.pkt_addr = htole64(rxbuf->map->dm_segs[0].ds_addr); 169583306792Spatrick 169683306792Spatrick return 0; 169783306792Spatrick } 169883306792Spatrick 169983306792Spatrick void 170083306792Spatrick igc_configure_queues(struct igc_softc *sc) 170183306792Spatrick { 170283306792Spatrick struct igc_hw *hw = &sc->hw; 170383306792Spatrick struct igc_queue *iq = sc->queues; 170483306792Spatrick uint32_t ivar, newitr = 0; 170583306792Spatrick int i; 170683306792Spatrick 170783306792Spatrick /* First turn on RSS capability */ 170883306792Spatrick IGC_WRITE_REG(hw, IGC_GPIE, IGC_GPIE_MSIX_MODE | IGC_GPIE_EIAME | 170983306792Spatrick IGC_GPIE_PBA | IGC_GPIE_NSICR); 171083306792Spatrick 171183306792Spatrick /* Set the starting interrupt rate */ 171283306792Spatrick newitr = (4000000 / MAX_INTS_PER_SEC) & 0x7FFC; 171383306792Spatrick 171483306792Spatrick newitr |= IGC_EITR_CNT_IGNR; 171583306792Spatrick 171683306792Spatrick /* Turn on MSI-X */ 171783306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, iq++) { 171883306792Spatrick /* RX entries */ 171983306792Spatrick igc_set_queues(sc, i, iq->msix, 0); 172083306792Spatrick /* TX entries */ 172183306792Spatrick igc_set_queues(sc, i, iq->msix, 1); 172283306792Spatrick sc->msix_queuesmask |= iq->eims; 172383306792Spatrick IGC_WRITE_REG(hw, IGC_EITR(iq->msix), newitr); 172483306792Spatrick } 172583306792Spatrick 172683306792Spatrick /* And for the link interrupt */ 172783306792Spatrick ivar = (sc->linkvec | IGC_IVAR_VALID) << 8; 172883306792Spatrick sc->msix_linkmask = 1 << sc->linkvec; 172983306792Spatrick IGC_WRITE_REG(hw, IGC_IVAR_MISC, ivar); 173083306792Spatrick } 173183306792Spatrick 173283306792Spatrick void 173383306792Spatrick igc_set_queues(struct igc_softc *sc, uint32_t entry, uint32_t vector, int type) 173483306792Spatrick { 173583306792Spatrick struct igc_hw *hw = &sc->hw; 173683306792Spatrick uint32_t ivar, index; 173783306792Spatrick 173883306792Spatrick index = entry >> 1; 173983306792Spatrick ivar = IGC_READ_REG_ARRAY(hw, IGC_IVAR0, index); 174083306792Spatrick if (type) { 174183306792Spatrick if (entry & 1) { 174283306792Spatrick ivar &= 0x00FFFFFF; 174383306792Spatrick ivar |= (vector | IGC_IVAR_VALID) << 24; 174483306792Spatrick } else { 174583306792Spatrick ivar &= 0xFFFF00FF; 174683306792Spatrick ivar |= (vector | IGC_IVAR_VALID) << 8; 174783306792Spatrick } 174883306792Spatrick } else { 174983306792Spatrick if (entry & 1) { 175083306792Spatrick ivar &= 0xFF00FFFF; 175183306792Spatrick ivar |= (vector | IGC_IVAR_VALID) << 16; 175283306792Spatrick } else { 175383306792Spatrick ivar &= 0xFFFFFF00; 175483306792Spatrick ivar |= vector | IGC_IVAR_VALID; 175583306792Spatrick } 175683306792Spatrick } 175783306792Spatrick IGC_WRITE_REG_ARRAY(hw, IGC_IVAR0, index, ivar); 175883306792Spatrick } 175983306792Spatrick 176083306792Spatrick void 176183306792Spatrick igc_enable_queue(struct igc_softc *sc, uint32_t eims) 176283306792Spatrick { 176383306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_EIMS, eims); 176483306792Spatrick } 176583306792Spatrick 176683306792Spatrick void 176783306792Spatrick igc_enable_intr(struct igc_softc *sc) 176883306792Spatrick { 176983306792Spatrick struct igc_hw *hw = &sc->hw; 177083306792Spatrick uint32_t mask; 177183306792Spatrick 177283306792Spatrick mask = (sc->msix_queuesmask | sc->msix_linkmask); 177383306792Spatrick IGC_WRITE_REG(hw, IGC_EIAC, mask); 177483306792Spatrick IGC_WRITE_REG(hw, IGC_EIAM, mask); 177583306792Spatrick IGC_WRITE_REG(hw, IGC_EIMS, mask); 177683306792Spatrick IGC_WRITE_REG(hw, IGC_IMS, IGC_IMS_LSC); 177783306792Spatrick IGC_WRITE_FLUSH(hw); 177883306792Spatrick } 177983306792Spatrick 178083306792Spatrick void 178183306792Spatrick igc_disable_intr(struct igc_softc *sc) 178283306792Spatrick { 178383306792Spatrick struct igc_hw *hw = &sc->hw; 178483306792Spatrick 178583306792Spatrick IGC_WRITE_REG(hw, IGC_EIMC, 0xffffffff); 178683306792Spatrick IGC_WRITE_REG(hw, IGC_EIAC, 0); 178783306792Spatrick IGC_WRITE_REG(hw, IGC_IMC, 0xffffffff); 178883306792Spatrick IGC_WRITE_FLUSH(hw); 178983306792Spatrick } 179083306792Spatrick 179183306792Spatrick int 179283306792Spatrick igc_intr_link(void *arg) 179383306792Spatrick { 179483306792Spatrick struct igc_softc *sc = (struct igc_softc *)arg; 17957a97ce60Sjsg uint32_t reg_icr = IGC_READ_REG(&sc->hw, IGC_ICR); 179683306792Spatrick 179783306792Spatrick if (reg_icr & IGC_ICR_LSC) { 179883306792Spatrick KERNEL_LOCK(); 179983306792Spatrick sc->hw.mac.get_link_status = true; 180083306792Spatrick igc_update_link_status(sc); 180183306792Spatrick KERNEL_UNLOCK(); 180283306792Spatrick } 180383306792Spatrick 180483306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_IMS, IGC_IMS_LSC); 180583306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_EIMS, sc->msix_linkmask); 180683306792Spatrick 180783306792Spatrick return 1; 180883306792Spatrick } 180983306792Spatrick 181083306792Spatrick int 181183306792Spatrick igc_intr_queue(void *arg) 181283306792Spatrick { 181383306792Spatrick struct igc_queue *iq = arg; 181483306792Spatrick struct igc_softc *sc = iq->sc; 181583306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 1816fb54a5a4Sbluhm struct igc_rxring *rxr = iq->rxr; 1817fb54a5a4Sbluhm struct igc_txring *txr = iq->txr; 181883306792Spatrick 181983306792Spatrick if (ifp->if_flags & IFF_RUNNING) { 182040350728Spatrick igc_txeof(txr); 182183306792Spatrick igc_rxeof(rxr); 182283306792Spatrick igc_rxrefill(rxr); 182383306792Spatrick } 182483306792Spatrick 182583306792Spatrick igc_enable_queue(sc, iq->eims); 182683306792Spatrick 182783306792Spatrick return 1; 182883306792Spatrick } 182983306792Spatrick 183083306792Spatrick /********************************************************************* 183183306792Spatrick * 183283306792Spatrick * Allocate memory for tx_buffer structures. The tx_buffer stores all 183383306792Spatrick * the information needed to transmit a packet on the wire. 183483306792Spatrick * 183583306792Spatrick **********************************************************************/ 183683306792Spatrick int 1837fb54a5a4Sbluhm igc_allocate_transmit_buffers(struct igc_txring *txr) 183883306792Spatrick { 183983306792Spatrick struct igc_softc *sc = txr->sc; 184083306792Spatrick struct igc_tx_buf *txbuf; 184183306792Spatrick int error, i; 184283306792Spatrick 184383306792Spatrick txr->tx_buffers = mallocarray(sc->num_tx_desc, 184483306792Spatrick sizeof(struct igc_tx_buf), M_DEVBUF, M_NOWAIT | M_ZERO); 184583306792Spatrick if (txr->tx_buffers == NULL) { 184683306792Spatrick printf("%s: Unable to allocate tx_buffer memory\n", 184783306792Spatrick DEVNAME(sc)); 184883306792Spatrick error = ENOMEM; 184983306792Spatrick goto fail; 185083306792Spatrick } 185183306792Spatrick txr->txtag = txr->txdma.dma_tag; 185283306792Spatrick 185383306792Spatrick /* Create the descriptor buffer dma maps. */ 185483306792Spatrick for (i = 0; i < sc->num_tx_desc; i++) { 185583306792Spatrick txbuf = &txr->tx_buffers[i]; 185683306792Spatrick error = bus_dmamap_create(txr->txdma.dma_tag, IGC_TSO_SIZE, 185783306792Spatrick IGC_MAX_SCATTER, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &txbuf->map); 185883306792Spatrick if (error != 0) { 185983306792Spatrick printf("%s: Unable to create TX DMA map\n", 186083306792Spatrick DEVNAME(sc)); 186183306792Spatrick goto fail; 186283306792Spatrick } 186383306792Spatrick } 186483306792Spatrick 186583306792Spatrick return 0; 186683306792Spatrick fail: 186783306792Spatrick return error; 186883306792Spatrick } 186983306792Spatrick 187083306792Spatrick 187183306792Spatrick /********************************************************************* 187283306792Spatrick * 187383306792Spatrick * Allocate and initialize transmit structures. 187483306792Spatrick * 187583306792Spatrick **********************************************************************/ 187683306792Spatrick int 187783306792Spatrick igc_setup_transmit_structures(struct igc_softc *sc) 187883306792Spatrick { 1879fb54a5a4Sbluhm struct igc_txring *txr = sc->tx_rings; 188083306792Spatrick int i; 188183306792Spatrick 188283306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, txr++) { 188383306792Spatrick if (igc_setup_transmit_ring(txr)) 188483306792Spatrick goto fail; 188583306792Spatrick } 188683306792Spatrick 188783306792Spatrick return 0; 188883306792Spatrick fail: 188983306792Spatrick igc_free_transmit_structures(sc); 189083306792Spatrick return ENOBUFS; 189183306792Spatrick } 189283306792Spatrick 189383306792Spatrick /********************************************************************* 189483306792Spatrick * 189583306792Spatrick * Initialize a transmit ring. 189683306792Spatrick * 189783306792Spatrick **********************************************************************/ 189883306792Spatrick int 1899fb54a5a4Sbluhm igc_setup_transmit_ring(struct igc_txring *txr) 190083306792Spatrick { 190183306792Spatrick struct igc_softc *sc = txr->sc; 190283306792Spatrick 190383306792Spatrick /* Now allocate transmit buffers for the ring. */ 190483306792Spatrick if (igc_allocate_transmit_buffers(txr)) 190583306792Spatrick return ENOMEM; 190683306792Spatrick 190783306792Spatrick /* Clear the old ring contents */ 190883306792Spatrick bzero((void *)txr->tx_base, 190983306792Spatrick (sizeof(union igc_adv_tx_desc)) * sc->num_tx_desc); 191083306792Spatrick 191183306792Spatrick /* Reset indices. */ 191283306792Spatrick txr->next_avail_desc = 0; 191383306792Spatrick txr->next_to_clean = 0; 191483306792Spatrick 191583306792Spatrick bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 0, 191683306792Spatrick txr->txdma.dma_map->dm_mapsize, 191783306792Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 191883306792Spatrick 191983306792Spatrick return 0; 192083306792Spatrick } 192183306792Spatrick 192283306792Spatrick /********************************************************************* 192383306792Spatrick * 192483306792Spatrick * Enable transmit unit. 192583306792Spatrick * 192683306792Spatrick **********************************************************************/ 192783306792Spatrick void 192883306792Spatrick igc_initialize_transmit_unit(struct igc_softc *sc) 192983306792Spatrick { 193083306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 1931fb54a5a4Sbluhm struct igc_txring *txr; 193283306792Spatrick struct igc_hw *hw = &sc->hw; 193383306792Spatrick uint64_t bus_addr; 193483306792Spatrick uint32_t tctl, txdctl = 0; 193583306792Spatrick int i; 193683306792Spatrick 193783306792Spatrick /* Setup the Base and Length of the TX descriptor ring. */ 193883306792Spatrick for (i = 0; i < sc->sc_nqueues; i++) { 193983306792Spatrick txr = &sc->tx_rings[i]; 194083306792Spatrick 194183306792Spatrick bus_addr = txr->txdma.dma_map->dm_segs[0].ds_addr; 194283306792Spatrick 194383306792Spatrick /* Base and len of TX ring */ 194483306792Spatrick IGC_WRITE_REG(hw, IGC_TDLEN(i), 194583306792Spatrick sc->num_tx_desc * sizeof(union igc_adv_tx_desc)); 194683306792Spatrick IGC_WRITE_REG(hw, IGC_TDBAH(i), (uint32_t)(bus_addr >> 32)); 194783306792Spatrick IGC_WRITE_REG(hw, IGC_TDBAL(i), (uint32_t)bus_addr); 194883306792Spatrick 194983306792Spatrick /* Init the HEAD/TAIL indices */ 195083306792Spatrick IGC_WRITE_REG(hw, IGC_TDT(i), 0); 195183306792Spatrick IGC_WRITE_REG(hw, IGC_TDH(i), 0); 195283306792Spatrick 195383306792Spatrick txr->watchdog_timer = 0; 195483306792Spatrick 195583306792Spatrick txdctl = 0; /* Clear txdctl */ 195683306792Spatrick txdctl |= 0x1f; /* PTHRESH */ 195783306792Spatrick txdctl |= 1 << 8; /* HTHRESH */ 195883306792Spatrick txdctl |= 1 << 16; /* WTHRESH */ 195983306792Spatrick txdctl |= 1 << 22; /* Reserved bit 22 must always be 1 */ 196083306792Spatrick txdctl |= IGC_TXDCTL_GRAN; 196183306792Spatrick txdctl |= 1 << 25; /* LWTHRESH */ 196283306792Spatrick 196383306792Spatrick IGC_WRITE_REG(hw, IGC_TXDCTL(i), txdctl); 196483306792Spatrick } 196583306792Spatrick ifp->if_timer = 0; 196683306792Spatrick 196783306792Spatrick /* Program the Transmit Control Register */ 196883306792Spatrick tctl = IGC_READ_REG(&sc->hw, IGC_TCTL); 196983306792Spatrick tctl &= ~IGC_TCTL_CT; 197083306792Spatrick tctl |= (IGC_TCTL_PSP | IGC_TCTL_RTLC | IGC_TCTL_EN | 197183306792Spatrick (IGC_COLLISION_THRESHOLD << IGC_CT_SHIFT)); 197283306792Spatrick 197383306792Spatrick /* This write will effectively turn on the transmit unit. */ 197483306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_TCTL, tctl); 197583306792Spatrick } 197683306792Spatrick 197783306792Spatrick /********************************************************************* 197883306792Spatrick * 197983306792Spatrick * Free all transmit rings. 198083306792Spatrick * 198183306792Spatrick **********************************************************************/ 198283306792Spatrick void 198383306792Spatrick igc_free_transmit_structures(struct igc_softc *sc) 198483306792Spatrick { 1985fb54a5a4Sbluhm struct igc_txring *txr = sc->tx_rings; 198683306792Spatrick int i; 198783306792Spatrick 198883306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, txr++) 198983306792Spatrick igc_free_transmit_buffers(txr); 199083306792Spatrick } 199183306792Spatrick 199283306792Spatrick /********************************************************************* 199383306792Spatrick * 199483306792Spatrick * Free transmit ring related data structures. 199583306792Spatrick * 199683306792Spatrick **********************************************************************/ 199783306792Spatrick void 1998fb54a5a4Sbluhm igc_free_transmit_buffers(struct igc_txring *txr) 199983306792Spatrick { 200083306792Spatrick struct igc_softc *sc = txr->sc; 200183306792Spatrick struct igc_tx_buf *txbuf; 200283306792Spatrick int i; 200383306792Spatrick 200483306792Spatrick if (txr->tx_buffers == NULL) 200583306792Spatrick return; 200683306792Spatrick 200783306792Spatrick txbuf = txr->tx_buffers; 200883306792Spatrick for (i = 0; i < sc->num_tx_desc; i++, txbuf++) { 200983306792Spatrick if (txbuf->map != NULL && txbuf->map->dm_nsegs > 0) { 201083306792Spatrick bus_dmamap_sync(txr->txdma.dma_tag, txbuf->map, 201183306792Spatrick 0, txbuf->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 201283306792Spatrick bus_dmamap_unload(txr->txdma.dma_tag, txbuf->map); 201383306792Spatrick } 201483306792Spatrick if (txbuf->m_head != NULL) { 201583306792Spatrick m_freem(txbuf->m_head); 201683306792Spatrick txbuf->m_head = NULL; 201783306792Spatrick } 201883306792Spatrick if (txbuf->map != NULL) { 201983306792Spatrick bus_dmamap_destroy(txr->txdma.dma_tag, txbuf->map); 202083306792Spatrick txbuf->map = NULL; 202183306792Spatrick } 202283306792Spatrick } 202383306792Spatrick 202483306792Spatrick if (txr->tx_buffers != NULL) 202583306792Spatrick free(txr->tx_buffers, M_DEVBUF, 202683306792Spatrick sc->num_tx_desc * sizeof(struct igc_tx_buf)); 202783306792Spatrick txr->tx_buffers = NULL; 202883306792Spatrick txr->txtag = NULL; 202983306792Spatrick } 203083306792Spatrick 20315a60fbd4Smbuhl 20325a60fbd4Smbuhl /********************************************************************* 20335a60fbd4Smbuhl * 20345a60fbd4Smbuhl * Advanced Context Descriptor setup for VLAN, CSUM or TSO 20355a60fbd4Smbuhl * 20365a60fbd4Smbuhl **********************************************************************/ 20375a60fbd4Smbuhl 20385a60fbd4Smbuhl int 2039fb54a5a4Sbluhm igc_tx_ctx_setup(struct igc_txring *txr, struct mbuf *mp, int prod, 20402dad3cbaSmbuhl uint32_t *cmd_type_len, uint32_t *olinfo_status) 20415a60fbd4Smbuhl { 2042efd8dad8Snaddy struct ether_extracted ext; 20435a60fbd4Smbuhl struct igc_adv_tx_context_desc *txdesc; 20442011187aSmbuhl uint32_t mss_l4len_idx = 0; 20455a60fbd4Smbuhl uint32_t type_tucmd_mlhl = 0; 20465a60fbd4Smbuhl uint32_t vlan_macip_lens = 0; 20475a60fbd4Smbuhl int off = 0; 20485a60fbd4Smbuhl 20495a60fbd4Smbuhl /* 20505a60fbd4Smbuhl * In advanced descriptors the vlan tag must 20515a60fbd4Smbuhl * be placed into the context descriptor. Hence 20525a60fbd4Smbuhl * we need to make one even if not doing offloads. 20535a60fbd4Smbuhl */ 20545a60fbd4Smbuhl #if NVLAN > 0 20555a60fbd4Smbuhl if (ISSET(mp->m_flags, M_VLANTAG)) { 20565a60fbd4Smbuhl uint32_t vtag = mp->m_pkthdr.ether_vtag; 20575a60fbd4Smbuhl vlan_macip_lens |= (vtag << IGC_ADVTXD_VLAN_SHIFT); 20582dad3cbaSmbuhl *cmd_type_len |= IGC_ADVTXD_DCMD_VLE; 20595a60fbd4Smbuhl off = 1; 20605a60fbd4Smbuhl } 20615a60fbd4Smbuhl #endif 20625a60fbd4Smbuhl 20632011187aSmbuhl ether_extract_headers(mp, &ext); 20642011187aSmbuhl 20652011187aSmbuhl vlan_macip_lens |= (sizeof(*ext.eh) << IGC_ADVTXD_MACLEN_SHIFT); 20662011187aSmbuhl 2067efd8dad8Snaddy if (ext.ip4) { 20685a60fbd4Smbuhl type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV4; 20695a60fbd4Smbuhl if (ISSET(mp->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT)) { 20705a60fbd4Smbuhl *olinfo_status |= IGC_TXD_POPTS_IXSM << 8; 20715a60fbd4Smbuhl off = 1; 20725a60fbd4Smbuhl } 20735a60fbd4Smbuhl #ifdef INET6 2074efd8dad8Snaddy } else if (ext.ip6) { 20755a60fbd4Smbuhl type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV6; 20765a60fbd4Smbuhl #endif 20775a60fbd4Smbuhl } 20785a60fbd4Smbuhl 2079ac5f541aSbluhm vlan_macip_lens |= ext.iphlen; 20805a60fbd4Smbuhl type_tucmd_mlhl |= IGC_ADVTXD_DCMD_DEXT | IGC_ADVTXD_DTYP_CTXT; 20815a60fbd4Smbuhl 2082efd8dad8Snaddy if (ext.tcp) { 20835a60fbd4Smbuhl type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_TCP; 20845a60fbd4Smbuhl if (ISSET(mp->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) { 20855a60fbd4Smbuhl *olinfo_status |= IGC_TXD_POPTS_TXSM << 8; 20865a60fbd4Smbuhl off = 1; 20875a60fbd4Smbuhl } 2088efd8dad8Snaddy } else if (ext.udp) { 20895a60fbd4Smbuhl type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_UDP; 20905a60fbd4Smbuhl if (ISSET(mp->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) { 20915a60fbd4Smbuhl *olinfo_status |= IGC_TXD_POPTS_TXSM << 8; 20925a60fbd4Smbuhl off = 1; 20935a60fbd4Smbuhl } 20945a60fbd4Smbuhl } 20955a60fbd4Smbuhl 20962011187aSmbuhl if (ISSET(mp->m_pkthdr.csum_flags, M_TCP_TSO)) { 20977f8ccd64Sjan if (ext.tcp && mp->m_pkthdr.ph_mss > 0) { 20982011187aSmbuhl uint32_t hdrlen, thlen, paylen, outlen; 20992011187aSmbuhl 21002011187aSmbuhl thlen = ext.tcphlen; 21012011187aSmbuhl 21022011187aSmbuhl outlen = mp->m_pkthdr.ph_mss; 21032011187aSmbuhl mss_l4len_idx |= outlen << IGC_ADVTXD_MSS_SHIFT; 21042011187aSmbuhl mss_l4len_idx |= thlen << IGC_ADVTXD_L4LEN_SHIFT; 21052011187aSmbuhl 21062011187aSmbuhl hdrlen = sizeof(*ext.eh) + ext.iphlen + thlen; 21072011187aSmbuhl paylen = mp->m_pkthdr.len - hdrlen; 21082011187aSmbuhl CLR(*olinfo_status, IGC_ADVTXD_PAYLEN_MASK); 21092011187aSmbuhl *olinfo_status |= paylen << IGC_ADVTXD_PAYLEN_SHIFT; 21102011187aSmbuhl 21112011187aSmbuhl *cmd_type_len |= IGC_ADVTXD_DCMD_TSE; 21122011187aSmbuhl off = 1; 21132011187aSmbuhl 21142011187aSmbuhl tcpstat_add(tcps_outpkttso, 21152011187aSmbuhl (paylen + outlen - 1) / outlen); 21162011187aSmbuhl } else 21172011187aSmbuhl tcpstat_inc(tcps_outbadtso); 21182011187aSmbuhl } 21192011187aSmbuhl 21205a60fbd4Smbuhl if (off == 0) 21215a60fbd4Smbuhl return 0; 21225a60fbd4Smbuhl 21235a60fbd4Smbuhl /* Now ready a context descriptor */ 21245a60fbd4Smbuhl txdesc = (struct igc_adv_tx_context_desc *)&txr->tx_base[prod]; 21255a60fbd4Smbuhl 21265a60fbd4Smbuhl /* Now copy bits into descriptor */ 21275a60fbd4Smbuhl htolem32(&txdesc->vlan_macip_lens, vlan_macip_lens); 21285a60fbd4Smbuhl htolem32(&txdesc->type_tucmd_mlhl, type_tucmd_mlhl); 21295a60fbd4Smbuhl htolem32(&txdesc->seqnum_seed, 0); 21302011187aSmbuhl htolem32(&txdesc->mss_l4len_idx, mss_l4len_idx); 21315a60fbd4Smbuhl 21325a60fbd4Smbuhl return 1; 21335a60fbd4Smbuhl } 21345a60fbd4Smbuhl 213583306792Spatrick /********************************************************************* 213683306792Spatrick * 213783306792Spatrick * Allocate memory for rx_buffer structures. Since we use one 213883306792Spatrick * rx_buffer per received packet, the maximum number of rx_buffer's 213983306792Spatrick * that we'll need is equal to the number of receive descriptors 214083306792Spatrick * that we've allocated. 214183306792Spatrick * 214283306792Spatrick **********************************************************************/ 214383306792Spatrick int 2144fb54a5a4Sbluhm igc_allocate_receive_buffers(struct igc_rxring *rxr) 214583306792Spatrick { 214683306792Spatrick struct igc_softc *sc = rxr->sc; 214783306792Spatrick struct igc_rx_buf *rxbuf; 214883306792Spatrick int i, error; 214983306792Spatrick 215083306792Spatrick rxr->rx_buffers = mallocarray(sc->num_rx_desc, 215183306792Spatrick sizeof(struct igc_rx_buf), M_DEVBUF, M_NOWAIT | M_ZERO); 215283306792Spatrick if (rxr->rx_buffers == NULL) { 215383306792Spatrick printf("%s: Unable to allocate rx_buffer memory\n", 215483306792Spatrick DEVNAME(sc)); 215583306792Spatrick error = ENOMEM; 215683306792Spatrick goto fail; 215783306792Spatrick } 215883306792Spatrick 215983306792Spatrick rxbuf = rxr->rx_buffers; 216083306792Spatrick for (i = 0; i < sc->num_rx_desc; i++, rxbuf++) { 216183306792Spatrick error = bus_dmamap_create(rxr->rxdma.dma_tag, 2162*4cceae0fSdlg sc->rx_mbuf_sz, 1, sc->rx_mbuf_sz, 0, 216383306792Spatrick BUS_DMA_NOWAIT, &rxbuf->map); 216483306792Spatrick if (error) { 216583306792Spatrick printf("%s: Unable to create RX DMA map\n", 216683306792Spatrick DEVNAME(sc)); 216783306792Spatrick goto fail; 216883306792Spatrick } 216983306792Spatrick } 217083306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 0, 217183306792Spatrick rxr->rxdma.dma_map->dm_mapsize, 217283306792Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 217383306792Spatrick 217483306792Spatrick return 0; 217583306792Spatrick fail: 217683306792Spatrick return error; 217783306792Spatrick } 217883306792Spatrick 217983306792Spatrick /********************************************************************* 218083306792Spatrick * 218183306792Spatrick * Allocate and initialize receive structures. 218283306792Spatrick * 218383306792Spatrick **********************************************************************/ 218483306792Spatrick int 218583306792Spatrick igc_setup_receive_structures(struct igc_softc *sc) 218683306792Spatrick { 2187fb54a5a4Sbluhm struct igc_rxring *rxr = sc->rx_rings; 218883306792Spatrick int i; 218983306792Spatrick 219083306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, rxr++) { 219183306792Spatrick if (igc_setup_receive_ring(rxr)) 219283306792Spatrick goto fail; 219383306792Spatrick } 219483306792Spatrick 219583306792Spatrick return 0; 219683306792Spatrick fail: 219783306792Spatrick igc_free_receive_structures(sc); 219883306792Spatrick return ENOBUFS; 219983306792Spatrick } 220083306792Spatrick 220183306792Spatrick /********************************************************************* 220283306792Spatrick * 220383306792Spatrick * Initialize a receive ring and its buffers. 220483306792Spatrick * 220583306792Spatrick **********************************************************************/ 220683306792Spatrick int 2207fb54a5a4Sbluhm igc_setup_receive_ring(struct igc_rxring *rxr) 220883306792Spatrick { 220983306792Spatrick struct igc_softc *sc = rxr->sc; 221083306792Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 221183306792Spatrick int rsize; 221283306792Spatrick 221383306792Spatrick rsize = roundup2(sc->num_rx_desc * sizeof(union igc_adv_rx_desc), 221483306792Spatrick IGC_DBA_ALIGN); 221583306792Spatrick 221683306792Spatrick /* Clear the ring contents. */ 221783306792Spatrick bzero((void *)rxr->rx_base, rsize); 221883306792Spatrick 221983306792Spatrick if (igc_allocate_receive_buffers(rxr)) 222083306792Spatrick return ENOMEM; 222183306792Spatrick 222283306792Spatrick /* Setup our descriptor indices. */ 222383306792Spatrick rxr->next_to_check = 0; 222483306792Spatrick rxr->last_desc_filled = sc->num_rx_desc - 1; 222583306792Spatrick 2226*4cceae0fSdlg if_rxr_init(&rxr->rx_ring, 2227*4cceae0fSdlg 2 * howmany(ifp->if_hardmtu, sc->rx_mbuf_sz) + 1, 222883306792Spatrick sc->num_rx_desc - 1); 222983306792Spatrick 223083306792Spatrick return 0; 223183306792Spatrick } 223283306792Spatrick 223383306792Spatrick /********************************************************************* 223483306792Spatrick * 223583306792Spatrick * Enable receive unit. 223683306792Spatrick * 223783306792Spatrick **********************************************************************/ 2238cbab2262Skevlo #define BSIZEPKT_ROUNDUP ((1 << IGC_SRRCTL_BSIZEPKT_SHIFT) - 1) 2239cbab2262Skevlo 224083306792Spatrick void 224183306792Spatrick igc_initialize_receive_unit(struct igc_softc *sc) 224283306792Spatrick { 2243fb54a5a4Sbluhm struct igc_rxring *rxr = sc->rx_rings; 224483306792Spatrick struct igc_hw *hw = &sc->hw; 224583306792Spatrick uint32_t rctl, rxcsum, srrctl = 0; 224683306792Spatrick int i; 224783306792Spatrick 224883306792Spatrick /* 224983306792Spatrick * Make sure receives are disabled while setting 225083306792Spatrick * up the descriptor ring. 225183306792Spatrick */ 225283306792Spatrick rctl = IGC_READ_REG(hw, IGC_RCTL); 225383306792Spatrick IGC_WRITE_REG(hw, IGC_RCTL, rctl & ~IGC_RCTL_EN); 225483306792Spatrick 225583306792Spatrick /* Setup the Receive Control Register */ 225683306792Spatrick rctl &= ~(3 << IGC_RCTL_MO_SHIFT); 225783306792Spatrick rctl |= IGC_RCTL_EN | IGC_RCTL_BAM | IGC_RCTL_LBM_NO | 225883306792Spatrick IGC_RCTL_RDMTS_HALF | (hw->mac.mc_filter_type << IGC_RCTL_MO_SHIFT); 225983306792Spatrick 2260b88bced1Spatrick /* Do not store bad packets */ 2261b88bced1Spatrick rctl &= ~IGC_RCTL_SBP; 2262b88bced1Spatrick 226383306792Spatrick /* Enable Long Packet receive */ 226483306792Spatrick if (sc->hw.mac.max_frame_size != ETHER_MAX_LEN) 226583306792Spatrick rctl |= IGC_RCTL_LPE; 226683306792Spatrick 226783306792Spatrick /* Strip the CRC */ 226883306792Spatrick rctl |= IGC_RCTL_SECRC; 226983306792Spatrick 227083306792Spatrick /* 227183306792Spatrick * Set the interrupt throttling rate. Value is calculated 227283306792Spatrick * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) 227383306792Spatrick */ 227483306792Spatrick IGC_WRITE_REG(hw, IGC_ITR, DEFAULT_ITR); 227583306792Spatrick 227683306792Spatrick rxcsum = IGC_READ_REG(hw, IGC_RXCSUM); 227783306792Spatrick rxcsum &= ~IGC_RXCSUM_PCSD; 227883306792Spatrick 227983306792Spatrick if (sc->sc_nqueues > 1) 228083306792Spatrick rxcsum |= IGC_RXCSUM_PCSD; 228183306792Spatrick 228283306792Spatrick IGC_WRITE_REG(hw, IGC_RXCSUM, rxcsum); 228383306792Spatrick 2284b88bced1Spatrick if (sc->sc_nqueues > 1) 2285b88bced1Spatrick igc_initialize_rss_mapping(sc); 2286b88bced1Spatrick 2287cbab2262Skevlo /* Set maximum packet buffer len */ 2288cbab2262Skevlo srrctl |= (sc->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >> 2289cbab2262Skevlo IGC_SRRCTL_BSIZEPKT_SHIFT; 2290cbab2262Skevlo /* srrctl above overrides this but set the register to a sane value */ 229183306792Spatrick rctl |= IGC_RCTL_SZ_2048; 229283306792Spatrick 229383306792Spatrick /* 229483306792Spatrick * If TX flow control is disabled and there's > 1 queue defined, 229583306792Spatrick * enable DROP. 229683306792Spatrick * 229783306792Spatrick * This drops frames rather than hanging the RX MAC for all queues. 229883306792Spatrick */ 229983306792Spatrick if ((sc->sc_nqueues > 1) && (sc->fc == igc_fc_none || 230083306792Spatrick sc->fc == igc_fc_rx_pause)) { 230183306792Spatrick srrctl |= IGC_SRRCTL_DROP_EN; 230283306792Spatrick } 230383306792Spatrick 230483306792Spatrick /* Setup the Base and Length of the RX descriptor rings. */ 230583306792Spatrick for (i = 0; i < sc->sc_nqueues; i++, rxr++) { 230683306792Spatrick IGC_WRITE_REG(hw, IGC_RXDCTL(i), 0); 230783306792Spatrick uint64_t bus_addr = rxr->rxdma.dma_map->dm_segs[0].ds_addr; 230883306792Spatrick uint32_t rxdctl; 230983306792Spatrick 231083306792Spatrick srrctl |= IGC_SRRCTL_DESCTYPE_ADV_ONEBUF; 231183306792Spatrick 231283306792Spatrick IGC_WRITE_REG(hw, IGC_RDLEN(i), 231383306792Spatrick sc->num_rx_desc * sizeof(union igc_adv_rx_desc)); 231483306792Spatrick IGC_WRITE_REG(hw, IGC_RDBAH(i), (uint32_t)(bus_addr >> 32)); 231583306792Spatrick IGC_WRITE_REG(hw, IGC_RDBAL(i), (uint32_t)bus_addr); 231683306792Spatrick IGC_WRITE_REG(hw, IGC_SRRCTL(i), srrctl); 231783306792Spatrick 231883306792Spatrick /* Setup the Head and Tail Descriptor Pointers */ 231983306792Spatrick IGC_WRITE_REG(hw, IGC_RDH(i), 0); 232083306792Spatrick IGC_WRITE_REG(hw, IGC_RDT(i), 0); 232183306792Spatrick 232283306792Spatrick /* Enable this Queue */ 232383306792Spatrick rxdctl = IGC_READ_REG(hw, IGC_RXDCTL(i)); 232483306792Spatrick rxdctl |= IGC_RXDCTL_QUEUE_ENABLE; 232583306792Spatrick rxdctl &= 0xFFF00000; 232683306792Spatrick rxdctl |= IGC_RX_PTHRESH; 232783306792Spatrick rxdctl |= IGC_RX_HTHRESH << 8; 232883306792Spatrick rxdctl |= IGC_RX_WTHRESH << 16; 232983306792Spatrick IGC_WRITE_REG(hw, IGC_RXDCTL(i), rxdctl); 233083306792Spatrick } 233183306792Spatrick 233283306792Spatrick /* Make sure VLAN Filters are off */ 233383306792Spatrick rctl &= ~IGC_RCTL_VFE; 233483306792Spatrick 233583306792Spatrick /* Write out the settings */ 233683306792Spatrick IGC_WRITE_REG(hw, IGC_RCTL, rctl); 233783306792Spatrick } 233883306792Spatrick 233983306792Spatrick /********************************************************************* 234083306792Spatrick * 234183306792Spatrick * Free all receive rings. 234283306792Spatrick * 234383306792Spatrick **********************************************************************/ 234483306792Spatrick void 234583306792Spatrick igc_free_receive_structures(struct igc_softc *sc) 234683306792Spatrick { 2347fb54a5a4Sbluhm struct igc_rxring *rxr; 234883306792Spatrick int i; 234983306792Spatrick 235083306792Spatrick for (i = 0, rxr = sc->rx_rings; i < sc->sc_nqueues; i++, rxr++) 235183306792Spatrick if_rxr_init(&rxr->rx_ring, 0, 0); 235283306792Spatrick 235383306792Spatrick for (i = 0, rxr = sc->rx_rings; i < sc->sc_nqueues; i++, rxr++) 235483306792Spatrick igc_free_receive_buffers(rxr); 235583306792Spatrick } 235683306792Spatrick 235783306792Spatrick /********************************************************************* 235883306792Spatrick * 235983306792Spatrick * Free receive ring data structures 236083306792Spatrick * 236183306792Spatrick **********************************************************************/ 236283306792Spatrick void 2363fb54a5a4Sbluhm igc_free_receive_buffers(struct igc_rxring *rxr) 236483306792Spatrick { 236583306792Spatrick struct igc_softc *sc = rxr->sc; 236683306792Spatrick struct igc_rx_buf *rxbuf; 236783306792Spatrick int i; 236883306792Spatrick 236983306792Spatrick if (rxr->rx_buffers != NULL) { 237083306792Spatrick for (i = 0; i < sc->num_rx_desc; i++) { 237183306792Spatrick rxbuf = &rxr->rx_buffers[i]; 237283306792Spatrick if (rxbuf->buf != NULL) { 237383306792Spatrick bus_dmamap_sync(rxr->rxdma.dma_tag, rxbuf->map, 237483306792Spatrick 0, rxbuf->map->dm_mapsize, 237583306792Spatrick BUS_DMASYNC_POSTREAD); 237683306792Spatrick bus_dmamap_unload(rxr->rxdma.dma_tag, 237783306792Spatrick rxbuf->map); 237883306792Spatrick m_freem(rxbuf->buf); 237983306792Spatrick rxbuf->buf = NULL; 238083306792Spatrick } 238183306792Spatrick bus_dmamap_destroy(rxr->rxdma.dma_tag, rxbuf->map); 238283306792Spatrick rxbuf->map = NULL; 238383306792Spatrick } 238483306792Spatrick free(rxr->rx_buffers, M_DEVBUF, 238583306792Spatrick sc->num_rx_desc * sizeof(struct igc_rx_buf)); 238683306792Spatrick rxr->rx_buffers = NULL; 238783306792Spatrick } 238883306792Spatrick } 238983306792Spatrick 239083306792Spatrick /* 239183306792Spatrick * Initialise the RSS mapping for NICs that support multiple transmit/ 239283306792Spatrick * receive rings. 239383306792Spatrick */ 239483306792Spatrick void 239583306792Spatrick igc_initialize_rss_mapping(struct igc_softc *sc) 239683306792Spatrick { 239783306792Spatrick struct igc_hw *hw = &sc->hw; 239883306792Spatrick uint32_t rss_key[10], mrqc, reta, shift = 0; 239983306792Spatrick int i, queue_id; 240083306792Spatrick 240183306792Spatrick /* 240283306792Spatrick * The redirection table controls which destination 240383306792Spatrick * queue each bucket redirects traffic to. 240483306792Spatrick * Each DWORD represents four queues, with the LSB 240583306792Spatrick * being the first queue in the DWORD. 240683306792Spatrick * 240783306792Spatrick * This just allocates buckets to queues using round-robin 240883306792Spatrick * allocation. 240983306792Spatrick * 241083306792Spatrick * NOTE: It Just Happens to line up with the default 241183306792Spatrick * RSS allocation method. 241283306792Spatrick */ 241383306792Spatrick 241483306792Spatrick /* Warning FM follows */ 241583306792Spatrick reta = 0; 241683306792Spatrick for (i = 0; i < 128; i++) { 241783306792Spatrick queue_id = (i % sc->sc_nqueues); 241883306792Spatrick /* Adjust if required */ 241983306792Spatrick queue_id = queue_id << shift; 242083306792Spatrick 242183306792Spatrick /* 242283306792Spatrick * The low 8 bits are for hash value (n+0); 242383306792Spatrick * The next 8 bits are for hash value (n+1), etc. 242483306792Spatrick */ 242583306792Spatrick reta = reta >> 8; 242683306792Spatrick reta = reta | ( ((uint32_t) queue_id) << 24); 242783306792Spatrick if ((i & 3) == 3) { 242883306792Spatrick IGC_WRITE_REG(hw, IGC_RETA(i >> 2), reta); 242983306792Spatrick reta = 0; 243083306792Spatrick } 243183306792Spatrick } 243283306792Spatrick 243383306792Spatrick /* 243483306792Spatrick * MRQC: Multiple Receive Queues Command 243583306792Spatrick * Set queuing to RSS control, number depends on the device. 243683306792Spatrick */ 243783306792Spatrick mrqc = IGC_MRQC_ENABLE_RSS_4Q; 243883306792Spatrick 243983306792Spatrick /* Set up random bits */ 244083306792Spatrick stoeplitz_to_key(&rss_key, sizeof(rss_key)); 244183306792Spatrick 244283306792Spatrick /* Now fill our hash function seeds */ 244383306792Spatrick for (i = 0; i < 10; i++) 244483306792Spatrick IGC_WRITE_REG_ARRAY(hw, IGC_RSSRK(0), i, rss_key[i]); 244583306792Spatrick 244683306792Spatrick /* 244783306792Spatrick * Configure the RSS fields to hash upon. 244883306792Spatrick */ 244983306792Spatrick mrqc |= (IGC_MRQC_RSS_FIELD_IPV4 | IGC_MRQC_RSS_FIELD_IPV4_TCP); 245083306792Spatrick mrqc |= (IGC_MRQC_RSS_FIELD_IPV6 | IGC_MRQC_RSS_FIELD_IPV6_TCP); 245183306792Spatrick mrqc |= IGC_MRQC_RSS_FIELD_IPV6_TCP_EX; 245283306792Spatrick 245383306792Spatrick IGC_WRITE_REG(hw, IGC_MRQC, mrqc); 245483306792Spatrick } 245583306792Spatrick 245683306792Spatrick /* 245783306792Spatrick * igc_get_hw_control sets the {CTRL_EXT|FWSM}:DRV_LOAD bit. 245883306792Spatrick * For ASF and Pass Through versions of f/w this means 245983306792Spatrick * that the driver is loaded. For AMT version type f/w 246083306792Spatrick * this means that the network i/f is open. 246183306792Spatrick */ 246283306792Spatrick void 246383306792Spatrick igc_get_hw_control(struct igc_softc *sc) 246483306792Spatrick { 246583306792Spatrick uint32_t ctrl_ext; 246683306792Spatrick 246783306792Spatrick ctrl_ext = IGC_READ_REG(&sc->hw, IGC_CTRL_EXT); 246883306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_CTRL_EXT, ctrl_ext | IGC_CTRL_EXT_DRV_LOAD); 246983306792Spatrick } 247083306792Spatrick 247183306792Spatrick /* 247283306792Spatrick * igc_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit. 247383306792Spatrick * For ASF and Pass Through versions of f/w this means that 247483306792Spatrick * the driver is no longer loaded. For AMT versions of the 247583306792Spatrick * f/w this means that the network i/f is closed. 247683306792Spatrick */ 247783306792Spatrick void 247883306792Spatrick igc_release_hw_control(struct igc_softc *sc) 247983306792Spatrick { 248083306792Spatrick uint32_t ctrl_ext; 248183306792Spatrick 248283306792Spatrick ctrl_ext = IGC_READ_REG(&sc->hw, IGC_CTRL_EXT); 248383306792Spatrick IGC_WRITE_REG(&sc->hw, IGC_CTRL_EXT, ctrl_ext & ~IGC_CTRL_EXT_DRV_LOAD); 248483306792Spatrick } 248583306792Spatrick 248683306792Spatrick int 248783306792Spatrick igc_is_valid_ether_addr(uint8_t *addr) 248883306792Spatrick { 248983306792Spatrick char zero_addr[6] = { 0, 0, 0, 0, 0, 0 }; 249083306792Spatrick 249183306792Spatrick if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) { 249283306792Spatrick return 0; 249383306792Spatrick } 249483306792Spatrick 249583306792Spatrick return 1; 249683306792Spatrick } 2497bf6ccf13Sdlg 2498bf6ccf13Sdlg #if NKSTAT > 0 2499bf6ccf13Sdlg 2500bf6ccf13Sdlg /* 2501bf6ccf13Sdlg * the below are read to clear, so they need to be accumulated for 2502bf6ccf13Sdlg * userland to see counters. periodically fetch the counters from a 2503bf6ccf13Sdlg * timeout to avoid a 32 roll-over between kstat reads. 2504bf6ccf13Sdlg */ 2505bf6ccf13Sdlg 2506bf6ccf13Sdlg enum igc_stat { 2507bf6ccf13Sdlg igc_stat_crcerrs, 2508bf6ccf13Sdlg igc_stat_algnerrc, 2509bf6ccf13Sdlg igc_stat_rxerrc, 2510bf6ccf13Sdlg igc_stat_mpc, 2511bf6ccf13Sdlg igc_stat_scc, 2512bf6ccf13Sdlg igc_stat_ecol, 2513bf6ccf13Sdlg igc_stat_mcc, 2514bf6ccf13Sdlg igc_stat_latecol, 2515bf6ccf13Sdlg igc_stat_colc, 2516bf6ccf13Sdlg igc_stat_rerc, 2517bf6ccf13Sdlg igc_stat_dc, 2518bf6ccf13Sdlg igc_stat_tncrs, 2519bf6ccf13Sdlg igc_stat_htdpmc, 2520bf6ccf13Sdlg igc_stat_rlec, 2521bf6ccf13Sdlg igc_stat_xonrxc, 2522bf6ccf13Sdlg igc_stat_xontxc, 2523bf6ccf13Sdlg igc_stat_xoffrxc, 2524bf6ccf13Sdlg igc_stat_xofftxc, 2525bf6ccf13Sdlg igc_stat_fcruc, 2526bf6ccf13Sdlg igc_stat_prc64, 2527bf6ccf13Sdlg igc_stat_prc127, 2528bf6ccf13Sdlg igc_stat_prc255, 2529bf6ccf13Sdlg igc_stat_prc511, 2530bf6ccf13Sdlg igc_stat_prc1023, 2531bf6ccf13Sdlg igc_stat_prc1522, 2532bf6ccf13Sdlg igc_stat_gprc, 2533bf6ccf13Sdlg igc_stat_bprc, 2534bf6ccf13Sdlg igc_stat_mprc, 2535bf6ccf13Sdlg igc_stat_gptc, 2536bf6ccf13Sdlg igc_stat_gorc, 2537bf6ccf13Sdlg igc_stat_gotc, 2538bf6ccf13Sdlg igc_stat_rnbc, 2539bf6ccf13Sdlg igc_stat_ruc, 2540bf6ccf13Sdlg igc_stat_rfc, 2541bf6ccf13Sdlg igc_stat_roc, 2542bf6ccf13Sdlg igc_stat_rjc, 2543bf6ccf13Sdlg igc_stat_mgtprc, 2544bf6ccf13Sdlg igc_stat_mgtpdc, 2545bf6ccf13Sdlg igc_stat_mgtptc, 2546bf6ccf13Sdlg igc_stat_tor, 2547bf6ccf13Sdlg igc_stat_tot, 2548bf6ccf13Sdlg igc_stat_tpr, 2549bf6ccf13Sdlg igc_stat_tpt, 2550bf6ccf13Sdlg igc_stat_ptc64, 2551bf6ccf13Sdlg igc_stat_ptc127, 2552bf6ccf13Sdlg igc_stat_ptc255, 2553bf6ccf13Sdlg igc_stat_ptc511, 2554bf6ccf13Sdlg igc_stat_ptc1023, 2555bf6ccf13Sdlg igc_stat_ptc1522, 2556bf6ccf13Sdlg igc_stat_mptc, 2557bf6ccf13Sdlg igc_stat_bptc, 2558bf6ccf13Sdlg igc_stat_tsctc, 2559bf6ccf13Sdlg 2560bf6ccf13Sdlg igc_stat_iac, 2561bf6ccf13Sdlg igc_stat_rpthc, 2562bf6ccf13Sdlg igc_stat_tlpic, 2563bf6ccf13Sdlg igc_stat_rlpic, 2564bf6ccf13Sdlg igc_stat_hgptc, 2565bf6ccf13Sdlg igc_stat_rxdmtc, 2566bf6ccf13Sdlg igc_stat_hgorc, 2567bf6ccf13Sdlg igc_stat_hgotc, 2568bf6ccf13Sdlg igc_stat_lenerrs, 2569bf6ccf13Sdlg 2570bf6ccf13Sdlg igc_stat_count 2571bf6ccf13Sdlg }; 2572bf6ccf13Sdlg 2573bf6ccf13Sdlg struct igc_counter { 2574bf6ccf13Sdlg const char *name; 2575bf6ccf13Sdlg enum kstat_kv_unit unit; 2576bf6ccf13Sdlg uint32_t reg; 2577bf6ccf13Sdlg }; 2578bf6ccf13Sdlg 2579bf6ccf13Sdlg static const struct igc_counter igc_counters[igc_stat_count] = { 2580bf6ccf13Sdlg [igc_stat_crcerrs] = 2581bf6ccf13Sdlg { "crc errs", KSTAT_KV_U_NONE, IGC_CRCERRS }, 2582bf6ccf13Sdlg [igc_stat_algnerrc] = 2583bf6ccf13Sdlg { "alignment errs", KSTAT_KV_U_NONE, IGC_ALGNERRC }, 2584bf6ccf13Sdlg [igc_stat_rxerrc] = 2585bf6ccf13Sdlg { "rx errs", KSTAT_KV_U_NONE, IGC_RXERRC }, 2586bf6ccf13Sdlg [igc_stat_mpc] = 2587bf6ccf13Sdlg { "missed pkts", KSTAT_KV_U_NONE, IGC_MPC }, 2588bf6ccf13Sdlg [igc_stat_scc] = 2589bf6ccf13Sdlg { "single colls", KSTAT_KV_U_NONE, IGC_SCC }, 2590bf6ccf13Sdlg [igc_stat_ecol] = 2591bf6ccf13Sdlg { "excessive colls", KSTAT_KV_U_NONE, IGC_ECOL }, 2592bf6ccf13Sdlg [igc_stat_mcc] = 2593bf6ccf13Sdlg { "multiple colls", KSTAT_KV_U_NONE, IGC_MCC }, 2594bf6ccf13Sdlg [igc_stat_latecol] = 2595bf6ccf13Sdlg { "late colls", KSTAT_KV_U_NONE, IGC_LATECOL }, 2596bf6ccf13Sdlg [igc_stat_colc] = 2597bf6ccf13Sdlg { "collisions", KSTAT_KV_U_NONE, IGC_COLC }, 2598bf6ccf13Sdlg [igc_stat_rerc] = 2599bf6ccf13Sdlg { "recv errs", KSTAT_KV_U_NONE, IGC_RERC }, 2600bf6ccf13Sdlg [igc_stat_dc] = 2601bf6ccf13Sdlg { "defers", KSTAT_KV_U_NONE, IGC_DC }, 2602bf6ccf13Sdlg [igc_stat_tncrs] = 2603bf6ccf13Sdlg { "tx no crs", KSTAT_KV_U_NONE, IGC_TNCRS}, 2604bf6ccf13Sdlg [igc_stat_htdpmc] = 2605bf6ccf13Sdlg { "host tx discards", KSTAT_KV_U_NONE, IGC_HTDPMC }, 2606bf6ccf13Sdlg [igc_stat_rlec] = 2607bf6ccf13Sdlg { "recv len errs", KSTAT_KV_U_NONE, IGC_RLEC }, 2608bf6ccf13Sdlg [igc_stat_xonrxc] = 2609bf6ccf13Sdlg { "xon rx", KSTAT_KV_U_NONE, IGC_XONRXC }, 2610bf6ccf13Sdlg [igc_stat_xontxc] = 2611bf6ccf13Sdlg { "xon tx", KSTAT_KV_U_NONE, IGC_XONTXC }, 2612bf6ccf13Sdlg [igc_stat_xoffrxc] = 2613bf6ccf13Sdlg { "xoff rx", KSTAT_KV_U_NONE, IGC_XOFFRXC }, 2614bf6ccf13Sdlg [igc_stat_xofftxc] = 2615bf6ccf13Sdlg { "xoff tx", KSTAT_KV_U_NONE, IGC_XOFFTXC }, 2616bf6ccf13Sdlg [igc_stat_fcruc] = 2617bf6ccf13Sdlg { "fc rx unsupp", KSTAT_KV_U_NONE, IGC_FCRUC }, 2618bf6ccf13Sdlg [igc_stat_prc64] = 2619bf6ccf13Sdlg { "rx 64B", KSTAT_KV_U_PACKETS, IGC_PRC64 }, 2620bf6ccf13Sdlg [igc_stat_prc127] = 2621bf6ccf13Sdlg { "rx 65-127B", KSTAT_KV_U_PACKETS, IGC_PRC127 }, 2622bf6ccf13Sdlg [igc_stat_prc255] = 2623bf6ccf13Sdlg { "rx 128-255B", KSTAT_KV_U_PACKETS, IGC_PRC255 }, 2624bf6ccf13Sdlg [igc_stat_prc511] = 2625bf6ccf13Sdlg { "rx 256-511B", KSTAT_KV_U_PACKETS, IGC_PRC511 }, 2626bf6ccf13Sdlg [igc_stat_prc1023] = 2627bf6ccf13Sdlg { "rx 512-1023B", KSTAT_KV_U_PACKETS, IGC_PRC1023 }, 2628bf6ccf13Sdlg [igc_stat_prc1522] = 2629bf6ccf13Sdlg { "rx 1024-maxB", KSTAT_KV_U_PACKETS, IGC_PRC1522 }, 2630bf6ccf13Sdlg [igc_stat_gprc] = 2631bf6ccf13Sdlg { "rx good", KSTAT_KV_U_PACKETS, IGC_GPRC }, 2632bf6ccf13Sdlg [igc_stat_bprc] = 2633bf6ccf13Sdlg { "rx bcast", KSTAT_KV_U_PACKETS, IGC_BPRC }, 2634bf6ccf13Sdlg [igc_stat_mprc] = 2635bf6ccf13Sdlg { "rx mcast", KSTAT_KV_U_PACKETS, IGC_MPRC }, 2636bf6ccf13Sdlg [igc_stat_gptc] = 2637bf6ccf13Sdlg { "tx good", KSTAT_KV_U_PACKETS, IGC_GPTC }, 2638bf6ccf13Sdlg [igc_stat_gorc] = 2639bf6ccf13Sdlg { "rx good bytes", KSTAT_KV_U_BYTES, 0 }, 2640bf6ccf13Sdlg [igc_stat_gotc] = 2641bf6ccf13Sdlg { "tx good bytes", KSTAT_KV_U_BYTES, 0 }, 2642bf6ccf13Sdlg [igc_stat_rnbc] = 2643bf6ccf13Sdlg { "rx no bufs", KSTAT_KV_U_NONE, IGC_RNBC }, 2644bf6ccf13Sdlg [igc_stat_ruc] = 2645bf6ccf13Sdlg { "rx undersize", KSTAT_KV_U_NONE, IGC_RUC }, 2646bf6ccf13Sdlg [igc_stat_rfc] = 2647bf6ccf13Sdlg { "rx frags", KSTAT_KV_U_NONE, IGC_RFC }, 2648bf6ccf13Sdlg [igc_stat_roc] = 2649bf6ccf13Sdlg { "rx oversize", KSTAT_KV_U_NONE, IGC_ROC }, 2650bf6ccf13Sdlg [igc_stat_rjc] = 2651bf6ccf13Sdlg { "rx jabbers", KSTAT_KV_U_NONE, IGC_RJC }, 2652bf6ccf13Sdlg [igc_stat_mgtprc] = 2653bf6ccf13Sdlg { "rx mgmt", KSTAT_KV_U_PACKETS, IGC_MGTPRC }, 2654bf6ccf13Sdlg [igc_stat_mgtpdc] = 2655bf6ccf13Sdlg { "rx mgmt drops", KSTAT_KV_U_PACKETS, IGC_MGTPDC }, 2656bf6ccf13Sdlg [igc_stat_mgtptc] = 2657bf6ccf13Sdlg { "tx mgmt", KSTAT_KV_U_PACKETS, IGC_MGTPTC }, 2658bf6ccf13Sdlg [igc_stat_tor] = 2659bf6ccf13Sdlg { "rx total bytes", KSTAT_KV_U_BYTES, 0 }, 2660bf6ccf13Sdlg [igc_stat_tot] = 2661bf6ccf13Sdlg { "tx total bytes", KSTAT_KV_U_BYTES, 0 }, 2662bf6ccf13Sdlg [igc_stat_tpr] = 2663bf6ccf13Sdlg { "rx total", KSTAT_KV_U_PACKETS, IGC_TPR }, 2664bf6ccf13Sdlg [igc_stat_tpt] = 2665bf6ccf13Sdlg { "tx total", KSTAT_KV_U_PACKETS, IGC_TPT }, 2666bf6ccf13Sdlg [igc_stat_ptc64] = 2667bf6ccf13Sdlg { "tx 64B", KSTAT_KV_U_PACKETS, IGC_PTC64 }, 2668bf6ccf13Sdlg [igc_stat_ptc127] = 2669bf6ccf13Sdlg { "tx 65-127B", KSTAT_KV_U_PACKETS, IGC_PTC127 }, 2670bf6ccf13Sdlg [igc_stat_ptc255] = 2671bf6ccf13Sdlg { "tx 128-255B", KSTAT_KV_U_PACKETS, IGC_PTC255 }, 2672bf6ccf13Sdlg [igc_stat_ptc511] = 2673bf6ccf13Sdlg { "tx 256-511B", KSTAT_KV_U_PACKETS, IGC_PTC511 }, 2674bf6ccf13Sdlg [igc_stat_ptc1023] = 2675bf6ccf13Sdlg { "tx 512-1023B", KSTAT_KV_U_PACKETS, IGC_PTC1023 }, 2676bf6ccf13Sdlg [igc_stat_ptc1522] = 2677bf6ccf13Sdlg { "tx 1024-maxB", KSTAT_KV_U_PACKETS, IGC_PTC1522 }, 2678bf6ccf13Sdlg [igc_stat_mptc] = 2679bf6ccf13Sdlg { "tx mcast", KSTAT_KV_U_PACKETS, IGC_MPTC }, 2680bf6ccf13Sdlg [igc_stat_bptc] = 2681bf6ccf13Sdlg { "tx bcast", KSTAT_KV_U_PACKETS, IGC_BPTC }, 2682bf6ccf13Sdlg [igc_stat_tsctc] = 2683bf6ccf13Sdlg { "tx tso ctx", KSTAT_KV_U_NONE, IGC_TSCTC }, 2684bf6ccf13Sdlg 2685bf6ccf13Sdlg [igc_stat_iac] = 2686bf6ccf13Sdlg { "interrupts", KSTAT_KV_U_NONE, IGC_IAC }, 2687bf6ccf13Sdlg [igc_stat_rpthc] = 2688bf6ccf13Sdlg { "rx to host", KSTAT_KV_U_PACKETS, IGC_RPTHC }, 2689bf6ccf13Sdlg [igc_stat_tlpic] = 2690bf6ccf13Sdlg { "eee tx lpi", KSTAT_KV_U_NONE, IGC_TLPIC }, 2691bf6ccf13Sdlg [igc_stat_rlpic] = 2692bf6ccf13Sdlg { "eee rx lpi", KSTAT_KV_U_NONE, IGC_RLPIC }, 2693bf6ccf13Sdlg [igc_stat_hgptc] = 2694bf6ccf13Sdlg { "host rx", KSTAT_KV_U_PACKETS, IGC_HGPTC }, 2695bf6ccf13Sdlg [igc_stat_rxdmtc] = 2696bf6ccf13Sdlg { "rxd min thresh", KSTAT_KV_U_NONE, IGC_RXDMTC }, 2697bf6ccf13Sdlg [igc_stat_hgorc] = 2698bf6ccf13Sdlg { "host good rx", KSTAT_KV_U_BYTES, 0 }, 2699bf6ccf13Sdlg [igc_stat_hgotc] = 2700bf6ccf13Sdlg { "host good tx", KSTAT_KV_U_BYTES, 0 }, 2701bf6ccf13Sdlg [igc_stat_lenerrs] = 2702bf6ccf13Sdlg { "len errs", KSTAT_KV_U_NONE, IGC_LENERRS }, 2703bf6ccf13Sdlg }; 2704bf6ccf13Sdlg 2705bf6ccf13Sdlg static void 2706bf6ccf13Sdlg igc_stat_read(struct igc_softc *sc) 2707bf6ccf13Sdlg { 2708bf6ccf13Sdlg struct igc_hw *hw = &sc->hw; 2709bf6ccf13Sdlg struct kstat *ks = sc->ks; 2710bf6ccf13Sdlg struct kstat_kv *kvs = ks->ks_data; 2711bf6ccf13Sdlg uint32_t hi, lo; 2712bf6ccf13Sdlg unsigned int i; 2713bf6ccf13Sdlg 2714bf6ccf13Sdlg for (i = 0; i < nitems(igc_counters); i++) { 2715bf6ccf13Sdlg const struct igc_counter *c = &igc_counters[i]; 2716bf6ccf13Sdlg if (c->reg == 0) 2717bf6ccf13Sdlg continue; 2718bf6ccf13Sdlg 2719bf6ccf13Sdlg kstat_kv_u64(&kvs[i]) += IGC_READ_REG(hw, c->reg); 2720bf6ccf13Sdlg } 2721bf6ccf13Sdlg 2722bf6ccf13Sdlg lo = IGC_READ_REG(hw, IGC_GORCL); 2723bf6ccf13Sdlg hi = IGC_READ_REG(hw, IGC_GORCH); 2724bf6ccf13Sdlg kstat_kv_u64(&kvs[igc_stat_gorc]) += 2725bf6ccf13Sdlg ((uint64_t)hi << 32) | ((uint64_t)lo << 0); 2726bf6ccf13Sdlg 2727bf6ccf13Sdlg lo = IGC_READ_REG(hw, IGC_GOTCL); 2728bf6ccf13Sdlg hi = IGC_READ_REG(hw, IGC_GOTCH); 2729bf6ccf13Sdlg kstat_kv_u64(&kvs[igc_stat_gotc]) += 2730bf6ccf13Sdlg ((uint64_t)hi << 32) | ((uint64_t)lo << 0); 2731bf6ccf13Sdlg 2732bf6ccf13Sdlg lo = IGC_READ_REG(hw, IGC_TORL); 2733bf6ccf13Sdlg hi = IGC_READ_REG(hw, IGC_TORH); 2734bf6ccf13Sdlg kstat_kv_u64(&kvs[igc_stat_tor]) += 2735bf6ccf13Sdlg ((uint64_t)hi << 32) | ((uint64_t)lo << 0); 2736bf6ccf13Sdlg 2737bf6ccf13Sdlg lo = IGC_READ_REG(hw, IGC_TOTL); 2738bf6ccf13Sdlg hi = IGC_READ_REG(hw, IGC_TOTH); 2739bf6ccf13Sdlg kstat_kv_u64(&kvs[igc_stat_tot]) += 2740bf6ccf13Sdlg ((uint64_t)hi << 32) | ((uint64_t)lo << 0); 2741bf6ccf13Sdlg 2742bf6ccf13Sdlg lo = IGC_READ_REG(hw, IGC_HGORCL); 2743bf6ccf13Sdlg hi = IGC_READ_REG(hw, IGC_HGORCH); 2744bf6ccf13Sdlg kstat_kv_u64(&kvs[igc_stat_hgorc]) += 2745bf6ccf13Sdlg ((uint64_t)hi << 32) | ((uint64_t)lo << 0); 2746bf6ccf13Sdlg 2747bf6ccf13Sdlg lo = IGC_READ_REG(hw, IGC_HGOTCL); 2748bf6ccf13Sdlg hi = IGC_READ_REG(hw, IGC_HGOTCH); 2749bf6ccf13Sdlg kstat_kv_u64(&kvs[igc_stat_hgotc]) += 2750bf6ccf13Sdlg ((uint64_t)hi << 32) | ((uint64_t)lo << 0); 2751bf6ccf13Sdlg } 2752bf6ccf13Sdlg 2753bf6ccf13Sdlg static void 2754bf6ccf13Sdlg igc_kstat_tick(void *arg) 2755bf6ccf13Sdlg { 2756bf6ccf13Sdlg struct igc_softc *sc = arg; 2757bf6ccf13Sdlg 2758bf6ccf13Sdlg if (mtx_enter_try(&sc->ks_mtx)) { 2759bf6ccf13Sdlg igc_stat_read(sc); 2760bf6ccf13Sdlg mtx_leave(&sc->ks_mtx); 2761bf6ccf13Sdlg } 2762bf6ccf13Sdlg 2763bf6ccf13Sdlg timeout_add_sec(&sc->ks_tmo, 4); 2764bf6ccf13Sdlg } 2765bf6ccf13Sdlg 2766bf6ccf13Sdlg static int 2767bf6ccf13Sdlg igc_kstat_read(struct kstat *ks) 2768bf6ccf13Sdlg { 2769bf6ccf13Sdlg struct igc_softc *sc = ks->ks_softc; 2770bf6ccf13Sdlg 2771bf6ccf13Sdlg igc_stat_read(sc); 2772bf6ccf13Sdlg nanouptime(&ks->ks_updated); 2773bf6ccf13Sdlg 2774bf6ccf13Sdlg return (0); 2775bf6ccf13Sdlg } 2776bf6ccf13Sdlg 2777bf6ccf13Sdlg void 2778bf6ccf13Sdlg igc_kstat_attach(struct igc_softc *sc) 2779bf6ccf13Sdlg { 2780bf6ccf13Sdlg struct kstat *ks; 2781bf6ccf13Sdlg struct kstat_kv *kvs; 2782bf6ccf13Sdlg size_t len; 2783bf6ccf13Sdlg unsigned int i; 2784bf6ccf13Sdlg 2785bf6ccf13Sdlg mtx_init(&sc->ks_mtx, IPL_SOFTCLOCK); 2786bf6ccf13Sdlg timeout_set(&sc->ks_tmo, igc_kstat_tick, sc); 2787bf6ccf13Sdlg 2788bf6ccf13Sdlg kvs = mallocarray(sizeof(*kvs), nitems(igc_counters), M_DEVBUF, 2789bf6ccf13Sdlg M_WAITOK|M_ZERO|M_CANFAIL); 2790bf6ccf13Sdlg if (kvs == NULL) { 2791bf6ccf13Sdlg printf("%s: unable to allocate igc kstats\n", DEVNAME(sc)); 2792bf6ccf13Sdlg return; 2793bf6ccf13Sdlg } 2794bf6ccf13Sdlg len = sizeof(*kvs) * nitems(igc_counters); 2795bf6ccf13Sdlg 2796bf6ccf13Sdlg ks = kstat_create(DEVNAME(sc), 0, "igc-stats", 0, KSTAT_T_KV, 0); 2797bf6ccf13Sdlg if (ks == NULL) { 2798bf6ccf13Sdlg printf("%s: unable to create igc kstats\n", DEVNAME(sc)); 2799bf6ccf13Sdlg free(kvs, M_DEVBUF, len); 2800bf6ccf13Sdlg return; 2801bf6ccf13Sdlg } 2802bf6ccf13Sdlg 2803bf6ccf13Sdlg for (i = 0; i < nitems(igc_counters); i++) { 2804bf6ccf13Sdlg const struct igc_counter *c = &igc_counters[i]; 2805bf6ccf13Sdlg kstat_kv_unit_init(&kvs[i], c->name, 2806bf6ccf13Sdlg KSTAT_KV_T_COUNTER64, c->unit); 2807bf6ccf13Sdlg } 2808bf6ccf13Sdlg 2809bf6ccf13Sdlg ks->ks_softc = sc; 2810bf6ccf13Sdlg ks->ks_data = kvs; 2811bf6ccf13Sdlg ks->ks_datalen = len; 2812bf6ccf13Sdlg ks->ks_read = igc_kstat_read; 2813bf6ccf13Sdlg kstat_set_mutex(ks, &sc->ks_mtx); 2814bf6ccf13Sdlg 2815bf6ccf13Sdlg kstat_install(ks); 2816bf6ccf13Sdlg 2817bf6ccf13Sdlg sc->ks = ks; 2818bf6ccf13Sdlg 2819bf6ccf13Sdlg igc_kstat_tick(sc); /* let's gooo */ 2820bf6ccf13Sdlg } 2821bf6ccf13Sdlg #endif /* NKSTAT > 0 */ 2822