diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-06-08 20:01:03 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-06-08 20:01:03 +0000 |
commit | 7d829f821d596d1784575f3740d354527557e722 (patch) | |
tree | e473299c37fe2daa61ec12eb7b8dffb64d3cb134 | |
parent | ffabbf45d32e0e779da43c25ca02243b38e5b19f (diff) |
Import ix, a driver for the Intel 82598 PCI-Express 10 Gig Ethernet Adapter,
based on Intel's ixgbe driver.
Done on borrowed hardware since Intel was too poor to give us a card.
ok deraadt@
-rw-r--r-- | sys/dev/pci/files.pci | 10 | ||||
-rw-r--r-- | sys/dev/pci/if_ix.c | 3443 | ||||
-rw-r--r-- | sys/dev/pci/if_ix.h | 312 | ||||
-rw-r--r-- | sys/dev/pci/ixgbe.c | 1851 | ||||
-rw-r--r-- | sys/dev/pci/ixgbe.h | 236 | ||||
-rw-r--r-- | sys/dev/pci/ixgbe_82598.c | 1116 | ||||
-rw-r--r-- | sys/dev/pci/ixgbe_phy.c | 671 | ||||
-rw-r--r-- | sys/dev/pci/ixgbe_type.h | 1559 |
8 files changed, 9197 insertions, 1 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 3b53dccad52..1df012e89ad 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.253 2008/05/07 02:31:01 krw Exp $ +# $OpenBSD: files.pci,v 1.254 2008/06/08 20:01:02 reyk Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -355,6 +355,14 @@ file dev/pci/if_ixgb.c ixgb file dev/pci/ixgb_ee.c ixgb file dev/pci/ixgb_hw.c ixgb +# Intel 82598 10GbE +device ix: ether, ifnet, ifmedia +attach ix at pci +file dev/pci/if_ix.c ix +file dev/pci/ixgbe.c ix +file dev/pci/ixgbe_82598.c ix +file dev/pci/ixgbe_phy.c ix + # Neterion Xframe 10 Gigabit ethernet device xge: ether, ifnet, ifmedia attach xge at pci diff --git a/sys/dev/pci/if_ix.c b/sys/dev/pci/if_ix.c new file mode 100644 index 00000000000..21318c1e697 --- /dev/null +++ b/sys/dev/pci/if_ix.c @@ -0,0 +1,3443 @@ +/* $OpenBSD: if_ix.c,v 1.1 2008/06/08 20:01:02 reyk Exp $ */ + +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD: src/sys/dev/ixgbe/ixgbe.c,v 1.5 2008/05/16 18:46:30 jfv Exp $*/ + +#include <dev/pci/if_ix.h> + +/********************************************************************* + * Driver version + *********************************************************************/ + +#define IXGBE_DRIVER_VERSION "1.4.4" + +/********************************************************************* + * PCI Device ID Table + * + * Used by probe to select devices to load on + *********************************************************************/ + +const struct pci_matchid ixgbe_devices[] = { + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598AF_DUAL }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598AF }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598AT_DUAL }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598EB_CX4 }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598EB_CX4_DUAL }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598EB_XF_LR }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598AT } +}; + +/********************************************************************* + * Function prototypes + *********************************************************************/ +int ixgbe_probe(struct device *, void *, void *); +void ixgbe_attach(struct device *, struct device *, void *); +int ixgbe_detach(struct device *, int); +void ixgbe_power(int, void *); +void ixgbe_shutdown(void *); +void ixgbe_start(struct ifnet *); +void ixgbe_start_locked(struct tx_ring *, struct ifnet *); +int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); +void ixgbe_watchdog(struct ifnet *); +void ixgbe_init(void *); +void ixgbe_stop(void *); +void ixgbe_media_status(struct ifnet *, struct ifmediareq *); +int ixgbe_media_change(struct ifnet *); +void ixgbe_identify_hardware(struct ix_softc *); +int ixgbe_allocate_pci_resources(struct ix_softc *); +int ixgbe_allocate_legacy(struct ix_softc *); +int ixgbe_allocate_queues(struct ix_softc *); +void ixgbe_free_pci_resources(struct ix_softc *); +void ixgbe_local_timer(void *); +int ixgbe_hardware_init(struct ix_softc *); +void ixgbe_setup_interface(struct ix_softc *); + +int ixgbe_allocate_transmit_buffers(struct tx_ring *); +int ixgbe_setup_transmit_structures(struct ix_softc *); +void ixgbe_setup_transmit_ring(struct tx_ring *); +void ixgbe_initialize_transmit_units(struct ix_softc *); +void ixgbe_free_transmit_structures(struct ix_softc *); +void ixgbe_free_transmit_buffers(struct tx_ring *); + +int ixgbe_allocate_receive_buffers(struct rx_ring *); +int ixgbe_setup_receive_structures(struct ix_softc *); +int ixgbe_setup_receive_ring(struct rx_ring *); +void ixgbe_initialize_receive_units(struct ix_softc *); +void ixgbe_free_receive_structures(struct ix_softc *); +void ixgbe_free_receive_buffers(struct rx_ring *); + +void ixgbe_enable_intr(struct ix_softc *); +void ixgbe_disable_intr(struct ix_softc *); +void ixgbe_update_stats_counters(struct ix_softc *); +bool ixgbe_txeof(struct tx_ring *); +bool ixgbe_rxeof(struct rx_ring *, int); +void ixgbe_rx_checksum(struct ix_softc *, u32, struct mbuf *); +void ixgbe_set_promisc(struct ix_softc *); +void ixgbe_disable_promisc(struct ix_softc *); +void ixgbe_set_multi(struct ix_softc *); +#ifdef IX_DEBUG +void ixgbe_print_hw_stats(struct ix_softc *); +#endif +void ixgbe_update_link_status(struct ix_softc *); +int ixgbe_get_buf(struct rx_ring *, int, struct mbuf *); +int ixgbe_encap(struct tx_ring *, struct mbuf *); +#if NVLAN > 0 +void ixgbe_enable_hw_vlans(struct ix_softc * sc); +#endif +#if 0 +void ixgbe_print_debug_info(struct ix_softc *); +int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS); +#endif +int ixgbe_dma_malloc(struct ix_softc *, bus_size_t, + struct ixgbe_dma_alloc *, int); +void ixgbe_dma_free(struct ix_softc *, struct ixgbe_dma_alloc *); +#ifdef IX_CSUM_OFFLOAD +boolean_t ixgbe_tx_ctx_setup(struct tx_ring *, struct mbuf *); +boolean_t ixgbe_tso_setup(struct tx_ring *, struct mbuf *, u32 *); +#endif +void ixgbe_set_ivar(struct ix_softc *, u16, u8); +void ixgbe_configure_ivars(struct ix_softc *); +u8 *ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); + +/* Legacy (single vector interrupt handler */ +int ixgbe_legacy_irq(void *); + +#if 0 +/* The MSI/X Interrupt handlers */ +int ixgbe_allocate_msix(struct ix_softc *); +int ixgbe_setup_msix(struct ix_softc *); +void ixgbe_msix_tx(void *); +void ixgbe_msix_rx(void *); +void ixgbe_msix_link(void *); +#endif + +#ifndef NO_82598_A0_SUPPORT +void desc_flip(void *); +#endif + +/********************************************************************* + * OpenBSD Device Interface Entry Points + *********************************************************************/ + +struct cfdriver ix_cd = { + 0, "ix", DV_IFNET +}; + +struct cfattach ix_ca = { + sizeof(struct ix_softc), ixgbe_probe, ixgbe_attach, ixgbe_detach +}; + +/* Total number of Interfaces - need for config sanity check */ +static int ixgbe_total_ports; + +/********************************************************************* + * Device identification routine + * + * ixgbe_probe determines if the driver should be loaded on + * sc based on PCI vendor/device id of the sc. + * + * return 0 on success, positive on failure + *********************************************************************/ + +int +ixgbe_probe(struct device *parent, void *match, void *aux) +{ + INIT_DEBUGOUT("ixgbe_probe: begin"); + + return (pci_matchbyid((struct pci_attach_args *)aux, ixgbe_devices, + sizeof(ixgbe_devices)/sizeof(ixgbe_devices[0]))); +} + +/********************************************************************* + * Device initialization routine + * + * The attach entry point is called when the driver is being loaded. + * This routine identifies the type of hardware, allocates all resources + * and initializes the hardware. + * + * return 0 on success, positive on failure + *********************************************************************/ + +void +ixgbe_attach(struct device *parent, struct device *self, void *aux) +{ + struct pci_attach_args *pa = (struct pci_attach_args *)aux; + struct ix_softc *sc = (struct ix_softc *)self; + int error = 0; + u32 ctrl_ext; + + INIT_DEBUGOUT("ixgbe_attach: begin"); + + sc->osdep.os_sc = sc; + sc->osdep.os_pa = pa; + + /* Core Lock Init*/ + mtx_init(&sc->core_mtx, IPL_NET); + + /* Set up the timer callout */ + timeout_set(&sc->timer, ixgbe_local_timer, sc); + + /* Determine hardware revision */ + ixgbe_identify_hardware(sc); + + /* Indicate to RX setup to use Jumbo Clusters */ + sc->bigbufs = FALSE; + sc->num_tx_desc = DEFAULT_TXD; + sc->num_rx_desc = DEFAULT_RXD; + sc->rx_process_limit = 100; // XXX + + /* Do base PCI setup - map BAR0 */ + if (ixgbe_allocate_pci_resources(sc)) { + printf(": allocation of PCI resources failed\n"); + goto err_out; + } + + /* Allocate our TX/RX Queues */ + if (ixgbe_allocate_queues(sc)) + goto err_out; + + /* Initialize the shared code */ + sc->hw.mac.type = ixgbe_mac_82598EB; + if (ixgbe_init_ops_82598(&sc->hw) != 0) { + printf(": failed to init the 82598EB\n"); + goto err_late; + } + + /* Initialize the hardware */ + if (ixgbe_hardware_init(sc)) { + printf(": unable to initialize the hardware\n"); + goto err_late; + } + + /* XXX sc->msix > 1 && ixgbe_allocate_msix() */ + error = ixgbe_allocate_legacy(sc); + if (error) + goto err_late; + + /* Setup OS specific network interface */ + ixgbe_setup_interface(sc); + + /* Initialize statistics */ + ixgbe_update_stats_counters(sc); + + /* let hardware know driver is loaded */ + ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; + IXGBE_WRITE_REG(&sc->hw, IXGBE_CTRL_EXT, ctrl_ext); + + sc->powerhook = powerhook_establish(ixgbe_power, sc); + sc->shutdownhook = shutdownhook_establish(ixgbe_shutdown, sc); + + printf(", address %s\n", ether_sprintf(sc->hw.mac.addr)); + + INIT_DEBUGOUT("ixgbe_attach: end"); + return; + +err_late: + ixgbe_free_transmit_structures(sc); + ixgbe_free_receive_structures(sc); +err_out: + ixgbe_free_pci_resources(sc); +} + +/********************************************************************* + * Device removal routine + * + * The detach entry point is called when the driver is being removed. + * This routine stops the sc and deallocates all the resources + * that were allocated for driver operation. + * + * return 0 on success, positive on failure + *********************************************************************/ + +int +ixgbe_detach(struct device *self, int flags) +{ + struct ix_softc *sc = (struct ix_softc *)self; + struct ifnet *ifp = &sc->arpcom.ac_if; + u32 ctrl_ext; + + INIT_DEBUGOUT("ixgbe_detach: begin"); + + ixgbe_stop(sc); + + /* let hardware know driver is unloading */ + ctrl_ext = IXGBE_READ_REG(&sc->hw, IXGBE_CTRL_EXT); + ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; + IXGBE_WRITE_REG(&sc->hw, IXGBE_CTRL_EXT, ctrl_ext); + + ether_ifdetach(ifp); + if_detach(ifp); + + timeout_del(&sc->timer); + ixgbe_free_pci_resources(sc); + + ixgbe_free_transmit_structures(sc); + ixgbe_free_receive_structures(sc); + + return (0); +} + +void +ixgbe_power(int why, void *arg) +{ + struct ix_softc *sc = (struct ix_softc *)arg; + struct ifnet *ifp; + + if (why == PWR_RESUME) { + ifp = &sc->arpcom.ac_if; + if (ifp->if_flags & IFF_UP) + ixgbe_init(sc); + } +} + +/********************************************************************* + * + * Shutdown entry point + * + **********************************************************************/ + +void +ixgbe_shutdown(void *arg) +{ + struct ix_softc *sc = (struct ix_softc *)arg; + + ixgbe_stop(sc); +} + +/********************************************************************* + * Transmit entry point + * + * ixgbe_start is called by the stack to initiate a transmit. + * The driver will remain in this routine as long as there are + * packets to transmit and transmit resources are available. + * In case resources are not available stack is notified and + * the packet is requeued. + **********************************************************************/ + +void +ixgbe_start_locked(struct tx_ring *txr, struct ifnet * ifp) +{ + struct mbuf *m_head; + struct ix_softc *sc = txr->sc; + + if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) + return; + + if (!sc->link_active) + return; + + for (;;) { + IFQ_POLL(&ifp->if_snd, m_head); + + if (m_head == NULL) + break; + + if (ixgbe_encap(txr, m_head)) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + + IFQ_DEQUEUE(&ifp->if_snd, m_head); + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); +#endif + + /* Set timeout in case hardware has problems transmitting */ + txr->watchdog_timer = IXGBE_TX_TIMEOUT; + ifp->if_timer = IXGBE_TX_TIMEOUT; + } + return; +} + + +void +ixgbe_start(struct ifnet *ifp) +{ + struct ix_softc *sc = ifp->if_softc; + struct tx_ring *txr = sc->tx_rings; + u32 queue = 0; + +#if 0 + /* + * This is really just here for testing + * TX multiqueue, ultimately what is + * needed is the flow support in the stack + * and appropriate logic here to deal with + * it. -jfv + */ + if (sc->num_tx_queues > 1) + queue = (curcpu % sc->num_tx_queues); +#endif + + txr = &sc->tx_rings[queue]; + + if (ifp->if_flags & IFF_RUNNING) + ixgbe_start_locked(txr, ifp); + + return; +} + +/********************************************************************* + * Ioctl entry point + * + * ixgbe_ioctl is called when the user wants to configure the + * interface. + * + * return 0 on success, positive on failure + **********************************************************************/ + +int +ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) +{ + int s, error = 0; + struct ifreq *ifr = (struct ifreq *) data; + struct ifaddr *ifa = (struct ifaddr *) data; + struct ix_softc *sc = ifp->if_softc; + + s = splnet(); + + if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) { + splx(s); + return (error); + } + + switch (command) { + case SIOCSIFADDR: + IOCTL_DEBUGOUT("ioctl: SIOCxIFADDR (Get/Set Interface Addr)"); + ifp->if_flags |= IFF_UP; + if (!(ifp->if_flags & IFF_RUNNING)) + ixgbe_init(sc); +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) + arp_ifinit(&sc->arpcom, ifa); +#endif + break; + case SIOCSIFMTU: + IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); + if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu) + error = EINVAL; + else if (ifp->if_mtu != ifr->ifr_mtu) { + ifp->if_mtu = ifr->ifr_mtu; + sc->max_frame_size = + ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + ixgbe_init(sc); + } + break; + case SIOCSIFFLAGS: + IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_flags & IFF_RUNNING)) { + if ((ifp->if_flags ^ sc->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) { + ixgbe_disable_promisc(sc); + ixgbe_set_promisc(sc); + } + } else + ixgbe_init(sc); + } else + if (ifp->if_flags & IFF_RUNNING) + ixgbe_stop(sc); + sc->if_flags = ifp->if_flags; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); + error = (command == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->arpcom) : + ether_delmulti(ifr, &sc->arpcom); + + if (error == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) { + ixgbe_disable_intr(sc); + ixgbe_set_multi(sc); + ixgbe_enable_intr(sc); + } + error = 0; + } + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); + error = ifmedia_ioctl(ifp, ifr, &sc->media, command); + break; + default: + IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); + error = ENOTTY; + break; + } + + splx(s); + return (error); +} + +/********************************************************************* + * Watchdog entry point + * + * This routine is called by the local timer + * to detect hardware hangs . + * + **********************************************************************/ + +void +ixgbe_watchdog(struct ifnet * ifp) +{ + struct ix_softc *sc = (struct ix_softc *)ifp->if_softc; + struct tx_ring *txr = sc->tx_rings; + struct ixgbe_hw *hw = &sc->hw; + bool tx_hang = FALSE; + int i; + + /* + * The timer is set to 5 every time ixgbe_start() queues a packet. + * Then ixgbe_txeof() keeps resetting to 5 as long as it cleans at + * least one descriptor. + * Finally, anytime all descriptors are clean the timer is + * set to 0. + */ + for (i = 0; i < sc->num_tx_queues; i++, txr++) { + if (txr->watchdog_timer == 0 || --txr->watchdog_timer) + continue; + else { + tx_hang = TRUE; + break; + } + } + if (tx_hang == FALSE) + return; + + /* + * If we are in this routine because of pause frames, then don't + * reset the hardware. + */ + if (IXGBE_READ_REG(hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF) { + for (i = 0; i < sc->num_tx_queues; i++, txr++) + txr->watchdog_timer = IXGBE_TX_TIMEOUT; + ifp->if_timer = IXGBE_TX_TIMEOUT; + return; + } + + + printf("%s: Watchdog timeout -- resetting\n", ifp->if_xname); + for (i = 0; i < sc->num_tx_queues; i++, txr++) { + printf("%s: Queue(%d) tdh = %d, hw tdt = %d\n", ifp->if_xname, i, + IXGBE_READ_REG(hw, IXGBE_TDH(i)), + IXGBE_READ_REG(hw, IXGBE_TDT(i))); + printf("%s: TX(%d) desc avail = %d, Next TX to Clean = %d\n", ifp->if_xname, + i, txr->tx_avail, txr->next_tx_to_clean); + } + ifp->if_flags &= ~IFF_RUNNING; + sc->watchdog_events++; + + ixgbe_init(sc); + return; +} + +/********************************************************************* + * Init entry point + * + * This routine is used in two ways. It is used by the stack as + * init entry point in network interface structure. It is also used + * by the driver as a hw/sw initialization routine to get to a + * consistent state. + * + * return 0 on success, positive on failure + **********************************************************************/ +#define IXGBE_MHADD_MFS_SHIFT 16 + +void +ixgbe_init(void *arg) +{ + struct ix_softc *sc = (struct ix_softc *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + u32 txdctl, rxdctl, mhadd, gpie; + int i, s; + + INIT_DEBUGOUT("ixgbe_init: begin"); + + s = splnet(); + + ixgbe_stop(sc); + + /* Get the latest mac address, User can use a LAA */ + bcopy(sc->arpcom.ac_enaddr, sc->hw.mac.addr, + IXGBE_ETH_LENGTH_OF_ADDRESS); + ixgbe_hw(&sc->hw, set_rar, 0, sc->hw.mac.addr, 0, 1); + sc->hw.addr_ctrl.rar_used_count = 1; + + /* Initialize the hardware */ + if (ixgbe_hardware_init(sc)) { + printf("%s: Unable to initialize the hardware\n", + ifp->if_xname); + splx(s); + return; + } + +#if NVLAN > 0 + if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) + ixgbe_enable_hw_vlans(sc); +#endif + + /* Prepare transmit descriptors and buffers */ + if (ixgbe_setup_transmit_structures(sc)) { + printf("%s: Could not setup transmit structures\n", + ifp->if_xname); + ixgbe_stop(sc); + splx(s); + return; + } + + ixgbe_initialize_transmit_units(sc); + + /* Setup Multicast table */ + ixgbe_set_multi(sc); + + /* + * If we are resetting MTU smaller than 2K + * drop to small RX buffers + */ + if (sc->max_frame_size <= MCLBYTES) + sc->bigbufs = FALSE; + + /* Prepare receive descriptors and buffers */ + if (ixgbe_setup_receive_structures(sc)) { + printf("%s: Could not setup receive structures\n", ifp->if_xname); + ixgbe_stop(sc); + splx(s); + return; + } + + /* Configure RX settings */ + ixgbe_initialize_receive_units(sc); + + gpie = IXGBE_READ_REG(&sc->hw, IXGBE_GPIE); + /* Enable Fan Failure Interrupt */ + if (sc->hw.phy.media_type == ixgbe_media_type_copper) + gpie |= IXGBE_SDP1_GPIEN; + if (sc->msix) { + /* Enable Enhanced MSIX mode */ + gpie |= IXGBE_GPIE_MSIX_MODE; + gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | + IXGBE_GPIE_OCD; + } + IXGBE_WRITE_REG(&sc->hw, IXGBE_GPIE, gpie); + + /* Set MTU size */ + if (ifp->if_mtu > ETHERMTU) { + mhadd = IXGBE_READ_REG(&sc->hw, IXGBE_MHADD); + mhadd &= ~IXGBE_MHADD_MFS_MASK; + mhadd |= sc->max_frame_size << IXGBE_MHADD_MFS_SHIFT; + IXGBE_WRITE_REG(&sc->hw, IXGBE_MHADD, mhadd); + } + + /* Now enable all the queues */ + + for (i = 0; i < sc->num_tx_queues; i++) { + txdctl = IXGBE_READ_REG(&sc->hw, IXGBE_TXDCTL(i)); + txdctl |= IXGBE_TXDCTL_ENABLE; + /* Set WTHRESH to 8, burst writeback */ + txdctl |= (8 << 16); + IXGBE_WRITE_REG(&sc->hw, IXGBE_TXDCTL(i), txdctl); + } + + for (i = 0; i < sc->num_rx_queues; i++) { + rxdctl = IXGBE_READ_REG(&sc->hw, IXGBE_RXDCTL(i)); + /* PTHRESH set to 32 */ + rxdctl |= 0x0020; + rxdctl |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(&sc->hw, IXGBE_RXDCTL(i), rxdctl); + } + + timeout_add(&sc->timer, hz); + + /* Set up MSI/X routing */ + ixgbe_configure_ivars(sc); + + ixgbe_enable_intr(sc); + + /* Now inform the stack we're ready */ + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + splx(s); +} + +/********************************************************************* + * + * Legacy Interrupt Service routine + * + **********************************************************************/ + +int +ixgbe_legacy_irq(void *arg) +{ + struct ix_softc *sc = (struct ix_softc *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + u32 reg_eicr; + struct tx_ring *txr = sc->tx_rings; + struct rx_ring *rxr = sc->rx_rings; + struct ixgbe_hw *hw = &sc->hw; + int claimed = 0; + + for (;;) { + reg_eicr = IXGBE_READ_REG(&sc->hw, IXGBE_EICR); + if (reg_eicr == 0) + break; + + claimed = 1; + + if (ifp->if_flags & IFF_RUNNING) { + ixgbe_rxeof(rxr, -1); + ixgbe_txeof(txr); + } + + /* Check for fan failure */ + if ((hw->phy.media_type == ixgbe_media_type_copper) && + (reg_eicr & IXGBE_EICR_GPI_SDP1)) { + printf("%s: \nCRITICAL: FAN FAILURE!! " + "REPLACE IMMEDIATELY!!\n", ifp->if_xname); + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMS, + IXGBE_EICR_GPI_SDP1); + } + + /* Link status change */ + if (reg_eicr & IXGBE_EICR_LSC) { + timeout_del(&sc->timer); + ixgbe_update_link_status(sc); + timeout_add(&sc->timer, hz); + } + } + + if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd)) + ixgbe_start_locked(txr, ifp); + + return (claimed); +} + +/********************************************************************* + * + * Media Ioctl callback + * + * This routine is called whenever the user queries the status of + * the interface using ifconfig. + * + **********************************************************************/ +void +ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) +{ + struct ix_softc *sc = ifp->if_softc; + + INIT_DEBUGOUT("ixgbe_media_status: begin"); + ixgbe_update_link_status(sc); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!sc->link_active) { + ifmr->ifm_status |= IFM_NONE; + return; + } + + ifmr->ifm_status |= IFM_ACTIVE; + + switch (sc->link_speed) { + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_T | IFM_FDX; + break; + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= sc->optics | IFM_FDX; + break; + } +} + +/********************************************************************* + * + * Media Ioctl callback + * + * This routine is called when the user changes speed/duplex using + * media/mediopt option with ifconfig. + * + **********************************************************************/ +int +ixgbe_media_change(struct ifnet * ifp) +{ + struct ix_softc *sc = ifp->if_softc; + struct ifmedia *ifm = &sc->media; + + INIT_DEBUGOUT("ixgbe_media_change: begin"); + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + sc->hw.mac.autoneg = TRUE; + sc->hw.phy.autoneg_advertised = + IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_10GB_FULL; + break; + default: + printf("%s: Only auto media type\n", ifp->if_xname); + return (EINVAL); + } + + return (0); +} + +/********************************************************************* + * + * This routine maps the mbufs to tx descriptors. + * WARNING: while this code is using an MQ style infrastructure, + * it would NOT work as is with more than 1 queue. + * + * return 0 on success, positive on failure + **********************************************************************/ + +int +ixgbe_encap(struct tx_ring *txr, struct mbuf *m_head) +{ + struct ix_softc *sc = txr->sc; + u32 olinfo_status = 0, cmd_type_len = 0; + int i, j, error; + int first, last = 0; + bus_dmamap_t map; + struct ixgbe_tx_buf *txbuf, *txbuf_mapped; + union ixgbe_adv_tx_desc *txd = NULL; +#ifdef IX_CSUM_OFFLOAD + u32 paylen = 0; +#endif + + /* Basic descriptor defines */ + cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA; + cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT; + +#if NVLAN > 0 + /* VLAN tagging? */ + if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && + m_head->m_pkthdr.rcvif != NULL) + cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; +#endif + + /* + * Force a cleanup if number of TX descriptors + * available is below the threshold. If it fails + * to get above, then abort transmit. + */ + if (txr->tx_avail <= IXGBE_TX_CLEANUP_THRESHOLD) { + ixgbe_txeof(txr); + /* Make sure things have improved */ + if (txr->tx_avail <= IXGBE_TX_OP_THRESHOLD) { + txr->no_tx_desc_avail++; + return (ENOBUFS); + } + } + + /* + * Important to capture the first descriptor + * used because it will contain the index of + * the one we tell the hardware to report back + */ + first = txr->next_avail_tx_desc; + txbuf = &txr->tx_buffers[first]; + txbuf_mapped = txbuf; + map = txbuf->map; + + /* + * Map the packet for DMA. + */ + error = bus_dmamap_load_mbuf(txr->txtag, map, + m_head, BUS_DMA_NOWAIT); + + if (error == ENOMEM) { + sc->no_tx_dma_setup++; + return (error); + } else if (error != 0) { + sc->no_tx_dma_setup++; + return (error); + } + + /* Make certain there are enough descriptors */ + if (map->dm_nsegs > txr->tx_avail - 2) { + txr->no_tx_desc_avail++; + error = ENOBUFS; + goto xmit_fail; + } + +#ifdef IX_CSUM_OFFLOAD + /* + * Set the appropriate offload context + * this becomes the first descriptor of + * a packet. + */ + if (ixgbe_tso_setup(txr, m_head, &paylen)) { + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; + olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; + olinfo_status |= paylen << IXGBE_ADVTXD_PAYLEN_SHIFT; + ++sc->tso_tx; + } else if (ixgbe_tx_ctx_setup(txr, m_head)) + olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; +#endif + + i = txr->next_avail_tx_desc; + for (j = 0; j < map->dm_nsegs; j++) { + txbuf = &txr->tx_buffers[i]; + txd = &txr->tx_base[i]; + + txd->read.buffer_addr = htole64(map->dm_segs[j].ds_addr); + txd->read.cmd_type_len = htole32(txr->txd_cmd | + cmd_type_len | map->dm_segs[j].ds_len); + txd->read.olinfo_status = htole32(olinfo_status); + last = i; /* Next descriptor that will get completed */ + + if (++i == sc->num_tx_desc) + i = 0; + + txbuf->m_head = NULL; + + /* + * we have to do this inside the loop right now + * because of the hardware workaround. + */ + if (j == (map->dm_nsegs -1)) /* Last descriptor gets EOP and RS */ + txd->read.cmd_type_len |= + htole32(IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS); +#ifndef NO_82598_A0_SUPPORT + if (sc->hw.revision_id == 0) + desc_flip(txd); +#endif + } + + txr->tx_avail -= map->dm_nsegs; + txr->next_avail_tx_desc = i; + + txbuf->m_head = m_head; + txbuf->map = map; + bus_dmamap_sync(txr->txtag, map, 0, map->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + /* Set the index of the descriptor that will be marked done */ + txbuf = &txr->tx_buffers[first]; + + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + 0, txr->txdma.dma_map->dm_mapsize, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* + * Advance the Transmit Descriptor Tail (Tdt), this tells the + * hardware that this frame is available to transmit. + */ + IXGBE_WRITE_REG(&sc->hw, IXGBE_TDT(txr->me), i); + ++txr->tx_packets; + return (0); + +xmit_fail: + bus_dmamap_unload(txr->txtag, txbuf->map); + return (error); + +} + +void +ixgbe_set_promisc(struct ix_softc *sc) +{ + + u_int32_t reg_rctl; + struct ifnet *ifp = &sc->arpcom.ac_if; + + reg_rctl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL); + + if (ifp->if_flags & IFF_PROMISC) { + reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, reg_rctl); + } else if (ifp->if_flags & IFF_ALLMULTI) { + reg_rctl |= IXGBE_FCTRL_MPE; + reg_rctl &= ~IXGBE_FCTRL_UPE; + IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, reg_rctl); + } + return; +} + +void +ixgbe_disable_promisc(struct ix_softc * sc) +{ + u_int32_t reg_rctl; + + reg_rctl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL); + + reg_rctl &= (~IXGBE_FCTRL_UPE); + reg_rctl &= (~IXGBE_FCTRL_MPE); + IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, reg_rctl); + + return; +} + + +/********************************************************************* + * Multicast Update + * + * This routine is called whenever multicast address list is updated. + * + **********************************************************************/ +#define IXGBE_RAR_ENTRIES 16 + +void +ixgbe_set_multi(struct ix_softc *sc) +{ + u32 fctrl; + u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 *update_ptr; + struct ether_multi *enm; + struct ether_multistep step; + int mcnt = 0; + struct ifnet *ifp = &sc->arpcom.ac_if; + + IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); + + fctrl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL); + fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + if (ifp->if_flags & IFF_PROMISC) + fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + else if (ifp->if_flags & IFF_ALLMULTI) { + fctrl |= IXGBE_FCTRL_MPE; + fctrl &= ~IXGBE_FCTRL_UPE; + } else + fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + + IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, fctrl); + + ETHER_FIRST_MULTI(step, &sc->arpcom, enm); + while (enm != NULL) { + if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { + ifp->if_flags |= IFF_ALLMULTI; + mcnt = MAX_NUM_MULTICAST_ADDRESSES; + } + if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) + break; + bcopy(enm->enm_addrlo, + &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], + IXGBE_ETH_LENGTH_OF_ADDRESS); + mcnt++; + ETHER_NEXT_MULTI(step, enm); + } + + update_ptr = mta; + ixgbe_hw(&sc->hw, update_mc_addr_list, + update_ptr, mcnt, ixgbe_mc_array_itr); + + return; +} + +/* + * This is an iterator function now needed by the multicast + * shared code. It simply feeds the shared code routine the + * addresses in the array of ixgbe_set_multi() one by one. + */ +u8 * +ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) +{ + u8 *addr = *update_ptr; + u8 *newptr; + *vmdq = 0; + + newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; + *update_ptr = newptr; + return addr; +} + + +/********************************************************************* + * Timer routine + * + * This routine checks for link status,updates statistics, + * and runs the watchdog timer. + * + **********************************************************************/ + +void +ixgbe_local_timer(void *arg) +{ + struct ix_softc *sc = arg; +#ifdef IX_DEBUG + struct ifnet *ifp = &sc->arpcom.ac_if; +#endif + int s; + + s = splnet(); + + ixgbe_update_link_status(sc); + ixgbe_update_stats_counters(sc); + +#ifdef IX_DEBUG + if ((ifp->if_flags & (IFF_RUNNING|IFF_DEBUG)) == + (IFF_RUNNING|IFF_DEBUG)) + ixgbe_print_hw_stats(sc); +#endif + + timeout_add(&sc->timer, hz); + + splx(s); +} + +void +ixgbe_update_link_status(struct ix_softc *sc) +{ + boolean_t link_up = FALSE; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct tx_ring *txr = sc->tx_rings; + int i; + + ixgbe_hw(&sc->hw, check_link, &sc->link_speed, &link_up, 0); + + switch (sc->link_speed) { + case IXGBE_LINK_SPEED_UNKNOWN: + ifp->if_baudrate = 0; + break; + case IXGBE_LINK_SPEED_100_FULL: + ifp->if_baudrate = IF_Mbps(100); + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifp->if_baudrate = IF_Gbps(1); + break; + case IXGBE_LINK_SPEED_10GB_FULL: + ifp->if_baudrate = IF_Gbps(10); + break; + } + + if (link_up){ + if (sc->link_active == FALSE) { + sc->link_active = TRUE; + ifp->if_link_state = LINK_STATE_FULL_DUPLEX; + if_link_state_change(ifp); + } + } else { /* Link down */ + if (sc->link_active == TRUE) { + ifp->if_baudrate = 0; + ifp->if_link_state = LINK_STATE_DOWN; + if_link_state_change(ifp); + sc->link_active = FALSE; + for (i = 0; i < sc->num_tx_queues; + i++, txr++) + txr->watchdog_timer = FALSE; + ifp->if_timer = 0; + } + } + + return; +} + + + +/********************************************************************* + * + * This routine disables all traffic on the sc by issuing a + * global reset on the MAC and deallocates TX/RX buffers. + * + **********************************************************************/ + +void +ixgbe_stop(void *arg) +{ + struct ix_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + INIT_DEBUGOUT("ixgbe_stop: begin\n"); + ixgbe_disable_intr(sc); + + /* Tell the stack that the interface is no longer active */ + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + + ixgbe_hw(&sc->hw, reset_hw); + sc->hw.adapter_stopped = FALSE; + ixgbe_hw(&sc->hw, stop_adapter); + timeout_del(&sc->timer); + + /* reprogram the RAR[0] in case user changed it. */ + ixgbe_hw(&sc->hw, set_rar, 0, sc->hw.mac.addr, 0, IXGBE_RAH_AV); +} + + +/********************************************************************* + * + * Determine hardware revision. + * + **********************************************************************/ +void +ixgbe_identify_hardware(struct ix_softc *sc) +{ + struct ixgbe_osdep *os = &sc->osdep; + struct pci_attach_args *pa = os->os_pa; + u_int32_t reg; + + /* Save off the information about this board */ + sc->hw.vendor_id = PCI_VENDOR(pa->pa_id); + sc->hw.device_id = PCI_PRODUCT(pa->pa_id); + + reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG); + sc->hw.revision_id = PCI_REVISION(reg); + + reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); + sc->hw.subsystem_vendor_id = PCI_VENDOR(reg); + sc->hw.subsystem_device_id = PCI_PRODUCT(reg); + + ixgbe_total_ports++; + switch (sc->hw.device_id) { + case PCI_PRODUCT_INTEL_82598AF_DUAL: + case PCI_PRODUCT_INTEL_82598EB_CX4_DUAL: + case PCI_PRODUCT_INTEL_82598AT_DUAL: + ixgbe_total_ports++; + break; + } + + switch (sc->hw.device_id) { + case PCI_PRODUCT_INTEL_82598AF_DUAL: + case PCI_PRODUCT_INTEL_82598AF: + sc->optics = IFM_10G_SR; + break; + case PCI_PRODUCT_INTEL_82598EB_CX4_DUAL: + case PCI_PRODUCT_INTEL_82598EB_CX4: + sc->optics = IFM_10G_CX4; + break; + case PCI_PRODUCT_INTEL_82598EB_XF_LR: + sc->optics = IFM_10G_LR; + break; + case PCI_PRODUCT_INTEL_82598AT_DUAL: + case PCI_PRODUCT_INTEL_82598AT: + default: + sc->optics = IFM_AUTO; + break; + } +} + +/********************************************************************* + * + * Setup the Legacy or MSI Interrupt handler + * + **********************************************************************/ +int +ixgbe_allocate_legacy(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_osdep *os = &sc->osdep; + struct pci_attach_args *pa = os->os_pa; + const char *intrstr = NULL; + pci_chipset_tag_t pc = pa->pa_pc; + pci_intr_handle_t ih; + + /* Legacy RID at 0 */ + if (sc->msix == 0) + sc->rid[0] = 0; + + /* We allocate a single interrupt resource */ + if (pci_intr_map(pa, &ih)) { + printf(": couldn't map interrupt\n"); + return (ENXIO); + } + + intrstr = pci_intr_string(pc, ih); + sc->tag[0] = pci_intr_establish(pc, ih, IPL_NET, + ixgbe_legacy_irq, sc, ifp->if_xname); + if (sc->tag[0] == NULL) { + printf(": couldn't establish interrupt"); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return (ENXIO); + } + printf(": %s", intrstr); + + return (0); +} + +#if 0 +/********************************************************************* + * + * Setup MSIX Interrupt resources and handlers + * + **********************************************************************/ +int +ixgbe_allocate_msix(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct tx_ring *txr = sc->tx_rings; + struct rx_ring *rxr = sc->rx_rings; + int error, vector = 0, i; + + /* TX setup: the code is here for multi tx, + there are other parts of the driver not ready for it */ + for (i = 0; i < sc->num_tx_queues; i++, vector++, txr++) { + sc->res[vector] = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &sc->rid[vector], + RF_SHAREABLE | RF_ACTIVE); + if (!sc->res[vector]) { + printf("%s: Unable to allocate" + " bus resource: tx interrupt [%d]\n", ifp->if_xname, vector); + return (ENXIO); + } + /* Set the handler function */ + error = bus_setup_intr(dev, sc->res[vector], + INTR_TYPE_NET | INTR_MPSAFE, NULL, + ixgbe_msix_tx, txr, &sc->tag[vector]); + if (error) { + sc->res[vector] = NULL; + printf("%s: Failed to register TX handler"); + return (error); + } + txr->msix = vector; + txr->eims = IXGBE_IVAR_TX_QUEUE(vector); + /* Make tasklet for deferred handling - one per queue */ + txr->tx_task = ixgbe_handle_tx; + txr->tq = workq_create("ix_txq", sc->num_tx_queues + 1); + } + + /* RX setup */ + for (i = 0; i < sc->num_rx_queues; i++, vector++, rxr++) { + sc->res[vector] = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &sc->rid[vector], + RF_SHAREABLE | RF_ACTIVE); + if (!sc->res[vector]) { + printf("%s: Unable to allocate" + " bus resource: rx interrupt [%d]," + "rid = %d\n", ifp->if_xname, i, sc->rid[vector]); + return (ENXIO); + } + /* Set the handler function */ + error = bus_setup_intr(dev, sc->res[vector], + INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_msix_rx, + rxr, &sc->tag[vector]); + if (error) { + sc->res[vector] = NULL; + printf("%s: Failed to register RX handler"); + return (error); + } + rxr->msix = vector; + rxr->eims = IXGBE_IVAR_RX_QUEUE(vector); + rxr->rx_task = ixgbe_handle_rx; + rxr->tq = workq_create("ix_rxq", sc->num_rx_queues + 1); + } + + /* Now for Link changes */ + sc->res[vector] = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &sc->rid[vector], RF_SHAREABLE | RF_ACTIVE); + if (!sc->res[vector]) { + printf("%s: Unable to allocate" + " bus resource: Link interrupt [%d]\n", ifp->if_xname, sc->rid[vector]); + return (ENXIO); + } + /* Set the link handler function */ + error = bus_setup_intr(dev, sc->res[vector], + INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_msix_link, + sc, &sc->tag[vector]); + if (error) { + sc->res[vector] = NULL; + printf("%s: Failed to register LINK handler"); + return (error); + } + sc->linkvec = vector; + sc->link_task = ixgbe_handle_link; + + return (0); +} + +/* + * Setup Either MSI/X or MSI + */ +int +ixgbe_setup_msix(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + int rid, want, queues, msgs; + + /* First try MSI/X */ + rid = PCIR_BAR(IXGBE_MSIX_BAR); + sc->msix_mem = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (!sc->msix_mem) { + /* May not be enabled */ + printf("%s: Unable to map MSIX table \n", ifp->if_xname); + goto msi; + } + + msgs = pci_msix_count(dev); + if (msgs == 0) { /* system has msix disabled */ + bus_release_resource(dev, SYS_RES_MEMORY, + PCIR_BAR(IXGBE_MSIX_BAR), sc->msix_mem); + sc->msix_mem = NULL; + goto msi; + } + + /* Figure out a reasonable auto config value */ + queues = (mp_ncpus > ((msgs-1)/2)) ? (msgs-1)/2 : mp_ncpus; + + if (ixgbe_tx_queues == 0) + ixgbe_tx_queues = queues; + if (ixgbe_rx_queues == 0) + ixgbe_rx_queues = queues; + want = ixgbe_tx_queues + ixgbe_rx_queues + 1; + if (msgs >= want) + msgs = want; + else { + printf("%s: MSIX Configuration Problem, " + "%d vectors but %d queues wanted!\n", ifp->if_xname, + msgs, want); + return (ENXIO); + } + if ((msgs) && pci_alloc_msix(dev, &msgs) == 0) { + printf("%s: Using MSIX interrupts with %d vectors\n", + ifp->if_xname, msgs); + sc->num_tx_queues = ixgbe_tx_queues; + sc->num_rx_queues = ixgbe_rx_queues; + return (msgs); + } +msi: + msgs = pci_msi_count(dev); + if (msgs == 1 && pci_alloc_msi(dev, &msgs) == 0) + printf("%s: Using MSI interrupt\n", ifp->if_xname); + return (msgs); + /* MSI is not supported yet */ + return (0); +} +#endif + +int +ixgbe_allocate_pci_resources(struct ix_softc *sc) +{ + struct ixgbe_osdep *os = &sc->osdep; + struct pci_attach_args *pa = os->os_pa; + int val, i; + + val = pci_conf_read(pa->pa_pc, pa->pa_tag, PCIR_BAR(0)); + if (PCI_MAPREG_TYPE(val) != PCI_MAPREG_TYPE_MEM && + PCI_MAPREG_TYPE(val) != PCI_MAPREG_MEM_TYPE_64BIT) { + printf(": mmba is not mem space\n"); + return (ENXIO); + } + + if (pci_mapreg_map(pa, PCIR_BAR(0), PCI_MAPREG_MEM_TYPE(val), 0, + &os->os_memt, &os->os_memh, &os->os_membase, &os->os_memsize, 0)) { + printf(": cannot find mem space\n"); + return (ENXIO); + } + sc->hw.hw_addr = (u8 *)os->os_membase; + + /* + * Init the resource arrays + */ + for (i = 0; i < IXGBE_MSGS; i++) { + sc->rid[i] = i + 1; /* MSI/X RID starts at 1 */ + sc->tag[i] = NULL; + sc->res[i] = NULL; + } + + /* Legacy defaults */ + sc->num_tx_queues = 1; + sc->num_rx_queues = 1; + + /* Now setup MSI or MSI/X */ +#if 0 + sc->msix = ixgbe_setup_msix(sc); +#endif + sc->hw.back = os; + + return (0); +} + +void +ixgbe_free_pci_resources(struct ix_softc * sc) +{ + struct ixgbe_osdep *os = &sc->osdep; + struct pci_attach_args *pa = os->os_pa; + +#if 0 + int i; + + /* + * Legacy has this set to 0, but we need + * to run this once, so reset it. + */ + if (sc->msix == 0) + sc->msix = 1; + + /* + * First release all the interrupt resources: + * notice that since these are just kept + * in an array we can do the same logic + * whether its MSIX or just legacy. + */ + for (i = 0; i < sc->msix; i++) { + if (sc->tag[i] != NULL) { + pci_intr_disestablish(pa->pa_pc, sc->tag[0]); + sc->tag[i] = NULL; + } + if (sc->res[i] != NULL) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->rid[i], sc->res[i]); + } + } + + if (sc->msix) + pci_release_msi(dev); + + if (sc->msix_mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + PCIR_BAR(IXGBE_MSIX_BAR), sc->msix_mem); +#else + pci_intr_disestablish(pa->pa_pc, sc->tag[0]); + sc->tag[0] = NULL; +#endif + + if (os->os_membase != NULL) + bus_space_unmap(os->os_memt, os->os_memh, os->os_memsize); + os->os_membase = 0; + + return; +} + +/********************************************************************* + * + * Initialize the hardware to a configuration as specified by the + * sc structure. The controller is reset, the EEPROM is + * verified, the MAC address is set, then the shared initialization + * routines are called. + * + **********************************************************************/ +int +ixgbe_hardware_init(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + u16 csum; + + csum = 0; + /* Issue a global reset */ + sc->hw.adapter_stopped = FALSE; + ixgbe_hw(&sc->hw, stop_adapter); + + /* Make sure we have a good EEPROM before we read from it */ + if (ixgbe_ee(&sc->hw, validate_checksum, &csum) < 0) { + printf("%s: The EEPROM Checksum Is Not Valid\n", ifp->if_xname); + return (EIO); + } + + /* Get Hardware Flow Control setting */ + sc->hw.fc.type = ixgbe_fc_full; + sc->hw.fc.pause_time = IXGBE_FC_PAUSE; + sc->hw.fc.low_water = IXGBE_FC_LO; + sc->hw.fc.high_water = IXGBE_FC_HI; + sc->hw.fc.send_xon = TRUE; + + if (ixgbe_hw(&sc->hw, init_hw) != 0) { + printf("%s: Hardware Initialization Failed"); + return (EIO); + } + bcopy(sc->hw.mac.addr, sc->arpcom.ac_enaddr, + IXGBE_ETH_LENGTH_OF_ADDRESS); + + return (0); +} + +/********************************************************************* + * + * Setup networking device structure and register an interface. + * + **********************************************************************/ +void +ixgbe_setup_interface(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + struct ifnet *ifp = &sc->arpcom.ac_if; + INIT_DEBUGOUT("ixgbe_setup_interface: begin"); + + strlcpy(ifp->if_xname, sc->dev.dv_xname, IFNAMSIZ); + ifp->if_baudrate = IF_Gbps(10); +#if 0 + ifp->if_init = ixgbe_init; +#endif + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = ixgbe_ioctl; + ifp->if_start = ixgbe_start; + ifp->if_timer = 0; + ifp->if_watchdog = ixgbe_watchdog; + ifp->if_hardmtu = IXGBE_MAX_FRAME_SIZE - + ETHER_HDR_LEN - ETHER_CRC_LEN; + IFQ_SET_MAXLEN(&ifp->if_snd, sc->num_tx_desc - 1); + IFQ_SET_READY(&ifp->if_snd); + + ifp->if_capabilities |= IFCAP_VLAN_MTU; +#ifdef IX_CSUM_OFFLOAD + ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; + ifp->if_capabilities |= IFCAP_CSUM_IPv4; + ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; +#endif + + sc->max_frame_size = + ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + + if ((hw->device_id == PCI_PRODUCT_INTEL_82598AT) || + (hw->device_id == PCI_PRODUCT_INTEL_82598AT_DUAL)) + ixgbe_hw(hw, setup_link_speed, + IXGBE_LINK_SPEED_10GB_FULL | + IXGBE_LINK_SPEED_1GB_FULL, TRUE, TRUE); + else + ixgbe_hw(hw, setup_link_speed, + IXGBE_LINK_SPEED_10GB_FULL, + TRUE, FALSE); + + /* + * Specify the media types supported by this sc and register + * callbacks to update media and link information + */ + ifmedia_init(&sc->media, IFM_IMASK, ixgbe_media_change, + ixgbe_media_status); + ifmedia_add(&sc->media, IFM_ETHER | sc->optics | + IFM_FDX, 0, NULL); + if ((hw->device_id == PCI_PRODUCT_INTEL_82598AT) || + (hw->device_id == PCI_PRODUCT_INTEL_82598AT_DUAL)) { + ifmedia_add(&sc->media, + IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); + ifmedia_add(&sc->media, + IFM_ETHER | IFM_1000_T, 0, NULL); + } + ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); + + if_attach(ifp); + ether_ifattach(ifp); + + + return; +} + +int +ixgbe_dma_malloc(struct ix_softc *sc, bus_size_t size, + struct ixgbe_dma_alloc *dma, int mapflags) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_osdep *os = &sc->osdep; + int r; + + dma->dma_tag = os->os_pa->pa_dmat; + r = bus_dmamap_create(dma->dma_tag, size, 1, size, 0, + BUS_DMA_NOWAIT, &dma->dma_map); + if (r != 0) { + printf("%s: ixgbe_dma_malloc: bus_dma_tag_create failed; " + "error %u\n", ifp->if_xname, r); + goto fail_0; + } + + r = bus_dmamem_alloc(dma->dma_tag, size, PAGE_SIZE, 0, + &dma->dma_seg, 1, &dma->dma_nseg, BUS_DMA_NOWAIT); + if (r != 0) { + printf("%s: ixgbe_dma_malloc: bus_dmamem_alloc failed; " + "error %u\n", ifp->if_xname, r); + goto fail_1; + } + r = bus_dmamem_map(dma->dma_tag, &dma->dma_seg, dma->dma_nseg, size, + &dma->dma_vaddr, BUS_DMA_NOWAIT); + if (r != 0) { + printf("%s: ixgbe_dma_malloc: bus_dmamem_map failed; " + "error %u\n", ifp->if_xname, r); + goto fail_2; + } + r = bus_dmamap_load(dma->dma_tag, dma->dma_map, + dma->dma_vaddr, size, NULL, + mapflags | BUS_DMA_NOWAIT); + if (r != 0) { + printf("%s: ixgbe_dma_malloc: bus_dmamap_load failed; " + "error %u\n", ifp->if_xname, r); + goto fail_3; + } + dma->dma_size = size; + return (0); +fail_3: + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size); +fail_2: + bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg); +fail_1: + bus_dmamap_destroy(dma->dma_tag, dma->dma_map); +fail_0: + dma->dma_map = NULL; + dma->dma_tag = NULL; + return (r); +} + +void +ixgbe_dma_free(struct ix_softc *sc, struct ixgbe_dma_alloc *dma) +{ + if (dma->dma_tag == NULL) + return; + + if (dma->dma_map != NULL) { + bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, + dma->dma_map->dm_mapsize, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dma->dma_tag, dma->dma_map); + bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, dma->dma_size); + bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg); + bus_dmamap_destroy(dma->dma_tag, dma->dma_map); + } +} + + +/********************************************************************* + * + * Allocate memory for the transmit and receive rings, and then + * the descriptors associated with each, called only once at attach. + * + **********************************************************************/ +int +ixgbe_allocate_queues(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct tx_ring *txr; + struct rx_ring *rxr; + int rsize, tsize, error = IXGBE_SUCCESS; + int txconf = 0, rxconf = 0, i; + + /* First allocate the TX ring struct memory */ + if (!(sc->tx_rings = + (struct tx_ring *) malloc(sizeof(struct tx_ring) * + sc->num_tx_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + printf("%s: Unable to allocate TX ring memory\n", ifp->if_xname); + error = ENOMEM; + goto fail; + } + txr = sc->tx_rings; + + /* Next allocate the RX */ + if (!(sc->rx_rings = + (struct rx_ring *) malloc(sizeof(struct rx_ring) * + sc->num_rx_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + printf("%s: Unable to allocate RX ring memory\n", ifp->if_xname); + error = ENOMEM; + goto rx_fail; + } + rxr = sc->rx_rings; + + /* For the ring itself */ + tsize = roundup2(sc->num_tx_desc * + sizeof(union ixgbe_adv_tx_desc), 4096); + + /* + * Now set up the TX queues, txconf is needed to handle the + * possibility that things fail midcourse and we need to + * undo memory gracefully + */ + for (i = 0; i < sc->num_tx_queues; i++, txconf++) { + /* Set up some basics */ + txr = &sc->tx_rings[i]; + txr->sc = sc; + txr->me = i; + + /* Initialize the TX side lock */ + mtx_init(&txr->tx_mtx, IPL_NET); + + if (ixgbe_dma_malloc(sc, tsize, + &txr->txdma, BUS_DMA_NOWAIT)) { + printf("%s: Unable to allocate TX Descriptor memory\n", + ifp->if_xname); + error = ENOMEM; + goto err_tx_desc; + } + txr->tx_base = (union ixgbe_adv_tx_desc *)txr->txdma.dma_vaddr; + bzero((void *)txr->tx_base, tsize); + + if (ixgbe_dma_malloc(sc, sizeof(u_int32_t), + &txr->txwbdma, BUS_DMA_NOWAIT)) { + printf("%s: Unable to allocate TX Write Back memory\n", + ifp->if_xname); + error = ENOMEM; + goto err_tx_desc; + } + txr->tx_hwb = (u_int32_t *)txr->txwbdma.dma_vaddr; + *txr->tx_hwb = 0; + + /* Now allocate transmit buffers for the ring */ + if (ixgbe_allocate_transmit_buffers(txr)) { + printf("%s: Critical Failure setting up transmit buffers\n", + ifp->if_xname); + error = ENOMEM; + goto err_tx_desc; + } + + } + + /* + * Next the RX queues... + */ + rsize = roundup2(sc->num_rx_desc * + sizeof(union ixgbe_adv_rx_desc), 4096); + for (i = 0; i < sc->num_rx_queues; i++, rxconf++) { + rxr = &sc->rx_rings[i]; + /* Set up some basics */ + rxr->sc = sc; + rxr->me = i; + + /* Initialize the TX side lock */ + mtx_init(&rxr->rx_mtx, IPL_NET); + + if (ixgbe_dma_malloc(sc, rsize, + &rxr->rxdma, BUS_DMA_NOWAIT)) { + printf("%s: Unable to allocate RxDescriptor memory\n", + ifp->if_xname); + error = ENOMEM; + goto err_rx_desc; + } + rxr->rx_base = (union ixgbe_adv_rx_desc *)rxr->rxdma.dma_vaddr; + bzero((void *)rxr->rx_base, rsize); + + /* Allocate receive buffers for the ring*/ + if (ixgbe_allocate_receive_buffers(rxr)) { + printf("%s: Critical Failure setting up receive buffers\n", + ifp->if_xname); + error = ENOMEM; + goto err_rx_desc; + } + } + + return (0); + +err_rx_desc: + for (rxr = sc->rx_rings; rxconf > 0; rxr++, rxconf--) + ixgbe_dma_free(sc, &rxr->rxdma); +err_tx_desc: + for (txr = sc->tx_rings; txconf > 0; txr++, txconf--) { + ixgbe_dma_free(sc, &txr->txdma); + ixgbe_dma_free(sc, &txr->txwbdma); + } + free(sc->rx_rings, M_DEVBUF); +rx_fail: + free(sc->tx_rings, M_DEVBUF); +fail: + return (error); +} + +/********************************************************************* + * + * Allocate memory for tx_buffer structures. The tx_buffer stores all + * the information needed to transmit a packet on the wire. This is + * called only once at attach, setup is done every reset. + * + **********************************************************************/ +int +ixgbe_allocate_transmit_buffers(struct tx_ring *txr) +{ + struct ix_softc *sc = txr->sc; + struct ixgbe_osdep *os = &sc->osdep; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_tx_buf *txbuf; + int error, i; + + txr->txtag = os->os_pa->pa_dmat; + if (!(txr->tx_buffers = + (struct ixgbe_tx_buf *) malloc(sizeof(struct ixgbe_tx_buf) * + sc->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) { + printf("%s: Unable to allocate tx_buffer memory\n", ifp->if_xname); + error = ENOMEM; + goto fail; + } + + /* Create the descriptor buffer dma maps */ + txbuf = txr->tx_buffers; + for (i = 0; i < sc->num_tx_desc; i++, txbuf++) { + error = bus_dmamap_create(txr->txtag, IXGBE_TSO_SIZE, + IXGBE_MAX_SCATTER, PAGE_SIZE, 0, + BUS_DMA_NOWAIT, &txbuf->map); + if (error != 0) { + printf("%s: Unable to create TX DMA map\n", ifp->if_xname); + goto fail; + } + } + + return 0; +fail: + /* We free all, it handles case where we are in the middle */ + ixgbe_free_transmit_structures(sc); + return (error); +} + +/********************************************************************* + * + * Initialize a transmit ring. + * + **********************************************************************/ +void +ixgbe_setup_transmit_ring(struct tx_ring *txr) +{ + struct ix_softc *sc = txr->sc; + struct ixgbe_tx_buf *txbuf; + int i; + + /* Clear the old ring contents */ + bzero((void *)txr->tx_base, + (sizeof(union ixgbe_adv_tx_desc)) * sc->num_tx_desc); + /* Reset indices */ + txr->next_avail_tx_desc = 0; + txr->next_tx_to_clean = 0; + + /* Free any existing tx buffers. */ + txbuf = txr->tx_buffers; + for (i = 0; i < sc->num_tx_desc; i++, txbuf++) { + if (txbuf->m_head != NULL) { + bus_dmamap_sync(txr->txtag, txbuf->map, + 0, txbuf->map->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(txr->txtag, txbuf->map); + m_freem(txbuf->m_head); + } + txbuf->m_head = NULL; + } + + /* Set number of descriptors available */ + txr->tx_avail = sc->num_tx_desc; + + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + 0, txr->txdma.dma_map->dm_mapsize, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + +} + +/********************************************************************* + * + * Initialize all transmit rings. + * + **********************************************************************/ +int +ixgbe_setup_transmit_structures(struct ix_softc *sc) +{ + struct tx_ring *txr = sc->tx_rings; + int i; + + for (i = 0; i < sc->num_tx_queues; i++, txr++) + ixgbe_setup_transmit_ring(txr); + + return (0); +} + +/********************************************************************* + * + * Enable transmit unit. + * + **********************************************************************/ +void +ixgbe_initialize_transmit_units(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct tx_ring *txr; + struct ixgbe_hw *hw = &sc->hw; + int i; + u64 tdba, txhwb; + u32 txctrl; + + /* Setup the Base and Length of the Tx Descriptor Ring */ + + for (i = 0; i < sc->num_tx_queues; i++) { + txr = &sc->tx_rings[i]; + + /* Setup descriptor base address */ + tdba = txr->txdma.dma_map->dm_segs[0].ds_addr; + IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), + (tdba & 0x00000000ffffffffULL)); + IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), + sc->num_tx_desc * sizeof(struct ixgbe_legacy_tx_desc)); + + /* Setup for Head WriteBack */ + txhwb = txr->txwbdma.dma_map->dm_segs[0].ds_addr; + txhwb |= IXGBE_TDWBAL_HEAD_WB_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(i), + (txhwb & 0x00000000ffffffffULL)); + IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(i), + (txhwb >> 32)); + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); + + /* Setup the HW Tx Head and Tail descriptor pointers */ + IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0); + + /* Setup Transmit Descriptor Cmd Settings */ + txr->txd_cmd = IXGBE_TXD_CMD_IFCS; + + txr->watchdog_timer = 0; + } + ifp->if_timer = 0; + + return; +} + +/********************************************************************* + * + * Free all transmit rings. + * + **********************************************************************/ +void +ixgbe_free_transmit_structures(struct ix_softc *sc) +{ + struct tx_ring *txr = sc->tx_rings; + int i; + + for (i = 0; i < sc->num_tx_queues; i++, txr++) { + ixgbe_free_transmit_buffers(txr); + ixgbe_dma_free(sc, &txr->txdma); + ixgbe_dma_free(sc, &txr->txwbdma); + } + free(sc->tx_rings, M_DEVBUF); +} + +/********************************************************************* + * + * Free transmit ring related data structures. + * + **********************************************************************/ +void +ixgbe_free_transmit_buffers(struct tx_ring *txr) +{ + struct ix_softc *sc = txr->sc; + struct ixgbe_tx_buf *tx_buffer; + int i; + + INIT_DEBUGOUT("free_transmit_ring: begin"); + + if (txr->tx_buffers == NULL) + return; + + tx_buffer = txr->tx_buffers; + for (i = 0; i < sc->num_tx_desc; i++, tx_buffer++) { + if (tx_buffer->m_head != NULL) { + bus_dmamap_sync(txr->txtag, tx_buffer->map, + 0, tx_buffer->map->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(txr->txtag, + tx_buffer->map); + m_freem(tx_buffer->m_head); + if (tx_buffer->map != NULL) { + bus_dmamap_destroy(txr->txtag, + tx_buffer->map); + } + } else if (tx_buffer->map != NULL) { + bus_dmamap_unload(txr->txtag, + tx_buffer->map); + bus_dmamap_destroy(txr->txtag, + tx_buffer->map); + } + tx_buffer->m_head = NULL; + tx_buffer->map = NULL; + } + + if (txr->tx_buffers != NULL) + free(txr->tx_buffers, M_DEVBUF); + txr->tx_buffers = NULL; +#if 0 + if (txr->txtag != NULL) + bus_dma_tag_destroy(txr->txtag); +#endif + txr->txtag = NULL; + return; +} + +#ifdef IX_CSUM_OFFLOAD +/********************************************************************* + * + * Advanced Context Descriptor setup for VLAN or CSUM + * + **********************************************************************/ + +boolean_t +ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp) +{ + struct ix_softc *sc = txr->sc; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_adv_tx_context_desc *TXD; + struct ixgbe_tx_buf *tx_buffer; + u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; + struct ip *ip; + struct ip6_hdr *ip6; + int ehdrlen, ip_hlen = 0; + u16 etype; + u8 ipproto = 0; + bool offload = TRUE; + int ctxd = txr->next_avail_tx_desc; +#if NVLAN > 0 + struct ether_vlan_header *eh; + struct ifvlan *ifv = NULL; + + if ((mp->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && + mp->m_pkthdr.rcvif != NULL) + ifv = mp->m_pkthdr.rcvif->if_softc; +#else + struct ether_header *eh; +#endif + + if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) == 0) + offload = FALSE; + + tx_buffer = &txr->tx_buffers[ctxd]; + TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; + + /* + * In advanced descriptors the vlan tag must + * be placed into the descriptor itself. + */ +#if NVLAN > 0 + if (ifv != NULL) { + vlan_macip_lens |= + htole16(ifv->ifv_tag) << IXGBE_ADVTXD_VLAN_SHIFT; + } else +#endif + if (offload == FALSE) + return FALSE; /* No need for CTX */ + + /* + * Determine where frame payload starts. + * Jump over vlan headers if already present, + * helpful for QinQ too. + */ +#if NVLAN > 0 + eh = mtod(mp, struct ether_vlan_header *); + if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { + etype = ntohs(eh->evl_proto); + ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + } else { + etype = ntohs(eh->evl_encap_proto); + ehdrlen = ETHER_HDR_LEN; + } +#else + eh = mtod(mp, struct ether_header *); + etype = ntohs(eh->ether_type); + ehdrlen = ETHER_HDR_LEN; +#endif + + /* Set the ether header length */ + vlan_macip_lens |= ehdrlen << IXGBE_ADVTXD_MACLEN_SHIFT; + + switch (etype) { + case ETHERTYPE_IP: + ip = (struct ip *)(mp->m_data + ehdrlen); + ip_hlen = ip->ip_hl << 2; + if (mp->m_len < ehdrlen + ip_hlen) + return FALSE; /* failure */ + ipproto = ip->ip_p; + if (mp->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + break; + case ETHERTYPE_IPV6: + ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); + ip_hlen = sizeof(struct ip6_hdr); + if (mp->m_len < ehdrlen + ip_hlen) + return FALSE; /* failure */ + ipproto = ip6->ip6_nxt; + if (mp->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; + break; + default: + offload = FALSE; + break; + } + + vlan_macip_lens |= ip_hlen; + type_tucmd_mlhl |= IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT; + + switch (ipproto) { + case IPPROTO_TCP: + if (mp->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + break; + case IPPROTO_UDP: + if (mp->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP; + break; + default: + offload = FALSE; + break; + } + + /* Now copy bits into descriptor */ + TXD->vlan_macip_lens |= htole32(vlan_macip_lens); + TXD->type_tucmd_mlhl |= htole32(type_tucmd_mlhl); + TXD->seqnum_seed = htole32(0); + TXD->mss_l4len_idx = htole32(0); + +#ifndef NO_82598_A0_SUPPORT + if (sc->hw.revision_id == 0) + desc_flip(TXD); +#endif + + tx_buffer->m_head = NULL; + + /* We've consumed the first desc, adjust counters */ + if (++ctxd == sc->num_tx_desc) + ctxd = 0; + txr->next_avail_tx_desc = ctxd; + --txr->tx_avail; + + return (offload); +} + +#if 0 +/********************************************************************** + * + * Setup work for hardware segmentation offload (TSO) on + * scs using advanced tx descriptors + * + **********************************************************************/ +boolean_t +ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *paylen) +{ + struct ix_softc *sc = txr->sc; + struct ixgbe_adv_tx_context_desc *TXD; + struct ixgbe_tx_buf *tx_buffer; + u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; + u32 mss_l4len_idx = 0; + int ctxd, ehdrlen, hdrlen, ip_hlen, tcp_hlen; +#if NVLAN > 0 + u16 vtag = 0; + struct ether_vlan_header *eh; + + struct ifvlan *ifv = NULL; + + if ((mp->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && + mp->m_pkthdr.rcvif != NULL) + ifv = mp->m_pkthdr.rcvif->if_softc; +#else + struct ether_header *eh; +#endif + struct ip *ip; + struct tcphdr *th; + + if (((mp->m_pkthdr.csum_flags & CSUM_TSO) == 0) || + (mp->m_pkthdr.len <= IXGBE_TX_BUFFER_SIZE)) + return FALSE; + + /* + * Determine where frame payload starts. + * Jump over vlan headers if already present + */ +#if NVLAN > 0 + eh = mtod(mp, struct ether_vlan_header *); + if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) + ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + else + ehdrlen = ETHER_HDR_LEN; +#else + eh = mtod(mp, struct ether_header *); + ehdrlen = ETHER_HDR_LEN; +#endif + + /* Ensure we have at least the IP+TCP header in the first mbuf. */ + if (mp->m_len < ehdrlen + sizeof(struct ip) + sizeof(struct tcphdr)) + return FALSE; + + ctxd = txr->next_avail_tx_desc; + tx_buffer = &txr->tx_buffers[ctxd]; + TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; + + ip = (struct ip *)(mp->m_data + ehdrlen); + if (ip->ip_p != IPPROTO_TCP) + return FALSE; /* 0 */ + ip->ip_len = 0; + ip->ip_sum = 0; + ip_hlen = ip->ip_hl << 2; + th = (struct tcphdr *)((caddr_t)ip + ip_hlen); + th->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htons(IPPROTO_TCP)); + tcp_hlen = th->th_off << 2; + hdrlen = ehdrlen + ip_hlen + tcp_hlen; + /* This is used in the transmit desc in encap */ + *paylen = mp->m_pkthdr.len - hdrlen; + +#if NVLAN > 0 + /* VLAN MACLEN IPLEN */ + if (ifv != NULL) { + vtag = htole16(mp->m_pkthdr.ether_vtag); + vlan_macip_lens |= (ifv->ifv_tag << IXGBE_ADVTXD_VLAN_SHIFT); + } +#endif + + vlan_macip_lens |= ehdrlen << IXGBE_ADVTXD_MACLEN_SHIFT; + vlan_macip_lens |= ip_hlen; + TXD->vlan_macip_lens |= htole32(vlan_macip_lens); + + /* ADV DTYPE TUCMD */ + type_tucmd_mlhl |= IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT; + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + TXD->type_tucmd_mlhl |= htole32(type_tucmd_mlhl); + + + /* MSS L4LEN IDX */ + mss_l4len_idx |= (mp->m_pkthdr.tso_segsz << IXGBE_ADVTXD_MSS_SHIFT); + mss_l4len_idx |= (tcp_hlen << IXGBE_ADVTXD_L4LEN_SHIFT); + TXD->mss_l4len_idx = htole32(mss_l4len_idx); + + TXD->seqnum_seed = htole32(0); + tx_buffer->m_head = NULL; + +#ifndef NO_82598_A0_SUPPORT + if (sc->hw.revision_id == 0) + desc_flip(TXD); +#endif + + if (++ctxd == sc->num_tx_desc) + ctxd = 0; + + txr->tx_avail--; + txr->next_avail_tx_desc = ctxd; + return TRUE; +} + +#else /* For 6.2 RELEASE */ +/* This makes it easy to keep the code common */ +boolean_t +ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *paylen) +{ + return (FALSE); +} +#endif +#endif + +/********************************************************************** + * + * Examine each tx_buffer in the used queue. If the hardware is done + * processing the packet then free associated resources. The + * tx_buffer is put back on the free queue. + * + **********************************************************************/ +boolean_t +ixgbe_txeof(struct tx_ring *txr) +{ + struct ix_softc *sc = txr->sc; + struct ifnet *ifp = &sc->arpcom.ac_if; + u_int first, last, done, num_avail; + struct ixgbe_tx_buf *tx_buffer; + struct ixgbe_legacy_tx_desc *tx_desc; + + if (txr->tx_avail == sc->num_tx_desc) + return FALSE; + + num_avail = txr->tx_avail; + first = txr->next_tx_to_clean; + + tx_buffer = &txr->tx_buffers[first]; + + /* For cleanup we just use legacy struct */ + tx_desc = (struct ixgbe_legacy_tx_desc *)&txr->tx_base[first]; + + /* Get the HWB */ + bus_dmamap_sync(txr->txwbdma.dma_tag, txr->txwbdma.dma_map, + 0, txr->txwbdma.dma_map->dm_mapsize, + BUS_DMASYNC_POSTREAD); + done = *txr->tx_hwb; + + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + 0, txr->txdma.dma_map->dm_mapsize, + BUS_DMASYNC_POSTREAD); + + while (TRUE) { + /* We clean the range til last head write back */ + while (first != done) { + tx_desc->upper.data = 0; + tx_desc->lower.data = 0; + tx_desc->buffer_addr = 0; + num_avail++; + + if (tx_buffer->m_head) { + ifp->if_opackets++; + bus_dmamap_sync(txr->txtag, + tx_buffer->map, + 0, tx_buffer->map->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(txr->txtag, + tx_buffer->map); + m_freem(tx_buffer->m_head); + tx_buffer->m_head = NULL; + } + + if (++first == sc->num_tx_desc) + first = 0; + + tx_buffer = &txr->tx_buffers[first]; + tx_desc = (struct ixgbe_legacy_tx_desc *) + &txr->tx_base[first]; + } + /* See if there is more work now */ + last = done; + bus_dmamap_sync(txr->txwbdma.dma_tag, txr->txwbdma.dma_map, + 0, txr->txwbdma.dma_map->dm_mapsize, + BUS_DMASYNC_POSTREAD); + done = *txr->tx_hwb; + if (last == done) + break; + } + + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + 0, txr->txdma.dma_map->dm_mapsize, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + txr->next_tx_to_clean = first; + + /* + * If we have enough room, clear IFF_OACTIVE to tell the stack that + * it is OK to send packets. If there are no pending descriptors, + * clear the timeout. Otherwise, if some descriptors have been freed, + * restart the timeout. + */ + if (num_avail > IXGBE_TX_CLEANUP_THRESHOLD) { + ifp->if_flags &= ~IFF_OACTIVE; + + /* If all are clean turn off the timer */ + if (num_avail == sc->num_tx_desc) { + ifp->if_timer = 0; + txr->watchdog_timer = 0; + txr->tx_avail = num_avail; + return FALSE; + } + /* Some were cleaned, so reset timer */ + else if (num_avail != txr->tx_avail) { + ifp->if_timer = IXGBE_TX_TIMEOUT; + txr->watchdog_timer = IXGBE_TX_TIMEOUT; + } + } + + txr->tx_avail = num_avail; + + return TRUE; +} + +/********************************************************************* + * + * Get a buffer from system mbuf buffer pool. + * + **********************************************************************/ +int +ixgbe_get_buf(struct rx_ring *rxr, int i, struct mbuf *nmp) +{ + struct ix_softc *sc = rxr->sc; + struct mbuf *mp = nmp; + bus_dmamap_t map; + int error, old, s = 0; + int size = MCLBYTES; + struct ixgbe_rx_buf *rxbuf; + +#if 0 + /* Are we going to Jumbo clusters? */ + if (sc->bigbufs) { + size = MJUMPAGESIZE; + s = 1; + }; + + mp = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); + if (mp == NULL) { + sc->mbuf_alloc_failed++; + return (ENOBUFS); + } +#endif + + if (mp == NULL) { + MGETHDR(mp, M_DONTWAIT, MT_DATA); + if (mp == NULL) { + sc->mbuf_alloc_failed++; + return (ENOBUFS); + } + MCLGET(mp, M_DONTWAIT); + if ((mp->m_flags & M_EXT) == 0) { + m_freem(mp); + sc->mbuf_cluster_failed++; + return (ENOBUFS); + } + mp->m_len = mp->m_pkthdr.len = size; + } else { + mp->m_len = mp->m_pkthdr.len = size; + mp->m_data = mp->m_ext.ext_buf; + mp->m_next = NULL; + } + + if (sc->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + m_adj(mp, ETHER_ALIGN); + + /* + * Using memory from the mbuf cluster pool, invoke the bus_dma + * machinery to arrange the memory mapping. + */ + error = bus_dmamap_load_mbuf(rxr->rxtag[s], rxr->spare_map[s], + mp, BUS_DMA_NOWAIT); + if (error) { + m_freem(mp); + return (error); + } + + /* Now check our target buffer for existing mapping */ + rxbuf = &rxr->rx_buffers[i]; + old = rxbuf->bigbuf; + if (rxbuf->m_head != NULL) + bus_dmamap_unload(rxr->rxtag[old], rxbuf->map[old]); + + map = rxbuf->map[old]; + rxbuf->map[s] = rxr->spare_map[s]; + rxr->spare_map[old] = map; + rxbuf->m_head = mp; + rxbuf->bigbuf = s; + + rxr->rx_base[i].read.pkt_addr = + htole64(rxbuf->map[s]->dm_segs[0].ds_addr); + + bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], + 0, rxbuf->map[s]->dm_mapsize, BUS_DMASYNC_PREREAD); + +#ifndef NO_82598_A0_SUPPORT + /* A0 needs to One's Compliment descriptors */ + if (sc->hw.revision_id == 0) { + struct dhack {u32 a1; u32 a2; u32 b1; u32 b2;}; + struct dhack *d; + + d = (struct dhack *)&rxr->rx_base[i]; + d->a1 = ~(d->a1); + d->a2 = ~(d->a2); + } +#endif + + return (0); +} + +/********************************************************************* + * + * Allocate memory for rx_buffer structures. Since we use one + * rx_buffer per received packet, the maximum number of rx_buffer's + * that we'll need is equal to the number of receive descriptors + * that we've allocated. + * + **********************************************************************/ +int +ixgbe_allocate_receive_buffers(struct rx_ring *rxr) +{ + struct ix_softc *sc = rxr->sc; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_osdep *os = &sc->osdep; + struct ixgbe_rx_buf *rxbuf; + int i, bsize, error; + + bsize = sizeof(struct ixgbe_rx_buf) * sc->num_rx_desc; + if (!(rxr->rx_buffers = + (struct ixgbe_rx_buf *) malloc(bsize, + M_DEVBUF, M_NOWAIT | M_ZERO))) { + printf("%s: Unable to allocate rx_buffer memory\n", ifp->if_xname); + error = ENOMEM; + goto fail; + } + rxr->rxtag[0] = rxr->rxtag[1] = os->os_pa->pa_dmat; + + /* Create the spare maps (used by getbuf) */ + error = bus_dmamap_create(rxr->rxtag[0], + MCLBYTES, 1, MCLBYTES, 0, BUS_DMA_NOWAIT, &rxr->spare_map[0]); + if (error) { + printf("%s: %s: bus_dmamap_create failed: %d\n", ifp->if_xname, + __func__, error); + goto fail; + } + error = bus_dmamap_create(rxr->rxtag[1], + MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, BUS_DMA_NOWAIT, &rxr->spare_map[1]); + if (error) { + printf("%s: %s: bus_dmamap_create failed: %d\n", ifp->if_xname, + __func__, error); + goto fail; + } + + for (i = 0; i < sc->num_rx_desc; i++, rxbuf++) { + rxbuf = &rxr->rx_buffers[i]; + error = bus_dmamap_create(rxr->rxtag[0], MCLBYTES, 1, MCLBYTES, + 0, BUS_DMA_NOWAIT, &rxbuf->map[0]); + if (error) { + printf("%s: Unable to create Small RX DMA map\n", ifp->if_xname); + goto fail; + } + error = bus_dmamap_create(rxr->rxtag[1], MJUMPAGESIZE, 1, MJUMPAGESIZE, + 0, BUS_DMA_NOWAIT, &rxbuf->map[1]); + if (error) { + printf("%s: Unable to create Large RX DMA map\n", ifp->if_xname); + goto fail; + } + } + + return (0); + +fail: + /* Frees all, but can handle partial completion */ + ixgbe_free_receive_structures(sc); + return (error); +} + +/********************************************************************* + * + * Initialize a receive ring and its buffers. + * + **********************************************************************/ +int +ixgbe_setup_receive_ring(struct rx_ring *rxr) +{ + struct ix_softc *sc = rxr->sc; + struct ixgbe_rx_buf *rxbuf; +#if 0 + struct ifnet *ifp = &sc->arpcom.ac_if; + struct lro_ctrl *lro = &rxr->lro; +#endif + int j, rsize, s = 0, i; + + rsize = roundup2(sc->num_rx_desc * + sizeof(union ixgbe_adv_rx_desc), 4096); + /* Clear the ring contents */ + bzero((void *)rxr->rx_base, rsize); + + /* + ** Free current RX buffers: the size buffer + ** that is loaded is indicated by the buffer + ** bigbuf value. + */ + for (i = 0; i < sc->num_rx_desc; i++) { + rxbuf = &rxr->rx_buffers[i]; + s = rxbuf->bigbuf; + if (rxbuf->m_head != NULL) { + bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], + 0, rxbuf->map[s]->dm_mapsize, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); + m_freem(rxbuf->m_head); + rxbuf->m_head = NULL; + } + } + + for (j = 0; j < sc->num_rx_desc; j++) { + if (ixgbe_get_buf(rxr, j, NULL) == ENOBUFS) { + rxr->rx_buffers[j].m_head = NULL; + rxr->rx_base[j].read.pkt_addr = 0; + /* If we fail some may have change size */ + s = sc->bigbufs; + goto fail; + } + } + + /* Setup our descriptor indices */ + rxr->next_to_check = 0; + rxr->last_cleaned = 0; + + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, + 0, rxr->rxdma.dma_map->dm_mapsize, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + +#if 0 + /* Now set up the LRO interface */ + if (ixgbe_enable_lro) { + int err = tcp_lro_init(lro); + if (err) { + printf("%s: LRO Initialization failed!\n", ifp->if_xname); + goto fail; + } + printf("%s: RX LRO Initialized\n", ifp->if_xname); + lro->ifp = &sc->arpcom.ac_if; + } +#endif + + return (0); +fail: + /* + * We need to clean up any buffers allocated so far + * 'j' is the failing index, decrement it to get the + * last success. + */ + for (--j; j < 0; j--) { + rxbuf = &rxr->rx_buffers[j]; + if (rxbuf->m_head != NULL) { + bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], + 0, rxbuf->map[s]->dm_mapsize, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); + m_freem(rxbuf->m_head); + rxbuf->m_head = NULL; + } + } + return (ENOBUFS); +} + +/********************************************************************* + * + * Initialize all receive rings. + * + **********************************************************************/ +int +ixgbe_setup_receive_structures(struct ix_softc *sc) +{ + struct rx_ring *rxr = sc->rx_rings; + int i, j, s; + + for (i = 0; i < sc->num_rx_queues; i++, rxr++) + if (ixgbe_setup_receive_ring(rxr)) + goto fail; + + return (0); +fail: + /* + * Free RX buffers allocated so far, we will only handle + * the rings that completed, the failing case will have + * cleaned up for itself. The value of 'i' will be the + * failed ring so we must pre-decrement it. + */ + rxr = sc->rx_rings; + for (--i; i > 0; i--, rxr++) { + for (j = 0; j < sc->num_rx_desc; j++) { + struct ixgbe_rx_buf *rxbuf; + rxbuf = &rxr->rx_buffers[j]; + s = rxbuf->bigbuf; + if (rxbuf->m_head != NULL) { + bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], + 0, rxbuf->map[s]->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); + m_freem(rxbuf->m_head); + rxbuf->m_head = NULL; + } + } + } + + return (ENOBUFS); +} + +/********************************************************************* + * + * Enable receive unit. + * + **********************************************************************/ +void +ixgbe_initialize_receive_units(struct ix_softc *sc) +{ + struct rx_ring *rxr = sc->rx_rings; + struct ifnet *ifp = &sc->arpcom.ac_if; + u32 rxctrl, fctrl, srrctl, rxcsum; + u32 reta, mrqc, hlreg, linkvec; + u32 random[10]; + int i; + + + /* + * Make sure receives are disabled while + * setting up the descriptor ring + */ + rxctrl = IXGBE_READ_REG(&sc->hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(&sc->hw, IXGBE_RXCTRL, + rxctrl & ~IXGBE_RXCTRL_RXEN); + + /* Enable broadcasts */ + fctrl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL); + fctrl |= IXGBE_FCTRL_BAM; + IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, fctrl); + + hlreg = IXGBE_READ_REG(&sc->hw, IXGBE_HLREG0); + if (ifp->if_mtu > ETHERMTU) + hlreg |= IXGBE_HLREG0_JUMBOEN; + else + hlreg &= ~IXGBE_HLREG0_JUMBOEN; + IXGBE_WRITE_REG(&sc->hw, IXGBE_HLREG0, hlreg); + + srrctl = IXGBE_READ_REG(&sc->hw, IXGBE_SRRCTL(0)); + srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; + srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + if (sc->bigbufs) + srrctl |= 4096 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= 2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + IXGBE_WRITE_REG(&sc->hw, IXGBE_SRRCTL(0), srrctl); + + /* Set Queue moderation rate */ + for (i = 0; i < IXGBE_MSGS; i++) + IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(i), DEFAULT_ITR); + + /* Set Link moderation lower */ + linkvec = sc->num_tx_queues + sc->num_rx_queues; + IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(linkvec), LINK_ITR); + + for (i = 0; i < sc->num_rx_queues; i++, rxr++) { + u64 rdba = rxr->rxdma.dma_map->dm_segs[0].ds_addr; + /* Setup the Base and Length of the Rx Descriptor Ring */ + IXGBE_WRITE_REG(&sc->hw, IXGBE_RDBAL(i), + (rdba & 0x00000000ffffffffULL)); + IXGBE_WRITE_REG(&sc->hw, IXGBE_RDBAH(i), (rdba >> 32)); + IXGBE_WRITE_REG(&sc->hw, IXGBE_RDLEN(i), + sc->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); + + /* Setup the HW Rx Head and Tail Descriptor Pointers */ + IXGBE_WRITE_REG(&sc->hw, IXGBE_RDH(i), 0); + IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(i), + sc->num_rx_desc - 1); + } + + rxcsum = IXGBE_READ_REG(&sc->hw, IXGBE_RXCSUM); + + if (sc->num_rx_queues > 1) { + /* set up random bits */ + arc4random_bytes(&random, sizeof(random)); + switch (sc->num_rx_queues) { + case 8: + case 4: + reta = 0x00010203; + break; + case 2: + reta = 0x00010001; + break; + default: + reta = 0x00000000; + } + + /* Set up the redirection table */ + for (i = 0; i < 32; i++) { + IXGBE_WRITE_REG(&sc->hw, IXGBE_RETA(i), reta); + if (sc->num_rx_queues > 4) { + ++i; + IXGBE_WRITE_REG(&sc->hw, + IXGBE_RETA(i), 0x04050607); + } + } + + /* Now fill our hash function seeds */ + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG_ARRAY(&sc->hw, + IXGBE_RSSRK(0), i, random[i]); + + mrqc = IXGBE_MRQC_RSSEN + /* Perform hash on these packet types */ + | IXGBE_MRQC_RSS_FIELD_IPV4 + | IXGBE_MRQC_RSS_FIELD_IPV4_TCP + | IXGBE_MRQC_RSS_FIELD_IPV4_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX + | IXGBE_MRQC_RSS_FIELD_IPV6 + | IXGBE_MRQC_RSS_FIELD_IPV6_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; + IXGBE_WRITE_REG(&sc->hw, IXGBE_MRQC, mrqc); + + /* RSS and RX IPP Checksum are mutually exclusive */ + rxcsum |= IXGBE_RXCSUM_PCSD; + } + +#if 0 + if (ifp->if_capenable & IFCAP_RXCSUM) + rxcsum |= IXGBE_RXCSUM_PCSD; +#endif + + if (!(rxcsum & IXGBE_RXCSUM_PCSD)) + rxcsum |= IXGBE_RXCSUM_IPPCSE; + + IXGBE_WRITE_REG(&sc->hw, IXGBE_RXCSUM, rxcsum); + + /* Enable Receive engine */ + rxctrl |= (IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS); + IXGBE_WRITE_REG(&sc->hw, IXGBE_RXCTRL, rxctrl); + + return; +} + +/********************************************************************* + * + * Free all receive rings. + * + **********************************************************************/ +void +ixgbe_free_receive_structures(struct ix_softc *sc) +{ + struct rx_ring *rxr = sc->rx_rings; + int i; + + for (i = 0; i < sc->num_rx_queues; i++, rxr++) { +#if 0 + struct lro_ctrl *lro = &rxr->lro; + /* Free LRO memory */ + tcp_lro_free(lro); +#endif + ixgbe_free_receive_buffers(rxr); + /* Free the ring memory as well */ + ixgbe_dma_free(sc, &rxr->rxdma); + } + + free(sc->rx_rings, M_DEVBUF); +} + +/********************************************************************* + * + * Free receive ring data structures + * + **********************************************************************/ +void +ixgbe_free_receive_buffers(struct rx_ring *rxr) +{ + struct ix_softc *sc = NULL; + struct ixgbe_rx_buf *rxbuf = NULL; + int i, s; + + INIT_DEBUGOUT("free_receive_buffers: begin"); + sc = rxr->sc; + if (rxr->rx_buffers != NULL) { + rxbuf = &rxr->rx_buffers[0]; + for (i = 0; i < sc->num_rx_desc; i++) { + int s = rxbuf->bigbuf; + if (rxbuf->map != NULL) { + bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); + bus_dmamap_destroy(rxr->rxtag[s], rxbuf->map[s]); + } + if (rxbuf->m_head != NULL) { + m_freem(rxbuf->m_head); + } + rxbuf->m_head = NULL; + ++rxbuf; + } + } + if (rxr->rx_buffers != NULL) { + free(rxr->rx_buffers, M_DEVBUF); + rxr->rx_buffers = NULL; + } + for (s = 0; s < 2; s++) { + if (rxr->rxtag[s] != NULL) { +#if 0 + bus_dma_tag_destroy(rxr->rxtag[s]); +#endif + rxr->rxtag[s] = NULL; + } + } + return; +} + +/********************************************************************* + * + * This routine executes in interrupt context. It replenishes + * the mbufs in the descriptor and sends data which has been + * dma'ed into host memory to upper layer. + * + * We loop at most count times if count is > 0, or until done if + * count < 0. + * + *********************************************************************/ +bool +ixgbe_rxeof(struct rx_ring *rxr, int count) +{ + struct ix_softc *sc = rxr->sc; + struct ifnet *ifp = &sc->arpcom.ac_if; +#if 0 + struct lro_ctrl *lro = &rxr->lro; + struct lro_entry *queued; +#endif + struct mbuf *mp; + int len, i, eop = 0; + u8 accept_frame = 0; + u32 staterr; + union ixgbe_adv_rx_desc *cur; + + i = rxr->next_to_check; + cur = &rxr->rx_base[i]; + + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 0, + rxr->rxdma.dma_map->dm_mapsize, BUS_DMASYNC_POSTREAD); + + staterr = cur->wb.upper.status_error; + if (!(staterr & IXGBE_RXD_STAT_DD)) + return FALSE; + + while ((staterr & IXGBE_RXD_STAT_DD) && (count != 0) && + (ifp->if_flags & IFF_RUNNING)) { + struct mbuf *m = NULL; + int s; + + mp = rxr->rx_buffers[i].m_head; + s = rxr->rx_buffers[i].bigbuf; + bus_dmamap_sync(rxr->rxtag[s], rxr->rx_buffers[i].map[s], + 0, rxr->rx_buffers[i].map[s]->dm_mapsize, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag[s], + rxr->rx_buffers[i].map[s]); + + accept_frame = 1; + if (staterr & IXGBE_RXD_STAT_EOP) { + count--; + eop = 1; + } else { + eop = 0; + } + len = cur->wb.upper.length; + + if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) + accept_frame = 0; + + if (accept_frame) { + /* Get a fresh buffer */ + if (ixgbe_get_buf(rxr, i, NULL) != 0) { + ifp->if_iqdrops++; + goto discard; + } + + /* Assign correct length to the current fragment */ + mp->m_len = len; + + if (rxr->fmp == NULL) { + mp->m_pkthdr.len = len; + rxr->fmp = mp; /* Store the first mbuf */ + rxr->lmp = mp; + } else { + /* Chain mbuf's together */ + mp->m_flags &= ~M_PKTHDR; + rxr->lmp->m_next = mp; + rxr->lmp = rxr->lmp->m_next; + rxr->fmp->m_pkthdr.len += len; + } + + if (eop) { + rxr->fmp->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + rxr->packet_count++; + rxr->byte_count += rxr->fmp->m_pkthdr.len; + m = rxr->fmp; + + ixgbe_rx_checksum(sc, staterr, rxr->fmp); + +#if NVLAN > 0 && defined(IX_CSUM_OFFLOAD) + if (staterr & IXGBE_RXD_STAT_VP) { + struct ether_vlan_header vh; + + if (m->m_pkthdr.len < ETHER_HDR_LEN) + goto discard; + m_copydata(m, 0, + ETHER_HDR_LEN, (caddr_t)&vh); + vh.evl_proto = vh.evl_encap_proto; + vh.evl_tag = + letoh16(cur->wb.upper.vlan); + vh.evl_encap_proto = + htons(ETHERTYPE_VLAN); + m_adj(m, ETHER_HDR_LEN); + M_PREPEND(m, sizeof(vh), M_DONTWAIT); + if (m == NULL) + goto discard; + m_copyback(m, 0, sizeof(vh), &vh); + } +#endif + rxr->fmp = NULL; + rxr->lmp = NULL; + } + } else { +discard: + ixgbe_get_buf(rxr, i, mp); + if (rxr->fmp != NULL) { + m_freem(rxr->fmp); + rxr->fmp = NULL; + rxr->lmp = NULL; + } + m = NULL; + } + + /* Zero out the receive descriptors status */ + cur->wb.upper.status_error = 0; + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, + 0, rxr->rxdma.dma_map->dm_mapsize, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + rxr->last_cleaned = i; /* for updating tail */ + + if (++i == sc->num_rx_desc) + i = 0; + + /* Now send up to the stack */ + if (m != NULL) { + rxr->next_to_check = i; +#ifdef notyet + /* Use LRO if possible */ + if ((!lro->lro_cnt) || (tcp_lro_rx(lro, m, 0))) { +#endif +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); +#endif + ether_input_mbuf(ifp, m); + i = rxr->next_to_check; +#ifdef notyet + } +#endif + } + /* Get next descriptor */ + cur = &rxr->rx_base[i]; + staterr = cur->wb.upper.status_error; + } + rxr->next_to_check = i; + + /* Advance the IXGB's Receive Queue "Tail Pointer" */ + IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(rxr->me), rxr->last_cleaned); + +#if 0 + /* + ** Flush any outstanding LRO work + ** this may call into the stack and + ** must not hold a driver lock. + */ + while(!SLIST_EMPTY(&lro->lro_active)) { + queued = SLIST_FIRST(&lro->lro_active); + SLIST_REMOVE_HEAD(&lro->lro_active, next); + tcp_lro_flush(lro, queued); + } +#endif + + if (!(staterr & IXGBE_RXD_STAT_DD)) + return FALSE; + + return TRUE; +} + +/********************************************************************* + * + * Verify that the hardware indicated that the checksum is valid. + * Inform the stack about the status of checksum so that stack + * doesn't spend time verifying the checksum. + * + *********************************************************************/ +void +ixgbe_rx_checksum(struct ix_softc *sc, + u32 staterr, struct mbuf * mp) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + u16 status = (u16) staterr; + u8 errors = (u8) (staterr >> 24); + + /* Not offloading */ + if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) == 0) { + mp->m_pkthdr.csum_flags = 0; + return; + } + + // XXX + printf("%s: status 0x%04x errors 0x%02x\n", ifp->if_xname, + status, errors); + + mp->m_pkthdr.csum_flags = 0; + if (status & IXGBE_RXD_STAT_IPCS) { + /* Did it pass? */ + if (!(errors & IXGBE_RXD_ERR_IPE)) + /* IP Checksum Good */ + mp->m_pkthdr.csum_flags = M_IPV4_CSUM_IN_OK; + } + /* Did it pass? */ + if (errors & IXGBE_RXD_ERR_TCPE) + return; + if (status & IXGBE_RXD_STAT_L4CS) + mp->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK; + if (status & IXGBE_RXD_STAT_UDPCS) + mp->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK; +} + +#if NVLAN > 0 +void +ixgbe_enable_hw_vlans(struct ix_softc *sc) +{ + u32 ctrl; + + ixgbe_disable_intr(sc); + ctrl = IXGBE_READ_REG(&sc->hw, IXGBE_VLNCTRL); + ctrl |= IXGBE_VLNCTRL_VME; + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(&sc->hw, IXGBE_VLNCTRL, ctrl); + ixgbe_enable_intr(sc); +} +#endif + +void +ixgbe_enable_intr(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + u32 mask = IXGBE_EIMS_ENABLE_MASK; + + /* Enable Fan Failure detection */ + if (hw->phy.media_type == ixgbe_media_type_copper) + mask |= IXGBE_EIMS_GPI_SDP1; + /* With RSS we use auto clear */ + if (sc->msix_mem) { + /* Dont autoclear Link */ + mask &= ~IXGBE_EIMS_OTHER; + mask &= ~IXGBE_EIMS_LSC; + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIAC, + sc->eims_mask | mask); + } + + IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); + IXGBE_WRITE_FLUSH(hw); + + return; +} + +void +ixgbe_disable_intr(struct ix_softc *sc) +{ + if (sc->msix_mem) + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIAC, 0); + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, ~0); + IXGBE_WRITE_FLUSH(&sc->hw); + return; +} + +u16 +ixgbe_read_pci_cfg(struct ixgbe_hw *hw, u32 reg) +{ + struct pci_attach_args *pa; + u16 value; + + pa = ((struct ixgbe_osdep *)hw->back)->os_pa; + + /* Should we do read/mask/write...? 16 vs 32 bit!!! */ + value = pci_conf_read(pa->pa_pc, pa->pa_tag, reg) & 0xffff; + + return (value); +} + +void +ixgbe_set_ivar(struct ix_softc *sc, u16 entry, u8 vector) +{ + u32 ivar, index; + + vector |= IXGBE_IVAR_ALLOC_VAL; + index = (entry >> 2) & 0x1F; + ivar = IXGBE_READ_REG(&sc->hw, IXGBE_IVAR(index)); + ivar &= ~(0xFF << (8 * (entry & 0x3))); + ivar |= (vector << (8 * (entry & 0x3))); + IXGBE_WRITE_REG(&sc->hw, IXGBE_IVAR(index), ivar); +} + +void +ixgbe_configure_ivars(struct ix_softc *sc) +{ + struct tx_ring *txr = sc->tx_rings; + struct rx_ring *rxr = sc->rx_rings; + int i; + + for (i = 0; i < sc->num_rx_queues; i++, rxr++) { + ixgbe_set_ivar(sc, IXGBE_IVAR_RX_QUEUE(i), rxr->msix); + sc->eims_mask |= rxr->eims; + } + + for (i = 0; i < sc->num_tx_queues; i++, txr++) { + ixgbe_set_ivar(sc, IXGBE_IVAR_TX_QUEUE(i), txr->msix); + sc->eims_mask |= txr->eims; + } + + /* For the Link interrupt */ + ixgbe_set_ivar(sc, IXGBE_IVAR_OTHER_CAUSES_INDEX, + sc->linkvec); + sc->eims_mask |= IXGBE_IVAR_OTHER_CAUSES_INDEX; +} + +/********************************************************************** + * + * Update the board statistics counters. + * + **********************************************************************/ +void +ixgbe_update_stats_counters(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if;; + struct ixgbe_hw *hw = &sc->hw; + u32 missed_rx = 0, bprc, lxon, lxoff, total; + int i; + + sc->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); + + for (i = 0; i < 8; i++) { + int mp; + mp = IXGBE_READ_REG(hw, IXGBE_MPC(i)); + missed_rx += mp; + sc->stats.mpc[i] += mp; + sc->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + } + + /* Hardware workaround, gprc counts missed packets */ + sc->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); + sc->stats.gprc -= missed_rx; + + sc->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); + sc->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); + sc->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH); + + /* + * Workaround: mprc hardware is incorrectly counting + * broadcasts, so for now we subtract those. + */ + bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); + sc->stats.bprc += bprc; + sc->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); + sc->stats.mprc -= bprc; + + sc->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC); + sc->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); + sc->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); + sc->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); + sc->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); + sc->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); + sc->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); + sc->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); + + sc->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); + sc->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + + lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); + sc->stats.lxontxc += lxon; + lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + sc->stats.lxofftxc += lxoff; + total = lxon + lxoff; + + sc->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); + sc->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); + sc->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); + sc->stats.gptc -= total; + sc->stats.mptc -= total; + sc->stats.ptc64 -= total; + sc->stats.gotc -= total * ETHER_MIN_LEN; + + sc->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); + sc->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); + sc->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); + sc->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); + sc->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); + sc->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); + sc->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); + sc->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); + sc->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); + sc->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); + +#if 0 + /* Fill out the OS statistics structure */ + ifp->if_ipackets = sc->stats.gprc; + ifp->if_opackets = sc->stats.gptc; + ifp->if_ibytes = sc->stats.gorc; + ifp->if_obytes = sc->stats.gotc; + ifp->if_imcasts = sc->stats.mprc; +#endif + ifp->if_collisions = 0; + ifp->if_oerrors = sc->watchdog_events; + ifp->if_ierrors = missed_rx + sc->stats.crcerrs + sc->stats.rlec; +} + +#ifdef IX_DEBUG +/********************************************************************** + * + * This routine is called only when ixgbe_display_debug_stats is enabled. + * This routine provides a way to take a look at important statistics + * maintained by the driver and hardware. + * + **********************************************************************/ +void +ixgbe_print_hw_stats(struct ix_softc * sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if;; + + printf("%s: mbuf alloc failed %lu, mbuf cluster failed %lu, " + "missed pkts %llu, rx len errs %llu, crc errs %llu, " + "dropped pkts %lu, watchdog timeouts %ld, " + "XON rx %llu, XON tx %llu, XOFF rx %llu, XOFF tx %llu, " + "total pkts rx %llu, good pkts rx %llu, good pkts tx %llu, " + "tso tx %lu\n", + ifp->if_xname, + sc->mbuf_alloc_failed, + sc->mbuf_cluster_failed, + (long long)sc->stats.mpc[0], + (long long)sc->stats.roc + (long long)sc->stats.ruc, + (long long)sc->stats.crcerrs, + sc->dropped_pkts, + sc->watchdog_events, + (long long)sc->stats.lxonrxc, + (long long)sc->stats.lxontxc, + (long long)sc->stats.lxoffrxc, + (long long)sc->stats.lxofftxc, + (long long)sc->stats.tpr, + (long long)sc->stats.gprc, + (long long)sc->stats.gptc, + sc->tso_tx); +} + +/* + * Set flow control using sysctl: + * Flow control values: + * 0 - off + * 1 - rx pause + * 2 - tx pause + * 3 - full + */ +int +ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS) +{ + int error; + struct ix_softc *sc; + + error = sysctl_handle_int(oidp, &ixgbe_flow_control, 0, req); + + if (error) + return (error); + + sc = (struct ix_softc *) arg1; + switch (ixgbe_flow_control) { + case ixgbe_fc_rx_pause: + case ixgbe_fc_tx_pause: + case ixgbe_fc_full: + sc->hw.fc.type = ixgbe_flow_control; + break; + case ixgbe_fc_none: + default: + sc->hw.fc.type = ixgbe_fc_none; + } + + ixgbe_setup_fc(&sc->hw, 0); + return error; +} +#endif + +#ifndef NO_82598_A0_SUPPORT +/* + * A0 Workaround: invert descriptor for hardware + */ +void +desc_flip(void *desc) +{ + struct dhack {u32 a1; u32 a2; u32 b1; u32 b2;}; + struct dhack *d; + + d = (struct dhack *)desc; + d->a1 = ~(d->a1); + d->a2 = ~(d->a2); + d->b1 = ~(d->b1); + d->b2 = ~(d->b2); + d->b2 &= 0xFFFFFFF0; + d->b1 &= ~IXGBE_ADVTXD_DCMD_RS; +} +#endif + + + diff --git a/sys/dev/pci/if_ix.h b/sys/dev/pci/if_ix.h new file mode 100644 index 00000000000..42ed5f63f00 --- /dev/null +++ b/sys/dev/pci/if_ix.h @@ -0,0 +1,312 @@ +/* $OpenBSD: if_ix.h,v 1.1 2008/06/08 20:01:02 reyk Exp $ */ + +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD: src/sys/dev/ixgbe/ixgbe.h,v 1.4 2008/05/16 18:46:30 jfv Exp $*/ + +#ifndef _IXGBE_H_ +#define _IXGBE_H_ + +#include <dev/pci/ixgbe.h> + +#if 0 +#include "tcp_lro.h" +#endif + +/* Tunables */ + +/* + * TxDescriptors Valid Range: 64-4096 Default Value: 256 This value is the + * number of transmit descriptors allocated by the driver. Increasing this + * value allows the driver to queue more transmits. Each descriptor is 16 + * bytes. Performance tests have show the 2K value to be optimal for top + * performance. + */ +#define DEFAULT_TXD 256 +#define PERFORM_TXD 2048 +#define MAX_TXD 4096 +#define MIN_TXD 64 + +/* + * RxDescriptors Valid Range: 64-4096 Default Value: 256 This value is the + * number of receive descriptors allocated for each RX queue. Increasing this + * value allows the driver to buffer more incoming packets. Each descriptor + * is 16 bytes. A receive buffer is also allocated for each descriptor. + * + * Note: with 8 rings and a dual port card, it is possible to bump up + * against the system mbuf pool limit, you can tune nmbclusters + * to adjust for this. + */ +#define DEFAULT_RXD 256 +#define PERFORM_RXD 2048 +#define MAX_RXD 4096 +#define MIN_RXD 64 + +/* Alignment for rings */ +#define DBA_ALIGN 128 + +/* + * This parameter controls the maximum no of times the driver will loop in + * the isr. Minimum Value = 1 + */ +#define MAX_INTR 10 + +/* + * This parameter controls the duration of transmit watchdog timer. + */ +#define IXGBE_TX_TIMEOUT 5 /* set to 5 seconds */ + +/* + * This parameters control when the driver calls the routine to reclaim + * transmit descriptors. + */ +#define IXGBE_TX_CLEANUP_THRESHOLD (sc->num_tx_desc / 8) +#define IXGBE_TX_OP_THRESHOLD (sc->num_tx_desc / 32) + +#define IXGBE_MAX_FRAME_SIZE 0x3F00 + +/* Flow control constants */ +#define IXGBE_FC_PAUSE 0x680 +#define IXGBE_FC_HI 0x20000 +#define IXGBE_FC_LO 0x10000 + +/* Defines for printing debug information */ +#define DEBUG_INIT 0 +#define DEBUG_IOCTL 0 +#define DEBUG_HW 0 + +#define INIT_DEBUGOUT(S) if (DEBUG_INIT) printf(S "\n") +#define INIT_DEBUGOUT1(S, A) if (DEBUG_INIT) printf(S "\n", A) +#define INIT_DEBUGOUT2(S, A, B) if (DEBUG_INIT) printf(S "\n", A, B) +#define IOCTL_DEBUGOUT(S) if (DEBUG_IOCTL) printf(S "\n") +#define IOCTL_DEBUGOUT1(S, A) if (DEBUG_IOCTL) printf(S "\n", A) +#define IOCTL_DEBUGOUT2(S, A, B) if (DEBUG_IOCTL) printf(S "\n", A, B) +#define HW_DEBUGOUT(S) if (DEBUG_HW) printf(S "\n") +#define HW_DEBUGOUT1(S, A) if (DEBUG_HW) printf(S "\n", A) +#define HW_DEBUGOUT2(S, A, B) if (DEBUG_HW) printf(S "\n", A, B) + +#define MAX_NUM_MULTICAST_ADDRESSES 128 +#define IXGBE_MAX_SCATTER 100 +#define IXGBE_MSIX_BAR 3 +#if 0 +#define IXGBE_TSO_SIZE 65535 +#else +#define IXGBE_TSO_SIZE IXGBE_MAX_FRAME_SIZE +#endif +#define IXGBE_TX_BUFFER_SIZE ((u32) 1514) +#define IXGBE_RX_HDR_SIZE ((u32) 256) +#define CSUM_OFFLOAD 7 /* Bits in csum flags */ + +/* The number of MSIX messages the 82598 supports */ +#define IXGBE_MSGS 18 + +/* For 6.X code compatibility */ +#if __FreeBSD_version < 700000 +#define ETHER_BPF_MTAP BPF_MTAP +#define CSUM_TSO 0 +#define IFCAP_TSO4 0 +#define FILTER_STRAY +#define FILTER_HANDLED +#endif + +/* + * Interrupt Moderation parameters + * for now we hardcode, later + * it would be nice to do dynamic + */ +#define MAX_IRQ_SEC 8000 +#define DEFAULT_ITR 1000000000/(MAX_IRQ_SEC * 256) +#define LINK_ITR 1000000000/(1950 * 256) + +/* Used for auto RX queue configuration */ +extern int mp_ncpus; + +struct ixgbe_tx_buf { + struct mbuf *m_head; + bus_dmamap_t map; +}; + +struct ixgbe_rx_buf { + struct mbuf *m_head; + boolean_t bigbuf; + /* one small and one large map */ + bus_dmamap_t map[2]; +}; + +/* + * Bus dma allocation structure used by ixgbe_dma_malloc and ixgbe_dma_free. + */ +struct ixgbe_dma_alloc { + caddr_t dma_vaddr; + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; + bus_dma_segment_t dma_seg; + bus_size_t dma_size; + int dma_nseg; +}; + +/* + * The transmit ring, one per tx queue + */ +struct tx_ring { + struct ix_softc *sc; + struct mutex tx_mtx; + u32 me; + u32 msix; + u32 eims; + u32 watchdog_timer; + union ixgbe_adv_tx_desc *tx_base; + u_int32_t *tx_hwb; + struct ixgbe_dma_alloc txdma; + struct ixgbe_dma_alloc txwbdma; + u32 next_avail_tx_desc; + u32 next_tx_to_clean; + struct ixgbe_tx_buf *tx_buffers; + volatile u16 tx_avail; + u32 txd_cmd; + bus_dma_tag_t txtag; + /* Soft Stats */ + u32 no_tx_desc_avail; + u32 no_tx_desc_late; + u64 tx_irq; + u64 tx_packets; +}; + + +/* + * The Receive ring, one per rx queue + */ +struct rx_ring { + struct ix_softc *sc; + struct mutex rx_mtx; + u32 me; + u32 msix; + u32 eims; + u32 payload; + union ixgbe_adv_rx_desc *rx_base; + struct ixgbe_dma_alloc rxdma; +#if 0 + struct lro_ctrl lro; +#endif + unsigned int last_cleaned; + unsigned int next_to_check; + struct ixgbe_rx_buf *rx_buffers; + bus_dma_tag_t rxtag[2]; + bus_dmamap_t spare_map[2]; + struct mbuf *fmp; + struct mbuf *lmp; + /* Soft stats */ + u64 rx_irq; + u64 packet_count; + u64 byte_count; +}; + +/* Our adapter structure */ +struct ix_softc { + struct device dev; + struct arpcom arpcom; + + struct ixgbe_hw hw; + struct ixgbe_osdep osdep; + void *powerhook; + void *shutdownhook; + + struct resource *pci_mem; + struct resource *msix_mem; + + /* + * Interrupt resources: + * Oplin has 20 MSIX messages + * so allocate that for now. + */ + void *tag[IXGBE_MSGS]; + struct resource *res[IXGBE_MSGS]; + int rid[IXGBE_MSGS]; + u32 eims_mask; + + struct ifmedia media; + struct timeout timer; + int msix; + int if_flags; + + struct mutex core_mtx; + + /* Legacy Fast Intr handling */ + workq_fn link_task; + + /* Info about the board itself */ + u32 part_num; + bool link_active; + u16 max_frame_size; + u32 link_speed; + u32 tx_int_delay; + u32 tx_abs_int_delay; + u32 rx_int_delay; + u32 rx_abs_int_delay; + + /* Indicates the cluster size to use */ + bool bigbufs; + + /* + * Transmit rings: + * Allocated at run time, an array of rings. + */ + struct tx_ring *tx_rings; + int num_tx_desc; + int num_tx_queues; + + /* + * Receive rings: + * Allocated at run time, an array of rings. + */ + struct rx_ring *rx_rings; + int num_rx_desc; + int num_rx_queues; + u32 rx_process_limit; + u_int optics; + + /* Misc stats maintained by the driver */ + unsigned long dropped_pkts; + unsigned long mbuf_alloc_failed; + unsigned long mbuf_cluster_failed; + unsigned long no_tx_map_avail; + unsigned long no_tx_dma_setup; + unsigned long watchdog_events; + unsigned long tso_tx; + unsigned long linkvec; + unsigned long link_irq; + + struct ixgbe_hw_stats stats; +}; + +#endif /* _IXGBE_H_ */ diff --git a/sys/dev/pci/ixgbe.c b/sys/dev/pci/ixgbe.c new file mode 100644 index 00000000000..e2c836bc14e --- /dev/null +++ b/sys/dev/pci/ixgbe.c @@ -0,0 +1,1851 @@ +/* $OpenBSD: ixgbe.c,v 1.1 2008/06/08 20:01:02 reyk Exp $ */ + +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_common.c,v 1.4 2008/05/16 18:46:30 jfv Exp $*/ + +#include <dev/pci/ixgbe.h> + +static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw); +static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw); +static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); +static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw); +static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw); +static void ixgbe_standby_eeprom(struct ixgbe_hw *hw); +static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, + u16 count); +static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count); +static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); +static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); +static void ixgbe_release_eeprom(struct ixgbe_hw *hw); +static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw); + +static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index); +static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index); +static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); +void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr); +void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq); + +/** + * ixgbe_init_ops_generic - Inits function ptrs + * @hw: pointer to the hardware structure + * + * Initialize the function pointers. + **/ +s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + struct ixgbe_mac_info *mac = &hw->mac; + u32 eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + /* EEPROM */ + eeprom->ops.init_params = &ixgbe_init_eeprom_params_generic; + /* If EEPROM is valid (bit 8 = 1), use EERD otherwise use bit bang */ + if (eec & (1 << 8)) + eeprom->ops.read = &ixgbe_read_eeprom_generic; + else + eeprom->ops.read = &ixgbe_read_eeprom_bit_bang_generic; + eeprom->ops.write = &ixgbe_write_eeprom_generic; + eeprom->ops.validate_checksum = + &ixgbe_validate_eeprom_checksum_generic; + eeprom->ops.update_checksum = &ixgbe_update_eeprom_checksum_generic; + + /* MAC */ + mac->ops.init_hw = &ixgbe_init_hw_generic; + mac->ops.reset_hw = NULL; + mac->ops.start_hw = &ixgbe_start_hw_generic; + mac->ops.clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic; + mac->ops.get_media_type = NULL; + mac->ops.get_mac_addr = &ixgbe_get_mac_addr_generic; + mac->ops.stop_adapter = &ixgbe_stop_adapter_generic; + mac->ops.get_bus_info = &ixgbe_get_bus_info_generic; + mac->ops.read_analog_reg8 = &ixgbe_read_analog_reg8_generic; + mac->ops.write_analog_reg8 = &ixgbe_write_analog_reg8_generic; + + /* LEDs */ + mac->ops.led_on = &ixgbe_led_on_generic; + mac->ops.led_off = &ixgbe_led_off_generic; + mac->ops.blink_led_start = NULL; + mac->ops.blink_led_stop = NULL; + + /* RAR, Multicast, VLAN */ + mac->ops.set_rar = &ixgbe_set_rar_generic; + mac->ops.set_vmdq = NULL; + mac->ops.init_rx_addrs = &ixgbe_init_rx_addrs_generic; + mac->ops.update_uc_addr_list = &ixgbe_update_uc_addr_list_generic; + mac->ops.update_mc_addr_list = &ixgbe_update_mc_addr_list_generic; + mac->ops.enable_mc = &ixgbe_enable_mc_generic; + mac->ops.disable_mc = &ixgbe_disable_mc_generic; + mac->ops.clear_vfta = &ixgbe_clear_vfta_generic; + mac->ops.set_vfta = &ixgbe_set_vfta_generic; + + /* Flow Control */ + mac->ops.setup_fc = NULL; + + /* Link */ + mac->ops.get_link_capabilities = NULL; + mac->ops.setup_link = NULL; + mac->ops.setup_link_speed = NULL; + mac->ops.check_link = NULL; + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware by filling the bus info structure and media type, clears + * all on chip counters, initializes receive address registers, multicast + * table, VLAN filter table, calls routine to set up link and flow control + * settings, and leaves transmit and receive units disabled and uninitialized + **/ +s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) +{ + u32 ctrl_ext; + + /* Set the media type */ + hw->phy.media_type = hw->mac.ops.get_media_type(hw); + + /* Set bus info */ + hw->mac.ops.get_bus_info(hw); + + /* Identify the PHY */ + hw->phy.ops.identify(hw); + + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table + */ + hw->mac.ops.init_rx_addrs(hw); + + /* Clear the VLAN filter table */ + hw->mac.ops.clear_vfta(hw); + + /* Set up link */ + hw->mac.ops.setup_link(hw); + + /* Clear statistics registers */ + hw->mac.ops.clear_hw_cntrs(hw); + + /* Set No Snoop Disable */ + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + IXGBE_WRITE_FLUSH(hw); + + /* Clear adapter stopped flag */ + hw->adapter_stopped = FALSE; + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_init_hw_generic - Generic hardware initialization + * @hw: pointer to hardware structure + * + * Initialize the hardware by resetting the hardware, filling the bus info + * structure and media type, clears all on chip counters, initializes receive + * address registers, multicast table, VLAN filter table, calls routine to set + * up link and flow control settings, and leaves transmit and receive units + * disabled and uninitialized + **/ +s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) +{ + /* Reset the hardware */ + hw->mac.ops.reset_hw(hw); + + /* Start the HW */ + hw->mac.ops.start_hw(hw); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_clear_hw_cntrs_generic - Generic clear hardware counters + * @hw: pointer to hardware structure + * + * Clears all hardware statistics counters by reading them from the hardware + * Statistics counters are clear on read. + **/ +s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw) +{ + u16 i = 0; + + IXGBE_READ_REG(hw, IXGBE_CRCERRS); + IXGBE_READ_REG(hw, IXGBE_ILLERRC); + IXGBE_READ_REG(hw, IXGBE_ERRBC); + IXGBE_READ_REG(hw, IXGBE_MSPDC); + for (i = 0; i < 8; i++) + IXGBE_READ_REG(hw, IXGBE_MPC(i)); + + IXGBE_READ_REG(hw, IXGBE_MLFC); + IXGBE_READ_REG(hw, IXGBE_MRFC); + IXGBE_READ_REG(hw, IXGBE_RLEC); + IXGBE_READ_REG(hw, IXGBE_LXONTXC); + IXGBE_READ_REG(hw, IXGBE_LXONRXC); + IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + + for (i = 0; i < 8; i++) { + IXGBE_READ_REG(hw, IXGBE_PXONTXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXONRXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i)); + } + + IXGBE_READ_REG(hw, IXGBE_PRC64); + IXGBE_READ_REG(hw, IXGBE_PRC127); + IXGBE_READ_REG(hw, IXGBE_PRC255); + IXGBE_READ_REG(hw, IXGBE_PRC511); + IXGBE_READ_REG(hw, IXGBE_PRC1023); + IXGBE_READ_REG(hw, IXGBE_PRC1522); + IXGBE_READ_REG(hw, IXGBE_GPRC); + IXGBE_READ_REG(hw, IXGBE_BPRC); + IXGBE_READ_REG(hw, IXGBE_MPRC); + IXGBE_READ_REG(hw, IXGBE_GPTC); + IXGBE_READ_REG(hw, IXGBE_GORCL); + IXGBE_READ_REG(hw, IXGBE_GORCH); + IXGBE_READ_REG(hw, IXGBE_GOTCL); + IXGBE_READ_REG(hw, IXGBE_GOTCH); + for (i = 0; i < 8; i++) + IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + IXGBE_READ_REG(hw, IXGBE_RUC); + IXGBE_READ_REG(hw, IXGBE_RFC); + IXGBE_READ_REG(hw, IXGBE_ROC); + IXGBE_READ_REG(hw, IXGBE_RJC); + IXGBE_READ_REG(hw, IXGBE_MNGPRC); + IXGBE_READ_REG(hw, IXGBE_MNGPDC); + IXGBE_READ_REG(hw, IXGBE_MNGPTC); + IXGBE_READ_REG(hw, IXGBE_TORL); + IXGBE_READ_REG(hw, IXGBE_TORH); + IXGBE_READ_REG(hw, IXGBE_TPR); + IXGBE_READ_REG(hw, IXGBE_TPT); + IXGBE_READ_REG(hw, IXGBE_PTC64); + IXGBE_READ_REG(hw, IXGBE_PTC127); + IXGBE_READ_REG(hw, IXGBE_PTC255); + IXGBE_READ_REG(hw, IXGBE_PTC511); + IXGBE_READ_REG(hw, IXGBE_PTC1023); + IXGBE_READ_REG(hw, IXGBE_PTC1522); + IXGBE_READ_REG(hw, IXGBE_MPTC); + IXGBE_READ_REG(hw, IXGBE_BPTC); + for (i = 0; i < 16; i++) { + IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + IXGBE_READ_REG(hw, IXGBE_QBRC(i)); + IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + IXGBE_READ_REG(hw, IXGBE_QBTC(i)); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_read_pba_num - Reads part number from EEPROM + * @hw: pointer to hardware structure + * @pba_num: stores the part number from the EEPROM + * + * Reads the part number from the EEPROM. + **/ +s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num) +{ + s32 ret_val; + u16 data; + + DEBUGFUNC("ixgbe_read_pba_num_generic"); + + ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + return ret_val; + } + *pba_num = (u32)(data << 16); + + ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM1_PTR, &data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + return ret_val; + } + *pba_num |= data; + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_get_mac_addr_generic - Generic get MAC address + * @hw: pointer to hardware structure + * @mac_addr: Adapter MAC address + * + * Reads the adapter's MAC address from first Receive Address Register (RAR0) + * A reset of the adapter must be performed prior to calling this function + * in order for the MAC address to have been loaded from the EEPROM into RAR0 + **/ +s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr) +{ + u32 rar_high; + u32 rar_low; + u16 i; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(0)); + rar_low = IXGBE_READ_REG(hw, IXGBE_RAL(0)); + + for (i = 0; i < 4; i++) + mac_addr[i] = (u8)(rar_low >> (i*8)); + + for (i = 0; i < 2; i++) + mac_addr[i+4] = (u8)(rar_high >> (i*8)); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_get_bus_info_generic - Generic set PCI bus info + * @hw: pointer to hardware structure + * + * Sets the PCI bus info (speed, width, type) within the ixgbe_hw structure + **/ +s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw) +{ + u16 link_status; + + hw->bus.type = ixgbe_bus_type_pci_express; + + /* Get the negotiated link width and speed from PCI config space */ + link_status = IXGBE_READ_PCIE_WORD(hw, IXGBE_PCI_LINK_STATUS); + + switch (link_status & IXGBE_PCI_LINK_WIDTH) { + case IXGBE_PCI_LINK_WIDTH_1: + hw->bus.width = ixgbe_bus_width_pcie_x1; + break; + case IXGBE_PCI_LINK_WIDTH_2: + hw->bus.width = ixgbe_bus_width_pcie_x2; + break; + case IXGBE_PCI_LINK_WIDTH_4: + hw->bus.width = ixgbe_bus_width_pcie_x4; + break; + case IXGBE_PCI_LINK_WIDTH_8: + hw->bus.width = ixgbe_bus_width_pcie_x8; + break; + default: + hw->bus.width = ixgbe_bus_width_unknown; + break; + } + + switch (link_status & IXGBE_PCI_LINK_SPEED) { + case IXGBE_PCI_LINK_SPEED_2500: + hw->bus.speed = ixgbe_bus_speed_2500; + break; + case IXGBE_PCI_LINK_SPEED_5000: + hw->bus.speed = ixgbe_bus_speed_5000; + break; + default: + hw->bus.speed = ixgbe_bus_speed_unknown; + break; + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_stop_adapter_generic - Generic stop Tx/Rx units + * @hw: pointer to hardware structure + * + * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts, + * disables transmit and receive units. The adapter_stopped flag is used by + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) +{ + u32 number_of_queues; + u32 reg_val; + u16 i; + + /* + * Set the adapter_stopped flag so other driver functions stop touching + * the hardware + */ + hw->adapter_stopped = TRUE; + + /* Disable the receive unit */ + reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + reg_val &= ~(IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); + IXGBE_WRITE_FLUSH(hw); + msec_delay(2); + + /* Clear interrupt mask to stop from interrupts being generated */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); + + /* Clear any pending interrupts */ + IXGBE_READ_REG(hw, IXGBE_EICR); + + /* Disable the transmit unit. Each queue must be disabled. */ + number_of_queues = hw->mac.max_tx_queues; + for (i = 0; i < number_of_queues; i++) { + reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); + if (reg_val & IXGBE_TXDCTL_ENABLE) { + reg_val &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), reg_val); + } + } + + /* + * Prevent the PCI-E bus from from hanging by disabling PCI-E master + * access and verify no pending requests + */ + if (ixgbe_disable_pcie_master(hw) != IXGBE_SUCCESS) { + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_led_on_generic - Turns on the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn on + **/ +s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index) +{ + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* To turn on the LED, set mode to ON. */ + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_led_off_generic - Turns off the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn off + **/ +s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index) +{ + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* To turn off the LED, set mode to OFF. */ + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_init_eeprom_params_generic - Initialize EEPROM params + * @hw: pointer to hardware structure + * + * Initializes the EEPROM parameters ixgbe_eeprom_info within the + * ixgbe_hw struct in order to set up EEPROM access. + **/ +s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + u32 eec; + u16 eeprom_size; + + if (eeprom->type == ixgbe_eeprom_uninitialized) { + eeprom->type = ixgbe_eeprom_none; + + /* + * Check for EEPROM present first. + * If not present leave as none + */ + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + if (eec & IXGBE_EEC_PRES) { + eeprom->type = ixgbe_eeprom_spi; + + /* + * SPI EEPROM is assumed here. This code would need to + * change if a future EEPROM is not SPI. + */ + eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >> + IXGBE_EEC_SIZE_SHIFT); + eeprom->word_size = 1 << (eeprom_size + + IXGBE_EEPROM_WORD_SIZE_SHIFT); + } + + if (eec & IXGBE_EEC_ADDR_SIZE) + eeprom->address_bits = 16; + else + eeprom->address_bits = 8; + DEBUGOUT3("Eeprom params: type = %d, size = %d, address bits: " + "%d\n", eeprom->type, eeprom->word_size, + eeprom->address_bits); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be written to + * @data: 16 bit word to be written to the EEPROM + * + * If ixgbe_eeprom_update_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. + **/ +s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +{ + s32 status; + u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI; + + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + /* Prepare the EEPROM for writing */ + status = ixgbe_acquire_eeprom(hw); + + if (status == IXGBE_SUCCESS) { + if (ixgbe_ready_eeprom(hw) != IXGBE_SUCCESS) { + ixgbe_release_eeprom(hw); + status = IXGBE_ERR_EEPROM; + } + } + + if (status == IXGBE_SUCCESS) { + ixgbe_standby_eeprom(hw); + + /* Send the WRITE ENABLE command (8 bit opcode ) */ + ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_WREN_OPCODE_SPI, + IXGBE_EEPROM_OPCODE_BITS); + + ixgbe_standby_eeprom(hw); + + /* + * Some SPI eeproms use the 8th address bit embedded in the + * opcode + */ + if ((hw->eeprom.address_bits == 8) && (offset >= 128)) + write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, write_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), + hw->eeprom.address_bits); + + /* Send the data */ + data = (data >> 8) | (data << 8); + ixgbe_shift_out_eeprom_bits(hw, data, 16); + ixgbe_standby_eeprom(hw); + + msec_delay(10); + + /* Done with writing - release the EEPROM */ + ixgbe_release_eeprom(hw); + } + +out: + return status; +} + +/** + * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be read + * @data: read 16 bit value from EEPROM + * + * Reads 16 bit value from EEPROM through bit-bang method + **/ +s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 *data) +{ + s32 status; + u16 word_in; + u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; + + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + /* Prepare the EEPROM for reading */ + status = ixgbe_acquire_eeprom(hw); + + if (status == IXGBE_SUCCESS) { + if (ixgbe_ready_eeprom(hw) != IXGBE_SUCCESS) { + ixgbe_release_eeprom(hw); + status = IXGBE_ERR_EEPROM; + } + } + + if (status == IXGBE_SUCCESS) { + ixgbe_standby_eeprom(hw); + + /* + * Some SPI eeproms use the 8th address bit embedded in the + * opcode + */ + if ((hw->eeprom.address_bits == 8) && (offset >= 128)) + read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, read_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), + hw->eeprom.address_bits); + + /* Read the data. */ + word_in = ixgbe_shift_in_eeprom_bits(hw, 16); + *data = (word_in >> 8) | (word_in << 8); + + /* End this read operation */ + ixgbe_release_eeprom(hw); + } + +out: + return status; +} + +/** + * ixgbe_read_eeprom_generic - Read EEPROM word using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) +{ + u32 eerd; + s32 status; + + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) + + IXGBE_EEPROM_READ_REG_START; + + IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); + status = ixgbe_poll_eeprom_eerd_done(hw); + + if (status == IXGBE_SUCCESS) + *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >> + IXGBE_EEPROM_READ_REG_DATA); + else + DEBUGOUT("Eeprom read timed out\n"); + +out: + return status; +} + +/** + * ixgbe_poll_eeprom_eerd_done - Poll EERD status + * @hw: pointer to hardware structure + * + * Polls the status bit (bit 1) of the EERD to determine when the read is done. + **/ +static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw) +{ + u32 i; + u32 reg; + s32 status = IXGBE_ERR_EEPROM; + + for (i = 0; i < IXGBE_EERD_ATTEMPTS; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_EERD); + if (reg & IXGBE_EEPROM_READ_REG_DONE) { + status = IXGBE_SUCCESS; + break; + } + usec_delay(5); + } + return status; +} + +/** + * ixgbe_acquire_eeprom - Acquire EEPROM using bit-bang + * @hw: pointer to hardware structure + * + * Prepares EEPROM for access using bit-bang method. This function should + * be called before issuing a command to the EEPROM. + **/ +static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_SUCCESS; + u32 eec; + u32 i; + + if (ixgbe_acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != IXGBE_SUCCESS) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == IXGBE_SUCCESS) { + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + /* Request EEPROM Access */ + eec |= IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + + for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) { + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + if (eec & IXGBE_EEC_GNT) + break; + usec_delay(5); + } + + /* Release if grant not acquired */ + if (!(eec & IXGBE_EEC_GNT)) { + eec &= ~IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + DEBUGOUT("Could not acquire EEPROM grant\n"); + + ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + status = IXGBE_ERR_EEPROM; + } + } + + /* Setup EEPROM for Read/Write */ + if (status == IXGBE_SUCCESS) { + /* Clear CS and SK */ + eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK); + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + usec_delay(1); + } + return status; +} + +/** + * ixgbe_get_eeprom_semaphore - Get hardware semaphore + * @hw: pointer to hardware structure + * + * Sets the hardware semaphores so EEPROM access can occur for bit-bang method + **/ +static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_EEPROM; + u32 timeout; + u32 i; + u32 swsm; + + /* Set timeout value based on size of EEPROM */ + timeout = hw->eeprom.word_size + 1; + + /* Get SMBI software semaphore between device drivers first */ + for (i = 0; i < timeout; i++) { + /* + * If the SMBI bit is 0 when we read it, then the bit will be + * set and we have the semaphore + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (!(swsm & IXGBE_SWSM_SMBI)) { + status = IXGBE_SUCCESS; + break; + } + msec_delay(1); + } + + /* Now get the semaphore between SW/FW through the SWESMBI bit */ + if (status == IXGBE_SUCCESS) { + for (i = 0; i < timeout; i++) { + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + + /* Set the SW EEPROM semaphore bit to request access */ + swsm |= IXGBE_SWSM_SWESMBI; + IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); + + /* + * If we set the bit successfully then we got the + * semaphore. + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (swsm & IXGBE_SWSM_SWESMBI) + break; + + usec_delay(50); + } + + /* + * Release semaphores and return error if SW EEPROM semaphore + * was not granted because we don't have access to the EEPROM + */ + if (i >= timeout) { + DEBUGOUT("Driver can't access the Eeprom - Semaphore " + "not granted.\n"); + ixgbe_release_eeprom_semaphore(hw); + status = IXGBE_ERR_EEPROM; + } + } + + return status; +} + +/** + * ixgbe_release_eeprom_semaphore - Release hardware semaphore + * @hw: pointer to hardware structure + * + * This function clears hardware semaphore bits. + **/ +static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) +{ + u32 swsm; + + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + + /* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */ + swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI); + IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); + IXGBE_WRITE_FLUSH(hw); +} + +/** + * ixgbe_ready_eeprom - Polls for EEPROM ready + * @hw: pointer to hardware structure + **/ +static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_SUCCESS; + u16 i; + u8 spi_stat_reg; + + /* + * Read "Status Register" repeatedly until the LSB is cleared. The + * EEPROM will signal that the command has been completed by clearing + * bit 0 of the internal status register. If it's not cleared within + * 5 milliseconds, then error out. + */ + for (i = 0; i < IXGBE_EEPROM_MAX_RETRY_SPI; i += 5) { + ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_RDSR_OPCODE_SPI, + IXGBE_EEPROM_OPCODE_BITS); + spi_stat_reg = (u8)ixgbe_shift_in_eeprom_bits(hw, 8); + if (!(spi_stat_reg & IXGBE_EEPROM_STATUS_RDY_SPI)) + break; + + usec_delay(5); + ixgbe_standby_eeprom(hw); + }; + + /* + * On some parts, SPI write time could vary from 0-20mSec on 3.3V + * devices (and only 0-5mSec on 5V devices) + */ + if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) { + DEBUGOUT("SPI EEPROM Status error\n"); + status = IXGBE_ERR_EEPROM; + } + + return status; +} + +/** + * ixgbe_standby_eeprom - Returns EEPROM to a "standby" state + * @hw: pointer to hardware structure + **/ +static void ixgbe_standby_eeprom(struct ixgbe_hw *hw) +{ + u32 eec; + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + /* Toggle CS to flush commands */ + eec |= IXGBE_EEC_CS; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + usec_delay(1); + eec &= ~IXGBE_EEC_CS; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + usec_delay(1); +} + +/** + * ixgbe_shift_out_eeprom_bits - Shift data bits out to the EEPROM. + * @hw: pointer to hardware structure + * @data: data to send to the EEPROM + * @count: number of bits to shift out + **/ +static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, + u16 count) +{ + u32 eec; + u32 mask; + u32 i; + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + /* + * Mask is used to shift "count" bits of "data" out to the EEPROM + * one bit at a time. Determine the starting bit based on count + */ + mask = 0x01 << (count - 1); + + for (i = 0; i < count; i++) { + /* + * A "1" is shifted out to the EEPROM by setting bit "DI" to a + * "1", and then raising and then lowering the clock (the SK + * bit controls the clock input to the EEPROM). A "0" is + * shifted out to the EEPROM by setting "DI" to "0" and then + * raising and then lowering the clock. + */ + if (data & mask) + eec |= IXGBE_EEC_DI; + else + eec &= ~IXGBE_EEC_DI; + + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + + usec_delay(1); + + ixgbe_raise_eeprom_clk(hw, &eec); + ixgbe_lower_eeprom_clk(hw, &eec); + + /* + * Shift mask to signify next bit of data to shift in to the + * EEPROM + */ + mask = mask >> 1; + }; + + /* We leave the "DI" bit set to "0" when we leave this routine. */ + eec &= ~IXGBE_EEC_DI; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); +} + +/** + * ixgbe_shift_in_eeprom_bits - Shift data bits in from the EEPROM + * @hw: pointer to hardware structure + **/ +static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count) +{ + u32 eec; + u32 i; + u16 data = 0; + + /* + * In order to read a register from the EEPROM, we need to shift + * 'count' bits in from the EEPROM. Bits are "shifted in" by raising + * the clock input to the EEPROM (setting the SK bit), and then reading + * the value of the "DO" bit. During this "shifting in" process the + * "DI" bit should always be clear. + */ + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + eec &= ~(IXGBE_EEC_DO | IXGBE_EEC_DI); + + for (i = 0; i < count; i++) { + data = data << 1; + ixgbe_raise_eeprom_clk(hw, &eec); + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + eec &= ~(IXGBE_EEC_DI); + if (eec & IXGBE_EEC_DO) + data |= 1; + + ixgbe_lower_eeprom_clk(hw, &eec); + } + + return data; +} + +/** + * ixgbe_raise_eeprom_clk - Raises the EEPROM's clock input. + * @hw: pointer to hardware structure + * @eec: EEC register's current value + **/ +static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) +{ + /* + * Raise the clock input to the EEPROM + * (setting the SK bit), then delay + */ + *eec = *eec | IXGBE_EEC_SK; + IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec); + IXGBE_WRITE_FLUSH(hw); + usec_delay(1); +} + +/** + * ixgbe_lower_eeprom_clk - Lowers the EEPROM's clock input. + * @hw: pointer to hardware structure + * @eecd: EECD's current value + **/ +static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) +{ + /* + * Lower the clock input to the EEPROM (clearing the SK bit), then + * delay + */ + *eec = *eec & ~IXGBE_EEC_SK; + IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec); + IXGBE_WRITE_FLUSH(hw); + usec_delay(1); +} + +/** + * ixgbe_release_eeprom - Release EEPROM, release semaphores + * @hw: pointer to hardware structure + **/ +static void ixgbe_release_eeprom(struct ixgbe_hw *hw) +{ + u32 eec; + + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + + eec |= IXGBE_EEC_CS; /* Pull CS high */ + eec &= ~IXGBE_EEC_SK; /* Lower SCK */ + + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + + usec_delay(1); + + /* Stop requesting EEPROM access */ + eec &= ~IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + + ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); +} + +/** + * ixgbe_calc_eeprom_checksum - Calculates and returns the checksum + * @hw: pointer to hardware structure + **/ +static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw) +{ + u16 i; + u16 j; + u16 checksum = 0; + u16 length = 0; + u16 pointer = 0; + u16 word = 0; + + /* Include 0x0-0x3F in the checksum */ + for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { + if (hw->eeprom.ops.read(hw, i, &word) != IXGBE_SUCCESS) { + DEBUGOUT("EEPROM read failed\n"); + break; + } + checksum += word; + } + + /* Include all data from pointers except for the fw pointer */ + for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) { + hw->eeprom.ops.read(hw, i, &pointer); + + /* Make sure the pointer seems valid */ + if (pointer != 0xFFFF && pointer != 0) { + hw->eeprom.ops.read(hw, pointer, &length); + + if (length != 0xFFFF && length != 0) { + for (j = pointer+1; j <= pointer+length; j++) { + hw->eeprom.ops.read(hw, j, &word); + checksum += word; + } + } + } + } + + checksum = (u16)IXGBE_EEPROM_SUM - checksum; + + return checksum; +} + +/** + * ixgbe_validate_eeprom_checksum_generic - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum_val: calculated checksum + * + * Performs checksum calculation and validates the EEPROM checksum. If the + * caller does not need checksum_val, the value can be NULL. + **/ +s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, + u16 *checksum_val) +{ + s32 status; + u16 checksum; + u16 read_checksum = 0; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); + + if (status == IXGBE_SUCCESS) { + checksum = ixgbe_calc_eeprom_checksum(hw); + + hw->eeprom.ops.read(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); + + /* + * Verify read checksum from EEPROM is the same as + * calculated checksum + */ + if (read_checksum != checksum) + status = IXGBE_ERR_EEPROM_CHECKSUM; + + /* If the user cares, return the calculated checksum */ + if (checksum_val) + *checksum_val = checksum; + } else { + DEBUGOUT("EEPROM read failed\n"); + } + + return status; +} + +/** + * ixgbe_update_eeprom_checksum_generic - Updates the EEPROM checksum + * @hw: pointer to hardware structure + **/ +s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw) +{ + s32 status; + u16 checksum; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); + + if (status == IXGBE_SUCCESS) { + checksum = ixgbe_calc_eeprom_checksum(hw); + status = hw->eeprom.ops.write(hw, IXGBE_EEPROM_CHECKSUM, + checksum); + } else { + DEBUGOUT("EEPROM read failed\n"); + } + + return status; +} + +/** + * ixgbe_validate_mac_addr - Validate MAC address + * @mac_addr: pointer to MAC address. + * + * Tests a MAC address to ensure it is a valid Individual Address + **/ +s32 ixgbe_validate_mac_addr(u8 *mac_addr) +{ + s32 status = IXGBE_SUCCESS; + + /* Make sure it is not a multicast address */ + if (IXGBE_IS_MULTICAST(mac_addr)) { + DEBUGOUT("MAC address is multicast\n"); + status = IXGBE_ERR_INVALID_MAC_ADDR; + /* Not a broadcast address */ + } else if (IXGBE_IS_BROADCAST(mac_addr)) { + DEBUGOUT("MAC address is broadcast\n"); + status = IXGBE_ERR_INVALID_MAC_ADDR; + /* Reject the zero address */ + } else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 && + mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) { + DEBUGOUT("MAC address is all zeros\n"); + status = IXGBE_ERR_INVALID_MAC_ADDR; + } + return status; +} + +/** + * ixgbe_set_rar_generic - Set Rx address register + * @hw: pointer to hardware structure + * @index: Receive address register to write + * @addr: Address to put into receive address register + * @vmdq: VMDq "set" or "pool" index + * @enable_addr: set flag that address is active + * + * Puts an ethernet address into a receive address register. + **/ +s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, + u32 enable_addr) +{ + u32 rar_low, rar_high; + u32 rar_entries = hw->mac.num_rar_entries; + + /* setup VMDq pool selection before this RAR gets enabled */ + hw->mac.ops.set_vmdq(hw, index, vmdq); + + /* Make sure we are using a valid rar index range */ + if (index < rar_entries) { + /* + * HW expects these in little endian so we reverse the byte + * order from network order (big endian) to little endian + */ + rar_low = ((u32)addr[0] | + ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | + ((u32)addr[3] << 24)); + /* + * Some parts put the VMDq setting in the extra RAH bits, + * so save everything except the lower 16 bits that hold part + * of the address and the address valid bit. + */ + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); + rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); + rar_high |= ((u32)addr[4] | ((u32)addr[5] << 8)); + + if (enable_addr != 0) + rar_high |= IXGBE_RAH_AV; + + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + } else { + DEBUGOUT("Current RAR index is out of range."); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_enable_rar - Enable Rx address register + * @hw: pointer to hardware structure + * @index: index into the RAR table + * + * Enables the select receive address register. + **/ +static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index) +{ + u32 rar_high; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); + rar_high |= IXGBE_RAH_AV; + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); +} + +/** + * ixgbe_disable_rar - Disable Rx address register + * @hw: pointer to hardware structure + * @index: index into the RAR table + * + * Disables the select receive address register. + **/ +static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index) +{ + u32 rar_high; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); + rar_high &= (~IXGBE_RAH_AV); + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); +} + +/** + * ixgbe_init_rx_addrs_generic - Initializes receive address filters. + * @hw: pointer to hardware structure + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive address registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + **/ +s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) +{ + u32 i; + u32 rar_entries = hw->mac.num_rar_entries; + + /* + * If the current mac address is valid, assume it is a software override + * to the permanent address. + * Otherwise, use the permanent address from the eeprom. + */ + if (ixgbe_validate_mac_addr(hw->mac.addr) == + IXGBE_ERR_INVALID_MAC_ADDR) { + /* Get the MAC address from the RAR0 for later reference */ + hw->mac.ops.get_mac_addr(hw, hw->mac.addr); + + DEBUGOUT3(" Keeping Current RAR0 Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + DEBUGOUT3("%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + } else { + /* Setup the receive address. */ + DEBUGOUT("Overriding MAC Address in RAR[0]\n"); + DEBUGOUT3(" New MAC Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + DEBUGOUT3("%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + } + hw->addr_ctrl.overflow_promisc = 0; + + hw->addr_ctrl.rar_used_count = 1; + + /* Zero out the other receive addresses. */ + DEBUGOUT1("Clearing RAR[1-%d]\n", rar_entries - 1); + for (i = 1; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Clear the MTA */ + hw->addr_ctrl.mc_addr_in_rar_count = 0; + hw->addr_ctrl.mta_in_use = 0; + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); + + DEBUGOUT(" Clearing MTA\n"); + for (i = 0; i < hw->mac.mcft_size; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_add_uc_addr - Adds a secondary unicast address. + * @hw: pointer to hardware structure + * @addr: new address + * + * Adds it to unused receive address register or goes into promiscuous mode. + **/ +void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) +{ + u32 rar_entries = hw->mac.num_rar_entries; + u32 rar; + + DEBUGOUT6(" UC Addr = %.2X %.2X %.2X %.2X %.2X %.2X\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + + /* + * Place this address in the RAR if there is room, + * else put the controller into promiscuous mode + */ + if (hw->addr_ctrl.rar_used_count < rar_entries) { + rar = hw->addr_ctrl.rar_used_count - + hw->addr_ctrl.mc_addr_in_rar_count; + hw->mac.ops.set_rar(hw, rar, addr, vmdq, IXGBE_RAH_AV); + DEBUGOUT1("Added a secondary address to RAR[%d]\n", rar); + hw->addr_ctrl.rar_used_count++; + } else { + hw->addr_ctrl.overflow_promisc++; + } + + DEBUGOUT("ixgbe_add_uc_addr Complete\n"); +} + +/** + * ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses + * @hw: pointer to hardware structure + * @addr_list: the list of new addresses + * @addr_count: number of addresses + * @next: iterator function to walk the address list + * + * The given list replaces any existing list. Clears the secondary addrs from + * receive address registers. Uses unused receive address registers for the + * first secondary addresses, and falls back to promiscuous mode as needed. + * + * Drivers using secondary unicast addresses must set user_set_promisc when + * manually putting the device into promiscuous mode. + **/ +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, + u32 addr_count, ixgbe_mc_addr_itr next) +{ + u8 *addr; + u32 i; + u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc; + u32 uc_addr_in_use; + u32 fctrl; + u32 vmdq; + + /* + * Clear accounting of old secondary address list, + * don't count RAR[0] + */ + uc_addr_in_use = hw->addr_ctrl.rar_used_count - + hw->addr_ctrl.mc_addr_in_rar_count - 1; + hw->addr_ctrl.rar_used_count -= uc_addr_in_use; + hw->addr_ctrl.overflow_promisc = 0; + + /* Zero out the other receive addresses */ + DEBUGOUT1("Clearing RAR[1-%d]\n", uc_addr_in_use); + for (i = 1; i <= uc_addr_in_use; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Add the new addresses */ + for (i = 0; i < addr_count; i++) { + DEBUGOUT(" Adding the secondary addresses:\n"); + addr = next(hw, &addr_list, &vmdq); + ixgbe_add_uc_addr(hw, addr, vmdq); + } + + if (hw->addr_ctrl.overflow_promisc) { + /* enable promisc if not already in overflow or set by user */ + if (!old_promisc_setting && !hw->addr_ctrl.user_set_promisc) { + DEBUGOUT( " Entering address overflow promisc mode\n"); + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + fctrl |= IXGBE_FCTRL_UPE; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + } + } else { + /* only disable if set by overflow, not by user */ + if (old_promisc_setting && !hw->addr_ctrl.user_set_promisc) { + DEBUGOUT(" Leaving address overflow promisc mode\n"); + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + fctrl &= ~IXGBE_FCTRL_UPE; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + } + } + + DEBUGOUT("ixgbe_update_uc_addr_list_generic Complete\n"); + return IXGBE_SUCCESS; +} + +/** + * ixgbe_mta_vector - Determines bit-vector in multicast table to set + * @hw: pointer to hardware structure + * @mc_addr: the multicast address + * + * Extracts the 12 bits, from a multicast address, to determine which + * bit-vector to set in the multicast table. The hardware uses 12 bits, from + * incoming rx multicast addresses, to determine the bit-vector to check in + * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set + * by the MO field of the MCSTCTRL. The MO field is set during initialization + * to mc_filter_type. + **/ +static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 vector = 0; + + switch (hw->mac.mc_filter_type) { + case 0: /* use bits [47:36] of the address */ + vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); + break; + case 1: /* use bits [46:35] of the address */ + vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); + break; + case 2: /* use bits [45:34] of the address */ + vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); + break; + case 3: /* use bits [43:32] of the address */ + vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); + break; + default: /* Invalid mc_filter_type */ + DEBUGOUT("MC filter type param set incorrectly\n"); + ASSERT(0); + break; + } + + /* vector can only be 12-bits or boundary will be exceeded */ + vector &= 0xFFF; + return vector; +} + +/** + * ixgbe_set_mta - Set bit-vector in multicast table + * @hw: pointer to hardware structure + * @hash_value: Multicast address hash value + * + * Sets the bit-vector in the multicast table. + **/ +void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 vector; + u32 vector_bit; + u32 vector_reg; + u32 mta_reg; + + hw->addr_ctrl.mta_in_use++; + + vector = ixgbe_mta_vector(hw, mc_addr); + DEBUGOUT1(" bit-vector = 0x%03X\n", vector); + + /* + * The MTA is a register array of 128 32-bit registers. It is treated + * like an array of 4096 bits. We want to set bit + * BitArray[vector_value]. So we figure out what register the bit is + * in, read it, OR in the new bit, then write back the new value. The + * register is determined by the upper 7 bits of the vector value and + * the bit within that register are determined by the lower 5 bits of + * the value. + */ + vector_reg = (vector >> 5) & 0x7F; + vector_bit = vector & 0x1F; + mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg)); + mta_reg |= (1 << vector_bit); + IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); +} + +/** + * ixgbe_add_mc_addr - Adds a multicast address. + * @hw: pointer to hardware structure + * @mc_addr: new multicast address + * + * Adds it to unused receive address register or to the multicast table. + **/ +void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 rar_entries = hw->mac.num_rar_entries; + u32 rar; + + DEBUGOUT6(" MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n", + mc_addr[0], mc_addr[1], mc_addr[2], + mc_addr[3], mc_addr[4], mc_addr[5]); + + /* + * Place this multicast address in the RAR if there is room, + * else put it in the MTA + */ + if (hw->addr_ctrl.rar_used_count < rar_entries) { + /* use RAR from the end up for multicast */ + rar = rar_entries - hw->addr_ctrl.mc_addr_in_rar_count - 1; + hw->mac.ops.set_rar(hw, rar, mc_addr, 0, IXGBE_RAH_AV); + DEBUGOUT1("Added a multicast address to RAR[%d]\n", rar); + hw->addr_ctrl.rar_used_count++; + hw->addr_ctrl.mc_addr_in_rar_count++; + } else { + ixgbe_set_mta(hw, mc_addr); + } + + DEBUGOUT("ixgbe_add_mc_addr Complete\n"); +} + +/** + * ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses + * @hw: pointer to hardware structure + * @mc_addr_list: the list of new multicast addresses + * @mc_addr_count: number of addresses + * @next: iterator function to walk the multicast address list + * + * The given list replaces any existing list. Clears the MC addrs from receive + * address registers and the multicast table. Uses unused receive address + * registers for the first multicast addresses, and hashes the rest into the + * multicast table. + **/ +s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, ixgbe_mc_addr_itr next) +{ + u32 i; + u32 rar_entries = hw->mac.num_rar_entries; + u32 vmdq; + + /* + * Set the new number of MC addresses that we are being requested to + * use. + */ + hw->addr_ctrl.num_mc_addrs = mc_addr_count; + hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count; + hw->addr_ctrl.mc_addr_in_rar_count = 0; + hw->addr_ctrl.mta_in_use = 0; + + /* Zero out the other receive addresses. */ + DEBUGOUT2("Clearing RAR[%d-%d]\n", hw->addr_ctrl.rar_used_count, + rar_entries - 1); + for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Clear the MTA */ + DEBUGOUT(" Clearing MTA\n"); + for (i = 0; i < hw->mac.mcft_size; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + + /* Add the new addresses */ + for (i = 0; i < mc_addr_count; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + ixgbe_add_mc_addr(hw, next(hw, &mc_addr_list, &vmdq)); + } + + /* Enable mta */ + if (hw->addr_ctrl.mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, + IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); + + DEBUGOUT("ixgbe_update_mc_addr_list_generic Complete\n"); + return IXGBE_SUCCESS; +} + +/** + * ixgbe_enable_mc_generic - Enable multicast address in RAR + * @hw: pointer to hardware structure + * + * Enables multicast address in RAR and the use of the multicast hash table. + **/ +s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw) +{ + u32 i; + u32 rar_entries = hw->mac.num_rar_entries; + struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; + + if (a->mc_addr_in_rar_count > 0) + for (i = (rar_entries - a->mc_addr_in_rar_count); + i < rar_entries; i++) + ixgbe_enable_rar(hw, i); + + if (a->mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, IXGBE_MCSTCTRL_MFE | + hw->mac.mc_filter_type); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_disable_mc_generic - Disable multicast address in RAR + * @hw: pointer to hardware structure + * + * Disables multicast address in RAR and the use of the multicast hash table. + **/ +s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) +{ + u32 i; + u32 rar_entries = hw->mac.num_rar_entries; + struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; + + if (a->mc_addr_in_rar_count > 0) + for (i = (rar_entries - a->mc_addr_in_rar_count); + i < rar_entries; i++) + ixgbe_disable_rar(hw, i); + + if (a->mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_clear_vfta_generic - Clear VLAN filter table + * @hw: pointer to hardware structure + * + * Clears the VLAN filer table, and the VMDq index associated with the filter + **/ +s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw) +{ + u32 offset; + u32 vlanbyte; + + for (offset = 0; offset < hw->mac.vft_size; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); + + for (vlanbyte = 0; vlanbyte < 4; vlanbyte++) + for (offset = 0; offset < hw->mac.vft_size; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset), + 0); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_set_vfta_generic - Set VLAN filter table + * @hw: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * @vind: VMDq output index that maps queue to VLAN id in VFTA + * @vlan_on: boolean flag to turn on/off VLAN in VFTA + * + * Turn on/off specified VLAN in the VLAN filter table. + **/ +s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) +{ + u32 VftaIndex; + u32 BitOffset; + u32 VftaReg; + u32 VftaByte; + + /* Determine 32-bit word position in array */ + VftaIndex = (vlan >> 5) & 0x7F; /* upper seven bits */ + + /* Determine the location of the (VMD) queue index */ + VftaByte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */ + BitOffset = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */ + + /* Set the nibble for VMD queue index */ + VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex)); + VftaReg &= (~(0x0F << BitOffset)); + VftaReg |= (vind << BitOffset); + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg); + + /* Determine the location of the bit for this VLAN id */ + BitOffset = vlan & 0x1F; /* lower five bits */ + + VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex)); + if (vlan_on) + /* Turn on this VLAN id */ + VftaReg |= (1 << BitOffset); + else + /* Turn off this VLAN id */ + VftaReg &= ~(1 << BitOffset); + IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_disable_pcie_master - Disable PCI-express master access + * @hw: pointer to hardware structure + * + * Disables PCI-Express master access and verifies there are no pending + * requests. IXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable + * bit hasn't caused the master requests to be disabled, else IXGBE_SUCCESS + * is returned signifying master requests disabled. + **/ +s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) +{ + u32 ctrl; + s32 i; + s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + ctrl |= IXGBE_CTRL_GIO_DIS; + IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); + + for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { + if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) { + status = IXGBE_SUCCESS; + break; + } + usec_delay(100); + } + + return status; +} + + +/** + * ixgbe_acquire_swfw_sync - Acquire SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to acquire + * + * Acquires the SWFW semaphore thought the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) +{ + u32 gssr; + u32 swmask = mask; + u32 fwmask = mask << 5; + s32 timeout = 200; + + while (timeout) { + if (ixgbe_get_eeprom_semaphore(hw)) + return -IXGBE_ERR_SWFW_SYNC; + + gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); + if (!(gssr & (fwmask | swmask))) + break; + + /* + * Firmware currently using resource (fwmask) or other software + * thread currently using resource (swmask) + */ + ixgbe_release_eeprom_semaphore(hw); + msec_delay(5); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Driver can't access resource, GSSR timeout.\n"); + return -IXGBE_ERR_SWFW_SYNC; + } + + gssr |= swmask; + IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + + ixgbe_release_eeprom_semaphore(hw); + return IXGBE_SUCCESS; +} + +/** + * ixgbe_release_swfw_sync - Release SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to release + * + * Releases the SWFW semaphore thought the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) +{ + u32 gssr; + u32 swmask = mask; + + ixgbe_get_eeprom_semaphore(hw); + + gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); + gssr &= ~swmask; + IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + + ixgbe_release_eeprom_semaphore(hw); +} + +/** + * ixgbe_read_analog_reg8_generic - Reads 8 bit Atlas analog register + * @hw: pointer to hardware structure + * @reg: analog register to read + * @val: read value + * + * Performs read operation to Atlas analog register specified. + **/ +s32 ixgbe_read_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 *val) +{ + u32 atlas_ctl; + + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, IXGBE_ATLASCTL_WRITE_CMD | (reg << 8)); + IXGBE_WRITE_FLUSH(hw); + usec_delay(10); + atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); + *val = (u8)atlas_ctl; + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_write_analog_reg8_generic - Writes 8 bit Atlas analog register + * @hw: pointer to hardware structure + * @reg: atlas register to write + * @val: value to write + * + * Performs write operation to Atlas analog register specified. + **/ +s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val) +{ + u32 atlas_ctl; + + atlas_ctl = (reg << 8) | val; + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl); + IXGBE_WRITE_FLUSH(hw); + usec_delay(10); + + return IXGBE_SUCCESS; +} + diff --git a/sys/dev/pci/ixgbe.h b/sys/dev/pci/ixgbe.h new file mode 100644 index 00000000000..10b8e818795 --- /dev/null +++ b/sys/dev/pci/ixgbe.h @@ -0,0 +1,236 @@ +/* $OpenBSD: ixgbe.h,v 1.1 2008/06/08 20:01:02 reyk Exp $ */ + +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_osdep.h,v 1.4 2008/05/16 18:46:30 jfv Exp $*/ + +#ifndef _IXGBE_OS_H_ +#define _IXGBE_OS_H_ + +#include "bpfilter.h" +#include "vlan.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <sys/timeout.h> +#include <sys/workq.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/bpf.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> + +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif + +#if NVLAN > 0 +#include <net/if_types.h> +#include <net/if_vlan_var.h> +#endif + +#include <uvm/uvm_extern.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <dev/rndvar.h> + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef boolean_t bool; + +#include <dev/pci/ixgbe_type.h> + +#define ASSERT(x) if(!(x)) panic("IXGBE: x") + +/* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */ +#define usec_delay(x) DELAY(x) +#define msec_delay(x) DELAY(1000*(x)) + +#define DBG 0 +#define MSGOUT(S, A, B) printf(S "\n", A, B) +#define DEBUGFUNC(F) DEBUGOUT(F); +#if DBG +#define DEBUGOUT(S) printf(S "\n") +#define DEBUGOUT1(S,A) printf(S "\n",A) +#define DEBUGOUT2(S,A,B) printf(S "\n",A,B) +#define DEBUGOUT3(S,A,B,C) printf(S "\n",A,B,C) +#define DEBUGOUT7(S,A,B,C,D,E,F,G) printf(S "\n",A,B,C,D,E,F,G) +#else +#define DEBUGOUT(S) +#define DEBUGOUT1(S,A) +#define DEBUGOUT2(S,A,B) +#define DEBUGOUT3(S,A,B,C) +#define DEBUGOUT6(S,A,B,C,D,E,F) +#define DEBUGOUT7(S,A,B,C,D,E,F,G) +#endif + +#define FALSE 0 +#define TRUE 1 +#define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */ +#define PCI_COMMAND_REGISTER PCIR_COMMAND + +typedef struct device device_t; +#define TUNABLE_INT(x...) +#define DRIVER_MODULE(x...) +#define MODULE_DEPEND(x...) + +/* This is needed by the shared code */ +struct ixgbe_hw; +extern u16 ixgbe_read_pci_cfg(struct ixgbe_hw *, u32); +#define IXGBE_READ_PCIE_WORD ixgbe_read_pci_cfg + +struct ixgbe_osdep { + bus_dma_tag_t os_dmat; + bus_space_tag_t os_memt; + bus_space_handle_t os_memh; + + bus_size_t os_memsize; + bus_addr_t os_membase; + + void *os_sc; + struct pci_attach_args *os_pa; +}; + +#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS) + +#define IXGBE_READ_REG(a, reg) \ + bus_space_read_4(((struct ixgbe_osdep *)(a)->back)->os_memt, \ + ((struct ixgbe_osdep *)(a)->back)->os_memh, reg) +#define IXGBE_WRITE_REG(a, reg, value) \ + bus_space_write_4(((struct ixgbe_osdep *)(a)->back)->os_memt, \ + ((struct ixgbe_osdep *)(a)->back)->os_memh, reg, value) +#define IXGBE_READ_REG_ARRAY(a, reg, offset) \ + bus_space_read_4(((struct ixgbe_osdep *)(a)->back)->os_memt, \ + ((struct ixgbe_osdep *)(a)->back)->os_memh, (reg + ((offset) << 2)))) +#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) \ + bus_space_write_4(((struct ixgbe_osdep *)(a)->back)->os_memt, \ + ((struct ixgbe_osdep *)(a)->back)->os_memh, (reg + ((offset) << 2)), value) + +/* FreeBSD compat glue */ +#define MJUMPAGESIZE MCLBYTES +#define PCIR_BAR(_x) (0x10 + (_x) * 4) +#define roundup2(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) + +s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw); +s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw); +s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw); +s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw); +s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num); +s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr); +s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw); +s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw); + +s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); + +s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); +s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); +s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 *data); +s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, + u16 *checksum_val); +s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); + +s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, + u32 enable_addr); +s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw); +s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, + ixgbe_mc_addr_itr func); +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, + u32 addr_count, ixgbe_mc_addr_itr func); +s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); +s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); +s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw); +s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, + u32 vind, bool vlan_on); + +s32 ixgbe_validate_mac_addr(u8 *mac_addr); +s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask); +void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask); +s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw); + +s32 ixgbe_read_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 *val); +s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val); + +void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr); +s32 ixgbe_init_ops_82598(struct ixgbe_hw *hw); + +/* PHY */ +s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); +bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); +enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); +s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); +s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); +s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw); +s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data); +s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data); +s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw); +s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); + +s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *link_up); +s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, + u16 *firmware_version); + +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw); + +#endif /* _IXGBE_OS_H_ */ diff --git a/sys/dev/pci/ixgbe_82598.c b/sys/dev/pci/ixgbe_82598.c new file mode 100644 index 00000000000..58e38a27cc1 --- /dev/null +++ b/sys/dev/pci/ixgbe_82598.c @@ -0,0 +1,1116 @@ +/* $OpenBSD: ixgbe_82598.c,v 1.1 2008/06/08 20:01:02 reyk Exp $ */ + +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_82598.c,v 1.4 2008/05/16 18:46:30 jfv Exp $*/ + +#include <dev/pci/ixgbe.h> +#include <dev/pci/ixgbe_type.h> + +s32 ixgbe_init_ops_82598(struct ixgbe_hw *hw); +s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg); +s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg); +enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw); +s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num); +s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw); +s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *link_up, bool link_up_wait_to_complete); +s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); +s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); +s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); +#ifndef NO_82598_A0_SUPPORT +s32 ixgbe_reset_hw_rev_0_82598(struct ixgbe_hw *hw); +#endif +s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw); +s32 ixgbe_configure_fiber_serdes_fc_82598(struct ixgbe_hw *hw); +s32 ixgbe_setup_fiber_serdes_link_82598(struct ixgbe_hw *hw); +s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq); +s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_blink_led_start_82598(struct ixgbe_hw *hw, u32 index); + +/** + * ixgbe_init_ops_82598 - Inits func ptrs and MAC type + * @hw: pointer to hardware structure + * + * Initialize the function pointers and assign the MAC type for 82598. + * Does not touch the hardware. + **/ +s32 ixgbe_init_ops_82598(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; + s32 ret_val; + + ret_val = ixgbe_init_phy_ops_generic(hw); + ret_val = ixgbe_init_ops_generic(hw); + + /* MAC */ +#ifndef NO_82598_A0_SUPPORT + if (hw->revision_id == 0) + mac->ops.reset_hw = &ixgbe_reset_hw_rev_0_82598; + else + mac->ops.reset_hw = &ixgbe_reset_hw_82598; +#else + mac->ops.reset_hw = &ixgbe_reset_hw_82598; +#endif + mac->ops.get_media_type = &ixgbe_get_media_type_82598; + + /* LEDs */ + mac->ops.blink_led_start = &ixgbe_blink_led_start_82598; + mac->ops.blink_led_stop = &ixgbe_blink_led_stop_82598; + + /* RAR, Multicast, VLAN */ + mac->ops.set_vmdq = &ixgbe_set_vmdq_82598; + + /* Flow Control */ + mac->ops.setup_fc = &ixgbe_setup_fc_82598; + + /* Call PHY identify routine to get the phy type */ + phy->ops.identify(hw); + + /* PHY Init */ + switch (hw->phy.type) { + case ixgbe_phy_tn: + phy->ops.check_link = &ixgbe_check_phy_link_tnx; + phy->ops.get_firmware_version = + &ixgbe_get_phy_firmware_version_tnx; + break; + case ixgbe_phy_nl: + phy->ops.reset = &ixgbe_reset_phy_nl; + break; + default: + break; + } + + /* Link */ + mac->ops.check_link = &ixgbe_check_mac_link_82598; + if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { + mac->ops.setup_link = &ixgbe_setup_copper_link_82598; + mac->ops.setup_link_speed = + &ixgbe_setup_copper_link_speed_82598; + mac->ops.get_link_capabilities = + &ixgbe_get_copper_link_capabilities_82598; + } else { + mac->ops.setup_link = &ixgbe_setup_mac_link_82598; + mac->ops.setup_link_speed = &ixgbe_setup_mac_link_speed_82598; + mac->ops.get_link_capabilities = + &ixgbe_get_link_capabilities_82598; + } + + mac->mcft_size = 128; + mac->vft_size = 128; + mac->num_rar_entries = 16; + mac->max_tx_queues = 32; + mac->max_rx_queues = 64; + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_get_link_capabilities_82598 - Determines link capabilities + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * + * Determines the link capabilities by reading the AUTOC register. + **/ +s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) +{ + s32 status = IXGBE_SUCCESS; + s32 autoc_reg; + + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + if (hw->mac.link_settings_loaded) { + autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE; + autoc_reg &= ~IXGBE_AUTOC_LMS_MASK; + autoc_reg |= hw->mac.link_attach_type; + autoc_reg |= hw->mac.link_mode_select; + } + + switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) { + case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: + *speed = IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = FALSE; + break; + + case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: + *speed = IXGBE_LINK_SPEED_10GB_FULL; + *autoneg = FALSE; + break; + + case IXGBE_AUTOC_LMS_1G_AN: + *speed = IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = TRUE; + break; + + case IXGBE_AUTOC_LMS_KX4_AN: + case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: + *speed = IXGBE_LINK_SPEED_UNKNOWN; + if (autoc_reg & IXGBE_AUTOC_KX4_SUPP) + *speed |= IXGBE_LINK_SPEED_10GB_FULL; + if (autoc_reg & IXGBE_AUTOC_KX_SUPP) + *speed |= IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = TRUE; + break; + + default: + status = IXGBE_ERR_LINK_SETUP; + break; + } + + return status; +} + +/** + * ixgbe_get_copper_link_capabilities_82598 - Determines link capabilities + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * + * Determines the link capabilities by reading the AUTOC register. + **/ +s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) +{ + s32 status = IXGBE_ERR_LINK_SETUP; + u16 speed_ability; + + *speed = 0; + *autoneg = TRUE; + + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &speed_ability); + + if (status == IXGBE_SUCCESS) { + if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) + *speed |= IXGBE_LINK_SPEED_10GB_FULL; + if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) + *speed |= IXGBE_LINK_SPEED_1GB_FULL; + } + + return status; +} + +/** + * ixgbe_get_media_type_82598 - Determines media type + * @hw: pointer to hardware structure + * + * Returns the media type (fiber, copper, backplane) + **/ +enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) +{ + enum ixgbe_media_type media_type; + + /* Media type for I82598 is based on device ID */ + switch (hw->device_id) { + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598EB_CX4: + case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: + case IXGBE_DEV_ID_82598EB_XF_LR: + media_type = ixgbe_media_type_fiber; + break; + case IXGBE_DEV_ID_82598AT: + media_type = ixgbe_media_type_copper; + break; + case IXGBE_DEV_ID_82598AT_DUAL_PORT: + media_type = ixgbe_media_type_copper; + break; + default: + media_type = ixgbe_media_type_unknown; + break; + } + + return media_type; +} + +/** + * ixgbe_setup_fc_82598 - Configure flow control settings + * @hw: pointer to hardware structure + * @packetbuf_num: packet buffer number (0-7) + * + * Configures the flow control settings based on SW configuration. This + * function is used for 802.3x flow control configuration only. + **/ +s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) +{ + u32 frctl_reg; + u32 rmcs_reg; + + if (packetbuf_num < 0 || packetbuf_num > 7) { + DEBUGOUT1("Invalid packet buffer number [%d], expected range is" + " 0-7\n", packetbuf_num); + ASSERT(0); + } + + frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); + + rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X); + + /* + * 10 gig parts do not have a word in the EEPROM to determine the + * default flow control setting, so we explicitly set it to full. + */ + if (hw->fc.type == ixgbe_fc_default) + hw->fc.type = ixgbe_fc_full; + + /* + * We want to save off the original Flow Control configuration just in + * case we get disconnected and then reconnected into a different hub + * or switch with different Flow Control capabilities. + */ + hw->fc.original_type = hw->fc.type; + + /* + * The possible values of the "flow_control" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames but not + * send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we do not + * support receiving pause frames) + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.type) { + case ixgbe_fc_none: + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled, + * and Tx Flow control is disabled. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is disabled, + * by a software over-ride. + */ + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + case ixgbe_fc_full: + /* + * Flow control (both Rx and Tx) is enabled by a software + * over-ride. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Enable 802.3x based flow control settings. */ + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg); + IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); + + /* + * Check for invalid software configuration, zeros are completely + * invalid for all parameters used past this point, and if we enable + * flow control with zero water marks, we blast flow control packets. + */ + if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { + DEBUGOUT("Flow control structure initialized incorrectly\n"); + return IXGBE_ERR_INVALID_LINK_SETTINGS; + } + + /* + * We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + if (hw->fc.type & ixgbe_fc_tx_pause) { + if (hw->fc.send_xon) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + (hw->fc.low_water | IXGBE_FCRTL_XONE)); + } else { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + hw->fc.low_water); + } + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), + (hw->fc.high_water)|IXGBE_FCRTH_FCEN); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time); + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_setup_mac_link_82598 - Configures MAC link settings + * @hw: pointer to hardware structure + * + * Configures link settings based on values in the ixgbe_hw struct. + * Restarts the link. Performs autonegotiation if needed. + **/ +s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) +{ + ixgbe_link_speed speed; + bool link_up; + u32 autoc_reg; + u32 links_reg; + u32 i; + s32 status = IXGBE_SUCCESS; + + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + if (hw->mac.link_settings_loaded) { + autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE; + autoc_reg &= ~IXGBE_AUTOC_LMS_MASK; + autoc_reg |= hw->mac.link_attach_type; + autoc_reg |= hw->mac.link_mode_select; + + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + IXGBE_WRITE_FLUSH(hw); + msec_delay(50); + } + + /* Restart link */ + autoc_reg |= IXGBE_AUTOC_AN_RESTART; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + + /* Only poll for autoneg to complete if specified to do so */ + if (hw->phy.autoneg_wait_to_complete) { + if (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN || + hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) { + links_reg = 0; /* Just in case Autoneg time = 0 */ + for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) { + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + if (links_reg & IXGBE_LINKS_KX_AN_COMP) + break; + msec_delay(100); + } + if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { + status = IXGBE_ERR_AUTONEG_NOT_COMPLETE; + DEBUGOUT("Autonegotiation did not complete.\n"); + } + } + } + + /* + * We want to save off the original Flow Control configuration just in + * case we get disconnected and then reconnected into a different hub + * or switch with different Flow Control capabilities. + */ + hw->fc.original_type = hw->fc.type; + /* + * Set up the SerDes link if in 1Gb mode, otherwise just set up + * 10Gb flow control. + */ + hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); + if (speed == IXGBE_LINK_SPEED_1GB_FULL) + status = ixgbe_setup_fiber_serdes_link_82598(hw); + else + ixgbe_setup_fc_82598(hw, 0); + + /* Add delay to filter out noises during initial link setup */ + msec_delay(50); + + return status; +} + +/** + * ixgbe_check_mac_link_82598 - Get link/speed status + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: TRUE is link is up, FALSE otherwise + * @link_up_wait_to_complete: bool used to wait for link up or not + * + * Reads the links register to determine if link is up and the current speed + **/ +s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed *speed, + bool *link_up, bool link_up_wait_to_complete) +{ + u32 links_reg; + u32 i; + u16 link_reg, adapt_comp_reg; + + if (hw->phy.type == ixgbe_phy_nl) { + hw->phy.ops.read_reg(hw, 1, IXGBE_TWINAX_DEV, &link_reg); + hw->phy.ops.read_reg(hw, 1, IXGBE_TWINAX_DEV, &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV, + &adapt_comp_reg); + if (link_up_wait_to_complete) { + for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { + if ((link_reg & (1 << 2)) && + ((adapt_comp_reg & 1) == 0)) { + *link_up = TRUE; + break; + } else { + *link_up = FALSE; + } + msec_delay(100); + hw->phy.ops.read_reg(hw, 1, IXGBE_TWINAX_DEV, + &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, + IXGBE_TWINAX_DEV, + &adapt_comp_reg); + } + } else { + if ((link_reg & (1 << 2)) && + ((adapt_comp_reg & 1) == 0)) + *link_up = TRUE; + else + *link_up = FALSE; + } + + if (*link_up == FALSE) + goto out; + } + + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + if (link_up_wait_to_complete) { + for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { + if (links_reg & IXGBE_LINKS_UP) { + *link_up = TRUE; + break; + } else { + *link_up = FALSE; + } + msec_delay(100); + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + } + } else { + if (links_reg & IXGBE_LINKS_UP) + *link_up = TRUE; + else + *link_up = FALSE; + } + + if (links_reg & IXGBE_LINKS_SPEED) + *speed = IXGBE_LINK_SPEED_10GB_FULL; + else + *speed = IXGBE_LINK_SPEED_1GB_FULL; + +out: + return IXGBE_SUCCESS; +} + +/** + * ixgbe_configure_fiber_serdes_fc_82598 - Configure fiber flow control + * @hw: pointer to hardware structure + * + * Reads PCS registers and sets flow control settings, based on + * link-partner's abilities. + **/ +s32 ixgbe_configure_fiber_serdes_fc_82598(struct ixgbe_hw *hw) +{ + s32 ret_val = IXGBE_SUCCESS; + u32 pcs_anadv_reg, pcs_lpab_reg, pcs_lstat_reg, i; + DEBUGFUNC("ixgbe_configure_fiber_serdes_fc_82598"); + + /* Check that autonegotiation has completed */ + for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { + msec_delay(10); + pcs_lstat_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); + if (pcs_lstat_reg & IXGBE_PCS1GLSTA_LINK_OK) { + if (pcs_lstat_reg & IXGBE_PCS1GLSTA_AN_COMPLETE) { + if (!(pcs_lstat_reg & + (IXGBE_PCS1GLSTA_AN_TIMED_OUT))) + hw->mac.autoneg_failed = 0; + else + hw->mac.autoneg_failed = 1; + break; + } else { + hw->mac.autoneg_failed = 1; + break; + } + } + } + + if (hw->mac.autoneg_failed) { + /* + * AutoNeg failed to achieve a link, so we will turn + * flow control off. + */ + hw->fc.type = ixgbe_fc_none; + DEBUGOUT("Flow Control = NONE.\n"); + ret_val = ixgbe_setup_fc_82598(hw, 0); + goto out; + } + + /* + * Read the AN advertisement and LP ability registers and resolve + * local flow control settings accordingly + */ + pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); + if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE)) { + /* + * Now we need to check if the user selected Rx ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.original_type == ixgbe_fc_full) { + hw->fc.type = ixgbe_fc_full; + DEBUGOUT("Flow Control = FULL.\n"); + } else { + hw->fc.type = ixgbe_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\n"); + } + } else if (!(pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) { + hw->fc.type = ixgbe_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\n"); + } else if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) && + !(pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) { + hw->fc.type = ixgbe_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\n"); + } else { + hw->fc.type = ixgbe_fc_none; + DEBUGOUT("Flow Control = NONE.\n"); + } + + ret_val = ixgbe_setup_fc_82598(hw, 0); + if (ret_val) { + DEBUGOUT("Error forcing flow control settings\n"); + goto out; + } + +out: + return ret_val; +} + +/** + * ixgbe_setup_fiber_serdes_link_82598 - Configure fiber serdes link + * @hw: pointer to hardware structure + * + * Sets up PCS registers and sets flow control settings, based on + * link-partner's abilities. + **/ +s32 ixgbe_setup_fiber_serdes_link_82598(struct ixgbe_hw *hw) +{ + u32 reg; + s32 ret_val; + + DEBUGFUNC("ixgbe_setup_fiber_serdes_link_82598"); + + /* + * 10 gig parts do not have a word in the EEPROM to determine the + * default flow control setting, so we explicitly set it to full. + */ + if (hw->fc.type == ixgbe_fc_default) + hw->fc.type = ixgbe_fc_full; + + /* + * 82598 fiber/serdes devices require that flow control be resolved in + * software. + */ + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + + /* + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but + * we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + */ + switch (hw->fc.type) { + case ixgbe_fc_none: + /* + * Flow control completely disabled by a software + * over-ride. + */ + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by a software over-ride. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled, by a software over-ride. + */ + reg |= (IXGBE_PCS1GANA_ASM_PAUSE); + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); + break; + case ixgbe_fc_full: + /* + * Flow control (both Rx and Tx) is enabled by a + * software over-ride. + */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ret_val = -IXGBE_ERR_CONFIG; + goto out; + break; + } + + IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); + + /* Set PCS register for autoneg */ + /* Enable and restart autoneg */ + reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; + + reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; /* Disable AN timeout */ + DEBUGOUT1("Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); + IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); + + /* + * Configure flow control. If we aren't auto-negotiating, + * just setup the flow control and do not worry about PCS autoneg. + */ + ixgbe_configure_fiber_serdes_fc_82598(hw); + +out: + return IXGBE_SUCCESS; +} + +/** + * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: TRUE if auto-negotiation enabled + * @autoneg_wait_to_complete: TRUE if waiting is needed to complete + * + * Set the link speed in the AUTOC register and restarts link. + **/ +s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, + ixgbe_link_speed speed, bool autoneg, + bool autoneg_wait_to_complete) +{ + s32 status = IXGBE_SUCCESS; + + /* If speed is 10G, then check for CX4 or XAUI. */ + if ((speed == IXGBE_LINK_SPEED_10GB_FULL) && + (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) { + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; + } else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) { + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN; + } else if (autoneg) { + /* BX mode - Autonegotiate 1G */ + if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD)) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN; + else /* KX/KX4 mode */ + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN; + } else { + status = IXGBE_ERR_LINK_SETUP; + } + + if (status == IXGBE_SUCCESS) { + hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete; + + hw->mac.link_settings_loaded = TRUE; + /* + * Setup and restart the link based on the new values in + * ixgbe_hw This will write the AUTOC register based on the new + * stored values + */ + ixgbe_setup_mac_link_82598(hw); + } + + return status; +} + + +/** + * ixgbe_setup_copper_link_82598 - Setup copper link settings + * @hw: pointer to hardware structure + * + * Configures link settings based on values in the ixgbe_hw struct. + * Restarts the link. Performs autonegotiation if needed. Restart + * phy and wait for autonegotiate to finish. Then synchronize the + * MAC and PHY. + **/ +s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) +{ + s32 status; + + /* Restart autonegotiation on PHY */ + status = hw->phy.ops.setup_link(hw); + + /* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */ + hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; + + /* Set up MAC */ + ixgbe_setup_mac_link_82598(hw); + + return status; +} + +/** + * ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: TRUE if autonegotiation enabled + * @autoneg_wait_to_complete: TRUE if waiting is needed to complete + * + * Sets the link speed in the AUTOC register in the MAC and restarts link. + **/ +s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) +{ + s32 status; + + /* Setup the PHY according to input speed */ + status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, + autoneg_wait_to_complete); + + /* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */ + hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; + + /* Set up MAC */ + ixgbe_setup_mac_link_82598(hw); + + return status; +} + +#ifndef NO_82598_A0_SUPPORT +/** + * ixgbe_reset_hw_rev_0_82598 - Performs hardware reset + * @hw: pointer to hardware structure + * + * Resets the hardware by resetting the transmit and receive units, masks and + * clears all interrupts, performing a PHY reset, and performing a link (MAC) + * reset. + **/ +s32 ixgbe_reset_hw_rev_0_82598(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_SUCCESS; + u32 ctrl; + u32 gheccr; + u32 autoc; + u32 i; + u32 resets; + + /* Call adapter stop to disable tx/rx and clear interrupts */ + hw->mac.ops.stop_adapter(hw); + + /* Reset PHY */ + hw->phy.ops.reset(hw); + + for (resets = 0; resets < 10; resets++) { + /* + * Prevent the PCI-E bus from from hanging by disabling PCI-E + * master access and verify no pending requests before reset + */ + if (ixgbe_disable_pcie_master(hw) != IXGBE_SUCCESS) { + status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + + /* + * Issue global reset to the MAC. This needs to be a SW reset. + * If link reset is used, it might reset the MAC when mng is + * using it. + */ + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST)); + IXGBE_WRITE_FLUSH(hw); + + /* + * Poll for reset bit to self-clear indicating reset is + * complete + */ + for (i = 0; i < 10; i++) { + usec_delay(1); + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + if (!(ctrl & IXGBE_CTRL_RST)) + break; + } + if (ctrl & IXGBE_CTRL_RST) { + status = IXGBE_ERR_RESET_FAILED; + DEBUGOUT("Reset polling failed to complete.\n"); + } + } + + msec_delay(50); + + gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR); + gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6)); + IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr); + + /* + * AUTOC register which stores link settings gets cleared + * and reloaded from EEPROM after reset. We need to restore + * our stored value from init in case SW changed the attach + * type or speed. If this is the first time and link settings + * have not been stored, store default settings from AUTOC. + */ + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + if (hw->mac.link_settings_loaded) { + autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE); + autoc &= ~(IXGBE_AUTOC_LMS_MASK); + autoc |= hw->mac.link_attach_type; + autoc |= hw->mac.link_mode_select; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + } else { + hw->mac.link_attach_type = + (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); + hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK); + hw->mac.link_settings_loaded = TRUE; + } + + /* Store the permanent mac address */ + hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); + + return status; +} + +#endif /* NO_A0_SUPPORT */ +/** + * ixgbe_reset_hw_82598 - Performs hardware reset + * @hw: pointer to hardware structure + * + * Resets the hardware by resetting the transmit and receive units, masks and + * clears all interrupts, performing a PHY reset, and performing a link (MAC) + * reset. + **/ +s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_SUCCESS; + u32 ctrl; + u32 gheccr; + u32 i; + u32 autoc; + u8 analog_val; + + /* Call adapter stop to disable tx/rx and clear interrupts */ + hw->mac.ops.stop_adapter(hw); + + /* + * Power up the Atlas Tx lanes if they are currently powered down. + * Atlas Tx lanes are powered down for MAC loopback tests, but + * they are not automatically restored on reset. + */ + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) { + /* Enable Tx Atlas so packets can be transmitted again */ + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, + &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, + analog_val); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, + &analog_val); + analog_val &= ~ IXGBE_ATLAS_PDN_TX_10G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, + analog_val); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, + &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, + analog_val); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, + &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, + analog_val); + } + + /* Reset PHY */ + if (hw->phy.reset_disable == FALSE) + hw->phy.ops.reset(hw); + + /* + * Prevent the PCI-E bus from from hanging by disabling PCI-E master + * access and verify no pending requests before reset + */ + if (ixgbe_disable_pcie_master(hw) != IXGBE_SUCCESS) { + status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + + /* + * Issue global reset to the MAC. This needs to be a SW reset. + * If link reset is used, it might reset the MAC when mng is using it + */ + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST)); + IXGBE_WRITE_FLUSH(hw); + + /* Poll for reset bit to self-clear indicating reset is complete */ + for (i = 0; i < 10; i++) { + usec_delay(1); + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + if (!(ctrl & IXGBE_CTRL_RST)) + break; + } + if (ctrl & IXGBE_CTRL_RST) { + status = IXGBE_ERR_RESET_FAILED; + DEBUGOUT("Reset polling failed to complete.\n"); + } + + msec_delay(50); + + gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR); + gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6)); + IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr); + + /* + * AUTOC register which stores link settings gets cleared + * and reloaded from EEPROM after reset. We need to restore + * our stored value from init in case SW changed the attach + * type or speed. If this is the first time and link settings + * have not been stored, store default settings from AUTOC. + */ + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + if (hw->mac.link_settings_loaded) { + autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE); + autoc &= ~(IXGBE_AUTOC_LMS_MASK); + autoc |= hw->mac.link_attach_type; + autoc |= hw->mac.link_mode_select; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + } else { + hw->mac.link_attach_type = + (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); + hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK); + hw->mac.link_settings_loaded = TRUE; + } + + /* Store the permanent mac address */ + hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); + + return status; +} + +/** + * ixgbe_set_vmdq_82598 - Associate a VMDq set index with a rx address + * @hw: pointer to hardware struct + * @rar: receive address register index to associate with a VMDq index + * @vmdq: VMDq set index + **/ +s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +{ + u32 rar_high; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar)); + rar_high &= ~IXGBE_RAH_VIND_MASK; + rar_high |= ((vmdq << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK); + IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high); + return IXGBE_SUCCESS; +} + +/** + * ixgbe_blink_led_start_82598 - Blink LED based on index. + * @hw: pointer to hardware structure + * @index: led number to blink + **/ +s32 ixgbe_blink_led_start_82598(struct ixgbe_hw *hw, u32 index) +{ + ixgbe_link_speed speed = 0; + bool link_up = 0; + u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* + * Link must be up to auto-blink the LEDs on the 82598EB MAC; + * force it if link is down. + */ + hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); + + if (!link_up) { + autoc_reg |= IXGBE_AUTOC_FLU; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + msec_delay(10); + } + + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_blink_led_stop_82598 - Stop blinking LED based on index. + * @hw: pointer to hardware structure + * @index: led number to stop blinking + **/ +s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index) +{ + u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + autoc_reg &= ~IXGBE_AUTOC_FLU; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg &= ~IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return IXGBE_SUCCESS; +} diff --git a/sys/dev/pci/ixgbe_phy.c b/sys/dev/pci/ixgbe_phy.c new file mode 100644 index 00000000000..83d59b719c5 --- /dev/null +++ b/sys/dev/pci/ixgbe_phy.c @@ -0,0 +1,671 @@ +/* $OpenBSD: ixgbe_phy.c,v 1.1 2008/06/08 20:01:02 reyk Exp $ */ + +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_phy.c,v 1.4 2008/05/16 18:46:30 jfv Exp $*/ + +#include <dev/pci/ixgbe.h> + +/** + * ixgbe_init_phy_ops_generic - Inits PHY function ptrs + * @hw: pointer to the hardware structure + * + * Initialize the function pointers. + **/ +s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw) +{ + struct ixgbe_phy_info *phy = &hw->phy; + + /* PHY */ + phy->ops.identify = &ixgbe_identify_phy_generic; + phy->ops.reset = &ixgbe_reset_phy_generic; + phy->ops.read_reg = &ixgbe_read_phy_reg_generic; + phy->ops.write_reg = &ixgbe_write_phy_reg_generic; + phy->ops.setup_link = &ixgbe_setup_phy_link_generic; + phy->ops.setup_link_speed = &ixgbe_setup_phy_link_speed_generic; + phy->ops.check_link = NULL; + phy->ops.get_firmware_version = NULL; + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_identify_phy_generic - Get physical layer module + * @hw: pointer to hardware structure + * + * Determines the physical layer module found on the current adapter. + **/ +s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + u32 phy_addr; + + if (hw->phy.type == ixgbe_phy_unknown) { + for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { + if (ixgbe_validate_phy_addr(hw, phy_addr)) { + hw->phy.addr = phy_addr; + ixgbe_get_phy_id(hw); + hw->phy.type = + ixgbe_get_phy_type_from_id(hw->phy.id); + status = IXGBE_SUCCESS; + break; + } + } + } else { + status = IXGBE_SUCCESS; + } + + return status; +} + +/** + * ixgbe_validate_phy_addr - Determines phy address is valid + * @hw: pointer to hardware structure + * + **/ +bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr) +{ + u16 phy_id = 0; + bool valid = FALSE; + + hw->phy.addr = phy_addr; + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id); + + if (phy_id != 0xFFFF && phy_id != 0x0) + valid = TRUE; + + return valid; +} + +/** + * ixgbe_get_phy_id - Get the phy type + * @hw: pointer to hardware structure + * + **/ +s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) +{ + u32 status; + u16 phy_id_high = 0; + u16 phy_id_low = 0; + + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_high); + + if (status == IXGBE_SUCCESS) { + hw->phy.id = (u32)(phy_id_high << 16); + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_low); + hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); + hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); + } + + return status; +} + +/** + * ixgbe_get_phy_type_from_id - Get the phy type + * @hw: pointer to hardware structure + * + **/ +enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) +{ + enum ixgbe_phy_type phy_type; + + switch (phy_id) { + case TN1010_PHY_ID: + phy_type = ixgbe_phy_tn; + break; + case QT2022_PHY_ID: + phy_type = ixgbe_phy_qt; + break; + case ATH_PHY_ID: + phy_type = ixgbe_phy_nl; + break; + default: + phy_type = ixgbe_phy_unknown; + break; + } + + DEBUGOUT1("phy type found is %d\n", phy_type); + return phy_type; +} + +/** + * ixgbe_reset_phy_generic - Performs a PHY reset + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) +{ + /* + * Perform soft PHY reset to the PHY_XS. + * This will cause a soft reset to the PHY + */ + return hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + IXGBE_MDIO_PHY_XS_RESET); +} + +/** + * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit address of PHY register to read + * @phy_data: Pointer to read data from PHY register + **/ +s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data) +{ + u32 command; + u32 i; + u32 data; + s32 status = IXGBE_SUCCESS; + u16 gssr; + + if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) + gssr = IXGBE_GSSR_PHY1_SM; + else + gssr = IXGBE_GSSR_PHY0_SM; + + if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == IXGBE_SUCCESS) { + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { + break; + } + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + DEBUGOUT("PHY address command did not complete.\n"); + status = IXGBE_ERR_PHY; + } + + if (status == IXGBE_SUCCESS) { + /* + * Address cycle complete, setup and write the read + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle + * completed. The MDI Command bit will clear when the + * operation is complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + DEBUGOUT("PHY read command didn't complete\n"); + status = IXGBE_ERR_PHY; + } else { + /* + * Read operation is complete. Get the data + * from MSRWD + */ + data = IXGBE_READ_REG(hw, IXGBE_MSRWD); + data >>= IXGBE_MSRWD_READ_DATA_SHIFT; + *phy_data = (u16)(data); + } + } + + ixgbe_release_swfw_sync(hw, gssr); + } + + return status; +} + +/** + * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 5 bit device type + * @phy_data: Data to write to the PHY register + **/ +s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data) +{ + u32 command; + u32 i; + s32 status = IXGBE_SUCCESS; + u16 gssr; + + if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) + gssr = IXGBE_GSSR_PHY1_SM; + else + gssr = IXGBE_GSSR_PHY0_SM; + + if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == IXGBE_SUCCESS) { + /* Put the data in the MDI single read and write data register*/ + IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); + + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + DEBUGOUT("PHY address cmd didn't complete\n"); + status = IXGBE_ERR_PHY; + } + + if (status == IXGBE_SUCCESS) { + /* + * Address cycle complete, setup and write the write + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle + * completed. The MDI Command bit will clear when the + * operation is complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + DEBUGOUT("PHY address cmd didn't complete\n"); + status = IXGBE_ERR_PHY; + } + } + + ixgbe_release_swfw_sync(hw, gssr); + } + + return status; +} + +/** + * ixgbe_setup_phy_link_generic - Set and restart autoneg + * @hw: pointer to hardware structure + * + * Restart autonegotiation and PHY and waits for completion. + **/ +s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_NOT_IMPLEMENTED; + u32 time_out; + u32 max_time_out = 10; + u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; + + /* + * Set advertisement settings in PHY based on autoneg_advertised + * settings. If autoneg_advertised = 0, then advertise default values + * tnx devices cannot be "forced" to a autoneg 10G and fail. But can + * for a 1G. + */ + hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); + + if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL) + autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */ + else + autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */ + + hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + + /* Restart PHY autonegotiation and wait for completion */ + hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); + + autoneg_reg |= IXGBE_MII_RESTART; + + hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + + /* Wait for autonegotiation to finish */ + for (time_out = 0; time_out < max_time_out; time_out++) { + usec_delay(10); + /* Restart PHY autonegotiation and wait for completion */ + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + + autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; + if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) { + status = IXGBE_SUCCESS; + break; + } + } + + if (time_out == max_time_out) + status = IXGBE_ERR_LINK_SETUP; + + return status; +} + +/** + * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: TRUE if autonegotiation enabled + **/ +s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) +{ + UNREFERENCED_PARAMETER(autoneg); + UNREFERENCED_PARAMETER(autoneg_wait_to_complete); + + /* + * Clear autoneg_advertised and set new values based on input link + * speed. + */ + hw->phy.autoneg_advertised = 0; + + if (speed & IXGBE_LINK_SPEED_10GB_FULL) { + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; + } + if (speed & IXGBE_LINK_SPEED_1GB_FULL) { + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; + } + + /* Setup link based on the new speed settings */ + hw->phy.ops.setup_link(hw); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_check_phy_link_tnx - Determine link and speed status + * @hw: pointer to hardware structure + * + * Reads the VS1 register to determine if link is up and the current speed for + * the PHY. + **/ +s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, + bool *link_up) +{ + s32 status = IXGBE_SUCCESS; + u32 time_out; + u32 max_time_out = 10; + u16 phy_link = 0; + u16 phy_speed = 0; + u16 phy_data = 0; + + /* Initialize speed and link to default case */ + *link_up = FALSE; + *speed = IXGBE_LINK_SPEED_10GB_FULL; + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + for (time_out = 0; time_out < max_time_out; time_out++) { + usec_delay(10); + status = hw->phy.ops.read_reg(hw, + IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + &phy_data); + phy_link = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; + phy_speed = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; + if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { + *link_up = TRUE; + if (phy_speed == + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) + *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + } + } + + return status; +} + +/** + * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version + * @hw: pointer to hardware structure + * @firmware_version: pointer to the PHY Firmware Version + **/ +s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, + u16 *firmware_version) +{ + s32 status = IXGBE_SUCCESS; + + status = hw->phy.ops.read_reg(hw, TNX_FW_REV, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + firmware_version); + + return status; +} + +/** + * ixgbe_reset_phy_nl - Performs a PHY reset + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) +{ + u16 phy_offset, control, eword, edata, list_crc, block_crc, id, sfp_id; + bool end_data = FALSE; + u16 list_offset, data_offset; + u16 phy_data = 0; + s32 ret_val = IXGBE_SUCCESS; + u32 i; + + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + + /* reset the PHY and poll for completion */ + hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + (phy_data | IXGBE_MDIO_PHY_XS_RESET)); + + for (i = 0; i < 100; i++) { + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0 ) + break; + msec_delay(10); + } + + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { + DEBUGOUT("PHY reset did not complete.\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + + /* read offset to PHY init contents */ + hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, &list_offset); + + if ((!list_offset) || (list_offset == 0xFFFF)) { + ret_val = IXGBE_ERR_PHY; + goto out; + } + + /* Acquire the CRC */ + hw->eeprom.ops.read(hw, list_offset, &list_crc); + + /* Shift offset to first ID word */ + list_offset++; + + /* determine the sfp sequence based on device ID */ + switch (hw->device_id) { + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + sfp_id = 0; + break; + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: + sfp_id = 1; + break; + default: + ret_val = IXGBE_ERR_PHY; + goto out; + } + + /* + * Find the matching sfp ID in the EEPROM + * and program the init sequence + */ + hw->eeprom.ops.read(hw, list_offset, &id); + + while (!((id == IXGBE_CONTROL_EOL_NL) || (end_data == TRUE))) { + if (id == sfp_id) { + list_offset++; + hw->eeprom.ops.read(hw, list_offset, &data_offset); + if ((!data_offset) || (data_offset == 0xFFFF)) + break; + ret_val = hw->eeprom.ops.read(hw, data_offset, + &block_crc); + data_offset++; + while (!end_data) { + /* + * Read control word from PHY init contents + * offset + */ + ret_val = hw->eeprom.ops.read(hw, data_offset, + &eword); + control = (eword & IXGBE_CONTROL_MASK_NL) >> + IXGBE_CONTROL_SHIFT_NL; + edata = eword & IXGBE_DATA_MASK_NL; + switch (control) { + case IXGBE_DELAY_NL: + data_offset++; + DEBUGOUT1("DELAY: %d MS\n", edata); + msec_delay(edata); + break; + case IXGBE_DATA_NL: + DEBUGOUT("DATA: \n"); + data_offset++; + hw->eeprom.ops.read(hw, data_offset++, + &phy_offset); + for (i = 0; i < edata; i++) { + hw->eeprom.ops.read(hw, + data_offset, + &eword); + hw->phy.ops.write_reg(hw, + phy_offset, + IXGBE_TWINAX_DEV, + eword); + DEBUGOUT2("Wrote %4.4x to %4.4x\n", + eword, phy_offset); + data_offset++; + phy_offset++; + } + break; + case IXGBE_CONTROL_NL: + data_offset++; + DEBUGOUT("CONTROL: \n"); + if (edata == IXGBE_CONTROL_EOL_NL) { + DEBUGOUT("EOL\n"); + end_data = TRUE; + } else if (edata == IXGBE_CONTROL_SOL_NL) { + DEBUGOUT("SOL\n"); + } else { + DEBUGOUT("Bad control value\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + break; + default: + DEBUGOUT("Bad control type\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + } + } else { + list_offset += 2; + ret_val = hw->eeprom.ops.read(hw, list_offset, &id); + if (ret_val) + goto out; + } + } + +out: + return ret_val; +} diff --git a/sys/dev/pci/ixgbe_type.h b/sys/dev/pci/ixgbe_type.h new file mode 100644 index 00000000000..be689aad597 --- /dev/null +++ b/sys/dev/pci/ixgbe_type.h @@ -0,0 +1,1559 @@ +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_type.h,v 1.4 2008/05/16 18:46:30 jfv Exp $*/ + +#ifndef _IXGBE_TYPE_H_ +#define _IXGBE_TYPE_H_ + +/* Vendor ID */ +#define IXGBE_INTEL_VENDOR_ID 0x8086 + +/* Device IDs */ +#define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 +#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 +#define IXGBE_DEV_ID_82598AT 0x10C8 +#define IXGBE_DEV_ID_82598AT_DUAL_PORT 0x10D7 +#define IXGBE_DEV_ID_82598EB_CX4 0x10DD +#define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC +#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 +#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1 +#define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 + +/* General Registers */ +#define IXGBE_CTRL 0x00000 +#define IXGBE_STATUS 0x00008 +#define IXGBE_CTRL_EXT 0x00018 +#define IXGBE_ESDP 0x00020 +#define IXGBE_EODSDP 0x00028 +#define IXGBE_LEDCTL 0x00200 +#define IXGBE_FRTIMER 0x00048 +#define IXGBE_TCPTIMER 0x0004C + +/* NVM Registers */ +#define IXGBE_EEC 0x10010 +#define IXGBE_EERD 0x10014 +#define IXGBE_FLA 0x1001C +#define IXGBE_EEMNGCTL 0x10110 +#define IXGBE_EEMNGDATA 0x10114 +#define IXGBE_FLMNGCTL 0x10118 +#define IXGBE_FLMNGDATA 0x1011C +#define IXGBE_FLMNGCNT 0x10120 +#define IXGBE_FLOP 0x1013C +#define IXGBE_GRC 0x10200 + +/* Interrupt Registers */ +#define IXGBE_EICR 0x00800 +#define IXGBE_EICS 0x00808 +#define IXGBE_EIMS 0x00880 +#define IXGBE_EIMC 0x00888 +#define IXGBE_EIAC 0x00810 +#define IXGBE_EIAM 0x00890 +#define IXGBE_EITR(_i) (((_i) <= 23) ? (0x00820 + ((_i) * 4)) : (0x012300 + ((_i) * 4))) +#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */ +#define IXGBE_MSIXT 0x00000 /* MSI-X Table. 0x0000 - 0x01C */ +#define IXGBE_MSIXPBA 0x02000 /* MSI-X Pending bit array */ +#define IXGBE_PBACL(_i) (((_i) == 0) ? (0x11068) : (0x110C0 + ((_i) * 4))) +#define IXGBE_GPIE 0x00898 + +/* Flow Control Registers */ +#define IXGBE_PFCTOP 0x03008 +#define IXGBE_FCTTV(_i) (0x03200 + ((_i) * 4)) /* 4 of these (0-3) */ +#define IXGBE_FCRTL(_i) (0x03220 + ((_i) * 8)) /* 8 of these (0-7) */ +#define IXGBE_FCRTH(_i) (0x03260 + ((_i) * 8)) /* 8 of these (0-7) */ +#define IXGBE_FCRTV 0x032A0 +#define IXGBE_TFCS 0x0CE00 + +/* Receive DMA Registers */ +#define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : (0x0D000 + ((_i - 64) * 0x40))) +#define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : (0x0D004 + ((_i - 64) * 0x40))) +#define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : (0x0D008 + ((_i - 64) * 0x40))) +#define IXGBE_RDH(_i) (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : (0x0D010 + ((_i - 64) * 0x40))) +#define IXGBE_RDT(_i) (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : (0x0D018 + ((_i - 64) * 0x40))) +#define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : (0x0D028 + ((_i - 64) * 0x40))) +/* + * Split and Replication Receive Control Registers + * 00-15 : 0x02100 + n*4 + * 16-64 : 0x01014 + n*0x40 + * 64-127: 0x0D014 + (n-64)*0x40 + */ +#define IXGBE_SRRCTL(_i) (((_i) <= 15) ? (0x02100 + ((_i) * 4)) : \ + (((_i) < 64) ? (0x01014 + ((_i) * 0x40)) : \ + (0x0D014 + ((_i - 64) * 0x40)))) +/* + * Rx DCA Control Register: + * 00-15 : 0x02200 + n*4 + * 16-64 : 0x0100C + n*0x40 + * 64-127: 0x0D00C + (n-64)*0x40 + */ +#define IXGBE_DCA_RXCTRL(_i) (((_i) <= 15) ? (0x02200 + ((_i) * 4)) : \ + (((_i) < 64) ? (0x0100C + ((_i) * 0x40)) : \ + (0x0D00C + ((_i - 64) * 0x40)))) +#define IXGBE_RDRXCTL 0x02F00 +#define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4)) + /* 8 of these 0x03C00 - 0x03C1C */ +#define IXGBE_RXCTRL 0x03000 +#define IXGBE_DROPEN 0x03D04 +#define IXGBE_RXPBSIZE_SHIFT 10 + +/* Receive Registers */ +#define IXGBE_RXCSUM 0x05000 +#define IXGBE_RFCTL 0x05008 +/* Multicast Table Array - 128 entries */ +#define IXGBE_MTA(_i) (0x05200 + ((_i) * 4)) +#define IXGBE_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x0A200 + ((_i) * 8))) +#define IXGBE_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x0A204 + ((_i) * 8))) +/* Packet split receive type */ +#define IXGBE_PSRTYPE(_i) (((_i) <= 15) ? (0x05480 + ((_i) * 4)) : (0x0EA00 + ((_i) * 4))) +/* array of 4096 1-bit vlan filters */ +#define IXGBE_VFTA(_i) (0x0A000 + ((_i) * 4)) +/*array of 4096 4-bit vlan vmdq indices */ +#define IXGBE_VFTAVIND(_j, _i) (0x0A200 + ((_j) * 0x200) + ((_i) * 4)) +#define IXGBE_FCTRL 0x05080 +#define IXGBE_VLNCTRL 0x05088 +#define IXGBE_MCSTCTRL 0x05090 +#define IXGBE_MRQC 0x05818 +#define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_IMIRVP 0x05AC0 +#define IXGBE_VMD_CTL 0x0581C +#define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ +#define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ + + +/* Transmit DMA registers */ +#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/ +#define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) +#define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40)) +#define IXGBE_TDH(_i) (0x06010 + ((_i) * 0x40)) +#define IXGBE_TDT(_i) (0x06018 + ((_i) * 0x40)) +#define IXGBE_TXDCTL(_i) (0x06028 + ((_i) * 0x40)) +#define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40)) +#define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40)) +#define IXGBE_DTXCTL 0x07E00 + +#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */ +#define IXGBE_TIPG 0x0CB00 +#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) *0x04)) /* 8 of these */ +#define IXGBE_MNGTXMAP 0x0CD10 +#define IXGBE_TIPG_FIBER_DEFAULT 3 +#define IXGBE_TXPBSIZE_SHIFT 10 + +/* Wake up registers */ +#define IXGBE_WUC 0x05800 +#define IXGBE_WUFC 0x05808 +#define IXGBE_WUS 0x05810 +#define IXGBE_IPAV 0x05838 +#define IXGBE_IP4AT 0x05840 /* IPv4 table 0x5840-0x5858 */ +#define IXGBE_IP6AT 0x05880 /* IPv6 table 0x5880-0x588F */ +#define IXGBE_WUPL 0x05900 +#define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ +#define IXGBE_FHFT 0x09000 /* Flex host filter table 9000-93FC */ + +/* Music registers */ +#define IXGBE_RMCS 0x03D00 +#define IXGBE_DPMCS 0x07F40 +#define IXGBE_PDPMCS 0x0CD00 +#define IXGBE_RUPPBMR 0x050A0 +#define IXGBE_RT2CR(_i) (0x03C20 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_RT2SR(_i) (0x03C40 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TDTQ2TCCR(_i) (0x0602C + ((_i) * 0x40)) /* 8 of these (0-7) */ +#define IXGBE_TDTQ2TCSR(_i) (0x0622C + ((_i) * 0x40)) /* 8 of these (0-7) */ +#define IXGBE_TDPT2TCCR(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */ + +/* LinkSec (MacSec) Registers */ +#define IXGBE_LSECTXCTRL 0x08A04 +#define IXGBE_LSECTXSCL 0x08A08 /* SCI Low */ +#define IXGBE_LSECTXSCH 0x08A0C /* SCI High */ +#define IXGBE_LSECTXSA 0x08A10 +#define IXGBE_LSECTXPN0 0x08A14 +#define IXGBE_LSECTXPN1 0x08A18 +#define IXGBE_LSECTXKEY0(_n) (0x08A1C + (4 * (_n))) /* 4 of these (0-3) */ +#define IXGBE_LSECTXKEY1(_n) (0x08A2C + (4 * (_n))) /* 4 of these (0-3) */ +#define IXGBE_LSECRXCTRL 0x08F04 +#define IXGBE_LSECRXSCL 0x08F08 +#define IXGBE_LSECRXSCH 0x08F0C +#define IXGBE_LSECRXSA(_i) (0x08F10 + (4 * (_i))) /* 2 of these (0-1) */ +#define IXGBE_LSECRXPN(_i) (0x08F18 + (4 * (_i))) /* 2 of these (0-1) */ +#define IXGBE_LSECRXKEY(_n, _m) (0x08F20 + ((0x10 * (_n)) + (4 * (_m)))) + +/* IpSec Registers */ +#define IXGBE_IPSTXIDX 0x08900 +#define IXGBE_IPSTXSALT 0x08904 +#define IXGBE_IPSTXKEY(_i) (0x08908 + (4 * (_i))) /* 4 of these (0-3) */ +#define IXGBE_IPSRXIDX 0x08E00 +#define IXGBE_IPSRXIPADDR(_i) (0x08E04 + (4 * (_i))) /* 4 of these (0-3) */ +#define IXGBE_IPSRXSPI 0x08E14 +#define IXGBE_IPSRXIPIDX 0x08E18 +#define IXGBE_IPSRXKEY(_i) (0x08E1C + (4 * (_i))) /* 4 of these (0-3) */ +#define IXGBE_IPSRXSALT 0x08E2C +#define IXGBE_IPSRXMOD 0x08E30 + + +/* Stats registers */ +#define IXGBE_CRCERRS 0x04000 +#define IXGBE_ILLERRC 0x04004 +#define IXGBE_ERRBC 0x04008 +#define IXGBE_MSPDC 0x04010 +#define IXGBE_MPC(_i) (0x03FA0 + ((_i) * 4)) /* 8 of these 3FA0-3FBC*/ +#define IXGBE_MLFC 0x04034 +#define IXGBE_MRFC 0x04038 +#define IXGBE_RLEC 0x04040 +#define IXGBE_LXONTXC 0x03F60 +#define IXGBE_LXONRXC 0x0CF60 +#define IXGBE_LXOFFTXC 0x03F68 +#define IXGBE_LXOFFRXC 0x0CF68 +#define IXGBE_PXONTXC(_i) (0x03F00 + ((_i) * 4)) /* 8 of these 3F00-3F1C*/ +#define IXGBE_PXONRXC(_i) (0x0CF00 + ((_i) * 4)) /* 8 of these CF00-CF1C*/ +#define IXGBE_PXOFFTXC(_i) (0x03F20 + ((_i) * 4)) /* 8 of these 3F20-3F3C*/ +#define IXGBE_PXOFFRXC(_i) (0x0CF20 + ((_i) * 4)) /* 8 of these CF20-CF3C*/ +#define IXGBE_PRC64 0x0405C +#define IXGBE_PRC127 0x04060 +#define IXGBE_PRC255 0x04064 +#define IXGBE_PRC511 0x04068 +#define IXGBE_PRC1023 0x0406C +#define IXGBE_PRC1522 0x04070 +#define IXGBE_GPRC 0x04074 +#define IXGBE_BPRC 0x04078 +#define IXGBE_MPRC 0x0407C +#define IXGBE_GPTC 0x04080 +#define IXGBE_GORCL 0x04088 +#define IXGBE_GORCH 0x0408C +#define IXGBE_GOTCL 0x04090 +#define IXGBE_GOTCH 0x04094 +#define IXGBE_RNBC(_i) (0x03FC0 + ((_i) * 4)) /* 8 of these 3FC0-3FDC*/ +#define IXGBE_RUC 0x040A4 +#define IXGBE_RFC 0x040A8 +#define IXGBE_ROC 0x040AC +#define IXGBE_RJC 0x040B0 +#define IXGBE_MNGPRC 0x040B4 +#define IXGBE_MNGPDC 0x040B8 +#define IXGBE_MNGPTC 0x0CF90 +#define IXGBE_TORL 0x040C0 +#define IXGBE_TORH 0x040C4 +#define IXGBE_TPR 0x040D0 +#define IXGBE_TPT 0x040D4 +#define IXGBE_PTC64 0x040D8 +#define IXGBE_PTC127 0x040DC +#define IXGBE_PTC255 0x040E0 +#define IXGBE_PTC511 0x040E4 +#define IXGBE_PTC1023 0x040E8 +#define IXGBE_PTC1522 0x040EC +#define IXGBE_MPTC 0x040F0 +#define IXGBE_BPTC 0x040F4 +#define IXGBE_XEC 0x04120 + +#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */ +#define IXGBE_TQSMR(_i) (((_i) <= 7) ? (0x07300 + ((_i) * 4)) : (0x08600 + ((_i) * 4))) + +#define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QBRC(_i) (0x01034 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QBTC(_i) (0x06034 + ((_i) * 0x40)) /* 16 of these */ + +/* Management */ +#define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MFUTP(_i) (0x05030 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MANC 0x05820 +#define IXGBE_MFVAL 0x05824 +#define IXGBE_MANC2H 0x05860 +#define IXGBE_MDEF(_i) (0x05890 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MIPAF 0x058B0 +#define IXGBE_MMAL(_i) (0x05910 + ((_i) * 8)) /* 4 of these (0-3) */ +#define IXGBE_MMAH(_i) (0x05914 + ((_i) * 8)) /* 4 of these (0-3) */ +#define IXGBE_FTFT 0x09400 /* 0x9400-0x97FC */ + +/* ARC Subsystem registers */ +#define IXGBE_HICR 0x15F00 +#define IXGBE_FWSTS 0x15F0C +#define IXGBE_HSMC0R 0x15F04 +#define IXGBE_HSMC1R 0x15F08 +#define IXGBE_SWSR 0x15F10 +#define IXGBE_HFDR 0x15FE8 +#define IXGBE_FLEX_MNG 0x15800 /* 0x15800 - 0x15EFC */ + +/* PCI-E registers */ +#define IXGBE_GCR 0x11000 +#define IXGBE_GTV 0x11004 +#define IXGBE_FUNCTAG 0x11008 +#define IXGBE_GLT 0x1100C +#define IXGBE_GSCL_1 0x11010 +#define IXGBE_GSCL_2 0x11014 +#define IXGBE_GSCL_3 0x11018 +#define IXGBE_GSCL_4 0x1101C +#define IXGBE_GSCN_0 0x11020 +#define IXGBE_GSCN_1 0x11024 +#define IXGBE_GSCN_2 0x11028 +#define IXGBE_GSCN_3 0x1102C +#define IXGBE_FACTPS 0x10150 +#define IXGBE_PCIEANACTL 0x11040 +#define IXGBE_SWSM 0x10140 +#define IXGBE_FWSM 0x10148 +#define IXGBE_GSSR 0x10160 +#define IXGBE_MREVID 0x11064 +#define IXGBE_DCA_ID 0x11070 +#define IXGBE_DCA_CTRL 0x11074 + +/* Diagnostic Registers */ +#define IXGBE_RDSTATCTL 0x02C20 +#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */ +#define IXGBE_RDHMPN 0x02F08 +#define IXGBE_RIC_DW(_i) (0x02F10 + ((_i) * 4)) +#define IXGBE_RDPROBE 0x02F20 +#define IXGBE_TDSTATCTL 0x07C20 +#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ +#define IXGBE_TDHMPN 0x07F08 +#define IXGBE_TIC_DW(_i) (0x07F10 + ((_i) * 4)) +#define IXGBE_TDPROBE 0x07F20 +#define IXGBE_TXBUFCTRL 0x0C600 +#define IXGBE_TXBUFDATA0 0x0C610 +#define IXGBE_TXBUFDATA1 0x0C614 +#define IXGBE_TXBUFDATA2 0x0C618 +#define IXGBE_TXBUFDATA3 0x0C61C +#define IXGBE_RXBUFCTRL 0x03600 +#define IXGBE_RXBUFDATA0 0x03610 +#define IXGBE_RXBUFDATA1 0x03614 +#define IXGBE_RXBUFDATA2 0x03618 +#define IXGBE_RXBUFDATA3 0x0361C +#define IXGBE_PCIE_DIAG(_i) (0x11090 + ((_i) * 4)) /* 8 of these */ +#define IXGBE_RFVAL 0x050A4 +#define IXGBE_MDFTC1 0x042B8 +#define IXGBE_MDFTC2 0x042C0 +#define IXGBE_MDFTFIFO1 0x042C4 +#define IXGBE_MDFTFIFO2 0x042C8 +#define IXGBE_MDFTS 0x042CC +#define IXGBE_RXDATAWRPTR(_i) (0x03700 + ((_i) * 4)) /* 8 of these 3700-370C*/ +#define IXGBE_RXDESCWRPTR(_i) (0x03710 + ((_i) * 4)) /* 8 of these 3710-371C*/ +#define IXGBE_RXDATARDPTR(_i) (0x03720 + ((_i) * 4)) /* 8 of these 3720-372C*/ +#define IXGBE_RXDESCRDPTR(_i) (0x03730 + ((_i) * 4)) /* 8 of these 3730-373C*/ +#define IXGBE_TXDATAWRPTR(_i) (0x0C700 + ((_i) * 4)) /* 8 of these C700-C70C*/ +#define IXGBE_TXDESCWRPTR(_i) (0x0C710 + ((_i) * 4)) /* 8 of these C710-C71C*/ +#define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/ +#define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/ +#define IXGBE_PCIEECCCTL 0x1106C +#define IXGBE_PBTXECC 0x0C300 +#define IXGBE_PBRXECC 0x03300 +#define IXGBE_GHECCR 0x110B0 + +/* MAC Registers */ +#define IXGBE_PCS1GCFIG 0x04200 +#define IXGBE_PCS1GLCTL 0x04208 +#define IXGBE_PCS1GLSTA 0x0420C +#define IXGBE_PCS1GDBG0 0x04210 +#define IXGBE_PCS1GDBG1 0x04214 +#define IXGBE_PCS1GANA 0x04218 +#define IXGBE_PCS1GANLP 0x0421C +#define IXGBE_PCS1GANNP 0x04220 +#define IXGBE_PCS1GANLPNP 0x04224 +#define IXGBE_HLREG0 0x04240 +#define IXGBE_HLREG1 0x04244 +#define IXGBE_PAP 0x04248 +#define IXGBE_MACA 0x0424C +#define IXGBE_APAE 0x04250 +#define IXGBE_ARD 0x04254 +#define IXGBE_AIS 0x04258 +#define IXGBE_MSCA 0x0425C +#define IXGBE_MSRWD 0x04260 +#define IXGBE_MLADD 0x04264 +#define IXGBE_MHADD 0x04268 +#define IXGBE_TREG 0x0426C +#define IXGBE_PCSS1 0x04288 +#define IXGBE_PCSS2 0x0428C +#define IXGBE_XPCSS 0x04290 +#define IXGBE_SERDESC 0x04298 +#define IXGBE_MACS 0x0429C +#define IXGBE_AUTOC 0x042A0 +#define IXGBE_LINKS 0x042A4 +#define IXGBE_AUTOC2 0x042A8 +#define IXGBE_AUTOC3 0x042AC +#define IXGBE_ANLP1 0x042B0 +#define IXGBE_ANLP2 0x042B4 +#define IXGBE_ATLASCTL 0x04800 + + +/* CTRL Bit Masks */ +#define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */ +#define IXGBE_CTRL_LNK_RST 0x00000008 /* Link Reset. Resets everything. */ +#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */ + +/* FACTPS */ +#define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */ + +/* MHADD Bit Masks */ +#define IXGBE_MHADD_MFS_MASK 0xFFFF0000 +#define IXGBE_MHADD_MFS_SHIFT 16 + +/* Extended Device Control */ +#define IXGBE_CTRL_EXT_NS_DIS 0x00010000 /* No Snoop disable */ +#define IXGBE_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ +#define IXGBE_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ + +/* Direct Cache Access (DCA) definitions */ +#define IXGBE_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */ +#define IXGBE_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */ + +#define IXGBE_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */ +#define IXGBE_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */ + +#define IXGBE_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */ +#define IXGBE_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */ +#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */ +#define IXGBE_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */ + +#define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ +#define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ +#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */ +#define IXGBE_DCA_MAX_QUEUES_82598 16 /* DCA regs only on 16 queues */ + +/* MSCA Bit Masks */ +#define IXGBE_MSCA_NP_ADDR_MASK 0x0000FFFF /* MDI Address (new protocol) */ +#define IXGBE_MSCA_NP_ADDR_SHIFT 0 +#define IXGBE_MSCA_DEV_TYPE_MASK 0x001F0000 /* Device Type (new protocol) */ +#define IXGBE_MSCA_DEV_TYPE_SHIFT 16 /* Register Address (old protocol */ +#define IXGBE_MSCA_PHY_ADDR_MASK 0x03E00000 /* PHY Address mask */ +#define IXGBE_MSCA_PHY_ADDR_SHIFT 21 /* PHY Address shift*/ +#define IXGBE_MSCA_OP_CODE_MASK 0x0C000000 /* OP CODE mask */ +#define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */ +#define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */ +#define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */ +#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */ +#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/ +#define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */ +#define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */ +#define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */ +#define IXGBE_MSCA_OLD_PROTOCOL 0x10000000 /* ST CODE 01 (old protocol) */ +#define IXGBE_MSCA_MDI_COMMAND 0x40000000 /* Initiate MDI command */ +#define IXGBE_MSCA_MDI_IN_PROG_EN 0x80000000 /* MDI in progress enable */ + +/* MSRWD bit masks */ +#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF +#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0 +#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000 +#define IXGBE_MSRWD_READ_DATA_SHIFT 16 + +/* Atlas registers */ +#define IXGBE_ATLAS_PDN_LPBK 0x24 +#define IXGBE_ATLAS_PDN_10G 0xB +#define IXGBE_ATLAS_PDN_1G 0xC +#define IXGBE_ATLAS_PDN_AN 0xD + +/* Atlas bit masks */ +#define IXGBE_ATLASCTL_WRITE_CMD 0x00010000 +#define IXGBE_ATLAS_PDN_TX_REG_EN 0x10 +#define IXGBE_ATLAS_PDN_TX_10G_QL_ALL 0xF0 +#define IXGBE_ATLAS_PDN_TX_1G_QL_ALL 0xF0 +#define IXGBE_ATLAS_PDN_TX_AN_QL_ALL 0xF0 + +/* Device Type definitions for new protocol MDIO commands */ +#define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 +#define IXGBE_MDIO_PCS_DEV_TYPE 0x3 +#define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 +#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ +#define IXGBE_TWINAX_DEV 1 + +#define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ + +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL 0x0 /* VS1 Control Reg */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS 0x1 /* VS1 Status Reg */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS 0x0008 /* 1 = Link Up */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS 0x0010 /* 0 - 10G, 1 - 1G */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED 0x0018 +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED 0x0010 + +#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */ +#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */ +#define IXGBE_MDIO_PHY_XS_CONTROL 0x0 /* PHY_XS Control Reg */ +#define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */ +#define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/ +#define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ +#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Ability Reg */ +#define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */ +#define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */ + +/* MII clause 22/28 definitions */ +#define IXGBE_MDIO_PHY_LOW_POWER_MODE 0x0800 + +#define IXGBE_MII_SPEED_SELECTION_REG 0x10 +#define IXGBE_MII_RESTART 0x200 +#define IXGBE_MII_AUTONEG_COMPLETE 0x20 +#define IXGBE_MII_AUTONEG_REG 0x0 + +#define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 +#define IXGBE_MAX_PHY_ADDR 32 + +/* PHY IDs*/ +#define TN1010_PHY_ID 0x00A19410 +#define TNX_FW_REV 0xB +#define QT2022_PHY_ID 0x0043A400 +#define ATH_PHY_ID 0x03429050 + +/* PHY Types */ +#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 + +/* Special PHY Init Routine */ +#define IXGBE_PHY_INIT_OFFSET_NL 0x002B +#define IXGBE_CONTROL_MASK_NL 0xF000 +#define IXGBE_DATA_MASK_NL 0x0FFF +#define IXGBE_CONTROL_SHIFT_NL 12 +#define IXGBE_DELAY_NL 0 +#define IXGBE_DATA_NL 1 +#define IXGBE_CONTROL_NL 0x000F +#define IXGBE_CONTROL_EOL_NL 0x0FFF +#define IXGBE_CONTROL_SOL_NL 0x0000 + +/* General purpose Interrupt Enable */ +#define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ +#define IXGBE_SDP1_GPIEN 0x00000002 /* SDP1 */ +#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ +#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ +#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ +#define IXGBE_GPIE_EIAME 0x40000000 +#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 + +/* Transmit Flow Control status */ +#define IXGBE_TFCS_TXOFF 0x00000001 +#define IXGBE_TFCS_TXOFF0 0x00000100 +#define IXGBE_TFCS_TXOFF1 0x00000200 +#define IXGBE_TFCS_TXOFF2 0x00000400 +#define IXGBE_TFCS_TXOFF3 0x00000800 +#define IXGBE_TFCS_TXOFF4 0x00001000 +#define IXGBE_TFCS_TXOFF5 0x00002000 +#define IXGBE_TFCS_TXOFF6 0x00004000 +#define IXGBE_TFCS_TXOFF7 0x00008000 + +/* TCP Timer */ +#define IXGBE_TCPTIMER_KS 0x00000100 +#define IXGBE_TCPTIMER_COUNT_ENABLE 0x00000200 +#define IXGBE_TCPTIMER_COUNT_FINISH 0x00000400 +#define IXGBE_TCPTIMER_LOOP 0x00000800 +#define IXGBE_TCPTIMER_DURATION_MASK 0x000000FF + +/* HLREG0 Bit Masks */ +#define IXGBE_HLREG0_TXCRCEN 0x00000001 /* bit 0 */ +#define IXGBE_HLREG0_RXCRCSTRP 0x00000002 /* bit 1 */ +#define IXGBE_HLREG0_JUMBOEN 0x00000004 /* bit 2 */ +#define IXGBE_HLREG0_TXPADEN 0x00000400 /* bit 10 */ +#define IXGBE_HLREG0_TXPAUSEEN 0x00001000 /* bit 12 */ +#define IXGBE_HLREG0_RXPAUSEEN 0x00004000 /* bit 14 */ +#define IXGBE_HLREG0_LPBK 0x00008000 /* bit 15 */ +#define IXGBE_HLREG0_MDCSPD 0x00010000 /* bit 16 */ +#define IXGBE_HLREG0_CONTMDC 0x00020000 /* bit 17 */ +#define IXGBE_HLREG0_CTRLFLTR 0x00040000 /* bit 18 */ +#define IXGBE_HLREG0_PREPEND 0x00F00000 /* bits 20-23 */ +#define IXGBE_HLREG0_PRIPAUSEEN 0x01000000 /* bit 24 */ +#define IXGBE_HLREG0_RXPAUSERECDA 0x06000000 /* bits 25-26 */ +#define IXGBE_HLREG0_RXLNGTHERREN 0x08000000 /* bit 27 */ +#define IXGBE_HLREG0_RXPADSTRIPEN 0x10000000 /* bit 28 */ + +/* VMD_CTL bitmasks */ +#define IXGBE_VMD_CTL_VMDQ_EN 0x00000001 +#define IXGBE_VMD_CTL_VMDQ_FILTER 0x00000002 + +/* RDHMPN and TDHMPN bitmasks */ +#define IXGBE_RDHMPN_RDICADDR 0x007FF800 +#define IXGBE_RDHMPN_RDICRDREQ 0x00800000 +#define IXGBE_RDHMPN_RDICADDR_SHIFT 11 +#define IXGBE_TDHMPN_TDICADDR 0x003FF800 +#define IXGBE_TDHMPN_TDICRDREQ 0x00800000 +#define IXGBE_TDHMPN_TDICADDR_SHIFT 11 + +/* Receive Checksum Control */ +#define IXGBE_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ +#define IXGBE_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ + +/* FCRTL Bit Masks */ +#define IXGBE_FCRTL_XONE 0x80000000 /* bit 31, XON enable */ +#define IXGBE_FCRTH_FCEN 0x80000000 /* Rx Flow control enable */ + +/* PAP bit masks*/ +#define IXGBE_PAP_TXPAUSECNT_MASK 0x0000FFFF /* Pause counter mask */ + +/* RMCS Bit Masks */ +#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recycle Mode enable */ +/* Receive Arbitration Control: 0 Round Robin, 1 DFP */ +#define IXGBE_RMCS_RAC 0x00000004 +#define IXGBE_RMCS_DFP IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */ +#define IXGBE_RMCS_TFCE_802_3X 0x00000008 /* Tx Priority flow control ena */ +#define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */ +#define IXGBE_RMCS_ARBDIS 0x00000040 /* Arbitration disable bit */ + + +/* Interrupt register bitmasks */ + +/* Extended Interrupt Cause Read */ +#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */ +#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ +#define IXGBE_EICR_GPI_SDP1 0x02000000 /* Gen Purpose Interrupt on SDP1 */ +#define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */ +#define IXGBE_EICR_MNG 0x00400000 /* Manageability Event Interrupt */ +#define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */ +#define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */ +#define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ +#define IXGBE_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ + +/* Extended Interrupt Cause Set */ +#define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EICS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* Gen Purpose Interrupt on SDP0 */ +#define IXGBE_EICS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* Gen Purpose Interrupt on SDP1 */ +#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EICS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Set */ +#define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* Gen Purpose Interrupt on SDP0 */ +#define IXGBE_EIMS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* Gen Purpose Interrupt on SDP1 */ +#define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */ +#define IXGBE_EIMS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Clear */ +#define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMC_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* Gen Purpose Interrupt on SDP0 */ +#define IXGBE_EIMC_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* Gen Purpose Interrupt on SDP1 */ +#define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EIMC_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +#define IXGBE_EIMS_ENABLE_MASK ( \ + IXGBE_EIMS_RTX_QUEUE | \ + IXGBE_EIMS_LSC | \ + IXGBE_EIMS_TCP_TIMER | \ + IXGBE_EIMS_OTHER) + +/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */ +#define IXGBE_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */ +#define IXGBE_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */ +#define IXGBE_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */ +#define IXGBE_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */ +#define IXGBE_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */ +#define IXGBE_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */ +#define IXGBE_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */ +#define IXGBE_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */ +#define IXGBE_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */ +#define IXGBE_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of control bits */ + +/* Interrupt clear mask */ +#define IXGBE_IRQ_CLEAR_MASK 0xFFFFFFFF + +/* Interrupt Vector Allocation Registers */ +#define IXGBE_IVAR_REG_NUM 25 +#define IXGBE_IVAR_TXRX_ENTRY 96 +#define IXGBE_IVAR_RX_ENTRY 64 +#define IXGBE_IVAR_RX_QUEUE(_i) (0 + (_i)) +#define IXGBE_IVAR_TX_QUEUE(_i) (64 + (_i)) +#define IXGBE_IVAR_TX_ENTRY 32 + +#define IXGBE_IVAR_TCP_TIMER_INDEX 96 /* 0 based index */ +#define IXGBE_IVAR_OTHER_CAUSES_INDEX 97 /* 0 based index */ + +#define IXGBE_MSIX_VECTOR(_i) (0 + (_i)) + +#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */ + +/* VLAN Control Bit Masks */ +#define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ +#define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */ +#define IXGBE_VLNCTRL_CFIEN 0x20000000 /* bit 29 */ +#define IXGBE_VLNCTRL_VFE 0x40000000 /* bit 30 */ +#define IXGBE_VLNCTRL_VME 0x80000000 /* bit 31 */ + + +#define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */ + +/* STATUS Bit Masks */ +#define IXGBE_STATUS_LAN_ID 0x0000000C /* LAN ID */ +#define IXGBE_STATUS_GIO 0x00080000 /* GIO Master Enable Status */ + +#define IXGBE_STATUS_LAN_ID_0 0x00000000 /* LAN ID 0 */ +#define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */ + +/* ESDP Bit Masks */ +#define IXGBE_ESDP_SDP4 0x00000001 /* SDP4 Data Value */ +#define IXGBE_ESDP_SDP5 0x00000002 /* SDP5 Data Value */ +#define IXGBE_ESDP_SDP4_DIR 0x00000004 /* SDP4 IO direction */ +#define IXGBE_ESDP_SDP5_DIR 0x00000008 /* SDP5 IO direction */ + +/* LEDCTL Bit Masks */ +#define IXGBE_LED_IVRT_BASE 0x00000040 +#define IXGBE_LED_BLINK_BASE 0x00000080 +#define IXGBE_LED_MODE_MASK_BASE 0x0000000F +#define IXGBE_LED_OFFSET(_base, _i) (_base << (8 * (_i))) +#define IXGBE_LED_MODE_SHIFT(_i) (8*(_i)) +#define IXGBE_LED_IVRT(_i) IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i) +#define IXGBE_LED_BLINK(_i) IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i) +#define IXGBE_LED_MODE_MASK(_i) IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i) + +/* LED modes */ +#define IXGBE_LED_LINK_UP 0x0 +#define IXGBE_LED_LINK_10G 0x1 +#define IXGBE_LED_MAC 0x2 +#define IXGBE_LED_FILTER 0x3 +#define IXGBE_LED_LINK_ACTIVE 0x4 +#define IXGBE_LED_LINK_1G 0x5 +#define IXGBE_LED_ON 0xE +#define IXGBE_LED_OFF 0xF + +/* AUTOC Bit Masks */ +#define IXGBE_AUTOC_KX4_SUPP 0x80000000 +#define IXGBE_AUTOC_KX_SUPP 0x40000000 +#define IXGBE_AUTOC_PAUSE 0x30000000 +#define IXGBE_AUTOC_RF 0x08000000 +#define IXGBE_AUTOC_PD_TMR 0x06000000 +#define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000 +#define IXGBE_AUTOC_AN_RX_DRIFT 0x00800000 +#define IXGBE_AUTOC_AN_RX_ALIGN 0x007C0000 +#define IXGBE_AUTOC_AN_RESTART 0x00001000 +#define IXGBE_AUTOC_FLU 0x00000001 +#define IXGBE_AUTOC_LMS_SHIFT 13 +#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) + +#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200 +#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180 +#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7 +#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9 +#define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_10G_KX4 (0x1 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_10G_CX4 (0x2 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_1G_BX (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_1G_KX (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT) + +/* LINKS Bit Masks */ +#define IXGBE_LINKS_KX_AN_COMP 0x80000000 +#define IXGBE_LINKS_UP 0x40000000 +#define IXGBE_LINKS_SPEED 0x20000000 +#define IXGBE_LINKS_MODE 0x18000000 +#define IXGBE_LINKS_RX_MODE 0x06000000 +#define IXGBE_LINKS_TX_MODE 0x01800000 +#define IXGBE_LINKS_XGXS_EN 0x00400000 +#define IXGBE_LINKS_PCS_1G_EN 0x00200000 +#define IXGBE_LINKS_1G_AN_EN 0x00100000 +#define IXGBE_LINKS_KX_AN_IDLE 0x00080000 +#define IXGBE_LINKS_1G_SYNC 0x00040000 +#define IXGBE_LINKS_10G_ALIGN 0x00020000 +#define IXGBE_LINKS_10G_LANE_SYNC 0x00017000 +#define IXGBE_LINKS_TL_FAULT 0x00001000 +#define IXGBE_LINKS_SIGNAL 0x00000F00 + +#define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ +#define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ + +#define FIBER_LINK_UP_LIMIT 50 + +/* PCS1GLSTA Bit Masks */ +#define IXGBE_PCS1GLSTA_LINK_OK 1 +#define IXGBE_PCS1GLSTA_SYNK_OK 0x10 +#define IXGBE_PCS1GLSTA_AN_COMPLETE 0x10000 +#define IXGBE_PCS1GLSTA_AN_PAGE_RX 0x20000 +#define IXGBE_PCS1GLSTA_AN_TIMED_OUT 0x40000 +#define IXGBE_PCS1GLSTA_AN_REMOTE_FAULT 0x80000 +#define IXGBE_PCS1GLSTA_AN_ERROR_RWS 0x100000 + +#define IXGBE_PCS1GANA_SYM_PAUSE 0x80 +#define IXGBE_PCS1GANA_ASM_PAUSE 0x100 + +/* PCS1GLCTL Bit Masks */ +#define IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN 0x00040000 /* PCS 1G autoneg timeout enable (bit 18) */ +#define IXGBE_PCS1GLCTL_FLV_LINK_UP 1 +#define IXGBE_PCS1GLCTL_FORCE_LINK 0x20 +#define IXGBE_PCS1GLCTL_LOW_LINK_LATCH 0x40 +#define IXGBE_PCS1GLCTL_AN_ENABLE 0x10000 +#define IXGBE_PCS1GLCTL_AN_RESTART 0x20000 + +/* SW Semaphore Register bitmasks */ +#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define IXGBE_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ + +/* GSSR definitions */ +#define IXGBE_GSSR_EEP_SM 0x0001 +#define IXGBE_GSSR_PHY0_SM 0x0002 +#define IXGBE_GSSR_PHY1_SM 0x0004 +#define IXGBE_GSSR_MAC_CSR_SM 0x0008 +#define IXGBE_GSSR_FLASH_SM 0x0010 + +/* EEC Register */ +#define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */ +#define IXGBE_EEC_CS 0x00000002 /* EEPROM Chip Select */ +#define IXGBE_EEC_DI 0x00000004 /* EEPROM Data In */ +#define IXGBE_EEC_DO 0x00000008 /* EEPROM Data Out */ +#define IXGBE_EEC_FWE_MASK 0x00000030 /* FLASH Write Enable */ +#define IXGBE_EEC_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define IXGBE_EEC_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define IXGBE_EEC_FWE_SHIFT 4 +#define IXGBE_EEC_REQ 0x00000040 /* EEPROM Access Request */ +#define IXGBE_EEC_GNT 0x00000080 /* EEPROM Access Grant */ +#define IXGBE_EEC_PRES 0x00000100 /* EEPROM Present */ +#define IXGBE_EEC_ARD 0x00000200 /* EEPROM Auto Read Done */ +/* EEPROM Addressing bits based on type (0-small, 1-large) */ +#define IXGBE_EEC_ADDR_SIZE 0x00000400 +#define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */ + +#define IXGBE_EEC_SIZE_SHIFT 11 +#define IXGBE_EEPROM_WORD_SIZE_SHIFT 6 +#define IXGBE_EEPROM_OPCODE_BITS 8 + +/* Checksum and EEPROM pointers */ +#define IXGBE_EEPROM_CHECKSUM 0x3F +#define IXGBE_EEPROM_SUM 0xBABA +#define IXGBE_PCIE_ANALOG_PTR 0x03 +#define IXGBE_ATLAS0_CONFIG_PTR 0x04 +#define IXGBE_ATLAS1_CONFIG_PTR 0x05 +#define IXGBE_PCIE_GENERAL_PTR 0x06 +#define IXGBE_PCIE_CONFIG0_PTR 0x07 +#define IXGBE_PCIE_CONFIG1_PTR 0x08 +#define IXGBE_CORE0_PTR 0x09 +#define IXGBE_CORE1_PTR 0x0A +#define IXGBE_MAC0_PTR 0x0B +#define IXGBE_MAC1_PTR 0x0C +#define IXGBE_CSR0_CONFIG_PTR 0x0D +#define IXGBE_CSR1_CONFIG_PTR 0x0E +#define IXGBE_FW_PTR 0x0F +#define IXGBE_PBANUM0_PTR 0x15 +#define IXGBE_PBANUM1_PTR 0x16 + +/* Legacy EEPROM word offsets */ +#define IXGBE_ISCSI_BOOT_CAPS 0x0033 +#define IXGBE_ISCSI_SETUP_PORT_0 0x0030 +#define IXGBE_ISCSI_SETUP_PORT_1 0x0034 + +/* EEPROM Commands - SPI */ +#define IXGBE_EEPROM_MAX_RETRY_SPI 5000 /* Max wait 5ms for RDY signal */ +#define IXGBE_EEPROM_STATUS_RDY_SPI 0x01 +#define IXGBE_EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */ +#define IXGBE_EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */ +#define IXGBE_EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = addr bit-8 */ +#define IXGBE_EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Ena latch */ +/* EEPROM reset Write Enable latch */ +#define IXGBE_EEPROM_WRDI_OPCODE_SPI 0x04 +#define IXGBE_EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status reg */ +#define IXGBE_EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status reg */ +#define IXGBE_EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */ +#define IXGBE_EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */ +#define IXGBE_EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */ + +/* EEPROM Read Register */ +#define IXGBE_EEPROM_READ_REG_DATA 16 /* data offset in EEPROM read reg */ +#define IXGBE_EEPROM_READ_REG_DONE 2 /* Offset to READ done bit */ +#define IXGBE_EEPROM_READ_REG_START 1 /* First bit to start operation */ +#define IXGBE_EEPROM_READ_ADDR_SHIFT 2 /* Shift to the address bits */ + +#define IXGBE_ETH_LENGTH_OF_ADDRESS 6 + +#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS +#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ +#endif + +#ifndef IXGBE_EERD_ATTEMPTS +/* Number of 5 microseconds we wait for EERD read to complete */ +#define IXGBE_EERD_ATTEMPTS 100000 +#endif + +/* PCI Bus Info */ +#define IXGBE_PCI_LINK_STATUS 0xB2 +#define IXGBE_PCI_LINK_WIDTH 0x3F0 +#define IXGBE_PCI_LINK_WIDTH_1 0x10 +#define IXGBE_PCI_LINK_WIDTH_2 0x20 +#define IXGBE_PCI_LINK_WIDTH_4 0x40 +#define IXGBE_PCI_LINK_WIDTH_8 0x80 +#define IXGBE_PCI_LINK_SPEED 0xF +#define IXGBE_PCI_LINK_SPEED_2500 0x1 +#define IXGBE_PCI_LINK_SPEED_5000 0x2 +#define IXGBE_PCI_HEADER_TYPE_REGISTER 0x0E +#define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80 + +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 + +/* Check whether address is multicast. This is little-endian specific check.*/ +#define IXGBE_IS_MULTICAST(Address) \ + (bool)(((u8 *)(Address))[0] & ((u8)0x01)) + +/* Check whether an address is broadcast. */ +#define IXGBE_IS_BROADCAST(Address) \ + ((((u8 *)(Address))[0] == ((u8)0xff)) && \ + (((u8 *)(Address))[1] == ((u8)0xff))) + +/* RAH */ +#define IXGBE_RAH_VIND_MASK 0x003C0000 +#define IXGBE_RAH_VIND_SHIFT 18 +#define IXGBE_RAH_AV 0x80000000 + +/* Header split receive */ +#define IXGBE_RFCTL_ISCSI_DIS 0x00000001 +#define IXGBE_RFCTL_ISCSI_DWC_MASK 0x0000003E +#define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1 +#define IXGBE_RFCTL_NFSW_DIS 0x00000040 +#define IXGBE_RFCTL_NFSR_DIS 0x00000080 +#define IXGBE_RFCTL_NFS_VER_MASK 0x00000300 +#define IXGBE_RFCTL_NFS_VER_SHIFT 8 +#define IXGBE_RFCTL_NFS_VER_2 0 +#define IXGBE_RFCTL_NFS_VER_3 1 +#define IXGBE_RFCTL_NFS_VER_4 2 +#define IXGBE_RFCTL_IPV6_DIS 0x00000400 +#define IXGBE_RFCTL_IPV6_XSUM_DIS 0x00000800 +#define IXGBE_RFCTL_IPFRSP_DIS 0x00004000 +#define IXGBE_RFCTL_IPV6_EX_DIS 0x00010000 +#define IXGBE_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 + +/* Transmit Config masks */ +#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */ +#define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */ +/* Enable short packet padding to 64 bytes */ +#define IXGBE_TX_PAD_ENABLE 0x00000400 +#define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */ +/* This allows for 16K packets + 4k for vlan */ +#define IXGBE_MAX_FRAME_SZ 0x40040000 + +#define IXGBE_TDWBAL_HEAD_WB_ENABLE 0x1 /* Tx head write-back enable */ +#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq. # write-back enable */ + +/* Receive Config masks */ +#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ +#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */ +#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ + +#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */ +#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ +#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */ +#define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */ +#define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */ +#define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */ +/* Receive Priority Flow Control Enable */ +#define IXGBE_FCTRL_RPFCE 0x00004000 +#define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */ + +/* Multiple Receive Queue Control */ +#define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */ +#define IXGBE_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define IXGBE_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define IXGBE_MRQC_RSS_FIELD_IPV4 0x00020000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 0x00040000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define IXGBE_MRQC_RSS_FIELD_IPV6 0x00100000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 +#define IXGBE_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 0x01000000 + +#define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define IXGBE_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */ +#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */ + +/* Receive Descriptor bit definitions */ +#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ +#define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */ +#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ +#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */ +#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ +#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ +#define IXGBE_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ +#define IXGBE_RXD_ERR_CE 0x01 /* CRC Error */ +#define IXGBE_RXD_ERR_LE 0x02 /* Length Error */ +#define IXGBE_RXD_ERR_PE 0x08 /* Packet Error */ +#define IXGBE_RXD_ERR_OSE 0x10 /* Oversize Error */ +#define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */ +#define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */ +#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ +#define IXGBE_RXDADV_HBO 0x00800000 +#define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ +#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ +#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */ +#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */ +#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */ +#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */ +#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */ +#define IXGBE_RXD_VLAN_ID_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define IXGBE_RXD_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define IXGBE_RXD_PRI_SHIFT 13 +#define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define IXGBE_RXD_CFI_SHIFT 12 + +/* SRRCTL bit definitions */ +#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ +#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F +#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 +#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 +#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 +#define IXGBE_SRRCTL_DESCTYPE_MASK 0x0E000000 + +#define IXGBE_RXDPS_HDRSTAT_HDRSP 0x00008000 +#define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF + +#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F +#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0 +#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0 +#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5 +#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 +#define IXGBE_RXDADV_SPH 0x8000 + +/* RSS Hash results */ +#define IXGBE_RXDADV_RSSTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP 0x00000001 +#define IXGBE_RXDADV_RSSTYPE_IPV4 0x00000002 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP 0x00000003 +#define IXGBE_RXDADV_RSSTYPE_IPV6_EX 0x00000004 +#define IXGBE_RXDADV_RSSTYPE_IPV6 0x00000005 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006 +#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP 0x00000007 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP 0x00000008 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009 + +/* RSS Packet Types as indicated in the receive descriptor. */ +#define IXGBE_RXDADV_PKTTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPv4 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPv4 hdr + extensions */ +#define IXGBE_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPv6 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPv6 hdr + extensions */ +#define IXGBE_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ + +/* Masks to determine if packets should be dropped due to frame errors */ +#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \ + IXGBE_RXD_ERR_CE | \ + IXGBE_RXD_ERR_LE | \ + IXGBE_RXD_ERR_PE | \ + IXGBE_RXD_ERR_OSE | \ + IXGBE_RXD_ERR_USE) + +#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK ( \ + IXGBE_RXDADV_ERR_CE | \ + IXGBE_RXDADV_ERR_LE | \ + IXGBE_RXDADV_ERR_PE | \ + IXGBE_RXDADV_ERR_OSE | \ + IXGBE_RXDADV_ERR_USE) + +/* Multicast bit mask */ +#define IXGBE_MCSTCTRL_MFE 0x4 + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_TX_BUFFER_GRANULARITY 1024 + +/* Vlan-specific macros */ +#define IXGBE_RX_DESC_SPECIAL_VLAN_MASK 0x0FFF /* VLAN ID in lower 12 bits */ +#define IXGBE_RX_DESC_SPECIAL_PRI_MASK 0xE000 /* Priority in upper 3 bits */ +#define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */ +#define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT + +#ifndef __le16 +/* Little Endian defines */ +#define __le8 u8 +#define __le16 u16 +#define __le32 u32 +#define __le64 u64 + +#endif + + +/* Transmit Descriptor - Legacy */ +struct ixgbe_legacy_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + __le32 data; + struct { + __le16 length; /* Data buffer length */ + __le8 cso; /* Checksum offset */ + __le8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + __le32 data; + struct { + __le8 status; /* Descriptor status */ + __le8 css; /* Checksum start */ + __le16 vlan; + } fields; + } upper; +}; + +/* Transmit Descriptor - Advanced */ +union ixgbe_adv_tx_desc { + struct { + __le64 buffer_addr; /* Address of descriptor's data buf */ + __le32 cmd_type_len; + __le32 olinfo_status; + } read; + struct { + __le64 rsvd; /* Reserved */ + __le32 nxtseq_seed; + __le32 status; + } wb; +}; + +/* Receive Descriptor - Legacy */ +struct ixgbe_legacy_rx_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 length; /* Length of data DMAed into data buffer */ + __le16 csum; /* Packet checksum */ + __le8 status; /* Descriptor status */ + __le8 errors; /* Descriptor Errors */ + __le16 vlan; +}; + +/* Receive Descriptor - Advanced */ +union ixgbe_adv_rx_desc { + struct { + __le64 pkt_addr; /* Packet buffer address */ + __le64 hdr_addr; /* Header buffer address */ + } read; + struct { + struct { + union { + __le32 data; + struct { + __le16 pkt_info; /* RSS type, Packet type */ + __le16 hdr_info; /* Split Header, header len */ + } hs_rss; + } lo_dword; + union { + __le32 rss; /* RSS Hash */ + struct { + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + __le32 status_error; /* ext status/error */ + __le16 length; /* Packet length */ + __le16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +/* Context descriptors */ +struct ixgbe_adv_tx_context_desc { + __le32 vlan_macip_lens; + __le32 seqnum_seed; + __le32 type_tucmd_mlhl; + __le32 mss_l4len_idx; +}; + +/* Adv Transmit Descriptor Config Masks */ +#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buffer length(bytes) */ +#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ +#define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */ +#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ +#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */ +#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */ +#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */ +#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ +#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */ +#define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */ +#define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ +#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */ +#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */ +#define IXGBE_ADVTXD_STAT_RSV 0x0000000C /* STA Reserved */ +#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ +#define IXGBE_ADVTXD_CC 0x00000080 /* Check Context */ +#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */ +#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */ +#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ +#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ +#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ +#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ +#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +#define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */ +#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */ +#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ + +/* Autonegotiation advertised speeds */ +typedef u32 ixgbe_autoneg_advertised; +/* Link speed */ +typedef u32 ixgbe_link_speed; +#define IXGBE_LINK_SPEED_UNKNOWN 0 +#define IXGBE_LINK_SPEED_100_FULL 0x0008 +#define IXGBE_LINK_SPEED_1GB_FULL 0x0020 +#define IXGBE_LINK_SPEED_10GB_FULL 0x0080 +#define IXGBE_LINK_SPEED_82598_AUTONEG (IXGBE_LINK_SPEED_1GB_FULL | \ + IXGBE_LINK_SPEED_10GB_FULL) + +enum ixgbe_eeprom_type { + ixgbe_eeprom_uninitialized = 0, + ixgbe_eeprom_spi, + ixgbe_eeprom_none /* No NVM support */ +}; + +enum ixgbe_mac_type { + ixgbe_mac_unknown = 0, + ixgbe_mac_82598EB, + ixgbe_num_macs +}; + +enum ixgbe_phy_type { + ixgbe_phy_unknown = 0, + ixgbe_phy_tn, + ixgbe_phy_qt, + ixgbe_phy_xaui, + ixgbe_phy_nl, + ixgbe_phy_generic +}; + +enum ixgbe_media_type { + ixgbe_media_type_unknown = 0, + ixgbe_media_type_fiber, + ixgbe_media_type_copper, + ixgbe_media_type_backplane, + ixgbe_media_type_virtual +}; + +/* Flow Control Settings */ +enum ixgbe_fc_type { + ixgbe_fc_none = 0, + ixgbe_fc_rx_pause, + ixgbe_fc_tx_pause, + ixgbe_fc_full, + ixgbe_fc_default +}; + +/* PCI bus types */ +enum ixgbe_bus_type { + ixgbe_bus_type_unknown = 0, + ixgbe_bus_type_pci, + ixgbe_bus_type_pcix, + ixgbe_bus_type_pci_express, + ixgbe_bus_type_reserved +}; + +/* PCI bus speeds */ +enum ixgbe_bus_speed { + ixgbe_bus_speed_unknown = 0, + ixgbe_bus_speed_33, + ixgbe_bus_speed_66, + ixgbe_bus_speed_100, + ixgbe_bus_speed_120, + ixgbe_bus_speed_133, + ixgbe_bus_speed_2500, + ixgbe_bus_speed_5000, + ixgbe_bus_speed_reserved +}; + +/* PCI bus widths */ +enum ixgbe_bus_width { + ixgbe_bus_width_unknown = 0, + ixgbe_bus_width_pcie_x1, + ixgbe_bus_width_pcie_x2, + ixgbe_bus_width_pcie_x4 = 4, + ixgbe_bus_width_pcie_x8 = 8, + ixgbe_bus_width_32, + ixgbe_bus_width_64, + ixgbe_bus_width_reserved +}; + +struct ixgbe_addr_filter_info { + u32 num_mc_addrs; + u32 rar_used_count; + u32 mc_addr_in_rar_count; + u32 mta_in_use; + u32 overflow_promisc; + bool user_set_promisc; +}; + +/* Bus parameters */ +struct ixgbe_bus_info { + enum ixgbe_bus_speed speed; + enum ixgbe_bus_width width; + enum ixgbe_bus_type type; +}; + +/* Flow control parameters */ +struct ixgbe_fc_info { + u32 high_water; /* Flow Control High-water */ + u32 low_water; /* Flow Control Low-water */ + u16 pause_time; /* Flow Control Pause timer */ + bool send_xon; /* Flow control send XON */ + bool strict_ieee; /* Strict IEEE mode */ + enum ixgbe_fc_type type; /* Type of flow control */ + enum ixgbe_fc_type original_type; +}; + +/* Statistics counters collected by the MAC */ +struct ixgbe_hw_stats { + u64 crcerrs; + u64 illerrc; + u64 errbc; + u64 mspdc; + u64 mpctotal; + u64 mpc[8]; + u64 mlfc; + u64 mrfc; + u64 rlec; + u64 lxontxc; + u64 lxonrxc; + u64 lxofftxc; + u64 lxoffrxc; + u64 pxontxc[8]; + u64 pxonrxc[8]; + u64 pxofftxc[8]; + u64 pxoffrxc[8]; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorc; + u64 gotc; + u64 rnbc[8]; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mngprc; + u64 mngpdc; + u64 mngptc; + u64 tor; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 xec; + u64 rqsmr[16]; + u64 tqsmr[8]; + u64 qprc[16]; + u64 qptc[16]; + u64 qbrc[16]; + u64 qbtc[16]; +}; + +/* forward declaration */ +struct ixgbe_hw; + +/* iterator type for walking multicast address lists */ +typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr, + u32 *vmdq); + +/* Function pointer table */ +struct ixgbe_eeprom_operations { + s32 (*init_params)(struct ixgbe_hw *); + s32 (*read)(struct ixgbe_hw *, u16, u16 *); + s32 (*write)(struct ixgbe_hw *, u16, u16); + s32 (*validate_checksum)(struct ixgbe_hw *, u16 *); + s32 (*update_checksum)(struct ixgbe_hw *); +}; + +struct ixgbe_mac_operations { + s32 (*init_hw)(struct ixgbe_hw *); + s32 (*reset_hw)(struct ixgbe_hw *); + s32 (*start_hw)(struct ixgbe_hw *); + s32 (*clear_hw_cntrs)(struct ixgbe_hw *); + enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); + s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); + s32 (*stop_adapter)(struct ixgbe_hw *); + s32 (*get_bus_info)(struct ixgbe_hw *); + s32 (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*); + s32 (*write_analog_reg8)(struct ixgbe_hw*, u32, u8); + + /* Link */ + s32 (*setup_link)(struct ixgbe_hw *); + s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, + bool); + s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); + s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, + bool *); + + /* LED */ + s32 (*led_on)(struct ixgbe_hw *, u32); + s32 (*led_off)(struct ixgbe_hw *, u32); + s32 (*blink_led_start)(struct ixgbe_hw *, u32); + s32 (*blink_led_stop)(struct ixgbe_hw *, u32); + + /* RAR, Multicast, VLAN */ + s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32, u32); + s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32); + s32 (*init_rx_addrs)(struct ixgbe_hw *); + s32 (*update_uc_addr_list)(struct ixgbe_hw *, u8 *, u32, + ixgbe_mc_addr_itr); + s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, + ixgbe_mc_addr_itr); + s32 (*enable_mc)(struct ixgbe_hw *); + s32 (*disable_mc)(struct ixgbe_hw *); + s32 (*clear_vfta)(struct ixgbe_hw *); + s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool); + + /* Flow Control */ + s32 (*setup_fc)(struct ixgbe_hw *, s32); +}; + +struct ixgbe_phy_operations { + s32 (*identify)(struct ixgbe_hw *); + s32 (*reset)(struct ixgbe_hw *); + s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *); + s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16); + s32 (*setup_link)(struct ixgbe_hw *); + s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, + bool); + s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); + s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *); +}; + +struct ixgbe_eeprom_info { + struct ixgbe_eeprom_operations ops; + enum ixgbe_eeprom_type type; + u16 word_size; + u16 address_bits; +}; + +struct ixgbe_mac_info { + struct ixgbe_mac_operations ops; + enum ixgbe_mac_type type; + u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + s32 mc_filter_type; + u32 mcft_size; + u32 vft_size; + u32 num_rar_entries; + u32 max_tx_queues; + u32 max_rx_queues; + u32 link_attach_type; + u32 link_mode_select; + bool link_settings_loaded; + bool autoneg; + bool autoneg_failed; +}; + +struct ixgbe_phy_info { + struct ixgbe_phy_operations ops; + enum ixgbe_phy_type type; + u32 addr; + u32 id; + u32 revision; + enum ixgbe_media_type media_type; + bool reset_disable; + ixgbe_autoneg_advertised autoneg_advertised; + bool autoneg_wait_to_complete; +}; + +struct ixgbe_hw { + u8 *hw_addr; + void *back; + struct ixgbe_mac_info mac; + struct ixgbe_addr_filter_info addr_ctrl; + struct ixgbe_fc_info fc; + struct ixgbe_phy_info phy; + struct ixgbe_eeprom_info eeprom; + struct ixgbe_bus_info bus; + u16 device_id; + u16 vendor_id; + u16 subsystem_device_id; + u16 subsystem_vendor_id; + u8 revision_id; + bool adapter_stopped; +}; + +#define ixgbe_hw(hw, func, ...) \ + ((hw)->mac.ops.func != NULL) ? \ + (hw)->mac.ops.func(hw, ##__VA_ARGS__) : IXGBE_NOT_IMPLEMENTED +#define ixgbe_ee(hw, func, ...) \ + ((hw)->eeprom.ops.func != NULL) ? \ + (hw)->eeprom.ops.func(hw, ##__VA_ARGS__) : IXGBE_NOT_IMPLEMENTED + +/* Error Codes */ +#define IXGBE_SUCCESS 0 +#define IXGBE_ERR_EEPROM -1 +#define IXGBE_ERR_EEPROM_CHECKSUM -2 +#define IXGBE_ERR_PHY -3 +#define IXGBE_ERR_CONFIG -4 +#define IXGBE_ERR_PARAM -5 +#define IXGBE_ERR_MAC_TYPE -6 +#define IXGBE_ERR_UNKNOWN_PHY -7 +#define IXGBE_ERR_LINK_SETUP -8 +#define IXGBE_ERR_ADAPTER_STOPPED -9 +#define IXGBE_ERR_INVALID_MAC_ADDR -10 +#define IXGBE_ERR_DEVICE_NOT_SUPPORTED -11 +#define IXGBE_ERR_MASTER_REQUESTS_PENDING -12 +#define IXGBE_ERR_INVALID_LINK_SETTINGS -13 +#define IXGBE_ERR_AUTONEG_NOT_COMPLETE -14 +#define IXGBE_ERR_RESET_FAILED -15 +#define IXGBE_ERR_SWFW_SYNC -16 +#define IXGBE_ERR_PHY_ADDR_INVALID -17 +#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF + +#define UNREFERENCED_PARAMETER(_p) + +#endif /* _IXGBE_TYPE_H_ */ |